summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog1193
-rw-r--r--MANIFEST35
-rw-r--r--Makefile.in134
-rw-r--r--README29
-rw-r--r--README.EXT341
-rw-r--r--README.jp23
-rw-r--r--ToDo3
-rw-r--r--array.c158
-rw-r--r--bignum.c157
-rw-r--r--class.c48
-rw-r--r--config.dj3
-rwxr-xr-xconfig.guess48
-rwxr-xr-xconfig.sub11
-rw-r--r--configure.in184
-rw-r--r--defines.h16
-rw-r--r--dir.c65
-rw-r--r--dln.c86
-rw-r--r--enum.c9
-rw-r--r--error.c85
-rw-r--r--eval.c2120
-rw-r--r--ext/Setup3
-rw-r--r--ext/Setup.dj4
-rw-r--r--ext/Setup.nt12
-rw-r--r--ext/Setup.x6812
-rw-r--r--ext/aix_ld.rb73
-rw-r--r--ext/curses/MANIFEST6
-rw-r--r--ext/curses/curses.c725
-rw-r--r--ext/curses/extconf.rb21
-rw-r--r--ext/curses/hello.rb28
-rw-r--r--ext/curses/rain.rb76
-rw-r--r--ext/curses/view.rb90
-rw-r--r--ext/dbm/dbm.c57
-rw-r--r--ext/dbm/extconf.rb1
-rw-r--r--ext/etc/etc.c2
-rw-r--r--ext/extmk.rb.in120
-rw-r--r--ext/extmk.rb.nt436
-rw-r--r--ext/fcntl/MANIFEST3
-rw-r--r--ext/fcntl/depend1
-rw-r--r--ext/fcntl/fcntl.c106
-rw-r--r--ext/kconv/MANIFEST1
-rw-r--r--ext/kconv/depend1
-rw-r--r--ext/kconv/kconv.c87
-rw-r--r--ext/marshal/extconf.rb1
-rw-r--r--ext/marshal/marshal.c702
-rw-r--r--ext/md5/md5init.c10
-rw-r--r--ext/socket/extconf.rb10
-rw-r--r--ext/socket/socket.c588
-rw-r--r--ext/tkutil/tkutil.c9
-rw-r--r--file.c299
-rw-r--r--gc.c345
-rw-r--r--glob.c6
-rw-r--r--hash.c470
-rw-r--r--inits.c3
-rw-r--r--io.c782
-rw-r--r--io.h7
-rw-r--r--lib/English.rb28
-rw-r--r--lib/base64.rb47
-rw-r--r--lib/date.rb221
-rw-r--r--lib/debug.rb262
-rw-r--r--lib/e2mmap.rb94
-rw-r--r--lib/e2mmap1_0.rb71
-rw-r--r--lib/finalize.rb205
-rw-r--r--lib/ftplib.rb617
-rw-r--r--lib/jcode.rb35
-rw-r--r--lib/mathn.rb3
-rw-r--r--lib/matrix.rb777
-rw-r--r--lib/mutex_m.rb183
-rw-r--r--lib/observer.rb2
-rw-r--r--lib/parsedate.rb12
-rw-r--r--lib/ping.rb55
-rw-r--r--lib/safe.rb78
-rw-r--r--lib/sync.rb376
-rw-r--r--lib/thread.rb117
-rw-r--r--lib/thwait.rb128
-rw-r--r--lib/tk.rb128
-rw-r--r--lib/tkcanvas.rb21
-rw-r--r--lib/tkclass.rb2
-rw-r--r--lib/tkcore.rb40
-rw-r--r--lib/tkentry.rb15
-rw-r--r--lib/tkscrollbox.rb4
-rw-r--r--lib/tktext.rb46
-rw-r--r--lib/tkthcore.rb33
-rw-r--r--lib/tracer.rb75
-rw-r--r--main.c18
-rw-r--r--missing/dir.h248
-rw-r--r--missing/file.h31
-rw-r--r--missing/nt.c407
-rw-r--r--missing/nt.h123
-rw-r--r--missing/setenv.c6
-rw-r--r--missing/strcasecmp.c13
-rw-r--r--node.h161
-rw-r--r--numeric.c35
-rw-r--r--object.c296
-rw-r--r--pack.c256
-rw-r--r--parse.y510
-rw-r--r--process.c373
-rw-r--r--random.c13
-rw-r--r--range.c4
-rw-r--r--re.c389
-rw-r--r--re.h3
-rw-r--r--regex.c285
-rw-r--r--regex.h4
-rw-r--r--ruby.c245
-rw-r--r--ruby.h133
-rw-r--r--sample/biorhythm.rb227
-rw-r--r--sample/dbmtest.rb (renamed from sample/dbm.rb)0
-rw-r--r--sample/dir.rb2
-rw-r--r--sample/eval.rb7
-rw-r--r--sample/freq.rb4
-rwxr-xr-xsample/from.rb93
-rw-r--r--sample/mrshtest.rb (renamed from sample/marshal.rb)11
-rw-r--r--sample/philos.rb2
-rw-r--r--sample/regx.rb2
-rw-r--r--sample/ruby-mode.el225
-rw-r--r--sample/rubydb2x.el104
-rw-r--r--sample/rubydb3x.el104
-rw-r--r--sample/svr.rb2
-rw-r--r--sample/test.rb115
-rw-r--r--sample/tkbiff.rb2
-rw-r--r--sample/tkfrom.rb18
-rw-r--r--sig.h1
-rw-r--r--signal.c16
-rw-r--r--sprintf.c314
-rw-r--r--st.c77
-rw-r--r--st.h2
-rw-r--r--string.c359
-rw-r--r--struct.c73
-rw-r--r--time.c58
-rw-r--r--top.sed30
-rw-r--r--util.c405
-rw-r--r--variable.c351
-rw-r--r--version.c7
-rw-r--r--version.h4
-rw-r--r--win32/Makefile233
-rw-r--r--win32/config.h60
-rw-r--r--win32/ntsetup.bat10
-rw-r--r--win32/ruby.def6
-rw-r--r--x68/_dtos18.c250
-rw-r--r--x68/_round.c45
-rw-r--r--x68/fconvert.c81
-rw-r--r--x68/select.c167
141 files changed, 16380 insertions, 4160 deletions
diff --git a/ChangeLog b/ChangeLog
index 9281697f25..d2fa79921f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,1192 @@
+Thu Oct 2 17:59:18 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-971002
+
+Wed Oct 1 14:01:49 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * ext/marshal/marshal.c (w_byte): argument must be char.
+
+Wed Oct 1 10:30:22 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * ext/marshal/marshal.c (marshal_dump): try to set binmode.
+
+ * ext/marshal/marshal.c (r_object): forgot to re-regist structs in
+ the object table.
+
+ * eval.c (ruby_options): call Init_ext() before any require()
+ calls by `-r'.
+
+Tue Sep 30 14:51:07 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970930
+
+Fri Sep 30 14:29:22 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * ext/marshal/marshal.c (w_object): marshal dumped core.
+
+Tue Sep 30 10:27:39 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * sample/test.rb: bignum test suits added.
+
+Mon Sep 29 13:37:58 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * ruby.c (forbid_setid): forbid some options in suid mode.
+
+Mon Sep 27 09:53:48 1997 EGUCHI Matsumoto <eguchi@shizuokanet.or.jp>
+
+ * bignum.c: modified for speeding.
+
+Fri Sep 26 18:27:59 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * sample/from.rb: some extensions.
+
+Mon Sep 29 13:15:56 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * parse.y (lhs): no more syntax error on `obj.CONSTANT = value'.
+
+Fri Sep 26 14:41:46 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * eval.c (ruby_run): deferred calling Init_ext() just before eval_node.
+
+Fri Sep 26 13:27:24 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * io.c (io_isatty): forgot to return TRUE value.
+
+Fri Sep 25 11:10:58 1997 EGUCHI Osamu <eguchi@shizuokanet.or.jp>
+
+ * eval.c: use _setjmp/_longjmp instead of setjmp/longjmp on some
+ platforms.
+
+Wed Sep 24 17:43:13 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * string.c (Init_String): String#taint and String#taint? added.
+
+Wed Sep 24 00:57:00 1997 Katsuyuki Okabe <HGC02147@niftyserve.or.jp>
+
+ * X68000 patch.
+
+Tue Sep 23 20:42:30 1997 EGUCHI Osamu <eguchi@shizuokanet.or.jp>
+
+ * parse.y (node_newnode): SEGV on null node setup.
+
+Mon Sep 22 11:22:46 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * ruby.c (ruby_prog_init): wrong safe condition check.
+
+Sun Sep 21 14:46:02 1997 MAEDA shugo <shugo@po.aianet.ne.jp>
+
+ * error.c (exc_inspect): garbage added to classpath.
+
+Fri Sep 19 11:49:23 1997 <matz@netlab.co.jp>
+
+ * version 1.0-970919
+
+ * parse.y (newtok): forgot to adjust buffer size when shrinking
+ the token buffer.
+
+ * enum.c (enum_find): rb_eval_cmd() does not return value.
+
+ * io.c (pipe_open): close fds on pipe exec. fcntl(fd, F_SETFD, 1)
+ no longer used.
+
+Tue Sep 16 17:54:25 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * file.c (f_test): problem if wrong command specified.
+
+ * ruby.c (ruby_prog_init): close stdaux and stdprn for MSDOS.
+
+ * ruby.c (ruby_prog_init): should not add path from environment
+ variable, if ruby is running under seuid.
+
+ * process.c (init_ids): check suid check for setuid/seteuid etc.
+
+Mon Sep 15 00:42:04 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * regex.c (re_compile_pattern): \w{3} and \W{3} did not work.
+
+Thu Sep 11 10:31:48 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970911
+
+ * ext/socket/socket.c (sock_new): no setbuf() for NT.
+
+ * io.c (rb_fopen,rb_fdopen): set close-on-exec for every fd.
+
+Wed Sep 10 15:55:31 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970910
+
+ * ext/marshal/marshal.c (r_bytes0): extra big length check.
+
+Tue Sep 9 16:27:14 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * io.c (pipe_fptr_atexit): clean up popen()'ed fptr.
+
+ * error.c (set_syserr): some system has error code that is bigger
+ than sys_nerr. grrr.
+
+Tue Sep 9 16:27:14 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970909
+
+ * error.c (set_syserr): some system has error code that is bigger
+ than sys_nerr. grrr.
+
+Wed Sep 3 18:11:00 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970903
+
+ * eval.c (f_load): expand path if fname begins with `~'.
+
+Mon Sep 1 13:42:48 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * eval.c (rb_call): alias occured in the module body caused SEGV.
+
+Fri Aug 29 11:10:21 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * parse.y (yylex): spaces can follow =begin/=end.
+
+ * variable.c (find_class_path): look for class_tbl also for
+ unnamed fundamental classes, such as Object, String, etc.
+
+ * variable.c (rb_name_class): can't name class before String class
+ is initilialized.
+
+ * inits.c (rb_call_inits): unrecognized dependency from GC to
+ Array.
+
+ * variable.c (find_class_path): could not find class if Object's
+ iv_tbl is NULL.
+
+Thu Aug 28 13:12:05 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * parse.y (yylex): revised `=begin' skip code.
+
+ * eval.c (is_defined): separated from rb_eval().
+
+Wed Aug 27 11:32:42 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * variable.c (fc_i): some classes/modules does not have iv_tbl.
+
+ * variable.c (find_class_path): avoid inifinite loop.
+
+Tue Aug 26 13:43:47 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * eval.c (rb_eval): undef'ing non-existing method will raise
+ NameError exception.
+
+ * object.c (class_s_new): needed to create metaclass too.
+
+ * eval.c (error_print): no class name print for anonymous class.
+
+ * eval.c (rb_longjmp): proper exception raised if raise() called
+ without arguments, with $! or $@ set.
+
+ * object.c (Init_Object): superclass()'s method argument setting
+ was wrong again.
+
+Mon Aug 25 11:53:11 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * sample/ruby-mode.el (ruby-parse-region): auto-indent now
+ supports "\\" in the strings.
+
+ * struct.c (struct_getmember): new API to get member value from C
+ language side.
+
+Fri Aug 22 14:26:40 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * eval.c (error_print): modified exception print format.
+
+Thu Aug 21 16:10:58 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * sample/ruby-mode.el (ruby-calculate-indent): wrong indent level
+ calculated with keyword operators.
+
+Thu Aug 21 11:55:41 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970821
+
+Thu Aug 21 11:36:58 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * parse.y (arg): ary[0] += 1 cause SEGV
+
+Wed Aug 20 14:24:42 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970820
+
+ * eval.c (rb_call): infinite loop bug
+
+Tue Aug 19 00:15:38 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970819
+
+ * eval.c (rb_call): did not raise ArgumentError if too many
+ arguments more than optional arguments (without rest arg).
+
+ * eval.c (rb_eval): did not work well for op_asgn2 (attribute
+ self assignment).
+
+Mon Aug 18 09:25:56 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * object.c (inspect_i): did not display T_DATA instance variables.
+
+ * parse.y: provides more accurate line number information.
+
+ * eval.c (thread_value): include value's backtrace information in
+ the variable `$@'.
+
+ * eval.c (f_abort): print backtrace and exit.
+
+Sat Aug 16 00:17:44 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * object.c (class_s_new): do not make subclass of singleton class.
+
+Fri Aug 15 15:49:46 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * eval.c (call_trace_func): block context switch in the trace
+ function.
+
+ * eval.c (rb_eval): clear method cache at class extention.
+
+Fri Aug 15 19:40:43 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * ext/socket/socket.c (Init_socket): small typo caused SEGV.
+
+Tue Aug 12 16:02:18 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * variable.c: option variables: $-0, $-p(readonly), $-v,
+ $-I(load_path), $-a(readonly), $-K, $-d, $-F, $-i, $-l.
+
+ * parse.y (yylex): ignore rd (ruby document) in the code.
+
+Mon Aug 11 12:37:58 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * re.c (Init_Regexp): $-K as alias to the $KCODE.
+
+ * io.c (Init_IO): new virtual variable $-i for the value of -i
+ option.
+
+ * enum.c (Init_Enumerable): include? as alias of member?
+
+Fri Aug 8 11:16:50 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * io.c (io_foreach): now the record separator can be specified.
+
+ * io.c (io_s_readlines): new method to read in whole file (or
+ command output) from path.
+
+ * ext/socket/socket.c (Init_socket): recvfrom did not work.
+
+ * ext/socket/socket.c (sock_send): forgot to check nil for false
+ value.
+
+Thu Aug 7 11:40:01 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * object.c (Init_Object): remove private_attr/public_attr.
+
+Wed Aug 6 14:21:36 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * object.c (mod_attr): forgot to check nil for false value.
+
+Mon Aug 4 11:50:28 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * variable.c (rb_class_path): scan class constants for anonymous
+ classes/modules to make up pathes.
+
+Wed Jul 30 08:45:12 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * eval.c (rb_eval): stop to cache const value in nodes.
+
+Sat Jul 26 03:17:22 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * numeric.c (flo_to_s): wrong .0 at end.
+
+Sat Jul 26 00:36:36 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * eval.c (error_print): always print exception type in the
+ toplevel exception handler.
+
+ * string.c (str_hash): wrong hash value.
+
+Thu Jul 24 11:05:51 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * string.c (uscore_get): proper error message for unset $_.
+
+Wed Jul 23 09:56:55 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * object.c (obj_methods): returns list of method names of the
+ specified object.
+
+ * class.c (mod_instance_methods): returns list of method names of
+ the class instnace.
+
+Fri Jul 11 22:38:55 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * object.c (class_superclass): returns class's superclass
+ itself. (1.1)
+
+ * object.c (obj_type): returns object's class itself. (1.1)
+
+ * class.c (mod_included_modules): list included modules.
+
+ * object.c (class_superclass): raises error for Object.
+
+Thu Jul 3 09:54:02 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (SETUP_ARGS): save source position, remove nd_line().
+
+ * eval.c (rb_call): replace modulo by bit-masking.
+
+ * eval.c (POP_SCOPE): force recycle scope object to reduce gc rate.
+
+ * gc.c (obj_free): aboid calling run_final() when no finalizer is set.
+
+ * eval.c (PUSH_VARS): do not allocate the dynamic scope's end-mark
+ object.
+
+Wed Jul 2 14:25:07 1997 KIMURA Koichi <kkimura@pure.cpdc.canon.co.jp>
+
+ * Native mswin32 support.
+
+Tue Jul 1 09:59:00 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970701
+
+ * parse.y (mrhs): allow rest-star(*) in right hand side.
+
+Tue Jun 24 19:04:31 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970624
+
+Sat Jun 20 22:22:51 1997 Michio "Karl" Jinbo <karl@marcer.nagaokaut.ac.jp>
+
+ * eval.c: freebsd 3.0 <sys/select.h> support.
+
+Fri Jun 20 01:24:45 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970620
+
+ * gc.c: eliminate uninitilalized field of Hash, Array etc., to
+ avoid dumping core.
+
+Thu Jun 19 01:29:44 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970619
+
+ * string.c (str_split_method): wrong limit.
+
+Sat Jun 14 01:54:16 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * class.c (rb_singleton_class): no singleton for special
+ constants (now raises exception).
+
+ * eval.c (ruby_init): cbase in TOPLEVEL_BINDING need to be
+ initialized.
+
+Sat Jun 14 01:01:16 1997 maeda shugo <shugo@po.aianet.ne.jp>
+
+ * array.c (sort_2): wrong comparison.
+
+Sat Jun 14 00:53:44 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * hash.c (hash_foreach): safe iteration.
+
+Fri Jun 13 14:04:56 1997 Michio "Karl" Jinbo <karl@marcer.nagaokaut.ac.jp>
+
+ * configure.in: -Bshareable option for netbsd.
+
+Fri Jun 13 01:16:22 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * io.c (pipe_open): call io_unbuffered() only for writable pipes.
+
+Thu Jun 12 01:14:15 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970612
+
+ * ext/socket/socket.c (sock_new): use io_unbuffered().
+
+ * ext/marshal/marshal.c (w_long): compact long format, which
+ supports 64 bit architectures (unless longs are >32 bit size).
+
+ * ext/marshal/marshal.c: allows recursive data for marshaling.
+
+ * parse.y (rb_intern): raise exception for non-internable string.
+
+ * ext/marshal/marshal.c (marshal_load): allows direct loading from
+ strings.
+
+ * ext/marshal/marshal.c (marshal_dump): allows direct dump to strings.
+
+ * ext/marshal/marshal.c (marshal_dump): interface changed.
+
+Wed Jun 11 18:26:00 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * gc.c (rb_newobj): remove needless memset().
+
+Mon Jun 9 13:03:43 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (rb_eval): reduce condition checks from while/until loop.
+
+ * eval.c (rb_eval): wrong jump point for `next'.
+
+Fri Jun 6 11:47:39 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ruby.c (ruby_set_argv): initialize dln_argv0 for dln_a_out.
+
+ * ext/socket/socket.c (open_unix): display path name for exceptions.
+
+ * ruby.c (proc_options): option -S did not work well.
+
+Fri May 30 02:14:44 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970530
+
+ * eval.c (eval): set $! properly if exception raised in eval().
+
+ * io.c (io_write): now handles non T_FILE object.
+
+ * io.c (io_defset): $< can be anything which has `write' method.
+
+Thu May 29 15:40:22 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (eval): $@ is always an array (not string).
+
+ * pack.c (pack_unpack): avoid corrupting memory for unexpected
+ input strings.
+
+Wed May 28 12:46:13 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970528
+
+ * process.c (rb_waitpid): do not block other threads.
+
+Tue May 27 12:02:31 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (ruby_init): split initialize and processing command line
+ options.
+
+ * ruby.c (ruby_options): ruby_init(0, 0, envp) dumps core.
+
+Tue May 20 18:59:45 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * variable.c (rb_ivar_set): invalid instance variable access for
+ built-in object raises TypeError.
+
+Fri May 16 17:32:21 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970516
+
+ * dir.c (push_globs): was freeing non heap pointer.
+
+ * gc.c: remove some duplicated prototypes.
+
+ * ext/kconv/kconv.c: fix prototypes.
+
+Fri May 9 11:38:59 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970509
+
+ * gc.c (obj_free): avoid free(NULL).
+
+ * eval.c (rb_check_safe_str): argument missing for TypeError().
+
+Thu May 8 01:14:28 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * file.c (file_s_dirname): need to return "." for path without
+ slashes.
+
+Wed May 7 19:18:48 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * process.c (f_fork): child processe does not inherit parent's
+ itimer setting on linux. call setitimer() again in the child
+ process.
+
+Sat May 3 02:49:43 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ext/curses/curses.c: modified for portability and add to the
+ standard distribution.
+
+Wed Apr 30 00:34:00 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * file.c (file_s_size): returns 0 for empty files (not FALSE).
+
+Fri Apr 25 02:17:50 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970425
+
+ * eval.c (f_load): free unused name-table.
+
+ * eval.c (f_load): copy local variable name-table.
+
+ * gc.c (obj_free): avoid free(NULL).
+
+ * eval.c (rb_eval): forgot to make link from the scope object to
+ NODE_SCOPE. It may crash the interpreter.
+
+Thu Apr 24 00:35:09 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * random.c (f_srand): save old seed anyway. srand() returns no
+ value on some systems.
+
+ * gc.c (obj_free): avoid double free of the local variable name
+ table.
+
+ * parse.y (top_local_setup): modify realloc to handle offset.
+
+Tue Apr 22 12:58:26 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970422
+
+Thu Apr 17 00:40:51 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * configure.in (rb_cv_bsdpgrp): proper check for BSD
+ setpgrp/setpgrp.
+
+Wed Apr 16 16:14:02 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (proc_call): proc called in other thread must be orphan.
+
+Tue Apr 15 10:46:31 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970415
+
+ * gc.c (obj_free): NODE_SCOPE marked from SCOPE object.
+
+ * gc.c (gc_mark): some nodes marked wrong.
+
+ * process.c (proc_getpgrp): wrong argument
+
+Fri Apr 14 18:32:42 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970414
+
+Fri Apr 12 01:20:12 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ruby.h: String pointer changed to unsigned char.
+
+Fri Apr 11 10:27:29 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970411
+
+ * Makefile.in: create libruby.a before linking ruby.
+
+ * string.c (str_strip_bang): >0x80 characters for isspace().
+
+ * eval.c (proc_call): set safe-level temporally
+
+ * eval.c (proc_s_new): save safe-level in the proc context.
+
+ * eval.c (rb_eval): no class/module extention in safe mode.
+
+Thu Apr 10 02:10:41 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * gc.c (gc_mark): remove some pointer checks for speeding up.
+
+ * ruby.c (ruby_options): set $0 temporally for -r option.
+
+ * eval.c: built-in security feature.
+
+ * gc.c (gc_sweep): do not free nodes during compile.
+
+ * parse.y (yycompile): set flag when compiling.
+
+Wed Apr 9 10:19:02 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ruby.c: forgot to include <ctype.h> for isspace().
+
+ * file.c: provide S_ISREG for some platforms.
+
+ * io.c (Init_IO): added some $< operations.
+
+ * lib/ping.rb: check host upness using TCP echo.
+
+Tue Apr 8 00:10:15 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * io.c (arg_read): bug with 0 length input.
+
+Mon Apr 7 11:36:16 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ext/fcntl/fcntl.c: module for fcntl constants.
+
+ * eval.c (rb_alias): bug when original was an alias.
+
+ * parse.y (primary): syntax to access singleton class.
+
+ * eval.c (mod_public_method): method's to specify visibitily of
+ the class methods. make_method_{public,private} removed.
+
+Fri Apr 4 21:43:57 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970404
+
+ * gc.c (obj_free): finalizer added for experiment.
+
+Thu Apr 3 02:12:31 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (thread_schedule): make Fatal rise on main_thread on
+ deadlocks.
+
+ * eval.c (thread_join): raise ThreadError instead of Fatal, in
+ case of deadlock.
+
+ * regex.c (re_compile_fastmap): uninitialized local variable.
+
+ * parse.y (parse_regx): new option //[nes] to specify character
+ code for regexp literals. Last specified code option is valid.
+
+ * re.c (reg_s_new): addtional 3rd argument to specify compiled
+ regexp's character code.
+
+ * re.c (reg_new_1): regexp character code can be specified for
+ each regexp object.
+
+Wed Apr 2 14:51:06 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (thread_create): handle uncaught throw.
+
+ * eval.c (thread_create): halt on some deadlock conditions.
+
+ * regex.c (is_in_list): wrong result for non-mbc higher-byte
+ characters.
+
+ * regex.c (re_match): wrong skip for multi-byte characters.
+
+ * regex.c (re_compile_fastmap): wrong fastmap in non-mbc mode.
+
+ * hash.c (Init_Hash): hash compatible features added to ENV.
+
+Tue Apr 1 15:24:06 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (obj_extend): remove Object#extend as an iterator which
+ is in experimental state, since it unveils internal singleton
+ classes.
+
+Mon Mar 31 14:29:39 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970331
+
+Sun Mar 30 19:40:57 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * parse.y (terms): avoided win32 gcc's optimization bug.
+
+Sat Mar 29 11:21:58 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * struct.c (make_struct): St[val,..] creates new structure.
+
+Fri Mar 28 11:24:51 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (obj_make_private): new method make_method_{public,private}
+ to change visibility of singleton methods.
+
+ * regex.c (re_compile_pattern): enables numeric literal >= 0x80 in
+ the character class.
+
+ * regex.c (re_compile_pattern): enabled numeric literal >= 0x80,
+ in multibyte mode.
+
+ * regex.c (re_compile_fastmap): modified exantn and charset(_not)
+ to set fastmap for higher bytes properly.
+
+ * regex.c (is_in_list): now matches numeric literals.
+
+Thu Mar 27 13:34:20 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * pack.c (pack_unpack): extra null byte after unpacked string.
+
+Wed Mar 26 15:20:34 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * regex.c (re_compile_pattern): register numbers must be fit in a
+ byte (0 <= regnum <= 0xff).
+
+ * regex.c (re_compile_fastmap): forgot to set mbchar map for
+ charset_not if RE_MBCTYPE is on.
+
+ * regex.c (re_compile_pattern): set list bits for multi-byte
+ characters for \W, \S, \D in range expression.
+
+ * object.c (obj_is_kind_of): defined that nil itself is kind of
+ nil. TRUE is kind of TRUE, FALSE is kind of FALSE likewise.
+ This change makes `obj.kind_of?(eval(obj.type))' always true.
+
+Tue Mar 25 14:08:43 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * lib/English.rb: provides nicer English alias for the variables.
+
+ * parse.y (expr): alias $var1 $var2 makes alias of the global
+ variable.
+
+Mon Mar 24 18:23:20 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970324
+
+Thu Mar 20 22:04:59 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (mod_modfunc): forget to clear method cache.
+
+Wed Mar 19 17:06:55 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * parse.y (program): set methods' default private/public status
+ correctly under eval().
+
+ * eval.c (eval): set the_class correctly while evaluating string.
+
+Tue Mar 18 12:23:53 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (eval): yield can be called from eval().
+
+ * version 1.0-970318
+
+ * parse.y (program): regexp in condition expression should do
+ matching operation with $_.
+
+ * re.c (reg_regsub): wrong substitution.
+
+Fri Mar 14 14:36:28 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * hash.c (hash_invert): returns value to key mapping of the
+ associative array.
+
+ * ext/socket/extconf.rb: set environment variable SOCKS_SERVER to
+ compile with libsocks.a.
+
+ * ext/socket/socket.c (socks_s_open): SOCKSsocket class to access
+ internet via SOCKS library.
+
+ * sprintf.c (f_sprintf): unsigned formats display leading double
+ dots for imaginary sequence of signed bit to the left.
+
+ * sprintf.c (f_sprintf): correct width and precision formatting
+ for big integers.
+
+ * parse.y (yylex): enables negative hex/octal numbers and `_' in
+ non-decimal numbers.
+
+ * sprintf.c (f_sprintf): %u added for unsigned decimal format.
+
+Thu Mar 13 10:24:27 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * sprintf.c (f_sprintf): wrong output for bignums.
+
+ * array.c (ary_reverse_each): iterates in reverse order.
+
+ * pack.c (pack_unpack): L unpacked signed long.
+
+ * io.c (f_backquote): now returns an empty string for no output.
+
+Wed Mar 12 10:20:30 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ext/socks/socks.c: socket module with socks library.
+
+Mon Mar 10 20:44:22 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * re.c (reg_regsub): \& for substitution. \`, \', and \+ are
+ avaiable also.
+
+Thu Mar 6 01:47:03 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970306
+
+ * sample/rubydb.el (gud): ruby debugger emacs interface
+
+ * lib/debug.rb: ruby debugger
+
+ * parse.y (exprs): more accurate line number display.
+
+Wed Mar 5 21:31:46 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970305
+
+Tue Mar 4 12:28:32 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ruby.c (proc_options): search through RUBYPATH and PATH for
+ option -S.
+
+Mon Mar 3 22:44:55 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (thread_status): returns nil for exception terminated
+ threads.
+
+ * eval.c (thread_value): re-raise exceptions.
+
+Sat Mar 1 00:59:47 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (rb_eval): restore $! value after rescue clause, to
+ re-raise exceptions correctly.
+
+Fri Feb 28 16:43:38 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970228
+
+Thu Feb 27 11:23:41 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (rb_yield_0): redo raises exception
+
+ * eval.c (thread_schedule): bug in interrupt handling by rescue.
+
+Wed Feb 26 00:55:36 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (eval): forgot to restore dynamic local variable
+ bindings.
+
+Tue Feb 25 11:22:08 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ext/aix_ld.rb: AIX dynamic load support (not tested).
+
+ * eval.c (rb_eval): wrong return value for defined? super.
+
+ * error.c (exception): more error check.
+
+ * re.c (reg_regsub): wrong substitution when sub expanded to null
+ string.
+
+Fri Feb 21 13:01:47 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970221
+
+ * eval.c (f_require): volatile added. register variable was
+ recycled, so that GC did not mark that variable.
+
+ * object.c (Init_Object): forget to mark main object (was mostly
+ ok, but made trouble with early GC.)
+
+Thu Feb 20 11:50:50 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970220
+
+Thu Feb 20 11:25:50 1997 Yasuo OHBA <jammy@shljapan.co.jp>
+
+ * lib/date.rb: update
+
+Thu Feb 20 08:25:57 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * parse.y (yylex): forgot tokfix() before rb_intern().
+
+ * lib/tk.rb (TkVariable): give up using trace_var.
+
+Wed Feb 19 00:24:35 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970219
+
+ * pack.c (pack_pack): packed by null for A specifier. must be
+ space filled.
+
+ * pack.c (pack_unpack): bug in skipping spaces
+
+ * gc.c (xmalloc): garbage collect for every 4 Meg. allocation.
+
+ * string.c (str_split_method): limit worked wrong way.
+
+ * io.c (io_gets_method): misunderstand 0xff in binary files when
+ $/ == nil.
+
+ * re.c (reg_regsub): re-implement.
+
+ * ext/socket/socket.c (thread_connect): remove O_NONBLOCK, which
+ is not defined on some platform like NeXT.
+
+Mon Feb 17 13:08:30 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970217
+
+ * object.c (mod_eqq): === extended for subclass check (to use case
+ as typecase).
+
+Sat Feb 15 02:07:22 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * regex.c (re_compile_pattern): wrong match backref at end of pattern.
+
+ * io.c (arg_read): now works beyond end of file.
+
+Thu Feb 13 16:21:24 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * parse.y (expr): return/yield now accept normal argument format.
+
+ * parse.y (yylex): a star in `yield *x' must not be multiplication
+ operator.
+
+Wed Feb 12 15:06:44 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * time.c (time_plus): bug in simple addition.
+
+ * eval.c (thread_raise): raise exceptions from outside.
+
+ * eval.c (Init_Thread): Thread#alive? -- alias for Thread#status.
+
+Mon Feb 10 00:38:55 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ruby.h (Data_Make_Struct): rename macros.
+
+Sun Feb 8 11:48:13 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * io.c (f_syscall): argument offset was wrong.
+
+Fri Feb 7 18:01:17 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970207
+
+ * eval.c: add volatiles to avoid variable crobbering by longjmp().
+
+ * eval.c (f_raise): 1st argument can be the GlobalExit object now.
+
+ * array.c (ary_unshift): no longer accept more than 2 args.
+
+ * eval.c (f_raise): bug if 2nd argument is the exception.
+
+Tue Feb 4 00:37:29 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970204
+
+ * eval.c (eval): check compile errors by nerrs.
+
+ * eval.c (rb_eval): check syntax error by nerrs, not by the return
+ value, which may be NULL.
+
+ * eval.c (compile): Do not clear errinfo.
+
+Mon Feb 3 10:13:06 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (obj_extend): move real inclusion to Module#extend_object
+ to allow redfinition.
+
+ * object.c (Init_Object): Kernel class is now Module. Object class
+ became the true root class.
+
+ * object.c (obj_inspect): remove useless buffer.
+
+ * hash.c (any_cmp): disable interrupts and context switching.
+
+ * st.c: remove ALLOW_INTS to disable interrupt during operations.
+
+Fri Jan 31 22:10:08 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * hash.c (hash_rehash): re-register all key-value.
+
+Thu Jan 30 02:14:49 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * io.c (io_reopen): re-implement according to clone() way.
+
+ * io.c (io_clone): copy IO object.
+
+ * struct.c (struct_eql): compare elements by eql?.
+
+ * io.c (io_mode_flags): detect "rb", "wb" etc.
+
+ * io.h (FMODE_BINMODE): added.
+
+ * ext/socket/socket.c (Init_socket): undef BasicSocket.new
+
+ * file.c (Init_File): File.new(path[,mode])
+
+ * io.c (Init_IO): IO.new(fd[,mode])
+
+ * eval.c (rb_method_boundp): forgot to enable priv argument.
+
+ * object.c (Init_Object): remove `=~' from Kernel class.
+
+ * ext/socket/socket.c (open_inet): initialize sockaddr before
+ calling bind(2).
+
+ * sample/ruby-mode.el (ruby-calculate-indent): skip comment lines
+
+Wed Jan 29 18:43:22 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (Init_Thread): DEFER_INTS during initializing threads.
+
+ * hash.c (Init_Hash): Hash#eql? checks for object identity.
+
+ * eval.c (thread_set_critical): wrong value assigned.
+
+Mon Jan 27 16:10:51 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * io.c (io_print): remove print_on().
+
+ * eval.c (f_missing): proper error message for undefined method
+ without argument
+
+Sat Jan 25 23:32:32 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * string.c (str_sub_s): false alert - sub() does not modify string.
+
+ * array.c (ary_times): negative multiplication detected
+
+ * string.c (str_times): negative multiplication detected
+
+Fri Jan 24 10:51:39 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * time.c (time_arg): month -> 0 == "jan" == "1" == "01", little bit
+ confusing but wanted to conform japanese style.
+
+ * version 1.0-970124
+
+Fri Jan 24 09:52:49 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * util.c (_fixpath): supports SJIS filenames on DJGPP.
+
+Thu Jan 23 16:52:06 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * README.EXT: update. partially translated into English.
+
+ * ext/extmk.rb.in: inherit $LDFLAGS to the final link.
+
+ * ext/socket/socket.c (Init_socket): add various constants.
+
+Mon Jan 23 11:40:59 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * eval.c (Init_Thread): allocate main_thread first to avoid crash.
+
+Thu Jan 23 02:09:26 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * gc.c (ObjectSpace): API modified. each_object method will do all
+ the iteration.
+
+ * eval.c (proc_call): wrong return from nested lambda.
+
+ * ext/GD/GD.c: debugged.
+
+Wed Jan 22 16:12:25 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970122
+
+ * gc.c (gc_mark): forgot to mark match->str.
+
+ * ext/GD/GD.c: GD interface module.
+
+ * eval.c (PUSH_BLOCK): wrong value pushed as the block level.
+
+Mon Jan 20 14:01:31 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (thread_run): no context switch in the critical section.
+
+Mon Jan 20 09:40:59 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * utils.c: supports 8+3 filenames
+
+Sat Jan 18 01:23:03 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970118
+
+ * regex.c (PATFETCH): need cast to unsigned char.
+
+ * io.c (io_ctl): bug in case when arg is not a string.
+
+ * lib/tk.rb: forgot that Kernel#type returns the class name now.
+
+ * regex.c (re_search): "abc\n" =~ "^$" should not match.
+
+Fri Jan 17 12:31:37 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970117
+
+ * ruby.c (ruby_options): constant PLATFORM, which is in the {cpu}-{os}
+ form, defined.
+
+ * configure.in: platform infomation embedded in the interpreter.
+
+ * regex.c (re_search): /^$/ did not match to "" by wrong exit condition.
+
+ * lib/thread.rb: re-write Mutex/Queue based on Thread.critical.
+
+ * eval.c (thread_set_critical): remove Thread.exclusive, add
+ Thread.critical = TRUE/FALSE instead.
+
+ * re.c (reg_search): re-compile pattern if needed
+
+ * regex.c (PATFETCH): do translate at compile time
+
+Thu Jan 16 00:49:10 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * gc.c (gc_mark_frame): forgot to mark frame->cbase.
+
+ * regex.c (re_compile_pattern): /a$|b)/ causes error.
+
+ * regex.c (re_compile_pattern): /(^|b)/ causes error.
+
+ * version 1.0-970116
+
+ * re.c (Init_Regexp): set RE_CONTEXTUAL_INVALID_OPS flag.
+
+Tue Jan 14 02:09:06 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (proc_call): Proc#callをイテレータとして呼んだ時に対応
+
+ * configure.in: nextstep対応?
+
+ * eval.c (rb_eval): a[b]=cで無駄な配列を割り当てない
+
+ * eval.c (f_send): イテレータとして呼ばれたらイテレータとしてメソッ
+ ドを呼ぶ.
+
+ * string.c (str_new4): match共有用の生成関数
+
+ * re.c (reg_search): matchの実体(文字列)をマッチを行った文字列と
+ copy-on-writeで共有
+
+ * string.c (str_hash): toupperをかける条件が違っていた
+
+ * array.c (sort_2): FixnumとStringを特別扱いして高速化
+
+Mon Jan 13 11:03:53 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (thread_create): threadが生成されるまで割込みを設定しない
+
+ * eval.c (Init_Thread): 割込みタイミングを100msecに
+
+Sat Jan 11 00:17:05 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * regex.c (re_search): マッチに失敗する場合があった(本当に直ったか?)
+
+ * io.c (io_ioctl,io_fcntl): 第2引数を省略可能に
+
+ * io.c (io_ioctl,io_fcntl): 戻り値がIOだった.整数(システムコール
+ の戻り値)を返すようにした.
+
+ * io.c (io_ctl): 引数が整数の時に対応
+
+ * io.c (io_fcntl): file.cから移動
+
+Fri Jan 10 17:01:47 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970110
+
+ * ext/socket/socket.c (thread_connect): open(connect(2))で他の
+ threadをブロックしないように
+
+ * eval.c (thread_create): exitでないときにexitだと思い込む
+
+Mon Jan 6 17:42:22 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * string.c (str_sub_s): 文字列長より長いoffsetの検出
+
+ * regex.c (re_search): 空にマッチするパターン後の$で失敗
+
+Thu Jan 2 16:36:23 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * file.c (file_reopen): Fileのreopen(pathまたはIOで指定).
+
+ * io.c (io_reopen): IOのreopen(IOで指定) -- change classつき
+
+Wed Jan 1 11:09:01 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * io.c (f_select): timeoutでnilを返す
+
+Fri Dec 27 13:06:44 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * file.c (file_s_open): サブクラスではそのクラスのインスタンスを返
+ すように.
+
+Fri Dec 27 08:58:27 1996 ono@isl.nara.sharp.co.jp
+
+ * numeric.c (flo_to_s): index()を使わない.strstr()に.
+
+Thu Dec 26 01:34:17 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * lib/tk.rb: placeが使えるように
+
+ * pack.c (endian): マクロDYNAMIC_ENDIANを指定すると実行時にendian
+ を判定するように.
+
+ * eval.c (thread_alloc): 初期化忘れのメンバがあった.
+
Wed Dec 25 00:33:19 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 1.0-961225
@@ -208,7 +1397,7 @@ Fri Nov 29 12:17:59 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* hash.c (Init_Hash): 述語key?,value?,include?の追加
- * eval.c (rb_eval): else節が実行されない(うーん)
+ * eval.c (rb_eval): unlessでelse節が実行されない(うーん)
* string.c (str_sub_iter_s): イテレータブロック内でマッチが行われ
ると位置がずれる(時に無限ループに落ちる)
@@ -261,7 +1450,7 @@ Thu Nov 21 04:13:21 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* pack.c (pack_unpack): 行末の改行がない時にもチェックサムをスキッ
プするように
-Wed Nov 20 96 21:42:51 1996 Yasuo OHBA <jammy@shljapan.co.jp>
+Wed Nov 20 96 21:42:51 1996 Yasuo OHBA <jammy@shljapan.co.jp>xc
* configure.in: freebsd対応
diff --git a/MANIFEST b/MANIFEST
index 3b0ba3e0d0..587294b705 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -66,21 +66,36 @@ version.c
version.h
ext/Setup
ext/Setup.dj
+ext/Setup.nt
+ext/Setup.x68
ext/extmk.rb.in
+ext/extmk.rb.nt
+ext/aix_ld.rb
+lib/English.rb
lib/base64.rb
lib/cgi-lib.rb
lib/complex.rb
+lib/date.rb
+lib/debug.rb
+lib/e2mmap.rb
+lib/e2mmap1_0.rb
lib/find.rb
+lib/finalize.rb
+lib/ftplib.rb
lib/getopts.rb
lib/jcode.rb
lib/mailread.rb
lib/mathn.rb
+lib/matrix.rb
+lib/mutex_m.rb
lib/observer.rb
lib/parsearg.rb
lib/parsedate.rb
+lib/ping.rb
lib/rational.rb
-lib/safe.rb
+lib/sync.rb
lib/thread.rb
+lib/thwait.rb
lib/tk.rb
lib/tkcore.rb
lib/tkcanvas.rb
@@ -89,15 +104,19 @@ lib/tkentry.rb
lib/tkscrollbox.rb
lib/tktext.rb
lib/tkthcore.rb
+lib/tracer.rb
missing/alloca.c
missing/crypt.c
+missing/dir.h
missing/dup2.c
+missing/file.h
missing/flock.c
missing/memmove.c
missing/mkdir.c
missing/nt.c
missing/nt.h
missing/setenv.c
+missing/strcasecmp.c
missing/strdup.c
missing/strerror.c
missing/strftime.c
@@ -107,7 +126,7 @@ missing/strtoul.c
sample/biorhythm.rb
sample/cbreak.rb
sample/clnt.rb
-sample/dbm.rb
+sample/dbmtest.rb
sample/dir.rb
sample/eval.rb
sample/export.rb
@@ -126,7 +145,7 @@ sample/less.rb
sample/list.rb
sample/list2.rb
sample/list3.rb
-sample/marshal.rb
+sample/mrshtest.rb
sample/mkproto.rb
sample/mpart.rb
sample/observ.rb
@@ -140,6 +159,8 @@ sample/rcs.dat
sample/rcs.rb
sample/regx.rb
sample/ruby-mode.el
+sample/rubydb2x.el
+sample/rubydb3x.el
sample/sieve.rb
sample/svr.rb
sample/test.rb
@@ -154,3 +175,11 @@ sample/tktimer.rb
sample/trojan.rb
sample/tsvr.rb
sample/uumerge.rb
+win32/Makefile
+win32/config.h
+win32/ntsetup.bat
+win32/ruby.def
+x68/fconvert.c
+x68/select.c
+x68/_dtos18.c
+x68/_round.c
diff --git a/Makefile.in b/Makefile.in
index aa018968ff..ee0ac1fcfc 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -3,32 +3,40 @@ SHELL = /bin/sh
#### Start of system configuration section. ####
srcdir = @srcdir@
-VPATH = @srcdir@
+VPATH = @srcdir@:@srcdir@/missing
CC = @CC@
YACC = @YACC@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
-PURIFY=
+PURIFY =
@SET_MAKE@
-CFLAGS = @CFLAGS@ -I.
-STATIC = @STATIC@
-LDFLAGS = $(CFLAGS) @LDFLAGS@
-LIBS = -lm @LIBS@ $(EXTLIBS)
+CFLAGS = @CFLAGS@ -I@srcdir@
+LDFLAGS = @STATIC@ $(CFLAGS) @LDFLAGS@
+LIBS = @LIBS@ $(EXTLIBS)
MISSING = @LIBOBJS@ @ALLOCA@
+program_transform_name = -e @program_transform_name@
+RUBY_INSTALL_NAME = `t='$(program_transform_name)'; echo ruby | sed $$t`
+
prefix = @prefix@
-binprefix =
exec_prefix = @exec_prefix@
-bindir = $(exec_prefix)/bin
-libdir = @prefix@/lib/ruby
+bindir = @bindir@
+libdir = @libdir@/$(RUBY_INSTALL_NAME)
+
+binsuffix = @binsuffix@
#### End of system configuration section. ####
+
+LIBRUBY = libruby.a
+
EXTOBJS = dmyext.o
+MAINOBJ = main.o
+
OBJS = array.o \
bignum.o \
class.o \
@@ -45,7 +53,6 @@ OBJS = array.o \
hash.o \
inits.o \
io.o \
- main.o \
math.o \
numeric.o \
object.o \
@@ -66,41 +73,44 @@ OBJS = array.o \
util.o \
variable.o \
version.o \
- $(MISSING) \
- $(EXTOBJS)
-
-PROGRAM = miniruby
+ $(MISSING)
-all: extruby
-
-extruby: miniruby ext/Setup
+all: miniruby$(binsuffix) @srcdir@/ext/Setup
@if test -z "$$UNDER_EXTMAKE_RB"; \
then echo "Compiling ext modules"; \
UNDER_EXTMAKE_RB=yes; export UNDER_EXTMAKE_RB; \
cd ext; ../miniruby ./extmk.rb @EXTSTATIC@; fi
-$(PROGRAM): $(OBJS)
- @rm -f $(PROGRAM)
- $(PURIFY) $(CC) $(STATIC) $(LDFLAGS) $(OBJS) $(LIBS) -o $(PROGRAM)
+miniruby$(binsuffix): $(OBJS) $(MAINOBJ) $(EXTOBJS)
+ @rm -f $@
+ $(PURIFY) $(CC) $(LDFLAGS) $(MAINOBJ) $(OBJS) $(EXTOBJS) $(LIBS) -o miniruby
+
+ruby$(binsuffix): $(LIBRUBY) $(MAINOBJ) $(EXTOBJS)
+ @rm -f $@
+ $(PURIFY) $(CC) $(LDFLAGS) $(MAINOBJ) $(EXTOBJS) $(LIBRUBY) $(LIBS) -o ruby
+
+$(LIBRUBY): $(OBJS) dmyext.o
+ @AR@ rcu $(LIBRUBY) $(OBJS) dmyext.o
+ @-@RANLIB@ $(LIBRUBY) 2> /dev/null || true
-install:; $(INSTALL_PROGRAM) ruby $(bindir)/ruby
- @-@STRIP@ $(bindir)/ruby
+install:; $(INSTALL_PROGRAM) ruby$(binsuffix) $(bindir)/$(RUBY_INSTALL_NAME)$(binsuffix)
+ @-@STRIP@ $(bindir)/$(RUBY_INSTALL_NAME)$(binsuffix)
@test -d $(libdir) || mkdir $(libdir)
cd ext; ../miniruby ./extmk.rb install
- @for rb in `grep '^lib/' MANIFEST`; do \
- $(INSTALL_DATA) $$rb $(libdir); \
+ @for rb in `grep '^lib/' @srcdir@/MANIFEST`; do \
+ $(INSTALL_DATA) @srcdir@/$$rb $(libdir); \
done
-clean:; @rm -f $(OBJS)
- @rm -f ext/extinit.c ext/extinit.o
+clean:; @rm -f $(OBJS) $(LIBRUBY) $(MAINOBJ)
+ @rm -f ext/extinit.c ext/extinit.o dmyext.o
cd ext; ../miniruby ./extmk.rb clean
realclean: clean
- @rm -f Makefile ext/extmk.rb
+ @rm -f Makefile ext/extmk.rb ext/config.cache parse.c
@rm -f config.cache config.h config.log config.status
- @rm -f core ruby miniruby *~
+ @rm -f core ruby$(binsuffix) miniruby$(binsuffix) parse.c *~ *.core gmon.out
-test:; @-./ruby sample/test.rb > ./ruby_test 2>&1; \
+test:; @-./ruby @srcdir@/sample/test.rb > ./ruby_test 2>&1; \
if grep '^end of test' ./ruby_test > /dev/null; then \
echo "test succeeded"; \
else \
@@ -113,47 +123,57 @@ test:; @-./ruby sample/test.rb > ./ruby_test 2>&1; \
.c.o:
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
-alloca.o: missing/alloca.c
- $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/alloca.c
+parse.c: parse.y
+ $(YACC) $<
+ mv -f y.tab.c parse.c
+
+alloca.o: @srcdir@/missing/alloca.c
+ $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/alloca.c
+
+crypt.o: @srcdir@/missing/crypt.c
+ $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/crypt.c
+
+dup2.o: @srcdir@/missing/dup2.c
+ $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/dup2.c
-crypt.o: missing/crypt.c
- $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/crypt.c
+flock.o: @srcdir@/missing/flock.c
+ $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/flock.c
-dup2.o: missing/dup2.c
- $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/dup2.c
+memmove.o: @srcdir@/missing/memmove.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/memmove.c
-flock.o: missing/flock.c
- $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/flock.c
+mkdir.o: @srcdir@/missing/mkdir.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/mkdir.c
-memmove.o: missing/memmove.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/memmove.c
+setenv.o: @srcdir@/missing/setenv.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/setenv.c
-mkdir.o: missing/mkdir.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/mkdir.c
+strcasecmp.o: @srcdir@/missing/strcasecmp.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strcasecmp.c
-setenv.o: missing/setenv.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/setenv.c
+strerror.o: @srcdir@/missing/strerror.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strerror.c
-strerror.o: missing/strerror.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/strerror.c
+strdup.o: @srcdir@/missing/strdup.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strdup.c
-strdup.o: missing/strdup.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/strdup.c
+strftime.o: @srcdir@/missing/strftime.c
+ $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strftime.c
-strftime.o: missing/strftime.c
- $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/strftime.c
+strstr.o: @srcdir@/missing/strstr.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strstr.c
-strstr.o: missing/strstr.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/strstr.c
+strtol.o: @srcdir@/missing/strtol.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strtol.c
-strtol.o: missing/strtol.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/strtol.c
+strtoul.o: @srcdir@/missing/strtoul.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strtoul.c
-strtoul.o: missing/strtoul.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/strtoul.c
+nt.o: @srcdir@/missing/nt.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/nt.c
-nt.o: missing/nt.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/nt.c
+x68.o: @srcdir@/missing/x68.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/x68.c
# Prevent GNU make v3 from overflowing arg limit on SysV.
.NOEXPORT:
diff --git a/README b/README
index debf3e4b1c..6583bc889f 100644
--- a/README
+++ b/README
@@ -23,16 +23,7 @@ perl). It is simple, straight-forward, and extensible.
The ruby distribution can be found on
- ftp://ftp.caelum.co.jp/pub/lang/ruby/
-
-** by mail
-
-Send the mail which subject is 'send' to the address below.
-
- ruby-archive@caelum.co.jp
-
-You will receive the uuencoded gzipped tar file of the newest ruby
-distribution.
+ ftp://ftp.netlab.co.jp/pub/lang/ruby/
* How to compile and install
@@ -61,13 +52,13 @@ the error log and machine/OS type, to help others.
* Copying
-Ruby is copyrighted by Yukihiro Matsumoto <matz@caelum.co.jp>.
+Ruby is copyrighted by Yukihiro Matsumoto <matz@ruby.club.co.jp>.
This source is distributed under the conditions blow:
1. You may make and give away verbatim copies of the source form of
the software without restriction, provided that you do not modify
- the original distribution file.
+ the original distribution files.
If you want to distribute the modified version in any way, contact
the author.
@@ -80,11 +71,11 @@ This source is distributed under the conditions blow:
distribute the modified version.
4. You may modify and include the part of the software into any other
- software (possibly commercial). But some files in the
- distribution are not written by the author, so that they are not
- under this terms. They are gc.c(partly),regex.[ch],fnmatch.[ch],
- glob.c, st.[ch] and somme files under ./missing directory. See
- each files for the condition.
+ software (possibly commercial). But some files in the distribution
+ are not written by the author, so that they are not under this terms.
+ They are gc.c(partly),utils.c(partly), regex.[ch],fnmatch.[ch],
+ glob.c, st.[ch] and somme files under the ./missing directory. See
+ each files for the copying condition.
5. The scripts and library files supplied as input to or produced as
output from the software do not automatically fall under the
@@ -101,14 +92,14 @@ This source is distributed under the conditions blow:
The URL of the ruby home-page is:
- http://www.caelum.co.jp/~matz/ruby/index-en.html
+ http://www.netlab.co.jp/ruby/
* The Author
Feel free to send comments and bug reports to the author. Here is the
author's latest mail address:
- matz@ruby.club.or.jp
+ matz@netlab.co.jp
-------------------------------------------------------
created at: Thu Aug 3 11:57:36 JST 1995
diff --git a/README.EXT b/README.EXT
index fdf8c96af7..c2f81d1a7a 100644
--- a/README.EXT
+++ b/README.EXT
@@ -1,49 +1,50 @@
.\" README.EXT - -*- Text -*- created at: Mon Aug 7 16:45:54 JST 1995
-rubyの拡張モジュールの作り方を説明します.
+This document explains how to make extention modules for ruby.
-1.基礎知識
+1.Basic knowledge
-Cの変数には型があり,データには型がありません.ですから,た
-とえばポインタをintの変数に代入すると,その値は整数として取
-り扱われます.逆にrubyの変数には型がなく,データに型がありま
-す.この違いのため,Cとrubyは相互に変換しなければ,お互いの
-データをアクセスできません.
+In C, variables have types and data do not have types. In contrast,
+ruby variables do not have static type and data themselves have
+types. So, data need to be converted across the languages.
+
+Data in ruby represented C type `VALUE'. Each VALUE data have its
+data-type.
rubyのデータはVALUEというCの型で表現されます.VALUE型のデー
タはそのデータタイプを自分で知っています.このデータタイプと
いうのはデータ(オブジェクト)の実際の構造を意味していて,ruby
のクラスとはまた違ったものです.
-VALUEからCにとって意味のあるデータを取り出すためには
+To retrieve an C data from the VALUE, you need to:
+
+ (1) Identify VALUE's data type
+ (2) Convert VALUE into C data
- (1) VALUEのデータタイプを知る
- (2) VALUEをCのデータに変換する
+Converting to wrong data type may cause serious promblems.
-の両方が必要です.(1)を忘れると間違ったデータの変換が行われ
-て,最悪プログラムがcore dumpします.
-1.1 データタイプ
+1.1 Data-types
-rubyにはユーザが使う可能性のある以下のタイプがあります.
+Ruby interpreter has data-types as below:
T_NIL nil
- T_OBJECT 通常のオブジェクト
- T_CLASS クラス
- T_MODULE モジュール
- T_FLOAT 浮動小数点数
- T_STRING 文字列
- T_REGEXP 正規表現
- T_ARRAY 配列
- T_FIXNUM Fixnum(31bit長整数)
- T_HASH 連想配列
- T_STRUCT (rubyの)構造体
- T_BIGNUM 多倍長整数
- T_TRUE 真
- T_FALSE 偽
- T_DATA データ
-
-その他に内部で利用されている以下のタイプがあります.
+ T_OBJECT ordinaly object
+ T_CLASS class
+ T_MODULE module
+ T_FLOAT floating point number
+ T_STRING string
+ T_REGEXP regular expression
+ T_ARRAY array
+ T_FIXNUM Fixnum(31bit integer)
+ T_HASH assosiative array
+ T_STRUCT (ruby) structure
+ T_BIGNUM multi precision integer
+ T_TRUE true
+ T_FALSE false
+ T_DATA data
+
+Otherwise, there are several other types used internally:
T_ICLASS
T_MATCH
@@ -51,41 +52,42 @@ rubyにはユーザが使う可能性のある以下のタイプがあります.
T_SCOPE
T_NODE
-いくつかのタイプはCの構造体で実装されています.
+Most of the types are represented by C structures.
-1.2 VALUEのデータタイプをチェックする
+1.2 Check Data Type of the VALUE
-ruby.hではTYPE()というマクロが定義されていて,VALUEのデータ
-タイプを知ることが出来ます.TYPE()マクロは上で紹介したT_XXXX
-の形式の定数を返します.VALUEのデータタイプに応じて処理する
-場合には,TYPE()の値で分岐することになります.
+The macro TYPE() defined in ruby.h shows data-type of the VALUE.
+TYPE() returns the constant number T_XXXX described above. To handle
+data-types, the code will be like:
switch (TYPE(obj)) {
case T_FIXNUM:
- /* FIXNUMの処理 */
+ /* process Fixnum */
break;
case T_STRING:
- /* 文字列の処理 */
+ /* process String */
break;
case T_ARRAY:
- /* 配列の処理 */
+ /* process Array */
break;
default:
- /* 例外を発生させる */
+ /* raise exception */
Fail("not valid value");
break;
}
-それとデータタイプをチェックして,正しくなければ例外を発生す
-る関数が用意されています.
+There is the data-type check function.
void Check_Type(VALUE value, int type)
-この関数はvalueがtypeで無ければ,例外を発生させます.引数と
-して与えられたVALUEのデータタイプが正しいかどうかチェックす
-るためには,この関数を使います.
+It raises an exception, if the VALUE does not have the type specified.
+
+There are faster check-macros for fixnums and nil.
+
+ FIXNUM_P(obj)
+ NIL_P(obj)
-1.3 VALUEをCのデータに変換する
+1.3 Convert VALUE into C data
データタイプがT_NIL, T_FALSE, T_TRUEである時,データはそれぞ
れnil, FALSE, TRUEです.このデータタイプのオブジェクトはひと
@@ -119,7 +121,7 @@ rubyの構造体を直接アクセスする時に気をつけなければならないこ
ないことです.直接変更した場合,オブジェクトの内容の整合性が
とれなくなって,思わぬバグの原因になります.
-1.4 CのデータをVALUEに変換する
+1.4 Convert C data into VALUE
VALUEの実際の構造は
@@ -151,7 +153,7 @@ FIXNUMに関しては変換マクロを経由する必要があります.Cの整数
INT2NUM()は整数がFIXNUMの範囲に収まらない場合,Bignumに変換
してくれます(が,少し遅い).
-1.5 rubyのデータを操作する
+1.5 Manipulate ruby data
先程も述べた通り,rubyの構造体をアクセスする時に内容の更新を
行うことは勧められません.で,rubyのデータを操作する時には
@@ -160,39 +162,39 @@ rubyが用意している関数を用いてください.
ここではもっとも使われるであろう文字列と配列の生成/操作を行
い関数をあげます(全部ではないです).
- 文字列に対する関数
+ String funtions
str_new(char *ptr, int len)
- 新しいrubyの文字列を生成する.
+ Creates a new ruby string.
str_new2(char *ptr)
- Cの文字列からrubyの文字列を生成する.この関数の機能は
- str_new(ptr, strlen(ptr))と同等である.
+ Creates a new ruby string from C string. This is equivalent to
+ str_new(ptr, strlen(ptr)).
str_cat(VALUE str, char *ptr, int len)
- rubyの文字列strにlenバイトの文字列ptrを追加する.
+ Appends len bytes data from ptr to the ruby string.
- 配列に対する関数
+ Array functions
ary_new()
- 要素が0の配列を生成する.
+ Creates an array with no element.
ary_new2(int len)
- 要素が0の配列を生成する.len要素分の領域をあらかじめ割り
- 当てておく.
+ Creates an array with no element, with allocating internal buffer
+ for len elements.
ary_new3(int n, ...)
- 引数で指定したn要素を含む配列を生成する.
+ Creates an n-elements array from arguments.
- ary_new4(int n, VALUE elts[])
+ ary_new4(int n, VALUE *elts)
- 配列で与えたn要素の配列を生成する.
+ Creates an n-elements array from C array.
ary_push(VALUE ary)
ary_pop(VALUE ary, VALUE val)
@@ -200,17 +202,17 @@ rubyが用意している関数を用いてください.
ary_unshift(VALUE ary, VALUE val)
ary_entry(VALUE ary, int idx)
- Arrayの同名のメソッドと同じ働きをする関数.第1引数は必ず
- 配列でなければならない.
+ Array operations. The first argument to each functions must be an
+ array. They may dump core if other types given.
-2.rubyの機能を使う
+2. Extend ruby with C
原理的にrubyで書けることはCでも書けます.rubyそのものがCで記
述されているんですから,当然といえば当然なんですけど.ここで
はrubyの拡張に使うことが多いだろうと予測される機能を中心に紹
介します.
-2.1 rubyに機能を追加する
+2.1 Add new features to ruby
rubyで提供されている関数を使えばrubyインタプリタに新しい機能
を追加することができます.rubyでは以下の機能を追加する関数が
@@ -222,25 +224,25 @@ rubyで提供されている関数を使えばrubyインタプリタに新しい機能
では順に紹介します.
-2.1.1 クラス/モジュール定義
+2.1.1 Class/module definition
クラスやモジュールを定義するためには,以下の関数を使います.
VALUE rb_define_class(char *name, VALUE super)
- VALUE rb_define_module(char *name)
+ VALUE rb_define_module(char *name)
これらの関数は新しく定義されたクラスやモジュールを返します.
メソッドや定数の定義にこれらの値が必要なので,ほとんどの場合
は戻り値を変数に格納しておく必要があるでしょう.
-2.1.2 メソッド/特異メソッド定義
+2.1.2 Method/singleton method definition
メソッドや特異メソッドを定義するには以下の関数を使います.
void rb_define_method(VALUE class, char *name,
VALUE (*func)(), int argc)
- void rb_define_sigleton_method(VALUE object, char *name,
+ void rb_define_singleton_method(VALUE object, char *name,
VALUE (*func)(), int argc)
@@ -282,10 +284,16 @@ privateメソッドとは関数形式でしか呼び出すことの出来ないメソッ
という形式でも使えます.モジュール関数を定義する関数は以下の
通りです.
- void rb_define_module_method(VALUE module, char *name,
- VALUE (*func)(), int argc)
+ void rb_define_module_function(VALUE module, char *name,
+ VALUE (*func)(), int argc)
+
+関数的メソッド(Kernelモジュールのprivaet method)を定義するた
+めの関数は以下の通りです.
+
+ void rb_define_global_function(char *name, VALUE (*func)(), int argc)
+
-2.1.3 定数定義
+2.1.3 Constant definition
拡張モジュールが必要な定数はあらかじめ定義しておいた方が良い
でしょう.定数を定義する関数は二つあります.
@@ -296,7 +304,7 @@ privateメソッドとは関数形式でしか呼び出すことの出来ないメソッ
前者は特定のクラス/モジュールに属する定数を定義するもの,後
者はグローバルな定数を定義するものです.
-2.2 rubyの機能をCから呼び出す
+2.2 Use ruby features from C
既に『1.5 rubyのデータを操作する』で一部紹介したような関数を
使えば,rubyの機能を実現している関数を直接呼び出すことが出来
@@ -315,9 +323,9 @@ Cからrubyの機能を呼び出すもっとも簡単な方法として,文字列で
VALUE rb_eval_string(char *str)
この評価は現在の環境で行われます.つまり,現在のローカル変数
-やselfなどを受け継ぎます.
+などを受け継ぎます.
-2.2.2 IDまたはシンボル
+2.2.2 ID or Symbol
Cから文字列を経由せずにrubyのメソッドを呼び出すこともできま
す.その前に,rubyインタプリタ内でメソッドや変数名を指定する
@@ -331,9 +339,10 @@ IDとは変数名,メソッド名を表す整数です.rubyの中では
rb_intern(char *name)
-を使います.
+を使います.また一文字の演算子はその文字コードがそのままシン
+ボルになっています.
-2.2.3 Cからrubyのメソッドを呼び出す
+2.2.3 Invoke ruby method from C
Cから文字列を経由せずにrubyのメソッドを呼び出すためには以下
の関数を使います.
@@ -353,7 +362,7 @@ Cから関数を使って参照・更新できるのは,クラス定数,インスタ
りです.
VALUE rb_ivar_get(VALUE obj, ID id)
- VALUE rb_ivar_get(VALUE obj, ID id, VALUE val)
+ VALUE rb_ivar_set(VALUE obj, ID id, VALUE val)
idはrb_intern()で得られるものを使ってください.
@@ -364,24 +373,24 @@ idはrb_intern()で得られるものを使ってください.
クラス定数を新しく定義するためには『2.1.3 定数定義』で紹介さ
れている関数を使ってください.
-3.rubyとCとの情報共有
+3. Informatin sharing between ruby and C
C言語とrubyの間で情報を共有する方法について解説します.
-3.1 Cから参照できるrubyの定数
+3.1 Ruby constant that Cから参照できるrubyの定数
-以下のrubyの定数はCのレベルから参照できる.
+Following ruby constants can be referred from C.
TRUE
FALSE
-真偽値.FALSEはC言語でも偽とみなされる.
+Boolean values. FALSE is false in the C also (i.e. 0).
Qnil
-C言語から見た「nil」.
+Ruby nil in C scope.
-3.2 Cとrubyで共有される大域変数
+3.2 Global variables shared between C and ruby
Cとrubyで大域変数を使って情報を共有できます.共有できる大域
変数にはいくつかの種類があります.そのなかでもっとも良く使わ
@@ -399,18 +408,18 @@ Cとrubyで大域変数を使って情報を共有できます.共有できる大域
void rb_define_readonly_variable(char *name, VALUE *var)
これら変数の他にhookをつけた大域変数を定義できます.hook付き
-の大域変数は以下の関数を用いて定義します.
+の大域変数は以下の関数を用いて定義します.hook付き大域変数の
+値の参照や設定はhookで行う必要があります.
void rb_define_hooked_variable(char *name, VALUE *var,
VALUE (*getter)(), VALUE (*setter)())
この関数はCの関数によってhookのつけられた大域変数を定義しま
す.変数が参照された時には関数getterが,変数に値がセットされ
-た時には関数setterが呼ばれます.hookを指定しない場合はgetter
-やsetterに0を指定してください.
+た時には関数setterが呼ばれる.hookを指定しない場合はgetterや
+setterに0を指定します.
-# getterもsetterも0ならばrb_define_variable()と同じ働きをし
-# ます.
+# getterもsetterも0ならばrb_define_variable()と同じになる.
それから,Cの関数によって実現されるrubyの大域変数を定義する
関数があります.
@@ -421,7 +430,12 @@ Cとrubyで大域変数を使って情報を共有できます.共有できる大域
この関数によって定義されたrubyの大域変数が参照された時には
getterが,変数に値がセットされた時にはsetterが呼ばれます.
-3.3 Cのデータをrubyオブジェクトにする
+The prototypes of the getter and setter functions are as following:
+
+ (*getter)(ID id, void *data, struct global_entry* entry);
+ (*setter)(VALUE val, ID id, void *data, struct global_entry* entry);
+
+3.3 Encapsulate C data into ruby object
Cの世界で定義されたデータ(構造体)をrubyのオブジェクトとして
取り扱いたい場合がありえます.このような場合には,Dataという
@@ -431,41 +445,48 @@ rubyオブジェクトにCの構造体(へのポインタ)をくるむことでruby
Dataオブジェクトを生成して構造体をrubyオブジェクトにカプセル
化するためには,以下のマクロを使います.
- Make_Data_Struct(class, type, mark, free, sval)
+ Data_Wrap_Struct(class,mark,free,ptr)
+
+このマクロの戻り値は生成されたDataオブジェクトです.
-ここでclassは新しく生成されるインスタンスのクラス,,typeは
-カプセル化するCのデータの型(構造体)です.markはこの構造体が
-rubyのオブジェクトへの参照がある時に使う関数です.そのような
-参照を含まない時には0を指定します.freeはこの構造体がもう不
-要になった時に呼ばれる関数です.この関数がガーベージコレクタ
-から呼ばれます.svalはtype型の変数で,Make_Data_Structの中で
-アロケートされます.
+classはこのDataオブジェクトのクラスです.ptrはカプセル化する
+Cの構造体へのポインタです.markはこの構造体がrubyのオブジェ
+クトへの参照がある時に使う関数です.そのような参照を含まない
+時には0を指定します.
-マクロMake_Data_StructはDataオブジェクトを生成して,それを値
-として返します.
+# そのような参照は勧められません.
-このマクロを呼び出すとsvalに構造体がmalloc()されて代入され,
-かつその構造体をカプセル化したDataオブジェクトがインスタンス
-変数としてobjにセットされます.
+freeはこの構造体がもう不要になった時に呼ばれる関数です.この
+関数がガーベージコレクタから呼ばれます.
-DataオブジェクトからCポインタを取り出すためには以下のマクロ
-を使います.
+Cの構造体の割当とDataオブジェクトの生成を同時に行うマクロと
+して以下のものが提供されています.
- Get_Data_Struct(obj, type, sval)
+ Data_Make_Struct(class, type, mark, free, sval)
-Dataオブジェクトからtype型のCポインタを取り出して,svalに代
-入します.
+このマクロの戻り値は生成されたDataオブジェクトです.
+
+class, mark, freeはData_Wrap_Structと同じ働きをします.type
+は割り当てるC構造体の型です.割り当てられた構造体は変数sval
+に代入されます.この変数の型は (type*) である必要があります.
+
+Dataオブジェクトからポインタを取り出すのは以下のマクロを用い
+ます.
+
+ Data_Get_Struct(obj, type, sval)
+
+Cの構造体へのポインタは変数svalに代入されます.
これらのDataの使い方はちょっと分かりにくいので,後で説明する
例題を参照してください.
-4.例題 - dbmパッケージを作る
+4.Example - Create dbm module
ここまでの説明でとりあえず拡張モジュールは作れるはずです.
rubyのextディレクトリにすでに含まれているdbmモジュールを例に
して段階的に説明します.
-(1) ディレクトリを作る
+(1) make the directory
% mkdir ext/dbm
@@ -473,7 +494,7 @@ rubyを展開したディレクトリの下,extディレクトリの中に拡張モ
ジュール用のディレクトリを作ります.名前は適当に選んで構いま
せん.
-(2) MANIFESTファイルを作る
+(2) create MANIFEST file
% cd ext/dbm
% touch MANIFEST
@@ -485,14 +506,14 @@ rubyを展開したディレクトリの下,extディレクトリの中に拡張モ
MANIFESTというファイルは,makeの時にディレクトリが拡張モジュー
ルを含んでいるかどうか判定するために使われれています.
-(3) 設計する
+(3) design the library
まあ,当然なんですけど,どういう機能を実現するかどうかまず設
計する必要があります.どんなクラスをつくるか,そのクラスには
どんなメソッドがあるか,クラスが提供する定数などについて設計
します.dbmクラスについてはext/dbm.docを参照してください.
-(4) Cコードを書く
+(4) write C code.
拡張モジュール本体となるC言語のソースを書きます.C言語のソー
スがひとつの時には「モジュール名.c」を選ぶと良いでしょう.C
@@ -522,34 +543,45 @@ Init_dbm()
/* DBMクラスのメソッド[]: 引数は1個 */
rb_define_method(cDBM, "[]", fdbm_fetch, 1);
:
+
+ /* DBMデータを格納するインスタンス変数名のためのID */
+ id_dbm = rb_intern("dbm");
}
--
DBMモジュールはdbmのデータと対応するオブジェクトになるはずで
すから,Cの世界のdbmをrubyの世界に取り込む必要があります.
-dbm.cではDBMのデータを格納するために以下のような構造体を使っ
-ています.
+dbm.cではData_Make_Structを以下のように使っています.
+
+--
struct dbmdata {
int di_size;
DBM *di_dbm;
};
-RubyのDBMオブジェクトを生成するためには以下のようなコードを
-使っています.
- obj = Make_Data_Struct(class,struct dbmdata,0,free_dbm,dbmp);
- dbmp->di_dbm = dbm;
- dbmp->di_size = -1;
+obj = Data_Make_Struct(class,struct dbmdata,0,free_dbm,dbmp);
+--
+
+ここではdbmstruct構造体へのポインタをDataにカプセル化してい
+ます.DBM*を直接カプセル化しないのはclose()した時の処理を考
+えてのことです.
-DBMオブジェクトからCのDBMポインタを取り出すためには以下のよ
-うなマクロを使っています.
+Dataオブジェクトからdbmstruct構造体のポインタを取り出すため
+に以下のマクロを使っています.
+--
#define GetDBM(obj, dbmp) {\
- Get_Data_Struct(obj, struct dbmdata, dbmp);\
- if (dbmp->di_dbm == 0) closeddbm();\
+ Data_Get_Struct(obj, struct dbmdata, dbmp);\
+ if (dbmp->di_dbm == 0) closed_dbm();\
}
+--
+
+ちょっと複雑なマクロですが,要するにdbmdata構造体のポインタ
+の取り出しと,closeされているかどうかのチェックをまとめてい
+るだけです.
DBMクラスにはたくさんメソッドがありますが,分類すると3種類の
引数の受け方があります.ひとつは引数の数が固定のもので,例と
@@ -623,12 +655,11 @@ fdbm_indexes(obj, args)
rubyと共有はしないがrubyのオブジェクトを格納する可能性のある
Cの大域変数は以下の関数を使ってrubyインタプリタに変数の存在
-を教えてあげてください.でないとGCでトラブルを起こす可能性が
-あります.
+を教えてあげてください.でないとGCでトラブルを起こします.
void rb_global_variable(VALUE *var)
-(5) extconf.rbを用意する
+(5) prepare extconf.rb
もしディレクトリに「extconf.rb」というファイルが存在すれば,
make時に実行されます.なければ適当にMakefileが生成されます.
@@ -642,10 +673,16 @@ extconf.rbはモジュールのコンパイルに必要な条件のチェックなど
have_header(header): ヘッダファイルの存在チェック
create_makefile(target): Makefileの生成
+以下の変数を使うことができます.
+
+ $CFLAGS: コンパイル時に追加的に指定するフラグ(-Iなど)
+ $LDFLAGS: リンク時に追加的に指定するフラグ(-Lなど)
+
モジュールをコンパイルする条件が揃わなず,そのモジュールはコ
-ンパイルしない時にはcreate_makefileを呼ばなければ良い.
+ンパイルしない時にはcreate_makefileを呼ばなければMakefileは
+生成されず,コンパイルも行われません.
-(6) dependを用意する
+(6) prepare depend (optional)
もし,ディレクトリにdependというファイルが存在すれば,
Makefileが依存関係をチェックしてくれます.
@@ -661,25 +698,24 @@ Makefileが依存関係をチェックしてくれます.
*.o, *~など不必要なファイル以外はMANIFESTに追加しておきます.
make時にはMANIFESTの内容は参照しませんので,空のままでも問題
-は起きないんですけど,パッケージングの時に参照することがある
-し,必要なファイルを区別できるんで,用意しておいた方が良いで
-しょう.
+は起きませんが,パッケージングの時に参照することがあるのと,
+必要なファイルを区別できるので,用意しておいた方が良いでしょ
+う.
-(8) makeする
+(8) make
-rubyのディレクトリでmakeを実行するとMakefileを生成してくれま
-す.一度Makefileが生成されれば拡張モジュールのディレクトリの
-中でmakeすることができます.extconf.rbを書き換えるなどして
-Makefileの再生成が必要な時はまたrubyディレクトリでmakeしてく
-ださい.
+rubyのディレクトリでmakeを実行するとMakefileを生成からmake,
+必要によってはそのモジュールのrubyへのリンクまで自動的に実行
+してくれます.extconf.rbを書き換えるなどしてMakefileの再生成
+が必要な時はまたrubyディレクトリでmakeしてください.
-(9) デバッグ
+(9) debug
まあ,デバッグしないと動かないでしょうね.ext/Setupにディレ
クトリ名を書くと静的にリンクするのでデバッガが使えるようにな
ります.その分コンパイルが遅くなりますけど.
-(10) できあがり
+(10) done, now you have the extension module
後はこっそり使うなり,広く公開するなり,売るなり,ご自由にお
使いください.rubyの作者は拡張モジュールに関して一切の権利を
@@ -692,7 +728,7 @@ rubyのソースはいくつかに分類することが出来ます.このうちクラ
ています.これらのソースは今までの説明でほとんど理解できると
思います.
-ruby言語のコア
+coore ruby language
class.c
error.c
@@ -702,7 +738,7 @@ ruby言語のコア
parse.y
variable.c
-ユーティリティ関数
+utility functions
dln.c
fnmatch.c
@@ -711,7 +747,7 @@ ruby言語のコア
st.c
util.c
-rubyコマンドの実装
+ruby interpreter implementation
dmyext.c
inits.c
@@ -719,7 +755,7 @@ rubyコマンドの実装
ruby.c
version.c
-クラスライブラリ
+class library
array.c
bignum.c
@@ -755,23 +791,23 @@ rubyオブジェクトを表現する型.必要に応じてキャストして用いる.
体である.VALUE型をこれらにキャストするためにRで始まる構造体
名を全て大文字にした名前のマクロが用意されている.
-** 変数・定数
+** Variables and constants
Qnil
-定数: nilオブジェクト
+const: nil object
TRUE
-定数: TRUEオブジェクト(真のデフォルト値)
+const: TRUE object(default true value)
FALSE
-定数: FALSEオブジェクト
+const: FALSE object
** Cデータのカプセル化
- VALUE data_new(void *sval, void (*mark)(), void (*free)())
+ Data_Wrap_Struct(VALUE class, void (*mark)(), void (*free)(), void *sval)
Cの任意のポインタをカプセル化したrubyオブジェクトを返す.こ
のポインタがrubyからアクセスされなくなった時,freeで指定した
@@ -779,15 +815,14 @@ Cの任意のポインタをカプセル化したrubyオブジェクトを返す.こ
ジェクトを指している場合,markに指定する関数でマークする必要
がある.
- Make_Data_Struct(obj, iv, type, mark, free, sval)
+ Data_Make_Struct(class, type, mark, free, sval)
type型のメモリをmallocし,変数svalに代入した後,それをカプセ
-ル化したデータをobjのインスタンス変数ivに代入するマクロ.
+ル化したデータを返すマクロ.
- Get_Data_Struct(obj, iv, type, sval)
+ Data_Get_Struct(data, type, sval)
-objのインスタンス変数ivが指すデータからtype型のポインタを取
-り出し変数svalに代入するマクロ.
+dataからtype型のポインタを取り出し変数svalに代入するマクロ.
** クラス/モジュール定義
diff --git a/README.jp b/README.jp
index 06c0832b10..8a100106b1 100644
--- a/README.jp
+++ b/README.jp
@@ -27,22 +27,13 @@ Rubyはテキスト処理関係の能力などに優れ,perlと同じくらい強力
以下の場所においてあります.
- ftp://ftp.caelum.co.jp/pub/lang/ruby/
-
-** メイルで
-
-以下のアドレスに`send'というSubjectのメイルを送って下さい.
-
- ruby-archive@caelum.co.jp
-
-本文には何を書いても構いません.折り返し,最新版のrubyが送っ
-て来ます.
+ ftp://ftp.netlab.co.jp/pub/lang/ruby/
* ホームページ
RubyのホームページのURLは
- http://www.caelum.co.jp/~matz/ruby/
+ http://www.netlab.co.jp/ruby/jp/
です.
@@ -51,7 +42,7 @@ Rubyはテキスト処理関係の能力などに優れ,perlと同じくらい強力
Rubyに関わる話題のためのメイリングリストを開設しました.ア
ドレスは
- ruby-list@caelum.co.jp
+ ruby-list@netlab.co.jp
です.このアドレスにメイルを送れば,自動的に登録されます.
@@ -133,9 +124,9 @@ UNIXであればconfigureがほとんどの差異を吸収してくれるはずで
いかなる目的であれ自由です.ただし,rubyに含まれる他の作
者によるコードは,それぞれの作者の意向による制限が加えら
- れます.具体的にはgc.c(一部),regex.[ch],fnmatch.[ch],
- glob.c, st.[ch]とmissingディレクトリ下のファイル群が該当
- します.
+ れます.具体的にはgc.c(一部),util.c(一部),regex.[ch],
+ fnmatch.[ch],glob.c,st.[ch]と./missingディレクトリ下の
+ ファイル群が該当します.
+ Rubyスクリプトの権利
@@ -151,7 +142,7 @@ UNIXであればconfigureがほとんどの差異を吸収してくれるはずで
* 著者
-コメント,バグレポートその他は matz@ruby.club.or.jp まで.
+コメント,バグレポートその他は matz@netlab.co.jp まで.
-------------------------------------------------------
created at: Thu Aug 3 11:57:36 JST 1995
Local variables:
diff --git a/ToDo b/ToDo
index cfac8981fd..3b6edee08f 100644
--- a/ToDo
+++ b/ToDo
@@ -1,5 +1,4 @@
+* non-blocking open/write for thread
* パッケージまたは大域変数のアクセス制御
* format機能
-* perlのようなsetuid check
-* write debugger for ruby
* re-write regex code for speed and copyright
diff --git a/array.c b/array.c
index 741f09b9b1..c1ad9981c1 100644
--- a/array.c
+++ b/array.c
@@ -20,14 +20,43 @@ VALUE rb_to_a();
void
memclear(mem, size)
- VALUE *mem;
- int size;
+ register VALUE *mem;
+ register int size;
{
while (size--) {
*mem++ = Qnil;
}
}
+#define ARY_FREEZE FL_USER1
+
+static void
+ary_modify(ary)
+ VALUE ary;
+{
+ rb_secure(5);
+ if (FL_TEST(ary, ARY_FREEZE)) {
+ TypeError("can't modify frozen array");
+ }
+}
+
+VALUE
+ary_freeze(ary)
+ VALUE ary;
+{
+ FL_SET(ary, ARY_FREEZE);
+ return ary;
+}
+
+static VALUE
+ary_frozen_p(ary)
+ VALUE ary;
+{
+ if (FL_TEST(ary, ARY_FREEZE))
+ return TRUE;
+ return FALSE;
+}
+
VALUE
ary_new2(len)
int len;
@@ -148,12 +177,13 @@ ary_s_create(argc, argv, class)
return (VALUE)ary;
}
-static void
-astore(ary, idx, val)
+void
+ary_store(ary, idx, val)
struct RArray *ary;
int idx;
VALUE val;
{
+ ary_modify(ary);
if (idx < 0) {
IndexError("negative index for array");
}
@@ -177,7 +207,7 @@ ary_push(ary, item)
struct RArray *ary;
VALUE item;
{
- astore(ary, ary->len, item);
+ ary_store(ary, ary->len, item);
return (VALUE)ary;
}
@@ -188,7 +218,7 @@ ary_push_method(argc, argv, ary)
struct RArray *ary;
{
while (argc--) {
- astore(ary, ary->len, *argv++);
+ ary_store(ary, ary->len, *argv++);
}
return (VALUE)ary;
}
@@ -231,6 +261,7 @@ ary_unshift(ary, item)
struct RArray *ary;
int item;
{
+ ary_modify(ary);
if (ary->len >= ary->capa) {
ary->capa+=ARY_DEFAULT_SIZE;
REALLOC_N(ary->ptr, VALUE, ary->capa);
@@ -243,18 +274,6 @@ ary_unshift(ary, item)
return ary->ptr[0] = item;
}
-static VALUE
-ary_unshift_method(argc, argv, ary)
- int argc;
- VALUE *argv;
- VALUE ary;
-{
- while (argc--) {
- ary_unshift(ary, argv[argc]);
- }
- return (VALUE)ary;
-}
-
VALUE
ary_entry(ary, offset)
struct RArray *ary;
@@ -402,7 +421,7 @@ ary_indexes(ary, args)
p = args->ptr; pend = p + args->len;
while (p < pend) {
- astore(new_ary, i++, ary_entry(ary, NUM2INT(*p)));
+ ary_store(new_ary, i++, ary_entry(ary, NUM2INT(*p)));
p++;
}
return new_ary;
@@ -413,6 +432,7 @@ ary_replace(ary, beg, len, rpl)
struct RArray *ary, *rpl;
int beg, len;
{
+ ary_modify(ary);
if (TYPE(rpl) != T_ARRAY) {
rpl = (struct RArray*)rb_to_a(rpl);
}
@@ -490,11 +510,11 @@ ary_aset(argc, argv, ary)
if (offset < 0) {
offset = ary->len + offset;
}
- astore(ary, offset, arg2);
+ ary_store(ary, offset, arg2);
return arg2;
}
-static VALUE
+VALUE
ary_each(ary)
struct RArray *ary;
{
@@ -519,6 +539,18 @@ ary_each_index(ary)
}
static VALUE
+ary_reverse_each(ary)
+ struct RArray *ary;
+{
+ int len = ary->len;
+
+ while (len--) {
+ rb_yield(ary->ptr[len]);
+ }
+ return Qnil;
+}
+
+static VALUE
ary_length(ary)
struct RArray *ary;
{
@@ -575,6 +607,7 @@ ary_join(ary, sep)
}
if (!NIL_P(sep)) str_cat(result, sep->ptr, sep->len);
str_cat(result, RSTRING(tmp)->ptr, RSTRING(tmp)->len);
+ if (str_tainted(tmp)) str_taint(result);
}
return result;
@@ -590,9 +623,7 @@ ary_join_method(argc, argv, ary)
rb_scan_args(argc, argv, "01", &sep);
if (NIL_P(sep)) sep = OFS;
-
- if (!NIL_P(sep))
- Check_Type(sep, T_STRING);
+ if (!NIL_P(sep)) Check_Type(sep, T_STRING);
return ary_join(ary, sep);
}
@@ -628,7 +659,6 @@ ary_inspect(ary)
{
int i, len;
VALUE s, str;
- char *p;
if (ary->len == 0) return str_new2("[]");
str = str_new2("[");
@@ -707,6 +737,13 @@ sort_2(a, b)
{
VALUE retval;
+ if (FIXNUM_P(*a)) {
+ if (FIXNUM_P(*b)) return *a - *b;
+ }
+ else if (TYPE(*a) == T_STRING) {
+ if (TYPE(*b) == T_STRING) return str_cmp(*a, *b);
+ }
+
retval = rb_funcall(*a, cmp, 1, *b);
return NUM2INT(retval);
}
@@ -715,6 +752,7 @@ VALUE
ary_sort_bang(ary)
struct RArray *ary;
{
+ ary_modify(ary);
qsort(ary->ptr, ary->len, sizeof(VALUE), iterator_p()?sort_1:sort_2);
return (VALUE)ary;
}
@@ -726,13 +764,14 @@ ary_sort(ary)
return ary_sort_bang(ary_clone(ary));
}
-static VALUE
+VALUE
ary_delete(ary, item)
struct RArray *ary;
VALUE item;
{
int i1, i2;
+ ary_modify(ary);
for (i1 = i2 = 0; i1 < ary->len; i1++) {
if (rb_equal(ary->ptr[i1], item)) continue;
if (i1 != i2) {
@@ -741,13 +780,14 @@ ary_delete(ary, item)
i2++;
}
if (ary->len == i2) {
- if (iterator_p()) rb_yield(Qnil);
+ if (iterator_p()) rb_yield(item);
+ return Qnil;
}
else {
ary->len = i2;
}
- return (VALUE)ary;
+ return item;
}
VALUE
@@ -758,6 +798,7 @@ ary_delete_at(ary, at)
int i1, i2, pos;
VALUE del = Qnil;
+ ary_modify(ary);
pos = NUM2INT(at);
for (i1 = i2 = 0; i1 < ary->len; i1++) {
if (i1 == pos) {
@@ -780,6 +821,7 @@ ary_delete_if(ary)
{
int i1, i2;
+ ary_modify(ary);
for (i1 = i2 = 0; i1 < ary->len; i1++) {
if (rb_yield(ary->ptr[i1])) continue;
if (i1 != i2) {
@@ -792,6 +834,21 @@ ary_delete_if(ary)
return (VALUE)ary;
}
+#if 0
+static VALUE
+ary_replace(ary)
+ struct RArray *ary;
+{
+ int i;
+
+ for (i = 0; i < ary->len; i++) {
+ ary->ptr[i] = rb_yield(ary->ptr[i]);
+ }
+
+ return (VALUE)ary;
+}
+#endif
+
static VALUE
ary_clear(ary)
struct RArray *ary;
@@ -871,7 +928,6 @@ VALUE
ary_concat(x, y)
struct RArray *x, *y;
{
- struct RArray *z;
VALUE *p, *pend;
if (TYPE(y) != T_ARRAY) {
@@ -881,7 +937,7 @@ ary_concat(x, y)
p = y->ptr;
pend = p + y->len;
while (p < pend) {
- astore(x, x->len, *p);
+ ary_store(x, x->len, *p);
p++;
}
return (VALUE)x;
@@ -903,6 +959,10 @@ ary_times(ary, times)
ary2 = (struct RArray*)ary_new2(len);
ary2->len = len;
+ if (len < 0) {
+ ArgError("negative argument");
+ }
+
for (i=0; i<len; i+=ary->len) {
MEMCPY(ary2->ptr+i, ary->ptr, VALUE, ary->len);
}
@@ -962,21 +1022,34 @@ ary_equal(ary1, ary2)
}
static VALUE
+ary_eql(ary1, ary2)
+ struct RArray *ary1, *ary2;
+{
+ int i;
+
+ if (TYPE(ary2) != T_ARRAY) return FALSE;
+ if (ary1->len != ary2->len) return FALSE;
+ for (i=0; i<ary1->len; i++) {
+ if (!rb_eql(ary1->ptr[i], ary2->ptr[i]))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static VALUE
ary_hash(ary)
struct RArray *ary;
{
- int i, h;
- ID hash = rb_intern("hash");
+ int h, i;
- h = 0;
+ h = ary->len;
for (i=0; i<ary->len; i++) {
- h ^= rb_funcall(ary->ptr[i], hash, 0);
+ h ^= rb_hash(ary->ptr[i]);
}
- h += ary->len;
return INT2FIX(h);
}
-static VALUE
+VALUE
ary_includes(ary, item)
struct RArray *ary;
VALUE item;
@@ -1055,6 +1128,7 @@ ary_compact_bang(ary)
{
VALUE *p, *t, *end;
+ ary_modify(ary);
p = t = ary->ptr;
end = p + ary->len;
while (t < end) {
@@ -1104,10 +1178,13 @@ Init_Array()
rb_define_method(cArray, "inspect", ary_inspect, 0);
rb_define_method(cArray, "to_a", ary_to_a, 0);
- rb_define_method(cArray, "print_on", ary_print_on, 1);
+ rb_define_method(cArray, "freeze", ary_freeze, 0);
+ rb_define_method(cArray, "frozen?", ary_frozen_p, 0);
rb_define_method(cArray, "==", ary_equal, 1);
+ rb_define_method(cArray, "eql?", ary_eql, 1);
rb_define_method(cArray, "hash", ary_hash, 0);
+
rb_define_method(cArray, "[]", ary_aref, -1);
rb_define_method(cArray, "[]=", ary_aset, -1);
rb_define_method(cArray, "concat", ary_concat, 1);
@@ -1115,9 +1192,10 @@ Init_Array()
rb_define_method(cArray, "push", ary_push_method, -1);
rb_define_method(cArray, "pop", ary_pop, 0);
rb_define_method(cArray, "shift", ary_shift, 0);
- rb_define_method(cArray, "unshift", ary_unshift_method, -1);
+ rb_define_method(cArray, "unshift", ary_unshift, 1);
rb_define_method(cArray, "each", ary_each, 0);
rb_define_method(cArray, "each_index", ary_each_index, 0);
+ rb_define_method(cArray, "reverse_each", ary_reverse_each, 0);
rb_define_method(cArray, "length", ary_length, 0);
rb_define_alias(cArray, "size", "length");
rb_define_method(cArray, "empty?", ary_empty_p, 0);
@@ -1132,10 +1210,12 @@ Init_Array()
rb_define_method(cArray, "delete", ary_delete, 1);
rb_define_method(cArray, "delete_at", ary_delete_at, 1);
rb_define_method(cArray, "delete_if", ary_delete_if, 0);
+#if 0
+ rb_define_method(cArray, "replace", ary_replace, 0);
+#endif
rb_define_method(cArray, "clear", ary_clear, 0);
rb_define_method(cArray, "fill", ary_fill, -1);
rb_define_method(cArray, "include?", ary_includes, 1);
- rb_define_method(cArray, "includes?", ary_includes, 1); /* obsolate */
rb_define_method(cArray, "assoc", ary_assoc, 1);
rb_define_method(cArray, "rassoc", ary_rassoc, 1);
diff --git a/bignum.c b/bignum.c
index e3bd528e72..8af40d6731 100644
--- a/bignum.c
+++ b/bignum.c
@@ -65,9 +65,17 @@ big_2comp(x) /* get 2's complement */
ds[i++] = BIGLO(num);
num = BIGDN(num);
} while (i < x->len);
+ if (ds[0] == 1 || ds[0] == 0) {
+ for (i=1;i<x->len;i++) {
+ if (ds[i] != 0) return;
+ }
+ REALLOC_N(BDIGITS(x), USHORT, x->len++);
+ ds = BDIGITS(x);
+ ds[x->len-1] = 1;
+ }
}
-VALUE
+static VALUE
bignorm(x)
struct RBignum *x;
{
@@ -150,7 +158,7 @@ int2inum(n)
VALUE
str2inum(str, base)
- char *str;
+ UCHAR *str;
int base;
{
char sign = 1, c;
@@ -189,7 +197,7 @@ str2inum(str, base)
}
if (len <= (sizeof(VALUE)*CHAR_BIT)) {
- UINT val = strtoul(str, 0, base);
+ UINT val = strtoul((char*)str, 0, base);
if (POSFIXABLE(val)) {
if (sign) return INT2FIX(val);
@@ -256,7 +264,7 @@ big2str(x, base)
USHORT *ds;
UINT i, j, hbase;
VALUE ss;
- char *s, c;
+ UCHAR *s, c;
if (FIXNUM_P(x)) {
return fix2str(x, base);
@@ -431,6 +439,14 @@ big_cmp(x, y)
}
static VALUE
+big_eq(x, y)
+ VALUE x, y;
+{
+ if (big_cmp(x, y) == INT2FIX(0)) return TRUE;
+ return FALSE;
+}
+
+static VALUE
big_uminus(x)
struct RBignum *x;
{
@@ -487,35 +503,20 @@ bigsub(x, y)
z = (struct RBignum*)bignew(x->len, (z == 0)?1:0);
zds = BDIGITS(z);
- i = x->len;
- while (i--) zds[i] = BDIGITS(x)[i];
-
- i = 0; num = 0;
- do {
- num += (long)zds[i] - BDIGITS(y)[i];
- if (num < 0) {
- zds[i] = num + BIGRAD;
- num = -1;
- }
- else {
- zds[i] = BIGLO(num);
- num = 0;
- }
- } while (++i < y->len);
- if (num) {
- while (num && i < x->len) {
- num += zds[i];
- if (num < 0) {
- zds[i++] = num + BIGRAD;
- num = -1;
- }
- else {
- zds[i++] = BIGLO(num);
- num = 0;
- }
- }
+ for (i = 0, num = 0; i < y->len; i++) {
+ num += (long)BDIGITS(x)[i] - BDIGITS(y)[i];
+ zds[i] = BIGLO(num);
+ num = BIGDN(num);
+ }
+ while (num && i < x->len) {
+ num += BDIGITS(x)[i];
+ zds[i++] = BIGLO(num);
+ num = BIGDN(num);
}
-
+ while (i < x->len) {
+ zds[i++] = BDIGITS(x)[i];
+ }
+
return bignorm(z);
}
@@ -525,10 +526,8 @@ bigadd(x, y, sign)
char sign;
{
struct RBignum *z;
- USHORT *zds;
long num;
UINT i, len;
-
if (x->sign == (y->sign ^ sign)) {
if (y->sign == sign) return bigsub(y, x);
return bigsub(x, y);
@@ -541,27 +540,24 @@ bigadd(x, y, sign)
len = y->len + 1;
}
z = (struct RBignum*)bignew(len, sign==y->sign);
- zds = BDIGITS(z);
-
- i = len;
- while (i--) zds[i] = 0;
- i = y->len;
- while (i--) zds[i] = BDIGITS(y)[i];
- i = 0; num = 0;
- do {
- num += (long)zds[i] + BDIGITS(x)[i];
- zds[i++] = BIGLO(num);
- num = BIGDN(num);
- } while (i < x->len);
- if (num) {
- while (i < y->len) {
- num += zds[i];
- zds[i++] = BIGLO(num);
- num = BIGDN(num);
- }
- BDIGITS(z)[i] = num;
+ if (x->len > y->len) {
+ struct RBignum* t = x; x = y; y = t;
+ }
+ for (i = 0, num = 0; i < x->len; i++) {
+ num += (long)(BDIGITS(x)[i]) + BDIGITS(y)[i];
+ BDIGITS(z)[i] = BIGLO(num);
+ num = BIGDN(num);
}
+ while (num && i < y->len) {
+ num += BDIGITS(y)[i];
+ BDIGITS(z)[i++] = BIGLO(num);
+ num = BIGDN(num);
+ }
+ while (i < y->len) {
+ BDIGITS(z)[i++] = BDIGITS(y)[i];
+ }
+ BDIGITS(z)[i] = num;
return bignorm(z);
}
@@ -570,8 +566,6 @@ VALUE
big_plus(x, y)
VALUE x, y;
{
- VALUE z;
-
switch (TYPE(y)) {
case T_FIXNUM:
y = int2big(FIX2INT(y));
@@ -591,8 +585,6 @@ VALUE
big_minus(x, y)
VALUE x, y;
{
- VALUE cmp;
-
switch (TYPE(y)) {
case T_FIXNUM:
y = int2big(FIX2INT(y));
@@ -637,20 +629,20 @@ big_mul(x, y)
z = bignew(j, x->sign==y->sign);
zds = BDIGITS(z);
while (j--) zds[j] = 0;
- do {
- j = 0;
- if (BDIGITS(x)[i]) {
- do {
- n += zds[i + j] + ((unsigned long)BDIGITS(x)[i]*BDIGITS(y)[j]);
- zds[i + j++] = BIGLO(n);
- n = BIGDN(n);
- } while (j < y->len);
- if (n) {
- zds[i + j] = n;
- n = 0;
- }
+ for (i = 0; i < x->len; i++) {
+ unsigned long dd = BDIGITS(x)[i];
+ if (dd == 0) continue;
+ n = 0;
+ for (j = 0; j < y->len; j++) {
+ int ee = n + dd * BDIGITS(y)[j];
+ n = zds[i + j] + ee;
+ if (ee) zds[i + j] = BIGLO(n);
+ n = BIGDN(n);
}
- } while (++i < x->len);
+ if (n) {
+ zds[i + j] = n;
+ }
+ }
return bignorm(z);
}
@@ -669,7 +661,7 @@ bigdivmod(x, y, div, mod)
yds = BDIGITS(y);
if (ny == 0 && yds[0] == 0) num_zerodiv();
- if (nx < ny) {
+ if (nx < ny || nx == ny && BDIGITS(x)[nx - 1] < BDIGITS(y)[ny - 1]) {
if (div) *div = INT2FIX(0);
if (mod) *mod = bignorm(x);
return;
@@ -680,7 +672,7 @@ bigdivmod(x, y, div, mod)
z = big_clone(x);
zds = BDIGITS(z);
t2 = 0; i = nx;
- while(i--) {
+ while (i--) {
t2 = BIGUP(t2) + zds[i];
zds[i] = t2 / dd;
t2 %= dd;
@@ -728,24 +720,21 @@ bigdivmod(x, y, div, mod)
if (q) {
i = 0; num = 0; t2 = 0;
do { /* multiply and subtract */
+ int ee;
t2 += (unsigned long)yds[i] * q;
- num += zds[j - ny + i] - BIGLO(t2);
- if (num < 0) {
- zds[j - ny + i] = num + BIGRAD;
- num = -1;
- }
- else {
- zds[j - ny + i] = num;
- num = 0;
- }
+ ee = num - BIGLO(t2);
+ num = zds[j - ny + i] + ee;
+ if (ee) zds[j - ny + i] = BIGLO(num);
+ num = BIGDN(num);
t2 = BIGDN(t2);
} while (++i < ny);
num += zds[j - ny + i] - t2; /* borrow from high digit; don't update */
while (num) { /* "add back" required */
i = 0; num = 0; q--;
do {
- num += (long) zds[j - ny + i] + yds[i];
- zds[j - ny + i] = BIGLO(num);
+ int ee = num + yds[i];
+ num = (long) zds[j - ny + i] + ee;
+ if (ee) zds[j - ny + i] = BIGLO(num);
num = BIGDN(num);
} while (++i < ny);
num--;
@@ -1241,6 +1230,8 @@ Init_Bignum()
rb_define_method(cBignum, "[]", big_aref, 1);
rb_define_method(cBignum, "<=>", big_cmp, 1);
+ rb_define_method(cBignum, "==", big_eq, 1);
+ rb_define_method(cBignum, "eql?", big_eq, 1);
rb_define_method(cBignum, "hash", big_hash, 0);
rb_define_method(cBignum, "to_i", big_to_i, 0);
rb_define_method(cBignum, "to_f", big_to_f, 0);
diff --git a/class.c b/class.c
index 645d295c19..6cb55fa240 100644
--- a/class.c
+++ b/class.c
@@ -28,6 +28,8 @@ class_new(super)
OBJSETUP(cls, cClass, T_CLASS);
cls->super = super;
+ cls->iv_tbl = 0;
+ cls->m_tbl = 0; /* safe GC */
cls->m_tbl = new_idhash();
return (VALUE)cls;
@@ -66,6 +68,8 @@ singleton_class_clone(class)
CLONESETUP(clone, class);
clone->super = class->super;
+ clone->iv_tbl = 0;
+ clone->m_tbl = 0;
clone->m_tbl = new_idhash();
st_foreach(class->m_tbl, clone_method, clone->m_tbl);
FL_SET(clone, FL_SINGLETON);
@@ -128,6 +132,8 @@ module_new()
OBJSETUP(mdl, cModule, T_MODULE);
mdl->super = 0;
+ mdl->iv_tbl = 0;
+ mdl->m_tbl = 0;
mdl->m_tbl = new_idhash();
return (VALUE)mdl;
@@ -197,7 +203,7 @@ include_class_new(module, super)
void
rb_include_module(class, module)
- struct RClass *class, *module;
+ VALUE class, module;
{
struct RClass *p;
@@ -216,18 +222,14 @@ rb_include_module(class, module)
while (module) {
/* ignore if the module included already in superclasses */
- for (p = class->super; p; p = p->super) {
- if (BUILTIN_TYPE(p) == T_ICLASS && p->m_tbl == module->m_tbl)
+ for (p = RCLASS(class)->super; p; p = p->super) {
+ if (BUILTIN_TYPE(p) == T_ICLASS && p->m_tbl == RCLASS(module)->m_tbl)
return;
}
- if (verbose) {
- rb_const_check(class, module);
- }
-
- class->super = include_class_new(module, class->super);
- class = class->super;
- module = module->super;
+ RCLASS(class)->super = include_class_new(module, RCLASS(class)->super);
+ class = (VALUE)RCLASS(class)->super;
+ module = (VALUE)RCLASS(module)->super;
}
}
@@ -243,7 +245,7 @@ rb_define_method_id(class, name, func, argc)
void
rb_define_method(class, name, func, argc)
- struct RClass *class;
+ VALUE class;
char *name;
VALUE (*func)();
int argc;
@@ -253,7 +255,7 @@ rb_define_method(class, name, func, argc)
void
rb_undef_method(class, name)
- struct RClass *class;
+ VALUE class;
char *name;
{
rb_add_method(class, rb_intern(name), 0, NOEX_PUBLIC);
@@ -273,6 +275,9 @@ VALUE
rb_singleton_class(obj)
struct RBasic *obj;
{
+ if (rb_special_const_p((VALUE)obj)) {
+ TypeError("cannot define singleton");
+ }
if (FL_TEST(obj->class, FL_SINGLETON)) {
return (VALUE)obj->class;
}
@@ -300,9 +305,20 @@ rb_define_module_function(module, name, func, argc)
rb_define_singleton_method(module, name, func, argc);
}
+VALUE mKernel;
+
+void
+rb_define_global_function(name, func, argc)
+ char *name;
+ VALUE (*func)();
+ int argc;
+{
+ rb_define_private_method(mKernel, name, func, argc);
+}
+
void
rb_define_alias(class, name1, name2)
- struct RClass *class;
+ VALUE class;
char *name1, *name2;
{
rb_alias(class, rb_intern(name1), rb_intern(name2));
@@ -310,7 +326,7 @@ rb_define_alias(class, name1, name2)
void
rb_define_attr(class, id, pub)
- struct RClass *class;
+ VALUE class;
ID id;
int pub;
{
@@ -325,10 +341,10 @@ rb_define_attr(class, id, pub)
attreq = rb_intern(buf);
sprintf(buf, "@%s", name);
attriv = rb_intern(buf);
- if (!rb_method_boundp(class, attr)) {
+ if (!rb_method_boundp(class, attr, NOEX_PRIVATE)) {
rb_add_method(class, attr, NEW_IVAR(attriv), 0);
}
- if (pub && !rb_method_boundp(class, attreq)) {
+ if (pub && !rb_method_boundp(class, attreq, NOEX_PRIVATE)) {
rb_add_method(class, attreq, NEW_ATTRSET(attriv), 0);
}
}
diff --git a/config.dj b/config.dj
index 13f4e6ddb6..8ad3883380 100644
--- a/config.dj
+++ b/config.dj
@@ -32,4 +32,5 @@
#define FILE_COUNT _cnt
#define DLEXT ".so"
#define RUBY_LIB ";/usr/local/lib/ruby;."
-#define RUBY_ARCHLIB "/usr/local/lib/ruby/i386-msdos"
+#define RUBY_ARCHLIB "/usr/local/lib/ruby/i386-djgpp"
+#define RUBY_PLATFORM "i386-djgpp"
diff --git a/config.guess b/config.guess
index ce6e12a8fd..ea28434e58 100755
--- a/config.guess
+++ b/config.guess
@@ -35,6 +35,17 @@
# (but try to keep the structure clean).
#
+# Modified for Human68k by K.Okabe 1997.07.09
+# Last change: 1997.07.09
+
+case "$KSH_VERSION" in
+*X6*)
+ echo m68k-sharp-human
+ exit 0 ;;
+*)
+ ;;
+esac
+
# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
# (ghazi@noc.rutgers.edu 8/24/94.)
if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
@@ -322,6 +333,9 @@ EOF
*:NetBSD:*:*)
echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
exit 0 ;;
+ *:*:*BOW*:*)
+ echo i386-pc-bow
+ exit 0 ;;
i*:CYGWIN*:*)
echo i386-pc-cygwin32
exit 0 ;;
@@ -417,16 +431,40 @@ EOF
mc68*:A/UX:*:*)
echo m68k-apple-aux${UNAME_RELEASE}
exit 0 ;;
- R3000:*System_V*:*:*)
+ X680[02346]0:Human68k:*:*)
+ echo m68k-sharp-human
+ exit 0 ;;
+ R[34]000:*System_V*:*:*)
if [ -d /usr/nec ]; then
echo mips-nec-sysv${UNAME_RELEASE}
else
echo mips-unknown-sysv${UNAME_RELEASE}
fi
exit 0 ;;
+ R[34]???:UNIX_SV:4.?MP:*)
+ if [ -x /sbin/uversion ]; then
+ UVERSION_RELEASE=`(/sbin/uversion -r) 2>/dev/null` \
+ || UVERSION_RELEASE=unknown
+ UVERSION_SYSTEM=`(/sbin/uversion -s) 2>/dev/null` \
+ || UVERSION_SYSTEM=unknown
+ case "${UVERSION_RELEASE}:${UVERSION_SYSTEM}" in
+ Release*:EWS4800/*)
+ suffix=`echo ${UNAME_RELEASE} | tr '[A-Z]' '[a-z]'`
+ suffix=${suffix}r`echo ${UVERSION_RELEASE} | \
+ sed -e 's/Release//' -e 's/ Rev.*$//'`
+ echo mips-nec-sysv${suffix}
+ exit 0 ;;
+ esac
+ fi;;
+ *:machten:*:*)
+ echo ${UNAME_MACHINE}-apple-machten
+ exit 0 ;;
powerpc:JCC_BSD+:*:*)
echo powerpc-jcc-bsd4.4
exit 0 ;;
+ DS/90*:*:*:V20*)
+ echo sparc-fujitsu-uxpds
+ exit 0 ;;
esac
#echo '(No uname command or uname output not recognized.)' 1>&2
@@ -526,12 +564,16 @@ main ()
printf ("i860-alliant-bsd\n"); exit (0);
#endif
+#if defined (__human68k__) || defined (HUMAN68K)
+ printf ("m68k-sharp-human\n"); exit (0);
+#endif
+
exit (1);
}
EOF
-${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0
-rm -f dummy.c dummy
+${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy.x dummy && exit 0
+rm -f dummy.c dummy.x dummy
# Apollos put the system type in the environment.
diff --git a/config.sub b/config.sub
index 27819cc8dc..9dec8e3c13 100755
--- a/config.sub
+++ b/config.sub
@@ -634,6 +634,10 @@ case $basic_machine in
orion105)
basic_machine=clipper-highlevel
;;
+ human)
+ basic_machine=m68k-sharp
+ os=-human
+ ;;
*)
echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
exit 1
@@ -687,7 +691,7 @@ case $os in
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
| -cygwin32* | -pe* | -psos* | -moss* | -proelf* \
- | -linux*)
+ | -linux* | -bow*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-sunos5*)
@@ -745,6 +749,11 @@ case $os in
-xenix)
os=-xenix
;;
+ -uxpds)
+ os=-uxpds
+ ;;
+ -human)
+ ;;
-none)
;;
*)
diff --git a/configure.in b/configure.in
index 7f89f5e69c..699ca1eed3 100644
--- a/configure.in
+++ b/configure.in
@@ -1,9 +1,6 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT(ruby.h)
-PROGS="ruby"
-AC_SUBST(PROGS)dnl
-
dnl checks for alternative programs
AC_ARG_WITH(gcc, [--without-gcc never use gcc], [
case $withval in
@@ -31,11 +28,15 @@ if test $rb_thread = yes; then
fi
AC_CANONICAL_HOST
+AC_ARG_PROGRAM
dnl Checks for programs.
AC_PROG_CC
AC_PROG_GCC_TRADITIONAL
AC_PROG_YACC
+AC_PROG_RANLIB
+AC_SUBST(AR)
+AC_CHECK_PROGS(AR, ar aal, ar)
AC_PROG_INSTALL
AC_PROG_MAKE_SET
@@ -43,6 +44,11 @@ AC_PROG_MAKE_SET
AC_MINIX
dnl Checks for libraries.
+case "$host_os" in
+nextstep*) ;;
+human*) ;;
+*) LIBS="-lm $LIBS";;
+esac
AC_CHECK_LIB(crypt, crypt)
AC_CHECK_LIB(dl, dlopen) # Dynamic linking for SunOS/Solaris and SYSV
AC_CHECK_LIB(dld, shl_load) # Dynamic linking for HP-UX
@@ -50,15 +56,17 @@ AC_CHECK_LIB(dld, shl_load) # Dynamic linking for HP-UX
dnl Checks for header files.
AC_HEADER_DIRENT
AC_HEADER_STDC
-AC_CHECK_HEADERS(unistd.h limits.h sys/file.h sys/ioctl.h pwd.h sys/select.h\
- sys/time.h sys/times.h sys/param.h sys/wait.h\
+AC_CHECK_HEADERS(stdlib.h unistd.h limits.h sys/file.h sys/ioctl.h pwd.h \
+ sys/select.h sys/time.h sys/times.h sys/param.h sys/wait.h\
syscall.h a.out.h string.h utime.h memory.h)
dnl Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_UID_T
AC_TYPE_SIZE_T
AC_STRUCT_ST_BLKSIZE
+save_LIBOJBS="$LIBOBJS"
AC_STRUCT_ST_BLOCKS
+LIBOBJS="$save_LIBOBJS"
AC_STRUCT_ST_RDEV
dnl Checks for library functions.
@@ -66,12 +74,13 @@ AC_TYPE_GETGROUPS
AC_TYPE_SIGNAL
AC_FUNC_ALLOCA
AC_FUNC_VFORK
-AC_REPLACE_FUNCS(dup2 setenv memmove mkdir strerror strftime\
+AC_REPLACE_FUNCS(dup2 setenv memmove mkdir strcasecmp strerror strftime\
strstr strtoul strdup strcasecmp crypt flock)
AC_CHECK_FUNCS(fmod killpg random wait4 waitpid syscall getcwd\
truncate chsize times utimes fcntl lockf setitimer\
setruid seteuid setreuid setrgid setegid setregid\
- getgroups getpgid getpriority dlopen sigprocmask sigaction)
+ setpgrp2 getpgid getgroups getpriority\
+ dlopen sigprocmask sigaction _setjmp)
if test "$ac_cv_func_strftime" = no; then
AC_STRUCT_TIMEZONE
AC_TRY_LINK([],
@@ -83,18 +92,18 @@ if test "$ac_cv_func_sigprocmask" = yes && test "$ac_cv_func_sigaction" = yes; t
else
AC_MSG_CHECKING(for BSD signal semantics)
AC_CACHE_VAL(rb_cv_bsd_signal,
- [AC_TRY_RUN([
+ [AC_TRY_RUN([
#include <stdio.h>
#include <signal.h>
-void sig_handler(dummy)
+void
+sig_handler(dummy)
int dummy;
{
}
-int main(argc, argv)
- int argc;
- char ** argv;
+int
+main()
{
signal(SIGINT, sig_handler);
kill(getpid(), SIGINT);
@@ -103,14 +112,38 @@ int main(argc, argv)
}
],
rb_cv_bsd_signal=yes,
- rb_cv_bsd_signal=no,
- [:])])
+ rb_cv_bsd_signal=no)])
AC_MSG_RESULT($rb_cv_bsd_signal)
if test "$rb_cv_bsd_signal" = yes; then
AC_DEFINE(BSD_SIGNAL)
fi
fi
+if test "$ac_cv_func_setpgrp2" = yes; then
+ AC_DEFINE(BSD_GETPGRP, getpgrp2)
+ AC_DEFINE(BSD_SETPGRP, setpgrp2)
+else
+ AC_MSG_CHECKING(whether getpgrp() has arg)
+ AC_CACHE_VAL(rb_cv_bsdgetpgrp,
+ [AC_TRY_COMPILE([#include <unistd.h>], [getpgrp(0);],
+ rb_cv_bsdgetpgrp=yes,
+ rb_cv_bsdgetpgrp=no)])
+ AC_MSG_RESULT($rb_cv_bsdgetpgrp)
+ if test "$rb_cv_bsdgetpgrp" = yes; then
+ AC_DEFINE(BSD_GETPGRP, getpgrp)
+ fi
+
+ AC_MSG_CHECKING(whether setpgrp() has args)
+ AC_CACHE_VAL(rb_cv_bsdsetpgrp,
+ [AC_TRY_COMPILE([#include <unistd.h>], [setpgrp(1, 1);],
+ rb_cv_bsdsetpgrp=yes,
+ rb_cv_bsdsetpgrp=no)])
+ AC_MSG_RESULT($rb_cv_bsdsetpgrp)
+ if test "$rb_cv_bsdsetpgrp" = yes; then
+ AC_DEFINE(BSD_SETPGRP, setpgrp)
+ fi
+fi
+
AC_C_BIGENDIAN
AC_CHAR_UNSIGNED
@@ -183,6 +216,7 @@ main() {
AC_MSG_RESULT($rb_cv_linux_elf)
if test "$rb_cv_linux_elf" = no; then
with_dln_a_out=yes
+ host_os=linux-a.out
else
LDFLAGS="-rdynamic"
fi;;
@@ -201,33 +235,49 @@ if test "$with_dln_a_out" != yes; then
rb_cv_dlopen=unknown
AC_MSG_CHECKING(whether OS depend dynamic link works)
if test "$GCC" = yes; then
- CCDLFLAGS=-fpic
+ case "$host_os" in
+ nextstep*) ;;
+ human*) ;;
+ *) CCDLFLAGS=-fpic;;
+ esac
else
case "$host_os" in
hpux*) CCDLFLAGS='+z';;
- solaris*|irix*) CCDLFLAGS='-K pic' ;;
- sunos*) CCDLFLAGS='-pic' ;;
- svr4*|esix*) CCDLFLAGS='-Kpic' ;;
- *) CCDLFLAGS='' ;;
+ solaris*|irix*) CCDLFLAGS='-K pic' ;;
+ sunos*) CCDLFLAGS='-pic' ;;
+ esix*|uxpds*) CCDLFLAGS='-Kpic' ;;
+ *) CCDLFLAGS='' ;;
esac
fi
case "$host_os" in
- hpux*) DLDFLAGS="-E"
- LDSHARED='ld -b'
- LDFLAGS="-Wl,-E"
- rb_cv_dlopen=yes;;
- solaris*) LDSHARED='ld -G'
- rb_cv_dlopen=yes;;
- sunos*) LDSHARED='ld -assert nodefinitions'
- rb_cv_dlopen=yes;;
- svr4*|esix*) LDSHARED="ld -G"
- rb_cv_dlopen=yes ;;
- linux*) LDSHARED="gcc -shared"
- rb_cv_dlopen=yes ;;
- freebsd*) LDSHARED="ld -Bshareable"
- rb_cv_dlopen=yes ;;
- *) LDSHARED='ld' ;;
+ hpux*) DLDFLAGS="-E"
+ LDSHARED='ld -b'
+ LDFLAGS="-Wl,-E"
+ rb_cv_dlopen=yes;;
+ solaris*) LDSHARED='ld -G'
+ rb_cv_dlopen=yes;;
+ sunos*) LDSHARED='ld -assert nodefinitions'
+ rb_cv_dlopen=yes;;
+ sysv4*) LDSHARED='ld -G'
+ rb_cv_dlopen=yes;;
+ esix*|uxpds*) LDSHARED="ld -G"
+ rb_cv_dlopen=yes ;;
+ linux*) LDSHARED="gcc -shared"
+ rb_cv_dlopen=yes ;;
+ freebsd*) LDSHARED="ld -Bshareable"
+ rb_cv_dlopen=yes ;;
+ netbsd*) LDSHARED="ld -Bshareable"
+ rb_cv_dlopen=yes ;;
+ nextstep*) LDSHARED='ld'
+ LDFLAGS="-u libsys_s"
+ rb_cv_dlopen=yes ;;
+ aix*) LDSHARED='../../miniruby ../aix_ld.rb $(TARGET)'
+ rb_cv_dlopen=yes ;;
+ human*) DLDFLAGS=''
+ LDSHARED=''
+ LDFLAGS='' ;;
+ *) LDSHARED='ld' ;;
esac
AC_MSG_RESULT($rb_cv_dlopen)
fi
@@ -297,13 +347,71 @@ AC_ARG_WITH(static-linked-ext,
*) ;;
esac])
+case "$host_os" in
+ human*)
+ AC_CHECK_LIB(signal, _harderr)
+ AC_CHECK_LIB(hmem, hmemset)
+ AC_CHECK_FUNCS(select)
+ AC_MSG_CHECKING(whether PD libc _dtos18 fail to convert big number)
+ AC_CACHE_VAL(rb_cv_missing__dtos18,
+ [AC_TRY_RUN(
+changequote(<<, >>)dnl
+<<
+#include <stdio.h>
+main ()
+{
+ char buf[256];
+ sprintf (buf, "%g", 1e+300);
+ exit (strcmp (buf, "1e+300") ? 0 : 1);
+}
+>>,
+changequote([, ])dnl
+rb_cv_missing__dtos18=yes, rb_cv_missing__dtos18=no)])
+ AC_MSG_RESULT($rb_cv_missing__dtos18)
+ if test "$rb_cv_missing__dtos18" = yes; then
+ AC_DEFINE(MISSING__DTOS18)
+ fi
+ AC_MSG_CHECKING(whether PD libc fconvert fail to round)
+ AC_CACHE_VAL(rb_cv_missing_fconvert,
+ [AC_TRY_RUN(
+changequote(<<, >>)dnl
+<<
+#include <stdio.h>
+#include <math.h>
+main ()
+{
+ char buf[256];
+ sprintf (buf, "%f", log(exp(1.0)));
+ exit (strcmp (buf, "1.000000") ? 0 : 1);
+}
+>>,
+changequote([, ])dnl
+rb_cv_missing_fconvert=yes, rb_cv_missing_fconvert=no)])
+ AC_MSG_RESULT($rb_cv_missing_fconvert)
+ if test "$rb_cv_missing_fconvert" = yes; then
+ AC_DEFINE(MISSING_FCONVERT)
+ fi
+ LIBOBJS="$LIBOBJS x68.o"
+ CFLAGS="$CFLAGS -fansi-only -cc1-stack=196608 -cpp-stack=2694144"
+ binsuffix=.x
+ setup=Setup.x68
+ ;;
+ *)
+ binsuffix=
+ setup=Setup
+ ;;
+esac
+AC_SUBST(binsuffix)
+AC_SUBST(setup)
+
if test "$prefix" = NONE; then
prefix=$ac_default_prefix
fi
-AC_DEFINE_UNQUOTED(RUBY_LIB, "${prefix}/lib/ruby:.")
-AC_SUBST(archlib)dnl
-archlib="${prefix}/lib/ruby/${host_cpu}-${host_os}"
-AC_DEFINE_UNQUOTED(RUBY_ARCHLIB, "$archlib")
+AC_DEFINE_UNQUOTED(RUBY_LIB, "${prefix}/lib/ruby")
+AC_SUBST(arch)dnl
+arch="${host_cpu}-${host_os}"
+AC_DEFINE_UNQUOTED(RUBY_ARCHLIB, "${prefix}/lib/ruby/${host_cpu}-${host_os}")
+AC_DEFINE_UNQUOTED(RUBY_PLATFORM, "$arch")
echo "creating config.h"
cat confdefs.h > config.h
diff --git a/defines.h b/defines.h
index 70e010aac9..b981d8617d 100644
--- a/defines.h
+++ b/defines.h
@@ -13,14 +13,19 @@
#define RUBY
/* define EUC/SJIS for default kanji-code */
+#if defined(MSDOS) || defined(__CYGWIN32__) || defined(__human68k__)
+#undef EUC
+#define SJIS
+#else
#define EUC
#undef SJIS
+#endif
#ifdef NeXT
+#define DYNAMIC_ENDIAN /* determine endian at runtime */
#define S_IXUSR _S_IXUSR /* execute/search permission, owner */
#define S_IXGRP 0000010 /* execute/search permission, group */
#define S_IXOTH 0000001 /* execute/search permission, other */
-#define S_ISREG(mode) (((mode) & (_S_IFMT)) == (_S_IFREG))
#endif /* NeXT */
#ifdef NT
@@ -33,4 +38,13 @@
#define FLUSH_REGISTER_WINDOWS /* empty */
#endif
+#ifdef __human68k__
+#undef HAVE_RANDOM
+#undef HAVE_SETITIMER
+#endif
+
+#ifndef RUBY_PLATFORM
+#define RUBY_PLATFORM "unknown-unknown"
+#endif
+
#endif
diff --git a/dir.c b/dir.c
index fe4910b3a9..a099d5e595 100644
--- a/dir.c
+++ b/dir.c
@@ -39,21 +39,23 @@
# include <ndir.h>
# endif
# ifdef NT
-# include "missing/dirent.h"
+# include "missing/dir.h"
# endif
#endif
#include <errno.h>
+#ifndef NT
char *getenv();
+#endif
static VALUE cDir;
static void
free_dir(dir)
- DIR **dir;
+ DIR *dir;
{
- if (dir && *dir) closedir(*dir);
+ if (dir) closedir(dir);
}
static VALUE
@@ -62,9 +64,9 @@ dir_s_open(dir_class, dirname)
struct RString *dirname;
{
VALUE obj;
- DIR *dirp, **d;
+ DIR *dirp;
- Check_Type(dirname, T_STRING);
+ Check_SafeStr(dirname);
dirp = opendir(dirname->ptr);
if (dirp == NULL) {
@@ -77,23 +79,20 @@ dir_s_open(dir_class, dirname)
}
}
- obj = Make_Data_Struct(dir_class, DIR*, 0, free_dir, d);
- *d = dirp;
+ obj = Data_Wrap_Struct(dir_class, 0, free_dir, dirp);
return obj;
}
static void
-closeddir()
+dir_closed()
{
Fail("closed directory");
}
#define GetDIR(obj, dirp) {\
- DIR **_dp;\
- Get_Data_Struct(obj, DIR*, _dp);\
- dirp = *_dp;\
- if (dirp == NULL) closeddir();\
+ Data_Get_Struct(obj, DIR, dirp);\
+ if (dirp == NULL) dir_closed();\
}
static VALUE
@@ -106,7 +105,7 @@ dir_each(dir)
GetDIR(dir, dirp);
for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
- file = str_new(dp->d_name, NAMLEN(dp));
+ file = str_taint(str_new(dp->d_name, NAMLEN(dp)));
rb_yield(file);
}
return dir;
@@ -158,12 +157,12 @@ static VALUE
dir_close(dir)
VALUE dir;
{
- DIR **dirpp;
+ DIR *dirp;
- Get_Data_Struct(dir, DIR*, dirpp);
- if (*dirpp == NULL) closeddir();
- closedir(*dirpp);
- *dirpp = NULL;
+ Data_Get_Struct(dir, DIR, dirp);
+ if (dirp == NULL) dir_closed();
+ closedir(dirp);
+ DATA_PTR(dir) = NULL;
return Qnil;
}
@@ -177,9 +176,10 @@ dir_s_chdir(argc, argv, obj)
VALUE path;
char *dist = "";
+ rb_secure(2);
rb_scan_args(argc, argv, "01", &path);
if (path) {
- Check_Type(path, T_STRING);
+ Check_SafeStr(path);
dist = RSTRING(path)->ptr;
}
else {
@@ -208,15 +208,16 @@ dir_s_getwd(dir)
if (getwd(path) == 0) rb_sys_fail(path);
#endif
- return str_new2(path);
+ return str_taint(str_new2(path));
}
static VALUE
dir_s_chroot(dir, path)
VALUE dir, path;
{
-#if !defined(DJGPP) && !defined(__CYGWIN32__)
- Check_Type(path, T_STRING);
+#if !defined(DJGPP) && !defined(__CYGWIN32__) && !defined(NT) && !defined(__human68k__)
+ rb_secure(2);
+ Check_SafeStr(path);
if (chroot(RSTRING(path)->ptr) == -1)
rb_sys_fail(0);
@@ -236,6 +237,7 @@ dir_s_mkdir(argc, argv, obj)
VALUE path, vmode;
int mode;
+ rb_secure(2);
if (rb_scan_args(argc, argv, "11", &path, &vmode) == 2) {
mode = NUM2INT(vmode);
}
@@ -243,9 +245,14 @@ dir_s_mkdir(argc, argv, obj)
mode = 0777;
}
- Check_Type(path, T_STRING);
+ Check_SafeStr(path);
+#ifndef NT
if (mkdir(RSTRING(path)->ptr, mode) == -1)
rb_sys_fail(RSTRING(path)->ptr);
+#else
+ if (mkdir(RSTRING(path)->ptr) == -1)
+ rb_sys_fail(RSTRING(path)->ptr);
+#endif
return INT2FIX(0);
}
@@ -255,7 +262,8 @@ dir_s_rmdir(obj, dir)
VALUE obj;
struct RString *dir;
{
- Check_Type(dir, T_STRING);
+ rb_secure(2);
+ Check_SafeStr(dir);
if (rmdir(dir->ptr) < 0)
rb_sys_fail(dir->ptr);
@@ -265,6 +273,7 @@ dir_s_rmdir(obj, dir)
#define isdelim(c) ((c)==' '||(c)=='\t'||(c)=='\n'||(c)=='\0')
char **glob_filename();
+extern char *glob_error_return;
static void
push_globs(ary, s)
@@ -277,11 +286,13 @@ push_globs(ary, s)
if (fnames == (char**)-1) rb_sys_fail(s);
ff = fnames;
while (*ff) {
- ary_push(ary, str_new2(*ff));
+ ary_push(ary, str_taint(str_new2(*ff)));
free(*ff);
ff++;
}
- free(fnames);
+ if (fnames != &glob_error_return) {
+ free(fnames);
+ }
}
static void
@@ -332,7 +343,7 @@ dir_s_glob(dir, str)
int nest;
VALUE ary;
- Check_Type(str, T_STRING);
+ Check_SafeStr(str);
ary = ary_new();
diff --git a/dln.c b/dln.c
index e5193a7ed7..ee5429a596 100644
--- a/dln.c
+++ b/dln.c
@@ -29,7 +29,11 @@ void *xcalloc();
void *xrealloc();
#include <stdio.h>
+#ifndef NT
#include <sys/file.h>
+#else
+#include "missing/file.h"
+#endif
#include <sys/types.h>
#include <sys/stat.h>
@@ -49,9 +53,11 @@ void *xrealloc();
# include <strings.h>
#endif
+#ifndef NT
char *strdup();
char *getenv();
+#endif
int eaccess();
@@ -61,7 +67,7 @@ int eaccess();
#endif
#ifndef FUNCNAME_PATTERN
-# if defined(__hp9000s300) || defined(__NetBSD__) || defined(__BORLANDC__) || defined(__FreeBSD__)
+# if defined(__hp9000s300) || defined(__NetBSD__) || defined(__BORLANDC__) || defined(__FreeBSD__) || defined(NeXT)
# define FUNCNAME_PATTERN "_Init_%.200s"
# else
# define FUNCNAME_PATTERN "Init_%.200s"
@@ -92,8 +98,8 @@ init_funcname(buf, file)
# define LIBC_NAME "libc.a"
#endif
-#ifndef DLN_DEFAULT_PATH
-# define DLN_DEFAULT_PATH "/lib:/usr/lib:."
+#ifndef DLN_DEFAULT_LIB_PATH
+# define DLN_DEFAULT_LIB_PATH "/lib:/usr/lib:/usr/local/lib:."
#endif
#include <errno.h>
@@ -136,12 +142,12 @@ load_header(fd, hdrp, disp)
int size;
lseek(fd, disp, 0);
- size = read(fd, hdrp, sizeof(*hdrp));
+ size = read(fd, hdrp, sizeof(struct exec));
if (size == -1) {
dln_errno = errno;
return -1;
}
- if (size != sizeof(*hdrp) || N_BADMAG(*hdrp)) {
+ if (size != sizeof(struct exec) || N_BADMAG(*hdrp)) {
dln_errno = DLN_ENOEXEC;
return -1;
}
@@ -206,11 +212,10 @@ load_reloc(fd, hdrp, disp)
struct exec *hdrp;
long disp;
{
- struct relocation_info * reloc;
+ struct relocation_info *reloc;
int size;
lseek(fd, disp + N_TXTOFF(*hdrp) + hdrp->a_text + hdrp->a_data, 0);
-
size = hdrp->a_trsize + hdrp->a_drsize;
reloc = (struct relocation_info*)xmalloc(size);
if (reloc == NULL) {
@@ -295,6 +300,7 @@ sym_hash(hdrp, syms)
static int
dln_init(prog)
+ char *prog;
{
char *file;
int fd;
@@ -672,7 +678,7 @@ load_1(fd, disp, need_init)
sym = syms;
while (sym < end) {
struct nlist *new_sym;
- char *key, *name;
+ char *key;
switch (sym->n_type) {
case N_COMM:
@@ -856,23 +862,11 @@ search_undef(key, value, lib_tbl)
int value;
st_table *lib_tbl;
{
-#if 0
- static char *last = "";
- int offset;
-
- if (st_lookup(lib_tbl, key, &offset) == 0) return ST_CONTINUE;
- if (strcmp(last, key) != 0) {
- last = key;
- target_offset = offset;
- }
- return ST_STOP;
-#else
int offset;
if (st_lookup(lib_tbl, key, &offset) == 0) return ST_CONTINUE;
target_offset = offset;
return ST_STOP;
-#endif
}
struct symdef {
@@ -880,7 +874,7 @@ struct symdef {
int lib_offset;
};
-char *dln_library_path = DLN_DEFAULT_PATH;
+char *dln_library_path = DLN_DEFAULT_LIB_PATH;
static int
load_lib(lib)
@@ -1108,7 +1102,7 @@ dln_strerror()
#endif
#ifdef USE_DLN_DLOPEN
- return dlerror();
+ return (char*)dlerror();
#endif
}
@@ -1259,9 +1253,6 @@ dln_load(file)
char *object_files[2] = {NULL, NULL};
void (*init_fct)();
- int len = strlen(file);
- char *point;
- char init_name[len +7];
object_files[0] = file;
@@ -1302,8 +1293,15 @@ dln_find_exe(fname, path)
char *fname;
char *path;
{
+#if defined(__human68k__)
+ if (!path)
+ path = getenv("path");
+ if (!path)
+ path = "/usr/local/bin;/usr/usb;/usr/bin;/bin;.";
+#else
if (!path) path = getenv("PATH");
if (!path) path = "/usr/local/bin:/usr/ucb:/usr/bin:/bin:.";
+#endif
return dln_find_1(fname, path, 1);
}
@@ -1332,6 +1330,12 @@ dln_find_1(fname, path, exe_flag)
if (fname[0] == '/') return fname;
if (strncmp("./", fname, 2) == 0 || strncmp("../", fname, 3) == 0)
return fname;
+#if defined(MSDOS) || defined(NT) || defined(__human68k__)
+ if (fname[0] == '\\') return fname;
+ if (fname[1] == ':') return fname;
+ if (strncmp(".\\", fname, 2) == 0 || strncmp("..\\", fname, 3) == 0)
+ return fname;
+#endif
for (dp = path;; dp = ++ep) {
register int l;
@@ -1339,7 +1343,11 @@ dln_find_1(fname, path, exe_flag)
int fspace;
/* extract a component */
+#if !defined(MSDOS) && !defined(NT) && !defined(__human68k__)
ep = strchr(dp, ':');
+#else
+ ep = strchr(dp, ';');
+#endif
if (ep == NULL)
ep = dp+strlen(dp);
@@ -1399,6 +1407,34 @@ dln_find_1(fname, path, exe_flag)
/* looking for executable */
if (eaccess(fbuf, X_OK) == 0) return fbuf;
}
+#if defined(MSDOS) || defined(NT) || defined(__human68k__)
+ if (exe_flag) {
+ static const char *extension[] = {
+#if defined(MSDOS)
+ ".com", ".exe", ".bat",
+#if defined(DJGPP)
+ ".btm", ".sh", ".ksh", ".pl", ".sed",
+#endif
+#else
+ ".r", ".R", ".x", ".X", ".bat", ".BAT",
+#endif
+ (char *) NULL
+ };
+ int j;
+
+ for (j = 0; extension[j]; j++) {
+ if (fspace < strlen(extension[j])) {
+ fprintf(stderr, "openpath: pathname too long (ignored)\n");
+ fprintf(stderr, "\tDirectory \"%.*s\"\n", (int) (bp - fbuf), fbuf);
+ fprintf(stderr, "\tFile \"%s%s\"\n", fname, extension[j]);
+ continue;
+ }
+ strcpy(bp + i, extension[j]);
+ if (stat(fbuf, &st) == 0)
+ return fbuf;
+ }
+ }
+#endif /* MSDOS or NT or __human68k__ */
/* if not, and no other alternatives, life is bleak */
if (*ep == '\0') {
return NULL;
diff --git a/enum.c b/enum.c
index 5ec71bce42..63ef9e9371 100644
--- a/enum.c
+++ b/enum.c
@@ -90,8 +90,10 @@ enum_find(argc, argv, obj)
if (arg.found) {
return arg.val;
}
- if (NIL_P(if_none)) return Qnil;
- return rb_eval_cmd(if_none, Qnil);
+ if (!NIL_P(if_none)) {
+ rb_eval_cmd(if_none, Qnil);
+ }
+ return Qnil;
}
static void
@@ -275,7 +277,7 @@ index_i(item, iv)
VALUE item;
struct i_v_pair *iv;
{
- if (rb_equal(item, 1, iv->v)) {
+ if (rb_equal(item, iv->v)) {
iv->found = 1;
rb_break();
}
@@ -357,6 +359,7 @@ Init_Enumerable()
rb_define_method(mEnumerable,"max", enum_max, 0);
rb_define_method(mEnumerable,"index", enum_index, 1);
rb_define_method(mEnumerable,"member?", enum_member, 1);
+ rb_define_method(mEnumerable,"include?", enum_member, 1);
rb_define_method(mEnumerable,"length", enum_length, 0);
rb_define_method(mEnumerable,"size", enum_length, 0);
diff --git a/error.c b/error.c
index d1c465b78f..5291d9ea76 100644
--- a/error.c
+++ b/error.c
@@ -159,7 +159,7 @@ static struct types {
extern void TypeError();
void
-Check_Type(x, t)
+rb_check_type(x, t)
VALUE x;
int t;
{
@@ -191,12 +191,13 @@ VALUE eNameError;
VALUE eIndexError;
VALUE eNotImpError;
VALUE eLoadError;
+VALUE eSecurityError;
VALUE eSystemCallError;
VALUE mErrno;
VALUE
-exc_new0(etype, ptr, len)
+exc_new(etype, ptr, len)
VALUE etype;
char *ptr;
UINT len;
@@ -215,15 +216,15 @@ exc_new0(etype, ptr, len)
}
VALUE
-exc_new(etype, s)
+exc_new2(etype, s)
VALUE etype;
char *s;
{
- return exc_new0(etype, s, strlen(s));
+ return exc_new(etype, s, strlen(s));
}
VALUE
-exc_new2(etype, str)
+exc_new3(etype, str)
VALUE etype;
struct RString *str;
{
@@ -240,21 +241,70 @@ exc_s_new(argc, argv, etype)
VALUE arg;
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
- return exc_new0(etype, 0, 0);
+ return exc_new(etype, 0, 0);
}
Check_Type(arg, T_STRING);
- return exc_new2(etype, arg);
+ return exc_new3(etype, arg);
+}
+
+static VALUE
+exc_inspect(exc)
+ VALUE exc;
+{
+ struct RString *classpath = RSTRING(rb_class_path(CLASS_OF(exc)));
+ VALUE str = str_new(classpath->ptr, classpath->len);
+
+ str_cat(str, ":", 1);
+ if (RSTRING(exc)->len == 0) {
+ str_cat(str, "\"\"", 2);
+ }
+ str_cat(str, RSTRING(exc)->ptr, RSTRING(exc)->len);
+ return str;
+}
+
+static VALUE
+exception(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ void ArgError();
+ VALUE v = Qnil;
+ int i;
+ ID id;
+
+ if (argc == 0) {
+ ArgError("wrong # of arguments");
+ }
+ for (i=0; i<argc; i++) { /* argument check */
+ id = rb_to_id(argv[i]);
+ if (!rb_id2name(id)) {
+ ArgError("argument needs to be symbol or string");
+ }
+ if (!rb_is_const_id(id)) {
+ ArgError("identifier %s needs to be constant", rb_id2name(id));
+ }
+ }
+ for (i=0; i<argc; i++) {
+ v = rb_define_class(rb_id2name(rb_to_id(argv[i])), eException);
+ }
+ return v;
}
static VALUE *syserr_list;
+#ifndef NT
+extern int sys_nerr;
+#endif
+
static void
set_syserr(i, name)
int i;
char *name;
{
- syserr_list[i] = rb_define_class_under(mErrno, name, eSystemCallError);
- rb_global_variable(&syserr_list[i]);
+ if (i <= sys_nerr) {
+ syserr_list[i] = rb_define_class_under(mErrno, name, eSystemCallError);
+ rb_global_variable(&syserr_list[i]);
+ }
}
static void init_syserr();
@@ -264,6 +314,7 @@ Init_Exception()
{
eGlobalExit = rb_define_class("GlobalExit", cString);
rb_define_method(eGlobalExit, "new", exc_s_new, -1);
+ rb_define_method(eGlobalExit, "inspect", exc_inspect, 0);
eSystemExit = rb_define_class("SystemExit", eGlobalExit);
eFatal = rb_define_class("fatal", eGlobalExit);
@@ -279,8 +330,11 @@ Init_Exception()
eLoadError = rb_define_class("LoadError", eException);
eRuntimeError = rb_define_class("RuntimeError", eException);
+ eSecurityError = rb_define_class("SecurityError", eException);
init_syserr();
+
+ rb_define_global_function("Exception", exception, -1);
}
#define RAISE_ERROR(class) {\
@@ -291,11 +345,12 @@ Init_Exception()
vsprintf(buf, fmt, args);\
va_end(args);\
\
- rb_raise(exc_new(class, buf));\
+ rb_raise(exc_new2(class, buf));\
}
void
Raise(exc, fmt, va_alist)
+ VALUE exc;
char *fmt;
va_dcl
{
@@ -371,14 +426,16 @@ Fatal(fmt, va_alist)
va_end(args);
rb_in_eval = 0;
- rb_fatal(exc_new(eFatal, buf));
+ rb_fatal(exc_new2(eFatal, buf));
}
void
rb_sys_fail(mesg)
char *mesg;
{
+#ifndef NT
char *strerror();
+#endif
char buf[BUFSIZ];
extern int errno;
int n = errno;
@@ -389,17 +446,15 @@ rb_sys_fail(mesg)
sprintf(buf, "%s", strerror(errno));
errno = 0;
- if (!syserr_list[n]) {
+ if (n > sys_nerr || !syserr_list[n]) {
char name[6];
sprintf(name, "E%03d", n);
set_syserr(n, name);
}
- rb_raise(exc_new(syserr_list[n], buf));
+ rb_raise(exc_new2(syserr_list[n], buf));
}
-extern int sys_nerr;
-
static void
init_syserr()
{
diff --git a/eval.c b/eval.c
index 2f2ee5923a..564ff9a7ad 100644
--- a/eval.c
+++ b/eval.c
@@ -6,7 +6,7 @@
$Date: 1996/12/25 08:54:45 $
created at: Thu Jun 10 14:22:17 JST 1993
- Copyright (C) 1993-1995 Yukihiro Matsumoto
+ Copyright (C) 1993-1997 Yukihiro Matsumoto
************************************************/
@@ -26,8 +26,17 @@
char *strrchr();
#endif
-static VALUE cProc;
+#ifndef setjmp
+#ifdef HAVE__SETJMP
+#define setjmp(env) _setjmp(env)
+#define longjmp(env,val) _longjmp(env,val)
+#endif
+#endif
+
+extern VALUE cData;
+VALUE cProc;
static VALUE proc_call();
+static VALUE f_binding();
#define CACHE_SIZE 0x200
#define CACHE_MASK 0x1ff
@@ -45,6 +54,18 @@ struct cache_entry { /* method hash table. */
static struct cache_entry cache[CACHE_SIZE];
void
+rb_clear_cache()
+{
+ struct cache_entry *ent, *end;
+
+ ent = cache; end = ent + CACHE_SIZE;
+ while (ent < end) {
+ ent->mid = 0;
+ ent++;
+ }
+}
+
+void
rb_add_method(class, mid, node, noex)
struct RClass *class;
ID mid;
@@ -118,21 +139,31 @@ rb_alias(class, name, def)
ID name, def;
{
struct RClass *origin;
- NODE *body, *old;
+ NODE *orig, *body;
if (name == def) return;
- body = search_method(class, def, &origin);
- if (!body || !body->nd_body) {
- NameError("undefined method `%s' for class `%s'",
- rb_id2name(def), rb_class2name(class));
+ orig = search_method(class, def, &origin);
+ if (!orig || !orig->nd_body) {
+ if (TYPE(class) == T_MODULE) {
+ orig = search_method(cObject, def, &origin);
+ }
+ }
+ if (!orig || !orig->nd_body) {
+ NameError("undefined method `%s' for `%s'",
+ rb_id2name(def), rb_class2name((VALUE)class));
+ }
+ body = orig->nd_body;
+ if (nd_type(body) == NODE_FBODY) { /* was alias */
+ body = body->nd_head;
+ def = body->nd_mid;
+ origin = (struct RClass*)body->nd_orig;
}
st_insert(class->m_tbl, name,
- NEW_METHOD(NEW_FBODY(body->nd_body, def, origin),
- body->nd_noex));
+ NEW_METHOD(NEW_FBODY(body, def, origin), orig->nd_noex));
}
-void
+static void
rb_export_method(class, name, noex)
struct RClass *class;
ID name;
@@ -142,15 +173,19 @@ rb_export_method(class, name, noex)
struct RClass *origin;
body = search_method(class, name, &origin);
+ if (!body && TYPE(class) == T_MODULE) {
+ body = search_method(cObject, name, &origin);
+ }
if (!body) {
- NameError("undefined method `%s' for class `%s'",
- rb_id2name(name), rb_class2name(class));
+ NameError("undefined method `%s' for `%s'",
+ rb_id2name(name), rb_class2name((VALUE)class));
}
if (body->nd_noex != noex) {
if (class == origin) {
body->nd_noex = noex;
}
else {
+ rb_clear_cache();
rb_add_method(class, name, NEW_ZSUPER(), noex);
}
}
@@ -173,33 +208,25 @@ method_boundp(class, id, ex)
}
int
-rb_method_boundp(class, id)
- struct RClass *class;
+rb_method_boundp(class, id, priv)
+ VALUE class;
ID id;
+ int priv;
{
- if (method_boundp(class, id, NOEX_PRIVATE))
+ if (method_boundp(class, id, priv?NOEX_PRIVATE:NOEX_PUBLIC))
return TRUE;
return FALSE;
}
-void
-rb_clear_cache()
-{
- struct cache_entry *ent, *end;
-
- ent = cache; end = ent + CACHE_SIZE;
- while (ent < end) {
- ent->mid = 0;
- ent++;
- }
-}
-
static ID init, eqq, each, aref, aset;
VALUE errinfo = Qnil, errat = Qnil;
extern NODE *eval_tree;
extern int nerrs;
-extern VALUE cKernel;
+extern VALUE mKernel;
+extern VALUE cModule;
+extern VALUE cClass;
+extern VALUE eFatal;
extern VALUE eGlobalExit;
extern VALUE eInterrupt;
extern VALUE eSystemExit;
@@ -207,6 +234,7 @@ extern VALUE eException;
extern VALUE eRuntimeError;
extern VALUE eSyntaxError;
static VALUE eLocalJumpError;
+extern VALUE eSecurityError;
extern VALUE TopSelf;
@@ -236,12 +264,15 @@ struct BLOCK {
int level;
int iter;
struct RVarmap *d_vars;
+#ifdef THREAD
+ VALUE orig_thread;
+#endif
struct BLOCK *prev;
} *the_block;
#define PUSH_BLOCK(v,b) { \
struct BLOCK _block; \
- _block.level = (int)&prot_tag; \
+ _block.level = (int)prot_tag; \
_block.var = v; \
_block.body = b; \
_block.self = self; \
@@ -260,7 +291,7 @@ struct BLOCK {
_block = *b; \
_block.prev = the_block; \
the_block = &_block;
-
+
#define POP_BLOCK() \
the_block = the_block->prev; \
}
@@ -268,9 +299,12 @@ struct BLOCK {
struct RVarmap *the_dyna_vars;
#define PUSH_VARS() { \
struct RVarmap *_old; \
- _old = the_dyna_vars;
+ _old = the_dyna_vars; \
+ the_dyna_vars = 0;
-#define POP_VARS() the_dyna_vars = _old; }
+#define POP_VARS() \
+ the_dyna_vars = _old; \
+}
VALUE
dyna_var_defined(id)
@@ -278,7 +312,7 @@ dyna_var_defined(id)
{
struct RVarmap *vars = the_dyna_vars;
- while (vars && vars->id) {
+ while (vars) {
if (vars->id == id) return TRUE;
vars = vars->next;
}
@@ -291,7 +325,7 @@ dyna_var_ref(id)
{
struct RVarmap *vars = the_dyna_vars;
- while (vars && vars->id) {
+ while (vars) {
if (vars->id == id) {
return vars->val;
}
@@ -307,7 +341,7 @@ dyna_var_asgn(id, value)
{
struct RVarmap *vars = the_dyna_vars;
- while (vars && vars->id) {
+ while (vars) {
if (vars->id == id) {
vars->val = value;
return value;
@@ -325,17 +359,6 @@ dyna_var_asgn(id, value)
return value;
}
-static VALUE
-dyna_var_mark()
-{
- NEWOBJ(_vars, struct RVarmap);
- OBJSETUP(_vars, 0, T_VARMAP);
- _vars->id = 0;
- _vars->val = Qnil;
- _vars->next = the_dyna_vars;
- the_dyna_vars = _vars;
-}
-
static struct iter {
int iter;
struct iter *prev;
@@ -378,7 +401,7 @@ static struct tag {
}
#define JUMP_TAG3(val,data1,data2) \
- JUMP_TAG(newnode(NODE_TAG,(val),(data1),(data2)))
+ JUMP_TAG(node_newnode(NODE_TAG,(val),(data1),(data2)))
#define JUMP_TAG2(val,data) JUMP_TAG3((val),(data),0)
@@ -408,6 +431,9 @@ struct RClass *the_class;
struct SCOPE *_old; \
NEWOBJ(_scope, struct SCOPE); \
OBJSETUP(_scope, 0, T_SCOPE); \
+ _scope->local_tbl = 0; \
+ _scope->local_vars = 0; \
+ _scope->flag = 0; \
_old = the_scope; \
the_scope = _scope; \
@@ -415,8 +441,12 @@ struct RClass *the_class;
if (the_scope->flag == SCOPE_ALLOCA) {\
the_scope->local_vars = 0;\
the_scope->local_tbl = 0;\
+ if (the_scope != top_scope)\
+ gc_force_recycle(the_scope);\
+ }\
+ else {\
+ the_scope->flag |= SCOPE_NOSTACK;\
}\
- the_scope->flag |= SCOPE_NOSTACK;\
the_scope = _old;\
}
@@ -426,40 +456,110 @@ static NODE *compile();
static VALUE rb_call();
VALUE rb_apply();
+VALUE rb_funcall2();
+
+static VALUE module_setup();
+
+static VALUE massign();
+static void assign();
+
+static int safe_level = 0;
+/* safe-level:
+ 0 - strings from streams/environment/ARGV are tainted (default)
+ 1 - no dangerous operation by tainted string
+ 2 - some process operations prohibited
+ 3 - all genetated strings are tainted
+ 4 - no global variable value modification/no direct output
+ 5 - no instance variable value modification
+*/
+
+int
+rb_safe_level()
+{
+ return safe_level;
+}
-static void module_setup();
+void
+rb_set_safe_level(level)
+ int level;
+{
+ if (level > safe_level) {
+ safe_level = level;
+ }
+}
+
+static VALUE
+safe_getter()
+{
+ return INT2FIX(safe_level);
+}
-static VALUE masign();
-static void asign();
+static void
+safe_setter(val)
+ VALUE val;
+{
+ int level = NUM2INT(val);
-extern VALUE rb_stderr;
+ if (level < safe_level) {
+ Raise(eSecurityError, "tried to downgrade safe level from %d to %d",
+ safe_level, level);
+ }
+ safe_level = level;
+}
+
+void
+rb_check_safe_str(x)
+ VALUE x;
+{
+ if (TYPE(x)!= T_STRING) {
+ TypeError("wrong argument type %s (expected String)",
+ rb_class2name(CLASS_OF(x)));
+ }
+ if (rb_safe_level() > 0 && str_tainted(x)) {
+ Raise(eSecurityError, "Insecure operation - %s",
+ rb_id2name(the_frame->last_func));
+ }
+}
+
+void
+rb_secure(level)
+ int level;
+{
+ if (level <= safe_level) {
+ Raise(eSecurityError, "Insecure operation `%s' for level %d",
+ rb_id2name(the_frame->last_func), level);
+ }
+}
extern int sourceline;
extern char *sourcefile;
+static VALUE trace_func = 0;
+static void call_trace_func();
+
static void
error_pos()
{
if (sourcefile) {
if (the_frame->last_func) {
- fprintf(stderr, "%s:%d:in `%s': ", sourcefile, sourceline,
+ fprintf(stderr, "%s:%d:in `%s'", sourcefile, sourceline,
rb_id2name(the_frame->last_func));
}
else {
- fprintf(stderr, "%s:%d: ", sourcefile, sourceline);
+ fprintf(stderr, "%s:%d", sourcefile, sourceline);
}
}
}
static void
-error_print(state)
- NODE *state;
+error_print()
{
- struct FRAME *frame = the_frame;
- VALUE etype;
+ VALUE eclass;
+
+ if (NIL_P(errinfo)) return;
if (!NIL_P(errat)) {
- VALUE mesg;
+ VALUE mesg = Qnil;
switch (TYPE(errat)) {
case T_STRING:
@@ -470,26 +570,36 @@ error_print(state)
mesg = RARRAY(errat)->ptr[0];
break;
}
- fwrite(RSTRING(mesg)->ptr, 1, RSTRING(mesg)->len, stderr);
- fprintf(stderr, ": ");
+ if (NIL_P(mesg)) error_pos();
+ else {
+ fwrite(RSTRING(mesg)->ptr, 1, RSTRING(mesg)->len, stderr);
+ }
}
- etype = rb_class_path(CLASS_OF(errinfo));
-
- if (verbose) {
- fwrite(RSTRING(etype)->ptr, 1, RSTRING(etype)->len, stderr);
- putc('|', stderr);
- }
- if (RSTRING(errinfo)->len == 0) {
- fprintf(stderr, "unhandled exception.\n");
+ eclass = CLASS_OF(errinfo);
+ if (eclass == eRuntimeError && RSTRING(errinfo)->len == 0) {
+ fprintf(stderr, ": unhandled exception\n");
}
else {
- fwrite(RSTRING(errinfo)->ptr, 1, RSTRING(errinfo)->len, stderr);
+ PUSH_TAG();
+ if (EXEC_TAG() == 0) {
+ VALUE epath = rb_class_path(eclass);
+ if (RSTRING(epath)->ptr[0] != '#') {
+ fprintf(stderr, ": ");
+ fwrite(RSTRING(epath)->ptr, 1, RSTRING(epath)->len, stderr);
+ }
+ }
+ POP_TAG();
+
+ if (RSTRING(errinfo)->len > 0) {
+ fprintf(stderr, ": ");
+ fwrite(RSTRING(errinfo)->ptr, 1, RSTRING(errinfo)->len, stderr);
+ }
if (RSTRING(errinfo)->ptr[RSTRING(errinfo)->len - 1] != '\n') {
putc('\n', stderr);
}
}
-
+
if (!NIL_P(errat)) {
int i;
struct RArray *ep = RARRAY(errat);
@@ -509,13 +619,17 @@ error_print(state)
}
}
+#ifndef NT
extern char **environ;
+#endif
char **origenviron;
+#if (_MSC_VER >= 1000)
+__declspec(dllexport) void __stdcall
+#else
void
-ruby_init(argc, argv, envp)
- int argc;
- char **argv, **envp;
+#endif
+ruby_init()
{
static struct FRAME frame;
static struct iter iter;
@@ -525,9 +639,6 @@ ruby_init(argc, argv, envp)
the_iter = &iter;
origenviron = environ;
-#ifdef NT
- NtInitialize(&argc, &argv);
-#endif
init_heap();
PUSH_SCOPE();
@@ -539,15 +650,43 @@ ruby_init(argc, argv, envp)
if ((state = EXEC_TAG()) == 0) {
rb_call_inits();
the_class = (struct RClass*)cObject;
- the_frame->cbase = (VALUE)newnode(NODE_CREF,cObject,0,0);
- ruby_options(argc, argv, envp);
+ the_frame->cbase = (VALUE)node_newnode(NODE_CREF,cObject,0,0);
+ rb_define_global_const("TOPLEVEL_BINDING", f_binding(TopSelf));
+ ruby_prog_init();
}
POP_TAG();
- if (state) error_print(state);
+ if (state) error_print();
POP_SCOPE();
the_scope = top_scope;
}
+static int ext_init = 0;
+
+#if (_MSC_VER >= 1000)
+__declspec(dllexport) void __stdcall
+#else
+void
+#endif
+ruby_options(argc, argv)
+ int argc;
+ char **argv;
+{
+ NODE *state;
+
+ PUSH_TAG()
+ if ((state = EXEC_TAG()) == 0) {
+ NODE *save = eval_tree;
+
+ Init_ext();
+ ext_init = 1;
+ rb_require_modules();
+ eval_tree = save;
+ ruby_process_options(argc, argv);
+ }
+ POP_TAG();
+ if (state) error_print();
+}
+
static VALUE
eval_node(self)
VALUE self;
@@ -555,7 +694,7 @@ eval_node(self)
VALUE result = Qnil;
NODE *tree;
- if (!eval_tree) return FALSE;
+ if (!eval_tree) return Qnil;
tree = eval_tree;
eval_tree = 0;
@@ -569,11 +708,16 @@ int rb_in_eval;
#ifdef THREAD
static void thread_cleanup();
static void thread_wait_other_threads();
+static VALUE thread_current();
#endif
static int exit_status;
+#if (_MSC_VER >= 1000)
+__declspec(dllexport) void __stdcall
+#else
void
+#endif
ruby_run()
{
NODE *state;
@@ -587,6 +731,7 @@ ruby_run()
PUSH_TAG();
PUSH_ITER(ITER_NOT);
if ((state = EXEC_TAG()) == 0) {
+ if (!ext_init) Init_ext();
eval_node(TopSelf);
}
POP_ITER();
@@ -613,6 +758,7 @@ ruby_run()
}
switch (ex->nd_tag) {
+ case IN_BLOCK|TAG_RETURN:
case TAG_RETURN:
error_pos();
fprintf(stderr, "unexpected return\n");
@@ -623,6 +769,7 @@ ruby_run()
fprintf(stderr, "unexpected next\n");
exit(1);
break;
+ case IN_BLOCK|TAG_BREAK:
case TAG_BREAK:
error_pos();
fprintf(stderr, "unexpected break\n");
@@ -635,7 +782,7 @@ ruby_run()
break;
case TAG_RETRY:
error_pos();
- fprintf(stderr, "retry outside of protect clause\n");
+ fprintf(stderr, "retry outside of rescue clause\n");
exit(1);
break;
case TAG_RAISE:
@@ -643,7 +790,7 @@ ruby_run()
if (obj_is_kind_of(errinfo, eSystemExit)) {
exit(exit_status);
}
- error_print(ex);
+ error_print();
exit(1);
break;
case TAG_THROW:
@@ -665,7 +812,7 @@ compile_error(at)
mesg = errinfo;
nerrs = 0;
- errinfo = exc_new(eSyntaxError, "compile error in ");
+ errinfo = exc_new2(eSyntaxError, "compile error in ");
str_cat(errinfo, at, strlen(at));
str_cat(errinfo, ":\n", 2);
str_cat(errinfo, RSTRING(mesg)->ptr, RSTRING(mesg)->len);
@@ -692,6 +839,7 @@ rb_eval_cmd(cmd, arg)
{
NODE *state;
struct SCOPE *saved_scope;
+ volatile int safe = rb_safe_level();
if (TYPE(cmd) != T_STRING) {
if (obj_is_kind_of(cmd, cProc)) {
@@ -706,12 +854,16 @@ rb_eval_cmd(cmd, arg)
the_scope = top_scope;
the_class = (struct RClass*)cObject;
+ if (str_tainted(cmd)) {
+ safe_level = 5;
+ }
if ((state = EXEC_TAG()) == 0) {
eval(TopSelf, cmd, Qnil);
}
the_scope = saved_scope;
+ safe_level = safe;
POP_TAG();
POP_CLASS();
@@ -730,7 +882,7 @@ rb_eval_cmd(cmd, arg)
Raise(eLocalJumpError, "unexpected redo");
break;
case TAG_RETRY:
- Raise(eLocalJumpError, "retry outside of protect clause");
+ Raise(eLocalJumpError, "retry outside of rescue clause");
break;
default:
JUMP_TAG(state);
@@ -761,7 +913,7 @@ superclass(self, node)
VALUE self;
NODE *node;
{
- VALUE val;
+ VALUE val = 0;
NODE *state;
PUSH_TAG();
@@ -769,18 +921,24 @@ superclass(self, node)
val = rb_eval(self, node);
}
POP_TAG();
- if ((state && state->nd_tag == TAG_RAISE) || !val || TYPE(val) != T_CLASS){
- switch (nd_type(node)) {
- case NODE_COLON2:
- TypeError("undefined superclass `%s'", rb_id2name(node->nd_mid));
- case NODE_CVAR:
- case NODE_CONST:
- TypeError("undefined superclass `%s'", rb_id2name(node->nd_vid));
+ if (state) {
+ if (state->nd_tag == TAG_RAISE) {
+ superclass_error:
+ switch (nd_type(node)) {
+ case NODE_COLON2:
+ TypeError("undefined superclass `%s'", rb_id2name(node->nd_mid));
+ case NODE_CVAR:
+ TypeError("undefined superclass `%s'", rb_id2name(node->nd_vid));
+ default:
+ TypeError("superclass undefined");
+ }
}
- if (state) JUMP_TAG(state);
- TypeError("superclass undefined");
+ JUMP_TAG(state);
+ }
+ if (TYPE(val) != T_CLASS) goto superclass_error;
+ if (FL_TEST(val, FL_SINGLETON)) {
+ TypeError("can't make subclass of virtual class");
}
- if (state) JUMP_TAG(state);
return val;
}
@@ -824,8 +982,8 @@ ev_const_get(cref, id)
return rb_const_get(cref->nd_clss, id);
}
-#define SETUP_ARGS {\
- NODE *n = node->nd_args;\
+#define SETUP_ARGS(anode) {\
+ NODE *n = anode;\
if (!n) {\
argc = 0;\
argv = 0;\
@@ -834,14 +992,15 @@ ev_const_get(cref, id)
argc=n->nd_alen;\
if (argc > 0) {\
int i;\
- n = node->nd_args;\
+ int line = sourceline;\
+ n = anode;\
argv = ALLOCA_N(VALUE,argc);\
for (i=0;i<argc;i++) {\
argv[i] = rb_eval(self,n->nd_head);\
n=n->nd_next;\
}\
- sourceline = nd_line(node);\
- sourcefile = node->file;\
+ sourcefile = anode->file;\
+ sourceline = line;\
}\
else {\
argc = 0;\
@@ -850,13 +1009,14 @@ ev_const_get(cref, id)
}\
else {\
VALUE args = rb_eval(self,n);\
+ int line = sourceline;\
if (TYPE(args) != T_ARRAY)\
args = rb_to_a(args);\
argc = RARRAY(args)->len;\
argv = ALLOCA_N(VALUE, argc);\
MEMCPY(argv, RARRAY(args)->ptr, VALUE, argc);\
- sourceline = nd_line(node);\
- sourcefile = node->file;\
+ sourcefile = anode->file;\
+ sourceline = line;\
}\
}
@@ -867,25 +1027,225 @@ rb_test_false_or_nil(v)
return (v != Qnil) && (v != FALSE);
}
+#define MATCH_DATA the_scope->local_vars[node->nd_cnt]
+
+static char*
+is_defined(self, node, buf)
+ VALUE self;
+ NODE *node; /* OK */
+ char *buf;
+{
+ VALUE val; /* OK */
+ NODE *state;
+
+ node = node->nd_head;
+
+ switch (nd_type(node)) {
+ case NODE_SUPER:
+ case NODE_ZSUPER:
+ if (the_frame->last_func == 0) return 0;
+ else if (method_boundp(the_frame->last_class->super,
+ the_frame->last_func, 1)) {
+ return "super";
+ }
+ break;
+
+ case NODE_FCALL:
+ case NODE_VCALL:
+ val = CLASS_OF(self);
+ goto check_bound;
+
+ case NODE_CALL:
+ PUSH_TAG();
+ if ((state = EXEC_TAG()) == 0) {
+ val = rb_eval(self, node->nd_recv);
+ val = CLASS_OF(val);
+ }
+ POP_TAG();
+ if (state) {
+ return 0;
+ }
+ check_bound:
+ if (method_boundp(val, node->nd_mid,
+ nd_type(node)== NODE_CALL)) {
+ return "method";
+ }
+ break;
+
+ case NODE_YIELD:
+ if (iterator_p()) {
+ return "yield";
+ }
+ break;
+
+ case NODE_SELF:
+ return "self";
+
+ case NODE_NIL:
+ return "nil";
+
+ case NODE_ATTRSET:
+ case NODE_OP_ASGN1:
+ case NODE_OP_ASGN2:
+ case NODE_MASGN:
+ case NODE_LASGN:
+ case NODE_DASGN:
+ case NODE_GASGN:
+ case NODE_IASGN:
+ case NODE_CASGN:
+ return "assignment";
+
+ case NODE_LVAR:
+ case NODE_DVAR:
+ return "local-variable";
+
+ case NODE_GVAR:
+ if (rb_gvar_defined(node->nd_entry)) {
+ return "global-variable";
+ }
+ break;
+
+ case NODE_IVAR:
+ if (rb_ivar_defined(self, node->nd_vid)) {
+ return "instance-variable";
+ }
+ break;
+
+ case NODE_CVAR:
+ if (ev_const_defined(the_frame->cbase, node->nd_vid)) {
+ return "constant";
+ }
+ break;
+
+ case NODE_COLON2:
+ PUSH_TAG();
+ if ((state = EXEC_TAG()) == 0) {
+ val = rb_eval(self, node->nd_head);
+ }
+ POP_TAG();
+ if (state) {
+ return 0;
+ }
+ else {
+ switch (TYPE(val)) {
+ case T_CLASS:
+ case T_MODULE:
+ if (rb_const_defined_at(val, node->nd_mid))
+ return "constant";
+ }
+ }
+ break;
+
+ case NODE_NTH_REF:
+ if (reg_nth_defined(node->nd_nth, MATCH_DATA)) {
+ sprintf(buf, "$%d", node->nd_nth);
+ return buf;
+ }
+ break;
+
+ case NODE_BACK_REF:
+ if (reg_nth_defined(0, MATCH_DATA)) {
+ sprintf(buf, "$%c", node->nd_nth);
+ return buf;
+ }
+ break;
+
+ default:
+ PUSH_TAG();
+ if ((state = EXEC_TAG()) == 0) {
+ rb_eval(self, node);
+ }
+ POP_TAG();
+ if (!state) {
+ return "expression";
+ }
+ break;
+ }
+ return 0;
+}
+
static int handle_rescue();
VALUE rb_yield_0();
+static void blk_free();
+
+static VALUE
+set_trace_func(obj, trace)
+ VALUE obj;
+ struct RData *trace;
+{
+ if (NIL_P(trace)) {
+ trace_func = 0;
+ return Qnil;
+ }
+ if (TYPE(trace) != T_DATA || trace->dfree != blk_free) {
+ TypeError("trace_func needs to be Proc");
+ }
+ return trace_func = (VALUE)trace;
+}
+
+static void
+call_trace_func(event, file, line, self, id)
+ char *event;
+ char *file;
+ int line;
+ VALUE self;
+ ID id;
+{
+ NODE *state;
+ volatile VALUE trace;
+ struct FRAME *prev;
+
+ if (!trace_func) return;
+
+ trace = trace_func;
+ trace_func = 0;
+#ifdef THREAD
+ thread_critical++;
+#endif
+
+ prev = the_frame;
+ PUSH_FRAME();
+ *the_frame = *_frame.prev;
+ the_frame->prev = prev;
+
+ the_frame->line = sourceline = line;
+ the_frame->file = sourcefile = file;
+ PUSH_TAG();
+ if ((state = EXEC_TAG()) == 0) {
+ proc_call(trace, ary_new3(5, str_new2(event),
+ str_new2(sourcefile),
+ INT2FIX(sourceline),
+ INT2FIX(id),
+ self?f_binding(self):Qnil));
+ }
+ POP_TAG();
+ POP_FRAME();
+
+#ifdef THREAD
+ thread_critical--;
+#endif
+ if (!trace_func) trace_func = trace;
+ if (state) JUMP_TAG(state);
+}
+
static VALUE
rb_eval(self, node)
VALUE self;
- register NODE *node;
+ NODE * volatile node;
{
NODE *state;
- VALUE result = Qnil;
+ volatile VALUE result = Qnil;
#define RETURN(v) { result = (v); goto finish; }
again:
if (!node) RETURN(Qnil);
+#if 0
sourceline = nd_line(node);
sourcefile = node->file;
-
+#endif
switch (nd_type(node)) {
case NODE_BLOCK:
while (node) {
@@ -926,15 +1286,6 @@ rb_eval(self, node)
}
goto again;
- case NODE_UNLESS:
- if (!RTEST(rb_eval(self, node->nd_cond))) {
- node = node->nd_body;
- }
- else {
- node = node->nd_else;
- }
- goto again;
-
case NODE_CASE:
{
VALUE val;
@@ -945,13 +1296,17 @@ rb_eval(self, node)
NODE *tag;
if (nd_type(node) != NODE_WHEN) {
-
- RETURN(rb_eval(self, node));
+ goto again;
}
tag = node->nd_head;
while (tag) {
+ if (trace_func) {
+ call_trace_func("line", tag->file, nd_line(tag),
+ self, the_frame->last_func);
+ }
if (RTEST(rb_funcall2(rb_eval(self, tag->nd_head),eqq,1,&val))){
- RETURN(rb_eval(self, node->nd_body));
+ node = node->nd_body;
+ goto again;
}
tag = tag->nd_next;
}
@@ -963,15 +1318,14 @@ rb_eval(self, node)
case NODE_WHILE:
PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
- while_next:
- for (;;) {
- if (node->nd_state && !RTEST(rb_eval(self, node->nd_cond)))
- break;
+ if (node->nd_state && !RTEST(rb_eval(self, node->nd_cond)))
+ goto while_out;
+ do {
while_redo:
rb_eval(self, node->nd_body);
- if (!node->nd_state && !RTEST(rb_eval(self, node->nd_cond)))
- break;
- }
+ while_next:
+ ;
+ } while (RTEST(rb_eval(self, node->nd_cond)));
}
else {
switch (state->nd_tag) {
@@ -981,12 +1335,15 @@ rb_eval(self, node)
case TAG_NEXT:
state = 0;
goto while_next;
+ case TAG_BREAK:
+ state = 0;
default:
break;
}
}
+ while_out:
POP_TAG();
- if (state && state->nd_tag != TAG_BREAK) {
+ if (state) {
JUMP_TAG(state);
}
RETURN(Qnil);
@@ -994,30 +1351,32 @@ rb_eval(self, node)
case NODE_UNTIL:
PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
- until_next:
- for (;;) {
- if (node->nd_state && RTEST(rb_eval(self, node->nd_cond)))
- break;
+ if (node->nd_state && RTEST(rb_eval(self, node->nd_cond)))
+ goto until_out;
+ do {
until_redo:
rb_eval(self, node->nd_body);
- if (!node->nd_state && RTEST(rb_eval(self, node->nd_cond)))
- break;
- }
+ until_next:
+ ;
+ } while (!RTEST(rb_eval(self, node->nd_cond)));
}
else {
switch (state->nd_tag) {
case TAG_REDO:
state = 0;
- goto while_redo;
+ goto until_redo;
case TAG_NEXT:
state = 0;
- goto while_next;
+ goto until_next;
+ case TAG_BREAK:
+ state = 0;
default:
break;
}
}
+ until_out:
POP_TAG();
- if (state && state->nd_tag != TAG_BREAK) {
+ if (state) {
JUMP_TAG(state);
}
RETURN(Qnil);
@@ -1040,11 +1399,12 @@ rb_eval(self, node)
}
else {
VALUE recv;
+ int line = sourceline;
recv = rb_eval(self, node->nd_iter);
PUSH_ITER(ITER_PRE);
- sourceline = nd_line(node);
sourcefile = node->file;
+ sourceline = line;
result = rb_call(CLASS_OF(recv),recv,each,0,0,0);
POP_ITER();
}
@@ -1080,39 +1440,44 @@ rb_eval(self, node)
case NODE_RESCUE:
retry_entry:
- PUSH_TAG();
- if ((state = EXEC_TAG()) == 0) {
- result = rb_eval(self, node->nd_head);
- }
- POP_TAG();
- if (state) {
- if (state->nd_tag == TAG_RAISE) {
- NODE *resq = node->nd_resq;
- while (resq) {
- if (handle_rescue(self, resq)) {
- state = 0;
- PUSH_TAG();
- if ((state = EXEC_TAG()) == 0) {
- result = rb_eval(self, resq->nd_body);
- }
- POP_TAG();
- if (state == 0) {
- errat = Qnil;
- }
- else if (state->nd_tag == TAG_RETRY) {
+ {
+ volatile VALUE e_info = errinfo, e_at = errat;
+
+ PUSH_TAG();
+ if ((state = EXEC_TAG()) == 0) {
+ result = rb_eval(self, node->nd_head);
+ }
+ POP_TAG();
+ if (state) {
+ if (state->nd_tag == TAG_RAISE) {
+ NODE * volatile resq = node->nd_resq;
+ while (resq) {
+ if (handle_rescue(self, resq)) {
state = 0;
- goto retry_entry;
+ PUSH_TAG();
+ if ((state = EXEC_TAG()) == 0) {
+ result = rb_eval(self, resq->nd_body);
+ }
+ POP_TAG();
+ if (state == 0) {
+ errinfo = e_info;
+ errat = e_at;
+ }
+ else if (state->nd_tag == TAG_RETRY) {
+ state = 0;
+ goto retry_entry;
+ }
+ break;
}
- break;
+ resq = resq->nd_head; /* next rescue */
}
- resq = resq->nd_head; /* next rescue */
}
- }
- if (state) {
- JUMP_TAG(state);
+ if (state) {
+ JUMP_TAG(state);
+ }
}
}
- break;
+ break;
case NODE_ENSURE:
PUSH_TAG();
@@ -1192,7 +1557,7 @@ rb_eval(self, node)
PUSH_ITER(ITER_NOT);
recv = rb_eval(self, node->nd_recv);
- SETUP_ARGS;
+ SETUP_ARGS(node->nd_args);
POP_ITER();
result = rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0);
}
@@ -1203,12 +1568,16 @@ rb_eval(self, node)
int argc; VALUE *argv; /* used in SETUP_ARGS */
PUSH_ITER(ITER_NOT);
- SETUP_ARGS;
+ SETUP_ARGS(node->nd_args);
POP_ITER();
result = rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,1);
}
break;
+ case NODE_VCALL:
+ result = rb_call(CLASS_OF(self),self,node->nd_mid,0,0,2);
+ break;
+
case NODE_SUPER:
case NODE_ZSUPER:
{
@@ -1220,7 +1589,7 @@ rb_eval(self, node)
}
else {
PUSH_ITER(ITER_NOT);
- SETUP_ARGS;
+ SETUP_ARGS(node->nd_args);
POP_ITER();
}
@@ -1239,7 +1608,9 @@ rb_eval(self, node)
PUSH_TAG();
if (node->nd_rval) the_frame->cbase = (VALUE)node->nd_rval;
if (node->nd_tbl) {
- the_scope->local_vars = ALLOCA_N(VALUE, node->nd_tbl[0]);
+ VALUE *vars = ALLOCA_N(VALUE, node->nd_tbl[0]+1);
+ *vars++ = (VALUE)node;
+ the_scope->local_vars = vars;
memclear(the_scope->local_vars, node->nd_tbl[0]);
the_scope->local_tbl = node->nd_tbl;
}
@@ -1259,17 +1630,17 @@ rb_eval(self, node)
case NODE_OP_ASGN1:
{
- VALUE recv, args, val;
+ int argc; VALUE *argv; /* used in SETUP_ARGS */
+ VALUE recv, val;
NODE *rval;
recv = rb_eval(self, node->nd_recv);
rval = node->nd_args->nd_head;
-
- args = rb_eval(self, node->nd_args->nd_next);
- val = rb_apply(recv, aref, args);
+ SETUP_ARGS(node->nd_args->nd_next);
+ val = rb_funcall2(recv, aref, argc-1, argv);
val = rb_funcall(val, node->nd_mid, 1, rb_eval(self, rval));
- ary_push(args, val);
- rb_apply(recv, aset, args);
+ argv[argc-1] = val;
+ val = rb_funcall2(recv, aset, argc, argv);
result = val;
}
break;
@@ -1282,7 +1653,7 @@ rb_eval(self, node)
recv = rb_eval(self, node->nd_recv);
val = rb_funcall(recv, id, 0);
- val = rb_funcall(recv, node->nd_next->nd_mid, 2, val,
+ val = rb_funcall(val, node->nd_next->nd_mid, 1,
rb_eval(self, node->nd_value));
rb_funcall2(recv, id_attrset(id), 1, &val);
@@ -1291,12 +1662,12 @@ rb_eval(self, node)
break;
case NODE_MASGN:
- result = masign(self, node, rb_eval(self, node->nd_value));
+ result = massign(self, node, rb_eval(self, node->nd_value));
break;
case NODE_LASGN:
if (the_scope->local_vars == 0)
- Bug("unexpected local variable asignment");
+ Bug("unexpected local variable assignment");
the_scope->local_vars[node->nd_cnt] = rb_eval(self, node->nd_value);
result = the_scope->local_vars[node->nd_cnt];
break;
@@ -1332,7 +1703,7 @@ rb_eval(self, node)
val = rb_eval(self, node->nd_value);
/* check for static scope constants */
if (verbose && ev_const_defined(the_frame->cbase, node->nd_vid)) {
- Warning("already initialized constnant %s",
+ Warning("already initialized constant %s",
rb_id2name(node->nd_vid));
}
rb_const_set(the_class, node->nd_vid, val);
@@ -1361,12 +1732,6 @@ rb_eval(self, node)
case NODE_CVAR:
result = ev_const_get(the_frame->cbase, node->nd_vid);
- nd_set_type(node, NODE_CONST);
- node->nd_cval = result;
- break;
-
- case NODE_CONST:
- result = node->nd_cval;
break;
case NODE_COLON2:
@@ -1386,7 +1751,6 @@ rb_eval(self, node)
}
break;
-#define MATCH_DATA the_scope->local_vars[node->nd_cnt]
case NODE_NTH_REF:
result = reg_nth_match(node->nd_nth, MATCH_DATA);
break;
@@ -1472,14 +1836,14 @@ rb_eval(self, node)
rb_in_eval++;
list->nd_head = compile(list->nd_head->nd_lit);
rb_in_eval--;
- if (!node) {
+ if (nerrs > 0) {
compile_error("string expand");
}
}
str2 = rb_eval(self, list->nd_head);
+ str2 = obj_as_string(str2);
}
if (str2) {
- str2 = obj_as_string(str2);
str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len);
}
list = list->nd_next;
@@ -1530,12 +1894,6 @@ rb_eval(self, node)
if (origin == (VALUE)the_class) {
Warning("redefine %s", rb_id2name(node->nd_mid));
}
- else {
- if (body->nd_noex != node->nd_noex) {
- Warning("change method %s's scope",
- rb_id2name(node->nd_mid));
- }
- }
rb_clear_cache();
}
@@ -1553,10 +1911,18 @@ rb_eval(self, node)
VALUE class;
NODE *body;
+ if (FIXNUM_P(recv)) {
+ TypeError("Can't define method \"%s\" for Fixnum",
+ rb_id2name(node->nd_mid));
+ }
if (NIL_P(recv)) {
TypeError("Can't define method \"%s\" for nil",
rb_id2name(node->nd_mid));
}
+ if (rb_special_const_p(recv)) {
+ TypeError("Can't define method \"%s\" for special constants",
+ rb_id2name(node->nd_mid));
+ }
class = rb_singleton_class(recv);
if (st_lookup(RCLASS(class)->m_tbl, node->nd_mid, &body)) {
@@ -1572,10 +1938,13 @@ rb_eval(self, node)
case NODE_UNDEF:
{
+ struct RClass *origin;
NODE *body;
- if (st_lookup(the_class->m_tbl, node->nd_mid, &body)) {
- Warning("redefine %s", rb_id2name(node->nd_mid));
+ body = search_method(the_class, node->nd_mid, &origin);
+ if (!body || !body->nd_body) {
+ NameError("undefined method `%s' for class `%s'",
+ rb_id2name(node->nd_mid), rb_class2name((VALUE)the_class));
}
rb_clear_cache();
rb_add_method(the_class, node->nd_mid, 0, NOEX_PUBLIC);
@@ -1588,6 +1957,11 @@ rb_eval(self, node)
result = Qnil;
break;
+ case NODE_VALIAS:
+ rb_alias_variable(node->nd_new, node->nd_old);
+ result = Qnil;
+ break;
+
case NODE_CLASS:
{
VALUE super, class;
@@ -1600,23 +1974,31 @@ rb_eval(self, node)
super = 0;
}
- if (!rb_autoload_defined(node->nd_cname) &&
- ev_const_defined(the_frame->cbase, node->nd_cname)) {
- class = rb_const_get(the_class, node->nd_cname);
- if (TYPE(class) != T_CLASS)
+ if (rb_const_defined_at(the_class, node->nd_cname) &&
+ ((VALUE)the_class != cObject ||
+ !rb_autoload_defined(node->nd_cname))) {
+
+ class = rb_const_get_at(the_class, node->nd_cname);
+ if (TYPE(class) != T_CLASS) {
TypeError("%s is not a class", rb_id2name(node->nd_cname));
+ }
if (super) {
tmp = RCLASS(class)->super;
- while (FL_TEST(tmp, FL_SINGLETON)) {
+ if (FL_TEST(tmp, FL_SINGLETON)) {
tmp = RCLASS(tmp)->super;
}
while (TYPE(tmp) == T_ICLASS) {
tmp = RCLASS(tmp)->super;
}
- if (tmp != RCLASS(super))
+ if (tmp != RCLASS(super)) {
TypeError("superclass mismatch for %s",
rb_id2name(node->nd_cname));
+ }
+ }
+ if (safe_level >= 4) {
+ Raise(eSecurityError, "extending class prohibited");
}
+ rb_clear_cache();
Warning("extending class %s", rb_id2name(node->nd_cname));
}
else {
@@ -1626,8 +2008,7 @@ rb_eval(self, node)
rb_set_class_path(class,the_class,rb_id2name(node->nd_cname));
}
- module_setup(class, node->nd_body);
- result = class;
+ result = module_setup(class, node->nd_body);
}
break;
@@ -1635,11 +2016,17 @@ rb_eval(self, node)
{
VALUE module;
- if (!rb_autoload_defined(node->nd_cname) &&
- ev_const_defined(the_frame->cbase, node->nd_cname)) {
- module = rb_const_get(the_class, node->nd_cname);
- if (TYPE(module) != T_MODULE)
+ if (rb_const_defined_at(the_class, node->nd_cname) &&
+ ((VALUE)the_class != cObject ||
+ !rb_autoload_defined(node->nd_cname))) {
+
+ module = rb_const_get_at(the_class, node->nd_cname);
+ if (TYPE(module) != T_MODULE) {
TypeError("%s is not a module", rb_id2name(node->nd_cname));
+ }
+ if (safe_level >= 4) {
+ Raise(eSecurityError, "extending module prohibited");
+ }
Warning("extending module %s", rb_id2name(node->nd_cname));
}
else {
@@ -1648,150 +2035,53 @@ rb_eval(self, node)
rb_set_class_path(module,the_class,rb_id2name(node->nd_cname));
}
- module_setup(module, node->nd_body);
- result = module;
+ result = module_setup(module, node->nd_body);
}
break;
- case NODE_DEFINED:
+ case NODE_SCLASS:
{
- VALUE obj;
- char buf[20];
- char *desc = 0;
-
- node = node->nd_head;
-
- switch (nd_type(node)) {
- case NODE_SUPER:
- case NODE_ZSUPER:
- if (the_frame->last_func == 0) result = FALSE;
- else {
- result = method_boundp(the_frame->last_class->super,
- the_frame->last_func, 1);
- }
- break;
-
- case NODE_FCALL:
- obj = CLASS_OF(self);
- goto check_bound;
-
- case NODE_CALL:
- PUSH_TAG();
- if ((state = EXEC_TAG()) == 0) {
- obj = rb_eval(self, node->nd_recv);
- }
- POP_TAG();
- if (state) {
- break;
- }
- else {
- if (state) JUMP_TAG(state);
- obj = CLASS_OF(obj);
- check_bound:
- if (method_boundp(obj, node->nd_mid,
- nd_type(node)== NODE_CALL)) {
- desc = "method";
- }
- }
- break;
-
- case NODE_YIELD:
- if (iterator_p()) {
- desc = "iterator";
- }
- break;
-
- case NODE_SELF:
- desc = "self"; break;
- case NODE_NIL:
- desc = "nil"; break;
-
- case NODE_ATTRSET:
- case NODE_OP_ASGN1:
- case NODE_OP_ASGN2:
- case NODE_MASGN:
- case NODE_LASGN:
- case NODE_DASGN:
- case NODE_GASGN:
- case NODE_IASGN:
- case NODE_CASGN:
- desc = "asignment"; break;
-
- case NODE_LVAR:
- desc = "local-variable"; break;
- case NODE_DVAR:
- desc = "dynamic-local-variable"; break;
-
- case NODE_GVAR:
- if (rb_gvar_defined(node->nd_entry)) {
- desc = "global-variable";
- }
- break;
-
- case NODE_IVAR:
- if (rb_ivar_defined(self, node->nd_vid)) {
- desc = "instance-variable";
- }
- break;
-
- case NODE_CVAR:
- if (ev_const_defined(the_frame->cbase, node->nd_vid)) {
- case NODE_CONST: /* jump in */
- desc = "class-constant";
- }
- break;
+ VALUE class;
- case NODE_COLON2:
- PUSH_TAG();
- if ((state = EXEC_TAG()) == 0) {
- obj = rb_eval(self, node->nd_head);
- }
- POP_TAG();
- if (state) {
- break;
- }
- else {
- if (state) JUMP_TAG(state);
- switch (TYPE(obj)) {
- case T_CLASS:
- case T_MODULE:
- if (rb_const_defined_at(obj, node->nd_mid))
- desc = "class-constant";
- break;
- }
- }
- break;
+ class = rb_eval(self, node->nd_recv);
+ if (FIXNUM_P(class)) {
+ TypeError("No virtual class for Fixnums");
+ }
+ if (NIL_P(class)) {
+ TypeError("No virtual class for nil");
+ }
+ if (rb_special_const_p(class)) {
+ TypeError("No virtual class for special constants");
+ }
+ if (FL_TEST(CLASS_OF(class), FL_SINGLETON)) {
+ rb_clear_cache();
+ }
+ class = rb_singleton_class(class);
- case NODE_NTH_REF:
- if (reg_nth_defined(node->nd_nth, MATCH_DATA)) {
- sprintf(buf, "$%d", node->nd_nth);
- desc = buf;
- }
- break;
+ result = module_setup(class, node->nd_body);
+ }
+ break;
- case NODE_BACK_REF:
- if (reg_nth_defined(0, MATCH_DATA)) {
- sprintf(buf, "$%c", node->nd_nth);
- desc = buf;
- }
- break;
+ case NODE_DEFINED:
+ {
+ char buf[20];
+ char *desc = is_defined(self, node, buf);
- default:
- PUSH_TAG();
- if ((state = EXEC_TAG()) == 0) {
- rb_eval(self, node);
- }
- POP_TAG();
- if (state) break;
- else {
- desc = "expression";
- }
- }
if (desc) result = str_new2(desc);
else result = FALSE;
}
break;
+ case NODE_NEWLINE:
+ sourcefile = node->file;
+ sourceline = node->nd_nth;
+ if (trace_func) {
+ call_trace_func("line", sourcefile, sourceline,
+ self, the_frame->last_func);
+ }
+ node = node->nd_next;
+ goto again;
+
default:
Bug("unknown node type %d", nd_type(node));
}
@@ -1800,13 +2090,14 @@ rb_eval(self, node)
return result;
}
-static void
+static VALUE
module_setup(module, node)
VALUE module;
- NODE *node;
+ NODE * volatile node;
{
NODE *state;
VALUE save = the_frame->cbase;
+ VALUE result; /* OK */
/* fill c-ref */
node->nd_clss = module;
@@ -1818,7 +2109,9 @@ module_setup(module, node)
if (node->nd_rval) the_frame->cbase = node->nd_rval;
if (node->nd_tbl) {
- the_scope->local_vars = ALLOCA_N(VALUE, node->nd_tbl[0]);
+ VALUE *vars = ALLOCA_N(VALUE, node->nd_tbl[0]+1);
+ *vars++ = (VALUE)node;
+ the_scope->local_vars = vars;
memclear(the_scope->local_vars, node->nd_tbl[0]);
the_scope->local_tbl = node->nd_tbl;
}
@@ -1829,13 +2122,23 @@ module_setup(module, node)
PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
- rb_eval((VALUE)the_class, node->nd_body);
+ if (trace_func) {
+ call_trace_func("class", node->file, nd_line(node),
+ the_class, the_frame->last_func);
+ }
+ result = rb_eval((VALUE)the_class, node->nd_body);
}
POP_TAG();
POP_SCOPE();
POP_CLASS();
the_frame->cbase = save;
+ if (trace_func) {
+ call_trace_func("end", node->file, nd_line(node), 0,
+ the_frame->last_func);
+ }
if (state) JUMP_TAG(state);
+
+ return result;
}
int
@@ -1850,7 +2153,7 @@ rb_respond_to(obj, id)
}
static VALUE
-krn_respond_to(argc, argv, obj)
+obj_respond_to(argc, argv, obj)
int argc;
VALUE *argv;
VALUE obj;
@@ -1870,7 +2173,7 @@ static VALUE
mod_method_defined(mod, mid)
VALUE mod, mid;
{
- if (rb_method_boundp(mod, rb_to_id(mid), TRUE)) {
+ if (rb_method_boundp(mod, rb_to_id(mid), 1)) {
return TRUE;
}
return FALSE;
@@ -1882,7 +2185,7 @@ rb_exit(status)
{
if (prot_tag) {
exit_status = status;
- rb_raise(exc_new(eSystemExit, ""));
+ rb_raise(exc_new(eSystemExit, 0, 0));
}
exit(status);
}
@@ -1895,6 +2198,7 @@ f_exit(argc, argv, obj)
{
VALUE status;
+ rb_secure(2);
if (rb_scan_args(argc, argv, "01", &status) == 1) {
status = NUM2INT(status);
}
@@ -1905,6 +2209,17 @@ f_exit(argc, argv, obj)
/* not reached */
}
+static VALUE
+f_abort()
+{
+ rb_secure(2);
+ if (errinfo) {
+ error_print();
+ }
+ rb_exit(1);
+ /* not reached */
+}
+
void
rb_break()
{
@@ -1946,8 +2261,8 @@ rb_longjmp(tag, mesg)
int tag;
VALUE mesg;
{
- if (NIL_P(errat) && NIL_P(mesg)) {
- errinfo = exc_new(eRuntimeError, "");
+ if (NIL_P(errinfo) && NIL_P(mesg)) {
+ errinfo = exc_new(eRuntimeError, 0, 0);
}
if (sourcefile && (NIL_P(errat) || !NIL_P(mesg))) {
@@ -1959,7 +2274,7 @@ rb_longjmp(tag, mesg)
errinfo = mesg;
}
else {
- errinfo = exc_new2(eRuntimeError, mesg);
+ errinfo = exc_new3(eRuntimeError, mesg);
}
str_freeze(errinfo);
}
@@ -1984,7 +2299,7 @@ rb_fatal(mesg)
void
rb_interrupt()
{
- rb_raise(exc_new(eInterrupt, "Interrupt"));
+ Raise(eInterrupt, "");
}
static VALUE
@@ -1994,23 +2309,30 @@ f_raise(argc, argv)
{
VALUE arg1, arg2;
VALUE etype, mesg;
+ int n;
etype = eRuntimeError;
mesg = Qnil;
- switch (rb_scan_args(argc, argv, "02", &arg1, &arg2)) {
+ switch (n = rb_scan_args(argc, argv, "02", &arg1, &arg2)) {
case 1:
mesg = arg1;
break;
case 2:
etype = arg1;
+ if (obj_is_kind_of(etype, eGlobalExit)) {
+ etype = CLASS_OF(etype);
+ }
+ else {
+ Check_Type(etype, T_CLASS);
+ }
mesg = arg2;
break;
}
if (!NIL_P(mesg)) {
Check_Type(mesg, T_STRING);
- if (!obj_is_kind_of(mesg, eException)) {
- mesg = exc_new2(etype, mesg);
+ if (n == 2 || !obj_is_kind_of(mesg, eException)) {
+ mesg = exc_new3(etype, mesg);
}
}
@@ -2036,11 +2358,12 @@ f_iterator_p()
VALUE
rb_yield_0(val, self)
- VALUE val, self;
+ VALUE val;
+ volatile VALUE self;
{
NODE *node;
NODE *state;
- VALUE result = Qnil;
+ volatile VALUE result = Qnil;
struct BLOCK *block;
struct SCOPE *old_scope;
struct FRAME frame;
@@ -2064,9 +2387,9 @@ rb_yield_0(val, self)
node = block->body;
if (block->var) {
if (nd_type(block->var) == NODE_MASGN)
- masign(self, block->var, val);
+ massign(self, block->var, val);
else
- asign(self, block->var, val);
+ assign(self, block->var, val);
}
PUSH_ITER(block->iter);
PUSH_TAG();
@@ -2076,7 +2399,7 @@ rb_yield_0(val, self)
result = Qnil;
}
else if (nd_type(node) == NODE_CFUNC) {
- result = (*node->nd_cfnc)(val,node->nd_argc,self);
+ result = (*node->nd_cfnc)(val, node->nd_argc, self);
}
else {
result = rb_eval(self, node);
@@ -2085,9 +2408,11 @@ rb_yield_0(val, self)
else {
switch (state->nd_tag) {
case TAG_REDO:
+ state = 0;
goto redo;
case TAG_NEXT:
state = 0;
+ result = Qnil;
break;
case TAG_BREAK:
case TAG_RETURN:
@@ -2123,7 +2448,8 @@ f_loop()
}
static VALUE
-masign(self, node, val)
+massign(self, node, val)
+ VALUE self;
NODE *node;
VALUE val;
{
@@ -2138,30 +2464,30 @@ masign(self, node, val)
}
len = RARRAY(val)->len;
for (i=0; list && i<len; i++) {
- asign(self, list->nd_head, RARRAY(val)->ptr[i]);
+ assign(self, list->nd_head, RARRAY(val)->ptr[i]);
list = list->nd_next;
}
if (node->nd_args) {
if (!list && i<len) {
- asign(self, node->nd_args, ary_new4(len-i, RARRAY(val)->ptr+i));
+ assign(self, node->nd_args, ary_new4(len-i, RARRAY(val)->ptr+i));
}
else {
- asign(self, node->nd_args, ary_new2(0));
+ assign(self, node->nd_args, ary_new2(0));
}
}
}
else if (node->nd_args) {
- asign(self, node->nd_args, Qnil);
+ assign(self, node->nd_args, Qnil);
}
while (list) {
- asign(self, list->nd_head, Qnil);
+ assign(self, list->nd_head, Qnil);
list = list->nd_next;
}
return val;
}
static void
-asign(self, lhs, val)
+assign(self, lhs, val)
VALUE self;
NODE *lhs;
VALUE val;
@@ -2177,7 +2503,7 @@ asign(self, lhs, val)
case NODE_LASGN:
if (the_scope->local_vars == 0)
- Bug("unexpected iterator variable asignment");
+ Bug("unexpected iterator variable assignment");
the_scope->local_vars[lhs->nd_cnt] = val;
break;
@@ -2209,7 +2535,7 @@ asign(self, lhs, val)
break;
default:
- Bug("bug in variable asignment");
+ Bug("bug in variable assignment");
break;
}
}
@@ -2220,7 +2546,7 @@ rb_iterate(it_proc, data1, bl_proc, data2)
void *data1, *data2;
{
NODE *state;
- VALUE retval = Qnil;
+ volatile VALUE retval = Qnil;
NODE *node = NEW_CFUNC(bl_proc, data2);
VALUE self = TopSelf;
int tag_level;
@@ -2234,8 +2560,8 @@ rb_iterate(it_proc, data1, bl_proc, data2)
if (state == 0) {
retval = (*it_proc)(data1);
}
-
POP_TAG();
+
tag_level = the_block->level;
POP_BLOCK();
POP_ITER();
@@ -2276,9 +2602,12 @@ handle_rescue(self, node)
}
PUSH_ITER(ITER_NOT);
- SETUP_ARGS;
+ SETUP_ARGS(node->nd_args);
POP_ITER();
while (argc--) {
+ if (!obj_is_kind_of(argv[0], cModule)) {
+ TypeError("class or module required for rescue clause");
+ }
if (obj_is_kind_of(errinfo, argv[0])) return 1;
argv++;
}
@@ -2291,7 +2620,7 @@ rb_rescue(b_proc, data1, r_proc, data2)
void *data1, *data2;
{
NODE *state;
- VALUE result;
+ volatile VALUE result;
PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
@@ -2302,8 +2631,7 @@ rb_rescue(b_proc, data1, r_proc, data2)
if (state->nd_tag == TAG_RAISE) {
if (r_proc) {
PUSH_TAG();
- state = EXEC_TAG();
- if (state == 0) {
+ if ((state = EXEC_TAG()) == 0) {
result = (*r_proc)(data2, errinfo);
}
POP_TAG();
@@ -2333,7 +2661,7 @@ rb_ensure(b_proc, data1, e_proc, data2)
void *data1, *data2;
{
NODE *state;
- VALUE result = Qnil;
+ volatile VALUE result = Qnil;
PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
@@ -2348,7 +2676,9 @@ rb_ensure(b_proc, data1, e_proc, data2)
return result;
}
-static int last_noex;
+static int last_call_status;
+#define CSTAT_NOEX 1
+#define CSTAT_VCALL 2
static VALUE
f_missing(argc, argv, obj)
@@ -2358,8 +2688,9 @@ f_missing(argc, argv, obj)
{
VALUE desc = 0;
ID id;
- char *format;
- struct FRAME *frame;
+ char *format = 0;
+ char *file = sourcefile;
+ int line = sourceline;
id = FIX2INT(argv[0]);
argc--; argv++;
@@ -2382,36 +2713,48 @@ f_missing(argc, argv, obj)
break;
}
if (desc) {
- if (last_noex)
+ if (last_call_status & CSTAT_NOEX) {
format = "private method `%s' called for %s(%s)";
- else if (argc == 0) {
- format = "undefined local variable or method `%s' for %s(%s)";
}
- else {
+ else if (iterator_p()) {
+ format = "undefined iterator `%s' for %s(%s)";
+ }
+ else if (last_call_status & CSTAT_VCALL) {
+ char *mname = rb_id2name(id);
+
+ if (('a' <= mname[0] && mname[0] <= 'z') || mname[0] == '_') {
+ format = "undefined local variable or method `%s' for %s(%s)";
+ }
+ }
+ if (!format) {
format = "undefined method `%s' for %s(%s)";
}
if (RSTRING(desc)->len > 65) {
- desc = krn_to_s(obj);
+ desc = any_to_s(obj);
}
}
+ sourcefile = file;
+ sourceline = line;
PUSH_FRAME(); /* fake frame */
*the_frame = *_frame.prev->prev;
NameError(format,
rb_id2name(id),
- desc?RSTRING(desc)->ptr:"",
+ desc?(char*)RSTRING(desc)->ptr:"",
desc?rb_class2name(CLASS_OF(obj)):"");
POP_FRAME();
+
+ return Qnil; /* not reached */
}
static VALUE
-rb_undefined(obj, id, argc, argv, noex)
+rb_undefined(obj, id, argc, argv, call_status)
VALUE obj;
ID id;
int argc;
VALUE*argv;
- int noex;
+ int call_status;
{
VALUE *nargv;
@@ -2419,12 +2762,21 @@ rb_undefined(obj, id, argc, argv, noex)
nargv[0] = INT2FIX(id);
MEMCPY(nargv+1, argv, VALUE, argc);
- last_noex = noex;
+ last_call_status = call_status;
return rb_funcall2(obj, rb_intern("method_missing"), argc+1, nargv);
}
-#define STACK_LEVEL_MAX 655350
+#ifdef DJGPP
+# define STACK_LEVEL_MAX 65535
+#else
+#ifdef __human68k__
+extern int _stacksize;
+# define STACK_LEVEL_MAX (_stacksize - 4096)
+#else
+# define STACK_LEVEL_MAX 655350
+#endif
+#endif
extern VALUE *gc_stack_start;
static int
stack_length()
@@ -2444,19 +2796,20 @@ rb_call(class, recv, mid, argc, argv, scope)
struct RClass *class;
VALUE recv;
ID mid;
- int argc;
- VALUE *argv;
+ int argc; /* OK */
+ VALUE *argv; /* OK */
int scope;
{
- NODE *body;
+ NODE *body, *b2; /* OK */
int noex;
ID id = mid;
struct cache_entry *ent;
- VALUE result = Qnil;
+ volatile VALUE result = Qnil;
int itr;
enum node_type type;
static int tick;
+ again:
/* is it in the method cache? */
ent = cache + EXPR1(class, mid);
if (ent->mid == mid && ent->class == class) {
@@ -2466,12 +2819,12 @@ rb_call(class, recv, mid, argc, argv, scope)
body = ent->method;
}
else if ((body = rb_get_method_body(&class, &id, &noex)) == 0) {
- return rb_undefined(recv, mid, argc, argv, 0);
+ return rb_undefined(recv, mid, argc, argv, scope==2?CSTAT_VCALL:0);
}
/* receiver specified form for private method */
if (noex == NOEX_PRIVATE && scope == 0)
- return rb_undefined(recv, mid, argc, argv, 1);
+ return rb_undefined(recv, mid, argc, argv, CSTAT_NOEX);
switch (the_iter->iter) {
case ITER_PRE:
@@ -2485,11 +2838,27 @@ rb_call(class, recv, mid, argc, argv, scope)
type = nd_type(body);
if (type == NODE_ZSUPER) {
- /* for re-scoped method */
- return rb_call(class->super, recv, id, argc, argv, scope?scope:1);
+ /* for re-scoped/renamed method */
+ mid = id;
+ if (scope == 0) scope = 1;
+ if (class->super == 0) {
+ /* origin is the Module, so need to scan superclass hierarchy. */
+ struct RClass *cl = class;
+
+ class = (struct RClass*)RBASIC(recv)->class;
+ while (class) {
+ if (class->m_tbl == cl->m_tbl)
+ break;
+ class = class->super;
+ }
+ }
+ else {
+ class = class->super;
+ }
+ goto again;
}
- if (++tick % 1000 == 0 && stack_length() > STACK_LEVEL_MAX)
+ if ((++tick & 0xfff) == 0 && stack_length() > STACK_LEVEL_MAX)
Fatal("stack level too deep");
PUSH_ITER(itr);
@@ -2602,7 +2971,7 @@ rb_call(class, recv, mid, argc, argv, scope)
default:
if (len < 0) {
Bug("bad argc(%d) specified for `%s(%s)'",
- len, rb_class2name(class), rb_id2name(mid));
+ len, rb_class2name((VALUE)class), rb_id2name(mid));
}
else {
ArgError("too many arguments(%d)", len);
@@ -2627,7 +2996,8 @@ rb_call(class, recv, mid, argc, argv, scope)
if (body->nd_rval) the_frame->cbase = body->nd_rval;
if (body->nd_tbl) {
- local_vars = ALLOCA_N(VALUE, body->nd_tbl[0]);
+ local_vars = ALLOCA_N(VALUE, body->nd_tbl[0]+1);
+ *local_vars++ = (VALUE)body;
memclear(local_vars, body->nd_tbl[0]);
the_scope->local_tbl = body->nd_tbl;
the_scope->local_vars = local_vars;
@@ -2636,13 +3006,12 @@ rb_call(class, recv, mid, argc, argv, scope)
local_vars = the_scope->local_vars = 0;
the_scope->local_tbl = 0;
}
- body = body->nd_body;
+ b2 = body = body->nd_body;
PUSH_TAG();
PUSH_VARS();
- dyna_var_mark();
- state = EXEC_TAG();
- if (state == 0) {
+
+ if ((state = EXEC_TAG()) == 0) {
if (nd_type(body) == NODE_BLOCK) {
NODE *node = body->nd_head;
int i;
@@ -2653,11 +3022,22 @@ rb_call(class, recv, mid, argc, argv, scope)
body = body->nd_next;
i = node->nd_cnt;
- if (i > argc
- || (node->nd_rest == -1
- && i+(node->nd_opt?node->nd_opt->nd_alen:0)<argc)){
+ if (i > argc) {
ArgError("Wrong # of arguments(%d for %d)", argc, i);
}
+ if (node->nd_rest == -1) {
+ int opt = argc - i;
+ NODE *optnode = node->nd_opt;
+
+ while (optnode) {
+ opt--;
+ optnode = optnode->nd_next;
+ }
+ if (opt > 0) {
+ ArgError("Wrong # of arguments(%d for %d)",
+ argc, argc-opt);
+ }
+ }
if (local_vars) {
if (i > 0) {
@@ -2668,7 +3048,7 @@ rb_call(class, recv, mid, argc, argv, scope)
NODE *opt = node->nd_opt;
while (opt && argc) {
- asign(recv, opt->nd_head, *argv);
+ assign(recv, opt->nd_head, *argv);
argv++; argc--;
opt = opt->nd_next;
}
@@ -2685,11 +3065,24 @@ rb_call(class, recv, mid, argc, argv, scope)
else if (nd_type(body) == NODE_ARGS) {
body = 0;
}
+ if (trace_func) {
+ call_trace_func("call", b2->file, nd_line(b2),
+ recv, the_frame->last_func);
+ }
result = rb_eval(recv, body);
}
POP_VARS();
POP_TAG();
POP_SCOPE();
+ if (trace_func) {
+ char *file = the_frame->prev->file;
+ int line = the_frame->prev->line;
+ if (!file) {
+ file = sourcefile;
+ line = sourceline;
+ }
+ call_trace_func("return", file, line, 0, the_frame->last_func);
+ }
if (state) {
switch (state->nd_tag) {
case TAG_NEXT:
@@ -2752,7 +3145,11 @@ f_send(argc, argv, recv)
else {
mid = NUM2INT(vid);
}
- return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 1);
+ PUSH_ITER(iterator_p()?ITER_PRE:ITER_NOT);
+ vid = rb_call(CLASS_OF(recv), recv, mid, argc, argv, 1);
+ POP_ITER();
+
+ return vid;
}
#include <varargs.h>
@@ -2802,7 +3199,9 @@ backtrace(lev)
struct FRAME *frame = the_frame;
char buf[BUFSIZ];
VALUE ary;
+ int slev = safe_level;
+ safe_level = 0;
ary = ary_new();
if (lev < 0) {
if (frame->last_func) {
@@ -2832,6 +3231,7 @@ backtrace(lev)
ary_push(ary, str_new2(buf));
frame = frame->prev;
}
+ safe_level = slev;
return ary;
}
@@ -2841,7 +3241,6 @@ f_caller(argc, argv)
VALUE *argv;
{
VALUE level;
- struct FRAME *frame = the_frame;
int lev;
rb_scan_args(argc, argv, "01", &level);
@@ -2857,12 +3256,12 @@ void
rb_backtrace()
{
int i, lev;
- VALUE ary, c;
+ VALUE ary;
lev = INT2FIX(0);
ary = backtrace(-1);
for (i=0; i<RARRAY(ary)->len; i++) {
- printf("\tfrom %s\n", RSTRING(RARRAY(ary)->ptr)->ptr);
+ printf("\tfrom %s\n", RSTRING(RARRAY(ary)->ptr[i])->ptr);
}
}
@@ -2889,15 +3288,12 @@ compile(src)
Check_Type(src, T_STRING);
- errinfo = Qnil;
node = compile_string(sourcefile, src->ptr, src->len);
if (nerrs == 0) return node;
return 0;
}
-static void blk_free();
-
static VALUE
eval(self, src, scope)
VALUE self;
@@ -2905,57 +3301,70 @@ eval(self, src, scope)
struct RData *scope;
{
struct BLOCK *data;
- VALUE result = Qnil;
- NODE *node;
+ volatile VALUE result = Qnil;
NODE *state;
- struct BLOCK *old_block;
- struct SCOPE *old_scope;
+ volatile VALUE old_block;
+ volatile VALUE old_scope;
+ volatile VALUE old_d_vars;
struct FRAME frame;
char *file = sourcefile;
int line = sourceline;
+ volatile int iter = the_frame->iter;
- PUSH_TAG();
- PUSH_CLASS();
if (!NIL_P(scope)) {
if (TYPE(scope) != T_DATA || scope->dfree != blk_free) {
TypeError("wrong argument type %s (expected Proc/Binding)",
rb_class2name(CLASS_OF(scope)));
}
- Get_Data_Struct(scope, struct BLOCK, data);
+ Data_Get_Struct(scope, struct BLOCK, data);
/* PUSH BLOCK from data */
frame = data->frame;
frame.prev = the_frame;
the_frame = &(frame);
- old_scope = the_scope;
+ old_scope = (VALUE)the_scope;
the_scope = data->scope;
- old_block = the_block;
+ old_block = (VALUE)the_block;
the_block = data->prev;
+ old_d_vars = (VALUE)the_dyna_vars;
the_dyna_vars = data->d_vars;
- the_class = data->class;
+
self = data->self;
+ the_frame->iter = data->iter;
+ }
+ else {
+ if (the_frame->prev) {
+ the_frame->iter = the_frame->prev->iter;
+ }
}
+ PUSH_CLASS();
+ the_class = (struct RClass*)((NODE*)the_frame->cbase)->nd_clss;
rb_in_eval++;
if (TYPE(the_class) == T_ICLASS) {
the_class = (struct RClass*)RBASIC(the_class)->class;
}
+ PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
- if (!compile(src)) {
- rb_in_eval--;
+ compile(src);
+ if (nerrs > 0) {
compile_error("eval()");
}
result = eval_node(self);
}
+ POP_TAG();
+ POP_CLASS();
+ rb_in_eval--;
if (!NIL_P(scope)) {
the_frame = the_frame->prev;
- the_scope = old_scope;
- the_block = old_block;
+ the_scope = (struct SCOPE*)old_scope;
+ the_block = (struct BLOCK*)old_block;
+ the_dyna_vars = (struct RVarmap*)old_d_vars;
+ }
+ else {
+ the_frame->iter = iter;
}
- POP_CLASS();
- POP_TAG();
- rb_in_eval--;
if (state) {
VALUE err ;
@@ -2964,13 +3373,14 @@ eval(self, src, scope)
sourcefile = file;
sourceline = line;
if (strcmp(sourcefile, "(eval)") == 0) {
- err = errat;
- if (sourceline != 1) {
+ err = errinfo;
+ if (sourceline > 1) {
+ err = RARRAY(errat)->ptr[0];
str_cat(err, ": ", 2);
str_cat(err, RSTRING(errinfo)->ptr, RSTRING(errinfo)->len);
}
errat = Qnil;
- rb_raise(exc_new2(CLASS_OF(errinfo), err));
+ rb_raise(exc_new3(CLASS_OF(errinfo), err));
}
rb_raise(Qnil);
}
@@ -2989,6 +3399,8 @@ f_eval(argc, argv, self)
VALUE src, scope;
rb_scan_args(argc, argv, "11", &src, &scope);
+
+ Check_SafeStr(src);
return eval(self, src, scope);
}
@@ -3005,10 +3417,24 @@ find_file(file)
char *path;
if (file[0] == '/') return file;
+#if defined(MSDOS) || defined(NT) || defined(__human68k__)
+ if (file[0] == '\\') return file;
+ if (file[1] == ':') return file;
+#endif
if (rb_load_path) {
+ int i;
+
Check_Type(rb_load_path, T_ARRAY);
+ for (i=0;i<RARRAY(rb_load_path)->len;i++) {
+ Check_SafeStr(RARRAY(rb_load_path)->ptr[i]);
+ }
+#if !defined(MSDOS) && !defined(NT) && !defined(__human68k__)
vpath = ary_join(rb_load_path, str_new2(":"));
+#else
+ vpath = ary_join(rb_load_path, str_new2(";"));
+#endif
+ Check_SafeStr(vpath);
path = RSTRING(vpath)->ptr;
}
else {
@@ -3024,10 +3450,13 @@ f_load(obj, fname)
struct RString *fname;
{
NODE *state;
- char *file, *src;
+ char *file;
volatile ID last_func;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
+ if (fname->ptr[0] == '~') {
+ fname = (struct RString*)file_s_expand_path(0, fname);
+ }
file = find_file(fname->ptr);
if (!file) LoadError("No such file to load -- %s", fname->ptr);
@@ -3035,8 +3464,16 @@ f_load(obj, fname)
PUSH_CLASS();
the_class = (struct RClass*)cObject;
PUSH_SCOPE();
- the_scope->local_vars = top_scope->local_vars;
- the_scope->local_tbl = top_scope->local_tbl;
+ if (top_scope->local_tbl) {
+ int len = top_scope->local_tbl[0]+1;
+ ID *tbl = ALLOC_N(ID, len);
+ VALUE *vars = ALLOCA_N(VALUE, len);
+ *vars++ = 0;
+ MEMCPY(tbl, top_scope->local_tbl, ID, len);
+ MEMCPY(vars, top_scope->local_vars, ID, len-1);
+ the_scope->local_tbl = tbl;
+ the_scope->local_vars = vars;
+ }
state = EXEC_TAG();
last_func = the_frame->last_func;
@@ -3050,7 +3487,9 @@ f_load(obj, fname)
}
}
the_frame->last_func = last_func;
- top_scope->flag = the_scope->flag;
+ if (the_scope->flag == SCOPE_ALLOCA && the_scope->local_tbl) {
+ free(the_scope->local_tbl);
+ }
POP_SCOPE();
POP_CLASS();
POP_TAG();
@@ -3108,9 +3547,9 @@ f_require(obj, fname)
struct RString *fname;
{
char *ext, *file, *feature, *buf;
- VALUE load;
+ volatile VALUE load;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (rb_provided(fname->ptr))
return FALSE;
@@ -3216,7 +3655,7 @@ mod_public(argc, argv, module)
VALUE module;
{
set_method_visibility(module, argc, argv, NOEX_PUBLIC);
- return Qnil;
+ return module;
}
static VALUE
@@ -3226,7 +3665,27 @@ mod_private(argc, argv, module)
VALUE module;
{
set_method_visibility(module, argc, argv, NOEX_PRIVATE);
- return Qnil;
+ return module;
+}
+
+static VALUE
+mod_public_method(argc, argv, obj)
+ int argc;
+ VALUE *argv;
+ VALUE obj;
+{
+ set_method_visibility(CLASS_OF(obj), argc, argv, NOEX_PUBLIC);
+ return obj;
+}
+
+static VALUE
+mod_private_method(argc, argv, obj)
+ int argc;
+ VALUE *argv;
+ VALUE obj;
+{
+ set_method_visibility(CLASS_OF(obj), argc, argv, NOEX_PRIVATE);
+ return obj;
}
static VALUE
@@ -3237,8 +3696,9 @@ mod_modfunc(argc, argv, module)
{
int i;
ID id;
- NODE *body, *old;
+ NODE *body;
+ rb_clear_cache();
set_method_visibility(module, argc, argv, NOEX_PRIVATE);
for (i=0; i<argc; i++) {
id = rb_to_id(argv[i]);
@@ -3249,14 +3709,14 @@ mod_modfunc(argc, argv, module)
}
rb_add_method(rb_singleton_class(module), id, body->nd_body, NOEX_PUBLIC);
}
- return Qnil;
+ return module;
}
static VALUE
mod_include(argc, argv, module)
int argc;
VALUE *argv;
- struct RClass *module;
+ VALUE module;
{
int i;
@@ -3264,10 +3724,10 @@ mod_include(argc, argv, module)
Check_Type(argv[i], T_MODULE);
rb_include_module(module, argv[i]);
}
- return Qnil;
+ return module;
}
-VALUE /* moved from object.c for push_iter */
+VALUE
class_s_new(argc, argv, class)
int argc;
VALUE *argv;
@@ -3275,6 +3735,29 @@ class_s_new(argc, argv, class)
{
VALUE obj = obj_alloc(class);
+ if (FL_TEST(class, FL_SINGLETON)) {
+ TypeError("can't create instance of virtual class");
+ }
+ obj = obj_alloc(class);
+ PUSH_ITER(iterator_p()?ITER_PRE:ITER_NOT);
+ rb_funcall2(obj, init, argc, argv);
+ POP_ITER();
+ return obj;
+}
+
+
+VALUE
+class_new_instance(argc, argv, class)
+ int argc;
+ VALUE *argv;
+ VALUE class;
+{
+ VALUE obj;
+
+ if (FL_TEST(class, FL_SINGLETON)) {
+ TypeError("can't create instance of virtual class");
+ }
+ obj = obj_alloc(class);
PUSH_ITER(iterator_p()?ITER_PRE:ITER_NOT);
rb_funcall2(obj, init, argc, argv);
POP_ITER();
@@ -3286,9 +3769,25 @@ top_include(argc, argv)
int argc;
VALUE *argv;
{
+ rb_secure(4);
return mod_include(argc, argv, cObject);
}
+void
+rb_extend_object(obj, module)
+ VALUE obj, module;
+{
+ rb_include_module(rb_singleton_class(obj), module);
+}
+
+static VALUE
+mod_extend_object(mod, obj)
+ VALUE mod, obj;
+{
+ rb_extend_object(obj, mod);
+ return obj;
+}
+
static VALUE
obj_extend(argc, argv, obj)
int argc;
@@ -3297,41 +3796,43 @@ obj_extend(argc, argv, obj)
{
int i;
- mod_include(argc, argv, rb_singleton_class(obj));
+ for (i=0; i<argc; i++) Check_Type(argv[i], T_MODULE);
for (i=0; i<argc; i++) {
- rb_funcall(argv[i], rb_intern("object_extended"), 1, obj);
+ rb_funcall(argv[i], rb_intern("extend_object"), 1, obj);
}
- return Qnil;
-}
-
-void
-rb_extend_object(obj, module)
- VALUE obj, module;
-{
- rb_include_module(rb_singleton_class(obj), module);
+ return obj;
}
-extern VALUE cModule;
-
VALUE f_trace_var();
VALUE f_untrace_var();
-extern VALUE rb_str_setter();
+extern void rb_str_setter();
-static VALUE
+static void
errat_setter(val, id, var)
VALUE val;
ID id;
VALUE *var;
{
- if (!NIL_P(val) && TYPE(val) != T_ARRAY) {
- TypeError("value of $@ must be Array of String");
+ int i;
+ static char *err = "value of $@ must be Array of String";
+
+ if (!NIL_P(val)) {
+ if (TYPE(val) != T_ARRAY) {
+ TypeError(err);
+ }
+ for (i=0;i<RARRAY(val)->len;i++) {
+ if (TYPE(RARRAY(val)->ptr[i]) != T_STRING) {
+ TypeError(err);
+ }
+ }
}
- return *var = val;
+ *var = val;
}
static VALUE
f_catch(dmy, tag)
+ VALUE dmy, tag;
{
NODE *state;
ID t;
@@ -3383,45 +3884,53 @@ Init_eval()
rb_define_hooked_variable("$@", &errat, 0, errat_setter);
rb_define_hooked_variable("$!", &errinfo, 0, rb_str_setter);
- rb_define_private_method(cKernel, "eval", f_eval, -1);
- rb_define_private_method(cKernel, "iterator?", f_iterator_p, 0);
- rb_define_private_method(cKernel, "method_missing", f_missing, -1);
- rb_define_private_method(cKernel, "loop", f_loop, 0);
+ rb_define_global_function("eval", f_eval, -1);
+ rb_define_global_function("iterator?", f_iterator_p, 0);
+ rb_define_global_function("method_missing", f_missing, -1);
+ rb_define_global_function("loop", f_loop, 0);
- rb_define_method(cKernel, "respond_to?", krn_respond_to, -1);
+ rb_define_method(mKernel, "respond_to?", obj_respond_to, -1);
- rb_define_private_method(cKernel, "break", f_break, 0);
- rb_define_alias(cKernel, "break!", "break");
- rb_define_private_method(cKernel, "next", f_next, 0);
- rb_define_alias(cKernel, "next!", "next");
- rb_define_alias(cKernel, "continue", "next");
- rb_define_private_method(cKernel, "redo", f_redo, 0);
- rb_define_alias(cKernel, "redo!", "redo");
- rb_define_private_method(cKernel, "retry", f_retry, 0);
- rb_define_alias(cKernel, "retry!", "retry");
- rb_define_private_method(cKernel, "raise", f_raise, -1);
- rb_define_alias(cKernel, "fail", "raise");
+ rb_define_global_function("break", f_break, 0);
+ rb_define_alias(mKernel, "break!", "break");
+ rb_define_global_function("next", f_next, 0);
+ rb_define_alias(mKernel, "next!", "next");
+ rb_define_alias(mKernel, "continue", "next");
+ rb_define_global_function("redo", f_redo, 0);
+ rb_define_alias(mKernel, "redo!", "redo");
+ rb_define_global_function("retry", f_retry, 0);
+ rb_define_alias(mKernel, "retry!", "retry");
+ rb_define_global_function("raise", f_raise, -1);
+ rb_define_alias(mKernel, "fail", "raise");
- rb_define_private_method(cKernel, "caller", f_caller, -1);
+ rb_define_global_function("caller", f_caller, -1);
- rb_define_private_method(cKernel, "exit", f_exit, -1);
+ rb_define_global_function("exit", f_exit, -1);
+ rb_define_global_function("abort", f_abort, 0);
- rb_define_private_method(cKernel, "catch", f_catch, 1);
- rb_define_private_method(cKernel, "throw", f_throw, -1);
+ rb_define_global_function("catch", f_catch, 1);
+ rb_define_global_function("throw", f_throw, -1);
- rb_define_method(cKernel, "send", f_send, -1);
+ rb_define_method(mKernel, "send", f_send, -1);
- rb_define_method(cModule, "include", mod_include, -1);
- rb_define_method(cModule, "public", mod_public, -1);
- rb_define_method(cModule, "private", mod_private, -1);
- rb_define_method(cModule, "module_function", mod_modfunc, -1);
+ rb_define_private_method(cModule, "include", mod_include, -1);
+ rb_define_private_method(cModule, "public", mod_public, -1);
+ rb_define_private_method(cModule, "private", mod_private, -1);
+ rb_define_private_method(cModule, "module_function", mod_modfunc, -1);
rb_define_method(cModule, "method_defined?", mod_method_defined, 1);
+ rb_define_method(cModule, "extend_object", mod_extend_object, 1);
+ rb_define_method(cModule, "public_class_method", mod_public_method, -1);
+ rb_define_method(cModule, "private_class_method", mod_private_method, -1);
rb_define_method(CLASS_OF(TopSelf), "include", top_include, -1);
- rb_define_method(cObject, "extend", obj_extend, -1);
+ rb_define_method(mKernel, "extend", obj_extend, -1);
- rb_define_private_method(cKernel, "trace_var", f_trace_var, -1);
- rb_define_private_method(cKernel, "untrace_var", f_untrace_var, -1);
+ rb_define_global_function("trace_var", f_trace_var, -1);
+ rb_define_global_function("untrace_var", f_untrace_var, -1);
+
+ rb_define_global_function("set_trace_func", set_trace_func, 1);
+
+ rb_define_virtual_variable("$SAFE", safe_getter, safe_setter);
}
VALUE f_autoload();
@@ -3431,14 +3940,15 @@ Init_load()
{
rb_load_path = ary_new();
rb_define_readonly_variable("$:", &rb_load_path);
+ rb_define_readonly_variable("$-I", &rb_load_path);
rb_define_readonly_variable("$LOAD_PATH", &rb_load_path);
rb_features = ary_new();
rb_define_readonly_variable("$\"", &rb_features);
- rb_define_private_method(cKernel, "load", f_load, 1);
- rb_define_private_method(cKernel, "require", f_require, 1);
- rb_define_private_method(cKernel, "autoload", f_autoload, 2);
+ rb_define_global_function("load", f_load, 1);
+ rb_define_global_function("require", f_require, 1);
+ rb_define_global_function("autoload", f_autoload, 2);
}
static void
@@ -3448,17 +3958,19 @@ scope_dup(scope)
ID *tbl;
VALUE *vars;
- if (scope->flag == SCOPE_MALLOC) return;
+ if (scope->flag & SCOPE_MALLOC) return;
if (scope->local_tbl) {
tbl = scope->local_tbl;
- scope->local_tbl = ALLOC_N(ID, tbl[0]+1);
- MEMCPY(scope->local_tbl, tbl, ID, tbl[0]+1);
- vars = scope->local_vars;
- scope->local_vars = ALLOC_N(VALUE, tbl[0]);
- MEMCPY(scope->local_vars, vars, VALUE, tbl[0]);
+ vars = ALLOC_N(VALUE, tbl[0]+1);
+ *vars++ = scope->local_vars[-1];
+ MEMCPY(vars, scope->local_vars, VALUE, tbl[0]);
+ scope->local_vars = vars;
scope->flag = SCOPE_MALLOC;
}
+ else {
+ scope->flag = SCOPE_NOSTACK;
+ }
}
static void
@@ -3484,15 +3996,14 @@ static VALUE
f_binding(self)
VALUE self;
{
- extern VALUE cData;
struct BLOCK *data;
VALUE bind;
PUSH_BLOCK(0,0);
- bind = Make_Data_Struct(cData, struct BLOCK, blk_mark, blk_free, data);
+ bind = Data_Make_Struct(cData, struct BLOCK, blk_mark, blk_free, data);
MEMCPY(data, the_block, struct BLOCK, 1);
- data->iter = ITER_NOT;
+ data->iter = f_iterator_p();
data->frame.last_func = 0;
data->frame.argv = ALLOC_N(VALUE, data->frame.argc);
MEMCPY(data->frame.argv, the_block->frame.argv, VALUE, data->frame.argc);
@@ -3503,6 +4014,12 @@ f_binding(self)
return bind;
}
+#define PROC_TAINT FL_USER0
+#define PROC_T3 FL_USER1
+#define PROC_T4 FL_USER2
+#define PROC_T5 (FL_USER1|FL_USER2)
+#define PROC_TMASK (FL_USER1|FL_USER2)
+
static VALUE
proc_s_new(class)
VALUE class;
@@ -3514,14 +4031,31 @@ proc_s_new(class)
ArgError("tryed to create Procedure-Object out of iterator");
}
- proc = Make_Data_Struct(class, struct BLOCK, blk_mark, blk_free, data);
+ proc = Data_Make_Struct(class, struct BLOCK, blk_mark, blk_free, data);
*data = *the_block;
- data->iter = ITER_NOT;
+#ifdef THREAD
+ data->orig_thread = thread_current();
+#endif
+ data->iter = f_iterator_p();
data->frame.argv = ALLOC_N(VALUE, data->frame.argc);
MEMCPY(data->frame.argv, the_block->frame.argv, VALUE, data->frame.argc);
scope_dup(data->scope);
+ if (safe_level >= 3) {
+ FL_SET(proc, PROC_TAINT);
+ switch (safe_level) {
+ case 3:
+ FL_SET(proc, PROC_T3);
+ break;
+ case 4:
+ FL_SET(proc, PROC_T4);
+ break;
+ case 5:
+ FL_SET(proc, PROC_T5);
+ break;
+ }
+ }
return proc;
}
@@ -3537,9 +4071,11 @@ proc_call(proc, args)
VALUE proc, args;
{
struct BLOCK *data;
- VALUE result = Qnil;
+ volatile VALUE result = Qnil;
NODE *state;
int tag_level;
+ volatile int orphan;
+ volatile int safe = safe_level;
if (TYPE(args) == T_ARRAY) {
switch (RARRAY(args)->len) {
@@ -3552,14 +4088,48 @@ proc_call(proc, args)
}
}
- Get_Data_Struct(proc, struct BLOCK, data);
+ Data_Get_Struct(proc, struct BLOCK, data);
+
+ if (data->scope && (data->scope->flag & SCOPE_NOSTACK)) {
+ orphan = 1;
+ }
+ else {
+#ifdef THREAD
+ if (data->orig_thread != thread_current()) {
+ orphan = 1;
+ }
+ else
+#endif
+ orphan = 0;
+ }
+ if (orphan) {/* orphan procedure */
+ if (iterator_p()) {
+ data->frame.iter = ITER_CUR;
+ }
+ else {
+ data->frame.iter = ITER_NOT;
+ }
+ }
/* PUSH BLOCK from data */
PUSH_BLOCK2(data);
PUSH_ITER(ITER_CUR);
the_frame->iter = ITER_CUR;
- PUSH_TAG();
+ if (FL_TEST(proc, PROC_TAINT)) {
+ switch (RBASIC(proc)->flags & PROC_TMASK) {
+ case PROC_T3:
+ safe_level = 3;
+ break;
+ case PROC_T4:
+ safe_level = 4;
+ break;
+ case PROC_T5:
+ safe_level = 5;
+ break;
+ }
+ }
+ PUSH_TAG();
state = EXEC_TAG();
if (state == 0) {
result = rb_yield(args);
@@ -3569,15 +4139,14 @@ proc_call(proc, args)
POP_ITER();
tag_level = the_block->level;
POP_BLOCK();
+ safe_level = safe;
if (state) {
- if (data->scope && (data->scope->flag & SCOPE_NOSTACK)) {
- /* orphan procedure */
+ if (orphan) {/* orphan procedure */
switch (state->nd_tag) {
case TAG_BREAK: /* never happen */
- break;
case IN_BLOCK|TAG_BREAK:
- if (state->nd_tlev != tag_level)
+ if (state->nd_tlev == tag_level)
Raise(eLocalJumpError, "break from proc-closure");
break;
case TAG_RETRY:
@@ -3585,11 +4154,12 @@ proc_call(proc, args)
break;
case TAG_RETURN: /* never happen */
case IN_BLOCK|TAG_RETURN:
- Raise(eLocalJumpError, "return from proc-closure");
+ if (state->nd_tlev == tag_level)
+ Raise(eLocalJumpError, "return from proc-closure");
break;
}
}
- else {
+ else if (state->nd_tlev == tag_level) {
state->nd_tag &= ~IN_BLOCK;
}
JUMP_TAG(state);
@@ -3606,26 +4176,37 @@ Init_Proc()
rb_define_singleton_method(cProc, "new", proc_s_new, 0);
rb_define_method(cProc, "call", proc_call, -2);
- rb_define_private_method(cKernel, "proc", f_lambda, 0);
- rb_define_private_method(cKernel, "lambda", f_lambda, 0);
- rb_define_private_method(cKernel, "binding", f_binding, 0);
+ rb_define_global_function("proc", f_lambda, 0);
+ rb_define_global_function("lambda", f_lambda, 0);
+ rb_define_global_function("binding", f_binding, 0);
}
#ifdef THREAD
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
+static VALUE eThreadError;
int thread_pending = 0;
static VALUE cThread;
#include <sys/types.h>
-#include <sys/time.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#else
+#ifndef NT
+struct timeval {
+ long tv_sec; /* seconds */
+ long tv_usec; /* and microseconds */
+};
+#endif /* NT */
+#endif
#include <signal.h>
#include <errno.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
extern VALUE last_status;
enum thread_status {
@@ -3647,8 +4228,6 @@ typedef struct thread * thread_t;
struct thread {
struct thread *next, *prev;
jmp_buf context;
- VALUE (*func)();
- void *arg;
VALUE result;
@@ -3665,6 +4244,8 @@ struct thread {
struct iter *iter;
struct tag *tag;
+ VALUE trace;
+
char *file;
int line;
@@ -3673,11 +4254,16 @@ struct thread {
VALUE last_line;
VALUE last_match;
+ int safe;
+
enum thread_status status;
int wait_for;
int fd;
double delay;
thread_t join;
+
+ int abort;
+
VALUE thread;
};
@@ -3686,10 +4272,11 @@ static int num_waiting_on_fd;
static int num_waiting_on_timer;
static int num_waiting_on_join;
-thread_curr() {return (int)curr_thread;}
+#define FOREACH_THREAD_FROM(f,x) x = f; do { x = x->next;
+#define END_FOREACH_FROM(f,x) } while (x != f)
-#define FOREACH_THREAD(x) x = curr_thread; do { x = x->next;
-#define END_FOREACH(x) } while (x != curr_thread)
+#define FOREACH_THREAD(x) FOREACH_THREAD_FROM(curr_thread,x)
+#define END_FOREACH(x) END_FOREACH_FROM(curr_thread,x)
/* Return the current time as a floating-point number */
static double
@@ -3713,10 +4300,12 @@ thread_mark(th)
struct BLOCK *block;
gc_mark(th->result);
- gc_mark_locations(th->stk_ptr, th->stk_ptr+th->stk_len);
-#ifdef THINK_C
- gc_mark_locations(th->stk_ptr+2, th->stk_ptr+th->stk_len+2);
+ if (th->stk_ptr) {
+ gc_mark_locations(th->stk_ptr, th->stk_ptr+th->stk_len);
+#if defined(THINK_C) || defined(__human68k__)
+ gc_mark_locations(th->stk_ptr+2, th->stk_ptr+th->stk_len+2);
#endif
+ }
gc_mark(th->thread);
if (th->join) gc_mark(th->join->thread);
@@ -3780,7 +4369,7 @@ void lastline_set();
VALUE backref_get();
void backref_set();
-static int
+static void
thread_save_context(th)
thread_t th;
{
@@ -3808,7 +4397,9 @@ thread_save_context(th)
th->last_status = last_status;
th->last_line = lastline_get();
th->last_match = backref_get();
+ th->safe = safe_level;
+ th->trace = trace_func;
th->file = sourcefile;
th->line = sourceline;
}
@@ -3826,6 +4417,11 @@ stack_extend(th, exit)
thread_restore_context(th, exit);
}
+static int th_raise_argc;
+static VALUE th_raise_argv[2];
+static char *th_raise_file;
+static int th_raise_line;
+
static void
thread_restore_context(th, exit)
thread_t th;
@@ -3857,7 +4453,9 @@ thread_restore_context(th, exit)
errat = th->errat;
errinfo = th->errinfo;
last_status = th->last_status;
+ safe_level = th->safe;
+ trace_func = th->trace;
sourcefile = th->file;
sourceline = th->line;
@@ -3878,6 +4476,13 @@ thread_restore_context(th, exit)
rb_interrupt();
break;
+ case 3:
+ the_frame->last_func = 0;
+ sourcefile = th_raise_file;
+ sourceline = th_raise_line;
+ f_raise(th_raise_argc, th_raise_argv);
+ break;
+
default:
longjmp(tmp->context, 1);
}
@@ -3918,6 +4523,17 @@ thread_dead(th)
return th->status == THREAD_KILLED;
}
+static void
+thread_deadlock()
+{
+ curr_thread = main_thread;
+ th_raise_argc = 1;
+ th_raise_argv[0] = exc_new2(eFatal, "Thread: deadlock");
+ th_raise_file = sourcefile;
+ th_raise_line = sourceline;
+ f_abort();
+}
+
void
thread_schedule()
{
@@ -3925,27 +4541,29 @@ thread_schedule()
thread_t th;
thread_t curr;
+ select_err:
thread_pending = 0;
if (curr_thread == curr_thread->next) return;
next = 0;
- curr = curr_thread; /* real current thread */
+ curr = curr_thread; /* starting thread */
- if (curr_thread->status == THREAD_KILLED) {
- curr_thread = curr_thread->prev;
+ while (curr->status == THREAD_KILLED) {
+ curr = curr->prev;
}
- again:
- FOREACH_THREAD(th) {
- if (th->status != THREAD_STOPPED && th->status != THREAD_KILLED) {
- next = th;
- break;
- }
+ FOREACH_THREAD_FROM(curr,th) {
+ if (th->status != THREAD_STOPPED && th->status != THREAD_KILLED) {
+ next = th;
+ break;
+ }
}
- END_FOREACH(th);
+ END_FOREACH_FROM(curr,th);
if (num_waiting_on_join) {
- FOREACH_THREAD(th) {
+ curr_thread->file = sourcefile;
+ curr_thread->line = sourceline;
+ FOREACH_THREAD_FROM(curr,th) {
if ((th->wait_for & WAIT_JOIN) && thread_dead(th->join)) {
th->join = 0;
th->wait_for &= ~WAIT_JOIN;
@@ -3954,7 +4572,7 @@ thread_schedule()
if (!next) next = th;
}
}
- END_FOREACH(th);
+ END_FOREACH_FROM(curr,th);
}
if (num_waiting_on_fd > 0 || num_waiting_on_timer > 0) {
@@ -3965,23 +4583,22 @@ thread_schedule()
int n, max;
do {
- select_err:
max = 0;
FD_ZERO(&readfds);
if (num_waiting_on_fd > 0) {
- FOREACH_THREAD(th) {
+ FOREACH_THREAD_FROM(curr,th) {
if (th->wait_for & WAIT_FD) {
FD_SET(th->fd, &readfds);
if (th->fd > max) max = th->fd;
}
}
- END_FOREACH(th);
+ END_FOREACH_FROM(curr,th);
}
delay = DELAY_INFTY;
if (num_waiting_on_timer > 0) {
now = timeofday();
- FOREACH_THREAD(th) {
+ FOREACH_THREAD_FROM(curr,th) {
if (th->wait_for & WAIT_TIME) {
if (th->delay <= now) {
th->delay = 0.0;
@@ -3994,7 +4611,7 @@ thread_schedule()
}
}
}
- END_FOREACH(th);
+ END_FOREACH_FROM(curr,th);
}
/* Do the select if needed */
if (num_waiting_on_fd > 0 || !next) {
@@ -4014,11 +4631,16 @@ thread_schedule()
delay_tv.tv_usec = (delay - (double)delay_tv.tv_sec) * 1e6;
delay_ptr = &delay_tv;
}
+
n = select(max+1, &readfds, 0, 0, delay_ptr);
+ if (n < 0) {
+ if (trap_pending) rb_trap_exec();
+ goto select_err;
+ }
if (n > 0) {
/* Some descriptors are ready.
Make the corresponding threads runnable. */
- FOREACH_THREAD(th)
+ FOREACH_THREAD_FROM(curr,th) {
if ((th->wait_for&WAIT_FD)
&& FD_ISSET(th->fd, &readfds)) {
/* Wake up only one thread per fd. */
@@ -4029,9 +4651,9 @@ thread_schedule()
num_waiting_on_fd--;
if (!next) next = th; /* Found one. */
}
- END_FOREACH(th);
+ }
+ END_FOREACH_FROM(curr,th);
}
- if (n < 0 && !next) goto select_err;
}
/* The delays for some of the threads should have expired.
Go through the loop once more, to check the delays. */
@@ -4039,15 +4661,16 @@ thread_schedule()
}
if (!next) {
- FOREACH_THREAD(th) {
+ FOREACH_THREAD_FROM(curr,th) {
fprintf(stderr, "%s:%d:deadlock 0x%x: %d:%d %s\n",
th->file, th->line, th->thread, th->status,
th->wait_for, th==main_thread?"(main)":"");
}
- END_FOREACH(th);
- Fatal("Thread: deadlock");
+ END_FOREACH_FROM(curr,th);
+ /* raise fatal error to main thread */
+ thread_deadlock();
}
- if (next == curr) {
+ if (next == curr_thread) {
return;
}
@@ -4087,9 +4710,9 @@ thread_fd_writable(fd)
struct timeval zero;
fd_set fds;
- zero.tv_sec = zero.tv_usec = 0;
if (curr_thread == curr_thread->next) return;
+ zero.tv_sec = zero.tv_usec = 0;
for (;;) {
FD_ZERO(&fds);
FD_SET(fd, &fds);
@@ -4138,7 +4761,13 @@ thread_wait_for(time)
thread_schedule();
}
-void thread_sleep();
+void thread_sleep_forever();
+
+int
+thread_alone()
+{
+ return curr_thread == curr_thread->next;
+}
int
thread_select(max, read, write, except, timeout)
@@ -4153,8 +4782,8 @@ thread_select(max, read, write, except, timeout)
if (!read && !write && !except) {
if (!timeout) {
- thread_sleep();
- return;
+ thread_sleep_forever();
+ return 0;
}
thread_wait_for(*timeout);
return 0;
@@ -4229,22 +4858,22 @@ thread_select(max, read, write, except, timeout)
}
static VALUE
-thread_join(dmy, data)
+thread_join(dmy, thread)
VALUE dmy;
- struct RData *data;
+ VALUE thread;
{
- thread_t th = thread_check(data);
+ thread_t th = thread_check(thread);
- if (thread_dead(th)) return Qnil;
+ if (thread_dead(th)) return thread;
if ((th->wait_for & WAIT_JOIN) && th->join == curr_thread)
- Fatal("Thread.join: deadlock");
+ Raise(eThreadError, "Thread.join: deadlock");
curr_thread->status = THREAD_STOPPED;
curr_thread->join = th;
num_waiting_on_join++;
curr_thread->wait_for |= WAIT_JOIN;
thread_schedule();
- return Qnil;
+ return thread;
}
static VALUE
@@ -4253,39 +4882,48 @@ thread_current()
return curr_thread->thread;
}
-int
-th_cur()
+static VALUE
+thread_main()
{
- return (int)curr_thread;
+ return main_thread->thread;
}
static VALUE
-thread_run(data)
- struct RData *data;
+thread_wakeup(thread)
+ VALUE thread;
{
- thread_t th = thread_check(data);
+ thread_t th = thread_check(thread);
- if (th->status == THREAD_KILLED) Fail("killed thread");
+ if (th->status == THREAD_KILLED) Raise(eThreadError, "killed thread");
thread_ready(th);
- thread_schedule();
- return (VALUE)data;
+ return thread;
}
static VALUE
-thread_kill(data)
- struct RData *data;
+thread_run(thread)
+ VALUE thread;
{
- thread_t th = thread_check(data);
+ thread_wakeup(thread);
+ if (!thread_critical) thread_schedule();
- if (th->status == THREAD_TO_KILL) return Qnil;
- if (th->status == THREAD_KILLED) return Qnil;
+ return thread;
+}
+
+static VALUE
+thread_kill(thread)
+ VALUE thread;
+{
+ thread_t th = thread_check(thread);
+
+ if (th->status == THREAD_TO_KILL || th->status == THREAD_KILLED)
+ return thread;
if (th == th->next || th == main_thread) rb_exit(0);
thread_ready(th);
th->status = THREAD_TO_KILL;
thread_schedule();
- /* not reached */
+ return Qnil; /* not reached */
}
static VALUE
@@ -4302,25 +4940,47 @@ thread_exit()
}
static VALUE
-thread_stop_method(data)
- struct RData *data;
+thread_pass()
+{
+ thread_schedule();
+ return Qnil;
+}
+
+static VALUE
+thread_stop_method(thread)
+ VALUE thread;
{
- thread_t th = thread_check(data);
+ thread_t th = thread_check(thread);
+ thread_critical = 0;
th->status = THREAD_STOPPED;
thread_schedule();
- return Qnil;
+ return thread;
}
-static void
+static VALUE
thread_stop()
{
thread_stop_method(curr_thread->thread);
+ return Qnil;
}
void
-thread_sleep()
+thread_sleep(sec)
+ int sec;
+{
+ if (curr_thread == curr_thread->next) {
+ TRAP_BEG;
+ sleep(sec);
+ TRAP_END;
+ return;
+ }
+ thread_wait_for(time_timeval(INT2FIX(sec)));
+}
+
+void
+thread_sleep_forever()
{
if (curr_thread == curr_thread->next) {
TRAP_BEG;
@@ -4328,7 +4988,47 @@ thread_sleep()
TRAP_END;
return;
}
- thread_stop_method(curr_thread->thread);
+
+ num_waiting_on_timer++;
+ curr_thread->delay = DELAY_INFTY;
+ curr_thread->wait_for |= WAIT_TIME;
+ curr_thread->status = THREAD_STOPPED;
+ thread_schedule();
+}
+
+static int thread_abort;
+
+static VALUE
+thread_s_abort_exc()
+{
+ return thread_abort?TRUE:FALSE;
+}
+
+static VALUE
+thread_s_abort_exc_set(self, val)
+ VALUE self, val;
+{
+ thread_abort = RTEST(val);
+ return val;
+}
+
+static VALUE
+thread_abort_exc(thread)
+ VALUE thread;
+{
+ thread_t th = thread_check(thread);
+
+ return th->abort?TRUE:FALSE;
+}
+
+static VALUE
+thread_abort_exc_set(thread, val)
+ VALUE thread, val;
+{
+ thread_t th = thread_check(thread);
+
+ th->abort = RTEST(val);
+ return val;
}
static thread_t
@@ -4338,8 +5038,6 @@ thread_alloc()
th = ALLOC(struct thread);
th->status = THREAD_RUNNABLE;
- th->func = 0;
- th->arg = 0;
th->status = 0;
th->result = 0;
@@ -4361,6 +5059,12 @@ thread_alloc()
th->block = 0;
th->iter = 0;
th->tag = 0;
+ th->errat = 0;
+ th->errinfo = 0;
+ th->last_status = 0;
+ th->last_line = 0;
+ th->last_match = 0;
+ th->abort = 0;
th->thread = data_object_alloc(cThread, th, 0, thread_free);
@@ -4378,6 +5082,26 @@ thread_alloc()
return th;
}
+#if defined(HAVE_SETITIMER) && !defined(__BOW__)
+static void
+catch_timer(sig)
+ int sig;
+{
+#if !defined(POSIX_SIGNAL) && !defined(BSD_SIGNAL)
+ signal(sig, catch_timer);
+#endif
+ if (!thread_critical) {
+ if (trap_immediate) {
+ trap_immediate = 0;
+ thread_schedule();
+ }
+ else thread_pending = 1;
+ }
+}
+#else
+int thread_tick = THREAD_TICK;
+#endif
+
VALUE
thread_create(fn, arg)
VALUE (*fn)();
@@ -4386,35 +5110,79 @@ thread_create(fn, arg)
thread_t th = thread_alloc();
NODE *state;
+#if defined(HAVE_SETITIMER) && !defined(__BOW__)
+ static init = 0;
+
+ if (!init) {
+ struct itimerval tval;
+
+#ifdef POSIX_SIGNAL
+ posix_signal(SIGVTALRM, catch_timer);
+#else
+ signal(SIGVTALRM, catch_timer);
+#endif
+
+ tval.it_interval.tv_sec = 0;
+ tval.it_interval.tv_usec = 100000;
+ tval.it_value = tval.it_interval;
+ setitimer(ITIMER_VIRTUAL, &tval, NULL);
+
+ init = 1;
+ }
+#endif
+
thread_save_context(curr_thread);
if (setjmp(curr_thread->context)) {
return th->thread;
}
- th->func = fn;
- th->arg = arg;
-
PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
thread_save_context(th);
if (setjmp(th->context) == 0) {
curr_thread = th;
- th->result = (*th->func)(th->arg, th);
+ th->result = (*fn)(arg, th);
}
}
POP_TAG();
- if (state && th->status != THREAD_TO_KILL) {
- /* global exit within this thread */
- main_thread->errat = errat;
- main_thread->errinfo = errinfo;
- thread_cleanup();
+ if (state) {
+ if (state->nd_tag == TAG_THROW) {
+ char *mesg;
+ char *tag = rb_id2name(state->nd_tlev);
+
+ mesg = ALLOCA_N(char, strlen(tag) + 64);
+
+ sprintf(mesg, "uncaught throw `%s' in thread 0x%x\n",
+ tag, th->thread);
+ curr_thread->errinfo = exc_new2(eThreadError, mesg);
+ curr_thread->errat = make_backtrace();
+ }
+ else if (th->status != THREAD_TO_KILL && !NIL_P(errinfo)) {
+ if (state->nd_tag == TAG_FATAL ||
+ obj_is_kind_of(errinfo, eSystemExit)) {
+ /* fatal error or global exit within this thread */
+ /* need to stop whole script */
+ main_thread->errat = errat;
+ main_thread->errinfo = errinfo;
+ thread_cleanup();
+ }
+ else if (thread_abort || curr_thread->abort) {
+ f_abort();
+ }
+ else {
+ curr_thread->errat = errat;
+ curr_thread->errinfo = errinfo;
+ }
+ }
}
thread_remove();
+ return 0;
}
static void
thread_yield(arg, th)
- thread_t th;
+ int arg;
+ thread_t th;
{
scope_dup(the_block->scope);
rb_yield(th->thread);
@@ -4424,35 +5192,47 @@ static VALUE
thread_start()
{
if (!iterator_p()) {
- Raise(eLocalJumpError, "must be called as iterator");
+ Raise(eThreadError, "must be called as iterator");
}
return thread_create(thread_yield, 0);
}
static VALUE
-thread_value(data)
- struct RData *data;
+thread_value(thread)
+ VALUE thread;
{
- thread_t th = thread_check(data);
+ thread_t th = thread_check(thread);
+
+ thread_join(0, thread);
+ if (!NIL_P(th->errinfo)) {
+ errat = make_backtrace();
+ ary_unshift(errat, ary_entry(th->errat, 0));
+ sourcefile = 0; /* kludge to print errat */
+ rb_raise(th->errinfo);
+ }
- thread_join(0, data);
return th->result;
}
static VALUE
-thread_status(data)
- struct RData *data;
+thread_status(thread)
+ VALUE thread;
{
- thread_t th = thread_check(data);
+ thread_t th = thread_check(thread);
+
+ if (thread_dead(th)) {
+ if (NIL_P(th->errinfo)) return FALSE;
+ return Qnil;
+ }
- return thread_dead(th)?FALSE:TRUE;
+ return TRUE;
}
static VALUE
-thread_stopped(data)
- struct RData *data;
+thread_stopped(thread)
+ VALUE thread;
{
- thread_t th = thread_check(data);
+ thread_t th = thread_check(thread);
if (thread_dead(th)) return TRUE;
if (th->status == THREAD_STOPPED) return TRUE;
@@ -4473,6 +5253,10 @@ thread_cleanup()
{
thread_t th;
+ if (curr_thread != curr_thread->next->prev) {
+ curr_thread = curr_thread->prev;
+ }
+
FOREACH_THREAD(th) {
if (th != curr_thread && th->status != THREAD_KILLED) {
th->status = THREAD_TO_KILL;
@@ -4485,37 +5269,64 @@ thread_cleanup()
int thread_critical;
static VALUE
-thread_exclusive()
+thread_get_critical()
{
- NODE *state;
-
- thread_critical++;
-
- PUSH_TAG();
- if ((state = EXEC_TAG()) == 0) {
- rb_yield(Qnil);
- }
- POP_TAG();
- thread_critical--;
+ return thread_critical?TRUE:FALSE;
+}
- if (state) JUMP_TAG(state);
- thread_schedule();
- return Qnil;
+static VALUE
+thread_set_critical(obj, val)
+ VALUE obj, val;
+{
+ thread_critical = RTEST(val);
+ return val;
}
void
thread_interrupt()
{
- thread_t th = main_thread;
-
+ thread_critical = 0;
thread_ready(main_thread);
- if (th == curr_thread) {
+ if (curr_thread == main_thread) {
rb_interrupt();
}
+ thread_save_context(curr_thread);
+ if (setjmp(curr_thread->context)) {
+ return;
+ }
curr_thread = main_thread;
thread_restore_context(curr_thread, 2);
}
+static VALUE
+thread_raise(argc, argv, thread)
+ int argc;
+ VALUE *argv;
+ VALUE thread;
+{
+ thread_t th = thread_check(thread);
+
+ if (thread_dead(th)) return thread;
+ if (curr_thread == th) {
+ f_raise(argc, argv);
+ }
+
+ thread_save_context(curr_thread);
+ if (setjmp(curr_thread->context)) {
+ return thread;
+ }
+
+ rb_scan_args(argc, argv, "11", &th_raise_argv[0], &th_raise_argv[1]);
+ thread_ready(th);
+ curr_thread = th;
+
+ th_raise_argc = argc;
+ th_raise_file = sourcefile;
+ th_raise_line = sourceline;
+ thread_restore_context(curr_thread, 3);
+ return Qnil; /* not reached */
+}
+
static thread_t loading_thread;
static int loading_nest;
@@ -4545,29 +5356,10 @@ thread_loading_done()
}
}
-#if defined(HAVE_SETITIMER) && !defined(__BOW__)
-static void
-catch_timer(sig)
- int sig;
-{
-#if !defined(POSIX_SIGNAL) && !defined(BSD_SIGNAL)
- signal(sig, catch_timer);
-#endif
- if (!thread_critical) {
- if (trap_immediate) {
- trap_immediate = 0;
- thread_schedule();
- }
- else thread_pending = 1;
- }
-}
-#else
-int thread_tick = THREAD_TICK;
-#endif
-
void
Init_Thread()
{
+ eThreadError = rb_define_class("ThreadError", eException);
cThread = rb_define_class("Thread", cObject);
rb_define_singleton_method(cThread, "new", thread_start, 0);
@@ -4577,37 +5369,31 @@ Init_Thread()
rb_define_singleton_method(cThread, "stop", thread_stop, 0);
rb_define_singleton_method(cThread, "kill", thread_s_kill, 1);
rb_define_singleton_method(cThread, "exit", thread_exit, 0);
- rb_define_singleton_method(cThread, "pass", thread_schedule, 0);
+ rb_define_singleton_method(cThread, "pass", thread_pass, 0);
rb_define_singleton_method(cThread, "join", thread_join, 1);
rb_define_singleton_method(cThread, "current", thread_current, 0);
- rb_define_singleton_method(cThread, "exclusive", thread_exclusive, 0);
+ rb_define_singleton_method(cThread, "main", thread_main, 0);
+
+ rb_define_singleton_method(cThread, "critical", thread_get_critical, 0);
+ rb_define_singleton_method(cThread, "critical=", thread_set_critical, 1);
+
+ rb_define_singleton_method(cThread, "abort_on_exception", thread_s_abort_exc, 0);
+ rb_define_singleton_method(cThread, "abort_on_exception=", thread_s_abort_exc_set, 1);
rb_define_method(cThread, "run", thread_run, 0);
+ rb_define_method(cThread, "wakeup", thread_wakeup, 0);
rb_define_method(cThread, "stop", thread_stop_method, 0);
rb_define_method(cThread, "exit", thread_kill, 0);
rb_define_method(cThread, "value", thread_value, 0);
rb_define_method(cThread, "status", thread_status, 0);
+ rb_define_method(cThread, "alive?", thread_status, 0);
rb_define_method(cThread, "stop?", thread_stopped, 0);
- rb_define_method(cThread, "stopped?", thread_stopped, 0);
+ rb_define_method(cThread, "raise", thread_raise, -1);
+
+ rb_define_method(cThread, "abort_on_exception", thread_abort_exc, 0);
+ rb_define_method(cThread, "abort_on_exception=", thread_abort_exc_set, 1);
/* allocate main thread */
main_thread = thread_alloc();
-
-#if defined(HAVE_SETITIMER) && !defined(__BOW__)
- {
- struct itimerval tval;
-
-#ifdef POSIX_SIGNAL
- posix_signal(SIGVTALRM, catch_timer);
-#else
- signal(SIGVTALRM, catch_timer);
-#endif
-
- tval.it_interval.tv_sec = 0;
- tval.it_interval.tv_usec = 50000;
- tval.it_value = tval.it_interval;
- setitimer(ITIMER_VIRTUAL, &tval, NULL);
- }
-#endif
}
#endif
diff --git a/ext/Setup b/ext/Setup
index 4ea6aea10a..a5dd7978c3 100644
--- a/ext/Setup
+++ b/ext/Setup
@@ -1,7 +1,10 @@
#option nodynamic
+#GD
+#curses
#dbm
#etc
+#fcntl
#kconv
#marshal
#md5
diff --git a/ext/Setup.dj b/ext/Setup.dj
index eb60525de0..25adea2035 100644
--- a/ext/Setup.dj
+++ b/ext/Setup.dj
@@ -1,7 +1,11 @@
option nodynamic
+#GD
+#curses
dbm
#etc
+fcntl
+kconv
marshal
md5
#socket
diff --git a/ext/Setup.nt b/ext/Setup.nt
new file mode 100644
index 0000000000..8e43179f9e
--- /dev/null
+++ b/ext/Setup.nt
@@ -0,0 +1,12 @@
+option nodynamic
+
+#GD
+#curses
+#dbm
+#etc
+fcntl
+kconv
+#marshal
+md5
+socket
+#tkutil
diff --git a/ext/Setup.x68 b/ext/Setup.x68
new file mode 100644
index 0000000000..25adea2035
--- /dev/null
+++ b/ext/Setup.x68
@@ -0,0 +1,12 @@
+option nodynamic
+
+#GD
+#curses
+dbm
+#etc
+fcntl
+kconv
+marshal
+md5
+#socket
+#tkutil
diff --git a/ext/aix_ld.rb b/ext/aix_ld.rb
new file mode 100644
index 0000000000..1058977b88
--- /dev/null
+++ b/ext/aix_ld.rb
@@ -0,0 +1,73 @@
+#! /usr/local/bin/ruby
+
+def older(file1, file2)
+ if !File.exist?(file1) then
+ return TRUE
+ end
+ if !File.exist?(file2) then
+ return FALSE
+ end
+ if File.mtime(file1) < File.mtime(file2)
+ return TRUE
+ end
+ return FALSE
+end
+
+target = ARGV.shift
+unless target =~ /\.so/
+ STDERR.printf "wrong suffix specified\n"
+ exit 1
+end
+base = File.basename(target, ".so")
+entry="Init_#{base}"
+ldargs = "-e#{entry} -bI:../ruby.imp -bM:SRE -T512 -H512 -lc"
+
+def uniq(data)
+ last=nil
+ data.delete_if do |name|
+ if last == name
+ TRUE
+ else
+ last = name
+ FALSE
+ end
+ end
+end
+
+def extract(nm, out)
+ data = nm.readlines.collect{|line|
+ line = line.split
+ case line[1]
+ when "B", "D", "T"
+ line[2]
+ else
+ next
+ end
+ }.sort!
+ uniq(data)
+ exp = open(out, "w")
+ for line in data
+ exp.printf "%s\n", line
+ end
+ exp.close
+ nm.close
+end
+if older("../ruby.imp", "../../miniruby")
+# nm = open("|/usr/ccs/bin/nm -Bex ../../*.o")
+# nm = open("|/usr/ccs/bin/nm -Bex ../../*.o")
+ nm = open("|nm ../../*.o")
+ extract(nm, "../ruby.imp")
+end
+
+objs = Dir["*.o"].join(" ")
+#nm = open("|/usr/ccs/bin/nm -Bex #{objs}")
+nm = open("|nm #{objs}")
+extract(nm, "#{base}.exp")
+
+#system format("/usr/ccs/bin/ld %s %s ",ldargs,ARGV.join(' '))
+#system "/bin/rm -f #{base}.exp"
+#system "chmod o-rwx ${base}.so"
+
+p format("/usr/ccs/bin/ld %s %s ",ldargs,ARGV.join(' '))
+p "/bin/rm -f #{base}.exp"
+p "chmod o-rwx ${base}.so"
diff --git a/ext/curses/MANIFEST b/ext/curses/MANIFEST
new file mode 100644
index 0000000000..db5e54ffe8
--- /dev/null
+++ b/ext/curses/MANIFEST
@@ -0,0 +1,6 @@
+MANIFEST
+curses.c
+extconf.rb
+hello.rb
+rain.rb
+view.rb
diff --git a/ext/curses/curses.c b/ext/curses/curses.c
new file mode 100644
index 0000000000..16ba90cff0
--- /dev/null
+++ b/ext/curses/curses.c
@@ -0,0 +1,725 @@
+/*
+ * ext/curses/curses.c
+ *
+ * by MAEDA Shugo (ender@pic-internet.or.jp)
+ * modified by Yukihiro Matsumoto (matz@ruby.club.or.jp)
+ */
+
+#ifdef HAVE_NCURSES_H
+# include <ncurses.h>
+#else
+# ifdef HAVE_NCURSES_CURSES_H
+# include <ncurses/curses.h>
+# else
+# include <curses.h>
+# if defined(__NetBSD__) && !defined(_maxx)
+# define _maxx maxx
+# endif
+# if defined(__NetBSD__) && !defined(_maxy)
+# define _maxy maxy
+# endif
+# endif
+#endif
+
+#include "ruby.h"
+
+static VALUE mCurses;
+static VALUE cWindow;
+
+VALUE rb_stdscr;
+
+struct windata {
+ WINDOW *window;
+};
+
+#define NUM2CHAR(x) (char)NUM2INT(x)
+#define CHAR2FIX(x) INT2FIX((int)x)
+
+static void
+no_window()
+{
+ Fail("already closed window");
+}
+
+#define GetWINDOW(obj, winp) {\
+ Data_Get_Struct(obj, struct windata, winp);\
+ if (winp->window == 0) no_window();\
+}
+
+static void
+curses_err()
+{
+ Fail("curses error");
+}
+
+#define CHECK(c) if ((c)==ERR) {curses_err();}
+
+static void
+free_window(struct windata *winp)
+{
+ if (winp->window && winp->window != stdscr) delwin(winp->window);
+ winp->window = 0;
+}
+
+static VALUE
+prep_window(VALUE class, WINDOW *window)
+{
+ VALUE obj;
+ struct windata *winp;
+
+ if (window == NULL) {
+ Fail("failed to create window");
+ }
+
+ obj = Data_Make_Struct(class, struct windata, 0, free_window, winp);
+ winp->window = window;
+
+ return obj;
+}
+
+/*-------------------------- module Curses --------------------------*/
+
+/* def init_screen */
+static VALUE
+curses_init_screen()
+{
+ initscr();
+ if (stdscr == 0) {
+ Fail("cannot initialize curses");
+ }
+ clear();
+ rb_stdscr = prep_window(cWindow, stdscr);
+ return Qnil;
+}
+
+/* def stdscr */
+static VALUE
+curses_stdscr()
+{
+ if (!rb_stdscr) curses_init_screen();
+ return rb_stdscr;
+}
+
+/* def close_screen */
+static VALUE
+curses_close_screen()
+{
+ CHECK(endwin());
+ return Qnil;
+}
+
+/* def closed? */
+static VALUE
+curses_closed()
+{
+#ifdef HAVE_ENDWIN
+ if (isendwin()) {
+ return TRUE;
+ }
+ return FALSE;
+#else
+ rb_notimplement();
+#endif
+}
+
+/* def clear */
+static VALUE
+curses_clear(VALUE obj)
+{
+ wclear(stdscr);
+ return Qnil;
+}
+
+/* def refresh */
+static VALUE
+curses_refresh(VALUE obj)
+{
+ CHECK(refresh());
+ return Qnil;
+}
+
+/* def refresh */
+static VALUE
+curses_doupdate(VALUE obj)
+{
+ CHECK(doupdate());
+ return Qnil;
+}
+
+/* def echo */
+static VALUE
+curses_echo(VALUE obj)
+{
+ CHECK(echo());
+ return Qnil;
+}
+
+/* def noecho */
+static VALUE
+curses_noecho(VALUE obj)
+{
+ CHECK(noecho());
+ return Qnil;
+}
+
+/* def raw */
+static VALUE
+curses_raw(VALUE obj)
+{
+ CHECK(raw());
+ return Qnil;
+}
+
+/* def noraw */
+static VALUE
+curses_noraw(VALUE obj)
+{
+ CHECK(noraw());
+ return Qnil;
+}
+
+/* def cbreak */
+static VALUE
+curses_cbreak(VALUE obj)
+{
+ CHECK(cbreak());
+ return Qnil;
+}
+
+/* def nocbreak */
+static VALUE
+curses_nocbreak(VALUE obj)
+{
+ CHECK(nocbreak());
+ return Qnil;
+}
+
+/* def nl */
+static VALUE
+curses_nl(VALUE obj)
+{
+ CHECK(nl());
+ return Qnil;
+}
+
+/* def nonl */
+static VALUE
+curses_nonl(VALUE obj)
+{
+ CHECK(nonl());
+ return Qnil;
+}
+
+/* def beep */
+static VALUE
+curses_beep(VALUE obj)
+{
+#ifdef HAVE_BEEP
+ beep();
+#endif
+ return Qnil;
+}
+
+/* def flash */
+static VALUE
+curses_flash(VALUE obj)
+{
+ flash();
+ return Qnil;
+}
+
+/* def ungetch */
+static VALUE
+curses_ungetch(VALUE obj, VALUE ch)
+{
+#ifdef HAVE_UNGETCH
+ CHECK(ungetch(NUM2INT(ch)));
+#else
+ rb_notimplement();
+#endif
+ return Qnil;
+}
+
+/* def setpos(y, x) */
+static VALUE
+curses_setpos(VALUE obj, VALUE y, VALUE x)
+{
+ CHECK(move(NUM2INT(y), NUM2INT(x)));
+ return Qnil;
+}
+
+/* def standout */
+static VALUE
+curses_standout(VALUE obj)
+{
+ standout();
+ return Qnil;
+}
+
+/* def standend */
+static VALUE
+curses_standend(VALUE obj)
+{
+ standend();
+ return Qnil;
+}
+
+/* def inch */
+static VALUE
+curses_inch(VALUE obj)
+{
+ return CHAR2FIX(inch());
+}
+
+/* def addch(ch) */
+static VALUE
+curses_addch(VALUE obj, VALUE ch)
+{
+ CHECK(addch(NUM2CHAR(ch)));
+ return Qnil;
+}
+
+/* def insch(ch) */
+static VALUE
+curses_insch(VALUE obj, VALUE ch)
+{
+ CHECK(insch(NUM2CHAR(ch)));
+ return Qnil;
+}
+
+/* def addstr(str) */
+static VALUE
+curses_addstr(VALUE obj, VALUE str)
+{
+ addstr(RSTRING(str)->ptr);
+ return Qnil;
+}
+
+/* def getch */
+static VALUE
+curses_getch(VALUE obj)
+{
+ return CHAR2FIX(getch());
+}
+
+/* def getstr */
+static VALUE
+curses_getstr(VALUE obj)
+{
+ char rtn[1024]; /* This should be big enough.. I hope */
+ CHECK(getstr(rtn));
+ return str_taint(str_new2(rtn));
+}
+
+/* def delch */
+static VALUE
+curses_delch(VALUE obj)
+{
+ CHECK(delch());
+ return Qnil;
+}
+
+/* def delelteln */
+static VALUE
+curses_deleteln(VALUE obj)
+{
+ CHECK(deleteln());
+ return Qnil;
+}
+
+static VALUE
+curses_lines()
+{
+ return INT2FIX(LINES);
+}
+
+static VALUE
+curses_cols()
+{
+ return INT2FIX(COLS);
+}
+
+/*-------------------------- class Window --------------------------*/
+
+/* def new(lines, cols, top, left) */
+static VALUE
+window_s_new(VALUE class,
+ VALUE lines, VALUE cols,
+ VALUE top, VALUE left)
+{
+ WINDOW *window;
+
+ window = newwin(NUM2INT(lines), NUM2INT(cols), NUM2INT(top), NUM2INT(left));
+ wclear(window);
+ return prep_window(class, window);
+}
+
+/* def subwin(lines, cols, top, left) */
+static VALUE
+window_subwin(VALUE obj,
+ VALUE lines, VALUE cols,
+ VALUE top, VALUE left)
+{
+ struct windata *winp;
+ WINDOW *window;
+
+ GetWINDOW(obj, winp);
+ window = subwin(winp->window, NUM2INT(lines), NUM2INT(cols),
+ NUM2INT(top), NUM2INT(left));
+ return prep_window(cWindow, window);
+}
+
+/* def close */
+static VALUE
+window_close(VALUE obj)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ free_window(winp);
+
+ return Qnil;
+}
+
+/* def clear */
+static VALUE
+window_clear(VALUE obj)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ wclear(winp->window);
+
+ return Qnil;
+}
+
+/* def refresh */
+static VALUE
+window_refresh(VALUE obj)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ CHECK(wrefresh(winp->window));
+
+ return Qnil;
+}
+
+/* def box(vert, hor) */
+static VALUE
+window_box(VALUE obj, VALUE vert, VALUE hor)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ box(winp->window, NUM2CHAR(vert), NUM2CHAR(hor));
+
+ return Qnil;
+}
+
+
+/* def move(y, x) */
+static VALUE
+window_move(VALUE obj, VALUE y, VALUE x)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ CHECK(mvwin(winp->window, NUM2INT(y), NUM2INT(x)));
+
+ return Qnil;
+}
+
+/* def setpos(y, x) */
+static VALUE
+window_setpos(VALUE obj, VALUE y, VALUE x)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ CHECK(wmove(winp->window, NUM2INT(y), NUM2INT(x)));
+ return Qnil;
+}
+
+/* def cury */
+static VALUE
+window_cury(VALUE obj)
+{
+ struct windata *winp;
+ int x, y;
+
+ GetWINDOW(obj, winp);
+ getyx(winp->window, y, x);
+ return INT2FIX(y);
+}
+
+/* def curx */
+static VALUE
+window_curx(VALUE obj)
+{
+ struct windata *winp;
+ int x, y;
+
+ GetWINDOW(obj, winp);
+ getyx(winp->window, y, x);
+ return INT2FIX(x);
+}
+
+/* def maxy */
+static VALUE
+window_maxy(VALUE obj)
+{
+ struct windata *winp;
+ int x, y;
+
+ GetWINDOW(obj, winp);
+#ifdef getmaxy
+ return INT2FIX(getmaxy(winp->window));
+#else
+#ifdef getmaxyx
+ getmaxyx(winp->window, y, x);
+ return INT2FIX(y);
+#else
+ return INT2FIX(winp->window->_maxy+1);
+#endif
+#endif
+}
+
+/* def maxx */
+static VALUE
+window_maxx(VALUE obj)
+{
+ struct windata *winp;
+ int x, y;
+
+ GetWINDOW(obj, winp);
+#ifdef getmaxx
+ return INT2FIX(getmaxx(winp->window));
+#else
+#ifdef getmaxyx
+ getmaxyx(winp->window, y, x);
+ return INT2FIX(x);
+#else
+ return INT2FIX(winp->window->_maxx+1);
+#endif
+#endif
+}
+
+/* def begy */
+static VALUE
+window_begy(VALUE obj)
+{
+ struct windata *winp;
+ int x, y;
+
+ GetWINDOW(obj, winp);
+#ifdef getbegyx
+ getbegyx(winp->window, y, x);
+ return INT2FIX(y);
+#else
+ return INT2FIX(winp->window->_begy);
+#endif
+}
+
+/* def begx */
+static VALUE
+window_begx(VALUE obj)
+{
+ struct windata *winp;
+ int x, y;
+
+ GetWINDOW(obj, winp);
+#ifdef getbegyx
+ getbegyx(winp->window, y, x);
+ return INT2FIX(x);
+#else
+ return INT2FIX(winp->window->_begx);
+#endif
+}
+
+/* def standout */
+static VALUE
+window_standout(VALUE obj)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ wstandout(winp->window);
+ return Qnil;
+}
+
+/* def standend */
+static VALUE
+window_standend(VALUE obj)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ wstandend(winp->window);
+ return Qnil;
+}
+
+/* def inch */
+static VALUE
+window_inch(VALUE obj)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ return CHAR2FIX(winch(winp->window));
+}
+
+/* def addch(ch) */
+static VALUE
+window_addch(VALUE obj, VALUE ch)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ CHECK(waddch(winp->window, NUM2CHAR(ch)));
+
+ return Qnil;
+}
+
+/* def insch(ch) */
+static VALUE
+window_insch(VALUE obj, VALUE ch)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ CHECK(winsch(winp->window, NUM2CHAR(ch)));
+
+ return Qnil;
+}
+
+/* def addstr(str) */
+static VALUE
+window_addstr(VALUE obj, VALUE str)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ CHECK(waddstr(winp->window, RSTRING(str)->ptr));
+
+ return Qnil;
+}
+
+/* def <<(str) */
+static VALUE
+window_addstr2(VALUE obj, VALUE str)
+{
+ window_addstr(obj, str);
+ return obj;
+}
+
+/* def getch */
+static VALUE
+window_getch(VALUE obj)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ return CHAR2FIX(wgetch(winp->window));
+}
+
+/* def getstr */
+static VALUE
+window_getstr(VALUE obj)
+{
+ struct windata *winp;
+ char rtn[1024]; /* This should be big enough.. I hope */
+
+ GetWINDOW(obj, winp);
+ CHECK(wgetstr(winp->window, rtn));
+ return str_taint(str_new2(rtn));
+}
+
+/* def delch */
+static VALUE
+window_delch(VALUE obj)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ CHECK(wdelch(winp->window));
+ return Qnil;
+}
+
+/* def delelteln */
+static VALUE
+window_deleteln(VALUE obj)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ CHECK(wdeleteln(winp->window));
+ return Qnil;
+}
+
+/*------------------------- Initialization -------------------------*/
+void
+Init_curses()
+{
+ mCurses = rb_define_module("Curses");
+ rb_define_module_function(mCurses, "init_screen", curses_init_screen, 0);
+ rb_define_module_function(mCurses, "close_screen", curses_close_screen, 0);
+ rb_define_module_function(mCurses, "closed?", curses_closed, 0);
+ rb_define_module_function(mCurses, "stdscr", curses_stdscr, 0);
+ rb_define_module_function(mCurses, "refresh", curses_refresh, 0);
+ rb_define_module_function(mCurses, "doupdate", curses_doupdate, 0);
+ rb_define_module_function(mCurses, "clear", curses_clear, 0);
+ rb_define_module_function(mCurses, "echo", curses_echo, 0);
+ rb_define_module_function(mCurses, "noecho", curses_noecho, 0);
+ rb_define_module_function(mCurses, "raw", curses_raw, 0);
+ rb_define_module_function(mCurses, "noraw", curses_noraw, 0);
+ rb_define_module_function(mCurses, "cbreak", curses_cbreak, 0);
+ rb_define_module_function(mCurses, "nocbreak", curses_nocbreak, 0);
+ rb_define_alias(mCurses, "crmode", "cbreak");
+ rb_define_alias(mCurses, "nocrmode", "nocbreak");
+ rb_define_module_function(mCurses, "nl", curses_nl, 0);
+ rb_define_module_function(mCurses, "nonl", curses_nonl, 0);
+ rb_define_module_function(mCurses, "beep", curses_beep, 0);
+ rb_define_module_function(mCurses, "flash", curses_flash, 0);
+ rb_define_module_function(mCurses, "ungetch", curses_ungetch, 1);
+ rb_define_module_function(mCurses, "setpos", curses_setpos, 2);
+ rb_define_module_function(mCurses, "standout", curses_standout, 0);
+ rb_define_module_function(mCurses, "standend", curses_standend, 0);
+ rb_define_module_function(mCurses, "inch", curses_inch, 0);
+ rb_define_module_function(mCurses, "addch", curses_addch, 1);
+ rb_define_module_function(mCurses, "insch", curses_insch, 1);
+ rb_define_module_function(mCurses, "addstr", curses_addstr, 1);
+ rb_define_module_function(mCurses, "getch", curses_getch, 0);
+ rb_define_module_function(mCurses, "getstr", curses_getstr, 0);
+ rb_define_module_function(mCurses, "delch", curses_delch, 0);
+ rb_define_module_function(mCurses, "deleteln", curses_deleteln, 0);
+ rb_define_module_function(mCurses, "lines", curses_lines, 0);
+ rb_define_module_function(mCurses, "cols", curses_cols, 0);
+
+ cWindow = rb_define_class_under(mCurses, "Window", cObject);
+ rb_define_singleton_method(cWindow, "new", window_s_new, 4);
+ rb_define_method(cWindow, "subwin", window_subwin, 4);
+ rb_define_method(cWindow, "close", window_close, 0);
+ rb_define_method(cWindow, "clear", window_clear, 0);
+ rb_define_method(cWindow, "refresh", window_refresh, 0);
+ rb_define_method(cWindow, "box", window_box, 2);
+ rb_define_method(cWindow, "move", window_move, 2);
+ rb_define_method(cWindow, "setpos", window_setpos, 2);
+ rb_define_method(cWindow, "cury", window_cury, 0);
+ rb_define_method(cWindow, "curx", window_curx, 0);
+ rb_define_method(cWindow, "maxy", window_maxy, 0);
+ rb_define_method(cWindow, "maxx", window_maxx, 0);
+ rb_define_method(cWindow, "begy", window_begy, 0);
+ rb_define_method(cWindow, "begx", window_begx, 0);
+ rb_define_method(cWindow, "standout", window_standout, 0);
+ rb_define_method(cWindow, "standend", window_standend, 0);
+ rb_define_method(cWindow, "inch", window_inch, 0);
+ rb_define_method(cWindow, "addch", window_addch, 1);
+ rb_define_method(cWindow, "insch", window_insch, 1);
+ rb_define_method(cWindow, "addstr", window_addstr, 1);
+ rb_define_method(cWindow, "<<", window_addstr2, 1);
+ rb_define_method(cWindow, "getch", window_getch, 0);
+ rb_define_method(cWindow, "getstr", window_getstr, 0);
+ rb_define_method(cWindow, "delch", window_delch, 0);
+ rb_define_method(cWindow, "deleteln", window_deleteln, 0);
+}
diff --git a/ext/curses/extconf.rb b/ext/curses/extconf.rb
new file mode 100644
index 0000000000..22b1e2f0cc
--- /dev/null
+++ b/ext/curses/extconf.rb
@@ -0,0 +1,21 @@
+$CFLAGS="-I/usr/include/ncurses -I/usr/local/include/ncurses"
+$LDFLAGS="-L/usr/local/lib"
+make=FALSE
+if have_header("ncurses.h") and have_library("ncurses", "initscr")
+ make=TRUE
+elsif have_header("ncurses/curses.h") and have_library("ncurses", "initscr")
+ make=TRUE
+else
+ $CFLAGS=nil
+ have_library("termcap", "tparam")
+ if have_library("curses", "initscr")
+ make=TRUE
+ end
+end
+
+if make then
+ for f in ["isendwin", "ungetch", "beep"]
+ have_func(f)
+ end
+ create_makefile("curses")
+end
diff --git a/ext/curses/hello.rb b/ext/curses/hello.rb
new file mode 100644
index 0000000000..bed7779aac
--- /dev/null
+++ b/ext/curses/hello.rb
@@ -0,0 +1,28 @@
+#!/usr/local/bin/ruby
+
+require "curses"
+include Curses
+
+def show_message(message)
+ width = message.length + 6
+ win = Window.new(5, width,
+ (lines - 5) / 2, (cols - width) / 2)
+ win.box(?|, ?=)
+ win.setpos(2, 3)
+ win.addstr(message)
+ win.getch
+ win.close
+end
+
+init_screen
+begin
+ crmode
+# show_message("Hit any key")
+ setpos (lines - 5) / 2, (cols - 10) / 2
+ addstr("Hit any key")
+ getch
+ show_message("Hello, World!")
+ refresh
+ensure
+ close_screen
+end
diff --git a/ext/curses/rain.rb b/ext/curses/rain.rb
new file mode 100644
index 0000000000..36f0f84de2
--- /dev/null
+++ b/ext/curses/rain.rb
@@ -0,0 +1,76 @@
+#!/usr/local/bin/ruby
+# rain for a curses test
+
+require "curses"
+include Curses
+
+def onsig(sig)
+ close_screen
+ exit sig
+end
+
+def ranf
+ rand(32767).to_f / 32767
+end
+
+# main #
+for i in 1 .. 15 # SIGHUP .. SIGTERM
+ if trap(i, "SIG_IGN") != 0 then # 0 for SIG_IGN
+ trap(i) {|sig| onsig(sig) }
+ end
+end
+
+init_screen
+nl
+noecho
+srand
+
+xpos = {}
+ypos = {}
+r = lines - 4
+c = cols - 4
+for i in 0 .. 4
+ xpos[i] = (c * ranf).to_i + 2
+ ypos[i] = (r * ranf).to_i + 2
+end
+
+i = 0
+while TRUE
+ x = (c * ranf).to_i + 2
+ y = (r * ranf).to_i + 2
+
+
+ setpos(y, x); addstr(".")
+
+ setpos(ypos[i], xpos[i]); addstr("o")
+
+ i = if i == 0 then 4 else i - 1 end
+ setpos(ypos[i], xpos[i]); addstr("O")
+
+ i = if i == 0 then 4 else i - 1 end
+ setpos(ypos[i] - 1, xpos[i]); addstr("-")
+ setpos(ypos[i], xpos[i] - 1); addstr("|.|")
+ setpos(ypos[i] + 1, xpos[i]); addstr("-")
+
+ i = if i == 0 then 4 else i - 1 end
+ setpos(ypos[i] - 2, xpos[i]); addstr("-")
+ setpos(ypos[i] - 1, xpos[i] - 1); addstr("/ \\")
+ setpos(ypos[i], xpos[i] - 2); addstr("| O |")
+ setpos(ypos[i] + 1, xpos[i] - 1); addstr("\\ /")
+ setpos(ypos[i] + 2, xpos[i]); addstr("-")
+
+ i = if i == 0 then 4 else i - 1 end
+ setpos(ypos[i] - 2, xpos[i]); addstr(" ")
+ setpos(ypos[i] - 1, xpos[i] - 1); addstr(" ")
+ setpos(ypos[i], xpos[i] - 2); addstr(" ")
+ setpos(ypos[i] + 1, xpos[i] - 1); addstr(" ")
+ setpos(ypos[i] + 2, xpos[i]); addstr(" ")
+
+
+ xpos[i] = x
+ ypos[i] = y
+ refresh
+ sleep(0.5)
+end
+
+# end of main
diff --git a/ext/curses/view.rb b/ext/curses/view.rb
new file mode 100644
index 0000000000..e59a74ed44
--- /dev/null
+++ b/ext/curses/view.rb
@@ -0,0 +1,90 @@
+#!/usr/local/bin/ruby
+
+require "curses"
+include Curses
+
+#
+# main
+#
+
+if ARGV.size != 1 then
+ printf("usage: view file\n");
+ exit
+end
+begin
+ fp = open(ARGV[0], "r")
+rescue
+ raise "cannot open file: #{ARGV[1]}"
+end
+
+# signal(SIGINT, finish)
+
+init_screen
+#keypad(stdscr, TRUE)
+nonl
+cbreak
+noecho
+#scrollok(stdscr, TRUE)
+
+# slurp the file
+data_lines = []
+fp.each_line { |l|
+ data_lines.push(l)
+}
+fp.close
+
+
+lptr = 0
+while TRUE
+ i = 0
+ while i < lines
+ setpos(i, 0)
+ #clrtoeol
+ addstr(data_lines[lptr + i]) #if data_lines[lptr + i]
+ i += 1
+ end
+
+ explicit = FALSE
+ n = 0
+ while TRUE
+ c = getch.chr
+ if c =~ "[0-9]" then
+ n = 10 * n + c.to_i
+ else
+ break
+ end
+ end
+
+ n = 1 if !explicit && n == 0
+
+ case c
+ when "n" #when KEY_DOWN
+ i = 0
+ while i < n
+ if lptr + lines < data_lines.size then
+ lptr += 1
+ else
+ break
+ end
+ i += 1
+ end
+ #wscrl(i)
+
+ when "p" #when KEY_UP
+ i = 0
+ while i < n
+ if lptr > 0 then
+ lptr -= 1
+ else
+ break
+ end
+ i += 1
+ end
+ #wscrl(-i)
+
+ when "q"
+ break
+ end
+
+end
+close_screen
diff --git a/ext/dbm/dbm.c b/ext/dbm/dbm.c
index 5d8a12e3f9..f0522f2d48 100644
--- a/ext/dbm/dbm.c
+++ b/ext/dbm/dbm.c
@@ -26,14 +26,14 @@ struct dbmdata {
};
static void
-closeddbm()
+closed_dbm()
{
Fail("closed DBM file");
}
#define GetDBM(obj, dbmp) {\
- Get_Data_Struct(obj, struct dbmdata, dbmp);\
- if (dbmp->di_dbm == 0) closeddbm();\
+ Data_Get_Struct(obj, struct dbmdata, dbmp);\
+ if (dbmp->di_dbm == 0) closed_dbm();\
}
static void
@@ -64,7 +64,7 @@ fdbm_s_open(argc, argv, class)
else {
mode = NUM2INT(vmode);
}
- Check_Type(file, T_STRING);
+ Check_SafeStr(file);
dbm = 0;
if (mode >= 0)
@@ -79,7 +79,7 @@ fdbm_s_open(argc, argv, class)
rb_sys_fail(RSTRING(file)->ptr);
}
- obj = Make_Data_Struct(class,struct dbmdata,0,free_dbm,dbmp);
+ obj = Data_Make_Struct(class,struct dbmdata,0,free_dbm,dbmp);
dbmp->di_dbm = dbm;
dbmp->di_size = -1;
@@ -92,8 +92,8 @@ fdbm_close(obj)
{
struct dbmdata *dbmp;
- Get_Data_Struct(obj, struct dbmdata, dbmp);
- if (dbmp->di_dbm == 0) closeddbm();
+ Data_Get_Struct(obj, struct dbmdata, dbmp);
+ if (dbmp->di_dbm == 0) closed_dbm();
dbm_close(dbmp->di_dbm);
dbmp->di_dbm = 0;
@@ -118,7 +118,7 @@ fdbm_fetch(obj, keystr)
if (value.dptr == 0) {
return Qnil;
}
- return str_new(value.dptr, value.dsize);
+ return str_taint(str_new(value.dptr, value.dsize));
}
static VALUE
@@ -148,6 +148,7 @@ fdbm_delete(obj, keystr)
struct dbmdata *dbmp;
DBM *dbm;
+ rb_secure(4);
Check_Type(keystr, T_STRING);
key.dptr = RSTRING(keystr)->ptr;
key.dsize = RSTRING(keystr)->len;
@@ -157,7 +158,7 @@ fdbm_delete(obj, keystr)
value = dbm_fetch(dbm, key);
if (value.dptr == 0) {
- if (iterator_p()) rb_yield(Qnil);
+ if (iterator_p()) rb_yield(keystr);
return Qnil;
}
@@ -180,6 +181,7 @@ fdbm_shift(obj)
DBM *dbm;
VALUE keystr, valstr;
+ rb_secure(4);
GetDBM(obj, dbmp);
dbm = dbmp->di_dbm;
@@ -188,8 +190,8 @@ fdbm_shift(obj)
val = dbm_fetch(dbm, key);
dbm_delete(dbm, key);
- keystr = str_new(key.dptr, key.dsize);
- valstr = str_new(val.dptr, val.dsize);
+ keystr = str_taint(str_new(key.dptr, key.dsize));
+ valstr = str_taint(str_new(val.dptr, val.dsize));
return assoc_new(keystr, valstr);
}
@@ -202,11 +204,12 @@ fdbm_delete_if(obj)
DBM *dbm;
VALUE keystr, valstr;
+ rb_secure(4);
GetDBM(obj, dbmp);
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
val = dbm_fetch(dbm, key);
- keystr = str_new(key.dptr, key.dsize);
- valstr = str_new(val.dptr, val.dsize);
+ keystr = str_taint(str_new(key.dptr, key.dsize));
+ valstr = str_taint(str_new(val.dptr, val.dsize));
if (RTEST(rb_yield(assoc_new(keystr, valstr)))) {
if (dbm_delete(dbm, key)) {
Fail("dbm_delete failed");
@@ -224,6 +227,7 @@ fdbm_clear(obj)
struct dbmdata *dbmp;
DBM *dbm;
+ rb_secure(4);
GetDBM(obj, dbmp);
dbm = dbmp->di_dbm;
dbmp->di_size = -1;
@@ -248,6 +252,7 @@ fdbm_store(obj, keystr, valstr)
return Qnil;
}
+ rb_secure(4);
keystr = obj_as_string(keystr);
key.dptr = RSTRING(keystr)->ptr;
@@ -259,7 +264,7 @@ fdbm_store(obj, keystr, valstr)
val.dptr = RSTRING(valstr)->ptr;
val.dsize = RSTRING(valstr)->len;
- Get_Data_Struct(obj, struct dbmdata, dbmp);
+ Data_Get_Struct(obj, struct dbmdata, dbmp);
dbmp->di_size = -1;
dbm = dbmp->di_dbm;
if (dbm_store(dbm, key, val, DBM_REPLACE)) {
@@ -280,7 +285,7 @@ fdbm_length(obj)
DBM *dbm;
int i = 0;
- Get_Data_Struct(obj, struct dbmdata, dbmp);
+ Data_Get_Struct(obj, struct dbmdata, dbmp);
if (dbmp->di_size > 0) return INT2FIX(dbmp->di_size);
dbm = dbmp->di_dbm;
@@ -293,7 +298,7 @@ fdbm_length(obj)
}
static VALUE
-fdbm_empty(obj)
+fdbm_empty_p(obj)
VALUE obj;
{
datum key;
@@ -301,7 +306,7 @@ fdbm_empty(obj)
DBM *dbm;
int i = 0;
- Get_Data_Struct(obj, struct dbmdata, dbmp);
+ Data_Get_Struct(obj, struct dbmdata, dbmp);
if (dbmp->di_size < 0) {
dbm = dbmp->di_dbm;
@@ -328,7 +333,7 @@ fdbm_each_value(obj)
dbm = dbmp->di_dbm;
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
val = dbm_fetch(dbm, key);
- rb_yield(str_new(val.dptr, val.dsize));
+ rb_yield(str_taint(str_new(val.dptr, val.dsize)));
}
return obj;
}
@@ -344,7 +349,7 @@ fdbm_each_key(obj)
GetDBM(obj, dbmp);
dbm = dbmp->di_dbm;
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
- rb_yield(str_new(key.dptr, key.dsize));
+ rb_yield(str_taint(str_new(key.dptr, key.dsize)));
}
return obj;
}
@@ -363,8 +368,8 @@ fdbm_each_pair(obj)
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
val = dbm_fetch(dbm, key);
- keystr = str_new(key.dptr, key.dsize);
- valstr = str_new(val.dptr, val.dsize);
+ keystr = str_taint(str_new(key.dptr, key.dsize));
+ valstr = str_taint(str_new(val.dptr, val.dsize));
rb_yield(assoc_new(keystr, valstr));
}
@@ -385,7 +390,7 @@ fdbm_keys(obj)
ary = ary_new();
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
- ary_push(ary, str_new(key.dptr, key.dsize));
+ ary_push(ary, str_taint(str_new(key.dptr, key.dsize)));
}
return ary;
@@ -406,7 +411,7 @@ fdbm_values(obj)
ary = ary_new();
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
val = dbm_fetch(dbm, key);
- ary_push(ary, str_new(val.dptr, val.dsize));
+ ary_push(ary, str_taint(str_new(val.dptr, val.dsize)));
}
return ary;
@@ -469,8 +474,8 @@ fdbm_to_a(obj)
ary = ary_new();
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
val = dbm_fetch(dbm, key);
- ary_push(ary, assoc_new(str_new(key.dptr, key.dsize),
- str_new(val.dptr, val.dsize)));
+ ary_push(ary, assoc_new(str_taint(str_new(key.dptr, key.dsize)),
+ str_taint(str_new(val.dptr, val.dsize))));
}
return ary;
@@ -488,7 +493,7 @@ Init_dbm()
rb_define_method(cDBM, "indexes", fdbm_indexes, -2);
rb_define_method(cDBM, "length", fdbm_length, 0);
rb_define_alias(cDBM, "size", "length");
- rb_define_method(cDBM, "empty?", fdbm_empty, 0);
+ rb_define_method(cDBM, "empty?", fdbm_empty_p, 0);
rb_define_method(cDBM, "each", fdbm_each_pair, 0);
rb_define_method(cDBM, "each_value", fdbm_each_value, 0);
rb_define_method(cDBM, "each_key", fdbm_each_key, 0);
diff --git a/ext/dbm/extconf.rb b/ext/dbm/extconf.rb
index 2302ee2d5d..4a5d41f275 100644
--- a/ext/dbm/extconf.rb
+++ b/ext/dbm/extconf.rb
@@ -1,3 +1,4 @@
+$LDFLAGS = "-L/usr/local/lib"
have_library("gdbm", "dbm_open") or have_library("dbm", "dbm_open")
if have_func("dbm_open")
create_makefile("dbm")
diff --git a/ext/etc/etc.c b/ext/etc/etc.c
index 524800bd03..5cab110449 100644
--- a/ext/etc/etc.c
+++ b/ext/etc/etc.c
@@ -123,7 +123,7 @@ static VALUE
etc_passwd(obj)
VALUE obj;
{
-#ifdef HAVE_GETPWENT
+#if defined(HAVE_GETPWENT) && !defined(__CYGWIN32__)
struct passwd *pw;
if (iterator_p()) {
diff --git a/ext/extmk.rb.in b/ext/extmk.rb.in
index bd4eed306b..f1acef5608 100644
--- a/ext/extmk.rb.in
+++ b/ext/extmk.rb.in
@@ -17,6 +17,14 @@ $cache_mod = FALSE;
$lib_cache = {}
$func_cache = {}
$hdr_cache = {}
+$topdir = "@top_srcdir@"
+if $topdir !~ "^/"
+ # get absolute path
+ save = Dir.pwd
+ Dir.chdir ".."
+ $topdir = Dir.pwd
+ Dir.chdir save
+end
if File.exist?("config.cache") then
f = open("config.cache", "r")
@@ -46,14 +54,29 @@ def older(file1, file2)
return FALSE
end
-LINK = "@CC@ -o conftest %s %s conftest.c %s > /dev/null 2>&1"
-CPP = "@CPP@ @CPPFLAGS@ %s conftest.c > /dev/null 2>&1"
+if PLATFORM == "m68k-human"
+CFLAGS = "@CFLAGS@".gsub(/-c..-stack=[0-9]+ */, '')
+LINK = "@CC@ -o conftest -I#{$topdir} " + CFLAGS + " %s @LDFLAGS@ %s conftest.c @LIBS@ %s > nul 2>&1"
+CPP = "@CPP@ @CPPFLAGS@ -I#{$topdir} " + CFLAGS + " %s conftest.c > nul 2>&1"
+else
+CFLAGS = "@CFLAGS@"
+LINK = "@CC@ -o conftest -I#{$topdir} " + CFLAGS + " %s @LDFLAGS@ %s conftest.c %s > /dev/null 2>&1"
+CPP = "@CPP@ @CPPFLAGS@ -I#{$topdir} " + CFLAGS + " %s conftest.c > /dev/null 2>&1"
+end
+
+def try_link(libs)
+ system(format(LINK, $CFLAGS, $LDFLAGS, libs))
+end
+
+def try_cpp
+ system(format(CPP, $CFLAGS))
+end
def have_library(lib, func)
if $lib_cache[lib]
if $lib_cache[lib] == "yes"
if $libs
- $libs = $libs + " -l" + lib
+ $libs = "-l" + lib + " " + $libs
else
$libs = "-l" + lib
end
@@ -72,17 +95,17 @@ int t() { %s(); return 0; }
begin
if $libs
- libs = "-l" + lib + " " + $libs
+ libs = "-l" + lib + " " + $libs
else
libs = "-l" + lib
end
- if !system(format(LINK, $CFLAGS, $LDFLAGS, libs))
+ unless try_link(libs)
$lib_cache[lib] = 'no'
$cache_mod = TRUE
return FALSE
end
ensure
- system "/bin/rm -f conftest*"
+ system "rm -f conftest*"
end
$libs = libs
@@ -113,13 +136,13 @@ int t() { %s(); return 0; }
libs = "" if libs == nil
begin
- if !system(format(LINK, $CFLAGS, $LDFLAGS, libs))
+ unless try_link(libs)
$func_cache[func] = 'no'
$cache_mod = TRUE
return FALSE
end
ensure
- system "/bin/rm -f conftest*"
+ system "rm -f conftest*"
end
$defs.push(format("-DHAVE_%s", func.upcase))
$func_cache[func] = 'yes'
@@ -145,13 +168,13 @@ def have_header(header)
cfile.close
begin
- if !system(format(CPP, $CFLAGS))
+ unless try_cpp
$hdr_cache[header] = 'no'
$cache_mod = TRUE
return FALSE
end
ensure
- system "/bin/rm -f conftest*"
+ system "rm -f conftest*"
end
$hdr_cache[header] = 'yes'
header.tr!("a-z./\055", "A-Z___")
@@ -180,39 +203,39 @@ def create_makefile(target)
end
$defs.push(format("-DEXTLIB='%s'", libs.join(",")))
end
- $libs = "" if not $libs
+ $libs = "" unless $libs
+ $srcdir = $topdir + "/ext/" + target
mfile = open("Makefile", "w")
mfile.printf "\
SHELL = /bin/sh
#### Start of system configuration section. ####
-srcdir = @srcdir@
-VPATH = @srcdir@
+srcdir = #{$srcdir}
+VPATH = #{$srcdir}
CC = @CC@
-CFLAGS = %s #$CFLAGS %s
-LDFLAGS = @LDFLAGS@
-DLDFLAGS = @DLDFLAGS@
+CFLAGS = %s -I#{$topdir} %s #$CFLAGS %s
+DLDFLAGS = @DLDFLAGS@ #$LDFLAGS
LDSHARED = @LDSHARED@
-", if $static then "" else "@CCDLFLAGS@" end, $defs.join(" ")
+", if $static then "" else "@CCDLFLAGS@" end, CFLAGS, $defs.join(" ")
mfile.printf "\
prefix = @prefix@
exec_prefix = @exec_prefix@
-bindir = $(exec_prefix)/bin
-libdir = @archlib@
+libdir = @libdir@/ruby/@arch@
@SET_MAKE@
#### End of system configuration section. ####
"
+ mfile.printf "LOCAL_LIBS = %s\n", $local_libs if $local_libs
mfile.printf "LIBS = %s\n", $libs
mfile.printf "OBJS = "
if !$objs then
- $objs = Dir["*.c"]
+ $objs = Dir["#{$topdir}/ext/#{target}/*.c"]
for f in $objs
f.sub!(/\.c$/, ".o")
end
@@ -220,17 +243,19 @@ libdir = @archlib@
mfile.printf $objs.join(" ")
mfile.printf "\n"
- dots = if "@INSTALL@" =~ /^\// then "" else "../" end
+ dots = if "@INSTALL@" =~ /^\// then "" else "#{$topdir}/" end
mfile.printf "\
TARGET = %s.%s
INSTALL = %s@INSTALL@
+binsuffix = @binsuffix@
+
all: $(TARGET)
clean:; @rm -f *.o *.so *.sl
@rm -f Makefile extconf.h conftest.*
- @rm -f core ruby *~
+ @rm -f core ruby$(binsuffix) *~
realclean: clean
", target,
@@ -255,13 +280,20 @@ install:;
if !$static && "@DLEXT@" != "o"
mfile.printf "\
$(TARGET): $(OBJS)
- $(LDSHARED) $(DLDFLAGS) -o $(TARGET) $(OBJS) $(LIBS)
+ $(LDSHARED) $(DLDFLAGS) -o $(TARGET) $(OBJS) $(LOCAL_LIBS) $(LIBS)
+"
+ elsif not File.exist?(target + ".c")
+ if PLATFORM == "m68k-human"
+ mfile.printf "\
+$(TARGET): $(OBJS)
+ ar cru $(TARGET) $(OBJS)
"
- elsif !File.exist?(target + ".c")
+ else
mfile.printf "\
$(TARGET): $(OBJS)
- ld $(LDFLAGS) -r -o $(TARGET) $(OBJS)
+ ld $(DLDFLAGS) -r -o $(TARGET) $(OBJS)
"
+ end
end
if File.exist?("depend")
@@ -287,16 +319,18 @@ def extmake(target)
return if $nodynamic and not $static
+ $local_libs = nil
$libs = nil
$objs = nil
- $CFLAGS = "-I../.. @CFLAGS@"
- $LDFLAGS = "@STATIC@ @LDFLAGS@"
+ $CFLAGS = nil
+ $LDFLAGS = nil
begin
+ system "mkdir " + target unless File.directory?(target)
Dir.chdir target
if $static_ext.size > 0 ||
!File.exist?("./Makefile") ||
- older("./Makefile", "../Setup") ||
+ older("./Makefile", "#{$topdir}/ext/@setup@") ||
older("./Makefile", "../extmk.rb") ||
older("./Makefile", "./extconf.rb")
then
@@ -316,7 +350,11 @@ def extmake(target)
system "make all"
end
end
- $extlibs += " " + $libs if $static && $libs
+ if $static
+ $extlibs += " " + $LDFLAGS if $LDFLAGS
+ $extlibs += " " + $local_libs if $local_libs
+ $extlibs += " " + $libs if $libs
+ end
ensure
Dir.chdir ".."
end
@@ -324,8 +362,8 @@ end
# get static-link modules
$static_ext = {}
-if File.file? "./Setup"
- f = open("./Setup")
+if File.file? "#{$topdir}/ext/@setup@"
+ f = open("#{$topdir}/ext/@setup@")
while f.gets()
$_.chop!
sub!(/#.*$/, '')
@@ -339,11 +377,11 @@ if File.file? "./Setup"
f.close
end
-for d in Dir["*"]
+for d in Dir["#{$topdir}/ext/*"]
File.directory?(d) || next
File.file?(d + "/MANIFEST") || next
- d = $1 if d =~ /\/([\/]*)$/
+ d = File.basename(d)
if $install
print "installing ", d, "\n"
elsif $clean
@@ -385,7 +423,7 @@ if $extlist.size > 0
end
end
- if older("extinit.c", "Setup")
+ if older("extinit.c", "#{$topdir}/ext/@setup@")
f = open("extinit.c", "w")
f.printf "void Init_ext() {\n"
f.printf $extinit
@@ -393,24 +431,24 @@ if $extlist.size > 0
f.close
end
if older("extinit.o", "extinit.c")
- cmd = "@CC@ @CFLAGS@ -c extinit.c"
+ cmd = "@CC@ " + CFLAGS + " -c extinit.c"
print cmd, "\n"
system cmd or exit 1
end
Dir.chdir ".."
- if older("ruby", "ext/Setup") or older("ruby", "miniruby")
- `rm -f ruby`
+ if older("ruby@binsuffix@", "#{$topdir}/ext/@setup@") or older("ruby@binsuffix@", "miniruby@binsuffix@")
+ `rm -f ruby@binsuffix@`
end
$extobjs = "ext/extinit.o " + $extobjs
- system format('make ruby PROGRAM=ruby EXTOBJS="%s" EXTLIBS="%s"', $extobjs, $extlibs)
+ system format('make ruby@binsuffix@ EXTOBJS="%s" EXTLIBS="%s"', $extobjs, $extlibs)
else
Dir.chdir ".."
- if older("ruby", "miniruby")
- `rm -f ruby`
- `cp miniruby ruby`
+ if older("ruby@binsuffix@", "miniruby@binsuffix@")
+ `rm -f ruby@binsuffix@`
+ `cp miniruby@binsuffix@ ruby@binsuffix@`
end
end
diff --git a/ext/extmk.rb.nt b/ext/extmk.rb.nt
new file mode 100644
index 0000000000..33f676a804
--- /dev/null
+++ b/ext/extmk.rb.nt
@@ -0,0 +1,436 @@
+#! /usr/local/bin/ruby
+
+if ARGV[0] == 'static'
+ $force_static = TRUE
+ ARGV.shift
+elsif ARGV[0] == 'install'
+ $install = TRUE
+ ARGV.shift
+elsif ARGV[0] == 'clean'
+ $clean = TRUE
+ ARGV.shift
+end
+
+$extlist = []
+
+$cache_mod = FALSE;
+$lib_cache = {}
+$func_cache = {}
+$hdr_cache = {}
+
+if File.exist?("config.cache") then
+ f = open("config.cache", "r")
+ while f.gets
+ case $_
+ when /^lib: ([\w_]+) (yes|no)/
+ $lib_cache[$1] = $2
+ when /^func: ([\w_]+) (yes|no)/
+ $func_cache[$1] = $2
+ when /^hdr: (.+) (yes|no)/
+ $hdr_cache[$1] = $2
+ end
+ end
+ f.close
+end
+
+def older(file1, file2)
+ if !File.exist?(file1) then
+ return TRUE
+ end
+ if !File.exist?(file2) then
+ return FALSE
+ end
+ if File.mtime(file1) < File.mtime(file2)
+ return TRUE
+ end
+ return FALSE
+end
+
+LINK = "cl -o conftest -I../.. -Zi -O -I. %s %s conftest.c %s > nul"
+CPP = "cl -E -I../.. -Zi -O -I. %s conftest.c > nul"
+
+def try_link(libs)
+ system(format(LINK, $CFLAGS, $LDFLAGS, libs))
+end
+
+def try_cpp
+ system(format(CPP, $CFLAGS))
+end
+
+def have_library(lib, func)
+ if $lib_cache[lib]
+ if $lib_cache[lib] == "yes"
+ if $libs
+ $libs = "-l" + lib + " " + $libs
+ else
+ $libs = "-l" + lib
+ end
+ return TRUE
+ else
+ return FALSE
+ end
+ end
+
+ cfile = open("conftest.c", "w")
+ cfile.printf "\
+int main() { return 0; }
+int t() { %s(); return 0; }
+", func
+ cfile.close
+
+ begin
+ if $libs
+ libs = lib + ".lib " + $libs
+ else
+ libs = lib + ".lib"
+ end
+ unless try_link(libs)
+ $lib_cache[lib] = 'no'
+ $cache_mod = TRUE
+ return FALSE
+ end
+ ensure
+ system "rm -f conftest*"
+ end
+
+ $libs = libs
+ $lib_cache[lib] = 'yes'
+ $cache_mod = TRUE
+ return TRUE
+end
+
+def have_func(func)
+ if $func_cache[func]
+ if $func_cache[func] == "yes"
+ $defs.push(format("-DHAVE_%s", func.upcase))
+ return TRUE
+ else
+ return FALSE
+ end
+ end
+
+ cfile = open("conftest.c", "w")
+ cfile.printf "\
+char %s();
+int main() { return 0; }
+int t() { %s(); return 0; }
+", func, func
+ cfile.close
+
+ libs = $libs
+ libs = "" if libs == nil
+
+ begin
+ unless try_link(libs)
+ $func_cache[func] = 'no'
+ $cache_mod = TRUE
+ return FALSE
+ end
+ ensure
+ system "rm -f conftest*"
+ end
+ $defs.push(format("-DHAVE_%s", func.upcase))
+ $func_cache[func] = 'yes'
+ $cache_mod = TRUE
+ return TRUE
+end
+
+def have_header(header)
+ if $hdr_cache[header]
+ if $hdr_cache[header] == "yes"
+ header.tr!("a-z./\055", "A-Z___")
+ $defs.push(format("-DHAVE_%s", header))
+ return TRUE
+ else
+ return FALSE
+ end
+ end
+
+ cfile = open("conftest.c", "w")
+ cfile.printf "\
+#include <%s>
+", header
+ cfile.close
+
+ begin
+ unless try_cpp
+ $hdr_cache[header] = 'no'
+ $cache_mod = TRUE
+ return FALSE
+ end
+ ensure
+ system "rm -f conftest*"
+ end
+ $hdr_cache[header] = 'yes'
+ header.tr!("a-z./\055", "A-Z___")
+ $defs.push(format("-DHAVE_%s", header))
+ $cache_mod = TRUE
+ return TRUE
+end
+
+def create_header()
+ if $defs.length > 0
+ hfile = open("extconf.h", "w")
+ for line in $defs
+ line =~ /^-D(.*)/
+ hfile.printf "#define %s 1\n", $1
+ end
+ hfile.close
+ end
+end
+
+def create_makefile(target)
+
+ if $libs and "obj" == "obj"
+ libs = $libs.split
+ for lib in libs
+ lib.sub!(/(.*)/, '"lib\1.lib"')
+ end
+ $defs.push(format("-DEXTLIB='%s'", libs.join(",")))
+ end
+ $libs = "" unless $libs
+
+ mfile = open("Makefile", "w")
+ mfile.printf "\
+SHELL = $(COMPSEC)
+
+#### Start of system configuration section. ####
+
+srcdir = .
+VPATH = .
+
+CC = cl
+
+CFLAGS = %s -I../.. -Zi -O -I. -DNT -MD #$CFLAGS %s
+DLDFLAGS = /DLL
+LDSHARED =
+", if $static then "" else "-fpic" end, $defs.join(" ")
+
+ mfile.printf "\
+
+libdir = /usr/local/lib/ruby/i386-mswin32
+
+
+#### End of system configuration section. ####
+"
+ mfile.printf "LOCAL_LIBS = %s\n", $local_libs if $local_libs
+ mfile.printf "LIBS = %s\n", $libs
+ mfile.printf "OBJS = "
+ if !$objs then
+ $objs = Dir["*.c"]
+ for f in $objs
+ f.sub!(/\.c$/, ".obj")
+ end
+ end
+ mfile.printf $objs.join(" ")
+ mfile.printf "\n"
+
+ dots = if "ginstall -c" =~ /^\// then "" else "../" end
+ mfile.printf "\
+TARGET = %s.%s
+
+INSTALL = %sginstall -c
+
+all: $(TARGET)
+
+clean:; @rm -f *.obj *.lib *.exp *.pdb *.bak
+ @rm -f Makefile extconf.h conftest.*
+
+realclean: clean
+", target,
+ if $static then "obj" else "obj" end, dots
+
+ if !$static
+ mfile.printf "\
+
+install: $(libdir)/$(TARGET)
+
+$(libdir)/$(TARGET): $(TARGET)
+ @test -d $(libdir) || mkdir $(libdir)
+ $(INSTALL) $(TARGET) $(libdir)/$(TARGET)
+"
+ else
+ mfile.printf "\
+
+install:;
+"
+ end
+
+ if !$static && "obj" != "obj"
+ mfile.printf "\
+$(TARGET): $(OBJS)
+ $(LDSHARED) $(DLDFLAGS) -o $(TARGET) $(OBJS) $(LOCAL_LIBS) $(LIBS)
+"
+ elsif not File.exist?(target + ".c")
+ mfile.printf "\
+$(TARGET): $(OBJS)
+# ld $(DLDFLAGS) -r -o $(TARGET) $(OBJS)
+ cl -c $(OBJS)
+ lib /OUT:$(TARGET) $(OBJS)
+"
+ end
+
+ if File.exist?("depend")
+ dfile = open("depend", "r")
+ mfile.printf "###\n"
+ while line = dfile.gets()
+ mfile.printf "%s", line
+ end
+ dfile.close
+ end
+ mfile.close
+ if $static
+ printf format("push %s,%s\n", $static, target); ##debug print##
+ $extlist.push [$static,target]
+ end
+end
+
+def extmake(target)
+ if $force_static or $static_ext[target]
+ $static = target
+ else
+ $static = FALSE
+ end
+
+ return if $nodynamic and not $static
+
+ $local_libs = nil
+ $libs = nil
+ $objs = nil
+ $CFLAGS = nil
+ $LDFLAGS = nil
+
+ begin
+ Dir.chdir target
+ if $static_ext.size > 0 ||
+ !File.exist?("./Makefile") ||
+ older("./Makefile", "../Setup") ||
+ older("./Makefile", "../extmk.rb") ||
+ older("./Makefile", "./extconf.rb")
+ then
+ $defs = []
+ if File.exist?("extconf.rb")
+ load "extconf.rb"
+ else
+ create_makefile(target);
+ end
+ end
+ if File.exist?("./Makefile")
+ if $install
+ system "nmake install"
+ elsif $clean
+ system "nmake clean"
+ else
+ system "nmake all"
+ end
+ end
+ if $static
+ $extlibs += " " + $LDFLAGS if $LDFLAGS
+ $extlibs += " " + $local_libs if $local_libs
+ $extlibs += " " + $libs if $libs
+ end
+ ensure
+ Dir.chdir ".."
+ end
+end
+
+# get static-link modules
+$static_ext = {}
+if File.file? "./Setup"
+ f = open("./Setup")
+ while f.gets()
+ $_.chop!
+ sub!(/#.*$/, '')
+ next if /^\s*$/
+ print $_, "\n"
+ if /^option +nodynamic/
+ $nodynamic = TRUE
+ next
+ end
+ $static_ext[$_.split[0]] = TRUE
+ end
+ f.close
+end
+
+for d in Dir["*"]
+ File.directory?(d) || next
+ File.file?(d + "/MANIFEST") || next
+
+ d = $1 if d =~ /\/([\/]*)$/
+ if $install
+ print "installing ", d, "\n"
+ elsif $clean
+ print "cleaning ", d, "\n"
+ else
+ print "compiling ", d, "\n"
+ end
+ extmake(d)
+end
+
+if $cache_mod
+ f = open("config.cache", "w")
+ for k,v in $lib_cache
+ f.printf "lib: %s %s\n", k, v
+ end
+ for k,v in $func_cache
+ f.printf "func: %s %s\n", k, v
+ end
+ for k,v in $hdr_cache
+ f.printf "hdr: %s %s\n", k, v
+ end
+ f.close
+end
+
+exit if $install or $clean
+if $extlist.size > 0
+ #for s,t in $extlist
+ for s,t in $static_ext
+ #f = format("%s/%s.obj", s, t)
+ f = format("%s/%s.obj", s, s)
+ #print format("%s/%s.obj\n", s, s) ##debug print##
+ if File.exist?(f)
+ $extinit += format("\
+\tInit_%s();\n\
+\trb_provide(\"%s.o\");\n\
+", s, s)
+ $extobjs += "ext/"
+ $extobjs += f
+ $extobjs += " "
+ else
+ FALSE
+ end
+ end
+
+ if older("extinit.c", "Setup")
+ f = open("extinit.c", "w")
+ f.printf "void Init_ext() {\n"
+ f.printf $extinit
+ f.printf "}\n"
+ f.close
+ end
+ if older("extinit.obj", "extinit.c")
+ cmd = "cl -Zi -O -I. -c extinit.c"
+ print cmd, "\n"
+ system cmd or exit 1
+ end
+
+ Dir.chdir ".."
+
+ if older("ruby.exe", "ext/Setup") or older("ruby.exe", "miniruby.exe")
+ `rm -f ruby.exe`
+ end
+
+ $extobjs = "ext/extinit.obj " + $extobjs
+ $extlibs = ""
+ system format('nmake ruby.exe EXTOBJS="%s" EXTLIBS="%s"', $extobjs, $extlibs)
+else
+ Dir.chdir ".."
+ if older("ruby.exe", "miniruby.exe")
+ `rm -f ruby.exe`
+ `cp miniruby.exe ruby.exe`
+ end
+end
+
+#Local variables:
+# mode: ruby
+#end:
diff --git a/ext/fcntl/MANIFEST b/ext/fcntl/MANIFEST
new file mode 100644
index 0000000000..aef7ad4ca0
--- /dev/null
+++ b/ext/fcntl/MANIFEST
@@ -0,0 +1,3 @@
+MANIFEST
+depend
+fcntl.c
diff --git a/ext/fcntl/depend b/ext/fcntl/depend
new file mode 100644
index 0000000000..3c7ef8485e
--- /dev/null
+++ b/ext/fcntl/depend
@@ -0,0 +1 @@
+fcntl.o: fcntl.c ../../ruby.h ../../config.h ../../defines.h
diff --git a/ext/fcntl/fcntl.c b/ext/fcntl/fcntl.c
new file mode 100644
index 0000000000..977d5951a8
--- /dev/null
+++ b/ext/fcntl/fcntl.c
@@ -0,0 +1,106 @@
+/************************************************
+
+ fcntl.c -
+
+ $Author: matz $
+ created at: Mon Apr 7 18:53:05 JST 1997
+
+ Copyright (C) 1997 Yukihiro Matsumoto
+
+************************************************/
+
+/************************************************
+= NAME
+
+fcntl - load the C fcntl.h defines
+
+= SYNOPSIS
+
+ require "fcntl"
+ m = s.fcntl(Fcntl::F_GETFL, 0)
+ f.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK|m)
+
+= DESCRIPTION
+
+This module is just a translation of the C <fnctl.h> file.
+
+= NOTE
+
+Only #define symbols get translated; you must still correctly
+pack up your own arguments to pass as args for locking functions, etc.
+
+************************************************/
+
+#include "ruby.h"
+#include <fcntl.h>
+
+Init_fcntl()
+{
+ VALUE mFcntl = rb_define_module("Fcntl");
+#ifdef F_DUPFD
+ rb_define_const(mFcntl, "F_DUPFD", INT2NUM(F_DUPFD));
+#endif
+#ifdef F_GETFD
+ rb_define_const(mFcntl, "F_GETFD", INT2NUM(F_GETFD));
+#endif
+#ifdef F_GETLK
+ rb_define_const(mFcntl, "F_GETLK", INT2NUM(F_GETLK));
+#endif
+#ifdef F_SETFD
+ rb_define_const(mFcntl, "F_SETFD", INT2NUM(F_SETFD));
+#endif
+#ifdef F_GETFL
+ rb_define_const(mFcntl, "F_GETFL", INT2NUM(F_GETFL));
+#endif
+#ifdef F_SETFL
+ rb_define_const(mFcntl, "F_SETFL", INT2NUM(F_SETFL));
+#endif
+#ifdef F_SETLK
+ rb_define_const(mFcntl, "F_SETLK", INT2NUM(F_SETLK));
+#endif
+#ifdef F_SETLKW
+ rb_define_const(mFcntl, "F_SETLKW", INT2NUM(F_SETLKW));
+#endif
+#ifdef FD_CLOEXEC
+ rb_define_const(mFcntl, "FD_CLOEXEC", INT2NUM(FD_CLOEXEC));
+#endif
+#ifdef F_RDLCK
+ rb_define_const(mFcntl, "F_RDLCK", INT2NUM(F_RDLCK));
+#endif
+#ifdef F_UNLCK
+ rb_define_const(mFcntl, "F_UNLCK", INT2NUM(F_UNLCK));
+#endif
+#ifdef F_WRLCK
+ rb_define_const(mFcntl, "F_WRLCK", INT2NUM(F_WRLCK));
+#endif
+#ifdef O_CREAT
+ rb_define_const(mFcntl, "O_CREAT", INT2NUM(O_CREAT));
+#endif
+#ifdef O_EXCL
+ rb_define_const(mFcntl, "O_EXCL", INT2NUM(O_EXCL));
+#endif
+#ifdef O_NOCTTY
+ rb_define_const(mFcntl, "O_NOCTTY", INT2NUM(O_NOCTTY));
+#endif
+#ifdef O_TRUNC
+ rb_define_const(mFcntl, "O_TRUNC", INT2NUM(O_TRUNC));
+#endif
+#ifdef O_APPEND
+ rb_define_const(mFcntl, "O_APPEND", INT2NUM(O_APPEND));
+#endif
+#ifdef O_NONBLOCK
+ rb_define_const(mFcntl, "O_NONBLOCK", INT2NUM(O_NONBLOCK));
+#endif
+#ifdef O_NDELAY
+ rb_define_const(mFcntl, "O_NDELAY", INT2NUM(O_NDELAY));
+#endif
+#ifdef O_RDONLY
+ rb_define_const(mFcntl, "O_RDONLY", INT2NUM(O_RDONLY));
+#endif
+#ifdef O_RDWR
+ rb_define_const(mFcntl, "O_RDWR", INT2NUM(O_RDWR));
+#endif
+#ifdef O_WRONLY
+ rb_define_const(mFcntl, "O_WRONLY", INT2NUM(O_WRONLY));
+#endif
+}
diff --git a/ext/kconv/MANIFEST b/ext/kconv/MANIFEST
index 8f37a9e166..cb89e8239c 100644
--- a/ext/kconv/MANIFEST
+++ b/ext/kconv/MANIFEST
@@ -1,2 +1,3 @@
MANIFEST
+depend
kconv.c
diff --git a/ext/kconv/depend b/ext/kconv/depend
new file mode 100644
index 0000000000..e87b1fdea7
--- /dev/null
+++ b/ext/kconv/depend
@@ -0,0 +1 @@
+kconv.o: kconv.c ../../ruby.h ../../config.h ../../defines.h
diff --git a/ext/kconv/kconv.c b/ext/kconv/kconv.c
index 791b34b26b..3c59cb6acf 100644
--- a/ext/kconv/kconv.c
+++ b/ext/kconv/kconv.c
@@ -82,9 +82,6 @@ static char *Patchlevel =
/* #define DEFAULT_CODE_SJIS */
/* #define DEFAULT_CODE_EUC */
/******************************/
-/* プロトタイプの選択 */
-#define ANSI_C_PROTOTYPE
-/******************************/
/* for Kconv: _AUTO, _EUC, _SJIS, _JIS */
#define _AUTO 0
@@ -92,10 +89,6 @@ static char *Patchlevel =
#define _EUC 2
#define _SJIS 3
-#ifdef __STDC__
-#define ANSI_C_PROTOTYPE
-#endif
-
#if (defined(__TURBOC__) || defined(LSI_C)) && !defined(MSDOS)
#define MSDOS
#endif
@@ -202,10 +195,6 @@ static unsigned int mime_input = 0; /* undecoded */
/* flags */
static int unbuf_f = FALSE;
static int estab_f = FALSE;
-#ifdef notdef
-static int nop_f = FALSE;
-static int binmode_f = TRUE; /* binary mode */
-#endif
static int rot_f = FALSE; /* rot14/43 mode */
static int input_f = FALSE; /* non fixed input code */
static int alpha_f = FALSE; /* convert JIx0208 alphbet to ASCII */
@@ -235,7 +224,6 @@ static char kanji_intro = DEFAULT_J,
/* Folding */
-static int fold();
#define FOLD_MARGIN 10
#define DEFAULT_FOLD 60
@@ -345,43 +333,25 @@ static int mime_encode[] = {
0
};
-#ifdef notdef
-static int file_out = FALSE;
-static int end_check;
-#endif
static int add_cr = FALSE;
static int del_cr = FALSE;
-/* function prototype */
-#ifdef ANSI_C_PROTOTYPE
-static void (*iconv) (register int c2,register int c1); /* s_iconv or oconv */
-static void (*oconv) (register int c2,register int c1); /* [ejs]_oconv */
-static int do_kconv(char *i, char *o, int siz, int out_code, int in_code);
-static void h_conv(register int c2,register int c1);
-static int push_hold_buf(int c2,int c1);
-static void s_iconv(register int c2,register int c1);
-static void e_oconv(register int c2,register int c1);
-static void s_oconv(register int c2,register int c1);
-static void j_oconv(register int c2,register int c1);
-static int fold(register int c2,register int c1);
-static int pre_convert(register int c1,register int c2);
-static int mime_begin();
-static int mime_getc();
-static int mime_ungetc(unsigned int c);
-static int mime_integrity(unsigned char *p);
-static int base64decode(int c);
-#else
-static void (*iconv) (); /* s_iconv or oconv */
-static void (*oconv) (); /* [ejs]_oconv */
-static int s_iconv ();
-static int e_oconv ();
-static int j_oconv ();
-static int s_oconv ();
-static int noconvert ();
-static int do_kconv();
-static void h_conv ();
-static int push_hold_buf ();
-#endif
+static void (*iconv) _((register int c2,register int c1)); /* s_iconv or oconv */
+static void (*oconv) _((register int c2,register int c1)); /* [ejs]_oconv */
+static int do_kconv _((char *i, char *o, int siz, int out_code, int in_code));
+static void h_conv _((register int c2,register int c1));
+static int push_hold_buf _((int c2,int c1));
+static void s_iconv _((register int c2,register int c1));
+static void e_oconv _((register int c2,register int c1));
+static void s_oconv _((register int c2,register int c1));
+static void j_oconv _((register int c2,register int c1));
+static int fold _((register int c2,register int c1));
+static int pre_convert _((register int c1,register int c2));
+static int mime_begin _((void));
+static int mime_getc _((void));
+static int mime_ungetc _((unsigned int c));
+static int mime_integrity _((unsigned char *p));
+static int base64decode _((int c));
#ifdef notdef
main (argc, argv)
@@ -414,9 +384,6 @@ main (argc, argv)
case 'u': /* non bufferd mode */
unbuf_f = TRUE;
continue;
- case 't': /* transparent mode */
- nop_f = TRUE;
- continue;
case 'j': /* JIS output */
case 'n':
oconv = j_oconv;
@@ -553,10 +520,7 @@ main (argc, argv)
setbinmode(stdin);
#endif
setvbuffer (stdin, stdibuf, IOBUF_SIZE);
- if(nop_f)
- noconvert (stdin);
- else
- convert (stdin);
+ convert (stdin);
} else {
while (argc--) {
if((fin = fopen (*argv++, "r")) == NULL) {
@@ -594,10 +558,7 @@ main (argc, argv)
setbinmode(fin);
#endif
setvbuffer (fin, stdibuf, IOBUF_SIZE);
- if(nop_f)
- noconvert (fin);
- else
- convert (fin);
+ convert (fin);
fclose (fin);
}
}
@@ -613,18 +574,6 @@ main (argc, argv)
#endif
return (0);
}
-
-int
-noconvert (f)
- register FILE *f;
-{
- register int c;
-
- while ((c = getc (f)) != EOF)
- putchar (c);
- return 1;
-}
-
#endif /* notdef */
static int
diff --git a/ext/marshal/extconf.rb b/ext/marshal/extconf.rb
index 65923049e5..ab30bd117b 100644
--- a/ext/marshal/extconf.rb
+++ b/ext/marshal/extconf.rb
@@ -1,2 +1 @@
-have_func("tmpnam")
create_makefile("marshal")
diff --git a/ext/marshal/marshal.c b/ext/marshal/marshal.c
index eae8d7fe09..47cb0fcd2a 100644
--- a/ext/marshal/marshal.c
+++ b/ext/marshal/marshal.c
@@ -13,131 +13,167 @@
#include "io.h"
#include "st.h"
-#define MARSHAL_MAJOR 2
-#define MARSHAL_MINOR 1
+#define MARSHAL_MAJOR 4
+#define MARSHAL_MINOR 0
#define TYPE_NIL '0'
#define TYPE_TRUE 'T'
#define TYPE_FALSE 'F'
#define TYPE_FIXNUM 'i'
+#define TYPE_UCLASS 'C'
#define TYPE_OBJECT 'o'
#define TYPE_USERDEF 'u'
#define TYPE_FLOAT 'f'
#define TYPE_BIGNUM 'l'
#define TYPE_STRING '"'
-#define TYPE_STRING2 '\''
#define TYPE_REGEXP '/'
#define TYPE_ARRAY '['
-#define TYPE_ARRAY2 ']'
#define TYPE_HASH '{'
-#define TYPE_HASH2 '}'
#define TYPE_STRUCT 'S'
+#define TYPE_MODULE 'M'
#define TYPE_SYMBOL ':'
#define TYPE_SYMLINK ';'
-VALUE cString;
-VALUE cArray;
-VALUE cHash;
+#define TYPE_LINK '@'
+
+extern VALUE cString;
+extern VALUE cRegexp;
+extern VALUE cArray;
+extern VALUE cHash;
-char *rb_class2path();
VALUE rb_path2class();
static ID s_dump, s_load;
-#if (defined(linux) && defined(USE_DLN_A_OUT)) || !defined(HAVE_TMPNAM)
-#define tmpnam(s) ltmpnam(s)
-static char *
-tmpnam(s)
- char *s;
-{
- static int n = 0;
+struct dump_arg {
+ VALUE obj;
+ FILE *fp;
+ struct RString *str;
+ st_table *symbol;
+ st_table *data;
+};
+
+struct dump_call_arg {
+ VALUE obj;
+ struct dump_arg *arg;
+ int limit;
+};
+
+static void w_long _((long, struct dump_arg*));
- sprintf(s, "/tmp/rb-mrsr-%x%x", getpid(), n++);
- return s;
+static void
+w_byte(c, arg)
+ char c;
+ struct dump_arg *arg;
+{
+ if (arg->fp) putc(c, arg->fp);
+ else str_cat(arg->str, &c, 1);
}
-#endif
-#define w_byte(c, fp) putc((c), fp)
-#define w_bytes(s, n, fp) (w_long((n), fp),fwrite(s, 1, n, fp))
+static void
+w_bytes(s, n, arg)
+ char *s;
+ int n;
+ struct dump_arg *arg;
+{
+ w_long(n, arg);
+ if (arg->fp) {
+ fwrite(s, 1, n, arg->fp);
+ }
+ else {
+ str_cat(arg->str, s, n);
+ }
+}
static void
-w_short(x, fp)
+w_short(x, arg)
int x;
- FILE *fp;
+ struct dump_arg *arg;
{
- w_byte( x & 0xff, fp);
- w_byte((x>> 8) & 0xff, fp);
+ w_byte( x & 0xff, arg);
+ w_byte((x>> 8) & 0xff, arg);
}
static void
-w_long(x, fp)
+w_long(x, arg)
long x;
- FILE *fp;
+ struct dump_arg *arg;
{
- w_byte((int)( x & 0xff), fp);
- w_byte((int)((x>> 8) & 0xff), fp);
- w_byte((int)((x>>16) & 0xff), fp);
- w_byte((int)((x>>24) & 0xff), fp);
+ char buf[sizeof(long)+1];
+ int i, len = 0;
+
+ if (x == 0) {
+ w_byte(0, arg);
+ return;
+ }
+ for (i=1;i<sizeof(long)+1;i++) {
+ buf[i] = x & 0xff;
+ x = RSHIFT(x,8);
+ if (x == 0) {
+ buf[0] = i;
+ break;
+ }
+ if (x == -1) {
+ buf[0] = -i;
+ break;
+ }
+ }
+ len = i;
+ for (i=0;i<=len;i++) {
+ w_byte(buf[i], arg);
+ }
}
static void
-w_float(d, fp)
+w_float(d, arg)
double d;
- FILE *fp;
+ struct dump_arg *arg;
{
char buf[100];
sprintf(buf, "%.12g", d);
- w_bytes(buf, strlen(buf), fp);
+ w_bytes(buf, strlen(buf), arg);
}
static void
-w_symbol(id, fp, table)
+w_symbol(id, arg)
ID id;
- FILE *fp;
- st_table *table;
+ struct dump_arg *arg;
{
char *sym = rb_id2name(id);
int num;
- if (st_lookup(table, id, &num)) {
- w_byte(TYPE_SYMLINK, fp);
- w_long(num, fp);
+ if (st_lookup(arg->symbol, id, &num)) {
+ w_byte(TYPE_SYMLINK, arg);
+ w_long(num, arg);
}
else {
- w_byte(TYPE_SYMBOL, fp);
- w_bytes(sym, strlen(sym), fp);
- st_insert(table, id, table->num_entries);
+ w_byte(TYPE_SYMBOL, arg);
+ w_bytes(sym, strlen(sym), arg);
+ st_insert(arg->symbol, id, arg->symbol->num_entries);
}
}
static void
-w_unique(s, fp, table)
+w_unique(s, arg)
char *s;
- FILE *fp;
- st_table *table;
+ struct dump_arg *arg;
{
- w_symbol(rb_intern(s), fp, table);
+ w_symbol(rb_intern(s), arg);
}
-static void w_object();
-extern VALUE cBignum, cStruct;
-
-struct each_arg {
- FILE *fp;
- VALUE limit;
- st_table *table;
-};
+static void w_object _((VALUE,struct dump_arg*,int));
+extern VALUE cIO, cBignum, cStruct;
static int
hash_each(key, value, arg)
VALUE key, value;
- struct each_arg *arg;
+ struct dump_call_arg *arg;
{
- w_object(key, arg->fp, arg->limit, arg->table);
- w_object(value, arg->fp, arg->limit, arg->table);
+ w_object(key, arg->arg, arg->limit);
+ w_object(value, arg->arg, arg->limit);
return ST_CONTINUE;
}
@@ -145,154 +181,166 @@ static int
obj_each(id, value, arg)
ID id;
VALUE value;
- struct each_arg *arg;
+ struct dump_call_arg *arg;
{
- w_symbol(id, arg->fp, arg->table);
- w_object(value, arg->fp, arg->limit, arg->table);
+ w_symbol(id, arg->arg);
+ w_object(value, arg->arg, arg->limit);
return ST_CONTINUE;
}
static void
-w_object(obj, fp, limit, table)
+w_uclass(obj, class, arg)
+ VALUE obj, class;
+ struct dump_arg *arg;
+{
+ if (CLASS_OF(obj) != class) {
+ w_byte(TYPE_UCLASS, arg);
+ w_unique(rb_class2name(CLASS_OF(obj)), arg);
+ }
+}
+
+static void
+w_object(obj, arg, limit)
VALUE obj;
- FILE *fp;
+ struct dump_arg *arg;
int limit;
- st_table *table;
{
- struct each_arg arg;
int n;
+ struct dump_call_arg c_arg;
if (limit == 0) {
Fail("exceed depth limit");
}
limit--;
-
- arg.fp = fp;
- arg.limit = limit;
- arg.table = table;
+ c_arg.limit = limit;
+ c_arg.arg = arg;
if (obj == Qnil) {
- w_byte(TYPE_NIL, fp);
+ w_byte(TYPE_NIL, arg);
}
else if (obj == TRUE) {
- w_byte(TYPE_TRUE, fp);
+ w_byte(TYPE_TRUE, arg);
}
else if (obj == FALSE) {
- w_byte(TYPE_FALSE, fp);
+ w_byte(TYPE_FALSE, arg);
}
else if (FIXNUM_P(obj)) {
if (sizeof(long) == 4) {
- w_byte(TYPE_FIXNUM, fp);
- w_long(FIX2INT(obj), fp);
+ w_byte(TYPE_FIXNUM, arg);
+ w_long(FIX2INT(obj), arg);
}
}
else {
+ int num;
+
+ if (st_lookup(arg->data, obj, &num)) {
+ w_byte(TYPE_LINK, arg);
+ w_long(num, arg);
+ return;
+ }
+ st_insert(arg->data, obj, arg->data->num_entries);
if (rb_respond_to(obj, s_dump)) {
VALUE v;
- w_byte(TYPE_USERDEF, fp);
- w_unique(rb_class2path(CLASS_OF(obj)), fp, table);
+ w_byte(TYPE_USERDEF, arg);
+ w_unique(rb_class2name(CLASS_OF(obj)), arg);
v = rb_funcall(obj, s_dump, 1, limit);
if (TYPE(v) != T_STRING) {
TypeError("_dump_to must return String");
}
- w_bytes(RSTRING(v)->ptr, RSTRING(v)->len, fp);
+ w_bytes(RSTRING(v)->ptr, RSTRING(v)->len, arg);
return;
}
+
switch (BUILTIN_TYPE(obj)) {
+ case T_MODULE:
+ case T_CLASS:
+ w_byte(TYPE_MODULE, arg);
+ {
+ VALUE path = rb_class_path(obj);
+ w_bytes(RSTRING(path)->ptr, RSTRING(path)->len, arg);
+ }
+ return;
+
case T_FLOAT:
- w_byte(TYPE_FLOAT, fp);
- w_float(RFLOAT(obj)->value, fp);
+ w_byte(TYPE_FLOAT, arg);
+ w_float(RFLOAT(obj)->value, arg);
return;
case T_BIGNUM:
- w_byte(TYPE_BIGNUM, fp);
+ w_byte(TYPE_BIGNUM, arg);
{
char sign = RBIGNUM(obj)->sign?'+':'-';
int len = RBIGNUM(obj)->len;
USHORT *d = RBIGNUM(obj)->digits;
- w_byte(sign, fp);
- w_long(len, fp);
+ w_byte(sign, arg);
+ w_long(len, arg);
while (len--) {
- w_short(d, fp);
+ w_short(*d, arg);
d++;
}
}
return;
- }
- switch (BUILTIN_TYPE(obj)) {
case T_STRING:
- if (CLASS_OF(obj) == cString) {
- w_byte(TYPE_STRING, fp);
- w_bytes(RSTRING(obj)->ptr, RSTRING(obj)->len, fp);
- }
- else {
- w_byte(TYPE_STRING2, fp);
- w_bytes(RSTRING(obj)->ptr, RSTRING(obj)->len, fp);
- w_unique(rb_class2path(CLASS_OF(obj)), fp, table);
- }
+ w_uclass(obj, cString, arg);
+ w_byte(TYPE_STRING, arg);
+ w_bytes(RSTRING(obj)->ptr, RSTRING(obj)->len, arg);
return;
case T_REGEXP:
- w_byte(TYPE_REGEXP, fp);
- w_bytes(RREGEXP(obj)->str, RREGEXP(obj)->len, fp);
- w_byte(FL_TEST(obj, FL_USER1), fp);
+ w_uclass(obj, cRegexp, arg);
+ w_byte(TYPE_REGEXP, arg);
+ w_bytes(RREGEXP(obj)->str, RREGEXP(obj)->len, arg);
+ w_byte(FL_TEST(obj, FL_USER1), arg);
return;
case T_ARRAY:
- if (CLASS_OF(obj) == cArray) w_byte(TYPE_ARRAY, fp);
- else w_byte(TYPE_ARRAY2, fp);
+ w_uclass(obj, cArray, arg);
+ w_byte(TYPE_ARRAY, arg);
{
int len = RARRAY(obj)->len;
VALUE *ptr = RARRAY(obj)->ptr;
- w_long(len, fp);
+ w_long(len, arg);
while (len--) {
- w_object(*ptr, fp, limit, table);
+ w_object(*ptr, arg, limit);
ptr++;
}
}
- if (CLASS_OF(obj) != cArray) {
- w_unique(rb_class2path(CLASS_OF(obj)), fp, table);
- }
break;
case T_HASH:
- if (CLASS_OF(obj) == cHash) w_byte(TYPE_HASH, fp);
- else w_byte(TYPE_HASH2, fp);
- w_byte(TYPE_HASH, fp);
- w_long(RHASH(obj)->tbl->num_entries, fp);
- st_foreach(RHASH(obj)->tbl, hash_each, &arg);
- if (CLASS_OF(obj) != cHash) {
- w_unique(rb_class2path(CLASS_OF(obj)), fp, table);
- }
+ w_uclass(obj, cHash, arg);
+ w_byte(TYPE_HASH, arg);
+ w_long(RHASH(obj)->tbl->num_entries, arg);
+ st_foreach(RHASH(obj)->tbl, hash_each, &c_arg);
break;
case T_STRUCT:
- w_byte(TYPE_STRUCT, fp);
+ w_byte(TYPE_STRUCT, arg);
{
int len = RSTRUCT(obj)->len;
- char *path = rb_class2path(CLASS_OF(obj));
+ char *path = rb_class2name(CLASS_OF(obj));
VALUE mem;
int i;
- w_unique(path, fp, table);
- w_long(len, fp);
+ w_unique(path, arg);
+ w_long(len, arg);
mem = rb_ivar_get(CLASS_OF(obj), rb_intern("__member__"));
if (mem == Qnil) {
Fatal("non-initialized struct");
}
for (i=0; i<len; i++) {
- w_symbol(FIX2INT(RARRAY(mem)->ptr[i]), fp, table);
- w_object(RSTRUCT(obj)->ptr[i], fp, limit, table);
+ w_symbol(FIX2INT(RARRAY(mem)->ptr[i]), arg);
+ w_object(RSTRUCT(obj)->ptr[i], arg, limit);
}
}
break;
case T_OBJECT:
- w_byte(TYPE_OBJECT, fp);
+ w_byte(TYPE_OBJECT, arg);
{
VALUE class = CLASS_OF(obj);
char *path;
@@ -300,14 +348,14 @@ w_object(obj, fp, limit, table)
if (FL_TEST(class, FL_SINGLETON)) {
TypeError("singleton can't be dumped");
}
- path = rb_class2path(class);
- w_unique(path, fp, table);
+ path = rb_class2name(class);
+ w_unique(path, arg);
if (ROBJECT(obj)->iv_tbl) {
- w_long(ROBJECT(obj)->iv_tbl->num_entries, fp);
- st_foreach(ROBJECT(obj)->iv_tbl, obj_each, &arg);
+ w_long(ROBJECT(obj)->iv_tbl->num_entries, arg);
+ st_foreach(ROBJECT(obj)->iv_tbl, obj_each, &c_arg);
}
else {
- w_long(0, fp);
+ w_long(0, arg);
}
}
break;
@@ -319,146 +367,157 @@ w_object(obj, fp, limit, table)
}
}
-struct dump_arg {
- VALUE obj;
- FILE *fp;
- int limit;
- st_table *table;
-};
-
static VALUE
dump(arg)
- struct dump_arg *arg;
+ struct dump_call_arg *arg;
{
- w_object(arg->obj, arg->fp, arg->limit, arg->table);
+ w_object(arg->obj, arg->arg, arg->limit);
}
static VALUE
dump_ensure(arg)
struct dump_arg *arg;
{
- st_free_table(arg->table);
+ st_free_table(arg->symbol);
+ st_free_table(arg->data);
}
static VALUE
-dump_on(obj, port, limit)
- VALUE obj, port;
- int limit;
+marshal_dump(argc, argv)
+ int argc;
+ VALUE argv;
{
+ VALUE obj, port, a1, a2;
+ int limit = -1;
extern VALUE cIO;
- FILE *fp;
- OpenFile *fptr;
struct dump_arg arg;
+ struct dump_call_arg c_arg;
- if (obj_is_kind_of(port, cIO)) {
- GetOpenFile(port, fptr);
- io_writable(fptr);
- fp = (fptr->f2) ? fptr->f2 : fptr->f;
+ port = 0;
+ rb_scan_args(argc, argv, "12", &obj, &a1, &a2);
+ if (argc == 3) {
+ limit = NUM2INT(a2);
+ port = a1;
+ }
+ else if (argc == 2) {
+ if (FIXNUM_P(a1)) limit = FIX2INT(a1);
+ else port = a1;
+ }
+ if (port) {
+ if (obj_is_kind_of(port, cIO)) {
+ OpenFile *fptr;
+
+ io_binmode(port);
+ GetOpenFile(port, fptr);
+ io_writable(fptr);
+ arg.fp = (fptr->f2) ? fptr->f2 : fptr->f;
+ }
+ else {
+ TypeError("instance of IO needed");
+ }
}
else {
- TypeError("instance of IO needed");
+ arg.fp = 0;
+ port = str_new(0, 0);
+ arg.str = RSTRING(port);
}
- w_byte(MARSHAL_MAJOR, fp);
- w_byte(MARSHAL_MINOR, fp);
-
- arg.obj = obj;
- arg.fp = fp;
- arg.limit = limit;
- arg.table = st_init_numtable();
- rb_ensure(dump, &arg, dump_ensure, &arg);
-
- return Qnil;
-}
+ arg.symbol = st_init_numtable();
+ arg.data = st_init_numtable();
+ c_arg.obj = obj;
+ c_arg.arg = &arg;
+ c_arg.limit = limit;
-static VALUE
-marshal_dump(argc, argv)
- int argc;
- VALUE argv;
-{
- VALUE obj, port, lim;
- int limit;
+ w_byte(MARSHAL_MAJOR, &arg);
+ w_byte(MARSHAL_MINOR, &arg);
- rb_scan_args(argc, argv, "21", &obj, &port, &lim);
- if (NIL_P(lim)) limit = 100;
- else limit = NUM2INT(lim);
+ rb_ensure(dump, &c_arg, dump_ensure, &arg);
- dump_on(obj, port, limit);
+ return port;
}
-static VALUE
-marshal_dumps(argc, argv)
- int argc;
- VALUE argv;
-{
- VALUE obj, lim;
- int limit;
- VALUE str = str_new(0, 0);
- VALUE port;
- FILE *fp = 0;
- char buf[BUFSIZ];
- int n;
-
- rb_scan_args(argc, argv, "11", &obj, &lim);
- if (NIL_P(lim)) limit = 100;
- else limit = NUM2INT(lim);
-
- tmpnam(buf);
- port = file_open(buf, "w");
- fp = rb_fopen(buf, "r");
-#if !defined(MSDOS) && !defined(__BOW__)
- unlink(buf);
-#endif
-
- dump_on(obj, port, limit);
- io_close(port);
-#if defined(MSDOS) || defined(__BOW__)
- unlink(buf);
-#endif
-
- while (n = fread(buf, 1, BUFSIZ, fp)) {
- str_cat(str, buf, n);
- }
+struct load_arg {
+ FILE *fp;
+ UCHAR *ptr, *end;
+ st_table *symbol;
+ st_table *data;
+};
- return str;
+static int
+r_byte(arg)
+ struct load_arg *arg;
+{
+ if (arg->fp) return getc(arg->fp);
+ if (arg->ptr < arg->end) return *arg->ptr++;
+ return EOF;
}
-#define r_byte(fp) getc(fp)
-
static int
-r_short(fp)
- FILE *fp;
+r_short(arg)
+ struct load_arg *arg;
{
register short x;
- x = r_byte(fp);
- x |= r_byte(fp) << 8;
+ x = r_byte(arg);
+ x |= r_byte(arg) << 8;
/* XXX If your short is > 16 bits, add sign-extension here!!! */
return x;
}
+static void
+long_toobig(size)
+ int size;
+{
+ TypeError("long too big for this architecture (size %d, given %d)",
+ sizeof(long), size);
+}
+
static long
-r_long(fp)
- FILE *fp;
+r_long(arg)
+ struct load_arg *arg;
{
+ char c = r_byte(arg), i;
register long x;
- x = r_byte(fp);
- x |= (long)r_byte(fp) << 8;
- x |= (long)r_byte(fp) << 16;
- x |= (long)r_byte(fp) << 24;
- /* XXX If your long is > 32 bits, add sign-extension here!!! */
+
+ if (c == 0) return 0;
+ if (c > 0) {
+ if (c > sizeof(long)) long_toobig((int)c);
+ x = 0;
+ for (i=0;i<c;i++) {
+ x |= (long)r_byte(arg) << (8*i);
+ }
+ }
+ else if (c < 0) {
+ c = -c;
+ if (c > sizeof(long)) long_toobig((int)c);
+ x = -1;
+ for (i=0;i<c;i++) {
+ x &= ~(0xff << (8*i));
+ x |= (long)r_byte(arg) << (8*i);
+ }
+ }
return x;
}
-#define r_bytes(s, fp) \
- (s = (char*)r_long(fp), r_bytes0(&s,ALLOCA_N(char,(int)s),(int)s,fp))
+#define r_bytes(s, arg) \
+ (s = (char*)r_long(arg), r_bytes0(&s,ALLOCA_N(char,(int)s),(int)s,arg))
-static char
-r_bytes0(sp, s, len, fp)
+static int
+r_bytes0(sp, s, len, arg)
char **sp, *s;
int len;
- FILE *fp;
+ struct load_arg *arg;
{
- fread(s, 1, len, fp);
+ if (arg->fp) {
+ len = fread(s, 1, len, arg->fp);
+ }
+ else {
+ if (arg->ptr + len > arg->end) {
+ len = arg->end - arg->ptr;
+ }
+ memcpy(s, arg->ptr, len);
+ arg->ptr += len;
+ }
+
(s)[len] = '\0';
*sp = s;
@@ -466,63 +525,84 @@ r_bytes0(sp, s, len, fp)
}
static ID
-r_symbol(fp, table)
- FILE *fp;
- st_table *table;
+r_symbol(arg)
+ struct load_arg *arg;
{
char *buf;
ID id;
char type;
- if (r_byte(fp) == TYPE_SYMLINK) {
- int num = r_long(fp);
+ if (r_byte(arg) == TYPE_SYMLINK) {
+ int num = r_long(arg);
- if (st_lookup(table, num, &id)) {
+ if (st_lookup(arg->symbol, num, &id)) {
return id;
}
TypeError("bad symbol");
}
- r_bytes(buf, fp);
+ r_bytes(buf, arg);
id = rb_intern(buf);
- st_insert(table, table->num_entries, id);
+ st_insert(arg->symbol, arg->symbol->num_entries, id);
return id;
}
static char*
-r_unique(fp, table)
- FILE *fp;
- st_table *table;
+r_unique(arg)
+ struct load_arg *arg;
{
- return rb_id2name(r_symbol(fp, table));
+ return rb_id2name(r_symbol(arg));
}
static VALUE
-r_string(fp)
- FILE *fp;
+r_string(arg)
+ struct load_arg *arg;
{
char *buf;
- int len = r_bytes(buf, fp);
- VALUE v;
+ int len = r_bytes(buf, arg);
- v = str_new(buf, len);
+ return str_taint(str_new(buf, len));
+}
+static VALUE
+r_regist(v, arg)
+ VALUE v;
+ struct load_arg *arg;
+{
+ st_insert(arg->data, arg->data->num_entries, v);
return v;
}
static VALUE
-r_object(fp, table)
- FILE *fp;
- st_table *table;
+r_object(arg)
+ struct load_arg *arg;
{
VALUE v;
- int type = r_byte(fp);
+ int type = r_byte(arg);
switch (type) {
case EOF:
eof_error("EOF read where object expected");
return Qnil;
+ case TYPE_LINK:
+ if (st_lookup(arg->data, r_long(arg), &v)) {
+ return v;
+ }
+ ArgError("dump format error (unlinked)");
+ break;
+
+ case TYPE_UCLASS:
+ {
+ VALUE c = rb_path2class(r_unique(arg));
+ v = r_object(arg);
+ if (rb_special_const_p(v)) {
+ ArgError("dump format error (user class)");
+ }
+ RBASIC(v)->class = c;
+ return v;
+ }
+
case TYPE_NIL:
return Qnil;
@@ -534,7 +614,7 @@ r_object(fp, table)
case TYPE_FIXNUM:
{
- int i = r_long(fp);
+ int i = r_long(arg);
return INT2FIX(i);
}
@@ -543,9 +623,9 @@ r_object(fp, table)
double atof();
char *buf;
- r_bytes(buf, fp);
+ r_bytes(buf, arg);
v = float_new(atof(buf));
- return v;
+ return r_regist(v, arg);
}
case TYPE_BIGNUM:
@@ -555,50 +635,46 @@ r_object(fp, table)
NEWOBJ(big, struct RBignum);
OBJSETUP(big, cBignum, T_BIGNUM);
- big->sign = (r_byte(fp) == '+');
- big->len = len = r_long(fp);
+ big->sign = (r_byte(arg) == '+');
+ big->len = len = r_long(arg);
big->digits = digits = ALLOC_N(USHORT, len);
while (len--) {
- *digits++ = r_short(fp);
+ *digits++ = r_short(arg);
}
- return (VALUE)big;
+ return r_regist(big, arg);
}
case TYPE_STRING:
- return r_string(fp);
-
- case TYPE_STRING2:
- v = r_string(fp);
- RBASIC(v)->class = rb_path2class(r_unique(fp, table));
- return v;
+ return r_regist(r_string(arg), arg);
case TYPE_REGEXP:
{
char *buf;
- int len = r_bytes(buf, fp);
- int ci = r_byte(fp);
- v = reg_new(buf, len, ci);
- return v;
+ int len = r_bytes(buf, arg);
+ int ci = r_byte(arg);
+ return r_regist(reg_new(buf, len, ci), arg);
}
case TYPE_ARRAY:
{
- int len = r_long(fp);
+ volatile int len = r_long(arg);
v = ary_new2(len);
+ r_regist(v, arg);
while (len--) {
- ary_push(v, r_object(fp, table));
+ ary_push(v, r_object(arg));
}
return v;
}
case TYPE_HASH:
{
- int len = r_long(fp);
+ int len = r_long(arg);
v = hash_new();
+ r_regist(v, arg);
while (len--) {
- VALUE key = r_object(fp, table);
- VALUE value = r_object(fp, table);
+ VALUE key = r_object(arg);
+ VALUE value = r_object(arg);
hash_aset(v, key, value);
}
return v;
@@ -608,23 +684,27 @@ r_object(fp, table)
{
VALUE class, mem, values;
int i, len;
+ int num = arg->data->num_entries;
- class = rb_path2class(r_unique(fp, table));
+ st_insert(arg->data, num, 15); /* temp reg. */
+ class = rb_path2class(r_unique(arg));
mem = rb_ivar_get(class, rb_intern("__member__"));
if (mem == Qnil) {
Fatal("non-initialized struct");
}
- len = r_long(fp);
+ len = r_long(arg);
values = ary_new2(len);
i = 0;
for (i=0; i<len; i++) {
- ID slot = r_symbol(fp, table);
+ ID slot = r_symbol(arg);
if (RARRAY(mem)->ptr[i] != INT2FIX(slot))
TypeError("struct not compatible");
- ary_push(values, r_object(fp, table));
+ ary_push(values, r_object(arg));
}
v = struct_alloc(class, values);
+ st_insert(arg->data, num, v); /* re-regist */
+ return v;
}
break;
@@ -633,112 +713,101 @@ r_object(fp, table)
VALUE class;
int len;
- class = rb_path2class(r_unique(fp, table));
+ class = rb_path2class(r_unique(arg));
if (rb_respond_to(class, s_load)) {
- v = rb_funcall(class, s_load, 1, r_string(fp));
- }
- else {
- TypeError("class %s needs to have method `_load_from'",
- rb_class2name(class));
+ v = rb_funcall(class, s_load, 1, r_string(arg));
+ return r_regist(v, arg);
}
+ TypeError("class %s needs to have method `_load_from'",
+ rb_class2name(class));
}
break;
+
case TYPE_OBJECT:
{
VALUE class;
int len;
- class = rb_path2class(r_unique(fp, table));
- len = r_long(fp);
+ class = rb_path2class(r_unique(arg));
+ len = r_long(arg);
v = obj_alloc(class);
+ r_regist(v, arg);
if (len > 0) {
while (len--) {
- ID id = r_symbol(fp, table);
- VALUE val = r_object(fp, table);
+ ID id = r_symbol(arg);
+ VALUE val = r_object(arg);
rb_ivar_set(v, id, val);
}
}
+ return v;
}
break;
+ case TYPE_MODULE:
+ {
+ char *buf;
+ r_bytes(buf, arg);
+ return rb_path2class(buf);
+ }
+
default:
ArgError("dump format error(0x%x)", type);
break;
}
- return v;
}
-struct load_arg {
- FILE *fp;
- st_table *table;
-};
-
static VALUE
load(arg)
struct load_arg *arg;
{
- return r_object(arg->fp, arg->table);
+ return r_object(arg);
}
static VALUE
load_ensure(arg)
struct load_arg *arg;
{
- st_free_table(arg->table);
+ st_free_table(arg->symbol);
+ st_free_table(arg->data);
}
static VALUE
marshal_load(self, port)
VALUE self, port;
{
- extern VALUE cIO;
FILE *fp;
int major;
VALUE v;
OpenFile *fptr;
- char buf[32];
-#if defined(MSDOS) || defined(__BOW__)
- int need_unlink_tmp = 0;
-#endif
struct load_arg arg;
if (TYPE(port) == T_STRING) {
- tmpnam(buf);
- fp = rb_fopen(buf, "w");
- v = file_open(buf, "r");
-#if defined(MSDOS) || defined(__BOW__)
- need_unlink_tmp = 0;
-#else
- unlink(buf);
-#endif
-
- fwrite(RSTRING(port)->ptr, RSTRING(port)->len, 1, fp);
- fclose(fp);
- port = v;
- }
-
- if (obj_is_kind_of(port, cIO)) {
- GetOpenFile(port, fptr);
- io_readable(fptr);
- fp = fptr->f;
+ arg.fp = 0;
+ arg.ptr = RSTRING(port)->ptr;
+ arg.end = arg.ptr + RSTRING(port)->len;
}
else {
- TypeError("instance of IO needed");
+ if (obj_is_kind_of(port, cIO)) {
+ io_binmode(port);
+ GetOpenFile(port, fptr);
+ io_readable(fptr);
+ arg.fp = fptr->f;
+ }
+ else {
+ TypeError("instance of IO needed");
+ }
}
- major = r_byte(fp);
+ major = r_byte(&arg);
if (major == MARSHAL_MAJOR) {
- if (r_byte(fp) != MARSHAL_MINOR) {
+ if (r_byte(&arg) != MARSHAL_MINOR) {
Warning("Old marshal file format (can be read)");
}
- arg.fp = fp;
- arg.table = st_init_numtable();
+ arg.symbol = st_init_numtable();
+ arg.data = st_init_numtable();
v = rb_ensure(load, &arg, load_ensure, &arg);
}
-#if defined(MSDOS) || defined(__BOW__)
- if (need_unlink_tmp) unlink(buf);
-#endif
- if (major != MARSHAL_MAJOR) {
+ else {
TypeError("Old marshal file format (can't read)");
}
@@ -752,7 +821,6 @@ Init_marshal()
s_dump = rb_intern("_dump_to");
s_load = rb_intern("_load_from");
rb_define_module_function(mMarshal, "dump", marshal_dump, -1);
- rb_define_module_function(mMarshal, "dumps", marshal_dumps, -1);
rb_define_module_function(mMarshal, "load", marshal_load, 1);
rb_define_module_function(mMarshal, "restore", marshal_load, 1);
}
diff --git a/ext/md5/md5init.c b/ext/md5/md5init.c
index 85f0847e71..762d53edc9 100644
--- a/ext/md5/md5init.c
+++ b/ext/md5/md5init.c
@@ -26,7 +26,7 @@ md5_update(obj, str)
MD5_CTX *md5;
Check_Type(str, T_STRING);
- Get_Data_Struct(obj, MD5_CTX, md5);
+ Data_Get_Struct(obj, MD5_CTX, md5);
MD5Update(md5, str->ptr, str->len);
return Qnil;
@@ -38,7 +38,7 @@ md5_digest(obj)
MD5_CTX *md5, ctx;
unsigned char digest[16];
- Get_Data_Struct(obj, MD5_CTX, md5);
+ Data_Get_Struct(obj, MD5_CTX, md5);
ctx = *md5;
MD5Final(digest, &ctx);
@@ -52,8 +52,8 @@ md5_clone(obj)
VALUE clone;
MD5_CTX *md5, *md5_new;
- Get_Data_Struct(obj, MD5_CTX, md5);
- obj = Make_Data_Struct(CLASS_OF(obj), MD5_CTX, 0, 0, md5_new);
+ Data_Get_Struct(obj, MD5_CTX, md5);
+ obj = Data_Make_Struct(CLASS_OF(obj), MD5_CTX, 0, 0, md5_new);
*md5_new = *md5;
return obj;
@@ -69,7 +69,7 @@ md5_new(argc, argv, class)
rb_scan_args(argc, argv, "01", &arg);
if (!NIL_P(arg)) Check_Type(arg, T_STRING);
- obj = Make_Data_Struct(class, MD5_CTX, 0, 0, md5);
+ obj = Data_Make_Struct(class, MD5_CTX, 0, 0, md5);
MD5Init(md5);
if (!NIL_P(arg)) {
md5_update(obj, arg);
diff --git a/ext/socket/extconf.rb b/ext/socket/extconf.rb
index f2ec0578d5..bbde1a0c35 100644
--- a/ext/socket/extconf.rb
+++ b/ext/socket/extconf.rb
@@ -1,11 +1,17 @@
-have_library("socket", "socket")
+$LDFLAGS = "-L/usr/local/lib"
+have_library("wsock32", "cygwin32_socket") or have_library("socket", "socket")
have_library("inet", "gethostbyname")
have_library("nsl", "gethostbyname")
have_header("sys/un.h")
-if have_func("socket")
+if have_func("socket") or have_func("cygwin32_socket")
have_func("hsterror")
unless have_func("gethostname")
have_func("uname")
end
+ if ENV["SOCKS_SERVER"] # test if SOCKSsocket needed
+ if have_library("socks", "Rconnect")
+ $CFLAGS="-DSOCKS"
+ end
+ end
create_makefile("socket")
end
diff --git a/ext/socket/socket.c b/ext/socket/socket.c
index 6b4f0f5559..be9118d0a8 100644
--- a/ext/socket/socket.c
+++ b/ext/socket/socket.c
@@ -20,6 +20,18 @@
#include <sys/un.h>
#endif
+#if defined(THREAD) && defined(HAVE_FCNTL)
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#include <sys/types.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#endif
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK EAGAIN
+#endif
+
extern VALUE cIO;
extern VALUE cInteger;
@@ -35,9 +47,19 @@ VALUE cSocket;
extern VALUE eException;
static VALUE eSocket;
+#ifdef SOCKS
+VALUE cSOCKSsocket;
+void SOCKSinit();
+int Rconnect();
+#endif
+
FILE *rb_fdopen();
char *strdup();
+#define INET_CLIENT 0
+#define INET_SERVER 1
+#define INET_SOCKS 2
+
#ifdef NT
static void
sock_finalize(fptr)
@@ -60,13 +82,15 @@ sock_new(class, fd)
OBJSETUP(sock, class, T_FILE);
MakeOpenFile(sock, fp);
+ fp->f = rb_fdopen(fd, "r");
#ifdef NT
fp->finalize = sock_finalize;
-#endif
- fp->f = rb_fdopen(fd, "r");
+#else
setbuf(fp->f, NULL);
+#endif
fp->f2 = rb_fdopen(fd, "w");
- fp->mode = FMODE_READWRITE|FMODE_SYNC;
+ fp->mode = FMODE_READWRITE;
+ io_unbuffered(fp);
return (VALUE)sock;
}
@@ -106,6 +130,7 @@ bsock_setsockopt(sock, lev, optname, val)
char *v;
int vlen;
+ rb_secure(2);
level = NUM2INT(lev);
option = NUM2INT(optname);
switch (TYPE(val)) {
@@ -136,26 +161,20 @@ static VALUE
bsock_getsockopt(sock, lev, optname)
VALUE sock, lev, optname;
{
-#if !defined(__CYGWIN32__)
int level, option, len;
- struct RString *val;
+ char *buf;
OpenFile *fptr;
level = NUM2INT(lev);
option = NUM2INT(optname);
len = 256;
- val = (struct RString*)str_new(0, len);
- Check_Type(val, T_STRING);
+ buf = ALLOCA_N(char,len);
GetOpenFile(sock, fptr);
- if (getsockopt(fileno(fptr->f), level, option, val->ptr, &len) < 0)
+ if (getsockopt(fileno(fptr->f), level, option, buf, &len) < 0)
rb_sys_fail(fptr->path);
- val->len = len;
- return (VALUE)val;
-#else
- rb_notimplement();
-#endif
+ return str_new(buf, len);
}
static VALUE
@@ -187,9 +206,210 @@ bsock_getpeername(sock)
}
static VALUE
-open_inet(class, h, serv, server)
+bsock_send(argc, argv, sock)
+ int argc;
+ VALUE *argv;
+ VALUE sock;
+{
+ struct RString *msg, *to;
+ VALUE flags;
+ OpenFile *fptr;
+ FILE *f;
+ int fd, n;
+
+ rb_secure(4);
+ rb_scan_args(argc, argv, "21", &msg, &flags, &to);
+
+ Check_Type(msg, T_STRING);
+
+ GetOpenFile(sock, fptr);
+ f = fptr->f2?fptr->f2:fptr->f;
+ fd = fileno(f);
+ retry:
+#ifdef THREAD
+ thread_fd_writable(fd);
+#endif
+ if (RTEST(to)) {
+ Check_Type(to, T_STRING);
+ n = sendto(fd, msg->ptr, msg->len, NUM2INT(flags),
+ (struct sockaddr*)to->ptr, to->len);
+ }
+ else {
+ n = send(fd, msg->ptr, msg->len, NUM2INT(flags));
+ }
+ if (n < 0) {
+ switch (errno) {
+ case EINTR:
+ case EWOULDBLOCK:
+#if EAGAIN != EWOULDBLOCK
+ case EAGAIN:
+#endif
+#ifdef THREAD
+ thread_schedule();
+#endif
+ goto retry;
+ }
+ rb_sys_fail("send(2)");
+ }
+ return INT2FIX(n);
+}
+
+static VALUE tcpaddr _((struct sockaddr_in*));
+#ifdef HAVE_SYS_UN_H
+static VALUE unixaddr _((struct sockaddr_un*));
+#endif
+
+static VALUE
+s_recv(sock, argc, argv, from)
+ VALUE sock;
+ int argc;
+ VALUE *argv;
+ int from; /* 0 - recv,
+ 1 - TCPsocket#recvfrom,
+ 2 - UNIXsocket#recvfrom,
+ 3 - Socket#recvfrom */
+{
+ OpenFile *fptr;
+ FILE f;
+ struct RString *str;
+ char buf[1024];
+ int fd, alen = sizeof buf;
+ VALUE len, flg;
+ int flags;
+
+ rb_scan_args(argc, argv, "11", &len, &flg);
+
+ if (flg == Qnil) flags = 0;
+ else flags = NUM2INT(flg);
+
+ str = (struct RString*)str_new(0, NUM2INT(len));
+
+ GetOpenFile(sock, fptr);
+ fd = fileno(fptr->f);
+#ifdef THREAD
+ thread_wait_fd(fd);
+#endif
+ TRAP_BEG;
+ retry:
+ str->len = recvfrom(fd, str->ptr, str->len, flags,
+ (struct sockaddr*)buf, &alen);
+ TRAP_END;
+
+ if (str->len < 0) {
+ switch (errno) {
+ case EINTR:
+ case EWOULDBLOCK:
+#if EAGAIN != EWOULDBLOCK
+ case EAGAIN:
+#endif
+#ifdef THREAD
+ thread_schedule();
+#endif
+ goto retry;
+ }
+ rb_sys_fail("recvfrom(2)");
+ }
+ str_taint(str);
+ switch (from) {
+ case 0:
+ return (VALUE)str;
+ case 1:
+ if (alen != sizeof(struct sockaddr_in)) {
+ TypeError("sockaddr size differs - should not happen");
+ }
+ return assoc_new(str, tcpaddr((struct sockaddr_in *)buf));
+#ifdef HAVE_SYS_UN_H
+ case 2:
+ if (alen != sizeof(struct sockaddr_un)) {
+ TypeError("sockaddr size differs - should not happen");
+ }
+ return assoc_new(str, unixaddr((struct sockaddr_un *)buf));
+#endif
+ case 3:
+ return assoc_new(str, str_new(buf, alen));
+ }
+}
+
+static VALUE
+bsock_recv(argc, argv, sock)
+ int argc;
+ VALUE *argv;
+ VALUE sock;
+{
+ return s_recv(sock, argc, argv, 0);
+}
+
+#if defined(THREAD) && defined(HAVE_FCNTL)
+static int
+thread_connect(fd, sockaddr, len, type)
+ int fd;
+ struct sockaddr *sockaddr;
+ int len;
+ int type;
+{
+ int status;
+ int mode;
+ fd_set fds;
+
+ mode = fcntl(fd, F_GETFL, 0);
+
+#ifdef O_NDELAY
+# define NONBLOCKING O_NDELAY
+#else
+#ifdef O_NBIO
+# define NONBLOCKING O_NBIO
+#else
+# define NONBLOCKING O_NONBLOCK
+#endif
+#endif
+ fcntl(fd, F_SETFL, mode|NONBLOCKING);
+ for (;;) {
+#ifdef SOCKS
+ if (type == INET_SOCKS) {
+ status = Rconnect(fd, sockaddr, len);
+ }
+ else
+#endif
+ {
+ status = connect(fd, sockaddr, len);
+ }
+ if (status < 0) {
+ switch (errno) {
+#ifdef EINPROGRESS
+ case EINPROGRESS:
+#ifdef EAGAIN
+ case EAGAIN:
+#endif
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ thread_select(fd+1, 0, &fds, 0, 0, 0);
+ continue;
+#endif
+
+#ifdef EISCONN
+ case EISCONN:
+#endif
+#ifdef EALREADY
+ case EALREADY:
+#endif
+#if defined(EISCONN) || defined(EALREADY)
+ status = 0;
+ errno = 0;
+ break;
+#endif
+ }
+ }
+ mode &= ~NONBLOCKING;
+ fcntl(fd, F_SETFL, mode);
+ return status;
+ }
+}
+#endif
+
+static VALUE
+open_inet(class, h, serv, type)
VALUE class, h, serv;
- int server;
+ int type;
{
char *host;
struct hostent *hostent, _hostent;
@@ -203,13 +423,13 @@ open_inet(class, h, serv, server)
VALUE sock;
if (h) {
- Check_Type(h, T_STRING);
+ Check_SafeStr(h);
host = RSTRING(h)->ptr;
hostent = gethostbyname(host);
if (hostent == NULL) {
hostaddr = inet_addr(host);
if (hostaddr == -1) {
- if (server && !strlen(host))
+ if (type == INET_SERVER && !strlen(host))
hostaddr = INADDR_ANY;
else {
#ifdef HAVE_HSTRERROR
@@ -252,6 +472,7 @@ open_inet(class, h, serv, server)
fd = socket(PF_INET, SOCK_STREAM, protoent->p_proto);
+ memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
if (h) {
memcpy((char *)&(sockaddr.sin_addr.s_addr),
@@ -263,12 +484,27 @@ open_inet(class, h, serv, server)
}
sockaddr.sin_port = servent->s_port;
- if (server) {
+ if (type == INET_SERVER) {
+ status = 1;
+ setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char*)&status,sizeof(status));
status = bind(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
syscall = "bind(2)";
}
else {
- status = connect(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
+#if defined(THREAD) && defined(HAVE_FCNTL)
+ status = thread_connect(fd, (struct sockaddr*)&sockaddr,
+ sizeof(sockaddr), type);
+#else
+#ifdef SOCKS
+ if (type == INET_SOCKS) {
+ status = Rconnect(fd, &sockaddr, sizeof(sockaddr));
+ }
+ else
+#endif
+ {
+ status = connect(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
+ }
+#endif
syscall = "connect(2)";
}
@@ -276,7 +512,7 @@ open_inet(class, h, serv, server)
close (fd);
rb_sys_fail(syscall);
}
- if (server) listen(fd, 5);
+ if (type == INET_SERVER) listen(fd, 5);
/* create new instance */
sock = sock_new(class, fd);
@@ -288,10 +524,27 @@ static VALUE
tcp_s_open(class, host, serv)
VALUE class, host, serv;
{
- Check_Type(host, T_STRING);
- return open_inet(class, host, serv, 0);
+ Check_SafeStr(host);
+ return open_inet(class, host, serv, INET_CLIENT);
}
+#ifdef SOCKS
+static VALUE
+socks_s_open(class, host, serv)
+ VALUE class, host, serv;
+{
+ static init = 0;
+
+ if (init == 0) {
+ SOCKSinit("ruby");
+ init = 1;
+ }
+
+ Check_SafeStr(host);
+ return open_inet(class, host, serv, INET_SOCKS);
+}
+#endif
+
static VALUE
tcp_svr_s_open(argc, argv, class)
int argc;
@@ -301,9 +554,9 @@ tcp_svr_s_open(argc, argv, class)
VALUE arg1, arg2;
if (rb_scan_args(argc, argv, "11", &arg1, &arg2) == 2)
- return open_inet(class, arg1, arg2, 1);
+ return open_inet(class, arg1, arg2, INET_SERVER);
else
- return open_inet(class, 0, arg1, 1);
+ return open_inet(class, 0, arg1, INET_SERVER);
}
static VALUE
@@ -323,7 +576,17 @@ s_accept(class, fd, sockaddr, len)
fd2 = accept(fd, sockaddr, len);
TRAP_END;
if (fd2 < 0) {
- if (errno == EINTR) goto retry;
+ switch (errno) {
+ case EINTR:
+ case EWOULDBLOCK:
+#if EAGAIN != EWOULDBLOCK
+ case EAGAIN:
+#endif
+#ifdef THREAD
+ thread_schedule();
+#endif
+ goto retry;
+ }
rb_sys_fail(0);
}
return sock_new(class, fd2);
@@ -352,30 +615,28 @@ open_unix(class, path, server)
{
struct sockaddr_un sockaddr;
int fd, status;
- char *syscall;
VALUE sock;
OpenFile *fptr;
- Check_Type(path, T_STRING);
+ Check_SafeStr(path);
fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (fd < 0) rb_sys_fail("socket(2)");
+ memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sun_family = AF_UNIX;
strncpy(sockaddr.sun_path, path->ptr, sizeof(sockaddr.sun_path)-1);
sockaddr.sun_path[sizeof(sockaddr.sun_path)-1] = '\0';
if (server) {
status = bind(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
- syscall = "bind(2)";
}
else {
status = connect(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
- syscall = "connect(2)";
}
if (status < 0) {
- close (fd);
- rb_sys_fail(syscall);
+ close(fd);
+ rb_sys_fail(sockaddr.sun_path);
}
if (server) listen(fd, 5);
@@ -397,8 +658,6 @@ setipaddr(name, addr)
char ch;
struct hostent *hp;
long x;
- unsigned char *a;
- char buf[16];
if (name[0] == 0) {
addr->sin_addr.s_addr = INADDR_ANY;
@@ -496,6 +755,15 @@ tcp_peeraddr(sock)
}
static VALUE
+tcp_recvfrom(argc, argv, sock)
+ int argc;
+ VALUE *argv;
+ VALUE sock;
+{
+ return s_recv(sock, argc, argv, 1);
+}
+
+static VALUE
tcp_s_getaddress(obj, host)
VALUE obj, host;
{
@@ -547,6 +815,15 @@ unix_svr_s_open(class, path)
}
static VALUE
+unix_recvfrom(argc, argv, sock)
+ int argc;
+ VALUE *argv;
+ VALUE sock;
+{
+ return s_recv(sock, argc, argv, 2);
+}
+
+static VALUE
unix_accept(sock)
VALUE sock;
{
@@ -685,7 +962,7 @@ static VALUE
sock_s_socketpair(class, domain, type, protocol)
VALUE class, domain, type, protocol;
{
-#if !defined(__CYGWIN32__)
+#if !defined(__CYGWIN32__) && !defined(NT)
int fd;
int d, t, sp[2];
@@ -710,8 +987,21 @@ sock_connect(sock, addr)
str_modify(addr);
GetOpenFile(sock, fptr);
- if (connect(fileno(fptr->f), (struct sockaddr*)addr->ptr, addr->len) < 0)
+ retry:
+ if (connect(fileno(fptr->f), (struct sockaddr*)addr->ptr, addr->len) < 0) {
+ switch (errno) {
+ case EINTR:
+ case EWOULDBLOCK:
+#if EAGAIN != EWOULDBLOCK
+ case EAGAIN:
+#endif
+#ifdef THREAD
+ thread_schedule();
+#endif
+ goto retry;
+ }
rb_sys_fail("connect(2)");
+ }
return INT2FIX(0);
}
@@ -747,114 +1037,27 @@ sock_listen(sock, log)
}
static VALUE
-sock_accept(sock)
- VALUE sock;
-{
- OpenFile *fptr;
- VALUE addr, sock2;
- char buf[1024];
- int len = sizeof buf;
-
- GetOpenFile(sock, fptr);
- sock2 = s_accept(cSocket,fileno(fptr->f),(struct sockaddr*)buf,&len);
-
- return assoc_new(sock2, str_new(buf, len));
-}
-
-static VALUE
-sock_send(argc, argv, sock)
+sock_recvfrom(argc, argv, sock)
int argc;
VALUE *argv;
VALUE sock;
{
- struct RString *msg, *to;
- VALUE flags;
- OpenFile *fptr;
- FILE *f;
- int fd, n;
-
- rb_scan_args(argc, argv, "21", &msg, &flags, &to);
-
- Check_Type(msg, T_STRING);
-
- GetOpenFile(sock, fptr);
- f = fptr->f2?fptr->f2:fptr->f;
- fd = fileno(f);
-#ifdef THREAD
- thread_fd_writable(fd);
-#endif
- if (to) {
- Check_Type(to, T_STRING);
- n = sendto(fd, msg->ptr, msg->len, NUM2INT(flags),
- (struct sockaddr*)to->ptr, to->len);
- }
- else {
- n = send(fd, msg->ptr, msg->len, NUM2INT(flags));
- }
- if (n < 0) {
- rb_sys_fail("send(2)");
- }
- return INT2FIX(n);
+ return s_recv(sock, argc, argv, 3);
}
static VALUE
-s_recv(sock, argc, argv, from)
- VALUE sock;
- int argc;
- VALUE *argv;
- int from;
+sock_accept(sock)
+ VALUE sock;
{
OpenFile *fptr;
- FILE f;
- struct RString *str;
+ VALUE addr, sock2;
char buf[1024];
- int fd, alen = sizeof buf;
- VALUE len, flg;
- int flags;
-
- rb_scan_args(argc, argv, "11", &len, &flg);
-
- if (flg == Qnil) flags = 0;
- else flags = NUM2INT(flg);
-
- str = (struct RString*)str_new(0, NUM2INT(len));
+ int len = sizeof buf;
GetOpenFile(sock, fptr);
- fd = fileno(fptr->f);
-#ifdef THREAD
- thread_wait_fd(fd);
-#endif
- TRAP_BEG;
- str->len = recvfrom(fd, str->ptr, str->len, flags,
- (struct sockaddr*)buf, &alen);
- TRAP_END;
-
- if (str->len < 0) {
- rb_sys_fail("recvfrom(2)");
- }
-
- if (from)
- return assoc_new(str, str_new(buf, alen));
- else
- return (VALUE)str;
-}
-
-static VALUE
-sock_recv(argc, argv, sock)
- int argc;
- VALUE *argv;
- VALUE sock;
-{
- return s_recv(sock, argc, argv, 0);
-}
+ sock2 = s_accept(cSocket,fileno(fptr->f),(struct sockaddr*)buf,&len);
-static VALUE
-sock_recvfrom(argc, argv, sock)
- int argc;
- VALUE *argv;
- VALUE sock;
-{
- return s_recv(sock, argc, argv, 1);
+ return assoc_new(sock2, str_new(buf, len));
}
#ifdef HAVE_GETHOSTNAME
@@ -951,6 +1154,7 @@ sock_s_gethostbyname(obj, host)
return mkhostent(h);
}
+static VALUE
sock_s_gethostbyaddr(argc, argv)
int argc;
VALUE *argv;
@@ -999,17 +1203,19 @@ sock_s_getservbyaname(argc, argv)
return INT2FIX(port);
}
-Init_socket ()
+Init_socket()
{
eSocket = rb_define_class("SocketError", eException);
cBasicSocket = rb_define_class("BasicSocket", cIO);
- rb_undef_method(cBasicSocket, "new");
+ rb_undef_method(CLASS_OF(cBasicSocket), "new");
rb_define_method(cBasicSocket, "shutdown", bsock_shutdown, -1);
rb_define_method(cBasicSocket, "setsockopt", bsock_setsockopt, 3);
rb_define_method(cBasicSocket, "getsockopt", bsock_getsockopt, 2);
rb_define_method(cBasicSocket, "getsockname", bsock_getsockname, 0);
rb_define_method(cBasicSocket, "getpeername", bsock_getpeername, 0);
+ rb_define_method(cBasicSocket, "send", bsock_send, -1);
+ rb_define_method(cBasicSocket, "recv", bsock_recv, -1);
cTCPsocket = rb_define_class("TCPsocket", cBasicSocket);
rb_define_singleton_method(cTCPsocket, "open", tcp_s_open, 2);
@@ -1017,6 +1223,13 @@ Init_socket ()
rb_define_method(cTCPsocket, "addr", tcp_addr, 0);
rb_define_method(cTCPsocket, "peeraddr", tcp_peeraddr, 0);
rb_define_singleton_method(cTCPsocket, "getaddress", tcp_s_getaddress, 1);
+ rb_define_method(cTCPsocket, "recvfrom", tcp_recvfrom, -1);
+
+#ifdef SOCKS
+ cSOCKSsocket = rb_define_class("SOCKSsocket", cTCPsocket);
+ rb_define_singleton_method(cSOCKSsocket, "open", socks_s_open, 2);
+ rb_define_singleton_method(cSOCKSsocket, "new", socks_s_open, 2);
+#endif
cTCPserver = rb_define_class("TCPserver", cTCPsocket);
rb_define_singleton_method(cTCPserver, "open", tcp_svr_s_open, -1);
@@ -1030,6 +1243,7 @@ Init_socket ()
rb_define_method(cUNIXsocket, "path", unix_path, 0);
rb_define_method(cUNIXsocket, "addr", unix_addr, 0);
rb_define_method(cUNIXsocket, "peeraddr", unix_peeraddr, 0);
+ rb_define_method(cUNIXsocket, "recvfrom", unix_recvfrom, -1);
cUNIXserver = rb_define_class("UNIXserver", cUNIXsocket);
rb_define_singleton_method(cUNIXserver, "open", unix_svr_s_open, 1);
@@ -1047,9 +1261,7 @@ Init_socket ()
rb_define_method(cSocket, "listen", sock_listen, 1);
rb_define_method(cSocket, "accept", sock_accept, 0);
- rb_define_method(cSocket, "send", sock_send, -1);
- rb_define_method(cSocket, "recv", sock_recv, -1);
- rb_define_method(cSocket, "recvfrom", sock_recv, -1);
+ rb_define_method(cSocket, "recvfrom", sock_recvfrom, -1);
rb_define_singleton_method(cSocket, "socketpair", sock_s_socketpair, 3);
rb_define_singleton_method(cSocket, "pair", sock_s_socketpair, 3);
@@ -1059,12 +1271,29 @@ Init_socket ()
rb_define_singleton_method(cSocket, "getservbyname", sock_s_getservbyaname, -1);
/* constants */
+ rb_define_const(cSocket, "SOCK_STREAM", INT2FIX(SOCK_STREAM));
+ rb_define_const(cSocket, "SOCK_DGRAM", INT2FIX(SOCK_DGRAM));
+ rb_define_const(cSocket, "SOCK_RAW", INT2FIX(SOCK_RAW));
+#ifdef SOCK_RDM
+ rb_define_const(cSocket, "SOCK_RDM", INT2FIX(SOCK_RDM));
+#endif
+#ifdef SOCK_SEQPACKET
+ rb_define_const(cSocket, "SOCK_SEQPACKET", INT2FIX(SOCK_SEQPACKET));
+#endif
+#ifdef SOCK_PACKET
+ rb_define_const(cSocket, "SOCK_PACKET", INT2FIX(SOCK_PACKET));
+#endif
+
rb_define_const(cSocket, "AF_INET", INT2FIX(AF_INET));
rb_define_const(cSocket, "PF_INET", INT2FIX(PF_INET));
#ifdef AF_UNIX
rb_define_const(cSocket, "AF_UNIX", INT2FIX(AF_UNIX));
rb_define_const(cSocket, "PF_UNIX", INT2FIX(PF_UNIX));
#endif
+#ifdef AF_AX25
+ rb_define_const(cSocket, "AF_AX25", INT2FIX(AF_AX25));
+ rb_define_const(cSocket, "PF_AX25", INT2FIX(PF_AX25));
+#endif
#ifdef AF_IPX
rb_define_const(cSocket, "AF_IPX", INT2FIX(AF_IPX));
rb_define_const(cSocket, "PF_IPX", INT2FIX(PF_IPX));
@@ -1078,19 +1307,6 @@ Init_socket ()
rb_define_const(cSocket, "MSG_PEEK", INT2FIX(MSG_PEEK));
rb_define_const(cSocket, "MSG_DONTROUTE", INT2FIX(MSG_DONTROUTE));
- rb_define_const(cSocket, "SOCK_STREAM", INT2FIX(SOCK_STREAM));
- rb_define_const(cSocket, "SOCK_DGRAM", INT2FIX(SOCK_DGRAM));
- rb_define_const(cSocket, "SOCK_RAW", INT2FIX(SOCK_RAW));
-#ifdef SOCK_RDM
- rb_define_const(cSocket, "SOCK_RDM", INT2FIX(SOCK_RDM));
-#endif
-#ifdef SOCK_SEQPACKET
- rb_define_const(cSocket, "SOCK_SEQPACKET", INT2FIX(SOCK_SEQPACKET));
-#endif
-#ifdef SOCK_PACKET
- rb_define_const(cSocket, "SOCK_PACKET", INT2FIX(SOCK_PACKET));
-#endif
-
rb_define_const(cSocket, "SOL_SOCKET", INT2FIX(SOL_SOCKET));
#ifdef SOL_IP
rb_define_const(cSocket, "SOL_IP", INT2FIX(SOL_IP));
@@ -1098,6 +1314,9 @@ Init_socket ()
#ifdef SOL_IPX
rb_define_const(cSocket, "SOL_IPX", INT2FIX(SOL_IPX));
#endif
+#ifdef SOL_AX25
+ rb_define_const(cSocket, "SOL_AX25", INT2FIX(SOL_AX25));
+#endif
#ifdef SOL_ATALK
rb_define_const(cSocket, "SOL_ATALK", INT2FIX(SOL_ATALK));
#endif
@@ -1108,8 +1327,81 @@ Init_socket ()
rb_define_const(cSocket, "SOL_UDP", INT2FIX(SOL_UDP));
#endif
+#ifdef SO_DEBUG
rb_define_const(cSocket, "SO_DEBUG", INT2FIX(SO_DEBUG));
+#endif
rb_define_const(cSocket, "SO_REUSEADDR", INT2FIX(SO_REUSEADDR));
+#ifdef SO_TYPE
+ rb_define_const(cSocket, "SO_TYPE", INT2FIX(SO_TYPE));
+#endif
+#ifdef SO_ERROR
+ rb_define_const(cSocket, "SO_ERROR", INT2FIX(SO_ERROR));
+#endif
+#ifdef SO_DONTROUTE
+ rb_define_const(cSocket, "SO_DONTROUTE", INT2FIX(SO_DONTROUTE));
+#endif
+#ifdef SO_BROADCAST
+ rb_define_const(cSocket, "SO_BROADCAST", INT2FIX(SO_BROADCAST));
+#endif
+#ifdef SO_SNDBUF
+ rb_define_const(cSocket, "SO_SNDBUF", INT2FIX(SO_SNDBUF));
+#endif
+#ifdef SO_RCVBUF
+ rb_define_const(cSocket, "SO_RCVBUF", INT2FIX(SO_RCVBUF));
+#endif
rb_define_const(cSocket, "SO_KEEPALIVE", INT2FIX(SO_KEEPALIVE));
+#ifdef SO_OOBINLINE
+ rb_define_const(cSocket, "SO_OOBINLINE", INT2FIX(SO_OOBINLINE));
+#endif
+#ifdef SO_NO_CHECK
+ rb_define_const(cSocket, "SO_NO_CHECK", INT2FIX(SO_NO_CHECK));
+#endif
+#ifdef SO_PRIORITY
+ rb_define_const(cSocket, "SO_PRIORITY", INT2FIX(SO_PRIORITY));
+#endif
rb_define_const(cSocket, "SO_LINGER", INT2FIX(SO_LINGER));
+
+#ifdef SOPRI_INTERACTIVE
+ rb_define_const(cSocket, "SOPRI_INTERACTIVE", INT2FIX(SOPRI_INTERACTIVE));
+#endif
+#ifdef SOPRI_NORMAL
+ rb_define_const(cSocket, "SOPRI_NORMAL", INT2FIX(SOPRI_NORMAL));
+#endif
+#ifdef SOPRI_BACKGROUND
+ rb_define_const(cSocket, "SOPRI_BACKGROUND", INT2FIX(SOPRI_BACKGROUND));
+#endif
+
+#ifdef IP_MULTICAST_IF
+ rb_define_const(cSocket, "IP_MULTICAST_IF", INT2FIX(IP_MULTICAST_IF));
+#endif
+#ifdef IP_MULTICAST_TTL
+ rb_define_const(cSocket, "IP_MULTICAST_TTL", INT2FIX(IP_MULTICAST_TTL));
+#endif
+#ifdef IP_MULTICAST_LOOP
+ rb_define_const(cSocket, "IP_MULTICAST_LOOP", INT2FIX(IP_MULTICAST_LOOP));
+#endif
+#ifdef IP_ADD_MEMBERSHIP
+ rb_define_const(cSocket, "IP_ADD_MEMBERSHIP", INT2FIX(IP_ADD_MEMBERSHIP));
+#endif
+
+#ifdef IP_DEFAULT_MULTICAST_TTL
+ rb_define_const(cSocket, "IP_DEFAULT_MULTICAST_TTL", INT2FIX(IP_DEFAULT_MULTICAST_TTL));
+#endif
+#ifdef IP_DEFAULT_MULTICAST_LOOP
+ rb_define_const(cSocket, "IP_DEFAULT_MULTICAST_LOOP", INT2FIX(IP_DEFAULT_MULTICAST_LOOP));
+#endif
+#ifdef IP_MAX_MEMBERSHIPS
+ rb_define_const(cSocket, "IP_MAX_MEMBERSHIPS", INT2FIX(IP_MAX_MEMBERSHIPS));
+#endif
+
+#ifdef IPX_TYPE
+ rb_define_const(cSocket, "IPX_TYPE", INT2FIX(IPX_TYPE));
+#endif
+
+#ifdef TCP_NODELAY
+ rb_define_const(cSocket, "TCP_NODELAY", INT2FIX(TCP_NODELAY));
+#endif
+#ifdef TCP_MAXSEG
+ rb_define_const(cSocket, "TCP_MAXSEG", INT2FIX(TCP_MAXSEG));
+#endif
}
diff --git a/ext/tkutil/tkutil.c b/ext/tkutil/tkutil.c
index 51e3412ab5..5e6b77b9af 100644
--- a/ext/tkutil/tkutil.c
+++ b/ext/tkutil/tkutil.c
@@ -23,13 +23,6 @@ tk_eval_cmd(argc, argv)
}
static VALUE
-tk_yield(obj)
- VALUE obj;
-{
- rb_yield_0(obj, obj);
-}
-
-static VALUE
tk_s_new(argc, argv, class)
int argc;
VALUE *argv;
@@ -38,7 +31,7 @@ tk_s_new(argc, argv, class)
VALUE obj = obj_alloc(class);
rb_funcall2(obj, rb_intern("initialize"), argc, argv);
- if (iterator_p()) tk_yield(obj);
+ if (iterator_p()) rb_yield_0(obj, obj);
return obj;
}
diff --git a/file.c b/file.c
index 656650b11b..0894c72ffb 100644
--- a/file.c
+++ b/file.c
@@ -26,10 +26,12 @@
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#else
-stuct timeval {
+#ifndef NT
+struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* and microseconds */
};
+#endif /* NT */
#endif
#ifdef HAVE_UTIME_H
@@ -46,8 +48,14 @@ stuct timeval {
char *strrchr();
#endif
+#ifdef NT
+#include <sys/stat.h>
+#endif
+
+#ifndef NT
char *strdup();
char *getenv();
+#endif
extern VALUE cIO;
VALUE cFile;
@@ -66,7 +74,6 @@ file_open(fname, mode)
MakeOpenFile(port, fptr);
fptr->mode = io_mode_flags(mode);
-
fptr->f = rb_fopen(fname, mode);
fptr->path = strdup(fname);
@@ -74,23 +81,77 @@ file_open(fname, mode)
}
static VALUE
-file_s_open(argc, argv)
+file_s_open(argc, argv, class)
int argc;
VALUE *argv;
+ VALUE class;
{
- VALUE fname, vmode;
+ VALUE fname, vmode, file;
char *mode;
- rb_scan_args(argc, argv, "11", &fname, &mode);
- Check_Type(fname, T_STRING);
- if (!NIL_P(mode)) {
- Check_Type(mode, T_STRING);
- mode = RSTRING(mode)->ptr;
+ rb_scan_args(argc, argv, "11", &fname, &vmode);
+ Check_SafeStr(fname);
+ if (!NIL_P(vmode)) {
+ Check_Type(vmode, T_STRING);
+ mode = RSTRING(vmode)->ptr;
+ }
+ else {
+ mode = "r";
+ }
+ file = file_open(RSTRING(fname)->ptr, mode);
+
+ RBASIC(file)->class = class;
+ return file;
+}
+
+static VALUE
+file_reopen(argc, argv, file)
+ int argc;
+ VALUE *argv;
+ VALUE file;
+{
+ VALUE fname, nmode;
+ char *mode;
+ OpenFile *fptr;
+
+ if (rb_scan_args(argc, argv, "11", &fname, &nmode) == 1) {
+ if (TYPE(fname) == T_FILE) { /* fname must be IO */
+ return io_reopen(file, fname);
+ }
+ }
+
+ Check_SafeStr(fname);
+ if (!NIL_P(nmode)) {
+ Check_Type(nmode, T_STRING);
+ mode = RSTRING(nmode)->ptr;
}
else {
mode = "r";
}
- return file_open(RSTRING(fname)->ptr, mode);
+
+ GetOpenFile(file, fptr);
+ if (fptr->path) free(fptr->path);
+ fptr->path = strdup(RSTRING(fname)->ptr);
+ fptr->mode = io_mode_flags(mode);
+ if (!fptr->f) {
+ fptr->f = rb_fopen(RSTRING(fname)->ptr, mode);
+ if (fptr->f2) {
+ fclose(fptr->f2);
+ fptr->f2 = NULL;
+ }
+ return file;
+ }
+
+ if (freopen(RSTRING(fname)->ptr, mode, fptr->f) == NULL) {
+ rb_sys_fail(fptr->path);
+ }
+ if (fptr->f2) {
+ if (freopen(RSTRING(fname)->ptr, "w", fptr->f2) == NULL) {
+ rb_sys_fail(fptr->path);
+ }
+ }
+
+ return file;
}
static int
@@ -103,8 +164,11 @@ apply2files(func, args, arg)
VALUE path;
for (i=0; i<args->len; i++) {
+ Check_SafeStr(args->ptr[i]);
+ }
+
+ for (i=0; i<args->len; i++) {
path = args->ptr[i];
- Check_Type(path, T_STRING);
if ((*func)(RSTRING(path)->ptr, arg) < 0)
rb_sys_fail(RSTRING(path)->ptr);
}
@@ -200,7 +264,11 @@ file_isatty(obj)
}
#include <sys/types.h>
+#ifndef NT
#include <sys/file.h>
+#else
+#include "missing/file.h"
+#endif
#include <sys/stat.h>
static VALUE
@@ -243,7 +311,7 @@ file_s_stat(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) == -1) {
rb_sys_fail(fname->ptr);
}
@@ -269,10 +337,10 @@ file_s_lstat(obj, fname)
VALUE obj;
struct RString *fname;
{
-#if !defined(MSDOS)
+#if !defined(MSDOS) && !defined(NT)
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (lstat(fname->ptr, &st) == -1) {
rb_sys_fail(fname->ptr);
}
@@ -286,7 +354,7 @@ static VALUE
file_lstat(obj)
VALUE obj;
{
-#if !defined(MSDOS)
+#if !defined(MSDOS) && !defined(NT)
OpenFile *fptr;
struct stat st;
@@ -335,6 +403,7 @@ eaccess(path, mode)
char *path;
int mode;
{
+#ifndef NT
struct stat st;
static int euid = -1;
@@ -355,6 +424,19 @@ eaccess(path, mode)
return 0;
}
+#if defined(DJGPP)
+ {
+ int stat_mode = 0;
+ if (mode & X_OK)
+ stat_mode |= S_IXOTH;
+ if (mode & W_OK)
+ stat_mode |= S_IWOTH;
+ if (mode & R_OK)
+ stat_mode |= S_IROTH;
+ mode = stat_mode;
+ }
+#endif
+
if (st.st_uid == euid) /* owner */
mode <<= 6;
else if (group_member (st.st_gid))
@@ -363,6 +445,9 @@ eaccess(path, mode)
if (st.st_mode & mode) return 0;
return -1;
+#else /* !NT*/
+ return 0;
+#endif
}
static VALUE
@@ -376,7 +461,7 @@ test_d(obj, fname)
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (S_ISDIR(st.st_mode)) return TRUE;
return FALSE;
@@ -394,7 +479,7 @@ test_p(obj, fname)
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (S_ISFIFO(st.st_mode)) return TRUE;
@@ -424,7 +509,7 @@ test_l(obj, fname)
#ifdef S_ISLNK
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (lstat(fname->ptr, &st) < 0) return FALSE;
if (S_ISLNK(st.st_mode)) return TRUE;
@@ -432,7 +517,7 @@ test_l(obj, fname)
return FALSE;
}
-VALUE
+static VALUE
test_S(obj, fname)
VALUE obj;
struct RString *fname;
@@ -454,7 +539,7 @@ test_S(obj, fname)
#ifdef S_ISSOCK
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (S_ISSOCK(st.st_mode)) return TRUE;
@@ -470,13 +555,15 @@ test_b(obj, fname)
#ifndef S_ISBLK
# ifdef S_IFBLK
# define S_ISBLK(m) ((m & S_IFMT) == S_IFBLK)
+# else
+# define S_ISBLK(m) (0) /* anytime false */
# endif
#endif
#ifdef S_ISBLK
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (S_ISBLK(st.st_mode)) return TRUE;
@@ -495,7 +582,7 @@ test_c(obj, fname)
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (S_ISBLK(st.st_mode)) return TRUE;
@@ -509,7 +596,7 @@ test_e(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
return TRUE;
}
@@ -519,7 +606,7 @@ test_r(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (eaccess(fname->ptr, R_OK) < 0) return FALSE;
return TRUE;
}
@@ -529,7 +616,7 @@ test_R(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (access(fname->ptr, R_OK) < 0) return FALSE;
return TRUE;
}
@@ -539,7 +626,7 @@ test_w(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (eaccess(fname->ptr, W_OK) < 0) return FALSE;
return TRUE;
}
@@ -549,7 +636,7 @@ test_W(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (access(fname->ptr, W_OK) < 0) return FALSE;
return TRUE;
}
@@ -559,7 +646,7 @@ test_x(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (eaccess(fname->ptr, X_OK) < 0) return FALSE;
return TRUE;
}
@@ -569,11 +656,15 @@ test_X(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (access(fname->ptr, X_OK) < 0) return FALSE;
return TRUE;
}
+#ifndef S_ISREG
+# define S_ISREG(m) ((m & S_IFMT) == S_IFREG)
+#endif
+
static VALUE
test_f(obj, fname)
VALUE obj;
@@ -581,7 +672,7 @@ test_f(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (S_ISREG(st.st_mode)) return TRUE;
return FALSE;
@@ -594,7 +685,7 @@ test_z(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (st.st_size == 0) return TRUE;
return FALSE;
@@ -607,7 +698,7 @@ test_s(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (st.st_size == 0) return FALSE;
return int2inum(st.st_size);
@@ -620,7 +711,7 @@ test_owned(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (st.st_uid == geteuid()) return TRUE;
return FALSE;
@@ -633,7 +724,7 @@ test_rowned(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (st.st_uid == getuid()) return TRUE;
return FALSE;
@@ -647,11 +738,9 @@ test_grpowned(obj, fname)
#ifndef NT
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (st.st_gid == getegid()) return TRUE;
-#else
- Check_Type(fname, T_STRING);
#endif
return FALSE;
}
@@ -675,8 +764,8 @@ test_suid(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
#ifdef S_ISUID
+ Check_SafeStr(fname);
return check3rdbyte(fname->ptr, S_ISUID);
#else
return FALSE;
@@ -688,8 +777,8 @@ test_sgid(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
#ifndef NT
+ Check_SafeStr(fname);
return check3rdbyte(fname->ptr, S_ISGID);
#else
return FALSE;
@@ -710,14 +799,26 @@ test_sticky(obj, fname)
}
static VALUE
-file_s_type(obj, fname)
+file_s_size(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ struct stat st;
+
+ Check_SafeStr(fname);
+ if (stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr);
+ return int2inum(st.st_size);
+}
+
+static VALUE
+file_s_ftype(obj, fname)
VALUE obj;
struct RString *fname;
{
struct stat st;
char *t;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr);
if (S_ISREG(st.st_mode)) {
@@ -732,7 +833,7 @@ file_s_type(obj, fname)
t = "blockSpecial";
}
#endif
-#ifndef S_ISFIFO
+#ifdef S_ISFIFO
else if (S_ISFIFO(st.st_mode)) {
t = "fifo";
}
@@ -761,7 +862,7 @@ file_s_atime(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr);
return time_new(st.st_atime, 0);
}
@@ -787,7 +888,7 @@ file_s_mtime(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr);
return time_new(st.st_mtime, 0);
}
@@ -813,7 +914,7 @@ file_s_ctime(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr);
return time_new(st.st_ctime, 0);
}
@@ -864,10 +965,11 @@ file_chmod(obj, vmode)
OpenFile *fptr;
int mode;
+ rb_secure(2);
mode = NUM2INT(vmode);
GetOpenFile(obj, fptr);
-#if defined(DJGPP) || defined(__CYGWIN32__)
+#if defined(DJGPP) || defined(__CYGWIN32__) || defined(NT)
if (chmod(fptr->path, mode) == -1)
rb_sys_fail(fptr->path);
#else
@@ -918,14 +1020,15 @@ file_s_chown(argc, argv)
return INT2FIX(n);
}
-VALUE
+static VALUE
file_chown(obj, owner, group)
VALUE obj, owner, group;
{
OpenFile *fptr;
+ rb_secure(2);
GetOpenFile(obj, fptr);
-#if defined(DJGPP) || defined(__CYGWIN32__)
+#if defined(DJGPP) || defined(__CYGWIN32__) || defined(NT)
if (chown(fptr->path, NUM2INT(owner), NUM2INT(group)) == -1)
rb_sys_fail(fptr->path);
#else
@@ -972,6 +1075,7 @@ file_s_utime(argc, argv)
#ifndef HAVE_UTIME_H
# ifdef NT
# include <sys/utime.h>
+# define utimbuf _utimbuf
# else
struct utimbuf {
long actime;
@@ -1017,12 +1121,16 @@ file_s_link(obj, from, to)
VALUE obj;
struct RString *from, *to;
{
- Check_Type(from, T_STRING);
- Check_Type(to, T_STRING);
+#ifndef __human68k__
+ Check_SafeStr(from);
+ Check_SafeStr(to);
if (link(from->ptr, to->ptr) < 0)
rb_sys_fail(from->ptr);
return INT2FIX(0);
+#else
+ rb_notimplement();
+#endif
}
static VALUE
@@ -1030,9 +1138,9 @@ file_s_symlink(obj, from, to)
VALUE obj;
struct RString *from, *to;
{
-#if !defined(MSDOS)
- Check_Type(from, T_STRING);
- Check_Type(to, T_STRING);
+#if !defined(MSDOS) && !defined(NT)
+ Check_SafeStr(from);
+ Check_SafeStr(to);
if (symlink(from->ptr, to->ptr) < 0)
rb_sys_fail(from->ptr);
@@ -1047,18 +1155,18 @@ file_s_readlink(obj, path)
VALUE obj;
struct RString *path;
{
-#if !defined(MSDOS)
+#if !defined(MSDOS) && !defined(NT)
char buf[MAXPATHLEN];
int cc;
- Check_Type(path, T_STRING);
+ Check_SafeStr(path);
if ((cc = readlink(path->ptr, buf, MAXPATHLEN)) < 0)
rb_sys_fail(path->ptr);
return str_new(buf, cc);
#else
- rb_notimplement();
+ rb_notimplement();
#endif
}
@@ -1086,8 +1194,8 @@ file_s_rename(obj, from, to)
VALUE obj;
struct RString *from, *to;
{
- Check_Type(from, T_STRING);
- Check_Type(to, T_STRING);
+ Check_SafeStr(from);
+ Check_SafeStr(to);
if (rename(from->ptr, to->ptr) == -1)
rb_sys_fail(from->ptr);
@@ -1107,7 +1215,7 @@ file_s_umask(argc, argv)
umask(omask);
}
else if (argc == 1) {
- omask = umask(NUM2INT(argv[1]));
+ omask = umask(NUM2INT(argv[0]));
}
else {
ArgError("wrong # of argument");
@@ -1115,7 +1223,7 @@ file_s_umask(argc, argv)
return INT2FIX(omask);
}
-static VALUE
+VALUE
file_s_expand_path(obj, fname)
VALUE obj;
struct RString *fname;
@@ -1205,7 +1313,7 @@ file_s_expand_path(obj, fname)
if (p == buf || *p != '/') p++;
*p = '\0';
- return str_new2(buf);
+ return str_taint(str_new2(buf));
}
static int
@@ -1252,7 +1360,7 @@ file_s_basename(argc, argv)
f = rmext(p, ext->ptr);
if (f) return str_new(p, f);
}
- return str_new2(p);
+ return str_taint(str_new2(p));
}
static VALUE
@@ -1260,18 +1368,16 @@ file_s_dirname(obj, fname)
VALUE obj;
struct RString *fname;
{
- char *p;
+ UCHAR *p;
Check_Type(fname, T_STRING);
p = strrchr(fname->ptr, '/');
if (!p) {
- return str_new(0,0);
+ return str_new2(".");
}
- return str_new(fname->ptr, p - fname->ptr);
+ return str_taint(str_new(fname->ptr, p - fname->ptr));
}
-static VALUE separator;
-
static VALUE
file_s_split(obj, path)
VALUE obj, path;
@@ -1279,12 +1385,21 @@ file_s_split(obj, path)
return assoc_new(file_s_dirname(Qnil, path), file_s_basename(1,&path));
}
+static VALUE separator;
+
+static VALUE
+file_s_join(obj, args)
+ VALUE obj, args;
+{
+ return ary_join(args, separator);
+}
+
static VALUE
file_s_truncate(obj, path, len)
VALUE obj, len;
struct RString *path;
{
- Check_Type(path, T_STRING);
+ Check_SafeStr(path);
#ifdef HAVE_TRUNCATE
if (truncate(path->ptr, NUM2INT(len)) < 0)
@@ -1324,6 +1439,7 @@ file_truncate(obj, len)
GetOpenFile(obj, fptr);
+ rb_secure(2);
if (!(fptr->mode & FMODE_WRITABLE)) {
Fail("not opened for writing");
}
@@ -1342,30 +1458,18 @@ file_truncate(obj, len)
}
static VALUE
-file_fcntl(obj, req, arg)
- VALUE obj, req;
- struct RString *arg;
-{
-#ifdef HAVE_FCNTL
- io_ctl(obj, req, arg, 0);
-#else
- rb_notimplement();
-#endif
- return obj;
-}
-
-static VALUE
file_flock(obj, operation)
VALUE obj;
VALUE operation;
{
- OpenFile *fptr;
+ OpenFile *fptr;
GetOpenFile(obj, fptr);
+ rb_secure(2);
if (flock(fileno(fptr->f), NUM2INT(operation)) < 0) {
#ifdef EWOULDBLOCK
- if (errno = EWOULDBLOCK) {
+ if (errno == EWOULDBLOCK) {
return FALSE;
}
#endif
@@ -1384,7 +1488,7 @@ test_check(n, argc, argv)
n+=1;
if (n < argc) ArgError("Wrong # of arguments(%d for %d)", argc, n);
for (i=1; i<n; i++) {
- Check_Type(argv[i], T_STRING);
+ Check_SafeStr(argv[i]);
}
}
@@ -1398,8 +1502,13 @@ f_test(argc, argv)
int cmd;
if (argc == 0) ArgError("Wrong # of arguments");
- Need_Fixnum(argv[0]);
- cmd = FIX2INT(argv[0]);
+ if (TYPE(argv[0]) == T_STRING && RSTRING(argv[0])->len == 1) {
+ cmd = RSTRING(argv[0])->ptr[0];
+ }
+ else {
+ cmd = NUM2INT(argv[0]);
+ }
+ if (cmd == 0) return FALSE;
if (strchr("bcdefgGkloOprRsSuwWxXz", cmd)) {
CHECK(1);
switch (cmd) {
@@ -1519,7 +1628,7 @@ f_test(argc, argv)
return FALSE;
}
-extern VALUE cKernel;
+extern VALUE mKernel;
void
Init_File()
@@ -1537,7 +1646,7 @@ Init_File()
rb_define_module_function(mFileTest, "executable_real?", test_X, 1);
rb_define_module_function(mFileTest, "file?", test_f, 1);
rb_define_module_function(mFileTest, "zero?", test_z, 1);
- rb_define_module_function(mFileTest, "size", test_s, 1);
+ rb_define_module_function(mFileTest, "size?", test_s, 1);
rb_define_module_function(mFileTest, "owned?", test_owned, 1);
rb_define_module_function(mFileTest, "grpowned?", test_grpowned, 1);
@@ -1555,15 +1664,17 @@ Init_File()
cFile = rb_define_class("File", cIO);
rb_extend_object(cFile, CLASS_OF(mFileTest));
+ rb_define_singleton_method(cFile, "new", file_s_open, -1);
rb_define_singleton_method(cFile, "open", file_s_open, -1);
rb_define_singleton_method(cFile, "stat", file_s_stat, 1);
rb_define_singleton_method(cFile, "lstat", file_s_lstat, 1);
- rb_define_singleton_method(cFile, "ftype", file_s_type, 1);
+ rb_define_singleton_method(cFile, "ftype", file_s_ftype, 1);
rb_define_singleton_method(cFile, "atime", file_s_atime, 1);
rb_define_singleton_method(cFile, "mtime", file_s_mtime, 1);
rb_define_singleton_method(cFile, "ctime", file_s_ctime, 1);
+ rb_define_singleton_method(cFile, "size", file_s_size, 1);
rb_define_singleton_method(cFile, "utime", file_s_utime, -1);
rb_define_singleton_method(cFile, "chmod", file_s_chmod, -1);
@@ -1582,9 +1693,12 @@ Init_File()
rb_define_singleton_method(cFile, "basename", file_s_basename, -1);
rb_define_singleton_method(cFile, "dirname", file_s_dirname, 1);
- separator = INT2FIX('/');
+ separator = str_new2("/");
rb_define_const(cFile, "Separator", separator);
rb_define_singleton_method(cFile, "split", file_s_split, 1);
+ rb_define_singleton_method(cFile, "join", file_s_join, -2);
+
+ rb_define_method(cFile, "reopen", file_reopen, -1);
rb_define_method(cFile, "stat", file_stat, 0);
rb_define_method(cFile, "lstat", file_lstat, 0);
@@ -1606,10 +1720,9 @@ Init_File()
rb_define_method(cFile, "rewind", file_rewind, 0);
rb_define_method(cFile, "isatty", file_isatty, 0);
rb_define_method(cFile, "tty?", file_isatty, 0);
- rb_define_method(cFile, "eof", file_eof, 0);
+ rb_define_method(cFile, "eof", file_eof, 0);
rb_define_method(cFile, "eof?", file_eof, 0);
- rb_define_method(cIO, "fcntl", file_fcntl, 2);
rb_define_method(cFile, "flock", file_flock, 1);
# ifndef LOCK_SH
@@ -1632,7 +1745,7 @@ Init_File()
rb_define_method(cFile, "path", file_path, 0);
- rb_define_method(cKernel, "test", f_test, -1);
+ rb_define_global_function("test", f_test, -1);
sStat = struct_define("Stat", "dev", "ino", "mode",
"nlink", "uid", "gid", "rdev",
diff --git a/gc.c b/gc.c
index 21d09809be..f69f4741f3 100644
--- a/gc.c
+++ b/gc.c
@@ -19,19 +19,34 @@
#include <stdio.h>
#include <setjmp.h>
+#ifndef setjmp
+#ifdef HAVE__SETJMP
+#define setjmp(env) _setjmp(env)
+#define longjmp(env,val) _longjmp(env,val)
+#endif
+#endif
+
#ifdef _AIX
#pragma alloca
#endif
-void *malloc();
-void *calloc();
-void *realloc();
#ifdef C_ALLOCA
void *alloca();
#endif
void gc();
void gc_mark();
+static void run_final();
+
+#ifndef GC_MALLOC_LIMIT
+#if defined(MSDOS) || defined(__human68k__)
+#define GC_MALLOC_LIMIT 200000
+#else
+#define GC_MALLOC_LIMIT 400000
+#endif
+#endif
+
+static unsigned long malloc_memories = 0;
void *
xmalloc(size)
@@ -40,6 +55,10 @@ xmalloc(size)
void *mem;
if (size == 0) size = 1;
+ malloc_memories += size;
+ if (malloc_memories > GC_MALLOC_LIMIT) {
+ gc();
+ }
mem = malloc(size);
if (!mem) {
gc();
@@ -112,6 +131,7 @@ Paradigm Associates Inc Phone: 617-492-6079
Cambridge, MA 02138
*/
+extern int rb_in_compile;
static int dont_gc;
VALUE
@@ -196,7 +216,7 @@ add_heap()
if (heaps_used == heaps_length) {
/* Realloc heaps */
heaps_length += HEAPS_INCREMENT;
- heaps = (heaps_used)?
+ heaps = (heaps_used>0)?
(RVALUE**)realloc(heaps, heaps_length*sizeof(RVALUE)):
(RVALUE**)malloc(heaps_length*sizeof(RVALUE));
if (heaps == 0) Fatal("can't alloc memory");
@@ -217,14 +237,13 @@ add_heap()
}
struct RBasic *
-newobj()
+rb_newobj()
{
struct RBasic *obj;
if (freelist) {
retry:
obj = (struct RBasic*)freelist;
freelist = freelist->as.free.next;
- memset(obj, 0, sizeof(RVALUE));
return obj;
}
if (dont_gc) add_heap();
@@ -240,7 +259,7 @@ data_object_alloc(class, datap, dmark, dfree)
void (*dfree)();
void (*dmark)();
{
- struct RData *data = (struct RData*)newobj();
+ struct RData *data = (struct RData*)rb_newobj();
OBJSETUP(data, class, T_DATA);
data->data = datap;
@@ -260,8 +279,7 @@ looks_pointerp(p)
register RVALUE *heap_org;
register long i;
- if (p < lomem) return FALSE;
- if (p > himem) return FALSE;
+ if (p < lomem || p > himem) return FALSE;
/* check if p looks like a pointer */
for (i=0; i < heaps_used; i++) {
@@ -311,10 +329,11 @@ mark_entry(key, value)
return ST_CONTINUE;
}
-static int
+static void
mark_tbl(tbl)
st_table *tbl;
{
+ if (!tbl) return;
st_foreach(tbl, mark_entry, 0);
}
@@ -328,10 +347,11 @@ mark_hashentry(key, value)
return ST_CONTINUE;
}
-static int
+static void
mark_hash(tbl)
st_table *tbl;
{
+ if (!tbl) return;
st_foreach(tbl, mark_hashentry, 0);
}
@@ -350,7 +370,7 @@ gc_mark(obj)
{
Top:
if (FIXNUM_P(obj)) return; /* fixnum not marked */
- if (rb_special_const_p(obj)) return; /* special const not marked */
+ if (rb_special_const_p((VALUE)obj)) return; /* special const not marked */
if (obj->as.basic.flags == 0) return; /* free cell */
if (obj->as.basic.flags & FL_MARK) return; /* marked */
@@ -363,15 +383,79 @@ gc_mark(obj)
break;
case T_NODE:
- if (looks_pointerp(obj->as.node.u1.node)) {
- gc_mark(obj->as.node.u1.node);
- }
- if (looks_pointerp(obj->as.node.u2.node)) {
+ switch (nd_type(obj)) {
+ case NODE_IF: /* 1,2,3 */
+ case NODE_FOR:
+ case NODE_ITER:
gc_mark(obj->as.node.u2.node);
- }
- if (looks_pointerp(obj->as.node.u3.node)) {
+ /* fall through */
+ case NODE_BLOCK: /* 1,3 */
+ case NODE_ARRAY:
+ case NODE_DSTR:
+ case NODE_DXSTR:
+ case NODE_EVSTR:
+ case NODE_DREGX:
+ case NODE_DREGX_ONCE:
+ case NODE_FBODY:
+ case NODE_CALL:
+ gc_mark(obj->as.node.u1.node);
+ /* fall through */
+ case NODE_SUPER: /* 3 */
+ case NODE_FCALL:
+ case NODE_NEWLINE:
obj = (RVALUE*)obj->as.node.u3.node;
goto Top;
+
+ case NODE_WHILE: /* 1,2 */
+ case NODE_UNTIL:
+ gc_mark(obj->as.node.u1.node);
+ /* fall through */
+ case NODE_METHOD: /* 2 */
+ case NODE_NOT:
+ obj = (RVALUE*)obj->as.node.u2.node;
+ goto Top;
+
+ case NODE_HASH: /* 1 */
+ case NODE_LIT:
+ case NODE_STR:
+ case NODE_XSTR:
+ case NODE_DEFINED:
+ obj = (RVALUE*)obj->as.node.u1.node;
+ goto Top;
+
+ case NODE_SCOPE: /* 2,3 */
+ gc_mark(obj->as.node.u3.node);
+ obj = (RVALUE*)obj->as.node.u2.node;
+ goto Top;
+
+ case NODE_ZARRAY: /* - */
+ case NODE_CFUNC:
+ case NODE_VCALL:
+ case NODE_GVAR:
+ case NODE_LVAR:
+ case NODE_DVAR:
+ case NODE_IVAR:
+ case NODE_CVAR:
+ case NODE_NTH_REF:
+ case NODE_BACK_REF:
+ case NODE_ALIAS:
+ case NODE_VALIAS:
+ case NODE_UNDEF:
+ case NODE_SELF:
+ case NODE_NIL:
+ break;
+
+ default:
+ if (looks_pointerp(obj->as.node.u1.node)) {
+ gc_mark(obj->as.node.u1.node);
+ }
+ if (looks_pointerp(obj->as.node.u2.node)) {
+ gc_mark(obj->as.node.u2.node);
+ }
+ if (looks_pointerp(obj->as.node.u3.node)) {
+ obj = (RVALUE*)obj->as.node.u3.node;
+ goto Top;
+ }
}
return; /* no need to mark class. */
}
@@ -380,7 +464,7 @@ gc_mark(obj)
switch (obj->as.basic.flags & T_MASK) {
case T_ICLASS:
gc_mark(obj->as.class.super);
- if (obj->as.class.iv_tbl) mark_tbl(obj->as.class.iv_tbl);
+ mark_tbl(obj->as.class.iv_tbl);
mark_tbl(obj->as.class.m_tbl);
break;
@@ -388,7 +472,7 @@ gc_mark(obj)
case T_MODULE:
gc_mark(obj->as.class.super);
mark_tbl(obj->as.class.m_tbl);
- if (obj->as.class.iv_tbl) mark_tbl(obj->as.class.iv_tbl);
+ mark_tbl(obj->as.class.iv_tbl);
break;
case T_ARRAY:
@@ -417,16 +501,22 @@ gc_mark(obj)
break;
case T_OBJECT:
- if (obj->as.object.iv_tbl) mark_tbl(obj->as.object.iv_tbl);
+ mark_tbl(obj->as.object.iv_tbl);
break;
case T_FILE:
- case T_MATCH:
case T_REGEXP:
case T_FLOAT:
case T_BIGNUM:
break;
+ case T_MATCH:
+ if (obj->as.match.str) {
+ obj = (RVALUE*)obj->as.match.str;
+ goto Top;
+ }
+ break;
+
case T_VARMAP:
gc_mark(obj->as.varmap.val);
obj = (RVALUE*)obj->as.varmap.next;
@@ -435,12 +525,12 @@ gc_mark(obj)
case T_SCOPE:
if (obj->as.scope.local_vars) {
- int n = obj->as.scope.local_tbl[0];
- VALUE *tbl = obj->as.scope.local_vars;
+ int n = obj->as.scope.local_tbl[0]+1;
+ VALUE *vars = &obj->as.scope.local_vars[-1];
while (n--) {
- gc_mark_maybe(*tbl);
- tbl++;
+ gc_mark_maybe(*vars);
+ vars++;
}
}
break;
@@ -456,7 +546,9 @@ gc_mark(obj)
break;
default:
- Bug("gc_mark(): unknown data type %d", obj->as.basic.flags & T_MASK);
+ Bug("gc_mark(): unknown data type 0x%x(0x%x) %s",
+ obj->as.basic.flags & T_MASK, obj,
+ looks_pointerp(obj)?"corrupted object":"non object");
}
}
@@ -467,12 +559,23 @@ static void obj_free();
static void
gc_sweep()
{
+ RVALUE *p, *pend;
int freed = 0;
int i;
+ if (rb_in_compile) {
+ for (i = 0; i < heaps_used; i++) {
+ p = heaps[i]; pend = p + HEAP_SLOTS;
+ while (p < pend) {
+ if (!(p->as.basic.flags&FL_MARK) && BUILTIN_TYPE(p) == T_NODE)
+ gc_mark(p);
+ p++;
+ }
+ }
+ }
+
freelist = 0;
for (i = 0; i < heaps_used; i++) {
- RVALUE *p, *pend;
RVALUE *nfreelist;
int n = 0;
@@ -499,6 +602,17 @@ gc_sweep()
}
}
+void
+gc_force_recycle(p)
+ RVALUE *p;
+{
+ p->as.free.flag = 0;
+ p->as.free.next = freelist;
+ freelist = p;
+}
+
+static int need_call_final = 0;
+
static void
obj_free(obj)
RVALUE *obj;
@@ -506,10 +620,15 @@ obj_free(obj)
switch (obj->as.basic.flags & T_MASK) {
case T_NIL:
case T_FIXNUM:
+ case T_TRUE:
+ case T_FALSE:
Bug("obj_free() called for broken object");
break;
}
+ if (need_call_final) {
+ run_final(obj);
+ }
switch (obj->as.basic.flags & T_MASK) {
case T_OBJECT:
if (obj->as.object.iv_tbl) st_free_table(obj->as.object.iv_tbl);
@@ -524,7 +643,7 @@ obj_free(obj)
if (!obj->as.string.orig) free(obj->as.string.ptr);
break;
case T_ARRAY:
- free(obj->as.array.ptr);
+ if (obj->as.array.ptr) free(obj->as.array.ptr);
break;
case T_HASH:
st_free_table(obj->as.hash.tbl);
@@ -534,13 +653,13 @@ obj_free(obj)
free(obj->as.regexp.str);
break;
case T_DATA:
- if (obj->as.data.dfree) (*obj->as.data.dfree)(DATA_PTR(obj));
- free(DATA_PTR(obj));
+ if (obj->as.data.dfree && DATA_PTR(obj))
+ (*obj->as.data.dfree)(DATA_PTR(obj));
+ if (DATA_PTR(obj)) free(DATA_PTR(obj));
break;
case T_MATCH:
re_free_registers(obj->as.match.regs);
free(obj->as.match.regs);
- if (obj->as.match.ptr) free(obj->as.match.ptr);
break;
case T_FILE:
io_fptr_finalize(obj->as.file.fptr);
@@ -552,8 +671,6 @@ obj_free(obj)
case T_FLOAT:
case T_VARMAP:
- case T_TRUE:
- case T_FALSE:
break;
case T_BIGNUM:
@@ -566,10 +683,13 @@ obj_free(obj)
return; /* no need to free iv_tbl */
case T_SCOPE:
- if (obj->as.scope.local_vars)
- free(obj->as.scope.local_vars);
- if (obj->as.scope.local_tbl)
- free(obj->as.scope.local_tbl);
+ if (obj->as.scope.local_vars) {
+ VALUE *vars = obj->as.scope.local_vars-1;
+ if (vars[0] == 0)
+ free(obj->as.scope.local_tbl);
+ if (obj->as.scope.flag&SCOPE_MALLOC)
+ free(vars);
+ }
break;
case T_STRUCT:
@@ -592,8 +712,44 @@ gc_mark_frame(frame)
gc_mark_maybe(*tbl);
tbl++;
}
+ gc_mark(frame->cbase);
}
+#ifdef __GNUC__
+#if defined(__human68k__) || defined(DJGPP)
+#if defined(__human68k__)
+typedef unsigned long rb_jmp_buf[8];
+__asm__ (".even
+_rb_setjmp:
+ move.l 4(sp),a0
+ movem.l d3-d7/a3-a5,(a0)
+ moveq.l #0,d0
+ rts");
+#else
+#if defined(DJGPP)
+typedef unsigned long rb_jmp_buf[6];
+__asm__ (".align 4
+_rb_setjmp:
+ pushl %ebp
+ movl %esp,%ebp
+ movl 8(%ebp),%ebp
+ movl %eax,(%ebp)
+ movl %ebx,4(%ebp)
+ movl %ecx,8(%ebp)
+ movl %edx,12(%ebp)
+ movl %esi,16(%ebp)
+ movl %edi,20(%ebp)
+ popl %ebp
+ xorl %eax,%eax
+ ret");
+#endif
+#endif
+int rb_setjmp (rb_jmp_buf);
+#define jmp_buf rb_jmp_buf
+#define setjmp rb_setjmp
+#endif /* __human68k__ or DJGPP */
+#endif /* __GNUC__ */
+
void
gc()
{
@@ -605,6 +761,7 @@ gc()
if (dont_gc) return;
dont_gc++;
+ malloc_memories = 0;
#ifdef C_ALLOCA
alloca(0);
#endif
@@ -619,10 +776,13 @@ gc()
FLUSH_REGISTER_WINDOWS;
/* This assumes that all registers are saved into the jmp_buf */
setjmp(save_regs_gc_mark);
- gc_mark_locations((VALUE*)save_regs_gc_mark,
- (VALUE*)(((char*)save_regs_gc_mark)+sizeof(save_regs_gc_mark)));
- gc_mark_locations(gc_stack_start, (VALUE*) &stack_end);
-#ifdef THINK_C
+ mark_locations_array((VALUE*)&save_regs_gc_mark, sizeof(save_regs_gc_mark) / sizeof(VALUE *));
+ gc_mark_locations(gc_stack_start, (VALUE*)&stack_end);
+#if defined(THINK_C) || defined(__human68k__)
+#ifndef __human68k__
+ mark_locations_array((VALUE*)((char*)save_regs_gc_mark+2),
+ sizeof(save_regs_gc_mark) / sizeof(VALUE *));
+#endif
gc_mark_locations((VALUE*)((char*)gc_stack_start + 2),
(VALUE*)((char*)&stack_end + 2));
#endif
@@ -644,12 +804,24 @@ gc()
dont_gc--;
}
+static VALUE
+gc_method()
+{
+ gc();
+ return Qnil;
+}
+
void
init_stack()
{
+#ifdef __human68k__
+ extern void *_SEND;
+ gc_stack_start = _SEND;
+#else
VALUE start;
gc_stack_start = &start;
+#endif
}
void
@@ -660,8 +832,7 @@ init_heap()
}
static VALUE
-os_live_obj(obj)
- VALUE obj;
+os_live_obj()
{
int i;
int n = 0;
@@ -692,8 +863,8 @@ os_live_obj(obj)
}
static VALUE
-os_obj_of(obj, of)
- VALUE obj, of;
+os_obj_of(of)
+ VALUE of;
{
int i;
int n = 0;
@@ -725,6 +896,74 @@ os_obj_of(obj, of)
return INT2FIX(n);
}
+static VALUE
+os_each_obj(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ VALUE of;
+
+ if (rb_scan_args(argc, argv, "01", &of) == 0) {
+ return os_live_obj();
+ }
+ else {
+ return os_obj_of(of);
+ }
+}
+
+static VALUE finalizers;
+
+static VALUE
+add_final(os, proc)
+ VALUE os, proc;
+{
+ extern VALUE cProc;
+
+ if (!obj_is_kind_of(proc, cProc)) {
+ ArgError("wrong type argument %s (Proc required)",
+ rb_class2name(CLASS_OF(proc)));
+ }
+ ary_push(finalizers, proc);
+ return proc;
+}
+
+static VALUE
+rm_final(os, proc)
+ VALUE os, proc;
+{
+ ary_delete(finalizers, proc);
+ return proc;
+}
+
+static VALUE
+finals()
+{
+ return finalizers;
+}
+
+static VALUE
+call_final(os, obj)
+ VALUE os, obj;
+{
+ need_call_final = 1;
+ FL_SET(obj, FL_FINALIZE);
+ return obj;
+}
+
+static void
+run_final(obj)
+ VALUE obj;
+{
+ int i;
+
+ if (!FL_TEST(obj, FL_FINALIZE)) return;
+
+ obj |= FIXNUM_FLAG; /* make obj into id */
+ for (i=0; i<RARRAY(finalizers)->len; i++) {
+ rb_eval_cmd(RARRAY(finalizers)->ptr[i], obj);
+ }
+}
+
extern VALUE cModule;
void
@@ -733,13 +972,19 @@ Init_GC()
VALUE mObSpace;
mGC = rb_define_module("GC");
- rb_define_singleton_method(mGC, "start", gc, 0);
+ rb_define_singleton_method(mGC, "start", gc_method, 0);
rb_define_singleton_method(mGC, "enable", gc_s_enable, 0);
rb_define_singleton_method(mGC, "disable", gc_s_disable, 0);
- rb_define_method(mGC, "garbage_collect", gc, 0);
+ rb_define_method(mGC, "garbage_collect", gc_method, 0);
mObSpace = rb_define_module("ObjectSpace");
- rb_define_module_function(mObSpace, "each_live_object", os_live_obj, 0);
- rb_define_module_function(mObSpace, "each_object_of", os_obj_of, 1);
+ rb_define_module_function(mObSpace, "each_object", os_each_obj, -1);
rb_define_module_function(mObSpace, "garbage_collect", gc, 0);
+ rb_define_module_function(mObSpace, "add_finalizer", add_final, 1);
+ rb_define_module_function(mObSpace, "remove_finalizer", rm_final, 1);
+ rb_define_module_function(mObSpace, "finalizers", finals, 0);
+ rb_define_module_function(mObSpace, "call_finalizer", call_final, 1);
+
+ rb_global_variable(&finalizers);
+ finalizers = ary_new();
}
diff --git a/glob.c b/glob.c
index 7599c1ca72..6c355ad260 100644
--- a/glob.c
+++ b/glob.c
@@ -44,7 +44,11 @@
# include "ndir.h"
# endif /* !Xenix */
# else /* !USG */
+# if defined(NT)
+# include "missing/dir.h"
+# else
# include <sys/dir.h>
+# endif /* !NT */
# endif /* !USG */
#endif /* !HAVE_DIRENT_H */
@@ -68,7 +72,9 @@
# include <strings.h>
#endif /* !HAVE_STRING_H */
+#ifndef bcopy
# define bcopy(s, d, n) (memcpy ((d), (s), (n)))
+#endif
#ifdef _AIX
#pragma alloca
diff --git a/hash.c b/hash.c
index c6af916559..0ced1d5a51 100644
--- a/hash.c
+++ b/hash.c
@@ -6,12 +6,13 @@
$Date: 1996/12/25 10:42:26 $
created at: Mon Nov 22 18:51:18 JST 1993
- Copyright (C) 1993-1996 Yukihiro Matsumoto
+ Copyright (C) 1993-1997 Yukihiro Matsumoto
************************************************/
#include "ruby.h"
#include "st.h"
+#include "sig.h"
#ifdef HAVE_STRING_H
# include <string.h>
@@ -19,31 +20,44 @@
char *strchr();
#endif
+#define HASH_DELETED 0x1
+#define HASH_REHASHED 0x2
+
+#ifndef NT
char *getenv();
+#endif
VALUE cHash;
static VALUE envtbl;
static ID hash;
-VALUE f_getenv(), f_setenv();
+
+VALUE
+rb_hash(obj)
+ VALUE obj;
+{
+ return rb_funcall(obj, hash, 0);
+}
static int
-rb_cmp(a, b)
+any_cmp(a, b)
VALUE a, b;
{
if (FIXNUM_P(a)) {
if (FIXNUM_P(b)) return a != b;
}
-
- if (TYPE(a) == T_STRING) {
+ else if (TYPE(a) == T_STRING) {
if (TYPE(b) == T_STRING) return str_cmp(a, b);
}
- return !rb_eql(a, b);
+ DEFER_INTS;
+ a = !rb_eql(a, b);
+ ENABLE_INTS;
+ return a;
}
static int
-rb_hash(a, mod)
+any_hash(a, mod)
VALUE a;
int mod;
{
@@ -59,17 +73,85 @@ rb_hash(a, mod)
break;
default:
+ DEFER_INTS;
hval = rb_funcall(a, hash, 0);
+ if (!FIXNUM_P(hval)) {
+ hval = rb_funcall(hval, '%', 1, INT2FIX(65439));
+ }
+ ENABLE_INTS;
hval = FIX2INT(hval);
}
return hval % mod;
}
static struct st_hash_type objhash = {
- rb_cmp,
- rb_hash,
+ any_cmp,
+ any_hash,
+};
+
+struct hash_foreach_arg {
+ struct RHash *hash;
+ enum st_retval (*func)();
+ char *arg;
};
+static int
+hash_foreach_iter(key, value, arg)
+ VALUE key, value;
+ struct hash_foreach_arg *arg;
+{
+ int status;
+
+ if (key == Qnil) return ST_CONTINUE;
+ status = (*arg->func)(key, value, arg->arg);
+ if (arg->hash->status & HASH_REHASHED) return ST_STOP;
+ return status;
+}
+
+static int
+hash_foreach_call(arg)
+ struct hash_foreach_arg *arg;
+{
+ return st_foreach(arg->hash->tbl, hash_foreach_iter, arg);
+}
+
+static int
+hash_delete_nil(key, value)
+ VALUE key, value;
+{
+ if (key == Qnil) return ST_DELETE;
+ return ST_CONTINUE;
+}
+
+static void
+hash_foreach_ensure(hash)
+ struct RHash *hash;
+{
+ hash->iter_lev--;
+
+ if (hash->iter_lev == 0) {
+ if (hash->status & HASH_DELETED) {
+ st_foreach(hash->tbl, hash_delete_nil, 0);
+ }
+ hash->status = 0;
+ }
+}
+
+static int
+hash_foreach(hash, func, farg)
+ struct RHash *hash;
+ enum st_retval (*func)();
+ char *farg;
+{
+ struct hash_foreach_arg arg;
+
+ hash->iter_lev++;
+ arg.hash = hash;
+ arg.func = func;
+ arg.arg = farg;
+ return rb_ensure(hash_foreach_call, &arg, hash_foreach_ensure, hash);
+}
+
static VALUE
hash_s_new(argc, argv, class)
int argc;
@@ -86,13 +168,14 @@ hash_s_new(argc, argv, class)
if (NIL_P(sz)) size = 0;
else size = NUM2INT(sz);
+ hash->iter_lev = 0;
+ hash->status = 0;
+ hash->tbl = 0; /* avoid GC crashing */
hash->tbl = st_init_table_with_size(&objhash, size);
return (VALUE)hash;
}
-static VALUE hash_clone();
-
VALUE
hash_new2(class)
VALUE class;
@@ -120,8 +203,11 @@ hash_s_create(argc, argv, class)
else {
NEWOBJ(hash, struct RHash);
OBJSETUP(hash, class, T_HASH);
+
+ hash->iter_lev = 0;
+ hash->status = 0;
+ hash->tbl = 0; /* avoid GC crashing */
hash->tbl = (st_table*)st_copy(RHASH(argv[0])->tbl);
-
return (VALUE)hash;
}
}
@@ -145,11 +231,39 @@ hash_clone(hash)
NEWOBJ(hash2, struct RHash);
CLONESETUP(hash2, hash);
+ hash2->iter_lev = 0;
+ hash2->status = 0;
+ hash2->tbl = 0; /* avoid GC crashing */
hash2->tbl = (st_table*)st_copy(hash->tbl);
return (VALUE)hash2;
}
+static int
+hash_rehash_i(key, value, tbl)
+ VALUE key, value;
+ st_table *tbl;
+{
+ if (key != Qnil) {
+ st_insert(tbl, key, value);
+ }
+ return ST_CONTINUE;
+}
+
+static VALUE
+hash_rehash(hash)
+ struct RHash *hash;
+{
+ st_table *tbl = st_init_table_with_size(&objhash, hash->tbl->num_entries);
+
+ st_foreach(hash->tbl, hash_rehash_i, tbl);
+ st_free_table(hash->tbl);
+ hash->tbl = tbl;
+ if (hash->iter_lev > 0) hash->status |= HASH_REHASHED;
+
+ return (VALUE)hash;
+}
+
VALUE
hash_aref(hash, key)
struct RHash *hash;
@@ -164,23 +278,17 @@ hash_aref(hash, key)
}
static VALUE
-hash_indexes(hash, args)
+hash_indexes(argc, argv, hash)
+ int argc;
+ VALUE *argv;
struct RHash *hash;
- struct RArray *args;
{
- VALUE *p, *pend;
struct RArray *indexes;
- int i = 0;
-
- if (!args || NIL_P(args)) {
- return ary_new2(0);
- }
-
- indexes = (struct RArray*)ary_new2(args->len);
+ int i;
- p = args->ptr; pend = p + args->len;
- while (p < pend) {
- indexes->ptr[i++] = hash_aref(hash, *p++);
+ indexes = (struct RArray*)ary_new2(argc);
+ for (i=0; i<argc; i++) {
+ indexes->ptr[i] = hash_aref(hash, argv[i]);
}
indexes->len = i;
return (VALUE)indexes;
@@ -193,9 +301,12 @@ hash_delete(hash, key)
{
VALUE val;
- if (st_delete(hash->tbl, &key, &val))
+ rb_secure(5);
+ if (hash->iter_lev > 0 && st_delete_safe(hash->tbl, &key, &val, Qnil))
+ return val;
+ else if (st_delete(hash->tbl, &key, &val))
return val;
- if (iterator_p()) rb_yield(Qnil);
+ if (iterator_p()) rb_yield(key);
return Qnil;
}
@@ -205,11 +316,12 @@ struct shift_var {
VALUE val;
};
-static
+static int
shift_i(key, value, var)
VALUE key, value;
struct shift_var *var;
{
+ if (key == Qnil) return ST_CONTINUE;
if (var->stop) return ST_STOP;
var->stop = 1;
var->key = key;
@@ -223,6 +335,7 @@ hash_shift(hash)
{
struct shift_var var;
+ rb_secure(5);
var.stop = 0;
st_foreach(hash->tbl, shift_i, &var);
@@ -234,6 +347,7 @@ static int
delete_if_i(key, value)
VALUE key, value;
{
+ if (key == Qnil) return ST_CONTINUE;
if (rb_yield(assoc_new(key, value)))
return ST_DELETE;
return ST_CONTINUE;
@@ -243,7 +357,8 @@ static VALUE
hash_delete_if(hash)
struct RHash *hash;
{
- st_foreach(hash->tbl, delete_if_i, 0);
+ rb_secure(5);
+ hash_foreach(hash, delete_if_i, 0);
return (VALUE)hash;
}
@@ -259,6 +374,7 @@ static VALUE
hash_clear(hash)
struct RHash *hash;
{
+ rb_secure(5);
st_foreach(hash->tbl, clear_i);
return (VALUE)hash;
@@ -269,6 +385,7 @@ hash_aset(hash, key, val)
struct RHash *hash;
VALUE key, val;
{
+ rb_secure(5);
if (NIL_P(val)) {
hash_delete(hash, key);
return Qnil;
@@ -300,6 +417,7 @@ static int
each_value_i(key, value)
VALUE key, value;
{
+ if (key == Qnil) return ST_CONTINUE;
rb_yield(value);
return ST_CONTINUE;
}
@@ -308,7 +426,7 @@ static VALUE
hash_each_value(hash)
struct RHash *hash;
{
- st_foreach(hash->tbl, each_value_i);
+ hash_foreach(hash, each_value_i);
return (VALUE)hash;
}
@@ -316,6 +434,7 @@ static int
each_key_i(key, value)
VALUE key, value;
{
+ if (key == Qnil) return ST_CONTINUE;
rb_yield(key);
return ST_CONTINUE;
}
@@ -324,7 +443,7 @@ static VALUE
hash_each_key(hash)
struct RHash *hash;
{
- st_foreach(hash->tbl, each_key_i);
+ hash_foreach(hash, each_key_i);
return (VALUE)hash;
}
@@ -332,6 +451,7 @@ static int
each_pair_i(key, value)
VALUE key, value;
{
+ if (key == Qnil) return ST_CONTINUE;
rb_yield(assoc_new(key, value));
return ST_CONTINUE;
}
@@ -340,7 +460,7 @@ static VALUE
hash_each_pair(hash)
struct RHash *hash;
{
- st_foreach(hash->tbl, each_pair_i);
+ hash_foreach(hash, each_pair_i);
return (VALUE)hash;
}
@@ -348,6 +468,7 @@ static int
to_a_i(key, value, ary)
VALUE key, value, ary;
{
+ if (key == Qnil) return ST_CONTINUE;
ary_push(ary, assoc_new(key, value));
return ST_CONTINUE;
}
@@ -371,6 +492,7 @@ inspect_i(key, value, str)
{
VALUE str2;
+ if (key == Qnil) return ST_CONTINUE;
if (str->len > 1) {
str_cat(str, ", ", 2);
}
@@ -407,6 +529,7 @@ static int
keys_i(key, value, ary)
VALUE key, value, ary;
{
+ if (key == Qnil) return ST_CONTINUE;
ary_push(ary, key);
return ST_CONTINUE;
}
@@ -427,6 +550,7 @@ static int
values_i(key, value, ary)
VALUE key, value, ary;
{
+ if (key == Qnil) return ST_CONTINUE;
ary_push(ary, value);
return ST_CONTINUE;
}
@@ -443,17 +567,6 @@ hash_values(hash)
return ary;
}
-static int
-hash_search_value(key, value, data)
- VALUE key, value, *data;
-{
- if (rb_equal(value, data[1])) {
- data[0] = TRUE;
- return ST_STOP;
- }
- return ST_CONTINUE;
-}
-
static VALUE
hash_has_key(hash, key)
struct RHash *hash;
@@ -465,6 +578,18 @@ hash_has_key(hash, key)
return FALSE;
}
+static int
+hash_search_value(key, value, data)
+ VALUE key, value, *data;
+{
+ if (key == Qnil) return ST_CONTINUE;
+ if (rb_equal(value, data[1])) {
+ data[0] = TRUE;
+ return ST_STOP;
+ }
+ return ST_CONTINUE;
+}
+
static VALUE
hash_has_value(hash, val)
struct RHash *hash;
@@ -490,6 +615,7 @@ equal_i(key, val1, data)
{
VALUE val2;
+ if (key == Qnil) return ST_CONTINUE;
if (!st_lookup(data->tbl, key, &val2)) {
data->result = FALSE;
return ST_STOP;
@@ -519,45 +645,30 @@ hash_equal(hash1, hash2)
}
static int
-hash_i(key, val, data)
- VALUE key, val;
- int *data;
+hash_invert_i(key, value, hash)
+ VALUE key, value;
+ struct RHash *hash;
{
- *data ^= rb_funcall(key, hash, 0);
- *data ^= rb_funcall(val, hash, 0);
+ if (key == Qnil) return ST_CONTINUE;
+ hash_aset(hash, value, key);
return ST_CONTINUE;
}
static VALUE
-hash_hash(hash)
+hash_invert(hash)
struct RHash *hash;
{
- int h;
+ VALUE h = hash_new();
- st_foreach(hash->tbl, hash_i, &h);
- return INT2FIX(h);
+ st_foreach(hash->tbl, hash_invert_i, h);
+ return h;
}
-extern char **environ;
-
-static VALUE
-env_each(hash)
- VALUE hash;
-{
- char **env;
-
- env = environ;
- while (*env) {
- VALUE var, val;
- char *s = strchr(*env, '=');
+int env_path_tainted = 0;
- var = str_new(*env, s-*env);
- val = str_new2(s+1);
- rb_yield(assoc_new(var, val));
- env++;
- }
- return hash;
-}
+#ifndef NT
+extern char **environ;
+#endif
static VALUE
env_delete(obj, name)
@@ -567,9 +678,11 @@ env_delete(obj, name)
int i, len;
char *nam, *val = 0;
+ rb_secure(4);
Check_Type(name, T_STRING);
nam = name->ptr;
len = strlen(nam);
+ if (strcmp(nam, "PATH") == 0) env_path_tainted = 0;
for(i=0; environ[i]; i++) {
if (strncmp(environ[i], nam, len) == 0 && environ[i][len] == '=') {
val = environ[i]+len+1;
@@ -586,7 +699,7 @@ env_delete(obj, name)
return Qnil;
}
-VALUE
+static VALUE
f_getenv(obj, name)
VALUE obj;
struct RString *name;
@@ -600,43 +713,222 @@ f_getenv(obj, name)
env = getenv(name->ptr);
if (env) {
- return str_new2(env);
+ if (strcmp(name->ptr, "PATH") == 0 && !env_path_tainted)
+ return str_new2(env);
+ return str_taint(str_new2(env));
}
return Qnil;
}
-VALUE
+static VALUE
f_setenv(obj, name, value)
VALUE obj;
struct RString *name, *value;
{
- Check_Type(name, T_STRING);
+ if (rb_safe_level() >= 4) {
+ extern VALUE eSecurityError;
+ Raise(eSecurityError, "cannot change environment variable");
+ }
+
+ Check_SafeStr(name);
if (NIL_P(value)) {
env_delete(obj, name);
return Qnil;
}
- Check_Type(value, T_STRING);
-
+ Check_SafeStr(value);
if (strlen(name->ptr) != name->len)
ArgError("Bad environment name");
if (strlen(value->ptr) != value->len)
ArgError("Bad environment value");
setenv(name->ptr, value->ptr, 1);
+ if (strcmp(name->ptr, "PATH") == 0) env_path_tainted = 0;
return TRUE;
}
static VALUE
+env_keys()
+{
+ char **env;
+ VALUE ary = ary_new();
+
+ env = environ;
+ while (*env) {
+ char *s = strchr(*env, '=');
+ ary_push(ary, str_taint(str_new(*env, s-*env)));
+ env++;
+ }
+ return ary;
+}
+
+static VALUE
+env_each_key(hash)
+ VALUE hash;
+{
+ return ary_each(env_keys());
+}
+
+static VALUE
+env_values()
+{
+ char **env;
+ VALUE ary = ary_new();
+
+ env = environ;
+ while (*env) {
+ char *s = strchr(*env, '=');
+ ary_push(ary, str_taint(str_new2(s+1)));
+ env++;
+ }
+ return ary;
+}
+
+static VALUE
+env_each_value(hash)
+ VALUE hash;
+{
+ return ary_each(env_values());
+}
+
+static VALUE
+env_each(hash)
+ VALUE hash;
+{
+ VALUE ary = env_keys();
+ VALUE *ptr = RARRAY(ary)->ptr;
+ int len = RARRAY(ary)->len;
+
+ while (len--) {
+ VALUE val = f_getenv(Qnil, *ptr);
+ if (!NIL_P(val)) {
+ rb_yield(assoc_new(*ptr, val));
+ }
+ ptr++;
+ }
+ return hash;
+}
+
+static VALUE
+env_delete_if()
+{
+ VALUE ary = env_keys();
+ VALUE *ptr = RARRAY(ary)->ptr;
+ int len = RARRAY(ary)->len;
+
+ while (len--) {
+ VALUE val = f_getenv(Qnil, *ptr);
+ if (!NIL_P(val)) {
+ if (RTEST(rb_yield(assoc_new(*ptr, val)))) {
+ env_delete(Qnil, *ptr);
+ }
+ }
+ ptr++;
+ }
+ return envtbl;
+}
+
+static VALUE
env_to_s()
{
return str_new2("ENV");
}
+static VALUE
+env_to_a()
+{
+ char **env;
+ VALUE ary = ary_new();
+
+ env = environ;
+ while (*env) {
+ char *s = strchr(*env, '=');
+ ary_push(ary, assoc_new(str_taint(str_new(*env, s-*env)),
+ str_taint(str_new2(s+1))));
+ env++;
+ }
+ return ary;
+}
+
+static VALUE
+env_none()
+{
+ return Qnil;
+}
+
+static VALUE
+env_size()
+{
+ int i;
+
+ for(i=0; environ[i]; i++)
+ ;
+ return INT2FIX(i);
+}
+
+static VALUE
+env_empty_p()
+{
+ if (environ[0] == 0) return TRUE;
+ return FALSE;
+}
+
+static VALUE
+env_has_key(env, key)
+ VALUE env, key;
+{
+ if (TYPE(key) != T_STRING) return FALSE;
+ if (getenv(RSTRING(key)->ptr)) return TRUE;
+ return FALSE;
+}
+
+static VALUE
+env_has_value(dmy, value)
+ VALUE dmy, value;
+{
+ char **env;
+ VALUE ary;
+
+ if (TYPE(value) != T_STRING) return FALSE;
+ ary = ary_new();
+ env = environ;
+ while (*env) {
+ char *s = strchr(*env, '=')+1;
+ int len = strlen(s);
+ if (strncmp(s, RSTRING(value)->ptr, len) == 0) return TRUE;
+ env++;
+ }
+ return FALSE;
+}
+
+static VALUE
+env_indexes(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ int i;
+ VALUE indexes = ary_new2(argc);
+
+ for (i=0;i<argc;i++) {
+ char *v = 0;
+ if (TYPE(argv[i]) == T_STRING) {
+ v = getenv(RSTRING(argv[i])->ptr);
+ }
+ if (v) {
+ RARRAY(indexes)->ptr[i] = str_new2(v);
+ }
+ else {
+ RARRAY(indexes)->ptr[i] = Qnil;
+ }
+ RARRAY(indexes)->len = i+1;
+ }
+
+ return indexes;
+}
+
void
Init_Hash()
{
- extern VALUE cKernel;
extern VALUE mEnumerable;
hash = rb_intern("hash");
@@ -649,16 +941,16 @@ Init_Hash()
rb_define_singleton_method(cHash, "[]", hash_s_create, -1);
rb_define_method(cHash,"clone", hash_clone, 0);
+ rb_define_method(cHash,"rehash", hash_rehash, 0);
rb_define_method(cHash,"to_a", hash_to_a, 0);
rb_define_method(cHash,"to_s", hash_to_s, 0);
rb_define_method(cHash,"inspect", hash_inspect, 0);
rb_define_method(cHash,"==", hash_equal, 1);
- rb_define_method(cHash,"hash", hash_hash, 0);
rb_define_method(cHash,"[]", hash_aref, 1);
rb_define_method(cHash,"[]=", hash_aset, 2);
- rb_define_method(cHash,"indexes", hash_indexes, -2);
+ rb_define_method(cHash,"indexes", hash_indexes, -1);
rb_define_method(cHash,"length", hash_length, 0);
rb_define_alias(cHash, "size", "length");
rb_define_method(cHash,"empty?", hash_empty_p, 0);
@@ -675,6 +967,7 @@ Init_Hash()
rb_define_method(cHash,"delete", hash_delete, 1);
rb_define_method(cHash,"delete_if", hash_delete_if, 0);
rb_define_method(cHash,"clear", hash_clear, 0);
+ rb_define_method(cHash,"invert", hash_invert, 0);
rb_define_method(cHash,"include?", hash_has_key, 1);
rb_define_method(cHash,"has_key?", hash_has_key, 1);
@@ -688,9 +981,24 @@ Init_Hash()
rb_define_singleton_method(envtbl,"[]", f_getenv, 1);
rb_define_singleton_method(envtbl,"[]=", f_setenv, 2);
rb_define_singleton_method(envtbl,"each", env_each, 0);
+ rb_define_singleton_method(envtbl,"each_pair", env_each, 0);
+ rb_define_singleton_method(envtbl,"each_key", env_each_key, 0);
+ rb_define_singleton_method(envtbl,"each_value", env_each_value, 0);
rb_define_singleton_method(envtbl,"delete", env_delete, 1);
+ rb_define_singleton_method(envtbl,"delete_if", env_delete_if, 0);
rb_define_singleton_method(envtbl,"to_s", env_to_s, 0);
+ rb_define_singleton_method(envtbl,"rehash", env_none, 0);
+ rb_define_singleton_method(envtbl,"to_a", env_to_a, 0);
+ rb_define_singleton_method(envtbl,"indexes", env_indexes, -1);
+ rb_define_singleton_method(envtbl,"length", env_size, 0);
+ rb_define_singleton_method(envtbl,"empty?", env_empty_p, 0);
+ rb_define_singleton_method(envtbl,"keys", env_keys, 0);
+ rb_define_singleton_method(envtbl,"values", env_values, 0);
+ rb_define_singleton_method(envtbl,"include?", env_has_key, 1);
+ rb_define_singleton_method(envtbl,"has_key?", env_has_key, 1);
+ rb_define_singleton_method(envtbl,"has_value?", env_has_value, 1);
+ rb_define_singleton_method(envtbl,"key?", env_has_key, 1);
+ rb_define_singleton_method(envtbl,"value?", env_has_value, 1);
- rb_define_readonly_variable("$ENV", &envtbl);
rb_define_global_const("ENV", envtbl);
}
diff --git a/inits.c b/inits.c
index e3456814e8..b8fcb0f826 100644
--- a/inits.c
+++ b/inits.c
@@ -21,7 +21,6 @@ rb_call_inits()
#ifdef THREAD
Init_Thread();
#endif
- Init_GC();
Init_eval();
Init_Comparable();
Init_Enumerable();
@@ -44,6 +43,6 @@ rb_call_inits()
Init_load();
Init_Proc();
Init_Math();
- Init_ext();
+ Init_GC();
Init_version();
}
diff --git a/io.c b/io.c
index 7c0fbd8d2b..8d3fb7b879 100644
--- a/io.c
+++ b/io.c
@@ -16,28 +16,39 @@
#include <errno.h>
#include <sys/types.h>
-#ifndef DJGPP
+#if !defined(DJGPP) && !defined(NT) && !defined(__human68k__)
#include <sys/ioctl.h>
#endif
+#if defined(HAVE_FCNTL)
+#include <fcntl.h>
+#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#else
+#ifndef NT
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* and microseconds */
};
#endif
+#endif
#ifdef HAVE_VFORK_H
#include <vfork.h>
#endif
#include <sys/stat.h>
-#ifdef DJGPP
+#if defined(DJGPP) || defined(__CYGWIN32__) || defined(NT) || defined(__human68k__)
#include <fcntl.h>
#endif
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#else
+# define NOFILE 64
+#endif
+
VALUE rb_ad_string();
VALUE cIO;
@@ -53,7 +64,7 @@ VALUE RS_default;
static VALUE argf;
-ID id_write, id_fd, id_print_on;
+ID id_write;
VALUE lastline_get();
void lastline_set();
@@ -116,11 +127,6 @@ closed()
Raise(eIOError, "closed stream");
}
-void
-io_wrong_type()
-{
-}
-
/* writing functions */
VALUE
io_write(io, str)
@@ -129,23 +135,40 @@ io_write(io, str)
{
OpenFile *fptr;
FILE *f;
- VALUE out;
int n;
+ if (TYPE(str) != T_STRING)
+ str = (struct RString*)obj_as_string(str);
+ if (str->len == 0) return INT2FIX(0);
+
+ if (BUILTIN_TYPE(io) != T_FILE) {
+ return rb_funcall(io, id_write, 1, str);
+ }
+
+ rb_secure(4);
GetOpenFile(io, fptr);
io_writable(fptr);
- f = (fptr->f2) ? fptr->f2 : fptr->f;
+ f = GetWriteFile(fptr);
if (f == NULL) closed();
- if (TYPE(str) != T_STRING)
- str = (struct RString*)obj_as_string(str);
- if (str->len == 0) return INT2FIX(0);
-
+#ifdef __human68k__
+ {
+ register UCHAR *ptr = str->ptr;
+ n = (int) str->len;
+ while (--n >= 0)
+ if (fputc(*ptr++, f) == EOF)
+ rb_sys_fail(fptr->path);
+ n = ptr - str->ptr;
+ }
+ if (ferror(f))
+ rb_sys_fail(fptr->path);
+#else
n = fwrite(str->ptr, 1, str->len, f);
if (n == 0 || ferror(f)) {
rb_sys_fail(fptr->path);
}
+#endif
if (fptr->mode & FMODE_SYNC) {
fflush(f);
}
@@ -170,7 +193,7 @@ io_flush(io)
GetOpenFile(io, fptr);
io_writable(fptr);
- f = (fptr->f2) ? fptr->f2 : fptr->f;
+ f = GetWriteFile(fptr);
if (f == NULL) closed();
if (fflush(f) == EOF) rb_sys_fail(0);
@@ -247,7 +270,7 @@ read_all(port)
VALUE port;
{
OpenFile *fptr;
- VALUE str;
+ VALUE str = Qnil;
char buf[BUFSIZ];
int n;
@@ -255,7 +278,6 @@ read_all(port)
io_readable(fptr);
if (fptr->f == NULL) closed();
- str = str_new(0, 0);
for (;;) {
READ_CHECK(fptr->f);
TRAP_BEG;
@@ -263,9 +285,10 @@ read_all(port)
TRAP_END;
if (n == 0) break;
if (n < 0) rb_sys_fail(0);
- str_cat(str, buf, n);
+ if (NIL_P(str)) str = str_new(buf, n);
+ else str_cat(str, buf, n);
}
- return str;
+ return str_taint(str);
}
static VALUE
@@ -301,7 +324,7 @@ io_read(argc, argv, io)
RSTRING(str)->len = n;
RSTRING(str)->ptr[n] = '\0';
- return str;
+ return str_taint(str);
}
static VALUE lineno;
@@ -320,11 +343,10 @@ io_gets_method(argc, argv, io)
int rslen, rspara = 0;
VALUE rs;
- if (rb_scan_args(argc, argv, "01", &rs) == 1) {
- if (!NIL_P(rs)) Check_Type(rs, T_STRING);
- }
+ if (argc == 0) rs = RS;
else {
- rs = RS;
+ rb_scan_args(argc, argv, "1", &rs);
+ if (!NIL_P(rs)) Check_Type(rs, T_STRING);
}
GetOpenFile(io, fptr);
@@ -384,8 +406,11 @@ io_gets_method(argc, argv, io)
cnt = bp - buf;
}
else {
+ READ_CHECK(f);
+ TRAP_BEG;
cnt = fread(buf, 1, sizeof(buf), f);
- c = cnt ? buf[cnt - 1]: EOF;
+ TRAP_END;
+ c = cnt ? 0 : EOF;
}
if (c == EOF) {
@@ -429,7 +454,7 @@ io_gets_method(argc, argv, io)
}
lastline_set(str);
- return (VALUE)str;
+ return str_taint(str);
}
VALUE
@@ -454,6 +479,21 @@ io_readline(argc, argv, io)
}
static VALUE
+io_readlines(argc, argv, io)
+ int argc;
+ VALUE argv;
+ VALUE io;
+{
+ VALUE line, ary;
+
+ ary = ary_new();
+ while (!NIL_P(line = io_gets_method(argc, argv, io))) {
+ ary_push(ary, line);
+ }
+ return ary;
+}
+
+static VALUE
io_each_line(argc, argv, io)
int argc;
VALUE argv;
@@ -550,12 +590,10 @@ io_isatty(io)
{
OpenFile *fptr;
-#ifndef NT
GetOpenFile(io, fptr);
if (fptr->f == NULL) closed();
if (isatty(fileno(fptr->f)) == 0)
return FALSE;
-#endif
return TRUE;
}
@@ -623,12 +661,13 @@ io_syswrite(io, str)
FILE *f;
int n;
+ rb_secure(4);
if (TYPE(str) != T_STRING)
str = obj_as_string(str);
GetOpenFile(io, fptr);
io_writable(fptr);
- f = (fptr->f2) ? fptr->f2 : fptr->f;
+ f = GetWriteFile(fptr);
if (f == NULL) closed();
#ifdef THREAD
@@ -668,22 +707,31 @@ io_sysread(io, len)
RSTRING(str)->len = n;
RSTRING(str)->ptr[n] = '\0';
- return str;
+ return str_taint(str);
}
-static VALUE
+VALUE
io_binmode(io)
VALUE io;
{
-#if defined(NT) || defined(DJGPP)
+#if defined(NT) || defined(DJGPP) || defined(__CYGWIN32__) || defined(__human68k__)
OpenFile *fptr;
GetOpenFile(io, fptr);
+#ifdef __human68k__
+ if (fptr->f)
+ fmode(fptr->f, _IOBIN);
+ if (fptr->f2);
+ fmode(fptr->f2, _IOBIN);
+#else
if (fptr->f && setmode(fileno(fptr->f), O_BINARY) == -1)
rb_sys_fail(fptr->path);
if (fptr->f2 && setmode(fileno(fptr->f2), O_BINARY) == -1)
rb_sys_fail(fptr->path);
#endif
+
+ fptr->mode |= FMODE_BINMODE;
+#endif
return io;
}
@@ -706,8 +754,14 @@ io_mode_flags(mode)
default:
ArgError("illegal access mode");
}
+
+ if (mode[1] == 'b') {
+ flags |= FMODE_BINMODE;
+ mode++;
+ }
+
if (mode[1] == '+') {
- flags |= FMODE_READABLE | FMODE_WRITABLE;
+ flags |= FMODE_READWRITE;
}
return flags;
@@ -752,7 +806,59 @@ rb_fdopen(fd, mode)
return f;
}
-#if defined (NT) || defined(DJGPP)
+#if defined (NT) || defined(DJGPP) || defined(__CYGWIN32__) || defined(__human68k__)
+static struct pipe_list {
+ OpenFile *fptr;
+ struct pipe_list *next;
+} *pipe_list;
+
+static void
+pipe_add_fptr(fptr)
+ OpenFile *fptr;
+{
+ struct pipe_list *list;
+
+ list = ALLOC(struct pipe_list);
+ list->fptr = fptr;
+ list->next = pipe_list;
+ pipe_list = list;
+}
+
+static void
+pipe_del_fptr(fptr)
+ OpenFile *fptr;
+{
+ struct pipe_list *list = pipe_list;
+ struct pipe_list *tmp;
+
+ if (list->fptr == fptr) {
+ pipe_list = list->next;
+ return;
+ }
+
+ while (list->next) {
+ if (list->next->fptr == fptr) {
+ tmp = list->next;
+ list->next = list->next->next;
+ free(tmp);
+ return;
+ }
+ list = list->next;
+ }
+}
+
+static void
+pipe_atexit()
+{
+ struct pipe_list *list = pipe_list;
+
+ while (list) {
+ io_fptr_finalize(list->fptr);
+ list = list->next;
+ }
+}
+
+#if !defined (__CYGWIN32__)
static void
pipe_finalize(fptr)
OpenFile *fptr;
@@ -760,9 +866,24 @@ pipe_finalize(fptr)
if (fptr->f != NULL) {
pclose(fptr->f);
}
+ if (fptr->f2 != NULL) {
+ pclose(fptr->f2);
+ }
fptr->f = fptr->f2 = NULL;
+ pipe_del_fptr(fptr);
}
#endif
+#endif
+
+void
+io_unbuffered(fptr)
+ OpenFile *fptr;
+{
+ if (fptr->f2 == 0) TypeError("non-writable fptr");
+ setbuf(fptr->f, NULL);
+ setbuf(fptr->f2, NULL);
+ fptr->mode |= FMODE_SYNC;
+}
static VALUE
pipe_open(pname, mode)
@@ -771,7 +892,7 @@ pipe_open(pname, mode)
int modef = io_mode_flags(mode);
OpenFile *fptr;
-#if defined(NT) || defined(DJGPP)
+#if defined(NT) || defined(DJGPP) || defined(__human68k__)
FILE *f = popen(pname, mode);
if (f == NULL) rb_sys_fail(pname);
@@ -780,10 +901,14 @@ pipe_open(pname, mode)
OBJSETUP(port, cIO, T_FILE);
MakeOpenFile(port, fptr);
fptr->finalize = pipe_finalize;
+ fptr->mode = modef;
+ pipe_add_fptr(fptr);
if (modef & FMODE_READABLE) fptr->f = f;
- if (modef & FMODE_WRITABLE) fptr->f2 = f;
- fptr->mode = modef | FMODE_SYNC;
+ if (modef & FMODE_WRITABLE) {
+ fptr->f2 = f;
+ io_unbuffered(fptr);
+ }
return (VALUE)port;
}
#else
@@ -806,32 +931,47 @@ pipe_open(pname, mode)
case 0: /* child */
if (modef & FMODE_READABLE) {
close(pr[0]);
- dup2(pr[1], 1);
- close(pr[1]);
+ if (pr[1] != 1) {
+ dup2(pr[1], 1);
+ close(pr[1]);
+ }
}
if (modef & FMODE_WRITABLE) {
close(pw[1]);
- dup2(pw[0], 0);
- close(pw[0]);
+ if (pw[0] != 0) {
+ dup2(pw[0], 0);
+ close(pw[0]);
+ }
}
if (doexec) {
- VALUE fd = io_fileno(rb_stderr);
- int f = FIX2INT(fd);
+ VALUE serr = io_fileno(rb_stderr);
+ int fd = FIX2INT(serr);
+ extern char *sourcefile;
+ extern int sourceline;
- if (f != 2) {
+ if (fd != 2) {
close(2);
- dup2(f, 2);
- close(f);
+ dup2(fd, 2);
+ close(fd);
}
+
+ for (fd = 3; fd < NOFILE; fd++)
+ close(fd);
rb_proc_exec(pname);
+ fprintf(stderr, "%s:%d: command not found: %s\n",
+ sourcefile, sourceline, pname);
_exit(127);
}
return Qnil;
case -1: /* fork failed */
if (errno == EAGAIN) {
+#ifdef THREAD
+ thread_sleep(1);
+#else
sleep(1);
+#endif
goto retry;
}
close(pr[0]); close(pw[1]);
@@ -843,15 +983,24 @@ pipe_open(pname, mode)
NEWOBJ(port, struct RFile);
OBJSETUP(port, cIO, T_FILE);
MakeOpenFile(port, fptr);
- if (modef & FMODE_READABLE) close(pr[1]);
- if (modef & FMODE_WRITABLE) close(pw[0]);
fptr->mode = modef;
fptr->mode |= FMODE_SYNC;
fptr->pid = pid;
- if (modef & FMODE_READABLE) fptr->f = rb_fdopen(pr[0], "r");
- if (modef & FMODE_WRITABLE) fptr->f2 = rb_fdopen(pw[1], "w");
+ if (modef & FMODE_READABLE) {
+ close(pr[1]);
+ fptr->f = rb_fdopen(pr[0], "r");
+ }
+ if (modef & FMODE_WRITABLE) {
+ FILE *f = rb_fdopen(pw[1], "w");
+ close(pw[0]);
+ if (fptr->f) fptr->f2 = f;
+ else fptr->f = f;
+ }
+#if defined (__CYGWIN32__)
+ pipe_add_fptr(fptr);
+#endif
return (VALUE)port;
}
}
@@ -859,7 +1008,7 @@ pipe_open(pname, mode)
}
static VALUE
-io_popen(argc, argv, self)
+io_s_popen(argc, argv, self)
int argc;
VALUE *argv;
VALUE self;
@@ -868,7 +1017,7 @@ io_popen(argc, argv, self)
VALUE pname, pmode;
rb_scan_args(argc, argv, "11", &pname, &pmode);
- Check_Type(pname, T_STRING);
+ Check_SafeStr(pname);
if (NIL_P(pmode)) {
mode = "r";
}
@@ -877,7 +1026,7 @@ io_popen(argc, argv, self)
if (RSTRING(pmode)->len == 0 || RSTRING(pmode)->len > 2)
ArgError("illegal access mode");
mode = RSTRING(pmode)->ptr;
- }
+ }
return pipe_open(RSTRING(pname)->ptr, mode);
}
@@ -903,7 +1052,7 @@ f_open(argc, argv, self)
VALUE pname, pmode;
rb_scan_args(argc, argv, "11", &pname, &pmode);
- Check_Type(pname, T_STRING);
+ Check_SafeStr(pname);
if (NIL_P(pmode)) {
mode = "r";
}
@@ -916,6 +1065,126 @@ f_open(argc, argv, self)
return io_open(RSTRING(pname)->ptr, mode);
}
+#ifndef NT
+extern char *strdup();
+#endif
+
+VALUE
+io_reopen(io, nfile)
+ VALUE io, nfile;
+{
+ OpenFile *fptr, *orig;
+ char *mode;
+ int fd;
+
+ GetOpenFile(io, fptr);
+ Check_Type(nfile, T_FILE);
+ GetOpenFile(nfile, orig);
+
+ if (orig->f2) {
+ fflush(orig->f2);
+ }
+ else if (orig->mode & FMODE_WRITABLE) {
+ fflush(orig->f);
+ }
+
+ /* copy OpenFile structure */
+ fptr->mode = orig->mode;
+ fptr->pid = orig->pid;
+ fptr->lineno = orig->lineno;
+ if (fptr->path) free(fptr->path);
+ if (orig->path) fptr->path = strdup(orig->path);
+ else fptr->path = 0;
+ fptr->finalize = orig->finalize;
+
+ switch (fptr->mode & FMODE_READWRITE) {
+ case FMODE_READABLE:
+ default:
+ mode = "r"; break;
+ case FMODE_WRITABLE:
+ mode = "w"; break;
+ case FMODE_READWRITE:
+ if (orig->f2) mode = "r";
+ else mode = "r+";
+ break;
+ }
+ fd = fileno(fptr->f);
+ fclose(fptr->f);
+ dup2(fileno(orig->f), fd);
+ fptr->f = rb_fdopen(fd, mode);
+
+ if (fptr->f2) {
+ fd = fileno(fptr->f2);
+ fclose(fptr->f2);
+ if (orig->f2) {
+ dup2(fileno(orig->f2), fd);
+ fptr->f = rb_fdopen(fd, "w");
+ }
+ else {
+ fptr->f2 = 0;
+ }
+ }
+
+ if (fptr->mode & FMODE_BINMODE) {
+ io_binmode(io);
+ }
+
+ RBASIC(io)->class = RBASIC(nfile)->class;
+ return io;
+}
+
+static VALUE
+io_clone(io)
+ VALUE io;
+{
+ OpenFile *fptr, *orig;
+ int fd;
+ char *mode;
+
+ NEWOBJ(obj, struct RFile);
+ OBJSETUP(obj, CLASS_OF(io), T_FILE);
+
+ GetOpenFile(io, orig);
+ MakeOpenFile(obj, fptr);
+
+ if (orig->f2) {
+ fflush(orig->f2);
+ }
+ else if (orig->mode & FMODE_WRITABLE) {
+ fflush(orig->f);
+ }
+
+ /* copy OpenFile structure */
+ fptr->mode = orig->mode;
+ fptr->pid = orig->pid;
+ fptr->lineno = orig->lineno;
+ if (orig->path) fptr->path = strdup(orig->path);
+ fptr->finalize = orig->finalize;
+
+ switch (fptr->mode & FMODE_READWRITE) {
+ case FMODE_READABLE:
+ default:
+ mode = "r"; break;
+ case FMODE_WRITABLE:
+ mode = "w"; break;
+ case FMODE_READWRITE:
+ if (orig->f2) mode = "r";
+ else mode = "r+";
+ break;
+ }
+ fd = dup(fileno(orig->f));
+ fptr->f = rb_fdopen(fd, mode);
+ if (fptr->f2) {
+ fd = dup(fileno(orig->f2));
+ fptr->f = rb_fdopen(fd, "w");
+ }
+ if (fptr->mode & FMODE_BINMODE) {
+ io_binmode(obj);
+ }
+
+ return (VALUE)obj;
+}
+
static VALUE
io_printf(argc, argv, out)
int argc;
@@ -971,14 +1240,17 @@ io_print(argc, argv, out)
io_write(out, OFS);
}
switch (TYPE(argv[i])) {
- case T_STRING:
- io_write(out, argv[i]);
- break;
case T_NIL:
io_write(out, str_new2("nil"));
break;
+ case T_ARRAY:
+ ary_print_on(argv[i], out);
+ break;
+ case T_HASH:
+ break;
+ case T_STRING:
default:
- rb_funcall(argv[i], id_print_on, 1, out);
+ io_write(out, argv[i]);
break;
}
}
@@ -998,8 +1270,9 @@ f_print(argc, argv)
return Qnil;
}
-VALUE
+static VALUE
f_p(obj, val)
+ VALUE obj, val;
{
VALUE str = rb_inspect(val);
@@ -1009,7 +1282,7 @@ f_p(obj, val)
return Qnil;
}
-static VALUE
+static void
io_defset(val, id)
VALUE val;
ID id;
@@ -1017,17 +1290,11 @@ io_defset(val, id)
if (TYPE(val) == T_STRING) {
val = io_open(RSTRING(val)->ptr, "w");
}
- if (!obj_is_kind_of(val, cIO)) {
- TypeError("$< must be a file, %s given", rb_class2name(CLASS_OF(val)));
+ if (!rb_respond_to(val, id_write)) {
+ TypeError("$< must have write method, %s given",
+ rb_class2name(CLASS_OF(val)));
}
- return rb_defout = val;
-}
-
-static VALUE
-f_print_on(obj, port)
- VALUE obj, port;
-{
- return io_write(port, obj);
+ rb_defout = val;
}
static VALUE
@@ -1046,6 +1313,25 @@ prep_stdio(f, mode)
return (VALUE)obj;
}
+static VALUE
+io_s_new(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ VALUE fnum, mode;
+ FILE *f;
+ char *m = "r";
+
+ rb_scan_args(argc, argv, "11", &fnum, &mode);
+
+ if (!NIL_P(mode)) {
+ Check_SafeStr(mode);
+ m = RSTRING(mode)->ptr;
+ }
+ f = rb_fdopen(NUM2INT(fnum), m);
+ return prep_stdio(f, io_mode_flags(m));
+}
+
static VALUE filename, file;
static int gets_lineno;
static int init_p = 0, next_p = 0;
@@ -1094,12 +1380,12 @@ next_argv()
fstat(fileno(fr), &st);
if (*inplace) {
str = str_new2(fn);
-#ifdef NT
+#if defined(MSDOS) || defined(__CYGWIN32__) || defined(NT)
add_suffix(str, inplace);
#else
str_cat(str, inplace, strlen(inplace));
#endif
-#if defined(MSDOS) || defined(__BOW__)
+#if defined(MSDOS) || defined(__BOW__) || defined(__CYGWIN32__) || defined(NT) || defined(__human68k__)
(void)fclose(fr);
(void)unlink(RSTRING(str)->ptr);
(void)rename(fn, RSTRING(str)->ptr);
@@ -1114,7 +1400,7 @@ next_argv()
#endif
}
else {
-#if !defined(MSDOS) && !defined(__BOW__)
+#if !defined(MSDOS) && !defined(__BOW__) && !defined(__CYGWIN32__) && !defined(NT) && !defined(__human68k__)
if (unlink(fn) < 0) {
Warning("Can't remove %s: %s, skipping file",
fn, strerror(errno));
@@ -1126,7 +1412,7 @@ next_argv()
#endif
}
fw = rb_fopen(fn, "w");
-#if !defined(DJGPP) && !defined(__CYGWIN32__)
+#if !defined(MSDOS) && !defined(__CYGWIN32__) && !(NT) && !defined(__human68k__)
fstat(fileno(fw), &st2);
fchmod(fileno(fw), st.st_mode);
if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
@@ -1149,7 +1435,7 @@ next_argv()
static VALUE
f_gets_method(argc, argv)
int argc;
- VALUE argv;
+ VALUE *argv;
{
VALUE line;
@@ -1168,9 +1454,7 @@ f_gets_method(argc, argv)
}
VALUE
-f_gets(argc, argv)
- int argc;
- VALUE argv;
+f_gets()
{
return f_gets_method(0,0);
}
@@ -1237,14 +1521,14 @@ f_readlines(argc, argv)
VALUE line, ary;
ary = ary_new();
- while (RTEST(line = f_gets_method(argc, argv))) {
+ while (!NIL_P(line = f_gets_method(argc, argv))) {
ary_push(ary, line);
}
return ary;
}
-VALUE
+void
rb_str_setter(val, id, var)
VALUE val;
ID id;
@@ -1253,7 +1537,7 @@ rb_str_setter(val, id, var)
if (!NIL_P(val) && TYPE(val) != T_STRING) {
TypeError("value of %s must be String", rb_id2name(id));
}
- return *var = val;
+ *var = val;
}
static VALUE
@@ -1262,20 +1546,23 @@ f_backquote(obj, str)
struct RString *str;
{
VALUE port, result;
- OpenFile *fptr;
- Check_Type(str, T_STRING);
+ Check_SafeStr(str);
port = pipe_open(str->ptr, "r");
result = read_all(port);
io_close(port);
+ if (NIL_P(result)) return str_new(0,0);
return result;
}
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
+#ifdef NT
+#define select(v, w, x, y, z) (-1) /* anytime fail */
+#endif
static VALUE
f_select(argc, argv, obj)
@@ -1290,6 +1577,7 @@ f_select(argc, argv, obj)
OpenFile *fptr;
int i, max = 0, n;
int interrupt = 0;
+ int pending = 0;
rb_scan_args(argc, argv, "13", &read, &write, &except, &timeout);
if (NIL_P(timeout)) {
@@ -1302,7 +1590,6 @@ f_select(argc, argv, obj)
FD_ZERO(&pset);
if (!NIL_P(read)) {
- int pending = 0;
Check_Type(read, T_ARRAY);
rp = &rset;
@@ -1384,6 +1671,7 @@ f_select(argc, argv, obj)
interrupt = 1;
}
#endif
+ if (!pending && n == 0) return Qnil; /* returns nil on timeout */
res = ary_new2(3);
ary_push(res, rp?ary_new():ary_new2(0));
@@ -1391,7 +1679,6 @@ f_select(argc, argv, obj)
ary_push(res, ep?ary_new():ary_new2(0));
if (interrupt == 0) {
-
if (rp) {
list = RARRAY(res)->ptr[0];
for (i=0; i< RARRAY(read)->len; i++) {
@@ -1430,64 +1717,100 @@ f_select(argc, argv, obj)
}
}
- return res;
+ return res; /* returns an empty array on interrupt */
}
-void
+static VALUE
io_ctl(io, req, arg, io_p)
VALUE io, req;
struct RString *arg;
int io_p;
{
-#if !defined(MSDOS)
+#if !defined(MSDOS) && !defined(__human68k__)
int cmd = NUM2INT(req);
OpenFile *fptr;
int len, fd;
+ long narg = 0;
+ int retval;
+ rb_secure(2);
GetOpenFile(io, fptr);
+ if (NIL_P(arg) || (VALUE)arg == FALSE) {
+ narg = 0;
+ }
+ else if (FIXNUM_P(arg)) {
+ narg = FIX2INT(arg);
+ }
+ else if ((VALUE)arg == TRUE) {
+ narg = 1;
+ }
+ else {
+ Check_Type(arg, T_STRING);
+
#ifdef IOCPARM_MASK
#ifndef IOCPARM_LEN
#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
#endif
#endif
#ifdef IOCPARM_LEN
- len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
+ len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
#else
- len = 256; /* otherwise guess at what's safe */
+ len = 256; /* otherwise guess at what's safe */
#endif
+ str_modify(arg);
- Check_Type(arg, T_STRING);
- str_modify(arg);
-
- str_resize(arg, len+1);
- arg->ptr[len] = 17;
+ if (arg->len < len) {
+ str_resize(arg, len+1);
+ arg->ptr[len] = 17; /* a little sanity check here */
+ narg = (long)arg->ptr;
+ }
+ }
fd = fileno(fptr->f);
#ifdef HAVE_FCNTL
- if ((io_p?ioctl(fd, cmd, arg->ptr):fcntl(fd, cmd, arg->ptr))<0) {
- rb_sys_fail(fptr->path);
- }
+ retval = io_p?ioctl(fd, cmd, narg):fcntl(fd, cmd, narg);
#else
if (!io_p) {
rb_notimplement();
}
- if (ioctl(fd, cmd, arg->ptr)<0) rb_sys_fail(fptr->path);
+ retval = ioctl(fd, cmd, narg);
#endif
- if (arg->ptr[len] != 17) {
- ArgError("Return value overflowed string");
+ if (retval < 0) rb_sys_fail(fptr->path);
+ if (TYPE(arg) == T_STRING && arg->ptr[len] != 17) {
+ ArgError("return value overflowed string");
}
+ return INT2NUM(retval);
#else
- rb_notimplement();
+ rb_notimplement();
#endif
}
static VALUE
-io_ioctl(io, req, arg)
- VALUE io, req;
- struct RString *arg;
+io_ioctl(argc, argv, io)
+ int argc;
+ VALUE *argv;
+ VALUE io;
{
- io_ctl(io, req, arg, 1);
- return io;
+ VALUE req, arg;
+
+ rb_scan_args(argc, argv, "11", &req, &arg);
+ return io_ctl(io, req, arg, 1);
+}
+
+static VALUE
+io_fcntl(argc, argv, io)
+ int argc;
+ VALUE *argv;
+ VALUE io;
+{
+#ifdef HAVE_FCNTL
+ VALUE req, arg;
+
+ rb_scan_args(argc, argv, "11", &req, &arg);
+ return io_ctl(io, req, arg, 0);
+#else
+ rb_notimplement();
+#endif
}
static VALUE
@@ -1502,7 +1825,7 @@ f_syscall(argc, argv)
unsigned long arg[8];
#endif
int retval = -1;
- int i = 0;
+ int i = 1;
int items = argc - 1;
/* This probably won't work on machines where sizeof(long) != sizeof(int)
@@ -1510,6 +1833,7 @@ f_syscall(argc, argv)
* not likely have syscall implemented either, so who cares?
*/
+ rb_secure(2);
arg[0] = NUM2INT(argv[0]); argv++;
while (items--) {
if (FIXNUM_P(*argv)) {
@@ -1585,13 +1909,19 @@ f_syscall(argc, argv)
}
static VALUE
-io_pipe()
+io_s_pipe()
{
+#ifndef __human68k__
int pipes[2];
VALUE r, w, ary;
+#ifdef NT
+ if (_pipe(pipes, 1024, O_BINARY) == -1)
+#else
if (pipe(pipes) == -1)
+#endif
rb_sys_fail(0);
+
r = prep_stdio(fdopen(pipes[0], "r"), FMODE_READABLE);
w = prep_stdio(fdopen(pipes[1], "w"), FMODE_WRITABLE);
@@ -1600,52 +1930,112 @@ io_pipe()
ary_push(ary, w);
return ary;
+#else
+ rb_notimplement();
+#endif
}
+struct foreach_arg {
+ int argc;
+ VALUE sep;
+ VALUE io;
+};
static VALUE
-io_foreach_line(io)
- VALUE io;
+io_foreach_line(arg)
+ struct foreach_arg *arg;
{
VALUE str;
- while (!NIL_P(str = io_gets(io))) {
+ while (!NIL_P(str = io_gets_method(arg->argc, &arg->sep, arg->io))) {
rb_yield(str);
}
return Qnil;
}
static VALUE
-io_foreach(io, fname)
+io_s_foreach(argc, argv, io)
+ int argc;
+ VALUE *argv;
VALUE io;
+{
struct RString *fname;
+ struct foreach_arg arg;
+
+ rb_scan_args(argc, argv, "11", &fname, &arg.sep);
+ Check_SafeStr(fname);
+
+ arg.argc = argc - 1;
+ arg.io = io_open(fname->ptr, "r");
+ return rb_ensure(io_foreach_line, &arg, io_close, arg.io);
+}
+
+static VALUE
+io_readline_line(arg)
+ struct foreach_arg *arg;
+{
+ VALUE line, ary;
+
+ ary = ary_new();
+ while (!NIL_P(line = io_gets_method(arg->argc, &arg->sep, arg->io))) {
+ ary_push(ary, line);
+ }
+
+ return ary;
+}
+
+static VALUE
+io_s_readlines(argc, argv, io)
+ int argc;
+ VALUE *argv;
+ VALUE io;
{
- VALUE f, v;
+ struct RString *fname;
+ struct foreach_arg arg;
+
+ rb_scan_args(argc, argv, "11", &fname, &arg.sep);
+ Check_SafeStr(fname);
+
+ arg.argc = argc - 1;
+ arg.io = io_open(fname->ptr, "r");
+ return rb_ensure(io_readline_line, &arg, io_close, arg.io);
+}
- Check_Type(fname, T_STRING);
- f = io_open(fname->ptr, "r");
- return rb_ensure(io_foreach_line, f, io_close, f);
+static VALUE
+arg_fileno()
+{
+ return io_fileno(file);
}
static VALUE
arg_read(argc, argv)
int argc;
- VALUE argv;
+ VALUE *argv;
{
- VALUE str, str2;
+ VALUE tmp, str;
+ int len;
- str = str_new(0, 0);
- for (;;) {
- retry:
- if (!next_argv()) return Qnil;
- str2 = io_read(argc, argv, file);
- if (NIL_P(str2) && next_p != -1) {
- io_close(file);
- next_p = 1;
- goto retry;
- }
- if (NIL_P(str2)) break;
- str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len);
+ if (argc == 1) len = NUM2INT(argv[0]);
+ str = Qnil;
+
+ retry:
+ if (!next_argv()) return str;
+ tmp = io_read(argc, argv, file);
+ if (NIL_P(tmp) && next_p != -1) {
+ io_close(file);
+ next_p = 1;
+ goto retry;
+ }
+ if (NIL_P(tmp)) return str;
+ else if (NIL_P(str)) str = tmp;
+ else str_cat(str, RSTRING(tmp)->ptr, RSTRING(tmp)->len);
+ if (argc == 0) {
+ goto retry;
+ }
+ if (RSTRING(tmp)->len < len) {
+ len -= RSTRING(tmp)->len;
+ argv[0] = INT2FIX(len);
+ goto retry;
}
return str;
@@ -1669,6 +2059,17 @@ arg_getc()
}
static VALUE
+arg_readchar()
+{
+ VALUE c = io_getc(file);
+
+ if (NIL_P(c)) {
+ eof_error();
+ }
+ return c;
+}
+
+static VALUE
arg_each_line(argc, argv)
int argc;
VALUE argv;
@@ -1704,68 +2105,116 @@ arg_file()
return file;
}
+static VALUE
+arg_skip()
+{
+ if (next_p != -1) {
+ io_close(file);
+ next_p = 1;
+ }
+ return argf;
+}
+
+static VALUE
+arg_close()
+{
+ io_close(file);
+ if (next_p != -1) {
+ next_p = 1;
+ }
+ gets_lineno = 0;
+ return argf;
+}
+
+static VALUE
+arg_closed()
+{
+ return io_closed(file);
+}
+
+static VALUE
+opt_i_get()
+{
+ if (!inplace) return Qnil;
+ return str_new2(inplace);
+}
+
+static void
+opt_i_set(val)
+ struct RString *val;
+{
+ if (NIL_P(val)) {
+ inplace = 0;
+ return;
+ }
+ Check_Type(val, T_STRING);
+ inplace = val->ptr;
+}
+
extern VALUE mEnumerable;
void
Init_IO()
{
- extern VALUE cKernel;
+ extern VALUE mKernel;
extern VALUE eException;
eEOFError = rb_define_class("EOFError", eException);
id_write = rb_intern("write");
- id_fd = rb_intern("fd");
- id_print_on = rb_intern("print_on");
-
- rb_define_private_method(cKernel, "syscall", f_syscall, -1);
- rb_define_private_method(cKernel, "open", f_open, -1);
- rb_define_private_method(cKernel, "printf", f_printf, -1);
- rb_define_private_method(cKernel, "print", f_print, -1);
- rb_define_private_method(cKernel, "gets", f_gets_method, -1);
- rb_define_private_method(cKernel, "readline", f_readline, -1);
- rb_define_private_method(cKernel, "eof", f_eof, 0);
- rb_define_private_method(cKernel, "getc", f_getc, 0);
- rb_define_private_method(cKernel, "readchar", f_readchar, 0);
- rb_define_private_method(cKernel, "select", f_select, -1);
- rb_define_private_method(cKernel, "ungetc", f_ungetc, 1);
+ rb_define_global_function("syscall", f_syscall, -1);
- rb_define_private_method(cKernel, "readlines", f_readlines, -1);
+ rb_define_global_function("open", f_open, -1);
+ rb_define_global_function("printf", f_printf, -1);
+ rb_define_global_function("print", f_print, -1);
+ rb_define_global_function("gets", f_gets_method, -1);
+ rb_define_global_function("readline", f_readline, -1);
+ rb_define_global_function("eof", f_eof, 0);
+ rb_define_global_function("eof?", f_eof, 0);
+ rb_define_global_function("getc", f_getc, 0);
+ rb_define_global_function("readchar", f_readchar, 0);
+ rb_define_global_function("select", f_select, -1);
+ rb_define_global_function("ungetc", f_ungetc, 1);
- rb_define_method(cKernel, "print_on", f_print_on, 1);
+ rb_define_global_function("readlines", f_readlines, -1);
- rb_define_private_method(cKernel, "`", f_backquote, 1);
- rb_define_private_method(cKernel, "pipe", io_pipe, 0);
+ rb_define_global_function("`", f_backquote, 1);
+ rb_define_global_function("pipe", io_s_pipe, 0);
- rb_define_private_method(cKernel, "p", f_p, 1);
+ rb_define_global_function("p", f_p, 1);
cIO = rb_define_class("IO", cObject);
rb_include_module(cIO, mEnumerable);
- rb_undef_method(CLASS_OF(cIO), "new");
-
- rb_define_singleton_method(cIO, "popen", io_popen, -1);
- rb_define_singleton_method(cIO, "foreach", io_foreach, 1);
+ rb_define_singleton_method(cIO, "new", io_s_new, -1);
+ rb_define_singleton_method(cIO, "popen", io_s_popen, -1);
+ rb_define_singleton_method(cIO, "foreach", io_s_foreach, -1);
+ rb_define_singleton_method(cIO, "readlines", io_s_readlines, -1);
rb_define_singleton_method(cIO, "select", f_select, -1);
FS = OFS = Qnil;
rb_define_hooked_variable("$;", &FS, 0, rb_str_setter);
+ rb_define_hooked_variable("$-F", &FS, 0, rb_str_setter);
rb_define_hooked_variable("$,", &OFS, 0, rb_str_setter);
RS = RS_default = str_new2("\n"); ORS = Qnil;
rb_global_variable(&RS_default);
rb_define_hooked_variable("$/", &RS, 0, rb_str_setter);
+ rb_define_hooked_variable("$-0", &RS, 0, rb_str_setter);
rb_define_hooked_variable("$\\", &ORS, 0, rb_str_setter);
rb_define_variable("$.", &lineno);
rb_define_virtual_variable("$_", lastline_get, lastline_set);
+ rb_define_method(cIO, "clone", io_clone, 0);
+ rb_define_method(cIO, "reopen", io_reopen, 1);
+
rb_define_method(cIO, "print", io_print, -1);
rb_define_method(cIO, "printf", io_printf, -1);
rb_define_method(cIO, "each", io_each_line, -1);
- rb_define_method(cIO, "each_line", io_each_line, 0);
+ rb_define_method(cIO, "each_line", io_each_line, -1);
rb_define_method(cIO, "each_byte", io_each_byte, 0);
rb_define_method(cIO, "syswrite", io_syswrite, 1);
@@ -1777,7 +2226,7 @@ Init_IO()
rb_define_method(cIO, "sync", io_sync, 0);
rb_define_method(cIO, "sync=", io_set_sync, 1);
- rb_define_alias(cIO, "readlines", "to_a");
+ rb_define_method(cIO, "readlines", io_readlines, -1);
rb_define_method(cIO, "read", io_read, -1);
rb_define_method(cIO, "write", io_write, 1);
@@ -1790,6 +2239,7 @@ Init_IO()
rb_define_method(cIO, "<<", io_puts, 1);
rb_define_method(cIO, "flush", io_flush, 0);
rb_define_method(cIO, "eof", io_eof, 0);
+ rb_define_method(cIO, "eof?", io_eof, 0);
rb_define_method(cIO, "close", io_close, 0);
rb_define_method(cIO, "closed?", io_closed, 0);
@@ -1798,7 +2248,8 @@ Init_IO()
rb_define_method(cIO, "tty?", io_isatty, 0);
rb_define_method(cIO, "binmode", io_binmode, 0);
- rb_define_method(cIO, "ioctl", io_ioctl, 2);
+ rb_define_method(cIO, "ioctl", io_ioctl, -1);
+ rb_define_method(cIO, "fcntl", io_fcntl, -1);
rb_stdin = prep_stdio(stdin, FMODE_READABLE);
rb_define_readonly_variable("$stdin", &rb_stdin);
@@ -1817,18 +2268,21 @@ Init_IO()
rb_extend_object(argf, mEnumerable);
rb_define_readonly_variable("$<", &argf);
- rb_define_readonly_variable("$ARGF", &argf);
rb_define_global_const("ARGF", argf);
- rb_define_singleton_method(argf, "each", arg_each_line, 0);
+ rb_define_singleton_method(argf, "fileno", arg_fileno, 0);
+ rb_define_singleton_method(argf, "to_i", arg_fileno, 0);
+ rb_define_singleton_method(argf, "each", arg_each_line, -1);
rb_define_singleton_method(argf, "each_line", arg_each_line, -1);
rb_define_singleton_method(argf, "each_byte", arg_each_byte, 0);
rb_define_singleton_method(argf, "read", arg_read, -1);
rb_define_singleton_method(argf, "readlines", f_readlines, -1);
+ rb_define_singleton_method(argf, "to_a", f_readlines, -1);
rb_define_singleton_method(argf, "gets", f_gets_method, -1);
rb_define_singleton_method(argf, "readline", f_readline, -1);
rb_define_singleton_method(argf, "getc", arg_getc, 0);
+ rb_define_singleton_method(argf, "readchar", arg_readchar, 0);
rb_define_singleton_method(argf, "eof", f_eof, 0);
rb_define_singleton_method(argf, "eof?", f_eof, 0);
rb_define_singleton_method(argf, "ungetc", f_ungetc, 1);
@@ -1836,11 +2290,19 @@ Init_IO()
rb_define_singleton_method(argf, "to_s", arg_filename, 0);
rb_define_singleton_method(argf, "filename", arg_filename, 0);
rb_define_singleton_method(argf, "file", arg_file, 0);
+ rb_define_singleton_method(argf, "skip", arg_skip, 0);
+ rb_define_singleton_method(argf, "close", arg_close, 0);
+ rb_define_singleton_method(argf, "closed?", arg_closed, 0);
filename = str_new2("-");
rb_define_readonly_variable("$FILENAME", &filename);
file = rb_stdin;
rb_global_variable(&file);
+ rb_define_virtual_variable("$-i", opt_i_get, opt_i_set);
Init_File();
+
+#if defined (NT) || defined(DJGPP) || defined(__CYGWIN32__) || defined(__human68k__)
+ atexit(pipe_atexit);
+#endif
}
diff --git a/io.h b/io.h
index bc15d46e0e..05789a9c73 100644
--- a/io.h
+++ b/io.h
@@ -31,9 +31,8 @@ typedef struct OpenFile {
#define FMODE_READABLE 1
#define FMODE_WRITABLE 2
#define FMODE_READWRITE 3
-#define FMODE_SYNC 4
-
-void io_wrong_type();
+#define FMODE_BINMODE 4
+#define FMODE_SYNC 8
#define GetOpenFile(obj,fp) ((fp) = RFILE(obj)->fptr)
@@ -47,6 +46,8 @@ void io_wrong_type();
fp->finalize = 0;\
} while (0)
+#define GetWriteFile(fptr) (((fptr)->f2) ? (fptr)->f2 : (fptr)->f)
+
FILE *rb_fopen();
#endif
diff --git a/lib/English.rb b/lib/English.rb
new file mode 100644
index 0000000000..c7e13bebe6
--- /dev/null
+++ b/lib/English.rb
@@ -0,0 +1,28 @@
+
+alias $ERROR_INFO $!
+alias $ERROR_POSITION $@
+alias $LOADED_FEATURES $"
+alias $FS $;
+alias $FIELD_SEPARATOR $;
+alias $OFS $,
+alias $OUTPUT_FIELD_SEPARATOR $,
+alias $RS $/
+alias $INPUT_RECORD_SEPARATOR $/
+alias $ORS $\
+alias $OUPUT_RECORD_SEPARATOR $\
+alias $INPUT_LINE_NUMBER $.
+alias $NR $.
+alias $LAST_READ_LINE $_
+alias $DEFAULT_OUTPUT $>
+alias $DEFAULT_INPUT $<
+alias $PID $$
+alias $PROCESS_ID $$
+alias $CHILD_STATUS $?
+alias $LAST_MATCH_INFO $~
+alias $IGNORECASE $=
+alias $PROGRAM_NAME $0
+alias $ARGV $*
+alias $MATCH $&
+alias $PREMATCH $`
+alias $POSTMATCH $'
+alias $LAST_PAREN_MATCH $+
diff --git a/lib/base64.rb b/lib/base64.rb
index 9bb6487bee..96208a634d 100644
--- a/lib/base64.rb
+++ b/lib/base64.rb
@@ -1,29 +1,11 @@
def decode64(str)
- e = -1;
- c = ","
- string=''
+ string = ''
for line in str.split("\n")
- line.sub!(/=+$/, '')
- line.tr! 'A-Za-z0-9+/', "\000-\377"
- line.each_byte { |ch|
- n +=1
- e +=1
- if e==0
- c = ch << 2
- elsif e==1
- c |= ch >>4
- string += [c].pack('c')
- c = ch << 4
- elsif e == 2
- c |= ch >> 2
- string += [c].pack('c');
- c = ch << 6
- elsif e==3
- c |= ch
- string += [c].pack('c')
- e = -1
- end
- }
+ line.delete!('^A-Za-z0-9+/') # remove non-base64 chars
+ line.tr!('A-Za-z0-9+/', ' -_') # convert to uuencoded format
+ len = ["#{32 + line.length * 3 / 4}"].pack("c")
+ # compute length byte
+ string += "#{len}#{line}".unpack("u") # uudecode and concatenate
end
return string
end
@@ -53,3 +35,20 @@ def decode_b(str)
str.gsub!(/\0/, '')
j2e(str)
end
+
+def encode64(bin)
+ encode = ""
+ pad = 0
+ [bin].pack("u").each do |uu|
+ len = (2 + (uu[0] - 32)* 4) / 3
+ encode << uu[1, len].tr('` -_', 'AA-Za-z0-9+/')
+ pad += uu.length - 2 - len
+ end
+ encode + "=" * (pad % 3)
+end
+
+def b64encode(bin, len = 60)
+ encode64(bin).scan(/.{1,#{len}}/o) do
+ print $&, "\n"
+ end
+end
diff --git a/lib/date.rb b/lib/date.rb
new file mode 100644
index 0000000000..260f6e79ec
--- /dev/null
+++ b/lib/date.rb
@@ -0,0 +1,221 @@
+#
+# Date.rb -
+# $Release Version: $
+# $Revision: 1.2 $
+# $Date: 1997/02/14 11:05:29 $
+# by Yasuo OHBA(SHL Japan Inc. Technology Dept.)
+#
+# --
+#
+# September 1752
+# S M Tu W Th F S
+# 1 2 14 15 16
+# 17 18 19 20 21 22 23
+# 24 25 26 27 28 29 30
+#
+
+class Date
+ include Comparable
+
+ def initialize(y = 1, m = 1, d = 1)
+ if y.kind_of?(String) && y.size == 8
+ @year = y[0,4].to_i
+ @month = y[4,2].to_i
+ @day = y[6,2].to_i
+ else
+ if m.kind_of?(String)
+ ml = {"jan"=>1, "feb"=>2, "mar"=>3, "apr"=>4, "may"=>5, "jun"=>6, "jul"=>7, "aug"=>8, "sep"=>9, "oct"=>10, "nov"=>11, "dec"=>12}
+ m = ml[m.downcase]
+ if m.nil?
+ raise ArgumentError, "Wrong argument. (month)"
+ end
+ end
+ @year = y.to_i
+ @month = m.to_i
+ @day = d.to_i
+ end
+ _check_date
+ return self
+ end
+
+ def year
+ return @year
+ end
+
+ def month
+ return @month
+ end
+
+ def day
+ return @day
+ end
+
+ def period
+ return Date.period!(@year, @month, @day)
+ end
+
+ def day_of_week
+ dl = Date.daylist(@year)
+ d = Date.jan1!(@year)
+ for m in 1..(@month - 1)
+ d += dl[m]
+ end
+ d += @day - 1
+ if @year == 1752 && @month == 9 && @day >= 14
+ d -= (14 - 3)
+ end
+ return (d % 7)
+ end
+
+ Weektag = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
+ def name_of_week
+ return Weektag[self.day_of_week]
+ end
+
+ def +(o)
+ if o.kind_of?(Integer)
+ d = self.period + o
+ elsif o.kind_of?(Date)
+ d = self.period + o.period
+ else
+ raise TypeError, "Illegal type. (Integer or Date)"
+ end
+ return Date.at(d)
+ end
+
+ def -(o)
+ if o.kind_of?(Integer)
+ d = self.period - o
+ elsif o.kind_of?(Date)
+ d = self.period - o.period
+ else
+ raise TypeError, "Illegal type. (Integer or Date)"
+ end
+ if d <= 0
+ raise ArgumentError, "argument out of range. (self > other)"
+ end
+ return Date.at(d)
+ end
+
+ def <=>(o)
+ if o.kind_of?(Integer)
+ d = o
+ elsif o.kind_of?(Date)
+ d = o.period
+ else
+ raise TypeError, "Illegal type. (Integer or Date)"
+ end
+ return self.period <=> d
+ end
+
+ def eql?(o)
+ self == o
+ end
+
+ def hash
+ return @year ^ @month ^ @day
+ end
+
+ def leapyear?
+ if Date.leapyear(@year) == 1
+ return FALSE
+ else
+ return TRUE
+ end
+ end
+
+ def _check_date
+ m = Date.daylist(@year)
+ if @month < 1 || @month > 12
+ raise ArgumentError, "argument(month) out of range."
+ return nil
+ end
+ if @year == 1752 && @month == 9
+ if @day >= 3 && @day <= 13
+ raise ArgumentError, "argument(1752/09/3-13) out of range."
+ return nil
+ end
+ d = 30
+ else
+ d = m[@month]
+ end
+ if @day < 1 || @day > d
+ raise ArgumentError, "argument(day) out of range."
+ return nil
+ end
+ return self
+ end
+
+ private :_check_date
+end
+
+def Date.at(d)
+ mm = 1
+ yy = (d / 366.0).to_i
+ if yy != 0
+ dd = d - (Date.period!(yy, 1, 1) - 1)
+ else
+ dd = d
+ yy = 1
+ end
+ dl = Date.daylist(yy)
+ while dd > dl[mm]
+ if dd > dl[0]
+ dd -= dl[0]
+ yy += 1
+ dl = Date.daylist(yy)
+ else
+ dd -= dl[mm]
+ mm += 1
+ end
+ end
+ if yy == 1752 && mm == 9 && dd >= 3 && dd <= 19
+ dd += (14 - 3) # 1752/09/03-19 -> 1752/09/14-30
+ end
+
+ return Date.new(yy, mm, dd)
+end
+
+def Date.period!(y, m, d)
+ p = d
+ dl = Date.daylist(y)
+ for mm in 1..(m - 1)
+ p += dl[mm]
+ end
+ p += (y - 1) * 365 + ((y - 1) / 4.0).to_i
+ if (y - 1) > 1752
+ p -= ((y - 1 - 1752) / 100.0).to_i
+ p += ((y - 1 - 1752) / 400.0).to_i
+ p -= (14 - 3)
+ elsif y == 1752 && m == 9 && d >= 14 && d <= 30
+ p -= (14 - 3)
+ end
+ return p
+end
+
+def Date.leapyear(yy)
+ return ((Date.jan1!(yy + 1) + 7 - Date.jan1!(yy)) % 7)
+end
+
+def Date.daylist(yy)
+ case (Date.leapyear(yy))
+ when 1 # non-leapyear
+ return [365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
+ when 2 # leapyear
+ return [366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
+ else # 1752
+ return [355, 31, 29, 31, 30, 31, 30, 31, 31, 19, 31, 30, 31]
+ end
+end
+
+def Date.jan1!(y)
+ d = 4 + y + (y + 3) / 4
+ if y > 1800
+ d -= (y - 1701) / 100
+ d += (y - 1601) / 400
+ end
+ if y > 1752
+ d += 3
+ end
+ return (d % 7)
+end
diff --git a/lib/debug.rb b/lib/debug.rb
new file mode 100644
index 0000000000..432c7b4d19
--- /dev/null
+++ b/lib/debug.rb
@@ -0,0 +1,262 @@
+
+class DEBUGGER__
+ trap("INT") { DEBUGGER__::CONTEXT.interrupt }
+ $DEBUG = TRUE
+ def initialize
+ @break_points = []
+ @stop_next = 1
+ @frames = [nil]
+ @frame_pos = nil
+ @last_file = nil
+ @scripts = {}
+ end
+
+ def interrupt
+ @stop_next = 1
+ end
+
+ def debug_eval(str, binding)
+ begin
+ val = eval(str, binding)
+ val
+ rescue
+ at = caller(0)
+ printf "%s:%s\n", at.shift, $!
+ for i in at
+ break if i =~ /`debug_(eval|command)'$/ #`
+ printf "\tfrom %s\n", i
+ end
+ end
+ end
+
+ def debug_command(file, line, id, binding)
+ if (ENV['EMACS'] == 't')
+ printf "\032\032%s:%d:\n", file, line
+ else
+ printf "%s:%d:%s", file, line, line_at(file, line)
+ end
+ @frames[-1] = binding
+ STDOUT.print "(rdb:-) "
+ STDOUT.flush
+ while input = STDIN.gets
+ input.chop!
+ case input
+ when /^b(reak)?\s+(([^:\n]+:)?.+)/
+ pos = $2
+ if pos.index ":"
+ file, pos = pos.split(":")
+ end
+ file = File.basename(file)
+ if pos =~ /^\d+$/
+ pname = pos
+ pos = Integer(pos)
+ else
+ pname = pos = pos.intern.id2name
+ end
+ printf "Set breakpoint %d at %s:%s\n", @break_points.size, file, pname
+ @break_points.push [file, pos]
+ when /^b(reak)?$/, /^info b(reak)?$/
+ n = 0
+ for f, p in @break_points
+ printf "%d %s:%s\n", n, f, p
+ n += 1
+ end
+ when /^del(ete)?(\s+(\d+))?$/
+ pos = $3
+ unless pos
+ STDOUT.print "clear all breakpoints? (y/n) "
+ STDOUT.flush
+ input = STDIN.gets.chop!
+ if input == "y"
+ for n in @break_points.indexes
+ @break_points[n] = nil
+ end
+ end
+ else
+ pos = Integer(pos)
+ if @break_points[pos]
+ bp = @break_points[pos]
+ printf "Clear breakpoint %d at %s:%s\n", pos, bp[0], bp[1]
+ @break_points[pos] = nil
+ else
+ printf "Breakpoint %d is not defined\n", pos
+ end
+ end
+ when /^c(ont)?$/
+ return
+ when /^s(tep)?\s*(\d+)?$/
+ if $1
+ lev = Integer($1)
+ else
+ lev = 1
+ end
+ @stop_next = lev
+ return
+ when /^n(ext)?\s*(\d+)?$/
+ if $1
+ lev = Integer($1)
+ else
+ lev = 1
+ end
+ @stop_next = lev
+ @no_step = @frames.size
+ return
+ when /^up\s*(\d+)?$/
+ if $1
+ lev = Integer($1)
+ else
+ lev = 1
+ end
+ unless @frame_pos
+ @frame_pos = @frames.size - 1
+ end
+ @frame_pos -= lev
+ if @frame_pos < 0
+ STDOUT.print "at toplevel\n"
+ @frame_pos = 0
+ else
+ binding = @frames[@frame_pos]
+ end
+ when /^down\s*(\d+)??$/
+ if $1
+ lev = Integer($1)
+ else
+ lev = 1
+ end
+ if lev >= @frames.size or @frame_pos and @frame_pos+lev >= @frames.size
+ STDOUT.print "at stack bottom\n"
+ @frame_pos = nil
+ else
+ @frame_pos += lev
+ binding = @frames[@frame_pos]
+ end
+ when /^fin(ish)?$/
+ @finish_pos = @frames.size
+ return
+ when /^q(uit)?$/
+ STDOUT.print "really quit? (y/n) "
+ STDOUT.flush
+ input = STDIN.gets.chop!
+ exit if input == "y"
+ when /^where$/
+ at = caller(4)
+ for i in at
+ printf " %s\n", i
+ end
+ when /^l(ist)?(\s+(.*))?$/
+ if $3
+ b, e = $3.split(/[-,]/)
+ b = Integer(b)-1
+ if e
+ e = Integer(e)-1
+ else
+ e = b + 10
+ end
+ end
+ unless b
+ b = line - 1
+ e = line + 9
+ end
+ p [b,e]
+ line_at(file, line)
+ if lines = @scripts[file] and lines != TRUE
+ n = b+1
+ for l in lines[b..e]
+ printf "%4d %s", n, l
+ n += 1
+ end
+ else
+ printf "no sourcefile available for %s\n", file
+ end
+ when /^p\s+/
+ p debug_eval($', binding)
+ else
+ v = debug_eval(input, binding)
+ p v unless v == nil
+ end
+ STDOUT.print "(rdb:-) "
+ STDOUT.flush
+ end
+ end
+
+ def line_at(file, line)
+ lines = @scripts[file]
+ if lines
+ return "\n" if lines == TRUE
+ line = lines[line-1]
+ return "\n" unless line
+ return line
+ end
+ begin
+ f = open(file)
+ lines = @scripts[file] = f.readlines
+ rescue
+ @scripts[file] = TRUE
+ return "\n"
+ end
+ line = lines[line-1]
+ return "\n" unless line
+ return line
+ end
+
+ def debug_funcname(id)
+ if id == 0
+ "toplevel"
+ else
+ id.id2name
+ end
+ end
+
+ def check_break_points(file, pos, binding, id)
+ file = File.basename(file)
+ if @break_points.include? [file, pos]
+ index = @break_points.index([file, pos])
+ printf "Breakpoint %d, %s at %s:%s\n",
+ index, debug_funcname(id), file, pos
+ return TRUE
+ end
+ return FALSE
+ end
+
+ def trace_func(event, file, line, id, binding)
+ if event == 'line'
+ if @no_step == nil or @no_step >= @frames.size
+ @stop_next -= 1
+ end
+ if @stop_next == 0
+ if [file, line] == @last
+ @stop_next = 1
+ else
+ @no_step = nil
+ debug_command(file, line, id, binding)
+ @last = [file, line]
+ end
+ end
+ if check_break_points(file, line, binding, id)
+ debug_command(file, line, id, binding)
+ end
+ end
+ if event == 'call'
+ @frames.push binding
+ if check_break_points(file, id.id2name, binding, id)
+ debug_command(file, line, id, binding)
+ end
+ end
+ if event == 'class'
+ @frames.push binding
+ end
+ if event == 'return' or event == 'end'
+ if @finish_pos == @frames.size
+ @stop_next = 1
+ end
+ @frames.pop
+ end
+ @last_file = file
+ end
+
+ CONTEXT = new
+end
+
+set_trace_func proc{|event, file, line, id, binding|
+ DEBUGGER__::CONTEXT.trace_func event, file, line, id, binding
+}
diff --git a/lib/e2mmap.rb b/lib/e2mmap.rb
new file mode 100644
index 0000000000..d10657bbad
--- /dev/null
+++ b/lib/e2mmap.rb
@@ -0,0 +1,94 @@
+#
+# e2mmap.rb - for ruby 1.1
+# $Release Version: 1.1$
+# $Revision: 1.4 $
+# $Date: 1997/08/18 07:12:12 $
+# by Keiju ISHITSUKA
+#
+# --
+#
+#
+if VERSION < "1.1"
+ require "e2mmap1_0.rb"
+else
+
+ module Exception2MessageMapper
+ RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/RCS/e2mmap.rb,v 1.4 1997/08/18 07:12:12 keiju Exp keiju $-'
+
+ E2MM = Exception2MessageMapper
+
+ def E2MM.extend_object(cl)
+ super
+ cl.bind(self)
+ end
+
+ # 以前との互換性のために残してある.
+ def E2MM.extend_to(b)
+ c = eval("self", b)
+ c.extend(self)
+ end
+
+# public :fail
+ # alias e2mm_fail fail
+
+ def fail(err = nil, *rest)
+ Exception2MessageMapper.fail Exception2MessageMapper::ErrNotRegisteredException, err.to_s
+ end
+
+ def bind(cl)
+ self.module_eval %q^
+ E2MM_ErrorMSG = {}
+ # fail(err, *rest)
+ # err: 例外
+ # rest: メッセージに渡すパラメータ
+ #
+ def self.fail(err = nil, *rest)
+ $@ = caller(0) if $@.nil?
+ $@.shift
+ if form = E2MM_ErrorMSG[err]
+ $! = err.new(sprintf(form, *rest))
+ # e2mm_fail()
+ raise()
+# elsif self == Exception2MessageMapper
+# fail Exception2MessageMapper::ErrNotRegisteredException, err.to_s
+ else
+# print "super\n"
+ super
+ end
+ end
+ class << self
+ public :fail
+ end
+
+ # def_exception(c, m)
+ # c: exception
+ # m: message_form
+ # 例外cのメッセージをmとする.
+ #
+ def self.def_e2message(c, m)
+ E2MM_ErrorMSG[c] = m
+ end
+
+ # def_exception(c, m)
+ # n: exception_name
+ # m: message_form
+ # s: 例外スーパークラス(デフォルト: Exception)
+ # 例外名``c''をもつ例外を定義し, そのメッセージをmとする.
+ #
+ #def def_exception(n, m)
+ def self.def_exception(n, m, s = Exception)
+ n = n.id2name if n.kind_of?(Fixnum)
+ e = Class.new(s)
+ const_set(n, e)
+ E2MM_ErrorMSG[e] = m
+ # const_get(:E2MM_ErrorMSG)[e] = m
+ end
+ ^
+ end
+
+ extend E2MM
+ def_exception(:ErrNotClassOrModule, "Not Class or Module")
+ def_exception(:ErrNotRegisteredException, "not registerd exception(%s)")
+ end
+end
+
diff --git a/lib/e2mmap1_0.rb b/lib/e2mmap1_0.rb
new file mode 100644
index 0000000000..c5797fd573
--- /dev/null
+++ b/lib/e2mmap1_0.rb
@@ -0,0 +1,71 @@
+#
+# e2mmap.rb -
+# $Release Version: 1.0$
+# $Revision: 1.4 $
+# $Date: 1997/08/18 07:12:12 $
+# by Keiju ISHITSUKA
+#
+# --
+#
+#
+
+module Exception2MessageMapper
+ RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/RCS/e2mmap.rb,v 1.4 1997/08/18 07:12:12 keiju Exp keiju $-'
+ E2MM = Exception2MessageMapper
+
+ def E2MM.extend_to(b)
+ c = eval("self", b)
+ c.extend(self)
+ c.bind(b)
+ end
+
+ def bind(b)
+ eval "
+ @binding = binding
+ E2MM_ErrorMSG = Hash.new
+
+ # fail(err, *rest)
+ # err: 例外
+ # rest: メッセージに渡すパラメータ
+ #
+ def fail!(*rest)
+ super
+ end
+
+ def fail(err, *rest)
+ $! = err.new(sprintf(E2MM_ErrorMSG[err], *rest))
+ super()
+ end
+
+ public :fail
+ # def_exception(c, m)
+ # c: exception
+ # m: message_form
+ # 例外cのメッセージをmとする.
+ #
+ def def_e2message(c, m)
+ E2MM_ErrorMSG[c] = m
+ end
+
+ # def_exception(c, m)
+ # c: exception_name
+ # m: message_form
+ # s: 例外スーパークラス(デフォルト: Exception)
+ # 例外名``c''をもつ例外を定義し, そのメッセージをmとする.
+ #
+ def def_exception(c, m)
+
+ c = c.id2name if c.kind_of?(Fixnum)
+ eval \"class \#{c} < Exception
+ end
+ E2MM_ErrorMSG[\#{c}] = '\#{m}'
+ \", @binding
+ end
+", b
+
+ end
+
+ E2MM.extend_to(binding)
+ def_exception("ErrNotClassOrModule", "Not Class or Module")
+end
+
diff --git a/lib/finalize.rb b/lib/finalize.rb
new file mode 100644
index 0000000000..e934753e19
--- /dev/null
+++ b/lib/finalize.rb
@@ -0,0 +1,205 @@
+#
+# finalize.rb -
+# $Release Version: $
+# $Revision: 1.2 $
+# $Date: 1997/07/25 02:43:00 $
+# by Keiju ISHITSUKA(SHL Japan Inc.)
+#
+# --
+#
+# Usage:
+#
+# add(obj, dependant, method = :finalize, *opt)
+# add_dependency(obj, dependant, method = :finalize, *opt)
+# 依存関係 R_method(obj, dependant) の追加
+#
+# delete(obj_or_id, dependant, method = :finalize)
+# delete_dependency(obj_or_id, dependant, method = :finalize)
+# 依存関係 R_method(obj, dependant) の削除
+# delete_all_dependency(obj_or_id, dependant)
+# 依存関係 R_*(obj, dependant) の削除
+# delete_by_dependant(dependant, method = :finalize)
+# 依存関係 R_method(*, dependant) の削除
+# delete_all_by_dependant(dependant)
+# 依存関係 R_*(*, dependant) の削除
+# delete_all
+# 全ての依存関係の削除.
+#
+# finalize(obj_or_id, dependant, method = :finalize)
+# finalize_dependency(obj_or_id, dependant, method = :finalize)
+# 依存関連 R_method(obj, dependtant) で結ばれるdependantを
+# finalizeする.
+# finalize_all_dependency(obj_or_id, dependant)
+# 依存関連 R_*(obj, dependtant) で結ばれるdependantをfinalizeする.
+# finalize_by_dependant(dependant, method = :finalize)
+# 依存関連 R_method(*, dependtant) で結ばれるdependantをfinalizeする.
+# fainalize_all_by_dependant(dependant)
+# 依存関連 R_*(*, dependtant) で結ばれるdependantをfinalizeする.
+# finalize_all
+# Finalizerに登録される全てのdependantをfinalizeする
+#
+# safe{..}
+# gc時にFinalizerが起動するのを止める.
+#
+#
+
+module Finalizer
+ RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/RCS/finalize.rb,v 1.2 1997/07/25 02:43:00 keiju Exp keiju $-'
+
+ # @dependency: {id => [[dependant, method, *opt], ...], ...}
+
+ # 依存関係 R_method(obj, dependant) の追加
+ def add_dependency(obj, dependant, method = :finalize, *opt)
+ ObjectSpace.call_finalizer(obj)
+ method = method.id unless method.kind_of?(Fixnum)
+ assoc = [dependant, method].concat(opt)
+ if dep = @dependency[obj.id]
+ dep.push assoc
+ else
+ @dependency[obj.id] = [assoc]
+ end
+ end
+ alias add add_dependency
+
+ # 依存関係 R_method(obj, dependant) の削除
+ def delete_dependency(id, dependant, method = :finalize)
+ id = id.id unless id.kind_of?(Fixnum)
+ method = method.id unless method.kind_of?(Fixnum)
+ for assoc in @dependency[id]
+ assoc.delete_if do
+ |d, m, *o|
+ d == dependant && m == method
+ end
+ @dependency.delete(id) if assoc.empty?
+ end
+ end
+ alias delete delete_dependency
+
+ # 依存関係 R_*(obj, dependant) の削除
+ def delete_all_dependency(id, dependant)
+ id = id.id unless id.kind_of?(Fixnum)
+ method = method.id unless method.kind_of?(Fixnum)
+ for assoc in @dependency[id]
+ assoc.delete_if do
+ |d, m, *o|
+ d == dependant
+ end
+ @dependency.delete(id) if assoc.empty?
+ end
+ end
+
+ # 依存関係 R_method(*, dependant) の削除
+ def delete_by_dependant(dependant, method = :finalize)
+ method = method.id unless method.kind_of?(Fixnum)
+ for id in @dependency.keys
+ delete(id, dependant, method)
+ end
+ end
+
+ # 依存関係 R_*(*, dependant) の削除
+ def delete_all_by_dependant(dependant)
+ for id in @dependency.keys
+ delete_all_dependency(id, dependant)
+ end
+ end
+
+ # 依存関連 R_method(obj, dependtant) で結ばれるdependantをfinalizeす
+ # る.
+ def finalize_dependency(id, dependant, method = :finalize)
+ id = id.id unless id.kind_of?(Fixnum)
+ method = method.id unless method.kind_of?(Fixnum)
+ for assocs in @dependency[id]
+ assocs.delete_if do
+ |d, m, *o|
+ d.send(m, *o) if ret = d == dependant && m == method
+ ret
+ end
+ @dependency.delete(id) if assoc.empty?
+ end
+ end
+ alias finalize finalize_dependency
+
+ # 依存関連 R_*(obj, dependtant) で結ばれるdependantをfinalizeする.
+ def finalize_all_dependency(id, dependant)
+ id = id.id unless id.kind_of?(Fixnum)
+ method = method.id unless method.kind_of?(Fixnum)
+ for assoc in @dependency[id]
+ assoc.delete_if do
+ |d, m, *o|
+ d.send(m, *o) if ret = d == dependant
+ end
+ @dependency.delete(id) if assoc.empty?
+ end
+ end
+
+ # 依存関連 R_method(*, dependtant) で結ばれるdependantをfinalizeする.
+ def finalize_by_dependant(dependant, method = :finalize)
+ method = method.id unless method.kind_of?(Fixnum)
+ for id in @dependency.keys
+ finalize(id, dependant, method)
+ end
+ end
+
+ # 依存関連 R_*(*, dependtant) で結ばれるdependantをfinalizeする.
+ def fainalize_all_by_dependant(dependant)
+ for id in @dependency.keys
+ finalize_all_dependency(id, dependant)
+ end
+ end
+
+ # Finalizerに登録されている全てのdependantをfinalizeする
+ def finalize_all
+ for id, assocs in @dependency
+ for dependant, method, *opt in assocs
+ dependant.send(method, id, *opt)
+ end
+ assocs.clear
+ end
+ end
+
+ # finalize_* を安全に呼び出すためのイテレータ
+ def safe
+ old_status = Thread.critical
+ Thread.critical = TRUE
+ ObjectSpace.remove_finalizer(@proc)
+ yield
+ ObjectSpace.add_finalizer(@proc)
+ Thread.critical = old_status
+ end
+
+ # ObjectSpace#add_finalizerへの登録関数
+ def final_of(id)
+ if assocs = @dependency.delete(id)
+ for dependant, method, *opt in assocs
+ dependant.send(method, id, *opt)
+ end
+ end
+ end
+
+ @dependency = Hash.new
+ @proc = proc{|id| final_of(id)}
+ ObjectSpace.add_finalizer(@proc)
+
+ module_function :add
+ module_function :add_dependency
+
+ module_function :delete
+ module_function :delete_dependency
+ module_function :delete_all_dependency
+ module_function :delete_by_dependant
+ module_function :delete_all_by_dependant
+
+ module_function :finalize
+ module_function :finalize_dependency
+ module_function :finalize_all_dependency
+ module_function :finalize_by_dependant
+ module_function :fainalize_all_by_dependant
+ module_function :finalize_all
+
+ module_function :safe
+
+ module_function :final_of
+ private_class_method :final_of
+
+end
+
diff --git a/lib/ftplib.rb b/lib/ftplib.rb
new file mode 100644
index 0000000000..34ee2f8d62
--- /dev/null
+++ b/lib/ftplib.rb
@@ -0,0 +1,617 @@
+### ftplib.rb -*- Mode: ruby; tab-width: 8; -*-
+
+## $Revision: 1.5 $
+## $Date: 1997/09/16 08:03:31 $
+## by maeda shugo <shugo@po.aianet.ne.jp>
+
+### Code:
+
+require "socket"
+require "sync" if defined? Thread
+
+class FTPError < Exception; end
+class FTPReplyError < FTPError; end
+class FTPTempError < FTPError; end
+class FTPPermError < FTPError; end
+class FTPProtoError < FTPError; end
+
+class FTP
+
+ RCS_ID = '$Id: ftplib.rb,v 1.5 1997/09/16 08:03:31 shugo Exp $'
+
+ FTP_PORT = 21
+ CRLF = "\r\n"
+
+ attr :passive, TRUE
+ attr :return_code, TRUE
+ attr :debug_mode, TRUE
+ attr :welcome
+ attr :lastresp
+
+ THREAD_SAFE = defined?(Thread) != FALSE
+
+ if THREAD_SAFE
+ def synchronize(mode = :EX)
+ if @sync
+ @sync.synchronize(mode) do
+ yield
+ end
+ end
+ end
+
+ def sock_synchronize(mode = :EX)
+ if @sock
+ @sock.synchronize(mode) do
+ yield
+ end
+ end
+ end
+ else
+ def synchronize(mode = :EX)
+ yield
+ end
+
+ def sock_synchronize(mode = :EX)
+ yield
+ end
+ end
+ private :sock_synchronize
+
+ def FTP.open(host, user = nil, passwd = nil, acct = nil)
+ new(host, user, passwd, acct)
+ end
+
+ def initialize(host = nil, user = nil,
+ passwd = nil, acct = nil)
+ if THREAD_SAFE
+ @sync = Sync.new
+ end
+ @passive = FALSE
+ @return_code = "\n"
+ @debug_mode = FALSE
+ if host
+ connect(host)
+ if user
+ login(user, passwd, acct)
+ end
+ end
+ end
+
+ def open_socket(host, port)
+ if defined? SOCKSsocket and ENV["SOCKS_SERVER"]
+ @passive = TRUE
+ SOCKSsocket.open(host, port)
+ else
+ TCPsocket.open(host, port)
+ end
+ end
+ private :open_socket
+
+ def connect(host, port = FTP_PORT)
+ if @debug_mode
+ print "connect: ", host, ", ", port, "\n"
+ end
+ synchronize do
+ @sock = open_socket(host, port)
+ if THREAD_SAFE
+ @sock.extend Sync_m
+ end
+ voidresp
+ end
+ end
+
+ def sanitize(s)
+ if s =~ /^PASS /i
+ s[0, 5] + "*" * (s.length - 5)
+ else
+ s
+ end
+ end
+ private :sanitize
+
+ def putline(line)
+ if @debug_mode
+ print "put: ", sanitize(line), "\n"
+ end
+ line = line + CRLF
+ @sock.write(line)
+ end
+ private :putline
+
+ def getline
+ line = @sock.readline # if get EOF, raise EOFError
+ if line[-2, 2] == CRLF
+ line = line[0 .. -3]
+ elsif line[-1] == ?\r or
+ line[-1] == ?\n
+ line = line[0 .. -2]
+ end
+ if @debug_mode
+ print "get: ", sanitize(line), "\n"
+ end
+ line
+ end
+ private :getline
+
+ def getmultiline
+ line = getline
+ buff = line
+ if line[3] == ?-
+ code = line[0, 3]
+ begin
+ line = getline
+ buff << "\n" << line
+ end until line[0, 3] == code and line[3] != ?-
+ end
+ buff << "\n"
+ end
+ private :getmultiline
+
+ def getresp
+ resp = getmultiline
+ @lastresp = resp[0, 3]
+ c = resp[0]
+ case c
+ when ?1, ?2, ?3
+ return resp
+ when ?4
+ raise FTPTempError, resp
+ when ?5
+ raise FTPPermError, resp
+ else
+ raise FTPProtoError, resp
+ end
+ end
+ private :getresp
+
+ def voidresp
+ resp = getresp
+ if resp[0] != ?2
+ raise FTPReplyError, resp
+ end
+ end
+ private :voidresp
+
+ def sendcmd(cmd)
+ synchronize do
+ sock_synchronize do
+ putline(cmd)
+ getresp
+ end
+ end
+ end
+
+ def voidcmd(cmd)
+ synchronize do
+ sock_synchronize do
+ putline(cmd)
+ voidresp
+ end
+ end
+ nil
+ end
+
+ def sendport(host, port)
+ hbytes = host.split(".")
+ pbytes = [port / 256, port % 256]
+ bytes = hbytes + pbytes
+ cmd = "PORT " + bytes.join(",")
+ voidcmd(cmd)
+ end
+ private :sendport
+
+ def makeport
+ sock = TCPserver.open(0)
+ port = sock.addr[1]
+ host = TCPsocket.getaddress(@sock.addr[2])
+ resp = sendport(host, port)
+ sock
+ end
+ private :makeport
+
+ def transfercmd(cmd)
+ if @passive
+ host, port = parse227(sendcmd("PASV"))
+ conn = open_socket(host, port)
+ resp = sendcmd(cmd)
+ if resp[0] != ?1
+ raise FTPReplyError, resp
+ end
+ else
+ sock = makeport
+ resp = sendcmd(cmd)
+ if resp[0] != ?1
+ raise FTPReplyError, resp
+ end
+ conn = sock.accept
+ end
+ conn
+ end
+ private :transfercmd
+
+ def getaddress
+ thishost = Socket.gethostname
+ if not thishost.index(".")
+ thishost = Socket.gethostbyname(thishost)[0]
+ end
+ if ENV.has_key?("LOGNAME")
+ realuser = ENV["LOGNAME"]
+ elsif ENV.has_key?("USER")
+ realuser = ENV["USER"]
+ else
+ realuser = "anonymous"
+ end
+ realuser + "@" + thishost
+ end
+ private :getaddress
+
+ def login(user = "anonymous", passwd = nil, acct = nil)
+ if user == "anonymous" and passwd == nil
+ passwd = getaddress
+ end
+
+ resp = ""
+ synchronize do
+ resp = sendcmd('USER ' + user)
+ if resp[0] == ?3
+ resp = sendcmd('PASS ' + passwd)
+ end
+ if resp[0] == ?3
+ resp = sendcmd('ACCT ' + acct)
+ end
+ end
+ if resp[0] != ?2
+ raise FTPReplyError, resp
+ end
+ @welcome = resp
+ end
+
+ def retrbinary(cmd, blocksize, callback = Proc.new)
+ synchronize do
+ voidcmd("TYPE I")
+ conn = transfercmd(cmd)
+ while TRUE
+ data = conn.read(blocksize)
+ break if data == nil
+ callback.call(data)
+ end
+ conn.close
+ voidresp
+ end
+ end
+
+ def retrlines(cmd, callback = nil)
+ if iterator?
+ callback = Proc.new
+ elsif not callback.is_a?(Proc)
+ callback = Proc.new {|line| print line, "\n"}
+ end
+ synchronize do
+ voidcmd("TYPE A")
+ conn = transfercmd(cmd)
+ while TRUE
+ line = conn.gets
+ break if line == nil
+ if line[-2, 2] == CRLF
+ line = line[0 .. -3]
+ elsif line[-1] == ?\n
+ line = line[0 .. -2]
+ end
+ callback.call(line)
+ end
+ conn.close
+ voidresp
+ end
+ end
+
+ def storbinary(cmd, file, blocksize, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ synchronize do
+ voidcmd("TYPE I")
+ conn = transfercmd(cmd)
+ while TRUE
+ buf = file.read(blocksize)
+ break if buf == nil
+ conn.write(buf)
+ if use_callback
+ callback.call(buf)
+ end
+ end
+ conn.close
+ voidresp
+ end
+ end
+
+ def storlines(cmd, file, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ synchronize do
+ voidcmd("TYPE A")
+ conn = transfercmd(cmd)
+ while TRUE
+ buf = file.gets
+ break if buf == nil
+ if buf[-2, 2] != CRLF
+ if buf[-1] == ?\r or
+ buf[-1] == ?\n
+ buf = buf[0 .. -2]
+ end
+ buf = buf + CRLF
+ end
+ conn.write(buf)
+ if use_callback
+ callback.call(buf)
+ end
+ end
+ conn.close
+ voidresp
+ end
+ end
+
+ def getbinaryfile(remotefile, localfile,
+ blocksize, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ f = open(localfile, "w")
+ begin
+ f.binmode
+ retrbinary("RETR " + remotefile, blocksize) do |data|
+ f.write(data)
+ if use_callback
+ callback.call(data)
+ end
+ end
+ ensure
+ f.close
+ end
+ end
+
+ def gettextfile(remotefile, localfile, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ f = open(localfile, "w")
+ begin
+ retrlines("RETR " + remotefile) do |line|
+ line = line + @return_code
+ f.write(line)
+ if use_callback
+ callback.call(line)
+ end
+ end
+ ensure
+ f.close
+ end
+ end
+
+ def putbinaryfile(localfile, remotefile,
+ blocksize, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ f = open(localfile)
+ begin
+ f.binmode
+ storbinary("STOR " + remotefile, f, blocksize) do |data|
+ if use_callback
+ callback.call(data)
+ end
+ end
+ ensure
+ f.close
+ end
+ end
+
+ def puttextfile(localfile, remotefile, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ f = open(localfile)
+ begin
+ storlines("STOR " + remotefile, f) do |line|
+ if use_callback
+ callback.call(line)
+ end
+ end
+ ensure
+ f.close
+ end
+ end
+
+ def acct(account)
+ cmd = "ACCT " + account
+ voidcmd(cmd)
+ end
+
+ def nlst(dir = nil)
+ cmd = "NLST"
+ if dir
+ cmd = cmd + " " + dir
+ end
+ files = []
+ retrlines(cmd) do |line|
+ files.push(line)
+ end
+ files
+ end
+
+ def list(*args)
+ cmd = "LIST"
+ if iterator?
+ callback = Proc.new
+ elsif args[-1].is_a?(Proc)
+ callback = args.pop
+ else
+ callback = nil
+ end
+ args.each do |arg|
+ cmd = cmd + " " + arg
+ end
+ retrlines(cmd, callback)
+ end
+ alias ls list
+ alias dir list
+
+ def rename(fromname, toname)
+ resp = sendcmd("RNFR " + fromname)
+ if resp[0] != ?3
+ raise FTPReplyError, resp
+ end
+ voidcmd("RNTO " + toname)
+ end
+
+ def delete(filename)
+ resp = sendcmd("DELE " + filename)
+ if resp[0, 3] == "250"
+ return
+ elsif resp[0] == ?5
+ raise FTPPermError, resp
+ else
+ raise FTPReplyError, resp
+ end
+ end
+
+ def chdir(dirname)
+ if dirname == ".."
+ begin
+ voidcmd("CDUP")
+ return
+ rescue FTPPermError
+ if $![0, 3] != "500"
+ raise FTPPermError, $!
+ end
+ end
+ end
+ cmd = "CWD " + dirname
+ voidcmd(cmd)
+ end
+
+ def size(filename)
+ resp = sendcmd("SIZE " + filename)
+ if resp[0, 3] == "213"
+ return Integer(resp[3 .. -1].strip)
+ end
+ end
+
+ def mkdir(dirname)
+ resp = sendcmd("MKD " + dirname)
+ return parse257(resp)
+ end
+
+ def rmdir(dirname)
+ voidcmd("RMD " + dirname)
+ end
+
+ def pwd
+ resp = sendcmd("PWD")
+ return parse257(resp)
+ end
+ alias getdir pwd
+
+ def system
+ resp = sendcmd("SYST")
+ if resp[0, 3] != "215"
+ raise FTPReplyError, resp
+ end
+ return resp[4 .. -1]
+ end
+
+ def abort
+ line = "ABOR" + CRLF
+ resp = ""
+ sock_synchronize do
+ print "put: ABOR\n" if @debug_mode
+ @sock.send(line, Socket::MSG_OOB)
+ resp = getmultiline
+ end
+ unless ["426", "226", "225"].include?(resp[0, 3])
+ raise FTPProtoError, resp
+ end
+ resp
+ end
+
+ def status
+ line = "STAT" + CRLF
+ resp = ""
+ sock_synchronize do
+ print "put: STAT\n" if @debug_mode
+ @sock.send(line, Socket::MSG_OOB)
+ resp = getresp
+ end
+ resp
+ end
+
+ def help(arg = nil)
+ cmd = "HELP"
+ if arg
+ cmd = cmd + " " + arg
+ end
+ sendcmd(cmd)
+ end
+
+ def quit
+ voidcmd("QUIT")
+ end
+
+ def close
+ @sock.close if @sock and not @sock.closed?
+ end
+
+ def closed?
+ @sock == nil or @sock.closed?
+ end
+
+ def parse227(resp)
+ if resp[0, 3] != "227"
+ raise FTPReplyError, resp
+ end
+ left = resp.index("(")
+ right = resp.index(")")
+ if left == nil or right == nil
+ raise FTPProtoError, resp
+ end
+ numbers = resp[left + 1 .. right - 1].split(",")
+ if numbers.length != 6
+ raise FTPProtoError, resp
+ end
+ host = numbers[0, 4].join(".")
+ port = (Integer(numbers[4]) << 8) + Integer(numbers[5])
+ return host, port
+ end
+ private :parse227
+
+ def parse257(resp)
+ if resp[0, 3] != "257"
+ raise FTPReplyError, resp
+ end
+ if resp[3, 2] != ' "'
+ return ""
+ end
+ dirname = ""
+ i = 5
+ n = resp.length
+ while i < n
+ c = resp[i, 1]
+ i = i + 1
+ if c == '"'
+ if i > n or resp[i, 1] != '"'
+ break
+ end
+ i = i + 1
+ end
+ dirname = dirname + c
+ end
+ return dirname
+ end
+ private :parse257
+end
diff --git a/lib/jcode.rb b/lib/jcode.rb
index 5b2289932f..40ab48ddac 100644
--- a/lib/jcode.rb
+++ b/lib/jcode.rb
@@ -1,15 +1,31 @@
# jcode.rb - ruby code to handle japanese (EUC/SJIS) string
+$vsave, $VERBOSE = $VERBOSE, FALSE
class String
printf STDERR, "feel free for some warnings:\n" if $VERBOSE
+ def jlength
+ self.split(//).length
+ end
+
alias original_succ succ
private :original_succ
+ def mbchar?(c)
+ if $KCODE =~ /^s/i
+ c =~ /[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc]/n
+ elsif $KCODE =~ /^e/i
+ c =~ /[\xa1-\xfe][\xa1-\xfe]/n
+ else
+ FALSE
+ end
+ end
+
def succ
if self[-2] && self[-2] & 0x80 != 0
s = self.dup
s[-1] += 1
+ s[-1] += 1 if !mbchar?(s)
return s
else
original_succ
@@ -23,8 +39,11 @@ class String
tail = self[-2..-1]
if tail.length == 2 and tail =~ /^.$/ then
if self[0..-2] == to[0..-2]
+ first = self[-2].chr
for c in self[-1] .. to[-1]
- yield self[0..-2]+c.chr
+ if mbchar?(first+c.chr)
+ yield self[0..-2]+c.chr
+ end
end
end
else
@@ -171,4 +190,18 @@ class String
self.dup.tr_s!(from,to)
end
+ alias original_chop! chop!
+ private :original_chop!
+
+ def chop!
+ if self =~ /(.)$/ and $1.size == 2
+ original_chop!
+ end
+ original_chop!
+ end
+
+ def chop
+ self.dup.chop!
+ end
end
+$VERBOSE = $vsave
diff --git a/lib/mathn.rb b/lib/mathn.rb
index 359cb45769..fdf27f6771 100644
--- a/lib/mathn.rb
+++ b/lib/mathn.rb
@@ -2,7 +2,7 @@
# mathn.rb -
# $Release Version: 0.5 $
# $Revision: 1.1 $
-# $Date: 1996/11/11 04:25:24 $
+# $Date: 1997/07/03 04:43:47 $
# by Keiju ISHITSUKA(SHL Japan Inc.)
#
# --
@@ -12,6 +12,7 @@
require "rational.rb"
require "complex.rb"
+require "matrix.rb"
class Integer
diff --git a/lib/matrix.rb b/lib/matrix.rb
new file mode 100644
index 0000000000..394c66f098
--- /dev/null
+++ b/lib/matrix.rb
@@ -0,0 +1,777 @@
+#!/usr/local/bin/ruby
+#
+# matrix.rb -
+# $Release Version: 1.0$
+# $Revision: 1.0 $
+# $Date: 97/05/23 11:35:28 $
+# Original Version from Smalltalk-80 version
+# on July 23, 1985 at 8:37:17 am
+# by Keiju ISHITSUKA
+#
+# --
+#
+# Matrix[[1,2,3],
+# :
+# [3,4,5]]
+# Matrix[row0,
+# row1,
+# :
+# rown]
+#
+# column: 列
+# row: 行
+#
+
+require "e2mmap.rb"
+
+module ExceptionForMatrix
+ Exception2MessageMapper.extend_to(binding)
+
+ def_e2message(TypeError, "wrong argument type %s (expected %s)")
+ def_e2message(ArgumentError, "Wrong # of arguments(%d for %d)")
+
+ def_exception("ErrDimensionMismatch", "\#{self.type} dimemsion mismatch")
+ def_exception("ErrNotRegular", "Not Regular Matrix")
+ def_exception("ErrOperationNotDefined", "This operation(%s) can\\'t defined")
+end
+
+class Matrix
+ RCS_ID='-$Header: ruby-mode,v 1.2 91/04/20 17:24:57 keiju Locked $-'
+
+ include ExceptionForMatrix
+
+ # instance creations
+ private_class_method :new
+
+ def Matrix.[](*rows)
+ new(:init_rows, rows, FALSE)
+ end
+
+ def Matrix.rows(rows, copy = TRUE)
+ new(:init_rows, rows, copy)
+ end
+
+ def Matrix.columns(columns)
+ rows = (0 .. columns[0].size - 1).collect {
+ |i|
+ (0 .. columns.size - 1).collect {
+ |j|
+ columns[j][i]
+ }
+ }
+ Matrix.rows(rows, FALSE)
+ end
+
+ def Matrix.diagonal(*values)
+ size = values.size
+ rows = (0 .. size - 1).collect {
+ |j|
+ row = Array.new(size).fill(0, 0, size)
+ row[j] = values[j]
+ row
+ }
+ self
+ rows(rows, FALSE)
+ end
+
+ def Matrix.scalar(n, value)
+ Matrix.diagonal(*Array.new(n).fill(value, 0, n))
+ end
+
+ def Matrix.identity(n)
+ Matrix.scalar(n, 1)
+ end
+ class << Matrix
+ alias unit identity
+ alias I identity
+ end
+
+ def Matrix.zero(n)
+ Matrix.scalar(n, 0)
+ end
+
+ def Matrix.row_vector(row)
+ case row
+ when Vector
+ Matrix.rows([row.to_a], FALSE)
+ when Array
+ Matrix.rows([row.dup], FALSE)
+ else
+ Matrix.row([[row]], FALSE)
+ end
+ end
+
+ def Matrix.column_vector(column)
+ case column
+ when Vector
+ Matrix.columns([column.to_a])
+ when Array
+ Matrix.columns([column])
+ else
+ Matrix.columns([[column]])
+ end
+ end
+
+ # initializing
+ def initialize(init_method, *argv)
+ self.send(init_method, *argv)
+ end
+
+ def init_rows(rows, copy)
+ if copy
+ @rows = rows.collect{|row| row.dup}
+ else
+ @rows = rows
+ end
+ self
+ end
+ private :init_rows
+
+ #accessing
+ def [](i, j)
+ @rows[i][j]
+ end
+
+ def row_size
+ @rows.size
+ end
+
+ def column_size
+ @rows[0].size
+ end
+
+ def row(i)
+ if iterator?
+ for e in @rows[i]
+ yield e
+ end
+ else
+ Vector.elements(@rows[i])
+ end
+ end
+
+ def column(j)
+ if iterator?
+ 0.upto(row_size - 1) do
+ |i|
+ yield @rows[i][j]
+ end
+ else
+ col = (0 .. row_size - 1).collect {
+ |i|
+ @rows[i][j]
+ }
+ Vector.elements(col, FALSE)
+ end
+ end
+
+ def collect
+ rows = @rows.collect{|row| row.collect{|e| yield e}}
+ Matrix.rows(rows, FALSE)
+ end
+ alias map collect
+
+ #
+ # param: (from_row, row_size, from_col, size_col)
+ # (from_row..to_row, from_col..to_col)
+ #
+ def minor(*param)
+ case param.size
+ when 2
+ from_row = param[0].first
+ size_row = param[0].size
+ from_col = param[1].first
+ size_col = param[1].size
+ when 4
+ from_row = param[0]
+ size_row = param[1]
+ from_col = param[2]
+ size_col = param[3]
+ else
+ Matrix.fail ArgumentError, param.inspect
+ end
+
+ rows = @rows[from_row, size_row].collect{
+ |row|
+ row[from_col, size_col]
+ }
+ Matrix.rows(rows, FALSE)
+ end
+
+ # TESTING
+ def regular?
+ square? and rank == column_size
+ end
+
+ def singular?
+ not regular?
+ end
+
+ def square?
+ column_size == row_size
+ end
+
+ # ARITHMETIC
+
+ def *(m) #is matrix or vector or number"
+ case(m)
+ when Numeric
+ rows = @rows.collect {
+ |row|
+ row.collect {
+ |e|
+ e * m
+ }
+ }
+ return Matrix.rows(rows, FALSE)
+ when Vector
+ m = Matrix.column_vector(m)
+ r = self * m
+ return r.column(0)
+ when Matrix
+ Matrix.fail ErrDimensionMismatch if column_size != m.row_size
+
+ rows = (0 .. row_size - 1).collect {
+ |i|
+ (0 .. m.column_size - 1).collect {
+ |j|
+ vij = 0
+ 0.upto(column_size - 1) do
+ |k|
+ vij += self[i, k] * m[k, j]
+ end
+ vij
+ }
+ }
+ return Matrix.rows(rows, FALSE)
+ else
+ x, y = m.coerce(self)
+ return x * y
+ end
+ end
+
+ def +(m)
+ case m
+ when Numeric
+ Matrix.fail ErrOperationNotDefined, "+"
+ when Vector
+ m = Matrix.column_vector(m)
+ when Matrix
+ else
+ x, y = m.coerce(self)
+ return x + y
+ end
+
+ Matrix.fail ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
+
+ rows = (0 .. row_size - 1).collect {
+ |i|
+ (0 .. column_size - 1).collect {
+ |j|
+ self[i, j] + m[i, j]
+ }
+ }
+ Matrix.rows(rows, FALSE)
+ end
+
+ def -(m)
+ case m
+ when Numeric
+ Matrix.fail ErrOperationNotDefined, "-"
+ when Vector
+ m = Matrix.column_vector(m)
+ when Matrix
+ else
+ x, y = m.coerce(self)
+ return x - y
+ end
+
+ Matrix.fail ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
+
+ rows = (0 .. row_size - 1).collect {
+ |i|
+ (0 .. column_size - 1).collect {
+ |j|
+ self[i, j] - m[i, j]
+ }
+ }
+ Matrix.rows(rows, FALSE)
+ end
+
+ def inverse
+ Matrix.fail ErrDimensionMismatch unless square?
+ Matrix.I(row_size).inverse_from(self)
+ end
+ alias inv inverse
+
+ def inverse_from(src)
+ size = row_size - 1
+ a = src.to_a
+
+ for k in 0..size
+ if (akk = a[k][k]) == 0
+ i = k
+ begin
+ fail ErrNotRegular if (i += 1) > size
+ end while a[i][k] == 0
+ a[i], a[k] = a[k], a[i]
+ @rows[i], @rows[k] = @rows[k], @rows[i]
+ akk = a[k][k]
+ end
+
+ for i in 0 .. size
+ next if i == k
+ q = a[i][k] / akk
+ a[i][k] = 0
+
+ (k + 1).upto(size) do
+ |j|
+ a[i][j] -= a[k][j] * q
+ end
+ 0.upto(size) do
+ |j|
+ @rows[i][j] -= @rows[k][j] * q
+ end
+ end
+
+ (k + 1).upto(size) do
+ |j|
+ a[k][j] /= akk
+ end
+ 0.upto(size) do
+ |j|
+ @rows[k][j] /= akk
+ end
+ end
+ self
+ end
+ #alias reciprocal inverse
+
+ def ** (other)
+ if other.kind_of?(Integer)
+ x = self
+ if other <= 0
+ x = self.inverse
+ return Matrix.identity(self.column_size) if other == 0
+ other = -other
+ end
+ z = x
+ n = other - 1
+ while n != 0
+ while (div, mod = n.divmod(2)
+ mod == 0)
+ x = x * x
+ n = div
+ end
+ z *= x
+ n -= 1
+ end
+ z
+ elsif other.kind_of?(Float) || defined?(Rational) && other.kind_of?(Rational)
+ fail ErrOperationNotDefined, "**"
+ else
+ fail ErrOperationNotDefined, "**"
+ end
+ end
+
+ # Matrix functions
+
+ def determinant
+ return 0 unless square?
+
+ size = row_size - 1
+ a = to_a
+
+ det = 1
+ k = 0
+ begin
+ if (akk = a[k][k]) == 0
+ i = k
+ begin
+ return 0 if (i += 1) > size
+ end while a[i][k] == 0
+ a[i], a[k] = a[k], a[i]
+ akk = a[k][k]
+ end
+ (k + 1).upto(size) do
+ |i|
+ q = a[i][k] / akk
+ (k + 1).upto(size) do
+ |j|
+ a[i][j] -= a[k][j] * q
+ end
+ end
+ det *= akk
+ end while (k += 1) <= size
+ det
+ end
+ alias det determinant
+
+ def rank
+ if column_size > row_size
+ a = transpose.to_a
+ else
+ a = to_a
+ end
+ rank = 0
+ k = 0
+ begin
+ if (akk = a[k][k]) == 0
+ i = -1
+ nothing = FALSE
+ begin
+ if (i += 1) > column_size - 1
+ nothing = TRUE
+ break
+ end
+ end while a[i][k] == 0
+ next if nothing
+ a[i], a[k] = a[k], a[i]
+ akk = a[k][k]
+ end
+ (k + 1).upto(row_size - 1) do
+ |i|
+ q = a[i][k] / akk
+ (k + 1).upto(column_size - 1) do
+ |j|
+ a[i][j] -= a[k][j] * q
+ end
+ end
+ rank += 1
+ end while (k += 1) <= column_size - 1
+ return rank
+ end
+
+ def trace
+ tr = 0
+ 0.upto(column_size - 1) do
+ |i|
+ tr += @rows[i][i]
+ end
+ tr
+ end
+ alias tr trace
+
+ def transpose
+ Matrix.columns(@rows)
+ end
+ alias t transpose
+
+ # CONVERTING
+
+ def coerce(other)
+ case other
+ when Numeric
+ return Scalar.new(other), self
+ end
+ end
+
+ def row_vectors
+ rows = (0 .. column_size - 1).collect {
+ |i|
+ row(i)
+ }
+ rows
+ end
+
+ def column_vectors
+ columns = (0 .. row_size - 1).collect {
+ |i|
+ column(i)
+ }
+ columns
+ end
+
+ def to_a
+ @rows.collect{|row| row.collect{|e| e}}
+ end
+
+ def to_f
+ collect{|e| e.to_f}
+ end
+
+ def to_i
+ collect{|e| e.to_i}
+ end
+
+ def to_r
+ collect{|e| e.to_r}
+ end
+
+ # PRINTING
+ def to_s
+ "Matrix[" + @rows.collect{
+ |row|
+ "[" + row.collect{|e| e.to_s}.join(", ") + "]"
+ }.join(", ")+"]"
+ end
+
+ def inspect
+ "Matrix"+@rows.inspect
+ end
+
+ # Private CLASS
+
+ class Scalar < Numeric
+ include ExceptionForMatrix
+
+ def initialize(value)
+ @value = value
+ end
+
+ # ARITHMETIC
+ def +(other)
+ case other
+ when Numeric
+ Scalar.new(@value + other)
+ when Vector, Matrix
+ Scalar.fail WrongArgType, other.type, "Numeric or Scalar"
+ when Scalar
+ Scalar.new(@value + other.value)
+ else
+ x, y = other.coerce(self)
+ x + y
+ end
+ end
+
+ def -(other)
+ case other
+ when Numeric
+ Scalar.new(@value - other)
+ when Vector, Matrix
+ Scalar.fail WrongArgType, other.type, "Numeric or Scalar"
+ when Scalar
+ Scalar.new(@value - other.value)
+ else
+ x, y = other.coerce(self)
+ x - y
+ end
+ end
+
+ def *(other)
+ case other
+ when Numeric
+ Scalar.new(@value * other)
+ when Vector, Matrix
+ other.collect{|e| @value * e}
+ else
+ x, y = other.coerce(self)
+ x * y
+ end
+ end
+
+ def / (other)
+ case other
+ when Numeric
+ Scalar.new(@value / other)
+ when Vector
+ Scalar.fail WrongArgType, other.type, "Numeric or Scalar or Matrix"
+ when Matrix
+ self * _M.inverse
+ else
+ x, y = other.coerce(self)
+ x / y
+ end
+ end
+
+ def ** (other)
+ case other
+ when Numeric
+ Scalar.new(@value ** other)
+ when Vector
+ Scalar.fail WrongArgType, other.type, "Numeric or Scalar or Matrix"
+ when Matrix
+ other.powered_by(self)
+ else
+ x, y = other.coerce(self)
+ x ** y
+ end
+ end
+ end
+end
+
+#----------------------------------------------------------------------
+#
+# -
+#
+#----------------------------------------------------------------------
+class Vector
+ include ExceptionForMatrix
+
+
+ #INSTANCE CREATION
+
+ private_class_method :new
+ def Vector.[](*array)
+ new(:init_elements, array, copy = FALSE)
+ end
+
+ def Vector.elements(array, copy = TRUE)
+ new(:init_elements, array, copy)
+ end
+
+ def initialize(method, array, copy)
+ self.send(method, array, copy)
+ end
+
+ def init_elements(array, copy)
+ if copy
+ @elements = array.dup
+ else
+ @elements = array
+ end
+ end
+
+ # ACCSESSING
+
+ def [](i)
+ @elements[i]
+ end
+
+ def size
+ @elements.size
+ end
+
+ # ENUMRATIONS
+ def each2(v)
+ Vector.fail ErrDimensionMismatch if size != v.size
+ 0.upto(size - 1) do
+ |i|
+ yield @elements[i], v[i]
+ end
+ end
+
+ def collect2(v)
+ Vector.fail ErrDimensionMismatch if size != v.size
+ (0 .. size - 1).collect do
+ |i|
+ yield @elements[i], v[i]
+ end
+ end
+
+ # ARITHMETIC
+
+ def *(x) "is matrix or number"
+ case x
+ when Numeric
+ els = @elements.collect{|e| e * x}
+ Vector.elements(els, FALSE)
+ when Matrix
+ self.covector * x
+ else
+ s, x = X.corece(self)
+ s * x
+ end
+ end
+
+ def +(v)
+ case v
+ when Vector
+ Vector.fail ErrDimensionMismatch if size != v.size
+ els = collect2(v) {
+ |v1, v2|
+ v1 + v2
+ }
+ Vector.elements(els, FALSE)
+ when Matrix
+ Matrix.column_vector(self) + v
+ else
+ s, x = v.corece(self)
+ s + x
+ end
+ end
+
+ def -(v)
+ case v
+ when Vector
+ Vector.fail ErrDimensionMismatch if size != v.size
+ els = collect2(v) {
+ |v1, v2|
+ v1 - v2
+ }
+ Vector.elements(els, FALSE)
+ when Matrix
+ Matrix.column_vector(self) - v
+ else
+ s, x = v.corece(self)
+ s - x
+ end
+ end
+
+ # VECTOR FUNCTIONS
+
+ def inner_product(v)
+ Vector.fail ErrDimensionMismatch if size != v.size
+
+ p = 0
+ each2(v) {
+ |v1, v2|
+ p += v1 * v2
+ }
+ p
+ end
+
+ def collect
+ els = @elements.collect {
+ |v|
+ yield v
+ }
+ Vector.elements(els, FALSE)
+ end
+ alias map collect
+
+ def map2(v)
+ els = collect2(v) {
+ |v1, v2|
+ yield v1, v2
+ }
+ Vector.elements(els, FALSE)
+ end
+
+ def r
+ v = 0
+ for e in @elements
+ v += e*e
+ end
+ return v.sqrt
+ end
+
+ # CONVERTING
+ def covector
+ Matrix.row_vector(self)
+ end
+
+ def to_a
+ @elements.dup
+ end
+
+ def to_f
+ collect{|e| e.to_f}
+ end
+
+ def to_i
+ collect{|e| e.to_i}
+ end
+
+ def to_r
+ collect{|e| e.to_r}
+ end
+
+ def coerce(other)
+ case other
+ when Numeric
+ return Scalar.new(other), self
+ end
+ end
+
+ # PRINTING
+
+ def to_s
+ "Vector[" + @elements.join(", ") + "]"
+ end
+
+ def inspect
+ str = "Vector"+@elements.inspect
+ end
+end
+
diff --git a/lib/mutex_m.rb b/lib/mutex_m.rb
new file mode 100644
index 0000000000..823888e72f
--- /dev/null
+++ b/lib/mutex_m.rb
@@ -0,0 +1,183 @@
+#
+# mutex_m.rb -
+# $Release Version: 2.0$
+# $Revision: 1.2 $
+# $Date: 1997/07/25 02:43:21 $
+# Original from mutex.rb
+# by Keiju ISHITSUKA(SHL Japan Inc.)
+#
+# --
+# Usage:
+# require "mutex_m.rb"
+# obj = Object.new
+# obj.extend Mutex_m
+# ...
+# 後はMutexと同じ使い方
+#
+
+require "finalize"
+
+module Mutex_m
+ def Mutex_m.extend_object(obj)
+ if Fixnum === obj or TRUE === obj or FALSE === obj or nil == obj
+ raise TypeError, "Mutex_m can't extend to this class(#{obj.type})"
+ else
+ begin
+ eval "class << obj
+ @mu_locked
+ end"
+ obj.extend(For_primitive_object)
+ rescue TypeError
+ obj.extend(For_general_object)
+ end
+ end
+ end
+
+ def mu_extended
+ unless (defined? locked? and
+ defined? lock and
+ defined? unlock and
+ defined? try_lock and
+ defined? synchronize)
+ eval "class << self
+ alias locked mu_locked?
+ alias lock mu_lock
+ alias unlock mu_unlock
+ alias try_lock mu_try_lock
+ alias synchronize mu_synchronize
+ end"
+ end
+ end
+
+ def mu_synchronize
+ begin
+ mu_lock
+ yield
+ ensure
+ mu_unlock
+ end
+ end
+
+ module For_general_object
+ include Mutex_m
+
+ def For_general_object.extend_object(obj)
+ super
+ obj.mu_extended
+ end
+
+ def mu_extended
+ super
+ @mu_waiting = []
+ @mu_locked = FALSE;
+ end
+
+ def mu_locked?
+ @mu_locked
+ end
+
+ def mu_try_lock
+ result = FALSE
+ Thread.critical = TRUE
+ unless @mu_locked
+ @mu_locked = TRUE
+ result = TRUE
+ end
+ Thread.critical = FALSE
+ result
+ end
+
+ def mu_lock
+ while (Thread.critical = TRUE; @mu_locked)
+ @mu_waiting.push Thread.current
+ Thread.stop
+ end
+ @mu_locked = TRUE
+ Thread.critical = FALSE
+ self
+ end
+
+ def mu_unlock
+ return unless @mu_locked
+ Thread.critical = TRUE
+ wait = @mu_waiting
+ @mu_waiting = []
+ @mu_locked = FALSE
+ Thread.critical = FALSE
+ for w in wait
+ w.run
+ end
+ self
+ end
+
+ end
+
+ module For_primitive_object
+ include Mutex_m
+ Mu_Locked = Hash.new
+
+ def For_primitive_object.extend_object(obj)
+ super
+ obj.mu_extended
+ Finalizer.add(obj, For_primitive_object, :mu_finalize)
+ end
+
+ def For_primitive_object.mu_finalize(id)
+ Thread.critical = TRUE
+ if wait = Mu_Locked.delete(id)
+ # wait == [] ときだけ GCされるので, for w in wait は意味なし.
+ Thread.critical = FALSE
+ for w in wait
+ w.run
+ end
+ else
+ Thread.critical = FALSE
+ end
+ self
+ end
+
+ def mu_locked?
+ Mu_Locked.key?(self.id)
+ end
+
+ def mu_try_lock
+ Thread.critical = TRUE
+ if Mu_Locked.key?(self.id)
+ ret = FALSE
+ else
+ Mu_Locked[self.id] = []
+ Finalizer.set(self, For_primitive_object, :mu_delete_Locked)
+ ret = TRUE
+ end
+ Thread.critical = FALSE
+ ret
+ end
+
+ def mu_lock
+ while (Thread.critical = TRUE; w = Mu_Locked[self.id])
+ w.push Thread.current
+ Thread.stop
+ end
+ Mu_Locked[self.id] = []
+ Finalizer.add(self, For_primitive_object, :mu_delete_Locked)
+ Thread.critical = FALSE
+ self
+ end
+
+ def mu_unlock
+ Thread.critical = TRUE
+ if wait = Mu_Locked.delete(self.id)
+ Finalizer.delete(self, For_primitive_object, :mu_finalize)
+ Thread.critical = FALSE
+ for w in wait
+ w.run
+ end
+ else
+ Thread.critical = FALSE
+ end
+ self
+ end
+ end
+end
+
+
diff --git a/lib/observer.rb b/lib/observer.rb
index 9a753939a2..b802dac633 100644
--- a/lib/observer.rb
+++ b/lib/observer.rb
@@ -30,7 +30,7 @@ module Observable
@observer_state
end
def notify_observers(*arg)
- if @observer_state
+ if @observer_peers and @observer_state
for i in @observer_peers
i.update(*arg)
end
diff --git a/lib/parsedate.rb b/lib/parsedate.rb
index 3f4612ebe5..1c1dda76bc 100644
--- a/lib/parsedate.rb
+++ b/lib/parsedate.rb
@@ -14,26 +14,26 @@ module ParseDate
time = $1
end
if date =~ /19(\d\d)/
- year = $1
+ year = Integer($1)
end
if date.sub!(/\s*(\d+)\s+(#{MONTHPAT})\S*\s+/i, ' ')
- dayofmonth = $1
+ dayofmonth = $1.to_i
monthname = $2
elsif date.sub!(/\s*(#{MONTHPAT})\S*\s+(\d+)\s+/i, ' ')
monthname = $1
- dayofmonth = $2
+ dayofmonth = $2.to_i
elsif date.sub!(/\s*(#{MONTHPAT})\S*\s+(\d+)\D+/i, ' ')
monthname = $1
- dayofmonth = $2
+ dayofmonth = $2.to_i
elsif date.sub!(/\s*(\d\d?)\/(\d\d?)/, ' ')
month = $1
- dayofmonth = $2
+ dayofmonth = $2.to_i
end
if monthname
month = MONTHS[monthname.downcase]
end
if ! year && date =~ /\d\d/
- year = $&
+ year = Integer($&)
end
return year, month, dayofmonth
end
diff --git a/lib/ping.rb b/lib/ping.rb
new file mode 100644
index 0000000000..d742a50f99
--- /dev/null
+++ b/lib/ping.rb
@@ -0,0 +1,55 @@
+#
+# ping.rb -- check a host for upness
+#
+#= SYNOPSIS
+#
+# require 'ping'
+# print "'jimmy' is alive and kicking\n" if Ping.pingecho('jimmy', 10) ;
+#
+#= DESCRIPTION
+#
+# This module contains routines to test for the reachability of remote hosts.
+# Currently the only routine implemented is pingecho().
+#
+# pingecho() uses a TCP echo (I<not> an ICMP one) to determine if the
+# remote host is reachable. This is usually adequate to tell that a remote
+# host is available to rsh(1), ftp(1), or telnet(1) onto.
+#
+#== Parameters
+#
+# : hostname
+#
+# The remote host to check, specified either as a hostname or as an
+# IP address.
+#
+# : timeout
+#
+# The timeout in seconds. If not specified it will default to 5 seconds.
+#
+#= WARNING
+#
+# pingecho() uses user-level thread to implement the timeout, so it may block
+# for long period if named does not respond for some reason.
+#
+#=end
+
+module Ping
+ require "socket"
+ def pingecho(host, timeout=5)
+ begin
+ x = Thread.current
+ y = Thread.start {
+ sleep timeout
+ x.raise RuntimeError if x.status
+ }
+ s = TCPsocket.new(host, "echo")
+ s.close
+ return TRUE
+ rescue
+ return FALSE;
+ ensure
+ Thread.kill y if y.status
+ end
+ end
+ module_function "pingecho"
+end
diff --git a/lib/safe.rb b/lib/safe.rb
deleted file mode 100644
index 7c95555495..0000000000
--- a/lib/safe.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-# this is a safe-mode for ruby, which is still incomplete.
-
-unless defined? SecurityError
- class SecurityError<Exception
- end
-end
-
-module Restricted
-
- printf STDERR, "feel free for some warnings:\n" if $VERBOSE
- module Bastion
- include Restricted
- extend Restricted
- BINDING = binding
- def Bastion.to_s; "main" end
- end
-
- class R_File<File
- NG_FILE_OP = []
- def R_File.open(*args)
- raise SecurityError, "can't use File.open() in safe mode" #'
- end
- end
-
- IO = nil
- File = R_File
- FileTest = nil
- Dir = nil
- ObjectSpace = nil
-
- def eval(string)
- begin
- super(string, Bastion::BINDING)
- rescue
- $@ = caller
- raise
- end
- end
- module_function :eval
-
- DEFAULT_SECURITY_MANAGER = Object.new
-
- def Restricted.set_securuty_manager(sec_man)
- if @sec_man
- raise SecurityError, "cannot change security manager"
- end
- @sec_man = sec_man
- end
-
- def Restricted.securuty_manager
- return @sec_man if @sec_man
- return DEFAULT_SECURITY_MANAGER
- end
-
- for cmd in ["test", "require", "load", "open", "system"]
- eval format("def DEFAULT_SECURITY_MANAGER.%s(*args)
- raise SecurityError, \"can't use %s() in safe mode\"
- end", cmd, cmd) #'
- eval format("def %s(*args)
- Restricted.securuty_manager.%s(*args)
- end", cmd, cmd)
- end
-
- def `(arg) #`
- Restricted.securuty_manager.send(:`, arg) #`)
- end
-
- def DEFAULT_SECURITY_MANAGER.`(arg) #`
- raise SecurityError, "can't use backquote(``) in safe mode"
- end
-end
-
-if $DEBUG
- p eval("File.open('/dev/null')")
- p Restricted.eval("self")
- p Restricted.eval("open('/dev/null')")
- p Restricted.eval("File.open('/dev/null')")
-end
diff --git a/lib/sync.rb b/lib/sync.rb
new file mode 100644
index 0000000000..fd18291ca9
--- /dev/null
+++ b/lib/sync.rb
@@ -0,0 +1,376 @@
+#
+# sync.rb - カウント付2-フェーズロッククラス
+# $Release Version: 0.1$
+# $Revision: 1.3 $
+# $Date: 1997/08/18 07:17:08 $
+# by Keiju ISHITSUKA
+#
+# --
+# Usage:
+# Sync_m, Synchronizer_m
+#
+# Sync_m#sync_mode
+# Sync_m#sync_locked?, locked?
+# Sync_m#sync_shared?, shared?
+# Sync_m#sync_exclusive?, sync_exclusive?
+# Sync_m#sync_try_lock, try_lock
+# Sync_m#sync_lock, lock
+# Sync_m#sync_unlock, unlock
+#
+# Sync, Synchronicer:
+# include Sync_m
+#
+# sync = Sync.new
+# Sync#mode
+# Sync#locked?
+# Sync#shared?
+# Sync#exclusive?
+# Sync#try_lock(mode) -- mode = :EX, :SH, :UN
+# Sync#lock(mode) -- mode = :EX, :SH, :UN
+# Sync#unlock
+# Sync#synchronize(mode) {...}
+#
+#
+
+unless defined? Thread
+ fail "Thread not available for this ruby interpreter"
+end
+
+require "finalize.rb"
+
+module Sync_m
+ RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/RCS/sync.rb,v 1.3 1997/08/18 07:17:08 keiju Exp keiju $-'
+
+ UN = :UN
+ SH = :SH
+ EX = :EX
+
+ class Err < Exception
+ def Err.Fail(*opt)
+ fail self, sprintf(self::Message, *opt)
+ end
+
+ class UnknownLocker < Err
+ Message = "Thread(%s) not locked."
+ def UnknownLocker.Fail(th)
+ super(th.inspect)
+ end
+ end
+
+ class LockModeFailer < Err
+ Message = "Unknown lock mode(%s)"
+ def LockModeFailer.Fail(mode)
+ if mode.id2name
+ mode = id2name
+ end
+ super(mode)
+ end
+ end
+ end
+
+ def Sync_m.extend_object(obj)
+ if Fixnum === obj or TRUE === obj or FALSE === obj or nil == obj
+ raise TypeError, "Sync_m can't extend to this class(#{obj.type})"
+ else
+ begin
+ eval "class << obj
+ @sync_locked
+ end"
+ obj.extend(For_primitive_object)
+ rescue TypeError
+ obj.extend(For_general_object)
+ end
+ end
+ end
+
+ def sync_extended
+ unless (defined? locked? and
+ defined? shared? and
+ defined? exclusive? and
+ defined? lock and
+ defined? unlock and
+ defined? try_lock and
+ defined? synchronize)
+ eval "class << self
+ alias locked? sync_locked?
+ alias shared? sync_shared?
+ alias excluive? sync_exclusive?
+ alias lock sync_lock
+ alias unlock sync_unlock
+ alias try_lock sync_try_lock
+ alias synchronize sync_synchronize
+ end"
+ end
+ end
+
+ def sync_locked?
+ sync_mode != UN
+ end
+
+ def sync_shared?
+ sync_mode == SH
+ end
+
+ def sync_exclusive?
+ sync_mode == EX
+ end
+
+ def sync_try_lock(mode = EX)
+ return unlock if sync_mode == UN
+
+ Thread.critical = TRUE
+ ret = sync_try_lock_sub(sync_mode)
+ Thread.critical = FALSE
+ ret
+ end
+
+ def sync_lock(m = EX)
+ return unlock if m == UN
+
+ until (Thread.critical = TRUE; sync_try_lock_sub(m))
+ if sync_sh_locker[Thread.current]
+ sync_upgrade_waiting.push [Thread.current, sync_sh_locker[Thread.current]]
+ sync_sh_locker.delete(Thread.current)
+ else
+ sync_waiting.push Thread.current
+ end
+ Thread.stop
+ end
+ Thread.critical = FALSE
+ self
+ end
+
+ def sync_unlock(m = EX)
+ Thread.critical = TRUE
+ if sync_mode == UN
+ Thread.critical = FALSE
+ Err::UnknownLocker.Fail(Thread.current)
+ end
+
+ m = sync_mode if m == EX and sync_mode == SH
+
+ runnable = FALSE
+ case m
+ when UN
+ Thread.critical = FALSE
+ Err::UnknownLocker.Fail(Thread.current)
+
+ when EX
+ if sync_ex_locker == Thread.current
+ if (self.sync_ex_count = sync_ex_count - 1) == 0
+ self.sync_ex_locker = nil
+ if sync_sh_locker.include?(Thread.current)
+ self.sync_mode = SH
+ else
+ self.sync_mode = UN
+ end
+ runnable = TRUE
+ end
+ else
+ Err::UnknownLocker.Fail(Thread.current)
+ end
+
+ when SH
+ if (count = sync_sh_locker[Thread.current]).nil?
+ Err::UnknownLocker.Fail(Thread.current)
+ else
+ if (sync_sh_locker[Thread.current] = count - 1) == 0
+ sync_sh_locker.delete(Thread.current)
+ if sync_sh_locker.empty? and sync_ex_count == 0
+ self.sync_mode = UN
+ runnable = TRUE
+ end
+ end
+ end
+ end
+
+ if runnable
+ if sync_upgrade_waiting.size > 0
+ for k, v in sync_upgrade_waiting
+ sync_sh_locker[k] = v
+ end
+ wait = sync_upgrade_waiting
+ self.sync_upgrade_waiting = []
+ Thread.critical = FALSE
+
+ for w, v in wait
+ w.run
+ end
+ else
+ wait = sync_waiting
+ self.sync_waiting = []
+ Thread.critical = FALSE
+ for w in wait
+ w.run
+ end
+ end
+ end
+
+ Thread.critical = FALSE
+ self
+ end
+
+ def sync_try_lock_sub(m)
+ case m
+ when SH
+ case sync_mode
+ when UN
+ self.sync_mode = m
+ sync_sh_locker[Thread.current] = 1
+ ret = TRUE
+ when SH
+ count = 0 unless count = sync_sh_locker[Thread.current]
+ sync_sh_locker[Thread.current] = count + 1
+ ret = TRUE
+ when EX
+ # 既に, モードがEXである時は, 必ずEXロックとなる.
+ if sync_ex_locker == Thread.current
+ self.sync_ex_count = sync_ex_count + 1
+ ret = TRUE
+ else
+ ret = FALSE
+ end
+ end
+ when EX
+ if sync_mode == UN or
+ sync_mode == SH && sync_sh_locker.size == 1 && sync_sh_locker.include?(Thread.current)
+ self.sync_mode = m
+ self.sync_ex_locker = Thread.current
+ self.sync_ex_count = 1
+ ret = TRUE
+
+ elsif sync_mode == EX && sync_ex_locker == Thread.current
+ self.sync_ex_count = sync_ex_count + 1
+ ret = TRUE
+ else
+ ret = FALSE
+ end
+ else
+ Thread.critical = FALSE
+ Err::LockModeFailer.Fail mode
+ end
+ return ret
+ end
+ private :sync_try_lock_sub
+
+ def sync_synchronize(mode = EX)
+ begin
+ sync_lock(mode)
+ yield
+ ensure
+ sync_unlock
+ end
+ end
+
+ module For_primitive_object
+ include Sync_m
+
+ LockState = Struct.new("LockState",
+ :mode,
+ :waiting,
+ :upgrade_waiting,
+ :sh_locker,
+ :ex_locker,
+ :ex_count)
+
+ Sync_Locked = Hash.new
+
+ def For_primitive_object.extend_object(obj)
+ super
+ obj.sync_extended
+ Finalizer.add(obj, For_primitive_object, :sync_finalize)
+ end
+
+ def sync_extended
+ super
+ Sync_Locked[id] = LockState.new(UN, [], [], Hash.new, nil, 0 )
+ end
+
+ def sync_finalize
+ wait = Sync_Locked.delete(id)
+ # waiting == [] ときだけ GCされるので, 待ち行列の解放は意味がない.
+ end
+
+ def sync_mode
+ Sync_Locked[id].mode
+ end
+ def sync_mode=(value)
+ Sync_Locked[id].mode = value
+ end
+
+ def sync_waiting
+ Sync_Locked[id].waiting
+ end
+ def sync_waiting=(v)
+ Sync_Locked[id].waiting = v
+ end
+
+ def sync_upgrade_waiting
+ Sync_Locked[id].upgrade_waiting
+ end
+ def sync_upgrade_waiting=(v)
+ Sync_Locked[id].upgrade_waiting = v
+ end
+
+ def sync_sh_locker
+ Sync_Locked[id].sh_locker
+ end
+ def sync_sh_locker=(v)
+ Sync_Locked[id].sh_locker = v
+ end
+
+ def sync_ex_locker
+ Sync_Locked[id].ex_locker
+ end
+ def sync_ex_locker=(value)
+ Sync_Locked[id].ex_locker = value
+ end
+
+ def sync_ex_count
+ Sync_Locked[id].ex_count
+ end
+ def sync_ex_count=(value)
+ Sync_Locked[id].ex_count = value
+ end
+
+ end
+
+ module For_general_object
+ include Sync_m
+
+ def For_general_object.extend_object(obj)
+ super
+ obj.sync_extended
+ end
+
+ def sync_extended
+ super
+ @sync_mode = UN
+ @sync_waiting = []
+ @sync_upgrade_waiting = []
+ @sync_sh_locker = Hash.new
+ @sync_ex_locker = nil
+ @sync_ex_count = 0
+ end
+
+ attr :sync_mode, TRUE
+
+ attr :sync_waiting, TRUE
+ attr :sync_upgrade_waiting, TRUE
+ attr :sync_sh_locker, TRUE
+ attr :sync_ex_locker, TRUE
+ attr :sync_ex_count, TRUE
+
+ end
+end
+Synchronizer_m = Sync_m
+
+class Sync
+ include Sync_m::For_general_object
+
+ def initialize
+ sync_extended
+ end
+
+end
+Synchronizer = Sync
diff --git a/lib/thread.rb b/lib/thread.rb
index c3347b60b4..30f77ddbeb 100644
--- a/lib/thread.rb
+++ b/lib/thread.rb
@@ -24,27 +24,37 @@ class Mutex
end
def try_lock
- Thread.exclusive do
- if not @locked
- @locked=TRUE
- return TRUE
- end
+ result = FALSE
+ Thread.critical = TRUE
+ unless @locked
+ @locked = TRUE
+ result = TRUE
end
- FALSE
+ Thread.critical = FALSE
+ result
end
def lock
- while not try_lock
+ while (Thread.critical = TRUE; @locked)
@waiting.push Thread.current
Thread.stop
end
+ @locked = TRUE
+ Thread.critical = FALSE
+ self
end
def unlock
+ return unless @locked
+ Thread.critical = TRUE
+ wait = @waiting
+ @waiting = []
@locked = FALSE
- if w = @waiting.shift
+ Thread.critical = FALSE
+ for w in wait
w.run
end
+ self
end
def synchronize
@@ -57,37 +67,6 @@ class Mutex
end
end
-class SharedMutex<Mutex
- def initialize
- @locking = nil
- @num_locks = 0;
- super
- end
- def try_lock
- if @locking == Thread.current
- @num_locks += 1
- return TRUE
- end
- if super
- @num_locks = 1
- @locking = Thread.current
- TRUE
- else
- FALSE
- end
- end
- def unlock
- unless @locking == Thread.current
- raise ThreadError, "cannot release shared mutex"
- end
- @num_locks -= 1
- if @num_locks == 0
- @locking = nil
- super
- end
- end
-end
-
class Queue
def initialize
@que = []
@@ -95,19 +74,30 @@ class Queue
end
def push(obj)
+ Thread.critical = TRUE
@que.push obj
- if t = @waiting.shift
- t.run
- end
+ t = @waiting.shift
+ Thread.critical = FALSE
+ t.run if t
end
def pop non_block=FALSE
- if @que.length == 0
- raise ThreadError, "queue empty" if non_block
- @waiting.push Thread.current
- Thread.stop
+ item = nil
+ until item
+ Thread.critical = TRUE
+ if @que.length == 0
+ if non_block
+ Thread.critical = FALSE
+ raise ThreadError, "queue empty"
+ end
+ @waiting.push Thread.current
+ Thread.stop
+ else
+ item = @que.shift
+ end
end
- @que.shift
+ Thread.critical = FALSE
+ item
end
def empty?
@@ -118,36 +108,3 @@ class Queue
@que.length
end
end
-
-class Condition
- def initialize
- @waiting = []
- end
-
- def wait(mut)
- Thread.exclusive do
- mut.unlock
- @waiting.push Thread.current
- end
- Thread.sleep
- mut.lock
- end
-
- def signal
- th = nil
- Thread.exclusive do
- th = @waiting.pop
- end
- th.run
- end
-
- def broadcast
- w = @waiting
- Thread.exclusive do
- th = []
- end
- for th in w
- th.run
- end
- end
-end
diff --git a/lib/thwait.rb b/lib/thwait.rb
new file mode 100644
index 0000000000..c638335f5d
--- /dev/null
+++ b/lib/thwait.rb
@@ -0,0 +1,128 @@
+#
+# thwait.rb -
+# $Release Version: $
+# $Revision: 1.1 $
+# $Date: 1997/08/18 03:13:14 $
+# by Keiju ISHITSUKA(Nippon Rational Inc.)
+#
+# --
+#
+#
+#
+
+require "thread.rb"
+require "e2mmap.rb"
+
+class ThreadsWait
+ RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/RCS/thwait.rb,v 1.1 1997/08/18 03:13:14 keiju Exp keiju $-'
+
+ Exception2MessageMapper.extend_to(binding)
+ def_exception("ErrWaitThreadsNothing", "Wait threads nothing.")
+ def_exception("FinshedThreadsNothing", "finished thread nothing.")
+
+ # class mthods
+ # all_waits
+
+ #
+ # 指定したスレッドが全て終了するまで待つ. イテレータとして呼ばれると
+ # 指定したスレッドが終了するとイテレータを呼び出す.
+ #
+ def ThreadsWait.all_waits(*threads)
+ tw = ThreadsWait.new(th1, th2, th3, th4, th5)
+ if iterator?
+ tw.all_waits do
+ |th|
+ yield th
+ end
+ else
+ tw.all_waits
+ end
+ end
+
+ # initialize and terminating:
+ # initialize
+
+ #
+ # 初期化. 待つスレッドの指定ができる.
+ #
+ def initialize(*threads)
+ @threads = []
+ @wait_queue = Queue.new
+ join_nowait(*threads) unless threads.empty?
+ end
+
+ # accessing
+ # threads
+
+ # 待ちスレッドの一覧を返す.
+ attr :threads
+
+ # testing
+ # empty?
+ # finished?
+ #
+
+ #
+ # 待ちスレッドが存在するかどうかを返す.
+ def empty?
+ @threads.empty?
+ end
+
+ #
+ # すでに終了したスレッドがあるかどうか返す
+ def finished?
+ !@wait_queue.empty?
+ end
+
+ # main process:
+ # join
+ # join_nowait
+ # next_wait
+ # all_wait
+
+ #
+ # 待っているスレッドを追加し待ちにはいる.
+ #
+ def join(*threads)
+ join_nowait(*threads)
+ next_wait
+ end
+
+ #
+ # 待っているスレッドを追加する. 待ちには入らない.
+ #
+ def join_nowait(*threads)
+ @threads.concat threads
+ for th in threads
+ Thread.start do
+ th = Thread.join(th)
+ @wait_queue.push th
+ end
+ end
+ end
+
+ #
+ # 次の待ちにはいる.
+ # 待つべきスレッドがなければ, 例外ErrWaitThreadsNothing を返す.
+ # nonnlockが真の時には, nonblockingで調べる. 存在しなければ, 例外
+ # FinishedThreadNothingを返す.
+ #
+ def next_wait(nonblock = nil)
+ Threads.Wait.fail ErrWaitThreadsNothing if @threads.empty?
+
+ th = @wait_queue.pop(nonblock)
+ @threads.delete th
+ th
+ end
+
+ #
+ # 全てのスレッドが終了するまで待つ. イテレータとして呼ばれた時は, ス
+ # レッドが終了する度に, イテレータを呼び出す.
+ #
+ def all_waits
+ until @threads.empty?
+ th = next_wait
+ yield th if iterator?
+ end
+ end
+end
diff --git a/lib/tk.rb b/lib/tk.rb
index 237408a77a..48a3940fcc 100644
--- a/lib/tk.rb
+++ b/lib/tk.rb
@@ -345,7 +345,7 @@ class TkObject<TkKernel
def configure(slot, value)
if value == FALSE
value = "0"
- elsif value.type == Proc
+ elsif value.kind_of? Proc
value = install_cmd(value)
end
tk_call path, 'configure', "-#{slot}", value
@@ -358,6 +358,61 @@ class TkObject<TkKernel
def bind(context, cmd=Proc.new, args=nil)
_bind path, context, cmd, args
end
+
+ def tk_trace_variable(v)
+ unless v.kind_of?(TkVariable)
+ fail ArgumentError, format("requires TkVariable given %s", v.type)
+ end
+ v
+ end
+ private :tk_trace_variable
+
+ def destroy
+ tk_call 'trace', 'vdelete', @tk_vn, 'w', @var_id if @var_id
+ end
+end
+
+
+class TkVariable
+ include Tk
+ $tk_variable_id = "v00000"
+ def initialize(val="")
+ @id = $tk_variable_id
+ $tk_variable_id = $tk_variable_id.succ
+ tk_call(format('global %s; set %s', @id, @id), val)
+ end
+
+ def id
+ @id
+ end
+
+ def value
+ tk_call(format('global %s; set', @id), @id)
+ end
+
+ def value=(val)
+ tk_call(format('global %s; set %s', @id, @id), val)
+ end
+
+ def to_i
+ Integer(number(value))
+ end
+
+ def to_f
+ Float(number(value))
+ end
+
+ def to_s
+ String(string(value))
+ end
+
+ def inspect
+ format "<TkVariable: %s>", @id
+ end
+
+ def to_a
+ list(value)
+ end
end
class TkWindow<TkObject
@@ -391,6 +446,36 @@ class TkWindow<TkObject
self
end
+ def place(keys = nil)
+ tk_call 'place', epath, *hash_kv(keys)
+ self
+ end
+
+ def unplace(keys = nil)
+ tk_call 'place', 'forget', epath, *hash_kv(keys)
+ self
+ end
+ alias place_forget unplace
+
+ def place_config(keys)
+ tk_call "place", 'configure', epath, *hash_kv(keys)
+ end
+
+ def place_info()
+ ilist = list(tk_call('place', 'info', epath))
+ info = {}
+ while key = ilist.shift
+ info[key[1,-1]] = ilist.shift
+ end
+ return info
+ end
+
+ def place_slaves()
+ list(tk_call('place', 'slaves', epath)).collect { |w|
+ window(w)
+ }
+ end
+
def focus
tk_call 'focus', path
self
@@ -426,7 +511,7 @@ class TkWindow<TkObject
self
end
- def command(cmd)
+ def command(cmd=Proc.new)
configure_cmd 'command', cmd
end
@@ -443,6 +528,7 @@ class TkWindow<TkObject
end
end
$tk_window_list[path] = nil
+ super
end
end
@@ -486,14 +572,7 @@ class TkLabel<TkWindow
tk_call 'label', @path
end
def textvariable(v)
- v = v.id2name unless v.kind_of? String
- vn = @path + v
- vset = format("global {%s}; set {%s} %%s", vn, vn)
- tk_write vset, eval(v).inspect
- trace_var v, proc{|val|
- tk_write vset, val.inspect
- }
- configure 'textvariable', vn
+ configure 'textvariable', tk_trace_variable(v)
end
end
@@ -520,26 +599,7 @@ class TkRadioButton<TkButton
tk_send 'select'
end
def variable(v)
- v = v.id2name unless v.kind_of? String
- if v =~ /^\$/
- v = $'
- else
- fail ArgumentError, "variable must be global(%s)", v
- end
- vn = 'btns_selected_' + v
- trace_var v, proc{|val|
- tk_write 'global %s; set %s %s', vn, val
- }
- @var_id = install_cmd(proc{|name1,|
- val = tk_call(format('global %s; set', name1), name1)
- eval(format("%s = '%s'", v.id2name, val))
- })
- tk_call 'trace', 'variable', vn, 'w', @var_id
- configure 'variable', vn
- end
- def destroy
- tk_call 'trace vdelete', vn, 'w', @var_id
- super
+ configure 'variable', tk_trace_variable(v)
end
end
@@ -678,7 +738,7 @@ class TkMenu<TkWindow
tk_send 'activate', index
end
def add(type, keys=nil)
- tk_send 'add', type, *kv_hash(keys)
+ tk_send 'add', type, *hash_kv(keys)
end
def index(index)
tk_send 'index', index
@@ -686,8 +746,8 @@ class TkMenu<TkWindow
def invoke
tk_send 'invoke'
end
- def insert(index, type, keys=nil)
- tk_send 'add', index, type, *kv_hash(keys)
+ def insert(index, type, *keys)
+ tk_send 'add', index, type, *hash_kv(keys)
end
def post(x, y)
tk_send 'post', x, y
@@ -695,7 +755,7 @@ class TkMenu<TkWindow
def postcascade(index)
tk_send 'postcascade', index
end
- def postcommand(cmd)
+ def postcommand(cmd=Proc.new)
configure_cmd 'postcommand', cmd
end
def menutype(index)
diff --git a/lib/tkcanvas.rb b/lib/tkcanvas.rb
index b0ae8b1daa..46acd8c9d7 100644
--- a/lib/tkcanvas.rb
+++ b/lib/tkcanvas.rb
@@ -110,11 +110,11 @@ class TkCanvas<TkWindow
def select(*args)
tk_send 'select', *args
end
- def xview(index)
- tk_send 'xview', index
+ def xview(*index)
+ tk_send 'xview', *index
end
- def yview(index)
- tk_send 'yview', index
+ def yview(*index)
+ tk_send 'yview', *index
end
end
@@ -125,12 +125,12 @@ class TkcItem<TkObject
end
@c = parent
@path = parent.path
- if args[-1].type == Hash
+ if args[-1].kind_of? Hash
keys = args.pop
end
@id = create_self(*args)
if keys
- tk_call @path, 'itemconfigure', *hash_kv(keys)
+ tk_call @path, 'itemconfigure', @id, *hash_kv(keys)
end
end
def create_self(*args) end
@@ -226,6 +226,11 @@ class TkcPolygon<TkcItem
tk_call(@path, 'create', 'polygon', *args)
end
end
+class TkcRectangle<TkcItem
+ def create_self(*args)
+ tk_call(@path, 'create', 'rectangle', *args)
+ end
+end
class TkcText<TkcItem
def create_self(*args)
tk_call(@path, 'create', 'text', *args)
@@ -272,7 +277,7 @@ class TkImage<TkObject
def initialize(keys=nil)
@path = $tk_image_id
$tk_image_id = $tk_image_id.succ
- tk_call 'image', @type, @path, *hash_kv(keys)
+ tk_call 'image', 'create', @type, @path, *hash_kv(keys)
end
def height
@@ -302,7 +307,7 @@ end
class TkPhotoImage<TkImage
def initialize(*args)
- @type = 'bitmap'
+ @type = 'photo'
super
end
diff --git a/lib/tkclass.rb b/lib/tkclass.rb
index 10ecc80b20..17f57f581d 100644
--- a/lib/tkclass.rb
+++ b/lib/tkclass.rb
@@ -25,11 +25,13 @@ Bitmap = TkcBitmap
Line = TkcLine
Oval = TkcOval
Polygon = TkcPolygon
+Rectangle = TkcRectangle
TextItem = TkcText
WindowItem = TkcWindow
Selection = TkSelection
Winfo = TkWinfo
Pack = TkPack
+Variable = TkVariable
def Mainloop
Tk.mainloop
diff --git a/lib/tkcore.rb b/lib/tkcore.rb
index 018e140ef0..9fd2c88efc 100644
--- a/lib/tkcore.rb
+++ b/lib/tkcore.rb
@@ -22,7 +22,7 @@ module Tk
break if wish_path
end
}
- fail 'can\'t find wish' if not wish_path
+ fail 'can\'t find wish' if not wish_path #'
def Tk.tk_exit
if not PORT.closed?
@@ -31,7 +31,8 @@ module Tk
end
end
- PORT = open(format("|%s -n %s", wish_path, File.basename($0)), "w+");
+# PORT = open(format("|%s -n %s", wish_path, File.basename($0)), "w+");
+ PORT = open(format("|%s", wish_path), "w+");
trap "EXIT", proc{Tk.tk_exit}
trap "PIPE", ""
@@ -46,8 +47,8 @@ proc rb_out args {
puts [format %%s $args]
flush stdout
}
-proc rb_ans args {
- if [catch "$args" var] {puts "!$var"} {puts "=$var@@"}
+proc rb_ans arg {
+ if [catch $arg var] {puts "!$var"} {puts "=$var@@"}
flush stdout
}
proc tkerror args { exit }
@@ -85,12 +86,11 @@ after 120000 keepalive'
}
def error_at
- n = 1
- while c = caller(n)
- break if c !~ /tk\.rb:/
- n+=1
+ frames = caller(1)
+ frames.delete_if do |c|
+ c =~ %r!/tk(|core|thcore|canvas|text|entry|scrollbox)\.rb:\d+!
end
- c
+ frames
end
def tk_tcl2ruby(val)
@@ -197,17 +197,21 @@ after 120000 keepalive'
s = "1"
elsif s.kind_of?(TkObject)
s = s.path
+ elsif s.kind_of?(TkVariable)
+ s = s.id
else
s = s.to_s
- s.gsub!(/[{}]/, '\\\\\0')
+ s.gsub!(/["\\\$\[\]]/, '\\\\\0') #"
+ s.gsub!(/\{/, '\\\\173')
+ s.gsub!(/\}/, '\\\\175')
end
- "{#{s}}"
+ "\"#{s}\""
end
}
str += " "
str += args.join(" ")
print str, "\n" if $DEBUG
- tk_write 'rb_ans %s', str
+ tk_write 'rb_ans {%s}', str
while PORT.gets
print $_ if $DEBUG
$_.chop!
@@ -229,10 +233,12 @@ after 120000 keepalive'
$@ = error_at
msg = $'
if msg =~ /unknown option "-(.*)"/
- fail NameError, format("undefined method `%s' for %s(%s)", $1, self, self.type) #`'
+ $! = NameError.new(format("undefined method `%s' for %s(%s)",
+ $1, self, self.type)) #`'
else
- fail format("%s - %s", self.type, msg)
+ $! = RuntimeError.new(format("%s - %s", self.type, msg))
end
+ fail
end
$tk_event_queue.push $_
end
@@ -250,7 +256,7 @@ after 120000 keepalive'
if keys
for k, v in keys
conf.push("-#{k}")
- v = install_cmd(v) if v.type == Proc
+ v = install_cmd(v) if v.kind_of? Proc
conf.push(v)
end
end
@@ -415,10 +421,10 @@ after 120000 keepalive'
module_function :after, :update, :dispatch, :mainloop, :root, :bell
module Scrollable
- def xscrollcommand(cmd)
+ def xscrollcommand(cmd=Proc.new)
configure_cmd 'xscrollcommand', cmd
end
- def yscrollcommand(cmd)
+ def yscrollcommand(cmd=Proc.new)
configure_cmd 'yscrollcommand', cmd
end
end
diff --git a/lib/tkentry.rb b/lib/tkentry.rb
index 9a03c34058..7c13e3bdb1 100644
--- a/lib/tkentry.rb
+++ b/lib/tkentry.rb
@@ -14,11 +14,7 @@ class TkEntry<TkLabel
end
def delete(s, e=None)
- if e
- tk_send 'delete', s
- else
- tk_send 'delete', s, e
- end
+ tk_send 'delete', s, e
end
def cursor
@@ -28,13 +24,10 @@ class TkEntry<TkLabel
tk_send 'icursor', index
end
def index(index)
- tk_send 'index', index
+ number(tk_send('index', index))
end
- def insert(text, pos=None)
- if pos
- tk_send 'icursor', pos
- end
- tk_send 'insert', 'insert', text
+ def insert(pos,text)
+ tk_send 'insert', pos, text
end
def mark(pos)
tk_send 'scan', 'mark', pos
diff --git a/lib/tkscrollbox.rb b/lib/tkscrollbox.rb
index b8dbe9b236..76844ed90a 100644
--- a/lib/tkscrollbox.rb
+++ b/lib/tkscrollbox.rb
@@ -18,8 +18,8 @@ class TkScrollbox<TkListbox
scroll.configure 'command', list.path+" yview"
scroll.pack 'side'=>'right','fill'=>'y'
- delegate('DEFALUT', list)
- delegate('foreground', list, scroll)
+ delegate('DEFAULT', list)
+ delegate('foreground', list)
delegate('background', list, scroll)
delegate('borderwidth', @frame)
delegate('relief', @frame)
diff --git a/lib/tktext.rb b/lib/tktext.rb
index 55e396c497..91a60529d1 100644
--- a/lib/tktext.rb
+++ b/lib/tktext.rb
@@ -24,10 +24,9 @@ class TkText<TkTextWin
def _addcmd(cmd)
@cmdtbl.push id
end
- def _addtag(cmd)
- @cmdtbl.push id
+ def _addtag(name, obj)
+ @tags[name] = obj
end
- private :_addcmd, :_addtag
def tag_names
tk_send('tag', 'names').collect{|elt|
if not @tags[elt]
@@ -75,18 +74,25 @@ class TkText<TkTextWin
def yview_pickplace(*what)
tk_send 'yview', '-pickplace', *what
end
+
+ def xview(*what)
+ tk_send 'xview', *what
+ end
+ def xview_pickplace(*what)
+ tk_send 'xview', '-pickplace', *what
+ end
end
class TkTextTag<TkObject
$tk_text_tag = 'tag0000'
- def initialize(parent)
+ def initialize(parent, keys=nil)
if not parent.kind_of?(TkText)
fail format("%s need to be TkText", parent.inspect)
end
@t = parent
- @path = parent.path
- @id = $tk_text_tag
+ @path = @id = $tk_text_tag
$tk_text_tag = $tk_text_tag.succ
+ tk_call @t.path, "tag", "configure", @id, *hash_kv(keys)
@t._addtag id, self
end
def id
@@ -94,25 +100,25 @@ class TkTextTag<TkObject
end
def add(*index)
- tk_call path, 'tag', 'add', @id, *index
+ tk_call @t.path, 'tag', 'add', @id, *index
end
- def configure(slot, value)
- tk_call path, 'tag', 'configure', id, "-#{slot}", value
+ def configure(keys)
+ tk_call @t.path, 'tag', 'configure', @id, *hash_kv(keys)
end
def bind(seq, cmd=Proc.new)
id = install_cmd(cmd)
- tk_call path, 'tag', 'bind', tag, "<#{seq}>", id
+ tk_call @t, 'tag', 'bind', tag, "<#{seq}>", id
@t._addcmd cmd
end
def lower(below=None)
- tk_call path, 'tag', 'lower', below
+ tk_call @t.path, 'tag', 'lower', below
end
def destroy
- tk_call path, 'tag', 'delete', @id
+ tk_call @t.path, 'tag', 'delete', @id
end
end
@@ -123,10 +129,9 @@ class TkTextMark<TkObject
fail format("%s need to be TkText", parent.inspect)
end
@t = parent
- @path = parent.path
- @id = $tk_text_mark
+ @path = @id = $tk_text_mark
$tk_text_mark = $tk_text_mark.succ
- tk_call @t, 'set', @id, index
+ tk_call @t.path, 'set', @id, index
@t._addtag id, self
end
def id
@@ -134,11 +139,11 @@ class TkTextMark<TkObject
end
def set(where)
- tk_call path, 'mark', 'unset', @id, where
+ tk_call @t.path, 'mark', 'unset', @id, where
end
def unset
- tk_call path, 'mark', 'unset', @id
+ tk_call @t.path, 'mark', 'unset', @id
end
alias destroy unset
end
@@ -149,12 +154,11 @@ class TkTextWindow<TkObject
fail format("%s need to be TkText", parent.inspect)
end
@t = parent
- @path = parent.path
- @index = index
- tk_call @path, 'window', 'create', index, *args
+ @path = @index = index
+ tk_call @t.path, 'window', 'create', index, *args
end
def configure(slot, value)
- tk_call path, 'window', 'configure', @index, "-#{slot}", value
+ tk_call @t.path, 'window', 'configure', @index, "-#{slot}", value
end
end
diff --git a/lib/tkthcore.rb b/lib/tkthcore.rb
index 5e0abd72c5..b89850cb73 100644
--- a/lib/tkthcore.rb
+++ b/lib/tkthcore.rb
@@ -30,7 +30,7 @@ module Tk
break if wish_path
end
}
- fail 'can\'t find wish' if not wish_path
+ fail 'can\'t find wish' if not wish_path #'
# mark for non-given arguments
None = Object.new
@@ -66,9 +66,10 @@ module Tk
ary = [PORT]
loop do
str = Qin.pop
- print str, "\n" if $DEBUG
+ print "Qin: ", str, "\n" if $DEBUG
tk_write 'if [catch {%s} var] {puts "!$var"} {puts "=$var@@"};flush stdout', str
- Qout.push(tk_recv)
+ line = tk_recv
+ Qout.push(line)
end
end
end
@@ -89,7 +90,7 @@ module Tk
val += $'
return val
else
- v>al += $_
+ val += $_
end
end
elsif /^!/
@@ -101,7 +102,6 @@ module Tk
fail format("%s - %s", self.type, msg)
end
end
- Qcmd.push line
end
fail 'wish closed' if PORT.closed?
@@ -122,11 +122,15 @@ module Tk
s = "1"
elsif s.kind_of?(TkObject)
s = s.path
+ elsif s.kind_of?(TkVariable)
+ s = s.id
else
s = s.to_s
- s.gsub!(/[{}]/, '\\\\\0')
+ s.gsub!(/["\\\$\[\]]/, '\\\\\0') #"
+ s.gsub!(/\{/, '\\\\173')
+ s.gsub!(/\}/, '\\\\175')
end
- "{#{s}}"
+ "\"#{s}\""
end
}
str += " "
@@ -240,12 +244,11 @@ after 120000 keepalive'
module_function :dispatch
def error_at
- n = 1
- while c = caller(n)
- break if c !~ /tk\.rb:/
- n+=1
+ frames = caller(1)
+ frames.delete_if do |c|
+ c =~ %r!/tk(|core|thcore|canvas|text|entry|scrollbox)\.rb:\d+!
end
- c
+ frames
end
def bool(val)
@@ -295,7 +298,7 @@ after 120000 keepalive'
if keys
for k, v in keys
conf.push("-#{k}")
- v = install_cmd(v) if v.type == Proc
+ v = install_cmd(v) if v.kind_of? Proc
conf.push(v)
end
end
@@ -440,10 +443,10 @@ after 120000 keepalive'
module_function :after, :update, :dispatch, :mainloop, :root, :bell
module Scrollable
- def xscrollcommand(cmd)
+ def xscrollcommand(cmd=Proc.new)
configure_cmd 'xscrollcommand', cmd
end
- def yscrollcommand(cmd)
+ def yscrollcommand(cmd=Proc.new)
configure_cmd 'yscrollcommand', cmd
end
end
diff --git a/lib/tracer.rb b/lib/tracer.rb
new file mode 100644
index 0000000000..d37339fd62
--- /dev/null
+++ b/lib/tracer.rb
@@ -0,0 +1,75 @@
+class Tracer
+ MY_FILE_NAME_PATTERN = /^tracer\.(rb)?/
+ Threads = Hash.new
+ Sources = Hash.new
+
+ EVENT_SYMBOL = {
+ "line" => "-",
+ "call" => ">",
+ "return" => "<",
+ "class" => "C",
+ "end" => "E"}
+
+ def on
+ set_trace_func proc{|event, file, line, id, binding|
+ trace_func event, file, line, id, binding
+ }
+ print "Trace on\n"
+ end
+
+ def off
+ set_trace_func nil
+ print "Trace off\n"
+ end
+
+ def get_thread_no
+ unless no = Threads[Thread.current.id]
+ Threads[Thread.current.id] = no = Threads.size
+ end
+ no
+ end
+
+ def get_line(file, line)
+ unless list = Sources[file]
+ f =open(file)
+ begin
+ Sources[file] = list = f.readlines
+ ensure
+ f.close
+ end
+ end
+ list[line - 1]
+ end
+
+ def trace_func(event, file, line, id, binding)
+ return if File.basename(file) =~ MY_FILE_NAME_PATTERN
+
+ Thread.critical = TRUE
+ printf("#%d:%s:%d:%s: %s",
+ get_thread_no,
+ file,
+ line,
+ EVENT_SYMBOL[event],
+ get_line(file, line))
+ Thread.critical = FALSE
+ end
+
+ Single = new
+ def Tracer.on
+ Single.on
+ end
+
+ def Tracer.off
+ Single.off
+ end
+
+end
+
+if File.basename($0) =~ Tracer::MY_FILE_NAME_PATTERN
+ $0 = ARGV.shift
+
+ Tracer.on
+ load $0
+else
+ Tracer.on
+end
diff --git a/main.c b/main.c
index c42656e61b..f3c1c31455 100644
--- a/main.c
+++ b/main.c
@@ -12,11 +12,27 @@
unsigned int _stklen = 0x100000;
#endif
+#ifdef __human68k__
+int _stacksize = 131072;
+#endif
+
+#if (_MSC_VER >= 1000)
+__declspec(dllexport) void __stdcall ruby_init();
+__declspec(dllexport) void __stdcall ruby_options(int, char *[]);
+__declspec(dllexport) void __stdcall ruby_run(void);
+__declspec(dllexport) void __stdcall NtInitialize(int *, char ***);
+#endif
+
void
main(argc, argv, envp)
int argc;
char **argv, **envp;
{
- ruby_init(argc, argv, envp);
+#if defined(NT)
+ NtInitialize(&argc, &argv);
+#endif
+
+ ruby_init();
+ ruby_options(argc, argv);
ruby_run();
}
diff --git a/missing/dir.h b/missing/dir.h
new file mode 100644
index 0000000000..51904c6f88
--- /dev/null
+++ b/missing/dir.h
@@ -0,0 +1,248 @@
+/* $RCSfile: dir.h,v $$Revision: 4.0.1.1 $$Date: 91/06/07 11:22:10 $
+ *
+ * (C) Copyright 1987, 1990 Diomidis Spinellis.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: dir.h,v $
+ * Revision 4.0.1.1 91/06/07 11:22:10 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:34:20 lwall
+ * 4.0 baseline.
+ *
+ * Revision 3.0.1.1 90/03/27 16:07:08 lwall
+ * patch16: MSDOS support
+ *
+ * Revision 1.1 90/03/18 20:32:29 dds
+ * Initial revision
+ *
+ *
+ */
+
+/*
+ * defines the type returned by the directory(3) functions
+ */
+
+#ifndef __DIR_INCLUDED
+#define __DIR_INCLUDED
+
+/*Directory entry size */
+#ifdef DIRSIZ
+#undef DIRSIZ
+#endif
+#define DIRSIZ(rp) (sizeof(struct direct))
+
+/*
+ * Structure of a directory entry
+ */
+struct direct {
+ ino_t d_ino; /* inode number (not used by MS-DOS) */
+ int d_namlen; /* Name length */
+ char d_name[256]; /* file name */
+};
+
+struct _dir_struc { /* Structure used by dir operations */
+ char *start; /* Starting position */
+ char *curr; /* Current position */
+ long size; /* Size of string table */
+ long nfiles; /* number if filenames in table */
+ struct direct dirstr; /* Directory structure to return */
+};
+
+typedef struct _dir_struc DIR; /* Type returned by dir operations */
+
+DIR *cdecl opendir(char *filename);
+struct direct *readdir(DIR *dirp);
+long telldir(DIR *dirp);
+void seekdir(DIR *dirp,long loc);
+void rewinddir(DIR *dirp);
+void closedir(DIR *dirp);
+
+#endif /* __DIR_INCLUDED */
+/* $RCSfile: dir.h,v $$Revision: 4.0.1.1 $$Date: 91/06/07 11:22:10 $
+ *
+ * (C) Copyright 1987, 1990 Diomidis Spinellis.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: dir.h,v $
+ * Revision 4.0.1.1 91/06/07 11:22:10 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:34:20 lwall
+ * 4.0 baseline.
+ *
+ * Revision 3.0.1.1 90/03/27 16:07:08 lwall
+ * patch16: MSDOS support
+ *
+ * Revision 1.1 90/03/18 20:32:29 dds
+ * Initial revision
+ *
+ *
+ */
+
+/*
+ * defines the type returned by the directory(3) functions
+ */
+
+#ifndef __DIR_INCLUDED
+#define __DIR_INCLUDED
+
+/*Directory entry size */
+#ifdef DIRSIZ
+#undef DIRSIZ
+#endif
+#define DIRSIZ(rp) (sizeof(struct direct))
+
+/*
+ * Structure of a directory entry
+ */
+struct direct {
+ ino_t d_ino; /* inode number (not used by MS-DOS) */
+ int d_namlen; /* Name length */
+ char d_name[256]; /* file name */
+};
+
+struct _dir_struc { /* Structure used by dir operations */
+ char *start; /* Starting position */
+ char *curr; /* Current position */
+ struct direct dirstr; /* Directory structure to return */
+};
+
+typedef struct _dir_struc DIR; /* Type returned by dir operations */
+
+DIR *cdecl opendir(char *filename);
+struct direct *readdir(DIR *dirp);
+long telldir(DIR *dirp);
+void seekdir(DIR *dirp,long loc);
+void rewinddir(DIR *dirp);
+void closedir(DIR *dirp);
+