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