From 3c1d5b89c33546028fce534546b8e356369ee231 Mon Sep 17 00:00:00 2001 From: matz Date: Thu, 9 Jul 1998 08:40:46 +0000 Subject: 1.1b9_30 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/v1_1r@263 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 33 ++- MANIFEST | 2 + Makefile.in | 1 + bignum.c | 36 ++-- eval.c | 99 +++++++-- ext/tcltklib/extconf.rb | 2 +- ext/tcltklib/tcltklib.c | 16 +- lib/cgi-lib.rb | 2 +- lib/complex.rb | 14 +- lib/matrix.rb | 230 +++++++++++++++++++- lib/singleton.rb | 37 ++++ lib/telnet.rb | 200 +++++++++++------ lib/tk.rb | 472 ++++++++++++++++++++++++++++++++++++++-- lib/tkcanvas.rb | 33 ++- lib/tkentry.rb | 6 + lib/tkfont.rb | 556 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/tktext.rb | 66 ++++-- node.h | 8 +- numeric.c | 4 +- parse.y | 50 ++--- process.c | 15 +- regex.c | 2 +- ruby.h | 2 + sample/ruby-mode.el | 2 +- sample/test.rb | 21 +- signal.c | 3 - sprintf.c | 8 +- version.h | 4 +- 28 files changed, 1722 insertions(+), 202 deletions(-) create mode 100644 lib/singleton.rb create mode 100644 lib/tkfont.rb diff --git a/ChangeLog b/ChangeLog index 53ec606730..47718c1430 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,32 @@ +Thu Jul 9 17:38:23 1998 Yukihiro Matsumoto + + * experimental release 1.1b9_30. + +Thu Jul 9 16:01:48 1998 Yukihiro Matsumoto + + * 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 + + * bignum.c (big_pow): abandon power by bignum (too big). + +Tue Jul 7 13:58:43 1998 Yukihiro Matsumoto + + * eval.c (rb_catch): add C level catch/throw feature. + +Mon Jul 6 15:18:09 1998 Yukihiro Matsumoto + + * parse.y (arg): proper return values for `||=' and `&&='. + Fri Jul 3 16:05:11 1998 Yukihiro Matsumoto * experimental release 1.1b9_29. @@ -9,7 +38,7 @@ Fri Jul 3 11:20:46 1998 Yukihiro Matsumoto * 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 * struct.c (make_struct): name parameter can be nil for unnamed structures. -pMon Jun 15 16:30:10 1998 Yukihiro Matsumoto +Mon Jun 15 16:30:10 1998 Yukihiro Matsumoto * object.c (class_s_inherited): prohibiting to make subclass of class Class. diff --git a/MANIFEST b/MANIFEST index 199e11af99..9a9507627e 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 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@ diff --git a/bignum.c b/bignum.c index ec16c991ea..94d7095aca 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 a24ffc5872..2a174a1868 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; } @@ -6530,6 +6571,25 @@ f_catch(dmy, tag) return val; } +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; @@ -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 # # == 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 287bda62af..34f42ac390 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(/>= 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<") 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")).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(/>@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<") 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(/><") 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(/> (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 a7844d4386..13b020406e 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 384e3f2aba..faa5e9dd67 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 17212becc1..77d6fd09e0 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 edc3de9b19..439bb1ae93 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 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 diff --git a/signal.c b/signal.c index a8e5ae6ffb..d262a57d72 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 5bc530377c..5817f19224 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 a4eeb9bd9b..d75ab4c314 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" -- cgit v1.2.3