ruby.c


DEFINITIONS

This source file includes following functions.
  1. usage
  2. rubylib_mangle
  3. ruby_incpush
  4. ruby_init_loadpath
  5. add_modules
  6. require_libraries
  7. process_sflag
  8. moreswitches
  9. proc_options
  10. load_file
  11. rb_load_file
  12. load_stdin
  13. set_arg0
  14. ruby_script
  15. init_ids
  16. forbid_setid
  17. ruby_prog_init
  18. ruby_set_argv
  19. ruby_process_options


   1  /**********************************************************************
   2  
   3    ruby.c -
   4  
   5    $Author: aamine $
   6    $Date: 2002/09/02 12:19:30 $
   7    created at: Tue Aug 10 12:47:31 JST 1993
   8  
   9    Copyright (C) 1993-2002 Yukihiro Matsumoto
  10    Copyright (C) 2000  Network Applied Communication Laboratory, Inc.
  11    Copyright (C) 2000  Information-technology Promotion Agency, Japan
  12  
  13  **********************************************************************/
  14  
  15  #if defined _WIN32 || defined __CYGWIN__
  16  #include <windows.h>
  17  #endif
  18  #include "ruby.h"
  19  #include "dln.h"
  20  #include "node.h"
  21  #include <stdio.h>
  22  #include <sys/types.h>
  23  #include <ctype.h>
  24  
  25  #ifdef __hpux
  26  #include <sys/pstat.h>
  27  #endif
  28  
  29  #ifdef HAVE_UNISTD_H
  30  #include <unistd.h>
  31  #endif
  32  
  33  #ifndef HAVE_STRING_H
  34  char *strchr _((const char*,const char));
  35  char *strrchr _((const char*,const char));
  36  char *strstr _((const char*,const char*));
  37  #endif
  38  
  39  #include "util.h"
  40  
  41  #ifndef HAVE_STDLIB_H
  42  char *getenv();
  43  #endif
  44  
  45  VALUE ruby_debug = Qfalse;
  46  VALUE ruby_verbose = Qfalse;
  47  static int sflag = 0;
  48  static int xflag = 0;
  49  extern int ruby_yydebug;
  50  
  51  char *ruby_inplace_mode = Qfalse;
  52  
  53  static void load_stdin _((void));
  54  static void load_file _((char *, int));
  55  static void forbid_setid _((const char *));
  56  
  57  static VALUE do_loop = Qfalse, do_print = Qfalse;
  58  static VALUE do_check = Qfalse, do_line = Qfalse;
  59  static VALUE do_split = Qfalse;
  60  
  61  static char *script;
  62  
  63  static int origargc;
  64  static char **origargv;
  65  
  66  static void
  67  usage(name)
  68      const char *name;
  69  {
  70      /* This message really ought to be max 23 lines.
  71       * Removed -h because the user already knows that option. Others? */
  72  
  73      static char *usage_msg[] = {
  74  "-0[octal]       specify record separator (\\0, if no argument)",
  75  "-a              autosplit mode with -n or -p (splits $_ into $F)",
  76  "-c              check syntax only",
  77  "-Cdirectory     cd to directory, before executing your script",
  78  "-d              set debugging flags (set $DEBUG to true)",
  79  "-e 'command'    one line of script. Several -e's allowed. Omit [programfile]",
  80  "-Fpattern       split() pattern for autosplit (-a)",
  81  "-i[extension]   edit ARGV files in place (make backup if extension supplied)",
  82  "-Idirectory     specify $LOAD_PATH directory (may be used more than once)",
  83  "-Kkcode         specifies KANJI (Japanese) code-set",
  84  "-l              enable line ending processing",
  85  "-n              assume 'while gets(); ... end' loop around your script",
  86  "-p              assume loop like -n but print line also like sed",
  87  "-rlibrary       require the library, before executing your script",
  88  "-s              enable some switch parsing for switches after script name",
  89  "-S              look for the script using PATH environment variable",
  90  "-T[level]       turn on tainting checks",
  91  "-v              print version number, then turn on verbose mode",
  92  "-w              turn warnings on for your script",
  93  "-x[directory]   strip off text before #!ruby line and perhaps cd to directory",
  94  "--copyright     print the copyright",
  95  "--version       print the version",
  96  NULL
  97  };
  98      char **p = usage_msg;
  99  
 100      printf("Usage: %s [switches] [--] [programfile] [arguments]\n", name);
 101      while (*p)
 102          printf("  %s\n", *p++);
 103  }
 104  
 105  extern VALUE rb_load_path;
 106  
 107  #define STATIC_FILE_LENGTH 255
 108  
 109  #if defined _WIN32 || defined __CYGWIN__ || defined __DJGPP__
 110  static char *
 111  rubylib_mangle(s, l)
 112      char *s;
 113      unsigned int l;
 114  {
 115      static char *newp, *oldp;
 116      static int newl, oldl, notfound;
 117      static char newsub[STATIC_FILE_LENGTH+1];
 118  
 119      if (!newp && !notfound) {
 120          newp = getenv("RUBYLIB_PREFIX");
 121          if (newp) {
 122              char *s;
 123  
 124              oldp = newp;
 125              while (*newp && !ISSPACE(*newp) && *newp != ';') {
 126                  newp++; oldl++;         /* Skip digits. */
 127              }
 128              while (*newp && (ISSPACE(*newp) || *newp == ';')) {
 129                  newp++;                 /* Skip whitespace. */
 130              }
 131              newl = strlen(newp);
 132              if (newl == 0 || oldl == 0 || newl > STATIC_FILE_LENGTH) {
 133                  rb_fatal("malformed RUBYLIB_PREFIX");
 134              }
 135              strcpy(newsub, newp);
 136              s = newsub;
 137              while (*s) {
 138                  if (*s == '\\') *s = '/';
 139                  s++;
 140              }
 141          }
 142          else {
 143              notfound = 1;
 144          }
 145      }
 146      if (l == 0) {
 147          l = strlen(s);
 148      }
 149      if (!newp || l < oldl || strncasecmp(oldp, s, oldl) != 0) {
 150          static char ret[STATIC_FILE_LENGTH+1];
 151          strncpy(ret, s, l);
 152          ret[l] = 0;
 153          return ret;
 154      }
 155      if (l + newl - oldl > STATIC_FILE_LENGTH || newl > STATIC_FILE_LENGTH) {
 156          rb_fatal("malformed RUBYLIB_PREFIX");
 157      }
 158      strcpy(newsub + newl, s + oldl);
 159      newsub[l + newl - oldl] = 0;
 160      return newsub;
 161  }
 162  #define rubylib_mangled_path(s, l) rb_str_new2(rubylib_mangle((s), (l)))
 163  #define rubylib_mangled_path2(s) rb_str_new2(rubylib_mangle((s), 0))
 164  #else
 165  #define rubylib_mangled_path(s, l) rb_str_new((s), (l))
 166  #define rubylib_mangled_path2(s) rb_str_new2(s)
 167  #endif
 168  
 169  void
 170  ruby_incpush(path)
 171      const char *path;
 172  {
 173      const char sep = PATH_SEP_CHAR;
 174  
 175      if (path == 0) return;
 176  #if defined(__CYGWIN__)
 177      {
 178          char rubylib[FILENAME_MAX];
 179          conv_to_posix_path(path, rubylib, FILENAME_MAX);
 180          path = rubylib;
 181      }
 182  #endif
 183      if (strchr(path, sep)) {
 184          const char *p, *s;
 185          VALUE ary = rb_ary_new();
 186  
 187          p = path;
 188          while (*p) {
 189              while (*p == sep) p++;
 190              if (s = strchr(p, sep)) {
 191                  rb_ary_push(ary, rubylib_mangled_path(p, (int)(s-p)));
 192                  p = s + 1;
 193              }
 194              else {
 195                  rb_ary_push(ary, rubylib_mangled_path2(p));
 196                  break;
 197              }
 198          }
 199          rb_ary_concat(rb_load_path, ary);
 200      }
 201      else {
 202          rb_ary_push(rb_load_path, rubylib_mangled_path2(path));
 203      }
 204  }
 205  
 206  #if defined _WIN32 || defined __CYGWIN__ || defined __DJGPP__ || defined __EMX__
 207  #define LOAD_RELATIVE 1
 208  #endif
 209  
 210  void
 211  ruby_init_loadpath()
 212  {
 213  #if defined LOAD_RELATIVE
 214      char libpath[FILENAME_MAX+1];
 215      char *p;
 216      int rest;
 217  #if defined _WIN32 || defined __CYGWIN__
 218  # if defined LIBRUBY_SO
 219      HMODULE libruby = GetModuleHandle(LIBRUBY_SO);
 220  # else
 221      HMODULE libruby = NULL;
 222  # endif
 223      GetModuleFileName(libruby, libpath, sizeof libpath);
 224  #elif defined(DJGPP)
 225      extern char *__dos_argv0;
 226      strncpy(libpath, __dos_argv0, FILENAME_MAX);
 227  #define CharNext(p) ((p) + mblen(p, MB_CUR_MAX))
 228  #elif defined(__EMX__)
 229      _execname(libpath, FILENAME_MAX);
 230  #endif
 231  
 232  #ifndef CharNext                /* defined as CharNext[AW] on Windows. */
 233  #define CharNext(p) ((p) + 1)
 234  #endif
 235  
 236      for (p = libpath; *p; p = CharNext(p))
 237          if (*p == '\\')
 238              *p = '/';
 239  
 240      p = strrchr(libpath, '/');
 241      if (p) {
 242          *p = 0;
 243          if (p-libpath > 3 && !strcasecmp(p-4, "/bin")) {
 244              p -= 4;
 245              *p = 0;
 246          }
 247      }
 248      else {
 249          strcpy(libpath, ".");
 250          p = libpath + 1;
 251      }
 252  
 253      rest = FILENAME_MAX - (p - libpath);
 254  
 255  #define RUBY_RELATIVE(path) (strncpy(p, (path), rest), libpath)
 256  #else
 257  #define RUBY_RELATIVE(path) (path)
 258  #endif
 259  
 260      if (rb_safe_level() == 0) {
 261          ruby_incpush(getenv("RUBYLIB"));
 262      }
 263  
 264  #ifdef RUBY_SEARCH_PATH
 265      ruby_incpush(RUBY_RELATIVE(RUBY_SEARCH_PATH));
 266  #endif
 267  
 268      ruby_incpush(RUBY_RELATIVE(RUBY_SITE_LIB2));
 269  #ifdef RUBY_SITE_THIN_ARCHLIB
 270      ruby_incpush(RUBY_RELATIVE(RUBY_SITE_THIN_ARCHLIB));
 271  #endif
 272      ruby_incpush(RUBY_RELATIVE(RUBY_SITE_ARCHLIB));
 273      ruby_incpush(RUBY_RELATIVE(RUBY_SITE_LIB));
 274  
 275      ruby_incpush(RUBY_RELATIVE(RUBY_LIB));
 276  #ifdef RUBY_THIN_ARCHLIB
 277      ruby_incpush(RUBY_RELATIVE(RUBY_THIN_ARCHLIB));
 278  #endif
 279      ruby_incpush(RUBY_RELATIVE(RUBY_ARCHLIB));
 280  
 281      if (rb_safe_level() == 0) {
 282          ruby_incpush(".");
 283      }
 284  }
 285  
 286  struct req_list {
 287      char *name;
 288      struct req_list *next;
 289  };
 290  static struct req_list req_list_head, *req_list_last = &req_list_head;
 291  
 292  static void
 293  add_modules(mod)
 294      const char *mod;
 295  {
 296      struct req_list *list;
 297  
 298      list = ALLOC(struct req_list);
 299      list->name = ALLOC_N(char, strlen(mod)+1);
 300      strcpy(list->name, mod);
 301      list->next = 0;
 302      req_list_last->next = list;
 303      req_list_last = list;
 304  }
 305  
 306  extern void Init_ext _((void));
 307  
 308  static void
 309  require_libraries()
 310  {
 311      extern NODE *ruby_eval_tree;
 312      extern NODE *ruby_eval_tree_begin;
 313      NODE *save[3];
 314      struct req_list *list = req_list_head.next;
 315      struct req_list *tmp;
 316  
 317      Init_ext();         /* should be called here for some reason :-( */
 318      save[0] = ruby_eval_tree;
 319      save[1] = ruby_eval_tree_begin;
 320      save[2] = NEW_NEWLINE(0);
 321      ruby_eval_tree = ruby_eval_tree_begin = 0;
 322      req_list_last = 0;
 323      while (list) {
 324          rb_require(list->name);
 325          tmp = list->next;
 326          free(list->name);
 327          free(list);
 328          list = tmp;
 329      }
 330      req_list_head.next = 0;
 331      ruby_eval_tree = save[0];
 332      ruby_eval_tree_begin = save[1];
 333      ruby_current_node = save[2];
 334      ruby_set_current_source();
 335      ruby_current_node = 0;
 336      rb_gc_force_recycle((VALUE)save[2]);
 337  }
 338  
 339  static void
 340  process_sflag()
 341  {
 342      if (sflag) {
 343          long n;
 344          VALUE *args;
 345  
 346          n = RARRAY(rb_argv)->len;
 347          args = RARRAY(rb_argv)->ptr;
 348          while (n > 0) {
 349              VALUE v = *args++;
 350              char *s = StringValuePtr(v);
 351              char *p;
 352  
 353              if (s[0] != '-') break;
 354              n--;
 355              if (s[1] == '-' && s[2] == '\0') break;
 356  
 357              s[0] = '$';
 358              if (p = strchr(s, '=')) {
 359                  *p++ = '\0';
 360                  rb_gv_set(s, rb_str_new2(p));
 361              }
 362              else {
 363                  rb_gv_set(s, Qtrue);
 364              }
 365              s[0] = '-';
 366          }
 367          n = RARRAY(rb_argv)->len - n;
 368          while (n--) {
 369              rb_ary_shift(rb_argv);
 370          }
 371      }
 372      sflag = 0;
 373  }
 374  
 375  static void proc_options _((int argc, char **argv));
 376  
 377  static char*
 378  moreswitches(s)
 379      char *s;
 380  {
 381      int argc; char *argv[3];
 382      char *p = s;
 383  
 384      argc = 2; argv[0] = argv[2] = 0;
 385      while (*s && !ISSPACE(*s))
 386          s++;
 387      argv[1] = ALLOCA_N(char, s-p+2);
 388      argv[1][0] = '-';
 389      strncpy(argv[1]+1, p, s-p);
 390      argv[1][s-p+1] = '\0';
 391      proc_options(argc, argv);
 392      while (*s && ISSPACE(*s))
 393          s++;
 394      return s;
 395  }
 396  
 397  static void
 398  proc_options(argc, argv)
 399      int argc;
 400      char **argv;
 401  {
 402      char *argv0 = argv[0];
 403      int do_search;
 404      char *s;
 405  
 406      int version = 0;
 407      int copyright = 0;
 408      int verbose = 0;
 409      VALUE e_script = Qfalse;
 410  
 411      if (argc == 0) return;
 412  
 413      do_search = Qfalse;
 414  
 415      for (argc--,argv++; argc > 0; argc--,argv++) {
 416          if (argv[0][0] != '-' || !argv[0][1]) break;
 417  
 418          s = argv[0]+1;
 419        reswitch:
 420          switch (*s) {
 421            case 'a':
 422              do_split = Qtrue;
 423              s++;
 424              goto reswitch;
 425  
 426            case 'p':
 427              do_print = Qtrue;
 428              /* through */
 429            case 'n':
 430              do_loop = Qtrue;
 431              s++;
 432              goto reswitch;
 433  
 434            case 'd':
 435              ruby_debug = Qtrue;
 436              ruby_verbose = Qtrue;
 437              s++;
 438              goto reswitch;
 439  
 440            case 'y':
 441              ruby_yydebug = 1;
 442              s++;
 443              goto reswitch;
 444  
 445            case 'v':
 446              if (argv0 == 0 || verbose) {
 447                  s++;
 448                  goto reswitch;
 449              }
 450              ruby_show_version();
 451              verbose = 1;
 452            case 'w':
 453              ruby_verbose = Qtrue;
 454              s++;
 455              goto reswitch;
 456  
 457            case 'c':
 458              do_check = Qtrue;
 459              s++;
 460              goto reswitch;
 461  
 462            case 's':
 463              forbid_setid("-s");
 464              sflag = 1;
 465              s++;
 466              goto reswitch;
 467  
 468            case 'h':
 469              usage(origargv[0]);
 470              exit(0);
 471  
 472            case 'l':
 473              do_line = Qtrue;
 474              rb_output_rs = rb_rs;
 475              s++;
 476              goto reswitch;
 477  
 478            case 'S':
 479              forbid_setid("-S");
 480              do_search = Qtrue;
 481              s++;
 482              goto reswitch;
 483  
 484            case 'e':
 485              forbid_setid("-e");
 486              if (!*++s) {
 487                  s = argv[1];
 488                  argc--,argv++;
 489              }
 490              if (!s) {
 491                  fprintf(stderr, "%s: no code specified for -e\n", origargv[0]);
 492                  exit(2);
 493              }
 494              if (!e_script) {
 495                  e_script = rb_str_new(0,0);
 496                  if (script == 0) script = "-e";
 497              }
 498              rb_str_cat2(e_script, s);
 499              rb_str_cat2(e_script, "\n");
 500              break;
 501  
 502            case 'r':
 503              forbid_setid("-r");
 504              if (*++s) {
 505                  add_modules(s);
 506              }
 507              else if (argv[1]) {
 508                  add_modules(argv[1]);
 509                  argc--,argv++;
 510              }
 511              break;
 512  
 513            case 'i':
 514              forbid_setid("-i");
 515              if (ruby_inplace_mode) free(ruby_inplace_mode);
 516              ruby_inplace_mode = strdup(s+1);
 517              break;
 518  
 519            case 'x':
 520              xflag = Qtrue;
 521              s++;
 522              if (*s && chdir(s) < 0) {
 523                  rb_fatal("Can't chdir to %s", s);
 524              }
 525              break;
 526  
 527            case 'C':
 528            case 'X':
 529              s++;
 530              if (!*s) {
 531                  s = argv[1];
 532                  argc--,argv++;
 533              }
 534              if (!s || !*s) {
 535                  rb_fatal("Can't chdir");
 536              }
 537              if (chdir(s) < 0) {
 538                  rb_fatal("Can't chdir to %s", s);
 539              }
 540              break;
 541  
 542            case 'F':
 543              if (*++s) {
 544                  rb_fs = rb_str_new2(s);
 545              }
 546              break;
 547  
 548            case 'K':
 549              if (*++s) {
 550                  rb_set_kcode(s);
 551                  s++;
 552              }
 553              goto reswitch;
 554  
 555            case 'T':
 556              {
 557                  int numlen;
 558                  int v = 1;
 559  
 560                  if (*++s) {
 561                      v = scan_oct(s, 2, &numlen);
 562                      if (numlen == 0) v = 1;
 563                      s += numlen;
 564                  }
 565                  rb_set_safe_level(v);
 566              }
 567              goto reswitch;
 568  
 569            case 'I':
 570              forbid_setid("-I");
 571              if (*++s)
 572                  ruby_incpush(s);
 573              else if (argv[1]) {
 574                  ruby_incpush(argv[1]);
 575                  argc--,argv++;
 576              }
 577              break;
 578  
 579            case '0':
 580              {
 581                  int numlen;
 582                  int v;
 583                  char c;
 584  
 585                  v = scan_oct(s, 4, &numlen);
 586                  s += numlen;
 587                  if (v > 0377) rb_rs = Qnil;
 588                  else if (v == 0 && numlen >= 2) {
 589                      rb_rs = rb_str_new2("\n\n");
 590                  }
 591                  else {
 592                      c = v & 0xff;
 593                      rb_rs = rb_str_new(&c, 1);
 594                  }
 595              }
 596              goto reswitch;
 597  
 598            case '-':
 599              if (!s[1] || s[1] == '\r' && !s[2]) {
 600                  argc--,argv++;
 601                  goto switch_end;
 602              }
 603              s++;
 604              if (strcmp("copyright", s) == 0)
 605                  copyright = 1;
 606              else if (strcmp("debug", s) == 0) {
 607                  ruby_debug = Qtrue;
 608                  ruby_verbose = Qtrue;
 609              }
 610              else if (strcmp("version", s) == 0)
 611                  version = 1;
 612              else if (strcmp("verbose", s) == 0) {
 613                  verbose = 1;
 614                  ruby_verbose = Qtrue;
 615              }
 616              else if (strcmp("yydebug", s) == 0)
 617                  ruby_yydebug = 1;
 618              else if (strcmp("help", s) == 0) {
 619                  usage(origargv[0]);
 620                  exit(0);
 621              }
 622              else {
 623                  fprintf(stderr, "%s: invalid option --%s  (-h will show valid options)\n",
 624                          origargv[0], s);
 625                  exit(2);
 626              }
 627              break;
 628  
 629            default:
 630              fprintf(stderr, "%s: invalid option -%c  (-h will show valid options)\n",
 631                      origargv[0], *s);
 632              exit(2);
 633  
 634            case 0:
 635              break;
 636          }
 637      }
 638  
 639    switch_end:
 640      if (argv0 == 0) return;
 641  
 642      if (rb_safe_level() == 0 && (s = getenv("RUBYOPT"))) {
 643          while (ISSPACE(*s)) s++;
 644          if (*s == '-' && *(s+1) == 'T') {
 645              int numlen;
 646              int v = 1;
 647  
 648              s += 2;
 649              if (*++s) {
 650                  v = scan_oct(s, 2, &numlen);
 651                  if (numlen == 0) v = 1;
 652              }
 653              rb_set_safe_level(v);
 654          }
 655          else {
 656              while (s && *s) {
 657                  if (*s == '-') {
 658                      s++;
 659                      if (ISSPACE(*s)) {
 660                          do {s++;} while (ISSPACE(*s));
 661                          continue;
 662                      }
 663                  }
 664                  if (!*s) break;
 665                  if (!strchr("IdvwrK", *s))
 666                      rb_raise(rb_eRuntimeError, "Illegal switch in RUBYOPT: -%c", *s);
 667                  s = moreswitches(s);
 668              }
 669          }
 670      }
 671  
 672      if (version) {
 673          ruby_show_version();
 674          exit(0);
 675      }
 676      if (copyright) {
 677          ruby_show_copyright();
 678      }
 679  
 680      if (rb_safe_level() >= 4) {
 681        OBJ_TAINT(rb_argv);
 682        OBJ_TAINT(rb_load_path);
 683      }
 684  
 685      if (!e_script && argc == 0) { /* no more args */
 686          if (verbose) exit(0);
 687          script = "-";
 688      }
 689      else {
 690          if (!e_script) {
 691              script = argv[0];
 692          }
 693          if (script[0] == '\0') {
 694              script = "-";
 695          }
 696          else {
 697              if (do_search) {
 698                  char *path = getenv("RUBYPATH");
 699  
 700                  script = 0;
 701                  if (path) {
 702                      script = dln_find_file(argv[0], path);
 703                  }
 704                  if (!script) {
 705                      script = dln_find_file(argv[0], getenv("PATH"));
 706                  }
 707                  if (!script) script = argv[0];
 708              }
 709          }
 710          if (!e_script) {
 711              argc--; argv++;
 712          }
 713      }
 714  
 715      ruby_script(script);
 716      ruby_set_argv(argc, argv);
 717      process_sflag();
 718  
 719      ruby_init_loadpath();
 720      ruby_sourcefile = rb_source_filename(argv0);
 721      if (e_script) {
 722          require_libraries();
 723          rb_compile_string(script, e_script, 1);
 724      }
 725      else if (strlen(script) == 1 && script[0] == '-') {
 726          load_stdin();
 727      }
 728      else {
 729          load_file(script, 1);
 730      }
 731  
 732      process_sflag();
 733      xflag = 0;
 734  
 735      if (rb_safe_level() >= 4) {
 736        FL_UNSET(rb_argv, FL_TAINT);
 737        FL_UNSET(rb_load_path, FL_TAINT);
 738      }
 739  }
 740  
 741  extern int ruby__end__seen;
 742  
 743  static void
 744  load_file(fname, script)
 745      char *fname;
 746      int script;
 747  {
 748      extern VALUE rb_stdin;
 749      VALUE f;
 750      int line_start = 1;
 751  
 752      if (strcmp(fname, "-") == 0) {
 753          f = rb_stdin;
 754      }
 755      else {
 756          FILE *fp = fopen(fname, "r");
 757  
 758          if (fp == NULL) {
 759              rb_load_fail(fname);
 760          }
 761          fclose(fp);
 762  
 763          f = rb_file_open(fname, "r");
 764  #if defined DOSISH || defined __CYGWIN__
 765          {
 766              char *ext = strrchr(fname, '.');
 767              if (ext && strcasecmp(ext, ".exe") == 0)
 768                  rb_io_binmode(f);
 769          }
 770  #endif
 771      }
 772  
 773      if (script) {
 774          VALUE c = 1;            /* something not nil */
 775          VALUE line;
 776          char *p;
 777  
 778          if (xflag) {
 779              forbid_setid("-x");
 780              xflag = Qfalse;
 781              while (!NIL_P(line = rb_io_gets(f))) {
 782                  line_start++;
 783                  if (RSTRING(line)->len > 2
 784                      && RSTRING(line)->ptr[0] == '#'
 785                      && RSTRING(line)->ptr[1] == '!') {
 786                      if (p = strstr(RSTRING(line)->ptr, "ruby")) {
 787                          goto start_read;
 788                      }
 789                  }
 790              }
 791              rb_raise(rb_eLoadError, "No Ruby script found in input");
 792          }
 793  
 794          c = rb_io_getc(f);
 795          if (c == INT2FIX('#')) {
 796              line = rb_io_gets(f);
 797              if (NIL_P(line)) return;
 798              line_start++;
 799  
 800              if (RSTRING(line)->len > 2 && RSTRING(line)->ptr[0] == '!') {
 801                  if ((p = strstr(RSTRING(line)->ptr, "ruby")) == 0) {
 802                      /* not ruby script, kick the program */
 803                      char **argv;
 804                      char *path;
 805                      char *pend = RSTRING(line)->ptr + RSTRING(line)->len;
 806  
 807                      p = RSTRING(line)->ptr + 1; /* skip `#!' */
 808                      if (pend[-1] == '\n') pend--; /* chomp line */
 809                      if (pend[-1] == '\r') pend--;
 810                      *pend = '\0';
 811                      while (p < pend && ISSPACE(*p))
 812                          p++;
 813                      path = p;   /* interpreter path */
 814                      while (p < pend && !ISSPACE(*p))
 815                          p++;
 816                      *p++ = '\0';
 817                      if (p < pend) {
 818                          argv = ALLOCA_N(char*, origargc+3);
 819                          argv[1] = p;
 820                          MEMCPY(argv+2, origargv+1, char*, origargc);
 821                      }
 822                      else {
 823                          argv = origargv;
 824                      }
 825                      argv[0] = path;
 826                      execv(path, argv);
 827  
 828                      ruby_sourcefile = rb_source_filename(fname);
 829                      ruby_sourceline = 1;
 830                      rb_fatal("Can't exec %s", path);
 831                  }
 832  
 833                start_read:
 834                  p += 4;
 835                  RSTRING(line)->ptr[RSTRING(line)->len-1] = '\0';
 836                  if (RSTRING(line)->ptr[RSTRING(line)->len-2] == '\r')
 837                      RSTRING(line)->ptr[RSTRING(line)->len-2] = '\0';
 838                  if (p = strstr(p, " -")) {
 839                      p++;        /* skip space before `-' */
 840                      while (*p == '-') {
 841                          p = moreswitches(p+1);
 842                      }
 843                  }
 844              }
 845          }
 846          else if (!NIL_P(c)) {
 847              rb_io_ungetc(f, c);
 848          }
 849          require_libraries();    /* Why here? unnatural */
 850          if (NIL_P(c)) return;
 851      }
 852      rb_compile_file(fname, f, line_start);
 853      if (script && ruby__end__seen) {
 854          rb_define_global_const("DATA", f);
 855      }
 856      else if (f != rb_stdin) {
 857          rb_io_close(f);
 858      }
 859  
 860      if (ruby_parser_stack_on_heap()) {
 861          rb_gc();
 862      }
 863  }
 864  
 865  void
 866  rb_load_file(fname)
 867      char *fname;
 868  {
 869      load_file(fname, 0);
 870  }
 871  
 872  static void
 873  load_stdin()
 874  {
 875      forbid_setid("program input from stdin");
 876      load_file("-", 1);
 877  }
 878  
 879  VALUE rb_progname;
 880  VALUE rb_argv;
 881  VALUE rb_argv0;
 882  
 883  static void
 884  set_arg0(val, id)
 885      VALUE val;
 886      ID id;
 887  {
 888      char *s;
 889      long i;
 890      static int len;
 891  
 892      if (origargv == 0) rb_raise(rb_eRuntimeError, "$0 not initialized");
 893      StringValue(val);
 894      s = RSTRING(val)->ptr;
 895      i = RSTRING(val)->len;
 896  #ifdef __hpux
 897      if (i >= PST_CLEN) {
 898        union pstun j;
 899        j.pst_command = s;
 900        i = PST_CLEN;
 901        RSTRING(val)->len = i;
 902        *(s + i) = '\0';
 903        pstat(PSTAT_SETCMD, j, PST_CLEN, 0, 0);
 904      }
 905      else {
 906        union pstun j;
 907        j.pst_command = s;
 908        pstat(PSTAT_SETCMD, j, i, 0, 0);
 909      }
 910      rb_progname = rb_tainted_str_new(s, i);
 911  #elif defined(HAVE_SETPROCTITLE)
 912      setproctitle("%.*s", i, s);
 913      rb_progname = rb_tainted_str_new(s, i);
 914  #else
 915      if (len == 0) {
 916          char *s = origargv[0];
 917          int i;
 918  
 919          s += strlen(s);
 920          /* See if all the arguments are contiguous in memory */
 921          for (i = 1; i < origargc; i++) {
 922              if (origargv[i] == s + 1) {
 923                  s++;
 924                  s += strlen(s); /* this one is ok too */
 925              }
 926              else {
 927                  break;
 928              }
 929          }
 930          len = s - origargv[0];
 931      }
 932  
 933      if (i >= len) {
 934          i = len;
 935          memcpy(origargv[0], s, i);
 936          origargv[0][i] = '\0';
 937      }
 938      else {
 939          memcpy(origargv[0], s, i);
 940          s = origargv[0]+i;
 941          *s++ = '\0';
 942          while (++i < len)
 943              *s++ = ' ';
 944          for (i = 1; i < origargc; i++)
 945              origargv[i] = 0;
 946      }
 947      rb_progname = rb_tainted_str_new2(origargv[0]);
 948  #endif
 949  }
 950  
 951  void
 952  ruby_script(name)
 953      char *name;
 954  {
 955      if (name) {
 956          rb_progname = rb_tainted_str_new2(name);
 957          ruby_sourcefile = rb_source_filename(name);
 958      }
 959  }
 960  
 961  static int uid, euid, gid, egid;
 962  
 963  static void
 964  init_ids()
 965  {
 966      uid = (int)getuid();
 967      euid = (int)geteuid();
 968      gid = (int)getgid();
 969      egid = (int)getegid();
 970  #ifdef VMS
 971      uid |= gid << 16;
 972      euid |= egid << 16;
 973  #endif
 974      if (uid && (euid != uid || egid != gid)) {
 975          rb_set_safe_level(1);
 976      }
 977  }
 978  
 979  static void
 980  forbid_setid(s)
 981      const char *s;
 982  {
 983      if (euid != uid)
 984          rb_raise(rb_eSecurityError, "No %s allowed while running setuid", s);
 985      if (egid != gid)
 986          rb_raise(rb_eSecurityError, "No %s allowed while running setgid", s);
 987      if (rb_safe_level() > 0)
 988          rb_raise(rb_eSecurityError, "No %s allowed in tainted mode", s);
 989  }
 990  
 991  void
 992  ruby_prog_init()
 993  {
 994      init_ids();
 995  
 996      ruby_sourcefile = rb_source_filename("ruby");
 997      rb_define_variable("$VERBOSE", &ruby_verbose);
 998      rb_define_variable("$-v", &ruby_verbose);
 999      rb_define_variable("$-w", &ruby_verbose);
1000      rb_define_variable("$DEBUG", &ruby_debug);
1001      rb_define_variable("$-d", &ruby_debug);
1002      rb_define_readonly_variable("$-p", &do_print);
1003      rb_define_readonly_variable("$-l", &do_line);
1004  
1005      rb_define_hooked_variable("$0", &rb_progname, 0, set_arg0);
1006  
1007      rb_argv = rb_ary_new();
1008      rb_define_readonly_variable("$*", &rb_argv);
1009      rb_define_global_const("ARGV", rb_argv);
1010      rb_define_readonly_variable("$-a", &do_split);
1011      rb_global_variable(&rb_argv0);
1012  
1013  #ifdef MSDOS
1014      /*
1015       * There is no way we can refer to them from ruby, so close them to save
1016       * space.
1017       */
1018      (void)fclose(stdaux);
1019      (void)fclose(stdprn);
1020  #endif
1021  }
1022  
1023  void
1024  ruby_set_argv(argc, argv)
1025      int argc;
1026      char **argv;
1027  {
1028      int i;
1029  
1030  #if defined(USE_DLN_A_OUT)
1031      if (origargv) dln_argv0 = origargv[0];
1032      else          dln_argv0 = argv[0];
1033  #endif
1034      rb_ary_clear(rb_argv);
1035      for (i=0; i < argc; i++) {
1036          rb_ary_push(rb_argv, rb_tainted_str_new2(argv[i]));
1037      }
1038  }
1039  
1040  void
1041  ruby_process_options(argc, argv)
1042      int argc;
1043      char **argv;
1044  {
1045      origargc = argc; origargv = argv;
1046  
1047      ruby_script(argv[0]);       /* for the time being */
1048      rb_argv0 = rb_progname;
1049  #if defined(USE_DLN_A_OUT)
1050      dln_argv0 = argv[0];
1051  #endif
1052      proc_options(argc, argv);
1053  
1054      if (do_check && ruby_nerrs == 0) {
1055          printf("Syntax OK\n");
1056          exit(0);
1057      }
1058      if (do_print) {
1059          rb_parser_append_print();
1060      }
1061      if (do_loop) {
1062          rb_parser_while_loop(do_line, do_split);
1063      }
1064  }