From 278b96ff97878af2ee4281596214f396cd57d00f Mon Sep 17 00:00:00 2001 From: "(no author)" <(no author)@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> Date: Tue, 17 Apr 2001 15:35:46 +0000 Subject: This commit was manufactured by cvs2svn to create tag 'v1_6_4_preview2'. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/tags/v1_6_4_preview2@1327 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- .cvsignore | 27 +- ChangeLog | 892 +++++++++++++++++++++++++++++++++++- Makefile.in | 5 +- README | 23 +- README.jp | 16 +- array.c | 2 +- bignum.c | 18 +- class.c | 75 ++- configure.in | 62 ++- cygwin/GNUmakefile.in | 2 +- dir.c | 76 ++- djgpp/config.status | 77 ---- dln.c | 31 +- dln.h | 2 +- error.c | 7 + eval.c | 679 ++++++++++++++++++--------- ext/.cvsignore | 1 + ext/Win32API/Win32API.c | 6 - ext/Win32API/extconf.rb | 2 +- ext/curses/.cvsignore | 1 + ext/curses/curses.c | 8 +- ext/curses/extconf.rb | 4 + ext/dbm/.cvsignore | 1 + ext/etc/.cvsignore | 1 + ext/extmk.rb.in | 34 +- ext/fcntl/.cvsignore | 1 + ext/gdbm/.cvsignore | 1 + ext/md5/.cvsignore | 1 + ext/nkf/.cvsignore | 1 + ext/pty/.cvsignore | 1 + ext/pty/extconf.rb | 16 +- ext/readline/.cvsignore | 1 + ext/readline/extconf.rb | 3 + ext/readline/readline.c | 9 +- ext/sdbm/.cvsignore | 1 + ext/sdbm/_sdbm.c | 4 +- ext/socket/.cvsignore | 1 + ext/tcltklib/.cvsignore | 1 + ext/tk/.cvsignore | 1 + ext/tk/lib/tk.rb | 143 ++++-- ext/tk/lib/tkcanvas.rb | 8 +- ext/tk/lib/tkentry.rb | 2 +- ext/tk/lib/tktext.rb | 8 + ext/tk/lib/tkvirtevent.rb | 33 +- file.c | 171 ++++--- gc.c | 118 ++--- hash.c | 9 +- intern.h | 6 +- io.c | 39 +- lib/Env.rb | 14 +- lib/cgi.rb | 232 ++-------- lib/cgi/session.rb | 15 +- lib/date.rb | 38 +- lib/debug.rb | 210 +++++++-- lib/delegate.rb | 2 +- lib/importenv.rb | 6 +- lib/irb/ruby-lex.rb | 2 +- lib/mkmf.rb | 53 ++- lib/monitor.rb | 96 ++-- lib/net/http.rb | 1118 +++++++++++++++++++++++++-------------------- lib/net/imap.rb | 487 +++++++++++++++++++- lib/net/pop.rb | 13 +- lib/net/protocol.rb | 309 ++++++++----- lib/net/smtp.rb | 29 +- lib/net/telnet.rb | 217 +-------- lib/observer.rb | 2 +- lib/parsedate.rb | 11 +- lib/ping.rb | 2 + lib/thread.rb | 2 +- marshal.c | 12 +- math.c | 5 + misc/ruby-mode.el | 2 +- missing/dir.h | 5 +- missing/flock.c | 120 +++-- missing/strftime.c | 6 - missing/vsnprintf.c | 6 +- mkconfig.rb | 17 +- node.h | 14 +- numeric.c | 2 +- object.c | 41 +- pack.c | 8 +- parse.y | 365 ++++++++------- prec.c | 2 +- re.c | 14 +- regex.c | 15 +- ruby.c | 29 +- ruby.h | 37 +- sample/README | 3 - signal.c | 16 +- sprintf.c | 2 +- string.c | 39 +- time.c | 17 +- util.c | 38 +- variable.c | 17 +- version.h | 8 +- win32/Makefile.sub | 4 +- win32/config.h.in | 1 + win32/config.status.in | 4 +- win32/win32.c | 91 +++- win32/win32.h | 2 + 100 files changed, 4207 insertions(+), 2224 deletions(-) delete mode 100644 djgpp/config.status create mode 100644 ext/.cvsignore create mode 100644 ext/curses/.cvsignore create mode 100644 ext/dbm/.cvsignore create mode 100644 ext/etc/.cvsignore create mode 100644 ext/fcntl/.cvsignore create mode 100644 ext/gdbm/.cvsignore create mode 100644 ext/md5/.cvsignore create mode 100644 ext/nkf/.cvsignore create mode 100644 ext/pty/.cvsignore create mode 100644 ext/readline/.cvsignore create mode 100644 ext/sdbm/.cvsignore create mode 100644 ext/socket/.cvsignore create mode 100644 ext/tcltklib/.cvsignore create mode 100644 ext/tk/.cvsignore diff --git a/.cvsignore b/.cvsignore index 8fcaffddb2..35fff17b58 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1,19 +1,20 @@ -parse.c -newver.rb -ruby -miniruby +*.bak +*.orig +*.rej +*.sav +*~ +.cvsignore +Makefile README.fat-patch -configure +archive config.cache config.h config.log config.status -Makefile +configure +miniruby +newver.rb +parse.c ppack -archive -extmk.rb -*.orig -*.rej -*.bak -*.sav -*~ +rbconfig.rb +ruby diff --git a/ChangeLog b/ChangeLog index c6cd432b49..ee862e9723 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,854 @@ +Wed Apr 18 00:24:40 2001 Yukihiro Matsumoto + + * regex.c (re_compile_pattern): char class at either edge of range + should be invalid. + +Tue Apr 17 16:54:39 2001 K.Kosako + + * eval.c (safe_getter): should use INT2NUM(). + +Tue Apr 17 15:12:56 2001 Yukihiro Matsumoto + + * bignum.c (rb_big2long): 2**31 cannot fit in 31 bit long. + +Sat Apr 14 22:46:43 2001 Guy Decoux + + * regex.c (calculate_must_string): wrong length calculation. + +Sat Apr 14 13:33:32 2001 Usaku Nakamura + + * win32/config.status.in: no longer use missing/alloca.c. + + * win32/Makefile.sub: ditto. + +Fri Apr 13 12:40:48 2001 K.Kosako + + * eval.c (rb_thread_start_0): fixed memory leak. + +Fri Apr 13 16:41:18 2001 Yukihiro Matsumoto + + * parse.y (none): should clear cmdarg_stack too. + +Fri Apr 13 06:19:29 2001 GOTOU YUUZOU + + * io.c (rb_fopen): use setvbuf() to avoid recursive malloc() on + some platforms. + +Wed Apr 11 23:36:26 2001 Yukihiro Matsumoto + + * file.c (rb_stat_dev): device functions should honor stat field + types (except long long such as dev_t). + +Wed Apr 11 18:07:53 2001 K.Kosako + + * eval.c (rb_mod_nesting): should not push nil for nesting array. + + * eval.c (rb_mod_s_constants): should not search array by + rb_mod_const_at() for nil (happens for singleton class). + +Wed Apr 11 13:29:26 2001 Yukihiro Matsumoto + + * class.c (rb_singleton_class_attached): should modify iv_tbl by + itself, no longer use rb_iv_set() to avoid freeze check error. + + * variable.c (rb_const_get): error message "uninitialized constant + Foo at Bar::Baz" instead of "uninitialized constantBar::Baz::Foo". + +Tue Apr 10 02:24:40 2001 Nobuyoshi Nakada + + * io.c (opt_i_set): should strdup() inplace_edit string. + +Mon Apr 9 23:29:54 2001 Yukihiro Matsumoto + + * eval.c (exec_under): need to push cref too. + +Mon Apr 9 12:05:44 2001 Yukihiro Matsumoto + + * file.c (Init_File): should redifine "new" class method. + +Mon Apr 9 11:56:52 2001 Shugo Maeda + + * lib/net/imap.rb: fix typo. + +Thu Apr 5 22:40:12 2001 Yukihiro Matsumoto + + * variable.c (rb_const_get): no recursion to show full class path + for modules. + + * eval.c (rb_set_safe_level): should set safe level in curr_thread + as well. + + * eval.c (safe_setter): ditto. + +Thu Apr 5 13:46:06 2001 K.Kosako + + * object.c (rb_obj_is_instance_of): nil belongs to false, not true. + +Thu Apr 5 02:19:03 2001 Yukihiro Matsumoto + + * time.c (make_time_t): proper (I hope) daylight saving time + handling for both US and Europe. I HATE SUMMER TIME! + + * eval.c (rb_thread_wait_for): non blocked signal interrupt should + stop the interval. + +Wed Apr 4 03:47:03 2001 Yukihiro Matsumoto + + * class.c (rb_mod_clone): should copy method bodies too. + + * bignum.c (bigdivrem): should trim trailing zero bdigits of + remainder, even if dd == 0. + +Tue Apr 3 15:29:10 2001 Akinori MUSHA + + * Makefile.in: Introduce MAINLIBS. + + * configure.in: Link libc_r against the ruby executable on + FreeBSD, which is the first attempt to work around a certain + problem regarding pthread on FreeBSD. It should make ruby/libruby + happy when it loads an extention to a library compiled and linked + with -pthread. Note, however, that libruby is _not_ linked with + libc_r so as not to mess up pthread unfriendly stuff including + apache+mod_ruby and vim6+ruby_interp. + +Tue Apr 3 09:56:20 2001 WATANABE Hirofumi + + * ext/extmk.rb.in (create_makefile): create def file only if + it does not yet exist. + + * lib/mkmf.rb: ditto. + +Tue Apr 3 00:05:07 2001 Yukihiro Matsumoto + + * time.c (make_time_t): remove HAVE_TM_ZONE code since it + sometimes reports wrong time. + + * time.c (make_time_t): remove unnecessary range check for + platforms where negative time_t is available. + +Mon Apr 2 14:25:49 2001 Shugo Maeda + + * lib/monitor.rb (wait): ensure reentrance. + + * lib/monitor.rb (wait): fix timeout support. + +Mon Apr 2 12:44:53 2001 Shugo Maeda + + * lib/net/imap.rb: backport from ruby-1.7. + +Mon Apr 2 01:16:24 2001 WATANABE Hirofumi + + * win32/win32.c: use ruby's opendir on mingw32. + + * missing/dir.h, dir.c, Makefile: ditto. + +Sun Apr 1 23:26:14 2001 TOYOFUKU Chikanobu + + * numeric.c (flodivmod): a bug in no fmod case. + +Sun Apr 1 18:36:14 2001 Koji Arai + + * process.c (pst_wifsignaled): should apply WIFSIGNALED for status + (int), not st (VALUE). + +Sat Mar 31 03:24:10 2001 Yukihiro Matsumoto + + * class.c (rb_include_module): module inclusion should be check + taints. + +Fri Mar 30 12:51:19 2001 Yukihiro Matsumoto + + * class.c (rb_include_module): freeze check at first. + +Thu Mar 29 17:05:09 2001 Yukihiro Matsumoto + + * eval.c (rb_attr): sprintf() and rb_intern() moved into + conditional body. + +Wed Mar 28 23:43:00 2001 Nobuyoshi Nakada + + * ext/extmk.rb.in, lib/mkmf.rb: add C++ rules in addition to C + rules for the mswin32 platforms. + +Wed Mar 28 19:29:21 2001 Akinori MUSHA + + * ext/extmk.rb.in, lib/mkmf.rb: move C++ rules to the right place. + +Wed Mar 28 17:39:04 2001 Yukihiro Matsumoto + + * object.c (rb_str2cstr): warn if string contains \0 and length + value is ignored. + +Wed Mar 28 15:00:31 2001 K.Kosako + + * class.c (rb_singleton_class_clone): should copy class constant + table as well. + +Wed Mar 28 15:03:23 2001 Yukihiro Matsumoto + + * class.c (rb_include_module): sometimes cache was mistakenly left + uncleared - based on the patch by K.Kosako. + +Wed Mar 28 09:52:33 2001 WATANABE Hirofumi + + * win32/Makefile.sub: disable global optimization. + +Tue Mar 27 15:00:54 2001 K.Kosako + + * eval.c (rb_mod_define_method): should have clear method cache. + + * eval.c (rb_mod_define_method): should have raised exception for + type error. + +Tue Mar 27 14:48:17 2001 Yukihiro Matsumoto + + * ruby.h: changed "extern INLINE" to "static inline". + +Mon Mar 26 23:19:33 2001 WATANABE Hirofumi + + * time.c (rb_strftime): check whether strftime returns empty string. + +Mon Mar 26 18:14:47 2001 Yukihiro Matsumoto + + * dir.c (rb_glob_helper): part of 1.7 globber backported to proper + following of symlinks. + +Mon Mar 26 17:21:07 2001 Yukihiro Matsumoto + + * eval.c: remove TMP_PROTECT_END to prevent C_ALLOCA crash. + +Mon Mar 26 14:04:41 2001 WATANABE Hirofumi + + * ext/Win32API/Win32API.c: remove Init_win32api(). + +Sat Mar 24 23:44:50 2001 Yukihiro Matsumoto + + * eval.c (ev_const_defined): should ignore toplevel cbase (Object). + + * eval.c (ev_const_get): ditto. + +Fri Mar 23 12:18:44 2001 SHIROYAMA Takayuki + + * ext/curses/curses.c: curses on Mac OS X public beta does not + have _maxx etc. + +Fri Mar 23 10:50:31 2001 Yukihiro Matsumoto + + * marshal.c (w_object): should truncate trailing zero short for + bignums. + +Thu Mar 22 22:15:45 2001 WATANABE Hirofumi + + * ext/Win32API/extconf.rb: add -fno-omit-frame-pointer. + +Thu Mar 22 17:43:44 2001 Yukihiro Matsumoto + + * ruby.h: better inline function support. + + * configure.in (NO_C_INLINE): check if inline is available for the + C compiler. + +Wed Mar 21 23:07:45 2001 WATANABE Hirofumi + + * win32/win32.c (win32_stat): WinNT/2k "//host/share" support. + +Wed Mar 21 01:26:14 2001 Yukihiro Matsumoto + + * gc.c (id2ref): sometimes confused symbol and reference. + +Tue Mar 20 23:09:33 2001 WATANABE Hirofumi + + * win32/win32.c (win32_stat): UNC support. + + * dir.c (extract_path): fix "./*" problem. + +Mon Mar 19 19:14:47 2001 Guy Decoux + + * marshal.c (shortlen): shortlen should return number of bytes + written. + +Mon Mar 19 18:56:55 2001 Yukihiro Matsumoto + + * stable version 1.6.3 released. + +Mon Mar 19 16:52:23 2001 K.Kosako + + * eval.c (ev_const_defined): need not to check if cbase->nd_class + is rb_cObject. + + * eval.c (ev_const_get): ditto. + +Mon Mar 19 16:27:32 2001 Yukihiro Matsumoto + + * eval.c (THREAD_ALLOC): flags should be initialized. + + * signal.c (rb_f_kill): should use FIX2INT, not FIX2UINT. + +Mon Mar 19 11:03:10 2001 Koji Arai + + * marshal.c (r_object): len calculation patch was wrong for + machines SIZEOF_BDIGITS == SIZEOF_SHORT. + + * gc.c: alloca prototype reorganized for C_ALLOCA machine. + +Sun Mar 18 08:58:18 2001 Wakou Aoyama + + * lib/net/cgi.rb: // === '' --> //.match('') + + * lib/net/cgi.rb: cgi#header(): improvement for mod_ruby. + + * lib/net/cgi.rb: cgi#rfc1123date(): improvement. + thanks to TADA Tadashi . + + * lib/net/cgi.rb: cgi#rfc1123date(): document bug fix. + thanks to Kazuhiro NISHIYAMA . + + * lib/net/cgi.rb: cgi#header(): bug fix. + thanks to IWATSUKI Hiroyuki . + +Fri Mar 16 17:21:25 2001 Akinori MUSHA + + * configure.in: Set SOLIBS properly for all ELF and + FreeBSD/NetBSD/OpenBSD a.out platforms so that the shlib + dependencies are recorded in the libruby shlib. + +Wed Mar 14 16:41:45 2001 Yukihiro Matsumoto + + * eval.c (rb_thread_schedule): raise FATAL just once to + THREAD_TO_KILL. + +Wed Mar 14 10:41:34 2001 Yukihiro Matsumoto + + * eval.c (rb_yield_0): 0 (= Qfalse) is a valid value, so that + default self should be checked by klass == 0. + + * bignum.c (rb_cstr2inum): should disallow '++1', '+-1', etc. + +Tue Mar 13 17:51:09 2001 Yukihiro Matsumoto + + * eval.c (ev_const_defined): add new parameter self for special + const fallback. + + * eval.c (ev_const_get): ditto. + +Tue Mar 13 16:39:45 2001 WATANABE Hirofumi + + * dir.c (rb_glob_helper): fix drive letter handling on DOSISH. + +Tue Mar 13 15:01:12 2001 Minero Aoki + + * lib/net/http.rb: add HTTPRequest#basic_auth. + + * lib/net/smtp.rb: raise if only account or password is given. + + * lib/net/protocol.rb: WriteAdapter#<< returns self. + +Tue Mar 13 14:41:16 2001 Yukihiro Matsumoto + + * io.c (argf_seek): wrong calling sequence of rb_io_seek(). + +Mon Mar 12 18:59:38 2001 WATANABE Hirofumi + + * lib/mkmf.rb (create_makefile): save/restore $libs and $LIBPATH. + +Sun Mar 11 00:55:31 2001 WATANABE Hirofumi + + * lib/mkmf.rb (install_rb): fix handling of destination path. + +Sat Mar 10 02:34:18 2001 WATANABE Hirofumi + + * math.c (math_log, math_log10): use nan() instead of 0.0/0.0 on Cygwin. + +Thu Mar 8 17:43:59 2001 Minero Aoki + + * lib/net/protocol.rb: one write(2) per one line. + +Wed Mar 7 14:26:11 2001 WATANABE Hirofumi + + * math.c (math_log, math_log10): should return NaN if x < 0.0 + on Cygwin. + +Thu Mar 7 10:31:26 2001 Nobuyoshi Nakada + + * parse.y (stmt): while/until modifier must work for empty body. + +Tue Mar 6 22:53:58 2001 Kazuhiro Yoshida + + * ruby.c (ruby_set_argv): clear ARGV contents before adding args. + +Tue Mar 6 10:50:29 2001 Yukihiro Matsumoto + + * parse.y (primary): rescue and ensure clauses should be allowed + to appear in singleton method body. + +Mon Mar 5 17:25:13 2001 Yukihiro Matsumoto + + * eval.c (proc_eq): compare Procs using blocktag equality. + + * eval.c (proc_to_s): stringify according to block tag address. + +Mon Mar 5 17:19:56 2001 WATANABE Hirofumi + + * win32/win32.c (gettimeofday): use GetLocalTime() instead of ftime() + for high-resolution timing. + +Sun Mar 4 20:45:20 2001 Akinori MUSHA + + * ext/extmk.rb.in, lib/mkmf.rb: add C++ rules in addition to C + rules. + +Sun Mar 4 17:01:09 2001 WATANABE Hirofumi + + * string.c (trnext): support backslash escape in String#tr. + +Wed Feb 28 11:02:41 2001 Yukihiro Matsumoto + + * string.c (rb_str_delete_bang): delete! should take at least 1 + argument. + +Tue Feb 27 16:38:15 2001 Yukihiro Matsumoto + + * eval.c (ev_const_get): retrieve Object's caonstat if no current + class is available (e.g. defining singleton class for Fixnums). + + * eval.c (ev_const_defined): check Object's constant if no current + class is available (e.g. defining singleton class for Fixnums). + + * eval.c (proc_call): ignore block to `call' always, despite of + being orphan or not. + +Wed Feb 27 10:16:32 2001 Nobuyoshi Nakada + + * eval.c (rb_yield_0): should check based on rb_block_given_p() + and rb_f_block_given_p(). + +Mon Feb 26 16:20:27 2001 Yukihiro Matsumoto + + * ruby.c (proc_options): call ruby_show_version() just once. + +Mon Feb 26 00:04:52 2001 Yukihiro Matsumoto + + * eval.c (proc_call): should not modify ruby_block->frame.iter + based on ruby_frame->iter altered by PUSH_ITER(). + +Mon Feb 26 05:27:52 2001 Wakou Aoyama + + * lib/net/telnet.rb: #telnetmode(), #binmode(): bug fix. + thanks to nobu.nakada@nifty.ne.jp. + +Mon Feb 26 04:55:50 2001 Wakou Aoyama + + * lib/cgi.rb: CGI#form(): bug fix. + thanks to MoonWolf . + + * lib/cgi.rb: CGI#rfc1123_date(): improvement. + thanks to Tomoyasu Akita . + + * lib/cgi.rb: CGI#header(): improvement for mod_ruby. + thanks to Shugo Maeda . + +Sun Feb 25 02:45:30 2001 WATANABE Hirofumi + + * file.c (rb_file_s_rename): avoid Cygwin's bug. + +Sat Feb 24 23:32:55 2001 Yukihiro Matsumoto + + * eval.c (rb_thread_fd_close): should save current context before + raising exception. + +Sat Feb 24 22:14:00 2001 WATANABE Hirofumi + + * win32/win32.c (myrename): fix error handling. + +Sat Feb 24 15:43:31 2001 Minero Aoki + + * lib/net/protocol.rb: use net 1.2 for also ruby 1.6 branch. + + * lib/net/smtp.rb: ditto. + + * lib/net/pop.rb: ditto. + + * lib/net/http.rb: ditto. + +Fri Feb 23 16:36:09 2001 Minero Aoki + + * lib/net/http.rb: always close connection if body is not exist. + +Fri Feb 23 13:27:05 2001 Minero Aoki + + * lib/net/http.rb: keep-alive detection was incomplete. + +Fri Feb 23 08:24:53 2001 Minero Aoki + + * lib/net/protocol.rb: clear read buffer after reopen. + + * lib/net/http.rb: update RD document. + +Tue Feb 20 16:37:58 2001 Yukihiro Matsumoto + + * bignum.c (rb_big2long): should not raise RangeError for Bignum + LONG_MIN value. + +Mon Feb 19 17:46:37 2001 Yukihiro Matsumoto + + * string.c (rb_str_substr): "a"[1,2] should return ""; need + rubicon upgrade. + +Mon Feb 19 01:55:43 2001 Yukihiro Matsumoto + + * eval.c (secure_visibility): visibility check for untainted modules. + +Mon Feb 19 00:29:29 2001 Nobuyoshi Nakada + + * signal.c (sigpipe): sighandler which does nothing. + + * signal.c (trap): set sigpipe function for SIGPIPE. + + * signal.c (Init_signal): default SIGPIPE handler should be + sigpipe function. + +Sun Feb 18 15:42:38 2001 WATANABE Hirofumi + + * ext/curses/extconf.rb: add dir_config. + + * missing/flock.c: use fcntl(2) instead of lockf(2). + +Sun Feb 18 13:02:03 2001 Yasushi Shoji + + * array.c (rb_ary_subseq): wrong boundary check. + +Fri Feb 16 01:44:56 2001 Yukihiro Matsumoto + + * io.c (set_outfile): f should be the FILE* from the assigning value. + +Thu Feb 15 11:33:49 2001 Shugo Maeda + + * lib/cgi/session.rb (close): fixed reversed condition. + +Wed Feb 14 17:28:24 2001 Shugo Maeda + + * lib/net/imap.rb: supports unknown resp_text_code. + +Wed Feb 14 00:44:17 2001 Yukihiro Matsumoto + + * dir.c (dir_s_glob): call rb_yield directly (via push_pattern) if + block is given to the method. + + * dir.c (push_pattern): do not call rb_ary_push; yield directly. + +Tue Feb 13 23:05:38 2001 WATANABE Hirofumi + + * dir.c (lstat): should use rb_sys_stat if lstat(2) is not + available. + +Tue Feb 13 17:00:18 2001 Minero Aoki + + * lib/net/http.rb: supports HTTP 1.0 server. + +Tue Feb 13 01:13:43 2001 Yukihiro Matsumoto + + * parse.y (primary): preserve and clear in_single and in_def using + stack to prevent nested method errors in singleton class bodies. + +Sun Feb 11 16:00:30 2001 WATANABE Hirofumi + + * eval.c (stack_length): use __builtin_frame_address() only if + GCC and i386 CPU. + + * gc.c (rb_gc, Init_stack): ditto. + + * configure.in: add ac_cv_func_getpgrp_void=yes on DJGPP. + +Sat Feb 10 23:43:49 2001 Nobuyoshi Nakada + + * hash.c (rb_any_hash): dumped core on machines sizeof(int) != sizeof(long). + +Sat Feb 10 23:07:15 2001 Yukihiro Matsumoto + + * regex.c (PREV_IS_A_LETTER): should not treat c>0x7f as a word + character if -Kn. + +Sat Feb 10 00:06:28 2001 Nobuyoshi Nakada + + * win32/win32.c (win32_stat): replace stat for enable when pathname + ends with '/' or '\' for mswin32 on Win9X / Win2k. + + * win32/win32.h: ditto. + + * ruby.h: ditto. + + * dir.c (rb_glob_helper): ditto. + + * file.c (rb_stat, rb_file_s_stat, eaccess, check3rdbyte): ditto. + +Fri Feb 9 22:54:57 2001 WATANABE Hirofumi + + * ruby.c (ruby_init_loadpath): convert '\\' to '/' + before finding executable file path. + +Fri Feb 9 17:41:53 2001 Triet H. Lai + + * dir.c (rb_glob_helper): do not follow symbolic links. + +Fri Feb 8 23:53:08 2001 Usaku Nakamura + + * win32/config.h.in (inline): add inline definition. + +Thu Feb 8 21:27:24 2001 WATANABE Hirofumi + + * lib/mkmf.rb (install_rb): fix handling of relative path. + + * lib/mkmf.rb (create_makefile): add srcdir. + +Wed Feb 7 16:05:22 2001 Nobuyoshi Nakada + + * parse.y (parse_quotedwords): %w should allow parenthesis escape. + +Wed Feb 7 00:57:42 2001 Yukihiro Matsumoto + + * parse.y (parse_qstring): %q should allow terminator escape. + +Wed Feb 7 00:57:42 2001 Yukihiro Matsumoto + + * re.c (rb_reg_equal): all option flags should be same to be equal. + +Tue Feb 6 21:01:29 2001 Minero Aoki + + * lib/net/protocol.rb: ignore EOFError on only specified case. + + * lib/net/http.rb: take HTTP 1.0 server into account. + +Mon Feb 5 00:39:06 2001 KANEKO Naoshi + + * dir.c: use ISXXX() instead of isxxx(). + + * dln.c (aix_loaderror): ditto. + + * file.c (rb_file_s_expand_path): ditto. + + * string.c (rb_str_upcase_bang): ditto. + + * win32/win32.c (do_spawn): ditto. + + * win32/win32.c (NtMakeCmdVector): ditto. + + * win32/win32.c (opendir): ditto. + +Fri Feb 3 00:48:50 2001 Usaku Nakamura + + * win32/win32.c (isInternalCmd): ignore case for shell's internal + command. (marge from HEAD) + +Fri Feb 2 16:14:51 2001 Yukihiro Matsumoto + + * eval.c (POP_VARS): propagate DVAR_DONT_RECYCLE, if + SCOPE_DONT_RECYCLE of ruby_scope is set. + +Wed Jan 31 22:27:29 2001 WATANABE Hirofumi + + * configure.in: gcc-2.95.2-7(cygwin) support. + add -mwin32 if available. + + * cygwin/GNUmakefile: ditto. + +Mon Jan 29 17:36:19 2001 TOYOFUKU Chikanobu + + * eval.c (rb_eval): nd_iter evaluation should be wrapped by + BEGIN_CALLARGS and END_CALLARGS. + +Mon Jan 29 01:40:27 2001 Yukihiro Matsumoto + + * string.c (str_independent): should not clear str->orig here. + it's too early. + +Wed Jan 24 01:45:49 2001 Yukihiro Matsumoto + + * eval.c (POP_BLOCK_TAG): call rb_gc_force_recycle() if block has + not been objectified. + + * eval.c (rb_callcc): should nail down block->tag history to avoid + rb_gc_force_recycle(). + +Tue Jan 23 18:51:57 2001 Yukihiro Matsumoto + + * gc.c (rb_gc_call_finalizer_at_exit): should finalize objects in + deferred_final_list too. + +Tue Jan 23 16:10:12 2001 Yukihiro Matsumoto + + * gc.c (os_live_obj): do not list terminated object. + + * gc.c (os_obj_of): ditto. + + * gc.c (rb_gc_mark): support new T_BLKTAG tag. + + * gc.c (obj_free): ditto. + + * eval.c (new_blktag): creation of new block tag, which holds + destination of global jump and orphan status. + + * eval.c (block_pass): break from orphan Proc object will raise a + LocalJumpError exception. + +Mon Jan 22 16:33:16 2001 WATANABE Hirofumi + + * mkconfig.rb: autoconf 2.49 support. + +Sat Jan 20 03:54:00 2001 Yukihiro Matsumoto + + * parse.y (yylex): fixed serious syntax misbehavior. do's + preceding was too high. a block in `foo bar do .. end' should + be passed to `foo', not `bar'. + + * parse.y (block_call): syntax restructure. + +Fri Jan 19 04:04:31 2001 Akinori MUSHA + + * lib/irb/ruby-lex.rb: Merge from HEAD: rev.1.4 + +Wed Jan 17 13:28:26 2001 WATANABE Hirofumi + + * configure.in: remove DEFS definition. + + * mkconfig.rb: ditto. + + * win32/config.status.in: ditto. + +Tue Jan 16 16:59:14 2001 Minero Aoki + + * lib/net/protocol.rb: ignore EOFError for read + +Sun Jan 14 21:49:28 2001 Koji Arai + + * sprintf.c (rb_f_sprintf): simple typo. binary base should be 2, + not '2'. + +Sun Jan 14 02:49:57 2001 Minero Aoki + + * lib/net/protocol.rb (adding): too few "yield" in case of arg is + not String/File. + +Sat Jan 13 19:18:18 2001 WATANABE Hirofumi + + * re.c (rb_reg_desc): separate RE_OPTION_MULTILINE + + * re.c (rb_reg_options): add RE_OPTION_{POSIXLINE,RE_OPTION_MULTILINE, + RE_OPTION_EXTENDED} + +Thu Jan 11 06:45:55 2001 Yukihiro Matsumoto + + * object.c (rb_mod_dup): should propagate FL_SINGLETON. + + * object.c (inspect_obj): handles the case of no instance variable. + +Wed Jan 10 01:50:45 2001 Yukihiro Matsumoto + + * string.c (rb_str_reverse_bang): forgot to call rb_str_modify(). + +Tue Jan 9 17:41:40 2001 Yukihiro Matsumoto + + * object.c (rb_obj_taint): check frozen status before modifying + taint status. + + * object.c (rb_obj_untaint): ditto. + +Mon Jan 8 21:35:10 2001 Guy Decoux + + * file.c (path_check_1): should restore modified path. + +Mon Jan 8 21:24:37 2001 Yukihiro Matsumoto + + * bignum.c (bigdivrem): t2 might be too big for signed long; do + not use rb_int2big(), but rb_uint2big(). + +Mon Jan 8 03:09:58 2001 Yukihiro Matsumoto + + * error.c (rb_load_fail): new func to report LoadError. + + * ruby.c (load_file): use rb_load_fail. + +Sat Jan 6 00:55:59 2001 Yukihiro Matsumoto + + * pack.c (pack_pack): template "m2" or "u2" caused inifinite loop. + +Fri Jan 5 01:02:17 2001 Yukihiro Matsumoto + + * eval.c (ruby_finalize): should enclosed by PUSH_TAG/POP_TAG. + +Sun Dec 31 01:39:16 2000 Guy Decoux + + * eval.c (rb_mod_define_method): wrong comparison for blocks. + +Sat Dec 30 19:28:50 2000 Yukihiro Matsumoto + + * gc.c (id2ref): should handle Symbol too. + + * gc.c (id2ref): should print original ptr value + +Sat Dec 30 03:14:22 2000 Yukihiro Matsumoto + + * eval.c (rb_iterate): NODE_CFUNC does not protect its data + (nd_tval), so create new node NODE_IFUNC for iteration C + function. + + * eval.c (rb_yield_0): use NODE_IFUNC. + + * gc.c (rb_gc_mark): support NODE_IFUNC. + +Fri Dec 29 11:41:55 2000 Yukihiro Matsumoto + + * gc.c (mem_error): prohibit recursive mem_error(). + (ruby-bugs-ja:PR#36) + +Fri Dec 29 11:05:41 2000 Yukihiro Matsumoto + + * eval.c (rb_thread_fd_writable): should not switch context if + rb_thread_critical is set. + + * eval.c (rb_thread_wait_fd): ditto. + + * eval.c (rb_thread_wait_for): ditto. + + * eval.c (rb_thread_select): ditto. + + * eval.c (rb_thread_join): join during critical section causes + deadlock. + +Tue Dec 26 18:46:41 2000 NAKAMURA Hiroshi + + * lib/debug.rb: Avoid thread deadlock in debugging stopped thread. + + * lib/debug.rb: Uncleared 'finish' state. + +Tue Dec 26 16:53:55 2000 Yukihiro Matsumoto + + * eval.c (rb_yield_0): remove dvar node by rb_gc_force_recycle() + more eagerly. + + * eval.c (rb_f_binding): recycling should be stopped for outer + scope too. + + * eval.c (proc_new): ditto. + +Tue Dec 26 15:45:35 2000 Yukihiro Matsumoto + + * string.c (rb_str_inspect): should treat multibyte chracters + properly. + +Mon Dec 25 17:49:08 2000 K.Kosako + + * string.c (rb_str_replace_m): unexpected string share happens if + replace is done for associated (STR_NO_ORIG) string. + +Tue Dec 26 15:01:53 2000 Yukihiro Matsumoto + + * io.c (rb_f_p): should not call rb_io_flush() if rb_defout is not + a IO (T_FILE). + +Mon Dec 25 15:52:39 2000 Yukihiro Matsumoto + + * stable version 1.6.2 released. + Mon Dec 25 05:11:04 2000 Wakou Aoyama * lib/cgi.rb: version 2.1.2 (some bug fixes). @@ -21,10 +872,6 @@ Mon Dec 25 00:04:54 2000 Nobuyoshi Nakada * eval.c (rb_thread_schedule): initial value of `max' changed to -1. -Fri Dec 22 17:59:30 2000 Yukihiro Matsumoto - - * stable version 1.6.2 released. - Mon Dec 25 00:16:14 2000 Yukihiro Matsumoto * string.c (rb_str_replace_m): copy-on-write replace. @@ -85,7 +932,7 @@ Tue Dec 19 13:44:50 2000 K.Kosako Tue Dec 19 00:57:10 2000 Yukihiro Matsumoto - * time.c (time_minus): usec might overflow (ruby-bugs-ja:#PR#35). + * time.c (time_minus): usec might overflow. (ruby-bugs-ja:PR#35) * eval.c (rb_obj_extend): Object#extend should take at least one argument. @@ -837,7 +1684,7 @@ Sat Sep 23 03:06:25 2000 Yukihiro Matsumoto Fri Sep 22 15:46:21 2000 Minero Aoki - * lib/net/http.rb: too early parameter expantion in string. + * lib/net/http.rb: too early parameter expansion in string. Fri Sep 22 13:58:51 2000 WATANABE Hirofumi @@ -894,7 +1741,7 @@ Wed Sep 20 23:21:38 2000 Yukihiro Matsumoto Wed Sep 20 14:01:45 2000 Yukihiro Matsumoto - * eval.c (rb_provided): detect infnite load loop. + * eval.c (rb_provided): detect infinite load loop. * eval.c (rb_provided): too weak filename comparison. @@ -959,7 +1806,7 @@ Thu Sep 14 02:46:54 2000 Yukihiro Matsumoto Wed Sep 13 17:01:03 2000 Yukihiro Matsumoto - * bignum.c (rb_big_eq): imcomplete value compare of bignums. + * bignum.c (rb_big_eq): incomplete value comparison of bignums. Wed Sep 13 06:39:54 2000 Yukihiro Matsumoto @@ -1084,7 +1931,7 @@ Fri Sep 1 10:36:29 2000 Yukihiro Matsumoto * parse.y (aref_args,opt_call_args): add block_call to allow a method without parentheses and with block as a last argument. - * hash.c (rb_hash_sort): should not retrun nil. + * hash.c (rb_hash_sort): should not return nil. * re.c (match_aref): should use rb_reg_nth_match(). @@ -1252,7 +2099,7 @@ Fri Aug 11 15:43:46 2000 Yukihiro Matsumoto Thu Aug 10 08:05:03 2000 Yukihiro Matsumoto - * eval.c (rb_callcc): returned current thread instaed of + * eval.c (rb_callcc): returned current thread instead of continuation wrongly. Thu Aug 10 05:40:28 2000 WATANABE Hirofumi @@ -1425,7 +2272,7 @@ Tue Jul 18 14:58:30 2000 Yukihiro Matsumoto Mon Jul 17 04:29:50 2000 Minero Aoki - * lib/mkmf.rb: converts extention of $objs into $OBJEXT. + * lib/mkmf.rb: converts extension of $objs into $OBJEXT. Sun Jul 16 03:02:34 2000 Dave Thomas @@ -1522,7 +2369,7 @@ Mon Jul 10 09:07:54 2000 Yukihiro Matsumoto Sat Jul 8 23:08:40 2000 Yukihiro Matsumoto * eval.c (rb_thread_start_0): should copy previous scopes to - prevent rb_gc_force_recylce(). + prevent rb_gc_force_recycle(). Fri Jul 7 23:36:36 2000 Katsuyuki Komatsu @@ -1597,7 +2444,7 @@ Wed Jul 5 09:47:14 2000 Yukihiro Matsumoto * time.c (time_arg): Time::local, Time::gm now take 7th optional argument for usec. - * numeric.c (num_ceil, etc): default ceil, floor, round, trancate + * numeric.c (num_ceil, etc): default ceil, floor, round, truncate implementation for Numeric, using `to_f'. * io.c (rb_io_reopen): clear fptr->path after free() to prevent @@ -1688,7 +2535,7 @@ Mon Jul 3 13:15:02 2000 Yukihiro Matsumoto * bignum.c (rb_big_divmod): ditto. - * numeric.c (fixdivmod): does not depend C's undifined % + * numeric.c (fixdivmod): does not depend C's undefined % behavior. adopt to fmod(3m) behavior. * numeric.c (flo_mod): modulo now reserves fmod(3m) behavior. @@ -1731,7 +2578,7 @@ Sat Jul 1 15:22:35 2000 Yukihiro Matsumoto Sat Jul 1 15:22:35 2000 Yukihiro Matsumoto * eval.c (rb_eval): the value from RTEST() is not valid Ruby - objct. result should be either true or false. + object. result should be either true or false. Sat Jul 1 09:30:06 2000 Katsuyuki Komatsu @@ -2824,6 +3671,13 @@ Sat Mar 25 23:21:10 2000 Yukihiro Matsumoto * marshal.c (w_object): symbols should be converted to ID before dumping out. +Sun Mar 25 16:52:48 2001 Koji Arai + + * file.c (rb_file_flock): do not trap EINTR. + + * missing/flock.c (flock): returns the value from lockf(2) + directly. + Fri Mar 24 18:26:51 2000 Yukihiro Matsumoto * file.c (test_check): should have checked exact number of arguments. @@ -3924,7 +4778,7 @@ Thu Oct 21 16:14:19 1999 Yukihiro Matsumoto * ruby.c (proc_options): use RUBYOPT environment variable to retrieve the default options. - * dir.c (fnmatch): use eban's fnmatch; do not depend on systems's + * dir.c (fnmatch): use eban's fnmatch; do not depend on system's fnmatch (which may have portability problem) anymore. Wed Oct 20 15:14:24 1999 Yukihiro Matsumoto @@ -6519,7 +7373,7 @@ Sun Nov 1 01:18:52 1998 EGUCHI Osamu Sat Oct 31 23:18:34 1998 Yukihiro Matsumoto * string.c (rb_str_split_method): negative LIMIT means number of - splitted fields are unlimited, as in perl. + split fields are unlimited, as in perl. * string.c (rb_str_split_method): if LIMIT is unspecified, trailing null fields are stripped. @@ -8775,7 +9629,7 @@ Wed Nov 12 13:44:47 1997 Yukihiro Matsumoto Mon Nov 10 11:24:51 1997 Yukihiro Matsumoto - * regex.c (re_compile_pattern): non-resitering parens (?:..). + * regex.c (re_compile_pattern): non-registering parens (?:..). * regex.c (re_compile_pattern): new meta character \< (wordbeg) and \> (wordend). @@ -9031,7 +9885,7 @@ Tue Sep 16 17:54:25 1997 Yukihiro Matsumoto * 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. + variable, if ruby is running under setuid. * process.c (init_ids): check suid check for setuid/seteuid etc. diff --git a/Makefile.in b/Makefile.in index b1b0166b89..420bd3985b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -22,6 +22,7 @@ MISSING = @LIBOBJS@ @ALLOCA@ LDSHARED = @LIBRUBY_LDSHARED@ DLDFLAGS = @LIBRUBY_DLDFLAGS@ SOLIBS = @SOLIBS@ +MAINLIBS = @MAINLIBS@ RUBY_INSTALL_NAME=@RUBY_INSTALL_NAME@ RUBY_SO_NAME=@RUBY_SO_NAME@ @@ -91,7 +92,7 @@ miniruby$(EXEEXT): config.status $(LIBRUBY_A) $(MAINOBJ) dmyext.@OBJEXT@ $(PROGRAM): $(LIBRUBY) $(MAINOBJ) $(EXTOBJS) @rm -f $@ - $(PURIFY) $(CC) $(LDFLAGS) $(XLDFLAGS) $(MAINOBJ) $(EXTOBJS) $(LIBRUBYARG) $(LIBS) -o $@ + $(PURIFY) $(CC) $(LDFLAGS) $(XLDFLAGS) $(MAINLIBS) $(MAINOBJ) $(EXTOBJS) $(LIBRUBYARG) $(LIBS) -o $@ $(LIBRUBY_A): $(OBJS) dmyext.@OBJEXT@ @AR@ rcu $@ $(OBJS) dmyext.@OBJEXT@ @@ -230,7 +231,7 @@ dl_os2.@OBJEXT@: $(srcdir)/missing/dl_os2.c $(CC) $(CFLAGS) $(CPPFLAGS) -c $(srcdir)/missing/dl_os2.c win32.@OBJEXT@: $(srcdir)/win32/win32.c - $(CC) $(CFLAGS) $(CPPFLAGS) -c $(srcdir)/win32/win32.c + $(CC) $(CFLAGS) $(CPPFLAGS) -I$(srcdir)/missing -c $(srcdir)/win32/win32.c # Prevent GNU make v3 from overflowing arg limit on SysV. .NOEXPORT: diff --git a/README b/README index 5794f5daf6..83a88e1359 100644 --- a/README +++ b/README @@ -26,10 +26,10 @@ The Ruby distribution can be found on: You can get it by anonymous CVS. How to check out is: - $ cvs -d :pserver:anonymous@cvs.netlab.co.jp:/home/cvs login - (Logging in to anonymous@cvs.netlab.co.jp) + $ cvs -d :pserver:anonymous@cvs.ruby-lang.org:/home/cvs login + (Logging in to anonymous@cvs.ruby-lang.org) CVS password: guest - $ cvs -d :pserver:anonymous@cvs.netlab.co.jp:/home/cvs checkout ruby + $ cvs -d :pserver:anonymous@cvs.ruby-lang.org:/home/cvs checkout ruby * Mailing list @@ -40,17 +40,20 @@ To subscribe this list, please send the following phrase e.g. subscribe Joseph Smith -in the mail body (not subject) to the address . +in the mail body (not subject) to the address . * How to compile and install This is what you need to do to compile and install Ruby: - 1. Run ./configure, which will generate config.h and Makefile. + 1. If ./configure does not exist or is older than configure.in, + run autoconf to (re)generate configure. - 2. Edit defines.h if you need. Probably this step will not need. + 2. Run ./configure, which will generate config.h and Makefile. - 3. Remove comment mark(#) before the module names from ext/Setup (or + 3. Edit defines.h if you need. Probably this step will not need. + + 4. Remove comment mark(#) before the module names from ext/Setup (or add module names if not present), if you want to link modules statically. @@ -59,13 +62,13 @@ This is what you need to do to compile and install Ruby: remove comment mark from the line "#option nodynamic" in ext/Setup. - 4. Run make. + 5. Run make. - 5. Optionally, run 'make test' to check whether the compiled Ruby + 6. Optionally, run 'make test' to check whether the compiled Ruby interpreter works well. If you see the message "test succeeded", your ruby works as it should (hopefully). - 6. Run 'make install' + 7. Run 'make install' You may have to be a super user to install ruby. diff --git a/README.jp b/README.jp index fccedb2f99..566fbcdac4 100644 --- a/README.jp +++ b/README.jp @@ -78,13 +78,17 @@ Ruby 以下の手順で行ってください. - 1. configureを実行してMakefileなどを生成する + 1. もしconfigureファイルが見つからない、もしくは + configure.inより古いようなら、autoconfを実行して + 新しくconfigureを生成する - 2. (必要ならば)defines.hを編集する + 2. configureを実行してMakefileなどを生成する + + 3. (必要ならば)defines.hを編集する 多分,必要無いと思います. - 3. (必要ならば)ext/Setupに静的にリンクする拡張モジュールを + 4. (必要ならば)ext/Setupに静的にリンクする拡張モジュールを 指定する ext/Setupに記述したモジュールは静的にリンクされます. @@ -95,14 +99,14 @@ Ruby 拡張モジュールを利用するためには,あらかじめ静的にリン クしておく必要があります. - 4. makeを実行してコンパイルする + 5. makeを実行してコンパイルする - 5. make testでテストを行う. + 6. make testでテストを行う. 「test succeeded」と表示されれば成功です.ただしテスト に成功しても完璧だと保証されている訳ではありません. - 6. make install + 7. make install rootで作業する必要があるかもしれません. diff --git a/array.c b/array.c index 638b392753..3349a81f8f 100644 --- a/array.c +++ b/array.c @@ -1171,7 +1171,7 @@ rb_ary_replace_m(ary, ary2) return ary; } -static VALUE +VALUE rb_ary_clear(ary) VALUE ary; { diff --git a/bignum.c b/bignum.c index daf131b042..708d74c155 100644 --- a/bignum.c +++ b/bignum.c @@ -209,6 +209,10 @@ rb_cstr2inum(str, base) str++; sign = 0; } + if (str[0] == '+' || str[0] == '-') { + if (badcheck) goto bad; + return INT2FIX(0); + } if (base == 0) { if (str[0] == '0') { if (str[1] == 'x' || str[1] == 'X') { @@ -467,7 +471,7 @@ rb_big2long(x) { unsigned long num = big2ulong(x, "int"); - if ((long)num < 0) { + if ((long)num < 0 && (RBIGNUM(x)->sign || (long)num != LONG_MIN)) { rb_raise(rb_eRangeError, "bignum too big to convert into `int'"); } if (!RBIGNUM(x)->sign) return -(long)num; @@ -831,8 +835,10 @@ bigdivrem(x, y, divp, modp) t2 %= dd; } RBIGNUM(z)->sign = RBIGNUM(x)->sign==RBIGNUM(y)->sign; - if (!RBIGNUM(x)->sign) t2 = -(long)t2; - if (modp) *modp = rb_int2big((long)t2); + if (modp) { + *modp = rb_uint2big((unsigned long)t2); + RBIGNUM(*modp)->sign = RBIGNUM(x)->sign; + } if (divp) *divp = z; return; } @@ -911,10 +917,10 @@ bigdivrem(x, y, divp, modp) } if (modp) { /* just normalize remainder */ *modp = rb_big_clone(z); + zds = BDIGITS(*modp); + while (0 < ny && !zds[ny-1]) ny--; if (dd) { - zds = BDIGITS(*modp); - while (ny-- && !zds[ny]) ; - t2 = 0; i = ++ny; + t2 = 0; i = ny; while(i--) { t2 = (t2 | zds[i]) >> dd; q = zds[i]; diff --git a/class.c b/class.c index 2eedb262dc..b5caf3082a 100644 --- a/class.c +++ b/class.c @@ -33,16 +33,6 @@ rb_class_new(super) return (VALUE)klass; } -VALUE -rb_singleton_class_new(super) - VALUE super; -{ - VALUE klass = rb_class_new(super); - - FL_SET(klass, FL_SINGLETON); - return klass; -} - static int clone_method(mid, body, tbl) ID mid; @@ -53,6 +43,47 @@ clone_method(mid, body, tbl) return ST_CONTINUE; } +VALUE +rb_mod_clone(module) + VALUE module; +{ + NEWOBJ(clone, struct RClass); + CLONESETUP(clone, module); + + clone->super = RCLASS(module)->super; + if (RCLASS(module)->iv_tbl) { + clone->iv_tbl = st_copy(RCLASS(module)->iv_tbl); + } + if (RCLASS(module)->m_tbl) { + clone->m_tbl = st_init_numtable(); + st_foreach(RCLASS(module)->m_tbl, clone_method, clone->m_tbl); + } + + return (VALUE)clone; +} + +VALUE +rb_mod_dup(mod) + VALUE mod; +{ + VALUE dup = rb_mod_clone(mod); + OBJSETUP(dup, RBASIC(mod)->klass, BUILTIN_TYPE(mod)); + if (FL_TEST(mod, FL_SINGLETON)) { + FL_SET(dup, FL_SINGLETON); + } + return dup; +} + +VALUE +rb_singleton_class_new(super) + VALUE super; +{ + VALUE klass = rb_class_new(super); + + FL_SET(klass, FL_SINGLETON); + return klass; +} + VALUE rb_singleton_class_clone(klass) VALUE klass; @@ -67,6 +98,9 @@ rb_singleton_class_clone(klass) clone->super = RCLASS(klass)->super; clone->iv_tbl = 0; clone->m_tbl = 0; + if (RCLASS(klass)->iv_tbl) { + clone->iv_tbl = st_copy(RCLASS(klass)->iv_tbl); + } clone->m_tbl = st_init_numtable(); st_foreach(RCLASS(klass)->m_tbl, clone_method, clone->m_tbl); FL_SET(clone, FL_SINGLETON); @@ -78,8 +112,12 @@ void rb_singleton_class_attached(klass, obj) VALUE klass, obj; { - if (FL_TEST(klass, FL_SINGLETON)) - rb_iv_set(klass, "__attached__", obj); + if (FL_TEST(klass, FL_SINGLETON)) { + if (!RCLASS(klass)->iv_tbl) { + RCLASS(klass)->iv_tbl = st_init_numtable(); + } + st_insert(RCLASS(klass)->iv_tbl, rb_intern("__attached__"), obj); + } } VALUE @@ -217,7 +255,12 @@ rb_include_module(klass, module) VALUE klass, module; { VALUE p; + int changed = 0; + rb_frozen_class_p(klass); + if (!OBJ_TAINTED(klass)) { + rb_secure(4); + } if (NIL_P(module)) return; if (klass == module) return; @@ -238,16 +281,16 @@ rb_include_module(klass, module) if (RCLASS(module)->super) { rb_include_module(p, RCLASS(module)->super); } + if (changed) rb_clear_cache(); return; } } - rb_frozen_class_p(klass); - RCLASS(klass)->super = - include_class_new(module, RCLASS(klass)->super); + RCLASS(klass)->super = include_class_new(module, RCLASS(klass)->super); klass = RCLASS(klass)->super; module = RCLASS(module)->super; + changed = 1; } - rb_clear_cache(); + if (changed) rb_clear_cache(); } VALUE diff --git a/configure.in b/configure.in index b24f492665..094098861d 100644 --- a/configure.in +++ b/configure.in @@ -90,14 +90,20 @@ AC_CHECK_TOOL(AR, ar) AC_CHECK_PROGS(AR, ar aal, ar) case "$target_os" in - cygwin*|mingw*) - AC_CHECK_TOOL(NM, nm) - AC_CHECK_TOOL(DLLWRAP, dllwrap) - AC_CHECK_TOOL(AS, as) - AC_CHECK_TOOL(DLLTOOL, dlltool) - AC_CHECK_TOOL(WINDRES, windres) - ;; +cygwin*|mingw*) + AC_CHECK_TOOL(NM, nm) + AC_CHECK_TOOL(DLLWRAP, dllwrap) + AC_CHECK_TOOL(AS, as) + AC_CHECK_TOOL(DLLTOOL, dlltool) + AC_CHECK_TOOL(WINDRES, windres) + echo 'main(){}' > conftest.c + if $CC -mwin32 -c conftest.c 2> /dev/null; then + MWIN32=-mwin32 + CFLAGS="$CFLAGS $MWIN32" + fi + ;; esac +AC_SUBST(MWIN32) AC_PROG_LN_S AC_PROG_MAKE_SET @@ -163,6 +169,14 @@ if test "$rb_cv_have_attr_noreturn" = yes; then AC_DEFINE(HAVE_ATTR_NORETURN) fi +dnl wheather link libc_r or not +AC_ARG_WITH(libc_r, + [--with-libc_r link libc_r if possible (FreeBSD only)], [ + case $withval in + yes) with_libc_r=yes;; + *) with_libc_r=no;; + esac], [with_libc_r=yes]) + dnl Checks for libraries. case "$target_os" in nextstep*) ;; @@ -184,6 +198,8 @@ mingw*) LIBS="-lwsock32 -lmsvcrt $LIBS" ac_cv_func_times=yes;; os2_emx*) LIBS="-lm $LIBS" ac_cv_lib_dir_opendir=no;; +msdosdjgpp*) LIBS="-lm $LIBS" + ac_cv_func_getpgrp_void=yes;; freebsd*) LIBS="-lm $LIBS" AC_CACHE_CHECK([whether -lxpg4 has to be linked], rb_cv_lib_xpg4_needed, @@ -200,6 +216,25 @@ freebsd*) LIBS="-lm $LIBS" if test "$rb_cv_lib_xpg4_needed" = yes; then AC_CHECK_LIB(xpg4, setlocale) fi + if test "$with_libc_r" = yes; then + AC_CACHE_CHECK([whether libc_r is supplementary to libc], + rb_cv_supplementary_lib_c_r, + [AC_TRY_CPP([ +#include +#if 500016 <= __FreeBSD_version +#error libc_r is supplementary to libc +#endif + ], + rb_cv_supplementary_lib_c_r=no, + rb_cv_supplementary_lib_c_r=yes, + rb_cv_supplementary_lib_c_r=yes)]) + if test "$rb_cv_supplementary_lib_c_r" = yes; then + MAINLIBS="-lc_r $MAINLIBS" + else + MAINLIBS="-pthread $MAINLIBS" + CFLAGS="-D_THREAD_SAFE $CFLAGS" + fi + fi ;; *) LIBS="-lm $LIBS";; esac @@ -316,6 +351,7 @@ test $rb_cv_func_strtod = no && LIBOBJS="$LIBOBJS strtod.o" AC_C_BIGENDIAN AC_C_CONST AC_C_CHAR_UNSIGNED +AC_C_INLINE AC_CACHE_CHECK(whether right shift preserve sign bit, rb_cv_rshift_sign, [AC_TRY_RUN([ @@ -380,7 +416,7 @@ AC_ARG_WITH(default-kcode, esac]) AC_DEFINE_UNQUOTED(DEFAULT_KCODE, $DEFAULT_KCODE) -dnl wheather use dln_a_out ot not +dnl wheather use dln_a_out or not AC_ARG_WITH(dln-a-out, [--with-dln-a-out use dln_a_out if possible], [ case $withval in @@ -757,6 +793,9 @@ if test "$enable_shared" = 'yes'; then LIBRUBYARG='-L. -l$(RUBY_INSTALL_NAME)' CFLAGS="$CFLAGS $CCDLFLAGS" ENABLE_SHARED=yes + if test "$rb_cv_binary_elf" = yes; then + SOLIBS='$(LIBS)' + fi case "$target_os" in sunos4*) LIBRUBY_ALIASES='lib$(RUBY_INSTALL_NAME).so.$(MAJOR).$(MINOR) lib$(RUBY_INSTALL_NAME).so' @@ -766,6 +805,7 @@ if test "$enable_shared" = 'yes'; then LIBRUBY_ALIASES='lib$(RUBY_INSTALL_NAME).so.$(MAJOR).$(MINOR) lib$(RUBY_INSTALL_NAME).so' ;; freebsd*) + SOLIBS='$(LIBS)' LIBRUBY_SO='lib$(RUBY_INSTALL_NAME).so.$(MAJOR)$(MINOR)' if test "$rb_cv_binary_elf" != "yes" ; then LIBRUBY_SO="$LIBRUBY_SO.\$(TEENY)" @@ -773,6 +813,7 @@ if test "$enable_shared" = 'yes'; then fi ;; netbsd*) + SOLIBS='$(LIBS)' LIBRUBY_SO='lib$(RUBY_INSTALL_NAME).so.$(MAJOR).$(MINOR)' if test "$rb_cv_binary_elf" = yes; then # ELF platforms LIBRUBY_ALIASES='lib$(RUBY_INSTALL_NAME).so.$(MAJOR) lib$(RUBY_INSTALL_NAME).so' @@ -780,6 +821,9 @@ if test "$enable_shared" = 'yes'; then LIBRUBY_ALIASES= # a.out platforms fi ;; + openbsd*) + SOLIBS='$(LIBS)' + ;; solaris*) XLDFLAGS='-R${prefix}/lib' ;; @@ -893,6 +937,7 @@ AC_SUBST(LIBRUBYARG) AC_SUBST(SOLIBS) AC_SUBST(DLDLIBS) AC_SUBST(ENABLE_SHARED) +AC_SUBST(MAINLIBS) ri_prefix= test "$program_prefix" != NONE && @@ -963,5 +1008,6 @@ fi echo "creating config.h" tr -d '\015' < confdefs.h > config.h +: > confdefs.h AC_OUTPUT($FIRSTMAKEFILE Makefile ext/extmk.rb) diff --git a/cygwin/GNUmakefile.in b/cygwin/GNUmakefile.in index 76ce832a31..0e89d15dec 100644 --- a/cygwin/GNUmakefile.in +++ b/cygwin/GNUmakefile.in @@ -21,7 +21,7 @@ $(LIBRUBY_SO): $(RUBYDEF) $(LIBRUBY_SO).res.@OBJEXT@ $(LIBRUBY): $(LIBRUBY_SO) %.res.@OBJEXT@: %.rc - @WINDRES@ --include-dir . --include-dir $( #endif -#if HAVE_DIRENT_H +#if defined HAVE_DIRENT_H && !defined NT # include # define NAMLEN(dirent) strlen((dirent)->d_name) -#elif HAVE_DIRECT_H +#elif defined HAVE_DIRECT_H && !defined NT # include # define NAMLEN(dirent) strlen((dirent)->d_name) #else @@ -44,7 +44,7 @@ # if HAVE_NDIR_H # include # endif -# if defined(NT) && defined(_MSC_VER) +# if defined(NT) # include "missing/dir.h" # endif #endif @@ -61,6 +61,10 @@ char *strchr _((char*,char)); #include +#ifndef HAVE_LSTAT +#define lstat rb_sys_stat +#endif + #define FNM_NOESCAPE 0x01 #define FNM_PATHNAME 0x02 #define FNM_PERIOD 0x04 @@ -69,7 +73,7 @@ char *strchr _((char*,char)); #define FNM_NOMATCH 1 #define FNM_ERROR 2 -#define downcase(c) (nocase && isupper(c) ? tolower(c) : (c)) +#define downcase(c) (nocase && ISUPPER(c) ? tolower(c) : (c)) #if defined DOSISH #define isdirsep(c) ((c) == '/' || (c) == '\\') @@ -531,7 +535,11 @@ extract_path(p, pend) len = pend - p; alloc = ALLOC_N(char, len+1); memcpy(alloc, p, len); - if (len > 1 && pend[-1] == '/') { + if (len > 1 && pend[-1] == '/' +#if defined DOSISH + && pend[-2] != ':' +#endif + ) { alloc[len-1] = 0; } else { @@ -568,7 +576,7 @@ rb_glob_helper(path, flag, func, arg) char *p, *m; if (!has_magic(path, 0)) { - if (stat(path, &st) == 0) { + if (rb_sys_stat(path, &st) == 0) { (*func)(path, arg); } return; @@ -601,12 +609,27 @@ rb_glob_helper(path, flag, func, arg) rb_glob_helper(buf, flag, func, arg); free(buf); } - dirp = opendir(dir); - if (dirp == NULL) { - free(base); - break; + if (rb_sys_stat(dir, &st) < 0) { + free(base); + break; + } + if (S_ISDIR(st.st_mode)) { + dirp = opendir(dir); + if (dirp == NULL) { + free(base); + break; + } + } + else { + free(base); + break; } + +#if defined DOSISH +#define BASE (*base && !((isdirsep(*base) && !base[1]) || (base[1] == ':' && isdirsep(base[2]) && !base[3]))) +#else #define BASE (*base && !(*base == '/' && !base[1])) +#endif for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { if (recursive) { @@ -614,7 +637,15 @@ rb_glob_helper(path, flag, func, arg) continue; buf = ALLOC_N(char, strlen(base)+NAMLEN(dp)+strlen(m)+6); sprintf(buf, "%s%s%s/**%s", base, (BASE)?"/":"", dp->d_name, m); - rb_glob_helper(buf, flag, func, arg); + sprintf(buf, "%s%s%s", base, (BASE)?"/":"", dp->d_name); + if (lstat(buf, &st) < 0) { + continue; + } + if (S_ISDIR(st.st_mode)) { + strcat(buf, "/**"); + strcat(buf, m); + rb_glob_helper(buf, flag, func, arg); + } free(buf); continue; } @@ -679,7 +710,14 @@ push_pattern(path, ary) char *path; VALUE ary; { - rb_ary_push(ary, rb_tainted_str_new2(path)); + VALUE str = rb_tainted_str_new2(path); + + if (ary) { + rb_ary_push(ary, str); + } + else { + rb_yield(str); + } } static void @@ -753,10 +791,12 @@ dir_s_glob(dir, str) char buffer[MAXPATHLEN], *buf = buffer; char *t; int nest; - VALUE ary; + VALUE ary = 0; Check_SafeStr(str); - ary = rb_ary_new(); + if (!rb_block_given_p()) { + ary = rb_ary_new(); + } if (RSTRING(str)->len >= MAXPATHLEN) buf = xmalloc(RSTRING(str)->len + 1); @@ -783,14 +823,6 @@ dir_s_glob(dir, str) } if (buf != buffer) free(buf); - if (rb_block_given_p()) { - long len = RARRAY(ary)->len; - VALUE *ptr = RARRAY(ary)->ptr; - - while (len--) { - rb_yield(*ptr++); - } - } return ary; } diff --git a/djgpp/config.status b/djgpp/config.status deleted file mode 100644 index 7a10754d1d..0000000000 --- a/djgpp/config.status +++ /dev/null @@ -1,77 +0,0 @@ -/^SHELL/s,/bin/sh,$(COMPSEC), -s%@srcdir@%.%g -s%@top_srcdir@%..% -s%@CFLAGS@%-O2%g -s%@CPPFLAGS@%%g -s%@CXXFLAGS@%%g -s%@LDFLAGS@%%g -s%@LIBS@%-lm %g -s%@exec_prefix@%${prefix}%g -s%@prefix@%/usr/local%g -s%@program_transform_name@%s,x,x,%g -s%@bindir@%${exec_prefix}/bin%g -s%@sbindir@%${exec_prefix}/sbin%g -s%@libexecdir@%${exec_prefix}/libexec%g -s%@datadir@%${prefix}/share%g -s%@sysconfdir@%${prefix}/etc%g -s%@sharedstatedir@%${prefix}/com%g -s%@localstatedir@%${prefix}/var%g -s%@libdir@%${exec_prefix}/lib%g -s%@includedir@%${prefix}/include%g -s%@oldincludedir@%/usr/include%g -s%@infodir@%${prefix}/info%g -s%@mandir@%${prefix}/man%g -s%@host@%i386-pc-msdosdjgpp%g -s%@host_alias@%i386-msdosdjgpp%g -s%@host_cpu@%i386%g -s%@host_vendor@%pc%g -s%@host_os@%msdosdjgpp%g -s%@CC@%gcc%g -s%@CPP@%gcc -E%g -s%@YACC@%bison -y%g -s%@RANLIB@%ranlib%g -s%@AR@%ar%g -s%@INSTALL_PROGRAM@%${INSTALL}%g -s%@INSTALL_DATA@%${INSTALL} -m 644%g -s%@SET_MAKE@%%g -s%@LIBOBJS@% crypt.o flock.o vsnprintf.o%g -s%@ALLOCA@%%g -s%@DEFAULT_KCODE@%%g -s%@EXEEXT@%.exe%g -s%@OBJEXT@%o%g -s%@XLDFLAGS@%%g -s%@DLDFLAGS@%%g -s%@STATIC@%%g -s%@CCDLFLAGS@%%g -s%@LDSHARED@%ld%g -s%@DLEXT@%o%g -s%@STRIP@%strip%g -s%@EXTSTATIC@%%g -s%@binsuffix@%.exe%g -s%@setup@%Setup.dj%g -s%@LIBRUBY@%libruby.a%g -s%@LIBRUBY_A@%libruby.a%g -s%@LIBRUBYARG@%libruby.a%g -s%@LIBRUBY_SO@%%g -s%@SOLIBS@%%g -s%@arch@%i386-msdosdjgpp%g -;s%/bin/rm%rm% -s%@DLDLIBS@%-lc%g -s%@PREP@%% -s%@RUBY_INSTALL_NAME@%ruby%g -s%@RUBY_SO_NAME@%%g -s%@arch@%i386-msdosdjgpp%g -s%@sitedir@%${prefix}/lib/ruby/site_ruby%g -s%@MINIRUBY@%./miniruby% -s%@archlib@%/usr/local/lib/ruby/i386-msdosdjgpp% -;s%|| true%% -;/\/dev\/null/ { -;s,/dev/null 2>&1, nul, -;s,2> /dev/null,, -;} -;/^config.status/ { -; N;N;N;N;N;d -;} -;s%y\.tab\.c%y_tab.c% -/^,THIS_IS_DUMMY_PATTERN_/i\ -ac_given_srcdir=. diff --git a/dln.c b/dln.c index c843bee57b..ae3cbf2fb3 100644 --- a/dln.c +++ b/dln.c @@ -1166,7 +1166,7 @@ dln_strerror() } -#if defined(_AIX) +#if defined(_AIX) && ! defined(_IA64) static void aix_loaderror(const char *pathname) { @@ -1204,7 +1204,7 @@ aix_loaderror(const char *pathname) if (nerr == load_errtab[i].errno && load_errtab[i].errstr) ERRBUF_APPEND(load_errtab[i].errstr); } - while (isdigit(*message[i])) message[i]++; + while (ISDIGIT(*message[i])) message[i]++; ERRBUF_APPEND(message[i]); ERRBUF_APPEND("\n"); } @@ -1214,7 +1214,7 @@ aix_loaderror(const char *pathname) } #endif -void +void* dln_load(file) const char *file; { @@ -1234,23 +1234,21 @@ dln_load(file) /* Load file */ if ((handle = LoadLibraryExA(winfile, NULL, LOAD_WITH_ALTERED_SEARCH_PATH)) == NULL) { - printf("LoadLibraryExA: %s\n", winfile); goto failed; } if ((init_fct = (void(*)())GetProcAddress(handle, buf)) == NULL) { - printf("GetProcAddress %s\n", buf); - goto failed; + rb_loaderror("%s - %s\n%s", dln_strerror(), buf, file); } /* Call the init code */ (*init_fct)(); - return; + return handle; #else #ifdef USE_DLN_A_OUT if (load(file) == -1) { goto failed; } - return; + return 0; #else char buf[MAXPATHLEN]; @@ -1276,11 +1274,12 @@ dln_load(file) } if ((init_fct = (void(*)())dlsym(handle, buf)) == NULL) { + dlclose(handle); goto failed; } /* Call the init code */ (*init_fct)(); - return; + return handle; } #endif /* USE_DLN_DLOPEN */ @@ -1306,11 +1305,11 @@ dln_load(file) } } (*init_fct)(); - return; + return (void*)lib; } #endif /* hpux */ -#if defined(_AIX) +#if defined(_AIX) && ! defined(_IA64) #define DLN_DEFINED { void (*init_fct)(); @@ -1323,7 +1322,7 @@ dln_load(file) aix_loaderror(file); } (*init_fct)(); - return; + return (void*)init_fct; } #endif /* _AIX */ @@ -1362,7 +1361,7 @@ dln_load(file) init_fct = (void(*)())init_address; (*init_fct)(); - return; + return (void*)init_address; } #else/* OPENSTEP dyld functions */ { @@ -1392,7 +1391,7 @@ dln_load(file) init_fct = NSAddressOfSymbol(NSLookupAndBindSymbol(buf)); (*init_fct)(); - return; + return (void*)init_fct; } #endif /* rld or dyld */ #endif @@ -1440,7 +1439,7 @@ dln_load(file) /* call module initialize function. */ (*init_fct)(); - return; + return (void*)img_id; } #endif /* __BEOS__*/ @@ -1488,7 +1487,7 @@ dln_load(file) init_fct = (void (*)())symAddr; (*init_fct)(); - return; + return (void*)init_fct; } #endif /* __MACOS__ */ diff --git a/dln.h b/dln.h index 7e3ab9fabb..c29d3bd8e9 100644 --- a/dln.h +++ b/dln.h @@ -29,5 +29,5 @@ char *dln_find_file _((const char*,const char*)); extern char *dln_argv0; #endif -void dln_load _((const char*)); +void *dln_load _((const char*)); #endif diff --git a/error.c b/error.c index 4527128030..6a008cdac5 100644 --- a/error.c +++ b/error.c @@ -694,6 +694,13 @@ rb_sys_fail(mesg) rb_exc_raise(ee); } +void +rb_load_fail(path) + char *path; +{ + rb_loaderror("%s -- %s", strerror(errno), path); +} + void rb_error_frozen(what) char *what; diff --git a/eval.c b/eval.c index ae2ce62da9..b1f01f958d 100644 --- a/eval.c +++ b/eval.c @@ -6,7 +6,7 @@ $Date$ created at: Thu Jun 10 14:22:17 JST 1993 - Copyright (C) 1993-2000 Yukihiro Matsumoto + Copyright (C) 1993-2001 Yukihiro Matsumoto Copyright (C) 2000 Network Applied Communication Laboratory, Inc. Copyright (C) 2000 Information-technology Promotion Agency, Japan @@ -22,6 +22,25 @@ #include "st.h" #include "dln.h" +/* Make alloca work the best possible way. */ +#ifdef __GNUC__ +# ifndef atarist +# ifndef alloca +# define alloca __builtin_alloca +# endif +# endif /* atarist */ +#else +# if defined(HAVE_ALLOCA_H) +# include +# elif !defined(alloca) +char *alloca(); +# endif +#endif /* __GNUC__ */ + +#ifdef _AIX +#pragma alloca +#endif + #ifdef HAVE_STDARG_PROTOTYPES #include #define va_init_list(a,b) va_start(a,b) @@ -109,33 +128,8 @@ int ruby_safe_level = 0; 4 - no global (non-tainted) variable modification/no direct output */ -void -rb_set_safe_level(level) - int level; -{ - if (level > ruby_safe_level) { - ruby_safe_level = level; - } -} - -static VALUE -safe_getter() -{ - return INT2FIX(ruby_safe_level); -} - -static void -safe_setter(val) - VALUE val; -{ - int level = NUM2INT(val); - - if (level < ruby_safe_level) { - rb_raise(rb_eSecurityError, "tried to downgrade safe level from %d to %d", - ruby_safe_level, level); - } - ruby_safe_level = level; -} +static VALUE safe_getter _((void)); +static void safe_setter _((VALUE val)); void rb_secure(level) @@ -483,9 +477,9 @@ rb_attr(klass, id, read, write, ex) rb_clear_cache_by_id(id); rb_funcall(klass, added, 1, ID2SYM(id)); } - sprintf(buf, "%s=", name); - id = rb_intern(buf); if (write) { + sprintf(buf, "%s=", name); + id = rb_intern(buf); rb_add_method(klass, id, NEW_ATTRSET(attriv), noex); rb_clear_cache_by_id(id); rb_funcall(klass, added, 1, ID2SYM(id)); @@ -527,14 +521,20 @@ static struct SCOPE *top_scope; ruby_sourceline = _frame.line; \ ruby_frame = _frame.prev; } +struct BLOCKTAG { + struct RBasic super; + long dst; + long flags; +}; + struct BLOCK { NODE *var; NODE *body; VALUE self; struct FRAME frame; struct SCOPE *scope; + struct BLOCKTAG *tag; VALUE klass; - struct tag *tag; int iter; int vmode; int flags; @@ -545,12 +545,23 @@ struct BLOCK { #define BLOCK_D_SCOPE 1 #define BLOCK_DYNAMIC 2 +#define BLOCK_ORPHAN 4 static struct BLOCK *ruby_block; +static struct BLOCKTAG* +new_blktag() +{ + NEWOBJ(blktag, struct BLOCKTAG); + OBJSETUP(blktag, 0, T_BLKTAG); + blktag->dst = 0; + blktag->flags = 0; + return blktag; +} + #define PUSH_BLOCK(v,b) { \ struct BLOCK _block; \ - _block.tag = prot_tag; \ + _block.tag = new_blktag(); \ _block.var = v; \ _block.body = b; \ _block.self = self; \ @@ -566,19 +577,18 @@ static struct BLOCK *ruby_block; _block.dyna_vars = ruby_dyna_vars; \ ruby_block = &_block; +#define POP_BLOCK_TAG(tag) do { \ + if ((tag)->flags & BLOCK_DYNAMIC) \ + (tag)->flags |= BLOCK_ORPHAN; \ + else \ + rb_gc_force_recycle((VALUE)tag); \ +} while (0) + #define POP_BLOCK() \ + POP_BLOCK_TAG(_block.tag); \ ruby_block = _block.prev; \ } -#define PUSH_BLOCK2(b) { \ - struct BLOCK * volatile _old; \ - _old = ruby_block; \ - ruby_block = b; - -#define POP_BLOCK2() \ - ruby_block = _old; \ -} - struct RVarmap *ruby_dyna_vars; #define PUSH_VARS() { \ struct RVarmap * volatile _old; \ @@ -586,6 +596,8 @@ struct RVarmap *ruby_dyna_vars; ruby_dyna_vars = 0; #define POP_VARS() \ + if (_old && (ruby_scope->flag & SCOPE_DONT_RECYCLE)) \ + FL_SET(_old, DVAR_DONT_RECYCLE); \ ruby_dyna_vars = _old; \ } @@ -739,7 +751,6 @@ static struct tag *prot_tag; _tag.frame = ruby_frame; \ _tag.iter = ruby_iter; \ _tag.prev = prot_tag; \ - _tag.retval = Qnil; \ _tag.scope = ruby_scope; \ _tag.tag = ptag; \ _tag.dst = 0; \ @@ -785,6 +796,11 @@ static VALUE ruby_wrapper; /* security wrapper */ #define POP_CLASS() ruby_class = _class; } +static NODE *ruby_cref = 0; +static NODE *top_cref; +#define PUSH_CREF(c) ruby_cref = rb_node_newnode(NODE_CREF,(c),0,ruby_cref) +#define POP_CREF() ruby_cref = ruby_cref->nd_next + #define PUSH_SCOPE() { \ volatile int _vmode = scope_vmode; \ struct SCOPE * volatile _old; \ @@ -1011,7 +1027,9 @@ ruby_init() rb_call_inits(); ruby_class = rb_cObject; ruby_frame->self = ruby_top_self; - ruby_frame->cbase = (VALUE)rb_node_newnode(NODE_CREF,rb_cObject,0,0); + top_cref = rb_node_newnode(NODE_CREF,rb_cObject,0,0); + ruby_cref = top_cref; + ruby_frame->cbase = (VALUE)ruby_cref; rb_define_global_const("TOPLEVEL_BINDING", rb_f_binding(ruby_top_self)); #ifdef __MACOS__ _macruby_init(); @@ -1051,7 +1069,7 @@ static int error_handle(ex) int ex; { - switch (ex & 0xf) { + switch (ex & TAG_MASK) { case 0: ex = 0; break; @@ -1122,9 +1140,13 @@ void rb_exec_end_proc _((void)); void ruby_finalize() { - rb_trap_exit(); - rb_exec_end_proc(); - rb_gc_call_finalizer_at_exit(); + PUSH_TAG(PROT_NONE); + if (EXEC_TAG() == 0) { + rb_trap_exit(); + rb_exec_end_proc(); + rb_gc_call_finalizer_at_exit(); + } + POP_TAG(); } void @@ -1255,6 +1277,34 @@ rb_eval_string_wrap(str, state) return val; } +static void +jump_tag_but_local_jump(state) + int state; +{ + switch (state) { + case 0: + break; + case TAG_RETURN: + rb_raise(rb_eLocalJumpError, "unexpected return"); + break; + case TAG_NEXT: + rb_raise(rb_eLocalJumpError, "unexpected next"); + break; + case TAG_BREAK: + rb_raise(rb_eLocalJumpError, "unexpected break"); + break; + case TAG_REDO: + rb_raise(rb_eLocalJumpError, "unexpected redo"); + break; + case TAG_RETRY: + rb_raise(rb_eLocalJumpError, "retry outside of rescue clause"); + break; + default: + JUMP_TAG(state); + break; + } +} + VALUE rb_eval_cmd(cmd, arg) VALUE cmd, arg; @@ -1290,28 +1340,7 @@ rb_eval_cmd(cmd, arg) POP_TAG(); POP_CLASS(); - switch (state) { - case 0: - break; - case TAG_RETURN: - rb_raise(rb_eLocalJumpError, "unexpected return"); - break; - case TAG_NEXT: - rb_raise(rb_eLocalJumpError, "unexpected next"); - break; - case TAG_BREAK: - rb_raise(rb_eLocalJumpError, "unexpected break"); - break; - case TAG_REDO: - rb_raise(rb_eLocalJumpError, "unexpected redo"); - break; - case TAG_RETRY: - rb_raise(rb_eLocalJumpError, "retry outside of rescue clause"); - break; - default: - JUMP_TAG(state); - break; - } + jump_tag_but_local_jump(state); return val; } @@ -1373,17 +1402,18 @@ superclass(self, node) #define ruby_cbase (RNODE(ruby_frame->cbase)->nd_clss) static VALUE -ev_const_defined(cref, id) +ev_const_defined(cref, id, self) NODE *cref; ID id; + VALUE self; { NODE *cbase = cref; - while (cbase && cbase->nd_clss != rb_cObject) { + while (cbase && cbase->nd_next) { struct RClass *klass = RCLASS(cbase->nd_clss); - if (klass->iv_tbl && - st_lookup(klass->iv_tbl, id, 0)) { + if (NIL_P(klass)) return rb_const_defined(CLASS_OF(self), id); + if (klass->iv_tbl && st_lookup(klass->iv_tbl, id, 0)) { return Qtrue; } cbase = cbase->nd_next; @@ -1392,16 +1422,18 @@ ev_const_defined(cref, id) } static VALUE -ev_const_get(cref, id) +ev_const_get(cref, id, self) NODE *cref; ID id; + VALUE self; { NODE *cbase = cref; VALUE result; - while (cbase && cbase->nd_clss != rb_cObject) { + while (cbase && cbase->nd_next) { struct RClass *klass = RCLASS(cbase->nd_clss); + if (NIL_P(klass)) return rb_const_get(CLASS_OF(self), id); if (klass->iv_tbl && st_lookup(klass->iv_tbl, id, &result)) { return result; } @@ -1410,35 +1442,14 @@ ev_const_get(cref, id) return rb_const_get(cref->nd_clss, id); } -static VALUE -ev_const_set(cref, id, val) - NODE *cref; - ID id; - VALUE val; -{ - NODE *cbase = cref; - - while (cbase && cbase->nd_clss != rb_cObject) { - struct RClass *klass = RCLASS(cbase->nd_clss); - - if (klass->iv_tbl && st_lookup(klass->iv_tbl, id, 0)) { - st_insert(klass->iv_tbl, id, val); - return val; - } - cbase = cbase->nd_next; - } - rb_const_assign(cbase->nd_clss, id, val); - return val; -} - static VALUE rb_mod_nesting() { NODE *cbase = RNODE(ruby_frame->cbase); VALUE ary = rb_ary_new(); - while (cbase && cbase->nd_clss != rb_cObject) { - rb_ary_push(ary, cbase->nd_clss); + while (cbase && cbase->nd_next) { + if (!NIL_P(cbase->nd_clss)) rb_ary_push(ary, cbase->nd_clss); cbase = cbase->nd_next; } return ary; @@ -1450,12 +1461,12 @@ rb_mod_s_constants() NODE *cbase = RNODE(ruby_frame->cbase); VALUE ary = rb_ary_new(); - while (cbase && cbase->nd_clss != rb_cObject) { - rb_mod_const_at(cbase->nd_clss, ary); + while (cbase) { + if (!NIL_P(cbase->nd_clss)) rb_mod_const_at(cbase->nd_clss, ary); cbase = cbase->nd_next; } - rb_mod_const_of(ruby_cbase, ary); + if (!NIL_P(ruby_cbase)) rb_mod_const_of(ruby_cbase, ary); return ary; } @@ -1576,22 +1587,32 @@ rb_mod_alias_method(mod, newname, oldname) return mod; } +static NODE* +copy_node_scope(node, rval) + NODE *node; + VALUE rval; +{ + NODE *copy = rb_node_newnode(NODE_SCOPE,0,rval,node->nd_next); + + if (node->nd_tbl) { + copy->nd_tbl = ALLOC_N(ID, node->nd_tbl[0]+1); + MEMCPY(copy->nd_tbl, node->nd_tbl, ID, node->nd_tbl[0]+1); + } + else { + copy->nd_tbl = 0; + } + return copy; +} + #ifdef C_ALLOCA # define TMP_PROTECT NODE * volatile tmp__protect_tmp=0 # define TMP_ALLOC(n) \ (tmp__protect_tmp = rb_node_newnode(NODE_ALLOCA, \ ALLOC_N(VALUE,n),tmp__protect_tmp,n), \ (void*)tmp__protect_tmp->nd_head) -# define TMP_PROTECT_END do {\ - if (tmp__protect_tmp) {\ - rb_gc_force_recycle((VALUE)tmp__protect_tmp);\ - alloca(0);\ - }\ -} while (0) #else # define TMP_PROTECT typedef int foobazzz # define TMP_ALLOC(n) ALLOCA_N(VALUE,n) -# define TMP_PROTECT_END #endif #define SETUP_ARGS(anode) {\ @@ -1776,7 +1797,7 @@ is_defined(self, node, buf) break; case NODE_CONST: - if (ev_const_defined(RNODE(ruby_frame->cbase), node->nd_vid)) { + if (ev_const_defined(RNODE(ruby_frame->cbase), node->nd_vid, self)) { return "constant"; } break; @@ -2207,15 +2228,14 @@ rb_eval(self, n) case NODE_FOR: { iter_retry: - PUSH_BLOCK(node->nd_var, node->nd_body); PUSH_TAG(PROT_FUNC); + PUSH_BLOCK(node->nd_var, node->nd_body); state = EXEC_TAG(); if (state == 0) { + PUSH_ITER(ITER_PRE); if (nd_type(node) == NODE_ITER) { - PUSH_ITER(ITER_PRE); result = rb_eval(self, node->nd_iter); - POP_ITER(); } else { VALUE recv; @@ -2223,13 +2243,14 @@ rb_eval(self, n) int line = ruby_sourceline; _block.flags &= ~BLOCK_D_SCOPE; + BEGIN_CALLARGS; recv = rb_eval(self, node->nd_iter); - PUSH_ITER(ITER_PRE); + END_CALLARGS; ruby_sourcefile = file; ruby_sourceline = line; result = rb_call(CLASS_OF(recv),recv,each,0,0,0); - POP_ITER(); } + POP_ITER(); } else if (_block.tag->dst == state) { state &= TAG_MASK; @@ -2237,8 +2258,8 @@ rb_eval(self, n) result = prot_tag->retval; } } - POP_TAG(); POP_BLOCK(); + POP_TAG(); switch (state) { case 0: break; @@ -2460,7 +2481,6 @@ rb_eval(self, n) END_CALLARGS; result = rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0); - TMP_PROTECT_END; } break; @@ -2474,7 +2494,6 @@ rb_eval(self, n) END_CALLARGS; result = rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,1); - TMP_PROTECT_END; } break; @@ -2507,13 +2526,13 @@ rb_eval(self, n) ruby_frame->self, ruby_frame->last_func, argc, argv, 3); POP_ITER(); - TMP_PROTECT_END; } break; case NODE_SCOPE: { struct FRAME frame; + NODE *saved_cref = 0; frame = *ruby_frame; frame.tmp = ruby_frame; @@ -2521,7 +2540,11 @@ rb_eval(self, n) PUSH_SCOPE(); PUSH_TAG(PROT_NONE); - if (node->nd_rval) ruby_frame->cbase = node->nd_rval; + if (node->nd_rval) { + saved_cref = ruby_cref; + ruby_cref = (NODE*)node->nd_rval; + ruby_frame->cbase = node->nd_rval; + } if (node->nd_tbl) { VALUE *vars = ALLOCA_N(VALUE, node->nd_tbl[0]+1); *vars++ = (VALUE)node; @@ -2539,6 +2562,8 @@ rb_eval(self, n) POP_TAG(); POP_SCOPE(); ruby_frame = frame.tmp; + if (saved_cref) + ruby_cref = saved_cref; if (state) JUMP_TAG(state); } break; @@ -2569,7 +2594,6 @@ rb_eval(self, n) argv[argc-1] = val; val = rb_funcall2(recv, aset, argc, argv); result = val; - TMP_PROTECT_END; } break; @@ -2688,7 +2712,7 @@ rb_eval(self, n) break; case NODE_CONST: - result = ev_const_get(RNODE(ruby_frame->cbase), node->nd_vid); + result = ev_const_get(RNODE(ruby_frame->cbase), node->nd_vid, self); break; case NODE_CVAR: /* normal method */ @@ -2878,7 +2902,7 @@ rb_eval(self, n) case NODE_DEFN: if (node->nd_defn) { - NODE *body; + NODE *body, *defn; VALUE origin; int noex; @@ -2920,11 +2944,13 @@ rb_eval(self, n) if (body && origin == ruby_class && body->nd_noex & NOEX_UNDEF) { noex |= NOEX_UNDEF; } - rb_add_method(ruby_class, node->nd_mid, node->nd_defn, noex); + + defn = copy_node_scope(node->nd_defn, ruby_cref); + rb_add_method(ruby_class, node->nd_mid, defn, noex); rb_clear_cache_by_id(node->nd_mid); if (scope_vmode == SCOPE_MODFUNC) { rb_add_method(rb_singleton_class(ruby_class), - node->nd_mid, node->nd_defn, NOEX_PUBLIC); + node->nd_mid, defn, NOEX_PUBLIC); rb_funcall(ruby_class, singleton_added, 1, ID2SYM(node->nd_mid)); } if (FL_TEST(ruby_class, FL_SINGLETON)) { @@ -2942,7 +2968,7 @@ rb_eval(self, n) if (node->nd_defn) { VALUE recv = rb_eval(self, node->nd_recv); VALUE klass; - NODE *body = 0; + NODE *body = 0, *defn; if (rb_safe_level() >= 4 && !OBJ_TAINTED(recv)) { rb_raise(rb_eSecurityError, "Insecure; can't define singleton method"); @@ -2964,7 +2990,9 @@ rb_eval(self, n) rb_warning("redefine %s", rb_id2name(node->nd_mid)); } } - rb_add_method(klass, node->nd_mid, node->nd_defn, + defn = copy_node_scope(node->nd_defn, ruby_cref); + defn->nd_rval = (VALUE)ruby_cref; + rb_add_method(klass, node->nd_mid, defn, NOEX_PUBLIC|(body?body->nd_noex&NOEX_UNDEF:0)); rb_clear_cache_by_id(node->nd_mid); rb_funcall(recv, singleton_added, 1, ID2SYM(node->nd_mid)); @@ -3162,16 +3190,11 @@ module_setup(module, n) frame.tmp = ruby_frame; ruby_frame = &frame; - /* fill c-ref */ - node->nd_clss = module; - node = node->nd_body; - PUSH_CLASS(); ruby_class = module; PUSH_SCOPE(); PUSH_VARS(); - if (node->nd_rval) ruby_frame->cbase = node->nd_rval; if (node->nd_tbl) { VALUE *vars = TMP_ALLOC(node->nd_tbl[0]+1); *vars++ = (VALUE)node; @@ -3184,6 +3207,8 @@ module_setup(module, n) ruby_scope->local_tbl = 0; } + PUSH_CREF(module); + ruby_frame->cbase = (VALUE)ruby_cref; PUSH_TAG(PROT_NONE); if ((state = EXEC_TAG()) == 0) { if (trace_func) { @@ -3194,6 +3219,7 @@ module_setup(module, n) result = rb_eval(ruby_class, node->nd_next); } POP_TAG(); + POP_CREF(); POP_VARS(); POP_SCOPE(); POP_CLASS(); @@ -3203,7 +3229,6 @@ module_setup(module, n) call_trace_func("end", file, line, 0, ruby_frame->last_func, ruby_frame->last_class); } - TMP_PROTECT_END; if (state) JUMP_TAG(state); return result; @@ -3467,7 +3492,7 @@ rb_yield_0(val, self, klass, acheck) int state; static unsigned serial = 1; - if (!ruby_frame->iter || !ruby_block) { + if (!(rb_block_given_p() || rb_f_block_given_p()) || !ruby_block) { rb_raise(rb_eLocalJumpError, "yield called out of block"); } @@ -3489,7 +3514,7 @@ rb_yield_0(val, self, klass, acheck) ruby_dyna_vars = block->dyna_vars; } ruby_class = klass?klass:block->klass; - if (!self) self = block->self; + if (!klass) self = block->self; node = block->body; if (block->var) { @@ -3526,7 +3551,7 @@ rb_yield_0(val, self, klass, acheck) if (!node) { result = Qnil; } - else if (nd_type(node) == NODE_CFUNC) { + else if (nd_type(node) == NODE_CFUNC || nd_type(node) == NODE_IFUNC) { if (val == Qundef) val = rb_ary_new2(0); result = (*node->nd_cfnc)(val, node->nd_tval, self); } @@ -3548,7 +3573,7 @@ rb_yield_0(val, self, klass, acheck) case TAG_RETURN: state |= (serial++ << 8); state |= 0x10; - block->tag->dst = state; + block->tag->dst = state; break; default: break; @@ -3558,26 +3583,56 @@ rb_yield_0(val, self, klass, acheck) pop_state: POP_ITER(); POP_CLASS(); - if ((block->flags & BLOCK_D_SCOPE) && +#if 0 + if (ruby_dyna_vars && (block->flags & BLOCK_D_SCOPE) && + (!(ruby_scope->flags & SCOPE_DONT_RECYCLE) || + !(block->tag->flags & BLOCK_DYNAMIC) || + !FL_TEST(ruby_dyna_vars, DVAR_DONT_RECYCLE))) { + struct RVarmap *vars, *tmp; + + if (ruby_dyna_vars->id == 0) { + vars = ruby_dyna_vars->next; + rb_gc_force_recycle((VALUE)ruby_dyna_vars); + while (vars && vars->id != 0) { + tmp = vars->next; + rb_gc_force_recycle((VALUE)vars); + vars = tmp; + } + } + } +#else + if (ruby_dyna_vars && (block->flags & BLOCK_D_SCOPE) && !FL_TEST(ruby_dyna_vars, DVAR_DONT_RECYCLE)) { struct RVarmap *vars = ruby_dyna_vars; - while (vars && vars->id != 0) { - struct RVarmap *tmp = vars->next; - rb_gc_force_recycle((VALUE)vars); - vars = tmp; - } - if (ruby_dyna_vars && ruby_dyna_vars->id == 0) { + if (ruby_dyna_vars->id == 0) { + vars = ruby_dyna_vars->next; rb_gc_force_recycle((VALUE)ruby_dyna_vars); + while (vars && vars->id != 0) { + struct RVarmap *tmp = vars->next; + rb_gc_force_recycle((VALUE)vars); + vars = tmp; + } } } +#endif POP_VARS(); ruby_block = block; ruby_frame = ruby_frame->prev; if (ruby_scope->flag & SCOPE_DONT_RECYCLE) scope_dup(old_scope); ruby_scope = old_scope; - if (state) JUMP_TAG(state); + if (state) { + if (!block->tag) { + switch (state & TAG_MASK) { + case TAG_BREAK: + case TAG_RETURN: + jump_tag_but_local_jump(state & TAG_MASK); + break; + } + } + JUMP_TAG(state); + } return result; } @@ -3744,7 +3799,7 @@ rb_iterate(it_proc, data1, bl_proc, data2) { int state; volatile VALUE retval = Qnil; - NODE *node = NEW_CFUNC(bl_proc, data2); + NODE *node = NEW_IFUNC(bl_proc, data2); VALUE self = ruby_top_self; iter_retry: @@ -3809,7 +3864,6 @@ handle_rescue(self, node) if (rb_obj_is_kind_of(ruby_errinfo, argv[0])) return 1; argv++; } - TMP_PROTECT_END; return 0; } @@ -4053,6 +4107,7 @@ static int STACK_LEVEL_MAX = 65535; #ifdef __human68k__ extern int _stacksize; # define STACK_LEVEL_MAX (_stacksize - 4096) +#undef HAVE_GETRLIMIT #else #ifdef HAVE_GETRLIMIT static int STACK_LEVEL_MAX = 655300; @@ -4072,7 +4127,7 @@ stack_length(p) alloca(0); # define STACK_END (&stack_end) #else -# if defined(__GNUC__) && !defined(__alpha__) && !defined(__APPLE__) +# if defined(__GNUC__) && defined(__i386__) VALUE *stack_end = __builtin_frame_address(0); # else VALUE *stack_end = alloca(1); @@ -4081,7 +4136,7 @@ stack_length(p) #endif if (p) *p = STACK_END; -#ifdef sparc +#ifdef __sparc__ return rb_gc_stack_start - STACK_END + 0x80; #else return (STACK_END < rb_gc_stack_start) ? rb_gc_stack_start - STACK_END @@ -4266,14 +4321,19 @@ rb_call0(klass, recv, id, argc, argv, body, nosuper) result = proc_call(body->nd_cval, rb_ary_new4(argc, argv)); break; - default: + case NODE_SCOPE: { int state; VALUE *local_vars; /* OK */ + NODE *saved_cref = 0; PUSH_SCOPE(); - if (body->nd_rval) ruby_frame->cbase = body->nd_rval; + if (body->nd_rval) { + saved_cref = ruby_cref; + ruby_cref = (NODE*)body->nd_rval; + ruby_frame->cbase = body->nd_rval; + } if (body->nd_tbl) { local_vars = TMP_ALLOC(body->nd_tbl[0]+1); *local_vars++ = (VALUE)body; @@ -4366,6 +4426,7 @@ rb_call0(klass, recv, id, argc, argv, body, nosuper) POP_TAG(); POP_VARS(); POP_SCOPE(); + ruby_cref = saved_cref; if (trace_func) { char *file = ruby_frame->prev->file; int line = ruby_frame->prev->line; @@ -4379,27 +4440,24 @@ rb_call0(klass, recv, id, argc, argv, body, nosuper) case 0: break; - case TAG_NEXT: - rb_raise(rb_eLocalJumpError, "unexpected next"); - break; - case TAG_BREAK: - rb_raise(rb_eLocalJumpError, "unexpected break"); - break; - case TAG_REDO: - rb_raise(rb_eLocalJumpError, "unexpected redo"); - break; case TAG_RETRY: - if (!rb_block_given_p()) { - rb_raise(rb_eLocalJumpError, "retry outside of rescue clause"); + if (rb_block_given_p()) { + break; } + /* fall through */ default: - JUMP_TAG(state); + jump_tag_but_local_jump(state); + break; } } + break; + + default: + rb_bug("unknown node type %d", nd_type(body)); + break; } POP_FRAME(); POP_ITER(); - TMP_PROTECT_END; return result; } @@ -4416,6 +4474,9 @@ rb_call(klass, recv, mid, argc, argv, scope) ID id = mid; struct cache_entry *ent; + if (!klass) { + rb_raise(rb_eNotImpError, "method call on terminated object"); + } /* is it in the method cache? */ ent = cache + EXPR1(klass, mid); if (ent->mid == mid && ent->klass == klass) { @@ -4701,7 +4762,6 @@ eval(self, src, scope, file, line) } Data_Get_Struct(scope, struct BLOCK, data); - /* PUSH BLOCK from data */ frame = data->frame; frame.tmp = ruby_frame; /* gc protection */ @@ -4747,14 +4807,33 @@ eval(self, src, scope, file, line) POP_CLASS(); ruby_in_eval--; if (!NIL_P(scope)) { + int dont_recycle = ruby_scope->flag & SCOPE_DONT_RECYCLE; + ruby_frame = frame.tmp; - if (ruby_scope->flag & SCOPE_DONT_RECYCLE) - scope_dup(old_scope); ruby_scope = old_scope; ruby_block = old_block; ruby_dyna_vars = old_dyna_vars; data->vmode = scope_vmode; /* write back visibility mode */ scope_vmode = old_vmode; + if (dont_recycle) { + struct tag *tag; + struct RVarmap *vars; + + scope_dup(ruby_scope); + for (tag=prot_tag; tag; tag=tag->prev) { + scope_dup(tag->scope); + } + if (ruby_block) { + struct BLOCK *block = ruby_block; + while (block) { + block->tag->flags |= BLOCK_DYNAMIC; + block = block->prev; + } + } + for (vars = ruby_dyna_vars; vars; vars = vars->next) { + FL_SET(vars, DVAR_DONT_RECYCLE); + } + } } else { ruby_frame->iter = iter; @@ -4849,6 +4928,7 @@ exec_under(func, under, args) if (ruby_cbase != under) { ruby_frame->cbase = (VALUE)rb_node_newnode(NODE_CREF,under,0,ruby_frame->cbase); } + PUSH_CREF(under); mode = scope_vmode; SCOPE_SET(SCOPE_PUBLIC); @@ -4857,6 +4937,7 @@ exec_under(func, under, args) val = (*func)(args); } POP_TAG(); + POP_CREF(); SCOPE_SET(mode); POP_FRAME(); POP_CLASS(); @@ -5014,6 +5095,7 @@ rb_load(fname, wrap) volatile ID last_func; volatile VALUE wrapper = 0; volatile VALUE self = ruby_top_self; + NODE *saved_cref = ruby_cref; TMP_PROTECT; if (wrap) { @@ -5031,6 +5113,7 @@ rb_load(fname, wrap) PUSH_VARS(); PUSH_CLASS(); wrapper = ruby_wrapper; + ruby_cref = top_cref; if (!wrap) { rb_secure(4); /* should alter global state */ ruby_class = rb_cObject; @@ -5041,6 +5124,7 @@ rb_load(fname, wrap) ruby_class = ruby_wrapper = rb_module_new(); self = rb_obj_clone(ruby_top_self); rb_extend_object(self, ruby_class); + PUSH_CREF(ruby_wrapper); } PUSH_FRAME(); ruby_frame->last_func = 0; @@ -5083,6 +5167,7 @@ rb_load(fname, wrap) free(ruby_scope->local_tbl); } POP_TAG(); + ruby_cref = saved_cref; POP_SCOPE(); POP_FRAME(); POP_CLASS(); @@ -5092,8 +5177,7 @@ rb_load(fname, wrap) ruby_nerrs = 0; rb_exc_raise(ruby_errinfo); } - TMP_PROTECT_END; - if (state) JUMP_TAG(state); + if (state) jump_tag_but_local_jump(state); if (!NIL_P(ruby_errinfo)) /* exception during load */ rb_exc_raise(ruby_errinfo); } @@ -5126,6 +5210,7 @@ rb_f_load(argc, argv) return Qtrue; } +VALUE ruby_dln_librefs; static VALUE rb_features; static st_table *loading_tbl; @@ -5167,7 +5252,7 @@ rb_feature_p(feature, wait) while (st_lookup(loading_tbl, f, &th)) { if (th == curr_thread) { - rb_raise(rb_eLoadError, "infinite load loop -- %s", f); + return Qtrue; } CHECK_INTS; rb_thread_schedule(); @@ -5293,9 +5378,12 @@ rb_f_require(obj, fname) PUSH_TAG(PROT_NONE); if ((state = EXEC_TAG()) == 0) { + void *handle; + load = rb_str_new2(file); file = RSTRING(load)->ptr; - dln_load(file); + handle = dln_load(file); + rb_ary_push(ruby_dln_librefs, INT2NUM((long)handle)); } POP_TAG(); if (state) JUMP_TAG(state); @@ -5332,6 +5420,15 @@ rb_require(fname) return rb_f_require(Qnil, rb_str_new2(fname)); } +static void +secure_visibility(self) + VALUE self; +{ + if (rb_safe_level() >= 4 && !OBJ_TAINTED(self)) { + rb_raise(rb_eSecurityError, "Insecure: can't change method visibility"); + } +} + static void set_method_visibility(self, argc, argv, ex) VALUE self; @@ -5341,6 +5438,7 @@ set_method_visibility(self, argc, argv, ex) { int i; + secure_visibility(self); for (i=0; iself); rb_gc_mark(data->dyna_vars); rb_gc_mark(data->klass); + rb_gc_mark(data->tag); data = data->prev; } } @@ -5916,6 +6022,7 @@ blk_copy_prev(block) struct BLOCK *block; { struct BLOCK *tmp; + struct RVarmap* vars; while (block->prev) { tmp = ALLOC_N(struct BLOCK, 1); @@ -5925,6 +6032,13 @@ blk_copy_prev(block) MEMCPY(tmp->frame.argv, block->prev->frame.argv, VALUE, tmp->frame.argc); } scope_dup(tmp->scope); + tmp->tag->flags |= BLOCK_DYNAMIC; + + for (vars = tmp->dyna_vars; vars; vars = vars->next) { + if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; + FL_SET(vars, DVAR_DONT_RECYCLE); + } + block->prev = tmp; block = tmp; } @@ -5980,7 +6094,7 @@ static VALUE rb_f_binding(self) VALUE self; { - struct BLOCK *data; + struct BLOCK *data, *p; struct RVarmap *vars; VALUE bind; @@ -6002,10 +6116,14 @@ rb_f_binding(self) else { data->prev = 0; } + data->flags |= BLOCK_DYNAMIC; + data->tag->flags |= BLOCK_DYNAMIC; - for (vars = data->dyna_vars; vars; vars = vars->next) { - if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; - FL_SET(vars, DVAR_DONT_RECYCLE); + for (p = data; p; p = p->prev) { + for (vars = p->dyna_vars; vars; vars = vars->next) { + if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; + FL_SET(vars, DVAR_DONT_RECYCLE); + } } scope_dup(data->scope); POP_BLOCK(); @@ -6063,11 +6181,11 @@ proc_new(klass) VALUE klass; { volatile VALUE proc; - struct BLOCK *data; + struct BLOCK *data, *p; struct RVarmap *vars; if (!rb_block_given_p() && !rb_f_block_given_p()) { - rb_raise(rb_eArgError, "tried to create Procedure-Object without a block"); + rb_raise(rb_eArgError, "tried to create Proc object without a block"); } proc = Data_Make_Struct(klass, struct BLOCK, blk_mark, blk_free, data); @@ -6075,7 +6193,6 @@ proc_new(klass) data->orig_thread = rb_thread_current(); data->iter = data->prev?Qtrue:Qfalse; - data->tag = 0; /* should not point into stack */ frame_dup(&data->frame); if (data->iter) { blk_copy_prev(data); @@ -6084,10 +6201,13 @@ proc_new(klass) data->prev = 0; } data->flags |= BLOCK_DYNAMIC; + data->tag->flags |= BLOCK_DYNAMIC; - for (vars = data->dyna_vars; vars; vars = vars->next) { - if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; - FL_SET(vars, DVAR_DONT_RECYCLE); + for (p = data; p; p = p->prev) { + for (vars = p->dyna_vars; vars; vars = vars->next) { + if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; + FL_SET(vars, DVAR_DONT_RECYCLE); + } } scope_dup(data->scope); proc_save_safe_level(proc); @@ -6165,6 +6285,8 @@ proc_call(proc, args) old_block = ruby_block; _block = *data; ruby_block = &_block; + ruby_block->frame.iter = ITER_NOT; + PUSH_ITER(ITER_CUR); ruby_frame->iter = ITER_CUR; @@ -6172,17 +6294,7 @@ proc_call(proc, args) args = callargs(args); } - if (orphan) {/* orphan procedure */ - if (rb_block_given_p()) { - ruby_block->frame.iter = ITER_CUR; - } - else { - ruby_block->frame.iter = ITER_NOT; - } - } - PUSH_TAG(PROT_NONE); - _block.tag = prot_tag; state = EXEC_TAG(); if (state == 0) { proc_set_safe_level(proc); @@ -6242,6 +6354,39 @@ proc_arity(proc) } } +static VALUE +proc_eq(self, other) + VALUE self, other; +{ + struct BLOCK *data, *data2; + + if (self == other) return Qtrue; + if (TYPE(other) != T_DATA) return Qfalse; + if (RDATA(other)->dmark != (RUBY_DATA_FUNC)blk_mark) return Qfalse; + if (CLASS_OF(self) != CLASS_OF(other)) return Qfalse; + Data_Get_Struct(self, struct BLOCK, data); + Data_Get_Struct(other, struct BLOCK, data2); + if (data->tag == data2->tag) return Qtrue; + return Qfalse; +} + +static VALUE +proc_to_s(self, other) + VALUE self, other; +{ + struct BLOCK *data; + char *cname = rb_class2name(CLASS_OF(self)); + VALUE str; + + Data_Get_Struct(self, struct BLOCK, data); + str = rb_str_new(0, strlen(cname)+6+16+1); /* 6:tags 16:addr 1:eos */ + sprintf(RSTRING(str)->ptr, "#<%s:0x%lx>", cname, data->tag); + RSTRING(str)->len = strlen(RSTRING(str)->ptr); + if (OBJ_TAINTED(self)) OBJ_TAINT(str); + + return str; +} + static VALUE block_pass(self, node) VALUE self; @@ -6278,7 +6423,6 @@ block_pass(self, node) ruby_frame->iter = ITER_PRE; PUSH_TAG(PROT_NONE); - _block.tag = prot_tag; state = EXEC_TAG(); if (state == 0) { proc_set_safe_level(block); @@ -6300,25 +6444,33 @@ block_pass(self, node) } ptr = ptr->prev; } + if (!ptr) { + state &= TAG_MASK; + } } } ruby_block = old_block; ruby_safe_level = safe; - if (state) { - switch (state) {/* escape from orphan procedure */ - case TAG_BREAK: + switch (state) {/* escape from orphan procedure */ + case 0: + break; + case TAG_BREAK: + if (orphan) { rb_raise(rb_eLocalJumpError, "break from proc-closure"); - break; - case TAG_RETRY: - rb_raise(rb_eLocalJumpError, "retry from proc-closure"); - break; - case TAG_RETURN: + } + break; + case TAG_RETRY: + rb_raise(rb_eLocalJumpError, "retry from proc-closure"); + break; + case TAG_RETURN: + if (orphan) { rb_raise(rb_eLocalJumpError, "return from proc-closure"); - break; } + default: JUMP_TAG(state); } + return result; } @@ -6445,8 +6597,8 @@ method_call(argc, argv, method) Data_Get_Struct(method, struct METHOD, data); PUSH_ITER(rb_block_given_p()?ITER_PRE:ITER_NOT); PUSH_TAG(PROT_NONE); - if (OBJ_TAINTED(method)) { - if (ruby_safe_level < 4) ruby_safe_level = 4; + if (OBJ_TAINTED(method) && ruby_safe_level < 4) { + ruby_safe_level = 4; } if ((state = EXEC_TAG()) == 0) { result = rb_call0(data->klass,data->recv,data->id,argc,argv,data->body,0); @@ -6611,7 +6763,7 @@ rb_mod_define_method(argc, argv, mod) VALUE mod; { ID id; - VALUE name, body; + VALUE body; if (argc == 1) { id = rb_to_id(argv[0]); @@ -6626,17 +6778,20 @@ rb_mod_define_method(argc, argv, mod) } if (TYPE(body) != T_DATA) { /* type error */ + rb_raise(rb_eTypeError, "wrong argument type (expected Proc)"); } if (RDATA(body)->dmark == (RUBY_DATA_FUNC)bm_mark) { rb_add_method(mod, id, NEW_DMETHOD(method_unbind(body)), NOEX_PUBLIC); } - else if (RDATA(body)->dmark != (RUBY_DATA_FUNC)blk_mark) { + else if (RDATA(body)->dmark == (RUBY_DATA_FUNC)blk_mark) { rb_add_method(mod, id, NEW_BMETHOD(body), NOEX_PUBLIC); } else { /* type error */ + rb_raise(rb_eTypeError, "wrong argument type (expected Proc)"); } + rb_clear_cache_by_id(id); return body; } @@ -6652,6 +6807,8 @@ Init_Proc() rb_define_method(rb_cProc, "call", proc_call, -2); rb_define_method(rb_cProc, "arity", proc_arity, 0); rb_define_method(rb_cProc, "[]", proc_call, -2); + rb_define_method(rb_cProc, "==", proc_eq, 1); + rb_define_method(rb_cProc, "to_s", proc_to_s, 0); rb_define_global_function("proc", rb_f_lambda, 0); rb_define_global_function("lambda", rb_f_lambda, 0); rb_define_global_function("binding", rb_f_binding, 0); @@ -6725,6 +6882,7 @@ struct thread { struct tag *tag; VALUE klass; VALUE wrapper; + NODE *cref; int flags; /* misc. states (vmode/rb_trap_immediate/raised) */ @@ -6758,7 +6916,9 @@ struct thread { VALUE thread; }; -#define THREAD_RAISED 0x200 +#define THREAD_RAISED 0x200 /* temporary flag */ +#define THREAD_TERMINATING 0x400 /* persistent flag */ +#define THREAD_FLAGS_MASK 0x400 /* mask for persistent flags */ #define FOREACH_THREAD_FROM(f,x) x = f; do { x = x->next; #define END_FOREACH_FROM(f,x) } while (x != f) @@ -6766,6 +6926,37 @@ struct thread { #define FOREACH_THREAD(x) FOREACH_THREAD_FROM(curr_thread,x) #define END_FOREACH(x) END_FOREACH_FROM(curr_thread,x) +/* $SAFE accessor */ +void +rb_set_safe_level(level) + int level; +{ + if (level > ruby_safe_level) { + ruby_safe_level = level; + curr_thread->safe = level; + } +} + +static VALUE +safe_getter() +{ + return INT2NUM(ruby_safe_level); +} + +static void +safe_setter(val) + VALUE val; +{ + int level = NUM2INT(val); + + if (level < ruby_safe_level) { + rb_raise(rb_eSecurityError, "tried to downgrade safe level from %d to %d", + ruby_safe_level, level); + } + ruby_safe_level = level; + curr_thread->safe = level; +} + /* Return the current time as a floating-point number */ static double timeofday() @@ -6791,6 +6982,7 @@ thread_mark(th) rb_gc_mark(th->klass); rb_gc_mark(th->wrapper); + rb_gc_mark(th->cref); rb_gc_mark(th->scope); rb_gc_mark(th->dyna_vars); @@ -6868,6 +7060,8 @@ rb_thread_check(data) return (rb_thread_t)RDATA(data)->data; } +static VALUE rb_thread_raise _((int, VALUE*, rb_thread_t)); + static int th_raise_argc; static VALUE th_raise_argv[2]; static char *th_raise_file; @@ -6906,9 +7100,11 @@ rb_thread_save_context(th) th->scope = ruby_scope; th->klass = ruby_class; th->wrapper = ruby_wrapper; + th->cref = ruby_cref; th->dyna_vars = ruby_dyna_vars; th->block = ruby_block; - th->flags = scope_vmode | (rb_trap_immediate<<8); + th->flags &= THREAD_FLAGS_MASK; + th->flags |= (rb_trap_immediate<<8) | scope_vmode; th->iter = ruby_iter; th->tag = prot_tag; th->tracing = tracing; @@ -6995,6 +7191,7 @@ rb_thread_restore_context(th, exit) ruby_scope = th->scope; ruby_class = th->klass; ruby_wrapper = th->wrapper; + ruby_cref = th->cref; ruby_dyna_vars = th->dyna_vars; ruby_block = th->block; scope_vmode = th->flags&SCOPE_MASK; @@ -7055,13 +7252,8 @@ rb_thread_fd_close(fd) FOREACH_THREAD(th) { if ((th->wait_for & WAIT_FD) && fd == th->fd) { - th_raise_argc = 1; - th_raise_argv[0] = rb_exc_new2(rb_eIOError, "stream closed"); - th_raise_file = ruby_sourcefile; - th_raise_line = ruby_sourceline; - curr_thread = th; - rb_thread_ready(th); - rb_thread_restore_context(curr_thread, RESTORE_RAISE); + VALUE exc = rb_exc_new2(rb_eIOError, "stream closed"); + rb_thread_raise(1, &exc, th); } } END_FOREACH(th); @@ -7339,8 +7531,11 @@ rb_thread_schedule() curr_thread = next; if (next->status == THREAD_TO_KILL) { - /* execute ensure-clause if any */ - rb_thread_restore_context(next, RESTORE_FATAL); + if (!(next->flags & THREAD_TERMINATING)) { + next->flags |= THREAD_TERMINATING; + /* terminate; execute ensure-clause if any */ + rb_thread_restore_context(next, RESTORE_FATAL); + } } rb_thread_restore_context(next, RESTORE_NORMAL); } @@ -7349,6 +7544,7 @@ void rb_thread_wait_fd(fd) int fd; { + if (rb_thread_critical) return; if (curr_thread == curr_thread->next) return; if (curr_thread->status == THREAD_TO_KILL) return; @@ -7362,9 +7558,9 @@ int rb_thread_fd_writable(fd) int fd; { + if (rb_thread_critical) return Qtrue; if (curr_thread == curr_thread->next) return Qtrue; if (curr_thread->status == THREAD_TO_KILL) return Qtrue; - curr_thread->status = THREAD_STOPPED; FD_ZERO(&curr_thread->readfds); FD_ZERO(&curr_thread->writefds); @@ -7382,7 +7578,8 @@ rb_thread_wait_for(time) { double date; - if (curr_thread == curr_thread->next || + if (rb_thread_critical || + curr_thread == curr_thread->next || curr_thread->status == THREAD_TO_KILL) { int n; #ifndef linux @@ -7394,7 +7591,14 @@ rb_thread_wait_for(time) n = select(0, 0, 0, 0, &time); TRAP_END; if (n == 0) return; - + if (n < 0) { + switch (errno) { + case EINTR: + return; + default: + rb_sys_fail("sleep"); + } + } #ifndef linux d = limit - timeofday(); @@ -7447,7 +7651,8 @@ rb_thread_select(max, read, write, except, timeout) (double)timeout->tv_sec+(double)timeout->tv_usec*1e-6; } - if (curr_thread == curr_thread->next || + if (rb_thread_critical || + curr_thread == curr_thread->next || curr_thread->status == THREAD_TO_KILL) { #ifndef linux struct timeval tv, *tvp = timeout; @@ -7513,6 +7718,7 @@ rb_thread_join(thread) rb_thread_t th = rb_thread_check(thread); enum thread_status last_status = THREAD_RUNNABLE; + if (rb_thread_critical) rb_thread_deadlock(); if (!rb_thread_dead(th)) { if (th == curr_thread) rb_raise(rb_eThreadError, "thread tried to join itself"); @@ -7612,8 +7818,8 @@ rb_thread_kill(thread) rb_thread_ready(th); th->gid = 0; th->status = THREAD_TO_KILL; - rb_thread_schedule(); - return Qnil; /* not reached */ + if (!rb_thread_critical) rb_thread_schedule(); + return thread; } static VALUE @@ -7780,6 +7986,7 @@ rb_thread_abort_exc_set(thread, val) \ th->status = THREAD_RUNNABLE;\ th->result = 0;\ + th->flags = 0;\ \ th->stk_ptr = 0;\ th->stk_len = 0;\ @@ -7795,6 +8002,7 @@ rb_thread_abort_exc_set(thread, val) th->scope = 0;\ th->klass = 0;\ th->wrapper = 0;\ + th->cref = ruby_cref;\ th->dyna_vars = ruby_dyna_vars;\ th->block = 0;\ th->iter = 0;\ @@ -7846,8 +8054,6 @@ catch_timer(sig) int rb_thread_tick = THREAD_TICK; #endif -static VALUE rb_thread_raise _((int, VALUE*, rb_thread_t)); - #define SCOPE_SHARED FL_USER1 #if defined(HAVE_SETITIMER) @@ -7886,6 +8092,7 @@ rb_thread_start_0(fn, arg, th_arg) { volatile rb_thread_t th = th_arg; volatile VALUE thread = th->thread; + struct BLOCK* saved_block = 0; enum thread_status status; int state; @@ -7903,7 +8110,11 @@ rb_thread_start_0(fn, arg, th_arg) #endif if (ruby_block) { /* should nail down higher scopes */ - blk_copy_prev(ruby_block); + struct BLOCK dummy; + + dummy.prev = ruby_block; + blk_copy_prev(&dummy); + saved_block = ruby_block = dummy.prev; } scope_dup(ruby_scope); FL_SET(ruby_scope, SCOPE_SHARED); @@ -7930,6 +8141,16 @@ rb_thread_start_0(fn, arg, th_arg) } POP_TAG(); status = th->status; + + while (saved_block) { + struct BLOCK *tmp = saved_block; + + if (tmp->frame.argc > 0) + free(tmp->frame.argv); + saved_block = tmp->prev; + free(tmp); + } + if (th == main_thread) ruby_stop(state); rb_thread_remove(th); if (state && status != THREAD_TO_KILL && !NIL_P(ruby_errinfo)) { @@ -8018,8 +8239,6 @@ static VALUE rb_thread_start(klass, args) VALUE klass, args; { - rb_thread_t th; - if (!rb_block_given_p()) { rb_raise(rb_eThreadError, "must be called with a block"); } @@ -8366,6 +8585,14 @@ rb_callcc(self) for (tag=prot_tag; tag; tag=tag->prev) { scope_dup(tag->scope); } + if (ruby_block) { + struct BLOCK *block = ruby_block; + + while (block) { + block->tag->flags |= BLOCK_DYNAMIC; + block = block->prev; + } + } th->thread = curr_thread->thread; for (vars = th->dyna_vars; vars; vars = vars->next) { diff --git a/ext/.cvsignore b/ext/.cvsignore new file mode 100644 index 0000000000..d8b8a61d92 --- /dev/null +++ b/ext/.cvsignore @@ -0,0 +1 @@ +extmk.rb diff --git a/ext/Win32API/Win32API.c b/ext/Win32API/Win32API.c index dcfdd7caab..0ee28f05ac 100644 --- a/ext/Win32API/Win32API.c +++ b/ext/Win32API/Win32API.c @@ -305,9 +305,3 @@ Init_Win32API() rb_define_method(cWin32API, "call", Win32API_Call, -1); rb_define_alias(cWin32API, "Call", "call"); } - -void -Init_win32api() -{ - Init_Win32API(); -} diff --git a/ext/Win32API/extconf.rb b/ext/Win32API/extconf.rb index f8d78e1465..5e42f62558 100644 --- a/ext/Win32API/extconf.rb +++ b/ext/Win32API/extconf.rb @@ -1,6 +1,6 @@ case RUBY_PLATFORM when /cygwin/,/mingw/ - $CFLAGS = "-fno-defer-pop" + $CFLAGS = "-fno-defer-pop -fno-omit-frame-pointer" create_makefile("Win32API") when /win32/ create_makefile("Win32API") diff --git a/ext/curses/.cvsignore b/ext/curses/.cvsignore new file mode 100644 index 0000000000..f3c7a7c5da --- /dev/null +++ b/ext/curses/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/ext/curses/curses.c b/ext/curses/curses.c index db620654bd..4a8c46f483 100644 --- a/ext/curses/curses.c +++ b/ext/curses/curses.c @@ -16,16 +16,16 @@ # include # else # include -# if (defined(__bsdi__) || defined(__NetBSD__)) && !defined(_maxx) +# if (defined(__bsdi__) || defined(__NetBSD__) || defined(__APPLE__) ) && !defined(_maxx) # define _maxx maxx # endif -# if (defined(__bsdi__) || defined(__NetBSD__)) && !defined(_maxy) +# if (defined(__bsdi__) || defined(__NetBSD__) || defined(__APPLE__)) && !defined(_maxy) # define _maxy maxy # endif -# if (defined(__bsdi__) || defined(__NetBSD__)) && !defined(_begx) +# if (defined(__bsdi__) || defined(__NetBSD__) || defined(__APPLE__)) && !defined(_begx) # define _begx begx # endif -# if (defined(__bsdi__) || defined(__NetBSD__)) && !defined(_begy) +# if (defined(__bsdi__) || defined(__NetBSD__) || defined(__APPLE__)) && !defined(_begy) # define _begy begy # endif # endif diff --git a/ext/curses/extconf.rb b/ext/curses/extconf.rb index 5c6881164a..c16ab00f28 100644 --- a/ext/curses/extconf.rb +++ b/ext/curses/extconf.rb @@ -1,5 +1,9 @@ require 'mkmf' +dir_config('curses') +dir_config('ncurses') +dir_config('termcap') + make=false have_library("mytinfo", "tgetent") if /bow/ =~ RUBY_PLATFORM if have_header("ncurses.h") and have_library("ncurses", "initscr") diff --git a/ext/dbm/.cvsignore b/ext/dbm/.cvsignore new file mode 100644 index 0000000000..f3c7a7c5da --- /dev/null +++ b/ext/dbm/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/ext/etc/.cvsignore b/ext/etc/.cvsignore new file mode 100644 index 0000000000..f3c7a7c5da --- /dev/null +++ b/ext/etc/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/ext/extmk.rb.in b/ext/extmk.rb.in index 92d11d0f6e..a369933a14 100644 --- a/ext/extmk.rb.in +++ b/ext/extmk.rb.in @@ -370,13 +370,15 @@ def create_makefile(target) if $configure_args['--enable-shared'] or "@LIBRUBY@" != "@LIBRUBY_A@" $libs = "@LIBRUBYARG@ " + $libs - $LIBPATH |= [$topdir] + $LIBPATH.unshift $topdir end defflag = '' if RUBY_PLATFORM =~ /cygwin|mingw/ and not $static - open(target + '.def', 'wb') do |f| - f.print "EXPORTS\n", "Init_", target, "\n" + if not File.exist? target + '.def' + open(target + '.def', 'wb') do |f| + f.print "EXPORTS\n", "Init_", target, "\n" + end end defflag = "--def=" + target + ".def" end @@ -492,19 +494,43 @@ EOS mfile.puts " .c.@OBJEXT@: $(CC) $(CFLAGS) $(CPPFLAGS) -c $< + +.cc.@OBJEXT@: + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< +.cpp.@OBJEXT@: + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< +.cxx.@OBJEXT@: + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< +.C.@OBJEXT@: + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< " elsif /nmake/i =~ $make mfile.print " {$(srcdir)}.c{}.@OBJEXT@: $(CC) -I. -I$(]+>*/).collect!{|subseq| + case (subseq) + when /^<<[^<>]+>>$/ + TkVirtualEvent.getobj(subseq[1..-2]) + when /^<[^<>]+>$/ + subseq[1..-2] + else + subseq.split('') + end + }.flatten + (l.size == 1) ? l[0] : l } end end @@ -651,12 +661,76 @@ module TkCore end end +module TkPackage + include TkCore + extend TkPackage + + def forget(package) + tk_call('package', 'forget', package) + nil + end + + def names + tk_split_simplelist(tk_call('package', 'names')) + end + + def provide(package, version=nil) + if version + tk_call('package', 'provide', package, version) + nil + else + tk_call('package', 'provide', package) + end + end + + def present(package, version=None) + tk_call('package', 'present', package, version) + end + + def present_exact(package, version) + tk_call('package', 'present', '-exact', package, version) + end + + def require(package, version=None) + tk_call('package', 'require', package, version) + end + + def require_exact(package, version) + tk_call('package', 'require', '-exact', package, version) + end + + def versions(package) + tk_split_simplelist(tk_call('package', 'versions', package)) + end + + def vcompare(version1, version2) + Integer(tk_call('package', 'vcompare', version1, version2)) + end + + def vsatisfies(version1, version2) + bool(tk_call('package', 'vsatisfies', version1, version2)) + end +end + module Tk include TkCore extend Tk TCL_VERSION = INTERP._invoke("info", "tclversion") TK_VERSION = INTERP._invoke("set", "tk_version") + + TCL_PATCHLEVEL = INTERP._invoke("info", "patchlevel") + TK_PATCHLEVEL = INTERP._invoke("set", "tk_patchLevel") + + TCL_LIBRARY = INTERP._invoke("set", "tcl_library") + TK_LIBRARY = INTERP._invoke("set", "tk_library") + LIBRARY = INTERP._invoke("info", "library") + + TCL_PACKAGE_PATH = INTERP._invoke("set", "tcl_pkgPath") + AUTO_PATH = tk_split_simplelist(INTERP._invoke("set", "auto_path")) + + PLATFORM = Hash[*tk_split_simplelist(INTERP._eval('array get tcl_platform'))] + JAPANIZED_TK = (INTERP._invoke("info", "commands", "kanji") != "") def root @@ -680,6 +754,10 @@ module Tk tk_tcl2ruby(tk_call('focus', '-lastfor', win)) end + def Tk.strictMotif(bool=None) + bool(tk_call('set', 'tk_strictMotif', bool)) + end + def Tk.show_kinsoku(mode='both') begin if /^8\.*/ === TK_VERSION && JAPANIZED_TK @@ -710,11 +788,11 @@ module Tk end end - def toUTF8(str,encoding) + def Tk.toUTF8(str,encoding) INTERP._toUTF8(str,encoding) end - def fromUTF8(str,encoding) + def Tk.fromUTF8(str,encoding) INTERP._fromUTF8(str,encoding) end @@ -978,6 +1056,12 @@ class TkBindTag BTagID_TBL[id]? BTagID_TBL[id]: id end + ALL = self.new + ALL.instance_eval { + @id = 'all' + BTagID_TBL[@id] = self + } + def initialize(*args) @id = Tk_BINDTAG_ID[0] Tk_BINDTAG_ID[0] = Tk_BINDTAG_ID[0].succ @@ -995,20 +1079,11 @@ class TkBindTag end class TkBindTagAll") + PreDefVirtEvent.new(event) + else + fail ArgumentError, "undefined virtual event '<#{event}>'" + end + end end def TkVirtualEvent.info @@ -22,8 +37,8 @@ class TkVirtualEvent", TkVirturlEventID[0]) - TkVirturlEventID[0] += 1 + @path = @id = format("", TkVirtualEventID[0]) + TkVirtualEventID[0] += 1 add(*sequences) end @@ -31,7 +46,7 @@ class TkVirtualEvent", *(sequences.collect{|seq| "<#{tk_event_sequence(seq)}>"}) ) - TkVirturlEventTBL[@id] = self + TkVirtualEventTBL[@id] = self end self end @@ -39,11 +54,11 @@ class TkVirtualEvent") - TkVirturlEventTBL[@id] = nil + TkVirtualEventTBL[@id] = nil else tk_call('event', 'delete', "<#{@id}>", *(sequences.collect{|seq| "<#{tk_event_sequence(seq)}>"}) ) - TkVirturlEventTBL[@id] = nil if info == [] + TkVirtualEventTBL[@id] = nil if info == [] end self end diff --git a/file.c b/file.c index 98098f9047..af18b88fba 100644 --- a/file.c +++ b/file.c @@ -67,7 +67,7 @@ char *strrchr _((const char*,const char)); #include #ifndef HAVE_LSTAT -#define lstat stat +#define lstat rb_sys_stat #endif VALUE rb_cFile; @@ -113,7 +113,8 @@ rb_file_path(obj) #endif static VALUE -stat_new(st) +stat_new_0(klass, st) + VALUE klass; struct stat *st; { struct stat *nst; @@ -121,7 +122,14 @@ stat_new(st) nst = ALLOC(struct stat); *nst = *st; - return Data_Wrap_Struct(rb_cStat, NULL, free, nst); + return Data_Wrap_Struct(klass, NULL, free, nst); +} + +static VALUE +stat_new(st) + struct stat *st; +{ + return stat_new_0(rb_cStat, st); } static struct stat* @@ -152,42 +160,42 @@ static VALUE rb_stat_dev(self) VALUE self; { - return INT2FIX((int)get_stat(self)->st_dev); + return INT2NUM(get_stat(self)->st_dev); } static VALUE rb_stat_ino(self) VALUE self; { - return INT2FIX((int)get_stat(self)->st_ino); + return UINT2NUM(get_stat(self)->st_ino); } static VALUE rb_stat_mode(self) VALUE self; { - return INT2FIX((int)get_stat(self)->st_mode); + return UINT2NUM(get_stat(self)->st_mode); } static VALUE rb_stat_nlink(self) VALUE self; { - return INT2FIX((int)get_stat(self)->st_nlink); + return UINT2NUM(get_stat(self)->st_nlink); } static VALUE rb_stat_uid(self) VALUE self; { - return INT2FIX((int)get_stat(self)->st_uid); + return UINT2NUM(get_stat(self)->st_uid); } static VALUE rb_stat_gid(self) VALUE self; { - return INT2FIX((int)get_stat(self)->st_gid); + return UINT2NUM(get_stat(self)->st_gid); } static VALUE @@ -195,7 +203,7 @@ rb_stat_rdev(self) VALUE self; { #ifdef HAVE_ST_RDEV - return INT2FIX((int)get_stat(self)->st_rdev); + return INT2NUM(get_stat(self)->st_rdev); #else return INT2FIX(0); #endif @@ -205,7 +213,7 @@ static VALUE rb_stat_size(self) VALUE self; { - return INT2FIX((int)get_stat(self)->st_size); + return INT2NUM(get_stat(self)->st_size); } static VALUE @@ -213,7 +221,7 @@ rb_stat_blksize(self) VALUE self; { #ifdef HAVE_ST_BLKSIZE - return INT2FIX((int)get_stat(self)->st_blksize); + return UINT2NUM(get_stat(self)->st_blksize); #else return INT2FIX(0); #endif @@ -224,7 +232,7 @@ rb_stat_blocks(self) VALUE self; { #ifdef HAVE_ST_BLOCKS - return INT2FIX((int)get_stat(self)->st_blocks); + return UINT2NUM(get_stat(self)->st_blocks); #else return INT2FIX(0); #endif @@ -314,17 +322,17 @@ rb_stat(file, st) #if defined DJGPP if (RSTRING(file)->len == 0) return -1; #endif - return stat(RSTRING(file)->ptr, st); + return rb_sys_stat(RSTRING(file)->ptr, st); } static VALUE -rb_file_s_stat(obj, fname) - VALUE obj, fname; +rb_file_s_stat(klass, fname) + VALUE klass, fname; { struct stat st; Check_SafeStr(fname); - if (stat(RSTRING(fname)->ptr, &st) == -1) { + if (rb_sys_stat(RSTRING(fname)->ptr, &st) == -1) { rb_sys_fail(RSTRING(fname)->ptr); } return stat_new(&st); @@ -345,8 +353,8 @@ rb_io_stat(obj) } static VALUE -rb_file_s_lstat(obj, fname) - VALUE obj, fname; +rb_file_s_lstat(klass, fname) + VALUE klass, fname; { #ifdef HAVE_LSTAT struct stat st; @@ -357,7 +365,7 @@ rb_file_s_lstat(obj, fname) } return stat_new(&st); #else - return rb_file_s_stat(obj, fname); + return rb_file_s_stat(klass, fname); #endif } @@ -420,7 +428,7 @@ eaccess(path, mode) struct stat st; static int euid = -1; - if (stat(path, &st) < 0) return (-1); + if (rb_sys_stat(path, &st) < 0) return (-1); if (euid == -1) euid = geteuid (); @@ -722,7 +730,7 @@ check3rdbyte(file, mode) { struct stat st; - if (stat(file, &st) < 0) return Qfalse; + if (rb_sys_stat(file, &st) < 0) return Qfalse; if (st.st_mode & mode) return Qtrue; return Qfalse; } @@ -757,15 +765,16 @@ test_sticky(obj, fname) VALUE obj, fname; { #ifdef S_ISVTX - return check3rdbyte(STR2CSTR(fname), S_ISVTX); + Check_SafeStr(fname); + return check3rdbyte(RSTRING(fname)->ptr, S_ISVTX); #else return Qnil; #endif } static VALUE -rb_file_s_size(obj, fname) - VALUE obj, fname; +rb_file_s_size(klass, fname) + VALUE klass, fname; { struct stat st; @@ -815,8 +824,8 @@ rb_file_ftype(st) } static VALUE -rb_file_s_ftype(obj, fname) - VALUE obj, fname; +rb_file_s_ftype(klass, fname) + VALUE klass, fname; { struct stat st; @@ -829,8 +838,8 @@ rb_file_s_ftype(obj, fname) } static VALUE -rb_file_s_atime(obj, fname) - VALUE obj, fname; +rb_file_s_atime(klass, fname) + VALUE klass, fname; { struct stat st; @@ -854,8 +863,8 @@ rb_file_atime(obj) } static VALUE -rb_file_s_mtime(obj, fname) - VALUE obj, fname; +rb_file_s_mtime(klass, fname) + VALUE klass, fname; { struct stat st; @@ -879,8 +888,8 @@ rb_file_mtime(obj) } static VALUE -rb_file_s_ctime(obj, fname) - VALUE obj, fname; +rb_file_s_ctime(klass, fname) + VALUE klass, fname; { struct stat st; @@ -1097,8 +1106,8 @@ rb_file_s_utime(argc, argv) #endif static VALUE -rb_file_s_link(obj, from, to) - VALUE obj, from, to; +rb_file_s_link(klass, from, to) + VALUE klass, from, to; { Check_SafeStr(from); Check_SafeStr(to); @@ -1109,8 +1118,8 @@ rb_file_s_link(obj, from, to) } static VALUE -rb_file_s_symlink(obj, from, to) - VALUE obj, from, to; +rb_file_s_symlink(klass, from, to) + VALUE klass, from, to; { #ifdef HAVE_SYMLINK Check_SafeStr(from); @@ -1126,8 +1135,8 @@ rb_file_s_symlink(obj, from, to) } static VALUE -rb_file_s_readlink(obj, path) - VALUE obj, path; +rb_file_s_readlink(klass, path) + VALUE klass, path; { #ifdef HAVE_READLINK char buf[MAXPATHLEN]; @@ -1154,8 +1163,8 @@ unlink_internal(path) } static VALUE -rb_file_s_unlink(obj, args) - VALUE obj, args; +rb_file_s_unlink(klass, args) + VALUE klass, args; { int n; @@ -1164,14 +1173,19 @@ rb_file_s_unlink(obj, args) } static VALUE -rb_file_s_rename(obj, from, to) - VALUE obj, from, to; +rb_file_s_rename(klass, from, to) + VALUE klass, from, to; { Check_SafeStr(from); Check_SafeStr(to); - if (rename(RSTRING(from)->ptr, RSTRING(to)->ptr) < 0) + if (rename(RSTRING(from)->ptr, RSTRING(to)->ptr) < 0) { +#if defined __CYGWIN__ + extern unsigned long __attribute__((stdcall)) GetLastError(); + errno = GetLastError(); /* This is a Cygwin bug */ +#endif rb_sys_fail(RSTRING(from)->ptr); + } return INT2FIX(0); } @@ -1253,7 +1267,7 @@ rb_file_s_expand_path(argc, argv) } #if defined DOSISH /* skip drive letter */ - else if (isalpha(s[0]) && s[1] == ':' && isdirsep(s[2])) { + else if (ISALPHA(s[0]) && s[1] == ':' && isdirsep(s[2])) { while (*s && !isdirsep(*s)) { *p++ = *s++; } @@ -1388,8 +1402,8 @@ rb_file_s_basename(argc, argv) } static VALUE -rb_file_s_dirname(obj, fname) - VALUE obj, fname; +rb_file_s_dirname(klass, fname) + VALUE klass, fname; { char *name, *p; VALUE dirname; @@ -1407,8 +1421,8 @@ rb_file_s_dirname(obj, fname) } static VALUE -rb_file_s_split(obj, path) - VALUE obj, path; +rb_file_s_split(klass, path) + VALUE klass, path; { return rb_assoc_new(rb_file_s_dirname(Qnil, path), rb_file_s_basename(1,&path)); } @@ -1416,15 +1430,15 @@ rb_file_s_split(obj, path) static VALUE separator; static VALUE -rb_file_s_join(obj, args) - VALUE obj, args; +rb_file_s_join(klass, args) + VALUE klass, args; { return rb_ary_join(args, separator); } static VALUE -rb_file_s_truncate(obj, path, len) - VALUE obj, path, len; +rb_file_s_truncate(klass, path, len) + VALUE klass, path, len; { rb_secure(2); Check_SafeStr(path); @@ -1509,11 +1523,14 @@ rb_thread_flock(fd, op, fptr) op |= LOCK_NB; while (flock(fd, op) < 0) { switch (errno) { - case EINTR: /* can be happen? */ + case EAGAIN: + case EACCES: +#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN case EWOULDBLOCK: +#endif rb_thread_polling(); /* busy wait */ rb_io_check_closed(fptr); - break; + continue; default: return -1; } @@ -1542,11 +1559,14 @@ rb_file_flock(obj, operation) ret = flock(fileno(fptr->f), NUM2INT(operation)); TRAP_END; if (ret < 0) { -#ifdef EWOULDBLOCK - if (errno == EWOULDBLOCK) { - return Qfalse; - } + switch (errno) { + case EAGAIN: + case EACCES: +#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: #endif + return Qfalse; + } rb_sys_fail(fptr->path); } #endif @@ -1715,6 +1735,30 @@ rb_f_test(argc, argv) return Qnil; /* not reached */ } +static VALUE +rb_stat_s_new(klass, fname) + VALUE klass, fname; +{ + VALUE s; + struct stat st; + + Check_SafeStr(fname); + if (rb_sys_stat(RSTRING(fname)->ptr, &st) == -1) { + rb_sys_fail(RSTRING(fname)->ptr); + } + s = stat_new_0(klass, &st); + rb_obj_call_init(s, 1, &fname); + return s; +} + +static VALUE +rb_stat_init(klass, fname) + VALUE klass, fname; +{ + /* do nothing */ + return Qnil; +} + static VALUE rb_stat_ftype(obj) VALUE obj; @@ -2029,6 +2073,7 @@ path_check_1(path) } for (;;) { if (stat(path, &st) == 0 && (st.st_mode & 002)) { + if (p) *p = '/'; return 0; } s = strrchr(path, '/'); @@ -2056,7 +2101,10 @@ rb_path_check(path) if (pend) *pend = '\0'; safe = path_check_1(p); - if (!safe) return 0; + if (!safe) { + if (pend) *pend = sep; + return 0; + } if (!pend) break; *pend = sep; p = pend + 1; @@ -2159,6 +2207,7 @@ define_filetest_function(name, func, argc) rb_define_singleton_method(rb_cFile, name, func, argc); } +void Init_File() { rb_mFileTest = rb_define_module("FileTest"); @@ -2254,6 +2303,8 @@ Init_File() rb_define_global_function("test", rb_f_test, -1); rb_cStat = rb_define_class_under(rb_cFile, "Stat", rb_cObject); + rb_define_singleton_method(rb_cStat, "new", rb_stat_s_new, 1); + rb_define_method(rb_cStat, "initialize", rb_stat_init, 1); rb_include_module(rb_cStat, rb_mComparable); diff --git a/gc.c b/gc.c index a3578aef2f..a0e4ce6404 100644 --- a/gc.c +++ b/gc.c @@ -31,10 +31,23 @@ void rb_io_fptr_finalize _((struct OpenFile*)); #endif #endif -#ifdef C_ALLOCA -#ifndef alloca +/* Make alloca work the best possible way. */ +#ifdef __GNUC__ +# ifndef atarist +# ifndef alloca +# define alloca __builtin_alloca +# endif +# endif /* atarist */ +#else +# if defined(HAVE_ALLOCA_H) +# include +# elif !defined(alloca) void *alloca(); -#endif +# endif +#endif /* __GNUC__ */ + +#ifdef _AIX +#pragma alloca #endif static void run_final(); @@ -53,10 +66,17 @@ static void mem_error(mesg) char *mesg; { + static int recurse = 0; + if (rb_safe_level() >= 4) { rb_raise(rb_eNoMemError, mesg); } - rb_fatal(mesg); + if (recurse == 0) { + recurse++; + rb_fatal(mesg); + } + fprintf(stderr, "[FATAL] failed to allocate memory\n"); + exit(1); } void * @@ -308,10 +328,7 @@ rb_data_object_alloc(klass, datap, dmark, dfree) extern st_table *rb_class_tbl; VALUE *rb_gc_stack_start = 0; -#if defined(__GNUC__) && __GNUC__ >= 2 -__inline__ -#endif -static int +static inline int is_pointer_to_heap(ptr) void *ptr; { @@ -606,6 +623,7 @@ rb_gc_mark(ptr) case T_REGEXP: case T_FLOAT: case T_BIGNUM: + case T_BLKTAG: break; case T_MATCH: @@ -712,7 +730,7 @@ gc_sweep() during_gc = 0; /* clear finalization list */ - if (need_call_final && final_list) { + if (final_list) { RVALUE *tmp; if (rb_prohibit_interrupt || ruby_in_compile) { @@ -822,6 +840,7 @@ obj_free(obj) case T_FLOAT: case T_VARMAP: + case T_BLKTAG: break; case T_BIGNUM: @@ -924,7 +943,7 @@ rb_gc() alloca(0); # define STACK_END (&stack_end) #else -# if defined(__GNUC__) && !defined(__alpha__) && !defined(__APPLE__) +# if defined(__GNUC__) && defined(__i386__) VALUE *stack_end = __builtin_frame_address(0); # else VALUE *stack_end = alloca(1); @@ -1004,7 +1023,7 @@ Init_stack(addr) #if defined(__human68k__) extern void *_SEND; rb_gc_stack_start = _SEND; -#elif defined(__GNUC__) && !defined(__alpha__) && !defined(__APPLE__) +#elif defined(__GNUC__) && defined(__i386__) rb_gc_stack_start = __builtin_frame_address(2); #else VALUE start; @@ -1044,6 +1063,7 @@ os_live_obj() case T_CLASS: if (FL_TEST(p, FL_SINGLETON)) continue; default: + if (!p->as.basic.klass) continue; rb_yield((VALUE)p); n++; } @@ -1076,6 +1096,7 @@ os_obj_of(of) case T_CLASS: if (FL_TEST(p, FL_SINGLETON)) continue; default: + if (!p->as.basic.klass) continue; if (rb_obj_is_kind_of((VALUE)p, of)) { rb_yield((VALUE)p); n++; @@ -1207,8 +1228,7 @@ run_final(obj) args[0] = RARRAY(finalizers)->ptr[i]; rb_protect(run_single_final, (VALUE)args, &status); } - if (finalizer_table && st_lookup(finalizer_table, obj, &table)) { - st_delete(finalizer_table, &obj, 0); + if (finalizer_table && st_delete(finalizer_table, &obj, &table)) { for (i=0; ilen; i++) { args[0] = RARRAY(table)->ptr[i]; rb_protect(run_single_final, (VALUE)args, &status); @@ -1223,14 +1243,25 @@ rb_gc_call_finalizer_at_exit() int i; /* run finalizers */ - for (i = 0; i < heaps_used; i++) { - p = heaps[i]; pend = p + HEAP_SLOTS; - while (p < pend) { - if (FL_TEST(p, FL_FINALIZE)) { - p->as.free.flag = 0; - run_final((VALUE)p); + if (need_call_final) { + if (deferred_final_list) { + p = deferred_final_list; + while (p) { + RVALUE *tmp = p; + p = p->as.free.next; + run_final((VALUE)tmp); + } + } + for (i = 0; i < heaps_used; i++) { + p = heaps[i]; pend = p + HEAP_SLOTS; + while (p < pend) { + if (FL_TEST(p, FL_FINALIZE)) { + FL_UNSET(p, FL_FINALIZE); + p->as.basic.klass = 0; + run_final((VALUE)p); + } + p++; } - p++; } } /* run data object's finaliers */ @@ -1255,21 +1286,24 @@ static VALUE id2ref(obj, id) VALUE obj, id; { - unsigned long ptr; + unsigned long ptr, p0; rb_secure(4); - ptr = NUM2UINT(id); - if (FIXNUM_P(ptr)) return (VALUE)ptr; + p0 = ptr = NUM2UINT(id); if (ptr == Qtrue) return Qtrue; if (ptr == Qfalse) return Qfalse; if (ptr == Qnil) return Qnil; + if (FIXNUM_P(ptr)) return (VALUE)ptr; + if (SYMBOL_P(ptr) && rb_id2name(SYM2ID((VALUE)ptr)) != 0) { + return (VALUE)ptr; + } ptr = id ^ FIXNUM_FLAG; /* unset FIXNUM_FLAG */ if (!is_pointer_to_heap(ptr)) { - rb_raise(rb_eRangeError, "0x%x is not id value", ptr); + rb_raise(rb_eRangeError, "0x%x is not id value", p0); } if (BUILTIN_TYPE(ptr) == 0) { - rb_raise(rb_eRangeError, "0x%x is recycled object", ptr); + rb_raise(rb_eRangeError, "0x%x is recycled object", p0); } return (VALUE)ptr; } @@ -1303,37 +1337,3 @@ Init_GC() rb_gc_unregister_address(&rb_mObSpace); finalizers = rb_ary_new(); } - -#undef xmalloc -#undef xcalloc -#undef xrealloc -#undef xfree - -void* -xmalloc(size) - long size; -{ - return ruby_xmalloc(size); -} - -void* -xcalloc(n,size) - long n,size; -{ - return ruby_xcalloc(n, size); -} - -void* -xrealloc(ptr,size) - void *ptr; - long size; -{ - return ruby_xrealloc(ptr, size); -} - -void -xfree(ptr) - void *ptr; -{ - ruby_xfree(ptr); -} diff --git a/hash.c b/hash.c index 2a5803c96e..eb6e73908c 100644 --- a/hash.c +++ b/hash.c @@ -79,16 +79,16 @@ static int rb_any_hash(a) VALUE a; { - unsigned int hval; + VALUE hval; switch (TYPE(a)) { case T_FIXNUM: case T_SYMBOL: - hval = a; + return (int)a; break; case T_STRING: - hval = rb_str_hash(a); + return rb_str_hash(a); break; default: @@ -98,9 +98,8 @@ rb_any_hash(a) hval = rb_funcall(hval, '%', 1, INT2FIX(65439)); } ENABLE_INTS; - hval = FIX2LONG(hval); + return (int)FIX2LONG(hval); } - return hval; } static struct st_hash_type objhash = { diff --git a/intern.h b/intern.h index 7d8b0de130..147fb605df 100644 --- a/intern.h +++ b/intern.h @@ -41,6 +41,7 @@ VALUE rb_ary_sort _((VALUE)); VALUE rb_ary_sort_bang _((VALUE)); VALUE rb_ary_delete _((VALUE, VALUE)); VALUE rb_ary_delete_at _((VALUE, long)); +VALUE rb_ary_clear _((VALUE)); VALUE rb_ary_plus _((VALUE, VALUE)); VALUE rb_ary_concat _((VALUE, VALUE)); VALUE rb_ary_assoc _((VALUE, VALUE)); @@ -77,6 +78,8 @@ VALUE rb_big_lshift _((VALUE, VALUE)); VALUE rb_big_rand _((VALUE, double)); /* class.c */ VALUE rb_class_new _((VALUE)); +VALUE rb_mod_clone _((VALUE)); +VALUE rb_mod_dup _((VALUE)); VALUE rb_singleton_class_new _((VALUE)); VALUE rb_singleton_class_clone _((VALUE)); void rb_singleton_class_attached _((VALUE,VALUE)); @@ -107,7 +110,8 @@ VALUE rb_exc_new3 _((VALUE, VALUE)); void rb_loaderror __((const char*, ...)) NORETURN; void rb_compile_error __((const char*, ...)); void rb_compile_error_append __((const char*, ...)); -void rb_error_frozen _((char*)); +void rb_load_fail _((char*)) NORETURN; +void rb_error_frozen _((char*)) NORETURN; /* eval.c */ void rb_exc_raise _((VALUE)) NORETURN; void rb_exc_fatal _((VALUE)) NORETURN; diff --git a/io.c b/io.c index a422cc0869..79118b073a 100644 --- a/io.c +++ b/io.c @@ -27,6 +27,10 @@ # define NO_LONG_FNAME #endif +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(sun) +# define USE_SETVBUF +#endif + #include #if !defined(DJGPP) && !defined(NT) && !defined(__human68k__) #include @@ -1362,6 +1366,10 @@ rb_fopen(fname, mode) rb_sys_fail(fname); } } +#ifdef USE_SETVBUF + if (setvbuf(file, NULL, _IOFBF, 0) != 0) + rb_warn("setvbuf() can't be honered for %s", fname); +#endif #ifdef __human68k__ fmode(file, _IOTEXT); #endif @@ -1385,6 +1393,11 @@ rb_fdopen(fd, mode) rb_sys_fail(0); } } +#ifdef USE_SETVBUF + if (setvbuf(file, NULL, _IOFBF, 0) != 0) + rb_warn("setvbuf() can't be honered (fd=%d)", fd); +#endif + return file; } @@ -1902,12 +1915,18 @@ rb_io_reopen(argc, argv, file) fclose(fptr->f2); fptr->f2 = 0; } + return file; } if (freopen(RSTRING(fname)->ptr, mode, fptr->f) == 0) { rb_sys_fail(fptr->path); } +#ifdef USE_SETVBUF + if (setvbuf(fptr->f, NULL, _IOFBF, 0) != 0) + rb_warn("setvbuf() can't be honered for %s", RSTRING(fname)->ptr); +#endif + if (fptr->f2) { if (freopen(RSTRING(fname)->ptr, "w", fptr->f2) == 0) { rb_sys_fail(fptr->path); @@ -2156,7 +2175,9 @@ rb_f_p(argc, argv) for (i=0; i'/', 'WINDOWS'=>'\\', 'MACINTOSH'=>':'} HTTP_STATUS = { @@ -350,11 +351,11 @@ class CGI =begin === MAKE RFC1123 DATE STRING CGI::rfc1123_date(Time.now) - # Sat, 1 Jan 2000 00:00:00 GMT + # Sat, 01 Jan 2000 00:00:00 GMT =end def CGI::rfc1123_date(time) t = time.clone.gmtime - return format("%s, %d %s %d %.2d:%.2d:%.2d GMT", + return format("%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT", RFC822_DAYS[t.wday], t.day, RFC822_MONTHS[t.month-1], t.year, t.hour, t.min, t.sec) end @@ -423,7 +424,8 @@ status: options["type"].concat( options.delete("charset") ) end - if options.delete("nph") or (/IIS/n === env_table['SERVER_SOFTWARE']) + options.delete("nph") if defined?(MOD_RUBY) + if options.delete("nph") or /IIS/n.match(env_table['SERVER_SOFTWARE']) buf.concat( (env_table["SERVER_PROTOCOL"] or "HTTP/1.0") + " " ) buf.concat( (HTTP_STATUS[options["status"]] or options["status"] or @@ -446,7 +448,9 @@ status: end if options.has_key?("status") - buf.concat("Status: " + options.delete("status") + EOL) + status = (HTTP_STATUS[options["status"]] or options["status"]) + buf.concat("Status: " + status + EOL) + options.delete("status") end if options.has_key?("server") @@ -496,8 +500,21 @@ status: } if defined?(MOD_RUBY) - buf.scan(/([^:]+): (.+)#{EOL}/n){ - Apache::request[$1] = $2 + table = Apache::request.headers_out + buf.scan(/([^:]+): (.+)#{EOL}/n){ |name, value| + $stderr.printf("name:%s value:%s\n", name, value) if $DEBUG + case name + when 'Set-Cookie' + table.add($1, $2) + when /^status$/ni + Apache::request.status_line = value + when /^content-type$/ni + Apache::request.content_type = value + when /^content-encoding$/ni + Apache::request.content_encoding = value + else + Apache::request.headers_out[name] = value + end } Apache::request.send_http_header '' @@ -793,9 +810,9 @@ convert string charset, and set language to "ja". body = Tempfile.new("CGI") body.binmode - until head and (/#{boundary}(?:#{EOL}|--)/n === buf) + until head and /#{boundary}(?:#{EOL}|--)/n.match(buf) - if (not head) and (/#{EOL}#{EOL}/n === buf) + if (not head) and /#{EOL}#{EOL}/n.match(buf) buf = buf.sub(/\A((?:.|\n)*?#{EOL})#{EOL}/n) do head = $1.dup "" @@ -834,14 +851,14 @@ convert string charset, and set language to "ja". end END - /Content-Disposition:.* filename="?([^\";]*)"?/ni === head + /Content-Disposition:.* filename="?([^\";]*)"?/ni.match(head) eval <<-END def body.original_filename #{ filename = ($1 or "").dup - if (/Mac/ni === env_table['HTTP_USER_AGENT']) and - (/Mozilla/ni === env_table['HTTP_USER_AGENT']) and - (not /MSIE/ni === env_table['HTTP_USER_AGENT']) + if /Mac/ni.match(env_table['HTTP_USER_AGENT']) and + /Mozilla/ni.match(env_table['HTTP_USER_AGENT']) and + (not /MSIE/ni.match(env_table['HTTP_USER_AGENT'])) CGI::unescape(filename) else filename @@ -850,14 +867,14 @@ convert string charset, and set language to "ja". end END - /Content-Type: (.*)/ni === head + /Content-Type: (.*)/ni.match(head) eval <<-END def body.content_type #{($1 or "").dump.untaint}.taint end END - /Content-Disposition:.* name="?([^\";]*)"?/ni === head + /Content-Disposition:.* name="?([^\";]*)"?/ni.match(head) name = $1.dup if params.has_key?(name) @@ -889,7 +906,7 @@ convert string charset, and set language to "ja". words = Shellwords.shellwords(string) - if words.find{|x| /=/n === x } + if words.find{|x| /=/n.match(x) } words.join('&') else words.join('+') @@ -899,8 +916,7 @@ convert string charset, and set language to "ja". def initialize_query() if ("POST" == env_table['REQUEST_METHOD']) and - (%r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n === - env_table['CONTENT_TYPE']) + %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n.match(env_table['CONTENT_TYPE']) boundary = $1.dup @params = read_multipart(boundary, Integer(env_table['CONTENT_LENGTH'])) else @@ -975,8 +991,8 @@ convert string charset, and set language to "ja". cgi = CGI.new("html3") # add HTML generation methods cgi.element cgi.element{ "string" } - cgi.element({ "ATTRILUTE1" => "value1", "ATTRIBUTE2" => "value2" }) - cgi.element({ "ATTRILUTE1" => "value1", "ATTRIBUTE2" => "value2" }){ "string" } + cgi.element({ "ATTRIBUTE1" => "value1", "ATTRIBUTE2" => "value2" }) + cgi.element({ "ATTRIBUTE1" => "value1", "ATTRIBUTE2" => "value2" }){ "string" } # add HTML generation methods CGI.new("html3") # html3.2 @@ -1235,8 +1251,10 @@ convert string charset, and set language to "ja". form("get", "url"){ "string" } #
string
- form({"METHOD" => "post", ENCTYPE => "enctype"}){ "string" } + form({"METHOD" => "post", "ENCTYPE" => "enctype"}){ "string" } #
string
+ +The hash keys are case sensitive. Ask the samples. =end def form(method = "post", action = nil, enctype = "application/x-www-form-urlencoded") attributes = if method.kind_of?(String) @@ -1244,7 +1262,7 @@ convert string charset, and set language to "ja". "ENCTYPE" => enctype } else unless method.has_key?("METHOD") - method["METHOD"] = method + method["METHOD"] = "post" end unless method.has_key?("ENCTYPE") method["ENCTYPE"] = enctype @@ -1935,161 +1953,7 @@ end == HISTORY -* Mon Dec 25 05:02:27 JST 2000 - wakou - * version 2.1.2 - * bug fix: CGI::escapeElement(): didn't accept empty element. - * bug fix: CGI::unescapeElement(): ditto. - * bug fix: CGI::unescapeHTML(): support for "©, ♥, ..." - thanks to YANAGAWA Kazuhisa - * bug fix: CGI::unescapeHTML(): support for " " - thanks to OHSHIMA Ryunosuke - * Regexp::last_match[0] --> $& - * Regexp::last_match[1] --> $1 - * Regexp::last_match[2] --> $2 - * add: CGI#param(): test implement. undocumented. - -* Mon Dec 11 00:16:51 JST 2000 - wakou - * version 2.1.1 - * support -T1 on ruby 1.6.2 - * body.original_filename: eval(str.dump.untaint).taint - * body.content_type: eval(str.dump.untaint).taint - * $& --> Regexp::last_match[0] - * $1 --> Regexp::last_match[1] - * $2 --> Regexp::last_match[2] - -* Thu Oct 12 01:16:59 JST 2000 - wakou - * version 2.1.0 - * bug fix: CGI::html(): PRETTY option didn't work. - thanks to akira yamada - -* Wed Sep 13 06:09:26 JST 2000 - wakou - * version 2.0.1 - * bug fix: CGI::header(): output status header. - thanks to Yasuhiro Fukuma - -* Tue Sep 12 06:56:51 JST 2000 - wakou - * version 2.0.0 - * require ruby1.5.4 or later. (ruby1.4 doesn't have block_given? method.) - * improvement: CGI::escape(), CGI::unescape(). - thanks to WATANABE Hirofumi - * bug fix: CGI::escapeElement(). - * improvement: CGI::unescapeHTML(). - thanks to Kazuhiro NISHIYAMA - -* 2000/08/09 04:32:22 - matz - * improvement: CGI::pretty() - -* 2000/06/23 07:01:34 - matz - * change: iterator? --> block_given? - -* Sun Jun 18 23:31:44 JST 2000 - wakou - * version 1.7.0 - * change: version syntax. old: x.yz, now: x.y.z - -* 2000/06/13 15:49:27 - wakou - * version 1.61 - * read_multipart(): if no content body then raise EOFError. - -* 2000/06/03 18:16:17 - wakou - * version 1.60 - * improve: CGI::pretty() - -* 2000/05/30 19:04:08 - wakou - * version 1.50 - * CGI#out(): if "HEAD" == REQUEST_METHOD then output only HTTP header. - -* 2000/05/24 06:58:51 - wakou - * version 1.40 - * typo: CGI::Cookie::new() - * bug fix: CGI::escape(): bad: " " --> "%2B"; true: " " --> "+"; - thanks to Ryunosuke Ohshima - -* 2000/05/08 21:51:30 - wakou - * version 1.31 - * improvement of time forming new CGI object accompanied with HTML generation methods. - -* 2000/05/07 21:51:14 - wakou - * version 1.30 - * require English.rb - * improvement of load time. - -* 2000/05/02 21:44:12 - wakou - * version 1.21 - * support for ruby 1.5.3 (2000-05-01) (Array#filter --> Array#collect!) - -* 2000/04/03 18:31:42 - wakou - * version 1.20 - * bug fix: CGI#image_button() can't get Hash option. - thanks to Takashi Ikeda - * CGI::unescapeHTML(): simple support for "〹" - * CGI::Cookie::new(): simple support for IE - * CGI::escape(): ' ' replaced by '+' - -* 1999/12/06 20:16:34 - wakou - * version 1.10 - * can make many CGI objects. - * if use mod_ruby, then require ruby1.4.3 or later. - -* 1999/11/29 21:35:58 - wakou - * version 1.01 - * support for ruby 1.5.0 (1999-11-20) - -* 1999/09/13 23:00:58 - wakou - * version 1.00 - * COUTION! name change. CGI.rb --> cgi.rb - * CGI#auth_type, CGI#content_length, CGI#content_type, ... - if not ENV included it, then return nil. - * CGI#content_length and CGI#server_port return Integer. - * if not CGI#params.include?('name'), then CGI#params['name'] return []. - * if not CGI#cookies.include?('name'), then CGI#cookies['name'] return []. - -* 1999/08/05 18:04:59 - wakou - * version 0.41 - * typo. thanks to MJ Ray - HTTP_STATUS["NOT_INPLEMENTED"] --> HTTP_STATUS["NOT_IMPLEMENTED"] - -* 1999/07/20 20:44:31 - wakou - * version 0.40 - * COUTION! incompatible change. - sorry, but probably this change is last big incompatible change. - * CGI::print --> CGI#out - cgi = CGI.new - cgi.out{"string"} # old: CGI::print{"string"} - * CGI::cookie --> CGI::Cookie::new - cookie1 = CGI::Cookie::new # old: CGI::cookie - * CGI::header --> CGI#header - -* 1999/06/29 06:50:21 - wakou - * version 0.30 - * COUTION! incompatible change. - query = CGI.new - cookies = query.cookies # old: query.cookie - values = query.cookies[name] # old: query.cookie[name] - -* 1999/06/21 21:05:57 - wakou - * version 0.24 - * CGI::Cookie::parse() return { name => CGI::Cookie object } pairs. - -* 1999/06/20 23:29:12 - wakou - * version 0.23 - * modified a bit to clear module separation. - -* Mon Jun 14 17:49:32 JST 1999 - matz - * version 0.22 - * Cookies are now CGI::Cookie objects. - * Cookie modeled after CGI::Cookie.pm. - -* Fri Jun 11 11:19:11 JST 1999 - matz - * version 0.21 - * modified a bit to clear module separation. - -* 1999/06/03 06:48:15 - wakou - * version 0.20 - * support for multipart form. - -* 1999/05/24 07:05:41 - wakou - * version 0.10 - * first release. - -$Date$ +delete. see cvs log. + + =end diff --git a/lib/cgi/session.rb b/lib/cgi/session.rb index 48f3496939..1120fb50f0 100644 --- a/lib/cgi/session.rb +++ b/lib/cgi/session.rb @@ -1,3 +1,4 @@ +# Copyright (C) 2001 Yukihiro "Matz" Matsumoto # Copyright (C) 2000 Network Applied Communication Laboratory, Inc. # Copyright (C) 2000 Information-technology Promotion Agency, Japan @@ -15,23 +16,22 @@ class CGI } end - def create_new_id + def Session::create_new_id require 'md5' md5 = MD5::new md5.update(String(Time::now)) md5.update(String(rand(0))) md5.update(String($$)) md5.update('foobar') - @session_id = md5.hexdigest[0,16] + md5.hexdigest[0,16] end - private :create_new_id def initialize(request, option={}) session_key = option['session_key'] || '_session_id' id, = option['session_id'] unless id if option['new_session'] - id = create_new_id + id = Session::create_new_id end end unless id @@ -43,7 +43,7 @@ class CGI if option.key?('new_session') and not option['new_session'] raise ArgumentError, "session_key `%s' should be supplied"%session_key end - id = create_new_id + id = Session::create_new_id end end @session_id = id @@ -54,7 +54,9 @@ class CGI @output_cookies = [ Cookie::new("name" => session_key, "value" => id, - "path" => if ENV["SCRIPT_NAME"] then + "path" => if option['session_path'] then + option['session_path'] + elsif ENV["SCRIPT_NAME"] then File::dirname(ENV["SCRIPT_NAME"]) else "" @@ -132,6 +134,7 @@ class CGI end def close + return if @f.closed? update @f.close end diff --git a/lib/date.rb b/lib/date.rb index 58179a7153..3422121298 100644 --- a/lib/date.rb +++ b/lib/date.rb @@ -1,5 +1,5 @@ -# date.rb: Written by Tadayoshi Funaba 1998-2000 -# $Id: date.rb,v 1.22 2000-07-16 10:23:40+09 tadf Exp $ +# date2.rb: Written by Tadayoshi Funaba 1998-2001 +# $Id: date2.rb,v 1.23 2001-01-18 12:09:47+09 tadf Exp $ class Date @@ -128,16 +128,15 @@ class Date end if d < 0 ny, nm = clfloor(y * 12 + m, 12) - nm, = clfloor(m + 1, 1) - la = nil - 31.downto 1 do |z| - break if la = exist3?(y, m, z, sg) - end - ns = ns?(la, sg) - d = jd_to_civil(civil_to_jd(ny, nm, 1, ns) + d, ns)[-1] + nm, = clfloor(nm + 1, 1) + jd = civil_to_jd(ny, nm, d + 1, sg) + ns = ns?(jd, sg) + return unless [y, m] == jd_to_civil(jd, sg)[0..1] + return unless [ny, nm, 1] == jd_to_civil(jd - d, ns) + else + jd = civil_to_jd(y, m, d, sg) + return unless [y, m, d] == jd_to_civil(jd, sg) end - jd = civil_to_jd(y, m, d, sg) - return unless [y, m, d] == jd_to_civil(jd, sg) jd end @@ -154,16 +153,15 @@ class Date def exist2? (y, d, sg=ITALY) if d < 0 - ny = y + 1 - la = nil - 366.downto 1 do |z| - break if la = exist2?(y, z, sg) - end - ns = ns?(la, sg) - d = jd_to_ordinal(ordinal_to_jd(ny, 1, ns) + d, ns)[-1] + ny, = clfloor(y + 1, 1) + jd = ordinal_to_jd(ny, d + 1, sg) + ns = ns?(jd, sg) + return unless [y] == jd_to_ordinal(jd, sg)[0..0] + return unless [ny, 1] == jd_to_ordinal(jd - d, ns) + else + jd = ordinal_to_jd(y, d, sg) + return unless [y, d] == jd_to_ordinal(jd, sg) end - jd = ordinal_to_jd(y, d, sg) - return unless [y, d] == jd_to_ordinal(jd, sg) jd end diff --git a/lib/debug.rb b/lib/debug.rb index b6968cc338..220b68d2c9 100644 --- a/lib/debug.rb +++ b/lib/debug.rb @@ -91,22 +91,70 @@ class DEBUGGER__ @finish_pos = 0 @trace = false @catch = "StandardError" + @suspend_next = false end def stop_next(n=1) @stop_next = n end + def set_suspend + @suspend_next = true + end + + def clear_suspend + @suspend_next = false + end + + def suspend_all + DEBUGGER__.suspend + end + + def resume_all + DEBUGGER__.resume + end + + def check_suspend + while (Thread.critical = true; @suspend_next) + DEBUGGER__.waiting.push Thread.current + @suspend_next = false + Thread.stop + end + Thread.critical = false + end + + def trace? + @trace + end + + def set_trace(arg) + @trace = arg + end + def stdout DEBUGGER__.stdout end + def break_points DEBUGGER__.break_points end + def display DEBUGGER__.display end + def context(th) + DEBUGGER__.context(th) + end + + def set_trace_all(arg) + DEBUGGER__.set_trace(arg) + end + + def set_last_thread(th) + DEBUGGER__.set_last_thread(th) + end + def debug_eval(str, binding) begin val = eval(str, binding) @@ -205,7 +253,7 @@ class DEBUGGER__ def debug_command(file, line, id, binding) MUTEX.lock - DEBUGGER__.set_last_thread(Thread.current) + set_last_thread(Thread.current) frame_pos = 0 binding_file = file binding_line = line @@ -218,7 +266,8 @@ class DEBUGGER__ end @frames[0] = [binding, file, line, id] display_expressions(binding) - while input = readline("(rdb:%d) "%thnum(), true) + prompt = true + while prompt and input = readline("(rdb:%d) "%thnum(), true) catch(:debug_error) do if input == "" input = DEBUG_LAST_CMD[0] @@ -228,18 +277,24 @@ class DEBUGGER__ end case input - when /^\s*tr(?:ace)?(?:\s+(on|off))?$/ - if defined?( $1 ) + when /^\s*tr(?:ace)?(?:\s+(on|off))?(?:\s+(all))?$/ + if defined?( $2 ) if $1 == 'on' - @trace = true + set_trace_all true else - @trace = false + set_trace_all false + end + elsif defined?( $1 ) + if $1 == 'on' + set_trace true + else + set_trace false end end - if @trace - stdout.print "Trace on\n" + if trace? + stdout.print "Trace on.\n" else - stdout.print "Trace off\n" + stdout.print "Trace off.\n" end when /^\s*b(?:reak)?\s+((?:.*?+:)?.+)$/ @@ -336,8 +391,7 @@ class DEBUGGER__ end when /^\s*c(?:ont)?$/ - MUTEX.unlock - return + prompt = false when /^\s*s(?:tep)?(?:\s+(\d+))?$/ if $1 @@ -346,7 +400,7 @@ class DEBUGGER__ lev = 1 end @stop_next = lev - return + prompt = false when /^\s*n(?:ext)?(?:\s+(\d+))?$/ if $1 @@ -356,7 +410,7 @@ class DEBUGGER__ end @stop_next = lev @no_step = @frames.size - frame_pos - return + prompt = false when /^\s*w(?:here)?$/, /^\s*f(?:rame)?$/ display_frames(frame_pos) @@ -417,8 +471,7 @@ class DEBUGGER__ else @finish_pos = @frames.size - frame_pos frame_pos = 0 - MUTEX.unlock - return + prompt = false end when /^\s*cat(?:ch)?(?:\s+(.+))?$/ @@ -440,8 +493,10 @@ class DEBUGGER__ end when /^\s*q(?:uit)?$/ - input = readline("really quit? (y/n) ", false) - exit if input == "y" + input = readline("Really quit? (y/n) ", false) + if input == "y" + exit! # exit -> exit!: No graceful way to stop threads... + end when /^\s*v(?:ar)?\s+/ debug_variable_info($', binding) @@ -451,8 +506,7 @@ class DEBUGGER__ when /^\s*th(?:read)?\s+/ if DEBUGGER__.debug_thread_info($', binding) == :cont - MUTEX.unlock - return + prompt = false end when /^\s*p\s+/ @@ -467,6 +521,8 @@ class DEBUGGER__ end end end + MUTEX.unlock + resume_all end def debug_print_help @@ -492,7 +548,8 @@ Commands up[ nn] move to higher frame down[ nn] move to lower frame fin[ish] return to outer frame - tr[ace][ (on|off)] set trace mode + tr[ace] (on|off) set trace mode of current thread + tr[ace] (on|off) all set trace mode of all threads q[uit] exit from debugger v[ar] g[lobal] show global variables v[ar] l[ocal] show local variables @@ -501,11 +558,10 @@ Commands m[ethod] i[nstance] show methods of object m[ethod] show instance methods of class or module th[read] l[ist] list all threads - th[read] c[ur[rent]] show current threads - th[read] stop thread nnn - th[read] stop alias for th[read] - th[read] c[ur[rent]] alias for th[read] - th[read] resume run thread nnn + th[read] c[ur[rent]] show current thread + th[read] [sw[itch]] switch thread context to nnn + th[read] stop stop thread nnn + th[read] resume resume thread nnn p expression evaluate expression and print its value h[elp] print this help evaluate @@ -587,7 +643,7 @@ EOHELP end def check_break_points(file, pos, binding, id) - MUTEX.lock # Stop all threads before 'line' and 'call'. + return false if break_points.empty? file = File.basename(file) n = 1 for b in break_points @@ -604,7 +660,6 @@ EOHELP end n += 1 end - MUTEX.unlock return false end @@ -616,7 +671,6 @@ EOHELP end if @catch and ($!.type.ancestors.find { |e| e.to_s == @catch }) - MUTEX.lock fs = @frames.size tb = caller(0)[-fs..-1] if tb @@ -624,12 +678,14 @@ EOHELP stdout.printf "\tfrom %s\n", i end end + suspend_all debug_command(file, line, id, binding) end end def trace_func(event, file, line, id, binding, klass) - Tracer.trace_func(event, file, line, id, binding) if @trace + Tracer.trace_func(event, file, line, id, binding, klass) if trace? + context(Thread.current).check_suspend @file = file @line = line case event @@ -647,6 +703,7 @@ EOHELP @stop_next = 1 else @no_step = nil + suspend_all debug_command(file, line, id, binding) @last = [file, line] end @@ -656,6 +713,7 @@ EOHELP @frames.unshift [binding, file, line, id] if check_break_points(file, id.id2name, binding, id) or check_break_points(klass.to_s, id.id2name, binding, id) + suspend_all debug_command(file, line, id, binding) end @@ -668,6 +726,7 @@ EOHELP when 'return', 'end' if @frames.size == @finish_pos @stop_next = 1 + @finish_pos = 0 end @frames.shift @@ -682,19 +741,20 @@ EOHELP end end - trap("INT") { DEBUGGER__.interrupt } -# $DEBUG = true + trap("INT") { DEBUGGER__.interrupt } @last_thread = Thread::main @max_thread = 1 @thread_list = {Thread::main => 1} @break_points = [] @display = [] + @waiting = [] @stdout = STDOUT class < true +# foo.hash == foo2.hash # => false # # Foo = DelegateClass(Array) # diff --git a/lib/importenv.rb b/lib/importenv.rb index fcf306a9ab..586f37661b 100644 --- a/lib/importenv.rb +++ b/lib/importenv.rb @@ -10,10 +10,10 @@ for k,v in ENV next unless /^[a-zA-Z][_a-zA-Z0-9]*/ =~ k eval < -Version: 1.2.1 += monitor.rb -USAGE: +Copyright (C) 2001 Shugo Maeda - foo = Foo.new - foo.extend(MonitorMixin) - cond = foo.new_cond +This library is distributed under the terms of the Ruby license. +You can freely distribute/modify this library. - thread1: - foo.synchronize { - ... - cond.wait_until { foo.done? } - ... - } +== example - thread2: - foo.synchronize { - foo.do_something - cond.signal - } +This is a simple example. + + require 'monitor.rb' + + buf = [] + buf.extend(MonitorMixin) + empty_cond = buf.new_cond + + # consumer + Thread.start do + loop do + buf.synchronize do + empty_cond.wait_while { buf.empty? } + print buf.shift + end + end + end + + # producer + while line = ARGF.gets + buf.synchronize do + buf.push(line) + empty_cond.signal + end + end + +The consumer thread waits for the producer thread to push a line +to buf while buf.empty?, and the producer thread (main thread) +reads a line from ARGF and push it to buf, then call +empty_cond.signal. =end @@ -52,6 +69,15 @@ module MonitorMixin raise ThreadError, "current thread not owner" end + if timeout + ct = Thread.current + timeout_thread = Thread.start { + Thread.pass + sleep(timeout) + ct.raise(Timeout.new) + } + end + Thread.critical = true count = @monitor.mon_count @monitor.mon_count = 0 @@ -63,34 +89,28 @@ module MonitorMixin end t.wakeup if t @waiters.push(Thread.current) - - if timeout - t = Thread.current - timeout_thread = Thread.start { - sleep(timeout) - t.raise(Timeout.new) - } - end + begin Thread.stop rescue Timeout - @waiters.delete(Thread.current) ensure + Thread.critical = true if timeout && timeout_thread.alive? Thread.kill(timeout_thread) end + if @waiters.include?(Thread.current) # interrupted? + @waiters.delete(Thread.current) + end + while @monitor.mon_owner && + @monitor.mon_owner != Thread.current + @monitor.mon_waiting_queue.push(Thread.current) + Thread.stop + Thread.critical = true + end + @monitor.mon_owner = Thread.current + @monitor.mon_count = count + Thread.critical = false end - - Thread.critical = true - while @monitor.mon_owner && - @monitor.mon_owner != Thread.current - @monitor.mon_waiting_queue.push(Thread.current) - Thread.stop - Thread.critical = true - end - @monitor.mon_owner = Thread.current - @monitor.mon_count = count - Thread.critical = false end def wait_while diff --git a/lib/net/http.rb b/lib/net/http.rb index 3900ed6c68..26e5285525 100644 --- a/lib/net/http.rb +++ b/lib/net/http.rb @@ -1,8 +1,9 @@ =begin -= net/http.rb version 1.1.32 += net/http.rb version 1.1.34 + +written by Minero Aoki -maintained by Minero Aoki This file is derived from "http-access.rb". This program is free software. @@ -14,9 +15,34 @@ You can get it from RAA (Ruby Application Archive: http://www.ruby-lang.org/en/raa.html). -= class HTTP +== http.rb version 1.2 features + +You can use 1.2 features by calling HTTP.version_1_2. And +calling Net::HTTP.version_1_1 allows to use 1.1 features. + + # example + HTTP.start {|http1| ...(http1 has 1.1 features)... } + + HTTP.version_1_2 + HTTP.start {|http2| ...(http2 has 1.2 features)... } + + HTTP.version_1_1 + HTTP.start {|http3| ...(http3 has 1.1 features)... } + +Changes are: -== Class Methods + * HTTP#get, head, post does not raise ProtocolError + * HTTP#get, head, post returns only one object, a HTTPResponse object + * HTTPResponseReceiver is joined into HTTPResponse + * request object: HTTP::Get, Head, Post; and HTTP#request(req) + +WARNING: These features are not definite yet. +They will change without notice! + + +== class HTTP + +=== Class Methods : new( address = 'localhost', port = 80, proxy_addr = nil, proxy_port = nil ) creates a new Net::HTTP object. @@ -49,7 +75,7 @@ You can get it from RAA HTTP default port (80). -== Methods +=== Methods : start : start {|http| .... } @@ -72,7 +98,7 @@ You can get it from RAA get data from "path" on connecting host. "header" must be a Hash like { 'Accept' => '*/*', ... }. Data is written to "dest" by using "<<" method. - This method returns Net::HTTPResponse object, and "dest". + This method returns HTTPResponse object, and "dest". # example response, body = http.get( '/index.html' ) @@ -95,7 +121,7 @@ You can get it from RAA : head( path, header = nil ) gets only header from "path" on connecting host. "header" is a Hash like { 'Accept' => '*/*', ... }. - This method returns a Net::HTTPResponse object. + This method returns a HTTPResponse object. You can http header from this object like: response['content-length'] #-> '2554' @@ -109,7 +135,7 @@ You can get it from RAA If the body exists, also gets entity body. Data is written to "dest" by using "<<" method. "header" must be a Hash like { 'Accept' => '*/*', ... }. - This method returns Net::HTTPResponse object and "dest". + This method returns HTTPResponse object and "dest". If called with block, gives a part of entity body string. @@ -181,21 +207,21 @@ You can get it from RAA response.body -= class HTTPResponse +== class HTTPResponse HTTP response object. All "key" is case-insensitive. -== Methods +=== Methods : body - the entity body. ("dest" argument for HTTP#get, post, put) + the entity body (String). : self[ key ] returns header field for "key". for HTTP, value is a string like 'text/plain'(for Content-Type), - '2045'(for Content-Length), 'bytes 0-1024/10024'(for Content-Range). - Multiple header had be joined by HTTP1.1 scheme. + '2045'(for Content-Length), 'bytes 0-1023/10024'(for Content-Range). + If there's some fields which has same name, they are joined with ','. : self[ key ] = val set field value for "key". @@ -204,88 +230,92 @@ All "key" is case-insensitive. true if key exists : each {|name,value| .... } - iterates for each field name and value pair + iterates for each field name and value pair. : code - HTTP result code string. For example, '302' + HTTP result code string. For example, '302'. : message - HTTP result message. For example, 'Not Found' + HTTP result message. For example, 'Not Found'. -= class HTTPResponseReceiver +== class HTTPResponseReceiver -== Methods +=== Methods : header : response - Net::HTTPResponse object + HTTPResponse object -: body( dest = '' ) -: entity( dest = '' ) - entity body. A body is written to "dest" using "<<" method. +: read_body( dest = '' ) + reads entity body into DEST by calling "<<" method and + returns DEST. -: body {|str| ... } - gets entity body with block. - If this method is called twice, block is not executed and - returns first "dest". +: read_body {|string| ... } + reads entity body little by little and gives it to block + until entity ends. +: body +: entity + entity body. If #read_body is called already, returns its + argument DEST. Else returns entity body as String. -= http.rb version 1.2 features + Calling this method any times causes returning same + object (does not read entity again). -You can use 1.2 features by calling HTTP.version_1_2. And -calling Net::HTTP.version_1_1 allows to use 1.1 features. +=end - # example - HTTP.start {|http1| ...(http1 has 1.1 features)... } +require 'net/protocol' - HTTP.version_1_2 - HTTP.start {|http2| ...(http2 has 1.2 features)... } - HTTP.version_1_1 - HTTP.start {|http3| ...(http3 has 1.1 features)... } +module Net -== Method (only diff to 1.1) + class HTTPBadResponse < StandardError; end + class HTTPHeaderSyntaxError < StandardError; end -: get( path, u_header = nil ) -: get( path, u_header = nil ) {|str| .... } - gets document from "path". - returns HTTPResponse object. -: head( path, u_header = nil ) - gets only document header from "path". - returns HTTPResponse object. + class HTTP < Protocol -: post( path, data, u_header = nil ) -: post( path, data, u_header = nil ) {|str| .... } - posts "data" to "path" entity and gets document. - returns HTTPResponse object. + HTTPVersion = '1.1' -=end + # + # connection + # -require 'net/protocol' + protocol_param :port, '80' -module Net + def initialize( addr = nil, port = nil ) + super - class HTTPBadResponse < StandardError; end + @proxy_address = nil + @proxy_port = nil + @curr_http_version = HTTPVersion + @seems_1_0_server = false + end - class HTTP < Protocol - protocol_param :port, '80' - protocol_param :command_type, '::Net::NetPrivate::HTTPCommand' + private + def conn_command( sock ) + end + + def do_finish + end + + + # + # proxy + # + + public - ### - ### proxy - ### class << self def Proxy( p_addr, p_port = nil ) - ::Net::NetPrivate::HTTPProxy.create_proxy_class( - p_addr, p_port || self.port ) + ProxyMod.create_proxy_class( p_addr, p_port || self.port ) end alias orig_new new @@ -293,7 +323,7 @@ module Net def new( address = nil, port = nil, p_addr = nil, p_port = nil ) c = p_addr ? self::Proxy(p_addr, p_port) : self i = c.orig_new( address, port ) - setimplv i + setvar i i end @@ -332,385 +362,230 @@ module Net end - ### - ### 1.2 implementation - ### + module ProxyMod - @@newimpl = false + class << self - #class << self + def create_proxy_class( p_addr, p_port ) + mod = self + klass = Class.new( HTTP ) + klass.module_eval { + include mod + @proxy_address = p_addr + @proxy_port = p_port + } + def klass.proxy_class? + true + end - def self.version_1_2 - @@newimpl = true - end + def klass.proxy_address + @proxy_address + end - def self.version_1_1 - @@newimpl = false - end + def klass.proxy_port + @proxy_port + end - #private + klass + end - def self.setimplv( obj ) - f = @@newimpl - obj.instance_eval { @newimpl = f } end - #end - - - ### - ### http operations - ### - - def get( path, u_header = nil, dest = nil, &block ) - resp = get2( path, u_header ) {|f| f.body( dest, &block ) } - if @newimpl then - resp - else - resp.value - return resp, resp.body + def initialize( addr, port ) + super + @proxy_address = type.proxy_address + @proxy_port = type.proxy_port end - end - - def get2( path, u_header = nil, &block ) - common_oper( u_header, true, block ) {|uh| - @command.get edit_path(path), uh - } - end + + attr_reader :proxy_address, :proxy_port + alias proxyaddr proxy_address + alias proxyport proxy_port - def head( path, u_header = nil ) - resp = head2( path, u_header ) - unless @newimpl then - resp.value + def proxy? + true end - resp - end - - def head2( path, u_header = nil, &block ) - common_oper( u_header, false, block ) {|uh| - @command.head edit_path(path), uh - } - end - - - def post( path, data, u_header = nil, dest = nil, &block ) - resp = post2( path, data, u_header ) {|f| f.body( dest, &block ) } - if @newimpl then - resp - else - resp.value - return resp, resp.body + + private + + def conn_socket( addr, port ) + super @proxy_address, @proxy_port end - end - - def post2( path, data, u_header = nil, &block ) - common_oper( u_header, true, block ) {|uh| - @command.post edit_path(path), uh, data - } - end - - # not tested because I could not setup apache (__;;; - def put( path, src, u_header = nil ) - resp = put2( path, src, u_header ) {|f| f.body } - if @newimpl then - resp - else - resp.value - return resp, resp.body + def edit_path( path ) + 'http://' + addr_port + path end - end + + end # module ProxyMod - def put2( path, src, u_header = nil, &block ) - common_oper( u_header, true, block ) {|uh| - @command.put path, uh, src - } - end - - - private - - - def common_oper( u_header, body_exist, block ) - header = procheader( u_header ) - recv = err = nil - - connecting( header ) { - recv = HTTPResponseReceiver.new( @command, body_exist ) - yield header - begin - block.call recv if block - rescue Exception => err - ; - end - recv.terminate - - recv.response - } - raise err if err - recv.response - end + # + # for backward compatibility + # - def connecting( header ) - if not @socket then - header['Connection'] = 'close' - start - elsif @socket.closed? then - @socket.reopen - end + @@newimpl = false - resp = yield + class << self - unless keep_alive? header, resp then - @socket.close + def version_1_2 + @@newimpl = true end - end - def keep_alive?( header, resp ) - if resp.key? 'connection' then - if /keep-alive/i === resp['connection'] then - return true - end - elsif resp.key? 'proxy-connection' then - if /keep-alive/i === resp['proxy-connection'] then - return true - end - elsif header.key? 'Connection' then - if /keep-alive/i === header['Connection'] then - return true - end - else - if @command.http_version == '1.1' then - return true - end + def version_1_1 + @@newimpl = false end - false - end - - def procheader( h ) - ret = {} - ret[ 'Host' ] = address + - ((port == HTTP.port) ? '' : ":#{port}") - ret[ 'Connection' ] = 'Keep-Alive' - ret[ 'Accept' ] = '*/*' + private - return ret unless h - tmp = {} - h.each do |k,v| - key = k.split('-').collect {|i| i.capitalize }.join('-') - if tmp[key] then - $stderr.puts "'#{key}' http header appered twice" if $VERBOSE - end - tmp[key] = v + def setvar( obj ) + f = @@newimpl + obj.instance_eval { @newimpl = f } end - ret.update tmp - ret end - def do_finish - end + # + # http operations + # - end - - HTTPSession = HTTP - - - module NetPrivate - - module HTTPProxy - - class << self - - def create_proxy_class( p_addr, p_port ) - klass = Class.new( HTTP ) - klass.module_eval { - include HTTPProxy - @proxy_address = p_addr - @proxy_port = p_port - } - def klass.proxy_class? - true - end + public - def klass.proxy_address - @proxy_address + def self.def_http_method( nm, hasdest, hasdata ) + name = nm.id2name.downcase + cname = nm.id2name + lineno = __LINE__ + 2 + src = <<" ----" + + def #{name}( path, #{hasdata ? 'data,' : ''} + u_header = nil #{hasdest ? ',dest = nil, &block' : ''} ) + resp = nil + request( + #{cname}.new( path, u_header ) #{hasdata ? ',data' : ''} + ) do |resp| + resp.read_body( #{hasdest ? 'dest, &block' : ''} ) + end + if @newimpl then + resp + else + resp.value + #{hasdest ? 'return resp, resp.body' : 'resp'} + end end - def klass.proxy_port - @proxy_port + def #{name}2( path, #{hasdata ? 'data,' : ''} + u_header = nil, &block ) + request( #{cname}.new(path, u_header), + #{hasdata ? 'data,' : ''} &block ) end - - klass - end - - end - - - def initialize( addr, port ) - super - @proxy_address = type.proxy_address - @proxy_port = type.proxy_port + ---- + module_eval src, __FILE__, lineno end - attr_reader :proxy_address, :proxy_port + def_http_method :Get, true, false + def_http_method :Head, false, false + def_http_method :Post, true, true + def_http_method :Put, false, true - alias proxyaddr proxy_address - alias proxyport proxy_port - - def proxy? - true - end - - def connect( addr = nil, port = nil ) - super @proxy_address, @proxy_port - end - - def edit_path( path ) - 'http://' + address + (port == type.port ? '' : ":#{port}") + path + def request( req, *args ) + common_oper( req ) { + req.__send__( :exec, + @socket, @curr_http_version, edit_path(req.path), *args ) + yield req.response if block_given? + } + req.response end - - end - - end # net private + private - class HTTPResponseReceiver - - def initialize( command, body_exist ) - @command = command - @body_exist = body_exist - @header = @body = nil - end - - def inspect - "#<#{type}>" - end - def read_header - unless @header then - stream_check - @header = @command.get_response + def common_oper( req ) + req['connection'] ||= 'keep-alive' + if not @socket then + start + req['connection'] = 'close' + elsif @socket.closed? then + re_connect end - @header - end - - alias header read_header - alias response read_header - - def read_body( dest = nil, &block ) - unless @body then - read_header - - to = procdest( dest, block ) - stream_check - - if @body_exist and @header.code_type.body_exist? then - @command.get_body @header, to - @header.body = @body = to - else - @command.no_body - @header.body = nil - @body = 1 - end + if not req.body_exist? or @seems_1_0_server then + req['connection'] = 'close' end - @body == 1 ? nil : @body - end - - alias body read_body - alias entity read_body + req['host'] = addr_port - def terminate - read_header - read_body - @command = nil - end + yield req + req.response.__send__ :terminate + @curr_http_version = req.response.http_version - - private - - def stream_check - unless @command then - raise IOError, 'receiver was used out of block' - end - end - - def procdest( dest, block ) - if dest and block then - raise ArgumentError, - 'both of arg and block are given for HTTP method' - end - if block then - NetPrivate::ReadAdapter.new block + if not req.response.body then + @socket.close + elsif keep_alive? req, req.response then + D 'Conn keep-alive' + if @socket.closed? then # (only) read stream had been closed + D 'Conn (but seems 1.0 server)' + @seems_1_0_server = true + @socket.close + end else - dest or '' + D 'Conn close' + @socket.close end - end - - end - - HTTPReadAdapter = HTTPResponseReceiver - - class HTTPResponse < Response - - def initialize( code_type, code, msg ) - super - @data = {} - @body = nil + req.response end - attr_accessor :body + def keep_alive?( req, res ) + /close/i === req['connection'].to_s and return false + @seems_1_0_server and return false - def inspect - "#<#{type.name} #{code}>" - end + /keep-alive/i === res['connection'].to_s and return true + /close/i === res['connection'].to_s and return false + /keep-alive/i === res['proxy-connection'].to_s and return true + /close/i === res['proxy-connection'].to_s and return false - def []( key ) - @data[ key.downcase ] + @curr_http_version == '1.1' and return true + false end - def []=( key, val ) - @data[ key.downcase ] = val - end - def each( &block ) - @data.each( &block ) - end + # + # utils + # - def each_key( &block ) - @data.each_key( &block ) - end + public - def each_value( &block ) - @data.each_value( &block ) + def self.get( addr, path, port = nil ) + req = Get.new( path ) + resp = nil + new( addr, port || HTTP.port ).start {|http| + resp = http.request( req ) + } + resp.body end - def delete( key ) - @data.delete key.downcase + def self.get_print( addr, path, port = nil ) + print get( addr, path, port ) end - def key?( key ) - @data.key? key.downcase - end - def to_hash - @data.dup + private + + def addr_port + address + (port == HTTP.port ? '' : ":#{port}") end - def value - unless SuccessCode === self then - error! self + def D( msg ) + if @dout then + @dout << msg + @dout << "\n" end end end + HTTPSession = HTTP + + class Code @@ -776,101 +651,246 @@ module Net HTTPVersionNotSupported = HTTPServerErrorCode.http_mkchild - module NetPrivate + ### + ### header + ### - class HTTPCommand < Command + net_private { - HTTPVersion = '1.1' + module HTTPHeader - def initialize( sock ) - @http_version = HTTPVersion - super sock + def size + @header.size end - attr_reader :http_version + alias length size - def inspect - "#" + def []( key ) + @header[ key.downcase ] end + def []=( key, val ) + @header[ key.downcase ] = val + end - ### - ### request - ### + def each( &block ) + @header.each( &block ) + end - public + def each_key( &block ) + @header.each_key( &block ) + end - def get( path, u_header ) - return unless begin_critical - request sprintf('GET %s HTTP/%s', path, HTTPVersion), u_header + def each_value( &block ) + @header.each_value( &block ) end - - def head( path, u_header ) - return unless begin_critical - request sprintf('HEAD %s HTTP/%s', path, HTTPVersion), u_header + + def delete( key ) + @header.delete key.downcase + end + + def key?( key ) + @header.key? key.downcase + end + + def to_hash + @header.dup end - def post( path, u_header, data ) - return unless begin_critical - u_header[ 'Content-Length' ] = data.size.to_s - request sprintf('POST %s HTTP/%s', path, HTTPVersion), u_header - @socket.write data + def canonical_each + @header.each do |k,v| + yield canonical(k), v + end end - def put( path, u_header, src ) - return unless begin_critical - request sprintf('PUT %s HTTP/%s', path, HTTPVersion), u_header - @socket.write_bin src + def canonical( k ) + k.split('-').collect {|i| i.capitalize }.join('-') end - # def delete + def range + s = @header['range'] + s or return nil - # def trace + arr = [] + s.split(',').each do |spec| + m = /bytes\s*=\s*(\d+)?\s*-\s*(\d+)?/i.match( spec ) + m or raise HTTPHeaderSyntaxError, "wrong Range: #{spec}" - # def options + d1 = m[1].to_i + d2 = m[2].to_i + if m[1] and m[2] then arr.push (d1 .. d2) + elsif m[1] then arr.push (d1 .. -1) + elsif m[2] then arr.push (-d2 .. -1) + else + raise HTTPHeaderSyntaxError, 'range is not specified' + end + end - def quit + return *arr end + def range=( r, fin = nil ) + if fin then + r = r ... r+fin + end - private + case r + when Numeric + s = r > 0 ? "0-#{r - 1}" : "-#{-r}" + when Range + first = r.first + last = r.last + if r.exclude_end? then + last -= 1 + end - def request( req, u_header ) - @socket.writeline req - u_header.each do |n,v| - @socket.writeline n + ': ' + v + if last == -1 then + s = first > 0 ? "#{first}-" : "-#{-first}" + else + first >= 0 or raise HTTPHeaderSyntaxError, 'range.first is negative' + last > 0 or raise HTTPHeaderSyntaxError, 'range.last is negative' + first < last or raise HTTPHeaderSyntaxError, 'must be .first < .last' + s = "#{first}-#{last}" + end + else + raise TypeError, 'Range/Integer is required' end - @socket.writeline '' + + @header['range'] = "bytes=#{s}" + r end + alias set_range range= - ### - ### response line & header - ### + def content_length + s = @header['content-length'] + s or return nil - public + m = /\d+/.match(s) + m or raise HTTPHeaderSyntaxError, 'wrong Content-Length format' + m[0].to_i + end - def get_response - resp = get_resp0 - resp = get_resp0 while ContinueCode === resp - resp + def chunked? + s = @header['transfer-encoding'] + (s and /(?:\A|[^\-\w])chunked(?:[^\-\w]|\z)/i === s) ? true : false + end + + def content_range + s = @header['content-range'] + s or return nil + + m = %ri.match( s ) + m or raise HTTPHeaderSyntaxError, 'wrong Content-Range format' + + m[1].to_i .. m[2].to_i + 1 + end + + def range_length + r = content_range + r and r.length + end + + def basic_auth( acc, pass ) + @header['authorization'] = + 'Basic ' + ["#{acc}:#{pass}"].pack('m').gsub(/\s+/, '') + end + + end + + } + + + ### + ### request + ### + + net_private { + + class HTTPRequest + + include ::Net::NetPrivate::HTTPHeader + + def initialize( path, uhead = nil ) + @path = path + @header = tmp = {} + return unless uhead + uhead.each do |k,v| + key = k.downcase + if tmp.key? key then + $stderr.puts "WARNING: duplicated HTTP header: #{k}" if $VERBOSE + end + tmp[ key ] = v.strip + end + tmp['accept'] ||= '*/*' + + @socket = nil + @response = nil + end + + attr_reader :path + attr_reader :response + + def inspect + "\#<#{type}>" + end + + def body_exist? + type::HAS_BODY end private - def get_resp0 - resp = get_reply + # + # write + # + + def exec( sock, ver, path ) + ready( sock ) { + request ver, path + } + @response + end + + def ready( sock ) + @response = nil + @socket = sock + yield + @response = get_response + @socket = nil + end + + def request( ver, path ) + @socket.writeline sprintf('%s %s HTTP/%s', type::METHOD, path, ver) + canonical_each do |k,v| + @socket.writeline k + ': ' + v + end + @socket.writeline '' + end + + # + # read + # + + def get_response + begin + resp = read_response + end while ContinueCode === resp + resp + end + + def read_response + resp = get_resline while true do - line = @socket.readline + line = @socket.readuntil( "\n", true ) # ignore EOF + line.sub!( /\s+\z/, '' ) # don't use chop! break if line.empty? m = /\A([^:]+):\s*/.match( line ) - unless m then - raise HTTPBadResponse, 'wrong header line format' - end + m or raise HTTPBadResponse, 'wrong header line format' nm = m[1] line = m.post_match if resp.key? nm then @@ -883,23 +903,117 @@ module Net resp end - def get_reply + def get_resline str = @socket.readline - m = /\AHTTP\/(\d+\.\d+)?\s+(\d\d\d)\s*(.*)\z/i.match( str ) - unless m then - raise HTTPBadResponse, "wrong status line: #{str}" - end - @http_version = m[1] + m = /\AHTTP(?:\/(\d+\.\d+))?\s+(\d\d\d)\s*(.*)\z/i.match( str ) + m or raise HTTPBadResponse, "wrong status line: #{str}" + httpver = m[1] status = m[2] discrip = m[3] - code = HTTPCODE_TO_OBJ[status] || - HTTPCODE_CLASS_TO_OBJ[status[0,1]] || - UnknownCode - HTTPResponse.new( code, status, discrip ) + ::Net::NetPrivate::HTTPResponse.new( + status, discrip, @socket, type::HAS_BODY, httpver ) + end + + end + + + class HTTPRequestWithBody < HTTPRequest + + private + + def exec( sock, ver, path, str = nil ) + check_arg str, block_given? + + if block_given? then + ac = Accumulator.new + yield ac # must be yield, DO NOT USE block.call + data = ac.terminate + else + data = str + end + @header['content-length'] = data.size.to_s + @header.delete 'transfer-encoding' + + ready( sock ) { + request ver, path + @socket.write data + } + @response + end + + def check_arg( data, blkp ) + if data and blkp then + raise ArgumentError, 'both of data and block given' + end + unless data or blkp then + raise ArgumentError, 'str or block required' + end + end + + end + + + class Accumulator + + def initialize + @buf = '' + end + + def write( s ) + @buf.concat s + end + + alias << write + + def terminate + ret = @buf + @buf = nil + ret + end + + end + + } + + + class HTTP + + class Get < ::Net::NetPrivate::HTTPRequest + HAS_BODY = true + METHOD = 'GET' + end + + class Head < ::Net::NetPrivate::HTTPRequest + HAS_BODY = false + METHOD = 'HEAD' + end + + class Post < ::Net::NetPrivate::HTTPRequestWithBody + HAS_BODY = true + METHOD = 'POST' + end + + class Put < ::Net::NetPrivate::HTTPRequestWithBody + HAS_BODY = true + METHOD = 'PUT' end - HTTPCODE_CLASS_TO_OBJ = { + end + + + + ### + ### response + ### + + net_private { + + class HTTPResponse < Response + + include ::Net::NetPrivate::HTTPHeader + + CODE_CLASS_TO_OBJ = { '1' => HTTPInformationCode, '2' => HTTPSuccessCode, '3' => HTTPRedirectionCode, @@ -907,7 +1021,7 @@ module Net '5' => HTTPServerErrorCode } - HTTPCODE_TO_OBJ = { + CODE_TO_OBJ = { '100' => ContinueCode, '101' => HTTPSwitchProtocol, @@ -951,22 +1065,87 @@ module Net '505' => HTTPVersionNotSupported } + def initialize( stat, msg, sock, be, hv ) + code = CODE_TO_OBJ[stat] || + CODE_CLASS_TO_OBJ[stat[0,1]] || + UnknownCode + super code, stat, msg + @socket = sock + @body_exist = be + @http_version = hv - ### - ### body - ### + @header = {} + @body = nil + @read = false + end - public + attr_reader :http_version + + def inspect + "#<#{type} #{code}>" + end + + def value + SuccessCode === self or error! self + end - def get_body( resp, dest ) - if chunked? resp then + + # + # header (for backward compatibility) + # + + def read_header + self + end + + alias header read_header + alias response read_header + + # + # body + # + + def read_body( dest = nil, &block ) + if @read and (dest or block) then + raise IOError, "#{type}\#read_body called twice with argument" + end + + unless @read then + to = procdest( dest, block ) + stream_check + + if @body_exist and code_type.body_exist? then + read_body_0 to + @body = to + else + @body = nil + end + @read = true + end + + @body + end + + alias body read_body + alias entity read_body + + + private + + + def terminate + read_body + end + + def read_body_0( dest ) + if chunked? then read_chunked dest else - clen = content_length( resp ) + clen = content_length if clen then - @socket.read clen, dest + @socket.read clen, dest, true # ignore EOF else - clen = range_length( resp ) + clen = range_length if clen then @socket.read clen, dest else @@ -974,16 +1153,8 @@ module Net end end end - end_critical - end - - def no_body - end_critical end - - private - def read_chunked( dest ) len = nil total = 0 @@ -991,9 +1162,7 @@ module Net while true do line = @socket.readline m = /[0-9a-fA-F]+/.match( line ) - unless m then - raise HTTPBadResponse, "wrong chunk size line: #{line}" - end + m or raise HTTPBadResponse, "wrong chunk size line: #{line}" len = m[0].hex break if len == 0 @socket.read( len, dest ); total += len @@ -1004,44 +1173,27 @@ module Net end end - def content_length( resp ) - if resp.key? 'content-length' then - m = /\d+/.match( resp['content-length'] ) - unless m then - raise HTTPBadResponse, 'wrong Content-Length format' - end - m[0].to_i - else - nil - end + def stream_check + @socket.closed? and raise IOError, 'try to read body out of block' end - def chunked?( resp ) - tmp = resp['transfer-encoding'] - tmp and /(?:\A|\s+)chunked(?:\s+|\z)/i === tmp - end - - def range_length( resp ) - if resp.key? 'content-range' then - m = %r.match( resp['content-range'] ) - unless m then - raise HTTPBadResponse, 'wrong Content-Range format' - end - l = m[2].to_i - u = m[1].to_i - if l > u then - nil - else - u - l - end + def procdest( dest, block ) + if dest and block then + raise ArgumentError, 'both of arg and block are given for HTTP method' + end + if block then + ::Net::NetPrivate::ReadAdapter.new block else - nil + dest || '' end end end + } + - end # module Net::NetPrivate + HTTPResponse = NetPrivate::HTTPResponse + HTTPResponseReceiver = NetPrivate::HTTPResponse end # module Net diff --git a/lib/net/imap.rb b/lib/net/imap.rb index 34d324ed12..ea064d2552 100644 --- a/lib/net/imap.rb +++ b/lib/net/imap.rb @@ -7,9 +7,10 @@ Copyright (C) 2000 Shugo Maeda This library is distributed under the terms of the Ruby license. You can freely distribute/modify this library. -== class Net::IMAP +== Net::IMAP Net::IMAP implements Internet Message Access Protocol (IMAP) clients. +(The protocol is described in ((<[IMAP]>)).) === Super Class @@ -102,21 +103,24 @@ Object : list(refname, mailbox) Sends a LIST command, and returns a subset of names from the complete set of all names available to the client. + The return value is an array of (()). ex). imap.create("foo/bar") imap.create("foo/baz") p imap.list("", "foo/%") - #=> [#, #, #] + #=> [#, #, #] : lsub(refname, mailbox) Sends a LSUB command, and returns a subset of names from the set of names that the user has declared as being "active" or "subscribed". + The return value is an array of (()). : status(mailbox, attr) Sends a STATUS command, and returns the status of the indicated mailbox. + The return value is a hash of attributes. ex). p imap.status("inbox", ["MESSAGES", "RECENT"]) @@ -166,6 +170,7 @@ Object in the mailbox. the set parameter is a number or an array of numbers or a Range object. the number is a message sequence number (fetch) or a unique identifier (uid_fetch). + The return value is an array of (()). ex). p imap.fetch(6..8, "UID") @@ -188,6 +193,7 @@ Object in the mailbox. the set parameter is a number or an array of numbers or a Range object. the number is a message sequence number (store) or a unique identifier (uid_store). + The return value is an array of (()). ex). p imap.store(6..8, "+FLAGS", [:Deleted]) @@ -210,6 +216,443 @@ Object p imap.sort(["DATE"], ["SUBJECT", "hello"], "US-ASCII") #=> [6, 7, 8, 1] +== Net::IMAP::ContinuationRequest + +Net::IMAP::ContinuationRequest represents command continuation requests. + +The command continuation request response is indicated by a "+" token +instead of a tag. This form of response indicates that the server is +ready to accept the continuation of a command from the client. The +remainder of this response is a line of text. + + continue_req ::= "+" SPACE (resp_text / base64) + +=== Super Class + +Struct + +=== Methods + +: data + Returns the data (Net::IMAP::ResponseText). + +: raw_data + Returns the raw data string. + +== Net::IMAP::UntaggedResponse + +Net::IMAP::UntaggedResponse represents untagged responses. + +Data transmitted by the server to the client and status responses +that do not indicate command completion are prefixed with the token +"*", and are called untagged responses. + + response_data ::= "*" SPACE (resp_cond_state / resp_cond_bye / + mailbox_data / message_data / capability_data) + +=== Super Class + +Struct + +=== Methods + +: name + Returns the name such as "FLAGS", "LIST", "FETCH".... + +: data + Returns the data such as an array of flag symbols, + a (()) object.... + +: raw_data + Returns the raw data string. + +== Net::IMAP::TaggedResponse + +Net::IMAP::TaggedResponse represents tagged responses. + +The server completion result response indicates the success or +failure of the operation. It is tagged with the same tag as the +client command which began the operation. + + response_tagged ::= tag SPACE resp_cond_state CRLF + + tag ::= 1* + + resp_cond_state ::= ("OK" / "NO" / "BAD") SPACE resp_text + +=== Super Class + +Struct + +=== Methods + +: tag + Returns the tag. + +: name + Returns the name. the name is one of "OK", "NO", "BAD". + +: data + Returns the data. See (()). + +: raw_data + Returns the raw data string. + +== Net::IMAP::ResponseText + +Net::IMAP::ResponseText represents texts of responses. +The text may be prefixed by the response code. + + resp_text ::= ["[" resp_text_code "]" SPACE] (text_mime2 / text) + ;; text SHOULD NOT begin with "[" or "=" + +=== Super Class + +Struct + +=== Methods + +: code + Returns the response code. See (()). + +: text + Returns the text. + +== Net::IMAP::ResponseCode + +Net::IMAP::ResponseCode represents response codes. + + resp_text_code ::= "ALERT" / "PARSE" / + "PERMANENTFLAGS" SPACE "(" #(flag / "\*") ")" / + "READ-ONLY" / "READ-WRITE" / "TRYCREATE" / + "UIDVALIDITY" SPACE nz_number / + "UNSEEN" SPACE nz_number / + atom [SPACE 1*] + +=== SuperClass + +Struct + +=== Methods + +: name + Returns the name such as "ALERT", "PERMANENTFLAGS", "UIDVALIDITY".... + +: data + Returns the data if it exists. + +== Net::IMAP::MailboxList + +Net::IMAP::MailboxList represents contents of the LIST response. + + mailbox_list ::= "(" #("\Marked" / "\Noinferiors" / + "\Noselect" / "\Unmarked" / flag_extension) ")" + SPACE (<"> QUOTED_CHAR <"> / nil) SPACE mailbox + +=== Super Class + +Struct + +=== Methods + +: attr + Returns the name attributes. Each name attribute is a symbol + capitalized by String#capitalize, such as :Noselect (not :NoSelect). + +: delim + Returns the hierarchy delimiter + +: name + Returns the mailbox name. + +== Net::IMAP::StatusData + +Net::IMAP::StatusData represents contents of the STATUS response. + +=== Super Class + +Object + +=== Methods + +: mailbox + Returns the mailbox name. + +: attr + Returns a hash. Each key is one of "MESSAGES", "RECENT", "UIDNEXT", + "UIDVALIDITY", "UNSEEN". Each value is a number. + +== Net::IMAP::FetchData + +Net::IMAP::FetchData represents contents of the FETCH response. + +=== Super Class + +Object + +=== Methods + +: seqno + Returns the message sequence number. + (Note: not the unique identifier, even for the UID command response.) + +: attr + Returns a hash. Each key is a data item name, and each value is + its value. + + The current data items are: + + : BODY + A form of BODYSTRUCTURE without extension data. + : BODY[
]<> + A string expressing the body contents of the specified section. + : BODYSTRUCTURE + An object that describes the ((<[MIME-IMB]>)) body structure of a message. + See (()), (()), + (()), (()). + : ENVELOPE + A (()) object that describes the envelope + structure of a message. + : FLAGS + A array of flag symbols that are set for this message. flag symbols + are capitalized by String#capitalize. + : INTERNALDATE + A string representing the internal date of the message. + : RFC822 + Equivalent to BODY[]. + : RFC822.HEADER + Equivalent to BODY.PEEK[HEADER]. + : RFC822.SIZE + A number expressing the ((<[RFC-822]>)) size of the message. + : RFC822.TEXT + Equivalent to BODY[TEXT]. + : UID + A number expressing the unique identifier of the message. + +== Net::IMAP::Envelope + +Net::IMAP::Envelope represents envelope structures of messages. + +=== Super Class + +Struct + +=== Methods + +: date + Retunns a string that represents the date. + +: subject + Retunns a string that represents the subject. + +: from + Retunns an array of (()) that represents the from. + +: sender + Retunns an array of (()) that represents the sender. + +: reply_to + Retunns an array of (()) that represents the reply-to. + +: to + Retunns an array of (()) that represents the to. + +: cc + Retunns an array of (()) that represents the cc. + +: bcc + Retunns an array of (()) that represents the bcc. + +: in_reply_to + Retunns a string that represents the in-reply-to. + +: message_id + Retunns a string that represents the message-id. + +== Net::IMAP::Address + +(()) represents electronic mail addresses. + +=== Super Class + +Struct + +=== Methods + +: name + Returns the phrase from ((<[RFC-822]>)) mailbox. + +: route + Returns the route from ((<[RFC-822]>)) route-addr. + +: mailbox + nil indicates end of ((<[RFC-822]>)) group. + If non-nil and host is nil, returns ((<[RFC-822]>)) group name. + Otherwise, returns ((<[RFC-822]>)) local-part + +: host + nil indicates ((<[RFC-822]>)) group syntax. + Otherwise, returns ((<[RFC-822]>)) domain name. + +== Net::IMAP::ContentDisposition + +Net::IMAP::ContentDisposition represents Content-Disposition fields. + +=== Super Class + +Struct + +=== Methods + +: dsp_type + Returns the disposition type. + +: param + Returns a hash that represents parameters of the Content-Disposition + field. + +== Net::IMAP::BodyTypeBasic + +Net::IMAP::BodyTypeBasic represents basic body structures of messages. + +=== Super Class + +Struct + +=== Methods + +: media_type + Returns the content media type name as defined in ((<[MIME-IMB]>)). + +: subtype + Returns the content subtype name as defined in ((<[MIME-IMB]>)). + +: param + Returns a hash that represents parameters as defined in + ((<[MIME-IMB]>)). + +: content_id + Returns a string giving the content id as defined in ((<[MIME-IMB]>)). + +: description + Returns a string giving the content description as defined in + ((<[MIME-IMB]>)). + +: encoding + Returns a string giving the content transfer encoding as defined in + ((<[MIME-IMB]>)). + +: size + Returns a number giving the size of the body in octets. + +: md5 + Returns a string giving the body MD5 value as defined in ((<[MD5]>)). + +: disposition + Returns a (()) object giving + the content disposition. + +: language + Returns a string or an array of strings giving the body + language value as defined in [LANGUAGE-TAGS]. + +: extension + Returns extension data. + +: multipart? + Returns false. + +== Net::IMAP::BodyTypeText + +Net::IMAP::BodyTypeText represents TEXT body structures of messages. + +=== Super Class + +Struct + +=== Methods + +: lines + Returns the size of the body in text lines. + +And Net::IMAP::BodyTypeText has all methods of (()). + +== Net::IMAP::BodyTypeMessage + +Net::IMAP::BodyTypeMessage represents MESSAGE/RFC822 body structures of messages. + +=== Super Class + +Struct + +=== Methods + +: envelope + Returns a (()) giving the envelope structure. + +: body + Returns an object giving the body structure. + +And Net::IMAP::BodyTypeMessage has all methods of (()). + +== Net::IMAP::BodyTypeText + +=== Super Class + +Struct + +=== Methods + +: media_type + Returns the content media type name as defined in ((<[MIME-IMB]>)). + +: subtype + Returns the content subtype name as defined in ((<[MIME-IMB]>)). + +: parts + Returns multiple parts. + +: param + Returns a hash that represents parameters as defined in + ((<[MIME-IMB]>)). + +: disposition + Returns a (()) object giving + the content disposition. + +: language + Returns a string or an array of strings giving the body + language value as defined in [LANGUAGE-TAGS]. + +: extension + Returns extension data. + +: multipart? + Returns true. + +== References + +: [IMAP] + M. Crispin, "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1", + RFC 2060, December 1996. + +: [LANGUAGE-TAGS] + Alvestrand, H., "Tags for the Identification of + Languages", RFC 1766, March 1995. + +: [MD5] + Myers, J., and M. Rose, "The Content-MD5 Header Field", RFC + 1864, October 1995. + +: [MIME-IMB] + Freed, N., and N. Borenstein, "MIME (Multipurpose Internet + Mail Extensions) Part One: Format of Internet Message Bodies", RFC + 2045, November 1996. + +: [RFC-822] + Crocker, D., "Standard for the Format of ARPA Internet Text + Messages", STD 11, RFC 822, University of Delaware, August 1982. + =end require "socket" @@ -702,7 +1145,7 @@ module Net Address = Struct.new(:name, :route, :mailbox, :host) ContentDisposition = Struct.new(:dsp_type, :param) - class BodyTypeBasic < Struct.new(:media_type, :media_subtype, + class BodyTypeBasic < Struct.new(:media_type, :subtype, :param, :content_id, :description, :encoding, :size, :md5, :disposition, :language, @@ -710,9 +1153,15 @@ module Net def multipart? return false end + + def media_subtype + $stderr.printf("warning: media_subtype is obsolete.\n") + $stderr.printf(" use subtype instead.\n") + return subtype + end end - class BodyTypeText < Struct.new(:media_type, :media_subtype, + class BodyTypeText < Struct.new(:media_type, :subtype, :param, :content_id, :description, :encoding, :size, :lines, @@ -721,9 +1170,15 @@ module Net def multipart? return false end + + def media_subtype + $stderr.printf("warning: media_subtype is obsolete.\n") + $stderr.printf(" use subtype instead.\n") + return subtype + end end - class BodyTypeMessage < Struct.new(:media_type, :media_subtype, + class BodyTypeMessage < Struct.new(:media_type, :subtype, :param, :content_id, :description, :encoding, :size, :envelope, :body, :lines, @@ -732,15 +1187,27 @@ module Net def multipart? return false end + + def media_subtype + $stderr.printf("warning: media_subtype is obsolete.\n") + $stderr.printf(" use subtype instead.\n") + return subtype + end end - class BodyTypeMultipart < Struct.new(:media_type, :media_subtype, + class BodyTypeMultipart < Struct.new(:media_type, :subtype, :parts, :param, :disposition, :language, :extension) def multipart? return true end + + def media_subtype + $stderr.printf("warning: media_subtype is obsolete.\n") + $stderr.printf(" use subtype instead.\n") + return subtype + end end class ResponseParser @@ -1475,6 +1942,12 @@ module Net when /\A(?:UIDVALIDITY|UIDNEXT|UNSEEN)\z/n match(T_SPACE) result = ResponseCode.new(name, number) + else + match(T_SPACE) + @lex_state = EXPR_CTEXT + token = match(T_TEXT) + @lex_state = EXPR_BEG + result = ResponseCode.new(name, token.value) end match(T_RBRA) @lex_state = EXPR_RTEXT @@ -1579,7 +2052,7 @@ module Net if @str.index(/\(([^)]*)\)/ni, @pos) @pos = $~.end(0) return $1.scan(FLAG_REGEXP).collect { |flag, atom| - atom || flag.intern + atom || flag.capitalize.intern } else parse_error("invalid flag list") diff --git a/lib/net/pop.rb b/lib/net/pop.rb index 4f6eb930a4..8f3f978e8c 100644 --- a/lib/net/pop.rb +++ b/lib/net/pop.rb @@ -1,6 +1,6 @@ =begin -= net/pop.rb version 1.1.32 += net/pop.rb version 1.1.34 written by Minero Aoki @@ -184,6 +184,7 @@ module Net protocol_param :port, '110' protocol_param :command_type, '::Net::NetPrivate::POP3Command' + protocol_param :apop_command_type, '::Net::NetPrivate::APOPCommand' protocol_param :mail_type, '::Net::POPMail' @@ -206,9 +207,10 @@ module Net end - def initialize( addr = nil, port = nil ) - super + def initialize( addr = nil, port = nil, apop = false ) + super addr, port @mails = nil + @apop = false end attr :mails @@ -238,6 +240,11 @@ module Net private + def conn_command( sock ) + @command = + (@apop ? type.apop_command_type : type.command_type).new(sock) + end + def do_start( acnt, pwd ) @command.auth( acnt, pwd ) diff --git a/lib/net/protocol.rb b/lib/net/protocol.rb index 161024cfe2..343721add3 100644 --- a/lib/net/protocol.rb +++ b/lib/net/protocol.rb @@ -1,6 +1,6 @@ =begin -= net/protocol.rb version 1.1.32 += net/protocol.rb version 1.1.34 written by Minero Aoki @@ -59,13 +59,22 @@ Object =end require 'socket' +require 'timeout' module Net + module NetPrivate + end + + def self.net_private( &block ) + ::Net::NetPrivate.module_eval( &block ) + end + + class Protocol - Version = '1.1.32' + Version = '1.1.34' class << self @@ -116,8 +125,12 @@ module Net @command = nil @socket = nil - @active = false - @pipe = nil + @active = false + + @open_timeout = nil + @read_timeout = nil + + @dout = nil end attr_reader :address @@ -126,10 +139,26 @@ module Net attr_reader :command attr_reader :socket + attr_accessor :open_timeout + attr_accessor :read_timeout + + def active? + @active + end + + def set_debug_output( arg ) # un-documented + @dout = arg + end + + alias set_pipe set_debug_output + def inspect "#<#{type} #{address}:#{port} open=#{active?}>" end + # + # open session + # def start( *args ) return false if active? @@ -146,45 +175,59 @@ module Net end end + private + def _start( args ) connect do_start( *args ) @active = true end - private :_start - - def finish - return false unless active? - do_finish unless @command.critical? - disconnect - @active = false - true + def connect + conn_socket @address, @port + conn_command @socket + on_connect end - def active? - @active + def re_connect + @socket.reopen @open_timeout + on_connect end - def set_pipe( arg ) # un-documented - @pipe = arg + def conn_socket( addr, port ) + @socket = type.socket_type.open( + addr, port, @open_timeout, @read_timeout, @dout ) end + def conn_command( sock ) + @command = type.command_type.new( sock ) + end - private - + def on_connect + end def do_start end - def do_finish - @command.quit + # + # close session + # + + public + + def finish + return false unless active? + + do_finish if @command and not @command.critical? + disconnect + @active = false + true end + private - def connect( addr = @address, port = @port ) - @socket = type.socket_type.open( addr, port, @pipe ) - @command = type.command_type.new( @socket ) + def do_finish + @command.quit end def disconnect @@ -192,7 +235,11 @@ module Net if @socket and not @socket.closed? then @socket.close end - @socket = nil + @socket = nil + on_disconnect + end + + def on_disconnect end end @@ -200,6 +247,7 @@ module Net Session = Protocol + net_private { class Response @@ -223,6 +271,8 @@ module Net end + } + class ProtocolError < StandardError; end class ProtoSyntaxError < ProtocolError; end @@ -294,8 +344,7 @@ module Net - module NetPrivate - + net_private { class WriteAdapter @@ -311,7 +360,11 @@ module Net def write( str ) @sock.__send__ @mid, str end - alias << write + + def <<( str ) + @sock.__send__ @mid, str + self + end end @@ -407,6 +460,7 @@ module Net @critical = false end + private def critical @@ -431,22 +485,30 @@ module Net class Socket - def initialize( addr, port, pipe = nil ) + def initialize( addr, port, otime = nil, rtime = nil, dout = nil ) @addr = addr @port = port - @pipe = pipe - @prepipe = nil - @closed = true - @ipaddr = '' + @read_timeout = rtime + + @debugout = dout + + @socket = nil @sending = '' @buffer = '' - @socket = TCPsocket.new( addr, port ) - @closed = false - @ipaddr = @socket.addr[3] + connect otime + D 'opened' end + def connect( otime ) + D "opening connection to #{@addr}..." + timeout( otime ) { + @socket = TCPsocket.new( @addr, @port ) + } + end + private :connect + attr :pipe, true class << self @@ -454,27 +516,31 @@ module Net end def inspect - "#<#{type} open=#{!@closed}>" + "#<#{type} #{closed? ? 'closed' : 'opened'}>" end - def reopen - unless closed? then - close - @buffer = '' - end - @socket = TCPsocket.new( @addr, @port ) - @closed = false + def reopen( otime = nil ) + D 'reopening...' + close + connect otime + D 'reopened' end attr :socket, true def close - @socket.close - @closed = true + if @socket then + @socket.close + D 'closed' + else + D 'close call for already closed socket' + end + @socket = nil + @buffer = '' end def closed? - @closed + not @socket end def address @@ -486,7 +552,8 @@ module Net attr_reader :port def ip_address - @ipaddr.dup + @socket or return '' + @socket.addr[3] end alias ipaddr ip_address @@ -494,57 +561,64 @@ module Net attr_reader :sending - ### - ### read - ### + # + # read + # + + public CRLF = "\r\n" - def read( len, dest = '' ) - @pipe << "reading #{len} bytes...\n" if @pipe; pipeoff + def read( len, dest = '', ignerr = false ) + D_off "reading #{len} bytes..." rsize = 0 - while rsize + @buffer.size < len do - rsize += writeinto( dest, @buffer.size ) - fill_rbuf + begin + while rsize + @buffer.size < len do + rsize += rbuf_moveto( dest, @buffer.size ) + rbuf_fill + end + rbuf_moveto dest, len - rsize + rescue EOFError + raise unless igneof end - writeinto( dest, len - rsize ) - @pipe << "read #{len} bytes\n" if pipeon + D_on "read #{len} bytes" dest end - def read_all( dest = '' ) - @pipe << "reading all...\n" if @pipe; pipeoff + D_off 'reading all...' rsize = 0 begin while true do - rsize += writeinto( dest, @buffer.size ) - fill_rbuf + rsize += rbuf_moveto( dest, @buffer.size ) + rbuf_fill end rescue EOFError ; end - @pipe << "read #{rsize} bytes\n" if pipeon + D_on "read #{rsize} bytes" dest end - - def readuntil( target ) - while true do - idx = @buffer.index( target ) - break if idx - fill_rbuf - end - + def readuntil( target, igneof = false ) dest = '' - writeinto( dest, idx + target.size ) + begin + while true do + idx = @buffer.index( target ) + break if idx + rbuf_fill + end + rbuf_moveto dest, idx + target.size + rescue EOFError + raise unless igneof + rbuf_moveto dest, @buffer.size + end dest end - def readline ret = readuntil( "\n" ) @@ -552,9 +626,8 @@ module Net ret end - def read_pendstr( dest ) - @pipe << "reading text...\n" if @pipe; pipeoff + D_off 'reading text...' rsize = 0 while (str = readuntil("\r\n")) != ".\r\n" do @@ -563,14 +636,13 @@ module Net dest << str end - @pipe << "read #{rsize} bytes\n" if pipeon + D_on "read #{rsize} bytes" dest end - # private use only (can not handle 'break') def read_pendlist - @pipe << "reading list...\n" if @pipe; pipeoff + D_off 'reading list...' str = nil i = 0 @@ -580,55 +652,59 @@ module Net yield str end - @pipe << "read #{i} items\n" if pipeon + D_on "read #{i} items" end private - READ_BLOCK = 1024 * 8 + READ_SIZE = 1024 * 4 - def fill_rbuf - @buffer << @socket.sysread( READ_BLOCK ) + def rbuf_fill + unless IO.select [@socket], nil, nil, @read_timeout then + on_read_timeout + end + @buffer << @socket.sysread( READ_SIZE ) end - def writeinto( dest, len ) + def on_read_timeout + raise TimeoutError, "socket read timeout (#{@read_timeout} sec)" + end + + def rbuf_moveto( dest, len ) bsi = @buffer.size - dest << @buffer[ 0, len ] + s = @buffer[ 0, len ] + dest << s @buffer = @buffer[ len, bsi - len ] - @pipe << %{read "#{Net.quote dest}"\n} if @pipe + @debugout << % if @debugout len end - ### - ### write - ### + # + # write interfece + # public - def write( str ) writing { do_write str } end - def writeline( str ) writing { - do_write str - do_write "\r\n" + do_write str + "\r\n" } end - def write_bin( src, block ) writing { if block then - block.call WriteAdapter.new( self, :do_write ) + block.call ::Net::NetPrivate::WriteAdapter.new( self, :do_write ) else src.each do |bin| do_write bin @@ -637,19 +713,18 @@ module Net } end - def write_pendstr( src, block ) - @pipe << "writing text from #{src.type}\n" if @pipe; pipeoff + D_off "writing text from #{src.type}" wsize = use_each_crlf_line { if block then - block.call WriteAdapter.new( self, :wpend_in ) + block.call ::Net::NetPrivate::WriteAdapter.new( self, :wpend_in ) else wpend_in src end } - @pipe << "wrote #{wsize} bytes text\n" if pipeon + D_on "wrote #{wsize} bytes text" wsize end @@ -696,17 +771,17 @@ module Net beg = 0 buf = @wbuf while buf.index( /\n|\r\n|\r/, beg ) do - m = $~ + m = Regexp.last_match if m.begin(0) == buf.size - 1 and buf[-1] == ?\r then # "...\r" : can follow "\n..." break end - str = buf[ beg, m.begin(0) - beg ] + str = buf[ beg ... m.begin(0) ] str.concat "\r\n" yield str beg = m.end(0) end - @wbuf = buf[ beg, buf.size - beg ] + @wbuf = buf[ beg ... buf.size ] end end @@ -736,6 +811,7 @@ module Net yield end end + yield unless @wbuf.empty? end end @@ -746,17 +822,17 @@ module Net yield - if @pipe then - @pipe << 'write "' - @pipe << @sending - @pipe << "\"\n" + if @debugout then + @debugout << 'write "' + @debugout << @sending + @debugout << "\"\n" end @socket.flush @writtensize end def do_write( arg ) - if @pipe or @sending.size < 128 then + if @debugout or @sending.size < 128 then @sending << Net.quote( arg ) else @sending << '...' unless @sending[-1] == ?. @@ -768,22 +844,25 @@ module Net end - def pipeoff - @prepipe = @pipe - @pipe = nil - @prepipe + def D_off( msg ) + D msg + @savedo, @debugout = @debugout, nil end - def pipeon - @pipe = @prepipe - @prepipe = nil - @pipe + def D_on( msg ) + @debugout = @savedo + D msg end - end + def D( msg ) + @debugout or return + @debugout << msg + @debugout << "\n" + end + end - end # module Net::NetPrivate + } def Net.quote( str ) diff --git a/lib/net/smtp.rb b/lib/net/smtp.rb index 9679984e2c..befc1adf03 100644 --- a/lib/net/smtp.rb +++ b/lib/net/smtp.rb @@ -1,6 +1,6 @@ =begin -= net/smtp.rb version 1.1.32 += net/smtp.rb version 1.1.34 written by Minero Aoki @@ -30,10 +30,8 @@ Net::Protocol === Methods -: start( helo_domain = Socket.gethostname, \ - account = nil, password = nil, authtype = nil ) -: start( helo_domain = Socket.gethostname, \ - account = nil, password = nil, authtype = nil ) {|smtp| .... } +: start( helo_domain = Socket.gethostname, account = nil, password = nil, authtype = nil ) +: start( helo_domain = Socket.gethostname, account = nil, password = nil, authtype = nil ) {|smtp| .... } opens TCP connection and starts SMTP session. If protocol had been started, do nothing and return false. @@ -53,10 +51,10 @@ Net::Protocol to_addrs must be a String(s) or an Array of String. Exceptions which SMTP raises are: - * Net::ProtoSyntaxError: syntax error (errno.500) - * Net::ProtoFatalError: fatal error (errno.550) - * Net::ProtoUnknownError: unknown error - * Net::ProtoServerBusy: temporary error (errno.420/450) + * Net::ProtoSyntaxError: syntax error (errno.500) + * Net::ProtoFatalError: fatal error (errno.550) + * Net::ProtoUnknownError: unknown error + * Net::ProtoServerBusy: temporary error (errno.420/450) # usage example @@ -153,12 +151,15 @@ module Net end end - if user and secret then + if user or secret then + (user and secret) or + raise ArgumentError, 'both of account and password are required' + mid = 'auth_' + (authtype || 'cram_md5').to_s - unless @command.respond_to? mid then - raise ArgumentError, "wrong auth type #{authtype.to_s}" - end - @command.send mid, user, secret + @command.respond_to? mid or + raise ArgumentError, "wrong auth type #{authtype.to_s}" + + @command.__send__ mid, user, secret end end diff --git a/lib/net/telnet.rb b/lib/net/telnet.rb index 87790c0300..380e834bea 100644 --- a/lib/net/telnet.rb +++ b/lib/net/telnet.rb @@ -4,7 +4,7 @@ net/telnet.rb - simple telnet client library -Version 1.6.2 +Version 1.6.3 Wakou Aoyama @@ -239,10 +239,11 @@ module Net CR = "\015" LF = "\012" EOL = CR + LF - VERSION = "1.6.2" - RELEASE_DATE = "2000-12-25" - VERSION_CODE = 162 - RELEASE_CODE = 20001225 + VERSION = '1.6.3' + RELEASE_DATE = '2001-02-26' + VERSION_CODE = 163 + RELEASE_CODE = 20010226 + REVISION = '$Id$' def initialize(options) @options = options @@ -346,14 +347,13 @@ module Net attr :sock def telnetmode(mode = nil) - if mode - if (true == mode or false == mode) - @options["Telnetmode"] = mode - else - raise ArgumentError, "required true or false" - end - else + case mode + when nil @options["Telnetmode"] + when true, false + @options["Telnetmode"] = mode + else + raise ArgumentError, "required true or false" end end @@ -366,14 +366,13 @@ module Net end def binmode(mode = nil) - if mode - if (true == mode or false == mode) - @options["Binmode"] = mode - else - raise ArgumentError, "required true or false" - end - else + case mode + when nil @options["Binmode"] + when true, false + @options["Binmode"] = mode + else + raise ArgumentError, "required true or false" end end @@ -599,181 +598,7 @@ end == HISTORY -* Mon Dec 25 01:37:43 JST 2000 - wakou - * version 1.6.2 - * Regexp::last_match[1] --> $1 - -* Mon Dec 11 00:16:51 JST 2000 - wakou - * version 1.6.1 - * $1 --> Regexp::last_match[1] - -* 2000/09/12 05:37:35 - matz - * change: iterator? --> block_given? - -* Tue Sep 12 06:52:48 JST 2000 - wakou - * version 1.6.0 - * correct: document. - thanks to Kazuhiro NISHIYAMA - * add: Telnet#puts(). - -* Sun Jun 18 23:31:44 JST 2000 - wakou - * version 1.5.0 - * change: version syntax. old: x.yz, now: x.y.z - -* 2000/05/24 06:57:38 - wakou - * version 1.40 - * improve: binmode(), telnetmode() interface. - thanks to Dave Thomas - -* 2000/05/09 22:02:56 - wakou - * version 1.32 - * require English.rb - -* 2000/05/02 21:48:39 - wakou - * version 1.31 - * Proxy option: can receive IO object. - -* 2000/04/03 18:27:02 - wakou - * version 1.30 - * telnet.rb --> net/telnet.rb - -* 2000/01/24 17:02:57 - wakou - * version 1.20 - * respond to "IAC WILL x" with "IAC DONT x" - * respond to "IAC WONT x" with "IAC DONT x" - * better dumplog format. - thanks to WATANABE Hirofumi - -* 2000/01/18 17:47:31 - wakou - * version 1.10 - * bug fix: write method - * respond to "IAC WILL BINARY" with "IAC DO BINARY" - -* 1999/10/04 22:51:26 - wakou - * version 1.00 - * bug fix: waitfor(preprocess) method. - thanks to Shin-ichiro Hara - * add simple support for AO, DM, IP, NOP, SB, SE - * COUTION! TimeOut --> TimeoutError - -* 1999/09/21 21:24:07 - wakou - * version 0.50 - * add write method - -* 1999/09/17 17:41:41 - wakou - * version 0.40 - * bug fix: preprocess method - -* 1999/09/14 23:09:05 - wakou - * version 0.30 - * change prompt check order. - not IO::select([@sock], nil, nil, waittime) and prompt === line - --> prompt === line and not IO::select([@sock], nil, nil, waittime) - -* 1999/09/13 22:28:33 - wakou - * version 0.24 - * Telnet#login: if ommit password, then not require password prompt. - -* 1999/08/10 05:20:21 - wakou - * version 0.232 - * STATUS OUTPUT sample code typo. - thanks to Tadayoshi Funaba - host = Telnet.new({"Hosh" => "localhost"){|c| print c } - --> host = Telnet.new({"Host" => "localhost"){|c| print c } - -* 1999/07/16 13:39:42 - wakou - * version 0.231 - * TRUE --> true, FALSE --> false - -* 1999/07/15 22:32:09 - wakou - * version 0.23 - * waitfor: if end of file reached, then return nil. - -* 1999/06/29 09:08:51 - wakou - * version 0.22 - * new, waitfor, cmd: {"Timeout" => false} # ignore timeout - -* 1999/06/28 18:18:55 - wakou - * version 0.21 - * waitfor: not rescue (EOFError) - -* 1999/06/04 06:24:58 - wakou - * version 0.20 - * waitfor: support for divided telnet command - -* 1999/05/22 - wakou - * version 0.181 - * bug fix: print method - -* 1999/05/14 - wakou - * version 0.18 - * respond to "IAC WON'T SGA" with "IAC DON'T SGA" - * DON'T SGA : end of line --> CR + LF - * bug fix: preprocess method - -* 1999/04/30 - wakou - * version 0.17 - * bug fix: $! + "\n" --> $!.to_s + "\n" - -* 1999/04/11 - wakou - * version 0.163 - * STDOUT.write(message) --> yield(message) if iterator? - -* 1999/03/17 - wakou - * version 0.162 - * add "Proxy" option - * required timeout.rb - -* 1999/02/03 - wakou - * version 0.161 - * select --> IO::select - -* 1998/10/09 - wakou - * version 0.16 - * preprocess method change for the better - * add binmode method. - * change default Binmode. TRUE --> FALSE - -* 1998/10/04 - wakou - * version 0.15 - * add telnetmode method. - -* 1998/09/22 - wakou - * version 0.141 - * change default prompt. /[$%#>] $/ --> /[$%#>] \Z/ - -* 1998/09/01 - wakou - * version 0.14 - * IAC WILL SGA send EOL --> CR+NULL - * IAC WILL SGA IAC DO BIN send EOL --> CR - * NONE send EOL --> LF - * add Dump_log option. - -* 1998/08/25 - wakou - * version 0.13 - * add print method. - -* 1998/08/05 - wakou - * version 0.122 - * support for HP-UX 10.20. - thanks to WATANABE Tetsuya - * socket.<< --> socket.write - -* 1998/07/15 - wakou - * version 0.121 - * string.+= --> string.concat - -* 1998/06/01 - wakou - * version 0.12 - * add timeout, waittime. - -* 1998/04/21 - wakou - * version 0.11 - * add realtime output. - -* 1998/04/13 - wakou - * version 0.10 - * first release. - -$Date$ +delete. see cvs log. + + =end diff --git a/lib/observer.rb b/lib/observer.rb index 08e75f5125..e1b249e885 100644 --- a/lib/observer.rb +++ b/lib/observer.rb @@ -5,7 +5,7 @@ module Observable def add_observer(observer) @observer_peers = [] unless defined? @observer_peers - unless defined? observer.update + unless observer.respond_to? :update raise NameError, "observer needs to respond to `update'" end @observer_peers.push observer diff --git a/lib/parsedate.rb b/lib/parsedate.rb index eee114acb2..7fc75cf0c2 100644 --- a/lib/parsedate.rb +++ b/lib/parsedate.rb @@ -1,5 +1,5 @@ -# parsedate.rb: Written by Tadayoshi Funaba 2000 -# $Id: parsedate.rb,v 1.2 2000-04-01 12:16:56+09 tadf Exp $ +# parsedate3.rb: Written by Tadayoshi Funaba 2000, 2001 +# $Id: parsedate3.rb,v 1.3 2001-01-18 12:09:47+09 tadf Exp $ module ParseDate @@ -46,7 +46,12 @@ module ParseDate hour = $1.to_i min = $2.to_i sec = $3.to_i if $3 - hour += 12 if $4 and $4.downcase == 'p' + if $4 + hour %= 12 + if $4.downcase == 'p' + hour += 12 + end + end zone = $5 end diff --git a/lib/ping.rb b/lib/ping.rb index 48657818cc..d698dd0c52 100644 --- a/lib/ping.rb +++ b/lib/ping.rb @@ -47,6 +47,8 @@ module Ping s = TCPsocket.new(host, service) s.close end + rescue Errno::ECONNREFUSED + return true rescue return false end diff --git a/lib/thread.rb b/lib/thread.rb index d4b6ad6ec1..559cd95a8a 100644 --- a/lib/thread.rb +++ b/lib/thread.rb @@ -185,7 +185,7 @@ class Queue end end def shift(non_block=false) - pop(non_block=false) + pop(non_block) end alias deq shift diff --git a/marshal.c b/marshal.c index cf84e5ed24..1f0efa8843 100644 --- a/marshal.c +++ b/marshal.c @@ -14,7 +14,7 @@ #include "rubyio.h" #include "st.h" -#ifndef atof +#if !defined(atof) && !defined(HAVE_STDLIB_H) double strtod(); #endif @@ -46,7 +46,7 @@ shortlen(len, ds) num = SHORTDN(num); offset++; } - return len*sizeof(BDIGIT)/sizeof(short) - offset; + return (len - 1)*sizeof(BDIGIT)/sizeof(short) + offset; } #define SHORTLEN(x) shortlen((x),d) #endif @@ -378,7 +378,7 @@ w_object(obj, arg, limit) for (i=0; isign = (r_byte(arg) == '+'); len = r_long(arg); +#if SIZEOF_BDIGITS == SIZEOF_SHORT + big->len = len; +#else big->len = (len + 1) * sizeof(short) / sizeof(BDIGIT); +#endif big->digits = digits = ALLOC_N(BDIGIT, big->len); while (len > 0) { #if SIZEOF_BDIGITS > SIZEOF_SHORT @@ -1055,7 +1059,7 @@ marshal_load(argc, argv) \tformat version %d.%d required; %d.%d given", MARSHAL_MAJOR, MARSHAL_MINOR, major, minor); } - if (minor != MARSHAL_MINOR) { + if (ruby_verbose && minor != MARSHAL_MINOR) { rb_warn("incompatible marshal file format (can be read)\n\ \tformat version %d.%d required; %d.%d given", MARSHAL_MAJOR, MARSHAL_MINOR, major, minor); diff --git a/math.c b/math.c index ac87b9c8dc..2cac83e938 100644 --- a/math.c +++ b/math.c @@ -64,6 +64,11 @@ math_exp(obj, x) return rb_float_new(exp(RFLOAT(x)->value)); } +#if defined __CYGWIN__ +#define log(x) ((x) < 0.0 ? nan() : log(x)) +#define log10(x) ((x) < 0.0 ? nan() : log10(x)) +#endif + static VALUE math_log(obj, x) VALUE obj, x; diff --git a/misc/ruby-mode.el b/misc/ruby-mode.el index c0754efad4..7dd4708176 100644 --- a/misc/ruby-mode.el +++ b/misc/ruby-mode.el @@ -749,7 +749,7 @@ An end of a defun is found by moving forward from the beginning of one." '("^\\s *def\\s +\\([^( ]+\\)" 1 font-lock-function-name-face) ;; symbols - '("\\(^\\|[^:]\\)\\(:\\(\\w\\|_\\)+\\??\\)\\b" + '("\\(^\\|[^:]\\)\\(:\\([-+/%&|^~`]\\|\\*\\*?\\|<\\(<\\|=>?\\)?\\|>[>=]?\\|===?\\|=~\\|\\[\\]\\|\\(\\w\\|_\\)+\\([!?=]\\|\\b\\)\\)\\)" 2 font-lock-reference-face)) "*Additional expressions to highlight in ruby mode.")) diff --git a/missing/dir.h b/missing/dir.h index 830239b3ea..4fe0e120d5 100644 --- a/missing/dir.h +++ b/missing/dir.h @@ -28,7 +28,9 @@ #ifndef __DIR_INCLUDED #define __DIR_INCLUDED -#if !defined __MINGW32__ +#if defined __MINGW32__ +#define cdecl +#endif /*Directory entry size */ #ifdef DIRSIZ #undef DIRSIZ @@ -61,5 +63,4 @@ void seekdir(DIR *dirp,long loc); void rewinddir(DIR *dirp); void closedir(DIR *dirp); -#endif #endif /* __DIR_INCLUDED */ diff --git a/missing/flock.c b/missing/flock.c index 78576d438c..c828fcc7ad 100644 --- a/missing/flock.c +++ b/missing/flock.c @@ -1,6 +1,55 @@ #include "config.h" -#if defined(HAVE_LOCKF) +#if defined HAVE_FCNTL && defined HAVE_FCNTL_H + +/* These are the flock() constants. Since this sytems doesn't have + flock(), the values of the constants are probably not available. +*/ +# ifndef LOCK_SH +# define LOCK_SH 1 +# endif +# ifndef LOCK_EX +# define LOCK_EX 2 +# endif +# ifndef LOCK_NB +# define LOCK_NB 4 +# endif +# ifndef LOCK_UN +# define LOCK_UN 8 +# endif + +#include +#include +#include + +int +flock(fd, operation) + int fd; + int operation; +{ + struct flock lock; + + switch (operation & ~LOCK_NB) { + case LOCK_SH: + lock.l_type = F_RDLCK; + break; + case LOCK_EX: + lock.l_type = F_WRLCK; + break; + case LOCK_UN: + lock.l_type = F_UNLCK; + break; + default: + errno = EINVAL; + return -1; + } + lock.l_whence = SEEK_SET; + lock.l_start = lock.l_len = 0L; + + return fcntl(fd, (operation & LOCK_NB) ? F_SETLK : F_SETLKW, &lock); +} + +#elif defined(HAVE_LOCKF) #include #include @@ -45,86 +94,33 @@ flock(fd, operation) int fd; int operation; { - int i; switch (operation) { /* LOCK_SH - get a shared lock */ case LOCK_SH: + rb_notimplement(); + return -1; /* LOCK_EX - get an exclusive lock */ case LOCK_EX: - i = lockf (fd, F_LOCK, 0); - break; + return lockf (fd, F_LOCK, 0); /* LOCK_SH|LOCK_NB - get a non-blocking shared lock */ case LOCK_SH|LOCK_NB: + rb_notimplement(); + return -1; /* LOCK_EX|LOCK_NB - get a non-blocking exclusive lock */ case LOCK_EX|LOCK_NB: - i = lockf (fd, F_TLOCK, 0); - if (i == -1) - if ((errno == EAGAIN) || (errno == EACCES)) - errno = EWOULDBLOCK; - break; + return lockf (fd, F_TLOCK, 0); /* LOCK_UN - unlock */ case LOCK_UN: - i = lockf (fd, F_ULOCK, 0); - break; + return lockf (fd, F_ULOCK, 0); /* Default - can't decipher operation */ default: - i = -1; errno = EINVAL; - break; + return -1; } - return i; -} -#elif defined HAVE_FCNTL && defined HAVE_FCNTL_H - -/* These are the flock() constants. Since this sytems doesn't have - flock(), the values of the constants are probably not available. -*/ -# ifndef LOCK_SH -# define LOCK_SH 1 -# endif -# ifndef LOCK_EX -# define LOCK_EX 2 -# endif -# ifndef LOCK_NB -# define LOCK_NB 4 -# endif -# ifndef LOCK_UN -# define LOCK_UN 8 -# endif - -#include -#include -#include - -int -flock(fd, operation) - int fd; - int operation; -{ - struct flock lock; - - switch (operation & ~LOCK_NB) { - case LOCK_SH: - lock.l_type = F_RDLCK; - break; - case LOCK_EX: - lock.l_type = F_WRLCK; - break; - case LOCK_UN: - lock.l_type = F_UNLCK; - break; - default: - errno = EINVAL; - return -1; - } - lock.l_whence = SEEK_SET; - lock.l_start = lock.l_len = 0L; - - return fcntl(fd, (operation & LOCK_NB) ? F_SETLK : F_SETLKW, &lock); } #elif !defined NT int diff --git a/missing/strftime.c b/missing/strftime.c index 6bce490249..3042649aeb 100644 --- a/missing/strftime.c +++ b/missing/strftime.c @@ -113,12 +113,6 @@ extern char *getenv(); extern char *strchr(); #endif -#ifdef __GNUC__ -#define inline __inline__ -#else -#define inline /**/ -#endif - #define range(low, item, hi) max(low, min(item, hi)) #if !defined(OS2) && !defined(MSDOS) && defined(HAVE_TZNAME) diff --git a/missing/vsnprintf.c b/missing/vsnprintf.c index d297209d06..489bf58361 100644 --- a/missing/vsnprintf.c +++ b/missing/vsnprintf.c @@ -108,9 +108,7 @@ #define __const #endif /* People who don't like const sys_error */ -#if defined NT && !defined __MINGW32__ -typedef long size_t; -#endif +#include #ifndef NULL #define NULL 0 @@ -1095,8 +1093,6 @@ vsnprintf(str, n, fmt, ap) static char sccsid[] = "@(#)snprintf.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ -#include - #if defined(__STDC__) # include #else diff --git a/mkconfig.rb b/mkconfig.rb index 175a4c3b15..c190861b5e 100644 --- a/mkconfig.rb +++ b/mkconfig.rb @@ -28,11 +28,11 @@ has_srcdir = false has_version = false File.foreach "config.status" do |$_| next if /^#/ - if /^s%@program_transform_name@%s,(.*)%g$/ + if /^s[%,]@program_transform_name@[%,]s,(.*)[%,]/ next if $install_name ptn = $1.sub(/\$\$/, '$').split(/,/) #' v_fast << " CONFIG[\"ruby_install_name\"] = \"" + "ruby".sub(ptn[0],ptn[1]) + "\"\n" - elsif /^s%@(\w+)@%(.*)%g/ + elsif /^s[%,]@(\w+)@[%,](.*)[%,]/ name = $1 val = $2 || "" next if name =~ /^(INSTALL|DEFS|configure_input|srcdir|top_srcdir)$/ @@ -48,19 +48,6 @@ File.foreach "config.status" do |$_| v_others << v end has_version = true if name == "MAJOR" - if /DEFS/ - val.split(/\s*-D/).each do |i| - if i =~ /(.*)=(\\")?([^\\]*)(\\")?/ - key, val = $1, $3 - if val == '1' - val = "TRUE" - else - val.sub! /^\s*(.*)\s*$/, '"\1"' - end - print " CONFIG[\"#{key}\"] = #{val}\n" - end - end - end elsif /^ac_given_srcdir=(.*)/ v_fast << " CONFIG[\"srcdir\"] = \"" + File.expand_path($1) + "\"\n" has_srcdir = true diff --git a/node.h b/node.h index 1904a0a072..4788f8bc95 100644 --- a/node.h +++ b/node.h @@ -21,6 +21,7 @@ enum node_type { NODE_METHOD, NODE_FBODY, NODE_CFUNC, + NODE_IFUNC, NODE_SCOPE, NODE_BLOCK, NODE_IF, @@ -234,8 +235,9 @@ typedef struct RNode { #define NEW_DEFN(i,a,d,p) rb_node_newnode(NODE_DEFN,p,i,NEW_RFUNC(a,d)) #define NEW_DEFS(r,i,a,d) rb_node_newnode(NODE_DEFS,r,i,NEW_RFUNC(a,d)) #define NEW_CFUNC(f,c) rb_node_newnode(NODE_CFUNC,f,c,0) +#define NEW_IFUNC(f,c) rb_node_newnode(NODE_IFUNC,f,c,0) #define NEW_RFUNC(b1,b2) NEW_SCOPE(block_append(b1,b2)) -#define NEW_SCOPE(b) rb_node_newnode(NODE_SCOPE,local_tbl(),cur_cref,(b)) +#define NEW_SCOPE(b) rb_node_newnode(NODE_SCOPE,local_tbl(),0,(b)) #define NEW_BLOCK(a) rb_node_newnode(NODE_BLOCK,a,0,0) #define NEW_IF(c,t,e) rb_node_newnode(NODE_IF,c,t,e) #define NEW_UNLESS(c,t,e) NEW_IF(c,e,t) @@ -307,14 +309,12 @@ typedef struct RNode { #define NEW_ALIAS(n,o) rb_node_newnode(NODE_ALIAS,o,n,0) #define NEW_VALIAS(n,o) rb_node_newnode(NODE_VALIAS,o,n,0) #define NEW_UNDEF(i) rb_node_newnode(NODE_UNDEF,0,i,0) -#define NEW_CLASS(n,b,s) rb_node_newnode(NODE_CLASS,n,NEW_CBODY(b),(s)) -#define NEW_SCLASS(r,b) rb_node_newnode(NODE_SCLASS,r,NEW_CBODY(b),0) -#define NEW_MODULE(n,b) rb_node_newnode(NODE_MODULE,n,NEW_CBODY(b),0) +#define NEW_CLASS(n,b,s) rb_node_newnode(NODE_CLASS,n,NEW_SCOPE(b),(s)) +#define NEW_SCLASS(r,b) rb_node_newnode(NODE_SCLASS,r,NEW_SCOPE(b),0) +#define NEW_MODULE(n,b) rb_node_newnode(NODE_MODULE,n,NEW_SCOPE(b),0) #define NEW_COLON2(c,i) rb_node_newnode(NODE_COLON2,c,i,0) #define NEW_COLON3(i) rb_node_newnode(NODE_COLON3,0,i,0) -#define NEW_CREF0() (cur_cref=RNODE(ruby_frame->cbase)) -#define NEW_CREF() (cur_cref=rb_node_newnode(NODE_CREF,0,0,cur_cref)) -#define NEW_CBODY(b) (cur_cref->nd_body=NEW_SCOPE(b),cur_cref) +#define NEW_CREF(c) (rb_node_newnode(NODE_CREF,0,0,c)) #define NEW_DOT2(b,e) rb_node_newnode(NODE_DOT2,b,e,0) #define NEW_DOT3(b,e) rb_node_newnode(NODE_DOT3,b,e,0) #define NEW_ATTRSET(a) rb_node_newnode(NODE_ATTRSET,a,0,0) diff --git a/numeric.c b/numeric.c index 0dd86f0532..b5cd479a57 100644 --- a/numeric.c +++ b/numeric.c @@ -332,7 +332,7 @@ flodivmod(x, y, divp, modp) double z; modf(x/y, &z); - mod = x - z * x; + mod = x - z * y; } #endif div = (x - mod) / y; diff --git a/object.c b/object.c index 4e3d5dd856..9f3c033a76 100644 --- a/object.c +++ b/object.c @@ -162,6 +162,7 @@ inspect_i(id, value, str) if (!rb_is_instance_id(id)) return ST_CONTINUE; if (RSTRING(str)->ptr[0] == '-') { /* first element */ RSTRING(str)->ptr[0] = '#'; + rb_str_cat2(str, " "); } else { rb_str_cat2(str, ", "); @@ -182,6 +183,7 @@ inspect_obj(obj, str) { st_foreach(ROBJECT(obj)->iv_tbl, inspect_i, str); rb_str_cat2(str, ">"); + RSTRING(str)->ptr[0] = '#'; OBJ_INFECT(str, obj); return str; @@ -227,12 +229,10 @@ rb_obj_is_instance_of(obj, c) return Qfalse; case T_FALSE: - if (obj) return Qfalse; - return Qtrue; + return RTEST(obj) ? Qfalse : Qtrue; case T_TRUE: - if (obj) return Qtrue; - return Qfalse; + return RTEST(obj) ? Qtrue : Qfalse; default: rb_raise(rb_eTypeError, "class or module required"); @@ -286,6 +286,9 @@ rb_obj_taint(obj) VALUE obj; { rb_secure(4); + if (OBJ_FROZEN(obj)) { + rb_error_frozen("object"); + } OBJ_TAINT(obj); return obj; } @@ -513,33 +516,6 @@ sym_to_s(sym) return rb_str_new2(rb_id2name(SYM2ID(sym))); } -static VALUE -rb_mod_clone(module) - VALUE module; -{ - NEWOBJ(clone, struct RClass); - CLONESETUP(clone, module); - - clone->super = RCLASS(module)->super; - if (RCLASS(module)->iv_tbl) { - clone->iv_tbl = st_copy(RCLASS(module)->iv_tbl); - } - if (RCLASS(module)->m_tbl) { - clone->m_tbl = st_copy(RCLASS(module)->m_tbl); - } - - return (VALUE)clone; -} - -static VALUE -rb_mod_dup(module) - VALUE module; -{ - VALUE dup = rb_mod_clone(module); - OBJSETUP(dup, RBASIC(module)->klass, BUILTIN_TYPE(module)); - return dup; -} - static VALUE rb_mod_to_s(klass) VALUE klass; @@ -1036,6 +1012,9 @@ rb_str2cstr(str, len) str = rb_str_to_str(str); } if (len) *len = RSTRING(str)->len; + else if (ruby_verbose && RSTRING(str)->len != strlen(RSTRING(str)->ptr)) { + rb_warn("string contains \\0 character"); + } return RSTRING(str)->ptr; } diff --git a/pack.c b/pack.c index 5538600449..9e05f46c5a 100644 --- a/pack.c +++ b/pack.c @@ -826,7 +826,7 @@ pack_pack(ary, fmt) case 'm': ptr = rb_str2cstr(NEXTFROM, &plen); - if (len <= 1) + if (len <= 2) len = 45; else len = len / 3 * 3; @@ -1026,11 +1026,7 @@ qpencode(str, from, len) } } -#if defined(__GNUC__) && __GNUC__ >= 2 && !defined(RUBY_NO_INLINE) -static __inline__ int -#else -static int -#endif +static inline int hex2num(c) char c; { diff --git a/parse.y b/parse.y index d1f1a32321..bf611f7479 100644 --- a/parse.y +++ b/parse.y @@ -6,7 +6,7 @@ $Date$ created at: Fri May 28 18:02:42 JST 1993 - Copyright (C) 1993-2000 Yukihiro Matsumoto + Copyright (C) 1993-2001 Yukihiro Matsumoto **********************************************************************/ @@ -49,7 +49,6 @@ static int yyerror(); static enum lex_state { EXPR_BEG, /* ignore newline, +/- is a sign. */ EXPR_END, /* newline significant, +/- is a operator. */ - EXPR_PAREN, /* almost like EXPR_END, `do' works as `{'. */ EXPR_ARG, /* newline significant, +/- is a operator. */ EXPR_MID, /* newline significant, +/- is a operator. */ EXPR_FNAME, /* ignore newline, no reserved words. */ @@ -57,8 +56,16 @@ static enum lex_state { EXPR_CLASS, /* immediate after `class', no here document. */ } lex_state; +#if SIZEOF_LONG_LONG > 0 +typedef unsigned long long stack_type; +#elif SIZEOF___INT64 > 0 +typedef unsigned __int64 stack_type; +#else +typedef unsigned long stack_type; +#endif + static int cond_nest = 0; -static unsigned long cond_stack = 0; +static stack_type cond_stack = 0; #define COND_PUSH do {\ cond_nest++;\ cond_stack = (cond_stack<<1)|1;\ @@ -67,10 +74,20 @@ static unsigned long cond_stack = 0; cond_nest--;\ cond_stack >>= 1;\ } while (0) -#define IN_COND (cond_nest > 0 && (cond_stack&1)) +#define COND_P() (cond_nest > 0 && (cond_stack&1)) + +static stack_type cmdarg_stack = 0; +#define CMDARG_PUSH do {\ + cmdarg_stack = (cmdarg_stack<<1)|1;\ +} while(0) +#define CMDARG_POP do {\ + cmdarg_stack >>= 1;\ +} while (0) +#define CMDARG_P() (cmdarg_stack && (cmdarg_stack&1)) static int class_nest = 0; static int in_single = 0; +static int in_def = 0; static int compile_for_eval = 0; static ID cur_mid = 0; @@ -115,10 +132,6 @@ static struct RVarmap *dyna_push(); static void dyna_pop(); static int dyna_in_block(); -#define cref_push() NEW_CREF() -static void cref_pop(); -static NODE *cur_cref; - static void top_local_init(); static void top_local_setup(); %} @@ -155,7 +168,8 @@ static void top_local_setup(); kRETRY kIN kDO - kDO2 + kDO_COND + kDO_BLOCK kRETURN kYIELD kSUPER @@ -184,11 +198,11 @@ static void top_local_setup(); %type singleton string %type literal numeric -%type compstmt stmts stmt expr arg primary command_call method_call +%type compstmt stmts stmt expr arg primary command command_call method_call %type if_tail opt_else case_body cases rescue exc_list exc_var ensure -%type opt_call_args call_args ret_args args when_args -%type aref_args opt_block_arg block_arg stmt_rhs -%type mrhs mrhs_basic superclass generic_call block_call var_ref +%type args ret_args when_args call_args paren_args opt_paren_args +%type command_args aref_args opt_block_arg block_arg var_ref +%type mrhs mrhs_basic superclass block_call block_command %type f_arglist f_args f_optarg f_opt f_block_arg opt_f_block_arg %type assoc_list assocs assoc undef_list backref %type block_var opt_block_var brace_block do_block lhs none @@ -251,7 +265,6 @@ program : { $$ = ruby_dyna_vars; lex_state = EXPR_BEG; top_local_init(); - NEW_CREF0(); /* initialize constant c-ref */ if ((VALUE)ruby_class == rb_cObject) class_nest = 0; else class_nest = 1; } @@ -270,7 +283,6 @@ program : { } ruby_eval_tree = block_append(ruby_eval_tree, $2); top_local_setup(); - cur_cref = 0; class_nest = 0; ruby_dyna_vars = $1; } @@ -295,16 +307,15 @@ stmts : none $$ = $2; } -stmt : block_call - | kALIAS fitem {lex_state = EXPR_FNAME;} fitem +stmt : kALIAS fitem {lex_state = EXPR_FNAME;} fitem { - if (cur_mid || in_single) + if (in_def || in_single) yyerror("alias within method"); $$ = NEW_ALIAS($2, $4); } | kALIAS tGVAR tGVAR { - if (cur_mid || in_single) + if (in_def || in_single) yyerror("alias within method"); $$ = NEW_VALIAS($2, $3); } @@ -312,7 +323,7 @@ stmt : block_call { char buf[3]; - if (cur_mid || in_single) + if (in_def || in_single) yyerror("alias within method"); sprintf(buf, "$%c", $3->nd_nth); $$ = NEW_VALIAS($2, rb_intern(buf)); @@ -324,7 +335,7 @@ stmt : block_call } | kUNDEF undef_list { - if (cur_mid || in_single) + if (in_def || in_single) yyerror("undef within method"); $$ = $2; } @@ -343,31 +354,21 @@ stmt : block_call | stmt kWHILE_MOD expr { value_expr($3); - if ($1) { - if (nd_type($1) == NODE_BEGIN) { - $$ = NEW_WHILE(cond($3), $1->nd_body, 0); - } - else { - $$ = NEW_WHILE(cond($3), $1, 1); - } + if ($1 && nd_type($1) == NODE_BEGIN) { + $$ = NEW_WHILE(cond($3), $1->nd_body, 0); } else { - $$ = 0; + $$ = NEW_WHILE(cond($3), $1, 1); } } | stmt kUNTIL_MOD expr { value_expr($3); - if ($1) { - if (nd_type($1) == NODE_BEGIN) { - $$ = NEW_UNTIL(cond($3), $1->nd_body, 0); - } - else { - $$ = NEW_UNTIL(cond($3), $1, 1); - } + if ($1 && nd_type($1) == NODE_BEGIN) { + $$ = NEW_UNTIL(cond($3), $1->nd_body, 0); } else { - $$ = 0; + $$ = NEW_UNTIL(cond($3), $1, 1); } } | stmt kRESCUE_MOD stmt @@ -376,7 +377,7 @@ stmt : block_call } | klBEGIN { - if (cur_mid || in_single) { + if (in_def || in_single) { yyerror("BEGIN in method"); } local_push(); @@ -390,18 +391,18 @@ stmt : block_call } | klEND '{' compstmt '}' { - if (compile_for_eval && (cur_mid || in_single)) { + if (compile_for_eval && (in_def || in_single)) { yyerror("END in method; use at_exit"); } $$ = NEW_ITER(0, NEW_POSTEXE(), $3); } - | lhs '=' stmt_rhs + | lhs '=' command_call { value_expr($3); $$ = node_assign($1, $3); } - | mlhs '=' stmt_rhs + | mlhs '=' command_call { value_expr($3); $1->nd_value = $3; @@ -421,7 +422,7 @@ expr : mlhs '=' mrhs } | kRETURN ret_args { - if (!compile_for_eval && !cur_mid && !in_single) + if (!compile_for_eval && !in_def && !in_single) yyerror("return appeared outside of method"); $$ = NEW_RETURN($2); } @@ -445,26 +446,41 @@ expr : mlhs '=' mrhs } | arg -command_call : operation call_args +command_call : command + | block_command + +block_command : block_call + | block_call '.' operation2 command_args + { + value_expr($1); + $$ = new_call($1, $3, $4); + } + | block_call tCOLON2 operation2 command_args + { + value_expr($1); + $$ = new_call($1, $3, $4); + } + +command : operation command_args { $$ = new_fcall($1, $2); fixpos($$, $2); } - | primary '.' operation2 call_args + | primary '.' operation2 command_args { value_expr($1); $$ = new_call($1, $3, $4); fixpos($$, $1); } - | primary tCOLON2 operation2 call_args + | primary tCOLON2 operation2 command_args { value_expr($1); $$ = new_call($1, $3, $4); fixpos($$, $1); } - | kSUPER call_args + | kSUPER command_args { - if (!compile_for_eval && !cur_mid && !in_single) + if (!compile_for_eval && !in_def && !in_single) yyerror("super called outside of method"); $$ = new_super($2); fixpos($$, $2); @@ -475,7 +491,6 @@ command_call : operation call_args fixpos($$, $2); } - mlhs : mlhs_basic | tLPAREN mlhs_entry ')' { @@ -897,14 +912,6 @@ aref_args : none { $$ = list_append($1, $3); } - | block_call opt_nl - { - $$ = NEW_LIST($1); - } - | args ',' block_call opt_nl - { - $$ = list_append($1, $3); - } | args trailer { $$ = $1; @@ -924,22 +931,31 @@ aref_args : none $$ = NEW_RESTARGS($2); } -opt_call_args : none - | call_args opt_nl - | block_call opt_nl +paren_args : '(' none ')' { - $$ = NEW_LIST($1); + $$ = $2; } - | args ',' block_call + | '(' call_args opt_nl ')' { - $$ = list_append($1, $3); + $$ = $2; + } + | '(' block_call opt_nl ')' + { + $$ = NEW_LIST($2); } + | '(' args ',' block_call opt_nl ')' + { + $$ = list_append($2, $4); + } + +opt_paren_args : none + | paren_args -call_args : command_call +call_args : command { $$ = NEW_LIST($1); } - | args ',' command_call + | args ',' command { $$ = list_append($1, $3); } @@ -953,10 +969,6 @@ call_args : command_call $$ = arg_concat($1, $4); $$ = arg_blk_pass($$, $5); } - | assocs ',' - { - $$ = NEW_LIST(NEW_HASH($1)); - } | assocs opt_block_arg { $$ = NEW_LIST(NEW_HASH($1)); @@ -973,10 +985,6 @@ call_args : command_call $$ = list_append($1, NEW_HASH($3)); $$ = arg_blk_pass($$, $4); } - | args ',' assocs ',' - { - $$ = list_append($1, NEW_HASH($3)); - } | args ',' assocs ',' tSTAR arg opt_block_arg { value_expr($6); @@ -990,6 +998,12 @@ call_args : command_call } | block_arg +command_args : {CMDARG_PUSH;} call_args + { + CMDARG_POP; + $$ = $2; + } + block_arg : tAMPER arg { value_expr($2); @@ -1119,20 +1133,20 @@ primary : literal } | kRETURN '(' ret_args ')' { - if (!compile_for_eval && !cur_mid && !in_single) + if (!compile_for_eval && !in_def && !in_single) yyerror("return appeared outside of method"); value_expr($3); $$ = NEW_RETURN($3); } | kRETURN '(' ')' { - if (!compile_for_eval && !cur_mid && !in_single) + if (!compile_for_eval && !in_def && !in_single) yyerror("return appeared outside of method"); $$ = NEW_RETURN(0); } | kRETURN { - if (!compile_for_eval && !cur_mid && !in_single) + if (!compile_for_eval && !in_def && !in_single) yyerror("return appeared outside of method"); $$ = NEW_RETURN(0); } @@ -1225,11 +1239,9 @@ primary : literal } | kCLASS cname superclass { - if (cur_mid || in_single) + if (in_def || in_single) yyerror("class definition in method body"); - class_nest++; - cref_push(); local_push(); $$ = ruby_sourceline; } @@ -1239,30 +1251,35 @@ primary : literal $$ = NEW_CLASS($2, $5, $3); nd_set_line($$, $4); local_pop(); - cref_pop(); class_nest--; } - | kCLASS tLSHFT expr term + | kCLASS tLSHFT expr + { + $$ = in_def; + in_def = 0; + } + term { + $$ = in_single; + in_single = 0; class_nest++; - cref_push(); local_push(); } compstmt kEND { - $$ = NEW_SCLASS($3, $6); + $$ = NEW_SCLASS($3, $7); fixpos($$, $3); local_pop(); - cref_pop(); class_nest--; + in_def = $4; + in_single = $6; } | kMODULE cname { - if (cur_mid || in_single) + if (in_def || in_single) yyerror("module definition in method body"); class_nest++; - cref_push(); local_push(); $$ = ruby_sourceline; } @@ -1272,14 +1289,15 @@ primary : literal $$ = NEW_MODULE($2, $4); nd_set_line($$, $3); local_pop(); - cref_pop(); class_nest--; } | kDEF fname { - if (cur_mid || in_single) + if (in_def || in_single) yyerror("nested method definition"); + $$ = cur_mid; cur_mid = $2; + in_def++; local_push(); } f_arglist @@ -1301,7 +1319,8 @@ primary : literal if (is_attrset_id($2)) $$->nd_noex = NOEX_PUBLIC; fixpos($$, $4); local_pop(); - cur_mid = 0; + in_def--; + cur_mid = $3; } | kDEF singleton dot_or_colon {lex_state = EXPR_FNAME;} fname { @@ -1312,8 +1331,18 @@ primary : literal } f_arglist compstmt + rescue + opt_else + ensure kEND { + if ($9) $8 = NEW_RESCUE($8, $9, $10); + else if ($10) { + rb_warn("else without rescue is useless"); + $8 = block_append($8, $10); + } + if ($11) $8 = NEW_ENSURE($8, $11); + $$ = NEW_DEFS($2, $5, $7, $8); fixpos($$, $2); local_pop(); @@ -1341,7 +1370,7 @@ then : term | term kTHEN do : term - | kDO + | kDO_COND if_tail : opt_else | kELSIF expr then @@ -1377,7 +1406,7 @@ opt_block_var : none } -do_block : kDO +do_block : kDO_BLOCK { $$ = dyna_push(); } @@ -1390,47 +1419,7 @@ do_block : kDO dyna_pop($2); } -brace_block : '{' - { - $$ = dyna_push(); - } - opt_block_var - compstmt '}' - { - $$ = NEW_ITER($3, 0, $4); - fixpos($$, $4); - dyna_pop($2); - } - | kDO2 - { - $$ = dyna_push(); - } - opt_block_var - compstmt - kEND - { - $$ = NEW_ITER($3, 0, $4); - fixpos($$, $4); - dyna_pop($2); - } - - -generic_call : tIDENTIFIER - { - $$ = NEW_VCALL($1); - } - | tCONSTANT - { - $$ = NEW_VCALL($1); - } - | tFID - { - $$ = NEW_VCALL($1); - } - | method_call - | command_call - -block_call : generic_call do_block +block_call : command do_block { if ($1 && nd_type($1) == NODE_BLOCK_PASS) { rb_compile_error("both block arg and actual block given"); @@ -1439,28 +1428,32 @@ block_call : generic_call do_block $$ = $2; fixpos($$, $2); } - -method_call : operation '(' opt_call_args close_paren + | block_call '.' operation2 opt_paren_args { - $$ = new_fcall($1, $3); - fixpos($$, $3); + value_expr($1); + $$ = new_call($1, $3, $4); } - | primary '.' operation2 '(' opt_call_args close_paren + | block_call tCOLON2 operation2 opt_paren_args { value_expr($1); - $$ = new_call($1, $3, $5); - fixpos($$, $1); + $$ = new_call($1, $3, $4); } - | primary '.' operation2 + +method_call : operation paren_args + { + $$ = new_fcall($1, $2); + fixpos($$, $2); + } + | primary '.' operation2 opt_paren_args { value_expr($1); - $$ = new_call($1, $3, 0); + $$ = new_call($1, $3, $4); fixpos($$, $1); } - | primary tCOLON2 operation2 '(' opt_call_args close_paren + | primary tCOLON2 operation2 paren_args { value_expr($1); - $$ = new_call($1, $3, $5); + $$ = new_call($1, $3, $4); fixpos($$, $1); } | primary tCOLON2 operation3 @@ -1468,28 +1461,43 @@ method_call : operation '(' opt_call_args close_paren value_expr($1); $$ = new_call($1, $3, 0); } - | kSUPER '(' opt_call_args close_paren + | kSUPER paren_args { - if (!compile_for_eval && !cur_mid && + if (!compile_for_eval && !in_def && !in_single && !in_defined) yyerror("super called outside of method"); - $$ = new_super($3); + $$ = new_super($2); } | kSUPER { - if (!compile_for_eval && !cur_mid && + if (!compile_for_eval && !in_def && !in_single && !in_defined) yyerror("super called outside of method"); $$ = NEW_ZSUPER(); } -close_paren : ')' +brace_block : '{' { - if (!IN_COND) lex_state = EXPR_PAREN; + $$ = dyna_push(); + } + opt_block_var + compstmt '}' + { + $$ = NEW_ITER($3, 0, $4); + fixpos($$, $4); + dyna_pop($2); + } + | kDO + { + $$ = dyna_push(); + } + opt_block_var + compstmt kEND + { + $$ = NEW_ITER($3, 0, $4); + fixpos($$, $4); + dyna_pop($2); } - -stmt_rhs : block_call - | command_call case_body : kWHEN when_args then compstmt @@ -1965,8 +1973,10 @@ yycompile(f, line) ruby_in_compile = 0; cond_nest = 0; cond_stack = 0; + cmdarg_stack = 0; class_nest = 0; in_single = 0; + in_def = 0; cur_mid = 0; if (n == 0) node = ruby_eval_tree; @@ -2043,10 +2053,7 @@ rb_compile_file(f, file, start) return yycompile(strdup(f), start); } -#if defined(__GNUC__) && __GNUC__ >= 2 -__inline__ -#endif -static int +static inline int nextc() { int c; @@ -2542,13 +2549,12 @@ parse_qstring(term, paren) c = '\\'; break; - case '\'': - if (term == '\'') { - c = '\''; - break; - } - /* fall through */ default: + /* fall through */ + if (c == term || (paren && c == paren)) { + tokadd(c); + continue; + } tokadd('\\'); } } @@ -2603,7 +2609,7 @@ parse_quotedwords(term, paren) c = '\\'; break; default: - if (c == term) { + if (c == term || (paren && c == paren)) { tokadd(c); continue; } @@ -2794,7 +2800,7 @@ arg_ambiguous() rb_warning("ambiguous first argument; make sure"); } -#ifndef strtod +#if !defined(strtod) && !defined(HAVE_STDLIB_H) double strtod (); #endif @@ -2919,8 +2925,7 @@ yylex() case '<': c = nextc(); if (c == '<' && - lex_state != EXPR_END && lex_state != EXPR_PAREN && - lex_state != EXPR_CLASS && + lex_state != EXPR_END && lex_state != EXPR_CLASS && (lex_state != EXPR_ARG || space_seen)) { int c2 = nextc(); int indent = 0; @@ -2979,7 +2984,7 @@ yylex() return parse_qstring(c,0); case '?': - if (lex_state == EXPR_END || lex_state == EXPR_PAREN) { + if (lex_state == EXPR_END) { lex_state = EXPR_BEG; return '?'; } @@ -3306,7 +3311,7 @@ yylex() return tCOLON2; } pushback(c); - if (lex_state == EXPR_END || lex_state == EXPR_PAREN || ISSPACE(c)) { + if (lex_state == EXPR_END || ISSPACE(c)) { lex_state = EXPR_BEG; return ':'; } @@ -3390,9 +3395,7 @@ yylex() return c; case '{': - if (lex_state != EXPR_END && - lex_state != EXPR_PAREN && - lex_state != EXPR_ARG) + if (lex_state != EXPR_END && lex_state != EXPR_ARG) c = tLBRACE; lex_state = EXPR_BEG; return c; @@ -3616,10 +3619,10 @@ yylex() if (state == EXPR_FNAME) { yylval.id = rb_intern(kw->name); } - if (kw->id[0] == kDO && - (state == EXPR_PAREN || - (!IN_COND && state == EXPR_ARG))) { - return kDO2; + if (kw->id[0] == kDO) { + if (COND_P()) return kDO_COND; + if (CMDARG_P()) return kDO_BLOCK; + return kDO; } return kw->id[state != EXPR_BEG]; } @@ -4121,7 +4124,7 @@ assignable(id, val) return NEW_IASGN(id, val); } else if (is_const_id(id)) { - if (cur_mid || in_single) + if (in_def || in_single) yyerror("dynamic constant assignment"); return NEW_CDECL(id, val); } @@ -4375,6 +4378,9 @@ void_expr(node) } } + +static NODE *cond2 _((NODE*)); + static void void_stmts(node) NODE *node; @@ -4390,8 +4396,6 @@ void_stmts(node) } } -static NODE *cond2(); - static int assign_in_cond(node) NODE *node; @@ -4733,12 +4737,6 @@ dyna_in_block() return (lvtbl->dlev > 0); } -static void -cref_pop() -{ - cur_cref = cur_cref->nd_next; -} - void rb_parser_append_print() { @@ -4822,7 +4820,6 @@ Init_sym() { sym_tbl = st_init_strtable_with_size(200); sym_rev_tbl = st_init_numtable_with_size(200); - rb_global_variable((VALUE*)&cur_cref); rb_global_variable((VALUE*)&lex_lastline); } diff --git a/prec.c b/prec.c index 8dcd121bc0..fab5ea3899 100644 --- a/prec.c +++ b/prec.c @@ -43,7 +43,7 @@ prec_prec_f(x) static VALUE prec_induced_from(module, x) - + VALUE module, x; { rb_raise(rb_eTypeError, "undefined conversion from %s into %s", rb_class2name(CLASS_OF(x)), rb_class2name(module)); diff --git a/re.c b/re.c index bb9898fdb4..0cf81ef607 100644 --- a/re.c +++ b/re.c @@ -288,11 +288,11 @@ rb_reg_desc(s, len, re) rb_str_cat2(str, "/"); if (re) { rb_reg_check(re); - if (RREGEXP(re)->ptr->options & RE_OPTION_MULTILINE) - rb_str_cat2(str, "m"); /* /p is obsolete; to be removed */ if ((RREGEXP(re)->ptr->options & RE_OPTION_POSIXLINE) == RE_OPTION_POSIXLINE) rb_str_cat2(str, "p"); + else if (RREGEXP(re)->ptr->options & RE_OPTION_MULTILINE) + rb_str_cat2(str, "m"); if (RREGEXP(re)->ptr->options & RE_OPTION_IGNORECASE) rb_str_cat2(str, "i"); if (RREGEXP(re)->ptr->options & RE_OPTION_EXTENDED) @@ -915,8 +915,7 @@ rb_reg_equal(re1, re2) if (min > RREGEXP(re2)->len) min = RREGEXP(re2)->len; if (memcmp(RREGEXP(re1)->str, RREGEXP(re2)->str, min) == 0 && rb_reg_cur_kcode(re1) == rb_reg_cur_kcode(re2) && - !((RREGEXP(re1)->ptr->options & RE_OPTION_IGNORECASE) ^ - (RREGEXP(re2)->ptr->options & RE_OPTION_IGNORECASE))) { + RREGEXP(re1)->ptr->options == RREGEXP(re2)->ptr->options) { return Qtrue; } return Qfalse; @@ -1015,6 +1014,7 @@ rb_reg_initialize_m(argc, argv, self) p = rb_str2cstr(src, &len); rb_reg_initialize(self, p, len, flag); } + return self; } static VALUE @@ -1123,6 +1123,12 @@ rb_reg_options(re) rb_reg_check(re); if (RREGEXP(re)->ptr->options & RE_OPTION_IGNORECASE) options |= RE_OPTION_IGNORECASE; + if ((RREGEXP(re)->ptr->options & RE_OPTION_POSIXLINE) == RE_OPTION_POSIXLINE) + options |= RE_OPTION_POSIXLINE; + else if (RREGEXP(re)->ptr->options & RE_OPTION_MULTILINE) + options |= RE_OPTION_MULTILINE; + if (RREGEXP(re)->ptr->options & RE_OPTION_EXTENDED) + options |= RE_OPTION_EXTENDED; if (FL_TEST(re, KCODE_FIXED)) { options |= rb_reg_get_kcode(re); } diff --git a/regex.c b/regex.c index d4c1c2a915..9268b31f9b 100644 --- a/regex.c +++ b/regex.c @@ -1049,7 +1049,7 @@ calculate_must_string(start, end) EXTRACT_NUMBER_AND_INCR(mcnt, p); if (mcnt > 0) p += mcnt; if ((enum regexpcode)p[-3] == jump) { - p -= 3; + p -= 2; EXTRACT_NUMBER_AND_INCR(mcnt, p); if (mcnt > 0) p += mcnt; } @@ -1438,6 +1438,10 @@ re_compile_pattern(pattern, size, bufp) EXTEND_BUFFER; } range_retry: + if (range && had_char_class) { + FREE_AND_RETURN(stackb, "invalid regular expression; can't use character class as a end value of range"); + goto invalid_pattern; + } PATFETCH(c); if (c == ']') { @@ -1473,6 +1477,7 @@ re_compile_pattern(pattern, size, bufp) if (current_mbctype) { set_list_bits(0x80, 0xffffffff, b); } + had_char_class = 1; last = -1; continue; @@ -1483,6 +1488,7 @@ re_compile_pattern(pattern, size, bufp) !current_mbctype && SYNTAX(c) != Sword2)) SET_LIST_BIT(c); } + had_char_class = 1; last = -1; continue; @@ -1490,6 +1496,7 @@ re_compile_pattern(pattern, size, bufp) for (c = 0; c < 256; c++) if (ISSPACE(c)) SET_LIST_BIT(c); + had_char_class = 1; last = -1; continue; @@ -1499,12 +1506,14 @@ re_compile_pattern(pattern, size, bufp) SET_LIST_BIT(c); if (current_mbctype) set_list_bits(0x80, 0xffffffff, b); + had_char_class = 1; last = -1; continue; case 'd': for (c = '0'; c <= '9'; c++) SET_LIST_BIT(c); + had_char_class = 1; last = -1; continue; @@ -1514,6 +1523,7 @@ re_compile_pattern(pattern, size, bufp) SET_LIST_BIT(c); if (current_mbctype) set_list_bits(0x80, 0xffffffff, b); + had_char_class = 1; last = -1; continue; @@ -3461,7 +3471,8 @@ re_search(bufp, string, size, startpos, range, regs) #define PREV_IS_A_LETTER(d) ((current_mbctype == MBCTYPE_SJIS)? \ IS_A_LETTER((d)-(!AT_STRINGS_BEG((d)-1)&& \ ismbchar((d)[-2])?2:1)): \ - ((d)[-1] >= 0x80 || IS_A_LETTER((d)-1))) + ((current_mbctype && ((d)[-1] >= 0x80)) || \ + IS_A_LETTER((d)-1))) static void init_regs(regs, num_regs) diff --git a/ruby.c b/ruby.c index 9649b69af4..da1049533d 100644 --- a/ruby.c +++ b/ruby.c @@ -214,13 +214,23 @@ ruby_init_loadpath() #elif defined(DJGPP) extern char *__dos_argv0; strncpy(libpath, __dos_argv0, FILENAME_MAX); +#define CharNext(p) ((p) + mblen(p, MB_CUR_MAX)) #elif defined(__EMX__) _execname(libpath, FILENAME_MAX); #endif - p = strrchr(libpath, '\\'); + +#ifndef CharNext /* defined as CharNext[AW] on Windows. */ +#define CharNext(p) ((p) + 1) +#endif + + for (p = libpath; *p; p = CharNext(p)) + if (*p == '\\') + *p = '/'; + + p = strrchr(libpath, '/'); if (p) { *p = 0; - if (p-libpath > 3 && !strcasecmp(p-4, "\\bin")) { + if (p-libpath > 3 && !strcasecmp(p-4, "/bin")) { p -= 4; *p = 0; } @@ -229,14 +239,6 @@ ruby_init_loadpath() p = libpath + 1; } -#if !defined(__CYGWIN32__) -#ifndef CharNext /* defined as CharNext[AW] on Windows. */ -#define CharNext(p) ((p) + 1) -#endif - for (p = libpath; *p; p = CharNext(p)) - if (*p == '\\') - *p = '/'; -#endif rest = FILENAME_MAX - (p - libpath); #define RUBY_RELATIVE(path) (strncpy(p, (path), rest), libpath) @@ -428,6 +430,10 @@ proc_options(argc, argv) goto reswitch; case 'v': + if (verbose) { + s++; + goto reswitch; + } ruby_show_version(); verbose = 1; case 'w': @@ -728,7 +734,7 @@ load_file(fname, script) FILE *fp = fopen(fname, "r"); if (fp == NULL) { - rb_raise(rb_eLoadError, "No such file to load -- %s", fname); + rb_load_fail(fname); } fclose(fp); @@ -983,6 +989,7 @@ ruby_set_argv(argc, argv) if (origargv) dln_argv0 = origargv[0]; else dln_argv0 = argv[0]; #endif + rb_ary_clear(rb_argv); for (i=0; i < argc; i++) { rb_ary_push(rb_argv, rb_tainted_str_new2(argv[i])); } diff --git a/ruby.h b/ruby.h index ca97ee2c42..d9e3460684 100644 --- a/ruby.h +++ b/ruby.h @@ -164,6 +164,7 @@ VALUE rb_uint2inum _((unsigned long)); #define T_MATCH 0x23 #define T_SYMBOL 0x24 +#define T_BLKTAG 0x3b #define T_UNDEF 0x3c #define T_VARMAP 0x3d #define T_SCOPE 0x3e @@ -541,13 +542,13 @@ EXTERN VALUE rb_eNameError; EXTERN VALUE rb_eSyntaxError; EXTERN VALUE rb_eLoadError; -#if defined(__GNUC__) && __GNUC__ >= 2 && !defined(RUBY_NO_INLINE) -extern __inline__ VALUE rb_class_of _((VALUE)); -extern __inline__ int rb_type _((VALUE)); -extern __inline__ int rb_special_const_p _((VALUE)); - -extern __inline__ VALUE +static inline VALUE +#if defined(__cplusplus) rb_class_of(VALUE obj) +#else +rb_class_of(obj) + VALUE obj; +#endif { if (FIXNUM_P(obj)) return rb_cFixnum; if (obj == Qnil) return rb_cNilClass; @@ -558,8 +559,13 @@ rb_class_of(VALUE obj) return RBASIC(obj)->klass; } -extern __inline__ int +static inline int +#if defined(__cplusplus) rb_type(VALUE obj) +#else +rb_type(obj) + VALUE obj; +#endif { if (FIXNUM_P(obj)) return T_FIXNUM; if (obj == Qnil) return T_NIL; @@ -570,19 +576,18 @@ rb_type(VALUE obj) return BUILTIN_TYPE(obj); } -extern __inline__ int +static inline int +#if defined(__cplusplus) rb_special_const_p(VALUE obj) +#else +rb_special_const_p(obj) + VALUE obj; +#endif { if (SPECIAL_CONST_P(obj)) return Qtrue; return Qfalse; } -#else -VALUE rb_class_of _((VALUE)); -int rb_type _((VALUE)); -int rb_special_const_p _((VALUE)); -#endif - #include "intern.h" #if defined(EXTLIB) && defined(USE_DLN_A_OUT) @@ -590,6 +595,10 @@ int rb_special_const_p _((VALUE)); static char *dln_libs_to_be_linked[] = { EXTLIB, 0 }; #endif +#ifndef rb_sys_stat +#define rb_sys_stat stat +#endif + #if defined(__cplusplus) } /* extern "C" { */ #endif diff --git a/sample/README b/sample/README index 82db05eec9..bf080c1d51 100644 --- a/sample/README +++ b/sample/README @@ -7,7 +7,6 @@ dbmtest.rb test for dbm dir.rb directory access dualstack-fetch.rb IPv6 demo dualstack-httpd.rb IPv6 demo -dstore.rb object database on dbm eval.rb simple evaluator export.rb method access example exyacc.rb extrace BNF from yacc file @@ -22,7 +21,6 @@ from.rb scan mail spool fullpath.rb convert ls -lR to fullpath format getopts.test test fot getopt.rb goodfriday.rb print various christian calendar event. -io.rb io test irb.rb interactive ruby less.rb front end for less list.rb stupid object sample @@ -41,7 +39,6 @@ pi.rb calculate PI rcs.awk random character stereogram (AWK) rcs.rb random character stereogram (Ruby) rcs.dat data for random character stereogram -rd2html.rb rd (Ruby Document) to HTML translator regx.rb regular expression tester sieve.rb sieve of Eratosthenes svr.rb socket server diff --git a/signal.c b/signal.c index 2bb8bada28..48849a6554 100644 --- a/signal.c +++ b/signal.c @@ -252,7 +252,7 @@ rb_f_kill(argc, argv) else { for (i=1; iorig, add); } -static ID to_str; +static ID id_to_s; VALUE rb_obj_as_string(obj) @@ -185,7 +185,7 @@ rb_obj_as_string(obj) if (TYPE(obj) == T_STRING) { return obj; } - str = rb_funcall(obj, to_str, 0); + str = rb_funcall(obj, id_to_s, 0); if (TYPE(str) != T_STRING) return rb_any_to_s(obj); if (OBJ_TAINTED(obj)) OBJ_TAINT(str); @@ -339,7 +339,6 @@ rb_str_substr(str, beg, len) if (len < 0) return Qnil; if (beg > RSTRING(str)->len) return Qnil; - if (beg == RSTRING(str)->len && len > 0) return Qnil; if (beg < 0) { beg += RSTRING(str)->len; if (beg < 0) return Qnil; @@ -367,7 +366,6 @@ str_independent(str) rb_raise(rb_eSecurityError, "Insecure: can't modify string"); if (!RSTRING(str)->orig || FL_TEST(str, STR_NO_ORIG)) return 1; if (TYPE(RSTRING(str)->orig) != T_STRING) rb_bug("non string str->orig"); - RSTRING(str)->orig = 0; return 0; } @@ -384,6 +382,7 @@ rb_str_modify(str) } ptr[RSTRING(str)->len] = 0; RSTRING(str)->ptr = ptr; + RSTRING(str)->orig = 0; } VALUE @@ -1127,7 +1126,7 @@ rb_str_sub_bang(argc, argv, str) iter = 1; } else if (argc == 2) { - repl = rb_obj_as_string(argv[1]);; + repl = rb_str_to_str(argv[1]);; if (OBJ_TAINTED(repl)) tainted = 1; } else { @@ -1200,7 +1199,7 @@ str_gsub(argc, argv, str, bang) iter = 1; } else if (argc == 2) { - repl = rb_obj_as_string(argv[1]); + repl = rb_str_to_str(argv[1]); if (OBJ_TAINTED(repl)) tainted = 1; } else { @@ -1278,6 +1277,9 @@ str_gsub(argc, argv, str, bang) if (str_independent(str)) { free(RSTRING(str)->ptr); } + else { + RSTRING(str)->orig = 0; + } } else { NEWOBJ(dup, struct RString); @@ -1316,15 +1318,19 @@ static VALUE rb_str_replace_m(str, str2) VALUE str, str2; { + if (str == str2) return str; if (TYPE(str2) != T_STRING) str2 = rb_str_to_str(str2); - rb_str_modify(str); - if (RSTRING(str2)->orig && FL_TEST(str2, STR_NO_ORIG)) { + if (RSTRING(str2)->orig && !FL_TEST(str2, STR_NO_ORIG)) { + if (str_independent(str)) { + free(RSTRING(str)->ptr); + } RSTRING(str)->len = RSTRING(str2)->len; RSTRING(str)->ptr = RSTRING(str2)->ptr; RSTRING(str)->orig = RSTRING(str2)->orig; } else { + rb_str_modify(str); rb_str_resize(str, RSTRING(str2)->len); memcpy(RSTRING(str)->ptr, RSTRING(str2)->ptr, RSTRING(str2)->len); } @@ -1395,6 +1401,7 @@ rb_str_reverse_bang(str) char *s, *e; char c; + rb_str_modify(str); s = RSTRING(str)->ptr; e = s + RSTRING(str)->len - 1; while (s < e) { @@ -1490,8 +1497,8 @@ rb_str_inspect(str) char c = *p++; if (ismbchar(c) && p < pend) { int len = mbclen(c); - rb_str_cat(result, p, len); - p += len; + rb_str_cat(result, p - 1, len); + p += len - 1; } else if (c == '"'|| c == '\\') { s[0] = '\\'; s[1] = c; @@ -1644,7 +1651,7 @@ rb_str_upcase_bang(str) if (ismbchar(*s)) { s+=mbclen(*s) - 1; } - else if (islower(*s)) { + else if (ISLOWER(*s)) { *s = toupper(*s); modify = 1; } @@ -1784,7 +1791,10 @@ trnext(t) if (!t->gen) { if (t->p == t->pend) return -1; t->now = *(USTR)t->p++; - if (t->p < t->pend - 1 && *t->p == '-') { + if (t->p < t->pend - 1 && *t->p == '\\') { + t->p++; + } + else if (t->p < t->pend - 1 && *t->p == '-') { t->p++; if (t->p < t->pend) { if (t->now > *(USTR)t->p) { @@ -1965,6 +1975,9 @@ rb_str_delete_bang(argc, argv, str) int init = 1; int i; + if (argc < 1) { + rb_raise(rb_eArgError, "wrong # of arguments"); + } for (i=0; itm_gmtoff; -#else struct tm gt, lt; long tzsec; @@ -357,10 +352,14 @@ make_time_t(tptr, utc_or_local) } tm = localtime(&guess); if (!tm) goto error; - if (lt.tm_isdst != tm->tm_isdst) { - guess -= 3600; + if (lt.tm_isdst != tm->tm_isdst || tptr->tm_hour != tm->tm_hour) { + oguess = guess - 3600; + tm = localtime(&oguess); + if (!tm) goto error; + if (tptr->tm_hour == tm->tm_hour) { + guess = oguess; + } } -#endif if (guess < 0) { goto out_of_range; } @@ -891,7 +890,7 @@ rb_strftime(buf, format, time) return 0; } len = strftime(*buf, SMALLBUF, format, time); - if (len != 0) return len; + if (len != 0 || **buf == '\0') return len; for (size=1024; ; size*=2) { *buf = xmalloc(size); (*buf)[0] = '\0'; diff --git a/util.c b/util.c index 9cbfb5fc74..8fc543dbc0 100644 --- a/util.c +++ b/util.c @@ -16,45 +16,9 @@ #include "missing/file.h" #endif -#define RUBY_NO_INLINE +#define INLINE_DEFINE #include "ruby.h" -VALUE -rb_class_of(obj) - VALUE obj; -{ - if (FIXNUM_P(obj)) return rb_cFixnum; - if (obj == Qnil) return rb_cNilClass; - if (obj == Qfalse) return rb_cFalseClass; - if (obj == Qtrue) return rb_cTrueClass; - if (SYMBOL_P(obj)) return rb_cSymbol; - - return RBASIC(obj)->klass; -} - -int -rb_type(obj) - VALUE obj; -{ - if (FIXNUM_P(obj)) return T_FIXNUM; - if (obj == Qnil) return T_NIL; - if (obj == Qfalse) return T_FALSE; - if (obj == Qtrue) return T_TRUE; - if (obj == Qundef) return T_UNDEF; - if (SYMBOL_P(obj)) return T_SYMBOL; - - return BUILTIN_TYPE(obj); -} - -int -rb_special_const_p(obj) - VALUE obj; -{ - if (SPECIAL_CONST_P(obj)) return Qtrue; - - return Qfalse; -} - #include "util.h" #ifndef HAVE_STRING_H char *strchr _((char*,char)); diff --git a/variable.c b/variable.c index 69791ab26d..6e2ef0c875 100644 --- a/variable.c +++ b/variable.c @@ -1064,10 +1064,11 @@ rb_const_get(klass, id) VALUE klass; ID id; { - VALUE value; - VALUE tmp; + VALUE value, tmp; + int mod_retry = 0; tmp = klass; + retry: while (tmp) { if (RCLASS(tmp)->iv_tbl && st_lookup(RCLASS(tmp)->iv_tbl,id,&value)) { return value; @@ -1075,15 +1076,17 @@ rb_const_get(klass, id) if (tmp == rb_cObject && top_const_get(id, &value)) return value; tmp = RCLASS(tmp)->super; } - if (BUILTIN_TYPE(klass) == T_MODULE) { - return rb_const_get(rb_cObject, id); + if (!mod_retry && BUILTIN_TYPE(klass) == T_MODULE) { + mod_retry = 1; + tmp = rb_cObject; + goto retry; } /* Uninitialized constant */ if (klass && klass != rb_cObject) - rb_raise(rb_eNameError, "uninitialized constant %s::%s", - RSTRING(rb_class_path(klass))->ptr, - rb_id2name(id)); + rb_raise(rb_eNameError, "uninitialized constant %s at %s", + rb_id2name(id), + RSTRING(rb_class_path(klass))->ptr); else { rb_raise(rb_eNameError, "uninitialized constant %s",rb_id2name(id)); } diff --git a/version.h b/version.h index 71d484b8fd..f90b413a11 100644 --- a/version.h +++ b/version.h @@ -1,4 +1,4 @@ -#define RUBY_VERSION "1.6.2" -#define RUBY_RELEASE_DATE "2000-12-25" -#define RUBY_VERSION_CODE 162 -#define RUBY_RELEASE_CODE 20001225 +#define RUBY_VERSION "1.6.4" +#define RUBY_RELEASE_DATE "2001-04-18" +#define RUBY_VERSION_CODE 164 +#define RUBY_RELEASE_CODE 20010418 diff --git a/win32/Makefile.sub b/win32/Makefile.sub index 227ab68b18..42100a5d92 100644 --- a/win32/Makefile.sub +++ b/win32/Makefile.sub @@ -30,13 +30,13 @@ AUTOCONF = autoconf prefix = /usr -CFLAGS = -nologo -DNT=1 -Zi -MD -O2b2x -G5 +CFLAGS = -nologo -DNT=1 -Zi -MD -O2b2xg- -G5 CPPFLAGS = -I$(srcdir) -I$(srcdir)/missing LDFLAGS = $(CFLAGS) -Fm XLDFLAGS = #EXTLIBS = LIBS = user32.lib advapi32.lib wsock32.lib $(EXTLIBS) -MISSING = crypt.obj alloca.obj win32.obj isinf.obj isnan.obj +MISSING = crypt.obj win32.obj isinf.obj isnan.obj LDSHARED = DLDFLAGS = SOLIBS = diff --git a/win32/config.h.in b/win32/config.h.in index a7e28120e6..f1ba8da5c3 100644 --- a/win32/config.h.in +++ b/win32/config.h.in @@ -1,6 +1,7 @@ #define HAVE_PROTOTYPES 1 #define HAVE_STDARG_PROTOTYPES 1 /* #define HAVE_ATTR_NORETURN 1 */ +#define inline __inline /* #define HAVE_DIRENT_H 1 */ /* #define HAVE_UNISTD_H 1 */ #define HAVE_STDLIB_H 1 diff --git a/win32/config.status.in b/win32/config.status.in index 461877b886..f337d97b35 100644 --- a/win32/config.status.in +++ b/win32/config.status.in @@ -3,8 +3,6 @@ s%@CFLAGS@%-nologo -DNT=1 -Zi -MD -O2b2x -G5%g s%@CPPFLAGS@%%g s%@CXXFLAGS@%%g s%@FFLAGS@%%g -s%@DEFS@% - -DUSE_THREAD -DSIZEOF_INT=4 -DSIZEOF_SHORT=2 -DSIZEOF_LONG=4 -DSIZEOF_VOIDP=4 -DSIZEOF_FLOAT=4 -DSIZEOF_DOUBLE=8 -DHAVE_PROTOTYPES=1 -DHAVE_STDARG_PROTOTYPES=1 -DHAVE_STDLIB_H=1 -DHAVE_LIMITS_H=1 -DHAVE_FCNTL_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_ST_RDEV=1 -DGETGROUPS_T=int -DRETSIGTYPE=void -DHAVE_ALLOCA=1 -DHAVE_FMOD=1 -DHAVE_WAITPID=1 -DHAVE_GETCWD=1 -DHAVE_CHSIZE=1 -DHAVE_GETGROUPS=1 -DHAVE_GETLOGIN=1 -DRSHIFT=\(x,y\)\ \(\(x\)\>\>y\) -DFILE_COUNT=_cnt -DDLEXT=\".so\" -DDLEXT2=\".dll\" -DRUBY_PLATFORM=\"i586-mswin32\" %g s%@LDFLAGS@%-nologo%g s%@LIBS@%user32.lib advapi32.lib wsock32.lib%g s%@exec_prefix@%${prefix}%g @@ -34,7 +32,7 @@ s%@RANLIB@%rem%g s%@AR@%lib -nologo%g s%@LN_S@%%g s%@SET_MAKE@%%g -s%@LIBOBJS@% crypt.obj alloca.obj win32.obj isinf.obj isnan.obj%g +s%@LIBOBJS@% crypt.obj win32.obj isinf.obj isnan.obj%g s%@ALLOCA@%%g s%@DEFAULT_KCODE@%%g s%@EXEEXT@%.exe%g diff --git a/win32/win32.c b/win32/win32.c index bd07bb644e..9fb120e09d 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -29,6 +29,7 @@ #ifndef index #define index(x, y) strchr((x), (y)) #endif +#define isdirsep(x) ((x) == '/' || (x) == '\\') #ifndef bool #define bool int @@ -357,7 +358,7 @@ isInternalCmd(char *cmd) int vecc = NtMakeCmdVector(cmd, &vec, FALSE); for( i = 0; szInternalCmds[i] ; i++){ - if(!strcmp(szInternalCmds[i], vec[0])){ + if(!strcasecmp(szInternalCmds[i], vec[0])){ fRet = 1; break; } @@ -777,10 +778,10 @@ char *cmd; strcpy(cmd2, cmd); a = argv; for (s = cmd2; *s;) { - while (*s && isspace(*s)) s++; + while (*s && ISSPACE(*s)) s++; if (*s) *(a++) = s; - while (*s && !isspace(*s)) s++; + while (*s && !ISSPACE(*s)) s++; if (*s) *s++ = '\0'; } @@ -1054,7 +1055,7 @@ NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd) // ptr = cmdline+(cmdlen - 1); - while(ptr >= cmdline && isspace(*ptr)) + while(ptr >= cmdline && ISSPACE(*ptr)) --ptr; *++ptr = '\0'; @@ -1074,7 +1075,7 @@ NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd) // zap any leading whitespace // - while(isspace(*ptr)) + while(ISSPACE(*ptr)) ptr++; base = ptr; @@ -1277,7 +1278,6 @@ NtMakeCmdVector (char *cmdline, char ***vec, int InputCmd) } -#if !defined __MINGW32__ // // UNIX compatible directory access functions for NT // @@ -1309,9 +1309,9 @@ opendir(char *filename) // check to see if we\'ve got a directory // - if ((stat (filename, &sbuf) < 0 || + if ((win32_stat (filename, &sbuf) < 0 || sbuf.st_mode & _S_IFDIR == 0) && - (!isalpha(filename[0]) || filename[1] != ':' || filename[2] != '\0' || + (!ISALPHA(filename[0]) || filename[1] != ':' || filename[2] != '\0' || ((1 << (filename[0] & 0x5f) - 'A') & GetLogicalDrives()) == 0)) { return NULL; } @@ -1466,7 +1466,6 @@ closedir(DIR *dirp) free(dirp->start); free(dirp); } -#endif // @@ -2425,13 +2424,23 @@ waitpid (pid_t pid, int *stat_loc, int options) int _cdecl gettimeofday(struct timeval *tv, struct timezone *tz) { - struct timeb tb; + SYSTEMTIME st; + time_t t; + struct tm tm; + + GetLocalTime(&st); + tm.tm_sec = st.wSecond; + tm.tm_min = st.wMinute; + tm.tm_hour = st.wHour; + tm.tm_mday = st.wDay; + tm.tm_mon = st.wMonth - 1; + tm.tm_year = st.wYear - 1900; + tm.tm_isdst = -1; + t = mktime(&tm); + tv->tv_sec = t; + tv->tv_usec = st.wMilliseconds * 1000; - ftime(&tb); - tv->tv_sec = tb.time; - tv->tv_usec = tb.millitm * 1000; - - return 0; + return 0; } char * @@ -2545,7 +2554,7 @@ myrename(const char *oldpath, const char *newpath) newatts = GetFileAttributes(newpath); if (oldatts == -1) { - printf("file to move doesn't exist"); + errno = GetLastError(); return -1; } @@ -2583,6 +2592,56 @@ myrename(const char *oldpath, const char *newpath) return res; } +static int +isUNCRoot(const char *path) +{ + if (path[0] == '\\' && path[1] == '\\') { + const char *p; + for (p = path + 3; *p; p = CharNext(p)) { + if (*p == '\\') + break; + } + if (p[0] && p[1]) { + for (p++; *p; p = CharNext(p)) { + if (*p == '\\') + break; + } + if (!p[0] || !p[1]) + return 1; + } + } + return 0; +} + +int +win32_stat(const char *path, struct stat *st) +{ + const char *p; + char *buf1 = ALLOCA_N(char, strlen(path) + 1); + char *buf2 = ALLOCA_N(char, MAXPATHLEN); + char *s; + int len; + + for (p = path, s = buf1; *p; p++, s++) { + if (*p == '/') + *s = '\\'; + else + *s = *p; + } + *s = '\0'; + len = strlen(buf1); + p = CharPrev(buf1, buf1 + len); + if (isUNCRoot(buf1)) { + if (*p != '\\') + strcat(buf1, "\\"); + } else if (*p == '\\' || *p == ':') + strcat(buf1, "."); + if (_fullpath(buf2, buf1, MAXPATHLEN)) + return stat(buf2, st); + else + return -1; +} + static long filetime_to_clock(FILETIME *ft) { diff --git a/win32/win32.h b/win32/win32.h index ebffc5c8ab..ffbe967703 100644 --- a/win32/win32.h +++ b/win32/win32.h @@ -162,6 +162,8 @@ extern "C++" { #define pclose _pclose #define strcasecmp _stricmp #define strncasecmp _strnicmp +#undef rb_sys_stat +#define rb_sys_stat win32_stat /* these are defined in nt.c */ #ifdef __MINGW32__ -- cgit v1.2.3