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