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