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 

Generated on Wed Aug 10 09:17:13 2011 for Ruby by  doxygen 1.4.7