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