summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYukihiro Matsumoto <matz@ruby-lang.org>1997-10-02 17:59:18 +0900
committerTakashi Kokubun <takashikkbn@gmail.com>2019-08-17 22:09:32 +0900
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 9281697f25..d2fa79921f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,1192 @@
+Thu Oct 2 17:59:18 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-971002
+
+Wed Oct 1 14:01:49 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * ext/marshal/marshal.c (w_byte): argument must be char.
+
+Wed Oct 1 10:30:22 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * ext/marshal/marshal.c (marshal_dump): try to set binmode.
+
+ * ext/marshal/marshal.c (r_object): forgot to re-regist structs in
+ the object table.
+
+ * eval.c (ruby_options): call Init_ext() before any require()
+ calls by `-r'.
+
+Tue Sep 30 14:51:07 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970930
+
+Fri Sep 30 14:29:22 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * ext/marshal/marshal.c (w_object): marshal dumped core.
+
+Tue Sep 30 10:27:39 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * sample/test.rb: bignum test suits added.
+
+Mon Sep 29 13:37:58 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * ruby.c (forbid_setid): forbid some options in suid mode.
+
+Mon Sep 27 09:53:48 1997 EGUCHI Matsumoto <eguchi@shizuokanet.or.jp>
+
+ * bignum.c: modified for speeding.
+
+Fri Sep 26 18:27:59 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * sample/from.rb: some extensions.
+
+Mon Sep 29 13:15:56 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * parse.y (lhs): no more syntax error on `obj.CONSTANT = value'.
+
+Fri Sep 26 14:41:46 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * eval.c (ruby_run): deferred calling Init_ext() just before eval_node.
+
+Fri Sep 26 13:27:24 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * io.c (io_isatty): forgot to return TRUE value.
+
+Fri Sep 25 11:10:58 1997 EGUCHI Osamu <eguchi@shizuokanet.or.jp>
+
+ * eval.c: use _setjmp/_longjmp instead of setjmp/longjmp on some
+ platforms.
+
+Wed Sep 24 17:43:13 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * string.c (Init_String): String#taint and String#taint? added.
+
+Wed Sep 24 00:57:00 1997 Katsuyuki Okabe <HGC02147@niftyserve.or.jp>
+
+ * X68000 patch.
+
+Tue Sep 23 20:42:30 1997 EGUCHI Osamu <eguchi@shizuokanet.or.jp>
+
+ * parse.y (node_newnode): SEGV on null node setup.
+
+Mon Sep 22 11:22:46 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * ruby.c (ruby_prog_init): wrong safe condition check.
+
+Sun Sep 21 14:46:02 1997 MAEDA shugo <shugo@po.aianet.ne.jp>
+
+ * error.c (exc_inspect): garbage added to classpath.
+
+Fri Sep 19 11:49:23 1997 <matz@netlab.co.jp>
+
+ * version 1.0-970919
+
+ * parse.y (newtok): forgot to adjust buffer size when shrinking
+ the token buffer.
+
+ * enum.c (enum_find): rb_eval_cmd() does not return value.
+
+ * io.c (pipe_open): close fds on pipe exec. fcntl(fd, F_SETFD, 1)
+ no longer used.
+
+Tue Sep 16 17:54:25 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * file.c (f_test): problem if wrong command specified.
+
+ * ruby.c (ruby_prog_init): close stdaux and stdprn for MSDOS.
+
+ * ruby.c (ruby_prog_init): should not add path from environment
+ variable, if ruby is running under seuid.
+
+ * process.c (init_ids): check suid check for setuid/seteuid etc.
+
+Mon Sep 15 00:42:04 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * regex.c (re_compile_pattern): \w{3} and \W{3} did not work.
+
+Thu Sep 11 10:31:48 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970911
+
+ * ext/socket/socket.c (sock_new): no setbuf() for NT.
+
+ * io.c (rb_fopen,rb_fdopen): set close-on-exec for every fd.
+
+Wed Sep 10 15:55:31 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970910
+
+ * ext/marshal/marshal.c (r_bytes0): extra big length check.
+
+Tue Sep 9 16:27:14 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * io.c (pipe_fptr_atexit): clean up popen()'ed fptr.
+
+ * error.c (set_syserr): some system has error code that is bigger
+ than sys_nerr. grrr.
+
+Tue Sep 9 16:27:14 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970909
+
+ * error.c (set_syserr): some system has error code that is bigger
+ than sys_nerr. grrr.
+
+Wed Sep 3 18:11:00 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970903
+
+ * eval.c (f_load): expand path if fname begins with `~'.
+
+Mon Sep 1 13:42:48 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * eval.c (rb_call): alias occured in the module body caused SEGV.
+
+Fri Aug 29 11:10:21 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * parse.y (yylex): spaces can follow =begin/=end.
+
+ * variable.c (find_class_path): look for class_tbl also for
+ unnamed fundamental classes, such as Object, String, etc.
+
+ * variable.c (rb_name_class): can't name class before String class
+ is initilialized.
+
+ * inits.c (rb_call_inits): unrecognized dependency from GC to
+ Array.
+
+ * variable.c (find_class_path): could not find class if Object's
+ iv_tbl is NULL.
+
+Thu Aug 28 13:12:05 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * parse.y (yylex): revised `=begin' skip code.
+
+ * eval.c (is_defined): separated from rb_eval().
+
+Wed Aug 27 11:32:42 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * variable.c (fc_i): some classes/modules does not have iv_tbl.
+
+ * variable.c (find_class_path): avoid inifinite loop.
+
+Tue Aug 26 13:43:47 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * eval.c (rb_eval): undef'ing non-existing method will raise
+ NameError exception.
+
+ * object.c (class_s_new): needed to create metaclass too.
+
+ * eval.c (error_print): no class name print for anonymous class.
+
+ * eval.c (rb_longjmp): proper exception raised if raise() called
+ without arguments, with $! or $@ set.
+
+ * object.c (Init_Object): superclass()'s method argument setting
+ was wrong again.
+
+Mon Aug 25 11:53:11 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * sample/ruby-mode.el (ruby-parse-region): auto-indent now
+ supports "\\" in the strings.
+
+ * struct.c (struct_getmember): new API to get member value from C
+ language side.
+
+Fri Aug 22 14:26:40 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * eval.c (error_print): modified exception print format.
+
+Thu Aug 21 16:10:58 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * sample/ruby-mode.el (ruby-calculate-indent): wrong indent level
+ calculated with keyword operators.
+
+Thu Aug 21 11:55:41 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970821
+
+Thu Aug 21 11:36:58 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * parse.y (arg): ary[0] += 1 cause SEGV
+
+Wed Aug 20 14:24:42 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970820
+
+ * eval.c (rb_call): infinite loop bug
+
+Tue Aug 19 00:15:38 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * version 1.0-970819
+
+ * eval.c (rb_call): did not raise ArgumentError if too many
+ arguments more than optional arguments (without rest arg).
+
+ * eval.c (rb_eval): did not work well for op_asgn2 (attribute
+ self assignment).
+
+Mon Aug 18 09:25:56 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * object.c (inspect_i): did not display T_DATA instance variables.
+
+ * parse.y: provides more accurate line number information.
+
+ * eval.c (thread_value): include value's backtrace information in
+ the variable `$@'.
+
+ * eval.c (f_abort): print backtrace and exit.
+
+Sat Aug 16 00:17:44 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * object.c (class_s_new): do not make subclass of singleton class.
+
+Fri Aug 15 15:49:46 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * eval.c (call_trace_func): block context switch in the trace
+ function.
+
+ * eval.c (rb_eval): clear method cache at class extention.
+
+Fri Aug 15 19:40:43 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * ext/socket/socket.c (Init_socket): small typo caused SEGV.
+
+Tue Aug 12 16:02:18 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * variable.c: option variables: $-0, $-p(readonly), $-v,
+ $-I(load_path), $-a(readonly), $-K, $-d, $-F, $-i, $-l.
+
+ * parse.y (yylex): ignore rd (ruby document) in the code.
+
+Mon Aug 11 12:37:58 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * re.c (Init_Regexp): $-K as alias to the $KCODE.
+
+ * io.c (Init_IO): new virtual variable $-i for the value of -i
+ option.
+
+ * enum.c (Init_Enumerable): include? as alias of member?
+
+Fri Aug 8 11:16:50 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * io.c (io_foreach): now the record separator can be specified.
+
+ * io.c (io_s_readlines): new method to read in whole file (or
+ command output) from path.
+
+ * ext/socket/socket.c (Init_socket): recvfrom did not work.
+
+ * ext/socket/socket.c (sock_send): forgot to check nil for false
+ value.
+
+Thu Aug 7 11:40:01 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * object.c (Init_Object): remove private_attr/public_attr.
+
+Wed Aug 6 14:21:36 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * object.c (mod_attr): forgot to check nil for false value.
+
+Mon Aug 4 11:50:28 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * variable.c (rb_class_path): scan class constants for anonymous
+ classes/modules to make up pathes.
+
+Wed Jul 30 08:45:12 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * eval.c (rb_eval): stop to cache const value in nodes.
+
+Sat Jul 26 03:17:22 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * numeric.c (flo_to_s): wrong .0 at end.
+
+Sat Jul 26 00:36:36 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * eval.c (error_print): always print exception type in the
+ toplevel exception handler.
+
+ * string.c (str_hash): wrong hash value.
+
+Thu Jul 24 11:05:51 1997 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * string.c (uscore_get): proper error message for unset $_.
+
+Wed Jul 23 09:56:55 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * object.c (obj_methods): returns list of method names of the
+ specified object.
+
+ * class.c (mod_instance_methods): returns list of method names of
+ the class instnace.
+
+Fri Jul 11 22:38:55 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * object.c (class_superclass): returns class's superclass
+ itself. (1.1)
+
+ * object.c (obj_type): returns object's class itself. (1.1)
+
+ * class.c (mod_included_modules): list included modules.
+
+ * object.c (class_superclass): raises error for Object.
+
+Thu Jul 3 09:54:02 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (SETUP_ARGS): save source position, remove nd_line().
+
+ * eval.c (rb_call): replace modulo by bit-masking.
+
+ * eval.c (POP_SCOPE): force recycle scope object to reduce gc rate.
+
+ * gc.c (obj_free): aboid calling run_final() when no finalizer is set.
+
+ * eval.c (PUSH_VARS): do not allocate the dynamic scope's end-mark
+ object.
+
+Wed Jul 2 14:25:07 1997 KIMURA Koichi <kkimura@pure.cpdc.canon.co.jp>
+
+ * Native mswin32 support.
+
+Tue Jul 1 09:59:00 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970701
+
+ * parse.y (mrhs): allow rest-star(*) in right hand side.
+
+Tue Jun 24 19:04:31 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970624
+
+Sat Jun 20 22:22:51 1997 Michio "Karl" Jinbo <karl@marcer.nagaokaut.ac.jp>
+
+ * eval.c: freebsd 3.0 <sys/select.h> support.
+
+Fri Jun 20 01:24:45 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970620
+
+ * gc.c: eliminate uninitilalized field of Hash, Array etc., to
+ avoid dumping core.
+
+Thu Jun 19 01:29:44 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970619
+
+ * string.c (str_split_method): wrong limit.
+
+Sat Jun 14 01:54:16 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * class.c (rb_singleton_class): no singleton for special
+ constants (now raises exception).
+
+ * eval.c (ruby_init): cbase in TOPLEVEL_BINDING need to be
+ initialized.
+
+Sat Jun 14 01:01:16 1997 maeda shugo <shugo@po.aianet.ne.jp>
+
+ * array.c (sort_2): wrong comparison.
+
+Sat Jun 14 00:53:44 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * hash.c (hash_foreach): safe iteration.
+
+Fri Jun 13 14:04:56 1997 Michio "Karl" Jinbo <karl@marcer.nagaokaut.ac.jp>
+
+ * configure.in: -Bshareable option for netbsd.
+
+Fri Jun 13 01:16:22 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * io.c (pipe_open): call io_unbuffered() only for writable pipes.
+
+Thu Jun 12 01:14:15 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970612
+
+ * ext/socket/socket.c (sock_new): use io_unbuffered().
+
+ * ext/marshal/marshal.c (w_long): compact long format, which
+ supports 64 bit architectures (unless longs are >32 bit size).
+
+ * ext/marshal/marshal.c: allows recursive data for marshaling.
+
+ * parse.y (rb_intern): raise exception for non-internable string.
+
+ * ext/marshal/marshal.c (marshal_load): allows direct loading from
+ strings.
+
+ * ext/marshal/marshal.c (marshal_dump): allows direct dump to strings.
+
+ * ext/marshal/marshal.c (marshal_dump): interface changed.
+
+Wed Jun 11 18:26:00 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * gc.c (rb_newobj): remove needless memset().
+
+Mon Jun 9 13:03:43 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (rb_eval): reduce condition checks from while/until loop.
+
+ * eval.c (rb_eval): wrong jump point for `next'.
+
+Fri Jun 6 11:47:39 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ruby.c (ruby_set_argv): initialize dln_argv0 for dln_a_out.
+
+ * ext/socket/socket.c (open_unix): display path name for exceptions.
+
+ * ruby.c (proc_options): option -S did not work well.
+
+Fri May 30 02:14:44 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970530
+
+ * eval.c (eval): set $! properly if exception raised in eval().
+
+ * io.c (io_write): now handles non T_FILE object.
+
+ * io.c (io_defset): $< can be anything which has `write' method.
+
+Thu May 29 15:40:22 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (eval): $@ is always an array (not string).
+
+ * pack.c (pack_unpack): avoid corrupting memory for unexpected
+ input strings.
+
+Wed May 28 12:46:13 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970528
+
+ * process.c (rb_waitpid): do not block other threads.
+
+Tue May 27 12:02:31 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (ruby_init): split initialize and processing command line
+ options.
+
+ * ruby.c (ruby_options): ruby_init(0, 0, envp) dumps core.
+
+Tue May 20 18:59:45 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * variable.c (rb_ivar_set): invalid instance variable access for
+ built-in object raises TypeError.
+
+Fri May 16 17:32:21 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970516
+
+ * dir.c (push_globs): was freeing non heap pointer.
+
+ * gc.c: remove some duplicated prototypes.
+
+ * ext/kconv/kconv.c: fix prototypes.
+
+Fri May 9 11:38:59 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970509
+
+ * gc.c (obj_free): avoid free(NULL).
+
+ * eval.c (rb_check_safe_str): argument missing for TypeError().
+
+Thu May 8 01:14:28 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * file.c (file_s_dirname): need to return "." for path without
+ slashes.
+
+Wed May 7 19:18:48 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * process.c (f_fork): child processe does not inherit parent's
+ itimer setting on linux. call setitimer() again in the child
+ process.
+
+Sat May 3 02:49:43 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ext/curses/curses.c: modified for portability and add to the
+ standard distribution.
+
+Wed Apr 30 00:34:00 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * file.c (file_s_size): returns 0 for empty files (not FALSE).
+
+Fri Apr 25 02:17:50 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970425
+
+ * eval.c (f_load): free unused name-table.
+
+ * eval.c (f_load): copy local variable name-table.
+
+ * gc.c (obj_free): avoid free(NULL).
+
+ * eval.c (rb_eval): forgot to make link from the scope object to
+ NODE_SCOPE. It may crash the interpreter.
+
+Thu Apr 24 00:35:09 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * random.c (f_srand): save old seed anyway. srand() returns no
+ value on some systems.
+
+ * gc.c (obj_free): avoid double free of the local variable name
+ table.
+
+ * parse.y (top_local_setup): modify realloc to handle offset.
+
+Tue Apr 22 12:58:26 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970422
+
+Thu Apr 17 00:40:51 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * configure.in (rb_cv_bsdpgrp): proper check for BSD
+ setpgrp/setpgrp.
+
+Wed Apr 16 16:14:02 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (proc_call): proc called in other thread must be orphan.
+
+Tue Apr 15 10:46:31 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970415
+
+ * gc.c (obj_free): NODE_SCOPE marked from SCOPE object.
+
+ * gc.c (gc_mark): some nodes marked wrong.
+
+ * process.c (proc_getpgrp): wrong argument
+
+Fri Apr 14 18:32:42 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970414
+
+Fri Apr 12 01:20:12 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ruby.h: String pointer changed to unsigned char.
+
+Fri Apr 11 10:27:29 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970411
+
+ * Makefile.in: create libruby.a before linking ruby.
+
+ * string.c (str_strip_bang): >0x80 characters for isspace().
+
+ * eval.c (proc_call): set safe-level temporally
+
+ * eval.c (proc_s_new): save safe-level in the proc context.
+
+ * eval.c (rb_eval): no class/module extention in safe mode.
+
+Thu Apr 10 02:10:41 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * gc.c (gc_mark): remove some pointer checks for speeding up.
+
+ * ruby.c (ruby_options): set $0 temporally for -r option.
+
+ * eval.c: built-in security feature.
+
+ * gc.c (gc_sweep): do not free nodes during compile.
+
+ * parse.y (yycompile): set flag when compiling.
+
+Wed Apr 9 10:19:02 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ruby.c: forgot to include <ctype.h> for isspace().
+
+ * file.c: provide S_ISREG for some platforms.
+
+ * io.c (Init_IO): added some $< operations.
+
+ * lib/ping.rb: check host upness using TCP echo.
+
+Tue Apr 8 00:10:15 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * io.c (arg_read): bug with 0 length input.
+
+Mon Apr 7 11:36:16 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ext/fcntl/fcntl.c: module for fcntl constants.
+
+ * eval.c (rb_alias): bug when original was an alias.
+
+ * parse.y (primary): syntax to access singleton class.
+
+ * eval.c (mod_public_method): method's to specify visibitily of
+ the class methods. make_method_{public,private} removed.
+
+Fri Apr 4 21:43:57 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970404
+
+ * gc.c (obj_free): finalizer added for experiment.
+
+Thu Apr 3 02:12:31 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (thread_schedule): make Fatal rise on main_thread on
+ deadlocks.
+
+ * eval.c (thread_join): raise ThreadError instead of Fatal, in
+ case of deadlock.
+
+ * regex.c (re_compile_fastmap): uninitialized local variable.
+
+ * parse.y (parse_regx): new option //[nes] to specify character
+ code for regexp literals. Last specified code option is valid.
+
+ * re.c (reg_s_new): addtional 3rd argument to specify compiled
+ regexp's character code.
+
+ * re.c (reg_new_1): regexp character code can be specified for
+ each regexp object.
+
+Wed Apr 2 14:51:06 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (thread_create): handle uncaught throw.
+
+ * eval.c (thread_create): halt on some deadlock conditions.
+
+ * regex.c (is_in_list): wrong result for non-mbc higher-byte
+ characters.
+
+ * regex.c (re_match): wrong skip for multi-byte characters.
+
+ * regex.c (re_compile_fastmap): wrong fastmap in non-mbc mode.
+
+ * hash.c (Init_Hash): hash compatible features added to ENV.
+
+Tue Apr 1 15:24:06 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (obj_extend): remove Object#extend as an iterator which
+ is in experimental state, since it unveils internal singleton
+ classes.
+
+Mon Mar 31 14:29:39 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970331
+
+Sun Mar 30 19:40:57 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * parse.y (terms): avoided win32 gcc's optimization bug.
+
+Sat Mar 29 11:21:58 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * struct.c (make_struct): St[val,..] creates new structure.
+
+Fri Mar 28 11:24:51 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (obj_make_private): new method make_method_{public,private}
+ to change visibility of singleton methods.
+
+ * regex.c (re_compile_pattern): enables numeric literal >= 0x80 in
+ the character class.
+
+ * regex.c (re_compile_pattern): enabled numeric literal >= 0x80,
+ in multibyte mode.
+
+ * regex.c (re_compile_fastmap): modified exantn and charset(_not)
+ to set fastmap for higher bytes properly.
+
+ * regex.c (is_in_list): now matches numeric literals.
+
+Thu Mar 27 13:34:20 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * pack.c (pack_unpack): extra null byte after unpacked string.
+
+Wed Mar 26 15:20:34 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * regex.c (re_compile_pattern): register numbers must be fit in a
+ byte (0 <= regnum <= 0xff).
+
+ * regex.c (re_compile_fastmap): forgot to set mbchar map for
+ charset_not if RE_MBCTYPE is on.
+
+ * regex.c (re_compile_pattern): set list bits for multi-byte
+ characters for \W, \S, \D in range expression.
+
+ * object.c (obj_is_kind_of): defined that nil itself is kind of
+ nil. TRUE is kind of TRUE, FALSE is kind of FALSE likewise.
+ This change makes `obj.kind_of?(eval(obj.type))' always true.
+
+Tue Mar 25 14:08:43 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * lib/English.rb: provides nicer English alias for the variables.
+
+ * parse.y (expr): alias $var1 $var2 makes alias of the global
+ variable.
+
+Mon Mar 24 18:23:20 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970324
+
+Thu Mar 20 22:04:59 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (mod_modfunc): forget to clear method cache.
+
+Wed Mar 19 17:06:55 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * parse.y (program): set methods' default private/public status
+ correctly under eval().
+
+ * eval.c (eval): set the_class correctly while evaluating string.
+
+Tue Mar 18 12:23:53 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (eval): yield can be called from eval().
+
+ * version 1.0-970318
+
+ * parse.y (program): regexp in condition expression should do
+ matching operation with $_.
+
+ * re.c (reg_regsub): wrong substitution.
+
+Fri Mar 14 14:36:28 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * hash.c (hash_invert): returns value to key mapping of the
+ associative array.
+
+ * ext/socket/extconf.rb: set environment variable SOCKS_SERVER to
+ compile with libsocks.a.
+
+ * ext/socket/socket.c (socks_s_open): SOCKSsocket class to access
+ internet via SOCKS library.
+
+ * sprintf.c (f_sprintf): unsigned formats display leading double
+ dots for imaginary sequence of signed bit to the left.
+
+ * sprintf.c (f_sprintf): correct width and precision formatting
+ for big integers.
+
+ * parse.y (yylex): enables negative hex/octal numbers and `_' in
+ non-decimal numbers.
+
+ * sprintf.c (f_sprintf): %u added for unsigned decimal format.
+
+Thu Mar 13 10:24:27 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * sprintf.c (f_sprintf): wrong output for bignums.
+
+ * array.c (ary_reverse_each): iterates in reverse order.
+
+ * pack.c (pack_unpack): L unpacked signed long.
+
+ * io.c (f_backquote): now returns an empty string for no output.
+
+Wed Mar 12 10:20:30 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ext/socks/socks.c: socket module with socks library.
+
+Mon Mar 10 20:44:22 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * re.c (reg_regsub): \& for substitution. \`, \', and \+ are
+ avaiable also.
+
+Thu Mar 6 01:47:03 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970306
+
+ * sample/rubydb.el (gud): ruby debugger emacs interface
+
+ * lib/debug.rb: ruby debugger
+
+ * parse.y (exprs): more accurate line number display.
+
+Wed Mar 5 21:31:46 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970305
+
+Tue Mar 4 12:28:32 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ruby.c (proc_options): search through RUBYPATH and PATH for
+ option -S.
+
+Mon Mar 3 22:44:55 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (thread_status): returns nil for exception terminated
+ threads.
+
+ * eval.c (thread_value): re-raise exceptions.
+
+Sat Mar 1 00:59:47 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (rb_eval): restore $! value after rescue clause, to
+ re-raise exceptions correctly.
+
+Fri Feb 28 16:43:38 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970228
+
+Thu Feb 27 11:23:41 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (rb_yield_0): redo raises exception
+
+ * eval.c (thread_schedule): bug in interrupt handling by rescue.
+
+Wed Feb 26 00:55:36 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (eval): forgot to restore dynamic local variable
+ bindings.
+
+Tue Feb 25 11:22:08 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ext/aix_ld.rb: AIX dynamic load support (not tested).
+
+ * eval.c (rb_eval): wrong return value for defined? super.
+
+ * error.c (exception): more error check.
+
+ * re.c (reg_regsub): wrong substitution when sub expanded to null
+ string.
+
+Fri Feb 21 13:01:47 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970221
+
+ * eval.c (f_require): volatile added. register variable was
+ recycled, so that GC did not mark that variable.
+
+ * object.c (Init_Object): forget to mark main object (was mostly
+ ok, but made trouble with early GC.)
+
+Thu Feb 20 11:50:50 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970220
+
+Thu Feb 20 11:25:50 1997 Yasuo OHBA <jammy@shljapan.co.jp>
+
+ * lib/date.rb: update
+
+Thu Feb 20 08:25:57 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * parse.y (yylex): forgot tokfix() before rb_intern().
+
+ * lib/tk.rb (TkVariable): give up using trace_var.
+
+Wed Feb 19 00:24:35 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970219
+
+ * pack.c (pack_pack): packed by null for A specifier. must be
+ space filled.
+
+ * pack.c (pack_unpack): bug in skipping spaces
+
+ * gc.c (xmalloc): garbage collect for every 4 Meg. allocation.
+
+ * string.c (str_split_method): limit worked wrong way.
+
+ * io.c (io_gets_method): misunderstand 0xff in binary files when
+ $/ == nil.
+
+ * re.c (reg_regsub): re-implement.
+
+ * ext/socket/socket.c (thread_connect): remove O_NONBLOCK, which
+ is not defined on some platform like NeXT.
+
+Mon Feb 17 13:08:30 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970217
+
+ * object.c (mod_eqq): === extended for subclass check (to use case
+ as typecase).
+
+Sat Feb 15 02:07:22 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * regex.c (re_compile_pattern): wrong match backref at end of pattern.
+
+ * io.c (arg_read): now works beyond end of file.
+
+Thu Feb 13 16:21:24 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * parse.y (expr): return/yield now accept normal argument format.
+
+ * parse.y (yylex): a star in `yield *x' must not be multiplication
+ operator.
+
+Wed Feb 12 15:06:44 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * time.c (time_plus): bug in simple addition.
+
+ * eval.c (thread_raise): raise exceptions from outside.
+
+ * eval.c (Init_Thread): Thread#alive? -- alias for Thread#status.
+
+Mon Feb 10 00:38:55 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * ruby.h (Data_Make_Struct): rename macros.
+
+Sun Feb 8 11:48:13 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * io.c (f_syscall): argument offset was wrong.
+
+Fri Feb 7 18:01:17 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970207
+
+ * eval.c: add volatiles to avoid variable crobbering by longjmp().
+
+ * eval.c (f_raise): 1st argument can be the GlobalExit object now.
+
+ * array.c (ary_unshift): no longer accept more than 2 args.
+
+ * eval.c (f_raise): bug if 2nd argument is the exception.
+
+Tue Feb 4 00:37:29 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970204
+
+ * eval.c (eval): check compile errors by nerrs.
+
+ * eval.c (rb_eval): check syntax error by nerrs, not by the return
+ value, which may be NULL.
+
+ * eval.c (compile): Do not clear errinfo.
+
+Mon Feb 3 10:13:06 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (obj_extend): move real inclusion to Module#extend_object
+ to allow redfinition.
+
+ * object.c (Init_Object): Kernel class is now Module. Object class
+ became the true root class.
+
+ * object.c (obj_inspect): remove useless buffer.
+
+ * hash.c (any_cmp): disable interrupts and context switching.
+
+ * st.c: remove ALLOW_INTS to disable interrupt during operations.
+
+Fri Jan 31 22:10:08 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * hash.c (hash_rehash): re-register all key-value.
+
+Thu Jan 30 02:14:49 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * io.c (io_reopen): re-implement according to clone() way.
+
+ * io.c (io_clone): copy IO object.
+
+ * struct.c (struct_eql): compare elements by eql?.
+
+ * io.c (io_mode_flags): detect "rb", "wb" etc.
+
+ * io.h (FMODE_BINMODE): added.
+
+ * ext/socket/socket.c (Init_socket): undef BasicSocket.new
+
+ * file.c (Init_File): File.new(path[,mode])
+
+ * io.c (Init_IO): IO.new(fd[,mode])
+
+ * eval.c (rb_method_boundp): forgot to enable priv argument.
+
+ * object.c (Init_Object): remove `=~' from Kernel class.
+
+ * ext/socket/socket.c (open_inet): initialize sockaddr before
+ calling bind(2).
+
+ * sample/ruby-mode.el (ruby-calculate-indent): skip comment lines
+
+Wed Jan 29 18:43:22 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (Init_Thread): DEFER_INTS during initializing threads.
+
+ * hash.c (Init_Hash): Hash#eql? checks for object identity.
+
+ * eval.c (thread_set_critical): wrong value assigned.
+
+Mon Jan 27 16:10:51 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * io.c (io_print): remove print_on().
+
+ * eval.c (f_missing): proper error message for undefined method
+ without argument
+
+Sat Jan 25 23:32:32 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * string.c (str_sub_s): false alert - sub() does not modify string.
+
+ * array.c (ary_times): negative multiplication detected
+
+ * string.c (str_times): negative multiplication detected
+
+Fri Jan 24 10:51:39 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * time.c (time_arg): month -> 0 == "jan" == "1" == "01", little bit
+ confusing but wanted to conform japanese style.
+
+ * version 1.0-970124
+
+Fri Jan 24 09:52:49 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * util.c (_fixpath): supports SJIS filenames on DJGPP.
+
+Thu Jan 23 16:52:06 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * README.EXT: update. partially translated into English.
+
+ * ext/extmk.rb.in: inherit $LDFLAGS to the final link.
+
+ * ext/socket/socket.c (Init_socket): add various constants.
+
+Mon Jan 23 11:40:59 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * eval.c (Init_Thread): allocate main_thread first to avoid crash.
+
+Thu Jan 23 02:09:26 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * gc.c (ObjectSpace): API modified. each_object method will do all
+ the iteration.
+
+ * eval.c (proc_call): wrong return from nested lambda.
+
+ * ext/GD/GD.c: debugged.
+
+Wed Jan 22 16:12:25 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970122
+
+ * gc.c (gc_mark): forgot to mark match->str.
+
+ * ext/GD/GD.c: GD interface module.
+
+ * eval.c (PUSH_BLOCK): wrong value pushed as the block level.
+
+Mon Jan 20 14:01:31 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (thread_run): no context switch in the critical section.
+
+Mon Jan 20 09:40:59 1997 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
+
+ * utils.c: supports 8+3 filenames
+
+Sat Jan 18 01:23:03 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970118
+
+ * regex.c (PATFETCH): need cast to unsigned char.
+
+ * io.c (io_ctl): bug in case when arg is not a string.
+
+ * lib/tk.rb: forgot that Kernel#type returns the class name now.
+
+ * regex.c (re_search): "abc\n" =~ "^$" should not match.
+
+Fri Jan 17 12:31:37 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * version 1.0-970117
+
+ * ruby.c (ruby_options): constant PLATFORM, which is in the {cpu}-{os}
+ form, defined.
+
+ * configure.in: platform infomation embedded in the interpreter.
+
+ * regex.c (re_search): /^$/ did not match to "" by wrong exit condition.
+
+ * lib/thread.rb: re-write Mutex/Queue based on Thread.critical.
+
+ * eval.c (thread_set_critical): remove Thread.exclusive, add
+ Thread.critical = TRUE/FALSE instead.
+
+ * re.c (reg_search): re-compile pattern if needed
+
+ * regex.c (PATFETCH): do translate at compile time
+
+Thu Jan 16 00:49:10 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * gc.c (gc_mark_frame): forgot to mark frame->cbase.
+
+ * regex.c (re_compile_pattern): /a$|b)/ causes error.
+
+ * regex.c (re_compile_pattern): /(^|b)/ causes error.
+
+ * version 1.0-970116
+
+ * re.c (Init_Regexp): set RE_CONTEXTUAL_INVALID_OPS flag.
+
+Tue Jan 14 02:09:06 1997 Yukihiro Matsumoto <matz@caelum.co.jp>
+
+ * eval.c (proc_call): Proc#call򥤥ƥ졼ȤƸƤб
+
+ * configure.in: nextstepб
+
+ * eval.c (rb_eval): a[b]=c̵̤Ƥʤ
+
+ * eval.c (f_send): ƥ졼ȤƸƤФ줿饤ƥ졼Ȥƥ᥽
+ ɤƤ֡
+
+ * string.c (str_new4): matchͭѤؿ
+
+ * re.c (reg_search): matchμ(ʸ)ޥåԤäʸ
+ copy-on-writeǶͭ
+
+ * string.c (str_hash): toupper򤫤郎äƤ
+
+ * array.c (sort_2): 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 3b0ba3e0d0..587294b705 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -66,21 +66,36 @@ version.c
version.h
ext/Setup
ext/Setup.dj
+ext/Setup.nt
+ext/Setup.x68
ext/extmk.rb.in
+ext/extmk.rb.nt
+ext/aix_ld.rb
+lib/English.rb
lib/base64.rb
lib/cgi-lib.rb
lib/complex.rb
+lib/date.rb
+lib/debug.rb
+lib/e2mmap.rb
+lib/e2mmap1_0.rb
lib/find.rb
+lib/finalize.rb
+lib/ftplib.rb
lib/getopts.rb
lib/jcode.rb
lib/mailread.rb
lib/mathn.rb
+lib/matrix.rb
+lib/mutex_m.rb
lib/observer.rb
lib/parsearg.rb
lib/parsedate.rb
+lib/ping.rb
lib/rational.rb
-lib/safe.rb
+lib/sync.rb
lib/thread.rb
+lib/thwait.rb
lib/tk.rb
lib/tkcore.rb
lib/tkcanvas.rb
@@ -89,15 +104,19 @@ lib/tkentry.rb
lib/tkscrollbox.rb
lib/tktext.rb
lib/tkthcore.rb
+lib/tracer.rb
missing/alloca.c
missing/crypt.c
+missing/dir.h
missing/dup2.c
+missing/file.h
missing/flock.c
missing/memmove.c
missing/mkdir.c
missing/nt.c
missing/nt.h
missing/setenv.c
+missing/strcasecmp.c
missing/strdup.c
missing/strerror.c
missing/strftime.c
@@ -107,7 +126,7 @@ missing/strtoul.c
sample/biorhythm.rb
sample/cbreak.rb
sample/clnt.rb
-sample/dbm.rb
+sample/dbmtest.rb
sample/dir.rb
sample/eval.rb
sample/export.rb
@@ -126,7 +145,7 @@ sample/less.rb
sample/list.rb
sample/list2.rb
sample/list3.rb
-sample/marshal.rb
+sample/mrshtest.rb
sample/mkproto.rb
sample/mpart.rb
sample/observ.rb
@@ -140,6 +159,8 @@ sample/rcs.dat
sample/rcs.rb
sample/regx.rb
sample/ruby-mode.el
+sample/rubydb2x.el
+sample/rubydb3x.el
sample/sieve.rb
sample/svr.rb
sample/test.rb
@@ -154,3 +175,11 @@ sample/tktimer.rb
sample/trojan.rb
sample/tsvr.rb
sample/uumerge.rb
+win32/Makefile
+win32/config.h
+win32/ntsetup.bat
+win32/ruby.def
+x68/fconvert.c
+x68/select.c
+x68/_dtos18.c
+x68/_round.c
diff --git a/Makefile.in b/Makefile.in
index aa018968ff..ee0ac1fcfc 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -3,32 +3,40 @@ SHELL = /bin/sh
#### Start of system configuration section. ####
srcdir = @srcdir@
-VPATH = @srcdir@
+VPATH = @srcdir@:@srcdir@/missing
CC = @CC@
YACC = @YACC@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
-PURIFY=
+PURIFY =
@SET_MAKE@
-CFLAGS = @CFLAGS@ -I.
-STATIC = @STATIC@
-LDFLAGS = $(CFLAGS) @LDFLAGS@
-LIBS = -lm @LIBS@ $(EXTLIBS)
+CFLAGS = @CFLAGS@ -I@srcdir@
+LDFLAGS = @STATIC@ $(CFLAGS) @LDFLAGS@
+LIBS = @LIBS@ $(EXTLIBS)
MISSING = @LIBOBJS@ @ALLOCA@
+program_transform_name = -e @program_transform_name@
+RUBY_INSTALL_NAME = `t='$(program_transform_name)'; echo ruby | sed $$t`
+
prefix = @prefix@
-binprefix =
exec_prefix = @exec_prefix@
-bindir = $(exec_prefix)/bin
-libdir = @prefix@/lib/ruby
+bindir = @bindir@
+libdir = @libdir@/$(RUBY_INSTALL_NAME)
+
+binsuffix = @binsuffix@
#### End of system configuration section. ####
+
+LIBRUBY = libruby.a
+
EXTOBJS = dmyext.o
+MAINOBJ = main.o
+
OBJS = array.o \
bignum.o \
class.o \
@@ -45,7 +53,6 @@ OBJS = array.o \
hash.o \
inits.o \
io.o \
- main.o \
math.o \
numeric.o \
object.o \
@@ -66,41 +73,44 @@ OBJS = array.o \
util.o \
variable.o \
version.o \
- $(MISSING) \
- $(EXTOBJS)
-
-PROGRAM = miniruby
+ $(MISSING)
-all: extruby
-
-extruby: miniruby ext/Setup
+all: miniruby$(binsuffix) @srcdir@/ext/Setup
@if test -z "$$UNDER_EXTMAKE_RB"; \
then echo "Compiling ext modules"; \
UNDER_EXTMAKE_RB=yes; export UNDER_EXTMAKE_RB; \
cd ext; ../miniruby ./extmk.rb @EXTSTATIC@; fi
-$(PROGRAM): $(OBJS)
- @rm -f $(PROGRAM)
- $(PURIFY) $(CC) $(STATIC) $(LDFLAGS) $(OBJS) $(LIBS) -o $(PROGRAM)
+miniruby$(binsuffix): $(OBJS) $(MAINOBJ) $(EXTOBJS)
+ @rm -f $@
+ $(PURIFY) $(CC) $(LDFLAGS) $(MAINOBJ) $(OBJS) $(EXTOBJS) $(LIBS) -o miniruby
+
+ruby$(binsuffix): $(LIBRUBY) $(MAINOBJ) $(EXTOBJS)
+ @rm -f $@
+ $(PURIFY) $(CC) $(LDFLAGS) $(MAINOBJ) $(EXTOBJS) $(LIBRUBY) $(LIBS) -o ruby
+
+$(LIBRUBY): $(OBJS) dmyext.o
+ @AR@ rcu $(LIBRUBY) $(OBJS) dmyext.o
+ @-@RANLIB@ $(LIBRUBY) 2> /dev/null || true
-install:; $(INSTALL_PROGRAM) ruby $(bindir)/ruby
- @-@STRIP@ $(bindir)/ruby
+install:; $(INSTALL_PROGRAM) ruby$(binsuffix) $(bindir)/$(RUBY_INSTALL_NAME)$(binsuffix)
+ @-@STRIP@ $(bindir)/$(RUBY_INSTALL_NAME)$(binsuffix)
@test -d $(libdir) || mkdir $(libdir)
cd ext; ../miniruby ./extmk.rb install
- @for rb in `grep '^lib/' MANIFEST`; do \
- $(INSTALL_DATA) $$rb $(libdir); \
+ @for rb in `grep '^lib/' @srcdir@/MANIFEST`; do \
+ $(INSTALL_DATA) @srcdir@/$$rb $(libdir); \
done
-clean:; @rm -f $(OBJS)
- @rm -f ext/extinit.c ext/extinit.o
+clean:; @rm -f $(OBJS) $(LIBRUBY) $(MAINOBJ)
+ @rm -f ext/extinit.c ext/extinit.o dmyext.o
cd ext; ../miniruby ./extmk.rb clean
realclean: clean
- @rm -f Makefile ext/extmk.rb
+ @rm -f Makefile ext/extmk.rb ext/config.cache parse.c
@rm -f config.cache config.h config.log config.status
- @rm -f core ruby miniruby *~
+ @rm -f core ruby$(binsuffix) miniruby$(binsuffix) parse.c *~ *.core gmon.out
-test:; @-./ruby sample/test.rb > ./ruby_test 2>&1; \
+test:; @-./ruby @srcdir@/sample/test.rb > ./ruby_test 2>&1; \
if grep '^end of test' ./ruby_test > /dev/null; then \
echo "test succeeded"; \
else \
@@ -113,47 +123,57 @@ test:; @-./ruby sample/test.rb > ./ruby_test 2>&1; \
.c.o:
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
-alloca.o: missing/alloca.c
- $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/alloca.c
+parse.c: parse.y
+ $(YACC) $<
+ mv -f y.tab.c parse.c
+
+alloca.o: @srcdir@/missing/alloca.c
+ $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/alloca.c
+
+crypt.o: @srcdir@/missing/crypt.c
+ $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/crypt.c
+
+dup2.o: @srcdir@/missing/dup2.c
+ $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/dup2.c
-crypt.o: missing/crypt.c
- $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/crypt.c
+flock.o: @srcdir@/missing/flock.c
+ $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/flock.c
-dup2.o: missing/dup2.c
- $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/dup2.c
+memmove.o: @srcdir@/missing/memmove.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/memmove.c
-flock.o: missing/flock.c
- $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/flock.c
+mkdir.o: @srcdir@/missing/mkdir.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/mkdir.c
-memmove.o: missing/memmove.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/memmove.c
+setenv.o: @srcdir@/missing/setenv.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/setenv.c
-mkdir.o: missing/mkdir.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/mkdir.c
+strcasecmp.o: @srcdir@/missing/strcasecmp.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strcasecmp.c
-setenv.o: missing/setenv.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/setenv.c
+strerror.o: @srcdir@/missing/strerror.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strerror.c
-strerror.o: missing/strerror.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/strerror.c
+strdup.o: @srcdir@/missing/strdup.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strdup.c
-strdup.o: missing/strdup.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/strdup.c
+strftime.o: @srcdir@/missing/strftime.c
+ $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strftime.c
-strftime.o: missing/strftime.c
- $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/strftime.c
+strstr.o: @srcdir@/missing/strstr.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strstr.c
-strstr.o: missing/strstr.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/strstr.c
+strtol.o: @srcdir@/missing/strtol.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strtol.c
-strtol.o: missing/strtol.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/strtol.c
+strtoul.o: @srcdir@/missing/strtoul.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/strtoul.c
-strtoul.o: missing/strtoul.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/strtoul.c
+nt.o: @srcdir@/missing/nt.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/nt.c
-nt.o: missing/nt.c
- $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/nt.c
+x68.o: @srcdir@/missing/x68.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c @srcdir@/missing/x68.c
# Prevent GNU make v3 from overflowing arg limit on SysV.
.NOEXPORT:
diff --git a/README b/README
index debf3e4b1c..6583bc889f 100644
--- a/README
+++ b/README
@@ -23,16 +23,7 @@ perl). It is simple, straight-forward, and extensible.
The ruby distribution can be found on
- ftp://ftp.caelum.co.jp/pub/lang/ruby/
-
-** by mail
-
-Send the mail which subject is 'send' to the address below.
-
- ruby-archive@caelum.co.jp
-
-You will receive the uuencoded gzipped tar file of the newest ruby
-distribution.
+ ftp://ftp.netlab.co.jp/pub/lang/ruby/
* How to compile and install
@@ -61,13 +52,13 @@ the error log and machine/OS type, to help others.
* Copying
-Ruby is copyrighted by Yukihiro Matsumoto <matz@caelum.co.jp>.
+Ruby is copyrighted by Yukihiro Matsumoto <matz@ruby.club.co.jp>.
This source is distributed under the conditions blow:
1. You may make and give away verbatim copies of the source form of
the software without restriction, provided that you do not modify
- the original distribution file.
+ the original distribution files.
If you want to distribute the modified version in any way, contact
the author.
@@ -80,11 +71,11 @@ This source is distributed under the conditions blow:
distribute the modified version.
4. You may modify and include the part of the software into any other
- software (possibly commercial). But some files in the
- distribution are not written by the author, so that they are not
- under this terms. They are gc.c(partly)regex.[ch]fnmatch.[ch]
- glob.c, st.[ch] and somme files under ./missing directory. See
- each files for the condition.
+ software (possibly commercial). But some files in the distribution
+ are not written by the author, so that they are not under this terms.
+ They are gc.c(partly)utils.c(partly), regex.[ch]fnmatch.[ch]
+ glob.c, st.[ch] and somme files under the ./missing directory. See
+ each files for the copying condition.
5. The scripts and library files supplied as input to or produced as
output from the software do not automatically fall under the
@@ -101,14 +92,14 @@ This source is distributed under the conditions blow:
The URL of the ruby home-page is:
- http://www.caelum.co.jp/~matz/ruby/index-en.html
+ http://www.netlab.co.jp/ruby/
* The Author
Feel free to send comments and bug reports to the author. Here is the
author's latest mail address:
- matz@ruby.club.or.jp
+ matz@netlab.co.jp
-------------------------------------------------------
created at: Thu Aug 3 11:57:36 JST 1995
diff --git a/README.EXT b/README.EXT
index fdf8c96af7..c2f81d1a7a 100644
--- a/README.EXT
+++ b/README.EXT
@@ -1,49 +1,50 @@
.\" README.EXT - -*- Text -*- created at: Mon Aug 7 16:45:54 JST 1995
-rubyγĥ⥸塼κޤ
+This document explains how to make extention modules for ruby.
-1μ
+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 06c0832b10..8a100106b1 100644
--- a/README.jp
+++ b/README.jp
@@ -27,22 +27,13 @@ RubyϥƥȽطǽϤʤɤͥ졤perlƱ餤
ʲξˤƤޤ
- ftp://ftp.caelum.co.jp/pub/lang/ruby/
-
-** ᥤ
-
-ʲΥɥ쥹`send'ȤSubjectΥᥤäƲ
-
- ruby-archive@caelum.co.jp
-
-ʸˤϲ񤤤Ƥ⹽ޤޤ֤ǿǤruby
+ ftp://ftp.netlab.co.jp/pub/lang/ruby/
* ۡڡ
RubyΥۡڡURL
- http://www.caelum.co.jp/~matz/ruby/
+ http://www.netlab.co.jp/ruby/jp/
Ǥ
@@ -51,7 +42,7 @@ RubyϥƥȽطǽϤʤɤͥ졤perlƱ餤
Ruby˴ؤΤΥᥤ󥰥ꥹȤߤޤ
ɥ쥹
- ruby-list@caelum.co.jp
+ ruby-list@netlab.co.jp
ǤΥɥ쥹˥ᥤСưŪϿޤ
@@ -133,9 +124,9 @@ UNIXǤconfigureۤȤɤκۤۼƤϤ
ʤŪǤ켫ͳǤruby˴ޤޤ¾κ
Ԥˤ륳ɤϡ줾κԤΰոˤ¤ä
- ޤŪˤgc.c()regex.[ch]fnmatch.[ch]
- glob.c, st.[ch]missingǥ쥯ȥ겼Υե뷲
- ޤ
+ ޤŪˤgc.c()util.c()regex.[ch]
+ fnmatch.[ch]glob.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 cfac8981fd..3b6edee08f 100644
--- a/ToDo
+++ b/ToDo
@@ -1,5 +1,4 @@
+* non-blocking open/write for thread
* ѥåޤѿΥ
* formatǽ
-* perlΤ褦setuid check
-* write debugger for ruby
* re-write regex code for speed and copyright
diff --git a/array.c b/array.c
index 741f09b9b1..c1ad9981c1 100644
--- a/array.c
+++ b/array.c
@@ -20,14 +20,43 @@ VALUE rb_to_a();
void
memclear(mem, size)
- VALUE *mem;
- int size;
+ register VALUE *mem;
+ register int size;
{
while (size--) {
*mem++ = Qnil;
}
}
+#define ARY_FREEZE FL_USER1
+
+static void
+ary_modify(ary)
+ VALUE ary;
+{
+ rb_secure(5);
+ if (FL_TEST(ary, ARY_FREEZE)) {
+ TypeError("can't modify frozen array");
+ }
+}
+
+VALUE
+ary_freeze(ary)
+ VALUE ary;
+{
+ FL_SET(ary, ARY_FREEZE);
+ return ary;
+}
+
+static VALUE
+ary_frozen_p(ary)
+ VALUE ary;
+{
+ if (FL_TEST(ary, ARY_FREEZE))
+ return TRUE;
+ return FALSE;
+}
+
VALUE
ary_new2(len)
int len;
@@ -148,12 +177,13 @@ ary_s_create(argc, argv, class)
return (VALUE)ary;
}
-static void
-astore(ary, idx, val)
+void
+ary_store(ary, idx, val)
struct RArray *ary;
int idx;
VALUE val;
{
+ ary_modify(ary);
if (idx < 0) {
IndexError("negative index for array");
}
@@ -177,7 +207,7 @@ ary_push(ary, item)
struct RArray *ary;
VALUE item;
{
- astore(ary, ary->len, item);
+ ary_store(ary, ary->len, item);
return (VALUE)ary;
}
@@ -188,7 +218,7 @@ ary_push_method(argc, argv, ary)
struct RArray *ary;
{
while (argc--) {
- astore(ary, ary->len, *argv++);
+ ary_store(ary, ary->len, *argv++);
}
return (VALUE)ary;
}
@@ -231,6 +261,7 @@ ary_unshift(ary, item)
struct RArray *ary;
int item;
{
+ ary_modify(ary);
if (ary->len >= ary->capa) {
ary->capa+=ARY_DEFAULT_SIZE;
REALLOC_N(ary->ptr, VALUE, ary->capa);
@@ -243,18 +274,6 @@ ary_unshift(ary, item)
return ary->ptr[0] = item;
}
-static VALUE
-ary_unshift_method(argc, argv, ary)
- int argc;
- VALUE *argv;
- VALUE ary;
-{
- while (argc--) {
- ary_unshift(ary, argv[argc]);
- }
- return (VALUE)ary;
-}
-
VALUE
ary_entry(ary, offset)
struct RArray *ary;
@@ -402,7 +421,7 @@ ary_indexes(ary, args)
p = args->ptr; pend = p + args->len;
while (p < pend) {
- astore(new_ary, i++, ary_entry(ary, NUM2INT(*p)));
+ ary_store(new_ary, i++, ary_entry(ary, NUM2INT(*p)));
p++;
}
return new_ary;
@@ -413,6 +432,7 @@ ary_replace(ary, beg, len, rpl)
struct RArray *ary, *rpl;
int beg, len;
{
+ ary_modify(ary);
if (TYPE(rpl) != T_ARRAY) {
rpl = (struct RArray*)rb_to_a(rpl);
}
@@ -490,11 +510,11 @@ ary_aset(argc, argv, ary)
if (offset < 0) {
offset = ary->len + offset;
}
- astore(ary, offset, arg2);
+ ary_store(ary, offset, arg2);
return arg2;
}
-static VALUE
+VALUE
ary_each(ary)
struct RArray *ary;
{
@@ -519,6 +539,18 @@ ary_each_index(ary)
}
static VALUE
+ary_reverse_each(ary)
+ struct RArray *ary;
+{
+ int len = ary->len;
+
+ while (len--) {
+ rb_yield(ary->ptr[len]);
+ }
+ return Qnil;
+}
+
+static VALUE
ary_length(ary)
struct RArray *ary;
{
@@ -575,6 +607,7 @@ ary_join(ary, sep)
}
if (!NIL_P(sep)) str_cat(result, sep->ptr, sep->len);
str_cat(result, RSTRING(tmp)->ptr, RSTRING(tmp)->len);
+ if (str_tainted(tmp)) str_taint(result);
}
return result;
@@ -590,9 +623,7 @@ ary_join_method(argc, argv, ary)
rb_scan_args(argc, argv, "01", &sep);
if (NIL_P(sep)) sep = OFS;
-
- if (!NIL_P(sep))
- Check_Type(sep, T_STRING);
+ if (!NIL_P(sep)) Check_Type(sep, T_STRING);
return ary_join(ary, sep);
}
@@ -628,7 +659,6 @@ ary_inspect(ary)
{
int i, len;
VALUE s, str;
- char *p;
if (ary->len == 0) return str_new2("[]");
str = str_new2("[");
@@ -707,6 +737,13 @@ sort_2(a, b)
{
VALUE retval;
+ if (FIXNUM_P(*a)) {
+ if (FIXNUM_P(*b)) return *a - *b;
+ }
+ else if (TYPE(*a) == T_STRING) {
+ if (TYPE(*b) == T_STRING) return str_cmp(*a, *b);
+ }
+
retval = rb_funcall(*a, cmp, 1, *b);
return NUM2INT(retval);
}
@@ -715,6 +752,7 @@ VALUE
ary_sort_bang(ary)
struct RArray *ary;
{
+ ary_modify(ary);
qsort(ary->ptr, ary->len, sizeof(VALUE), iterator_p()?sort_1:sort_2);
return (VALUE)ary;
}
@@ -726,13 +764,14 @@ ary_sort(ary)
return ary_sort_bang(ary_clone(ary));
}
-static VALUE
+VALUE
ary_delete(ary, item)
struct RArray *ary;
VALUE item;
{
int i1, i2;
+ ary_modify(ary);
for (i1 = i2 = 0; i1 < ary->len; i1++) {
if (rb_equal(ary->ptr[i1], item)) continue;
if (i1 != i2) {
@@ -741,13 +780,14 @@ ary_delete(ary, item)
i2++;
}
if (ary->len == i2) {
- if (iterator_p()) rb_yield(Qnil);
+ if (iterator_p()) rb_yield(item);
+ return Qnil;
}
else {
ary->len = i2;
}
- return (VALUE)ary;
+ return item;
}
VALUE
@@ -758,6 +798,7 @@ ary_delete_at(ary, at)
int i1, i2, pos;
VALUE del = Qnil;
+ ary_modify(ary);
pos = NUM2INT(at);
for (i1 = i2 = 0; i1 < ary->len; i1++) {
if (i1 == pos) {
@@ -780,6 +821,7 @@ ary_delete_if(ary)
{
int i1, i2;
+ ary_modify(ary);
for (i1 = i2 = 0; i1 < ary->len; i1++) {
if (rb_yield(ary->ptr[i1])) continue;
if (i1 != i2) {
@@ -792,6 +834,21 @@ ary_delete_if(ary)
return (VALUE)ary;
}
+#if 0
+static VALUE
+ary_replace(ary)
+ struct RArray *ary;
+{
+ int i;
+
+ for (i = 0; i < ary->len; i++) {
+ ary->ptr[i] = rb_yield(ary->ptr[i]);
+ }
+
+ return (VALUE)ary;
+}
+#endif
+
static VALUE
ary_clear(ary)
struct RArray *ary;
@@ -871,7 +928,6 @@ VALUE
ary_concat(x, y)
struct RArray *x, *y;
{
- struct RArray *z;
VALUE *p, *pend;
if (TYPE(y) != T_ARRAY) {
@@ -881,7 +937,7 @@ ary_concat(x, y)
p = y->ptr;
pend = p + y->len;
while (p < pend) {
- astore(x, x->len, *p);
+ ary_store(x, x->len, *p);
p++;
}
return (VALUE)x;
@@ -903,6 +959,10 @@ ary_times(ary, times)
ary2 = (struct RArray*)ary_new2(len);
ary2->len = len;
+ if (len < 0) {
+ ArgError("negative argument");
+ }
+
for (i=0; i<len; i+=ary->len) {
MEMCPY(ary2->ptr+i, ary->ptr, VALUE, ary->len);
}
@@ -962,21 +1022,34 @@ ary_equal(ary1, ary2)
}
static VALUE
+ary_eql(ary1, ary2)
+ struct RArray *ary1, *ary2;
+{
+ int i;
+
+ if (TYPE(ary2) != T_ARRAY) return FALSE;
+ if (ary1->len != ary2->len) return FALSE;
+ for (i=0; i<ary1->len; i++) {
+ if (!rb_eql(ary1->ptr[i], ary2->ptr[i]))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static VALUE
ary_hash(ary)
struct RArray *ary;
{
- int i, h;
- ID hash = rb_intern("hash");
+ int h, i;
- h = 0;
+ h = ary->len;
for (i=0; i<ary->len; i++) {
- h ^= rb_funcall(ary->ptr[i], hash, 0);
+ h ^= rb_hash(ary->ptr[i]);
}
- h += ary->len;
return INT2FIX(h);
}
-static VALUE
+VALUE
ary_includes(ary, item)
struct RArray *ary;
VALUE item;
@@ -1055,6 +1128,7 @@ ary_compact_bang(ary)
{
VALUE *p, *t, *end;
+ ary_modify(ary);
p = t = ary->ptr;
end = p + ary->len;
while (t < end) {
@@ -1104,10 +1178,13 @@ Init_Array()
rb_define_method(cArray, "inspect", ary_inspect, 0);
rb_define_method(cArray, "to_a", ary_to_a, 0);
- rb_define_method(cArray, "print_on", ary_print_on, 1);
+ rb_define_method(cArray, "freeze", ary_freeze, 0);
+ rb_define_method(cArray, "frozen?", ary_frozen_p, 0);
rb_define_method(cArray, "==", ary_equal, 1);
+ rb_define_method(cArray, "eql?", ary_eql, 1);
rb_define_method(cArray, "hash", ary_hash, 0);
+
rb_define_method(cArray, "[]", ary_aref, -1);
rb_define_method(cArray, "[]=", ary_aset, -1);
rb_define_method(cArray, "concat", ary_concat, 1);
@@ -1115,9 +1192,10 @@ Init_Array()
rb_define_method(cArray, "push", ary_push_method, -1);
rb_define_method(cArray, "pop", ary_pop, 0);
rb_define_method(cArray, "shift", ary_shift, 0);
- rb_define_method(cArray, "unshift", ary_unshift_method, -1);
+ rb_define_method(cArray, "unshift", ary_unshift, 1);
rb_define_method(cArray, "each", ary_each, 0);
rb_define_method(cArray, "each_index", ary_each_index, 0);
+ rb_define_method(cArray, "reverse_each", ary_reverse_each, 0);
rb_define_method(cArray, "length", ary_length, 0);
rb_define_alias(cArray, "size", "length");
rb_define_method(cArray, "empty?", ary_empty_p, 0);
@@ -1132,10 +1210,12 @@ Init_Array()
rb_define_method(cArray, "delete", ary_delete, 1);
rb_define_method(cArray, "delete_at", ary_delete_at, 1);
rb_define_method(cArray, "delete_if", ary_delete_if, 0);
+#if 0
+ rb_define_method(cArray, "replace", ary_replace, 0);
+#endif
rb_define_method(cArray, "clear", ary_clear, 0);
rb_define_method(cArray, "fill", ary_fill, -1);
rb_define_method(cArray, "include?", ary_includes, 1);
- rb_define_method(cArray, "includes?", ary_includes, 1); /* obsolate */
rb_define_method(cArray, "assoc", ary_assoc, 1);
rb_define_method(cArray, "rassoc", ary_rassoc, 1);
diff --git a/bignum.c b/bignum.c
index e3bd528e72..8af40d6731 100644
--- a/bignum.c
+++ b/bignum.c
@@ -65,9 +65,17 @@ big_2comp(x) /* get 2's complement */
ds[i++] = BIGLO(num);
num = BIGDN(num);
} while (i < x->len);
+ if (ds[0] == 1 || ds[0] == 0) {
+ for (i=1;i<x->len;i++) {
+ if (ds[i] != 0) return;
+ }
+ REALLOC_N(BDIGITS(x), USHORT, x->len++);
+ ds = BDIGITS(x);
+ ds[x->len-1] = 1;
+ }
}
-VALUE
+static VALUE
bignorm(x)
struct RBignum *x;
{
@@ -150,7 +158,7 @@ int2inum(n)
VALUE
str2inum(str, base)
- char *str;
+ UCHAR *str;
int base;
{
char sign = 1, c;
@@ -189,7 +197,7 @@ str2inum(str, base)
}
if (len <= (sizeof(VALUE)*CHAR_BIT)) {
- UINT val = strtoul(str, 0, base);
+ UINT val = strtoul((char*)str, 0, base);
if (POSFIXABLE(val)) {
if (sign) return INT2FIX(val);
@@ -256,7 +264,7 @@ big2str(x, base)
USHORT *ds;
UINT i, j, hbase;
VALUE ss;
- char *s, c;
+ UCHAR *s, c;
if (FIXNUM_P(x)) {
return fix2str(x, base);
@@ -431,6 +439,14 @@ big_cmp(x, y)
}
static VALUE
+big_eq(x, y)
+ VALUE x, y;
+{
+ if (big_cmp(x, y) == INT2FIX(0)) return TRUE;
+ return FALSE;
+}
+
+static VALUE
big_uminus(x)
struct RBignum *x;
{
@@ -487,35 +503,20 @@ bigsub(x, y)
z = (struct RBignum*)bignew(x->len, (z == 0)?1:0);
zds = BDIGITS(z);
- i = x->len;
- while (i--) zds[i] = BDIGITS(x)[i];
-
- i = 0; num = 0;
- do {
- num += (long)zds[i] - BDIGITS(y)[i];
- if (num < 0) {
- zds[i] = num + BIGRAD;
- num = -1;
- }
- else {
- zds[i] = BIGLO(num);
- num = 0;
- }
- } while (++i < y->len);
- if (num) {
- while (num && i < x->len) {
- num += zds[i];
- if (num < 0) {
- zds[i++] = num + BIGRAD;
- num = -1;
- }
- else {
- zds[i++] = BIGLO(num);
- num = 0;
- }
- }
+ for (i = 0, num = 0; i < y->len; i++) {
+ num += (long)BDIGITS(x)[i] - BDIGITS(y)[i];
+ zds[i] = BIGLO(num);
+ num = BIGDN(num);
+ }
+ while (num && i < x->len) {
+ num += BDIGITS(x)[i];
+ zds[i++] = BIGLO(num);
+ num = BIGDN(num);
}
-
+ while (i < x->len) {
+ zds[i++] = BDIGITS(x)[i];
+ }
+
return bignorm(z);
}
@@ -525,10 +526,8 @@ bigadd(x, y, sign)
char sign;
{
struct RBignum *z;
- USHORT *zds;
long num;
UINT i, len;
-
if (x->sign == (y->sign ^ sign)) {
if (y->sign == sign) return bigsub(y, x);
return bigsub(x, y);
@@ -541,27 +540,24 @@ bigadd(x, y, sign)
len = y->len + 1;
}
z = (struct RBignum*)bignew(len, sign==y->sign);
- zds = BDIGITS(z);
-
- i = len;
- while (i--) zds[i] = 0;
- i = y->len;
- while (i--) zds[i] = BDIGITS(y)[i];
- i = 0; num = 0;
- do {
- num += (long)zds[i] + BDIGITS(x)[i];
- zds[i++] = BIGLO(num);
- num = BIGDN(num);
- } while (i < x->len);
- if (num) {
- while (i < y->len) {
- num += zds[i];
- zds[i++] = BIGLO(num);
- num = BIGDN(num);
- }
- BDIGITS(z)[i] = num;
+ if (x->len > y->len) {
+ struct RBignum* t = x; x = y; y = t;
+ }
+ for (i = 0, num = 0; i < x->len; i++) {
+ num += (long)(BDIGITS(x)[i]) + BDIGITS(y)[i];
+ BDIGITS(z)[i] = BIGLO(num);
+ num = BIGDN(num);
}
+ while (num && i < y->len) {
+ num += BDIGITS(y)[i];
+ BDIGITS(z)[i++] = BIGLO(num);
+ num = BIGDN(num);
+ }
+ while (i < y->len) {
+ BDIGITS(z)[i++] = BDIGITS(y)[i];
+ }
+ BDIGITS(z)[i] = num;
return bignorm(z);
}
@@ -570,8 +566,6 @@ VALUE
big_plus(x, y)
VALUE x, y;
{
- VALUE z;
-
switch (TYPE(y)) {
case T_FIXNUM:
y = int2big(FIX2INT(y));
@@ -591,8 +585,6 @@ VALUE
big_minus(x, y)
VALUE x, y;
{
- VALUE cmp;
-
switch (TYPE(y)) {
case T_FIXNUM:
y = int2big(FIX2INT(y));
@@ -637,20 +629,20 @@ big_mul(x, y)
z = bignew(j, x->sign==y->sign);
zds = BDIGITS(z);
while (j--) zds[j] = 0;
- do {
- j = 0;
- if (BDIGITS(x)[i]) {
- do {
- n += zds[i + j] + ((unsigned long)BDIGITS(x)[i]*BDIGITS(y)[j]);
- zds[i + j++] = BIGLO(n);
- n = BIGDN(n);
- } while (j < y->len);
- if (n) {
- zds[i + j] = n;
- n = 0;
- }
+ for (i = 0; i < x->len; i++) {
+ unsigned long dd = BDIGITS(x)[i];
+ if (dd == 0) continue;
+ n = 0;
+ for (j = 0; j < y->len; j++) {
+ int ee = n + dd * BDIGITS(y)[j];
+ n = zds[i + j] + ee;
+ if (ee) zds[i + j] = BIGLO(n);
+ n = BIGDN(n);
}
- } while (++i < x->len);
+ if (n) {
+ zds[i + j] = n;
+ }
+ }
return bignorm(z);
}
@@ -669,7 +661,7 @@ bigdivmod(x, y, div, mod)
yds = BDIGITS(y);
if (ny == 0 && yds[0] == 0) num_zerodiv();
- if (nx < ny) {
+ if (nx < ny || nx == ny && BDIGITS(x)[nx - 1] < BDIGITS(y)[ny - 1]) {
if (div) *div = INT2FIX(0);
if (mod) *mod = bignorm(x);
return;
@@ -680,7 +672,7 @@ bigdivmod(x, y, div, mod)
z = big_clone(x);
zds = BDIGITS(z);
t2 = 0; i = nx;
- while(i--) {
+ while (i--) {
t2 = BIGUP(t2) + zds[i];
zds[i] = t2 / dd;
t2 %= dd;
@@ -728,24 +720,21 @@ bigdivmod(x, y, div, mod)
if (q) {
i = 0; num = 0; t2 = 0;
do { /* multiply and subtract */
+ int ee;
t2 += (unsigned long)yds[i] * q;
- num += zds[j - ny + i] - BIGLO(t2);
- if (num < 0) {
- zds[j - ny + i] = num + BIGRAD;
- num = -1;
- }
- else {
- zds[j - ny + i] = num;
- num = 0;
- }
+ ee = num - BIGLO(t2);
+ num = zds[j - ny + i] + ee;
+ if (ee) zds[j - ny + i] = BIGLO(num);
+ num = BIGDN(num);
t2 = BIGDN(t2);
} while (++i < ny);
num += zds[j - ny + i] - t2; /* borrow from high digit; don't update */
while (num) { /* "add back" required */
i = 0; num = 0; q--;
do {
- num += (long) zds[j - ny + i] + yds[i];
- zds[j - ny + i] = BIGLO(num);
+ int ee = num + yds[i];
+ num = (long) zds[j - ny + i] + ee;
+ if (ee) zds[j - ny + i] = BIGLO(num);
num = BIGDN(num);
} while (++i < ny);
num--;
@@ -1241,6 +1230,8 @@ Init_Bignum()
rb_define_method(cBignum, "[]", big_aref, 1);
rb_define_method(cBignum, "<=>", big_cmp, 1);
+ rb_define_method(cBignum, "==", big_eq, 1);
+ rb_define_method(cBignum, "eql?", big_eq, 1);
rb_define_method(cBignum, "hash", big_hash, 0);
rb_define_method(cBignum, "to_i", big_to_i, 0);
rb_define_method(cBignum, "to_f", big_to_f, 0);
diff --git a/class.c b/class.c
index 645d295c19..6cb55fa240 100644
--- a/class.c
+++ b/class.c
@@ -28,6 +28,8 @@ class_new(super)
OBJSETUP(cls, cClass, T_CLASS);
cls->super = super;
+ cls->iv_tbl = 0;
+ cls->m_tbl = 0; /* safe GC */
cls->m_tbl = new_idhash();
return (VALUE)cls;
@@ -66,6 +68,8 @@ singleton_class_clone(class)
CLONESETUP(clone, class);
clone->super = class->super;
+ clone->iv_tbl = 0;
+ clone->m_tbl = 0;
clone->m_tbl = new_idhash();
st_foreach(class->m_tbl, clone_method, clone->m_tbl);
FL_SET(clone, FL_SINGLETON);
@@ -128,6 +132,8 @@ module_new()
OBJSETUP(mdl, cModule, T_MODULE);
mdl->super = 0;
+ mdl->iv_tbl = 0;
+ mdl->m_tbl = 0;
mdl->m_tbl = new_idhash();
return (VALUE)mdl;
@@ -197,7 +203,7 @@ include_class_new(module, super)
void
rb_include_module(class, module)
- struct RClass *class, *module;
+ VALUE class, module;
{
struct RClass *p;
@@ -216,18 +222,14 @@ rb_include_module(class, module)
while (module) {
/* ignore if the module included already in superclasses */
- for (p = class->super; p; p = p->super) {
- if (BUILTIN_TYPE(p) == T_ICLASS && p->m_tbl == module->m_tbl)
+ for (p = RCLASS(class)->super; p; p = p->super) {
+ if (BUILTIN_TYPE(p) == T_ICLASS && p->m_tbl == RCLASS(module)->m_tbl)
return;
}
- if (verbose) {
- rb_const_check(class, module);
- }
-
- class->super = include_class_new(module, class->super);
- class = class->super;
- module = module->super;
+ RCLASS(class)->super = include_class_new(module, RCLASS(class)->super);
+ class = (VALUE)RCLASS(class)->super;
+ module = (VALUE)RCLASS(module)->super;
}
}
@@ -243,7 +245,7 @@ rb_define_method_id(class, name, func, argc)
void
rb_define_method(class, name, func, argc)
- struct RClass *class;
+ VALUE class;
char *name;
VALUE (*func)();
int argc;
@@ -253,7 +255,7 @@ rb_define_method(class, name, func, argc)
void
rb_undef_method(class, name)
- struct RClass *class;
+ VALUE class;
char *name;
{
rb_add_method(class, rb_intern(name), 0, NOEX_PUBLIC);
@@ -273,6 +275,9 @@ VALUE
rb_singleton_class(obj)
struct RBasic *obj;
{
+ if (rb_special_const_p((VALUE)obj)) {
+ TypeError("cannot define singleton");
+ }
if (FL_TEST(obj->class, FL_SINGLETON)) {
return (VALUE)obj->class;
}
@@ -300,9 +305,20 @@ rb_define_module_function(module, name, func, argc)
rb_define_singleton_method(module, name, func, argc);
}
+VALUE mKernel;
+
+void
+rb_define_global_function(name, func, argc)
+ char *name;
+ VALUE (*func)();
+ int argc;
+{
+ rb_define_private_method(mKernel, name, func, argc);
+}
+
void
rb_define_alias(class, name1, name2)
- struct RClass *class;
+ VALUE class;
char *name1, *name2;
{
rb_alias(class, rb_intern(name1), rb_intern(name2));
@@ -310,7 +326,7 @@ rb_define_alias(class, name1, name2)
void
rb_define_attr(class, id, pub)
- struct RClass *class;
+ VALUE class;
ID id;
int pub;
{
@@ -325,10 +341,10 @@ rb_define_attr(class, id, pub)
attreq = rb_intern(buf);
sprintf(buf, "@%s", name);
attriv = rb_intern(buf);
- if (!rb_method_boundp(class, attr)) {
+ if (!rb_method_boundp(class, attr, NOEX_PRIVATE)) {
rb_add_method(class, attr, NEW_IVAR(attriv), 0);
}
- if (pub && !rb_method_boundp(class, attreq)) {
+ if (pub && !rb_method_boundp(class, attreq, NOEX_PRIVATE)) {
rb_add_method(class, attreq, NEW_ATTRSET(attriv), 0);
}
}
diff --git a/config.dj b/config.dj
index 13f4e6ddb6..8ad3883380 100644
--- a/config.dj
+++ b/config.dj
@@ -32,4 +32,5 @@
#define FILE_COUNT _cnt
#define DLEXT ".so"
#define RUBY_LIB ";/usr/local/lib/ruby;."
-#define RUBY_ARCHLIB "/usr/local/lib/ruby/i386-msdos"
+#define RUBY_ARCHLIB "/usr/local/lib/ruby/i386-djgpp"
+#define RUBY_PLATFORM "i386-djgpp"
diff --git a/config.guess b/config.guess
index ce6e12a8fd..ea28434e58 100755
--- a/config.guess
+++ b/config.guess
@@ -35,6 +35,17 @@
# (but try to keep the structure clean).
#
+# Modified for Human68k by K.Okabe 1997.07.09
+# Last change: 1997.07.09
+
+case "$KSH_VERSION" in
+*X6*)
+ echo m68k-sharp-human
+ exit 0 ;;
+*)
+ ;;
+esac
+
# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
# (ghazi@noc.rutgers.edu 8/24/94.)
if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
@@ -322,6 +333,9 @@ EOF
*:NetBSD:*:*)
echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
exit 0 ;;
+ *:*:*BOW*:*)
+ echo i386-pc-bow
+ exit 0 ;;
i*:CYGWIN*:*)
echo i386-pc-cygwin32
exit 0 ;;
@@ -417,16 +431,40 @@ EOF
mc68*:A/UX:*:*)
echo m68k-apple-aux${UNAME_RELEASE}
exit 0 ;;
- R3000:*System_V*:*:*)
+ X680[02346]0:Human68k:*:*)
+ echo m68k-sharp-human
+ exit 0 ;;
+ R[34]000:*System_V*:*:*)
if [ -d /usr/nec ]; then
echo mips-nec-sysv${UNAME_RELEASE}
else
echo mips-unknown-sysv${UNAME_RELEASE}
fi
exit 0 ;;
+ R[34]???:UNIX_SV:4.?MP:*)
+ if [ -x /sbin/uversion ]; then
+ UVERSION_RELEASE=`(/sbin/uversion -r) 2>/dev/null` \
+ || UVERSION_RELEASE=unknown
+ UVERSION_SYSTEM=`(/sbin/uversion -s) 2>/dev/null` \
+ || UVERSION_SYSTEM=unknown
+ case "${UVERSION_RELEASE}:${UVERSION_SYSTEM}" in
+ Release*:EWS4800/*)
+ suffix=`echo ${UNAME_RELEASE} | tr '[A-Z]' '[a-z]'`
+ suffix=${suffix}r`echo ${UVERSION_RELEASE} | \
+ sed -e 's/Release//' -e 's/ Rev.*$//'`
+ echo mips-nec-sysv${suffix}
+ exit 0 ;;
+ esac
+ fi;;
+ *:machten:*:*)
+ echo ${UNAME_MACHINE}-apple-machten
+ exit 0 ;;
powerpc:JCC_BSD+:*:*)
echo powerpc-jcc-bsd4.4
exit 0 ;;
+ DS/90*:*:*:V20*)
+ echo sparc-fujitsu-uxpds
+ exit 0 ;;
esac
#echo '(No uname command or uname output not recognized.)' 1>&2
@@ -526,12 +564,16 @@ main ()
printf ("i860-alliant-bsd\n"); exit (0);
#endif
+#if defined (__human68k__) || defined (HUMAN68K)
+ printf ("m68k-sharp-human\n"); exit (0);
+#endif
+
exit (1);
}
EOF
-${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0
-rm -f dummy.c dummy
+${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy.x dummy && exit 0
+rm -f dummy.c dummy.x dummy
# Apollos put the system type in the environment.
diff --git a/config.sub b/config.sub
index 27819cc8dc..9dec8e3c13 100755
--- a/config.sub
+++ b/config.sub
@@ -634,6 +634,10 @@ case $basic_machine in
orion105)
basic_machine=clipper-highlevel
;;
+ human)
+ basic_machine=m68k-sharp
+ os=-human
+ ;;
*)
echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
exit 1
@@ -687,7 +691,7 @@ case $os in
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
| -cygwin32* | -pe* | -psos* | -moss* | -proelf* \
- | -linux*)
+ | -linux* | -bow*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-sunos5*)
@@ -745,6 +749,11 @@ case $os in
-xenix)
os=-xenix
;;
+ -uxpds)
+ os=-uxpds
+ ;;
+ -human)
+ ;;
-none)
;;
*)
diff --git a/configure.in b/configure.in
index 7f89f5e69c..699ca1eed3 100644
--- a/configure.in
+++ b/configure.in
@@ -1,9 +1,6 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT(ruby.h)
-PROGS="ruby"
-AC_SUBST(PROGS)dnl
-
dnl checks for alternative programs
AC_ARG_WITH(gcc, [--without-gcc never use gcc], [
case $withval in
@@ -31,11 +28,15 @@ if test $rb_thread = yes; then
fi
AC_CANONICAL_HOST
+AC_ARG_PROGRAM
dnl Checks for programs.
AC_PROG_CC
AC_PROG_GCC_TRADITIONAL
AC_PROG_YACC
+AC_PROG_RANLIB
+AC_SUBST(AR)
+AC_CHECK_PROGS(AR, ar aal, ar)
AC_PROG_INSTALL
AC_PROG_MAKE_SET
@@ -43,6 +44,11 @@ AC_PROG_MAKE_SET
AC_MINIX
dnl Checks for libraries.
+case "$host_os" in
+nextstep*) ;;
+human*) ;;
+*) LIBS="-lm $LIBS";;
+esac
AC_CHECK_LIB(crypt, crypt)
AC_CHECK_LIB(dl, dlopen) # Dynamic linking for SunOS/Solaris and SYSV
AC_CHECK_LIB(dld, shl_load) # Dynamic linking for HP-UX
@@ -50,15 +56,17 @@ AC_CHECK_LIB(dld, shl_load) # Dynamic linking for HP-UX
dnl Checks for header files.
AC_HEADER_DIRENT
AC_HEADER_STDC
-AC_CHECK_HEADERS(unistd.h limits.h sys/file.h sys/ioctl.h pwd.h sys/select.h\
- sys/time.h sys/times.h sys/param.h sys/wait.h\
+AC_CHECK_HEADERS(stdlib.h unistd.h limits.h sys/file.h sys/ioctl.h pwd.h \
+ sys/select.h sys/time.h sys/times.h sys/param.h sys/wait.h\
syscall.h a.out.h string.h utime.h memory.h)
dnl Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_UID_T
AC_TYPE_SIZE_T
AC_STRUCT_ST_BLKSIZE
+save_LIBOJBS="$LIBOBJS"
AC_STRUCT_ST_BLOCKS
+LIBOBJS="$save_LIBOBJS"
AC_STRUCT_ST_RDEV
dnl Checks for library functions.
@@ -66,12 +74,13 @@ AC_TYPE_GETGROUPS
AC_TYPE_SIGNAL
AC_FUNC_ALLOCA
AC_FUNC_VFORK
-AC_REPLACE_FUNCS(dup2 setenv memmove mkdir strerror strftime\
+AC_REPLACE_FUNCS(dup2 setenv memmove mkdir strcasecmp strerror strftime\
strstr strtoul strdup strcasecmp crypt flock)
AC_CHECK_FUNCS(fmod killpg random wait4 waitpid syscall getcwd\
truncate chsize times utimes fcntl lockf setitimer\
setruid seteuid setreuid setrgid setegid setregid\
- getgroups getpgid getpriority dlopen sigprocmask sigaction)
+ setpgrp2 getpgid getgroups getpriority\
+ dlopen sigprocmask sigaction _setjmp)
if test "$ac_cv_func_strftime" = no; then
AC_STRUCT_TIMEZONE
AC_TRY_LINK([],
@@ -83,18 +92,18 @@ if test "$ac_cv_func_sigprocmask" = yes && test "$ac_cv_func_sigaction" = yes; t
else
AC_MSG_CHECKING(for BSD signal semantics)
AC_CACHE_VAL(rb_cv_bsd_signal,
- [AC_TRY_RUN([
+ [AC_TRY_RUN([
#include <stdio.h>
#include <signal.h>
-void sig_handler(dummy)
+void
+sig_handler(dummy)
int dummy;
{
}
-int main(argc, argv)
- int argc;
- char ** argv;
+int
+main()
{
signal(SIGINT, sig_handler);
kill(getpid(), SIGINT);
@@ -103,14 +112,38 @@ int main(argc, argv)
}
],
rb_cv_bsd_signal=yes,
- rb_cv_bsd_signal=no,
- [:])])
+ rb_cv_bsd_signal=no)])
AC_MSG_RESULT($rb_cv_bsd_signal)
if test "$rb_cv_bsd_signal" = yes; then
AC_DEFINE(BSD_SIGNAL)
fi
fi
+if test "$ac_cv_func_setpgrp2" = yes; then
+ AC_DEFINE(BSD_GETPGRP, getpgrp2)
+ AC_DEFINE(BSD_SETPGRP, setpgrp2)
+else
+ AC_MSG_CHECKING(whether getpgrp() has arg)
+ AC_CACHE_VAL(rb_cv_bsdgetpgrp,
+ [AC_TRY_COMPILE([#include <unistd.h>], [getpgrp(0);],
+ rb_cv_bsdgetpgrp=yes,
+ rb_cv_bsdgetpgrp=no)])
+ AC_MSG_RESULT($rb_cv_bsdgetpgrp)
+ if test "$rb_cv_bsdgetpgrp" = yes; then
+ AC_DEFINE(BSD_GETPGRP, getpgrp)
+ fi
+
+ AC_MSG_CHECKING(whether setpgrp() has args)
+ AC_CACHE_VAL(rb_cv_bsdsetpgrp,
+ [AC_TRY_COMPILE([#include <unistd.h>], [setpgrp(1, 1);],
+ rb_cv_bsdsetpgrp=yes,
+ rb_cv_bsdsetpgrp=no)])
+ AC_MSG_RESULT($rb_cv_bsdsetpgrp)
+ if test "$rb_cv_bsdsetpgrp" = yes; then
+ AC_DEFINE(BSD_SETPGRP, setpgrp)
+ fi
+fi
+
AC_C_BIGENDIAN
AC_CHAR_UNSIGNED
@@ -183,6 +216,7 @@ main() {
AC_MSG_RESULT($rb_cv_linux_elf)
if test "$rb_cv_linux_elf" = no; then
with_dln_a_out=yes
+ host_os=linux-a.out
else
LDFLAGS="-rdynamic"
fi;;
@@ -201,33 +235,49 @@ if test "$with_dln_a_out" != yes; then
rb_cv_dlopen=unknown
AC_MSG_CHECKING(whether OS depend dynamic link works)
if test "$GCC" = yes; then
- CCDLFLAGS=-fpic
+ case "$host_os" in
+ nextstep*) ;;
+ human*) ;;
+ *) CCDLFLAGS=-fpic;;
+ esac
else
case "$host_os" in
hpux*) CCDLFLAGS='+z';;
- solaris*|irix*) CCDLFLAGS='-K pic' ;;
- sunos*) CCDLFLAGS='-pic' ;;
- svr4*|esix*) CCDLFLAGS='-Kpic' ;;
- *) CCDLFLAGS='' ;;
+ solaris*|irix*) CCDLFLAGS='-K pic' ;;
+ sunos*) CCDLFLAGS='-pic' ;;
+ esix*|uxpds*) CCDLFLAGS='-Kpic' ;;
+ *) CCDLFLAGS='' ;;
esac
fi
case "$host_os" in
- hpux*) DLDFLAGS="-E"
- LDSHARED='ld -b'
- LDFLAGS="-Wl,-E"
- rb_cv_dlopen=yes;;
- solaris*) LDSHARED='ld -G'
- rb_cv_dlopen=yes;;
- sunos*) LDSHARED='ld -assert nodefinitions'
- rb_cv_dlopen=yes;;
- svr4*|esix*) LDSHARED="ld -G"
- rb_cv_dlopen=yes ;;
- linux*) LDSHARED="gcc -shared"
- rb_cv_dlopen=yes ;;
- freebsd*) LDSHARED="ld -Bshareable"
- rb_cv_dlopen=yes ;;
- *) LDSHARED='ld' ;;
+ hpux*) DLDFLAGS="-E"
+ LDSHARED='ld -b'
+ LDFLAGS="-Wl,-E"
+ rb_cv_dlopen=yes;;
+ solaris*) LDSHARED='ld -G'
+ rb_cv_dlopen=yes;;
+ sunos*) LDSHARED='ld -assert nodefinitions'
+ rb_cv_dlopen=yes;;
+ sysv4*) LDSHARED='ld -G'
+ rb_cv_dlopen=yes;;
+ esix*|uxpds*) LDSHARED="ld -G"
+ rb_cv_dlopen=yes ;;
+ linux*) LDSHARED="gcc -shared"
+ rb_cv_dlopen=yes ;;
+ freebsd*) LDSHARED="ld -Bshareable"
+ rb_cv_dlopen=yes ;;
+ netbsd*) LDSHARED="ld -Bshareable"
+ rb_cv_dlopen=yes ;;
+ nextstep*) LDSHARED='ld'
+ LDFLAGS="-u libsys_s"
+ rb_cv_dlopen=yes ;;
+ aix*) LDSHARED='../../miniruby ../aix_ld.rb $(TARGET)'
+ rb_cv_dlopen=yes ;;
+ human*) DLDFLAGS=''
+ LDSHARED=''
+ LDFLAGS='' ;;
+ *) LDSHARED='ld' ;;
esac
AC_MSG_RESULT($rb_cv_dlopen)
fi
@@ -297,13 +347,71 @@ AC_ARG_WITH(static-linked-ext,
*) ;;
esac])
+case "$host_os" in
+ human*)
+ AC_CHECK_LIB(signal, _harderr)
+ AC_CHECK_LIB(hmem, hmemset)
+ AC_CHECK_FUNCS(select)
+ AC_MSG_CHECKING(whether PD libc _dtos18 fail to convert big number)
+ AC_CACHE_VAL(rb_cv_missing__dtos18,
+ [AC_TRY_RUN(
+changequote(<<, >>)dnl
+<<
+#include <stdio.h>
+main ()
+{
+ char buf[256];
+ sprintf (buf, "%g", 1e+300);
+ exit (strcmp (buf, "1e+300") ? 0 : 1);
+}
+>>,
+changequote([, ])dnl
+rb_cv_missing__dtos18=yes, rb_cv_missing__dtos18=no)])
+ AC_MSG_RESULT($rb_cv_missing__dtos18)
+ if test "$rb_cv_missing__dtos18" = yes; then
+ AC_DEFINE(MISSING__DTOS18)
+ fi
+ AC_MSG_CHECKING(whether PD libc fconvert fail to round)
+ AC_CACHE_VAL(rb_cv_missing_fconvert,
+ [AC_TRY_RUN(
+changequote(<<, >>)dnl
+<<
+#include <stdio.h>
+#include <math.h>
+main ()
+{
+ char buf[256];
+ sprintf (buf, "%f", log(exp(1.0)));
+ exit (strcmp (buf, "1.000000") ? 0 : 1);
+}
+>>,
+changequote([, ])dnl
+rb_cv_missing_fconvert=yes, rb_cv_missing_fconvert=no)])
+ AC_MSG_RESULT($rb_cv_missing_fconvert)
+ if test "$rb_cv_missing_fconvert" = yes; then
+ AC_DEFINE(MISSING_FCONVERT)
+ fi
+ LIBOBJS="$LIBOBJS x68.o"
+ CFLAGS="$CFLAGS -fansi-only -cc1-stack=196608 -cpp-stack=2694144"
+ binsuffix=.x
+ setup=Setup.x68
+ ;;
+ *)
+ binsuffix=
+ setup=Setup
+ ;;
+esac
+AC_SUBST(binsuffix)
+AC_SUBST(setup)
+
if test "$prefix" = NONE; then
prefix=$ac_default_prefix
fi
-AC_DEFINE_UNQUOTED(RUBY_LIB, "${prefix}/lib/ruby:.")
-AC_SUBST(archlib)dnl
-archlib="${prefix}/lib/ruby/${host_cpu}-${host_os}"
-AC_DEFINE_UNQUOTED(RUBY_ARCHLIB, "$archlib")
+AC_DEFINE_UNQUOTED(RUBY_LIB, "${prefix}/lib/ruby")
+AC_SUBST(arch)dnl
+arch="${host_cpu}-${host_os}"
+AC_DEFINE_UNQUOTED(RUBY_ARCHLIB, "${prefix}/lib/ruby/${host_cpu}-${host_os}")
+AC_DEFINE_UNQUOTED(RUBY_PLATFORM, "$arch")
echo "creating config.h"
cat confdefs.h > config.h
diff --git a/defines.h b/defines.h
index 70e010aac9..b981d8617d 100644
--- a/defines.h
+++ b/defines.h
@@ -13,14 +13,19 @@
#define RUBY
/* define EUC/SJIS for default kanji-code */
+#if defined(MSDOS) || defined(__CYGWIN32__) || defined(__human68k__)
+#undef EUC
+#define SJIS
+#else
#define EUC
#undef SJIS
+#endif
#ifdef NeXT
+#define DYNAMIC_ENDIAN /* determine endian at runtime */
#define S_IXUSR _S_IXUSR /* execute/search permission, owner */
#define S_IXGRP 0000010 /* execute/search permission, group */
#define S_IXOTH 0000001 /* execute/search permission, other */
-#define S_ISREG(mode) (((mode) & (_S_IFMT)) == (_S_IFREG))
#endif /* NeXT */
#ifdef NT
@@ -33,4 +38,13 @@
#define FLUSH_REGISTER_WINDOWS /* empty */
#endif
+#ifdef __human68k__
+#undef HAVE_RANDOM
+#undef HAVE_SETITIMER
+#endif
+
+#ifndef RUBY_PLATFORM
+#define RUBY_PLATFORM "unknown-unknown"
+#endif
+
#endif
diff --git a/dir.c b/dir.c
index fe4910b3a9..a099d5e595 100644
--- a/dir.c
+++ b/dir.c
@@ -39,21 +39,23 @@
# include <ndir.h>
# endif
# ifdef NT
-# include "missing/dirent.h"
+# include "missing/dir.h"
# endif
#endif
#include <errno.h>
+#ifndef NT
char *getenv();
+#endif
static VALUE cDir;
static void
free_dir(dir)
- DIR **dir;
+ DIR *dir;
{
- if (dir && *dir) closedir(*dir);
+ if (dir) closedir(dir);
}
static VALUE
@@ -62,9 +64,9 @@ dir_s_open(dir_class, dirname)
struct RString *dirname;
{
VALUE obj;
- DIR *dirp, **d;
+ DIR *dirp;
- Check_Type(dirname, T_STRING);
+ Check_SafeStr(dirname);
dirp = opendir(dirname->ptr);
if (dirp == NULL) {
@@ -77,23 +79,20 @@ dir_s_open(dir_class, dirname)
}
}
- obj = Make_Data_Struct(dir_class, DIR*, 0, free_dir, d);
- *d = dirp;
+ obj = Data_Wrap_Struct(dir_class, 0, free_dir, dirp);
return obj;
}
static void
-closeddir()
+dir_closed()
{
Fail("closed directory");
}
#define GetDIR(obj, dirp) {\
- DIR **_dp;\
- Get_Data_Struct(obj, DIR*, _dp);\
- dirp = *_dp;\
- if (dirp == NULL) closeddir();\
+ Data_Get_Struct(obj, DIR, dirp);\
+ if (dirp == NULL) dir_closed();\
}
static VALUE
@@ -106,7 +105,7 @@ dir_each(dir)
GetDIR(dir, dirp);
for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
- file = str_new(dp->d_name, NAMLEN(dp));
+ file = str_taint(str_new(dp->d_name, NAMLEN(dp)));
rb_yield(file);
}
return dir;
@@ -158,12 +157,12 @@ static VALUE
dir_close(dir)
VALUE dir;
{
- DIR **dirpp;
+ DIR *dirp;
- Get_Data_Struct(dir, DIR*, dirpp);
- if (*dirpp == NULL) closeddir();
- closedir(*dirpp);
- *dirpp = NULL;
+ Data_Get_Struct(dir, DIR, dirp);
+ if (dirp == NULL) dir_closed();
+ closedir(dirp);
+ DATA_PTR(dir) = NULL;
return Qnil;
}
@@ -177,9 +176,10 @@ dir_s_chdir(argc, argv, obj)
VALUE path;
char *dist = "";
+ rb_secure(2);
rb_scan_args(argc, argv, "01", &path);
if (path) {
- Check_Type(path, T_STRING);
+ Check_SafeStr(path);
dist = RSTRING(path)->ptr;
}
else {
@@ -208,15 +208,16 @@ dir_s_getwd(dir)
if (getwd(path) == 0) rb_sys_fail(path);
#endif
- return str_new2(path);
+ return str_taint(str_new2(path));
}
static VALUE
dir_s_chroot(dir, path)
VALUE dir, path;
{
-#if !defined(DJGPP) && !defined(__CYGWIN32__)
- Check_Type(path, T_STRING);
+#if !defined(DJGPP) && !defined(__CYGWIN32__) && !defined(NT) && !defined(__human68k__)
+ rb_secure(2);
+ Check_SafeStr(path);
if (chroot(RSTRING(path)->ptr) == -1)
rb_sys_fail(0);
@@ -236,6 +237,7 @@ dir_s_mkdir(argc, argv, obj)
VALUE path, vmode;
int mode;
+ rb_secure(2);
if (rb_scan_args(argc, argv, "11", &path, &vmode) == 2) {
mode = NUM2INT(vmode);
}
@@ -243,9 +245,14 @@ dir_s_mkdir(argc, argv, obj)
mode = 0777;
}
- Check_Type(path, T_STRING);
+ Check_SafeStr(path);
+#ifndef NT
if (mkdir(RSTRING(path)->ptr, mode) == -1)
rb_sys_fail(RSTRING(path)->ptr);
+#else
+ if (mkdir(RSTRING(path)->ptr) == -1)
+ rb_sys_fail(RSTRING(path)->ptr);
+#endif
return INT2FIX(0);
}
@@ -255,7 +262,8 @@ dir_s_rmdir(obj, dir)
VALUE obj;
struct RString *dir;
{
- Check_Type(dir, T_STRING);
+ rb_secure(2);
+ Check_SafeStr(dir);
if (rmdir(dir->ptr) < 0)
rb_sys_fail(dir->ptr);
@@ -265,6 +273,7 @@ dir_s_rmdir(obj, dir)
#define isdelim(c) ((c)==' '||(c)=='\t'||(c)=='\n'||(c)=='\0')
char **glob_filename();
+extern char *glob_error_return;
static void
push_globs(ary, s)
@@ -277,11 +286,13 @@ push_globs(ary, s)
if (fnames == (char**)-1) rb_sys_fail(s);
ff = fnames;
while (*ff) {
- ary_push(ary, str_new2(*ff));
+ ary_push(ary, str_taint(str_new2(*ff)));
free(*ff);
ff++;
}
- free(fnames);
+ if (fnames != &glob_error_return) {
+ free(fnames);
+ }
}
static void
@@ -332,7 +343,7 @@ dir_s_glob(dir, str)
int nest;
VALUE ary;
- Check_Type(str, T_STRING);
+ Check_SafeStr(str);
ary = ary_new();
diff --git a/dln.c b/dln.c
index e5193a7ed7..ee5429a596 100644
--- a/dln.c
+++ b/dln.c
@@ -29,7 +29,11 @@ void *xcalloc();
void *xrealloc();
#include <stdio.h>
+#ifndef NT
#include <sys/file.h>
+#else
+#include "missing/file.h"
+#endif
#include <sys/types.h>
#include <sys/stat.h>
@@ -49,9 +53,11 @@ void *xrealloc();
# include <strings.h>
#endif
+#ifndef NT
char *strdup();
char *getenv();
+#endif
int eaccess();
@@ -61,7 +67,7 @@ int eaccess();
#endif
#ifndef FUNCNAME_PATTERN
-# if defined(__hp9000s300) || defined(__NetBSD__) || defined(__BORLANDC__) || defined(__FreeBSD__)
+# if defined(__hp9000s300) || defined(__NetBSD__) || defined(__BORLANDC__) || defined(__FreeBSD__) || defined(NeXT)
# define FUNCNAME_PATTERN "_Init_%.200s"
# else
# define FUNCNAME_PATTERN "Init_%.200s"
@@ -92,8 +98,8 @@ init_funcname(buf, file)
# define LIBC_NAME "libc.a"
#endif
-#ifndef DLN_DEFAULT_PATH
-# define DLN_DEFAULT_PATH "/lib:/usr/lib:."
+#ifndef DLN_DEFAULT_LIB_PATH
+# define DLN_DEFAULT_LIB_PATH "/lib:/usr/lib:/usr/local/lib:."
#endif
#include <errno.h>
@@ -136,12 +142,12 @@ load_header(fd, hdrp, disp)
int size;
lseek(fd, disp, 0);
- size = read(fd, hdrp, sizeof(*hdrp));
+ size = read(fd, hdrp, sizeof(struct exec));
if (size == -1) {
dln_errno = errno;
return -1;
}
- if (size != sizeof(*hdrp) || N_BADMAG(*hdrp)) {
+ if (size != sizeof(struct exec) || N_BADMAG(*hdrp)) {
dln_errno = DLN_ENOEXEC;
return -1;
}
@@ -206,11 +212,10 @@ load_reloc(fd, hdrp, disp)
struct exec *hdrp;
long disp;
{
- struct relocation_info * reloc;
+ struct relocation_info *reloc;
int size;
lseek(fd, disp + N_TXTOFF(*hdrp) + hdrp->a_text + hdrp->a_data, 0);
-
size = hdrp->a_trsize + hdrp->a_drsize;
reloc = (struct relocation_info*)xmalloc(size);
if (reloc == NULL) {
@@ -295,6 +300,7 @@ sym_hash(hdrp, syms)
static int
dln_init(prog)
+ char *prog;
{
char *file;
int fd;
@@ -672,7 +678,7 @@ load_1(fd, disp, need_init)
sym = syms;
while (sym < end) {
struct nlist *new_sym;
- char *key, *name;
+ char *key;
switch (sym->n_type) {
case N_COMM:
@@ -856,23 +862,11 @@ search_undef(key, value, lib_tbl)
int value;
st_table *lib_tbl;
{
-#if 0
- static char *last = "";
- int offset;
-
- if (st_lookup(lib_tbl, key, &offset) == 0) return ST_CONTINUE;
- if (strcmp(last, key) != 0) {
- last = key;
- target_offset = offset;
- }
- return ST_STOP;
-#else
int offset;
if (st_lookup(lib_tbl, key, &offset) == 0) return ST_CONTINUE;
target_offset = offset;
return ST_STOP;
-#endif
}
struct symdef {
@@ -880,7 +874,7 @@ struct symdef {
int lib_offset;
};
-char *dln_library_path = DLN_DEFAULT_PATH;
+char *dln_library_path = DLN_DEFAULT_LIB_PATH;
static int
load_lib(lib)
@@ -1108,7 +1102,7 @@ dln_strerror()
#endif
#ifdef USE_DLN_DLOPEN
- return dlerror();
+ return (char*)dlerror();
#endif
}
@@ -1259,9 +1253,6 @@ dln_load(file)
char *object_files[2] = {NULL, NULL};
void (*init_fct)();
- int len = strlen(file);
- char *point;
- char init_name[len +7];
object_files[0] = file;
@@ -1302,8 +1293,15 @@ dln_find_exe(fname, path)
char *fname;
char *path;
{
+#if defined(__human68k__)
+ if (!path)
+ path = getenv("path");
+ if (!path)
+ path = "/usr/local/bin;/usr/usb;/usr/bin;/bin;.";
+#else
if (!path) path = getenv("PATH");
if (!path) path = "/usr/local/bin:/usr/ucb:/usr/bin:/bin:.";
+#endif
return dln_find_1(fname, path, 1);
}
@@ -1332,6 +1330,12 @@ dln_find_1(fname, path, exe_flag)
if (fname[0] == '/') return fname;
if (strncmp("./", fname, 2) == 0 || strncmp("../", fname, 3) == 0)
return fname;
+#if defined(MSDOS) || defined(NT) || defined(__human68k__)
+ if (fname[0] == '\\') return fname;
+ if (fname[1] == ':') return fname;
+ if (strncmp(".\\", fname, 2) == 0 || strncmp("..\\", fname, 3) == 0)
+ return fname;
+#endif
for (dp = path;; dp = ++ep) {
register int l;
@@ -1339,7 +1343,11 @@ dln_find_1(fname, path, exe_flag)
int fspace;
/* extract a component */
+#if !defined(MSDOS) && !defined(NT) && !defined(__human68k__)
ep = strchr(dp, ':');
+#else
+ ep = strchr(dp, ';');
+#endif
if (ep == NULL)
ep = dp+strlen(dp);
@@ -1399,6 +1407,34 @@ dln_find_1(fname, path, exe_flag)
/* looking for executable */
if (eaccess(fbuf, X_OK) == 0) return fbuf;
}
+#if defined(MSDOS) || defined(NT) || defined(__human68k__)
+ if (exe_flag) {
+ static const char *extension[] = {
+#if defined(MSDOS)
+ ".com", ".exe", ".bat",
+#if defined(DJGPP)
+ ".btm", ".sh", ".ksh", ".pl", ".sed",
+#endif
+#else
+ ".r", ".R", ".x", ".X", ".bat", ".BAT",
+#endif
+ (char *) NULL
+ };
+ int j;
+
+ for (j = 0; extension[j]; j++) {
+ if (fspace < strlen(extension[j])) {
+ fprintf(stderr, "openpath: pathname too long (ignored)\n");
+ fprintf(stderr, "\tDirectory \"%.*s\"\n", (int) (bp - fbuf), fbuf);
+ fprintf(stderr, "\tFile \"%s%s\"\n", fname, extension[j]);
+ continue;
+ }
+ strcpy(bp + i, extension[j]);
+ if (stat(fbuf, &st) == 0)
+ return fbuf;
+ }
+ }
+#endif /* MSDOS or NT or __human68k__ */
/* if not, and no other alternatives, life is bleak */
if (*ep == '\0') {
return NULL;
diff --git a/enum.c b/enum.c
index 5ec71bce42..63ef9e9371 100644
--- a/enum.c
+++ b/enum.c
@@ -90,8 +90,10 @@ enum_find(argc, argv, obj)
if (arg.found) {
return arg.val;
}
- if (NIL_P(if_none)) return Qnil;
- return rb_eval_cmd(if_none, Qnil);
+ if (!NIL_P(if_none)) {
+ rb_eval_cmd(if_none, Qnil);
+ }
+ return Qnil;
}
static void
@@ -275,7 +277,7 @@ index_i(item, iv)
VALUE item;
struct i_v_pair *iv;
{
- if (rb_equal(item, 1, iv->v)) {
+ if (rb_equal(item, iv->v)) {
iv->found = 1;
rb_break();
}
@@ -357,6 +359,7 @@ Init_Enumerable()
rb_define_method(mEnumerable,"max", enum_max, 0);
rb_define_method(mEnumerable,"index", enum_index, 1);
rb_define_method(mEnumerable,"member?", enum_member, 1);
+ rb_define_method(mEnumerable,"include?", enum_member, 1);
rb_define_method(mEnumerable,"length", enum_length, 0);
rb_define_method(mEnumerable,"size", enum_length, 0);
diff --git a/error.c b/error.c
index d1c465b78f..5291d9ea76 100644
--- a/error.c
+++ b/error.c
@@ -159,7 +159,7 @@ static struct types {
extern void TypeError();
void
-Check_Type(x, t)
+rb_check_type(x, t)
VALUE x;
int t;
{
@@ -191,12 +191,13 @@ VALUE eNameError;
VALUE eIndexError;
VALUE eNotImpError;
VALUE eLoadError;
+VALUE eSecurityError;
VALUE eSystemCallError;
VALUE mErrno;
VALUE
-exc_new0(etype, ptr, len)
+exc_new(etype, ptr, len)
VALUE etype;
char *ptr;
UINT len;
@@ -215,15 +216,15 @@ exc_new0(etype, ptr, len)
}
VALUE
-exc_new(etype, s)
+exc_new2(etype, s)
VALUE etype;
char *s;
{
- return exc_new0(etype, s, strlen(s));
+ return exc_new(etype, s, strlen(s));
}
VALUE
-exc_new2(etype, str)
+exc_new3(etype, str)
VALUE etype;
struct RString *str;
{
@@ -240,21 +241,70 @@ exc_s_new(argc, argv, etype)
VALUE arg;
if (rb_scan_args(argc, argv, "01", &arg) == 0) {
- return exc_new0(etype, 0, 0);
+ return exc_new(etype, 0, 0);
}
Check_Type(arg, T_STRING);
- return exc_new2(etype, arg);
+ return exc_new3(etype, arg);
+}
+
+static VALUE
+exc_inspect(exc)
+ VALUE exc;
+{
+ struct RString *classpath = RSTRING(rb_class_path(CLASS_OF(exc)));
+ VALUE str = str_new(classpath->ptr, classpath->len);
+
+ str_cat(str, ":", 1);
+ if (RSTRING(exc)->len == 0) {
+ str_cat(str, "\"\"", 2);
+ }
+ str_cat(str, RSTRING(exc)->ptr, RSTRING(exc)->len);
+ return str;
+}
+
+static VALUE
+exception(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ void ArgError();
+ VALUE v = Qnil;
+ int i;
+ ID id;
+
+ if (argc == 0) {
+ ArgError("wrong # of arguments");
+ }
+ for (i=0; i<argc; i++) { /* argument check */
+ id = rb_to_id(argv[i]);
+ if (!rb_id2name(id)) {
+ ArgError("argument needs to be symbol or string");
+ }
+ if (!rb_is_const_id(id)) {
+ ArgError("identifier %s needs to be constant", rb_id2name(id));
+ }
+ }
+ for (i=0; i<argc; i++) {
+ v = rb_define_class(rb_id2name(rb_to_id(argv[i])), eException);
+ }
+ return v;
}
static VALUE *syserr_list;
+#ifndef NT
+extern int sys_nerr;
+#endif
+
static void
set_syserr(i, name)
int i;
char *name;
{
- syserr_list[i] = rb_define_class_under(mErrno, name, eSystemCallError);
- rb_global_variable(&syserr_list[i]);
+ if (i <= sys_nerr) {
+ syserr_list[i] = rb_define_class_under(mErrno, name, eSystemCallError);
+ rb_global_variable(&syserr_list[i]);
+ }
}
static void init_syserr();
@@ -264,6 +314,7 @@ Init_Exception()
{
eGlobalExit = rb_define_class("GlobalExit", cString);
rb_define_method(eGlobalExit, "new", exc_s_new, -1);
+ rb_define_method(eGlobalExit, "inspect", exc_inspect, 0);
eSystemExit = rb_define_class("SystemExit", eGlobalExit);
eFatal = rb_define_class("fatal", eGlobalExit);
@@ -279,8 +330,11 @@ Init_Exception()
eLoadError = rb_define_class("LoadError", eException);
eRuntimeError = rb_define_class("RuntimeError", eException);
+ eSecurityError = rb_define_class("SecurityError", eException);
init_syserr();
+
+ rb_define_global_function("Exception", exception, -1);
}
#define RAISE_ERROR(class) {\
@@ -291,11 +345,12 @@ Init_Exception()
vsprintf(buf, fmt, args);\
va_end(args);\
\
- rb_raise(exc_new(class, buf));\
+ rb_raise(exc_new2(class, buf));\
}
void
Raise(exc, fmt, va_alist)
+ VALUE exc;
char *fmt;
va_dcl
{
@@ -371,14 +426,16 @@ Fatal(fmt, va_alist)
va_end(args);
rb_in_eval = 0;
- rb_fatal(exc_new(eFatal, buf));
+ rb_fatal(exc_new2(eFatal, buf));
}
void
rb_sys_fail(mesg)
char *mesg;
{
+#ifndef NT
char *strerror();
+#endif
char buf[BUFSIZ];
extern int errno;
int n = errno;
@@ -389,17 +446,15 @@ rb_sys_fail(mesg)
sprintf(buf, "%s", strerror(errno));
errno = 0;
- if (!syserr_list[n]) {
+ if (n > sys_nerr || !syserr_list[n]) {
char name[6];
sprintf(name, "E%03d", n);
set_syserr(n, name);
}
- rb_raise(exc_new(syserr_list[n], buf));
+ rb_raise(exc_new2(syserr_list[n], buf));
}
-extern int sys_nerr;
-
static void
init_syserr()
{
diff --git a/eval.c b/eval.c
index 2f2ee5923a..564ff9a7ad 100644
--- a/eval.c
+++ b/eval.c
@@ -6,7 +6,7 @@
$Date: 1996/12/25 08:54:45 $
created at: Thu Jun 10 14:22:17 JST 1993
- Copyright (C) 1993-1995 Yukihiro Matsumoto
+ Copyright (C) 1993-1997 Yukihiro Matsumoto
************************************************/
@@ -26,8 +26,17 @@
char *strrchr();
#endif
-static VALUE cProc;
+#ifndef setjmp
+#ifdef HAVE__SETJMP
+#define setjmp(env) _setjmp(env)
+#define longjmp(env,val) _longjmp(env,val)
+#endif
+#endif
+
+extern VALUE cData;
+VALUE cProc;
static VALUE proc_call();
+static VALUE f_binding();
#define CACHE_SIZE 0x200
#define CACHE_MASK 0x1ff
@@ -45,6 +54,18 @@ struct cache_entry { /* method hash table. */
static struct cache_entry cache[CACHE_SIZE];
void
+rb_clear_cache()
+{
+ struct cache_entry *ent, *end;
+
+ ent = cache; end = ent + CACHE_SIZE;
+ while (ent < end) {
+ ent->mid = 0;
+ ent++;
+ }
+}
+
+void
rb_add_method(class, mid, node, noex)
struct RClass *class;
ID mid;
@@ -118,21 +139,31 @@ rb_alias(class, name, def)
ID name, def;
{
struct RClass *origin;
- NODE *body, *old;
+ NODE *orig, *body;
if (name == def) return;
- body = search_method(class, def, &origin);
- if (!body || !body->nd_body) {
- NameError("undefined method `%s' for class `%s'",
- rb_id2name(def), rb_class2name(class));
+ orig = search_method(class, def, &origin);
+ if (!orig || !orig->nd_body) {
+ if (TYPE(class) == T_MODULE) {
+ orig = search_method(cObject, def, &origin);
+ }
+ }
+ if (!orig || !orig->nd_body) {
+ NameError("undefined method `%s' for `%s'",
+ rb_id2name(def), rb_class2name((VALUE)class));
+ }
+ body = orig->nd_body;
+ if (nd_type(body) == NODE_FBODY) { /* was alias */
+ body = body->nd_head;
+ def = body->nd_mid;
+ origin = (struct RClass*)body->nd_orig;
}
st_insert(class->m_tbl, name,
- NEW_METHOD(NEW_FBODY(body->nd_body, def, origin),
- body->nd_noex));
+ NEW_METHOD(NEW_FBODY(body, def, origin), orig->nd_noex));
}
-void
+static void
rb_export_method(class, name, noex)
struct RClass *class;
ID name;
@@ -142,15 +173,19 @@ rb_export_method(class, name, noex)
struct RClass *origin;
body = search_method(class, name, &origin);
+ if (!body && TYPE(class) == T_MODULE) {
+ body = search_method(cObject, name, &origin);
+ }
if (!body) {
- NameError("undefined method `%s' for class `%s'",
- rb_id2name(name), rb_class2name(class));
+ NameError("undefined method `%s' for `%s'",
+ rb_id2name(name), rb_class2name((VALUE)class));
}
if (body->nd_noex != noex) {
if (class == origin) {
body->nd_noex = noex;
}
else {
+ rb_clear_cache();
rb_add_method(class, name, NEW_ZSUPER(), noex);
}
}
@@ -173,33 +208,25 @@ method_boundp(class, id, ex)
}
int
-rb_method_boundp(class, id)
- struct RClass *class;
+rb_method_boundp(class, id, priv)
+ VALUE class;
ID id;
+ int priv;
{
- if (method_boundp(class, id, NOEX_PRIVATE))
+ if (method_boundp(class, id, priv?NOEX_PRIVATE:NOEX_PUBLIC))
return TRUE;
return FALSE;
}
-void
-rb_clear_cache()
-{
- struct cache_entry *ent, *end;
-
- ent = cache; end = ent + CACHE_SIZE;
- while (ent < end) {
- ent->mid = 0;
- ent++;
- }
-}
-
static ID init, eqq, each, aref, aset;
VALUE errinfo = Qnil, errat = Qnil;
extern NODE *eval_tree;
extern int nerrs;
-extern VALUE cKernel;
+extern VALUE mKernel;
+extern VALUE cModule;
+extern VALUE cClass;
+extern VALUE eFatal;
extern VALUE eGlobalExit;
extern VALUE eInterrupt;
extern VALUE eSystemExit;
@@ -207,6 +234,7 @@ extern VALUE eException;
extern VALUE eRuntimeError;
extern VALUE eSyntaxError;
static VALUE eLocalJumpError;
+extern VALUE eSecurityError;
extern VALUE TopSelf;
@@ -236,12 +264,15 @@ struct BLOCK {
int level;
int iter;
struct RVarmap *d_vars;
+#ifdef THREAD
+ VALUE orig_thread;
+#endif
struct BLOCK *prev;
} *the_block;
#define PUSH_BLOCK(v,b) { \
struct BLOCK _block; \
- _block.level = (int)&prot_tag; \
+ _block.level = (int)prot_tag; \
_block.var = v; \
_block.body = b; \
_block.self = self; \
@@ -260,7 +291,7 @@ struct BLOCK {
_block = *b; \
_block.prev = the_block; \
the_block = &_block;
-
+
#define POP_BLOCK() \
the_block = the_block->prev; \
}
@@ -268,9 +299,12 @@ struct BLOCK {
struct RVarmap *the_dyna_vars;
#define PUSH_VARS() { \
struct RVarmap *_old; \
- _old = the_dyna_vars;
+ _old = the_dyna_vars; \
+ the_dyna_vars = 0;
-#define POP_VARS() the_dyna_vars = _old; }
+#define POP_VARS() \
+ the_dyna_vars = _old; \
+}
VALUE
dyna_var_defined(id)
@@ -278,7 +312,7 @@ dyna_var_defined(id)
{
struct RVarmap *vars = the_dyna_vars;
- while (vars && vars->id) {
+ while (vars) {
if (vars->id == id) return TRUE;
vars = vars->next;
}
@@ -291,7 +325,7 @@ dyna_var_ref(id)
{
struct RVarmap *vars = the_dyna_vars;
- while (vars && vars->id) {
+ while (vars) {
if (vars->id == id) {
return vars->val;
}
@@ -307,7 +341,7 @@ dyna_var_asgn(id, value)
{
struct RVarmap *vars = the_dyna_vars;
- while (vars && vars->id) {
+ while (vars) {
if (vars->id == id) {
vars->val = value;
return value;
@@ -325,17 +359,6 @@ dyna_var_asgn(id, value)
return value;
}
-static VALUE
-dyna_var_mark()
-{
- NEWOBJ(_vars, struct RVarmap);
- OBJSETUP(_vars, 0, T_VARMAP);
- _vars->id = 0;
- _vars->val = Qnil;
- _vars->next = the_dyna_vars;
- the_dyna_vars = _vars;
-}
-
static struct iter {
int iter;
struct iter *prev;
@@ -378,7 +401,7 @@ static struct tag {
}
#define JUMP_TAG3(val,data1,data2) \
- JUMP_TAG(newnode(NODE_TAG,(val),(data1),(data2)))
+ JUMP_TAG(node_newnode(NODE_TAG,(val),(data1),(data2)))
#define JUMP_TAG2(val,data) JUMP_TAG3((val),(data),0)
@@ -408,6 +431,9 @@ struct RClass *the_class;
struct SCOPE *_old; \
NEWOBJ(_scope, struct SCOPE); \
OBJSETUP(_scope, 0, T_SCOPE); \
+ _scope->local_tbl = 0; \
+ _scope->local_vars = 0; \
+ _scope->flag = 0; \
_old = the_scope; \
the_scope = _scope; \
@@ -415,8 +441,12 @@ struct RClass *the_class;
if (the_scope->flag == SCOPE_ALLOCA) {\
the_scope->local_vars = 0;\
the_scope->local_tbl = 0;\
+ if (the_scope != top_scope)\
+ gc_force_recycle(the_scope);\
+ }\
+ else {\
+ the_scope->flag |= SCOPE_NOSTACK;\
}\
- the_scope->flag |= SCOPE_NOSTACK;\
the_scope = _old;\
}
@@ -426,40 +456,110 @@ static NODE *compile();
static VALUE rb_call();
VALUE rb_apply();
+VALUE rb_funcall2();
+
+static VALUE module_setup();
+
+static VALUE massign();
+static void assign();
+
+static int safe_level = 0;
+/* safe-level:
+ 0 - strings from streams/environment/ARGV are tainted (default)
+ 1 - no dangerous operation by tainted string
+ 2 - some process operations prohibited
+ 3 - all genetated strings are tainted
+ 4 - no global variable value modification/no direct output
+ 5 - no instance variable value modification
+*/
+
+int
+rb_safe_level()
+{
+ return safe_level;
+}
-static void module_setup();
+void
+rb_set_safe_level(level)
+ int level;
+{
+ if (level > safe_level) {
+ safe_level = level;
+ }
+}
+
+static VALUE
+safe_getter()
+{
+ return INT2FIX(safe_level);
+}
-static VALUE masign();
-static void asign();
+static void
+safe_setter(val)
+ VALUE val;
+{
+ int level = NUM2INT(val);
-extern VALUE rb_stderr;
+ if (level < safe_level) {
+ Raise(eSecurityError, "tried to downgrade safe level from %d to %d",
+ safe_level, level);
+ }
+ safe_level = level;
+}
+
+void
+rb_check_safe_str(x)
+ VALUE x;
+{
+ if (TYPE(x)!= T_STRING) {
+ TypeError("wrong argument type %s (expected String)",
+ rb_class2name(CLASS_OF(x)));
+ }
+ if (rb_safe_level() > 0 && str_tainted(x)) {
+ Raise(eSecurityError, "Insecure operation - %s",
+ rb_id2name(the_frame->last_func));
+ }
+}
+
+void
+rb_secure(level)
+ int level;
+{
+ if (level <= safe_level) {
+ Raise(eSecurityError, "Insecure operation `%s' for level %d",
+ rb_id2name(the_frame->last_func), level);
+ }
+}
extern int sourceline;
extern char *sourcefile;
+static VALUE trace_func = 0;
+static void call_trace_func();
+
static void
error_pos()
{
if (sourcefile) {
if (the_frame->last_func) {
- fprintf(stderr, "%s:%d:in `%s': ", sourcefile, sourceline,
+ fprintf(stderr, "%s:%d:in `%s'", sourcefile, sourceline,
rb_id2name(the_frame->last_func));
}
else {
- fprintf(stderr, "%s:%d: ", sourcefile, sourceline);
+ fprintf(stderr, "%s:%d", sourcefile, sourceline);
}
}
}
static void
-error_print(state)
- NODE *state;
+error_print()
{
- struct FRAME *frame = the_frame;
- VALUE etype;
+ VALUE eclass;
+
+ if (NIL_P(errinfo)) return;
if (!NIL_P(errat)) {
- VALUE mesg;
+ VALUE mesg = Qnil;
switch (TYPE(errat)) {
case T_STRING:
@@ -470,26 +570,36 @@ error_print(state)
mesg = RARRAY(errat)->ptr[0];
break;
}
- fwrite(RSTRING(mesg)->ptr, 1, RSTRING(mesg)->len, stderr);
- fprintf(stderr, ": ");
+ if (NIL_P(mesg)) error_pos();
+ else {
+ fwrite(RSTRING(mesg)->ptr, 1, RSTRING(mesg)->len, stderr);
+ }
}
- etype = rb_class_path(CLASS_OF(errinfo));
-
- if (verbose) {
- fwrite(RSTRING(etype)->ptr, 1, RSTRING(etype)->len, stderr);
- putc('|', stderr);
- }
- if (RSTRING(errinfo)->len == 0) {
- fprintf(stderr, "unhandled exception.\n");
+ eclass = CLASS_OF(errinfo);
+ if (eclass == eRuntimeError && RSTRING(errinfo)->len == 0) {
+ fprintf(stderr, ": unhandled exception\n");
}
else {
- fwrite(RSTRING(errinfo)->ptr, 1, RSTRING(errinfo)->len, stderr);
+ PUSH_TAG();
+ if (EXEC_TAG() == 0) {
+ VALUE epath = rb_class_path(eclass);
+ if (RSTRING(epath)->ptr[0] != '#') {
+ fprintf(stderr, ": ");
+ fwrite(RSTRING(epath)->ptr, 1, RSTRING(epath)->len, stderr);
+ }
+ }
+ POP_TAG();
+
+ if (RSTRING(errinfo)->len > 0) {
+ fprintf(stderr, ": ");
+ fwrite(RSTRING(errinfo)->ptr, 1, RSTRING(errinfo)->len, stderr);
+ }
if (RSTRING(errinfo)->ptr[RSTRING(errinfo)->len - 1] != '\n') {
putc('\n', stderr);
}
}
-
+
if (!NIL_P(errat)) {
int i;
struct RArray *ep = RARRAY(errat);
@@ -509,13 +619,17 @@ error_print(state)
}
}
+#ifndef NT
extern char **environ;
+#endif
char **origenviron;
+#if (_MSC_VER >= 1000)
+__declspec(dllexport) void __stdcall
+#else
void
-ruby_init(argc, argv, envp)
- int argc;
- char **argv, **envp;
+#endif
+ruby_init()
{
static struct FRAME frame;
static struct iter iter;
@@ -525,9 +639,6 @@ ruby_init(argc, argv, envp)
the_iter = &iter;
origenviron = environ;
-#ifdef NT
- NtInitialize(&argc, &argv);
-#endif
init_heap();
PUSH_SCOPE();
@@ -539,15 +650,43 @@ ruby_init(argc, argv, envp)
if ((state = EXEC_TAG()) == 0) {
rb_call_inits();
the_class = (struct RClass*)cObject;
- the_frame->cbase = (VALUE)newnode(NODE_CREF,cObject,0,0);
- ruby_options(argc, argv, envp);
+ the_frame->cbase = (VALUE)node_newnode(NODE_CREF,cObject,0,0);
+ rb_define_global_const("TOPLEVEL_BINDING", f_binding(TopSelf));
+ ruby_prog_init();
}
POP_TAG();
- if (state) error_print(state);
+ if (state) error_print();
POP_SCOPE();
the_scope = top_scope;
}
+static int ext_init = 0;
+
+#if (_MSC_VER >= 1000)
+__declspec(dllexport) void __stdcall
+#else
+void
+#endif
+ruby_options(argc, argv)
+ int argc;
+ char **argv;
+{
+ NODE *state;
+
+ PUSH_TAG()
+ if ((state = EXEC_TAG()) == 0) {
+ NODE *save = eval_tree;
+
+ Init_ext();
+ ext_init = 1;
+ rb_require_modules();
+ eval_tree = save;
+ ruby_process_options(argc, argv);
+ }
+ POP_TAG();
+ if (state) error_print();
+}
+
static VALUE
eval_node(self)
VALUE self;
@@ -555,7 +694,7 @@ eval_node(self)
VALUE result = Qnil;
NODE *tree;
- if (!eval_tree) return FALSE;
+ if (!eval_tree) return Qnil;
tree = eval_tree;
eval_tree = 0;
@@ -569,11 +708,16 @@ int rb_in_eval;
#ifdef THREAD
static void thread_cleanup();
static void thread_wait_other_threads();
+static VALUE thread_current();
#endif
static int exit_status;
+#if (_MSC_VER >= 1000)
+__declspec(dllexport) void __stdcall
+#else
void
+#endif
ruby_run()
{
NODE *state;
@@ -587,6 +731,7 @@ ruby_run()
PUSH_TAG();
PUSH_ITER(ITER_NOT);
if ((state = EXEC_TAG()) == 0) {
+ if (!ext_init) Init_ext();
eval_node(TopSelf);
}
POP_ITER();
@@ -613,6 +758,7 @@ ruby_run()
}
switch (ex->nd_tag) {
+ case IN_BLOCK|TAG_RETURN:
case TAG_RETURN:
error_pos();
fprintf(stderr, "unexpected return\n");
@@ -623,6 +769,7 @@ ruby_run()
fprintf(stderr, "unexpected next\n");
exit(1);
break;
+ case IN_BLOCK|TAG_BREAK:
case TAG_BREAK:
error_pos();
fprintf(stderr, "unexpected break\n");
@@ -635,7 +782,7 @@ ruby_run()
break;
case TAG_RETRY:
error_pos();
- fprintf(stderr, "retry outside of protect clause\n");
+ fprintf(stderr, "retry outside of rescue clause\n");
exit(1);
break;
case TAG_RAISE:
@@ -643,7 +790,7 @@ ruby_run()
if (obj_is_kind_of(errinfo, eSystemExit)) {
exit(exit_status);
}
- error_print(ex);
+ error_print();
exit(1);
break;
case TAG_THROW:
@@ -665,7 +812,7 @@ compile_error(at)
mesg = errinfo;
nerrs = 0;
- errinfo = exc_new(eSyntaxError, "compile error in ");
+ errinfo = exc_new2(eSyntaxError, "compile error in ");
str_cat(errinfo, at, strlen(at));
str_cat(errinfo, ":\n", 2);
str_cat(errinfo, RSTRING(mesg)->ptr, RSTRING(mesg)->len);
@@ -692,6 +839,7 @@ rb_eval_cmd(cmd, arg)
{
NODE *state;
struct SCOPE *saved_scope;
+ volatile int safe = rb_safe_level();
if (TYPE(cmd) != T_STRING) {
if (obj_is_kind_of(cmd, cProc)) {
@@ -706,12 +854,16 @@ rb_eval_cmd(cmd, arg)
the_scope = top_scope;
the_class = (struct RClass*)cObject;
+ if (str_tainted(cmd)) {
+ safe_level = 5;
+ }
if ((state = EXEC_TAG()) == 0) {
eval(TopSelf, cmd, Qnil);
}
the_scope = saved_scope;
+ safe_level = safe;
POP_TAG();
POP_CLASS();
@@ -730,7 +882,7 @@ rb_eval_cmd(cmd, arg)
Raise(eLocalJumpError, "unexpected redo");
break;
case TAG_RETRY:
- Raise(eLocalJumpError, "retry outside of protect clause");
+ Raise(eLocalJumpError, "retry outside of rescue clause");
break;
default:
JUMP_TAG(state);
@@ -761,7 +913,7 @@ superclass(self, node)
VALUE self;
NODE *node;
{
- VALUE val;
+ VALUE val = 0;
NODE *state;
PUSH_TAG();
@@ -769,18 +921,24 @@ superclass(self, node)
val = rb_eval(self, node);
}
POP_TAG();
- if ((state && state->nd_tag == TAG_RAISE) || !val || TYPE(val) != T_CLASS){
- switch (nd_type(node)) {
- case NODE_COLON2:
- TypeError("undefined superclass `%s'", rb_id2name(node->nd_mid));
- case NODE_CVAR:
- case NODE_CONST:
- TypeError("undefined superclass `%s'", rb_id2name(node->nd_vid));
+ if (state) {
+ if (state->nd_tag == TAG_RAISE) {
+ superclass_error:
+ switch (nd_type(node)) {
+ case NODE_COLON2:
+ TypeError("undefined superclass `%s'", rb_id2name(node->nd_mid));
+ case NODE_CVAR:
+ TypeError("undefined superclass `%s'", rb_id2name(node->nd_vid));
+ default:
+ TypeError("superclass undefined");
+ }
}
- if (state) JUMP_TAG(state);
- TypeError("superclass undefined");
+ JUMP_TAG(state);
+ }
+ if (TYPE(val) != T_CLASS) goto superclass_error;
+ if (FL_TEST(val, FL_SINGLETON)) {
+ TypeError("can't make subclass of virtual class");
}
- if (state) JUMP_TAG(state);
return val;
}
@@ -824,8 +982,8 @@ ev_const_get(cref, id)
return rb_const_get(cref->nd_clss, id);
}
-#define SETUP_ARGS {\
- NODE *n = node->nd_args;\
+#define SETUP_ARGS(anode) {\
+ NODE *n = anode;\
if (!n) {\
argc = 0;\
argv = 0;\
@@ -834,14 +992,15 @@ ev_const_get(cref, id)
argc=n->nd_alen;\
if (argc > 0) {\
int i;\
- n = node->nd_args;\
+ int line = sourceline;\
+ n = anode;\
argv = ALLOCA_N(VALUE,argc);\
for (i=0;i<argc;i++) {\
argv[i] = rb_eval(self,n->nd_head);\
n=n->nd_next;\
}\
- sourceline = nd_line(node);\
- sourcefile = node->file;\
+ sourcefile = anode->file;\
+ sourceline = line;\
}\
else {\
argc = 0;\
@@ -850,13 +1009,14 @@ ev_const_get(cref, id)
}\
else {\
VALUE args = rb_eval(self,n);\
+ int line = sourceline;\
if (TYPE(args) != T_ARRAY)\
args = rb_to_a(args);\
argc = RARRAY(args)->len;\
argv = ALLOCA_N(VALUE, argc);\
MEMCPY(argv, RARRAY(args)->ptr, VALUE, argc);\
- sourceline = nd_line(node);\
- sourcefile = node->file;\
+ sourcefile = anode->file;\
+ sourceline = line;\
}\
}
@@ -867,25 +1027,225 @@ rb_test_false_or_nil(v)
return (v != Qnil) && (v != FALSE);
}
+#define MATCH_DATA the_scope->local_vars[node->nd_cnt]
+
+static char*
+is_defined(self, node, buf)
+ VALUE self;
+ NODE *node; /* OK */
+ char *buf;
+{
+ VALUE val; /* OK */
+ NODE *state;
+
+ node = node->nd_head;
+
+ switch (nd_type(node)) {
+ case NODE_SUPER:
+ case NODE_ZSUPER:
+ if (the_frame->last_func == 0) return 0;
+ else if (method_boundp(the_frame->last_class->super,
+ the_frame->last_func, 1)) {
+ return "super";
+ }
+ break;
+
+ case NODE_FCALL:
+ case NODE_VCALL:
+ val = CLASS_OF(self);
+ goto check_bound;
+
+ case NODE_CALL:
+ PUSH_TAG();
+ if ((state = EXEC_TAG()) == 0) {
+ val = rb_eval(self, node->nd_recv);
+ val = CLASS_OF(val);
+ }
+ POP_TAG();
+ if (state) {
+ return 0;
+ }
+ check_bound:
+ if (method_boundp(val, node->nd_mid,
+ nd_type(node)== NODE_CALL)) {
+ return "method";
+ }
+ break;
+
+ case NODE_YIELD:
+ if (iterator_p()) {
+ return "yield";
+ }
+ break;
+
+ case NODE_SELF:
+ return "self";
+
+ case NODE_NIL:
+ return "nil";
+
+ case NODE_ATTRSET:
+ case NODE_OP_ASGN1:
+ case NODE_OP_ASGN2:
+ case NODE_MASGN:
+ case NODE_LASGN:
+ case NODE_DASGN:
+ case NODE_GASGN:
+ case NODE_IASGN:
+ case NODE_CASGN:
+ return "assignment";
+
+ case NODE_LVAR:
+ case NODE_DVAR:
+ return "local-variable";
+
+ case NODE_GVAR:
+ if (rb_gvar_defined(node->nd_entry)) {
+ return "global-variable";
+ }
+ break;
+
+ case NODE_IVAR:
+ if (rb_ivar_defined(self, node->nd_vid)) {
+ return "instance-variable";
+ }
+ break;
+
+ case NODE_CVAR:
+ if (ev_const_defined(the_frame->cbase, node->nd_vid)) {
+ return "constant";
+ }
+ break;
+
+ case NODE_COLON2:
+ PUSH_TAG();
+ if ((state = EXEC_TAG()) == 0) {
+ val = rb_eval(self, node->nd_head);
+ }
+ POP_TAG();
+ if (state) {
+ return 0;
+ }
+ else {
+ switch (TYPE(val)) {
+ case T_CLASS:
+ case T_MODULE:
+ if (rb_const_defined_at(val, node->nd_mid))
+ return "constant";
+ }
+ }
+ break;
+
+ case NODE_NTH_REF:
+ if (reg_nth_defined(node->nd_nth, MATCH_DATA)) {
+ sprintf(buf, "$%d", node->nd_nth);
+ return buf;
+ }
+ break;
+
+ case NODE_BACK_REF:
+ if (reg_nth_defined(0, MATCH_DATA)) {
+ sprintf(buf, "$%c", node->nd_nth);
+ return buf;
+ }
+ break;
+
+ default:
+ PUSH_TAG();
+ if ((state = EXEC_TAG()) == 0) {
+ rb_eval(self, node);
+ }
+ POP_TAG();
+ if (!state) {
+ return "expression";
+ }
+ break;
+ }
+ return 0;
+}
+
static int handle_rescue();
VALUE rb_yield_0();
+static void blk_free();
+
+static VALUE
+set_trace_func(obj, trace)
+ VALUE obj;
+ struct RData *trace;
+{
+ if (NIL_P(trace)) {
+ trace_func = 0;
+ return Qnil;
+ }
+ if (TYPE(trace) != T_DATA || trace->dfree != blk_free) {
+ TypeError("trace_func needs to be Proc");
+ }
+ return trace_func = (VALUE)trace;
+}
+
+static void
+call_trace_func(event, file, line, self, id)
+ char *event;
+ char *file;
+ int line;
+ VALUE self;
+ ID id;
+{
+ NODE *state;
+ volatile VALUE trace;
+ struct FRAME *prev;
+
+ if (!trace_func) return;
+
+ trace = trace_func;
+ trace_func = 0;
+#ifdef THREAD
+ thread_critical++;
+#endif
+
+ prev = the_frame;
+ PUSH_FRAME();
+ *the_frame = *_frame.prev;
+ the_frame->prev = prev;
+
+ the_frame->line = sourceline = line;
+ the_frame->file = sourcefile = file;
+ PUSH_TAG();
+ if ((state = EXEC_TAG()) == 0) {
+ proc_call(trace, ary_new3(5, str_new2(event),
+ str_new2(sourcefile),
+ INT2FIX(sourceline),
+ INT2FIX(id),
+ self?f_binding(self):Qnil));
+ }
+ POP_TAG();
+ POP_FRAME();
+
+#ifdef THREAD
+ thread_critical--;
+#endif
+ if (!trace_func) trace_func = trace;
+ if (state) JUMP_TAG(state);
+}
+
static VALUE
rb_eval(self, node)
VALUE self;
- register NODE *node;
+ NODE * volatile node;
{
NODE *state;
- VALUE result = Qnil;
+ volatile VALUE result = Qnil;
#define RETURN(v) { result = (v); goto finish; }
again:
if (!node) RETURN(Qnil);
+#if 0
sourceline = nd_line(node);
sourcefile = node->file;
-
+#endif
switch (nd_type(node)) {
case NODE_BLOCK:
while (node) {
@@ -926,15 +1286,6 @@ rb_eval(self, node)
}
goto again;
- case NODE_UNLESS:
- if (!RTEST(rb_eval(self, node->nd_cond))) {
- node = node->nd_body;
- }
- else {
- node = node->nd_else;
- }
- goto again;
-
case NODE_CASE:
{
VALUE val;
@@ -945,13 +1296,17 @@ rb_eval(self, node)
NODE *tag;
if (nd_type(node) != NODE_WHEN) {
-
- RETURN(rb_eval(self, node));
+ goto again;
}
tag = node->nd_head;
while (tag) {
+ if (trace_func) {
+ call_trace_func("line", tag->file, nd_line(tag),
+ self, the_frame->last_func);
+ }
if (RTEST(rb_funcall2(rb_eval(self, tag->nd_head),eqq,1,&val))){
- RETURN(rb_eval(self, node->nd_body));
+ node = node->nd_body;
+ goto again;
}
tag = tag->nd_next;
}
@@ -963,15 +1318,14 @@ rb_eval(self, node)
case NODE_WHILE:
PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
- while_next:
- for (;;) {
- if (node->nd_state && !RTEST(rb_eval(self, node->nd_cond)))
- break;
+ if (node->nd_state && !RTEST(rb_eval(self, node->nd_cond)))
+ goto while_out;
+ do {
while_redo:
rb_eval(self, node->nd_body);
- if (!node->nd_state && !RTEST(rb_eval(self, node->nd_cond)))
- break;
- }
+ while_next:
+ ;
+ } while (RTEST(rb_eval(self, node->nd_cond)));
}
else {
switch (state->nd_tag) {
@@ -981,12 +1335,15 @@ rb_eval(self, node)
case TAG_NEXT:
state = 0;
goto while_next;
+ case TAG_BREAK:
+ state = 0;
default:
break;
}
}
+ while_out:
POP_TAG();
- if (state && state->nd_tag != TAG_BREAK) {
+ if (state) {
JUMP_TAG(state);
}
RETURN(Qnil);
@@ -994,30 +1351,32 @@ rb_eval(self, node)
case NODE_UNTIL:
PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
- until_next:
- for (;;) {
- if (node->nd_state && RTEST(rb_eval(self, node->nd_cond)))
- break;
+ if (node->nd_state && RTEST(rb_eval(self, node->nd_cond)))
+ goto until_out;
+ do {
until_redo:
rb_eval(self, node->nd_body);
- if (!node->nd_state && RTEST(rb_eval(self, node->nd_cond)))
- break;
- }
+ until_next:
+ ;
+ } while (!RTEST(rb_eval(self, node->nd_cond)));
}
else {
switch (state->nd_tag) {
case TAG_REDO:
state = 0;
- goto while_redo;
+ goto until_redo;
case TAG_NEXT:
state = 0;
- goto while_next;
+ goto until_next;
+ case TAG_BREAK:
+ state = 0;
default:
break;
}
}
+ until_out:
POP_TAG();
- if (state && state->nd_tag != TAG_BREAK) {
+ if (state) {
JUMP_TAG(state);
}
RETURN(Qnil);
@@ -1040,11 +1399,12 @@ rb_eval(self, node)
}
else {
VALUE recv;
+ int line = sourceline;
recv = rb_eval(self, node->nd_iter);
PUSH_ITER(ITER_PRE);
- sourceline = nd_line(node);
sourcefile = node->file;
+ sourceline = line;
result = rb_call(CLASS_OF(recv),recv,each,0,0,0);
POP_ITER();
}
@@ -1080,39 +1440,44 @@ rb_eval(self, node)
case NODE_RESCUE:
retry_entry:
- PUSH_TAG();
- if ((state = EXEC_TAG()) == 0) {
- result = rb_eval(self, node->nd_head);
- }
- POP_TAG();
- if (state) {
- if (state->nd_tag == TAG_RAISE) {
- NODE *resq = node->nd_resq;
- while (resq) {
- if (handle_rescue(self, resq)) {
- state = 0;
- PUSH_TAG();
- if ((state = EXEC_TAG()) == 0) {
- result = rb_eval(self, resq->nd_body);
- }
- POP_TAG();
- if (state == 0) {
- errat = Qnil;
- }
- else if (state->nd_tag == TAG_RETRY) {
+ {
+ volatile VALUE e_info = errinfo, e_at = errat;
+
+ PUSH_TAG();
+ if ((state = EXEC_TAG()) == 0) {
+ result = rb_eval(self, node->nd_head);
+ }
+ POP_TAG();
+ if (state) {
+ if (state->nd_tag == TAG_RAISE) {
+ NODE * volatile resq = node->nd_resq;
+ while (resq) {
+ if (handle_rescue(self, resq)) {
state = 0;
- goto retry_entry;
+ PUSH_TAG();
+ if ((state = EXEC_TAG()) == 0) {
+ result = rb_eval(self, resq->nd_body);
+ }
+ POP_TAG();
+ if (state == 0) {
+ errinfo = e_info;
+ errat = e_at;
+ }
+ else if (state->nd_tag == TAG_RETRY) {
+ state = 0;
+ goto retry_entry;
+ }
+ break;
}
- break;
+ resq = resq->nd_head; /* next rescue */
}
- resq = resq->nd_head; /* next rescue */
}
- }
- if (state) {
- JUMP_TAG(state);
+ if (state) {
+ JUMP_TAG(state);
+ }
}
}
- break;
+ break;
case NODE_ENSURE:
PUSH_TAG();
@@ -1192,7 +1557,7 @@ rb_eval(self, node)
PUSH_ITER(ITER_NOT);
recv = rb_eval(self, node->nd_recv);
- SETUP_ARGS;
+ SETUP_ARGS(node->nd_args);
POP_ITER();
result = rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0);
}
@@ -1203,12 +1568,16 @@ rb_eval(self, node)
int argc; VALUE *argv; /* used in SETUP_ARGS */
PUSH_ITER(ITER_NOT);
- SETUP_ARGS;
+ SETUP_ARGS(node->nd_args);
POP_ITER();
result = rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,1);
}
break;
+ case NODE_VCALL:
+ result = rb_call(CLASS_OF(self),self,node->nd_mid,0,0,2);
+ break;
+
case NODE_SUPER:
case NODE_ZSUPER:
{
@@ -1220,7 +1589,7 @@ rb_eval(self, node)
}
else {
PUSH_ITER(ITER_NOT);
- SETUP_ARGS;
+ SETUP_ARGS(node->nd_args);
POP_ITER();
}
@@ -1239,7 +1608,9 @@ rb_eval(self, node)
PUSH_TAG();
if (node->nd_rval) the_frame->cbase = (VALUE)node->nd_rval;
if (node->nd_tbl) {
- the_scope->local_vars = ALLOCA_N(VALUE, node->nd_tbl[0]);
+ VALUE *vars = ALLOCA_N(VALUE, node->nd_tbl[0]+1);
+ *vars++ = (VALUE)node;
+ the_scope->local_vars = vars;
memclear(the_scope->local_vars, node->nd_tbl[0]);
the_scope->local_tbl = node->nd_tbl;
}
@@ -1259,17 +1630,17 @@ rb_eval(self, node)
case NODE_OP_ASGN1:
{
- VALUE recv, args, val;
+ int argc; VALUE *argv; /* used in SETUP_ARGS */
+ VALUE recv, val;
NODE *rval;
recv = rb_eval(self, node->nd_recv);
rval = node->nd_args->nd_head;
-
- args = rb_eval(self, node->nd_args->nd_next);
- val = rb_apply(recv, aref, args);
+ SETUP_ARGS(node->nd_args->nd_next);
+ val = rb_funcall2(recv, aref, argc-1, argv);
val = rb_funcall(val, node->nd_mid, 1, rb_eval(self, rval));
- ary_push(args, val);
- rb_apply(recv, aset, args);
+ argv[argc-1] = val;
+ val = rb_funcall2(recv, aset, argc, argv);
result = val;
}
break;
@@ -1282,7 +1653,7 @@ rb_eval(self, node)
recv = rb_eval(self, node->nd_recv);
val = rb_funcall(recv, id, 0);
- val = rb_funcall(recv, node->nd_next->nd_mid, 2, val,
+ val = rb_funcall(val, node->nd_next->nd_mid, 1,
rb_eval(self, node->nd_value));
rb_funcall2(recv, id_attrset(id), 1, &val);
@@ -1291,12 +1662,12 @@ rb_eval(self, node)
break;
case NODE_MASGN:
- result = masign(self, node, rb_eval(self, node->nd_value));
+ result = massign(self, node, rb_eval(self, node->nd_value));
break;
case NODE_LASGN:
if (the_scope->local_vars == 0)
- Bug("unexpected local variable asignment");
+ Bug("unexpected local variable assignment");
the_scope->local_vars[node->nd_cnt] = rb_eval(self, node->nd_value);
result = the_scope->local_vars[node->nd_cnt];
break;
@@ -1332,7 +1703,7 @@ rb_eval(self, node)
val = rb_eval(self, node->nd_value);
/* check for static scope constants */
if (verbose && ev_const_defined(the_frame->cbase, node->nd_vid)) {
- Warning("already initialized constnant %s",
+ Warning("already initialized constant %s",
rb_id2name(node->nd_vid));
}
rb_const_set(the_class, node->nd_vid, val);
@@ -1361,12 +1732,6 @@ rb_eval(self, node)
case NODE_CVAR:
result = ev_const_get(the_frame->cbase, node->nd_vid);
- nd_set_type(node, NODE_CONST);
- node->nd_cval = result;
- break;
-
- case NODE_CONST:
- result = node->nd_cval;
break;
case NODE_COLON2:
@@ -1386,7 +1751,6 @@ rb_eval(self, node)
}
break;
-#define MATCH_DATA the_scope->local_vars[node->nd_cnt]
case NODE_NTH_REF:
result = reg_nth_match(node->nd_nth, MATCH_DATA);
break;
@@ -1472,14 +1836,14 @@ rb_eval(self, node)
rb_in_eval++;
list->nd_head = compile(list->nd_head->nd_lit);
rb_in_eval--;
- if (!node) {
+ if (nerrs > 0) {
compile_error("string expand");
}
}
str2 = rb_eval(self, list->nd_head);
+ str2 = obj_as_string(str2);
}
if (str2) {
- str2 = obj_as_string(str2);
str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len);
}
list = list->nd_next;
@@ -1530,12 +1894,6 @@ rb_eval(self, node)
if (origin == (VALUE)the_class) {
Warning("redefine %s", rb_id2name(node->nd_mid));
}
- else {
- if (body->nd_noex != node->nd_noex) {
- Warning("change method %s's scope",
- rb_id2name(node->nd_mid));
- }
- }
rb_clear_cache();
}
@@ -1553,10 +1911,18 @@ rb_eval(self, node)
VALUE class;
NODE *body;
+ if (FIXNUM_P(recv)) {
+ TypeError("Can't define method \"%s\" for Fixnum",
+ rb_id2name(node->nd_mid));
+ }
if (NIL_P(recv)) {
TypeError("Can't define method \"%s\" for nil",
rb_id2name(node->nd_mid));
}
+ if (rb_special_const_p(recv)) {
+ TypeError("Can't define method \"%s\" for special constants",
+ rb_id2name(node->nd_mid));
+ }
class = rb_singleton_class(recv);
if (st_lookup(RCLASS(class)->m_tbl, node->nd_mid, &body)) {
@@ -1572,10 +1938,13 @@ rb_eval(self, node)
case NODE_UNDEF:
{
+ struct RClass *origin;
NODE *body;
- if (st_lookup(the_class->m_tbl, node->nd_mid, &body)) {
- Warning("redefine %s", rb_id2name(node->nd_mid));
+ body = search_method(the_class, node->nd_mid, &origin);
+ if (!body || !body->nd_body) {
+ NameError("undefined method `%s' for class `%s'",
+ rb_id2name(node->nd_mid), rb_class2name((VALUE)the_class));
}
rb_clear_cache();
rb_add_method(the_class, node->nd_mid, 0, NOEX_PUBLIC);
@@ -1588,6 +1957,11 @@ rb_eval(self, node)
result = Qnil;
break;
+ case NODE_VALIAS:
+ rb_alias_variable(node->nd_new, node->nd_old);
+ result = Qnil;
+ break;
+
case NODE_CLASS:
{
VALUE super, class;
@@ -1600,23 +1974,31 @@ rb_eval(self, node)
super = 0;
}
- if (!rb_autoload_defined(node->nd_cname) &&
- ev_const_defined(the_frame->cbase, node->nd_cname)) {
- class = rb_const_get(the_class, node->nd_cname);
- if (TYPE(class) != T_CLASS)
+ if (rb_const_defined_at(the_class, node->nd_cname) &&
+ ((VALUE)the_class != cObject ||
+ !rb_autoload_defined(node->nd_cname))) {
+
+ class = rb_const_get_at(the_class, node->nd_cname);
+ if (TYPE(class) != T_CLASS) {
TypeError("%s is not a class", rb_id2name(node->nd_cname));
+ }
if (super) {
tmp = RCLASS(class)->super;
- while (FL_TEST(tmp, FL_SINGLETON)) {
+ if (FL_TEST(tmp, FL_SINGLETON)) {
tmp = RCLASS(tmp)->super;
}
while (TYPE(tmp) == T_ICLASS) {
tmp = RCLASS(tmp)->super;
}
- if (tmp != RCLASS(super))
+ if (tmp != RCLASS(super)) {
TypeError("superclass mismatch for %s",
rb_id2name(node->nd_cname));
+ }
+ }
+ if (safe_level >= 4) {
+ Raise(eSecurityError, "extending class prohibited");
}
+ rb_clear_cache();
Warning("extending class %s", rb_id2name(node->nd_cname));
}
else {
@@ -1626,8 +2008,7 @@ rb_eval(self, node)
rb_set_class_path(class,the_class,rb_id2name(node->nd_cname));
}
- module_setup(class, node->nd_body);
- result = class;
+ result = module_setup(class, node->nd_body);
}
break;
@@ -1635,11 +2016,17 @@ rb_eval(self, node)
{
VALUE module;
- if (!rb_autoload_defined(node->nd_cname) &&
- ev_const_defined(the_frame->cbase, node->nd_cname)) {
- module = rb_const_get(the_class, node->nd_cname);
- if (TYPE(module) != T_MODULE)
+ if (rb_const_defined_at(the_class, node->nd_cname) &&
+ ((VALUE)the_class != cObject ||
+ !rb_autoload_defined(node->nd_cname))) {
+
+ module = rb_const_get_at(the_class, node->nd_cname);
+ if (TYPE(module) != T_MODULE) {
TypeError("%s is not a module", rb_id2name(node->nd_cname));
+ }
+ if (safe_level >= 4) {
+ Raise(eSecurityError, "extending module prohibited");
+ }
Warning("extending module %s", rb_id2name(node->nd_cname));
}
else {
@@ -1648,150 +2035,53 @@ rb_eval(self, node)
rb_set_class_path(module,the_class,rb_id2name(node->nd_cname));
}
- module_setup(module, node->nd_body);
- result = module;
+ result = module_setup(module, node->nd_body);
}
break;
- case NODE_DEFINED:
+ case NODE_SCLASS:
{
- VALUE obj;
- char buf[20];
- char *desc = 0;
-
- node = node->nd_head;
-
- switch (nd_type(node)) {
- case NODE_SUPER:
- case NODE_ZSUPER:
- if (the_frame->last_func == 0) result = FALSE;
- else {
- result = method_boundp(the_frame->last_class->super,
- the_frame->last_func, 1);
- }
- break;
-
- case NODE_FCALL:
- obj = CLASS_OF(self);
- goto check_bound;
-
- case NODE_CALL:
- PUSH_TAG();
- if ((state = EXEC_TAG()) == 0) {
- obj = rb_eval(self, node->nd_recv);
- }
- POP_TAG();
- if (state) {
- break;
- }
- else {
- if (state) JUMP_TAG(state);
- obj = CLASS_OF(obj);
- check_bound:
- if (method_boundp(obj, node->nd_mid,
- nd_type(node)== NODE_CALL)) {
- desc = "method";
- }
- }
- break;
-
- case NODE_YIELD:
- if (iterator_p()) {
- desc = "iterator";
- }
- break;
-
- case NODE_SELF:
- desc = "self"; break;
- case NODE_NIL:
- desc = "nil"; break;
-
- case NODE_ATTRSET:
- case NODE_OP_ASGN1:
- case NODE_OP_ASGN2:
- case NODE_MASGN:
- case NODE_LASGN:
- case NODE_DASGN:
- case NODE_GASGN:
- case NODE_IASGN:
- case NODE_CASGN:
- desc = "asignment"; break;
-
- case NODE_LVAR:
- desc = "local-variable"; break;
- case NODE_DVAR:
- desc = "dynamic-local-variable"; break;
-
- case NODE_GVAR:
- if (rb_gvar_defined(node->nd_entry)) {
- desc = "global-variable";
- }
- break;
-
- case NODE_IVAR:
- if (rb_ivar_defined(self, node->nd_vid)) {
- desc = "instance-variable";
- }
- break;
-
- case NODE_CVAR:
- if (ev_const_defined(the_frame->cbase, node->nd_vid)) {
- case NODE_CONST: /* jump in */
- desc = "class-constant";
- }
- break;
+ VALUE class;
- case NODE_COLON2:
- PUSH_TAG();
- if ((state = EXEC_TAG()) == 0) {
- obj = rb_eval(self, node->nd_head);
- }
- POP_TAG();
- if (state) {
- break;
- }
- else {
- if (state) JUMP_TAG(state);
- switch (TYPE(obj)) {
- case T_CLASS:
- case T_MODULE:
- if (rb_const_defined_at(obj, node->nd_mid))
- desc = "class-constant";
- break;
- }
- }
- break;
+ class = rb_eval(self, node->nd_recv);
+ if (FIXNUM_P(class)) {
+ TypeError("No virtual class for Fixnums");
+ }
+ if (NIL_P(class)) {
+ TypeError("No virtual class for nil");
+ }
+ if (rb_special_const_p(class)) {
+ TypeError("No virtual class for special constants");
+ }
+ if (FL_TEST(CLASS_OF(class), FL_SINGLETON)) {
+ rb_clear_cache();
+ }
+ class = rb_singleton_class(class);
- case NODE_NTH_REF:
- if (reg_nth_defined(node->nd_nth, MATCH_DATA)) {
- sprintf(buf, "$%d", node->nd_nth);
- desc = buf;
- }
- break;
+ result = module_setup(class, node->nd_body);
+ }
+ break;
- case NODE_BACK_REF:
- if (reg_nth_defined(0, MATCH_DATA)) {
- sprintf(buf, "$%c", node->nd_nth);
- desc = buf;
- }
- break;
+ case NODE_DEFINED:
+ {
+ char buf[20];
+ char *desc = is_defined(self, node, buf);
- default:
- PUSH_TAG();
- if ((state = EXEC_TAG()) == 0) {
- rb_eval(self, node);
- }
- POP_TAG();
- if (state) break;
- else {
- desc = "expression";
- }
- }
if (desc) result = str_new2(desc);
else result = FALSE;
}
break;
+ case NODE_NEWLINE:
+ sourcefile = node->file;
+ sourceline = node->nd_nth;
+ if (trace_func) {
+ call_trace_func("line", sourcefile, sourceline,
+ self, the_frame->last_func);
+ }
+ node = node->nd_next;
+ goto again;
+
default:
Bug("unknown node type %d", nd_type(node));
}
@@ -1800,13 +2090,14 @@ rb_eval(self, node)
return result;
}
-static void
+static VALUE
module_setup(module, node)
VALUE module;
- NODE *node;
+ NODE * volatile node;
{
NODE *state;
VALUE save = the_frame->cbase;
+ VALUE result; /* OK */
/* fill c-ref */
node->nd_clss = module;
@@ -1818,7 +2109,9 @@ module_setup(module, node)
if (node->nd_rval) the_frame->cbase = node->nd_rval;
if (node->nd_tbl) {
- the_scope->local_vars = ALLOCA_N(VALUE, node->nd_tbl[0]);
+ VALUE *vars = ALLOCA_N(VALUE, node->nd_tbl[0]+1);
+ *vars++ = (VALUE)node;
+ the_scope->local_vars = vars;
memclear(the_scope->local_vars, node->nd_tbl[0]);
the_scope->local_tbl = node->nd_tbl;
}
@@ -1829,13 +2122,23 @@ module_setup(module, node)
PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
- rb_eval((VALUE)the_class, node->nd_body);
+ if (trace_func) {
+ call_trace_func("class", node->file, nd_line(node),
+ the_class, the_frame->last_func);
+ }
+ result = rb_eval((VALUE)the_class, node->nd_body);
}
POP_TAG();
POP_SCOPE();
POP_CLASS();
the_frame->cbase = save;
+ if (trace_func) {
+ call_trace_func("end", node->file, nd_line(node), 0,
+ the_frame->last_func);
+ }
if (state) JUMP_TAG(state);
+
+ return result;
}
int
@@ -1850,7 +2153,7 @@ rb_respond_to(obj, id)
}
static VALUE
-krn_respond_to(argc, argv, obj)
+obj_respond_to(argc, argv, obj)
int argc;
VALUE *argv;
VALUE obj;
@@ -1870,7 +2173,7 @@ static VALUE
mod_method_defined(mod, mid)
VALUE mod, mid;
{
- if (rb_method_boundp(mod, rb_to_id(mid), TRUE)) {
+ if (rb_method_boundp(mod, rb_to_id(mid), 1)) {
return TRUE;
}
return FALSE;
@@ -1882,7 +2185,7 @@ rb_exit(status)
{
if (prot_tag) {
exit_status = status;
- rb_raise(exc_new(eSystemExit, ""));
+ rb_raise(exc_new(eSystemExit, 0, 0));
}
exit(status);
}
@@ -1895,6 +2198,7 @@ f_exit(argc, argv, obj)
{
VALUE status;
+ rb_secure(2);
if (rb_scan_args(argc, argv, "01", &status) == 1) {
status = NUM2INT(status);
}
@@ -1905,6 +2209,17 @@ f_exit(argc, argv, obj)
/* not reached */
}
+static VALUE
+f_abort()
+{
+ rb_secure(2);
+ if (errinfo) {
+ error_print();
+ }
+ rb_exit(1);
+ /* not reached */
+}
+
void
rb_break()
{
@@ -1946,8 +2261,8 @@ rb_longjmp(tag, mesg)
int tag;
VALUE mesg;
{
- if (NIL_P(errat) && NIL_P(mesg)) {
- errinfo = exc_new(eRuntimeError, "");
+ if (NIL_P(errinfo) && NIL_P(mesg)) {
+ errinfo = exc_new(eRuntimeError, 0, 0);
}
if (sourcefile && (NIL_P(errat) || !NIL_P(mesg))) {
@@ -1959,7 +2274,7 @@ rb_longjmp(tag, mesg)
errinfo = mesg;
}
else {
- errinfo = exc_new2(eRuntimeError, mesg);
+ errinfo = exc_new3(eRuntimeError, mesg);
}
str_freeze(errinfo);
}
@@ -1984,7 +2299,7 @@ rb_fatal(mesg)
void
rb_interrupt()
{
- rb_raise(exc_new(eInterrupt, "Interrupt"));
+ Raise(eInterrupt, "");
}
static VALUE
@@ -1994,23 +2309,30 @@ f_raise(argc, argv)
{
VALUE arg1, arg2;
VALUE etype, mesg;
+ int n;
etype = eRuntimeError;
mesg = Qnil;
- switch (rb_scan_args(argc, argv, "02", &arg1, &arg2)) {
+ switch (n = rb_scan_args(argc, argv, "02", &arg1, &arg2)) {
case 1:
mesg = arg1;
break;
case 2:
etype = arg1;
+ if (obj_is_kind_of(etype, eGlobalExit)) {
+ etype = CLASS_OF(etype);
+ }
+ else {
+ Check_Type(etype, T_CLASS);
+ }
mesg = arg2;
break;
}
if (!NIL_P(mesg)) {
Check_Type(mesg, T_STRING);
- if (!obj_is_kind_of(mesg, eException)) {
- mesg = exc_new2(etype, mesg);
+ if (n == 2 || !obj_is_kind_of(mesg, eException)) {
+ mesg = exc_new3(etype, mesg);
}
}
@@ -2036,11 +2358,12 @@ f_iterator_p()
VALUE
rb_yield_0(val, self)
- VALUE val, self;
+ VALUE val;
+ volatile VALUE self;
{
NODE *node;
NODE *state;
- VALUE result = Qnil;
+ volatile VALUE result = Qnil;
struct BLOCK *block;
struct SCOPE *old_scope;
struct FRAME frame;
@@ -2064,9 +2387,9 @@ rb_yield_0(val, self)
node = block->body;
if (block->var) {
if (nd_type(block->var) == NODE_MASGN)
- masign(self, block->var, val);
+ massign(self, block->var, val);
else
- asign(self, block->var, val);
+ assign(self, block->var, val);
}
PUSH_ITER(block->iter);
PUSH_TAG();
@@ -2076,7 +2399,7 @@ rb_yield_0(val, self)
result = Qnil;
}
else if (nd_type(node) == NODE_CFUNC) {
- result = (*node->nd_cfnc)(val,node->nd_argc,self);
+ result = (*node->nd_cfnc)(val, node->nd_argc, self);
}
else {
result = rb_eval(self, node);
@@ -2085,9 +2408,11 @@ rb_yield_0(val, self)
else {
switch (state->nd_tag) {
case TAG_REDO:
+ state = 0;
goto redo;
case TAG_NEXT:
state = 0;
+ result = Qnil;
break;
case TAG_BREAK:
case TAG_RETURN:
@@ -2123,7 +2448,8 @@ f_loop()
}
static VALUE
-masign(self, node, val)
+massign(self, node, val)
+ VALUE self;
NODE *node;
VALUE val;
{
@@ -2138,30 +2464,30 @@ masign(self, node, val)
}
len = RARRAY(val)->len;
for (i=0; list && i<len; i++) {
- asign(self, list->nd_head, RARRAY(val)->ptr[i]);
+ assign(self, list->nd_head, RARRAY(val)->ptr[i]);
list = list->nd_next;
}
if (node->nd_args) {
if (!list && i<len) {
- asign(self, node->nd_args, ary_new4(len-i, RARRAY(val)->ptr+i));
+ assign(self, node->nd_args, ary_new4(len-i, RARRAY(val)->ptr+i));
}
else {
- asign(self, node->nd_args, ary_new2(0));
+ assign(self, node->nd_args, ary_new2(0));
}
}
}
else if (node->nd_args) {
- asign(self, node->nd_args, Qnil);
+ assign(self, node->nd_args, Qnil);
}
while (list) {
- asign(self, list->nd_head, Qnil);
+ assign(self, list->nd_head, Qnil);
list = list->nd_next;
}
return val;
}
static void
-asign(self, lhs, val)
+assign(self, lhs, val)
VALUE self;
NODE *lhs;
VALUE val;
@@ -2177,7 +2503,7 @@ asign(self, lhs, val)
case NODE_LASGN:
if (the_scope->local_vars == 0)
- Bug("unexpected iterator variable asignment");
+ Bug("unexpected iterator variable assignment");
the_scope->local_vars[lhs->nd_cnt] = val;
break;
@@ -2209,7 +2535,7 @@ asign(self, lhs, val)
break;
default:
- Bug("bug in variable asignment");
+ Bug("bug in variable assignment");
break;
}
}
@@ -2220,7 +2546,7 @@ rb_iterate(it_proc, data1, bl_proc, data2)
void *data1, *data2;
{
NODE *state;
- VALUE retval = Qnil;
+ volatile VALUE retval = Qnil;
NODE *node = NEW_CFUNC(bl_proc, data2);
VALUE self = TopSelf;
int tag_level;
@@ -2234,8 +2560,8 @@ rb_iterate(it_proc, data1, bl_proc, data2)
if (state == 0) {
retval = (*it_proc)(data1);
}
-
POP_TAG();
+
tag_level = the_block->level;
POP_BLOCK();
POP_ITER();
@@ -2276,9 +2602,12 @@ handle_rescue(self, node)
}
PUSH_ITER(ITER_NOT);
- SETUP_ARGS;
+ SETUP_ARGS(node->nd_args);
POP_ITER();
while (argc--) {
+ if (!obj_is_kind_of(argv[0], cModule)) {
+ TypeError("class or module required for rescue clause");
+ }
if (obj_is_kind_of(errinfo, argv[0])) return 1;
argv++;
}
@@ -2291,7 +2620,7 @@ rb_rescue(b_proc, data1, r_proc, data2)
void *data1, *data2;
{
NODE *state;
- VALUE result;
+ volatile VALUE result;
PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
@@ -2302,8 +2631,7 @@ rb_rescue(b_proc, data1, r_proc, data2)
if (state->nd_tag == TAG_RAISE) {
if (r_proc) {
PUSH_TAG();
- state = EXEC_TAG();
- if (state == 0) {
+ if ((state = EXEC_TAG()) == 0) {
result = (*r_proc)(data2, errinfo);
}
POP_TAG();
@@ -2333,7 +2661,7 @@ rb_ensure(b_proc, data1, e_proc, data2)
void *data1, *data2;
{
NODE *state;
- VALUE result = Qnil;
+ volatile VALUE result = Qnil;
PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
@@ -2348,7 +2676,9 @@ rb_ensure(b_proc, data1, e_proc, data2)
return result;
}
-static int last_noex;
+static int last_call_status;
+#define CSTAT_NOEX 1
+#define CSTAT_VCALL 2
static VALUE
f_missing(argc, argv, obj)
@@ -2358,8 +2688,9 @@ f_missing(argc, argv, obj)
{
VALUE desc = 0;
ID id;
- char *format;
- struct FRAME *frame;
+ char *format = 0;
+ char *file = sourcefile;
+ int line = sourceline;
id = FIX2INT(argv[0]);
argc--; argv++;
@@ -2382,36 +2713,48 @@ f_missing(argc, argv, obj)
break;
}
if (desc) {
- if (last_noex)
+ if (last_call_status & CSTAT_NOEX) {
format = "private method `%s' called for %s(%s)";
- else if (argc == 0) {
- format = "undefined local variable or method `%s' for %s(%s)";
}
- else {
+ else if (iterator_p()) {
+ format = "undefined iterator `%s' for %s(%s)";
+ }
+ else if (last_call_status & CSTAT_VCALL) {
+ char *mname = rb_id2name(id);
+
+ if (('a' <= mname[0] && mname[0] <= 'z') || mname[0] == '_') {
+ format = "undefined local variable or method `%s' for %s(%s)";
+ }
+ }
+ if (!format) {
format = "undefined method `%s' for %s(%s)";
}
if (RSTRING(desc)->len > 65) {
- desc = krn_to_s(obj);
+ desc = any_to_s(obj);
}
}
+ sourcefile = file;
+ sourceline = line;
PUSH_FRAME(); /* fake frame */
*the_frame = *_frame.prev->prev;
NameError(format,
rb_id2name(id),
- desc?RSTRING(desc)->ptr:"",
+ desc?(char*)RSTRING(desc)->ptr:"",
desc?rb_class2name(CLASS_OF(obj)):"");
POP_FRAME();
+
+ return Qnil; /* not reached */
}
static VALUE
-rb_undefined(obj, id, argc, argv, noex)
+rb_undefined(obj, id, argc, argv, call_status)
VALUE obj;
ID id;
int argc;
VALUE*argv;
- int noex;
+ int call_status;
{
VALUE *nargv;
@@ -2419,12 +2762,21 @@ rb_undefined(obj, id, argc, argv, noex)
nargv[0] = INT2FIX(id);
MEMCPY(nargv+1, argv, VALUE, argc);
- last_noex = noex;
+ last_call_status = call_status;
return rb_funcall2(obj, rb_intern("method_missing"), argc+1, nargv);
}
-#define STACK_LEVEL_MAX 655350
+#ifdef DJGPP
+# define STACK_LEVEL_MAX 65535
+#else
+#ifdef __human68k__
+extern int _stacksize;
+# define STACK_LEVEL_MAX (_stacksize - 4096)
+#else
+# define STACK_LEVEL_MAX 655350
+#endif
+#endif
extern VALUE *gc_stack_start;
static int
stack_length()
@@ -2444,19 +2796,20 @@ rb_call(class, recv, mid, argc, argv, scope)
struct RClass *class;
VALUE recv;
ID mid;
- int argc;
- VALUE *argv;
+ int argc; /* OK */
+ VALUE *argv; /* OK */
int scope;
{
- NODE *body;
+ NODE *body, *b2; /* OK */
int noex;
ID id = mid;
struct cache_entry *ent;
- VALUE result = Qnil;
+ volatile VALUE result = Qnil;
int itr;
enum node_type type;
static int tick;
+ again:
/* is it in the method cache? */
ent = cache + EXPR1(class, mid);
if (ent->mid == mid && ent->class == class) {
@@ -2466,12 +2819,12 @@ rb_call(class, recv, mid, argc, argv, scope)
body = ent->method;
}
else if ((body = rb_get_method_body(&class, &id, &noex)) == 0) {
- return rb_undefined(recv, mid, argc, argv, 0);
+ return rb_undefined(recv, mid, argc, argv, scope==2?CSTAT_VCALL:0);
}
/* receiver specified form for private method */
if (noex == NOEX_PRIVATE && scope == 0)
- return rb_undefined(recv, mid, argc, argv, 1);
+ return rb_undefined(recv, mid, argc, argv, CSTAT_NOEX);
switch (the_iter->iter) {
case ITER_PRE:
@@ -2485,11 +2838,27 @@ rb_call(class, recv, mid, argc, argv, scope)
type = nd_type(body);
if (type == NODE_ZSUPER) {
- /* for re-scoped method */
- return rb_call(class->super, recv, id, argc, argv, scope?scope:1);
+ /* for re-scoped/renamed method */
+ mid = id;
+ if (scope == 0) scope = 1;
+ if (class->super == 0) {
+ /* origin is the Module, so need to scan superclass hierarchy. */
+ struct RClass *cl = class;
+
+ class = (struct RClass*)RBASIC(recv)->class;
+ while (class) {
+ if (class->m_tbl == cl->m_tbl)
+ break;
+ class = class->super;
+ }
+ }
+ else {
+ class = class->super;
+ }
+ goto again;
}
- if (++tick % 1000 == 0 && stack_length() > STACK_LEVEL_MAX)
+ if ((++tick & 0xfff) == 0 && stack_length() > STACK_LEVEL_MAX)
Fatal("stack level too deep");
PUSH_ITER(itr);
@@ -2602,7 +2971,7 @@ rb_call(class, recv, mid, argc, argv, scope)
default:
if (len < 0) {
Bug("bad argc(%d) specified for `%s(%s)'",
- len, rb_class2name(class), rb_id2name(mid));
+ len, rb_class2name((VALUE)class), rb_id2name(mid));
}
else {
ArgError("too many arguments(%d)", len);
@@ -2627,7 +2996,8 @@ rb_call(class, recv, mid, argc, argv, scope)
if (body->nd_rval) the_frame->cbase = body->nd_rval;
if (body->nd_tbl) {
- local_vars = ALLOCA_N(VALUE, body->nd_tbl[0]);
+ local_vars = ALLOCA_N(VALUE, body->nd_tbl[0]+1);
+ *local_vars++ = (VALUE)body;
memclear(local_vars, body->nd_tbl[0]);
the_scope->local_tbl = body->nd_tbl;
the_scope->local_vars = local_vars;
@@ -2636,13 +3006,12 @@ rb_call(class, recv, mid, argc, argv, scope)
local_vars = the_scope->local_vars = 0;
the_scope->local_tbl = 0;
}
- body = body->nd_body;
+ b2 = body = body->nd_body;
PUSH_TAG();
PUSH_VARS();
- dyna_var_mark();
- state = EXEC_TAG();
- if (state == 0) {
+
+ if ((state = EXEC_TAG()) == 0) {
if (nd_type(body) == NODE_BLOCK) {
NODE *node = body->nd_head;
int i;
@@ -2653,11 +3022,22 @@ rb_call(class, recv, mid, argc, argv, scope)
body = body->nd_next;
i = node->nd_cnt;
- if (i > argc
- || (node->nd_rest == -1
- && i+(node->nd_opt?node->nd_opt->nd_alen:0)<argc)){
+ if (i > argc) {
ArgError("Wrong # of arguments(%d for %d)", argc, i);
}
+ if (node->nd_rest == -1) {
+ int opt = argc - i;
+ NODE *optnode = node->nd_opt;
+
+ while (optnode) {
+ opt--;
+ optnode = optnode->nd_next;
+ }
+ if (opt > 0) {
+ ArgError("Wrong # of arguments(%d for %d)",
+ argc, argc-opt);
+ }
+ }
if (local_vars) {
if (i > 0) {
@@ -2668,7 +3048,7 @@ rb_call(class, recv, mid, argc, argv, scope)
NODE *opt = node->nd_opt;
while (opt && argc) {
- asign(recv, opt->nd_head, *argv);
+ assign(recv, opt->nd_head, *argv);
argv++; argc--;
opt = opt->nd_next;
}
@@ -2685,11 +3065,24 @@ rb_call(class, recv, mid, argc, argv, scope)
else if (nd_type(body) == NODE_ARGS) {
body = 0;
}
+ if (trace_func) {
+ call_trace_func("call", b2->file, nd_line(b2),
+ recv, the_frame->last_func);
+ }
result = rb_eval(recv, body);
}
POP_VARS();
POP_TAG();
POP_SCOPE();
+ if (trace_func) {
+ char *file = the_frame->prev->file;
+ int line = the_frame->prev->line;
+ if (!file) {
+ file = sourcefile;
+ line = sourceline;
+ }
+ call_trace_func("return", file, line, 0, the_frame->last_func);
+ }
if (state) {
switch (state->nd_tag) {
case TAG_NEXT:
@@ -2752,7 +3145,11 @@ f_send(argc, argv, recv)
else {
mid = NUM2INT(vid);
}
- return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 1);
+ PUSH_ITER(iterator_p()?ITER_PRE:ITER_NOT);
+ vid = rb_call(CLASS_OF(recv), recv, mid, argc, argv, 1);
+ POP_ITER();
+
+ return vid;
}
#include <varargs.h>
@@ -2802,7 +3199,9 @@ backtrace(lev)
struct FRAME *frame = the_frame;
char buf[BUFSIZ];
VALUE ary;
+ int slev = safe_level;
+ safe_level = 0;
ary = ary_new();
if (lev < 0) {
if (frame->last_func) {
@@ -2832,6 +3231,7 @@ backtrace(lev)
ary_push(ary, str_new2(buf));
frame = frame->prev;
}
+ safe_level = slev;
return ary;
}
@@ -2841,7 +3241,6 @@ f_caller(argc, argv)
VALUE *argv;
{
VALUE level;
- struct FRAME *frame = the_frame;
int lev;
rb_scan_args(argc, argv, "01", &level);
@@ -2857,12 +3256,12 @@ void
rb_backtrace()
{
int i, lev;
- VALUE ary, c;
+ VALUE ary;
lev = INT2FIX(0);
ary = backtrace(-1);
for (i=0; i<RARRAY(ary)->len; i++) {
- printf("\tfrom %s\n", RSTRING(RARRAY(ary)->ptr)->ptr);
+ printf("\tfrom %s\n", RSTRING(RARRAY(ary)->ptr[i])->ptr);
}
}
@@ -2889,15 +3288,12 @@ compile(src)
Check_Type(src, T_STRING);
- errinfo = Qnil;
node = compile_string(sourcefile, src->ptr, src->len);
if (nerrs == 0) return node;
return 0;
}
-static void blk_free();
-
static VALUE
eval(self, src, scope)
VALUE self;
@@ -2905,57 +3301,70 @@ eval(self, src, scope)
struct RData *scope;
{
struct BLOCK *data;
- VALUE result = Qnil;
- NODE *node;
+ volatile VALUE result = Qnil;
NODE *state;
- struct BLOCK *old_block;
- struct SCOPE *old_scope;
+ volatile VALUE old_block;
+ volatile VALUE old_scope;
+ volatile VALUE old_d_vars;
struct FRAME frame;
char *file = sourcefile;
int line = sourceline;
+ volatile int iter = the_frame->iter;
- PUSH_TAG();
- PUSH_CLASS();
if (!NIL_P(scope)) {
if (TYPE(scope) != T_DATA || scope->dfree != blk_free) {
TypeError("wrong argument type %s (expected Proc/Binding)",
rb_class2name(CLASS_OF(scope)));
}
- Get_Data_Struct(scope, struct BLOCK, data);
+ Data_Get_Struct(scope, struct BLOCK, data);
/* PUSH BLOCK from data */
frame = data->frame;
frame.prev = the_frame;
the_frame = &(frame);
- old_scope = the_scope;
+ old_scope = (VALUE)the_scope;
the_scope = data->scope;
- old_block = the_block;
+ old_block = (VALUE)the_block;
the_block = data->prev;
+ old_d_vars = (VALUE)the_dyna_vars;
the_dyna_vars = data->d_vars;
- the_class = data->class;
+
self = data->self;
+ the_frame->iter = data->iter;
+ }
+ else {
+ if (the_frame->prev) {
+ the_frame->iter = the_frame->prev->iter;
+ }
}
+ PUSH_CLASS();
+ the_class = (struct RClass*)((NODE*)the_frame->cbase)->nd_clss;
rb_in_eval++;
if (TYPE(the_class) == T_ICLASS) {
the_class = (struct RClass*)RBASIC(the_class)->class;
}
+ PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
- if (!compile(src)) {
- rb_in_eval--;
+ compile(src);
+ if (nerrs > 0) {
compile_error("eval()");
}
result = eval_node(self);
}
+ POP_TAG();
+ POP_CLASS();
+ rb_in_eval--;
if (!NIL_P(scope)) {
the_frame = the_frame->prev;
- the_scope = old_scope;
- the_block = old_block;
+ the_scope = (struct SCOPE*)old_scope;
+ the_block = (struct BLOCK*)old_block;
+ the_dyna_vars = (struct RVarmap*)old_d_vars;
+ }
+ else {
+ the_frame->iter = iter;
}
- POP_CLASS();
- POP_TAG();
- rb_in_eval--;
if (state) {
VALUE err ;
@@ -2964,13 +3373,14 @@ eval(self, src, scope)
sourcefile = file;
sourceline = line;
if (strcmp(sourcefile, "(eval)") == 0) {
- err = errat;
- if (sourceline != 1) {
+ err = errinfo;
+ if (sourceline > 1) {
+ err = RARRAY(errat)->ptr[0];
str_cat(err, ": ", 2);
str_cat(err, RSTRING(errinfo)->ptr, RSTRING(errinfo)->len);
}
errat = Qnil;
- rb_raise(exc_new2(CLASS_OF(errinfo), err));
+ rb_raise(exc_new3(CLASS_OF(errinfo), err));
}
rb_raise(Qnil);
}
@@ -2989,6 +3399,8 @@ f_eval(argc, argv, self)
VALUE src, scope;
rb_scan_args(argc, argv, "11", &src, &scope);
+
+ Check_SafeStr(src);
return eval(self, src, scope);
}
@@ -3005,10 +3417,24 @@ find_file(file)
char *path;
if (file[0] == '/') return file;
+#if defined(MSDOS) || defined(NT) || defined(__human68k__)
+ if (file[0] == '\\') return file;
+ if (file[1] == ':') return file;
+#endif
if (rb_load_path) {
+ int i;
+
Check_Type(rb_load_path, T_ARRAY);
+ for (i=0;i<RARRAY(rb_load_path)->len;i++) {
+ Check_SafeStr(RARRAY(rb_load_path)->ptr[i]);
+ }
+#if !defined(MSDOS) && !defined(NT) && !defined(__human68k__)
vpath = ary_join(rb_load_path, str_new2(":"));
+#else
+ vpath = ary_join(rb_load_path, str_new2(";"));
+#endif
+ Check_SafeStr(vpath);
path = RSTRING(vpath)->ptr;
}
else {
@@ -3024,10 +3450,13 @@ f_load(obj, fname)
struct RString *fname;
{
NODE *state;
- char *file, *src;
+ char *file;
volatile ID last_func;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
+ if (fname->ptr[0] == '~') {
+ fname = (struct RString*)file_s_expand_path(0, fname);
+ }
file = find_file(fname->ptr);
if (!file) LoadError("No such file to load -- %s", fname->ptr);
@@ -3035,8 +3464,16 @@ f_load(obj, fname)
PUSH_CLASS();
the_class = (struct RClass*)cObject;
PUSH_SCOPE();
- the_scope->local_vars = top_scope->local_vars;
- the_scope->local_tbl = top_scope->local_tbl;
+ if (top_scope->local_tbl) {
+ int len = top_scope->local_tbl[0]+1;
+ ID *tbl = ALLOC_N(ID, len);
+ VALUE *vars = ALLOCA_N(VALUE, len);
+ *vars++ = 0;
+ MEMCPY(tbl, top_scope->local_tbl, ID, len);
+ MEMCPY(vars, top_scope->local_vars, ID, len-1);
+ the_scope->local_tbl = tbl;
+ the_scope->local_vars = vars;
+ }
state = EXEC_TAG();
last_func = the_frame->last_func;
@@ -3050,7 +3487,9 @@ f_load(obj, fname)
}
}
the_frame->last_func = last_func;
- top_scope->flag = the_scope->flag;
+ if (the_scope->flag == SCOPE_ALLOCA && the_scope->local_tbl) {
+ free(the_scope->local_tbl);
+ }
POP_SCOPE();
POP_CLASS();
POP_TAG();
@@ -3108,9 +3547,9 @@ f_require(obj, fname)
struct RString *fname;
{
char *ext, *file, *feature, *buf;
- VALUE load;
+ volatile VALUE load;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (rb_provided(fname->ptr))
return FALSE;
@@ -3216,7 +3655,7 @@ mod_public(argc, argv, module)
VALUE module;
{
set_method_visibility(module, argc, argv, NOEX_PUBLIC);
- return Qnil;
+ return module;
}
static VALUE
@@ -3226,7 +3665,27 @@ mod_private(argc, argv, module)
VALUE module;
{
set_method_visibility(module, argc, argv, NOEX_PRIVATE);
- return Qnil;
+ return module;
+}
+
+static VALUE
+mod_public_method(argc, argv, obj)
+ int argc;
+ VALUE *argv;
+ VALUE obj;
+{
+ set_method_visibility(CLASS_OF(obj), argc, argv, NOEX_PUBLIC);
+ return obj;
+}
+
+static VALUE
+mod_private_method(argc, argv, obj)
+ int argc;
+ VALUE *argv;
+ VALUE obj;
+{
+ set_method_visibility(CLASS_OF(obj), argc, argv, NOEX_PRIVATE);
+ return obj;
}
static VALUE
@@ -3237,8 +3696,9 @@ mod_modfunc(argc, argv, module)
{
int i;
ID id;
- NODE *body, *old;
+ NODE *body;
+ rb_clear_cache();
set_method_visibility(module, argc, argv, NOEX_PRIVATE);
for (i=0; i<argc; i++) {
id = rb_to_id(argv[i]);
@@ -3249,14 +3709,14 @@ mod_modfunc(argc, argv, module)
}
rb_add_method(rb_singleton_class(module), id, body->nd_body, NOEX_PUBLIC);
}
- return Qnil;
+ return module;
}
static VALUE
mod_include(argc, argv, module)
int argc;
VALUE *argv;
- struct RClass *module;
+ VALUE module;
{
int i;
@@ -3264,10 +3724,10 @@ mod_include(argc, argv, module)
Check_Type(argv[i], T_MODULE);
rb_include_module(module, argv[i]);
}
- return Qnil;
+ return module;
}
-VALUE /* moved from object.c for push_iter */
+VALUE
class_s_new(argc, argv, class)
int argc;
VALUE *argv;
@@ -3275,6 +3735,29 @@ class_s_new(argc, argv, class)
{
VALUE obj = obj_alloc(class);
+ if (FL_TEST(class, FL_SINGLETON)) {
+ TypeError("can't create instance of virtual class");
+ }
+ obj = obj_alloc(class);
+ PUSH_ITER(iterator_p()?ITER_PRE:ITER_NOT);
+ rb_funcall2(obj, init, argc, argv);
+ POP_ITER();
+ return obj;
+}
+
+
+VALUE
+class_new_instance(argc, argv, class)
+ int argc;
+ VALUE *argv;
+ VALUE class;
+{
+ VALUE obj;
+
+ if (FL_TEST(class, FL_SINGLETON)) {
+ TypeError("can't create instance of virtual class");
+ }
+ obj = obj_alloc(class);
PUSH_ITER(iterator_p()?ITER_PRE:ITER_NOT);
rb_funcall2(obj, init, argc, argv);
POP_ITER();
@@ -3286,9 +3769,25 @@ top_include(argc, argv)
int argc;
VALUE *argv;
{
+ rb_secure(4);
return mod_include(argc, argv, cObject);
}
+void
+rb_extend_object(obj, module)
+ VALUE obj, module;
+{
+ rb_include_module(rb_singleton_class(obj), module);
+}
+
+static VALUE
+mod_extend_object(mod, obj)
+ VALUE mod, obj;
+{
+ rb_extend_object(obj, mod);
+ return obj;
+}
+
static VALUE
obj_extend(argc, argv, obj)
int argc;
@@ -3297,41 +3796,43 @@ obj_extend(argc, argv, obj)
{
int i;
- mod_include(argc, argv, rb_singleton_class(obj));
+ for (i=0; i<argc; i++) Check_Type(argv[i], T_MODULE);
for (i=0; i<argc; i++) {
- rb_funcall(argv[i], rb_intern("object_extended"), 1, obj);
+ rb_funcall(argv[i], rb_intern("extend_object"), 1, obj);
}
- return Qnil;
-}
-
-void
-rb_extend_object(obj, module)
- VALUE obj, module;
-{
- rb_include_module(rb_singleton_class(obj), module);
+ return obj;
}
-extern VALUE cModule;
-
VALUE f_trace_var();
VALUE f_untrace_var();
-extern VALUE rb_str_setter();
+extern void rb_str_setter();
-static VALUE
+static void
errat_setter(val, id, var)
VALUE val;
ID id;
VALUE *var;
{
- if (!NIL_P(val) && TYPE(val) != T_ARRAY) {
- TypeError("value of $@ must be Array of String");
+ int i;
+ static char *err = "value of $@ must be Array of String";
+
+ if (!NIL_P(val)) {
+ if (TYPE(val) != T_ARRAY) {
+ TypeError(err);
+ }
+ for (i=0;i<RARRAY(val)->len;i++) {
+ if (TYPE(RARRAY(val)->ptr[i]) != T_STRING) {
+ TypeError(err);
+ }
+ }
}
- return *var = val;
+ *var = val;
}
static VALUE
f_catch(dmy, tag)
+ VALUE dmy, tag;
{
NODE *state;
ID t;
@@ -3383,45 +3884,53 @@ Init_eval()
rb_define_hooked_variable("$@", &errat, 0, errat_setter);
rb_define_hooked_variable("$!", &errinfo, 0, rb_str_setter);
- rb_define_private_method(cKernel, "eval", f_eval, -1);
- rb_define_private_method(cKernel, "iterator?", f_iterator_p, 0);
- rb_define_private_method(cKernel, "method_missing", f_missing, -1);
- rb_define_private_method(cKernel, "loop", f_loop, 0);
+ rb_define_global_function("eval", f_eval, -1);
+ rb_define_global_function("iterator?", f_iterator_p, 0);
+ rb_define_global_function("method_missing", f_missing, -1);
+ rb_define_global_function("loop", f_loop, 0);
- rb_define_method(cKernel, "respond_to?", krn_respond_to, -1);
+ rb_define_method(mKernel, "respond_to?", obj_respond_to, -1);
- rb_define_private_method(cKernel, "break", f_break, 0);
- rb_define_alias(cKernel, "break!", "break");
- rb_define_private_method(cKernel, "next", f_next, 0);
- rb_define_alias(cKernel, "next!", "next");
- rb_define_alias(cKernel, "continue", "next");
- rb_define_private_method(cKernel, "redo", f_redo, 0);
- rb_define_alias(cKernel, "redo!", "redo");
- rb_define_private_method(cKernel, "retry", f_retry, 0);
- rb_define_alias(cKernel, "retry!", "retry");
- rb_define_private_method(cKernel, "raise", f_raise, -1);
- rb_define_alias(cKernel, "fail", "raise");
+ rb_define_global_function("break", f_break, 0);
+ rb_define_alias(mKernel, "break!", "break");
+ rb_define_global_function("next", f_next, 0);
+ rb_define_alias(mKernel, "next!", "next");
+ rb_define_alias(mKernel, "continue", "next");
+ rb_define_global_function("redo", f_redo, 0);
+ rb_define_alias(mKernel, "redo!", "redo");
+ rb_define_global_function("retry", f_retry, 0);
+ rb_define_alias(mKernel, "retry!", "retry");
+ rb_define_global_function("raise", f_raise, -1);
+ rb_define_alias(mKernel, "fail", "raise");
- rb_define_private_method(cKernel, "caller", f_caller, -1);
+ rb_define_global_function("caller", f_caller, -1);
- rb_define_private_method(cKernel, "exit", f_exit, -1);
+ rb_define_global_function("exit", f_exit, -1);
+ rb_define_global_function("abort", f_abort, 0);
- rb_define_private_method(cKernel, "catch", f_catch, 1);
- rb_define_private_method(cKernel, "throw", f_throw, -1);
+ rb_define_global_function("catch", f_catch, 1);
+ rb_define_global_function("throw", f_throw, -1);
- rb_define_method(cKernel, "send", f_send, -1);
+ rb_define_method(mKernel, "send", f_send, -1);
- rb_define_method(cModule, "include", mod_include, -1);
- rb_define_method(cModule, "public", mod_public, -1);
- rb_define_method(cModule, "private", mod_private, -1);
- rb_define_method(cModule, "module_function", mod_modfunc, -1);
+ rb_define_private_method(cModule, "include", mod_include, -1);
+ rb_define_private_method(cModule, "public", mod_public, -1);
+ rb_define_private_method(cModule, "private", mod_private, -1);
+ rb_define_private_method(cModule, "module_function", mod_modfunc, -1);
rb_define_method(cModule, "method_defined?", mod_method_defined, 1);
+ rb_define_method(cModule, "extend_object", mod_extend_object, 1);
+ rb_define_method(cModule, "public_class_method", mod_public_method, -1);
+ rb_define_method(cModule, "private_class_method", mod_private_method, -1);
rb_define_method(CLASS_OF(TopSelf), "include", top_include, -1);
- rb_define_method(cObject, "extend", obj_extend, -1);
+ rb_define_method(mKernel, "extend", obj_extend, -1);
- rb_define_private_method(cKernel, "trace_var", f_trace_var, -1);
- rb_define_private_method(cKernel, "untrace_var", f_untrace_var, -1);
+ rb_define_global_function("trace_var", f_trace_var, -1);
+ rb_define_global_function("untrace_var", f_untrace_var, -1);
+
+ rb_define_global_function("set_trace_func", set_trace_func, 1);
+
+ rb_define_virtual_variable("$SAFE", safe_getter, safe_setter);
}
VALUE f_autoload();
@@ -3431,14 +3940,15 @@ Init_load()
{
rb_load_path = ary_new();
rb_define_readonly_variable("$:", &rb_load_path);
+ rb_define_readonly_variable("$-I", &rb_load_path);
rb_define_readonly_variable("$LOAD_PATH", &rb_load_path);
rb_features = ary_new();
rb_define_readonly_variable("$\"", &rb_features);
- rb_define_private_method(cKernel, "load", f_load, 1);
- rb_define_private_method(cKernel, "require", f_require, 1);
- rb_define_private_method(cKernel, "autoload", f_autoload, 2);
+ rb_define_global_function("load", f_load, 1);
+ rb_define_global_function("require", f_require, 1);
+ rb_define_global_function("autoload", f_autoload, 2);
}
static void
@@ -3448,17 +3958,19 @@ scope_dup(scope)
ID *tbl;
VALUE *vars;
- if (scope->flag == SCOPE_MALLOC) return;
+ if (scope->flag & SCOPE_MALLOC) return;
if (scope->local_tbl) {
tbl = scope->local_tbl;
- scope->local_tbl = ALLOC_N(ID, tbl[0]+1);
- MEMCPY(scope->local_tbl, tbl, ID, tbl[0]+1);
- vars = scope->local_vars;
- scope->local_vars = ALLOC_N(VALUE, tbl[0]);
- MEMCPY(scope->local_vars, vars, VALUE, tbl[0]);
+ vars = ALLOC_N(VALUE, tbl[0]+1);
+ *vars++ = scope->local_vars[-1];
+ MEMCPY(vars, scope->local_vars, VALUE, tbl[0]);
+ scope->local_vars = vars;
scope->flag = SCOPE_MALLOC;
}
+ else {
+ scope->flag = SCOPE_NOSTACK;
+ }
}
static void
@@ -3484,15 +3996,14 @@ static VALUE
f_binding(self)
VALUE self;
{
- extern VALUE cData;
struct BLOCK *data;
VALUE bind;
PUSH_BLOCK(0,0);
- bind = Make_Data_Struct(cData, struct BLOCK, blk_mark, blk_free, data);
+ bind = Data_Make_Struct(cData, struct BLOCK, blk_mark, blk_free, data);
MEMCPY(data, the_block, struct BLOCK, 1);
- data->iter = ITER_NOT;
+ data->iter = f_iterator_p();
data->frame.last_func = 0;
data->frame.argv = ALLOC_N(VALUE, data->frame.argc);
MEMCPY(data->frame.argv, the_block->frame.argv, VALUE, data->frame.argc);
@@ -3503,6 +4014,12 @@ f_binding(self)
return bind;
}
+#define PROC_TAINT FL_USER0
+#define PROC_T3 FL_USER1
+#define PROC_T4 FL_USER2
+#define PROC_T5 (FL_USER1|FL_USER2)
+#define PROC_TMASK (FL_USER1|FL_USER2)
+
static VALUE
proc_s_new(class)
VALUE class;
@@ -3514,14 +4031,31 @@ proc_s_new(class)
ArgError("tryed to create Procedure-Object out of iterator");
}
- proc = Make_Data_Struct(class, struct BLOCK, blk_mark, blk_free, data);
+ proc = Data_Make_Struct(class, struct BLOCK, blk_mark, blk_free, data);
*data = *the_block;
- data->iter = ITER_NOT;
+#ifdef THREAD
+ data->orig_thread = thread_current();
+#endif
+ data->iter = f_iterator_p();
data->frame.argv = ALLOC_N(VALUE, data->frame.argc);
MEMCPY(data->frame.argv, the_block->frame.argv, VALUE, data->frame.argc);
scope_dup(data->scope);
+ if (safe_level >= 3) {
+ FL_SET(proc, PROC_TAINT);
+ switch (safe_level) {
+ case 3:
+ FL_SET(proc, PROC_T3);
+ break;
+ case 4:
+ FL_SET(proc, PROC_T4);
+ break;
+ case 5:
+ FL_SET(proc, PROC_T5);
+ break;
+ }
+ }
return proc;
}
@@ -3537,9 +4071,11 @@ proc_call(proc, args)
VALUE proc, args;
{
struct BLOCK *data;
- VALUE result = Qnil;
+ volatile VALUE result = Qnil;
NODE *state;
int tag_level;
+ volatile int orphan;
+ volatile int safe = safe_level;
if (TYPE(args) == T_ARRAY) {
switch (RARRAY(args)->len) {
@@ -3552,14 +4088,48 @@ proc_call(proc, args)
}
}
- Get_Data_Struct(proc, struct BLOCK, data);
+ Data_Get_Struct(proc, struct BLOCK, data);
+
+ if (data->scope && (data->scope->flag & SCOPE_NOSTACK)) {
+ orphan = 1;
+ }
+ else {
+#ifdef THREAD
+ if (data->orig_thread != thread_current()) {
+ orphan = 1;
+ }
+ else
+#endif
+ orphan = 0;
+ }
+ if (orphan) {/* orphan procedure */
+ if (iterator_p()) {
+ data->frame.iter = ITER_CUR;
+ }
+ else {
+ data->frame.iter = ITER_NOT;
+ }
+ }
/* PUSH BLOCK from data */
PUSH_BLOCK2(data);
PUSH_ITER(ITER_CUR);
the_frame->iter = ITER_CUR;
- PUSH_TAG();
+ if (FL_TEST(proc, PROC_TAINT)) {
+ switch (RBASIC(proc)->flags & PROC_TMASK) {
+ case PROC_T3:
+ safe_level = 3;
+ break;
+ case PROC_T4:
+ safe_level = 4;
+ break;
+ case PROC_T5:
+ safe_level = 5;
+ break;
+ }
+ }
+ PUSH_TAG();
state = EXEC_TAG();
if (state == 0) {
result = rb_yield(args);
@@ -3569,15 +4139,14 @@ proc_call(proc, args)
POP_ITER();
tag_level = the_block->level;
POP_BLOCK();
+ safe_level = safe;
if (state) {
- if (data->scope && (data->scope->flag & SCOPE_NOSTACK)) {
- /* orphan procedure */
+ if (orphan) {/* orphan procedure */
switch (state->nd_tag) {
case TAG_BREAK: /* never happen */
- break;
case IN_BLOCK|TAG_BREAK:
- if (state->nd_tlev != tag_level)
+ if (state->nd_tlev == tag_level)
Raise(eLocalJumpError, "break from proc-closure");
break;
case TAG_RETRY:
@@ -3585,11 +4154,12 @@ proc_call(proc, args)
break;
case TAG_RETURN: /* never happen */
case IN_BLOCK|TAG_RETURN:
- Raise(eLocalJumpError, "return from proc-closure");
+ if (state->nd_tlev == tag_level)
+ Raise(eLocalJumpError, "return from proc-closure");
break;
}
}
- else {
+ else if (state->nd_tlev == tag_level) {
state->nd_tag &= ~IN_BLOCK;
}
JUMP_TAG(state);
@@ -3606,26 +4176,37 @@ Init_Proc()
rb_define_singleton_method(cProc, "new", proc_s_new, 0);
rb_define_method(cProc, "call", proc_call, -2);
- rb_define_private_method(cKernel, "proc", f_lambda, 0);
- rb_define_private_method(cKernel, "lambda", f_lambda, 0);
- rb_define_private_method(cKernel, "binding", f_binding, 0);
+ rb_define_global_function("proc", f_lambda, 0);
+ rb_define_global_function("lambda", f_lambda, 0);
+ rb_define_global_function("binding", f_binding, 0);
}
#ifdef THREAD
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
+static VALUE eThreadError;
int thread_pending = 0;
static VALUE cThread;
#include <sys/types.h>
-#include <sys/time.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#else
+#ifndef NT
+struct timeval {
+ long tv_sec; /* seconds */
+ long tv_usec; /* and microseconds */
+};
+#endif /* NT */
+#endif
#include <signal.h>
#include <errno.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
extern VALUE last_status;
enum thread_status {
@@ -3647,8 +4228,6 @@ typedef struct thread * thread_t;
struct thread {
struct thread *next, *prev;
jmp_buf context;
- VALUE (*func)();
- void *arg;
VALUE result;
@@ -3665,6 +4244,8 @@ struct thread {
struct iter *iter;
struct tag *tag;
+ VALUE trace;
+
char *file;
int line;
@@ -3673,11 +4254,16 @@ struct thread {
VALUE last_line;
VALUE last_match;
+ int safe;
+
enum thread_status status;
int wait_for;
int fd;
double delay;
thread_t join;
+
+ int abort;
+
VALUE thread;
};
@@ -3686,10 +4272,11 @@ static int num_waiting_on_fd;
static int num_waiting_on_timer;
static int num_waiting_on_join;
-thread_curr() {return (int)curr_thread;}
+#define FOREACH_THREAD_FROM(f,x) x = f; do { x = x->next;
+#define END_FOREACH_FROM(f,x) } while (x != f)
-#define FOREACH_THREAD(x) x = curr_thread; do { x = x->next;
-#define END_FOREACH(x) } while (x != curr_thread)
+#define FOREACH_THREAD(x) FOREACH_THREAD_FROM(curr_thread,x)
+#define END_FOREACH(x) END_FOREACH_FROM(curr_thread,x)
/* Return the current time as a floating-point number */
static double
@@ -3713,10 +4300,12 @@ thread_mark(th)
struct BLOCK *block;
gc_mark(th->result);
- gc_mark_locations(th->stk_ptr, th->stk_ptr+th->stk_len);
-#ifdef THINK_C
- gc_mark_locations(th->stk_ptr+2, th->stk_ptr+th->stk_len+2);
+ if (th->stk_ptr) {
+ gc_mark_locations(th->stk_ptr, th->stk_ptr+th->stk_len);
+#if defined(THINK_C) || defined(__human68k__)
+ gc_mark_locations(th->stk_ptr+2, th->stk_ptr+th->stk_len+2);
#endif
+ }
gc_mark(th->thread);
if (th->join) gc_mark(th->join->thread);
@@ -3780,7 +4369,7 @@ void lastline_set();
VALUE backref_get();
void backref_set();
-static int
+static void
thread_save_context(th)
thread_t th;
{
@@ -3808,7 +4397,9 @@ thread_save_context(th)
th->last_status = last_status;
th->last_line = lastline_get();
th->last_match = backref_get();
+ th->safe = safe_level;
+ th->trace = trace_func;
th->file = sourcefile;
th->line = sourceline;
}
@@ -3826,6 +4417,11 @@ stack_extend(th, exit)
thread_restore_context(th, exit);
}
+static int th_raise_argc;
+static VALUE th_raise_argv[2];
+static char *th_raise_file;
+static int th_raise_line;
+
static void
thread_restore_context(th, exit)
thread_t th;
@@ -3857,7 +4453,9 @@ thread_restore_context(th, exit)
errat = th->errat;
errinfo = th->errinfo;
last_status = th->last_status;
+ safe_level = th->safe;
+ trace_func = th->trace;
sourcefile = th->file;
sourceline = th->line;
@@ -3878,6 +4476,13 @@ thread_restore_context(th, exit)
rb_interrupt();
break;
+ case 3:
+ the_frame->last_func = 0;
+ sourcefile = th_raise_file;
+ sourceline = th_raise_line;
+ f_raise(th_raise_argc, th_raise_argv);
+ break;
+
default:
longjmp(tmp->context, 1);
}
@@ -3918,6 +4523,17 @@ thread_dead(th)
return th->status == THREAD_KILLED;
}
+static void
+thread_deadlock()
+{
+ curr_thread = main_thread;
+ th_raise_argc = 1;
+ th_raise_argv[0] = exc_new2(eFatal, "Thread: deadlock");
+ th_raise_file = sourcefile;
+ th_raise_line = sourceline;
+ f_abort();
+}
+
void
thread_schedule()
{
@@ -3925,27 +4541,29 @@ thread_schedule()
thread_t th;
thread_t curr;
+ select_err:
thread_pending = 0;
if (curr_thread == curr_thread->next) return;
next = 0;
- curr = curr_thread; /* real current thread */
+ curr = curr_thread; /* starting thread */
- if (curr_thread->status == THREAD_KILLED) {
- curr_thread = curr_thread->prev;
+ while (curr->status == THREAD_KILLED) {
+ curr = curr->prev;
}
- again:
- FOREACH_THREAD(th) {
- if (th->status != THREAD_STOPPED && th->status != THREAD_KILLED) {
- next = th;
- break;
- }
+ FOREACH_THREAD_FROM(curr,th) {
+ if (th->status != THREAD_STOPPED && th->status != THREAD_KILLED) {
+ next = th;
+ break;
+ }
}
- END_FOREACH(th);
+ END_FOREACH_FROM(curr,th);
if (num_waiting_on_join) {
- FOREACH_THREAD(th) {
+ curr_thread->file = sourcefile;
+ curr_thread->line = sourceline;
+ FOREACH_THREAD_FROM(curr,th) {
if ((th->wait_for & WAIT_JOIN) && thread_dead(th->join)) {
th->join = 0;
th->wait_for &= ~WAIT_JOIN;
@@ -3954,7 +4572,7 @@ thread_schedule()
if (!next) next = th;
}
}
- END_FOREACH(th);
+ END_FOREACH_FROM(curr,th);
}
if (num_waiting_on_fd > 0 || num_waiting_on_timer > 0) {
@@ -3965,23 +4583,22 @@ thread_schedule()
int n, max;
do {
- select_err:
max = 0;
FD_ZERO(&readfds);
if (num_waiting_on_fd > 0) {
- FOREACH_THREAD(th) {
+ FOREACH_THREAD_FROM(curr,th) {
if (th->wait_for & WAIT_FD) {
FD_SET(th->fd, &readfds);
if (th->fd > max) max = th->fd;
}
}
- END_FOREACH(th);
+ END_FOREACH_FROM(curr,th);
}
delay = DELAY_INFTY;
if (num_waiting_on_timer > 0) {
now = timeofday();
- FOREACH_THREAD(th) {
+ FOREACH_THREAD_FROM(curr,th) {
if (th->wait_for & WAIT_TIME) {
if (th->delay <= now) {
th->delay = 0.0;
@@ -3994,7 +4611,7 @@ thread_schedule()
}
}
}
- END_FOREACH(th);
+ END_FOREACH_FROM(curr,th);
}
/* Do the select if needed */
if (num_waiting_on_fd > 0 || !next) {
@@ -4014,11 +4631,16 @@ thread_schedule()
delay_tv.tv_usec = (delay - (double)delay_tv.tv_sec) * 1e6;
delay_ptr = &delay_tv;
}
+
n = select(max+1, &readfds, 0, 0, delay_ptr);
+ if (n < 0) {
+ if (trap_pending) rb_trap_exec();
+ goto select_err;
+ }
if (n > 0) {
/* Some descriptors are ready.
Make the corresponding threads runnable. */
- FOREACH_THREAD(th)
+ FOREACH_THREAD_FROM(curr,th) {
if ((th->wait_for&WAIT_FD)
&& FD_ISSET(th->fd, &readfds)) {
/* Wake up only one thread per fd. */
@@ -4029,9 +4651,9 @@ thread_schedule()
num_waiting_on_fd--;
if (!next) next = th; /* Found one. */
}
- END_FOREACH(th);
+ }
+ END_FOREACH_FROM(curr,th);
}
- if (n < 0 && !next) goto select_err;
}
/* The delays for some of the threads should have expired.
Go through the loop once more, to check the delays. */
@@ -4039,15 +4661,16 @@ thread_schedule()
}
if (!next) {
- FOREACH_THREAD(th) {
+ FOREACH_THREAD_FROM(curr,th) {
fprintf(stderr, "%s:%d:deadlock 0x%x: %d:%d %s\n",
th->file, th->line, th->thread, th->status,
th->wait_for, th==main_thread?"(main)":"");
}
- END_FOREACH(th);
- Fatal("Thread: deadlock");
+ END_FOREACH_FROM(curr,th);
+ /* raise fatal error to main thread */
+ thread_deadlock();
}
- if (next == curr) {
+ if (next == curr_thread) {
return;
}
@@ -4087,9 +4710,9 @@ thread_fd_writable(fd)
struct timeval zero;
fd_set fds;
- zero.tv_sec = zero.tv_usec = 0;
if (curr_thread == curr_thread->next) return;
+ zero.tv_sec = zero.tv_usec = 0;
for (;;) {
FD_ZERO(&fds);
FD_SET(fd, &fds);
@@ -4138,7 +4761,13 @@ thread_wait_for(time)
thread_schedule();
}
-void thread_sleep();
+void thread_sleep_forever();
+
+int
+thread_alone()
+{
+ return curr_thread == curr_thread->next;
+}
int
thread_select(max, read, write, except, timeout)
@@ -4153,8 +4782,8 @@ thread_select(max, read, write, except, timeout)
if (!read && !write && !except) {
if (!timeout) {
- thread_sleep();
- return;
+ thread_sleep_forever();
+ return 0;
}
thread_wait_for(*timeout);
return 0;
@@ -4229,22 +4858,22 @@ thread_select(max, read, write, except, timeout)
}
static VALUE
-thread_join(dmy, data)
+thread_join(dmy, thread)
VALUE dmy;
- struct RData *data;
+ VALUE thread;
{
- thread_t th = thread_check(data);
+ thread_t th = thread_check(thread);
- if (thread_dead(th)) return Qnil;
+ if (thread_dead(th)) return thread;
if ((th->wait_for & WAIT_JOIN) && th->join == curr_thread)
- Fatal("Thread.join: deadlock");
+ Raise(eThreadError, "Thread.join: deadlock");
curr_thread->status = THREAD_STOPPED;
curr_thread->join = th;
num_waiting_on_join++;
curr_thread->wait_for |= WAIT_JOIN;
thread_schedule();
- return Qnil;
+ return thread;
}
static VALUE
@@ -4253,39 +4882,48 @@ thread_current()
return curr_thread->thread;
}
-int
-th_cur()
+static VALUE
+thread_main()
{
- return (int)curr_thread;
+ return main_thread->thread;
}
static VALUE
-thread_run(data)
- struct RData *data;
+thread_wakeup(thread)
+ VALUE thread;
{
- thread_t th = thread_check(data);
+ thread_t th = thread_check(thread);
- if (th->status == THREAD_KILLED) Fail("killed thread");
+ if (th->status == THREAD_KILLED) Raise(eThreadError, "killed thread");
thread_ready(th);
- thread_schedule();
- return (VALUE)data;
+ return thread;
}
static VALUE
-thread_kill(data)
- struct RData *data;
+thread_run(thread)
+ VALUE thread;
{
- thread_t th = thread_check(data);
+ thread_wakeup(thread);
+ if (!thread_critical) thread_schedule();
- if (th->status == THREAD_TO_KILL) return Qnil;
- if (th->status == THREAD_KILLED) return Qnil;
+ return thread;
+}
+
+static VALUE
+thread_kill(thread)
+ VALUE thread;
+{
+ thread_t th = thread_check(thread);
+
+ if (th->status == THREAD_TO_KILL || th->status == THREAD_KILLED)
+ return thread;
if (th == th->next || th == main_thread) rb_exit(0);
thread_ready(th);
th->status = THREAD_TO_KILL;
thread_schedule();
- /* not reached */
+ return Qnil; /* not reached */
}
static VALUE
@@ -4302,25 +4940,47 @@ thread_exit()
}
static VALUE
-thread_stop_method(data)
- struct RData *data;
+thread_pass()
+{
+ thread_schedule();
+ return Qnil;
+}
+
+static VALUE
+thread_stop_method(thread)
+ VALUE thread;
{
- thread_t th = thread_check(data);
+ thread_t th = thread_check(thread);
+ thread_critical = 0;
th->status = THREAD_STOPPED;
thread_schedule();
- return Qnil;
+ return thread;
}
-static void
+static VALUE
thread_stop()
{
thread_stop_method(curr_thread->thread);
+ return Qnil;
}
void
-thread_sleep()
+thread_sleep(sec)
+ int sec;
+{
+ if (curr_thread == curr_thread->next) {
+ TRAP_BEG;
+ sleep(sec);
+ TRAP_END;
+ return;
+ }
+ thread_wait_for(time_timeval(INT2FIX(sec)));
+}
+
+void
+thread_sleep_forever()
{
if (curr_thread == curr_thread->next) {
TRAP_BEG;
@@ -4328,7 +4988,47 @@ thread_sleep()
TRAP_END;
return;
}
- thread_stop_method(curr_thread->thread);
+
+ num_waiting_on_timer++;
+ curr_thread->delay = DELAY_INFTY;
+ curr_thread->wait_for |= WAIT_TIME;
+ curr_thread->status = THREAD_STOPPED;
+ thread_schedule();
+}
+
+static int thread_abort;
+
+static VALUE
+thread_s_abort_exc()
+{
+ return thread_abort?TRUE:FALSE;
+}
+
+static VALUE
+thread_s_abort_exc_set(self, val)
+ VALUE self, val;
+{
+ thread_abort = RTEST(val);
+ return val;
+}
+
+static VALUE
+thread_abort_exc(thread)
+ VALUE thread;
+{
+ thread_t th = thread_check(thread);
+
+ return th->abort?TRUE:FALSE;
+}
+
+static VALUE
+thread_abort_exc_set(thread, val)
+ VALUE thread, val;
+{
+ thread_t th = thread_check(thread);
+
+ th->abort = RTEST(val);
+ return val;
}
static thread_t
@@ -4338,8 +5038,6 @@ thread_alloc()
th = ALLOC(struct thread);
th->status = THREAD_RUNNABLE;
- th->func = 0;
- th->arg = 0;
th->status = 0;
th->result = 0;
@@ -4361,6 +5059,12 @@ thread_alloc()
th->block = 0;
th->iter = 0;
th->tag = 0;
+ th->errat = 0;
+ th->errinfo = 0;
+ th->last_status = 0;
+ th->last_line = 0;
+ th->last_match = 0;
+ th->abort = 0;
th->thread = data_object_alloc(cThread, th, 0, thread_free);
@@ -4378,6 +5082,26 @@ thread_alloc()
return th;
}
+#if defined(HAVE_SETITIMER) && !defined(__BOW__)
+static void
+catch_timer(sig)
+ int sig;
+{
+#if !defined(POSIX_SIGNAL) && !defined(BSD_SIGNAL)
+ signal(sig, catch_timer);
+#endif
+ if (!thread_critical) {
+ if (trap_immediate) {
+ trap_immediate = 0;
+ thread_schedule();
+ }
+ else thread_pending = 1;
+ }
+}
+#else
+int thread_tick = THREAD_TICK;
+#endif
+
VALUE
thread_create(fn, arg)
VALUE (*fn)();
@@ -4386,35 +5110,79 @@ thread_create(fn, arg)
thread_t th = thread_alloc();
NODE *state;
+#if defined(HAVE_SETITIMER) && !defined(__BOW__)
+ static init = 0;
+
+ if (!init) {
+ struct itimerval tval;
+
+#ifdef POSIX_SIGNAL
+ posix_signal(SIGVTALRM, catch_timer);
+#else
+ signal(SIGVTALRM, catch_timer);
+#endif
+
+ tval.it_interval.tv_sec = 0;
+ tval.it_interval.tv_usec = 100000;
+ tval.it_value = tval.it_interval;
+ setitimer(ITIMER_VIRTUAL, &tval, NULL);
+
+ init = 1;
+ }
+#endif
+
thread_save_context(curr_thread);
if (setjmp(curr_thread->context)) {
return th->thread;
}
- th->func = fn;
- th->arg = arg;
-
PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
thread_save_context(th);
if (setjmp(th->context) == 0) {
curr_thread = th;
- th->result = (*th->func)(th->arg, th);
+ th->result = (*fn)(arg, th);
}
}
POP_TAG();
- if (state && th->status != THREAD_TO_KILL) {
- /* global exit within this thread */
- main_thread->errat = errat;
- main_thread->errinfo = errinfo;
- thread_cleanup();
+ if (state) {
+ if (state->nd_tag == TAG_THROW) {
+ char *mesg;
+ char *tag = rb_id2name(state->nd_tlev);
+
+ mesg = ALLOCA_N(char, strlen(tag) + 64);
+
+ sprintf(mesg, "uncaught throw `%s' in thread 0x%x\n",
+ tag, th->thread);
+ curr_thread->errinfo = exc_new2(eThreadError, mesg);
+ curr_thread->errat = make_backtrace();
+ }
+ else if (th->status != THREAD_TO_KILL && !NIL_P(errinfo)) {
+ if (state->nd_tag == TAG_FATAL ||
+ obj_is_kind_of(errinfo, eSystemExit)) {
+ /* fatal error or global exit within this thread */
+ /* need to stop whole script */
+ main_thread->errat = errat;
+ main_thread->errinfo = errinfo;
+ thread_cleanup();
+ }
+ else if (thread_abort || curr_thread->abort) {
+ f_abort();
+ }
+ else {
+ curr_thread->errat = errat;
+ curr_thread->errinfo = errinfo;
+ }
+ }
}
thread_remove();
+ return 0;
}
static void
thread_yield(arg, th)
- thread_t th;
+ int arg;
+ thread_t th;
{
scope_dup(the_block->scope);
rb_yield(th->thread);
@@ -4424,35 +5192,47 @@ static VALUE
thread_start()
{
if (!iterator_p()) {
- Raise(eLocalJumpError, "must be called as iterator");
+ Raise(eThreadError, "must be called as iterator");
}
return thread_create(thread_yield, 0);
}
static VALUE
-thread_value(data)
- struct RData *data;
+thread_value(thread)
+ VALUE thread;
{
- thread_t th = thread_check(data);
+ thread_t th = thread_check(thread);
+
+ thread_join(0, thread);
+ if (!NIL_P(th->errinfo)) {
+ errat = make_backtrace();
+ ary_unshift(errat, ary_entry(th->errat, 0));
+ sourcefile = 0; /* kludge to print errat */
+ rb_raise(th->errinfo);
+ }
- thread_join(0, data);
return th->result;
}
static VALUE
-thread_status(data)
- struct RData *data;
+thread_status(thread)
+ VALUE thread;
{
- thread_t th = thread_check(data);
+ thread_t th = thread_check(thread);
+
+ if (thread_dead(th)) {
+ if (NIL_P(th->errinfo)) return FALSE;
+ return Qnil;
+ }
- return thread_dead(th)?FALSE:TRUE;
+ return TRUE;
}
static VALUE
-thread_stopped(data)
- struct RData *data;
+thread_stopped(thread)
+ VALUE thread;
{
- thread_t th = thread_check(data);
+ thread_t th = thread_check(thread);
if (thread_dead(th)) return TRUE;
if (th->status == THREAD_STOPPED) return TRUE;
@@ -4473,6 +5253,10 @@ thread_cleanup()
{
thread_t th;
+ if (curr_thread != curr_thread->next->prev) {
+ curr_thread = curr_thread->prev;
+ }
+
FOREACH_THREAD(th) {
if (th != curr_thread && th->status != THREAD_KILLED) {
th->status = THREAD_TO_KILL;
@@ -4485,37 +5269,64 @@ thread_cleanup()
int thread_critical;
static VALUE
-thread_exclusive()
+thread_get_critical()
{
- NODE *state;
-
- thread_critical++;
-
- PUSH_TAG();
- if ((state = EXEC_TAG()) == 0) {
- rb_yield(Qnil);
- }
- POP_TAG();
- thread_critical--;
+ return thread_critical?TRUE:FALSE;
+}
- if (state) JUMP_TAG(state);
- thread_schedule();
- return Qnil;
+static VALUE
+thread_set_critical(obj, val)
+ VALUE obj, val;
+{
+ thread_critical = RTEST(val);
+ return val;
}
void
thread_interrupt()
{
- thread_t th = main_thread;
-
+ thread_critical = 0;
thread_ready(main_thread);
- if (th == curr_thread) {
+ if (curr_thread == main_thread) {
rb_interrupt();
}
+ thread_save_context(curr_thread);
+ if (setjmp(curr_thread->context)) {
+ return;
+ }
curr_thread = main_thread;
thread_restore_context(curr_thread, 2);
}
+static VALUE
+thread_raise(argc, argv, thread)
+ int argc;
+ VALUE *argv;
+ VALUE thread;
+{
+ thread_t th = thread_check(thread);
+
+ if (thread_dead(th)) return thread;
+ if (curr_thread == th) {
+ f_raise(argc, argv);
+ }
+
+ thread_save_context(curr_thread);
+ if (setjmp(curr_thread->context)) {
+ return thread;
+ }
+
+ rb_scan_args(argc, argv, "11", &th_raise_argv[0], &th_raise_argv[1]);
+ thread_ready(th);
+ curr_thread = th;
+
+ th_raise_argc = argc;
+ th_raise_file = sourcefile;
+ th_raise_line = sourceline;
+ thread_restore_context(curr_thread, 3);
+ return Qnil; /* not reached */
+}
+
static thread_t loading_thread;
static int loading_nest;
@@ -4545,29 +5356,10 @@ thread_loading_done()
}
}
-#if defined(HAVE_SETITIMER) && !defined(__BOW__)
-static void
-catch_timer(sig)
- int sig;
-{
-#if !defined(POSIX_SIGNAL) && !defined(BSD_SIGNAL)
- signal(sig, catch_timer);
-#endif
- if (!thread_critical) {
- if (trap_immediate) {
- trap_immediate = 0;
- thread_schedule();
- }
- else thread_pending = 1;
- }
-}
-#else
-int thread_tick = THREAD_TICK;
-#endif
-
void
Init_Thread()
{
+ eThreadError = rb_define_class("ThreadError", eException);
cThread = rb_define_class("Thread", cObject);
rb_define_singleton_method(cThread, "new", thread_start, 0);
@@ -4577,37 +5369,31 @@ Init_Thread()
rb_define_singleton_method(cThread, "stop", thread_stop, 0);
rb_define_singleton_method(cThread, "kill", thread_s_kill, 1);
rb_define_singleton_method(cThread, "exit", thread_exit, 0);
- rb_define_singleton_method(cThread, "pass", thread_schedule, 0);
+ rb_define_singleton_method(cThread, "pass", thread_pass, 0);
rb_define_singleton_method(cThread, "join", thread_join, 1);
rb_define_singleton_method(cThread, "current", thread_current, 0);
- rb_define_singleton_method(cThread, "exclusive", thread_exclusive, 0);
+ rb_define_singleton_method(cThread, "main", thread_main, 0);
+
+ rb_define_singleton_method(cThread, "critical", thread_get_critical, 0);
+ rb_define_singleton_method(cThread, "critical=", thread_set_critical, 1);
+
+ rb_define_singleton_method(cThread, "abort_on_exception", thread_s_abort_exc, 0);
+ rb_define_singleton_method(cThread, "abort_on_exception=", thread_s_abort_exc_set, 1);
rb_define_method(cThread, "run", thread_run, 0);
+ rb_define_method(cThread, "wakeup", thread_wakeup, 0);
rb_define_method(cThread, "stop", thread_stop_method, 0);
rb_define_method(cThread, "exit", thread_kill, 0);
rb_define_method(cThread, "value", thread_value, 0);
rb_define_method(cThread, "status", thread_status, 0);
+ rb_define_method(cThread, "alive?", thread_status, 0);
rb_define_method(cThread, "stop?", thread_stopped, 0);
- rb_define_method(cThread, "stopped?", thread_stopped, 0);
+ rb_define_method(cThread, "raise", thread_raise, -1);
+
+ rb_define_method(cThread, "abort_on_exception", thread_abort_exc, 0);
+ rb_define_method(cThread, "abort_on_exception=", thread_abort_exc_set, 1);
/* allocate main thread */
main_thread = thread_alloc();
-
-#if defined(HAVE_SETITIMER) && !defined(__BOW__)
- {
- struct itimerval tval;
-
-#ifdef POSIX_SIGNAL
- posix_signal(SIGVTALRM, catch_timer);
-#else
- signal(SIGVTALRM, catch_timer);
-#endif
-
- tval.it_interval.tv_sec = 0;
- tval.it_interval.tv_usec = 50000;
- tval.it_value = tval.it_interval;
- setitimer(ITIMER_VIRTUAL, &tval, NULL);
- }
-#endif
}
#endif
diff --git a/ext/Setup b/ext/Setup
index 4ea6aea10a..a5dd7978c3 100644
--- a/ext/Setup
+++ b/ext/Setup
@@ -1,7 +1,10 @@
#option nodynamic
+#GD
+#curses
#dbm
#etc
+#fcntl
#kconv
#marshal
#md5
diff --git a/ext/Setup.dj b/ext/Setup.dj
index eb60525de0..25adea2035 100644
--- a/ext/Setup.dj
+++ b/ext/Setup.dj
@@ -1,7 +1,11 @@
option nodynamic
+#GD
+#curses
dbm
#etc
+fcntl
+kconv
marshal
md5
#socket
diff --git a/ext/Setup.nt b/ext/Setup.nt
new file mode 100644
index 0000000000..8e43179f9e
--- /dev/null
+++ b/ext/Setup.nt
@@ -0,0 +1,12 @@
+option nodynamic
+
+#GD
+#curses
+#dbm
+#etc
+fcntl
+kconv
+#marshal
+md5
+socket
+#tkutil
diff --git a/ext/Setup.x68 b/ext/Setup.x68
new file mode 100644
index 0000000000..25adea2035
--- /dev/null
+++ b/ext/Setup.x68
@@ -0,0 +1,12 @@
+option nodynamic
+
+#GD
+#curses
+dbm
+#etc
+fcntl
+kconv
+marshal
+md5
+#socket
+#tkutil
diff --git a/ext/aix_ld.rb b/ext/aix_ld.rb
new file mode 100644
index 0000000000..1058977b88
--- /dev/null
+++ b/ext/aix_ld.rb
@@ -0,0 +1,73 @@
+#! /usr/local/bin/ruby
+
+def older(file1, file2)
+ if !File.exist?(file1) then
+ return TRUE
+ end
+ if !File.exist?(file2) then
+ return FALSE
+ end
+ if File.mtime(file1) < File.mtime(file2)
+ return TRUE
+ end
+ return FALSE
+end
+
+target = ARGV.shift
+unless target =~ /\.so/
+ STDERR.printf "wrong suffix specified\n"
+ exit 1
+end
+base = File.basename(target, ".so")
+entry="Init_#{base}"
+ldargs = "-e#{entry} -bI:../ruby.imp -bM:SRE -T512 -H512 -lc"
+
+def uniq(data)
+ last=nil
+ data.delete_if do |name|
+ if last == name
+ TRUE
+ else
+ last = name
+ FALSE
+ end
+ end
+end
+
+def extract(nm, out)
+ data = nm.readlines.collect{|line|
+ line = line.split
+ case line[1]
+ when "B", "D", "T"
+ line[2]
+ else
+ next
+ end
+ }.sort!
+ uniq(data)
+ exp = open(out, "w")
+ for line in data
+ exp.printf "%s\n", line
+ end
+ exp.close
+ nm.close
+end
+if older("../ruby.imp", "../../miniruby")
+# nm = open("|/usr/ccs/bin/nm -Bex ../../*.o")
+# nm = open("|/usr/ccs/bin/nm -Bex ../../*.o")
+ nm = open("|nm ../../*.o")
+ extract(nm, "../ruby.imp")
+end
+
+objs = Dir["*.o"].join(" ")
+#nm = open("|/usr/ccs/bin/nm -Bex #{objs}")
+nm = open("|nm #{objs}")
+extract(nm, "#{base}.exp")
+
+#system format("/usr/ccs/bin/ld %s %s ",ldargs,ARGV.join(' '))
+#system "/bin/rm -f #{base}.exp"
+#system "chmod o-rwx ${base}.so"
+
+p format("/usr/ccs/bin/ld %s %s ",ldargs,ARGV.join(' '))
+p "/bin/rm -f #{base}.exp"
+p "chmod o-rwx ${base}.so"
diff --git a/ext/curses/MANIFEST b/ext/curses/MANIFEST
new file mode 100644
index 0000000000..db5e54ffe8
--- /dev/null
+++ b/ext/curses/MANIFEST
@@ -0,0 +1,6 @@
+MANIFEST
+curses.c
+extconf.rb
+hello.rb
+rain.rb
+view.rb
diff --git a/ext/curses/curses.c b/ext/curses/curses.c
new file mode 100644
index 0000000000..16ba90cff0
--- /dev/null
+++ b/ext/curses/curses.c
@@ -0,0 +1,725 @@
+/*
+ * ext/curses/curses.c
+ *
+ * by MAEDA Shugo (ender@pic-internet.or.jp)
+ * modified by Yukihiro Matsumoto (matz@ruby.club.or.jp)
+ */
+
+#ifdef HAVE_NCURSES_H
+# include <ncurses.h>
+#else
+# ifdef HAVE_NCURSES_CURSES_H
+# include <ncurses/curses.h>
+# else
+# include <curses.h>
+# if defined(__NetBSD__) && !defined(_maxx)
+# define _maxx maxx
+# endif
+# if defined(__NetBSD__) && !defined(_maxy)
+# define _maxy maxy
+# endif
+# endif
+#endif
+
+#include "ruby.h"
+
+static VALUE mCurses;
+static VALUE cWindow;
+
+VALUE rb_stdscr;
+
+struct windata {
+ WINDOW *window;
+};
+
+#define NUM2CHAR(x) (char)NUM2INT(x)
+#define CHAR2FIX(x) INT2FIX((int)x)
+
+static void
+no_window()
+{
+ Fail("already closed window");
+}
+
+#define GetWINDOW(obj, winp) {\
+ Data_Get_Struct(obj, struct windata, winp);\
+ if (winp->window == 0) no_window();\
+}
+
+static void
+curses_err()
+{
+ Fail("curses error");
+}
+
+#define CHECK(c) if ((c)==ERR) {curses_err();}
+
+static void
+free_window(struct windata *winp)
+{
+ if (winp->window && winp->window != stdscr) delwin(winp->window);
+ winp->window = 0;
+}
+
+static VALUE
+prep_window(VALUE class, WINDOW *window)
+{
+ VALUE obj;
+ struct windata *winp;
+
+ if (window == NULL) {
+ Fail("failed to create window");
+ }
+
+ obj = Data_Make_Struct(class, struct windata, 0, free_window, winp);
+ winp->window = window;
+
+ return obj;
+}
+
+/*-------------------------- module Curses --------------------------*/
+
+/* def init_screen */
+static VALUE
+curses_init_screen()
+{
+ initscr();
+ if (stdscr == 0) {
+ Fail("cannot initialize curses");
+ }
+ clear();
+ rb_stdscr = prep_window(cWindow, stdscr);
+ return Qnil;
+}
+
+/* def stdscr */
+static VALUE
+curses_stdscr()
+{
+ if (!rb_stdscr) curses_init_screen();
+ return rb_stdscr;
+}
+
+/* def close_screen */
+static VALUE
+curses_close_screen()
+{
+ CHECK(endwin());
+ return Qnil;
+}
+
+/* def closed? */
+static VALUE
+curses_closed()
+{
+#ifdef HAVE_ENDWIN
+ if (isendwin()) {
+ return TRUE;
+ }
+ return FALSE;
+#else
+ rb_notimplement();
+#endif
+}
+
+/* def clear */
+static VALUE
+curses_clear(VALUE obj)
+{
+ wclear(stdscr);
+ return Qnil;
+}
+
+/* def refresh */
+static VALUE
+curses_refresh(VALUE obj)
+{
+ CHECK(refresh());
+ return Qnil;
+}
+
+/* def refresh */
+static VALUE
+curses_doupdate(VALUE obj)
+{
+ CHECK(doupdate());
+ return Qnil;
+}
+
+/* def echo */
+static VALUE
+curses_echo(VALUE obj)
+{
+ CHECK(echo());
+ return Qnil;
+}
+
+/* def noecho */
+static VALUE
+curses_noecho(VALUE obj)
+{
+ CHECK(noecho());
+ return Qnil;
+}
+
+/* def raw */
+static VALUE
+curses_raw(VALUE obj)
+{
+ CHECK(raw());
+ return Qnil;
+}
+
+/* def noraw */
+static VALUE
+curses_noraw(VALUE obj)
+{
+ CHECK(noraw());
+ return Qnil;
+}
+
+/* def cbreak */
+static VALUE
+curses_cbreak(VALUE obj)
+{
+ CHECK(cbreak());
+ return Qnil;
+}
+
+/* def nocbreak */
+static VALUE
+curses_nocbreak(VALUE obj)
+{
+ CHECK(nocbreak());
+ return Qnil;
+}
+
+/* def nl */
+static VALUE
+curses_nl(VALUE obj)
+{
+ CHECK(nl());
+ return Qnil;
+}
+
+/* def nonl */
+static VALUE
+curses_nonl(VALUE obj)
+{
+ CHECK(nonl());
+ return Qnil;
+}
+
+/* def beep */
+static VALUE
+curses_beep(VALUE obj)
+{
+#ifdef HAVE_BEEP
+ beep();
+#endif
+ return Qnil;
+}
+
+/* def flash */
+static VALUE
+curses_flash(VALUE obj)
+{
+ flash();
+ return Qnil;
+}
+
+/* def ungetch */
+static VALUE
+curses_ungetch(VALUE obj, VALUE ch)
+{
+#ifdef HAVE_UNGETCH
+ CHECK(ungetch(NUM2INT(ch)));
+#else
+ rb_notimplement();
+#endif
+ return Qnil;
+}
+
+/* def setpos(y, x) */
+static VALUE
+curses_setpos(VALUE obj, VALUE y, VALUE x)
+{
+ CHECK(move(NUM2INT(y), NUM2INT(x)));
+ return Qnil;
+}
+
+/* def standout */
+static VALUE
+curses_standout(VALUE obj)
+{
+ standout();
+ return Qnil;
+}
+
+/* def standend */
+static VALUE
+curses_standend(VALUE obj)
+{
+ standend();
+ return Qnil;
+}
+
+/* def inch */
+static VALUE
+curses_inch(VALUE obj)
+{
+ return CHAR2FIX(inch());
+}
+
+/* def addch(ch) */
+static VALUE
+curses_addch(VALUE obj, VALUE ch)
+{
+ CHECK(addch(NUM2CHAR(ch)));
+ return Qnil;
+}
+
+/* def insch(ch) */
+static VALUE
+curses_insch(VALUE obj, VALUE ch)
+{
+ CHECK(insch(NUM2CHAR(ch)));
+ return Qnil;
+}
+
+/* def addstr(str) */
+static VALUE
+curses_addstr(VALUE obj, VALUE str)
+{
+ addstr(RSTRING(str)->ptr);
+ return Qnil;
+}
+
+/* def getch */
+static VALUE
+curses_getch(VALUE obj)
+{
+ return CHAR2FIX(getch());
+}
+
+/* def getstr */
+static VALUE
+curses_getstr(VALUE obj)
+{
+ char rtn[1024]; /* This should be big enough.. I hope */
+ CHECK(getstr(rtn));
+ return str_taint(str_new2(rtn));
+}
+
+/* def delch */
+static VALUE
+curses_delch(VALUE obj)
+{
+ CHECK(delch());
+ return Qnil;
+}
+
+/* def delelteln */
+static VALUE
+curses_deleteln(VALUE obj)
+{
+ CHECK(deleteln());
+ return Qnil;
+}
+
+static VALUE
+curses_lines()
+{
+ return INT2FIX(LINES);
+}
+
+static VALUE
+curses_cols()
+{
+ return INT2FIX(COLS);
+}
+
+/*-------------------------- class Window --------------------------*/
+
+/* def new(lines, cols, top, left) */
+static VALUE
+window_s_new(VALUE class,
+ VALUE lines, VALUE cols,
+ VALUE top, VALUE left)
+{
+ WINDOW *window;
+
+ window = newwin(NUM2INT(lines), NUM2INT(cols), NUM2INT(top), NUM2INT(left));
+ wclear(window);
+ return prep_window(class, window);
+}
+
+/* def subwin(lines, cols, top, left) */
+static VALUE
+window_subwin(VALUE obj,
+ VALUE lines, VALUE cols,
+ VALUE top, VALUE left)
+{
+ struct windata *winp;
+ WINDOW *window;
+
+ GetWINDOW(obj, winp);
+ window = subwin(winp->window, NUM2INT(lines), NUM2INT(cols),
+ NUM2INT(top), NUM2INT(left));
+ return prep_window(cWindow, window);
+}
+
+/* def close */
+static VALUE
+window_close(VALUE obj)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ free_window(winp);
+
+ return Qnil;
+}
+
+/* def clear */
+static VALUE
+window_clear(VALUE obj)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ wclear(winp->window);
+
+ return Qnil;
+}
+
+/* def refresh */
+static VALUE
+window_refresh(VALUE obj)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ CHECK(wrefresh(winp->window));
+
+ return Qnil;
+}
+
+/* def box(vert, hor) */
+static VALUE
+window_box(VALUE obj, VALUE vert, VALUE hor)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ box(winp->window, NUM2CHAR(vert), NUM2CHAR(hor));
+
+ return Qnil;
+}
+
+
+/* def move(y, x) */
+static VALUE
+window_move(VALUE obj, VALUE y, VALUE x)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ CHECK(mvwin(winp->window, NUM2INT(y), NUM2INT(x)));
+
+ return Qnil;
+}
+
+/* def setpos(y, x) */
+static VALUE
+window_setpos(VALUE obj, VALUE y, VALUE x)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ CHECK(wmove(winp->window, NUM2INT(y), NUM2INT(x)));
+ return Qnil;
+}
+
+/* def cury */
+static VALUE
+window_cury(VALUE obj)
+{
+ struct windata *winp;
+ int x, y;
+
+ GetWINDOW(obj, winp);
+ getyx(winp->window, y, x);
+ return INT2FIX(y);
+}
+
+/* def curx */
+static VALUE
+window_curx(VALUE obj)
+{
+ struct windata *winp;
+ int x, y;
+
+ GetWINDOW(obj, winp);
+ getyx(winp->window, y, x);
+ return INT2FIX(x);
+}
+
+/* def maxy */
+static VALUE
+window_maxy(VALUE obj)
+{
+ struct windata *winp;
+ int x, y;
+
+ GetWINDOW(obj, winp);
+#ifdef getmaxy
+ return INT2FIX(getmaxy(winp->window));
+#else
+#ifdef getmaxyx
+ getmaxyx(winp->window, y, x);
+ return INT2FIX(y);
+#else
+ return INT2FIX(winp->window->_maxy+1);
+#endif
+#endif
+}
+
+/* def maxx */
+static VALUE
+window_maxx(VALUE obj)
+{
+ struct windata *winp;
+ int x, y;
+
+ GetWINDOW(obj, winp);
+#ifdef getmaxx
+ return INT2FIX(getmaxx(winp->window));
+#else
+#ifdef getmaxyx
+ getmaxyx(winp->window, y, x);
+ return INT2FIX(x);
+#else
+ return INT2FIX(winp->window->_maxx+1);
+#endif
+#endif
+}
+
+/* def begy */
+static VALUE
+window_begy(VALUE obj)
+{
+ struct windata *winp;
+ int x, y;
+
+ GetWINDOW(obj, winp);
+#ifdef getbegyx
+ getbegyx(winp->window, y, x);
+ return INT2FIX(y);
+#else
+ return INT2FIX(winp->window->_begy);
+#endif
+}
+
+/* def begx */
+static VALUE
+window_begx(VALUE obj)
+{
+ struct windata *winp;
+ int x, y;
+
+ GetWINDOW(obj, winp);
+#ifdef getbegyx
+ getbegyx(winp->window, y, x);
+ return INT2FIX(x);
+#else
+ return INT2FIX(winp->window->_begx);
+#endif
+}
+
+/* def standout */
+static VALUE
+window_standout(VALUE obj)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ wstandout(winp->window);
+ return Qnil;
+}
+
+/* def standend */
+static VALUE
+window_standend(VALUE obj)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ wstandend(winp->window);
+ return Qnil;
+}
+
+/* def inch */
+static VALUE
+window_inch(VALUE obj)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ return CHAR2FIX(winch(winp->window));
+}
+
+/* def addch(ch) */
+static VALUE
+window_addch(VALUE obj, VALUE ch)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ CHECK(waddch(winp->window, NUM2CHAR(ch)));
+
+ return Qnil;
+}
+
+/* def insch(ch) */
+static VALUE
+window_insch(VALUE obj, VALUE ch)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ CHECK(winsch(winp->window, NUM2CHAR(ch)));
+
+ return Qnil;
+}
+
+/* def addstr(str) */
+static VALUE
+window_addstr(VALUE obj, VALUE str)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ CHECK(waddstr(winp->window, RSTRING(str)->ptr));
+
+ return Qnil;
+}
+
+/* def <<(str) */
+static VALUE
+window_addstr2(VALUE obj, VALUE str)
+{
+ window_addstr(obj, str);
+ return obj;
+}
+
+/* def getch */
+static VALUE
+window_getch(VALUE obj)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ return CHAR2FIX(wgetch(winp->window));
+}
+
+/* def getstr */
+static VALUE
+window_getstr(VALUE obj)
+{
+ struct windata *winp;
+ char rtn[1024]; /* This should be big enough.. I hope */
+
+ GetWINDOW(obj, winp);
+ CHECK(wgetstr(winp->window, rtn));
+ return str_taint(str_new2(rtn));
+}
+
+/* def delch */
+static VALUE
+window_delch(VALUE obj)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ CHECK(wdelch(winp->window));
+ return Qnil;
+}
+
+/* def delelteln */
+static VALUE
+window_deleteln(VALUE obj)
+{
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ CHECK(wdeleteln(winp->window));
+ return Qnil;
+}
+
+/*------------------------- Initialization -------------------------*/
+void
+Init_curses()
+{
+ mCurses = rb_define_module("Curses");
+ rb_define_module_function(mCurses, "init_screen", curses_init_screen, 0);
+ rb_define_module_function(mCurses, "close_screen", curses_close_screen, 0);
+ rb_define_module_function(mCurses, "closed?", curses_closed, 0);
+ rb_define_module_function(mCurses, "stdscr", curses_stdscr, 0);
+ rb_define_module_function(mCurses, "refresh", curses_refresh, 0);
+ rb_define_module_function(mCurses, "doupdate", curses_doupdate, 0);
+ rb_define_module_function(mCurses, "clear", curses_clear, 0);
+ rb_define_module_function(mCurses, "echo", curses_echo, 0);
+ rb_define_module_function(mCurses, "noecho", curses_noecho, 0);
+ rb_define_module_function(mCurses, "raw", curses_raw, 0);
+ rb_define_module_function(mCurses, "noraw", curses_noraw, 0);
+ rb_define_module_function(mCurses, "cbreak", curses_cbreak, 0);
+ rb_define_module_function(mCurses, "nocbreak", curses_nocbreak, 0);
+ rb_define_alias(mCurses, "crmode", "cbreak");
+ rb_define_alias(mCurses, "nocrmode", "nocbreak");
+ rb_define_module_function(mCurses, "nl", curses_nl, 0);
+ rb_define_module_function(mCurses, "nonl", curses_nonl, 0);
+ rb_define_module_function(mCurses, "beep", curses_beep, 0);
+ rb_define_module_function(mCurses, "flash", curses_flash, 0);
+ rb_define_module_function(mCurses, "ungetch", curses_ungetch, 1);
+ rb_define_module_function(mCurses, "setpos", curses_setpos, 2);
+ rb_define_module_function(mCurses, "standout", curses_standout, 0);
+ rb_define_module_function(mCurses, "standend", curses_standend, 0);
+ rb_define_module_function(mCurses, "inch", curses_inch, 0);
+ rb_define_module_function(mCurses, "addch", curses_addch, 1);
+ rb_define_module_function(mCurses, "insch", curses_insch, 1);
+ rb_define_module_function(mCurses, "addstr", curses_addstr, 1);
+ rb_define_module_function(mCurses, "getch", curses_getch, 0);
+ rb_define_module_function(mCurses, "getstr", curses_getstr, 0);
+ rb_define_module_function(mCurses, "delch", curses_delch, 0);
+ rb_define_module_function(mCurses, "deleteln", curses_deleteln, 0);
+ rb_define_module_function(mCurses, "lines", curses_lines, 0);
+ rb_define_module_function(mCurses, "cols", curses_cols, 0);
+
+ cWindow = rb_define_class_under(mCurses, "Window", cObject);
+ rb_define_singleton_method(cWindow, "new", window_s_new, 4);
+ rb_define_method(cWindow, "subwin", window_subwin, 4);
+ rb_define_method(cWindow, "close", window_close, 0);
+ rb_define_method(cWindow, "clear", window_clear, 0);
+ rb_define_method(cWindow, "refresh", window_refresh, 0);
+ rb_define_method(cWindow, "box", window_box, 2);
+ rb_define_method(cWindow, "move", window_move, 2);
+ rb_define_method(cWindow, "setpos", window_setpos, 2);
+ rb_define_method(cWindow, "cury", window_cury, 0);
+ rb_define_method(cWindow, "curx", window_curx, 0);
+ rb_define_method(cWindow, "maxy", window_maxy, 0);
+ rb_define_method(cWindow, "maxx", window_maxx, 0);
+ rb_define_method(cWindow, "begy", window_begy, 0);
+ rb_define_method(cWindow, "begx", window_begx, 0);
+ rb_define_method(cWindow, "standout", window_standout, 0);
+ rb_define_method(cWindow, "standend", window_standend, 0);
+ rb_define_method(cWindow, "inch", window_inch, 0);
+ rb_define_method(cWindow, "addch", window_addch, 1);
+ rb_define_method(cWindow, "insch", window_insch, 1);
+ rb_define_method(cWindow, "addstr", window_addstr, 1);
+ rb_define_method(cWindow, "<<", window_addstr2, 1);
+ rb_define_method(cWindow, "getch", window_getch, 0);
+ rb_define_method(cWindow, "getstr", window_getstr, 0);
+ rb_define_method(cWindow, "delch", window_delch, 0);
+ rb_define_method(cWindow, "deleteln", window_deleteln, 0);
+}
diff --git a/ext/curses/extconf.rb b/ext/curses/extconf.rb
new file mode 100644
index 0000000000..22b1e2f0cc
--- /dev/null
+++ b/ext/curses/extconf.rb
@@ -0,0 +1,21 @@
+$CFLAGS="-I/usr/include/ncurses -I/usr/local/include/ncurses"
+$LDFLAGS="-L/usr/local/lib"
+make=FALSE
+if have_header("ncurses.h") and have_library("ncurses", "initscr")
+ make=TRUE
+elsif have_header("ncurses/curses.h") and have_library("ncurses", "initscr")
+ make=TRUE
+else
+ $CFLAGS=nil
+ have_library("termcap", "tparam")
+ if have_library("curses", "initscr")
+ make=TRUE
+ end
+end
+
+if make then
+ for f in ["isendwin", "ungetch", "beep"]
+ have_func(f)
+ end
+ create_makefile("curses")
+end
diff --git a/ext/curses/hello.rb b/ext/curses/hello.rb
new file mode 100644
index 0000000000..bed7779aac
--- /dev/null
+++ b/ext/curses/hello.rb
@@ -0,0 +1,28 @@
+#!/usr/local/bin/ruby
+
+require "curses"
+include Curses
+
+def show_message(message)
+ width = message.length + 6
+ win = Window.new(5, width,
+ (lines - 5) / 2, (cols - width) / 2)
+ win.box(?|, ?=)
+ win.setpos(2, 3)
+ win.addstr(message)
+ win.getch
+ win.close
+end
+
+init_screen
+begin
+ crmode
+# show_message("Hit any key")
+ setpos (lines - 5) / 2, (cols - 10) / 2
+ addstr("Hit any key")
+ getch
+ show_message("Hello, World!")
+ refresh
+ensure
+ close_screen
+end
diff --git a/ext/curses/rain.rb b/ext/curses/rain.rb
new file mode 100644
index 0000000000..36f0f84de2
--- /dev/null
+++ b/ext/curses/rain.rb
@@ -0,0 +1,76 @@
+#!/usr/local/bin/ruby
+# rain for a curses test
+
+require "curses"
+include Curses
+
+def onsig(sig)
+ close_screen
+ exit sig
+end
+
+def ranf
+ rand(32767).to_f / 32767
+end
+
+# main #
+for i in 1 .. 15 # SIGHUP .. SIGTERM
+ if trap(i, "SIG_IGN") != 0 then # 0 for SIG_IGN
+ trap(i) {|sig| onsig(sig) }
+ end
+end
+
+init_screen
+nl
+noecho
+srand
+
+xpos = {}
+ypos = {}
+r = lines - 4
+c = cols - 4
+for i in 0 .. 4
+ xpos[i] = (c * ranf).to_i + 2
+ ypos[i] = (r * ranf).to_i + 2
+end
+
+i = 0
+while TRUE
+ x = (c * ranf).to_i + 2
+ y = (r * ranf).to_i + 2
+
+
+ setpos(y, x); addstr(".")
+
+ setpos(ypos[i], xpos[i]); addstr("o")
+
+ i = if i == 0 then 4 else i - 1 end
+ setpos(ypos[i], xpos[i]); addstr("O")
+
+ i = if i == 0 then 4 else i - 1 end
+ setpos(ypos[i] - 1, xpos[i]); addstr("-")
+ setpos(ypos[i], xpos[i] - 1); addstr("|.|")
+ setpos(ypos[i] + 1, xpos[i]); addstr("-")
+
+ i = if i == 0 then 4 else i - 1 end
+ setpos(ypos[i] - 2, xpos[i]); addstr("-")
+ setpos(ypos[i] - 1, xpos[i] - 1); addstr("/ \\")
+ setpos(ypos[i], xpos[i] - 2); addstr("| O |")
+ setpos(ypos[i] + 1, xpos[i] - 1); addstr("\\ /")
+ setpos(ypos[i] + 2, xpos[i]); addstr("-")
+
+ i = if i == 0 then 4 else i - 1 end
+ setpos(ypos[i] - 2, xpos[i]); addstr(" ")
+ setpos(ypos[i] - 1, xpos[i] - 1); addstr(" ")
+ setpos(ypos[i], xpos[i] - 2); addstr(" ")
+ setpos(ypos[i] + 1, xpos[i] - 1); addstr(" ")
+ setpos(ypos[i] + 2, xpos[i]); addstr(" ")
+
+
+ xpos[i] = x
+ ypos[i] = y
+ refresh
+ sleep(0.5)
+end
+
+# end of main
diff --git a/ext/curses/view.rb b/ext/curses/view.rb
new file mode 100644
index 0000000000..e59a74ed44
--- /dev/null
+++ b/ext/curses/view.rb
@@ -0,0 +1,90 @@
+#!/usr/local/bin/ruby
+
+require "curses"
+include Curses
+
+#
+# main
+#
+
+if ARGV.size != 1 then
+ printf("usage: view file\n");
+ exit
+end
+begin
+ fp = open(ARGV[0], "r")
+rescue
+ raise "cannot open file: #{ARGV[1]}"
+end
+
+# signal(SIGINT, finish)
+
+init_screen
+#keypad(stdscr, TRUE)
+nonl
+cbreak
+noecho
+#scrollok(stdscr, TRUE)
+
+# slurp the file
+data_lines = []
+fp.each_line { |l|
+ data_lines.push(l)
+}
+fp.close
+
+
+lptr = 0
+while TRUE
+ i = 0
+ while i < lines
+ setpos(i, 0)
+ #clrtoeol
+ addstr(data_lines[lptr + i]) #if data_lines[lptr + i]
+ i += 1
+ end
+
+ explicit = FALSE
+ n = 0
+ while TRUE
+ c = getch.chr
+ if c =~ "[0-9]" then
+ n = 10 * n + c.to_i
+ else
+ break
+ end
+ end
+
+ n = 1 if !explicit && n == 0
+
+ case c
+ when "n" #when KEY_DOWN
+ i = 0
+ while i < n
+ if lptr + lines < data_lines.size then
+ lptr += 1
+ else
+ break
+ end
+ i += 1
+ end
+ #wscrl(i)
+
+ when "p" #when KEY_UP
+ i = 0
+ while i < n
+ if lptr > 0 then
+ lptr -= 1
+ else
+ break
+ end
+ i += 1
+ end
+ #wscrl(-i)
+
+ when "q"
+ break
+ end
+
+end
+close_screen
diff --git a/ext/dbm/dbm.c b/ext/dbm/dbm.c
index 5d8a12e3f9..f0522f2d48 100644
--- a/ext/dbm/dbm.c
+++ b/ext/dbm/dbm.c
@@ -26,14 +26,14 @@ struct dbmdata {
};
static void
-closeddbm()
+closed_dbm()
{
Fail("closed DBM file");
}
#define GetDBM(obj, dbmp) {\
- Get_Data_Struct(obj, struct dbmdata, dbmp);\
- if (dbmp->di_dbm == 0) closeddbm();\
+ Data_Get_Struct(obj, struct dbmdata, dbmp);\
+ if (dbmp->di_dbm == 0) closed_dbm();\
}
static void
@@ -64,7 +64,7 @@ fdbm_s_open(argc, argv, class)
else {
mode = NUM2INT(vmode);
}
- Check_Type(file, T_STRING);
+ Check_SafeStr(file);
dbm = 0;
if (mode >= 0)
@@ -79,7 +79,7 @@ fdbm_s_open(argc, argv, class)
rb_sys_fail(RSTRING(file)->ptr);
}
- obj = Make_Data_Struct(class,struct dbmdata,0,free_dbm,dbmp);
+ obj = Data_Make_Struct(class,struct dbmdata,0,free_dbm,dbmp);
dbmp->di_dbm = dbm;
dbmp->di_size = -1;
@@ -92,8 +92,8 @@ fdbm_close(obj)
{
struct dbmdata *dbmp;
- Get_Data_Struct(obj, struct dbmdata, dbmp);
- if (dbmp->di_dbm == 0) closeddbm();
+ Data_Get_Struct(obj, struct dbmdata, dbmp);
+ if (dbmp->di_dbm == 0) closed_dbm();
dbm_close(dbmp->di_dbm);
dbmp->di_dbm = 0;
@@ -118,7 +118,7 @@ fdbm_fetch(obj, keystr)
if (value.dptr == 0) {
return Qnil;
}
- return str_new(value.dptr, value.dsize);
+ return str_taint(str_new(value.dptr, value.dsize));
}
static VALUE
@@ -148,6 +148,7 @@ fdbm_delete(obj, keystr)
struct dbmdata *dbmp;
DBM *dbm;
+ rb_secure(4);
Check_Type(keystr, T_STRING);
key.dptr = RSTRING(keystr)->ptr;
key.dsize = RSTRING(keystr)->len;
@@ -157,7 +158,7 @@ fdbm_delete(obj, keystr)
value = dbm_fetch(dbm, key);
if (value.dptr == 0) {
- if (iterator_p()) rb_yield(Qnil);
+ if (iterator_p()) rb_yield(keystr);
return Qnil;
}
@@ -180,6 +181,7 @@ fdbm_shift(obj)
DBM *dbm;
VALUE keystr, valstr;
+ rb_secure(4);
GetDBM(obj, dbmp);
dbm = dbmp->di_dbm;
@@ -188,8 +190,8 @@ fdbm_shift(obj)
val = dbm_fetch(dbm, key);
dbm_delete(dbm, key);
- keystr = str_new(key.dptr, key.dsize);
- valstr = str_new(val.dptr, val.dsize);
+ keystr = str_taint(str_new(key.dptr, key.dsize));
+ valstr = str_taint(str_new(val.dptr, val.dsize));
return assoc_new(keystr, valstr);
}
@@ -202,11 +204,12 @@ fdbm_delete_if(obj)
DBM *dbm;
VALUE keystr, valstr;
+ rb_secure(4);
GetDBM(obj, dbmp);
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
val = dbm_fetch(dbm, key);
- keystr = str_new(key.dptr, key.dsize);
- valstr = str_new(val.dptr, val.dsize);
+ keystr = str_taint(str_new(key.dptr, key.dsize));
+ valstr = str_taint(str_new(val.dptr, val.dsize));
if (RTEST(rb_yield(assoc_new(keystr, valstr)))) {
if (dbm_delete(dbm, key)) {
Fail("dbm_delete failed");
@@ -224,6 +227,7 @@ fdbm_clear(obj)
struct dbmdata *dbmp;
DBM *dbm;
+ rb_secure(4);
GetDBM(obj, dbmp);
dbm = dbmp->di_dbm;
dbmp->di_size = -1;
@@ -248,6 +252,7 @@ fdbm_store(obj, keystr, valstr)
return Qnil;
}
+ rb_secure(4);
keystr = obj_as_string(keystr);
key.dptr = RSTRING(keystr)->ptr;
@@ -259,7 +264,7 @@ fdbm_store(obj, keystr, valstr)
val.dptr = RSTRING(valstr)->ptr;
val.dsize = RSTRING(valstr)->len;
- Get_Data_Struct(obj, struct dbmdata, dbmp);
+ Data_Get_Struct(obj, struct dbmdata, dbmp);
dbmp->di_size = -1;
dbm = dbmp->di_dbm;
if (dbm_store(dbm, key, val, DBM_REPLACE)) {
@@ -280,7 +285,7 @@ fdbm_length(obj)
DBM *dbm;
int i = 0;
- Get_Data_Struct(obj, struct dbmdata, dbmp);
+ Data_Get_Struct(obj, struct dbmdata, dbmp);
if (dbmp->di_size > 0) return INT2FIX(dbmp->di_size);
dbm = dbmp->di_dbm;
@@ -293,7 +298,7 @@ fdbm_length(obj)
}
static VALUE
-fdbm_empty(obj)
+fdbm_empty_p(obj)
VALUE obj;
{
datum key;
@@ -301,7 +306,7 @@ fdbm_empty(obj)
DBM *dbm;
int i = 0;
- Get_Data_Struct(obj, struct dbmdata, dbmp);
+ Data_Get_Struct(obj, struct dbmdata, dbmp);
if (dbmp->di_size < 0) {
dbm = dbmp->di_dbm;
@@ -328,7 +333,7 @@ fdbm_each_value(obj)
dbm = dbmp->di_dbm;
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
val = dbm_fetch(dbm, key);
- rb_yield(str_new(val.dptr, val.dsize));
+ rb_yield(str_taint(str_new(val.dptr, val.dsize)));
}
return obj;
}
@@ -344,7 +349,7 @@ fdbm_each_key(obj)
GetDBM(obj, dbmp);
dbm = dbmp->di_dbm;
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
- rb_yield(str_new(key.dptr, key.dsize));
+ rb_yield(str_taint(str_new(key.dptr, key.dsize)));
}
return obj;
}
@@ -363,8 +368,8 @@ fdbm_each_pair(obj)
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
val = dbm_fetch(dbm, key);
- keystr = str_new(key.dptr, key.dsize);
- valstr = str_new(val.dptr, val.dsize);
+ keystr = str_taint(str_new(key.dptr, key.dsize));
+ valstr = str_taint(str_new(val.dptr, val.dsize));
rb_yield(assoc_new(keystr, valstr));
}
@@ -385,7 +390,7 @@ fdbm_keys(obj)
ary = ary_new();
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
- ary_push(ary, str_new(key.dptr, key.dsize));
+ ary_push(ary, str_taint(str_new(key.dptr, key.dsize)));
}
return ary;
@@ -406,7 +411,7 @@ fdbm_values(obj)
ary = ary_new();
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
val = dbm_fetch(dbm, key);
- ary_push(ary, str_new(val.dptr, val.dsize));
+ ary_push(ary, str_taint(str_new(val.dptr, val.dsize)));
}
return ary;
@@ -469,8 +474,8 @@ fdbm_to_a(obj)
ary = ary_new();
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
val = dbm_fetch(dbm, key);
- ary_push(ary, assoc_new(str_new(key.dptr, key.dsize),
- str_new(val.dptr, val.dsize)));
+ ary_push(ary, assoc_new(str_taint(str_new(key.dptr, key.dsize)),
+ str_taint(str_new(val.dptr, val.dsize))));
}
return ary;
@@ -488,7 +493,7 @@ Init_dbm()
rb_define_method(cDBM, "indexes", fdbm_indexes, -2);
rb_define_method(cDBM, "length", fdbm_length, 0);
rb_define_alias(cDBM, "size", "length");
- rb_define_method(cDBM, "empty?", fdbm_empty, 0);
+ rb_define_method(cDBM, "empty?", fdbm_empty_p, 0);
rb_define_method(cDBM, "each", fdbm_each_pair, 0);
rb_define_method(cDBM, "each_value", fdbm_each_value, 0);
rb_define_method(cDBM, "each_key", fdbm_each_key, 0);
diff --git a/ext/dbm/extconf.rb b/ext/dbm/extconf.rb
index 2302ee2d5d..4a5d41f275 100644
--- a/ext/dbm/extconf.rb
+++ b/ext/dbm/extconf.rb
@@ -1,3 +1,4 @@
+$LDFLAGS = "-L/usr/local/lib"
have_library("gdbm", "dbm_open") or have_library("dbm", "dbm_open")
if have_func("dbm_open")
create_makefile("dbm")
diff --git a/ext/etc/etc.c b/ext/etc/etc.c
index 524800bd03..5cab110449 100644
--- a/ext/etc/etc.c
+++ b/ext/etc/etc.c
@@ -123,7 +123,7 @@ static VALUE
etc_passwd(obj)
VALUE obj;
{
-#ifdef HAVE_GETPWENT
+#if defined(HAVE_GETPWENT) && !defined(__CYGWIN32__)
struct passwd *pw;
if (iterator_p()) {
diff --git a/ext/extmk.rb.in b/ext/extmk.rb.in
index bd4eed306b..f1acef5608 100644
--- a/ext/extmk.rb.in
+++ b/ext/extmk.rb.in
@@ -17,6 +17,14 @@ $cache_mod = FALSE;
$lib_cache = {}
$func_cache = {}
$hdr_cache = {}
+$topdir = "@top_srcdir@"
+if $topdir !~ "^/"
+ # get absolute path
+ save = Dir.pwd
+ Dir.chdir ".."
+ $topdir = Dir.pwd
+ Dir.chdir save
+end
if File.exist?("config.cache") then
f = open("config.cache", "r")
@@ -46,14 +54,29 @@ def older(file1, file2)
return FALSE
end
-LINK = "@CC@ -o conftest %s %s conftest.c %s > /dev/null 2>&1"
-CPP = "@CPP@ @CPPFLAGS@ %s conftest.c > /dev/null 2>&1"
+if PLATFORM == "m68k-human"
+CFLAGS = "@CFLAGS@".gsub(/-c..-stack=[0-9]+ */, '')
+LINK = "@CC@ -o conftest -I#{$topdir} " + CFLAGS + " %s @LDFLAGS@ %s conftest.c @LIBS@ %s > nul 2>&1"
+CPP = "@CPP@ @CPPFLAGS@ -I#{$topdir} " + CFLAGS + " %s conftest.c > nul 2>&1"
+else
+CFLAGS = "@CFLAGS@"
+LINK = "@CC@ -o conftest -I#{$topdir} " + CFLAGS + " %s @LDFLAGS@ %s conftest.c %s > /dev/null 2>&1"
+CPP = "@CPP@ @CPPFLAGS@ -I#{$topdir} " + CFLAGS + " %s conftest.c > /dev/null 2>&1"
+end
+
+def try_link(libs)
+ system(format(LINK, $CFLAGS, $LDFLAGS, libs))
+end
+
+def try_cpp
+ system(format(CPP, $CFLAGS))
+end
def have_library(lib, func)
if $lib_cache[lib]
if $lib_cache[lib] == "yes"
if $libs
- $libs = $libs + " -l" + lib
+ $libs = "-l" + lib + " " + $libs
else
$libs = "-l" + lib
end
@@ -72,17 +95,17 @@ int t() { %s(); return 0; }
begin
if $libs
- libs = "-l" + lib + " " + $libs
+ libs = "-l" + lib + " " + $libs
else
libs = "-l" + lib
end
- if !system(format(LINK, $CFLAGS, $LDFLAGS, libs))
+ unless try_link(libs)
$lib_cache[lib] = 'no'
$cache_mod = TRUE
return FALSE
end
ensure
- system "/bin/rm -f conftest*"
+ system "rm -f conftest*"
end
$libs = libs
@@ -113,13 +136,13 @@ int t() { %s(); return 0; }
libs = "" if libs == nil
begin
- if !system(format(LINK, $CFLAGS, $LDFLAGS, libs))
+ unless try_link(libs)
$func_cache[func] = 'no'
$cache_mod = TRUE
return FALSE
end
ensure
- system "/bin/rm -f conftest*"
+ system "rm -f conftest*"
end
$defs.push(format("-DHAVE_%s", func.upcase))
$func_cache[func] = 'yes'
@@ -145,13 +168,13 @@ def have_header(header)
cfile.close
begin
- if !system(format(CPP, $CFLAGS))
+ unless try_cpp
$hdr_cache[header] = 'no'
$cache_mod = TRUE
return FALSE
end
ensure
- system "/bin/rm -f conftest*"
+ system "rm -f conftest*"
end
$hdr_cache[header] = 'yes'
header.tr!("a-z./\055", "A-Z___")
@@ -180,39 +203,39 @@ def create_makefile(target)
end
$defs.push(format("-DEXTLIB='%s'", libs.join(",")))
end
- $libs = "" if not $libs
+ $libs = "" unless $libs
+ $srcdir = $topdir + "/ext/" + target
mfile = open("Makefile", "w")
mfile.printf "\
SHELL = /bin/sh
#### Start of system configuration section. ####
-srcdir = @srcdir@
-VPATH = @srcdir@
+srcdir = #{$srcdir}
+VPATH = #{$srcdir}
CC = @CC@
-CFLAGS = %s #$CFLAGS %s
-LDFLAGS = @LDFLAGS@
-DLDFLAGS = @DLDFLAGS@
+CFLAGS = %s -I#{$topdir} %s #$CFLAGS %s
+DLDFLAGS = @DLDFLAGS@ #$LDFLAGS
LDSHARED = @LDSHARED@
-", if $static then "" else "@CCDLFLAGS@" end, $defs.join(" ")
+", if $static then "" else "@CCDLFLAGS@" end, CFLAGS, $defs.join(" ")
mfile.printf "\
prefix = @prefix@
exec_prefix = @exec_prefix@
-bindir = $(exec_prefix)/bin
-libdir = @archlib@
+libdir = @libdir@/ruby/@arch@
@SET_MAKE@
#### End of system configuration section. ####
"
+ mfile.printf "LOCAL_LIBS = %s\n", $local_libs if $local_libs
mfile.printf "LIBS = %s\n", $libs
mfile.printf "OBJS = "
if !$objs then
- $objs = Dir["*.c"]
+ $objs = Dir["#{$topdir}/ext/#{target}/*.c"]
for f in $objs
f.sub!(/\.c$/, ".o")
end
@@ -220,17 +243,19 @@ libdir = @archlib@
mfile.printf $objs.join(" ")
mfile.printf "\n"
- dots = if "@INSTALL@" =~ /^\// then "" else "../" end
+ dots = if "@INSTALL@" =~ /^\// then "" else "#{$topdir}/" end
mfile.printf "\
TARGET = %s.%s
INSTALL = %s@INSTALL@
+binsuffix = @binsuffix@
+
all: $(TARGET)
clean:; @rm -f *.o *.so *.sl
@rm -f Makefile extconf.h conftest.*
- @rm -f core ruby *~
+ @rm -f core ruby$(binsuffix) *~
realclean: clean
", target,
@@ -255,13 +280,20 @@ install:;
if !$static && "@DLEXT@" != "o"
mfile.printf "\
$(TARGET): $(OBJS)
- $(LDSHARED) $(DLDFLAGS) -o $(TARGET) $(OBJS) $(LIBS)
+ $(LDSHARED) $(DLDFLAGS) -o $(TARGET) $(OBJS) $(LOCAL_LIBS) $(LIBS)
+"
+ elsif not File.exist?(target + ".c")
+ if PLATFORM == "m68k-human"
+ mfile.printf "\
+$(TARGET): $(OBJS)
+ ar cru $(TARGET) $(OBJS)
"
- elsif !File.exist?(target + ".c")
+ else
mfile.printf "\
$(TARGET): $(OBJS)
- ld $(LDFLAGS) -r -o $(TARGET) $(OBJS)
+ ld $(DLDFLAGS) -r -o $(TARGET) $(OBJS)
"
+ end
end
if File.exist?("depend")
@@ -287,16 +319,18 @@ def extmake(target)
return if $nodynamic and not $static
+ $local_libs = nil
$libs = nil
$objs = nil
- $CFLAGS = "-I../.. @CFLAGS@"
- $LDFLAGS = "@STATIC@ @LDFLAGS@"
+ $CFLAGS = nil
+ $LDFLAGS = nil
begin
+ system "mkdir " + target unless File.directory?(target)
Dir.chdir target
if $static_ext.size > 0 ||
!File.exist?("./Makefile") ||
- older("./Makefile", "../Setup") ||
+ older("./Makefile", "#{$topdir}/ext/@setup@") ||
older("./Makefile", "../extmk.rb") ||
older("./Makefile", "./extconf.rb")
then
@@ -316,7 +350,11 @@ def extmake(target)
system "make all"
end
end
- $extlibs += " " + $libs if $static && $libs
+ if $static
+ $extlibs += " " + $LDFLAGS if $LDFLAGS
+ $extlibs += " " + $local_libs if $local_libs
+ $extlibs += " " + $libs if $libs
+ end
ensure
Dir.chdir ".."
end
@@ -324,8 +362,8 @@ end
# get static-link modules
$static_ext = {}
-if File.file? "./Setup"
- f = open("./Setup")
+if File.file? "#{$topdir}/ext/@setup@"
+ f = open("#{$topdir}/ext/@setup@")
while f.gets()
$_.chop!
sub!(/#.*$/, '')
@@ -339,11 +377,11 @@ if File.file? "./Setup"
f.close
end
-for d in Dir["*"]
+for d in Dir["#{$topdir}/ext/*"]
File.directory?(d) || next
File.file?(d + "/MANIFEST") || next
- d = $1 if d =~ /\/([\/]*)$/
+ d = File.basename(d)
if $install
print "installing ", d, "\n"
elsif $clean
@@ -385,7 +423,7 @@ if $extlist.size > 0
end
end
- if older("extinit.c", "Setup")
+ if older("extinit.c", "#{$topdir}/ext/@setup@")
f = open("extinit.c", "w")
f.printf "void Init_ext() {\n"
f.printf $extinit
@@ -393,24 +431,24 @@ if $extlist.size > 0
f.close
end
if older("extinit.o", "extinit.c")
- cmd = "@CC@ @CFLAGS@ -c extinit.c"
+ cmd = "@CC@ " + CFLAGS + " -c extinit.c"
print cmd, "\n"
system cmd or exit 1
end
Dir.chdir ".."
- if older("ruby", "ext/Setup") or older("ruby", "miniruby")
- `rm -f ruby`
+ if older("ruby@binsuffix@", "#{$topdir}/ext/@setup@") or older("ruby@binsuffix@", "miniruby@binsuffix@")
+ `rm -f ruby@binsuffix@`
end
$extobjs = "ext/extinit.o " + $extobjs
- system format('make ruby PROGRAM=ruby EXTOBJS="%s" EXTLIBS="%s"', $extobjs, $extlibs)
+ system format('make ruby@binsuffix@ EXTOBJS="%s" EXTLIBS="%s"', $extobjs, $extlibs)
else
Dir.chdir ".."
- if older("ruby", "miniruby")
- `rm -f ruby`
- `cp miniruby ruby`
+ if older("ruby@binsuffix@", "miniruby@binsuffix@")
+ `rm -f ruby@binsuffix@`
+ `cp miniruby@binsuffix@ ruby@binsuffix@`
end
end
diff --git a/ext/extmk.rb.nt b/ext/extmk.rb.nt
new file mode 100644
index 0000000000..33f676a804
--- /dev/null
+++ b/ext/extmk.rb.nt
@@ -0,0 +1,436 @@
+#! /usr/local/bin/ruby
+
+if ARGV[0] == 'static'
+ $force_static = TRUE
+ ARGV.shift
+elsif ARGV[0] == 'install'
+ $install = TRUE
+ ARGV.shift
+elsif ARGV[0] == 'clean'
+ $clean = TRUE
+ ARGV.shift
+end
+
+$extlist = []
+
+$cache_mod = FALSE;
+$lib_cache = {}
+$func_cache = {}
+$hdr_cache = {}
+
+if File.exist?("config.cache") then
+ f = open("config.cache", "r")
+ while f.gets
+ case $_
+ when /^lib: ([\w_]+) (yes|no)/
+ $lib_cache[$1] = $2
+ when /^func: ([\w_]+) (yes|no)/
+ $func_cache[$1] = $2
+ when /^hdr: (.+) (yes|no)/
+ $hdr_cache[$1] = $2
+ end
+ end
+ f.close
+end
+
+def older(file1, file2)
+ if !File.exist?(file1) then
+ return TRUE
+ end
+ if !File.exist?(file2) then
+ return FALSE
+ end
+ if File.mtime(file1) < File.mtime(file2)
+ return TRUE
+ end
+ return FALSE
+end
+
+LINK = "cl -o conftest -I../.. -Zi -O -I. %s %s conftest.c %s > nul"
+CPP = "cl -E -I../.. -Zi -O -I. %s conftest.c > nul"
+
+def try_link(libs)
+ system(format(LINK, $CFLAGS, $LDFLAGS, libs))
+end
+
+def try_cpp
+ system(format(CPP, $CFLAGS))
+end
+
+def have_library(lib, func)
+ if $lib_cache[lib]
+ if $lib_cache[lib] == "yes"
+ if $libs
+ $libs = "-l" + lib + " " + $libs
+ else
+ $libs = "-l" + lib
+ end
+ return TRUE
+ else
+ return FALSE
+ end
+ end
+
+ cfile = open("conftest.c", "w")
+ cfile.printf "\
+int main() { return 0; }
+int t() { %s(); return 0; }
+", func
+ cfile.close
+
+ begin
+ if $libs
+ libs = lib + ".lib " + $libs
+ else
+ libs = lib + ".lib"
+ end
+ unless try_link(libs)
+ $lib_cache[lib] = 'no'
+ $cache_mod = TRUE
+ return FALSE
+ end
+ ensure
+ system "rm -f conftest*"
+ end
+
+ $libs = libs
+ $lib_cache[lib] = 'yes'
+ $cache_mod = TRUE
+ return TRUE
+end
+
+def have_func(func)
+ if $func_cache[func]
+ if $func_cache[func] == "yes"
+ $defs.push(format("-DHAVE_%s", func.upcase))
+ return TRUE
+ else
+ return FALSE
+ end
+ end
+
+ cfile = open("conftest.c", "w")
+ cfile.printf "\
+char %s();
+int main() { return 0; }
+int t() { %s(); return 0; }
+", func, func
+ cfile.close
+
+ libs = $libs
+ libs = "" if libs == nil
+
+ begin
+ unless try_link(libs)
+ $func_cache[func] = 'no'
+ $cache_mod = TRUE
+ return FALSE
+ end
+ ensure
+ system "rm -f conftest*"
+ end
+ $defs.push(format("-DHAVE_%s", func.upcase))
+ $func_cache[func] = 'yes'
+ $cache_mod = TRUE
+ return TRUE
+end
+
+def have_header(header)
+ if $hdr_cache[header]
+ if $hdr_cache[header] == "yes"
+ header.tr!("a-z./\055", "A-Z___")
+ $defs.push(format("-DHAVE_%s", header))
+ return TRUE
+ else
+ return FALSE
+ end
+ end
+
+ cfile = open("conftest.c", "w")
+ cfile.printf "\
+#include <%s>
+", header
+ cfile.close
+
+ begin
+ unless try_cpp
+ $hdr_cache[header] = 'no'
+ $cache_mod = TRUE
+ return FALSE
+ end
+ ensure
+ system "rm -f conftest*"
+ end
+ $hdr_cache[header] = 'yes'
+ header.tr!("a-z./\055", "A-Z___")
+ $defs.push(format("-DHAVE_%s", header))
+ $cache_mod = TRUE
+ return TRUE
+end
+
+def create_header()
+ if $defs.length > 0
+ hfile = open("extconf.h", "w")
+ for line in $defs
+ line =~ /^-D(.*)/
+ hfile.printf "#define %s 1\n", $1
+ end
+ hfile.close
+ end
+end
+
+def create_makefile(target)
+
+ if $libs and "obj" == "obj"
+ libs = $libs.split
+ for lib in libs
+ lib.sub!(/(.*)/, '"lib\1.lib"')
+ end
+ $defs.push(format("-DEXTLIB='%s'", libs.join(",")))
+ end
+ $libs = "" unless $libs
+
+ mfile = open("Makefile", "w")
+ mfile.printf "\
+SHELL = $(COMPSEC)
+
+#### Start of system configuration section. ####
+
+srcdir = .
+VPATH = .
+
+CC = cl
+
+CFLAGS = %s -I../.. -Zi -O -I. -DNT -MD #$CFLAGS %s
+DLDFLAGS = /DLL
+LDSHARED =
+", if $static then "" else "-fpic" end, $defs.join(" ")
+
+ mfile.printf "\
+
+libdir = /usr/local/lib/ruby/i386-mswin32
+
+
+#### End of system configuration section. ####
+"
+ mfile.printf "LOCAL_LIBS = %s\n", $local_libs if $local_libs
+ mfile.printf "LIBS = %s\n", $libs
+ mfile.printf "OBJS = "
+ if !$objs then
+ $objs = Dir["*.c"]
+ for f in $objs
+ f.sub!(/\.c$/, ".obj")
+ end
+ end
+ mfile.printf $objs.join(" ")
+ mfile.printf "\n"
+
+ dots = if "ginstall -c" =~ /^\// then "" else "../" end
+ mfile.printf "\
+TARGET = %s.%s
+
+INSTALL = %sginstall -c
+
+all: $(TARGET)
+
+clean:; @rm -f *.obj *.lib *.exp *.pdb *.bak
+ @rm -f Makefile extconf.h conftest.*
+
+realclean: clean
+", target,
+ if $static then "obj" else "obj" end, dots
+
+ if !$static
+ mfile.printf "\
+
+install: $(libdir)/$(TARGET)
+
+$(libdir)/$(TARGET): $(TARGET)
+ @test -d $(libdir) || mkdir $(libdir)
+ $(INSTALL) $(TARGET) $(libdir)/$(TARGET)
+"
+ else
+ mfile.printf "\
+
+install:;
+"
+ end
+
+ if !$static && "obj" != "obj"
+ mfile.printf "\
+$(TARGET): $(OBJS)
+ $(LDSHARED) $(DLDFLAGS) -o $(TARGET) $(OBJS) $(LOCAL_LIBS) $(LIBS)
+"
+ elsif not File.exist?(target + ".c")
+ mfile.printf "\
+$(TARGET): $(OBJS)
+# ld $(DLDFLAGS) -r -o $(TARGET) $(OBJS)
+ cl -c $(OBJS)
+ lib /OUT:$(TARGET) $(OBJS)
+"
+ end
+
+ if File.exist?("depend")
+ dfile = open("depend", "r")
+ mfile.printf "###\n"
+ while line = dfile.gets()
+ mfile.printf "%s", line
+ end
+ dfile.close
+ end
+ mfile.close
+ if $static
+ printf format("push %s,%s\n", $static, target); ##debug print##
+ $extlist.push [$static,target]
+ end
+end
+
+def extmake(target)
+ if $force_static or $static_ext[target]
+ $static = target
+ else
+ $static = FALSE
+ end
+
+ return if $nodynamic and not $static
+
+ $local_libs = nil
+ $libs = nil
+ $objs = nil
+ $CFLAGS = nil
+ $LDFLAGS = nil
+
+ begin
+ Dir.chdir target
+ if $static_ext.size > 0 ||
+ !File.exist?("./Makefile") ||
+ older("./Makefile", "../Setup") ||
+ older("./Makefile", "../extmk.rb") ||
+ older("./Makefile", "./extconf.rb")
+ then
+ $defs = []
+ if File.exist?("extconf.rb")
+ load "extconf.rb"
+ else
+ create_makefile(target);
+ end
+ end
+ if File.exist?("./Makefile")
+ if $install
+ system "nmake install"
+ elsif $clean
+ system "nmake clean"
+ else
+ system "nmake all"
+ end
+ end
+ if $static
+ $extlibs += " " + $LDFLAGS if $LDFLAGS
+ $extlibs += " " + $local_libs if $local_libs
+ $extlibs += " " + $libs if $libs
+ end
+ ensure
+ Dir.chdir ".."
+ end
+end
+
+# get static-link modules
+$static_ext = {}
+if File.file? "./Setup"
+ f = open("./Setup")
+ while f.gets()
+ $_.chop!
+ sub!(/#.*$/, '')
+ next if /^\s*$/
+ print $_, "\n"
+ if /^option +nodynamic/
+ $nodynamic = TRUE
+ next
+ end
+ $static_ext[$_.split[0]] = TRUE
+ end
+ f.close
+end
+
+for d in Dir["*"]
+ File.directory?(d) || next
+ File.file?(d + "/MANIFEST") || next
+
+ d = $1 if d =~ /\/([\/]*)$/
+ if $install
+ print "installing ", d, "\n"
+ elsif $clean
+ print "cleaning ", d, "\n"
+ else
+ print "compiling ", d, "\n"
+ end
+ extmake(d)
+end
+
+if $cache_mod
+ f = open("config.cache", "w")
+ for k,v in $lib_cache
+ f.printf "lib: %s %s\n", k, v
+ end
+ for k,v in $func_cache
+ f.printf "func: %s %s\n", k, v
+ end
+ for k,v in $hdr_cache
+ f.printf "hdr: %s %s\n", k, v
+ end
+ f.close
+end
+
+exit if $install or $clean
+if $extlist.size > 0
+ #for s,t in $extlist
+ for s,t in $static_ext
+ #f = format("%s/%s.obj", s, t)
+ f = format("%s/%s.obj", s, s)
+ #print format("%s/%s.obj\n", s, s) ##debug print##
+ if File.exist?(f)
+ $extinit += format("\
+\tInit_%s();\n\
+\trb_provide(\"%s.o\");\n\
+", s, s)
+ $extobjs += "ext/"
+ $extobjs += f
+ $extobjs += " "
+ else
+ FALSE
+ end
+ end
+
+ if older("extinit.c", "Setup")
+ f = open("extinit.c", "w")
+ f.printf "void Init_ext() {\n"
+ f.printf $extinit
+ f.printf "}\n"
+ f.close
+ end
+ if older("extinit.obj", "extinit.c")
+ cmd = "cl -Zi -O -I. -c extinit.c"
+ print cmd, "\n"
+ system cmd or exit 1
+ end
+
+ Dir.chdir ".."
+
+ if older("ruby.exe", "ext/Setup") or older("ruby.exe", "miniruby.exe")
+ `rm -f ruby.exe`
+ end
+
+ $extobjs = "ext/extinit.obj " + $extobjs
+ $extlibs = ""
+ system format('nmake ruby.exe EXTOBJS="%s" EXTLIBS="%s"', $extobjs, $extlibs)
+else
+ Dir.chdir ".."
+ if older("ruby.exe", "miniruby.exe")
+ `rm -f ruby.exe`
+ `cp miniruby.exe ruby.exe`
+ end
+end
+
+#Local variables:
+# mode: ruby
+#end:
diff --git a/ext/fcntl/MANIFEST b/ext/fcntl/MANIFEST
new file mode 100644
index 0000000000..aef7ad4ca0
--- /dev/null
+++ b/ext/fcntl/MANIFEST
@@ -0,0 +1,3 @@
+MANIFEST
+depend
+fcntl.c
diff --git a/ext/fcntl/depend b/ext/fcntl/depend
new file mode 100644
index 0000000000..3c7ef8485e
--- /dev/null
+++ b/ext/fcntl/depend
@@ -0,0 +1 @@
+fcntl.o: fcntl.c ../../ruby.h ../../config.h ../../defines.h
diff --git a/ext/fcntl/fcntl.c b/ext/fcntl/fcntl.c
new file mode 100644
index 0000000000..977d5951a8
--- /dev/null
+++ b/ext/fcntl/fcntl.c
@@ -0,0 +1,106 @@
+/************************************************
+
+ fcntl.c -
+
+ $Author: matz $
+ created at: Mon Apr 7 18:53:05 JST 1997
+
+ Copyright (C) 1997 Yukihiro Matsumoto
+
+************************************************/
+
+/************************************************
+= NAME
+
+fcntl - load the C fcntl.h defines
+
+= SYNOPSIS
+
+ require "fcntl"
+ m = s.fcntl(Fcntl::F_GETFL, 0)
+ f.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK|m)
+
+= DESCRIPTION
+
+This module is just a translation of the C <fnctl.h> file.
+
+= NOTE
+
+Only #define symbols get translated; you must still correctly
+pack up your own arguments to pass as args for locking functions, etc.
+
+************************************************/
+
+#include "ruby.h"
+#include <fcntl.h>
+
+Init_fcntl()
+{
+ VALUE mFcntl = rb_define_module("Fcntl");
+#ifdef F_DUPFD
+ rb_define_const(mFcntl, "F_DUPFD", INT2NUM(F_DUPFD));
+#endif
+#ifdef F_GETFD
+ rb_define_const(mFcntl, "F_GETFD", INT2NUM(F_GETFD));
+#endif
+#ifdef F_GETLK
+ rb_define_const(mFcntl, "F_GETLK", INT2NUM(F_GETLK));
+#endif
+#ifdef F_SETFD
+ rb_define_const(mFcntl, "F_SETFD", INT2NUM(F_SETFD));
+#endif
+#ifdef F_GETFL
+ rb_define_const(mFcntl, "F_GETFL", INT2NUM(F_GETFL));
+#endif
+#ifdef F_SETFL
+ rb_define_const(mFcntl, "F_SETFL", INT2NUM(F_SETFL));
+#endif
+#ifdef F_SETLK
+ rb_define_const(mFcntl, "F_SETLK", INT2NUM(F_SETLK));
+#endif
+#ifdef F_SETLKW
+ rb_define_const(mFcntl, "F_SETLKW", INT2NUM(F_SETLKW));
+#endif
+#ifdef FD_CLOEXEC
+ rb_define_const(mFcntl, "FD_CLOEXEC", INT2NUM(FD_CLOEXEC));
+#endif
+#ifdef F_RDLCK
+ rb_define_const(mFcntl, "F_RDLCK", INT2NUM(F_RDLCK));
+#endif
+#ifdef F_UNLCK
+ rb_define_const(mFcntl, "F_UNLCK", INT2NUM(F_UNLCK));
+#endif
+#ifdef F_WRLCK
+ rb_define_const(mFcntl, "F_WRLCK", INT2NUM(F_WRLCK));
+#endif
+#ifdef O_CREAT
+ rb_define_const(mFcntl, "O_CREAT", INT2NUM(O_CREAT));
+#endif
+#ifdef O_EXCL
+ rb_define_const(mFcntl, "O_EXCL", INT2NUM(O_EXCL));
+#endif
+#ifdef O_NOCTTY
+ rb_define_const(mFcntl, "O_NOCTTY", INT2NUM(O_NOCTTY));
+#endif
+#ifdef O_TRUNC
+ rb_define_const(mFcntl, "O_TRUNC", INT2NUM(O_TRUNC));
+#endif
+#ifdef O_APPEND
+ rb_define_const(mFcntl, "O_APPEND", INT2NUM(O_APPEND));
+#endif
+#ifdef O_NONBLOCK
+ rb_define_const(mFcntl, "O_NONBLOCK", INT2NUM(O_NONBLOCK));
+#endif
+#ifdef O_NDELAY
+ rb_define_const(mFcntl, "O_NDELAY", INT2NUM(O_NDELAY));
+#endif
+#ifdef O_RDONLY
+ rb_define_const(mFcntl, "O_RDONLY", INT2NUM(O_RDONLY));
+#endif
+#ifdef O_RDWR
+ rb_define_const(mFcntl, "O_RDWR", INT2NUM(O_RDWR));
+#endif
+#ifdef O_WRONLY
+ rb_define_const(mFcntl, "O_WRONLY", INT2NUM(O_WRONLY));
+#endif
+}
diff --git a/ext/kconv/MANIFEST b/ext/kconv/MANIFEST
index 8f37a9e166..cb89e8239c 100644
--- a/ext/kconv/MANIFEST
+++ b/ext/kconv/MANIFEST
@@ -1,2 +1,3 @@
MANIFEST
+depend
kconv.c
diff --git a/ext/kconv/depend b/ext/kconv/depend
new file mode 100644
index 0000000000..e87b1fdea7
--- /dev/null
+++ b/ext/kconv/depend
@@ -0,0 +1 @@
+kconv.o: kconv.c ../../ruby.h ../../config.h ../../defines.h
diff --git a/ext/kconv/kconv.c b/ext/kconv/kconv.c
index 791b34b26b..3c59cb6acf 100644
--- a/ext/kconv/kconv.c
+++ b/ext/kconv/kconv.c
@@ -82,9 +82,6 @@ static char *Patchlevel =
/* #define DEFAULT_CODE_SJIS */
/* #define DEFAULT_CODE_EUC */
/******************************/
-/* ץȥפ */
-#define ANSI_C_PROTOTYPE
-/******************************/
/* for Kconv: _AUTO, _EUC, _SJIS, _JIS */
#define _AUTO 0
@@ -92,10 +89,6 @@ static char *Patchlevel =
#define _EUC 2
#define _SJIS 3
-#ifdef __STDC__
-#define ANSI_C_PROTOTYPE
-#endif
-
#if (defined(__TURBOC__) || defined(LSI_C)) && !defined(MSDOS)
#define MSDOS
#endif
@@ -202,10 +195,6 @@ static unsigned int mime_input = 0; /* undecoded */
/* flags */
static int unbuf_f = FALSE;
static int estab_f = FALSE;
-#ifdef notdef
-static int nop_f = FALSE;
-static int binmode_f = TRUE; /* binary mode */
-#endif
static int rot_f = FALSE; /* rot14/43 mode */
static int input_f = FALSE; /* non fixed input code */
static int alpha_f = FALSE; /* convert JIx0208 alphbet to ASCII */
@@ -235,7 +224,6 @@ static char kanji_intro = DEFAULT_J,
/* Folding */
-static int fold();
#define FOLD_MARGIN 10
#define DEFAULT_FOLD 60
@@ -345,43 +333,25 @@ static int mime_encode[] = {
0
};
-#ifdef notdef
-static int file_out = FALSE;
-static int end_check;
-#endif
static int add_cr = FALSE;
static int del_cr = FALSE;
-/* function prototype */
-#ifdef ANSI_C_PROTOTYPE
-static void (*iconv) (register int c2,register int c1); /* s_iconv or oconv */
-static void (*oconv) (register int c2,register int c1); /* [ejs]_oconv */
-static int do_kconv(char *i, char *o, int siz, int out_code, int in_code);
-static void h_conv(register int c2,register int c1);
-static int push_hold_buf(int c2,int c1);
-static void s_iconv(register int c2,register int c1);
-static void e_oconv(register int c2,register int c1);
-static void s_oconv(register int c2,register int c1);
-static void j_oconv(register int c2,register int c1);
-static int fold(register int c2,register int c1);
-static int pre_convert(register int c1,register int c2);
-static int mime_begin();
-static int mime_getc();
-static int mime_ungetc(unsigned int c);
-static int mime_integrity(unsigned char *p);
-static int base64decode(int c);
-#else
-static void (*iconv) (); /* s_iconv or oconv */
-static void (*oconv) (); /* [ejs]_oconv */
-static int s_iconv ();
-static int e_oconv ();
-static int j_oconv ();
-static int s_oconv ();
-static int noconvert ();
-static int do_kconv();
-static void h_conv ();
-static int push_hold_buf ();
-#endif
+static void (*iconv) _((register int c2,register int c1)); /* s_iconv or oconv */
+static void (*oconv) _((register int c2,register int c1)); /* [ejs]_oconv */
+static int do_kconv _((char *i, char *o, int siz, int out_code, int in_code));
+static void h_conv _((register int c2,register int c1));
+static int push_hold_buf _((int c2,int c1));
+static void s_iconv _((register int c2,register int c1));
+static void e_oconv _((register int c2,register int c1));
+static void s_oconv _((register int c2,register int c1));
+static void j_oconv _((register int c2,register int c1));
+static int fold _((register int c2,register int c1));
+static int pre_convert _((register int c1,register int c2));
+static int mime_begin _((void));
+static int mime_getc _((void));
+static int mime_ungetc _((unsigned int c));
+static int mime_integrity _((unsigned char *p));
+static int base64decode _((int c));
#ifdef notdef
main (argc, argv)
@@ -414,9 +384,6 @@ main (argc, argv)
case 'u': /* non bufferd mode */
unbuf_f = TRUE;
continue;
- case 't': /* transparent mode */
- nop_f = TRUE;
- continue;
case 'j': /* JIS output */
case 'n':
oconv = j_oconv;
@@ -553,10 +520,7 @@ main (argc, argv)
setbinmode(stdin);
#endif
setvbuffer (stdin, stdibuf, IOBUF_SIZE);
- if(nop_f)
- noconvert (stdin);
- else
- convert (stdin);
+ convert (stdin);
} else {
while (argc--) {
if((fin = fopen (*argv++, "r")) == NULL) {
@@ -594,10 +558,7 @@ main (argc, argv)
setbinmode(fin);
#endif
setvbuffer (fin, stdibuf, IOBUF_SIZE);
- if(nop_f)
- noconvert (fin);
- else
- convert (fin);
+ convert (fin);
fclose (fin);
}
}
@@ -613,18 +574,6 @@ main (argc, argv)
#endif
return (0);
}
-
-int
-noconvert (f)
- register FILE *f;
-{
- register int c;
-
- while ((c = getc (f)) != EOF)
- putchar (c);
- return 1;
-}
-
#endif /* notdef */
static int
diff --git a/ext/marshal/extconf.rb b/ext/marshal/extconf.rb
index 65923049e5..ab30bd117b 100644
--- a/ext/marshal/extconf.rb
+++ b/ext/marshal/extconf.rb
@@ -1,2 +1 @@
-have_func("tmpnam")
create_makefile("marshal")
diff --git a/ext/marshal/marshal.c b/ext/marshal/marshal.c
index eae8d7fe09..47cb0fcd2a 100644
--- a/ext/marshal/marshal.c
+++ b/ext/marshal/marshal.c
@@ -13,131 +13,167 @@
#include "io.h"
#include "st.h"
-#define MARSHAL_MAJOR 2
-#define MARSHAL_MINOR 1
+#define MARSHAL_MAJOR 4
+#define MARSHAL_MINOR 0
#define TYPE_NIL '0'
#define TYPE_TRUE 'T'
#define TYPE_FALSE 'F'
#define TYPE_FIXNUM 'i'
+#define TYPE_UCLASS 'C'
#define TYPE_OBJECT 'o'
#define TYPE_USERDEF 'u'
#define TYPE_FLOAT 'f'
#define TYPE_BIGNUM 'l'
#define TYPE_STRING '"'
-#define TYPE_STRING2 '\''
#define TYPE_REGEXP '/'
#define TYPE_ARRAY '['
-#define TYPE_ARRAY2 ']'
#define TYPE_HASH '{'
-#define TYPE_HASH2 '}'
#define TYPE_STRUCT 'S'
+#define TYPE_MODULE 'M'
#define TYPE_SYMBOL ':'
#define TYPE_SYMLINK ';'
-VALUE cString;
-VALUE cArray;
-VALUE cHash;
+#define TYPE_LINK '@'
+
+extern VALUE cString;
+extern VALUE cRegexp;
+extern VALUE cArray;
+extern VALUE cHash;
-char *rb_class2path();
VALUE rb_path2class();
static ID s_dump, s_load;
-#if (defined(linux) && defined(USE_DLN_A_OUT)) || !defined(HAVE_TMPNAM)
-#define tmpnam(s) ltmpnam(s)
-static char *
-tmpnam(s)
- char *s;
-{
- static int n = 0;
+struct dump_arg {
+ VALUE obj;
+ FILE *fp;
+ struct RString *str;
+ st_table *symbol;
+ st_table *data;
+};
+
+struct dump_call_arg {
+ VALUE obj;
+ struct dump_arg *arg;
+ int limit;
+};
+
+static void w_long _((long, struct dump_arg*));
- sprintf(s, "/tmp/rb-mrsr-%x%x", getpid(), n++);
- return s;
+static void
+w_byte(c, arg)
+ char c;
+ struct dump_arg *arg;
+{
+ if (arg->fp) putc(c, arg->fp);
+ else str_cat(arg->str, &c, 1);
}
-#endif
-#define w_byte(c, fp) putc((c), fp)
-#define w_bytes(s, n, fp) (w_long((n), fp),fwrite(s, 1, n, fp))
+static void
+w_bytes(s, n, arg)
+ char *s;
+ int n;
+ struct dump_arg *arg;
+{
+ w_long(n, arg);
+ if (arg->fp) {
+ fwrite(s, 1, n, arg->fp);
+ }
+ else {
+ str_cat(arg->str, s, n);
+ }
+}
static void
-w_short(x, fp)
+w_short(x, arg)
int x;
- FILE *fp;
+ struct dump_arg *arg;
{
- w_byte( x & 0xff, fp);
- w_byte((x>> 8) & 0xff, fp);
+ w_byte( x & 0xff, arg);
+ w_byte((x>> 8) & 0xff, arg);
}
static void
-w_long(x, fp)
+w_long(x, arg)
long x;
- FILE *fp;
+ struct dump_arg *arg;
{
- w_byte((int)( x & 0xff), fp);
- w_byte((int)((x>> 8) & 0xff), fp);
- w_byte((int)((x>>16) & 0xff), fp);
- w_byte((int)((x>>24) & 0xff), fp);
+ char buf[sizeof(long)+1];
+ int i, len = 0;
+
+ if (x == 0) {
+ w_byte(0, arg);
+ return;
+ }
+ for (i=1;i<sizeof(long)+1;i++) {
+ buf[i] = x & 0xff;
+ x = RSHIFT(x,8);
+ if (x == 0) {
+ buf[0] = i;
+ break;
+ }
+ if (x == -1) {
+ buf[0] = -i;
+ break;
+ }
+ }
+ len = i;
+ for (i=0;i<=len;i++) {
+ w_byte(buf[i], arg);
+ }
}
static void
-w_float(d, fp)
+w_float(d, arg)
double d;
- FILE *fp;
+ struct dump_arg *arg;
{
char buf[100];
sprintf(buf, "%.12g", d);
- w_bytes(buf, strlen(buf), fp);
+ w_bytes(buf, strlen(buf), arg);
}
static void
-w_symbol(id, fp, table)
+w_symbol(id, arg)
ID id;
- FILE *fp;
- st_table *table;
+ struct dump_arg *arg;
{
char *sym = rb_id2name(id);
int num;
- if (st_lookup(table, id, &num)) {
- w_byte(TYPE_SYMLINK, fp);
- w_long(num, fp);
+ if (st_lookup(arg->symbol, id, &num)) {
+ w_byte(TYPE_SYMLINK, arg);
+ w_long(num, arg);
}
else {
- w_byte(TYPE_SYMBOL, fp);
- w_bytes(sym, strlen(sym), fp);
- st_insert(table, id, table->num_entries);
+ w_byte(TYPE_SYMBOL, arg);
+ w_bytes(sym, strlen(sym), arg);
+ st_insert(arg->symbol, id, arg->symbol->num_entries);
}
}
static void
-w_unique(s, fp, table)
+w_unique(s, arg)
char *s;
- FILE *fp;
- st_table *table;
+ struct dump_arg *arg;
{
- w_symbol(rb_intern(s), fp, table);
+ w_symbol(rb_intern(s), arg);
}
-static void w_object();
-extern VALUE cBignum, cStruct;
-
-struct each_arg {
- FILE *fp;
- VALUE limit;
- st_table *table;
-};
+static void w_object _((VALUE,struct dump_arg*,int));
+extern VALUE cIO, cBignum, cStruct;
static int
hash_each(key, value, arg)
VALUE key, value;
- struct each_arg *arg;
+ struct dump_call_arg *arg;
{
- w_object(key, arg->fp, arg->limit, arg->table);
- w_object(value, arg->fp, arg->limit, arg->table);
+ w_object(key, arg->arg, arg->limit);
+ w_object(value, arg->arg, arg->limit);
return ST_CONTINUE;
}
@@ -145,154 +181,166 @@ static int
obj_each(id, value, arg)
ID id;
VALUE value;
- struct each_arg *arg;
+ struct dump_call_arg *arg;
{
- w_symbol(id, arg->fp, arg->table);
- w_object(value, arg->fp, arg->limit, arg->table);
+ w_symbol(id, arg->arg);
+ w_object(value, arg->arg, arg->limit);
return ST_CONTINUE;
}
static void
-w_object(obj, fp, limit, table)
+w_uclass(obj, class, arg)
+ VALUE obj, class;
+ struct dump_arg *arg;
+{
+ if (CLASS_OF(obj) != class) {
+ w_byte(TYPE_UCLASS, arg);
+ w_unique(rb_class2name(CLASS_OF(obj)), arg);
+ }
+}
+
+static void
+w_object(obj, arg, limit)
VALUE obj;
- FILE *fp;
+ struct dump_arg *arg;
int limit;
- st_table *table;
{
- struct each_arg arg;
int n;
+ struct dump_call_arg c_arg;
if (limit == 0) {
Fail("exceed depth limit");
}
limit--;
-
- arg.fp = fp;
- arg.limit = limit;
- arg.table = table;
+ c_arg.limit = limit;
+ c_arg.arg = arg;
if (obj == Qnil) {
- w_byte(TYPE_NIL, fp);
+ w_byte(TYPE_NIL, arg);
}
else if (obj == TRUE) {
- w_byte(TYPE_TRUE, fp);
+ w_byte(TYPE_TRUE, arg);
}
else if (obj == FALSE) {
- w_byte(TYPE_FALSE, fp);
+ w_byte(TYPE_FALSE, arg);
}
else if (FIXNUM_P(obj)) {
if (sizeof(long) == 4) {
- w_byte(TYPE_FIXNUM, fp);
- w_long(FIX2INT(obj), fp);
+ w_byte(TYPE_FIXNUM, arg);
+ w_long(FIX2INT(obj), arg);
}
}
else {
+ int num;
+
+ if (st_lookup(arg->data, obj, &num)) {
+ w_byte(TYPE_LINK, arg);
+ w_long(num, arg);
+ return;
+ }
+ st_insert(arg->data, obj, arg->data->num_entries);
if (rb_respond_to(obj, s_dump)) {
VALUE v;
- w_byte(TYPE_USERDEF, fp);
- w_unique(rb_class2path(CLASS_OF(obj)), fp, table);
+ w_byte(TYPE_USERDEF, arg);
+ w_unique(rb_class2name(CLASS_OF(obj)), arg);
v = rb_funcall(obj, s_dump, 1, limit);
if (TYPE(v) != T_STRING) {
TypeError("_dump_to must return String");
}
- w_bytes(RSTRING(v)->ptr, RSTRING(v)->len, fp);
+ w_bytes(RSTRING(v)->ptr, RSTRING(v)->len, arg);
return;
}
+
switch (BUILTIN_TYPE(obj)) {
+ case T_MODULE:
+ case T_CLASS:
+ w_byte(TYPE_MODULE, arg);
+ {
+ VALUE path = rb_class_path(obj);
+ w_bytes(RSTRING(path)->ptr, RSTRING(path)->len, arg);
+ }
+ return;
+
case T_FLOAT:
- w_byte(TYPE_FLOAT, fp);
- w_float(RFLOAT(obj)->value, fp);
+ w_byte(TYPE_FLOAT, arg);
+ w_float(RFLOAT(obj)->value, arg);
return;
case T_BIGNUM:
- w_byte(TYPE_BIGNUM, fp);
+ w_byte(TYPE_BIGNUM, arg);
{
char sign = RBIGNUM(obj)->sign?'+':'-';
int len = RBIGNUM(obj)->len;
USHORT *d = RBIGNUM(obj)->digits;
- w_byte(sign, fp);
- w_long(len, fp);
+ w_byte(sign, arg);
+ w_long(len, arg);
while (len--) {
- w_short(d, fp);
+ w_short(*d, arg);
d++;
}
}
return;
- }
- switch (BUILTIN_TYPE(obj)) {
case T_STRING:
- if (CLASS_OF(obj) == cString) {
- w_byte(TYPE_STRING, fp);
- w_bytes(RSTRING(obj)->ptr, RSTRING(obj)->len, fp);
- }
- else {
- w_byte(TYPE_STRING2, fp);
- w_bytes(RSTRING(obj)->ptr, RSTRING(obj)->len, fp);
- w_unique(rb_class2path(CLASS_OF(obj)), fp, table);
- }
+ w_uclass(obj, cString, arg);
+ w_byte(TYPE_STRING, arg);
+ w_bytes(RSTRING(obj)->ptr, RSTRING(obj)->len, arg);
return;
case T_REGEXP:
- w_byte(TYPE_REGEXP, fp);
- w_bytes(RREGEXP(obj)->str, RREGEXP(obj)->len, fp);
- w_byte(FL_TEST(obj, FL_USER1), fp);
+ w_uclass(obj, cRegexp, arg);
+ w_byte(TYPE_REGEXP, arg);
+ w_bytes(RREGEXP(obj)->str, RREGEXP(obj)->len, arg);
+ w_byte(FL_TEST(obj, FL_USER1), arg);
return;
case T_ARRAY:
- if (CLASS_OF(obj) == cArray) w_byte(TYPE_ARRAY, fp);
- else w_byte(TYPE_ARRAY2, fp);
+ w_uclass(obj, cArray, arg);
+ w_byte(TYPE_ARRAY, arg);
{
int len = RARRAY(obj)->len;
VALUE *ptr = RARRAY(obj)->ptr;
- w_long(len, fp);
+ w_long(len, arg);
while (len--) {
- w_object(*ptr, fp, limit, table);
+ w_object(*ptr, arg, limit);
ptr++;
}
}
- if (CLASS_OF(obj) != cArray) {
- w_unique(rb_class2path(CLASS_OF(obj)), fp, table);
- }
break;
case T_HASH:
- if (CLASS_OF(obj) == cHash) w_byte(TYPE_HASH, fp);
- else w_byte(TYPE_HASH2, fp);
- w_byte(TYPE_HASH, fp);
- w_long(RHASH(obj)->tbl->num_entries, fp);
- st_foreach(RHASH(obj)->tbl, hash_each, &arg);
- if (CLASS_OF(obj) != cHash) {
- w_unique(rb_class2path(CLASS_OF(obj)), fp, table);
- }
+ w_uclass(obj, cHash, arg);
+ w_byte(TYPE_HASH, arg);
+ w_long(RHASH(obj)->tbl->num_entries, arg);
+ st_foreach(RHASH(obj)->tbl, hash_each, &c_arg);
break;
case T_STRUCT:
- w_byte(TYPE_STRUCT, fp);
+ w_byte(TYPE_STRUCT, arg);
{
int len = RSTRUCT(obj)->len;
- char *path = rb_class2path(CLASS_OF(obj));
+ char *path = rb_class2name(CLASS_OF(obj));
VALUE mem;
int i;
- w_unique(path, fp, table);
- w_long(len, fp);
+ w_unique(path, arg);
+ w_long(len, arg);
mem = rb_ivar_get(CLASS_OF(obj), rb_intern("__member__"));
if (mem == Qnil) {
Fatal("non-initialized struct");
}
for (i=0; i<len; i++) {
- w_symbol(FIX2INT(RARRAY(mem)->ptr[i]), fp, table);
- w_object(RSTRUCT(obj)->ptr[i], fp, limit, table);
+ w_symbol(FIX2INT(RARRAY(mem)->ptr[i]), arg);
+ w_object(RSTRUCT(obj)->ptr[i], arg, limit);
}
}
break;
case T_OBJECT:
- w_byte(TYPE_OBJECT, fp);
+ w_byte(TYPE_OBJECT, arg);
{
VALUE class = CLASS_OF(obj);
char *path;
@@ -300,14 +348,14 @@ w_object(obj, fp, limit, table)
if (FL_TEST(class, FL_SINGLETON)) {
TypeError("singleton can't be dumped");
}
- path = rb_class2path(class);
- w_unique(path, fp, table);
+ path = rb_class2name(class);
+ w_unique(path, arg);
if (ROBJECT(obj)->iv_tbl) {
- w_long(ROBJECT(obj)->iv_tbl->num_entries, fp);
- st_foreach(ROBJECT(obj)->iv_tbl, obj_each, &arg);
+ w_long(ROBJECT(obj)->iv_tbl->num_entries, arg);
+ st_foreach(ROBJECT(obj)->iv_tbl, obj_each, &c_arg);
}
else {
- w_long(0, fp);
+ w_long(0, arg);
}
}
break;
@@ -319,146 +367,157 @@ w_object(obj, fp, limit, table)
}
}
-struct dump_arg {
- VALUE obj;
- FILE *fp;
- int limit;
- st_table *table;
-};
-
static VALUE
dump(arg)
- struct dump_arg *arg;
+ struct dump_call_arg *arg;
{
- w_object(arg->obj, arg->fp, arg->limit, arg->table);
+ w_object(arg->obj, arg->arg, arg->limit);
}
static VALUE
dump_ensure(arg)
struct dump_arg *arg;
{
- st_free_table(arg->table);
+ st_free_table(arg->symbol);
+ st_free_table(arg->data);
}
static VALUE
-dump_on(obj, port, limit)
- VALUE obj, port;
- int limit;
+marshal_dump(argc, argv)
+ int argc;
+ VALUE argv;
{
+ VALUE obj, port, a1, a2;
+ int limit = -1;
extern VALUE cIO;
- FILE *fp;
- OpenFile *fptr;
struct dump_arg arg;
+ struct dump_call_arg c_arg;
- if (obj_is_kind_of(port, cIO)) {
- GetOpenFile(port, fptr);
- io_writable(fptr);
- fp = (fptr->f2) ? fptr->f2 : fptr->f;
+ port = 0;
+ rb_scan_args(argc, argv, "12", &obj, &a1, &a2);
+ if (argc == 3) {
+ limit = NUM2INT(a2);
+ port = a1;
+ }
+ else if (argc == 2) {
+ if (FIXNUM_P(a1)) limit = FIX2INT(a1);
+ else port = a1;
+ }
+ if (port) {
+ if (obj_is_kind_of(port, cIO)) {
+ OpenFile *fptr;
+
+ io_binmode(port);
+ GetOpenFile(port, fptr);
+ io_writable(fptr);
+ arg.fp = (fptr->f2) ? fptr->f2 : fptr->f;
+ }
+ else {
+ TypeError("instance of IO needed");
+ }
}
else {
- TypeError("instance of IO needed");
+ arg.fp = 0;
+ port = str_new(0, 0);
+ arg.str = RSTRING(port);
}
- w_byte(MARSHAL_MAJOR, fp);
- w_byte(MARSHAL_MINOR, fp);
-
- arg.obj = obj;
- arg.fp = fp;
- arg.limit = limit;
- arg.table = st_init_numtable();
- rb_ensure(dump, &arg, dump_ensure, &arg);
-
- return Qnil;
-}
+ arg.symbol = st_init_numtable();
+ arg.data = st_init_numtable();
+ c_arg.obj = obj;
+ c_arg.arg = &arg;
+ c_arg.limit = limit;
-static VALUE
-marshal_dump(argc, argv)
- int argc;
- VALUE argv;
-{
- VALUE obj, port, lim;
- int limit;
+ w_byte(MARSHAL_MAJOR, &arg);
+ w_byte(MARSHAL_MINOR, &arg);
- rb_scan_args(argc, argv, "21", &obj, &port, &lim);
- if (NIL_P(lim)) limit = 100;
- else limit = NUM2INT(lim);
+ rb_ensure(dump, &c_arg, dump_ensure, &arg);
- dump_on(obj, port, limit);
+ return port;
}
-static VALUE
-marshal_dumps(argc, argv)
- int argc;
- VALUE argv;
-{
- VALUE obj, lim;
- int limit;
- VALUE str = str_new(0, 0);
- VALUE port;
- FILE *fp = 0;
- char buf[BUFSIZ];
- int n;
-
- rb_scan_args(argc, argv, "11", &obj, &lim);
- if (NIL_P(lim)) limit = 100;
- else limit = NUM2INT(lim);
-
- tmpnam(buf);
- port = file_open(buf, "w");
- fp = rb_fopen(buf, "r");
-#if !defined(MSDOS) && !defined(__BOW__)
- unlink(buf);
-#endif
-
- dump_on(obj, port, limit);
- io_close(port);
-#if defined(MSDOS) || defined(__BOW__)
- unlink(buf);
-#endif
-
- while (n = fread(buf, 1, BUFSIZ, fp)) {
- str_cat(str, buf, n);
- }
+struct load_arg {
+ FILE *fp;
+ UCHAR *ptr, *end;
+ st_table *symbol;
+ st_table *data;
+};
- return str;
+static int
+r_byte(arg)
+ struct load_arg *arg;
+{
+ if (arg->fp) return getc(arg->fp);
+ if (arg->ptr < arg->end) return *arg->ptr++;
+ return EOF;
}
-#define r_byte(fp) getc(fp)
-
static int
-r_short(fp)
- FILE *fp;
+r_short(arg)
+ struct load_arg *arg;
{
register short x;
- x = r_byte(fp);
- x |= r_byte(fp) << 8;
+ x = r_byte(arg);
+ x |= r_byte(arg) << 8;
/* XXX If your short is > 16 bits, add sign-extension here!!! */
return x;
}
+static void
+long_toobig(size)
+ int size;
+{
+ TypeError("long too big for this architecture (size %d, given %d)",
+ sizeof(long), size);
+}
+
static long
-r_long(fp)
- FILE *fp;
+r_long(arg)
+ struct load_arg *arg;
{
+ char c = r_byte(arg), i;
register long x;
- x = r_byte(fp);
- x |= (long)r_byte(fp) << 8;
- x |= (long)r_byte(fp) << 16;
- x |= (long)r_byte(fp) << 24;
- /* XXX If your long is > 32 bits, add sign-extension here!!! */
+
+ if (c == 0) return 0;
+ if (c > 0) {
+ if (c > sizeof(long)) long_toobig((int)c);
+ x = 0;
+ for (i=0;i<c;i++) {
+ x |= (long)r_byte(arg) << (8*i);
+ }
+ }
+ else if (c < 0) {
+ c = -c;
+ if (c > sizeof(long)) long_toobig((int)c);
+ x = -1;
+ for (i=0;i<c;i++) {
+ x &= ~(0xff << (8*i));
+ x |= (long)r_byte(arg) << (8*i);
+ }
+ }
return x;
}
-#define r_bytes(s, fp) \
- (s = (char*)r_long(fp), r_bytes0(&s,ALLOCA_N(char,(int)s),(int)s,fp))
+#define r_bytes(s, arg) \
+ (s = (char*)r_long(arg), r_bytes0(&s,ALLOCA_N(char,(int)s),(int)s,arg))
-static char
-r_bytes0(sp, s, len, fp)
+static int
+r_bytes0(sp, s, len, arg)
char **sp, *s;
int len;
- FILE *fp;
+ struct load_arg *arg;
{
- fread(s, 1, len, fp);
+ if (arg->fp) {
+ len = fread(s, 1, len, arg->fp);
+ }
+ else {
+ if (arg->ptr + len > arg->end) {
+ len = arg->end - arg->ptr;
+ }
+ memcpy(s, arg->ptr, len);
+ arg->ptr += len;
+ }
+
(s)[len] = '\0';
*sp = s;
@@ -466,63 +525,84 @@ r_bytes0(sp, s, len, fp)
}
static ID
-r_symbol(fp, table)
- FILE *fp;
- st_table *table;
+r_symbol(arg)
+ struct load_arg *arg;
{
char *buf;
ID id;
char type;
- if (r_byte(fp) == TYPE_SYMLINK) {
- int num = r_long(fp);
+ if (r_byte(arg) == TYPE_SYMLINK) {
+ int num = r_long(arg);
- if (st_lookup(table, num, &id)) {
+ if (st_lookup(arg->symbol, num, &id)) {
return id;
}
TypeError("bad symbol");
}
- r_bytes(buf, fp);
+ r_bytes(buf, arg);
id = rb_intern(buf);
- st_insert(table, table->num_entries, id);
+ st_insert(arg->symbol, arg->symbol->num_entries, id);
return id;
}
static char*
-r_unique(fp, table)
- FILE *fp;
- st_table *table;
+r_unique(arg)
+ struct load_arg *arg;
{
- return rb_id2name(r_symbol(fp, table));
+ return rb_id2name(r_symbol(arg));
}
static VALUE
-r_string(fp)
- FILE *fp;
+r_string(arg)
+ struct load_arg *arg;
{
char *buf;
- int len = r_bytes(buf, fp);
- VALUE v;
+ int len = r_bytes(buf, arg);
- v = str_new(buf, len);
+ return str_taint(str_new(buf, len));
+}
+static VALUE
+r_regist(v, arg)
+ VALUE v;
+ struct load_arg *arg;
+{
+ st_insert(arg->data, arg->data->num_entries, v);
return v;
}
static VALUE
-r_object(fp, table)
- FILE *fp;
- st_table *table;
+r_object(arg)
+ struct load_arg *arg;
{
VALUE v;
- int type = r_byte(fp);
+ int type = r_byte(arg);
switch (type) {
case EOF:
eof_error("EOF read where object expected");
return Qnil;
+ case TYPE_LINK:
+ if (st_lookup(arg->data, r_long(arg), &v)) {
+ return v;
+ }
+ ArgError("dump format error (unlinked)");
+ break;
+
+ case TYPE_UCLASS:
+ {
+ VALUE c = rb_path2class(r_unique(arg));
+ v = r_object(arg);
+ if (rb_special_const_p(v)) {
+ ArgError("dump format error (user class)");
+ }
+ RBASIC(v)->class = c;
+ return v;
+ }
+
case TYPE_NIL:
return Qnil;
@@ -534,7 +614,7 @@ r_object(fp, table)
case TYPE_FIXNUM:
{
- int i = r_long(fp);
+ int i = r_long(arg);
return INT2FIX(i);
}
@@ -543,9 +623,9 @@ r_object(fp, table)
double atof();
char *buf;
- r_bytes(buf, fp);
+ r_bytes(buf, arg);
v = float_new(atof(buf));
- return v;
+ return r_regist(v, arg);
}
case TYPE_BIGNUM:
@@ -555,50 +635,46 @@ r_object(fp, table)
NEWOBJ(big, struct RBignum);
OBJSETUP(big, cBignum, T_BIGNUM);
- big->sign = (r_byte(fp) == '+');
- big->len = len = r_long(fp);
+ big->sign = (r_byte(arg) == '+');
+ big->len = len = r_long(arg);
big->digits = digits = ALLOC_N(USHORT, len);
while (len--) {
- *digits++ = r_short(fp);
+ *digits++ = r_short(arg);
}
- return (VALUE)big;
+ return r_regist(big, arg);
}
case TYPE_STRING:
- return r_string(fp);
-
- case TYPE_STRING2:
- v = r_string(fp);
- RBASIC(v)->class = rb_path2class(r_unique(fp, table));
- return v;
+ return r_regist(r_string(arg), arg);
case TYPE_REGEXP:
{
char *buf;
- int len = r_bytes(buf, fp);
- int ci = r_byte(fp);
- v = reg_new(buf, len, ci);
- return v;
+ int len = r_bytes(buf, arg);
+ int ci = r_byte(arg);
+ return r_regist(reg_new(buf, len, ci), arg);
}
case TYPE_ARRAY:
{
- int len = r_long(fp);
+ volatile int len = r_long(arg);
v = ary_new2(len);
+ r_regist(v, arg);
while (len--) {
- ary_push(v, r_object(fp, table));
+ ary_push(v, r_object(arg));
}
return v;
}
case TYPE_HASH:
{
- int len = r_long(fp);
+ int len = r_long(arg);
v = hash_new();
+ r_regist(v, arg);
while (len--) {
- VALUE key = r_object(fp, table);
- VALUE value = r_object(fp, table);
+ VALUE key = r_object(arg);
+ VALUE value = r_object(arg);
hash_aset(v, key, value);
}
return v;
@@ -608,23 +684,27 @@ r_object(fp, table)
{
VALUE class, mem, values;
int i, len;
+ int num = arg->data->num_entries;
- class = rb_path2class(r_unique(fp, table));
+ st_insert(arg->data, num, 15); /* temp reg. */
+ class = rb_path2class(r_unique(arg));
mem = rb_ivar_get(class, rb_intern("__member__"));
if (mem == Qnil) {
Fatal("non-initialized struct");
}
- len = r_long(fp);
+ len = r_long(arg);
values = ary_new2(len);
i = 0;
for (i=0; i<len; i++) {
- ID slot = r_symbol(fp, table);
+ ID slot = r_symbol(arg);
if (RARRAY(mem)->ptr[i] != INT2FIX(slot))
TypeError("struct not compatible");
- ary_push(values, r_object(fp, table));
+ ary_push(values, r_object(arg));
}
v = struct_alloc(class, values);
+ st_insert(arg->data, num, v); /* re-regist */
+ return v;
}
break;
@@ -633,112 +713,101 @@ r_object(fp, table)
VALUE class;
int len;
- class = rb_path2class(r_unique(fp, table));
+ class = rb_path2class(r_unique(arg));
if (rb_respond_to(class, s_load)) {
- v = rb_funcall(class, s_load, 1, r_string(fp));
- }
- else {
- TypeError("class %s needs to have method `_load_from'",
- rb_class2name(class));
+ v = rb_funcall(class, s_load, 1, r_string(arg));
+ return r_regist(v, arg);
}
+ TypeError("class %s needs to have method `_load_from'",
+ rb_class2name(class));
}
break;
+
case TYPE_OBJECT:
{
VALUE class;
int len;
- class = rb_path2class(r_unique(fp, table));
- len = r_long(fp);
+ class = rb_path2class(r_unique(arg));
+ len = r_long(arg);
v = obj_alloc(class);
+ r_regist(v, arg);
if (len > 0) {
while (len--) {
- ID id = r_symbol(fp, table);
- VALUE val = r_object(fp, table);
+ ID id = r_symbol(arg);
+ VALUE val = r_object(arg);
rb_ivar_set(v, id, val);
}
}
+ return v;
}
break;
+ case TYPE_MODULE:
+ {
+ char *buf;
+ r_bytes(buf, arg);
+ return rb_path2class(buf);
+ }
+
default:
ArgError("dump format error(0x%x)", type);
break;
}
- return v;
}
-struct load_arg {
- FILE *fp;
- st_table *table;
-};
-
static VALUE
load(arg)
struct load_arg *arg;
{
- return r_object(arg->fp, arg->table);
+ return r_object(arg);
}
static VALUE
load_ensure(arg)
struct load_arg *arg;
{
- st_free_table(arg->table);
+ st_free_table(arg->symbol);
+ st_free_table(arg->data);
}
static VALUE
marshal_load(self, port)
VALUE self, port;
{
- extern VALUE cIO;
FILE *fp;
int major;
VALUE v;
OpenFile *fptr;
- char buf[32];
-#if defined(MSDOS) || defined(__BOW__)
- int need_unlink_tmp = 0;
-#endif
struct load_arg arg;
if (TYPE(port) == T_STRING) {
- tmpnam(buf);
- fp = rb_fopen(buf, "w");
- v = file_open(buf, "r");
-#if defined(MSDOS) || defined(__BOW__)
- need_unlink_tmp = 0;
-#else
- unlink(buf);
-#endif
-
- fwrite(RSTRING(port)->ptr, RSTRING(port)->len, 1, fp);
- fclose(fp);
- port = v;
- }
-
- if (obj_is_kind_of(port, cIO)) {
- GetOpenFile(port, fptr);
- io_readable(fptr);
- fp = fptr->f;
+ arg.fp = 0;
+ arg.ptr = RSTRING(port)->ptr;
+ arg.end = arg.ptr + RSTRING(port)->len;
}
else {
- TypeError("instance of IO needed");
+ if (obj_is_kind_of(port, cIO)) {
+ io_binmode(port);
+ GetOpenFile(port, fptr);
+ io_readable(fptr);
+ arg.fp = fptr->f;
+ }
+ else {
+ TypeError("instance of IO needed");
+ }
}
- major = r_byte(fp);
+ major = r_byte(&arg);
if (major == MARSHAL_MAJOR) {
- if (r_byte(fp) != MARSHAL_MINOR) {
+ if (r_byte(&arg) != MARSHAL_MINOR) {
Warning("Old marshal file format (can be read)");
}
- arg.fp = fp;
- arg.table = st_init_numtable();
+ arg.symbol = st_init_numtable();
+ arg.data = st_init_numtable();
v = rb_ensure(load, &arg, load_ensure, &arg);
}
-#if defined(MSDOS) || defined(__BOW__)
- if (need_unlink_tmp) unlink(buf);
-#endif
- if (major != MARSHAL_MAJOR) {
+ else {
TypeError("Old marshal file format (can't read)");
}
@@ -752,7 +821,6 @@ Init_marshal()
s_dump = rb_intern("_dump_to");
s_load = rb_intern("_load_from");
rb_define_module_function(mMarshal, "dump", marshal_dump, -1);
- rb_define_module_function(mMarshal, "dumps", marshal_dumps, -1);
rb_define_module_function(mMarshal, "load", marshal_load, 1);
rb_define_module_function(mMarshal, "restore", marshal_load, 1);
}
diff --git a/ext/md5/md5init.c b/ext/md5/md5init.c
index 85f0847e71..762d53edc9 100644
--- a/ext/md5/md5init.c
+++ b/ext/md5/md5init.c
@@ -26,7 +26,7 @@ md5_update(obj, str)
MD5_CTX *md5;
Check_Type(str, T_STRING);
- Get_Data_Struct(obj, MD5_CTX, md5);
+ Data_Get_Struct(obj, MD5_CTX, md5);
MD5Update(md5, str->ptr, str->len);
return Qnil;
@@ -38,7 +38,7 @@ md5_digest(obj)
MD5_CTX *md5, ctx;
unsigned char digest[16];
- Get_Data_Struct(obj, MD5_CTX, md5);
+ Data_Get_Struct(obj, MD5_CTX, md5);
ctx = *md5;
MD5Final(digest, &ctx);
@@ -52,8 +52,8 @@ md5_clone(obj)
VALUE clone;
MD5_CTX *md5, *md5_new;
- Get_Data_Struct(obj, MD5_CTX, md5);
- obj = Make_Data_Struct(CLASS_OF(obj), MD5_CTX, 0, 0, md5_new);
+ Data_Get_Struct(obj, MD5_CTX, md5);
+ obj = Data_Make_Struct(CLASS_OF(obj), MD5_CTX, 0, 0, md5_new);
*md5_new = *md5;
return obj;
@@ -69,7 +69,7 @@ md5_new(argc, argv, class)
rb_scan_args(argc, argv, "01", &arg);
if (!NIL_P(arg)) Check_Type(arg, T_STRING);
- obj = Make_Data_Struct(class, MD5_CTX, 0, 0, md5);
+ obj = Data_Make_Struct(class, MD5_CTX, 0, 0, md5);
MD5Init(md5);
if (!NIL_P(arg)) {
md5_update(obj, arg);
diff --git a/ext/socket/extconf.rb b/ext/socket/extconf.rb
index f2ec0578d5..bbde1a0c35 100644
--- a/ext/socket/extconf.rb
+++ b/ext/socket/extconf.rb
@@ -1,11 +1,17 @@
-have_library("socket", "socket")
+$LDFLAGS = "-L/usr/local/lib"
+have_library("wsock32", "cygwin32_socket") or have_library("socket", "socket")
have_library("inet", "gethostbyname")
have_library("nsl", "gethostbyname")
have_header("sys/un.h")
-if have_func("socket")
+if have_func("socket") or have_func("cygwin32_socket")
have_func("hsterror")
unless have_func("gethostname")
have_func("uname")
end
+ if ENV["SOCKS_SERVER"] # test if SOCKSsocket needed
+ if have_library("socks", "Rconnect")
+ $CFLAGS="-DSOCKS"
+ end
+ end
create_makefile("socket")
end
diff --git a/ext/socket/socket.c b/ext/socket/socket.c
index 6b4f0f5559..be9118d0a8 100644
--- a/ext/socket/socket.c
+++ b/ext/socket/socket.c
@@ -20,6 +20,18 @@
#include <sys/un.h>
#endif
+#if defined(THREAD) && defined(HAVE_FCNTL)
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#include <sys/types.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#endif
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK EAGAIN
+#endif
+
extern VALUE cIO;
extern VALUE cInteger;
@@ -35,9 +47,19 @@ VALUE cSocket;
extern VALUE eException;
static VALUE eSocket;
+#ifdef SOCKS
+VALUE cSOCKSsocket;
+void SOCKSinit();
+int Rconnect();
+#endif
+
FILE *rb_fdopen();
char *strdup();
+#define INET_CLIENT 0
+#define INET_SERVER 1
+#define INET_SOCKS 2
+
#ifdef NT
static void
sock_finalize(fptr)
@@ -60,13 +82,15 @@ sock_new(class, fd)
OBJSETUP(sock, class, T_FILE);
MakeOpenFile(sock, fp);
+ fp->f = rb_fdopen(fd, "r");
#ifdef NT
fp->finalize = sock_finalize;
-#endif
- fp->f = rb_fdopen(fd, "r");
+#else
setbuf(fp->f, NULL);
+#endif
fp->f2 = rb_fdopen(fd, "w");
- fp->mode = FMODE_READWRITE|FMODE_SYNC;
+ fp->mode = FMODE_READWRITE;
+ io_unbuffered(fp);
return (VALUE)sock;
}
@@ -106,6 +130,7 @@ bsock_setsockopt(sock, lev, optname, val)
char *v;
int vlen;
+ rb_secure(2);
level = NUM2INT(lev);
option = NUM2INT(optname);
switch (TYPE(val)) {
@@ -136,26 +161,20 @@ static VALUE
bsock_getsockopt(sock, lev, optname)
VALUE sock, lev, optname;
{
-#if !defined(__CYGWIN32__)
int level, option, len;
- struct RString *val;
+ char *buf;
OpenFile *fptr;
level = NUM2INT(lev);
option = NUM2INT(optname);
len = 256;
- val = (struct RString*)str_new(0, len);
- Check_Type(val, T_STRING);
+ buf = ALLOCA_N(char,len);
GetOpenFile(sock, fptr);
- if (getsockopt(fileno(fptr->f), level, option, val->ptr, &len) < 0)
+ if (getsockopt(fileno(fptr->f), level, option, buf, &len) < 0)
rb_sys_fail(fptr->path);
- val->len = len;
- return (VALUE)val;
-#else
- rb_notimplement();
-#endif
+ return str_new(buf, len);
}
static VALUE
@@ -187,9 +206,210 @@ bsock_getpeername(sock)
}
static VALUE
-open_inet(class, h, serv, server)
+bsock_send(argc, argv, sock)
+ int argc;
+ VALUE *argv;
+ VALUE sock;
+{
+ struct RString *msg, *to;
+ VALUE flags;
+ OpenFile *fptr;
+ FILE *f;
+ int fd, n;
+
+ rb_secure(4);
+ rb_scan_args(argc, argv, "21", &msg, &flags, &to);
+
+ Check_Type(msg, T_STRING);
+
+ GetOpenFile(sock, fptr);
+ f = fptr->f2?fptr->f2:fptr->f;
+ fd = fileno(f);
+ retry:
+#ifdef THREAD
+ thread_fd_writable(fd);
+#endif
+ if (RTEST(to)) {
+ Check_Type(to, T_STRING);
+ n = sendto(fd, msg->ptr, msg->len, NUM2INT(flags),
+ (struct sockaddr*)to->ptr, to->len);
+ }
+ else {
+ n = send(fd, msg->ptr, msg->len, NUM2INT(flags));
+ }
+ if (n < 0) {
+ switch (errno) {
+ case EINTR:
+ case EWOULDBLOCK:
+#if EAGAIN != EWOULDBLOCK
+ case EAGAIN:
+#endif
+#ifdef THREAD
+ thread_schedule();
+#endif
+ goto retry;
+ }
+ rb_sys_fail("send(2)");
+ }
+ return INT2FIX(n);
+}
+
+static VALUE tcpaddr _((struct sockaddr_in*));
+#ifdef HAVE_SYS_UN_H
+static VALUE unixaddr _((struct sockaddr_un*));
+#endif
+
+static VALUE
+s_recv(sock, argc, argv, from)
+ VALUE sock;
+ int argc;
+ VALUE *argv;
+ int from; /* 0 - recv,
+ 1 - TCPsocket#recvfrom,
+ 2 - UNIXsocket#recvfrom,
+ 3 - Socket#recvfrom */
+{
+ OpenFile *fptr;
+ FILE f;
+ struct RString *str;
+ char buf[1024];
+ int fd, alen = sizeof buf;
+ VALUE len, flg;
+ int flags;
+
+ rb_scan_args(argc, argv, "11", &len, &flg);
+
+ if (flg == Qnil) flags = 0;
+ else flags = NUM2INT(flg);
+
+ str = (struct RString*)str_new(0, NUM2INT(len));
+
+ GetOpenFile(sock, fptr);
+ fd = fileno(fptr->f);
+#ifdef THREAD
+ thread_wait_fd(fd);
+#endif
+ TRAP_BEG;
+ retry:
+ str->len = recvfrom(fd, str->ptr, str->len, flags,
+ (struct sockaddr*)buf, &alen);
+ TRAP_END;
+
+ if (str->len < 0) {
+ switch (errno) {
+ case EINTR:
+ case EWOULDBLOCK:
+#if EAGAIN != EWOULDBLOCK
+ case EAGAIN:
+#endif
+#ifdef THREAD
+ thread_schedule();
+#endif
+ goto retry;
+ }
+ rb_sys_fail("recvfrom(2)");
+ }
+ str_taint(str);
+ switch (from) {
+ case 0:
+ return (VALUE)str;
+ case 1:
+ if (alen != sizeof(struct sockaddr_in)) {
+ TypeError("sockaddr size differs - should not happen");
+ }
+ return assoc_new(str, tcpaddr((struct sockaddr_in *)buf));
+#ifdef HAVE_SYS_UN_H
+ case 2:
+ if (alen != sizeof(struct sockaddr_un)) {
+ TypeError("sockaddr size differs - should not happen");
+ }
+ return assoc_new(str, unixaddr((struct sockaddr_un *)buf));
+#endif
+ case 3:
+ return assoc_new(str, str_new(buf, alen));
+ }
+}
+
+static VALUE
+bsock_recv(argc, argv, sock)
+ int argc;
+ VALUE *argv;
+ VALUE sock;
+{
+ return s_recv(sock, argc, argv, 0);
+}
+
+#if defined(THREAD) && defined(HAVE_FCNTL)
+static int
+thread_connect(fd, sockaddr, len, type)
+ int fd;
+ struct sockaddr *sockaddr;
+ int len;
+ int type;
+{
+ int status;
+ int mode;
+ fd_set fds;
+
+ mode = fcntl(fd, F_GETFL, 0);
+
+#ifdef O_NDELAY
+# define NONBLOCKING O_NDELAY
+#else
+#ifdef O_NBIO
+# define NONBLOCKING O_NBIO
+#else
+# define NONBLOCKING O_NONBLOCK
+#endif
+#endif
+ fcntl(fd, F_SETFL, mode|NONBLOCKING);
+ for (;;) {
+#ifdef SOCKS
+ if (type == INET_SOCKS) {
+ status = Rconnect(fd, sockaddr, len);
+ }
+ else
+#endif
+ {
+ status = connect(fd, sockaddr, len);
+ }
+ if (status < 0) {
+ switch (errno) {
+#ifdef EINPROGRESS
+ case EINPROGRESS:
+#ifdef EAGAIN
+ case EAGAIN:
+#endif
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ thread_select(fd+1, 0, &fds, 0, 0, 0);
+ continue;
+#endif
+
+#ifdef EISCONN
+ case EISCONN:
+#endif
+#ifdef EALREADY
+ case EALREADY:
+#endif
+#if defined(EISCONN) || defined(EALREADY)
+ status = 0;
+ errno = 0;
+ break;
+#endif
+ }
+ }
+ mode &= ~NONBLOCKING;
+ fcntl(fd, F_SETFL, mode);
+ return status;
+ }
+}
+#endif
+
+static VALUE
+open_inet(class, h, serv, type)
VALUE class, h, serv;
- int server;
+ int type;
{
char *host;
struct hostent *hostent, _hostent;
@@ -203,13 +423,13 @@ open_inet(class, h, serv, server)
VALUE sock;
if (h) {
- Check_Type(h, T_STRING);
+ Check_SafeStr(h);
host = RSTRING(h)->ptr;
hostent = gethostbyname(host);
if (hostent == NULL) {
hostaddr = inet_addr(host);
if (hostaddr == -1) {
- if (server && !strlen(host))
+ if (type == INET_SERVER && !strlen(host))
hostaddr = INADDR_ANY;
else {
#ifdef HAVE_HSTRERROR
@@ -252,6 +472,7 @@ open_inet(class, h, serv, server)
fd = socket(PF_INET, SOCK_STREAM, protoent->p_proto);
+ memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
if (h) {
memcpy((char *)&(sockaddr.sin_addr.s_addr),
@@ -263,12 +484,27 @@ open_inet(class, h, serv, server)
}
sockaddr.sin_port = servent->s_port;
- if (server) {
+ if (type == INET_SERVER) {
+ status = 1;
+ setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char*)&status,sizeof(status));
status = bind(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
syscall = "bind(2)";
}
else {
- status = connect(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
+#if defined(THREAD) && defined(HAVE_FCNTL)
+ status = thread_connect(fd, (struct sockaddr*)&sockaddr,
+ sizeof(sockaddr), type);
+#else
+#ifdef SOCKS
+ if (type == INET_SOCKS) {
+ status = Rconnect(fd, &sockaddr, sizeof(sockaddr));
+ }
+ else
+#endif
+ {
+ status = connect(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
+ }
+#endif
syscall = "connect(2)";
}
@@ -276,7 +512,7 @@ open_inet(class, h, serv, server)
close (fd);
rb_sys_fail(syscall);
}
- if (server) listen(fd, 5);
+ if (type == INET_SERVER) listen(fd, 5);
/* create new instance */
sock = sock_new(class, fd);
@@ -288,10 +524,27 @@ static VALUE
tcp_s_open(class, host, serv)
VALUE class, host, serv;
{
- Check_Type(host, T_STRING);
- return open_inet(class, host, serv, 0);
+ Check_SafeStr(host);
+ return open_inet(class, host, serv, INET_CLIENT);
}
+#ifdef SOCKS
+static VALUE
+socks_s_open(class, host, serv)
+ VALUE class, host, serv;
+{
+ static init = 0;
+
+ if (init == 0) {
+ SOCKSinit("ruby");
+ init = 1;
+ }
+
+ Check_SafeStr(host);
+ return open_inet(class, host, serv, INET_SOCKS);
+}
+#endif
+
static VALUE
tcp_svr_s_open(argc, argv, class)
int argc;
@@ -301,9 +554,9 @@ tcp_svr_s_open(argc, argv, class)
VALUE arg1, arg2;
if (rb_scan_args(argc, argv, "11", &arg1, &arg2) == 2)
- return open_inet(class, arg1, arg2, 1);
+ return open_inet(class, arg1, arg2, INET_SERVER);
else
- return open_inet(class, 0, arg1, 1);
+ return open_inet(class, 0, arg1, INET_SERVER);
}
static VALUE
@@ -323,7 +576,17 @@ s_accept(class, fd, sockaddr, len)
fd2 = accept(fd, sockaddr, len);
TRAP_END;
if (fd2 < 0) {
- if (errno == EINTR) goto retry;
+ switch (errno) {
+ case EINTR:
+ case EWOULDBLOCK:
+#if EAGAIN != EWOULDBLOCK
+ case EAGAIN:
+#endif
+#ifdef THREAD
+ thread_schedule();
+#endif
+ goto retry;
+ }
rb_sys_fail(0);
}
return sock_new(class, fd2);
@@ -352,30 +615,28 @@ open_unix(class, path, server)
{
struct sockaddr_un sockaddr;
int fd, status;
- char *syscall;
VALUE sock;
OpenFile *fptr;
- Check_Type(path, T_STRING);
+ Check_SafeStr(path);
fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (fd < 0) rb_sys_fail("socket(2)");
+ memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sun_family = AF_UNIX;
strncpy(sockaddr.sun_path, path->ptr, sizeof(sockaddr.sun_path)-1);
sockaddr.sun_path[sizeof(sockaddr.sun_path)-1] = '\0';
if (server) {
status = bind(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
- syscall = "bind(2)";
}
else {
status = connect(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
- syscall = "connect(2)";
}
if (status < 0) {
- close (fd);
- rb_sys_fail(syscall);
+ close(fd);
+ rb_sys_fail(sockaddr.sun_path);
}
if (server) listen(fd, 5);
@@ -397,8 +658,6 @@ setipaddr(name, addr)
char ch;
struct hostent *hp;
long x;
- unsigned char *a;
- char buf[16];
if (name[0] == 0) {
addr->sin_addr.s_addr = INADDR_ANY;
@@ -496,6 +755,15 @@ tcp_peeraddr(sock)
}
static VALUE
+tcp_recvfrom(argc, argv, sock)
+ int argc;
+ VALUE *argv;
+ VALUE sock;
+{
+ return s_recv(sock, argc, argv, 1);
+}
+
+static VALUE
tcp_s_getaddress(obj, host)
VALUE obj, host;
{
@@ -547,6 +815,15 @@ unix_svr_s_open(class, path)
}
static VALUE
+unix_recvfrom(argc, argv, sock)
+ int argc;
+ VALUE *argv;
+ VALUE sock;
+{
+ return s_recv(sock, argc, argv, 2);
+}
+
+static VALUE
unix_accept(sock)
VALUE sock;
{
@@ -685,7 +962,7 @@ static VALUE
sock_s_socketpair(class, domain, type, protocol)
VALUE class, domain, type, protocol;
{
-#if !defined(__CYGWIN32__)
+#if !defined(__CYGWIN32__) && !defined(NT)
int fd;
int d, t, sp[2];
@@ -710,8 +987,21 @@ sock_connect(sock, addr)
str_modify(addr);
GetOpenFile(sock, fptr);
- if (connect(fileno(fptr->f), (struct sockaddr*)addr->ptr, addr->len) < 0)
+ retry:
+ if (connect(fileno(fptr->f), (struct sockaddr*)addr->ptr, addr->len) < 0) {
+ switch (errno) {
+ case EINTR:
+ case EWOULDBLOCK:
+#if EAGAIN != EWOULDBLOCK
+ case EAGAIN:
+#endif
+#ifdef THREAD
+ thread_schedule();
+#endif
+ goto retry;
+ }
rb_sys_fail("connect(2)");
+ }
return INT2FIX(0);
}
@@ -747,114 +1037,27 @@ sock_listen(sock, log)
}
static VALUE
-sock_accept(sock)
- VALUE sock;
-{
- OpenFile *fptr;
- VALUE addr, sock2;
- char buf[1024];
- int len = sizeof buf;
-
- GetOpenFile(sock, fptr);
- sock2 = s_accept(cSocket,fileno(fptr->f),(struct sockaddr*)buf,&len);
-
- return assoc_new(sock2, str_new(buf, len));
-}
-
-static VALUE
-sock_send(argc, argv, sock)
+sock_recvfrom(argc, argv, sock)
int argc;
VALUE *argv;
VALUE sock;
{
- struct RString *msg, *to;
- VALUE flags;
- OpenFile *fptr;
- FILE *f;
- int fd, n;
-
- rb_scan_args(argc, argv, "21", &msg, &flags, &to);
-
- Check_Type(msg, T_STRING);
-
- GetOpenFile(sock, fptr);
- f = fptr->f2?fptr->f2:fptr->f;
- fd = fileno(f);
-#ifdef THREAD
- thread_fd_writable(fd);
-#endif
- if (to) {
- Check_Type(to, T_STRING);
- n = sendto(fd, msg->ptr, msg->len, NUM2INT(flags),
- (struct sockaddr*)to->ptr, to->len);
- }
- else {
- n = send(fd, msg->ptr, msg->len, NUM2INT(flags));
- }
- if (n < 0) {
- rb_sys_fail("send(2)");
- }
- return INT2FIX(n);
+ return s_recv(sock, argc, argv, 3);
}
static VALUE
-s_recv(sock, argc, argv, from)
- VALUE sock;
- int argc;
- VALUE *argv;
- int from;
+sock_accept(sock)
+ VALUE sock;
{
OpenFile *fptr;
- FILE f;
- struct RString *str;
+ VALUE addr, sock2;
char buf[1024];
- int fd, alen = sizeof buf;
- VALUE len, flg;
- int flags;
-
- rb_scan_args(argc, argv, "11", &len, &flg);
-
- if (flg == Qnil) flags = 0;
- else flags = NUM2INT(flg);
-
- str = (struct RString*)str_new(0, NUM2INT(len));
+ int len = sizeof buf;
GetOpenFile(sock, fptr);
- fd = fileno(fptr->f);
-#ifdef THREAD
- thread_wait_fd(fd);
-#endif
- TRAP_BEG;
- str->len = recvfrom(fd, str->ptr, str->len, flags,
- (struct sockaddr*)buf, &alen);
- TRAP_END;
-
- if (str->len < 0) {
- rb_sys_fail("recvfrom(2)");
- }
-
- if (from)
- return assoc_new(str, str_new(buf, alen));
- else
- return (VALUE)str;
-}
-
-static VALUE
-sock_recv(argc, argv, sock)
- int argc;
- VALUE *argv;
- VALUE sock;
-{
- return s_recv(sock, argc, argv, 0);
-}
+ sock2 = s_accept(cSocket,fileno(fptr->f),(struct sockaddr*)buf,&len);
-static VALUE
-sock_recvfrom(argc, argv, sock)
- int argc;
- VALUE *argv;
- VALUE sock;
-{
- return s_recv(sock, argc, argv, 1);
+ return assoc_new(sock2, str_new(buf, len));
}
#ifdef HAVE_GETHOSTNAME
@@ -951,6 +1154,7 @@ sock_s_gethostbyname(obj, host)
return mkhostent(h);
}
+static VALUE
sock_s_gethostbyaddr(argc, argv)
int argc;
VALUE *argv;
@@ -999,17 +1203,19 @@ sock_s_getservbyaname(argc, argv)
return INT2FIX(port);
}
-Init_socket ()
+Init_socket()
{
eSocket = rb_define_class("SocketError", eException);
cBasicSocket = rb_define_class("BasicSocket", cIO);
- rb_undef_method(cBasicSocket, "new");
+ rb_undef_method(CLASS_OF(cBasicSocket), "new");
rb_define_method(cBasicSocket, "shutdown", bsock_shutdown, -1);
rb_define_method(cBasicSocket, "setsockopt", bsock_setsockopt, 3);
rb_define_method(cBasicSocket, "getsockopt", bsock_getsockopt, 2);
rb_define_method(cBasicSocket, "getsockname", bsock_getsockname, 0);
rb_define_method(cBasicSocket, "getpeername", bsock_getpeername, 0);
+ rb_define_method(cBasicSocket, "send", bsock_send, -1);
+ rb_define_method(cBasicSocket, "recv", bsock_recv, -1);
cTCPsocket = rb_define_class("TCPsocket", cBasicSocket);
rb_define_singleton_method(cTCPsocket, "open", tcp_s_open, 2);
@@ -1017,6 +1223,13 @@ Init_socket ()
rb_define_method(cTCPsocket, "addr", tcp_addr, 0);
rb_define_method(cTCPsocket, "peeraddr", tcp_peeraddr, 0);
rb_define_singleton_method(cTCPsocket, "getaddress", tcp_s_getaddress, 1);
+ rb_define_method(cTCPsocket, "recvfrom", tcp_recvfrom, -1);
+
+#ifdef SOCKS
+ cSOCKSsocket = rb_define_class("SOCKSsocket", cTCPsocket);
+ rb_define_singleton_method(cSOCKSsocket, "open", socks_s_open, 2);
+ rb_define_singleton_method(cSOCKSsocket, "new", socks_s_open, 2);
+#endif
cTCPserver = rb_define_class("TCPserver", cTCPsocket);
rb_define_singleton_method(cTCPserver, "open", tcp_svr_s_open, -1);
@@ -1030,6 +1243,7 @@ Init_socket ()
rb_define_method(cUNIXsocket, "path", unix_path, 0);
rb_define_method(cUNIXsocket, "addr", unix_addr, 0);
rb_define_method(cUNIXsocket, "peeraddr", unix_peeraddr, 0);
+ rb_define_method(cUNIXsocket, "recvfrom", unix_recvfrom, -1);
cUNIXserver = rb_define_class("UNIXserver", cUNIXsocket);
rb_define_singleton_method(cUNIXserver, "open", unix_svr_s_open, 1);
@@ -1047,9 +1261,7 @@ Init_socket ()
rb_define_method(cSocket, "listen", sock_listen, 1);
rb_define_method(cSocket, "accept", sock_accept, 0);
- rb_define_method(cSocket, "send", sock_send, -1);
- rb_define_method(cSocket, "recv", sock_recv, -1);
- rb_define_method(cSocket, "recvfrom", sock_recv, -1);
+ rb_define_method(cSocket, "recvfrom", sock_recvfrom, -1);
rb_define_singleton_method(cSocket, "socketpair", sock_s_socketpair, 3);
rb_define_singleton_method(cSocket, "pair", sock_s_socketpair, 3);
@@ -1059,12 +1271,29 @@ Init_socket ()
rb_define_singleton_method(cSocket, "getservbyname", sock_s_getservbyaname, -1);
/* constants */
+ rb_define_const(cSocket, "SOCK_STREAM", INT2FIX(SOCK_STREAM));
+ rb_define_const(cSocket, "SOCK_DGRAM", INT2FIX(SOCK_DGRAM));
+ rb_define_const(cSocket, "SOCK_RAW", INT2FIX(SOCK_RAW));
+#ifdef SOCK_RDM
+ rb_define_const(cSocket, "SOCK_RDM", INT2FIX(SOCK_RDM));
+#endif
+#ifdef SOCK_SEQPACKET
+ rb_define_const(cSocket, "SOCK_SEQPACKET", INT2FIX(SOCK_SEQPACKET));
+#endif
+#ifdef SOCK_PACKET
+ rb_define_const(cSocket, "SOCK_PACKET", INT2FIX(SOCK_PACKET));
+#endif
+
rb_define_const(cSocket, "AF_INET", INT2FIX(AF_INET));
rb_define_const(cSocket, "PF_INET", INT2FIX(PF_INET));
#ifdef AF_UNIX
rb_define_const(cSocket, "AF_UNIX", INT2FIX(AF_UNIX));
rb_define_const(cSocket, "PF_UNIX", INT2FIX(PF_UNIX));
#endif
+#ifdef AF_AX25
+ rb_define_const(cSocket, "AF_AX25", INT2FIX(AF_AX25));
+ rb_define_const(cSocket, "PF_AX25", INT2FIX(PF_AX25));
+#endif
#ifdef AF_IPX
rb_define_const(cSocket, "AF_IPX", INT2FIX(AF_IPX));
rb_define_const(cSocket, "PF_IPX", INT2FIX(PF_IPX));
@@ -1078,19 +1307,6 @@ Init_socket ()
rb_define_const(cSocket, "MSG_PEEK", INT2FIX(MSG_PEEK));
rb_define_const(cSocket, "MSG_DONTROUTE", INT2FIX(MSG_DONTROUTE));
- rb_define_const(cSocket, "SOCK_STREAM", INT2FIX(SOCK_STREAM));
- rb_define_const(cSocket, "SOCK_DGRAM", INT2FIX(SOCK_DGRAM));
- rb_define_const(cSocket, "SOCK_RAW", INT2FIX(SOCK_RAW));
-#ifdef SOCK_RDM
- rb_define_const(cSocket, "SOCK_RDM", INT2FIX(SOCK_RDM));
-#endif
-#ifdef SOCK_SEQPACKET
- rb_define_const(cSocket, "SOCK_SEQPACKET", INT2FIX(SOCK_SEQPACKET));
-#endif
-#ifdef SOCK_PACKET
- rb_define_const(cSocket, "SOCK_PACKET", INT2FIX(SOCK_PACKET));
-#endif
-
rb_define_const(cSocket, "SOL_SOCKET", INT2FIX(SOL_SOCKET));
#ifdef SOL_IP
rb_define_const(cSocket, "SOL_IP", INT2FIX(SOL_IP));
@@ -1098,6 +1314,9 @@ Init_socket ()
#ifdef SOL_IPX
rb_define_const(cSocket, "SOL_IPX", INT2FIX(SOL_IPX));
#endif
+#ifdef SOL_AX25
+ rb_define_const(cSocket, "SOL_AX25", INT2FIX(SOL_AX25));
+#endif
#ifdef SOL_ATALK
rb_define_const(cSocket, "SOL_ATALK", INT2FIX(SOL_ATALK));
#endif
@@ -1108,8 +1327,81 @@ Init_socket ()
rb_define_const(cSocket, "SOL_UDP", INT2FIX(SOL_UDP));
#endif
+#ifdef SO_DEBUG
rb_define_const(cSocket, "SO_DEBUG", INT2FIX(SO_DEBUG));
+#endif
rb_define_const(cSocket, "SO_REUSEADDR", INT2FIX(SO_REUSEADDR));
+#ifdef SO_TYPE
+ rb_define_const(cSocket, "SO_TYPE", INT2FIX(SO_TYPE));
+#endif
+#ifdef SO_ERROR
+ rb_define_const(cSocket, "SO_ERROR", INT2FIX(SO_ERROR));
+#endif
+#ifdef SO_DONTROUTE
+ rb_define_const(cSocket, "SO_DONTROUTE", INT2FIX(SO_DONTROUTE));
+#endif
+#ifdef SO_BROADCAST
+ rb_define_const(cSocket, "SO_BROADCAST", INT2FIX(SO_BROADCAST));
+#endif
+#ifdef SO_SNDBUF
+ rb_define_const(cSocket, "SO_SNDBUF", INT2FIX(SO_SNDBUF));
+#endif
+#ifdef SO_RCVBUF
+ rb_define_const(cSocket, "SO_RCVBUF", INT2FIX(SO_RCVBUF));
+#endif
rb_define_const(cSocket, "SO_KEEPALIVE", INT2FIX(SO_KEEPALIVE));
+#ifdef SO_OOBINLINE
+ rb_define_const(cSocket, "SO_OOBINLINE", INT2FIX(SO_OOBINLINE));
+#endif
+#ifdef SO_NO_CHECK
+ rb_define_const(cSocket, "SO_NO_CHECK", INT2FIX(SO_NO_CHECK));
+#endif
+#ifdef SO_PRIORITY
+ rb_define_const(cSocket, "SO_PRIORITY", INT2FIX(SO_PRIORITY));
+#endif
rb_define_const(cSocket, "SO_LINGER", INT2FIX(SO_LINGER));
+
+#ifdef SOPRI_INTERACTIVE
+ rb_define_const(cSocket, "SOPRI_INTERACTIVE", INT2FIX(SOPRI_INTERACTIVE));
+#endif
+#ifdef SOPRI_NORMAL
+ rb_define_const(cSocket, "SOPRI_NORMAL", INT2FIX(SOPRI_NORMAL));
+#endif
+#ifdef SOPRI_BACKGROUND
+ rb_define_const(cSocket, "SOPRI_BACKGROUND", INT2FIX(SOPRI_BACKGROUND));
+#endif
+
+#ifdef IP_MULTICAST_IF
+ rb_define_const(cSocket, "IP_MULTICAST_IF", INT2FIX(IP_MULTICAST_IF));
+#endif
+#ifdef IP_MULTICAST_TTL
+ rb_define_const(cSocket, "IP_MULTICAST_TTL", INT2FIX(IP_MULTICAST_TTL));
+#endif
+#ifdef IP_MULTICAST_LOOP
+ rb_define_const(cSocket, "IP_MULTICAST_LOOP", INT2FIX(IP_MULTICAST_LOOP));
+#endif
+#ifdef IP_ADD_MEMBERSHIP
+ rb_define_const(cSocket, "IP_ADD_MEMBERSHIP", INT2FIX(IP_ADD_MEMBERSHIP));
+#endif
+
+#ifdef IP_DEFAULT_MULTICAST_TTL
+ rb_define_const(cSocket, "IP_DEFAULT_MULTICAST_TTL", INT2FIX(IP_DEFAULT_MULTICAST_TTL));
+#endif
+#ifdef IP_DEFAULT_MULTICAST_LOOP
+ rb_define_const(cSocket, "IP_DEFAULT_MULTICAST_LOOP", INT2FIX(IP_DEFAULT_MULTICAST_LOOP));
+#endif
+#ifdef IP_MAX_MEMBERSHIPS
+ rb_define_const(cSocket, "IP_MAX_MEMBERSHIPS", INT2FIX(IP_MAX_MEMBERSHIPS));
+#endif
+
+#ifdef IPX_TYPE
+ rb_define_const(cSocket, "IPX_TYPE", INT2FIX(IPX_TYPE));
+#endif
+
+#ifdef TCP_NODELAY
+ rb_define_const(cSocket, "TCP_NODELAY", INT2FIX(TCP_NODELAY));
+#endif
+#ifdef TCP_MAXSEG
+ rb_define_const(cSocket, "TCP_MAXSEG", INT2FIX(TCP_MAXSEG));
+#endif
}
diff --git a/ext/tkutil/tkutil.c b/ext/tkutil/tkutil.c
index 51e3412ab5..5e6b77b9af 100644
--- a/ext/tkutil/tkutil.c
+++ b/ext/tkutil/tkutil.c
@@ -23,13 +23,6 @@ tk_eval_cmd(argc, argv)
}
static VALUE
-tk_yield(obj)
- VALUE obj;
-{
- rb_yield_0(obj, obj);
-}
-
-static VALUE
tk_s_new(argc, argv, class)
int argc;
VALUE *argv;
@@ -38,7 +31,7 @@ tk_s_new(argc, argv, class)
VALUE obj = obj_alloc(class);
rb_funcall2(obj, rb_intern("initialize"), argc, argv);
- if (iterator_p()) tk_yield(obj);
+ if (iterator_p()) rb_yield_0(obj, obj);
return obj;
}
diff --git a/file.c b/file.c
index 656650b11b..0894c72ffb 100644
--- a/file.c
+++ b/file.c
@@ -26,10 +26,12 @@
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#else
-stuct timeval {
+#ifndef NT
+struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* and microseconds */
};
+#endif /* NT */
#endif
#ifdef HAVE_UTIME_H
@@ -46,8 +48,14 @@ stuct timeval {
char *strrchr();
#endif
+#ifdef NT
+#include <sys/stat.h>
+#endif
+
+#ifndef NT
char *strdup();
char *getenv();
+#endif
extern VALUE cIO;
VALUE cFile;
@@ -66,7 +74,6 @@ file_open(fname, mode)
MakeOpenFile(port, fptr);
fptr->mode = io_mode_flags(mode);
-
fptr->f = rb_fopen(fname, mode);
fptr->path = strdup(fname);
@@ -74,23 +81,77 @@ file_open(fname, mode)
}
static VALUE
-file_s_open(argc, argv)
+file_s_open(argc, argv, class)
int argc;
VALUE *argv;
+ VALUE class;
{
- VALUE fname, vmode;
+ VALUE fname, vmode, file;
char *mode;
- rb_scan_args(argc, argv, "11", &fname, &mode);
- Check_Type(fname, T_STRING);
- if (!NIL_P(mode)) {
- Check_Type(mode, T_STRING);
- mode = RSTRING(mode)->ptr;
+ rb_scan_args(argc, argv, "11", &fname, &vmode);
+ Check_SafeStr(fname);
+ if (!NIL_P(vmode)) {
+ Check_Type(vmode, T_STRING);
+ mode = RSTRING(vmode)->ptr;
+ }
+ else {
+ mode = "r";
+ }
+ file = file_open(RSTRING(fname)->ptr, mode);
+
+ RBASIC(file)->class = class;
+ return file;
+}
+
+static VALUE
+file_reopen(argc, argv, file)
+ int argc;
+ VALUE *argv;
+ VALUE file;
+{
+ VALUE fname, nmode;
+ char *mode;
+ OpenFile *fptr;
+
+ if (rb_scan_args(argc, argv, "11", &fname, &nmode) == 1) {
+ if (TYPE(fname) == T_FILE) { /* fname must be IO */
+ return io_reopen(file, fname);
+ }
+ }
+
+ Check_SafeStr(fname);
+ if (!NIL_P(nmode)) {
+ Check_Type(nmode, T_STRING);
+ mode = RSTRING(nmode)->ptr;
}
else {
mode = "r";
}
- return file_open(RSTRING(fname)->ptr, mode);
+
+ GetOpenFile(file, fptr);
+ if (fptr->path) free(fptr->path);
+ fptr->path = strdup(RSTRING(fname)->ptr);
+ fptr->mode = io_mode_flags(mode);
+ if (!fptr->f) {
+ fptr->f = rb_fopen(RSTRING(fname)->ptr, mode);
+ if (fptr->f2) {
+ fclose(fptr->f2);
+ fptr->f2 = NULL;
+ }
+ return file;
+ }
+
+ if (freopen(RSTRING(fname)->ptr, mode, fptr->f) == NULL) {
+ rb_sys_fail(fptr->path);
+ }
+ if (fptr->f2) {
+ if (freopen(RSTRING(fname)->ptr, "w", fptr->f2) == NULL) {
+ rb_sys_fail(fptr->path);
+ }
+ }
+
+ return file;
}
static int
@@ -103,8 +164,11 @@ apply2files(func, args, arg)
VALUE path;
for (i=0; i<args->len; i++) {
+ Check_SafeStr(args->ptr[i]);
+ }
+
+ for (i=0; i<args->len; i++) {
path = args->ptr[i];
- Check_Type(path, T_STRING);
if ((*func)(RSTRING(path)->ptr, arg) < 0)
rb_sys_fail(RSTRING(path)->ptr);
}
@@ -200,7 +264,11 @@ file_isatty(obj)
}
#include <sys/types.h>
+#ifndef NT
#include <sys/file.h>
+#else
+#include "missing/file.h"
+#endif
#include <sys/stat.h>
static VALUE
@@ -243,7 +311,7 @@ file_s_stat(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) == -1) {
rb_sys_fail(fname->ptr);
}
@@ -269,10 +337,10 @@ file_s_lstat(obj, fname)
VALUE obj;
struct RString *fname;
{
-#if !defined(MSDOS)
+#if !defined(MSDOS) && !defined(NT)
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (lstat(fname->ptr, &st) == -1) {
rb_sys_fail(fname->ptr);
}
@@ -286,7 +354,7 @@ static VALUE
file_lstat(obj)
VALUE obj;
{
-#if !defined(MSDOS)
+#if !defined(MSDOS) && !defined(NT)
OpenFile *fptr;
struct stat st;
@@ -335,6 +403,7 @@ eaccess(path, mode)
char *path;
int mode;
{
+#ifndef NT
struct stat st;
static int euid = -1;
@@ -355,6 +424,19 @@ eaccess(path, mode)
return 0;
}
+#if defined(DJGPP)
+ {
+ int stat_mode = 0;
+ if (mode & X_OK)
+ stat_mode |= S_IXOTH;
+ if (mode & W_OK)
+ stat_mode |= S_IWOTH;
+ if (mode & R_OK)
+ stat_mode |= S_IROTH;
+ mode = stat_mode;
+ }
+#endif
+
if (st.st_uid == euid) /* owner */
mode <<= 6;
else if (group_member (st.st_gid))
@@ -363,6 +445,9 @@ eaccess(path, mode)
if (st.st_mode & mode) return 0;
return -1;
+#else /* !NT*/
+ return 0;
+#endif
}
static VALUE
@@ -376,7 +461,7 @@ test_d(obj, fname)
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (S_ISDIR(st.st_mode)) return TRUE;
return FALSE;
@@ -394,7 +479,7 @@ test_p(obj, fname)
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (S_ISFIFO(st.st_mode)) return TRUE;
@@ -424,7 +509,7 @@ test_l(obj, fname)
#ifdef S_ISLNK
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (lstat(fname->ptr, &st) < 0) return FALSE;
if (S_ISLNK(st.st_mode)) return TRUE;
@@ -432,7 +517,7 @@ test_l(obj, fname)
return FALSE;
}
-VALUE
+static VALUE
test_S(obj, fname)
VALUE obj;
struct RString *fname;
@@ -454,7 +539,7 @@ test_S(obj, fname)
#ifdef S_ISSOCK
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (S_ISSOCK(st.st_mode)) return TRUE;
@@ -470,13 +555,15 @@ test_b(obj, fname)
#ifndef S_ISBLK
# ifdef S_IFBLK
# define S_ISBLK(m) ((m & S_IFMT) == S_IFBLK)
+# else
+# define S_ISBLK(m) (0) /* anytime false */
# endif
#endif
#ifdef S_ISBLK
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (S_ISBLK(st.st_mode)) return TRUE;
@@ -495,7 +582,7 @@ test_c(obj, fname)
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (S_ISBLK(st.st_mode)) return TRUE;
@@ -509,7 +596,7 @@ test_e(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
return TRUE;
}
@@ -519,7 +606,7 @@ test_r(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (eaccess(fname->ptr, R_OK) < 0) return FALSE;
return TRUE;
}
@@ -529,7 +616,7 @@ test_R(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (access(fname->ptr, R_OK) < 0) return FALSE;
return TRUE;
}
@@ -539,7 +626,7 @@ test_w(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (eaccess(fname->ptr, W_OK) < 0) return FALSE;
return TRUE;
}
@@ -549,7 +636,7 @@ test_W(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (access(fname->ptr, W_OK) < 0) return FALSE;
return TRUE;
}
@@ -559,7 +646,7 @@ test_x(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (eaccess(fname->ptr, X_OK) < 0) return FALSE;
return TRUE;
}
@@ -569,11 +656,15 @@ test_X(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (access(fname->ptr, X_OK) < 0) return FALSE;
return TRUE;
}
+#ifndef S_ISREG
+# define S_ISREG(m) ((m & S_IFMT) == S_IFREG)
+#endif
+
static VALUE
test_f(obj, fname)
VALUE obj;
@@ -581,7 +672,7 @@ test_f(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (S_ISREG(st.st_mode)) return TRUE;
return FALSE;
@@ -594,7 +685,7 @@ test_z(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (st.st_size == 0) return TRUE;
return FALSE;
@@ -607,7 +698,7 @@ test_s(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (st.st_size == 0) return FALSE;
return int2inum(st.st_size);
@@ -620,7 +711,7 @@ test_owned(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (st.st_uid == geteuid()) return TRUE;
return FALSE;
@@ -633,7 +724,7 @@ test_rowned(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (st.st_uid == getuid()) return TRUE;
return FALSE;
@@ -647,11 +738,9 @@ test_grpowned(obj, fname)
#ifndef NT
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) return FALSE;
if (st.st_gid == getegid()) return TRUE;
-#else
- Check_Type(fname, T_STRING);
#endif
return FALSE;
}
@@ -675,8 +764,8 @@ test_suid(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
#ifdef S_ISUID
+ Check_SafeStr(fname);
return check3rdbyte(fname->ptr, S_ISUID);
#else
return FALSE;
@@ -688,8 +777,8 @@ test_sgid(obj, fname)
VALUE obj;
struct RString *fname;
{
- Check_Type(fname, T_STRING);
#ifndef NT
+ Check_SafeStr(fname);
return check3rdbyte(fname->ptr, S_ISGID);
#else
return FALSE;
@@ -710,14 +799,26 @@ test_sticky(obj, fname)
}
static VALUE
-file_s_type(obj, fname)
+file_s_size(obj, fname)
+ VALUE obj;
+ struct RString *fname;
+{
+ struct stat st;
+
+ Check_SafeStr(fname);
+ if (stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr);
+ return int2inum(st.st_size);
+}
+
+static VALUE
+file_s_ftype(obj, fname)
VALUE obj;
struct RString *fname;
{
struct stat st;
char *t;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr);
if (S_ISREG(st.st_mode)) {
@@ -732,7 +833,7 @@ file_s_type(obj, fname)
t = "blockSpecial";
}
#endif
-#ifndef S_ISFIFO
+#ifdef S_ISFIFO
else if (S_ISFIFO(st.st_mode)) {
t = "fifo";
}
@@ -761,7 +862,7 @@ file_s_atime(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr);
return time_new(st.st_atime, 0);
}
@@ -787,7 +888,7 @@ file_s_mtime(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr);
return time_new(st.st_mtime, 0);
}
@@ -813,7 +914,7 @@ file_s_ctime(obj, fname)
{
struct stat st;
- Check_Type(fname, T_STRING);
+ Check_SafeStr(fname);
if (stat(fname->ptr, &st) < 0) rb_sys_fail(fname->ptr);
return time_new(st.st_ctime, 0);
}
@@ -864,10 +965,11 @@ file_chmod(obj, vmode)
OpenFile *fptr;
int mode;
+ rb_secure(2);
mode = NUM2INT(vmode);
GetOpenFile(obj, fptr);
-#if defined(DJGPP) || defined(__CYGWIN32__)
+#if defined(DJGPP) || defined(__CYGWIN32__) || defined(NT)
if (chmod(fptr->path, mode) == -1)
rb_sys_fail(fptr->path);
#else
@@ -918,14 +1020,15 @@ file_s_chown(argc, argv)
return INT2FIX(n);
}
-VALUE
+static VALUE
file_chown(obj, owner, group)
VALUE obj, owner, group;
{
OpenFile *fptr;
+ rb_secure(2);
GetOpenFile(obj, fptr);
-#if defined(DJGPP) || defined(__CYGWIN32__)
+#if defined(DJGPP) || defined(__CYGWIN32__) || defined(NT)
if (chown(fptr->path, NUM2INT(owner), NUM2INT(group)) == -1)
rb_sys_fail(fptr->path);
#else
@@ -972,6 +1075,7 @@ file_s_utime(argc, argv)
#ifndef HAVE_UTIME_H
# ifdef NT
# include <sys/utime.h>
+# define utimbuf _utimbuf
# else
struct utimbuf {
long actime;
@@ -1017,12 +1121,16 @@ file_s_link(obj, from, to)
VALUE obj;
struct RString *from, *to;
{
- Check_Type(from, T_STRING);
- Check_Type(to, T_STRING);
+#ifndef __human68k__
+ Check_SafeStr(from);
+ Check_SafeStr(to);
if (link(from->ptr, to->ptr) < 0)
rb_sys_fail(from->ptr);
return INT2FIX(0);
+#else
+ rb_notimplement();
+#endif
}
static VALUE
@@ -1030,9 +1138,9 @@ file_s_symlink(obj, from, to)
VALUE obj;
struct RString *from, *to;
{
-#if !defined(MSDOS)
- Check_Type(from, T_STRING);
- Check_Type(to, T_STRING);
+#if !defined(MSDOS) && !defined(NT)
+ Check_SafeStr(from);
+ Check_SafeStr(to);
if (symlink(from->ptr, to->ptr) < 0)
rb_sys_fail(from->ptr);
@@ -1047,18 +1155,18 @@ file_s_readlink(obj, path)
VALUE obj;
struct RString *path;
{
-#if !defined(MSDOS)
+#if !defined(MSDOS) && !defined(NT)
char buf[MAXPATHLEN];
int cc;
- Check_Type(path, T_STRING);
+ Check_SafeStr(path);
if ((cc = readlink(path->ptr, buf, MAXPATHLEN)) < 0)
rb_sys_fail(path->ptr);
return str_new(buf, cc);
#else
- rb_notimplement();
+ rb_notimplement();
#endif
}
@@ -1086,8 +1194,8 @@ file_s_rename(obj, from, to)
VALUE obj;
struct RString *from, *to;
{
- Check_Type(from, T_STRING);
- Check_Type(to, T_STRING);
+ Check_SafeStr(from);
+ Check_SafeStr(to);
if (rename(from->ptr, to->ptr) == -1)
rb_sys_fail(from->ptr);
@@ -1107,7 +1215,7 @@ file_s_umask(argc, argv)
umask(omask);
}
else if (argc == 1) {
- omask = umask(NUM2INT(argv[1]));
+ omask = umask(NUM2INT(argv[0]));
}
else {
ArgError("wrong # of argument");
@@ -1115,7 +1223,7 @@ file_s_umask(argc, argv)
return INT2FIX(omask);
}
-static VALUE
+VALUE
file_s_expand_path(obj, fname)
VALUE obj;
struct RString *fname;
@@ -1205,7 +1313,7 @@ file_s_expand_path(obj, fname)
if (p == buf || *p != '/') p++;
*p = '\0';
- return str_new2(buf);
+ return str_taint(str_new2(buf));
}
static int
@@ -1252,7 +1360,7 @@ file_s_basename(argc, argv)
f = rmext(p, ext->ptr);
if (f) return str_new(p, f);
}
- return str_new2(p);
+ return str_taint(str_new2(p));
}
static VALUE
@@ -1260,18 +1368,16 @@ file_s_dirname(obj, fname)
VALUE obj;
struct RString *fname;
{
- char *p;
+ UCHAR *p;
Check_Type(fname, T_STRING);
p = strrchr(fname->ptr, '/');
if (!p) {
- return str_new(0,0);
+ return str_new2(".");
}
- return str_new(fname->ptr, p - fname->ptr);
+ return str_taint(str_new(fname->ptr, p - fname->ptr));
}
-static VALUE separator;
-
static VALUE
file_s_split(obj, path)
VALUE obj, path;
@@ -1279,12 +1385,21 @@ file_s_split(obj, path)
return assoc_new(file_s_dirname(Qnil, path), file_s_basename(1,&path));
}
+static VALUE separator;
+
+static VALUE
+file_s_join(obj, args)
+ VALUE obj, args;
+{
+ return ary_join(args, separator);
+}
+
static VALUE
file_s_truncate(obj, path, len)
VALUE obj, len;
struct RString *path;
{
- Check_Type(path, T_STRING);
+ Check_SafeStr(path);
#ifdef HAVE_TRUNCATE
if (truncate(path->ptr, NUM2INT(len)) < 0)
@@ -1324,6 +1439,7 @@ file_truncate(obj, len)
GetOpenFile(obj, fptr);
+ rb_secure(2);
if (!(fptr->mode & FMODE_WRITABLE)) {
Fail("not opened for writing");
}
@@ -1342,30 +1458,18 @@ file_truncate(obj, len)
}
static VALUE
-file_fcntl(obj, req, arg)
- VALUE obj, req;
- struct RString *arg;
-{
-#ifdef HAVE_FCNTL
- io_ctl(obj, req, arg, 0);
-#else
- rb_notimplement();
-#endif
- return obj;
-}
-
-static VALUE
file_flock(obj, operation)
VALUE obj;
VALUE operation;
{
- OpenFile *fptr;
+ OpenFile *fptr;
GetOpenFile(obj, fptr);
+ rb_secure(2);
if (flock(fileno(fptr->f), NUM2INT(operation)) < 0) {
#ifdef EWOULDBLOCK
- if (errno = EWOULDBLOCK) {
+ if (errno == EWOULDBLOCK) {
return FALSE;
}
#endif
@@ -1384,7 +1488,7 @@ test_check(n, argc, argv)
n+=1;
if (n < argc) ArgError("Wrong # of arguments(%d for %d)", argc, n);
for (i=1; i<n; i++) {
- Check_Type(argv[i], T_STRING);
+ Check_SafeStr(argv[i]);
}
}
@@ -1398,8 +1502,13 @@ f_test(argc, argv)
int cmd;
if (argc == 0) ArgError("Wrong # of arguments");
- Need_Fixnum(argv[0]);
- cmd = FIX2INT(argv[0]);
+ if (TYPE(argv[0]) == T_STRING && RSTRING(argv[0])->len == 1) {
+ cmd = RSTRING(argv[0])->ptr[0];
+ }
+ else {
+ cmd = NUM2INT(argv[0]);
+ }
+ if (cmd == 0) return FALSE;
if (strchr("bcdefgGkloOprRsSuwWxXz", cmd)) {
CHECK(1);
switch (cmd) {
@@ -1519,7 +1628,7 @@ f_test(argc, argv)
return FALSE;
}
-extern VALUE cKernel;
+extern VALUE mKernel;
void
Init_File()
@@ -1537,7 +1646,7 @@ Init_File()
rb_define_module_function(mFileTest, "executable_real?", test_X, 1);
rb_define_module_function(mFileTest, "file?", test_f, 1);
rb_define_module_function(mFileTest, "zero?", test_z, 1);
- rb_define_module_function(mFileTest, "size", test_s, 1);
+ rb_define_module_function(mFileTest, "size?", test_s, 1);
rb_define_module_function(mFileTest, "owned?", test_owned, 1);
rb_define_module_function(mFileTest, "grpowned?", test_grpowned, 1);
@@ -1555,15 +1664,17 @@ Init_File()
cFile = rb_define_class("File", cIO);
rb_extend_object(cFile, CLASS_OF(mFileTest));
+ rb_define_singleton_method(cFile, "new", file_s_open, -1);
rb_define_singleton_method(cFile, "open", file_s_open, -1);
rb_define_singleton_method(cFile, "stat", file_s_stat, 1);
rb_define_singleton_method(cFile, "lstat", file_s_lstat, 1);
- rb_define_singleton_method(cFile, "ftype", file_s_type, 1);
+ rb_define_singleton_method(cFile, "ftype", file_s_ftype, 1);
rb_define_singleton_method(cFile, "atime", file_s_atime, 1);
rb_define_singleton_method(cFile, "mtime", file_s_mtime, 1);
rb_define_singleton_method(cFile, "ctime", file_s_ctime, 1);
+ rb_define_singleton_method(cFile, "size", file_s_size, 1);
rb_define_singleton_method(cFile, "utime", file_s_utime, -1);
rb_define_singleton_method(cFile, "chmod", file_s_chmod, -1);
@@ -1582,9 +1693,12 @@ Init_File()
rb_define_singleton_method(cFile, "basename", file_s_basename, -1);
rb_define_singleton_method(cFile, "dirname", file_s_dirname, 1);
- separator = INT2FIX('/');
+ separator = str_new2("/");
rb_define_const(cFile, "Separator", separator);
rb_define_singleton_method(cFile, "split", file_s_split, 1);
+ rb_define_singleton_method(cFile, "join", file_s_join, -2);
+
+ rb_define_method(cFile, "reopen", file_reopen, -1);
rb_define_method(cFile, "stat", file_stat, 0);
rb_define_method(cFile, "lstat", file_lstat, 0);
@@ -1606,10 +1720,9 @@ Init_File()
rb_define_method(cFile, "rewind", file_rewind, 0);
rb_define_method(cFile, "isatty", file_isatty, 0);
rb_define_method(cFile, "tty?", file_isatty, 0);
- rb_define_method(cFile, "eof", file_eof, 0);
+ rb_define_method(cFile, "eof", file_eof, 0);
rb_define_method(cFile, "eof?", file_eof, 0);
- rb_define_method(cIO, "fcntl", file_fcntl, 2);
rb_define_method(cFile, "flock", file_flock, 1);
# ifndef LOCK_SH
@@ -1632,7 +1745,7 @@ Init_File()
rb_define_method(cFile, "path", file_path, 0);
- rb_define_method(cKernel, "test", f_test, -1);
+ rb_define_global_function("test", f_test, -1);
sStat = struct_define("Stat", "dev", "ino", "mode",
"nlink", "uid", "gid", "rdev",
diff --git a/gc.c b/gc.c
index 21d09809be..f69f4741f3 100644
--- a/gc.c
+++ b/gc.c
@@ -19,19 +19,34 @@
#include <stdio.h>
#include <setjmp.h>
+#ifndef setjmp
+#ifdef HAVE__SETJMP
+#define setjmp(env) _setjmp(env)
+#define longjmp(env,val) _longjmp(env,val)
+#endif
+#endif
+
#ifdef _AIX
#pragma alloca
#endif
-void *malloc();
-void *calloc();
-void *realloc();
#ifdef C_ALLOCA
void *alloca();
#endif
void gc();
void gc_mark();
+static void run_final();
+
+#ifndef GC_MALLOC_LIMIT
+#if defined(MSDOS) || defined(__human68k__)
+#define GC_MALLOC_LIMIT 200000
+#else
+#define GC_MALLOC_LIMIT 400000
+#endif
+#endif
+
+static unsigned long malloc_memories = 0;
void *
xmalloc(size)
@@ -40,6 +55,10 @@ xmalloc(size)
void *mem;
if (size == 0) size = 1;
+ malloc_memories += size;
+ if (malloc_memories > GC_MALLOC_LIMIT) {
+ gc();
+ }
mem = malloc(size);
if (!mem) {
gc();
@@ -112,6 +131,7 @@ Paradigm Associates Inc Phone: 617-492-6079
Cambridge, MA 02138
*/
+extern int rb_in_compile;
static int dont_gc;
VALUE
@@ -196,7 +216,7 @@ add_heap()
if (heaps_used == heaps_length) {
/* Realloc heaps */
heaps_length += HEAPS_INCREMENT;
- heaps = (heaps_used)?
+ heaps = (heaps_used>0)?
(RVALUE**)realloc(heaps, heaps_length*sizeof(RVALUE)):
(RVALUE**)malloc(heaps_length*sizeof(RVALUE));
if (heaps == 0) Fatal("can't alloc memory");
@@ -217,14 +237,13 @@ add_heap()
}
struct RBasic *
-newobj()
+rb_newobj()
{
struct RBasic *obj;
if (freelist) {
retry:
obj = (struct RBasic*)freelist;
freelist = freelist->as.free.next;
- memset(obj, 0, sizeof(RVALUE));
return obj;
}
if (dont_gc) add_heap();
@@ -240,7 +259,7 @@ data_object_alloc(class, datap, dmark, dfree)
void (*dfree)();
void (*dmark)();
{
- struct RData *data = (struct RData*)newobj();
+ struct RData *data = (struct RData*)rb_newobj();
OBJSETUP(data, class, T_DATA);
data->data = datap;
@@ -260,8 +279,7 @@ looks_pointerp(p)
register RVALUE *heap_org;
register long i;
- if (p < lomem) return FALSE;
- if (p > himem) return FALSE;
+ if (p < lomem || p > himem) return FALSE;
/* check if p looks like a pointer */
for (i=0; i < heaps_used; i++) {
@@ -311,10 +329,11 @@ mark_entry(key, value)
return ST_CONTINUE;
}
-static int
+static void
mark_tbl(tbl)
st_table *tbl;
{
+ if (!tbl) return;
st_foreach(tbl, mark_entry, 0);
}
@@ -328,10 +347,11 @@ mark_hashentry(key, value)
return ST_CONTINUE;
}
-static int
+static void
mark_hash(tbl)
st_table *tbl;
{
+ if (!tbl) return;
st_foreach(tbl, mark_hashentry, 0);
}
@@ -350,7 +370,7 @@ gc_mark(obj)
{
Top:
if (FIXNUM_P(obj)) return; /* fixnum not marked */
- if (rb_special_const_p(obj)) return; /* special const not marked */
+ if (rb_special_const_p((VALUE)obj)) return; /* special const not marked */
if (obj->as.basic.flags == 0) return; /* free cell */
if (obj->as.basic.flags & FL_MARK) return; /* marked */
@@ -363,15 +383,79 @@ gc_mark(obj)
break;
case T_NODE:
- if (looks_pointerp(obj->as.node.u1.node)) {
- gc_mark(obj->as.node.u1.node);
- }
- if (looks_pointerp(obj->as.node.u2.node)) {
+ switch (nd_type(obj)) {
+ case NODE_IF: /* 1,2,3 */
+ case NODE_FOR:
+ case NODE_ITER:
gc_mark(obj->as.node.u2.node);
- }
- if (looks_pointerp(obj->as.node.u3.node)) {
+ /* fall through */
+ case NODE_BLOCK: /* 1,3 */
+ case NODE_ARRAY:
+ case NODE_DSTR:
+ case NODE_DXSTR:
+ case NODE_EVSTR:
+ case NODE_DREGX:
+ case NODE_DREGX_ONCE:
+ case NODE_FBODY:
+ case NODE_CALL:
+ gc_mark(obj->as.node.u1.node);
+ /* fall through */
+ case NODE_SUPER: /* 3 */
+ case NODE_FCALL:
+ case NODE_NEWLINE:
obj = (RVALUE*)obj->as.node.u3.node;
goto Top;
+
+ case NODE_WHILE: /* 1,2 */
+ case NODE_UNTIL:
+ gc_mark(obj->as.node.u1.node);
+ /* fall through */
+ case NODE_METHOD: /* 2 */
+ case NODE_NOT:
+ obj = (RVALUE*)obj->as.node.u2.node;
+ goto Top;
+
+ case NODE_HASH: /* 1 */
+ case NODE_LIT:
+ case NODE_STR:
+ case NODE_XSTR:
+ case NODE_DEFINED:
+ obj = (RVALUE*)obj->as.node.u1.node;
+ goto Top;
+
+ case NODE_SCOPE: /* 2,3 */
+ gc_mark(obj->as.node.u3.node);
+ obj = (RVALUE*)obj->as.node.u2.node;
+ goto Top;
+
+ case NODE_ZARRAY: /* - */
+ case NODE_CFUNC:
+ case NODE_VCALL:
+ case NODE_GVAR:
+ case NODE_LVAR:
+ case NODE_DVAR:
+ case NODE_IVAR:
+ case NODE_CVAR:
+ case NODE_NTH_REF:
+ case NODE_BACK_REF:
+ case NODE_ALIAS:
+ case NODE_VALIAS:
+ case NODE_UNDEF:
+ case NODE_SELF:
+ case NODE_NIL:
+ break;
+
+ default:
+ if (looks_pointerp(obj->as.node.u1.node)) {
+ gc_mark(obj->as.node.u1.node);
+ }
+ if (looks_pointerp(obj->as.node.u2.node)) {
+ gc_mark(obj->as.node.u2.node);
+ }
+ if (looks_pointerp(obj->as.node.u3.node)) {
+ obj = (RVALUE*)obj->as.node.u3.node;
+ goto Top;
+ }
}
return; /* no need to mark class. */
}
@@ -380,7 +464,7 @@ gc_mark(obj)
switch (obj->as.basic.flags & T_MASK) {
case T_ICLASS:
gc_mark(obj->as.class.super);
- if (obj->as.class.iv_tbl) mark_tbl(obj->as.class.iv_tbl);
+ mark_tbl(obj->as.class.iv_tbl);
mark_tbl(obj->as.class.m_tbl);
break;
@@ -388,7 +472,7 @@ gc_mark(obj)
case T_MODULE:
gc_mark(obj->as.class.super);
mark_tbl(obj->as.class.m_tbl);
- if (obj->as.class.iv_tbl) mark_tbl(obj->as.class.iv_tbl);
+ mark_tbl(obj->as.class.iv_tbl);
break;
case T_ARRAY:
@@ -417,16 +501,22 @@ gc_mark(obj)
break;
case T_OBJECT:
- if (obj->as.object.iv_tbl) mark_tbl(obj->as.object.iv_tbl);
+ mark_tbl(obj->as.object.iv_tbl);
break;
case T_FILE:
- case T_MATCH:
case T_REGEXP:
case T_FLOAT:
case T_BIGNUM:
break;
+ case T_MATCH:
+ if (obj->as.match.str) {
+ obj = (RVALUE*)obj->as.match.str;
+ goto Top;
+ }
+ break;
+
case T_VARMAP:
gc_mark(obj->as.varmap.val);
obj = (RVALUE*)obj->as.varmap.next;
@@ -435,12 +525,12 @@ gc_mark(obj)
case T_SCOPE:
if (obj->as.scope.local_vars) {
- int n = obj->as.scope.local_tbl[0];
- VALUE *tbl = obj->as.scope.local_vars;
+ int n = obj->as.scope.local_tbl[0]+1;
+ VALUE *vars = &obj->as.scope.local_vars[-1];
while (n--) {
- gc_mark_maybe(*tbl);
- tbl++;
+ gc_mark_maybe(*vars);
+ vars++;
}
}
break;
@@ -456,7 +546,9 @@ gc_mark(obj)
break;
default:
- Bug("gc_mark(): unknown data type %d", obj->as.basic.flags & T_MASK);
+ Bug("gc_mark(): unknown data type 0x%x(0x%x) %s",
+ obj->as.basic.flags & T_MASK, obj,
+ looks_pointerp(obj)?"corrupted object":"non object");
}
}
@@ -467,12 +559,23 @@ static void obj_free();
static void
gc_sweep()
{
+ RVALUE *p, *pend;
int freed = 0;
int i;
+ if (rb_in_compile) {
+ for (i = 0; i < heaps_used; i++) {
+ p = heaps[i]; pend = p + HEAP_SLOTS;
+ while (p < pend) {
+ if (!(p->as.basic.flags&FL_MARK) && BUILTIN_TYPE(p) == T_NODE)
+ gc_mark(p);
+ p++;
+ }
+ }
+ }
+
freelist = 0;
for (i = 0; i < heaps_used; i++) {
- RVALUE *p, *pend;
RVALUE *nfreelist;
int n = 0;
@@ -499,6 +602,17 @@ gc_sweep()
}
}
+void
+gc_force_recycle(p)
+ RVALUE *p;
+{
+ p->as.free.flag = 0;
+ p->as.free.next = freelist;
+ freelist = p;
+}
+
+static int need_call_final = 0;
+
static void
obj_free(obj)
RVALUE *obj;
@@ -506,10 +620,15 @@ obj_free(obj)
switch (obj->as.basic.flags & T_MASK) {
case T_NIL:
case T_FIXNUM:
+ case T_TRUE:
+ case T_FALSE:
Bug("obj_free() called for broken object");
break;
}
+ if (need_call_final) {
+ run_final(obj);
+ }
switch (obj->as.basic.flags & T_MASK) {
case T_OBJECT:
if (obj->as.object.iv_tbl) st_free_table(obj->as.object.iv_tbl);
@@ -524,7 +643,7 @@ obj_free(obj)
if (!obj->as.string.orig) free(obj->as.string.ptr);
break;
case T_ARRAY:
- free(obj->as.array.ptr);
+ if (obj->as.array.ptr) free(obj->as.array.ptr);
break;
case T_HASH:
st_free_table(obj->as.hash.tbl);
@@ -534,13 +653,13 @@ obj_free(obj)
free(obj->as.regexp.str);
break;
case T_DATA:
- if (obj->as.data.dfree) (*obj->as.data.dfree)(DATA_PTR(obj));
- free(DATA_PTR(obj));
+ if (obj->as.data.dfree && DATA_PTR(obj))
+ (*obj->as.data.dfree)(DATA_PTR(obj));
+ if (DATA_PTR(obj)) free(DATA_PTR(obj));
break;
case T_MATCH:
re_free_registers(obj->as.match.regs);
free(obj->as.match.regs);
- if (obj->as.match.ptr) free(obj->as.match.ptr);
break;
case T_FILE:
io_fptr_finalize(obj->as.file.fptr);
@@ -552,8 +671,6 @@ obj_free(obj)
case T_FLOAT:
case T_VARMAP:
- case T_TRUE:
- case T_FALSE:
break;
case T_BIGNUM:
@@ -566,10 +683,13 @@ obj_free(obj)
return; /* no need to free iv_tbl */
case T_SCOPE:
- if (obj->as.scope.local_vars)
- free(obj->as.scope.local_vars);
- if (obj->as.scope.local_tbl)
- free(obj->as.scope.local_tbl);
+ if (obj->as.scope.local_vars) {
+ VALUE *vars = obj->as.scope.local_vars-1;
+ if (vars[0] == 0)
+ free(obj->as.scope.local_tbl);
+ if (obj->as.scope.flag&SCOPE_MALLOC)
+ free(vars);
+ }
break;
case T_STRUCT:
@@ -592,8 +712,44 @@ gc_mark_frame(frame)
gc_mark_maybe(*tbl);
tbl++;
}
+ gc_mark(frame->cbase);
}
+#ifdef __GNUC__
+#if defined(__human68k__) || defined(DJGPP)
+#if defined(__human68k__)
+typedef unsigned long rb_jmp_buf[8];
+__asm__ (".even
+_rb_setjmp:
+ move.l 4(sp),a0
+ movem.l d3-d7/a3-a5,(a0)
+ moveq.l #0,d0
+ rts");
+#else
+#if defined(DJGPP)
+typedef unsigned long rb_jmp_buf[6];
+__asm__ (".align 4
+_rb_setjmp:
+ pushl %ebp
+ movl %esp,%ebp
+ movl 8(%ebp),%ebp
+ movl %eax,(%ebp)
+ movl %ebx,4(%ebp)
+ movl %ecx,8(%ebp)
+ movl %edx,12(%ebp)
+ movl %esi,16(%ebp)
+ movl %edi,20(%ebp)
+ popl %ebp
+ xorl %eax,%eax
+ ret");
+#endif
+#endif
+int rb_setjmp (rb_jmp_buf);
+#define jmp_buf rb_jmp_buf
+#define setjmp rb_setjmp
+#endif /* __human68k__ or DJGPP */
+#endif /* __GNUC__ */
+
void
gc()
{
@@ -605,6 +761,7 @@ gc()
if (dont_gc) return;
dont_gc++;
+ malloc_memories = 0;
#ifdef C_ALLOCA
alloca(0);
#endif
@@ -619,10 +776,13 @@ gc()
FLUSH_REGISTER_WINDOWS;
/* This assumes that all registers are saved into the jmp_buf */
setjmp(save_regs_gc_mark);
- gc_mark_locations((VALUE*)save_regs_gc_mark,
- (VALUE*)(((char*)save_regs_gc_mark)+sizeof(save_regs_gc_mark)));
- gc_mark_locations(gc_stack_start, (VALUE*) &stack_end);
-#ifdef THINK_C
+ mark_locations_array((VALUE*)&save_regs_gc_mark, sizeof(save_regs_gc_mark) / sizeof(VALUE *));
+ gc_mark_locations(gc_stack_start, (VALUE*)&stack_end);
+#if defined(THINK_C) || defined(__human68k__)
+#ifndef __human68k__
+ mark_locations_array((VALUE*)((char*)save_regs_gc_mark+2),
+ sizeof(save_regs_gc_mark) / sizeof(VALUE *));
+#endif
gc_mark_locations((VALUE*)((char*)gc_stack_start + 2),
(VALUE*)((char*)&stack_end + 2));
#endif
@@ -644,12 +804,24 @@ gc()
dont_gc--;
}
+static VALUE
+gc_method()
+{
+ gc();
+ return Qnil;
+}
+
void
init_stack()
{
+#ifdef __human68k__
+ extern void *_SEND;
+ gc_stack_start = _SEND;
+#else
VALUE start;
gc_stack_start = &start;
+#endif
}
void
@@ -660,8 +832,7 @@ init_heap()
}
static VALUE
-os_live_obj(obj)
- VALUE obj;
+os_live_obj()
{
int i;
int n = 0;
@@ -692,8 +863,8 @@ os_live_obj(obj)
}
static VALUE
-os_obj_of(obj, of)
- VALUE obj, of;
+os_obj_of(of)
+ VALUE of;
{
int i;
int n = 0;
@@ -725,6 +896,74 @@ os_obj_of(obj, of)
return INT2FIX(n);
}
+static VALUE
+os_each_obj(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ VALUE of;
+
+ if (rb_scan_args(argc, argv, "01", &of) == 0) {
+ return os_live_obj();
+ }
+ else {
+ return os_obj_of(of);
+ }
+}
+
+static VALUE finalizers;
+
+static VALUE
+add_final(os, proc)
+ VALUE os, proc;
+{
+ extern VALUE cProc;
+
+ if (!obj_is_kind_of(proc, cProc)) {
+ ArgError("wrong type argument %s (Proc required)",
+ rb_class2name(CLASS_OF(proc)));
+ }
+ ary_push(finalizers, proc);
+ return proc;
+}
+
+static VALUE
+rm_final(os, proc)
+ VALUE os, proc;
+{
+ ary_delete(finalizers, proc);
+ return proc;
+}
+
+static VALUE
+finals()
+{
+ return finalizers;
+}
+
+static VALUE
+call_final(os, obj)
+ VALUE os, obj;
+{
+ need_call_final = 1;
+ FL_SET(obj, FL_FINALIZE);
+ return obj;
+}
+
+static void
+run_final(obj)
+ VALUE obj;
+{
+ int i;
+
+ if (!FL_TEST(obj, FL_FINALIZE)) return;
+
+ obj |= FIXNUM_FLAG; /* make obj into id */
+ for (i=0; i<RARRAY(finalizers)->len; i++) {
+ rb_eval_cmd(RARRAY(finalizers)->ptr[i], obj);
+ }
+}
+
extern VALUE cModule;
void
@@ -733,13 +972,19 @@ Init_GC()
VALUE mObSpace;
mGC = rb_define_module("GC");
- rb_define_singleton_method(mGC, "start", gc, 0);
+ rb_define_singleton_method(mGC, "start", gc_method, 0);
rb_define_singleton_method(mGC, "enable", gc_s_enable, 0);
rb_define_singleton_method(mGC, "disable", gc_s_disable, 0);
- rb_define_method(mGC, "garbage_collect", gc, 0);
+ rb_define_method(mGC, "garbage_collect", gc_method, 0);
mObSpace = rb_define_module("ObjectSpace");
- rb_define_module_function(mObSpace, "each_live_object", os_live_obj, 0);
- rb_define_module_function(mObSpace, "each_object_of", os_obj_of, 1);
+ rb_define_module_function(mObSpace, "each_object", os_each_obj, -1);
rb_define_module_function(mObSpace, "garbage_collect", gc, 0);
+ rb_define_module_function(mObSpace, "add_finalizer", add_final, 1);
+ rb_define_module_function(mObSpace, "remove_finalizer", rm_final, 1);
+ rb_define_module_function(mObSpace, "finalizers", finals, 0);
+ rb_define_module_function(mObSpace, "call_finalizer", call_final, 1);
+
+ rb_global_variable(&finalizers);
+ finalizers = ary_new();
}
diff --git a/glob.c b/glob.c
index 7599c1ca72..6c355ad260 100644
--- a/glob.c
+++ b/glob.c
@@ -44,7 +44,11 @@
# include "ndir.h"
# endif /* !Xenix */
# else /* !USG */
+# if defined(NT)
+# include "missing/dir.h"
+# else
# include <sys/dir.h>
+# endif /* !NT */
# endif /* !USG */
#endif /* !HAVE_DIRENT_H */
@@ -68,7 +72,9 @@
# include <strings.h>
#endif /* !HAVE_STRING_H */
+#ifndef bcopy
# define bcopy(s, d, n) (memcpy ((d), (s), (n)))
+#endif
#ifdef _AIX
#pragma alloca
diff --git a/hash.c b/hash.c
index c6af916559..0ced1d5a51 100644
--- a/hash.c
+++ b/hash.c
@@ -6,12 +6,13 @@
$Date: 1996/12/25 10:42:26 $
created at: Mon Nov 22 18:51:18 JST 1993
- Copyright (C) 1993-1996 Yukihiro Matsumoto
+ Copyright (C) 1993-1997 Yukihiro Matsumoto
************************************************/
#include "ruby.h"
#include "st.h"
+#include "sig.h"
#ifdef HAVE_STRING_H
# include <string.h>
@@ -19,31 +20,44 @@
char *strchr();
#endif
+#define HASH_DELETED 0x1
+#define HASH_REHASHED 0x2
+
+#ifndef NT
char *getenv();
+#endif
VALUE cHash;
static VALUE envtbl;
static ID hash;
-VALUE f_getenv(), f_setenv();
+
+VALUE
+rb_hash(obj)
+ VALUE obj;
+{
+ return rb_funcall(obj, hash, 0);
+}
static int
-rb_cmp(a, b)
+any_cmp(a, b)
VALUE a, b;
{
if (FIXNUM_P(a)) {
if (FIXNUM_P(b)) return a != b;
}
-
- if (TYPE(a) == T_STRING) {
+ else if (TYPE(a) == T_STRING) {
if (TYPE(b) == T_STRING) return str_cmp(a, b);
}
- return !rb_eql(a, b);
+ DEFER_INTS;
+ a = !rb_eql(a, b);
+ ENABLE_INTS;
+ return a;
}
static int
-rb_hash(a, mod)
+any_hash(a, mod)
VALUE a;
int mod;
{
@@ -59,17 +73,85 @@ rb_hash(a, mod)
break;
default:
+ DEFER_INTS;
hval = rb_funcall(a, hash, 0);
+ if (!FIXNUM_P(hval)) {
+ hval = rb_funcall(hval, '%', 1, INT2FIX(65439));
+ }
+ ENABLE_INTS;
hval = FIX2INT(hval);
}
return hval % mod;
}
static struct st_hash_type objhash = {
- rb_cmp,
- rb_hash,
+ any_cmp,
+ any_hash,
+};
+
+struct hash_foreach_arg {
+ struct RHash *hash;
+ enum st_retval (*func)();
+ char *arg;
};
+static int
+hash_foreach_iter(key, value, arg)
+ VALUE key, value;
+ struct hash_foreach_arg *arg;
+{
+ int status;
+
+ if (key == Qnil) return ST_CONTINUE;
+ status = (*arg->func)(key, value, arg->arg);
+ if (arg->hash->status & HASH_REHASHED) return ST_STOP;
+ return status;
+}
+
+static int
+hash_foreach_call(arg)
+ struct hash_foreach_arg *arg;
+{
+ return st_foreach(arg->hash->tbl, hash_foreach_iter, arg);
+}
+
+static int
+hash_delete_nil(key, value)
+ VALUE key, value;
+{
+ if (key == Qnil) return ST_DELETE;
+ return ST_CONTINUE;
+}
+
+static void
+hash_foreach_ensure(hash)
+ struct RHash *hash;
+{
+ hash->iter_lev--;
+
+ if (hash->iter_lev == 0) {
+ if (hash->status & HASH_DELETED) {
+ st_foreach(hash->tbl, hash_delete_nil, 0);
+ }
+ hash->status = 0;
+ }
+}
+
+static int
+hash_foreach(hash, func, farg)
+ struct RHash *hash;
+ enum st_retval (*func)();
+ char *farg;
+{
+ struct hash_foreach_arg arg;
+
+ hash->iter_lev++;
+ arg.hash = hash;
+ arg.func = func;
+ arg.arg = farg;
+ return rb_ensure(hash_foreach_call, &arg, hash_foreach_ensure, hash);
+}
+
static VALUE
hash_s_new(argc, argv, class)
int argc;
@@ -86,13 +168,14 @@ hash_s_new(argc, argv, class)
if (NIL_P(sz)) size = 0;
else size = NUM2INT(sz);
+ hash->iter_lev = 0;
+ hash->status = 0;
+ hash->tbl = 0; /* avoid GC crashing */
hash->tbl = st_init_table_with_size(&objhash, size);
return (VALUE)hash;
}
-static VALUE hash_clone();
-
VALUE
hash_new2(class)
VALUE class;
@@ -120,8 +203,11 @@ hash_s_create(argc, argv, class)
else {
NEWOBJ(hash, struct RHash);
OBJSETUP(hash, class, T_HASH);
+
+ hash->iter_lev = 0;
+ hash->status = 0;
+ hash->tbl = 0; /* avoid GC crashing */
hash->tbl = (st_table*)st_copy(RHASH(argv[0])->tbl);
-
return (VALUE)hash;
}
}
@@ -145,11 +231,39 @@ hash_clone(hash)
NEWOBJ(hash2, struct RHash);
CLONESETUP(hash2, hash);
+ hash2->iter_lev = 0;
+ hash2->status = 0;
+ hash2->tbl = 0; /* avoid GC crashing */
hash2->tbl = (st_table*)st_copy(hash->tbl);
return (VALUE)hash2;
}
+static int
+hash_rehash_i(key, value, tbl)
+ VALUE key, value;
+ st_table *tbl;
+{
+ if (key != Qnil) {
+ st_insert(tbl, key, value);
+ }
+ return ST_CONTINUE;
+}
+
+static VALUE
+hash_rehash(hash)
+ struct RHash *hash;
+{
+ st_table *tbl = st_init_table_with_size(&objhash, hash->tbl->num_entries);
+
+ st_foreach(hash->tbl, hash_rehash_i, tbl);
+ st_free_table(hash->tbl);
+ hash->tbl = tbl;
+ if (hash->iter_lev > 0) hash->status |= HASH_REHASHED;
+
+ return (VALUE)hash;
+}
+
VALUE
hash_aref(hash, key)
struct RHash *hash;
@@ -164,23 +278,17 @@ hash_aref(hash, key)
}
static VALUE
-hash_indexes(hash, args)
+hash_indexes(argc, argv, hash)
+ int argc;
+ VALUE *argv;
struct RHash *hash;
- struct RArray *args;
{
- VALUE *p, *pend;
struct RArray *indexes;
- int i = 0;
-
- if (!args || NIL_P(args)) {
- return ary_new2(0);
- }
-
- indexes = (struct RArray*)ary_new2(args->len);
+ int i;
- p = args->ptr; pend = p + args->len;
- while (p < pend) {
- indexes->ptr[i++] = hash_aref(hash, *p++);
+ indexes = (struct RArray*)ary_new2(argc);
+ for (i=0; i<argc; i++) {
+ indexes->ptr[i] = hash_aref(hash, argv[i]);
}
indexes->len = i;
return (VALUE)indexes;
@@ -193,9 +301,12 @@ hash_delete(hash, key)
{
VALUE val;
- if (st_delete(hash->tbl, &key, &val))
+ rb_secure(5);
+ if (hash->iter_lev > 0 && st_delete_safe(hash->tbl, &key, &val, Qnil))
+ return val;
+ else if (st_delete(hash->tbl, &key, &val))
return val;
- if (iterator_p()) rb_yield(Qnil);
+ if (iterator_p()) rb_yield(key);
return Qnil;
}
@@ -205,11 +316,12 @@ struct shift_var {
VALUE val;
};
-static
+static int
shift_i(key, value, var)
VALUE key, value;
struct shift_var *var;
{
+ if (key == Qnil) return ST_CONTINUE;
if (var->stop) return ST_STOP;
var->stop = 1;
var->key = key;
@@ -223,6 +335,7 @@ hash_shift(hash)
{
struct shift_var var;
+ rb_secure(5);
var.stop = 0;
st_foreach(hash->tbl, shift_i, &var);
@@ -234,6 +347,7 @@ static int
delete_if_i(key, value)
VALUE key, value;
{
+ if (key == Qnil) return ST_CONTINUE;
if (rb_yield(assoc_new(key, value)))
return ST_DELETE;
return ST_CONTINUE;
@@ -243,7 +357,8 @@ static VALUE
hash_delete_if(hash)
struct RHash *hash;
{
- st_foreach(hash->tbl, delete_if_i, 0);
+ rb_secure(5);
+ hash_foreach(hash, delete_if_i, 0);
return (VALUE)hash;
}
@@ -259,6 +374,7 @@ static VALUE
hash_clear(hash)
struct RHash *hash;
{
+ rb_secure(5);
st_foreach(hash->tbl, clear_i);
return (VALUE)hash;
@@ -269,6 +385,7 @@ hash_aset(hash, key, val)
struct RHash *hash;
VALUE key, val;
{
+ rb_secure(5);
if (NIL_P(val)) {
hash_delete(hash, key);
return Qnil;
@@ -300,6 +417,7 @@ static int
each_value_i(key, value)
VALUE key, value;
{
+ if (key == Qnil) return ST_CONTINUE;
rb_yield(value);
return ST_CONTINUE;
}
@@ -308,7 +426,7 @@ static VALUE
hash_each_value(hash)
struct RHash *hash;
{
- st_foreach(hash->tbl, each_value_i);
+ hash_foreach(hash, each_value_i);
return (VALUE)hash;
}
@@ -316,6 +434,7 @@ static int
each_key_i(key, value)
VALUE key, value;
{
+ if (key == Qnil) return ST_CONTINUE;
rb_yield(key);
return ST_CONTINUE;
}
@@ -324,7 +443,7 @@ static VALUE
hash_each_key(hash)
struct RHash *hash;
{
- st_foreach(hash->tbl, each_key_i);
+ hash_foreach(hash, each_key_i);
return (VALUE)hash;
}
@@ -332,6 +451,7 @@ static int
each_pair_i(key, value)
VALUE key, value;
{
+ if (key == Qnil) return ST_CONTINUE;
rb_yield(assoc_new(key, value));
return ST_CONTINUE;
}
@@ -340,7 +460,7 @@ static VALUE
hash_each_pair(hash)
struct RHash *hash;
{
- st_foreach(hash->tbl, each_pair_i);
+ hash_foreach(hash, each_pair_i);
return (VALUE)hash;
}
@@ -348,6 +468,7 @@ static int
to_a_i(key, value, ary)
VALUE key, value, ary;
{
+ if (key == Qnil) return ST_CONTINUE;
ary_push(ary, assoc_new(key, value));
return ST_CONTINUE;
}
@@ -371,6 +492,7 @@ inspect_i(key, value, str)
{
VALUE str2;
+ if (key == Qnil) return ST_CONTINUE;
if (str->len > 1) {
str_cat(str, ", ", 2);
}
@@ -407,6 +529,7 @@ static int
keys_i(key, value, ary)
VALUE key, value, ary;
{
+ if (key == Qnil) return ST_CONTINUE;
ary_push(ary, key);
return ST_CONTINUE;
}
@@ -427,6 +550,7 @@ static int
values_i(key, value, ary)
VALUE key, value, ary;
{
+ if (key == Qnil) return ST_CONTINUE;
ary_push(ary, value);
return ST_CONTINUE;
}
@@ -443,17 +567,6 @@ hash_values(hash)
return ary;
}
-static int
-hash_search_value(key, value, data)
- VALUE key, value, *data;
-{
- if (rb_equal(value, data[1])) {
- data[0] = TRUE;
- return ST_STOP;
- }
- return ST_CONTINUE;
-}
-
static VALUE
hash_has_key(hash, key)
struct RHash *hash;
@@ -465,6 +578,18 @@ hash_has_key(hash, key)
return FALSE;
}
+static int
+hash_search_value(key, value, data)
+ VALUE key, value, *data;
+{
+ if (key == Qnil) return ST_CONTINUE;
+ if (rb_equal(value, data[1])) {
+ data[0] = TRUE;
+ return ST_STOP;
+ }
+ return ST_CONTINUE;
+}
+
static VALUE
hash_has_value(hash, val)
struct RHash *hash;
@@ -490,6 +615,7 @@ equal_i(key, val1, data)
{
VALUE val2;
+ if (key == Qnil) return ST_CONTINUE;
if (!st_lookup(data->tbl, key, &val2)) {
data->result = FALSE;
return ST_STOP;
@@ -519,45 +645,30 @@ hash_equal(hash1, hash2)
}
static int
-hash_i(key, val, data)
- VALUE key, val;
- int *data;
+hash_invert_i(key, value, hash)
+ VALUE key, value;
+ struct RHash *hash;
{
- *data ^= rb_funcall(key, hash, 0);
- *data ^= rb_funcall(val, hash, 0);
+ if (key == Qnil) return ST_CONTINUE;
+ hash_aset(hash, value, key);
return ST_CONTINUE;
}
static VALUE
-hash_hash(hash)
+hash_invert(hash)
struct RHash *hash;
{
- int h;
+ VALUE h = hash_new();
- st_foreach(hash->tbl, hash_i, &h);
- return INT2FIX(h);
+ st_foreach(hash->tbl, hash_invert_i, h);
+ return h;
}
-extern char **environ;
-
-static VALUE
-env_each(hash)
- VALUE hash;
-{
- char **env;
-
- env = environ;
- while (*env) {
- VALUE var, val;
- char *s = strchr(*env, '=');
+int env_path_tainted = 0;
- var = str_new(*env, s-*env);
- val = str_new2(s+1);
- rb_yield(assoc_new(var, val));
- env++;
- }
- return hash;
-}
+#ifndef NT
+extern char **environ;
+#endif
static VALUE
env_delete(obj, name)
@@ -567,9 +678,11 @@ env_delete(obj, name)
int i, len;
char *nam, *val = 0;
+ rb_secure(4);
Check_Type(name, T_STRING);
nam = name->ptr;
len = strlen(nam);
+ if (strcmp(nam, "PATH") == 0) env_path_tainted = 0;
for(i=0; environ[i]; i++) {
if (strncmp(environ[i], nam, len) == 0 && environ[i][len] == '=') {
val = environ[i]+len+1;
@@ -586,7 +699,7 @@ env_delete(obj, name)
return Qnil;
}
-VALUE
+static VALUE
f_getenv(obj, name)
VALUE obj;
struct RString *name;
@@ -600,43 +713,222 @@ f_getenv(obj, name)
env = getenv(name->ptr);
if (env) {
- return str_new2(env);
+ if (strcmp(name->ptr, "PATH") == 0 && !env_path_tainted)
+ return str_new2(env);
+ return str_taint(str_new2(env));
}
return Qnil;
}
-VALUE
+static VALUE
f_setenv(obj, name, value)
VALUE obj;
struct RString *name, *value;
{
- Check_Type(name, T_STRING);
+ if (rb_safe_level() >= 4) {
+ extern VALUE eSecurityError;
+ Raise(eSecurityError, "cannot change environment variable");
+ }
+
+ Check_SafeStr(name);
if (NIL_P(value)) {
env_delete(obj, name);
return Qnil;
}
- Check_Type(value, T_STRING);
-
+ Check_SafeStr(value);
if (strlen(name->ptr) != name->len)
ArgError("Bad environment name");
if (strlen(value->ptr) != value->len)
ArgError("Bad environment value");
setenv(name->ptr, value->ptr, 1);
+ if (strcmp(name->ptr, "PATH") == 0) env_path_tainted = 0;
return TRUE;
}
static VALUE
+env_keys()
+{
+ char **env;
+ VALUE ary = ary_new();
+
+ env = environ;
+ while (*env) {
+ char *s = strchr(*env, '=');
+ ary_push(ary, str_taint(str_new(*env, s-*env)));
+ env++;
+ }
+ return ary;
+}
+
+static VALUE
+env_each_key(hash)
+ VALUE hash;
+{
+ return ary_each(env_keys());
+}
+
+static VALUE
+env_values()
+{
+ char **env;
+ VALUE ary = ary_new();
+
+ env = environ;
+ while (*env) {
+ char *s = strchr(*env, '=');
+ ary_push(ary, str_taint(str_new2(s+1)));
+ env++;
+ }
+ return ary;
+}
+
+static VALUE
+env_each_value(hash)
+ VALUE hash;
+{
+ return ary_each(env_values());
+}
+
+static VALUE
+env_each(hash)
+ VALUE hash;
+{
+ VALUE ary = env_keys();
+ VALUE *ptr = RARRAY(ary)->ptr;
+ int len = RARRAY(ary)->len;
+
+ while (len--) {
+ VALUE val = f_getenv(Qnil, *ptr);
+ if (!NIL_P(val)) {
+ rb_yield(assoc_new(*ptr, val));
+ }
+ ptr++;
+ }
+ return hash;
+}
+
+static VALUE
+env_delete_if()
+{
+ VALUE ary = env_keys();
+ VALUE *ptr = RARRAY(ary)->ptr;
+ int len = RARRAY(ary)->len;
+
+ while (len--) {
+ VALUE val = f_getenv(Qnil, *ptr);
+ if (!NIL_P(val)) {
+ if (RTEST(rb_yield(assoc_new(*ptr, val)))) {
+ env_delete(Qnil, *ptr);
+ }
+ }
+ ptr++;
+ }
+ return envtbl;
+}
+
+static VALUE
env_to_s()
{
return str_new2("ENV");
}
+static VALUE
+env_to_a()
+{
+ char **env;
+ VALUE ary = ary_new();
+
+ env = environ;
+ while (*env) {
+ char *s = strchr(*env, '=');
+ ary_push(ary, assoc_new(str_taint(str_new(*env, s-*env)),
+ str_taint(str_new2(s+1))));
+ env++;
+ }
+ return ary;
+}
+
+static VALUE
+env_none()
+{
+ return Qnil;
+}
+
+static VALUE
+env_size()
+{
+ int i;
+
+ for(i=0; environ[i]; i++)
+ ;
+ return INT2FIX(i);
+}
+
+static VALUE
+env_empty_p()
+{
+ if (environ[0] == 0) return TRUE;
+ return FALSE;
+}
+
+static VALUE
+env_has_key(env, key)
+ VALUE env, key;
+{
+ if (TYPE(key) != T_STRING) return FALSE;
+ if (getenv(RSTRING(key)->ptr)) return TRUE;
+ return FALSE;
+}
+
+static VALUE
+env_has_value(dmy, value)
+ VALUE dmy, value;
+{
+ char **env;
+ VALUE ary;
+
+ if (TYPE(value) != T_STRING) return FALSE;
+ ary = ary_new();
+ env = environ;
+ while (*env) {
+ char *s = strchr(*env, '=')+1;
+ int len = strlen(s);
+ if (strncmp(s, RSTRING(value)->ptr, len) == 0) return TRUE;
+ env++;
+ }
+ return FALSE;
+}
+
+static VALUE
+env_indexes(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ int i;
+ VALUE indexes = ary_new2(argc);
+
+ for (i=0;i<argc;i++) {
+ char *v = 0;
+ if (TYPE(argv[i]) == T_STRING) {
+ v = getenv(RSTRING(argv[i])->ptr);
+ }
+ if (v) {
+ RARRAY(indexes)->ptr[i] = str_new2(v);
+ }
+ else {
+ RARRAY(indexes)->ptr[i] = Qnil;
+ }
+ RARRAY(indexes)->len = i+1;
+ }
+
+ return indexes;
+}
+
void
Init_Hash()
{
- extern VALUE cKernel;
extern VALUE mEnumerable;
hash = rb_intern("hash");
@@ -649,16 +941,16 @@ Init_Hash()
rb_define_singleton_method(cHash, "[]", hash_s_create, -1);
rb_define_method(cHash,"clone", hash_clone, 0);
+ rb_define_method(cHash,"rehash", hash_rehash, 0);
rb_define_method(cHash,"to_a", hash_to_a, 0);
rb_define_method(cHash,"to_s", hash_to_s, 0);
rb_define_method(cHash,"inspect", hash_inspect, 0);
rb_define_method(cHash,"==", hash_equal, 1);
- rb_define_method(cHash,"hash", hash_hash, 0);
rb_define_method(cHash,"[]", hash_aref, 1);
rb_define_method(cHash,"[]=", hash_aset, 2);
- rb_define_method(cHash,"indexes", hash_indexes, -2);
+ rb_define_method(cHash,"indexes", hash_indexes, -1);
rb_define_method(cHash,"length", hash_length, 0);
rb_define_alias(cHash, "size", "length");
rb_define_method(cHash,"empty?", hash_empty_p, 0);
@@ -675,6 +967,7 @@ Init_Hash()
rb_define_method(cHash,"delete", hash_delete, 1);
rb_define_method(cHash,"delete_if", hash_delete_if, 0);
rb_define_method(cHash,"clear", hash_clear, 0);
+ rb_define_method(cHash,"invert", hash_invert, 0);
rb_define_method(cHash,"include?", hash_has_key, 1);
rb_define_method(cHash,"has_key?", hash_has_key, 1);
@@ -688,9 +981,24 @@ Init_Hash()
rb_define_singleton_method(envtbl,"[]", f_getenv, 1);
rb_define_singleton_method(envtbl,"[]=", f_setenv, 2);
rb_define_singleton_method(envtbl,"each", env_each, 0);
+ rb_define_singleton_method(envtbl,"each_pair", env_each, 0);
+ rb_define_singleton_method(envtbl,"each_key", env_each_key, 0);
+ rb_define_singleton_method(envtbl,"each_value", env_each_value, 0);
rb_define_singleton_method(envtbl,"delete", env_delete, 1);
+ rb_define_singleton_method(envtbl,"delete_if", env_delete_if, 0);
rb_define_singleton_method(envtbl,"to_s", env_to_s, 0);
+ rb_define_singleton_method(envtbl,"rehash", env_none, 0);
+ rb_define_singleton_method(envtbl,"to_a", env_to_a, 0);
+ rb_define_singleton_method(envtbl,"indexes", env_indexes, -1);
+ rb_define_singleton_method(envtbl,"length", env_size, 0);
+ rb_define_singleton_method(envtbl,"empty?", env_empty_p, 0);
+ rb_define_singleton_method(envtbl,"keys", env_keys, 0);
+ rb_define_singleton_method(envtbl,"values", env_values, 0);
+ rb_define_singleton_method(envtbl,"include?", env_has_key, 1);
+ rb_define_singleton_method(envtbl,"has_key?", env_has_key, 1);
+ rb_define_singleton_method(envtbl,"has_value?", env_has_value, 1);
+ rb_define_singleton_method(envtbl,"key?", env_has_key, 1);
+ rb_define_singleton_method(envtbl,"value?", env_has_value, 1);
- rb_define_readonly_variable("$ENV", &envtbl);
rb_define_global_const("ENV", envtbl);
}
diff --git a/inits.c b/inits.c
index e3456814e8..b8fcb0f826 100644
--- a/inits.c
+++ b/inits.c
@@ -21,7 +21,6 @@ rb_call_inits()
#ifdef THREAD
Init_Thread();
#endif
- Init_GC();
Init_eval();
Init_Comparable();
Init_Enumerable();
@@ -44,6 +43,6 @@ rb_call_inits()
Init_load();
Init_Proc();
Init_Math();
- Init_ext();
+ Init_GC();
Init_version();
}
diff --git a/io.c b/io.c
index 7c0fbd8d2b..8d3fb7b879 100644
--- a/io.c
+++ b/io.c
@@ -16,28 +16,39 @@
#include <errno.h>
#include <sys/types.h>
-#ifndef DJGPP
+#if !defined(DJGPP) && !defined(NT) && !defined(__human68k__)
#include <sys/ioctl.h>
#endif
+#if defined(HAVE_FCNTL)
+#include <fcntl.h>
+#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#else
+#ifndef NT
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* and microseconds */
};
#endif
+#endif
#ifdef HAVE_VFORK_H
#include <vfork.h>
#endif
#include <sys/stat.h>
-#ifdef DJGPP
+#if defined(DJGPP) || defined(__CYGWIN32__) || defined(NT) || defined(__human68k__)
#include <fcntl.h>
#endif
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#else
+# define NOFILE 64
+#endif
+
VALUE rb_ad_string();
VALUE cIO;
@@ -53,7 +64,7 @@ VALUE RS_default;
static VALUE argf;
-ID id_write, id_fd, id_print_on;
+ID id_write;
VALUE lastline_get();
void lastline_set();
@@ -116,11 +127,6 @@ closed()
Raise(eIOError, "closed stream");
}
-void
-io_wrong_type()
-{
-}
-
/* writing functions */
VALUE
io_write(io, str)
@@ -129,23 +135,40 @@ io_write(io, str)
{
OpenFile *fptr;
FILE *f;
- VALUE out;
int n;
+ if (TYPE(str) != T_STRING)
+ str = (struct RString*)obj_as_string(str);
+ if (str->len == 0) return INT2FIX(0);
+
+ if (BUILTIN_TYPE(io) != T_FILE) {
+ return rb_funcall(io, id_write, 1, str);
+ }
+
+ rb_secure(4);
GetOpenFile(io, fptr);
io_writable(fptr);
- f = (fptr->f2) ? fptr->f2 : fptr->f;
+ f = GetWriteFile(fptr);
if (f == NULL) closed();
- if (TYPE(str) != T_STRING)
- str = (struct RString*)obj_as_string(str);
- if (str->len == 0) return INT2FIX(0);
-
+#ifdef __human68k__
+ {
+ register UCHAR *ptr = str->ptr;
+ n = (int) str->len;
+ while (--n >= 0)
+ if (fputc(*ptr++, f) == EOF)
+ rb_sys_fail(fptr->path);
+ n = ptr - str->ptr;
+ }
+ if (ferror(f))
+ rb_sys_fail(fptr->path);
+#else
n = fwrite(str->ptr, 1, str->len, f);
if (n == 0 || ferror(f)) {
rb_sys_fail(fptr->path);
}
+#endif
if (fptr->mode & FMODE_SYNC) {
fflush(f);
}
@@ -170,7 +193,7 @@ io_flush(io)
GetOpenFile(io, fptr);
io_writable(fptr);
- f = (fptr->f2) ? fptr->f2 : fptr->f;
+ f = GetWriteFile(fptr);
if (f == NULL) closed();
if (fflush(f) == EOF) rb_sys_fail(0);
@@ -247,7 +270,7 @@ read_all(port)
VALUE port;
{
OpenFile *fptr;
- VALUE str;
+ VALUE str = Qnil;
char buf[BUFSIZ];
int n;
@@ -255,7 +278,6 @@ read_all(port)
io_readable(fptr);
if (fptr->f == NULL) closed();
- str = str_new(0, 0);
for (;;) {
READ_CHECK(fptr->f);
TRAP_BEG;
@@ -263,9 +285,10 @@ read_all(port)
TRAP_END;
if (n == 0) break;
if (n < 0) rb_sys_fail(0);
- str_cat(str, buf, n);
+ if (NIL_P(str)) str = str_new(buf, n);
+ else str_cat(str, buf, n);
}
- return str;
+ return str_taint(str);
}
static VALUE
@@ -301,7 +324,7 @@ io_read(argc, argv, io)
RSTRING(str)->len = n;
RSTRING(str)->ptr[n] = '\0';
- return str;
+ return str_taint(str);
}
static VALUE lineno;
@@ -320,11 +343,10 @@ io_gets_method(argc, argv, io)
int rslen, rspara = 0;
VALUE rs;
- if (rb_scan_args(argc, argv, "01", &rs) == 1) {
- if (!NIL_P(rs)) Check_Type(rs, T_STRING);
- }
+ if (argc == 0) rs = RS;
else {
- rs = RS;
+ rb_scan_args(argc, argv, "1", &rs);
+ if (!NIL_P(rs)) Check_Type(rs, T_STRING);
}
GetOpenFile(io, fptr);
@@ -384,8 +406,11 @@ io_gets_method(argc, argv, io)
cnt = bp - buf;
}
else {
+ READ_CHECK(f);
+ TRAP_BEG;
cnt = fread(buf, 1, sizeof(buf), f);
- c = cnt ? buf[cnt - 1]: EOF;
+ TRAP_END;
+ c = cnt ? 0 : EOF;
}
if (c == EOF) {
@@ -429,7 +454,7 @@ io_gets_method(argc, argv, io)
}
lastline_set(str);
- return (VALUE)str;
+ return str_taint(str);
}
VALUE
@@ -454,6 +479,21 @@ io_readline(argc, argv, io)
}
static VALUE
+io_readlines(argc, argv, io)
+ int argc;
+ VALUE argv;
+ VALUE io;
+{
+ VALUE line, ary;
+
+ ary = ary_new();
+ while (!NIL_P(line = io_gets_method(argc, argv, io))) {
+ ary_push(ary, line);
+ }
+ return ary;
+}
+
+static VALUE
io_each_line(argc, argv, io)
int argc;
VALUE argv;
@@ -550,12 +590,10 @@ io_isatty(io)
{
OpenFile *fptr;
-#ifndef NT
GetOpenFile(io, fptr);
if (fptr->f == NULL) closed();
if (isatty(fileno(fptr->f)) == 0)
return FALSE;
-#endif
return TRUE;
}
@@ -623,12 +661,13 @@ io_syswrite(io, str)
FILE *f;
int n;
+ rb_secure(4);
if (TYPE(str) != T_STRING)
str = obj_as_string(str);
GetOpenFile(io, fptr);
io_writable(fptr);
- f = (fptr->f2) ? fptr->f2 : fptr->f;
+ f = GetWriteFile(fptr);
if (f == NULL) closed();
#ifdef THREAD
@@ -668,22 +707,31 @@ io_sysread(io, len)
RSTRING(str)->len = n;
RSTRING(str)->ptr[n] = '\0';
- return str;
+ return str_taint(str);
}
-static VALUE
+VALUE
io_binmode(io)
VALUE io;
{
-#if defined(NT) || defined(DJGPP)
+#if defined(NT) || defined(DJGPP) || defined(__CYGWIN32__) || defined(__human68k__)
OpenFile *fptr;
GetOpenFile(io, fptr);
+#ifdef __human68k__
+ if (fptr->f)
+ fmode(fptr->f, _IOBIN);
+ if (fptr->f2);
+ fmode(fptr->f2, _IOBIN);
+#else
if (fptr->f && setmode(fileno(fptr->f), O_BINARY) == -1)
rb_sys_fail(fptr->path);
if (fptr->f2 && setmode(fileno(fptr->f2), O_BINARY) == -1)
rb_sys_fail(fptr->path);
#endif
+
+ fptr->mode |= FMODE_BINMODE;
+#endif
return io;
}
@@ -706,8 +754,14 @@ io_mode_flags(mode)
default:
ArgError("illegal access mode");
}
+
+ if (mode[1] == 'b') {
+ flags |= FMODE_BINMODE;
+ mode++;
+ }
+
if (mode[1] == '+') {
- flags |= FMODE_READABLE | FMODE_WRITABLE;
+ flags |= FMODE_READWRITE;
}
return flags;
@@ -752,7 +806,59 @@ rb_fdopen(fd, mode)
return f;
}
-#if defined (NT) || defined(DJGPP)
+#if defined (NT) || defined(DJGPP) || defined(__CYGWIN32__) || defined(__human68k__)
+static struct pipe_list {
+ OpenFile *fptr;
+ struct pipe_list *next;
+} *pipe_list;
+
+static void
+pipe_add_fptr(fptr)
+ OpenFile *fptr;
+{
+ struct pipe_list *list;
+
+ list = ALLOC(struct pipe_list);
+ list->fptr = fptr;
+ list->next = pipe_list;
+ pipe_list = list;
+}
+
+static void
+pipe_del_fptr(fptr)
+ OpenFile *fptr;
+{
+ struct pipe_list *list = pipe_list;
+ struct pipe_list *tmp;
+
+ if (list->fptr == fptr) {
+ pipe_list = list->next;
+ return;
+ }
+
+ while (list->next) {
+ if (list->next->fptr == fptr) {
+ tmp = list->next;
+ list->next = list->next->next;
+ free(tmp);
+ return;
+ }
+ list = list->next;
+ }
+}
+
+static void
+pipe_atexit()
+{
+ struct pipe_list *list = pipe_list;
+
+ while (list) {
+ io_fptr_finalize(list->fptr);
+ list = list->next;
+ }
+}
+
+#if !defined (__CYGWIN32__)
static void
pipe_finalize(fptr)
OpenFile *fptr;
@@ -760,9 +866,24 @@ pipe_finalize(fptr)
if (fptr->f != NULL) {
pclose(fptr->f);
}
+ if (fptr->f2 != NULL) {
+ pclose(fptr->f2);
+ }
fptr->f = fptr->f2 = NULL;
+ pipe_del_fptr(fptr);
}
#endif
+#endif
+
+void
+io_unbuffered(fptr)
+ OpenFile *fptr;
+{
+ if (fptr->f2 == 0) TypeError("non-writable fptr");
+ setbuf(fptr->f, NULL);
+ setbuf(fptr->f2, NULL);
+ fptr->mode |= FMODE_SYNC;
+}
static VALUE
pipe_open(pname, mode)
@@ -771,7 +892,7 @@ pipe_open(pname, mode)
int modef = io_mode_flags(mode);
OpenFile *fptr;
-#if defined(NT) || defined(DJGPP)
+#if defined(NT) || defined(DJGPP) || defined(__human68k__)
FILE *f = popen(pname, mode);
if (f == NULL) rb_sys_fail(pname);
@@ -780,10 +901,14 @@ pipe_open(pname, mode)
OBJSETUP(port, cIO, T_FILE);
MakeOpenFile(port, fptr);
fptr->finalize = pipe_finalize;
+ fptr->mode = modef;
+ pipe_add_fptr(fptr);
if (modef & FMODE_READABLE) fptr->f = f;
- if (modef & FMODE_WRITABLE) fptr->f2 = f;
- fptr->mode = modef | FMODE_SYNC;
+ if (modef & FMODE_WRITABLE) {
+ fptr->f2 = f;
+ io_unbuffered(fptr);
+ }
return (VALUE)port;
}
#else
@@ -806,32 +931,47 @@ pipe_open(pname, mode)
case 0: /* child */
if (modef & FMODE_READABLE) {
close(pr[0]);
- dup2(pr[1], 1);
- close(pr[1]);
+ if (pr[1] != 1) {
+ dup2(pr[1], 1);
+ close(pr[1]);
+ }
}
if (modef & FMODE_WRITABLE) {
close(pw[1]);
- dup2(pw[0], 0);
- close(pw[0]);
+ if (pw[0] != 0) {
+ dup2(pw[0], 0);
+ close(pw[0]);
+ }
}
if (doexec) {
- VALUE fd = io_fileno(rb_stderr);
- int f = FIX2INT(fd);
+ VALUE serr = io_fileno(rb_stderr);
+ int fd = FIX2INT(serr);
+ extern char *sourcefile;
+ extern int sourceline;
- if (f != 2) {
+ if (fd != 2) {
close(2);
- dup2(f, 2);
- close(f);
+ dup2(fd, 2);
+ close(fd);
}
+
+ for (fd = 3; fd < NOFILE; fd++)
+ close(fd);
rb_proc_exec(pname);
+ fprintf(stderr, "%s:%d: command not found: %s\n",
+ sourcefile, sourceline, pname);
_exit(127);
}
return Qnil;
case -1: /* fork failed */
if (errno == EAGAIN) {
+#ifdef THREAD
+ thread_sleep(1);
+#else
sleep(1);
+#endif
goto retry;
}
close(pr[0]); close(pw[1]);
@@ -843,15 +983,24 @@ pipe_open(pname, mode)
NEWOBJ(port, struct RFile);
OBJSETUP(port, cIO, T_FILE);
MakeOpenFile(port, fptr);
- if (modef & FMODE_READABLE) close(pr[1]);
- if (modef & FMODE_WRITABLE) close(pw[0]);
fptr->mode = modef;
fptr->mode |= FMODE_SYNC;
fptr->pid = pid;
- if (modef & FMODE_READABLE) fptr->f = rb_fdopen(pr[0], "r");
- if (modef & FMODE_WRITABLE) fptr->f2 = rb_fdopen(pw[1], "w");
+ if (modef & FMODE_READABLE) {
+ close(pr[1]);
+ fptr->f = rb_fdopen(pr[0], "r");
+ }
+ if (modef & FMODE_WRITABLE) {
+ FILE *f = rb_fdopen(pw[1], "w");
+ close(pw[0]);
+ if (fptr->f) fptr->f2 = f;
+ else fptr->f = f;
+ }
+#if defined (__CYGWIN32__)
+ pipe_add_fptr(fptr);
+#endif
return (VALUE)port;
}
}
@@ -859,7 +1008,7 @@ pipe_open(pname, mode)
}
static VALUE
-io_popen(argc, argv, self)
+io_s_popen(argc, argv, self)
int argc;
VALUE *argv;
VALUE self;
@@ -868,7 +1017,7 @@ io_popen(argc, argv, self)
VALUE pname, pmode;
rb_scan_args(argc, argv, "11", &pname, &pmode);
- Check_Type(pname, T_STRING);
+ Check_SafeStr(pname);
if (NIL_P(pmode)) {
mode = "r";
}
@@ -877,7 +1026,7 @@ io_popen(argc, argv, self)
if (RSTRING(pmode)->len == 0 || RSTRING(pmode)->len > 2)
ArgError("illegal access mode");
mode = RSTRING(pmode)->ptr;
- }
+ }
return pipe_open(RSTRING(pname)->ptr, mode);
}
@@ -903,7 +1052,7 @@ f_open(argc, argv, self)
VALUE pname, pmode;
rb_scan_args(argc, argv, "11", &pname, &pmode);
- Check_Type(pname, T_STRING);
+ Check_SafeStr(pname);
if (NIL_P(pmode)) {
mode = "r";
}
@@ -916,6 +1065,126 @@ f_open(argc, argv, self)
return io_open(RSTRING(pname)->ptr, mode);
}
+#ifndef NT
+extern char *strdup();
+#endif
+
+VALUE
+io_reopen(io, nfile)
+ VALUE io, nfile;
+{
+ OpenFile *fptr, *orig;
+ char *mode;
+ int fd;
+
+ GetOpenFile(io, fptr);
+ Check_Type(nfile, T_FILE);
+ GetOpenFile(nfile, orig);
+
+ if (orig->f2) {
+ fflush(orig->f2);
+ }
+ else if (orig->mode & FMODE_WRITABLE) {
+ fflush(orig->f);
+ }
+
+ /* copy OpenFile structure */
+ fptr->mode = orig->mode;
+ fptr->pid = orig->pid;
+ fptr->lineno = orig->lineno;
+ if (fptr->path) free(fptr->path);
+ if (orig->path) fptr->path = strdup(orig->path);
+ else fptr->path = 0;
+ fptr->finalize = orig->finalize;
+
+ switch (fptr->mode & FMODE_READWRITE) {
+ case FMODE_READABLE:
+ default:
+ mode = "r"; break;
+ case FMODE_WRITABLE:
+ mode = "w"; break;
+ case FMODE_READWRITE:
+ if (orig->f2) mode = "r";
+ else mode = "r+";
+ break;
+ }
+ fd = fileno(fptr->f);
+ fclose(fptr->f);
+ dup2(fileno(orig->f), fd);
+ fptr->f = rb_fdopen(fd, mode);
+
+ if (fptr->f2) {
+ fd = fileno(fptr->f2);
+ fclose(fptr->f2);
+ if (orig->f2) {
+ dup2(fileno(orig->f2), fd);
+ fptr->f = rb_fdopen(fd, "w");
+ }
+ else {
+ fptr->f2 = 0;
+ }
+ }
+
+ if (fptr->mode & FMODE_BINMODE) {
+ io_binmode(io);
+ }
+
+ RBASIC(io)->class = RBASIC(nfile)->class;
+ return io;
+}
+
+static VALUE
+io_clone(io)
+ VALUE io;
+{
+ OpenFile *fptr, *orig;
+ int fd;
+ char *mode;
+
+ NEWOBJ(obj, struct RFile);
+ OBJSETUP(obj, CLASS_OF(io), T_FILE);
+
+ GetOpenFile(io, orig);
+ MakeOpenFile(obj, fptr);
+
+ if (orig->f2) {
+ fflush(orig->f2);
+ }
+ else if (orig->mode & FMODE_WRITABLE) {
+ fflush(orig->f);
+ }
+
+ /* copy OpenFile structure */
+ fptr->mode = orig->mode;
+ fptr->pid = orig->pid;
+ fptr->lineno = orig->lineno;
+ if (orig->path) fptr->path = strdup(orig->path);
+ fptr->finalize = orig->finalize;
+
+ switch (fptr->mode & FMODE_READWRITE) {
+ case FMODE_READABLE:
+ default:
+ mode = "r"; break;
+ case FMODE_WRITABLE:
+ mode = "w"; break;
+ case FMODE_READWRITE:
+ if (orig->f2) mode = "r";
+ else mode = "r+";
+ break;
+ }
+ fd = dup(fileno(orig->f));
+ fptr->f = rb_fdopen(fd, mode);
+ if (fptr->f2) {
+ fd = dup(fileno(orig->f2));
+ fptr->f = rb_fdopen(fd, "w");
+ }
+ if (fptr->mode & FMODE_BINMODE) {
+ io_binmode(obj);
+ }
+
+ return (VALUE)obj;
+}
+
static VALUE
io_printf(argc, argv, out)
int argc;
@@ -971,14 +1240,17 @@ io_print(argc, argv, out)
io_write(out, OFS);
}
switch (TYPE(argv[i])) {
- case T_STRING:
- io_write(out, argv[i]);
- break;
case T_NIL:
io_write(out, str_new2("nil"));
break;
+ case T_ARRAY:
+ ary_print_on(argv[i], out);
+ break;
+ case T_HASH:
+ break;
+ case T_STRING:
default:
- rb_funcall(argv[i], id_print_on, 1, out);
+ io_write(out, argv[i]);
break;
}
}
@@ -998,8 +1270,9 @@ f_print(argc, argv)
return Qnil;
}
-VALUE
+static VALUE
f_p(obj, val)
+ VALUE obj, val;
{
VALUE str = rb_inspect(val);
@@ -1009,7 +1282,7 @@ f_p(obj, val)
return Qnil;
}
-static VALUE
+static void
io_defset(val, id)
VALUE val;
ID id;
@@ -1017,17 +1290,11 @@ io_defset(val, id)
if (TYPE(val) == T_STRING) {
val = io_open(RSTRING(val)->ptr, "w");
}
- if (!obj_is_kind_of(val, cIO)) {
- TypeError("$< must be a file, %s given", rb_class2name(CLASS_OF(val)));
+ if (!rb_respond_to(val, id_write)) {
+ TypeError("$< must have write method, %s given",
+ rb_class2name(CLASS_OF(val)));
}
- return rb_defout = val;
-}
-
-static VALUE
-f_print_on(obj, port)
- VALUE obj, port;
-{
- return io_write(port, obj);
+ rb_defout = val;
}
static VALUE
@@ -1046,6 +1313,25 @@ prep_stdio(f, mode)
return (VALUE)obj;
}
+static VALUE
+io_s_new(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ VALUE fnum, mode;
+ FILE *f;
+ char *m = "r";
+
+ rb_scan_args(argc, argv, "11", &fnum, &mode);
+
+ if (!NIL_P(mode)) {
+ Check_SafeStr(mode);
+ m = RSTRING(mode)->ptr;
+ }
+ f = rb_fdopen(NUM2INT(fnum), m);
+ return prep_stdio(f, io_mode_flags(m));
+}
+
static VALUE filename, file;
static int gets_lineno;
static int init_p = 0, next_p = 0;
@@ -1094,12 +1380,12 @@ next_argv()
fstat(fileno(fr), &st);
if (*inplace) {
str = str_new2(fn);
-#ifdef NT
+#if defined(MSDOS) || defined(__CYGWIN32__) || defined(NT)
add_suffix(str, inplace);
#else
str_cat(str, inplace, strlen(inplace));
#endif
-#if defined(MSDOS) || defined(__BOW__)
+#if defined(MSDOS) || defined(__BOW__) || defined(__CYGWIN32__) || defined(NT) || defined(__human68k__)
(void)fclose(fr);
(void)unlink(RSTRING(str)->ptr);
(void)rename(fn, RSTRING(str)->ptr);
@@ -1114,7 +1400,7 @@ next_argv()
#endif
}
else {
-#if !defined(MSDOS) && !defined(__BOW__)
+#if !defined(MSDOS) && !defined(__BOW__) && !defined(__CYGWIN32__) && !defined(NT) && !defined(__human68k__)
if (unlink(fn) < 0) {
Warning("Can't remove %s: %s, skipping file",
fn, strerror(errno));
@@ -1126,7 +1412,7 @@ next_argv()
#endif
}
fw = rb_fopen(fn, "w");
-#if !defined(DJGPP) && !defined(__CYGWIN32__)
+#if !defined(MSDOS) && !defined(__CYGWIN32__) && !(NT) && !defined(__human68k__)
fstat(fileno(fw), &st2);
fchmod(fileno(fw), st.st_mode);
if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
@@ -1149,7 +1435,7 @@ next_argv()
static VALUE
f_gets_method(argc, argv)
int argc;
- VALUE argv;
+ VALUE *argv;
{
VALUE line;
@@ -1168,9 +1454,7 @@ f_gets_method(argc, argv)
}
VALUE
-f_gets(argc, argv)
- int argc;
- VALUE argv;
+f_gets()
{
return f_gets_method(0,0);
}
@@ -1237,14 +1521,14 @@ f_readlines(argc, argv)
VALUE line, ary;
ary = ary_new();
- while (RTEST(line = f_gets_method(argc, argv))) {
+ while (!NIL_P(line = f_gets_method(argc, argv))) {
ary_push(ary, line);
}
return ary;
}
-VALUE
+void
rb_str_setter(val, id, var)
VALUE val;
ID id;
@@ -1253,7 +1537,7 @@ rb_str_setter(val, id, var)
if (!NIL_P(val) && TYPE(val) != T_STRING) {
TypeError("value of %s must be String", rb_id2name(id));
}
- return *var = val;
+ *var = val;
}
static VALUE
@@ -1262,20 +1546,23 @@ f_backquote(obj, str)
struct RString *str;
{
VALUE port, result;
- OpenFile *fptr;
- Check_Type(str, T_STRING);
+ Check_SafeStr(str);
port = pipe_open(str->ptr, "r");
result = read_all(port);
io_close(port);
+ if (NIL_P(result)) return str_new(0,0);
return result;
}
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
+#ifdef NT
+#define select(v, w, x, y, z) (-1) /* anytime fail */
+#endif
static VALUE
f_select(argc, argv, obj)
@@ -1290,6 +1577,7 @@ f_select(argc, argv, obj)
OpenFile *fptr;
int i, max = 0, n;
int interrupt = 0;
+ int pending = 0;
rb_scan_args(argc, argv, "13", &read, &write, &except, &timeout);
if (NIL_P(timeout)) {
@@ -1302,7 +1590,6 @@ f_select(argc, argv, obj)
FD_ZERO(&pset);
if (!NIL_P(read)) {
- int pending = 0;
Check_Type(read, T_ARRAY);
rp = &rset;
@@ -1384,6 +1671,7 @@ f_select(argc, argv, obj)
interrupt = 1;
}
#endif
+ if (!pending && n == 0) return Qnil; /* returns nil on timeout */
res = ary_new2(3);
ary_push(res, rp?ary_new():ary_new2(0));
@@ -1391,7 +1679,6 @@ f_select(argc, argv, obj)
ary_push(res, ep?ary_new():ary_new2(0));
if (interrupt == 0) {
-
if (rp) {
list = RARRAY(res)->ptr[0];
for (i=0; i< RARRAY(read)->len; i++) {
@@ -1430,64 +1717,100 @@ f_select(argc, argv, obj)
}
}
- return res;
+ return res; /* returns an empty array on interrupt */
}
-void
+static VALUE
io_ctl(io, req, arg, io_p)
VALUE io, req;
struct RString *arg;
int io_p;
{
-#if !defined(MSDOS)
+#if !defined(MSDOS) && !defined(__human68k__)
int cmd = NUM2INT(req);
OpenFile *fptr;
int len, fd;
+ long narg = 0;
+ int retval;
+ rb_secure(2);
GetOpenFile(io, fptr);
+ if (NIL_P(arg) || (VALUE)arg == FALSE) {
+ narg = 0;
+ }
+ else if (FIXNUM_P(arg)) {
+ narg = FIX2INT(arg);
+ }
+ else if ((VALUE)arg == TRUE) {
+ narg = 1;
+ }
+ else {
+ Check_Type(arg, T_STRING);
+
#ifdef IOCPARM_MASK
#ifndef IOCPARM_LEN
#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
#endif
#endif
#ifdef IOCPARM_LEN
- len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
+ len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
#else
- len = 256; /* otherwise guess at what's safe */
+ len = 256; /* otherwise guess at what's safe */
#endif
+ str_modify(arg);
- Check_Type(arg, T_STRING);
- str_modify(arg);
-
- str_resize(arg, len+1);
- arg->ptr[len] = 17;
+ if (arg->len < len) {
+ str_resize(arg, len+1);
+ arg->ptr[len] = 17; /* a little sanity check here */
+ narg = (long)arg->ptr;
+ }
+ }
fd = fileno(fptr->f);
#ifdef HAVE_FCNTL
- if ((io_p?ioctl(fd, cmd, arg->ptr):fcntl(fd, cmd, arg->ptr))<0) {
- rb_sys_fail(fptr->path);
- }
+ retval = io_p?ioctl(fd, cmd, narg):fcntl(fd, cmd, narg);
#else
if (!io_p) {
rb_notimplement();
}
- if (ioctl(fd, cmd, arg->ptr)<0) rb_sys_fail(fptr->path);
+ retval = ioctl(fd, cmd, narg);
#endif
- if (arg->ptr[len] != 17) {
- ArgError("Return value overflowed string");
+ if (retval < 0) rb_sys_fail(fptr->path);
+ if (TYPE(arg) == T_STRING && arg->ptr[len] != 17) {
+ ArgError("return value overflowed string");
}
+ return INT2NUM(retval);
#else
- rb_notimplement();
+ rb_notimplement();
#endif
}
static VALUE
-io_ioctl(io, req, arg)
- VALUE io, req;
- struct RString *arg;
+io_ioctl(argc, argv, io)
+ int argc;
+ VALUE *argv;
+ VALUE io;
{
- io_ctl(io, req, arg, 1);
- return io;
+ VALUE req, arg;
+
+ rb_scan_args(argc, argv, "11", &req, &arg);
+ return io_ctl(io, req, arg, 1);
+}
+
+static VALUE
+io_fcntl(argc, argv, io)
+ int argc;
+ VALUE *argv;
+ VALUE io;
+{
+#ifdef HAVE_FCNTL
+ VALUE req, arg;
+
+ rb_scan_args(argc, argv, "11", &req, &arg);
+ return io_ctl(io, req, arg, 0);
+#else
+ rb_notimplement();
+#endif
}
static VALUE
@@ -1502,7 +1825,7 @@ f_syscall(argc, argv)
unsigned long arg[8];
#endif
int retval = -1;
- int i = 0;
+ int i = 1;
int items = argc - 1;
/* This probably won't work on machines where sizeof(long) != sizeof(int)
@@ -1510,6 +1833,7 @@ f_syscall(argc, argv)
* not likely have syscall implemented either, so who cares?
*/
+ rb_secure(2);
arg[0] = NUM2INT(argv[0]); argv++;
while (items--) {
if (FIXNUM_P(*argv)) {
@@ -1585,13 +1909,19 @@ f_syscall(argc, argv)
}
static VALUE
-io_pipe()
+io_s_pipe()
{
+#ifndef __human68k__
int pipes[2];
VALUE r, w, ary;
+#ifdef NT
+ if (_pipe(pipes, 1024, O_BINARY) == -1)
+#else
if (pipe(pipes) == -1)
+#endif
rb_sys_fail(0);
+
r = prep_stdio(fdopen(pipes[0], "r"), FMODE_READABLE);
w = prep_stdio(fdopen(pipes[1], "w"), FMODE_WRITABLE);
@@ -1600,52 +1930,112 @@ io_pipe()
ary_push(ary, w);
return ary;
+#else
+ rb_notimplement();
+#endif
}
+struct foreach_arg {
+ int argc;
+ VALUE sep;
+ VALUE io;
+};
static VALUE
-io_foreach_line(io)
- VALUE io;
+io_foreach_line(arg)
+ struct foreach_arg *arg;
{
VALUE str;
- while (!NIL_P(str = io_gets(io))) {
+ while (!NIL_P(str = io_gets_method(arg->argc, &arg->sep, arg->io))) {
rb_yield(str);
}
return Qnil;
}
static VALUE
-io_foreach(io, fname)
+io_s_foreach(argc, argv, io)
+ int argc;
+ VALUE *argv;
VALUE io;
+{
struct RString *fname;
+ struct foreach_arg arg;
+
+ rb_scan_args(argc, argv, "11", &fname, &arg.sep);
+ Check_SafeStr(fname);
+
+ arg.argc = argc - 1;
+ arg.io = io_open(fname->ptr, "r");
+ return rb_ensure(io_foreach_line, &arg, io_close, arg.io);
+}
+
+static VALUE
+io_readline_line(arg)
+ struct foreach_arg *arg;
+{
+ VALUE line, ary;
+
+ ary = ary_new();
+ while (!NIL_P(line = io_gets_method(arg->argc, &arg->sep, arg->io))) {
+ ary_push(ary, line);
+ }
+
+ return ary;
+}
+
+static VALUE
+io_s_readlines(argc, argv, io)
+ int argc;
+ VALUE *argv;
+ VALUE io;
{
- VALUE f, v;
+ struct RString *fname;
+ struct foreach_arg arg;
+
+ rb_scan_args(argc, argv, "11", &fname, &arg.sep);
+ Check_SafeStr(fname);
+
+ arg.argc = argc - 1;
+ arg.io = io_open(fname->ptr, "r");
+ return rb_ensure(io_readline_line, &arg, io_close, arg.io);
+}
- Check_Type(fname, T_STRING);
- f = io_open(fname->ptr, "r");
- return rb_ensure(io_foreach_line, f, io_close, f);
+static VALUE
+arg_fileno()
+{
+ return io_fileno(file);
}
static VALUE
arg_read(argc, argv)
int argc;
- VALUE argv;
+ VALUE *argv;
{
- VALUE str, str2;
+ VALUE tmp, str;
+ int len;
- str = str_new(0, 0);
- for (;;) {
- retry:
- if (!next_argv()) return Qnil;
- str2 = io_read(argc, argv, file);
- if (NIL_P(str2) && next_p != -1) {
- io_close(file);
- next_p = 1;
- goto retry;
- }
- if (NIL_P(str2)) break;
- str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len);
+ if (argc == 1) len = NUM2INT(argv[0]);
+ str = Qnil;
+
+ retry:
+ if (!next_argv()) return str;
+ tmp = io_read(argc, argv, file);
+ if (NIL_P(tmp) && next_p != -1) {
+ io_close(file);
+ next_p = 1;
+ goto retry;
+ }
+ if (NIL_P(tmp)) return str;
+ else if (NIL_P(str)) str = tmp;
+ else str_cat(str, RSTRING(tmp)->ptr, RSTRING(tmp)->len);
+ if (argc == 0) {
+ goto retry;
+ }
+ if (RSTRING(tmp)->len < len) {
+ len -= RSTRING(tmp)->len;
+ argv[0] = INT2FIX(len);
+ goto retry;
}
return str;
@@ -1669,6 +2059,17 @@ arg_getc()
}
static VALUE
+arg_readchar()
+{
+ VALUE c = io_getc(file);
+
+ if (NIL_P(c)) {
+ eof_error();
+ }
+ return c;
+}
+
+static VALUE
arg_each_line(argc, argv)
int argc;
VALUE argv;
@@ -1704,68 +2105,116 @@ arg_file()
return file;
}
+static VALUE
+arg_skip()
+{
+ if (next_p != -1) {
+ io_close(file);
+ next_p = 1;
+ }
+ return argf;
+}
+
+static VALUE
+arg_close()
+{
+ io_close(file);
+ if (next_p != -1) {
+ next_p = 1;
+ }
+ gets_lineno = 0;
+ return argf;
+}
+
+static VALUE
+arg_closed()
+{
+ return io_closed(file);
+}
+
+static VALUE
+opt_i_get()
+{
+ if (!inplace) return Qnil;
+ return str_new2(inplace);
+}
+
+static void
+opt_i_set(val)
+ struct RString *val;
+{
+ if (NIL_P(val)) {
+ inplace = 0;
+ return;
+ }
+ Check_Type(val, T_STRING);
+ inplace = val->ptr;
+}
+
extern VALUE mEnumerable;
void
Init_IO()
{
- extern VALUE cKernel;
+ extern VALUE mKernel;
extern VALUE eException;
eEOFError = rb_define_class("EOFError", eException);
id_write = rb_intern("write");
- id_fd = rb_intern("fd");
- id_print_on = rb_intern("print_on");
-
- rb_define_private_method(cKernel, "syscall", f_syscall, -1);
- rb_define_private_method(cKernel, "open", f_open, -1);
- rb_define_private_method(cKernel, "printf", f_printf, -1);
- rb_define_private_method(cKernel, "print", f_print, -1);
- rb_define_private_method(cKernel, "gets", f_gets_method, -1);
- rb_define_private_method(cKernel, "readline", f_readline, -1);
- rb_define_private_method(cKernel, "eof", f_eof, 0);
- rb_define_private_method(cKernel, "getc", f_getc, 0);
- rb_define_private_method(cKernel, "readchar", f_readchar, 0);
- rb_define_private_method(cKernel, "select", f_select, -1);
- rb_define_private_method(cKernel, "ungetc", f_ungetc, 1);
+ rb_define_global_function("syscall", f_syscall, -1);
- rb_define_private_method(cKernel, "readlines", f_readlines, -1);
+ rb_define_global_function("open", f_open, -1);
+ rb_define_global_function("printf", f_printf, -1);
+ rb_define_global_function("print", f_print, -1);
+ rb_define_global_function("gets", f_gets_method, -1);
+ rb_define_global_function("readline", f_readline, -1);
+ rb_define_global_function("eof", f_eof, 0);
+ rb_define_global_function("eof?", f_eof, 0);
+ rb_define_global_function("getc", f_getc, 0);
+ rb_define_global_function("readchar", f_readchar, 0);
+ rb_define_global_function("select", f_select, -1);
+ rb_define_global_function("ungetc", f_ungetc, 1);
- rb_define_method(cKernel, "print_on", f_print_on, 1);
+ rb_define_global_function("readlines", f_readlines, -1);
- rb_define_private_method(cKernel, "`", f_backquote, 1);
- rb_define_private_method(cKernel, "pipe", io_pipe, 0);
+ rb_define_global_function("`", f_backquote, 1);
+ rb_define_global_function("pipe", io_s_pipe, 0);
- rb_define_private_method(cKernel, "p", f_p, 1);
+ rb_define_global_function("p", f_p, 1);
cIO = rb_define_class("IO", cObject);
rb_include_module(cIO, mEnumerable);
- rb_undef_method(CLASS_OF(cIO), "new");
-
- rb_define_singleton_method(cIO, "popen", io_popen, -1);
- rb_define_singleton_method(cIO, "foreach", io_foreach, 1);
+ rb_define_singleton_method(cIO, "new", io_s_new, -1);
+ rb_define_singleton_method(cIO, "popen", io_s_popen, -1);
+ rb_define_singleton_method(cIO, "foreach", io_s_foreach, -1);
+ rb_define_singleton_method(cIO, "readlines", io_s_readlines, -1);
rb_define_singleton_method(cIO, "select", f_select, -1);
FS = OFS = Qnil;
rb_define_hooked_variable("$;", &FS, 0, rb_str_setter);
+ rb_define_hooked_variable("$-F", &FS, 0, rb_str_setter);
rb_define_hooked_variable("$,", &OFS, 0, rb_str_setter);
RS = RS_default = str_new2("\n"); ORS = Qnil;
rb_global_variable(&RS_default);
rb_define_hooked_variable("$/", &RS, 0, rb_str_setter);
+ rb_define_hooked_variable("$-0", &RS, 0, rb_str_setter);
rb_define_hooked_variable("$\\", &ORS, 0, rb_str_setter);
rb_define_variable("$.", &lineno);
rb_define_virtual_variable("$_", lastline_get, lastline_set);
+ rb_define_method(cIO, "clone", io_clone, 0);
+ rb_define_method(cIO, "reopen", io_reopen, 1);
+
rb_define_method(cIO, "print", io_print, -1);
rb_define_method(cIO, "printf", io_printf, -1);
rb_define_method(cIO, "each", io_each_line, -1);
- rb_define_method(cIO, "each_line", io_each_line, 0);
+ rb_define_method(cIO, "each_line", io_each_line, -1);
rb_define_method(cIO, "each_byte", io_each_byte, 0);
rb_define_method(cIO, "syswrite", io_syswrite, 1);
@@ -1777,7 +2226,7 @@ Init_IO()
rb_define_method(cIO, "sync", io_sync, 0);
rb_define_method(cIO, "sync=", io_set_sync, 1);
- rb_define_alias(cIO, "readlines", "to_a");
+ rb_define_method(cIO, "readlines", io_readlines, -1);
rb_define_method(cIO, "read", io_read, -1);
rb_define_method(cIO, "write", io_write, 1);
@@ -1790,6 +2239,7 @@ Init_IO()
rb_define_method(cIO, "<<", io_puts, 1);
rb_define_method(cIO, "flush", io_flush, 0);
rb_define_method(cIO, "eof", io_eof, 0);
+ rb_define_method(cIO, "eof?", io_eof, 0);
rb_define_method(cIO, "close", io_close, 0);
rb_define_method(cIO, "closed?", io_closed, 0);
@@ -1798,7 +2248,8 @@ Init_IO()
rb_define_method(cIO, "tty?", io_isatty, 0);
rb_define_method(cIO, "binmode", io_binmode, 0);
- rb_define_method(cIO, "ioctl", io_ioctl, 2);
+ rb_define_method(cIO, "ioctl", io_ioctl, -1);
+ rb_define_method(cIO, "fcntl", io_fcntl, -1);
rb_stdin = prep_stdio(stdin, FMODE_READABLE);
rb_define_readonly_variable("$stdin", &rb_stdin);
@@ -1817,18 +2268,21 @@ Init_IO()
rb_extend_object(argf, mEnumerable);
rb_define_readonly_variable("$<", &argf);
- rb_define_readonly_variable("$ARGF", &argf);
rb_define_global_const("ARGF", argf);
- rb_define_singleton_method(argf, "each", arg_each_line, 0);
+ rb_define_singleton_method(argf, "fileno", arg_fileno, 0);
+ rb_define_singleton_method(argf, "to_i", arg_fileno, 0);
+ rb_define_singleton_method(argf, "each", arg_each_line, -1);
rb_define_singleton_method(argf, "each_line", arg_each_line, -1);
rb_define_singleton_method(argf, "each_byte", arg_each_byte, 0);
rb_define_singleton_method(argf, "read", arg_read, -1);
rb_define_singleton_method(argf, "readlines", f_readlines, -1);
+ rb_define_singleton_method(argf, "to_a", f_readlines, -1);
rb_define_singleton_method(argf, "gets", f_gets_method, -1);
rb_define_singleton_method(argf, "readline", f_readline, -1);
rb_define_singleton_method(argf, "getc", arg_getc, 0);
+ rb_define_singleton_method(argf, "readchar", arg_readchar, 0);
rb_define_singleton_method(argf, "eof", f_eof, 0);
rb_define_singleton_method(argf, "eof?", f_eof, 0);
rb_define_singleton_method(argf, "ungetc", f_ungetc, 1);
@@ -1836,11 +2290,19 @@ Init_IO()
rb_define_singleton_method(argf, "to_s", arg_filename, 0);
rb_define_singleton_method(argf, "filename", arg_filename, 0);
rb_define_singleton_method(argf, "file", arg_file, 0);
+ rb_define_singleton_method(argf, "skip", arg_skip, 0);
+ rb_define_singleton_method(argf, "close", arg_close, 0);
+ rb_define_singleton_method(argf, "closed?", arg_closed, 0);
filename = str_new2("-");
rb_define_readonly_variable("$FILENAME", &filename);
file = rb_stdin;
rb_global_variable(&file);
+ rb_define_virtual_variable("$-i", opt_i_get, opt_i_set);
Init_File();
+
+#if defined (NT) || defined(DJGPP) || defined(__CYGWIN32__) || defined(__human68k__)
+ atexit(pipe_atexit);
+#endif
}
diff --git a/io.h b/io.h
index bc15d46e0e..05789a9c73 100644
--- a/io.h
+++ b/io.h
@@ -31,9 +31,8 @@ typedef struct OpenFile {
#define FMODE_READABLE 1
#define FMODE_WRITABLE 2
#define FMODE_READWRITE 3
-#define FMODE_SYNC 4
-
-void io_wrong_type();
+#define FMODE_BINMODE 4
+#define FMODE_SYNC 8
#define GetOpenFile(obj,fp) ((fp) = RFILE(obj)->fptr)
@@ -47,6 +46,8 @@ void io_wrong_type();
fp->finalize = 0;\
} while (0)
+#define GetWriteFile(fptr) (((fptr)->f2) ? (fptr)->f2 : (fptr)->f)
+
FILE *rb_fopen();
#endif
diff --git a/lib/English.rb b/lib/English.rb
new file mode 100644
index 0000000000..c7e13bebe6
--- /dev/null
+++ b/lib/English.rb
@@ -0,0 +1,28 @@
+
+alias $ERROR_INFO $!
+alias $ERROR_POSITION $@
+alias $LOADED_FEATURES $"
+alias $FS $;
+alias $FIELD_SEPARATOR $;
+alias $OFS $,
+alias $OUTPUT_FIELD_SEPARATOR $,
+alias $RS $/
+alias $INPUT_RECORD_SEPARATOR $/
+alias $ORS $\
+alias $OUPUT_RECORD_SEPARATOR $\
+alias $INPUT_LINE_NUMBER $.
+alias $NR $.
+alias $LAST_READ_LINE $_
+alias $DEFAULT_OUTPUT $>
+alias $DEFAULT_INPUT $<
+alias $PID $$
+alias $PROCESS_ID $$
+alias $CHILD_STATUS $?
+alias $LAST_MATCH_INFO $~
+alias $IGNORECASE $=
+alias $PROGRAM_NAME $0
+alias $ARGV $*
+alias $MATCH $&
+alias $PREMATCH $`
+alias $POSTMATCH $'
+alias $LAST_PAREN_MATCH $+
diff --git a/lib/base64.rb b/lib/base64.rb
index 9bb6487bee..96208a634d 100644
--- a/lib/base64.rb
+++ b/lib/base64.rb
@@ -1,29 +1,11 @@
def decode64(str)
- e = -1;
- c = ","
- string=''
+ string = ''
for line in str.split("\n")
- line.sub!(/=+$/, '')
- line.tr! 'A-Za-z0-9+/', "\000-\377"
- line.each_byte { |ch|
- n +=1
- e +=1
- if e==0
- c = ch << 2
- elsif e==1
- c |= ch >>4
- string += [c].pack('c')
- c = ch << 4
- elsif e == 2
- c |= ch >> 2
- string += [c].pack('c');
- c = ch << 6
- elsif e==3
- c |= ch
- string += [c].pack('c')
- e = -1
- end
- }
+ line.delete!('^A-Za-z0-9+/') # remove non-base64 chars
+ line.tr!('A-Za-z0-9+/', ' -_') # convert to uuencoded format
+ len = ["#{32 + line.length * 3 / 4}"].pack("c")
+ # compute length byte
+ string += "#{len}#{line}".unpack("u") # uudecode and concatenate
end
return string
end
@@ -53,3 +35,20 @@ def decode_b(str)
str.gsub!(/\0/, '')
j2e(str)
end
+
+def encode64(bin)
+ encode = ""
+ pad = 0
+ [bin].pack("u").each do |uu|
+ len = (2 + (uu[0] - 32)* 4) / 3
+ encode << uu[1, len].tr('` -_', 'AA-Za-z0-9+/')
+ pad += uu.length - 2 - len
+ end
+ encode + "=" * (pad % 3)
+end
+
+def b64encode(bin, len = 60)
+ encode64(bin).scan(/.{1,#{len}}/o) do
+ print $&, "\n"
+ end
+end
diff --git a/lib/date.rb b/lib/date.rb
new file mode 100644
index 0000000000..260f6e79ec
--- /dev/null
+++ b/lib/date.rb
@@ -0,0 +1,221 @@
+#
+# Date.rb -
+# $Release Version: $
+# $Revision: 1.2 $
+# $Date: 1997/02/14 11:05:29 $
+# by Yasuo OHBA(SHL Japan Inc. Technology Dept.)
+#
+# --
+#
+# September 1752
+# S M Tu W Th F S
+# 1 2 14 15 16
+# 17 18 19 20 21 22 23
+# 24 25 26 27 28 29 30
+#
+
+class Date
+ include Comparable
+
+ def initialize(y = 1, m = 1, d = 1)
+ if y.kind_of?(String) && y.size == 8
+ @year = y[0,4].to_i
+ @month = y[4,2].to_i
+ @day = y[6,2].to_i
+ else
+ if m.kind_of?(String)
+ ml = {"jan"=>1, "feb"=>2, "mar"=>3, "apr"=>4, "may"=>5, "jun"=>6, "jul"=>7, "aug"=>8, "sep"=>9, "oct"=>10, "nov"=>11, "dec"=>12}
+ m = ml[m.downcase]
+ if m.nil?
+ raise ArgumentError, "Wrong argument. (month)"
+ end
+ end
+ @year = y.to_i
+ @month = m.to_i
+ @day = d.to_i
+ end
+ _check_date
+ return self
+ end
+
+ def year
+ return @year
+ end
+
+ def month
+ return @month
+ end
+
+ def day
+ return @day
+ end
+
+ def period
+ return Date.period!(@year, @month, @day)
+ end
+
+ def day_of_week
+ dl = Date.daylist(@year)
+ d = Date.jan1!(@year)
+ for m in 1..(@month - 1)
+ d += dl[m]
+ end
+ d += @day - 1
+ if @year == 1752 && @month == 9 && @day >= 14
+ d -= (14 - 3)
+ end
+ return (d % 7)
+ end
+
+ Weektag = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
+ def name_of_week
+ return Weektag[self.day_of_week]
+ end
+
+ def +(o)
+ if o.kind_of?(Integer)
+ d = self.period + o
+ elsif o.kind_of?(Date)
+ d = self.period + o.period
+ else
+ raise TypeError, "Illegal type. (Integer or Date)"
+ end
+ return Date.at(d)
+ end
+
+ def -(o)
+ if o.kind_of?(Integer)
+ d = self.period - o
+ elsif o.kind_of?(Date)
+ d = self.period - o.period
+ else
+ raise TypeError, "Illegal type. (Integer or Date)"
+ end
+ if d <= 0
+ raise ArgumentError, "argument out of range. (self > other)"
+ end
+ return Date.at(d)
+ end
+
+ def <=>(o)
+ if o.kind_of?(Integer)
+ d = o
+ elsif o.kind_of?(Date)
+ d = o.period
+ else
+ raise TypeError, "Illegal type. (Integer or Date)"
+ end
+ return self.period <=> d
+ end
+
+ def eql?(o)
+ self == o
+ end
+
+ def hash
+ return @year ^ @month ^ @day
+ end
+
+ def leapyear?
+ if Date.leapyear(@year) == 1
+ return FALSE
+ else
+ return TRUE
+ end
+ end
+
+ def _check_date
+ m = Date.daylist(@year)
+ if @month < 1 || @month > 12
+ raise ArgumentError, "argument(month) out of range."
+ return nil
+ end
+ if @year == 1752 && @month == 9
+ if @day >= 3 && @day <= 13
+ raise ArgumentError, "argument(1752/09/3-13) out of range."
+ return nil
+ end
+ d = 30
+ else
+ d = m[@month]
+ end
+ if @day < 1 || @day > d
+ raise ArgumentError, "argument(day) out of range."
+ return nil
+ end
+ return self
+ end
+
+ private :_check_date
+end
+
+def Date.at(d)
+ mm = 1
+ yy = (d / 366.0).to_i
+ if yy != 0
+ dd = d - (Date.period!(yy, 1, 1) - 1)
+ else
+ dd = d
+ yy = 1
+ end
+ dl = Date.daylist(yy)
+ while dd > dl[mm]
+ if dd > dl[0]
+ dd -= dl[0]
+ yy += 1
+ dl = Date.daylist(yy)
+ else
+ dd -= dl[mm]
+ mm += 1
+ end
+ end
+ if yy == 1752 && mm == 9 && dd >= 3 && dd <= 19
+ dd += (14 - 3) # 1752/09/03-19 -> 1752/09/14-30
+ end
+
+ return Date.new(yy, mm, dd)
+end
+
+def Date.period!(y, m, d)
+ p = d
+ dl = Date.daylist(y)
+ for mm in 1..(m - 1)
+ p += dl[mm]
+ end
+ p += (y - 1) * 365 + ((y - 1) / 4.0).to_i
+ if (y - 1) > 1752
+ p -= ((y - 1 - 1752) / 100.0).to_i
+ p += ((y - 1 - 1752) / 400.0).to_i
+ p -= (14 - 3)
+ elsif y == 1752 && m == 9 && d >= 14 && d <= 30
+ p -= (14 - 3)
+ end
+ return p
+end
+
+def Date.leapyear(yy)
+ return ((Date.jan1!(yy + 1) + 7 - Date.jan1!(yy)) % 7)
+end
+
+def Date.daylist(yy)
+ case (Date.leapyear(yy))
+ when 1 # non-leapyear
+ return [365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
+ when 2 # leapyear
+ return [366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
+ else # 1752
+ return [355, 31, 29, 31, 30, 31, 30, 31, 31, 19, 31, 30, 31]
+ end
+end
+
+def Date.jan1!(y)
+ d = 4 + y + (y + 3) / 4
+ if y > 1800
+ d -= (y - 1701) / 100
+ d += (y - 1601) / 400
+ end
+ if y > 1752
+ d += 3
+ end
+ return (d % 7)
+end
diff --git a/lib/debug.rb b/lib/debug.rb
new file mode 100644
index 0000000000..432c7b4d19
--- /dev/null
+++ b/lib/debug.rb
@@ -0,0 +1,262 @@
+
+class DEBUGGER__
+ trap("INT") { DEBUGGER__::CONTEXT.interrupt }
+ $DEBUG = TRUE
+ def initialize
+ @break_points = []
+ @stop_next = 1
+ @frames = [nil]
+ @frame_pos = nil
+ @last_file = nil
+ @scripts = {}
+ end
+
+ def interrupt
+ @stop_next = 1
+ end
+
+ def debug_eval(str, binding)
+ begin
+ val = eval(str, binding)
+ val
+ rescue
+ at = caller(0)
+ printf "%s:%s\n", at.shift, $!
+ for i in at
+ break if i =~ /`debug_(eval|command)'$/ #`
+ printf "\tfrom %s\n", i
+ end
+ end
+ end
+
+ def debug_command(file, line, id, binding)
+ if (ENV['EMACS'] == 't')
+ printf "\032\032%s:%d:\n", file, line
+ else
+ printf "%s:%d:%s", file, line, line_at(file, line)
+ end
+ @frames[-1] = binding
+ STDOUT.print "(rdb:-) "
+ STDOUT.flush
+ while input = STDIN.gets
+ input.chop!
+ case input
+ when /^b(reak)?\s+(([^:\n]+:)?.+)/
+ pos = $2
+ if pos.index ":"
+ file, pos = pos.split(":")
+ end
+ file = File.basename(file)
+ if pos =~ /^\d+$/
+ pname = pos
+ pos = Integer(pos)
+ else
+ pname = pos = pos.intern.id2name
+ end
+ printf "Set breakpoint %d at %s:%s\n", @break_points.size, file, pname
+ @break_points.push [file, pos]
+ when /^b(reak)?$/, /^info b(reak)?$/
+ n = 0
+ for f, p in @break_points
+ printf "%d %s:%s\n", n, f, p
+ n += 1
+ end
+ when /^del(ete)?(\s+(\d+))?$/
+ pos = $3
+ unless pos
+ STDOUT.print "clear all breakpoints? (y/n) "
+ STDOUT.flush
+ input = STDIN.gets.chop!
+ if input == "y"
+ for n in @break_points.indexes
+ @break_points[n] = nil
+ end
+ end
+ else
+ pos = Integer(pos)
+ if @break_points[pos]
+ bp = @break_points[pos]
+ printf "Clear breakpoint %d at %s:%s\n", pos, bp[0], bp[1]
+ @break_points[pos] = nil
+ else
+ printf "Breakpoint %d is not defined\n", pos
+ end
+ end
+ when /^c(ont)?$/
+ return
+ when /^s(tep)?\s*(\d+)?$/
+ if $1
+ lev = Integer($1)
+ else
+ lev = 1
+ end
+ @stop_next = lev
+ return
+ when /^n(ext)?\s*(\d+)?$/
+ if $1
+ lev = Integer($1)
+ else
+ lev = 1
+ end
+ @stop_next = lev
+ @no_step = @frames.size
+ return
+ when /^up\s*(\d+)?$/
+ if $1
+ lev = Integer($1)
+ else
+ lev = 1
+ end
+ unless @frame_pos
+ @frame_pos = @frames.size - 1
+ end
+ @frame_pos -= lev
+ if @frame_pos < 0
+ STDOUT.print "at toplevel\n"
+ @frame_pos = 0
+ else
+ binding = @frames[@frame_pos]
+ end
+ when /^down\s*(\d+)??$/
+ if $1
+ lev = Integer($1)
+ else
+ lev = 1
+ end
+ if lev >= @frames.size or @frame_pos and @frame_pos+lev >= @frames.size
+ STDOUT.print "at stack bottom\n"
+ @frame_pos = nil
+ else
+ @frame_pos += lev
+ binding = @frames[@frame_pos]
+ end
+ when /^fin(ish)?$/
+ @finish_pos = @frames.size
+ return
+ when /^q(uit)?$/
+ STDOUT.print "really quit? (y/n) "
+ STDOUT.flush
+ input = STDIN.gets.chop!
+ exit if input == "y"
+ when /^where$/
+ at = caller(4)
+ for i in at
+ printf " %s\n", i
+ end
+ when /^l(ist)?(\s+(.*))?$/
+ if $3
+ b, e = $3.split(/[-,]/)
+ b = Integer(b)-1
+ if e
+ e = Integer(e)-1
+ else
+ e = b + 10
+ end
+ end
+ unless b
+ b = line - 1
+ e = line + 9
+ end
+ p [b,e]
+ line_at(file, line)
+ if lines = @scripts[file] and lines != TRUE
+ n = b+1
+ for l in lines[b..e]
+ printf "%4d %s", n, l
+ n += 1
+ end
+ else
+ printf "no sourcefile available for %s\n", file
+ end
+ when /^p\s+/
+ p debug_eval($', binding)
+ else
+ v = debug_eval(input, binding)
+ p v unless v == nil
+ end
+ STDOUT.print "(rdb:-) "
+ STDOUT.flush
+ end
+ end
+
+ def line_at(file, line)
+ lines = @scripts[file]
+ if lines
+ return "\n" if lines == TRUE
+ line = lines[line-1]
+ return "\n" unless line
+ return line
+ end
+ begin
+ f = open(file)
+ lines = @scripts[file] = f.readlines
+ rescue
+ @scripts[file] = TRUE
+ return "\n"
+ end
+ line = lines[line-1]
+ return "\n" unless line
+ return line
+ end
+
+ def debug_funcname(id)
+ if id == 0
+ "toplevel"
+ else
+ id.id2name
+ end
+ end
+
+ def check_break_points(file, pos, binding, id)
+ file = File.basename(file)
+ if @break_points.include? [file, pos]
+ index = @break_points.index([file, pos])
+ printf "Breakpoint %d, %s at %s:%s\n",
+ index, debug_funcname(id), file, pos
+ return TRUE
+ end
+ return FALSE
+ end
+
+ def trace_func(event, file, line, id, binding)
+ if event == 'line'
+ if @no_step == nil or @no_step >= @frames.size
+ @stop_next -= 1
+ end
+ if @stop_next == 0
+ if [file, line] == @last
+ @stop_next = 1
+ else
+ @no_step = nil
+ debug_command(file, line, id, binding)
+ @last = [file, line]
+ end
+ end
+ if check_break_points(file, line, binding, id)
+ debug_command(file, line, id, binding)
+ end
+ end
+ if event == 'call'
+ @frames.push binding
+ if check_break_points(file, id.id2name, binding, id)
+ debug_command(file, line, id, binding)
+ end
+ end
+ if event == 'class'
+ @frames.push binding
+ end
+ if event == 'return' or event == 'end'
+ if @finish_pos == @frames.size
+ @stop_next = 1
+ end
+ @frames.pop
+ end
+ @last_file = file
+ end
+
+ CONTEXT = new
+end
+
+set_trace_func proc{|event, file, line, id, binding|
+ DEBUGGER__::CONTEXT.trace_func event, file, line, id, binding
+}
diff --git a/lib/e2mmap.rb b/lib/e2mmap.rb
new file mode 100644
index 0000000000..d10657bbad
--- /dev/null
+++ b/lib/e2mmap.rb
@@ -0,0 +1,94 @@
+#
+# e2mmap.rb - for ruby 1.1
+# $Release Version: 1.1$
+# $Revision: 1.4 $
+# $Date: 1997/08/18 07:12:12 $
+# by Keiju ISHITSUKA
+#
+# --
+#
+#
+if VERSION < "1.1"
+ require "e2mmap1_0.rb"
+else
+
+ module Exception2MessageMapper
+ RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/RCS/e2mmap.rb,v 1.4 1997/08/18 07:12:12 keiju Exp keiju $-'
+
+ E2MM = Exception2MessageMapper
+
+ def E2MM.extend_object(cl)
+ super
+ cl.bind(self)
+ end
+
+ # ȤθߴΤ˻ĤƤ.
+ def E2MM.extend_to(b)
+ c = eval("self", b)
+ c.extend(self)
+ end
+
+# public :fail
+ # alias e2mm_fail fail
+
+ def fail(err = nil, *rest)
+ Exception2MessageMapper.fail Exception2MessageMapper::ErrNotRegisteredException, err.to_s
+ end
+
+ def bind(cl)
+ self.module_eval %q^
+ E2MM_ErrorMSG = {}
+ # fail(err, *rest)
+ # err: 㳰
+ # rest: åϤѥ᡼
+ #
+ def self.fail(err = nil, *rest)
+ $@ = caller(0) if $@.nil?
+ $@.shift
+ if form = E2MM_ErrorMSG[err]
+ $! = err.new(sprintf(form, *rest))
+ # e2mm_fail()
+ raise()
+# elsif self == Exception2MessageMapper
+# fail Exception2MessageMapper::ErrNotRegisteredException, err.to_s
+ else
+# print "super\n"
+ super
+ end
+ end
+ class << self
+ public :fail
+ end
+
+ # def_exception(c, m)
+ # c: exception
+ # m: message_form
+ # 㳰cΥåmȤ.
+ #
+ def self.def_e2message(c, m)
+ E2MM_ErrorMSG[c] = m
+ end
+
+ # def_exception(c, m)
+ # n: exception_name
+ # m: message_form
+ # s: 㳰ѡ饹(ǥե: Exception)
+ # 㳰̾``c''㳰, ΥåmȤ.
+ #
+ #def def_exception(n, m)
+ def self.def_exception(n, m, s = Exception)
+ n = n.id2name if n.kind_of?(Fixnum)
+ e = Class.new(s)
+ const_set(n, e)
+ E2MM_ErrorMSG[e] = m
+ # const_get(:E2MM_ErrorMSG)[e] = m
+ end
+ ^
+ end
+
+ extend E2MM
+ def_exception(:ErrNotClassOrModule, "Not Class or Module")
+ def_exception(:ErrNotRegisteredException, "not registerd exception(%s)")
+ end
+end
+
diff --git a/lib/e2mmap1_0.rb b/lib/e2mmap1_0.rb
new file mode 100644
index 0000000000..c5797fd573
--- /dev/null
+++ b/lib/e2mmap1_0.rb
@@ -0,0 +1,71 @@
+#
+# e2mmap.rb -
+# $Release Version: 1.0$
+# $Revision: 1.4 $
+# $Date: 1997/08/18 07:12:12 $
+# by Keiju ISHITSUKA
+#
+# --
+#
+#
+
+module Exception2MessageMapper
+ RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/RCS/e2mmap.rb,v 1.4 1997/08/18 07:12:12 keiju Exp keiju $-'
+ E2MM = Exception2MessageMapper
+
+ def E2MM.extend_to(b)
+ c = eval("self", b)
+ c.extend(self)
+ c.bind(b)
+ end
+
+ def bind(b)
+ eval "
+ @binding = binding
+ E2MM_ErrorMSG = Hash.new
+
+ # fail(err, *rest)
+ # err: 㳰
+ # rest: åϤѥ᡼
+ #
+ def fail!(*rest)
+ super
+ end
+
+ def fail(err, *rest)
+ $! = err.new(sprintf(E2MM_ErrorMSG[err], *rest))
+ super()
+ end
+
+ public :fail
+ # def_exception(c, m)
+ # c: exception
+ # m: message_form
+ # 㳰cΥåmȤ.
+ #
+ def def_e2message(c, m)
+ E2MM_ErrorMSG[c] = m
+ end
+
+ # def_exception(c, m)
+ # c: exception_name
+ # m: message_form
+ # s: 㳰ѡ饹(ǥե: Exception)
+ # 㳰̾``c''㳰, ΥåmȤ.
+ #
+ def def_exception(c, m)
+
+ c = c.id2name if c.kind_of?(Fixnum)
+ eval \"class \#{c} < Exception
+ end
+ E2MM_ErrorMSG[\#{c}] = '\#{m}'
+ \", @binding
+ end
+", b
+
+ end
+
+ E2MM.extend_to(binding)
+ def_exception("ErrNotClassOrModule", "Not Class or Module")
+end
+
diff --git a/lib/finalize.rb b/lib/finalize.rb
new file mode 100644
index 0000000000..e934753e19
--- /dev/null
+++ b/lib/finalize.rb
@@ -0,0 +1,205 @@
+#
+# finalize.rb -
+# $Release Version: $
+# $Revision: 1.2 $
+# $Date: 1997/07/25 02:43:00 $
+# by Keiju ISHITSUKA(SHL Japan Inc.)
+#
+# --
+#
+# Usage:
+#
+# add(obj, dependant, method = :finalize, *opt)
+# add_dependency(obj, dependant, method = :finalize, *opt)
+# ¸ط R_method(obj, dependant) ɲ
+#
+# delete(obj_or_id, dependant, method = :finalize)
+# delete_dependency(obj_or_id, dependant, method = :finalize)
+# ¸ط R_method(obj, dependant) κ
+# delete_all_dependency(obj_or_id, dependant)
+# ¸ط R_*(obj, dependant) κ
+# delete_by_dependant(dependant, method = :finalize)
+# ¸ط R_method(*, dependant) κ
+# delete_all_by_dependant(dependant)
+# ¸ط R_*(*, dependant) κ
+# delete_all
+# Ƥΰ¸طκ.
+#
+# finalize(obj_or_id, dependant, method = :finalize)
+# finalize_dependency(obj_or_id, dependant, method = :finalize)
+# ¸Ϣ R_method(obj, dependtant) ǷФdependant
+# finalize.
+# finalize_all_dependency(obj_or_id, dependant)
+# ¸Ϣ R_*(obj, dependtant) ǷФdependantfinalize.
+# finalize_by_dependant(dependant, method = :finalize)
+# ¸Ϣ R_method(*, dependtant) ǷФdependantfinalize.
+# fainalize_all_by_dependant(dependant)
+# ¸Ϣ R_*(*, dependtant) ǷФdependantfinalize.
+# finalize_all
+# FinalizerϿƤdependantfinalize
+#
+# safe{..}
+# gcFinalizerưΤߤ.
+#
+#
+
+module Finalizer
+ RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/RCS/finalize.rb,v 1.2 1997/07/25 02:43:00 keiju Exp keiju $-'
+
+ # @dependency: {id => [[dependant, method, *opt], ...], ...}
+
+ # ¸ط R_method(obj, dependant) ɲ
+ def add_dependency(obj, dependant, method = :finalize, *opt)
+ ObjectSpace.call_finalizer(obj)
+ method = method.id unless method.kind_of?(Fixnum)
+ assoc = [dependant, method].concat(opt)
+ if dep = @dependency[obj.id]
+ dep.push assoc
+ else
+ @dependency[obj.id] = [assoc]
+ end
+ end
+ alias add add_dependency
+
+ # ¸ط R_method(obj, dependant) κ
+ def delete_dependency(id, dependant, method = :finalize)
+ id = id.id unless id.kind_of?(Fixnum)
+ method = method.id unless method.kind_of?(Fixnum)
+ for assoc in @dependency[id]
+ assoc.delete_if do
+ |d, m, *o|
+ d == dependant && m == method
+ end
+ @dependency.delete(id) if assoc.empty?
+ end
+ end
+ alias delete delete_dependency
+
+ # ¸ط R_*(obj, dependant) κ
+ def delete_all_dependency(id, dependant)
+ id = id.id unless id.kind_of?(Fixnum)
+ method = method.id unless method.kind_of?(Fixnum)
+ for assoc in @dependency[id]
+ assoc.delete_if do
+ |d, m, *o|
+ d == dependant
+ end
+ @dependency.delete(id) if assoc.empty?
+ end
+ end
+
+ # ¸ط R_method(*, dependant) κ
+ def delete_by_dependant(dependant, method = :finalize)
+ method = method.id unless method.kind_of?(Fixnum)
+ for id in @dependency.keys
+ delete(id, dependant, method)
+ end
+ end
+
+ # ¸ط R_*(*, dependant) κ
+ def delete_all_by_dependant(dependant)
+ for id in @dependency.keys
+ delete_all_dependency(id, dependant)
+ end
+ end
+
+ # ¸Ϣ R_method(obj, dependtant) ǷФdependantfinalize
+ # .
+ def finalize_dependency(id, dependant, method = :finalize)
+ id = id.id unless id.kind_of?(Fixnum)
+ method = method.id unless method.kind_of?(Fixnum)
+ for assocs in @dependency[id]
+ assocs.delete_if do
+ |d, m, *o|
+ d.send(m, *o) if ret = d == dependant && m == method
+ ret
+ end
+ @dependency.delete(id) if assoc.empty?
+ end
+ end
+ alias finalize finalize_dependency
+
+ # ¸Ϣ R_*(obj, dependtant) ǷФdependantfinalize.
+ def finalize_all_dependency(id, dependant)
+ id = id.id unless id.kind_of?(Fixnum)
+ method = method.id unless method.kind_of?(Fixnum)
+ for assoc in @dependency[id]
+ assoc.delete_if do
+ |d, m, *o|
+ d.send(m, *o) if ret = d == dependant
+ end
+ @dependency.delete(id) if assoc.empty?
+ end
+ end
+
+ # ¸Ϣ R_method(*, dependtant) ǷФdependantfinalize.
+ def finalize_by_dependant(dependant, method = :finalize)
+ method = method.id unless method.kind_of?(Fixnum)
+ for id in @dependency.keys
+ finalize(id, dependant, method)
+ end
+ end
+
+ # ¸Ϣ R_*(*, dependtant) ǷФdependantfinalize.
+ def fainalize_all_by_dependant(dependant)
+ for id in @dependency.keys
+ finalize_all_dependency(id, dependant)
+ end
+ end
+
+ # FinalizerϿƤƤdependantfinalize
+ def finalize_all
+ for id, assocs in @dependency
+ for dependant, method, *opt in assocs
+ dependant.send(method, id, *opt)
+ end
+ assocs.clear
+ end
+ end
+
+ # finalize_* ˸ƤӽФΥƥ졼
+ def safe
+ old_status = Thread.critical
+ Thread.critical = TRUE
+ ObjectSpace.remove_finalizer(@proc)
+ yield
+ ObjectSpace.add_finalizer(@proc)
+ Thread.critical = old_status
+ end
+
+ # ObjectSpace#add_finalizerؤϿؿ
+ def final_of(id)
+ if assocs = @dependency.delete(id)
+ for dependant, method, *opt in assocs
+ dependant.send(method, id, *opt)
+ end
+ end
+ end
+
+ @dependency = Hash.new
+ @proc = proc{|id| final_of(id)}
+ ObjectSpace.add_finalizer(@proc)
+
+ module_function :add
+ module_function :add_dependency
+
+ module_function :delete
+ module_function :delete_dependency
+ module_function :delete_all_dependency
+ module_function :delete_by_dependant
+ module_function :delete_all_by_dependant
+
+ module_function :finalize
+ module_function :finalize_dependency
+ module_function :finalize_all_dependency
+ module_function :finalize_by_dependant
+ module_function :fainalize_all_by_dependant
+ module_function :finalize_all
+
+ module_function :safe
+
+ module_function :final_of
+ private_class_method :final_of
+
+end
+
diff --git a/lib/ftplib.rb b/lib/ftplib.rb
new file mode 100644
index 0000000000..34ee2f8d62
--- /dev/null
+++ b/lib/ftplib.rb
@@ -0,0 +1,617 @@
+### ftplib.rb -*- Mode: ruby; tab-width: 8; -*-
+
+## $Revision: 1.5 $
+## $Date: 1997/09/16 08:03:31 $
+## by maeda shugo <shugo@po.aianet.ne.jp>
+
+### Code:
+
+require "socket"
+require "sync" if defined? Thread
+
+class FTPError < Exception; end
+class FTPReplyError < FTPError; end
+class FTPTempError < FTPError; end
+class FTPPermError < FTPError; end
+class FTPProtoError < FTPError; end
+
+class FTP
+
+ RCS_ID = '$Id: ftplib.rb,v 1.5 1997/09/16 08:03:31 shugo Exp $'
+
+ FTP_PORT = 21
+ CRLF = "\r\n"
+
+ attr :passive, TRUE
+ attr :return_code, TRUE
+ attr :debug_mode, TRUE
+ attr :welcome
+ attr :lastresp
+
+ THREAD_SAFE = defined?(Thread) != FALSE
+
+ if THREAD_SAFE
+ def synchronize(mode = :EX)
+ if @sync
+ @sync.synchronize(mode) do
+ yield
+ end
+ end
+ end
+
+ def sock_synchronize(mode = :EX)
+ if @sock
+ @sock.synchronize(mode) do
+ yield
+ end
+ end
+ end
+ else
+ def synchronize(mode = :EX)
+ yield
+ end
+
+ def sock_synchronize(mode = :EX)
+ yield
+ end
+ end
+ private :sock_synchronize
+
+ def FTP.open(host, user = nil, passwd = nil, acct = nil)
+ new(host, user, passwd, acct)
+ end
+
+ def initialize(host = nil, user = nil,
+ passwd = nil, acct = nil)
+ if THREAD_SAFE
+ @sync = Sync.new
+ end
+ @passive = FALSE
+ @return_code = "\n"
+ @debug_mode = FALSE
+ if host
+ connect(host)
+ if user
+ login(user, passwd, acct)
+ end
+ end
+ end
+
+ def open_socket(host, port)
+ if defined? SOCKSsocket and ENV["SOCKS_SERVER"]
+ @passive = TRUE
+ SOCKSsocket.open(host, port)
+ else
+ TCPsocket.open(host, port)
+ end
+ end
+ private :open_socket
+
+ def connect(host, port = FTP_PORT)
+ if @debug_mode
+ print "connect: ", host, ", ", port, "\n"
+ end
+ synchronize do
+ @sock = open_socket(host, port)
+ if THREAD_SAFE
+ @sock.extend Sync_m
+ end
+ voidresp
+ end
+ end
+
+ def sanitize(s)
+ if s =~ /^PASS /i
+ s[0, 5] + "*" * (s.length - 5)
+ else
+ s
+ end
+ end
+ private :sanitize
+
+ def putline(line)
+ if @debug_mode
+ print "put: ", sanitize(line), "\n"
+ end
+ line = line + CRLF
+ @sock.write(line)
+ end
+ private :putline
+
+ def getline
+ line = @sock.readline # if get EOF, raise EOFError
+ if line[-2, 2] == CRLF
+ line = line[0 .. -3]
+ elsif line[-1] == ?\r or
+ line[-1] == ?\n
+ line = line[0 .. -2]
+ end
+ if @debug_mode
+ print "get: ", sanitize(line), "\n"
+ end
+ line
+ end
+ private :getline
+
+ def getmultiline
+ line = getline
+ buff = line
+ if line[3] == ?-
+ code = line[0, 3]
+ begin
+ line = getline
+ buff << "\n" << line
+ end until line[0, 3] == code and line[3] != ?-
+ end
+ buff << "\n"
+ end
+ private :getmultiline
+
+ def getresp
+ resp = getmultiline
+ @lastresp = resp[0, 3]
+ c = resp[0]
+ case c
+ when ?1, ?2, ?3
+ return resp
+ when ?4
+ raise FTPTempError, resp
+ when ?5
+ raise FTPPermError, resp
+ else
+ raise FTPProtoError, resp
+ end
+ end
+ private :getresp
+
+ def voidresp
+ resp = getresp
+ if resp[0] != ?2
+ raise FTPReplyError, resp
+ end
+ end
+ private :voidresp
+
+ def sendcmd(cmd)
+ synchronize do
+ sock_synchronize do
+ putline(cmd)
+ getresp
+ end
+ end
+ end
+
+ def voidcmd(cmd)
+ synchronize do
+ sock_synchronize do
+ putline(cmd)
+ voidresp
+ end
+ end
+ nil
+ end
+
+ def sendport(host, port)
+ hbytes = host.split(".")
+ pbytes = [port / 256, port % 256]
+ bytes = hbytes + pbytes
+ cmd = "PORT " + bytes.join(",")
+ voidcmd(cmd)
+ end
+ private :sendport
+
+ def makeport
+ sock = TCPserver.open(0)
+ port = sock.addr[1]
+ host = TCPsocket.getaddress(@sock.addr[2])
+ resp = sendport(host, port)
+ sock
+ end
+ private :makeport
+
+ def transfercmd(cmd)
+ if @passive
+ host, port = parse227(sendcmd("PASV"))
+ conn = open_socket(host, port)
+ resp = sendcmd(cmd)
+ if resp[0] != ?1
+ raise FTPReplyError, resp
+ end
+ else
+ sock = makeport
+ resp = sendcmd(cmd)
+ if resp[0] != ?1
+ raise FTPReplyError, resp
+ end
+ conn = sock.accept
+ end
+ conn
+ end
+ private :transfercmd
+
+ def getaddress
+ thishost = Socket.gethostname
+ if not thishost.index(".")
+ thishost = Socket.gethostbyname(thishost)[0]
+ end
+ if ENV.has_key?("LOGNAME")
+ realuser = ENV["LOGNAME"]
+ elsif ENV.has_key?("USER")
+ realuser = ENV["USER"]
+ else
+ realuser = "anonymous"
+ end
+ realuser + "@" + thishost
+ end
+ private :getaddress
+
+ def login(user = "anonymous", passwd = nil, acct = nil)
+ if user == "anonymous" and passwd == nil
+ passwd = getaddress
+ end
+
+ resp = ""
+ synchronize do
+ resp = sendcmd('USER ' + user)
+ if resp[0] == ?3
+ resp = sendcmd('PASS ' + passwd)
+ end
+ if resp[0] == ?3
+ resp = sendcmd('ACCT ' + acct)
+ end
+ end
+ if resp[0] != ?2
+ raise FTPReplyError, resp
+ end
+ @welcome = resp
+ end
+
+ def retrbinary(cmd, blocksize, callback = Proc.new)
+ synchronize do
+ voidcmd("TYPE I")
+ conn = transfercmd(cmd)
+ while TRUE
+ data = conn.read(blocksize)
+ break if data == nil
+ callback.call(data)
+ end
+ conn.close
+ voidresp
+ end
+ end
+
+ def retrlines(cmd, callback = nil)
+ if iterator?
+ callback = Proc.new
+ elsif not callback.is_a?(Proc)
+ callback = Proc.new {|line| print line, "\n"}
+ end
+ synchronize do
+ voidcmd("TYPE A")
+ conn = transfercmd(cmd)
+ while TRUE
+ line = conn.gets
+ break if line == nil
+ if line[-2, 2] == CRLF
+ line = line[0 .. -3]
+ elsif line[-1] == ?\n
+ line = line[0 .. -2]
+ end
+ callback.call(line)
+ end
+ conn.close
+ voidresp
+ end
+ end
+
+ def storbinary(cmd, file, blocksize, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ synchronize do
+ voidcmd("TYPE I")
+ conn = transfercmd(cmd)
+ while TRUE
+ buf = file.read(blocksize)
+ break if buf == nil
+ conn.write(buf)
+ if use_callback
+ callback.call(buf)
+ end
+ end
+ conn.close
+ voidresp
+ end
+ end
+
+ def storlines(cmd, file, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ synchronize do
+ voidcmd("TYPE A")
+ conn = transfercmd(cmd)
+ while TRUE
+ buf = file.gets
+ break if buf == nil
+ if buf[-2, 2] != CRLF
+ if buf[-1] == ?\r or
+ buf[-1] == ?\n
+ buf = buf[0 .. -2]
+ end
+ buf = buf + CRLF
+ end
+ conn.write(buf)
+ if use_callback
+ callback.call(buf)
+ end
+ end
+ conn.close
+ voidresp
+ end
+ end
+
+ def getbinaryfile(remotefile, localfile,
+ blocksize, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ f = open(localfile, "w")
+ begin
+ f.binmode
+ retrbinary("RETR " + remotefile, blocksize) do |data|
+ f.write(data)
+ if use_callback
+ callback.call(data)
+ end
+ end
+ ensure
+ f.close
+ end
+ end
+
+ def gettextfile(remotefile, localfile, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ f = open(localfile, "w")
+ begin
+ retrlines("RETR " + remotefile) do |line|
+ line = line + @return_code
+ f.write(line)
+ if use_callback
+ callback.call(line)
+ end
+ end
+ ensure
+ f.close
+ end
+ end
+
+ def putbinaryfile(localfile, remotefile,
+ blocksize, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ f = open(localfile)
+ begin
+ f.binmode
+ storbinary("STOR " + remotefile, f, blocksize) do |data|
+ if use_callback
+ callback.call(data)
+ end
+ end
+ ensure
+ f.close
+ end
+ end
+
+ def puttextfile(localfile, remotefile, callback = nil)
+ if iterator?
+ callback = Proc.new
+ end
+ use_callback = callback.is_a?(Proc)
+ f = open(localfile)
+ begin
+ storlines("STOR " + remotefile, f) do |line|
+ if use_callback
+ callback.call(line)
+ end
+ end
+ ensure
+ f.close
+ end
+ end
+
+ def acct(account)
+ cmd = "ACCT " + account
+ voidcmd(cmd)
+ end
+
+ def nlst(dir = nil)
+ cmd = "NLST"
+ if dir
+ cmd = cmd + " " + dir
+ end
+ files = []
+ retrlines(cmd) do |line|
+ files.push(line)
+ end
+ files
+ end
+
+ def list(*args)
+ cmd = "LIST"
+ if iterator?
+ callback = Proc.new
+ elsif args[-1].is_a?(Proc)
+ callback = args.pop
+ else
+ callback = nil
+ end
+ args.each do |arg|
+ cmd = cmd + " " + arg
+ end
+ retrlines(cmd, callback)
+ end
+ alias ls list
+ alias dir list
+
+ def rename(fromname, toname)
+ resp = sendcmd("RNFR " + fromname)
+ if resp[0] != ?3
+ raise FTPReplyError, resp
+ end
+ voidcmd("RNTO " + toname)
+ end
+
+ def delete(filename)
+ resp = sendcmd("DELE " + filename)
+ if resp[0, 3] == "250"
+ return
+ elsif resp[0] == ?5
+ raise FTPPermError, resp
+ else
+ raise FTPReplyError, resp
+ end
+ end
+
+ def chdir(dirname)
+ if dirname == ".."
+ begin
+ voidcmd("CDUP")
+ return
+ rescue FTPPermError
+ if $![0, 3] != "500"
+ raise FTPPermError, $!
+ end
+ end
+ end
+ cmd = "CWD " + dirname
+ voidcmd(cmd)
+ end
+
+ def size(filename)
+ resp = sendcmd("SIZE " + filename)
+ if resp[0, 3] == "213"
+ return Integer(resp[3 .. -1].strip)
+ end
+ end
+
+ def mkdir(dirname)
+ resp = sendcmd("MKD " + dirname)
+ return parse257(resp)
+ end
+
+ def rmdir(dirname)
+ voidcmd("RMD " + dirname)
+ end
+
+ def pwd
+ resp = sendcmd("PWD")
+ return parse257(resp)
+ end
+ alias getdir pwd
+
+ def system
+ resp = sendcmd("SYST")
+ if resp[0, 3] != "215"
+ raise FTPReplyError, resp
+ end
+ return resp[4 .. -1]
+ end
+
+ def abort
+ line = "ABOR" + CRLF
+ resp = ""
+ sock_synchronize do
+ print "put: ABOR\n" if @debug_mode
+ @sock.send(line, Socket::MSG_OOB)
+ resp = getmultiline
+ end
+ unless ["426", "226", "225"].include?(resp[0, 3])
+ raise FTPProtoError, resp
+ end
+ resp
+ end
+
+ def status
+ line = "STAT" + CRLF
+ resp = ""
+ sock_synchronize do
+ print "put: STAT\n" if @debug_mode
+ @sock.send(line, Socket::MSG_OOB)
+ resp = getresp
+ end
+ resp
+ end
+
+ def help(arg = nil)
+ cmd = "HELP"
+ if arg
+ cmd = cmd + " " + arg
+ end
+ sendcmd(cmd)
+ end
+
+ def quit
+ voidcmd("QUIT")
+ end
+
+ def close
+ @sock.close if @sock and not @sock.closed?
+ end
+
+ def closed?
+ @sock == nil or @sock.closed?
+ end
+
+ def parse227(resp)
+ if resp[0, 3] != "227"
+ raise FTPReplyError, resp
+ end
+ left = resp.index("(")
+ right = resp.index(")")
+ if left == nil or right == nil
+ raise FTPProtoError, resp
+ end
+ numbers = resp[left + 1 .. right - 1].split(",")
+ if numbers.length != 6
+ raise FTPProtoError, resp
+ end
+ host = numbers[0, 4].join(".")
+ port = (Integer(numbers[4]) << 8) + Integer(numbers[5])
+ return host, port
+ end
+ private :parse227
+
+ def parse257(resp)
+ if resp[0, 3] != "257"
+ raise FTPReplyError, resp
+ end
+ if resp[3, 2] != ' "'
+ return ""
+ end
+ dirname = ""
+ i = 5
+ n = resp.length
+ while i < n
+ c = resp[i, 1]
+ i = i + 1
+ if c == '"'
+ if i > n or resp[i, 1] != '"'
+ break
+ end
+ i = i + 1
+ end
+ dirname = dirname + c
+ end
+ return dirname
+ end
+ private :parse257
+end
diff --git a/lib/jcode.rb b/lib/jcode.rb
index 5b2289932f..40ab48ddac 100644
--- a/lib/jcode.rb
+++ b/lib/jcode.rb
@@ -1,15 +1,31 @@
# jcode.rb - ruby code to handle japanese (EUC/SJIS) string
+$vsave, $VERBOSE = $VERBOSE, FALSE
class String
printf STDERR, "feel free for some warnings:\n" if $VERBOSE
+ def jlength
+ self.split(//).length
+ end
+
alias original_succ succ
private :original_succ
+ def mbchar?(c)
+ if $KCODE =~ /^s/i
+ c =~ /[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc]/n
+ elsif $KCODE =~ /^e/i
+ c =~ /[\xa1-\xfe][\xa1-\xfe]/n
+ else
+ FALSE
+ end
+ end
+
def succ
if self[-2] && self[-2] & 0x80 != 0
s = self.dup
s[-1] += 1
+ s[-1] += 1 if !mbchar?(s)
return s
else
original_succ
@@ -23,8 +39,11 @@ class String
tail = self[-2..-1]
if tail.length == 2 and tail =~ /^.$/ then
if self[0..-2] == to[0..-2]
+ first = self[-2].chr
for c in self[-1] .. to[-1]
- yield self[0..-2]+c.chr
+ if mbchar?(first+c.chr)
+ yield self[0..-2]+c.chr
+ end
end
end
else
@@ -171,4 +190,18 @@ class String
self.dup.tr_s!(from,to)
end
+ alias original_chop! chop!
+ private :original_chop!
+
+ def chop!
+ if self =~ /(.)$/ and $1.size == 2
+ original_chop!
+ end
+ original_chop!
+ end
+
+ def chop
+ self.dup.chop!
+ end
end
+$VERBOSE = $vsave
diff --git a/lib/mathn.rb b/lib/mathn.rb
index 359cb45769..fdf27f6771 100644
--- a/lib/mathn.rb
+++ b/lib/mathn.rb
@@ -2,7 +2,7 @@
# mathn.rb -
# $Release Version: 0.5 $
# $Revision: 1.1 $
-# $Date: 1996/11/11 04:25:24 $
+# $Date: 1997/07/03 04:43:47 $
# by Keiju ISHITSUKA(SHL Japan Inc.)
#
# --
@@ -12,6 +12,7 @@
require "rational.rb"
require "complex.rb"
+require "matrix.rb"
class Integer
diff --git a/lib/matrix.rb b/lib/matrix.rb
new file mode 100644
index 0000000000..394c66f098
--- /dev/null
+++ b/lib/matrix.rb
@@ -0,0 +1,777 @@
+#!/usr/local/bin/ruby
+#
+# matrix.rb -
+# $Release Version: 1.0$
+# $Revision: 1.0 $
+# $Date: 97/05/23 11:35:28 $
+# Original Version from Smalltalk-80 version
+# on July 23, 1985 at 8:37:17 am
+# by Keiju ISHITSUKA
+#
+# --
+#
+# Matrix[[1,2,3],
+# :
+# [3,4,5]]
+# Matrix[row0,
+# row1,
+# :
+# rown]
+#
+# column:
+# row:
+#
+
+require "e2mmap.rb"
+
+module ExceptionForMatrix
+ Exception2MessageMapper.extend_to(binding)
+
+ def_e2message(TypeError, "wrong argument type %s (expected %s)")
+ def_e2message(ArgumentError, "Wrong # of arguments(%d for %d)")
+
+ def_exception("ErrDimensionMismatch", "\#{self.type} dimemsion mismatch")
+ def_exception("ErrNotRegular", "Not Regular Matrix")
+ def_exception("ErrOperationNotDefined", "This operation(%s) can\\'t defined")
+end
+
+class Matrix
+ RCS_ID='-$Header: ruby-mode,v 1.2 91/04/20 17:24:57 keiju Locked $-'
+
+ include ExceptionForMatrix
+
+ # instance creations
+ private_class_method :new
+
+ def Matrix.[](*rows)
+ new(:init_rows, rows, FALSE)
+ end
+
+ def Matrix.rows(rows, copy = TRUE)
+ new(:init_rows, rows, copy)
+ end
+
+ def Matrix.columns(columns)
+ rows = (0 .. columns[0].size - 1).collect {
+ |i|
+ (0 .. columns.size - 1).collect {
+ |j|
+ columns[j][i]
+ }
+ }
+ Matrix.rows(rows, FALSE)
+ end
+
+ def Matrix.diagonal(*values)
+ size = values.size
+ rows = (0 .. size - 1).collect {
+ |j|
+ row = Array.new(size).fill(0, 0, size)
+ row[j] = values[j]
+ row
+ }
+ self
+ rows(rows, FALSE)
+ end
+
+ def Matrix.scalar(n, value)
+ Matrix.diagonal(*Array.new(n).fill(value, 0, n))
+ end
+
+ def Matrix.identity(n)
+ Matrix.scalar(n, 1)
+ end
+ class << Matrix
+ alias unit identity
+ alias I identity
+ end
+
+ def Matrix.zero(n)
+ Matrix.scalar(n, 0)
+ end
+
+ def Matrix.row_vector(row)
+ case row
+ when Vector
+ Matrix.rows([row.to_a], FALSE)
+ when Array
+ Matrix.rows([row.dup], FALSE)
+ else
+ Matrix.row([[row]], FALSE)
+ end
+ end
+
+ def Matrix.column_vector(column)
+ case column
+ when Vector
+ Matrix.columns([column.to_a])
+ when Array
+ Matrix.columns([column])
+ else
+ Matrix.columns([[column]])
+ end
+ end
+
+ # initializing
+ def initialize(init_method, *argv)
+ self.send(init_method, *argv)
+ end
+
+ def init_rows(rows, copy)
+ if copy
+ @rows = rows.collect{|row| row.dup}
+ else
+ @rows = rows
+ end
+ self
+ end
+ private :init_rows
+
+ #accessing
+ def [](i, j)
+ @rows[i][j]
+ end
+
+ def row_size
+ @rows.size
+ end
+
+ def column_size
+ @rows[0].size
+ end
+
+ def row(i)
+ if iterator?
+ for e in @rows[i]
+ yield e
+ end
+ else
+ Vector.elements(@rows[i])
+ end
+ end
+
+ def column(j)
+ if iterator?
+ 0.upto(row_size - 1) do
+ |i|
+ yield @rows[i][j]
+ end
+ else
+ col = (0 .. row_size - 1).collect {
+ |i|
+ @rows[i][j]
+ }
+ Vector.elements(col, FALSE)
+ end
+ end
+
+ def collect
+ rows = @rows.collect{|row| row.collect{|e| yield e}}
+ Matrix.rows(rows, FALSE)
+ end
+ alias map collect
+
+ #
+ # param: (from_row, row_size, from_col, size_col)
+ # (from_row..to_row, from_col..to_col)
+ #
+ def minor(*param)
+ case param.size
+ when 2
+ from_row = param[0].first
+ size_row = param[0].size
+ from_col = param[1].first
+ size_col = param[1].size
+ when 4
+ from_row = param[0]
+ size_row = param[1]
+ from_col = param[2]
+ size_col = param[3]
+ else
+ Matrix.fail ArgumentError, param.inspect
+ end
+
+ rows = @rows[from_row, size_row].collect{
+ |row|
+ row[from_col, size_col]
+ }
+ Matrix.rows(rows, FALSE)
+ end
+
+ # TESTING
+ def regular?
+ square? and rank == column_size
+ end
+
+ def singular?
+ not regular?
+ end
+
+ def square?
+ column_size == row_size
+ end
+
+ # ARITHMETIC
+
+ def *(m) #is matrix or vector or number"
+ case(m)
+ when Numeric
+ rows = @rows.collect {
+ |row|
+ row.collect {
+ |e|
+ e * m
+ }
+ }
+ return Matrix.rows(rows, FALSE)
+ when Vector
+ m = Matrix.column_vector(m)
+ r = self * m
+ return r.column(0)
+ when Matrix
+ Matrix.fail ErrDimensionMismatch if column_size != m.row_size
+
+ rows = (0 .. row_size - 1).collect {
+ |i|
+ (0 .. m.column_size - 1).collect {
+ |j|
+ vij = 0
+ 0.upto(column_size - 1) do
+ |k|
+ vij += self[i, k] * m[k, j]
+ end
+ vij
+ }
+ }
+ return Matrix.rows(rows, FALSE)
+ else
+ x, y = m.coerce(self)
+ return x * y
+ end
+ end
+
+ def +(m)
+ case m
+ when Numeric
+ Matrix.fail ErrOperationNotDefined, "+"
+ when Vector
+ m = Matrix.column_vector(m)
+ when Matrix
+ else
+ x, y = m.coerce(self)
+ return x + y
+ end
+
+ Matrix.fail ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
+
+ rows = (0 .. row_size - 1).collect {
+ |i|
+ (0 .. column_size - 1).collect {
+ |j|
+ self[i, j] + m[i, j]
+ }
+ }
+ Matrix.rows(rows, FALSE)
+ end
+
+ def -(m)
+ case m
+ when Numeric
+ Matrix.fail ErrOperationNotDefined, "-"
+ when Vector
+ m = Matrix.column_vector(m)
+ when Matrix
+ else
+ x, y = m.coerce(self)
+ return x - y
+ end
+
+ Matrix.fail ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
+
+ rows = (0 .. row_size - 1).collect {
+ |i|
+ (0 .. column_size - 1).collect {
+ |j|
+ self[i, j] - m[i, j]
+ }
+ }
+ Matrix.rows(rows, FALSE)
+ end
+
+ def inverse
+ Matrix.fail ErrDimensionMismatch unless square?
+ Matrix.I(row_size).inverse_from(self)
+ end
+ alias inv inverse
+
+ def inverse_from(src)
+ size = row_size - 1
+ a = src.to_a
+
+ for k in 0..size
+ if (akk = a[k][k]) == 0
+ i = k
+ begin
+ fail ErrNotRegular if (i += 1) > size
+ end while a[i][k] == 0
+ a[i], a[k] = a[k], a[i]
+ @rows[i], @rows[k] = @rows[k], @rows[i]
+ akk = a[k][k]
+ end
+
+ for i in 0 .. size
+ next if i == k
+ q = a[i][k] / akk
+ a[i][k] = 0
+
+ (k + 1).upto(size) do
+ |j|
+ a[i][j] -= a[k][j] * q
+ end
+ 0.upto(size) do
+ |j|
+ @rows[i][j] -= @rows[k][j] * q
+ end
+ end
+
+ (k + 1).upto(size) do
+ |j|
+ a[k][j] /= akk
+ end
+ 0.upto(size) do
+ |j|
+ @rows[k][j] /= akk
+ end
+ end
+ self
+ end
+ #alias reciprocal inverse
+
+ def ** (other)
+ if other.kind_of?(Integer)
+ x = self
+ if other <= 0
+ x = self.inverse
+ return Matrix.identity(self.column_size) if other == 0
+ other = -other
+ end
+ z = x
+ n = other - 1
+ while n != 0
+ while (div, mod = n.divmod(2)
+ mod == 0)
+ x = x * x
+ n = div
+ end
+ z *= x
+ n -= 1
+ end
+ z
+ elsif other.kind_of?(Float) || defined?(Rational) && other.kind_of?(Rational)
+ fail ErrOperationNotDefined, "**"
+ else
+ fail ErrOperationNotDefined, "**"
+ end
+ end
+
+ # Matrix functions
+
+ def determinant
+ return 0 unless square?
+
+ size = row_size - 1
+ a = to_a
+
+ det = 1
+ k = 0
+ begin
+ if (akk = a[k][k]) == 0
+ i = k
+ begin
+ return 0 if (i += 1) > size
+ end while a[i][k] == 0
+ a[i], a[k] = a[k], a[i]
+ akk = a[k][k]
+ end
+ (k + 1).upto(size) do
+ |i|
+ q = a[i][k] / akk
+ (k + 1).upto(size) do
+ |j|
+ a[i][j] -= a[k][j] * q
+ end
+ end
+ det *= akk
+ end while (k += 1) <= size
+ det
+ end
+ alias det determinant
+
+ def rank
+ if column_size > row_size
+ a = transpose.to_a
+ else
+ a = to_a
+ end
+ rank = 0
+ k = 0
+ begin
+ if (akk = a[k][k]) == 0
+ i = -1
+ nothing = FALSE
+ begin
+ if (i += 1) > column_size - 1
+ nothing = TRUE
+ break
+ end
+ end while a[i][k] == 0
+ next if nothing
+ a[i], a[k] = a[k], a[i]
+ akk = a[k][k]
+ end
+ (k + 1).upto(row_size - 1) do
+ |i|
+ q = a[i][k] / akk
+ (k + 1).upto(column_size - 1) do
+ |j|
+ a[i][j] -= a[k][j] * q
+ end
+ end
+ rank += 1
+ end while (k += 1) <= column_size - 1
+ return rank
+ end
+
+ def trace
+ tr = 0
+ 0.upto(column_size - 1) do
+ |i|
+ tr += @rows[i][i]
+ end
+ tr
+ end
+ alias tr trace
+
+ def transpose
+ Matrix.columns(@rows)
+ end
+ alias t transpose
+
+ # CONVERTING
+
+ def coerce(other)
+ case other
+ when Numeric
+ return Scalar.new(other), self
+ end
+ end
+
+ def row_vectors
+ rows = (0 .. column_size - 1).collect {
+ |i|
+ row(i)
+ }
+ rows
+ end
+
+ def column_vectors
+ columns = (0 .. row_size - 1).collect {
+ |i|
+ column(i)
+ }
+ columns
+ end
+
+ def to_a
+ @rows.collect{|row| row.collect{|e| e}}
+ end
+
+ def to_f
+ collect{|e| e.to_f}
+ end
+
+ def to_i
+ collect{|e| e.to_i}
+ end
+
+ def to_r
+ collect{|e| e.to_r}
+ end
+
+ # PRINTING
+ def to_s
+ "Matrix[" + @rows.collect{
+ |row|
+ "[" + row.collect{|e| e.to_s}.join(", ") + "]"
+ }.join(", ")+"]"
+ end
+
+ def inspect
+ "Matrix"+@rows.inspect
+ end
+
+ # Private CLASS
+
+ class Scalar < Numeric
+ include ExceptionForMatrix
+
+ def initialize(value)
+ @value = value
+ end
+
+ # ARITHMETIC
+ def +(other)
+ case other
+ when Numeric
+ Scalar.new(@value + other)
+ when Vector, Matrix
+ Scalar.fail WrongArgType, other.type, "Numeric or Scalar"
+ when Scalar
+ Scalar.new(@value + other.value)
+ else
+ x, y = other.coerce(self)
+ x + y
+ end
+ end
+
+ def -(other)
+ case other
+ when Numeric
+ Scalar.new(@value - other)
+ when Vector, Matrix
+ Scalar.fail WrongArgType, other.type, "Numeric or Scalar"
+ when Scalar
+ Scalar.new(@value - other.value)
+ else
+ x, y = other.coerce(self)
+ x - y
+ end
+ end
+
+ def *(other)
+ case other
+ when Numeric
+ Scalar.new(@value * other)
+ when Vector, Matrix
+ other.collect{|e| @value * e}
+ else
+ x, y = other.coerce(self)
+ x * y
+ end
+ end
+
+ def / (other)
+ case other
+ when Numeric
+ Scalar.new(@value / other)
+ when Vector
+ Scalar.fail WrongArgType, other.type, "Numeric or Scalar or Matrix"
+ when Matrix
+ self * _M.inverse
+ else
+ x, y = other.coerce(self)
+ x / y
+ end
+ end
+
+ def ** (other)
+ case other
+ when Numeric
+ Scalar.new(@value ** other)
+ when Vector
+ Scalar.fail WrongArgType, other.type, "Numeric or Scalar or Matrix"
+ when Matrix
+ other.powered_by(self)
+ else
+ x, y = other.coerce(self)
+ x ** y
+ end
+ end
+ end
+end
+
+#----------------------------------------------------------------------
+#
+# -
+#
+#----------------------------------------------------------------------
+class Vector
+ include ExceptionForMatrix
+
+
+ #INSTANCE CREATION
+
+ private_class_method :new
+ def Vector.[](*array)
+ new(:init_elements, array, copy = FALSE)
+ end
+
+ def Vector.elements(array, copy = TRUE)
+ new(:init_elements, array, copy)
+ end
+
+ def initialize(method, array, copy)
+ self.send(method, array, copy)
+ end
+
+ def init_elements(array, copy)
+ if copy
+ @elements = array.dup
+ else
+ @elements = array
+ end
+ end
+
+ # ACCSESSING
+
+ def [](i)
+ @elements[i]
+ end
+
+ def size
+ @elements.size
+ end
+
+ # ENUMRATIONS
+ def each2(v)
+ Vector.fail ErrDimensionMismatch if size != v.size
+ 0.upto(size - 1) do
+ |i|
+ yield @elements[i], v[i]
+ end
+ end
+
+ def collect2(v)
+ Vector.fail ErrDimensionMismatch if size != v.size
+ (0 .. size - 1).collect do
+ |i|
+ yield @elements[i], v[i]
+ end
+ end
+
+ # ARITHMETIC
+
+ def *(x) "is matrix or number"
+ case x
+ when Numeric
+ els = @elements.collect{|e| e * x}
+ Vector.elements(els, FALSE)
+ when Matrix
+ self.covector * x
+ else
+ s, x = X.corece(self)
+ s * x
+ end
+ end
+
+ def +(v)
+ case v
+ when Vector
+ Vector.fail ErrDimensionMismatch if size != v.size
+ els = collect2(v) {
+ |v1, v2|
+ v1 + v2
+ }
+ Vector.elements(els, FALSE)
+ when Matrix
+ Matrix.column_vector(self) + v
+ else
+ s, x = v.corece(self)
+ s + x
+ end
+ end
+
+ def -(v)
+ case v
+ when Vector
+ Vector.fail ErrDimensionMismatch if size != v.size
+ els = collect2(v) {
+ |v1, v2|
+ v1 - v2
+ }
+ Vector.elements(els, FALSE)
+ when Matrix
+ Matrix.column_vector(self) - v
+ else
+ s, x = v.corece(self)
+ s - x
+ end
+ end
+
+ # VECTOR FUNCTIONS
+
+ def inner_product(v)
+ Vector.fail ErrDimensionMismatch if size != v.size
+
+ p = 0
+ each2(v) {
+ |v1, v2|
+ p += v1 * v2
+ }
+ p
+ end
+
+ def collect
+ els = @elements.collect {
+ |v|
+ yield v
+ }
+ Vector.elements(els, FALSE)
+ end
+ alias map collect
+
+ def map2(v)
+ els = collect2(v) {
+ |v1, v2|
+ yield v1, v2
+ }
+ Vector.elements(els, FALSE)
+ end
+
+ def r
+ v = 0
+ for e in @elements
+ v += e*e
+ end
+ return v.sqrt
+ end
+
+ # CONVERTING
+ def covector
+ Matrix.row_vector(self)
+ end
+
+ def to_a
+ @elements.dup
+ end
+
+ def to_f
+ collect{|e| e.to_f}
+ end
+
+ def to_i
+ collect{|e| e.to_i}
+ end
+
+ def to_r
+ collect{|e| e.to_r}
+ end
+
+ def coerce(other)
+ case other
+ when Numeric
+ return Scalar.new(other), self
+ end
+ end
+
+ # PRINTING
+
+ def to_s
+ "Vector[" + @elements.join(", ") + "]"
+ end
+
+ def inspect
+ str = "Vector"+@elements.inspect
+ end
+end
+
diff --git a/lib/mutex_m.rb b/lib/mutex_m.rb
new file mode 100644
index 0000000000..823888e72f
--- /dev/null
+++ b/lib/mutex_m.rb
@@ -0,0 +1,183 @@
+#
+# mutex_m.rb -
+# $Release Version: 2.0$
+# $Revision: 1.2 $
+# $Date: 1997/07/25 02:43:21 $
+# Original from mutex.rb
+# by Keiju ISHITSUKA(SHL Japan Inc.)
+#
+# --
+# Usage:
+# require "mutex_m.rb"
+# obj = Object.new
+# obj.extend Mutex_m
+# ...
+# MutexƱȤ
+#
+
+require "finalize"
+
+module Mutex_m
+ def Mutex_m.extend_object(obj)
+ if Fixnum === obj or TRUE === obj or FALSE === obj or nil == obj
+ raise TypeError, "Mutex_m can't extend to this class(#{obj.type})"
+ else
+ begin
+ eval "class << obj
+ @mu_locked
+ end"
+ obj.extend(For_primitive_object)
+ rescue TypeError
+ obj.extend(For_general_object)
+ end
+ end
+ end
+
+ def mu_extended
+ unless (defined? locked? and
+ defined? lock and
+ defined? unlock and
+ defined? try_lock and
+ defined? synchronize)
+ eval "class << self
+ alias locked mu_locked?
+ alias lock mu_lock
+ alias unlock mu_unlock
+ alias try_lock mu_try_lock
+ alias synchronize mu_synchronize
+ end"
+ end
+ end
+
+ def mu_synchronize
+ begin
+ mu_lock
+ yield
+ ensure
+ mu_unlock
+ end
+ end
+
+ module For_general_object
+ include Mutex_m
+
+ def For_general_object.extend_object(obj)
+ super
+ obj.mu_extended
+ end
+
+ def mu_extended
+ super
+ @mu_waiting = []
+ @mu_locked = FALSE;
+ end
+
+ def mu_locked?
+ @mu_locked
+ end
+
+ def mu_try_lock
+ result = FALSE
+ Thread.critical = TRUE
+ unless @mu_locked
+ @mu_locked = TRUE
+ result = TRUE
+ end
+ Thread.critical = FALSE
+ result
+ end
+
+ def mu_lock
+ while (Thread.critical = TRUE; @mu_locked)
+ @mu_waiting.push Thread.current
+ Thread.stop
+ end
+ @mu_locked = TRUE
+ Thread.critical = FALSE
+ self
+ end
+
+ def mu_unlock
+ return unless @mu_locked
+ Thread.critical = TRUE
+ wait = @mu_waiting
+ @mu_waiting = []
+ @mu_locked = FALSE
+ Thread.critical = FALSE
+ for w in wait
+ w.run
+ end
+ self
+ end
+
+ end
+
+ module For_primitive_object
+ include Mutex_m
+ Mu_Locked = Hash.new
+
+ def For_primitive_object.extend_object(obj)
+ super
+ obj.mu_extended
+ Finalizer.add(obj, For_primitive_object, :mu_finalize)
+ end
+
+ def For_primitive_object.mu_finalize(id)
+ Thread.critical = TRUE
+ if wait = Mu_Locked.delete(id)
+ # wait == [] Ȥ GCΤ, for w in wait ϰ̣ʤ.
+ Thread.critical = FALSE
+ for w in wait
+ w.run
+ end
+ else
+ Thread.critical = FALSE
+ end
+ self
+ end
+
+ def mu_locked?
+ Mu_Locked.key?(self.id)
+ end
+
+ def mu_try_lock
+ Thread.critical = TRUE
+ if Mu_Locked.key?(self.id)
+ ret = FALSE
+ else
+ Mu_Locked[self.id] = []
+ Finalizer.set(self, For_primitive_object, :mu_delete_Locked)
+ ret = TRUE
+ end
+ Thread.critical = FALSE
+ ret
+ end
+
+ def mu_lock
+ while (Thread.critical = TRUE; w = Mu_Locked[self.id])
+ w.push Thread.current
+ Thread.stop
+ end
+ Mu_Locked[self.id] = []
+ Finalizer.add(self, For_primitive_object, :mu_delete_Locked)
+ Thread.critical = FALSE
+ self
+ end
+
+ def mu_unlock
+ Thread.critical = TRUE
+ if wait = Mu_Locked.delete(self.id)
+ Finalizer.delete(self, For_primitive_object, :mu_finalize)
+ Thread.critical = FALSE
+ for w in wait
+ w.run
+ end
+ else
+ Thread.critical = FALSE
+ end
+ self
+ end
+ end
+end
+
+
diff --git a/lib/observer.rb b/lib/observer.rb
index 9a753939a2..b802dac633 100644
--- a/lib/observer.rb
+++ b/lib/observer.rb
@@ -30,7 +30,7 @@ module Observable
@observer_state
end
def notify_observers(*arg)
- if @observer_state
+ if @observer_peers and @observer_state
for i in @observer_peers
i.update(*arg)
end
diff --git a/lib/parsedate.rb b/lib/parsedate.rb
index 3f4612ebe5..1c1dda76bc 100644
--- a/lib/parsedate.rb
+++ b/lib/parsedate.rb
@@ -14,26 +14,26 @@ module ParseDate
time = $1
end
if date =~ /19(\d\d)/
- year = $1
+ year = Integer($1)
end
if date.sub!(/\s*(\d+)\s+(#{MONTHPAT})\S*\s+/i, ' ')
- dayofmonth = $1
+ dayofmonth = $1.to_i
monthname = $2
elsif date.sub!(/\s*(#{MONTHPAT})\S*\s+(\d+)\s+/i, ' ')
monthname = $1
- dayofmonth = $2
+ dayofmonth = $2.to_i
elsif date.sub!(/\s*(#{MONTHPAT})\S*\s+(\d+)\D+/i, ' ')
monthname = $1
- dayofmonth = $2
+ dayofmonth = $2.to_i
elsif date.sub!(/\s*(\d\d?)\/(\d\d?)/, ' ')
month = $1
- dayofmonth = $2
+ dayofmonth = $2.to_i
end
if monthname
month = MONTHS[monthname.downcase]
end
if ! year && date =~ /\d\d/
- year = $&
+ year = Integer($&)
end
return year, month, dayofmonth
end
diff --git a/lib/ping.rb b/lib/ping.rb
new file mode 100644
index 0000000000..d742a50f99
--- /dev/null
+++ b/lib/ping.rb
@@ -0,0 +1,55 @@
+#
+# ping.rb -- check a host for upness
+#
+#= SYNOPSIS
+#
+# require 'ping'
+# print "'jimmy' is alive and kicking\n" if Ping.pingecho('jimmy', 10) ;
+#
+#= DESCRIPTION
+#
+# This module contains routines to test for the reachability of remote hosts.
+# Currently the only routine implemented is pingecho().
+#
+# pingecho() uses a TCP echo (I<not> an ICMP one) to determine if the
+# remote host is reachable. This is usually adequate to tell that a remote
+# host is available to rsh(1), ftp(1), or telnet(1) onto.
+#
+#== Parameters
+#
+# : hostname
+#
+# The remote host to check, specified either as a hostname or as an
+# IP address.
+#
+# : timeout
+#
+# The timeout in seconds. If not specified it will default to 5 seconds.
+#
+#= WARNING
+#
+# pingecho() uses user-level thread to implement the timeout, so it may block
+# for long period if named does not respond for some reason.
+#
+#=end
+
+module Ping
+ require "socket"
+ def pingecho(host, timeout=5)
+ begin
+ x = Thread.current
+ y = Thread.start {
+ sleep timeout
+ x.raise RuntimeError if x.status
+ }
+ s = TCPsocket.new(host, "echo")
+ s.close
+ return TRUE
+ rescue
+ return FALSE;
+ ensure
+ Thread.kill y if y.status
+ end
+ end
+ module_function "pingecho"
+end
diff --git a/lib/safe.rb b/lib/safe.rb
deleted file mode 100644
index 7c95555495..0000000000
--- a/lib/safe.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-# this is a safe-mode for ruby, which is still incomplete.
-
-unless defined? SecurityError
- class SecurityError<Exception
- end
-end
-
-module Restricted
-
- printf STDERR, "feel free for some warnings:\n" if $VERBOSE
- module Bastion
- include Restricted
- extend Restricted
- BINDING = binding
- def Bastion.to_s; "main" end
- end
-
- class R_File<File
- NG_FILE_OP = []
- def R_File.open(*args)
- raise SecurityError, "can't use File.open() in safe mode" #'
- end
- end
-
- IO = nil
- File = R_File
- FileTest = nil
- Dir = nil
- ObjectSpace = nil
-
- def eval(string)
- begin
- super(string, Bastion::BINDING)
- rescue
- $@ = caller
- raise
- end
- end
- module_function :eval
-
- DEFAULT_SECURITY_MANAGER = Object.new
-
- def Restricted.set_securuty_manager(sec_man)
- if @sec_man
- raise SecurityError, "cannot change security manager"
- end
- @sec_man = sec_man
- end
-
- def Restricted.securuty_manager
- return @sec_man if @sec_man
- return DEFAULT_SECURITY_MANAGER
- end
-
- for cmd in ["test", "require", "load", "open", "system"]
- eval format("def DEFAULT_SECURITY_MANAGER.%s(*args)
- raise SecurityError, \"can't use %s() in safe mode\"
- end", cmd, cmd) #'
- eval format("def %s(*args)
- Restricted.securuty_manager.%s(*args)
- end", cmd, cmd)
- end
-
- def `(arg) #`
- Restricted.securuty_manager.send(:`, arg) #`)
- end
-
- def DEFAULT_SECURITY_MANAGER.`(arg) #`
- raise SecurityError, "can't use backquote(``) in safe mode"
- end
-end
-
-if $DEBUG
- p eval("File.open('/dev/null')")
- p Restricted.eval("self")
- p Restricted.eval("open('/dev/null')")
- p Restricted.eval("File.open('/dev/null')")
-end
diff --git a/lib/sync.rb b/lib/sync.rb
new file mode 100644
index 0000000000..fd18291ca9
--- /dev/null
+++ b/lib/sync.rb
@@ -0,0 +1,376 @@
+#
+# sync.rb - 2-եå饹
+# $Release Version: 0.1$
+# $Revision: 1.3 $
+# $Date: 1997/08/18 07:17:08 $
+# by Keiju ISHITSUKA
+#
+# --
+# Usage:
+# Sync_m, Synchronizer_m
+#
+# Sync_m#sync_mode
+# Sync_m#sync_locked?, locked?
+# Sync_m#sync_shared?, shared?
+# Sync_m#sync_exclusive?, sync_exclusive?
+# Sync_m#sync_try_lock, try_lock
+# Sync_m#sync_lock, lock
+# Sync_m#sync_unlock, unlock
+#
+# Sync, Synchronicer:
+# include Sync_m
+#
+# sync = Sync.new
+# Sync#mode
+# Sync#locked?
+# Sync#shared?
+# Sync#exclusive?
+# Sync#try_lock(mode) -- mode = :EX, :SH, :UN
+# Sync#lock(mode) -- mode = :EX, :SH, :UN
+# Sync#unlock
+# Sync#synchronize(mode) {...}
+#
+#
+
+unless defined? Thread
+ fail "Thread not available for this ruby interpreter"
+end
+
+require "finalize.rb"
+
+module Sync_m
+ RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/RCS/sync.rb,v 1.3 1997/08/18 07:17:08 keiju Exp keiju $-'
+
+ UN = :UN
+ SH = :SH
+ EX = :EX
+
+ class Err < Exception
+ def Err.Fail(*opt)
+ fail self, sprintf(self::Message, *opt)
+ end
+
+ class UnknownLocker < Err
+ Message = "Thread(%s) not locked."
+ def UnknownLocker.Fail(th)
+ super(th.inspect)
+ end
+ end
+
+ class LockModeFailer < Err
+ Message = "Unknown lock mode(%s)"
+ def LockModeFailer.Fail(mode)
+ if mode.id2name
+ mode = id2name
+ end
+ super(mode)
+ end
+ end
+ end
+
+ def Sync_m.extend_object(obj)
+ if Fixnum === obj or TRUE === obj or FALSE === obj or nil == obj
+ raise TypeError, "Sync_m can't extend to this class(#{obj.type})"
+ else
+ begin
+ eval "class << obj
+ @sync_locked
+ end"
+ obj.extend(For_primitive_object)
+ rescue TypeError
+ obj.extend(For_general_object)
+ end
+ end
+ end
+
+ def sync_extended
+ unless (defined? locked? and
+ defined? shared? and
+ defined? exclusive? and
+ defined? lock and
+ defined? unlock and
+ defined? try_lock and
+ defined? synchronize)
+ eval "class << self
+ alias locked? sync_locked?
+ alias shared? sync_shared?
+ alias excluive? sync_exclusive?
+ alias lock sync_lock
+ alias unlock sync_unlock
+ alias try_lock sync_try_lock
+ alias synchronize sync_synchronize
+ end"
+ end
+ end
+
+ def sync_locked?
+ sync_mode != UN
+ end
+
+ def sync_shared?
+ sync_mode == SH
+ end
+
+ def sync_exclusive?
+ sync_mode == EX
+ end
+
+ def sync_try_lock(mode = EX)
+ return unlock if sync_mode == UN
+
+ Thread.critical = TRUE
+ ret = sync_try_lock_sub(sync_mode)
+ Thread.critical = FALSE
+ ret
+ end
+
+ def sync_lock(m = EX)
+ return unlock if m == UN
+
+ until (Thread.critical = TRUE; sync_try_lock_sub(m))
+ if sync_sh_locker[Thread.current]
+ sync_upgrade_waiting.push [Thread.current, sync_sh_locker[Thread.current]]
+ sync_sh_locker.delete(Thread.current)
+ else
+ sync_waiting.push Thread.current
+ end
+ Thread.stop
+ end
+ Thread.critical = FALSE
+ self
+ end
+
+ def sync_unlock(m = EX)
+ Thread.critical = TRUE
+ if sync_mode == UN
+ Thread.critical = FALSE
+ Err::UnknownLocker.Fail(Thread.current)
+ end
+
+ m = sync_mode if m == EX and sync_mode == SH
+
+ runnable = FALSE
+ case m
+ when UN
+ Thread.critical = FALSE
+ Err::UnknownLocker.Fail(Thread.current)
+
+ when EX
+ if sync_ex_locker == Thread.current
+ if (self.sync_ex_count = sync_ex_count - 1) == 0
+ self.sync_ex_locker = nil
+ if sync_sh_locker.include?(Thread.current)
+ self.sync_mode = SH
+ else
+ self.sync_mode = UN
+ end
+ runnable = TRUE
+ end
+ else
+ Err::UnknownLocker.Fail(Thread.current)
+ end
+
+ when SH
+ if (count = sync_sh_locker[Thread.current]).nil?
+ Err::UnknownLocker.Fail(Thread.current)
+ else
+ if (sync_sh_locker[Thread.current] = count - 1) == 0
+ sync_sh_locker.delete(Thread.current)
+ if sync_sh_locker.empty? and sync_ex_count == 0
+ self.sync_mode = UN
+ runnable = TRUE
+ end
+ end
+ end
+ end
+
+ if runnable
+ if sync_upgrade_waiting.size > 0
+ for k, v in sync_upgrade_waiting
+ sync_sh_locker[k] = v
+ end
+ wait = sync_upgrade_waiting
+ self.sync_upgrade_waiting = []
+ Thread.critical = FALSE
+
+ for w, v in wait
+ w.run
+ end
+ else
+ wait = sync_waiting
+ self.sync_waiting = []
+ Thread.critical = FALSE
+ for w in wait
+ w.run
+ end
+ end
+ end
+
+ Thread.critical = FALSE
+ self
+ end
+
+ def sync_try_lock_sub(m)
+ case m
+ when SH
+ case sync_mode
+ when UN
+ self.sync_mode = m
+ sync_sh_locker[Thread.current] = 1
+ ret = TRUE
+ when SH
+ count = 0 unless count = sync_sh_locker[Thread.current]
+ sync_sh_locker[Thread.current] = count + 1
+ ret = TRUE
+ when EX
+ # , ⡼ɤEXǤ, ɬEXåȤʤ.
+ if sync_ex_locker == Thread.current
+ self.sync_ex_count = sync_ex_count + 1
+ ret = TRUE
+ else
+ ret = FALSE
+ end
+ end
+ when EX
+ if sync_mode == UN or
+ sync_mode == SH && sync_sh_locker.size == 1 && sync_sh_locker.include?(Thread.current)
+ self.sync_mode = m
+ self.sync_ex_locker = Thread.current
+ self.sync_ex_count = 1
+ ret = TRUE
+
+ elsif sync_mode == EX && sync_ex_locker == Thread.current
+ self.sync_ex_count = sync_ex_count + 1
+ ret = TRUE
+ else
+ ret = FALSE
+ end
+ else
+ Thread.critical = FALSE
+ Err::LockModeFailer.Fail mode
+ end
+ return ret
+ end
+ private :sync_try_lock_sub
+
+ def sync_synchronize(mode = EX)
+ begin
+ sync_lock(mode)
+ yield
+ ensure
+ sync_unlock
+ end
+ end
+
+ module For_primitive_object
+ include Sync_m
+
+ LockState = Struct.new("LockState",
+ :mode,
+ :waiting,
+ :upgrade_waiting,
+ :sh_locker,
+ :ex_locker,
+ :ex_count)
+
+ Sync_Locked = Hash.new
+
+ def For_primitive_object.extend_object(obj)
+ super
+ obj.sync_extended
+ Finalizer.add(obj, For_primitive_object, :sync_finalize)
+ end
+
+ def sync_extended
+ super
+ Sync_Locked[id] = LockState.new(UN, [], [], Hash.new, nil, 0 )
+ end
+
+ def sync_finalize
+ wait = Sync_Locked.delete(id)
+ # waiting == [] Ȥ GCΤ, Ԥβϰ̣ʤ.
+ end
+
+ def sync_mode
+ Sync_Locked[id].mode
+ end
+ def sync_mode=(value)
+ Sync_Locked[id].mode = value
+ end
+
+ def sync_waiting
+ Sync_Locked[id].waiting
+ end
+ def sync_waiting=(v)
+ Sync_Locked[id].waiting = v
+ end
+
+ def sync_upgrade_waiting
+ Sync_Locked[id].upgrade_waiting
+ end
+ def sync_upgrade_waiting=(v)
+ Sync_Locked[id].upgrade_waiting = v
+ end
+
+ def sync_sh_locker
+ Sync_Locked[id].sh_locker
+ end
+ def sync_sh_locker=(v)
+ Sync_Locked[id].sh_locker = v
+ end
+
+ def sync_ex_locker
+ Sync_Locked[id].ex_locker
+ end
+ def sync_ex_locker=(value)
+ Sync_Locked[id].ex_locker = value
+ end
+
+ def sync_ex_count
+ Sync_Locked[id].ex_count
+ end
+ def sync_ex_count=(value)
+ Sync_Locked[id].ex_count = value
+ end
+
+ end
+
+ module For_general_object
+ include Sync_m
+
+ def For_general_object.extend_object(obj)
+ super
+ obj.sync_extended
+ end
+
+ def sync_extended
+ super
+ @sync_mode = UN
+ @sync_waiting = []
+ @sync_upgrade_waiting = []
+ @sync_sh_locker = Hash.new
+ @sync_ex_locker = nil
+ @sync_ex_count = 0
+ end
+
+ attr :sync_mode, TRUE
+
+ attr :sync_waiting, TRUE
+ attr :sync_upgrade_waiting, TRUE
+ attr :sync_sh_locker, TRUE
+ attr :sync_ex_locker, TRUE
+ attr :sync_ex_count, TRUE
+
+ end
+end
+Synchronizer_m = Sync_m
+
+class Sync
+ include Sync_m::For_general_object
+
+ def initialize
+ sync_extended
+ end
+
+end
+Synchronizer = Sync
diff --git a/lib/thread.rb b/lib/thread.rb
index c3347b60b4..30f77ddbeb 100644
--- a/lib/thread.rb
+++ b/lib/thread.rb
@@ -24,27 +24,37 @@ class Mutex
end
def try_lock
- Thread.exclusive do
- if not @locked
- @locked=TRUE
- return TRUE
- end
+ result = FALSE
+ Thread.critical = TRUE
+ unless @locked
+ @locked = TRUE
+ result = TRUE
end
- FALSE
+ Thread.critical = FALSE
+ result
end
def lock
- while not try_lock
+ while (Thread.critical = TRUE; @locked)
@waiting.push Thread.current
Thread.stop
end
+ @locked = TRUE
+ Thread.critical = FALSE
+ self
end
def unlock
+ return unless @locked
+ Thread.critical = TRUE
+ wait = @waiting
+ @waiting = []
@locked = FALSE
- if w = @waiting.shift
+ Thread.critical = FALSE
+ for w in wait
w.run
end
+ self
end
def synchronize
@@ -57,37 +67,6 @@ class Mutex
end
end
-class SharedMutex<Mutex
- def initialize
- @locking = nil
- @num_locks = 0;
- super
- end
- def try_lock
- if @locking == Thread.current
- @num_locks += 1
- return TRUE
- end
- if super
- @num_locks = 1
- @locking = Thread.current
- TRUE
- else
- FALSE
- end
- end
- def unlock
- unless @locking == Thread.current
- raise ThreadError, "cannot release shared mutex"
- end
- @num_locks -= 1
- if @num_locks == 0
- @locking = nil
- super
- end
- end
-end
-
class Queue
def initialize
@que = []
@@ -95,19 +74,30 @@ class Queue
end
def push(obj)
+ Thread.critical = TRUE
@que.push obj
- if t = @waiting.shift
- t.run
- end
+ t = @waiting.shift
+ Thread.critical = FALSE
+ t.run if t
end
def pop non_block=FALSE
- if @que.length == 0
- raise ThreadError, "queue empty" if non_block
- @waiting.push Thread.current
- Thread.stop
+ item = nil
+ until item
+ Thread.critical = TRUE
+ if @que.length == 0
+ if non_block
+ Thread.critical = FALSE
+ raise ThreadError, "queue empty"
+ end
+ @waiting.push Thread.current
+ Thread.stop
+ else
+ item = @que.shift
+ end
end
- @que.shift
+ Thread.critical = FALSE
+ item
end
def empty?
@@ -118,36 +108,3 @@ class Queue
@que.length
end
end
-
-class Condition
- def initialize
- @waiting = []
- end
-
- def wait(mut)
- Thread.exclusive do
- mut.unlock
- @waiting.push Thread.current
- end
- Thread.sleep
- mut.lock
- end
-
- def signal
- th = nil
- Thread.exclusive do
- th = @waiting.pop
- end
- th.run
- end
-
- def broadcast
- w = @waiting
- Thread.exclusive do
- th = []
- end
- for th in w
- th.run
- end
- end
-end
diff --git a/lib/thwait.rb b/lib/thwait.rb
new file mode 100644
index 0000000000..c638335f5d
--- /dev/null
+++ b/lib/thwait.rb
@@ -0,0 +1,128 @@
+#
+# thwait.rb -
+# $Release Version: $
+# $Revision: 1.1 $
+# $Date: 1997/08/18 03:13:14 $
+# by Keiju ISHITSUKA(Nippon Rational Inc.)
+#
+# --
+#
+#
+#
+
+require "thread.rb"
+require "e2mmap.rb"
+
+class ThreadsWait
+ RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/RCS/thwait.rb,v 1.1 1997/08/18 03:13:14 keiju Exp keiju $-'
+
+ Exception2MessageMapper.extend_to(binding)
+ def_exception("ErrWaitThreadsNothing", "Wait threads nothing.")
+ def_exception("FinshedThreadsNothing", "finished thread nothing.")
+
+ # class mthods
+ # all_waits
+
+ #
+ # ꤷåɤƽλޤԤ. ƥ졼ȤƸƤФ
+ # ꤷåɤλȥƥ졼ƤӽФ.
+ #
+ def ThreadsWait.all_waits(*threads)
+ tw = ThreadsWait.new(th1, th2, th3, th4, th5)
+ if iterator?
+ tw.all_waits do
+ |th|
+ yield th
+ end
+ else
+ tw.all_waits
+ end
+ end
+
+ # initialize and terminating:
+ # initialize
+
+ #
+ # . Ԥĥåɤλ꤬Ǥ.
+ #
+ def initialize(*threads)
+ @threads = []
+ @wait_queue = Queue.new
+ join_nowait(*threads) unless threads.empty?
+ end
+
+ # accessing
+ # threads
+
+ # Ԥåɤΰ֤.
+ attr :threads
+
+ # testing
+ # empty?
+ # finished?
+ #
+
+ #
+ # Ԥåɤ¸ߤ뤫ɤ֤.
+ def empty?
+ @threads.empty?
+ end
+
+ #
+ # Ǥ˽λåɤ뤫ɤ֤
+ def finished?
+ !@wait_queue.empty?
+ end
+
+ # main process:
+ # join
+ # join_nowait
+ # next_wait
+ # all_wait
+
+ #
+ # ԤäƤ륹åɤɲäԤˤϤ.
+ #
+ def join(*threads)
+ join_nowait(*threads)
+ next_wait
+ end
+
+ #
+ # ԤäƤ륹åɤɲä. Ԥˤʤ.
+ #
+ def join_nowait(*threads)
+ @threads.concat threads
+ for th in threads
+ Thread.start do
+ th = Thread.join(th)
+ @wait_queue.push th
+ end
+ end
+ end
+
+ #
+ # ԤˤϤ.
+ # ԤĤ٤åɤʤ, 㳰ErrWaitThreadsNothing ֤.
+ # nonnlockλˤ, nonblockingĴ٤. ¸ߤʤ, 㳰
+ # FinishedThreadNothing֤.
+ #
+ def next_wait(nonblock = nil)
+ Threads.Wait.fail ErrWaitThreadsNothing if @threads.empty?
+
+ th = @wait_queue.pop(nonblock)
+ @threads.delete th
+ th
+ end
+
+ #
+ # ƤΥåɤλޤԤ. ƥ졼ȤƸƤФ줿,
+ # åɤλ٤, ƥ졼ƤӽФ.
+ #
+ def all_waits
+ until @threads.empty?
+ th = next_wait
+ yield th if iterator?
+ end
+ end
+end
diff --git a/lib/tk.rb b/lib/tk.rb
index 237408a77a..48a3940fcc 100644
--- a/lib/tk.rb
+++ b/lib/tk.rb
@@ -345,7 +345,7 @@ class TkObject<TkKernel
def configure(slot, value)
if value == FALSE
value = "0"
- elsif value.type == Proc
+ elsif value.kind_of? Proc
value = install_cmd(value)
end
tk_call path, 'configure', "-#{slot}", value
@@ -358,6 +358,61 @@ class TkObject<TkKernel
def bind(context, cmd=Proc.new, args=nil)
_bind path, context, cmd, args
end
+
+ def tk_trace_variable(v)
+ unless v.kind_of?(TkVariable)
+ fail ArgumentError, format("requires TkVariable given %s", v.type)
+ end
+ v
+ end
+ private :tk_trace_variable
+
+ def destroy
+ tk_call 'trace', 'vdelete', @tk_vn, 'w', @var_id if @var_id
+ end
+end
+
+
+class TkVariable
+ include Tk
+ $tk_variable_id = "v00000"
+ def initialize(val="")
+ @id = $tk_variable_id
+ $tk_variable_id = $tk_variable_id.succ
+ tk_call(format('global %s; set %s', @id, @id), val)
+ end
+
+ def id
+ @id
+ end
+
+ def value
+ tk_call(format('global %s; set', @id), @id)
+ end
+
+ def value=(val)
+ tk_call(format('global %s; set %s', @id, @id), val)
+ end
+
+ def to_i
+ Integer(number(value))
+ end
+
+ def to_f
+ Float(number(value))
+ end
+
+ def to_s
+ String(string(value))
+ end
+
+ def inspect
+ format "<TkVariable: %s>", @id
+ end
+
+ def to_a
+ list(value)
+ end
end
class TkWindow<TkObject
@@ -391,6 +446,36 @@ class TkWindow<TkObject
self
end
+ def place(keys = nil)
+ tk_call 'place', epath, *hash_kv(keys)
+ self
+ end
+
+ def unplace(keys = nil)
+ tk_call 'place', 'forget', epath, *hash_kv(keys)
+ self
+ end
+ alias place_forget unplace
+
+ def place_config(keys)
+ tk_call "place", 'configure', epath, *hash_kv(keys)
+ end
+
+ def place_info()
+ ilist = list(tk_call('place', 'info', epath))
+ info = {}
+ while key = ilist.shift
+ info[key[1,-1]] = ilist.shift
+ end
+ return info
+ end
+
+ def place_slaves()
+ list(tk_call('place', 'slaves', epath)).collect { |w|
+ window(w)
+ }
+ end
+
def focus
tk_call 'focus', path
self
@@ -426,7 +511,7 @@ class TkWindow<TkObject
self
end
- def command(cmd)
+ def command(cmd=Proc.new)
configure_cmd 'command', cmd
end
@@ -443,6 +528,7 @@ class TkWindow<TkObject
end
end
$tk_window_list[path] = nil
+ super
end
end
@@ -486,14 +572,7 @@ class TkLabel<TkWindow
tk_call 'label', @path
end
def textvariable(v)
- v = v.id2name unless v.kind_of? String
- vn = @path + v
- vset = format("global {%s}; set {%s} %%s", vn, vn)
- tk_write vset, eval(v).inspect
- trace_var v, proc{|val|
- tk_write vset, val.inspect
- }
- configure 'textvariable', vn
+ configure 'textvariable', tk_trace_variable(v)
end
end
@@ -520,26 +599,7 @@ class TkRadioButton<TkButton
tk_send 'select'
end
def variable(v)
- v = v.id2name unless v.kind_of? String
- if v =~ /^\$/
- v = $'
- else
- fail ArgumentError, "variable must be global(%s)", v
- end
- vn = 'btns_selected_' + v
- trace_var v, proc{|val|
- tk_write 'global %s; set %s %s', vn, val
- }
- @var_id = install_cmd(proc{|name1,|
- val = tk_call(format('global %s; set', name1), name1)
- eval(format("%s = '%s'", v.id2name, val))
- })
- tk_call 'trace', 'variable', vn, 'w', @var_id
- configure 'variable', vn
- end
- def destroy
- tk_call 'trace vdelete', vn, 'w', @var_id
- super
+ configure 'variable', tk_trace_variable(v)
end
end
@@ -678,7 +738,7 @@ class TkMenu<TkWindow
tk_send 'activate', index
end
def add(type, keys=nil)
- tk_send 'add', type, *kv_hash(keys)
+ tk_send 'add', type, *hash_kv(keys)
end
def index(index)
tk_send 'index', index
@@ -686,8 +746,8 @@ class TkMenu<TkWindow
def invoke
tk_send 'invoke'
end
- def insert(index, type, keys=nil)
- tk_send 'add', index, type, *kv_hash(keys)
+ def insert(index, type, *keys)
+ tk_send 'add', index, type, *hash_kv(keys)
end
def post(x, y)
tk_send 'post', x, y
@@ -695,7 +755,7 @@ class TkMenu<TkWindow
def postcascade(index)
tk_send 'postcascade', index
end
- def postcommand(cmd)
+ def postcommand(cmd=Proc.new)
configure_cmd 'postcommand', cmd
end
def menutype(index)
diff --git a/lib/tkcanvas.rb b/lib/tkcanvas.rb
index b0ae8b1daa..46acd8c9d7 100644
--- a/lib/tkcanvas.rb
+++ b/lib/tkcanvas.rb
@@ -110,11 +110,11 @@ class TkCanvas<TkWindow
def select(*args)
tk_send 'select', *args
end
- def xview(index)
- tk_send 'xview', index
+ def xview(*index)
+ tk_send 'xview', *index
end
- def yview(index)
- tk_send 'yview', index
+ def yview(*index)
+ tk_send 'yview', *index
end
end
@@ -125,12 +125,12 @@ class TkcItem<TkObject
end
@c = parent
@path = parent.path
- if args[-1].type == Hash
+ if args[-1].kind_of? Hash
keys = args.pop
end
@id = create_self(*args)
if keys
- tk_call @path, 'itemconfigure', *hash_kv(keys)
+ tk_call @path, 'itemconfigure', @id, *hash_kv(keys)
end
end
def create_self(*args) end
@@ -226,6 +226,11 @@ class TkcPolygon<TkcItem
tk_call(@path, 'create', 'polygon', *args)
end
end
+class TkcRectangle<TkcItem
+ def create_self(*args)
+ tk_call(@path, 'create', 'rectangle', *args)
+ end
+end
class TkcText<TkcItem
def create_self(*args)
tk_call(@path, 'create', 'text', *args)
@@ -272,7 +277,7 @@ class TkImage<TkObject
def initialize(keys=nil)
@path = $tk_image_id
$tk_image_id = $tk_image_id.succ
- tk_call 'image', @type, @path, *hash_kv(keys)
+ tk_call 'image', 'create', @type, @path, *hash_kv(keys)
end
def height
@@ -302,7 +307,7 @@ end
class TkPhotoImage<TkImage
def initialize(*args)
- @type = 'bitmap'
+ @type = 'photo'
super
end
diff --git a/lib/tkclass.rb b/lib/tkclass.rb
index 10ecc80b20..17f57f581d 100644
--- a/lib/tkclass.rb
+++ b/lib/tkclass.rb
@@ -25,11 +25,13 @@ Bitmap = TkcBitmap
Line = TkcLine
Oval = TkcOval
Polygon = TkcPolygon
+Rectangle = TkcRectangle
TextItem = TkcText
WindowItem = TkcWindow
Selection = TkSelection
Winfo = TkWinfo
Pack = TkPack
+Variable = TkVariable
def Mainloop
Tk.mainloop
diff --git a/lib/tkcore.rb b/lib/tkcore.rb
index 018e140ef0..9fd2c88efc 100644
--- a/lib/tkcore.rb
+++ b/lib/tkcore.rb
@@ -22,7 +22,7 @@ module Tk
break if wish_path
end
}
- fail 'can\'t find wish' if not wish_path
+ fail 'can\'t find wish' if not wish_path #'
def Tk.tk_exit
if not PORT.closed?
@@ -31,7 +31,8 @@ module Tk
end
end
- PORT = open(format("|%s -n %s", wish_path, File.basename($0)), "w+");
+# PORT = open(format("|%s -n %s", wish_path, File.basename($0)), "w+");
+ PORT = open(format("|%s", wish_path), "w+");
trap "EXIT", proc{Tk.tk_exit}
trap "PIPE", ""
@@ -46,8 +47,8 @@ proc rb_out args {
puts [format %%s $args]
flush stdout
}
-proc rb_ans args {
- if [catch "$args" var] {puts "!$var"} {puts "=$var@@"}
+proc rb_ans arg {
+ if [catch $arg var] {puts "!$var"} {puts "=$var@@"}
flush stdout
}
proc tkerror args { exit }
@@ -85,12 +86,11 @@ after 120000 keepalive'
}
def error_at
- n = 1
- while c = caller(n)
- break if c !~ /tk\.rb:/
- n+=1
+ frames = caller(1)
+ frames.delete_if do |c|
+ c =~ %r!/tk(|core|thcore|canvas|text|entry|scrollbox)\.rb:\d+!
end
- c
+ frames
end
def tk_tcl2ruby(val)
@@ -197,17 +197,21 @@ after 120000 keepalive'
s = "1"
elsif s.kind_of?(TkObject)
s = s.path
+ elsif s.kind_of?(TkVariable)
+ s = s.id
else
s = s.to_s
- s.gsub!(/[{}]/, '\\\\\0')
+ s.gsub!(/["\\\$\[\]]/, '\\\\\0') #"
+ s.gsub!(/\{/, '\\\\173')
+ s.gsub!(/\}/, '\\\\175')
end
- "{#{s}}"
+ "\"#{s}\""
end
}
str += " "
str += args.join(" ")
print str, "\n" if $DEBUG
- tk_write 'rb_ans %s', str
+ tk_write 'rb_ans {%s}', str
while PORT.gets
print $_ if $DEBUG
$_.chop!
@@ -229,10 +233,12 @@ after 120000 keepalive'
$@ = error_at
msg = $'
if msg =~ /unknown option "-(.*)"/
- fail NameError, format("undefined method `%s' for %s(%s)", $1, self, self.type) #`'
+ $! = NameError.new(format("undefined method `%s' for %s(%s)",
+ $1, self, self.type)) #`'
else
- fail format("%s - %s", self.type, msg)
+ $! = RuntimeError.new(format("%s - %s", self.type, msg))
end
+ fail
end
$tk_event_queue.push $_
end
@@ -250,7 +256,7 @@ after 120000 keepalive'
if keys
for k, v in keys
conf.push("-#{k}")
- v = install_cmd(v) if v.type == Proc
+ v = install_cmd(v) if v.kind_of? Proc
conf.push(v)
end
end
@@ -415,10 +421,10 @@ after 120000 keepalive'
module_function :after, :update, :dispatch, :mainloop, :root, :bell
module Scrollable
- def xscrollcommand(cmd)
+ def xscrollcommand(cmd=Proc.new)
configure_cmd 'xscrollcommand', cmd
end
- def yscrollcommand(cmd)
+ def yscrollcommand(cmd=Proc.new)
configure_cmd 'yscrollcommand', cmd
end
end
diff --git a/lib/tkentry.rb b/lib/tkentry.rb
index 9a03c34058..7c13e3bdb1 100644
--- a/lib/tkentry.rb
+++ b/lib/tkentry.rb
@@ -14,11 +14,7 @@ class TkEntry<TkLabel
end
def delete(s, e=None)
- if e
- tk_send 'delete', s
- else
- tk_send 'delete', s, e
- end
+ tk_send 'delete', s, e
end
def cursor
@@ -28,13 +24,10 @@ class TkEntry<TkLabel
tk_send 'icursor', index
end
def index(index)
- tk_send 'index', index
+ number(tk_send('index', index))
end
- def insert(text, pos=None)
- if pos
- tk_send 'icursor', pos
- end
- tk_send 'insert', 'insert', text
+ def insert(pos,text)
+ tk_send 'insert', pos, text
end
def mark(pos)
tk_send 'scan', 'mark', pos
diff --git a/lib/tkscrollbox.rb b/lib/tkscrollbox.rb
index b8dbe9b236..76844ed90a 100644
--- a/lib/tkscrollbox.rb
+++ b/lib/tkscrollbox.rb
@@ -18,8 +18,8 @@ class TkScrollbox<TkListbox
scroll.configure 'command', list.path+" yview"
scroll.pack 'side'=>'right','fill'=>'y'
- delegate('DEFALUT', list)
- delegate('foreground', list, scroll)
+ delegate('DEFAULT', list)
+ delegate('foreground', list)
delegate('background', list, scroll)
delegate('borderwidth', @frame)
delegate('relief', @frame)
diff --git a/lib/tktext.rb b/lib/tktext.rb
index 55e396c497..91a60529d1 100644
--- a/lib/tktext.rb
+++ b/lib/tktext.rb
@@ -24,10 +24,9 @@ class TkText<TkTextWin
def _addcmd(cmd)
@cmdtbl.push id
end
- def _addtag(cmd)
- @cmdtbl.push id
+ def _addtag(name, obj)
+ @tags[name] = obj
end
- private :_addcmd, :_addtag
def tag_names
tk_send('tag', 'names').collect{|elt|
if not @tags[elt]
@@ -75,18 +74,25 @@ class TkText<TkTextWin
def yview_pickplace(*what)
tk_send 'yview', '-pickplace', *what
end
+
+ def xview(*what)
+ tk_send 'xview', *what
+ end
+ def xview_pickplace(*what)
+ tk_send 'xview', '-pickplace', *what
+ end
end
class TkTextTag<TkObject
$tk_text_tag = 'tag0000'
- def initialize(parent)
+ def initialize(parent, keys=nil)
if not parent.kind_of?(TkText)
fail format("%s need to be TkText", parent.inspect)
end
@t = parent
- @path = parent.path
- @id = $tk_text_tag
+ @path = @id = $tk_text_tag
$tk_text_tag = $tk_text_tag.succ
+ tk_call @t.path, "tag", "configure", @id, *hash_kv(keys)
@t._addtag id, self
end
def id
@@ -94,25 +100,25 @@ class TkTextTag<TkObject
end
def add(*index)
- tk_call path, 'tag', 'add', @id, *index
+ tk_call @t.path, 'tag', 'add', @id, *index
end
- def configure(slot, value)
- tk_call path, 'tag', 'configure', id, "-#{slot}", value
+ def configure(keys)
+ tk_call @t.path, 'tag', 'configure', @id, *hash_kv(keys)
end
def bind(seq, cmd=Proc.new)
id = install_cmd(cmd)
- tk_call path, 'tag', 'bind', tag, "<#{seq}>", id
+ tk_call @t, 'tag', 'bind', tag, "<#{seq}>", id
@t._addcmd cmd
end
def lower(below=None)
- tk_call path, 'tag', 'lower', below
+ tk_call @t.path, 'tag', 'lower', below
end
def destroy
- tk_call path, 'tag', 'delete', @id
+ tk_call @t.path, 'tag', 'delete', @id
end
end
@@ -123,10 +129,9 @@ class TkTextMark<TkObject
fail format("%s need to be TkText", parent.inspect)
end
@t = parent
- @path = parent.path
- @id = $tk_text_mark
+ @path = @id = $tk_text_mark
$tk_text_mark = $tk_text_mark.succ
- tk_call @t, 'set', @id, index
+ tk_call @t.path, 'set', @id, index
@t._addtag id, self
end
def id
@@ -134,11 +139,11 @@ class TkTextMark<TkObject
end
def set(where)
- tk_call path, 'mark', 'unset', @id, where
+ tk_call @t.path, 'mark', 'unset', @id, where
end
def unset
- tk_call path, 'mark', 'unset', @id
+ tk_call @t.path, 'mark', 'unset', @id
end
alias destroy unset
end
@@ -149,12 +154,11 @@ class TkTextWindow<TkObject
fail format("%s need to be TkText", parent.inspect)
end
@t = parent
- @path = parent.path
- @index = index
- tk_call @path, 'window', 'create', index, *args
+ @path = @index = index
+ tk_call @t.path, 'window', 'create', index, *args
end
def configure(slot, value)
- tk_call path, 'window', 'configure', @index, "-#{slot}", value
+ tk_call @t.path, 'window', 'configure', @index, "-#{slot}", value
end
end
diff --git a/lib/tkthcore.rb b/lib/tkthcore.rb
index 5e0abd72c5..b89850cb73 100644
--- a/lib/tkthcore.rb
+++ b/lib/tkthcore.rb
@@ -30,7 +30,7 @@ module Tk
break if wish_path
end
}
- fail 'can\'t find wish' if not wish_path
+ fail 'can\'t find wish' if not wish_path #'
# mark for non-given arguments
None = Object.new
@@ -66,9 +66,10 @@ module Tk
ary = [PORT]
loop do
str = Qin.pop
- print str, "\n" if $DEBUG
+ print "Qin: ", str, "\n" if $DEBUG
tk_write 'if [catch {%s} var] {puts "!$var"} {puts "=$var@@"};flush stdout', str
- Qout.push(tk_recv)
+ line = tk_recv
+ Qout.push(line)
end
end
end
@@ -89,7 +90,7 @@ module Tk
val += $'
return val
else
- v>al += $_
+ val += $_
end
end
elsif /^!/
@@ -101,7 +102,6 @@ module Tk
fail format("%s - %s", self.type, msg)
end
end
- Qcmd.push line
end
fail 'wish closed' if PORT.closed?
@@ -122,11 +122,15 @@ module Tk
s = "1"
elsif s.kind_of?(TkObject)
s = s.path
+ elsif s.kind_of?(TkVariable)
+ s = s.id
else
s = s.to_s
- s.gsub!(/[{}]/, '\\\\\0')
+ s.gsub!(/["\\\$\[\]]/, '\\\\\0') #"
+ s.gsub!(/\{/, '\\\\173')
+ s.gsub!(/\}/, '\\\\175')
end
- "{#{s}}"
+ "\"#{s}\""
end
}
str += " "
@@ -240,12 +244,11 @@ after 120000 keepalive'
module_function :dispatch
def error_at
- n = 1
- while c = caller(n)
- break if c !~ /tk\.rb:/
- n+=1
+ frames = caller(1)
+ frames.delete_if do |c|
+ c =~ %r!/tk(|core|thcore|canvas|text|entry|scrollbox)\.rb:\d+!
end
- c
+ frames
end
def bool(val)
@@ -295,7 +298,7 @@ after 120000 keepalive'
if keys
for k, v in keys
conf.push("-#{k}")
- v = install_cmd(v) if v.type == Proc
+ v = install_cmd(v) if v.kind_of? Proc
conf.push(v)
end
end
@@ -440,10 +443,10 @@ after 120000 keepalive'
module_function :after, :update, :dispatch, :mainloop, :root, :bell
module Scrollable
- def xscrollcommand(cmd)
+ def xscrollcommand(cmd=Proc.new)
configure_cmd 'xscrollcommand', cmd
end
- def yscrollcommand(cmd)
+ def yscrollcommand(cmd=Proc.new)
configure_cmd 'yscrollcommand', cmd
end
end
diff --git a/lib/tracer.rb b/lib/tracer.rb
new file mode 100644
index 0000000000..d37339fd62
--- /dev/null
+++ b/lib/tracer.rb
@@ -0,0 +1,75 @@
+class Tracer
+ MY_FILE_NAME_PATTERN = /^tracer\.(rb)?/
+ Threads = Hash.new
+ Sources = Hash.new
+
+ EVENT_SYMBOL = {
+ "line" => "-",
+ "call" => ">",
+ "return" => "<",
+ "class" => "C",
+ "end" => "E"}
+
+ def on
+ set_trace_func proc{|event, file, line, id, binding|
+ trace_func event, file, line, id, binding
+ }
+ print "Trace on\n"
+ end
+
+ def off
+ set_trace_func nil
+ print "Trace off\n"
+ end
+
+ def get_thread_no
+ unless no = Threads[Thread.current.id]
+ Threads[Thread.current.id] = no = Threads.size
+ end
+ no
+ end
+
+ def get_line(file, line)
+ unless list = Sources[file]
+ f =open(file)
+ begin
+ Sources[file] = list = f.readlines
+ ensure
+ f.close
+ end
+ end
+ list[line - 1]
+ end
+
+ def trace_func(event, file, line, id, binding)
+ return if File.basename(file) =~ MY_FILE_NAME_PATTERN
+
+ Thread.critical = TRUE
+ printf("#%d:%s:%d:%s: %s",
+ get_thread_no,
+ file,
+ line,
+ EVENT_SYMBOL[event],
+ get_line(file, line))
+ Thread.critical = FALSE
+ end
+
+ Single = new
+ def Tracer.on
+ Single.on
+ end
+
+ def Tracer.off
+ Single.off
+ end
+
+end
+
+if File.basename($0) =~ Tracer::MY_FILE_NAME_PATTERN
+ $0 = ARGV.shift
+
+ Tracer.on
+ load $0
+else
+ Tracer.on
+end
diff --git a/main.c b/main.c
index c42656e61b..f3c1c31455 100644
--- a/main.c
+++ b/main.c
@@ -12,11 +12,27 @@
unsigned int _stklen = 0x100000;
#endif
+#ifdef __human68k__
+int _stacksize = 131072;
+#endif
+
+#if (_MSC_VER >= 1000)
+__declspec(dllexport) void __stdcall ruby_init();
+__declspec(dllexport) void __stdcall ruby_options(int, char *[]);
+__declspec(dllexport) void __stdcall ruby_run(void);
+__declspec(dllexport) void __stdcall NtInitialize(int *, char ***);
+#endif
+
void
main(argc, argv, envp)
int argc;
char **argv, **envp;
{
- ruby_init(argc, argv, envp);
+#if defined(NT)
+ NtInitialize(&argc, &argv);
+#endif
+
+ ruby_init();
+ ruby_options(argc, argv);
ruby_run();
}
diff --git a/missing/dir.h b/missing/dir.h
new file mode 100644
index 0000000000..51904c6f88
--- /dev/null
+++ b/missing/dir.h
@@ -0,0 +1,248 @@
+/* $RCSfile: dir.h,v $$Revision: 4.0.1.1 $$Date: 91/06/07 11:22:10 $
+ *
+ * (C) Copyright 1987, 1990 Diomidis Spinellis.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: dir.h,v $
+ * Revision 4.0.1.1 91/06/07 11:22:10 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:34:20 lwall
+ * 4.0 baseline.
+ *
+ * Revision 3.0.1.1 90/03/27 16:07:08 lwall
+ * patch16: MSDOS support
+ *
+ * Revision 1.1 90/03/18 20:32:29 dds
+ * Initial revision
+ *
+ *
+ */
+
+/*
+ * defines the type returned by the directory(3) functions
+ */
+
+#ifndef __DIR_INCLUDED
+#define __DIR_INCLUDED
+
+/*Directory entry size */
+#ifdef DIRSIZ
+#undef DIRSIZ
+#endif
+#define DIRSIZ(rp) (sizeof(struct direct))
+
+/*
+ * Structure of a directory entry
+ */
+struct direct {
+ ino_t d_ino; /* inode number (not used by MS-DOS) */
+ int d_namlen; /* Name length */
+ char d_name[256]; /* file name */
+};
+
+struct _dir_struc { /* Structure used by dir operations */
+ char *start; /* Starting position */
+ char *curr; /* Current position */
+ long size; /* Size of string table */
+ long nfiles; /* number if filenames in table */
+ struct direct dirstr; /* Directory structure to return */
+};
+
+typedef struct _dir_struc DIR; /* Type returned by dir operations */
+
+DIR *cdecl opendir(char *filename);
+struct direct *readdir(DIR *dirp);
+long telldir(DIR *dirp);
+void seekdir(DIR *dirp,long loc);
+void rewinddir(DIR *dirp);
+void closedir(DIR *dirp);
+
+#endif /* __DIR_INCLUDED */
+/* $RCSfile: dir.h,v $$Revision: 4.0.1.1 $$Date: 91/06/07 11:22:10 $
+ *
+ * (C) Copyright 1987, 1990 Diomidis Spinellis.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: dir.h,v $
+ * Revision 4.0.1.1 91/06/07 11:22:10 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:34:20 lwall
+ * 4.0 baseline.
+ *
+ * Revision 3.0.1.1 90/03/27 16:07:08 lwall
+ * patch16: MSDOS support
+ *
+ * Revision 1.1 90/03/18 20:32:29 dds
+ * Initial revision
+ *
+ *
+ */
+
+/*
+ * defines the type returned by the directory(3) functions
+ */
+
+#ifndef __DIR_INCLUDED
+#define __DIR_INCLUDED
+
+/*Directory entry size */
+#ifdef DIRSIZ
+#undef DIRSIZ
+#endif
+#define DIRSIZ(rp) (sizeof(struct direct))
+
+/*
+ * Structure of a directory entry
+ */
+struct direct {
+ ino_t d_ino; /* inode number (not used by MS-DOS) */
+ int d_namlen; /* Name length */
+ char d_name[256]; /* file name */
+};
+
+struct _dir_struc { /* Structure used by dir operations */
+ char *start; /* Starting position */
+ char *curr; /* Current position */
+ struct direct dirstr; /* Directory structure to return */
+};
+
+typedef struct _dir_struc DIR; /* Type returned by dir operations */
+
+DIR *cdecl opendir(char *filename);
+struct direct *readdir(DIR *dirp);
+long telldir(DIR *dirp);
+void seekdir(DIR *dirp,long loc);
+void rewinddir(DIR *dirp);
+void closedir(DIR *dirp);
+
+#endif /* __DIR_INCLUDED */
+/* $RCSfile: dir.h,v $$Revision: 4.0.1.1 $$Date: 91/06/07 11:22:10 $
+ *
+ * (C) Copyright 1987, 1990 Diomidis Spinellis.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: dir.h,v $
+ * Revision 4.0.1.1 91/06/07 11:22:10 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:34:20 lwall
+ * 4.0 baseline.
+ *
+ * Revision 3.0.1.1 90/03/27 16:07:08 lwall
+ * patch16: MSDOS support
+ *
+ * Revision 1.1 90/03/18 20:32:29 dds
+ * Initial revision
+ *
+ *
+ */
+
+/*
+ * defines the type returned by the directory(3) functions
+ */
+
+#ifndef __DIR_INCLUDED
+#define __DIR_INCLUDED
+
+/*Directory entry size */
+#ifdef DIRSIZ
+#undef DIRSIZ
+#endif
+#define DIRSIZ(rp) (sizeof(struct direct))
+
+/*
+ * Structure of a directory entry
+ */
+struct direct {
+ ino_t d_ino; /* inode number (not used by MS-DOS) */
+ int d_namlen; /* Name length */
+ char d_name[256]; /* file name */
+};
+
+struct _dir_struc { /* Structure used by dir operations */
+ char *start; /* Starting position */
+ char *curr; /* Current position */
+ struct direct dirstr; /* Directory structure to return */
+};
+
+typedef struct _dir_struc DIR; /* Type returned by dir operations */
+
+DIR *cdecl opendir(char *filename);
+struct direct *readdir(DIR *dirp);
+long telldir(DIR *dirp);
+void seekdir(DIR *dirp,long loc);
+void rewinddir(DIR *dirp);
+void closedir(DIR *dirp);
+
+#endif /* __DIR_INCLUDED */
+/* $RCSfile: dir.h,v $$Revision: 4.0.1.1 $$Date: 91/06/07 11:22:10 $
+ *
+ * (C) Copyright 1987, 1990 Diomidis Spinellis.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file.
+ *
+ * $Log: dir.h,v $
+ * Revision 4.0.1.1 91/06/07 11:22:10 lwall
+ * patch4: new copyright notice
+ *
+ * Revision 4.0 91/03/20 01:34:20 lwall
+ * 4.0 baseline.
+ *
+ * Revision 3.0.1.1 90/03/27 16:07:08 lwall
+ * patch16: MSDOS support
+ *
+ * Revision 1.1 90/03/18 20:32:29 dds
+ * Initial revision
+ *
+ *
+ */
+
+/*
+ * defines the type returned by the directory(3) functions
+ */
+
+#ifndef __DIR_INCLUDED
+#define __DIR_INCLUDED
+
+/*Directory entry size */
+#ifdef DIRSIZ
+#undef DIRSIZ
+#endif
+#define DIRSIZ(rp) (sizeof(struct direct))
+
+/*
+ * Structure of a directory entry
+ */
+struct direct {
+ ino_t d_ino; /* inode number (not used by MS-DOS) */
+ int d_namlen; /* Name length */
+ char d_name[256]; /* file name */
+};
+
+struct _dir_struc { /* Structure used by dir operations */
+ char *start; /* Starting position */
+ char *curr; /* Current position */
+ long size; /* Size of string table */
+ long nfiles; /* number if filenames in table */
+ struct direct dirstr; /* Directory structure to return */
+};
+
+typedef struct _dir_struc DIR; /* Type returned by dir operations */
+
+DIR *cdecl opendir(char *filename);
+struct direct *readdir(DIR *dirp);
+long telldir(DIR *dirp);
+void seekdir(DIR *dirp,long loc);
+void rewinddir(DIR *dirp);
+void closedir(DIR *dirp);
+
+#endif /* __DIR_INCLUDED */
diff --git a/missing/file.h b/missing/file.h
new file mode 100644
index 0000000000..d8b8402852
--- /dev/null
+++ b/missing/file.h
@@ -0,0 +1,31 @@
+/* This is file FILE.H */
+/*
+** Copyright (C) 1991 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
+**
+** This file is distributed under the terms listed in the document
+** "copying.dj", available from DJ Delorie at the address above.
+** A copy of "copying.dj" should accompany this file; if not, a copy
+** should be available from where this file was obtained. This file
+** may not be distributed without a verbatim copy of "copying.dj".
+**
+** This file is distributed WITHOUT ANY WARRANTY; without even the implied
+** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#ifndef _FILE_H_
+#define _FILE_H_
+
+#include <fcntl.h>
+
+#define L_SET 0
+#define L_CURR 1
+#define L_INCR 1
+#define L_XTND 2
+
+
+#define F_OK 0 /* does file exist */
+#define X_OK 1 /* is it executable by caller */
+#define W_OK 2 /* is it writable by caller */
+#define R_OK 4 /* is it readable by caller */
+
+#endif
diff --git a/missing/nt.c b/missing/nt.c
index e553abbe70..6674f09207 100644
--- a/missing/nt.c
+++ b/missing/nt.c
@@ -14,17 +14,42 @@
#include <fcntl.h>
#include <process.h>
#include <sys/stat.h>
-#include <sys/wait.h>
+/* #include <sys/wait.h> */
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
#include <assert.h>
-bool NtSyncProcess = FALSE;
+#include <windows.h>
+#include <winbase.h>
+#include <wincon.h>
+#include "nt.h"
+#include "dir.h"
+#ifndef index
+#define index(x, y) strchr((x), (y))
+#endif
+
+#ifndef bool
+#define bool int
+#endif
+
+bool NtSyncProcess = TRUE;
+#if 0 // declared in header file
extern char **environ;
+#define environ _environ
+#endif
static bool NtHasRedirection (char *);
static int valid_filename(char *s);
+static void StartSockets ();
+static char *str_grow(struct RString *str, size_t new_size);
+
+char *NTLoginName;
-FILE *fdopen(int, char *);
+#undef const
+FILE *fdopen(int, const char *);
+#if 0
void
sleep(unsigned int len)
{
@@ -34,15 +59,19 @@ sleep(unsigned int len)
while (time((time_t *)0) < end)
;
}
+#endif
//
// Initialization stuff
//
+#if (_MSC_VER >= 1000)
+__declspec(dllexport) void __stdcall
+#else
void
+#endif
NtInitialize(int *argc, char ***argv) {
WORD version;
- WSADATA retdata;
int ret;
//
@@ -55,6 +84,9 @@ NtInitialize(int *argc, char ***argv) {
//
tzset();
+
+ // Initialize Winsock
+ // StartSockets();
}
@@ -79,6 +111,7 @@ char *getlogin()
+#if 1
// popen stuff
//
@@ -95,9 +128,69 @@ char *getlogin()
struct {
int inuse;
int pid;
+ HANDLE oshandle;
FILE *pipe;
} MyPopenRecord[MYPOPENSIZE];
+int SafeFree(char **vec, int vecc)
+{
+ // vec
+ // |
+ // V ^---------------------V
+ // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ // | | | .... | NULL | | ..... |\0 | | ..... |\0 |...
+ // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ // |- elements+1 -| ^ 1st element ^ 2nd element
+
+ char *p;
+
+ p = (char *)(vec - (vecc * sizeof (char *) + 1));
+ free(p);
+
+ return 0;
+}
+
+
+static char *szInternalCmds[] = {
+ "cd",
+ "chdir",
+ "cls",
+ "copy",
+ "date",
+ "del",
+ "dir",
+ "echo",
+ "erase",
+ "label",
+ "md",
+ "mkdir",
+ "path",
+ "rd",
+ "rem",
+ "ren",
+ "rename",
+ "rmdir",
+ "set",
+ "start",
+ "time",
+ "type",
+ "ver",
+ "vol",
+};
+
+int
+isInternalCmd(char *cmd)
+{
+ int fRet;
+ char **vec;
+ int vecc = NtMakeCmdVector(cmd, &vec, FALSE);
+
+ SafeFree (vec, vecc);
+
+ return 0;
+}
+
+
FILE *
mypopen (char *cmd, char *mode)
{
@@ -118,6 +211,8 @@ mypopen (char *cmd, char *mode)
MyPopenRecord[slot].inuse = FALSE;
}
+ //printf("mypopen %s\n", cmd);
+
//
// find a free popen slot
//
@@ -140,6 +235,7 @@ mypopen (char *cmd, char *mode)
// Now get a pipe
//
+#if 0
if (_pipe(pipes, NtPipeSize, pipemode) == -1) {
return NULL;
}
@@ -203,11 +299,12 @@ mypopen (char *cmd, char *mode)
char **vec;
int vecc = NtMakeCmdVector(cmd, &vec, FALSE);
- pid = spawnvpe (_P_NOWAIT, vec[0], vec, environ);
+ //pid = spawnvpe (_P_NOWAIT, vec[0], vec, environ);
+ pid = spawnvpe (_P_WAIT, vec[0], vec, environ);
if (pid == -1) {
goto docmd;
}
- Safefree (vec);
+ Safefree (vec, vecc);
}
if (reading) {
@@ -272,6 +369,126 @@ mypopen (char *cmd, char *mode)
MyPopenRecord[slot].pid = pid;
return fp;
+#else
+ {
+ int p[2];
+
+ BOOL fRet;
+ HANDLE hInFile, hOutFile, hStdin, hStdout;
+ LPCSTR lpApplicationName = NULL;
+ LPTSTR lpCommandLine;
+ LPTSTR lpCmd2 = NULL;
+ DWORD dwCreationFlags;
+ STARTUPINFO aStartupInfo;
+ PROCESS_INFORMATION aProcessInformation;
+ SECURITY_ATTRIBUTES sa;
+ int fd;
+
+ sa.nLength = sizeof (SECURITY_ATTRIBUTES);
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+
+ fRet = CreatePipe(&hInFile, &hOutFile, &sa, 2048L);
+ if (!fRet)
+ Fatal("cannot open pipe \"%s\" (%s)", cmd, strerror(errno));
+
+ memset(&aStartupInfo, 0, sizeof (STARTUPINFO));
+ memset(&aProcessInformation, 0, sizeof (PROCESS_INFORMATION));
+ aStartupInfo.cb = sizeof (STARTUPINFO);
+ aStartupInfo.dwFlags = STARTF_USESTDHANDLES;
+
+ if (reading) {
+ aStartupInfo.hStdInput = GetStdHandle(STD_OUTPUT_HANDLE);//hStdin;
+ aStartupInfo.hStdError = INVALID_HANDLE_VALUE;
+ //for save
+ DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_OUTPUT_HANDLE),
+ GetCurrentProcess(), &hStdout,
+ 0, FALSE, DUPLICATE_SAME_ACCESS
+ );
+ //for redirect
+ DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_INPUT_HANDLE),
+ GetCurrentProcess(), &hStdin,
+ 0, TRUE, DUPLICATE_SAME_ACCESS
+ );
+ aStartupInfo.hStdOutput = hOutFile;
+ }
+ else {
+ aStartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); //hStdout;
+ aStartupInfo.hStdError = INVALID_HANDLE_VALUE;
+ // for save
+ DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_INPUT_HANDLE),
+ GetCurrentProcess(), &hStdin,
+ 0, FALSE, DUPLICATE_SAME_ACCESS
+ );
+ //for redirect
+ DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_OUTPUT_HANDLE),
+ GetCurrentProcess(), &hStdout,
+ 0, TRUE, DUPLICATE_SAME_ACCESS
+ );
+ aStartupInfo.hStdInput = hInFile;
+ }
+
+ dwCreationFlags = (NORMAL_PRIORITY_CLASS);
+
+ lpCommandLine = cmd;
+ if (NtHasRedirection(cmd) || isInternalCmd(cmd)) {
+ lpApplicationName = getenv("COMSPEC");
+ lpCmd2 = malloc(strlen(lpApplicationName) + 1 + strlen(cmd) + sizeof (" /c "));
+ if (lpCmd2 == NULL)
+ Fatal("Mypopen: malloc failed");
+ sprintf(lpCmd2, "%s %s%s", lpApplicationName, " /c ", cmd);
+ lpCommandLine = lpCmd2;
+ }
+
+ fRet = CreateProcess(lpApplicationName, lpCommandLine, &sa, &sa,
+ sa.bInheritHandle, dwCreationFlags, NULL, NULL, &aStartupInfo, &aProcessInformation);
+
+ if (!fRet) {
+ CloseHandle(hInFile);
+ CloseHandle(hOutFile);
+ Fatal("cannot fork for \"%s\" (%s)", cmd, strerror(errno));
+ }
+
+ CloseHandle(aProcessInformation.hThread);
+
+ if (reading) {
+ HANDLE hDummy;
+
+ fd = _open_osfhandle((long)hInFile, (_O_RDONLY | pipemode));
+ CloseHandle(hOutFile);
+ DuplicateHandle(GetCurrentProcess(), hStdout,
+ GetCurrentProcess(), &hDummy,
+ 0, TRUE, (DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)
+ );
+ }
+ else {
+ HANDLE hDummy;
+
+ fd = _open_osfhandle((long)hOutFile, (_O_WRONLY | pipemode));
+ CloseHandle(hInFile);
+ DuplicateHandle(GetCurrentProcess(), hStdin,
+ GetCurrentProcess(), &hDummy,
+ 0, TRUE, (DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)
+ );
+ }
+
+ if (fd == -1)
+ Fatal("cannot open pipe \"%s\" (%s)", cmd, strerror(errno));
+
+
+ if ((fp = (FILE *) fdopen(fd, mode)) == NULL)
+ return NULL;
+
+ if (lpCmd2)
+ free(lpCmd2);
+
+ MyPopenRecord[slot].inuse = TRUE;
+ MyPopenRecord[slot].pipe = fp;
+ MyPopenRecord[slot].oshandle = (reading ? hInFile : hOutFile);
+ MyPopenRecord[slot].pid = (int)aProcessInformation.hProcess;
+ return fp;
+ }
+#endif
}
int
@@ -280,30 +497,53 @@ mypclose(FILE *fp)
int i;
int exitcode;
+ Sleep(100);
for (i = 0; i < MYPOPENSIZE; i++) {
if (MyPopenRecord[i].inuse && MyPopenRecord[i].pipe == fp)
break;
}
if (i >= MYPOPENSIZE) {
- fprintf(stderr,"Invalid file pointer passed to mypclose!\n");
- abort();
+ Fatal("Invalid file pointer passed to mypclose!\n");
}
//
// get the return status of the process
//
+#if 0
if (_cwait(&exitcode, MyPopenRecord[i].pid, WAIT_CHILD) == -1) {
if (errno == ECHILD) {
fprintf(stderr, "mypclose: nosuch child as pid %x\n",
MyPopenRecord[i].pid);
}
}
+#else
+ for (;;) {
+ if (GetExitCodeProcess((HANDLE)MyPopenRecord[i].pid, &exitcode)) {
+ if (exitcode == STILL_ACTIVE) {
+ //printf("Process is Active.\n");
+ Sleep(100);
+ TerminateProcess((HANDLE)MyPopenRecord[i].pid, 0); // ugly...
+ continue;
+ }
+ else if (exitcode == 0) {
+ //printf("done.\n");
+ break;
+ }
+ else {
+ //printf("never.\n");
+ break;
+ }
+ }
+ }
+#endif
+
//
// close the pipe
//
-
+ CloseHandle(MyPopenRecord[i].oshandle);
+ fflush(fp);
fclose(fp);
//
@@ -311,11 +551,17 @@ mypclose(FILE *fp)
//
MyPopenRecord[i].inuse = FALSE;
+ MyPopenRecord[i].pipe = NULL;
+ MyPopenRecord[i].pid = 0;
return exitcode;
}
+#endif
+
+#if 1
+typedef char* CHARP;
/*
* The following code is based on the do_exec and do_aexec functions
* in file doio.c
@@ -333,17 +579,43 @@ char *cmd;
int mode = NtSyncProcess ? P_WAIT : P_NOWAIT;
/* save an extra exec if possible */
- if ((shell = getenv("COMSPEC")) == 0)
- shell = "cmd.exe";
-
- /* see if there are shell metacharacters in it */
- if (NtHasRedirection(cmd)) {
- doshell:
- return spawnle(mode, shell, shell, "/c", cmd, (char*)0, environ);
+ if ((shell = getenv("RUBYSHELL")) != 0) {
+ if (NtHasRedirection(cmd)) {
+ int i;
+ char *p;
+ char *argv[4];
+ char *cmdline = ALLOC_N(char, (strlen(cmd) * 2 + 1));
+
+ p=cmdline;
+ *p++ = '"';
+ for (s=cmd; *s;) {
+ if (*s == '"')
+ *p++ = '\\'; /* Escape d-quote */
+ *p++ = *s++;
+ }
+ *p++ = '"';
+ *p = '\0';
+
+ /* fprintf(stderr, "do_spawn: %s %s\n", shell, cmdline); */
+ argv[0] = shell;
+ argv[1] = "-c";
+ argv[2] = cmdline;
+ argv[4] = NULL;
+ status = spawnvpe(mode, argv[0], argv, environ);
+ /* return spawnle(mode, shell, shell, "-c", cmd, (char*)0, environ); */
+ free(cmdline);
+ return status;
+ }
+ }
+ else if ((shell = getenv("COMSPEC")) != 0) {
+ if (NtHasRedirection(cmd) /* || isInternalCmd(cmd) */) {
+ do_comspec_shell:
+ return spawnle(mode, shell, shell, "/c", cmd, (char*)0, environ);
+ }
}
- argv = ALLOC_N(char*, strlen(cmd) / 2 + 2);
- cmd2 = ALOOC_N(char, strlen(cmd) + 1);
+ argv = ALLOC_N(CHARP, (strlen(cmd) / 2 + 2));
+ cmd2 = ALLOC_N(char, (strlen(cmd) + 1));
strcpy(cmd2, cmd);
a = argv;
for (s = cmd2; *s;) {
@@ -354,12 +626,12 @@ char *cmd;
if (*s)
*s++ = '\0';
}
- *a = Qnil;
+ *a = NULL;
if (argv[0]) {
if ((status = spawnvpe(mode, argv[0], argv, environ)) == -1) {
free(argv);
free(cmd2);
- goto doshell;
+ return -1;
}
}
free(cmd2);
@@ -367,7 +639,7 @@ char *cmd;
return status;
}
-
+#endif
typedef struct _NtCmdLineElement {
struct _NtCmdLineElement *next, *prev;
@@ -781,6 +1053,13 @@ NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd)
// make vptr point to the start of the buffer
// and ptr point to the area we\'ll consider the string table.
//
+ // buffer (*vec)
+ // |
+ // V ^---------------------V
+ // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ // | | | .... | NULL | | ..... |\0 | | ..... |\0 |...
+ // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ // |- elements+1 -| ^ 1st element ^ 2nd element
vptr = (char **) buffer;
@@ -798,6 +1077,7 @@ NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd)
}
+#if 1
//
// UNIX compatible directory access functions for NT
//
@@ -911,9 +1191,11 @@ opendir(char *filename)
// new name and it's null terminator
//
+ #define Renew(x, y, z) (x = (z *)realloc(x, y))
+
Renew (p->start, idx+len+1, char);
if (p->start == NULL) {
- fatal ("opendir: malloc failed!\n");
+ Fatal ("opendir: malloc failed!\n");
}
strcpy(&p->start[idx], FindData.cFileName);
if (downcase)
@@ -1009,13 +1291,15 @@ closedir(DIR *dirp)
free(dirp->start);
free(dirp);
}
-
+#endif
//
// 98.2% of this code was lifted from the OS2 port. (JCW)
//
+#if 0
+// add_suffix is in util.c too.
/*
* Suffix appending for in-place editing under MS-DOS and OS/2 (and now NT!).
*
@@ -1134,6 +1418,7 @@ fallback:
str_grow(str, strlen(buf));
memcpy(str->ptr, buf, str->len);
}
+#endif
static int
valid_filename(char *s)
@@ -1173,7 +1458,7 @@ valid_filename(char *s)
//
FILE *
-fdopen (int fd, char *mode)
+fdopen (int fd, const char *mode)
{
FILE *fp;
char sockbuf[80];
@@ -1182,7 +1467,11 @@ fdopen (int fd, char *mode)
extern int errno;
retval = getsockopt((SOCKET)fd, SOL_SOCKET, SO_TYPE, sockbuf, &optlen);
- if (retval == SOCKET_ERROR && WSAGetLastError() == WSAENOTSOCK) {
+ if (retval == SOCKET_ERROR) {
+ int iRet;
+
+ iRet = WSAGetLastError();
+ if (iRet == WSAENOTSOCK || iRet == WSANOTINITIALISED)
return (_fdopen(fd, mode));
}
@@ -1195,7 +1484,7 @@ fdopen (int fd, char *mode)
#else
fp->_file = fd;
#endif
- if (*mode = 'r')
+ if (*mode == 'r')
fp->_flag = _IOREAD;
else
fp->_flag = _IOWRT;
@@ -1286,7 +1575,8 @@ setgid(int gid)
//
int
-ioctl(int i, unsigned int u, char *data)
+/* ioctl(int i, unsigned int u, char *data) */
+ioctl(int i, unsigned int u, long data)
{
return -1;
}
@@ -1327,12 +1617,12 @@ StartSockets () {
//
version = MAKEWORD(1, 1);
if (ret = WSAStartup(version, &retdata))
- fatal ("Unable to locate winsock library!\n");
+ Fatal ("Unable to locate winsock library!\n");
if (LOBYTE(retdata.wVersion) != 1)
- fatal("could not find version 1 of winsock dll\n");
+ Fatal("could not find version 1 of winsock dll\n");
if (HIBYTE(retdata.wVersion) != 1)
- fatal("could not find version 1 of winsock dll\n");
+ Fatal("could not find version 1 of winsock dll\n");
atexit((void (*)(void)) WSACleanup);
}
@@ -1678,6 +1968,10 @@ void setprotoent (int stayopen) {}
void setservent (int stayopen) {}
+#ifndef WNOHANG
+#define WNOHANG -1
+#endif
+
pid_t
waitpid (pid_t pid, int *stat_loc, int options)
{
@@ -1713,7 +2007,7 @@ getcwd(buffer, size)
int size;
{
int length;
- char *pb;
+ char *bp;
if (_getcwd(buffer, size) == NULL) {
return NULL;
@@ -1730,3 +2024,54 @@ getcwd(buffer, size)
}
return buffer;
}
+
+static char *
+str_grow(struct RString *str, size_t new_size)
+{
+ char *p;
+
+ p = realloc(str->ptr, new_size);
+ if (p == NULL)
+ Fatal("cannot grow string\n");
+
+ str->len = new_size;
+ str->ptr = p;
+
+ return p;
+}
+
+int
+chown(char *path, int owner, int group)
+{
+ return 0;
+}
+
+int
+kill(int pid, int sig)
+{
+#if 1
+ if (pid == GetCurrentProcessId())
+ return raise(sig);
+
+ if (sig == 2 && pid > 0)
+ if (GenerateConsoleCtrlEvent(CTRL_C_EVENT, (DWORD)pid))
+ return 0;
+
+ return -1;
+#else
+ return 0;
+#endif
+}
+
+int
+link(char *from, char *to)
+{
+ return -1;
+}
+
+int
+wait()
+{
+ return 0;
+}
+
diff --git a/missing/nt.h b/missing/nt.h
index 8b208594b6..cf9f4cb00a 100644
--- a/missing/nt.h
+++ b/missing/nt.h
@@ -18,7 +18,7 @@
// Define the following so we don't get tons of extra stuff
// when we include windows.h
//
-
+#if 0
#define NOGDICAPMASKS
#define NOVIRTUALKEYCODES
#define NOWINMESSAGES
@@ -57,14 +57,20 @@
#define NOHELP
#define NOPROFILER
#define NODEFERWINDOWPOS
-
+#endif
//
// Ok now we can include the normal include files.
//
-#include <stdarg.h>
+// #include <stdarg.h> conflict with varargs.h?
+// There is function-name conflitct, so we rename it
+#if !defined(IN) && !defined(FLOAT)
+#define OpenFile WINAPI_OpenFile
#include <windows.h>
+#include <winsock.h>
+#undef OpenFile
+#endif
//
// We\'re not using Microsoft\'s "extensions" to C for
// Structured Exception Handling (SEH) so we can nuke these
@@ -73,12 +79,15 @@
#undef except
#undef finally
#undef leave
-#include <winsock.h>
-#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <direct.h>
#include <process.h>
#include <io.h>
#include <time.h>
+#include <math.h>
+#include <sys/types.h>
#include <sys/utime.h>
//
@@ -127,18 +136,17 @@
#define fileno _fileno
#endif
#define utime _utime
-#define pipe _pipe
+//#define pipe _pipe
+#define perror _perror
-#define popen mypopen
-#define pclose mypclose
/* these are defined in nt.c */
extern int NtMakeCmdVector(char *, char ***, int);
-extern void NtInitialize(int *, char ***);
-
+/* extern void NtInitialize(int *, char ***); */
extern char *NtGetLib(void);
extern char *NtGetBin(void);
+extern FILE *mypopen(char *, char *);
//
// define this so we can do inplace editing
@@ -149,7 +157,8 @@ extern char *NtGetBin(void);
//
// stubs
//
-extern int ioctl (int, unsigned int, char *);
+// extern int ioctl (int, unsigned int, char *);
+extern int ioctl (int, unsigned int, long);
#if 0
extern void sleep (unsigned int);
#else
@@ -164,74 +173,12 @@ extern int setuid (int);
extern int setgid (int);
-//
-// Got the idea and some of the code from the MSDOS implementation
-//
-
-/*
- * (C) Copyright 1987, 1990 Diomidis Spinellis.
- *
- * You may distribute under the terms of either the GNU General Public
- * License or the Artistic License, as specified in the README file.
- *
- * Included in the nt header file for use by nt port
- *
- * $Log: dir.h,v $
- * Revision 4.0.1.1 91/06/07 11:22:10 lwall
- * patch4: new copyright notice
- *
- * Revision 4.0 91/03/20 01:34:20 lwall
- * 4.0 baseline.
- *
- * Revision 3.0.1.1 90/03/27 16:07:08 lwall
- * patch16: MSDOS support
- *
- * Revision 1.1 90/03/18 20:32:29 dds
- * Initial revision
- *
- *
- */
-/*
- * defines the type returned by the directory(3) functions
- */
-
-/*Directory entry size */
-#ifdef DIRSIZ
-#undef DIRSIZ
-#endif
-#define DIRSIZ(rp) (sizeof(struct direct))
-
-/* need this so that directory stuff will compile! */
-#define DIRENT direct
-
-/*
- * Structure of a directory entry
- */
-struct direct {
- ino_t d_ino; /* inode number (not used by MS-DOS) */
- int d_namlen; /* Name length */
- char d_name[257]; /* file name */
-};
-
-struct _dir_struc { /* Structure used by dir operations */
- char *start; /* Starting position */
- char *curr; /* Current position */
- long size; /* Size of string table */
- long nfiles; /* number if filenames in table */
- struct direct dirstr; /* Directory structure to return */
-};
-
-typedef struct _dir_struc DIR; /* Type returned by dir operations */
-
-DIR *cdecl opendir(char *filename);
-struct direct *readdir(DIR *dirp);
-long telldir(DIR *dirp);
-void seekdir(DIR *dirp,long loc);
-void rewinddir(DIR *dirp);
-void closedir(DIR *dirp);
+#undef IN /* confict in parse.c */
+#if 0
extern int sys_nerr;
extern char *sys_errlist[];
+#endif
extern char *mystrerror(int);
#define strerror(e) mystrerror(e)
@@ -243,4 +190,28 @@ extern char *mystrerror(int);
#define HAVE_WAITPID 1
#define HAVE_GETCWD 1
+#ifdef popen
+#undef popen
+#define popen mypopen
+#endif
+#ifdef pclose
+#undef pclose
+#define pclose mypclose
+#endif
+
+#undef va_start
+#undef va_end
+
+#ifdef popen
+#undef popen
+#define popen mypopen
+#endif
+#ifdef pclose
+#undef pclose
+#define pclose mypclose
+#endif
+
+#undef va_start
+#undef va_end
+
#endif
diff --git a/missing/setenv.c b/missing/setenv.c
index 16ecbc6090..8a53a6e4eb 100644
--- a/missing/setenv.c
+++ b/missing/setenv.c
@@ -7,12 +7,16 @@
#include "ruby.h"
+#ifndef NT
extern char **environ;
+#endif
extern char **origenviron;
+#ifndef NT
char *strdup();
+#endif
-int
+static int
envix(nam)
char *nam;
{
diff --git a/missing/strcasecmp.c b/missing/strcasecmp.c
new file mode 100644
index 0000000000..83aa50d9c3
--- /dev/null
+++ b/missing/strcasecmp.c
@@ -0,0 +1,13 @@
+#include <ctype.h>
+
+#define min(a,b) (((a)>(b))?(b):(a))
+int
+strcasecmp(p1, p2)
+ char *p1, *p2;
+{
+ for ( ; *p1 && *p2; p1++, p2++) {
+ if (toupper(*p1) != toupper(*p2))
+ return toupper(*p1) - toupper(*p2);
+ }
+ return strlen(p1) - strlen(p2);
+}
diff --git a/node.h b/node.h
index d6f5c21b97..382a50cde9 100644
--- a/node.h
+++ b/node.h
@@ -22,7 +22,6 @@ enum node_type {
NODE_SCOPE,
NODE_BLOCK,
NODE_IF,
- NODE_UNLESS,
NODE_CASE,
NODE_WHEN,
NODE_OPT_N,
@@ -47,6 +46,7 @@ enum node_type {
NODE_OP_ASGN2,
NODE_CALL,
NODE_FCALL,
+ NODE_VCALL,
NODE_SUPER,
NODE_ZSUPER,
NODE_ARRAY,
@@ -59,7 +59,6 @@ enum node_type {
NODE_GVAR,
NODE_IVAR,
NODE_CVAR,
- NODE_CONST,
NODE_NTH_REF,
NODE_BACK_REF,
NODE_MATCH_REF,
@@ -77,9 +76,11 @@ enum node_type {
NODE_DEFN,
NODE_DEFS,
NODE_ALIAS,
+ NODE_VALIAS,
NODE_UNDEF,
NODE_CLASS,
NODE_MODULE,
+ NODE_SCLASS,
NODE_COLON2,
NODE_CNAME,
NODE_CREF,
@@ -92,6 +93,7 @@ enum node_type {
NODE_NIL,
NODE_DEFINED,
NODE_TAG,
+ NODE_NEWLINE,
};
typedef struct RNode {
@@ -122,13 +124,13 @@ typedef struct RNode {
#define RNODE(obj) (R_CAST(RNode)(obj))
-#define nd_type(n) (((RNODE(n))->flags>>10)&0x7f)
+#define nd_type(n) (((RNODE(n))->flags>>FL_USHIFT)&0x7f)
#define nd_set_type(n,t) \
- RNODE(n)->flags=(RNODE(n)->flags&~FL_UMASK|(((t)<<10)&FL_UMASK))
+ RNODE(n)->flags=((RNODE(n)->flags&~FL_UMASK)|(((t)<<FL_USHIFT)&FL_UMASK))
-#define nd_line(n) (((RNODE(n))->flags>>17)&0x7fff)
+#define nd_line(n) (((RNODE(n))->flags>>18)&0x3fff)
#define nd_set_line(n,l) \
- RNODE(n)->flags=(RNODE(n)->flags&~(-1<<17)|(((l)&0x7fff)<<17))
+ RNODE(n)->flags=((RNODE(n)->flags&~(-1<<18))|(((l)&0x7fff)<<18))
#define nd_head u1.node
#define nd_alen u2.argc
@@ -199,79 +201,84 @@ typedef struct RNode {
#define nd_tlev u3.cnt
#define nd_tval u2.value
-#define NEW_METHOD(n,x) newnode(NODE_METHOD,x,n,0)
-#define NEW_FBODY(n,i,o) newnode(NODE_FBODY,n,i,o)
-#define NEW_DEFN(i,a,d,p) newnode(NODE_DEFN,p,i,NEW_RFUNC(a,d))
-#define NEW_DEFS(r,i,a,d) newnode(NODE_DEFS,r,i,NEW_RFUNC(a,d))
-#define NEW_CFUNC(f,c) newnode(NODE_CFUNC,f,c,0)
+#define nd_file file
+
+#define NEW_METHOD(n,x) node_newnode(NODE_METHOD,x,n,0)
+#define NEW_FBODY(n,i,o) node_newnode(NODE_FBODY,n,i,o)
+#define NEW_DEFN(i,a,d,p) node_newnode(NODE_DEFN,p,i,NEW_RFUNC(a,d))
+#define NEW_DEFS(r,i,a,d) node_newnode(NODE_DEFS,r,i,NEW_RFUNC(a,d))
+#define NEW_CFUNC(f,c) node_newnode(NODE_CFUNC,f,c,0)
#define NEW_RFUNC(b1,b2) NEW_SCOPE(block_append(b1,b2))
-#define NEW_SCOPE(b) newnode(NODE_SCOPE,local_tbl(),(b),cur_cref)
-#define NEW_BLOCK(a) newnode(NODE_BLOCK,a,1,0)
-#define NEW_IF(c,t,e) newnode(NODE_IF,c,t,e)
-#define NEW_UNLESS(c,t,e) newnode(NODE_UNLESS,c,t,e)
-#define NEW_EXNOT(c) newnode(NODE_EXNOT,c,0,0)
-#define NEW_CASE(h,b) newnode(NODE_CASE,h,b,0)
-#define NEW_WHEN(c,t,e) newnode(NODE_WHEN,c,t,e)
-#define NEW_OPT_N(b) newnode(NODE_OPT_N,0,b,0)
-#define NEW_WHILE(c,b,n) newnode(NODE_WHILE,c,b,n)
-#define NEW_UNTIL(c,b,n) newnode(NODE_UNTIL,c,b,n)
-#define NEW_FOR(v,i,b) newnode(NODE_FOR,v,b,i)
-#define NEW_ITER(v,i,b) newnode(NODE_ITER,v,b,i)
-#define NEW_BEGIN(b) newnode(NODE_BEGIN,0,b,0)
-#define NEW_RESCUE(b,res) newnode(NODE_RESCUE,b,res,0)
-#define NEW_RESBODY(a,ex,n) newnode(NODE_RESBODY,n,ex,a)
-#define NEW_ENSURE(b,en) newnode(NODE_ENSURE,b,0,en)
-#define NEW_RET(s) newnode(NODE_RETURN,s,0,0)
-#define NEW_YIELD(a) newnode(NODE_YIELD,a,0,0)
-#define NEW_LIST(a) NEW_ARRAY(a)
-#define NEW_ARRAY(a) newnode(NODE_ARRAY,a,1,0)
-#define NEW_ZARRAY() newnode(NODE_ZARRAY,0,0,0)
-#define NEW_HASH(a) newnode(NODE_HASH,a,0,0)
-#define NEW_NOT(a) newnode(NODE_NOT,0,a,0)
-#define NEW_MASGN(l,r) newnode(NODE_MASGN,l,0,r)
-#define NEW_GASGN(v,val) newnode(NODE_GASGN,v,val,rb_global_entry(v))
-#define NEW_LASGN(v,val) newnode(NODE_LASGN,v,val,local_cnt(v))
-#define NEW_DASGN(v,val) newnode(NODE_DASGN,v,val,0);
-#define NEW_IASGN(v,val) newnode(NODE_IASGN,v,val,0)
-#define NEW_CASGN(v,val) newnode(NODE_CASGN,v,val,0)
-#define NEW_OP_ASGN1(p,id,a) newnode(NODE_OP_ASGN1,p,id,a)
-#define NEW_OP_ASGN2(r,i,o,val) newnode(NODE_OP_ASGN2,r,val,NEW_OP_ASGN3(i,o))
-#define NEW_OP_ASGN3(i,o) newnode(NODE_OP_ASGN2,i,o,0)
-#define NEW_GVAR(v) newnode(NODE_GVAR,v,0,rb_global_entry(v))
-#define NEW_LVAR(v) newnode(NODE_LVAR,v,0,local_cnt(v))
-#define NEW_DVAR(v) newnode(NODE_DVAR,v,0,0);
-#define NEW_IVAR(v) newnode(NODE_IVAR,v,0,0)
-#define NEW_CVAR(v) newnode(NODE_CVAR,v,0,0)
-#define NEW_NTH_REF(n) newnode(NODE_NTH_REF,0,n,local_cnt('~'))
-#define NEW_BACK_REF(n) newnode(NODE_BACK_REF,0,n,local_cnt('~'))
-#define NEW_MATCH(c) newnode(NODE_MATCH,c,0,0)
-#define NEW_LIT(l) newnode(NODE_LIT,l,0,0)
-#define NEW_STR(s) newnode(NODE_STR,s,0,0)
-#define NEW_DSTR(s) newnode(NODE_DSTR,s,0,0)
-#define NEW_XSTR(s) newnode(NODE_XSTR,s,0,0)
-#define NEW_DXSTR(s) newnode(NODE_DXSTR,s,0,0)
-#define NEW_EVSTR(s,l) newnode(NODE_EVSTR,str_new(s,l),0,0)
-#define NEW_CALL(r,m,a) newnode(NODE_CALL,r,m,a)
-#define NEW_FCALL(m,a) newnode(NODE_FCALL,0,m,a)
-#define NEW_SUPER(a) newnode(NODE_SUPER,0,0,a)
-#define NEW_ZSUPER() newnode(NODE_ZSUPER,0,0,0)
-#define NEW_ARGS(f,o,r) newnode(NODE_ARGS,o,r,f)
-#define NEW_ALIAS(n,o) newnode(NODE_ALIAS,0,n,o)
-#define NEW_UNDEF(i) newnode(NODE_UNDEF,0,i,0)
-#define NEW_CLASS(n,b,s) newnode(NODE_CLASS,n,NEW_CBODY(b),s)
-#define NEW_MODULE(n,b) newnode(NODE_MODULE,n,NEW_CBODY(b),0)
-#define NEW_COLON2(c,i) newnode(NODE_COLON2,c,i,0)
-#define NEW_CREF0() (cur_cref=newnode(NODE_CREF,RNODE(the_frame->cbase)->nd_clss,0,0))
-#define NEW_CREF() (cur_cref=newnode(NODE_CREF,0,0,cur_cref))
+#define NEW_SCOPE(b) node_newnode(NODE_SCOPE,local_tbl(),(b),cur_cref)
+#define NEW_BLOCK(a) node_newnode(NODE_BLOCK,a,0,0)
+#define NEW_IF(c,t,e) node_newnode(NODE_IF,c,t,e)
+#define NEW_UNLESS(c,t,e) node_newnode(NODE_IF,c,e,t)
+#define NEW_CASE(h,b) node_newnode(NODE_CASE,h,b,0)
+#define NEW_WHEN(c,t,e) node_newnode(NODE_WHEN,c,t,e)
+#define NEW_OPT_N(b) node_newnode(NODE_OPT_N,0,b,0)
+#define NEW_WHILE(c,b,n) node_newnode(NODE_WHILE,c,b,n)
+#define NEW_UNTIL(c,b,n) node_newnode(NODE_UNTIL,c,b,n)
+#define NEW_FOR(v,i,b) node_newnode(NODE_FOR,v,b,i)
+#define NEW_ITER(v,i,b) node_newnode(NODE_ITER,v,b,i)
+#define NEW_BEGIN(b) node_newnode(NODE_BEGIN,0,b,0)
+#define NEW_RESCUE(b,res) node_newnode(NODE_RESCUE,b,res,0)
+#define NEW_RESBODY(a,ex,n) node_newnode(NODE_RESBODY,n,ex,a)
+#define NEW_ENSURE(b,en) node_newnode(NODE_ENSURE,b,0,en)
+#define NEW_RET(s) node_newnode(NODE_RETURN,s,0,0)
+#define NEW_YIELD(a) node_newnode(NODE_YIELD,a,0,0)
+#define NEW_LIST(a) NEW_ARRAY(a)
+#define NEW_ARRAY(a) node_newnode(NODE_ARRAY,a,1,0)
+#define NEW_ZARRAY() node_newnode(NODE_ZARRAY,0,0,0)
+#define NEW_HASH(a) node_newnode(NODE_HASH,a,0,0)
+#define NEW_NOT(a) node_newnode(NODE_NOT,0,a,0)
+#define NEW_MASGN(l,r) node_newnode(NODE_MASGN,l,0,r)
+#define NEW_GASGN(v,val) node_newnode(NODE_GASGN,v,val,rb_global_entry(v))
+#define NEW_LASGN(v,val) node_newnode(NODE_LASGN,v,val,local_cnt(v))
+#define NEW_DASGN(v,val) node_newnode(NODE_DASGN,v,val,0);
+#define NEW_IASGN(v,val) node_newnode(NODE_IASGN,v,val,0)
+#define NEW_CASGN(v,val) node_newnode(NODE_CASGN,v,val,0)
+#define NEW_OP_ASGN1(p,id,a) node_newnode(NODE_OP_ASGN1,p,id,a)
+#define NEW_OP_ASGN2(r,i,o,val) node_newnode(NODE_OP_ASGN2,r,val,NEW_OP_ASGN3(i,o))
+#define NEW_OP_ASGN3(i,o) node_newnode(NODE_OP_ASGN2,i,o,0)
+#define NEW_GVAR(v) node_newnode(NODE_GVAR,v,0,rb_global_entry(v))
+#define NEW_LVAR(v) node_newnode(NODE_LVAR,v,0,local_cnt(v))
+#define NEW_DVAR(v) node_newnode(NODE_DVAR,v,0,0);
+#define NEW_IVAR(v) node_newnode(NODE_IVAR,v,0,0)
+#define NEW_CVAR(v) node_newnode(NODE_CVAR,v,0,0)
+#define NEW_NTH_REF(n) node_newnode(NODE_NTH_REF,0,n,local_cnt('~'))
+#define NEW_BACK_REF(n) node_newnode(NODE_BACK_REF,0,n,local_cnt('~'))
+#define NEW_MATCH(c) node_newnode(NODE_MATCH,c,0,0)
+#define NEW_LIT(l) node_newnode(NODE_LIT,l,0,0)
+#define NEW_STR(s) node_newnode(NODE_STR,s,0,0)
+#define NEW_DSTR(s) node_newnode(NODE_DSTR,s,0,0)
+#define NEW_XSTR(s) node_newnode(NODE_XSTR,s,0,0)
+#define NEW_DXSTR(s) node_newnode(NODE_DXSTR,s,0,0)
+#define NEW_EVSTR(s,l) node_newnode(NODE_EVSTR,str_new(s,l),0,0)
+#define NEW_CALL(r,m,a) node_newnode(NODE_CALL,r,m,a)
+#define NEW_FCALL(m,a) node_newnode(NODE_FCALL,0,m,a)
+#define NEW_VCALL(m) node_newnode(NODE_VCALL,0,m,0)
+#define NEW_SUPER(a) node_newnode(NODE_SUPER,0,0,a)
+#define NEW_ZSUPER() node_newnode(NODE_ZSUPER,0,0,0)
+#define NEW_ARGS(f,o,r) node_newnode(NODE_ARGS,o,r,f)
+#define NEW_ALIAS(n,o) node_newnode(NODE_ALIAS,0,n,o)
+#define NEW_VALIAS(n,o) node_newnode(NODE_VALIAS,0,n,o)
+#define NEW_UNDEF(i) node_newnode(NODE_UNDEF,0,i,0)
+#define NEW_CLASS(n,b,s) node_newnode(NODE_CLASS,n,NEW_CBODY(b),s)
+#define NEW_SCLASS(r,b) node_newnode(NODE_SCLASS,r,NEW_CBODY(b),0)
+#define NEW_MODULE(n,b) node_newnode(NODE_MODULE,n,NEW_CBODY(b),0)
+#define NEW_COLON2(c,i) node_newnode(NODE_COLON2,c,i,0)
+#define NEW_CREF0() (cur_cref=node_newnode(NODE_CREF,RNODE(the_frame->cbase)->nd_clss,0,0))
+#define NEW_CREF() (cur_cref=node_newnode(NODE_CREF,0,0,cur_cref))
#define NEW_CBODY(b) (cur_cref->nd_body=NEW_SCOPE(b),cur_cref)
-#define NEW_DOT2(b,e) newnode(NODE_DOT2,b,e,0)
-#define NEW_DOT3(b,e) newnode(NODE_DOT3,b,e,0)
-#define NEW_ATTRSET(a) newnode(NODE_ATTRSET,a,0,0)
-#define NEW_SELF() newnode(NODE_SELF,0,0,0)
-#define NEW_NIL() newnode(NODE_NIL,0,0,0)
-#define NEW_DEFINED(e) newnode(NODE_DEFINED,e,0,0)
-
-NODE *newnode();
+#define NEW_DOT2(b,e) node_newnode(NODE_DOT2,b,e,0)
+#define NEW_DOT3(b,e) node_newnode(NODE_DOT3,b,e,0)
+#define NEW_ATTRSET(a) node_newnode(NODE_ATTRSET,a,0,0)
+#define NEW_SELF() node_newnode(NODE_SELF,0,0,0)
+#define NEW_NIL() node_newnode(NODE_NIL,0,0,0)
+#define NEW_DEFINED(e) node_newnode(NODE_DEFINED,e,0,0)
+#define NEW_NEWLINE(n) node_newnode(NODE_NEWLINE,0,0,n)
+
+NODE *node_newnode();
VALUE rb_method_booundp();
#define NOEX_PUBLIC 0
diff --git a/numeric.c b/numeric.c
index 61575834db..6c54bf9986 100644
--- a/numeric.c
+++ b/numeric.c
@@ -12,6 +12,11 @@
#include "ruby.h"
#include <math.h>
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else
+# include <strings.h>
+#endif
static ID coerce;
static ID to_i;
@@ -30,7 +35,7 @@ double big2dbl();
void
num_zerodiv()
{
- rb_raise(exc_new(eZeroDiv, "divided by 0"));
+ Raise(eZeroDiv, "divided by 0");
}
static VALUE
@@ -147,15 +152,15 @@ flo_to_s(flt)
char buf[32];
sprintf(buf, "%g", flt->value);
- if (index(buf, '.') == 0) {
+ if (strchr(buf, '.') == 0) {
int len = strlen(buf);
+ char *ind = strchr(buf, 'e');
- if (len > 1 && buf[1] == 'e') {
- memmove(buf+3, buf+1, len-1);
- buf[1] = '.';
- buf[2] = '0';
- }
- else {
+ if (ind) {
+ memmove(ind+2, ind, len-(ind-buf)+1);
+ ind[0] = '.';
+ ind[1] = '0';
+ } else {
strcat(buf, ".0");
}
}
@@ -273,9 +278,7 @@ flo_mod(x, y)
return num_coerce_bin(x, y);
}
#ifdef HAVE_FMOD
- {
- value = fmod(x->value, value);
- }
+ value = fmod(x->value, value);
#else
{
double value1 = x->value;
@@ -385,6 +388,15 @@ flo_cmp(x, y)
}
static VALUE
+flo_eql(x, y)
+ struct RFloat *x, *y;
+{
+ if (TYPE(y) == T_FLOAT) {
+ if (x->value == y->value) return TRUE;
+ }
+}
+
+static VALUE
flo_to_i(num)
struct RFloat *num;
{
@@ -1134,6 +1146,7 @@ Init_Numeric()
rb_define_method(cFloat, "**", flo_pow, 1);
rb_define_method(cFloat, "==", flo_eq, 1);
rb_define_method(cFloat, "<=>", flo_cmp, 1);
+ rb_define_method(cFloat, "eql?", flo_eql, 1);
rb_define_method(cFloat, "hash", flo_hash, 0);
rb_define_method(cFloat, "to_i", flo_to_i, 0);
rb_define_method(cFloat, "to_f", flo_to_f, 0);
diff --git a/object.c b/object.c
index 6feca1bdad..a0e1eb35b4 100644
--- a/object.c
+++ b/object.c
@@ -14,16 +14,16 @@
#include "st.h"
#include <stdio.h>
-VALUE cKernel;
+VALUE mKernel;
VALUE cObject;
VALUE cModule;
VALUE cClass;
VALUE cFixnum;
VALUE cData;
-static VALUE cNil;
-static VALUE cTrue;
-static VALUE cFalse;
+static VALUE cNilClass;
+static VALUE cTrueClass;
+static VALUE cFalseClass;
struct st_table *new_idhash();
@@ -34,7 +34,7 @@ VALUE obj_alloc();
static ID eq, eql;
static ID inspect;
-int
+VALUE
rb_equal(obj1, obj2)
VALUE obj1, obj2;
{
@@ -53,15 +53,8 @@ rb_eql(obj1, obj2)
return rb_funcall(obj1, eql, 1, obj2);
}
-static VALUE
-krn_nil_p(obj)
- VALUE obj;
-{
- return FALSE;
-}
-
-static VALUE
-krn_equal(obj1, obj2)
+VALUE
+obj_equal(obj1, obj2)
VALUE obj1, obj2;
{
if (obj1 == obj2) return TRUE;
@@ -69,30 +62,28 @@ krn_equal(obj1, obj2)
}
static VALUE
-krn_to_a(obj)
+any_to_a(obj)
VALUE obj;
{
return ary_new3(1, obj);
}
static VALUE
-krn_id(obj)
+obj_id(obj)
VALUE obj;
{
return obj | FIXNUM_FLAG;
}
-char *rb_class2path();
-
static VALUE
-krn_type(obj)
+obj_type(obj)
struct RBasic *obj;
{
- return rb_class_path(obj->class);
+ return rb_class_path(CLASS_OF(obj));
}
static VALUE
-krn_clone(obj)
+obj_clone(obj)
VALUE obj;
{
VALUE clone;
@@ -112,14 +103,14 @@ krn_clone(obj)
}
static VALUE
-krn_dup(obj)
+obj_dup(obj)
VALUE obj;
{
return rb_funcall(obj, rb_intern("clone"), 0, 0);
}
VALUE
-krn_to_s(obj)
+any_to_s(obj)
VALUE obj;
{
char buf[256];
@@ -132,14 +123,7 @@ VALUE
rb_inspect(obj)
VALUE obj;
{
- return rb_funcall(obj, inspect, 0, 0);
-}
-
-static VALUE
-krn_inspect(obj)
- VALUE obj;
-{
- return rb_funcall(obj, rb_intern("to_s"), 0, 0);
+ return obj_as_string(rb_funcall(obj, inspect, 0, 0));
}
static int
@@ -152,7 +136,7 @@ inspect_i(id, value, str)
char *ivname;
/* need not to show internal data */
- if (TYPE(value) == T_DATA) return ST_CONTINUE;
+ if (CLASS_OF(value) == 0) return ST_CONTINUE;
if (str->ptr[0] == '-') {
str->ptr[0] = '#';
str_cat(str, ": ", 2);
@@ -164,7 +148,7 @@ inspect_i(id, value, str)
str_cat(str, ivname, strlen(ivname));
str_cat(str, "=", 1);
if (TYPE(value) == T_OBJECT) {
- str2 = krn_to_s(value);
+ str2 = any_to_s(value);
}
else {
str2 = rb_inspect(value);
@@ -178,20 +162,20 @@ static VALUE
obj_inspect(obj)
struct RObject *obj;
{
- if (TYPE(obj) == T_OBJECT && obj->iv_tbl) {
+ if (TYPE(obj) == T_OBJECT
+ && obj->iv_tbl && obj->iv_tbl->num_entries > 0) {
VALUE str;
- char buf[256];
+ char *b;
- sprintf(buf, "-<%s", rb_class2name(CLASS_OF(obj)));
- str = str_new2(buf);
+ str = str_new2("-<");
+ b = rb_class2name(CLASS_OF(obj));
+ str_cat(str, b, strlen(b));
st_foreach(obj->iv_tbl, inspect_i, str);
str_cat(str, ">", 1);
- if (RSTRING(str)->ptr[0] == '-') /* no instance-var */
- return krn_inspect(obj);
return str;
}
- return krn_inspect(obj);
+ return rb_funcall(obj, rb_intern("to_s"), 0, 0);
}
VALUE
@@ -204,6 +188,19 @@ obj_is_instance_of(obj, c)
case T_MODULE:
case T_CLASS:
break;
+
+ case T_NIL:
+ if (NIL_P(obj)) return TRUE;
+ return FALSE;
+
+ case T_FALSE:
+ if (obj) return FALSE;
+ return TRUE;
+
+ case T_TRUE:
+ if (obj) return TRUE;
+ return FALSE;
+
default:
TypeError("class or module required");
}
@@ -225,6 +222,19 @@ obj_is_kind_of(obj, c)
case T_MODULE:
case T_CLASS:
break;
+
+ case T_NIL:
+ if (NIL_P(obj)) return TRUE;
+ return FALSE;
+
+ case T_FALSE:
+ if (obj) return FALSE;
+ return TRUE;
+
+ case T_TRUE:
+ if (obj) return TRUE;
+ return FALSE;
+
default:
TypeError("class or module required");
}
@@ -252,13 +262,6 @@ obj_s_added(obj, id)
}
static VALUE
-nil_nil_p(obj)
- VALUE obj;
-{
- return TRUE;
-}
-
-static VALUE
nil_to_s(obj)
VALUE obj;
{
@@ -276,7 +279,7 @@ static VALUE
nil_type(obj)
VALUE obj;
{
- return str_new2("Nil");
+ return str_new2("nil");
}
static VALUE
@@ -332,12 +335,27 @@ false_type(obj)
return str_new2("FALSE");
}
+static VALUE
+rb_true(obj)
+ VALUE obj;
+{
+ return TRUE;
+}
+
+static VALUE
+rb_false(obj)
+ VALUE obj;
+{
+ return FALSE;
+}
+
VALUE
obj_alloc(class)
VALUE class;
{
NEWOBJ(obj, struct RObject);
OBJSETUP(obj, class, T_OBJECT);
+ obj->iv_tbl = 0;
return (VALUE)obj;
}
@@ -350,6 +368,8 @@ mod_clone(module)
OBJSETUP(clone, CLASS_OF(module), TYPE(module));
clone->super = module->super;
+ clone->iv_tbl = 0;
+ clone->m_tbl = 0; /* avoid GC crashing */
clone->m_tbl = st_copy(module->m_tbl);
return (VALUE)clone;
@@ -362,7 +382,35 @@ mod_to_s(class)
return rb_class_path(class);
}
-VALUE class_s_new(); /* moved to eval.c */
+static VALUE
+mod_eqq(mod, arg)
+ VALUE mod, arg;
+{
+ return obj_is_kind_of(arg, mod);
+}
+
+VALUE module_new();
+VALUE class_new_instance();
+
+static VALUE
+class_s_new(argc, argv, class)
+ int argc;
+ VALUE *argv;
+{
+ VALUE super, cls;
+
+ rb_scan_args(argc, argv, "01", &super);
+ if (NIL_P(super)) super = cObject;
+ Check_Type(super, T_CLASS);
+ if (FL_TEST(super, FL_SINGLETON)) {
+ TypeError("can't make subclass of virtual class");
+ }
+ cls = class_new(super);
+ /* make metaclass */
+ RBASIC(cls)->class = singleton_class_new(RBASIC(super)->class);
+
+ return cls;
+}
static VALUE
class_superclass(class)
@@ -370,9 +418,12 @@ class_superclass(class)
{
struct RClass *super = class->super;
- while (TYPE(super) == T_ICLASS)
+ while (TYPE(super) == T_ICLASS) {
super = super->super;
-
+ }
+ if (!super) {
+ return Qnil;
+ }
return (VALUE)super;
}
@@ -384,7 +435,7 @@ rb_to_id(name)
return rb_intern(RSTRING(name)->ptr);
}
Check_Type(name, T_FIXNUM);
- return FIX2INT(name);
+ return FIX2UINT(name);
}
static VALUE
@@ -394,26 +445,9 @@ mod_attr(argc, argv, class)
VALUE class;
{
VALUE name, pub;
- ID id;
rb_scan_args(argc, argv, "11", &name, &pub);
- rb_define_attr(class, rb_to_id(name), pub);
- return Qnil;
-}
-
-static VALUE
-mod_public_attr(class, name)
- VALUE class, name;
-{
- rb_define_attr(class, rb_to_id(name), 1);
- return Qnil;
-}
-
-static VALUE
-mod_private_attr(class, name)
- VALUE class, name;
-{
- rb_define_attr(class, rb_to_id(name), 0);
+ rb_define_attr(class, rb_to_id(name), RTEST(pub));
return Qnil;
}
@@ -510,9 +544,9 @@ rb_class_of(obj)
VALUE obj;
{
if (FIXNUM_P(obj)) return cFixnum;
- if (obj == Qnil) return cNil;
- if (obj == FALSE) return cFalse;
- if (obj == TRUE) return cTrue;
+ if (obj == Qnil) return cNilClass;
+ if (obj == FALSE) return cFalseClass;
+ if (obj == TRUE) return cTrueClass;
return RBASIC(obj)->class;
}
@@ -548,28 +582,23 @@ Init_Object()
{
VALUE metaclass;
- cKernel = boot_defclass("kernel", 0);
- cObject = boot_defclass("Object", cKernel);
+ cObject = boot_defclass("Object", 0);
cModule = boot_defclass("Module", cObject);
cClass = boot_defclass("Class", cModule);
- metaclass = RBASIC(cKernel)->class = singleton_class_new(cClass);
- metaclass = RBASIC(cObject)->class = singleton_class_new(metaclass);
+ metaclass = RBASIC(cObject)->class = singleton_class_new(cClass);
metaclass = RBASIC(cModule)->class = singleton_class_new(metaclass);
metaclass = RBASIC(cClass)->class = singleton_class_new(metaclass);
+ mKernel = rb_define_module("Kernel");
+ rb_include_module(cObject, mKernel);
+
/*
* Ruby's Class Hierarchy Chart
*
- * +------------------------+
- * | |
- * kernel----->(kernel) |
- * ^ ^ ^ ^ |
- * | | | | |
- * +---+ +----+ | +---+ |
- * | +-----|----+ | |
- * | | | | |
- * Nil->(Nil) Object---->(Object) |
+ * +------------------+
+ * | |
+ * Object---->(Object) |
* ^ ^ ^ ^ |
* | | | | |
* | | +-----+ +---------+ |
@@ -579,6 +608,7 @@ Init_Object()
* +------+ | Module--->(Module) |
* | | ^ ^ |
* OtherClass-->(OtherClass) | | |
+ * | | |
* Class---->(Class) |
* ^ |
* | |
@@ -587,76 +617,78 @@ Init_Object()
* + All metaclasses are instances of the class `Class'.
*/
- rb_define_method(cKernel, "nil?", krn_nil_p, 0);
- rb_define_method(cKernel, "==", krn_equal, 1);
- rb_define_alias(cKernel, "equal?", "==");
- rb_define_alias(cKernel, "===", "==");
- rb_define_alias(cKernel, "=~", "==");
+ rb_define_method(mKernel, "nil?", rb_false, 0);
+ rb_define_method(mKernel, "==", obj_equal, 1);
+ rb_define_alias(mKernel, "equal?", "==");
+ rb_define_alias(mKernel, "===", "==");
- rb_define_method(cKernel, "eql?", rb_equal, 1);
+ rb_define_method(mKernel, "eql?", obj_equal, 1);
- rb_define_method(cKernel, "hash", krn_id, 0);
- rb_define_method(cKernel, "id", krn_id, 0);
- rb_define_method(cKernel, "type", krn_type, 0);
+ rb_define_method(mKernel, "hash", obj_id, 0);
+ rb_define_method(mKernel, "id", obj_id, 0);
+ rb_define_method(mKernel, "type", obj_type, 0);
- rb_define_method(cKernel, "clone", krn_clone, 0);
- rb_define_method(cKernel, "dup", krn_dup, 0);
+ rb_define_method(mKernel, "clone", obj_clone, 0);
+ rb_define_method(mKernel, "dup", obj_dup, 0);
- rb_define_method(cKernel, "to_a", krn_to_a, 0);
- rb_define_method(cKernel, "to_s", krn_to_s, 0);
- rb_define_method(cKernel, "inspect", krn_inspect, 0);
+ rb_define_method(mKernel, "to_a", any_to_a, 0);
+ rb_define_method(mKernel, "to_s", any_to_s, 0);
+ rb_define_method(mKernel, "inspect", obj_inspect, 0);
- rb_define_method(cKernel, "instance_of?", obj_is_instance_of, 1);
- rb_define_method(cKernel, "kind_of?", obj_is_kind_of, 1);
- rb_define_method(cKernel, "is_a?", obj_is_kind_of, 1);
+ rb_define_method(mKernel, "instance_of?", obj_is_instance_of, 1);
+ rb_define_method(mKernel, "kind_of?", obj_is_kind_of, 1);
+ rb_define_method(mKernel, "is_a?", obj_is_kind_of, 1);
- rb_define_private_method(cKernel, "sprintf", f_sprintf, -1);
- rb_define_alias(cKernel, "format", "sprintf");
+ rb_define_global_function("sprintf", f_sprintf, -1);
+ rb_define_alias(mKernel, "format", "sprintf");
- rb_define_private_method(cKernel, "Integer", f_integer, 1);
- rb_define_private_method(cKernel, "Float", f_float, 1);
+ rb_define_global_function("Integer", f_integer, 1);
+ rb_define_global_function("Float", f_float, 1);
- rb_define_private_method(cKernel, "String", f_string, 1);
- rb_define_private_method(cKernel, "Array", f_array, 1);
+ rb_define_global_function("String", f_string, 1);
+ rb_define_global_function("Array", f_array, 1);
- cNil = rb_define_class("nil", cKernel);
- rb_define_method(cNil, "type", nil_type, 0);
- rb_define_method(cNil, "to_s", nil_to_s, 0);
- rb_define_method(cNil, "inspect", nil_inspect, 0);
+ cNilClass = rb_define_class("NilClass", cObject);
+ rb_define_method(cNilClass, "type", nil_type, 0);
+ rb_define_method(cNilClass, "to_s", nil_to_s, 0);
+ rb_define_method(cNilClass, "inspect", nil_inspect, 0);
+ rb_define_method(cNilClass, "=~", rb_equal, 1);
- rb_define_method(cNil, "nil?", nil_nil_p, 0);
+ rb_define_method(cNilClass, "nil?", rb_true, 0);
+ rb_undef_method(CLASS_OF(cNilClass), "new");
/* default addition */
- rb_define_method(cNil, "+", nil_plus, 1);
+ rb_define_method(cNilClass, "+", nil_plus, 1);
- rb_define_private_method(cObject, "initialize", obj_initialize, -1);
- rb_define_private_method(cObject, "singleton_method_added", obj_s_added, 1);
-
- rb_define_method(cObject, "inspect", obj_inspect, 0);
+ rb_define_global_function("initialize", obj_initialize, -1);
+ rb_define_global_function("singleton_method_added", obj_s_added, 1);
+ rb_define_method(cModule, "===", mod_eqq, 1);
rb_define_method(cModule, "to_s", mod_to_s, 0);
- rb_define_method(cModule, "clone", mod_clone, 0);
+
rb_define_private_method(cModule, "attr", mod_attr, -1);
- rb_define_private_method(cModule, "public_attr", mod_public_attr, -1);
- rb_define_private_method(cModule, "private_attr", mod_private_attr, -1);
- rb_define_private_method(cModule, "object_extended", obj_s_added, 1);
+ rb_define_singleton_method(cModule, "new", module_new, 0);
- rb_define_method(cClass, "new", class_s_new, -1);
- rb_define_method(cClass, "superclass", class_superclass, -1);
+ rb_define_method(cClass, "new", class_new_instance, -1);
+ rb_define_method(cClass, "superclass", class_superclass, 0);
+ rb_undef_method(cClass, "extend_object");
- cData = rb_define_class("Data", cKernel);
+ cData = rb_define_class("Data", cObject);
TopSelf = obj_alloc(cObject);
+ rb_global_variable(&TopSelf);
rb_define_singleton_method(TopSelf, "to_s", main_to_s, 0);
- cTrue = rb_define_class("true", cKernel);
- rb_define_method(cTrue, "to_s", true_to_s, 0);
- rb_define_method(cTrue, "type", true_type, 0);
+ cTrueClass = rb_define_class("TrueClass", cObject);
+ rb_define_method(cTrueClass, "to_s", true_to_s, 0);
+ rb_define_method(cTrueClass, "type", true_type, 0);
+ rb_undef_method(CLASS_OF(cTrueClass), "new");
rb_define_global_const("TRUE", TRUE);
- cFalse = rb_define_class("false", cKernel);
- rb_define_method(cFalse, "to_s", false_to_s, 0);
- rb_define_method(cFalse, "type", false_type, 0);
+ cFalseClass = rb_define_class("FalseClass", cObject);
+ rb_define_method(cFalseClass, "to_s", false_to_s, 0);
+ rb_define_method(cFalseClass, "type", false_type, 0);
+ rb_undef_method(CLASS_OF(cFalseClass), "new");
rb_define_global_const("FALSE", FALSE);
eq = rb_intern("==");
diff --git a/pack.c b/pack.c
index a0f96aa262..ccb5143834 100644
--- a/pack.c
+++ b/pack.c
@@ -19,6 +19,36 @@
+(((x)>>24)&0xFF) \
+(((x)&0x0000FF00)<<8) \
+(((x)&0x00FF0000)>>8) )
+
+#ifdef DYNAMIC_ENDIAN
+#ifdef ntohs
+#undef ntohs
+#undef ntohl
+#undef htons
+#undef htonl
+#endif
+static int
+endian()
+{
+ static int init = 0;
+ static int endian_value;
+ char *p;
+
+ if (init) return endian_value;
+ init = 1;
+ p = (char*)&init;
+ return endian_value = p[0]?0:1;
+}
+
+#define ntohs(x) (endian()?(x):swaps(x))
+#define ntohl(x) (endian()?(x):swapl(x))
+#define htons(x) (endian()?(x):swaps(x))
+#define htonl(x) (endian()?(x):swapl(x))
+#define htovs(x) (endian()?swaps(x):(x))
+#define htovl(x) (endian()?swapl(x):(x))
+#define vtohs(x) (endian()?swaps(x):(x))
+#define vtohl(x) (endian()?swapl(x):(x))
+#else
#ifdef WORDS_BIGENDIAN
#ifndef ntohs
#define ntohs(x) (x)
@@ -42,13 +72,15 @@
#define vtohs(x) (x)
#define vtohl(x) (x)
#endif
+#endif
extern VALUE cString, cArray;
+#ifndef atof
double atof();
+#endif
static char *toofew = "too few arguments";
-int strtoul();
static void encodes();
static VALUE
@@ -58,11 +90,11 @@ pack_pack(ary, fmt)
{
static char *nul10 = "\0\0\0\0\0\0\0\0\0\0";
static char *spc10 = " ";
- char *p, *pend;
+ UCHAR *p, *pend;
VALUE res, from;
char type;
int items, len, idx;
- char *ptr;
+ UCHAR *ptr;
int plen;
Check_Type(fmt, T_STRING);
@@ -84,7 +116,7 @@ pack_pack(ary, fmt)
p++;
}
else if (isdigit(*p)) {
- len = strtoul(p, &p, 10);
+ len = strtoul(p, (char**)&p, 10);
}
else {
len = 1;
@@ -117,13 +149,10 @@ pack_pack(ary, fmt)
str_cat(res, ptr, plen);
len -= plen;
while (len >= 10) {
- if (type == 'A')
- str_cat(res, spc10, 10);
- else
- str_cat(res, nul10, 10);
+ str_cat(res, (type == 'A')?spc10:nul10, 10);
len -= 10;
}
- str_cat(res, nul10, len);
+ str_cat(res, (type == 'A')?spc10:nul10, len);
}
break;
@@ -290,7 +319,7 @@ pack_pack(ary, fmt)
case 'n':
while (len-- > 0) {
- short s;
+ unsigned short s;
from = NEXTFROM;
if (NIL_P(from)) s = 0;
@@ -304,7 +333,7 @@ pack_pack(ary, fmt)
case 'N':
while (len-- > 0) {
- long l;
+ unsigned long l;
from = NEXTFROM;
if (NIL_P(from)) l = 0;
@@ -316,6 +345,34 @@ pack_pack(ary, fmt)
}
break;
+ case 'v':
+ while (len-- > 0) {
+ unsigned short s;
+
+ from = NEXTFROM;
+ if (NIL_P(from)) s = 0;
+ else {
+ s = NUM2INT(from);
+ }
+ s = htovs(s);
+ str_cat(res, &s, sizeof(short));
+ }
+ break;
+
+ case 'V':
+ while (len-- > 0) {
+ unsigned long l;
+
+ from = NEXTFROM;
+ if (NIL_P(from)) l = 0;
+ else {
+ l = NUM2INT(from);
+ }
+ l = htovl(l);
+ str_cat(res, &l, sizeof(long));
+ }
+ break;
+
case 'f':
case 'F':
while (len-- > 0) {
@@ -356,34 +413,6 @@ pack_pack(ary, fmt)
}
break;
- case 'v':
- while (len-- > 0) {
- short s;
-
- from = NEXTFROM;
- if (NIL_P(from)) s = 0;
- else {
- s = NUM2INT(from);
- }
- s = htovs(s);
- str_cat(res, &s, sizeof(short));
- }
- break;
-
- case 'V':
- while (len-- > 0) {
- long l;
-
- from = NEXTFROM;
- if (NIL_P(from)) l = 0;
- else {
- l = NUM2INT(from);
- }
- l = htovl(l);
- str_cat(res, &l, sizeof(long));
- }
- break;
-
case 'x':
grow:
while (len >= 10) {
@@ -445,11 +474,11 @@ pack_pack(ary, fmt)
static void
encodes(str, s, len)
struct RString *str;
- char *s;
+ UCHAR *s;
int len;
{
char hunk[4];
- char *p, *pend;
+ UCHAR *p, *pend;
*hunk = len + ' ';
str_cat(str, hunk, 1);
@@ -477,8 +506,8 @@ pack_unpack(str, fmt)
struct RString *str, *fmt;
{
static char *hexdigits = "0123456789abcdef0123456789ABCDEFx";
- char *s, *send;
- char *p, *pend;
+ UCHAR *s, *send;
+ UCHAR *p, *pend;
VALUE ary;
char type;
int len;
@@ -498,7 +527,7 @@ pack_unpack(str, fmt)
p++;
}
else if (isdigit(*p)) {
- len = strtoul(p, &p, 10);
+ len = strtoul(p, (char**)&p, 10);
}
else {
len = (type != '@');
@@ -512,14 +541,19 @@ pack_unpack(str, fmt)
case 'A':
if (len > send - s) len = send - s;
{
- char *t = s + len - 1;
+ int end = len;
+ UCHAR *t = s + len - 1;
while (t >= s) {
if (*t != ' ' && *t != '\0') break;
t--;
len--;
}
+ ary_push(ary, str_new(s, len));
+ s += end;
}
+ break;
+
case 'a':
if (len > send - s) len = send - s;
ary_push(ary, str_new(s, len));
@@ -529,50 +563,51 @@ pack_unpack(str, fmt)
case 'b':
{
VALUE bitstr;
- char *t;
+ UCHAR *t;
int bits, i;
if (p[-1] == '*' || len > (send - s) * 8)
len = (send - s) * 8;
- ary_push(ary, bitstr = str_new(0, len + 1));
+ bits = 0;
+ ary_push(ary, bitstr = str_new(0, len));
t = RSTRING(bitstr)->ptr;
for (i=0; i<len; i++) {
if (i & 7) bits >>= 1;
else bits = *s++;
*t++ = (bits & 1) ? '1' : '0';
}
- *t = '\0';
}
break;
case 'B':
{
VALUE bitstr;
- char *t;
+ UCHAR *t;
int bits, i;
if (p[-1] == '*' || len > (send - s) * 8)
len = (send - s) * 8;
- ary_push(ary, bitstr = str_new(0, len + 1));
+ bits = 0;
+ ary_push(ary, bitstr = str_new(0, len));
t = RSTRING(bitstr)->ptr;
for (i=0; i<len; i++) {
if (i & 7) bits <<= 1;
else bits = *s++;
*t++ = (bits & 128) ? '1' : '0';
}
- *t = '\0';
}
break;
case 'h':
{
VALUE bitstr;
- char *t;
+ UCHAR *t;
int bits, i;
if (p[-1] == '*' || len > (send - s) * 2)
len = (send - s) * 2;
- ary_push(ary, bitstr = str_new(0, len + 1));
+ bits = 0;
+ ary_push(ary, bitstr = str_new(0, len));
t = RSTRING(bitstr)->ptr;
for (i=0; i<len; i++) {
if (i & 1)
@@ -581,19 +616,19 @@ pack_unpack(str, fmt)
bits = *s++;
*t++ = hexdigits[bits & 15];
}
- *t = '\0';
}
break;
case 'H':
{
VALUE bitstr;
- char *t;
+ UCHAR *t;
int bits, i;
if (p[-1] == '*' || len > (send - s) * 2)
len = (send - s) * 2;
- ary_push(ary, bitstr = str_new(0, len + 1));
+ bits = 0;
+ ary_push(ary, bitstr = str_new(0, len));
t = RSTRING(bitstr)->ptr;
for (i=0; i<len; i++) {
if (i & 1)
@@ -602,7 +637,6 @@ pack_unpack(str, fmt)
bits = *s++;
*t++ = hexdigits[(bits >> 4) & 15];
}
- *t = '\0';
}
break;
@@ -611,9 +645,7 @@ pack_unpack(str, fmt)
len = send - s;
while (len-- > 0) {
int c = *s++;
-#ifdef __CHAR_UNSIGNED__
if (c > (char)127) c-=256;
-#endif
ary_push(ary, INT2FIX(c));
}
break;
@@ -622,7 +654,7 @@ pack_unpack(str, fmt)
if (len > send - s)
len = send - s;
while (len-- > 0) {
- unsigned char c = *s++;
+ UCHAR c = *s++;
ary_push(ary, INT2FIX(c));
}
break;
@@ -639,12 +671,12 @@ pack_unpack(str, fmt)
break;
case 'S':
- if (len >= (send - s) / sizeof(unsigned short))
- len = (send - s) / sizeof(unsigned short);
+ if (len >= (send - s) / sizeof(short))
+ len = (send - s) / sizeof(short);
while (len-- > 0) {
unsigned short tmp;
- memcpy(&tmp, s, sizeof(unsigned short));
- s += sizeof(unsigned short);
+ memcpy(&tmp, s, sizeof(short));
+ s += sizeof(short);
ary_push(ary, INT2FIX(tmp));
}
break;
@@ -661,12 +693,12 @@ pack_unpack(str, fmt)
break;
case 'I':
- if (len >= (send - s) / sizeof(unsigned int))
- len = (send - s) / sizeof(unsigned int);
+ if (len >= (send - s) / sizeof(int))
+ len = (send - s) / sizeof(int);
while (len-- > 0) {
unsigned int tmp;
- memcpy(&tmp, s, sizeof(unsigned int));
- s += sizeof(unsigned int);
+ memcpy(&tmp, s, sizeof(int));
+ s += sizeof(int);
ary_push(ary, int2inum(tmp));
}
break;
@@ -683,13 +715,13 @@ pack_unpack(str, fmt)
break;
case 'L':
- if (len >= (send - s) / sizeof(unsigned long))
- len = (send - s) / sizeof(unsigned long);
+ if (len >= (send - s) / sizeof(long))
+ len = (send - s) / sizeof(long);
while (len-- > 0) {
unsigned long tmp;
- memcpy(&tmp, s, sizeof(unsigned long));
- s += sizeof(unsigned long);
- ary_push(ary, int2inum(tmp));
+ memcpy(&tmp, s, sizeof(long));
+ s += sizeof(long);
+ ary_push(ary, uint2inum(tmp));
}
break;
@@ -697,11 +729,11 @@ pack_unpack(str, fmt)
if (len >= (send - s) / sizeof(short))
len = (send - s) / sizeof(short);
while (len-- > 0) {
- short tmp;
+ unsigned short tmp;
memcpy(&tmp, s, sizeof(short));
s += sizeof(short);
tmp = ntohs(tmp);
- ary_push(ary, int2inum(tmp));
+ ary_push(ary, uint2inum(tmp));
}
break;
@@ -709,16 +741,40 @@ pack_unpack(str, fmt)
if (len >= (send - s) / sizeof(long))
len = (send - s) / sizeof(long);
while (len-- > 0) {
- long tmp;
+ unsigned long tmp;
memcpy(&tmp, s, sizeof(long));
s += sizeof(long);
tmp = ntohl(tmp);
- ary_push(ary, int2inum(tmp));
+ ary_push(ary, uint2inum(tmp));
+ }
+ break;
+
+ case 'v':
+ if (len >= (send - s) / sizeof(short))
+ len = (send - s) / sizeof(short);
+ while (len-- > 0) {
+ unsigned short tmp;
+ memcpy(&tmp, s, sizeof(short));
+ s += sizeof(short);
+ tmp = vtohs(tmp);
+ ary_push(ary, uint2inum(tmp));
+ }
+ break;
+
+ case 'V':
+ if (len >= (send - s) / sizeof(long))
+ len = (send - s) / sizeof(long);
+ while (len-- > 0) {
+ unsigned long tmp;
+ memcpy(&tmp, s, sizeof(long));
+ s += sizeof(long);
+ tmp = vtohl(tmp);
+ ary_push(ary, uint2inum(tmp));
}
break;
- case 'F':
case 'f':
+ case 'F':
if (len >= (send - s) / sizeof(float))
len = (send - s) / sizeof(float);
while (len-- > 0) {
@@ -741,34 +797,10 @@ pack_unpack(str, fmt)
}
break;
- case 'v':
- if (len >= (send - s) / sizeof(short))
- len = (send - s) / sizeof(short);
- while (len-- > 0) {
- short tmp;
- memcpy(&tmp, s, sizeof(short));
- s += sizeof(short);
- tmp = vtohs(tmp);
- ary_push(ary, int2inum(tmp));
- }
- break;
-
- case 'V':
- if (len >= (send - s) / sizeof(long))
- len = (send - s) / sizeof(long);
- while (len-- > 0) {
- long tmp;
- memcpy(&tmp, s, sizeof(long));
- s += sizeof(long);
- tmp = vtohl(tmp);
- ary_push(ary, int2inum(tmp));
- }
- break;
-
case 'u':
{
VALUE str = str_new(0, (send - s)*3/4);
- char *ptr = RSTRING(str)->ptr;
+ UCHAR *ptr = RSTRING(str)->ptr;
int total = 0;
while (s < send && *s > ' ' && *s < 'a') {
@@ -778,8 +810,14 @@ pack_unpack(str, fmt)
hunk[3] = '\0';
len = (*s++ - ' ') & 077;
total += len;
+ if (total > RSTRING(str)->len) {
+ len -= total - RSTRING(str)->len;
+ total = RSTRING(str)->len;
+ }
while (len > 0) {
+ int mlen = len > 3 ? 3 : len;
+
if (s < send && *s >= ' ')
a = (*s++ - ' ') & 077;
else
@@ -799,13 +837,13 @@ pack_unpack(str, fmt)
hunk[0] = a << 2 | b >> 4;
hunk[1] = b << 4 | c >> 2;
hunk[2] = c << 6 | d;
- memcpy(ptr, hunk, len > 3 ? 3 : len);
- ptr += 3;
- len -= 3;
+ memcpy(ptr, hunk, mlen);
+ ptr += mlen;
+ len -= mlen;
}
- if (*s == '\n' || *s == '\r')
- s++;
- else if (s+1 == send || s[1] == '\n' || s[1] == '\r')
+ if (*s == '\r') s++;
+ if (*s == '\n') s++;
+ else if (s < send && (s+1 == send || s[1] == '\n'))
s += 2; /* possible checksum byte */
}
RSTRING(str)->len = total;
diff --git a/parse.y b/parse.y
index 350c83a7ca..50e6db2b39 100644
--- a/parse.y
+++ b/parse.y
@@ -56,7 +56,7 @@ static enum lex_state {
EXPR_BEG, /* ignore newline, +/- is a sign. */
EXPR_MID, /* newline significant, +/- is a sign. */
EXPR_END, /* newline significant, +/- is a operator. */
- EXPR_ARG, /* newline significant, +/- is a sign(meybe). */
+ EXPR_ARG, /* newline significant, +/- may be a sign. */
EXPR_FNAME, /* ignore newline, +/- is a operator. */
} lex_state;
@@ -68,16 +68,17 @@ static int value_expr();
static NODE *cond();
static NODE *logop();
+static NODE *newline_node();
+static void fixpos();
+
static NODE *block_append();
static NODE *list_append();
static NODE *list_concat();
-static NODE *list_copy();
-static NODE *expand_op();
static NODE *call_op();
static int in_defined = 0;
static NODE *gettable();
-static NODE *asignable();
+static NODE *assignable();
static NODE *aryset();
static NODE *attrset();
static void backref_error();
@@ -154,7 +155,7 @@ static void top_local_setup();
%type <val> literal numeric
%type <node> compexpr exprs expr arg primary command_call method_call
%type <node> if_tail opt_else case_body cases rescue ensure iterator
-%type <node> call_args call_args0 args args2 opt_args var_ref
+%type <node> call_args call_args0 ret_args args mrhs opt_args var_ref
%type <node> superclass f_arglist f_args f_optarg f_opt
%type <node> array assoc_list assocs assoc undef_list
%type <node> iter_var opt_iter_var iter_block iter_do_block
@@ -214,12 +215,15 @@ program : {
lex_state = EXPR_BEG;
top_local_init();
NEW_CREF0(); /* initialize constant c-ref */
+ if ((VALUE)the_class == cObject) class_nest = 0;
+ else class_nest = 1;
}
compexpr
{
eval_tree = block_append(eval_tree, $2);
top_local_setup();
cur_cref = 0;
+ class_nest = 0;
}
compexpr : exprs opt_terms
@@ -229,16 +233,19 @@ exprs : /* none */
$$ = 0;
}
| expr
+ {
+ $$ = newline_node($1);
+ }
| exprs terms expr
{
- $$ = block_append($1, $3);
+ $$ = block_append($1, newline_node($3));
}
| error expr
{
$$ = $2;
}
-expr : mlhs '=' args2
+expr : mlhs '=' mrhs
{
value_expr($3);
$1->nd_value = $3;
@@ -248,14 +255,14 @@ expr : mlhs '=' args2
{
$$ = NEW_HASH($1);
}
- | RETURN args2
+ | RETURN ret_args
{
value_expr($2);
if (!cur_mid && !in_single)
yyerror("return appeared outside of method");
$$ = NEW_RET($2);
}
- | YIELD args2
+ | YIELD ret_args
{
value_expr($2);
$$ = NEW_YIELD($2);
@@ -265,11 +272,40 @@ expr : mlhs '=' args2
{
$2->nd_iter = $1;
$$ = $2;
+ fixpos($$, $2);
}
| ALIAS fname {lex_state = EXPR_FNAME;} fname
{
+ if (cur_mid || in_single)
+ yyerror("alias within method");
$$ = NEW_ALIAS($2, $4);
}
+ | ALIAS GVAR GVAR
+ {
+ if (cur_mid || in_single)
+ yyerror("alias within method");
+ $$ = NEW_VALIAS($2, $3);
+ }
+ | ALIAS GVAR BACK_REF
+ {
+ char buf[3];
+
+ if (cur_mid || in_single)
+ yyerror("alias within method");
+ sprintf(buf, "$%c", $3->nd_nth);
+ $$ = NEW_VALIAS($2, rb_intern(buf));
+ }
+ | ALIAS GVAR NTH_REF
+ {
+ yyerror("can't make alias for the number variables");
+ $$ = 0;
+ }
+ | UNDEF undef_list
+ {
+ if (cur_mid || in_single)
+ yyerror("undef within method");
+ $$ = $2;
+ }
| expr IF_MOD expr
{
value_expr($3);
@@ -323,21 +359,20 @@ expr : mlhs '=' args2
command_call : operation call_args0
{
$$ = NEW_FCALL($1, $2);
+ fixpos($$, $2);
}
| primary '.' operation call_args0
{
value_expr($1);
$$ = NEW_CALL($1, $3, $4);
+ fixpos($$, $1);
}
| SUPER call_args0
{
if (!cur_mid && !in_single && !in_defined)
yyerror("super called outside of method");
$$ = NEW_SUPER($2);
- }
- | UNDEF undef_list
- {
- $$ = $2;
+ fixpos($$, $2);
}
mlhs : mlhs_head
@@ -374,7 +409,7 @@ mlhs_tail : lhs
lhs : variable
{
- $$ = asignable($1, 0);
+ $$ = assignable($1, 0);
}
| primary '[' opt_args opt_nl ']'
{
@@ -384,6 +419,10 @@ lhs : variable
{
$$ = attrset($1, $3, 0);
}
+ | primary '.' CONSTANT
+ {
+ $$ = attrset($1, $3, 0);
+ }
| backref
{
backref_error($1);
@@ -445,15 +484,23 @@ op : DOT2 { $$ = DOT2; }
arg : variable '=' arg
{
value_expr($3);
- $$ = asignable($1, $3);
+ $$ = assignable($1, $3);
+ fixpos($$, $3);
}
| primary '[' opt_args opt_nl ']' '=' arg
{
$$ = aryset($1, $3, $7);
+ fixpos($$, $7);
}
| primary '.' IDENTIFIER '=' arg
{
$$ = attrset($1, $3, $5);
+ fixpos($$, $5);
+ }
+ | primary '.' CONSTANT '=' arg
+ {
+ $$ = attrset($1, $3, $5);
+ fixpos($$, $5);
}
| backref '=' arg
{
@@ -466,18 +513,22 @@ arg : variable '=' arg
value_expr($3);
if (is_local_id($1)&&!local_id($1)&&dyna_in_block())
dyna_var_asgn($1, TRUE);
- $$ = asignable($1, call_op(gettable($1), $2, 1, $3));
+ $$ = assignable($1, call_op(gettable($1), $2, 1, $3));
+ fixpos($$, $3);
}
| primary '[' opt_args opt_nl ']' OP_ASGN arg
{
NODE *args = NEW_LIST($7);
- if ($3) list_concat(args, $3);
+ list_append($3, NEW_NIL());
+ list_concat(args, $3);
$$ = NEW_OP_ASGN1($1, $6, args);
+ fixpos($$, $7);
}
| primary '.' IDENTIFIER OP_ASGN arg
{
$$ = NEW_OP_ASGN2($1, $3, $4, $5);
+ fixpos($$, $5);
}
| backref OP_ASGN arg
{
@@ -570,10 +621,12 @@ arg : variable '=' arg
}
| arg MATCH arg
{
+ local_cnt('~');
$$ = NEW_CALL($1, MATCH, NEW_LIST($3));
}
| arg NMATCH arg
{
+ local_cnt('~');
$$ = NEW_NOT(NEW_CALL($1, MATCH, NEW_LIST($3)));
}
| '!' arg
@@ -601,10 +654,10 @@ arg : variable '=' arg
{
$$ = logop(NODE_OR, $1, $3);
}
- | DEFINED {in_defined = 1;} arg
+ | DEFINED opt_nl {in_defined = 1;} arg
{
in_defined = 0;
- $$ = NEW_DEFINED($3);
+ $$ = NEW_DEFINED($4);
}
| primary
{
@@ -627,10 +680,6 @@ call_args0 : args
{
$$ = NEW_LIST(NEW_HASH($1));
}
- | args ',' command_call
- {
- $$ = list_append($1, $3);
- }
| args ',' assocs
{
$$ = list_append($1, NEW_HASH($3));
@@ -666,7 +715,25 @@ args : arg
$$ = list_append($1, $3);
}
-args2 : args
+mrhs : args
+ {
+ if ($1 && $1->nd_next == 0) {
+ $$ = $1->nd_head;
+ }
+ else {
+ $$ = $1;
+ }
+ }
+ | args ',' STAR arg
+ {
+ $$ = call_op($1, '+', 1, $4);
+ }
+ | STAR arg
+ {
+ $$ = $2;
+ }
+
+ret_args : call_args0
{
if ($1 && $1->nd_next == 0) {
$$ = $1->nd_head;
@@ -732,13 +799,26 @@ primary : literal
{
$$ = NEW_HASH($2);
}
+ | RETURN '(' ret_args ')'
+ {
+ if (!cur_mid && !in_single)
+ yyerror("return appeared outside of method");
+ value_expr($3);
+ $$ = NEW_RET($3);
+ }
+ | RETURN '(' ')'
+ {
+ if (!cur_mid && !in_single)
+ yyerror("return appeared outside of method");
+ $$ = NEW_RET(0);
+ }
| RETURN
{
if (!cur_mid && !in_single)
yyerror("return appeared outside of method");
$$ = NEW_RET(0);
}
- | YIELD '(' args2 ')'
+ | YIELD '(' ret_args ')'
{
value_expr($3);
$$ = NEW_YIELD($3);
@@ -750,11 +830,11 @@ primary : literal
| YIELD
{
$$ = NEW_YIELD(0);
- }
- | DEFINED '(' {in_defined = 1;} expr ')'
+ }
+ | DEFINED opt_nl '(' {in_defined = 1;} expr ')'
{
in_defined = 0;
- $$ = NEW_DEFINED($4);
+ $$ = NEW_DEFINED($5);
}
| FID
{
@@ -770,6 +850,7 @@ primary : literal
{
$2->nd_iter = $1;
$$ = $2;
+ fixpos($$, $1);
}
| IF expr then
compexpr
@@ -778,6 +859,7 @@ primary : literal
{
value_expr($2);
$$ = NEW_IF(cond($2), $4, $5);
+ fixpos($$, $2);
}
| UNLESS expr then
compexpr
@@ -786,16 +868,19 @@ primary : literal
{
value_expr($2);
$$ = NEW_UNLESS(cond($2), $4, $5);
+ fixpos($$, $2);
}
| WHILE expr term compexpr END
{
value_expr($2);
$$ = NEW_WHILE(cond($2), $4, 1);
+ fixpos($$, $2);
}
| UNTIL expr term compexpr END
{
value_expr($2);
$$ = NEW_UNTIL(cond($2), $4, 1);
+ fixpos($$, $2);
}
| CASE compexpr
case_body
@@ -803,11 +888,13 @@ primary : literal
{
value_expr($2);
$$ = NEW_CASE($2, $3);
+ fixpos($$, $2);
}
| FOR iter_var IN expr term compexpr END
{
value_expr($2);
$$ = NEW_FOR($2, $4, $6);
+ fixpos($$, $2);
}
| BEGIN
compexpr
@@ -822,6 +909,7 @@ primary : literal
if ($4) $2 = NEW_ENSURE($2, $4);
$$ = $2;
}
+ fixpos($$, $2);
}
| LPAREN compexpr ')'
{
@@ -840,6 +928,25 @@ primary : literal
END
{
$$ = NEW_CLASS($2, $5, $3);
+ fixpos($$, $3);
+ local_pop();
+ cref_pop();
+ class_nest--;
+ }
+ | CLASS LSHFT expr term
+ {
+ if (cur_mid || in_single)
+ yyerror("class definition in method body");
+
+ class_nest++;
+ cref_push();
+ local_push();
+ }
+ compexpr
+ END
+ {
+ $$ = NEW_SCLASS($3, $6);
+ fixpos($$, $3);
local_pop();
cref_pop();
class_nest--;
@@ -856,6 +963,7 @@ primary : literal
END
{
$$ = NEW_MODULE($2, $4);
+ fixpos($$, $4);
local_pop();
cref_pop();
class_nest--;
@@ -872,6 +980,7 @@ primary : literal
END
{
$$ = NEW_DEFN($2, $4, $5, class_nest?0:1);
+ fixpos($$, $4);
local_pop();
cur_mid = 0;
}
@@ -887,6 +996,7 @@ primary : literal
END
{
$$ = NEW_DEFS($2, $5, $7, $8);
+ fixpos($$, $2);
local_pop();
in_single--;
}
@@ -902,6 +1012,7 @@ if_tail : opt_else
{
value_expr($2);
$$ = NEW_IF(cond($2), $4, $5);
+ fixpos($$, $2);
}
opt_else : /* none */
@@ -942,6 +1053,7 @@ iter_do_block : DO
END
{
$$ = NEW_ITER($3, 0, $4);
+ fixpos($$, $3?$3:$4);
dyna_pop($<vars>2);
}
@@ -953,6 +1065,7 @@ iter_block : '{'
compexpr '}'
{
$$ = NEW_ITER($3, 0, $4);
+ fixpos($$, $3?$3:$4);
dyna_pop($<vars>2);
}
@@ -974,11 +1087,13 @@ iterator : IDENTIFIER
method_call : operation '(' call_args ')'
{
$$ = NEW_FCALL($1, $3);
+ fixpos($$, $3);
}
| primary '.' operation '(' call_args ')'
{
value_expr($1);
$$ = NEW_CALL($1, $3, $5);
+ fixpos($$, $1);
}
| primary '.' operation
{
@@ -989,6 +1104,7 @@ method_call : operation '(' call_args ')'
{
value_expr($1);
$$ = NEW_CALL($1, $3, $5);
+ fixpos($$, $1);
}
case_body : WHEN args then
@@ -1005,6 +1121,7 @@ rescue : RESCUE opt_args term compexpr
rescue
{
$$ = NEW_RESBODY($2, $4, $5);
+ fixpos($$, $2?$2:$4);
}
| /* none */
{
@@ -1131,12 +1248,13 @@ f_opt : IDENTIFIER '=' arg
{
if (!is_local_id($1))
yyerror("formal argument must be local variable");
- $$ = asignable($1, $3);
+ $$ = assignable($1, $3);
}
f_optarg : f_opt
{
$$ = NEW_BLOCK($1);
+ $$->nd_end = $$;
}
| f_optarg ',' f_opt
{
@@ -1298,6 +1416,8 @@ yyerror(msg)
static int newline_seen;
+int rb_in_compile = 0;
+
static NODE*
yycompile(f)
char *f;
@@ -1307,7 +1427,9 @@ yycompile(f)
newline_seen = 0;
sourcefile = strdup(f);
eval_tree = 0;
+ rb_in_compile = 1;
n = yyparse();
+ rb_in_compile = 0;
if (n == 0) return eval_tree;
return 0;
@@ -1340,7 +1462,7 @@ compile_file(f, file, start)
return yycompile(f);
}
-int
+static int
nextc()
{
int c;
@@ -1357,7 +1479,7 @@ nextc()
return -1;
}
}
- c = *lex_p++;
+ c = (unsigned char)*lex_p++;
return c;
}
@@ -1375,7 +1497,7 @@ pushback(c)
#define toklen() tokidx
#define toklast() (tokidx>0?tokenbuf[tokidx-1]:0)
-char*
+static char*
newtok()
{
tokidx = 0;
@@ -1384,12 +1506,13 @@ newtok()
tokenbuf = ALLOC_N(char, 60);
}
if (toksiz > 1024) {
+ toksiz = 60;
REALLOC_N(tokenbuf, char, 60);
}
return tokenbuf;
}
-void
+static void
tokadd(c)
char c;
{
@@ -1432,18 +1555,19 @@ read_escape()
case '0': case '1': case '2': case '3': /* octal constant */
case '4': case '5': case '6': case '7':
- pushback(c);
{
char buf[3];
int i;
+ pushback(c);
for (i=0; i<3; i++) {
- buf[i] = nextc();
- if (buf[i] == -1) goto eof;
- if (buf[i] < '0' || '7' < buf[i]) {
- pushback(buf[i]);
+ c = nextc();
+ if (c == -1) goto eof;
+ if (c < '0' || '7' < c) {
+ pushback(c);
break;
}
+ buf[i] = c;
}
c = scan_oct(buf, i+1, &i);
}
@@ -1514,11 +1638,11 @@ parse_regx(term)
int term;
{
register int c;
+ char kcode = 0;
+ int once = 0;
int casefold = 0;
int in_brack = 0;
int re_start = sourceline;
- int once = 0;
- int quote = 0;
NODE *list = 0;
newtok();
@@ -1604,19 +1728,29 @@ parse_regx(term)
regx_end:
for (;;) {
- c = nextc();
- if (c == 'i') {
+ switch (c = nextc()) {
+ case 'i':
casefold = 1;
- }
- else if (c == 'o') {
+ break;
+ case 'o':
once = 1;
- }
- else {
- pushback(c);
break;
+ case 'n':
+ kcode = 2;
+ break;
+ case 'e':
+ kcode = 4;
+ break;
+ case 's':
+ kcode = 6;
+ break;
+ default:
+ pushback(c);
+ goto end_options;
}
}
+ end_options:
tokfix();
lex_state = EXPR_END;
if (list) {
@@ -1625,12 +1759,12 @@ parse_regx(term)
list_append(list, NEW_STR(ss));
}
nd_set_type(list, once?NODE_DREGX_ONCE:NODE_DREGX);
- list->nd_cflag = casefold;
+ list->nd_cflag = kcode | casefold;
yylval.node = list;
return DREGEXP;
}
else {
- yylval.val = reg_new(tok(), toklen(), casefold);
+ yylval.val = reg_new(tok(), toklen(), kcode | casefold);
return REGEXP;
}
}
@@ -1715,14 +1849,12 @@ static int
parse_qstring(term)
int term;
{
- int quote = 0;
int strstart;
int c;
strstart = sourceline;
newtok();
while ((c = nextc()) != term) {
- qstr_retry:
if (c == -1) {
sourceline = strstart;
Error("unterminated string meets end of file");
@@ -1811,6 +1943,10 @@ arg_ambiguous()
Warning("ambiguous first argument; make sure");
}
+#ifndef atof
+double atof();
+#endif
+
static int
yylex()
{
@@ -1819,7 +1955,7 @@ yylex()
struct kwtable *low = kwtable, *mid, *high = LAST(kwtable);
if (newline_seen) {
- sourceline++;
+ sourceline+=newline_seen;
newline_seen = 0;
}
@@ -1848,6 +1984,27 @@ retry:
}
/* fall through */
case '\n':
+ /* skip embedded rd document */
+ if ((c = nextc()) == '=' &&
+ strncmp(lex_p, "begin", 5) == 0 &&
+ (lex_p[5] == '\n' || lex_p[5] == '\r')) {
+ for (;;) {
+ if (c == -1) return 0;
+ c = nextc();
+ if (c != '\n') continue;
+ c = nextc();
+ if (c != '=') continue;
+ if (strncmp(lex_p, "end", 3) == 0 &&
+ (lex_p[3] == '\n' || lex_p[3] == '\r')) {
+ lex_p += 3; /* sizeof "end" */
+ break;
+ }
+ }
+ }
+ else {
+ pushback(c);
+ }
+
if (lex_state == EXPR_BEG || lex_state == EXPR_FNAME) {
sourceline++;
goto retry;
@@ -1877,7 +2034,7 @@ retry:
lex_state = EXPR_BEG;
return STAR;
}
- if (lex_state == EXPR_BEG) {
+ if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
return STAR;
}
lex_state = EXPR_BEG;
@@ -1895,6 +2052,25 @@ retry:
return '!';
case '=':
+ if (lex_p == lex_pbeg + 1) {
+ /* skip embedded rd document */
+ if (strncmp(lex_p, "begin", 5) == 0 && isspace(lex_p[5])) {
+ lex_p = lex_pend;
+ for (;;) {
+ if (c == -1) return 0;
+ c = nextc();
+ if (c != '\n') continue;
+ c = nextc();
+ if (c != '=') continue;
+ if (strncmp(lex_p, "end", 3) == 0 && isspace(lex_p[3])) {
+ lex_p = lex_pend;
+ break;
+ }
+ }
+ goto retry;
+ }
+ }
+
lex_state = EXPR_BEG;
if ((c = nextc()) == '=') {
if ((c = nextc()) == '=') {
@@ -2085,11 +2261,16 @@ retry:
is_float = seen_point = seen_e = 0;
lex_state = EXPR_END;
newtok();
+ if (c == '-' || c == '+') {
+ tokadd(c);
+ c = nextc();
+ }
if (c == '0') {
c = nextc();
if (c == 'x' || c == 'X') {
/* hexadecimal */
while (c = nextc()) {
+ if (c == '_') continue;
if (!isxdigit(c)) break;
tokadd(c);
}
@@ -2102,7 +2283,8 @@ retry:
/* octal */
do {
tokadd(c);
- c = nextc();
+ while ((c = nextc()) == '_')
+ ;
} while (c >= '0' && c <= '9');
pushback(c);
tokfix();
@@ -2121,10 +2303,6 @@ retry:
return INTEGER;
}
}
- if (c == '-' || c == '+') {
- tokadd(c);
- c = nextc();
- }
for (;;) {
switch (c) {
@@ -2178,8 +2356,6 @@ retry:
pushback(c);
tokfix();
if (is_float) {
- double atof();
-
yylval.val = float_new(atof(tok()));
return FLOAT;
}
@@ -2248,7 +2424,7 @@ retry:
}
}
lex_state = EXPR_BEG;
- return c;
+ return '~';
case '(':
if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
@@ -2311,7 +2487,16 @@ retry:
quotation:
if (!isalnum(c)) {
term = c;
- c = '"';
+ switch (c) {
+ case '\'':
+ c = 'q'; break;
+ case '/':
+ c = 'r'; break;
+ case '`':
+ c = 'x'; break;
+ default:
+ c = 'Q';break;
+ }
}
else {
term = nextc();
@@ -2387,6 +2572,15 @@ retry:
yylval.id = rb_intern(tok());
return GVAR;
+ case '-':
+ tokadd('$');
+ tokadd(c);
+ c = nextc();
+ tokadd(c);
+ tokfix();
+ yylval.id = rb_intern(tok());
+ return GVAR;
+
case '&': /* $&: last match */
case '`': /* $`: string before last match */
case '\'': /* $': string after last match */
@@ -2468,11 +2662,10 @@ retry:
/* See if it is a reserved word. */
while (low <= high) {
mid = low + (high - low)/2;
- if (( c = strcmp(mid->name, tok())) == 0) {
+ if ((c = strcmp(mid->name, tok())) == 0) {
enum lex_state state = lex_state;
lex_state = mid->state;
- if (state != EXPR_BEG
- && state != EXPR_BEG) {
+ if (state != EXPR_BEG) {
if (mid->id == IF) return IF_MOD;
if (mid->id == UNLESS) return UNLESS_MOD;
if (mid->id == WHILE) return WHILE_MOD;
@@ -2512,6 +2705,7 @@ retry:
result = IDENTIFIER;
}
}
+ tokfix();
yylval.id = rb_intern(tok());
return result;
}
@@ -2525,7 +2719,6 @@ str_extend(list, term)
int c;
VALUE ss;
NODE *node;
- ID id;
int nest;
c = nextc();
@@ -2579,6 +2772,7 @@ str_extend(list, term)
if (c == term) {
list_append(list, NEW_STR(str_new2("#$")));
pushback(c);
+ newtok();
return list;
}
switch (c) {
@@ -2618,7 +2812,6 @@ str_extend(list, term)
switch (c) {
case -1:
if (nest > 0) {
- bad_sub:
Error("bad substitution in string");
newtok();
return list;
@@ -2647,7 +2840,6 @@ str_extend(list, term)
newtok();
return list;
}
- add_char:
default:
tokadd(c);
break;
@@ -2665,11 +2857,11 @@ str_extend(list, term)
}
NODE*
-newnode(type, a0, a1, a2)
+node_newnode(type, a0, a1, a2)
enum node_type type;
NODE *a0, *a1, *a2;
{
- NODE *n = (NODE*)newobj();
+ NODE *n = (NODE*)rb_newobj();
n->flags |= T_NODE;
nd_set_type(n, type);
@@ -2690,41 +2882,79 @@ nodetype(node) /* for debug */
return (enum node_type)nd_type(node);
}
+int
+nodeline(node)
+ NODE *node;
+{
+ return nd_line(node);
+}
+
+static NODE*
+newline_node(node)
+ NODE *node;
+{
+ NODE *nl = 0;
+ if (node) {
+ nl = NEW_NEWLINE(node);
+ fixpos(nl, node);
+ nl->nd_nth = nd_line(node);
+ }
+ return nl;
+}
+
+static void
+fixpos(node, orig)
+ NODE *node, *orig;
+{
+ if (!node) return;
+ if (!orig) return;
+ node->file = orig->file;
+ nd_set_line(node, nd_line(orig));
+}
+
static NODE*
block_append(head, tail)
NODE *head, *tail;
{
extern int verbose;
- NODE *last;
+ NODE *end;
if (tail == 0) return head;
if (head == 0) return tail;
- if (nd_type(head) != NODE_BLOCK)
- head = last = NEW_BLOCK(head);
+ if (nd_type(head) != NODE_BLOCK) {
+ end = NEW_BLOCK(head);
+ end->nd_end = end;
+ fixpos(end, head);
+ head = end;
+ }
else {
- last = head;
- while (last->nd_next) {
- last = last->nd_next;
- }
+ end = head->nd_end;
}
if (verbose) {
- switch (nd_type(last->nd_head)) {
+ NODE *nd = end->nd_head;
+ newline:
+ switch (nd_type(nd)) {
case NODE_RETURN:
Warning("statement not reached");
break;
+ case NODE_NEWLINE:
+ nd = nd->nd_next;
+ goto newline;
+
default:
break;
}
}
-
+
if (nd_type(tail) != NODE_BLOCK) {
tail = NEW_BLOCK(tail);
+ tail->nd_end = tail;
}
- last->nd_next = tail;
- head->nd_alen += tail->nd_alen;
+ end->nd_next = tail;
+ head->nd_end = tail->nd_end;
return head;
}
@@ -2792,7 +3022,7 @@ gettable(id)
if (local_id(id)) return NEW_LVAR(id);
if (dyna_var_defined(id)) return NEW_DVAR(id);
/* method call without arguments */
- return NEW_FCALL(id, 0);
+ return NEW_VCALL(id);
}
else if (is_global_id(id)) {
return NEW_GVAR(id);
@@ -2808,7 +3038,7 @@ gettable(id)
}
static NODE*
-asignable(id, val)
+assignable(id, val)
ID id;
NODE *val;
{
@@ -2818,11 +3048,12 @@ asignable(id, val)
yyerror("Can't change the value of self");
}
else if (id == NIL) {
- yyerror("Can't asign to nil");
+ yyerror("Can't assign to nil");
}
else if (is_local_id(id)) {
- if (local_id(id) || !dyna_in_block())
+ if (local_id(id) || !dyna_in_block()) {
lhs = NEW_LASGN(id, val);
+ }
else{
dyna_var_asgn(id, TRUE);
lhs = NEW_DASGN(id, val);
@@ -2836,7 +3067,7 @@ asignable(id, val)
}
else if (is_const_id(id)) {
if (cur_mid || in_single)
- yyerror("dynamic constant asignment");
+ yyerror("dynamic constant assignment");
lhs = NEW_CASGN(id, val);
}
else {
@@ -2918,6 +3149,9 @@ value_expr(node)
case NODE_IF:
return value_expr(node->nd_body) && value_expr(node->nd_else);
+ case NODE_NEWLINE:
+ return value_expr(node->nd_next);
+
default:
return TRUE;
}
@@ -2934,6 +3168,8 @@ cond0(node)
switch (type) {
case NODE_DREGX:
case NODE_DREGX_ONCE:
+ local_cnt('_');
+ local_cnt('~');
return call_op(NEW_GVAR(rb_intern("$_")),MATCH,1,node);
case NODE_DOT2:
@@ -2946,6 +3182,8 @@ cond0(node)
case NODE_LIT:
if (TYPE(node->nd_lit) == T_REGEXP) {
+ local_cnt('_');
+ local_cnt('~');
return NEW_MATCH(node);
}
default:
@@ -2966,26 +3204,28 @@ cond(node)
case NODE_GASGN:
case NODE_IASGN:
case NODE_CASGN:
- Warning("asignment in condition");
+ Warning("assignment in condition");
break;
+ case NODE_NEWLINE:
+ node->nd_next = cond0(node->nd_next);
+ return node;
+ default:
+ break;
}
- node = cond0(node);
- if (type == NODE_CALL && node->nd_mid == '!') {
- if (node->nd_args || node->nd_recv == 0) {
- Bug("method `!' called with wrong # of operand");
- }
- node->nd_recv = cond0(node->nd_recv);
- }
- return node;
+ return cond0(node);
}
static NODE*
cond2(node)
NODE *node;
{
+ enum node_type type;
+
node = cond(node);
- if (nd_type(node) == NODE_LIT && FIXNUM_P(node->nd_lit)) {
+ type = nd_type(node);
+ if (type == NODE_NEWLINE) node = node->nd_next;
+ if (type == NODE_LIT && FIXNUM_P(node->nd_lit)) {
return call_op(node,EQ,1,NEW_GVAR(rb_intern("$.")));
}
return node;
@@ -2998,13 +3238,14 @@ logop(type, left, right)
{
value_expr(left);
- return newnode(type, cond(left), cond(right));
+ return node_newnode(type, cond(left), cond(right));
}
st_table *new_idhash();
static struct local_vars {
ID *tbl;
+ int nofree;
int cnt;
int dlev;
struct local_vars *prev;
@@ -3017,6 +3258,7 @@ local_push()
local = ALLOC(struct local_vars);
local->prev = lvtbl;
+ local->nofree = 0;
local->cnt = 0;
local->tbl = 0;
local->dlev = 0;
@@ -3029,13 +3271,17 @@ local_pop()
struct local_vars *local = lvtbl;
lvtbl = local->prev;
- if (local->tbl) local->tbl[0] = local->cnt;
+ if (local->tbl) {
+ local->tbl[0] = local->cnt;
+ if (!local->nofree) free(local->tbl);
+ }
free(local);
}
static ID*
local_tbl()
{
+ lvtbl->nofree = 1;
return lvtbl->tbl;
}
@@ -3051,6 +3297,7 @@ local_cnt(id)
if (lvtbl->tbl[cnt] == id) return cnt-1;
}
+
if (lvtbl->tbl == 0) {
lvtbl->tbl = ALLOC_N(ID, 2);
lvtbl->tbl[0] = 0;
@@ -3080,12 +3327,7 @@ static void
top_local_init()
{
local_push();
- if (the_scope->local_tbl) {
- lvtbl->cnt = the_scope->local_tbl[0];
- }
- else {
- lvtbl->cnt = 0;
- }
+ lvtbl->cnt = the_scope->local_tbl?the_scope->local_tbl[0]:0;
if (lvtbl->cnt > 0) {
lvtbl->tbl = ALLOC_N(ID, lvtbl->cnt+1);
MEMCPY(lvtbl->tbl, the_scope->local_tbl, ID, lvtbl->cnt+1);
@@ -3109,25 +3351,33 @@ top_local_setup()
i = lvtbl->tbl[0];
if (i < len) {
- if (the_scope->flag == SCOPE_ALLOCA) {
- VALUE *vars = the_scope->local_vars;
- the_scope->local_vars = ALLOC_N(VALUE, len);
- if (vars) {
- MEMCPY(the_scope->local_vars, vars, VALUE, i);
- memclear(the_scope->local_vars+i, len-i);
+ if (i == 0 || the_scope->flag == SCOPE_ALLOCA) {
+ VALUE *vars = ALLOC_N(VALUE, len+1);
+ if (the_scope->local_vars) {
+ *vars++ = the_scope->local_vars[-1];
+ MEMCPY(vars, the_scope->local_vars, VALUE, i);
+ memclear(vars+i, len-i);
}
else {
- memclear(the_scope->local_vars, len);
+ *vars++ = 0;
+ memclear(vars, len);
}
- the_scope->flag = SCOPE_MALLOC;
+ the_scope->local_vars = vars;
+ the_scope->flag |= SCOPE_MALLOC;
}
else {
- REALLOC_N(the_scope->local_vars, VALUE, len);
+ VALUE *vars = the_scope->local_vars-1;
+ REALLOC_N(vars, VALUE, len+1);
+ the_scope->local_vars = vars+1;
memclear(the_scope->local_vars+i, len-i);
- free(the_scope->local_tbl);
}
lvtbl->tbl[0] = len;
+ if (the_scope->local_tbl && the_scope->local_vars[-1] == 0) {
+ free(the_scope->local_tbl);
+ }
+ the_scope->local_vars[-1] = 0;
the_scope->local_tbl = lvtbl->tbl;
+ lvtbl->nofree = 1;
}
}
local_pop();
@@ -3157,8 +3407,6 @@ dyna_in_block()
static void
cref_pop()
{
- NODE *cref = cur_cref;
-
cur_cref = cur_cref->nd_next;
}
@@ -3199,10 +3447,10 @@ static struct op_tbl rb_op_tbl[] = {
'/', "/",
'%', "%",
POW, "**",
- UPLUS, "+(unary)",
- UMINUS, "-(unary)",
UPLUS, "+@",
UMINUS, "-@",
+ UPLUS, "+(unary)",
+ UMINUS, "-(unary)",
'|', "|",
'^', "^",
'&', "&",
@@ -3280,13 +3528,13 @@ rb_intern(name)
break;
}
}
- if (id == 0) Bug("Unknown operator `%s'", name);
+ if (id == 0) NameError("Unknown operator `%s'", name);
break;
}
last = strlen(name)-1;
if (name[last] == '=') {
- /* attribute asignment */
+ /* attribute assignment */
char *buf = ALLOCA_N(char,last+1);
strncpy(buf, name, last);
@@ -3362,24 +3610,20 @@ rb_id2name(id)
return ok.name;
}
-static int
-const_check(id, val, class)
+int
+rb_is_const_id(id)
ID id;
- VALUE val;
- struct RClass *class;
{
- if (is_const_id(id) && rb_const_defined(class, id)) {
- Warning("constant redefined for %s", rb_class2name(class));
- return ST_STOP;
- }
- return ST_CONTINUE;
+ if (is_const_id(id)) return TRUE;
+ return FALSE;
}
-void
-rb_const_check(class, module)
- struct RClass *class, *module;
+int
+rb_is_instance_id(id)
+ ID id;
{
- st_foreach(module->iv_tbl, const_check, class);
+ if (is_instance_id(id)) return TRUE;
+ return FALSE;
}
void
diff --git a/process.c b/process.c
index c3e7bffa54..4d1d96e980 100644
--- a/process.c
+++ b/process.c
@@ -16,6 +16,10 @@
#include <errno.h>
#include <ctype.h>
#include <signal.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifndef NT
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#else
@@ -24,6 +28,9 @@ struct timeval {
long tv_usec; /* and microseconds */
};
#endif
+#endif /* NT */
+
+struct timeval time_timeval();
#ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h>
@@ -52,10 +59,6 @@ get_ppid()
#endif
}
-#ifdef NT
-#define HAVE_WAITPID
-#endif
-
VALUE last_status = Qnil;
#if !defined(HAVE_WAITPID) && !defined(HAVE_WAIT4)
@@ -71,6 +74,12 @@ rb_waitpid(pid, flags, st)
int *st;
{
int result;
+#if defined(THREAD) && (defined(HAVE_WAITPID) || defined(HAVE_WAIT4))
+ int oflags = flags;
+ if (!thread_alone()) { /* there're other threads to run */
+ flags |= WNOHANG;
+ }
+#endif
#ifdef HAVE_WAITPID
retry:
@@ -84,9 +93,18 @@ rb_waitpid(pid, flags, st)
}
return -1;
}
+#ifdef THREAD
+ if (result == 0) {
+ if (oflags & WNOHANG) return 0;
+ thread_schedule();
+ if (thread_alone()) flags = oflags;
+ goto retry;
+ }
+#endif
#else
#ifdef HAVE_WAIT4
retry:
+
result = wait4(pid, st, flags, NULL);
if (result < 0) {
if (errno == EINTR) {
@@ -97,6 +115,14 @@ rb_waitpid(pid, flags, st)
}
return -1;
}
+#ifdef THREAD
+ if (result == 0) {
+ if (oflags & WNOHANG) return 0;
+ thread_schedule();
+ if (thread_alone()) flags = oflags;
+ goto retry;
+ }
+#endif
#else
if (pid_tbl && st_lookup(pid_tbl, pid, st)) {
last_status = INT2FIX(*st);
@@ -136,7 +162,7 @@ rb_waitpid(pid, flags, st)
struct wait_data {
int pid;
int status;
-}
+};
static int
wait_each(key, value, data)
@@ -161,8 +187,8 @@ f_wait()
data.status = -1;
st_foreach(pid_tbl, wait_each, &data);
if (data.status != -1) {
- status = data.status;
- return data.pid;
+ last_status = data.status;
+ return INT2FIX(data.pid);
}
#endif
@@ -200,27 +226,23 @@ char *strtok();
static void
before_exec()
{
- {
- struct itimerval tval;
+ struct itimerval tval;
- tval.it_interval.tv_sec = 0;
- tval.it_interval.tv_usec = 0;
- tval.it_value = tval.it_interval;
- setitimer(ITIMER_VIRTUAL, &tval, NULL);
- }
+ tval.it_interval.tv_sec = 0;
+ tval.it_interval.tv_usec = 0;
+ tval.it_value = tval.it_interval;
+ setitimer(ITIMER_VIRTUAL, &tval, NULL);
}
static void
after_exec()
{
- {
- struct itimerval tval;
+ struct itimerval tval;
- tval.it_interval.tv_sec = 1;
- tval.it_interval.tv_usec = 0;
- tval.it_value = tval.it_interval;
- setitimer(ITIMER_VIRTUAL, &tval, NULL);
- }
+ tval.it_interval.tv_sec = 0;
+ tval.it_interval.tv_usec = 100000;
+ tval.it_value = tval.it_interval;
+ setitimer(ITIMER_VIRTUAL, &tval, NULL);
}
#else
#define before_exec()
@@ -229,17 +251,63 @@ after_exec()
extern char *dln_find_exe();
+static void
+security(str)
+ char *str;
+{
+ extern int env_path_tainted;
+ extern VALUE eSecurityError;
+
+ if (rb_safe_level() > 0 && env_path_tainted) {
+ Raise(eSecurityError, "Insecure PATH - %s", str);
+ }
+}
+
static int
proc_exec_v(argv)
char **argv;
{
char *prog;
+ security(argv[0]);
prog = dln_find_exe(argv[0], 0);
if (!prog) {
errno = ENOENT;
return -1;
}
+#if (defined(MSDOS) && !defined(DJGPP)) || defined(__human68k__)
+ {
+#if defined(__human68k__)
+#define COMMAND "command.x"
+#else
+#define COMMAND "command.com"
+#endif
+ char *extension;
+
+ if ((extension = strrchr(prog, '.')) != NULL && strcasecmp(extension, ".bat") == 0) {
+ char **new_argv;
+ char *p;
+ int n;
+
+ for (n = 0; argv[n]; n++)
+ /* no-op */;
+ new_argv = ALLOCA_N(char *, n + 2);
+ for (; n > 0; n--)
+ new_argv[n + 1] = argv[n];
+ new_argv[1] = strcpy(ALLOCA_N(char, strlen(argv[0]) + 1), argv[0]);
+ for (p = new_argv[1]; *p != '\0'; p++)
+ if (*p == '/')
+ *p = '\\';
+ new_argv[0] = COMMAND;
+ argv = new_argv;
+ prog = dln_find_exe(argv[0], 0);
+ if (!prog) {
+ errno = ENOENT;
+ return -1;
+ }
+ }
+ }
+#endif /* MSDOS or __human68k__ */
before_exec();
execv(prog, argv);
after_exec();
@@ -256,7 +324,7 @@ proc_exec_n(argc, argv)
args = ALLOCA_N(char*, argc+1);
for (i=0; i<argc; i++) {
- Check_Type(argv[i], T_STRING);
+ Check_SafeStr(argv[i]);
args[i] = RSTRING(argv[i])->ptr;
}
args[i] = 0;
@@ -273,15 +341,34 @@ rb_proc_exec(str)
char *s = str, *t;
char **argv, **a;
+ security(str);
for (s=str; *s; s++) {
if (*s != ' ' && !isalpha(*s) && strchr("*?{}[]<>()~&|\\$;'`\"\n",*s)) {
#if defined(MSDOS)
- system(str);
+ int state;
+ before_exec();
+ state = system(str);
+ after_exec();
+ if (state != -1)
+ exit(state);
+#else
+#if defined(__human68k__)
+ char *shell = dln_find_exe("sh", 0);
+ int state = -1;
+ before_exec();
+ if (shell)
+ execl(shell, "sh", "-c", str, (char *) NULL);
+ else
+ state = system(str);
+ after_exec();
+ if (state != -1)
+ exit(state);
#else
before_exec();
execl("/bin/sh", "sh", "-c", str, (char *)NULL);
after_exec();
#endif
+#endif
return -1;
}
}
@@ -301,13 +388,102 @@ rb_proc_exec(str)
return -1;
}
+#if defined(__human68k__)
+static int
+proc_spawn_v(argv)
+ char **argv;
+{
+ char *prog;
+ char *extension;
+ int state;
+
+ prog = dln_find_exe(argv[0], 0);
+ if (!prog)
+ return -1;
+
+ if ((extension = strrchr(prog, '.')) != NULL && strcasecmp(extension, ".bat") == 0) {
+ char **new_argv;
+ char *p;
+ int n;
+
+ for (n = 0; argv[n]; n++)
+ /* no-op */;
+ new_argv = ALLOCA_N(char *, n + 2);
+ for (; n > 0; n--)
+ new_argv[n + 1] = argv[n];
+ new_argv[1] = strcpy(ALLOCA_N(char, strlen(argv[0]) + 1), argv[0]);
+ for (p = new_argv[1]; *p != '\0'; p++)
+ if (*p == '/')
+ *p = '\\';
+ new_argv[0] = COMMAND;
+ argv = new_argv;
+ prog = dln_find_exe(argv[0], 0);
+ if (!prog) {
+ errno = ENOENT;
+ return -1;
+ }
+ }
+ before_exec();
+ state = spawnv(P_WAIT, prog, argv);
+ after_exec();
+ return state;
+}
+
+static int
+proc_spawn_n(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ char **args;
+ int i;
+
+ args = ALLOCA_N(char *, argc + 1);
+ for (i = 0; i < argc; i++) {
+ Check_SafeStr(argv[i]);
+ args[i] = RSTRING(argv[i])->ptr;
+ }
+ args[i] = (char *) 0;
+ if (args[0])
+ return proc_exec_v(args);
+ return -1;
+}
+
+static int
+proc_spawn(str)
+ char *str;
+{
+ char *s = str, *t;
+ char **argv, **a;
+ int state;
+
+ for (s = str; *s; s++) {
+ if (*s != ' ' && !isalpha(*s) && strchr("*?{}[]<>()~&|\\$;'`\"\n",*s)) {
+ char *shell = dln_find_exe("sh", 0);
+ before_exec();
+ state = shell ? spawnl(P_WAIT, shell, "sh", "-c", str, (char *) NULL) : system(str) ;
+ after_exec();
+ return state;
+ }
+ }
+ a = argv = ALLOCA_N(char *, (s - str) / 2 + 2);
+ s = ALLOCA_N(char, s - str + 1);
+ strcpy(s, str);
+ if (*a++ = strtok(s, " \t")) {
+ while (t = strtok(NULL, " \t"))
+ *a++ = t;
+ *a = NULL;
+ }
+ return argv[0] ? proc_spawn_v(argv) : -1 ;
+}
+#endif /* __human68k__ */
+
static VALUE
f_exec(argc, argv)
int argc;
VALUE *argv;
{
if (argc == 1) {
- Check_Type(argv[0], T_STRING);
+ Check_SafeStr(argv[0]);
rb_proc_exec(RSTRING(argv[0])->ptr);
}
else {
@@ -320,10 +496,15 @@ static VALUE
f_fork(obj)
VALUE obj;
{
+#if !defined(__human68k__)
int pid;
+ rb_secure(2);
switch (pid = fork()) {
case 0:
+#ifdef linux
+ after_exec();
+#endif
if (iterator_p()) {
rb_yield(Qnil);
_exit(0);
@@ -337,6 +518,9 @@ f_fork(obj)
default:
return INT2FIX(pid);
}
+#else
+ rb_notimplement();
+#endif
}
static VALUE
@@ -345,6 +529,7 @@ f_exit_bang(obj, status)
{
int code = -1;
+ rb_secure(2);
if (FIXNUM_P(status)) {
code = INT2FIX(status);
}
@@ -358,18 +543,26 @@ void
rb_syswait(pid)
int pid;
{
- RETSIGTYPE (*hfunc)(), (*ifunc)(), (*qfunc)();
+ RETSIGTYPE (*hfunc)(), (*qfunc)(), (*ifunc)();
int status;
+#ifdef SIGHUP
hfunc = signal(SIGHUP, SIG_IGN);
- ifunc = signal(SIGINT, SIG_IGN);
+#endif
+#ifdef SIGQUIT
qfunc = signal(SIGQUIT, SIG_IGN);
+#endif
+ ifunc = signal(SIGINT, SIG_IGN);
if (rb_waitpid(pid, 0, &status) < 0) rb_sys_fail("wait");
+#ifdef SIGHUP
signal(SIGHUP, hfunc);
- signal(SIGINT, ifunc);
+#endif
+#ifdef SIGQUIT
signal(SIGQUIT, qfunc);
+#endif
+ signal(SIGINT, ifunc);
}
static VALUE
@@ -383,6 +576,7 @@ f_system(argc, argv)
cmd = ary_join(ary_new4(argc, argv), str_new2(" "));
+ Check_SafeStr(cmd);
state = do_spawn(RSTRING(cmd)->ptr);
last_status = INT2FIX(state);
@@ -395,12 +589,33 @@ f_system(argc, argv)
cmd = ary_join(ary_new4(argc, argv), str_new2(" "));
+ Check_SafeStr(cmd);
state = system(RSTRING(cmd)->ptr);
last_status = INT2FIX(state);
if (state == 0) return TRUE;
return FALSE;
#else
+#if defined(__human68k__)
+ int i;
+ int state;
+
+ fflush(stdin);
+ fflush(stdout);
+ fflush(stderr);
+ if (argc == 0) {
+ last_status = INT2FIX(0);
+ return INT2FIX(0);
+ }
+
+ for (i = 0; i < argc; i++)
+ Check_SafeStr(argv[i]);
+
+ state = argc == 1 ? proc_spawn(RSTRING(argv[0])->ptr) : proc_spawn_n(argc, argv) ;
+ last_status = state == -1 ? INT2FIX(127) : INT2FIX(state);
+
+ return state == 0 ? TRUE : FALSE ;
+#else
int i;
int pid;
@@ -413,7 +628,7 @@ f_system(argc, argv)
}
for (i=0; i<argc; i++) {
- Check_Type(argv[i], T_STRING);
+ Check_SafeStr(argv[i]);
}
retry:
@@ -430,7 +645,11 @@ f_system(argc, argv)
case -1:
if (errno == EAGAIN) {
- sleep(5);
+#ifdef THREAD
+ thread_sleep(1);
+#else
+ sleep(1);
+#endif
goto retry;
}
rb_sys_fail(0);
@@ -444,22 +663,20 @@ f_system(argc, argv)
return FALSE;
#endif
#endif
+#endif
}
-struct timeval time_timeval();
-
-VALUE
+static VALUE
f_sleep(argc, argv)
int argc;
VALUE *argv;
{
int beg, end;
- int n;
beg = time(0);
#ifdef THREAD
if (argc == 0) {
- thread_sleep();
+ thread_sleep_forever();
}
else if (argc == 1) {
thread_wait_for(time_timeval(argv[0]));
@@ -472,10 +689,11 @@ f_sleep(argc, argv)
}
else if (argc == 1) {
struct timeval tv;
+ int n;
tv = time_timeval(argv[0]);
TRAP_BEG;
- sleep(tv.tv_sec);
+ n = select(0, 0, 0, 0, &tv);
TRAP_END;
if (n<0) rb_sys_fail(0);
}
@@ -489,58 +707,48 @@ f_sleep(argc, argv)
return INT2FIX(end);
}
-#if !defined(NT) && !defined(DJGPP)
-#ifdef _POSIX_SOURCE
-static VALUE
-proc_getpgrp()
-{
- int pgrp;
-
- pgrp = getpgrp();
- if (pgrp < 0) rb_sys_fail(0);
- return INT2FIX(pgrp);
-}
-
-static VALUE
-proc_setpgrp(obj)
- VALUE obj;
-{
- int pgrp;
-
- if (setpgrp() < 0) rb_sys_fail(0);
- return Qnil;
-}
-
-#else
-
+#if !defined(NT) && !defined(DJGPP) && !defined(__human68k__)
static VALUE
proc_getpgrp(argc, argv)
int argc;
VALUE *argv;
{
+ int pgrp;
+#ifdef BSD_GETPGRP
VALUE vpid;
- int pgrp, pid;
+ int pid;
rb_scan_args(argc, argv, "01", &vpid);
- if (NIL_P(vpid)) pid = 0;
- else pid = NUM2INT(vpid);
- pgrp = getpgrp(pid);
+ pid = NUM2INT(vpid);
+ pgrp = BSD_GETPGRP(pid);
+#else
+ rb_scan_args(argc, argv, "0");
+ pgrp = getpgrp();
+#endif
if (pgrp < 0) rb_sys_fail(0);
return INT2FIX(pgrp);
}
static VALUE
-proc_setpgrp(obj, pid, pgrp)
- VALUE obj, pid, pgrp;
+proc_setpgrp(argc, argv)
+ int argc;
+ VALUE *argv;
{
+#ifdef BSD_SETPGRP
+ VALUE pid, pgrp;
int ipid, ipgrp;
+ rb_scan_args(argc, argv, "02", &pid, &pgrp);
+
ipid = NUM2INT(pid);
ipgrp = NUM2INT(pgrp);
- if (setpgrp(ipid, ipgrp) < 0) rb_sys_fail(0);
+ if (BSD_SETPGRP(ipid, ipgrp) < 0) rb_sys_fail(0);
+#else
+ rb_scan_args(argc, argv, "0");
+ if (setpgrp() < 0) rb_sys_fail(0);
+#endif
return Qnil;
}
-#endif
#ifdef HAVE_SETPGID
static VALUE
@@ -624,7 +832,7 @@ proc_setuid(obj, id)
}
#endif
#endif
- return INT2FIX(uid);
+ return INT2FIX(uid);
}
static VALUE
@@ -656,7 +864,7 @@ proc_setgid(obj, id)
}
#endif
#endif
- return INT2FIX(gid);
+ return INT2FIX(gid);
}
static VALUE
@@ -722,19 +930,21 @@ extern VALUE f_kill();
void
Init_process()
{
- extern VALUE cKernel;
+ extern VALUE mKernel;
rb_define_virtual_variable("$$", get_pid, 0);
rb_define_readonly_variable("$?", &last_status);
+ rb_define_global_function("exec", f_exec, -1);
#ifndef NT
- rb_define_private_method(cKernel, "exec", f_exec, -1);
- rb_define_private_method(cKernel, "fork", f_fork, 0);
- rb_define_private_method(cKernel, "exit!", f_exit_bang, 1);
- rb_define_private_method(cKernel, "system", f_system, -1);
- rb_define_private_method(cKernel, "sleep", f_sleep, -1);
+ rb_define_global_function("fork", f_fork, 0);
+#endif
+ rb_define_global_function("exit!", f_exit_bang, 1);
+ rb_define_global_function("system", f_system, -1);
+ rb_define_global_function("sleep", f_sleep, -1);
mProcess = rb_define_module("Process");
+#if !defined(NT) && !defined(DJGPP)
#ifdef WNOHANG
rb_define_const(mProcess, "WNOHANG", INT2FIX(WNOHANG));
#else
@@ -749,23 +959,20 @@ Init_process()
#ifndef NT
rb_define_singleton_method(mProcess, "fork", f_fork, 0);
- rb_define_singleton_method(mProcess, "exit!", f_exit_bang, 1);
#endif
+ rb_define_singleton_method(mProcess, "exit!", f_exit_bang, 1);
rb_define_module_function(mProcess, "kill", f_kill, -1);
+#ifndef NT
rb_define_module_function(mProcess, "wait", f_wait, 0);
rb_define_module_function(mProcess, "waitpid", f_waitpid, 2);
rb_define_module_function(mProcess, "pid", get_pid, 0);
rb_define_module_function(mProcess, "ppid", get_ppid, 0);
+#endif
-#if !defined(NT) && !defined(DJGPP)
-#ifdef _POSIX_SOURCE
- rb_define_module_function(mProcess, "getpgrp", proc_getpgrp, 0);
- rb_define_module_function(mProcess, "setpgrp", proc_setpgrp, 0);
-#else
+#if !defined(NT) && !defined(DJGPP) && !defined(__human68k__)
rb_define_module_function(mProcess, "getpgrp", proc_getpgrp, -1);
- rb_define_module_function(mProcess, "setpgrp", proc_setpgrp, 2);
-#endif
+ rb_define_module_function(mProcess, "setpgrp", proc_setpgrp, -1);
#ifdef HAVE_SETPGID
rb_define_module_function(mProcess, "setpgid", proc_setpgid, 2);
#endif
diff --git a/random.c b/random.c
index c9f4004ebb..80be6200a3 100644
--- a/random.c
+++ b/random.c
@@ -22,9 +22,7 @@ f_srand(argc, argv, obj)
VALUE obj;
{
int seed, old;
-#ifdef HAVE_RANDOM
static int saved_seed;
-#endif
if (rb_scan_args(argc, argv, "01", &seed) == 0) {
seed = time(0);
@@ -48,7 +46,10 @@ f_srand(argc, argv, obj)
return int2inum(old);
#else
- old = srand(seed);
+ srand(seed);
+ old = saved_seed;
+ saved_seed = seed;
+
return int2inum(old);
#endif
}
@@ -92,8 +93,8 @@ f_rand(obj, vmax)
void
Init_Random()
{
- extern VALUE cKernel;
+ extern VALUE mKernel;
- rb_define_private_method(cKernel, "srand", f_srand, -1);
- rb_define_private_method(cKernel, "rand", f_rand, 1);
+ rb_define_global_function("srand", f_srand, -1);
+ rb_define_global_function("rand", f_rand, 1);
}
diff --git a/range.c b/range.c
index da0e6a2d83..697fc98b68 100644
--- a/range.c
+++ b/range.c
@@ -49,7 +49,7 @@ range_new(first, last)
}
static VALUE
-range_match(rng, obj)
+range_eqq(rng, obj)
VALUE rng, obj;
{
VALUE first, last;
@@ -197,7 +197,7 @@ Init_Range()
cRange = rb_define_class("Range", cObject);
rb_include_module(cRange, mEnumerable);
rb_define_singleton_method(cRange, "new", range_s_new, 2);
- rb_define_method(cRange, "===", range_match, 1);
+ rb_define_method(cRange, "===", range_eqq, 1);
rb_define_method(cRange, "each", range_each, 0);
rb_define_method(cRange, "first", range_first, 0);
rb_define_method(cRange, "last", range_last, 0);
diff --git a/re.c b/re.c
index 673306e0f7..19b274bd4f 100644
--- a/re.c
+++ b/re.c
@@ -82,17 +82,18 @@ str_cicmp(str1, str2)
p1 = str1->ptr; p2 = str2->ptr;
for (i = 0; i < len; i++, p1++, p2++) {
- if (casetable[(int)*p1] != casetable[(int)*p2])
- return casetable[(int)*p1] - casetable[(int)*p2];
+ if (casetable[(unsigned)*p1] != casetable[(unsigned)*p2])
+ return casetable[(unsigned)*p1] - casetable[(unsigned)*p2];
}
return str1->len - str2->len;
}
#define REG_IGNORECASE FL_USER0
-#define KCODE_NONE 0
-#define KCODE_EUC FL_USER1
-#define KCODE_SJIS FL_USER2
+#define KCODE_NONE 0
+#define KCODE_EUC FL_USER2
+#define KCODE_SJIS FL_USER3
+#define KCODE_FIXED FL_USER4
#define KCODE_MASK (KCODE_EUC|KCODE_SJIS)
static int reg_kcode =
@@ -106,6 +107,69 @@ static int reg_kcode =
# endif
#endif
+static void
+kcode_euc(reg)
+ struct RRegexp *reg;
+{
+ FL_UNSET(reg, KCODE_MASK);
+ FL_SET(reg, KCODE_EUC);
+ FL_SET(reg, KCODE_FIXED);
+}
+
+static void
+kcode_sjis(reg)
+ struct RRegexp *reg;
+{
+ FL_UNSET(reg, KCODE_MASK);
+ FL_SET(reg, KCODE_SJIS);
+ FL_SET(reg, KCODE_FIXED);
+}
+
+static void
+kcode_none(reg)
+ struct RRegexp *reg;
+{
+ FL_UNSET(reg, KCODE_MASK);
+ FL_SET(reg, KCODE_FIXED);
+}
+
+static void
+kcode_set_option(reg)
+ struct RRegexp *reg;
+{
+ if (!FL_TEST(reg, KCODE_FIXED)) return;
+
+ re_syntax_options &= ~RE_MBCTYPE_MASK;
+ switch ((RBASIC(reg)->flags & KCODE_MASK)) {
+ case KCODE_NONE:
+ break;
+ case KCODE_EUC:
+ re_syntax_options |= RE_MBCTYPE_EUC;
+ break;
+ case KCODE_SJIS:
+ re_syntax_options |= RE_MBCTYPE_SJIS;
+ break;
+ }
+ re_set_syntax(re_syntax_options);
+}
+
+static void
+kcode_reset_option()
+{
+ re_syntax_options &= ~RE_MBCTYPE_MASK;
+ switch (reg_kcode) {
+ case KCODE_NONE:
+ break;
+ case KCODE_EUC:
+ re_syntax_options |= RE_MBCTYPE_EUC;
+ break;
+ case KCODE_SJIS:
+ re_syntax_options |= RE_MBCTYPE_SJIS;
+ break;
+ }
+ re_set_syntax(re_syntax_options);
+}
+
extern int rb_in_eval;
static VALUE
@@ -144,8 +208,10 @@ reg_desc(s, len, re)
}
}
str_cat(str, "/", 1);
- if (re && FL_TEST(re, REG_IGNORECASE)) {
- str_cat(str, "i", 1);
+ if (re) {
+ if (FL_TEST(re, REG_IGNORECASE)) {
+ str_cat(str, "i", 1);
+ }
}
return str;
}
@@ -158,25 +224,24 @@ reg_inspect(re)
}
static void
-reg_raise(s, len, err, compile, re)
+reg_raise(s, len, err, re)
char *s;
int len;
char *err;
- int compile;
VALUE re;
{
VALUE desc = reg_desc(s, len, re);
- if (!compile)
+ if (rb_in_eval)
Raise(eRegxpError, "%s: %s", err, RSTRING(desc)->ptr);
else
Error("%s: %s", err, RSTRING(desc)->ptr);
}
static Regexp*
-make_regexp(s, len)
+make_regexp(s, len, flag)
char *s;
- int len;
+ int len, flag;
{
Regexp *rp;
char *err;
@@ -193,9 +258,13 @@ make_regexp(s, len)
rp->buffer = ALLOC_N(char, 16);
rp->allocated = 16;
rp->fastmap = ALLOC_N(char, 256);
-
- if ((err = re_compile_pattern(s, (size_t)len, rp)) != NULL) {
- reg_raise(s, len, err, !rb_in_eval, 0);
+ if (flag) {
+ rp->translate = casetable;
+ }
+ err = re_compile_pattern(s, (size_t)len, rp);
+ kcode_reset_option();
+ if (err != NULL) {
+ reg_raise(s, len, err, 0);
}
return rp;
@@ -205,44 +274,12 @@ extern VALUE cData;
static VALUE cMatch;
static VALUE
-match_to_a(match)
- struct RMatch *match;
-{
- struct re_registers *regs = match->regs;
- VALUE ary = ary_new(regs->num_regs);
- int i;
-
- for (i=0; i<regs->num_regs; i++) {
- if (regs->beg[0] == -1) ary_push(ary, Qnil);
- else ary_push(ary, str_new(match->ptr+regs->beg[i],
- regs->end[i]-regs->beg[i]));
- }
- return ary;
-}
-
-static VALUE
-match_to_s(match)
- struct RMatch *match;
-{
- int beg, len;
-
- if (match->regs->allocated == 0) return Qnil;
-
- beg = match->regs->beg[0];
- if (beg == -1) return Qnil;
-
- len = match->regs->end[0] - beg;
- return str_new(match->ptr+beg, len);
-}
-
-static VALUE
match_alloc()
{
NEWOBJ(match, struct RMatch);
OBJSETUP(match, cMatch, T_MATCH);
- match->ptr = 0;
- match->len = 0;
+ match->str = 0;
match->regs = ALLOC(struct re_registers);
MEMZERO(match->regs, struct re_registers, 1);
@@ -262,6 +299,7 @@ reg_search(reg, str, start, regs)
int casefold = RTEST(ignorecase);
VALUE match = 0;
struct re_registers *regs0 = 0;
+ int need_recompile = 0;
if (start > str->len) return -1;
@@ -273,11 +311,13 @@ reg_search(reg, str, start, regs)
if (reg->ptr->translate != casetable) {
reg->ptr->translate = casetable;
reg->ptr->fastmap_accurate = 0;
+ need_recompile = 1;
}
}
else if (reg->ptr->translate) {
reg->ptr->translate = NULL;
reg->ptr->fastmap_accurate = 0;
+ need_recompile = 1;
}
if (regs == (struct re_registers*)-1) {
@@ -290,18 +330,28 @@ reg_search(reg, str, start, regs)
if (regs && !match) regs0 = regs;
- if ((RBASIC(reg)->flags & KCODE_MASK) != reg_kcode) {
+ if (FL_TEST(reg, KCODE_FIXED)) {
+ kcode_set_option(reg);
+ }
+ else if ((RBASIC(reg)->flags & KCODE_MASK) != reg_kcode) {
+ need_recompile = 1;
+ RBASIC(reg)->flags = RBASIC(reg)->flags & ~KCODE_MASK;
+ RBASIC(reg)->flags |= reg_kcode;
+ }
+
+ if (need_recompile) {
char *err;
- if ((err = re_compile_pattern(reg->str, reg->len, reg->ptr)) != NULL) {
+ err = re_compile_pattern(reg->str, reg->len, reg->ptr);
+ if (err != NULL) {
+ kcode_reset_option();
reg_raise(reg->str, reg->len, err, reg);
}
- RBASIC(reg)->flags = RBASIC(reg)->flags & ~KCODE_MASK;
- RBASIC(reg)->flags |= reg_kcode;
}
result = re_search(reg->ptr, str->ptr, str->len,
start, str->len - start, regs0);
+ kcode_reset_option();
if (start == -2) {
reg_raise(reg->str, reg->len, "Stack overfow in regexp matcher", reg);
@@ -310,10 +360,7 @@ reg_search(reg, str, start, regs)
backref_set(Qnil);
}
else if (match) {
- RMATCH(match)->len = str->len;
- REALLOC_N(RMATCH(match)->ptr, char, str->len+1);
- memcpy(RMATCH(match)->ptr, str->ptr, str->len);
- RMATCH(match)->ptr[str->len] = '\0';
+ RMATCH(match)->str = str_new4(str);
backref_set(match);
}
if (regs && regs0 && regs0 != regs) re_copy_registers(regs, regs0);
@@ -349,7 +396,7 @@ reg_nth_match(nth, match)
if (start == -1) return Qnil;
end = match->END(nth);
len = end - start;
- return str_new(match->ptr + start, len);
+ return str_new(RSTRING(match->str)->ptr + start, len);
}
VALUE
@@ -365,7 +412,7 @@ reg_match_pre(match)
{
if (NIL_P(match)) return Qnil;
if (match->BEG(0) == -1) return Qnil;
- return str_new(match->ptr, match->BEG(0));
+ return str_new(RSTRING(match->str)->ptr, match->BEG(0));
}
VALUE
@@ -374,8 +421,8 @@ reg_match_post(match)
{
if (NIL_P(match)) return Qnil;
if (match->BEG(0) == -1) return Qnil;
- return str_new(match->ptr+match->END(0),
- match->len-match->END(0));
+ return str_new(RSTRING(match->str)->ptr+match->END(0),
+ RSTRING(match->str)->len-match->END(0));
}
VALUE
@@ -393,6 +440,57 @@ reg_match_last(match)
return reg_nth_match(i, match);
}
+static VALUE
+last_match_getter()
+{
+ return reg_last_match(backref_get());
+}
+
+static VALUE
+prematch_getter()
+{
+ return reg_match_pre(backref_get());
+}
+
+static VALUE
+postmatch_getter()
+{
+ return reg_match_post(backref_get());
+}
+
+static VALUE
+last_paren_match_getter()
+{
+ return reg_match_last(backref_get());
+}
+
+static VALUE
+match_to_a(match)
+ struct RMatch *match;
+{
+ struct re_registers *regs = match->regs;
+ VALUE ary = ary_new(regs->num_regs);
+ char *ptr = RSTRING(match->str)->ptr;
+ int i;
+
+ for (i=0; i<regs->num_regs; i++) {
+ if (regs->beg[0] == -1) ary_push(ary, Qnil);
+ else ary_push(ary, str_new(ptr+regs->beg[i],
+ regs->end[i]-regs->beg[i]));
+ }
+ return ary;
+}
+
+static VALUE
+match_to_s(match)
+ struct RMatch *match;
+{
+ VALUE str = reg_last_match(match);
+
+ if (NIL_P(str)) return str_new(0,0);
+ return str;
+}
+
void
reg_free(rp)
Regexp *rp;
@@ -405,35 +503,56 @@ Regexp *rp;
VALUE cRegexp;
static VALUE
-reg_new_1(class, s, len, ci)
+reg_new_1(class, s, len, flag)
VALUE class;
char *s;
- int len, ci;
+ int len;
+ int flag; /* CASEFOLD = 0x1 */
+ /* CODE_NONE = 0x2 */
+ /* CODE_EUC = 0x4 */
+ /* CODE_SJIS = 0x6 */
{
NEWOBJ(re, struct RRegexp);
OBJSETUP(re, class, T_REGEXP);
- re->ptr = make_regexp(s, len);
+ if (flag & 0x1) {
+ FL_SET(re, REG_IGNORECASE);
+ }
+ switch (flag & ~0x1) {
+ case 0:
+ default:
+ FL_SET(re, reg_kcode);
+ break;
+ case 2:
+ kcode_none(re);
+ break;
+ case 4:
+ kcode_euc(re);
+ break;
+ case 6:
+ kcode_sjis(re);
+ break;
+ }
+
+ kcode_set_option(re);
+ re->ptr = make_regexp(s, len, flag & 0x1);
re->str = ALLOC_N(char, len+1);
memcpy(re->str, s, len);
re->str[len] = '\0';
re->len = len;
- FL_SET(re, reg_kcode);
- if (ci) FL_SET(re, REG_IGNORECASE);
-
return (VALUE)re;
}
VALUE
-reg_new(s, len, ci)
+reg_new(s, len, flag)
char *s;
- int len, ci;
+ int len, flag;
{
- return reg_new_1(cRegexp, s, len, ci);
+ return reg_new_1(cRegexp, s, len, flag);
}
-int ign_cache;
+static int ign_cache;
static VALUE reg_cache;
VALUE
@@ -490,23 +609,39 @@ reg_s_new(argc, argv, self)
VALUE self;
{
VALUE src;
- int ci = 0;
+ int flag = 0;
- if (argc == 0 || argc > 2) {
+ if (argc == 0 || argc > 3) {
ArgError("wrong # of argument");
}
- if (argc == 2 && argv[1]) {
- ci = 1;
+ if (argc >= 2 && RTEST(argv[1])) {
+ flag = 1;
+ }
+ if (argc == 3) {
+ Check_Type(argv[2], T_STRING);
+ switch (RSTRING(argv[2])->ptr[0]) {
+ case 'n': case 'N':
+ flag |= 2;
+ break;
+ case 'e': case 'E':
+ flag |= 4;
+ break;
+ case 's': case 'S':
+ flag |= 6;
+ break;
+ default:
+ break;
+ }
}
src = argv[0];
switch (TYPE(src)) {
case T_STRING:
- return reg_new_1(self, RSTRING(src)->ptr, RSTRING(src)->len, ci);
+ return reg_new_1(self, RSTRING(src)->ptr, RSTRING(src)->len, flag);
break;
case T_REGEXP:
- return reg_new_1(self, RREGEXP(src)->str, RREGEXP(src)->len, ci);
+ return reg_new_1(self, RREGEXP(src)->str, RREGEXP(src)->len, flag);
break;
default:
@@ -535,6 +670,7 @@ reg_s_quote(re, str)
if (*s == '[' || *s == ']'
|| *s == '{' || *s == '}'
|| *s == '(' || *s == ')'
+ || *s == '|'
|| *s == '*' || *s == '.' || *s == '\\'
|| *s == '?' || *s == '+'
|| *s == '^' || *s == '$') {
@@ -550,8 +686,20 @@ static VALUE
reg_clone(re)
struct RRegexp *re;
{
- int ci = FL_TEST(re, REG_IGNORECASE);
- return reg_new_1(CLASS_OF(re), re->str, re->len, ci);
+ int flag = FL_TEST(re, REG_IGNORECASE);
+ if (FL_TEST(re, KCODE_FIXED)) {
+ switch (RBASIC(re)->flags & KCODE_MASK) {
+ case KCODE_NONE:
+ flag |= 2; break;
+ case KCODE_EUC:
+ flag |= 4; break;
+ case KCODE_SJIS:
+ flag |= 6; break;
+ default:
+ break;
+ }
+ }
+ return reg_new_1(CLASS_OF(re), re->str, re->len, flag);
}
VALUE
@@ -560,7 +708,8 @@ reg_regsub(str, src, regs)
struct RString *src;
struct re_registers *regs;
{
- VALUE val = Qnil;
+ VALUE val = 0;
+ VALUE tmp;
char *p, *s, *e, c;
int no;
@@ -571,39 +720,57 @@ reg_regsub(str, src, regs)
char *ss = s;
c = *s++;
- if (c == '&')
+ if (c != '\\') continue;
+
+ if (!val) val = str_new(p, ss-p);
+ else str_cat(val, p, ss-p);
+
+ c = *s++;
+ p = s;
+ switch (c) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ no = c - '0';
+ break;
+ case '&':
no = 0;
- else if (c == '\\' && '0' <= *s && *s <= '9')
- no = *s++ - '0';
- else
- no = -1;
+ break;
- if (no >= 0) {
- if (NIL_P(val)) {
- val = str_new(p, ss-p);
- }
- else {
- str_cat(val, p, ss-p);
- }
- p = s;
+ case '`':
+ str_cat(val, src->ptr, BEG(0));
+ continue;
+
+ case '\'':
+ str_cat(val, src->ptr+END(0), src->len-END(0));
+ continue;
+
+ case '+':
+ no = regs->num_regs-1;
+ while (BEG(no) == -1 && no > 0) no--;
+ if (no == 0) continue;
+ break;
+
+ case '\\':
+ str_cat(val, s-1, 1);
+ continue;
+
+ default:
+ str_cat(val, s-2, 2);
+ continue;
}
- if (no < 0) { /* Ordinary character. */
- if (c == '\\' && (*s == '\\' || *s == '&'))
- p = s++;
- } else {
+ if (no >= 0) {
if (BEG(no) == -1) continue;
str_cat(val, src->ptr+BEG(no), END(no)-BEG(no));
}
}
- if (NIL_P(val)) return (VALUE)str;
if (p < e) {
- str_cat(val, p, e-p);
- }
- if (RSTRING(val)->len == 0) {
- return (VALUE)str;
+ if (!val) val = str_new(p, e-p);
+ else str_cat(val, p, e-p);
}
+ if (!val) return (VALUE)str;
+
return val;
}
@@ -624,19 +791,18 @@ void
rb_set_kcode(code)
char *code;
{
+ re_syntax_options &= ~RE_MBCTYPE_MASK;
if (code == 0) goto set_no_conversion;
switch (code[0]) {
case 'E':
case 'e':
reg_kcode = KCODE_EUC;
- re_syntax_options &= ~RE_MBCTYPE_MASK;
re_syntax_options |= RE_MBCTYPE_EUC;
break;
case 'S':
case 's':
reg_kcode = KCODE_SJIS;
- re_syntax_options &= ~RE_MBCTYPE_MASK;
re_syntax_options |= RE_MBCTYPE_SJIS;
break;
default:
@@ -644,19 +810,17 @@ rb_set_kcode(code)
case 'n':
set_no_conversion:
reg_kcode = KCODE_NONE;
- re_syntax_options &= ~RE_MBCTYPE_MASK;
break;
}
re_set_syntax(re_syntax_options);
}
-static VALUE
+static void
kcode_setter(val)
struct RString *val;
{
Check_Type(val, T_STRING);
rb_set_kcode(val->ptr);
- return (VALUE)val;
}
static VALUE
@@ -667,12 +831,13 @@ match_getter()
static void
match_setter(val)
+ VALUE val;
{
Check_Type(val, T_MATCH);
backref_set(val);
}
-VALUE krn_to_s();
+VALUE any_to_s();
void
Init_Regexp()
@@ -684,6 +849,7 @@ Init_Regexp()
re_set_syntax(RE_NO_BK_PARENS | RE_NO_BK_VBAR
| RE_INTERVALS
| RE_NO_BK_BRACES
+ | RE_CONTEXTUAL_INVALID_OPS
| RE_BACKSLASH_ESCAPE_IN_LISTS
#ifdef DEFAULT_MBCTYPE
| DEFAULT_MBCTYPE
@@ -691,9 +857,14 @@ Init_Regexp()
);
rb_define_virtual_variable("$~", match_getter, match_setter);
+ rb_define_virtual_variable("$&", last_match_getter, 0);
+ rb_define_virtual_variable("$`", prematch_getter, 0);
+ rb_define_virtual_variable("$'", postmatch_getter, 0);
+ rb_define_virtual_variable("$+", last_paren_match_getter, 0);
- rb_define_variable("$=", &ignorecase, 0);
+ rb_define_variable("$=", &ignorecase);
rb_define_virtual_variable("$KCODE", kcode_getter, kcode_setter);
+ rb_define_virtual_variable("$-K", kcode_getter, kcode_setter);
cRegexp = rb_define_class("Regexp", cObject);
rb_define_singleton_method(cRegexp, "new", reg_s_new, -1);
@@ -711,5 +882,5 @@ Init_Regexp()
cMatch = rb_define_class("MatchingData", cData);
rb_define_method(cMatch, "to_a", match_to_a, 0);
rb_define_method(cMatch, "to_s", match_to_s, 0);
- rb_define_method(cMatch, "inspect", krn_to_s, 0);
+ rb_define_method(cMatch, "inspect", any_to_s, 0);
}
diff --git a/re.h b/re.h
index 17e0d9545c..59d52e1f1b 100644
--- a/re.h
+++ b/re.h
@@ -23,8 +23,7 @@ typedef struct re_pattern_buffer Regexp;
struct RMatch {
struct RBasic basic;
- UINT len;
- char *ptr;
+ VALUE str;
struct re_registers *regs;
};
diff --git a/regex.c b/regex.c
index c6bbb3027f..da7f2c6e8a 100644
--- a/regex.c
+++ b/regex.c
@@ -303,11 +303,24 @@ long re_syntax_options = DEFAULT_MBCTYPE;
/* Macros for re_compile_pattern, which is found below these definitions. */
-/* Fetch the next character in the uncompiled pattern. */
+/* Fetch the next character in the uncompiled pattern---translating it
+ if necessary. Also cast from a signed character in the constant
+ string passed to us by the user to an unsigned char that we can use
+ as an array index (in, e.g., `translate'). */
#define PATFETCH(c) \
- {if (p == pend) goto end_of_pattern; \
- c = *(unsigned char *) p++; }
+ do {if (p == pend) goto end_of_pattern; \
+ c = (unsigned char) *p++; \
+ if (translate) c = (unsigned char)translate[c]; \
+ } while (0)
+
+/* Fetch the next character in the uncompiled pattern, with no
+ translation. */
+#define PATFETCH_RAW(c) \
+ do {if (p == pend) goto end_of_pattern; \
+ c = (unsigned char) *p++; \
+ } while (0)
+/* Go backwards one character in the pattern. */
#define PATUNFETCH p--
@@ -467,7 +480,7 @@ set_list_bits(c1, c2, b)
memmove(&b[(beg + 1)*4], &b[end*4], (mbc_size - end)*4);
STORE_MBC(&b[beg*4 + 0], c1);
STORE_MBC(&b[beg*4 + 2], c2);
- mbc_size += beg + 1 - end;
+ mbc_size += beg - end + 1;
STORE_NUMBER(&b[-2], mbc_size);
}
@@ -477,32 +490,44 @@ is_in_list(c, b)
const unsigned char *b;
{
unsigned short size;
+ unsigned short i, j;
+ int result = 0;
size = *b++;
- if ((int)c < 1 << BYTEWIDTH) {
+ if ((int)c < 1<<BYTEWIDTH) {
if ((int)c / BYTEWIDTH < (int)size && b[c / BYTEWIDTH] & 1 << c % BYTEWIDTH) {
return 1;
}
}
- else {
- unsigned short i, j;
-
- b += size + 2;
- size = EXTRACT_UNSIGNED(&b[-2]);
-
- for (i = 0, j = size; i < j; ) {
- unsigned short k = (unsigned short)(i + j) >> 1;
-
- if (c > EXTRACT_MBC(&b[k*4 + 2]))
- i = k + 1;
- else
- j = k;
+ b += size + 2;
+ size = EXTRACT_UNSIGNED(&b[-2]);
+ if (size == 0) return 0;
+
+ if (b[(size-1)*4] == 0xff) {
+ i = c;
+ if ((int)c >= 1<<BYTEWIDTH) {
+ i = i>>BYTEWIDTH;
}
- if (i < size && EXTRACT_MBC(&b[i*4]) <= c
- && ((unsigned char)c != '\n' && (unsigned char)c != '\0'))
- return 1;
+ while (size>0 && b[size*4-2] == 0xff) {
+ size--;
+ if (b[size*4+1] <= i && i <= b[size*4+3]) {
+ result = 2;
+ break;
+ }
+ }
+ }
+ for (i = 0, j = size; i < j; ) {
+ unsigned short k = (unsigned short)(i + j) >> 1;
+
+ if (c > EXTRACT_MBC(&b[k*4+2]))
+ i = k + 1;
+ else
+ j = k;
}
- return 0;
+ if (i < size && EXTRACT_MBC(&b[i*4]) <= c
+ && ((unsigned char)c != '\n' && (unsigned char)c != '\0'))
+ return 1;
+ return result;
}
/* re_compile_pattern takes a regular-expression string
@@ -592,6 +617,9 @@ re_compile_pattern(pattern, size, bufp)
int regnum = 1;
int range = 0;
+ /* How to translate the characters in the pattern. */
+ char *translate = bufp->translate;
+
bufp->fastmap_accurate = 0;
/* Initialize the syntax table. */
@@ -644,8 +672,11 @@ re_compile_pattern(pattern, size, bufp)
/* $ means succeed if at end of line, but only in special contexts.
If validly in the middle of a pattern, it is a normal character. */
+#if 0
+ /* not needed for perl4 compatible */
if ((re_syntax_options & RE_CONTEXTUAL_INVALID_OPS) && p1 != pend)
goto invalid_pattern;
+#endif
if (p1 == pend || *p1 == '\n'
|| (re_syntax_options & RE_CONTEXT_INDEP_OPS)
|| (re_syntax_options & RE_NO_BK_PARENS
@@ -678,7 +709,9 @@ re_compile_pattern(pattern, size, bufp)
begalt = b;
}
else
- BUFPUSH(begline);
+ {
+ BUFPUSH(begline);
+ }
break;
case '+':
@@ -828,7 +861,7 @@ re_compile_pattern(pattern, size, bufp)
}
if (ismbchar(c)) {
PATFETCH(c1);
- c = c << 8 | c1;
+ c = c << BYTEWIDTH | c1;
}
/* \ escapes characters when inside [...]. */
@@ -843,11 +876,12 @@ re_compile_pattern(pattern, size, bufp)
continue;
case 'W':
- if (re_syntax_options & RE_MBCTYPE_MASK)
- goto invalid_char;
for (c = 0; c < (1 << BYTEWIDTH); c++)
if (SYNTAX(c) != Sword)
SET_LIST_BIT(c);
+ if (re_syntax_options & RE_MBCTYPE_MASK) {
+ set_list_bits(0x8000, 0xffff, (unsigned char*)b);
+ }
last = -1;
continue;
@@ -859,11 +893,12 @@ re_compile_pattern(pattern, size, bufp)
continue;
case 'S':
- if (re_syntax_options & RE_MBCTYPE_MASK)
- goto invalid_char;
for (c = 0; c < 256; c++)
if (!isspace(c))
SET_LIST_BIT(c);
+ if (re_syntax_options & RE_MBCTYPE_MASK) {
+ set_list_bits(0x8000, 0xffff, (unsigned char*)b);
+ }
last = -1;
continue;
@@ -874,19 +909,19 @@ re_compile_pattern(pattern, size, bufp)
continue;
case 'D':
- if (re_syntax_options & RE_MBCTYPE_MASK)
- goto invalid_char;
- for (c = 0; c < '0'; c++)
- SET_LIST_BIT(c);
- for (c = '9' + 1; c < 256; c++)
- SET_LIST_BIT(c);
+ for (c = 0; c < 256; c++)
+ if (!isdigit(c))
+ SET_LIST_BIT(c);
+ if (re_syntax_options & RE_MBCTYPE_MASK) {
+ set_list_bits(0x8000, 0xffff, (unsigned char*)b);
+ }
last = -1;
continue;
case 'x':
c = scan_hex(p, 2, &numlen);
- if ((re_syntax_options & RE_MBCTYPE_MASK) && (c > 0x7f))
- goto invalid_char;
+ if ((re_syntax_options & RE_MBCTYPE_MASK) && c > 0x7f)
+ c = 0xff00 | c;
p += numlen;
break;
@@ -894,8 +929,8 @@ re_compile_pattern(pattern, size, bufp)
case '5': case '6': case '7': case '8': case '9':
PATUNFETCH;
c = scan_oct(p, 3, &numlen);
- if ((re_syntax_options & RE_MBCTYPE_MASK) && (c > 0x7f))
- goto invalid_char;
+ if ((re_syntax_options & RE_MBCTYPE_MASK) && ismbchar(c))
+ c = 0xff00 | c;
p += numlen;
break;
@@ -922,8 +957,9 @@ re_compile_pattern(pattern, size, bufp)
for (;last<=c;last++)
SET_LIST_BIT(last);
}
- else
+ else {
set_list_bits(last, c, (unsigned char*)b);
+ }
}
else if (p[0] == '-' && p[1] != ']') {
last = c;
@@ -966,13 +1002,17 @@ re_compile_pattern(pattern, size, bufp)
goto handle_bar;
case '|':
+#if 0
+ /* not needed for perl4 compatible */
if ((re_syntax_options & RE_CONTEXTUAL_INVALID_OPS)
&& (! laststart || p == pend))
goto invalid_pattern;
- else if (! (re_syntax_options & RE_NO_BK_VBAR))
+ else
+ if (! (re_syntax_options & RE_NO_BK_VBAR))
goto normal_char;
else
- goto handle_bar;
+#endif
+ goto handle_bar;
case '{':
if (! ((re_syntax_options & RE_NO_BK_CURLY_BRACES)
@@ -983,7 +1023,10 @@ re_compile_pattern(pattern, size, bufp)
case '\\':
if (p == pend) goto invalid_pattern;
- PATFETCH(c);
+ /* Do not translate the character after the \, so that we can
+ distinguish, e.g., \B from \b, even if we normally would
+ translate, e.g., B to b. */
+ PATFETCH_RAW(c);
switch (c)
{
case '(':
@@ -994,6 +1037,7 @@ re_compile_pattern(pattern, size, bufp)
/* Laststart should point to the start_memory that we are about
to push (unless the pattern has RE_NREGS or more ('s). */
+ /* obsolete: now RE_NREGS is just a default register size. */
*stackp++ = b - bufp->buffer;
BUFPUSH(start_memory);
BUFPUSH(regnum);
@@ -1003,6 +1047,8 @@ re_compile_pattern(pattern, size, bufp)
fixup_jump = 0;
laststart = 0;
begalt = b;
+ /* too many ()'s to fit in a byte. */
+ if (regnum >= (1<<BYTEWIDTH)) goto too_big;
break;
case ')':
@@ -1077,6 +1123,8 @@ re_compile_pattern(pattern, size, bufp)
if (! (*laststart == anychar
|| *laststart == charset
|| *laststart == charset_not
+ || *laststart == wordchar
+ || *laststart == notwordchar
|| *laststart == start_memory
|| (*laststart == exactn
&& (laststart[1] == 1
@@ -1235,7 +1283,7 @@ re_compile_pattern(pattern, size, bufp)
b[-1]--;
if (b[-1] != (1 << BYTEWIDTH) / BYTEWIDTH)
memmove(&b[b[-1]], &b[(1 << BYTEWIDTH) / BYTEWIDTH],
- 2 + EXTRACT_UNSIGNED (&b[(1 << BYTEWIDTH) / BYTEWIDTH])*4);
+ 2 + EXTRACT_UNSIGNED(&b[(1 << BYTEWIDTH) / BYTEWIDTH])*4);
b += b[-1] + 2 + EXTRACT_UNSIGNED(&b[b[-1]])*4;
break;
@@ -1261,9 +1309,9 @@ re_compile_pattern(pattern, size, bufp)
case 'x':
c1 = 0;
c = scan_hex(p, 2, &numlen);
- if ((re_syntax_options & RE_MBCTYPE_MASK) && (c > 0x7f))
- goto invalid_char;
p += numlen;
+ if ((re_syntax_options & RE_MBCTYPE_MASK) && c > 0x7f)
+ c1 = 0xff;
goto numeric_char;
/* octal */
@@ -1271,6 +1319,8 @@ re_compile_pattern(pattern, size, bufp)
c1 = 0;
c = scan_oct(p, 3, &numlen);
p += numlen;
+ if ((re_syntax_options & RE_MBCTYPE_MASK) && c > 0x7f)
+ c1 = 0xff;
goto numeric_char;
/* back-ref or octal */
@@ -1285,19 +1335,16 @@ re_compile_pattern(pattern, size, bufp)
c1 = 0;
GET_UNSIGNED_NUMBER(c1);
- PATUNFETCH;
+ if (p < pend) PATUNFETCH;
if (c1 >= regnum) {
- if (c1 < RE_NREGS)
- goto invalid_pattern;
-
/* need to get octal */
p = p_save;
c = scan_oct(p_save, 3, &numlen);
- if ((re_syntax_options & RE_MBCTYPE_MASK) && (c > 0x7f))
- goto invalid_char;
p = p_save + numlen;
c1 = 0;
+ if ((re_syntax_options & RE_MBCTYPE_MASK) && c > 0x7f)
+ c1 = 0xff;
goto numeric_char;
}
}
@@ -1332,6 +1379,9 @@ re_compile_pattern(pattern, size, bufp)
c1 = c;
PATFETCH(c);
}
+ else if (c > 0x7f) {
+ c1 = 0xff;
+ }
numeric_char:
if (!pending_exact || pending_exact + *pending_exact + 1 != b
|| *pending_exact >= (c1 ? 0176 : 0177)
@@ -1541,7 +1591,13 @@ re_compile_fastmap(bufp)
#endif
{
case exactn:
- if (translate)
+ if (p[1] == 0xff) {
+ if (translate)
+ fastmap[translate[p[2]]] = 2;
+ else
+ fastmap[p[2]] = 2;
+ }
+ else if (translate)
fastmap[translate[p[1]]] = 1;
else
fastmap[p[1]] = 1;
@@ -1558,7 +1614,7 @@ re_compile_fastmap(bufp)
else
fastmap['\n'] = 1;
- if (bufp->can_be_null != 1)
+ if (bufp->can_be_null == 0)
bufp->can_be_null = 2;
break;
@@ -1583,7 +1639,7 @@ re_compile_fastmap(bufp)
continue;
p++;
EXTRACT_NUMBER_AND_INCR(j, p);
- p += j;
+ p += j;
if (stackp != stackb && *stackp == p)
stackp--;
continue;
@@ -1640,9 +1696,11 @@ re_compile_fastmap(bufp)
break;
case notwordchar:
- for (j = 0; j < (1 << BYTEWIDTH); j++)
+ for (j = 0; j < 0x80; j++)
if (SYNTAX(j) != Sword)
fastmap[j] = 1;
+ for (j = 0x80; j < (1 << BYTEWIDTH); j++)
+ fastmap[j] = 1;
break;
case charset:
@@ -1658,19 +1716,30 @@ re_compile_fastmap(bufp)
}
{
unsigned short size;
- unsigned char c, end;
+ unsigned c, end;
p += p[-1] + 2;
size = EXTRACT_UNSIGNED(&p[-2]);
- for (j = 0; j < (int)size; j++)
- /* set bits for 1st bytes of multi-byte chars. */
- for (c = (unsigned char)p[j*4],
- end = (unsigned char)p[j*4 + 2];
- c <= end; c++)
- /* NOTE: Charset for multi-byte chars might contain
- single-byte chars. We must reject them. */
- if (ismbchar(c))
- fastmap[c] = 1;
+ for (j = 0; j < (int)size; j++) {
+ if ((unsigned char)p[j*4] == 0xff) {
+ for (c = (unsigned char)p[j*4+1],
+ end = (unsigned char)p[j*4+3];
+ c <= end; c++) {
+ fastmap[c] = 2;
+ }
+ }
+ else {
+ /* set bits for 1st bytes of multi-byte chars. */
+ for (c = (unsigned char)p[j*4],
+ end = (unsigned char)p[j*4 + 2];
+ c <= end; c++) {
+ /* NOTE: Charset for multi-byte chars might contain
+ single-byte chars. We must reject them. */
+ if (ismbchar(c))
+ fastmap[c] = 1;
+ }
+ }
+ }
}
break;
@@ -1702,12 +1771,23 @@ re_compile_fastmap(bufp)
p += p[-1] + 2;
size = EXTRACT_UNSIGNED(&p[-2]);
- c = 0x80;
- for (j = 0; j < (int)size; j++) {
- for (beg = (unsigned char)p[j*4 + 0]; c < beg; c++)
- if (ismbchar(c))
- fastmap[c] = 1;
- c = (unsigned char)p[j*4 + 2] + 1;
+ if (size == 0) {
+ for (j = 0x80; j < (1 << BYTEWIDTH); j++)
+ if (ismbchar(j))
+ fastmap[j] = 1;
+ }
+ for (j = 0,c = 0x80;j < (int)size; j++) {
+ if ((unsigned char)p[j*4] == 0xff) {
+ for (beg = (unsigned char)p[j*4+1]; c < beg; c++)
+ fastmap[c] = 2;
+ c = (unsigned char)p[j*4+3] + 1;
+ }
+ else {
+ for (beg = (unsigned char)p[j*4 + 0]; c < beg; c++)
+ if (ismbchar(c))
+ fastmap[c] = 1;
+ c = (unsigned char)p[j*4 + 2] + 1;
+ }
}
}
break;
@@ -1720,7 +1800,7 @@ re_compile_fastmap(bufp)
characters of one path of the pattern. We need not follow this
path any farther. Instead, look at the next alternative
remembered in the stack. */
- if (stackp != stackb)
+ if (stackp != stackb)
p = *stackp--;
else
break;
@@ -1752,7 +1832,7 @@ re_search(bufp, string, size, startpos, range, regs)
{
register char *fastmap = bufp->fastmap;
register unsigned char *translate = (unsigned char *) bufp->translate;
- int val;
+ int val, anchor = 0;
/* Check for out-of-range starting position. */
if (startpos < 0 || startpos > size)
@@ -1763,15 +1843,19 @@ re_search(bufp, string, size, startpos, range, regs)
re_compile_fastmap (bufp);
}
- while (1)
- {
+ if (bufp->used > 0 && (enum regexpcode)bufp->buffer[0] == begline)
+ anchor = 1;
+
+ for (;;)
+ {
/* If a fastmap is supplied, skip quickly over characters that
cannot possibly be the start of a match. Note, however, that
if the pattern can possibly match the null string, we must
test it at each starting point so that we take the first null
string we get. */
- if (fastmap && startpos < size && bufp->can_be_null != 1)
+ if (fastmap && startpos < size
+ && bufp->can_be_null != 1 && !(anchor && startpos == 0))
{
if (range > 0) /* Searching forwards. */
{
@@ -1787,8 +1871,10 @@ re_search(bufp, string, size, startpos, range, regs)
if (ismbchar(c)) {
if (fastmap[c])
break;
- p++;
+ c = *p++;
range--;
+ if (fastmap[c] == 2)
+ break;
}
else
if (fastmap[translate ? translate[c] : c])
@@ -1797,7 +1883,7 @@ re_search(bufp, string, size, startpos, range, regs)
}
startpos += irange - range;
}
- else /* Searching backwards. */
+ else /* Searching backwards. */
{
register unsigned char c;
@@ -1808,10 +1894,14 @@ re_search(bufp, string, size, startpos, range, regs)
}
}
- if (range >= 0 && startpos == size && fastmap) {
- if (bufp->can_be_null == 0 || (bufp->can_be_null == 2 && size > 0))
- return -1;
- }
+ if (anchor && startpos > 0 && startpos < size
+ && string[startpos-1] != '\n') goto advance;
+
+ if (fastmap && startpos == size && range >= 0
+ && (bufp->can_be_null == 0 ||
+ (bufp->can_be_null == 2 && size > 0
+ && string[startpos-1] == '\n')))
+ return -1;
val = re_match(bufp, string, size, startpos, regs);
if (val >= 0)
@@ -2333,21 +2423,24 @@ re_match(bufp, string_arg, size, pos, regs)
case charset_not:
{
int not; /* Nonzero for charset_not. */
+ int half; /* 2 if need to match latter half of mbc */
int c;
PREFETCH;
c = (unsigned char)*d;
if (ismbchar(c)) {
- c <<= 8;
- if (d + 1 != dend)
+ if (d + 1 != dend) {
+ c <<= 8;
c |= (unsigned char)d[1];
+ }
}
else if (translate)
c = (unsigned char)translate[c];
- not = is_in_list(c, p);
- if (*(p - 1) == (unsigned char)charset_not)
+ half = not = is_in_list(c, p);
+ if (*(p - 1) == (unsigned char)charset_not) {
not = !not;
+ }
p += 1 + *p + 2 + EXTRACT_UNSIGNED(&p[1 + *p])*4;
@@ -2355,7 +2448,7 @@ re_match(bufp, string_arg, size, pos, regs)
SET_REGS_MATCHED;
d++;
- if (d != dend && c >= 1 << BYTEWIDTH)
+ if (half != 2 && d != dend && c >= 1 << BYTEWIDTH)
d++;
break;
}
@@ -2547,6 +2640,8 @@ re_match(bufp, string_arg, size, pos, regs)
PREFETCH;
if (IS_A_LETTER(d))
goto fail;
+ if (ismbchar(*d) && d + 1 != dend)
+ d++;
d++;
SET_REGS_MATCHED;
break;
@@ -2565,11 +2660,18 @@ re_match(bufp, string_arg, size, pos, regs)
PREFETCH;
c = *d++;
- if (ismbchar(c)) {
+ if (*p == 0xff) {
+ p++;
+ if (!--mcnt
+ || d == dend
+ || (unsigned char)*d++ != (unsigned char)*p++)
+ goto fail;
+ continue;
+ }
+ else if (ismbchar(c)) {
if (c != (unsigned char)*p++
- || !--mcnt /* ѥѥ뤵
- Ƥ¤, Υå
- ĹǰΤ. */
+ || !--mcnt /* redundant check if pattern was
+ compiled properly. */
|| d == dend
|| (unsigned char)*d++ != (unsigned char)*p++)
goto fail;
@@ -2587,6 +2689,7 @@ re_match(bufp, string_arg, size, pos, regs)
do
{
PREFETCH;
+ if (*p == 0xff) {p++; mcnt--;}
if (*d++ != *p++) goto fail;
}
while (--mcnt);
diff --git a/regex.h b/regex.h
index 7b31b87b62..32b4cf10d4 100644
--- a/regex.h
+++ b/regex.h
@@ -248,6 +248,10 @@ struct re_registers
+#ifdef NeXT
+#define re_match rre_match
+#endif
+
#ifdef __STDC__
extern char *re_compile_pattern (char *, size_t, struct re_pattern_buffer *);
diff --git a/ruby.c b/ruby.c
index b61b72eb9a..33522f8b4d 100644
--- a/ruby.c
+++ b/ruby.c
@@ -14,6 +14,7 @@
#include "re.h"
#include "dln.h"
#include <stdio.h>
+#include <ctype.h>
#include <sys/types.h>
#include <fcntl.h>
@@ -25,15 +26,19 @@ char *strrchr();
char *strstr();
#endif
+char *getenv();
+
static int version, copyright;
int debug = FALSE;
int verbose = FALSE;
+int tainting = FALSE;
static int sflag = FALSE;
char *inplace = FALSE;
char *strdup();
+extern char *sourcefile;
extern int yydebug;
extern int nerrs;
@@ -41,7 +46,8 @@ static int xflag = FALSE;
extern VALUE RS, RS_default, ORS, FS;
static void load_stdin();
-static void load_file();
+static void load_file _((char *, int));
+static void forbid_setid _((char *));
static int do_loop = FALSE, do_print = FALSE;
static int do_check = FALSE, do_line = FALSE;
@@ -50,14 +56,10 @@ static int do_split = FALSE;
static char *script;
#ifndef RUBY_LIB
-#if defined(MSDOS)
-#define RUBY_LIB "/usr/local/lib/ruby;."
-#else
-#define RUBY_LIB "/usr/local/lib/ruby:."
-#endif
+#define RUBY_LIB "/usr/local/lib/ruby"
#endif
-#if defined(MSDOS)
+#if defined(MSDOS) || defined(NT)
#define RUBY_LIB_SEP ';'
#else
#define RUBY_LIB_SEP ':'
@@ -70,25 +72,64 @@ static void
addpath(path)
char *path;
{
- char *p, *s;
- VALUE ary;
-
if (path == 0) return;
-
- ary = ary_new();
- p = s = path;
- while (*p) {
- while (*p == RUBY_LIB_SEP) p++;
- if (s = strrchr(p, RUBY_LIB_SEP)) {
- ary_push(ary, str_new(p, (int)(s-p)));
- p = s + 1;
- }
- else {
- ary_push(ary, str_new2(p));
- break;
+ if (strchr(path, RUBY_LIB_SEP)) {
+ char *p, *s;
+ VALUE ary = ary_new();
+
+ p = path;
+ while (*p) {
+ while (*p == RUBY_LIB_SEP) p++;
+ if (s = strchr(p, RUBY_LIB_SEP)) {
+ ary_push(ary, str_new(p, (int)(s-p)));
+ p = s + 1;
+ }
+ else {
+ ary_push(ary, str_new2(p));
+ break;
+ }
}
+ rb_load_path = ary_plus(ary, rb_load_path);
+ }
+ else {
+ ary_unshift(rb_load_path, str_new2(path));
}
- rb_load_path = ary_plus(ary, rb_load_path);
+}
+
+struct req_list {
+ char *name;
+ struct req_list *next;
+} *req_list;
+
+static void
+add_modules(mod)
+ char *mod;
+{
+ struct req_list *list;
+
+ list = ALLOC(struct req_list);
+ list->name = mod;
+ list->next = req_list;
+ req_list = list;
+}
+
+void
+rb_require_modules()
+{
+ struct req_list *list = req_list;
+ struct req_list *tmp;
+ extern void *eval_tree; /* hack to save syntax tree */
+ void *save;
+
+ req_list = 0;
+ save = eval_tree;
+ while (list) {
+ f_require(Qnil, str_new2(list->name));
+ tmp = list->next;
+ free(list);
+ list = tmp;
+ }
+ eval_tree = save;
}
static void
@@ -150,6 +191,7 @@ proc_options(argcp, argvp)
goto reswitch;
case 's':
+ forbid_setid("-s");
sflag = TRUE;
s++;
goto reswitch;
@@ -161,11 +203,13 @@ proc_options(argcp, argvp)
goto reswitch;
case 'S':
+ forbid_setid("-S");
do_search = TRUE;
s++;
goto reswitch;
case 'e':
+ forbid_setid("-e");
script_given++;
if (script == 0) script = "-e";
if (argv[1]) {
@@ -178,16 +222,19 @@ proc_options(argcp, argvp)
break;
case 'r':
+ forbid_setid("-r");
if (*++s) {
- f_require(Qnil, str_new2(s));
+ add_modules(s);
}
else if (argv[1]) {
- f_require(Qnil, str_new2(argv[1]));
+ add_modules(argv[1]);
argc--,argv++;
}
break;
case 'i':
+ forbid_setid("-i");
+ if (inplace) free(inplace);
inplace = strdup(s+1);
break;
@@ -220,7 +267,22 @@ proc_options(argcp, argvp)
s++;
goto reswitch;
+ case 'T':
+ {
+ int numlen;
+ int v = 1;
+
+ if (*++s) {
+ v = scan_oct(s, 2, &numlen);
+ if (numlen == 0) v = 1;
+ }
+ rb_set_safe_level(v);
+ tainting = TRUE;
+ }
+ break;
+
case 'I':
+ forbid_setid("-I");
if (*++s)
addpath(s);
else if (argv[1]) {
@@ -302,7 +364,14 @@ proc_options(argcp, argvp)
}
else {
if (do_search) {
- script = dln_find_file(script, getenv("PATH"));
+ char *path = getenv("RUBYPATH");
+
+ if (path) {
+ script = dln_find_file(script, path);
+ }
+ if (!script) {
+ script = dln_find_file(script, getenv("PATH"));
+ }
if (!script) script = argv[0];
}
load_file(script, 1);
@@ -339,12 +408,6 @@ proc_options(argcp, argvp)
}
-static VALUE
-open_to_load(fname)
- char *fname;
-{
-}
-
static void
load_file(fname, script)
char *fname;
@@ -368,6 +431,7 @@ load_file(fname, script)
RS = RS_default;
if (xflag) {
+ forbid_setid("-x");
xflag = FALSE;
while (!NIL_P(line = io_gets(f))) {
line_start++;
@@ -397,7 +461,7 @@ load_file(fname, script)
start_read:
if (p = strstr(RSTRING(line)->ptr, "ruby -")) {
int argc; char *argv[2]; char **argvp = argv;
- char *s;
+ UCHAR *s;
s = RSTRING(line)->ptr;
while (isspace(*s++))
@@ -430,6 +494,7 @@ rb_load_file(fname)
static void
load_stdin()
{
+ forbid_setid("program input from stdin");
load_file("-", 1);
}
@@ -437,9 +502,9 @@ VALUE Progname;
VALUE Argv;
static int origargc;
-static char **origargv, **origenvp;
+static char **origargv;
-static VALUE
+static void
set_arg0(val, id)
VALUE val;
ID id;
@@ -448,6 +513,7 @@ set_arg0(val, id)
int i;
static int len;
+ if (origargv == 0) Fail("$0 not initialized");
Check_Type(val, T_STRING);
if (len == 0) {
s = origargv[0];
@@ -472,9 +538,7 @@ set_arg0(val, id)
while (++i < len)
*s++ = ' ';
}
- Progname = str_new2(origargv[0]);
-
- return val;
+ Progname = str_taint(str_new2(origargv[0]));
}
void
@@ -482,41 +546,112 @@ ruby_script(name)
char *name;
{
if (name) {
- Progname = str_new2(name);
+ Progname = str_taint(str_new2(name));
+ sourcefile = name;
}
}
-void
-ruby_options(argc, argv, envp)
- int argc;
- char **argv, **envp;
+static int uid, euid, gid, egid;
+
+static void
+init_ids()
{
- extern VALUE errat;
- int i;
+ uid = (int)getuid();
+ euid = (int)geteuid();
+ gid = (int)getgid();
+ egid = (int)getegid();
+#ifdef VMS
+ uid |= gid << 16;
+ euid |= egid << 16;
+#endif
+ if (uid && (euid != uid || egid != gid)) {
+ rb_set_safe_level(1);
+ }
+}
- origargc = argc; origargv = argv; origenvp = envp;
+static void
+forbid_setid(s)
+ char *s;
+{
+ if (euid != uid)
+ Fatal("No %s allowed while running setuid", s);
+ if (egid != gid)
+ Fatal("No %s allowed while running setgid", s);
+}
- errat = str_new2(argv[0]);
+void
+ruby_prog_init()
+{
+ init_ids();
+
+ sourcefile = "ruby";
rb_define_variable("$VERBOSE", &verbose);
+ rb_define_variable("$-v", &verbose);
rb_define_variable("$DEBUG", &debug);
+ rb_define_variable("$-d", &debug);
+ rb_define_readonly_variable("$-p", &do_print);
+ rb_define_readonly_variable("$-l", &do_line);
- addpath(getenv("RUBYLIB"));
- addpath(RUBY_LIB);
+ if (rb_safe_level() == 0) {
+ addpath(getenv("RUBYLIB"));
+ }
#ifdef RUBY_ARCHLIB
addpath(RUBY_ARCHLIB);
#endif
-#if defined(USE_DLN_A_OUT)
- dln_argv0 = argv[0];
-#endif
+ addpath(RUBY_LIB);
+ if (rb_safe_level() == 0) {
+ addpath(".");
+ }
rb_define_hooked_variable("$0", &Progname, 0, set_arg0);
- Argv = ary_new2(argc);
+ Argv = ary_new();
rb_define_readonly_variable("$*", &Argv);
rb_define_global_const("ARGV", Argv);
+ rb_define_readonly_variable("$-a", &do_split);
+
+#ifdef MSDOS
+ /*
+ * There is no way we can refer to them from ruby, so close them to save
+ * space.
+ */
+ (void)fclose(stdaux);
+ (void)fclose(stdprn);
+#endif
+}
+void
+ruby_set_argv(argc, argv)
+ int argc;
+ char **argv;
+{
+ int i;
+
+#if defined(USE_DLN_A_OUT)
+ if (origargv) dln_argv0 = origargv[0];
+ else dln_argv0 = argv[0];
+#endif
+ for (i=0; i < argc; i++) {
+ ary_push(Argv, str_taint(str_new2(argv[i])));
+ }
+}
+
+void
+ruby_process_options(argc, argv)
+ int argc;
+ char **argv;
+{
+ extern VALUE errat;
+ int i;
+
+ origargc = argc; origargv = argv;
+ ruby_script(argv[0]); /* for the time being */
+#if defined(USE_DLN_A_OUT)
+ dln_argv0 = argv[0];
+#endif
proc_options(&argc, &argv);
ruby_script(script);
+ ruby_set_argv(argc, argv);
if (do_check && nerrs == 0) {
printf("Syntax OK\n");
@@ -528,8 +663,4 @@ ruby_options(argc, argv, envp)
if (do_loop) {
yywhile_loop(do_line, do_split);
}
-
- for (i=0; i < argc; i++) {
- ary_push(Argv, str_new2(argv[i]));
- }
}
diff --git a/ruby.h b/ruby.h
index f9d0c6833b..9ac9d32f81 100644
--- a/ruby.h
+++ b/ruby.h
@@ -13,12 +13,14 @@
#ifndef RUBY_H
#define RUBY_H
-#ifndef NT
-# include "config.h"
-#endif
+#include "config.h"
#include "defines.h"
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
#ifndef __STDC__
# define volatile
# ifdef __GNUC__
@@ -26,7 +28,7 @@
# else
# define const
# endif
-# define _(args)
+# define _(args) ()
#else
# define _(args) args
#endif
@@ -44,6 +46,7 @@ typedef UINT VALUE;
typedef UINT ID;
typedef unsigned short USHORT;
+typedef unsigned char UCHAR;
#ifdef __STDC__
# include <limits.h>
@@ -72,7 +75,7 @@ typedef unsigned short USHORT;
#define FIXNUM_FLAG 0x01
#define INT2FIX(i) (VALUE)(((int)(i))<<1 | FIXNUM_FLAG)
-VALUE int2inum();
+VALUE int2inum _((int));
#define INT2NUM(v) int2inum(v)
#if (-1==(((-1)<<1)&FIXNUM_FLAG)>>1)
@@ -89,19 +92,20 @@ VALUE int2inum();
#define FIXABLE(f) (POSFIXABLE(f) && NEGFIXABLE(f))
/* special contants - i.e. non-zero and non-fixnum constants */
+#undef FALSE
#define FALSE 0
#undef TRUE
#define TRUE 2
#define Qnil 4
-int rb_test_false_or_nil();
-# define RTEST(v) rb_test_false_or_nil(v)
+int rb_test_false_or_nil _((VALUE));
+# define RTEST(v) rb_test_false_or_nil((VALUE)(v))
#define NIL_P(v) ((VALUE)(v) == Qnil)
extern VALUE cObject;
-VALUE rb_class_of();
-#define CLASS_OF(v) rb_class_of(v)
+VALUE rb_class_of _((VALUE));
+#define CLASS_OF(v) rb_class_of((VALUE)(v))
#define T_NIL 0x00
#define T_OBJECT 0x01
@@ -131,16 +135,20 @@ VALUE rb_class_of();
#define BUILTIN_TYPE(x) (((struct RBasic*)(x))->flags & T_MASK)
-int rb_type();
-#define TYPE(x) rb_type(x)
+int rb_type _((VALUE));
+#define TYPE(x) rb_type((VALUE)(x))
+
+void rb_check_type _((VALUE,int));
+#define Check_Type(v,t) rb_check_type((VALUE)(v),t)
+void rb_check_safe_str _((VALUE));
+#define Check_SafeStr(v) rb_check_safe_str((VALUE)(v))
+void rb_secure _((int));
-void Check_Type();
-#define Need_Fixnum(x) {if (!FIXNUM_P(x)) (x) = num2fix(x);}
#define NUM2INT(x) (FIXNUM_P(x)?FIX2INT(x):num2int(x))
-VALUE num2fix();
-int num2int();
+VALUE num2fix _((VALUE));
+int num2int _((VALUE));
-#define NEWOBJ(obj,type) type *obj = (type*)newobj()
+#define NEWOBJ(obj,type) type *obj = (type*)rb_newobj()
#define OBJSETUP(obj,c,t) {\
RBASIC(obj)->class = (c);\
RBASIC(obj)->flags = (t);\
@@ -173,7 +181,7 @@ struct RFloat {
struct RString {
struct RBasic basic;
UINT len;
- char *ptr;
+ UCHAR *ptr;
struct RString *orig;
};
@@ -187,12 +195,14 @@ struct RRegexp {
struct RBasic basic;
struct re_pattern_buffer *ptr;
UINT len;
- char *str;
+ UCHAR *str;
};
struct RHash {
struct RBasic basic;
struct st_table *tbl;
+ int iter_lev;
+ UINT status;
};
struct RFile {
@@ -209,14 +219,18 @@ struct RData {
#define DATA_PTR(dta) (RDATA(dta)->data)
-VALUE data_object_alloc();
-#define Make_Data_Struct(class,type,mark,free,sval) (\
+VALUE data_object_alloc _((VALUE,void*,void (*)(),void (*)()));
+#define Data_Make_Struct(class,type,mark,free,sval) (\
sval = ALLOC(type),\
memset(sval, 0, sizeof(type)),\
data_object_alloc(class,sval,mark,free)\
)
-#define Get_Data_Struct(obj,type,sval) {\
+#define Data_Wrap_Struct(class,mark,free,sval) (\
+ data_object_alloc(class,sval,mark,free)\
+)
+
+#define Data_Get_Struct(obj,type,sval) {\
Check_Type(obj, T_DATA); \
sval = (type*)DATA_PTR(obj);\
}
@@ -250,19 +264,22 @@ struct RBignum {
#define FL_SINGLETON (1<<8)
#define FL_MARK (1<<9)
+#define FL_FINALIZE (1<<10)
+
+#define FL_USHIFT 11
-#define FL_USER0 (1<<10)
-#define FL_USER1 (1<<11)
-#define FL_USER2 (1<<12)
-#define FL_USER3 (1<<13)
-#define FL_USER4 (1<<14)
-#define FL_USER5 (1<<15)
-#define FL_USER6 (1<<16)
+#define FL_USER0 (1<<(FL_USHIFT+0))
+#define FL_USER1 (1<<(FL_USHIFT+1))
+#define FL_USER2 (1<<(FL_USHIFT+2))
+#define FL_USER3 (1<<(FL_USHIFT+3))
+#define FL_USER4 (1<<(FL_USHIFT+4))
+#define FL_USER5 (1<<(FL_USHIFT+5))
+#define FL_USER6 (1<<(FL_USHIFT+6))
-#define FL_UMASK (0x7f<<10)
+#define FL_UMASK (0x7f<<FL_USHIFT)
-int rb_special_const_p();
-#define FL_ABLE(x) (!(FIXNUM_P(x)||rb_special_const_p(x)))
+int rb_special_const_p _((VALUE));
+#define FL_ABLE(x) (!(FIXNUM_P(x)||rb_special_const_p((VALUE)(x))))
#define FL_TEST(x,f) (FL_ABLE(x)?(RBASIC(x)->flags&(f)):0)
#define FL_SET(x,f) if (FL_ABLE(x)) {RBASIC(x)->flags |= (f);}
#define FL_UNSET(x,f) if(FL_ABLE(x)){RBASIC(x)->flags &= ~(f);}
@@ -278,51 +295,53 @@ int rb_special_const_p();
#define MEMCPY(p1,p2,type,n) memcpy((p1), (p2), sizeof(type)*(n))
#define MEMMOVE(p1,p2,type,n) memmove((p1), (p2), sizeof(type)*(n))
-void *xmalloc();
-void *xcalloc();
-void *xrealloc();
+void *xmalloc _((unsigned long));
+void *xcalloc _((unsigned long,unsigned long));
+void *xrealloc _((void*,unsigned long));
-VALUE rb_define_class();
-VALUE rb_define_module();
-void rb_include_module();
-void rb_extend_object();
+VALUE rb_define_class _((char*,VALUE));
+VALUE rb_define_module _((char*));
+void rb_include_module _((VALUE,VALUE));
+void rb_extend_object _((VALUE,VALUE));
-void rb_define_variable();
-void rb_define_const();
-void rb_define_global_const();
+void rb_define_variable _((char*,VALUE*));
+void rb_define_virtual_variable _((char*,VALUE(*)(),void(*)()));
+void rb_define_hooked_variable _((char*,VALUE*,VALUE(*)(),void(*)()));
+void rb_define_const _((VALUE,char*,VALUE));
+void rb_define_global_const _((char*,VALUE));
-void rb_define_method();
-void rb_define_singleton_method();
-void rb_undef_method();
-void rb_define_alias();
-void rb_define_attr();
+void rb_define_method _((VALUE,char*,VALUE(*)(),int));
+void rb_define_singleton_method _((VALUE,char*,VALUE(*)(),int));
+void rb_undef_method _((VALUE,char*));
+void rb_define_alias _((VALUE,char*,char*));
+void rb_define_attr _((VALUE,ID,int));
-ID rb_intern();
-char *rb_id2name();
-ID rb_to_id();
+ID rb_intern _((char*));
+char *rb_id2name _((ID));
+ID rb_to_id _((VALUE));
-char *rb_class2name();
-int rb_method_boundp();
+char *rb_class2name _((VALUE));
+int rb_method_boundp _((VALUE,ID,int));
-VALUE rb_eval_string();
+VALUE rb_eval_string _((char*));
VALUE rb_funcall();
-VALUE rb_funcall2();
int rb_scan_args();
-VALUE rb_ivar_get();
-VALUE rb_ivar_set();
-
VALUE rb_iv_get();
VALUE rb_iv_set();
void rb_const_set();
+VALUE rb_const_get();
VALUE rb_yield();
int iterator_p();
-int rb_equal();
+VALUE rb_equal _((VALUE,VALUE));
extern int verbose, debug;
+int rb_safe_level();
+void rb_set_safe_level _((int));
+
#ifdef __GNUC__
typedef void voidfn ();
volatile voidfn Raise;
diff --git a/sample/biorhythm.rb b/sample/biorhythm.rb
index 5a452e0078..b97ee85e16 100644
--- a/sample/biorhythm.rb
+++ b/sample/biorhythm.rb
@@ -1,74 +1,45 @@
-#!/mp/free/bin/ruby
+#!/usr/local/bin/ruby
#
-# biorhythm.rb -
-# $Release Version: $
-# $Revision: 1.6 $
-# $Date: 1994/02/24 10:23:34 $
-# by Yasuo OHBA(STAFS Development Room)
+# biorhythm.rb -
+# $Release Version: $
+# $Revision: 1.3 $
+# $Date: 1997/02/14 11:07:08 $
+# by Yasuo OHBA(STAFS Development Room)
#
# --
#
-#
+#
#
-$RCS_ID="$Header: /var/ohba/RCS/biorhythm.rb,v 1.6 1994/02/24 10:23:34 ohba Exp ohba $"
-
include Math
-load("parsearg.rb")
-
-$wochentag = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ]
-monatstag1 = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
-monatstag2 = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
+require "date.rb"
+require "parsearg.rb"
def usage()
- print("Usage:\n")
- print("biorhythm.rb [options]\n")
- print(" options...\n")
- print(" -D YYYYMMDD(birthday) : ٤ default ͤȤ. \n")
- print(" --sdate | --date YYYYMMDD : system date ⤷ϻꤷդȤ.\n")
- print(" --birthday YYYYMMDD : λ򤹤. \n")
- print(" -v | -g : Values or Graph λ. \n")
- print(" --days DAYS : ֤λ򤹤(Graph λΤͭ). \n")
- print(" --help : help\n")
+ print "Usage:\n"
+ print "biorhythm.rb [options]\n"
+ print " options...\n"
+ print " -D YYYYMMDD(birthday) : ٤ default ͤȤ. \n"
+ print " --sdate | --date YYYYMMDD : system date ⤷ϻꤷդȤ.\n"
+ print " --birthday YYYYMMDD : λ򤹤. \n"
+ print " -v | -g : Values or Graph λ. \n"
+ print " --days DAYS : ֤λ򤹤(Graph λΤͭ). \n"
+ print " --help : help\n"
end
$USAGE = 'usage'
-def leapyear(y)
- ta = 0
- if ((y % 4.0) == 0); ta = 1; end
- if ((y % 100.0) == 0); ta = 0; end
- if ((y % 400.0) == 0); ta = 1; end
- return ta
-end
-
-def bcalc(tt, m, j)
- ta = 0
- if (m <= 2)
- ta = (m - 1) * 31
- else
- ta = leapyear(j)
- ta = ta + ((306 * m - 324) / 10.0).to_i
- end
- ta = ta + (j - 1) * 365 + ((j - 1) / 4.0).to_i
- ta = ta - ((j - 1) / 100) + ((j - 1) / 400.0).to_i
- ta = ta + tt
- return ta
-end
-
-def printHeader(tg, mg, jg, gtag, tage)
- print("\n")
- print(" Biorhythm\n")
- print(" =========\n")
- print("\n")
- printf("The birthday %04d.%02d.%02d is a %s\n", jg, mg, tg, $wochentag[gtag])
- printf("Age in days: [%d]\n", tage)
+def printHeader(y, m, d, p, w)
+ print "\n>>> Biorhythm <<<\n"
+ printf "The birthday %04d.%02d.%02d is a %s\n", y, m, d, w
+ printf "Age in days: [%d]\n\n", p
end
def getPosition(z)
pi = 3.14159265
- $phys = (50.0 * (1.0 + sin((z / 23.0 - (z / 23)) * 360.0 * pi / 180.0))).to_i
- $emot = (50.0 * (1.0 + sin((z / 28.0 - (z / 28)) * 360.0 * pi / 180.0))).to_i
- $geist =(50.0 * (1.0 + sin((z / 33.0 - (z / 33)) * 360.0 * pi / 180.0))).to_i
+ phys = (50.0 * (1.0 + sin((z / 23.0 - (z / 23)) * 360.0 * pi / 180.0))).to_i
+ emot = (50.0 * (1.0 + sin((z / 28.0 - (z / 28)) * 360.0 * pi / 180.0))).to_i
+ geist =(50.0 * (1.0 + sin((z / 33.0 - (z / 33)) * 360.0 * pi / 180.0))).to_i
+ return phys, emot, geist
end
#
@@ -76,55 +47,41 @@ end
#
parseArgs(0, nil, "vg", "D:", "sdate", "date:", "birthday:", "days:")
-printf(STDERR, "\n")
-printf(STDERR, "Biorhythm (c) 1987-1994 V3.0\n")
-printf(STDERR, "\n")
-if ($OPT_D)
- dtmp = Time.now.strftime("%Y%m%d")
- jh = dtmp[0,4].to_i
- mh = dtmp[4,2].to_i
- th = dtmp[6,2].to_i
- dtmp = $OPT_D
- jg = dtmp[0,4].to_i
- mg = dtmp[4,2].to_i
- tg = dtmp[6,2].to_i
- gtag = bcalc(tg, mg, jg) % 7
+if $OPT_D
+ dd = Date.new(Time.now.strftime("%Y%m%d"))
+ bd = Date.new($OPT_D)
ausgabeart = "g"
else
- if ($OPT_birthday)
- dtmp = $OPT_birthday
+ if $OPT_birthday
+ bd = Date.new($OPT_birthday)
else
- printf(STDERR, "Birthday (YYYYMMDD) : ")
- dtmp = STDIN.gets.chop
+ printf(STDERR, "Birthday (YYYYMMDD) : ")
+ if (si = STDIN.gets.chop) != ""
+ bd = Date.new(si)
+ end
end
- if (dtmp.length != 8)
- printf(STDERR, "BAD Input Birthday!!\n")
+ if !bd
+ printf STDERR, "BAD Input Birthday!!\n"
exit()
end
- jg = dtmp[0,4].to_i
- mg = dtmp[4,2].to_i
- tg = dtmp[6,2].to_i
- gtag = bcalc(tg, mg, jg) % 7
-
- if ($OPT_sdate)
- dtmp = Time.now.strftime("%Y%m%d")
- elsif ($OPT_date)
- dtmp = $OPT_date
+ if $OPT_sdate
+ dd = Date.new(Time.now.strftime("%Y%m%d"))
+ elsif $OPT_date
+ dd = Date.new($OPT_date)
else
- printf(STDERR, "Date [<RETURN> for Systemdate] (YYYYMMDD) : ")
- dtmp = STDIN.gets.chop
+ printf(STDERR, "Date [<RETURN> for Systemdate] (YYYYMMDD) : ")
+ if (si = STDIN.gets.chop) != ""
+ dd = Date.new(si)
+ end
end
- if (dtmp.length != 8)
- dtmp = Time.now.strftime("%Y%m%d")
+ if !dd
+ dd = Date.new(Time.now.strftime("%Y%m%d"))
end
- jh = dtmp[0,4].to_i
- mh = dtmp[4,2].to_i
- th = dtmp[6,2].to_i
-
- if ($OPT_v)
+
+ if $OPT_v
ausgabeart = "v"
- elsif ($OPT_g)
+ elsif $OPT_g
ausgabeart = "g"
else
printf(STDERR, "Values for today or Graph (v/g) [default g] : ")
@@ -132,70 +89,50 @@ else
end
end
if (ausgabeart == "v")
- tag = bcalc(tg, mg, jg)
- tah = bcalc(th, mh, jh)
- tage = tah - tag
- printHeader(tg, mg, jg, gtag, tage)
- print("\n")
+ printHeader(bd.year, bd.month, bd.day, dd.period - bd.period, bd.name_of_week)
+ print "\n"
- getPosition(tage)
- printf("Biorhythm: %04d.%02d.%02d\n", jh, mh, th)
- printf("Physical: %d%%\n", $phys)
- printf("Emotional: %d%%\n", $emot)
- printf("Mental: %d%%\n", $geist)
- print("\n")
+ phys, emot, geist = getPosition(dd.period - bd.period)
+ printf "Biorhythm: %04d.%02d.%02d\n", dd.year, dd.month, dd.day
+ printf "Physical: %d%%\n", phys
+ printf "Emotional: %d%%\n", emot
+ printf "Mental: %d%%\n", geist
+ print "\n"
else
- if ($OPT_days)
- ktage = $OPT_days.to_i
+ if $OPT_days
+ display_period = $OPT_days.to_i
+ elsif $OPT_D
+ display_period = 9
else
- if ($OPT_D)
- ktage = 9
+ printf(STDERR, "Graph for how many days [default 10] : ")
+ display_period = STDIN.gets.chop
+ if (display_period == "")
+ display_period = 9
else
- printf(STDERR, "Graph for how many days [default 10] : ")
- ktage = STDIN.gets.chop
- if (ktage == "")
- ktage = 9
- else
- ktage = ktage.to_i - 1
- end
+ display_period = display_period.to_i - 1
end
end
- tag = bcalc(tg, mg, jg)
- tah = bcalc(th, mh, jh)
- tage = tah - tag
- printHeader(tg, mg, jg, gtag, tage)
- print(" P=physical, E=emotional, M=mental\n")
- print(" -------------------------+-------------------------\n")
- print(" Bad Condition | Good Condition\n")
- print(" -------------------------+-------------------------\n")
+
+ printHeader(bd.year, bd.month, bd.day, dd.period - bd.period, bd.name_of_week)
+ print " P=physical, E=emotional, M=mental\n"
+ print " -------------------------+-------------------------\n"
+ print " Bad Condition | Good Condition\n"
+ print " -------------------------+-------------------------\n"
- for z in tage..(tage + ktage)
- getPosition(z)
+ for z in (dd.period - bd.period)..(dd.period - bd.period + display_period)
+ phys, emot, geist = getPosition(z)
- printf("%04d.%02d.%02d : ", jh, mh, th)
- p = ($phys / 2.0 + 0.5).to_i
- e = ($emot / 2.0 + 0.5).to_i
- g = ($geist / 2.0 + 0.5).to_i
+ printf "%04d.%02d.%02d : ", dd.year, dd.month, dd.day
+ p = (phys / 2.0 + 0.5).to_i
+ e = (emot / 2.0 + 0.5).to_i
+ g = (geist / 2.0 + 0.5).to_i
graph = "." * 51
graph[25] = ?|
graph[p] = ?P
graph[e] = ?E
graph[g] = ?M
- print(graph, "\n")
- th = th + 1
- if (leapyear(jh) == 0)
- $MONATSTAG = monatstag1
- else
- $MONATSTAG = monatstag2
- end
- if (th > $MONATSTAG[mh - 1])
- mh = mh + 1
- th = 1
- end
- if (mh > 12)
- jh = jh + 1
- mh = 1
- end
+ print graph, "\n"
+ dd = dd + 1
end
- print(" -------------------------+-------------------------\n\n")
+ print " -------------------------+-------------------------\n\n"
end
diff --git a/sample/dbm.rb b/sample/dbmtest.rb
index c77cc2065b..c77cc2065b 100644
--- a/sample/dbm.rb
+++ b/sample/dbmtest.rb
diff --git a/sample/dir.rb b/sample/dir.rb
index 1fc0bb2aa8..2465c4d68e 100644
--- a/sample/dir.rb
+++ b/sample/dir.rb
@@ -3,7 +3,7 @@
dirp = Dir.open(".")
for f in dirp
$_ = f
- if (~/^\./ || ~/~$/ || ~/\.o/)
+ unless (~/^\./ || ~/~$/ || ~/\.o/)
print f, "\n"
end
end
diff --git a/sample/eval.rb b/sample/eval.rb
index da31b77153..216bf8ca39 100644
--- a/sample/eval.rb
+++ b/sample/eval.rb
@@ -1,9 +1,10 @@
line = ''
indent=0
+$stdout.sync = TRUE
print "ruby> "
while TRUE
l = gets
- if not l
+ unless l
break if line == ''
else
line = line + l
@@ -17,7 +18,7 @@ while TRUE
if l =~ /^\s*end\b[^_]/
indent -= 1
end
- if l =~ /{\s*(\|.*\|)?\s*$/
+ if l =~ /\{\s*(\|.*\|)?\s*$/
indent += 1
end
if l =~ /^\s*\}/
@@ -31,7 +32,7 @@ while TRUE
begin
print eval(line).inspect, "\n"
rescue
- $! = 'exception raised' if not $!
+ $! = 'exception raised' unless $!
print "ERR: ", $!, "\n"
end
break if not l
diff --git a/sample/freq.rb b/sample/freq.rb
index 0c433ae25a..d951591735 100644
--- a/sample/freq.rb
+++ b/sample/freq.rb
@@ -1,8 +1,8 @@
# word occurrence listing
# usege: ruby freq.rb file..
freq = {}
-while gets()
- while sub(/\w+/, '')
+while gets
+ while sub!(/\w+/, '')
word = $&
freq[word] +=1
end
diff --git a/sample/from.rb b/sample/from.rb
index 2ef000face..d39bb70084 100755
--- a/sample/from.rb
+++ b/sample/from.rb
@@ -1,81 +1,76 @@
#! /usr/local/bin/ruby
require "parsedate"
-require "base64"
+require "kconv"
+require "mailread"
include ParseDate
+include Kconv
-if ARGV[0] == '-w'
- wait = TRUE
- ARGV.shift
-end
+class String
-class Mail
+ public :kconv
- def Mail.new(f)
- if !f.kind_of?(IO)
- f = open(f, "r")
- me = super
- f.close
- else
- me = super
- end
- return me
+ def kconv(code = Kconv::EUC)
+ Kconv.kconv(self, code, Kconv::AUTO)
end
- def initialize(f)
- @header = {}
- @body = []
- while f.gets()
- $_.chop!
- next if /^From / # skip From-line
- break if /^$/ # end of header
- if /^(\S+):\s*(.*)/
- @header[attr = $1.capitalize] = $2
- elsif attr
- sub(/^\s*/, '')
- @header[attr] += "\n" + $_
- end
- end
-
- return if ! $_
-
- while f.gets()
- break if /^From /
- @body.push($_)
+ def kjust(len)
+ len += 1
+ me = self[0, len].ljust(len)
+ if me =~ /.$/ and $&.size == 2
+ me[-2, 2] = ' '
end
+ me.chop!
end
- def header
- return @header
- end
+end
- def body
- return @body
- end
+if ARGV[0] == '-w'
+ wait = TRUE
+ ARGV.shift
+end
+if ARGV.length == 0
+ user = ENV['USER']
+else
+ user = ARGV[0]
end
-ARGV[0] = '/usr/spool/mail/' + ENV['USER'] if ARGV.length == 0
+[ENV['SPOOLDIR'], '/usr/spool', '/var/spool', '/usr', '/var'].each do |m|
+ break if File.exist? ARGV[0] = "#{m}/mail/#{user}"
+end
$outcount = 0;
def fromout(date, from, subj)
return if !date
y = m = d = 0
- esc = "\033\(B"
y, m, d = parsedate(date) if date
- from = "sombody@somewhere" if ! from
- subj = "(nil)" if ! subj
- from = decode_b(from)
- subj = decode_b(subj)
- printf "%-02d/%02d/%02d [%-28.28s%s] %-40.40s%s\n",y,m,d,from,esc,subj,esc
+ if from
+ from.gsub! /\n/, ""
+ else
+ from = "sombody@somewhere"
+ end
+ if subj
+ subj.gsub! /\n/, ""
+ else
+ subj = "(nil)"
+ end
+ if ENV['LANG'] =~ /sjis/i
+ lang = Kconv::SJIS
+ else
+ lang = Kconv::EUC
+ end
+ from = from.kconv(lang).kjust(28)
+ subj = subj.kconv(lang).kjust(40)
+ printf "%02d/%02d/%02d [%s] %s\n",y,m,d,from,subj
$outcount += 1
end
for file in ARGV
next if !File.exist?(file)
f = open(file, "r")
- while !f.eof
+ while !f.eof?
mail = Mail.new(f)
fromout mail.header['Date'], mail.header['From'], mail.header['Subject']
end
diff --git a/sample/marshal.rb b/sample/mrshtest.rb
index 3d399ffe68..402b35ad55 100644
--- a/sample/marshal.rb
+++ b/sample/mrshtest.rb
@@ -1,13 +1,14 @@
require "marshal"
include Marshal
a = 25.6;
-pt = Struct.new('point', :x,:y);
+pt = Struct.new('Point', :x,:y);
x = pt.new(10, 10)
y = pt.new(20, 20)
-rt = Struct.new('rectangle', :origin,:corner);
+rt = Struct.new('Rectangle', :origin,:corner);
z = rt.new(x, y)
c = Object.new
s = [a, x, z, c, c, "fff"];
-print s.inspect;
-d = dumps(s);
-print load(d).inspect
+p s
+d = dump(s);
+p d
+p load(d)
diff --git a/sample/philos.rb b/sample/philos.rb
index ee0a8cd5fc..3ccb052532 100644
--- a/sample/philos.rb
+++ b/sample/philos.rb
@@ -30,7 +30,7 @@ def philosopher(n)
$forks[n].lock
if not $forks[(n+1)%N].try_lock
$forks[n].unlock # avoid deadlock
- continue
+ next
end
$state[n*2] = ?|;
$state[(n+1)%N*2] = ?|;
diff --git a/sample/regx.rb b/sample/regx.rb
index b9d8ca6e14..aaf4b5f1ee 100644
--- a/sample/regx.rb
+++ b/sample/regx.rb
@@ -17,7 +17,7 @@ while TRUE
re = gets
break if not re
re.chop!
- str.gsub! re, "#{st}&#{en}"
+ str.gsub! re, "#{st}\\&#{en}"
print str, "\n"
end
print "\n"
diff --git a/sample/ruby-mode.el b/sample/ruby-mode.el
index 9dfde8588c..678a43ba77 100644
--- a/sample/ruby-mode.el
+++ b/sample/ruby-mode.el
@@ -1,13 +1,12 @@
;;;
;;; ruby-mode.el -
;;;
-;;; $Author$
-;;; $Revision$
-;;; $Date$
+;;; $Author: matz$
+;;; Time-stamp: <97/03/21 01:16:05 matz>
;;; created at: Fri Feb 4 14:49:13 JST 1994
;;;
-(defconst ruby-mode-version "1.0.2")
+(defconst ruby-mode-version "1.0.7")
(defconst ruby-block-beg-re
"class\\|module\\|def\\|if\\|unless\\|case\\|while\\|until\\|for\\|begin\\|do"
@@ -25,15 +24,21 @@
"then\\|else\\|elsif\\|when\\|rescue\\|ensure"
)
+(defconst ruby-block-op-re
+ "and\\|or\\|not"
+ )
+
(defconst ruby-block-end-re "end")
(defconst ruby-delimiter
(concat "[?$/%(){}#\"'`]\\|\\[\\|\\]\\|\\<\\("
- ruby-block-beg-re "\\|" ruby-block-end-re "\\)\\>")
+ ruby-block-beg-re
+ "\\|" ruby-block-end-re
+ "\\)\\>\\|^=begin")
)
(defconst ruby-negative
- (concat "^[ \t]*\\(\\(" ruby-block-mid-re "\\)\\|\\("
+ (concat "^[ \t]*\\(\\(" ruby-block-mid-re "\\)\\>\\|\\("
ruby-block-end-re "\\)\\>\\|\\}\\|\\]\\)")
)
@@ -59,8 +64,9 @@
(define-key ruby-mode-map "\e\C-p" 'ruby-beginning-of-block)
(define-key ruby-mode-map "\e\C-n" 'ruby-end-of-block)
(define-key ruby-mode-map "\t" 'ruby-indent-command)
- (define-key ruby-mode-map "\C-m" 'ruby-reindent-then-newline-and-indent)
- (define-key ruby-mode-map "\C-j" 'newline))
+ (define-key ruby-mode-map "\C-c\C-e" 'ruby-insert-end)
+ (define-key ruby-mode-map "\C-j" 'ruby-reindent-then-newline-and-indent)
+ (define-key ruby-mode-map "\C-m" 'newline))
(defvar ruby-mode-syntax-table nil
"Syntax table in use in ruby-mode buffers.")
@@ -70,6 +76,7 @@
(setq ruby-mode-syntax-table (make-syntax-table))
(modify-syntax-entry ?\' "\"" ruby-mode-syntax-table)
(modify-syntax-entry ?\" "\"" ruby-mode-syntax-table)
+ (modify-syntax-entry ?\` "\"" ruby-mode-syntax-table)
(modify-syntax-entry ?# "<" ruby-mode-syntax-table)
(modify-syntax-entry ?\n ">" ruby-mode-syntax-table)
(modify-syntax-entry ?\\ "'" ruby-mode-syntax-table)
@@ -184,7 +191,10 @@ The variable ruby-indent-level controls the amount of indentation.
(forward-word -1)
(or
(looking-at ruby-block-beg-re)
- (looking-at ruby-block-mid-re)))))))
+ (looking-at ruby-block-op-re)
+ (looking-at ruby-block-mid-re))
+ (goto-char (match-end 0))
+ (looking-at "[^_]"))))))
(defun ruby-parse-region (start end)
(let ((indent-point end)
@@ -228,7 +238,7 @@ The variable ruby-indent-level controls the amount of indentation.
((looking-at "%")
(cond
((and (not (eobp)) (ruby-expr-beg)
- (looking-at "%[Qq\"'Rr/Xx`]\\(.\\)"))
+ (looking-at "%[Qqrx]?\\(.\\)"))
(setq w (buffer-substring (match-beginning 1)
(match-end 1)))
(cond
@@ -278,13 +288,16 @@ The variable ruby-indent-level controls the amount of indentation.
(setq depth (1- depth))
(goto-char pnt))
((looking-at ruby-block-end-re)
- (if (and (not (bolp))
- (progn
- (forward-char -1)
- (eq ?_ (char-after (point))))
- (progn
- (goto-char pnt)
- (eq ?_ (char-after (point)))))
+ (if (or (and (not (bolp))
+ (progn
+ (forward-char -1)
+ (eq ?_ (char-after (point)))))
+ (progn
+ (goto-char pnt)
+ (setq w (char-after (point)))
+ (or (eq ?_ w)
+ (eq ?! w)
+ (eq ?? w))))
nil
(setq nest (cdr nest))
(setq depth (1- depth)))
@@ -295,7 +308,7 @@ The variable ruby-indent-level controls the amount of indentation.
(progn
(forward-char -1)
(not (eq ?_ (char-after (point))))))
- (save-excursion
+ (progn
(goto-char pnt)
(setq w (char-after (point)))
(and (not (eq ?_ w))
@@ -312,6 +325,11 @@ The variable ruby-indent-level controls the amount of indentation.
(if (looking-at "def\\s *[/`]")
(goto-char (match-end 0))
(goto-char pnt)))
+ ((looking-at "^=begin")
+ (if (re-search-forward "^=end" indent-point t)
+ (forward-line 1)
+ (setq in-string (match-end 0))
+ (goto-char indent-point)))
(t
(error (format "bad string %s"
(buffer-substring (point) pnt)
@@ -342,7 +360,7 @@ The variable ruby-indent-level controls the amount of indentation.
(let ((column (current-column))
(s (ruby-parse-region (point) indent-point)))
(cond
- ((> (nth 2 s) 0)
+ ((and (nth 2 s) (> (nth 2 s) 0))
(goto-char (cdr (nth 1 s)))
(forward-word -1)
(setq indent (+ (current-column) ruby-indent-level)))
@@ -358,7 +376,7 @@ The variable ruby-indent-level controls the amount of indentation.
(setq indent (+ (current-column) (* (nth 2 state) ruby-indent-level)))))
))
- ((> (nth 2 state) 0) ; in nest
+ ((and (nth 2 state)(> (nth 2 state) 0)) ; in nest
(goto-char (cdr (nth 1 state)))
(forward-word -1) ; skip back a keyword
(cond
@@ -374,7 +392,7 @@ The variable ruby-indent-level controls the amount of indentation.
(t
(setq indent (+ (current-column) ruby-indent-level)))))
- ((< (nth 2 state) 0) ; in negative nest
+ ((and (nth 2 state) (< (nth 2 state) 0)) ; in negative nest
(setq indent (+ (current-column) (* (nth 2 state) ruby-indent-level)))))
(cond
@@ -385,7 +403,8 @@ The variable ruby-indent-level controls the amount of indentation.
(beginning-of-line)
(cond
((re-search-forward ruby-negative eol t)
- (setq indent (- indent ruby-indent-level)))
+ (and (not (eq ?_ (char-after (match-end 0))))
+ (setq indent (- indent ruby-indent-level))))
;;operator terminated lines
((and
(save-excursion
@@ -396,33 +415,41 @@ The variable ruby-indent-level controls the amount of indentation.
(save-excursion ;except non-block braces
(goto-char (cdr (nth 1 state)))
(or (bobp) (forward-char -1))
- (not (ruby-expr-beg))))))
- (beginning-of-line)
- (skip-chars-backward " \t\n")
- (beginning-of-line) ; goto beginning of non-empty line
+ (not (ruby-expr-beg))))))
+ ;; goto beginning of non-empty no-comment line
+ (let (end done)
+ (while (not done)
+ (skip-chars-backward " \t\n")
+ (setq end (point))
+ (beginning-of-line)
+ (if (re-search-forward "^\\s *#" end t)
+ (beginning-of-line)
+ (setq done t))))
(setq bol (point))
(end-of-line)
(skip-chars-backward " \t")
(or (bobp) (forward-char -1))
- (and (looking-at ruby-operator-chars)
- (or (not (or (eq ?/ (char-after (point)))))
- (null (nth 0 (ruby-parse-region parse-start (point)))))
- (save-excursion
- (goto-char parse-start))
- (not (eq (char-after (1- (point))) ?$))
- (or (not (eq ?| (char-after (point))))
- (save-excursion
- (or (eolp) (forward-char -1))
- (and (search-backward "|")
- (skip-chars-backward " \t\n")
- (and (not (eolp))
- (progn
- (forward-char -1)
- (not (looking-at "\\{")))
- (progn
- (forward-word -1)
- (not (looking-at "do\\>[^_]")))))))
- (setq indent (+ indent ruby-indent-level)))))))
+ (and
+ (or (and (looking-at ruby-symbol-chars)
+ (skip-chars-backward ruby-symbol-chars)
+ (looking-at ruby-block-op-re))
+ (and (looking-at ruby-operator-chars)
+ (or (not (or (eq ?/ (char-after (point)))))
+ (null (nth 0 (ruby-parse-region parse-start (point)))))
+ (not (eq (char-after (1- (point))) ?$))
+ (or (not (eq ?| (char-after (point))))
+ (save-excursion
+ (or (eolp) (forward-char -1))
+ (and (search-backward "|")
+ (skip-chars-backward " \t\n")
+ (and (not (eolp))
+ (progn
+ (forward-char -1)
+ (not (looking-at "\\{")))
+ (progn
+ (forward-word -1)
+ (not (looking-at "do\\>[^_]")))))))))
+ (setq indent (+ indent ruby-indent-level)))))))
indent)))
(defun ruby-electric-brace (arg)
@@ -450,7 +477,7 @@ Returns t unless search stops due to end of buffer."
"Move forward to next end of defun.
An end of a defun is found by moving forward from the beginning of one."
(interactive "p")
- (and (re-search-forward (concat "^\\(" ruby-block-end-re "\\)\\b")
+ (and (re-search-forward (concat "^\\(" ruby-block-end-re "\\)\\b[^_]")
nil 'move (or arg 1))
(progn (beginning-of-line) t))
(forward-line 1))
@@ -512,21 +539,91 @@ An end of a defun is found by moving forward from the beginning of one."
(save-excursion
(ruby-indent-line)))))
-(if (featurep 'hilit19)
- (hilit-set-mode-patterns
- 'ruby-mode
- '(("[^$\\?]\\(\"[^\\\"]*\\(\\\\\\(.\\|\n\\)[^\\\"]*\\)*\"\\)" 1 string)
- ("[^$\\?]\\('[^\\']*\\(\\\\\\(.\\|\n\\)[^\\']*\\)*'\\)" 1 string)
- ("[^$\\?]\\(`[^\\`]*\\(\\\\\\(.\\|\n\\)[^\\`]*\\)*`\\)" 1 string)
- ("^\\s *#.*$" nil comment)
- ("[^$@?\\]\\(#[^$@{].*$\\)" 1 comment)
- ("[^a-zA-Z_]\\(\\?\\(\\\\[CM]-\\)*.\\)" 1 string)
- ("^\\s *\\(require\\|load\\).*$" nil include)
- ("^\\s *\\(include\\|alias\\|undef\\).*$" nil decl)
- ("^\\s *\\<\\(class\\|def\\|module\\)\\>" "[)\n;]" defun)
- ("[^_]\\<\\(begin\\|case\\|else\\|elsif\\|end\\|ensure\\|for\\|if\\|unless\\|rescue\\|then\\|when\\|while\\|until\\|do\\)\\>[^_]" 1 defun)
- ("[^_]\\<\\(and\\|break\\|next\\|raise\\|fail\\|in\\|not\\|or\\|redo\\|retry\\|return\\|super\\|yield\\)\\>[^_]" 1 keyword)
- ("[^_]\\<\\(self\\|nil\\|[A-Z][a-zA-Z_0-9]*\\)\\>[^_]" 1 define)
- ("\\$\\(.\\|\\sw+\\)" nil type)
- ("[$@].[a-zA-Z_0-9]*" nil struct)
- ("^__END__" nil label))))
+(defun ruby-insert-end ()
+ (interactive)
+ (insert "end")
+ (ruby-indent-line t)
+ (end-of-line))
+
+(cond
+ ((featurep 'hilit19)
+ (hilit-set-mode-patterns
+ 'ruby-mode
+ '(("[^$\\?]\\(\"[^\\\"]*\\(\\\\\\(.\\|\n\\)[^\\\"]*\\)*\"\\)" 1 string)
+ ("[^$\\?]\\('[^\\']*\\(\\\\\\(.\\|\n\\)[^\\']*\\)*'\\)" 1 string)
+ ("[^$\\?]\\(`[^\\`]*\\(\\\\\\(.\\|\n\\)[^\\`]*\\)*`\\)" 1 string)
+ ("^\\s *#.*$" nil comment)
+ ("[^$@?\\]\\(#[^$@{].*$\\)" 1 comment)
+ ("[^a-zA-Z_]\\(\\?\\(\\\\[CM]-\\)*.\\)" 1 string)
+ ("^\\s *\\(require\\|load\\).*$" nil include)
+ ("^\\s *\\(include\\|alias\\|undef\\).*$" nil decl)
+ ("^\\s *\\<\\(class\\|def\\|module\\)\\>" "[)\n;]" defun)
+ ("[^_]\\<\\(begin\\|case\\|else\\|elsif\\|end\\|ensure\\|for\\|if\\|unless\\|rescue\\|then\\|when\\|while\\|until\\|do\\)\\>[^_]" 1 defun)
+ ("[^_]\\<\\(and\\|break\\|next\\|raise\\|fail\\|in\\|not\\|or\\|redo\\|retry\\|return\\|super\\|yield\\|self\\|nil\\)\\>[^_]" 1 keyword)
+ ("\\$\\(.\\|\\sw+\\)" nil type)
+ ("[$@].[a-zA-Z_0-9]*" nil struct)
+ ("^__END__" nil label))))
+
+ ((featurep 'font-lock)
+ (or (boundp 'font-lock-variable-name-face)
+ (setq font-lock-variable-name-face font-lock-type-face))
+ (defvar ruby-font-lock-keywords
+ (list
+ (cons (concat
+ "\\(^\\|[^_]\\)\\b\\("
+ (mapconcat
+ 'identity
+ '("alias"
+ "and"
+ "begin"
+ "break"
+ "case"
+ "class"
+ "do"
+ "elsif"
+ "else"
+ "fail"
+ "ensure"
+ "for"
+ "end"
+ "if"
+ "in"
+ "module"
+ "next"
+ "nil"
+ "not"
+ "or"
+ "raise"
+ "redo"
+ "rescue"
+ "retry"
+ "return"
+ "then"
+ "self"
+ "super"
+ "unless"
+ "undef"
+ "until"
+ "when"
+ "while"
+ )
+ "\\|")
+ "\\)[ \n\t()]")
+ 2)
+ ;; variables
+ '("nil\\|self\\|TRUE\\|FALSE"
+ 0 font-lock-variable-name-face)
+ ;; variables
+ '("\\[$@].\\([a-zA-Z0-9_]\\)"
+ 0 font-lock-variable-name-face)
+ ;; constants
+ '("\\b[A-Z]+[a-zA-Z0-9_]*"
+ 0 font-lock-type-face)
+ ;; functions
+ '("\\bdef[ \t]+[a-zA-Z_]+[a-zA-Z0-9_]*[?!]?"
+ 0 font-lock-function-name-face))
+ "*Additional expressions to highlight in ruby mode.")
+ (add-hook 'ruby-mode-hook
+ (lambda ()
+ (setq font-lock-keywords ruby-font-lock-keywords)
+ (font-lock-mode 1)))))
diff --git a/sample/rubydb2x.el b/sample/rubydb2x.el
new file mode 100644
index 0000000000..a74265fb0e
--- /dev/null
+++ b/sample/rubydb2x.el
@@ -0,0 +1,104 @@
+(require 'gud)
+(provide 'rubydb)
+
+;; ======================================================================
+;; rubydb functions
+
+;;; History of argument lists passed to rubydb.
+(defvar gud-rubydb-history nil)
+
+(defun gud-rubydb-massage-args (file args)
+ (cons "-I" (cons "." (cons "-r" (cons "debug" (cons file args))))))
+
+;; There's no guarantee that Emacs will hand the filter the entire
+;; marker at once; it could be broken up across several strings. We
+;; might even receive a big chunk with several markers in it. If we
+;; receive a chunk of text which looks like it might contain the
+;; beginning of a marker, we save it here between calls to the
+;; filter.
+(defvar gud-rubydb-marker-acc "")
+
+(defun gud-rubydb-marker-filter (string)
+ (save-match-data
+ (setq gud-marker-acc (concat gud-marker-acc string))
+ (let ((output ""))
+
+ ;; Process all the complete markers in this chunk.
+ (while (string-match "\032\032\\([^:\n]*\\):\\([0-9]*\\):.*\n"
+ gud-marker-acc)
+ (setq
+
+ ;; Extract the frame position from the marker.
+ gud-last-frame
+ (cons (substring gud-marker-acc (match-beginning 1) (match-end 1))
+ (string-to-int (substring gud-marker-acc
+ (match-beginning 2)
+ (match-end 2))))
+
+ ;; Append any text before the marker to the output we're going
+ ;; to return - we don't include the marker in this text.
+ output (concat output
+ (substring gud-marker-acc 0 (match-beginning 0)))
+
+ ;; Set the accumulator to the remaining text.
+ gud-marker-acc (substring gud-marker-acc (match-end 0))))
+
+ ;; Does the remaining text look like it might end with the
+ ;; beginning of another marker? If it does, then keep it in
+ ;; gud-marker-acc until we receive the rest of it. Since we
+ ;; know the full marker regexp above failed, it's pretty simple to
+ ;; test for marker starts.
+ (if (string-match "\032.*\\'" gud-marker-acc)
+ (progn
+ ;; Everything before the potential marker start can be output.
+ (setq output (concat output (substring gud-marker-acc
+ 0 (match-beginning 0))))
+
+ ;; Everything after, we save, to combine with later input.
+ (setq gud-marker-acc
+ (substring gud-marker-acc (match-beginning 0))))
+
+ (setq output (concat output gud-marker-acc)
+ gud-marker-acc ""))
+
+ output)))
+
+(defun gud-rubydb-find-file (f)
+ (find-file-noselect f))
+
+(defvar rubydb-command-name "ruby"
+ "File name for executing ruby.")
+
+;;;###autoload
+(defun rubydb (command-line)
+ "Run rubydb on program FILE in buffer *gud-FILE*.
+The directory containing FILE becomes the initial working directory
+and source-file directory for your debugger."
+ (interactive
+ (list (read-from-minibuffer "Run rubydb (like this): "
+ (if (consp gud-rubydb-history)
+ (car gud-rubydb-history)
+ (concat rubydb-command-name " "))
+ nil nil
+ '(gud-rubydb-history . 1))))
+
+ (gud-overload-functions '((gud-massage-args . gud-rubydb-massage-args)
+ (gud-marker-filter . gud-rubydb-marker-filter)
+ (gud-find-file . gud-rubydb-find-file)
+ ))
+ (gud-common-init command-line)
+
+ (gud-def gud-break "b %l" "\C-b" "Set breakpoint at current line.")
+; (gud-def gud-remove "clear %l" "\C-d" "Remove breakpoint at current line")
+ (gud-def gud-step "s" "\C-s" "Step one source line with display.")
+ (gud-def gud-next "n" "\C-n" "Step one line (skip functions).")
+ (gud-def gud-cont "c" "\C-r" "Continue with display.")
+ (gud-def gud-finish "finish" "\C-f" "Finish executing current function.")
+ (gud-def gud-up "up %p" "<" "Up N stack frames (numeric arg).")
+ (gud-def gud-down "down %p" ">" "Down N stack frames (numeric arg).")
+ (gud-def gud-print "p %e" "\C-p" "Evaluate ruby expression at point.")
+
+ (setq comint-prompt-regexp "^(rdb:-) ")
+ (setq paragraph-start comint-prompt-regexp)
+ (run-hooks 'rubydb-mode-hook)
+ )
diff --git a/sample/rubydb3x.el b/sample/rubydb3x.el
new file mode 100644
index 0000000000..9d4e31f90e
--- /dev/null
+++ b/sample/rubydb3x.el
@@ -0,0 +1,104 @@
+(require 'gud)
+(provide 'rubydb)
+
+;; ======================================================================
+;; rubydb functions
+
+;;; History of argument lists passed to rubydb.
+(defvar gud-rubydb-history nil)
+
+(defun gud-rubydb-massage-args (file args)
+ (cons "-r" (cons "debug" args)))
+
+;; There's no guarantee that Emacs will hand the filter the entire
+;; marker at once; it could be broken up across several strings. We
+;; might even receive a big chunk with several markers in it. If we
+;; receive a chunk of text which looks like it might contain the
+;; beginning of a marker, we save it here between calls to the
+;; filter.
+(defvar gud-rubydb-marker-acc "")
+
+(defun gud-rubydb-marker-filter (string)
+ (setq gud-marker-acc (concat gud-marker-acc string))
+ (let ((output ""))
+
+ ;; Process all the complete markers in this chunk.
+ (while (string-match "\032\032\\([^:\n]*\\):\\([0-9]*\\):.*\n"
+ gud-marker-acc)
+ (setq
+
+ ;; Extract the frame position from the marker.
+ gud-last-frame
+ (cons (substring gud-marker-acc (match-beginning 1) (match-end 1))
+ (string-to-int (substring gud-marker-acc
+ (match-beginning 2)
+ (match-end 2))))
+
+ ;; Append any text before the marker to the output we're going
+ ;; to return - we don't include the marker in this text.
+ output (concat output
+ (substring gud-marker-acc 0 (match-beginning 0)))
+
+ ;; Set the accumulator to the remaining text.
+ gud-marker-acc (substring gud-marker-acc (match-end 0))))
+
+ ;; Does the remaining text look like it might end with the
+ ;; beginning of another marker? If it does, then keep it in
+ ;; gud-marker-acc until we receive the rest of it. Since we
+ ;; know the full marker regexp above failed, it's pretty simple to
+ ;; test for marker starts.
+ (if (string-match "\032.*\\'" gud-marker-acc)
+ (progn
+ ;; Everything before the potential marker start can be output.
+ (setq output (concat output (substring gud-marker-acc
+ 0 (match-beginning 0))))
+
+ ;; Everything after, we save, to combine with later input.
+ (setq gud-marker-acc
+ (substring gud-marker-acc (match-beginning 0))))
+
+ (setq output (concat output gud-marker-acc)
+ gud-marker-acc ""))
+
+ output))
+
+(defun gud-rubydb-find-file (f)
+ (save-excursion
+ (let ((buf (find-file-noselect f)))
+ (set-buffer buf)
+ (gud-make-debug-menu)
+ buf)))
+
+(defvar rubydb-command-name "ruby"
+ "File name for executing ruby.")
+
+;;;###autoload
+(defun rubydb (command-line)
+ "Run rubydb on program FILE in buffer *gud-FILE*.
+The directory containing FILE becomes the initial working directory
+and source-file directory for your debugger."
+ (interactive
+ (list (read-from-minibuffer "Run rubydb (like this): "
+ (if (consp gud-rubydb-history)
+ (car gud-rubydb-history)
+ (concat rubydb-command-name " "))
+ nil nil
+ '(gud-rubydb-history . 1))))
+
+ (gud-common-init command-line 'gud-rubydb-massage-args
+ 'gud-rubydb-marker-filter 'gud-rubydb-find-file)
+
+ (gud-def gud-break "b %l" "\C-b" "Set breakpoint at current line.")
+; (gud-def gud-remove "clear %l" "\C-d" "Remove breakpoint at current line")
+ (gud-def gud-step "s" "\C-s" "Step one source line with display.")
+ (gud-def gud-next "n" "\C-n" "Step one line (skip functions).")
+ (gud-def gud-cont "c" "\C-r" "Continue with display.")
+ (gud-def gud-finish "finish" "\C-f" "Finish executing current function.")
+ (gud-def gud-up "up %p" "<" "Up N stack frames (numeric arg).")
+ (gud-def gud-down "down %p" ">" "Down N stack frames (numeric arg).")
+ (gud-def gud-print "p %e" "\C-p" "Evaluate ruby expression at point.")
+
+ (setq comint-prompt-regexp "^(rdb:-) ")
+ (setq paragraph-start comint-prompt-regexp)
+ (run-hooks 'rubydb-mode-hook)
+ )
diff --git a/sample/svr.rb b/sample/svr.rb
index 14aded8c3f..c866407eb0 100644
--- a/sample/svr.rb
+++ b/sample/svr.rb
@@ -18,7 +18,7 @@ while TRUE
socks.push(ns)
print(s, " is accepted\n")
else
- if s.eof
+ if s.eof?
print(s, " is gone\n")
s.close
socks.delete(s)
diff --git a/sample/test.rb b/sample/test.rb
index aacddbc56a..c940f0023f 100644
--- a/sample/test.rb
+++ b/sample/test.rb
@@ -96,13 +96,13 @@ tmp.close
# test break
tmp = open("while_tmp", "r")
-ok(tmp.type == "File")
+ok(tmp.kind_of?(File))
while tmp.gets()
break if /vt100/
end
-ok(!tmp.eof && /vt100/)
+ok(!tmp.eof? && /vt100/)
tmp.close
# test next
@@ -112,7 +112,7 @@ while tmp.gets()
next if /vt100/;
$bad = 1 if /vt100/;
end
-ok(!(!tmp.eof || /vt100/ || $bad))
+ok(!(!tmp.eof? || /vt100/ || $bad))
tmp.close
# test redo
@@ -126,9 +126,19 @@ while tmp.gets()
$bad = 1 if /vt100/;
$bad = 1 if /VT100/;
end
-ok(tmp.eof && !$bad)
+ok(tmp.eof? && !$bad)
tmp.close
+sum=0
+for i in 1..10
+ sum += i
+ i -= 1
+ if i > 0
+ redo
+ end
+end
+ok(sum == 220)
+
# test interval
$bad = FALSE
tmp = open("while_tmp", "r")
@@ -173,33 +183,23 @@ rescue
end
ok(TRUE)
-$bad = TRUE
-$string = "this must be handled no.3"
-begin
- fail $string
-rescue
-ensure
- $bad = FALSE
- ok(TRUE)
-end
-ok(FALSE) if $bad || $! != $string
-
# exception in rescue clause
+$string = "this must be handled no.3"
begin
begin
- fail "this must be handled no.4"
- rescue
fail "exception in rescue clause"
+ rescue
+ fail $string
end
ok(FALSE)
rescue
- ok(TRUE)
+ ok(TRUE) if $! == $string
end
# exception in ensure clause
begin
begin
- fail "this must be handled no.5"
+ fail "this must be handled no.4"
ensure
fail "exception in ensure clause"
end
@@ -222,7 +222,7 @@ ok(!$bad)
$bad = TRUE
begin
begin
- fail "this must be handled no.5"
+ fail "this must be handled no.6"
ensure
$bad = FALSE
end
@@ -429,8 +429,15 @@ ok($x == [1, 2, 3, 1, 2, 3, 4, 5, 6, 7])
check "bignum"
def fact(n)
return 1 if n == 0
- return n*fact(n-1)
+ f = 1
+ while n>0
+ f *= n
+ n -= 1
+ end
+ p f
+ return f
end
+fact(3)
$x = fact(40)
ok($x == $x)
ok($x == fact(40))
@@ -445,11 +452,48 @@ ok($x == -815915283247897734345611269596115894272000000000)
ok(2-(2**32) == -(2**32-2))
ok(2**32 - 5 == (2**32-3)-2)
+$good = TRUE;
+for i in 1000..3000
+ $good = FALSE if ((1<<i) != (2**i))
+end
+ok($good)
+
+$good = TRUE;
+n1=1
+for i in 0..3000
+ $good = FALSE if ((1<<i) != n1)
+ n1 *= 2
+end
+ok($good)
+
+$good = TRUE;
+n2=n1
+for i in 3000..-1
+ n1 = n1 / 2
+ n2 = n2 >> 1
+ $good = FALSE if (n1 != n2)
+end
+ok($good)
+
+$good = TRUE;
+for i in 3500..4000
+ n1 = 1 << i;
+ $good = FALSE if ((n1**2-1) / (n1+1) != (n1-1))
+end
+ok($good)
+
check "string & char"
ok("abcd" == "abcd")
ok("abcd" =~ "abcd")
ok("abcd" === "abcd")
+ok(("abc" =~ /^$/) == FALSE)
+ok(("abc\n" =~ /^$/) == FALSE)
+ok(("abc" =~ /^d*$/) == FALSE)
+ok(("abc" =~ /d*$/) == 3)
+ok("" =~ /^$/)
+ok("\n" =~ /^$/)
+ok("a\n\n" =~ /^$/)
$foo = "abc"
ok("#$foo = abc" == "abc = abc")
@@ -467,6 +511,13 @@ ok(foo * 5 == '-----')
ok(foo * 1 == '-')
ok(foo * 0 == '')
+$x = "a.gif"
+ok($x.sub(/.*\.([^\.]+)$/, '\1') == "gif")
+ok($x.sub(/.*\.([^\.]+)$/, 'b.\1') == "b.gif")
+ok($x.sub(/.*\.([^\.]+)$/, '\2') == "")
+ok($x.sub(/.*\.([^\.]+)$/, 'a\2b') == "ab")
+ok($x.sub(/.*\.([^\.]+)$/, '<\&>') == "<a.gif>")
+
# character constants(assumes ASCII)
ok("a"[0] == ?a)
ok(?a == ?a)
@@ -582,7 +633,7 @@ if defined? Process.kill
check "signal"
$x = 0
- trap "SIGINT", proc{|sig| $x = sig}
+ trap "SIGINT", proc{|sig| $x = 2}
Process.kill "SIGINT", $$
sleep 0.1
ok($x == 2)
@@ -596,12 +647,13 @@ if defined? Process.kill
rescue
x = $!
end
- ok(x =~ /Interrupt/)
+ ok(x && x =~ /Interrupt/)
else
ok(FALSE)
end
check "eval"
+ok(eval("") == nil)
$bad=FALSE
eval 'while FALSE; $bad = TRUE; print "foo\n" end'
ok(!$bad)
@@ -696,7 +748,6 @@ tmp.close
done = TRUE
tmp = open("script_tmp", "r")
while tmp.gets
- print "c: ", $_
if $_.to_i % 5 != 0
done = FALSE
break
@@ -859,6 +910,22 @@ ok(x.baz == "foo+foo")
# check for cache
ok(x.baz == "foo+foo")
+class Alias3<Alias2
+ def foo
+ defined? super
+ end
+ def bar
+ defined? super
+ end
+ def quux
+ defined? super
+ end
+end
+x = Alias3.new
+ok(!x.foo)
+ok(x.bar)
+ok(!x.quux)
+
check "gc"
begin
1.upto(10000) {
diff --git a/sample/tkbiff.rb b/sample/tkbiff.rb
index 24860c11a6..d2d7bf7beb 100644
--- a/sample/tkbiff.rb
+++ b/sample/tkbiff.rb
@@ -116,7 +116,7 @@ def pop_up
outcount = 0;
$list.delete 0, 'end'
f = open($spool, "r")
- while !f.eof
+ while !f.eof?
mail = Mail.new(f)
date, from, subj = mail.header['Date'], mail.header['From'], mail.header['Subject']
next if !date
diff --git a/sample/tkfrom.rb b/sample/tkfrom.rb
index 9a53ea2d72..b0ef8995ca 100644
--- a/sample/tkfrom.rb
+++ b/sample/tkfrom.rb
@@ -9,7 +9,7 @@ class Mail
def Mail.new(f)
if !f.kind_of?(IO)
f = open(f, "r")
- me = super
+ me = super(f)
f.close
else
me = super
@@ -22,7 +22,7 @@ class Mail
@body = []
while f.gets()
$_.chop!
- next if /^From / # skip From-line
+ next if /^From / # skip From-line
break if /^$/ # end of header
if /^(\S+):\s*(.*)/
@header[attr = $1.capitalize] = $2
@@ -50,7 +50,15 @@ class Mail
end
-ARGV[0] = '/usr/spool/mail/' + ENV['USER'] if ARGV.length == 0
+if ARGV.length == 0
+ if ENV['MAIL']
+ ARGV[0] = ENV['MAIL']
+ elsif ENV['USER']
+ ARGV[0] = '/usr/spool/mail/' + ENV['USER']
+ elsif ENV['LOGNAME']
+ ARGV[0] = '/usr/spool/mail/' + ENV['LOGNAME']
+ end
+end
require "tk"
list = scroll = nil
@@ -90,8 +98,10 @@ for file in ARGV
f = open(file, "r")
while !f.eof
mail = Mail.new(f)
- date, from, subj = mail.header['Date'], mail.header['From'], mail.header['Subject']
+ date = mail.header['Date']
next if !date
+ from = mail.header['From']
+ subj = mail.header['Subject']
y = m = d = 0
y, m, d = parsedate(date) if date
from = "sombody@somewhere" if ! from
diff --git a/sig.h b/sig.h
index 5fc8abe1b6..2d29a69a8a 100644
--- a/sig.h
+++ b/sig.h
@@ -17,6 +17,7 @@ extern int trap_immediate;
extern int prohibit_interrupt;
#define DEFER_INTS {prohibit_interrupt++;}
#define ALLOW_INTS {prohibit_interrupt--; CHECK_INTS;}
+#define ENABLE_INTS {prohibit_interrupt--;}
extern int trap_pending;
#ifdef THREAD
diff --git a/signal.c b/signal.c
index f36d9abac5..7ce1ef4b27 100644
--- a/signal.c
+++ b/signal.c
@@ -14,8 +14,12 @@
#include <stdio.h>
#ifndef NSIG
+#ifdef DJGPP
+#define NSIG SIGMAX
+#else
#define NSIG (_SIGMAX + 1) /* For QNX */
#endif
+#endif
static struct signals {
char *signm;
@@ -175,6 +179,7 @@ f_kill(argc, argv)
int i;
char *s;
+ rb_secure(2);
if (argc < 2)
ArgError("wrong # of arguments -- kill(sig, pid...)");
switch (TYPE(argv[0])) {
@@ -334,6 +339,7 @@ rb_trap_exec()
#else
rb_interrupt();
#endif
+ return;
}
rb_trap_eval(trap_list[i], i);
}
@@ -364,7 +370,7 @@ trap(arg)
{
RETSIGTYPE (*func)();
VALUE command, old;
- int i, sig;
+ int sig;
func = sighandle;
command = arg->cmd;
@@ -372,6 +378,7 @@ trap(arg)
func = SIG_IGN;
}
else if (TYPE(command) == T_STRING) {
+ Check_SafeStr(command); /* taint check */
if (RSTRING(command)->len == 0) {
func = SIG_IGN;
}
@@ -448,11 +455,13 @@ trap(arg)
trap_list[sig] = command;
/* enable at least specified signal. */
+#ifndef NT
#ifdef HAVE_SIGPROCMASK
sigdelset(&arg->mask, sig);
#else
arg->mask &= ~sigmask(sig);
#endif
+#endif
return old;
}
@@ -477,6 +486,7 @@ f_trap(argc, argv)
{
struct trap_arg arg;
+ rb_secure(2);
if (argc == 0 || argc > 2) {
ArgError("wrong # of arguments -- trap(sig, cmd)/trap(sig){...}");
}
@@ -507,9 +517,9 @@ f_trap(argc, argv)
void
Init_signal()
{
- extern VALUE cKernel;
+ extern VALUE mKernel;
- rb_define_private_method(cKernel, "trap", f_trap, -1);
+ rb_define_global_function("trap", f_trap, -1);
#ifdef POSIX_SIGNAL
posix_signal(SIGINT, sighandle);
#else
diff --git a/sprintf.c b/sprintf.c
index df0ecba376..015d3d4131 100644
--- a/sprintf.c
+++ b/sprintf.c
@@ -15,6 +15,95 @@
static void fmt_setup();
+static char*
+remove_sign_bits(str, base)
+ char *str;
+ int base;
+{
+ char *s, *t, *end;
+
+ s = t = str;
+
+ if (base == 16) {
+ x_retry:
+ switch (*t) {
+ case 'c':
+ *t = '8';
+ break;
+ case 'd':
+ *t = '9';
+ break;
+ case 'e':
+ *t = '2';
+ break;
+ case 'f':
+ if (t[1] > '8') {
+ t++;
+ goto x_retry;
+ }
+ *t = '1';
+ break;
+ case '1':
+ case '3':
+ case '7':
+ if (t[1] > '8') {
+ t++;
+ goto x_retry;
+ }
+ break;
+ }
+ switch (*t) {
+ case '1': *t = 'f'; break;
+ case '2': *t = 'e'; break;
+ case '3': *t = 'f'; break;
+ case '4': *t = 'c'; break;
+ case '5': *t = 'd'; break;
+ case '6': *t = 'e'; break;
+ case '7': *t = 'f'; break;
+ }
+ }
+ else if (base == 8) {
+ o_retry:
+ switch (*t) {
+ case '6':
+ *t = '2';
+ break;
+ case '7':
+ if (t[1] > '3') {
+ t++;
+ goto o_retry;
+ }
+ *t = '1';
+ break;
+ case '1':
+ case '3':
+ if (t[1] > '3') {
+ t++;
+ goto o_retry;
+ }
+ break;
+ }
+ switch (*t) {
+ case '1': *t = '7'; break;
+ case '2': *t = '6'; break;
+ case '3': *t = '7'; break;
+ }
+ }
+ else if (base == 2) {
+ while (t<end && *t == '1') t++;
+ t--;
+ }
+ while (*t) *s++ = *t++;
+ *s = '\0';
+
+ return str;
+}
+
+double big2dbl();
+#ifndef atof
+double atof();
+#endif
+
VALUE
f_sprintf(argc, argv)
int argc;
@@ -221,10 +310,12 @@ f_sprintf(argc, argv)
case 'B':
case 'o':
case 'x':
+ case 'u':
{
- VALUE val = GETARG();
- char fbuf[32], nbuf[64], *s, *t, *end;
+ volatile VALUE val = GETARG();
+ char fbuf[32], nbuf[64], *s, *t;
int v, base, bignum = 0;
+ int len, slen, pos;
bin_retry:
switch (TYPE(val)) {
@@ -246,93 +337,125 @@ f_sprintf(argc, argv)
break;
}
+ if (*p == 'x') base = 16;
+ else if (*p == 'o') base = 8;
+ else if (*p == 'u') base = 10;
+ else if (*p == 'b' || *p == 'B') base = 2;
if (!bignum) {
if (*p == 'b' || *p == 'B') {
val = int2big(v);
}
else {
- int len;
-
- fmt_setup(fbuf, *p, flags, width, prec);
- sprintf(nbuf, fbuf, v);
- len = strlen(nbuf);
-
- if (flags&FPREC) {
- CHECK(prec);
- }
- else if ((flags&FWIDTH) && width > len) {
- CHECK(width);
+ s = nbuf;
+ if (v < 0) {
+ strcpy(s, "..");
+ s += 2;
+ bignum = 2;
}
- else {
- CHECK(len);
+ sprintf(fbuf, "%%%c", *p);
+ sprintf(s, fbuf, v);
+ if (v < 0) {
+ char d = 0;
+
+ remove_sign_bits(s, base);
+ switch (base) {
+ case 16:
+ d = 'f'; break;
+ case 8:
+ d = '7'; break;
+ }
+ if (d && *s != d) {
+ memmove(s+1, s, strlen(s)+1);
+ *s = d;
+ }
}
- memcpy(&buf[blen], nbuf, len);
- blen += len;
- break;
+ s = nbuf;
+ goto unsigned_format;
}
}
- if (*p == 'x') base = 16;
- else if (*p == 'o') base = 8;
- else if (*p == 'b' || *p == 'B') base = 2;
if (*p != 'B' && !RBIGNUM(val)->sign) {
val = big_clone(val);
big_2comp(val);
}
val = big2str(val, base);
- fmt_setup(fbuf, 's', flags, width, prec);
-
- s = t = RSTRING(val)->ptr;
- end = s + RSTRING(val)->len;
+ s = RSTRING(val)->ptr;
if (*s == '-' && *p != 'B') {
- s++; t++;
- if (base == 16) {
- while (t<end && *t == 'f') t++;
- if (*t == 'e') {
- *t = '2';
- }
- else if (*t == 'd') {
- *t = '5';
- }
- else if (*t == 'c') {
- *t = '4';
- }
- else if (*t < '8') {
- *--t = '1';
- }
+ remove_sign_bits(++s, base);
+ val = str_new(0, 3+strlen(s));
+ t = RSTRING(val)->ptr;
+ strcpy(t, "..");
+ t += 2;
+ switch (base) {
+ case 16:
+ if (s[0] != 'f') strcpy(t++, "f"); break;
+ case 8:
+ if (s[0] != '7') strcpy(t++, "7"); break;
}
- if (base == 8) {
- while (t<end && *t == '7') t++;
- if (*t == '6') {
- *t = '2';
- }
- else if (*t < '4') {
- *--t = '1';
- }
+ strcpy(t, s);
+ bignum = 2;
+ }
+ s = RSTRING(val)->ptr;
+
+ unsigned_format:
+ slen = len = strlen(s);
+ pos = blen;
+ if (flags&FWIDTH) {
+ if (width <= len) flags &= ~FWIDTH;
+ else {
+ slen = width;
}
- if (base == 2) {
- while (t<end && *t == '1') t++;
- t--;
+ }
+ if (flags&FPREC) {
+ if (prec <= len) flags &= ~FPREC;
+ else {
+ if (prec >= slen) {
+ flags &= ~FWIDTH;
+ slen = prec;
+ }
}
- while (t<end) *s++ = *t++;
- *s = '\0';
}
- else if (flags & FZERO) {
- while (*s == ' ') {
- *s++ = '0';
+ if (slen > len) {
+ int n = slen-len;
+ char d = ' ';
+ if (flags & FZERO) d = '0';
+ CHECK(n);
+ while (n--) {
+ buf[blen++] = d;
}
}
- s = RSTRING(val)->ptr;
- if (flags&FPREC) {
- CHECK(prec);
+ if ((flags&(FWIDTH|FPREC)) == (FWIDTH|FPREC)) {
+ if (prec < width) {
+ pos = width - prec;
+ }
}
- else if ((flags&FWIDTH) && width > end - s) {
- CHECK(width);
+ CHECK(len);
+ strcpy(&buf[blen], s);
+ blen += len;
+ t = &buf[pos];
+ if (bignum == 2) {
+ char d = '.';
+
+ switch (base) {
+ case 16:
+ d = 'f'; break;
+ case 8:
+ d = '7'; break;
+ case '2':
+ d = '1'; break;
+ }
+
+ if ((flags & FPREC) == 0 || prec <= len-2) {
+ *t++ = '.'; *t++ = '.';
+ }
+ while (*t == ' ' || *t == '.') {
+ *t++ = d;
+ }
}
- else {
- CHECK(s - end);
+ else if (flags & (FPREC|FZERO)) {
+ while (*t == ' ') {
+ *t++ = '0';
+ }
}
- sprintf(&buf[blen], fbuf, s);
- blen += strlen(&buf[blen]);
}
break;
@@ -341,7 +464,7 @@ f_sprintf(argc, argv)
case 'O':
case 'X':
{
- VALUE val = GETARG();
+ volatile VALUE val = GETARG();
char fbuf[32], c = *p;
int bignum = 0, base;
int v;
@@ -371,28 +494,65 @@ f_sprintf(argc, argv)
}
if (bignum) {
- fmt_setup(fbuf, 's', flags, width, prec);
+ char *s = RSTRING(val)->ptr;
+ int slen, len, pos_b, pos;
+ slen = len = strlen(s);
+ pos = pos_b = blen;
+ if (flags&FWIDTH) {
+ if (width <= len) flags &= ~FWIDTH;
+ else {
+ slen = width;
+ }
+ }
if (flags&FPREC) {
- CHECK(prec);
+ if (prec <= len) flags &= ~FPREC;
+ else {
+ if (prec >= slen) {
+ flags &= ~FWIDTH;
+ slen = prec;
+ }
+ }
}
- else if ((flags&FWIDTH) && width > RSTRING(val)->len) {
- CHECK(width);
+ if (slen > len) {
+ int n = slen-len;
+ CHECK(n);
+ while (n--) {
+ buf[blen++] = ' ';
+ }
}
- else {
- CHECK(RSTRING(val)->len);
+ if ((flags&(FWIDTH|FPREC)) == (FWIDTH|FPREC)) {
+ if (prec < width) {
+ pos = width - prec;
+ }
+ }
+ CHECK(len);
+ strcpy(&buf[blen], s);
+ blen += len;
+ if (flags & (FPREC|FZERO)) {
+ char *t = &buf[pos];
+ char *b = &buf[pos_b];
+
+ if (s[0] == '-') {
+ if (slen > len && t != b ) t[-1] = '-';
+ else *t++ = '-';
+ }
+ while (*t == ' ' || *t == '-') {
+ *t++ = '0';
+ }
}
- sprintf(&buf[blen], fbuf, RSTRING(val)->ptr);
- blen += strlen(&buf[blen]);
}
else {
- fmt_setup(fbuf, c, flags, width, prec);
+ int max = 11;
- CHECK(11);
+ if ((flags & FPREC) && prec > max) max = prec;
+ if ((flags & FWIDTH) && width > max) max = width;
+ CHECK(max);
if (v < 0 && (c == 'X' || c == 'O')) {
v = -v;
PUSH("-", 1);
}
+ fmt_setup(fbuf, c, flags, width, prec);
sprintf(&buf[blen], fbuf, v);
blen += strlen(&buf[blen]);
}
@@ -406,8 +566,6 @@ f_sprintf(argc, argv)
VALUE val = GETARG();
double fval;
char fbuf[32];
- double big2dbl();
- double atof();
switch (TYPE(val)) {
case T_FIXNUM:
diff --git a/st.c b/st.c
index 3efba70e22..9067fad1c7 100644
--- a/st.c
+++ b/st.c
@@ -20,20 +20,18 @@ static char sccsid[] = "@(#) st.c 5.1 89/12/14 Crucible";
*/
static int numcmp();
static int numhash();
-struct st_hash_type type_numhash = {
+static struct st_hash_type type_numhash = {
numcmp,
numhash,
};
extern int strcmp();
static int strhash();
-struct st_hash_type type_strhash = {
+static struct st_hash_type type_strhash = {
strcmp,
strhash,
};
-#include "sig.h"
-
extern void *xmalloc();
static void rehash();
@@ -42,35 +40,9 @@ static void rehash();
#define alloc(type) (type*)xmalloc((unsigned)sizeof(type))
#define Calloc(n,s) (char*)xcalloc((n),(s))
-static int
-call_cmp_func(table, x, y)
- st_table *table;
- char *x, *y;
-{
- int cmp;
-
- DEFER_INTS;
- cmp = (*table->type->compare)(x, y);
- ALLOW_INTS;
- return cmp;
-}
-
-#define EQUAL(table, x, y) (call_cmp_func((table),(x), (y)) == 0)
+#define EQUAL(table, x, y) ((*table->type->compare)(x, y) == 0)
-static int
-call_hash_func(key, table)
- char *key;
- st_table *table;
-{
- int hash;
-
- DEFER_INTS;
- hash = (*table->type->hash)((key), table->num_bins);
- ALLOW_INTS;
- return hash;
-}
-
-#define do_hash(key, table) call_hash_func((key), table)
+#define do_hash(key, table) (*(table)->type->hash)((key), (table)->num_bins)
st_table*
st_init_table_with_size(type, size)
@@ -355,6 +327,47 @@ st_delete(table, key, value)
}
int
+st_delete_safe(table, key, value, never)
+ register st_table *table;
+ register char **key;
+ char **value;
+ char *never;
+{
+ int hash_val;
+ st_table_entry *tmp;
+ register st_table_entry *ptr;
+
+ hash_val = do_hash(*key, table);
+
+ ptr = table->bins[hash_val];
+
+ if (ptr == nil(st_table_entry)) {
+ if (value != nil(char*)) *value = nil(char);
+ return 0;
+ }
+
+ if (EQUAL(table, *key, ptr->key)) {
+ table->num_entries--;
+ *key = ptr->key;
+ if (value != nil(char*)) *value = ptr->record;
+ ptr->key = ptr->record = never;
+ return 1;
+ }
+
+ for(; ptr->next != nil(st_table_entry); ptr = ptr->next) {
+ if (EQUAL(table, ptr->next->key, *key)) {
+ table->num_entries--;
+ *key = ptr->key;
+ if (value != nil(char*)) *value = ptr->record;
+ ptr->key = ptr->record = never;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int
st_foreach(table, func, arg)
st_table *table;
enum st_retval (*func)();
diff --git a/st.h b/st.h
index 9b25c944f7..cfd86451f5 100644
--- a/st.h
+++ b/st.h
@@ -48,4 +48,4 @@ st_table *st_copy();
int st_strhash();
-#endif ST_INCLUDED
+#endif /* ST_INCLUDED */
diff --git a/string.c b/string.c
index 4d4867f37a..91bb1daab2 100644
--- a/string.c
+++ b/string.c
@@ -23,14 +23,22 @@ VALUE cString;
#define STRLEN(s) RSTRING(s)->len
+#define STR_FREEZE FL_USER1
+#define STR_TAINT FL_USER2
+VALUE str_taint();
+VALUE str_tainted();
+
VALUE
str_new(ptr, len)
- char *ptr;
+ UCHAR *ptr;
UINT len;
{
NEWOBJ(str, struct RString);
OBJSETUP(str, cString, T_STRING);
+ if (rb_safe_level() >= 3) {
+ FL_SET(str, STR_TAINT);
+ }
str->len = len;
str->orig = 0;
str->ptr = ALLOC_N(char,len+1);
@@ -43,7 +51,7 @@ str_new(ptr, len)
VALUE
str_new2(ptr)
- char *ptr;
+ UCHAR *ptr;
{
return str_new(ptr, strlen(ptr));
}
@@ -59,9 +67,36 @@ str_new3(str)
str2->ptr = str->ptr;
str2->orig = str;
+ if (rb_safe_level() >= 3) {
+ FL_SET(str2, STR_TAINT);
+ }
+
return (VALUE)str2;
}
+VALUE
+str_new4(orig)
+ struct RString *orig;
+{
+ NEWOBJ(str, struct RString);
+ OBJSETUP(str, cString, T_STRING);
+
+ str->len = orig->len;
+ str->ptr = orig->ptr;
+ if (orig->orig) {
+ str->orig = orig->orig;
+ }
+ else {
+ orig->orig = str;
+ str->orig = 0;
+ }
+ if (rb_safe_level() >= 3) {
+ FL_SET(str, STR_TAINT);
+ }
+
+ return (VALUE)str;
+}
+
#define as_str(str) (struct RString*)obj_as_string(str)
static ID pr_str;
@@ -77,48 +112,55 @@ obj_as_string(obj)
}
str = rb_funcall(obj, pr_str, 0);
if (TYPE(str) != T_STRING)
- return krn_to_s(obj);
+ return any_to_s(obj);
return str;
}
static VALUE
-str_clone(str)
- struct RString *str;
+str_clone(orig)
+ struct RString *orig;
{
- VALUE obj;
+ VALUE str;
- if (str->orig)
- obj = str_new3(str->orig);
+ if (orig->orig)
+ str = str_new3(orig->orig);
else
- obj = str_new(str->ptr, str->len);
- CLONESETUP(obj, str);
- return obj;
+ str = str_new(orig->ptr, orig->len);
+ CLONESETUP(str, orig);
+ return str;
}
VALUE
str_dup(str)
struct RString *str;
{
- return str_new(str->ptr, str->len);
+ VALUE s = str_new(str->ptr, str->len);
+ if (str_tainted(str)) s = str_taint(s);
+ return s;
}
static VALUE
-str_s_new(class, str)
+str_s_new(class, orig)
VALUE class;
- struct RString *str;
+ struct RString *orig;
{
- NEWOBJ(str2, struct RString);
- OBJSETUP(str2, class, T_STRING);
+ NEWOBJ(str, struct RString);
+ OBJSETUP(str, class, T_STRING);
- str = as_str(str);
- str2->len = str->len;
- str2->ptr = ALLOC_N(char, str->len+1);
- if (str2->ptr) {
- memcpy(str2->ptr, str->ptr, str->len);
+ orig = as_str(orig);
+ str->len = orig->len;
+ str->ptr = ALLOC_N(char, orig->len+1);
+ if (str->ptr) {
+ memcpy(str->ptr, orig->ptr, orig->len);
}
- str2->ptr[str->len] = '\0';
- str2->orig = 0;
- return (VALUE)str2;
+ str->ptr[orig->len] = '\0';
+ str->orig = 0;
+
+ if (rb_safe_level() >= 3) {
+ FL_SET(str, STR_TAINT);
+ }
+
+ return (VALUE)str;
}
static VALUE
@@ -140,6 +182,8 @@ str_plus(str1, str2)
memcpy(str3->ptr+str1->len, str2->ptr, str2->len);
str3->ptr[str3->len] = '\0';
+ if (str_tainted(str1) || str_tainted(str2))
+ return str_taint(str3);
return (VALUE)str3;
}
@@ -149,16 +193,22 @@ str_times(str, times)
VALUE times;
{
struct RString *str2;
- int i;
+ int i, len;
- times = NUM2INT(times);
+ len = NUM2INT(times);
+ if (len < 0) {
+ ArgError("negative argument");
+ }
- str2 = (struct RString*)str_new(0, str->len*times);
- for (i=0; i<times; i++) {
+ str2 = (struct RString*)str_new(0, str->len*len);
+ for (i=0; i<len; i++) {
memcpy(str2->ptr+(i*str->len), str->ptr, str->len);
}
str2->ptr[str2->len] = '\0';
+ if (str_tainted(str))
+ return str_taint(str2);
+
return (VALUE)str2;
}
@@ -184,7 +234,7 @@ str_substr(str, start, len)
return (VALUE)str2;
}
-VALUE
+static VALUE
str_subseq(str, beg, end)
struct RString *str;
int beg, end;
@@ -221,14 +271,16 @@ str_subseq(str, beg, end)
extern VALUE ignorecase;
-#define STR_FREEZE FL_USER1
-
void
str_modify(str)
struct RString *str;
{
- char *ptr;
+ UCHAR *ptr;
+ if (rb_safe_level() >= 5) {
+ extern VALUE eSecurityError;
+ Raise(eSecurityError, "cannot change string status");
+ }
if (FL_TEST(str, STR_FREEZE))
TypeError("can't modify frozen string");
if (!str->orig) return;
@@ -250,7 +302,7 @@ str_freeze(str)
}
static VALUE
-str_frozen(str)
+str_frozen_p(str)
VALUE str;
{
if (FL_TEST(str, STR_FREEZE))
@@ -268,9 +320,28 @@ str_dup_freezed(str)
}
VALUE
+str_taint(str)
+ VALUE str;
+{
+ if (TYPE(str) == T_STRING) {
+ FL_SET(str, STR_TAINT);
+ }
+ return str;
+}
+
+VALUE
+str_tainted(str)
+ VALUE str;
+{
+ if (FL_TEST(str, STR_TAINT))
+ return TRUE;
+ return FALSE;
+}
+
+VALUE
str_resize(str, len)
struct RString *str;
- UINT len;
+ int len;
{
str_modify(str);
@@ -287,12 +358,11 @@ str_resize(str, len)
VALUE
str_cat(str, ptr, len)
struct RString *str;
- char *ptr;
+ UCHAR *ptr;
UINT len;
{
- str_modify(str);
-
if (len > 0) {
+ str_modify(str);
REALLOC_N(str->ptr, char, str->len + len + 1);
if (ptr)
memcpy(str->ptr + str->len, ptr, len);
@@ -316,17 +386,19 @@ str_hash(str)
struct RString *str;
{
int len = str->len;
- unsigned char *p = (unsigned char*)str->ptr;
+ UCHAR *p = str->ptr;
int key = 0;
if (ignorecase) {
while (len--) {
- key = key*65599 + *p;
+ key = key*65599 + toupper(*p);
+ p++;
}
}
else {
while (len--) {
- key = key*65599 + toupper(*p);
+ key = key*65599 + *p;
+ p++;
}
}
return key;
@@ -425,7 +497,7 @@ str_index(str, sub, offset)
struct RString *str, *sub;
int offset;
{
- char *s, *e, *p;
+ UCHAR *s, *e, *p;
int len;
if (str->len - offset < sub->len) return -1;
@@ -472,7 +544,7 @@ str_index_method(argc, argv, str)
TypeError("Type mismatch: %s given", rb_class2name(CLASS_OF(sub)));
}
- if (pos == -1) return FALSE;
+ if (pos == -1) return Qnil;
return INT2FIX(pos);
}
@@ -485,7 +557,7 @@ str_rindex(argc, argv, str)
struct RString *sub;
VALUE initpos;
int pos, len;
- char *s, *sbeg, *t;
+ UCHAR *s, *sbeg, *t;
if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
pos = NUM2INT(initpos);
@@ -509,9 +581,9 @@ str_rindex(argc, argv, str)
return Qnil;
}
-static char
+static UCHAR
succ_char(s)
- char *s;
+ UCHAR *s;
{
char c = *s;
@@ -539,7 +611,7 @@ str_succ(orig)
struct RString *orig;
{
struct RString *str, *str2;
- char *sbeg, *s;
+ UCHAR *sbeg, *s;
char c = -1;
str = (struct RString*)str_new(orig->ptr, orig->len);
@@ -562,6 +634,9 @@ str_succ(orig)
}
}
+ if (str_tainted(orig))
+ return str_taint(str);
+
return (VALUE)str;
}
@@ -708,9 +783,6 @@ str_sub_s(str, pat, val, once)
int beg, offset, n;
struct re_registers *regs;
- val = obj_as_string(val);
- str_modify(str);
-
switch (TYPE(pat)) {
case T_REGEXP:
break;
@@ -724,6 +796,7 @@ str_sub_s(str, pat, val, once)
Check_Type(pat, T_REGEXP);
}
+ val = obj_as_string(val);
result = str_new(0,0);
offset=0; n=0;
while ((beg=reg_search(pat, str, offset, 0)) >= 0) {
@@ -750,8 +823,11 @@ str_sub_s(str, pat, val, once)
if (offset >= STRLEN(str)) break;
}
if (n == 0) return Qnil;
- str_cat(result, str->ptr+offset, str->len-offset);
+ if (str->len > offset) {
+ str_cat(result, str->ptr+offset, str->len-offset);
+ }
+ if (str_tainted(val)) str_taint(result);
return result;
}
@@ -762,11 +838,15 @@ str_sub_f(str, pat, val, once)
VALUE val;
int once;
{
- VALUE result = str_sub_s(str, pat, val, once);
+ VALUE result;
+
+ str_modify(str);
+ result = str_sub_s(str, pat, val, once);
if (NIL_P(result)) return Qnil;
str_resize(str, RSTRING(result)->len);
memcpy(str->ptr, RSTRING(result)->ptr, RSTRING(result)->len);
+ if (str_tainted(result)) str_taint(str);
return (VALUE)str;
}
@@ -785,7 +865,6 @@ str_sub_iter_s(str, pat, once)
ArgError("Wrong # of arguments(1 for 2)");
}
- str_modify(str);
switch (TYPE(pat)) {
case T_REGEXP:
break;
@@ -827,7 +906,9 @@ str_sub_iter_s(str, pat, once)
if (offset >= STRLEN(str)) break;
}
if (n == 0) return Qnil;
- str_cat(result, str->ptr+offset, str->len-offset);
+ if (str->len > offset) {
+ str_cat(result, str->ptr+offset, str->len-offset);
+ }
return result;
}
@@ -838,7 +919,10 @@ str_sub_iter_f(str, pat, once)
VALUE pat;
int once;
{
- VALUE result = str_sub_iter_s(str, pat, once);
+ VALUE result;
+
+ str_modify(str);
+ result = str_sub_iter_s(str, pat, once);
if (NIL_P(result)) return Qnil;
str_resize(str, RSTRING(result)->len);
@@ -989,14 +1073,25 @@ str_gsub(argc, argv, str)
}
static VALUE
+uscore_get()
+{
+ VALUE line;
+
+ line = lastline_get();
+ if (TYPE(line) != T_STRING) {
+ TypeError("$_ value need to be String");
+ }
+ return line;
+}
+
+static VALUE
f_sub_bang(argc, argv)
int argc;
VALUE *argv;
{
VALUE pat, val, line;
- line = lastline_get();
- Check_Type(line, T_STRING);
+ line = uscore_get();
if (rb_scan_args(argc, argv, "11", &pat, &val) == 1) {
return str_sub_iter_f(line, pat, 1);
}
@@ -1010,8 +1105,7 @@ f_sub(argc, argv)
{
VALUE pat, val, line, v;
- line = lastline_get();
- Check_Type(line, T_STRING);
+ line = uscore_get();
if (rb_scan_args(argc, argv, "11", &pat, &val) == 1) {
v = str_sub_iter_s(line, pat, 1);
}
@@ -1032,8 +1126,7 @@ f_gsub_bang(argc, argv)
{
VALUE pat, val, line;
- line = lastline_get();
- Check_Type(line, T_STRING);
+ line = uscore_get();
if (rb_scan_args(argc, argv, "11", &pat, &val) == 1) {
return str_sub_iter_f(line, pat, 0);
}
@@ -1047,8 +1140,7 @@ f_gsub(argc, argv)
{
VALUE pat, val, line, v;
- line = lastline_get();
- Check_Type(line, T_STRING);
+ line = uscore_get();
if (rb_scan_args(argc, argv, "11", &pat, &val) == 1) {
v = str_sub_iter_s(line, pat, 0);
}
@@ -1066,7 +1158,7 @@ static VALUE
str_reverse_bang(str)
struct RString *str;
{
- char *s, *e, *p;
+ UCHAR *s, *e, *p;
s = str->ptr;
e = s + str->len - 1;
@@ -1085,7 +1177,7 @@ str_reverse(str)
struct RString *str;
{
VALUE obj = str_new(0, str->len);
- char *s, *e, *p;
+ UCHAR *s, *e, *p;
s = str->ptr; e = s + str->len - 1;
p = RSTRING(obj)->ptr;
@@ -1104,11 +1196,14 @@ str_to_i(str)
return str2inum(str->ptr, 10);
}
+#ifndef atof
+double atof();
+#endif
+
static VALUE
str_to_f(str)
struct RString *str;
{
- double atof();
double f = atof(str->ptr);
return float_new(f);
@@ -1121,15 +1216,14 @@ str_to_s(str)
return str;
}
-static VALUE
+VALUE
str_inspect(str)
struct RString *str;
{
#define STRMAX 80
- char buf[STRMAX];
- char *p, *pend;
- char *b;
- int offset;
+ UCHAR buf[STRMAX];
+ UCHAR *p, *pend;
+ UCHAR *b;
p = str->ptr; pend = p + str->len;
b = buf;
@@ -1144,7 +1238,7 @@ str_inspect(str)
}
while (p < pend) {
- unsigned char c = *p++;
+ UCHAR c = *p++;
if (ismbchar(c) && p < pend) {
CHECK(2);
*b++ = c;
@@ -1214,7 +1308,7 @@ static VALUE
str_upcase_bang(str)
struct RString *str;
{
- char *s, *send;
+ UCHAR *s, *send;
str_modify(str);
s = str->ptr; send = s + str->len;
@@ -1222,7 +1316,7 @@ str_upcase_bang(str)
if (islower(*s)) {
*s = toupper(*s);
}
- *s++;
+ s++;
}
return (VALUE)str;
@@ -1239,7 +1333,7 @@ static VALUE
str_downcase_bang(str)
struct RString *str;
{
- char *s, *send;
+ UCHAR *s, *send;
str_modify(str);
s = str->ptr; send = s + str->len;
@@ -1247,7 +1341,7 @@ str_downcase_bang(str)
if (isupper(*s)) {
*s = tolower(*s);
}
- *s++;
+ s++;
}
return (VALUE)str;
@@ -1264,7 +1358,7 @@ static VALUE
str_capitalize_bang(str)
struct RString *str;
{
- char *s, *send;
+ UCHAR *s, *send;
str_modify(str);
s = str->ptr; send = s + str->len;
@@ -1289,7 +1383,7 @@ static VALUE
str_swapcase_bang(str)
struct RString *str;
{
- char *s, *send;
+ UCHAR *s, *send;
str_modify(str);
s = str->ptr; send = s + str->len;
@@ -1300,7 +1394,7 @@ str_swapcase_bang(str)
else if (islower(*s)) {
*s = toupper(*s);
}
- *s++;
+ s++;
}
return (VALUE)str;
@@ -1313,11 +1407,11 @@ str_swapcase(str)
return str_swapcase_bang(str_dup(str));
}
-typedef unsigned char *USTR;
+typedef UCHAR *USTR;
-struct tr {
+static struct tr {
int gen, now, max;
- char *p, *pend;
+ UCHAR *p, *pend;
} trsrc, trrepl;
static int
@@ -1360,9 +1454,9 @@ tr_trans(str, src, repl, sflag)
{
struct tr trsrc, trrepl;
int cflag = 0;
- char trans[256];
+ UCHAR trans[256];
int i, c, c0;
- char *s, *send, *t;
+ UCHAR *s, *send, *t;
Check_Type(src, T_STRING);
trsrc.p = src->ptr; trsrc.pend = trsrc.p + src->len;
@@ -1453,7 +1547,7 @@ str_tr(str, src, repl)
static void
tr_setup_table(str, table)
struct RString *str;
- char table[256];
+ UCHAR table[256];
{
struct tr tr;
int i, cflag = 0;
@@ -1478,8 +1572,8 @@ static VALUE
str_delete_bang(str1, str2)
struct RString *str1, *str2;
{
- char *s, *send, *t;
- char squeez[256];
+ UCHAR *s, *send, *t;
+ UCHAR squeez[256];
Check_Type(str2, T_STRING);
tr_setup_table(str2, squeez);
@@ -1511,8 +1605,8 @@ static VALUE
tr_squeeze(str1, str2)
struct RString *str1, *str2;
{
- char squeez[256];
- char *s, *send, *t;
+ UCHAR squeez[256];
+ UCHAR *s, *send, *t;
char c, save;
if (str2) {
@@ -1600,6 +1694,8 @@ str_split_method(argc, argv, str)
rb_scan_args(argc, argv, "02", &spat, &limit);
if (!NIL_P(limit)) {
lim = NUM2INT(limit);
+ if (lim == 0) limit = Qnil;
+ else if (lim == 1) return ary_new3(1, str);
i = 1;
}
@@ -1631,9 +1727,9 @@ str_split_method(argc, argv, str)
result = ary_new();
beg = 0;
if (char_sep != 0) {
- char *ptr = str->ptr;
+ UCHAR *ptr = str->ptr;
int len = str->len;
- char *eptr = ptr + len;
+ UCHAR *eptr = ptr + len;
if (char_sep == ' ') { /* AWK emulation */
int skip = 1;
@@ -1651,9 +1747,9 @@ str_split_method(argc, argv, str)
else {
if (isspace(*ptr)) {
ary_push(result, str_substr(str, beg, end-beg));
- if (!NIL_P(limit) && lim <= ++i) break;
skip = 1;
beg = end + 1;
+ if (!NIL_P(limit) && lim <= ++i) break;
}
else {
end++;
@@ -1665,8 +1761,8 @@ str_split_method(argc, argv, str)
for (end = beg = 0; ptr<eptr; ptr++) {
if (*ptr == char_sep) {
ary_push(result, str_substr(str, beg, end-beg));
- if (!NIL_P(limit) && lim <= ++i) break;
beg = end + 1;
+ if (!NIL_P(limit) && lim <= ++i) break;
}
end++;
}
@@ -1687,7 +1783,6 @@ str_split_method(argc, argv, str)
else
ary_push(result, str_substr(str, beg, 1));
beg = start;
- if (!NIL_P(limit) && lim <= ++i) break;
}
else {
start += ismbchar(str->ptr[start])?2:1;
@@ -1736,11 +1831,7 @@ f_split(argc, argv)
int argc;
VALUE *argv;
{
- VALUE line;
-
- line = lastline_get();
- Check_Type(line, T_STRING);
- return str_split_method(argc, argv, line);
+ return str_split_method(argc, argv, uscore_get());
}
static VALUE
@@ -1753,8 +1844,8 @@ str_each_line(argc, argv, str)
VALUE rs;
int newline;
int rslen;
- char *p = str->ptr, *pend = p + str->len, *s;
- char *ptr = p;
+ UCHAR *p = str->ptr, *pend = p + str->len, *s;
+ UCHAR *ptr = p;
int len = str->len;
VALUE line;
@@ -1824,11 +1915,12 @@ str_chop_bang(str)
str_modify(str);
str->len--;
- str->ptr[str->len] = '\0';
- if (str->len > 1 && str->ptr[str->len-1] == '\r') {
- str->len--;
- str->ptr[str->len] = '\0';
+ if (str->ptr[str->len] == '\n') {
+ if (str->len > 0 && str->ptr[str->len-1] == '\r') {
+ str->len--;
+ }
}
+ str->ptr[str->len] = '\0';
return (VALUE)str;
}
@@ -1844,28 +1936,20 @@ static VALUE
f_chop_bang(str)
struct RString *str;
{
- VALUE line;
-
- line = lastline_get();
- Check_Type(line, T_STRING);
- return str_chop_bang(line);
+ return str_chop_bang(uscore_get());
}
static VALUE
f_chop()
{
- VALUE line;
-
- line = lastline_get();
- Check_Type(line, T_STRING);
- return str_chop_bang(str_dup(line));
+ return str_chop_bang(str_dup(uscore_get()));
}
static VALUE
str_strip_bang(str)
struct RString *str;
{
- char *s, *t, *e;
+ UCHAR *s, *t, *e;
str_modify(str);
@@ -1881,7 +1965,7 @@ str_strip_bang(str)
str->len = t-s;
if (s > str->ptr) {
- char *p = str->ptr;
+ UCHAR *p = str->ptr;
str->ptr = ALLOC_N(char, str->len+1);
memcpy(str->ptr, s, str->len);
@@ -1994,10 +2078,12 @@ static VALUE
str_intern(str)
struct RString *str;
{
+ ID id;
+
if (strlen(str->ptr) != str->len)
ArgError("string contains `\0'");
-
- return rb_intern(str->ptr)|FIXNUM_FLAG;
+ id = rb_intern(str->ptr);
+ return INT2FIX(id);
}
static VALUE
@@ -2008,7 +2094,7 @@ str_sum(argc, argv, str)
{
VALUE vbits;
int bits;
- char *p, *pend;
+ UCHAR *p, *pend;
rb_scan_args(argc, argv, "01", &vbits);
if (NIL_P(vbits)) bits = 16;
@@ -2042,14 +2128,14 @@ str_sum(argc, argv, str)
}
}
-VALUE
+static VALUE
str_ljust(str, w)
struct RString *str;
VALUE w;
{
int width = NUM2INT(w);
struct RString *res;
- char *p, *pend;
+ UCHAR *p, *pend;
if (str->len >= width) return (VALUE)str;
res = (struct RString*)str_new(0, width);
@@ -2061,14 +2147,14 @@ str_ljust(str, w)
return (VALUE)res;
}
-VALUE
+static VALUE
str_rjust(str, w)
struct RString *str;
VALUE w;
{
int width = NUM2INT(w);
struct RString *res;
- char *p, *pend;
+ UCHAR *p, *pend;
if (str->len >= width) return (VALUE)str;
res = (struct RString*)str_new(0, width);
@@ -2080,14 +2166,14 @@ str_rjust(str, w)
return (VALUE)res;
}
-VALUE
+static VALUE
str_center(str, w)
struct RString *str;
VALUE w;
{
int width = NUM2INT(w);
struct RString *res;
- char *p, *pend;
+ UCHAR *p, *pend;
int n;
if (str->len >= width) return (VALUE)str;
@@ -2105,7 +2191,7 @@ str_center(str, w)
return (VALUE)res;
}
-extern VALUE cKernel;
+extern VALUE mKernel;
extern VALUE mComparable;
extern VALUE mEnumerable;
@@ -2121,6 +2207,7 @@ Init_String()
rb_define_method(cString, "<=>", str_cmp_method, 1);
rb_define_method(cString, "==", str_equal, 1);
rb_define_method(cString, "===", str_equal, 1);
+ rb_define_method(cString, "eql?", str_equal, 1);
rb_define_method(cString, "hash", str_hash_method, 0);
rb_define_method(cString, "+", str_plus, 1);
rb_define_method(cString, "*", str_times, 1);
@@ -2136,7 +2223,10 @@ Init_String()
rb_define_method(cString, "rindex", str_rindex, -1);
rb_define_method(cString, "freeze", str_freeze, 0);
- rb_define_method(cString, "frozen?", str_frozen, 0);
+ rb_define_method(cString, "frozen?", str_frozen_p, 0);
+
+ rb_define_method(cString, "taint", str_taint, 0);
+ rb_define_method(cString, "tainted?", str_tainted, 0);
rb_define_method(cString, "to_i", str_to_i, 0);
rb_define_method(cString, "to_f", str_to_f, 0);
@@ -2159,6 +2249,7 @@ Init_String()
rb_define_method(cString, "reverse", str_reverse, 0);
rb_define_method(cString, "reverse!", str_reverse_bang, 0);
rb_define_method(cString, "concat", str_concat, 1);
+ rb_define_method(cString, "<<", str_concat, 1);
rb_define_method(cString, "crypt", str_crypt, 1);
rb_define_method(cString, "intern", str_intern, 0);
@@ -2194,16 +2285,16 @@ Init_String()
rb_define_method(cString, "sum", str_sum, -1);
- rb_define_private_method(cKernel, "sub", f_sub, -1);
- rb_define_private_method(cKernel, "gsub", f_gsub, -1);
+ rb_define_global_function("sub", f_sub, -1);
+ rb_define_global_function("gsub", f_gsub, -1);
- rb_define_private_method(cKernel, "sub!", f_sub_bang, -1);
- rb_define_private_method(cKernel, "gsub!", f_gsub_bang, -1);
+ rb_define_global_function("sub!", f_sub_bang, -1);
+ rb_define_global_function("gsub!", f_gsub_bang, -1);
- rb_define_private_method(cKernel, "chop", f_chop, 0);
- rb_define_private_method(cKernel, "chop!", f_chop_bang, 0);
+ rb_define_global_function("chop", f_chop, 0);
+ rb_define_global_function("chop!", f_chop_bang, 0);
- rb_define_private_method(cKernel, "split", f_split, -1);
+ rb_define_global_function("split", f_split, -1);
pr_str = rb_intern("to_s");
}
diff --git a/struct.c b/struct.c
index e9980d145b..ae1abc581f 100644
--- a/struct.c
+++ b/struct.c
@@ -21,7 +21,7 @@ struct_s_members(obj)
struct RArray *member;
VALUE ary, *p, *pend;
- member = RARRAY(rb_ivar_get(obj, rb_intern("__member__")));
+ member = RARRAY(rb_iv_get(obj, "__member__"));
if (NIL_P(member)) {
Fatal("non-initialized struct");
}
@@ -42,28 +42,36 @@ struct_members(obj)
return struct_s_members(CLASS_OF(obj));
}
-static VALUE
-struct_ref(obj)
+VALUE
+struct_getmember(obj, id)
struct RStruct *obj;
+ ID id;
{
VALUE nstr, member, slot;
int i;
nstr = CLASS_OF(obj);
- member = rb_ivar_get(nstr, rb_intern("__member__"));
+ member = rb_iv_get(nstr, "__member__");
if (NIL_P(member)) {
- Fatal("non-initialized struct");
+ Bug("non-initialized struct");
}
- slot = INT2FIX(rb_frame_last_func());
+ slot = INT2FIX(id);
for (i=0; i<RARRAY(member)->len; i++) {
if (RARRAY(member)->ptr[i] == slot) {
return obj->ptr[i];
}
}
- NameError("not struct member");
+ NameError("%s is not struct member", rb_id2name(id));
/* not reached */
}
+static VALUE
+struct_ref(obj)
+ VALUE obj;
+{
+ return struct_getmember(obj, rb_frame_last_func());
+}
+
static VALUE struct_ref0(obj) struct RStruct *obj; {return obj->ptr[0];}
static VALUE struct_ref1(obj) struct RStruct *obj; {return obj->ptr[1];}
static VALUE struct_ref2(obj) struct RStruct *obj; {return obj->ptr[2];}
@@ -97,7 +105,7 @@ struct_set(obj, val)
int i;
nstr = CLASS_OF(obj);
- member = rb_ivar_get(nstr, rb_intern("__member__"));
+ member = rb_iv_get(nstr, "__member__");
if (NIL_P(member)) {
Fatal("non-initialized struct");
}
@@ -119,13 +127,19 @@ make_struct(name, member)
struct RArray *member;
{
VALUE nstr;
+ ID id;
int i;
+ id = rb_intern(name->ptr);
+ if (!rb_is_const_id(id)) {
+ NameError("identifier %s needs to be constant", name->ptr);
+ }
nstr = rb_define_class_under(cStruct, name->ptr, cStruct);
- rb_ivar_set(nstr, rb_intern("__size__"), INT2FIX(member->len));
- rb_ivar_set(nstr, rb_intern("__member__"), member);
+ rb_iv_set(nstr, "__size__", INT2FIX(member->len));
+ rb_iv_set(nstr, "__member__", member);
rb_define_singleton_method(nstr, "new", struct_alloc, -2);
+ rb_define_singleton_method(nstr, "[]", struct_alloc, -2);
rb_define_singleton_method(nstr, "members", struct_s_members, 0);
for (i=0; i< member->len; i++) {
ID id = FIX2INT(member->ptr[i]);
@@ -172,7 +186,6 @@ struct_s_def(argc, argv)
{
struct RString *name;
struct RArray *rest;
- VALUE nstr;
int i;
rb_scan_args(argc, argv, "1*", &name, &rest);
@@ -192,7 +205,7 @@ struct_alloc(class, values)
VALUE size;
int n;
- size = rb_ivar_get(class, rb_intern("__size__"));
+ size = rb_iv_get(class, "__size__");
n = FIX2INT(size);
if (n < values->len) {
ArgError("struct size differs");
@@ -201,6 +214,7 @@ struct_alloc(class, values)
NEWOBJ(st, struct RStruct);
OBJSETUP(st, class, T_STRUCT);
st->len = n;
+ st->ptr = 0; /* avoid GC crashing */
st->ptr = ALLOC_N(VALUE, n);
MEMCPY(st->ptr, values->ptr, VALUE, values->len);
memclear(st->ptr+values->len, n - values->len);
@@ -219,7 +233,7 @@ struct_new(class, va_alist)
int size;
va_list args;
- val = rb_ivar_get(class, rb_intern("__size__"));
+ val = rb_iv_get(class, "__size__");
size = FIX2INT(val);
mem = ary_new();
va_start(args);
@@ -245,7 +259,6 @@ struct_each(s)
}
char *rb_class2name();
-#define HDR "struct "
static VALUE
struct_to_s(s)
@@ -254,8 +267,8 @@ struct_to_s(s)
char *name, *buf;
name = rb_class2name(CLASS_OF(s));
- buf = ALLOCA_N(char, strlen(name)+sizeof(HDR)+1);
- sprintf(buf, "%s%s", HDR, name);
+ buf = ALLOCA_N(char, strlen(name)+1);
+ sprintf(buf, "%s", name);
return str_new2(buf);
}
@@ -268,12 +281,12 @@ struct_inspect(s)
char buf[256];
int i;
- member = rb_ivar_get(CLASS_OF(s), rb_intern("__member__"));
+ member = rb_iv_get(CLASS_OF(s), "__member__");
if (NIL_P(member)) {
Fatal("non-initialized struct");
}
- sprintf(buf, "#<%s%s: ", HDR, name);
+ sprintf(buf, "#<%s ", name);
str = str_new2(buf);
for (i=0; i<s->len; i++) {
VALUE str2, slot;
@@ -309,6 +322,7 @@ struct_clone(s)
NEWOBJ(st, struct RStruct);
CLONESETUP(st, s);
st->len = s->len;
+ st->ptr = 0; /* avoid GC crashing */
st->ptr = ALLOC_N(VALUE, s->len);
MEMCPY(st->ptr, s->ptr, VALUE, st->len);
@@ -366,15 +380,32 @@ struct_equal(s, s2)
}
static VALUE
+struct_eql(s, s2)
+ struct RStruct *s, *s2;
+{
+ int i;
+
+ if (TYPE(s2) != T_STRUCT) return FALSE;
+ if (CLASS_OF(s) != CLASS_OF(s2)) return FALSE;
+ if (s->len != s2->len) {
+ Bug("inconsistent struct"); /* should never happen */
+ }
+
+ for (i=0; i<s->len; i++) {
+ if (!rb_eql(s->ptr[i], s2->ptr[i])) return FALSE;
+ }
+ return TRUE;
+}
+
+static VALUE
struct_hash(s)
struct RStruct *s;
{
int i, h;
- ID hash = rb_intern("hash");
h = CLASS_OF(s);
for (i=0; i<s->len; i++) {
- h ^= rb_funcall(s->ptr[i], hash, 0);
+ h ^= rb_hash(s->ptr[i]);
}
return INT2FIX(h);
}
@@ -386,11 +417,11 @@ Init_Struct()
rb_include_module(cStruct, mEnumerable);
rb_define_singleton_method(cStruct, "new", struct_s_def, -1);
- rb_define_singleton_method(cStruct, "members", struct_s_members, 0);
rb_define_method(cStruct, "clone", struct_clone, 0);
rb_define_method(cStruct, "==", struct_equal, 1);
+ rb_define_method(cStruct, "eql?", struct_eql, 1);
rb_define_method(cStruct, "hash", struct_hash, 0);
rb_define_method(cStruct, "to_s", struct_to_s, 0);
diff --git a/time.c b/time.c
index 17e5497b22..51e2a0f548 100644
--- a/time.c
+++ b/time.c
@@ -13,7 +13,12 @@
#include "ruby.h"
#include <sys/types.h>
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+
#include <time.h>
+#ifndef NT
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#else
@@ -22,6 +27,7 @@ struct timeval {
long tv_usec; /* and microseconds */
};
#endif
+#endif /* NT */
#ifdef HAVE_SYS_TIMES_H
#include <sys/times.h>
@@ -44,7 +50,7 @@ struct time_object {
};
#define GetTimeval(obj, tobj) {\
- Get_Data_Struct(obj, struct time_object, tobj);\
+ Data_Get_Struct(obj, struct time_object, tobj);\
}
static VALUE
@@ -54,7 +60,7 @@ time_s_now(class)
VALUE obj;
struct time_object *tobj;
- obj = Make_Data_Struct(class, struct time_object, 0, 0, tobj);
+ obj = Data_Make_Struct(class, struct time_object, 0, 0, tobj);
tobj->tm_got=0;
if (gettimeofday(&(tobj->tv), 0) == -1) {
@@ -72,8 +78,8 @@ time_new_internal(class, sec, usec)
VALUE obj;
struct time_object *tobj;
- obj = Make_Data_Struct(class, struct time_object, 0, 0, tobj);
- tobj->tm_got=0;
+ obj = Data_Make_Struct(class, struct time_object, 0, 0, tobj);
+ tobj->tm_got = 0;
tobj->tv.tv_sec = sec;
tobj->tv.tv_usec = usec;
@@ -172,9 +178,16 @@ time_arg(argc, argv, args)
break;
}
}
+ if (args[1] == -1) {
+ char c = RSTRING(v[1])->ptr[0];
+
+ if ('0' <= c && c <= '9') {
+ args[1] = NUM2INT(v[1])-1;
+ }
+ }
}
else {
- args[1] = NUM2INT(v[1]) - 1;
+ args[1] = NUM2INT(v[1]);
}
if (v[2] == Qnil) {
args[2] = 1;
@@ -338,6 +351,22 @@ time_cmp(time1, time2)
}
static VALUE
+time_eql(time1, time2)
+ VALUE time1, time2;
+{
+ struct time_object *tobj1, *tobj2;
+
+ GetTimeval(time1, tobj1);
+ if (obj_is_instance_of(time2, cTime)) {
+ GetTimeval(time2, tobj2);
+ if (tobj1->tv.tv_sec == tobj2->tv.tv_sec) {
+ if (tobj1->tv.tv_usec == tobj2->tv.tv_usec) return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static VALUE
time_hash(time)
VALUE time;
{
@@ -357,7 +386,7 @@ time_localtime(time)
struct tm *tm_tmp;
GetTimeval(time, tobj);
- tm_tmp = localtime(&tobj->tv.tv_sec);
+ tm_tmp = localtime((const time_t*)&tobj->tv.tv_sec);
tobj->tm = *tm_tmp;
tobj->tm_got = 1;
#ifndef HAVE_TM_ZONE
@@ -374,7 +403,7 @@ time_gmtime(time)
struct tm *tm_tmp;
GetTimeval(time, tobj);
- tm_tmp = gmtime(&tobj->tv.tv_sec);
+ tm_tmp = gmtime((const time_t*)&tobj->tv.tv_sec);
tobj->tm = *tm_tmp;
tobj->tm_got = 1;
#ifndef HAVE_TM_ZONE
@@ -388,7 +417,7 @@ time_asctime(time)
VALUE time;
{
struct time_object *tobj;
- char buf[32];
+ char buf[64];
int len;
GetTimeval(time, tobj);
@@ -396,12 +425,13 @@ time_asctime(time)
time_localtime(time);
}
#ifndef HAVE_TM_ZONE
- if (tobj->gmt == 1)
- len = strftime(buf, 32, "%a %b %d %H:%M:%S GMT %Y", &(tobj->tm));
+ if (tobj->gmt == 1) {
+ len = strftime(buf, 64, "%a %b %d %H:%M:%S GMT %Y", &(tobj->tm));
+ }
else
#endif
{
- len = strftime(buf, 32, "%a %b %d %H:%M:%S %Z %Y", &(tobj->tm));
+ len = strftime(buf, 64, "%a %b %d %H:%M:%S %Z %Y", &(tobj->tm));
}
return str_new(buf, len);
}
@@ -429,8 +459,9 @@ time_plus(time1, time2)
GetTimeval(time1, tobj1);
if (TYPE(time2) == T_FLOAT) {
- sec = tobj1->tv.tv_sec + (unsigned int)RFLOAT(time2)->value;
- usec = tobj1->tv.tv_usec + (RFLOAT(time2)->value - (double)sec)*1e6;
+ unsigned int nsec = (unsigned int)RFLOAT(time2)->value;
+ sec = tobj1->tv.tv_sec + nsec;
+ usec = tobj1->tv.tv_usec + (RFLOAT(time2)->value - (double)nsec)*1e6;
}
else if (obj_is_instance_of(time2, cTime)) {
GetTimeval(time2, tobj2);
@@ -725,6 +756,7 @@ Init_Time()
rb_define_method(cTime, "to_i", time_to_i, 0);
rb_define_method(cTime, "to_f", time_to_f, 0);
rb_define_method(cTime, "<=>", time_cmp, 1);
+ rb_define_method(cTime, "eql?", time_eql, 0);
rb_define_method(cTime, "hash", time_hash, 0);
rb_define_method(cTime, "localtime", time_localtime, 0);
diff --git a/top.sed b/top.sed
index 371190875a..f8d56fcf54 100644
--- a/top.sed
+++ b/top.sed
@@ -1,7 +1,10 @@
+/^SHELL/s,/bin/sh,$(COMPSEC),
s/@srcdir@/./
s/@CC@/gcc/
s/@CPP@/gcc -E/
s/@CPPFLAGS@//
+s/@AR@/ar/
+s/@RANLIB@/ranlib/
s/@YACC@/bison -y/
s/@INSTALL@/ginstall -c/
s/@INSTALL_PROGRAM@/${INSTALL}/
@@ -11,20 +14,31 @@ s/@CFLAGS@/-g -O -I./
s/@STATIC@//
s/@LDFLAGS@//
s/@LIBS@//
-s/@LIBOBJS@/crypt.o/
+s/@LIBOBJS@/crypt.o flock.o/
s/@ALLOCA@//
s!@prefix@!/usr/local!
s/@exec_prefix@/${prefix}/
+s!@bindir@!${exec_prefix}/bin!
+s!@libdir@!${exec_prefix}/lib!
s/@STRIP@/strip/
s!/bin/rm!rm!
-s/@LDEXT@/so/
+s/@DLEXT@/o/
s/@CCDLFLAGS@/-fpic/
-s!@arclib@!/usr/local/lib/ruby/i386-msdos!
-/\/dev\/null/s,/dev/null 2>&1, nul,
-/if older/s/"ruby"/"ruby.exe"/g
-/`rm -f ruby`/s//`rm -f ruby.exe`/
-/`cp miniruby ruby`/s//`cp miniruby.exe ruby.exe`/
-/^extruby:/ {
+s/@DLDFLAGS@//
+s/@LDSHARED@//
+s/@binsuffix@/.exe/g
+s/@setup@/Setup/g
+s/|| true//
+s!@archlib@!/usr/local/lib/ruby/i386-djgpp!
+/\/dev\/null/ {
+s,/dev/null 2>&1, nul,
+s,2> /dev/null,,
+}
+s/y\.tab\.c/y_tab.c/
+#/if older/s/"ruby"/"ruby.exe"/g
+#/`rm -f ruby`/s//`rm -f ruby.exe`/
+#/`cp miniruby ruby`/s//`cp miniruby.exe ruby.exe`/
+/^all:.*miniruby/ {
n;N;N;N;c\
cd ext\
../miniruby ./extmk.rb\
diff --git a/util.c b/util.c
index 717e0beed9..8e822631ed 100644
--- a/util.c
+++ b/util.c
@@ -10,8 +10,7 @@
************************************************/
-#include "defines.h"
-#include "config.h"
+#include "ruby.h"
#include "util.h"
#ifdef HAVE_STRING_H
# include <string.h>
@@ -55,3 +54,405 @@ int *retlen;
*retlen = s - start;
return retval;
}
+
+#if defined(MSDOS) || defined(__CYGWIN32__) || defined(NT)
+#include <fcntl.h>
+/*
+ * Copyright (c) 1993, Intergraph Corporation
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the perl README file.
+ *
+ * Various Unix compatibility functions and NT specific functions.
+ *
+ * Some of this code was derived from the MSDOS port(s) and the OS/2 port.
+ *
+ */
+
+
+/*
+ * Suffix appending for in-place editing under MS-DOS and OS/2 (and now NT!).
+ *
+ * Here are the rules:
+ *
+ * Style 0: Append the suffix exactly as standard perl would do it.
+ * If the filesystem groks it, use it. (HPFS will always
+ * grok it. So will NTFS. FAT will rarely accept it.)
+ *
+ * Style 1: The suffix begins with a '.'. The extension is replaced.
+ * If the name matches the original name, use the fallback method.
+ *
+ * Style 2: The suffix is a single character, not a '.'. Try to add the
+ * suffix to the following places, using the first one that works.
+ * [1] Append to extension.
+ * [2] Append to filename,
+ * [3] Replace end of extension,
+ * [4] Replace end of filename.
+ * If the name matches the original name, use the fallback method.
+ *
+ * Style 3: Any other case: Ignore the suffix completely and use the
+ * fallback method.
+ *
+ * Fallback method: Change the extension to ".$$$". If that matches the
+ * original name, then change the extension to ".~~~".
+ *
+ * If filename is more than 1000 characters long, we die a horrible
+ * death. Sorry.
+ *
+ * The filename restriction is a cheat so that we can use buf[] to store
+ * assorted temporary goo.
+ *
+ * Examples, assuming style 0 failed.
+ *
+ * suffix = ".bak" (style 1)
+ * foo.bar => foo.bak
+ * foo.bak => foo.$$$ (fallback)
+ * foo.$$$ => foo.~~~ (fallback)
+ * makefile => makefile.bak
+ *
+ * suffix = "~" (style 2)
+ * foo.c => foo.c~
+ * foo.c~ => foo.c~~
+ * foo.c~~ => foo~.c~~
+ * foo~.c~~ => foo~~.c~~
+ * foo~~~~~.c~~ => foo~~~~~.$$$ (fallback)
+ *
+ * foo.pas => foo~.pas
+ * makefile => makefile.~
+ * longname.fil => longname.fi~
+ * longname.fi~ => longnam~.fi~
+ * longnam~.fi~ => longnam~.$$$
+ *
+ */
+
+
+static int valid_filename(char *s);
+
+static char suffix1[] = ".$$$";
+static char suffix2[] = ".~~~";
+
+#define ext (&buf[1000])
+
+#define strEQ(s1,s2) (strcmp(s1,s2) == 0)
+
+void
+add_suffix(struct RString *str, char *suffix)
+{
+ int baselen;
+ int extlen = strlen(suffix);
+ char *s, *t, *p;
+ int slen;
+ char buf[1024];
+
+ if (str->len > 1000)
+ Fatal("Cannot do inplace edit on long filename (%d characters)", str->len);
+
+#if defined(DJGPP) || defined(__CYGWIN32__) || defined(NT)
+ /* Style 0 */
+ slen = str->len;
+ str_cat(str, suffix, extlen);
+#if defined(DJGPP)
+ if (_USE_LFN) return;
+#else
+ if (valid_filename(str->ptr)) return;
+#endif
+
+ /* Fooey, style 0 failed. Fix str before continuing. */
+ str->ptr[str->len = slen] = '\0';
+#endif
+
+ slen = extlen;
+ t = buf; baselen = 0; s = str->ptr;
+ while ( (*t = *s) && *s != '.') {
+ baselen++;
+ if (*s == '\\' || *s == '/') baselen = 0;
+ s++; t++;
+ }
+ p = t;
+
+ t = ext; extlen = 0;
+ while (*t++ = *s++) extlen++;
+ if (extlen == 0) { ext[0] = '.'; ext[1] = 0; extlen++; }
+
+ if (*suffix == '.') { /* Style 1 */
+ if (strEQ(ext, suffix)) goto fallback;
+ strcpy(p, suffix);
+ } else if (suffix[1] == '\0') { /* Style 2 */
+ if (extlen < 4) {
+ ext[extlen] = *suffix;
+ ext[++extlen] = '\0';
+ } else if (baselen < 8) {
+ *p++ = *suffix;
+ } else if (ext[3] != *suffix) {
+ ext[3] = *suffix;
+ } else if (buf[7] != *suffix) {
+ buf[7] = *suffix;
+ } else goto fallback;
+ strcpy(p, ext);
+ } else { /* Style 3: Panic */
+fallback:
+ (void)memcpy(p, strEQ(ext, suffix1) ? suffix2 : suffix1, 5);
+ }
+ str_resize(str, strlen(buf));
+ memcpy(str->ptr, buf, str->len);
+}
+
+#if defined(__CYGWIN32__) || defined(NT)
+static int
+valid_filename(char *s)
+{
+ int fd;
+
+ /*
+ // if the file exists, then it's a valid filename!
+ */
+
+ if (_access(s, 0) == 0) {
+ return 1;
+ }
+
+ /*
+ // It doesn't exist, so see if we can open it.
+ */
+
+ if ((fd = _open(s, O_CREAT, 0666)) >= 0) {
+ _close(fd);
+ _unlink (s); /* don't leave it laying around */
+ return 1;
+ }
+ return 0;
+}
+#endif
+#endif
+
+#ifdef DJGPP
+/* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
+/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
+#include <libc/stubs.h>
+#include <stdio.h> /* For FILENAME_MAX */
+#include <errno.h> /* For errno */
+#include <ctype.h> /* For tolower */
+#include <string.h> /* For strlen() */
+#include <fcntl.h> /* For LFN stuff */
+#include <go32.h>
+#include <dpmi.h> /* For dpmisim */
+#include <crt0.h> /* For crt0 flags */
+#include <sys/stat.h>
+#include <libc/dosio.h>
+
+static unsigned use_lfn;
+
+static char *__get_current_directory(char *out, int drive_number);
+
+static char *
+__get_current_directory(char *out, int drive_number)
+{
+ __dpmi_regs r;
+ char tmpbuf[FILENAME_MAX];
+
+ memset(&r, 0, sizeof(r));
+ if(use_lfn)
+ r.x.ax = 0x7147;
+ else
+ r.h.ah = 0x47;
+ r.h.dl = drive_number + 1;
+ r.x.si = __tb_offset;
+ r.x.ds = __tb_segment;
+ __dpmi_int(0x21, &r);
+
+ if (r.x.flags & 1)
+ {
+ errno = r.x.ax;
+ return out;
+ }
+ else
+ {
+ dosmemget(__tb, sizeof(tmpbuf), tmpbuf);
+ strcpy(out+1,tmpbuf);
+
+ /* Root path, don't insert "/", it'll be added later */
+ if (*(out + 1) != '\0')
+ *out = '/';
+ else
+ *out = '\0';
+ return out + strlen(out);
+ }
+}
+
+__inline__ static int
+is_slash(int c)
+{
+ return c == '/' || c == '\\';
+}
+
+__inline__ static int
+is_term(int c)
+{
+ return c == '/' || c == '\\' || c == '\0';
+}
+
+#ifdef SJIS
+__inline__ static int
+is_sjis1(int c)
+{
+ return 0x81 <= c && (c <= 0x9f || 0xe0 <= c);
+}
+#endif
+
+/* Takes as input an arbitrary path. Fixes up the path by:
+ 1. Removing consecutive slashes
+ 2. Removing trailing slashes
+ 3. Making the path absolute if it wasn't already
+ 4. Removing "." in the path
+ 5. Removing ".." entries in the path (and the directory above them)
+ 6. Adding a drive specification if one wasn't there
+ 7. Converting all slashes to '/'
+ */
+void
+_fixpath(const char *in, char *out)
+{
+ int drive_number;
+ const char *ip = in;
+ char *op = out;
+ int preserve_case = _preserve_fncase();
+ char *name_start;
+
+ use_lfn = _USE_LFN;
+
+ /* Add drive specification to output string */
+ if (((*ip >= 'a' && *ip <= 'z') ||
+ (*ip >= 'A' && *ip <= 'Z'))
+ && (*(ip + 1) == ':'))
+ {
+ if (*ip >= 'a' && *ip <= 'z')
+ {
+ drive_number = *ip - 'a';
+ *op++ = *ip++;
+ }
+ else
+ {
+ drive_number = *ip - 'A';
+ if (*ip <= 'Z')
+ *op++ = drive_number + 'a';
+ else
+ *op++ = *ip;
+ ++ip;
+ }
+ *op++ = *ip++;
+ }
+ else
+ {
+ __dpmi_regs r;
+ r.h.ah = 0x19;
+ __dpmi_int(0x21, &r);
+ drive_number = r.h.al;
+ *op++ = drive_number + (drive_number < 26 ? 'a' : 'A');
+ *op++ = ':';
+ }
+
+ /* Convert relative path to absolute */
+ if (!is_slash(*ip))
+ op = __get_current_directory(op, drive_number);
+
+ /* Step through the input path */
+ while (*ip)
+ {
+ /* Skip input slashes */
+ if (is_slash(*ip))
+ {
+ ip++;
+ continue;
+ }
+
+ /* Skip "." and output nothing */
+ if (*ip == '.' && is_term(*(ip + 1)))
+ {
+ ip++;
+ continue;
+ }
+
+ /* Skip ".." and remove previous output directory */
+ if (*ip == '.' && *(ip + 1) == '.' && is_term(*(ip + 2)))
+ {
+ ip += 2;
+ /* Don't back up over drive spec */
+ if (op > out + 2)
+ /* This requires "/" to follow drive spec */
+ while (!is_slash(*--op));
+ continue;
+ }
+
+ /* Copy path component from in to out */
+ *op++ = '/';
+#ifndef SJIS
+ while (!is_term(*ip)) *op++ = *ip++;
+#else
+ while (!is_term(*ip)) {
+ if (is_sjis1((unsigned char)*ip))
+ *op++ = *ip++;
+ *op++ = *ip++;
+ }
+#endif
+ }
+
+ /* If root directory, insert trailing slash */
+ if (op == out + 2) *op++ = '/';
+
+ /* Null terminate the output */
+ *op = '\0';
+
+ /* switch FOO\BAR to foo/bar, downcase where appropriate */
+ for (op = out + 3, name_start = op - 1; *name_start; op++)
+ {
+ char long_name[FILENAME_MAX], short_name[13];
+
+#ifdef SJIS
+ if (is_sjis1((unsigned char)*op)) {
+ op++;
+ continue;
+ }
+#endif
+ if (*op == '\\')
+ *op = '/';
+ if (!preserve_case && (*op == '/' || *op == '\0'))
+ {
+ memcpy(long_name, name_start+1, op - name_start - 1);
+ long_name[op - name_start - 1] = '\0';
+ if (!strcmp(_lfn_gen_short_fname(long_name, short_name), long_name))
+ {
+#ifndef SJIS
+ while (++name_start < op)
+ if (*name_start >= 'A' && *name_start <= 'Z')
+ *name_start += 'a' - 'A';
+#else
+ while (++name_start < op) {
+ if (is_sjis1((unsigned char)*name_start))
+ name_start++;
+ else if (*name_start >= 'A' && *name_start <= 'Z')
+ *name_start += 'a' - 'A';
+ }
+#endif
+ }
+ else
+ name_start = op;
+ }
+ else if (*op == '\0')
+ break;
+ }
+}
+
+#ifdef TEST
+
+int main (int argc, char *argv[])
+{
+ char fixed[FILENAME_MAX];
+ if (argc > 1)
+ {
+ _fixpath (argv[1], fixed);
+ printf ("You mean %s?\n", fixed);
+ }
+ return 0;
+}
+
+#endif
+#endif
diff --git a/variable.c b/variable.c
index 668385f18a..b0d67362c1 100644
--- a/variable.c
+++ b/variable.c
@@ -13,15 +13,18 @@
#include "node.h"
#include "st.h"
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+
static st_table *rb_global_tbl;
st_table *rb_class_tbl;
#define global_tbl rb_global_tbl
#define class_tbl rb_class_tbl
int rb_const_defined();
-VALUE rb_const_get();
-st_table *
+st_table*
new_idhash()
{
return st_init_numtable();
@@ -34,8 +37,96 @@ Init_var_tables()
class_tbl = new_idhash();
}
-char *
-rb_class2path(class)
+struct fc_result {
+ ID name;
+ VALUE class;
+ VALUE path;
+ VALUE track;
+ struct fc_result *prev;
+};
+
+extern VALUE cModule;
+
+static int
+fc_i(key, value, res)
+ ID key;
+ VALUE value;
+ struct fc_result *res;
+{
+ VALUE path;
+ char *name;
+
+ if (!rb_is_const_id(key)) return ST_CONTINUE;
+
+ name = rb_id2name(key);
+ if (res->path) {
+ path = str_dup(res->path);
+ str_cat(path, "::", 2);
+ str_cat(path, name, strlen(name));
+ }
+ else {
+ path = str_new2(name);
+ }
+ if (value == res->class) {
+ res->name = key;
+ res->path = path;
+ return ST_STOP;
+ }
+ if (obj_is_kind_of(value, cModule)) {
+ struct fc_result arg;
+ struct fc_result *list;
+
+
+ if (!RCLASS(value)->iv_tbl) return ST_CONTINUE;
+
+ list = res;
+ while (list) {
+ if (list->track == value) return ST_CONTINUE;
+ list = list->prev;
+ }
+
+ arg.name = 0;
+ arg.path = path;
+ arg.class = res->class;
+ arg.track = value;
+ arg.prev = res;
+ st_foreach(RCLASS(value)->iv_tbl, fc_i, &arg);
+ if (arg.name) {
+ res->name = arg.name;
+ res->path = arg.path;
+ return ST_STOP;
+ }
+ }
+ return ST_CONTINUE;
+}
+
+static VALUE
+find_class_path(class)
+ VALUE class;
+{
+ VALUE c;
+ struct fc_result arg;
+
+ arg.name = 0;
+ arg.path = 0;
+ arg.class = class;
+ arg.track = cObject;
+ arg.prev = 0;
+ if (RCLASS(cObject)->iv_tbl) {
+ st_foreach(RCLASS(cObject)->iv_tbl, fc_i, &arg);
+ }
+ if (arg.name == 0) {
+ st_foreach(class_tbl, fc_i, &arg);
+ }
+ if (arg.name) {
+ rb_iv_set(class, "__classpath__", arg.path);
+ return arg.path;
+ }
+ return Qnil;
+}
+
+static VALUE
+classname(class)
VALUE class;
{
VALUE path;
@@ -43,26 +134,39 @@ rb_class2path(class)
while (TYPE(class) == T_ICLASS || FL_TEST(class, FL_SINGLETON)) {
class = (VALUE)RCLASS(class)->super;
}
- path = rb_ivar_get(class, rb_intern("__classpath__"));
+ path = rb_iv_get(class, "__classpath__");
if (NIL_P(path)) {
- return rb_class2name(class);
+ path = rb_iv_get(class, "__classid__");
+ if (!NIL_P(path)) {
+ path = str_new2(rb_id2name(FIX2INT(path)));
+ }
+ }
+ if (NIL_P(path)) {
+ path = find_class_path(class);
+ if (NIL_P(path)) {
+ return 0;
+ }
+ return path;
}
- if (TYPE(path) != T_STRING) Bug("class path does not set properly");
- return RSTRING(path)->ptr;
+ if (TYPE(path) != T_STRING) Bug("class path is not set properly");
+ return path;
}
VALUE
rb_class_path(class)
VALUE class;
{
- char *name = rb_class2path(class);
+ VALUE path = classname(class);
- if (strchr(name, ':')) {
- VALUE ary = str_split(str_new2(name), ":");
- ary = ary_reverse(ary);
- return ary_join(ary, str_new2("::"));
+ if (path) return path;
+ else {
+ char buf[256];
+ char *s = "Class";
+
+ if (TYPE(class) == T_MODULE) s = "Module";
+ sprintf(buf, "#<%s 0x%x>", s, class);
+ return str_new2(buf);
}
- return str_new2(name);
}
void
@@ -73,55 +177,25 @@ rb_set_class_path(class, under, name)
VALUE str;
char *s;
- if (cObject == under) return;
- str = str_new2(name);
- if (under) {
- str_cat(str, ":", 1);
- s = rb_class2path(under);
- str_cat(str, s, strlen(s));
+ if (under == cObject) {
+ str = str_new2(name);
+ }
+ else {
+ str = str_dup(rb_class_path(under));
+ str_cat(str, "::", 2);
+ str_cat(str, name, strlen(name));
}
- rb_ivar_set(class, rb_intern("__classpath__"), str);
+ rb_iv_set(class, "__classpath__", str);
}
VALUE
rb_path2class(path)
char *path;
{
- char *p, *name, *s;
- ID id;
- VALUE class;
-
- p = path;
- while (*p) {
- if (*p == ':') break;
- *p++;
- }
- if (*p == '\0') { /* pre-defined class */
- if (!st_lookup(RCLASS(cObject)->iv_tbl, rb_intern(path), &class)
- && !st_lookup(class_tbl, rb_intern(path), &class)) {
- NameError("Undefined class -- %s", path);
- }
- return class;
- }
- class = rb_path2class(p+1);
- name = ALLOCA_N(char, p-path+1);
- s = name;
- while (path<p) {
- *s++ = *path++;
- }
- *s = '\0';
- id = rb_intern(name);
- if (!rb_const_defined(class, id))
- Fatal("%s not defined", name);
- class = rb_const_get(class, id);
- switch (TYPE(class)) {
- case T_CLASS:
- case T_MODULE:
- break;
- default:
- Fatal("0x%x is not a class/module", class);
+ if (path[0] == '#') {
+ ArgError("can't retrieve anonymous class %s", path);
}
- return class;
+ return rb_eval_string(path);
}
void
@@ -129,7 +203,14 @@ rb_name_class(class, id)
VALUE class;
ID id;
{
- rb_ivar_set(class, rb_intern("__classname__"), id);
+ extern VALUE cString;
+
+ if (cString) {
+ rb_iv_set(class, "__classpath__", str_new2(rb_id2name(id)));
+ }
+ else {
+ rb_iv_set(class, "__classid__", INT2FIX(id));
+ }
}
static st_table *autoload_tbl = 0;
@@ -139,6 +220,10 @@ rb_autoload_id(id, filename)
ID id;
char *filename;
{
+ if (!rb_is_const_id(id)) {
+ NameError("autoload must be constant name", rb_id2name(id));
+ }
+
if (!autoload_tbl) {
autoload_tbl = new_idhash();
}
@@ -166,30 +251,9 @@ f_autoload(obj, class, file)
char *
rb_class2name(class)
- struct RClass *class;
+ VALUE class;
{
- int name;
-
- switch (TYPE(class)) {
- case T_ICLASS:
- class = (struct RClass*)RBASIC(class)->class;
- break;
- case T_CLASS:
- case T_MODULE:
- break;
- default:
- Fatal("0x%x is not a class/module", class);
- }
-
- while (FL_TEST(class, FL_SINGLETON) || TYPE(class) == T_ICLASS) {
- class = (struct RClass*)class->super;
- }
-
- name = rb_ivar_get(class, rb_intern("__classname__"));
- if (!NIL_P(name)) {
- return rb_id2name((ID)name);
- }
- Bug("class 0x%x not named", class);
+ return RSTRING(rb_class_path(class))->ptr;
}
struct trace_var {
@@ -322,9 +386,9 @@ var_marker(var)
static void
readonly_setter(val, id, var)
+ VALUE val;
ID id;
void *var;
- VALUE val;
{
NameError("Can't set variable %s", rb_id2name(id));
}
@@ -411,7 +475,7 @@ rb_define_virtual_variable(name, getter, setter)
rb_define_hooked_variable(name, 0, getter, setter);
}
-void
+static void
rb_trace_eval(cmd, val)
VALUE cmd, val;
{
@@ -534,6 +598,10 @@ rb_gvar_set(entry, val)
{
struct trace_data trace;
+ if (rb_safe_level() >= 4) {
+ extern VALUE eSecurityError;
+ Raise(eSecurityError, "cannot change global variable value");
+ }
(*entry->setter)(val, entry->id, entry->data, entry);
if (!entry->block_trace) {
@@ -564,6 +632,22 @@ rb_gvar_defined(entry)
return TRUE;
}
+void
+rb_alias_variable(name1, name2)
+ ID name1;
+ ID name2;
+{
+ struct global_entry *entry1, *entry2;
+
+ entry1 = rb_global_entry(name1);
+ entry2 = rb_global_entry(name2);
+
+ entry1->data = entry2->data;
+ entry1->getter = entry2->getter;
+ entry1->setter = entry2->setter;
+ entry1->marker = entry2->marker;
+}
+
VALUE
rb_ivar_get(obj, id)
struct RObject *obj;
@@ -579,8 +663,8 @@ rb_ivar_get(obj, id)
return val;
return Qnil;
default:
- Fatal("class %s can not have instance variables",
- rb_class2name(CLASS_OF(obj)));
+ TypeError("class %s can not have instance variables",
+ rb_class2name(CLASS_OF(obj)));
break;
}
Warning("instance var %s not initialized", rb_id2name(id));
@@ -593,6 +677,10 @@ rb_ivar_set(obj, id, val)
ID id;
VALUE val;
{
+ if (rb_safe_level() >= 5) {
+ extern VALUE eSecurityError;
+ Raise(eSecurityError, "cannot change object status");
+ }
switch (TYPE(obj)) {
case T_OBJECT:
case T_CLASS:
@@ -601,8 +689,8 @@ rb_ivar_set(obj, id, val)
st_insert(obj->iv_tbl, id, val);
break;
default:
- Fatal("class %s can not have instance variables",
- rb_class2name(CLASS_OF(obj)));
+ TypeError("class %s can not have instance variables",
+ rb_class2name(CLASS_OF(obj)));
break;
}
return val;
@@ -634,6 +722,9 @@ rb_const_get_at(class, id)
if (class->iv_tbl && st_lookup(class->iv_tbl, id, &value)) {
return value;
}
+ if ((VALUE)class == cObject) {
+ return rb_const_get(class, id);
+ }
NameError("Uninitialized constant %s::%s",
RSTRING(rb_class_path(class))->ptr,
rb_id2name(id));
@@ -679,12 +770,58 @@ rb_const_get(class, id)
NameError("Uninitialized constant %s::%s",
RSTRING(rb_class_path(class))->ptr,
rb_id2name(id));
- else
+ else {
NameError("Uninitialized constant %s",rb_id2name(id));
+ }
/* not reached */
}
int
+const_i(key, value, hash)
+ ID key;
+ VALUE value;
+ VALUE hash;
+{
+ if (rb_is_const_id(key)) {
+ hash_aset(hash, str_new2(rb_id2name(key)), value);
+ }
+ return ST_CONTINUE;
+}
+
+VALUE
+mod_constants(argc, argv, mod)
+ int argc;
+ VALUE *argv;
+ struct RClass *mod;
+{
+ VALUE option;
+ VALUE hash;
+
+ rb_scan_args(argc, argv, "01", &option);
+ hash = hash_new();
+ st_foreach(mod->iv_tbl, const_i, hash);
+ if (!FL_TEST(mod, FL_SINGLETON)) {
+ mod = mod->super;
+ if (!mod) {
+ Bug("no superclass for singleton class");
+ }
+ st_foreach(mod->iv_tbl, const_i, hash);
+ }
+ if (RTEST(option)) {
+ for (;;) {
+ mod = mod->super;
+ if (!mod) break;
+ st_foreach(mod->iv_tbl, const_i, hash);
+ }
+ st_foreach(class_tbl, const_i, hash);
+ if (autoload_tbl) {
+ st_foreach(autoload_tbl, const_i, hash);
+ }
+ }
+ return hash;
+}
+
+int
rb_const_defined_at(class, id)
struct RClass *class;
ID id;
@@ -692,6 +829,18 @@ rb_const_defined_at(class, id)
if (class->iv_tbl && st_lookup(class->iv_tbl, id, 0)) {
return TRUE;
}
+ if ((VALUE)class == cObject) {
+ return rb_const_defined(class, id);
+ }
+ return FALSE;
+}
+
+int
+rb_autoload_defined(id)
+ ID id;
+{
+ if (autoload_tbl && st_lookup(autoload_tbl, id, 0))
+ return TRUE;
return FALSE;
}
@@ -708,18 +857,7 @@ rb_const_defined(class, id)
}
if (st_lookup(class_tbl, id, 0))
return TRUE;
- if (autoload_tbl && st_lookup(autoload_tbl, id, 0))
- return TRUE;
- return FALSE;
-}
-
-int
-rb_autoload_defined(id)
- ID id;
-{
- if (autoload_tbl && st_lookup(autoload_tbl, id, 0))
- return TRUE;
- return FALSE;
+ return rb_autoload_defined(id);
}
void
@@ -732,10 +870,7 @@ rb_const_set(class, id, val)
class->iv_tbl = new_idhash();
}
else if (st_lookup(class->iv_tbl, id, 0)) {
- NameError("already initialized constnant %s", rb_id2name(id));
- }
- if (!rb_autoload_defined(id) && rb_const_defined(class, id)) {
- Warning("already initialized constnant %s", rb_id2name(id));
+ NameError("already initialized constant %s", rb_id2name(id));
}
st_insert(class->iv_tbl, id, val);
@@ -743,21 +878,25 @@ rb_const_set(class, id, val)
void
rb_define_const(class, name, val)
- struct RClass *class;
+ VALUE class;
char *name;
VALUE val;
{
- rb_const_set(class, rb_intern(name), val);
+ ID id = rb_intern(name);
+ if (!rb_is_const_id(id)) {
+ NameError("wrong constant name %s", name);
+ }
+ rb_const_set(class, id, val);
}
-extern VALUE cKernel;
+extern VALUE mKernel;
void
rb_define_global_const(name, val)
char *name;
VALUE val;
{
- rb_define_const(cKernel, name, val);
+ rb_define_const(mKernel, name, val);
}
VALUE
diff --git a/version.c b/version.c
index 440cba4c61..ec9f089d73 100644
--- a/version.c
+++ b/version.c
@@ -15,23 +15,22 @@
#include "version.h"
#include <stdio.h>
-extern VALUE cKernel;
-
void
Init_version()
{
rb_define_global_const("VERSION", str_new2(RUBY_VERSION));
+ rb_define_global_const("PLATFORM", str_new2(RUBY_PLATFORM));
}
void
show_version()
{
- fprintf(stderr, "ruby - version %s\n", RUBY_VERSION, VERSION_DATE);
+ fprintf(stderr, "ruby - version %s (%s)\n", RUBY_VERSION, RUBY_PLATFORM);
}
void
show_copyright()
{
- fprintf(stderr, "ruby - Copyright (C) 1993-1996 Yukihiro Matsumoto\n");
+ fprintf(stderr, "ruby - Copyright (C) 1993-1997 Yukihiro Matsumoto\n");
exit(0);
}
diff --git a/version.h b/version.h
index 8e8b66cb32..2002a99876 100644
--- a/version.h
+++ b/version.h
@@ -1,2 +1,2 @@
-#define RUBY_VERSION "1.0-961225"
-#define VERSION_DATE "96/12/25"
+#define RUBY_VERSION "1.0-971002"
+#define VERSION_DATE "97/10/02"
diff --git a/win32/Makefile b/win32/Makefile
new file mode 100644
index 0000000000..4927e05631
--- /dev/null
+++ b/win32/Makefile
@@ -0,0 +1,233 @@
+SHELL = $(COMPSEC)
+
+#### Start of system configuration section. ####
+
+srcdir = .
+VPATH = .:./missing
+
+CC = cl
+YACC = byacc
+RANLIB =
+AR =
+INSTALL = ginstall -c
+INSTALL_PROGRAM = $(INSTALL)
+INSTALL_DATA = $(INSTALL) -m 644
+PURIFY =
+
+
+#CFLAGS = -nologo -DNT=1 -Ox
+#LDFLAGS = $(CFLAGS) -Fm
+CFLAGS = -nologo -DNT=1 -Zi -MD
+LDFLAGS = $(CFLAGS) -Fm -MD
+LIBS = $(EXTLIBS) advapi32.lib wsock32.lib
+MISSING = crypt.obj flock.obj setenv.obj alloca.obj nt.obj
+
+prefix =
+binprefix =
+exec_prefix =
+bindir =
+libdir =
+
+STACK = 0x200000
+
+#### End of system configuration section. ####
+
+
+LIBRUBY = libruby.lib
+
+EXTOBJS = dmyext.obj
+
+MAINOBJ = main.obj
+
+OBJS = array.obj \
+ bignum.obj \
+ class.obj \
+ compar.obj \
+ dir.obj \
+ dln.obj \
+ enum.obj \
+ error.obj \
+ eval.obj \
+ file.obj \
+ fnmatch.obj \
+ gc.obj \
+ glob.obj \
+ hash.obj \
+ inits.obj \
+ io.obj \
+ math.obj \
+ numeric.obj \
+ object.obj \
+ pack.obj \
+ parse.obj \
+ process.obj \
+ random.obj \
+ range.obj \
+ re.obj \
+ regex.obj \
+ ruby.obj \
+ signal.obj \
+ sprintf.obj \
+ st.obj \
+ string.obj \
+ struct.obj \
+ time.obj \
+ util.obj \
+ variable.obj \
+ version.obj \
+ $(MISSING)
+
+all: miniruby.exe ext/Setup
+ cd ext
+ ..\miniruby .\extmk.rb static
+ cd ..
+
+miniruby.exe: $(OBJS) $(MAINOBJ) $(EXTOBJS)
+ @echo $(EXTOBJS)
+ @echo $(LIBS)
+ @rm -f miniruby.exe
+# $(PURIFY) $(CC) $(LDFLAGS) $(MAINOBJ) $(OBJS) $(EXTOBJS) $(LIBS) -o miniruby.exe
+ $(PURIFY) $(CC) $(LDFLAGS) $(MAINOBJ) $(OBJS) $(EXTOBJS) $(LIBS) -o miniruby.exe -link /NOD:LIBC
+
+ruby.exe: $(LIBRUBY) $(MAINOBJ) $(EXTOBJS) ruby.dll
+ @echo $(EXTOBJS)
+ @echo $(LIBS)
+ @rm -f ruby.exe
+# $(PURIFY) $(CC) $(LDFLAGS) $(MAINOBJ) $(EXTOBJS) $(LIBRUBY) $(LIBS) -o ruby.exe
+# $(PURIFY) $(CC) $(LDFLAGS) $(MAINOBJ) $(EXTOBJS) $(LIBRUBY) $(LIBS) -o ruby.exe -link /DEF:rubyexe.def /NOD:LIBC
+ $(CC) $(LDFLAGS) $(MAINOBJ) -o ruby.exe ruby.lib -link /NOD:LIBC /STACK:$(STACK)
+
+ruby.dll: $(LIBRUBY) $(EXTOBJS)
+ @echo $(EXTOBJS)
+ @echo $(LIBS)
+ @rm -f ruby.dll
+ $(PURIFY) $(CC) $(LDFLAGS) $(MAINOBJ) $(EXTOBJS) $(LIBRUBY) $(LIBS) -o ruby.dll -link /DLL /DEF:ruby.def /NOD:LIBC
+
+$(LIBRUBY): $(OBJS)
+ lib /OUT:$(LIBRUBY) $(OBJS)
+
+install:; $(INSTALL_PROGRAM) ruby.exe $(bindir)/ruby.exe
+ @-strip $(bindir)/ruby
+ @test -d $(libdir) || mkdir $(libdir)
+ cd ext; ../miniruby ./extmk.rb install
+ @for rb in `grep '^lib/' MANIFEST`; do \
+ $(INSTALL_DATA) $$rb $(libdir); \
+ done
+
+clean:; @rm -f $(OBJS) $(LIBRUBY) main.obj dmyext.obj *.pdb *.map *.exp
+ @rm -f ext/extinit.c ext/extinit.obj
+ cd ext
+ ..\miniruby .\extmk.rb clean
+ cd ..
+
+realclean: clean
+ @rm -f Makefile ext/extmk.rb
+ @rm -f config.cache config.h config.log config.status
+ @rm -f core ruby miniruby *~
+
+test:; @-./ruby sample/test.rb > ./ruby_test 2>&1; \
+ if grep '^end of test' ./ruby_test > /dev/null; then \
+ echo "test succeeded"; \
+ else \
+ grep '^sample/test.rb' ./ruby_test; \
+ grep '^not' ./ruby_test; \
+ echo "test failed";\
+ fi;\
+ rm -f ./ruby_test
+
+.c.obj:
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c $<
+
+alloca.obj: missing/alloca.c
+ $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/alloca.c
+
+crypt.obj: missing/crypt.c
+ $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/crypt.c
+
+dup2.obj: missing/dup2.c
+ $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/dup2.c
+
+flock.obj: missing/flock.c
+ $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/flock.c
+
+memmove.obj: missing/memmove.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/memmove.c
+
+mkdir.obj: missing/mkdir.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/mkdir.c
+
+setenv.obj: missing/setenv.c
+ $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/setenv.c
+
+strerror.obj: missing/strerror.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/strerror.c
+
+strdup.obj: missing/strdup.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/strdup.c
+
+strftime.obj: missing/strftime.c
+ $(CC) -I. $(CFLAGS) $(CPPFLAGS) -c missing/strftime.c
+
+strstr.obj: missing/strstr.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/strstr.c
+
+strtol.obj: missing/strtol.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/strtol.c
+
+strtoul.obj: missing/strtoul.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/strtoul.c
+
+# when I use -I., there is confliction at "OpenFile"
+# so, set . into environment varible "include"
+nt.obj: missing/nt.c
+ @set include=$(INCLUDE);.
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c missing/nt.c
+
+parse.c: parse.y
+ $(YACC) $(YFLAGS) parse.y
+ sed -e "s!^extern char \*getenv();!/* & */!" y.tab.c > parse.c
+ @rm y.tab.c
+
+# Prevent GNU make v3 from overflowing arg limit on SysV.
+.NOEXPORT:
+###
+parse.obj : parse.y ruby.h defines.h config.h env.h node.h st.h regex.h
+###
+array.obj: array.c ruby.h config.h defines.h
+bignum.obj: bignum.c ruby.h config.h defines.h
+class.obj: class.c ruby.h config.h defines.h node.h st.h
+compar.obj: compar.c ruby.h config.h defines.h
+dir.obj: dir.c ruby.h config.h defines.h
+dln.obj: dln.c config.h defines.h dln.h st.h
+dmyext.obj: dmyext.c
+enum.obj: enum.c ruby.h config.h defines.h
+error.obj: error.c ruby.h config.h defines.h env.h
+eval.obj: eval.c ruby.h config.h defines.h env.h node.h sig.h st.h dln.h
+file.obj: file.c ruby.h config.h defines.h io.h sig.h
+fnmatch.obj: fnmatch.c config.h fnmatch.h
+gc.obj: gc.c ruby.h config.h defines.h env.h sig.h st.h node.h re.h regex.h
+glob.obj: glob.c config.h fnmatch.h
+hash.obj: hash.c ruby.h config.h defines.h st.h
+inits.obj: inits.c ruby.h config.h defines.h
+io.obj: io.c ruby.h config.h defines.h io.h sig.h
+main.obj: main.c
+math.obj: math.c ruby.h config.h defines.h
+numeric.obj: numeric.c ruby.h config.h defines.h
+object.obj: object.c ruby.h config.h defines.h st.h
+pack.obj: pack.c ruby.h config.h defines.h
+process.obj: process.c ruby.h config.h defines.h sig.h st.h
+random.obj: random.c ruby.h config.h defines.h
+range.obj: range.c ruby.h config.h defines.h
+re.obj: re.c ruby.h config.h defines.h re.h regex.h
+regex.obj: regex.c config.h defines.h regex.h util.h
+ruby.obj: ruby.c ruby.h config.h defines.h re.h regex.h dln.h
+signal.obj: signal.c ruby.h config.h defines.h sig.h
+sprintf.obj: sprintf.c ruby.h config.h defines.h
+st.obj: st.c config.h st.h
+string.obj: string.c ruby.h config.h defines.h re.h regex.h
+struct.obj: struct.c ruby.h config.h defines.h
+time.obj: time.c ruby.h config.h defines.h
+util.obj: util.c defines.h config.h util.h
+variable.obj: variable.c ruby.h config.h defines.h env.h st.h
+version.obj: version.c ruby.h config.h defines.h version.h
+director.obj : director.c dir.h
diff --git a/win32/config.h b/win32/config.h
new file mode 100644
index 0000000000..d43cfdb535
--- /dev/null
+++ b/win32/config.h
@@ -0,0 +1,60 @@
+#define THREAD 1
+/* #define HAVE_DIRENT_H 1 */
+/* #define HAVE_UNISTD_H 1 */
+#define HAVE_STDLIB_H 1
+#define HAVE_LIMITS_H 1
+#define HAVE_SYS_FILE_H 1
+/* #define HAVE_PWD_H 1 */
+/* #define HAVE_SYS_TIME_H 1 */
+/* #define HAVE_SYS_TIMES_H 1 */
+/* #define HAVE_SYS_PARAM_H 1 */
+/* #define HAVE_SYS_WAIT_H 1 */
+#define HAVE_STRING_H 1
+/* #define HAVE_UTIME_H 1 */
+#define HAVE_MEMORY_H 1
+/* #define HAVE_ST_BLKSIZE 1 */
+#define HAVE_ST_RDEV 1
+/* #define GETGROUPS_T gid_t */
+#define GETGROUPS_T int
+#define RETSIGTYPE void
+#define HAVE_ALLOCA 1
+#define vfork fork
+#define HAVE_FMOD 1
+/* #define HAVE_RANDOM 1 */
+/* #define HAVE_WAITPID 1 */
+#define HAVE_GETCWD 1
+/* #define HAVE_TRUNCATE 1 */
+#define HAVE_CHSIZE 1
+/* #define HAVE_TIMES 1 */
+/* #define HAVE_UTIMES 1 */
+/* #define HAVE_FCNTL 1 */
+/* #define HAVE_SETITIMER 1 */
+#define HAVE_GETGROUPS 1
+/* #define HAVE_SIGPROCMASK 1 */
+#define FILE_COUNT _cnt
+#define DLEXT ".dll"
+#define RUBY_LIB ";/usr/local/lib/ruby;."
+#define RUBY_ARCHLIB "/usr/local/lib/ruby/i386-mswin32"
+#define RUBY_PLATFORM "i386-mswin32"
+
+/* NNN */
+#define strcasecmp _strcmpi
+#define popen _popen
+#define pclose _pclose
+#define pipe _pipe
+#define bzero(x, y) memset(x, 0, y)
+
+#define S_IFMT _S_IFMT
+#define S_IFDIR _S_IFDIR
+#define S_IFCHR _S_IFCHR
+#define S_IFREG _S_IFREG
+#define S_IREAD _S_IREAD
+#define S_IWRITE _S_IWRITE
+#define S_IEXEC _S_IEXEC
+#define S_ISFIFO _S_ISFIFO
+
+#define UIDTYPE int
+#define GIDTYPE int
+#define pid_t int
+#define WNOHANG -1
+//#define NT
diff --git a/win32/ntsetup.bat b/win32/ntsetup.bat
new file mode 100644
index 0000000000..1848d035ec
--- /dev/null
+++ b/win32/ntsetup.bat
@@ -0,0 +1,10 @@
+@echo off
+copy config.h ..
+copy Makefile ..
+copy ruby.def ..
+cd ..\ext
+copy Setup.nt Setup
+copy extmk.rb.nt extmk.rb
+
+cd ..
+echo type `nmake' to make ruby for mswin32.
diff --git a/win32/ruby.def b/win32/ruby.def
new file mode 100644
index 0000000000..1ec577d2a8
--- /dev/null
+++ b/win32/ruby.def
@@ -0,0 +1,6 @@
+DESCRIPTION 'win32 ruby.dll'
+
+EXPORTS
+ ruby_init
+ ruby_run
+ ruby_options
diff --git a/x68/_dtos18.c b/x68/_dtos18.c
new file mode 100644
index 0000000000..67656486ec
--- /dev/null
+++ b/x68/_dtos18.c
@@ -0,0 +1,250 @@
+/*
+ * PROJECT C Library, X68000 PROGRAMMING INTERFACE DEFINITION
+ * --------------------------------------------------------------------
+ * This file is written by the Project C Library Group, and completely
+ * in public domain. You can freely use, copy, modify, and redistribute
+ * the whole contents, without this notice.
+ * --------------------------------------------------------------------
+ * $Id: _dtos18.c,v 1.2 1994/11/27 13:05:20 mura Exp $
+ */
+
+/* System headers */
+#include <stdlib.h>
+#include <sys/xstdlib.h>
+
+/*
+** ܴؿưѴƤʸˤ뤿ᡢŪˤ
+** ˳ǼǤޤǤȤǤʤäƺǹ
+** 18Ǥ롣
+*/
+
+/* File scope variables */
+static double _pos1[32] = {
+ 1.0e+17, /* + 0 */
+ 1.0e+18, /* + 1 */
+ 1.0e+19, /* + 2 */
+ 1.0e+20, /* + 3 */
+ 1.0e+21, /* + 4 */
+ 1.0e+22, /* + 5 */
+ 1.0e+23, /* + 6 */
+ 1.0e+24, /* + 7 */
+ 1.0e+25, /* + 8 */
+ 1.0e+26, /* + 9 */
+ 1.0e+27, /* +10 */
+ 1.0e+28, /* +11 */
+ 1.0e+29, /* +12 */
+ 1.0e+30, /* +13 */
+ 1.0e+31, /* +14 */
+ 1.0e+32, /* +15 */
+ 1.0e+33, /* +16 */
+ 1.0e+34, /* +17 */
+ 1.0e+35, /* +18 */
+ 1.0e+36, /* +19 */
+ 1.0e+37, /* +20 */
+ 1.0e+38, /* +21 */
+ 1.0e+39, /* +22 */
+ 1.0e+40, /* +23 */
+ 1.0e+41, /* +24 */
+ 1.0e+42, /* +25 */
+ 1.0e+43, /* +26 */
+ 1.0e+44, /* +27 */
+ 1.0e+45, /* +28 */
+ 1.0e+46, /* +29 */
+ 1.0e+47, /* +30 */
+ 1.0e+48, /* +31 */
+};
+
+/* File scope variables */
+static double _neg1[32] = {
+ 1.0e+17, /* - 0 */
+ 1.0e+16, /* - 1 */
+ 1.0e+15, /* - 2 */
+ 1.0e+14, /* - 3 */
+ 1.0e+13, /* - 4 */
+ 1.0e+12, /* - 5 */
+ 1.0e+11, /* - 6 */
+ 1.0e+10, /* - 7 */
+ 1.0e+9, /* - 8 */
+ 1.0e+8, /* - 9 */
+ 1.0e+7, /* -10 */
+ 1.0e+6, /* -11 */
+ 1.0e+5, /* -12 */
+ 1.0e+4, /* -13 */
+ 1.0e+3, /* -14 */
+ 1.0e+2, /* -15 */
+ 1.0e+1, /* -16 */
+ 1.0e+0, /* -17 */
+ 1.0e-1, /* -18 */
+ 1.0e-2, /* -19 */
+ 1.0e-3, /* -20 */
+ 1.0e-4, /* -21 */
+ 1.0e-5, /* -22 */
+ 1.0e-6, /* -23 */
+ 1.0e-7, /* -24 */
+ 1.0e-8, /* -25 */
+ 1.0e-9, /* -26 */
+ 1.0e-10, /* -27 */
+ 1.0e-11, /* -28 */
+ 1.0e-12, /* -29 */
+ 1.0e-13, /* -30 */
+ 1.0e-14, /* -31 */
+};
+
+/* File scope variables */
+static double _pos2[10] = {
+ 1.0e+0, /* 000 */
+ 1.0e+32, /* 001 */
+ 1.0e+64, /* 010 */
+ 1.0e+96, /* 011 */
+ 1.0e+128, /* 100 */
+ 1.0e+160, /* 101 */
+ 1.0e+192, /* 110 */
+ 1.0e+224, /* 111 */
+ 1.0e+256, /* 1000 */
+ 1.0e+288, /* 1001 */
+};
+
+/* File scope variables */
+static double _neg2[10] = {
+ 1.0e-0, /* 000 */
+ 1.0e-32, /* 001 */
+ 1.0e-64, /* 010 */
+ 1.0e-96, /* 011 */
+ 1.0e-128, /* 100 */
+ 1.0e-160, /* 101 */
+ 1.0e-192, /* 110 */
+ 1.0e-224, /* 111 */
+ 1.0e-256, /* 1000 */
+ 1.0e-288, /* 1001 */
+};
+
+/* File scope functions */
+static int _cmpd (double x, double y)
+{
+ unsigned long vx, vy, rc;
+ unsigned long *x_ptr = (unsigned long *) &x;
+ unsigned long *y_ptr = (unsigned long *) &y;
+
+ /* xλؿӥåȤФ */
+ vx = x_ptr[0] & 0x7FF00000;
+
+ /* yλؿӥåȤФ */
+ vy = y_ptr[0] & 0x7FF00000;
+
+ /* ؿӥåȤȽǤ */
+ if ((rc = vy - vx) != 0)
+ return rc;
+
+ /* xͭξ̥ӥåȤФ */
+ vx = x_ptr[0] & 0x000FFFFF;
+
+ /* yͭξ̥ӥåȤФ */
+ vy = y_ptr[0] & 0x000FFFFF;
+
+ /* ̥ӥåȤȽǤ */
+ if ((rc = vy - vx) != 0)
+ return rc;
+
+ /* xͭβ̥ӥåȤФ */
+ vx = x_ptr[1];
+
+ /* yͭβ̥ӥåȤФ */
+ vy = y_ptr[1];
+
+ /* ǽȽ */
+ return vy - vx;
+}
+
+/* Functions */
+void _dtos18 (double x, int *decpt, int *sign, char *buffer)
+{
+ short e2;
+ int e, n;
+
+ /* 2λؿ(Хʤξ) */
+ e2 = (((unsigned short *) &x)[0] & 0x7FF0U) >> 4;
+
+ /* ؿ0ξϡ0.0å */
+ if (e2 == 0) {
+
+ unsigned long hi = ((unsigned long *) &x)[0] & 0xFFFFF;
+ unsigned long lo = ((unsigned long *) &x)[1];
+
+ /* ͭ0ɤ */
+ if (hi == 0 && lo == 0) {
+
+ /* ʸ */
+ buffer[0] = '0';
+
+ /* NUL */
+ buffer[1] = '\0';
+
+ /* ֤׻ */
+ *decpt = 1;
+
+ /* ׻ */
+ /* *sign = hi & 0x80000000UL; */
+ *sign = 0;
+
+ /* */
+ return;
+
+ }
+
+ }
+
+ /* 2λؿ˥Х򤫤Ƥ10λؿ򳵻 (approx. log10(2)) */
+ e = ((int) ((e2 - 1023) * 77)) >> 8;
+
+ /* ؿξ */
+ if (e >= 0) {
+
+ /* ؿ32꾮ϥơ֥1 */
+ if (e < 32)
+ x *= _neg1[e];
+
+ /* ؿ32礭ϥơ֥1,2 */
+ else
+ x *= _neg1[e & 31] * _neg2[e >> 5];
+
+ }
+
+ /* ؿξ */
+ else {
+
+ /* ͤ׻ */
+ n = -e;
+
+ /* ͤ32꾮ϥơ֥1 */
+ if (n < 32)
+ x *= _pos1[n];
+
+ /* ͤ32礭ϥơ֥1,2 */
+ else {
+ x *= _pos1[n & 31];
+ x *= _pos2[n >> 5];
+ }
+
+ }
+
+ /* 󥰤᤹ */
+ if (_cmpd (1.0e+18, x) >= 0) {
+ e++;
+ x *= 1.0e-1;
+ }
+
+ /* 󥰤­ʤɲ */
+ else if (_cmpd (1.0e+17, x) < 0) {
+ e--;
+ x *= 1.0e+1;
+ }
+
+ /* ֤׻ */
+ *decpt = e + 1;
+
+ /* ׻ */
+ *sign = ((unsigned char *) &x)[0] & 0x80U;
+
+ /* ʸѴ */
+ _ulltoa ((unsigned long long) x, buffer);
+}
diff --git a/x68/_round.c b/x68/_round.c
new file mode 100644
index 0000000000..73e44ca966
--- /dev/null
+++ b/x68/_round.c
@@ -0,0 +1,45 @@
+/*
+ * PROJECT C Library, X68000 PROGRAMMING INTERFACE DEFINITION
+ * --------------------------------------------------------------------
+ * This file is written by the Project C Library Group, and completely
+ * in public domain. You can freely use, copy, modify, and redistribute
+ * the whole contents, without this notice.
+ * --------------------------------------------------------------------
+ * $Id: _round.c,v 1.1 1994/11/27 13:05:36 mura Exp $
+ */
+/* changed 1997.2.2 by K.Okabe */
+
+/* System headers */
+#include <stdlib.h>
+#include <sys/xstdlib.h>
+
+/* Functions */
+int _round (char *top, char *cur, int undig)
+{
+ char *ptr;
+
+ /* Ǹ夬5̤ʤݤɬפʤ */
+ if (undig < '5')
+ return 0;
+
+ /* ݥ */
+ ptr = cur - 1;
+
+ /* Ƭޤʤݤ */
+ while (ptr >= top) {
+
+ /* 夬ʤФǽ */
+ if (++(*ptr) <= '9')
+ return 0;
+
+ /* η0᤹ */
+ *ptr-- = '0';
+
+ }
+
+ /* Ƭ1ˤ */
+ *++ptr = '1';
+
+ /* 夬򤷤餻 */
+ return 1;
+}
diff --git a/x68/fconvert.c b/x68/fconvert.c
new file mode 100644
index 0000000000..05ff1fbd1a
--- /dev/null
+++ b/x68/fconvert.c
@@ -0,0 +1,81 @@
+/*
+ * PROJECT C Library, X68000 PROGRAMMING INTERFACE DEFINITION
+ * --------------------------------------------------------------------
+ * This file is written by the Project C Library Group, and completely
+ * in public domain. You can freely use, copy, modify, and redistribute
+ * the whole contents, without this notice.
+ * --------------------------------------------------------------------
+ * $Id: fconvert.c,v 1.2 1994/11/27 13:06:19 mura Exp $
+ */
+/* changed 1997.2.3 by K.Okabe */
+
+/* System headers */
+#include <stdlib.h>
+#include <sys/xstdlib.h>
+
+/* Functions */
+char *fconvert (double x, int ndigit, int *decpt, int *sign, char *buffer)
+{
+ int pos, n;
+ char *src, *dst;
+ char string[24];
+ int figup;
+
+ /* 18ʸѴ */
+ _dtos18 (x, decpt, sign, string);
+
+ /* ԡɥ쥹 */
+ src = string;
+
+ /* ԡ襢ɥ쥹 */
+ dst = buffer;
+
+ /* ֤ */
+ pos = *decpt;
+
+ /* ֤ʤ */
+ if (pos < 0) {
+
+ /* ׻ */
+ n = min (-pos, ndigit);
+
+ /* Ƭ0 */
+ while (n-- > 0)
+ *dst++ = '0';
+
+ /* ֤0ˤʤ */
+ *decpt = 0;
+
+ }
+
+ /* ĤΥԡ */
+ n = ndigit + pos;
+
+ /* Ǽ˥ԡ */
+ while (n-- > 0) {
+
+ /* ­ʤʬ0 */
+ if (*src == '\0') {
+ while (n-- >= 0)
+ *dst++ = '0';
+ break;
+ }
+
+ /* Ѵʸ󤫤饳ԡ */
+ *dst++ = *src++;
+
+ }
+
+ /* ݤ */
+ *decpt += (figup = _round (buffer, dst, *src));
+
+ /* 夬꤬0ɲä */
+ if (figup)
+ *dst++ = '0';
+
+ /* ü NUL Ǥ */
+ *dst = '\0';
+
+ /* ɥ쥹֤ */
+ return buffer;
+}
diff --git a/x68/select.c b/x68/select.c
new file mode 100644
index 0000000000..b4bf464032
--- /dev/null
+++ b/x68/select.c
@@ -0,0 +1,167 @@
+/*
+ * PROJECT C Library, X68000 PROGRAMMING INTERFACE DEFINITION
+ * --------------------------------------------------------------------
+ * This file is written by the Project C Library Group, and completely
+ * in public domain. You can freely use, copy, modify, and redistribute
+ * the whole contents, without this notice.
+ * --------------------------------------------------------------------
+ * $Id$
+ */
+
+#ifndef __IOCS_INLINE__
+#define __IOCS_INLINE__
+#define __DOS_INLINE__
+#define __DOS_DOSCALL__
+#endif
+
+/* System headers */
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/dos.h>
+#include <sys/iocs.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#if 0
+#include <sys/select.h>
+#include <sys/xsocket.h>
+#endif
+#include <sys/xunistd.h>
+
+/* Macros */
+#define XFD_ISSET(fd,fds) ((fds) && FD_ISSET ((fd), (fds)))
+#define isreadable(mode) ((mode) == O_RDONLY || (mode) == O_RDWR)
+#define iswritable(mode) ((mode) == O_WRONLY || (mode) == O_RDWR)
+#ifndef _POSIX_FD_SETSIZE
+#define _POSIX_FD_SETSIZE OPEN_MAX
+#endif
+
+/* Functions */
+int
+select (int fds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout)
+{
+ fd_set oread, owrite, oexcept;
+ int ticks, start;
+ int nfds;
+
+ if (fds > _POSIX_FD_SETSIZE)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ FD_ZERO (&oread);
+ FD_ZERO (&owrite);
+ FD_ZERO (&oexcept);
+
+ nfds = 0;
+ ticks = -1;
+
+ if (timeout)
+ {
+ ticks = timeout->tv_sec * 100 + timeout->tv_usec / 10000;
+ if (ticks < 0)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+
+ start = _iocs_ontime ();
+ for (;;)
+ {
+ {
+ int fd;
+
+ for (fd = 0; fd < fds; fd++)
+ {
+ int accmode;
+
+ if (_fddb[fd].inuse == _FD_NOTUSED)
+ continue;
+
+ accmode = _fddb[fd].oflag & O_ACCMODE;
+
+ if (isatty (fd))
+ {
+ if (XFD_ISSET (fd, rfds) && isreadable (accmode) && _dos_k_keysns ())
+ {
+ FD_SET (fd, &oread);
+ nfds++;
+ }
+
+ if (XFD_ISSET (fd, wfds) && iswritable (accmode))
+ {
+ FD_SET (fd, &owrite);
+ nfds++;
+ }
+ }
+#if 0
+ else if (_fddb[fd].sockno >= 0)
+ {
+ if (XFD_ISSET (fd, rfds) && _socklen (_fddb[fd].sockno, 0))
+ {
+ FD_SET (fd, &oread);
+ nfds++;
+ }
+
+ if (XFD_ISSET (fd, wfds) /* && _socklen (_fddb[fd].sockno, 1) == 0 */)
+ {
+ FD_SET (fd, &owrite);
+ nfds++;
+ }
+ }
+#endif
+ else
+ {
+ if (XFD_ISSET (fd, rfds) && isreadable (accmode) && _dos_ioctrlis (fd))
+ {
+ FD_SET (fd, &oread);
+ nfds++;
+ }
+
+ if (XFD_ISSET (fd, wfds) && iswritable (accmode) && _dos_ioctrlos (fd))
+ {
+ FD_SET (fd, &owrite);
+ nfds++;
+ }
+ }
+ }
+ }
+
+ {
+ int rest;
+
+ if ((rest = (_iocs_ontime () - start) % 8640000) < 0)
+ rest += 8640000;
+
+ if (nfds != 0)
+ {
+ if (ticks >= 0)
+ {
+ int left;
+
+ if ((left = ticks - rest) < 0)
+ left = 0;
+
+ timeout->tv_sec = left / 100;
+ timeout->tv_usec = (left % 100) * 10000;
+ }
+
+ if (rfds)
+ *rfds = oread;
+ if (wfds)
+ *wfds = owrite;
+ if (efds)
+ *efds = oexcept;
+
+ return nfds;
+ }
+
+ if (ticks >= 0 && rest > ticks)
+ return 0;
+ }
+
+ _dos_change_pr ();
+ }
+}