From 10d21745c8c1c3c78678ea7e0b62c0a7433ccfce Mon Sep 17 00:00:00 2001 From: Yukihiro Matsumoto Date: Thu, 2 Oct 1997 17:59:18 +0900 Subject: version 1.0-971002 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://cache.ruby-lang.org/pub/ruby/1.0/ruby-1.0-971002.tar.gz Thu Oct 2 17:59:18 1997 Yukihiro Matsumoto * version 1.0-971002 Wed Oct 1 14:01:49 1997 WATANABE Hirofumi * ext/marshal/marshal.c (w_byte): argument must be char. Wed Oct 1 10:30:22 1997 Yukihiro Matsumoto * 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 * version 1.0-970930 Fri Sep 30 14:29:22 1997 WATANABE Hirofumi * ext/marshal/marshal.c (w_object): marshal dumped core. Tue Sep 30 10:27:39 1997 Yukihiro Matsumoto * sample/test.rb: bignum test suits added. Mon Sep 29 13:37:58 1997 Yukihiro Matsumoto * ruby.c (forbid_setid): forbid some options in suid mode. Mon Sep 27 09:53:48 1997 EGUCHI Matsumoto * bignum.c: modified for speeding. Fri Sep 26 18:27:59 1997 WATANABE Hirofumi * sample/from.rb: some extensions. Mon Sep 29 13:15:56 1997 Yukihiro Matsumoto * parse.y (lhs): no more syntax error on `obj.CONSTANT = value'. Fri Sep 26 14:41:46 1997 Yukihiro Matsumoto * eval.c (ruby_run): deferred calling Init_ext() just before eval_node. Fri Sep 26 13:27:24 1997 WATANABE Hirofumi * io.c (io_isatty): forgot to return TRUE value. Fri Sep 25 11:10:58 1997 EGUCHI Osamu * eval.c: use _setjmp/_longjmp instead of setjmp/longjmp on some platforms. Wed Sep 24 17:43:13 1997 Yukihiro Matsumoto * string.c (Init_String): String#taint and String#taint? added. Wed Sep 24 00:57:00 1997 Katsuyuki Okabe * X68000 patch. Tue Sep 23 20:42:30 1997 EGUCHI Osamu * parse.y (node_newnode): SEGV on null node setup. Mon Sep 22 11:22:46 1997 Yukihiro Matsumoto * ruby.c (ruby_prog_init): wrong safe condition check. Sun Sep 21 14:46:02 1997 MAEDA shugo * error.c (exc_inspect): garbage added to classpath. Fri Sep 19 11:49:23 1997 * 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 * 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 * regex.c (re_compile_pattern): \w{3} and \W{3} did not work. Thu Sep 11 10:31:48 1997 Yukihiro Matsumoto * 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 * version 1.0-970910 * ext/marshal/marshal.c (r_bytes0): extra big length check. Tue Sep 9 16:27:14 1997 Yukihiro Matsumoto * 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 * 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 * version 1.0-970903 * eval.c (f_load): expand path if fname begins with `~'. Mon Sep 1 13:42:48 1997 Yukihiro Matsumoto * eval.c (rb_call): alias occured in the module body caused SEGV. Fri Aug 29 11:10:21 1997 Yukihiro Matsumoto * 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 * parse.y (yylex): revised `=begin' skip code. * eval.c (is_defined): separated from rb_eval(). Wed Aug 27 11:32:42 1997 Yukihiro Matsumoto * 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 * 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 * 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 * eval.c (error_print): modified exception print format. Thu Aug 21 16:10:58 1997 Yukihiro Matsumoto * sample/ruby-mode.el (ruby-calculate-indent): wrong indent level calculated with keyword operators. Thu Aug 21 11:55:41 1997 Yukihiro Matsumoto * version 1.0-970821 Thu Aug 21 11:36:58 1997 WATANABE Hirofumi * parse.y (arg): ary[0] += 1 cause SEGV Wed Aug 20 14:24:42 1997 Yukihiro Matsumoto * version 1.0-970820 * eval.c (rb_call): infinite loop bug Tue Aug 19 00:15:38 1997 Yukihiro Matsumoto * 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 * 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 * object.c (class_s_new): do not make subclass of singleton class. Fri Aug 15 15:49:46 1997 Yukihiro Matsumoto * 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 * ext/socket/socket.c (Init_socket): small typo caused SEGV. Tue Aug 12 16:02:18 1997 Yukihiro Matsumoto * 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 * 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 * 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 * object.c (Init_Object): remove private_attr/public_attr. Wed Aug 6 14:21:36 1997 Yukihiro Matsumoto * object.c (mod_attr): forgot to check nil for false value. Mon Aug 4 11:50:28 1997 Yukihiro Matsumoto * 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 * eval.c (rb_eval): stop to cache const value in nodes. Sat Jul 26 03:17:22 1997 WATANABE Hirofumi * numeric.c (flo_to_s): wrong .0 at end. Sat Jul 26 00:36:36 1997 Yukihiro Matsumoto * 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 * string.c (uscore_get): proper error message for unset $_. Wed Jul 23 09:56:55 1997 Yukihiro Matsumoto * 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 * 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 * 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 * Native mswin32 support. Tue Jul 1 09:59:00 1997 Yukihiro Matsumoto * version 1.0-970701 * parse.y (mrhs): allow rest-star(*) in right hand side. Tue Jun 24 19:04:31 1997 Yukihiro Matsumoto * version 1.0-970624 Sat Jun 20 22:22:51 1997 Michio "Karl" Jinbo * eval.c: freebsd 3.0 support. Fri Jun 20 01:24:45 1997 Yukihiro Matsumoto * 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 * version 1.0-970619 * string.c (str_split_method): wrong limit. Sat Jun 14 01:54:16 1997 Yukihiro Matsumoto * 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 * array.c (sort_2): wrong comparison. Sat Jun 14 00:53:44 1997 Yukihiro Matsumoto * hash.c (hash_foreach): safe iteration. Fri Jun 13 14:04:56 1997 Michio "Karl" Jinbo * configure.in: -Bshareable option for netbsd. Fri Jun 13 01:16:22 1997 WATANABE Hirofumi * io.c (pipe_open): call io_unbuffered() only for writable pipes. Thu Jun 12 01:14:15 1997 Yukihiro Matsumoto * 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 * gc.c (rb_newobj): remove needless memset(). Mon Jun 9 13:03:43 1997 Yukihiro Matsumoto * 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 * 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 * 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 * 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 * version 1.0-970528 * process.c (rb_waitpid): do not block other threads. Tue May 27 12:02:31 1997 Yukihiro Matsumoto * 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 * variable.c (rb_ivar_set): invalid instance variable access for built-in object raises TypeError. Fri May 16 17:32:21 1997 Yukihiro Matsumoto * 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 * 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 * file.c (file_s_dirname): need to return "." for path without slashes. Wed May 7 19:18:48 1997 Yukihiro Matsumoto * 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 * ext/curses/curses.c: modified for portability and add to the standard distribution. Wed Apr 30 00:34:00 1997 Yukihiro Matsumoto * file.c (file_s_size): returns 0 for empty files (not FALSE). Fri Apr 25 02:17:50 1997 Yukihiro Matsumoto * 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 * 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 * version 1.0-970422 Thu Apr 17 00:40:51 1997 Yukihiro Matsumoto * configure.in (rb_cv_bsdpgrp): proper check for BSD setpgrp/setpgrp. Wed Apr 16 16:14:02 1997 Yukihiro Matsumoto * eval.c (proc_call): proc called in other thread must be orphan. Tue Apr 15 10:46:31 1997 Yukihiro Matsumoto * 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 * version 1.0-970414 Fri Apr 12 01:20:12 1997 Yukihiro Matsumoto * ruby.h: String pointer changed to unsigned char. Fri Apr 11 10:27:29 1997 Yukihiro Matsumoto * 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 * 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 * ruby.c: forgot to include 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 * io.c (arg_read): bug with 0 length input. Mon Apr 7 11:36:16 1997 Yukihiro Matsumoto * 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 * version 1.0-970404 * gc.c (obj_free): finalizer added for experiment. Thu Apr 3 02:12:31 1997 Yukihiro Matsumoto * 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 * 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 * 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 * version 1.0-970331 Sun Mar 30 19:40:57 1997 WATANABE Hirofumi * parse.y (terms): avoided win32 gcc's optimization bug. Sat Mar 29 11:21:58 1997 Yukihiro Matsumoto * struct.c (make_struct): St[val,..] creates new structure. Fri Mar 28 11:24:51 1997 Yukihiro Matsumoto * 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 * pack.c (pack_unpack): extra null byte after unpacked string. Wed Mar 26 15:20:34 1997 Yukihiro Matsumoto * 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 * 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 * version 1.0-970324 Thu Mar 20 22:04:59 1997 Yukihiro Matsumoto * eval.c (mod_modfunc): forget to clear method cache. Wed Mar 19 17:06:55 1997 Yukihiro Matsumoto * 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 * 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 * 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 * 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 * ext/socks/socks.c: socket module with socks library. Mon Mar 10 20:44:22 1997 Yukihiro Matsumoto * re.c (reg_regsub): \& for substitution. \`, \', and \+ are avaiable also. Thu Mar 6 01:47:03 1997 Yukihiro Matsumoto * 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 * version 1.0-970305 Tue Mar 4 12:28:32 1997 Yukihiro Matsumoto * ruby.c (proc_options): search through RUBYPATH and PATH for option -S. Mon Mar 3 22:44:55 1997 Yukihiro Matsumoto * 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 * eval.c (rb_eval): restore $! value after rescue clause, to re-raise exceptions correctly. Fri Feb 28 16:43:38 1997 Yukihiro Matsumoto * version 1.0-970228 Thu Feb 27 11:23:41 1997 Yukihiro Matsumoto * 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 * eval.c (eval): forgot to restore dynamic local variable bindings. Tue Feb 25 11:22:08 1997 Yukihiro Matsumoto * 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 * 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 * version 1.0-970220 Thu Feb 20 11:25:50 1997 Yasuo OHBA * lib/date.rb: update Thu Feb 20 08:25:57 1997 Yukihiro Matsumoto * 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 * 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 * 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 * 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 * 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 * 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 * ruby.h (Data_Make_Struct): rename macros. Sun Feb 8 11:48:13 1997 Yukihiro Matsumoto * io.c (f_syscall): argument offset was wrong. Fri Feb 7 18:01:17 1997 Yukihiro Matsumoto * 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 * 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 * 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 * hash.c (hash_rehash): re-register all key-value. Thu Jan 30 02:14:49 1997 Yukihiro Matsumoto * 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 * 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 * 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 * 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 * 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 * util.c (_fixpath): supports SJIS filenames on DJGPP. Thu Jan 23 16:52:06 1997 Yukihiro Matsumoto * 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 * eval.c (Init_Thread): allocate main_thread first to avoid crash. Thu Jan 23 02:09:26 1997 Yukihiro Matsumoto * 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 * 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 * eval.c (thread_run): no context switch in the critical section. Mon Jan 20 09:40:59 1997 WATANABE Hirofumi * utils.c: supports 8+3 filenames Sat Jan 18 01:23:03 1997 Yukihiro Matsumoto * 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 * 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 * 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 * 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 * eval.c (thread_create): threadが生成されるまで割込みを設定しない * eval.c (Init_Thread): 割込みタイミングを100msecに Sat Jan 11 00:17:05 1997 Yukihiro Matsumoto * 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 * 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 * string.c (str_sub_s): 文字列長より長いoffsetの検出 * regex.c (re_search): 空にマッチするパターン後の$で失敗 Thu Jan 2 16:36:23 1997 Yukihiro Matsumoto * 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 * io.c (f_select): timeoutでnilを返す Fri Dec 27 13:06:44 1996 Yukihiro Matsumoto * 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 * lib/tk.rb: placeが使えるように * pack.c (endian): マクロDYNAMIC_ENDIANを指定すると実行時にendian を判定するように. * eval.c (thread_alloc): 初期化忘れのメンバがあった. Co-authored-by: EGUCHI Matsumoto Co-authored-by: EGUCHI Osamu Co-authored-by: KIMURA Koichi Co-authored-by: Katsuyuki Okabe Co-authored-by: MAEDA shugo Co-authored-by: Michio "Karl" Jinbo Co-authored-by: WATANABE Hirofumi Co-authored-by: Yasuo OHBA Co-authored-by: maeda shugo Co-authored-by: ono --- ChangeLog | 1193 ++++++++++++++++++++++++++- MANIFEST | 35 +- Makefile.in | 134 +-- README | 29 +- README.EXT | 341 ++++---- README.jp | 23 +- ToDo | 3 +- array.c | 158 +++- bignum.c | 157 ++-- class.c | 48 +- config.dj | 3 +- config.guess | 48 +- config.sub | 11 +- configure.in | 184 ++++- defines.h | 16 +- dir.c | 65 +- dln.c | 86 +- enum.c | 9 +- error.c | 85 +- eval.c | 2152 +++++++++++++++++++++++++++++++++--------------- ext/Setup | 3 + ext/Setup.dj | 4 + ext/Setup.nt | 12 + ext/Setup.x68 | 12 + ext/aix_ld.rb | 73 ++ ext/curses/MANIFEST | 6 + ext/curses/curses.c | 725 ++++++++++++++++ ext/curses/extconf.rb | 21 + ext/curses/hello.rb | 28 + ext/curses/rain.rb | 76 ++ ext/curses/view.rb | 90 ++ ext/dbm/dbm.c | 57 +- ext/dbm/extconf.rb | 1 + ext/etc/etc.c | 2 +- ext/extmk.rb.in | 120 ++- ext/extmk.rb.nt | 436 ++++++++++ ext/fcntl/MANIFEST | 3 + ext/fcntl/depend | 1 + ext/fcntl/fcntl.c | 106 +++ ext/kconv/MANIFEST | 1 + ext/kconv/depend | 1 + ext/kconv/kconv.c | 87 +- ext/marshal/extconf.rb | 1 - ext/marshal/marshal.c | 702 +++++++++------- ext/md5/md5init.c | 10 +- ext/socket/extconf.rb | 10 +- ext/socket/socket.c | 588 +++++++++---- ext/tkutil/tkutil.c | 9 +- file.c | 299 ++++--- gc.c | 345 ++++++-- glob.c | 6 + hash.c | 470 +++++++++-- inits.c | 3 +- io.c | 782 ++++++++++++++---- io.h | 7 +- lib/English.rb | 28 + lib/base64.rb | 47 +- lib/date.rb | 221 +++++ lib/debug.rb | 262 ++++++ lib/e2mmap.rb | 94 +++ lib/e2mmap1_0.rb | 71 ++ lib/finalize.rb | 205 +++++ lib/ftplib.rb | 617 ++++++++++++++ lib/jcode.rb | 35 +- lib/mathn.rb | 3 +- lib/matrix.rb | 777 +++++++++++++++++ lib/mutex_m.rb | 183 ++++ lib/observer.rb | 2 +- lib/parsedate.rb | 12 +- lib/ping.rb | 55 ++ lib/safe.rb | 78 -- lib/sync.rb | 376 +++++++++ lib/thread.rb | 117 +-- lib/thwait.rb | 128 +++ lib/tk.rb | 128 ++- lib/tkcanvas.rb | 21 +- lib/tkclass.rb | 2 + lib/tkcore.rb | 40 +- lib/tkentry.rb | 15 +- lib/tkscrollbox.rb | 4 +- lib/tktext.rb | 46 +- lib/tkthcore.rb | 33 +- lib/tracer.rb | 75 ++ main.c | 18 +- missing/dir.h | 248 ++++++ missing/file.h | 31 + missing/nt.c | 407 ++++++++- missing/nt.h | 123 ++- missing/setenv.c | 6 +- missing/strcasecmp.c | 13 + node.h | 161 ++-- numeric.c | 35 +- object.c | 296 ++++--- pack.c | 256 +++--- parse.y | 510 +++++++++--- process.c | 373 +++++++-- random.c | 13 +- range.c | 4 +- re.c | 389 ++++++--- re.h | 3 +- regex.c | 285 +++++-- regex.h | 4 + ruby.c | 245 ++++-- ruby.h | 133 +-- sample/biorhythm.rb | 227 ++--- sample/dbm.rb | 14 - sample/dbmtest.rb | 14 + sample/dir.rb | 2 +- sample/eval.rb | 7 +- sample/freq.rb | 4 +- sample/from.rb | 93 +-- sample/marshal.rb | 13 - sample/mrshtest.rb | 14 + sample/philos.rb | 2 +- sample/regx.rb | 2 +- sample/ruby-mode.el | 225 +++-- sample/rubydb2x.el | 104 +++ sample/rubydb3x.el | 104 +++ sample/svr.rb | 2 +- sample/test.rb | 115 ++- sample/tkbiff.rb | 2 +- sample/tkfrom.rb | 18 +- sig.h | 1 + signal.c | 16 +- sprintf.c | 314 +++++-- st.c | 77 +- st.h | 2 +- string.c | 359 +++++--- struct.c | 73 +- time.c | 58 +- top.sed | 30 +- util.c | 405 ++++++++- variable.c | 351 +++++--- version.c | 7 +- version.h | 4 +- win32/Makefile | 233 ++++++ win32/config.h | 60 ++ win32/ntsetup.bat | 10 + win32/ruby.def | 6 + x68/_dtos18.c | 250 ++++++ x68/_round.c | 45 + x68/fconvert.c | 81 ++ x68/select.c | 167 ++++ 143 files changed, 16418 insertions(+), 4198 deletions(-) create mode 100644 ext/Setup.nt create mode 100644 ext/Setup.x68 create mode 100644 ext/aix_ld.rb create mode 100644 ext/curses/MANIFEST create mode 100644 ext/curses/curses.c create mode 100644 ext/curses/extconf.rb create mode 100644 ext/curses/hello.rb create mode 100644 ext/curses/rain.rb create mode 100644 ext/curses/view.rb create mode 100644 ext/extmk.rb.nt create mode 100644 ext/fcntl/MANIFEST create mode 100644 ext/fcntl/depend create mode 100644 ext/fcntl/fcntl.c create mode 100644 ext/kconv/depend create mode 100644 lib/English.rb create mode 100644 lib/date.rb create mode 100644 lib/debug.rb create mode 100644 lib/e2mmap.rb create mode 100644 lib/e2mmap1_0.rb create mode 100644 lib/finalize.rb create mode 100644 lib/ftplib.rb create mode 100644 lib/matrix.rb create mode 100644 lib/mutex_m.rb create mode 100644 lib/ping.rb delete mode 100644 lib/safe.rb create mode 100644 lib/sync.rb create mode 100644 lib/thwait.rb create mode 100644 lib/tracer.rb create mode 100644 missing/dir.h create mode 100644 missing/file.h create mode 100644 missing/strcasecmp.c delete mode 100644 sample/dbm.rb create mode 100644 sample/dbmtest.rb delete mode 100644 sample/marshal.rb create mode 100644 sample/mrshtest.rb create mode 100644 sample/rubydb2x.el create mode 100644 sample/rubydb3x.el create mode 100644 win32/Makefile create mode 100644 win32/config.h create mode 100644 win32/ntsetup.bat create mode 100644 win32/ruby.def create mode 100644 x68/_dtos18.c create mode 100644 x68/_round.c create mode 100644 x68/fconvert.c create mode 100644 x68/select.c 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 + + * version 1.0-971002 + +Wed Oct 1 14:01:49 1997 WATANABE Hirofumi + + * ext/marshal/marshal.c (w_byte): argument must be char. + +Wed Oct 1 10:30:22 1997 Yukihiro Matsumoto + + * 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 + + * version 1.0-970930 + +Fri Sep 30 14:29:22 1997 WATANABE Hirofumi + + * ext/marshal/marshal.c (w_object): marshal dumped core. + +Tue Sep 30 10:27:39 1997 Yukihiro Matsumoto + + * sample/test.rb: bignum test suits added. + +Mon Sep 29 13:37:58 1997 Yukihiro Matsumoto + + * ruby.c (forbid_setid): forbid some options in suid mode. + +Mon Sep 27 09:53:48 1997 EGUCHI Matsumoto + + * bignum.c: modified for speeding. + +Fri Sep 26 18:27:59 1997 WATANABE Hirofumi + + * sample/from.rb: some extensions. + +Mon Sep 29 13:15:56 1997 Yukihiro Matsumoto + + * parse.y (lhs): no more syntax error on `obj.CONSTANT = value'. + +Fri Sep 26 14:41:46 1997 Yukihiro Matsumoto + + * eval.c (ruby_run): deferred calling Init_ext() just before eval_node. + +Fri Sep 26 13:27:24 1997 WATANABE Hirofumi + + * io.c (io_isatty): forgot to return TRUE value. + +Fri Sep 25 11:10:58 1997 EGUCHI Osamu + + * eval.c: use _setjmp/_longjmp instead of setjmp/longjmp on some + platforms. + +Wed Sep 24 17:43:13 1997 Yukihiro Matsumoto + + * string.c (Init_String): String#taint and String#taint? added. + +Wed Sep 24 00:57:00 1997 Katsuyuki Okabe + + * X68000 patch. + +Tue Sep 23 20:42:30 1997 EGUCHI Osamu + + * parse.y (node_newnode): SEGV on null node setup. + +Mon Sep 22 11:22:46 1997 Yukihiro Matsumoto + + * ruby.c (ruby_prog_init): wrong safe condition check. + +Sun Sep 21 14:46:02 1997 MAEDA shugo + + * error.c (exc_inspect): garbage added to classpath. + +Fri Sep 19 11:49:23 1997 + + * 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 + + * 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 + + * regex.c (re_compile_pattern): \w{3} and \W{3} did not work. + +Thu Sep 11 10:31:48 1997 Yukihiro Matsumoto + + * 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 + + * version 1.0-970910 + + * ext/marshal/marshal.c (r_bytes0): extra big length check. + +Tue Sep 9 16:27:14 1997 Yukihiro Matsumoto + + * 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 + + * 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 + + * version 1.0-970903 + + * eval.c (f_load): expand path if fname begins with `~'. + +Mon Sep 1 13:42:48 1997 Yukihiro Matsumoto + + * eval.c (rb_call): alias occured in the module body caused SEGV. + +Fri Aug 29 11:10:21 1997 Yukihiro Matsumoto + + * 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 + + * parse.y (yylex): revised `=begin' skip code. + + * eval.c (is_defined): separated from rb_eval(). + +Wed Aug 27 11:32:42 1997 Yukihiro Matsumoto + + * 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 + + * 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 + + * 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 + + * eval.c (error_print): modified exception print format. + +Thu Aug 21 16:10:58 1997 Yukihiro Matsumoto + + * sample/ruby-mode.el (ruby-calculate-indent): wrong indent level + calculated with keyword operators. + +Thu Aug 21 11:55:41 1997 Yukihiro Matsumoto + + * version 1.0-970821 + +Thu Aug 21 11:36:58 1997 WATANABE Hirofumi + + * parse.y (arg): ary[0] += 1 cause SEGV + +Wed Aug 20 14:24:42 1997 Yukihiro Matsumoto + + * version 1.0-970820 + + * eval.c (rb_call): infinite loop bug + +Tue Aug 19 00:15:38 1997 Yukihiro Matsumoto + + * 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 + + * 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 + + * object.c (class_s_new): do not make subclass of singleton class. + +Fri Aug 15 15:49:46 1997 Yukihiro Matsumoto + + * 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 + + * ext/socket/socket.c (Init_socket): small typo caused SEGV. + +Tue Aug 12 16:02:18 1997 Yukihiro Matsumoto + + * 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 + + * 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 + + * 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 + + * object.c (Init_Object): remove private_attr/public_attr. + +Wed Aug 6 14:21:36 1997 Yukihiro Matsumoto + + * object.c (mod_attr): forgot to check nil for false value. + +Mon Aug 4 11:50:28 1997 Yukihiro Matsumoto + + * 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 + + * eval.c (rb_eval): stop to cache const value in nodes. + +Sat Jul 26 03:17:22 1997 WATANABE Hirofumi + + * numeric.c (flo_to_s): wrong .0 at end. + +Sat Jul 26 00:36:36 1997 Yukihiro Matsumoto + + * 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 + + * string.c (uscore_get): proper error message for unset $_. + +Wed Jul 23 09:56:55 1997 Yukihiro Matsumoto + + * 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 + + * 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 + + * 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 + + * Native mswin32 support. + +Tue Jul 1 09:59:00 1997 Yukihiro Matsumoto + + * version 1.0-970701 + + * parse.y (mrhs): allow rest-star(*) in right hand side. + +Tue Jun 24 19:04:31 1997 Yukihiro Matsumoto + + * version 1.0-970624 + +Sat Jun 20 22:22:51 1997 Michio "Karl" Jinbo + + * eval.c: freebsd 3.0 support. + +Fri Jun 20 01:24:45 1997 Yukihiro Matsumoto + + * 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 + + * version 1.0-970619 + + * string.c (str_split_method): wrong limit. + +Sat Jun 14 01:54:16 1997 Yukihiro Matsumoto + + * 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 + + * array.c (sort_2): wrong comparison. + +Sat Jun 14 00:53:44 1997 Yukihiro Matsumoto + + * hash.c (hash_foreach): safe iteration. + +Fri Jun 13 14:04:56 1997 Michio "Karl" Jinbo + + * configure.in: -Bshareable option for netbsd. + +Fri Jun 13 01:16:22 1997 WATANABE Hirofumi + + * io.c (pipe_open): call io_unbuffered() only for writable pipes. + +Thu Jun 12 01:14:15 1997 Yukihiro Matsumoto + + * 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 + + * gc.c (rb_newobj): remove needless memset(). + +Mon Jun 9 13:03:43 1997 Yukihiro Matsumoto + + * 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 + + * 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 + + * 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 + + * 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 + + * version 1.0-970528 + + * process.c (rb_waitpid): do not block other threads. + +Tue May 27 12:02:31 1997 Yukihiro Matsumoto + + * 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 + + * variable.c (rb_ivar_set): invalid instance variable access for + built-in object raises TypeError. + +Fri May 16 17:32:21 1997 Yukihiro Matsumoto + + * 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 + + * 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 + + * file.c (file_s_dirname): need to return "." for path without + slashes. + +Wed May 7 19:18:48 1997 Yukihiro Matsumoto + + * 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 + + * ext/curses/curses.c: modified for portability and add to the + standard distribution. + +Wed Apr 30 00:34:00 1997 Yukihiro Matsumoto + + * file.c (file_s_size): returns 0 for empty files (not FALSE). + +Fri Apr 25 02:17:50 1997 Yukihiro Matsumoto + + * 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 + + * 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 + + * version 1.0-970422 + +Thu Apr 17 00:40:51 1997 Yukihiro Matsumoto + + * configure.in (rb_cv_bsdpgrp): proper check for BSD + setpgrp/setpgrp. + +Wed Apr 16 16:14:02 1997 Yukihiro Matsumoto + + * eval.c (proc_call): proc called in other thread must be orphan. + +Tue Apr 15 10:46:31 1997 Yukihiro Matsumoto + + * 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 + + * version 1.0-970414 + +Fri Apr 12 01:20:12 1997 Yukihiro Matsumoto + + * ruby.h: String pointer changed to unsigned char. + +Fri Apr 11 10:27:29 1997 Yukihiro Matsumoto + + * 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 + + * 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 + + * ruby.c: forgot to include 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 + + * io.c (arg_read): bug with 0 length input. + +Mon Apr 7 11:36:16 1997 Yukihiro Matsumoto + + * 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 + + * version 1.0-970404 + + * gc.c (obj_free): finalizer added for experiment. + +Thu Apr 3 02:12:31 1997 Yukihiro Matsumoto + + * 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 + + * 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 + + * 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 + + * version 1.0-970331 + +Sun Mar 30 19:40:57 1997 WATANABE Hirofumi + + * parse.y (terms): avoided win32 gcc's optimization bug. + +Sat Mar 29 11:21:58 1997 Yukihiro Matsumoto + + * struct.c (make_struct): St[val,..] creates new structure. + +Fri Mar 28 11:24:51 1997 Yukihiro Matsumoto + + * 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 + + * pack.c (pack_unpack): extra null byte after unpacked string. + +Wed Mar 26 15:20:34 1997 Yukihiro Matsumoto + + * 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 + + * 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 + + * version 1.0-970324 + +Thu Mar 20 22:04:59 1997 Yukihiro Matsumoto + + * eval.c (mod_modfunc): forget to clear method cache. + +Wed Mar 19 17:06:55 1997 Yukihiro Matsumoto + + * 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 + + * 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 + + * 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 + + * 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 + + * ext/socks/socks.c: socket module with socks library. + +Mon Mar 10 20:44:22 1997 Yukihiro Matsumoto + + * re.c (reg_regsub): \& for substitution. \`, \', and \+ are + avaiable also. + +Thu Mar 6 01:47:03 1997 Yukihiro Matsumoto + + * 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 + + * version 1.0-970305 + +Tue Mar 4 12:28:32 1997 Yukihiro Matsumoto + + * ruby.c (proc_options): search through RUBYPATH and PATH for + option -S. + +Mon Mar 3 22:44:55 1997 Yukihiro Matsumoto + + * 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 + + * eval.c (rb_eval): restore $! value after rescue clause, to + re-raise exceptions correctly. + +Fri Feb 28 16:43:38 1997 Yukihiro Matsumoto + + * version 1.0-970228 + +Thu Feb 27 11:23:41 1997 Yukihiro Matsumoto + + * 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 + + * eval.c (eval): forgot to restore dynamic local variable + bindings. + +Tue Feb 25 11:22:08 1997 Yukihiro Matsumoto + + * 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 + + * 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 + + * version 1.0-970220 + +Thu Feb 20 11:25:50 1997 Yasuo OHBA + + * lib/date.rb: update + +Thu Feb 20 08:25:57 1997 Yukihiro Matsumoto + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * ruby.h (Data_Make_Struct): rename macros. + +Sun Feb 8 11:48:13 1997 Yukihiro Matsumoto + + * io.c (f_syscall): argument offset was wrong. + +Fri Feb 7 18:01:17 1997 Yukihiro Matsumoto + + * 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 + + * 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 + + * 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 + + * hash.c (hash_rehash): re-register all key-value. + +Thu Jan 30 02:14:49 1997 Yukihiro Matsumoto + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * util.c (_fixpath): supports SJIS filenames on DJGPP. + +Thu Jan 23 16:52:06 1997 Yukihiro Matsumoto + + * 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 + + * eval.c (Init_Thread): allocate main_thread first to avoid crash. + +Thu Jan 23 02:09:26 1997 Yukihiro Matsumoto + + * 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 + + * 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 + + * eval.c (thread_run): no context switch in the critical section. + +Mon Jan 20 09:40:59 1997 WATANABE Hirofumi + + * utils.c: supports 8+3 filenames + +Sat Jan 18 01:23:03 1997 Yukihiro Matsumoto + + * 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 + + * 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 + + * 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 + + * 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 + + * eval.c (thread_create): threadޤdzߤꤷʤ + + * eval.c (Init_Thread): ߥߥ󥰤100msec + +Sat Jan 11 00:17:05 1997 Yukihiro Matsumoto + + * 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 + + * 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 + + * string.c (str_sub_s): ʸĹĹoffsetθ + + * regex.c (re_search): ˥ޥåѥ$Ǽ + +Thu Jan 2 16:36:23 1997 Yukihiro Matsumoto + + * file.c (file_reopen): Filereopen(pathޤIOǻ) + + * io.c (io_reopen): IOreopen(IOǻ) -- change classĤ + +Wed Jan 1 11:09:01 1997 Yukihiro Matsumoto + + * io.c (f_select): timeoutnil֤ + +Fri Dec 27 13:06:44 1996 Yukihiro Matsumoto + + * 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 + + * lib/tk.rb: placeȤ褦 + + * pack.c (endian): ޥDYNAMIC_ENDIANꤹȼ¹Իendian + Ƚꤹ褦ˡ + + * eval.c (thread_alloc): ˺ΥФä + Wed Dec 25 00:33:19 1996 Yukihiro Matsumoto * version 1.0-961225 @@ -208,7 +1397,7 @@ Fri Nov 29 12:17:59 1996 Yukihiro Matsumoto * 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 * pack.c (pack_unpack): βԤʤˤå򥹥 פ褦 -Wed Nov 20 96 21:42:51 1996 Yasuo OHBA +Wed Nov 20 96 21:42:51 1996 Yasuo OHBA 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 . +Ruby is copyrighted by Yukihiro Matsumoto . 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 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 ǤϽ˾Ҳ𤷤ޤ -2.1.1 饹/⥸塼 +2.1.1 Class/module definition 饹⥸塼뤿ˤϡʲδؿȤޤ VALUE rb_define_class(char *name, VALUE super) - VALUE rb_define_module(char *name) + VALUE rb_define_module(char *name) δؿϿ줿饹⥸塼֤ޤ ᥽åɤˤͤɬפʤΤǡۤȤɤξ ͤѿ˳ǼƤɬפǤ礦 -2.1.2 ᥽å/ðۥ᥽å +2.1.2 Method/singleton method definition ᥽åɤðۥ᥽åɤˤϰʲδؿȤޤ void rb_define_method(VALUE class, char *name, VALUE (*func)(), int argc) - void rb_define_sigleton_method(VALUE object, char *name, + void rb_define_singleton_method(VALUE object, char *name, VALUE (*func)(), int argc) @@ -282,10 +284,16 @@ private ȤǤȤޤ⥸塼ؿؿϰʲ ̤Ǥ - void rb_define_module_method(VALUE module, char *name, - VALUE (*func)(), int argc) + void rb_define_module_function(VALUE module, char *name, + VALUE (*func)(), int argc) + +ؿŪ᥽å(Kernel⥸塼privaet method)뤿 +δؿϰʲ̤Ǥ + + void rb_define_global_function(char *name, VALUE (*func)(), int argc) + -2.1.3 +2.1.3 Constant definition ĥ⥸塼뤬ɬפϤ餫Ƥɤ Ǥ礦ؿĤޤ @@ -296,7 +304,7 @@ private ԤΥ饹/⥸塼°Ρ ԤϥХΤǤ -2.2 rubyεǽCƤӽФ +2.2 Use ruby features from C ˡ1.5 rubyΥǡ٤ǰҲ𤷤褦ʴؿ ȤСrubyεǽ¸ƤؿľܸƤӽФȤ @@ -315,9 +323,9 @@ C 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 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 @@ id 饹򿷤뤿ˤϡ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 @@ C 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 @@ C δؿˤä줿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 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 塼ѤΥǥ쥯ȥޤ̾Ŭǹ -(2) MANIFESTե +(2) create MANIFEST file % cd ext/dbm % touch MANIFEST @@ -485,14 +506,14 @@ ruby 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 ȤؤƤ硤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 ʲξˤƤޤ - 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 Ruby˴ؤΤΥᥤ󥰥ꥹȤߤޤ ɥ쥹 - ruby-list@caelum.co.jp + ruby-list@netlab.co.jp ǤΥɥ쥹˥ᥤСưŪϿޤ @@ -133,9 +124,9 @@ UNIX ʤŪǤ켫ͳǤ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 * -ȡХݡȤ¾ 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; { @@ -518,6 +538,18 @@ ary_each_index(ary) return Qnil; } +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; ilen) { MEMCPY(ary2->ptr+i, ary->ptr, VALUE, ary->len); } @@ -961,22 +1021,35 @@ ary_equal(ary1, ary2) return TRUE; } +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; ilen; 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; ilen; 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;ilen;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); @@ -430,6 +438,14 @@ big_cmp(x, y) (x->sign ? INT2FIX(-1) : INT2FIX(1)); } +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 #include -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 ], [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 ], [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 +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 +#include +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 # endif # ifdef NT -# include "missing/dirent.h" +# include "missing/dir.h" # endif #endif #include +#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 +#ifndef NT #include +#else +#include "missing/file.h" +#endif #include #include @@ -49,9 +53,11 @@ void *xrealloc(); # include #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 @@ -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 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 @@ -44,6 +53,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; @@ -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 void module_setup(); +static VALUE module_setup(); -static VALUE masign(); -static void asign(); +static VALUE massign(); +static void assign(); -extern VALUE rb_stderr; +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; +} + +void +rb_set_safe_level(level) + int level; +{ + if (level > safe_level) { + safe_level = level; + } +} + +static VALUE +safe_getter() +{ + return INT2FIX(safe_level); +} + +static void +safe_setter(val) + VALUE val; +{ + int level = NUM2INT(val); + + 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;ind_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,172 +2008,80 @@ 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; case NODE_MODULE: - { - 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) - TypeError("%s is not a module", rb_id2name(node->nd_cname)); - Warning("extending module %s", rb_id2name(node->nd_cname)); - } - else { - module = rb_define_module_id(node->nd_cname); - rb_const_set(the_class, node->nd_cname, module); - rb_set_class_path(module,the_class,rb_id2name(node->nd_cname)); - } - - module_setup(module, node->nd_body); - result = module; - } - break; - - case NODE_DEFINED: - { - 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; + { + VALUE module; - case NODE_CVAR: - if (ev_const_defined(the_frame->cbase, node->nd_vid)) { - case NODE_CONST: /* jump in */ - desc = "class-constant"; - } - break; + if (rb_const_defined_at(the_class, node->nd_cname) && + ((VALUE)the_class != cObject || + !rb_autoload_defined(node->nd_cname))) { - case NODE_COLON2: - PUSH_TAG(); - if ((state = EXEC_TAG()) == 0) { - obj = rb_eval(self, node->nd_head); - } - POP_TAG(); - if (state) { - break; + 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)); } - 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; - } + if (safe_level >= 4) { + Raise(eSecurityError, "extending module prohibited"); } - break; + Warning("extending module %s", rb_id2name(node->nd_cname)); + } + else { + module = rb_define_module_id(node->nd_cname); + rb_const_set(the_class, node->nd_cname, module); + rb_set_class_path(module,the_class,rb_id2name(node->nd_cname)); + } - 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(module, 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_SCLASS: + { + VALUE class; - default: - PUSH_TAG(); - if ((state = EXEC_TAG()) == 0) { - rb_eval(self, node); - } - POP_TAG(); - if (state) break; - else { - desc = "expression"; - } + 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); + + result = module_setup(class, node->nd_body); + } + break; + + case NODE_DEFINED: + { + char buf[20]; + char *desc = is_defined(self, node, buf); + 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 && ind_head, RARRAY(val)->ptr[i]); + assign(self, list->nd_head, RARRAY(val)->ptr[i]); list = list->nd_next; } if (node->nd_args) { if (!list && ind_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) { 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 @@ -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; ilen; 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;ilen;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; ind_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; ilen;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_global_function("trace_var", f_trace_var, -1); + rb_define_global_function("untrace_var", f_untrace_var, -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("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; + 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 BLOCK from data */ - PUSH_BLOCK2(data); - PUSH_ITER(ITER_CUR); - the_frame->iter = ITER_CUR; 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 -#endif +static VALUE eThreadError; int thread_pending = 0; static VALUE cThread; #include -#include +#ifdef HAVE_SYS_TIME_H +# include +#else +#ifndef NT +struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* and microseconds */ +}; +#endif /* NT */ +#endif #include #include +#ifdef HAVE_SYS_SELECT_H +#include +#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_wakeup(thread); + if (!thread_critical) thread_schedule(); + + return thread; +} + +static VALUE +thread_kill(thread) + VALUE thread; { - thread_t th = thread_check(data); + thread_t th = thread_check(thread); - if (th->status == THREAD_TO_KILL) return Qnil; - if (th->status == THREAD_KILLED) return Qnil; + 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(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() +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); - return thread_dead(th)?FALSE:TRUE; + if (thread_dead(th)) { + if (NIL_P(th->errinfo)) return FALSE; + return Qnil; + } + + 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 +#else +# ifdef HAVE_NCURSES_CURSES_H +# include +# else +# include +# 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 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 + +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;isymbol, 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; iptr[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 sizeof(long)) long_toobig((int)c); + x = -1; + for (i=0;ifp) { + 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; iptr[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 #endif +#if defined(THREAD) && defined(HAVE_FCNTL) +#ifdef HAVE_SYS_SELECT_H +#include +#endif +#include +#include +#include +#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; @@ -495,6 +754,15 @@ tcp_peeraddr(sock) return tcpaddr(&addr); } +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; @@ -546,6 +814,15 @@ unix_svr_s_open(class, path) return open_unix(class, path, 1); } +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 @@ -22,13 +22,6 @@ tk_eval_cmd(argc, argv) return Qnil; } -static VALUE -tk_yield(obj) - VALUE obj; -{ - rb_yield_0(obj, obj); -} - static VALUE tk_s_new(argc, argv, class) int argc; @@ -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 #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 +#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 @@ -102,9 +163,12 @@ apply2files(func, args, arg) int i; VALUE path; + for (i=0; ilen; i++) { + Check_SafeStr(args->ptr[i]); + } + for (i=0; ilen; 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 +#ifndef NT #include +#else +#include "missing/file.h" +#endif #include 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 +# 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"); } @@ -1341,31 +1457,19 @@ file_truncate(obj, len) return TRUE; } -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; ilen == 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 #include +#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; ilen; 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 +# endif /* !NT */ # endif /* !USG */ #endif /* !HAVE_DIRENT_H */ @@ -68,7 +72,9 @@ # include #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 @@ -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; iptr[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;iptr); + } + 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 #include -#ifndef DJGPP +#if !defined(DJGPP) && !defined(NT) && !defined(__human68k__) #include #endif +#if defined(HAVE_FCNTL) +#include +#endif #ifdef HAVE_SYS_TIME_H # include #else +#ifndef NT struct timeval { long tv_sec; /* seconds */ long tv_usec; /* and microseconds */ }; #endif +#endif #ifdef HAVE_VFORK_H #include #endif #include -#ifdef DJGPP +#if defined(DJGPP) || defined(__CYGWIN32__) || defined(NT) || defined(__human68k__) #include #endif +#ifdef HAVE_SYS_PARAM_H +# include +#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 @@ -453,6 +478,21 @@ io_readline(argc, argv, io) return line; } +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; @@ -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 #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; @@ -1668,6 +2058,17 @@ arg_getc() return byte; } +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; @@ -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 + +### 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 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 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", @id + end + + def to_a + list(value) + end end class TkWindow'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", 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 TkTextMarkal += $_ + 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 + +#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 #include #include -#include +/* #include */ +#include +#include +#include #include -bool NtSyncProcess = FALSE; +#include +#include +#include +#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 +// #include conflict with varargs.h? +// There is function-name conflitct, so we rename it +#if !defined(IN) && !defined(FLOAT) +#define OpenFile WINAPI_OpenFile #include +#include +#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 -#include +#include +#include +#include #include #include #include #include +#include +#include #include // @@ -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 + +#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)<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 +#if defined (HAVE_STRING_H) +# include +#else +# include +#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; @@ -384,6 +387,15 @@ flo_cmp(x, y) return INT2FIX(-1); } +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 -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"); } @@ -251,13 +261,6 @@ obj_s_added(obj, id) return Qnil; } -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>= 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 (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 (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> 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 literal numeric %type compexpr exprs expr arg primary command_call method_call %type if_tail opt_else case_body cases rescue ensure iterator -%type call_args call_args0 args args2 opt_args var_ref +%type call_args call_args0 ret_args args mrhs opt_args var_ref %type superclass f_arglist f_args f_optarg f_opt %type array assoc_list assocs assoc undef_list %type 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($2); } @@ -953,6 +1065,7 @@ iter_block : '{' compexpr '}' { $$ = NEW_ITER($3, 0, $4); + fixpos($$, $3?$3:$4); dyna_pop($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 #include #include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifndef NT #ifdef HAVE_SYS_TIME_H # include #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 @@ -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; iptr; } args[i] = 0; @@ -273,14 +341,33 @@ 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,11 +589,32 @@ 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; iptr; 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; @@ -204,45 +273,13 @@ make_regexp(s, len) 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; inum_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; inum_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<> 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; } - 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< 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 +#include #include #include @@ -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 +#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 @@ -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<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 [ for Systemdate] (YYYYMMDD) : ") - dtmp = STDIN.gets.chop + printf(STDERR, "Date [ 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/dbm.rb deleted file mode 100644 index c77cc2065b..0000000000 --- a/sample/dbm.rb +++ /dev/null @@ -1,14 +0,0 @@ -# ruby dbm acess -require "dbm" - -d = DBM.open("test") -keys = d.keys -if keys.length > 0 then - for k in keys; print k, "\n"; end - for v in d.values; print v, "\n"; end -else - d['foobar'] = 'FB' - d['baz'] = 'BZ' - d['quux'] = 'QX' -end - diff --git a/sample/dbmtest.rb b/sample/dbmtest.rb new file mode 100644 index 0000000000..c77cc2065b --- /dev/null +++ b/sample/dbmtest.rb @@ -0,0 +1,14 @@ +# ruby dbm acess +require "dbm" + +d = DBM.open("test") +keys = d.keys +if keys.length > 0 then + for k in keys; print k, "\n"; end + for v in d.values; print v, "\n"; end +else + d['foobar'] = 'FB' + d['baz'] = 'BZ' + d['quux'] = 'QX' +end + 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/marshal.rb deleted file mode 100644 index 3d399ffe68..0000000000 --- a/sample/marshal.rb +++ /dev/null @@ -1,13 +0,0 @@ -require "marshal" -include Marshal -a = 25.6; -pt = Struct.new('point', :x,:y); -x = pt.new(10, 10) -y = pt.new(20, 20) -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 diff --git a/sample/mrshtest.rb b/sample/mrshtest.rb new file mode 100644 index 0000000000..402b35ad55 --- /dev/null +++ b/sample/mrshtest.rb @@ -0,0 +1,14 @@ +require "marshal" +include Marshal +a = 25.6; +pt = Struct.new('Point', :x,:y); +x = pt.new(10, 10) +y = pt.new(20, 20) +rt = Struct.new('Rectangle', :origin,:corner); +z = rt.new(x, y) +c = Object.new +s = [a, x, z, c, c, "fff"]; +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<> 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(/.*\.([^\.]+)$/, '<\&>') == "") + # 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 #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,10 +455,12 @@ 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 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 (tptr; + 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 (tptr; + + unsigned_format: + slen = len = strlen(s); + pos = blen; + if (flags&FWIDTH) { + if (width <= len) flags &= ~FWIDTH; + else { + slen = width; } - if (base == 2) { - while (t= slen) { + flags &= ~FWIDTH; + slen = prec; + } } - while (t 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) @@ -354,6 +326,47 @@ st_delete(table, key, value) return 0; } +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; 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; ilen*len); + for (i=0; iptr+(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)) @@ -267,10 +319,29 @@ str_dup_freezed(str) return 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); @@ -988,6 +1072,18 @@ str_gsub(argc, argv, str) return v; } +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; @@ -995,8 +1091,7 @@ f_sub_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, 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; ptrptr[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; ilen; 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; ilen; 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); @@ -365,16 +379,33 @@ struct_equal(s, s2) return TRUE; } +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; ilen; 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; ilen; 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 +#ifdef HAVE_STRING_H +# include +#endif + #include +#ifndef NT #ifdef HAVE_SYS_TIME_H # include #else @@ -22,6 +27,7 @@ struct timeval { long tv_usec; /* and microseconds */ }; #endif +#endif /* NT */ #ifdef HAVE_SYS_TIMES_H #include @@ -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; @@ -337,6 +350,22 @@ time_cmp(time1, time2) return FIX2INT(-1); } +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 @@ -55,3 +54,405 @@ int *retlen; *retlen = s - start; return retval; } + +#if defined(MSDOS) || defined(__CYGWIN32__) || defined(NT) +#include +/* + * 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 +#include /* For FILENAME_MAX */ +#include /* For errno */ +#include /* For tolower */ +#include /* For strlen() */ +#include /* For LFN stuff */ +#include +#include /* For dpmisim */ +#include /* For crt0 flags */ +#include +#include + +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 +#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 (pathclass; - 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,11 +770,57 @@ 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; @@ -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 -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 +#include + +/* +** ܴؿưѴƤʸˤ뤿ᡢŪˤ +** ˳ǼǤޤǤȤǤʤäƺǹ +** 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 +#include + +/* 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 +#include + +/* 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 +#include +#include +#include +#include +#include +#include +#if 0 +#include +#include +#endif +#include + +/* 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 (); + } +} -- cgit v1.2.3