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