* io.c (rb_open_file): encoding in mode string was ignored if perm is
[ruby-svn.git] / ruby.c
blob25d95901e7361dc8749b3c22da358d649fd7f27a
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 VALUE rb_parser_get_yydebug(VALUE);
61 VALUE rb_parser_set_yydebug(VALUE, VALUE);
63 const char *ruby_get_inplace_mode(void);
64 void ruby_set_inplace_mode(const char *);
66 #define DISABLE_BIT(bit) (1U << disable_##bit)
67 enum disable_flag_bits {
68 disable_gems,
69 disable_rubyopt
72 #define DUMP_BIT(bit) (1U << dump_##bit)
73 enum dump_flag_bits {
74 dump_insns
77 struct cmdline_options {
78 int sflag, xflag;
79 int do_loop, do_print;
80 int do_check, do_line;
81 int do_split, do_search;
82 int usage;
83 int version;
84 int copyright;
85 unsigned int disable;
86 int verbose;
87 int yydebug;
88 unsigned int setids;
89 unsigned int dump;
90 const char *script;
91 VALUE script_name;
92 VALUE e_script;
93 struct {
94 struct {
95 VALUE name;
96 int index;
97 } enc;
98 } src, ext;
99 VALUE req_list;
102 static void init_ids(struct cmdline_options *);
104 #define src_encoding_index GET_VM()->src_encoding_index
106 static struct cmdline_options *
107 cmdline_options_init(struct cmdline_options *opt)
109 MEMZERO(opt, *opt, 1);
110 init_ids(opt);
111 opt->src.enc.index = src_encoding_index;
112 return opt;
115 struct cmdline_arguments {
116 int argc;
117 char **argv;
118 struct cmdline_options *opt;
121 static NODE *load_file(VALUE, const char *, int, struct cmdline_options *);
122 static void forbid_setid(const char *, struct cmdline_options *);
123 #define forbid_setid(s) forbid_setid(s, opt)
125 static struct {
126 int argc;
127 char **argv;
128 #if !defined(PSTAT_SETCMD) && !defined(HAVE_SETPROCTITLE)
129 int len;
130 #endif
131 } origarg;
133 static void
134 usage(const char *name)
136 /* This message really ought to be max 23 lines.
137 * Removed -h because the user already knows that option. Others? */
139 static const char *const usage_msg[] = {
140 "-0[octal] specify record separator (\\0, if no argument)",
141 "-a autosplit mode with -n or -p (splits $_ into $F)",
142 "-c check syntax only",
143 "-Cdirectory cd to directory, before executing your script",
144 "-d set debugging flags (set $DEBUG to true)",
145 "-e 'command' one line of script. Several -e's allowed. Omit [programfile]",
146 "-Eencoding specifies the character encoding for the program codes",
147 "-Fpattern split() pattern for autosplit (-a)",
148 "-i[extension] edit ARGV files in place (make backup if extension supplied)",
149 "-Idirectory specify $LOAD_PATH directory (may be used more than once)",
150 "-l enable line ending processing",
151 "-n assume 'while gets(); ... end' loop around your script",
152 "-p assume loop like -n but print line also like sed",
153 "-rlibrary require the library, before executing your script",
154 "-s enable some switch parsing for switches after script name",
155 "-S look for the script using PATH environment variable",
156 "-T[level] turn on tainting checks",
157 "-v print version number, then turn on verbose mode",
158 "-w turn warnings on for your script",
159 "-W[level] set warning level; 0=silence, 1=medium, 2=verbose (default)",
160 "-x[directory] strip off text before #!ruby line and perhaps cd to directory",
161 "--copyright print the copyright",
162 "--version print the version",
163 NULL
165 const char *const *p = usage_msg;
167 printf("Usage: %s [switches] [--] [programfile] [arguments]\n", name);
168 while (*p)
169 printf(" %s\n", *p++);
172 VALUE rb_get_load_path(void);
174 #ifndef CharNext /* defined as CharNext[AW] on Windows. */
175 #define CharNext(p) ((p) + mblen(p, RUBY_MBCHAR_MAXSIZE))
176 #endif
178 #if defined DOSISH || defined __CYGWIN__
179 static inline void
180 translate_char(char *p, int from, int to)
182 while (*p) {
183 if ((unsigned char)*p == from)
184 *p = to;
185 p = CharNext(p);
188 #endif
190 #if defined _WIN32 || defined __CYGWIN__ || defined __DJGPP__
191 static VALUE
192 rubylib_mangled_path(const char *s, unsigned int l)
194 static char *newp, *oldp;
195 static int newl, oldl, notfound;
196 char *ptr;
197 VALUE ret;
199 if (!newp && !notfound) {
200 newp = getenv("RUBYLIB_PREFIX");
201 if (newp) {
202 oldp = newp = strdup(newp);
203 while (*newp && !ISSPACE(*newp) && *newp != ';') {
204 newp = CharNext(newp); /* Skip digits. */
206 oldl = newp - oldp;
207 while (*newp && (ISSPACE(*newp) || *newp == ';')) {
208 newp = CharNext(newp); /* Skip whitespace. */
210 newl = strlen(newp);
211 if (newl == 0 || oldl == 0) {
212 rb_fatal("malformed RUBYLIB_PREFIX");
214 translate_char(newp, '\\', '/');
216 else {
217 notfound = 1;
220 if (!newp || l < oldl || STRNCASECMP(oldp, s, oldl) != 0) {
221 return rb_str_new(s, l);
223 ret = rb_str_new(0, l + newl - oldl);
224 ptr = RSTRING_PTR(ret);
225 memcpy(ptr, newp, newl);
226 memcpy(ptr + newl, s + oldl, l - oldl);
227 ptr[l + newl - oldl] = 0;
228 return ret;
231 static VALUE
232 rubylib_mangled_path2(const char *s)
234 return rubylib_mangled_path(s, strlen(s));
236 #else
237 #define rubylib_mangled_path rb_str_new
238 #define rubylib_mangled_path2 rb_str_new2
239 #endif
241 static void
242 push_include(const char *path, VALUE (*filter)(VALUE))
244 const char sep = PATH_SEP_CHAR;
245 const char *p, *s;
246 VALUE load_path = GET_VM()->load_path;
248 p = path;
249 while (*p) {
250 while (*p == sep)
251 p++;
252 if (!*p) break;
253 for (s = p; *s && *s != sep; s = CharNext(s));
254 rb_ary_push(load_path, (*filter)(rubylib_mangled_path(p, s - p)));
255 p = s;
259 #ifdef __CYGWIN__
260 static void
261 push_include_cygwin(const char *path, VALUE (*filter)(VALUE))
263 const char *p, *s;
264 char rubylib[FILENAME_MAX];
265 VALUE buf = 0;
267 p = path;
268 while (*p) {
269 unsigned int len;
270 while (*p == ';')
271 p++;
272 if (!*p) break;
273 for (s = p; *s && *s != ';'; s = CharNext(s));
274 len = s - p;
275 if (*s) {
276 if (!buf) {
277 buf = rb_str_new(p, len);
278 p = RSTRING_PTR(buf);
280 else {
281 rb_str_resize(buf, len);
282 p = strncpy(RSTRING_PTR(buf), p, len);
285 if (cygwin_conv_to_posix_path(p, rubylib) == 0)
286 p = rubylib;
287 push_include(p, filter);
288 if (!*s) break;
289 p = s + 1;
293 #define push_include push_include_cygwin
294 #endif
296 void
297 ruby_push_include(const char *path, VALUE (*filter)(VALUE))
299 if (path == 0)
300 return;
301 push_include(path, filter);
304 static VALUE
305 identical_path(VALUE path)
307 return path;
310 void
311 ruby_incpush(const char *path)
313 ruby_push_include(path, identical_path);
316 static VALUE
317 expand_include_path(VALUE path)
319 char *p = RSTRING_PTR(path);
320 if (!p)
321 return path;
322 if (*p == '.' && p[1] == '/')
323 return path;
324 return rb_file_expand_path(path, Qnil);
327 void
328 ruby_incpush_expand(const char *path)
330 ruby_push_include(path, expand_include_path);
333 #if defined DOSISH || defined __CYGWIN__
334 #define LOAD_RELATIVE 1
335 #endif
337 #if defined _WIN32 || defined __CYGWIN__
338 static HMODULE libruby;
340 BOOL WINAPI
341 DllMain(HINSTANCE dll, DWORD reason, LPVOID reserved)
343 if (reason == DLL_PROCESS_ATTACH)
344 libruby = dll;
345 return TRUE;
347 #endif
349 void
350 ruby_init_loadpath(void)
352 VALUE load_path;
353 #if defined LOAD_RELATIVE
354 char libpath[MAXPATHLEN + 1];
355 char *p;
356 int rest;
358 #if defined _WIN32 || defined __CYGWIN__
359 GetModuleFileName(libruby, libpath, sizeof libpath);
360 #elif defined(DJGPP)
361 extern char *__dos_argv0;
362 strncpy(libpath, __dos_argv0, sizeof(libpath) - 1);
363 #elif defined(__human68k__)
364 extern char **_argv;
365 strncpy(libpath, _argv[0], sizeof(libpath) - 1);
366 #elif defined(__EMX__)
367 _execname(libpath, sizeof(libpath) - 1);
368 #endif
370 libpath[sizeof(libpath) - 1] = '\0';
371 #if defined DOSISH
372 translate_char(libpath, '\\', '/');
373 #elif defined __CYGWIN__
375 char rubylib[FILENAME_MAX];
376 cygwin_conv_to_posix_path(libpath, rubylib);
377 strncpy(libpath, rubylib, sizeof(libpath));
379 #endif
380 p = strrchr(libpath, '/');
381 if (p) {
382 *p = 0;
383 if (p - libpath > 3 && !STRCASECMP(p - 4, "/bin")) {
384 p -= 4;
385 *p = 0;
388 else {
389 strcpy(libpath, ".");
390 p = libpath + 1;
393 rest = sizeof(libpath) - 1 - (p - libpath);
395 #define RUBY_RELATIVE(path) (strncpy(p, (path), rest), libpath)
396 #else
397 #define RUBY_RELATIVE(path) (path)
398 #endif
399 #define incpush(path) rb_ary_push(load_path, rubylib_mangled_path2(path))
400 load_path = GET_VM()->load_path;
402 if (rb_safe_level() == 0) {
403 ruby_incpush(getenv("RUBYLIB"));
406 #ifdef RUBY_SEARCH_PATH
407 incpush(RUBY_RELATIVE(RUBY_SEARCH_PATH));
408 #endif
410 incpush(RUBY_RELATIVE(RUBY_SITE_LIB2));
411 #ifdef RUBY_SITE_THIN_ARCHLIB
412 incpush(RUBY_RELATIVE(RUBY_SITE_THIN_ARCHLIB));
413 #endif
414 incpush(RUBY_RELATIVE(RUBY_SITE_ARCHLIB));
415 incpush(RUBY_RELATIVE(RUBY_SITE_LIB));
417 incpush(RUBY_RELATIVE(RUBY_VENDOR_LIB2));
418 #ifdef RUBY_VENDOR_THIN_ARCHLIB
419 incpush(RUBY_RELATIVE(RUBY_VENDOR_THIN_ARCHLIB));
420 #endif
421 incpush(RUBY_RELATIVE(RUBY_VENDOR_ARCHLIB));
422 incpush(RUBY_RELATIVE(RUBY_VENDOR_LIB));
424 incpush(RUBY_RELATIVE(RUBY_LIB));
425 #ifdef RUBY_THIN_ARCHLIB
426 incpush(RUBY_RELATIVE(RUBY_THIN_ARCHLIB));
427 #endif
428 incpush(RUBY_RELATIVE(RUBY_ARCHLIB));
430 if (rb_safe_level() == 0) {
431 incpush(".");
436 static void
437 add_modules(struct cmdline_options *opt, const char *mod)
439 VALUE list = opt->req_list;
441 if (!list) {
442 opt->req_list = list = rb_ary_new();
443 RBASIC(list)->klass = 0;
445 rb_ary_push(list, rb_obj_freeze(rb_str_new2(mod)));
448 extern void Init_ext(void);
449 extern VALUE rb_vm_top_self(void);
451 static void
452 require_libraries(struct cmdline_options *opt)
454 VALUE list = opt->req_list;
455 ID require;
457 Init_ext(); /* should be called here for some reason :-( */
458 CONST_ID(require, "require");
459 while (list && RARRAY_LEN(list) > 0) {
460 VALUE feature = rb_ary_shift(list);
461 rb_funcall2(rb_vm_top_self(), require, 1, &feature);
463 opt->req_list = 0;
466 static void
467 process_sflag(struct cmdline_options *opt)
469 if (opt->sflag) {
470 long n;
471 VALUE *args;
472 VALUE argv = rb_argv;
474 n = RARRAY_LEN(argv);
475 args = RARRAY_PTR(argv);
476 while (n > 0) {
477 VALUE v = *args++;
478 char *s = StringValuePtr(v);
479 char *p;
480 int hyphen = Qfalse;
482 if (s[0] != '-')
483 break;
484 n--;
485 if (s[1] == '-' && s[2] == '\0')
486 break;
488 v = Qtrue;
489 /* check if valid name before replacing - with _ */
490 for (p = s + 1; *p; p++) {
491 if (*p == '=') {
492 *p++ = '\0';
493 v = rb_str_new2(p);
494 break;
496 if (*p == '-') {
497 hyphen = Qtrue;
499 else if (*p != '_' && !ISALNUM(*p)) {
500 VALUE name_error[2];
501 name_error[0] =
502 rb_str_new2("invalid name for global variable - ");
503 if (!(p = strchr(p, '='))) {
504 rb_str_cat2(name_error[0], s);
506 else {
507 rb_str_cat(name_error[0], s, p - s);
509 name_error[1] = args[-1];
510 rb_exc_raise(rb_class_new_instance(2, name_error, rb_eNameError));
513 s[0] = '$';
514 if (hyphen) {
515 for (p = s + 1; *p; ++p) {
516 if (*p == '-')
517 *p = '_';
520 rb_gv_set(s, v);
522 n = RARRAY_LEN(argv) - n;
523 while (n--) {
524 rb_ary_shift(argv);
527 opt->sflag = 0;
530 NODE *rb_parser_append_print(VALUE, NODE *);
531 NODE *rb_parser_while_loop(VALUE, NODE *, int, int);
532 static int proc_options(int argc, char **argv, struct cmdline_options *opt);
534 static char *
535 moreswitches(const char *s, struct cmdline_options *opt)
537 int argc;
538 char *argv[3];
539 const char *p = s;
541 argc = 2;
542 argv[0] = argv[2] = 0;
543 while (*s && !ISSPACE(*s))
544 s++;
545 argv[1] = ALLOCA_N(char, s - p + 2);
546 argv[1][0] = '-';
547 strncpy(argv[1] + 1, p, s - p);
548 argv[1][s - p + 1] = '\0';
549 proc_options(argc, argv, opt);
550 while (*s && ISSPACE(*s))
551 s++;
552 return (char *)s;
555 #define NAME_MATCH_P(name, str, len) \
556 ((len) < sizeof(name) && strncmp((str), name, (len)) == 0)
558 #define UNSET_WHEN(name, bit, str, len) \
559 if (NAME_MATCH_P(name, str, len)) { \
560 *(unsigned int *)arg &= ~(bit); \
561 return; \
564 #define SET_WHEN(name, bit, str, len) \
565 if (NAME_MATCH_P(name, str, len)) { \
566 *(unsigned int *)arg |= (bit); \
567 return; \
570 static void
571 enable_option(const char *str, int len, void *arg)
573 #define UNSET_WHEN_DISABLE(bit) UNSET_WHEN(#bit, DISABLE_BIT(bit), str, len)
574 UNSET_WHEN_DISABLE(gems);
575 UNSET_WHEN_DISABLE(rubyopt);
576 if (NAME_MATCH_P("all", str, len)) {
577 *(unsigned int *)arg = 0U;
578 return;
580 rb_warn("unknown argument for --enable: `%.*s'", len, str);
583 static void
584 disable_option(const char *str, int len, void *arg)
586 #define SET_WHEN_DISABLE(bit) SET_WHEN(#bit, DISABLE_BIT(bit), str, len)
587 SET_WHEN_DISABLE(gems);
588 SET_WHEN_DISABLE(rubyopt);
589 if (NAME_MATCH_P("all", str, len)) {
590 *(unsigned int *)arg = ~0U;
591 return;
593 rb_warn("unknown argument for --disable: `%.*s'", len, str);
596 static void
597 dump_option(const char *str, int len, void *arg)
599 #define SET_WHEN_DUMP(bit) SET_WHEN(#bit, DUMP_BIT(bit), str, len)
600 SET_WHEN_DUMP(insns);
601 rb_warn("don't know how to dump `%.*s', (insns)", len, str);
604 static int
605 proc_options(int argc, char **argv, struct cmdline_options *opt)
607 int n, argc0 = argc;
608 const char *s;
610 if (argc == 0)
611 return 0;
613 for (argc--, argv++; argc > 0; argc--, argv++) {
614 if (argv[0][0] != '-' || !argv[0][1])
615 break;
617 s = argv[0] + 1;
618 reswitch:
619 switch (*s) {
620 case 'a':
621 opt->do_split = Qtrue;
622 s++;
623 goto reswitch;
625 case 'p':
626 opt->do_print = Qtrue;
627 /* through */
628 case 'n':
629 opt->do_loop = Qtrue;
630 s++;
631 goto reswitch;
633 case 'd':
634 ruby_debug = Qtrue;
635 ruby_verbose = Qtrue;
636 s++;
637 goto reswitch;
639 case 'y':
640 opt->yydebug = 1;
641 s++;
642 goto reswitch;
644 case 'v':
645 if (opt->verbose) {
646 s++;
647 goto reswitch;
649 ruby_show_version();
650 opt->verbose = 1;
651 case 'w':
652 ruby_verbose = Qtrue;
653 s++;
654 goto reswitch;
656 case 'W':
658 int numlen;
659 int v = 2; /* -W as -W2 */
661 if (*++s) {
662 v = scan_oct(s, 1, &numlen);
663 if (numlen == 0)
664 v = 1;
665 s += numlen;
667 switch (v) {
668 case 0:
669 ruby_verbose = Qnil;
670 break;
671 case 1:
672 ruby_verbose = Qfalse;
673 break;
674 default:
675 ruby_verbose = Qtrue;
676 break;
679 goto reswitch;
681 case 'c':
682 opt->do_check = Qtrue;
683 s++;
684 goto reswitch;
686 case 's':
687 forbid_setid("-s");
688 opt->sflag = 1;
689 s++;
690 goto reswitch;
692 case 'h':
693 usage(origarg.argv[0]);
694 rb_exit(EXIT_SUCCESS);
695 break;
697 case 'l':
698 opt->do_line = Qtrue;
699 rb_output_rs = rb_rs;
700 s++;
701 goto reswitch;
703 case 'S':
704 forbid_setid("-S");
705 opt->do_search = Qtrue;
706 s++;
707 goto reswitch;
709 case 'e':
710 forbid_setid("-e");
711 if (!*++s) {
712 s = argv[1];
713 argc--, argv++;
715 if (!s) {
716 rb_raise(rb_eRuntimeError, "no code specified for -e");
718 if (!opt->e_script) {
719 opt->e_script = rb_str_new(0, 0);
720 if (opt->script == 0)
721 opt->script = "-e";
723 rb_str_cat2(opt->e_script, s);
724 rb_str_cat2(opt->e_script, "\n");
725 break;
727 case 'r':
728 forbid_setid("-r");
729 if (*++s) {
730 add_modules(opt, s);
732 else if (argv[1]) {
733 add_modules(opt, argv[1]);
734 argc--, argv++;
736 break;
738 case 'i':
739 forbid_setid("-i");
740 ruby_set_inplace_mode(s + 1);
741 break;
743 case 'x':
744 opt->xflag = Qtrue;
745 s++;
746 if (*s && chdir(s) < 0) {
747 rb_fatal("Can't chdir to %s", s);
749 break;
751 case 'C':
752 case 'X':
753 s++;
754 if (!*s) {
755 s = argv[1];
756 argc--, argv++;
758 if (!s || !*s) {
759 rb_fatal("Can't chdir");
761 if (chdir(s) < 0) {
762 rb_fatal("Can't chdir to %s", s);
764 break;
766 case 'F':
767 if (*++s) {
768 rb_fs = rb_reg_new(s, strlen(s), 0);
770 break;
772 case 'E':
773 if (!*++s) goto next_encoding;
774 goto encoding;
776 case 'K':
777 if (*++s) {
778 const char *enc_name = 0;
779 switch (*s) {
780 case 'E': case 'e':
781 enc_name = "EUC-JP";
782 break;
783 case 'S': case 's':
784 enc_name = "Windows-31J";
785 break;
786 case 'U': case 'u':
787 enc_name = "UTF-8";
788 break;
789 case 'N': case 'n': case 'A': case 'a':
790 enc_name = "ASCII-8BIT";
791 break;
793 if (enc_name) {
794 opt->src.enc.name = rb_str_new2(enc_name);
795 opt->ext.enc.name = opt->src.enc.name;
797 s++;
799 goto reswitch;
801 case 'T':
803 int numlen;
804 int v = 1;
806 if (*++s) {
807 v = scan_oct(s, 2, &numlen);
808 if (numlen == 0)
809 v = 1;
810 s += numlen;
812 rb_set_safe_level(v);
814 goto reswitch;
816 case 'I':
817 forbid_setid("-I");
818 if (*++s)
819 ruby_incpush_expand(s);
820 else if (argv[1]) {
821 ruby_incpush_expand(argv[1]);
822 argc--, argv++;
824 break;
826 case '0':
828 int numlen;
829 int v;
830 char c;
832 v = scan_oct(s, 4, &numlen);
833 s += numlen;
834 if (v > 0377)
835 rb_rs = Qnil;
836 else if (v == 0 && numlen >= 2) {
837 rb_rs = rb_str_new2("\n\n");
839 else {
840 c = v & 0xff;
841 rb_rs = rb_str_new(&c, 1);
844 goto reswitch;
846 case '-':
847 if (!s[1] || (s[1] == '\r' && !s[2])) {
848 argc--, argv++;
849 goto switch_end;
851 s++;
852 if (strcmp("copyright", s) == 0)
853 opt->copyright = 1;
854 else if (strcmp("debug", s) == 0) {
855 ruby_debug = Qtrue;
856 ruby_verbose = Qtrue;
858 else if (strncmp("enable", s, n = 6) == 0 &&
859 (!s[n] || s[n] == '-' || s[n] == '=')) {
860 if ((s += n + 1)[-1] ? !*s : (!--argc || !(s = *++argv))) {
861 rb_raise(rb_eRuntimeError, "missing argument for --enable");
863 ruby_each_words(s, enable_option, &opt->disable);
865 else if (strncmp("disable", s, n = 7) == 0 &&
866 (!s[n] || s[n] == '-' || s[n] == '=')) {
867 if ((s += n + 1)[-1] ? !*s : (!--argc || !(s = *++argv))) {
868 rb_raise(rb_eRuntimeError, "missing argument for --disable");
870 ruby_each_words(s, disable_option, &opt->disable);
872 else if (strncmp("encoding", s, n = 8) == 0 && (!s[n] || s[n] == '=')) {
873 s += n;
874 if (!*s++) {
875 next_encoding:
876 if (!--argc || !(s = *++argv)) {
877 rb_raise(rb_eRuntimeError, "missing argument for --encoding");
880 encoding:
881 opt->ext.enc.name = rb_str_new2(s);
883 else if (strcmp("version", s) == 0)
884 opt->version = 1;
885 else if (strcmp("verbose", s) == 0) {
886 opt->verbose = 1;
887 ruby_verbose = Qtrue;
889 else if (strcmp("yydebug", s) == 0)
890 opt->yydebug = 1;
891 else if (strncmp("dump", s, n = 4) == 0 && (!s[n] || s[n] == '=')) {
892 if (!(s += n + 1)[-1] && (!--argc || !(s = *++argv)) && *s != '-') break;
893 ruby_each_words(s, dump_option, &opt->dump);
895 else if (strcmp("help", s) == 0) {
896 usage(origarg.argv[0]);
897 rb_exit(EXIT_SUCCESS);
899 else {
900 rb_raise(rb_eRuntimeError,
901 "invalid option --%s (-h will show valid options)", s);
903 break;
905 case '\r':
906 if (!s[1])
907 break;
909 default:
911 if (ISPRINT(*s)) {
912 rb_raise(rb_eRuntimeError,
913 "invalid option -%c (-h will show valid options)",
914 (int)(unsigned char)*s);
916 else {
917 rb_raise(rb_eRuntimeError,
918 "invalid option -\\x%02X (-h will show valid options)",
919 (int)(unsigned char)*s);
922 goto switch_end;
924 case 0:
925 break;
929 switch_end:
930 return argc0 - argc;
933 void Init_prelude(void);
935 static void
936 ruby_init_gems(int enable)
938 if (enable) rb_define_module("Gem");
939 Init_prelude();
942 static int
943 opt_enc_index(VALUE enc_name)
945 const char *s = RSTRING_PTR(enc_name);
946 int i = rb_enc_find_index(s);
948 if (i < 0) {
949 rb_raise(rb_eRuntimeError, "unknown encoding name - %s", s);
951 else if (rb_enc_dummy_p(rb_enc_from_index(i))) {
952 rb_raise(rb_eRuntimeError, "dummy encoding is not acceptable - %s ", s);
954 return i;
957 #define rb_progname (GET_VM()->progname)
958 VALUE rb_argv0;
960 static VALUE
961 process_options(VALUE arg)
963 struct cmdline_arguments *argp = (struct cmdline_arguments *)arg;
964 struct cmdline_options *opt = argp->opt;
965 int argc = argp->argc;
966 char **argv = argp->argv;
967 NODE *tree = 0;
968 VALUE parser;
969 VALUE iseq;
970 rb_encoding *enc, *lenc;
971 const char *s;
972 char fbuf[MAXPATHLEN];
973 int i = proc_options(argc, argv, opt);
974 int safe;
976 argc -= i;
977 argv += i;
979 if (!(opt->disable & DISABLE_BIT(rubyopt)) &&
980 rb_safe_level() == 0 && (s = getenv("RUBYOPT"))) {
981 VALUE src_enc_name = opt->src.enc.name;
982 VALUE ext_enc_name = opt->ext.enc.name;
984 while (ISSPACE(*s))
985 s++;
986 if (*s == 'T' || (*s == '-' && *(s + 1) == 'T')) {
987 int numlen;
988 int v = 1;
990 if (*s != 'T')
991 ++s;
992 if (*++s) {
993 v = scan_oct(s, 2, &numlen);
994 if (numlen == 0)
995 v = 1;
997 rb_set_safe_level(v);
999 else {
1000 while (s && *s) {
1001 if (*s == '-') {
1002 s++;
1003 if (ISSPACE(*s)) {
1004 do {
1005 s++;
1006 } while (ISSPACE(*s));
1007 continue;
1010 if (!*s)
1011 break;
1012 if (!strchr("EIdvwWrK", *s))
1013 rb_raise(rb_eRuntimeError,
1014 "invalid switch in RUBYOPT: -%c", *s);
1015 s = moreswitches(s, opt);
1018 if (src_enc_name)
1019 opt->src.enc.name = src_enc_name;
1020 if (ext_enc_name)
1021 opt->ext.enc.name = ext_enc_name;
1024 if (opt->version) {
1025 ruby_show_version();
1026 return Qtrue;
1028 if (opt->copyright) {
1029 ruby_show_copyright();
1032 if (rb_safe_level() >= 4) {
1033 OBJ_TAINT(rb_argv);
1034 OBJ_TAINT(GET_VM()->load_path);
1037 if (!opt->e_script) {
1038 if (argc == 0) { /* no more args */
1039 if (opt->verbose)
1040 return Qtrue;
1041 opt->script = "-";
1043 else {
1044 opt->script = argv[0];
1045 if (opt->script[0] == '\0') {
1046 opt->script = "-";
1048 else if (opt->do_search) {
1049 char *path = getenv("RUBYPATH");
1051 opt->script = 0;
1052 if (path) {
1053 opt->script = dln_find_file_r(argv[0], path, fbuf, sizeof(fbuf));
1055 if (!opt->script) {
1056 opt->script = dln_find_file_r(argv[0], getenv(PATH_ENV), fbuf, sizeof(fbuf));
1058 if (!opt->script)
1059 opt->script = argv[0];
1061 argc--;
1062 argv++;
1066 ruby_script(opt->script);
1067 #if defined DOSISH || defined __CYGWIN__
1068 translate_char(RSTRING_PTR(rb_progname), '\\', '/');
1069 #endif
1070 opt->script_name = rb_str_new4(rb_progname);
1071 opt->script = RSTRING_PTR(opt->script_name);
1072 safe = rb_safe_level();
1073 rb_set_safe_level_force(0);
1074 ruby_set_argv(argc, argv);
1075 process_sflag(opt);
1077 ruby_init_loadpath();
1078 ruby_init_gems(!(opt->disable & DISABLE_BIT(gems)));
1079 lenc = rb_locale_encoding();
1080 for (i = 0; i < RARRAY_LEN(rb_argv); i++) {
1081 rb_enc_associate(RARRAY_PTR(rb_argv)[i], lenc);
1083 parser = rb_parser_new();
1084 if (opt->yydebug) rb_parser_set_yydebug(parser, Qtrue);
1085 if (opt->ext.enc.name != 0) {
1086 opt->ext.enc.index = opt_enc_index(opt->ext.enc.name);
1088 if (opt->src.enc.name != 0) {
1089 opt->src.enc.index = opt_enc_index(opt->src.enc.name);
1090 src_encoding_index = opt->src.enc.index;
1092 if (opt->ext.enc.index >= 0) {
1093 enc = rb_enc_from_index(opt->ext.enc.index);
1095 else {
1096 enc = lenc;
1098 rb_enc_set_default_external(rb_enc_from_encoding(enc));
1100 rb_set_safe_level_force(safe);
1101 if (opt->e_script) {
1102 rb_encoding *eenc;
1103 if (opt->src.enc.index >= 0) {
1104 eenc = rb_enc_from_index(opt->src.enc.index);
1106 else {
1107 eenc = lenc;
1109 rb_enc_associate(opt->e_script, eenc);
1110 require_libraries(opt);
1111 tree = rb_parser_compile_string(parser, opt->script, opt->e_script, 1);
1113 else {
1114 if (opt->script[0] == '-' && !opt->script[1]) {
1115 forbid_setid("program input from stdin");
1117 tree = load_file(parser, opt->script, 1, opt);
1120 if (!tree) return Qfalse;
1122 process_sflag(opt);
1123 opt->xflag = 0;
1125 if (rb_safe_level() >= 4) {
1126 FL_UNSET(rb_argv, FL_TAINT);
1127 FL_UNSET(GET_VM()->load_path, FL_TAINT);
1130 if (opt->do_check) {
1131 printf("Syntax OK\n");
1132 return Qtrue;
1135 if (opt->do_print) {
1136 tree = rb_parser_append_print(parser, tree);
1138 if (opt->do_loop) {
1139 tree = rb_parser_while_loop(parser, tree, opt->do_line, opt->do_split);
1142 iseq = rb_iseq_new(tree, rb_str_new2("<main>"),
1143 opt->script_name, Qfalse, ISEQ_TYPE_TOP);
1145 if (opt->dump & DUMP_BIT(insns)) {
1146 rb_io_write(rb_stdout, ruby_iseq_disasm(iseq));
1147 rb_io_flush(rb_stdout);
1148 return Qtrue;
1151 return iseq;
1154 static NODE *
1155 load_file(VALUE parser, const char *fname, int script, struct cmdline_options *opt)
1157 extern VALUE rb_stdin;
1158 VALUE f;
1159 int line_start = 1;
1160 NODE *tree = 0;
1161 rb_encoding *enc;
1163 if (!fname)
1164 rb_load_fail(fname);
1165 if (strcmp(fname, "-") == 0) {
1166 f = rb_stdin;
1168 else {
1169 int fd, mode = O_RDONLY;
1170 #if defined DOSISH || defined __CYGWIN__
1172 const char *ext = strrchr(fname, '.');
1173 if (ext && STRCASECMP(ext, ".exe") == 0)
1174 mode |= O_BINARY;
1176 #endif
1177 if ((fd = open(fname, mode)) < 0) {
1178 rb_load_fail(fname);
1181 f = rb_io_fdopen(fd, mode, fname);
1184 if (script) {
1185 VALUE c = 1; /* something not nil */
1186 VALUE line;
1187 char *p;
1188 int no_src_enc = !opt->src.enc.name;
1189 int no_ext_enc = !opt->ext.enc.name;
1191 enc = rb_usascii_encoding();
1192 rb_funcall(f, rb_intern("set_encoding"), 1, rb_enc_from_encoding(enc));
1194 if (opt->xflag) {
1195 forbid_setid("-x");
1196 opt->xflag = Qfalse;
1197 while (!NIL_P(line = rb_io_gets(f))) {
1198 line_start++;
1199 if (RSTRING_LEN(line) > 2
1200 && RSTRING_PTR(line)[0] == '#'
1201 && RSTRING_PTR(line)[1] == '!') {
1202 if ((p = strstr(RSTRING_PTR(line), "ruby")) != 0) {
1203 goto start_read;
1207 rb_raise(rb_eLoadError, "no Ruby script found in input");
1210 c = rb_io_getbyte(f);
1211 if (c == INT2FIX('#')) {
1212 c = rb_io_getbyte(f);
1213 if (c == INT2FIX('!')) {
1214 line = rb_io_gets(f);
1215 if (NIL_P(line))
1216 return 0;
1218 if ((p = strstr(RSTRING_PTR(line), "ruby")) == 0) {
1219 /* not ruby script, kick the program */
1220 char **argv;
1221 char *path;
1222 char *pend = RSTRING_PTR(line) + RSTRING_LEN(line);
1224 p = RSTRING_PTR(line); /* skip `#!' */
1225 if (pend[-1] == '\n')
1226 pend--; /* chomp line */
1227 if (pend[-1] == '\r')
1228 pend--;
1229 *pend = '\0';
1230 while (p < pend && ISSPACE(*p))
1231 p++;
1232 path = p; /* interpreter path */
1233 while (p < pend && !ISSPACE(*p))
1234 p++;
1235 *p++ = '\0';
1236 if (p < pend) {
1237 argv = ALLOCA_N(char *, origarg.argc + 3);
1238 argv[1] = p;
1239 MEMCPY(argv + 2, origarg.argv + 1, char *, origarg.argc);
1241 else {
1242 argv = origarg.argv;
1244 argv[0] = path;
1245 execv(path, argv);
1247 rb_fatal("Can't exec %s", path);
1250 start_read:
1251 p += 4;
1252 RSTRING_PTR(line)[RSTRING_LEN(line) - 1] = '\0';
1253 if (RSTRING_PTR(line)[RSTRING_LEN(line) - 2] == '\r')
1254 RSTRING_PTR(line)[RSTRING_LEN(line) - 2] = '\0';
1255 if ((p = strstr(p, " -")) != 0) {
1256 p++; /* skip space before `-' */
1257 while (*p == '-') {
1258 p = moreswitches(p + 1, opt);
1262 /* push back shebang for pragma may exist in next line */
1263 rb_io_ungetc(f, rb_str_new2("!\n"));
1265 else if (!NIL_P(c)) {
1266 rb_io_ungetc(f, c);
1268 rb_io_ungetc(f, INT2FIX('#'));
1269 if (no_src_enc && opt->src.enc.name) {
1270 opt->src.enc.index = opt_enc_index(opt->src.enc.name);
1271 src_encoding_index = opt->src.enc.index;
1273 if (no_ext_enc && opt->ext.enc.name) {
1274 opt->ext.enc.index = opt_enc_index(opt->ext.enc.name);
1277 else if (!NIL_P(c)) {
1278 rb_io_ungetc(f, c);
1280 require_libraries(opt); /* Why here? unnatural */
1282 if (opt->src.enc.index >= 0) {
1283 enc = rb_enc_from_index(opt->src.enc.index);
1285 else if (f == rb_stdin) {
1286 enc = rb_locale_encoding();
1288 else {
1289 enc = rb_usascii_encoding();
1291 rb_funcall(f, rb_intern("set_encoding"), 1, rb_enc_from_encoding(enc));
1292 tree = (NODE *)rb_parser_compile_file(parser, fname, f, line_start);
1293 rb_funcall(f, rb_intern("set_encoding"), 1, rb_parser_encoding(parser));
1294 if (script && rb_parser_end_seen_p(parser)) {
1295 rb_define_global_const("DATA", f);
1297 else if (f != rb_stdin) {
1298 rb_io_close(f);
1300 return tree;
1303 void *
1304 rb_load_file(const char *fname)
1306 struct cmdline_options opt;
1308 return load_file(rb_parser_new(), fname, 0, cmdline_options_init(&opt));
1311 #if !defined(PSTAT_SETCMD) && !defined(HAVE_SETPROCTITLE)
1312 #if !defined(_WIN32) && !(defined(HAVE_SETENV) && defined(HAVE_UNSETENV))
1313 #define USE_ENVSPACE_FOR_ARG0
1314 #endif
1316 #ifdef USE_ENVSPACE_FOR_ARG0
1317 extern char **environ;
1318 #endif
1320 static int
1321 get_arglen(int argc, char **argv)
1323 char *s = argv[0];
1324 int i;
1326 if (!argc) return 0;
1327 s += strlen(s);
1328 /* See if all the arguments are contiguous in memory */
1329 for (i = 1; i < argc; i++) {
1330 if (argv[i] == s + 1) {
1331 s++;
1332 s += strlen(s); /* this one is ok too */
1334 else {
1335 break;
1338 #if defined(USE_ENVSPACE_FOR_ARG0)
1339 if (environ && (s == environ[0])) {
1340 s += strlen(s);
1341 for (i = 1; environ[i]; i++) {
1342 if (environ[i] == s + 1) {
1343 s++;
1344 s += strlen(s); /* this one is ok too */
1347 ruby_setenv("", NULL); /* duplicate environ vars */
1349 #endif
1350 return s - argv[0];
1352 #endif
1354 static void
1355 set_arg0(VALUE val, ID id)
1357 char *s;
1358 long i;
1360 if (origarg.argv == 0)
1361 rb_raise(rb_eRuntimeError, "$0 not initialized");
1362 StringValue(val);
1363 s = RSTRING_PTR(val);
1364 i = RSTRING_LEN(val);
1365 #if defined(PSTAT_SETCMD)
1366 if (i > PST_CLEN) {
1367 union pstun un;
1368 char buf[PST_CLEN + 1]; /* PST_CLEN is 64 (HP-UX 11.23) */
1369 strncpy(buf, s, PST_CLEN);
1370 buf[PST_CLEN] = '\0';
1371 un.pst_command = buf;
1372 pstat(PSTAT_SETCMD, un, PST_CLEN, 0, 0);
1374 else {
1375 union pstun un;
1376 un.pst_command = s;
1377 pstat(PSTAT_SETCMD, un, i, 0, 0);
1379 #elif defined(HAVE_SETPROCTITLE)
1380 setproctitle("%.*s", (int)i, s);
1381 #else
1383 if (i >= origarg.len) {
1384 i = origarg.len;
1387 memcpy(origarg.argv[0], s, i);
1390 int j;
1391 char *t = origarg.argv[0] + i;
1392 *t = '\0';
1394 if (i + 1 < origarg.len) memset(t + 1, ' ', origarg.len - i - 1);
1395 for (j = 1; j < origarg.argc; j++) {
1396 origarg.argv[j] = t;
1399 #endif
1400 rb_progname = rb_obj_freeze(rb_tainted_str_new(s, i));
1403 void
1404 ruby_script(const char *name)
1406 if (name) {
1407 rb_progname = rb_obj_freeze(rb_tainted_str_new2(name));
1411 static void
1412 init_ids(struct cmdline_options *opt)
1414 rb_uid_t uid = getuid();
1415 rb_uid_t euid = geteuid();
1416 rb_gid_t gid = getgid();
1417 rb_gid_t egid = getegid();
1419 #ifdef VMS
1420 uid |= gid << 16;
1421 euid |= egid << 16;
1422 #endif
1423 if (uid != euid) opt->setids |= 1;
1424 if (egid != gid) opt->setids |= 2;
1425 if (uid && opt->setids) {
1426 rb_set_safe_level(1);
1430 #undef forbid_setid
1431 static void
1432 forbid_setid(const char *s, struct cmdline_options *opt)
1434 if (opt->setids & 1)
1435 rb_raise(rb_eSecurityError, "no %s allowed while running setuid", s);
1436 if (opt->setids & 2)
1437 rb_raise(rb_eSecurityError, "no %s allowed while running setgid", s);
1438 if (rb_safe_level() > 0)
1439 rb_raise(rb_eSecurityError, "no %s allowed in tainted mode", s);
1442 static void
1443 verbose_setter(VALUE val, ID id, void *data)
1445 VALUE *variable = data;
1446 *variable = RTEST(val) ? Qtrue : val;
1449 static VALUE
1450 opt_W_getter(ID id, void *data)
1452 VALUE *variable = data;
1453 switch (*variable) {
1454 case Qnil:
1455 return INT2FIX(0);
1456 case Qfalse:
1457 return INT2FIX(1);
1458 case Qtrue:
1459 return INT2FIX(2);
1461 return Qnil; /* not reached */
1464 void
1465 ruby_prog_init(void)
1467 rb_define_hooked_variable("$VERBOSE", &ruby_verbose, 0, verbose_setter);
1468 rb_define_hooked_variable("$-v", &ruby_verbose, 0, verbose_setter);
1469 rb_define_hooked_variable("$-w", &ruby_verbose, 0, verbose_setter);
1470 rb_define_hooked_variable("$-W", &ruby_verbose, opt_W_getter, 0);
1471 rb_define_variable("$DEBUG", &ruby_debug);
1472 rb_define_variable("$-d", &ruby_debug);
1474 rb_define_hooked_variable("$0", &rb_progname, 0, set_arg0);
1475 rb_define_hooked_variable("$PROGRAM_NAME", &rb_progname, 0, set_arg0);
1477 rb_define_global_const("ARGV", rb_argv);
1478 rb_global_variable(&rb_argv0);
1480 #ifdef MSDOS
1482 * There is no way we can refer to them from ruby, so close them to save
1483 * space.
1485 (void)fclose(stdaux);
1486 (void)fclose(stdprn);
1487 #endif
1490 void
1491 ruby_set_argv(int argc, char **argv)
1493 int i;
1494 VALUE av = rb_argv;
1496 #if defined(USE_DLN_A_OUT)
1497 if (origarg.argv)
1498 dln_argv0 = origarg.argv[0];
1499 else
1500 dln_argv0 = argv[0];
1501 #endif
1502 rb_ary_clear(av);
1503 for (i = 0; i < argc; i++) {
1504 VALUE arg = rb_tainted_str_new2(argv[i]);
1506 OBJ_FREEZE(arg);
1507 rb_ary_push(av, arg);
1511 static VALUE
1512 false_value(void)
1514 return Qfalse;
1517 static VALUE
1518 true_value(void)
1520 return Qtrue;
1523 #define rb_define_readonly_boolean(name, val) \
1524 rb_define_virtual_variable((name), (val) ? true_value : false_value, 0)
1526 void *
1527 ruby_process_options(int argc, char **argv)
1529 struct cmdline_arguments args;
1530 struct cmdline_options opt;
1531 NODE *tree;
1533 ruby_script(argv[0]); /* for the time being */
1534 rb_argv0 = rb_str_new4(rb_progname);
1535 args.argc = argc;
1536 args.argv = argv;
1537 args.opt = cmdline_options_init(&opt);
1538 opt.ext.enc.index = -1;
1539 tree = (NODE *)rb_vm_call_cfunc(rb_vm_top_self(),
1540 process_options, (VALUE)&args,
1541 0, rb_progname);
1543 rb_define_readonly_boolean("$-p", opt.do_print);
1544 rb_define_readonly_boolean("$-l", opt.do_line);
1545 rb_define_readonly_boolean("$-a", opt.do_split);
1547 return tree;
1550 void
1551 ruby_sysinit(int *argc, char ***argv)
1553 #if defined(__APPLE__) && (defined(__MACH__) || defined(__DARWIN__))
1554 int i, n = *argc, len = 0;
1555 char **v1 = *argv, **v2, *p;
1557 for (i = 0; i < n; ++i) {
1558 len += strlen(v1[i]) + 1;
1560 v2 = malloc((n + 1)* sizeof(char*) + len);
1561 p = (char *)&v2[n + 1];
1562 for (i = 0; i < n; ++i) {
1563 int l = strlen(v1[i]);
1564 memcpy(p, v1[i], l + 1);
1565 v2[i] = p;
1566 p += l + 1;
1568 v2[n] = 0;
1569 *argv = v2;
1570 #elif defined(__MACOS__) && defined(__MWERKS__)
1571 *argc = ccommand(argv);
1572 #elif defined(_WIN32)
1573 void rb_w32_sysinit(int *argc, char ***argv);
1574 rb_w32_sysinit(argc, argv);
1575 #endif
1576 origarg.argc = *argc;
1577 origarg.argv = *argv;
1578 #if !defined(PSTAT_SETCMD) && !defined(HAVE_SETPROCTITLE)
1579 origarg.len = get_arglen(origarg.argc, origarg.argv);
1580 #endif
1581 #if defined(USE_DLN_A_OUT)
1582 dln_argv0 = origarg.argv[0];
1583 #endif