Ruby 1.9.3p327(2012-11-10revision37606)
ruby.c
Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   ruby.c -
00004 
00005   $Author: usa $
00006   created at: Tue Aug 10 12:47:31 JST 1993
00007 
00008   Copyright (C) 1993-2007 Yukihiro Matsumoto
00009   Copyright (C) 2000  Network Applied Communication Laboratory, Inc.
00010   Copyright (C) 2000  Information-technology Promotion Agency, Japan
00011 
00012 **********************************************************************/
00013 
00014 #ifdef __CYGWIN__
00015 #include <windows.h>
00016 #include <sys/cygwin.h>
00017 #endif
00018 #include "ruby/ruby.h"
00019 #include "ruby/encoding.h"
00020 #include "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     /* This message really ought to be max 23 lines.
00128      * Removed -h because the user already knows that option. Others? */
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);  /* Skip digits. */
00178             }
00179             oldl = newp - oldp;
00180             while (*newp && (ISSPACE(*newp) || *newp == ';')) {
00181                 newp = CharNext(newp);  /* Skip whitespace. */
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();         /* should be called here for some reason :-( */
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             /* check if valid name before replacing - with _ */
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     /* get rid of GC */
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             /* through */
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;      /* -W as -W2 */
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             /* "EIdvwWrKU" only */
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  *  call-seq:
01168  *     sub(pattern, replacement)   -> $_
01169  *     sub(pattern) { block }      -> $_
01170  *
01171  *  Equivalent to <code>$_.sub(<i>args</i>)</code>, except that
01172  *  <code>$_</code> will be updated if substitution occurs.
01173  *  Available only when -p/-n command line option specified.
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  *  call-seq:
01188  *     gsub(pattern, replacement)    -> string
01189  *     gsub(pattern) {|...| block }  -> string
01190  *
01191  *  Equivalent to <code>$_.gsub...</code>, except that <code>$_</code>
01192  *  receives the modified result.
01193  *  Available only when -p/-n command line option specified.
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  *  call-seq:
01209  *     chop   -> string
01210  *
01211  *  Equivalent to <code>($_.dup).chop!</code>, except <code>nil</code>
01212  *  is never returned. See <code>String#chop!</code>.
01213  *  Available only when -p/-n command line option specified.
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  *  call-seq:
01228  *     chomp            -> $_
01229  *     chomp(string)    -> $_
01230  *
01231  *  Equivalent to <code>$_ = $_.chomp(<em>string</em>)</code>. See
01232  *  <code>String#chomp</code>.
01233  *  Available only when -p/-n command line option specified.
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) {        /* no more args */
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         /* set eval context */
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         /* Set in the shebang line */
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         /* Freeze default_internal */
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;            /* something not nil */
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                     /* not ruby script, assume -x flag */
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                 /* push back shebang for pragma may exist in next line */
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);      /* Why here? unnatural */
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          * DATA is a File that contains the data section of the executed file.
01654          * To create a data section use <tt>__END__</tt>:
01655          *
01656          *   $ cat t.rb
01657          *   puts DATA.gets
01658          *   __END__
01659          *   hello world!
01660          *
01661          *   $ ruby t.rb
01662          *   hello world!
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;                /* not reached */
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      * ARGV contains the command line arguments used to run ruby with the
01787      * first value containing the name of the executable.
01788      *
01789      * A library like OptionParser can be used to process command-line
01790      * arguments.
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]);  /* for the time being */
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