Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals

ruby.c

Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   ruby.c -
00004 
00005   $Author: matz $
00006   $Date: 2005/12/12 00:36:52 $
00007   created at: Tue Aug 10 12:47:31 JST 1993
00008 
00009   Copyright (C) 1993-2003 Yukihiro Matsumoto
00010   Copyright (C) 2000  Network Applied Communication Laboratory, Inc.
00011   Copyright (C) 2000  Information-technology Promotion Agency, Japan
00012 
00013 **********************************************************************/
00014 
00015 #if defined _WIN32 || defined __CYGWIN__
00016 #include <windows.h>
00017 #endif
00018 #ifdef _WIN32_WCE
00019 #include <winsock.h>
00020 #include "wince.h"
00021 #endif
00022 #include "ruby.h"
00023 #include "dln.h"
00024 #include "node.h"
00025 #include <stdio.h>
00026 #include <sys/types.h>
00027 #include <ctype.h>
00028 
00029 #ifdef __hpux
00030 #include <sys/pstat.h>
00031 #endif
00032 
00033 #ifdef HAVE_UNISTD_H
00034 #include <unistd.h>
00035 #endif
00036 
00037 #ifndef HAVE_STRING_H
00038 char *strchr (const char*,const char);
00039 char *strrchr (const char*,const char);
00040 char *strstr (const char*,const char*);
00041 #endif
00042 
00043 #include "util.h"
00044 
00045 #ifndef HAVE_STDLIB_H
00046 char *getenv();
00047 #endif
00048 
00049 VALUE ruby_debug = Qfalse;
00050 VALUE ruby_verbose = Qfalse;
00051 static int sflag = 0;
00052 static int xflag = 0;
00053 extern int ruby_yydebug;
00054 
00055 char *ruby_inplace_mode = Qfalse;
00056 
00057 static void load_stdin (void);
00058 static void load_file (const char *, int);
00059 static void forbid_setid (const char *);
00060 
00061 static VALUE do_loop = Qfalse, do_print = Qfalse;
00062 static VALUE do_check = Qfalse, do_line = Qfalse;
00063 static VALUE do_split = Qfalse;
00064 
00065 static char *script;
00066 
00067 static int origargc;
00068 static char **origargv;
00069 
00070 static void
00071 usage(name)
00072     const char *name;
00073 {
00074     /* This message really ought to be max 23 lines.
00075      * Removed -h because the user already knows that option. Others? */
00076 
00077     static char *usage_msg[] = {
00078 "-0[octal]       specify record separator (\\0, if no argument)",
00079 "-a              autosplit mode with -n or -p (splits $_ into $F)",
00080 "-c              check syntax only",
00081 "-Cdirectory     cd to directory, before executing your script",
00082 "-d              set debugging flags (set $DEBUG to true)",
00083 "-e 'command'    one line of script. Several -e's allowed. Omit [programfile]",
00084 "-Fpattern       split() pattern for autosplit (-a)",
00085 "-i[extension]   edit ARGV files in place (make backup if extension supplied)",
00086 "-Idirectory     specify $LOAD_PATH directory (may be used more than once)",
00087 "-Kkcode         specifies KANJI (Japanese) code-set",
00088 "-l              enable line ending processing",
00089 "-n              assume 'while gets(); ... end' loop around your script",
00090 "-p              assume loop like -n but print line also like sed",
00091 "-rlibrary       require the library, before executing your script",
00092 "-s              enable some switch parsing for switches after script name",
00093 "-S              look for the script using PATH environment variable",
00094 "-T[level]       turn on tainting checks",
00095 "-v              print version number, then turn on verbose mode",
00096 "-w              turn warnings on for your script",
00097 "-W[level]       set warning level; 0=silence, 1=medium, 2=verbose (default)",
00098 "-x[directory]   strip off text before #!ruby line and perhaps cd to directory",
00099 "--copyright     print the copyright",
00100 "--version       print the version",
00101 NULL
00102 };
00103     char **p = usage_msg;
00104 
00105     printf("Usage: %s [switches] [--] [programfile] [arguments]\n", name);
00106     while (*p)
00107         printf("  %s\n", *p++);
00108 }
00109 
00110 extern VALUE rb_load_path;
00111 
00112 #define STATIC_FILE_LENGTH 255
00113 
00114 #if defined _WIN32 || defined __CYGWIN__ || defined __DJGPP__
00115 static char *
00116 rubylib_mangle(s, l)
00117     char *s;
00118     unsigned int l;
00119 {
00120     static char *newp, *oldp;
00121     static int newl, oldl, notfound;
00122     static char newsub[STATIC_FILE_LENGTH+1];
00123 
00124     if (!newp && !notfound) {
00125         newp = getenv("RUBYLIB_PREFIX");
00126         if (newp) {
00127             char *s;
00128 
00129             oldp = newp;
00130             while (*newp && !ISSPACE(*newp) && *newp != ';') {
00131                 newp++; oldl++;         /* Skip digits. */
00132             }
00133             while (*newp && (ISSPACE(*newp) || *newp == ';')) {
00134                 newp++;                 /* Skip whitespace. */
00135             }
00136             newl = strlen(newp);
00137             if (newl == 0 || oldl == 0 || newl > STATIC_FILE_LENGTH) {
00138                 rb_fatal("malformed RUBYLIB_PREFIX");
00139             }
00140             strcpy(newsub, newp);
00141             s = newsub;
00142             while (*s) {
00143                 if (*s == '\\') *s = '/';
00144                 s++;
00145             }
00146         }
00147         else {
00148             notfound = 1;
00149         }
00150     }
00151     if (l == 0) {
00152         l = strlen(s);
00153     }
00154     if (!newp || l < oldl || strncasecmp(oldp, s, oldl) != 0) {
00155         static char ret[STATIC_FILE_LENGTH+1];
00156         strncpy(ret, s, l);
00157         ret[l] = 0;
00158         return ret;
00159     }
00160     if (l + newl - oldl > STATIC_FILE_LENGTH || newl > STATIC_FILE_LENGTH) {
00161         rb_fatal("malformed RUBYLIB_PREFIX");
00162     }
00163     strcpy(newsub + newl, s + oldl);
00164     newsub[l + newl - oldl] = 0;
00165     return newsub;
00166 }
00167 #define rubylib_mangled_path(s, l) rb_str_new2(rubylib_mangle((s), (l)))
00168 #define rubylib_mangled_path2(s) rb_str_new2(rubylib_mangle((s), 0))
00169 #else
00170 #define rubylib_mangled_path(s, l) rb_str_new((s), (l))
00171 #define rubylib_mangled_path2(s) rb_str_new2(s)
00172 #endif
00173 
00174 void
00175 ruby_incpush(path)
00176     const char *path;
00177 {
00178     const char sep = PATH_SEP_CHAR;
00179 
00180     if (path == 0) return;
00181 #if defined(__CYGWIN__)
00182     {
00183         char rubylib[FILENAME_MAX];
00184         conv_to_posix_path(path, rubylib, FILENAME_MAX);
00185         path = rubylib;
00186     }
00187 #endif
00188     if (strchr(path, sep)) {
00189         const char *p, *s;
00190         VALUE ary = rb_ary_new();
00191 
00192         p = path;
00193         while (*p) {
00194             while (*p == sep) p++;
00195             if ((s = strchr(p, sep)) != 0) {
00196                 rb_ary_push(ary, rubylib_mangled_path(p, (int)(s-p)));
00197                 p = s + 1;
00198             }
00199             else {
00200                 rb_ary_push(ary, rubylib_mangled_path2(p));
00201                 break;
00202             }
00203         }
00204         rb_ary_concat(rb_load_path, ary);
00205     }
00206     else {
00207         rb_ary_push(rb_load_path, rubylib_mangled_path2(path));
00208     }
00209 }
00210 
00211 #if defined DOSISH || defined __CYGWIN__
00212 #define LOAD_RELATIVE 1
00213 #endif
00214 
00215 #if defined DOSISH || defined __CYGWIN__
00216 static inline void translate_char (char *, int, int);
00217 
00218 static inline void
00219 translate_char(p, from, to)
00220     char *p;
00221     int from, to;
00222 {
00223     while (*p) {
00224         if ((unsigned char)*p == from)
00225             *p = to;
00226 #ifdef CharNext         /* defined as CharNext[AW] on Windows. */
00227         p = CharNext(p);
00228 #else
00229         p += mblen(p, MB_CUR_MAX);
00230 #endif
00231     }
00232 }
00233 #endif
00234 
00235 void
00236 ruby_init_loadpath()
00237 {
00238 #if defined LOAD_RELATIVE
00239     char libpath[FILENAME_MAX+1];
00240     char *p;
00241     int rest;
00242 #if defined _WIN32 || defined __CYGWIN__
00243     HMODULE libruby = NULL;
00244     MEMORY_BASIC_INFORMATION m;
00245 
00246 #ifndef _WIN32_WCE
00247     memset(&m, 0, sizeof(m));
00248     if (VirtualQuery(ruby_init_loadpath, &m, sizeof(m)) && m.State == MEM_COMMIT)
00249         libruby = (HMODULE)m.AllocationBase;
00250 #endif
00251     GetModuleFileName(libruby, libpath, sizeof libpath);
00252 #elif defined(DJGPP)
00253     extern char *__dos_argv0;
00254     strncpy(libpath, __dos_argv0, FILENAME_MAX);
00255 #elif defined(__human68k__)
00256     extern char **_argv;
00257     strncpy(libpath, _argv[0], FILENAME_MAX);
00258 #elif defined(__EMX__)
00259     _execname(libpath, FILENAME_MAX);
00260 #endif
00261 
00262     libpath[FILENAME_MAX] = '\0';
00263 #if defined DOSISH || defined __CYGWIN__
00264     translate_char(libpath, '\\', '/');
00265 #endif
00266     p = strrchr(libpath, '/');
00267     if (p) {
00268         *p = 0;
00269         if (p-libpath > 3 && !strcasecmp(p-4, "/bin")) {
00270             p -= 4;
00271             *p = 0;
00272         }
00273     }
00274     else {
00275         strcpy(libpath, ".");
00276         p = libpath + 1;
00277     }
00278 
00279     rest = FILENAME_MAX - (p - libpath);
00280 
00281 #define RUBY_RELATIVE(path) (strncpy(p, (path), rest), libpath)
00282 #else
00283 #define RUBY_RELATIVE(path) (path)
00284 #endif
00285 
00286     if (rb_safe_level() == 0) {
00287         ruby_incpush(getenv("RUBYLIB"));
00288     }
00289 
00290 #ifdef RUBY_SEARCH_PATH
00291     ruby_incpush(RUBY_RELATIVE(RUBY_SEARCH_PATH));
00292 #endif
00293 
00294     ruby_incpush(RUBY_RELATIVE(RUBY_SITE_LIB2));
00295 #ifdef RUBY_SITE_THIN_ARCHLIB
00296     ruby_incpush(RUBY_RELATIVE(RUBY_SITE_THIN_ARCHLIB));
00297 #endif
00298     ruby_incpush(RUBY_RELATIVE(RUBY_SITE_ARCHLIB));
00299     ruby_incpush(RUBY_RELATIVE(RUBY_SITE_LIB));
00300 
00301     ruby_incpush(RUBY_RELATIVE(RUBY_LIB));
00302 #ifdef RUBY_THIN_ARCHLIB
00303     ruby_incpush(RUBY_RELATIVE(RUBY_THIN_ARCHLIB));
00304 #endif
00305     ruby_incpush(RUBY_RELATIVE(RUBY_ARCHLIB));
00306 
00307     if (rb_safe_level() == 0) {
00308         ruby_incpush(".");
00309     }
00310 }
00311 
00312 struct req_list {
00313     char *name;
00314     struct req_list *next;
00315 };
00316 static struct req_list req_list_head, *req_list_last = &req_list_head;
00317 
00318 static void
00319 add_modules(mod)
00320     const char *mod;
00321 {
00322     struct req_list *list;
00323 
00324     list = ALLOC(struct req_list);
00325     list->name = ALLOC_N(char, strlen(mod)+1);
00326     strcpy(list->name, mod);
00327     list->next = 0;
00328     req_list_last->next = list;
00329     req_list_last = list;
00330 }
00331 
00332 extern void Init_ext (void);
00333 
00334 static void
00335 require_libraries()
00336 {
00337     extern NODE *ruby_eval_tree;
00338     extern NODE *ruby_eval_tree_begin;
00339     NODE *save[3];
00340     struct req_list *list = req_list_head.next;
00341     struct req_list *tmp;
00342 
00343     save[0] = ruby_eval_tree;
00344     save[1] = ruby_eval_tree_begin;
00345     save[2] = NEW_NEWLINE(0);
00346     ruby_eval_tree = ruby_eval_tree_begin = 0;
00347     ruby_current_node = 0;
00348     Init_ext();         /* should be called here for some reason :-( */
00349     ruby_current_node = save[2];
00350     ruby_set_current_source();
00351     req_list_last = 0;
00352     while (list) {
00353         int state;
00354 
00355         ruby_current_node = 0;
00356         rb_protect((VALUE (*)(VALUE))rb_require, (VALUE)list->name, &state);
00357         if (state) rb_jump_tag(state);
00358         tmp = list->next;
00359         free(list->name);
00360         free(list);
00361         list = tmp;
00362         ruby_current_node = save[2];
00363         ruby_set_current_source();
00364     }
00365     req_list_head.next = 0;
00366     ruby_eval_tree = save[0];
00367     ruby_eval_tree_begin = save[1];
00368     rb_gc_force_recycle((VALUE)save[2]);
00369     ruby_current_node = 0;
00370 }
00371 
00372 static void
00373 process_sflag()
00374 {
00375     if (sflag) {
00376         long n;
00377         VALUE *args;
00378 
00379         n = RARRAY(rb_argv)->len;
00380         args = RARRAY(rb_argv)->ptr;
00381         while (n > 0) {
00382             VALUE v = *args++;
00383             char *s = StringValuePtr(v);
00384             char *p;
00385             int hyphen = Qfalse;
00386 
00387             if (s[0] != '-') break;
00388             n--;
00389             if (s[1] == '-' && s[2] == '\0') break;
00390 
00391             v = Qtrue;
00392             /* check if valid name before replacing - with _ */
00393             for (p = s + 1; *p; p++) {
00394                 if (*p == '=') {
00395                     *p++ = '\0';
00396                     v = rb_str_new2(p);
00397                     break;
00398                 }
00399                 if (*p == '-') {
00400                     hyphen = Qtrue;
00401                 }
00402                 else if (*p != '_' && !ISALNUM(*p)) {
00403                     VALUE name_error[2];
00404                     name_error[0] = rb_str_new2("invalid name for global variable - ");
00405                     if (!(p = strchr(p, '='))) {
00406                         rb_str_cat2(name_error[0], s);
00407                     }
00408                     else {
00409                         rb_str_cat(name_error[0], s, p - s);
00410                     }
00411                     name_error[1] = args[-1];
00412                     rb_exc_raise(rb_class_new_instance(2, name_error, rb_eNameError));
00413                 }
00414             }
00415             s[0] = '$';
00416             if (hyphen) {
00417                 for (p = s + 1; *p; ++p) {
00418                     if (*p == '-') *p = '_';
00419                 }
00420             }
00421             rb_gv_set(s, v);
00422         }
00423         n = RARRAY(rb_argv)->len - n;
00424         while (n--) {
00425             rb_ary_shift(rb_argv);
00426         }
00427     }
00428     sflag = 0;
00429 }
00430 
00431 static void proc_options (int argc, char **argv);
00432 
00433 static char*
00434 moreswitches(s)
00435     char *s;
00436 {
00437     int argc; char *argv[3];
00438     char *p = s;
00439 
00440     argc = 2; argv[0] = argv[2] = 0;
00441     while (*s && !ISSPACE(*s))
00442         s++;
00443     argv[1] = ALLOCA_N(char, s-p+2);
00444     argv[1][0] = '-';
00445     strncpy(argv[1]+1, p, s-p);
00446     argv[1][s-p+1] = '\0';
00447     proc_options(argc, argv);
00448     while (*s && ISSPACE(*s))
00449         s++;
00450     return s;
00451 }
00452 
00453 static void
00454 proc_options(argc, argv)
00455     int argc;
00456     char **argv;
00457 {
00458     char *argv0 = argv[0];
00459     int do_search;
00460     char *s;
00461     NODE *volatile script_node = 0;
00462 
00463     int version = 0;
00464     int copyright = 0;
00465     int verbose = 0;
00466     VALUE e_script = Qfalse;
00467 
00468     if (argc == 0) return;
00469 
00470     do_search = Qfalse;
00471 
00472     for (argc--,argv++; argc > 0; argc--,argv++) {
00473         if (argv[0][0] != '-' || !argv[0][1]) break;
00474 
00475         s = argv[0]+1;
00476       reswitch:
00477         switch (*s) {
00478           case 'a':
00479             do_split = Qtrue;
00480             s++;
00481             goto reswitch;
00482 
00483           case 'p':
00484             do_print = Qtrue;
00485             /* through */
00486           case 'n':
00487             do_loop = Qtrue;
00488             s++;
00489             goto reswitch;
00490 
00491           case 'd':
00492             ruby_debug = Qtrue;
00493             ruby_verbose = Qtrue;
00494             s++;
00495             goto reswitch;
00496 
00497           case 'y':
00498             ruby_yydebug = 1;
00499             s++;
00500             goto reswitch;
00501 
00502           case 'v':
00503             if (argv0 == 0 || verbose) {
00504                 s++;
00505                 goto reswitch;
00506             }
00507             ruby_show_version();
00508             verbose = 1;
00509           case 'w':
00510             ruby_verbose = Qtrue;
00511             s++;
00512             goto reswitch;
00513 
00514           case 'W':
00515             {
00516                 int numlen;
00517                 int v = 2;      /* -W as -W2 */
00518 
00519                 if (*++s) {
00520                     v = scan_oct(s, 1, &numlen);
00521                     if (numlen == 0) v = 1;
00522                     s += numlen;
00523                 }
00524                 switch (v) {
00525                   case 0:
00526                     ruby_verbose = Qnil; break;
00527                   case 1:
00528                     ruby_verbose = Qfalse; break;
00529                   default:
00530                     ruby_verbose = Qtrue; break;
00531                 }
00532             }
00533             goto reswitch;
00534 
00535           case 'c':
00536             do_check = Qtrue;
00537             s++;
00538             goto reswitch;
00539 
00540           case 's':
00541             forbid_setid("-s");
00542             sflag = 1;
00543             s++;
00544             goto reswitch;
00545 
00546           case 'h':
00547             usage(origargv[0]);
00548             exit(0);
00549 
00550           case 'l':
00551             do_line = Qtrue;
00552             rb_output_rs = rb_rs;
00553             s++;
00554             goto reswitch;
00555 
00556           case 'S':
00557             forbid_setid("-S");
00558             do_search = Qtrue;
00559             s++;
00560             goto reswitch;
00561 
00562           case 'e':
00563             forbid_setid("-e");
00564             if (!*++s) {
00565                 s = argv[1];
00566                 argc--,argv++;
00567             }
00568             if (!s) {
00569                 fprintf(stderr, "%s: no code specified for -e\n", origargv[0]);
00570                 exit(2);
00571             }
00572             if (!e_script) {
00573                 e_script = rb_str_new(0,0);
00574                 if (script == 0) script = "-e";
00575             }
00576             rb_str_cat2(e_script, s);
00577             rb_str_cat2(e_script, "\n");
00578             break;
00579 
00580           case 'r':
00581             forbid_setid("-r");
00582             if (*++s) {
00583                 add_modules(s);
00584             }
00585             else if (argv[1]) {
00586                 add_modules(argv[1]);
00587                 argc--,argv++;
00588             }
00589             break;
00590 
00591           case 'i':
00592             forbid_setid("-i");
00593             if (ruby_inplace_mode) free(ruby_inplace_mode);
00594             ruby_inplace_mode = strdup(s+1);
00595             break;
00596 
00597           case 'x':
00598             xflag = Qtrue;
00599             s++;
00600             if (*s && chdir(s) < 0) {
00601                 rb_fatal("Can't chdir to %s", s);
00602             }
00603             break;
00604 
00605           case 'C':
00606           case 'X':
00607             s++;
00608             if (!*s) {
00609                 s = argv[1];
00610                 argc--,argv++;
00611             }
00612             if (!s || !*s) {
00613                 rb_fatal("Can't chdir");
00614             }
00615             if (chdir(s) < 0) {
00616                 rb_fatal("Can't chdir to %s", s);
00617             }
00618             break;
00619 
00620           case 'F':
00621             if (*++s) {
00622                 rb_fs = rb_reg_new(s, strlen(s), 0);
00623             }
00624             break;
00625 
00626           case 'K':
00627             if (*++s) {
00628                 rb_set_kcode(s);
00629                 s++;
00630             }
00631             goto reswitch;
00632 
00633           case 'T':
00634             {
00635                 int numlen;
00636                 int v = 1;
00637 
00638                 if (*++s) {
00639                     v = scan_oct(s, 2, &numlen);
00640                     if (numlen == 0) v = 1;
00641                     s += numlen;
00642                 }
00643                 rb_set_safe_level(v);
00644             }
00645             goto reswitch;
00646 
00647           case 'I':
00648             forbid_setid("-I");
00649             if (*++s)
00650                 ruby_incpush(s);
00651             else if (argv[1]) {
00652                 ruby_incpush(argv[1]);
00653                 argc--,argv++;
00654             }
00655             break;
00656 
00657           case '0':
00658             {
00659                 int numlen;
00660                 int v;
00661                 char c;
00662 
00663                 v = scan_oct(s, 4, &numlen);
00664                 s += numlen;
00665                 if (v > 0377) rb_rs = Qnil;
00666                 else if (v == 0 && numlen >= 2) {
00667                     rb_rs = rb_str_new2("\n\n");
00668                 }
00669                 else {
00670                     c = v & 0xff;
00671                     rb_rs = rb_str_new(&c, 1);
00672                 }
00673             }
00674             goto reswitch;
00675 
00676           case '-':
00677             if (!s[1] || (s[1] == '\r' && !s[2])) {
00678                 argc--,argv++;
00679                 goto switch_end;
00680             }
00681             s++;
00682             if (strcmp("copyright", s) == 0)
00683                 copyright = 1;
00684             else if (strcmp("debug", s) == 0) {
00685                 ruby_debug = Qtrue;
00686                 ruby_verbose = Qtrue;
00687             }
00688             else if (strcmp("version", s) == 0)
00689                 version = 1;
00690             else if (strcmp("verbose", s) == 0) {
00691                 verbose = 1;
00692                 ruby_verbose = Qtrue;
00693             }
00694             else if (strcmp("yydebug", s) == 0)
00695                 ruby_yydebug = 1;
00696             else if (strcmp("help", s) == 0) {
00697                 usage(origargv[0]);
00698                 exit(0);
00699             }
00700             else {
00701                 fprintf(stderr, "%s: invalid option --%s  (-h will show valid options)\n",
00702                         origargv[0], s);
00703                 exit(2);
00704             }
00705             break;
00706 
00707           case '\r':
00708             if (!s[1]) break;
00709 
00710           default:
00711             {
00712                 const char *format;
00713                 if (ISPRINT(*s)) {
00714                     format = "%s: invalid option -%c  (-h will show valid options)\n";
00715                 }
00716                 else {
00717                     format = "%s: invalid option -\\%03o  (-h will show valid options)\n";
00718                 }
00719                 fprintf(stderr, format, origargv[0], (int)(unsigned char)*s);
00720             }
00721             exit(2);
00722 
00723           case 0:
00724             break;
00725         }
00726     }
00727 
00728   switch_end:
00729     if (argv0 == 0) return;
00730 
00731     if (rb_safe_level() == 0 && (s = getenv("RUBYOPT"))) {
00732         while (ISSPACE(*s)) s++;
00733         if (*s == 'T' || (*s == '-' && *(s+1) == 'T')) {
00734             int numlen;
00735             int v = 1;
00736 
00737             if (*s != 'T') ++s;
00738             if (*++s) {
00739                 v = scan_oct(s, 2, &numlen);
00740                 if (numlen == 0) v = 1;
00741             }
00742             rb_set_safe_level(v);
00743         }
00744         else {
00745             while (s && *s) {
00746                 if (*s == '-') {
00747                     s++;
00748                     if (ISSPACE(*s)) {
00749                         do {s++;} while (ISSPACE(*s));
00750                         continue;
00751                     }
00752                 }
00753                 if (!*s) break;
00754                 if (!strchr("IdvwrK", *s))
00755                     rb_raise(rb_eRuntimeError, "illegal switch in RUBYOPT: -%c", *s);
00756                 s = moreswitches(s);
00757             }
00758         }
00759     }
00760 
00761     if (version) {
00762         ruby_show_version();
00763         exit(0);
00764     }
00765     if (copyright) {
00766         ruby_show_copyright();
00767     }
00768 
00769     if (rb_safe_level() >= 4) {
00770         OBJ_TAINT(rb_argv);
00771         OBJ_TAINT(rb_load_path);
00772     }
00773 
00774     if (!e_script) {
00775         if (argc == 0) {        /* no more args */
00776             if (verbose) exit(0);
00777             script = "-";
00778         }
00779         else {
00780             script = argv[0];
00781             if (script[0] == '\0') {
00782                 script = "-";
00783             }
00784             else if (do_search) {
00785                 char *path = getenv("RUBYPATH");
00786 
00787                 script = 0;
00788                 if (path) {
00789                     script = dln_find_file(argv[0], path);
00790                 }
00791                 if (!script) {
00792                     script = dln_find_file(argv[0], getenv(PATH_ENV));
00793                 }
00794                 if (!script) script = argv[0];
00795                 script = ruby_sourcefile = rb_source_filename(script);
00796                 script_node = NEW_NEWLINE(0);
00797             }
00798 #if defined DOSISH || defined __CYGWIN__
00799             translate_char(script, '\\', '/');
00800 #endif
00801             argc--; argv++;
00802         }
00803     }
00804 
00805     ruby_script(script);
00806     ruby_set_argv(argc, argv);
00807     process_sflag();
00808 
00809     ruby_init_loadpath();
00810     ruby_sourcefile = rb_source_filename(argv0);
00811     if (e_script) {
00812         require_libraries();
00813         rb_compile_string(script, e_script, 1);
00814     }
00815     else if (strlen(script) == 1 && script[0] == '-') {
00816         load_stdin();
00817     }
00818     else {
00819         load_file(script, 1);
00820     }
00821 
00822     process_sflag();
00823     xflag = 0;
00824 
00825     if (rb_safe_level() >= 4) {
00826         FL_UNSET(rb_argv, FL_TAINT);
00827         FL_UNSET(rb_load_path, FL_TAINT);
00828     }
00829 }
00830 
00831 extern int ruby__end__seen;
00832 
00833 static void
00834 load_file(fname, script)
00835     const char *fname;
00836     int script;
00837 {
00838     extern VALUE rb_stdin;
00839     VALUE f;
00840     int line_start = 1;
00841 
00842     if (!fname) rb_load_fail(fname);
00843     if (strcmp(fname, "-") == 0) {
00844         f = rb_stdin;
00845     }
00846     else {
00847         FILE *fp = fopen(fname, "r");
00848 
00849         if (fp == NULL) {
00850             rb_load_fail(fname);
00851         }
00852         fclose(fp);
00853 
00854         f = rb_file_open(fname, "r");
00855 #if defined DOSISH || defined __CYGWIN__
00856         {
00857             char *ext = strrchr(fname, '.');
00858             if (ext && strcasecmp(ext, ".exe") == 0)
00859                 rb_io_binmode(f);
00860         }
00861 #endif
00862     }
00863 
00864     if (script) {
00865         VALUE c = 1;            /* something not nil */
00866         VALUE line;
00867         char *p;
00868 
00869         if (xflag) {
00870             forbid_setid("-x");
00871             xflag = Qfalse;
00872             while (!NIL_P(line = rb_io_gets(f))) {
00873                 line_start++;
00874                 if (RSTRING(line)->len > 2
00875                     && RSTRING(line)->ptr[0] == '#'
00876                     && RSTRING(line)->ptr[1] == '!') {
00877                     if ((p = strstr(RSTRING(line)->ptr, "ruby")) != 0) {
00878                         goto start_read;
00879                     }
00880                 }
00881             }
00882             rb_raise(rb_eLoadError, "no Ruby script found in input");
00883         }
00884 
00885         c = rb_io_getc(f);
00886         if (c == INT2FIX('#')) {
00887             line = rb_io_gets(f);
00888             if (NIL_P(line)) return;
00889             line_start++;
00890 
00891             if (RSTRING(line)->len > 2 && RSTRING(line)->ptr[0] == '!') {
00892                 if ((p = strstr(RSTRING(line)->ptr, "ruby")) == 0) {
00893                     /* not ruby script, kick the program */
00894                     char **argv;
00895                     char *path;
00896                     char *pend = RSTRING(line)->ptr + RSTRING(line)->len;
00897 
00898                     p = RSTRING(line)->ptr + 1; /* skip `#!' */
00899                     if (pend[-1] == '\n') pend--; /* chomp line */
00900                     if (pend[-1] == '\r') pend--;
00901                     *pend = '\0';
00902                     while (p < pend && ISSPACE(*p))
00903                         p++;
00904                     path = p;   /* interpreter path */
00905                     while (p < pend && !ISSPACE(*p))
00906                         p++;
00907                     *p++ = '\0';
00908                     if (p < pend) {
00909                         argv = ALLOCA_N(char*, origargc+3);
00910                         argv[1] = p;
00911                         MEMCPY(argv+2, origargv+1, char*, origargc);
00912                     }
00913                     else {
00914                         argv = origargv;
00915                     }
00916                     argv[0] = path;
00917                     execv(path, argv);
00918 
00919                     ruby_sourcefile = rb_source_filename(fname);
00920                     ruby_sourceline = 1;
00921                     rb_fatal("Can't exec %s", path);
00922                 }
00923 
00924               start_read:
00925                 p += 4;
00926                 RSTRING(line)->ptr[RSTRING(line)->len-1] = '\0';
00927                 if (RSTRING(line)->ptr[RSTRING(line)->len-2] == '\r')
00928                     RSTRING(line)->ptr[RSTRING(line)->len-2] = '\0';
00929                 if ((p = strstr(p, " -")) != 0) {
00930                     p++;        /* skip space before `-' */
00931                     while (*p == '-') {
00932                         p = moreswitches(p+1);
00933                     }
00934                 }
00935             }
00936         }
00937         else if (!NIL_P(c)) {
00938             rb_io_ungetc(f, c);
00939         }
00940         require_libraries();    /* Why here? unnatural */
00941         if (NIL_P(c)) return;
00942     }
00943     rb_compile_file(fname, f, line_start);
00944     if (script && ruby__end__seen) {
00945         rb_define_global_const("DATA", f);
00946     }
00947     else if (f != rb_stdin) {
00948         rb_io_close(f);
00949     }
00950 
00951     if (ruby_parser_stack_on_heap()) {
00952         rb_gc();
00953     }
00954 }
00955 
00956 void
00957 rb_load_file(fname)
00958     const char *fname;
00959 {
00960     load_file(fname, 0);
00961 }
00962 
00963 static void
00964 load_stdin()
00965 {
00966     forbid_setid("program input from stdin");
00967     load_file("-", 1);
00968 }
00969 
00970 VALUE rb_progname;
00971 VALUE rb_argv;
00972 VALUE rb_argv0;
00973 
00974 #if !defined(PSTAT_SETCMD) && !defined(HAVE_SETPROCTITLE) && !defined(DOSISH)
00975 static struct {
00976     char *begin, *end;
00977 } envspace;
00978 extern char **environ;
00979 
00980 static void
00981 set_arg0space()
00982 {
00983     char *s;
00984     int i;
00985 
00986     if (!environ || (s = environ[0]) == NULL) return;
00987     envspace.begin = s;
00988     s += strlen(s);
00989     for (i = 1; environ[i]; i++) {
00990         if (environ[i] == s + 1) {
00991             s++;
00992             s += strlen(s);     /* this one is ok too */
00993         }
00994     }
00995     envspace.end = s;
00996 }
00997 #else
00998 #define set_arg0space() ((void)0)
00999 #endif
01000 
01001 static void
01002 set_arg0(val, id)
01003     VALUE val;
01004     ID id;
01005 {
01006     char *s;
01007     long i;
01008 #if !defined(PSTAT_SETCMD) && !defined(HAVE_SETPROCTITLE)
01009     static int len;
01010 #endif
01011 
01012     if (origargv == 0) rb_raise(rb_eRuntimeError, "$0 not initialized");
01013     StringValue(val);
01014     s = RSTRING(val)->ptr;
01015     i = RSTRING(val)->len;
01016 #if defined(PSTAT_SETCMD)
01017     if (i >= PST_CLEN) {
01018         union pstun j;
01019         j.pst_command = s;
01020         i = PST_CLEN;
01021         RSTRING(val)->len = i;
01022         *(s + i) = '\0';
01023         pstat(PSTAT_SETCMD, j, PST_CLEN, 0, 0);
01024     }
01025     else {
01026         union pstun j;
01027         j.pst_command = s;
01028         pstat(PSTAT_SETCMD, j, i, 0, 0);
01029     }
01030     rb_progname = rb_tainted_str_new(s, i);
01031 #elif defined(HAVE_SETPROCTITLE)
01032     setproctitle("%.*s", (int)i, s);
01033     rb_progname = rb_tainted_str_new(s, i);
01034 #else
01035     if (len == 0) {
01036         char *s = origargv[0];
01037         int i;
01038 
01039         s += strlen(s);
01040         /* See if all the arguments are contiguous in memory */
01041         for (i = 1; i < origargc; i++) {
01042             if (origargv[i] == s + 1) {
01043                 s++;
01044                 s += strlen(s); /* this one is ok too */
01045             }
01046             else {
01047                 break;
01048             }
01049         }
01050 #ifndef DOSISH
01051         if (s + 1 == envspace.begin) {
01052             s = envspace.end;
01053             ruby_setenv("", NULL); /* duplicate environ vars */
01054         }
01055 #endif
01056         len = s - origargv[0];
01057     }
01058 
01059     if (i >= len) {
01060         i = len;
01061         memcpy(origargv[0], s, i);
01062         origargv[0][i] = '\0';
01063     }
01064     else {
01065         memcpy(origargv[0], s, i);
01066         s = origargv[0]+i;
01067         *s++ = '\0';
01068         while (++i < len)
01069             *s++ = ' ';
01070         for (i = 1; i < origargc; i++)
01071             origargv[i] = 0;
01072     }
01073     rb_progname = rb_tainted_str_new2(origargv[0]);
01074 #endif
01075 }
01076 
01077 void
01078 ruby_script(name)
01079     const char *name;
01080 {
01081     if (name) {
01082         rb_progname = rb_tainted_str_new2(name);
01083         ruby_sourcefile = rb_source_filename(name);
01084     }
01085 }
01086 
01087 static int uid, euid, gid, egid;
01088 
01089 static void
01090 init_ids()
01091 {
01092     uid = (int)getuid();
01093     euid = (int)geteuid();
01094     gid = (int)getgid();
01095     egid = (int)getegid();
01096 #ifdef VMS
01097     uid |= gid << 16;
01098     euid |= egid << 16;
01099 #endif
01100     if (uid && (euid != uid || egid != gid)) {
01101         rb_set_safe_level(1);
01102     }
01103 }
01104 
01105 static void
01106 forbid_setid(s)
01107     const char *s;
01108 {
01109     if (euid != uid)
01110         rb_raise(rb_eSecurityError, "no %s allowed while running setuid", s);
01111     if (egid != gid)
01112         rb_raise(rb_eSecurityError, "no %s allowed while running setgid", s);
01113     if (rb_safe_level() > 0)
01114         rb_raise(rb_eSecurityError, "no %s allowed in tainted mode", s);
01115 }
01116 
01117 static void
01118 verbose_setter(val, id, variable)
01119     VALUE val;
01120     ID id;
01121     VALUE *variable;
01122 {
01123     ruby_verbose = RTEST(val) ? Qtrue : val;
01124 }
01125 
01126 void
01127 ruby_prog_init()
01128 {
01129     init_ids();
01130 
01131     ruby_sourcefile = rb_source_filename("ruby");
01132     rb_define_hooked_variable("$VERBOSE", &ruby_verbose, 0, verbose_setter);
01133     rb_define_hooked_variable("$-v", &ruby_verbose, 0, verbose_setter);
01134     rb_define_hooked_variable("$-w", &ruby_verbose, 0, verbose_setter);
01135     rb_define_variable("$DEBUG", &ruby_debug);
01136     rb_define_variable("$-d", &ruby_debug);
01137     rb_define_readonly_variable("$-p", &do_print);
01138     rb_define_readonly_variable("$-l", &do_line);
01139 
01140     rb_define_hooked_variable("$0", &rb_progname, 0, set_arg0);
01141     rb_define_hooked_variable("$PROGRAM_NAME", &rb_progname, 0, set_arg0);
01142 
01143     rb_define_readonly_variable("$*", &rb_argv);
01144     rb_argv = rb_ary_new();
01145     rb_define_global_const("ARGV", rb_argv);
01146     rb_define_readonly_variable("$-a", &do_split);
01147     rb_global_variable(&rb_argv0);
01148 
01149 #ifdef MSDOS
01150     /*
01151      * There is no way we can refer to them from ruby, so close them to save
01152      * space.
01153      */
01154     (void)fclose(stdaux);
01155     (void)fclose(stdprn);
01156 #endif
01157 }
01158 
01159 void
01160 ruby_set_argv(argc, argv)
01161     int argc;
01162     char **argv;
01163 {
01164     int i;
01165 
01166 #if defined(USE_DLN_A_OUT)
01167     if (origargv) dln_argv0 = origargv[0];
01168     else          dln_argv0 = argv[0];
01169 #endif
01170     rb_ary_clear(rb_argv);
01171     for (i=0; i < argc; i++) {
01172         VALUE arg = rb_tainted_str_new2(argv[i]);
01173 
01174         OBJ_FREEZE(arg);
01175         rb_ary_push(rb_argv, arg);
01176     }
01177 }
01178 
01179 void
01180 ruby_process_options(argc, argv)
01181     int argc;
01182     char **argv;
01183 {
01184     origargc = argc; origargv = argv;
01185 
01186     ruby_script(argv[0]);       /* for the time being */
01187     rb_argv0 = rb_progname;
01188 #if defined(USE_DLN_A_OUT)
01189     dln_argv0 = argv[0];
01190 #endif
01191     set_arg0space();
01192     proc_options(argc, argv);
01193 
01194     if (do_check && ruby_nerrs == 0) {
01195         printf("Syntax OK\n");
01196         exit(0);
01197     }
01198     if (do_print) {
01199         rb_parser_append_print();
01200     }
01201     if (do_loop) {
01202         rb_parser_while_loop(do_line, do_split);
01203     }
01204 }
01205 

Generated on Wed Jan 18 23:32:06 2006 for Ruby by doxygen 1.3.5