/************************************************ ruby.c - $Author: matz $ $Date: 1995/01/10 10:42:51 $ created at: Tue Aug 10 12:47:31 JST 1993 Copyright (C) 1993-1995 Yukihiro Matsumoto ************************************************/ #include "ruby.h" #include "re.h" #include #include #include #include #include "dln.h" #ifdef HAVE_STRING_H # include #else char *strchr(); char *strstr(); #endif static int version, copyright; int debug = 0; int verbose = 0; static int sflag = FALSE; char *inplace = 0; char *strdup(); extern int yydebug; extern int nerrs; int xflag = FALSE; static void load_stdin(); static void load_file(); static int do_loop = FALSE, do_print = FALSE; static int do_check = FALSE, do_line = FALSE; static int do_split = FALSE; static char *script; #ifndef RUBY_LIB #define RUBY_LIB ".:/usr/local/lib/ruby" #endif #define RUBY_LIB_SEP ':' extern VALUE rb_load_path; VALUE Frequire(); static void addpath(path) char *path; { char *p, *s; if (path == 0) return; p = s = path; while (*p) { while (*p == RUBY_LIB_SEP) p++; if (s = strchr(p, RUBY_LIB_SEP)) { ary_push(rb_load_path, str_new(p, (int)(s-p))); p = s + 1; } else { ary_push(rb_load_path, str_new2(p)); break; } } } static void proc_options(argcp, argvp) int *argcp; char ***argvp; { int argc = *argcp; char **argv = *argvp; int script_given, do_search; char *s; extern VALUE RS, ORS, FS; if (argc == 0) return; version = FALSE; script_given = FALSE; do_search = FALSE; 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 = TRUE; s++; goto reswitch; case 'p': do_print = TRUE; /* through */ case 'n': do_loop = TRUE; s++; goto reswitch; case 'd': debug = TRUE; s++; goto reswitch; case 'y': yydebug = 1; s++; goto reswitch; case 'v': verbose = TRUE; show_version(); s++; goto reswitch; case 'c': do_check = TRUE; s++; goto reswitch; case 's': sflag = TRUE; s++; goto reswitch; case 'l': do_line = TRUE; ORS = RS; s++; goto reswitch; case 'S': do_search = TRUE; s++; goto reswitch; case 'e': script_given++; if (script == 0) script = "-e"; if (argv[1]) { lex_setsrc("-e", argv[1], strlen(argv[1])); argc--,argv++; } else { lex_setsrc("-e", "", 0); } yyparse(); break; case 'r': if (*++s) { f_require(Qnil, str_new2(s)); } else if (argv[1]) { f_require(Qnil, str_new2(argv[1])); argc--,argv++; } break; case 'i': inplace = strdup(s+1); break; case 'x': xflag = TRUE; s++; if (*s && chdir(s) < 0) { Fatal("Can't chdir to %s", s); } break; case 'X': s++; if (!*s) { s = argv[1]; argc--,argv++; } if (*s && chdir(s) < 0) { Fatal("Can't chdir to %s", s); } break; case 'F': FS = str_new2(s+1); break; case 'K': s++; rb_set_kcode(s); s++; goto reswitch; case 'I': if (*++s) ary_push(rb_load_path, str_new2(s)); else if (argv[1]) { ary_push(rb_load_path, str_new2(argv[1])); argc--,argv++; } break; case '0': { int numlen; int v; char c; v = scan_oct(s, 4, &numlen); s += numlen; if (v > 0377) RS = Qnil; else if (v == 0 && numlen >= 2) { RS = str_new2("\n\n"); } else { c = v & 0xff; RS = str_new(&c, 1); } } goto reswitch; case '-': if (!s[1]) { argc--,argv++; goto switch_end; } s++; if (strcmp("copyright", s) == 0) copyright = 1; else if (strcmp("debug", s) == 0) debug = 1; else if (strcmp("version", s) == 0) version = 1; else if (strcmp("verbose", s) == 0) verbose = 1; else if (strcmp("yydebug", s) == 0) yydebug = 1; else { Fatal("Unrecognized long option: --%s",s); } break; default: Fatal("Unrecognized switch: -%s",s); case 0: break; } } switch_end: if (*argvp[0] == 0) return; if (version) { show_version(); exit(0); } if (copyright) { show_copyright(); } if (script_given == 0) { if (argc == 0) { /* no more args */ if (verbose) exit(0); script = "-"; load_stdin(); } else { script = argv[0]; if (do_search) { script = dln_find_file(script, getenv("PATH")); if (!script) script = argv[0]; } load_file(script, 1); argc--,argv++; } } xflag = FALSE; *argvp = argv; *argcp = argc; if (sflag) { char *s; argc = *argcp; argv = *argvp; for (; argc > 0 && argv[0][0] == '-'; argc--,argv++) { if (argv[0][1] == '-') { argc--,argv++; break; } argv[0][0] = '$'; if (s = strchr(argv[0], '=')) { *s++ = '\0'; rb_gvar_set2(argv[0], str_new2(s)); } else { rb_gvar_set2(argv[0], TRUE); } } *argcp = argc; *argvp = argv; } } static void readin(fd, fname, script) int fd; char *fname; int script; { struct stat st; char *ptr, *p, *pend; if (fstat(fd, &st) < 0) rb_sys_fail(fname); if (!S_ISREG(st.st_mode)) Fail("script is not a regular file - %s", fname); p = ptr = ALLOC_N(char, st.st_size+1); if (read(fd, ptr, st.st_size) != st.st_size) { free(ptr); rb_sys_fail(fname); } pend = p + st.st_size; *pend = '\0'; if (script) { if (xflag) { xflag = FALSE; while (p < pend) { if (p[0] == '#' && p[1] == '!') { char *s = p; while (s < pend && *s != '\n') s++; if (*s == '\n') { *s = '\0'; if (strstr(p, "ruby")) { *s = '\n'; goto start_read; } } p = s + 1; } else { while (p < pend && *p++ != '\n') ; if (p >= pend) break; } } free(ptr); Fail("No Ruby script found in input"); } start_read: if (p[0] == '#' && p[1] == '!') { char *s = p, *q; while (s < pend && *s != '\n') s++; if (*s == '\n') { *s = '\0'; if (q = strstr(p, "ruby -")) { int argc; char *argv[2]; char **argvp = argv; argc = 2; argv[0] = Qnil; argv[1] = q + 5; proc_options(&argc, &argvp); p = s + 1; } else { *s = '\n'; } } } } lex_setsrc(fname, p, pend - p); yyparse(); free(ptr); } static void load_file(fname, script) char *fname; int script; { int fd; if (fname[0] == '\0') { load_stdin(); return; } fd = open(fname, O_RDONLY, 0); if (fd < 0) rb_sys_fail(fname); readin(fd, fname, script); close(fd); } void rb_load_file(fname) char *fname; { load_file(fname, 0); } static void load_stdin() { char buf[32]; FILE *f; char c; int fd; sprintf(buf, "/tmp/ruby-f%d", getpid()); f = fopen(buf, "w"); fd = open(buf, O_RDONLY, 0); if (fd < 0) rb_sys_fail(buf); unlink(buf); while ((c = getchar()) != EOF) { putc(c, f); } fclose(f); readin(fd, "-"); } VALUE Progname; VALUE Argv; static int origargc; static char **origargv, **origenvp; static VALUE set_arg0(val, id) VALUE val; ID id; { char *s; int i; static int len; Check_Type(val, T_STRING); if (len == 0) { s = origargv[0]; s += strlen(s); /* See if all the arguments are contiguous in memory */ for (i = 1; i < origargc; i++) { if (origargv[i] == s + 1) s += strlen(++s); /* this one is ok too */ } len = s - origargv[0]; } s = RSTRING(val)->ptr; i = RSTRING(val)->len; if (i > len) { memcpy(origargv[0], s, len); origargv[0][len] = '\0'; } else { memcpy(origargv[0], s, i); s = origargv[0]+i; *s++ = '\0'; while (++i < len) *s++ = ' '; } Progname = str_new2(origargv[0]); return val; } void ruby_script(name) char *name; { if (name) { Progname = str_new2(name); } } void ruby_options(argc, argv, envp) int argc; char **argv, **envp; { extern VALUE errat; int i; origargc = argc; origargv = argv; origenvp = envp; rb_define_variable("$@", &errat); errat = str_new2(argv[0]); rb_define_variable("$VERBOSE", &verbose); rb_define_variable("$DEBUG", &debug); #if defined(USE_DLN_A_OUT) dln_argv0 = argv[0]; #endif proc_options(&argc, &argv); if (do_check && nerrs == 0) { printf("Syntax OK\n"); exit(0); } if (do_print) { yyappend_print(); } if (do_loop) { yywhole_loop(do_line, do_split); } rb_define_hooked_variable("$0", &Progname, 0, set_arg0); ruby_script(script); addpath(getenv("RUBYLIB")); addpath(RUBY_LIB); rb_define_readonly_variable("$ARGV", &Argv); rb_define_readonly_variable("$*", &Argv); Argv = ary_new2(argc); for (i=0; i < argc; i++) { ary_push(Argv, str_new2(argv[i])); } }