ruby.c

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

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7