diff options
author | Yukihiro Matsumoto <matz@ruby-lang.org> | 1997-10-02 17:59:18 +0900 |
---|---|---|
committer | Takashi Kokubun <takashikkbn@gmail.com> | 2019-08-17 22:09:32 +0900 |
commit | 10d21745c8c1c3c78678ea7e0b62c0a7433ccfce (patch) | |
tree | 4e40254178d66c343cae763029131d959518f795 | |
parent | ce930d042913722f209bbd3209b6c90a3c71325f (diff) |
version 1.0-971002v1_0_971002
https://cache.ruby-lang.org/pub/ruby/1.0/ruby-1.0-971002.tar.gz
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): 初期化忘れのメンバがあった.
Co-authored-by: EGUCHI Matsumoto <eguchi@shizuokanet.or.jp>
Co-authored-by: EGUCHI Osamu <eguchi@shizuokanet.or.jp>
Co-authored-by: KIMURA Koichi <kkimura@pure.cpdc.canon.co.jp>
Co-authored-by: Katsuyuki Okabe <HGC02147@niftyserve.or.jp>
Co-authored-by: MAEDA shugo <shugo@po.aianet.ne.jp>
Co-authored-by: Michio "Karl" Jinbo <karl@marcer.nagaokaut.ac.jp>
Co-authored-by: WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
Co-authored-by: Yasuo OHBA <jammy@shljapan.co.jp>
Co-authored-by: maeda shugo <shugo@po.aianet.ne.jp>
Co-authored-by: ono <ono@isl.nara.sharp.co.jp>
-rw-r--r-- | ChangeLog | 1193 | ||||
-rw-r--r-- | MANIFEST | 35 | ||||
-rw-r--r-- | Makefile.in | 134 | ||||
-rw-r--r-- | README | 29 | ||||
-rw-r--r-- | README.EXT | 341 | ||||
-rw-r--r-- | README.jp | 23 | ||||
-rw-r--r-- | ToDo | 3 | ||||
-rw-r--r-- | array.c | 158 | ||||
-rw-r--r-- | bignum.c | 157 | ||||
-rw-r--r-- | class.c | 48 | ||||
-rw-r--r-- | config.dj | 3 | ||||
-rwxr-xr-x | config.guess | 48 | ||||
-rwxr-xr-x | config.sub | 11 | ||||
-rw-r--r-- | configure.in | 184 | ||||
-rw-r--r-- | defines.h | 16 | ||||
-rw-r--r-- | dir.c | 65 | ||||
-rw-r--r-- | dln.c | 86 | ||||
-rw-r--r-- | enum.c | 9 | ||||
-rw-r--r-- | error.c | 85 | ||||
-rw-r--r-- | eval.c | 2120 | ||||
-rw-r--r-- | ext/Setup | 3 | ||||
-rw-r--r-- | ext/Setup.dj | 4 | ||||
-rw-r--r-- | ext/Setup.nt | 12 | ||||
-rw-r--r-- | ext/Setup.x68 | 12 | ||||
-rw-r--r-- | ext/aix_ld.rb | 73 | ||||
-rw-r--r-- | ext/curses/MANIFEST | 6 | ||||
-rw-r--r-- | ext/curses/curses.c | 725 | ||||
-rw-r--r-- | ext/curses/extconf.rb | 21 | ||||
-rw-r--r-- | ext/curses/hello.rb | 28 | ||||
-rw-r--r-- | ext/curses/rain.rb | 76 | ||||
-rw-r--r-- | ext/curses/view.rb | 90 | ||||
-rw-r--r-- | ext/dbm/dbm.c | 57 | ||||
-rw-r--r-- | ext/dbm/extconf.rb | 1 | ||||
-rw-r--r-- | ext/etc/etc.c | 2 | ||||
-rw-r--r-- | ext/extmk.rb.in | 120 | ||||
-rw-r--r-- | ext/extmk.rb.nt | 436 | ||||
-rw-r--r-- | ext/fcntl/MANIFEST | 3 | ||||
-rw-r--r-- | ext/fcntl/depend | 1 | ||||
-rw-r--r-- | ext/fcntl/fcntl.c | 106 | ||||
-rw-r--r-- | ext/kconv/MANIFEST | 1 | ||||
-rw-r--r-- | ext/kconv/depend | 1 | ||||
-rw-r--r-- | ext/kconv/kconv.c | 87 | ||||
-rw-r--r-- | ext/marshal/extconf.rb | 1 | ||||
-rw-r--r-- | ext/marshal/marshal.c | 702 | ||||
-rw-r--r-- | ext/md5/md5init.c | 10 | ||||
-rw-r--r-- | ext/socket/extconf.rb | 10 | ||||
-rw-r--r-- | ext/socket/socket.c | 588 | ||||
-rw-r--r-- | ext/tkutil/tkutil.c | 9 | ||||
-rw-r--r-- | file.c | 299 | ||||
-rw-r--r-- | gc.c | 345 | ||||
-rw-r--r-- | glob.c | 6 | ||||
-rw-r--r-- | hash.c | 470 | ||||
-rw-r--r-- | inits.c | 3 | ||||
-rw-r--r-- | io.c | 782 | ||||
-rw-r--r-- | io.h | 7 | ||||
-rw-r--r-- | lib/English.rb | 28 | ||||
-rw-r--r-- | lib/base64.rb | 47 | ||||
-rw-r--r-- | lib/date.rb | 221 | ||||
-rw-r--r-- | lib/debug.rb | 262 | ||||
-rw-r--r-- | lib/e2mmap.rb | 94 | ||||
-rw-r--r-- | lib/e2mmap1_0.rb | 71 | ||||
-rw-r--r-- | lib/finalize.rb | 205 | ||||
-rw-r--r-- | lib/ftplib.rb | 617 | ||||
-rw-r--r-- | lib/jcode.rb | 35 | ||||
-rw-r--r-- | lib/mathn.rb | 3 | ||||
-rw-r--r-- | lib/matrix.rb | 777 | ||||
-rw-r--r-- | lib/mutex_m.rb | 183 | ||||
-rw-r--r-- | lib/observer.rb | 2 | ||||
-rw-r--r-- | lib/parsedate.rb | 12 | ||||
-rw-r--r-- | lib/ping.rb | 55 | ||||
-rw-r--r-- | lib/safe.rb | 78 | ||||
-rw-r--r-- | lib/sync.rb | 376 | ||||
-rw-r--r-- | lib/thread.rb | 117 | ||||
-rw-r--r-- | lib/thwait.rb | 128 | ||||
-rw-r--r-- | lib/tk.rb | 128 | ||||
-rw-r--r-- | lib/tkcanvas.rb | 21 | ||||
-rw-r--r-- | lib/tkclass.rb | 2 | ||||
-rw-r--r-- | lib/tkcore.rb | 40 | ||||
-rw-r--r-- | lib/tkentry.rb | 15 | ||||
-rw-r--r-- | lib/tkscrollbox.rb | 4 | ||||
-rw-r--r-- | lib/tktext.rb | 46 | ||||
-rw-r--r-- | lib/tkthcore.rb | 33 | ||||
-rw-r--r-- | lib/tracer.rb | 75 | ||||
-rw-r--r-- | main.c | 18 | ||||
-rw-r--r-- | missing/dir.h | 248 | ||||
-rw-r--r-- | missing/file.h | 31 | ||||
-rw-r--r-- | missing/nt.c | 407 | ||||
-rw-r--r-- | missing/nt.h | 123 | ||||
-rw-r--r-- | missing/setenv.c | 6 | ||||
-rw-r--r-- | missing/strcasecmp.c | 13 | ||||
-rw-r--r-- | node.h | 161 | ||||
-rw-r--r-- | numeric.c | 35 | ||||
-rw-r--r-- | object.c | 296 | ||||
-rw-r--r-- | pack.c | 256 | ||||
-rw-r--r-- | parse.y | 510 | ||||
-rw-r--r-- | process.c | 373 | ||||
-rw-r--r-- | random.c | 13 | ||||
-rw-r--r-- | range.c | 4 | ||||
-rw-r--r-- | re.c | 389 | ||||
-rw-r--r-- | re.h | 3 | ||||
-rw-r--r-- | regex.c | 285 | ||||
-rw-r--r-- | regex.h | 4 | ||||
-rw-r--r-- | ruby.c | 245 | ||||
-rw-r--r-- | ruby.h | 133 | ||||
-rw-r--r-- | sample/biorhythm.rb | 227 | ||||
-rw-r--r-- | sample/dbmtest.rb (renamed from sample/dbm.rb) | 0 | ||||
-rw-r--r-- | sample/dir.rb | 2 | ||||
-rw-r--r-- | sample/eval.rb | 7 | ||||
-rw-r--r-- | sample/freq.rb | 4 | ||||
-rwxr-xr-x | sample/from.rb | 93 | ||||
-rw-r--r-- | sample/mrshtest.rb (renamed from sample/marshal.rb) | 11 | ||||
-rw-r--r-- | sample/philos.rb | 2 | ||||
-rw-r--r-- | sample/regx.rb | 2 | ||||
-rw-r--r-- | sample/ruby-mode.el | 225 | ||||
-rw-r--r-- | sample/rubydb2x.el | 104 | ||||
-rw-r--r-- | sample/rubydb3x.el | 104 | ||||
-rw-r--r-- | sample/svr.rb | 2 | ||||
-rw-r--r-- | sample/test.rb | 115 | ||||
-rw-r--r-- | sample/tkbiff.rb | 2 | ||||
-rw-r--r-- | sample/tkfrom.rb | 18 | ||||
-rw-r--r-- | sig.h | 1 | ||||
-rw-r--r-- | signal.c | 16 | ||||
-rw-r--r-- | sprintf.c | 314 | ||||
-rw-r--r-- | st.c | 77 | ||||
-rw-r--r-- | st.h | 2 | ||||
-rw-r--r-- | string.c | 359 | ||||
-rw-r--r-- | struct.c | 73 | ||||
-rw-r--r-- | time.c | 58 | ||||
-rw-r--r-- | top.sed | 30 | ||||
-rw-r--r-- | util.c | 405 | ||||
-rw-r--r-- | variable.c | 351 | ||||
-rw-r--r-- | version.c | 7 | ||||
-rw-r--r-- | version.h | 4 | ||||
-rw-r--r-- | win32/Makefile | 233 | ||||
-rw-r--r-- | win32/config.h | 60 | ||||
-rw-r--r-- | win32/ntsetup.bat | 10 | ||||
-rw-r--r-- | win32/ruby.def | 6 | ||||
-rw-r--r-- | x68/_dtos18.c | 250 | ||||
-rw-r--r-- | x68/_round.c | 45 | ||||
-rw-r--r-- | x68/fconvert.c | 81 | ||||
-rw-r--r-- | x68/select.c | 167 |
141 files changed, 16380 insertions, 4160 deletions
@@ -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): FixnumString̰ƹ® + +Mon Jan 13 11:03:53 1997 Yukihiro Matsumoto <matz@caelum.co.jp> + + * eval.c (thread_create): threadޤdzߤꤷʤ + + * 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): Filereopen(pathޤIOǻ) + + * io.c (io_reopen): IOreopen(IOǻ) -- change classĤ + +Wed Jan 1 11:09:01 1997 Yukihiro Matsumoto <matz@caelum.co.jp> + + * io.c (f_select): timeoutnil֤ + +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): unlesselse¹Ԥʤ() * 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б @@ -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: @@ -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μ +1Basic knowledge -CѿˤϷꡤǡˤϷޤǤ顤 -ȤХݥintѿȡͤȤƼ -갷ޤդrubyѿˤϷʤǡ˷ -ΰ㤤ΤᡤCrubyߤѴʤСߤ -ǡǤޤ +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 Υ饹ȤϤޤäΤǤ -VALUECˤȤäựΤǡФˤ +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) VALUECΥǡѴ +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) -δؿvaluetype̵С㳰ȯޤ -Ϳ줿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 VALUECΥǡѴ +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ʸstrlenХȤʸ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. -2rubyεǽȤ +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 @@ CrubyεǽƤӽФäȤñˡȤơʸ 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 CrubyΥåɤƤӽФ +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) idrb_intern()ΤȤäƤ @@ -364,24 +373,24 @@ idrb_intern()ΤȤäƤ 饹뤿ˤϡ2.1.3 ٤ǾҲ ƤؿȤäƤ -3rubyCȤξͭ +3. Informatin sharing between ruby and C Crubyδ֤ǾͭˡˤĤƲ⤷ޤ -3.1 C黲ȤǤruby +3.1 Ruby constant that C黲ȤǤruby -ʲrubyCΥ٥뤫黲ȤǤ롥 +Following ruby constants can be referred from C. TRUE FALSE -͡FALSECǤȤߤʤ롥 +Boolean values. FALSE is false in the C also (i.e. 0). Qnil -C줫鸫nilס +Ruby nil in C scope. -3.2 CrubyǶͭѿ +3.2 Global variables shared between C and ruby CrubyѿȤäƾͭǤޤͭǤ ѿˤϤĤμबޤΤʤǤäȤɤȤ @@ -399,18 +408,18 @@ CrubyѿȤäƾͭǤޤͭǤ 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 -setter0ꤷƤ +ˤϴؿsetterƤФ롥hookꤷʤgetter +setter0ꤷޤ -# gettersetter0ʤrb_define_variable()ƱƯ -# ޤ +# gettersetter0ʤrb_define_variable()Ʊˤʤ롥 줫顤CδؿˤäƼ¸rubyѿ ؿޤ @@ -421,7 +430,12 @@ CrubyѿȤäƾͭǤޤͭǤ δؿˤä줿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Ϥι¤Τ⤦ -פˤʤä˸ƤФؿǤδؿ١쥯 -ƤФޤsvaltypeѿǡMake_Data_Struct -Ȥޤ +classϤData֥ȤΥ饹Ǥptrϥץ벽 +Cι¤ΤؤΥݥǤmarkϤι¤ΤrubyΥ֥ +ȤؤλȤ˻ȤؿǤΤ褦ʻȤޤޤʤ +ˤ0ꤷޤ -ޥMake_Data_StructData֥Ȥơ -Ȥ֤ޤ +# Τ褦ʻȤϴޤ -ΥޥƤӽФsval˹¤Τmalloc()졤 -Ĥι¤Τץ벽Data֥Ȥ -ѿȤobj˥åȤޤ +freeϤι¤Τ⤦פˤʤä˸ƤФؿǤ +ؿ١쥯ƤФޤ -Data֥ȤCݥФˤϰʲΥޥ -Ȥޤ +Cι¤ΤγData֥ȤƱ˹Ԥޥ +ưʲΤΤƤޤ - Get_Data_Struct(obj, type, sval) + Data_Make_Struct(class, type, mark, free, sval) -Data֥ȤtypeCݥФơsval -ޤ +Υޥͤ줿Data֥ȤǤ + +class, mark, freeData_Wrap_StructƱƯޤtype +ϳƤC¤ΤηǤƤ줿¤Τѿsval +ޤѿη (type*) Ǥɬפޤ + +Data֥ȤݥФΤϰʲΥޥѤ +ޤ + + Data_Get_Struct(obj, type, sval) + +Cι¤ΤؤΥݥѿsvalޤ DataλȤϤäʬˤΤǡ ȤƤ -4 - dbmѥå +4Example - Create dbm module ޤǤǤȤꤢĥ⥸塼ϺϤǤ rubyextǥ쥯ȥˤǤ˴ޤޤƤ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Υǡб륪֥ȤˤʤϤ 顤Cdbmruby˼ɬפޤ -dbm.cǤDBMΥǡǼ뤿˰ʲΤ褦ʹ¤ΤȤ -Ƥޤ +dbm.cǤData_Make_StructʲΤ褦˻ȤäƤޤ + +-- struct dbmdata { int di_size; DBM *di_dbm; }; -RubyDBM֥Ȥ뤿ˤϰʲΤ褦ʥɤ -ȤäƤޤ - 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֥ȤCDBMݥФˤϰʲΤ -ʥޥȤäƤޤ +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¹ԤMakefilemake +ɬפˤäƤϤΥ⥸塼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ޥ +datatypeΥݥФѿsvalޥ ** 饹/⥸塼 @@ -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.cst.[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: @@ -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 @@ -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); @@ -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); @@ -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); } } @@ -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 @@ -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 @@ -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(); @@ -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; @@ -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); @@ -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() { @@ -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 @@ -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; } @@ -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", @@ -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(); } @@ -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 @@ -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); } @@ -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(); } @@ -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 } @@ -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) ǷФdependantfinalize. +# finalize_by_dependant(dependant, method = :finalize) +# ¸Ϣ R_method(*, dependtant) ǷФdependantfinalize. +# fainalize_all_by_dependant(dependant) +# ¸Ϣ R_*(*, dependtant) ǷФdependantfinalize. +# finalize_all +# FinalizerϿƤdependantfinalize +# +# safe{..} +# gcFinalizerưΤߤ. +# +# + +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) ǷФdependantfinalize + # . + 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) ǷФdependantfinalize. + 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) ǷФdependantfinalize. + 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) ǷФdependantfinalize. + def fainalize_all_by_dependant(dependant) + for id in @dependency.keys + finalize_all_dependency(id, dependant) + end + end + + # FinalizerϿƤƤdependantfinalize + 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 @@ -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, *h |