diff options
Diffstat (limited to 'ruby_1_8_5/ruby.c')
-rw-r--r-- | ruby_1_8_5/ruby.c | 1230 |
1 files changed, 1230 insertions, 0 deletions
diff --git a/ruby_1_8_5/ruby.c b/ruby_1_8_5/ruby.c new file mode 100644 index 0000000000..51d8a7c845 --- /dev/null +++ b/ruby_1_8_5/ruby.c @@ -0,0 +1,1230 @@ +/********************************************************************** + + ruby.c - + + $Author: nobu $ + $Date: 2006/08/16 02:11:21 $ + 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 <windows.h> +#endif +#if defined __CYGWIN__ +#include <sys/cygwin.h> +#endif +#ifdef _WIN32_WCE +#include <winsock.h> +#include "wince.h" +#endif +#include "ruby.h" +#include "dln.h" +#include "node.h" +#include <stdio.h> +#include <sys/types.h> +#include <ctype.h> + +#ifdef __hpux +#include <sys/pstat.h> +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#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("IdvwrK", *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); + } +} |