diff options
author | matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 1998-07-09 08:40:46 +0000 |
---|---|---|
committer | matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 1998-07-09 08:40:46 +0000 |
commit | 3c1d5b89c33546028fce534546b8e356369ee231 (patch) | |
tree | fb658b101bf9a045c488663f2cbc6b3a178bbd3e | |
parent | 528b1f5237bc4e031228a27c00cdd679319f2472 (diff) |
1.1b9_30
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/v1_1r@263 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 33 | ||||
-rw-r--r-- | MANIFEST | 2 | ||||
-rw-r--r-- | Makefile.in | 1 | ||||
-rw-r--r-- | bignum.c | 36 | ||||
-rw-r--r-- | eval.c | 99 | ||||
-rw-r--r-- | ext/tcltklib/extconf.rb | 2 | ||||
-rw-r--r-- | ext/tcltklib/tcltklib.c | 16 | ||||
-rw-r--r-- | lib/cgi-lib.rb | 2 | ||||
-rw-r--r-- | lib/complex.rb | 14 | ||||
-rw-r--r-- | lib/matrix.rb | 230 | ||||
-rw-r--r-- | lib/singleton.rb | 37 | ||||
-rw-r--r-- | lib/telnet.rb | 200 | ||||
-rw-r--r-- | lib/tk.rb | 472 | ||||
-rw-r--r-- | lib/tkcanvas.rb | 33 | ||||
-rw-r--r-- | lib/tkentry.rb | 6 | ||||
-rw-r--r-- | lib/tkfont.rb | 556 | ||||
-rw-r--r-- | lib/tktext.rb | 66 | ||||
-rw-r--r-- | node.h | 8 | ||||
-rw-r--r-- | numeric.c | 4 | ||||
-rw-r--r-- | parse.y | 50 | ||||
-rw-r--r-- | process.c | 15 | ||||
-rw-r--r-- | regex.c | 2 | ||||
-rw-r--r-- | ruby.h | 2 | ||||
-rw-r--r-- | sample/ruby-mode.el | 2 | ||||
-rw-r--r-- | sample/test.rb | 21 | ||||
-rw-r--r-- | signal.c | 3 | ||||
-rw-r--r-- | sprintf.c | 8 | ||||
-rw-r--r-- | version.h | 4 |
28 files changed, 1722 insertions, 202 deletions
@@ -1,3 +1,32 @@ +Thu Jul 9 17:38:23 1998 Yukihiro Matsumoto <[email protected]> + + * experimental release 1.1b9_30. + +Thu Jul 9 16:01:48 1998 Yukihiro Matsumoto <[email protected]> + + * sprintf.c (fmt_setup): format specifier for long needed. + + * sprintf.c (f_sprintf): ditto. + + * numeric.c (fix2str): ditto. + + * eval.c (thread_create): no more ITIMER_REAL. + + * eval.c (thread_create): thread finalization needed before + aborting thread if thread_abort is set. + +Wed Jul 8 18:17:33 1998 Yukihiro Matsumoto <[email protected]> + + * bignum.c (big_pow): abandon power by bignum (too big). + +Tue Jul 7 13:58:43 1998 Yukihiro Matsumoto <[email protected]> + + * eval.c (rb_catch): add C level catch/throw feature. + +Mon Jul 6 15:18:09 1998 Yukihiro Matsumoto <[email protected]> + + * parse.y (arg): proper return values for `||=' and `&&='. + Fri Jul 3 16:05:11 1998 Yukihiro Matsumoto <[email protected]> * experimental release 1.1b9_29. @@ -9,7 +38,7 @@ Fri Jul 3 11:20:46 1998 Yukihiro Matsumoto <[email protected]> * numeric.c (fix_mul): use FIX2LONG() instead of FIX2INT() for 64bit architectures. - * marshal.c (r_bytes): use weird casting bwetween pointer and int. + * marshal.c (r_bytes): remove weird casting bwetween pointer and int. * process.c (proc_setsid): new method Process#setsid(). @@ -121,7 +150,7 @@ Tue Jun 16 12:30:46 1998 Yukihiro Matsumoto <[email protected]> * struct.c (make_struct): name parameter can be nil for unnamed structures. -pMon Jun 15 16:30:10 1998 Yukihiro Matsumoto <[email protected]> +Mon Jun 15 16:30:10 1998 Yukihiro Matsumoto <[email protected]> * object.c (class_s_inherited): prohibiting to make subclass of class Class. @@ -117,6 +117,7 @@ lib/pstore.rb lib/rational.rb lib/readbytes.rb lib/shellwords.rb +lib/singleton.rb lib/sync.rb lib/telnet.rb lib/tempfile.rb @@ -128,6 +129,7 @@ lib/tkcanvas.rb lib/tkclass.rb lib/tkdialog.rb lib/tkentry.rb +lib/tkfont.rb lib/tkmenubar.rb lib/tkpalette.rb lib/tkscrollbox.rb diff --git a/Makefile.in b/Makefile.in index 3195e89f2f..6cf8af8c95 100644 --- a/Makefile.in +++ b/Makefile.in @@ -13,6 +13,7 @@ PURIFY = prefix = @prefix@ CFLAGS = @CFLAGS@ -I@srcdir@ -I@includedir@ LDFLAGS = @STATIC@ $(CFLAGS) @LDFLAGS@ +EXTLIBS = LIBS = @LIBS@ $(EXTLIBS) MISSING = @LIBOBJS@ @ALLOCA@ LDSHARED = @LDSHARED@ @@ -917,7 +917,7 @@ big_pow(x, y) VALUE x, y; { double d; - VALUE z; + long yy; if (y == INT2FIX(0)) return INT2FIX(1); switch (TYPE(y)) { @@ -926,32 +926,34 @@ big_pow(x, y) break; case T_BIGNUM: - if (RBIGNUM(y)->sign) goto pos_big; + Warn("in a**b, b may be too big"); d = big2dbl(y); break; case T_FIXNUM: - if (FIX2LONG(y) > 0) goto pos_big; - d = (double)FIX2LONG(y); + yy = NUM2LONG(y); + if (yy > 0) { + VALUE z; + + z = x; + for (;;) { + yy = yy - 1; + if (yy == 0) break; + while (yy % 2 == 0) { + yy = yy / 2; + x = big_mul(x, x); + } + z = big_mul(z, x); + } + return z; + } + d = (double)yy; break; default: return num_coerce_bin(x, y); } return float_new(pow(big2dbl(x), d)); - - pos_big: - z = x; - for (;;) { - y = rb_funcall(y, '-', 1, INT2FIX(1)); - if (y == INT2FIX(0)) break; - while (rb_funcall(y, '%', 1, INT2FIX(2)) == INT2FIX(0)) { - y = rb_funcall(y, '/', 1, INT2FIX(2)); - x = big_mul(x, x); - } - z = big_mul(z, x); - } - return z; } VALUE @@ -2066,7 +2066,17 @@ rb_eval(self, node) rval = node->nd_args->nd_head; SETUP_ARGS(node->nd_args->nd_next); val = rb_funcall2(recv, aref, argc-1, argv); - val = rb_funcall(val, node->nd_mid, 1, rb_eval(self, rval)); + if (node->nd_mid == 0) { /* OR */ + if (RTEST(val)) break; + val = rb_eval(self, rval); + } + else if (node->nd_mid == 1) { /* AND */ + if (!RTEST(val)) break; + val = rb_eval(self, rval); + } + else { + val = rb_funcall(val, node->nd_mid, 1, rb_eval(self, rval)); + } argv[argc-1] = val; val = rb_funcall2(recv, aset, argc, argv); result = val; @@ -2080,15 +2090,38 @@ rb_eval(self, node) recv = rb_eval(self, node->nd_recv); val = rb_funcall(recv, id, 0); + if (node->nd_next->nd_mid == 0) { /* OR */ + if (RTEST(val)) break; + val = rb_eval(self, node->nd_value); + } + else if (node->nd_next->nd_mid == 1) { /* AND */ + if (!RTEST(val)) break; + val = rb_eval(self, node->nd_value); + } + else { + val = rb_funcall(val, node->nd_next->nd_mid, 1, + rb_eval(self, node->nd_value)); + } - val = rb_funcall(val, node->nd_next->nd_mid, 1, - rb_eval(self, node->nd_value)); - - rb_funcall2(recv, id_attrset(id), 1, &val); + rb_funcall2(recv, node->nd_next->nd_aid, 1, &val); result = val; } break; + case NODE_OP_ASGN_AND: + result = rb_eval(self, node->nd_head); + if (RTEST(result)) { + result = rb_eval(self, node->nd_value); + } + break; + + case NODE_OP_ASGN_OR: + result = rb_eval(self, node->nd_head); + if (!RTEST(result)) { + result = rb_eval(self, node->nd_value); + } + break; + case NODE_MASGN: result = massign(self, node, rb_eval(self, node->nd_value)); break; @@ -6223,12 +6256,6 @@ thread_create(fn, arg) tval.it_interval.tv_usec = 100000; tval.it_value = tval.it_interval; setitimer(ITIMER_VIRTUAL, &tval, NULL); -#if 1 - tval.it_interval.tv_sec = 2; /* unblock system calls */ - tval.it_interval.tv_usec = 0; - tval.it_value = tval.it_interval; - setitimer(ITIMER_REAL, &tval, NULL); -#endif init = 1; } #endif @@ -6248,15 +6275,29 @@ thread_create(fn, arg) } POP_TAG(); if (state && th->status != THREAD_TO_KILL && !NIL_P(errinfo)) { - if (state == TAG_FATAL || obj_is_kind_of(errinfo, eSystemExit)) { + if (state == TAG_FATAL || obj_is_kind_of(errinfo, eSystemExit) || + thread_abort || curr_thread->abort || RTEST(debug)) { /* fatal error or global exit within this thread */ /* need to stop whole script */ main_thread->errinfo = errinfo; thread_cleanup(); } +#if 0 else if (thread_abort || curr_thread->abort || RTEST(debug)) { - f_abort(); + thread_critical = 0; + thread_ready(main_thread); + main_thread->errinfo = errinfo; + if (curr_thread == main_thread) { + rb_raise(errinfo); + } + curr_thread = main_thread; + th_raise_argc = 1; + th_raise_argv[0] = errinfo; + th_raise_file = sourcefile; + th_raise_line = sourceline; + thread_restore_context(curr_thread, 4); } +#endif else { curr_thread->errinfo = errinfo; } @@ -6531,6 +6572,25 @@ f_catch(dmy, tag) } static VALUE +catch_i(tag) + ID tag; +{ + return f_catch(0, FIX2INT(tag)); +} + +VALUE +rb_catch(tag, proc, data) + char *tag; + VALUE (*proc)(); + VALUE data; +{ + return rb_iterate(catch_i, rb_intern(tag), proc, data); +} + + +static VALUE f_throw _((int,VALUE*)) NORETURN; + +static VALUE f_throw(argc, argv) int argc; VALUE *argv; @@ -6565,6 +6625,19 @@ f_throw(argc, argv) /* not reached */ } +void +rb_throw(tag, val) + char *tag; + VALUE val; +{ + VALUE argv[2]; + ID t = rb_intern(tag); + + argv[0] = FIX2INT(t); + argv[1] = val; + f_throw(2, argv); +} + static void return_check() { diff --git a/ext/tcltklib/extconf.rb b/ext/tcltklib/extconf.rb index 201070c4dd..31c858c203 100644 --- a/ext/tcltklib/extconf.rb +++ b/ext/tcltklib/extconf.rb @@ -45,7 +45,7 @@ search_header("X11/Xlib.h", "/usr/openwin/include", "/usr/X11*/include") -$CFLAGS = "-Wall " + $includes.collect{|path| "-I" + path}.join(" ") +$CFLAGS = $includes.collect{|path| "-I" + path}.join(" ") $libraries = [] def search_lib(file, func, *path) diff --git a/ext/tcltklib/tcltklib.c b/ext/tcltklib/tcltklib.c index ada4c7a96e..df242997e8 100644 --- a/ext/tcltklib/tcltklib.c +++ b/ext/tcltklib/tcltklib.c @@ -26,6 +26,10 @@ fprintf(stderr, ARG1, ARG2); fprintf(stderr, "\n"); } #define DUMP2(ARG1, ARG2) */ +/* for callback break & continue */ +VALUE eTkCallbackBreak; +VALUE eTkCallbackContinue; + /* from tkAppInit.c */ /* @@ -136,8 +140,15 @@ ip_ruby(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) Tcl_ResetResult(interp); if (failed) { + VALUE eclass = CLASS_OF(failed); Tcl_AppendResult(interp, STR2CSTR(failed), (char*)NULL); - return TCL_ERROR; + if (eclass == eTkCallbackBreak) { + return TCL_BREAK; + } else if (eclass == eTkCallbackContinue) { + return TCL_CONTINUE; + } else { + return TCL_ERROR; + } } /* result must be string or nil */ @@ -338,6 +349,9 @@ void Init_tcltklib() VALUE lib = rb_define_module("TclTkLib"); VALUE ip = rb_define_class("TclTkIp", cObject); + eTkCallbackBreak = rb_define_class("TkCallbackBreak", eStandardError); + eTkCallbackContinue = rb_define_class("TkCallbackContinue",eStandardError); + rb_define_module_function(lib, "mainloop", lib_mainloop, 0); rb_define_singleton_method(ip, "new", ip_new, 0); diff --git a/lib/cgi-lib.rb b/lib/cgi-lib.rb index 6a846b2017..c6c1caa98b 100644 --- a/lib/cgi-lib.rb +++ b/lib/cgi-lib.rb @@ -25,7 +25,7 @@ class CGI < SimpleDelegator words = Shellwords.shellwords(if not ARGV.empty? then ARGV.join(' ') else - STDERR.print "(offline mode: enter name=value pairs on standard input)\n" if STDOUT.tty? + STDERR.print "(offline mode: enter name=value pairs on standard input)\n" if STDIN.tty? readlines.join(' ').gsub(/\n/, '') end.gsub(/\\=/, '%3D').gsub(/\\&/, '%26')) diff --git a/lib/complex.rb b/lib/complex.rb index 69437b01bb..59caad6ebc 100644 --- a/lib/complex.rb +++ b/lib/complex.rb @@ -1,8 +1,8 @@ # # complex.rb - # $Release Version: 0.5 $ -# $Revision: 1.1.1.1 $ -# $Date: 1998/01/16 04:05:49 $ +# $Revision: 1.3 $ +# $Date: 1998/07/08 10:05:28 $ # by Keiju ISHITSUKA(SHL Japan Inc.) # # -- @@ -59,6 +59,7 @@ def Complex(a, b = 0) end class Complex < Numeric + @RCS_ID='-$Id: complex.rb,v 1.3 1998/07/08 10:05:28 keiju Exp keiju $-' def Complex.generic?(other) other.kind_of?(Integer) or @@ -284,6 +285,11 @@ class Complex < Numeric @real ^ @image end + def inspect + sprintf("Complex(%s, %s)", @real.inspect, @image.inspect) + end + + I = Complex(0,1) attr :real @@ -396,7 +402,7 @@ module Math cos!(z) else Complex(cos!(z.real)*cosh!(z.image), - sin!(z.real)*sinh!(z.image)) + -sin!(z.real)*sinh!(z.image)) end end @@ -405,7 +411,7 @@ module Math sin!(z) else Complex(sin!(z.real)*cosh!(z.image), - -cos!(z.real)*sinh!(z.image)) + cos!(z.real)*sinh!(z.image)) end end diff --git a/lib/matrix.rb b/lib/matrix.rb index 631b6547b3..6639fe72ea 100644 --- a/lib/matrix.rb +++ b/lib/matrix.rb @@ -1,8 +1,9 @@ +#!/usr/local/bin/ruby # # matrix.rb - # $Release Version: 1.0$ -# $Revision: 1.0 $ -# $Date: 97/05/23 11:35:28 $ +# $Revision: 1.4 $ +# $Date: 1998/07/08 06:39:13 $ # Original Version from Smalltalk-80 version # on July 23, 1985 at 8:37:17 am # by Keiju ISHITSUKA @@ -20,6 +21,150 @@ # column: �� # row: �� # +# module ExceptionForMatrix:: +# Exceptions: +# ErrDimensionMismatch +# �Ԥޤ�����������פ��Ƥ��ʤ�. +# ErrNotRegular +# ��§����Ǥʤ�. +# ErrOperationNotDefined +# ���α黻�ҤϤޤ��������Ƥ��ʤ�. +# +# class Matrix +# include ExceptionForMatrix +# +# Methods: +# class methods: +# Matrix.[](*rows) +# rows���Ϥ��줿�������������. rows����������� +# Matrix[[11, 12], [21, 22]] +# Matrix.rows(rows, copy = TRUE) +# rows��ԥ٥��ȥ�ν���Ȥ��ƹ������������. copy=FALSE �� +# ���Ϥ�������Τޤ��Ѥ���. +# Matrix.columns(columns) +# rows����٥��ȥ�ν���Ȥ��ƹ������������. +# Matrix.diagonal(*values) +# values���г���ʬ�Ȥ����гѹ������������. +# Matrix.scalar(n, value) +# value���г���ʬ�Ȥ���n���ΤΥ����顼�������������. +# Matrix.identity(n) +# Matrix.unit(n) +# Matrix.I(n) +# n����ñ�̹������������. +# Matrix.zero(n) +# n����0-�������������. +# Matrix.row_vector(row) +# row��ԥ٥��ȥ�Ȥ���1-n�������������. row��Vector��Array +# ����ǽ. +# Matrix.column_vector(column) +# column����٥��ȥ�Ȥ���n-1�������������. row��Vector��Array +# ����ǽ. +# accessing: +# [](i, j) +# �����(i, j)��ʬ���֤�. +# row_size +# �Կ����֤�. +# column_size +# ������֤�. +# row(i) +# i���ܤιԥ٥��ȥ���֤�. ���ƥ졼���Ȥ��ƻȤ�줿����, �� +# �٥��ȥ����֤˥��ơ��졼���֥��å����Ϥ�. +# column(j) +# j���ܤ���٥��ȥ���֤�. ��٥��ȥ����֤˥��ơ��졼���� +# ���å����Ϥ�. +# collect +# map +# ���Ƥ����Ǥƥ졼�Ȥ���������ͤ��ͤȤ����������� +# ������. +# minor(*param) +# �ޥ��ʡ�������֤�. �ѥ����Ȥ��Ƥ�, �ʲ��Υѥ����� +# ��: +# 1. from_row, row_size, from_col, size_col +# 2. from_row..to_row, from_col..to_col +# TESTING: +# regular? +# ��§���ɤ���? +# singular? +# ��§�ǤϤʤ����ɤ���? +# square? +# �������ɤ���? +# ARITHMETIC: +# *(m) +# ��ˡ +# +(m) +# ��ˡ +# -(m) +# ��ˡ +# /(m) +# self * m.inv +# inverse +# inv +# �չ��� +# ** +# �Ѿ� +# Matrix functions: +# determinant +# det +# ���� +# rank +# ��� +# trace +# tr +# �ȥ졼�� +# transpose +# t +# ž�ֹ��� +# CONVERTING: +# coerce(other) +# row_vectors +# row�٥��ȥ������ +# column_vectors +# colum�٥��ȥ������ +# to_a +# (2��)������Ѵ� +# to_f +# �����Ǥ�Float���Ѵ� +# to_i +# �����Ǥ�Integer���Ѵ� +# to_r +# �����Ǥ�Rational���Ѵ� +# PRINTING: +# to_s +# ʸ����Ȥ��Ƥ�ɽ�� +# inspect +# +# class Vector +# include ExceptionForMatrix +# +# INSTANCE CREATION: +# Vector.[](*array) +# Vector.elements(array, copy = TRUE) +# ACCSESSING: +# [](i) +# size +# ENUMRATIONS: +# each2(v) +# collect2(v) +# ARITHMETIC: +# *(x) "is matrix or number" +# +(v) +# -(v) +# VECTOR FUNCTIONS: +# inner_product(v) +# collect +# map +# map2(v) +# r +# CONVERTING: +# covector +# to_a +# to_f +# to_i +# to_r +# coerce(other) +# PRINTING: +# to_s +# inspect require "e2mmap.rb" @@ -35,7 +180,7 @@ module ExceptionForMatrix end class Matrix - RCS_ID='-$Header: matrix.rb,v 1.2 91/04/20 17:24:57 keiju Locked $-' + @RCS_ID='-$Id: matrix.rb,v 1.4 1998/07/08 06:39:13 keiju Exp keiju $-' include ExceptionForMatrix @@ -143,6 +288,7 @@ class Matrix if iterator? for e in @rows[i] yield e + end else Vector.elements(@rows[i]) @@ -210,6 +356,38 @@ class Matrix column_size == row_size end + # COMPARING + def ==(other) + return FALSE unless Matrix === other + + other.compare_by_row_vectors(@rows) + end + alias eqn? == + + def compare_by_row_vectors(rows) + return FALSE unless @rows.size == rows.size + + 0.upto(@rows.size - 1) do + |i| + return FALSE unless @rows[i] == rows[i] + end + TRUE + end + + def clone + Matrix.rows(@rows) + end + + def hash + value = 0 + for row in @rows + for e in row + value ^= e.hash + end + end + return value + end + # ARITHMETIC def *(m) #is matrix or vector or number" @@ -296,6 +474,25 @@ class Matrix } Matrix.rows(rows, FALSE) end + + def /(other) + case other + when Numeric + rows = @rows.collect { + |row| + row.collect { + |e| + e / other + } + } + return Matrix.rows(rows, FALSE) + when Matrix + return self * other.inverse + else + x, y = other.coerce(self) + rerurn x / y + end + end def inverse Matrix.fail ErrDimensionMismatch unless square? @@ -319,7 +516,7 @@ class Matrix end for i in 0 .. size - next if i == k + continue if i == k q = a[i][k] / akk a[i][k] = 0 @@ -424,7 +621,7 @@ class Matrix break end end while a[i][k] == 0 - next if nothing + continue if nothing a[i], a[k] = a[k], a[i] akk = a[k][k] end @@ -596,7 +793,6 @@ end #---------------------------------------------------------------------- class Vector include ExceptionForMatrix - #INSTANCE CREATION @@ -648,6 +844,26 @@ class Vector end end + # COMPARING + def ==(other) + return FALSE unless Vector === other + + other.compare_by(@elements) + end + alias eqn? == + + def compare_by(elements) + @elements == elements + end + + def clone + Vector.elements(@rows) + end + + def hash + @elements.hash + end + # ARITHMETIC def *(x) "is matrix or number" @@ -732,7 +948,7 @@ class Vector for e in @elements v += e*e end - return v.sqrt + return Math.sqrt(v) end # CONVERTING diff --git a/lib/singleton.rb b/lib/singleton.rb new file mode 100644 index 0000000000..8167a01aa8 --- /dev/null +++ b/lib/singleton.rb @@ -0,0 +1,37 @@ +# Singleton module that ensures only one object to be allocated. +# +# Usage: +# class SomeSingletonClass +# include Singleton +# #.... +# end +# a = SomeSingletonClass.instance +# b = SomeSingletonClass.instance # a and b are same object +# p [a,b] +# a = SomeSingletonClass.new # error (`new' is private) + +module Singleton + def Singleton.append_features(klass) + klass.private_class_method(:new) + klass.instance_eval %{ + def instance + unless @__instance__ + @__instance__ = new + end + return @__instance__ + end + } + end +end + +if __FILE__ == $0 + class SomeSingletonClass + include Singleton + #.... + end + + a = SomeSingletonClass.instance + b = SomeSingletonClass.instance # a and b are same object + p [a,b] + a = SomeSingletonClass.new # error (`new' is private) +end diff --git a/lib/telnet.rb b/lib/telnet.rb index 44fda9e41a..d9c72f65b2 100644 --- a/lib/telnet.rb +++ b/lib/telnet.rb @@ -1,65 +1,103 @@ # # telnet.rb -# ver0.11 1998/04/21 +# ver0.12 1998/06/01 # Wakou Aoyama <[email protected]> # # == make new Telnet object -# host = Telnet.new("Binmode" => TRUE, default: TRUE -# "Host" => "localhost", default: "localhost" -# "Output_log" => "output_log", default: not output -# "Port" => 23, default: 23 -# "Prompt" => /[$%#>] $/, default: /[$%#>] $/ -# "Telnetmode" => TRUE, default: TRUE -# "Timeout" => 10) default: 10 +# host = Telnet.new({"Binmode" => TRUE, default: TRUE +# "Host" => "localhost", default: "localhost" +# "Output_log" => "output_log", default: not output +# "Port" => 23, default: 23 +# "Prompt" => /[$%#>] $/, default: /[$%#>] $/ +# "Telnetmode" => TRUE, default: TRUE +# "Timeout" => 10, default: 10 +# "Waittime" => 0}) default: 0 # # if set "Telnetmode" option FALSE. not TELNET command interpretation. +# "Waittime" is time to confirm "Prompt". There is a possibility that +# the same character as "Prompt" is included in the data, and, when +# the network or the host is very heavy, the value is enlarged. # # == wait for match -# print host.waitfor(/match/) -# print host.waitfor("Match" => /match/, -# "String" => "string", -# "Timeout" => secs) +# line = host.waitfor(/match/) +# line = host.waitfor({"Match" => /match/, +# "String" => "string", +# "Timeout" => secs}) # if set "String" option. Match = Regexp.new(quote(string)) # # realtime output. of cource, set sync=TRUE or flush is necessary. # host.waitfor(/match/){|c| print c } -# host.waitfor("Match" => /match/, -# "String" => "string", -# "Timeout" => secs){|c| print c} +# host.waitfor({"Match" => /match/, +# "String" => "string", +# "Timeout" => secs}){|c| print c} # # == send string and wait prompt -# print host.cmd("string") -# print host.cmd("String" => "string", -# "Prompt" => /[$%#>] $//, -# "Timeout" => 10) +# line = host.cmd("string") +# line = host.cmd({"String" => "string", +# "Prompt" => /[$%#>] $//, +# "Timeout" => 10}) # # realtime output. of cource, set sync=TRUE or flush is necessary. # host.cmd("string"){|c| print c } -# host.cmd("String" => "string", -# "Prompt" => /[$%#>] $//, -# "Timeout" => 10){|c| print c } +# host.cmd({"String" => "string", +# "Prompt" => /[$%#>] $//, +# "Timeout" => 10}){|c| print c } # # == login # host.login("username", "password") -# host.login("Name" => "username", -# "Password" => "password", -# "Prompt" => /[$%#>] $/, -# "Timeout" => 10) +# host.login({"Name" => "username", +# "Password" => "password", +# "Prompt" => /[$%#>] $/, +# "Timeout" => 10}) +# +# realtime output. of cource, set sync=TRUE or flush is necessary. +# host.login("username", "password"){|c| print c } +# host.login({"Name" => "username", +# "Password" => "password", +# "Prompt" => /[$%#>] $/, +# "Timeout" => 10}){|c| print c } # # and Telnet object has socket class methods # # == sample -# localhost = Telnet.new("Host" => "localhost", -# "Timeout" => 10, -# "Prompt" => /[$%#>] $/) -# localhost.login("username", "password") -# print localhost.cmd("command") +# localhost = Telnet.new({"Host" => "localhost", +# "Timeout" => 10, +# "Prompt" => /[$%#>] $/}) +# localhost.login("username", "password"){|c| print c } +# localhost.cmd("command"){|c| print c } # localhost.close require "socket" require "delegate" +require "thread" + +class TimeOut < Exception +end class Telnet < SimpleDelegator + + def timeout(sec) + is_timeout = FALSE + begin + x = Thread.current + y = Thread.start { + sleep sec + if x.alive? + #print "timeout!\n" + x.raise TimeOut, "timeout" + end + } + begin + yield + rescue TimeOut + is_timeout = TRUE + end + ensure + Thread.kill y if y && y.alive? + end + is_timeout + end + # For those who are curious, here are some of the special characters # interpretted by the telnet protocol: # Name Octal Dec. Description @@ -85,29 +123,41 @@ class Telnet < SimpleDelegator # EOR = "\357" # 239 /* end of record (transparent mode) */ def initialize(options) - @options = {} - @options["Binmode"] = options["Binmode"] || TRUE - @options["Dump_Log"] = options["Dump_Log"] - @options["Errmode"] = options["Errmode"] - @options["Fhopen"] = options["Fhopen"] - @options["Host"] = options["Host"] || "localhost" - @options["Input_log"] = options["Input_log"] - @options["Input_record_separator"] = options["Input_record_separator"] - @options["Output_log"] = options["Output_log"] - @options["Output_record_separator"] = options["Output_record_separator"] - @options["Port"] = options["Port"] || 23 - @options["Prompt"] = options["Prompt"] || /[$%#>] $/ - @options["Telnetmode"] = options["Telnetmode"] || TRUE - @options["Timeout"] = options["Timeout"] || 10 + @options = options + @options["Binmode"] = TRUE if not @options.include?("Binmode") + @options["Host"] = "localhost" if not @options.include?("Host") + @options["Port"] = 23 if not @options.include?("Port") + @options["Prompt"] = /[$%#>] $/ if not @options.include?("Prompt") + @options["Telnetmode"] = TRUE if not @options.include?("Telnetmode") + @options["Timeout"] = 10 if not @options.include?("Timeout") + @options["Waittime"] = 0 if not @options.include?("Waittime") if @options.include?("Output_log") @log = File.open(@options["Output_log"], 'a+') @log.sync = TRUE @log.binmode if @options["Binmode"] end - @sock = TCPsocket.open(@options["Host"], @options["Port"]) + + message = "Trying " + @options["Host"] + "...\n" + STDOUT << message + @log << message if @options.include?("Output_log") + + is_timeout = timeout(@options["Timeout"]){ + begin + @sock = TCPsocket.open(@options["Host"], @options["Port"]) + rescue + @log << $! << "\n" if @options.include?("Output_log") + raise + end + } + raise TimeOut, "timed-out; opening of the host" if is_timeout @sock.sync = TRUE @sock.binmode if @options["Binmode"] + + message = "Connected to " + @options["Host"] + ".\n" + STDOUT << message + @log << message if @options.include?("Output_log") + super(@sock) end @@ -133,48 +183,54 @@ class Telnet < SimpleDelegator end def waitfor(options) - prompt = @options["Prompt"] - timeout = @options["Timeout"] + timeout = @options["Timeout"] + waittime = @options["Waittime"] + if options.kind_of?(Hash) - prompt = options["Prompt"] if options.include?("Prompt") - timeout = options["Timeout"] if options.include?("Timeout") - prompt = Regexp.new( Regexp.quote(options["String"]) ) if + prompt = options["Prompt"] if options.include?("Prompt") + timeout = options["Timeout"] if options.include?("Timeout") + waittime = options["Waittime"] if options.include?("Waittime") + prompt = Regexp.new( Regexp.quote(options["String"]) ) if options.include?("String") else prompt = options end + line = '' - while (not prompt === line and not @sock.closed?) - next if not select([@sock], nil, nil, timeout) + until(not select([@sock], nil, nil, waittime) and prompt === line) + raise TimeOut, "timed-out; wait for the next data" if + not select([@sock], nil, nil, timeout) + buf = '' begin buf = if @options["Telnetmode"] preprocess( @sock.sysread(1024 * 1024) ) else @sock.sysread(1024 * 1024) end - rescue - buf = "\nConnection closed by foreign host.\n" - @sock.close - end - @log.print(buf) if @options.include?("Output_log") - if iterator? - yield buf + rescue EOFError # End of file reached + break + ensure + @log.print(buf) if @options.include?("Output_log") + yield buf if iterator? + line += buf end - line += buf end line end def cmd(options) - match = @options["Prompt"] + match = @options["Prompt"] timeout = @options["Timeout"] + if options.kind_of?(Hash) - string = options["String"] - match = options["Match"] if options.include?("Match") + string = options["String"] + match = options["Match"] if options.include?("Match") timeout = options["Timeout"] if options.include?("Timeout") else string = options end + + select(nil, [@sock]) @sock << string.gsub(/\n/, CR) << CR if iterator? waitfor({"Prompt" => match, "Timeout" => timeout}){|c| yield c } @@ -183,7 +239,7 @@ class Telnet < SimpleDelegator end end - def login(options, password = nil) + def login(options, password = '') if options.kind_of?(Hash) username = options["Name"] password = options["Password"] @@ -191,9 +247,17 @@ class Telnet < SimpleDelegator username = options end - line = waitfor(/login[: ]*$/) - line += cmd({"String" => username, "Match" => /Password[: ]*$/}) - line += cmd(password) + if iterator? + line = waitfor(/login[: ]*$/){|c| yield c } + line += cmd({"String" => username, + "Match" => /Password[: ]*$/}){|c| yield c } + line += cmd(password){|c| yield c } + else + line = waitfor(/login[: ]*$/) + line += cmd({"String" => username, + "Match" => /Password[: ]*$/}) + line += cmd(password) + end line end @@ -257,25 +257,67 @@ module TkComm end end - def _bind(path, context, cmd, args=nil) + def tk_event_sequence(context) context = context.join("><") if context.kind_of? Array if /,/ =~ context context = context.split(/\s*,\s*/).join("><") + else + context end + end + + def _bind_core(mode, path, context, cmd, args=nil) id = install_bind(cmd, args) begin - tk_call 'bind', path, "<#{context}>", id + tk_call 'bind', path, "<#{tk_event_sequence(context)}>", mode + id rescue uninstall_cmd(id) fail end end - private :install_bind, :_bind + + def _bind(path, context, cmd, args=nil) + _bind_core('', path, context, cmd, args=nil) + end + + def _bind_append(path, context, cmd, args=nil) + _bind_core('+', path, context, cmd, args=nil) + end + private :install_bind, :tk_event_sequence, :_bind_core, :_bind, :_bind_append def bind_all(context, cmd=Proc.new, args=nil) _bind 'all', context, cmd, args end + def bind_append_all(context, cmd=Proc.new, args=nil) + _bind_append 'all', context, cmd, args + end + + def bind(tagOrClass, context, cmd=Proc.new, args=nil) + _bind tagOrClass, context, cmd, args + end + + def bind_append(tagOrClass, context, cmd=Proc.new, args=nil) + _bind_append tagOrClass, context, cmd, args + end + + def bindinfo(tagOrClass, context=nil) + if context + (tk_call('bind', tagOrClass, + "<#{tk_event_sequence(context)}>")).collect{|cmdline| + if cmdline =~ /^rb_out (c\d+)\s+(.*)$/ + [Tk_CMDTBL[$1], $2] + else + cmdline + end + } + else + tk_split_list(tk_call 'bind', tagOrClass).collect{|seq| + seq[1..-2].gsub(/></,',') + } + end + end + def pack(*args) TkPack.configure *args end @@ -299,7 +341,16 @@ module TkCore extend TkComm INTERP = TclTkIp.new - INTERP._invoke("proc", "rb_out", "args", "ruby [format \"TkCore.callback %%Q!%s!\" $args]") + + INTERP._invoke("proc", "rb_out", "args", "if {[set st [catch {ruby [format \"TkCore.callback %%Q!%s!\" $args]} ret]] != 0} {return -code $st $ret} {return $ret}") + + def callback_break + raise TkCallbackBreak, "Tk callback returns 'break' status" + end + + def callback_continue + raise TkCallbackContinue, "Tk callback returns 'continue' status" + end def after(ms, cmd=Proc.new) myid = _curr_cmd_id @@ -324,6 +375,39 @@ module TkCore _get_eval_string(TkUtil.eval_cmd(Tk_CMDTBL[arg.shift], *arg)) end + def appname(name=None) + tk_call('tk', 'appname', name) + end + + def appsend(interp, async, *args) + if async + tk_call('send', '-async', '--', interp, *args) + else + tk_call('send', '--', interp, *args) + end + end + + def rb_appsend(interp, async, *args) + args.unshift('ruby {') + args.push('}') + appsend(interp, async, *args) + end + + def appsend_displayof(interp, win, async, *args) + win = '.' if win == nil + if async + tk_call('send', '-async', '-displayof', win, '--', interp, *args) + else + tk_call('send', '-displayor', win, '--', interp, *args) + end + end + + def rb_appsend_displayof(interp, win, async, *args) + args.unshift('ruby {') + args.push('}') + appsend_displayof(interp, win, async, *args) + end + def mainloop TclTkLib.mainloop end @@ -478,8 +562,22 @@ end class TkVariable include Tk + extend TkCore + TkVar_CB_TBL = {} Tk_VARIABLE_ID = ["v00000"] + + INTERP._invoke("proc", "rb_var", "args", "ruby [format \"TkVariable.callback %%Q!%s!\" $args]") + + def TkVariable.callback(args) + name1,name2,op = tk_split_list(args) + if TkVar_CB_TBL[name1] + _get_eval_string(TkVar_CB_TBL[name1].trace_callback(name2,op)) + else + '' + end + end + def initialize(val="") @id = Tk_VARIABLE_ID[0] Tk_VARIABLE_ID[0] = Tk_VARIABLE_ID[0].succ @@ -487,11 +585,13 @@ class TkVariable INTERP._eval(format('global %s; set %s(0) 0; unset %s(0)', @id, @id, @id)) elsif val.kind_of?(Array) - s = '"' + array2tk_list(val).gsub(/[][$"]/, '\\\\\&') + '"' #' - INTERP._eval(format('global %s; array set %s %s', @id, @id, s)) + a = [] + val.each_with_index{|e,i| a.push(i); a.push(array2tk_list(e))} + s = '"' + a.join(" ").gsub(/[][$"]/, '\\\\\&') + '"' #' + INTERP._eval(format('global %s; array set %s %s', @id, @id, s)) elsif val.kind_of?(Hash) s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\ - ..gsub(/[][$"]/, '\\\\\&') + '"' #' + .gsub(/[][$"]/, '\\\\\&') + '"' #' INTERP._eval(format('global %s; array set %s %s', @id, @id, s)) else s = '"' + _get_eval_string(val).gsub(/[][$"]/, '\\\\\&') + '"' #' @@ -514,14 +614,16 @@ class TkVariable if INTERP._eval(format('global %s; array exists %s', @id, @id)) != "1" raise else - INTERP._eval(format('global %s; array get %s', @id, @id)) + Hash(*tk_tcl2ruby(INTERP._eval(format('global %s; array get %s', + @id, @id)))) end end end def value=(val) begin - INTERP._eval(format('global %s; set %s %s', @id, @id, _get_eval_string(val))) + s = '"' + _get_eval_string(val).gsub(/[][$"]/, '\\\\\&') + '"' #' + INTERP._eval(format('global %s; set %s %s', @id, @id, s)) rescue if INTERP._eval(format('global %s; array exists %s', @id, @id)) != "1" raise @@ -531,12 +633,16 @@ class TkVariable INTERP._eval(format('global %s; set %s(0) 0; unset %s(0)', @id, @id, @id)) elsif val.kind_of?(Array) - s = '"' + array2tk_list(val).gsub(/[][$"]/, '\\\\\&') + '"' #' - INTERP._eval(format('global %s; array set %s %s', @id, @id, s)) + a = [] + val.each_with_index{|e,i| a.push(i); a.push(array2tk_list(e))} + s = '"' + a.join(" ").gsub(/[][$"]/, '\\\\\&') + '"' #' + INTERP._eval(format('global %s; unset %s; array set %s %s', + @id, @id, @id, s)) elsif val.kind_of?(Hash) s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\ .gsub(/[][$"]/, '\\\\\&') + '"' #' - INTERP._eval(format('global %s; array set %s %s', @id, @id, s)) + INTERP._eval(format('global %s; unset %s; array set %s %s', + @id, @id, @id, s)) else raise end @@ -594,6 +700,147 @@ class TkVariable def to_eval @id end + + def unset(elem=nil) + if elem + INTERP._eval(format('global %s; unset %s(%s)', + @id, @id, tk_tcl2ruby(elem))) + else + INTERP._eval(format('global %s; unset %s', @id, @id)) + end + end + alias remove unset + + def trace_callback(elem, op) + if @trace_var.kind_of? Array + @trace_var.each{|m,e| e.call(self,elem,op) if m.index(op)} + end + if elem.kind_of? String + if @trace_elem[elem].kind_of? Array + @trace_elem[elem].each{|m,e| e.call(self,elem,op) if m.index(op)} + end + end + end + + def trace(opts, cmd) + @trace_var = [] if @trace_var == nil + opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('') + @trace_var.unshift([opts,cmd]) + if @trace_opts == nil + TkVar_CB_TBL[@id] = self + @trace_opts = opts + Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var') + else + newopts = @trace_opts.dup + opts.each_byte{|c| newopts += c.chr unless @newopts.index(c)} + if newopts != @trace_opts + Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var') + @trace_opts.replace(newopts) + Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var') + end + end + end + + def trace_element(elem, opts, cmd) + @trace_elem = {} if @trace_elem == nil + @trace_elem[elem] = [] if @trace_elem[elem] == nil + opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('') + @trace_elem[elem].unshift([opts,cmd]) + if @trace_opts == nil + TkVar_CB_TBL[@id] = self + @trace_opts = opts + Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var') + else + newopts = @trace_opts.dup + opts.each_byte{|c| newopts += c.chr unless @newopts.index(c)} + if newopts != @trace_opts + Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var') + @trace_opts.replace(newopts) + Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var') + end + end + end + + def trace_vinfo + return [] unless @trace_var + @trace_var.dup + end + def trace_vinfo_for_element(elem) + return [] unless @trace_elem + return [] unless @trace_elem[elem] + @trace_elem[elem].dup + end + + def trace_vdelete(opts,cmd) + return unless @trace_var.kind_of? Array + opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('') + idx = -1 + newopts = '' + @trace_var.each_with_index{|i,e| + if idx < 0 && e[0] == opts && e[1] == cmd + idx = i + continue + end + e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)} + } + if idx >= 0 + @trace_var.delete_at(idx) + else + return + end + + @trace_elem.each{|elem| + @trace_elem[elem].each{|e| + e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)} + } + } + + newopts = ['r','w','u'].find_all{|c| newopts.index(c)}.join('') + if newopts != @trace_opts + Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var') + @trace_opts.replace(newopts) + if @trace_opts != '' + Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var') + end + end + end + + def trace_vdelete_for_element(elem,opts,cmd) + return unless @trace_elem.kind_of? Hash + return unless @trace_elem[elem].kind_of? Array + opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('') + idx = -1 + @trace_elem[elem].each_with_index{|i,e| + if idx < 0 && e[0] == opts && e[1] == cmd + idx = i + continue + end + } + if idx >= 0 + @trace_elem[elem].delete_at(idx) + else + return + end + + newopts = '' + @trace_var.each{|e| + e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)} + } + @trace_elem.each{|elem| + @trace_elem[elem].each{|e| + e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)} + } + } + + newopts = ['r','w','u'].find_all{|c| newopts.index(c)}.join('') + if newopts != @trace_opts + Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var') + @trace_opts.replace(newopts) + if @trace_opts != '' + Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var') + end + end + end end class TkVarAccess<TkVariable @@ -633,6 +880,68 @@ module TkSelection module_function :clear, :get end +module TkKinput + include Tk + extend Tk + + def TkKinput.start(window, style=None) + tk_call 'kinput_start', window.path, style + end + def kinput_start(style=None) + TkKinput.start(self, style) + end + + def TkKinput.send_spot(window) + tk_call 'kinput_send_spot', window.path + end + def kinput_send_spot + TkKinput.send_spot(self) + end + + def TkKinput.input_start(window, keys=nil) + tk_call 'kanjiInput', 'start', window.path, *hash_kv(keys) + end + def kanji_input_start(keys=nil) + TkKinput.input_start(self, keys) + end + + def TkKinput.attribute_config(window, slot, value=None) + if slot.kind_of? Hash + tk_call 'kanjiInput', 'attribute', window.path, *hash_kv(slot) + else + tk_call 'kanjiInput', 'attribute', window.path, "-#{slot}", value + end + end + def kinput_attribute_config(slot, value=None) + TkKinput.attribute_config(self, slot, value) + end + + def TkKinput.attribute_info(window, slot=nil) + if slot + conf = tk_split_list(tk_call('kanjiInput', 'attribute', + window.path, "-#{slot}")) + conf[0] = conf[0][1..-1] + conf + else + tk_split_list(tk_call('kanjiInput', 'attribute', + window.path)).collect{|conf| + conf[0] = conf[0][1..-1] + conf + } + end + end + def kinput_attribute_info(slot=nil) + TkKinput.attribute_info(self, slot) + end + + def TkKinput.input_end(window) + tk_call 'kanjiInput', 'end', window.path + end + def kanji_input_end + TkKinput.input_end(self) + end +end + module TkWinfo include Tk extend Tk @@ -690,7 +999,7 @@ module TkWinfo number(tk_call('winfo', 'fpixels', window.path, number)) end def winfo_fpixels(number) - TkWinfo.fpixels self + TkWinfo.fpixels self, number end def TkWinfo.geometry(window) list(tk_call('winfo', 'geometry', window.path)) @@ -710,6 +1019,29 @@ module TkWinfo def winfo_id TkWinfo.id self end + def TkWinfo.interps(window=nil) + if window + tk_split_list(tk_call('winfo', '-displayof', window.path, + 'interps')).collect{|ip| + if ip.kind_of? Array + ip.flatten.join(' ') + else + ip + end + } + else + tk_split_list(tk_call('winfo', 'interps')).collect{|ip| + if ip.kind_of? Array + ip.flatten.join(' ') + else + ip + end + } + end + end + def winfo_interps + TkWinfo.interps self + end def TkWinfo.mapped?(window) bool(tk_call('winfo', 'ismapped', window.path)) end @@ -1053,6 +1385,10 @@ class TkObject<TkKernel _bind path, context, cmd, args end + def bind_append(context, cmd=Proc.new, args=nil) + _bind_append path, context, cmd, args + end + def tk_trace_variable(v) unless v.kind_of?(TkVariable) fail ArgumentError, format("requires TkVariable given %s", v.type) @@ -1066,7 +1402,28 @@ class TkObject<TkKernel end end +module TkClassBind + WidgetClassNameTBL = {} + + def TkClassBind.name2class(name) + WidgetClassNameTBL[name] + end + + def bind(context, cmd=Proc.new, args=nil) + Tk.bind to_eval, context, cmd, args + end + + def bind_append(context, cmd=Proc.new, args=nil) + Tk.bind_append to_eval, context, cmd, args + end + + def bindinfo(context=nil) + Tk.bind to_eval, context + end +end + class TkWindow<TkObject + extend TkClassBind def initialize(parent=nil, keys=nil) install_win(if parent then parent.path end) @@ -1203,6 +1560,23 @@ class TkWindow<TkObject def wait_destroy tk_call 'tkwait', 'window', path end + + def bindtags(taglist=nil) + if taglist + fail unless taglist.kind_of? Array + tk_call('bindtags', path, taglist) + else + tk_split_list(tk_call('bindtags', path)).collect{|tag| + if tag == nil + '.' + elsif tag.kind_of?(String) && (cls = TkClassBind.name2class(tag)) + cls + else + tag + end + } + end + end end class TkRoot<TkWindow @@ -1214,6 +1588,13 @@ class TkRoot<TkWindow ROOT[0] = new Tk_WINDOWS["."] = new end + + WidgetClassName = 'Tk'.freeze + TkClassBind::WidgetClassNameTBL[WidgetClassName] = self + def self.to_eval + WidgetClassName + end + def create_self @path = '.' end @@ -1224,6 +1605,13 @@ end class TkToplevel<TkWindow include Wm + + WidgetClassName = 'Toplevel'.freeze + TkClassBind::WidgetClassNameTBL[WidgetClassName] = self + def self.to_eval + WidgetClassName + end + def initialize(parent=nil, screen=nil, classname=nil, keys=nil) @screen = screen if screen @classname = classname if classname @@ -1236,15 +1624,29 @@ class TkToplevel<TkWindow s.push "-class #@classname" if @classname tk_call 'toplevel', path, *s end + + def specific_class + @classname + end end class TkFrame<TkWindow + WidgetClassName = 'Frame'.freeze + TkClassBind::WidgetClassNameTBL[WidgetClassName] = self + def self.to_eval + WidgetClassName + end def create_self tk_call 'frame', @path end end class TkLabel<TkWindow + WidgetClassName = 'Label'.freeze + TkClassBind::WidgetClassNameTBL[WidgetClassName] = self + def self.to_eval + WidgetClassName + end def create_self tk_call 'label', @path end @@ -1254,6 +1656,12 @@ class TkLabel<TkWindow end class TkButton<TkLabel + WidgetClassName = 'Button'.freeze + TkClassBind::WidgetClassNameTBL[WidgetClassName] = self +# def TkButton.to_eval + def self.to_eval + WidgetClassName + end def create_self tk_call 'button', @path end @@ -1266,6 +1674,11 @@ class TkButton<TkLabel end class TkRadioButton<TkButton + WidgetClassName = 'Radiobutton'.freeze + TkClassBind::WidgetClassNameTBL[WidgetClassName] = self + def TkRadioButton.to_eval + WidgetClassName + end def create_self tk_call 'radiobutton', @path end @@ -1281,6 +1694,10 @@ class TkRadioButton<TkButton end class TkCheckButton<TkRadioButton + TkClassBind::WidgetClassNameTBL['Checkbutton'] = self + def TkCheckButton.to_eval + 'Checkbutton' + end def create_self tk_call 'checkbutton', @path end @@ -1290,12 +1707,22 @@ class TkCheckButton<TkRadioButton end class TkMessage<TkLabel + TkClassBind::WidgetClassNameTBL['Message'] = self + def TkMessage.to_eval + 'Message' + end def create_self tk_call 'message', @path end end class TkScale<TkWindow + WidgetClassName = 'Scale'.freeze + TkClassBind::WidgetClassNameTBL[WidgetClassName] = self + def self.to_eval + WidgetClassName + end + def create_self tk_call 'scale', path end @@ -1318,6 +1745,12 @@ class TkScale<TkWindow end class TkScrollbar<TkWindow + WidgetClassName = 'Scrollbar'.freeze + TkClassBind::WidgetClassNameTBL[WidgetClassName] = self + def self.to_eval + WidgetClassName + end + def create_self tk_call 'scrollbar', path end @@ -1380,6 +1813,10 @@ class TkTextWin<TkWindow end class TkListbox<TkTextWin + TkClassBind::WidgetClassNameTBL['Listbox'] = self + def TkListbox.to_eval + 'Listbox' + end def create_self tk_call 'listbox', path end @@ -1419,6 +1856,11 @@ class TkListbox<TkTextWin end class TkMenu<TkWindow + WidgetClassName = 'Menu'.freeze + TkClassBind::WidgetClassNameTBL[WidgetClassName] = self + def self.to_eval + WidgetClassName + end def create_self tk_call 'menu', path end @@ -1461,6 +1903,10 @@ class TkMenu<TkWindow end class TkMenubutton<TkLabel + TkClassBind::WidgetClassNameTBL['Menubutton'] = self + def TkMenubutton.to_eval + 'Menubutton' + end def create_self tk_call 'menubutton', path end diff --git a/lib/tkcanvas.rb b/lib/tkcanvas.rb index 1d4c4c583a..4ee0c3cd48 100644 --- a/lib/tkcanvas.rb +++ b/lib/tkcanvas.rb @@ -8,6 +8,12 @@ require "tk" class TkCanvas<TkWindow + WidgetClassName = 'Canvas'.freeze + TkClassBind::WidgetClassNameTBL[WidgetClassName] = self + def self.to_eval + WidgetClassName + end + def create_self tk_call 'canvas', path end @@ -51,13 +57,9 @@ class TkCanvas<TkWindow end def itembind(tag, context, cmd=Proc.new, args=nil) - context = context.join("><") if context.kind_of? Array - if /,/ =~ context - context = context.split(/\s*,\s*/).join("><") - end id = install_bind(cmd, args) begin - tk_send 'bind', tagid(tag), "<#{context}>", id + tk_send 'bind', tagid(tag), "<#{tk_event_sequence(context)}>", id rescue uninstall_cmd(cmd) fail @@ -65,6 +67,23 @@ class TkCanvas<TkWindow # @cmdtbl.push id end + def itembindinfo(tag, context=nil) + if context + (tk_send('bind', tagid(tag), + "<#{tk_event_sequence(context)}>")).collect{|cmdline| + if cmdline =~ /^rb_out (c\d+)\s+(.*)$/ + [Tk_CMDTBL[$1], $2] + else + cmdline + end + } + else + tk_split_list(tk_send 'bind', tagid(tag)).filter{|seq| + seq[1..-2].gsub(/></,',') + } + end + end + def canvasx(x, *args) tk_tcl2ruby(tk_send 'canvasx', x, *args) end @@ -252,6 +271,10 @@ module TkcTagAccess @c.itembind @id, seq, cmd, args end + def bindinfo(seq=nil) + @c.itembindinfo @id, seq + end + def cget(option) @c.itemcget @id, option end diff --git a/lib/tkentry.rb b/lib/tkentry.rb index 645fc997b1..b834c455c6 100644 --- a/lib/tkentry.rb +++ b/lib/tkentry.rb @@ -6,6 +6,12 @@ require 'tk.rb' class TkEntry<TkLabel + WidgetClassName = 'Entry'.freeze + TkClassBind::WidgetClassNameTBL[WidgetClassName] = self + def self.to_eval + WidgetClassName + end + def create_self tk_call 'entry', @path end diff --git a/lib/tkfont.rb b/lib/tkfont.rb new file mode 100644 index 0000000000..5e20359523 --- /dev/null +++ b/lib/tkfont.rb @@ -0,0 +1,556 @@ +class TkFont + include Tk + extend TkCore + + Tk_FontID = [0] + Tk_FontNameTBL = {} + Tk_FontUseTBL = {} + + DEFAULT_LATIN_FONT_NAME = 'a14'.freeze + DEFAULT_KANJI_FONT_NAME = 'k14'.freeze + + ################################### + # class methods + ################################### + def TkFont.families(window=nil) + case (Tk::TK_VERSION) + when /^4.*/ + ['fixed'] + + when /^8.*/ + if window + list(tk_call('font', 'families', '-displayof', window)) + else + list(tk_call('font', 'families')) + end + end + end + + def TkFont.names + r = [] + case (Tk::TK_VERSION) + when /^4.*/ + r += ['fixed', 'a14', 'k14'] + Tk_FontNameTBL.each_value{|obj| r.push(obj)} + when /^8.*/ + list(tk_call('font', 'names')).each{|f| + if f =~ /^(@font[0-9]+)(c|l|k)$/ + r.push(Tk_FontNameTBL[$1]) if $2 == 'c' + else + r.push(f) + end + } + end + r + end + + ################################### + private + ################################### + def initialize(ltn=nil, knj=nil, keys=nil) + @id = format("@font%.4d", Tk_FontID[0]) + Tk_FontID[0] += 1 + Tk_FontNameTBL[@id] = self + + ltn = DEFAULT_LATIN_FONT_NAME unless ltn + create_latinfont(ltn) + + knj = DEFAULT_KANJI_FONT_NAME unless knj + create_kanjifont(knj) + + create_compoundfont(keys) + end + + def _get_font_info_from_hash(font) + foundry = (info = font['foundry'] .to_s)? info: '*' + family = (info = font['family'] .to_s)? info: '*' + weight = (info = font['weight'] .to_s)? info: '*' + slant = (info = font['slant'] .to_s)? info: '*' + swidth = (info = font['swidth'] .to_s)? info: '*' + adstyle = (info = font['adstyle'] .to_s)? info: '*' + pixels = (info = font['pixels'] .to_s)? info: '*' + points = (info = font['points'] .to_s)? info: '*' + resx = (info = font['resx'] .to_s)? info: '*' + resy = (info = font['resy'] .to_s)? info: '*' + space = (info = font['space'] .to_s)? info: '*' + avgWidth = (info = font['avgWidth'].to_s)? info: '*' + charset = (info = font['charset'] .to_s)? info: '*' + encoding = (info = font['encoding'].to_s)? info: '*' + + Array([foundry, family, weight, slant, swidth, adstyle, + pixels, points, resx, resy, space, avgWidth, charset, encoding]) + end + + def create_latinfont_tk4x(font=nil) + if font.kind_of? Hash + @latinfont = '-' + _get_font_info_from_hash(font).join('-') + '-' + + elsif font.kind_of? Array + finfo = {} + finfo['family'] = font[0].to_s + if font[1] && font[1] != '0' && font[1] =~ /^(|\+|-)([0-9]+)$/ + if $1 == '-' + finfo['pixels'] = font[1].to_s + else + finfo['points'] = font[1].to_s + end + end + finfo[2..-1].each{|style| + case (style) + when 'normal' + finfo['weight'] = style + when 'bold' + finfo['weight'] = style + when 'roman' + finfo['slant'] = 'r' + when 'italic' + finfo['slant'] = 'i' + end + } + + @latinfont = '-' + _get_font_info_from_hash(finfo).join('-') + '-' + + elsif font.kind_of? TkFont + @latinfont = font.latin_font + + else + @latinfont = font + + end + end + + def create_kanjifont_tk4x(font=nil) + if font.kind_of? Hash + @kanjifont = '-' + _get_font_info_from_hash(font).join('-') + '-' + + elsif font.kind_of? Array + finfo = {} + finfo['family'] = font[0].to_s + if font[1] && font[1] != '0' && font[1] =~ /^(|\+|-)([0-9]+)$/ + if $1 == '-' + finfo['pixels'] = $2 + else + finfo['points'] = $2 + end + else + finfo['points'] = '13' + end + finfo[2..-1].each{|style| + case (style) + when 'normal' + finfo['weight'] = style + when 'bold' + finfo['weight'] = style + when 'roman' + finfo['slant'] = 'r' + when 'italic' + finfo['slant'] = 'i' + end + } + + @kanjifont = '-' + _get_font_info_from_hash(finfo).join('-') + '-' + + elsif font.kind_of? TkFont + @kanjifont = font.kanji_font + + else + @kanjifont = font + + end + end + + def create_compoundfont_tk4x(keys) + @compoundfont = [[@latinfont], [@kanjifont]] + @fontslot = {'font'=>@latinfont, 'kanjifont'=>@kanjifont} + end + + def create_latinfont_tk80(font=nil) + @latinfont = @id + 'l' + + if font.kind_of? Hash + tk_call('font', 'create', @latinfont, *hash_kv(font)) + elsif font.kind_of? Array + tk_call('font', 'create', @latinfont, '-copy', array2tk_list(font)) + elsif font.kind_of? TkFont + tk_call('font', 'create', @latinfont, '-copy', font.latin_font) + else + tk_call('font', 'create', @latinfont, '-copy', font) + end + end + + def create_kanjifont_tk80(font=nil) + @kanjifont = @id + 'k' + + if font.kind_of? Hash + if font['charset'] + tk_call('font', 'create', @kanjifont, *hash_kv(font)) + else + tk_call('font', 'create', @kanjifont, + '-charset', 'jisx0208.1983', *hash_kv(font)) + end + elsif font.kind_of? Array + tk_call('font', 'create', @kanjifont, '-copy', array2tk_list(font)) + tk_call('font', 'configure', @kanjifont, '-charset', 'jisx0208.1983') + + elsif font.kind_of? TkFont + tk_call('font', 'create', @kanjifont, '-copy', font.kanji_font) + + else + tk_call('font', 'create', @kanjifont, '-copy', font, + '-charset', 'jisx0208.1983') + + end + end + + def create_compoundfont_tk80(keys) + @compoundfont = @id + 'c' + @fontslot = {'font'=>@compoundfont} + tk_call('font', 'create', @compoundfont, + '-compound', "#{@latinfont} #{@kanjifont}", *hash_kv(keys)) + end + + def set_font_core_tk4x(window) + Tk_FontUseTBL[window.path] = @id + window.configure(@fontslot) + end + + def set_font_core_tk80(window) + window.configure(@fontslot) + end + + def actual_core_tk4x(font, window=nil, option=nil) + # dummy + if option + "" + else + Array([ ['family',[]], ['size',[]], ['weight',[]], ['slant',[]], + ['underline',[]], ['overstrike',[]], ['charset',[]], + ['pointadjust',[]] ]) + end + end + + def actual_core_tk80(font, window=nil, option=nil) + if option == 'compound' + "" + elsif option + if window + tk_call('font', 'actual', font, "-#{option}") + else + tk_call('font', 'actual', font, "-displayof", window, "-#{option}") + end + else + l = tk_split_list(if window + tk_call('font', 'actual', font, "-displayof", window) + else + tk_call('font', 'actual', font) + end) + r = [] + while key=l.shift + if key == '-compound' + l.shift + else + r.push [key[1..-1], l.shift] + end + end + r + end + end + + def configure_core_tk4x(font, slot, value=None) + "" + end + + def configinfo_core_tk4x(font, option=nil) + # dummy + if option + "" + else + Array([ ['family',[]], ['size',[]], ['weight',[]], ['slant',[]], + ['underline',[]], ['overstrike',[]], ['charset',[]], + ['pointadjust',[]] ]) + end + end + + def configure_core_tk80(font, slot, value=None) + if slot.kind_of? Hash + tk_call 'font', 'configure', font, *hash_kv(slot) + else + tk_call 'font', 'configure', font, "-#{slot}", value + end + end + + def configinfo_core_tk80(font, option=nil) + if option == 'compound' + "" + elsif option + tk_call('font', 'configure', font, "-#{option}") + else + l = tk_split_list(tk_call('font', 'configure', font)) + r = [] + while key=l.shift + if key == '-compound' + l.shift + else + r.push [key[1..-1], l.shift] + end + end + r + end + end + + def latin_replace_core_tk4x(ltn) + create_latinfont_tk4x(ltn) + @compoundfont[0] = [@latinfont] + @fontslot['font'] = @latinfont + Tk_FontUseTBL.dup.each{|w, id| + if id == @id + begin + w.configure('font', @latinfont) + rescue + Tk_FontUseTBL[w] = nil + end + end + } + self + end + + def kanji_replace_core_tk4x(knj) + create_kanjifont_tk4x(knj) + @compoundfont[1] = [@kanjifont] + @fontslot['kanjifont'] = @kanjifont + Tk_FontUseTBL.dup.each{|w, id| + if id == @id + begin + w.configure('kanjifont', @kanjifont) + rescue + Tk_FontUseTBL[w] = nil + end + end + } + self + end + + def latin_replace_core_tk80(ltn) + tk_call('font', 'delete', @latinfont) + create_latinfont_tk80(ltn) + self + end + + def kanji_replace_core_tk80(knj) + tk_call('font', 'delete', @kanjifont) + create_kanjifont_tk80(knj) + self + end + + def measure_core_tk4x(window, text) + 0 + end + + def measure_core_tk80(window, text) + if window + number(tk_call('font', 'measure', @compoundfont, + '-displayof', window, text)) + else + number(tk_call('font', 'measure', @compoundfont, text)) + end + end + + def metrics_core_tk4x(font, window, option=nil) + # dummy + if option + "" + else + Array([ ['ascent',[]], ['descent',[]], ['linespace',[]], ['fixed',[]] ]) + end + end + + def metrics_core_tk80(font, window, option=nil) + if option + if window + number(tk_call('font', 'metrics', font, "-#{option}")) + else + number(tk_call('font', 'metrics', font, + "-displayof", window, "-#{option}")) + end + else + l = tk_split_list(if window + tk_call('font','metrics',font,"-displayof",window) + else + tk_call('font','metrics',font) + end) + r = [] + while key=l.shift + r.push [key[1..-1], l.shift.to_i] + end + r + end + end + + ################################### + # private alias + ################################### + case (Tk::TK_VERSION) + when /^4.*/ + alias create_latinfont create_latinfont_tk4x + alias create_kanjifont create_kanjifont_tk4x + alias create_compoundfont create_compoundfont_tk4x + alias set_font_core set_font_core_tk4x + alias actual_core actual_core_tk4x + alias configure_core configure_core_tk4x + alias configinfo_core configinfo_core_tk4x + alias latin_replace_core latin_replace_core_tk4x + alias kanji_replace_core kanji_replace_core_tk4x + alias measure_core measure_core_tk4x + alias metrics_core metrics_core_tk4x + + when /^8\.0/ + alias create_latinfont create_latinfont_tk80 + alias create_kanjifont create_kanjifont_tk80 + alias create_compoundfont create_compoundfont_tk80 + alias set_font_core set_font_core_tk80 + alias actual_core actual_core_tk80 + alias configure_core configure_core_tk80 + alias configinfo_core configinfo_core_tk80 + alias latin_replace_core latin_replace_core_tk80 + alias kanji_replace_core kanji_replace_core_tk80 + alias measure_core measure_core_tk80 + alias metrics_core metrics_core_tk80 + + end + + ################################### + public + ################################### + def set_font(window) + set_font_core(window) + end + + def latin_font + @latinfont + end + + def kanji_font + @kanjifont + end + + def actual(option=nil) + actual_core(@compoundfont, nil, option) + end + + def actual_displayof(window, option=nil) + window = '.' unless window + actual_core(@compoundfont, window, option) + end + + def latin_actual(option=nil) + actual_core(@latinfont, nil, option) + end + + def latin_actual_displayof(window, option=nil) + window = '.' unless window + actual_core(@latinfont, window, option) + end + + def kanji_actual(option=nil) + actual_core(@kanjifont, nil, option) + end + + def kanji_actual_displayof(window, option=nil) + window = '.' unless window + actual_core(@kanjifont, window, option) + end + + def [](slot) + configinfo slot + end + + def []=(slot, val) + configure slot, val + end + + def configure(slot, value=None) + configure_core(@compoundfont, slot, value) + end + + def configinfo(slot=nil) + configinfo_core(@compoundfont, slot) + end + + def latin_configure(slot, value=None) + configure_core(@latinfont, slot, value) + end + + def latin_configinfo(slot=nil) + configinfo_core(@latinfont, slot) + end + + def kanji_configure(slot, value=None) + configure_core(@kanjifont, slot, value) + end + + def kanji_configinfo(slot=nil) + configinfo_core(@kanjifont, slot) + end + + def replace(ltn, knj) + latin_replace(ltn) + kanji_replace(ltn) + end + + def latin_replace(ltn) + latin_replace_core(ltn) + end + + def kanji_replace(knj) + kanji_replace_core(knj) + end + + def measure(text) + measure_core(nil, text) + end + + def measure_displayof(window, text) + window = '.' unless window + measure_core(window, text) + end + + def metrics(option=nil) + metrics_core(@compoundfont, nil, option) + end + + def metrics_displayof(window, option=nil) + window = '.' unless window + metrics_core(@compoundfont, window, option) + end + + def latin_metrics(option=nil) + metrics_core(@latinfont, nil, option) + end + + def latin_metrics_displayof(window, option=nil) + window = '.' unless window + metrics_core(@latinfont, window, option) + end + + def kanji_metrics(option=nil) + metrics_core(@kanjifont, nil, option) + end + + def kanji_metrics_displayof(window, option=nil) + window = '.' unless window + metrics_core(@kanjifont, window, option) + end + + ################################### + # public alias + ################################### + alias ascii_font latin_font + alias create_asciifont create_latinfont + alias ascii_actual latin_actual + alias ascii_actual_displayof latin_actual_displayof + alias ascii_configure latin_configure + alias ascii_configinfo latin_configinfo + alias ascii_replace latin_replace + alias ascii_metrics latin_metrics + +end diff --git a/lib/tktext.rb b/lib/tktext.rb index 74fec8c953..7b5cea5c72 100644 --- a/lib/tktext.rb +++ b/lib/tktext.rb @@ -6,6 +6,11 @@ require 'tk.rb' class TkText<TkTextWin + WidgetClassName = 'Text'.freeze + TkClassBind::WidgetClassNameTBL[WidgetClassName] = self + def self.to_eval + WidgetClassName + end include Scrollable def create_self tk_call 'text', @path @@ -115,20 +120,36 @@ class TkText<TkTextWin tk_send 'tag', 'add', tag, index1, index2 end - def tag_bind(tag, seq, cmd=Proc.new, args=nil) - seq = context.join("><") if seq.kind_of? Array - if /,/ =~ seq - seq = seq.split(/\s*,\s*/).join("><") - end + def _tag_bind_core(mode, tag, seq, cmd=Proc.new, args=nil) id = install_bind(cmd, args) - tk_send 'tag', 'bind', tag, "<#{seq}>", id + tk_send 'tag', 'bind', tag, "<#{tk_event_sequence(seq)}>", mode + id # _addcmd cmd end + private :_tag_bind_core - def tag_bindinfo(tag) - tk_split_list(tk_send('tag', 'bind', tag)).filter{|seq| - seq.tr('<>',' ').strip.gsub(/\s+/,',') - } + def tag_bind(tag, seq, cmd=Proc.new, args=nil) + _tag_bind_core('', tag, seq, cmd=Proc.new, args=nil) + end + + def tag_bind_append(tag, seq, cmd=Proc.new, args=nil) + _tag_bind_core('+', tag, seq, cmd=Proc.new, args=nil) + end + + def tag_bindinfo(tag, context=nil) + if context + (tk_send('tag', 'bind', tag, + "<#{tk_event_sequence(context)}>")).collect{|cmdline| + if cmdline =~ /^rb_out (c\d+)\s+(.*)$/ + [Tk_CMDTBL[$1], $2] + else + cmdline + end + } + else + tk_split_list(tk_send('tag', 'bind', tag)).filter{|seq| + seq[1..-2].gsub(/></,',') + } + end end def tag_cget(tag, key) @@ -357,19 +378,26 @@ class TkTextTag<TkObject end def bind(seq, cmd=Proc.new, args=nil) - seq = context.join("><") if seq.kind_of? Array - if /,/ =~ seq - seq = seq.split(/\s*,\s*/).join("><") - end id = install_bind(cmd, args) - tk_call @t.path, 'tag', 'bind', @id, "<#{seq}>", id + tk_call @t.path, 'tag', 'bind', @id, "<#{tk_event_sequence(seq)}>", id # @t._addcmd cmd end - def bindinfo - tk_split_list(tk_call(@t.path, 'tag', 'bind', @id)).filter{|seq| - seq.tr('<>',' ').strip.gsub(/\s+/,',') - } + def bindinfo(context=nil) + if context + (tk_call(@t.path, 'tag', 'bind', @id, + "<#{tk_event_sequence(context)}>")).collect{|cmdline| + if cmdline =~ /^rb_out (c\d+)\s+(.*)$/ + [Tk_CMDTBL[$1], $2] + else + cmdline + end + } + else + tk_split_list(tk_call(@t.path, 'tag', 'bind', @id)).filter{|seq| + seq[1..-2].gsub(/></,',') + } + end end def raise(above=None) @@ -47,6 +47,8 @@ enum node_type { NODE_CASGN, NODE_OP_ASGN1, NODE_OP_ASGN2, + NODE_OP_ASGN_AND, + NODE_OP_ASGN_OR, NODE_CALL, NODE_FCALL, NODE_VCALL, @@ -255,8 +257,10 @@ typedef struct RNode { #define NEW_IASGN(v,val) node_newnode(NODE_IASGN,v,val,0) #define NEW_CASGN(v,val) node_newnode(NODE_CASGN,v,val,0) #define NEW_OP_ASGN1(p,id,a) node_newnode(NODE_OP_ASGN1,p,id,a) -#define NEW_OP_ASGN2(r,i,o,val) node_newnode(NODE_OP_ASGN2,r,val,NEW_OP_ASGN3(i,o)) -#define NEW_OP_ASGN3(i,o) node_newnode(NODE_OP_ASGN2,i,o,0) +#define NEW_OP_ASGN2(r,i,o,val) node_newnode(NODE_OP_ASGN2,r,val,NEW_OP_ASGN22(i,o)) +#define NEW_OP_ASGN22(i,o) node_newnode(NODE_OP_ASGN2,i,o,id_attrset(i)) +#define NEW_OP_ASGN_OR(i,val) node_newnode(NODE_OP_ASGN_OR,i,val,0) +#define NEW_OP_ASGN_AND(i,val) node_newnode(NODE_OP_ASGN_AND,i,val,0) #define NEW_GVAR(v) node_newnode(NODE_GVAR,v,0,rb_global_entry(v)) #define NEW_LVAR(v) node_newnode(NODE_LVAR,v,0,local_cnt(v)) #define NEW_DVAR(v) node_newnode(NODE_DVAR,v,0,0); @@ -789,7 +789,7 @@ fix2str(x, base) else if (base == 8) fmt[2] = 'o'; else Fatal("fixnum cannot treat base %d", base); - sprintf(buf, fmt, FIX2INT(x)); + sprintf(buf, fmt, FIX2LONG(x)); return str_new2(buf); } @@ -1099,7 +1099,7 @@ fix_lshift(x, y) val = NUM2LONG(x); width = NUM2LONG(y); if (width > (sizeof(VALUE)*CHAR_BIT-1) - || (unsigned)val>>(sizeof(VALUE)*CHAR_BIT-1-width) > 0) { + || (unsigned long)val>>(sizeof(VALUE)*CHAR_BIT-1-width) > 0) { return big_lshift(int2big(val), y); } val = val << width; @@ -32,12 +32,12 @@ #define ID_ATTRSET 0x04 #define ID_CONST 0x05 -#define is_id_nonop(id) ((id)>LAST_TOKEN) -#define is_local_id(id) (is_id_nonop(id)&&((id)&ID_SCOPE_MASK)==ID_LOCAL) -#define is_global_id(id) (is_id_nonop(id)&&((id)&ID_SCOPE_MASK)==ID_GLOBAL) -#define is_instance_id(id) (is_id_nonop(id)&&((id)&ID_SCOPE_MASK)==ID_INSTANCE) -#define is_attrset_id(id) (is_id_nonop(id)&&((id)&ID_SCOPE_MASK)==ID_ATTRSET) -#define is_const_id(id) (is_id_nonop(id)&&((id)&ID_SCOPE_MASK)==ID_CONST) +#define is_id_notop(id) ((id)>LAST_TOKEN) +#define is_local_id(id) (is_id_notop(id)&&((id)&ID_SCOPE_MASK)==ID_LOCAL) +#define is_global_id(id) (is_id_notop(id)&&((id)&ID_SCOPE_MASK)==ID_GLOBAL) +#define is_instance_id(id) (is_id_notop(id)&&((id)&ID_SCOPE_MASK)==ID_INSTANCE) +#define is_attrset_id(id) (is_id_notop(id)&&((id)&ID_SCOPE_MASK)==ID_ATTRSET) +#define is_const_id(id) (is_id_notop(id)&&((id)&ID_SCOPE_MASK)==ID_CONST) struct op_tbl { ID token; @@ -600,10 +600,12 @@ arg : variable '=' arg } } if ($2 == tOROP) { - $$ = NEW_UNLESS(gettable($1), assignable($1, $3), 0); + $$ = NEW_OP_ASGN_OR(gettable($1), + assignable($1, $3)); } else if ($2 == tANDOP) { - $$ = NEW_IF(gettable($1), assignable($1, $3), 0); + $$ = NEW_OP_ASGN_AND(gettable($1), + assignable($1, $3)); } else { $$ = assignable($1,call_op(gettable($1),$2,1,$3)); @@ -612,45 +614,39 @@ arg : variable '=' arg } | primary '[' aref_args ']' tOP_ASGN arg { + NODE *args = NEW_LIST($6); + + list_append($3, NEW_NIL()); + list_concat(args, $3); if ($5 == tOROP) { - $$ = NEW_UNLESS(NEW_CALL($1, tAREF, $3), aryset($1, $3, $6), 0); + $5 = 0; } else if ($5 == tANDOP) { - $$ = NEW_IF(NEW_CALL($1, tAREF, $3), aryset($1, $3, $6), 0); - } - else { - NODE *args = NEW_LIST($6); - - list_append($3, NEW_NIL()); - list_concat(args, $3); - $$ = NEW_OP_ASGN1($1, $5, args); + $5 = 1; } + $$ = NEW_OP_ASGN1($1, $5, args); fixpos($$, $1); } | primary '.' tIDENTIFIER tOP_ASGN arg { if ($4 == tOROP) { - $$ = NEW_UNLESS(new_call($1, $3, 0), attrset($1, $3, $5), 0); + $4 = 0; } else if ($4 == tANDOP) { - $$ = NEW_IF(new_call($1, $3, 0), attrset($1, $3, $5), 0); - } - else { - $$ = NEW_OP_ASGN2($1, $3, $4, $5); + $4 = 1; } + $$ = NEW_OP_ASGN2($1, $3, $4, $5); fixpos($$, $1); } | primary '.' tCONSTANT tOP_ASGN arg { if ($4 == tOROP) { - $$ = NEW_UNLESS(new_call($1, $3, 0), attrset($1, $3, $5), 0); + $4 = 0; } else if ($4 == tANDOP) { - $$ = NEW_IF(new_call($1, $3, 0), attrset($1, $3, $5), 0); - } - else { - $$ = NEW_OP_ASGN2($1, $3, $4, $5); + $4 = 1; } + $$ = NEW_OP_ASGN2($1, $3, $4, $5); fixpos($$, $1); } | backref tOP_ASGN arg @@ -66,9 +66,8 @@ get_ppid() VALUE last_status = Qnil; -#if defined(HAVE_WAITPID) || defined(HAVE_WAIT4) -# define WAIT_CALL -#else +#if !defined(HAVE_WAITPID) && !defined(HAVE_WAIT4) +#define NO_WAITPID static st_table *pid_tbl; #endif @@ -79,7 +78,7 @@ rb_waitpid(pid, flags, st) int *st; { int result; -#ifdef WAIT_CALL +#ifndef NO_WAITPID #if defined(THREAD) int oflags = flags; if (!thread_alone()) { /* there're other threads to run */ @@ -110,7 +109,7 @@ rb_waitpid(pid, flags, st) goto retry; } #endif -#else /* WAIT_CALL */ +#else /* NO_WAITPID */ if (pid_tbl && st_lookup(pid_tbl, pid, st)) { last_status = INT2FIX(*st); st_delete(pid_tbl, &pid, NULL); @@ -147,7 +146,7 @@ rb_waitpid(pid, flags, st) return result; } -#ifndef WAIT_CALL +#ifdef NO_WAITPID struct wait_data { int pid; int status; @@ -170,7 +169,7 @@ static VALUE f_wait() { int pid, state; -#ifndef WAIT_CALL +#ifdef NO_WAITPID struct wait_data data; data.status = -1; @@ -847,7 +846,7 @@ proc_setsid() int pid = setsid(); if (pid < 0) rb_sys_fail(0); - return NUM2INT(pid); + return INT2FIX(pid); #else rb_notimplement(); #endif @@ -152,7 +152,7 @@ static int group_match_null_string_p (); static char re_syntax_table[256]; static void init_syntax_once P((void)); -static char *translate = 0; +static unsigned char *translate = 0; #undef P @@ -480,6 +480,8 @@ int iterator_p _((void)); VALUE rb_iterate _((VALUE(*)(),VALUE,VALUE(*)(),VALUE)); VALUE rb_rescue _((VALUE(*)(),VALUE,VALUE(*)(),VALUE)); VALUE rb_ensure _((VALUE(*)(),VALUE,VALUE(*)(),VALUE)); +VALUE rb_catch _((char*,VALUE(*)(),VALUE)); +void rb_throw _((char*,VALUE)) NORETURN; extern VALUE mKernel; extern VALUE mComparable; diff --git a/sample/ruby-mode.el b/sample/ruby-mode.el index 7b9549612c..bfecb51214 100644 --- a/sample/ruby-mode.el +++ b/sample/ruby-mode.el @@ -319,7 +319,7 @@ The variable ruby-indent-level controls the amount of indentation. (setq nest (cdr nest)) (setq depth (1- depth))) (goto-char pnt)) - ((looking-at "def\\s *[^\n;]*\\(\\|$\\)") + ((looking-at "def\\s +[^(\n;]*") (if (or (bolp) (progn (forward-char -1) diff --git a/sample/test.rb b/sample/test.rb index 9f1a92a0eb..9bf6433b83 100644 --- a/sample/test.rb +++ b/sample/test.rb @@ -24,6 +24,24 @@ end # make sure conditional operators work +check "assignment" + +a=[]; a[0] ||= "bar"; +ok(a[0] == "bar") +h={}; h["foo"] ||= "bar"; +ok(h["foo"] == "bar") + +aa = 5 +aa ||= 25 +ok(aa == 5) +bb ||= 25 +ok(bb == 25) +cc &&=33 +ok(cc == nil) +cc = 5 +cc &&=44 +ok(cc == 44) + check "condition" $x = '0'; @@ -518,9 +536,6 @@ $good = true; for i in 4000..4096 n1 = 1 << i; if (n1**2-1) / (n1+1) != (n1-1) - p i - p (n1**2-1)/(n1+1) - p (n1-1) $good = false end end @@ -448,9 +448,6 @@ trap(arg) if (sig == SIGVTALRM) { ArgError("SIGVTALRM reserved for Thread; cannot set handler"); } - if (sig == SIGALRM) { - ArgError("SIGALRM reserved for Thread; cannot set handler"); - } #endif if (func == SIG_DFL) { switch (sig) { @@ -350,7 +350,7 @@ f_sprintf(argc, argv) s += 2; bignum = 2; } - sprintf(fbuf, "%%%c", *p); + sprintf(fbuf, "%l%%c", *p); sprintf(s, fbuf, v); if (v < 0) { char d = 0; @@ -469,6 +469,7 @@ f_sprintf(argc, argv) int v; if (c == 'D') c = 'd'; + if (c == 'O') c = 'o'; int_retry: switch (TYPE(val)) { case T_FIXNUM: @@ -542,7 +543,7 @@ f_sprintf(argc, argv) } } else { - int max = 11; + int max = 12; if ((flags & FPREC) && prec > max) max = prec; if ((flags & FWIDTH) && width > max) max = width; @@ -611,6 +612,9 @@ fmt_setup(buf, c, flags, width, prec) int flags, width, prec; { *buf++ = '%'; + if (strchr("doOXx", c)) { + *buf++ = 'l'; + } if (flags & FSHARP) *buf++ = '#'; if (flags & FPLUS) *buf++ = '+'; if (flags & FMINUS) *buf++ = '-'; @@ -1,2 +1,2 @@ -#define RUBY_VERSION "1.1b9_29" -#define VERSION_DATE "98/07/03" +#define RUBY_VERSION "1.1b9_30" +#define VERSION_DATE "98/07/09" |