/********************************************************************** ruby.c - $Author$ $Date$ created at: Tue Aug 10 12:47:31 JST 1993 Copyright (C) 1993-2003 Yukihiro Matsumoto Copyright (C) 2000 Network Applied Communication Laboratory, Inc. Copyright (C) 2000 Information-technology Promotion Agency, Japan **********************************************************************/ #if defined _WIN32 || defined __CYGWIN__ #include #endif #if defined __CYGWIN__ #include #endif #ifdef _WIN32_WCE #include #include "wince.h" #endif #include "ruby.h" #include "dln.h" #include "node.h" #include #include #include #ifdef __hpux #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifndef HAVE_STRING_H char *strchr _((const char*,const char)); char *strrchr _((const char*,const char)); char *strstr _((const char*,const char*)); #endif #include "util.h" #ifndef HAVE_STDLIB_H char *getenv(); #endif VALUE ruby_debug = Qfalse; VALUE ruby_verbose = Qfalse; static int sflag = 0; static int xflag = 0; extern int ruby_yydebug; char *ruby_inplace_mode = Qfalse; static void load_stdin _((void)); static void load_file _((const char *, int)); static void forbid_setid _((const char *)); static VALUE do_loop = Qfalse, do_print = Qfalse; static VALUE do_check = Qfalse, do_line = Qfalse; static VALUE do_split = Qfalse; static char *script; static int origargc; static char **origargv; static void usage(name) const char *name; { /* This message really ought to be max 23 lines. * Removed -h because the user already knows that option. Others? */ static char *usage_msg[] = { "-0[octal] specify record separator (\\0, if no argument)", "-a autosplit mode with -n or -p (splits $_ into $F)", "-c check syntax only", "-Cdirectory cd to directory, before executing your script", "-d set debugging flags (set $DEBUG to true)", "-e 'command' one line of script. Several -e's allowed. Omit [programfile]", "-Fpattern split() pattern for autosplit (-a)", "-i[extension] edit ARGV files in place (make backup if extension supplied)", "-Idirectory specify $LOAD_PATH directory (may be used more than once)", "-Kkcode specifies KANJI (Japanese) code-set", "-l enable line ending processing", "-n assume 'while gets(); ... end' loop around your script", "-p assume loop like -n but print line also like sed", "-rlibrary require the library, before executing your script", "-s enable some switch parsing for switches after script name", "-S look for the script using PATH environment variable", "-T[level] turn on tainting checks", "-v print version number, then turn on verbose mode", "-w turn warnings on for your script", "-W[level] set warning level; 0=silence, 1=medium, 2=verbose (default)", "-x[directory] strip off text before #!ruby line and perhaps cd to directory", "--copyright print the copyright", "--version print the version", NULL }; char **p = usage_msg; printf("Usage: %s [switches] [--] [programfile] [arguments]\n", name); while (*p) printf(" %s\n", *p++); } extern VALUE rb_load_path; #ifndef CharNext /* defined as CharNext[AW] on Windows. */ #define CharNext(p) ((p) + mblen(p, RUBY_MBCHAR_MAXSIZE)) #endif #if defined DOSISH || defined __CYGWIN__ static inline void translate_char(char *p, int from, int to) { while (*p) { if ((unsigned char)*p == from) *p = to; p = CharNext(p); } } #endif #if defined _WIN32 || defined __CYGWIN__ || defined __DJGPP__ static VALUE rubylib_mangled_path(const char *s, unsigned int l) { static char *newp, *oldp; static int newl, oldl, notfound; char *ptr; VALUE ret; if (!newp && !notfound) { newp = getenv("RUBYLIB_PREFIX"); if (newp) { oldp = newp = strdup(newp); while (*newp && !ISSPACE(*newp) && *newp != ';') { newp = CharNext(newp); /* Skip digits. */ } oldl = newp - oldp; while (*newp && (ISSPACE(*newp) || *newp == ';')) { newp = CharNext(newp); /* Skip whitespace. */ } newl = strlen(newp); if (newl == 0 || oldl == 0) { rb_fatal("malformed RUBYLIB_PREFIX"); } translate_char(newp, '\\', '/'); } else { notfound = 1; } } if (!newp || l < oldl || strncasecmp(oldp, s, oldl) != 0) { return rb_str_new(s, l); } ret = rb_str_new(0, l + newl - oldl); ptr = RSTRING_PTR(ret); memcpy(ptr, newp, newl); memcpy(ptr + newl, s + oldl, l - oldl); ptr[l + newl - oldl] = 0; return ret; } static VALUE rubylib_mangled_path2(const char *s) { return rubylib_mangled_path(s, strlen(s)); } #else #define rubylib_mangled_path rb_str_new #define rubylib_mangled_path2 rb_str_new2 #endif static void push_include _((const char *path)); static void push_include(path) const char *path; { const char sep = PATH_SEP_CHAR; const char *p, *s; p = path; while (*p) { while (*p == sep) p++; if (!*p) break; for (s = p; *s && *s != sep; s = CharNext(s)); rb_ary_push(rb_load_path, rubylib_mangled_path(p, s - p)); p = s; } } #ifdef __CYGWIN__ static void push_include_cygwin(const char *path) { const char *p, *s; char rubylib[FILENAME_MAX]; VALUE buf = 0; p = path; while (*p) { unsigned int len; while (*p == ';') p++; if (!*p) break; for (s = p; *s && *s != ';'; s = CharNext(s)); len = s - p; if (*s) { if (!buf) { buf = rb_str_new(p, len); p = RSTRING_PTR(buf); } else { rb_str_resize(buf, len); p = strncpy(RSTRING_PTR(buf), p, len); } } if (cygwin_conv_to_posix_path(p, rubylib) == 0) p = rubylib; push_include(p); if (!*s) break; p = s + 1; } } #define push_include push_include_cygwin #endif void ruby_incpush(path) const char *path; { if (path == 0) return; push_include(path); } #if defined DOSISH || defined __CYGWIN__ #define LOAD_RELATIVE 1 #endif void ruby_init_loadpath() { #if defined LOAD_RELATIVE char libpath[FILENAME_MAX+1]; char *p; int rest; #if defined _WIN32 || defined __CYGWIN__ HMODULE libruby = NULL; MEMORY_BASIC_INFORMATION m; #ifndef _WIN32_WCE memset(&m, 0, sizeof(m)); if (VirtualQuery(ruby_init_loadpath, &m, sizeof(m)) && m.State == MEM_COMMIT) libruby = (HMODULE)m.AllocationBase; #endif GetModuleFileName(libruby, libpath, sizeof libpath); #elif defined(DJGPP) extern char *__dos_argv0; strncpy(libpath, __dos_argv0, FILENAME_MAX); #elif defined(__human68k__) extern char **_argv; strncpy(libpath, _argv[0], FILENAME_MAX); #elif defined(__EMX__) _execname(libpath, FILENAME_MAX); #endif libpath[FILENAME_MAX] = '\0'; #if defined DOSISH translate_char(libpath, '\\', '/'); #elif defined __CYGWIN__ { char rubylib[FILENAME_MAX]; cygwin_conv_to_posix_path(libpath, rubylib); strncpy(libpath, rubylib, sizeof(libpath)); } #endif p = strrchr(libpath, '/'); if (p) { *p = 0; if (p - libpath > 3 && !strcasecmp(p - 4, "/bin")) { p -= 4; *p = 0; } } else { strcpy(libpath, "."); p = libpath + 1; } rest = FILENAME_MAX - (p - libpath); #define RUBY_RELATIVE(path) (strncpy(p, (path), rest), libpath) #else #define RUBY_RELATIVE(path) (path) #endif #define incpush(path) rb_ary_push(rb_load_path, rubylib_mangled_path2(path)) if (rb_safe_level() == 0) { ruby_incpush(getenv("RUBYLIB")); } #ifdef RUBY_SEARCH_PATH incpush(RUBY_RELATIVE(RUBY_SEARCH_PATH)); #endif incpush(RUBY_RELATIVE(RUBY_SITE_LIB2)); #ifdef RUBY_SITE_THIN_ARCHLIB incpush(RUBY_RELATIVE(RUBY_SITE_THIN_ARCHLIB)); #endif incpush(RUBY_RELATIVE(RUBY_SITE_ARCHLIB)); incpush(RUBY_RELATIVE(RUBY_SITE_LIB)); incpush(RUBY_RELATIVE(RUBY_LIB)); #ifdef RUBY_THIN_ARCHLIB incpush(RUBY_RELATIVE(RUBY_THIN_ARCHLIB)); #endif incpush(RUBY_RELATIVE(RUBY_ARCHLIB)); if (rb_safe_level() == 0) { incpush("."); } } struct req_list { char *name; struct req_list *next; }; static struct req_list req_list_head, *req_list_last = &req_list_head; static void add_modules(mod) const char *mod; { struct req_list *list; list = ALLOC(struct req_list); list->name = ALLOC_N(char, strlen(mod)+1); strcpy(list->name, mod); list->next = 0; req_list_last->next = list; req_list_last = list; } extern void Init_ext _((void)); static void require_libraries() { extern NODE *ruby_eval_tree; extern NODE *ruby_eval_tree_begin; NODE *save[3]; struct req_list *list = req_list_head.next; struct req_list *tmp; save[0] = ruby_eval_tree; save[1] = ruby_eval_tree_begin; save[2] = NEW_NEWLINE(0); ruby_eval_tree = ruby_eval_tree_begin = 0; ruby_current_node = 0; Init_ext(); /* should be called here for some reason :-( */ ruby_current_node = save[2]; ruby_set_current_source(); req_list_last = 0; while (list) { int state; ruby_current_node = 0; rb_protect((VALUE (*)(VALUE))rb_require, (VALUE)list->name, &state); if (state) rb_jump_tag(state); tmp = list->next; free(list->name); free(list); list = tmp; ruby_current_node = save[2]; ruby_set_current_source(); } req_list_head.next = 0; ruby_eval_tree = save[0]; ruby_eval_tree_begin = save[1]; rb_gc_force_recycle((VALUE)save[2]); ruby_current_node = 0; } static void process_sflag() { if (sflag) { long n; VALUE *args; n = RARRAY(rb_argv)->len; args = RARRAY(rb_argv)->ptr; while (n > 0) { VALUE v = *args++; char *s = StringValuePtr(v); char *p; int hyphen = Qfalse; if (s[0] != '-') break; n--; if (s[1] == '-' && s[2] == '\0') break; v = Qtrue; /* check if valid name before replacing - with _ */ for (p = s + 1; *p; p++) { if (*p == '=') { *p++ = '\0'; v = rb_str_new2(p); break; } if (*p == '-') { hyphen = Qtrue; } else if (*p != '_' && !ISALNUM(*p)) { VALUE name_error[2]; name_error[0] = rb_str_new2("invalid name for global variable - "); if (!(p = strchr(p, '='))) { rb_str_cat2(name_error[0], s); } else { rb_str_cat(name_error[0], s, p - s); } name_error[1] = args[-1]; rb_exc_raise(rb_class_new_instance(2, name_error, rb_eNameError)); } } s[0] = '$'; if (hyphen) { for (p = s + 1; *p; ++p) { if (*p == '-') *p = '_'; } } rb_gv_set(s, v); } n = RARRAY(rb_argv)->len - n; while (n--) { rb_ary_shift(rb_argv); } } sflag = 0; } static void proc_options _((int argc, char **argv)); static char* moreswitches(s) char *s; { int argc; char *argv[3]; char *p = s; argc = 2; argv[0] = argv[2] = 0; while (*s && !ISSPACE(*s)) s++; argv[1] = ALLOCA_N(char, s-p+2); argv[1][0] = '-'; strncpy(argv[1]+1, p, s-p); argv[1][s-p+1] = '\0'; proc_options(argc, argv); while (*s && ISSPACE(*s)) s++; return s; } static void proc_options(argc, argv) int argc; char **argv; { char *argv0 = argv[0]; int do_search; char *s; NODE *volatile script_node = 0; int version = 0; int copyright = 0; int verbose = 0; VALUE e_script = Qfalse; if (argc == 0) return; do_search = Qfalse; for (argc--,argv++; argc > 0; argc--,argv++) { if (argv[0][0] != '-' || !argv[0][1]) break; s = argv[0]+1; reswitch: switch (*s) { case 'a': do_split = Qtrue; s++; goto reswitch; case 'p': do_print = Qtrue; /* through */ case 'n': do_loop = Qtrue; s++; goto reswitch; case 'd': ruby_debug = Qtrue; ruby_verbose = Qtrue; s++; goto reswitch; case 'y': ruby_yydebug = 1; s++; goto reswitch; case 'v': if (argv0 == 0 || verbose) { s++; goto reswitch; } ruby_show_version(); verbose = 1; case 'w': ruby_verbose = Qtrue; s++; goto reswitch; case 'W': { int numlen; int v = 2; /* -W as -W2 */ if (*++s) { v = scan_oct(s, 1, &numlen); if (numlen == 0) v = 1; s += numlen; } switch (v) { case 0: ruby_verbose = Qnil; break; case 1: ruby_verbose = Qfalse; break; default: ruby_verbose = Qtrue; break; } } goto reswitch; case 'c': do_check = Qtrue; s++; goto reswitch; case 's': forbid_setid("-s"); sflag = 1; s++; goto reswitch; case 'h': usage(origargv[0]); exit(0); case 'l': do_line = Qtrue; rb_output_rs = rb_rs; s++; goto reswitch; case 'S': forbid_setid("-S"); do_search = Qtrue; s++; goto reswitch; case 'e': forbid_setid("-e"); if (!*++s) { s = argv[1]; argc--,argv++; } if (!s) { fprintf(stderr, "%s: no code specified for -e\n", origargv[0]); exit(2); } if (!e_script) { e_script = rb_str_new(0,0); if (script == 0) script = "-e"; } rb_str_cat2(e_script, s); rb_str_cat2(e_script, "\n"); break; case 'r': forbid_setid("-r"); if (*++s) { add_modules(s); } else if (argv[1]) { add_modules(argv[1]); argc--,argv++; } break; case 'i': forbid_setid("-i"); if (ruby_inplace_mode) free(ruby_inplace_mode); ruby_inplace_mode = strdup(s+1); break; case 'x': xflag = Qtrue; s++; if (*s && chdir(s) < 0) { rb_fatal("Can't chdir to %s", s); } break; case 'C': case 'X': s++; if (!*s) { s = argv[1]; argc--,argv++; } if (!s || !*s) { rb_fatal("Can't chdir"); } if (chdir(s) < 0) { rb_fatal("Can't chdir to %s", s); } break; case 'F': if (*++s) { rb_fs = rb_reg_new(s, strlen(s), 0); } break; case 'K': if (*++s) { rb_set_kcode(s); s++; } goto reswitch; case 'T': { int numlen; int v = 1; if (*++s) { v = scan_oct(s, 2, &numlen); if (numlen == 0) v = 1; s += numlen; } rb_set_safe_level(v); } goto reswitch; case 'I': forbid_setid("-I"); if (*++s) ruby_incpush(s); else if (argv[1]) { ruby_incpush(argv[1]); argc--,argv++; } break; case '0': { int numlen; int v; char c; v = scan_oct(s, 4, &numlen); s += numlen; if (v > 0377) rb_rs = Qnil; else if (v == 0 && numlen >= 2) { rb_rs = rb_str_new2("\n\n"); } else { c = v & 0xff; rb_rs = rb_str_new(&c, 1); } } goto reswitch; case '-': if (!s[1] || (s[1] == '\r' && !s[2])) { argc--,argv++; goto switch_end; } s++; if (strcmp("copyright", s) == 0) copyright = 1; else if (strcmp("debug", s) == 0) { ruby_debug = Qtrue; ruby_verbose = Qtrue; } else if (strcmp("version", s) == 0) version = 1; else if (strcmp("verbose", s) == 0) { verbose = 1; ruby_verbose = Qtrue; } else if (strcmp("yydebug", s) == 0) ruby_yydebug = 1; else if (strcmp("help", s) == 0) { usage(origargv[0]); exit(0); } else { fprintf(stderr, "%s: invalid option --%s (-h will show valid options)\n", origargv[0], s); exit(2); } break; case '\r': if (!s[1]) break; default: { const char *format; if (ISPRINT(*s)) { format = "%s: invalid option -%c (-h will show valid options)\n"; } else { format = "%s: invalid option -\\%03o (-h will show valid options)\n"; } fprintf(stderr, format, origargv[0], (int)(unsigned char)*s); } exit(2); case 0: break; } } switch_end: if (argv0 == 0) return; if (rb_safe_level() == 0 && (s = getenv("RUBYOPT"))) { while (ISSPACE(*s)) s++; if (*s == 'T' || (*s == '-' && *(s+1) == 'T')) { int numlen; int v = 1; if (*s != 'T') ++s; if (*++s) { v = scan_oct(s, 2, &numlen); if (numlen == 0) v = 1; } rb_set_safe_level(v); } else { while (s && *s) { if (*s == '-') { s++; if (ISSPACE(*s)) { do {s++;} while (ISSPACE(*s)); continue; } } if (!*s) break; if (!strchr("IdvwWrK", *s)) rb_raise(rb_eRuntimeError, "illegal switch in RUBYOPT: -%c", *s); s = moreswitches(s); } } } if (version) { ruby_show_version(); exit(0); } if (copyright) { ruby_show_copyright(); } if (rb_safe_level() >= 4) { OBJ_TAINT(rb_argv); OBJ_TAINT(rb_load_path); } if (!e_script) { if (argc == 0) { /* no more args */ if (verbose) exit(0); script = "-"; } else { script = argv[0]; if (script[0] == '\0') { script = "-"; } else if (do_search) { char *path = getenv("RUBYPATH"); script = 0; if (path) { script = dln_find_file(argv[0], path); } if (!script) { script = dln_find_file(argv[0], getenv(PATH_ENV)); } if (!script) script = argv[0]; script = ruby_sourcefile = rb_source_filename(script); script_node = NEW_NEWLINE(0); } #if defined DOSISH || defined __CYGWIN__ translate_char(script, '\\', '/'); #endif argc--; argv++; } } ruby_script(script); ruby_set_argv(argc, argv); process_sflag(); ruby_init_loadpath(); ruby_sourcefile = rb_source_filename(argv0); if (e_script) { require_libraries(); rb_compile_string(script, e_script, 1); } else if (strlen(script) == 1 && script[0] == '-') { load_stdin(); } else { load_file(script, 1); } process_sflag(); xflag = 0; if (rb_safe_level() >= 4) { FL_UNSET(rb_argv, FL_TAINT); FL_UNSET(rb_load_path, FL_TAINT); } } extern int ruby__end__seen; static void load_file(fname, script) const char *fname; int script; { extern VALUE rb_stdin; VALUE f; int line_start = 1; if (!fname) rb_load_fail(fname); if (strcmp(fname, "-") == 0) { f = rb_stdin; } else { FILE *fp = fopen(fname, "r"); if (fp == NULL) { rb_load_fail(fname); } fclose(fp); f = rb_file_open(fname, "r"); #if defined DOSISH || defined __CYGWIN__ { char *ext = strrchr(fname, '.'); if (ext && strcasecmp(ext, ".exe") == 0) rb_io_binmode(f); } #endif } if (script) { VALUE c = 1; /* something not nil */ VALUE line; char *p; if (xflag) { forbid_setid("-x"); xflag = Qfalse; while (!NIL_P(line = rb_io_gets(f))) { line_start++; if (RSTRING(line)->len > 2 && RSTRING(line)->ptr[0] == '#' && RSTRING(line)->ptr[1] == '!') { if ((p = strstr(RSTRING(line)->ptr, "ruby")) != 0) { goto start_read; } } } rb_raise(rb_eLoadError, "no Ruby script found in input"); } c = rb_io_getc(f); if (c == INT2FIX('#')) { line = rb_io_gets(f); if (NIL_P(line)) return; line_start++; if (RSTRING(line)->len > 2 && RSTRING(line)->ptr[0] == '!') { if ((p = strstr(RSTRING(line)->ptr, "ruby")) == 0) { /* not ruby script, kick the program */ char **argv; char *path; char *pend = RSTRING(line)->ptr + RSTRING(line)->len; p = RSTRING(line)->ptr + 1; /* skip `#!' */ if (pend[-1] == '\n') pend--; /* chomp line */ if (pend[-1] == '\r') pend--; *pend = '\0'; while (p < pend && ISSPACE(*p)) p++; path = p; /* interpreter path */ while (p < pend && !ISSPACE(*p)) p++; *p++ = '\0'; if (p < pend) { argv = ALLOCA_N(char*, origargc+3); argv[1] = p; MEMCPY(argv+2, origargv+1, char*, origargc); } else { argv = origargv; } argv[0] = path; execv(path, argv); ruby_sourcefile = rb_source_filename(fname); ruby_sourceline = 1; rb_fatal("Can't exec %s", path); } start_read: p += 4; RSTRING(line)->ptr[RSTRING(line)->len-1] = '\0'; if (RSTRING(line)->ptr[RSTRING(line)->len-2] == '\r') RSTRING(line)->ptr[RSTRING(line)->len-2] = '\0'; if ((p = strstr(p, " -")) != 0) { p++; /* skip space before `-' */ while (*p == '-') { p = moreswitches(p+1); } } } } else if (!NIL_P(c)) { rb_io_ungetc(f, c); } require_libraries(); /* Why here? unnatural */ if (NIL_P(c)) return; } rb_compile_file(fname, f, line_start); if (script && ruby__end__seen) { rb_define_global_const("DATA", f); } else if (f != rb_stdin) { rb_io_close(f); } if (ruby_parser_stack_on_heap()) { rb_gc(); } } void rb_load_file(fname) const char *fname; { load_file(fname, 0); } static void load_stdin() { forbid_setid("program input from stdin"); load_file("-", 1); } VALUE rb_progname; VALUE rb_argv; VALUE rb_argv0; #if defined(PSTAT_SETCMD) || defined(HAVE_SETPROCTITLE) #elif defined(_WIN32) #elif defined(HAVE_SETENV) && defined(HAVE_UNSETENV) #else #define USE_ENVSPACE_FOR_ARG0 #endif #ifdef USE_ENVSPACE_FOR_ARG0 static struct { char *begin, *end; } envspace; extern char **environ; static void set_arg0space() { char *s; int i; if (!environ || (s = environ[0]) == NULL) return; envspace.begin = s; s += strlen(s); for (i = 1; environ[i]; i++) { if (environ[i] == s + 1) { s++; s += strlen(s); /* this one is ok too */ } } envspace.end = s; } #else #define set_arg0space() ((void)0) #endif static void set_arg0(val, id) VALUE val; ID id; { char *s; long i; #if !defined(PSTAT_SETCMD) && !defined(HAVE_SETPROCTITLE) static int len; #endif if (origargv == 0) rb_raise(rb_eRuntimeError, "$0 not initialized"); StringValue(val); s = RSTRING(val)->ptr; i = RSTRING(val)->len; #if defined(PSTAT_SETCMD) if (i >= PST_CLEN) { union pstun j; j.pst_command = s; i = PST_CLEN; RSTRING(val)->len = i; *(s + i) = '\0'; pstat(PSTAT_SETCMD, j, PST_CLEN, 0, 0); } else { union pstun j; j.pst_command = s; pstat(PSTAT_SETCMD, j, i, 0, 0); } rb_progname = rb_tainted_str_new(s, i); #elif defined(HAVE_SETPROCTITLE) setproctitle("%.*s", (int)i, s); rb_progname = rb_tainted_str_new(s, i); #else if (len == 0) { char *s = origargv[0]; int i; s += strlen(s); /* See if all the arguments are contiguous in memory */ for (i = 1; i < origargc; i++) { if (origargv[i] == s + 1) { s++; s += strlen(s); /* this one is ok too */ } else { break; } } #if defined(USE_ENVSPACE_FOR_ARG0) if (s + 1 == envspace.begin) { s = envspace.end; ruby_setenv("", NULL); /* duplicate environ vars */ } #endif len = s - origargv[0]; } if (i >= len) { i = len; } memcpy(origargv[0], s, i); s = origargv[0] + i; *s = '\0'; if (++i < len) memset(s + 1, ' ', len - i); for (i = 1; i < origargc; i++) origargv[i] = s; rb_progname = rb_tainted_str_new2(origargv[0]); #endif } void ruby_script(name) const char *name; { if (name) { rb_progname = rb_tainted_str_new2(name); ruby_sourcefile = rb_source_filename(name); } } static int uid, euid, gid, egid; static void init_ids() { uid = (int)getuid(); euid = (int)geteuid(); gid = (int)getgid(); egid = (int)getegid(); #ifdef VMS uid |= gid << 16; euid |= egid << 16; #endif if (uid && (euid != uid || egid != gid)) { rb_set_safe_level(1); } } static void forbid_setid(s) const char *s; { if (euid != uid) rb_raise(rb_eSecurityError, "no %s allowed while running setuid", s); if (egid != gid) rb_raise(rb_eSecurityError, "no %s allowed while running setgid", s); if (rb_safe_level() > 0) rb_raise(rb_eSecurityError, "no %s allowed in tainted mode", s); } static void verbose_setter(val, id, variable) VALUE val; ID id; VALUE *variable; { ruby_verbose = RTEST(val) ? Qtrue : val; } void ruby_prog_init() { init_ids(); ruby_sourcefile = rb_source_filename("ruby"); rb_define_hooked_variable("$VERBOSE", &ruby_verbose, 0, verbose_setter); rb_define_hooked_variable("$-v", &ruby_verbose, 0, verbose_setter); rb_define_hooked_variable("$-w", &ruby_verbose, 0, verbose_setter); rb_define_variable("$DEBUG", &ruby_debug); rb_define_variable("$-d", &ruby_debug); rb_define_readonly_variable("$-p", &do_print); rb_define_readonly_variable("$-l", &do_line); rb_define_hooked_variable("$0", &rb_progname, 0, set_arg0); rb_define_hooked_variable("$PROGRAM_NAME", &rb_progname, 0, set_arg0); rb_define_readonly_variable("$*", &rb_argv); rb_argv = rb_ary_new(); rb_define_global_const("ARGV", rb_argv); rb_define_readonly_variable("$-a", &do_split); rb_global_variable(&rb_argv0); #ifdef MSDOS /* * There is no way we can refer to them from ruby, so close them to save * space. */ (void)fclose(stdaux); (void)fclose(stdprn); #endif } void ruby_set_argv(argc, argv) int argc; char **argv; { int i; #if defined(USE_DLN_A_OUT) if (origargv) dln_argv0 = origargv[0]; else dln_argv0 = argv[0]; #endif rb_ary_clear(rb_argv); for (i=0; i < argc; i++) { VALUE arg = rb_tainted_str_new2(argv[i]); OBJ_FREEZE(arg); rb_ary_push(rb_argv, arg); } } void ruby_process_options(argc, argv) int argc; char **argv; { origargc = argc; origargv = argv; ruby_script(argv[0]); /* for the time being */ rb_argv0 = rb_progname; #if defined(USE_DLN_A_OUT) dln_argv0 = argv[0]; #endif set_arg0space(); proc_options(argc, argv); if (do_check && ruby_nerrs == 0) { printf("Syntax OK\n"); exit(0); } if (do_print) { rb_parser_append_print(); } if (do_loop) { rb_parser_while_loop(do_line, do_split); } }