summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>1998-07-09 08:40:46 +0000
committermatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>1998-07-09 08:40:46 +0000
commit3c1d5b89c33546028fce534546b8e356369ee231 (patch)
treefb658b101bf9a045c488663f2cbc6b3a178bbd3e
parent528b1f5237bc4e031228a27c00cdd679319f2472 (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--ChangeLog33
-rw-r--r--MANIFEST2
-rw-r--r--Makefile.in1
-rw-r--r--bignum.c36
-rw-r--r--eval.c99
-rw-r--r--ext/tcltklib/extconf.rb2
-rw-r--r--ext/tcltklib/tcltklib.c16
-rw-r--r--lib/cgi-lib.rb2
-rw-r--r--lib/complex.rb14
-rw-r--r--lib/matrix.rb230
-rw-r--r--lib/singleton.rb37
-rw-r--r--lib/telnet.rb200
-rw-r--r--lib/tk.rb472
-rw-r--r--lib/tkcanvas.rb33
-rw-r--r--lib/tkentry.rb6
-rw-r--r--lib/tkfont.rb556
-rw-r--r--lib/tktext.rb66
-rw-r--r--node.h8
-rw-r--r--numeric.c4
-rw-r--r--parse.y50
-rw-r--r--process.c15
-rw-r--r--regex.c2
-rw-r--r--ruby.h2
-rw-r--r--sample/ruby-mode.el2
-rw-r--r--sample/test.rb21
-rw-r--r--signal.c3
-rw-r--r--sprintf.c8
-rw-r--r--version.h4
28 files changed, 1722 insertions, 202 deletions
diff --git a/ChangeLog b/ChangeLog
index 53ec6067300..47718c1430d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,32 @@
+Thu Jul 9 17:38:23 1998 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * experimental release 1.1b9_30.
+
+Thu Jul 9 16:01:48 1998 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * 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 <matz@netlab.co.jp>
+
+ * bignum.c (big_pow): abandon power by bignum (too big).
+
+Tue Jul 7 13:58:43 1998 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * eval.c (rb_catch): add C level catch/throw feature.
+
+Mon Jul 6 15:18:09 1998 Yukihiro Matsumoto <matz@netlab.co.jp>
+
+ * parse.y (arg): proper return values for `||=' and `&&='.
+
Fri Jul 3 16:05:11 1998 Yukihiro Matsumoto <matz@netlab.co.jp>
* experimental release 1.1b9_29.
@@ -9,7 +38,7 @@ Fri Jul 3 11:20:46 1998 Yukihiro Matsumoto <matz@netlab.co.jp>
* 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 <matz@netlab.co.jp>
* struct.c (make_struct): name parameter can be nil for unnamed
structures.
-pMon Jun 15 16:30:10 1998 Yukihiro Matsumoto <matz@netlab.co.jp>
+Mon Jun 15 16:30:10 1998 Yukihiro Matsumoto <matz@netlab.co.jp>
* object.c (class_s_inherited): prohibiting to make subclass of
class Class.
diff --git a/MANIFEST b/MANIFEST
index 199e11af990..9a9507627eb 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -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 3195e89f2fa..6cf8af8c951 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@
diff --git a/bignum.c b/bignum.c
index ec16c991eae..94d7095aca7 100644
--- a/bignum.c
+++ b/bignum.c
@@ -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
diff --git a/eval.c b/eval.c
index a24ffc58725..2a174a1868d 100644
--- a/eval.c
+++ b/eval.c
@@ -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 201070c4dd7..31c858c203e 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 ada4c7a96e3..df242997e8e 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 6a846b20172..c6c1caa98bb 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 69437b01bb5..59caad6ebc1 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 631b6547b32..6639fe72ea2 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 00000000000..8167a01aa89
--- /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 44fda9e41ae..d9c72f65b27 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 <wakou@fsinet.or.jp>
#
# == 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
diff --git a/lib/tk.rb b/lib/tk.rb
index 287bda62af4..34f42ac3905 100644
--- a/lib/tk.rb
+++ b/lib/tk.rb
@@ -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 1d4c4c583aa..4ee0c3cd486 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 645fc997b10..b834c455c6c 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 00000000000..5e203595233
--- /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 74fec8c9539..7b5cea5c723 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)
diff --git a/node.h b/node.h
index 090a38d3513..40fd657f6a1 100644
--- a/node.h
+++ b/node.h
@@ -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);
diff --git a/numeric.c b/numeric.c
index 58c3eaab807..605fa6d0b97 100644
--- a/numeric.c
+++ b/numeric.c
@@ -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;
diff --git a/parse.y b/parse.y
index a7844d4386e..13b020406ea 100644
--- a/parse.y
+++ b/parse.y
@@ -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
diff --git a/process.c b/process.c
index 384e3f2aba8..faa5e9dd679 100644
--- a/process.c
+++ b/process.c
@@ -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
diff --git a/regex.c b/regex.c
index 17212becc16..77d6fd09e09 100644
--- a/regex.c
+++ b/regex.c
@@ -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
diff --git a/ruby.h b/ruby.h
index edc3de9b193..439bb1ae934 100644
--- a/ruby.h
+++ b/ruby.h
@@ -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 7b9549612c4..bfecb512144 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 9f1a92a0eb3..9bf6433b833 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
diff --git a/signal.c b/signal.c
index a8e5ae6ffb0..d262a57d72c 100644
--- a/signal.c
+++ b/signal.c
@@ -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) {
diff --git a/sprintf.c b/sprintf.c
index 5bc530377c9..5817f192247 100644
--- a/sprintf.c
+++ b/sprintf.c
@@ -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++ = '-';
diff --git a/version.h b/version.h
index a4eeb9bd9bc..d75ab4c314d 100644
--- a/version.h
+++ b/version.h
@@ -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"