* string.c (rb_str_each_line): return original string.
[ruby-svn.git] / ruby.c
blobf0c1c278047fe3fb2525b8b53f3ff3fda835e673
1 /**********************************************************************
3 ruby.c -
5 $Author$
6 created at: Tue Aug 10 12:47:31 JST 1993
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
12 **********************************************************************/
14 #ifdef __CYGWIN__
15 #include <windows.h>
16 #include <sys/cygwin.h>
17 #endif
18 #ifdef _WIN32_WCE
19 #include <winsock.h>
20 #include "ruby/wince.h"
21 #endif
22 #include "ruby/ruby.h"
23 #include "ruby/node.h"
24 #include "ruby/encoding.h"
25 #include "eval_intern.h"
26 #include "dln.h"
27 #include <stdio.h>
28 #include <sys/types.h>
29 #include <ctype.h>
31 #ifdef __hpux
32 #include <sys/pstat.h>
33 #endif
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38 #if defined(HAVE_FCNTL_H)
39 #include <fcntl.h>
40 #elif defined(HAVE_SYS_FCNTL_H)
41 #include <sys/fcntl.h>
42 #endif
43 #ifdef HAVE_SYS_PARAM_H
44 # include <sys/param.h>
45 #endif
46 #ifndef MAXPATHLEN
47 # define MAXPATHLEN 1024
48 #endif
50 #if defined(__MACOS__) && defined(__MWERKS__)
51 #include <console.h>
52 #endif
54 #include "ruby/util.h"
56 #ifndef HAVE_STDLIB_H
57 char *getenv();
58 #endif
60 /* TODO: move to VM */
61 VALUE ruby_debug = Qfalse;
62 VALUE ruby_verbose = Qfalse;
63 VALUE rb_parser_get_yydebug(VALUE);
64 VALUE rb_parser_set_yydebug(VALUE, VALUE);
66 const char *ruby_get_inplace_mode(void);
67 void ruby_set_inplace_mode(const char *);
69 #define DISABLE_BIT(bit) (1U << disable_##bit)
70 enum disable_flag_bits {
71 disable_gems,
72 disable_rubyopt,
75 struct cmdline_options {
76 int sflag, xflag;
77 int do_loop, do_print;
78 int do_check, do_line;
79 int do_split, do_search;
80 int usage;
81 int version;
82 int copyright;
83 unsigned int disable;
84 int verbose;
85 int yydebug;
86 char *script;
87 VALUE script_name;
88 VALUE e_script;
89 struct {
90 struct {
91 VALUE name;
92 int index;
93 } enc;
94 } src, ext;
97 struct cmdline_arguments {
98 int argc;
99 char **argv;
100 struct cmdline_options *opt;
103 static NODE *load_file(VALUE, const char *, int, struct cmdline_options *);
104 static void forbid_setid(const char *);
106 static struct {
107 int argc;
108 char **argv;
109 #if !defined(PSTAT_SETCMD) && !defined(HAVE_SETPROCTITLE)
110 int len;
111 #endif
112 } origarg;
114 static void
115 usage(const char *name)
117 /* This message really ought to be max 23 lines.
118 * Removed -h because the user already knows that option. Others? */
120 static const char *const usage_msg[] = {
121 "-0[octal] specify record separator (\\0, if no argument)",
122 "-a autosplit mode with -n or -p (splits $_ into $F)",
123 "-c check syntax only",
124 "-Cdirectory cd to directory, before executing your script",
125 "-d set debugging flags (set $DEBUG to true)",
126 "-e 'command' one line of script. Several -e's allowed. Omit [programfile]",
127 "-Eencoding specifies the character encoding for the program codes",
128 "-Fpattern split() pattern for autosplit (-a)",
129 "-i[extension] edit ARGV files in place (make backup if extension supplied)",
130 "-Idirectory specify $LOAD_PATH directory (may be used more than once)",
131 "-l enable line ending processing",
132 "-n assume 'while gets(); ... end' loop around your script",
133 "-p assume loop like -n but print line also like sed",
134 "-rlibrary require the library, before executing your script",
135 "-s enable some switch parsing for switches after script name",
136 "-S look for the script using PATH environment variable",
137 "-T[level] turn on tainting checks",
138 "-v print version number, then turn on verbose mode",
139 "-w turn warnings on for your script",
140 "-W[level] set warning level; 0=silence, 1=medium, 2=verbose (default)",
141 "-x[directory] strip off text before #!ruby line and perhaps cd to directory",
142 "--copyright print the copyright",
143 "--version print the version",
144 NULL
146 const char *const *p = usage_msg;
148 printf("Usage: %s [switches] [--] [programfile] [arguments]\n", name);
149 while (*p)
150 printf(" %s\n", *p++);
153 VALUE rb_get_load_path(void);
155 #ifndef CharNext /* defined as CharNext[AW] on Windows. */
156 #define CharNext(p) ((p) + mblen(p, RUBY_MBCHAR_MAXSIZE))
157 #endif
159 #if defined DOSISH || defined __CYGWIN__
160 static inline void
161 translate_char(char *p, int from, int to)
163 while (*p) {
164 if ((unsigned char)*p == from)
165 *p = to;
166 p = CharNext(p);
169 #endif
171 #if defined _WIN32 || defined __CYGWIN__ || defined __DJGPP__
172 static VALUE
173 rubylib_mangled_path(const char *s, unsigned int l)
175 static char *newp, *oldp;
176 static int newl, oldl, notfound;
177 char *ptr;
178 VALUE ret;
180 if (!newp && !notfound) {
181 newp = getenv("RUBYLIB_PREFIX");
182 if (newp) {
183 oldp = newp = strdup(newp);
184 while (*newp && !ISSPACE(*newp) && *newp != ';') {
185 newp = CharNext(newp); /* Skip digits. */
187 oldl = newp - oldp;
188 while (*newp && (ISSPACE(*newp) || *newp == ';')) {
189 newp = CharNext(newp); /* Skip whitespace. */
191 newl = strlen(newp);
192 if (newl == 0 || oldl == 0) {
193 rb_fatal("malformed RUBYLIB_PREFIX");
195 translate_char(newp, '\\', '/');
197 else {
198 notfound = 1;
201 if (!newp || l < oldl || STRNCASECMP(oldp, s, oldl) != 0) {
202 return rb_str_new(s, l);
204 ret = rb_str_new(0, l + newl - oldl);
205 ptr = RSTRING_PTR(ret);
206 memcpy(ptr, newp, newl);
207 memcpy(ptr + newl, s + oldl, l - oldl);
208 ptr[l + newl - oldl] = 0;
209 return ret;
212 static VALUE
213 rubylib_mangled_path2(const char *s)
215 return rubylib_mangled_path(s, strlen(s));
217 #else
218 #define rubylib_mangled_path rb_str_new
219 #define rubylib_mangled_path2 rb_str_new2
220 #endif
222 static void
223 push_include(const char *path, VALUE (*filter)(VALUE))
225 const char sep = PATH_SEP_CHAR;
226 const char *p, *s;
227 VALUE load_path = GET_VM()->load_path;
229 p = path;
230 while (*p) {
231 while (*p == sep)
232 p++;
233 if (!*p) break;
234 for (s = p; *s && *s != sep; s = CharNext(s));
235 rb_ary_push(load_path, (*filter)(rubylib_mangled_path(p, s - p)));
236 p = s;
240 #ifdef __CYGWIN__
241 static void
242 push_include_cygwin(const char *path, VALUE (*filter)(VALUE))
244 const char *p, *s;
245 char rubylib[FILENAME_MAX];
246 VALUE buf = 0;
248 p = path;
249 while (*p) {
250 unsigned int len;
251 while (*p == ';')
252 p++;
253 if (!*p) break;
254 for (s = p; *s && *s != ';'; s = CharNext(s));
255 len = s - p;
256 if (*s) {
257 if (!buf) {
258 buf = rb_str_new(p, len);
259 p = RSTRING_PTR(buf);
261 else {
262 rb_str_resize(buf, len);
263 p = strncpy(RSTRING_PTR(buf), p, len);
266 if (cygwin_conv_to_posix_path(p, rubylib) == 0)
267 p = rubylib;
268 push_include(p, filter);
269 if (!*s) break;
270 p = s + 1;
274 #define push_include push_include_cygwin
275 #endif
277 void
278 ruby_push_include(const char *path, VALUE (*filter)(VALUE))
280 if (path == 0)
281 return;
282 push_include(path, filter);
285 static VALUE
286 identical_path(VALUE path)
288 return path;
291 void
292 ruby_incpush(const char *path)
294 ruby_push_include(path, identical_path);
297 static VALUE
298 expand_include_path(VALUE path)
300 char *p = RSTRING_PTR(path);
301 if (!p)
302 return path;
303 if (*p == '.' && p[1] == '/')
304 return path;
305 return rb_file_expand_path(path, Qnil);
308 void
309 ruby_incpush_expand(const char *path)
311 ruby_push_include(path, expand_include_path);
314 #if defined DOSISH || defined __CYGWIN__
315 #define LOAD_RELATIVE 1
316 #endif
318 #if defined _WIN32 || defined __CYGWIN__
319 static HMODULE libruby;
321 BOOL WINAPI
322 DllMain(HINSTANCE dll, DWORD reason, LPVOID reserved)
324 if (reason == DLL_PROCESS_ATTACH)
325 libruby = dll;
326 return TRUE;
328 #endif
330 void
331 ruby_init_loadpath(void)
333 VALUE load_path;
334 #if defined LOAD_RELATIVE
335 char libpath[MAXPATHLEN + 1];
336 char *p;
337 int rest;
339 #if defined _WIN32 || defined __CYGWIN__
340 GetModuleFileName(libruby, libpath, sizeof libpath);
341 #elif defined(DJGPP)
342 extern char *__dos_argv0;
343 strncpy(libpath, __dos_argv0, sizeof(libpath) - 1);
344 #elif defined(__human68k__)
345 extern char **_argv;
346 strncpy(libpath, _argv[0], sizeof(libpath) - 1);
347 #elif defined(__EMX__)
348 _execname(libpath, sizeof(libpath) - 1);
349 #endif
351 libpath[sizeof(libpath) - 1] = '\0';
352 #if defined DOSISH
353 translate_char(libpath, '\\', '/');
354 #elif defined __CYGWIN__
356 char rubylib[FILENAME_MAX];
357 cygwin_conv_to_posix_path(libpath, rubylib);
358 strncpy(libpath, rubylib, sizeof(libpath));
360 #endif
361 p = strrchr(libpath, '/');
362 if (p) {
363 *p = 0;
364 if (p - libpath > 3 && !STRCASECMP(p - 4, "/bin")) {
365 p -= 4;
366 *p = 0;
369 else {
370 strcpy(libpath, ".");
371 p = libpath + 1;
374 rest = sizeof(libpath) - 1 - (p - libpath);
376 #define RUBY_RELATIVE(path) (strncpy(p, (path), rest), libpath)
377 #else
378 #define RUBY_RELATIVE(path) (path)
379 #endif
380 #define incpush(path) rb_ary_push(load_path, rubylib_mangled_path2(path))
381 load_path = GET_VM()->load_path;
383 if (rb_safe_level() == 0) {
384 ruby_incpush(getenv("RUBYLIB"));
387 #ifdef RUBY_SEARCH_PATH
388 incpush(RUBY_RELATIVE(RUBY_SEARCH_PATH));
389 #endif
391 incpush(RUBY_RELATIVE(RUBY_SITE_LIB2));
392 #ifdef RUBY_SITE_THIN_ARCHLIB
393 incpush(RUBY_RELATIVE(RUBY_SITE_THIN_ARCHLIB));
394 #endif
395 incpush(RUBY_RELATIVE(RUBY_SITE_ARCHLIB));
396 incpush(RUBY_RELATIVE(RUBY_SITE_LIB));
398 incpush(RUBY_RELATIVE(RUBY_VENDOR_LIB2));
399 #ifdef RUBY_VENDOR_THIN_ARCHLIB
400 incpush(RUBY_RELATIVE(RUBY_VENDOR_THIN_ARCHLIB));
401 #endif
402 incpush(RUBY_RELATIVE(RUBY_VENDOR_ARCHLIB));
403 incpush(RUBY_RELATIVE(RUBY_VENDOR_LIB));
405 incpush(RUBY_RELATIVE(RUBY_LIB));
406 #ifdef RUBY_THIN_ARCHLIB
407 incpush(RUBY_RELATIVE(RUBY_THIN_ARCHLIB));
408 #endif
409 incpush(RUBY_RELATIVE(RUBY_ARCHLIB));
411 if (rb_safe_level() == 0) {
412 incpush(".");
416 struct req_list {
417 char *name;
418 struct req_list *next;
420 static struct {
421 struct req_list *last, head;
422 } req_list = {&req_list.head,};
424 static void
425 add_modules(const char *mod)
427 struct req_list *list;
429 list = ALLOC(struct req_list);
430 list->name = ALLOC_N(char, strlen(mod) + 1);
431 strcpy(list->name, mod);
432 list->next = 0;
433 req_list.last->next = list;
434 req_list.last = list;
437 extern void Init_ext(void);
438 extern VALUE rb_vm_top_self(void);
440 static void
441 require_libraries(void)
443 struct req_list *list = req_list.head.next;
444 struct req_list *tmp;
445 ID require = rb_intern("require");
447 Init_ext(); /* should be called here for some reason :-( */
448 req_list.last = 0;
449 while (list) {
450 VALUE feature = rb_str_new2(list->name);
451 tmp = list->next;
452 free(list->name);
453 free(list);
454 list = tmp;
455 rb_funcall2(rb_vm_top_self(), require, 1, &feature);
457 req_list.head.next = 0;
460 static void
461 process_sflag(struct cmdline_options *opt)
463 if (opt->sflag) {
464 long n;
465 VALUE *args;
466 VALUE argv = rb_argv;
468 n = RARRAY_LEN(argv);
469 args = RARRAY_PTR(argv);
470 while (n > 0) {
471 VALUE v = *args++;
472 char *s = StringValuePtr(v);
473 char *p;
474 int hyphen = Qfalse;
476 if (s[0] != '-')
477 break;
478 n--;
479 if (s[1] == '-' && s[2] == '\0')
480 break;
482 v = Qtrue;
483 /* check if valid name before replacing - with _ */
484 for (p = s + 1; *p; p++) {
485 if (*p == '=') {
486 *p++ = '\0';
487 v = rb_str_new2(p);
488 break;
490 if (*p == '-') {
491 hyphen = Qtrue;
493 else if (*p != '_' && !ISALNUM(*p)) {
494 VALUE name_error[2];
495 name_error[0] =
496 rb_str_new2("invalid name for global variable - ");
497 if (!(p = strchr(p, '='))) {
498 rb_str_cat2(name_error[0], s);
500 else {
501 rb_str_cat(name_error[0], s, p - s);
503 name_error[1] = args[-1];
504 rb_exc_raise(rb_class_new_instance(2, name_error, rb_eNameError));
507 s[0] = '$';
508 if (hyphen) {
509 for (p = s + 1; *p; ++p) {
510 if (*p == '-')
511 *p = '_';
514 rb_gv_set(s, v);
516 n = RARRAY_LEN(argv) - n;
517 while (n--) {
518 rb_ary_shift(argv);
521 opt->sflag = 0;
524 NODE *rb_parser_append_print(VALUE, NODE *);
525 NODE *rb_parser_while_loop(VALUE, NODE *, int, int);
526 static int proc_options(int argc, char **argv, struct cmdline_options *opt);
528 static char *
529 moreswitches(const char *s, struct cmdline_options *opt)
531 int argc;
532 char *argv[3];
533 const char *p = s;
535 argc = 2;
536 argv[0] = argv[2] = 0;
537 while (*s && !ISSPACE(*s))
538 s++;
539 argv[1] = ALLOCA_N(char, s - p + 2);
540 argv[1][0] = '-';
541 strncpy(argv[1] + 1, p, s - p);
542 argv[1][s - p + 1] = '\0';
543 proc_options(argc, argv, opt);
544 while (*s && ISSPACE(*s))
545 s++;
546 return (char *)s;
549 #define NAME_MATCH_P(name, str, len) \
550 ((len) < sizeof(name) && strncmp((str), name, (len)) == 0)
552 #define UNSET_WHEN(name, bit, str, len) \
553 if (NAME_MATCH_P(name, str, len)) { \
554 *(unsigned int *)arg &= ~(bit); \
555 return; \
558 #define SET_WHEN(name, bit, str, len) \
559 if (NAME_MATCH_P(name, str, len)) { \
560 *(unsigned int *)arg |= (bit); \
561 return; \
564 static void
565 enable_option(const char *str, int len, void *arg)
567 #define UNSET_WHEN_DISABLE(bit) UNSET_WHEN(#bit, DISABLE_BIT(bit), str, len)
568 UNSET_WHEN_DISABLE(gems);
569 UNSET_WHEN_DISABLE(rubyopt);
570 if (NAME_MATCH_P("all", str, len)) {
571 *(unsigned int *)arg = 0U;
572 return;
574 rb_warn("unknown argument for --enable: `%.*s'", len, str);
577 static void
578 disable_option(const char *str, int len, void *arg)
580 #define SET_WHEN_DISABLE(bit) SET_WHEN(#bit, DISABLE_BIT(bit), str, len)
581 SET_WHEN_DISABLE(gems);
582 SET_WHEN_DISABLE(rubyopt);
583 if (NAME_MATCH_P("all", str, len)) {
584 *(unsigned int *)arg = ~0U;
585 return;
587 rb_warn("unknown argument for --disable: `%.*s'", len, str);
590 static int
591 proc_options(int argc, char **argv, struct cmdline_options *opt)
593 int n, argc0 = argc;
594 const char *s;
596 if (argc == 0)
597 return 0;
599 for (argc--, argv++; argc > 0; argc--, argv++) {
600 if (argv[0][0] != '-' || !argv[0][1])
601 break;
603 s = argv[0] + 1;
604 reswitch:
605 switch (*s) {
606 case 'a':
607 opt->do_split = Qtrue;
608 s++;
609 goto reswitch;
611 case 'p':
612 opt->do_print = Qtrue;
613 /* through */
614 case 'n':
615 opt->do_loop = Qtrue;
616 s++;
617 goto reswitch;
619 case 'd':
620 ruby_debug = Qtrue;
621 ruby_verbose = Qtrue;
622 s++;
623 goto reswitch;
625 case 'y':
626 opt->yydebug = 1;
627 s++;
628 goto reswitch;
630 case 'v':
631 if (opt->verbose) {
632 s++;
633 goto reswitch;
635 ruby_show_version();
636 opt->verbose = 1;
637 case 'w':
638 ruby_verbose = Qtrue;
639 s++;
640 goto reswitch;
642 case 'W':
644 int numlen;
645 int v = 2; /* -W as -W2 */
647 if (*++s) {
648 v = scan_oct(s, 1, &numlen);
649 if (numlen == 0)
650 v = 1;
651 s += numlen;
653 switch (v) {
654 case 0:
655 ruby_verbose = Qnil;
656 break;
657 case 1:
658 ruby_verbose = Qfalse;
659 break;
660 default:
661 ruby_verbose = Qtrue;
662 break;
665 goto reswitch;
667 case 'c':
668 opt->do_check = Qtrue;
669 s++;
670 goto reswitch;
672 case 's':
673 forbid_setid("-s");
674 opt->sflag = 1;
675 s++;
676 goto reswitch;
678 case 'h':
679 usage(origarg.argv[0]);
680 rb_exit(EXIT_SUCCESS);
681 break;
683 case 'l':
684 opt->do_line = Qtrue;
685 rb_output_rs = rb_rs;
686 s++;
687 goto reswitch;
689 case 'S':
690 forbid_setid("-S");
691 opt->do_search = Qtrue;
692 s++;
693 goto reswitch;
695 case 'e':
696 forbid_setid("-e");
697 if (!*++s) {
698 s = argv[1];
699 argc--, argv++;
701 if (!s) {
702 rb_raise(rb_eRuntimeError, "no code specified for -e");
704 if (!opt->e_script) {
705 opt->e_script = rb_str_new(0, 0);
706 if (opt->script == 0)
707 opt->script = "-e";
709 rb_str_cat2(opt->e_script, s);
710 rb_str_cat2(opt->e_script, "\n");
711 break;
713 case 'r':
714 forbid_setid("-r");
715 if (*++s) {
716 add_modules(s);
718 else if (argv[1]) {
719 add_modules(argv[1]);
720 argc--, argv++;
722 break;
724 case 'i':
725 forbid_setid("-i");
726 ruby_set_inplace_mode(s + 1);
727 break;
729 case 'x':
730 opt->xflag = Qtrue;
731 s++;
732 if (*s && chdir(s) < 0) {
733 rb_fatal("Can't chdir to %s", s);
735 break;
737 case 'C':
738 case 'X':
739 s++;
740 if (!*s) {
741 s = argv[1];
742 argc--, argv++;
744 if (!s || !*s) {
745 rb_fatal("Can't chdir");
747 if (chdir(s) < 0) {
748 rb_fatal("Can't chdir to %s", s);
750 break;
752 case 'F':
753 if (*++s) {
754 rb_fs = rb_reg_new(s, strlen(s), 0);
756 break;
758 case 'E':
759 if (!*++s) goto next_encoding;
760 goto encoding;
762 case 'K':
763 if (*++s) {
764 const char *enc_name = 0;
765 switch (*s) {
766 case 'E': case 'e':
767 enc_name = "EUC-JP";
768 break;
769 case 'S': case 's':
770 enc_name = "Windows-31J";
771 break;
772 case 'U': case 'u':
773 enc_name = "UTF-8";
774 break;
775 case 'N': case 'n': case 'A': case 'a':
776 enc_name = "ASCII-8BIT";
777 break;
779 if (enc_name) {
780 opt->src.enc.name = rb_str_new2(enc_name);
781 opt->ext.enc.name = opt->src.enc.name;
783 s++;
785 goto reswitch;
787 case 'T':
789 int numlen;
790 int v = 1;
792 if (*++s) {
793 v = scan_oct(s, 2, &numlen);
794 if (numlen == 0)
795 v = 1;
796 s += numlen;
798 rb_set_safe_level(v);
800 goto reswitch;
802 case 'I':
803 forbid_setid("-I");
804 if (*++s)
805 ruby_incpush_expand(s);
806 else if (argv[1]) {
807 ruby_incpush_expand(argv[1]);
808 argc--, argv++;
810 break;
812 case '0':
814 int numlen;
815 int v;
816 char c;
818 v = scan_oct(s, 4, &numlen);
819 s += numlen;
820 if (v > 0377)
821 rb_rs = Qnil;
822 else if (v == 0 && numlen >= 2) {
823 rb_rs = rb_str_new2("\n\n");
825 else {
826 c = v & 0xff;
827 rb_rs = rb_str_new(&c, 1);
830 goto reswitch;
832 case '-':
833 if (!s[1] || (s[1] == '\r' && !s[2])) {
834 argc--, argv++;
835 goto switch_end;
837 s++;
838 if (strcmp("copyright", s) == 0)
839 opt->copyright = 1;
840 else if (strcmp("debug", s) == 0) {
841 ruby_debug = Qtrue;
842 ruby_verbose = Qtrue;
844 else if (strncmp("enable", s, n = 6) == 0 &&
845 (!s[n] || s[n] == '-' || s[n] == '=')) {
846 if ((s += n + 1)[-1] ? !*s : (!--argc || !(s = *++argv))) {
847 rb_raise(rb_eRuntimeError, "missing argument for --enable");
849 ruby_each_words(s, enable_option, &opt->disable);
851 else if (strncmp("disable", s, n = 7) == 0 &&
852 (!s[n] || s[n] == '-' || s[n] == '=')) {
853 if ((s += n + 1)[-1] ? !*s : (!--argc || !(s = *++argv))) {
854 rb_raise(rb_eRuntimeError, "missing argument for --disable");
856 ruby_each_words(s, disable_option, &opt->disable);
858 else if (strncmp("encoding", s, n = 8) == 0 && (!s[n] || s[n] == '=')) {
859 s += n;
860 if (!*s++) {
861 next_encoding:
862 if (!--argc || !(s = *++argv)) {
863 rb_raise(rb_eRuntimeError, "missing argument for --encoding");
866 encoding:
867 opt->ext.enc.name = rb_str_new2(s);
869 else if (strcmp("version", s) == 0)
870 opt->version = 1;
871 else if (strcmp("verbose", s) == 0) {
872 opt->verbose = 1;
873 ruby_verbose = Qtrue;
875 else if (strcmp("yydebug", s) == 0)
876 opt->yydebug = 1;
877 else if (strcmp("help", s) == 0) {
878 usage(origarg.argv[0]);
879 rb_exit(EXIT_SUCCESS);
881 else {
882 rb_raise(rb_eRuntimeError,
883 "invalid option --%s (-h will show valid options)", s);
885 break;
887 case '\r':
888 if (!s[1])
889 break;
891 default:
893 if (ISPRINT(*s)) {
894 rb_raise(rb_eRuntimeError,
895 "invalid option -%c (-h will show valid options)",
896 (int)(unsigned char)*s);
898 else {
899 rb_raise(rb_eRuntimeError,
900 "invalid option -\\x%02X (-h will show valid options)",
901 (int)(unsigned char)*s);
904 goto switch_end;
906 case 0:
907 break;
911 switch_end:
912 return argc0 - argc;
915 void Init_prelude(void);
917 static void
918 ruby_init_gems(int enable)
920 VALUE gem;
921 gem = rb_define_module("Gem");
922 rb_const_set(gem, rb_intern("Enable"), enable ? Qtrue : Qfalse);
923 Init_prelude();
926 static int
927 opt_enc_index(VALUE enc_name)
929 const char *s = RSTRING_PTR(enc_name);
930 int i = rb_enc_find_index(s);
932 if (i < 0) {
933 rb_raise(rb_eRuntimeError, "unknown encoding name - %s", s);
935 else if (rb_enc_dummy_p(rb_enc_from_index(i))) {
936 rb_raise(rb_eRuntimeError, "dummy encoding is not acceptable - %s ", s);
938 return i;
941 VALUE rb_progname;
942 VALUE rb_argv0;
943 static int src_encoding_index = -1; /* TODO: VM private */
945 static VALUE
946 process_options(VALUE arg)
948 struct cmdline_arguments *argp = (struct cmdline_arguments *)arg;
949 struct cmdline_options *opt = argp->opt;
950 int argc = argp->argc;
951 char **argv = argp->argv;
952 NODE *tree = 0;
953 VALUE parser;
954 rb_encoding *enc;
955 const char *s;
956 int i = proc_options(argc, argv, opt);
957 int safe;
959 argc -= i;
960 argv += i;
962 if (!(opt->disable & DISABLE_BIT(rubyopt)) &&
963 rb_safe_level() == 0 && (s = getenv("RUBYOPT"))) {
964 VALUE src_enc_name = opt->src.enc.name;
965 VALUE ext_enc_name = opt->ext.enc.name;
967 while (ISSPACE(*s))
968 s++;
969 if (*s == 'T' || (*s == '-' && *(s + 1) == 'T')) {
970 int numlen;
971 int v = 1;
973 if (*s != 'T')
974 ++s;
975 if (*++s) {
976 v = scan_oct(s, 2, &numlen);
977 if (numlen == 0)
978 v = 1;
980 rb_set_safe_level(v);
982 else {
983 while (s && *s) {
984 if (*s == '-') {
985 s++;
986 if (ISSPACE(*s)) {
987 do {
988 s++;
989 } while (ISSPACE(*s));
990 continue;
993 if (!*s)
994 break;
995 if (!strchr("EIdvwWrK", *s))
996 rb_raise(rb_eRuntimeError,
997 "invalid switch in RUBYOPT: -%c", *s);
998 s = moreswitches(s, opt);
1001 if (src_enc_name)
1002 opt->src.enc.name = src_enc_name;
1003 if (ext_enc_name)
1004 opt->ext.enc.name = ext_enc_name;
1007 if (opt->version) {
1008 ruby_show_version();
1009 return Qtrue;
1011 if (opt->copyright) {
1012 ruby_show_copyright();
1015 if (rb_safe_level() >= 4) {
1016 OBJ_TAINT(rb_argv);
1017 OBJ_TAINT(GET_VM()->load_path);
1020 if (!opt->e_script) {
1021 if (argc == 0) { /* no more args */
1022 if (opt->verbose)
1023 return Qtrue;
1024 opt->script = "-";
1026 else {
1027 opt->script = argv[0];
1028 if (opt->script[0] == '\0') {
1029 opt->script = "-";
1031 else if (opt->do_search) {
1032 char *path = getenv("RUBYPATH");
1034 opt->script = 0;
1035 if (path) {
1036 opt->script = dln_find_file(argv[0], path);
1038 if (!opt->script) {
1039 opt->script = dln_find_file(argv[0], getenv(PATH_ENV));
1041 if (!opt->script)
1042 opt->script = argv[0];
1044 argc--;
1045 argv++;
1049 ruby_script(opt->script);
1050 #if defined DOSISH || defined __CYGWIN__
1051 translate_char(RSTRING_PTR(rb_progname), '\\', '/');
1052 #endif
1053 opt->script_name = rb_str_new4(rb_progname);
1054 opt->script = RSTRING_PTR(opt->script_name);
1055 ruby_set_argv(argc, argv);
1056 process_sflag(opt);
1058 ruby_init_loadpath();
1059 safe = rb_safe_level();
1060 rb_set_safe_level_force(0);
1061 ruby_init_gems(!(opt->disable & DISABLE_BIT(gems)));
1062 parser = rb_parser_new();
1063 if (opt->yydebug) rb_parser_set_yydebug(parser, Qtrue);
1064 if (opt->ext.enc.name != 0) {
1065 opt->ext.enc.index = opt_enc_index(opt->ext.enc.name);
1067 if (opt->src.enc.name != 0) {
1068 opt->src.enc.index = opt_enc_index(opt->src.enc.name);
1069 src_encoding_index = opt->src.enc.index;
1071 if (opt->ext.enc.index >= 0) {
1072 enc = rb_enc_from_index(opt->ext.enc.index);
1074 else {
1075 enc = rb_locale_encoding();
1077 rb_enc_set_default_external(rb_enc_from_encoding(enc));
1079 rb_set_safe_level_force(safe);
1080 if (opt->e_script) {
1081 rb_encoding *eenc;
1082 if (opt->src.enc.index >= 0) {
1083 eenc = rb_enc_from_index(opt->src.enc.index);
1085 else {
1086 eenc = rb_locale_encoding();
1088 rb_enc_associate(opt->e_script, eenc);
1089 require_libraries();
1090 tree = rb_parser_compile_string(parser, opt->script, opt->e_script, 1);
1092 else {
1093 if (opt->script[0] == '-' && !opt->script[1]) {
1094 forbid_setid("program input from stdin");
1096 tree = load_file(parser, opt->script, 1, opt);
1099 if (!tree) return Qfalse;
1101 process_sflag(opt);
1102 opt->xflag = 0;
1104 if (rb_safe_level() >= 4) {
1105 FL_UNSET(rb_argv, FL_TAINT);
1106 FL_UNSET(GET_VM()->load_path, FL_TAINT);
1109 if (opt->do_check) {
1110 printf("Syntax OK\n");
1111 return Qtrue;
1114 if (opt->do_print) {
1115 tree = rb_parser_append_print(parser, tree);
1117 if (opt->do_loop) {
1118 tree = rb_parser_while_loop(parser, tree, opt->do_line, opt->do_split);
1121 return rb_iseq_new(tree, rb_str_new2("<main>"),
1122 opt->script_name, Qfalse, ISEQ_TYPE_TOP);
1125 static NODE *
1126 load_file(VALUE parser, const char *fname, int script, struct cmdline_options *opt)
1128 extern VALUE rb_stdin;
1129 VALUE f;
1130 int line_start = 1;
1131 NODE *tree = 0;
1132 rb_encoding *enc;
1134 if (!fname)
1135 rb_load_fail(fname);
1136 if (strcmp(fname, "-") == 0) {
1137 f = rb_stdin;
1139 else {
1140 int fd, mode = O_RDONLY;
1141 #if defined DOSISH || defined __CYGWIN__
1143 const char *ext = strrchr(fname, '.');
1144 if (ext && STRCASECMP(ext, ".exe") == 0)
1145 mode |= O_BINARY;
1147 #endif
1148 if ((fd = open(fname, mode)) < 0) {
1149 rb_load_fail(fname);
1152 f = rb_io_fdopen(fd, mode, fname);
1155 if (script) {
1156 VALUE c = 1; /* something not nil */
1157 VALUE line;
1158 char *p;
1159 int no_src_enc = !opt->src.enc.name;
1160 int no_ext_enc = !opt->ext.enc.name;
1162 enc = rb_usascii_encoding();
1163 rb_funcall(f, rb_intern("set_encoding"), 1, rb_enc_from_encoding(enc));
1165 if (opt->xflag) {
1166 forbid_setid("-x");
1167 opt->xflag = Qfalse;
1168 while (!NIL_P(line = rb_io_gets(f))) {
1169 line_start++;
1170 if (RSTRING_LEN(line) > 2
1171 && RSTRING_PTR(line)[0] == '#'
1172 && RSTRING_PTR(line)[1] == '!') {
1173 if ((p = strstr(RSTRING_PTR(line), "ruby")) != 0) {
1174 goto start_read;
1178 rb_raise(rb_eLoadError, "no Ruby script found in input");
1181 c = rb_io_getbyte(f);
1182 if (c == INT2FIX('#')) {
1183 c = rb_io_getbyte(f);
1184 if (c == INT2FIX('!')) {
1185 line = rb_io_gets(f);
1186 if (NIL_P(line))
1187 return 0;
1189 if ((p = strstr(RSTRING_PTR(line), "ruby")) == 0) {
1190 /* not ruby script, kick the program */
1191 char **argv;
1192 char *path;
1193 char *pend = RSTRING_PTR(line) + RSTRING_LEN(line);
1195 p = RSTRING_PTR(line); /* skip `#!' */
1196 if (pend[-1] == '\n')
1197 pend--; /* chomp line */
1198 if (pend[-1] == '\r')
1199 pend--;
1200 *pend = '\0';
1201 while (p < pend && ISSPACE(*p))
1202 p++;
1203 path = p; /* interpreter path */
1204 while (p < pend && !ISSPACE(*p))
1205 p++;
1206 *p++ = '\0';
1207 if (p < pend) {
1208 argv = ALLOCA_N(char *, origarg.argc + 3);
1209 argv[1] = p;
1210 MEMCPY(argv + 2, origarg.argv + 1, char *, origarg.argc);
1212 else {
1213 argv = origarg.argv;
1215 argv[0] = path;
1216 execv(path, argv);
1218 rb_fatal("Can't exec %s", path);
1221 start_read:
1222 p += 4;
1223 RSTRING_PTR(line)[RSTRING_LEN(line) - 1] = '\0';
1224 if (RSTRING_PTR(line)[RSTRING_LEN(line) - 2] == '\r')
1225 RSTRING_PTR(line)[RSTRING_LEN(line) - 2] = '\0';
1226 if ((p = strstr(p, " -")) != 0) {
1227 p++; /* skip space before `-' */
1228 while (*p == '-') {
1229 p = moreswitches(p + 1, opt);
1233 /* push back shebang for pragma may exist in next line */
1234 rb_io_ungetc(f, rb_str_new2("!\n"));
1236 else if (!NIL_P(c)) {
1237 rb_io_ungetc(f, c);
1239 rb_io_ungetc(f, INT2FIX('#'));
1240 if (no_src_enc && opt->src.enc.name) {
1241 opt->src.enc.index = opt_enc_index(opt->src.enc.name);
1242 src_encoding_index = opt->src.enc.index;
1244 if (no_ext_enc && opt->ext.enc.name) {
1245 opt->ext.enc.index = opt_enc_index(opt->ext.enc.name);
1248 else if (!NIL_P(c)) {
1249 rb_io_ungetc(f, c);
1251 require_libraries(); /* Why here? unnatural */
1253 if (opt->src.enc.index >= 0) {
1254 enc = rb_enc_from_index(opt->src.enc.index);
1256 else if (f == rb_stdin) {
1257 enc = rb_locale_encoding();
1259 else {
1260 enc = rb_usascii_encoding();
1262 rb_funcall(f, rb_intern("set_encoding"), 1, rb_enc_from_encoding(enc));
1263 tree = (NODE *)rb_parser_compile_file(parser, fname, f, line_start);
1264 rb_funcall(f, rb_intern("set_encoding"), 1, rb_parser_encoding(parser));
1265 if (script && rb_parser_end_seen_p(parser)) {
1266 rb_define_global_const("DATA", f);
1268 else if (f != rb_stdin) {
1269 rb_io_close(f);
1271 return tree;
1274 void *
1275 rb_load_file(const char *fname)
1277 struct cmdline_options opt;
1279 MEMZERO(&opt, opt, 1);
1280 opt.src.enc.index = src_encoding_index;
1281 return load_file(rb_parser_new(), fname, 0, &opt);
1284 #if !defined(PSTAT_SETCMD) && !defined(HAVE_SETPROCTITLE)
1285 #if !defined(_WIN32) && !(defined(HAVE_SETENV) && defined(HAVE_UNSETENV))
1286 #define USE_ENVSPACE_FOR_ARG0
1287 #endif
1289 #ifdef USE_ENVSPACE_FOR_ARG0
1290 extern char **environ;
1291 #endif
1293 static int
1294 get_arglen(int argc, char **argv)
1296 char *s = argv[0];
1297 int i;
1299 if (!argc) return 0;
1300 s += strlen(s);
1301 /* See if all the arguments are contiguous in memory */
1302 for (i = 1; i < argc; i++) {
1303 if (argv[i] == s + 1) {
1304 s++;
1305 s += strlen(s); /* this one is ok too */
1307 else {
1308 break;
1311 #if defined(USE_ENVSPACE_FOR_ARG0)
1312 if (environ && (s == environ[0])) {
1313 s += strlen(s);
1314 for (i = 1; environ[i]; i++) {
1315 if (environ[i] == s + 1) {
1316 s++;
1317 s += strlen(s); /* this one is ok too */
1320 ruby_setenv("", NULL); /* duplicate environ vars */
1322 #endif
1323 return s - argv[0];
1325 #endif
1327 static void
1328 set_arg0(VALUE val, ID id)
1330 char *s, *t;
1331 long i;
1333 if (origarg.argv == 0)
1334 rb_raise(rb_eRuntimeError, "$0 not initialized");
1335 StringValue(val);
1336 s = RSTRING_PTR(val);
1337 i = RSTRING_LEN(val);
1338 #if defined(PSTAT_SETCMD)
1339 if (i > PST_CLEN) {
1340 union pstun un;
1341 char buf[PST_CLEN + 1]; /* PST_CLEN is 64 (HP-UX 11.23) */
1342 strncpy(buf, s, PST_CLEN);
1343 buf[PST_CLEN] = '\0';
1344 un.pst_command = buf;
1345 pstat(PSTAT_SETCMD, un, PST_CLEN, 0, 0);
1347 else {
1348 union pstun un;
1349 un.pst_command = s;
1350 pstat(PSTAT_SETCMD, un, i, 0, 0);
1352 #elif defined(HAVE_SETPROCTITLE)
1353 setproctitle("%.*s", (int)i, s);
1354 #else
1356 if (i >= origarg.len) {
1357 i = origarg.len;
1360 memcpy(origarg.argv[0], s, i);
1361 t = origarg.argv[0] + i;
1362 *t = '\0';
1364 if (i + 1 < origarg.len) memset(t + 1, ' ', origarg.len - i - 1);
1367 int j;
1368 for (j = 1; j < origarg.argc; j++) {
1369 origarg.argv[j] = t;
1372 #endif
1373 rb_progname = rb_tainted_str_new(s, i);
1376 void
1377 ruby_script(const char *name)
1379 if (name) {
1380 rb_progname = rb_tainted_str_new2(name);
1384 static int uid, euid, gid, egid;
1386 static void
1387 init_ids(void)
1389 uid = (int)getuid();
1390 euid = (int)geteuid();
1391 gid = (int)getgid();
1392 egid = (int)getegid();
1393 #ifdef VMS
1394 uid |= gid << 16;
1395 euid |= egid << 16;
1396 #endif
1397 if (uid && (euid != uid || egid != gid)) {
1398 rb_set_safe_level(1);
1402 static void
1403 forbid_setid(const char *s)
1405 if (euid != uid)
1406 rb_raise(rb_eSecurityError, "no %s allowed while running setuid", s);
1407 if (egid != gid)
1408 rb_raise(rb_eSecurityError, "no %s allowed while running setgid", s);
1409 if (rb_safe_level() > 0)
1410 rb_raise(rb_eSecurityError, "no %s allowed in tainted mode", s);
1413 static void
1414 verbose_setter(VALUE val, ID id, VALUE *variable)
1416 ruby_verbose = RTEST(val) ? Qtrue : val;
1419 static VALUE
1420 opt_W_getter(VALUE val, ID id)
1422 if (ruby_verbose == Qnil)
1423 return INT2FIX(0);
1424 if (ruby_verbose == Qfalse)
1425 return INT2FIX(1);
1426 if (ruby_verbose == Qtrue)
1427 return INT2FIX(2);
1428 return Qnil; /* not reached */
1431 void
1432 ruby_prog_init(void)
1434 init_ids();
1436 rb_define_hooked_variable("$VERBOSE", &ruby_verbose, 0, verbose_setter);
1437 rb_define_hooked_variable("$-v", &ruby_verbose, 0, verbose_setter);
1438 rb_define_hooked_variable("$-w", &ruby_verbose, 0, verbose_setter);
1439 rb_define_virtual_variable("$-W", opt_W_getter, 0);
1440 rb_define_variable("$DEBUG", &ruby_debug);
1441 rb_define_variable("$-d", &ruby_debug);
1443 rb_define_hooked_variable("$0", &rb_progname, 0, set_arg0);
1444 rb_define_hooked_variable("$PROGRAM_NAME", &rb_progname, 0, set_arg0);
1446 rb_define_global_const("ARGV", rb_argv);
1447 rb_global_variable(&rb_argv0);
1449 #ifdef MSDOS
1451 * There is no way we can refer to them from ruby, so close them to save
1452 * space.
1454 (void)fclose(stdaux);
1455 (void)fclose(stdprn);
1456 #endif
1459 void
1460 ruby_set_argv(int argc, char **argv)
1462 int i;
1463 rb_encoding *enc = rb_locale_encoding();
1464 VALUE av = rb_argv;
1466 #if defined(USE_DLN_A_OUT)
1467 if (origarg.argv)
1468 dln_argv0 = origarg.argv[0];
1469 else
1470 dln_argv0 = argv[0];
1471 #endif
1472 rb_ary_clear(av);
1473 for (i = 0; i < argc; i++) {
1474 VALUE arg = rb_tainted_str_new2(argv[i]);
1475 rb_enc_associate(arg, enc);
1477 OBJ_FREEZE(arg);
1478 rb_ary_push(av, arg);
1482 static VALUE
1483 false_value(void)
1485 return Qfalse;
1488 static VALUE
1489 true_value(void)
1491 return Qtrue;
1494 #define rb_define_readonly_boolean(name, val) \
1495 rb_define_virtual_variable((name), (val) ? true_value : false_value, 0)
1497 void *
1498 ruby_process_options(int argc, char **argv)
1500 struct cmdline_arguments args;
1501 struct cmdline_options opt;
1502 NODE *tree;
1504 MEMZERO(&opt, opt, 1);
1505 ruby_script(argv[0]); /* for the time being */
1506 rb_argv0 = rb_progname;
1507 args.argc = argc;
1508 args.argv = argv;
1509 args.opt = &opt;
1510 opt.src.enc.index = src_encoding_index;
1511 opt.ext.enc.index = -1;
1512 tree = (NODE *)rb_vm_call_cfunc(rb_vm_top_self(),
1513 process_options, (VALUE)&args,
1514 0, rb_progname);
1516 rb_define_readonly_boolean("$-p", opt.do_print);
1517 rb_define_readonly_boolean("$-l", opt.do_line);
1518 rb_define_readonly_boolean("$-a", opt.do_split);
1520 return tree;
1523 void
1524 ruby_sysinit(int *argc, char ***argv)
1526 #if defined(__APPLE__) && (defined(__MACH__) || defined(__DARWIN__))
1527 int i, n = *argc, len = 0;
1528 char **v1 = *argv, **v2, *p;
1530 for (i = 0; i < n; ++i) {
1531 len += strlen(v1[i]) + 1;
1533 v2 = malloc((n + 1)* sizeof(char*) + len);
1534 p = (char *)&v2[n + 1];
1535 for (i = 0; i < n; ++i) {
1536 int l = strlen(v1[i]);
1537 memcpy(p, v1[i], l + 1);
1538 v2[i] = p;
1539 p += l + 1;
1541 v2[n] = 0;
1542 *argv = v2;
1543 #elif defined(__MACOS__) && defined(__MWERKS__)
1544 *argc = ccommand(argv);
1545 #elif defined(_WIN32)
1546 void rb_w32_sysinit(int *argc, char ***argv);
1547 rb_w32_sysinit(argc, argv);
1548 #endif
1549 origarg.argc = *argc;
1550 origarg.argv = *argv;
1551 #if !defined(PSTAT_SETCMD) && !defined(HAVE_SETPROCTITLE)
1552 origarg.len = get_arglen(origarg.argc, origarg.argv);
1553 #endif
1554 #if defined(USE_DLN_A_OUT)
1555 dln_argv0 = origarg.argv[0];
1556 #endif