1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Merge -r16241:16456 from ruby_1_8.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8_7@16458 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
knu 2008-05-18 15:02:36 +00:00
parent 32378c5abe
commit 8480bcc8d5
64 changed files with 5134 additions and 851 deletions

326
ChangeLog
View file

@ -1,3 +1,329 @@
Sun May 18 22:26:51 2008 GOTOU Yuuzou <gotoyuzo@notwork.org>
* lib/webrick/httpservlet/filehandler.rb: should normalize path
name in path_info to prevent script disclosure vulnerability on
DOSISH filesystems. (fix: CVE-2008-1891)
Note: NTFS/FAT filesystem should not be published by the platforms
other than Windows. Pathname interpretation (including short
filename) is less than perfect.
* lib/webrick/httpservlet/abstract.rb
(WEBrick::HTTPServlet::AbstracServlet#redirect_to_directory_uri):
should escape the value of Location: header.
* lib/webrick/httpservlet/cgi_runner.rb: accept interpreter
command line arguments.
Sat May 17 23:53:57 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
* file.c (file_expand_path): fix for short file name on Cygwin.
Sat May 17 11:29:11 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
* file.c (rb_file_s_extname): first dot is not an extension name.
Sat May 17 10:18:44 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
* re.c (rb_reg_search): need to free allocated buffer in re_register.
Fri May 16 17:01:44 2008 NAKAMURA Usaku <usa@ruby-lang.org>
* win32/Makefile.sub (test-rubyspec): added.
Fri May 16 16:22:40 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* ext/tk/tcltklib.c: sometimes freeze when receive Interrupt signal.
Fri May 16 14:54:56 2008 Tanaka Akira <akr@fsij.org>
* Makefile.in (update-rubyspec): move rubyspec to srcdir.
(test-rubyspec): ditto.
Fri May 16 14:25:22 2008 Tanaka Akira <akr@fsij.org>
* Makefile.in (test-rubyspec): use RUNRUBY. suggested by nobu.
Fri May 16 13:01:43 2008 Tanaka Akira <akr@fsij.org>
* Makefile.in (update-rubyspec): new target to download rubyspec.
(test-rubyspec): new target to run rubyspec. this doesn't work
before install.
Fri May 16 08:15:52 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* ext/tk/lib/tk.rb: fix memory (object) leak bug.
* ext/tk/sample/demos-jp/aniwave.rb, ext/tk/sample/demos-en/aniwave.rb:
bug fix.
Thu May 15 17:00:22 2008 Akinori MUSHA <knu@iDaemons.org>
* string.c (Init_String): Define #bytesize as an alias for #size
for compatibility with 1.9.
Thu May 15 15:33:59 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
* file.c (file_expand_path): support for alternative data stream
and ignored trailing garbages of NTFS.
* file.c (rb_file_s_basename): ditto.
* file.c (rb_file_s_extname): ditto.
Wed May 14 19:24:59 2008 Akinori MUSHA <knu@iDaemons.org>
* array.c (rb_ary_count): Override Enumerable#count for better
performance.
(rb_ary_nitems): Undo the backport. Use #count {} instead.
* enumerator.c (enumerator_iter_i): Remove an unused function.
(enumerator_with_index, enumerator_each): Remove unused
variables.
Wed May 14 17:15:11 2008 NAKAMURA Usaku <usa@ruby-lang.org>
* ext/tk/tkutil/extronf.rb: check stdndup() because it's not standard
function of C.
* ext/tk/tkutil/tkutil.c (cbsubst_table_setup): use malloc() and
strncpy() instead of strndup() if not available.
Wed May 14 09:52:02 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* ext/tk/tkutil/tkutil.c: improve handling callback-subst-keys.
Now, support longnam-keys (e.g. '%CTT' on tkdnd-2.0; however, still
not support tkdnd-2.0 on tkextlib), and symbols of parameters (e.g.
:widget=>'%W', :keycode=>'%k', '%x'=>:x, '%X'=>:root_x, and so on;
those are attributes of event object). It means that Ruby/Tk accepts
not only "widget.bind(ev, '%W', '%k', ...){|w, k, ...| ... }", but
also "widget.bind(ev, :widget, :keycode, ...){|w, k, ...| ... }".
It is potentially incompatible, when user passes symbols to the
arguments of the callback block (the block receives the symbols as
strings). I think that is very rare case (probably, used by Ruby/Tk
experts only). When causes such trouble, please give strings instead
of such symbol parameters (e.g. call Symbol#to_s method).
* ext/tk/lib/tk/event.rb, ext/tk/lib/tk/validation.rb,
ext/tk/lib/tkextlib/blt/treeview.rb,
ext/tk/lib/tkextlib/winico/winico.rb: ditto.
* ext/tk/tkutil/tkutil.c: strings are available on subst_tables on
TkUtil::CallbackSubst class (it is useful on Ruby 1.9).
* ext/tk/lib/tk/spinbox.rb, ext/tk/lib/tkextlib/iwidgets/hierarchy.rb,
ext/tk/lib/tkextlib/iwidgets/spinner.rb,
ext/tk/lib/tkextlib/iwidgets/entryfield.rb,
ext/tk/lib/tkextlib/iwidgets/calendar.rb,
ext/tk/lib/tkextlib/blt/dragdrop.rb,
ext/tk/lib/tkextlib/tkDND/tkdnd.rb,
ext/tk/lib/tkextlib/treectrl/tktreectrl.rb,
ext/tk/lib/tkextlib/tktable/tktable.rb: disable code piece became
unnecessary by reason of the changes of ext/tk/tkutil/tkutil.c.
Tue May 13 15:10:50 2008 Akinori MUSHA <knu@iDaemons.org>
* enumerator.c: Update rdoc.
(enumerator_initialize): Discourage the use.
(enum_each_slice, enum_each_cons, enumerator_each)
(enumerator_with_index): Add a note about a call without a block.
* NEWS: Intentionally omit enum_slice and enum_cons, which are
removed in 1.9.
Tue May 13 07:56:36 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
* string.c (rb_str_cat): fixed buffer overrun reported by
Christopher Thompson <cthompson at nexopia.com> in [ruby-core:16746]
Mon May 12 13:57:19 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
* eval.c (is_defined): add NODE_OP_ASGN_{OR,AND}. "defined?(a||=1)"
should not operate assignment. [ruby-dev:34645]
Mon May 12 12:59:23 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* ext/tk/lib/tk/wm.rb: Wm#overrideredirect overwrites arguemnt to
an invalid value.
* ext/tk/sample/ttk_wrapper.rb: support "if __FILE__ == $0" idiom.
Mon May 12 12:36:55 2008 NAKAMURA Usaku <usa@ruby-lang.org>
* win32/win32.c (rb_w32_select): backport from trunk.
[ruby-talk:300743]
Mon May 12 12:33:21 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
* common.mk (RUBYLIB, RUBYOPT): clear.
Mon May 12 10:41:10 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
* lib/delegate.rb (SimpleDelegator::dup): removed needless argument.
[ruby-list:44910]
* lib/delegate.rb (clone, dup): keep relationship with the target
object.
Sun May 11 23:19:39 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
* enum.c (all_iter_i, any_iter_i): reduced duplicated code.
Sun May 11 17:57:36 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
* configure.in (MINIRUBY): should not include extension library path.
Sun May 11 10:36:10 2008 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
* eval.c (method_name, method_owner): New methods; backported
from 1.9. (UnboundMethod#name, UnboundMethod#owner)
Sun May 11 02:48:13 2008 <nagai@orca16.orcabay.ddo.jp>
* ext/tk/lib/tk/pack.rb, ext/tk/lib/tk/grid.rb: fail to do pack/grid
without options.
* ext/tk/lib/tk.rb: add TkWindow#grid_anchor, grid_column, grid_row.
Sat May 10 18:19:16 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
* string.c (rb_str_each_line): RDoc updated. [ruby-dev:34586]
Sat May 10 13:17:56 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* ext/tk/lib/tk/pack.rb, ext/tk/lib/tk/grid.rb: increase supported
parameter patterns of configure method.
Sat May 10 09:16:13 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
* util.c (ruby_strtod): backported from 1.9. a patch from Satoshi
Nakagawa <psychs at limechat.net> in [ruby-dev:34625].
fixed: [ruby-dev:34623]
Fri May 9 23:33:25 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* ext/tk/lib/tk/wm.rb: methods of Tk::Wm_for_General module cannot
pass the given block to methods of Tk::Wm module.
* ext/tk/lib/tk/grid.rb: lack of module-method definitions.
* ext/tk/lib/tkextlib/tile.rb: lack of autoload definitions.
* ext/tk/lib/tkextlib/tile/tnotebook.rb: cannot use kanji (not UTF-8)
characters for headings.
* ext/tk/tcltklib.c: maybe a little more stable about @encoding value
of TclTkIp object.
Wed May 7 08:46:44 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
* struct.c (rb_struct_s_def): to_str should be called only once.
[ruby-core:16647]
Wed May 7 00:54:25 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
* ext/zlib/zlib.c (gzreader_gets): may cause infinite loop.
a patch from Kouya <kouyataifu4 at gmail.com> in
[ruby-reference-manual:762].
Sun May 4 09:35:51 2008 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
* sample/erb/erb4html.rb (ERB4Html) : add example of ERB#set_eoutvar.
ERB4Html is an auto-quote ERB.
Sat May 3 22:52:48 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* ext/tk/lib/tkextlib/tile.rb, ext/tk/lib/tkextlib/tile/style.rb,
ext/tk/sample/ttk_wrapper.rb: improve treating and control themes.
add Tk::Tile.themes and Tk::Tile.set_theme(theme).
Fri May 2 14:52:33 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
* misc/ruby-mode.el: move fontifying code from hook. a patch from
Phil Hagelberg <phil at hagelb.org> in [ruby-core:16636].
Fri May 2 13:47:51 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
* re.c (match_select): restore previous behavior of MatchData#select.
RDoc updated as well, mentioning the plan to remove this method
in the future. [ruby-dev:34556]
Fri May 2 13:04:04 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
* ext/dbm/dbm.c (Init_dbm): defines DBM::VERSION even when
DB_VERSION_STRING is not available. [ruby-dev:34569]
Thu May 1 23:57:06 2008 James Edward Gray II <jeg2@ruby-lang.org>
Merged 16257 from trunk.
* lib/net/telnet.rb: This patch from Brian Candler adds a FailEOF mode which
can be activated to have net/telnet raise EOFError exceptions when the
remote connection is closed. The default behavior remains unchanged though.
Thu May 1 23:43:21 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
* range.c (range_step): check if step can be converted to an integer.
[ruby-dev:34558]
* range.c (range_step): allow float step bigger than zero but less
than one. [ruby-dev:34557]
Wed Apr 30 20:22:40 2008 James Edward Gray II <jeg2@ruby-lang.org>
Merged 16241 from trunk.
* lib/net/telnet.rb: Fixing a bug where line endings would not be properly
escaped when the two character ending was broken up into separate TCP
packets. Issue reported and patched by Brian Candler.
Thu May 1 23:57:06 2008 James Edward Gray II <jeg2@ruby-lang.org>
Merged 16257 from trunk.
* lib/net/telnet.rb: This patch from Brian Candler adds a FailEOF mode which
can be activated to have net/telnet raise EOFError exceptions when the
remote connection is closed. The default behavior remains unchanged though.
Thu May 1 23:43:21 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
* range.c (range_step): check if step can be converted to an integer.
[ruby-dev:34558]
* range.c (range_step): allow float step bigger than zero but less
than one. [ruby-dev:34557]
Wed Apr 30 20:22:40 2008 James Edward Gray II <jeg2@ruby-lang.org>
Merged 16241 from trunk.
* lib/net/telnet.rb: Fixing a bug where line endings would not be properly
escaped when the two character ending was broken up into separate TCP
packets. Issue reported and patched by Brian Candler.
Thu May 1 23:57:06 2008 James Edward Gray II <jeg2@ruby-lang.org>
Merged 16257 from trunk.
* lib/net/telnet.rb: This patch from Brian Candler adds a FailEOF mode which
can be activated to have net/telnet raise EOFError exceptions when the
remote connection is closed. The default behavior remains unchanged though.
Thu May 1 23:43:21 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
* range.c (range_step): check if step can be converted to an integer.
[ruby-dev:34558]
* range.c (range_step): allow float step bigger than zero but less
than one. [ruby-dev:34557]
Wed Apr 30 20:22:40 2008 James Edward Gray II <jeg2@ruby-lang.org>
Merged 16241 from trunk.
* lib/net/telnet.rb: Fixing a bug where line endings would not be properly
escaped when the two character ending was broken up into separate TCP
packets. Issue reported and patched by Brian Candler.
Wed Apr 30 17:47:21 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
* re.c (rb_reg_search): use local variable. a patch from wanabe

View file

@ -181,3 +181,22 @@ distclean-local::
ext/extinit.$(OBJEXT): ext/extinit.c $(SETUP)
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(OUTFLAG)$@ -c ext/extinit.c
MSPEC_GIT_URL=git://github.com/brixen/mspec.git
RUBYSPEC_GIT_URL=git://github.com/brixen/rubyspec.git
update-rubyspec:
if [ -d $(srcdir)/rubyspec ]; then \
cd $(srcdir)/rubyspec/mspec; \
git pull; \
cd ../spec/rubyspec; \
git pull; \
else \
git clone $(MSPEC_GIT_URL) $(srcdir)/rubyspec/mspec; \
git clone $(RUBYSPEC_GIT_URL) $(srcdir)/rubyspec/spec/rubyspec; \
fi
test-rubyspec:
@if [ ! -d $(srcdir)/rubyspec ]; then echo No rubyspec here. make update-rubyspec first.; exit 1; fi
$(RUNRUBY) $(srcdir)/rubyspec/mspec/bin/mspec -r$(srcdir)/ext/purelib.rb $(srcdir)/rubyspec/spec/rubyspec/$(MAJOR).$(MINOR)

12
NEWS
View file

@ -17,10 +17,6 @@ with all sufficient information, see the ChangeLog file.
* builtin classes
* Array#nitems now takes a block optionally, which is used to
determine if each element should be counted instead of checking if
the element is non-nil.
* Array#flatten
* Array#flatten!
@ -87,9 +83,7 @@ with all sufficient information, see the ChangeLog file.
New class for various enumeration defined by the enumerator library.
* Enumerable#each_slice
* Enumerable#enum_slice
* Enumerable#each_cons
* Enumerable#enum_cons
* Object#to_enum
* Object#enum_for
@ -187,6 +181,8 @@ with all sufficient information, see the ChangeLog file.
* Method#receiver
* Method#name
* Method#owner
* UnboundMethod#name
* UnboundMethod#owner
New methods.
@ -209,6 +205,10 @@ with all sufficient information, see the ChangeLog file.
* Regexp.union accepts an array of patterns.
* String#bytesize
New method, returning the size in bytes. (alias length and size)
* String#chars
* String#each_char
* String#partition

55
array.c
View file

@ -3032,16 +3032,12 @@ rb_ary_compact(ary)
/*
* call-seq:
* array.nitems -> int
* array.nitems { |item| block } -> int
*
* Returns the number of non-<code>nil</code> elements in _self_.
* If a block is given, the elements yielding a true value are
* counted.
*
* May be zero.
*
* [ 1, nil, 3, nil, 5 ].nitems #=> 3
* [5,6,7,8,9].nitems { |x| x % 2 != 0 } #=> 3
*/
static VALUE
@ -3049,24 +3045,54 @@ rb_ary_nitems(ary)
VALUE ary;
{
long n = 0;
VALUE *p, *pend;
if (rb_block_given_p()) {
long i;
for (p = RARRAY(ary)->ptr, pend = p + RARRAY(ary)->len; p < pend; p++) {
if (!NIL_P(*p)) n++;
}
return LONG2NUM(n);
}
for (i=0; i<RARRAY(ary)->len; i++) {
VALUE v = RARRAY(ary)->ptr[i];
if (RTEST(rb_yield(v))) n++;
/*
* call-seq:
* array.count(obj) -> int
* array.count { |item| block } -> int
*
* Returns the number of elements which equals to <i>obj</i>.
* If a block is given, counts tthe number of elements yielding a true value.
*
* ary = [1, 2, 4, 2]
* ary.count(2) # => 2
* ary.count{|x|x%2==0} # => 3
*
*/
static VALUE
rb_ary_count(int argc, VALUE *argv, VALUE ary)
{
long n = 0;
if (argc == 0) {
VALUE *p, *pend;
RETURN_ENUMERATOR(ary, 0, 0);
for (p = RARRAY_PTR(ary), pend = p + RARRAY_LEN(ary); p < pend; p++) {
if (RTEST(rb_yield(*p))) n++;
}
}
else {
VALUE *p = RARRAY(ary)->ptr;
VALUE *pend = p + RARRAY(ary)->len;
VALUE obj, *p, *pend;
while (p < pend) {
if (!NIL_P(*p)) n++;
p++;
rb_scan_args(argc, argv, "1", &obj);
if (rb_block_given_p()) {
rb_warn("given block not used");
}
for (p = RARRAY_PTR(ary), pend = p + RARRAY_LEN(ary); p < pend; p++) {
if (rb_equal(*p, obj)) n++;
}
}
return LONG2NUM(n);
}
@ -3789,6 +3815,7 @@ Init_Array()
rb_define_method(rb_cArray, "flatten", rb_ary_flatten, -1);
rb_define_method(rb_cArray, "flatten!", rb_ary_flatten_bang, -1);
rb_define_method(rb_cArray, "nitems", rb_ary_nitems, 0);
rb_define_method(rb_cArray, "count", rb_ary_count, -1);
rb_define_method(rb_cArray, "shuffle!", rb_ary_shuffle_bang, 0);
rb_define_method(rb_cArray, "shuffle", rb_ary_shuffle, 0);
rb_define_method(rb_cArray, "choice", rb_ary_choice, 0);

View file

@ -2,7 +2,8 @@ bin: $(PROGRAM) $(WPROGRAM)
lib: $(LIBRUBY)
dll: $(LIBRUBY_SO)
RUBYOPT =
RUBYLIB = -
RUBYOPT = -
STATIC_RUBY = static-ruby

View file

@ -1402,6 +1402,7 @@ if test x"$cross_compiling" = xyes; then
RUNRUBY='$(MINIRUBY) -I`cd $(srcdir)/lib; pwd`'
else
MINIRUBY='./miniruby$(EXEEXT) -I$(srcdir)/lib'
MINIRUBY="$MINIRUBY"' -I$(EXTOUT)/common -I./- -r$(srcdir)/ext/purelib.rb'
PREP='miniruby$(EXEEXT)'
RUNRUBY='$(MINIRUBY) $(srcdir)/runruby.rb --extout=$(EXTOUT)'
fi

View file

@ -254,6 +254,14 @@ void rb_ia64_flushrs(void);
#define ENV_IGNORECASE
#endif
#ifndef CASEFOLD_FILESYSTEM
# if defined DOSISH || defined __VMS
# define CASEFOLD_FILESYSTEM 1
# else
# define CASEFOLD_FILESYSTEM 0
# endif
#endif
#ifndef DLEXT_MAXLEN
#define DLEXT_MAXLEN 4
#endif

40
enum.c
View file

@ -843,18 +843,6 @@ enum_sort_by(obj)
return ary;
}
static VALUE
all_iter_i(i, memo)
VALUE i;
VALUE *memo;
{
if (!RTEST(rb_yield(i))) {
*memo = Qfalse;
rb_iter_break();
}
return Qnil;
}
static VALUE
all_i(i, memo)
VALUE i;
@ -867,6 +855,14 @@ all_i(i, memo)
return Qnil;
}
static VALUE
all_iter_i(i, memo)
VALUE i;
VALUE *memo;
{
return all_i(rb_yield(i), memo);
}
/*
* call-seq:
* enum.all? [{|obj| block } ] => true or false
@ -894,18 +890,6 @@ enum_all(obj)
return result;
}
static VALUE
any_iter_i(i, memo)
VALUE i;
VALUE *memo;
{
if (RTEST(rb_yield(i))) {
*memo = Qtrue;
rb_iter_break();
}
return Qnil;
}
static VALUE
any_i(i, memo)
VALUE i;
@ -918,6 +902,14 @@ any_i(i, memo)
return Qnil;
}
static VALUE
any_iter_i(i, memo)
VALUE i;
VALUE *memo;
{
return any_i(rb_yield(i), memo);
}
/*
* call-seq:
* enum.any? [{|obj| block } ] => true or false

View file

@ -72,16 +72,6 @@ enumerator_ptr(obj)
return ptr;
}
static VALUE enumerator_iter_i _((VALUE, VALUE));
static VALUE
enumerator_iter_i(i, enum_obj)
VALUE i;
VALUE enum_obj;
{
struct enumerator *e = (struct enumerator *)enum_obj;
return rb_yield(proc_call(e->proc, i));
}
/*
* call-seq:
* obj.to_enum(method = :each, *args)
@ -138,8 +128,10 @@ each_slice_i(val, memo)
/*
* call-seq:
* e.each_slice(n) {...}
* e.each_slice(n)
*
* Iterates the given block for each slice of <n> elements.
* Iterates the given block for each slice of <n> elements. If no
* block is given, returns an enumerator.
*
* e.g.:
* (1..10).each_slice(3) {|a| p a}
@ -192,9 +184,10 @@ each_cons_i(val, memo)
/*
* call-seq:
* each_cons(n) {...}
* each_cons(n)
*
* Iterates the given block for each array of consecutive <n>
* elements.
* elements. If no block is given, returns an enumerator.a
*
* e.g.:
* (1..10).each_cons(3) {|a| p a}
@ -271,12 +264,8 @@ enumerator_init(enum_obj, obj, meth, argc, argv)
* used as an Enumerable object using the given object's given
* method with the given arguments.
*
* e.g.:
* str = "xyz"
*
* enum = Enumerable::Enumerator.new(str, :each_byte)
* a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"]
*
* Use of this method is not discouraged. Use Kernel#enum_for()
* instead.
*/
static VALUE
enumerator_initialize(argc, argv, obj)
@ -330,7 +319,7 @@ rb_enumeratorize(obj, meth, argc, argv)
* enum.each {...}
*
* Iterates the given block using the object and the method specified
* in the first place.
* in the first place. If no block is given, returns self.
*
*/
static VALUE
@ -340,7 +329,6 @@ enumerator_each(obj)
struct enumerator *e;
int argc = 0;
VALUE *argv = 0;
VALUE method;
if (!rb_block_given_p()) return obj;
e = enumerator_ptr(obj);
@ -364,9 +352,10 @@ enumerator_with_index_i(val, memo)
/*
* call-seq:
* e.with_index {|(*args), idx| ... }
* e.with_index
*
* Iterates the given block for each elements with an index, which
* start from 0.
* start from 0. If no block is given, returns an enumerator.
*
*/
static VALUE
@ -377,7 +366,6 @@ enumerator_with_index(obj)
VALUE memo = 0;
int argc = 0;
VALUE *argv = 0;
VALUE method;
RETURN_ENUMERATOR(obj, 0, 0);
if (e->args) {

4
eval.c
View file

@ -2440,6 +2440,8 @@ is_defined(self, node, buf)
case NODE_ATTRSET:
case NODE_OP_ASGN1:
case NODE_OP_ASGN2:
case NODE_OP_ASGN_OR:
case NODE_OP_ASGN_AND:
case NODE_MASGN:
case NODE_LASGN:
case NODE_DASGN:
@ -9917,6 +9919,8 @@ Init_Proc()
rb_define_method(rb_cUnboundMethod, "arity", method_arity, 0);
rb_define_method(rb_cUnboundMethod, "inspect", method_inspect, 0);
rb_define_method(rb_cUnboundMethod, "to_s", method_inspect, 0);
rb_define_method(rb_cUnboundMethod, "name", method_name, 0);
rb_define_method(rb_cUnboundMethod, "owner", method_owner, 0);
rb_define_method(rb_cUnboundMethod, "bind", umethod_bind, 1);
rb_define_method(rb_cModule, "instance_method", rb_mod_method, 1);
}

View file

@ -812,5 +812,7 @@ Init_dbm()
#ifdef DB_VERSION_STRING
rb_define_const(rb_cDBM, "VERSION", rb_str_new2(DB_VERSION_STRING));
#else
rb_define_const(rb_cDBM, "VERSION", rb_str_new2("unknown"));
#endif
}

View file

@ -1,3 +1,3 @@
if nul = $:.index("-")
if nul = $:.find_index {|path| /\A(?:\.\/)*-\z/ =~ path}
$:[nul..-1] = ["."]
end

View file

@ -1,3 +1,9 @@
2008-05-12 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* ext/tk/lib/tkextlib/tkDND/shape.rb: wrong package name.
--------------< ... some changes ... >------------------
2007-05-26 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* ext/tk/lib/tkextlib/tcllib/tablelist.rb: fix typo.

View file

@ -775,7 +775,7 @@ end
private :_curr_cmd_id, :_next_cmd_id
module_function :_curr_cmd_id, :_next_cmd_id
def TkComm.install_cmd(cmd)
def TkComm.install_cmd(cmd, local_cmdtbl=nil)
return '' if cmd == ''
begin
ns = TkCore::INTERP._invoke_without_enc('namespace', 'current')
@ -794,6 +794,15 @@ end
@cmdtbl = [] unless defined? @cmdtbl
@cmdtbl.taint unless @cmdtbl.tainted?
@cmdtbl.push id
if local_cmdtbl && local_cmdtbl.kind_of?(Array)
begin
local_cmdtbl << id
rescue Exception
# ignore
end
end
#return Kernel.format("rb_out %s", id);
if ns
'rb_out' << TkCore::INTERP._ip_id_ << ' ' << ns << ' ' << id
@ -801,19 +810,29 @@ end
'rb_out' << TkCore::INTERP._ip_id_ << ' ' << id
end
end
def TkComm.uninstall_cmd(id)
def TkComm.uninstall_cmd(id, local_cmdtbl=nil)
#id = $1 if /rb_out\S* (c(_\d+_)?\d+)/ =~ id
id = $4 if id =~ /rb_out\S*(?:\s+(::\S*|[{](::.*)[}]|["](::.*)["]))? (c(_\d+_)?(\d+))/
if local_cmdtbl && local_cmdtbl.kind_of?(Array)
begin
local_cmdtbl.delete(id)
rescue Exception
# ignore
end
end
@cmdtbl.delete(id)
#Tk_CMDTBL.delete(id)
TkCore::INTERP.tk_cmd_tbl.delete(id)
end
# private :install_cmd, :uninstall_cmd
# module_function :install_cmd, :uninstall_cmd
def install_cmd(cmd)
TkComm.install_cmd(cmd)
TkComm.install_cmd(cmd, @cmdtbl)
end
def uninstall_cmd(id)
TkComm.uninstall_cmd(id)
TkComm.uninstall_cmd(id, @cmdtbl)
end
=begin
@ -1447,7 +1466,9 @@ module TkCore
def after(ms, cmd=Proc.new)
cmdid = install_cmd(proc{ret = cmd.call;uninstall_cmd(cmdid); ret})
tk_call_without_enc("after",ms,cmdid) # return id
after_id = tk_call_without_enc("after",ms,cmdid)
after_id.instance_variable_set('@cmdid', cmdid)
after_id
end
=begin
def after(ms, cmd=Proc.new)
@ -1477,7 +1498,9 @@ module TkCore
def after_idle(cmd=Proc.new)
cmdid = install_cmd(proc{ret = cmd.call;uninstall_cmd(cmdid); ret})
tk_call_without_enc('after','idle',cmdid)
after_id = tk_call_without_enc('after','idle',cmdid)
after_id.instance_variable_set('@cmdid', cmdid)
after_id
end
=begin
def after_idle(cmd=Proc.new)
@ -1495,6 +1518,11 @@ module TkCore
def after_cancel(afterId)
tk_call_without_enc('after','cancel',afterId)
if (cmdid = afterId.instance_variable_get('@cmdid'))
afterId.instance_variable_set('@cmdid', nil)
uninstall_cmd(cmdid)
end
afterId
end
def windowingsystem
@ -4947,6 +4975,15 @@ class TkWindow<TkObject
self
end
def grid_anchor(anchor=None)
if anchor == None
TkGrid.anchor(self)
else
TkGrid.anchor(self, anchor)
self
end
end
def grid_forget
#tk_call('grid', 'forget', epath)
TkGrid.forget(self)
@ -4978,12 +5015,14 @@ class TkWindow<TkObject
TkGrid.columnconfigure(self, index, keys)
end
alias grid_columnconfigure grid_columnconfig
alias grid_column grid_columnconfig
def grid_rowconfig(index, keys)
#tk_call('grid', 'rowconfigure', epath, index, *hash_kv(keys))
TkGrid.rowconfigure(self, index, keys)
end
alias grid_rowconfigure grid_rowconfig
alias grid_row grid_rowconfig
def grid_columnconfiginfo(index, slot=nil)
#if slot
@ -5226,11 +5265,13 @@ class TkWindow<TkObject
end
children.each{|path, obj|
obj.instance_eval{
if defined?(@cmdtbl)
for id in @cmdtbl
uninstall_cmd id
end
end
}
TkCore::INTERP.tk_windows.delete(path)
}
@ -5348,7 +5389,7 @@ TkWidget = TkWindow
#Tk.freeze
module Tk
RELEASE_DATE = '2008-04-18'.freeze
RELEASE_DATE = '2008-05-16'.freeze
autoload :AUTO_PATH, 'tk/variable'
autoload :TCL_PACKAGE_PATH, 'tk/variable'

View file

@ -352,6 +352,14 @@ module TkEvent
nil
]
# [ <'%' subst-key str>, <proc type char>, <instance var (accessor) name>]
# the subst-key string will be converted to a bytecode (128+idx).
LONGKEY_TBL = [
# for example, for %CTT and %CST subst-key on tkdnd-2.0
# ['CTT', ?l, :drop_target_type],
# ['CST', ?l, :drop_source_type],
]
# [ <proc type char>, <proc/method to convert tcl-str to ruby-obj>]
PROC_TBL = [
[ ?n, TkComm.method(:num_or_str) ],
@ -371,6 +379,7 @@ module TkEvent
nil
]
=begin
# for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
KEY_TBL.map!{|inf|
if inf.kind_of?(Array)
@ -386,6 +395,7 @@ module TkEvent
end
inf
}
=end
# setup tables to be used by scan_args, _get_subst_key, _get_all_subst_keys
#
@ -399,7 +409,8 @@ module TkEvent
# ( which are Tcl strings ) to ruby objects based on the key string
# that is generated by _get_subst_key() or _get_all_subst_keys().
#
_setup_subst_table(KEY_TBL, PROC_TBL);
_setup_subst_table(KEY_TBL, PROC_TBL)
# _setup_subst_table(KEY_TBL, LONGKEY_TBL, PROC_TBL) # if use longname-keys
#
# NOTE: The order of parameters which passed to callback procedure is
@ -447,6 +458,7 @@ module TkEvent
extra_args_tbl = klass._get_extra_args_tbl
if args.compact.size > 0
args.map!{|arg| klass._sym2subst(arg)}
args = args.join(' ')
keys = klass._get_subst_key(args)

View file

@ -22,6 +22,7 @@ module TkGrid
list(tk_call_without_enc('grid', 'bbox', *args))
end
=begin
def configure(win, *args)
if args[-1].kind_of?(Hash)
opts = args.pop
@ -53,6 +54,48 @@ module TkGrid
tk_call_without_enc('grid', 'configure', *params)
end
end
=end
def configure(*args)
if args[-1].kind_of?(Hash)
opts = args.pop
else
opts = {}
end
fail ArgumentError, 'no widget is given' if args.empty?
params = []
args.flatten(1).each{|win|
case win
when '-', ?- # RELATIVE PLACEMENT (increase columnspan)
params.push('-')
when /^-+$/ # RELATIVE PLACEMENT (increase columnspan)
params.concat(win.to_s.split(//))
when '^', ?^ # RELATIVE PLACEMENT (increase rowspan)
params.push('^')
when /^\^+$/ # RELATIVE PLACEMENT (increase rowspan)
params.concat(win.to_s.split(//))
when 'x', :x, ?x, nil, '' # RELATIVE PLACEMENT (empty column)
params.push('x')
when /^x+$/ # RELATIVE PLACEMENT (empty column)
params.concat(win.to_s.split(//))
else
params.push(_epath(win))
end
}
opts.each{|k, v|
params.push("-#{k}")
params.push(_epath(v)) # have to use 'epath' (hash_kv() is unavailable)
}
if Tk::TCL_MAJOR_VERSION < 8 ||
(Tk::TCL_MAJOR_VERSION == 8 && Tk::TCL_MINOR_VERSION <= 3)
if params[0] == '-' || params[0] == 'x' || params[0] == '^'
tk_call_without_enc('grid', *params)
else
tk_call_without_enc('grid', 'configure', *params)
end
else
tk_call_without_enc('grid', 'configure', *params)
end
end
alias grid configure
def columnconfigure(master, index, args)
@ -61,12 +104,14 @@ module TkGrid
tk_call_without_enc("grid", 'columnconfigure',
master, index, *hash_kv(args))
end
alias column columnconfigure
def rowconfigure(master, index, args)
# master = master.epath if master.kind_of?(TkObject)
master = _epath(master)
tk_call_without_enc("grid", 'rowconfigure', master, index, *hash_kv(args))
end
alias row rowconfigure
def columnconfiginfo(master, index, slot=nil)
# master = master.epath if master.kind_of?(TkObject)
@ -189,10 +234,10 @@ module TkGrid
list(tk_call_without_enc('grid', 'slaves', master, *hash_kv(args)))
end
module_function :bbox, :forget, :propagate, :info
module_function :anchor, :bbox, :add, :forget, :propagate, :info
module_function :remove, :size, :slaves, :location
module_function :grid, :configure, :columnconfigure, :rowconfigure
module_function :columnconfiginfo, :rowconfiginfo
module_function :column, :row, :columnconfiginfo, :rowconfiginfo
end
=begin
def TkGrid(win, *args)

View file

@ -9,6 +9,7 @@ module TkPack
TkCommandNames = ['pack'.freeze].freeze
=begin
def configure(win, *args)
if args[-1].kind_of?(Hash)
opts = args.pop
@ -29,6 +30,22 @@ module TkPack
}
tk_call_without_enc("pack", 'configure', *params)
end
=end
def configure(*args)
if args[-1].kind_of?(Hash)
opts = args.pop
else
opts = {}
end
fail ArgumentError, 'no widget is given' if args.empty?
params = []
args.flatten(1).each{|win| params.push(_epath(win))}
opts.each{|k, v|
params.push("-#{k}")
params.push(_epath(v)) # have to use 'epath' (hash_kv() is unavailable)
}
tk_call_without_enc("pack", 'configure', *params)
end
alias pack configure
def forget(*args)

View file

@ -37,6 +37,7 @@ class Tk::Spinbox<Tk::Entry
nil
]
=begin
# for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
KEY_TBL.map!{|inf|
if inf.kind_of?(Array)
@ -52,6 +53,7 @@ class Tk::Spinbox<Tk::Entry
end
inf
}
=end
_setup_subst_table(KEY_TBL, PROC_TBL);

View file

@ -50,7 +50,8 @@ module Tk
key2class.each{|key, klass|
if keys[key].kind_of?(Array)
cmd, *args = keys[key]
keys[key] = klass.new(cmd, args.join(' '))
#keys[key] = klass.new(cmd, args.join(' '))
keys[key] = klass.new(cmd, *args)
# elsif keys[key].kind_of?(Proc) || keys[key].kind_of?(Method)
elsif TkComm._callback_entry?(keys[key])
keys[key] = klass.new(keys[key])
@ -151,7 +152,8 @@ module Tk
key2class.each{|key, klass|
if keys[key].kind_of?(Array)
cmd, *args = keys[key]
keys[key] = klass.new(cmd, args.join(' '))
#keys[key] = klass.new(cmd, args.join(' '))
keys[key] = klass.new(cmd, *args)
# elsif keys[key].kind_of?(Proc) || keys[key].kind_of?(Method)
elsif TkComm._callback_entry?(keys[key])
keys[key] = klass.new(keys[key])
@ -249,6 +251,7 @@ class TkValidateCommand
nil
]
=begin
# for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
KEY_TBL.map!{|inf|
if inf.kind_of?(Array)
@ -264,6 +267,7 @@ class TkValidateCommand
end
inf
}
=end
_setup_subst_table(KEY_TBL, PROC_TBL);
@ -293,6 +297,7 @@ class TkValidateCommand
extra_args_tbl = klass._get_extra_args_tbl
if args.compact.size > 0
args.map!{|arg| klass._sym2subst(arg)}
args = args.join(' ')
keys = klass._get_subst_key(args)
if cmd.kind_of?(String)

View file

@ -362,7 +362,7 @@ module Tk
end
end
def overrideredirect(mode=TkComm::None)
Wm.overrideredirect(self, mode=TkComm::None)
Wm.overrideredirect(self, mode)
end
alias wm_overrideredirect overrideredirect
TOPLEVEL_METHODCALL_OPTKEYS['overrideredirect'] = 'overrideredirect'
@ -545,7 +545,7 @@ module Tk
module Wm_for_General
Wm.instance_methods.each{|m|
if (m = m.to_s) =~ /^wm_(.*)$/
eval "def #{m}(*args); Tk::Wm.#{$1}(self, *args); end"
eval "def #{m}(*args, &b); Tk::Wm.#{$1}(self, *args, &b); end"
end
}
end

View file

@ -81,6 +81,7 @@ module Tk::BLT
nil
]
=begin
# for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
KEY_TBL.map!{|inf|
if inf.kind_of?(Array)
@ -96,6 +97,7 @@ module Tk::BLT
end
inf
}
=end
_setup_subst_table(KEY_TBL, PROC_TBL)
@ -123,6 +125,7 @@ module Tk::BLT
nil
]
=begin
# for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
KEY_TBL.map!{|inf|
if inf.kind_of?(Array)
@ -138,6 +141,7 @@ module Tk::BLT
end
inf
}
=end
_setup_subst_table(KEY_TBL, PROC_TBL)
@ -177,6 +181,7 @@ module Tk::BLT
nil
]
=begin
# for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
KEY_TBL.map!{|inf|
if inf.kind_of?(Array)
@ -192,6 +197,7 @@ module Tk::BLT
end
inf
}
=end
_setup_subst_table(KEY_TBL, PROC_TBL)
end

View file

@ -239,6 +239,7 @@ class Tk::BLT::Treeview
nil
]
=begin
# for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
KEY_TBL.map!{|inf|
if inf.kind_of?(Array)
@ -254,6 +255,7 @@ class Tk::BLT::Treeview
end
inf
}
=end
_setup_subst_table(KEY_TBL, PROC_TBL);
@ -492,6 +494,7 @@ class Tk::BLT::Treeview
nil
]
=begin
# for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
KEY_TBL.map!{|inf|
if inf.kind_of?(Array)
@ -507,6 +510,7 @@ class Tk::BLT::Treeview
end
inf
}
=end
_setup_subst_table(KEY_TBL, PROC_TBL);
@ -523,7 +527,8 @@ class Tk::BLT::Treeview
def _find_exec_flag_value(val)
if val.kind_of?(Array)
cmd, *args = val
FindExecFlagValue.new(cmd, args.join(' '))
#FindExecFlagValue.new(cmd, args.join(' '))
FindExecFlagValue.new(cmd, *args)
elsif TkComm._callback_entry?(val)
FindExecFlagValue.new(val)
else

View file

@ -46,6 +46,7 @@ class Tk::Iwidgets::Calendar
KEY_TBL = [ [?d, ?s, :date], nil ]
PROC_TBL = [ [?s, TkComm.method(:string) ], nil ]
=begin
# for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
KEY_TBL.map!{|inf|
if inf.kind_of?(Array)
@ -61,6 +62,7 @@ class Tk::Iwidgets::Calendar
end
inf
}
=end
_setup_subst_table(KEY_TBL, PROC_TBL);

View file

@ -43,6 +43,7 @@ class Tk::Iwidgets::Entryfield
nil
]
=begin
# for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
KEY_TBL.map!{|inf|
if inf.kind_of?(Array)
@ -58,6 +59,7 @@ class Tk::Iwidgets::Entryfield
end
inf
}
=end
_setup_subst_table(KEY_TBL, PROC_TBL);
end

View file

@ -31,6 +31,7 @@ class Tk::Iwidgets::Hierarchy
KEY_TBL = [ [?n, ?s, :node], nil ]
PROC_TBL = [ [?s, TkComm.method(:string) ], nil ]
=begin
# for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
KEY_TBL.map!{|inf|
if inf.kind_of?(Array)
@ -46,6 +47,7 @@ class Tk::Iwidgets::Hierarchy
end
inf
}
=end
_setup_subst_table(KEY_TBL, PROC_TBL);
@ -74,6 +76,7 @@ class Tk::Iwidgets::Hierarchy
nil
]
=begin
# for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
KEY_TBL.map!{|inf|
if inf.kind_of?(Array)
@ -89,6 +92,7 @@ class Tk::Iwidgets::Hierarchy
end
inf
}
=end
_setup_subst_table(KEY_TBL, PROC_TBL);
@ -112,6 +116,7 @@ class Tk::Iwidgets::Hierarchy
]
PROC_TBL = [ [ ?s, TkComm.method(:string) ], nil ]
=begin
# for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
KEY_TBL.map!{|inf|
if inf.kind_of?(Array)
@ -127,6 +132,7 @@ class Tk::Iwidgets::Hierarchy
end
inf
}
=end
_setup_subst_table(KEY_TBL, PROC_TBL);

View file

@ -38,6 +38,7 @@ class Tk::Iwidgets::Spinner
nil
]
=begin
# for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
KEY_TBL.map!{|inf|
if inf.kind_of?(Array)
@ -53,6 +54,7 @@ class Tk::Iwidgets::Spinner
end
inf
}
=end
_setup_subst_table(KEY_TBL, PROC_TBL);
end

View file

@ -201,6 +201,38 @@ module Tk
args.map!{|arg| TkComm._get_eval_string(arg)}.join('.')
end
def self.themes(glob_ptn = nil)
if TILE_SPEC_VERSION_ID < 8 && Tk.info(:commands, '::ttk::themes').empty?
fail RuntimeError, 'not support glob option' if glob_ptn
cmd = ['::tile::availableThemes']
else
glob_ptn = '*' unless glob_ptn
cmd = ['::ttk::themes', glob_ptn]
end
begin
TkComm.simplelist(Tk.tk_call_without_enc(*cmd))
rescue
TkComm.simplelist(Tk.tk_call('lsearch', '-all', '-inline',
Tk::Tile::Style.theme_names,
glob_ptn))
end
end
def self.set_theme(theme)
if TILE_SPEC_VERSION_ID < 8 && Tk.info(:commands, '::ttk::setTheme').empty?
cmd = '::tile::setTheme'
else
cmd = '::ttk::setTheme'
end
begin
Tk.tk_call_without_enc(cmd, theme)
rescue
Tk::Tile::Style.theme_use(theme)
end
end
module KeyNav
if Tk::Tile::TILE_SPEC_VERSION_ID < 8
def self.enableMnemonics(w)
@ -332,12 +364,16 @@ module Tk
autoload :TLabelframe, 'tkextlib/tile/tlabelframe'
autoload :Labelframe, 'tkextlib/tile/tlabelframe'
autoload :TLabelFrame, 'tkextlib/tile/tlabelframe'
autoload :LabelFrame, 'tkextlib/tile/tlabelframe'
autoload :TLabel, 'tkextlib/tile/tlabel'
autoload :Label, 'tkextlib/tile/tlabel'
autoload :TMenubutton, 'tkextlib/tile/tmenubutton'
autoload :Menubutton, 'tkextlib/tile/tmenubutton'
autoload :TMenuButton, 'tkextlib/tile/tmenubutton'
autoload :MenuButton, 'tkextlib/tile/tmenubutton'
autoload :TNotebook, 'tkextlib/tile/tnotebook'
autoload :Notebook, 'tkextlib/tile/tnotebook'

View file

@ -33,6 +33,8 @@ class << Tk::Tile::Style
# conflict with some definitions on Tcl/Tk scripts.
if Tk::Tile::TILE_SPEC_VERSION_ID < 7
def __define_wrapper_proc_for_compatibility__!
__define_themes_and_setTheme_proc__!
unless Tk.info(:commands, '::ttk::style').empty?
# fail RuntimeError,
# "can't define '::ttk::style' command (already exist)"
@ -59,6 +61,8 @@ class << Tk::Tile::Style
end
else ### TILE_SPEC_VERSION_ID == 7
def __define_wrapper_proc_for_compatibility__!
__define_themes_and_setTheme_proc__!
unless Tk.info(:commands, '::ttk::style').empty?
# fail RuntimeError,
# "can't define '::ttk::style' command (already exist)"
@ -91,6 +95,8 @@ class << Tk::Tile::Style
TkCommandNames = ['::ttk::style'.freeze].freeze
def __define_wrapper_proc_for_compatibility__!
__define_themes_and_setTheme_proc__!
unless Tk.info(:commands, '::style').empty?
# fail RuntimeError, "can't define '::style' command (already exist)"
@ -120,6 +126,36 @@ class << Tk::Tile::Style
end
end
def __define_themes_and_setTheme_proc__!
TkCore::INTERP.add_tk_procs('::ttk::themes', '{ptn *}', <<-'EOS')
#set themes [list]
set themes [::ttk::style theme names]
foreach pkg [lsearch -inline -all -glob [package names] ttk::theme::$ptn] {
set theme [namespace tail $pkg]
if {[lsearch -exact $themes $theme] < 0} {
lappend themes $theme
}
}
foreach pkg [lsearch -inline -all -glob [package names] tile::theme::$ptn] {
set theme [namespace tail $pkg]
if {[lsearch -exact $themes $theme] < 0} {
lappend themes $theme
}
}
return $themes
EOS
#########################
TkCore::INTERP.add_tk_procs('::ttk::setTheme', 'theme', <<-'EOS')
variable currentTheme
if {[lsearch -exact [::ttk::style theme names] $theme] < 0} {
package require [lsearch -inline -regexp [package names] (ttk|tile)::theme::$theme]
}
::ttk::style theme use $theme
set currentTheme $theme
EOS
end
private :__define_themes_and_setTheme_proc__!
def configure(style=nil, keys=nil)
if style.kind_of?(Hash)
keys = style

View file

@ -77,9 +77,9 @@ class Tk::Tile::TNotebook < TkWindow
def add(child, keys=nil)
if keys && keys != None
tk_send_without_enc('add', _epath(child), *hash_kv(keys))
tk_send('add', _epath(child), *hash_kv(keys))
else
tk_send_without_enc('add', _epath(child))
tk_send('add', _epath(child))
end
self
end

View file

@ -11,15 +11,15 @@ require 'tkextlib/setup.rb'
# call setup script
require 'tkextlib/tkDND/setup.rb'
# TkPackage.require('shape', '0.3')
TkPackage.require('shape')
# TkPackage.require('Shape', '0.3')
TkPackage.require('Shape')
module Tk
module TkDND
module Shape
extend TkCore
PACKAGE_NAME = 'shape'.freeze
PACKAGE_NAME = 'Shape'.freeze
def self.package_name
PACKAGE_NAME
end
@ -27,26 +27,28 @@ module Tk
=begin
def self.package_version
begin
TkPackage.require('shape')
TkPackage.require('Shape')
rescue
''
end
end
=end
def self.package_version
class << self
def package_version
Tk.tk_call('set', 'shape_version')
end
alias shape_version package_version
def self.package_patchlevel
Tk.tk_call('set', 'shape_patchlevel')
def package_patchlevel
Tk.tk_call('set', 'shape_patchLevel')
end
alias shape_patchlevel package_patchlevel
def self.version
def version
tk_call('shape', 'version')
end
alias xshape_version version
end
############################

View file

@ -57,6 +57,7 @@ module Tk
nil
]
=begin
# for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
KEY_TBL.map!{|inf|
if inf.kind_of?(Array)
@ -72,6 +73,7 @@ module Tk
end
inf
}
=end
# setup tables
_setup_subst_table(KEY_TBL, PROC_TBL);

View file

@ -291,6 +291,7 @@ class Tk::TkTable
nil
]
=begin
# for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
KEY_TBL.map!{|inf|
if inf.kind_of?(Array)
@ -306,6 +307,7 @@ class Tk::TkTable
end
inf
}
=end
_setup_subst_table(KEY_TBL, PROC_TBL);
@ -340,6 +342,7 @@ class Tk::TkTable
nil
]
=begin
# for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
KEY_TBL.map!{|inf|
if inf.kind_of?(Array)
@ -355,6 +358,7 @@ class Tk::TkTable
end
inf
}
=end
_setup_subst_table(KEY_TBL, PROC_TBL);
@ -387,6 +391,7 @@ class Tk::TkTable
nil
]
=begin
# for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
KEY_TBL.map!{|inf|
if inf.kind_of?(Array)
@ -402,6 +407,7 @@ class Tk::TkTable
end
inf
}
=end
_setup_subst_table(KEY_TBL, PROC_TBL);
@ -437,6 +443,7 @@ class Tk::TkTable
nil
]
=begin
# for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
KEY_TBL.map!{|inf|
if inf.kind_of?(Array)
@ -452,6 +459,7 @@ class Tk::TkTable
end
inf
}
=end
_setup_subst_table(KEY_TBL, PROC_TBL);
end

View file

@ -137,6 +137,7 @@ class Tk::TreeCtrl::NotifyEvent
nil
]
=begin
# for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
KEY_TBL.map!{|inf|
if inf.kind_of?(Array)
@ -152,6 +153,7 @@ class Tk::TreeCtrl::NotifyEvent
end
inf
}
=end
# setup tables to be used by scan_args, _get_subst_key, _get_all_subst_keys
#

View file

@ -2,5 +2,5 @@
# release date of tkextlib
#
module Tk
Tkextlib_RELEASE_DATE = '2008-04-18'.freeze
Tkextlib_RELEASE_DATE = '2008-05-14'.freeze
end

View file

@ -150,6 +150,7 @@ class Tk::Winico
nil
]
=begin
# for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
KEY_TBL.map!{|inf|
if inf.kind_of?(Array)
@ -165,6 +166,7 @@ class Tk::Winico
end
inf
}
=end
_setup_subst_table(KEY_TBL, PROC_TBL);
@ -185,7 +187,8 @@ class Tk::Winico
Winico_callback._config_keys.each{|k|
if keys[k].kind_of?(Array)
cmd, *args = keys[k]
keys[k] = Winico_callback.new(cmd, args.join(' '))
#keys[k] = Winico_callback.new(cmd, args.join(' '))
keys[k] = Winico_callback.new(cmd, *args)
# elsif keys[k].kind_of?(Proc)
elsif TkComm._callback_entry?(keys[k])
keys[k] = Winico_callback.new(keys[k])
@ -201,7 +204,8 @@ class Tk::Winico
Winico_callback._config_keys.each{|k|
if keys[k].kind_of?(Array)
cmd, *args = keys[k]
keys[k] = Winico_callback.new(cmd, args.join(' '))
#keys[k] = Winico_callback.new(cmd, args.join(' '))
keys[k] = Winico_callback.new(cmd, *args)
# elsif keys[k].kind_of?(Proc)
elsif TkComm._callback_entry?(keys[k])
keys[k] = Winico_callback.new(keys[k])

View file

@ -58,6 +58,7 @@ class AnimatedWaveDemo
@backupCoords = []
n = 0
(-10..300).step(5){|n| @waveCoords << [n, 100]; @backupCoords << [n, 100] }
n = 305
@waveCoords << [n, 0]; @backupCoords << [n, 0]
@waveCoords << [n+5, 200]; @backupCoords << [n+5, 200]
@coordsLen = @waveCoords.length

View file

@ -60,6 +60,7 @@ class AnimatedWaveDemo
@backupCoords = []
n = 0
(-10..300).step(5){|n| @waveCoords << [n, 100]; @backupCoords << [n, 100] }
n = 305
@waveCoords << [n, 0]; @backupCoords << [n, 0]
@waveCoords << [n+5, 200]; @backupCoords << [n+5, 200]
@coordsLen = @waveCoords.length

View file

@ -4,7 +4,7 @@
#
# by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)
#
version = '0.1.1'
version = '0.1.3'
#
##########################################################################
# parse commandline arguments
@ -107,38 +107,37 @@ TkConfigMethod.__set_IGNORE_UNKNOWN_CONFIGURE_OPTION__! true
TkItemConfigMethod.__set_IGNORE_UNKNOWN_CONFIGURE_OPTION__! true
##########################################################################
# define utility method
##########################################################################
def setTheme(theme)
unless Tk::Tile::Style.theme_names.find{|n| n == theme}
if (pkg = TkPackage.names.find{|n| n =~ /(tile|ttk)::theme::#{theme}/})
TkPackage.require(pkg)
end
end
Tk::Tile::Style.theme_use(theme)
end
##########################################################################
# make theme name list
##########################################################################
ThemesList = Tk::Tile::Style.theme_names
TkPackage.names.find_all{|n| n =~ /^(tile|ttk)::theme::/}.each{|pkg|
ThemesList << pkg.split('::')[-1]
}
ThemesList.uniq!
##########################################################################
# set theme of widget style
##########################################################################
if OPTS[:list] || OPTS[:verbose]
print "supported theme names: #{ThemesList.inspect}\n"
print "supported theme names: #{Tk::Tile.themes.inspect}\n"
exit if OPTS[:list] && ARGV.empty?
end
print "use theme: \"#{OPTS[:theme]}\"\n" if OPTS[:theme] && OPTS[:verbose]
setTheme(OPTS[:theme]) if OPTS[:theme]
#setTheme(OPTS[:theme]) if OPTS[:theme]
Tk::Tile.set_theme(OPTS[:theme]) if OPTS[:theme]
##########################################################################
# replace $0 and $RPAGRAM_NAME
##########################################################################
# When the expand_path of the target script is long, ruby sometimes
# fails to set the path to $0 (the path string is trimmed).
# The following replaces $0 and $PROGNAME to avoid such trouble.
progname_obj = $0.dup
$program_name = progname_obj
alias $REAL_PROGRAM_NAME $0
alias $PROGRAM_NAME $program_name
alias $0 $program_name
trace_var(:$program_name){|val|
unless progname_obj.object_id == val.object_id
progname_obj.replace(val.to_s)
$program_name = progname_obj
end
}
##########################################################################
@ -146,6 +145,7 @@ setTheme(OPTS[:theme]) if OPTS[:theme]
##########################################################################
if (path = ARGV.shift) && (script = File.expand_path(path))
print "load script \"#{script}\"\n" if OPTS[:verbose]
$0 = script
load(script)
else
print "Error: no script is given.\n"

View file

@ -4,7 +4,7 @@
* Oct. 24, 1997 Y. Matsumoto
*/
#define TCLTKLIB_RELEASE_DATE "2008-04-02"
#define TCLTKLIB_RELEASE_DATE "2008-05-16"
#include "ruby.h"
@ -3153,6 +3153,7 @@ ip_ruby_cmd(clientData, interp, argc, argv)
str, "'", (char *)NULL);
rbtk_pending_exception = rb_exc_new2(rb_eArgError,
Tcl_GetStringResult(interp));
if (old_gc == Qfalse) rb_gc_enable();
return TCL_ERROR;
#endif
}
@ -5155,6 +5156,8 @@ ip_finalize(ip)
Tcl_CreateCommand(ip, "ruby_cmd", ip_null_proc,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
#endif
rb_thread_critical = thr_crit_bup;
return;
}
/* delete root widget */
@ -5162,7 +5165,7 @@ ip_finalize(ip)
DUMP1("check `destroy'");
if (Tcl_GetCommandInfo(ip, "destroy", &info)) {
DUMP1("call `destroy'");
Tcl_GlobalEval(ip, "destroy .");
Tcl_GlobalEval(ip, "catch {destroy .}");
}
#endif
#if 1
@ -7106,7 +7109,8 @@ lib_toUTF8_core(ip_obj, src, encodename)
if (NIL_P(enc)) {
encoding = (Tcl_Encoding)NULL;
} else {
StringValue(enc);
/* StringValue(enc); */
enc = rb_funcall(enc, ID_to_s, 0, 0);
/* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); */
encoding = Tcl_GetEncoding((Tcl_Interp*)NULL,
RSTRING_PTR(enc));
@ -7292,7 +7296,8 @@ lib_fromUTF8_core(ip_obj, src, encodename)
if (NIL_P(enc)) {
encoding = (Tcl_Encoding)NULL;
} else {
StringValue(enc);
/* StringValue(enc); */
enc = rb_funcall(enc, ID_to_s, 0, 0);
/* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); */
encoding = Tcl_GetEncoding((Tcl_Interp*)NULL,
RSTRING_PTR(enc));

View file

@ -8,5 +8,6 @@ end
if has_tk
require 'mkmf'
have_func("rb_obj_instance_exec", "ruby.h")
have_func("strndup", "string.h")
create_makefile('tkutil')
end

View file

@ -7,7 +7,7 @@
************************************************/
#define TKUTIL_RELEASE_DATE "2008-03-29"
#define TKUTIL_RELEASE_DATE "2008-05-14"
#include "ruby.h"
@ -1073,11 +1073,13 @@ tcl2rb_num_or_str(self, value)
/*************************************/
#define CBSUBST_TBL_MAX (256)
struct cbsubst_info {
int size;
char *key;
char *type;
ID *ivar;
int full_subst_length;
int keylen[CBSUBST_TBL_MAX];
unsigned char *key[CBSUBST_TBL_MAX];
unsigned char type[CBSUBST_TBL_MAX];
ID ivar[CBSUBST_TBL_MAX];
VALUE proc;
VALUE aliases;
};
@ -1094,33 +1096,33 @@ static void
subst_free(ptr)
struct cbsubst_info *ptr;
{
int i;
if (ptr) {
if (ptr->key != (char*)NULL) free(ptr->key);
if (ptr->type != (char*)NULL) free(ptr->type);
if (ptr->ivar != (ID*)NULL) free(ptr->ivar);
for(i = 0; i < CBSUBST_TBL_MAX; i++) {
if (ptr->key[i] != (unsigned char *)NULL) free(ptr->key[i]);
}
free(ptr);
}
}
static void
cbsubst_init()
static struct cbsubst_info *
allocate_cbsubst_info()
{
struct cbsubst_info *inf;
ID *ivar;
volatile VALUE proc, aliases;
int idx;
inf = ALLOC(struct cbsubst_info);
inf->size = 0;
inf->full_subst_length = 0;
inf->key = ALLOC_N(char, 1);
inf->key[0] = '\0';
inf->type = ALLOC_N(char, 1);
inf->type[0] = '\0';
ivar = ALLOC_N(ID, 1);
inf->ivar = ivar;
for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) {
inf->keylen[idx] = 0;
inf->key[idx] = (unsigned char *) NULL;
inf->type[idx] = '\0';
inf->ivar[idx] = (ID) 0;
}
proc = rb_hash_new();
inf->proc = proc;
@ -1128,8 +1130,15 @@ cbsubst_init()
aliases = rb_hash_new();
inf->aliases = aliases;
return inf;
}
static void
cbsubst_init()
{
rb_const_set(cCB_SUBST, ID_SUBST_INFO,
Data_Wrap_Struct(cSUBST_INFO, subst_mark, subst_free, inf));
Data_Wrap_Struct(cSUBST_INFO, subst_mark, subst_free,
allocate_cbsubst_info()));
}
static VALUE
@ -1139,24 +1148,29 @@ cbsubst_initialize(argc, argv, self)
VALUE self;
{
struct cbsubst_info *inf;
int idx;
int idx, iv_idx;
Data_Get_Struct(rb_const_get(rb_obj_class(self), ID_SUBST_INFO),
struct cbsubst_info, inf);
for(idx = 0; idx < argc; idx++) {
rb_ivar_set(self, inf->ivar[idx], argv[idx]);
idx = 0;
for(iv_idx = 0; iv_idx < CBSUBST_TBL_MAX; iv_idx++) {
if ( inf->ivar[iv_idx] == (ID) 0 ) continue;
rb_ivar_set(self, inf->ivar[iv_idx], argv[idx++]);
if (idx >= argc) break;
}
return self;
}
static VALUE
cbsubst_ret_val(self, val)
VALUE self;
VALUE val;
{
/* This method may be overwritten on some sub-classes. */
/* This method is used for converting from ruby's callback-return-value */
/* to tcl's value (e.g. validation procedure of entry widget). */
return val;
}
@ -1216,6 +1230,59 @@ cbsubst_def_attr_aliases(self, tbl)
return rb_funcall(inf->aliases, rb_intern("update"), 1, tbl);
}
static VALUE
cbsubst_sym_to_subst(self, sym)
VALUE self;
VALUE sym;
{
struct cbsubst_info *inf;
const char *str;
unsigned char *buf, *ptr;
int idx, len;
ID id;
volatile VALUE ret;
if (TYPE(sym) != T_SYMBOL) return sym;
Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO),
struct cbsubst_info, inf);
if (!NIL_P(ret = rb_hash_aref(inf->aliases, sym))) {
str = rb_id2name(SYM2ID(ret));
} else {
str = rb_id2name(SYM2ID(sym));
}
id = rb_intern(RSTRING_PTR(rb_str_cat2(rb_str_new2("@"), str)));
for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) {
if (inf->ivar[idx] == id) break;
}
if (idx >= CBSUBST_TBL_MAX) return sym;
ptr = buf = ALLOC_N(char, inf->full_subst_length + 1);
*(ptr++) = '%';
if (len = inf->keylen[idx]) {
/* longname */
strncpy(ptr, inf->key[idx], len);
ptr += len;
} else {
/* single char */
*(ptr++) = idx;
}
*(ptr++) = ' ';
*(ptr++) = '\0';
ret = rb_str_new2(buf);
free(buf);
return ret;
}
static VALUE
cbsubst_get_subst_arg(argc, argv, self)
int argc;
@ -1224,17 +1291,15 @@ cbsubst_get_subst_arg(argc, argv, self)
{
struct cbsubst_info *inf;
const char *str;
char *buf, *ptr;
int i, j, len;
unsigned char *buf, *ptr;
int i, idx, len;
ID id;
volatile VALUE arg_sym, ret;
Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO),
struct cbsubst_info, inf);
buf = ALLOC_N(char, 3*argc + 1);
ptr = buf;
len = strlen(inf->key);
ptr = buf = ALLOC_N(char, inf->full_subst_length + 1);
for(i = 0; i < argc; i++) {
switch(TYPE(argv[i])) {
@ -1256,16 +1321,24 @@ cbsubst_get_subst_arg(argc, argv, self)
id = rb_intern(RSTRING_PTR(rb_str_cat2(rb_str_new2("@"), str)));
for(j = 0; j < len; j++) {
if (inf->ivar[j] == id) break;
for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) {
if (inf->ivar[idx] == id) break;
}
if (j >= len) {
if (idx >= CBSUBST_TBL_MAX) {
rb_raise(rb_eArgError, "cannot find attribute :%s", str);
}
*(ptr++) = '%';
*(ptr++) = *(inf->key + j);
if (len = inf->keylen[idx]) {
/* longname */
strncpy(ptr, inf->key[idx], len);
ptr += len;
} else {
/* single char */
*(ptr++) = idx;
}
*(ptr++) = ' ';
}
@ -1283,27 +1356,50 @@ cbsubst_get_subst_key(self, str)
VALUE self;
VALUE str;
{
struct cbsubst_info *inf;
volatile VALUE list;
volatile VALUE ret;
int i, len;
char *buf, *ptr;
VALUE keyval;
int i, len, keylen, idx;
unsigned char *buf, *ptr, *key;
list = rb_funcall(cTclTkLib, ID_split_tklist, 1, str);
len = RARRAY_LEN(list);
buf = ALLOC_N(char, len + 1);
Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO),
struct cbsubst_info, inf);
ptr = buf = ALLOC_N(unsigned char, inf->full_subst_length + len + 1);
for(i = 0; i < len; i++) {
ptr = RSTRING_PTR(RARRAY_PTR(list)[i]);
if (*ptr == '%' && *(ptr + 2) == '\0') {
*(buf + i) = *(ptr + 1);
keyval = RARRAY_PTR(list)[i];
key = (unsigned char*)RSTRING_PTR(keyval);
if (*key == '%') {
if (*(key + 2) == '\0') {
/* single char */
*(ptr++) = *(key + 1);
} else {
*(buf + i) = ' ';
/* search longname-key */
keylen = RSTRING_LEN(keyval) - 1;
for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) {
if (inf->keylen[idx] != keylen) continue;
if (inf->key[idx][0] != *(key + 1)) continue;
if (strncmp(inf->key[idx], key + 1, keylen)) continue;
break;
}
if (idx < CBSUBST_TBL_MAX) {
*(ptr++) = (unsigned char)idx;
} else {
*(ptr++) = ' ';
}
}
*(buf + len) = '\0';
} else {
*(ptr++) = ' ';
}
}
*ptr = '\0';
ret = rb_str_new2(buf);
ret = rb_str_new2((const char*)buf);
free(buf);
return ret;
}
@ -1313,24 +1409,40 @@ cbsubst_get_all_subst_keys(self)
VALUE self;
{
struct cbsubst_info *inf;
char *buf, *ptr;
int i, len;
unsigned char *buf, *ptr;
unsigned char *keys_buf, *keys_ptr;
int idx, len;
volatile VALUE ret;
Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO),
struct cbsubst_info, inf);
len = strlen(inf->key);
buf = ALLOC_N(char, 3*len + 1);
ptr = buf;
for(i = 0; i < len; i++) {
ptr = buf = ALLOC_N(unsigned char, inf->full_subst_length + 1);
keys_ptr = keys_buf = ALLOC_N(unsigned char, CBSUBST_TBL_MAX + 1);
for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) {
if (inf->ivar[idx] == (ID) 0) continue;
*(keys_ptr++) = (unsigned char)idx;
*(ptr++) = '%';
*(ptr++) = *(inf->key + i);
if (len = inf->keylen[idx]) {
/* longname */
strncpy(ptr, inf->key[idx], len);
ptr += len;
} else {
/* single char */
*(ptr++) = (unsigned char)idx;
}
*(ptr++) = ' ';
}
*(buf + 3*len) = '\0';
ret = rb_ary_new3(2, rb_str_new2(inf->key), rb_str_new2(buf));
*ptr = '\0';
*keys_ptr = '\0';
ret = rb_ary_new3(2, rb_str_new2(keys_buf), rb_str_new2((const char*)buf));
free(buf);
@ -1338,68 +1450,117 @@ cbsubst_get_all_subst_keys(self)
}
static VALUE
cbsubst_table_setup(self, key_inf, proc_inf)
cbsubst_table_setup(argc, argv, self)
int argc;
VALUE *argv;
VALUE self;
VALUE key_inf;
VALUE proc_inf;
{
volatile VALUE key_inf;
volatile VALUE longkey_inf;
volatile VALUE proc_inf;
VALUE inf;
ID id;
struct cbsubst_info *subst_inf;
int idx;
int len = RARRAY_LEN(key_inf);
int real_len = 0;
char *key = ALLOC_N(char, len + 1);
char *type = ALLOC_N(char, len + 1);
ID *ivar = ALLOC_N(ID, len + 1);
volatile VALUE proc = rb_hash_new();
volatile VALUE aliases = rb_hash_new();
volatile VALUE inf;
int idx, len;
unsigned char chr;
/* accept (key_inf, proc_inf) or (key_inf, longkey_inf, procinf) */
if (rb_scan_args(argc, argv, "21", &key_inf, &longkey_inf, &proc_inf) == 2) {
proc_inf = longkey_inf;
longkey_inf = rb_ary_new();
}
/* check the number of longkeys */
if (RARRAY_LEN(longkey_inf) > 125 /* from 0x80 to 0xFD */) {
rb_raise(rb_eArgError, "too many longname-key definitions");
}
/* init */
subst_inf = ALLOC(struct cbsubst_info);
/* subst_inf->size = len; */
subst_inf->key = key;
subst_inf->type = type;
subst_inf->ivar = ivar;
subst_inf->proc = proc;
subst_inf->aliases = aliases;
subst_inf = allocate_cbsubst_info();
/*
* keys : array of [subst, type, ivar]
* subst ==> char code
* type ==> char code
* subst ==> char code or string
* type ==> char code or string
* ivar ==> symbol
*/
len = RARRAY_LEN(key_inf);
for(idx = 0; idx < len; idx++) {
inf = RARRAY_PTR(key_inf)[idx];
if (TYPE(inf) != T_ARRAY) continue;
*(key + real_len) = NUM2CHR(RARRAY_PTR(inf)[0]);
*(type + real_len) = NUM2CHR(RARRAY_PTR(inf)[1]);
*(ivar + real_len)
= rb_intern(
RSTRING_PTR(
rb_str_cat2(rb_str_new2("@"),
rb_id2name(SYM2ID(RARRAY_PTR(inf)[2])))
)
);
rb_attr(self, SYM2ID(RARRAY_PTR(inf)[2]), 1, 0, Qtrue);
real_len++;
if (TYPE(RARRAY_PTR(inf)[0]) == T_STRING) {
chr = *(RSTRING_PTR(RARRAY_PTR(inf)[0]));
} else {
chr = NUM2CHR(RARRAY_PTR(inf)[0]);
}
if (TYPE(RARRAY_PTR(inf)[1]) == T_STRING) {
subst_inf->type[chr] = *(RSTRING_PTR(RARRAY_PTR(inf)[1]));
} else {
subst_inf->type[chr] = NUM2CHR(RARRAY_PTR(inf)[1]);
}
subst_inf->full_subst_length += 3;
id = SYM2ID(RARRAY_PTR(inf)[2]);
subst_inf->ivar[chr] = rb_intern(RSTRING_PTR(rb_str_cat2(rb_str_new2("@"), rb_id2name(id))));
rb_attr(self, id, 1, 0, Qtrue);
}
/*
* longkeys : array of [name, type, ivar]
* name ==> longname key string
* type ==> char code or string
* ivar ==> symbol
*/
len = RARRAY_LEN(longkey_inf);
for(idx = 0; idx < len; idx++) {
inf = RARRAY_PTR(longkey_inf)[idx];
if (TYPE(inf) != T_ARRAY) continue;
chr = (unsigned char)(0x80 + idx);
subst_inf->keylen[chr] = RSTRING_LEN(RARRAY_PTR(inf)[0]);
#if HAVE_STRNDUP
subst_inf->key[chr] = strndup(RSTRING_PTR(RARRAY_PTR(inf)[0]),
RSTRING_LEN(RARRAY_PTR(inf)[0]));
#else
subst_inf->key[chr] = malloc(RSTRING_LEN(RARRAY_PTR(inf)[0]) + 1);
if (subst_inf->key[chr]) {
strncpy(subst_inf->key[chr], RSTRING_PTR(RARRAY_PTR(inf)[0]),
RSTRING_LEN(RARRAY_PTR(inf)[0]) + 1);
subst_inf->key[chr][RSTRING_LEN(RARRAY_PTR(inf)[0])] = '\0';
}
#endif
if (TYPE(RARRAY_PTR(inf)[1]) == T_STRING) {
subst_inf->type[chr] = *(RSTRING_PTR(RARRAY_PTR(inf)[1]));
} else {
subst_inf->type[chr] = NUM2CHR(RARRAY_PTR(inf)[1]);
}
subst_inf->full_subst_length += (subst_inf->keylen[chr] + 2);
id = SYM2ID(RARRAY_PTR(inf)[2]);
subst_inf->ivar[chr] = rb_intern(RSTRING_PTR(rb_str_cat2(rb_str_new2("@"), rb_id2name(id))));
rb_attr(self, id, 1, 0, Qtrue);
}
*(key + real_len) = '\0';
*(type + real_len) = '\0';
subst_inf->size = real_len;
/*
* procs : array of [type, proc]
* type ==> char code
* type ==> char code or string
* proc ==> proc/method/obj (must respond to 'call')
*/
len = RARRAY_LEN(proc_inf);
for(idx = 0; idx < len; idx++) {
inf = RARRAY_PTR(proc_inf)[idx];
if (TYPE(inf) != T_ARRAY) continue;
rb_hash_aset(proc, RARRAY_PTR(inf)[0], RARRAY_PTR(inf)[1]);
rb_hash_aset(subst_inf->proc,
((TYPE(RARRAY_PTR(inf)[0]) == T_STRING)?
INT2FIX(*(RSTRING_PTR(RARRAY_PTR(inf)[0]))) :
RARRAY_PTR(inf)[0]),
RARRAY_PTR(inf)[1]);
}
rb_const_set(self, ID_SUBST_INFO,
@ -1424,10 +1585,11 @@ cbsubst_scan_args(self, arg_key, val_ary)
{
struct cbsubst_info *inf;
int idx;
int len = RARRAY_LEN(val_ary);
char c;
char *ptr;
volatile VALUE dst = rb_ary_new2(len);
unsigned char *keyptr = (unsigned char*)RSTRING_PTR(arg_key);
int keylen = RSTRING_LEN(arg_key);
int vallen = RARRAY_LEN(val_ary);
unsigned char type_chr;
volatile VALUE dst = rb_ary_new2(vallen);
volatile VALUE proc;
int thr_crit_bup;
VALUE old_gc;
@ -1440,25 +1602,24 @@ cbsubst_scan_args(self, arg_key, val_ary)
Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO),
struct cbsubst_info, inf);
for(idx = 0; idx < len; idx++) {
if (idx >= RSTRING_LEN(arg_key)) {
for(idx = 0; idx < vallen; idx++) {
if (idx >= keylen) {
proc = Qnil;
} else if (*(RSTRING_PTR(arg_key) + idx) == ' ') {
} else if (*(keyptr + idx) == ' ') {
proc = Qnil;
} else {
ptr = strchr(inf->key, *(RSTRING_PTR(arg_key) + idx));
if (ptr == (char*)NULL) {
proc = Qnil;
if (type_chr = inf->type[*(keyptr + idx)]) {
proc = rb_hash_aref(inf->proc, INT2FIX((int)type_chr));
} else {
c = *(inf->type + (ptr - inf->key));
proc = rb_hash_aref(inf->proc, INT2FIX(c));
proc = Qnil;
}
}
if (NIL_P(proc)) {
rb_ary_push(dst, RARRAY_PTR(val_ary)[idx]);
} else {
rb_ary_push(dst, rb_funcall(proc, ID_call, 1, RARRAY_PTR(val_ary)[idx]));
rb_ary_push(dst, rb_funcall(proc, ID_call, 1,
RARRAY_PTR(val_ary)[idx]));
}
}
@ -1543,6 +1704,8 @@ Init_tkutil()
ID_SUBST_INFO = rb_intern("SUBST_INFO");
rb_define_singleton_method(cCB_SUBST, "ret_val", cbsubst_ret_val, 1);
rb_define_singleton_method(cCB_SUBST, "scan_args", cbsubst_scan_args, 2);
rb_define_singleton_method(cCB_SUBST, "_sym2subst",
cbsubst_sym_to_subst, 1);
rb_define_singleton_method(cCB_SUBST, "subst_arg",
cbsubst_get_subst_arg, -1);
rb_define_singleton_method(cCB_SUBST, "_get_subst_key",
@ -1550,7 +1713,7 @@ Init_tkutil()
rb_define_singleton_method(cCB_SUBST, "_get_all_subst_keys",
cbsubst_get_all_subst_keys, 0);
rb_define_singleton_method(cCB_SUBST, "_setup_subst_table",
cbsubst_table_setup, 2);
cbsubst_table_setup, -1);
rb_define_singleton_method(cCB_SUBST, "_get_extra_args_tbl",
cbsubst_get_extra_args_tbl, 0);
rb_define_singleton_method(cCB_SUBST, "_define_attribute_aliases",

View file

@ -3111,6 +3111,8 @@ gzreader_gets(argc, argv, obj)
if (NIL_P(rs)) {
dst = gzfile_read_all(gz);
if (RSTRING(dst)->len != 0) gz->lineno++;
else
return Qnil;
return dst;
}

213
file.c
View file

@ -15,6 +15,10 @@
#ifdef _WIN32
#include "missing/file.h"
#endif
#ifdef __CYGWIN__
#include <windows.h>
#include <sys/cygwin.h>
#endif
#include "ruby.h"
#include "rubyio.h"
@ -2310,6 +2314,18 @@ rb_file_s_umask(argc, argv)
#define isdirsep(x) ((x) == '/')
#endif
#if defined _WIN32 || defined __CYGWIN__
#define USE_NTFS 1
#else
#define USE_NTFS 0
#endif
#if USE_NTFS
#define istrailinggabage(x) ((x) == '.' || (x) == ' ')
#else
#define istrailinggabage(x) 0
#endif
#ifndef CharNext /* defined as CharNext[AW] on Windows. */
# if defined(DJGPP)
# define CharNext(p) ((p) + mblen(p, MB_CUR_MAX))
@ -2454,6 +2470,30 @@ rb_path_end(path)
return chompdirsep(path);
}
#if USE_NTFS
static char *
ntfs_tail(const char *path)
{
while (*path && *path != ':') {
if (istrailinggabage(*path)) {
const char *last = path++;
while (istrailinggabage(*path)) path++;
if (!*path || *path == ':') return (char *)last;
}
else if (isdirsep(*path)) {
const char *last = path++;
while (isdirsep(*path)) path++;
if (!*path) return (char *)last;
if (*path == ':') path++;
}
else {
path = CharNext(path);
}
}
return (char *)path;
}
#endif
#define BUFCHECK(cond) do {\
long bdiff = p - buf;\
while (cond) {\
@ -2480,7 +2520,8 @@ static VALUE
file_expand_path(fname, dname, result)
VALUE fname, dname, result;
{
char *s, *buf, *b, *p, *pend, *root;
const char *s, *b;
char *buf, *p, *pend, *root;
long buflen, dirlen;
int tainted;
@ -2621,15 +2662,21 @@ file_expand_path(fname, dname, result)
case '.':
if (*(s+1) == '\0' || isdirsep(*(s+1))) {
/* We must go back to the parent */
char *n;
*p = '\0';
if (!(b = strrdirsep(root))) {
if (!(n = strrdirsep(root))) {
*p = '/';
}
else {
p = b;
p = n;
}
b = ++s;
}
#if USE_NTFS
else {
do *++s; while (istrailinggabage(*s));
}
#endif
break;
case '/':
#if defined DOSISH || defined __CYGWIN__
@ -2642,6 +2689,19 @@ file_expand_path(fname, dname, result)
break;
}
}
#if USE_NTFS
else {
--s;
case ' ': {
const char *e = s;
while (istrailinggabage(*s)) s++;
if (!*s) {
s = e;
goto endpath;
}
}
}
#endif
break;
case '/':
#if defined DOSISH || defined __CYGWIN__
@ -2664,15 +2724,79 @@ file_expand_path(fname, dname, result)
}
if (s > b) {
#if USE_NTFS
endpath:
if (s > b + 6 && strncasecmp(s - 6, ":$DATA", 6) == 0) {
/* alias of stream */
/* get rid of a bug of x64 VC++ */
if (*(s-7) == ':') s -= 7; /* prime */
else if (memchr(b, ':', s - 6 - b)) s -= 6; /* alternative */
}
#endif
BUFCHECK(bdiff + (s-b) >= buflen);
memcpy(++p, b, s-b);
p += s-b;
}
if (p == skiproot(buf) - 1) p++;
buflen = p - buf;
#if USE_NTFS
*p = '\0';
if (1 &&
#ifdef __CYGWIN__
!(buf[0] == '/' && !buf[1]) &&
#endif
!strpbrk(b = buf, "*?")) {
size_t len;
WIN32_FIND_DATA wfd;
#ifdef __CYGWIN__
int lnk_added = 0, is_symlink = 0;
struct stat st;
char w32buf[MAXPATHLEN], sep = 0;
p = 0;
if (lstat(buf, &st) == 0 && S_ISLNK(st.st_mode)) {
is_symlink = 1;
p = strrdirsep(buf);
if (!p) p = skipprefix(buf);
if (p) {
sep = *p;
*p = '\0';
}
}
if (cygwin_conv_to_win32_path(buf, w32buf) == 0) {
b = w32buf;
}
if (p) *p = sep;
else p = buf;
if (is_symlink && b == w32buf) {
len = strlen(p);
if (len > 4 && strcasecmp(p + len - 4, ".lnk") != 0) {
lnk_added = 1;
strlcat(w32buf, ".lnk", sizeof(w32buf));
}
}
#endif
HANDLE h = FindFirstFile(b, &wfd);
if (h != INVALID_HANDLE_VALUE) {
FindClose(h);
p = strrdirsep(buf);
len = strlen(wfd.cFileName);
#ifdef __CYGWIN__
if (lnk_added && len > 4 &&
strcasecmp(wfd.cFileName + len - 4, ".lnk") == 0) {
len -= 4;
}
#endif
if (!p) p = buf;
buflen = ++p - buf + len;
rb_str_resize(result, buflen);
memcpy(p, wfd.cFileName, len + 1);
}
}
#endif
if (tainted) OBJ_TAINT(result);
RSTRING(result)->len = p - buf;
*p = '\0';
rb_str_set_len(result, buflen);
return result;
}
@ -2716,23 +2840,31 @@ rb_file_s_expand_path(argc, argv)
}
static int
rmext(p, e)
rmext(p, l1, e)
const char *p, *e;
int l1;
{
int l1, l2;
int l2;
if (!e) return 0;
l1 = chompdirsep(p) - p;
l2 = strlen(e);
if (l2 == 2 && e[1] == '*') {
e = strrchr(p, *e);
if (!e) return 0;
unsigned char c = *e;
e = p + l1;
do {
if (e <= p) return 0;
} while (*--e != c);
return e - p;
}
if (l1 < l2) return l1;
if (strncmp(p+l1-l2, e, l2) == 0) {
#if CASEFOLD_FILESYSTEM
#define fncomp strncasecmp
#else
#define fncomp strncmp
#endif
if (fncomp(p+l1-l2, e, l2) == 0) {
return l1-l2;
}
return 0;
@ -2762,7 +2894,7 @@ rb_file_s_basename(argc, argv)
#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
char *root;
#endif
int f;
int f, n;
if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) {
StringValue(fext);
@ -2796,18 +2928,22 @@ rb_file_s_basename(argc, argv)
#endif
#endif
}
else if (!(p = strrdirsep(name))) {
if (NIL_P(fext) || !(f = rmext(name, StringValueCStr(fext)))) {
f = chompdirsep(name) - name;
if (f == RSTRING(fname)->len) return fname;
}
else {
if (!(p = strrdirsep(name))) {
p = name;
}
else {
while (isdirsep(*p)) p++; /* skip last / */
if (NIL_P(fext) || !(f = rmext(p, StringValueCStr(fext)))) {
f = chompdirsep(p) - p;
}
#if USE_NTFS
n = ntfs_tail(p) - p;
#else
n = chompdirsep(p) - p;
#endif
if (NIL_P(fext) || !(f = rmext(p, n, StringValueCStr(fext)))) {
f = n;
}
if (f == RSTRING_LEN(fname)) return fname;
}
basename = rb_str_new(p, f);
OBJ_INFECT(basename, fname);
@ -2883,7 +3019,7 @@ static VALUE
rb_file_s_extname(klass, fname)
VALUE klass, fname;
{
char *name, *p, *e;
const char *name, *p, *e;
VALUE extname;
name = StringValueCStr(fname);
@ -2891,12 +3027,39 @@ rb_file_s_extname(klass, fname)
if (!p)
p = name;
else
p++;
name = ++p;
e = strrchr(p, '.'); /* get the last dot of the last component */
if (!e || e == p || !e[1]) /* no dot, or the only dot is first or end? */
return rb_str_new2("");
extname = rb_str_new(e, chompdirsep(e) - e); /* keep the dot, too! */
e = 0;
while (*p) {
if (*p == '.' || istrailinggabage(*p)) {
#if USE_NTFS
const char *last = p++, *dot = last;
while (istrailinggabage(*p)) {
if (*p == '.') dot = p;
p++;
}
if (!*p || *p == ':') {
p = last;
break;
}
e = dot;
continue;
#else
e = p; /* get the last dot of the last component */
#endif
}
#if USE_NTFS
else if (*p == ':') {
break;
}
#endif
else if (isdirsep(*p))
break;
p = CharNext(p);
}
if (!e || e == name || e+1 == p) /* no dot, or the only dot is first or end? */
return rb_str_new(0, 0);
extname = rb_str_new(e, p - e); /* keep the dot, too! */
OBJ_INFECT(extname, fname);
return extname;
}

View file

@ -227,13 +227,15 @@ class SimpleDelegator<Delegator
# Clone support for the object returned by \_\_getobj\_\_.
def clone
super
__setobj__(__getobj__.clone)
new = super
new.__setobj__(__getobj__.clone)
new
end
# Duplication support for the object returned by \_\_getobj\_\_.
def dup(obj)
super
__setobj__(__getobj__.dup)
def dup
new = super
new.__setobj__(__getobj__.clone)
new
end
end
@ -280,12 +282,14 @@ def DelegateClass(superclass)
@_dc_obj = obj
end
def clone # :nodoc:
super
__setobj__(__getobj__.clone)
new = super
new.__setobj__(__getobj__.clone)
new
end
def dup # :nodoc:
super
__setobj__(__getobj__.dup)
new = super
new.__setobj__(__getobj__.clone)
new
end
}
for method in methods

View file

@ -520,10 +520,15 @@ module Net
# value specified when this instance was created will be
# used, or, failing that, the default value of 0 seconds,
# which means not to wait for more input.
# FailEOF:: if true, when the remote end closes the connection then an
# EOFError will be raised. Otherwise, defaults to the old
# behaviour that the function will return whatever data
# has been received already, or nil if nothing was received.
#
def waitfor(options) # :yield: recvdata
time_out = @options["Timeout"]
waittime = @options["Waittime"]
fail_eof = @options["FailEOF"]
if options.kind_of?(Hash)
prompt = if options.has_key?("Match")
@ -535,6 +540,7 @@ module Net
end
time_out = options["Timeout"] if options.has_key?("Timeout")
waittime = options["Waittime"] if options.has_key?("Waittime")
fail_eof = options["FailEOF"] if options.has_key?("FailEOF")
else
prompt = options
end
@ -559,7 +565,8 @@ module Net
Integer(c.rindex(/#{IAC}#{SB}/no))
buf = preprocess(c[0 ... c.rindex(/#{IAC}#{SB}/no)])
rest = c[c.rindex(/#{IAC}#{SB}/no) .. -1]
elsif pt = c.rindex(/#{IAC}[^#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]?\z/no)
elsif pt = c.rindex(/#{IAC}[^#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]?\z/no) ||
c.rindex(/\r\z/no)
buf = preprocess(c[0 ... pt])
rest = c[pt .. -1]
else
@ -571,14 +578,21 @@ module Net
#
# We cannot use preprocess() on this data, because that
# method makes some Telnetmode-specific assumptions.
buf = c
buf.gsub!(/#{EOL}/no, "\n") unless @options["Binmode"]
buf = rest + c
rest = ''
unless @options["Binmode"]
if pt = buf.rindex(/\r\z/no)
buf = buf[0 ... pt]
rest = buf[pt .. -1]
end
buf.gsub!(/#{EOL}/no, "\n")
end
end
@log.print(buf) if @options.has_key?("Output_log")
line += buf
yield buf if block_given?
rescue EOFError # End of file reached
raise if fail_eof
if line == ''
line = nil
yield nil if block_given?

View file

@ -58,7 +58,7 @@ module WEBrick
def redirect_to_directory_uri(req, res)
if req.path[-1] != ?/
location = req.path + "/"
location = WEBrick::HTTPUtils.escape_path(req.path + "/")
if req.query_string && req.query_string.size > 0
location << "?" << req.query_string
end

View file

@ -39,7 +39,9 @@ dir = File::dirname(ENV["SCRIPT_FILENAME"])
Dir::chdir dir
if interpreter = ARGV[0]
exec(interpreter, ENV["SCRIPT_FILENAME"])
argv = ARGV.dup
argv << ENV["SCRIPT_FILENAME"]
exec(*argv)
# NOTREACHED
end
exec ENV["SCRIPT_FILENAME"]

View file

@ -199,26 +199,38 @@ module WEBrick
private
def trailing_pathsep?(path)
# check for trailing path separator:
# File.dirname("/aaaa/bbbb/") #=> "/aaaa")
# File.dirname("/aaaa/bbbb/x") #=> "/aaaa/bbbb")
# File.dirname("/aaaa/bbbb") #=> "/aaaa")
# File.dirname("/aaaa/bbbbx") #=> "/aaaa")
return File.dirname(path) != File.dirname(path+"x")
end
def prevent_directory_traversal(req, res)
# Preventing directory traversal on DOSISH platforms;
# Preventing directory traversal on Windows platforms;
# Backslashes (0x5c) in path_info are not interpreted as special
# character in URI notation. So the value of path_info should be
# normalize before accessing to the filesystem.
if File::ALT_SEPARATOR
if trailing_pathsep?(req.path_info)
# File.expand_path removes the trailing path separator.
# Adding a character is a workaround to save it.
# File.expand_path("/aaa/") #=> "/aaa"
# File.expand_path("/aaa/" + "x") #=> "/aaa/x"
expanded = File.expand_path(req.path_info + "x")
expanded[-1, 1] = "" # remove trailing "x"
req.path_info = expanded
expanded.chop! # remove trailing "x"
else
expanded = File.expand_path(req.path_info)
end
req.path_info = expanded
end
def exec_handler(req, res)
raise HTTPStatus::NotFound, "`#{req.path}' not found" unless @root
if set_filename(req, res)
handler = get_handler(req)
handler = get_handler(req, res)
call_callback(:HandlerCallback, req, res)
h = handler.get_instance(@config, res.filename)
h.service(req, res)
@ -228,9 +240,13 @@ module WEBrick
return false
end
def get_handler(req)
suffix1 = (/\.(\w+)$/ =~ req.script_name) && $1.downcase
suffix2 = (/\.(\w+)\.[\w\-]+$/ =~ req.script_name) && $1.downcase
def get_handler(req, res)
suffix1 = (/\.(\w+)\z/ =~ res.filename) && $1.downcase
if /\.(\w+)\.([\w\-]+)\z/ =~ res.filename
if @options[:AcceptableLanguages].include?($2.downcase)
suffix2 = $1.downcase
end
end
handler_table = @options[:HandlerTable]
return handler_table[suffix1] || handler_table[suffix2] ||
HandlerTable[suffix1] || HandlerTable[suffix2] ||
@ -243,15 +259,13 @@ module WEBrick
path_info.unshift("") # dummy for checking @root dir
while base = path_info.first
check_filename(req, res, base)
break if base == "/"
break unless File.directory?(res.filename + base)
break unless File.directory?(File.expand_path(res.filename + base))
shift_path_info(req, res, path_info)
call_callback(:DirectoryCallback, req, res)
end
if base = path_info.first
check_filename(req, res, base)
if base == "/"
if file = search_index_file(req, res)
shift_path_info(req, res, path_info, file)
@ -272,12 +286,10 @@ module WEBrick
end
def check_filename(req, res, name)
@options[:NondisclosureName].each{|pattern|
if File.fnmatch("/#{pattern}", name, File::FNM_CASEFOLD)
if nondisclosure_name?(name) || windows_ambiguous_name?(name)
@logger.warn("the request refers nondisclosure name `#{name}'.")
raise HTTPStatus::NotFound, "`#{req.path}' not found."
end
}
end
def shift_path_info(req, res, path_info, base=nil)
@ -285,7 +297,8 @@ module WEBrick
base = base || tmp
req.path_info = path_info.join
req.script_name << base
res.filename << base
res.filename = File.expand_path(res.filename + base)
check_filename(req, res, File.basename(res.filename))
end
def search_index_file(req, res)
@ -325,6 +338,12 @@ module WEBrick
end
end
def windows_ambiguous_name?(name)
return true if /[. ]+\z/ =~ name
return true if /::\$DATA\z/ =~ name
return false
end
def nondisclosure_name?(name)
@options[:NondisclosureName].each{|pattern|
if File.fnmatch(pattern, name, File::FNM_CASEFOLD)
@ -343,7 +362,8 @@ module WEBrick
list = Dir::entries(local_path).collect{|name|
next if name == "." || name == ".."
next if nondisclosure_name?(name)
st = (File::stat(local_path + name) rescue nil)
next if windows_ambiguous_name?(name)
st = (File::stat(File.join(local_path, name)) rescue nil)
if st.nil?
[ name, nil, -1 ]
elsif st.directory?
@ -383,7 +403,7 @@ module WEBrick
res.body << "<A HREF=\"?S=#{d1}\">Size</A>\n"
res.body << "<HR>\n"
list.unshift [ "..", File::mtime(local_path+".."), -1 ]
list.unshift [ "..", File::mtime(local_path+"/.."), -1 ]
list.each{ |name, time, size|
if name == ".."
dname = "Parent Directory"

View file

@ -255,6 +255,11 @@ The variable ruby-indent-level controls the amount of indentation.
(make-local-variable 'add-log-current-defun-function)
(setq add-log-current-defun-function 'ruby-add-log-current-method)
(set (make-local-variable 'font-lock-defaults) '((ruby-font-lock-keywords) nil nil))
(set (make-local-variable 'font-lock-keywords) ruby-font-lock-keywords)
(set (make-local-variable 'font-lock-syntax-table) ruby-font-lock-syntax-table)
(set (make-local-variable 'font-lock-syntactic-keywords) ruby-font-lock-syntactic-keywords)
(run-mode-hooks 'ruby-mode-hook))
(defun ruby-current-indentation ()
@ -1020,24 +1025,13 @@ balanced expression is found."
("^\\(=\\)begin\\(\\s \\|$\\)" 1 (7 . nil))
("^\\(=\\)end\\(\\s \\|$\\)" 1 (7 . nil))))
(cond ((featurep 'xemacs)
(if (featurep 'xemacs)
(put 'ruby-mode 'font-lock-defaults
'((ruby-font-lock-keywords)
nil nil nil
beginning-of-line
(font-lock-syntactic-keywords
. ruby-font-lock-syntactic-keywords))))
(t
(add-hook 'ruby-mode-hook
'(lambda ()
(make-local-variable 'font-lock-defaults)
(make-local-variable 'font-lock-keywords)
(make-local-variable 'font-lock-syntax-table)
(make-local-variable 'font-lock-syntactic-keywords)
(setq font-lock-defaults '((ruby-font-lock-keywords) nil nil))
(setq font-lock-keywords ruby-font-lock-keywords)
(setq font-lock-syntax-table ruby-font-lock-syntax-table)
(setq font-lock-syntactic-keywords ruby-font-lock-syntactic-keywords)))))
(defun ruby-font-lock-docs (limit)
(if (re-search-forward "^=begin\\(\\s \\|$\\)" limit t)

13
range.c
View file

@ -307,24 +307,29 @@ range_step(argc, argv, range)
VALUE *argv;
VALUE range;
{
VALUE b, e, step;
VALUE b, e, step, tmp;
long unit;
RETURN_ENUMERATOR(range, argc, argv);
b = rb_ivar_get(range, id_beg);
e = rb_ivar_get(range, id_end);
if (rb_scan_args(argc, argv, "01", &step) == 0) {
if (argc == 0) {
step = INT2FIX(1);
unit = 1;
}
else if (FIXNUM_P(step)) {
else {
rb_scan_args(argc, argv, "01", &step);
tmp = rb_check_to_integer(step, "to_int");
if (!NIL_P(tmp)) {
step = tmp;
unit = NUM2LONG(step);
}
else {
VALUE tmp = rb_to_int(step);
tmp = rb_funcall(rb_funcall(b, '+', 1, step), '-', 1, b);
unit = rb_cmpint(tmp, step, INT2FIX(0));
}
}
if (unit < 0) {
rb_raise(rb_eArgError, "step can't be negative");
}

44
re.c
View file

@ -927,6 +927,7 @@ rb_reg_search(re, str, pos, reverse)
}
if (result < 0) {
re_free_registers(&regs);
rb_backref_set(Qnil);
return result;
}
@ -943,6 +944,7 @@ rb_reg_search(re, str, pos, reverse)
}
re_copy_registers(RMATCH(match)->regs, &regs);
re_free_registers(&regs);
RMATCH(match)->str = rb_str_new4(str);
rb_backref_set(match);
@ -1219,7 +1221,6 @@ match_entry(match, n)
/*
* call-seq:
* mtch.values_at([index]*) => array
* mtch.select([index]*) => array
*
* Uses each <i>index</i> to access the matching values, returning an array of
* the corresponding matches.
@ -1239,6 +1240,45 @@ match_values_at(argc, argv, match)
}
/*
* call-seq:
* mtch.select{|obj| block} => array
*
* Returns an array containing match strings for which <em>block</em>
* gives <code>true</code>. MatchData#select will be removed from Ruby 1.9.
*
* m = /(.)(.)(\d+)(\d)/.match("THX1138: The Movie")
* p m.select{|x| /X/ =~ x} #=> ["HX1138", "X"]
*/
static VALUE
match_select(argc, argv, match)
int argc;
VALUE *argv;
VALUE match;
{
if (argc > 0) {
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc);
}
else {
struct re_registers *regs = RMATCH(match)->regs;
VALUE target = RMATCH(match)->str;
VALUE result = rb_ary_new();
int i;
int taint = OBJ_TAINTED(match);
for (i=0; i<regs->num_regs; i++) {
VALUE str = rb_str_substr(target, regs->beg[i], regs->end[i]-regs->beg[i]);
if (taint) OBJ_TAINT(str);
if (RTEST(rb_yield(str))) {
rb_ary_push(result, str);
}
}
return result;
}
}
/*
* call-seq:
@ -2326,7 +2366,7 @@ Init_Regexp()
rb_define_method(rb_cMatch, "[]", match_aref, -1);
rb_define_method(rb_cMatch, "captures", match_captures, 0);
rb_define_method(rb_cMatch, "values_at", match_values_at, -1);
rb_define_method(rb_cMatch, "select", match_values_at, -1);
rb_define_method(rb_cMatch, "select", match_select, -1);
rb_define_method(rb_cMatch, "pre_match", rb_reg_match_pre, 0);
rb_define_method(rb_cMatch, "post_match", rb_reg_match_post, 0);
rb_define_method(rb_cMatch, "to_s", match_to_s, 0);

60
sample/erb/erb4html.rb Normal file
View file

@ -0,0 +1,60 @@
require 'erb'
class ERB
class ERBString < String
def to_s; self; end
def erb_concat(s)
if self.class === s
concat(s)
else
concat(erb_quote(s))
end
end
def erb_quote(s); s; end
end
end
class ERB4Html < ERB
def self.quoted(s)
HtmlString.new(s)
end
class HtmlString < ERB::ERBString
def erb_quote(s)
ERB::Util::html_escape(s)
end
end
def set_eoutvar(compiler, eoutvar = '_erbout')
compiler.put_cmd = "#{eoutvar}.concat"
compiler.insert_cmd = "#{eoutvar}.erb_concat"
cmd = []
cmd.push "#{eoutvar} = ERB4Html.quoted('')"
compiler.pre_cmd = cmd
cmd = []
cmd.push(eoutvar)
compiler.post_cmd = cmd
end
end
if __FILE__ == $0
page = <<EOP
<title><%=title%></title>
<p><%=para%></p>
EOP
erb = ERB4Html.new(page)
title = "<auto-quote>"
para = "&lt;quoted&gt;"
puts erb.result
title = "<auto-quote>"
para = ERB4Html.quoted("&lt;quoted&gt;")
puts erb.result
end

View file

@ -761,7 +761,7 @@ rb_str_cat(str, ptr, len)
}
if (FL_TEST(str, STR_ASSOC)) {
rb_str_modify(str);
REALLOC_N(RSTRING(str)->ptr, char, RSTRING(str)->len+len);
REALLOC_N(RSTRING(str)->ptr, char, RSTRING(str)->len+len+1);
memcpy(RSTRING(str)->ptr + RSTRING(str)->len, ptr, len);
RSTRING(str)->len += len;
RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; /* sentinel */
@ -3698,9 +3698,8 @@ rb_f_split(argc, argv)
*
* Splits <i>str</i> using the supplied parameter as the record separator
* (<code>$/</code> by default), passing each substring in turn to the supplied
* block. If a zero-length record separator is supplied, the string is split on
* <code>\n</code> characters, except that multiple successive newlines are
* appended together.
* block. If a zero-length record separator is supplied, the string is split
* into paragraphs delimited by multiple successive newlines.
*
* print "Example one\n"
* "hello\nworld".each {|s| p s}
@ -4922,6 +4921,7 @@ Init_String()
rb_define_method(rb_cString, "insert", rb_str_insert, 2);
rb_define_method(rb_cString, "length", rb_str_length, 0);
rb_define_method(rb_cString, "size", rb_str_length, 0);
rb_define_method(rb_cString, "bytesize", rb_str_length, 0);
rb_define_method(rb_cString, "empty?", rb_str_empty, 0);
rb_define_method(rb_cString, "=~", rb_str_match, 1);
rb_define_method(rb_cString, "match", rb_str_match_m, 1);

View file

@ -310,19 +310,14 @@ rb_struct_s_def(argc, argv, klass)
ID id;
rb_scan_args(argc, argv, "1*", &name, &rest);
if (!NIL_P(name) && SYMBOL_P(name)) {
rb_ary_unshift(rest, name);
name = Qnil;
}
for (i=0; i<RARRAY(rest)->len; i++) {
id = rb_to_id(RARRAY(rest)->ptr[i]);
RARRAY(rest)->ptr[i] = ID2SYM(id);
}
if (!NIL_P(name)) {
VALUE tmp = rb_check_string_type(name);
if (NIL_P(tmp)) {
id = rb_to_id(name);
rb_ary_unshift(rest, ID2SYM(id));
name = Qnil;
}
}
st = make_struct(name, rest, klass);
if (rb_block_given_p()) {
rb_mod_module_eval(0, 0, st);

View file

@ -528,6 +528,14 @@ class TestArray < Test::Unit::TestCase
assert_equal([1, 2, 3, 1, 2, 3], a)
end
def test_count
a = @cls[1, 2, 3, 1, 2]
assert_equal(2, a.count(1))
assert_equal(3, a.count {|x| x % 2 == 1 })
assert_equal(2, a.count(1) {|x| x % 2 == 1 })
assert_raise(ArgumentError) { a.count(0, 1) }
end
def test_delete
a = @cls[*('cab'..'cat').to_a]
assert_equal('cap', a.delete('cap'))

View file

@ -47,5 +47,7 @@ class TestMethod < Test::Unit::TestCase
assert_equal(o, m.receiver)
assert_equal("foo", m.name)
assert_equal(class << o; self; end, m.owner)
assert_equal("foo", m.unbind.name)
assert_equal(class << o; self; end, m.unbind.owner)
end
end

1
test/webrick/.htaccess Normal file
View file

@ -0,0 +1 @@
this file should not be published.

View file

@ -1,20 +1,13 @@
require "webrick"
require File.join(File.dirname(__FILE__), "utils.rb")
require "test/unit"
begin
loadpath = $:.dup
$:.replace($: | [File.expand_path("../ruby", File.dirname(__FILE__))])
require 'envutil'
ensure
$:.replace(loadpath)
end
class TestWEBrickCGI < Test::Unit::TestCase
def test_cgi
accepted = started = stopped = 0
requested0 = requested1 = 0
config = {
:CGIInterpreter => EnvUtil.rubybin,
:CGIInterpreter => TestWEBrick::RubyBin,
:DocumentRoot => File.dirname(__FILE__),
:DirectoryIndex => ["webrick.cgi"],
}

View file

@ -9,6 +9,10 @@ class WEBrick::TestFileHandler < Test::Unit::TestCase
klass.new(WEBrick::Config::HTTP, filename)
end
def windows?
File.directory?("\\")
end
def get_res_body(res)
return res.body.read rescue res.body
end
@ -115,10 +119,82 @@ class WEBrick::TestFileHandler < Test::Unit::TestCase
http = Net::HTTP.new(addr, port)
req = Net::HTTP::Get.new("/../../")
http.request(req){|res| assert_equal("400", res.code) }
req = Net::HTTP::Get.new(
"/..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5cboot.ini"
)
req = Net::HTTP::Get.new("/..%5c../#{File.basename(__FILE__)}")
http.request(req){|res| assert_equal(windows? ? "200" : "404", res.code) }
req = Net::HTTP::Get.new("/..%5c..%5cruby.c")
http.request(req){|res| assert_equal("404", res.code) }
end
end
def test_unwise_in_path
if windows?
config = { :DocumentRoot => File.dirname(__FILE__), }
this_file = File.basename(__FILE__)
TestWEBrick.start_httpserver(config) do |server, addr, port|
http = Net::HTTP.new(addr, port)
req = Net::HTTP::Get.new("/..%5c..")
http.request(req){|res| assert_equal("301", res.code) }
end
end
end
def test_short_filename
config = {
:CGIInterpreter => TestWEBrick::RubyBin,
:DocumentRoot => File.dirname(__FILE__),
:CGIPathEnv => ENV['PATH'],
}
TestWEBrick.start_httpserver(config) do |server, addr, port|
http = Net::HTTP.new(addr, port)
req = Net::HTTP::Get.new("/webric~1.cgi/test")
http.request(req) do |res|
if windows?
assert_equal("200", res.code)
assert_equal("/test", res.body)
else
assert_equal("404", res.code)
end
end
req = Net::HTTP::Get.new("/.htaccess")
http.request(req) {|res| assert_equal("404", res.code) }
req = Net::HTTP::Get.new("/htacce~1")
http.request(req) {|res| assert_equal("404", res.code) }
req = Net::HTTP::Get.new("/HTACCE~1")
http.request(req) {|res| assert_equal("404", res.code) }
end
end
def test_script_disclosure
config = {
:CGIInterpreter => TestWEBrick::RubyBin,
:DocumentRoot => File.dirname(__FILE__),
:CGIPathEnv => ENV['PATH'],
}
TestWEBrick.start_httpserver(config) do |server, addr, port|
http = Net::HTTP.new(addr, port)
req = Net::HTTP::Get.new("/webrick.cgi/test")
http.request(req) do |res|
assert_equal("200", res.code)
assert_equal("/test", res.body)
end
response_assertion = Proc.new do |res|
if windows?
assert_equal("200", res.code)
assert_equal("/test", res.body)
else
assert_equal("404", res.code)
end
end
req = Net::HTTP::Get.new("/webrick.cgi%20/test")
http.request(req, &response_assertion)
req = Net::HTTP::Get.new("/webrick.cgi./test")
http.request(req, &response_assertion)
req = Net::HTTP::Get.new("/webrick.cgi::$DATA/test")
http.request(req, &response_assertion)
end
end
end

View file

@ -1,3 +1,10 @@
begin
loadpath = $:.dup
$:.replace($: | [File.expand_path("../ruby", File.dirname(__FILE__))])
require 'envutil'
ensure
$:.replace(loadpath)
end
require "webrick"
begin
require "webrick/https"
@ -12,6 +19,11 @@ module TestWEBrick
return self
end
RubyBin = "\"#{EnvUtil.rubybin}\""
RubyBin << " \"-I#{File.expand_path("../..", File.dirname(__FILE__))}/lib\""
RubyBin << " \"-I#{File.dirname(EnvUtil.rubybin)}/.ext/common\""
RubyBin << " \"-I#{File.dirname(EnvUtil.rubybin)}/.ext/#{RUBY_PLATFORM}\""
module_function
def start_server(klass, config={}, &block)

View file

@ -0,0 +1,36 @@
#!ruby -d
require "webrick/cgi"
class TestApp < WEBrick::CGI
def do_GET(req, res)
res["content-type"] = "text/plain"
if (p = req.path_info) && p.length > 0
res.body = p
elsif (q = req.query).size > 0
res.body = q.keys.sort.collect{|key|
q[key].list.sort.collect{|v|
"#{key}=#{v}"
}.join(", ")
}.join(", ")
elsif %r{/$} =~ req.request_uri.to_s
res.body = ""
res.body << req.request_uri.to_s << "\n"
res.body << req.script_name
elsif !req.cookies.empty?
res.body = req.cookies.inject(""){|result, cookie|
result << "%s=%s\n" % [cookie.name, cookie.value]
}
res.cookies << WEBrick::Cookie.new("Customer", "WILE_E_COYOTE")
res.cookies << WEBrick::Cookie.new("Shipping", "FedEx")
else
res.body = req.script_name
end
end
def do_POST(req, res)
do_GET(req, res)
end
end
cgi = TestApp.new
cgi.start

3399
util.c

File diff suppressed because it is too large Load diff

View file

@ -639,6 +639,11 @@ class File
end
<<KEEP
test-rubyspec:
@if not exist $(srcdir:/=\)\rubyspec\nul echo No rubyspec here. put rubyspec to srcdir first. && exit 1
$(RUNRUBY) $(srcdir)/rubyspec/mspec/bin/mspec -r$(srcdir)/ext/purelib.rb $(srcdir)/rubyspec/spec/rubyspec/$(MAJOR).$(MINOR)
{$(srcdir)/missing}.c.obj:
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -c -Tc$(<:\=/)
{$(srcdir)/win32}.c.obj:

View file

@ -371,6 +371,7 @@ static void invalid_parameter(const wchar_t *expr, const wchar_t *func, const wc
}
#endif
static CRITICAL_SECTION select_mutex;
static BOOL fWinsock;
static char *envarea;
static void
@ -384,6 +385,7 @@ exit_handler(void)
FreeEnvironmentStrings(envarea);
envarea = NULL;
}
DeleteCriticalSection(&select_mutex);
}
static void
@ -472,6 +474,8 @@ NtInitialize(int *argc, char ***argv)
init_stdhandle();
InitializeCriticalSection(&select_mutex);
atexit(exit_handler);
// Initialize Winsock
@ -2057,87 +2061,250 @@ rb_w32_fdisset(int fd, fd_set *set)
static int NtSocketsInitialized = 0;
static int
extract_file_fd(fd_set *set, fd_set *fileset)
extract_fd(fd_set *dst, fd_set *src, int (*func)(SOCKET))
{
int idx;
int s = 0;
if (!src || !dst) return 0;
fileset->fd_count = 0;
if (!set)
while (s < src->fd_count) {
SOCKET fd = src->fd_array[s];
if (!func || (*func)(fd)) { /* move it to dst */
int d;
for (d = 0; d < dst->fd_count; d++) {
if (dst->fd_array[d] == fd) break;
}
if (d == dst->fd_count && dst->fd_count < FD_SETSIZE) {
dst->fd_array[dst->fd_count++] = fd;
}
memmove(
&src->fd_array[s],
&src->fd_array[s+1],
sizeof(src->fd_array[0]) * (--src->fd_count - s));
}
else s++;
}
return dst->fd_count;
}
static int
is_not_socket(SOCKET sock)
{
return !is_socket(sock);
}
static int
is_pipe(SOCKET sock) /* DONT call this for SOCKET! it clains it is PIPE. */
{
int ret;
RUBY_CRITICAL(
ret = (GetFileType((HANDLE)sock) == FILE_TYPE_PIPE)
);
return ret;
}
static int
is_readable_pipe(SOCKET sock) /* call this for pipe only */
{
int ret;
DWORD n = 0;
RUBY_CRITICAL(
if (PeekNamedPipe((HANDLE)sock, NULL, 0, NULL, &n, NULL)) {
ret = (n > 0);
}
else {
ret = (GetLastError() == ERROR_BROKEN_PIPE); /* pipe was closed */
}
);
return ret;
}
static int
is_console(SOCKET sock) /* DONT call this for SOCKET! */
{
int ret;
DWORD n = 0;
INPUT_RECORD ir;
RUBY_CRITICAL(
ret = (PeekConsoleInput((HANDLE)sock, &ir, 1, &n))
);
return ret;
}
static int
is_readable_console(SOCKET sock) /* call this for console only */
{
int ret = 0;
DWORD n = 0;
INPUT_RECORD ir;
RUBY_CRITICAL(
if (PeekConsoleInput((HANDLE)sock, &ir, 1, &n) && n > 0) {
if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown &&
ir.Event.KeyEvent.uChar.AsciiChar) {
ret = 1;
}
else {
ReadConsoleInput((HANDLE)sock, &ir, 1, &n);
}
}
);
return ret;
}
static int
do_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
struct timeval *timeout)
{
int r = 0;
if (nfds == 0) {
if (timeout)
rb_w32_sleep(timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
else
rb_w32_sleep(INFINITE);
}
else {
RUBY_CRITICAL(
EnterCriticalSection(&select_mutex);
r = select(nfds, rd, wr, ex, timeout);
LeaveCriticalSection(&select_mutex);
if (r == SOCKET_ERROR) {
errno = map_errno(WSAGetLastError());
r = -1;
}
);
}
return r;
}
static inline int
subst(struct timeval *rest, const struct timeval *wait)
{
while (rest->tv_usec < wait->tv_usec) {
if (rest->tv_sec <= wait->tv_sec) {
return 0;
for (idx = 0; idx < set->fd_count; idx++) {
SOCKET fd = set->fd_array[idx];
if (!is_socket(fd)) {
int i;
for (i = 0; i < fileset->fd_count; i++) {
if (fileset->fd_array[i] == fd) {
break;
}
rest->tv_sec -= 1;
rest->tv_usec += 1000 * 1000;
}
if (i == fileset->fd_count) {
if (fileset->fd_count < FD_SETSIZE) {
fileset->fd_array[i] = fd;
fileset->fd_count++;
}
}
}
}
return fileset->fd_count;
rest->tv_sec -= wait->tv_sec;
rest->tv_usec -= wait->tv_usec;
return 1;
}
static inline int
compare(const struct timeval *t1, const struct timeval *t2)
{
if (t1->tv_sec < t2->tv_sec)
return -1;
if (t1->tv_sec > t2->tv_sec)
return 1;
if (t1->tv_usec < t2->tv_usec)
return -1;
if (t1->tv_usec > t2->tv_usec)
return 1;
return 0;
}
#undef Sleep
long
rb_w32_select (int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
struct timeval *timeout)
{
long r;
fd_set file_rd;
fd_set file_wr;
#ifdef USE_INTERRUPT_WINSOCK
fd_set trap;
#endif /* USE_INTERRUPT_WINSOCK */
int file_nfds;
fd_set pipe_rd;
fd_set cons_rd;
fd_set else_rd;
fd_set else_wr;
int nonsock = 0;
if (nfds < 0 || (timeout && (timeout->tv_sec < 0 || timeout->tv_usec < 0))) {
errno = EINVAL;
return -1;
}
if (!NtSocketsInitialized) {
StartSockets();
}
// assume else_{rd,wr} (other than socket, pipe reader, console reader)
// are always readable/writable. but this implementation still has
// problem. if pipe's buffer is full, writing to pipe will block
// until some data is read from pipe. but ruby is single threaded system,
// so whole system will be blocked forever.
else_rd.fd_count = 0;
nonsock += extract_fd(&else_rd, rd, is_not_socket);
pipe_rd.fd_count = 0;
extract_fd(&pipe_rd, &else_rd, is_pipe); // should not call is_pipe for socket
cons_rd.fd_count = 0;
extract_fd(&cons_rd, &else_rd, is_console); // ditto
else_wr.fd_count = 0;
nonsock += extract_fd(&else_wr, wr, is_not_socket);
r = 0;
if (rd && rd->fd_count > r) r = rd->fd_count;
if (wr && wr->fd_count > r) r = wr->fd_count;
if (ex && ex->fd_count > r) r = ex->fd_count;
if (nfds > r) nfds = r;
if (nfds == 0 && timeout) {
Sleep(timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
return 0;
}
file_nfds = extract_file_fd(rd, &file_rd);
file_nfds += extract_file_fd(wr, &file_wr);
if (file_nfds)
{
// assume normal files are always readable/writable
// fake read/write fd_set and return value
if (rd) *rd = file_rd;
if (wr) *wr = file_wr;
return file_nfds;
struct timeval rest;
struct timeval wait;
struct timeval zero;
if (timeout) rest = *timeout;
wait.tv_sec = 0; wait.tv_usec = 10 * 1000; // 10ms
zero.tv_sec = 0; zero.tv_usec = 0; // 0ms
do {
if (nonsock) {
// modifying {else,pipe,cons}_rd is safe because
// if they are modified, function returns immediately.
extract_fd(&else_rd, &pipe_rd, is_readable_pipe);
extract_fd(&else_rd, &cons_rd, is_readable_console);
}
#if USE_INTERRUPT_WINSOCK
if (ex)
trap = *ex;
else
trap.fd_count = 0;
if (trap.fd_count < FD_SETSIZE)
trap.fd_array[trap.fd_count++] = (SOCKET)interrupted_event;
// else unable to catch interrupt.
ex = &trap;
#endif /* USE_INTERRUPT_WINSOCK */
RUBY_CRITICAL({
r = select(nfds, rd, wr, ex, timeout);
if (r == SOCKET_ERROR) {
errno = map_errno(WSAGetLastError());
if (else_rd.fd_count || else_wr.fd_count) {
r = do_select(nfds, rd, wr, ex, &zero); // polling
if (r < 0) break; // XXX: should I ignore error and return signaled handles?
r += extract_fd(rd, &else_rd, NULL); // move all
r += extract_fd(wr, &else_wr, NULL); // move all
break;
}
});
else {
struct timeval *dowait =
compare(&rest, &wait) < 0 ? &rest : &wait;
fd_set orig_rd;
fd_set orig_wr;
fd_set orig_ex;
if (rd) orig_rd = *rd;
if (wr) orig_wr = *wr;
if (ex) orig_ex = *ex;
r = do_select(nfds, rd, wr, ex, &zero); // polling
if (r != 0) break; // signaled or error
if (rd) *rd = orig_rd;
if (wr) *wr = orig_wr;
if (ex) *ex = orig_ex;
// XXX: should check the time select spent
Sleep(dowait->tv_sec * 1000 + dowait->tv_usec / 1000);
}
} while (!timeout || subst(&rest, &wait));
}
return r;
}
@ -3272,7 +3439,6 @@ rb_w32_times(struct tms *tmbuf)
return 0;
}
#undef Sleep
#define yield_once() Sleep(0)
#define yield_until(condition) do yield_once(); while (!(condition))