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