Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# ruby.c

Go to the documentation of this file.

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