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