summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYukihiro Matsumoto <matz@ruby-lang.org>1997-10-02 08:59:18 (GMT)
committerTakashi Kokubun <takashikkbn@gmail.com>2019-08-17 13:09:32 (GMT)
commit10d21745c8c1c3c78678ea7e0b62c0a7433ccfce (patch)
tree4e40254178d66c343cae763029131d959518f795
parentce930d042913722f209bbd3209b6c90a3c71325f (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--ChangeLog1193
-rw-r--r--MANIFEST35
-rw-r--r--Makefile.in134
-rw-r--r--README29
-rw-r--r--README.EXT341
-rw-r--r--README.jp23
-rw-r--r--ToDo3
-rw-r--r--array.c158
-rw-r--r--bignum.c157
-rw-r--r--class.c48
-rw-r--r--config.dj3
-rwxr-xr-xconfig.guess48
-rwxr-xr-xconfig.sub11
-rw-r--r--configure.in184
-rw-r--r--defines.h16
-rw-r--r--dir.c65
-rw-r--r--dln.c86
-rw-r--r--enum.c9
-rw-r--r--error.c85
-rw-r--r--eval.c2120
-rw-r--r--ext/Setup3
-rw-r--r--ext/Setup.dj4
-rw-r--r--ext/Setup.nt12
-rw-r--r--ext/Setup.x6812
-rw-r--r--ext/aix_ld.rb73
-rw-r--r--ext/curses/MANIFEST6
-rw-r--r--ext/curses/curses.c725
-rw-r--r--ext/curses/extconf.rb21
-rw-r--r--ext/curses/hello.rb28
-rw-r--r--ext/curses/rain.rb76
-rw-r--r--ext/curses/view.rb90
-rw-r--r--ext/dbm/dbm.c57
-rw-r--r--ext/dbm/extconf.rb1
-rw-r--r--ext/etc/etc.c2
-rw-r--r--ext/extmk.rb.in120
-rw-r--r--ext/extmk.rb.nt436
-rw-r--r--ext/fcntl/MANIFEST3
-rw-r--r--ext/fcntl/depend1
-rw-r--r--ext/fcntl/fcntl.c106
-rw-r--r--ext/kconv/MANIFEST1
-rw-r--r--ext/kconv/depend1
-rw-r--r--ext/kconv/kconv.c87
-rw-r--r--ext/marshal/extconf.rb1
-rw-r--r--ext/marshal/marshal.c702
-rw-r--r--ext/md5/md5init.c10
-rw-r--r--ext/socket/extconf.rb10
-rw-r--r--ext/socket/socket.c588
-rw-r--r--ext/tkutil/tkutil.c9
-rw-r--r--file.c299
-rw-r--r--gc.c345
-rw-r--r--glob.c6
-rw-r--r--hash.c470
-rw-r--r--inits.c3
-rw-r--r--io.c782
-rw-r--r--io.h7
-rw-r--r--lib/English.rb28
-rw-r--r--lib/base64.rb47
-rw-r--r--lib/date.rb221
-rw-r--r--lib/debug.rb262
-rw-r--r--lib/e2mmap.rb94
-rw-r--r--lib/e2mmap1_0.rb71
-rw-r--r--lib/finalize.rb205
-rw-r--r--lib/ftplib.rb617
-rw-r--r--lib/jcode.rb35
-rw-r--r--lib/mathn.rb3
-rw-r--r--lib/matrix.rb777
-rw-r--r--lib/mutex_m.rb183
-rw-r--r--lib/observer.rb2
-rw-r--r--lib/parsedate.rb12
-rw-r--r--lib/ping.rb55
-rw-r--r--lib/safe.rb78
-rw-r--r--lib/sync.rb376
-rw-r--r--lib/thread.rb117
-rw-r--r--lib/thwait.rb128
-rw-r--r--lib/tk.rb128
-rw-r--r--lib/tkcanvas.rb21
-rw-r--r--lib/tkclass.rb2
-rw-r--r--lib/tkcore.rb40
-rw-r--r--lib/tkentry.rb15
-rw-r--r--lib/tkscrollbox.rb4
-rw-r--r--lib/tktext.rb46
-rw-r--r--lib/tkthcore.rb33
-rw-r--r--lib/tracer.rb75
-rw-r--r--main.c18
-rw-r--r--missing/dir.h248
-rw-r--r--missing/file.h31
-rw-r--r--missing/nt.c407
-rw-r--r--missing/nt.h123
-rw-r--r--missing/setenv.c6
-rw-r--r--missing/strcasecmp.c13
-rw-r--r--node.h161
-rw-r--r--numeric.c35
-rw-r--r--object.c296
-rw-r--r--pack.c256
-rw-r--r--parse.y510
-rw-r--r--process.c373
-rw-r--r--random.c13
-rw-r--r--range.c4
-rw-r--r--re.c389
-rw-r--r--re.h3
-rw-r--r--regex.c285
-rw-r--r--regex.h4
-rw-r--r--ruby.c245
-rw-r--r--ruby.h133
-rw-r--r--sample/biorhythm.rb227
-rw-r--r--sample/dbmtest.rb (renamed from sample/dbm.rb)0
-rw-r--r--sample/dir.rb2
-rw-r--r--sample/eval.rb7
-rw-r--r--sample/freq.rb4
-rwxr-xr-xsample/from.rb93
-rw-r--r--sample/mrshtest.rb (renamed from sample/marshal.rb)11
-rw-r--r--sample/philos.rb2
-rw-r--r--sample/regx.rb2
-rw-r--r--sample/ruby-mode.el225
-rw-r--r--sample/rubydb2x.el104
-rw-r--r--sample/rubydb3x.el104
-rw-r--r--sample/svr.rb2
-rw-r--r--sample/test.rb115
-rw-r--r--sample/tkbiff.rb2
-rw-r--r--sample/tkfrom.rb18
-rw-r--r--sig.h1
-rw-r--r--signal.c16
-rw-r--r--sprintf.c314
-rw-r--r--st.c77
-rw-r--r--st.h2
-rw-r--r--string.c359
-rw-r--r--struct.c73
-rw-r--r--time.c58
-rw-r--r--top.sed30
-rw-r--r--util.c405
-rw-r--r--variable.c351
-rw-r--r--version.c7
-rw-r--r--version.h4
-rw-r--r--win32/Makefile233
-rw-r--r--win32/config.h60
-rw-r--r--win32/ntsetup.bat10
-rw-r--r--win32/ruby.def6
-rw-r--r--x68/_dtos18.c250
-rw-r--r--x68/_round.c45
-rw-r--r--x68/fconvert.c81
-rw-r--r--x68/select.c167
141 files changed, 16380 insertions, 4160 deletions
diff --git a/ChangeLog b/ChangeLog
index 9281697..d2fa799 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,1192 @@
+Thu Oct 2 17:59:18 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-971002
+
+Wed Oct 1 14:01:49 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * ext/marshal/marshal.c (w_byte): argument must be char.
+
+Wed Oct 1 10:30:22 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * ext/marshal/marshal.c (marshal_dump): try to set binmode.
+
+ * ext/marshal/marshal.c (r_object): forgot to re-regist structs in
+ the object table.
+
+ * eval.c (ruby_options): call Init_ext() before any require()
+ calls by `-r'.
+
+Tue Sep 30 14:51:07 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970930
+
+Fri Sep 30 14:29:22 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * ext/marshal/marshal.c (w_object): marshal dumped core.
+
+Tue Sep 30 10:27:39 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * sample/test.rb: bignum test suits added.
+
+Mon Sep 29 13:37:58 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * ruby.c (forbid_setid): forbid some options in suid mode.
+
+Mon Sep 27 09:53:48 1997 EGUCHI Matsumoto <eguchi@shizuokanet.or.jp>
+
+ * bignum.c: modified for speeding.
+
+Fri Sep 26 18:27:59 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * sample/from.rb: some extensions.
+
+Mon Sep 29 13:15:56 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * parse.y (lhs): no more syntax error on `obj.CONSTANT = value'.
+
+Fri Sep 26 14:41:46 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * eval.c (ruby_run): deferred calling Init_ext() just before eval_node.
+
+Fri Sep 26 13:27:24 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * io.c (io_isatty): forgot to return TRUE value.
+
+Fri Sep 25 11:10:58 1997 EGUCHI Osamu <eguchi@shizuokanet.or.jp>
+
+ * eval.c: use _setjmp/_longjmp instead of setjmp/longjmp on some
+ platforms.
+
+Wed Sep 24 17:43:13 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * string.c (Init_String): String#taint and String#taint? added.
+
+Wed Sep 24 00:57:00 1997 Katsuyuki Okabe <HGC02147@niftyserve.or.jp>
+
+ * X68000 patch.
+
+Tue Sep 23 20:42:30 1997 EGUCHI Osamu <eguchi@shizuokanet.or.jp>
+
+ * parse.y (node_newnode): SEGV on null node setup.
+
+Mon Sep 22 11:22:46 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * ruby.c (ruby_prog_init): wrong safe condition check.
+
+Sun Sep 21 14:46:02 1997 MAEDA shugo <shugo@po.aianet.ne.jp>
+
+ * error.c (exc_inspect): garbage added to classpath.
+
+Fri Sep 19 11:49:23 1997 <matz@netlab.co.jp>
+
+ * version 1.0-970919
+
+ * parse.y (newtok): forgot to adjust buffer size when shrinking
+ the token buffer.
+
+ * enum.c (enum_find): rb_eval_cmd() does not return value.
+
+ * io.c (pipe_open): close fds on pipe exec. fcntl(fd, F_SETFD, 1)
+ no longer used.
+
+Tue Sep 16 17:54:25 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * file.c (f_test): problem if wrong command specified.
+
+ * ruby.c (ruby_prog_init): close stdaux and stdprn for MSDOS.
+
+ * ruby.c (ruby_prog_init): should not add path from environment
+ variable, if ruby is running under seuid.
+
+ * process.c (init_ids): check suid check for setuid/seteuid etc.
+
+Mon Sep 15 00:42:04 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * regex.c (re_compile_pattern): \w{3} and \W{3} did not work.
+
+Thu Sep 11 10:31:48 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970911
+
+ * ext/socket/socket.c (sock_new): no setbuf() for NT.
+
+ * io.c (rb_fopen,rb_fdopen): set close-on-exec for every fd.
+
+Wed Sep 10 15:55:31 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970910
+
+ * ext/marshal/marshal.c (r_bytes0): extra big length check.
+
+Tue Sep 9 16:27:14 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * io.c (pipe_fptr_atexit): clean up popen()'ed fptr.
+
+ * error.c (set_syserr): some system has error code that is bigger
+ than sys_nerr. grrr.
+
+Tue Sep 9 16:27:14 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970909
+
+ * error.c (set_syserr): some system has error code that is bigger
+ than sys_nerr. grrr.
+
+Wed Sep 3 18:11:00 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970903
+
+ * eval.c (f_load): expand path if fname begins with `~'.
+
+Mon Sep 1 13:42:48 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * eval.c (rb_call): alias occured in the module body caused SEGV.
+
+Fri Aug 29 11:10:21 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * parse.y (yylex): spaces can follow =begin/=end.
+
+ * variable.c (find_class_path): look for class_tbl also for
+ unnamed fundamental classes, such as Object, String, etc.
+
+ * variable.c (rb_name_class): can't name class before String class
+ is initilialized.
+
+ * inits.c (rb_call_inits): unrecognized dependency from GC to
+ Array.
+
+ * variable.c (find_class_path): could not find class if Object's
+ iv_tbl is NULL.
+
+Thu Aug 28 13:12:05 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * parse.y (yylex): revised `=begin' skip code.
+
+ * eval.c (is_defined): separated from rb_eval().
+
+Wed Aug 27 11:32:42 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * variable.c (fc_i): some classes/modules does not have iv_tbl.
+
+ * variable.c (find_class_path): avoid inifinite loop.
+
+Tue Aug 26 13:43:47 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * eval.c (rb_eval): undef'ing non-existing method will raise
+ NameError exception.
+
+ * object.c (class_s_new): needed to create metaclass too.
+
+ * eval.c (error_print): no class name print for anonymous class.
+
+ * eval.c (rb_longjmp): proper exception raised if raise() called
+ without arguments, with $! or $@ set.
+
+ * object.c (Init_Object): superclass()'s method argument setting
+ was wrong again.
+
+Mon Aug 25 11:53:11 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * sample/ruby-mode.el (ruby-parse-region): auto-indent now
+ supports "\\" in the strings.
+
+ * struct.c (struct_getmember): new API to get member value from C
+ language side.
+
+Fri Aug 22 14:26:40 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * eval.c (error_print): modified exception print format.
+
+Thu Aug 21 16:10:58 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * sample/ruby-mode.el (ruby-calculate-indent): wrong indent level
+ calculated with keyword operators.
+
+Thu Aug 21 11:55:41 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970821
+
+Thu Aug 21 11:36:58 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * parse.y (arg): ary[0] += 1 cause SEGV
+
+Wed Aug 20 14:24:42 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970820
+
+ * eval.c (rb_call): infinite loop bug
+
+Tue Aug 19 00:15:38 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970819
+
+ * eval.c (rb_call): did not raise ArgumentError if too many
+ arguments more than optional arguments (without rest arg).
+
+ * eval.c (rb_eval): did not work well for op_asgn2 (attribute
+ self assignment).
+
+Mon Aug 18 09:25:56 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * object.c (inspect_i): did not display T_DATA instance variables.
+
+ * parse.y: provides more accurate line number information.
+
+ * eval.c (thread_value): include value's backtrace information in
+ the variable `$@'.
+
+ * eval.c (f_abort): print backtrace and exit.
+
+Sat Aug 16 00:17:44 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * object.c (class_s_new): do not make subclass of singleton class.
+
+Fri Aug 15 15:49:46 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * eval.c (call_trace_func): block context switch in the trace
+ function.
+
+ * eval.c (rb_eval): clear method cache at class extention.
+
+Fri Aug 15 19:40:43 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * ext/socket/socket.c (Init_socket): small typo caused SEGV.
+
+Tue Aug 12 16:02:18 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * variable.c: option variables: $-0, $-p(readonly), $-v,
+ $-I(load_path), $-a(readonly), $-K, $-d, $-F, $-i, $-l.
+
+ * parse.y (yylex): ignore rd (ruby document) in the code.
+
+Mon Aug 11 12:37:58 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * re.c (Init_Regexp): $-K as alias to the $KCODE.
+
+ * io.c (Init_IO): new virtual variable $-i for the value of -i
+ option.
+
+ * enum.c (Init_Enumerable): include? as alias of member?
+
+Fri Aug 8 11:16:50 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * io.c (io_foreach): now the record separator can be specified.
+
+ * io.c (io_s_readlines): new method to read in whole file (or
+ command output) from path.
+
+ * ext/socket/socket.c (Init_socket): recvfrom did not work.
+
+ * ext/socket/socket.c (sock_send): forgot to check nil for false
+ value.
+
+Thu Aug 7 11:40:01 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * object.c (Init_Object): remove private_attr/public_attr.
+
+Wed Aug 6 14:21:36 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * object.c (mod_attr): forgot to check nil for false value.
+
+Mon Aug 4 11:50:28 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * variable.c (rb_class_path): scan class constants for anonymous
+ classes/modules to make up pathes.
+
+Wed Jul 30 08:45:12 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * eval.c (rb_eval): stop to cache const value in nodes.
+
+Sat Jul 26 03:17:22 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * numeric.c (flo_to_s): wrong .0 at end.
+
+Sat Jul 26 00:36:36 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * eval.c (error_print): always print exception type in the
+ toplevel exception handler.
+
+ * string.c (str_hash): wrong hash value.
+
+Thu Jul 24 11:05:51 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * string.c (uscore_get): proper error message for unset $_.
+
+Wed Jul 23 09:56:55 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * object.c (obj_methods): returns list of method names of the
+ specified object.
+
+ * class.c (mod_instance_methods): returns list of method names of
+ the class instnace.
+
+Fri Jul 11 22:38:55 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * object.c (class_superclass): returns class's superclass
+ itself. (1.1)
+
+ * object.c (obj_type): returns object's class itself. (1.1)
+
+ * class.c (mod_included_modules): list included modules.
+
+ * object.c (class_superclass): raises error for Object.
+
+Thu Jul 3 09:54:02 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (SETUP_ARGS): save source position, remove nd_line().
+
+ * eval.c (rb_call): replace modulo by bit-masking.
+
+ * eval.c (POP_SCOPE): force recycle scope object to reduce gc rate.
+
+ * gc.c (obj_free): aboid calling run_final() when no finalizer is set.
+
+ * eval.c (PUSH_VARS): do not allocate the dynamic scope's end-mark
+ object.
+
+Wed Jul 2 14:25:07 1997 KIMURA Koichi <kkimura@pure.cpdc.canon.co.jp>
+
+ * Native mswin32 support.
+
+Tue Jul 1 09:59:00 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970701
+
+ * parse.y (mrhs): allow rest-star(*) in right hand side.
+
+Tue Jun 24 19:04:31 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970624
+
+Sat Jun 20 22:22:51 1997 Michio "Karl" Jinbo <karl@marcer.nagaokaut.ac.jp>
+
+ * eval.c: freebsd 3.0 <sys/select.h> support.
+
+Fri Jun 20 01:24:45 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970620
+
+ * gc.c: eliminate uninitilalized field of Hash, Array etc., to
+ avoid dumping core.
+
+Thu Jun 19 01:29:44 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970619
+
+ * string.c (str_split_method): wrong limit.
+
+Sat Jun 14 01:54:16 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * class.c (rb_singleton_class): no singleton for special
+ constants (now raises exception).
+
+ * eval.c (ruby_init): cbase in TOPLEVEL_BINDING need to be
+ initialized.
+
+Sat Jun 14 01:01:16 1997 maeda shugo <shugo@po.aianet.ne.jp>
+
+ * array.c (sort_2): wrong comparison.
+
+Sat Jun 14 00:53:44 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * hash.c (hash_foreach): safe iteration.
+
+Fri Jun 13 14:04:56 1997 Michio "Karl" Jinbo <karl@marcer.nagaokaut.ac.jp>
+
+ * configure.in: -Bshareable option for netbsd.
+
+Fri Jun 13 01:16:22 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * io.c (pipe_open): call io_unbuffered() only for writable pipes.
+
+Thu Jun 12 01:14:15 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970612
+
+ * ext/socket/socket.c (sock_new): use io_unbuffered().
+
+ * ext/marshal/marshal.c (w_long): compact long format, which
+ supports 64 bit architectures (unless longs are >32 bit size).
+
+ * ext/marshal/marshal.c: allows recursive data for marshaling.
+
+ * parse.y (rb_intern): raise exception for non-internable string.
+
+ * ext/marshal/marshal.c (marshal_load): allows direct loading from
+ strings.
+
+ * ext/marshal/marshal.c (marshal_dump): allows direct dump to strings.
+
+ * ext/marshal/marshal.c (marshal_dump): interface changed.
+
+Wed Jun 11 18:26:00 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * gc.c (rb_newobj): remove needless memset().
+
+Mon Jun 9 13:03:43 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (rb_eval): reduce condition checks from while/until loop.
+
+ * eval.c (rb_eval): wrong jump point for `next'.
+
+Fri Jun 6 11:47:39 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ruby.c (ruby_set_argv): initialize dln_argv0 for dln_a_out.
+
+ * ext/socket/socket.c (open_unix): display path name for exceptions.
+
+ * ruby.c (proc_options): option -S did not work well.
+
+Fri May 30 02:14:44 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970530
+
+ * eval.c (eval): set $! properly if exception raised in eval().
+
+ * io.c (io_write): now handles non T_FILE object.
+
+ * io.c (io_defset): $< can be anything which has `write' method.
+
+Thu May 29 15:40:22 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (eval): $@ is always an array (not string).
+
+ * pack.c (pack_unpack): avoid corrupting memory for unexpected
+ input strings.
+
+Wed May 28 12:46:13 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970528
+
+ * process.c (rb_waitpid): do not block other threads.
+
+Tue May 27 12:02:31 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (ruby_init): split initialize and processing command line
+ options.
+
+ * ruby.c (ruby_options): ruby_init(0, 0, envp) dumps core.
+
+Tue May 20 18:59:45 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * variable.c (rb_ivar_set): invalid instance variable access for
+ built-in object raises TypeError.
+
+Fri May 16 17:32:21 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970516
+
+ * dir.c (push_globs): was freeing non heap pointer.
+
+ * gc.c: remove some duplicated prototypes.
+
+ * ext/kconv/kconv.c: fix prototypes.
+
+Fri May 9 11:38:59 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970509
+
+ * gc.c (obj_free): avoid free(NULL).
+
+ * eval.c (rb_check_safe_str): argument missing for TypeError().
+
+Thu May 8 01:14:28 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * file.c (file_s_dirname): need to return "." for path without
+ slashes.
+
+Wed May 7 19:18:48 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * process.c (f_fork): child processe does not inherit parent's
+ itimer setting on linux. call setitimer() again in the child
+ process.
+
+Sat May 3 02:49:43 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ext/curses/curses.c: modified for portability and add to the
+ standard distribution.
+
+Wed Apr 30 00:34:00 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * file.c (file_s_size): returns 0 for empty files (not FALSE).
+
+Fri Apr 25 02:17:50 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970425
+
+ * eval.c (f_load): free unused name-table.
+
+ * eval.c (f_load): copy local variable name-table.
+
+ * gc.c (obj_free): avoid free(NULL).
+
+ * eval.c (rb_eval): forgot to make link from the scope object to
+ NODE_SCOPE. It may crash the interpreter.
+
+Thu Apr 24 00:35:09 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * random.c (f_srand): save old seed anyway. srand() returns no
+ value on some systems.
+
+ * gc.c (obj_free): avoid double free of the local variable name
+ table.
+
+ * parse.y (top_local_setup): modify realloc to handle offset.
+
+Tue Apr 22 12:58:26 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970422
+
+Thu Apr 17 00:40:51 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * configure.in (rb_cv_bsdpgrp): proper check for BSD
+ setpgrp/setpgrp.
+
+Wed Apr 16 16:14:02 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (proc_call): proc called in other thread must be orphan.
+
+Tue Apr 15 10:46:31 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970415
+
+ * gc.c (obj_free): NODE_SCOPE marked from SCOPE object.
+
+ * gc.c (gc_mark): some nodes marked wrong.
+
+ * process.c (proc_getpgrp): wrong argument
+
+Fri Apr 14 18:32:42 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970414
+
+Fri Apr 12 01:20:12 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ruby.h: String pointer changed to unsigned char.
+
+Fri Apr 11 10:27:29 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970411
+
+ * Makefile.in: create libruby.a before linking ruby.
+
+ * string.c (str_strip_bang): >0x80 characters for isspace().
+
+ * eval.c (proc_call): set safe-level temporally
+
+ * eval.c (proc_s_new): save safe-level in the proc context.
+
+ * eval.c (rb_eval): no class/module extention in safe mode.
+
+Thu Apr 10 02:10:41 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * gc.c (gc_mark): remove some pointer checks for speeding up.
+
+ * ruby.c (ruby_options): set $0 temporally for -r option.
+
+ * eval.c: built-in security feature.
+
+ * gc.c (gc_sweep): do not free nodes during compile.
+
+ * parse.y (yycompile): set flag when compiling.
+
+Wed Apr 9 10:19:02 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ruby.c: forgot to include <ctype.h> for isspace().
+
+ * file.c: provide S_ISREG for some platforms.
+
+ * io.c (Init_IO): added some $< operations.
+
+ * lib/ping.rb: check host upness using TCP echo.
+
+Tue Apr 8 00:10:15 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * io.c (arg_read): bug with 0 length input.
+
+Mon Apr 7 11:36:16 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ext/fcntl/fcntl.c: module for fcntl constants.
+
+ * eval.c (rb_alias): bug when original was an alias.
+
+ * parse.y (primary): syntax to access singleton class.
+
+ * eval.c (mod_public_method): method's to specify visibitily of
+ the class methods. make_method_{public,private} removed.
+
+Fri Apr 4 21:43:57 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970404
+
+ * gc.c (obj_free): finalizer added for experiment.
+
+Thu Apr 3 02:12:31 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (thread_schedule): make Fatal rise on main_thread on
+ deadlocks.
+
+ * eval.c (thread_join): raise ThreadError instead of Fatal, in
+ case of deadlock.
+
+ * regex.c (re_compile_fastmap): uninitialized local variable.
+
+ * parse.y (parse_regx): new option //[nes] to specify character
+ code for regexp literals. Last specified code option is valid.
+
+ * re.c (reg_s_new): addtional 3rd argument to specify compiled
+ regexp's character code.
+
+ * re.c (reg_new_1): regexp character code can be specified for
+ each regexp object.
+
+Wed Apr 2 14:51:06 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (thread_create): handle uncaught throw.
+
+ * eval.c (thread_create): halt on some deadlock conditions.
+
+ * regex.c (is_in_list): wrong result for non-mbc higher-byte
+ characters.
+
+ * regex.c (re_match): wrong skip for multi-byte characters.
+
+ * regex.c (re_compile_fastmap): wrong fastmap in non-mbc mode.
+
+ * hash.c (Init_Hash): hash compatible features added to ENV.
+
+Tue Apr 1 15:24:06 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (obj_extend): remove Object#extend as an iterator which
+ is in experimental state, since it unveils internal singleton
+ classes.
+
+Mon Mar 31 14:29:39 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970331
+
+Sun Mar 30 19:40:57 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * parse.y (terms): avoided win32 gcc's optimization bug.
+
+Sat Mar 29 11:21:58 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * struct.c (make_struct): St[val,..] creates new structure.
+
+Fri Mar 28 11:24:51 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (obj_make_private): new method make_method_{public,private}
+ to change visibility of singleton methods.
+
+ * regex.c (re_compile_pattern): enables numeric literal >= 0x80 in
+ the character class.
+
+ * regex.c (re_compile_pattern): enabled numeric literal >= 0x80,
+ in multibyte mode.
+
+ * regex.c (re_compile_fastmap): modified exantn and charset(_not)
+ to set fastmap for higher bytes properly.
+
+ * regex.c (is_in_list): now matches numeric literals.
+
+Thu Mar 27 13:34:20 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * pack.c (pack_unpack): extra null byte after unpacked string.
+
+Wed Mar 26 15:20:34 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * regex.c (re_compile_pattern): register numbers must be fit in a
+ byte (0 <= regnum <= 0xff).
+
+ * regex.c (re_compile_fastmap): forgot to set mbchar map for
+ charset_not if RE_MBCTYPE is on.
+
+ * regex.c (re_compile_pattern): set list bits for multi-byte
+ characters for \W, \S, \D in range expression.
+
+ * object.c (obj_is_kind_of): defined that nil itself is kind of
+ nil. TRUE is kind of TRUE, FALSE is kind of FALSE likewise.
+ This change makes `obj.kind_of?(eval(obj.type))' always true.
+
+Tue Mar 25 14:08:43 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * lib/English.rb: provides nicer English alias for the variables.
+
+ * parse.y (expr): alias $var1 $var2 makes alias of the global
+ variable.
+
+Mon Mar 24 18:23:20 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970324
+
+Thu Mar 20 22:04:59 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (mod_modfunc): forget to clear method cache.
+
+Wed Mar 19 17:06:55 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * parse.y (program): set methods' default private/public status
+ correctly under eval().
+
+ * eval.c (eval): set the_class correctly while evaluating string.
+
+Tue Mar 18 12:23:53 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (eval): yield can be called from eval().
+
+ * version 1.0-970318
+
+ * parse.y (program): regexp in condition expression should do
+ matching operation with $_.
+
+ * re.c (reg_regsub): wrong substitution.
+
+Fri Mar 14 14:36:28 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * hash.c (hash_invert): returns value to key mapping of the
+ associative array.
+
+ * ext/socket/extconf.rb: set environment variable SOCKS_SERVER to
+ compile with libsocks.a.
+
+ * ext/socket/socket.c (socks_s_open): SOCKSsocket class to access
+ internet via SOCKS library.
+
+ * sprintf.c (f_sprintf): unsigned formats display leading double
+ dots for imaginary sequence of signed bit to the left.
+
+ * sprintf.c (f_sprintf): correct width and precision formatting
+ for big integers.
+
+ * parse.y (yylex): enables negative hex/octal numbers and `_' in
+ non-decimal numbers.
+
+ * sprintf.c (f_sprintf): %u added for unsigned decimal format.
+
+Thu Mar 13 10:24:27 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * sprintf.c (f_sprintf): wrong output for bignums.
+
+ * array.c (ary_reverse_each): iterates in reverse order.
+
+ * pack.c (pack_unpack): L unpacked signed long.
+
+ * io.c (f_backquote): now returns an empty string for no output.
+
+Wed Mar 12 10:20:30 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ext/socks/socks.c: socket module with socks library.
+
+Mon Mar 10 20:44:22 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * re.c (reg_regsub): \& for substitution. \`, \', and \+ are
+ avaiable also.
+
+Thu Mar 6 01:47:03 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970306
+
+ * sample/rubydb.el (gud): ruby debugger emacs interface
+
+ * lib/debug.rb: ruby debugger
+
+ * parse.y (exprs): more accurate line number display.
+
+Wed Mar 5 21:31:46 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970305
+
+Tue Mar 4 12:28:32 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ruby.c (proc_options): search through RUBYPATH and PATH for
+ option -S.
+
+Mon Mar 3 22:44:55 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (thread_status): returns nil for exception terminated
+ threads.
+
+ * eval.c (thread_value): re-raise exceptions.
+
+Sat Mar 1 00:59:47 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (rb_eval): restore $! value after rescue clause, to
+ re-raise exceptions correctly.
+
+Fri Feb 28 16:43:38 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970228
+
+Thu Feb 27 11:23:41 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (rb_yield_0): redo raises exception
+
+ * eval.c (thread_schedule): bug in interrupt handling by rescue.
+
+Wed Feb 26 00:55:36 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (eval): forgot to restore dynamic local variable
+ bindings.
+
+Tue Feb 25 11:22:08 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ext/aix_ld.rb: AIX dynamic load support (not tested).
+
+ * eval.c (rb_eval): wrong return value for defined? super.
+
+ * error.c (exception): more error check.
+
+ * re.c (reg_regsub): wrong substitution when sub expanded to null
+ string.
+
+Fri Feb 21 13:01:47 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970221
+
+ * eval.c (f_require): volatile added. register variable was
+ recycled, so that GC did not mark that variable.
+
+ * object.c (Init_Object): forget to mark main object (was mostly
+ ok, but made trouble with early GC.)
+
+Thu Feb 20 11:50:50 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970220
+
+Thu Feb 20 11:25:50 1997 Yasuo OHBA <jammy@shljapan.co.jp>
+
+ * lib/date.rb: update
+
+Thu Feb 20 08:25:57 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * parse.y (yylex): forgot tokfix() before rb_intern().
+
+ * lib/tk.rb (TkVariable): give up using trace_var.
+
+Wed Feb 19 00:24:35 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970219
+
+ * pack.c (pack_pack): packed by null for A specifier. must be
+ space filled.
+
+ * pack.c (pack_unpack): bug in skipping spaces
+
+ * gc.c (xmalloc): garbage collect for every 4 Meg. allocation.
+
+ * string.c (str_split_method): limit worked wrong way.
+
+ * io.c (io_gets_method): misunderstand 0xff in binary files when
+ $/ == nil.
+
+ * re.c (reg_regsub): re-implement.
+
+ * ext/socket/socket.c (thread_connect): remove O_NONBLOCK, which
+ is not defined on some platform like NeXT.
+
+Mon Feb 17 13:08:30 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970217
+
+ * object.c (mod_eqq): === extended for subclass check (to use case
+ as typecase).
+
+Sat Feb 15 02:07:22 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * regex.c (re_compile_pattern): wrong match backref at end of pattern.
+
+ * io.c (arg_read): now works beyond end of file.
+
+Thu Feb 13 16:21:24 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * parse.y (expr): return/yield now accept normal argument format.
+
+ * parse.y (yylex): a star in `yield *x' must not be multiplication
+ operator.
+
+Wed Feb 12 15:06:44 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * time.c (time_plus): bug in simple addition.
+
+ * eval.c (thread_raise): raise exceptions from outside.
+
+ * eval.c (Init_Thread): Thread#alive? -- alias for Thread#status.
+
+Mon Feb 10 00:38:55 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ruby.h (Data_Make_Struct): rename macros.
+
+Sun Feb 8 11:48:13 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * io.c (f_syscall): argument offset was wrong.
+
+Fri Feb 7 18:01:17 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970207
+
+ * eval.c: add volatiles to avoid variable crobbering by longjmp().
+
+ * eval.c (f_raise): 1st argument can be the GlobalExit object now.
+
+ * array.c (ary_unshift): no longer accept more than 2 args.
+
+ * eval.c (f_raise): bug if 2nd argument is the exception.
+
+Tue Feb 4 00:37:29 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970204
+
+ * eval.c (eval): check compile errors by nerrs.
+
+ * eval.c (rb_eval): check syntax error by nerrs, not by the return
+ value, which may be NULL.
+
+ * eval.c (compile): Do not clear errinfo.
+
+Mon Feb 3 10:13:06 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (obj_extend): move real inclusion to Module#extend_object
+ to allow redfinition.
+
+ * object.c (Init_Object): Kernel class is now Module. Object class
+ became the true root class.
+
+ * object.c (obj_inspect): remove useless buffer.
+
+ * hash.c (any_cmp): disable interrupts and context switching.
+
+ * st.c: remove ALLOW_INTS to disable interrupt during operations.
+
+Fri Jan 31 22:10:08 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * hash.c (hash_rehash): re-register all key-value.
+
+Thu Jan 30 02:14:49 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * io.c (io_reopen): re-implement according to clone() way.
+
+ * io.c (io_clone): copy IO object.
+
+ * struct.c (struct_eql): compare elements by eql?.
+
+ * io.c (io_mode_flags): detect "rb", "wb" etc.
+
+ * io.h (FMODE_BINMODE): added.
+
+ * ext/socket/socket.c (Init_socket): undef BasicSocket.new
+
+ * file.c (Init_File): File.new(path[,mode])
+
+ * io.c (Init_IO): IO.new(fd[,mode])
+
+ * eval.c (rb_method_boundp): forgot to enable priv argument.
+
+ * object.c (Init_Object): remove `=~' from Kernel class.
+
+ * ext/socket/socket.c (open_inet): initialize sockaddr before
+ calling bind(2).
+
+ * sample/ruby-mode.el (ruby-calculate-indent): skip comment lines
+
+Wed Jan 29 18:43:22 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (Init_Thread): DEFER_INTS during initializing threads.
+
+ * hash.c (Init_Hash): Hash#eql? checks for object identity.
+
+ * eval.c (thread_set_critical): wrong value assigned.
+
+Mon Jan 27 16:10:51 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * io.c (io_print): remove print_on().
+
+ * eval.c (f_missing): proper error message for undefined method
+ without argument
+
+Sat Jan 25 23:32:32 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * string.c (str_sub_s): false alert - sub() does not modify string.
+
+ * array.c (ary_times): negative multiplication detected
+
+ * string.c (str_times): negative multiplication detected
+
+Fri Jan 24 10:51:39 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * time.c (time_arg): month -> 0 == "jan" == "1" == "01", little bit
+ confusing but wanted to conform japanese style.
+
+ * version 1.0-970124
+
+Fri Jan 24 09:52:49 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * util.c (_fixpath): supports SJIS filenames on DJGPP.
+
+Thu Jan 23 16:52:06 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * README.EXT: update. partially translated into English.
+
+ * ext/extmk.rb.in: inherit $LDFLAGS to the final link.
+
+ * ext/socket/socket.c (Init_socket): add various constants.
+
+Mon Jan 23 11:40:59 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * eval.c (Init_Thread): allocate main_thread first to avoid crash.
+
+Thu Jan 23 02:09:26 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * gc.c (ObjectSpace): API modified. each_object method will do all
+ the iteration.
+
+ * eval.c (proc_call): wrong return from nested lambda.
+
+ * ext/GD/GD.c: debugged.
+
+Wed Jan 22 16:12:25 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970122
+
+ * gc.c (gc_mark): forgot to mark match->str.
+
+ * ext/GD/GD.c: GD interface module.
+
+ * eval.c (PUSH_BLOCK): wrong value pushed as the block level.
+
+Mon Jan 20 14:01:31 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (thread_run): no context switch in the critical section.
+
+Mon Jan 20 09:40:59 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * utils.c: supports 8+3 filenames
+
+Sat Jan 18 01:23:03 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970118
+
+ * regex.c (PATFETCH): need cast to unsigned char.
+
+ * io.c (io_ctl): bug in case when arg is not a string.
+
+ * lib/tk.rb: forgot that Kernel#type returns the class name now.
+
+ * regex.c (re_search): "abc\n" =~ "^$" should not match.
+
+Fri Jan 17 12:31:37 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970117
+
+ * ruby.c (ruby_options): constant PLATFORM, which is in the {cpu}-{os}
+ form, defined.
+
+ * configure.in: platform infomation embedded in the interpreter.
+
+ * regex.c (re_search): /^$/ did not match to "" by wrong exit condition.
+
+ * lib/thread.rb: re-write Mutex/Queue based on Thread.critical.
+
+ * eval.c (thread_set_critical): remove Thread.exclusive, add
+ Thread.critical = TRUE/FALSE instead.
+
+ * re.c (reg_search): re-compile pattern if needed
+
+ * regex.c (PATFETCH): do translate at compile time
+
+Thu Jan 16 00:49:10 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * gc.c (gc_mark_frame): forgot to mark frame->cbase.
+
+ * regex.c (re_compile_pattern): /a$|b)/ causes error.
+
+ * regex.c (re_compile_pattern): /(^|b)/ causes error.
+
+ * version 1.0-970116
+
+ * re.c (Init_Regexp): set RE_CONTEXTUAL_INVALID_OPS flag.
+
+Tue Jan 14 02:09:06 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (proc_call): Proc#call򥤥ƥ졼ȤƸƤб
+
+ * configure.in: nextstepб
+
+ * eval.c (rb_eval): a[b]=c̵̤Ƥʤ
+
+ * eval.c (f_send): ƥ졼ȤƸƤФ줿饤ƥ졼Ȥƥ᥽
+ ɤƤ֡
+
+ * string.c (str_new4): matchͭѤؿ
+
+ * re.c (reg_search): matchμ(ʸ)ޥåԤäʸ
+ copy-on-writeǶͭ
+
+ * string.c (str_hash): toupper򤫤郎äƤ
+
+ * array.c (sort_2): 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б
diff --git a/MANIFEST b/MANIFEST
index 3b0ba3e..587294b 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -66,21 +66,36 @@ version.c
version.h
ext/Setup
ext/Setup.dj
+ext/Setup.nt
+ext/Setup.x68
ext/extmk.rb.in
+ext/extmk.rb.nt
+ext/aix_ld.rb
+lib/English.rb
lib/base64.rb
lib/cgi-lib.rb
lib/complex.rb
+lib/date.rb
+lib/debug.rb
+lib/e2mmap.rb
+lib/e2mmap1_0.rb
lib/find.rb
+lib/finalize.rb
+lib/ftplib.rb
lib/getopts.rb
lib/jcode.rb
lib/mailread.rb
lib/mathn.rb
+lib/matrix.rb
+lib/mutex_m.rb
lib/observer.rb
lib/parsearg.rb
lib/parsedate.rb
+lib/ping.rb
lib/rational.rb
-lib/safe.rb
+lib/sync.rb
lib/thread.rb
+lib/thwait.rb
lib/tk.rb
lib/tkcore.rb
lib/tkcanvas.rb
@@ -89,15 +104,19 @@ lib/tkentry.rb
lib/tkscrollbox.rb
lib/tktext.rb
lib/tkthcore.rb
+lib/tracer.rb
missing/alloca.c
missing/crypt.c
+missing/dir.h
missing/dup2.c
+missing/file.h
missing/flock.c
missing/memmove.c
missing/mkdir.c
missing/nt.c
missing/nt.h
missing/setenv.c
+missing/strcasecmp.c
missing/strdup.c
missing/strerror.c
missing/strftime.c
@@ -107,7 +126,7 @@ missing/strtoul.c
sample/biorhythm.rb
sample/cbreak.rb
sample/clnt.rb
-sample/dbm.rb
+sample/dbmtest.rb
sample/dir.rb
sample/eval.rb
sample/export.rb
@@ -126,7 +145,7 @@ sample/less.rb
sample/list.rb
sample/list2.rb
sample/list3.rb
-sample/marshal.rb
+sample/mrshtest.rb
sample/mkproto.rb
sample/mpart.rb
sample/observ.rb
@@ -140,6 +159,8 @@ sample/rcs.dat
sample/rcs.rb
sample/regx.rb
sample/ruby-mode.el
+sample/rubydb2x.el
+sample/rubydb3x.el
sample/sieve.rb
sample/svr.rb
sample/test.rb
@@ -154,3 +175,11 @@ sample/tktimer.rb
sample/trojan.rb
sample/tsvr.rb
sample/uumerge.rb
+win32/Makefile
+win32/config.h
+win32/ntsetup.bat
+win32/ruby.def
+x68/fconvert.c
+x68/select.c
+x68/_dtos18.c
+x68/_round.c
diff --git a/Makefile.in b/Makefile.in
index aa01896..ee0ac1f 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -3,32 +3,40 @@ SHELL = /bin/sh
#### Start of system configuration section. ####
srcdir = @srcdir@
-VPATH = @srcdir@
+VPATH = @srcdir@:@srcdir@/missing
CC = @CC@
YACC = @YACC@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
-PURIFY=
+PURIFY =
@SET_MAKE@
-CFLAGS = @CFLAGS@ -I.
-STATIC = @STATIC@
-LDFLAGS = $(CFLAGS) @LDFLAGS@
-LIBS = -lm @LIBS@ $(EXTLIBS)
+CFLAGS = @CFLAGS@ -I@srcdir@
+LDFLAGS = @STATIC@ $(CFLAGS) @LDFLAGS@
+LIBS = @LIBS@ $(EXTLIBS)
MISSING = @LIBOBJS@ @ALLOCA@
+program_transform_name = -e @program_transform_name@
+RUBY_INSTALL_NAME = `t='$(program_transform_name)'; echo ruby | sed $$t`
+
prefix = @prefix@
-binprefix =
exec_prefix = @exec_prefix@
-bindir = $(exec_prefix)/bin
-libdir = @prefix@/lib/ruby
+bindir = @bindir@
+libdir = @libdir@/$(RUBY_INSTALL_NAME)
+
+binsuffix = @binsuffix@
#### End of system configuration section. ####
+
+LIBRUBY = libruby.a
+
EXTOBJS = dmyext.o
+MAINOBJ = main.o
+
OBJS = array.o \
bignum.o \
class.o \
@@ -45,7 +53,6 @@ OBJS = array.o \
hash.o \
inits.o \
io.o \
- main.o \
math.o \
numeric.o \
object.o \
@@ -66,41 +73,44 @@ OBJS = array.o \
util.o \
variable.o \
version.o \
- $(MISSING) \
- $(EXTOBJS)
-
-PROGRAM = miniruby
+ $(MISSING)
-all: extruby
-
-extruby: miniruby ext/Setup
+all: miniruby$(binsuffix) @srcdir@/ext/Setup
@if test -z "$$UNDER_EXTMAKE_RB"; \
then echo "Compiling ext modules"; \
UNDER_EXTMAKE_RB=yes; export UNDER_EXTMAKE_RB; \
cd ext; ../miniruby ./extmk.rb @EXTSTATIC@; fi
-$(PROGRAM): $(OBJS)
- @rm -f $(PROGRAM)
- $(PURIFY) $(CC) $(STATIC) $(LDFLAGS) $(OBJS) $(LIBS) -o $(PROGRAM)
+miniruby$(binsuffix): $(OBJS) $(MAINOBJ) $(EXTOBJS)
+ @rm -f $@
+ $(PURIFY) $(CC) $(LDFLAGS) $(MAINOBJ) $(OBJS) $(EXTOBJS) $(LIBS) -o miniruby
+
+ruby$(binsuffix): $(LIBRUBY) $(MAINOBJ) $(EXTOBJS)
+ @rm -f $@
+ $(PURIFY) $(CC) $(LDFLAGS) $(MAINOBJ) $(EXTOBJS) $(LIBRUBY) $(LIBS) -o ruby
+
+$(LIBRUBY): $(OBJS) dmyext.o
+ @AR@ rcu $(LIBRUBY) $(OBJS) dmyext.o
+ @-@RANLIB@ $(LIBRUBY) 2> /dev/null || true
-install:; $(INSTALL_PROGRAM) ruby $(bindir)/ruby
- @-@STRIP@ $(bindir)/ruby
+install:; $(INSTALL_PROGRAM) ruby$(binsuffix) $(bindir)/$(RUBY_INSTALL_NAME)$(binsuffix)
+ @-@STRIP@ $(bindir)/$(RUBY_INSTALL_NAME)$(binsuffix)
@test -d $(libdir) || mkdir $(libdir)
cd ext; ../miniruby ./extmk.rb install
- @for rb in `grep '^lib/' MANIFEST`; do \
- $(INSTALL_DATA) $$rb $(libdir); \
+ @for rb in `grep '^lib/' @srcdir@/MANIFEST`; do \
+ $(INSTALL_DATA) @srcdir@/$$rb $(libdir); \
done
-clean:; @rm -f $(OBJS)
- @rm -f ext/extinit.c ext/extinit.o
+clean:; @rm -f $(OBJS) $(LIBRUBY) $(MAINOBJ)
+ @rm -f ext/extinit.c ext/extinit.o dmyext.o
cd ext; ../miniruby ./extmk.rb clean
realclean: clean
- @rm -f Makefile ext/extmk.rb
+ @rm -f Makefile ext/extmk.rb ext/config.cache parse.c
@rm -f config.cache config.h config.log config.status
- @rm -f core ruby miniruby *~
+ @rm -f core ruby$(binsuffix) miniruby$(binsuffix) parse.c *~ *.core gmon.out
-test:; @-./ruby sample/test.rb > ./ruby_test 2>&1; \
+test:; @-./ruby @srcdir@/sample/test.rb > ./ruby_test 2>&1; \
if grep '^end of test' ./ruby_test > /dev/null; then \
echo "test succeeded"; \
else \
@@ -113,47 +123,57 @@ test:; @-./ruby sample/test.rb > ./ruby_test 2>&1; \
.c.o:
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
-alloca.o: missing/alloca.c
- $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/alloca.c
+parse.c: parse.y
+ $(YACC) $<
+ mv -f y.tab.c parse.c
+
+alloca.o: @srcdir@/missing/alloca.c
+ $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/alloca.c
+
+crypt.o: @srcdir@/missing/crypt.c
+ $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/crypt.c
+
+dup2.o: @srcdir@/missing/dup2.c
+ $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/dup2.c
-crypt.o: missing/crypt.c
- $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/crypt.c
+flock.o: @srcdir@/missing/flock.c
+ $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/flock.c
-dup2.o: missing/dup2.c
- $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/dup2.c
+memmove.o: @srcdir@/missing/memmove.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/memmove.c
-flock.o: missing/flock.c
- $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/flock.c
+mkdir.o: @srcdir@/missing/mkdir.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/mkdir.c
-memmove.o: missing/memmove.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/memmove.c
+setenv.o: @srcdir@/missing/setenv.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/setenv.c
-mkdir.o: missing/mkdir.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/mkdir.c
+strcasecmp.o: @srcdir@/missing/strcasecmp.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strcasecmp.c
-setenv.o: missing/setenv.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/setenv.c
+strerror.o: @srcdir@/missing/strerror.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strerror.c
-strerror.o: missing/strerror.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/strerror.c
+strdup.o: @srcdir@/missing/strdup.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strdup.c
-strdup.o: missing/strdup.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/strdup.c
+strftime.o: @srcdir@/missing/strftime.c
+ $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strftime.c
-strftime.o: missing/strftime.c
- $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/strftime.c
+strstr.o: @srcdir@/missing/strstr.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strstr.c
-strstr.o: missing/strstr.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/strstr.c
+strtol.o: @srcdir@/missing/strtol.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strtol.c
-strtol.o: missing/strtol.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/strtol.c
+strtoul.o: @srcdir@/missing/strtoul.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strtoul.c
-strtoul.o: missing/strtoul.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/strtoul.c
+nt.o: @srcdir@/missing/nt.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/nt.c
-nt.o: missing/nt.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/nt.c
+x68.o: @srcdir@/missing/x68.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/x68.c
# Prevent GNU make v3 from overflowing arg limit on SysV.
.NOEXPORT:
diff --git a/README b/README
index debf3e4..6583bc8 100644
--- a/README
+++ b/README
@@ -23,16 +23,7 @@ perl). It is simple, straight-forward, and extensible.
The ruby distribution can be found on
- ftp://ftp.caelum.co.jp/pub/lang/ruby/
-
-** by mail
-
-Send the mail which subject is 'send' to the address below.
-
- ruby-archive@caelum.co.jp
-
-You will receive the uuencoded gzipped tar file of the newest ruby
-distribution.
+ ftp://ftp.netlab.co.jp/pub/lang/ruby/
* How to compile and install
@@ -61,13 +52,13 @@ the error log and machine/OS type, to help others.
* Copying
-Ruby is copyrighted by Yukihiro Matsumoto <matz@caelum.co.jp>.
+Ruby is copyrighted by Yukihiro Matsumoto <matz@ruby.club.co.jp>.
This source is distributed under the conditions blow:
1. You may make and give away verbatim copies of the source form of
the software without restriction, provided that you do not modify
- the original distribution file.
+ the original distribution files.
If you want to distribute the modified version in any way, contact
the author.
@@ -80,11 +71,11 @@ This source is distributed under the conditions blow:
distribute the modified version.
4. You may modify and include the part of the software into any other
- software (possibly commercial). But some files in the
- distribution are not written by the author, so that they are not
- under this terms. They are gc.c(partly)regex.[ch]fnmatch.[ch]
- glob.c, st.[ch] and somme files under ./missing directory. See
- each files for the condition.
+ software (possibly commercial). But some files in the distribution
+ are not written by the author, so that they are not under this terms.
+ They are gc.c(partly)utils.c(partly), regex.[ch]fnmatch.[ch]
+ glob.c, st.[ch] and somme files under the ./missing directory. See
+ each files for the copying condition.
5. The scripts and library files supplied as input to or produced as
output from the software do not automatically fall under the
@@ -101,14 +92,14 @@ This source is distributed under the conditions blow:
The URL of the ruby home-page is:
- http://www.caelum.co.jp/~matz/ruby/index-en.html
+ http://www.netlab.co.jp/ruby/
* The Author
Feel free to send comments and bug reports to the author. Here is the
author's latest mail address:
- matz@ruby.club.or.jp
+ matz@netlab.co.jp
-------------------------------------------------------
created at: Thu Aug 3 11:57:36 JST 1995
diff --git a/README.EXT b/README.EXT
index fdf8c96..c2f81d1 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ޥ
** 饹/⥸塼
diff --git a/README.jp b/README.jp
index 06c0832..8a10010 100644
--- a/README.jp
+++ b/README.jp
@@ -27,22 +27,13 @@ RubyϥƥȽطǽϤʤɤͥ졤perlƱ餤
ʲξˤƤޤ
- ftp://ftp.caelum.co.jp/pub/lang/ruby/
-
-** ᥤ
-
-ʲΥɥ쥹`send'ȤSubjectΥᥤäƲ
-
- ruby-archive@caelum.co.jp
-
-ʸˤϲ񤤤Ƥ⹽ޤޤ֤ǿǤruby
+ ftp://ftp.netlab.co.jp/pub/lang/ruby/
* ۡڡ
RubyΥۡڡURL
- http://www.caelum.co.jp/~matz/ruby/
+ http://www.netlab.co.jp/ruby/jp/
Ǥ
@@ -51,7 +42,7 @@ RubyϥƥȽطǽϤʤɤͥ졤perlƱ餤
Ruby˴ؤΤΥᥤ󥰥ꥹȤߤޤ
ɥ쥹
- ruby-list@caelum.co.jp
+ ruby-list@netlab.co.jp
ǤΥɥ쥹˥ᥤСưŪϿޤ
@@ -133,9 +124,9 @@ UNIXǤconfigureۤȤɤκۤۼƤϤ
ʤŪǤ켫ͳǤruby˴ޤޤ¾κ
Ԥˤ륳ɤϡ줾κԤΰոˤ¤ä
- ޤŪˤgc.c()regex.[ch]fnmatch.[ch]
- glob.c, st.[ch]missingǥ쥯ȥ겼Υե뷲
- ޤ
+ ޤŪˤgc.c()util.c()regex.[ch]
+ fnmatch.[ch]glob.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:
diff --git a/ToDo b/ToDo
index cfac898..3b6edee 100644
--- a/ToDo
+++ b/ToDo
@@ -1,5 +1,4 @@
+* non-blocking open/write for thread
* ѥåޤѿΥ
* formatǽ
-* perlΤ褦setuid check
-* write debugger for ruby
* re-write regex code for speed and copyright
diff --git a/array.c b/array.c
index 741f09b..c1ad998 100644
--- a/array.c
+++ b/array.c
@@ -20,14 +20,43 @@ VALUE rb_to_a();
void
memclear(mem, size)
- VALUE *mem;
- int size;
+ register VALUE *mem;
+ register int size;
{
while (size--) {
*mem++ = Qnil;
}
}
+#define ARY_FREEZE FL_USER1
+
+static void
+ary_modify(ary)
+ VALUE ary;
+{
+ rb_secure(5);
+ if (FL_TEST(ary, ARY_FREEZE)) {
+ TypeError("can't modify frozen array");
+ }
+}
+
+VALUE
+ary_freeze(ary)
+ VALUE ary;
+{
+ FL_SET(ary, ARY_FREEZE);
+ return ary;
+}
+
+static VALUE
+ary_frozen_p(ary)
+ VALUE ary;
+{
+ if (FL_TEST(ary, ARY_FREEZE))
+ return TRUE;
+ return FALSE;
+}
+
VALUE
ary_new2(len)
int len;
@@ -148,12 +177,13 @@ ary_s_create(argc, argv, class)
return (VALUE)ary;
}
-static void
-astore(ary, idx, val)
+void
+ary_store(ary, idx, val)
struct RArray *ary;
int idx;
VALUE val;
{
+ ary_modify(ary);
if (idx < 0) {
IndexError("negative index for array");
}
@@ -177,7 +207,7 @@ ary_push(ary, item)
struct RArray *ary;
VALUE item;
{
- astore(ary, ary->len, item);
+ ary_store(ary, ary->len, item);
return (VALUE)ary;
}
@@ -188,7 +218,7 @@ ary_push_method(argc, argv, ary)
struct RArray *ary;
{
while (argc--) {
- astore(ary, ary->len, *argv++);
+ ary_store(ary, ary->len, *argv++);
}
return (VALUE)ary;
}
@@ -231,6 +261,7 @@ ary_unshift(ary, item)
struct RArray *ary;
int item;
{
+ ary_modify(ary);
if (ary->len >= ary->capa) {
ary->capa+=ARY_DEFAULT_SIZE;
REALLOC_N(ary->ptr, VALUE, ary->capa);
@@ -243,18 +274,6 @@ ary_unshift(ary, item)
return ary->ptr[0] = item;
}
-static VALUE
-ary_unshift_method(argc, argv, ary)
- int argc;
- VALUE *argv;
- VALUE ary;
-{
- while (argc--) {
- ary_unshift(ary, argv[argc]);
- }
- return (VALUE)ary;
-}
-
VALUE
ary_entry(ary, offset)
struct RArray *ary;
@@ -402,7 +421,7 @@ ary_indexes(ary, args)
p = args->ptr; pend = p + args->len;
while (p < pend) {
- astore(new_ary, i++, ary_entry(ary, NUM2INT(*p)));
+ ary_store(new_ary, i++, ary_entry(ary, NUM2INT(*p)));
p++;
}
return new_ary;
@@ -413,6 +432,7 @@ ary_replace(ary, beg, len, rpl)
struct RArray *ary, *rpl;
int beg, len;
{
+ ary_modify(ary);
if (TYPE(rpl) != T_ARRAY) {
rpl = (struct RArray*)rb_to_a(rpl);
}
@@ -490,11 +510,11 @@ ary_aset(argc, argv, ary)
if (offset < 0) {
offset = ary->len + offset;
}
- astore(ary, offset, arg2);
+ ary_store(ary, offset, arg2);
return arg2;
}
-static VALUE
+VALUE
ary_each(ary)
struct RArray *ary;
{
@@ -519,6 +539,18 @@ ary_each_index(ary)
}
static VALUE
+ary_reverse_each(ary)
+ struct RArray *ary;
+{
+ int len = ary->len;
+
+ while (len--) {
+ rb_yield(ary->ptr[len]);
+ }
+ return Qnil;
+}
+
+static VALUE
ary_length(ary)
struct RArray *ary;
{
@@ -575,6 +607,7 @@ ary_join(ary, sep)
}
if (!NIL_P(sep)) str_cat(result, sep->ptr, sep->len);
str_cat(result, RSTRING(tmp)->ptr, RSTRING(tmp)->len);
+ if (str_tainted(tmp)) str_taint(result);
}
return result;
@@ -590,9 +623,7 @@ ary_join_method(argc, argv, ary)
rb_scan_args(argc, argv, "01", &sep);
if (NIL_P(sep)) sep = OFS;
-
- if (!NIL_P(sep))
- Check_Type(sep, T_STRING);
+ if (!NIL_P(sep)) Check_Type(sep, T_STRING);
return ary_join(ary, sep);
}
@@ -628,7 +659,6 @@ ary_inspect(ary)
{
int i, len;
VALUE s, str;
- char *p;
if (ary->len == 0) return str_new2("[]");
str = str_new2("[");
@@ -707,6 +737,13 @@ sort_2(a, b)
{
VALUE retval;
+ if (FIXNUM_P(*a)) {
+ if (FIXNUM_P(*b)) return *a - *b;
+ }
+ else if (TYPE(*a) == T_STRING) {
+ if (TYPE(*b) == T_STRING) return str_cmp(*a, *b);
+ }
+
retval = rb_funcall(*a, cmp, 1, *b);
return NUM2INT(retval);
}
@@ -715,6 +752,7 @@ VALUE
ary_sort_bang(ary)
struct RArray *ary;
{
+ ary_modify(ary);
qsort(ary->ptr, ary->len, sizeof(VALUE), iterator_p()?sort_1:sort_2);
return (VALUE)ary;
}
@@ -726,13 +764,14 @@ ary_sort(ary)
return ary_sort_bang(ary_clone(ary));
}
-static VALUE
+VALUE
ary_delete(ary, item)
struct RArray *ary;
VALUE item;
{
int i1, i2;
+ ary_modify(ary);
for (i1 = i2 = 0; i1 < ary->len; i1++) {
if (rb_equal(ary->ptr[i1], item)) continue;
if (i1 != i2) {
@@ -741,13 +780,14 @@ ary_delete(ary, item)
i2++;
}
if (ary->len == i2) {
- if (iterator_p()) rb_yield(Qnil);
+ if (iterator_p()) rb_yield(item);
+ return Qnil;
}
else {
ary->len = i2;
}
- return (VALUE)ary;
+ return item;
}
VALUE
@@ -758,6 +798,7 @@ ary_delete_at(ary, at)
int i1, i2, pos;
VALUE del = Qnil;
+ ary_modify(ary);
pos = NUM2INT(at);
for (i1 = i2 = 0; i1 < ary->len; i1++) {
if (i1 == pos) {
@@ -780,6 +821,7 @@ ary_delete_if(ary)
{
int i1, i2;
+ ary_modify(ary);
for (i1 = i2 = 0; i1 < ary->len; i1++) {
if (rb_yield(ary->ptr[i1])) continue;
if (i1 != i2) {
@@ -792,6 +834,21 @@ ary_delete_if(ary)
return (VALUE)ary;
}
+#if 0
+static VALUE
+ary_replace(ary)
+ struct RArray *ary;
+{
+ int i;
+
+ for (i = 0; i < ary->len; i++) {
+ ary->ptr[i] = rb_yield(ary->ptr[i]);
+ }
+
+ return (VALUE)ary;
+}
+#endif
+
static VALUE
ary_clear(ary)
struct RArray *ary;
@@ -871,7 +928,6 @@ VALUE
ary_concat(x, y)
struct RArray *x, *y;
{
- struct RArray *z;
VALUE *p, *pend;
if (TYPE(y) != T_ARRAY) {
@@ -881,7 +937,7 @@ ary_concat(x, y)
p = y->ptr;
pend = p + y->len;
while (p < pend) {
- astore(x, x->len, *p);
+ ary_store(x, x->len, *p);
p++;
}
return (VALUE)x;
@@ -903,6 +959,10 @@ ary_times(ary, times)
ary2 = (struct RArray*)ary_new2(len);
ary2->len = len;
+ if (len < 0) {
+ ArgError("negative argument");
+ }
+
for (i=0; i<len; i+=ary->len) {
MEMCPY(ary2->ptr+i, ary->ptr, VALUE, ary->len);
}
@@ -962,21 +1022,34 @@ ary_equal(ary1, ary2)
}
static VALUE
+ary_eql(ary1, ary2)
+ struct RArray *ary1, *ary2;
+{
+ int i;
+
+ if (TYPE(ary2) != T_ARRAY) return FALSE;
+ if (ary1->len != ary2->len) return FALSE;
+ for (i=0; i<ary1->len; i++) {
+ if (!rb_eql(ary1->ptr[i], ary2->ptr[i]))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static VALUE
ary_hash(ary)
struct RArray *ary;
{
- int i, h;
- ID hash = rb_intern("hash");
+ int h, i;
- h = 0;
+ h = ary->len;
for (i=0; i<ary->len; i++) {
- h ^= rb_funcall(ary->ptr[i], hash, 0);
+ h ^= rb_hash(ary->ptr[i]);
}
- h += ary->len;
return INT2FIX(h);
}
-static VALUE
+VALUE
ary_includes(ary, item)
struct RArray *ary;
VALUE item;
@@ -1055,6 +1128,7 @@ ary_compact_bang(ary)
{
VALUE *p, *t, *end;
+ ary_modify(ary);
p = t = ary->ptr;
end = p + ary->len;
while (t < end) {
@@ -1104,10 +1178,13 @@ Init_Array()
rb_define_method(cArray, "inspect", ary_inspect, 0);
rb_define_method(cArray, "to_a", ary_to_a, 0);
- rb_define_method(cArray, "print_on", ary_print_on, 1);
+ rb_define_method(cArray, "freeze", ary_freeze, 0);
+ rb_define_method(cArray, "frozen?", ary_frozen_p, 0);
rb_define_method(cArray, "==", ary_equal, 1);
+ rb_define_method(cArray, "eql?", ary_eql, 1);
rb_define_method(cArray, "hash", ary_hash, 0);
+
rb_define_method(cArray, "[]", ary_aref, -1);
rb_define_method(cArray, "[]=", ary_aset, -1);
rb_define_method(cArray, "concat", ary_concat, 1);
@@ -1115,9 +1192,10 @@ Init_Array()
rb_define_method(cArray, "push", ary_push_method, -1);
rb_define_method(cArray, "pop", ary_pop, 0);
rb_define_method(cArray, "shift", ary_shift, 0);
- rb_define_method(cArray, "unshift", ary_unshift_method, -1);
+ rb_define_method(cArray, "unshift", ary_unshift, 1);
rb_define_method(cArray, "each", ary_each, 0);
rb_define_method(cArray, "each_index", ary_each_index, 0);
+ rb_define_method(cArray, "reverse_each", ary_reverse_each, 0);
rb_define_method(cArray, "length", ary_length, 0);
rb_define_alias(cArray, "size", "length");
rb_define_method(cArray, "empty?", ary_empty_p, 0);
@@ -1132,10 +1210,12 @@ Init_Array()
rb_define_method(cArray, "delete", ary_delete, 1);
rb_define_method(cArray, "delete_at", ary_delete_at, 1);
rb_define_method(cArray, "delete_if", ary_delete_if, 0);
+#if 0
+ rb_define_method(cArray, "replace", ary_replace, 0);
+#endif
rb_define_method(cArray, "clear", ary_clear, 0);
rb_define_method(cArray, "fill", ary_fill, -1);
rb_define_method(cArray, "include?", ary_includes, 1);
- rb_define_method(cArray, "includes?", ary_includes, 1); /* obsolate */
rb_define_method(cArray, "assoc", ary_assoc, 1);
rb_define_method(cArray, "rassoc", ary_rassoc, 1);
diff --git a/bignum.c b/bignum.c
index e3bd528..8af40d6 100644
--- a/bignum.c
+++ b/bignum.c
@@ -65,9 +65,17 @@ big_2comp(x) /* get 2's complement */
ds[i++] = BIGLO(num);
num = BIGDN(num);
} while (i < x->len);
+ if (ds[0] == 1 || ds[0] == 0) {
+ for (i=1;i<x->len;i++) {
+ if (ds[i] != 0) return;
+ }
+ REALLOC_N(BDIGITS(x), USHORT, x->len++);
+ ds = BDIGITS(x);
+ ds[x->len-1] = 1;
+ }
}
-VALUE
+static VALUE
bignorm(x)
struct RBignum *x;
{
@@ -150,7 +158,7 @@ int2inum(n)
VALUE
str2inum(str, base)
- char *str;
+ UCHAR *str;
int base;
{
char sign = 1, c;
@@ -189,7 +197,7 @@ str2inum(str, base)
}
if (len <= (sizeof(VALUE)*CHAR_BIT)) {
- UINT val = strtoul(str, 0, base);
+ UINT val = strtoul((char*)str, 0, base);
if (POSFIXABLE(val)) {
if (sign) return INT2FIX(val);
@@ -256,7 +264,7 @@ big2str(x, base)
USHORT *ds;
UINT i, j, hbase;
VALUE ss;
- char *s, c;
+ UCHAR *s, c;
if (FIXNUM_P(x)) {
return fix2str(x, base);
@@ -431,6 +439,14 @@ big_cmp(x, y)
}
static VALUE
+big_eq(x, y)
+ VALUE x, y;
+{
+ if (big_cmp(x, y) == INT2FIX(0)) return TRUE;
+ return FALSE;
+}
+
+static VALUE
big_uminus(x)
struct RBignum *x;
{
@@ -487,35 +503,20 @@ bigsub(x, y)
z = (struct RBignum*)bignew(x->len, (z == 0)?1:0);
zds = BDIGITS(z);
- i = x->len;
- while (i--) zds[i] = BDIGITS(x)[i];
-
- i = 0; num = 0;
- do {
- num += (long)zds[i] - BDIGITS(y)[i];
- if (num < 0) {
- zds[i] = num + BIGRAD;
- num = -1;
- }
- else {
- zds[i] = BIGLO(num);
- num = 0;
- }
- } while (++i < y->len);
- if (num) {
- while (num && i < x->len) {
- num += zds[i];
- if (num < 0) {
- zds[i++] = num + BIGRAD;
- num = -1;
- }
- else {
- zds[i++] = BIGLO(num);
- num = 0;
- }
- }
+ for (i = 0, num = 0; i < y->len; i++) {
+ num += (long)BDIGITS(x)[i] - BDIGITS(y)[i];
+ zds[i] = BIGLO(num);
+ num = BIGDN(num);
+ }
+ while (num && i < x->len) {
+ num += BDIGITS(x)[i];
+ zds[i++] = BIGLO(num);
+ num = BIGDN(num);
}
-
+ while (i < x->len) {
+ zds[i++] = BDIGITS(x)[i];
+ }
+
return bignorm(z);
}
@@ -525,10 +526,8 @@ bigadd(x, y, sign)
char sign;
{
struct RBignum *z;
- USHORT *zds;
long num;
UINT i, len;
-
if (x->sign == (y->sign ^ sign)) {
if (y->sign == sign) return bigsub(y, x);
return bigsub(x, y);
@@ -541,27 +540,24 @@ bigadd(x, y, sign)
len = y->len + 1;
}
z = (struct RBignum*)bignew(len, sign==y->sign);
- zds = BDIGITS(z);
-
- i = len;
- while (i--) zds[i] = 0;
- i = y->len;
- while (i--) zds[i] = BDIGITS(y)[i];
- i = 0; num = 0;
- do {
- num += (long)zds[i] + BDIGITS(x)[i];
- zds[i++] = BIGLO(num);
- num = BIGDN(num);
- } while (i < x->len);
- if (num) {
- while (i < y->len) {
- num += zds[i];
- zds[i++] = BIGLO(num);
- num = BIGDN(num);
- }
- BDIGITS(z)[i] = num;
+ if (x->len > y->len) {
+ struct RBignum* t = x; x = y; y = t;
+ }
+ for (i = 0, num = 0; i < x->len; i++) {
+ num += (long)(BDIGITS(x)[i]) + BDIGITS(y)[i];
+ BDIGITS(z)[i] = BIGLO(num);
+ num = BIGDN(num);
}
+ while (num && i < y->len) {
+ num += BDIGITS(y)[i];
+ BDIGITS(z)[i++] = BIGLO(num);
+ num = BIGDN(num);
+ }
+ while (i < y->len) {
+ BDIGITS(z)[i++] = BDIGITS(y)[i];
+ }
+ BDIGITS(z)[i] = num;
return bignorm(z);
}
@@ -570,8 +566,6 @@ VALUE
big_plus(x, y)
VALUE x, y;
{
- VALUE z;
-
switch (TYPE(y)) {
case T_FIXNUM:
y = int2big(FIX2INT(y));
@@ -591,8 +585,6 @@ VALUE
big_minus(x, y)
VALUE x, y;
{
- VALUE cmp;
-
switch (TYPE(y)) {
case T_FIXNUM:
y = int2big(FIX2INT(y));
@@ -637,20 +629,20 @@ big_mul(x, y)
z = bignew(j, x->sign==y->sign);
zds = BDIGITS(z);
while (j--) zds[j] = 0;
- do {
- j = 0;
- if (BDIGITS(x)[i]) {
- do {
- n += zds[i + j] + ((unsigned long)BDIGITS(x)[i]*BDIGITS(y)[j]);
- zds[i + j++] = BIGLO(n);
- n = BIGDN(n);
- } while (j < y->len);
- if (n) {
- zds[i + j] = n;
- n = 0;
- }
+ for (i = 0; i < x->len; i++) {
+ unsigned long dd = BDIGITS(x)[i];
+ if (dd == 0) continue;
+ n = 0;
+ for (j = 0; j < y->len; j++) {
+ int ee = n + dd * BDIGITS(y)[j];
+ n = zds[i + j] + ee;
+ if (ee) zds[i + j] = BIGLO(n);
+ n = BIGDN(n);
}
- } while (++i < x->len);
+ if (n) {
+ zds[i + j] = n;
+ }
+ }
return bignorm(z);
}
@@ -669,7 +661,7 @@ bigdivmod(x, y, div, mod)
yds = BDIGITS(y);
if (ny == 0 && yds[0] == 0) num_zerodiv();
- if (nx < ny) {
+ if (nx < ny || nx == ny && BDIGITS(x)[nx - 1] < BDIGITS(y)[ny - 1]) {
if (div) *div = INT2FIX(0);
if (mod) *mod = bignorm(x);
return;
@@ -680,7 +672,7 @@ bigdivmod(x, y, div, mod)
z = big_clone(x);
zds = BDIGITS(z);
t2 = 0; i = nx;
- while(i--) {
+ while (i--) {
t2 = BIGUP(t2) + zds[i];
zds[i] = t2 / dd;
t2 %= dd;
@@ -728,24 +720,21 @@ bigdivmod(x, y, div, mod)
if (q) {
i = 0; num = 0; t2 = 0;
do { /* multiply and subtract */
+ int ee;
t2 += (unsigned long)yds[i] * q;
- num += zds[j - ny + i] - BIGLO(t2);
- if (num < 0) {
- zds[j - ny + i] = num + BIGRAD;
- num = -1;
- }
- else {
- zds[j - ny + i] = num;
- num = 0;
- }
+ ee = num - BIGLO(t2);
+ num = zds[j - ny + i] + ee;
+ if (ee) zds[j - ny + i] = BIGLO(num);
+ num = BIGDN(num);
t2 = BIGDN(t2);
} while (++i < ny);
num += zds[j - ny + i] - t2; /* borrow from high digit; don't update */
while (num) { /* "add back" required */
i = 0; num = 0; q--;
do {
- num += (long) zds[j - ny + i] + yds[i];
- zds[j - ny + i] = BIGLO(num);
+ int ee = num + yds[i];
+ num = (long) zds[j - ny + i] + ee;
+ if (ee) zds[j - ny + i] = BIGLO(num);
num = BIGDN(num);
} while (++i < ny);
num--;
@@ -1241,6 +1230,8 @@ Init_Bignum()
rb_define_method(cBignum, "[]", big_aref, 1);
rb_define_method(cBignum, "<=>", big_cmp, 1);
+ rb_define_method(cBignum, "==", big_eq, 1);
+ rb_define_method(cBignum, "eql?", big_eq, 1);
rb_define_method(cBignum, "hash", big_hash, 0);
rb_define_method(cBignum, "to_i", big_to_i, 0);
rb_define_method(cBignum, "to_f", big_to_f, 0);
diff --git a/class.c b/class.c
index 645d295..6cb55fa 100644
--- a/class.c
+++ b/class.c
@@ -28,6 +28,8 @@ class_new(super)
OBJSETUP(cls, cClass, T_CLASS);
cls->super = super;
+ cls->iv_tbl = 0;
+ cls->m_tbl = 0; /* safe GC */
cls->m_tbl = new_idhash();
return (VALUE)cls;
@@ -66,6 +68,8 @@ singleton_class_clone(class)
CLONESETUP(clone, class);
clone->super = class->super;
+ clone->iv_tbl = 0;
+ clone->m_tbl = 0;
clone->m_tbl = new_idhash();
st_foreach(class->m_tbl, clone_method, clone->m_tbl);
FL_SET(clone, FL_SINGLETON);
@@ -128,6 +132,8 @@ module_new()
OBJSETUP(mdl, cModule, T_MODULE);
mdl->super = 0;
+ mdl->iv_tbl = 0;
+ mdl->m_tbl = 0;
mdl->m_tbl = new_idhash();
return (VALUE)mdl;
@@ -197,7 +203,7 @@ include_class_new(module, super)
void
rb_include_module(class, module)
- struct RClass *class, *module;
+ VALUE class, module;
{
struct RClass *p;
@@ -216,18 +222,14 @@ rb_include_module(class, module)
while (module) {
/* ignore if the module included already in superclasses */
- for (p = class->super; p; p = p->super) {
- if (BUILTIN_TYPE(p) == T_ICLASS && p->m_tbl == module->m_tbl)
+ for (p = RCLASS(class)->super; p; p = p->super) {
+ if (BUILTIN_TYPE(p) == T_ICLASS && p->m_tbl == RCLASS(module)->m_tbl)
return;
}
- if (verbose) {
- rb_const_check(class, module);
- }
-
- class->super = include_class_new(module, class->super);
- class = class->super;
- module = module->super;
+ RCLASS(class)->super = include_class_new(module, RCLASS(class)->super);
+ class = (VALUE)RCLASS(class)->super;
+ module = (VALUE)RCLASS(module)->super;
}
}
@@ -243,7 +245,7 @@ rb_define_method_id(class, name, func, argc)
void
rb_define_method(class, name, func, argc)
- struct RClass *class;
+ VALUE class;
char *name;
VALUE (*func)();
int argc;
@@ -253,7 +255,7 @@ rb_define_method(class, name, func, argc)
void
rb_undef_method(class, name)
- struct RClass *class;
+ VALUE class;
char *name;
{
rb_add_method(class, rb_intern(name), 0, NOEX_PUBLIC);
@@ -273,6 +275,9 @@ VALUE
rb_singleton_class(obj)
struct RBasic *obj;
{
+ if (rb_special_const_p((VALUE)obj)) {
+ TypeError("cannot define singleton");
+ }
if (FL_TEST(obj->class, FL_SINGLETON)) {
return (VALUE)obj->class;
}
@@ -300,9 +305,20 @@ rb_define_module_function(module, name, func, argc)
rb_define_singleton_method(module, name, func, argc);
}
+VALUE mKernel;
+
+void
+rb_define_global_function(name, func, argc)
+ char *name;
+ VALUE (*func)();
+ int argc;
+{
+ rb_define_private_method(mKernel, name, func, argc);
+}
+
void
rb_define_alias(class, name1, name2)
- struct RClass *class;
+ VALUE class;
char *name1, *name2;
{
rb_alias(class, rb_intern(name1), rb_intern(name2));
@@ -310,7 +326,7 @@ rb_define_alias(class, name1, name2)
void
rb_define_attr(class, id, pub)
- struct RClass *class;
+ VALUE class;
ID id;
int pub;
{
@@ -325,10 +341,10 @@ rb_define_attr(class, id, pub)
attreq = rb_intern(buf);
sprintf(buf, "@%s", name);
attriv = rb_intern(buf);
- if (!rb_method_boundp(class, attr)) {
+ if (!rb_method_boundp(class, attr, NOEX_PRIVATE)) {
rb_add_method(class, attr, NEW_IVAR(attriv), 0);
}
- if (pub && !rb_method_boundp(class, attreq)) {
+ if (pub && !rb_method_boundp(class, attreq, NOEX_PRIVATE)) {
rb_add_method(class, attreq, NEW_ATTRSET(attriv), 0);
}
}
diff --git a/config.dj b/config.dj
index 13f4e6d..8ad3883 100644
--- a/config.dj
+++ b/config.dj
@@ -32,4 +32,5 @@
#define FILE_COUNT _cnt
#define DLEXT ".so"
#define RUBY_LIB ";/usr/local/lib/ruby;."
-#define RUBY_ARCHLIB "/usr/local/lib/ruby/i386-msdos"
+#define RUBY_ARCHLIB "/usr/local/lib/ruby/i386-djgpp"
+#define RUBY_PLATFORM "i386-djgpp"
diff --git a/config.guess b/config.guess
index ce6e12a..ea28434 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 27819cc..9dec8e3 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 7f89f5e..699ca1e 100644
--- a/configure.in
+++ b/configure.in
@@ -1,9 +1,6 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT(ruby.h)
-PROGS="ruby"
-AC_SUBST(PROGS)dnl
-
dnl checks for alternative programs
AC_ARG_WITH(gcc, [--without-gcc never use gcc], [
case $withval in
@@ -31,11 +28,15 @@ if test $rb_thread = yes; then
fi
AC_CANONICAL_HOST
+AC_ARG_PROGRAM
dnl Checks for programs.
AC_PROG_CC
AC_PROG_GCC_TRADITIONAL
AC_PROG_YACC
+AC_PROG_RANLIB
+AC_SUBST(AR)
+AC_CHECK_PROGS(AR, ar aal, ar)
AC_PROG_INSTALL
AC_PROG_MAKE_SET
@@ -43,6 +44,11 @@ AC_PROG_MAKE_SET
AC_MINIX
dnl Checks for libraries.
+case "$host_os" in
+nextstep*) ;;
+human*) ;;
+*) LIBS="-lm $LIBS";;
+esac
AC_CHECK_LIB(crypt, crypt)
AC_CHECK_LIB(dl, dlopen) # Dynamic linking for SunOS/Solaris and SYSV
AC_CHECK_LIB(dld, shl_load) # Dynamic linking for HP-UX
@@ -50,15 +56,17 @@ AC_CHECK_LIB(dld, shl_load) # Dynamic linking for HP-UX
dnl Checks for header files.
AC_HEADER_DIRENT
AC_HEADER_STDC
-AC_CHECK_HEADERS(unistd.h limits.h sys/file.h sys/ioctl.h pwd.h sys/select.h\
- sys/time.h sys/times.h sys/param.h sys/wait.h\
+AC_CHECK_HEADERS(stdlib.h unistd.h limits.h sys/file.h sys/ioctl.h pwd.h \
+ sys/select.h sys/time.h sys/times.h sys/param.h sys/wait.h\
syscall.h a.out.h string.h utime.h memory.h)
dnl Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_UID_T
AC_TYPE_SIZE_T
AC_STRUCT_ST_BLKSIZE
+save_LIBOJBS="$LIBOBJS"
AC_STRUCT_ST_BLOCKS
+LIBOBJS="$save_LIBOBJS"
AC_STRUCT_ST_RDEV
dnl Checks for library functions.
@@ -66,12 +74,13 @@ AC_TYPE_GETGROUPS
AC_TYPE_SIGNAL
AC_FUNC_ALLOCA
AC_FUNC_VFORK
-AC_REPLACE_FUNCS(dup2 setenv memmove mkdir strerror strftime\
+AC_REPLACE_FUNCS(dup2 setenv memmove mkdir strcasecmp strerror strftime\
strstr strtoul strdup strcasecmp crypt flock)
AC_CHECK_FUNCS(fmod killpg random wait4 waitpid syscall getcwd\
truncate chsize times utimes fcntl lockf setitimer\
setruid seteuid setreuid setrgid setegid setregid\
- getgroups getpgid getpriority dlopen sigprocmask sigaction)
+ setpgrp2 getpgid getgroups getpriority\
+ dlopen sigprocmask sigaction _setjmp)
if test "$ac_cv_func_strftime" = no; then
AC_STRUCT_TIMEZONE
AC_TRY_LINK([],
@@ -83,18 +92,18 @@ if test "$ac_cv_func_sigprocmask" = yes && test "$ac_cv_func_sigaction" = yes; t
else
AC_MSG_CHECKING(for BSD signal semantics)
AC_CACHE_VAL(rb_cv_bsd_signal,
- [AC_TRY_RUN([
+ [AC_TRY_RUN([
#include <stdio.h>
#include <signal.h>
-void sig_handler(dummy)
+void
+sig_handler(dummy)
int dummy;
{
}
-int main(argc, argv)
- int argc;
- char ** argv;
+int
+main()
{
signal(SIGINT, sig_handler);
kill(getpid(), SIGINT);
@@ -103,14 +112,38 @@ int main(argc, argv)
}
],
rb_cv_bsd_signal=yes,
- rb_cv_bsd_signal=no,
- [:])])
+ rb_cv_bsd_signal=no)])
AC_MSG_RESULT($rb_cv_bsd_signal)
if test "$rb_cv_bsd_signal" = yes; then
AC_DEFINE(BSD_SIGNAL)
fi
fi
+if test "$ac_cv_func_setpgrp2" = yes; then
+ AC_DEFINE(BSD_GETPGRP, getpgrp2)
+ AC_DEFINE(BSD_SETPGRP, setpgrp2)
+else
+ AC_MSG_CHECKING(whether getpgrp() has arg)
+ AC_CACHE_VAL(rb_cv_bsdgetpgrp,
+ [AC_TRY_COMPILE([#include <unistd.h>], [getpgrp(0);],
+ rb_cv_bsdgetpgrp=yes,
+ rb_cv_bsdgetpgrp=no)])
+ AC_MSG_RESULT($rb_cv_bsdgetpgrp)
+ if test "$rb_cv_bsdgetpgrp" = yes; then
+ AC_DEFINE(BSD_GETPGRP, getpgrp)
+ fi
+
+ AC_MSG_CHECKING(whether setpgrp() has args)
+ AC_CACHE_VAL(rb_cv_bsdsetpgrp,
+ [AC_TRY_COMPILE([#include <unistd.h>], [setpgrp(1, 1);],
+ rb_cv_bsdsetpgrp=yes,
+ rb_cv_bsdsetpgrp=no)])
+ AC_MSG_RESULT($rb_cv_bsdsetpgrp)
+ if test "$rb_cv_bsdsetpgrp" = yes; then
+ AC_DEFINE(BSD_SETPGRP, setpgrp)
+ fi
+fi
+
AC_C_BIGENDIAN
AC_CHAR_UNSIGNED
@@ -183,6 +216,7 @@ main() {
AC_MSG_RESULT($rb_cv_linux_elf)
if test "$rb_cv_linux_elf" = no; then
with_dln_a_out=yes
+ host_os=linux-a.out
else
LDFLAGS="-rdynamic"
fi;;
@@ -201,33 +235,49 @@ if test "$with_dln_a_out" != yes; then
rb_cv_dlopen=unknown
AC_MSG_CHECKING(whether OS depend dynamic link works)
if test "$GCC" = yes; then
- CCDLFLAGS=-fpic
+ case "$host_os" in
+ nextstep*) ;;
+ human*) ;;
+ *) CCDLFLAGS=-fpic;;
+ esac
else
case "$host_os" in
hpux*) CCDLFLAGS='+z';;
- solaris*|irix*) CCDLFLAGS='-K pic' ;;
- sunos*) CCDLFLAGS='-pic' ;;
- svr4*|esix*) CCDLFLAGS='-Kpic' ;;
- *) CCDLFLAGS='' ;;
+ solaris*|irix*) CCDLFLAGS='-K pic' ;;
+ sunos*) CCDLFLAGS='-pic' ;;
+ esix*|uxpds*) CCDLFLAGS='-Kpic' ;;
+ *) CCDLFLAGS='' ;;
esac
fi
case "$host_os" in
- hpux*) DLDFLAGS="-E"
- LDSHARED='ld -b'
- LDFLAGS="-Wl,-E"
- rb_cv_dlopen=yes;;
- solaris*) LDSHARED='ld -G'
- rb_cv_dlopen=yes;;
- sunos*) LDSHARED='ld -assert nodefinitions'
- rb_cv_dlopen=yes;;
- svr4*|esix*) LDSHARED="ld -G"
- rb_cv_dlopen=yes ;;
- linux*) LDSHARED="gcc -shared"
- rb_cv_dlopen=yes ;;
- freebsd*) LDSHARED="ld -Bshareable"
- rb_cv_dlopen=yes ;;
- *) LDSHARED='ld' ;;
+ hpux*) DLDFLAGS="-E"
+ LDSHARED='ld -b'
+ LDFLAGS="-Wl,-E"
+ rb_cv_dlopen=yes;;
+ solaris*) LDSHARED='ld -G'
+ rb_cv_dlopen=yes;;
+ sunos*) LDSHARED='ld -assert nodefinitions'
+ rb_cv_dlopen=yes;;
+ sysv4*) LDSHARED='ld -G'
+ rb_cv_dlopen=yes;;
+ esix*|uxpds*) LDSHARED="ld -G"
+ rb_cv_dlopen=yes ;;
+ linux*) LDSHARED="gcc -shared"
+ rb_cv_dlopen=yes ;;
+ freebsd*) LDSHARED="ld -Bshareable"
+ rb_cv_dlopen=yes ;;
+ netbsd*) LDSHARED="ld -Bshareable"
+ rb_cv_dlopen=yes ;;
+ nextstep*) LDSHARED='ld'
+ LDFLAGS="-u libsys_s"
+ rb_cv_dlopen=yes ;;
+ aix*) LDSHARED='../../miniruby ../aix_ld.rb $(TARGET)'
+ rb_cv_dlopen=yes ;;
+ human*) DLDFLAGS=''
+ LDSHARED=''
+ LDFLAGS='' ;;
+ *) LDSHARED='ld' ;;
esac
AC_MSG_RESULT($rb_cv_dlopen)
fi
@@ -297,13 +347,71 @@ AC_ARG_WITH(static-linked-ext,
*) ;;
esac])
+case "$host_os" in
+ human*)
+ AC_CHECK_LIB(signal, _harderr)
+ AC_CHECK_LIB(hmem, hmemset)
+ AC_CHECK_FUNCS(select)
+ AC_MSG_CHECKING(whether PD libc _dtos18 fail to convert big number)
+ AC_CACHE_VAL(rb_cv_missing__dtos18,
+ [AC_TRY_RUN(
+changequote(<<, >>)dnl
+<<
+#include <stdio.h>
+main ()
+{
+ char buf[256];
+ sprintf (buf, "%g", 1e+300);
+ exit (strcmp (buf, "1e+300") ? 0 : 1);
+}
+>>,
+changequote([, ])dnl
+rb_cv_missing__dtos18=yes, rb_cv_missing__dtos18=no)])
+ AC_MSG_RESULT($rb_cv_missing__dtos18)
+ if test "$rb_cv_missing__dtos18" = yes; then
+ AC_DEFINE(MISSING__DTOS18)
+ fi
+ AC_MSG_CHECKING(whether PD libc fconvert fail to round)
+ AC_CACHE_VAL(rb_cv_missing_fconvert,
+ [AC_TRY_RUN(
+changequote(<<, >>)dnl
+<<
+#include <stdio.h>
+#include <math.h>
+main ()
+{
+ char buf[256];
+ sprintf (buf, "%f", log(exp(1.0)));
+ exit (strcmp (buf, "1.000000") ? 0 : 1);
+}
+>>,
+changequote([, ])dnl
+rb_cv_missing_fconvert=yes, rb_cv_missing_fconvert=no)])
+ AC_MSG_RESULT($rb_cv_missing_fconvert)
+ if test "$rb_cv_missing_fconvert" = yes; then
+ AC_DEFINE(MISSING_FCONVERT)
+ fi
+ LIBOBJS="$LIBOBJS x68.o"
+ CFLAGS="$CFLAGS -fansi-only -cc1-stack=196608 -cpp-stack=2694144"
+ binsuffix=.x
+ setup=Setup.x68
+ ;;
+ *)
+ binsuffix=
+ setup=Setup
+ ;;
+esac
+AC_SUBST(binsuffix)
+AC_SUBST(setup)
+
if test "$prefix" = NONE; then
prefix=$ac_default_prefix
fi
-AC_DEFINE_UNQUOTED(RUBY_LIB, "${prefix}/lib/ruby:.")
-AC_SUBST(archlib)dnl
-archlib="${prefix}/lib/ruby/${host_cpu}-${host_os}"
-AC_DEFINE_UNQUOTED(RUBY_ARCHLIB, "$archlib")
+AC_DEFINE_UNQUOTED(RUBY_LIB, "${prefix}/lib/ruby")
+AC_SUBST(arch)dnl
+arch="${host_cpu}-${host_os}"
+AC_DEFINE_UNQUOTED(RUBY_ARCHLIB, "${prefix}/lib/ruby/${host_cpu}-${host_os}")
+AC_DEFINE_UNQUOTED(RUBY_PLATFORM, "$arch")
echo "creating config.h"
cat confdefs.h > config.h
diff --git a/defines.h b/defines.h
index 70e010a..b981d86 100644
--- a/defines.h
+++ b/defines.h
@@ -13,14 +13,19 @@
#define RUBY
/* define EUC/SJIS for default kanji-code */
+#if defined(MSDOS) || defined(__CYGWIN32__) || defined(__human68k__)
+#undef EUC
+#define SJIS
+#else
#define EUC
#undef SJIS
+#endif
#ifdef NeXT
+#define DYNAMIC_ENDIAN /* determine endian at runtime */
#define S_IXUSR _S_IXUSR /* execute/search permission, owner */
#define S_IXGRP 0000010 /* execute/search permission, group */
#define S_IXOTH 0000001 /* execute/search permission, other */
-#define S_ISREG(mode) (((mode) & (_S_IFMT)) == (_S_IFREG))
#endif /* NeXT */
#ifdef NT
@@ -33,4 +38,13 @@
#define FLUSH_REGISTER_WINDOWS /* empty */
#endif
+#ifdef __human68k__
+#undef HAVE_RANDOM
+#undef HAVE_SETITIMER
+#endif
+
+#ifndef RUBY_PLATFORM
+#define RUBY_PLATFORM "unknown-unknown"
+#endif
+
#endif
diff --git a/dir.c b/dir.c
index fe4910b..a099d5e 100644
--- a/dir.c
+++ b/dir.c
@@ -39,21 +39,23 @@
# include <ndir.h>
# endif
# ifdef NT
-# include "missing/dirent.h"
+# include "missing/dir.h"
# endif
#endif
#include <errno.h>
+#ifndef NT
char *getenv();
+#endif
static VALUE cDir;
static void
free_dir(dir)
- DIR **dir;
+ DIR *dir;
{
- if (dir && *dir) closedir(*dir);
+ if (dir) closedir(dir);
}
static VALUE
@@ -62,9 +64,9 @@ dir_s_open(dir_class, dirname)
struct RString *dirname;
{
VALUE obj;
- DIR *dirp, **d;
+ DIR *dirp;
- Check_Type(dirname, T_STRING);
+ Check_SafeStr(dirname);
dirp = opendir(dirname->ptr);
if (dirp == NULL) {
@@ -77,23 +79,20 @@ dir_s_open(dir_class, dirname)
}
}
- obj = Make_Data_Struct(dir_class, DIR*, 0, free_dir, d);
- *d = dirp;
+ obj = Data_Wrap_Struct(dir_class, 0, free_dir, dirp);
return obj;
}
static void
-closeddir()
+dir_closed()
{
Fail("closed directory");
}
#define GetDIR(obj, dirp) {\
- DIR **_dp;\
- Get_Data_Struct(obj, DIR*, _dp);\
- dirp = *_dp;\
- if (dirp == NULL) closeddir();\
+ Data_Get_Struct(obj, DIR, dirp);\
+ if (dirp == NULL) dir_closed();\
}
static VALUE
@@ -106,7 +105,7 @@ dir_each(dir)
GetDIR(dir, dirp);
for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
- file = str_new(dp->d_name, NAMLEN(dp));
+ file = str_taint(str_new(dp->d_name, NAMLEN(dp)));
rb_yield(file);
}
return dir;
@@ -158,12 +157,12 @@ static VALUE
dir_close(dir)
VALUE dir;
{
- DIR **dirpp;
+ DIR *dirp;
- Get_Data_Struct(dir, DIR*, dirpp);
- if (*dirpp == NULL) closeddir();
- closedir(*dirpp);
- *dirpp = NULL;
+ Data_Get_Struct(dir, DIR, dirp);
+ if (dirp == NULL) dir_closed();
+ closedir(dirp);
+ DATA_PTR(dir) = NULL;
return Qnil;
}
@@ -177,9 +176,10 @@ dir_s_chdir(argc, argv, obj)
VALUE path;
char *dist = "";
+ rb_secure(2);
rb_scan_args(argc, argv, "01", &path);
if (path) {
- Check_Type(path, T_STRING);
+ Check_SafeStr(path);
dist = RSTRING(path)->ptr;
}
else {
@@ -208,15 +208,16 @@ dir_s_getwd(dir)
if (getwd(path) == 0) rb_sys_fail(path);
#endif
- return str_new2(path);
+ return str_taint(str_new2(path));
}
static VALUE
dir_s_chroot(dir, path)
VALUE dir, path;
{
-#if !defined(DJGPP) && !defined(__CYGWIN32__)
- Check_Type(path, T_STRING);
+#if !defined(DJGPP) && !defined(__CYGWIN32__) && !defined(NT) && !defined(__human68k__)
+ rb_secure(2);
+ Check_SafeStr(path);
if (chroot(RSTRING(path)->ptr) == -1)
rb_sys_fail(0);
@@ -236,6 +237,7 @@ dir_s_mkdir(argc, argv, obj)
VALUE path, vmode;
int mode;
+ rb_secure(2);
if (rb_scan_args(argc, argv, "11", &path, &vmode) == 2) {
mode = NUM2INT(vmode);
}
@@ -243,9 +245,14 @@ dir_s_mkdir(argc, argv, obj)
mode = 0777;
}
- Check_Type(path, T_STRING);
+ Check_SafeStr(path);
+#ifndef NT
if (mkdir(RSTRING(path)->ptr, mode) == -1)
rb_sys_fail(RSTRING(path)->ptr);
+#else
+ if (mkdir(RSTRING(path)->ptr) == -1)
+ rb_sys_fail(RSTRING(path)->ptr);
+#endif
return INT2FIX(0);
}
@@ -255,7 +262,8 @@ dir_s_rmdir(obj, dir)
VALUE obj;
struct RString *dir;
{
- Check_Type(dir, T_STRING);
+ rb_secure(2);
+ Check_SafeStr(dir);
if (rmdir(dir->ptr) < 0)
rb_sys_fail(dir->ptr);
@@ -265,6 +273,7 @@ dir_s_rmdir(obj, dir)
#define isdelim(c) ((c)==' '||(c)=='\t'||(c)=='\n'||(c)=='\0')
char **glob_filename();
+extern char *glob_error_return;
static void
push_globs(ary, s)
@@ -277,11 +286,13 @@ push_globs(ary, s)
if (fnames == (char**)-1) rb_sys_fail(s);
ff = fnames;
while (*ff) {
- ary_push(ary, str_new2(*ff));
+ ary_push(ary, str_taint(str_new2(*ff)));
free(*ff);
ff++;
}
- free(fnames);
+ if (fnames != &glob_error_return) {
+ free(fnames);
+ }
}
static void
@@ -332,7 +343,7 @@ dir_s_glob(dir, str)
int nest;
VALUE ary;
- Check_Type(str, T_STRING);
+ Check_SafeStr(str);
ary = ary_new();
diff --git a/dln.c b/dln.c
index e5193a7..ee5429a 100644
--- a/dln.c
+++ b/dln.c
@@ -29,7 +29,11 @@ void *xcalloc();
void *xrealloc();
#include <stdio.h>
+#ifndef NT
#include <sys/file.h>
+#else
+#include "missing/file.h"
+#endif
#include <sys/types.h>
#include <sys/stat.h>
@@ -49,9 +53,11 @@ void *xrealloc();
# include <strings.h>
#endif
+#ifndef NT
char *strdup();
char *getenv();
+#endif
int eaccess();
@@ -61,7 +67,7 @@ int eaccess();
#endif
#ifndef FUNCNAME_PATTERN
-# if defined(__hp9000s300) || defined(__NetBSD__) || defined(__BORLANDC__) || defined(__FreeBSD__)
+# if defined(__hp9000s300) || defined(__NetBSD__) || defined(__BORLANDC__) || defined(__FreeBSD__) || defined(NeXT)
# define FUNCNAME_PATTERN "_Init_%.200s"
# else
# define FUNCNAME_PATTERN "Init_%.200s"
@@ -92,8 +98,8 @@ init_funcname(buf, file)
# define LIBC_NAME "libc.a"
#endif
-#ifndef DLN_DEFAULT_PATH
-# define DLN_DEFAULT_PATH "/lib:/usr/lib:."
+#ifndef DLN_DEFAULT_LIB_PATH
+# define DLN_DEFAULT_LIB_PATH "/lib:/usr/lib:/usr/local/lib:."
#endif
#include <errno.h>
@@ -136,12 +142,12 @@ load_header(fd, hdrp, disp)
int size;
lseek(fd, disp, 0);
- size = read(fd, hdrp, sizeof(*hdrp));
+ size = read(fd, hdrp, sizeof(struct exec));
if (size == -1) {
dln_errno = errno;
return -1;
}
- if (size != sizeof(*hdrp) || N_BADMAG(*hdrp)) {
+ if (size != sizeof(struct exec) || N_BADMAG(*hdrp)) {
dln_errno = DLN_ENOEXEC;
return -1;
}
@@ -206,11 +212,10 @@ load_reloc(fd, hdrp, disp)
struct exec *hdrp;
long disp;
{
- struct relocation_info * reloc;
+ struct relocation_info *reloc;
int size;
lseek(fd, disp + N_TXTOFF(*hdrp) + hdrp->a_text + hdrp->a_data, 0);
-
size = hdrp->a_trsize + hdrp->a_drsize;
reloc = (struct relocation_info*)xmalloc(size);
if (reloc == NULL) {
@@ -295,6 +300,7 @@ sym_hash(hdrp, syms)
static int
dln_init(prog)
+ char *prog;
{
char *file;
int fd;
@@ -672,7 +678,7 @@ load_1(fd, disp, need_init)
sym = syms;
while (sym < end) {
struct nlist *new_sym;
- char *key, *name;
+ char *key;
switch (sym->n_type) {
case N_COMM:
@@ -856,23 +862,11 @@ search_undef(key, value, lib_tbl)
int value;
st_table *lib_tbl;
{
-#if 0
- static char *last = "";
- int offset;
-
- if (st_lookup(lib_tbl, key, &offset) == 0) return ST_CONTINUE;
- if (strcmp(last, key) != 0) {
- last = key;
- target_offset = offset;
- }
- return ST_STOP;
-#else
int offset;
if (st_lookup(lib_tbl, key, &offset) == 0) return ST_CONTINUE;
target_offset = offset;
return ST_STOP;
-#endif
}
struct symdef {
@@ -880,7 +874,7 @@ struct symdef {
int lib_offset;
};
-char *dln_library_path = DLN_DEFAULT_PATH;
+char *dln_library_path = DLN_DEFAULT_LIB_PATH;
static int
load_lib(lib)
@@ -1108,7 +1102,7 @@ dln_strerror()
#endif
#ifdef USE_DLN_DLOPEN
- return dlerror();
+ return (char*)dlerror();
#endif
}
@@ -1259,9 +1253,6 @@ dln_load(file)
char *object_files[2] = {NULL, NULL};
void (*init_fct)();
- int len = strlen(file);
- char *point;
- char init_name[len +7];
object_files[0] = file;
@@ -1302,8 +1293,15 @@ dln_find_exe(fname, path)
char *fname;
char *path;
{
+#if defined(__human68k__)
+ if (!path)
+ path = getenv("path");
+ if (!path)
+ path = "/usr/local/bin;/usr/usb;/usr/bin;/bin;.";
+#else
if (!path) path = getenv("PATH");
if (!path) path = "/usr/local/bin:/usr/ucb:/usr/bin:/bin:.";
+#endif
return dln_find_1(fname, path, 1);
}
@@ -1332,6 +1330,12 @@ dln_find_1(fname, path, exe_flag)
if (fname[0] == '/') return fname;
if (strncmp("./", fname, 2) == 0 || strncmp("../", fname, 3) == 0)
return fname;
+#if defined(MSDOS) || defined(NT) || defined(__human68k__)
+ if (fname[0] == '\\') return fname;
+ if (fname[1] == ':') return fname;
+ if (strncmp(".\\", fname, 2) == 0 || strncmp("..\\", fname, 3) == 0)
+ return fname;
+#endif
for (dp = path;; dp = ++ep) {
register int l;
@@ -1339,7 +1343,11 @@ dln_find_1(fname, path, exe_flag)
int fspace;
/* extract a component */
+#if !defined(MSDOS) && !defined(NT) && !defined(__human68k__)
ep = strchr(dp, ':');
+#else
+ ep = strchr(dp, ';');
+#endif
if (ep == NULL)
ep = dp+strlen(dp);
@@ -1399,6 +1407,34 @@ dln_find_1(fname, path, exe_flag)
/* looking for executable */
if (eaccess(fbuf, X_OK) == 0) return fbuf;
}
+#if defined(MSDOS) || defined(NT) || defined(__human68k__)
+ if (exe_flag) {
+ static const char *extension[] = {
+#if defined(MSDOS)
+ ".com", ".exe", ".bat",
+#if defined(DJGPP)
+ ".btm", ".sh", ".ksh", ".pl", ".sed",
+#endif
+#else
+ ".r", ".R", ".x", ".X", ".bat", ".BAT",
+#endif
+ (char *) NULL
+ };
+ int j;
+
+ for (j = 0; extension[j]; j++) {
+ if (fspace < strlen(extension[j])) {
+ fprintf(stderr, "openpath: pathname too long (ignored)\n");
+ fprintf(stderr, "\tDirectory \"%.*s\"\n", (int) (bp - fbuf), fbuf);
+ fprintf(stderr, "\tFile \"%s%s\"\n", fname, extension[j]);
+ continue;
+ }
+ strcpy(bp + i, extension[j]);
+ if (stat(fbuf, &st) == 0)
+ return fbuf;
+ }
+ }
+#endif /* MSDOS or NT or __human68k__ */
/* if not, and no other alternatives, life is bleak */
if (*ep == '\0') {
return NULL;
diff --git a/enum.c b/enum.c
index 5ec71bc..63ef9e9 100644
--- a/enum.c
+++ b/enum.c
@@ -90,8 +90,10 @@ enum_find(argc, argv, obj)
if (arg.found) {
return arg.val;
}
- if (NIL_P(if_none)) return Qnil;
- return rb_eval_cmd(if_none, Qnil);
+ if (!NIL_P(if_none)) {
+ rb_eval_cmd(if_none, Qnil);
+ }
+ return Qnil;
}
static void
@@ -275,7 +277,7 @@ index_i(item, iv)
VALUE item;
struct i_v_pair *iv;
{
- if (rb_equal(item, 1, iv->v)) {
+ if (rb_equal(item, iv->v)) {
iv->found = 1;
rb_break();
}
@@ -357,6 +359,7 @@ Init_Enumerable()
rb_define_method(mEnumerable,"max", enum_max, 0);
rb_define_method(mEnumerable,"index", enum_index, 1);
rb_define_method(mEnumerable,"member?", enum_member, 1);
+ rb_define_method(mEnumerable,"include?", enum_member, 1);
rb_define_method(mEnumerable,"length", enum_length, 0);
rb_define_method(mEnumerable,"size", enum_length, 0);
diff --git a/error.c b/error.c
index d1c465b..5291d9e 100644
--- a/error.c
+++ b/error.c
@@ -159,7 +159,7 @@ static struct types {
extern void TypeError();
void
-Check_Type(x, t)
+rb_check_type(x, t)
VALUE x;
int t;
{
@@ -191,12 +191,13 @@ VALUE eNameError;
VALUE eIndexError;
VALUE eNotImpError;
VALUE eLoadError;
+VALUE eSecurityError;
VALUE eSystemCallError;
VALUE mErrno;
VALUE
-exc_new0(etype, ptr, len)
+exc_new(etype, ptr, len)
VALUE etype;
char *ptr;
UINT len;
@@ -215,15 +216,15 @@ exc_new0(etype, ptr, len)
}
VALUE
-exc_new(etype, s)
+exc_new2(etype, s)
VALUE etype;
char *s;
{
- return exc_new0(etype, s, strlen(s));
+ return exc_new(etype, s, strlen(s));
}
VALUE
-exc_new2(etype, str)
+exc_new3(etype, str)
VALUE etype;
struct RString *str;
{
@@ -240,21 +241,70 @@ exc_s_new(argc, argv, etype)
VALUE arg;
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
- return exc_new0(etype, 0, 0);
+ return exc_new(etype, 0, 0);
}
Check_Type(arg, T_STRING);
- return exc_new2(etype, arg);
+ return exc_new3(etype, arg);
+}
+
+static VALUE
+exc_inspect(exc)
+ VALUE exc;
+{
+ struct RString *classpath = RSTRING(rb_class_path(CLASS_OF(exc)));
+ VALUE str = str_new(classpath->ptr, classpath->len);
+
+ str_cat(str, ":", 1);
+ if (RSTRING(exc)->len == 0) {
+ str_cat(str, "\"\"", 2);
+ }
+ str_cat(str, RSTRING(exc)->ptr, RSTRING(exc)->len);
+ return str;
+}
+
+static VALUE
+exception(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ void ArgError();
+ VALUE v = Qnil;
+ int i;
+ ID id;
+
+ if (argc == 0) {
+ ArgError("wrong # of arguments");
+ }
+ for (i=0; i<argc; i++) { /* argument check */
+ id = rb_to_id(argv[i]);
+ if (!rb_id2name(id)) {
+ ArgError("argument needs to be symbol or string");
+ }
+ if (!rb_is_const_id(id)) {
+ ArgError("identifier %s needs to be constant", rb_id2name(id));
+ }
+ }
+ for (i=0; i<argc; i++) {
+ v = rb_define_class(rb_id2name(rb_to_id(argv[i])), eException);
+ }
+ return v;
}
static VALUE *syserr_list;
+#ifndef NT
+extern int sys_nerr;
+#endif
+
static void
set_syserr(i, name)
int i;
char *name;
{
- syserr_list[i] = rb_define_class_under(mErrno, name, eSystemCallError);
- rb_global_variable(&syserr_list[i]);
+ if (i <= sys_nerr) {
+ syserr_list[i] = rb_define_class_under(mErrno, name, eSystemCallError);
+ rb_global_variable(&syserr_list[i]);
+ }
}
static void init_syserr();
@@ -264,6 +314,7 @@ Init_Exception()
{
eGlobalExit = rb_define_class("GlobalExit", cString);
rb_define_method(eGlobalExit, "new", exc_s_new, -1);
+ rb_define_method(eGlobalExit, "inspect", exc_inspect, 0);
eSystemExit = rb_define_class("SystemExit", eGlobalExit);
eFatal = rb_define_class("fatal", eGlobalExit);
@@ -279,8 +330,11 @@ Init_Exception()
eLoadError = rb_define_class("LoadError", eException);
eRuntimeError = rb_define_class("RuntimeError", eException);
+ eSecurityError = rb_define_class("SecurityError", eException);
init_syserr();
+
+ rb_define_global_function("Exception", exception, -1);
}
#define RAISE_ERROR(class) {\
@@ -291,11 +345,12 @@ Init_Exception()
vsprintf(buf, fmt, args);\
va_end(args);\
\
- rb_raise(exc_new(class, buf));\
+ rb_raise(exc_new2(class, buf));\
}
void
Raise(exc, fmt, va_alist)
+ VALUE exc;
char *fmt;
va_dcl
{
@@ -371,14 +426,16 @@ Fatal(fmt, va_alist)
va_end(args);
rb_in_eval = 0;
- rb_fatal(exc_new(eFatal, buf));
+ rb_fatal(exc_new2(eFatal, buf));
}
void
rb_sys_fail(mesg)
char *mesg;
{
+#ifndef NT
char *strerror();
+#endif
char buf[BUFSIZ];
extern int errno;
int n = errno;
@@ -389,17 +446,15 @@ rb_sys_fail(mesg)
sprintf(buf, "%s", strerror(errno));
errno = 0;
- if (!syserr_list[n]) {
+ if (n > sys_nerr || !syserr_list[n]) {
char name[6];
sprintf(name, "E%03d", n);
set_syserr(n, name);
}
- rb_raise(exc_new(syserr_list[n], buf));
+ rb_raise(exc_new2(syserr_list[n], buf));
}
-extern int sys_nerr;
-
static void
init_syserr()
{
diff --git a/eval.c b/eval.c
index 2f2ee59..564ff9a 100644
--- a/eval.c
+++ b/eval.c
@@ -6,7 +6,7 @@
$Date: 1996/12/25 08:54:45 $
created at: Thu Jun 10 14:22:17 JST 1993
- Copyright (C) 1993-1995 Yukihiro Matsumoto
+ Copyright (C) 1993-1997 Yukihiro Matsumoto
************************************************/
@@ -26,8 +26,17 @@
char *strrchr();
#endif
-static VALUE cProc;
+#ifndef setjmp
+#ifdef HAVE__SETJMP
+#define setjmp(env) _setjmp(env)
+#define longjmp(env,val) _longjmp(env,val)
+#endif
+#endif
+
+extern VALUE cData;
+VALUE cProc;
static VALUE proc_call();
+static VALUE f_binding();
#define CACHE_SIZE 0x200
#define CACHE_MASK 0x1ff
@@ -45,6 +54,18 @@ struct cache_entry { /* method hash table. */
static struct cache_entry cache[CACHE_SIZE];
void
+rb_clear_cache()
+{
+ struct cache_entry *ent, *end;
+
+ ent = cache; end = ent + CACHE_SIZE;
+ while (ent < end) {
+ ent->mid = 0;
+ ent++;
+ }
+}
+
+void
rb_add_method(class, mid, node, noex)
struct RClass *class;
ID mid;
@@ -118,21 +139,31 @@ rb_alias(class, name, def)
ID name, def;
{
struct RClass *origin;
- NODE *body, *old;
+ NODE *orig, *body;
if (name == def) return;
- body = search_method(class, def, &origin);
- if (!body || !body->nd_body) {
- NameError("undefined method `%s' for class `%s'",
- rb_id2name(def), rb_class2name(class));
+ orig = search_method(class, def, &origin);
+ if (!orig || !orig->nd_body) {
+ if (TYPE(class) == T_MODULE) {
+ orig = search_method(cObject, def, &origin);
+ }
+ }
+ if (!orig || !orig->nd_body) {
+ NameError("undefined method `%s' for `%s'",
+ rb_id2name(def), rb_class2name((VALUE)class));
+ }
+ body = orig->nd_body;
+ if (nd_type(body) == NODE_FBODY) { /* was alias */
+ body = body->nd_head;
+ def = body->nd_mid;
+ origin = (struct RClass*)body->nd_orig;
}
st_insert(class->m_tbl, name,
- NEW_METHOD(NEW_FBODY(body->nd_body, def, origin),
- body->nd_noex));
+ NEW_METHOD(NEW_FBODY(body, def, origin), orig->nd_noex));
}
-void
+static void
rb_export_method(class, name, noex)
struct RClass *class;
ID name;
@@ -142,15 +173,19 @@ rb_export_method(class, name, noex)
struct RClass *origin;
body = search_method(class, name, &origin);
+ if (!body && TYPE(class) == T_MODULE) {
+ body = search_method(cObject, name, &origin);
+ }
if (!body) {
- NameError("undefined method `%s' for class `%s'",
- rb_id2name(name), rb_class2name(class));
+ NameError("undefined method `%s' for `%s'",
+ rb_id2name(name), rb_class2name((VALUE)class));
}
if (body->nd_noex != noex) {
if (class == origin) {
body->nd_noex = noex;
}
else {
+ rb_clear_cache();
rb_add_method(class, name, NEW_ZSUPER(), noex);
}
}
@@ -173,33 +208,25 @@ method_boundp(class, id, ex)
}
int
-rb_method_boundp(class, id)
- struct RClass *class;
+rb_method_boundp(class, id, priv)
+ VALUE class;
ID id;
+ int priv;
{
- if (method_boundp(class, id, NOEX_PRIVATE))
+ if (method_boundp(class, id, priv?NOEX_PRIVATE:NOEX_PUBLIC))
return TRUE;
return FALSE;
}
-void
-rb_clear_cache()
-{
- struct cache_entry *ent, *end;
-
- ent = cache; end = ent + CACHE_SIZE;
- while (ent < end) {
- ent->mid = 0;
- ent++;
- }
-}
-
static ID init, eqq, each, aref, aset;
VALUE errinfo = Qnil, errat = Qnil;
extern NODE *eval_tree;
extern int nerrs;
-extern VALUE cKernel;
+extern VALUE mKernel;
+extern VALUE cModule;
+extern VALUE cClass;
+extern VALUE eFatal;
extern VALUE eGlobalExit;
extern VALUE eInterrupt;
extern VALUE eSystemExit;
@@ -207,6 +234,7 @@ extern VALUE eException;
extern VALUE eRuntimeError;
extern VALUE eSyntaxError;
static VALUE eLocalJumpError;
+extern VALUE eSecurityError;
extern VALUE TopSelf;
@@ -236,12 +264,15 @@ struct BLOCK {
int level;
int iter;
struct RVarmap *d_vars;
+#ifdef THREAD
+ VALUE orig_thread;
+#endif
struct BLOCK *prev;
} *the_block;
#define PUSH_BLOCK(v,b) { \
struct BLOCK _block; \
- _block.level = (int)&prot_tag; \
+ _block.level = (int)prot_tag; \
_block.var = v; \
_block.body = b; \
_block.self = self; \
@@ -260,7 +291,7 @@ struct BLOCK {
_block = *b; \
_block.prev = the_block; \
the_block = &_block;
-
+
#define POP_BLOCK() \
the_block = the_block->prev; \
}
@@ -268,9 +299,12 @@ struct BLOCK {
struct RVarmap *the_dyna_vars;
#define PUSH_VARS() { \
struct RVarmap *_old; \
- _old = the_dyna_vars;
+ _old = the_dyna_vars; \
+ the_dyna_vars = 0;
-#define POP_VARS() the_dyna_vars = _old; }
+#define POP_VARS() \
+ the_dyna_vars = _old; \
+}
VALUE
dyna_var_defined(id)
@@ -278,7 +312,7 @@ dyna_var_defined(id)
{
struct RVarmap *vars = the_dyna_vars;
- while (vars && vars->id) {
+ while (vars) {
if (vars->id == id) return TRUE;
vars = vars->next;
}
@@ -291,7 +325,7 @@ dyna_var_ref(id)
{
struct RVarmap *vars = the_dyna_vars;
- while (vars && vars->id) {
+ while (vars) {
if (vars->id == id) {
return vars->val;
}
@@ -307,7 +341,7 @@ dyna_var_asgn(id, value)
{
struct RVarmap *vars = the_dyna_vars;
- while (vars && vars->id) {
+ while (vars) {
if (vars->id == id) {
vars->val = value;
return value;
@@ -325,17 +359,6 @@ dyna_var_asgn(id, value)
return value;
}
-static VALUE
-dyna_var_mark()
-{
- NEWOBJ(_vars, struct RVarmap);
- OBJSETUP(_vars, 0, T_VARMAP);
- _vars->id = 0;
- _vars->val = Qnil;
- _vars->next = the_dyna_vars;
- the_dyna_vars = _vars;
-}
-
static struct iter {
int iter;
struct iter *prev;
@@ -378,7 +401,7 @@ static struct tag {
}
#define JUMP_TAG3(val,data1,data2) \
- JUMP_TAG(newnode(NODE_TAG,(val),(data1),(data2)))
+ JUMP_TAG(node_newnode(NODE_TAG,(val),(data1),(data2)))
#define JUMP_TAG2(val,data) JUMP_TAG3((val),(data),0)
@@ -408,6 +431,9 @@ struct RClass *the_class;
struct SCOPE *_old; \
NEWOBJ(_scope, struct SCOPE); \
OBJSETUP(_scope, 0, T_SCOPE); \
+ _scope->local_tbl = 0; \
+ _scope->local_vars = 0; \
+ _scope->flag = 0; \
_old = the_scope; \
the_scope = _scope; \
@@ -415,8 +441,12 @@ struct RClass *the_class;
if (the_scope->flag == SCOPE_ALLOCA) {\
the_scope->local_vars = 0;\
the_scope->local_tbl = 0;\
+ if (the_scope != top_scope)\
+ gc_force_recycle(the_scope);\
+ }\
+ else {\
+ the_scope->flag |= SCOPE_NOSTACK;\
}\
- the_scope->flag |= SCOPE_NOSTACK;\
the_scope = _old;\
}
@@ -426,40 +456,110 @@ static NODE *compile();
static VALUE rb_call();
VALUE rb_apply();
+VALUE rb_funcall2();
+
+static VALUE module_setup();
+
+static VALUE massign();
+static void assign();
+
+static int safe_level = 0;
+/* safe-level:
+ 0 - strings from streams/environment/ARGV are tainted (default)
+ 1 - no dangerous operation by tainted string
+ 2 - some process operations prohibited
+ 3 - all genetated strings are tainted
+ 4 - no global variable value modification/no direct output
+ 5 - no instance variable value modification
+*/
+
+int
+rb_safe_level()
+{
+ return safe_level;
+}
-static void module_setup();
+void
+rb_set_safe_level(level)
+ int level;
+{
+ if (level > safe_level) {
+ safe_level = level;
+ }
+}
+
+static VALUE
+safe_getter()
+{
+ return INT2FIX(safe_level);
+}
-static VALUE masign();
-static void asign();
+static void
+safe_setter(val)
+ VALUE val;
+{
+ int level = NUM2INT(val);
-extern VALUE rb_stderr;
+ if (level < safe_level) {
+ Raise(eSecurityError, "tried to downgrade safe level from %d to %d",
+ safe_level, level);
+ }
+ safe_level = level;
+}
+
+void
+rb_check_safe_str(x)
+ VALUE x;
+{
+ if (TYPE(x)!= T_STRING) {
+ TypeError("wrong argument type %s (expected String)",
+ rb_class2name(CLASS_OF(x)));
+ }
+ if (rb_safe_level() > 0 && str_tainted(x)) {
+ Raise(eSecurityError, "Insecure operation - %s",
+ rb_id2name(the_frame->last_func));
+ }
+}
+
+void
+rb_secure(level)
+ int level;
+{
+ if (level <= safe_level) {
+ Raise(eSecurityError, "Insecure operation `%s' for level %d",
+ rb_id2name(the_frame->last_func), level);
+ }
+}
extern int sourceline;
extern char *sourcefile;
+static VALUE trace_func = 0;
+static void call_trace_func();
+
static void
error_pos()
{
if (sourcefile) {
if (the_frame->last_func) {
- fprintf(stderr, "%s:%d:in `%s': ", sourcefile, sourceline,
+ fprintf(stderr, "%s:%d:in `%s'", sourcefile, sourceline,
rb_id2name(the_frame->last_func));
}
else {
- fprintf(stderr, "%s:%d: ", sourcefile, sourceline);
+ fprintf(stderr, "%s:%d", sourcefile, sourceline);
}
}
}
static void
-error_print(state)
- NODE *state;
+error_print()
{
- struct FRAME *frame = the_frame;
- VALUE etype;
+ VALUE eclass;
+
+ if (NIL_P(errinfo)) return;
if (!NIL_P(errat)) {
- VALUE mesg;
+ VALUE mesg = Qnil;
switch (TYPE(errat)) {
case T_STRING:
@@ -470,26 +570,36 @@ error_print(state)
mesg = RARRAY(errat)->ptr[0];
break;
}
- fwrite(RSTRING(mesg)->ptr, 1, RSTRING(mesg)->len, stderr);
- fprintf(stderr, ": ");
+ if (NIL_P(mesg)) error_pos();
+ else {
+ fwrite(RSTRING(mesg)->ptr, 1, RSTRING(mesg)->len, stderr);
+ }
}
- etype = rb_class_path(CLASS_OF(errinfo));
-
- if (verbose) {
- fwrite(RSTRING(etype)->ptr, 1, RSTRING(etype)->len, stderr);
- putc('|', stderr);
- }
- if (RSTRING(errinfo)->len == 0) {
- fprintf(stderr, "unhandled exception.\n");
+ eclass = CLASS_OF(errinfo);
+ if (eclass == eRuntimeError && RSTRING(errinfo)->len == 0) {
+ fprintf(stderr, ": unhandled exception\n");
}
else {
- fwrite(RSTRING(errinfo)->ptr, 1, RSTRING(errinfo)->len, stderr);
+ PUSH_TAG();
+ if (EXEC_TAG() == 0) {
+ VALUE epath = rb_class_path(eclass);
+ if (RSTRING(epath)->ptr[0] != '#') {
+ fprintf(stderr, ": ");
+ fwrite(RSTRING(epath)->ptr, 1, RSTRING(epath)->len, stderr);
+ }
+ }
+ POP_TAG();
+
+ if (RSTRING(errinfo)->len > 0) {
+ fprintf(stderr, ": ");
+ fwrite(RSTRING(errinfo)->ptr, 1, RSTRING(errinfo)->len, stderr);
+ }
if (RSTRING(errinfo)->ptr[RSTRING(errinfo)->len - 1] != '\n') {
putc('\n', stderr);
}
}
-
+
if (!NIL_P(errat)) {
int i;
struct RArray *ep = RARRAY(errat);
@@ -509,13 +619,17 @@ error_print(state)
}
}
+#ifndef NT
extern char **environ;
+#endif
char **origenviron;
+#if (_MSC_VER >= 1000)
+__declspec(dllexport) void __stdcall
+#else
void
-ruby_init(argc, argv, envp)
- int argc;
- char **argv, **envp;
+#endif
+ruby_init()
{
static struct FRAME frame;
static struct iter iter;
@@ -525,9 +639,6 @@ ruby_init(argc, argv, envp)
the_iter = &iter;
origenviron = environ;
-#ifdef NT
- NtInitialize(&argc, &argv);
-#endif
init_heap();
PUSH_SCOPE();
@@ -539,15 +650,43 @@ ruby_init(argc, argv, envp)
if ((state = EXEC_TAG()) == 0) {
rb_call_inits();
the_class = (struct RClass*)cObject;
- the_frame->cbase = (VALUE)newnode(NODE_CREF,cObject,0,0);
- ruby_options(argc, argv, envp);
+ the_frame->cbase = (VALUE)node_newnode(NODE_CREF,cObject,0,0);
+ rb_define_global_const("TOPLEVEL_BINDING", f_binding(TopSelf));
+ ruby_prog_init();
}
POP_TAG();
- if (state) error_print(state);
+ if (state) error_print();
POP_SCOPE();
the_scope = top_scope;
}
+static int ext_init = 0;
+
+#if (_MSC_VER >= 1000)
+__declspec(dllexport) void __stdcall
+#else
+void
+#endif
+ruby_options(argc, argv)
+ int argc;
+ char **argv;
+{
+ NODE *state;
+
+ PUSH_TAG()
+ if ((state = EXEC_TAG()) == 0) {
+ NODE *save = eval_tree;
+
+ Init_ext();
+ ext_init = 1;
+ rb_require_modules();
+ eval_tree = save;
+ ruby_process_options(argc, argv);
+ }
+ POP_TAG();
+ if (state) error_print();
+}
+
static VALUE
eval_node(self)
VALUE self;
@@ -555,7 +694,7 @@ eval_node(self)
VALUE result = Qnil;
NODE *tree;
- if (!eval_tree) return FALSE;
+ if (!eval_tree) return Qnil;
tree = eval_tree;
eval_tree = 0;
@@ -569,11 +708,16 @@ int rb_in_eval;
#ifdef THREAD
static void thread_cleanup();
static void thread_wait_other_threads();
+static VALUE thread_current();
#endif
static int exit_status;
+#if (_MSC_VER >= 1000)
+__declspec(dllexport) void __stdcall
+#else
void
+#endif
ruby_run()
{
NODE *state;
@@ -587,6 +731,7 @@ ruby_run()
PUSH_TAG();
PUSH_ITER(ITER_NOT);
if ((state = EXEC_TAG()) == 0) {
+ if (!ext_init) Init_ext();
eval_node(TopSelf);
}
POP_ITER();
@@ -613,6 +758,7 @@ ruby_run()
}
switch (ex->nd_tag) {
+ case IN_BLOCK|TAG_RETURN:
case TAG_RETURN:
error_pos();
fprintf(stderr, "unexpected return\n");
@@ -623,6 +769,7 @@ ruby_run()
fprintf(stderr, "unexpected next\n");
exit(1);
break;
+ case IN_BLOCK|TAG_BREAK:
case TAG_BREAK:
error_pos();
fprintf(stderr, "unexpected break\n");
@@ -635,7 +782,7 @@ ruby_run()
break;
case TAG_RETRY:
error_pos();
- fprintf(stderr, "retry outside of protect clause\n");
+ fprintf(stderr, "retry outside of rescue clause\n");
exit(1);
break;
case TAG_RAISE:
@@ -643,7 +790,7 @@ ruby_run()
if (obj_is_kind_of(errinfo, eSystemExit)) {
exit(exit_status);
}
- error_print(ex);
+ error_print();
exit(1);
break;
case TAG_THROW:
@@ -665,7 +812,7 @@ compile_error(at)
mesg = errinfo;
nerrs = 0;
- errinfo = exc_new(eSyntaxError, "compile error in ");
+ errinfo = exc_new2(eSyntaxError, "compile error in ");
str_cat(errinfo, at, strlen(at));
str_cat(errinfo, ":\n", 2);
str_cat(errinfo, RSTRING(mesg)->ptr, RSTRING(mesg)->len);
@@ -692,6 +839,7 @@ rb_eval_cmd(cmd, arg)
{
NODE *state;
struct SCOPE *saved_scope;
+ volatile int safe = rb_safe_level();
if (TYPE(cmd) != T_STRING) {
if (obj_is_kind_of(cmd, cProc)) {
@@ -706,12 +854,16 @@ rb_eval_cmd(cmd, arg)
the_scope = top_scope;
the_class = (struct RClass*)cObject;
+ if (str_tainted(cmd)) {
+ safe_level = 5;
+ }
if ((state = EXEC_TAG()) == 0) {
eval(TopSelf, cmd, Qnil);
}
the_scope = saved_scope;
+ safe_level = safe;
POP_TAG();
POP_CLASS();
@@ -730,7 +882,7 @@ rb_eval_cmd(cmd, arg)
Raise(eLocalJumpError, "unexpected redo");
break;
case TAG_RETRY:
- Raise(eLocalJumpError, "retry outside of protect clause");
+ Raise(eLocalJumpError, "retry outside of rescue clause");
break;
default:
JUMP_TAG(state);
@@ -761,7 +913,7 @@ superclass(self, node)
VALUE self;
NODE *node;
{
- VALUE val;
+ VALUE val = 0;
NODE *state;
PUSH_TAG();
@@ -769,18 +921,24 @@ superclass(self, node)
val = rb_eval(self, node);
}
POP_TAG();
- if ((state && state->nd_tag == TAG_RAISE) || !val || TYPE(val) != T_CLASS){
- switch (nd_type(node)) {
- case NODE_COLON2:
- TypeError("undefined superclass `%s'", rb_id2name(node->nd_mid));
- case NODE_CVAR:
- case NODE_CONST:
- TypeError("undefined superclass `%s'", rb_id2name(node->nd_vid));
+ if (state) {
+ if (state->nd_tag == TAG_RAISE) {
+ superclass_error:
+ switch (nd_type(node)) {
+ case NODE_COLON2:
+ TypeError("undefined superclass `%s'", rb_id2name(node->nd_mid));
+ case NODE_CVAR:
+ TypeError("undefined superclass `%s'", rb_id2name(node->nd_vid));
+ default:
+ TypeError("superclass undefined");
+ }
}
- if (state) JUMP_TAG(state);
- TypeError("superclass undefined");
+ JUMP_TAG(state);
+ }
+ if (TYPE(val) != T_CLASS) goto superclass_error;
+ if (FL_TEST(val, FL_SINGLETON)) {
+ TypeError("can't make subclass of virtual class");
}
- if (state) JUMP_TAG(state);
return val;
}
@@ -824,8 +982,8 @@ ev_const_get(cref, id)
return rb_const_get(cref->nd_clss, id);
}
-#define SETUP_ARGS {\
- NODE *n = node->nd_args;\
+#define SETUP_ARGS(anode) {\
+ NODE *n = anode;\
if (!n) {\
argc = 0;\
argv = 0;\
@@ -834,14 +992,15 @@ ev_const_get(cref, id)
argc=n->nd_alen;\
if (argc > 0) {\
int i;\
- n = node->nd_args;\
+ int line = sourceline;\
+ n = anode;\
argv = ALLOCA_N(VALUE,argc);\
for (i=0;i<argc;i++) {\
argv[i] = rb_eval(self,n->nd_head);\
n=n->nd_next;\
}\
- sourceline = nd_line(node);\
- sourcefile = node->file;\
+ sourcefile = anode->file;\
+ sourceline = line;\
}\
else {\
argc = 0;\
@@ -850,13 +1009,14 @@ ev_const_get(cref, id)
}\
else {\
VALUE args = rb_eval(self,n);\
+ int line = sourceline;\
if (TYPE(args) != T_ARRAY)\
args = rb_to_a(args);\
argc = RARRAY(args)->len;\
argv = ALLOCA_N(VALUE, argc);\
MEMCPY(argv, RARRAY(args)->ptr, VALUE, argc);\
- sourceline = nd_line(node);\
- sourcefile = node->file;\
+ sourcefile = anode->file;\
+ sourceline = line;\
}\
}
@@ -867,25 +1027,225 @@ rb_test_false_or_nil(v)
return (v != Qnil) && (v != FALSE);
}
+#define MATCH_DATA the_scope->local_vars[node->nd_cnt]
+
+static char*
+is_defined(self, node, buf)
+ VALUE self;
+ NODE *node; /* OK */
+ char *buf;
+{
+ VALUE val; /* OK */
+ NODE *state;
+
+ node = node->nd_head;
+
+ switch (nd_type(node)) {
+ case NODE_SUPER:
+ case NODE_ZSUPER:
+ if (the_frame->last_func == 0) return 0;
+ else if (method_boundp(the_frame->last_class->super,
+ the_frame->last_func, 1)) {
+ return "super";
+ }
+ break;
+
+ case NODE_FCALL:
+ case NODE_VCALL:
+ val = CLASS_OF(self);
+ goto check_bound;
+
+ case NODE_CALL:
+ PUSH_TAG();
+ if ((state = EXEC_TAG()) == 0) {
+ val = rb_eval(self, node->nd_recv);
+ val = CLASS_OF(val);
+ }
+ POP_TAG();
+ if (state) {
+ return 0;
+ }
+ check_bound:
+ if (method_boundp(val, node->nd_mid,
+ nd_type(node)== NODE_CALL)) {
+ return "method";
+ }
+ break;
+
+ case NODE_YIELD:
+ if (iterator_p()) {
+ return "yield";
+ }
+ break;
+
+ case NODE_SELF:
+ return "self";
+
+ case NODE_NIL:
+ return "nil";
+
+ case NODE_ATTRSET:
+ case NODE_OP_ASGN1:
+ case NODE_OP_ASGN2:
+ case NODE_MASGN:
+ case NODE_LASGN:
+ case NODE_DASGN:
+ case NODE_GASGN:
+ case NODE_IASGN:
+ case NODE_CASGN:
+ return "assignment";
+
+ case NODE_LVAR:
+ case NODE_DVAR:
+ return "local-variable";
+
+ case NODE_GVAR:
+ if (rb_gvar_defined(node->nd_entry)) {
+ return "global-variable";
+ }
+ break;
+
+ case NODE_IVAR:
+ if (rb_ivar_defined(self, node->nd_vid)) {
+ return "instance-variable";
+ }
+ break;
+
+ case NODE_CVAR:
+ if (ev_const_defined(the_frame->cbase, node->nd_vid)) {
+ return "constant";
+ }
+ break;
+
+ case NODE_COLON2:
+ PUSH_TAG();
+ if ((state = EXEC_TAG()) == 0) {
+ val = rb_eval(self, node->nd_head);
+ }
+ POP_TAG();
+ if (state) {
+ return 0;
+ }
+ else {
+ switch (TYPE(val)) {
+ case T_CLASS:
+ case T_MODULE:
+ if (rb_const_defined_at(val, node->nd_mid))
+ return "constant";
+ }
+ }
+ break;
+
+ case NODE_NTH_REF:
+ if (reg_nth_defined(node->nd_nth, MATCH_DATA)) {
+ sprintf(buf, "$%d", node->nd_nth);
+ return buf;
+ }
+ break;
+
+ case NODE_BACK_REF:
+ if (reg_nth_defined(0, MATCH_DATA)) {
+ sprintf(buf, "$%c", node->nd_nth);
+ return buf;
+ }
+ break;
+
+ default:
+ PUSH_TAG();
+ if ((state = EXEC_TAG()) == 0) {
+ rb_eval(self, node);
+ }
+ POP_TAG();
+ if (!state) {
+ return "expression";
+ }
+ break;
+ }
+ return 0;
+}
+
static int handle_rescue();
VALUE rb_yield_0();
+static void blk_free();
+
+static VALUE
+set_trace_func(obj, trace)
+ VALUE obj;
+ struct RData *trace;
+{
+ if (NIL_P(trace)) {
+ trace_func = 0;
+ return Qnil;
+ }
+ if (TYPE(trace) != T_DATA || trace->dfree != blk_free) {
+ TypeError("trace_func needs to be Proc");
+ }
+ return trace_func = (VALUE)trace;
+}
+
+static void
+call_trace_func(event, file, line, self, id)
+ char *event;
+ char *file;
+ int line;
+ VALUE self;
+ ID id;
+{
+ NODE *state;
+ volatile VALUE trace;
+ struct FRAME *prev;
+
+ if (!trace_func) return;
+
+ trace = trace_func;
+ trace_func = 0;
+#ifdef THREAD
+ thread_critical++;
+#endif
+
+ prev = the_frame;
+ PUSH_FRAME();
+ *the_frame = *_frame.prev;
+ the_frame->prev = prev;
+
+ the_frame->line = sourceline = line;
+ the_frame->file = sourcefile = file;
+ PUSH_TAG();
+ if ((state = EXEC_TAG()) == 0) {
+ proc_call(trace, ary_new3(5, str_new2(event),
+ str_new2(sourcefile),
+ INT2FIX(sourceline),
+ INT2FIX(id),
+ self?f_binding(self):Qnil));
+ }
+ POP_TAG();
+ POP_FRAME();
+
+#ifdef THREAD
+ thread_critical--;
+#endif
+ if (!trace_func) trace_func = trace;
+ if (state) JUMP_TAG(state);
+}
+
static VALUE
rb_eval(self, node)
VALUE self;
- register NODE *node;
+ NODE * volatile node;
{
NODE *state;
- VALUE result = Qnil;
+ volatile VALUE result = Qnil;
#define RETURN(v) { result = (v); goto finish; }
again:
if (!node) RETURN(Qnil);
+#if 0
sourceline = nd_line(node);
sourcefile = node->file;
-
+#endif
switch (nd_type(node)) {
case NODE_BLOCK:
while (node) {
@@ -926,15 +1286,6 @@ rb_eval(self, node)
}
goto again;
- case NODE_UNLESS:
- if (!RTEST(rb_eval(self, node->nd_cond))) {
- node = node->nd_body;
- }
- else {
- node = node->nd_else;
- }
- goto again;
-
case NODE_CASE:
{
VALUE val;
@@ -945,13 +1296,17 @@ rb_eval(self, node)
NODE *tag;
if (nd_type(node) != NODE_WHEN) {
-
- RETURN(rb_eval(self, node));
+ goto again;
}
tag = node->nd_head;
while (tag) {
+ if (trace_func) {
+ call_trace_func("line", tag->file, nd_line(tag),
+ self, the_frame->last_func);
+ }
if (RTEST(rb_funcall2(rb_eval(self, tag->nd_head),eqq,1,&val))){
- RETURN(rb_eval(self, node->nd_body));
+ node = node->nd_body;
+ goto again;
}
tag = tag->nd_next;
}
@@ -963,15 +1318,14 @@ rb_eval(self, node)
case NODE_WHILE:
PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
- while_next:
- for (;;) {
- if (node->nd_state && !RTEST(rb_eval(self, node->nd_cond)))
- break;
+ if (node->nd_state && !RTEST(rb_eval(self, node->nd_cond)))
+ goto while_out;
+ do {
while_redo:
rb_eval(self, node->nd_body);
- if (!node->nd_state && !RTEST(rb_eval(self, node->nd_cond)))
- break;
- }
+ while_next:
+ ;
+ } while (RTEST(rb_eval(self, node->nd_cond)));
}
else {
switch (state->nd_tag) {
@@ -981,12 +1335,15 @@ rb_eval(self, node)
case TAG_NEXT:
state = 0;
goto while_next;
+ case TAG_BREAK:
+ state = 0;
default:
break;
}
}
+ while_out:
POP_TAG();
- if (state && state->nd_tag != TAG_BREAK) {
+ if (state) {
JUMP_TAG(state);
}
RETURN(Qnil);
@@ -994,30 +1351,32 @@ rb_eval(self, node)
case NODE_UNTIL:
PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
- until_next:
- for (;;) {
- if (node->nd_state && RTEST(rb_eval(self, node->nd_cond)))
- break;
+ if (node->nd_state && RTEST(rb_eval(self, node->nd_cond)))
+ goto until_out;
+ do {
until_redo:
rb_eval(self, node->nd_body);
- if (!node->nd_state && RTEST(rb_eval(self, node->nd_cond)))
- break;
- }
+ until_next:
+ ;
+ } while (!RTEST(rb_eval(self, node->nd_cond)));
}
else {
switch (state->nd_tag) {
case TAG_REDO:
state = 0;
- goto while_redo;
+ goto until_redo;
case TAG_NEXT:
state = 0;
- goto while_next;
+ goto until_next;
+ case TAG_BREAK:
+ state = 0;
default:
break;
}
}
+ until_out:
POP_TAG();
- if (state && state->nd_tag != TAG_BREAK) {
+ if (state) {
JUMP_TAG(state);
}
RETURN(Qnil);
@@ -1040,11 +1399,12 @@ rb_eval(self, node)
}
else {
VALUE recv;
+ int line = sourceline;
recv = rb_eval(self, node->nd_iter);
PUSH_ITER(ITER_PRE);
- sourceline = nd_line(node);
sourcefile = node->file;
+ sourceline = line;
result = rb_call(CLASS_OF(recv),recv,each,0,0,0);
POP_ITER();
}
@@ -1080,39 +1440,44 @@ rb_eval(self, node)
case NODE_RESCUE:
retry_entry:
- PUSH_TAG();
- if ((state = EXEC_TAG()) == 0) {
- result = rb_eval(self, node->nd_head);
- }
- POP_TAG();
- if (state) {
- if (state->nd_tag == TAG_RAISE) {
- NODE *resq = node->nd_resq;
- while (resq) {
- if (handle_rescue(self, resq)) {
- state = 0;
- PUSH_TAG();
- if ((state = EXEC_TAG()) == 0) {
- result = rb_eval(self, resq->nd_body);
- }
- POP_TAG();
- if (state == 0) {
- errat = Qnil;
- }
- else if (state->nd_tag == TAG_RETRY) {
+ {
+ volatile VALUE e_info = errinfo, e_at = errat;
+
+ PUSH_TAG();
+ if ((state = EXEC_TAG()) == 0) {
+ result = rb_eval(self, node->nd_head);
+ }
+ POP_TAG();
+ if (state) {
+ if (state->nd_tag == TAG_RAISE) {
+ NODE * volatile resq = node->nd_resq;
+ while (resq) {
+ if (handle_rescue(self, resq)) {
state = 0;
- goto retry_entry;
+ PUSH_TAG();
+ if ((state = EXEC_TAG()) == 0) {
+ result = rb_eval(self, resq->nd_body);
+ }
+ POP_TAG();
+ if (state == 0) {
+ errinfo = e_info;
+ errat = e_at;
+ }
+ else if (state->nd_tag == TAG_RETRY) {
+ state = 0;
+ goto retry_entry;
+ }
+ break;
}
- break;
+ resq = resq->nd_head; /* next rescue */
}
- resq = resq->nd_head; /* next rescue */
}
- }
- if (state) {
- JUMP_TAG(state);
+ if (state) {
+ JUMP_TAG(state);
+ }
}
}
- break;
+ break;
case NODE_ENSURE:
PUSH_TAG();
@@ -1192,7 +1557,7 @@ rb_eval(self, node)
PUSH_ITER(ITER_NOT);
recv = rb_eval(self, node->nd_recv);
- SETUP_ARGS;
+ SETUP_ARGS(node->nd_args);
POP_ITER();
result = rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0);
}
@@ -1203,12 +1568,16 @@ rb_eval(self, node)
int argc; VALUE *argv; /* used in SETUP_ARGS */
PUSH_ITER(ITER_NOT);
- SETUP_ARGS;
+ SETUP_ARGS(node->nd_args);
POP_ITER();
result = rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,1);
}
break;
+ case NODE_VCALL:
+ result = rb_call(CLASS_OF(self),self,node->nd_mid,0,0,2);
+ break;
+
case NODE_SUPER:
case NODE_ZSUPER:
{
@@ -1220,7 +1589,7 @@ rb_eval(self, node)
}
else {
PUSH_ITER(ITER_NOT);
- SETUP_ARGS;
+ SETUP_ARGS(node->nd_args);
POP_ITER();
}
@@ -1239,7 +1608,9 @@ rb_eval(self, node)
PUSH_TAG();
if (node->nd_rval) the_frame->cbase = (VALUE)node->nd_rval;
if (node->nd_tbl) {
- the_scope->local_vars = ALLOCA_N(VALUE, node->nd_tbl[0]);
+ VALUE *vars = ALLOCA_N(VALUE, node->nd_tbl[0]+1);
+ *vars++ = (VALUE)node;
+ the_scope->local_vars = vars;
memclear(the_scope->local_vars, node->nd_tbl[0]);
the_scope->local_tbl = node->nd_tbl;
}
@@ -1259,17 +1630,17 @@ rb_eval(self, node)
case NODE_OP_ASGN1:
{
- VALUE recv, args, val;
+ int argc; VALUE *argv; /* used in SETUP_ARGS */
+ VALUE recv, val;
NODE *rval;
recv = rb_eval(self, node->nd_recv);
rval = node->nd_args->nd_head;
-
- args = rb_eval(self, node->nd_args->nd_next);
- val = rb_apply(recv, aref, args);
+ SETUP_ARGS(node->nd_args->nd_next);
+ val = rb_funcall2(recv, aref, argc-1, argv);
val = rb_funcall(val, node->nd_mid, 1, rb_eval(self, rval));
- ary_push(args, val);
- rb_apply(recv, aset, args);
+ argv[argc-1] = val;
+ val = rb_funcall2(recv, aset, argc, argv);
result = val;
}
break;
@@ -1282,7 +1653,7 @@ rb_eval(self, node)
recv = rb_eval(self, node->nd_recv);
val = rb_funcall(recv, id, 0);
- val = rb_funcall(recv, node->nd_next->nd_mid, 2, val,
+ val = rb_funcall(val, node->nd_next->nd_mid, 1,
rb_eval(self, node->nd_value));
rb_funcall2(recv, id_attrset(id), 1, &val);
@@ -1291,12 +1662,12 @@ rb_eval(self, node)
break;
case NODE_MASGN:
- result = masign(self, node, rb_eval(self, node->nd_value));
+ result = massign(self, node, rb_eval(self, node->nd_value));
break;
case NODE_LASGN:
if (the_scope->local_vars == 0)
- Bug("unexpected local variable asignment");
+ Bug("unexpected local variable assignment");
the_scope->local_vars[node->nd_cnt] = rb_eval(self, node->nd_value);
result = the_scope->local_vars[node->nd_cnt];
break;
@@ -1332,7 +1703,7 @@ rb_eval(self, node)
val = rb_eval(self, node->nd_value);
/* check for static scope constants */
if (verbose && ev_const_defined(the_frame->cbase, node->nd_vid)) {
- Warning("already initialized constnant %s",
+ Warning("already initialized constant %s",
rb_id2name(node->nd_vid));
}
rb_const_set(the_class, node->nd_vid, val);
@@ -1361,12 +1732,6 @@ rb_eval(self, node)
case NODE_CVAR:
result = ev_const_get(the_frame->cbase, node->nd_vid);
- nd_set_type(node, NODE_CONST);
- node->nd_cval = result;
- break;
-
- case NODE_CONST:
- result = node->nd_cval;
break;
case NODE_COLON2:
@@ -1386,7 +1751,6 @@ rb_eval(self, node)
}
break;
-#define MATCH_DATA the_scope->local_vars[node->nd_cnt]
case NODE_NTH_REF:
result = reg_nth_match(node->nd_nth, MATCH_DATA);
break;
@@ -1472,14 +1836,14 @@ rb_eval(self, node)
rb_in_eval++;
list->nd_head = compile(list->nd_head->nd_lit);
rb_in_eval--;
- if (!node) {
+ if (nerrs > 0) {
compile_error("string expand");
}
}
str2 = rb_eval(self, list->nd_head);
+ str2 = obj_as_string(str2);
}
if (str2) {
- str2 = obj_as_string(str2);
str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len);
}
list = list->nd_next;
@@ -1530,12 +1894,6 @@ rb_eval(self, node)
if (origin == (VALUE)the_class) {
Warning("redefine %s", rb_id2name(node->nd_mid));
}
- else {
- if (body->nd_noex != node->nd_noex) {
- Warning("change method %s's scope",
- rb_id2name(node->nd_mid));
- }
- }
rb_clear_cache();
}
@@ -1553,10 +1911,18 @@ rb_eval(self, node)
VALUE class;
NODE *body;
+ if (FIXNUM_P(recv)) {
+ TypeError("Can't define method \"%s\" for Fixnum",
+ rb_id2name(node->nd_mid));
+ }
if (NIL_P(recv)) {
TypeError("Can't define method \"%s\" for nil",
rb_id2name(node->nd_mid));
}
+ if (rb_special_const_p(recv)) {
+ TypeError("Can't define method \"%s\" for special constants",
+ rb_id2name(node->nd_mid));
+ }
class = rb_singleton_class(recv);
if (st_lookup(RCLASS(class)->m_tbl, node->nd_mid, &body)) {
@@ -1572,10 +1938,13 @@ rb_eval(self, node)
case NODE_UNDEF:
{
+ struct RClass *origin;
NODE *body;
- if (st_lookup(the_class->m_tbl, node->nd_mid, &body)) {
- Warning("redefine %s", rb_id2name(node->nd_mid));
+ body = search_method(the_class, node->nd_mid, &origin);
+ if (!body || !body->nd_body) {
+ NameError("undefined method `%s' for class `%s'",
+ rb_id2name(node->nd_mid), rb_class2name((VALUE)the_class));
}
rb_clear_cache();
rb_add_method(the_class, node->nd_mid, 0, NOEX_PUBLIC);
@@ -1588,6 +1957,11 @@ rb_eval(self, node)
result = Qnil;
break;
+ case NODE_VALIAS:
+ rb_alias_variable(node->nd_new, node->nd_old);
+ result = Qnil;
+ break;
+
case NODE_CLASS:
{
VALUE super, class;
@@ -1600,23 +1974,31 @@ rb_eval(self, node)
super = 0;
}
- if (!rb_autoload_defined(node->nd_cname) &&
- ev_const_defined(the_frame->cbase, node->nd_cname)) {
- class = rb_const_get(the_class, node->nd_cname);
- if (TYPE(class) != T_CLASS)
+ if (rb_const_defined_at(the_class, node->nd_cname) &&
+ ((VALUE)the_class != cObject ||
+ !rb_autoload_defined(node->nd_cname))) {
+
+ class = rb_const_get_at(the_class, node->nd_cname);
+ if (TYPE(class) != T_CLASS) {
TypeError("%s is not a class", rb_id2name(node->nd_cname));
+ }
if (super) {
tmp = RCLASS(class)->super;
- while (FL_TEST(tmp, FL_SINGLETON)) {
+ if (FL_TEST(tmp, FL_SINGLETON)) {
tmp = RCLASS(tmp)->super;
}
while (TYPE(tmp) == T_ICLASS) {
tmp = RCLASS(tmp)->super;
}
- if (tmp != RCLASS(super))
+ if (tmp != RCLASS(super)) {
TypeError("superclass mismatch for %s",
rb_id2name(node->nd_cname));
+ }
+ }
+ if (safe_level >= 4) {
+ Raise(eSecurityError, "extending class prohibited");
}
+ rb_clear_cache();
Warning("extending class %s", rb_id2name(node->nd_cname));
}
else {
@@ -1626,8 +2008,7 @@ rb_eval(self, node)
rb_set_class_path(class,the_class,rb_id2name(node->nd_cname));
}
- module_setup(class, node->nd_body);
- result = class;
+ result = module_setup(class, node->nd_body);
}
break;
@@ -1635,11 +2016,17 @@ rb_eval(self, node)
{
VALUE module;
- if (!rb_autoload_defined(node->nd_cname) &&
- ev_const_defined(the_frame->cbase, node->nd_cname)) {
- module = rb_const_get(the_class, node->nd_cname);
- if (TYPE(module) != T_MODULE)
+ if (rb_const_defined_at(the_class, node->nd_cname) &&
+ ((VALUE)the_class != cObject ||
+ !rb_autoload_defined(node->nd_cname))) {
+
+ module = rb_const_get_at(the_class, node->nd_cname);
+ if (TYPE(module) != T_MODULE) {
TypeError("%s is not a module", rb_id2name(node->nd_cname));
+ }
+ if (safe_level >= 4) {
+ Raise(eSecurityError, "extending module prohibited");
+ }
Warning("extending module %s", rb_id2name(node->nd_cname));
}
else {
@@ -1648,150 +2035,53 @@ rb_eval(self, node)
rb_set_class_path(module,the_class,rb_id2name(node->nd_cname));
}
- module_setup(module, node->nd_body);
- result = module;
+ result = module_setup(module, node->nd_body);
}
break;
- case NODE_DEFINED:
+ case NODE_SCLASS:
{
- VALUE obj;
- char buf[20];
- char *desc = 0;
-
- node = node->nd_head;
-
- switch (nd_type(node)) {
- case NODE_SUPER:
- case NODE_ZSUPER:
- if (the_frame->last_func == 0) result = FALSE;
- else {
- result = method_boundp(the_frame->last_class->super,
- the_frame->last_func, 1);
- }
- break;
-
- case NODE_FCALL:
- obj = CLASS_OF(self);
- goto check_bound;
-
- case NODE_CALL:
- PUSH_TAG();
- if ((state = EXEC_TAG()) == 0) {
- obj = rb_eval(self, node->nd_recv);
- }
- POP_TAG();
- if (state) {
- break;
- }
- else {
- if (state) JUMP_TAG(state);
- obj = CLASS_OF(obj);
- check_bound:
- if (method_boundp(obj, node->nd_mid,
- nd_type(node)== NODE_CALL)) {
- desc = "method";
- }
- }
- break;
-
- case NODE_YIELD:
- if (iterator_p()) {
- desc = "iterator";
- }
- break;
-
- case NODE_SELF:
- desc = "self"; break;
- case NODE_NIL:
- desc = "nil"; break;
-
- case NODE_ATTRSET:
- case NODE_OP_ASGN1:
- case NODE_OP_ASGN2:
- case NODE_MASGN:
- case NODE_LASGN:
- case NODE_DASGN:
- case NODE_GASGN:
- case NODE_IASGN:
- case NODE_CASGN:
- desc = "asignment"; break;
-
- case NODE_LVAR:
- desc = "local-variable"; break;
- case NODE_DVAR:
- desc = "dynamic-local-variable"; break;
-
- case NODE_GVAR:
- if (rb_gvar_defined(node->nd_entry)) {
- desc = "global-variable";
- }
- break;
-
- case NODE_IVAR:
- if (rb_ivar_defined(self, node->nd_vid)) {
- desc = "instance-variable";
- }
- break;
-
- case NODE_CVAR:
- if (ev_const_defined(the_frame->cbase, node->nd_vid)) {
- case NODE_CONST: /* jump in */
- desc = "class-constant";
- }
- break;
+ VALUE class;
- case NODE_COLON2:
- PUSH_TAG();
- if ((state = EXEC_TAG()) == 0) {
- obj = rb_eval(self, node->nd_head);
- }
- POP_TAG();
- if (state) {
- break;
- }
- else {
- if (state) JUMP_TAG(state);
- switch (TYPE(obj)) {
- case T_CLASS:
- case T_MODULE:
- if (rb_const_defined_at(obj, node->nd_mid))
- desc = "class-constant";
- break;
- }
- }
- break;
+ class = rb_eval(self, node->nd_recv);
+ if (FIXNUM_P(class)) {
+ TypeError("No virtual class for Fixnums");
+ }
+ if (NIL_P(class)) {
+ TypeError("No virtual class for nil");
+ }
+ if (rb_special_const_p(class)) {
+ TypeError("No virtual class for special constants");
+ }
+ if (FL_TEST(CLASS_OF(class), FL_SINGLETON)) {
+ rb_clear_cache();
+ }
+ class = rb_singleton_class(class);
- case NODE_NTH_REF:
- if (reg_nth_defined(node->nd_nth, MATCH_DATA)) {
- sprintf(buf, "$%d", node->nd_nth);
- desc = buf;
- }
- break;
+ result = module_setup(class, node->nd_body);
+ }
+ break;
- case NODE_BACK_REF:
- if (reg_nth_defined(0, MATCH_DATA)) {
- sprintf(buf, "$%c", node->nd_nth);
- desc = buf;
- }
- break;
+ case NODE_DEFINED:
+ {
+ char buf[20];
+ char *desc = is_defined(self, node, buf);
- default:
- PUSH_TAG();
- if ((state = EXEC_TAG()) == 0) {
- rb_eval(self, node);
- }
- POP_TAG();
- if (state) break;
- else {
- desc = "expression";
- }
- }
if (desc) result = str_new2(desc);
else result = FALSE;
}
break;
+ case NODE_NEWLINE:
+ sourcefile = node->file;
+ sourceline = node->nd_nth;
+ if (trace_func) {
+ call_trace_func("line", sourcefile, sourceline,
+ self, the_frame->last_func);
+ }
+ node = node->nd_next;
+ goto again;
+
default:
Bug("unknown node type %d", nd_type(node));
}
@@ -1800,13 +2090,14 @@ rb_eval(self, node)
return result;
}
-static void
+static VALUE
module_setup(module, node)
VALUE module;
- NODE *node;
+ NODE * volatile node;
{
NODE *state;
VALUE save = the_frame->cbase;
+ VALUE result; /* OK */
/* fill c-ref */
node->nd_clss = module;
@@ -1818,7 +2109,9 @@ module_setup(module, node)
if (node->nd_rval) the_frame->cbase = node->nd_rval;
if (node->nd_tbl) {
- the_scope->local_vars = ALLOCA_N(VALUE, node->nd_tbl[0]);
+ VALUE *vars = ALLOCA_N(VALUE, node->nd_tbl[0]+1);
+ *vars++ = (VALUE)node;
+ the_scope->local_vars = vars;
memclear(the_scope->local_vars, node->nd_tbl[0]);
the_scope->local_tbl = node->nd_tbl;
}
@@ -1829,13 +2122,23 @@ module_setup(module, node)
PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
- rb_eval((VALUE)the_class, node->nd_body);
+ if (trace_func) {
+ call_trace_func("class", node->file, nd_line(node),
+ the_class, the_frame->last_func);
+ }
+ result = rb_eval((VALUE)the_class, node->nd_body);
}
POP_TAG();
POP_SCOPE();
POP_CLASS();
the_frame->cbase = save;
+ if (trace_func) {
+ call_trace_func("end", node->file, nd_line(node), 0,
+ the_frame->last_func);
+ }
if (state) JUMP_TAG(state);
+
+ return result;
}
int
@@ -1850,7 +2153,7 @@ rb_respond_to(obj, id)
}
static VALUE
-krn_respond_to(argc, argv, obj)
+obj_respond_to(argc, argv, obj)
int argc;
VALUE *argv;
VALUE obj;
@@ -1870,7 +2173,7 @@ static VALUE
mod_method_defined(mod, mid)
VALUE mod, mid;
{
- if (rb_method_boundp(mod, rb_to_id(mid), TRUE)) {
+ if (rb_method_boundp(mod, rb_to_id(mid), 1)) {
return TRUE;
}
return FALSE;
@@ -1882,7 +2185,7 @@ rb_exit(status)
{
if (prot_tag) {
exit_status = status;
- rb_raise(exc_new(eSystemExit, ""));
+ rb_raise(exc_new(eSystemExit, 0, 0));
}
exit(status);
}
@@ -1895,6 +2198,7 @@ f_exit(argc, argv, obj)
{
VALUE status;
+ rb_secure(2);
if (rb_scan_args(argc, argv, "01", &status) == 1) {
status = NUM2INT(status);
}
@@ -1905,6 +2209,17 @@ f_exit(argc, argv, obj)
/* not reached */
}
+static VALUE
+f_abort()
+{
+ rb_secure(2);
+ if (errinfo) {
+ error_print();
+ }
+ rb_exit(1);
+ /* not reached */
+}
+
void
rb_break()
{
@@ -1946,8 +2261,8 @@ rb_longjmp(tag, mesg)
int tag;
VALUE mesg;
{
- if (NIL_P(errat) && NIL_P(mesg)) {
- errinfo = exc_new(eRuntimeError, "");
+ if (NIL_P(errinfo) && NIL_P(mesg)) {
+ errinfo = exc_new(eRuntimeError, 0, 0);
}
if (sourcefile && (NIL_P(errat) || !NIL_P(mesg))) {
@@ -1959,7 +2274,7 @@ rb_longjmp(tag, mesg)
errinfo = mesg;
}
else {
- errinfo = exc_new2(eRuntimeError, mesg);
+ errinfo = exc_new3(eRuntimeError, mesg);
}
str_freeze(errinfo);
}
@@ -1984,7 +2299,7 @@ rb_fatal(mesg)
void
rb_interrupt()
{
- rb_raise(exc_new(eInterrupt, "Interrupt"));
+ Raise(eInterrupt, "");
}
static VALUE
@@ -1994,23 +2309,30 @@ f_raise(argc, argv)
{
VALUE arg1, arg2;
VALUE etype, mesg;
+ int n;
etype = eRuntimeError;
mesg = Qnil;
- switch (rb_scan_args(argc, argv, "02", &arg1, &arg2)) {
+ switch (n = rb_scan_args(argc, argv, "02", &arg1, &arg2)) {
case 1:
mesg = arg1;
break;
case 2:
etype = arg1;
+ if (obj_is_kind_of(etype, eGlobalExit)) {
+ etype = CLASS_OF(etype);
+ }
+ else {
+ Check_Type(etype, T_CLASS);
+ }
mesg = arg2;
break;
}
if (!NIL_P(mesg)) {
Check_Type(mesg, T_STRING);
- if (!obj_is_kind_of(mesg, eException)) {
- mesg = exc_new2(etype, mesg);
+ if (n == 2 || !obj_is_kind_of(mesg, eException)) {
+ mesg = exc_new3(etype, mesg);
}
}
@@ -2036,11 +2358,12 @@ f_iterator_p()
VALUE
rb_yield_0(val, self)
- VALUE val, self;
+ VALUE val;
+ volatile VALUE self;
{
NODE *node;
NODE *state;
- VALUE result = Qnil;
+ volatile VALUE result = Qnil;
struct BLOCK *block;
struct SCOPE *old_scope;
struct FRAME frame;
@@ -2064,9 +2387,9 @@ rb_yield_0(val, self)
node = block->body;
if (block->var) {
if (nd_type(block->var) == NODE_MASGN)
- masign(self, block->var, val);
+ massign(self, block->var, val);
else
- asign(self, block->var, val);
+ assign(self, block->var, val);
}
PUSH_ITER(block->iter);
PUSH_TAG();
@@ -2076,7 +2399,7 @@ rb_yield_0(val, self)
result = Qnil;
}
else if (nd_type(node) == NODE_CFUNC) {
- result = (*node->nd_cfnc)(val,node->nd_argc,self);
+ result = (*node->nd_cfnc)(val, node->nd_argc, self);
}
else {
result = rb_eval(self, node);
@@ -2085,9 +2408,11 @@ rb_yield_0(val, self)
else {
switch (state->nd_tag) {
case TAG_REDO:
+ state = 0;
goto redo;
case TAG_NEXT:
state = 0;
+ result = Qnil;
break;
case TAG_BREAK:
case TAG_RETURN:
@@ -2123,7 +2448,8 @@ f_loop()
}
static VALUE
-masign(self, node, val)
+massign(self, node, val)
+ VALUE self;
NODE *node;
VALUE val;
{
@@ -2138,30 +2464,30 @@ masign(self, node, val)
}
len = RARRAY(val)->len;
for (i=0; list && i<len; i++) {
- asign(self, list->nd_head, RARRAY(val)->ptr[i]);
+ assign(self, list->nd_head, RARRAY(val)->ptr[i]);
list = list->nd_next;
}
if (node->nd_args) {
if (!list && i<len) {
- asign(self, node->nd_args, ary_new4(len-i, RARRAY(val)->ptr+i));
+ assign(self, node->nd_args, ary_new4(len-i, RARRAY(val)->ptr+i));
}
else {
- asign(self, node->nd_args, ary_new2(0));
+ assign(self, node->nd_args, ary_new2(0));
}
}
}
else if (node->nd_args) {
- asign(self, node->nd_args, Qnil);
+ assign(self, node->nd_args, Qnil);
}
while (list) {
- asign(self, list->nd_head, Qnil);
+ assign(self, list->nd_head, Qnil);
list = list->nd_next;
}
return val;
}
static void
-asign(self, lhs, val)
+assign(self, lhs, val)
VALUE self;
NODE *lhs;
VALUE val;
@@ -2177,7 +2503,7 @@ asign(self, lhs, val)
case NODE_LASGN:
if (the_scope->local_vars == 0)
- Bug("unexpected iterator variable asignment");
+ Bug("unexpected iterator variable assignment");
the_scope->local_vars[lhs->nd_cnt] = val;
break;
@@ -2209,7 +2535,7 @@ asign(self, lhs, val)
break;
default:
- Bug("bug in variable asignment");
+ Bug("bug in variable assignment");
break;
}
}
@@ -2220,7 +2546,7 @@ rb_iterate(it_proc, data1, bl_proc, data2)
void *data1, *data2;
{
NODE *state;
- VALUE retval = Qnil;
+ volatile VALUE retval = Qnil;
NODE *node = NEW_CFUNC(bl_proc, data2);
VALUE self = TopSelf;
int tag_level;
@@ -2234,8 +2560,8 @@ rb_iterate(it_proc, data1, bl_proc, data2)
if (state == 0) {
retval = (*it_proc)(data1);
}
-
POP_TAG();
+
tag_level = the_block->level;
POP_BLOCK();
POP_ITER();
@@ -2276,9 +2602,12 @@ handle_rescue(self, node)
}
PUSH_ITER(ITER_NOT);
- SETUP_ARGS;
+ SETUP_ARGS(node->nd_args);
POP_ITER();
while (argc--) {
+ if (!obj_is_kind_of(argv[0], cModule)) {
+ TypeError("class or module required for rescue clause");
+ }
if (obj_is_kind_of(errinfo, argv[0])) return 1;
argv++;
}
@@ -2291,7 +2620,7 @@ rb_rescue(b_proc, data1, r_proc, data2)
void *data1, *data2;
{
NODE *state;
- VALUE result;
+ volatile VALUE result;
PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
@@ -2302,8 +2631,7 @@ rb_rescue(b_proc, data1, r_proc, data2)
if (state->nd_tag == TAG_RAISE) {
if (r_proc) {
PUSH_TAG();
- state = EXEC_TAG();
- if (state == 0) {
+ if ((state = EXEC_TAG()) == 0) {
result = (*r_proc)(data2, errinfo);
}
POP_TAG();
@@ -2333,7 +2661,7 @@ rb_ensure(b_proc, data1, e_proc, data2)
void *data1, *data2;
{
NODE *state;
- VALUE result = Qnil;
+ volatile VALUE result = Qnil;
PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
@@ -2348,7 +2676,9 @@ rb_ensure(b_proc, data1, e_proc, data2)
return result;
}
-static int last_noex;
+static int last_call_status;
+#define CSTAT_NOEX 1
+#define CSTAT_VCALL 2
static VALUE
f_missing(argc, argv, obj)
@@ -2358,8 +2688,9 @@ f_missing(argc, argv, obj)
{
VALUE desc = 0;
ID id;
- char *format;
- struct FRAME *frame;
+ char *format = 0;
+ char *file = sourcefile;
+ int line = sourceline;
id = FIX2INT(argv[0]);
argc--; argv++;
@@ -2382,36 +2713,48 @@ f_missing(argc, argv, obj)
break;
}
if (desc) {
- if (last_noex)
+ if (last_call_status & CSTAT_NOEX) {
format = "private method `%s' called for %s(%s)";
- else if (argc == 0) {
- format = "undefined local variable or method `%s' for %s(%s)";
}
- else {
+ else if (iterator_p()) {
+ format = "undefined iterator `%s' for %s(%s)";
+ }
+ else if (last_call_status & CSTAT_VCALL) {
+ char *mname = rb_id2name(id);
+
+ if (('a' <= mname[0] && mname[0] <= 'z') || mname[0] == '_') {
+ format = "undefined local variable or method `%s' for %s(%s)";
+ }
+ }
+ if (!format) {
format = "undefined method `%s' for %s(%s)";
}
if (RSTRING(desc)->len > 65) {
- desc = krn_to_s(obj);
+ desc = any_to_s(obj);
}
}
+ sourcefile = file;
+ sourceline = line;
PUSH_FRAME(); /* fake frame */
*the_frame = *_frame.prev->prev;
NameError(format,
rb_id2name(id),
- desc?RSTRING(desc)->ptr:"",
+ desc?(char*)RSTRING(desc)->ptr:"",
desc?rb_class2name(CLASS_OF(obj)):"");
POP_FRAME();
+
+ return Qnil; /* not reached */
}
static VALUE
-rb_undefined(obj, id, argc, argv, noex)
+rb_undefined(obj, id, argc, argv, call_status)
VALUE obj;
ID id;
int argc;
VALUE*argv;
- int noex;
+ int call_status;
{
VALUE *nargv;
@@ -2419,12 +2762,21 @@ rb_undefined(obj, id, argc, argv, noex)
nargv[0] = INT2FIX(id);
MEMCPY(nargv+1, argv, VALUE, argc);
- last_noex = noex;
+ last_call_status = call_status;
return rb_funcall2(obj, rb_intern("method_missing"), argc+1, nargv);
}
-#define STACK_LEVEL_MAX 655350
+#ifdef DJGPP
+# define STACK_LEVEL_MAX 65535
+#else
+#ifdef __human68k__
+extern int _stacksize;
+# define STACK_LEVEL_MAX (_stacksize - 4096)
+#else
+# define STACK_LEVEL_MAX 655350
+#endif
+#endif
extern VALUE *gc_stack_start;
static int
stack_length()
@@ -2444,19 +2796,20 @@ rb_call(class, recv, mid, argc, argv, scope)
struct RClass *class;
VALUE recv;
ID mid;
- int argc;
- VALUE *argv;
+ int argc; /* OK */
+ VALUE *argv; /* OK */
int scope;
{
- NODE *body;
+ NODE *body, *b2; /* OK */
int noex;
ID id = mid;
struct cache_entry *ent;
- VALUE result = Qnil;
+ volatile VALUE result = Qnil;
int itr;
enum node_type type;
static int tick;
+ again:
/* is it in the method cache? */
ent = cache + EXPR1(class, mid);
if (ent->mid == mid && ent->class == class) {
@@ -2466,12 +2819,12 @@ rb_call(class, recv, mid, argc, argv, scope)
body = ent->method;
}
else if ((body = rb_get_method_body(&class, &id, &noex)) == 0) {
- return rb_undefined(recv, mid, argc, argv, 0);
+ return rb_undefined(recv, mid, argc, argv, scope==2?CSTAT_VCALL:0);
}
/* receiver specified form for private method */
if (noex == NOEX_PRIVATE && scope == 0)
- return rb_undefined(recv, mid, argc, argv, 1);
+ return rb_undefined(recv, mid, argc, argv, CSTAT_NOEX);
switch (the_iter->iter) {
case ITER_PRE:
@@ -2485,11 +2838,27 @@ rb_call(class, recv, mid, argc, argv, scope)
type = nd_type(body);
if (type == NODE_ZSUPER) {
- /* for re-scoped method */
- return rb_call(class->super, recv, id, argc, argv, scope?scope:1);
+ /* for re-scoped/renamed method */
+ mid = id;
+ if (scope == 0) scope = 1;
+ if (class->super == 0) {
+ /* origin is the Module, so need to scan superclass hierarchy. */
+ struct RClass *cl = class;
+
+ class = (struct RClass*)RBASIC(recv)->class;
+ while (class) {
+ if (class->m_tbl == cl->m_tbl)
+ break;
+ class = class->super;
+ }
+ }
+ else {
+ class = class->super;
+ }
+ goto again;
}
- if (++tick % 1000 == 0 && stack_length() > STACK_LEVEL_MAX)
+ if ((++tick & 0xfff) == 0 && stack_length() > STACK_LEVEL_MAX)
Fatal("stack level too deep");
PUSH_ITER(itr);
@@ -2602,7 +2971,7 @@ rb_call(class, recv, mid, argc, argv, scope)
default:
if (len < 0) {
Bug("bad argc(%d) specified for `%s(%s)'",
- len, rb_class2name(class), rb_id2name(mid));
+ len, rb_class2name((VALUE)class), rb_id2name(mid));
}
else {
ArgError("too many arguments(%d)", len);
@@ -2627,7 +2996,8 @@ rb_call(class, recv, mid, argc, argv, scope)
if (body->nd_rval) the_frame->cbase = body->nd_rval;
if (body->nd_tbl) {
- local_vars = ALLOCA_N(VALUE, body->nd_tbl[0]);
+ local_vars = ALLOCA_N(VALUE, body->nd_tbl[0]+1);
+ *local_vars++ = (VALUE)body;
memclear(local_vars, body->nd_tbl[0]);
the_scope->local_tbl = body->nd_tbl;
the_scope->local_vars = local_vars;
@@ -2636,13 +3006,12 @@ rb_call(class, recv, mid, argc, argv, scope)
local_vars = the_scope->local_vars = 0;
the_scope->local_tbl = 0;
}
- body = body->nd_body;
+ b2 = body = body->nd_body;
PUSH_TAG();
PUSH_VARS();
- dyna_var_mark();
- state = EXEC_TAG();
- if (state == 0) {
+
+ if ((state = EXEC_TAG()) == 0) {
if (nd_type(body) == NODE_BLOCK) {
NODE *node = body->nd_head;
int i;
@@ -2653,11 +3022,22 @@ rb_call(class, recv, mid, argc, argv, scope)
body = body->nd_next;
i = node->nd_cnt;
- if (i > argc
- || (node->nd_rest == -1
- && i+(node->nd_opt?node->nd_opt->nd_alen:0)<argc)){
+ if (i > argc) {
ArgError("Wrong # of arguments(%d for %d)", argc, i);
}
+ if (node->nd_rest == -1) {
+ int opt = argc - i;
+ NODE *optnode = node->nd_opt;
+
+ while (optnode) {
+ opt--;
+ optnode = optnode->nd_next;
+ }
+ if (opt > 0) {
+ ArgError("Wrong # of arguments(%d for %d)",
+ argc, argc-opt);
+ }
+ }
if (local_vars) {
if (i > 0) {
@@ -2668,7 +3048,7 @@ rb_call(class, recv, mid, argc, argv, scope)
NODE *opt = node->nd_opt;
while (opt && argc) {
- asign(recv, opt->nd_head, *argv);
+ assign(recv, opt->nd_head, *argv);
argv++; argc--;
opt = opt->nd_next;
}
@@ -2685,11 +3065,24 @@ rb_call(class, recv, mid, argc, argv, scope)
else if (nd_type(body) == NODE_ARGS) {
body = 0;
}
+ if (trace_func) {
+ call_trace_func("call", b2->file, nd_line(b2),
+ recv, the_frame->last_func);
+ }
result = rb_eval(recv, body);
}
POP_VARS();
POP_TAG();
POP_SCOPE();
+ if (trace_func) {
+ char *file = the_frame->prev->file;
+ int line = the_frame->prev->line;
+ if (!file) {
+ file = sourcefile;
+ line = sourceline;
+ }
+ call_trace_func("return", file, line, 0, the_frame->last_func);
+ }
if (state) {
switch (state->nd_tag) {
case TAG_NEXT:
@@ -2752,7 +3145,11 @@ f_send(argc, argv, recv)
else {
mid = NUM2INT(vid);
}
- return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 1);
+ PUSH_ITER(iterator_p()?ITER_PRE:ITER_NOT);
+ vid = rb_call(CLASS_OF(recv), recv, mid, argc, argv, 1);
+ POP_ITER();
+
+ return vid;
}
#include <varargs.h>
@@ -2802,7 +3199,9 @@ backtrace(lev)
struct FRAME *frame = the_frame;
char buf[BUFSIZ];
VALUE ary;
+ int slev = safe_level;
+ safe_level = 0;
ary = ary_new();
if (lev < 0) {
if (frame->last_func) {
@@ -2832,6 +3231,7 @@ backtrace(lev)
ary_push(ary, str_new2(buf));
frame = frame->prev;
}
+ safe_level = slev;
return ary;
}
@@ -2841,7 +3241,6 @@ f_caller(argc, argv)
VALUE *argv;
{
VALUE level;
- struct FRAME *frame = the_frame;
int lev;
rb_scan_args(argc, argv, "01", &level);
@@ -2857,12 +3256,12 @@ void
rb_backtrace()
{
int i, lev;
- VALUE ary, c;
+ VALUE ary;
lev = INT2FIX(0);
ary = backtrace(-1);
for (i=0; i<RARRAY(ary)->len; i++) {
- printf("\tfrom %s\n", RSTRING(RARRAY(ary)->ptr)->ptr);
+ printf("\tfrom %s\n", RSTRING(RARRAY(ary)->ptr[i])->ptr);
}
}
@@ -2889,15 +3288,12 @@ compile(src)
Check_Type(src, T_STRING);
- errinfo = Qnil;
node = compile_string(sourcefile, src->ptr, src->len);
if (nerrs == 0) return node;
return 0;
}
-static void blk_free();
-
static VALUE
eval(self, src, scope)
VALUE self;
@@ -2905,57 +3301,70 @@ eval(self, src, scope)
struct RData *scope;
{
struct BLOCK *data;
- VALUE result = Qnil;
- NODE *node;
+ volatile VALUE result = Qnil;
NODE *state;
- struct BLOCK *old_block;
- struct SCOPE *old_scope;
+ volatile VALUE old_block;
+ volatile VALUE old_scope;
+ volatile VALUE old_d_vars;
struct FRAME frame;
char *file = sourcefile;
int line = sourceline;
+ volatile int iter = the_frame->iter;
- PUSH_TAG();
- PUSH_CLASS();
if (!NIL_P(scope)) {
if (TYPE(scope) != T_DATA || scope->dfree != blk_free) {
TypeError("wrong argument type %s (expected Proc/Binding)",
rb_class2name(CLASS_OF(scope)));
}
- Get_Data_Struct(scope, struct BLOCK, data);
+ Data_Get_Struct(scope, struct BLOCK, data);
/* PUSH BLOCK from data */
frame = data->frame;
frame.prev = the_frame;
the_frame = &(frame);
- old_scope = the_scope;
+ old_scope = (VALUE)the_scope;
the_scope = data->scope;
- old_block = the_block;
+ old_block = (VALUE)the_block;
the_block = data->prev;
+ old_d_vars = (VALUE)the_dyna_vars;
the_dyna_vars = data->d_vars;
- the_class = data->class;
+
self = data->self;
+ the_frame->iter = data->iter;
+ }
+ else {
+ if (the_frame->prev) {
+ the_frame->iter = the_frame->prev->iter;
+ }
}
+ PUSH_CLASS();
+ the_class = (struct RClass*)((NODE*)the_frame->cbase)->nd_clss;
rb_in_eval++;
if (TYPE(the_class) == T_ICLASS) {
the_class = (struct RClass*)RBASIC(the_class)->class;
}
+ PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
- if (!compile(src)) {
- rb_in_eval--;
+ compile(src);
+ if (nerrs > 0) {
compile_error("eval()");
}
result = eval_node(self);
}
+ POP_TAG();
+ POP_CLASS();
+ rb_in_eval--;
if (!NIL_P(scope)) {
the_frame = the_frame->prev;
- the_scope = old_scope;
- the_block = old_block;
+ the_scope = (struct SCOPE*)old_scope;
+ the_block = (struct BLOCK*)old_block;
+ the_dyna_vars = (struct RVarmap*)old_d_vars;
+ }
+ else {
+ the_frame->iter = iter;
}
- POP_CLASS();
- POP_TAG();
- rb_in_eval--;
if (state) {
VALUE err ;
@@ -2964,13 +3373,14 @@ eval(self, src, scope)
sourcefile = file;
sourceline = line;
if (strcmp(sourcefile, "(eval)") == 0) {
- err = errat;
- if (sourceline != 1) {
+ err = errinfo;
+ if (sourceline > 1) {
+ err = RARRAY(errat)->ptr[0];
str_cat(err, ": ", 2);
str_cat(err, RSTRING(errinfo)->ptr, RSTRING(errinfo)->len);
}
errat = Qnil;
- rb_raise(exc_new2(CLASS_OF(errinfo), err));
+ rb_raise(exc_new3(CLASS_OF(errinfo), err));
}
rb_raise(Qnil);
}
@@ -2989,6 +3399,8 @@ f_eval(argc, argv, self)
VALUE src, scope;
rb_scan_args(argc, argv, "11", &src, &scope);
+
+ Check_SafeStr(src);
return eval(self, src, scope);
}
@@ -3005,10 +3417,24 @@ find_file(file)
char *path;
if (file[0] == '/') return file;
+#if defined(MSDOS) || defined(NT) || defined(__human68k__)
+ if (file[0] == '\\') return file;
+ if (file[1] == ':') return file;
+#endif
if (rb_load_path) {
+ int i;
+
Check_Type(rb_load_path, T_ARRAY);
+ for (i=0;i<RARRAY(rb_load_path)->len;i++) {
+ Check_SafeStr(RARRAY(rb_load_path)->ptr[i]);
+ }
+#if !defined(MSDOS) && !defined(NT) && !defined(__human68k__)
vpath = ary_join(rb_load_path, str_new2(":"));
+#else
+ vpath = ary_join(rb_load_path, str_new2(";"));
+#endif
+ Check_SafeStr(vpath);
path = RSTRING(vpath)->ptr;
}
else {
@@ -3024,10 +3450,13 @@ f_load(obj, fname)
struct RString *fname;
{
NODE *state;
- char *file, *src;
+ char *file;
volatile ID last_func;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
+ if (fname->ptr[0] == '~') {
+ fname = (struct RString*)file_s_expand_path(0, fname);
+ }
file = find_file(fname->ptr);
if (!file) LoadError("No such file to load -- %s", fname->ptr);
@@ -3035,8 +3464,16 @@ f_load(obj, fname)
PUSH_CLASS();
the_class = (struct RClass*)cObject;
PUSH_SCOPE();
- the_scope->local_vars = top_scope->local_vars;
- the_scope->local_tbl = top_scope->local_tbl;
+ if (top_scope->local_tbl) {
+ int len = top_scope->local_tbl[0]+1;
+ ID *tbl = ALLOC_N(ID, len);
+ VALUE *vars = ALLOCA_N(VALUE, len);
+ *vars++ = 0;
+ MEMCPY(tbl, top_scope->local_tbl, ID, len);
+ MEMCPY(vars, top_scope->local_vars, ID, len-1);
+ the_scope->local_tbl = tbl;
+ the_scope->local_vars = vars;
+ }
state = EXEC_TAG();
last_func = the_frame->last_func;
@@ -3050,7 +3487,9 @@ f_load(obj, fname)
}
}
the_frame->last_func = last_func;
- top_scope->flag = the_scope->flag;
+ if (the_scope->flag == SCOPE_ALLOCA && the_scope->local_tbl) {
+ free(the_scope->local_tbl);
+ }
POP_SCOPE();
POP_CLASS();
POP_TAG();
@@ -3108,9 +3547,9 @@ f_require(obj, fname)
struct RString *fname;
{
char *ext, *file, *feature, *buf;
- VALUE load;
+ volatile VALUE load;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (rb_provided(fname->ptr))
return FALSE;
@@ -3216,7 +3655,7 @@ mod_public(argc, argv, module)
VALUE module;
{
set_method_visibility(module, argc, argv, NOEX_PUBLIC);
- return Qnil;
+ return module;
}
static VALUE
@@ -3226,7 +3665,27 @@ mod_private(argc, argv, module)
VALUE module;
{
set_method_visibility(module, argc, argv, NOEX_PRIVATE);
- return Qnil;
+ return module;
+}
+
+static VALUE
+mod_public_method(argc, argv, obj)
+ int argc;
+ VALUE *argv;
+ VALUE obj;
+{
+ set_method_visibility(CLASS_OF(obj), argc, argv, NOEX_PUBLIC);
+ return obj;
+}
+
+static VALUE
+mod_private_method(argc, argv, obj)
+ int argc;
+ VALUE *argv;
+ VALUE obj;
+{
+ set_method_visibility(CLASS_OF(obj), argc, argv, NOEX_PRIVATE);
+ return obj;
}
static VALUE
@@ -3237,8 +3696,9 @@ mod_modfunc(argc, argv, module)
{
int i;
ID id;
- NODE *body, *old;
+ NODE *body;
+ rb_clear_cache();
set_method_visibility(module, argc, argv, NOEX_PRIVATE);
for (i=0; i<argc; i++) {
id = rb_to_id(argv[i]);
@@ -3249,14 +3709,14 @@ mod_modfunc(argc, argv, module)
}
rb_add_method(rb_singleton_class(module), id, body->nd_body, NOEX_PUBLIC);
}
- return Qnil;
+ return module;
}
static VALUE
mod_include(argc, argv, module)
int argc;
VALUE *argv;
- struct RClass *module;
+ VALUE module;
{
int i;
@@ -3264,10 +3724,10 @@ mod_include(argc, argv, module)
Check_Type(argv[i], T_MODULE);
rb_include_module(module, argv[i]);
}
- return Qnil;
+ return module;
}
-VALUE /* moved from object.c for push_iter */
+VALUE
class_s_new(argc, argv, class)
int argc;
VALUE *argv;
@@ -3275,6 +3735,29 @@ class_s_new(argc, argv, class)
{
VALUE obj = obj_alloc(class);
+ if (FL_TEST(class, FL_SINGLETON)) {
+ TypeError("can't create instance of virtual class");
+ }
+ obj = obj_alloc(class);
+ PUSH_ITER(iterator_p()?ITER_PRE:ITER_NOT);
+ rb_funcall2(obj, init, argc, argv);
+ POP_ITER();
+ return obj;
+}
+
+
+VALUE
+class_new_instance(argc, argv, class)
+ int argc;
+ VALUE *argv;
+ VALUE class;
+{
+ VALUE obj;
+
+ if (FL_TEST(class, FL_SINGLETON)) {
+ TypeError("can't create instance of virtual class");
+ }
+ obj = obj_alloc(class);
PUSH_ITER(iterator_p()?ITER_PRE:ITER_NOT);
rb_funcall2(obj, init, argc, argv);
POP_ITER();
@@ -3286,9 +3769,25 @@ top_include(argc, argv)
int argc;
VALUE *argv;
{
+ rb_secure(4);
return mod_include(argc, argv, cObject);
}
+void
+rb_extend_object(obj, module)
+ VALUE obj, module;
+{
+ rb_include_module(rb_singleton_class(obj), module);
+}
+
+static VALUE
+mod_extend_object(mod, obj)
+ VALUE mod, obj;
+{
+ rb_extend_object(obj, mod);
+ return obj;
+}
+
static VALUE
obj_extend(argc, argv, obj)
int argc;
@@ -3297,41 +3796,43 @@ obj_extend(argc, argv, obj)
{
int i;
- mod_include(argc, argv, rb_singleton_class(obj));
+ for (i=0; i<argc; i++) Check_Type(argv[i], T_MODULE);
for (i=0; i<argc; i++) {
- rb_funcall(argv[i], rb_intern("object_extended"), 1, obj);
+ rb_funcall(argv[i], rb_intern("extend_object"), 1, obj);
}
- return Qnil;
-}
-
-void
-rb_extend_object(obj, module)
- VALUE obj, module;
-{
- rb_include_module(rb_singleton_class(obj), module);
+ return obj;
}
-extern VALUE cModule;
-
VALUE f_trace_var();
VALUE f_untrace_var();
-extern VALUE rb_str_setter();
+extern void rb_str_setter();
-static VALUE
+static void
errat_setter(val, id, var)
VALUE val;
ID id;
VALUE *var;
{
- if (!NIL_P(val) && TYPE(val) != T_ARRAY) {
- TypeError("value of $@ must be Array of String");
+ int i;
+ static char *err = "value of $@ must be Array of String";
+
+ if (!NIL_P(val)) {
+ if (TYPE(val) != T_ARRAY) {
+ TypeError(err);
+ }
+ for (i=0;i<RARRAY(val)->len;i++) {
+ if (TYPE(RARRAY(val)->ptr[i]) != T_STRING) {
+ TypeError(err);
+ }
+ }
}
- return *var = val;
+ *var = val;
}
static VALUE
f_catch(dmy, tag)
+ VALUE dmy, tag;
{
NODE *state;
ID t;
@@ -3383,45 +3884,53 @@ Init_eval()
rb_define_hooked_variable("$@", &errat, 0, errat_setter);
rb_define_hooked_variable("$!", &errinfo, 0, rb_str_setter);
- rb_define_private_method(cKernel, "eval", f_eval, -1);
- rb_define_private_method(cKernel, "iterator?", f_iterator_p, 0);
- rb_define_private_method(cKernel, "method_missing", f_missing, -1);
- rb_define_private_method(cKernel, "loop", f_loop, 0);
+ rb_define_global_function("eval", f_eval, -1);
+ rb_define_global_function("iterator?", f_iterator_p, 0);
+ rb_define_global_function("method_missing", f_missing, -1);
+ rb_define_global_function("loop", f_loop, 0);
- rb_define_method(cKernel, "respond_to?", krn_respond_to, -1);
+ rb_define_method(mKernel, "respond_to?", obj_respond_to, -1);
- rb_define_private_method(cKernel, "break", f_break, 0);
- rb_define_alias(cKernel, "break!", "break");
- rb_define_private_method(cKernel, "next", f_next, 0);
- rb_define_alias(cKernel, "next!", "next");
- rb_define_alias(cKernel, "continue", "next");
- rb_define_private_method(cKernel, "redo", f_redo, 0);
- rb_define_alias(cKernel, "redo!", "redo");
- rb_define_private_method(cKernel, "retry", f_retry, 0);
- rb_define_alias(cKernel, "retry!", "retry");
- rb_define_private_method(cKernel, "raise", f_raise, -1);
- rb_define_alias(cKernel, "fail", "raise");
+ rb_define_global_function("break", f_break, 0);
+ rb_define_alias(mKernel, "break!", "break");
+ rb_define_global_function("next", f_next, 0);
+ rb_define_alias(mKernel, "next!", "next");
+ rb_define_alias(mKernel, "continue", "next");
+ rb_define_global_function("redo", f_redo, 0);
+ rb_define_alias(mKernel, "redo!", "redo");
+ rb_define_global_function("retry", f_retry, 0);
+ rb_define_alias(mKernel, "retry!", "retry");
+ rb_define_global_function("raise", f_raise, -1);
+ rb_define_alias(mKernel, "fail", "raise");
- rb_define_private_method(cKernel, "caller", f_caller, -1);
+ rb_define_global_function("caller", f_caller, -1);
- rb_define_private_method(cKernel, "exit", f_exit, -1);
+ rb_define_global_function("exit", f_exit, -1);
+ rb_define_global_function("abort", f_abort, 0);
- rb_define_private_method(cKernel, "catch", f_catch, 1);
- rb_define_private_method(cKernel, "throw", f_throw, -1);
+ rb_define_global_function("catch", f_catch, 1);
+ rb_define_global_function("throw", f_throw, -1);
- rb_define_method(cKernel, "send", f_send, -1);
+ rb_define_method(mKernel, "send", f_send, -1);
- rb_define_method(cModule, "include", mod_include, -1);
- rb_define_method(cModule, "public", mod_public, -1);
- rb_define_method(cModule, "private", mod_private, -1);
- rb_define_method(cModule, "module_function", mod_modfunc, -1);
+ rb_define_private_method(cModule, "include", mod_include, -1);
+ rb_define_private_method(cModule, "public", mod_public, -1);
+ rb_define_private_method(cModule, "private", mod_private, -1);
+ rb_define_private_method(cModule, "module_function", mod_modfunc, -1);
rb_define_method(cModule, "method_defined?", mod_method_defined, 1);
+ rb_define_method(cModule, "extend_object", mod_extend_object, 1);
+ rb_define_method(cModule, "public_class_method", mod_public_method, -1);
+ rb_define_method(cModule, "private_class_method", mod_private_method, -1);
rb_define_method(CLASS_OF(TopSelf), "include", top_include, -1);
- rb_define_method(cObject, "extend", obj_extend, -1);
+ rb_define_method(mKernel, "extend", obj_extend, -1);
- rb_define_private_method(cKernel, "trace_var", f_trace_var, -1);
- rb_define_private_method(cKernel, "untrace_var", f_untrace_var, -1);
+ rb_define_global_function("trace_var", f_trace_var, -1);
+ rb_define_global_function("untrace_var", f_untrace_var, -1);
+
+ rb_define_global_function("set_trace_func", set_trace_func, 1);
+
+ rb_define_virtual_variable("$SAFE", safe_getter, safe_setter);
}
VALUE f_autoload();
@@ -3431,14 +3940,15 @@ Init_load()
{
rb_load_path = ary_new();
rb_define_readonly_variable("$:", &rb_load_path);
+ rb_define_readonly_variable("$-I", &rb_load_path);
rb_define_readonly_variable("$LOAD_PATH", &rb_load_path);
rb_features = ary_new();
rb_define_readonly_variable("$\"", &rb_features);
- rb_define_private_method(cKernel, "load", f_load, 1);
- rb_define_private_method(cKernel, "require", f_require, 1);
- rb_define_private_method(cKernel, "autoload", f_autoload, 2);
+ rb_define_global_function("load", f_load, 1);
+ rb_define_global_function("require", f_require, 1);
+ rb_define_global_function("autoload", f_autoload, 2);
}
static void
@@ -3448,17 +3958,19 @@ scope_dup(scope)
ID *tbl;
VALUE *vars;
- if (scope->flag == SCOPE_MALLOC) return;
+ if (scope->flag & SCOPE_MALLOC) return;
if (scope->local_tbl) {
tbl = scope->local_tbl;
- scope->local_tbl = ALLOC_N(ID, tbl[0]+1);
- MEMCPY(scope->local_tbl, tbl, ID, tbl[0]+1);
- vars = scope->local_vars;
- scope->local_vars = ALLOC_N(VALUE, tbl[0]);
- MEMCPY(scope->local_vars, vars, VALUE, tbl[0]);
+ vars = ALLOC_N(VALUE, tbl[0]+1);
+ *vars++ = scope->local_vars[-1];
+ MEMCPY(vars, scope->local_vars, VALUE, tbl[0]);
+ scope->local_vars = vars;
scope->flag = SCOPE_MALLOC;
}
+ else {
+ scope->flag = SCOPE_NOSTACK;
+ }
}
static void
@@ -3484,15 +3996,14 @@ static VALUE
f_binding(self)
VALUE self;
{
- extern VALUE cData;
struct BLOCK *data;
VALUE bind;
PUSH_BLOCK(0,0);
- bind = Make_Data_Struct(cData, struct BLOCK, blk_mark, blk_free, data);
+ bind = Data_Make_Struct(cData, struct BLOCK, blk_mark, blk_free, data);
MEMCPY(data, the_block, struct BLOCK, 1);
- data->iter = ITER_NOT;
+ data->iter = f_iterator_p();
data->frame.last_func = 0;
data->frame.argv = ALLOC_N(VALUE, data->frame.argc);
MEMCPY(data->frame.argv, the_block->frame.argv, VALUE, data->frame.argc);
@@ -3503,6 +4014,12 @@ f_binding(self)
return bind;
}
+#define PROC_TAINT FL_USER0
+#define PROC_T3 FL_USER1
+#define PROC_T4 FL_USER2
+#define PROC_T5 (FL_USER1|FL_USER2)
+#define PROC_TMASK (FL_USER1|FL_USER2)
+
static VALUE
proc_s_new(class)
VALUE class;
@@ -3514,14 +4031,31 @@ proc_s_new(class)
ArgError("tryed to create Procedure-Object out of iterator");
}
- proc = Make_Data_Struct(class, struct BLOCK, blk_mark, blk_free, data);
+ proc = Data_Make_Struct(class, struct BLOCK, blk_mark, blk_free, data);
*data = *the_block;
- data->iter = ITER_NOT;
+#ifdef THREAD
+ data->orig_thread = thread_current();
+#endif
+ data->iter = f_iterator_p();
data->frame.argv = ALLOC_N(VALUE, data->frame.argc);
MEMCPY(data->frame.argv, the_block->frame.argv, VALUE, data->frame.argc);
scope_dup(data->scope);
+ if (safe_level >= 3) {
+ FL_SET(proc, PROC_TAINT);
+ switch (safe_level) {
+ case 3:
+ FL_SET(proc, PROC_T3);
+ break;
+ case 4:
+ FL_SET(proc, PROC_T4);
+ break;
+ case 5:
+ FL_SET(proc, PROC_T5);
+ break;
+ }
+ }
return proc;
}
@@ -3537,9 +4071,11 @@ proc_call(proc, args)
VALUE proc, args;
{
struct BLOCK *data;
- VALUE result = Qnil;
+ volatile VALUE result = Qnil;
NODE *state;
int tag_level;
+ volatile int orphan;
+ volatile int safe = safe_level;
if (TYPE(args) == T_ARRAY) {
switch (RARRAY(args)->len) {
@@ -3552,14 +4088,48 @@ proc_call(proc, args)
}
}
- Get_Data_Struct(proc, struct BLOCK, data);
+ Data_Get_Struct(proc, struct BLOCK, data);
+
+ if (data->scope && (data->scope->flag & SCOPE_NOSTACK)) {
+ orphan = 1;
+ }
+ else {
+#ifdef THREAD
+ if (data->orig_thread != thread_current()) {
+ orphan = 1;
+ }
+ else
+#endif
+ orphan = 0;
+ }
+ if (orphan) {/* orphan procedure */
+ if (iterator_p()) {
+ data->frame.iter = ITER_CUR;
+ }
+ else {
+ data->frame.iter = ITER_NOT;
+ }
+ }
/* PUSH BLOCK from data */
PUSH_BLOCK2(data);
PUSH_ITER(ITER_CUR);
the_frame->iter = ITER_CUR;
- PUSH_TAG();
+ if (FL_TEST(proc, PROC_TAINT)) {
+ switch (RBASIC(proc)->flags & PROC_TMASK) {
+ case PROC_T3:
+ safe_level = 3;
+ break;
+ case PROC_T4:
+ safe_level = 4;
+ break;
+ case PROC_T5:
+ safe_level = 5;
+ break;
+ }
+ }
+ PUSH_TAG();
state = EXEC_TAG();
if (state == 0) {
result = rb_yield(args);
@@ -3569,15 +4139,14 @@ proc_call(proc, args)
POP_ITER();
tag_level = the_block->level;
POP_BLOCK();
+ safe_level = safe;
if (state) {
- if (data->scope && (data->scope->flag & SCOPE_NOSTACK)) {
- /* orphan procedure */
+ if (orphan) {/* orphan procedure */
switch (state->nd_tag) {
case TAG_BREAK: /* never happen */
- break;
case IN_BLOCK|TAG_BREAK:
- if (state->nd_tlev != tag_level)
+ if (state->nd_tlev == tag_level)
Raise(eLocalJumpError, "break from proc-closure");
break;
case TAG_RETRY:
@@ -3585,11 +4154,12 @@ proc_call(proc, args)
break;
case TAG_RETURN: /* never happen */
case IN_BLOCK|TAG_RETURN:
- Raise(eLocalJumpError, "return from proc-closure");
+ if (state->nd_tlev == tag_level)
+ Raise(eLocalJumpError, "return from proc-closure");
break;
}
}
- else {
+ else if (state->nd_tlev == tag_level) {
state->nd_tag &= ~IN_BLOCK;
}
JUMP_TAG(state);
@@ -3606,26 +4176,37 @@ Init_Proc()
rb_define_singleton_method(cProc, "new", proc_s_new, 0);
rb_define_method(cProc, "call", proc_call, -2);
- rb_define_private_method(cKernel, "proc", f_lambda, 0);
- rb_define_private_method(cKernel, "lambda", f_lambda, 0);
- rb_define_private_method(cKernel, "binding", f_binding, 0);
+ rb_define_global_function("proc", f_lambda, 0);
+ rb_define_global_function("lambda", f_lambda, 0);
+ rb_define_global_function("binding", f_binding, 0);
}
#ifdef THREAD
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
+static VALUE eThreadError;
int thread_pending = 0;
static VALUE cThread;
#include <sys/types.h>
-#include <sys/time.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#else
+#ifndef NT
+struct timeval {
+ long tv_sec; /* seconds */
+ long tv_usec; /* and microseconds */
+};
+#endif /* NT */
+#endif
#include <signal.h>
#include <errno.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
extern VALUE last_status;
enum thread_status {
@@ -3647,8 +4228,6 @@ typedef struct thread * thread_t;
struct thread {
struct thread *next, *prev;
jmp_buf context;
- VALUE (*func)();
- void *arg;
VALUE result;
@@ -3665,6 +4244,8 @@ struct thread {
struct iter *iter;
struct tag *tag;
+ VALUE trace;
+
char *file;
int line;
@@ -3673,11 +4254,16 @@ struct thread {
VALUE last_line;
VALUE last_match;
+ int safe;
+
enum thread_status status;
int wait_for;
int fd;
double delay;
thread_t join;
+
+ int abort;
+
VALUE thread;
};
@@ -3686,10 +4272,11 @@ static int num_waiting_on_fd;
static int num_waiting_on_timer;
static int num_waiting_on_join;
-thread_curr() {return (int)curr_thread;}
+#define FOREACH_THREAD_FROM(f,x) x = f; do { x = x->next;
+#define END_FOREACH_FROM(f,x) } while (x != f)
-#define FOREACH_THREAD(x) x = curr_thread; do { x = x->next;
-#define END_FOREACH(x) } while (x != curr_thread)
+#define FOREACH_THREAD(x) FOREACH_THREAD_FROM(curr_thread,x)
+#define END_FOREACH(x) END_FOREACH_FROM(curr_thread,x)
/* Return the current time as a floating-point number */
static double
@@ -3713,10 +4300,12 @@ thread_mark(th)
struct BLOCK *block;
gc_mark(th->result);
- gc_mark_locations(th->stk_ptr, th->stk_ptr+th->stk_len);
-#ifdef THINK_C
- gc_mark_locations(th->stk_ptr+2, th->stk_ptr+th->stk_len+2);
+ if (th->stk_ptr) {
+ gc_mark_locations(th->stk_ptr, th->stk_ptr+th->stk_len);
+#if defined(THINK_C) || defined(__human68k__)
+ gc_mark_locations(th->stk_ptr+2, th->stk_ptr+th->stk_len+2);
#endif
+ }
gc_mark(th->thread);
if (th->join) gc_mark(th->join->thread);
@@ -3780,7 +4369,7 @@ void lastline_set();
VALUE backref_get();
void backref_set();
-static int
+static void
thread_save_context(th)
thread_t th;
{
@@ -3808,7 +4397,9 @@ thread_save_context(th)
th->last_status = last_status;
th->last_line = lastline_get();
th->last_match = backref_get();
+ th->safe = safe_level;
+ th->trace = trace_func;
th->file = sourcefile;
th->line = sourceline;
}
@@ -3826,6 +4417,11 @@ stack_extend(th, exit)
thread_restore_context(th, exit);
}
+static int th_raise_argc;
+static VALUE th_raise_argv[2];
+static char *th_raise_file;
+static int th_raise_line;
+
static void
thread_restore_context(th, exit)
thread_t th;
@@ -3857,7 +4453,9 @@ thread_restore_context(th, exit)
errat = th->errat;
errinfo = th->errinfo;
last_status = th->last_status;
+ safe_level = th->safe;
+ trace_func = th->trace;
sourcefile = th->file;
sourceline = th->line;
@@ -3878,6 +4476,13 @@ thread_restore_context(th, exit)
rb_interrupt();
break;
+ case 3:
+ the_frame->last_func = 0;
+ sourcefile = th_raise_file;
+ sourceline = th_raise_line;
+ f_raise(th_raise_argc, th_raise_argv);
+ break;
+
default:
longjmp(tmp->context, 1);
}
@@ -3918,6 +4523,17 @@ thread_dead(th)
return th->status == THREAD_KILLED;
}
+static void
+thread_deadlock()
+{
+ curr_thread = main_thread;
+ th_raise_argc = 1;
+ th_raise_argv[0] = exc_new2(eFatal, "Thread: deadlock");
+ th_raise_file = sourcefile;
+ th_raise_line = sourceline;
+ f_abort();
+}
+
void
thread_schedule()
{
@@ -3925,27 +4541,29 @@ thread_schedule()
thread_t th;
thread_t curr;
+ select_err:
thread_pending = 0;
if (curr_thread == curr_thread->next) return;
next = 0;
- curr = curr_thread; /* real current thread */
+ curr = curr_thread; /* starting thread */
- if (curr_thread->status == THREAD_KILLED) {
- curr_thread = curr_thread->prev;
+ while (curr->status == THREAD_KILLED) {
+ curr = curr->prev;
}
- again:
- FOREACH_THREAD(th) {
- if (th->status != THREAD_STOPPED && th->status != THREAD_KILLED) {
- next = th;
- break;
- }
+ FOREACH_THREAD_FROM(curr,th) {
+ if (th->status != THREAD_STOPPED && th->status != THREAD_KILLED) {
+ next = th;
+ break;
+ }
}
- END_FOREACH(th);
+ END_FOREACH_FROM(curr,th);
if (num_waiting_on_join) {
- FOREACH_THREAD(th) {
+ curr_thread->file = sourcefile;
+ curr_thread->line = sourceline;
+ FOREACH_THREAD_FROM(curr,th) {
if ((th->wait_for & WAIT_JOIN) && thread_dead(th->join)) {
th->join = 0;
th->wait_for &= ~WAIT_JOIN;
@@ -3954,7 +4572,7 @@ thread_schedule()
if (!next) next = th;
}
}
- END_FOREACH(th);
+ END_FOREACH_FROM(curr,th);
}
if (num_waiting_on_fd > 0 || num_waiting_on_timer > 0) {
@@ -3965,23 +4583,22 @@ thread_schedule()
int n, max;
do {
- select_err:
max = 0;
FD_ZERO(&readfds);
if (num_waiting_on_fd > 0) {
- FOREACH_THREAD(th) {
+ FOREACH_THREAD_FROM(curr,th) {
if (th->wait_for & WAIT_FD) {
FD_SET(th->fd, &readfds);
if (th->fd > max) max = th->fd;
}
}
- END_FOREACH(th);
+ END_FOREACH_FROM(curr,th);
}
delay = DELAY_INFTY;
if (num_waiting_on_timer > 0) {
now = timeofday();
- FOREACH_THREAD(th) {
+ FOREACH_THREAD_FROM(curr,th) {
if (th->wait_for & WAIT_TIME) {
if (th->delay <= now) {
th->delay = 0.0;
@@ -3994,7 +4611,7 @@ thread_schedule()
}
}
}
- END_FOREACH(th);
+ END_FOREACH_FROM(curr,th);
}
/* Do the select if needed */
if (num_waiting_on_fd > 0 || !next) {
@@ -4014,11 +4631,16 @@ thread_schedule()
delay_tv.tv_usec = (delay - (double)delay_tv.tv_sec) * 1e6;
delay_ptr = &delay_tv;
}
+
n = select(max+1, &readfds, 0, 0, delay_ptr);
+ if (n < 0) {
+ if (trap_pending) rb_trap_exec();
+ goto select_err;
+ }
if (n > 0) {
/* Some descriptors are ready.
Make the corresponding threads runnable. */
- FOREACH_THREAD(th)
+ FOREACH_THREAD_FROM(curr,th) {
if ((th->wait_for&WAIT_FD)
&& FD_ISSET(th->fd, &readfds)) {
/* Wake up only one thread per fd. */
@@ -4029,9 +4651,9 @@ thread_schedule()
num_waiting_on_fd--;
if (!next) next = th; /* Found one. */
}
- END_FOREACH(th);
+ }
+ END_FOREACH_FROM(curr,th);
}
- if (n < 0 && !next) goto select_err;
}
/* The delays for some of the threads should have expired.
Go through the loop once more, to check the delays. */
@@ -4039,15 +4661,16 @@ thread_schedule()
}
if (!next) {
- FOREACH_THREAD(th) {
+ FOREACH_THREAD_FROM(curr,th) {
fprintf(stderr, "%s:%d:deadlock 0x%x: %d:%d %s\n",
th->file, th->line, th->thread, th->status,
th->wait_for, th==main_thread?"(main)":"");
}
- END_FOREACH(th);
- Fatal("Thread: deadlock");
+ END_FOREACH_FROM(curr,th);
+ /* raise fatal error to main thread */
+ thread_deadlock();
}
- if (next == curr) {
+ if (next == curr_thread) {
return;
}
@@ -4087,9 +4710,9 @@ thread_fd_writable(fd)
struct timeval zero;
fd_set fds;
- zero.tv_sec = zero.tv_usec = 0;
if (curr_thread == curr_thread->next) return;
+ zero.tv_sec = zero.tv_usec = 0;
for (;;) {
FD_ZERO(&fds);
FD_SET(fd, &fds);
@@ -4138,7 +4761,13 @@ thread_wait_for(time)
thread_schedule();
}
-void thread_sleep();
+void thread_sleep_forever();
+
+int
+thread_alone()
+{
+ return curr_thread == curr_thread->next;
+}
int
thread_select(max, read, write, except, timeout)
@@ -4153,8 +4782,8 @@ thread_select(max, read, write, except, timeout)
if (!read && !write && !except) {
if (!timeout) {
- thread_sleep();
- return;
+ thread_sleep_forever();
+ return 0;
}
thread_wait_for(*timeout);
return 0;
@@ -4229,22 +4858,22 @@ thread_select(max, read, write, except, timeout)
}
static VALUE
-thread_join(dmy, data)
+thread_join(dmy, thread)
VALUE dmy;
- struct RData *data;
+ VALUE thread;
{
- thread_t th = thread_check(data);
+ thread_t th = thread_check(thread);
- if (thread_dead(th)) return Qnil;
+ if (thread_dead(th)) return thread;
if ((th->wait_for & WAIT_JOIN) && th->join == curr_thread)
- Fatal("Thread.join: deadlock");
+ Raise(eThreadError, "Thread.join: deadlock");
curr_thread->status = THREAD_STOPPED;
curr_thread->join = th;
num_waiting_on_join++;
curr_thread->wait_for |= WAIT_JOIN;
thread_schedule();
- return Qnil;
+ return thread;
}
static VALUE
@@ -4253,39 +4882,48 @@ thread_current()
return curr_thread->thread;
}
-int
-th_cur()
+static VALUE
+thread_main()
{
- return (int)curr_thread;
+ return main_thread->thread;
}
static VALUE
-thread_run(data)
- struct RData *data;
+thread_wakeup(thread)
+ VALUE thread;
{
- thread_t th = thread_check(data);
+ thread_t th = thread_check(thread);
- if (th->status == THREAD_KILLED) Fail("killed thread");
+ if (th->status == THREAD_KILLED) Raise(eThreadError, "killed thread");
thread_ready(th);
- thread_schedule();
- return (VALUE)data;
+ return thread;
}
static VALUE
-thread_kill(data)
- struct RData *data;
+thread_run(thread)
+ VALUE thread;
{
- thread_t th = thread_check(data);
+ thread_wakeup(thread);
+ if (!thread_critical) thread_schedule();
- if (th->status == THREAD_TO_KILL) return Qnil;
- if (th->status == THREAD_KILLED) return Qnil;
+ return thread;
+}
+
+static VALUE
+thread_kill(thread)
+ VALUE thread;
+{
+ thread_t th = thread_check(thread);
+
+ if (th->status == THREAD_TO_KILL || th->status == THREAD_KILLED)
+ return thread;
if (th == th->next || th == main_thread) rb_exit(0);
thread_ready(th);
th->status = THREAD_TO_KILL;
thread_schedule();
- /* not reached */
+ return Qnil; /* not reached */
}
static VALUE
@@ -4302,25 +4940,47 @@ thread_exit()
}
static VALUE
-thread_stop_method(data)
- struct RData *data;
+thread_pass()
+{
+ thread_schedule();
+ return Qnil;
+}
+
+static VALUE
+thread_stop_method(thread)
+ VALUE thread;
{
- thread_t th = thread_check(data);
+ thread_t th = thread_check(thread);
+ thread_critical = 0;
th->status = THREAD_STOPPED;
thread_schedule();
- return Qnil;
+ return thread;
}
-static void
+static VALUE
thread_stop()
{
thread_stop_method(curr_thread->thread);
+ return Qnil;
}
void
-thread_sleep()
+thread_sleep(sec)
+ int sec;
+{
+ if (curr_thread == curr_thread->next) {
+ TRAP_BEG;
+ sleep(sec);
+ TRAP_END;
+ return;
+ }
+ thread_wait_for(time_timeval(INT2FIX(sec)));
+}
+
+void
+thread_sleep_forever()
{
if (curr_thread == curr_thread->next) {
TRAP_BEG;
@@ -4328,7 +4988,47 @@ thread_sleep()
TRAP_END;
return;
}
- thread_stop_method(curr_thread->thread);
+
+ num_waiting_on_timer++;
+ curr_thread->delay = DELAY_INFTY;
+ curr_thread->wait_for |= WAIT_TIME;
+ curr_thread->status = THREAD_STOPPED;
+ thread_schedule();
+}
+
+static int thread_abort;
+
+static VALUE
+thread_s_abort_exc()
+{
+ return thread_abort?TRUE:FALSE;
+}
+
+static VALUE
+thread_s_abort_exc_set(self, val)
+ VALUE self, val;
+{
+ thread_abort = RTEST(val);
+ return val;
+}
+
+static VALUE
+thread_abort_exc(thread)
+ VALUE thread;
+{
+ thread_t th = thread_check(thread);
+
+ return th->abort?TRUE:FALSE;
+}
+
+static VALUE
+thread_abort_exc_set(thread, val)
+ VALUE thread, val;
+{
+ thread_t th = thread_check(thread);
+
+ th->abort = RTEST(val);
+ return val;
}
static thread_t
@@ -4338,8 +5038,6 @@ thread_alloc()
th = ALLOC(struct thread);
th->status = THREAD_RUNNABLE;
- th->func = 0;
- th->arg = 0;
th->status = 0;
th->result = 0;
@@ -4361,6 +5059,12 @@ thread_alloc()
th->block = 0;
th->iter = 0;
th->tag = 0;
+ th->errat = 0;
+ th->errinfo = 0;
+ th->last_status = 0;
+ th->last_line = 0;
+ th->last_match = 0;
+ th->abort = 0;
th->thread = data_object_alloc(cThread, th, 0, thread_free);
@@ -4378,6 +5082,26 @@ thread_alloc()
return th;
}
+#if defined(HAVE_SETITIMER) && !defined(__BOW__)
+static void
+catch_timer(sig)
+ int sig;
+{
+#if !defined(POSIX_SIGNAL) && !defined(BSD_SIGNAL)
+ signal(sig, catch_timer);
+#endif
+ if (!thread_critical) {
+ if (trap_immediate) {
+ trap_immediate = 0;
+ thread_schedule();
+ }
+ else thread_pending = 1;
+ }
+}
+#else
+int thread_tick = THREAD_TICK;
+#endif
+
VALUE
thread_create(fn, arg)
VALUE (*fn)();
@@ -4386,35 +5110,79 @@ thread_create(fn, arg)
thread_t th = thread_alloc();
NODE *state;
+#if defined(HAVE_SETITIMER) && !defined(__BOW__)
+ static init = 0;
+
+ if (!init) {
+ struct itimerval tval;
+
+#ifdef POSIX_SIGNAL
+ posix_signal(SIGVTALRM, catch_timer);
+#else
+ signal(SIGVTALRM, catch_timer);
+#endif
+
+ tval.it_interval.tv_sec = 0;
+ tval.it_interval.tv_usec = 100000;
+ tval.it_value = tval.it_interval;
+ setitimer(ITIMER_VIRTUAL, &tval, NULL);
+
+ init = 1;
+ }
+#endif
+
thread_save_context(curr_thread);
if (setjmp(curr_thread->context)) {
return th->thread;
}
- th->func = fn;
- th->arg = arg;
-
PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
thread_save_context(th);
if (setjmp(th->context) == 0) {
curr_thread = th;
- th->result = (*th->func)(th->arg, th);
+ th->result = (*fn)(arg, th);
}
}
POP_TAG();
- if (state && th->status != THREAD_TO_KILL) {
- /* global exit within this thread */
- main_thread->errat = errat;
- main_thread->errinfo = errinfo;
- thread_cleanup();
+ if (state) {
+ if (state->nd_tag == TAG_THROW) {
+ char *mesg;
+ char *tag = rb_id2name(state->nd_tlev);
+
+ mesg = ALLOCA_N(char, strlen(tag) + 64);
+
+ sprintf(mesg, "uncaught throw `%s' in thread 0x%x\n",
+ tag, th->thread);
+ curr_thread->errinfo = exc_new2(eThreadError, mesg);
+ curr_thread->errat = make_backtrace();
+ }
+ else if (th->status != THREAD_TO_KILL && !NIL_P(errinfo)) {
+ if (state->nd_tag == TAG_FATAL ||
+ obj_is_kind_of(errinfo, eSystemExit)) {
+ /* fatal error or global exit within this thread */
+ /* need to stop whole script */
+ main_thread->errat = errat;
+ main_thread->errinfo = errinfo;
+ thread_cleanup();
+ }
+ else if (thread_abort || curr_thread->abort) {
+ f_abort();
+ }
+ else {
+ curr_thread->errat = errat;
+ curr_thread->errinfo = errinfo;
+ }
+ }
}
thread_remove();
+ return 0;
}
static void
thread_yield(arg, th)
- thread_t th;
+ int arg;
+ thread_t th;
{
scope_dup(the_block->scope);
rb_yield(th->thread);
@@ -4424,35 +5192,47 @@ static VALUE
thread_start()
{
if (!iterator_p()) {
- Raise(eLocalJumpError, "must be called as iterator");
+ Raise(eThreadError, "must be called as iterator");
}
return thread_create(thread_yield, 0);
}
static VALUE
-thread_value(data)
- struct RData *data;
+thread_value(thread)
+ VALUE thread;
{
- thread_t th = thread_check(data);
+ thread_t th = thread_check(thread);
+
+ thread_join(0, thread);
+ if (!NIL_P(th->errinfo)) {
+ errat = make_backtrace();
+ ary_unshift(errat, ary_entry(th->errat, 0));
+ sourcefile = 0; /* kludge to print errat */
+ rb_raise(th->errinfo);
+ }
- thread_join(0, data);
return th->result;
}
static VALUE
-thread_status(data)
- struct RData *data;
+thread_status(thread)
+ VALUE thread;
{
- thread_t th = thread_check(data);
+ thread_t th = thread_check(thread);
+
+ if (thread_dead(th)) {
+ if (NIL_P(th->errinfo)) return FALSE;
+ return Qnil;
+ }
- return thread_dead(th)?FALSE:TRUE;
+ return TRUE;
}
static VALUE
-thread_stopped(data)
- struct RData *data;
+thread_stopped(thread)
+ VALUE thread;
{
- thread_t th = thread_check(data);
+ thread_t th = thread_check(thread);
if (thread_dead(th)) return TRUE;
if (th->status == THREAD_STOPPED) return TRUE;
@@ -4473,6 +5253,10 @@ thread_cleanup()
{
thread_t th;
+ if (curr_thread != curr_thread->next->prev) {
+ curr_thread = curr_thread->prev;
+ }
+
FOREACH_THREAD(th) {
if (th != curr_thread && th->status != THREAD_KILLED) {
th->status = THREAD_TO_KILL;
@@ -4485,37 +5269,64 @@ thread_cleanup()
int thread_critical;
static VALUE
-thread_exclusive()
+thread_get_critical()
{
- NODE *state;
-
- thread_critical++;
-
- PUSH_TAG();
- if ((state = EXEC_TAG()) == 0) {
- rb_yield(Qnil);
- }
- POP_TAG();
- thread_critical--;
+ return thread_critical?TRUE:FALSE;
+}
- if (state) JUMP_TAG(state);
- thread_schedule();
- return Qnil;
+static VALUE
+thread_set_critical(obj, val)
+ VALUE obj, val;
+{
+ thread_critical = RTEST(val);
+ return val;
}
void
thread_interrupt()
{
- thread_t th = main_thread;
-
+ thread_critical = 0;
thread_ready(main_thread);
- if (th == curr_thread) {
+ if (curr_thread == main_thread) {
rb_interrupt();
}
+ thread_save_context(curr_thread);
+ if (setjmp(curr_thread->context)) {
+ return;
+ }
curr_thread = main_thread;
thread_restore_context(curr_thread, 2);
}
+static VALUE
+thread_raise(argc, argv, thread)
+ int argc;
+ VALUE *argv;
+ VALUE thread;
+{
+ thread_t th = thread_check(thread);
+
+ if (thread_dead(th)) return thread;
+ if (curr_thread == th) {
+ f_raise(argc, argv);
+ }
+
+ thread_save_context(curr_thread);
+ if (setjmp(curr_thread->context)) {
+ return thread;
+ }
+
+ rb_scan_args(argc, argv, "11", &th_raise_argv[0], &th_raise_argv[1]);
+ thread_ready(th);
+ curr_thread = th;
+
+ th_raise_argc = argc;
+ th_raise_file = sourcefile;
+ th_raise_line = sourceline;
+ thread_restore_context(curr_thread, 3);
+ return Qnil; /* not reached */
+}
+
static thread_t loading_thread;
static int loading_nest;
@@ -4545,29 +5356,10 @@ thread_loading_done()
}
}
-#if defined(HAVE_SETITIMER) && !defined(__BOW__)
-static void
-catch_timer(sig)
- int sig;
-{
-#if !defined(POSIX_SIGNAL) && !defined(BSD_SIGNAL)
- signal(sig, catch_timer);
-#endif
- if (!thread_critical) {
- if (trap_immediate) {
- trap_immediate = 0;
- thread_schedule();
- }
- else thread_pending = 1;
- }
-}
-#else
-int thread_tick = THREAD_TICK;
-#endif
-
void
Init_Thread()
{
+ eThreadError = rb_define_class("ThreadError", eException);
cThread = rb_define_class("Thread", cObject);
rb_define_singleton_method(cThread, "new", thread_start, 0);
@@ -4577,37 +5369,31 @@ Init_Thread()
rb_define_singleton_method(cThread, "stop", thread_stop, 0);
rb_define_singleton_method(cThread, "kill", thread_s_kill, 1);
rb_define_singleton_method(cThread, "exit", thread_exit, 0);
- rb_define_singleton_method(cThread, "pass", thread_schedule, 0);
+ rb_define_singleton_method(cThread, "pass", thread_pass, 0);
rb_define_singleton_method(cThread, "join", thread_join, 1);
rb_define_singleton_method(cThread, "current", thread_current, 0);
- rb_define_singleton_method(cThread, "exclusive", thread_exclusive, 0);
+ rb_define_singleton_method(cThread, "main", thread_main, 0);
+
+ rb_define_singleton_method(cThread, "critical", thread_get_critical, 0);
+ rb_define_singleton_method(cThread, "critical=", thread_set_critical, 1);
+
+ rb_define_singleton_method(cThread, "abort_on_exception", thread_s_abort_exc, 0);
+ rb_define_singleton_method(cThread, "abort_on_exception=", thread_s_abort_exc_set, 1);
rb_define_method(cThread, "run", thread_run, 0);
+ rb_define_method(cThread, "wakeup", thread_wakeup, 0);
rb_define_method(cThread, "stop", thread_stop_method, 0);
rb_define_method(cThread, "exit", thread_kill, 0);
rb_define_method(cThread, "value", thread_value, 0);
rb_define_method(cThread, "status", thread_status, 0);
+ rb_define_method(cThread, "alive?", thread_status, 0);
rb_define_method(cThread, "stop?", thread_stopped, 0);
- rb_define_method(cThread, "stopped?", thread_stopped, 0);
+ rb_define_method(cThread, "raise", thread_raise, -1);
+
+ rb_define_method(cThread, "abort_on_exception", thread_abort_exc, 0);
+ rb_define_method(cThread, "abort_on_exception=", thread_abort_exc_set, 1);
/* allocate main thread */
main_thread = thread_alloc();
-
-#if defined(HAVE_SETITIMER) && !defined(__BOW__)
- {
- struct itimerval tval;
-
-#ifdef POSIX_SIGNAL
- posix_signal(SIGVTALRM, catch_timer);
-#else
- signal(SIGVTALRM, catch_timer);
-#endif
-
- tval.it_interval.tv_sec = 0;
- tval.it_interval.tv_usec = 50000;
- tval.it_value = tval.it_interval;
- setitimer(ITIMER_VIRTUAL, &tval, NULL);
- }
-#endif
}
#endif
diff --git a/ext/Setup b/ext/Setup
index 4ea6aea..a5dd797 100644
--- a/ext/Setup
+++ b/ext/Setup
@@ -1,7 +1,10 @@
#option nodynamic
+#GD
+#curses
#dbm
#etc
+#fcntl
#kconv
#marshal
#md5
diff --git a/ext/Setup.dj b/ext/Setup.dj
index eb60525..25adea2 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 0000000..8e43179
--- /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 0000000..25adea2
--- /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 0000000..1058977
--- /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 0000000..db5e54f
--- /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 0000000..16ba90c
--- /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 0000000..22b1e2f
--- /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 0000000..bed7779
--- /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 0000000..36f0f84
--- /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 0000000..e59a74e
--- /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 5d8a12e..f0522f2 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 2302ee2..4a5d41f 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 524800b..5cab110 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 bd4eed3..f1acef5 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 0000000..33f676a
--- /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 0000000..aef7ad4
--- /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 0000000..3c7ef84
--- /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 0000000..977d595
--- /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 8f37a9e..cb89e82 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 0000000..e87b1fd
--- /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 791b34b..3c59cb6 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 6592304..ab30bd1 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 eae8d7f..47cb0fc 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 85f0847..762d53e 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 f2ec057..bbde1a0 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 6b4f0f5..be9118d 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 51e3412..5e6b77b 100644
--- a/ext/tkutil/tkutil.c
+++ b/ext/tkutil/tkutil.c
@@ -23,13 +23,6 @@ tk_eval_cmd(argc, argv)
}
static VALUE
-tk_yield(obj)
- VALUE obj;
-{
- rb_yield_0(obj, obj);
-}
-
-static VALUE
tk_s_new(argc, argv, class)
int argc;
VALUE *argv;
@@ -38,7 +31,7 @@ tk_s_new(argc, argv, class)
VALUE obj = obj_alloc(class);
rb_funcall2(obj, rb_intern("initialize"), argc, argv);
- if (iterator_p()) tk_yield(obj);
+ if (iterator_p()) rb_yield_0(obj, obj);
return obj;
}
diff --git a/file.c b/file.c
index 656650b..0894c72 100644
--- a/file.c
+++ b/file.c
@@ -26,10 +26,12 @@
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#else
-stuct timeval {
+#ifndef NT
+struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* and microseconds */
};
+#endif /* NT */
#endif
#ifdef HAVE_UTIME_H
@@ -46,8 +48,14 @@ stuct timeval {
char *strrchr();
#endif
+#ifdef NT
+#include <sys/stat.h>
+#endif
+
+#ifndef NT
char *strdup();
char *getenv();
+#endif
extern VALUE cIO;
VALUE cFile;
@@ -66,7 +74,6 @@ file_open(fname, mode)
MakeOpenFile(port, fptr);
fptr->mode = io_mode_flags(mode);
-
fptr->f = rb_fopen(fname, mode);
fptr->path = strdup(fname);
@@ -74,23 +81,77 @@ file_open(fname, mode)
}
static VALUE
-file_s_open(argc, argv)
+file_s_open(argc, argv, class)
int argc;
VALUE *argv;
+ VALUE class;
{
- VALUE fname, vmode;
+ VALUE fname, vmode, file;
char *mode;
- rb_scan_args(argc, argv, "11", &fname, &mode);
- Check_Type(fname, T_STRING);
- if (!NIL_P(mode)) {
- Check_Type(mode, T_STRING);
- mode = RSTRING(mode)->ptr;
+ rb_scan_args(argc, argv, "11", &fname, &vmode);
+ Check_SafeStr(fname);
+ if (!NIL_P(vmode)) {
+ Check_Type(vmode, T_STRING);
+ mode = RSTRING(vmode)->ptr;
+ }
+ else {
+ mode = "r";
+ }
+ file = file_open(RSTRING(fname)->ptr, mode);
+
+ RBASIC(file)->class = class;
+ return file;
+}
+
+static VALUE
+file_reopen(argc, argv, file)
+ int argc;
+ VALUE *argv;
+ VALUE file;
+{
+ VALUE fname, nmode;
+ char *mode;
+ OpenFile *fptr;
+
+ if (rb_scan_args(argc, argv, "11", &fname, &nmode) == 1) {
+ if (TYPE(fname) == T_FILE) { /* fname must be IO */
+ return io_reopen(file, fname);
+ }
+ }
+
+ Check_SafeStr(fname);
+ if (!NIL_P(nmode)) {
+ Check_Type(nmode, T_STRING);
+ mode = RSTRING(nmode)->ptr;
}
else {
mode = "r";
}
- return file_open(RSTRING(fname)->ptr, mode);
+
+ GetOpenFile(file, fptr);
+ if (fptr->path) free(fptr->path);
+ fptr->path = strdup(RSTRING(fname)->ptr);
+ fptr->mode = io_mode_flags(mode);
+ if (!fptr->f) {
+ fptr->f = rb_fopen(RSTRING(fname)->ptr, mode);
+ if (fptr->f2) {
+ fclose(fptr->f2);
+ fptr->f2 = NULL;
+ }
+ return file;
+ }
+
+ if (freopen(RSTRING(fname)->ptr, mode, fptr->f) == NULL) {
+ rb_sys_fail(fptr->path);
+ }
+ if (fptr->f2) {
+ if (freopen(RSTRING(fname)->ptr, "w", fptr->f2) == NULL) {
+ rb_sys_fail(fptr->path);
+ }
+ }
+
+ return file;
}
static int
@@ -103,8 +164,11 @@ apply2files(func, args, arg)
VALUE path;
for (i=0; i<args->len; i++) {
+ Check_SafeStr(args->ptr[i]);
+ }
+
+ for (i=0; i<args->len; i++) {
path = args->ptr[i];
- Check_Type(path, T_STRING);
if ((*func)(RSTRING(path)->ptr, arg) < 0)
rb_sys_fail(RSTRING(path)->ptr);
}
@@ -200,7 +264,11 @@ file_isatty(obj)
}
#include <sys/types.h>
+#ifndef NT
#include <sys/file.h>
+#else
+#include "missing/file.h"
+#endif
#include <sys/stat.h>
static VALUE
@@ -243,7 +311,7 @@ file_s_stat(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) == -1) {
rb_sys_fail(fname->ptr);
}
@@ -269,10 +337,10 @@ file_s_lstat(obj, fname)
VALUE obj;
struct RString *fname;
{
-#if !defined(MSDOS)
+#if !defined(MSDOS) && !defined(NT)
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (lstat(fname->ptr, &st) == -1) {
rb_sys_fail(fname->ptr);
}
@@ -286,7 +354,7 @@ static VALUE
file_lstat(obj)
VALUE obj;
{
-#if !defined(MSDOS)
+#if !defined(MSDOS) && !defined(NT)
OpenFile *fptr;
struct stat st;
@@ -335,6 +403,7 @@ eaccess(path, mode)
char *path;
int mode;
{
+#ifndef NT
struct stat st;
static int euid = -1;
@@ -355,6 +424,19 @@ eaccess(path, mode)
return 0;
}
+#if defined(DJGPP)
+ {
+ int stat_mode = 0;
+ if (mode & X_OK)
+ stat_mode |= S_IXOTH;
+ if (mode & W_OK)
+ stat_mode |= S_IWOTH;
+ if (mode & R_OK)
+ stat_mode |= S_IROTH;
+ mode = stat_mode;
+ }
+#endif
+
if (st.st_uid == euid) /* owner */
mode <<= 6;
else if (group_member (st.st_gid))
@@ -363,6 +445,9 @@ eaccess(path, mode)
if (st.st_mode & mode) return 0;
return -1;
+#else /* !NT*/
+ return 0;
+#endif
}
static VALUE
@@ -376,7 +461,7 @@ test_d(obj, fname)
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (S_ISDIR(st.st_mode)) return TRUE;
return FALSE;
@@ -394,7 +479,7 @@ test_p(obj, fname)
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (S_ISFIFO(st.st_mode)) return TRUE;
@@ -424,7 +509,7 @@ test_l(obj, fname)
#ifdef S_ISLNK
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (lstat(fname->ptr, &st) < 0) return FALSE;
if (S_ISLNK(st.st_mode)) return TRUE;
@@ -432,7 +517,7 @@ test_l(obj, fname)
return FALSE;
}
-VALUE
+static VALUE
test_S(obj, fname)
VALUE obj;
struct RString *fname;
@@ -454,7 +539,7 @@ test_S(obj, fname)
#ifdef S_ISSOCK
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (S_ISSOCK(st.st_mode)) return TRUE;
@@ -470,13 +555,15 @@ test_b(obj, fname)
#ifndef S_ISBLK
# ifdef S_IFBLK
# define S_ISBLK(m) ((m & S_IFMT) == S_IFBLK)
+# else
+# define S_ISBLK(m) (0) /* anytime false */
# endif
#endif
#ifdef S_ISBLK
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (S_ISBLK(st.st_mode)) return TRUE;
@@ -495,7 +582,7 @@ test_c(obj, fname)
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (S_ISBLK(st.st_mode)) return TRUE;
@@ -509,7 +596,7 @@ test_e(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
return TRUE;
}
@@ -519,7 +606,7 @@ test_r(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (eaccess(fname->ptr, R_OK) < 0) return FALSE;
return TRUE;
}
@@ -529,7 +616,7 @@ test_R(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (access(fname->ptr, R_OK) < 0) return FALSE;
return TRUE;
}
@@ -539,7 +626,7 @@ test_w(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (eaccess(fname->ptr, W_OK) < 0) return FALSE;
return TRUE;
}
@@ -549,7 +636,7 @@ test_W(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (access(fname->ptr, W_OK) < 0) return FALSE;
return TRUE;
}
@@ -559,7 +646,7 @@ test_x(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (eaccess(fname->ptr, X_OK) < 0) return FALSE;
return TRUE;
}
@@ -569,11 +656,15 @@ test_X(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (access(fname->ptr, X_OK) < 0) return FALSE;
return TRUE;
}
+#ifndef S_ISREG
+# define S_ISREG(m) ((m & S_IFMT) == S_IFREG)
+#endif
+
static VALUE
test_f(obj, fname)
VALUE obj;
@@ -581,7 +672,7 @@ test_f(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (S_ISREG(st.st_mode)) return TRUE;
return FALSE;
@@ -594,7 +685,7 @@ test_z(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (st.st_size == 0) return TRUE;
return FALSE;
@@ -607,7 +698,7 @@ test_s(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (st.st_size == 0) return FALSE;
return int2inum(st.st_size);
@@ -620,7 +711,7 @@ test_owned(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (st.st_uid == geteuid()) return TRUE;
return FALSE;
@@ -633,7 +724,7 @@ test_rowned(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (st.st_uid == getuid()) return TRUE;
return FALSE;
@@ -647,11 +738,9 @@ test_grpowned(obj, fname)
#ifndef NT
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (st.st_gid == getegid()) return TRUE;
-#else
- Check_Type(fname, T_STRING);
#endif
return FALSE;
}
@@ -675,8 +764,8 @@ test_suid(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
#ifdef S_ISUID
+ Check_SafeStr(fname);
return check3rdbyte(fname->ptr, S_ISUID);
#else
return FALSE;
@@ -688,8 +777,8 @@ test_sgid(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
#ifndef NT
+ Check_SafeStr(fname);
return check3rdbyte(fname->ptr, S_ISGID);
#else
return FALSE;
@@ -710,14 +799,26 @@ test_sticky(obj, fname)
}
static VALUE
-file_s_type(obj, fname)
+file_s_size(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ struct stat st;
+
+ Check_SafeStr(fname);
+ if (stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr);
+ return int2inum(st.st_size);
+}
+
+static VALUE
+file_s_ftype(obj, fname)
VALUE obj;
struct RString *fname;
{
struct stat st;
char *t;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr);
if (S_ISREG(st.st_mode)) {
@@ -732,7 +833,7 @@ file_s_type(obj, fname)
t = "blockSpecial";
}
#endif
-#ifndef S_ISFIFO
+#ifdef S_ISFIFO
else if (S_ISFIFO(st.st_mode)) {
t = "fifo";
}
@@ -761,7 +862,7 @@ file_s_atime(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr);
return time_new(st.st_atime, 0);
}
@@ -787,7 +888,7 @@ file_s_mtime(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr);
return time_new(st.st_mtime, 0);
}
@@ -813,7 +914,7 @@ file_s_ctime(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr);
return time_new(st.st_ctime, 0);
}
@@ -864,10 +965,11 @@ file_chmod(obj, vmode)
OpenFile *fptr;
int mode;
+ rb_secure(2);
mode = NUM2INT(vmode);
GetOpenFile(obj, fptr);
-#if defined(DJGPP) || defined(__CYGWIN32__)
+#if defined(DJGPP) || defined(__CYGWIN32__) || defined(NT)
if (chmod(fptr->path, mode) == -1)
rb_sys_fail(fptr->path);
#else
@@ -918,14 +1020,15 @@ file_s_chown(argc, argv)
return INT2FIX(n);
}
-VALUE
+static VALUE
file_chown(obj, owner, group)
VALUE obj, owner, group;
{
OpenFile *fptr;
+ rb_secure(2);
GetOpenFile(obj, fptr);
-#if defined(DJGPP) || defined(__CYGWIN32__)
+#if defined(DJGPP) || defined(__CYGWIN32__) || defined(NT)
if (chown(fptr->path, NUM2INT(owner), NUM2INT(group)) == -1)
rb_sys_fail(fptr->path);
#else
@@ -972,6 +1075,7 @@ file_s_utime(argc, argv)
#ifndef HAVE_UTIME_H
# ifdef NT
# include <sys/utime.h>
+# define utimbuf _utimbuf
# else
struct utimbuf {
long actime;
@@ -1017,12 +1121,16 @@ file_s_link(obj, from, to)
VALUE obj;
struct RString *from, *to;
{
- Check_Type(from, T_STRING);
- Check_Type(to, T_STRING);
+#ifndef __human68k__
+ Check_SafeStr(from);
+ Check_SafeStr(to);
if (link(from->ptr, to->ptr) < 0)
rb_sys_fail(from->ptr);
return INT2FIX(0);
+#else
+ rb_notimplement();
+#endif
}
static VALUE
@@ -1030,9 +1138,9 @@ file_s_symlink(obj, from, to)
VALUE obj;
struct RString *from, *to;
{
-#if !defined(MSDOS)
- Check_Type(from, T_STRING);
- Check_Type(to, T_STRING);
+#if !defined(MSDOS) && !defined(NT)
+ Check_SafeStr(from);
+ Check_SafeStr(to);
if (symlink(from->ptr, to->ptr) < 0)
rb_sys_fail(from->ptr);
@@ -1047,18 +1155,18 @@ file_s_readlink(obj, path)
VALUE obj;
struct RString *path;
{
-#if !defined(MSDOS)
+#if !defined(MSDOS) && !defined(NT)
char buf[MAXPATHLEN];
int cc;
- Check_Type(path, T_STRING);
+ Check_SafeStr(path);
if ((cc = readlink(path->ptr, buf, MAXPATHLEN)) < 0)
rb_sys_fail(path->ptr);
return str_new(buf, cc);
#else
- rb_notimplement();
+ rb_notimplement();
#endif
}
@@ -1086,8 +1194,8 @@ file_s_rename(obj, from, to)
VALUE obj;
struct RString *from, *to;
{
- Check_Type(from, T_STRING);
- Check_Type(to, T_STRING);
+ Check_SafeStr(from);
+ Check_SafeStr(to);
if (rename(from->ptr, to->ptr) == -1)
rb_sys_fail(from->ptr);
@@ -1107,7 +1215,7 @@ file_s_umask(argc, argv)
umask(omask);
}
else if (argc == 1) {
- omask = umask(NUM2INT(argv[1]));
+ omask = umask(NUM2INT(argv[0]));
}
else {
ArgError("wrong # of argument");
@@ -1115,7 +1223,7 @@ file_s_umask(argc, argv)
return INT2FIX(omask);
}
-static VALUE
+VALUE
file_s_expand_path(obj, fname)
VALUE obj;
struct RString *fname;
@@ -1205,7 +1313,7 @@ file_s_expand_path(obj, fname)
if (p == buf || *p != '/') p++;
*p = '\0';
- return str_new2(buf);
+ return str_taint(str_new2(buf));
}
static int
@@ -1252,7 +1360,7 @@ file_s_basename(argc, argv)
f = rmext(p, ext->ptr);
if (f) return str_new(p, f);
}
- return str_new2(p);
+ return str_taint(str_new2(p));
}
static VALUE
@@ -1260,18 +1368,16 @@ file_s_dirname(obj, fname)
VALUE obj;
struct RString *fname;
{
- char *p;
+ UCHAR *p;
Check_Type(fname, T_STRING);
p = strrchr(fname->ptr, '/');
if (!p) {
- return str_new(0,0);
+ return str_new2(".");
}
- return str_new(fname->ptr, p - fname->ptr);
+ return str_taint(str_new(fname->ptr, p - fname->ptr));
}
-static VALUE separator;
-
static VALUE
file_s_split(obj, path)
VALUE obj, path;
@@ -1279,12 +1385,21 @@ file_s_split(obj, path)
return assoc_new(file_s_dirname(Qnil, path), file_s_basename(1,&path));
}
+static VALUE separator;
+
+static VALUE
+file_s_join(obj, args)
+ VALUE obj, args;
+{
+ return ary_join(args, separator);
+}
+
static VALUE
file_s_truncate(obj, path, len)
VALUE obj, len;
struct RString *path;
{
- Check_Type(path, T_STRING);
+ Check_SafeStr(path);
#ifdef HAVE_TRUNCATE
if (truncate(path->ptr, NUM2INT(len)) < 0)
@@ -1324,6 +1439,7 @@ file_truncate(obj, len)
GetOpenFile(obj, fptr);
+ rb_secure(2);
if (!(fptr->mode & FMODE_WRITABLE)) {
Fail("not opened for writing");
}
@@ -1342,30 +1458,18 @@ file_truncate(obj, len)
}
static VALUE
-file_fcntl(obj, req, arg)
- VALUE obj, req;
- struct RString *arg;
-{
-#ifdef HAVE_FCNTL
- io_ctl(obj, req, arg, 0);
-#else
- rb_notimplement();
-#endif
- return obj;
-}
-
-static VALUE
file_flock(obj, operation)
VALUE obj;
VALUE operation;
{
- OpenFile *fptr;
+ OpenFile *fptr;
GetOpenFile(obj, fptr);
+ rb_secure(2);
if (flock(fileno(fptr->f), NUM2INT(operation)) < 0) {
#ifdef EWOULDBLOCK
- if (errno = EWOULDBLOCK) {
+ if (errno == EWOULDBLOCK) {
return FALSE;
}
#endif
@@ -1384,7 +1488,7 @@ test_check(n, argc, argv)
n+=1;
if (n < argc) ArgError("Wrong # of arguments(%d for %d)", argc, n);
for (i=1; i<n; i++) {
- Check_Type(argv[i], T_STRING);
+ Check_SafeStr(argv[i]);
}
}
@@ -1398,8 +1502,13 @@ f_test(argc, argv)
int cmd;
if (argc == 0) ArgError("Wrong # of arguments");
- Need_Fixnum(argv[0]);
- cmd = FIX2INT(argv[0]);
+ if (TYPE(argv[0]) == T_STRING && RSTRING(argv[0])->len == 1) {
+ cmd = RSTRING(argv[0])->ptr[0];
+ }
+ else {
+ cmd = NUM2INT(argv[0]);
+ }
+ if (cmd == 0) return FALSE;
if (strchr("bcdefgGkloOprRsSuwWxXz", cmd)) {
CHECK(1);
switch (cmd) {
@@ -1519,7 +1628,7 @@ f_test(argc, argv)
return FALSE;
}
-extern VALUE cKernel;
+extern VALUE mKernel;
void
Init_File()
@@ -1537,7 +1646,7 @@ Init_File()
rb_define_module_function(mFileTest, "executable_real?", test_X, 1);
rb_define_module_function(mFileTest, "file?", test_f, 1);
rb_define_module_function(mFileTest, "zero?", test_z, 1);
- rb_define_module_function(mFileTest, "size", test_s, 1);
+ rb_define_module_function(mFileTest, "size?", test_s, 1);
rb_define_module_function(mFileTest, "owned?", test_owned, 1);
rb_define_module_function(mFileTest, "grpowned?", test_grpowned, 1);
@@ -1555,15 +1664,17 @@ Init_File()
cFile = rb_define_class("File", cIO);
rb_extend_object(cFile, CLASS_OF(mFileTest));
+ rb_define_singleton_method(cFile, "new", file_s_open, -1);
rb_define_singleton_method(cFile, "open", file_s_open, -1);
rb_define_singleton_method(cFile, "stat", file_s_stat, 1);
rb_define_singleton_method(cFile, "lstat", file_s_lstat, 1);
- rb_define_singleton_method(cFile, "ftype", file_s_type, 1);
+ rb_define_singleton_method(cFile, "ftype", file_s_ftype, 1);
rb_define_singleton_method(cFile, "atime", file_s_atime, 1);
rb_define_singleton_method(cFile, "mtime", file_s_mtime, 1);
rb_define_singleton_method(cFile, "ctime", file_s_ctime, 1);
+ rb_define_singleton_method(cFile, "size", file_s_size, 1);
rb_define_singleton_method(cFile, "utime", file_s_utime, -1);
rb_define_singleton_method(cFile, "chmod", file_s_chmod, -1);
@@ -1582,9 +1693,12 @@ Init_File()
rb_define_singleton_method(cFile, "basename", file_s_basename, -1);
rb_define_singleton_method(cFile, "dirname", file_s_dirname, 1);
- separator = INT2FIX('/');
+ separator = str_new2("/");
rb_define_const(cFile, "Separator", separator);
rb_define_singleton_method(cFile, "split", file_s_split, 1);
+ rb_define_singleton_method(cFile, "join", file_s_join, -2);
+
+ rb_define_method(cFile, "reopen", file_reopen, -1);
rb_define_method(cFile, "stat", file_stat, 0);
rb_define_method(cFile, "lstat", file_lstat, 0);
@@ -1606,10 +1720,9 @@ Init_File()
rb_define_method(cFile, "rewind", file_rewind, 0);
rb_define_method(cFile, "isatty", file_isatty, 0);
rb_define_method(cFile, "tty?", file_isatty, 0);
- rb_define_method(cFile, "eof", file_eof, 0);
+ rb_define_method(cFile, "eof", file_eof, 0);
rb_define_method(cFile, "eof?", file_eof, 0);
- rb_define_method(cIO, "fcntl", file_fcntl, 2);
rb_define_method(cFile, "flock", file_flock, 1);
# ifndef LOCK_SH
@@ -1632,7 +1745,7 @@ Init_File()
rb_define_method(cFile, "path", file_path, 0);
- rb_define_method(cKernel, "test", f_test, -1);
+ rb_define_global_function("test", f_test, -1);
sStat = struct_define("Stat", "dev", "ino", "mode",
"nlink", "uid", "gid", "rdev",
diff --git a/gc.c b/gc.c
index 21d0980..f69f474 100644
--- a/gc.c
+++ b/gc.c
@@ -19,19 +19,34 @@
#include <stdio.h>
#include <setjmp.h>
+#ifndef setjmp
+#ifdef HAVE__SETJMP
+#define setjmp(env) _setjmp(env)
+#define longjmp(env,val) _longjmp(env,val)
+#endif
+#endif
+
#ifdef _AIX
#pragma alloca
#endif
-void *malloc();
-void *calloc();
-void *realloc();
#ifdef C_ALLOCA
void *alloca();
#endif
void gc();
void gc_mark();
+static void run_final();
+
+#ifndef GC_MALLOC_LIMIT
+#if defined(MSDOS) || defined(__human68k__)
+#define GC_MALLOC_LIMIT 200000
+#else
+#define GC_MALLOC_LIMIT 400000
+#endif
+#endif
+
+static unsigned long malloc_memories = 0;
void *
xmalloc(size)
@@ -40,6 +55,10 @@ xmalloc(size)
void *mem;
if (size == 0) size = 1;
+ malloc_memories += size;
+ if (malloc_memories > GC_MALLOC_LIMIT) {
+ gc();
+ }
mem = malloc(size);
if (!mem) {
gc();
@@ -112,6 +131,7 @@ Paradigm Associates Inc Phone: 617-492-6079
Cambridge, MA 02138
*/
+extern int rb_in_compile;
static int dont_gc;
VALUE
@@ -196,7 +216,7 @@ add_heap()
if (heaps_used == heaps_length) {
/* Realloc heaps */
heaps_length += HEAPS_INCREMENT;
- heaps = (heaps_used)?
+ heaps = (heaps_used>0)?
(RVALUE**)realloc(heaps, heaps_length*sizeof(RVALUE)):
(RVALUE**)malloc(heaps_length*sizeof(RVALUE));
if (heaps == 0) Fatal("can't alloc memory");
@@ -217,14 +237,13 @@ add_heap()
}
struct RBasic *
-newobj()
+rb_newobj()
{
struct RBasic *obj;
if (freelist) {
retry:
obj = (struct RBasic*)freelist;
freelist = freelist->as.free.next;
- memset(obj, 0, sizeof(RVALUE));
return obj;
}
if (dont_gc) add_heap();
@@ -240,7 +259,7 @@ data_object_alloc(class, datap, dmark, dfree)
void (*dfree)();
void (*dmark)();
{
- struct RData *data = (struct RData*)newobj();
+ struct RData *data = (struct RData*)rb_newobj();
OBJSETUP(data, class, T_DATA);
data->data = datap;
@@ -260,8 +279,7 @@ looks_pointerp(p)
register RVALUE *heap_org;
register long i;
- if (p < lomem) return FALSE;
- if (p > himem) return FALSE;
+ if (p < lomem || p > himem) return FALSE;
/* check if p looks like a pointer */
for (i=0; i < heaps_used; i++) {
@@ -311,10 +329,11 @@ mark_entry(key, value)
return ST_CONTINUE;
}
-static int
+static void
mark_tbl(tbl)
st_table *tbl;
{
+ if (!tbl) return;
st_foreach(tbl, mark_entry, 0);
}
@@ -328,10 +347,11 @@ mark_hashentry(key, value)
return ST_CONTINUE;
}
-static int
+static void
mark_hash(tbl)
st_table *tbl;
{
+ if (!tbl) return;
st_foreach(tbl, mark_hashentry, 0);
}
@@ -350,7 +370,7 @@ gc_mark(obj)
{
Top:
if (FIXNUM_P(obj)) return; /* fixnum not marked */
- if (rb_special_const_p(obj)) return; /* special const not marked */
+ if (rb_special_const_p((VALUE)obj)) return; /* special const not marked */
if (obj->as.basic.flags == 0) return; /* free cell */
if (obj->as.basic.flags & FL_MARK) return; /* marked */
@@ -363,15 +383,79 @@ gc_mark(obj)
break;
case T_NODE:
- if (looks_pointerp(obj->as.node.u1.node)) {
- gc_mark(obj->as.node.u1.node);
- }
- if (looks_pointerp(obj->as.node.u2.node)) {
+ switch (nd_type(obj)) {
+ case NODE_IF: /* 1,2,3 */
+ case NODE_FOR:
+ case NODE_ITER:
gc_mark(obj->as.node.u2.node);
- }
- if (looks_pointerp(obj->as.node.u3.node)) {
+ /* fall through */
+ case NODE_BLOCK: /* 1,3 */
+ case NODE_ARRAY:
+ case NODE_DSTR:
+ case NODE_DXSTR:
+ case NODE_EVSTR:
+ case NODE_DREGX:
+ case NODE_DREGX_ONCE:
+ case NODE_FBODY:
+ case NODE_CALL:
+ gc_mark(obj->as.node.u1.node);
+ /* fall through */
+ case NODE_SUPER: /* 3 */
+ case NODE_FCALL:
+ case NODE_NEWLINE:
obj = (RVALUE*)obj->as.node.u3.node;
goto Top;
+
+ case NODE_WHILE: /* 1,2 */
+ case NODE_UNTIL:
+ gc_mark(obj->as.node.u1.node);
+ /* fall through */
+ case NODE_METHOD: /* 2 */
+ case NODE_NOT:
+ obj = (RVALUE*)obj->as.node.u2.node;
+ goto Top;
+
+ case NODE_HASH: /* 1 */
+ case NODE_LIT:
+ case NODE_STR:
+ case NODE_XSTR:
+ case NODE_DEFINED:
+ obj = (RVALUE*)obj->as.node.u1.node;
+ goto Top;
+
+ case NODE_SCOPE: /* 2,3 */
+ gc_mark(obj->as.node.u3.node);
+ obj = (RVALUE*)obj->as.node.u2.node;
+ goto Top;
+
+ case NODE_ZARRAY: /* - */
+ case NODE_CFUNC:
+ case NODE_VCALL:
+ case NODE_GVAR:
+ case NODE_LVAR:
+ case NODE_DVAR:
+ case NODE_IVAR:
+ case NODE_CVAR:
+ case NODE_NTH_REF:
+ case NODE_BACK_REF:
+ case NODE_ALIAS:
+ case NODE_VALIAS:
+ case NODE_UNDEF:
+ case NODE_SELF:
+ case NODE_NIL:
+ break;
+
+ default:
+ if (looks_pointerp(obj->as.node.u1.node)) {
+ gc_mark(obj->as.node.u1.node);
+ }
+ if (looks_pointerp(obj->as.node.u2.node)) {
+ gc_mark(obj->as.node.u2.node);
+ }
+ if (looks_pointerp(obj->as.node.u3.node)) {
+ obj = (RVALUE*)obj->as.node.u3.node;
+ goto Top;
+ }
}
return; /* no need to mark class. */
}
@@ -380,7 +464,7 @@ gc_mark(obj)
switch (obj->as.basic.flags & T_MASK) {
case T_ICLASS:
gc_mark(obj->as.class.super);
- if (obj->as.class.iv_tbl) mark_tbl(obj->as.class.iv_tbl);
+ mark_tbl(obj->as.class.iv_tbl);
mark_tbl(obj->as.class.m_tbl);
break;
@@ -388,7 +472,7 @@ gc_mark(obj)
case T_MODULE:
gc_mark(obj->as.class.super);
mark_tbl(obj->as.class.m_tbl);
- if (obj->as.class.iv_tbl) mark_tbl(obj->as.class.iv_tbl);
+ mark_tbl(obj->as.class.iv_tbl);
break;
case T_ARRAY:
@@ -417,16 +501,22 @@ gc_mark(obj)
break;
case T_OBJECT:
- if (obj->as.object.iv_tbl) mark_tbl(obj->as.object.iv_tbl);
+ mark_tbl(obj->as.object.iv_tbl);
break;
case T_FILE:
- case T_MATCH:
case T_REGEXP:
case T_FLOAT:
case T_BIGNUM:
break;
+ case T_MATCH:
+ if (obj->as.match.str) {
+ obj = (RVALUE*)obj->as.match.str;
+ goto Top;
+ }
+ break;
+
case T_VARMAP:
gc_mark(obj->as.varmap.val);
obj = (RVALUE*)obj->as.varmap.next;
@@ -435,12 +525,12 @@ gc_mark(obj)
case T_SCOPE:
if (obj->as.scope.local_vars) {
- int n = obj->as.scope.local_tbl[0];
- VALUE *tbl = obj->as.scope.local_vars;
+ int n = obj->as.scope.local_tbl[0]+1;
+ VALUE *vars = &obj->as.scope.local_vars[-1];
while (n--) {
- gc_mark_maybe(*tbl);
- tbl++;
+ gc_mark_maybe(*vars);
+ vars++;
}
}
break;
@@ -456,7 +546,9 @@ gc_mark(obj)
break;
default:
- Bug("gc_mark(): unknown data type %d", obj->as.basic.flags & T_MASK);
+ Bug("gc_mark(): unknown data type 0x%x(0x%x) %s",
+ obj->as.basic.flags & T_MASK, obj,
+ looks_pointerp(obj)?"corrupted object":"non object");
}
}
@@ -467,12 +559,23 @@ static void obj_free();
static void
gc_sweep()
{
+ RVALUE *p, *pend;
int freed = 0;
int i;
+ if (rb_in_compile) {
+ for (i = 0; i < heaps_used; i++) {
+ p = heaps[i]; pend = p + HEAP_SLOTS;
+ while (p < pend) {
+ if (!(p->as.basic.flags&FL_MARK) && BUILTIN_TYPE(p) == T_NODE)
+ gc_mark(p);
+ p++;
+ }
+ }
+ }
+
freelist = 0;
for (i = 0; i < heaps_used; i++) {
- RVALUE *p, *pend;
RVALUE *nfreelist;
int n = 0;
@@ -499,6 +602,17 @@ gc_sweep()
}
}
+void
+gc_force_recycle(p)
+ RVALUE *p;
+{
+ p->as.free.flag = 0;
+ p->as.free.next = freelist;
+ freelist = p;
+}
+
+static int need_call_final = 0;
+
static void
obj_free(obj)
RVALUE *obj;
@@ -506,10 +620,15 @@ obj_free(obj)
switch (obj->as.basic.flags & T_MASK) {
case T_NIL:
case T_FIXNUM:
+ case T_TRUE:
+ case T_FALSE:
Bug("obj_free() called for broken object");
break;
}
+ if (need_call_final) {
+ run_final(obj);
+ }
switch (obj->as.basic.flags & T_MASK) {
case T_OBJECT:
if (obj->as.object.iv_tbl) st_free_table(obj->as.object.iv_tbl);
@@ -524,7 +643,7 @@ obj_free(obj)
if (!obj->as.string.orig) free(obj->as.string.ptr);
break;
case T_ARRAY:
- free(obj->as.array.ptr);
+ if (obj->as.array.ptr) free(obj->as.array.ptr);
break;
case T_HASH:
st_free_table(obj->as.hash.tbl);
@@ -534,13 +653,13 @@ obj_free(obj)
free(obj->as.regexp.str);
break;
case T_DATA:
- if (obj->as.data.dfree) (*obj->as.data.dfree)(DATA_PTR(obj));
- free(DATA_PTR(obj));
+ if (obj->as.data.dfree && DATA_PTR(obj))
+ (*obj->as.data.dfree)(DATA_PTR(obj));
+ if (DATA_PTR(obj)) free(DATA_PTR(obj));
break;
case T_MATCH:
re_free_registers(obj->as.match.regs);
free(obj->as.match.regs);
- if (obj->as.match.ptr) free(obj->as.match.ptr);
break;
case T_FILE:
io_fptr_finalize(obj->as.file.fptr);
@@ -552,8 +671,6 @@ obj_free(obj)
case T_FLOAT:
case T_VARMAP:
- case T_TRUE:
- case T_FALSE:
break;
case T_BIGNUM:
@@ -566,10 +683,13 @@ obj_free(obj)
return; /* no need to free iv_tbl */
case T_SCOPE:
- if (obj->as.scope.local_vars)
- free(obj->as.scope.local_vars);
- if (obj->as.scope.local_tbl)
- free(obj->as.scope.local_tbl);
+ if (obj->as.scope.local_vars) {
+ VALUE *vars = obj->as.scope.local_vars-1;
+ if (vars[0] == 0)
+ free(obj->as.scope.local_tbl);
+ if (obj->as.scope.flag&SCOPE_MALLOC)
+ free(vars);
+ }
break;
case T_STRUCT:
@@ -592,8 +712,44 @@ gc_mark_frame(frame)
gc_mark_maybe(*tbl);
tbl++;
}
+ gc_mark(frame->cbase);
}
+#ifdef __GNUC__
+#if defined(__human68k__) || defined(DJGPP)
+#if defined(__human68k__)
+typedef unsigned long rb_jmp_buf[8];
+__asm__ (".even
+_rb_setjmp:
+ move.l 4(sp),a0
+ movem.l d3-d7/a3-a5,(a0)
+ moveq.l #0,d0
+ rts");
+#else
+#if defined(DJGPP)
+typedef unsigned long rb_jmp_buf[6];
+__asm__ (".align 4
+_rb_setjmp:
+ pushl %ebp
+ movl %esp,%ebp
+ movl 8(%ebp),%ebp
+ movl %eax,(%ebp)
+ movl %ebx,4(%ebp)
+ movl %ecx,8(%ebp)
+ movl %edx,12(%ebp)
+ movl %esi,16(%ebp)
+ movl %edi,20(%ebp)
+ popl %ebp
+ xorl %eax,%eax
+ ret");
+#endif
+#endif
+int rb_setjmp (rb_jmp_buf);
+#define jmp_buf rb_jmp_buf
+#define setjmp rb_setjmp
+#endif /* __human68k__ or DJGPP */
+#endif /* __GNUC__ */
+
void
gc()
{
@@ -605,6 +761,7 @@ gc()
if (dont_gc) return;
dont_gc++;
+ malloc_memories = 0;
#ifdef C_ALLOCA
alloca(0);
#endif
@@ -619,10 +776,13 @@ gc()
FLUSH_REGISTER_WINDOWS;
/* This assumes that all registers are saved into the jmp_buf */
setjmp(save_regs_gc_mark);
- gc_mark_locations((VALUE*)save_regs_gc_mark,
- (VALUE*)(((char*)save_regs_gc_mark)+sizeof(save_regs_gc_mark)));
- gc_mark_locations(gc_stack_start, (VALUE*) &stack_end);
-#ifdef THINK_C
+ mark_locations_array((VALUE*)&save_regs_gc_mark, sizeof(save_regs_gc_mark) / sizeof(VALUE *));
+ gc_mark_locations(gc_stack_start, (VALUE*)&stack_end);
+#if defined(THINK_C) || defined(__human68k__)
+#ifndef __human68k__
+ mark_locations_array((VALUE*)((char*)save_regs_gc_mark+2),
+ sizeof(save_regs_gc_mark) / sizeof(VALUE *));
+#endif
gc_mark_locations((VALUE*)((char*)gc_stack_start + 2),
(VALUE*)((char*)&stack_end + 2));
#endif
@@ -644,12 +804,24 @@ gc()
dont_gc--;
}
+static VALUE
+gc_method()
+{
+ gc();
+ return Qnil;
+}
+
void
init_stack()
{
+#ifdef __human68k__
+ extern void *_SEND;
+ gc_stack_start = _SEND;
+#else
VALUE start;
gc_stack_start = &start;
+#endif
}
void
@@ -660,8 +832,7 @@ init_heap()
}
static VALUE
-os_live_obj(obj)
- VALUE obj;
+os_live_obj()
{
int i;
int n = 0;
@@ -692,8 +863,8 @@ os_live_obj(obj)
}
static VALUE
-os_obj_of(obj, of)
- VALUE obj, of;
+os_obj_of(of)
+ VALUE of;
{
int i;
int n = 0;
@@ -725,6 +896,74 @@ os_obj_of(obj, of)
return INT2FIX(n);
}
+static VALUE
+os_each_obj(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ VALUE of;
+
+ if (rb_scan_args(argc, argv, "01", &of) == 0) {
+ return os_live_obj();
+ }
+ else {
+ return os_obj_of(of);
+ }
+}
+
+static VALUE finalizers;
+
+static VALUE
+add_final(os, proc)
+ VALUE os, proc;
+{
+ extern VALUE cProc;
+
+ if (!obj_is_kind_of(proc, cProc)) {
+ ArgError("wrong type argument %s (Proc required)",
+ rb_class2name(CLASS_OF(proc)));
+ }
+ ary_push(finalizers, proc);
+ return proc;
+}
+
+static VALUE
+rm_final(os, proc)
+ VALUE os, proc;
+{
+ ary_delete(finalizers, proc);
+ return proc;
+}
+
+static VALUE
+finals()
+{
+ return finalizers;
+}
+
+static VALUE
+call_final(os, obj)
+ VALUE os, obj;
+{
+ need_call_final = 1;
+ FL_SET(obj, FL_FINALIZE);
+ return obj;
+}
+
+static void
+run_final(obj)
+ VALUE obj;
+{
+ int i;
+
+ if (!FL_TEST(obj, FL_FINALIZE)) return;
+
+ obj |= FIXNUM_FLAG; /* make obj into id */
+ for (i=0; i<RARRAY(finalizers)->len; i++) {
+ rb_eval_cmd(RARRAY(finalizers)->ptr[i], obj);
+ }
+}
+
extern VALUE cModule;
void
@@ -733,13 +972,19 @@ Init_GC()
VALUE mObSpace;
mGC = rb_define_module("GC");
- rb_define_singleton_method(mGC, "start", gc, 0);
+ rb_define_singleton_method(mGC, "start", gc_method, 0);
rb_define_singleton_method(mGC, "enable", gc_s_enable, 0);
rb_define_singleton_method(mGC, "disable", gc_s_disable, 0);
- rb_define_method(mGC, "garbage_collect", gc, 0);
+ rb_define_method(mGC, "garbage_collect", gc_method, 0);
mObSpace = rb_define_module("ObjectSpace");
- rb_define_module_function(mObSpace, "each_live_object", os_live_obj, 0);
- rb_define_module_function(mObSpace, "each_object_of", os_obj_of, 1);
+ rb_define_module_function(mObSpace, "each_object", os_each_obj, -1);
rb_define_module_function(mObSpace, "garbage_collect", gc, 0);
+ rb_define_module_function(mObSpace, "add_finalizer", add_final, 1);
+ rb_define_module_function(mObSpace, "remove_finalizer", rm_final, 1);
+ rb_define_module_function(mObSpace, "finalizers", finals, 0);
+ rb_define_module_function(mObSpace, "call_finalizer", call_final, 1);
+
+ rb_global_variable(&finalizers);
+ finalizers = ary_new();
}
diff --git a/glob.c b/glob.c
index 7599c1c..6c355ad 100644
--- a/glob.c
+++ b/glob.c
@@ -44,7 +44,11 @@
# include "ndir.h"
# endif /* !Xenix */
# else /* !USG */
+# if defined(NT)
+# include "missing/dir.h"
+# else
# include <sys/dir.h>
+# endif /* !NT */
# endif /* !USG */
#endif /* !HAVE_DIRENT_H */
@@ -68,7 +72,9 @@
# include <strings.h>
#endif /* !HAVE_STRING_H */
+#ifndef bcopy
# define bcopy(s, d, n) (memcpy ((d), (s), (n)))
+#endif
#ifdef _AIX
#pragma alloca
diff --git a/hash.c b/hash.c
index c6af916..0ced1d5 100644
--- a/hash.c
+++ b/hash.c
@@ -6,12 +6,13 @@
$Date: 1996/12/25 10:42:26 $
created at: Mon Nov 22 18:51:18 JST 1993
- Copyright (C) 1993-1996 Yukihiro Matsumoto
+ Copyright (C) 1993-1997 Yukihiro Matsumoto
************************************************/
#include "ruby.h"
#include "st.h"
+#include "sig.h"
#ifdef HAVE_STRING_H
# include <string.h>
@@ -19,31 +20,44 @@
char *strchr();
#endif
+#define HASH_DELETED 0x1
+#define HASH_REHASHED 0x2
+
+#ifndef NT
char *getenv();
+#endif
VALUE cHash;
static VALUE envtbl;
static ID hash;
-VALUE f_getenv(), f_setenv();
+
+VALUE
+rb_hash(obj)
+ VALUE obj;
+{
+ return rb_funcall(obj, hash, 0);
+}
static int
-rb_cmp(a, b)
+any_cmp(a, b)
VALUE a, b;
{
if (FIXNUM_P(a)) {
if (FIXNUM_P(b)) return a != b;
}
-
- if (TYPE(a) == T_STRING) {
+ else if (TYPE(a) == T_STRING) {
if (TYPE(b) == T_STRING) return str_cmp(a, b);
}
- return !rb_eql(a, b);
+ DEFER_INTS;
+ a = !rb_eql(a, b);
+ ENABLE_INTS;
+ return a;
}
static int
-rb_hash(a, mod)
+any_hash(a, mod)
VALUE a;
int mod;
{
@@ -59,17 +73,85 @@ rb_hash(a, mod)
break;
default:
+ DEFER_INTS;
hval = rb_funcall(a, hash, 0);
+ if (!FIXNUM_P(hval)) {
+ hval = rb_funcall(hval, '%', 1, INT2FIX(65439));
+ }
+ ENABLE_INTS;
hval = FIX2INT(hval);
}
return hval % mod;
}
static struct st_hash_type objhash = {
- rb_cmp,
- rb_hash,
+ any_cmp,
+ any_hash,
+};
+
+struct hash_foreach_arg {
+ struct RHash *hash;
+ enum st_retval (*func)();
+ char *arg;
};
+static int
+hash_foreach_iter(key, value, arg)
+ VALUE key, value;
+ struct hash_foreach_arg *arg;
+{
+ int status;
+
+ if (key == Qnil) return ST_CONTINUE;
+ status = (*arg->func)(key, value, arg->arg);
+ if (arg->hash->status & HASH_REHASHED) return ST_STOP;
+ return status;
+}
+
+static int
+hash_foreach_call(arg)
+ struct hash_foreach_arg *arg;
+{
+ return st_foreach(arg->hash->tbl, hash_foreach_iter, arg);
+}
+
+static int
+hash_delete_nil(key, value)
+ VALUE key, value;
+{
+ if (key == Qnil) return ST_DELETE;
+ return ST_CONTINUE;
+}
+
+static void
+hash_foreach_ensure(hash)
+ struct RHash *hash;
+{
+ hash->iter_lev--;
+
+ if (hash->iter_lev == 0) {
+ if (hash->status & HASH_DELETED) {
+ st_foreach(hash->tbl, hash_delete_nil, 0);
+ }
+ hash->status = 0;
+ }
+}
+
+static int
+hash_foreach(hash, func, farg)
+ struct RHash *hash;
+ enum st_retval (*func)();
+ char *farg;
+{
+ struct hash_foreach_arg arg;
+
+ hash->iter_lev++;
+ arg.hash = hash;
+ arg.func = func;
+ arg.arg = farg;
+ return rb_ensure(hash_foreach_call, &arg, hash_foreach_ensure, hash);
+}
+
static VALUE
hash_s_new(argc, argv, class)
int argc;
@@ -86,13 +168,14 @@ hash_s_new(argc, argv, class)
if (NIL_P(sz)) size = 0;
else size = NUM2INT(sz);
+ hash->iter_lev = 0;
+ hash->status = 0;
+ hash->tbl = 0; /* avoid GC crashing */
hash->tbl = st_init_table_with_size(&objhash, size);
return (VALUE)hash;
}
-static VALUE hash_clone();
-
VALUE
hash_new2(class)
VALUE class;
@@ -120,8 +203,11 @@ hash_s_create(argc, argv, class)
else {
NEWOBJ(hash, struct RHash);
OBJSETUP(hash, class, T_HASH);
+
+ hash->iter_lev = 0;
+ hash->status = 0;
+ hash->tbl = 0; /* avoid GC crashing */
hash->tbl = (st_table*)st_copy(RHASH(argv[0])->tbl);
-
return (VALUE)hash;
}
}
@@ -145,11 +231,39 @@ hash_clone(hash)
NEWOBJ(hash2, struct RHash);
CLONESETUP(hash2, hash);
+ hash2->iter_lev = 0;
+ hash2->status = 0;
+ hash2->tbl = 0; /* avoid GC crashing */
hash2->tbl = (st_table*)st_copy(hash->tbl);
return (VALUE)hash2;
}
+static int
+hash_rehash_i(key, value, tbl)
+ VALUE key, value;
+ st_table *tbl;
+{
+ if (key != Qnil) {
+ st_insert(tbl, key, value);
+ }
+ return ST_CONTINUE;
+}
+
+static VALUE
+hash_rehash(hash)
+ struct RHash *hash;
+{
+ st_table *tbl = st_init_table_with_size(&objhash, hash->tbl->num_entries);
+
+ st_foreach(hash->tbl, hash_rehash_i, tbl);
+ st_free_table(hash->tbl);
+ hash->tbl = tbl;
+ if (hash->iter_lev > 0) hash->status |= HASH_REHASHED;
+
+ return (VALUE)hash;
+}
+
VALUE
hash_aref(hash, key)
struct RHash *hash;
@@ -164,23 +278,17 @@ hash_aref(hash, key)
}
static VALUE
-hash_indexes(hash, args)
+hash_indexes(argc, argv, hash)
+ int argc;
+ VALUE *argv;
struct RHash *hash;
- struct RArray *args;
{
- VALUE *p, *pend;
struct RArray *indexes;
- int i = 0;
-
- if (!args || NIL_P(args)) {
- return ary_new2(0);
- }
-
- indexes = (struct RArray*)ary_new2(args->len);
+ int i;
- p = args->ptr; pend = p + args->len;
- while (p < pend) {
- indexes->ptr[i++] = hash_aref(hash, *p++);
+ indexes = (struct RArray*)ary_new2(argc);
+ for (i=0; i<argc; i++) {
+ indexes->ptr[i] = hash_aref(hash, argv[i]);
}
indexes->len = i;
return (VALUE)indexes;
@@ -193,9 +301,12 @@ hash_delete(hash, key)
{
VALUE val;
- if (st_delete(hash->tbl, &key, &val))
+ rb_secure(5);
+ if (hash->iter_lev > 0 && st_delete_safe(hash->tbl, &key, &val, Qnil))
+ return val;
+ else if (st_delete(hash->tbl, &key, &val))
return val;
- if (iterator_p()) rb_yield(Qnil);
+ if (iterator_p()) rb_yield(key);
return Qnil;
}
@@ -205,11 +316,12 @@ struct shift_var {
VALUE val;
};
-static
+static int
shift_i(key, value, var)
VALUE key, value;
struct shift_var *var;
{
+ if (key == Qnil) return ST_CONTINUE;
if (var->stop) return ST_STOP;
var->stop = 1;
var->key = key;
@@ -223,6 +335,7 @@ hash_shift(hash)
{
struct shift_var var;
+ rb_secure(5);
var.stop = 0;
st_foreach(hash->tbl, shift_i, &var);
@@ -234,6 +347,7 @@ static int
delete_if_i(key, value)
VALUE key, value;
{
+ if (key == Qnil) return ST_CONTINUE;
if (rb_yield(assoc_new(key, value)))
return ST_DELETE;
return ST_CONTINUE;
@@ -243,7 +357,8 @@ static VALUE
hash_delete_if(hash)
struct RHash *hash;
{
- st_foreach(hash->tbl, delete_if_i, 0);
+ rb_secure(5);
+ hash_foreach(hash, delete_if_i, 0);
return (VALUE)hash;
}
@@ -259,6 +374,7 @@ static VALUE
hash_clear(hash)
struct RHash *hash;
{
+ rb_secure(5);
st_foreach(hash->tbl, clear_i);
return (VALUE)hash;
@@ -269,6 +385,7 @@ hash_aset(hash, key, val)
struct RHash *hash;
VALUE key, val;
{
+ rb_secure(5);
if (NIL_P(val)) {
hash_delete(hash, key);
return Qnil;
@@ -300,6 +417,7 @@ static int
each_value_i(key, value)
VALUE key, value;
{
+ if (key == Qnil) return ST_CONTINUE;
rb_yield(value);
return ST_CONTINUE;
}
@@ -308,7 +426,7 @@ static VALUE
hash_each_value(hash)
struct RHash *hash;
{
- st_foreach(hash->tbl, each_value_i);
+ hash_foreach(hash, each_value_i);
return (VALUE)hash;
}
@@ -316,6 +434,7 @@ static int
each_key_i(key, value)
VALUE key, value;
{
+ if (key == Qnil) return ST_CONTINUE;
rb_yield(key);
return ST_CONTINUE;
}
@@ -324,7 +443,7 @@ static VALUE
hash_each_key(hash)
struct RHash *hash;
{
- st_foreach(hash->tbl, each_key_i);
+ hash_foreach(hash, each_key_i);
return (VALUE)hash;
}
@@ -332,6 +451,7 @@ static int
each_pair_i(key, value)
VALUE key, value;
{
+ if (key == Qnil) return ST_CONTINUE;
rb_yield(assoc_new(key, value));
return ST_CONTINUE;
}
@@ -340,7 +460,7 @@ static VALUE
hash_each_pair(hash)
struct RHash *hash;
{
- st_foreach(hash->tbl, each_pair_i);
+ hash_foreach(hash, each_pair_i);
return (VALUE)hash;
}
@@ -348,6 +468,7 @@ static int
to_a_i(key, value, ary)
VALUE key, value, ary;
{
+ if (key == Qnil) return ST_CONTINUE;
ary_push(ary, assoc_new(key, value));
return ST_CONTINUE;
}
@@ -371,6 +492,7 @@ inspect_i(key, value, str)
{
VALUE str2;
+ if (key == Qnil) return ST_CONTINUE;
if (str->len > 1) {
str_cat(str, ", ", 2);
}
@@ -407,6 +529,7 @@ static int
keys_i(key, value, ary)
VALUE key, value, ary;
{
+ if (key == Qnil) return ST_CONTINUE;
ary_push(ary, key);
return ST_CONTINUE;
}
@@ -427,6 +550,7 @@ static int
values_i(key, value, ary)
VALUE key, value, ary;
{
+ if (key == Qnil) return ST_CONTINUE;
ary_push(ary, value);
return ST_CONTINUE;
}
@@ -443,17 +567,6 @@ hash_values(hash)
return ary;
}
-static int
-hash_search_value(key, value, data)
- VALUE key, value, *data;
-{
- if (rb_equal(value, data[1])) {
- data[0] = TRUE;
- return ST_STOP;
- }
- return ST_CONTINUE;
-}
-
static VALUE
hash_has_key(hash, key)
struct RHash *hash;
@@ -465,6 +578,18 @@ hash_has_key(hash, key)
return FALSE;
}
+static int
+hash_search_value(key, value, data)
+ VALUE key, value, *data;
+{
+ if (key == Qnil) return ST_CONTINUE;
+ if (rb_equal(value, data[1])) {
+ data[0] = TRUE;
+ return ST_STOP;
+ }
+ return ST_CONTINUE;
+}
+
static VALUE
hash_has_value(hash, val)
struct RHash *hash;
@@ -490,6 +615,7 @@ equal_i(key, val1, data)
{
VALUE val2;
+ if (key == Qnil) return ST_CONTINUE;
if (!st_lookup(data->tbl, key, &val2)) {
data->result = FALSE;
return ST_STOP;
@@ -519,45 +645,30 @@ hash_equal(hash1, hash2)
}
static int
-hash_i(key, val, data)
- VALUE key, val;
- int *data;
+hash_invert_i(key, value, hash)
+ VALUE key, value;
+ struct RHash *hash;
{
- *data ^= rb_funcall(key, hash, 0);
- *data ^= rb_funcall(val, hash, 0);
+ if (key == Qnil) return ST_CONTINUE;
+ hash_aset(hash, value, key);
return ST_CONTINUE;
}
static VALUE
-hash_hash(hash)
+hash_invert(hash)
struct RHash *hash;
{
- int h;
+ VALUE h = hash_new();
- st_foreach(hash->tbl, hash_i, &h);
- return INT2FIX(h);
+ st_foreach(hash->tbl, hash_invert_i, h);
+ return h;
}
-extern char **environ;
-
-static VALUE
-env_each(hash)
- VALUE hash;
-{
- char **env;
-
- env = environ;
- while (*env) {
- VALUE var, val;
- char *s = strchr(*env, '=');
+int env_path_tainted = 0;
- var = str_new(*env, s-*env);
- val = str_new2(s+1);
- rb_yield(assoc_new(var, val));
- env++;
- }
- return hash;
-}
+#ifndef NT
+extern char **environ;
+#endif
static VALUE
env_delete(obj, name)
@@ -567,9 +678,11 @@ env_delete(obj, name)
int i, len;
char *nam, *val = 0;
+ rb_secure(4);
Check_Type(name, T_STRING);
nam = name->ptr;
len = strlen(nam);
+ if (strcmp(nam, "PATH") == 0) env_path_tainted = 0;
for(i=0; environ[i]; i++) {
if (strncmp(environ[i], nam, len) == 0 && environ[i][len] == '=') {
val = environ[i]+len+1;
@@ -586,7 +699,7 @@ env_delete(obj, name)
return Qnil;
}
-VALUE
+static VALUE
f_getenv(obj, name)
VALUE obj;
struct RString *name;
@@ -600,43 +713,222 @@ f_getenv(obj, name)
env = getenv(name->ptr);
if (env) {
- return str_new2(env);
+ if (strcmp(name->ptr, "PATH") == 0 && !env_path_tainted)
+ return str_new2(env);
+ return str_taint(str_new2(env));
}
return Qnil;
}
-VALUE
+static VALUE
f_setenv(obj, name, value)
VALUE obj;
struct RString *name, *value;
{
- Check_Type(name, T_STRING);
+ if (rb_safe_level() >= 4) {
+ extern VALUE eSecurityError;
+ Raise(eSecurityError, "cannot change environment variable");
+ }
+
+ Check_SafeStr(name);
if (NIL_P(value)) {
env_delete(obj, name);
return Qnil;
}
- Check_Type(value, T_STRING);
-
+ Check_SafeStr(value);
if (strlen(name->ptr) != name->len)
ArgError("Bad environment name");
if (strlen(value->ptr) != value->len)
ArgError("Bad environment value");
setenv(name->ptr, value->ptr, 1);
+ if (strcmp(name->ptr, "PATH") == 0) env_path_tainted = 0;
return TRUE;
}
static VALUE
+env_keys()
+{
+ char **env;
+ VALUE ary = ary_new();
+
+ env = environ;
+ while (*env) {
+ char *s = strchr(*env, '=');
+ ary_push(ary, str_taint(str_new(*env, s-*env)));
+ env++;
+ }
+ return ary;
+}
+
+static VALUE
+env_each_key(hash)
+ VALUE hash;
+{
+ return ary_each(env_keys());
+}
+
+static VALUE
+env_values()
+{
+ char **env;
+ VALUE ary = ary_new();
+
+ env = environ;
+ while (*env) {
+ char *s = strchr(*env, '=');
+ ary_push(ary, str_taint(str_new2(s+1)));
+ env++;
+ }
+ return ary;
+}
+
+static VALUE
+env_each_value(hash)
+ VALUE hash;
+{
+ return ary_each(env_values());
+}
+
+static VALUE
+env_each(hash)
+ VALUE hash;
+{
+ VALUE ary = env_keys();
+ VALUE *ptr = RARRAY(ary)->ptr;
+ int len = RARRAY(ary)->len;
+
+ while (len--) {
+ VALUE val = f_getenv(Qnil, *ptr);
+ if (!NIL_P(val)) {
+ rb_yield(assoc_new(*ptr, val));
+ }
+ ptr++;
+ }
+ return hash;
+}
+
+static VALUE
+env_delete_if()
+{
+ VALUE ary = env_keys();
+ VALUE *ptr = RARRAY(ary)->ptr;
+ int len = RARRAY(ary)->len;
+
+ while (len--) {
+ VALUE val = f_getenv(Qnil, *ptr);
+ if (!NIL_P(val)) {
+ if (RTEST(rb_yield(assoc_new(*ptr, val)))) {
+ env_delete(Qnil, *ptr);
+ }
+ }
+ ptr++;
+ }
+ return envtbl;
+}
+
+static VALUE
env_to_s()
{
return str_new2("ENV");
}
+static VALUE
+env_to_a()
+{
+ char **env;
+ VALUE ary = ary_new();
+
+ env = environ;
+ while (*env) {
+ char *s = strchr(*env, '=');
+ ary_push(ary, assoc_new(str_taint(str_new(*env, s-*env)),
+ str_taint(str_new2(s+1))));
+ env++;
+ }
+ return ary;
+}
+
+static VALUE
+env_none()
+{
+ return Qnil;
+}
+
+static VALUE
+env_size()
+{
+ int i;
+
+ for(i=0; environ[i]; i++)
+ ;
+ return INT2FIX(i);
+}
+
+static VALUE
+env_empty_p()
+{
+ if (environ[0] == 0) return TRUE;
+ return FALSE;
+}
+
+static VALUE
+env_has_key(env, key)
+ VALUE env, key;
+{
+ if (TYPE(key) != T_STRING) return FALSE;
+ if (getenv(RSTRING(key)->ptr)) return TRUE;
+ return FALSE;
+}
+
+static VALUE
+env_has_value(dmy, value)
+ VALUE dmy, value;
+{
+ char **env;
+ VALUE ary;
+
+ if (TYPE(value) != T_STRING) return FALSE;
+ ary = ary_new();
+ env = environ;
+ while (*env) {
+ char *s = strchr(*env, '=')+1;
+ int len = strlen(s);
+ if (strncmp(s, RSTRING(value)->ptr, len) == 0) return TRUE;
+ env++;
+ }
+ return FALSE;
+}
+
+static VALUE
+env_indexes(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ int i;
+ VALUE indexes = ary_new2(argc);
+
+ for (i=0;i<argc;i++) {
+ char *v = 0;
+ if (TYPE(argv[i]) == T_STRING) {
+ v = getenv(RSTRING(argv[i])->ptr);
+ }
+ if (v) {
+ RARRAY(indexes)->ptr[i] = str_new2(v);
+ }
+ else {
+ RARRAY(indexes)->ptr[i] = Qnil;
+ }
+ RARRAY(indexes)->len = i+1;
+ }
+
+ return indexes;
+}
+
void
Init_Hash()
{
- extern VALUE cKernel;
extern VALUE mEnumerable;
hash = rb_intern("hash");
@@ -649,16 +941,16 @@ Init_Hash()
rb_define_singleton_method(cHash, "[]", hash_s_create, -1);
rb_define_method(cHash,"clone", hash_clone, 0);
+ rb_define_method(cHash,"rehash", hash_rehash, 0);
rb_define_method(cHash,"to_a", hash_to_a, 0);
rb_define_method(cHash,"to_s", hash_to_s, 0);
rb_define_method(cHash,"inspect", hash_inspect, 0);
rb_define_method(cHash,"==", hash_equal, 1);
- rb_define_method(cHash,"hash", hash_hash, 0);
rb_define_method(cHash,"[]", hash_aref, 1);
rb_define_method(cHash,"[]=", hash_aset, 2);
- rb_define_method(cHash,"indexes", hash_indexes, -2);
+ rb_define_method(cHash,"indexes", hash_indexes, -1);
rb_define_method(cHash,"length", hash_length, 0);
rb_define_alias(cHash, "size", "length");
rb_define_method(cHash,"empty?", hash_empty_p, 0);
@@ -675,6 +967,7 @@ Init_Hash()
rb_define_method(cHash,"delete", hash_delete, 1);
rb_define_method(cHash,"delete_if", hash_delete_if, 0);
rb_define_method(cHash,"clear", hash_clear, 0);
+ rb_define_method(cHash,"invert", hash_invert, 0);
rb_define_method(cHash,"include?", hash_has_key, 1);
rb_define_method(cHash,"has_key?", hash_has_key, 1);
@@ -688,9 +981,24 @@ Init_Hash()
rb_define_singleton_method(envtbl,"[]", f_getenv, 1);
rb_define_singleton_method(envtbl,"[]=", f_setenv, 2);
rb_define_singleton_method(envtbl,"each", env_each, 0);
+ rb_define_singleton_method(envtbl,"each_pair", env_each, 0);
+ rb_define_singleton_method(envtbl,"each_key", env_each_key, 0);
+ rb_define_singleton_method(envtbl,"each_value", env_each_value, 0);
rb_define_singleton_method(envtbl,"delete", env_delete, 1);
+ rb_define_singleton_method(envtbl,"delete_if", env_delete_if, 0);
rb_define_singleton_method(envtbl,"to_s", env_to_s, 0);
+ rb_define_singleton_method(envtbl,"rehash", env_none, 0);
+ rb_define_singleton_method(envtbl,"to_a", env_to_a, 0);
+ rb_define_singleton_method(envtbl,"indexes", env_indexes, -1);
+ rb_define_singleton_method(envtbl,"length", env_size, 0);
+ rb_define_singleton_method(envtbl,"empty?", env_empty_p, 0);
+ rb_define_singleton_method(envtbl,"keys", env_keys, 0);
+ rb_define_singleton_method(envtbl,"values", env_values, 0);
+ rb_define_singleton_method(envtbl,"include?", env_has_key, 1);
+ rb_define_singleton_method(envtbl,"has_key?", env_has_key, 1);
+ rb_define_singleton_method(envtbl,"has_value?", env_has_value, 1);
+ rb_define_singleton_method(envtbl,"key?", env_has_key, 1);
+ rb_define_singleton_method(envtbl,"value?", env_has_value, 1);
- rb_define_readonly_variable("$ENV", &envtbl);
rb_define_global_const("ENV", envtbl);
}
diff --git a/inits.c b/inits.c
index e345681..b8fcb0f 100644
--- a/inits.c
+++ b/inits.c
@@ -21,7 +21,6 @@ rb_call_inits()
#ifdef THREAD
Init_Thread();
#endif
- Init_GC();
Init_eval();
Init_Comparable();
Init_Enumerable();
@@ -44,6 +43,6 @@ rb_call_inits()
Init_load();
Init_Proc();
Init_Math();
- Init_ext();
+ Init_GC();
Init_version();
}
diff --git a/io.c b/io.c
index 7c0fbd8..8d3fb7b 100644
--- a/io.c
+++ b/io.c
@@ -16,28 +16,39 @@
#include <errno.h>
#include <sys/types.h>
-#ifndef DJGPP
+#if !defined(DJGPP) && !defined(NT) && !defined(__human68k__)
#include <sys/ioctl.h>
#endif
+#if defined(HAVE_FCNTL)
+#include <fcntl.h>
+#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#else
+#ifndef NT
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* and microseconds */
};
#endif
+#endif
#ifdef HAVE_VFORK_H
#include <vfork.h>
#endif
#include <sys/stat.h>
-#ifdef DJGPP
+#if defined(DJGPP) || defined(__CYGWIN32__) || defined(NT) || defined(__human68k__)
#include <fcntl.h>
#endif
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#else
+# define NOFILE 64
+#endif
+
VALUE rb_ad_string();
VALUE cIO;
@@ -53,7 +64,7 @@ VALUE RS_default;
static VALUE argf;
-ID id_write, id_fd, id_print_on;
+ID id_write;
VALUE lastline_get();
void lastline_set();
@@ -116,11 +127,6 @@ closed()
Raise(eIOError, "closed stream");
}
-void
-io_wrong_type()
-{
-}
-
/* writing functions */
VALUE
io_write(io, str)
@@ -129,23 +135,40 @@ io_write(io, str)
{
OpenFile *fptr;
FILE *f;
- VALUE out;
int n;
+ if (TYPE(str) != T_STRING)
+ str = (struct RString*)obj_as_string(str);
+ if (str->len == 0) return INT2FIX(0);
+
+ if (BUILTIN_TYPE(io) != T_FILE) {
+ return rb_funcall(io, id_write, 1, str);
+ }
+
+ rb_secure(4);
GetOpenFile(io, fptr);
io_writable(fptr);
- f = (fptr->f2) ? fptr->f2 : fptr->f;
+ f = GetWriteFile(fptr);
if (f == NULL) closed();
- if (TYPE(str) != T_STRING)
- str = (struct RString*)obj_as_string(str);
- if (str->len == 0) return INT2FIX(0);
-
+#ifdef __human68k__
+ {
+ register UCHAR *ptr = str->ptr;
+ n = (int) str->len;
+ while (--n >= 0)
+ if (fputc(*ptr++, f) == EOF)
+ rb_sys_fail(fptr->path);
+ n = ptr - str->ptr;
+ }
+ if (ferror(f))
+ rb_sys_fail(fptr->path);
+#else
n = fwrite(str->ptr, 1, str->len, f);
if (n == 0 || ferror(f)) {
rb_sys_fail(fptr->path);
}
+#endif
if (fptr->mode & FMODE_SYNC) {
fflush(f);
}
@@ -170,7 +193,7 @@ io_flush(io)
GetOpenFile(io, fptr);
io_writable(fptr);
- f = (fptr->f2) ? fptr->f2 : fptr->f;
+ f = GetWriteFile(fptr);
if (f == NULL) closed();
if (fflush(f) == EOF) rb_sys_fail(0);
@@ -247,7 +270,7 @@ read_all(port)
VALUE port;
{
OpenFile *fptr;
- VALUE str;
+ VALUE str = Qnil;
char buf[BUFSIZ];
int n;
@@ -255,7 +278,6 @@ read_all(port)
io_readable(fptr);
if (fptr->f == NULL) closed();
- str = str_new(0, 0);
for (;;) {
READ_CHECK(fptr->f);
TRAP_BEG;
@@ -263,9 +285,10 @@ read_all(port)
TRAP_END;
if (n == 0) break;
if (n < 0) rb_sys_fail(0);
- str_cat(str, buf, n);
+ if (NIL_P(str)) str = str_new(buf, n);
+ else str_cat(str, buf, n);
}
- return str;
+ return str_taint(str);
}
static VALUE
@@ -301,7 +324,7 @@ io_read(argc, argv, io)
RSTRING(str)->len = n;
RSTRING(str)->ptr[n] = '\0';
- return str;
+ return str_taint(str);
}
static VALUE lineno;
@@ -320,11 +343,10 @@ io_gets_method(argc, argv, io)
int rslen, rspara = 0;
VALUE rs;
- if (rb_scan_args(argc, argv, "01", &rs) == 1) {
- if (!NIL_P(rs)) Check_Type(rs, T_STRING);
- }
+ if (argc == 0) rs = RS;
else {
- rs = RS;
+ rb_scan_args(argc, argv, "1", &rs);
+ if (!NIL_P(rs)) Check_Type(rs, T_STRING);
}
GetOpenFile(io, fptr);
@@ -384,8 +406,11 @@ io_gets_method(argc, argv, io)
cnt = bp - buf;
}
else {
+ READ_CHECK(f);
+ TRAP_BEG;
cnt = fread(buf, 1, sizeof(buf), f);
- c = cnt ? buf[cnt - 1]: EOF;
+ TRAP_END;
+ c = cnt ? 0 : EOF;
}
if (c == EOF) {
@@ -429,7 +454,7 @@ io_gets_method(argc, argv, io)
}
lastline_set(str);
- return (VALUE)str;
+ return str_taint(str);
}
VALUE
@@ -454,6 +479,21 @@ io_readline(argc, argv, io)
}
static VALUE
+io_readlines(argc, argv, io)
+ int argc;
+ VALUE argv;
+ VALUE io;
+{
+ VALUE line, ary;
+
+ ary = ary_new();
+ while (!NIL_P(line = io_gets_method(argc, argv, io))) {
+ ary_push(ary, line);
+ }
+ return ary;
+}
+
+static VALUE
io_each_line(argc, argv, io)
int argc;
VALUE argv;
@@ -550,12 +590,10 @@ io_isatty(io)
{
OpenFile *fptr;
-#ifndef NT
GetOpenFile(io, fptr);
if (fptr->f == NULL) closed();
if (isatty(fileno(fptr->f)) == 0)
return FALSE;
-#endif
return TRUE;
}
@@ -623,12 +661,13 @@ io_syswrite(io, str)
FILE *f;
int n;
+ rb_secure(4);
if (TYPE(str) != T_STRING)
str = obj_as_string(str);
GetOpenFile(io, fptr);
io_writable(fptr);
- f = (fptr->f2) ? fptr->f2 : fptr->f;
+ f = GetWriteFile(fptr);
if (f == NULL) closed();
#ifdef THREAD
@@ -668,22 +707,31 @@ io_sysread(io, len)
RSTRING(str)->len = n;
RSTRING(str)->ptr[n] = '\0';
- return str;
+ return str_taint(str);
}
-static VALUE
+VALUE
io_binmode(io)
VALUE io;
{
-#if defined(NT) || defined(DJGPP)
+#if defined(NT) || defined(DJGPP) || defined(__CYGWIN32__) || defined(__human68k__)
OpenFile *fptr;
GetOpenFile(io, fptr);
+#ifdef __human68k__
+ if (fptr->f)
+ fmode(fptr->f, _IOBIN);
+ if (fptr->f2);
+ fmode(fptr->f2, _IOBIN);
+#else
if (fptr->f && setmode(fileno(fptr->f), O_BINARY) == -1)
rb_sys_fail(fptr->path);
if (fptr->f2 && setmode(fileno(fptr->f2), O_BINARY) == -1)
rb_sys_fail(fptr->path);
#endif
+
+ fptr->mode |= FMODE_BINMODE;
+#endif
return io;
}
@@ -706,8 +754,14 @@ io_mode_flags(mode)
default:
ArgError("illegal access mode");
}
+
+ if (mode[1] == 'b') {
+ flags |= FMODE_BINMODE;
+ mode++;
+ }
+
if (mode[1] == '+') {
- flags |= FMODE_READABLE | FMODE_WRITABLE;
+ flags |= FMODE_READWRITE;
}
return flags;
@@ -752,7 +806,59 @@ rb_fdopen(fd, mode)
return f;
}
-#if defined (NT) || defined(DJGPP)
+#if defined (NT) || defined(DJGPP) || defined(__CYGWIN32__) || defined(__human68k__)
+static struct pipe_list {
+ OpenFile *fptr;
+ struct pipe_list *next;
+} *pipe_list;
+
+static void
+pipe_add_fptr(fptr)
+ OpenFile *fptr;
+{
+ struct pipe_list *list;
+
+ list = ALLOC(struct pipe_list);
+ list->fptr = fptr;
+ list->next = pipe_list;
+ pipe_list = list;
+}
+
+static void
+pipe_del_fptr(fptr)
+ OpenFile *fptr;
+{
+ struct pipe_list *list = pipe_list;
+ struct pipe_list *tmp;
+
+ if (list->fptr == fptr) {
+ pipe_list = list->next;
+ return;
+ }
+
+ while (list->next) {
+ if (list->next->fptr == fptr) {
+ tmp = list->next;
+ list->next = list->next->next;
+ free(tmp);
+ return;
+ }
+ list = list->next;
+ }
+}
+
+static void
+pipe_atexit()
+{
+ struct pipe_list *list = pipe_list;
+
+ while (list) {
+ io_fptr_finalize(list->fptr);
+ list = list->next;
+ }
+}
+
+#if !defined (__CYGWIN32__)
static void
pipe_finalize(fptr)
OpenFile *fptr;
@@ -760,9 +866,24 @@ pipe_finalize(fptr)
if (fptr->f != NULL) {
pclose(fptr->f);
}
+ if (fptr->f2 != NULL) {
+ pclose(fptr->f2);
+ }
fptr->f = fptr->f2 = NULL;
+ pipe_del_fptr(fptr);
}
#endif
+#endif
+
+void
+io_unbuffered(fptr)
+ OpenFile *fptr;
+{
+ if (fptr->f2 == 0) TypeError("non-writable fptr");
+ setbuf(fptr->f, NULL);
+ setbuf(fptr->f2, NULL);
+ fptr->mode |= FMODE_SYNC;
+}
static VALUE
pipe_open(pname, mode)
@@ -771,7 +892,7 @@ pipe_open(pname, mode)
int modef = io_mode_flags(mode);
OpenFile *fptr;
-#if defined(NT) || defined(DJGPP)
+#if defined(NT) || defined(DJGPP) || defined(__human68k__)
FILE *f = popen(pname, mode);
if (f == NULL) rb_sys_fail(pname);
@@ -780,10 +901,14 @@ pipe_open(pname, mode)
OBJSETUP(port, cIO, T_FILE);
MakeOpenFile(port, fptr);
fptr->finalize = pipe_finalize;
+ fptr->mode = modef;
+ pipe_add_fptr(fptr);
if (modef & FMODE_READABLE) fptr->f = f;
- if (modef & FMODE_WRITABLE) fptr->f2 = f;
- fptr->mode = modef | FMODE_SYNC;
+ if (modef & FMODE_WRITABLE) {
+ fptr->f2 = f;
+ io_unbuffered(fptr);
+ }
return (VALUE)port;
}
#else
@@ -806,32 +931,47 @@ pipe_open(pname, mode)
case 0: /* child */
if (modef & FMODE_READABLE) {
close(pr[0]);
- dup2(pr[1], 1);
- close(pr[1]);
+ if (pr[1] != 1) {
+ dup2(pr[1], 1);
+ close(pr[1]);
+ }
}
if (modef & FMODE_WRITABLE) {
close(pw[1]);
- dup2(pw[0], 0);
- close(pw[0]);
+ if (pw[0] != 0) {
+ dup2(pw[0], 0);
+ close(pw[0]);
+ }
}
if (doexec) {
- VALUE fd = io_fileno(rb_stderr);
- int f = FIX2INT(fd);
+ VALUE serr = io_fileno(rb_stderr);
+ int fd = FIX2INT(serr);
+ extern char *sourcefile;
+ extern int sourceline;
- if (f != 2) {
+ if (fd != 2) {
close(2);
- dup2(f, 2);
- close(f);
+ dup2(fd, 2);
+ close(fd);
}
+
+ for (fd = 3; fd < NOFILE; fd++)
+ close(fd);
rb_proc_exec(pname);
+ fprintf(stderr, "%s:%d: command not found: %s\n",
+ sourcefile, sourceline, pname);
_exit(127);
}
return Qnil;
case -1: /* fork failed */
if (errno == EAGAIN) {
+#ifdef THREAD
+ thread_sleep(1);
+#else
sleep(1);
+#endif
goto retry;
}
close(pr[0]); close(pw[1]);
@@ -843,15 +983,24 @@ pipe_open(pname, mode)
NEWOBJ(port, struct RFile);
OBJSETUP(port, cIO, T_FILE);
MakeOpenFile(port, fptr);
- if (modef & FMODE_READABLE) close(pr[1]);
- if (modef & FMODE_WRITABLE) close(pw[0]);
fptr->mode = modef;
fptr->mode |= FMODE_SYNC;
fptr->pid = pid;
- if (modef & FMODE_READABLE) fptr->f = rb_fdopen(pr[0], "r");
- if (modef & FMODE_WRITABLE) fptr->f2 = rb_fdopen(pw[1], "w");
+ if (modef & FMODE_READABLE) {
+ close(pr[1]);
+ fptr->f = rb_fdopen(pr[0], "r");
+ }
+ if (modef & FMODE_WRITABLE) {
+ FILE *f = rb_fdopen(pw[1], "w");
+ close(pw[0]);
+ if (fptr->f) fptr->f2 = f;
+ else fptr->f = f;
+ }
+#if defined (__CYGWIN32__)
+ pipe_add_fptr(fptr);
+#endif
return (VALUE)port;
}
}
@@ -859,7 +1008,7 @@ pipe_open(pname, mode)
}
static VALUE
-io_popen(argc, argv, self)
+io_s_popen(argc, argv, self)
int argc;
VALUE *argv;
VALUE self;
@@ -868,7 +1017,7 @@ io_popen(argc, argv, self)
VALUE pname, pmode;
rb_scan_args(argc, argv, "11", &pname, &pmode);
- Check_Type(pname, T_STRING);
+ Check_SafeStr(pname);
if (NIL_P(pmode)) {
mode = "r";
}
@@ -877,7 +1026,7 @@ io_popen(argc, argv, self)
if (RSTRING(pmode)->len == 0 || RSTRING(pmode)->len > 2)
ArgError("illegal access mode");
mode = RSTRING(pmode)->ptr;
- }
+ }
return pipe_open(RSTRING(pname)->ptr, mode);
}
@@ -903,7 +1052,7 @@ f_open(argc, argv, self)
VALUE pname, pmode;
rb_scan_args(argc, argv, "11", &pname, &pmode);
- Check_Type(pname, T_STRING);
+ Check_SafeStr(pname);
if (NIL_P(pmode)) {
mode = "r";
}
@@ -916,6 +1065,126 @@ f_open(argc, argv, self)
return io_open(RSTRING(pname)->ptr, mode);
}
+#ifndef NT
+extern char *strdup();
+#endif
+
+VALUE
+io_reopen(io, nfile)
+ VALUE io, nfile;
+{
+ OpenFile *fptr, *orig;
+ char *mode;
+ int fd;
+
+ GetOpenFile(io, fptr);
+ Check_Type(nfile, T_FILE);
+ GetOpenFile(nfile, orig);
+
+ if (orig->f2) {
+ fflush(orig->f2);
+ }
+ else if (orig->mode & FMODE_WRITABLE) {
+ fflush(orig->f);
+ }
+
+ /* copy OpenFile structure */
+ fptr->mode = orig->mode;
+ fptr->pid = orig->pid;
+ fptr->lineno = orig->lineno;
+ if (fptr->path) free(fptr->path);
+ if (orig->path) fptr->path = strdup(orig->path);
+ else fptr->path = 0;
+ fptr->finalize = orig->finalize;
+
+ switch (fptr->mode & FMODE_READWRITE) {
+ case FMODE_READABLE:
+ default:
+ mode = "r"; break;
+ case FMODE_WRITABLE:
+ mode = "w"; break;
+ case FMODE_READWRITE:
+ if (orig->f2) mode = "r";
+ else mode = "r+";
+ break;
+ }
+ fd = fileno(fptr->f);
+ fclose(fptr->f);
+ dup2(fileno(orig->f), fd);
+ fptr->f = rb_fdopen(fd, mode);
+
+ if (fptr->f2) {
+ fd = fileno(fptr->f2);
+ fclose(fptr->f2);
+ if (orig->f2) {
+ dup2(fileno(orig->f2), fd);
+ fptr->f = rb_fdopen(fd, "w");
+ }
+ else {
+ fptr->f2 = 0;
+ }
+ }
+
+ if (fptr->mode & FMODE_BINMODE) {
+ io_binmode(io);
+ }
+
+ RBASIC(io)->class = RBASIC(nfile)->class;
+ return io;
+}
+
+static VALUE
+io_clone(io)
+ VALUE io;
+{
+ OpenFile *fptr, *orig;
+ int fd;
+ char *mode;
+
+ NEWOBJ(obj, struct RFile);
+ OBJSETUP(obj, CLASS_OF(io), T_FILE);
+
+ GetOpenFile(io, orig);
+ MakeOpenFile(obj, fptr);
+
+ if (orig->f2) {
+ fflush(orig->f2);
+ }
+ else if (orig->mode & FMODE_WRITABLE) {
+ fflush(orig->f);
+ }
+
+ /* copy OpenFile structure */
+ fptr->mode = orig->mode;
+ fptr->pid = orig->pid;
+ fptr->lineno = orig->lineno;
+ if (orig->path) fptr->path = strdup(orig->path);
+ fptr->finalize = orig->finalize;
+
+ switch (fptr->mode & FMODE_READWRITE) {
+ case FMODE_READABLE:
+ default:
+ mode = "r"; break;
+ case FMODE_WRITABLE:
+ mode = "w"; break;
+ case FMODE_READWRITE:
+ if (orig->f2) mode = "r";
+ else mode = "r+";
+ break;
+ }
+ fd = dup(fileno(orig->f));
+ fptr->f = rb_fdopen(fd, mode);
+ if (fptr->f2) {
+ fd = dup(fileno(orig->f2));
+ fptr->f = rb_fdopen(fd, "w");
+ }
+ if (fptr->mode & FMODE_BINMODE) {
+ io_binmode(obj);
+ }
+
+ return (VALUE)obj;
+}
+
static VALUE
io_printf(argc, argv, out)
int argc;
@@ -971,14 +1240,17 @@ io_print(argc, argv, out)
io_write(out, OFS);
}
switch (TYPE(argv[i])) {
- case T_STRING:
- io_write(out, argv[i]);
- break;
case T_NIL:
io_write(out, str_new2("nil"));
break;
+ case T_ARRAY:
+ ary_print_on(argv[i], out);
+ break;
+ case T_HASH:
+ break;
+ case T_STRING:
default:
- rb_funcall(argv[i], id_print_on, 1, out);
+ io_write(out, argv[i]);
break;
}
}
@@ -998,8 +1270,9 @@ f_print(argc, argv)
return Qnil;
}
-VALUE
+static VALUE
f_p(obj, val)
+ VALUE obj, val;
{
VALUE str = rb_inspect(val);
@@ -1009,7 +1282,7 @@ f_p(obj, val)
return Qnil;
}
-static VALUE
+static void
io_defset(val, id)
VALUE val;
ID id;
@@ -1017,17 +1290,11 @@ io_defset(val, id)
if (TYPE(val) == T_STRING) {
val = io_open(RSTRING(val)->ptr, "w");
}
- if (!obj_is_kind_of(val, cIO)) {
- TypeError("$< must be a file, %s given", rb_class2name(CLASS_OF(val)));
+ if (!rb_respond_to(val, id_write)) {
+ TypeError("$< must have write method, %s given",
+ rb_class2name(CLASS_OF(val)));
}
- return rb_defout = val;
-}
-
-static VALUE
-f_print_on(obj, port)
- VALUE obj, port;
-{
- return io_write(port, obj);
+ rb_defout = val;
}
static VALUE
@@ -1046,6 +1313,25 @@ prep_stdio(f, mode)
return (VALUE)obj;
}
+static VALUE
+io_s_new(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ VALUE fnum, mode;
+ FILE *f;
+ char *m = "r";
+
+ rb_scan_args(argc, argv, "11", &fnum, &mode);
+
+ if (!NIL_P(mode)) {
+ Check_SafeStr(mode);
+ m = RSTRING(mode)->ptr;
+ }
+ f = rb_fdopen(NUM2INT(fnum), m);
+ return prep_stdio(f, io_mode_flags(m));
+}
+
static VALUE filename, file;
static int gets_lineno;
static int init_p = 0, next_p = 0;
@@ -1094,12 +1380,12 @@ next_argv()
fstat(fileno(fr), &st);
if (*inplace) {
str = str_new2(fn);
-#ifdef NT
+#if defined(MSDOS) || defined(__CYGWIN32__) || defined(NT)
add_suffix(str, inplace);
#else
str_cat(str, inplace, strlen(inplace));
#endif
-#if defined(MSDOS) || defined(__BOW__)
+#if defined(MSDOS) || defined(__BOW__) || defined(__CYGWIN32__) || defined(NT) || defined(__human68k__)
(void)fclose(fr);
(void)unlink(RSTRING(str)->ptr);
(void)rename(fn, RSTRING(str)->ptr);
@@ -1114,7 +1400,7 @@ next_argv()
#endif
}
else {
-#if !defined(MSDOS) && !defined(__BOW__)
+#if !defined(MSDOS) && !defined(__BOW__) && !defined(__CYGWIN32__) && !defined(NT) && !defined(__human68k__)
if (unlink(fn) < 0) {
Warning("Can't remove %s: %s, skipping file",
fn, strerror(errno));
@@ -1126,7 +1412,7 @@ next_argv()
#endif
}
fw = rb_fopen(fn, "w");
-#if !defined(DJGPP) && !defined(__CYGWIN32__)
+#if !defined(MSDOS) && !defined(__CYGWIN32__) && !(NT) && !defined(__human68k__)
fstat(fileno(fw), &st2);
fchmod(fileno(fw), st.st_mode);
if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
@@ -1149,7 +1435,7 @@ next_argv()
static VALUE
f_gets_method(argc, argv)
int argc;
- VALUE argv;
+ VALUE *argv;
{
VALUE line;
@@ -1168,9 +1454,7 @@ f_gets_method(argc, argv)
}
VALUE
-f_gets(argc, argv)
- int argc;
- VALUE argv;
+f_gets()
{
return f_gets_method(0,0);
}
@@ -1237,14 +1521,14 @@ f_readlines(argc, argv)
VALUE line, ary;
ary = ary_new();
- while (RTEST(line = f_gets_method(argc, argv))) {
+ while (!NIL_P(line = f_gets_method(argc, argv))) {
ary_push(ary, line);
}
return ary;
}
-VALUE
+void
rb_str_setter(val, id, var)
VALUE val;
ID id;
@@ -1253,7 +1537,7 @@ rb_str_setter(val, id, var)
if (!NIL_P(val) && TYPE(val) != T_STRING) {
TypeError("value of %s must be String", rb_id2name(id));
}
- return *var = val;
+ *var = val;
}
static VALUE
@@ -1262,20 +1546,23 @@ f_backquote(obj, str)
struct RString *str;
{
VALUE port, result;
- OpenFile *fptr;
- Check_Type(str, T_STRING);
+ Check_SafeStr(str);
port = pipe_open(str->ptr, "r");
result = read_all(port);
io_close(port);
+ if (NIL_P(result)) return str_new(0,0);
return result;
}
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
+#ifdef NT
+#define select(v, w, x, y, z) (-1) /* anytime fail */
+#endif
static VALUE
f_select(argc, argv, obj)
@@ -1290,6 +1577,7 @@ f_select(argc, argv, obj)
OpenFile *fptr;
int i, max = 0, n;
int interrupt = 0;
+ int pending = 0;
rb_scan_args(argc, argv, "13", &read, &write, &except, &timeout);
if (NIL_P(timeout)) {
@@ -1302,7 +1590,6 @@ f_select(argc, argv, obj)
FD_ZERO(&pset);
if (!NIL_P(read)) {
- int pending = 0;
Check_Type(read, T_ARRAY);
rp = &rset;
@@ -1384,6 +1671,7 @@ f_select(argc, argv, obj)
interrupt = 1;
}
#endif
+ if (!pending && n == 0) return Qnil; /* returns nil on timeout */
res = ary_new2(3);
ary_push(res, rp?ary_new():ary_new2(0));
@@ -1391,7 +1679,6 @@ f_select(argc, argv, obj)
ary_push(res, ep?ary_new():ary_new2(0));
if (interrupt == 0) {
-
if (rp) {
list = RARRAY(res)->ptr[0];
for (i=0; i< RARRAY(read)->len; i++) {
@@ -1430,64 +1717,100 @@ f_select(argc, argv, obj)
}
}
- return res;
+ return res; /* returns an empty array on interrupt */
}
-void
+static VALUE
io_ctl(io, req, arg, io_p)
VALUE io, req;
struct RString *arg;
int io_p;
{
-#if !defined(MSDOS)
+#if !defined(MSDOS) && !defined(__human68k__)
int cmd = NUM2INT(req);
OpenFile *fptr;
int len, fd;
+ long narg = 0;
+ int retval;
+ rb_secure(2);
GetOpenFile(io, fptr);
+ if (NIL_P(arg) || (VALUE)arg == FALSE) {
+ narg = 0;
+ }
+ else if (FIXNUM_P(arg)) {
+ narg = FIX2INT(arg);
+ }
+ else if ((VALUE)arg == TRUE) {
+ narg = 1;
+ }
+ else {
+ Check_Type(arg, T_STRING);
+
#ifdef IOCPARM_MASK
#ifndef IOCPARM_LEN
#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
#endif
#endif
#ifdef IOCPARM_LEN
- len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
+ len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
#else
- len = 256; /* otherwise guess at what's safe */
+ len = 256; /* otherwise guess at what's safe */
#endif
+ str_modify(arg);
- Check_Type(arg, T_STRING);
- str_modify(arg);
-
- str_resize(arg, len+1);
- arg->ptr[len] = 17;
+ if (arg->len < len) {
+ str_resize(arg, len+1);
+ arg->ptr[len] = 17; /* a little sanity check here */
+ narg = (long)arg->ptr;
+ }
+ }
fd = fileno(fptr->f);
#ifdef HAVE_FCNTL
- if ((io_p?ioctl(fd, cmd, arg->ptr):fcntl(fd, cmd, arg->ptr))<0) {
- rb_sys_fail(fptr->path);
- }
+ retval = io_p?ioctl(fd, cmd, narg):fcntl(fd, cmd, narg);
#else
if (!io_p) {
rb_notimplement();
}
- if (ioctl(fd, cmd, arg->ptr)<0) rb_sys_fail(fptr->path);
+ retval = ioctl(fd, cmd, narg);
#endif
- if (arg->ptr[len] != 17) {
- ArgError("Return value overflowed string");
+ if (retval < 0) rb_sys_fail(fptr->path);
+ if (TYPE(arg) == T_STRING && arg->ptr[len] != 17) {
+ ArgError("return value overflowed string");
}
+ return INT2NUM(retval);
#else
- rb_notimplement();
+ rb_notimplement();
#endif
}
static VALUE
-io_ioctl(io, req, arg)
- VALUE io, req;
- struct RString *arg;
+io_ioctl(argc, argv, io)
+ int argc;
+ VALUE *argv;
+ VALUE io;
{
- io_ctl(io, req, arg, 1);
- return io;
+ VALUE req, arg;
+
+ rb_scan_args(argc, argv, "11", &req, &arg);
+ return io_ctl(io, req, arg, 1);
+}
+
+static VALUE
+io_fcntl(argc, argv, io)
+ int argc;
+ VALUE *argv;
+ VALUE io;
+{
+#ifdef HAVE_FCNTL
+ VALUE req, arg;
+
+ rb_scan_args(argc, argv, "11", &req, &arg);
+ return io_ctl(io, req, arg, 0);
+#else
+ rb_notimplement();
+#endif
}
static VALUE
@@ -1502,7 +1825,7 @@ f_syscall(argc, argv)
unsigned long arg[8];
#endif
int retval = -1;
- int i = 0;
+ int i = 1;
int items = argc - 1;
/* This probably won't work on machines where sizeof(long) != sizeof(int)
@@ -1510,6 +1833,7 @@ f_syscall(argc, argv)
* not likely have syscall implemented either, so who cares?
*/
+ rb_secure(2);
arg[0] = NUM2INT(argv[0]); argv++;
while (items--) {
if (FIXNUM_P(*argv)) {
@@ -1585,13 +1909,19 @@ f_syscall(argc, argv)
}
static VALUE
-io_pipe()
+io_s_pipe()
{
+#ifndef __human68k__
int pipes[2];
VALUE r, w, ary;
+#ifdef NT
+ if (_pipe(pipes, 1024, O_BINARY) == -1)
+#else
if (pipe(pipes) == -1)
+#endif
rb_sys_fail(0);
+
r = prep_stdio(fdopen(pipes[0], "r"), FMODE_READABLE);
w = prep_stdio(fdopen(pipes[1], "w"), FMODE_WRITABLE);
@@ -1600,52 +1930,112 @@ io_pipe()
ary_push(ary, w);
return ary;
+#else
+ rb_notimplement();
+#endif
}
+struct foreach_arg {
+ int argc;
+ VALUE sep;
+ VALUE io;
+};
static VALUE
-io_foreach_line(io)
- VALUE io;
+io_foreach_line(arg)
+ struct foreach_arg *arg;
{
VALUE str;
- while (!NIL_P(str = io_gets(io))) {
+ while (!NIL_P(str = io_gets_method(arg->argc, &arg->sep, arg->io))) {
rb_yield(str);
}
return Qnil;
}
static VALUE
-io_foreach(io, fname)
+io_s_foreach(argc, argv, io)
+ int argc;
+ VALUE *argv;
VALUE io;
+{
struct RString *fname;
+ struct foreach_arg arg;
+
+ rb_scan_args(argc, argv, "11", &fname, &arg.sep);
+ Check_SafeStr(fname);
+
+ arg.argc = argc - 1;
+ arg.io = io_open(fname->ptr, "r");
+ return rb_ensure(io_foreach_line, &arg, io_close, arg.io);
+}
+
+static VALUE
+io_readline_line(arg)
+ struct foreach_arg *arg;
+{
+ VALUE line, ary;
+
+ ary = ary_new();
+ while (!NIL_P(line = io_gets_method(arg->argc, &arg->sep, arg->io))) {
+ ary_push(ary, line);
+ }
+
+ return ary;
+}
+
+static VALUE
+io_s_readlines(argc, argv, io)
+ int argc;
+ VALUE *argv;
+ VALUE io;
{
- VALUE f, v;
+ struct RString *fname;
+ struct foreach_arg arg;
+
+ rb_scan_args(argc, argv, "11", &fname, &arg.sep);
+ Check_SafeStr(fname);
+
+ arg.argc = argc - 1;
+ arg.io = io_open(fname->ptr, "r");
+ return rb_ensure(io_readline_line, &arg, io_close, arg.io);
+}
- Check_Type(fname, T_STRING);
- f = io_open(fname->ptr, "r");
- return rb_ensure(io_foreach_line, f, io_close, f);
+static VALUE
+arg_fileno()
+{
+ return io_fileno(file);
}
static VALUE
arg_read(argc, argv)
int argc;
- VALUE argv;
+ VALUE *argv;
{
- VALUE str, str2;
+ VALUE tmp, str;
+ int len;
- str = str_new(0, 0);
- for (;;) {
- retry:
- if (!next_argv()) return Qnil;
- str2 = io_read(argc, argv, file);
- if (NIL_P(str2) && next_p != -1) {
- io_close(file);
- next_p = 1;
- goto retry;
- }
- if (NIL_P(str2)) break;
- str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len);
+ if (argc == 1) len = NUM2INT(argv[0]);
+ str = Qnil;
+
+ retry:
+ if (!next_argv()) return str;
+ tmp = io_read(argc, argv, file);
+ if (NIL_P(tmp) && next_p != -1) {
+ io_close(file);
+ next_p = 1;
+ goto retry;
+ }
+ if (NIL_P(tmp)) return str;
+ else if (NIL_P(str)) str = tmp;
+ else str_cat(str, RSTRING(tmp)->ptr, RSTRING(tmp)->len);
+ if (argc == 0) {
+ goto retry;
+ }
+ if (RSTRING(tmp)->len < len) {
+ len -= RSTRING(tmp)->len;
+ argv[0] = INT2FIX(len);
+ goto retry;
}
return str;
@@ -1669,6 +2059,17 @@ arg_getc()
}
static VALUE
+arg_readchar()
+{
+ VALUE c = io_getc(file);
+
+ if (NIL_P(c)) {
+ eof_error();
+ }
+ return c;
+}
+
+static VALUE
arg_each_line(argc, argv)
int argc;
VALUE argv;
@@ -1704,68 +2105,116 @@ arg_file()
return file;
}
+static VALUE
+arg_skip()
+{
+ if (next_p != -1) {
+ io_close(file);
+ next_p = 1;
+ }
+ return argf;
+}
+
+static VALUE
+arg_close()
+{
+ io_close(file);
+ if (next_p != -1) {
+ next_p = 1;
+ }
+ gets_lineno = 0;
+ return argf;
+}
+
+static VALUE
+arg_closed()
+{
+ return io_closed(file);
+}
+
+static VALUE
+opt_i_get()
+{
+ if (!inplace) return Qnil;
+ return str_new2(inplace);
+}
+
+static void
+opt_i_set(val)
+ struct RString *val;
+{
+ if (NIL_P(val)) {
+ inplace = 0;
+ return;
+ }
+ Check_Type(val, T_STRING);
+ inplace = val->ptr;
+}
+
extern VALUE mEnumerable;
void
Init_IO()
{
- extern VALUE cKernel;
+ extern VALUE mKernel;
extern VALUE eException;
eEOFError = rb_define_class("EOFError", eException);
id_write = rb_intern("write");
- id_fd = rb_intern("fd");
- id_print_on = rb_intern("print_on");
-
- rb_define_private_method(cKernel, "syscall", f_syscall, -1);
- rb_define_private_method(cKernel, "open", f_open, -1);
- rb_define_private_method(cKernel, "printf", f_printf, -1);
- rb_define_private_method(cKernel, "print", f_print, -1);
- rb_define_private_method(cKernel, "gets", f_gets_method, -1);
- rb_define_private_method(cKernel, "readline", f_readline, -1);
- rb_define_private_method(cKernel, "eof", f_eof, 0);
- rb_define_private_method(cKernel, "getc", f_getc, 0);
- rb_define_private_method(cKernel, "readchar", f_readchar, 0);
- rb_define_private_method(cKernel, "select", f_select, -1);
- rb_define_private_method(cKernel, "ungetc", f_ungetc, 1);
+ rb_define_global_function("syscall", f_syscall, -1);
- rb_define_private_method(cKernel, "readlines", f_readlines, -1);
+ rb_define_global_function("open", f_open, -1);
+ rb_define_global_function("printf", f_printf, -1);
+ rb_define_global_function("print", f_print, -1);
+ rb_define_global_function("gets", f_gets_method, -1);
+ rb_define_global_function("readline", f_readline, -1);
+ rb_define_global_function("eof", f_eof, 0);
+ rb_define_global_function("eof?", f_eof, 0);
+ rb_define_global_function("getc", f_getc, 0);
+ rb_define_global_function("readchar", f_readchar, 0);
+ rb_define_global_function("select", f_select, -1);
+ rb_define_global_function("ungetc", f_ungetc, 1);
- rb_define_method(cKernel, "print_on", f_print_on, 1);
+ rb_define_global_function("readlines", f_readlines, -1);
- rb_define_private_method(cKernel, "`", f_backquote, 1);
- rb_define_private_method(cKernel, "pipe", io_pipe, 0);
+ rb_define_global_function("`", f_backquote, 1);
+ rb_define_global_function("pipe", io_s_pipe, 0);
- rb_define_private_method(cKernel, "p", f_p, 1);
+ rb_define_global_function("p", f_p, 1);
cIO = rb_define_class("IO", cObject);
rb_include_module(cIO, mEnumerable);
- rb_undef_method(CLASS_OF(cIO), "new");
-
- rb_define_singleton_method(cIO, "popen", io_popen, -1);
- rb_define_singleton_method(cIO, "foreach", io_foreach, 1);
+ rb_define_singleton_method(cIO, "new", io_s_new, -1);
+ rb_define_singleton_method(cIO, "popen", io_s_popen, -1);
+ rb_define_singleton_method(cIO, "foreach", io_s_foreach, -1);
+ rb_define_singleton_method(cIO, "readlines", io_s_readlines, -1);
rb_define_singleton_method(cIO, "select", f_select, -1);
FS = OFS = Qnil;
rb_define_hooked_variable("$;", &FS, 0, rb_str_setter);
+ rb_define_hooked_variable("$-F", &FS, 0, rb_str_setter);
rb_define_hooked_variable("$,", &OFS, 0, rb_str_setter);
RS = RS_default = str_new2("\n"); ORS = Qnil;
rb_global_variable(&RS_default);
rb_define_hooked_variable("$/", &RS, 0, rb_str_setter);
+ rb_define_hooked_variable("$-0", &RS, 0, rb_str_setter);
rb_define_hooked_variable("$\\", &ORS, 0, rb_str_setter);
rb_define_variable("$.", &lineno);
rb_define_virtual_variable("$_", lastline_get, lastline_set);
+ rb_define_method(cIO, "clone", io_clone, 0);
+ rb_define_method(cIO, "reopen", io_reopen, 1);
+
rb_define_method(cIO, "print", io_print, -1);
rb_define_method(cIO, "printf", io_printf, -1);
rb_define_method(cIO, "each", io_each_line, -1);
- rb_define_method(cIO, "each_line", io_each_line, 0);
+ rb_define_method(cIO, "each_line", io_each_line, -1);
rb_define_method(cIO, "each_byte", io_each_byte, 0);
rb_define_method(cIO, "syswrite", io_syswrite, 1);
@@ -1777,7 +2226,7 @@ Init_IO()
rb_define_method(cIO, "sync", io_sync, 0);
rb_define_method(cIO, "sync=", io_set_sync, 1);
- rb_define_alias(cIO, "readlines", "to_a");
+ rb_define_method(cIO, "readlines", io_readlines, -1);
rb_define_method(cIO, "read", io_read, -1);
rb_define_method(cIO, "write", io_write, 1);
@@ -1790,6 +2239,7 @@ Init_IO()
rb_define_method(cIO, "<<", io_puts, 1);
rb_define_method(cIO, "flush", io_flush, 0);
rb_define_method(cIO, "eof", io_eof, 0);
+ rb_define_method(cIO, "eof?", io_eof, 0);
rb_define_method(cIO, "close", io_close, 0);
rb_define_method(cIO, "closed?", io_closed, 0);
@@ -1798,7 +2248,8 @@ Init_IO()
rb_define_method(cIO, "tty?", io_isatty, 0);
rb_define_method(cIO, "binmode", io_binmode, 0);
- rb_define_method(cIO, "ioctl", io_ioctl, 2);
+ rb_define_method(cIO, "ioctl", io_ioctl, -1);
+ rb_define_method(cIO, "fcntl", io_fcntl, -1);
rb_stdin = prep_stdio(stdin, FMODE_READABLE);
rb_define_readonly_variable("$stdin", &rb_stdin);
@@ -1817,18 +2268,21 @@ Init_IO()
rb_extend_object(argf, mEnumerable);
rb_define_readonly_variable("$<", &argf);
- rb_define_readonly_variable("$ARGF", &argf);
rb_define_global_const("ARGF", argf);
- rb_define_singleton_method(argf, "each", arg_each_line, 0);
+ rb_define_singleton_method(argf, "fileno", arg_fileno, 0);
+ rb_define_singleton_method(argf, "to_i", arg_fileno, 0);
+ rb_define_singleton_method(argf, "each", arg_each_line, -1);
rb_define_singleton_method(argf, "each_line", arg_each_line, -1);
rb_define_singleton_method(argf, "each_byte", arg_each_byte, 0);
rb_define_singleton_method(argf, "read", arg_read, -1);
rb_define_singleton_method(argf, "readlines", f_readlines, -1);
+ rb_define_singleton_method(argf, "to_a", f_readlines, -1);
rb_define_singleton_method(argf, "gets", f_gets_method, -1);
rb_define_singleton_method(argf, "readline", f_readline, -1);
rb_define_singleton_method(argf, "getc", arg_getc, 0);
+ rb_define_singleton_method(argf, "readchar", arg_readchar, 0);
rb_define_singleton_method(argf, "eof", f_eof, 0);
rb_define_singleton_method(argf, "eof?", f_eof, 0);
rb_define_singleton_method(argf, "ungetc", f_ungetc, 1);
@@ -1836,11 +2290,19 @@ Init_IO()
rb_define_singleton_method(argf, "to_s", arg_filename, 0);
rb_define_singleton_method(argf, "filename", arg_filename, 0);
rb_define_singleton_method(argf, "file", arg_file, 0);
+ rb_define_singleton_method(argf, "skip", arg_skip, 0);
+ rb_define_singleton_method(argf, "close", arg_close, 0);
+ rb_define_singleton_method(argf, "closed?", arg_closed, 0);
filename = str_new2("-");
rb_define_readonly_variable("$FILENAME", &filename);
file = rb_stdin;
rb_global_variable(&file);
+ rb_define_virtual_variable("$-i", opt_i_get, opt_i_set);
Init_File();
+
+#if defined (NT) || defined(DJGPP) || defined(__CYGWIN32__) || defined(__human68k__)
+ atexit(pipe_atexit);
+#endif
}
diff --git a/io.h b/io.h
index bc15d46..05789a9 100644
--- a/io.h
+++ b/io.h
@@ -31,9 +31,8 @@ typedef struct OpenFile {
#define FMODE_READABLE 1
#define FMODE_WRITABLE 2
#define FMODE_READWRITE 3
-#define FMODE_SYNC 4
-
-void io_wrong_type();
+#define FMODE_BINMODE 4
+#define FMODE_SYNC 8
#define GetOpenFile(obj,fp) ((fp) = RFILE(obj)->fptr)
@@ -47,6 +46,8 @@ void io_wrong_type();
fp->finalize = 0;\
} while (0)
+#define GetWriteFile(fptr) (((fptr)->f2) ? (fptr)->f2 : (fptr)->f)
+
FILE *rb_fopen();
#endif
diff --git a/lib/English.rb b/lib/English.rb
new file mode 100644
index 0000000..c7e13be
--- /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 9bb6487..96208a6 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 0000000..260f6e7
--- /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 0000000..432c7b4
--- /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 0000000..d10657b
--- /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 0000000..c5797fd
--- /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 0000000..e934753
--- /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 0000000..34ee2f8
--- /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 5b22899..40ab48d 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 359cb45..fdf27f6 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 0000000..394c66f
--- /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 0000000..823888e
--- /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 9a75393..b802dac 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 3f4612e..1c1dda7 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 0000000..d742a50
--- /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 7c95555..0000000
--- 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 0000000..fd18291
--- /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 c3347b6..30f77dd 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 0000000..c638335
--- /dev/null
+++ b/lib/thwait.rb
@@ -0,0 +1,128 @@
+#
+# thwait.rb -
+# $Release Version: $
+# $Revision: 1.1 $
+# $Date: 1997/08/18 03:13:14 $
+# by Keiju ISHITSUKA(Nippon Rational Inc.)
+#
+# --
+#
+#
+#
+
+require "thread.rb"
+require "e2mmap.rb"
+
+class ThreadsWait
+ RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/RCS/thwait.rb,v 1.1 1997/08/18 03:13:14 keiju Exp keiju $-'
+
+ Exception2MessageMapper.extend_to(binding)
+ def_exception("ErrWaitThreadsNothing", "Wait threads nothing.")
+ def_exception("FinshedThreadsNothing", "finished thread nothing.")
+
+ # class mthods
+ # all_waits
+
+ #
+ # ꤷåɤƽλޤԤ. ƥ졼ȤƸƤФ
+ # ꤷåɤλȥƥ졼ƤӽФ.
+ #
+ def ThreadsWait.all_waits(*threads)
+ tw = ThreadsWait.new(th1, th2, th3, th4, th5)
+ if iterator?
+ tw.all_waits do
+ |th|
+ yield th
+ end
+ else
+ tw.all_waits
+ end
+ end
+
+ # initialize and terminating:
+ # initialize
+
+ #
+ # . Ԥĥåɤλ꤬Ǥ.
+ #
+ def initialize(*threads)
+ @threads = []
+ @wait_queue = Queue.new
+ join_nowait(*threads) unless threads.empty?
+ end
+
+ # accessing
+ # threads
+
+ # Ԥåɤΰ֤.
+ attr :threads
+
+ # testing
+ # empty?
+ # finished?
+ #
+
+ #
+ # Ԥåɤ¸ߤ뤫ɤ֤.
+ def empty?
+ @threads.empty?
+ end
+
+ #
+ # Ǥ˽λåɤ뤫ɤ֤
+ def finished?
+ !@wait_queue.empty?
+ end
+
+ # main process:
+ # join
+ # join_nowait
+ # next_wait
+ # all_wait
+
+ #
+ # ԤäƤ륹åɤɲäԤˤϤ.
+ #
+ def join(*threads)
+ join_nowait(*threads)
+ next_wait
+ end
+
+ #
+ # ԤäƤ륹åɤɲä. Ԥˤʤ.
+ #
+ def join_nowait(*threads)
+ @threads.concat threads
+ for th in threads
+ Thread.start do
+ th = Thread.join(th)
+ @wait_queue.push th
+ end
+ end
+ end
+
+ #
+ # ԤˤϤ.
+ # ԤĤ٤åɤʤ, 㳰ErrWaitThreadsNothing ֤.
+ # nonnlockλˤ, nonblockingĴ٤. ¸ߤʤ, 㳰
+ # FinishedThreadNothing֤.
+ #
+ def next_wait(nonblock = nil)
+ Threads.Wait.fail ErrWaitThreadsNothing if @threads.empty?
+
+ th = @wait_queue.pop(nonblock)
+ @threads.delete th
+ th
+ end
+
+ #
+ # ƤΥåɤλޤԤ. ƥ졼ȤƸƤФ줿,
+ # åɤλ٤, ƥ졼ƤӽФ.
+ #
+ def all_waits
+ until @threads.empty?
+ th = next_wait
+ yield th if iterator?
+ end
+ end
+end
diff --git a/lib/tk.rb b/lib/tk.rb
index 237408a..48a3940 100644
--- a/lib/tk.rb
+++ b/lib/tk.rb
@@ -345,7 +345,7 @@ class TkObject<TkKernel
def configure(slot, value)
if value == FALSE
value = "0"
- elsif value.type == Proc
+ elsif value.kind_of? Proc
value = install_cmd(value)
end
tk_call path, 'configure', "-#{slot}", value
@@ -358,6 +358,61 @@ class TkObject<TkKernel
def bind(context, cmd=Proc.new, args=nil)
_bind path, context, cmd, args
end
+
+ def tk_trace_variable(v)
+ unless v.kind_of?(TkVariable)
+ fail ArgumentError, format("requires TkVariable given %s", v.type)
+ end
+ v
+ end
+ private :tk_trace_variable
+
+ def destroy
+ tk_call 'trace', 'vdelete', @tk_vn, 'w', @var_id if @var_id
+ end
+end
+
+
+class TkVariable
+ include Tk
+ $tk_variable_id = "v00000"
+ def initialize(val="")
+ @id = $tk_variable_id
+ $tk_variable_id = $tk_variable_id.succ
+ tk_call(format('global %s; set %s', @id, @id), val)
+ end
+
+ def id
+ @id
+ end
+
+ def value
+ tk_call(format('global %s; set', @id), @id)
+ end
+
+ def value=(val)
+ tk_call(format('global %s; set %s', @id, @id), val)
+ end
+
+ def to_i
+ Integer(number(value))
+ end
+
+ def to_f
+ Float(number(value))
+ end
+
+ def to_s
+ String(string(value))
+ end
+
+ def inspect
+ format "<TkVariable: %s>", @id
+ end
+
+ def to_a
+ list(value)
+ end
end
class TkWindow<TkObject
@@ -391,6 +446,36 @@ class TkWindow<TkObject
self
end
+ def place(keys = nil)
+ tk_call 'place', epath, *hash_kv(keys)
+ self
+ end
+
+ def unplace(keys = nil)
+ tk_call 'place', 'forget', epath, *hash_kv(keys)
+ self
+ end
+ alias place_forget unplace
+
+ def place_config(keys)
+ tk_call "place", 'configure', epath, *hash_kv(keys)
+ end
+
+ def place_info()
+ ilist = list(tk_call('place', 'info', epath))
+ info = {}
+ while key = ilist.shift
+ info[key[1,-1]] = ilist.shift
+ end
+ return info
+ end
+
+ def place_slaves()
+ list(tk_call('place', 'slaves', epath)).collect { |w|
+ window(w)
+ }
+ end
+
def focus
tk_call 'focus', path
self
@@ -426,7 +511,7 @@ class TkWindow<TkObject
self
end
- def command(cmd)
+ def command(cmd=Proc.new)
configure_cmd 'command', cmd
end
@@ -443,6 +528,7 @@ class TkWindow<TkObject
end
end
$tk_window_list[path] = nil
+ super
end
end
@@ -486,14 +572,7 @@ class TkLabel<TkWindow
tk_call 'label', @path
end
def textvariable(v)
- v = v.id2name unless v.kind_of? String
- vn = @path + v
- vset = format("global {%s}; set {%s} %%s", vn, vn)
- tk_write vset, eval(v).inspect
- trace_var v, proc{|val|
- tk_write vset, val.inspect
- }
- configure 'textvariable', vn
+ configure 'textvariable', tk_trace_variable(v)
end
end
@@ -520,26 +599,7 @@ class TkRadioButton<TkButton
tk_send 'select'
end
def variable(v)
- v = v.id2name unless v.kind_of? String
- if v =~ /^\$/
- v = $'
- else
- fail ArgumentError, "variable must be global(%s)", v
- end
- vn = 'btns_selected_' + v
- trace_var v, proc{|val|
- tk_write 'global %s; set %s %s', vn, val
- }
- @var_id = install_cmd(proc{|name1,|
- val = tk_call(format('global %s; set', name1), name1)
- eval(format("%s = '%s'", v.id2name, val))
- })
- tk_call 'trace', 'variable', vn, 'w', @var_id
- configure 'variable', vn
- end
- def destroy
- tk_call 'trace vdelete', vn, 'w', @var_id
- super
+ configure 'variable', tk_trace_variable(v)
end
end
@@ -678,7 +738,7 @@ class TkMenu<TkWindow
tk_send 'activate', index
end
def add(type, keys=nil)
- tk_send 'add', type, *kv_hash(keys)
+ tk_send 'add', type, *hash_kv(keys)
end
def index(index)
tk_send 'index', index
@@ -686,8 +746,8 @@ class TkMenu<TkWindow
def invoke
tk_send 'invoke'
end
- def insert(index, type, keys=nil)
- tk_send 'add', index, type, *kv_hash(keys)
+ def insert(index, type, *keys)
+ tk_send 'add', index, type, *hash_kv(keys)
end
def post(x, y)
tk_send 'post', x, y
@@ -695,7 +755,7 @@ class TkMenu<TkWindow
def postcascade(index)
tk_send 'postcascade', index
end
- def postcommand(cmd)
+ def postcommand(cmd=Proc.new)
configure_cmd 'postcommand', cmd
end
def menutype(index)
diff --git a/lib/tkcanvas.rb b/lib/tkcanvas.rb
index b0ae8b1..46acd8c 100644
--- a/lib/tkcanvas.rb
+++ b/lib/tkcanvas.rb
@@ -110,11 +110,11 @@ class TkCanvas<TkWindow
def select(*args)
tk_send 'select', *args
end
- def xview(index)
- tk_send 'xview', index
+ def xview(*index)
+ tk_send 'xview', *index
end
- def yview(index)
- tk_send 'yview', index
+ def yview(*index)
+ tk_send 'yview', *index
end
end
@@ -125,12 +125,12 @@ class TkcItem<TkObject
end
@c = parent
@path = parent.path
- if args[-1].type == Hash
+ if args[-1].kind_of? Hash
keys = args.pop
end
@id = create_self(*args)
if keys
- tk_call @path, 'itemconfigure', *hash_kv(keys)
+ tk_call @path, 'itemconfigure', @id, *hash_kv(keys)
end
end
def create_self(*args) end
@@ -226,6 +226,11 @@ class TkcPolygon<TkcItem
tk_call(@path, 'create', 'polygon', *args)
end
end
+class TkcRectangle<TkcItem
+ def create_self(*args)
+ tk_call(@path, 'create', 'rectangle', *args)
+ end
+end
class TkcText<TkcItem
def create_self(*args)
tk_call(@path, 'create', 'text', *args)
@@ -272,7 +277,7 @@ class TkImage<TkObject
def initialize(keys=nil)
@path = $tk_image_id
$tk_image_id = $tk_image_id.succ
- tk_call 'image', @type, @path, *hash_kv(keys)
+ tk_call 'image', 'create', @type, @path, *hash_kv(keys)
end
def height
@@ -302,7 +307,7 @@ end
class TkPhotoImage<TkImage
def initialize(*args)
- @type = 'bitmap'
+ @type = 'photo'
super
end
diff --git a/lib/tkclass.rb b/lib/tkclass.rb
index 10ecc80..17f57f5 100644
--- a/lib/tkclass.rb
+++ b/lib/tkclass.rb
@@ -25,11 +25,13 @@ Bitmap = TkcBitmap
Line = TkcLine
Oval = TkcOval
Polygon = TkcPolygon
+Rectangle = TkcRectangle
TextItem = TkcText
WindowItem = TkcWindow
Selection = TkSelection
Winfo = TkWinfo
Pack = TkPack
+Variable = TkVariable
def Mainloop
Tk.mainloop
diff --git a/lib/tkcore.rb b/lib/tkcore.rb
index 018e140..9fd2c88 100644
--- a/lib/tkcore.rb
+++ b/lib/tkcore.rb
@@ -22,7 +22,7 @@ module Tk
break if wish_path
end
}
- fail 'can\'t find wish' if not wish_path
+ fail 'can\'t find wish' if not wish_path #'
def Tk.tk_exit
if not PORT.closed?
@@ -31,7 +31,8 @@ module Tk
end
end
- PORT = open(format("|%s -n %s", wish_path, File.basename($0)), "w+");
+# PORT = open(format("|%s -n %s", wish_path, File.basename($0)), "w+");
+ PORT = open(format("|%s", wish_path), "w+");
trap "EXIT", proc{Tk.tk_exit}
trap "PIPE", ""
@@ -46,8 +47,8 @@ proc rb_out args {
puts [format %%s $args]
flush stdout
}
-proc rb_ans args {
- if [catch "$args" var] {puts "!$var"} {puts "=$var@@"}
+proc rb_ans arg {
+ if [catch $arg var] {puts "!$var"} {puts "=$var@@"}
flush stdout
}
proc tkerror args { exit }
@@ -85,12 +86,11 @@ after 120000 keepalive'
}
def error_at
- n = 1
- while c = caller(n)
- break if c !~ /tk\.rb:/
- n+=1
+ frames = caller(1)
+ frames.delete_if do |c|
+ c =~ %r!/tk(|core|thcore|canvas|text|entry|scrollbox)\.rb:\d+!
end
- c
+ frames
end
def tk_tcl2ruby(val)
@@ -197,17 +197,21 @@ after 120000 keepalive'
s = "1"
elsif s.kind_of?(TkObject)
s = s.path
+ elsif s.kind_of?(TkVariable)
+ s = s.id
else
s = s.to_s
- s.gsub!(/[{}]/, '\\\\\0')
+ s.gsub!(/["\\\$\[\]]/, '\\\\\0') #"
+ s.gsub!(/\{/, '\\\\173')
+ s.gsub!(/\}/, '\\\\175')
end
- "{#{s}}"
+ "\"#{s}\""
end
}
str += " "
str += args.join(" ")
print str, "\n" if $DEBUG
- tk_write 'rb_ans %s', str
+ tk_write 'rb_ans {%s}', str
while PORT.gets
print $_ if $DEBUG
$_.chop!
@@ -229,10 +233,12 @@ after 120000 keepalive'
$@ = error_at
msg = $'
if msg =~ /unknown option "-(.*)"/
- fail NameError, format("undefined method `%s' for %s(%s)", $1, self,