|
Ruby
1.9.3p286(2012-10-12revision37165)
|
00001 /********************************************************************** 00002 00003 ruby.c - 00004 00005 $Author: usa $ 00006 created at: Tue Aug 10 12:47:31 JST 1993 00007 00008 Copyright (C) 1993-2007 Yukihiro Matsumoto 00009 Copyright (C) 2000 Network Applied Communication Laboratory, Inc. 00010 Copyright (C) 2000 Information-technology Promotion Agency, Japan 00011 00012 **********************************************************************/ 00013 00014 #ifdef __CYGWIN__ 00015 #include <windows.h> 00016 #include <sys/cygwin.h> 00017 #endif 00018 #include "ruby/ruby.h" 00019 #include "ruby/encoding.h" 00020 #include "internal.h" 00021 #include "eval_intern.h" 00022 #include "dln.h" 00023 #include <stdio.h> 00024 #include <sys/types.h> 00025 #include <ctype.h> 00026 00027 #ifdef __hpux 00028 #include <sys/pstat.h> 00029 #endif 00030 #if defined(LOAD_RELATIVE) && defined(HAVE_DLADDR) 00031 #include <dlfcn.h> 00032 #endif 00033 00034 #ifdef HAVE_UNISTD_H 00035 #include <unistd.h> 00036 #endif 00037 #if defined(HAVE_FCNTL_H) 00038 #include <fcntl.h> 00039 #elif defined(HAVE_SYS_FCNTL_H) 00040 #include <sys/fcntl.h> 00041 #endif 00042 #ifdef HAVE_SYS_PARAM_H 00043 # include <sys/param.h> 00044 #endif 00045 #ifndef MAXPATHLEN 00046 # define MAXPATHLEN 1024 00047 #endif 00048 00049 #include "ruby/util.h" 00050 00051 #ifndef HAVE_STDLIB_H 00052 char *getenv(); 00053 #endif 00054 00055 #define DISABLE_BIT(bit) (1U << disable_##bit) 00056 enum disable_flag_bits { 00057 disable_gems, 00058 disable_rubyopt, 00059 disable_flag_count 00060 }; 00061 00062 #define DUMP_BIT(bit) (1U << dump_##bit) 00063 enum dump_flag_bits { 00064 dump_version, 00065 dump_copyright, 00066 dump_usage, 00067 dump_yydebug, 00068 dump_syntax, 00069 dump_parsetree, 00070 dump_parsetree_with_comment, 00071 dump_insns, 00072 dump_flag_count 00073 }; 00074 00075 struct cmdline_options { 00076 int sflag, xflag; 00077 int do_loop, do_print; 00078 int do_line, do_split; 00079 int do_search; 00080 unsigned int disable; 00081 int verbose; 00082 int safe_level; 00083 unsigned int setids; 00084 unsigned int dump; 00085 const char *script; 00086 VALUE script_name; 00087 VALUE e_script; 00088 struct { 00089 struct { 00090 VALUE name; 00091 int index; 00092 } enc; 00093 } src, ext, intern; 00094 VALUE req_list; 00095 }; 00096 00097 static void init_ids(struct cmdline_options *); 00098 00099 #define src_encoding_index GET_VM()->src_encoding_index 00100 00101 static struct cmdline_options * 00102 cmdline_options_init(struct cmdline_options *opt) 00103 { 00104 MEMZERO(opt, *opt, 1); 00105 init_ids(opt); 00106 opt->src.enc.index = src_encoding_index; 00107 opt->ext.enc.index = -1; 00108 opt->intern.enc.index = -1; 00109 #if defined DISABLE_RUBYGEMS && DISABLE_RUBYGEMS 00110 opt->disable |= DISABLE_BIT(gems); 00111 #endif 00112 return opt; 00113 } 00114 00115 static NODE *load_file(VALUE, const char *, int, struct cmdline_options *); 00116 static void forbid_setid(const char *, struct cmdline_options *); 00117 #define forbid_setid(s) forbid_setid((s), opt) 00118 00119 static struct { 00120 int argc; 00121 char **argv; 00122 } origarg; 00123 00124 static void 00125 usage(const char *name) 00126 { 00127 /* This message really ought to be max 23 lines. 00128 * Removed -h because the user already knows that option. Others? */ 00129 00130 static const char *const usage_msg[] = { 00131 "-0[octal] specify record separator (\\0, if no argument)", 00132 "-a autosplit mode with -n or -p (splits $_ into $F)", 00133 "-c check syntax only", 00134 "-Cdirectory cd to directory, before executing your script", 00135 "-d set debugging flags (set $DEBUG to true)", 00136 "-e 'command' one line of script. Several -e's allowed. Omit [programfile]", 00137 "-Eex[:in] specify the default external and internal character encodings", 00138 "-Fpattern split() pattern for autosplit (-a)", 00139 "-i[extension] edit ARGV files in place (make backup if extension supplied)", 00140 "-Idirectory specify $LOAD_PATH directory (may be used more than once)", 00141 "-l enable line ending processing", 00142 "-n assume 'while gets(); ... end' loop around your script", 00143 "-p assume loop like -n but print line also like sed", 00144 "-rlibrary require the library, before executing your script", 00145 "-s enable some switch parsing for switches after script name", 00146 "-S look for the script using PATH environment variable", 00147 "-T[level=1] turn on tainting checks", 00148 "-v print version number, then turn on verbose mode", 00149 "-w turn warnings on for your script", 00150 "-W[level=2] set warning level; 0=silence, 1=medium, 2=verbose", 00151 "-x[directory] strip off text before #!ruby line and perhaps cd to directory", 00152 "--copyright print the copyright", 00153 "--version print the version", 00154 NULL 00155 }; 00156 const char *const *p = usage_msg; 00157 00158 printf("Usage: %s [switches] [--] [programfile] [arguments]\n", name); 00159 while (*p) 00160 printf(" %s\n", *p++); 00161 } 00162 00163 #ifdef MANGLED_PATH 00164 static VALUE 00165 rubylib_mangled_path(const char *s, unsigned int l) 00166 { 00167 static char *newp, *oldp; 00168 static int newl, oldl, notfound; 00169 char *ptr; 00170 VALUE ret; 00171 00172 if (!newp && !notfound) { 00173 newp = getenv("RUBYLIB_PREFIX"); 00174 if (newp) { 00175 oldp = newp = strdup(newp); 00176 while (*newp && !ISSPACE(*newp) && *newp != ';') { 00177 newp = CharNext(newp); /* Skip digits. */ 00178 } 00179 oldl = newp - oldp; 00180 while (*newp && (ISSPACE(*newp) || *newp == ';')) { 00181 newp = CharNext(newp); /* Skip whitespace. */ 00182 } 00183 newl = strlen(newp); 00184 if (newl == 0 || oldl == 0) { 00185 rb_fatal("malformed RUBYLIB_PREFIX"); 00186 } 00187 translit_char(newp, '\\', '/'); 00188 } 00189 else { 00190 notfound = 1; 00191 } 00192 } 00193 if (!newp || l < oldl || STRNCASECMP(oldp, s, oldl) != 0) { 00194 return rb_str_new(s, l); 00195 } 00196 ret = rb_str_new(0, l + newl - oldl); 00197 ptr = RSTRING_PTR(ret); 00198 memcpy(ptr, newp, newl); 00199 memcpy(ptr + newl, s + oldl, l - oldl); 00200 ptr[l + newl - oldl] = 0; 00201 return ret; 00202 } 00203 #else 00204 #define rubylib_mangled_path rb_str_new 00205 #endif 00206 00207 static void 00208 push_include(const char *path, VALUE (*filter)(VALUE)) 00209 { 00210 const char sep = PATH_SEP_CHAR; 00211 const char *p, *s; 00212 VALUE load_path = GET_VM()->load_path; 00213 00214 p = path; 00215 while (*p) { 00216 while (*p == sep) 00217 p++; 00218 if (!*p) break; 00219 for (s = p; *s && *s != sep; s = CharNext(s)); 00220 rb_ary_push(load_path, (*filter)(rubylib_mangled_path(p, s - p))); 00221 p = s; 00222 } 00223 } 00224 00225 #ifdef __CYGWIN__ 00226 static void 00227 push_include_cygwin(const char *path, VALUE (*filter)(VALUE)) 00228 { 00229 const char *p, *s; 00230 char rubylib[FILENAME_MAX]; 00231 VALUE buf = 0; 00232 00233 p = path; 00234 while (*p) { 00235 unsigned int len; 00236 while (*p == ';') 00237 p++; 00238 if (!*p) break; 00239 for (s = p; *s && *s != ';'; s = CharNext(s)); 00240 len = s - p; 00241 if (*s) { 00242 if (!buf) { 00243 buf = rb_str_new(p, len); 00244 p = RSTRING_PTR(buf); 00245 } 00246 else { 00247 rb_str_resize(buf, len); 00248 p = strncpy(RSTRING_PTR(buf), p, len); 00249 } 00250 } 00251 #ifdef HAVE_CYGWIN_CONV_PATH 00252 #define CONV_TO_POSIX_PATH(p, lib) \ 00253 cygwin_conv_path(CCP_WIN_A_TO_POSIX|CCP_RELATIVE, (p), (lib), sizeof(lib)) 00254 #else 00255 #define CONV_TO_POSIX_PATH(p, lib) \ 00256 cygwin_conv_to_posix_path((p), (lib)) 00257 #endif 00258 if (CONV_TO_POSIX_PATH(p, rubylib) == 0) 00259 p = rubylib; 00260 push_include(p, filter); 00261 if (!*s) break; 00262 p = s + 1; 00263 } 00264 } 00265 00266 #define push_include push_include_cygwin 00267 #endif 00268 00269 void 00270 ruby_push_include(const char *path, VALUE (*filter)(VALUE)) 00271 { 00272 if (path == 0) 00273 return; 00274 push_include(path, filter); 00275 } 00276 00277 static VALUE 00278 identical_path(VALUE path) 00279 { 00280 return path; 00281 } 00282 static VALUE 00283 locale_path(VALUE path) 00284 { 00285 rb_enc_associate(path, rb_locale_encoding()); 00286 return path; 00287 } 00288 00289 void 00290 ruby_incpush(const char *path) 00291 { 00292 ruby_push_include(path, locale_path); 00293 } 00294 00295 static VALUE 00296 expand_include_path(VALUE path) 00297 { 00298 char *p = RSTRING_PTR(path); 00299 if (!p) 00300 return path; 00301 if (*p == '.' && p[1] == '/') 00302 return path; 00303 return rb_file_expand_path(path, Qnil); 00304 } 00305 00306 void 00307 ruby_incpush_expand(const char *path) 00308 { 00309 ruby_push_include(path, expand_include_path); 00310 } 00311 00312 #if defined _WIN32 || defined __CYGWIN__ 00313 static HMODULE libruby; 00314 00315 BOOL WINAPI 00316 DllMain(HINSTANCE dll, DWORD reason, LPVOID reserved) 00317 { 00318 if (reason == DLL_PROCESS_ATTACH) 00319 libruby = dll; 00320 return TRUE; 00321 } 00322 00323 HANDLE 00324 rb_libruby_handle(void) 00325 { 00326 return libruby; 00327 } 00328 #endif 00329 00330 void ruby_init_loadpath_safe(int safe_level); 00331 00332 void 00333 ruby_init_loadpath(void) 00334 { 00335 ruby_init_loadpath_safe(0); 00336 } 00337 00338 void 00339 ruby_init_loadpath_safe(int safe_level) 00340 { 00341 VALUE load_path; 00342 ID id_initial_load_path_mark; 00343 extern const char ruby_initial_load_paths[]; 00344 const char *paths = ruby_initial_load_paths; 00345 #if defined LOAD_RELATIVE 00346 # if defined HAVE_DLADDR || defined HAVE_CYGWIN_CONV_PATH 00347 # define VARIABLE_LIBPATH 1 00348 # else 00349 # define VARIABLE_LIBPATH 0 00350 # endif 00351 # if VARIABLE_LIBPATH 00352 char *libpath; 00353 VALUE sopath; 00354 # else 00355 char libpath[MAXPATHLEN + 1]; 00356 # endif 00357 size_t baselen; 00358 char *p; 00359 00360 #if defined _WIN32 || defined __CYGWIN__ 00361 # if VARIABLE_LIBPATH 00362 sopath = rb_str_new(0, MAXPATHLEN); 00363 libpath = RSTRING_PTR(sopath); 00364 GetModuleFileName(libruby, libpath, MAXPATHLEN); 00365 # else 00366 GetModuleFileName(libruby, libpath, sizeof libpath); 00367 # endif 00368 #elif defined(__EMX__) 00369 _execname(libpath, sizeof(libpath) - 1); 00370 #elif defined(HAVE_DLADDR) 00371 Dl_info dli; 00372 if (dladdr((void *)(VALUE)expand_include_path, &dli)) { 00373 char fbuf[MAXPATHLEN]; 00374 char *f = dln_find_file_r(dli.dli_fname, getenv(PATH_ENV), fbuf, sizeof(fbuf)); 00375 VALUE fname = rb_str_new_cstr(f ? f : dli.dli_fname); 00376 rb_str_freeze(fname); 00377 sopath = rb_realpath_internal(Qnil, fname, 1); 00378 } 00379 else { 00380 sopath = rb_str_new(0, 0); 00381 } 00382 libpath = RSTRING_PTR(sopath); 00383 #endif 00384 00385 #if !VARIABLE_LIBPATH 00386 libpath[sizeof(libpath) - 1] = '\0'; 00387 #endif 00388 #if defined DOSISH 00389 translit_char(libpath, '\\', '/'); 00390 #elif defined __CYGWIN__ 00391 { 00392 # if VARIABLE_LIBPATH 00393 const int win_to_posix = CCP_WIN_A_TO_POSIX | CCP_RELATIVE; 00394 size_t newsize = cygwin_conv_path(win_to_posix, libpath, 0, 0); 00395 if (newsize > 0) { 00396 VALUE rubylib = rb_str_new(0, newsize); 00397 p = RSTRING_PTR(rubylib); 00398 if (cygwin_conv_path(win_to_posix, libpath, p, newsize) == 0) { 00399 rb_str_resize(sopath, 0); 00400 sopath = rubylib; 00401 libpath = p; 00402 } 00403 } 00404 # else 00405 char rubylib[FILENAME_MAX]; 00406 cygwin_conv_to_posix_path(libpath, rubylib); 00407 strncpy(libpath, rubylib, sizeof(libpath)); 00408 # endif 00409 } 00410 #endif 00411 p = strrchr(libpath, '/'); 00412 if (p) { 00413 static const char bindir[] = "/bin"; 00414 #ifdef LIBDIR_BASENAME 00415 static const char libdir[] = "/"LIBDIR_BASENAME; 00416 #else 00417 static const char libdir[] = "/lib"; 00418 #endif 00419 const ptrdiff_t bindir_len = (ptrdiff_t)sizeof(bindir) - 1; 00420 const ptrdiff_t libdir_len = (ptrdiff_t)sizeof(libdir) - 1; 00421 *p = 0; 00422 if (p - libpath >= bindir_len && !STRCASECMP(p - bindir_len, bindir)) { 00423 p -= bindir_len; 00424 *p = 0; 00425 } 00426 else if (p - libpath >= libdir_len && !STRCASECMP(p - libdir_len, libdir)) { 00427 p -= libdir_len; 00428 *p = 0; 00429 } 00430 } 00431 #if !VARIABLE_LIBPATH 00432 else { 00433 strlcpy(libpath, ".", sizeof(libpath)); 00434 p = libpath + 1; 00435 } 00436 baselen = p - libpath; 00437 #define PREFIX_PATH() rb_str_new(libpath, baselen) 00438 #else 00439 baselen = p - libpath; 00440 rb_str_resize(sopath, baselen); 00441 libpath = RSTRING_PTR(sopath); 00442 #define PREFIX_PATH() sopath 00443 #endif 00444 00445 #define BASEPATH() rb_str_buf_cat(rb_str_buf_new(baselen+len), libpath, baselen) 00446 00447 #define RUBY_RELATIVE(path, len) rb_str_buf_cat(BASEPATH(), (path), (len)) 00448 #else 00449 static const char exec_prefix[] = RUBY_EXEC_PREFIX; 00450 #define RUBY_RELATIVE(path, len) rubylib_mangled_path((path), (len)) 00451 #define PREFIX_PATH() RUBY_RELATIVE(exec_prefix, sizeof(exec_prefix)-1) 00452 #endif 00453 load_path = GET_VM()->load_path; 00454 00455 if (safe_level == 0) { 00456 #ifdef MANGLED_PATH 00457 rubylib_mangled_path("", 0); 00458 #endif 00459 ruby_push_include(getenv("RUBYLIB"), identical_path); 00460 } 00461 00462 id_initial_load_path_mark = rb_intern_const("@gem_prelude_index"); 00463 while (*paths) { 00464 size_t len = strlen(paths); 00465 VALUE path = RUBY_RELATIVE(paths, len); 00466 rb_ivar_set(path, id_initial_load_path_mark, path); 00467 rb_ary_push(load_path, path); 00468 paths += len + 1; 00469 } 00470 00471 rb_const_set(rb_cObject, rb_intern_const("TMP_RUBY_PREFIX"), rb_obj_freeze(PREFIX_PATH())); 00472 } 00473 00474 00475 static void 00476 add_modules(VALUE *req_list, const char *mod) 00477 { 00478 VALUE list = *req_list; 00479 00480 if (!list) { 00481 *req_list = list = rb_ary_new(); 00482 RBASIC(list)->klass = 0; 00483 } 00484 rb_ary_push(list, rb_obj_freeze(rb_str_new2(mod))); 00485 } 00486 00487 static void 00488 require_libraries(VALUE *req_list) 00489 { 00490 VALUE list = *req_list; 00491 VALUE self = rb_vm_top_self(); 00492 ID require; 00493 rb_thread_t *th = GET_THREAD(); 00494 rb_block_t *prev_base_block = th->base_block; 00495 int prev_parse_in_eval = th->parse_in_eval; 00496 th->base_block = 0; 00497 th->parse_in_eval = 0; 00498 00499 Init_ext(); /* should be called here for some reason :-( */ 00500 CONST_ID(require, "require"); 00501 while (list && RARRAY_LEN(list) > 0) { 00502 VALUE feature = rb_ary_shift(list); 00503 rb_funcall2(self, require, 1, &feature); 00504 } 00505 *req_list = 0; 00506 00507 th->parse_in_eval = prev_parse_in_eval; 00508 th->base_block = prev_base_block; 00509 } 00510 00511 static void 00512 process_sflag(int *sflag) 00513 { 00514 if (*sflag > 0) { 00515 long n; 00516 VALUE *args; 00517 VALUE argv = rb_argv; 00518 00519 n = RARRAY_LEN(argv); 00520 args = RARRAY_PTR(argv); 00521 while (n > 0) { 00522 VALUE v = *args++; 00523 char *s = StringValuePtr(v); 00524 char *p; 00525 int hyphen = FALSE; 00526 00527 if (s[0] != '-') 00528 break; 00529 n--; 00530 if (s[1] == '-' && s[2] == '\0') 00531 break; 00532 00533 v = Qtrue; 00534 /* check if valid name before replacing - with _ */ 00535 for (p = s + 1; *p; p++) { 00536 if (*p == '=') { 00537 *p++ = '\0'; 00538 v = rb_str_new2(p); 00539 break; 00540 } 00541 if (*p == '-') { 00542 hyphen = TRUE; 00543 } 00544 else if (*p != '_' && !ISALNUM(*p)) { 00545 VALUE name_error[2]; 00546 name_error[0] = 00547 rb_str_new2("invalid name for global variable - "); 00548 if (!(p = strchr(p, '='))) { 00549 rb_str_cat2(name_error[0], s); 00550 } 00551 else { 00552 rb_str_cat(name_error[0], s, p - s); 00553 } 00554 name_error[1] = args[-1]; 00555 rb_exc_raise(rb_class_new_instance(2, name_error, rb_eNameError)); 00556 } 00557 } 00558 s[0] = '$'; 00559 if (hyphen) { 00560 for (p = s + 1; *p; ++p) { 00561 if (*p == '-') 00562 *p = '_'; 00563 } 00564 } 00565 rb_gv_set(s, v); 00566 } 00567 n = RARRAY_LEN(argv) - n; 00568 while (n--) { 00569 rb_ary_shift(argv); 00570 } 00571 *sflag = -1; 00572 } 00573 } 00574 00575 static long proc_options(long argc, char **argv, struct cmdline_options *opt, int envopt); 00576 00577 static void 00578 moreswitches(const char *s, struct cmdline_options *opt, int envopt) 00579 { 00580 long argc, i, len; 00581 char **argv, *p; 00582 const char *ap = 0; 00583 VALUE argstr, argary; 00584 00585 while (ISSPACE(*s)) s++; 00586 if (!*s) return; 00587 argstr = rb_str_tmp_new((len = strlen(s)) + 2); 00588 argary = rb_str_tmp_new(0); 00589 00590 p = RSTRING_PTR(argstr); 00591 *p++ = ' '; 00592 memcpy(p, s, len + 1); 00593 ap = 0; 00594 rb_str_cat(argary, (char *)&ap, sizeof(ap)); 00595 while (*p) { 00596 ap = p; 00597 rb_str_cat(argary, (char *)&ap, sizeof(ap)); 00598 while (*p && !ISSPACE(*p)) ++p; 00599 if (!*p) break; 00600 *p++ = '\0'; 00601 while (ISSPACE(*p)) ++p; 00602 } 00603 argc = RSTRING_LEN(argary) / sizeof(ap); 00604 ap = 0; 00605 rb_str_cat(argary, (char *)&ap, sizeof(ap)); 00606 argv = (char **)RSTRING_PTR(argary); 00607 00608 while ((i = proc_options(argc, argv, opt, envopt)) > 1 && (argc -= i) > 0) { 00609 argv += i; 00610 if (**argv != '-') { 00611 *--*argv = '-'; 00612 } 00613 if ((*argv)[1]) { 00614 ++argc; 00615 --argv; 00616 } 00617 } 00618 00619 /* get rid of GC */ 00620 rb_str_resize(argary, 0); 00621 rb_str_resize(argstr, 0); 00622 } 00623 00624 #define NAME_MATCH_P(name, str, len) \ 00625 ((len) < (int)sizeof(name) && strncmp((str), (name), (len)) == 0) 00626 00627 #define UNSET_WHEN(name, bit, str, len) \ 00628 if (NAME_MATCH_P((name), (str), (len))) { \ 00629 *(unsigned int *)arg &= ~(bit); \ 00630 return; \ 00631 } 00632 00633 #define SET_WHEN(name, bit, str, len) \ 00634 if (NAME_MATCH_P((name), (str), (len))) { \ 00635 *(unsigned int *)arg |= (bit); \ 00636 return; \ 00637 } 00638 00639 static void 00640 enable_option(const char *str, int len, void *arg) 00641 { 00642 #define UNSET_WHEN_DISABLE(bit) UNSET_WHEN(#bit, DISABLE_BIT(bit), str, len) 00643 UNSET_WHEN_DISABLE(gems); 00644 UNSET_WHEN_DISABLE(rubyopt); 00645 if (NAME_MATCH_P("all", str, len)) { 00646 *(unsigned int *)arg = 0U; 00647 return; 00648 } 00649 rb_warn("unknown argument for --enable: `%.*s'", len, str); 00650 } 00651 00652 static void 00653 disable_option(const char *str, int len, void *arg) 00654 { 00655 #define SET_WHEN_DISABLE(bit) SET_WHEN(#bit, DISABLE_BIT(bit), str, len) 00656 SET_WHEN_DISABLE(gems); 00657 SET_WHEN_DISABLE(rubyopt); 00658 if (NAME_MATCH_P("all", str, len)) { 00659 *(unsigned int *)arg = ~0U; 00660 return; 00661 } 00662 rb_warn("unknown argument for --disable: `%.*s'", len, str); 00663 } 00664 00665 static void 00666 dump_option(const char *str, int len, void *arg) 00667 { 00668 #define SET_WHEN_DUMP(bit) SET_WHEN(#bit, DUMP_BIT(bit), str, len) 00669 SET_WHEN_DUMP(version); 00670 SET_WHEN_DUMP(copyright); 00671 SET_WHEN_DUMP(usage); 00672 SET_WHEN_DUMP(yydebug); 00673 SET_WHEN_DUMP(syntax); 00674 SET_WHEN_DUMP(parsetree); 00675 SET_WHEN_DUMP(parsetree_with_comment); 00676 SET_WHEN_DUMP(insns); 00677 rb_warn("don't know how to dump `%.*s',", len, str); 00678 rb_warn("but only [version, copyright, usage, yydebug, syntax, parsetree, parsetree_with_comment, insns]."); 00679 } 00680 00681 static void 00682 set_option_encoding_once(const char *type, VALUE *name, const char *e, long elen) 00683 { 00684 VALUE ename; 00685 00686 if (!elen) elen = strlen(e); 00687 ename = rb_str_new(e, elen); 00688 00689 if (*name && 00690 rb_funcall(ename, rb_intern("casecmp"), 1, *name) != INT2FIX(0)) { 00691 rb_raise(rb_eRuntimeError, 00692 "%s already set to %s", type, RSTRING_PTR(*name)); 00693 } 00694 *name = ename; 00695 } 00696 00697 #define set_internal_encoding_once(opt, e, elen) \ 00698 set_option_encoding_once("default_internal", &(opt)->intern.enc.name, (e), (elen)) 00699 #define set_external_encoding_once(opt, e, elen) \ 00700 set_option_encoding_once("default_external", &(opt)->ext.enc.name, (e), (elen)) 00701 #define set_source_encoding_once(opt, e, elen) \ 00702 set_option_encoding_once("source", &(opt)->src.enc.name, (e), (elen)) 00703 00704 static long 00705 proc_options(long argc, char **argv, struct cmdline_options *opt, int envopt) 00706 { 00707 long n, argc0 = argc; 00708 const char *s; 00709 00710 if (argc == 0) 00711 return 0; 00712 00713 for (argc--, argv++; argc > 0; argc--, argv++) { 00714 const char *const arg = argv[0]; 00715 if (arg[0] != '-' || !arg[1]) 00716 break; 00717 00718 s = arg + 1; 00719 reswitch: 00720 switch (*s) { 00721 case 'a': 00722 if (envopt) goto noenvopt; 00723 opt->do_split = TRUE; 00724 s++; 00725 goto reswitch; 00726 00727 case 'p': 00728 if (envopt) goto noenvopt; 00729 opt->do_print = TRUE; 00730 /* through */ 00731 case 'n': 00732 if (envopt) goto noenvopt; 00733 opt->do_loop = TRUE; 00734 s++; 00735 goto reswitch; 00736 00737 case 'd': 00738 ruby_debug = Qtrue; 00739 ruby_verbose = Qtrue; 00740 s++; 00741 goto reswitch; 00742 00743 case 'y': 00744 if (envopt) goto noenvopt; 00745 opt->dump |= DUMP_BIT(yydebug); 00746 s++; 00747 goto reswitch; 00748 00749 case 'v': 00750 if (opt->verbose) { 00751 s++; 00752 goto reswitch; 00753 } 00754 ruby_show_version(); 00755 opt->verbose = 1; 00756 case 'w': 00757 ruby_verbose = Qtrue; 00758 s++; 00759 goto reswitch; 00760 00761 case 'W': 00762 { 00763 size_t numlen; 00764 int v = 2; /* -W as -W2 */ 00765 00766 if (*++s) { 00767 v = scan_oct(s, 1, &numlen); 00768 if (numlen == 0) 00769 v = 1; 00770 s += numlen; 00771 } 00772 switch (v) { 00773 case 0: 00774 ruby_verbose = Qnil; 00775 break; 00776 case 1: 00777 ruby_verbose = Qfalse; 00778 break; 00779 default: 00780 ruby_verbose = Qtrue; 00781 break; 00782 } 00783 } 00784 goto reswitch; 00785 00786 case 'c': 00787 if (envopt) goto noenvopt; 00788 opt->dump |= DUMP_BIT(syntax); 00789 s++; 00790 goto reswitch; 00791 00792 case 's': 00793 if (envopt) goto noenvopt; 00794 forbid_setid("-s"); 00795 if (!opt->sflag) opt->sflag = 1; 00796 s++; 00797 goto reswitch; 00798 00799 case 'h': 00800 if (envopt) goto noenvopt; 00801 opt->dump |= DUMP_BIT(usage); 00802 goto switch_end; 00803 00804 case 'l': 00805 if (envopt) goto noenvopt; 00806 opt->do_line = TRUE; 00807 rb_output_rs = rb_rs; 00808 s++; 00809 goto reswitch; 00810 00811 case 'S': 00812 if (envopt) goto noenvopt; 00813 forbid_setid("-S"); 00814 opt->do_search = TRUE; 00815 s++; 00816 goto reswitch; 00817 00818 case 'e': 00819 if (envopt) goto noenvopt; 00820 forbid_setid("-e"); 00821 if (!*++s) { 00822 s = argv[1]; 00823 argc--, argv++; 00824 } 00825 if (!s) { 00826 rb_raise(rb_eRuntimeError, "no code specified for -e"); 00827 } 00828 if (!opt->e_script) { 00829 opt->e_script = rb_str_new(0, 0); 00830 if (opt->script == 0) 00831 opt->script = "-e"; 00832 } 00833 rb_str_cat2(opt->e_script, s); 00834 rb_str_cat2(opt->e_script, "\n"); 00835 break; 00836 00837 case 'r': 00838 forbid_setid("-r"); 00839 if (*++s) { 00840 add_modules(&opt->req_list, s); 00841 } 00842 else if (argv[1]) { 00843 add_modules(&opt->req_list, argv[1]); 00844 argc--, argv++; 00845 } 00846 break; 00847 00848 case 'i': 00849 if (envopt) goto noenvopt; 00850 forbid_setid("-i"); 00851 ruby_set_inplace_mode(s + 1); 00852 break; 00853 00854 case 'x': 00855 if (envopt) goto noenvopt; 00856 opt->xflag = TRUE; 00857 s++; 00858 if (*s && chdir(s) < 0) { 00859 rb_fatal("Can't chdir to %s", s); 00860 } 00861 break; 00862 00863 case 'C': 00864 case 'X': 00865 if (envopt) goto noenvopt; 00866 s++; 00867 if (!*s) { 00868 s = argv[1]; 00869 argc--, argv++; 00870 } 00871 if (!s || !*s) { 00872 rb_fatal("Can't chdir"); 00873 } 00874 if (chdir(s) < 0) { 00875 rb_fatal("Can't chdir to %s", s); 00876 } 00877 break; 00878 00879 case 'F': 00880 if (envopt) goto noenvopt; 00881 if (*++s) { 00882 rb_fs = rb_reg_new(s, strlen(s), 0); 00883 } 00884 break; 00885 00886 case 'E': 00887 if (!*++s && (!--argc || !(s = *++argv))) { 00888 rb_raise(rb_eRuntimeError, "missing argument for -E"); 00889 } 00890 goto encoding; 00891 00892 case 'U': 00893 set_internal_encoding_once(opt, "UTF-8", 0); 00894 ++s; 00895 goto reswitch; 00896 00897 case 'K': 00898 if (*++s) { 00899 const char *enc_name = 0; 00900 switch (*s) { 00901 case 'E': case 'e': 00902 enc_name = "EUC-JP"; 00903 break; 00904 case 'S': case 's': 00905 enc_name = "Windows-31J"; 00906 break; 00907 case 'U': case 'u': 00908 enc_name = "UTF-8"; 00909 break; 00910 case 'N': case 'n': case 'A': case 'a': 00911 enc_name = "ASCII-8BIT"; 00912 break; 00913 } 00914 if (enc_name) { 00915 opt->src.enc.name = rb_str_new2(enc_name); 00916 if (!opt->ext.enc.name) 00917 opt->ext.enc.name = opt->src.enc.name; 00918 } 00919 s++; 00920 } 00921 goto reswitch; 00922 00923 case 'T': 00924 { 00925 size_t numlen; 00926 int v = 1; 00927 00928 if (*++s) { 00929 v = scan_oct(s, 2, &numlen); 00930 if (numlen == 0) 00931 v = 1; 00932 s += numlen; 00933 } 00934 if (v > opt->safe_level) opt->safe_level = v; 00935 } 00936 goto reswitch; 00937 00938 case 'I': 00939 forbid_setid("-I"); 00940 if (*++s) 00941 ruby_incpush_expand(s); 00942 else if (argv[1]) { 00943 ruby_incpush_expand(argv[1]); 00944 argc--, argv++; 00945 } 00946 break; 00947 00948 case '0': 00949 if (envopt) goto noenvopt; 00950 { 00951 size_t numlen; 00952 int v; 00953 char c; 00954 00955 v = scan_oct(s, 4, &numlen); 00956 s += numlen; 00957 if (v > 0377) 00958 rb_rs = Qnil; 00959 else if (v == 0 && numlen >= 2) { 00960 rb_rs = rb_str_new2("\n\n"); 00961 } 00962 else { 00963 c = v & 0xff; 00964 rb_rs = rb_str_new(&c, 1); 00965 } 00966 } 00967 goto reswitch; 00968 00969 case '-': 00970 if (!s[1] || (s[1] == '\r' && !s[2])) { 00971 argc--, argv++; 00972 goto switch_end; 00973 } 00974 s++; 00975 00976 # define is_option_end(c, allow_hyphen) \ 00977 (!(c) || ((allow_hyphen) && (c) == '-') || (c) == '=') 00978 # define check_envopt(name, allow_envopt) \ 00979 (((allow_envopt) || !envopt) ? (void)0 : \ 00980 rb_raise(rb_eRuntimeError, "invalid switch in RUBYOPT: --" name)) 00981 # define need_argument(name, s) \ 00982 ((*(s)++ ? !*(s) : (!--argc || !((s) = *++argv))) ? \ 00983 rb_raise(rb_eRuntimeError, "missing argument for --" name) \ 00984 : (void)0) 00985 # define is_option_with_arg(name, allow_hyphen, allow_envopt) \ 00986 (strncmp((name), s, n = sizeof(name) - 1) == 0 && is_option_end(s[n], (allow_hyphen)) ? \ 00987 (check_envopt(name, (allow_envopt)), s += n, need_argument(name, s), 1) : 0) 00988 00989 if (strcmp("copyright", s) == 0) { 00990 if (envopt) goto noenvopt_long; 00991 opt->dump |= DUMP_BIT(copyright); 00992 } 00993 else if (strcmp("debug", s) == 0) { 00994 ruby_debug = Qtrue; 00995 ruby_verbose = Qtrue; 00996 } 00997 else if (is_option_with_arg("enable", Qtrue, Qtrue)) { 00998 ruby_each_words(s, enable_option, &opt->disable); 00999 } 01000 else if (is_option_with_arg("disable", Qtrue, Qtrue)) { 01001 ruby_each_words(s, disable_option, &opt->disable); 01002 } 01003 else if (is_option_with_arg("encoding", Qfalse, Qtrue)) { 01004 char *p; 01005 encoding: 01006 do { 01007 # define set_encoding_part(type) \ 01008 if (!(p = strchr(s, ':'))) { \ 01009 set_##type##_encoding_once(opt, s, 0); \ 01010 break; \ 01011 } \ 01012 else if (p > s) { \ 01013 set_##type##_encoding_once(opt, s, p-s); \ 01014 } 01015 set_encoding_part(external); 01016 if (!*(s = ++p)) break; 01017 set_encoding_part(internal); 01018 if (!*(s = ++p)) break; 01019 #if defined ALLOW_DEFAULT_SOURCE_ENCODING && ALLOW_DEFAULT_SOURCE_ENCODING 01020 set_encoding_part(source); 01021 if (!*(s = ++p)) break; 01022 #endif 01023 rb_raise(rb_eRuntimeError, "extra argument for %s: %s", 01024 (arg[1] == '-' ? "--encoding" : "-E"), s); 01025 # undef set_encoding_part 01026 } while (0); 01027 } 01028 else if (is_option_with_arg("internal-encoding", Qfalse, Qtrue)) { 01029 set_internal_encoding_once(opt, s, 0); 01030 } 01031 else if (is_option_with_arg("external-encoding", Qfalse, Qtrue)) { 01032 set_external_encoding_once(opt, s, 0); 01033 } 01034 #if defined ALLOW_DEFAULT_SOURCE_ENCODING && ALLOW_DEFAULT_SOURCE_ENCODING 01035 else if (is_option_with_arg("source-encoding", Qfalse, Qtrue)) { 01036 set_source_encoding_once(opt, s, 0); 01037 } 01038 #endif 01039 else if (strcmp("version", s) == 0) { 01040 if (envopt) goto noenvopt_long; 01041 opt->dump |= DUMP_BIT(version); 01042 } 01043 else if (strcmp("verbose", s) == 0) { 01044 opt->verbose = 1; 01045 ruby_verbose = Qtrue; 01046 } 01047 else if (strcmp("yydebug", s) == 0) { 01048 if (envopt) goto noenvopt_long; 01049 opt->dump |= DUMP_BIT(yydebug); 01050 } 01051 else if (is_option_with_arg("dump", Qfalse, Qfalse)) { 01052 ruby_each_words(s, dump_option, &opt->dump); 01053 } 01054 else if (strcmp("help", s) == 0) { 01055 if (envopt) goto noenvopt_long; 01056 opt->dump |= DUMP_BIT(usage); 01057 goto switch_end; 01058 } 01059 else { 01060 rb_raise(rb_eRuntimeError, 01061 "invalid option --%s (-h will show valid options)", s); 01062 } 01063 break; 01064 01065 case '\r': 01066 if (!s[1]) 01067 break; 01068 01069 default: 01070 { 01071 if (ISPRINT(*s)) { 01072 rb_raise(rb_eRuntimeError, 01073 "invalid option -%c (-h will show valid options)", 01074 (int)(unsigned char)*s); 01075 } 01076 else { 01077 rb_raise(rb_eRuntimeError, 01078 "invalid option -\\x%02X (-h will show valid options)", 01079 (int)(unsigned char)*s); 01080 } 01081 } 01082 goto switch_end; 01083 01084 noenvopt: 01085 /* "EIdvwWrKU" only */ 01086 rb_raise(rb_eRuntimeError, "invalid switch in RUBYOPT: -%c", *s); 01087 break; 01088 01089 noenvopt_long: 01090 rb_raise(rb_eRuntimeError, "invalid switch in RUBYOPT: --%s", s); 01091 break; 01092 01093 case 0: 01094 break; 01095 # undef is_option_end 01096 # undef check_envopt 01097 # undef need_argument 01098 # undef is_option_with_arg 01099 } 01100 } 01101 01102 switch_end: 01103 return argc0 - argc; 01104 } 01105 01106 static void 01107 ruby_init_prelude(void) 01108 { 01109 Init_prelude(); 01110 rb_const_remove(rb_cObject, rb_intern_const("TMP_RUBY_PREFIX")); 01111 } 01112 01113 static int 01114 opt_enc_index(VALUE enc_name) 01115 { 01116 const char *s = RSTRING_PTR(enc_name); 01117 int i = rb_enc_find_index(s); 01118 01119 if (i < 0) { 01120 rb_raise(rb_eRuntimeError, "unknown encoding name - %s", s); 01121 } 01122 else if (rb_enc_dummy_p(rb_enc_from_index(i))) { 01123 rb_raise(rb_eRuntimeError, "dummy encoding is not acceptable - %s ", s); 01124 } 01125 return i; 01126 } 01127 01128 #define rb_progname (GET_VM()->progname) 01129 VALUE rb_argv0; 01130 01131 static VALUE 01132 false_value(void) 01133 { 01134 return Qfalse; 01135 } 01136 01137 static VALUE 01138 true_value(void) 01139 { 01140 return Qtrue; 01141 } 01142 01143 #define rb_define_readonly_boolean(name, val) \ 01144 rb_define_virtual_variable((name), (val) ? true_value : false_value, 0) 01145 01146 static VALUE 01147 uscore_get(void) 01148 { 01149 VALUE line; 01150 01151 line = rb_lastline_get(); 01152 if (TYPE(line) != T_STRING) { 01153 rb_raise(rb_eTypeError, "$_ value need to be String (%s given)", 01154 NIL_P(line) ? "nil" : rb_obj_classname(line)); 01155 } 01156 return line; 01157 } 01158 01159 /* 01160 * call-seq: 01161 * sub(pattern, replacement) -> $_ 01162 * sub(pattern) { block } -> $_ 01163 * 01164 * Equivalent to <code>$_.sub(<i>args</i>)</code>, except that 01165 * <code>$_</code> will be updated if substitution occurs. 01166 * Available only when -p/-n command line option specified. 01167 */ 01168 01169 static VALUE 01170 rb_f_sub(argc, argv) 01171 int argc; 01172 VALUE *argv; 01173 { 01174 VALUE str = rb_funcall3(uscore_get(), rb_intern("sub"), argc, argv); 01175 rb_lastline_set(str); 01176 return str; 01177 } 01178 01179 /* 01180 * call-seq: 01181 * gsub(pattern, replacement) -> string 01182 * gsub(pattern) {|...| block } -> string 01183 * 01184 * Equivalent to <code>$_.gsub...</code>, except that <code>$_</code> 01185 * receives the modified result. 01186 * Available only when -p/-n command line option specified. 01187 * 01188 */ 01189 01190 static VALUE 01191 rb_f_gsub(argc, argv) 01192 int argc; 01193 VALUE *argv; 01194 { 01195 VALUE str = rb_funcall3(uscore_get(), rb_intern("gsub"), argc, argv); 01196 rb_lastline_set(str); 01197 return str; 01198 } 01199 01200 /* 01201 * call-seq: 01202 * chop -> string 01203 * 01204 * Equivalent to <code>($_.dup).chop!</code>, except <code>nil</code> 01205 * is never returned. See <code>String#chop!</code>. 01206 * Available only when -p/-n command line option specified. 01207 * 01208 */ 01209 01210 static VALUE 01211 rb_f_chop(void) 01212 { 01213 VALUE str = rb_funcall3(uscore_get(), rb_intern("chop"), 0, 0); 01214 rb_lastline_set(str); 01215 return str; 01216 } 01217 01218 01219 /* 01220 * call-seq: 01221 * chomp -> $_ 01222 * chomp(string) -> $_ 01223 * 01224 * Equivalent to <code>$_ = $_.chomp(<em>string</em>)</code>. See 01225 * <code>String#chomp</code>. 01226 * Available only when -p/-n command line option specified. 01227 * 01228 */ 01229 01230 static VALUE 01231 rb_f_chomp(argc, argv) 01232 int argc; 01233 VALUE *argv; 01234 { 01235 VALUE str = rb_funcall3(uscore_get(), rb_intern("chomp"), argc, argv); 01236 rb_lastline_set(str); 01237 return str; 01238 } 01239 01240 static VALUE 01241 process_options(int argc, char **argv, struct cmdline_options *opt) 01242 { 01243 NODE *tree = 0; 01244 VALUE parser; 01245 VALUE iseq; 01246 rb_encoding *enc, *lenc; 01247 const char *s; 01248 char fbuf[MAXPATHLEN]; 01249 int i = (int)proc_options(argc, argv, opt, 0); 01250 rb_thread_t *th = GET_THREAD(); 01251 rb_env_t *env = 0; 01252 01253 argc -= i; 01254 argv += i; 01255 01256 if (opt->dump & DUMP_BIT(usage)) { 01257 usage(origarg.argv[0]); 01258 return Qtrue; 01259 } 01260 01261 if (!(opt->disable & DISABLE_BIT(rubyopt)) && 01262 opt->safe_level == 0 && (s = getenv("RUBYOPT"))) { 01263 VALUE src_enc_name = opt->src.enc.name; 01264 VALUE ext_enc_name = opt->ext.enc.name; 01265 VALUE int_enc_name = opt->intern.enc.name; 01266 01267 opt->src.enc.name = opt->ext.enc.name = opt->intern.enc.name = 0; 01268 moreswitches(s, opt, 1); 01269 if (src_enc_name) 01270 opt->src.enc.name = src_enc_name; 01271 if (ext_enc_name) 01272 opt->ext.enc.name = ext_enc_name; 01273 if (int_enc_name) 01274 opt->intern.enc.name = int_enc_name; 01275 } 01276 01277 if (opt->dump & DUMP_BIT(version)) { 01278 ruby_show_version(); 01279 return Qtrue; 01280 } 01281 if (opt->dump & DUMP_BIT(copyright)) { 01282 ruby_show_copyright(); 01283 } 01284 01285 if (opt->safe_level >= 4) { 01286 OBJ_TAINT(rb_argv); 01287 OBJ_TAINT(GET_VM()->load_path); 01288 } 01289 01290 if (!opt->e_script) { 01291 if (argc == 0) { /* no more args */ 01292 if (opt->verbose) 01293 return Qtrue; 01294 opt->script = "-"; 01295 } 01296 else { 01297 opt->script = argv[0]; 01298 if (opt->script[0] == '\0') { 01299 opt->script = "-"; 01300 } 01301 else if (opt->do_search) { 01302 char *path = getenv("RUBYPATH"); 01303 01304 opt->script = 0; 01305 if (path) { 01306 opt->script = dln_find_file_r(argv[0], path, fbuf, sizeof(fbuf)); 01307 } 01308 if (!opt->script) { 01309 opt->script = dln_find_file_r(argv[0], getenv(PATH_ENV), fbuf, sizeof(fbuf)); 01310 } 01311 if (!opt->script) 01312 opt->script = argv[0]; 01313 } 01314 argc--; 01315 argv++; 01316 } 01317 } 01318 01319 opt->script_name = rb_str_new_cstr(opt->script); 01320 opt->script = RSTRING_PTR(opt->script_name); 01321 #if defined DOSISH || defined __CYGWIN__ 01322 translit_char(RSTRING_PTR(opt->script_name), '\\', '/'); 01323 #endif 01324 01325 ruby_init_loadpath_safe(opt->safe_level); 01326 rb_enc_find_index("encdb"); 01327 lenc = rb_locale_encoding(); 01328 rb_enc_associate(rb_progname, lenc); 01329 rb_obj_freeze(rb_progname); 01330 parser = rb_parser_new(); 01331 if (opt->dump & DUMP_BIT(yydebug)) { 01332 rb_parser_set_yydebug(parser, Qtrue); 01333 } 01334 if (opt->ext.enc.name != 0) { 01335 opt->ext.enc.index = opt_enc_index(opt->ext.enc.name); 01336 } 01337 if (opt->intern.enc.name != 0) { 01338 opt->intern.enc.index = opt_enc_index(opt->intern.enc.name); 01339 } 01340 if (opt->src.enc.name != 0) { 01341 opt->src.enc.index = opt_enc_index(opt->src.enc.name); 01342 src_encoding_index = opt->src.enc.index; 01343 } 01344 if (opt->ext.enc.index >= 0) { 01345 enc = rb_enc_from_index(opt->ext.enc.index); 01346 } 01347 else { 01348 enc = lenc; 01349 } 01350 rb_enc_set_default_external(rb_enc_from_encoding(enc)); 01351 if (opt->intern.enc.index >= 0) { 01352 enc = rb_enc_from_index(opt->intern.enc.index); 01353 rb_enc_set_default_internal(rb_enc_from_encoding(enc)); 01354 opt->intern.enc.index = -1; 01355 } 01356 rb_enc_associate(opt->script_name, lenc); 01357 rb_obj_freeze(opt->script_name); 01358 { 01359 long i; 01360 VALUE load_path = GET_VM()->load_path; 01361 for (i = 0; i < RARRAY_LEN(load_path); ++i) { 01362 rb_enc_associate(RARRAY_PTR(load_path)[i], lenc); 01363 } 01364 } 01365 if (!(opt->disable & DISABLE_BIT(gems))) { 01366 #if defined DISABLE_RUBYGEMS && DISABLE_RUBYGEMS 01367 rb_require("rubygems"); 01368 #else 01369 rb_define_module("Gem"); 01370 #endif 01371 } 01372 ruby_init_prelude(); 01373 ruby_set_argv(argc, argv); 01374 process_sflag(&opt->sflag); 01375 01376 { 01377 /* set eval context */ 01378 VALUE toplevel_binding = rb_const_get(rb_cObject, rb_intern("TOPLEVEL_BINDING")); 01379 rb_binding_t *bind; 01380 01381 GetBindingPtr(toplevel_binding, bind); 01382 GetEnvPtr(bind->env, env); 01383 } 01384 01385 #define PREPARE_PARSE_MAIN(expr) do { \ 01386 th->parse_in_eval--; \ 01387 th->base_block = &env->block; \ 01388 expr; \ 01389 th->parse_in_eval++; \ 01390 th->base_block = 0; \ 01391 } while (0) 01392 01393 if (opt->e_script) { 01394 VALUE progname = rb_progname; 01395 rb_encoding *eenc; 01396 if (opt->src.enc.index >= 0) { 01397 eenc = rb_enc_from_index(opt->src.enc.index); 01398 } 01399 else { 01400 eenc = lenc; 01401 } 01402 rb_enc_associate(opt->e_script, eenc); 01403 rb_vm_set_progname(rb_progname = opt->script_name); 01404 require_libraries(&opt->req_list); 01405 rb_vm_set_progname(rb_progname = progname); 01406 01407 PREPARE_PARSE_MAIN({ 01408 tree = rb_parser_compile_string(parser, opt->script, opt->e_script, 1); 01409 }); 01410 } 01411 else { 01412 if (opt->script[0] == '-' && !opt->script[1]) { 01413 forbid_setid("program input from stdin"); 01414 } 01415 01416 PREPARE_PARSE_MAIN({ 01417 tree = load_file(parser, opt->script, 1, opt); 01418 }); 01419 } 01420 rb_progname = opt->script_name; 01421 rb_vm_set_progname(rb_progname); 01422 if (opt->dump & DUMP_BIT(yydebug)) return Qtrue; 01423 01424 if (opt->ext.enc.index >= 0) { 01425 enc = rb_enc_from_index(opt->ext.enc.index); 01426 } 01427 else { 01428 enc = lenc; 01429 } 01430 rb_enc_set_default_external(rb_enc_from_encoding(enc)); 01431 if (opt->intern.enc.index >= 0) { 01432 /* Set in the shebang line */ 01433 enc = rb_enc_from_index(opt->intern.enc.index); 01434 rb_enc_set_default_internal(rb_enc_from_encoding(enc)); 01435 } 01436 else if (!rb_default_internal_encoding()) 01437 /* Freeze default_internal */ 01438 rb_enc_set_default_internal(Qnil); 01439 rb_stdio_set_default_encoding(); 01440 01441 if (!tree) return Qfalse; 01442 01443 process_sflag(&opt->sflag); 01444 opt->xflag = 0; 01445 01446 if (opt->safe_level >= 4) { 01447 FL_UNSET(rb_argv, FL_TAINT); 01448 FL_UNSET(GET_VM()->load_path, FL_TAINT); 01449 } 01450 01451 if (opt->dump & DUMP_BIT(syntax)) { 01452 printf("Syntax OK\n"); 01453 return Qtrue; 01454 } 01455 01456 if (opt->do_print) { 01457 PREPARE_PARSE_MAIN({ 01458 tree = rb_parser_append_print(parser, tree); 01459 }); 01460 } 01461 if (opt->do_loop) { 01462 PREPARE_PARSE_MAIN({ 01463 tree = rb_parser_while_loop(parser, tree, opt->do_line, opt->do_split); 01464 }); 01465 rb_define_global_function("sub", rb_f_sub, -1); 01466 rb_define_global_function("gsub", rb_f_gsub, -1); 01467 rb_define_global_function("chop", rb_f_chop, 0); 01468 rb_define_global_function("chomp", rb_f_chomp, -1); 01469 } 01470 01471 if (opt->dump & DUMP_BIT(parsetree) || opt->dump & DUMP_BIT(parsetree_with_comment)) { 01472 rb_io_write(rb_stdout, rb_parser_dump_tree(tree, opt->dump & DUMP_BIT(parsetree_with_comment))); 01473 rb_io_flush(rb_stdout); 01474 return Qtrue; 01475 } 01476 01477 PREPARE_PARSE_MAIN({ 01478 VALUE path = Qnil; 01479 if (!opt->e_script && strcmp(opt->script, "-")) 01480 path = rb_realpath_internal(Qnil, opt->script_name, 1); 01481 iseq = rb_iseq_new_main(tree, opt->script_name, path); 01482 }); 01483 01484 if (opt->dump & DUMP_BIT(insns)) { 01485 rb_io_write(rb_stdout, rb_iseq_disasm(iseq)); 01486 rb_io_flush(rb_stdout); 01487 return Qtrue; 01488 } 01489 01490 rb_define_readonly_boolean("$-p", opt->do_print); 01491 rb_define_readonly_boolean("$-l", opt->do_line); 01492 rb_define_readonly_boolean("$-a", opt->do_split); 01493 01494 rb_set_safe_level(opt->safe_level); 01495 rb_gc_set_params(); 01496 01497 return iseq; 01498 } 01499 01500 struct load_file_arg { 01501 VALUE parser; 01502 const char *fname; 01503 int script; 01504 struct cmdline_options *opt; 01505 }; 01506 01507 static VALUE 01508 load_file_internal(VALUE arg) 01509 { 01510 extern VALUE rb_stdin; 01511 struct load_file_arg *argp = (struct load_file_arg *)arg; 01512 VALUE parser = argp->parser; 01513 const char *fname = argp->fname; 01514 int script = argp->script; 01515 struct cmdline_options *opt = argp->opt; 01516 VALUE f; 01517 int line_start = 1; 01518 NODE *tree = 0; 01519 rb_encoding *enc; 01520 ID set_encoding; 01521 int xflag = 0; 01522 01523 if (!fname) 01524 rb_load_fail(fname); 01525 if (strcmp(fname, "-") == 0) { 01526 f = rb_stdin; 01527 } 01528 else { 01529 int fd, mode = O_RDONLY; 01530 #if defined DOSISH || defined __CYGWIN__ 01531 { 01532 const char *ext = strrchr(fname, '.'); 01533 if (ext && STRCASECMP(ext, ".exe") == 0) { 01534 mode |= O_BINARY; 01535 xflag = 1; 01536 } 01537 } 01538 #endif 01539 if ((fd = open(fname, mode)) < 0) { 01540 rb_load_fail(fname); 01541 } 01542 rb_update_max_fd(fd); 01543 01544 f = rb_io_fdopen(fd, mode, fname); 01545 } 01546 01547 CONST_ID(set_encoding, "set_encoding"); 01548 if (script) { 01549 VALUE c = 1; /* something not nil */ 01550 VALUE line; 01551 char *p; 01552 int no_src_enc = !opt->src.enc.name; 01553 int no_ext_enc = !opt->ext.enc.name; 01554 int no_int_enc = !opt->intern.enc.name; 01555 01556 enc = rb_ascii8bit_encoding(); 01557 rb_funcall(f, set_encoding, 1, rb_enc_from_encoding(enc)); 01558 01559 if (xflag || opt->xflag) { 01560 line_start--; 01561 search_shebang: 01562 forbid_setid("-x"); 01563 opt->xflag = FALSE; 01564 while (!NIL_P(line = rb_io_gets(f))) { 01565 line_start++; 01566 if (RSTRING_LEN(line) > 2 01567 && RSTRING_PTR(line)[0] == '#' 01568 && RSTRING_PTR(line)[1] == '!') { 01569 if ((p = strstr(RSTRING_PTR(line), "ruby")) != 0) { 01570 goto start_read; 01571 } 01572 } 01573 } 01574 rb_raise(rb_eLoadError, "no Ruby script found in input"); 01575 } 01576 01577 c = rb_io_getbyte(f); 01578 if (c == INT2FIX('#')) { 01579 c = rb_io_getbyte(f); 01580 if (c == INT2FIX('!')) { 01581 line = rb_io_gets(f); 01582 if (NIL_P(line)) 01583 return 0; 01584 01585 if ((p = strstr(RSTRING_PTR(line), "ruby")) == 0) { 01586 /* not ruby script, assume -x flag */ 01587 goto search_shebang; 01588 } 01589 01590 start_read: 01591 p += 4; 01592 RSTRING_PTR(line)[RSTRING_LEN(line) - 1] = '\0'; 01593 if (RSTRING_PTR(line)[RSTRING_LEN(line) - 2] == '\r') 01594 RSTRING_PTR(line)[RSTRING_LEN(line) - 2] = '\0'; 01595 if ((p = strstr(p, " -")) != 0) { 01596 moreswitches(p + 1, opt, 0); 01597 } 01598 01599 /* push back shebang for pragma may exist in next line */ 01600 rb_io_ungetbyte(f, rb_str_new2("!\n")); 01601 } 01602 else if (!NIL_P(c)) { 01603 rb_io_ungetbyte(f, c); 01604 } 01605 rb_io_ungetbyte(f, INT2FIX('#')); 01606 if (no_src_enc && opt->src.enc.name) { 01607 opt->src.enc.index = opt_enc_index(opt->src.enc.name); 01608 src_encoding_index = opt->src.enc.index; 01609 } 01610 if (no_ext_enc && opt->ext.enc.name) { 01611 opt->ext.enc.index = opt_enc_index(opt->ext.enc.name); 01612 } 01613 if (no_int_enc && opt->intern.enc.name) { 01614 opt->intern.enc.index = opt_enc_index(opt->intern.enc.name); 01615 } 01616 } 01617 else if (!NIL_P(c)) { 01618 rb_io_ungetbyte(f, c); 01619 } 01620 else { 01621 if (f != rb_stdin) rb_io_close(f); 01622 f = Qnil; 01623 } 01624 rb_vm_set_progname(rb_progname = opt->script_name); 01625 require_libraries(&opt->req_list); /* Why here? unnatural */ 01626 } 01627 if (opt->src.enc.index >= 0) { 01628 enc = rb_enc_from_index(opt->src.enc.index); 01629 } 01630 else if (f == rb_stdin) { 01631 enc = rb_locale_encoding(); 01632 } 01633 else { 01634 enc = rb_usascii_encoding(); 01635 } 01636 if (NIL_P(f)) { 01637 f = rb_str_new(0, 0); 01638 rb_enc_associate(f, enc); 01639 return (VALUE)rb_parser_compile_string(parser, fname, f, line_start); 01640 } 01641 rb_funcall(f, set_encoding, 2, rb_enc_from_encoding(enc), rb_str_new_cstr("-")); 01642 tree = rb_parser_compile_file(parser, fname, f, line_start); 01643 rb_funcall(f, set_encoding, 1, rb_parser_encoding(parser)); 01644 if (script && tree && rb_parser_end_seen_p(parser)) { 01645 /* 01646 * DATA is a File that contains the data section of the executed file. 01647 * To create a data section use <tt>__END__</tt>: 01648 * 01649 * $ cat t.rb 01650 * puts DATA.gets 01651 * __END__ 01652 * hello world! 01653 * 01654 * $ ruby t.rb 01655 * hello world! 01656 */ 01657 rb_define_global_const("DATA", f); 01658 } 01659 else if (f != rb_stdin) { 01660 rb_io_close(f); 01661 } 01662 return (VALUE)tree; 01663 } 01664 01665 static VALUE 01666 restore_lineno(VALUE lineno) 01667 { 01668 return rb_gv_set("$.", lineno); 01669 } 01670 01671 static NODE * 01672 load_file(VALUE parser, const char *fname, int script, struct cmdline_options *opt) 01673 { 01674 struct load_file_arg arg; 01675 arg.parser = parser; 01676 arg.fname = fname; 01677 arg.script = script; 01678 arg.opt = opt; 01679 return (NODE *)rb_ensure(load_file_internal, (VALUE)&arg, restore_lineno, rb_gv_get("$.")); 01680 } 01681 01682 void * 01683 rb_load_file(const char *fname) 01684 { 01685 struct cmdline_options opt; 01686 01687 return load_file(rb_parser_new(), fname, 0, cmdline_options_init(&opt)); 01688 } 01689 01690 static void 01691 set_arg0(VALUE val, ID id) 01692 { 01693 char *s; 01694 long i; 01695 01696 if (origarg.argv == 0) 01697 rb_raise(rb_eRuntimeError, "$0 not initialized"); 01698 StringValue(val); 01699 s = RSTRING_PTR(val); 01700 i = RSTRING_LEN(val); 01701 01702 setproctitle("%.*s", (int)i, s); 01703 01704 rb_progname = rb_obj_freeze(rb_external_str_new(s, i)); 01705 } 01706 01707 void 01708 ruby_script(const char *name) 01709 { 01710 if (name) { 01711 rb_progname = rb_external_str_new(name, strlen(name)); 01712 rb_vm_set_progname(rb_progname); 01713 } 01714 } 01715 01716 static void 01717 init_ids(struct cmdline_options *opt) 01718 { 01719 rb_uid_t uid = getuid(); 01720 rb_uid_t euid = geteuid(); 01721 rb_gid_t gid = getgid(); 01722 rb_gid_t egid = getegid(); 01723 01724 if (uid != euid) opt->setids |= 1; 01725 if (egid != gid) opt->setids |= 2; 01726 if (uid && opt->setids) { 01727 if (opt->safe_level < 1) opt->safe_level = 1; 01728 } 01729 } 01730 01731 #undef forbid_setid 01732 static void 01733 forbid_setid(const char *s, struct cmdline_options *opt) 01734 { 01735 if (opt->setids & 1) 01736 rb_raise(rb_eSecurityError, "no %s allowed while running setuid", s); 01737 if (opt->setids & 2) 01738 rb_raise(rb_eSecurityError, "no %s allowed while running setgid", s); 01739 if (opt->safe_level > 0) 01740 rb_raise(rb_eSecurityError, "no %s allowed in tainted mode", s); 01741 } 01742 01743 static void 01744 verbose_setter(VALUE val, ID id, void *data) 01745 { 01746 VALUE *variable = data; 01747 *variable = RTEST(val) ? Qtrue : val; 01748 } 01749 01750 static VALUE 01751 opt_W_getter(ID id, void *data) 01752 { 01753 VALUE *variable = data; 01754 switch (*variable) { 01755 case Qnil: 01756 return INT2FIX(0); 01757 case Qfalse: 01758 return INT2FIX(1); 01759 case Qtrue: 01760 return INT2FIX(2); 01761 } 01762 return Qnil; /* not reached */ 01763 } 01764 01765 void 01766 ruby_prog_init(void) 01767 { 01768 rb_define_hooked_variable("$VERBOSE", &ruby_verbose, 0, verbose_setter); 01769 rb_define_hooked_variable("$-v", &ruby_verbose, 0, verbose_setter); 01770 rb_define_hooked_variable("$-w", &ruby_verbose, 0, verbose_setter); 01771 rb_define_hooked_variable("$-W", &ruby_verbose, opt_W_getter, rb_gvar_readonly_setter); 01772 rb_define_variable("$DEBUG", &ruby_debug); 01773 rb_define_variable("$-d", &ruby_debug); 01774 01775 rb_define_hooked_variable("$0", &rb_progname, 0, set_arg0); 01776 rb_define_hooked_variable("$PROGRAM_NAME", &rb_progname, 0, set_arg0); 01777 01778 /* 01779 * ARGV contains the command line arguments used to run ruby with the 01780 * first value containing the name of the executable. 01781 * 01782 * A library like OptionParser can be used to process command-line 01783 * arguments. 01784 */ 01785 rb_define_global_const("ARGV", rb_argv); 01786 } 01787 01788 void 01789 ruby_set_argv(int argc, char **argv) 01790 { 01791 int i; 01792 VALUE av = rb_argv; 01793 01794 #if defined(USE_DLN_A_OUT) 01795 if (origarg.argv) 01796 dln_argv0 = origarg.argv[0]; 01797 else 01798 dln_argv0 = argv[0]; 01799 #endif 01800 rb_ary_clear(av); 01801 for (i = 0; i < argc; i++) { 01802 VALUE arg = rb_external_str_new_cstr(argv[i]); 01803 01804 OBJ_FREEZE(arg); 01805 rb_ary_push(av, arg); 01806 } 01807 } 01808 01809 void * 01810 ruby_process_options(int argc, char **argv) 01811 { 01812 struct cmdline_options opt; 01813 VALUE iseq; 01814 01815 ruby_script(argv[0]); /* for the time being */ 01816 rb_argv0 = rb_str_new4(rb_progname); 01817 rb_gc_register_mark_object(rb_argv0); 01818 iseq = process_options(argc, argv, cmdline_options_init(&opt)); 01819 01820 #ifndef HAVE_SETPROCTITLE 01821 { 01822 extern void ruby_init_setproctitle(int argc, char *argv[]); 01823 ruby_init_setproctitle(argc, argv); 01824 } 01825 #endif 01826 01827 return (void*)(struct RData*)iseq; 01828 } 01829 01830 static void 01831 fill_standard_fds(void) 01832 { 01833 int f0, f1, f2, fds[2]; 01834 struct stat buf; 01835 f0 = fstat(0, &buf) == -1 && errno == EBADF; 01836 f1 = fstat(1, &buf) == -1 && errno == EBADF; 01837 f2 = fstat(2, &buf) == -1 && errno == EBADF; 01838 if (f0) { 01839 if (pipe(fds) == 0) { 01840 close(fds[1]); 01841 if (fds[0] != 0) { 01842 dup2(fds[0], 0); 01843 close(fds[0]); 01844 } 01845 } 01846 } 01847 if (f1 || f2) { 01848 if (pipe(fds) == 0) { 01849 close(fds[0]); 01850 if (f1 && fds[1] != 1) 01851 dup2(fds[1], 1); 01852 if (f2 && fds[1] != 2) 01853 dup2(fds[1], 2); 01854 if (fds[1] != 1 && fds[1] != 2) 01855 close(fds[1]); 01856 } 01857 } 01858 } 01859 01860 void 01861 ruby_sysinit(int *argc, char ***argv) 01862 { 01863 #if defined(_WIN32) 01864 void rb_w32_sysinit(int *argc, char ***argv); 01865 rb_w32_sysinit(argc, argv); 01866 #endif 01867 origarg.argc = *argc; 01868 origarg.argv = *argv; 01869 #if defined(USE_DLN_A_OUT) 01870 dln_argv0 = origarg.argv[0]; 01871 #endif 01872 fill_standard_fds(); 01873 } 01874
1.7.6.1