diff options
author | Yukihiro Matsumoto <matz@ruby-lang.org> | 1996-12-24 15:20:58 +0900 |
---|---|---|
committer | Takashi Kokubun <takashikkbn@gmail.com> | 2019-08-17 22:09:32 +0900 |
commit | 554b989ba1623b9f6a0b76f00824c83a23fbcbc1 (patch) | |
tree | 71f06227fe259bebaa5ca4bf05cc398184bced68 /lib | |
parent | fca49a8a69a0f6bb4feae74c6cd0e93d7fac8b36 (diff) |
version 0.99.4-961224v0_99_4_961224
https://cache.ruby-lang.org/pub/ruby/1.0/ruby-0.99.4-961224.tar.gz
Tue Dec 24 15:20:58 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.4-961224
* configure.in: charがunsignedかどうかもチェック
* regex.c (SIGN_EXTEND_CHAR): __CHAR_UNSIGNED__にも対応
* pack.c (pack_unpack): 明示的にsigned charを指定.
Mon Dec 23 14:41:23 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* ruby.c (load_file): 標準入力からのスクリプトで一時ファイルを使わ
ないように
* object.c (f_integer): `0x', `0'などでbaseを解釈するように.
Fri Dec 20 01:44:39 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* Makefile.in (flock.o): flockに対応
Thu Dec 19 20:13:32 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.4-961219
Wed Dec 18 00:06:48 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* glob.c (glob_filename): strrchrがマクロの場合に対応
* configure.in: <sys/select.h>をチェック
* ext/kconv/kconv.c: 1.62ベースに
* ext/kconv/kconv.c: Kconvモジュール
* string.c (str_substr): lenが元の文字列より長い時に対応
* parse.y (iterator): 「$bar do .. end」などは許さないように
* parse.y (iterator): FID(foo!,foo?)をdo形式のイテレータにできる.
* missing/flock.c (flock): lockf()を使って代替
* file.c (file_flock): flockを実装
Tue Dec 17 12:13:38 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.4-961217
Fri Dec 13 02:05:03 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* configure.in: RUBYLIBのカレントを後回し(@mix/awk offline)
* dln.c: AIXに対応した?(@mix/awk offline)
* eval.c (thread_schedule): critical sectionでも明示的なコンテキス
トスイッチは起きないとまずい
* re.c (reg_search): matchに失敗した時に$~をnilに.
* re.c (reg_search): 毎回matchを生成するように
Thu Dec 12 17:03:30 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* numeric.c (flo_to_s): 2.0.to_s -> 2.0に
* eval.c (thread_save_context): $_, $~をthread毎に保存
* eval.c (thread_kill): main threadではexit(0)
* string.c (str_split_method): 間違った結果を返していた
Thu Dec 12 15:32:48 1996 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
* dir.c: CYGWIN32対応
* ext/socket/socket.c: CYGWIN32対応
* io.c: CYGWIN32対応
Thu Dec 12 14:43:51 1996 Jun Kuroda <j_kuro@pluto.ai.kutech.ac.jp>
* lib/tk.rb: wish4.2も探索候補に含める
* config.guess: JCC対応
Thu Dec 12 00:41:17 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.4-961212
* parse.y (parse_string): """..."""はやはり無くすことにした
* parse.y (parse_regx): %r|...|でterminatorを \ でエスケープできる
ように
* signal.c (posix_signal): sigactionを使うsignal
* configure.in: posix signal/bsd signalの検出
Wed Dec 11 17:47:35 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (thread_schedule): critical sectionではコンテキストスイッ
チが起きないように
* lib/thread.rb: SharedMutexクラス
* lib/jcode.rb: String#scanを使うように
Tue Dec 10 12:21:28 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.3-961210
* string.c (str_split_method): 正規表現に()を含む時にバグ
* lib/jcode.rb: ちょっとましになった
* string.c (tr_setup_table): 置換文字が短すぎる(2文字)のときのバグ
Mon Dec 9 11:38:04 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* string.c (str_scan): 文字列のマッチを行う.イテレータとしても動
作する
* regex.c (re_copy_registers): allocatedが初期化されていなかった
* re.c (match_to_s): $~の文字列化
* re.c (match_to_a): $~を配列化できるように
* re.c (match_getter): レジスタが初期化されていなかった
Thu Dec 5 11:06:10 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* string.c (str_split_method): マッチしなかった括弧は空文字列を
pushするべきではない
* string.c (str_succ): アルファベットを含まない文字に対応
Wed Dec 4 10:48:09 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.3-961204
* io.c (io_binmode): DJGPPでのbinmode対応
* sprintf.c (f_sprintf): intの範囲の数値は直接sprintfで変換する
* sprintf.c (f_sprintf): "%02s"に頼らない
* re.c (reg_search): indexでSEGV
Tue Dec 3 10:09:36 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.3-961203
* ext/extmk.rb.in (install): INSTALL_DATAからINSTALLに変更
* dln.c: hpux対応
* string.c (str_aset_method): 負の値を含む範囲でも例外を起こさない
* array.c (ary_replace): 負の値を含む範囲でも例外を起こさない
* array.c (beg_len): beg==endの時,長さ0に
Mon Dec 2 14:07:12 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* configure.in: HP shl対応
* string.c (str_upto): beg > endの時無限ループに落ちるのを止めた
* range.c (range_each): String#uptoが再定義された場合に対応
* string.c (str_split_method): "ABC".split(/(B)/)が誤動作
Sat Nov 30 01:43:52 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (rb_eval): undefでSEGV
Fri Nov 29 12:17:59 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* sample/ruby-mode.el (ruby-parse-region): %Q#..#などに対応.しか
し,区切り文字が演算子で行末にある場合には対応できなかった.
* re.c (reg_raise): 例外でもスラッシュをエスケープ
* re.c (reg_inspect): スラッシュをエスケープ
* parse.y (parse_string): `%[QqXxRr](.)..\1'なる文字列形式(テスト
採用)
* parse.y (parse_qstring): '''...'''の形式
* ext/dbm/dbm.c (Init_dbm): 述語key?,value?の追加
* ext/dbm/dbm.c (Init_dbm): includes->include?
* hash.c (Init_Hash): 述語key?,value?,include?の追加
* eval.c (rb_eval): else節が実行されない(うーん)
* string.c (str_sub_iter_s): イテレータブロック内でマッチが行われ
ると位置がずれる(時に無限ループに落ちる)
* string.c (str_resize): lenが0の時sizeの調整が行われなかった
Thu Nov 28 00:59:54 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.3-961128
* parse.y (parse_string): 3-quote styleの文字列(例:"""abc"d"e""")
* configure.in (EXTSTATIC): extを静的にリンクする時にはrubyはdllを
使うように
* io.c (Init_IO): getsの引数が間違っていた
* string.c (str_each_line): RSを明示的に指定できるように
Wed Nov 27 12:37:46 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.3-961127
* eval.c (rb_eval): iver defined? でselfを指定するのを忘れた
* io.c: gets等でRSを明示的に指定できるように
* ext/extmk.rb.in (install): static linkに失敗
Tue Nov 26 10:33:04 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.3-961126
* string.c (str_sub_s): 置換後の文字列長さが間違っていた
Mon Nov 25 09:11:22 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* numeric.c (fix_rshift): 32以上の右シフトで0を返すように(Cの
rshiftは(x>>(y%32))を返していた).
* string.c (str_gsub): 置換が行われない場合があった
* string.c (str_resize): 本当に必要な時だけrealloc
Thu Nov 21 04:13:21 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* configure.in (EXTSTATIC): --with-static-linked-extで全てのモジュー
ルを静的リンクするように
* pack.c (pack_unpack): 行末の改行がない時にもチェックサムをスキッ
プするように
Wed Nov 20 96 21:42:51 1996 Yasuo OHBA <jammy@shljapan.co.jp>
* configure.in: freebsd対応
Wed Nov 20 10:24:24 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* ext/extmk.rb.in (install): 通常リンク用のLDFLAGSとダイナミックリ
ンク用のDLDFALGSを分離
* ext/extmk.rb.in (install): コンパイルの成功したものを静的リンク
のリストに追加する
* eval.c (f_missing): オブジェクトの文字列表現が長すぎる時バッファ
を書き潰していた
* process.c (proc_exec_v): forkした後例外を発生させてはいけない
Tue Nov 19 13:28:15 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.3-961119
* eval.c (mod_method_defined): Module#method_defined? の追加
* parse.y (call_args): 引数が唯一のコマンドコールである時のバグ(戻
り値が展開されてしまう)
Mon Nov 18 13:28:18 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* string.c (str_sub): 失敗した時にnilを返していた
* string.c (str_split_method): 検索開始位置が移動してなかった
* ext/socket/socket.c (sock_s_getservbyaname): まだ間違っていた
* version 0.99.3-961118
* string.c (str_sub_s): 元の文字列を置換するのを止めた
* pack.c (encodes): 領域外をアクセスしていた
Fri Nov 15 17:10:35 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* bignum.c (big_divmod): Bignumが引数の場合の対応忘れ
* sample/ruby-mode.el (ruby-expr-beg): word?形式への対応が不完全
Wed Nov 13 15:42:40 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* string.c (str_tr_s_bang): tr_sでtrが行われていなかった
* eval.c (rb_eval): autoloadクラスのチェック
* string.c (f_sub): subがsub!と同じ動作になっていた
* eval.c (thread_sleep): stopとsleepの分離
Mon Nov 11 13:53:19 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.3-961111
* numeric.c (fix_step): to, stepが整数以外の場合に対応
* eval.c (rb_call): dynamic varがdynamic scopingになっていた(これ
はまずい)
* string.c (str_chop_bang): 長さ0の文字列のchopで,領域外のアクセ
スが発生していた.
* parse.y (yyerror): 割り当てた領域外をアクセスしていた
Fri Nov 8 11:54:46 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (thread_yield): scopeをheapにコピー
Thu Nov 7 09:56:53 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* numeric.c (num_coerce): とりあえず両辺をFloatに変換することに
Wed Nov 6 10:45:13 1996 Yasuo OHBA <jammy@shljapan.co.jp>
* lib/parsearg.rb: 第2引数を変更.
Tue Nov 5 14:21:09 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.3-961105
Sat Nov 2 01:11:40 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* bignum.c (big_pow): typo (dy -> dx)
* bignum.c (big_divmod): 知らない型はfloatに変換してみる
* numeric.c (fix_lshift): 境界条件のバグ(負になっていた)
* bignum.c (big_pow): 無駄なfloatへの変換をなくした
* math.c (math_atan2): typo(x -> y)
Fri Nov 1 15:30:59 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* ext/socket/socket.c (sock_gethostname): gethostnameがない時には
unameを使ってホスト名を得る
* ext/etc/etc.c (etc_getlogin): getloginがNULLを返しても環境変数を
調べるように
* object.c (krn_clone): オブジェクトのフラグもコピー
* hash.c (rb_cmp): ハッシュの比較を`=='でなく`eql?'に変更
* math.c (Need_Float): Float()を使って変換する
* compar.c (cmp_gt): 以前の右辺を返す仕様の名残が残っていた
Thu Oct 31 12:55:51 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.3-961031
* numeric.c (Init_Numeric): typo
* eval.c (error_print): 長すぎるtrace backを途中省略する
* regex.c (re_compile_pattern): 全角のrangeに対応
Wed Oct 30 03:03:18 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.3-961030
* io.c (f_ungetc): 関数を追加
* eval.c (dyna_var_asgn): return値忘れ
Tue Oct 29 10:05:28 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* string.c (f_split): 関数splitを追加
* eval.c (rb_call): ネストした外側のクラス/モジュールの定数を参照
できるように
Mon Oct 28 09:51:03 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* string.c (str_sub): offsetが文字の末尾にある時のチェック
* regex.c (re_match): 割り当てるレジスタの数が1多かった
* io.c (io_gets): $/ = ""の動作をperlに合わせる(awkとはちょっと違
うらしい)
* io.c (io_gets): $/ = nilの時少し高速化
* string.c (str_split_method): 括弧がnullにマッチした時にも無視し
ないように
* string.c (str_split_method): 括弧にマッチした分はlimitの数に含め
ないように.
* numeric.c (num_coerce_bin): coerceの定義を変更,2要素の配列
[x,y]を返すように
* sample/ruby-mode.el (ruby-calculate-indent): "do |aa|"の対応を改
善した.
Sat Oct 26 01:43:51 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* ext/marshal/marshal.c (w_object): ビルトインクラスのサブクラスを
正しく復旧できるように
* ext/marshal/marshal.c (w_object): ユーザ定義dumpの優先
* numeric.c (flo_coerce): Float()を使って定義
* numeric.c (Init_Numeric): Numericのnewのundefはまずい
* ext/marshal/marshal.c (w_symbol): シンボルの内容(文字列)は一度し
かファイルに書き出さない.
* sample/ruby-mode.el (ruby-parse-region): if/while修飾子に対応し
なくなっていた
* bignum.c (Init_Bignum): Bignum.newを除く
* eval.c (rb_eval): 引数評価後にファイル名と行番号を再設定
* numeric.c (flo_div): typo
* sample/ruby-mode.el (ruby-parse-region): def /, def `に対応
Fri Oct 25 09:26:29 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* sample/ruby-mode.el (ruby-calculate-indent): "do |aa|"に対応
* array.c (ary_aset): indexがfixnumの場合ちょっと高速化
* eval.c (thread_fd_writable): 書き込み前のselectチェック
* array.c (ary_assoc): 無限ループに落ちた
* eval.c (thread_wait_for): selectがエラー終了した時,linux以外で
の動作が正しくなかった.
Thu Oct 24 08:26:48 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (backtrace): `$@'を文字列から配列に変更した.
* eval.c (eval): eval中の例外発生位置を保存する
* bignum.c (bigsub): オペランドの大小比較の失敗
* re.c (reg_search): 直接参照がない時にも`$~'がセットされるように
Wed Oct 23 10:40:10 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.2-961023
* ext/marshal/marshal.c (r_bytes): mallocをやめ,allocaを使う
* sample/ruby-mode.el (ruby-calculate-indent): 括弧の対応を変更.
()内ではインデントをレベルを合わせるように
Tue Oct 22 12:59:11 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* hash.c (hash_s_new): sizeを指定できるように
* ext/marshal/marshal.c (w_object): dumpする深さ制限を指定できるよ
うに
* array.c (ary_s_new): sizeを指定した時の初期化忘れ
* object.c (f_float): big2dblの宣言忘れ.
* bignum.c (bigsub): 大きさの近いBignum同士の演算で結果が負になる
場合に間違いがあった.
* array.c (ary_aset): 置換先と置換元が同じ長さの時内容を
shift(memmove)しないように.
* ext/marshal/marshal.c (marshal_dump): ファイルフォーマットにバー
ジョンを埋め込むように
* ext/marshal/marshal.c (tmpnam): linux-aout-dln用に定義
Mon Oct 21 08:40:20 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* ext/socket/socket.c (sock_s_gethostbyname): hostent構造体の情報
を返す
(sock_s_gethostbyaddr): IPアドレスからhostent構造体を得る
(sock_s_getservbyaname): getservbyname(3)
Fri Oct 18 10:37:36 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* sample/ruby-mode.el (ruby-indent-to): 移動先カラムが負になるバグ
* eval.c (compile): evalで元ソースの行番号でエラーを表示する
Thu Oct 17 09:52:28 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (eval): evalで文法エラーがあった時にSEGV
* lib/safe.rb: Restricted.evalの中だけ制限を加える.
* eval.c (error_print): バックトレースの出力.callerで例外発生位置
を調整した時に問題が出る(そんなことをしなければ良いのだが…)
* eval.c (make_backtrace): バックトレースの生成
Wed Oct 16 12:56:22 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* ruby-man-0.99.2-jp/index.html: 日本語版ドキュメントの完成(長かった…)
* re.c (reg_regcomp): $=がnilの時の処理
* string.c (f_chop): $_に対するchop
Tue Oct 15 11:04:23 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.2-961015
Mon Oct 14 18:22:38 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (thread_schedule): BOW対応.selectが-1を返した時にバグ(実
はdo .. whileがcontinueで先頭にジャンプすると思い込んでいた.条
件の直前だったのね ^^);;;;;
* sample/ruby-mode.el (ruby-mode-syntax-table): ?のsyntaxが"/"では
まずいらしい
* hash.c (rb_hash): name conflict
Fri Oct 11 00:23:05 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.2-961011
* ext/marshal/marshal.c (w_object): 結局動いていなかった循環オブジェ
クト対応を外した.
* hash.c (rb_hash): Fixnumと文字列の高速化
* ext/marshal/marshal.c (w_object): 無駄なデータの削除(フォーマッ
トの非互換性)
* io.c (io_readline): 戻り値の不備
* ext/marshal/marshal.c (marshal_dumps): MSDOS対応
* ruby.c (load_file): MSDOS対応
Wed Oct 9 17:46:27 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* ext/extmk.rb.in (install): 無駄なコピーを避ける
* string.c (str_sub_method): マッチがなかった時のString#subの値が
違っていた.
* eval.c (obj_extend): extendした時にobject_extendedを呼ぶように
Tue Oct 8 00:55:38 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (thread_alloc): 割当の平均化
* eval.c (thread_schedule): joinのバグを修正
* eval.c (thread_wait_for): selectへの割込みなどに対応
* eval.c (thread_select): linuxのselectの挙動に対応(timeoutが変化
する)
Mon Oct 7 09:47:19 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.2-961007
* eval.c (PUSH_BLOCK): the_classの保存を忘れていた.
* ext/dbm/dbm.c (fdbm_store): sizeの保存する場所が間違っていた
* ext/socket/socket.c (s_accept): thread対応していなかった
Sat Oct 5 01:32:27 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* io.c (io_readchar): EOFで例外を発生させる
Fri Oct 4 11:59:54 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* ext/marshal/marshal.c (w_object): HashとObjectの復旧に必要なハッ
シュテーブルが渡されていなかった.
* variable.c (rb_path2class): ユーザ定義クラスの復旧に失敗していた
* variable.c (rb_path2class): クラスが存在しない時のエラーをFatal
からNameErrorへ.
* range.c (range_s_new): first,lastが両方Numericの時エラーになって
いた.
* range.c: start->first, end->last
Wed Oct 2 02:02:46 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* file.c: DJGPPでchmod,chownを使えるように(ってDOSにchownがあるのか?)
* class.c (rb_singleton_class): ビルトインクラスもextendしたり特異
メソッドを追加したりできるように
* variable.c (rb_set_class_path): ユーザ定義のトップレベルクラスに
pathを設定しない
* eval.c (eval): 例外がRuntimeErrorに化けていた
* eval.c (eval): eval中の例外の表現の改善
* eval.c (eval): eval_with_bindingとの一本化
* eval.c (rb_eval): クラス/モジュール定義の中から定義中のクラス/モ
ジュールが参照できるように
Tue Oct 1 01:40:09 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.2-961001
* parse.y: cur_crefが2度宣言されていた
* signal.c (trap): SIGSEGV,SIGBUSのない機種に対応
* io.c (Init_IO): 引数タイプの指定間違い
Mon Sep 30 15:28:00 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.2-960930
* config.guess,config.sub: $host_osが正しく設定されない
* eval.c (rb_eval): yieldで正しくないselfが設定されていた
* eval.c (ruby_run): toplevelの例外処理のバグ
Mon Sep 30 09:13:26 1996 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
* djgpp対応
Sat Sep 28 02:45:10 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.2-960928
* sample/ruby-mode.el (ruby-beginning-of-block): ブロックの先頭に
移動(正しくインデントしていないと動作しない)
(ruby-end-of-block): 同上
* eval.c (class_s_new): Class#newがイテレータとして呼ばれた時は
initializeもイテレータとして呼ばれるように
* signal.c (sigsegv): SEGVでbacktraceを表示するように
Fri Sep 27 09:51:07 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.2-960927
* eval.c (error_print): 引数のないraiseでメッセージが正しく表示さ
れるように.
* eval.c (rb_longjmp): mesgがnilの時RuntimeErrorを生成する.
* eval.c (f_raise): 引数がない時に対応
* eval.c (thread_mark): stack上にないデータのアドレス変換を行って
いた.
* eval.c (Init_Thread): 割込みの間隔が1秒と長すぎた.
Thu Sep 26 16:02:45 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (thread_schedule): 一度ペンディングになるとフラグがクリア
されていなかった.
* process.c (rb_proc_exec): system/execの引数が空文字列であった場
合,例外を発生すべきだった.
* config.sub/config.guess: 新しいものに置き換え
Thu Sep 26 15:41:35 1996 WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
* io.c (next_argv): -i.bakをBOWとDOSに対応.
Thu Sep 26 01:31:43 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* io.c (io_sysread): EOFで例外
* io.c (f_readline): EOFで例外を発生するように.getsは互換性のため
nilを返すままにする
* eval.c (proc_call): lambdaからのreturnでIN_BLOCKフラグが立ったま
まだった
* eval.c (PUSH_BLOCK2): threadに対応するためBlockを一度stackにコピー
Wed Sep 25 11:54:11 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* parse.y (method_call): Const::method()形式を使えるようにしてみた.
引数括弧は省略できない.
* sample/test.rb: Process.killの存在を確かめてからテストを行う
* eval.c (eval_with_binding): 第2引数としてbinding(またはlambda)を
与えるとその環境でevalを実行するようにした
* eval.c (f_binding): 現在のbindingを返す関数
* eval.c: block構造体にthe_classを保存するメンバを追加
* process.c (Init_process): kill,wait,waitpidをProcessに移動
Tue Sep 24 02:44:43 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* sample/ruby-mode.el: いろいろ問題が多いので以前の高速化は破棄.
別のアプローチを使った.
* lib/tk.rb (Tk.pack): 複数のウィンドウを受け付けるpack
Sat Sep 21 11:08:09 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* parse.y (exprs): 空文も受け付けるように文法を変更.今までは改行
の連続だけが許されていた.
Fri Sep 20 11:39:18 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* Failの大半を名前つき例外に変更.
* re.c (Init_Regexp): 名前つき例外を導入.
* eval.c (f_missing): Objectはinspectしない.
* object.c (inspect_i): Object#inspectでloopに対応.
* regex.c (re_search): /^$/が""にマッチしなかった.
Thu Sep 19 19:25:12 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* regex.c (re_search): /^$/が非空行にマッチしていた.
Tue Sep 17 10:28:11 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.2-960917
Mon Sep 16 10:47:56 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* sample/ruby-mode.el (ruby-calculate-indent): 演算子継続の場合の
文字列の判定のバグ
* sample/ruby-mode.el (ruby-calculate-indent): elseなどの次の行の
インデント計算を正しく.
Sat Sep 14 08:37:19 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.2-960914
Fri Sep 13 08:06:03 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* ext/socket/socket.c (tcpaddr): port番号にntohsをつけ忘れ
* dln.c (link_undef): テーブルの種類が間違っていた.
* bignum.c (bigadd): 引き算が発生する時に計算違いが起きていた.
* parse.y (iter_do_block): do..endでもdynamic variableを.
* bignum.c (big_pow): より正確な計算を(整数同士ではfloatに変換しな
い).
Thu Sep 12 13:11:55 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* variable.c (rb_set_class_path): Stringクラスが初期化される前に
Stringを作っていた.組込みクラスにはpathはいらない
* parse.y (yylex): 0.1が0になっていた
* parse.y (yylex): 行番号の不整合
* gc.c (oblist_live_obj): 今「生きている」全部のオブジェクトを返す
イテレータ.そのクラス(またはサブクラス)の全部のインスタンスを返
すeach_object_ofも定義した.
* class.c (rb_define_class_id): 無駄なクラスを割り当てていた.結果
として未初期化のクラスオブジェクトが存在していた.
Wed Sep 11 00:56:23 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* parse.y (yylex): octalの定数の検出をより正確に(090はエラーとか).
* bignum.c (big_minus): yがxより大きい場合にエラー.
* parse.y (yylex): エラー行番号の表示をより正確に
* sample/ruby-mode.el (ruby-expr-beg): 変数名が1文字の時誤動作して
いた.
* sample/ruby-mode.el (ruby-calculate-indent): ?/でループに落ちい
たバグを修正.
* enum.c (enum_min,enum_max): sortのようにイテレータとしても動作す
るように.
* enum.c (enum_find_all): typo
Tue Sep 10 12:07:12 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* node.h (nd_line): NODEのlineをflagsに押し込めてオブジェクトサイ
ズを小さくした.制限:32bit intのマシンの場合,ファイルの行数が
32767を越えると正常に表示されない.
* st.c: hashとcompareの関数メンバを構造体にパック,クラス的な使い
方を行う.1 tableあたり4 byteの節約.
Mon Sep 9 16:35:54 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* file.c (file_truncate): 提供されない時には特別な例外を発生するよ
うに.
* eval.c (Init_Proc): 不適切な位置のlocal-jumpを例外に.
Sat Sep 7 17:06:15 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (proc_call): まだスコープがスタック上にある時には局所脱出
を有効にする.これで,procを生成してcallすることは,スコープを脱
出しない限り,yieldと同じ意味を持つことになる.
Fri Sep 6 13:30:59 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* sample/ruby-mode.el (ruby-indent-to): インデントが変わらない時に
はバッファを変更しない.
(ruby-calculate-indent): まず文字列の内部か判断してから,前の行
からパーズを行う.defunが大きくなった時の高速化.
(ruby-in-string-p): 文字列の内部かどうかを判断する関数(以前の
parseから分離)
(ruby-parse-region): 文字列に対する処理をはずす.
(ruby-beginning-of-block): ブロックの先頭に
(ruby-end-of-block): ブロックの末尾に(遅い…)
Thu Sep 5 14:23:07 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* file.c (file_s_split): [dirname,basename]にsplitする.
* eval.c (rb_eval): evalの中でも定数の値が正しくなるように.これで
定数に関しては静的なスコープが保証されるようになった.
* st.c (rehash): ハッシュ拡大の系数を2から1.79に.割算がより良い値
を返すように.
Thu Sep 5 00:32:07 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (class_superclass) クラスのスーパークラスを返すメソッド.
Wed Sep 4 16:54:56 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* random.c (f_rand): Bignumやlongの範囲を越えるFloatに対する乱数も
発生できるように.
* struct.c (struct_alloc): Fatalではなく例外を発生させるように(通
常の使用で発生しうる).
* struct.c (struct_s_members): Structの特異メソッドではなく,生成
されたStructクラスの特異メソッドにした.
* st.c (st_init_table): ruby専用にパラメタを固定にした(サイ
ズが減った)
Mon Sep 2 11:37:59 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* array.c (ary_shift): capaがあまりにも大きい時には領域をREALLOC
(ary_pop): 同上
* string.c (str_inspect): multibyte character 対応にミス.
(str_inspect): unsigned charにしないと符号展開されてしまう
* parse.y (primary): `::'をprimaryに移動 Foo::Bar.Bazがエラーにな
らないように.
* parse.y (primary): オペレータ形式の特異メソッドが定義できない
* random.c (f_rand): maxが0の時に対応
* io.c (io_printf): 関数を定義していたがインタプリタに登録していな
かった.
* file.c (file_s_basename): 第2引数が無い時にエラー.
Thu Aug 29 10:49:40 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* parse.y (expr): イテレータの新形式に「method do .. end」形式を採
用した.もちろん昔の形式も有効.
* sample/ruby-mode.el (ruby-calculate-indent): endの数の方が多い場
合にもエラーを起こさないように.
Wed Aug 28 09:41:36 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* numeric.c (upto,downto,step,times): 対象がfixnumの範囲を越えても
動作するように.
Mon Aug 26 10:04:37 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* missing/setenv.c (envix): typo(missing `== 0' for memcmp)
* dir.c (dir_foreach): foreach(dir open -> read loop -> closeまで)
* io.c (io_foreach): foreach(file open -> read loop -> closeまで)
* Fatalのうち捕捉可能ないくつかを例外に.
Sat Aug 24 23:56:37 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* bignum.c (bigdivmod): FIX2INT -> INT2FIX 大間違い
Fri Aug 23 18:13:03 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* regex.c (re_free_registers): allocateしていない時には当然 free
してはいけない.
Thu Aug 22 01:20:35 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (thread_create): 外側から強制終了させられたthreadは
cleanupする必要が無い.
Wed Aug 21 09:57:28 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (thread_create): threadを終了させた大域脱出の情報を
main_threadに渡すように.
* parse.y (call_args): 最終引数に括弧を省略したメソッド呼出しを置
けるように(例: print foo bar, baz == print(foo(bar,baz)))
Tue Aug 20 13:37:16 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (masign): 多重代入とrest引数の動作を合わせて空の配列を代
入するように.
* parse.y (arg): defined?の強度をもうちょっと強く
* eval.c (error_print): -wで例外名も表示するように
* eval.c (rb_eval): 新構文に対応
(handle_rescue): 捕捉する例外を kind_of? で同定
* parse.y (primary): rescueの構文を変更(同定引数の追加,複数rescue)
* Fail()のかなりを適当な例外を使うように
* eval.c (thread_interrupt): Interrupt(今はnon-local jump)は
main-threadに送られるように.
* eval.c (rb_longjmp): $! の内容を文字列から例外クラスに変更
(rb_raise): rb_fail から名称変更
(rb_interrupt): 例外化
(rb_exit): 例外化
* error.c (Init_Exception): 例外クラスの新設(文字列のサブクラス)
Mon Aug 19 19:40:52 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* signal.c (trap): 古いハンドラを返すように.
Wed Aug 14 00:07:18 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (rb_trap_eval): ハンドラのためにthreadをforkすることを止
めた.
* eval.c (thread_mark): thread毎の $!, $@ をマークし忘れ
* ext/dbm/dbm.c (fdbm_delete): イテレータとして呼ばれた場合,要素
が無ければブロックを評価する.
* hash.c (hash_delete): イテレータとして呼ばれた場合,要素が無けれ
ばブロックを評価する.
* array.c (ary_delete): イテレータとして呼ばれた場合,要素が無けれ
ばブロックを評価する.
* eval.c (rb_interrupt): SIGINTのデフォルトをexitから特別な大域脱
出に.やはり割り込まれた位置の表示が無いのは寂しいので.
Tue Aug 13 01:34:00 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (rb_exit): sub-thread内でのexitもstatusを保存するように
(thread_create): 自thread内のexitに対応
* signal.c (sighandle): SIGINTのデフォルトハンドラはexitするように
(以前は例外を発生していた).
* 例外の一部をFatalに.
* string.c (str_aset): 文字列の置換の対象が部分文字列でなかった時,
例外を発生させないように
* eval.c (proc_call): Procの中からbreak/nextは通し,他のものは通さ
ないように
Mon Aug 12 14:15:09 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* object.c (krn_type): 文字列を返す
* eval.c (thread_create): sub-thread内でのexitに対応
* numeric.c (fix_type): 文字列を返す
* io.c (f_p): デバッグ用データ表示メソッド
* eval.c (f_missing): nil/TRUE/FALSEを特別扱い
* string.c (str_inspect): 長い文字列を短縮表示.inspectの働きを
human readable stringの生成に統一(re-generatable string は正式に
無くなった).
Sat Aug 10 16:54:21 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* object.c (Init_Object): kernel/nil/false/trueのクラス名を変更(小
文字に),rubyスクリプトからアクセスできないように.
* eval.c (rb_eval): CONSTANTのアクセス先を単純化.crefを使わない.
* eval.c (f_eval): 特異メソッド内でも定数の値が正しくなるように
Fri Aug 9 12:23:17 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* array.c (ary_concat): append -> concat Stringに合わせた
* parse.y (yylex): `$;'が使えなかった.
* array.c (ary_push_method): 複数引数を受け付けるように.
(ary_unshift): 複数引数を受け付けるように.
* io.c (io_popen): IO.popenでcommand pipeが開けるように.
* object.c (Init_Object): KernelとNilをruby scriptからアクセスでき
ないように.
Thu Aug 8 01:21:47 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* object.c (f_integer): 整数への変換関数
(f_float): 実数への変換関数
(f_string): 文字列への変換関数
(f_array): 配列への変換関数
* bignum.c (big_to_i): FIXNUMの範囲でない時はBignumのまま返すよう
に変更.
Wed Aug 7 09:28:38 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99.1-960807
* parse.y (mlhs): 「*foo = 1,2,3」タイプの多重代入も可能に.
* object.c (Init_Object): クラスTrue/Falseをruby scriptからアクセ
スできないように.
* object.c (nil_inspect): inspect表現は"nil"に
* io.c (io_print): nilのprintをnilに.
* object.c (nil_to_s): nilの文字列表現を""に.
Tue Aug 6 01:12:32 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* dir.c (dir_s_open): file descripterが足りない時にはgcしてからも
う一度openしてみる.
* io.c (rb_fopen): すべてのfopen()についてfile descripterが足りな
い時にはgcしてからもう一度openしてみる.
* ext/socket/socket.c (Init_socket): 定数の追加.
* sample/ruby-mode.el (ruby-indent-to): インデント後のカーソル位置
の調整を正しく.
* gc.c (gc): 割込みチェックを行わない(Cコードの中で安心して
malloc()が使えなくなるので).
* st.c (call_hash_func): signalとthreadによる割込みに対応.
* sig.h (DEFER_INTS): 割込み禁止区間の指定
* eval.c (f_require): threadによるrequireの競合に対応(最初の
requireが終了するまで他のthreadは待つ).
* bignum.c (str2inum): 0x80000000の値が負になっていた
* sprintf.c (f_sprintf): 文字列末尾,行末の単独の`%'に対応
* bignum.c (big_cmp): 比較の結果が逆になる時があった.
Mon Aug 5 10:58:13 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* process.c (proc_exec_v): 例外のメッセージを分かりやすく.
* ext/dbm/dbm.c (fdbm_store): nilを格納すると要素の削除になる
* ext/dbm/dbm.c: サイズをキャッシュ.
Sat Aug 3 01:52:52 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (rb_fail): `fail'が引数無しで呼ばれた時だけ以前の`$@'を保
存するように.
* eval.c (f_fail): frameの調整
Fri Aug 2 11:26:21 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* ext/socket/socket.c (bsock_setopt): valとしてTRUE/FALSE/Fixnumも
受け付けるように.
* ext/socket/socket.c (Init_socket): SO_REUSEADDR等の定数の追加
* ext/md5/md5init.c: md5モジュール(初の複数ファイルからなるモジュー
ルでもある)
* ruby.h (Make_Data_Struct): Data: objectのinstance変数に格納 ->
Data型のObjectに(Dir,Time,Proc,Thread,DBM)
Thu Aug 1 11:38:44 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* ext/dbm/dbm.c (fdbm_store): valueが文字で無い時に対応
Wed Jul 31 10:53:42 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* ext/socket/socket.c (open_inet): htonsが必要であった
(tcpaddr): ntohlで変換した
* process.c (rb_proc_exec): execvp -> execv
Tue Jul 30 17:48:33 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c: `$?'をthread localに
* Makefile.in (install): install時にstripを行う
* configure.in: install時のstripの検出
* configure.in: NEXTSTEP対応
* version 0.99.1-960730
Tue Jul 30 16:40:35 1996 SHIROYAMA Takayuki <psi@fortune.nest.or.jp>
* dln.c (dln_load): NeXT dln(mach-o)対応.configureは未対応
Tue Jul 30 09:46:51 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* process.c (f_system): 複数引数もとれるように
* process.c (f_exec): 複数引数もとれるように
* array.c (ary_append): 配列(またはEnum)の要素を破壊的に追加
* array.c (ary_plus): Enumはその要素を追加
* file.c (file_s_open): File.openを追加
* struct.c (struct_new): FIX2INTを忘れていた
* file.c (Init_File): exists? -> exist?
* object.c (obj_is_kind_of): is_kind_of? -> kind_of?, is_a?
* object.c (obj_is_instance_of): is_instance_of? -> instance_of?
Mon Jul 29 16:40:02 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* parse.y (parse_regx): 式展開を行った場合,casefoldの設定ができて
いなかった.
* object.c (true_type): TRUE/FALSEにtypeを実装.
* parse.y (read_escape): 3文字以内のoctalに対応(\0とか)
Fri Jul 26 00:31:45 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* array.c (ary_reverse_bang): in-placeで配列を反転させる
(ary_sort_bang): in-placeでsortする
(ary_sort): sortした配列を返すように
(ary_delete_at): 指定した位置の要素を削除する
* eval.c (rb_call): stack深さチェックを毎回は行わないように
* error.c (Warning): 実行中のwarningが表示されていなかった
* eval.c (compile): 例外発生を分離.
* eval.c (f_eval): 変数rb_in_evalを正しく管理するように
* ext/dbm/dbm.c (fdbm_store): 格納するkeyを文字列に変換
* eval.c (rb_call): 無限再帰のチェックを大域脱出を行うC methodにも
対応させた.threadのstack深さチェックルーチンを流用.
* parse.y (yylex): 第1引数のunary -/+の判定が間違っていた.
* parse.y (yylex): unary +で数字を余計に読んでいた(ex. +5 -> 55)
Thu Jul 25 12:15:04 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* parse.y (yylex): 曖昧でない引数に対して警告を出していた.
* eval.c (iterator_p): 引数で呼んでも正しい結果を返すように.
* parse.y: break/next/redo/retryのメソッド化.
* sample/ruby-mode.el (ruby-calculate-indent): nestのチェックミス
* sample/ruby-mode.el (ruby-parse-region): 予約語のチェックを強化
* parse.y (primary): unless/untilの復活
Tue Jul 23 18:50:10 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* array.c (Array#empty?), Hash.c (Hash#empty?), ext/dbm/dbm.c (DBM#empty?):
空の判定述語
* eval.c (f_unless): ifの逆をするイテレータ
* eval.c (f_until): whileの逆をするイテレータ
* parse.y: notの優先順位をand/orより高く
* parse.y (expr): `!'を引数括弧を省略したcallでも有効に
Mon Jul 22 10:15:38 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99-960722
* array.c (ary_print_on): OFSのNILチェックが不完全
* ruby.c (load_file): 標準入力からのスクリプトが空の時に対応.
* ruby.c (proc_options): -wでは引数無しの時には標準入力からスクリ
プトをとる(-vではたんに終了する).
* array.c (ary_compact): nilの要素を取り除くメソッド
* array.c (ary_nitems): nilでない要素を数えるメソッド
Sun Jul 20 00:51:53 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* ruby.c (proc_options): -w optionを追加
* parse.y: {}が閉じていない時には展開しない文字列を
Fri Jul 19 16:16:05 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99-960719
* lib/find.rb: 石塚版(pruneの拡張付き)
* file.c (test_l): lstatで調べないとね.
* eval.c (f_throw): 第2引数を省略可能に.
* parse.y (str_extend): {}のネストに対応
Thu Jul 18 18:25:46 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99-960718
* parse.y (str_extend): 文字列中の式展開に \" ' ` / を含む事ができ
るように.
Tue Jul 16 15:55:31 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* sample/ruby-mode.el (ruby-parse-region): 正規表現内のエスケープ
に対応
* version 0.99-960716
Fri Jul 12 10:06:19 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* io.c (f_select): 引数のclose check.
* ruby.c (load_file): #!行の引数チェックを第1引数に限定(実をいうと
DOS改行対策)
Wed Jul 10 17:18:35 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99-960710
* time.c (time_s_timegm/time_s_timelocal): 時間を生成するメソッド
Mon Jun 17 15:59:20 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99-960617
* parse.y (yyerror): エラー表示の簡略化.
Wed Jun 12 14:11:01 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* signal.c (rb_trap_exit): trap 0はthreadを生成せずに処理する.
Fri Jun 7 10:17:01 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* array.c/hash.c (indexes): 配列1引数のパターンを無くした.配列の
場合は`*ary'を使ってもらおう.
* eval.c (thread_wait_threads): main_threadが終了する前に他の
threadを待つ(強制的には終了させない).
(ruby_run): 他のthreadを待っている間にシグナルが来たら,全thread
を強制終了させる.
* eval.c (rb_fail): メソッド名を`$!'に埋め込む.
* eval.c (thread_create): main_threadのコンテクストがセーブされな
い場合があった.
* process.c (f_sleep): 時間を指定せず,threadがひとつしかない状況
にも対応.
* eval.c (thread_create): create後,fnを呼び出す前にcontext switch
が起きると違うcontextでfnが実行されてしまうバグ.
Mon Jun 3 08:03:17 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* struct.c (struct_s_def): メンバの指定を文字列,シンボル(FIXNUM)
双方で可能にした.
* ext/etc/etc.c (Init_etc): 構造体オブジェクトをGCから保護した.
* error.c (rb_sys_fail): nil/FALSEを引数として受け付けるように.
Thu May 30 16:19:08 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (thread_select): EINTRに対応.
Wed May 29 11:04:51 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (f_catch): catch/throwを実装した.
Tue May 28 13:30:52 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99-960528
* eval.c (thread_cleanup): main threadが終了すると他のthreadも終了
することの明確化.
* signal.c (trap): SIGINTのデフォルトの設定ミス(本当にSIG_DFLでは
まずかった).rubyではちゃんとハンドルしないと.
* eval.c (thread_interrupt): SIGINTはmain_threadに例外を発生させる
ように.
Mon May 27 15:13:31 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (thread_status): threadの状態を返すメソッド.threadの終了
を待たない.
* eval.c (thread_value): 一種のpromiseを実装するためのメソッド.
* eval.c (thread_join): 待っているthreadが例外を起こした時には,
joinがその例外を発生するように.
* eval.c (thread_create): threadでの例外をpropagateしないように.
Fri May 24 10:47:53 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* enum.c (Init_Enumerable): `size' as alias to the `length'
* eval.c (thread_save_context): `$@', `$!'をスレッド毎にセーブ.
* eval.c (superclass): エラー表示をより親切に.
Thu May 23 10:38:41 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.99-960523
* eval.c (superclass): エラー時にスーパークラス名を(分かれば)表示
するように.
Wed May 22 19:48:42 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* parse.y (superclass): スーパークラスの指定子を`:'から`<'に変更.
Tue May 21 09:27:59 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* lib/thread.rb: threadをサポートするクラス(Mutex, Queue).
Mon May 20 09:39:49 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* time.c (time_cmp): 浮動小数点数も扱えるように.
(time_minus): Time - Timeが浮動小数点数を返すように.
Fri May 17 15:40:10 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* process.c (rb_proc_exec): Thread対応時にexecの直前に
ITIMER_VIRTUALをリセットする.
Tue May 14 02:12:44 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* signal.c (sighandle): SIGINTに対してデフォルトで例外を発生させる
のをやめ,status 130でexitするようにした.
* eval.c (thread_schedule): Threadのバグはほとんどとれたようだ.
Fri May 10 11:21:08 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (thread_schedule): ユーザレベルThread機能.効率はともかく
移植性はある.今後,thread間の通信機能を実装する予定.
Thu May 2 21:22:31 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* time.c (time_timeval): struct timevalを直接返すように(static変数
を使わない).
Wed May 1 17:27:32 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* process.c (f_sleep): 整数以外のtimeを指定できるように.
Thu Apr 25 08:19:15 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* file.c (file_s_dirname): ファイル名が"/"を含まない時,"."を返す
ように(GNU dirnameの仕様).
* file.c (file_s_basename): まだnilと0を混同しているソースが残って
いた.
* parse.y (exprs): エラーリカバリを追加.
Wed Apr 24 15:51:05 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* string.c (str_chop_bang): CRLFの場合2 bytesをchop!するように.
* ext/socket/socket.c (tcp_svr_s_open): まだnilと0を混同しているソー
スが残っていた.
Tue Apr 23 18:14:25 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* pack.c (pack_pack): "A/a"のバグ.余計なpaddingが入っていた.
Thu Apr 18 13:02:11 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* configure.in: アーキテクチャ依存部を別ディレクトリにインストール
するように.
* parse.y (yyerror): エラー発生時にエラー行とその位置を表示するよ
うに.
Wed Apr 17 14:22:42 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* defines.h: SAFE_SIGHANDLEを無くし,危険な選択はできないように.
* io.c (io_ungetc): 新機能.
* ruby.c (load_file): ファイルからの読み込み方式が変わったのに対応.
* parse.y (compile_file): ファイルからの入力を一度全部読み込むのを
止めて,getsを使うことにした.
Wed Apr 10 17:40:11 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.98
Tue Apr 9 09:54:30 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* parse.y (iter_block): イテレータブロックの指定をメソッド呼び出し
に限定.文法の明確化.
* eval.c (rb_eval): 条件式の正規表現の比較をinline化.
* eval.c (rb_eval): defined? の 定義情報(種別)を文字列で返す.
* node.h: NODE_BEGIN -> NODE_RESCUE, NODE_ENSUREに分離.
* eval.c (rb_eval): option -n/-pのトップレベルループのinline展開.
* parse.y (cond0): 条件式中の文字列は比較の対象としない
Wed Mar 27 12:33:54 1996 Tairo Nomura <tairo@hucom.tp.titech.ac.jp>
* defines.h: NeXT対応
Wed Mar 27 10:02:44 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* parse.y: 予約語の変更 continue -> next
Mon Mar 25 07:34:37 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* parse.y (parse_regx): o(once)オプションを追加.
Fri Mar 22 14:25:35 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.97d
* eval.c (dyna_var_defined): 動的ローカル変数の定義チェック用ルー
チン.
* parse.y (gettable): eval()の中での動的ローカル変数(既に値を持っ
ているもの)の検出に失敗していた.
Tue Mar 19 10:46:47 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.97c
* re.c (reg_s_new): compile時にsegmentation fault.
* parse.y (str_extend): いつもevalするように.
Wed Mar 13 11:00:42 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* parse.y (str_extend): 文字列中の式展開の不備を無くした.
* parse.y: 下手なエラーリカバリを外した.
Tue Mar 12 12:30:20 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (rescue): 間違ってensureでも例外を捕捉していた.
Wed Mar 6 12:11:03 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* parse.y (var_extend): 変数展開"#{}"で,任意の式を書けるようにし
た,これで「変数」展開では無くなっちゃったなあ.
* regex.c (init_syntax_once): `_'をwordに追加.
* regex.c (re_compile_pattern): `\w',`\W'の判定をsyntax tableを使
うように.
Tue Feb 27 10:15:32 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* object.c (obj_inspect): 表示するインスタンス変数が無い時には,
to_sを使う.
* configure.in: dlnの検出を自動的に.
Mon Feb 26 19:55:33 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* ruby.c (readin): read(2)で一度にファイルが読み込めない場合に対応.
Sat Feb 24 14:47:18 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.97b
Fri Feb 23 11:26:02 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* class.c (rb_define_module): C言語で定義されたモジュールのPATHの
設定忘れ.文字列化でcore dump.
* eval.c (mod_include): 戻り値をnilに.
* version 0.97a
Thu Feb 22 21:03:42 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* array.c (ary_times): 「配列*文字列」がjoinと同じ働きをするように.
Wed Feb 21 11:18:09 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* configure.in : fileCountをcache.
* configure.in : LinuxでELF環境を自動的に検出できるよう.
Tue Feb 20 11:18:09 1996 Mitsuhide Satou <mit-sato@aries.bekkoame.or.jp>
* FreeBSD dynamic link対応.
Fri Feb 16 08:50:01 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* object.c (obj_inspect): インスタンス変数を持たないオブジェクトも
正しく表示されるように.
Wed Feb 14 16:56:44 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (rb_eval): 条件式の`2..2'など左辺成立直後に右辺が成立する
パターンにバグ.
Tue Feb 13 18:22:22 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.97
Fri Feb 9 21:32:55 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* lib/tkscrollbox.rb: スクロールでtclの設定を行い,ruby<->wishの不
要な通信を無くした.
Wed Feb 7 10:26:52 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* string.c (str_aref): indexをunsigned intでとっていた.
* string.c (str_aref): 範囲外のindexに対してnilを返す.
* parse.y (special_local_set): `$_'が宣言無しに使われた場合に対応.
関数をvariable.cから移動.
* string.c (str_sub): 置換開始位置が間違っていた.
Tue Feb 6 16:17:31 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* sample/ruby-mode.el (ruby-parse-region): コメントの読み飛ばしの
バグ.
Fri Feb 2 18:35:28 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* variable.c (lastline_get): `$_'を`$~'と同じようにSCOPEローカルな
変数にした.
Thu Feb 1 14:14:07 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* file.c: statのcacheをやめた.
Wed Jan 31 07:13:08 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (proc_s_new): procの中でyieldを呼ばれた時にcore dumpして
いた.とりあえず例外を発生させる.
* variable.c (rb_class2path): singleton classに対応.
* ext/etc/etc.c (Init_etc): struct_defineのターミネータがnilだった
(0でなければならない).
* ext/marshal/marshal.c: TRUE/FALSEを吐き出せるように.
* eval.c (rb_get_method_body): キャッシュのalias対応,いままでは
aliasはキャッシュに入っていなかった.
Tue Jan 30 09:55:13 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (rb_eval): NODE_BLOCK - tail recursive(というほどでもない
が).
* io.c (io_pipe): pipe(2)を実装した.
* eval.c (rb_eval): Qselfをなくした.thread対応への第一歩.先は遠
いが….
* eval.c (proc_call): procの中でのreturnはprocの終了を意味するよう
に.ただし,procからのyieldの中でのreturnは例外を発生する.
Wed Jan 24 11:33:48 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.96a
* dir.c (dir_each): `$_'の値を変更するのをやめた.
* io.c (f_readlines): nilとFALSEの分離のあおりで無限ループに落ちて
いた.
* ruby.c (ruby_options): $0の設定ミス.
Tue Jan 23 15:28:21 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (rb_eval): ``は文字列を引数とするメソッド(`)呼び出しのシ
ンタックスシュガーであるとした.
* ruby.c (addpath): `-I'オプションでディレクトリが「前に」追加され
るように変更.
Fri Jan 19 11:23:12 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* dln.c (load_1): N_INDR対応(出来たような気がする).
Thu Jan 18 18:14:20 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* ruby.texi: FALSEとnilの分離を反映した.
Tue Jan 16 17:39:23 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.96 - とりあえずnilとFALSEを区別する版
Wed Jan 10 15:31:48 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* re.c (reg_match): マッチしなかった時の戻り値はFALSE.
* object.c (rb_equal): `0 == nil'がTRUEになるバグ.
Tue Jan 9 00:44:58 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* nilとFALSEが分離可能に変更.
* nilとFALSEと0の区別を厳密に.
* struct.c (struct_new): 引数を0で終る必要が無くなった.
* object.c (inspect_i): オブジェクトのチェックのバグ(Fixnumでcore
dumpしていた).
* range.c (range_to_s): Rangeの表示を改善.
* object.c (true_inspect): TRUEの表示を`TRUE'に.
Mon Jan 8 15:02:33 1996 Yukihiro Matsumoto <matz@caelum.co.jp>
* numeric.c (fix_mul): divide by zero errorが発生した(オーバーフロー
検出のバグ)
* texinfo.texをパッケージに含めた.
Sun Dec 31 00:08:49 1995 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (rb_eval): `::'では,そのクラスで定義された定数を参照する
ように変更.
* string.c (Init_String): eachをeach_lineに戻した.
Thu Dec 28 12:31:55 1995 Yukihiro Matsumoto <matz@caelum.co.jp>
* eval.c (rb_eval): caseの演算子を`=~'から`==='に.
* variable.c (rb_const_set): クラス定数の再定義を許す(同じクラスで
は不可).警告は出す.
Wed Dec 27 13:27:52 1995 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.95c
* ext/tkutil/tkutil.c: wishがあってもなくても一応コンパイルだけは
するように.
* lib/tk.rb: 環境変数PATHから{wish|wish4.0}を探すように.
Tue Dec 26 01:03:42 1995 Yukihiro Matsumoto <matz@caelum.co.jp>
* sample/ruby-mode.el (ruby-parse-region): 正規表現の検出強化.
* numeric.c (fix_mul): 乗算のオーバーフロー検出アルゴリズムのバグ.
* ext/extmk.rb.in: ./install-shを使う場合のPATHを調整.
* Makefile.in (install): lib/*.rbを一つずつインストール.
* io.c (io_each_line): イテレータの戻り値をnilで統一.
Fri Dec 22 10:34:32 1995 Yukihiro Matsumoto <matz@caelum.co.jp>
* version 0.95b
* variable.c (f_untrace_var): 第2引数を指定すると特定のtraceを削除
できるように.
* variable.c (f_trace_var): 第2引数がnilの時,traceを削除する.
* lib/tk.rb (file_readable/file_writable): 第2引数をnilにすること
によるevent handlerの削除.
* parse.y (variable): ドキュメントに`__FILE__'と`__LINE__'が残って
いた.`caller(0)'で代用したはずだったのに.
* eval.c (f_eval): $!のリセット.
* error.c (err_sprintf): 勝手に"\n"を付加するのを止めた.
* parse.y (f_arglist): 引数リスト直後のif/whileの読み間違い.
lex_stateの値が設定されていなかった.
Co-authored-by: Jun Kuroda <j_kuro@pluto.ai.kutech.ac.jp>
Co-authored-by: Mitsuhide Satou <mit-sato@aries.bekkoame.or.jp>
Co-authored-by: SHIROYAMA Takayuki <psi@fortune.nest.or.jp>
Co-authored-by: Tairo Nomura <tairo@hucom.tp.titech.ac.jp>
Co-authored-by: WATANABE Hirofumi <watanabe@ase.ptg.sony.co.jp>
Co-authored-by: Yasuo OHBA <jammy@shljapan.co.jp>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/base64.rb | 2 | ||||
-rw-r--r-- | lib/cgi-lib.rb | 56 | ||||
-rw-r--r-- | lib/complex.rb | 490 | ||||
-rw-r--r-- | lib/find.rb | 47 | ||||
-rw-r--r-- | lib/getopts.rb | 173 | ||||
-rw-r--r-- | lib/jcode.rb | 174 | ||||
-rw-r--r-- | lib/mailread.rb | 19 | ||||
-rw-r--r-- | lib/mathn.rb | 307 | ||||
-rw-r--r-- | lib/observer.rb | 40 | ||||
-rw-r--r-- | lib/parsearg.rb | 103 | ||||
-rw-r--r-- | lib/rational.rb | 361 | ||||
-rw-r--r-- | lib/safe.rb | 78 | ||||
-rw-r--r-- | lib/thread.rb | 153 | ||||
-rw-r--r-- | lib/tk.rb | 557 | ||||
-rw-r--r-- | lib/tkcanvas.rb | 47 | ||||
-rw-r--r-- | lib/tkcore.rb | 521 | ||||
-rw-r--r-- | lib/tkentry.rb | 2 | ||||
-rw-r--r-- | lib/tkscrollbox.rb | 27 | ||||
-rw-r--r-- | lib/tktext.rb | 18 | ||||
-rw-r--r-- | lib/tkthcore.rb | 546 |
20 files changed, 3036 insertions, 685 deletions
diff --git a/lib/base64.rb b/lib/base64.rb index a6bf1adf92..9bb6487bee 100644 --- a/lib/base64.rb +++ b/lib/base64.rb @@ -46,7 +46,7 @@ def j2e(str) end def decode_b(str) - str.gsub!(/=\?ISO-2022-JP\?B\?([!->@-~]+)\?=/) { + str.gsub!(/=\?ISO-2022-JP\?B\?([!->@-~]+)\?=/i) { decode64($1) } str.gsub!(/\n/, ' ') diff --git a/lib/cgi-lib.rb b/lib/cgi-lib.rb new file mode 100644 index 0000000000..afadbff3b6 --- /dev/null +++ b/lib/cgi-lib.rb @@ -0,0 +1,56 @@ +#!/usr/local/bin/ruby +# +# Get CGI String +# +# EXAMPLE: +# require "cgi-lib.rb" +# foo = CGI.new +# foo['field'] <== value of 'field' +# foo.keys <== array of fields +# foo.inputs <== hash of { <field> => <value> } + +class CGI + attr("inputs") + + def initialize + str = if ENV['REQUEST_METHOD'] == "GET" + ENV['QUERY_STRING'] + elsif ENV['REQUEST_METHOD'] == "POST" + $stdin.read ENV['CONTENT_LENGTH'].to_i + else + "" + end + arr = str.split(/&/) + @inputs = {} + arr.each do |x| + x.gsub!(/\+/, ' ') + key, val = x.split(/=/, 2) + val = "" unless val + + key.gsub!(/%(..)/) { [$1.hex].pack("c") } + val.gsub!(/%(..)/) { [$1.hex].pack("c") } + + @inputs[key] += "\0" if @inputs[key] + @inputs[key] += val + end + end + + def keys + @inputs.keys + end + + def [](key) + @inputs[key] + end + + def CGI.message(msg, title = "") + print "Content-type: text/html\n\n" + print "<html><head><title>" + print title + print "</title></head><body>\n" + print msg + print "</body></html>\n" + TRUE + end + +end diff --git a/lib/complex.rb b/lib/complex.rb new file mode 100644 index 0000000000..aa5d219d2f --- /dev/null +++ b/lib/complex.rb @@ -0,0 +1,490 @@ +# +# complex.rb - +# $Release Version: 0.5 $ +# $Revision: 1.1 $ +# $Date: 1996/11/11 04:25:19 $ +# by Keiju ISHITSUKA(SHL Japan Inc.) +# +# -- +# Usage: +# class Complex < Numeric +# +# Complex(x, y) --> x + yi +# y.im --> 0 + yi +# +# Complex::polar +# +# Complex::+ +# Complex::- +# Complex::* +# Complex::/ +# Complex::** +# Complex::% +# Complex::divmod +# Complex::abs +# Complex::abs2 +# Complex::arg +# Complex::polar +# Complex::conjugate +# Complex::<=> +# Complex::== +# Complex::to_i +# Complex::to_f +# Complex::to_r +# Complex::to_s +# +# Complex::I +# +# Numeric::im +# +# Math.sqrt +# Math.exp +# Math.cos +# Math.sin +# Math.tan +# Math.log +# Math.log10 +# Math.atan2 +# +# + +def Complex(a, b = 0) + if a.kind_of?(Complex) and b == 0 + a + elsif b == 0 and defined? Complex::Unify + a + else + Complex.new(a, b) + end +end + +class Complex < Numeric + + def Complex.generic?(other) + other.kind_of?(Integer) or + other.kind_of?(Float) or + (defined?(Rational) and other.kind_of?(Rational)) + end + + def Complex.polar(r, theta) + Complex(r*Math.cos(theta), r*Math.sin(theta)) + end + + def initialize(a, b = 0) + @real = a + @image = b + end + + def + (other) + if other.kind_of?(Complex) + re = @real + other.real + im = @image + other.image + Complex(re, im) + elsif Complex.generic?(other) + Complex(@real + other, @image) + else + x , y = a.coerce(self) + x + y + end + end + + def - (other) + if other.kind_of?(Complex) + re = @real - other.real + im = @image - other.image + Complex(re, im) + elsif Complex.generic?(other) + Complex(@real - other, @image) + else + x , y = a.coerce(self) + x - y + end + end + + def * (other) + if other.kind_of?(Complex) + re = @real*other.real - @image*other.image + im = @real*other.image + @image*other.real + Complex(re, im) + elsif Complex.generic?(other) + Complex(@real * other, @image * other) + else + x , y = a.coerce(self) + x * y + end + end + + def / (other) + if other.kind_of?(Complex) + self * other.conjugate / other.abs2 + elsif Complex.generic?(other) + Complex(@real / other, @image / other) + else + x , y = a.coerce(self) + x / y + end + end + + def ** (other) + if other == 0 + return Complex(1) + end + if other.kind_of?(Complex) + r, theta = polar + ore = other.real + oim = other.image + nr = Math.exp!(ore*Math.log!(r) - oim * theta) + ntheta = theta*ore + oim*Math.log!(r) + Complex.polar(nr, ntheta) + elsif other.kind_of?(Integer) + if other > 0 + x = self + z = x + n = other - 1 + while n != 0 + while (div, mod = n.divmod(2) + mod == 0) + x = Complex(x.real*x.real - x.image*x.image, 2*x.real*x.image) + n = div + end + z *= x + n -= 1 + end + z + else + if defined? Rational + (Rational(1) / self) ** -other + else + self ** Float(other) + end + end + elsif Complex.generic?(other) + r, theta = polar + Complex.polar(r.power!(other), theta * other) + else + x , y = a.coerce(self) + x / y + end + end + + def % (other) + if other.kind_of?(Complex) + Complex(@real % other.real, @image % other.image) + elsif Complex.generic?(other) + Complex(@real % other, @image % other) + else + x , y = a.coerce(self) + x % y + end + end + + def divmod(other) + if other.kind_of?(Complex) + rdiv, rmod = @real.divmod(other.real) + idiv, imod = @image.divmod(other.image) + return Complex(rdiv, idiv), Complex(rmod, rdiv) + elsif Complex.generic?(other) + Complex(@real.divmod(other), @image.divmod(other)) + else + x , y = a.coerce(self) + x.divmod(y) + end + end + + def abs + Math.sqrt!((@real*@real + @image*@image).to_f) + end + + def abs2 + @real*@real + @image*@image + end + + def arg + Math.atan2(@image.to_f, @real.to_f) + end + + def polar + return abs, arg + end + + def conjugate + Complex(@real, -@image) + end + + def <=> (other) + self.abs <=> other.abs + end + + def == (other) + if other.kind_of?(Complex) + @real == other.real and @image == other.image + elsif Complex.generic?(other) + @real == other and @image == 0 + else + x , y = a.coerce(self) + x == y + end + end + + def coerce(other) + if Complex.generic?(other) + return Complex.new(other), self + else + super + end + end + + def to_i + Complex(@real.to_i, @image.to_i) + end + + def to_f + Complex(@real.to_f, @image.to_f) + end + + def to_r + Complex(@real.to_r, @image.to_r) + end + + def denominator + @real.denominator.lcm(@image.denominator) + end + + def numerator + cd = denominator + Complex(@real.numerator*(cd/@real.denominator), + @image.numerator*(cd/@image.denominator)) + end + + def to_s + if @real != 0 + if defined?(Rational) and @image.kind_of?(Rational) and @image.denominator != 1 + if @image >= 0 + @real.to_s+"+("+@image.to_s+")i" + else + @real.to_s+"-("+(-@image).to_s+")i" + end + else + if @image >= 0 + @real.to_s+"+"+@image.to_s+"i" + else + @real.to_s+"-"+(-@image).to_s+"i" + end + end + else + if defined?(Rational) and @image.kind_of?(Rational) and @image.denominator != 1 + "("+@image.to_s+")i" + else + @image.to_s+"i" + end + end + end + + def hash + @real ^ @image + end + + I = Complex(0,1) + + attr :real + attr :image + +end + +class Numeric + def im + Complex(0, self) + end + + def real + self + end + + def image + 0 + end + + def arg + if self >= 0 + return 0 + else + return Math.atan2(1,1)*4 + end + end + + def polar + return abs, arg + end + + def conjugate + self + end +end + +class Fixnum + if not defined? Rational + alias power! ** + end + + def ** (other) + if self < 0 + Complex.new(self) ** other + else + if defined? Rational + if other >= 0 + self.power!(other) + else + Rational.new!(self,1)**other + end + else + self.power!(other) + end + end + end +end + +class Bignum + if not defined? Rational + alias power! ** + end +end + +class Float + alias power! ** +end + +module Math + alias sqrt! sqrt + alias exp! exp + alias cos! cos + alias sin! sin + alias tan! tan + alias log! log + alias log10! log10 + alias atan2! atan2 + + def sqrt(z) + if Complex.generic?(z) + if z >= 0 + sqrt!(z) + else + Complex(0,sqrt!(-z)) + end + else + z**Rational(1,2) + end + end + + def exp(z) + if Complex.generic?(z) + exp!(z) + else + Complex(exp!(z.real) * cos!(z.image), exp!(z.real) * sin!(z.image)) + end + end + + def cosh!(x) + (exp!(x) + exp!(-x))/2.0 + end + + def sinh!(x) + (exp!(x) - exp!(-x))/2.0 + end + + def cos(z) + if Complex.generic?(z) + cos!(z) + else + Complex(cos!(z.real)*cosh!(z.image), + sin!(z.real)*sinh!(z.image)) + end + end + + def sin(z) + if Complex.generic?(z) + sin!(z) + else + Complex(sin!(z.real)*cosh!(z.image), + -cos!(z.real)*sinh!(z.image)) + end + end + + def tan(z) + if Complex.generic?(z) + tan!(z) + else + sin(z)/cos(z) + end + end + + def log(z) + if Complex.generic?(z) and z >= 0 + log!(z) + else + r, theta = z.polar + Complex(log!(r.abs), theta) + end + end + + def log10(z) + if Complex.generic?(z) + log10!(z) + else + log(z)/log!(10) + end + end + + def atan2(x, y) + if Complex.generic?(x) and Complex.generic?(y) + atan2!(x, y) + else + fail "Not yet implemented." + end + end + + def atanh!(x) + log((1.0 + x.to_f) / ( 1.0 - x.to_f)) / 2.0 + end + + def atan(z) + if Complex.generic?(z) + atan2!(z, 1) + elsif z.image == 0 + atan2(z.real,1) + else + a = z.real + b = z.image + + c = (a*a + b*b - 1.0) + d = (a*a + b*b + 1.0) + + Complex(atan2!((c + sqrt(c*c + 4.0*a*a)), 2.0*a), + atanh!((-d + sqrt(d*d - 4.0*b*b))/(2.0*b))) + end + end + + module_function :sqrt + module_function :sqrt! + module_function :exp! + module_function :exp + module_function :cosh! + module_function :cos! + module_function :cos + module_function :sinh! + module_function :sin! + module_function :sin + module_function :tan! + module_function :tan + module_function :log! + module_function :log + module_function :log10! + module_function :log + module_function :atan2! + module_function :atan2 +# module_function :atan! + module_function :atan + module_function :atanh! + +end + + diff --git a/lib/find.rb b/lib/find.rb index 340461c653..5ecc54329c 100644 --- a/lib/find.rb +++ b/lib/find.rb @@ -8,31 +8,32 @@ # module Find - extend Find - - def findpath(path, ary) - ary.push(path) - d = Dir.open(path) - for f in d - continue if f =~ /^\.\.?$/ - f = path + "/" + f - if File.directory? f - findpath(f, ary) - else - ary.push(f) - end + def find(*path) + while file = path.shift + catch(:prune) { + yield file + if File.directory? file and not File.symlink? file then + d = Dir.open(file) + begin + for f in d + next if f =~ /^\.\.?$/ + if file == "/" then + f = "/" + f + else + f = file + "/" + f + end + path.unshift f + end + ensure + d.close + end + end + } end end - private :findpath - def find(*path) - ary = [] - for p in path - findpath(p, ary) - for f in ary - yield f - end - end + def prune + throw :prune end - module_function :find + module_function :find, :prune end diff --git a/lib/getopts.rb b/lib/getopts.rb index 37fd3dc69d..d25437515d 100644 --- a/lib/getopts.rb +++ b/lib/getopts.rb @@ -1,117 +1,142 @@ +#!/usr/local/bin/ruby # -# getopts.rb - get options +# getopts.rb - # $Release Version: $ -# $Revision: 1.2 $ -# $Date: 1994/02/15 05:17:15 $ -# by Yasuo OHBA(STAFS Development Room) +# $Revision: 1.1 $ +# $Date: 1996/11/10 05:01:15 $ +# by Yasuo OHBA(SHL Japan Inc. Technology Dept.) # # -- -# IvV̉͂, $OPT_?? ɒlZbg܂. -# ŵȂIvVw肳ꂽ nil Ԃ܂. -# Iꍇ, ZbgꂽIvV̐Ԃ܂. # -# getopts(single_opts, *opts) -# -# ex. sample [options] filename -# options ... -# -f -x --version --geometry 100x200 -d unix:0.0 -# -# getopts("fx", "version", "geometry:", "d:") -# -# : -# -f -x (= -fx) ̗lȈꕶ̃IvV̎w܂. -# ňȂƂ nil ̎w肪Kvł. -# ȍ~: -# Ol[̃IvV, ̔IvV̎w܂. -# --version , --geometry 300x400 , -d host:0.0 ł. -# w ":" KtĂ. -# -# IvV̎w肪ꍇ, ϐ $OPT_?? non-nil , ̃I -# vV̈Zbg܂. -# -f -> $OPT_f = TRUE -# --geometry 300x400 -> $OPT_geometry = 300x400 -# -# - -- , ȍ~, SăIvV̉͂܂. +# # -$RCS_ID="$Header: /var/ohba/RCS/getopts.rb,v 1.2 1994/02/15 05:17:15 ohba Exp ohba $" +$RCS_ID="$Header: /home/jammy/current/ruby/RCS/getopts.rb,v 1.1 1996/11/10 05:01:15 jammy Exp $" + +def isSingle(lopt) + if lopt.index(":") + if lopt.split(":")[0].length == 1 + return TRUE + end + end + return nil +end + +def getOptionName(lopt) + return lopt.split(":")[0] +end + +def getDefaultOption(lopt) + od = lopt.split(":")[1] + if od + return od + end + return nil +end + +def setOption(name, value) + eval("$OPT_" + name + " = " + 'value') +end + +def setDefaultOption(lopt) + d = getDefaultOption(lopt) + if d + setOption(getOptionName(lopt), d) + end +end + +def setNewArgv(newargv) + ARGV.clear + for na in newargv + ARGV << na + end +end -def getopts(single_opts, *opts) - if (opts) + +def getopts(single_opts, *options) + if options single_colon = "" long_opts = [] sc = 0 - for option in opts - if (option.length <= 2) - single_colon[sc, 0] = option[0, 1] + for o in options + setDefaultOption(o) + if isSingle(o) + single_colon[sc, 0] = getOptionName(o) sc += 1 else - long_opts.push(option) + long_opts.push(o) end end end - + opts = {} count = 0 - while ($ARGV.length != 0) + newargv = [] + while ARGV.length != 0 compare = nil - case $ARGV[0] + case ARGV[0] when /^--?$/ - $ARGV.shift + ARGV.shift + newargv += ARGV break when /^--.*/ - compare = $ARGV[0][2, ($ARGV[0].length - 2)] - if (long_opts != "") - for option in long_opts - if (option[(option.length - 1), 1] == ":" && - option[0, (option.length - 1)] == compare) - if ($ARGV.length <= 1) + compare = ARGV[0][2, (ARGV[0].length - 2)] + if long_opts != "" + for lo in long_opts + if lo.index(":") && getOptionName(lo) == compare + if ARGV.length <= 1 return nil - end - eval("$OPT_" + compare + " = " + '$ARGV[1]') - opts[compare] = TRUE - $ARGV.shift + end + setOption(compare, ARGV[1]) + opts[compare] = TRUE + ARGV.shift count += 1 break - elsif (option == compare) - eval("$OPT_" + compare + " = TRUE") - opts[compare] = TRUE + elsif lo == compare + setOption(compare, TRUE) + opts[compare] = TRUE count += 1 - break - end - end + break + end + end + end + if compare.length <= 1 + return nil end when /^-.*/ - for index in 1..($ARGV[0].length - 1) - compare = $ARGV[0][index, 1] - if (single_opts && compare =~ "[" + single_opts + "]") - eval("$OPT_" + compare + " = TRUE") - opts[compare] = TRUE + for idx in 1..(ARGV[0].length - 1) + compare = ARGV[0][idx, 1] + if single_opts && compare =~ "[" + single_opts + "]" + setOption(compare, TRUE) + opts[compare] = TRUE count += 1 - elsif (single_colon != "" && compare =~ "[" + single_colon + "]") - if ($ARGV[0][index..-1].length > 1) - eval("$OPT_" + compare + " = " + '$ARGV[0][(index + 1)..-1]') - opts[compare] = TRUE + elsif single_colon != "" && compare =~ "[" + single_colon + "]" + if ARGV[0][idx..-1].length > 1 + setOption(compare, ARGV[0][(idx + 1)..-1]) + opts[compare] = TRUE count += 1 - elsif ($ARGV.length <= 1) + elsif ARGV.length <= 1 return nil else - eval("$OPT_" + compare + " = " + '$ARGV[1]') - opts[compare] = TRUE - $ARGV.shift - count = count + 1 + setOption(compare, ARGV[1]) + opts[compare] = TRUE + ARGV.shift + count += 1 end break end end else - break + compare = ARGV[0] + opts[compare] = TRUE + newargv << ARGV[0] end - - $ARGV.shift - if (!opts.includes(compare)) + + ARGV.shift + if !opts.has_key?(compare) return nil end end + setNewArgv(newargv) return count end diff --git a/lib/jcode.rb b/lib/jcode.rb new file mode 100644 index 0000000000..5b2289932f --- /dev/null +++ b/lib/jcode.rb @@ -0,0 +1,174 @@ +# jcode.rb - ruby code to handle japanese (EUC/SJIS) string + +class String + printf STDERR, "feel free for some warnings:\n" if $VERBOSE + + alias original_succ succ + private :original_succ + + def succ + if self[-2] && self[-2] & 0x80 != 0 + s = self.dup + s[-1] += 1 + return s + else + original_succ + end + end + + def upto(to) + return if self > to + + curr = self + tail = self[-2..-1] + if tail.length == 2 and tail =~ /^.$/ then + if self[0..-2] == to[0..-2] + for c in self[-1] .. to[-1] + yield self[0..-2]+c.chr + end + end + else + loop do + yield curr + return if curr == to + curr = curr.succ + return if curr.length > to.length + end + end + return nil + end + + def _expand_ch + a = [] + self.scan(/(.|\n)-(.|\n)|(.|\n)/) do |r| + if $3 + a.push $3 + elsif $1.length != $2.length + next + elsif $1.length == 1 + $1[0].upto($2[0]) { |c| a.push c.chr } + else + $1.upto($2) { |c| a.push c } + end + end + a + end + + def tr!(from, to) + return self.delete!(from) if to.length == 0 + + if from =~ /^\^/ + comp=TRUE + from = $' + end + afrom = from._expand_ch + ato = to._expand_ch + i = 0 + if comp + self.gsub!(/(.|\n)/) do |c| + unless afrom.include?(c) + ato[-1] + else + c + end + end + else + self.gsub!(/(.|\n)/) do |c| + if i = afrom.index(c) + if i < ato.size then ato[i] else ato[-1] end + else + c + end + end + end + end + + def tr(from, to) + self.dup.tr!(from, to) + end + + def delete!(del) + if del =~ /^\^/ + comp=TRUE + del = $' + end + adel = del._expand_ch + if comp + self.gsub!(/(.|\n)/) do |c| + next unless adel.include?(c) + c + end + else + self.gsub!(/(.|\n)/) do |c| + next if adel.include?(c) + c + end + end + end + + def delete(del) + self.dup.delete!(del) + end + + def squeeze!(del=nil) + if del + if del =~ /^\^/ + comp=TRUE + del = $' + end + adel = del._expand_ch + if comp + self.gsub!(/(.|\n)\1+/) do + next unless adel.include?($1) + $& + end + else + for c in adel + cq = Regexp.quote(c) + self.gsub!(/#{cq}(#{cq})+/, cq) + end + end + self + else + self.gsub!(/(.|\n)\1+/, '\1') + end + end + + def squeeze(del=nil) + self.dup.squeeze!(del) + end + + def tr_s!(from, to) + return self.delete!(from) if to.length == 0 + if from =~ /^\^/ + comp=TRUE + from = $' + end + afrom = from._expand_ch + ato = to._expand_ch + i = 0 + c = nil + last = nil + self.gsub!(/(.|\n)/) do |c| + if comp + unless afrom.include?(c) + ato[-1] + else + c + end + elsif i = afrom.index(c) + c = if i < ato.size then ato[i] else ato[-1] end + next if c == last + last = c + else + last = nil + c + end + end + end + + def tr_s(from, to) + self.dup.tr_s!(from,to) + end + +end diff --git a/lib/mailread.rb b/lib/mailread.rb index 4b04445beb..d9feffbb7a 100644 --- a/lib/mailread.rb +++ b/lib/mailread.rb @@ -1,9 +1,8 @@ class Mail - def Mail.new(f) - if !f.is_kind_of?(IO) + unless f.kind_of?(IO) f = open(f, "r") - me = super + me = super(f) f.close else me = super @@ -16,17 +15,18 @@ class Mail @body = [] while f.gets() $_.chop! - continue if /^From / # skip From-line + next if /^From / # skip From-line break if /^$/ # end of header + if /^(\S+):\s*(.*)/ - @header[attr = $1.capitalize] = $2 + @header[attr = $1.capitalize!] = $2 elsif attr - sub(/^\s*/, '') + sub!(/^\s*/, '') @header[attr] += "\n" + $_ end end - - return if ! $_ + + return unless $_ while f.gets() break if /^From / @@ -42,4 +42,7 @@ class Mail return @body end + def [](field) + @header[field] + end end diff --git a/lib/mathn.rb b/lib/mathn.rb new file mode 100644 index 0000000000..359cb45769 --- /dev/null +++ b/lib/mathn.rb @@ -0,0 +1,307 @@ +# +# mathn.rb - +# $Release Version: 0.5 $ +# $Revision: 1.1 $ +# $Date: 1996/11/11 04:25:24 $ +# by Keiju ISHITSUKA(SHL Japan Inc.) +# +# -- +# +# +# + +require "rational.rb" +require "complex.rb" + +class Integer + + def gcd2(int) + a = self.abs + b = int.abs + a, b = b, a if a < b + + pd_a = a.prime_division + pd_b = b.prime_division + + gcd = 1 + for pair in pd_a + as = pd_b.assoc(pair[0]) + if as + gcd *= as[0] ** [as[1], pair[1]].min + end + end + return gcd + end + + def Integer.from_prime_division(pd) + value = 1 + for prime, index in pd + value *= prime**index + end + value + end + + def prime_division + ps = Prime.new + value = self + pv = [] + for prime in ps + count = 0 + while (value1, mod = value.divmod(prime) + mod) == 0 + value = value1 + count += 1 + end + if count != 0 + pv.push [prime, count] + end + break if prime * prime >= value + end + if value > 1 + pv.push [value, 1] + end + return pv + end +end + +class Prime + include Enumerable + + def initialize + @seed = 1 + @primes = [] + @counts = [] + end + + def succ + i = -1 + size = @primes.size + while i < size + if i == -1 + @seed += 1 + i += 1 + else + while @seed > @counts[i] + @counts[i] += @primes[i] + end + if @seed != @counts[i] + i += 1 + else + i = -1 + end + end + end + @primes.push @seed + @counts.push @seed + @seed + return @seed + end + + def each + loop do + yield succ + end + end +end + +class Fixnum + alias divmod! divmod + alias / rdiv + def divmod(other) + a = self.div(other) + b = self % other + return a,b + end +end + +class Bignum + alias divmod! divmod + alias / rdiv +end + +class Rational + Unify = TRUE + + alias power! ** + + def ** (other) + if other.kind_of?(Rational) + if self < 0 + return Complex(self, 0) ** other + elsif other == 0 + return Rational(1,1) + elsif self == 0 + return Rational(0,1) + elsif self == 1 + return Rational(1,1) + end + + npd = @numerator.prime_division + dpd = @denominator.prime_division + if other < 0 + other = -other + npd, dpd = dpd, npd + end + + for elm in npd + elm[1] = elm[1] * other + if !elm[1].kind_of?(Integer) and elm[1].denominator != 1 + return Float(self) ** other + end + elm[1] = elm[1].to_i + end + + for elm in dpd + elm[1] = elm[1] * other + if !elm[1].kind_of?(Integer) and elm[1].denominator != 1 + return Float(self) ** other + end + elm[1] = elm[1].to_i + end + + num = Integer.from_prime_division(npd) + den = Integer.from_prime_division(dpd) + + Rational(num,den) + + elsif other.kind_of?(Integer) + if other > 0 + num = @numerator ** other + den = @denominator ** other + elsif other < 0 + num = @denominator ** -other + den = @numerator ** -other + elsif other == 0 + num = 1 + den = 1 + end + Rational.new!(num, den) + elsif other.kind_of?(Float) + Float(self) ** other + else + x , y = other.coerce(self) + x ** y + end + end + + def power2(other) + if other.kind_of?(Rational) + if self < 0 + return Complex(self, 0) ** other + elsif other == 0 + return Rational(1,1) + elsif self == 0 + return Rational(0,1) + elsif self == 1 + return Rational(1,1) + end + + dem = nil + x = self.denominator.to_f.to_i + neard = self.denominator.to_f ** (1.0/other.denominator.to_f) + loop do + if (neard**other.denominator == self.denominator) + dem = neaed + break + end + end + nearn = self.numerator.to_f ** (1.0/other.denominator.to_f) + Rational(num,den) + + elsif other.kind_of?(Integer) + if other > 0 + num = @numerator ** other + den = @denominator ** other + elsif other < 0 + num = @denominator ** -other + den = @numerator ** -other + elsif other == 0 + num = 1 + den = 1 + end + Rational.new!(num, den) + elsif other.kind_of?(Float) + Float(self) ** other + else + x , y = other.coerce(self) + x ** y + end + end +end + +module Math + def sqrt(a) + if a.kind_of?(Complex) + abs = sqrt(a.real*a.real + a.image*a.image) +# if not abs.kind_of?(Rational) +# return a**Rational(1,2) +# end + x = sqrt((a.real + abs)/Rational(2)) + y = sqrt((-a.real + abs)/Rational(2)) +# if !(x.kind_of?(Rational) and y.kind_of?(Rational)) +# return a**Rational(1,2) +# end + if a.image >= 0 + Complex(x, y) + else + Complex(x, -y) + end + elsif a >= 0 + rsqrt(a) + else + Complex(0,rsqrt(-a)) + end + end + + def rsqrt(a) + if a.kind_of?(Float) + sqrt!(a) + elsif a.kind_of?(Rational) + rsqrt(a.numerator)/rsqrt(a.denominator) + else + src = a + max = 2 ** 32 + byte_a = [src & 0xffffffff] + # ruby's bug + while (src >= max) and (src >>= 32) + byte_a.unshift src & 0xffffffff + end + + answer = 0 + main = 0 + side = 0 + for elm in byte_a + main = (main << 32) + elm + side <<= 16 + if answer != 0 + if main * 4 < side * side + applo = main.div(side) + else + applo = ((sqrt!(side * side + 4 * main) - side)/2.0).to_i + 1 + end + else + applo = sqrt!(main).to_i + 1 + end + + while (x = (side + applo) * applo) > main + applo -= 1 + end + main -= x + answer = (answer << 16) + applo + side += applo * 2 + end + if main == 0 + answer + else + sqrt!(a) + end + end + end + + module_function :sqrt + module_function :rsqrt +end + +class Complex + Unify = TRUE +end + diff --git a/lib/observer.rb b/lib/observer.rb new file mode 100644 index 0000000000..9a753939a2 --- /dev/null +++ b/lib/observer.rb @@ -0,0 +1,40 @@ +# Observable Mixin +# +# Observers must respond to update + +module Observable + def add_observer(observer) + @observer_peers = [] unless @observer_peers + unless defined? observer.update + raise NameError, "observer needs to respond to `update'" + end + @observer_peers.push observer + end + def delete_observer(observer) + @observer_peers.delete observer if @observer_peers + end + def delete_observers + @observer_peers.clear if @observer_peers + end + def count_observers + if @observer_peers + @observer_peers.size + else + 0 + end + end + def changed(state=TRUE) + @observer_state = state + end + def changed? + @observer_state + end + def notify_observers(*arg) + if @observer_state + for i in @observer_peers + i.update(*arg) + end + @observer_state = FALSE + end + end +end diff --git a/lib/parsearg.rb b/lib/parsearg.rb index e7e2b7a7f3..569ed260f7 100644 --- a/lib/parsearg.rb +++ b/lib/parsearg.rb @@ -1,68 +1,83 @@ +#!/usr/local/bin/ruby # -# parseargs.rb - parse arguments +# parsearg.rb - parse arguments # $Release Version: $ # $Revision: 1.3 $ -# $Date: 1994/02/15 05:16:21 $ -# by Yasuo OHBA(STAFS Development Room) +# $Date: 1996/11/12 06:48:51 $ +# by Yasuo OHBA(SHL Japan Inc. Technology Dept.) # # -- -# ̉͂, $OPT_?? ɒlZbg܂. -# Iꍇ, ZbgꂽIvV̐Ԃ܂. # -# parseArgs(argc, single_opts, *opts) -# -# ex. sample [options] filename -# options ... -# -f -x --version --geometry 100x200 -d unix:0.0 -# -# parseArgs(1, nil, "fx", "version", "geometry:", "d:") -# -# : -# IvVȊO̍Œ̐ -# : -# IvV̕KvcKKvȂ %TRUE łȂ %FALSE. -# O: -# -f -x (= -fx) ̗lȈꕶ̃IvV̎w܂. -# ňȂƂ nil ̎w肪Kvł. -# lȍ~: -# Ol[̃IvV, ̔IvV̎w܂. -# --version , --geometry 300x400 , -d host:0.0 ł. -# w ":" KtĂ. -# -# IvV̎w肪ꍇ, ϐ $OPT_?? non-nil , ̃I -# vV̈Zbg܂. -# -f -> $OPT_f = %TRUE -# --geometry 300x400 -> $OPT_geometry = 300x400 -# -# usage gꍇ, $USAGE usage() w肵܂. -# def usage() -# c -# end -# $USAGE = 'usage' -# usage , --help w肳ꂽ, Ԉwɕ\܂. -# -# - -- , ȍ~, SăIvV̉͂܂. +# # -$RCS_ID="$Header: /var/ohba/RCS/parseargs.rb,v 1.3 1994/02/15 05:16:21 ohba Exp ohba $" +$RCS_ID="$Header: /home/jammy/current/ruby/RCS/parsearg.rb,v 1.3 1996/11/12 06:48:51 jammy Exp $" load("getopts.rb") def printUsageAndExit() if $USAGE - apply($USAGE) + eval($USAGE) end exit() end +def setParenthesis(ex, opt, c) + if opt != "" + ex = sprintf("%s$OPT_%s%s", ex, opt, c) + else + ex = sprintf("%s%s", ex, c) + end + return ex +end + +def setOrAnd(ex, opt, c) + if opt != "" + ex = sprintf("%s$OPT_%s %s%s ", ex, opt, c, c) + else + ex = sprintf("%s %s%s ", ex, c, c) + end + return ex +end + +def setExpression(ex, opt, op) + if !op + ex = sprintf("%s$OPT_%s", ex, opt) + return ex + end + case op.chr + when "(", ")" + ex = setParenthesis(ex, opt, op.chr) + when "|", "&" + ex = setOrAnd(ex, opt, op.chr) + else + return nil + end + return ex +end + def parseArgs(argc, nopt, single_opts, *opts) - if ((noOptions = getopts(single_opts, *opts)) == nil) + if (noOptions = getopts(single_opts, *opts)) == nil printUsageAndExit() end - if (nopt && noOptions == 0) - printUsageAndExit() + if nopt + ex = nil + pos = 0 + for o in nopt.split(/[()|&]/) + pos += o.length + ex = setExpression(ex, o, nopt[pos]) + pos += 1 + end + begin + if !eval(ex) + printUsageAndExit() + end + rescue + print "Format Error!! : \"" + nopt + "\"\t[parseArgs]\n" + exit! -1 + end end - if ($ARGV.length < argc) + if ARGV.length < argc printUsageAndExit() end return noOptions diff --git a/lib/rational.rb b/lib/rational.rb new file mode 100644 index 0000000000..d4112c2956 --- /dev/null +++ b/lib/rational.rb @@ -0,0 +1,361 @@ +# +# rational.rb - +# $Release Version: 0.5 $ +# $Revision: 1.1 $ +# $Date: 1996/11/11 04:25:14 $ +# by Keiju ISHITSUKA(SHL Japan Inc.) +# +# -- +# Usage: +# class Rational < Numeric +# (include Compareable) +# +# Rational(a, b) --> a/b +# +# Rational::+ +# Rational::- +# Rational::* +# Rational::/ +# Rational::** +# Rational::% +# Rational::divmod +# Rational::abs +# Rational::<=> +# Rational::to_i +# Rational::to_f +# Rational::to_s +# +# Integer::gcd +# Integer::lcm +# Integer::gcdlcm +# Integer::to_r +# +# Fixnum::** +# Bignum::** +# +# + +def Rational(a, b = 1) + if a.kind_of?(Rational) && b == 1 + a + else + Rational.reduce(a, b) + end +end + +class Rational < Numeric + def Rational.reduce(num, den = 1) + if den < 0 + num = -num + den = -den + end + gcd = num.gcd(den) + num = num.div(gcd) + den = den.div(gcd) + if den == 1 && defined?(Unify) + num + else + new!(num, den) + end + end + + def Rational.new!(num, den = 1) + new(num, den) + end + + def initialize(num, den) + if den < 0 + num = -num + den = -den + end + if num.kind_of?(Integer) and den.kind_of?(Integer) + @numerator = num + @denominator = den + else + @numerator = num.to_i + @denoninator = den.to_i + end + end + + def + (a) + if a.kind_of?(Rational) + num = @numerator * a.denominator + num_a = a.numerator * @denominator + Rational(num + num_a, @denominator * a.denominator) + elsif a.kind_of?(Integer) + self + Rational.new!(a, 1) + elsif a.kind_of?(Float) + Float(self) + a + else + x , y = a.coerce(self) + x + y + end + end + + def - (a) + if a.kind_of?(Rational) + num = @numerator * a.denominator + num_a = a.numerator * @denominator + Rational(num - num_a, @denominator*a.denominator) + elsif a.kind_of?(Integer) + self - Rational.new!(a, 1) + elsif a.kind_of?(Float) + Float(self) - a + else + x , y = a.coerce(self) + x - y + end + end + + def * (a) + if a.kind_of?(Rational) + num = @numerator * a.numerator + den = @denominator * a.denominator + Rational(num, den) + elsif a.kind_of?(Integer) + self * Rational.new!(a, 1) + elsif a.kind_of?(Float) + Float(self) * a + else + x , y = a.coerce(self) + x * y + end + end + + def / (a) + if a.kind_of?(Rational) + num = @numerator * a.denominator + den = @denominator * a.numerator + Rational(num, den) + elsif a.kind_of?(Integer) + self / Rational.new!(a, 1) + elsif a.kind_of?(Float) + Float(self) / a + else + x , y = a.coerce(self) + x / y + end + end + + def ** (other) + if other.kind_of?(Rational) + Float(self) ** other + elsif other.kind_of?(Integer) + if other > 0 + num = @numerator ** other + den = @denominator ** other + elsif other < 0 + num = @denominator ** -other + den = @numerator ** -other + elsif other == 0 + num = 1 + den = 1 + end + Rational.new!(num, den) + elsif other.kind_of?(Float) + Float(self) ** other + else + x , y = other.coerce(self) + x ** y + end + end + + def % (other) + value = (self / other).to_i + return self - other * value + end + + def divmod(other) + value = (self / other).to_i + return value, self - other * value + end + + def abs + if @numerator > 0 + Rational.new!(@numerator, @denominator) + else + Rational.new!(-@numerator, @denominator) + end + end + + def <=> (other) + if other.kind_of?(Rational) + num = @numerator * other.denominator + num_a = other.numerator * @denominator + v = num - num_a + if v > 0 + return 1 + elsif v < 0 + return -1 + else + return 0 + end + elsif other.kind_of?(Integer) + return self <=> Rational.new!(other, 1) + elsif other.kind_of?(Float) + return Float(self) <=> other + else + x , y = other.coerce(self) + return x <=> y + end + end + + def coerce(other) + if other.kind_of?(Float) + return other, self.to_f + elsif other.kind_of?(Integer) + return Rational.new!(other, 1), self + else + super + end + end + + def to_i + Integer(@numerator.div(@denominator)) + end + + def to_f + @numerator.to_f/@denominator.to_f + end + + def to_s + if @denominator == 1 + @numerator.to_s + else + @numerator.to_s+"/"+@denominator.to_s + end + end + + def to_r + self + end + + def hash + @numerator ^ @denominator + end + + attr :numerator + attr :denominator + + private :initialize +end + +class Integer + def numerator + self + end + + def denomerator + 1 + end + + def to_r + Rational(self, 1) + end + + def gcd(int) + a = self.abs + b = int.abs + + a, b = b, a if a < b + + while b != 0 + void, a = a.divmod(b) + a, b = b, a + end + return a + end + + def lcm(int) + a = self.abs + b = int.abs + gcd = a.gcd(b) + (a.div(gcd)) * b + end + + def gcdlcm(int) + a = self.abs + b = int.abs + gcd = a.gcd(b) + return gcd, (a.div(gcd)) * b + end + +end + +class Fixnum + alias div! /; + def div(other) + if other.kind_of?(Fixnum) + self.div!(other) + elsif other.kind_of?(Bignum) + x, y = other.coerce(self) + x.div!(y) + else + x, y = other.coerce(self) + x / y + end + end + +# alias divmod! divmod + + if not defined? Complex + alias power! **; + end + +# def rdiv(other) +# if other.kind_of?(Fixnum) +# Rational(self, other) +# elsif +# x, y = other.coerce(self) +# if defined?(x.div()) +# x.div(y) +# else +# x / y +# end +# end + # end + + def rdiv(other) + Rational.new!(self,1) / other + end + + def rpower (other) + if other >= 0 + self.power!(other) + else + Rational.new!(self,1)**other + end + end + + if not defined? Complex + alias ** rpower + end +end + +class Bignum + alias div! /; + alias div /; + alias divmod! divmod + + if not defined? power! + alias power! ** + end + + def rdiv(other) + Rational.new!(self,1) / other + end + + def rpower (other) + if other >= 0 + self.power!(other) + else + Rational.new!(self, 1)**other + end + end + + if not defined? Complex + alias ** rpower + end + +end + diff --git a/lib/safe.rb b/lib/safe.rb new file mode 100644 index 0000000000..7c95555495 --- /dev/null +++ b/lib/safe.rb @@ -0,0 +1,78 @@ +# this is a safe-mode for ruby, which is still incomplete. + +unless defined? SecurityError + class SecurityError<Exception + end +end + +module Restricted + + printf STDERR, "feel free for some warnings:\n" if $VERBOSE + module Bastion + include Restricted + extend Restricted + BINDING = binding + def Bastion.to_s; "main" end + end + + class R_File<File + NG_FILE_OP = [] + def R_File.open(*args) + raise SecurityError, "can't use File.open() in safe mode" #' + end + end + + IO = nil + File = R_File + FileTest = nil + Dir = nil + ObjectSpace = nil + + def eval(string) + begin + super(string, Bastion::BINDING) + rescue + $@ = caller + raise + end + end + module_function :eval + + DEFAULT_SECURITY_MANAGER = Object.new + + def Restricted.set_securuty_manager(sec_man) + if @sec_man + raise SecurityError, "cannot change security manager" + end + @sec_man = sec_man + end + + def Restricted.securuty_manager + return @sec_man if @sec_man + return DEFAULT_SECURITY_MANAGER + end + + for cmd in ["test", "require", "load", "open", "system"] + eval format("def DEFAULT_SECURITY_MANAGER.%s(*args) + raise SecurityError, \"can't use %s() in safe mode\" + end", cmd, cmd) #' + eval format("def %s(*args) + Restricted.securuty_manager.%s(*args) + end", cmd, cmd) + end + + def `(arg) #` + Restricted.securuty_manager.send(:`, arg) #`) + end + + def DEFAULT_SECURITY_MANAGER.`(arg) #` + raise SecurityError, "can't use backquote(``) in safe mode" + end +end + +if $DEBUG + p eval("File.open('/dev/null')") + p Restricted.eval("self") + p Restricted.eval("open('/dev/null')") + p Restricted.eval("File.open('/dev/null')") +end diff --git a/lib/thread.rb b/lib/thread.rb new file mode 100644 index 0000000000..c3347b60b4 --- /dev/null +++ b/lib/thread.rb @@ -0,0 +1,153 @@ +# +# thread.rb - thread support classes +# $Date: 1996/05/21 09:29:21 $ +# by Yukihiro Matsumoto <matz@caelum.co.jp> +# + +unless defined? Thread + fail "Thread not available for this ruby interpreter" +end + +unless defined? ThreadError + class ThreadError<Exception + end +end + +class Mutex + def initialize + @waiting = [] + @locked = FALSE; + end + + def locked? + @locked + end + + def try_lock + Thread.exclusive do + if not @locked + @locked=TRUE + return TRUE + end + end + FALSE + end + + def lock + while not try_lock + @waiting.push Thread.current + Thread.stop + end + end + + def unlock + @locked = FALSE + if w = @waiting.shift + w.run + end + end + + def synchronize + begin + lock + yield + ensure + unlock + end + end +end + +class SharedMutex<Mutex + def initialize + @locking = nil + @num_locks = 0; + super + end + def try_lock + if @locking == Thread.current + @num_locks += 1 + return TRUE + end + if super + @num_locks = 1 + @locking = Thread.current + TRUE + else + FALSE + end + end + def unlock + unless @locking == Thread.current + raise ThreadError, "cannot release shared mutex" + end + @num_locks -= 1 + if @num_locks == 0 + @locking = nil + super + end + end +end + +class Queue + def initialize + @que = [] + @waiting = [] + end + + def push(obj) + @que.push obj + if t = @waiting.shift + t.run + end + end + + def pop non_block=FALSE + if @que.length == 0 + raise ThreadError, "queue empty" if non_block + @waiting.push Thread.current + Thread.stop + end + @que.shift + end + + def empty? + @que.length == 0 + end + + def length + @que.length + end +end + +class Condition + def initialize + @waiting = [] + end + + def wait(mut) + Thread.exclusive do + mut.unlock + @waiting.push Thread.current + end + Thread.sleep + mut.lock + end + + def signal + th = nil + Thread.exclusive do + th = @waiting.pop + end + th.run + end + + def broadcast + w = @waiting + Thread.exclusive do + th = [] + end + for th in w + th.run + end + end +end @@ -3,477 +3,10 @@ # $Date: 1995/11/03 08:17:15 $ # by Yukihiro Matsumoto <matz@caelum.co.jp> -require "tkutil" - -trap "PIPE", proc{exit 0} -trap "EXIT", proc{Tk.tk_exit} - -module Tk - include TkUtil - extend Tk - - $0 =~ /\/(.*$)/ - - PORT = open(format("|%s -n %s", WISH_PATH, $1), "w+"); - def tk_write(*args) - printf PORT, *args; - PORT.print "\n" - PORT.flush - end - tk_write '\ -wm withdraw . -proc rb_out args { - puts [format %%s $args] - flush stdout -} -proc tkerror args { exit } -proc keepalive {} { rb_out alive; after 120000 keepalive} -after 120000 keepalive' - - READABLE = [] - READ_CMD = {} - - def file_readable(port, cmd) - READABLE.push port - READ_CMD[port] = cmd - end - - WRITABLE = [] - WRITE_CMD = {} - def file_writable - WRITABLE.push port - WRITE_CMD[port] = cmd - end - module_function :file_readable, :file_writable - - file_readable PORT, proc { - exit if not PORT.gets - Tk.dispatch($_.chop!) - } - - def tk_exit - PORT.print "exit\n" - PORT.close - end - - def error_at - n = 1 - while c = caller(n) - break if c !~ /tk\.rb:/ - n+=1 - end - c - end - - def tk_tcl2ruby(val) - case val - when /^-?\d+$/ - val.to_i - when /^\./ - $tk_window_list[val] - when /^rb_out (c\d+)/ - $tk_cmdtbl[$1] - when / / - val.split.collect{|elt| - tk_tcl2ruby(elt) - } - when /^-?\d+\.\d*$/ - val.to_f - else - val - end - end - - def tk_split_list(str) - idx = str.index('{') - return tk_tcl2ruby(str) if not idx - - list = tk_tcl2ruby(str[0,idx]) - str = str[idx+1..-1] - i = -1 - brace = 1 - str.each_byte {|c| - i += 1 - brace += 1 if c == ?{ - brace -= 1 if c == ?} - break if brace == 0 - } - if str[0, i] == ' ' - list.push ' ' - else - list.push tk_split_list(str[0, i]) - end - list += tk_split_list(str[i+1..-1]) - list - end - private :tk_tcl2ruby, :tk_split_list - - def bool(val) - case bool - when "1", 1, 'yes', 'true' - TRUE - else - FALSE - end - end - def number(val) - case val - when /^-?\d+$/ - val.to_i - when /^-?\d+\.\d*$/ - val.to_f - else - val - end - end - def string(val) - if val == "{}" - '' - elsif val[0] == ?{ - val[1..-2] - else - val - end - end - def list(val) - tk_split_list(val) - end - def window(val) - $tk_window_list[val] - end - def procedure(val) - if val =~ /^rb_out (c\d+)/ - $tk_cmdtbl[$1] - else - nil - end - end - private :bool, :number, :string, :list, :window, :procedure - - # mark for non-given arguments - None = Object.new - def None.to_s - 'None' - end - - $tk_event_queue = [] - def tk_call(*args) - args = args.collect{|s| - continue if s == None - if s == FALSE - s = "0" - elsif s == TRUE - s = "1" - elsif s.is_kind_of?(TkObject) - s = s.path - else - s = s.to_s - s.gsub!(/[{}]/, '\\\\\0') - end - "{#{s}}" - } - str = args.join(" ") - tk_write 'if [catch {%s} var] {puts "!$var"} {puts "=$var@@"};flush stdout', str - while PORT.gets - $_.chop! - if /^=(.*)@@$/ - val = $1 - break - elsif /^=/ - val = $' + "\n" - while TRUE - PORT.gets - fail 'wish closed' if not $_ - if ~/@@$/ - val += $' - return val - else - val += $_ - end - end - elsif /^!/ - $@ = error_at - msg = $' - if msg =~ /unknown option "-(.*)"/ - fail format("undefined method `%s' for %s(%s)'", $1, self, self.type) - else - fail format("%s - %s", self.type, msg) - end - end - $tk_event_queue.push $_ - end - - while ev = $tk_event_queue.shift - Tk.dispatch ev - end - fail 'wish closed' if not $_ -# tk_split_list(val) - val - end - - def hash_kv(keys) - conf = [] - if keys - for k, v in keys - conf.push("-#{k}") - v = install_cmd(v) if v.type == Proc - conf.push(v) - end - end - conf - end - private :tk_call, :error_at, :hash_kv - - $tk_cmdid = "c00000" - def install_cmd(cmd) - return '' if cmd == '' # uninstall cmd - id = $tk_cmdid - $tk_cmdid = $tk_cmdid.next - $tk_cmdtbl[id] = cmd - @cmdtbl = [] if not @cmdtbl - @cmdtbl.push id - return format('rb_out %s', id) - end - def uninstall_cmd(id) - $tk_cmdtbl[id] = nil - end - private :install_cmd, :uninstall_cmd - - $tk_window_list = {} - class Event - def initialize(seq,b,f,h,k,s,t,w,x,y,aa,ee,kk,nn,ww,tt,xx,yy) - @serial = seq - @num = b - @focus = (f == 1) - @height = h - @keycode = k - @state = s - @time = t - @width = w - @x = x - @y = y - @char = aa - @send_event = (ee == 1) - @keysym = kk - @keysym_num = nn - @type = tt - @widget = ww - @x_root = xx - @y_root = yy - end - attr :serial - attr :num - attr :focus - attr :height - attr :keycode - attr :state - attr :time - attr :width - attr :x - attr :y - attr :char - attr :send_event - attr :keysym - attr :keysym_num - attr :type - attr :widget - attr :x_root - attr :y_root - end - - def install_bind(cmd) - id = install_cmd(proc{|args| - TkUtil.eval_cmd cmd, Event.new(*args) - }) - id + " %# %b %f %h %k %s %t %w %x %y %A %E %K %N %W %T %X %Y" - end - - def _bind(path, context, cmd) - begin - id = install_bind(cmd) - tk_call 'bind', path, "<#{context}>", id - rescue - $tk_cmdtbl[id] = nil - fail - end - end - private :install_bind, :_bind - - def bind_all(context, cmd=Proc.new) - _bind 'all', context, cmd - end - - $tk_cmdtbl = {} - - def after(ms, cmd=Proc.new) - myid = $tk_cmdid - tk_call 'after', ms, - install_cmd(proc{ - TkUtil.eval_cmd cmd - uninstall_cmd myid - }) - end - - def update(idle=nil) - if idle - tk_call 'update', 'idletasks' - else - tk_call 'update' - end - end - - def dispatch(line) - if line =~ /^c\d+/ - cmd = $& - fail "no command `#{cmd}'" if not $tk_cmdtbl[cmd] - args = tk_split_list($') - TkUtil.eval_cmd $tk_cmdtbl[cmd], *args - elsif line =~ /^alive$/ - # keep alive, do nothing - else - fail "malformed line <#{line}>" - end - end - - def mainloop - begin - tk_write 'after idle {wm deiconify .}' - while TRUE - rf, wf = select(READABLE, WRITABLE) - for f in rf - READ_CMD[f].call(f) if READ_CMD[f] - if f.closed? - READABLE.delete f - READ_CMD[f] = nil - end - end - for f in wf - WRITE_CMD[f].call(f) if WRITE_CMD[f] - if f.closed? - WRITABLE.delete f - WRITE_CMD[f] = nil - end - end - end - rescue - exit if $! =~ /^Interrupt/ - fail - ensure - tk_exit - end - end - - def root - $tk_root - end - - module_function :after, :update, :dispatch, :mainloop, :root - - module Scrollable - def xscrollcommand(cmd) - configure_cmd 'xscrollcommand', cmd - end - def yscrollcommand(cmd) - configure_cmd 'yscrollcommand', cmd - end - end - - module Wm - def aspect(*args) - w = window(tk_call('wm', 'grid', path, *args)) - w.split.collect{|s|s.to_i} if args.length == 0 - end - def client(name=None) - tk_call 'wm', 'client', path, name - end - def colormapwindows(*args) - list(tk_call('wm', 'colormapwindows', path, *args)) - end - def wm_command(value=None) - string(tk_call('wm', 'command', path, value)) - end - def deiconify - tk_call 'wm', 'deiconify', path - end - def focusmodel(*args) - tk_call 'wm', 'focusmodel', path, *args - end - def frame - tk_call 'wm', 'frame', path - end - def geometry(*args) - list(tk_call('wm', 'geometry', path, *args)) - end - def grid(*args) - w = tk_call('wm', 'grid', path, *args) - list(w) if args.size == 0 - end - def group(*args) - tk_call 'wm', 'path', path, *args - end - def iconbitmap(*args) - tk_call 'wm', 'bitmap', path, *args - end - def iconify - tk_call 'wm', 'iconify' - end - def iconmask(*args) - tk_call 'wm', 'iconmask', path, *args - end - def iconname(*args) - tk_call 'wm', 'iconname', path, *args - end - def iconposition(*args) - w = tk_call('wm', 'iconposition', path, *args) - list(w) if args.size == 0 - end - def iconwindow(*args) - tk_call 'wm', 'iconwindow', path, *args - end - def maxsize(*args) - w = tk_call('wm', 'maxsize', path, *args) - list(w) if not args.size == 0 - end - def minsize(*args) - w = tk_call('wm', 'minsize', path, *args) - list(w) if args.size == 0 - end - def overrideredirect(bool=None) - if bool == None - bool(tk_call('wm', 'overrideredirect', path)) - else - tk_call 'wm', 'overrideredirect', path, bool - end - end - def positionfrom(*args) - tk_call 'wm', 'positionfrom', path, *args - end - def protocol(name, func=None) - func = install_cmd(func) if not func == None - tk_call 'wm', 'command', path, name, func - end - def resizable(*args) - w = tk_call('wm', 'resizable', path, *args) - if args.length == 0 - list(w).collect{|e| bool(e)} - end - end - def sizefrom(*args) - list(tk_call('wm', 'sizefrom', path, *args)) - end - def state - tk_call 'wm', 'state', path - end - def title(*args) - tk_call 'wm', 'title', path, *args - end - def transient(*args) - tk_call 'wm', 'transient', path, *args - end - def withdraw - tk_call 'wm', 'withdraw', path - end - end +if defined? Thread and $tk_thread_safe + require "tkthcore" +else + require "tkcore" end module TkSelection @@ -550,11 +83,11 @@ module TkWinfo def winfo_depth(window) TkWinfo.depth self end - def TkWinfo.exists(window) + def TkWinfo.exist?(window) bool(tk_call('winfo', 'exists', window.path)) end - def winfo_exists(window) - TkWinfo.exists self + def winfo_exist?(window) + TkWinfo.exist? self end def TkWinfo.fpixels(window, number) number(tk_call('winfo', 'fpixels', window.path, number)) @@ -580,11 +113,11 @@ module TkWinfo def winfo_id(window) TkWinfo.id self end - def TkWinfo.ismapped(window) + def TkWinfo.mapped?(window) bool(tk_call('winfo', 'ismapped', window.path)) end - def winfo_ismapped(window) - TkWinfo.ismapped self + def winfo_mapped?(window) + TkWinfo.mapped? self end def TkWinfo.parent(window) window(tk_call('winfo', 'parent', window.path)) @@ -742,7 +275,7 @@ module TkPack include Tk extend Tk def configure(win, *args) - if args[-1].is_kind_of(Hash) + if args[-1].kind_of?(Hash) keys = args.pop end wins = [win.epath] @@ -780,7 +313,7 @@ module TkOption module_function :add, :clear, :get, :readfile end -class TkObject:TkKernel +class TkObject<TkKernel include Tk def path @@ -822,16 +355,16 @@ class TkObject:TkKernel configure slot, install_cmd(value) end - def bind(context, cmd=Proc.new) - _bind path, context, cmd + def bind(context, cmd=Proc.new, args=nil) + _bind path, context, cmd, args end end -class TkWindow:TkObject +class TkWindow<TkObject $tk_window_id = "w00000" def initialize(parent=nil, keys=nil) id = $tk_window_id - $tk_window_id = $tk_window_id.next + $tk_window_id = $tk_window_id.succ if !parent or parent == Tk.root @path = format(".%s", id); else @@ -880,7 +413,7 @@ class TkWindow:TkObject return val end else - fail 'wrong # of args' + fail ArgumentError, 'wrong # of args' end end @@ -913,7 +446,7 @@ class TkWindow:TkObject end end -class TkRoot:TkWindow +class TkRoot<TkWindow include Wm def TkRoot.new return $tk_root if $tk_root @@ -926,7 +459,7 @@ class TkRoot:TkWindow $tk_window_list['.'] = $tk_root end -class TkToplevel:TkWindow +class TkToplevel<TkWindow include Wm def initialize(parent=nil, screen=nil, classname=nil) @screen = screen if screen @@ -942,20 +475,21 @@ class TkToplevel:TkWindow end end -class TkFrame:TkWindow +class TkFrame<TkWindow def create_self tk_call 'frame', @path end end -class TkLabel:TkWindow +class TkLabel<TkWindow def create_self tk_call 'label', @path end def textvariable(v) - vn = @path + v.id2name + v = v.id2name unless v.kind_of "String" + vn = @path + v vset = format("global {%s}; set {%s}", vn, vn) - tk_call vset, eval(v.id2name).inspect + tk_call vset, eval(v).inspect trace_var v, proc{|val| tk_call vset, val.inspect } @@ -963,7 +497,7 @@ class TkLabel:TkWindow end end -class TkButton:TkLabel +class TkButton<TkLabel def create_self tk_call 'button', @path end @@ -975,7 +509,7 @@ class TkButton:TkLabel end end -class TkRadioButton:TkButton +class TkRadioButton<TkButton def create_self tk_call 'radiobutton', @path end @@ -986,8 +520,13 @@ class TkRadioButton:TkButton tk_send 'select' end def variable(v) - vn = v.id2name; vn =~ /^./ - vn = 'btns_selected_' + $' + v = v.id2name unless v.kind_of "String" + if v =~ /^\$/ + v = $' + else + fail ArgumentError, "variable must be global(%s)", v + end + vn = 'btns_selected_' + v trace_var v, proc{|val| tk_call 'set', vn, val } @@ -1004,7 +543,7 @@ class TkRadioButton:TkButton end end -class TkCheckButton:TkRadioButton +class TkCheckButton<TkRadioButton def create_self tk_call 'checkbutton', @path end @@ -1013,13 +552,13 @@ class TkCheckButton:TkRadioButton end end -class TkMessage:TkLabel +class TkMessage<TkLabel def create_self tk_call 'message', @path end end -class TkScale:TkWindow +class TkScale<TkWindow def create_self tk_call 'scale', path end @@ -1041,11 +580,23 @@ class TkScale:TkWindow end end -class TkScrollbar:TkWindow +class TkScrollbar<TkWindow def create_self tk_call 'scrollbar', path end + def delta(deltax=None, deltay=None) + number(tk_send('delta', deltax, deltay)) + end + + def fraction(x=None, y=None) + number(tk_send('fraction', x, y)) + end + + def identify(x=None, y=None) + tk_send('fraction', x, y) + end + def get ary1 = tk_send('get', path).split ary2 = [] @@ -1061,7 +612,7 @@ class TkScrollbar:TkWindow end # abstract class for Text and Listbox -class TkTextWin:TkWindow +class TkTextWin<TkWindow def bbox(index) tk_send 'bbox', index end @@ -1091,7 +642,7 @@ class TkTextWin:TkWindow end end -class TkListbox:TkTextWin +class TkListbox<TkTextWin def create_self tk_call 'listbox', path end @@ -1119,7 +670,7 @@ class TkListbox:TkTextWin end end -class TkMenu:TkWindow +class TkMenu<TkWindow def create_self tk_call 'menu', path end @@ -1158,7 +709,7 @@ class TkMenu:TkWindow end end -class TkMenubutton:TkLabel +class TkMenubutton<TkLabel def create_self tk_call 'menubutton', path end @@ -1181,7 +732,7 @@ module TkComposite def delegate(option, *wins) @delegates = {} if not @delegates @delegates['DEFAULT'] = @frame - if option.is_kind_of? String + if option.kind_of? String @delegates[option] = wins else for i in option diff --git a/lib/tkcanvas.rb b/lib/tkcanvas.rb index 33b28e3eff..b0ae8b1daa 100644 --- a/lib/tkcanvas.rb +++ b/lib/tkcanvas.rb @@ -5,12 +5,12 @@ require "tk" -class TkCanvas:TkWindow +class TkCanvas<TkWindow def create_self tk_call 'canvas', path end def tagid(tag) - if tag.is_kind_of?(TkcItem) + if tag.kind_of?(TkcItem) tag.id else tag @@ -89,6 +89,9 @@ class TkCanvas:TkWindow def move(tag, x, y) tk_send 'move', tagid(tag), x, y end + def itemtype(tag) + tk_send 'type', tagid(tag) + end def postscript(keys=None) tk_call "pack", *hash_kv(keys) end @@ -115,9 +118,9 @@ class TkCanvas:TkWindow end end -class TkcItem:TkObject +class TkcItem<TkObject def initialize(parent, *args) - if not parent.is_kind_of?(TkCanvas) + if not parent.kind_of?(TkCanvas) fail format("%s need to be TkCanvas", parent.inspect) end @c = parent @@ -137,7 +140,7 @@ class TkcItem:TkObject end def configure(slot, value) - tk_call path, 'itemconfigure', id, "-#{slot}", value + tk_call path, 'itemconfigure', @id, "-#{slot}", value end def addtag(tag) @@ -185,59 +188,59 @@ class TkcItem:TkObject def scale(xorigin, yorigin, xscale, yscale) @c.scale @id, xorigin, yorigin, xscale, yscale end - def type - @c.type @id + def itemtype + @c.itemtype @id end def destroy tk_call path, 'delete', @id end end -class TkcArc:TkcItem +class TkcArc<TkcItem def create_self(*args) tk_call(@path, 'create', 'arc', *args) end end -class TkcBitmap:TkcItem +class TkcBitmap<TkcItem def create_self(*args) tk_call(@path, 'create', 'bitmap', *args) end end -class TkcImage:TkcItem +class TkcImage<TkcItem def create_self(*args) tk_call(@path, 'create', 'image', *args) end end -class TkcLine:TkcItem +class TkcLine<TkcItem def create_self(*args) tk_call(@path, 'create', 'line', *args) end end -class TkcOval:TkcItem +class TkcOval<TkcItem def create_self(*args) tk_call(@path, 'create', 'oval', *args) end end -class TkcPolygon:TkcItem +class TkcPolygon<TkcItem def create_self(*args) tk_call(@path, 'create', 'polygon', *args) end end -class TkcText:TkcItem +class TkcText<TkcItem def create_self(*args) tk_call(@path, 'create', 'text', *args) end end -class TkcWindow:TkcItem +class TkcWindow<TkcItem def create_self(*args) tk_call(@path, 'create', 'window', *args) end end -class TkcGroup:TkcItem +class TkcGroup<TkcItem $tk_group_id = 'tkg00000' def create_self(*args) @id = $tk_group_id - $tk_group_id = $tk_group_id.next + $tk_group_id = $tk_group_id.succ end def add(*tags) @@ -262,20 +265,20 @@ class TkcGroup:TkcItem end -class TkImage:TkObject +class TkImage<TkObject include Tk $tk_image_id = 'i00000' def initialize(keys=nil) @path = $tk_image_id - $tk_image_id = $tk_image_id.next + $tk_image_id = $tk_image_id.succ tk_call 'image', @type, @path, *hash_kv(keys) end def height number(tk_call('image', 'height', @path)) end - def type + def itemtype tk_call('image', 'type', @path) end def width @@ -290,14 +293,14 @@ class TkImage:TkObject end end -class TkBitmapImage:TkImage +class TkBitmapImage<TkImage def initialize(*args) @type = 'bitmap' super end end -class TkPhotoImage:TkImage +class TkPhotoImage<TkImage def initialize(*args) @type = 'bitmap' super diff --git a/lib/tkcore.rb b/lib/tkcore.rb new file mode 100644 index 0000000000..df4af669ba --- /dev/null +++ b/lib/tkcore.rb @@ -0,0 +1,521 @@ +# +# tkcore.rb - Tk interface modue without thread +# $Date: 1996/11/09 22:51:15 $ +# by Yukihiro Matsumoto <matz@caelum.co.jp> + +require "tkutil" +if defined? Thread + require "thread" +end + +module Tk + include TkUtil + extend Tk + + wish_path = nil + ENV['PATH'].split(":").each {|path| + for wish in ['wish4.2', 'wish4.1', 'wish4.0', 'wish'] + if File.exist? path+'/'+wish + wish_path = path+'/'+wish + break + end + break if wish_path + end + } + fail 'can\'t find wish' if not wish_path + + def Tk.tk_exit + if not PORT.closed? + PORT.print "exit\n" + PORT.close + end + end + + PORT = open(format("|%s -n %s", wish_path, File.basename($0)), "w+"); + trap "EXIT", proc{Tk.tk_exit} + trap "PIPE", "" + + def tk_write(*args) + printf PORT, *args; + PORT.print "\n" + PORT.flush + end + tk_write '\ +wm withdraw . +proc rb_out args { + puts [format %%s $args] + flush stdout +} +proc rb_ans args { + if [catch "$args" var] {puts "!$var"} {puts "=$var@@"} + flush stdout +} +proc tkerror args { exit } +proc keepalive {} { rb_out alive; after 120000 keepalive} +after 120000 keepalive' + + READABLE = [] + READ_CMD = {} + + def file_readable(port, cmd) + if cmd == nil + READABLE.delete port + else + READABLE.push port + end + READ_CMD[port] = cmd + end + + WRITABLE = [] + WRITE_CMD = {} + def file_writable(port, cmd) + if cmd == nil + WRITABLE.delete port + else + WRITABLE.push port + end + WRITE_CMD[port] = cmd + end + module_function :file_readable, :file_writable + + file_readable PORT, proc { + line = PORT.gets + exit if not line + Tk.dispatch(line.chop!) + } + + def error_at + n = 1 + while c = caller(n) + break if c !~ /tk\.rb:/ + n+=1 + end + c + end + + def tk_tcl2ruby(val) + case val + when /^-?\d+$/ + val.to_i + when /^\./ + $tk_window_list[val] + when /^rb_out (c\d+)/ + $tk_cmdtbl[$1] + when / / + val.split.collect{|elt| + tk_tcl2ruby(elt) + } + when /^-?\d+\.\d*$/ + val.to_f + else + val + end + end + + def tk_split_list(str) + idx = str.index('{') + return tk_tcl2ruby(str) if not idx + + list = tk_tcl2ruby(str[0,idx]) + str = str[idx+1..-1] + i = -1 + brace = 1 + str.each_byte {|c| + i += 1 + brace += 1 if c == ?{ + brace -= 1 if c == ?} + break if brace == 0 + } + if str[0, i] == ' ' + list.push ' ' + else + list.push tk_split_list(str[0, i]) + end + list += tk_split_list(str[i+1..-1]) + list + end + private :tk_tcl2ruby, :tk_split_list + + def bool(val) + case bool + when "1", 1, 'yes', 'true' + TRUE + else + FALSE + end + end + def number(val) + case val + when /^-?\d+$/ + val.to_i + when /^-?\d+\.\d*$/ + val.to_f + else + val + end + end + def string(val) + if val == "{}" + '' + elsif val[0] == ?{ + val[1..-2] + else + val + end + end + def list(val) + tk_split_list(val) + end + def window(val) + $tk_window_list[val] + end + def procedure(val) + if val =~ /^rb_out (c\d+)/ + $tk_cmdtbl[$1] + else + nil + end + end + private :bool, :number, :string, :list, :window, :procedure + + # mark for non-given arguments + None = Object.new + def None.to_s + 'None' + end + + $tk_event_queue = [] + def tk_call(*args) + args = args.collect{|s| + next if s == None + if s.kind_of?(Hash) + s = hash_kv(s).join(" ") + else + if not s + s = "0" + elsif s == TRUE + s = "1" + elsif s.kind_of?(TkObject) + s = s.path + else + s = s.to_s + s.gsub!(/[{}]/, '\\\\\0') + end + "{#{s}}" + end + } + str = args.join(" ") + print str, "\n" if $DEBUG + tk_write 'rb_ans %s', str + while PORT.gets + print $_ if $DEBUG + $_.chop! + if /^=(.*)@@$/ + val = $1 + break + elsif /^=/ + val = $' + "\n" + while TRUE + PORT.readline + if ~/@@$/ + val += $' + return val + else + val += $_ + end + end + elsif /^!/ + $@ = error_at + msg = $' + if msg =~ /unknown option "-(.*)"/ + fail NameError, format("undefined method `%s' for %s(%s)", $1, self, self.type) #`' + else + fail format("%s - %s", self.type, msg) + end + end + $tk_event_queue.push $_ + end + + while ev = $tk_event_queue.shift + Tk.dispatch ev + end + fail 'wish closed' if PORT.closed? +# tk_split_list(val) + val + end + + def hash_kv(keys) + conf = [] + if keys + for k, v in keys + conf.push("-#{k}") + v = install_cmd(v) if v.type == Proc + conf.push(v) + end + end + conf + end + private :tk_call, :error_at, :hash_kv + + $tk_cmdid = 0 + def install_cmd(cmd) + return '' if cmd == '' # uninstall cmd + id = format("c%.4d", $tk_cmdid) + $tk_cmdid += 1 + $tk_cmdtbl[id] = cmd + @cmdtbl = [] if not @cmdtbl + @cmdtbl.push id + return format('rb_out %s', id) + end + def uninstall_cmd(id) + $tk_cmdtbl[id] = nil + end + private :install_cmd, :uninstall_cmd + + $tk_window_list = {} + class Event + def initialize(seq,b,f,h,k,s,t,w,x,y,aa,ee,kk,nn,ww,tt,xx,yy) + @serial = seq + @num = b + @focus = (f == 1) + @height = h + @keycode = k + @state = s + @time = t + @width = w + @x = x + @y = y + @char = aa + @send_event = (ee == 1) + @keysym = kk + @keysym_num = nn + @type = tt + @widget = ww + @x_root = xx + @y_root = yy + end + attr :serial + attr :num + attr :focus + attr :height + attr :keycode + attr :state + attr :time + attr :width + attr :x + attr :y + attr :char + attr :send_event + attr :keysym + attr :keysym_num + attr :type + attr :widget + attr :x_root + attr :y_root + end + + def install_bind(cmd, args=nil) + if args + id = install_cmd(proc{|arg| + TkUtil.eval_cmd cmd, *arg + }) + id + " " + args + else + id = install_cmd(proc{|arg| + TkUtil.eval_cmd cmd, Event.new(*arg) + }) + id + " %# %b %f %h %k %s %t %w %x %y %A %E %K %N %W %T %X %Y" + end + end + + def _bind(path, context, cmd, args=nil) + begin + id = install_bind(cmd, args) + tk_call 'bind', path, "<#{context}>", id + rescue + $tk_cmdtbl[id] = nil + fail + end + end + private :install_bind, :_bind + + def bind_all(context, cmd=Proc.new, args=nil) + _bind 'all', context, cmd, args + end + + def pack(*args) + TkPack.configure *args + end + + $tk_cmdtbl = {} + + def after(ms, cmd=Proc.new) + myid = format("c%.4d", $tk_cmdid) + tk_call 'after', ms, + install_cmd(proc{ + TkUtil.eval_cmd cmd + uninstall_cmd myid + }) + end + + def update(idle=nil) + if idle + tk_call 'update', 'idletasks' + else + tk_call 'update' + end + end + + def dispatch(line) + if line =~ /^c\d+/ + cmd = $& + fail "no command `#{cmd}'" if not $tk_cmdtbl[cmd] + args = tk_split_list($') + TkUtil.eval_cmd $tk_cmdtbl[cmd], *args + elsif line =~ /^alive$/ + # keep alive, do nothing + else + fail "malformed line <#{line}>" + end + end + + def mainloop + begin + tk_write 'after idle {wm deiconify .}' + while TRUE + rf, wf = select(READABLE, WRITABLE) + for f in rf + READ_CMD[f].call(f) if READ_CMD[f] + if f.closed? + READABLE.delete f + READ_CMD[f] = nil + end + end + for f in wf + WRITE_CMD[f].call(f) if WRITE_CMD[f] + if f.closed? + WRITABLE.delete f + WRITE_CMD[f] = nil + end + end + end + ensure + Tk.tk_exit + end + end + + def root + $tk_root + end + + def bell + tk_call 'bell' + end + module_function :after, :update, :dispatch, :mainloop, :root, :bell + + module Scrollable + def xscrollcommand(cmd) + configure_cmd 'xscrollcommand', cmd + end + def yscrollcommand(cmd) + configure_cmd 'yscrollcommand', cmd + end + end + + module Wm + def aspect(*args) + w = window(tk_call('wm', 'grid', path, *args)) + w.split.collect{|s|s.to_i} if args.length == 0 + end + def client(name=None) + tk_call 'wm', 'client', path, name + end + def colormapwindows(*args) + list(tk_call('wm', 'colormapwindows', path, *args)) + end + def wm_command(value=None) + string(tk_call('wm', 'command', path, value)) + end + def deiconify + tk_call 'wm', 'deiconify', path + end + def focusmodel(*args) + tk_call 'wm', 'focusmodel', path, *args + end + def frame + tk_call 'wm', 'frame', path + end + def geometry(*args) + list(tk_call('wm', 'geometry', path, *args)) + end + def grid(*args) + w = tk_call('wm', 'grid', path, *args) + list(w) if args.size == 0 + end + def group(*args) + tk_call 'wm', 'path', path, *args + end + def iconbitmap(*args) + tk_call 'wm', 'bitmap', path, *args + end + def iconify + tk_call 'wm', 'iconify' + end + def iconmask(*args) + tk_call 'wm', 'iconmask', path, *args + end + def iconname(*args) + tk_call 'wm', 'iconname', path, *args + end + def iconposition(*args) + w = tk_call('wm', 'iconposition', path, *args) + list(w) if args.size == 0 + end + def iconwindow(*args) + tk_call 'wm', 'iconwindow', path, *args + end + def maxsize(*args) + w = tk_call('wm', 'maxsize', path, *args) + list(w) if not args.size == 0 + end + def minsize(*args) + w = tk_call('wm', 'minsize', path, *args) + list(w) if args.size == 0 + end + def overrideredirect(bool=None) + if bool == None + bool(tk_call('wm', 'overrideredirect', path)) + else + tk_call 'wm', 'overrideredirect', path, bool + end + end + def positionfrom(*args) + tk_call 'wm', 'positionfrom', path, *args + end + def protocol(name, func=None) + func = install_cmd(func) if not func == None + tk_call 'wm', 'command', path, name, func + end + def resizable(*args) + w = tk_call('wm', 'resizable', path, *args) + if args.length == 0 + list(w).collect{|e| bool(e)} + end + end + def sizefrom(*args) + list(tk_call('wm', 'sizefrom', path, *args)) + end + def state + tk_call 'wm', 'state', path + end + def title(*args) + tk_call 'wm', 'title', path, *args + end + def transient(*args) + tk_call 'wm', 'transient', path, *args + end + def withdraw + tk_call 'wm', 'withdraw', path + end + end +end diff --git a/lib/tkentry.rb b/lib/tkentry.rb index dbd848d0ca..9a03c34058 100644 --- a/lib/tkentry.rb +++ b/lib/tkentry.rb @@ -5,7 +5,7 @@ require 'tk.rb' -class TkEntry:TkLabel +class TkEntry<TkLabel def create_self tk_call 'entry', @path end diff --git a/lib/tkscrollbox.rb b/lib/tkscrollbox.rb new file mode 100644 index 0000000000..b8dbe9b236 --- /dev/null +++ b/lib/tkscrollbox.rb @@ -0,0 +1,27 @@ +# +# tkscrollbox.rb - Tk Listbox with Scrollbar +# as an example of Composite Widget +# $Date: 1995/12/12 18:21:01 $ +# by Yukihiro Matsumoto <matz@caelum.co.jp> + +require 'tk.rb' + +class TkScrollbox<TkListbox + include TkComposite + def initialize_composite + list = TkListbox.new(@frame) + scroll = TkScrollbar.new(@frame) + @path = list.path + + list.configure 'yscroll', scroll.path+" set" + list.pack 'side'=>'left','fill'=>'both','expand'=>'yes' + scroll.configure 'command', list.path+" yview" + scroll.pack 'side'=>'right','fill'=>'y' + + delegate('DEFALUT', list) + delegate('foreground', list, scroll) + delegate('background', list, scroll) + delegate('borderwidth', @frame) + delegate('relief', @frame) + end +end diff --git a/lib/tktext.rb b/lib/tktext.rb index e7a2be950f..55e396c497 100644 --- a/lib/tktext.rb +++ b/lib/tktext.rb @@ -5,7 +5,7 @@ require 'tk.rb' -class TkText:TkTextWin +class TkText<TkTextWin include Scrollable def create_self tk_call 'text', @path @@ -77,16 +77,16 @@ class TkText:TkTextWin end end -class TkTextTag:TkObject +class TkTextTag<TkObject $tk_text_tag = 'tag0000' def initialize(parent) - if not parent.is_kind_of?(TkText) + if not parent.kind_of?(TkText) fail format("%s need to be TkText", parent.inspect) end @t = parent @path = parent.path @id = $tk_text_tag - $tk_text_tag = $tk_text_tag.next + $tk_text_tag = $tk_text_tag.succ @t._addtag id, self end def id @@ -116,16 +116,16 @@ class TkTextTag:TkObject end end -class TkTextMark:TkObject +class TkTextMark<TkObject $tk_text_mark = 'mark0000' def initialize(parent, index) - if not parent.is_kind_of?(TkText) + if not parent.kind_of?(TkText) fail format("%s need to be TkText", parent.inspect) end @t = parent @path = parent.path @id = $tk_text_mark - $tk_text_mark = $tk_text_mark.next + $tk_text_mark = $tk_text_mark.succ tk_call @t, 'set', @id, index @t._addtag id, self end @@ -143,9 +143,9 @@ class TkTextMark:TkObject alias destroy unset end -class TkTextWindow:TkObject +class TkTextWindow<TkObject def initialize(parent, index, *args) - if not parent.is_kind_of?(TkText) + if not parent.kind_of?(TkText) fail format("%s need to be TkText", parent.inspect) end @t = parent diff --git a/lib/tkthcore.rb b/lib/tkthcore.rb new file mode 100644 index 0000000000..adbad775d0 --- /dev/null +++ b/lib/tkthcore.rb @@ -0,0 +1,546 @@ +# +# tkthcore.rb - Tk interface modue using thread +# $Date: 1996/11/09 22:49:15 $ +# by Yukihiro Matsumoto <matz@caelum.co.jp> + +require "tkutil" +require "thread" + +module Tk + include TkUtil + extend Tk + + def Tk.tk_exit + if not PORT.closed? + tk_write "exit" + PORT.close + end + end + + trap "EXIT", proc{Tk.tk_exit} + trap "PIPE", '' + + wish_path = nil + ENV['PATH'].split(":").each {|path| + for wish in ['wish4.2', 'wish4.1', 'wish4.0', 'wish'] + if File.exist? path+'/'+wish + wish_path = path+'/'+wish + break + end + break if wish_path + end + } + fail 'can\'t find wish' if not wish_path + + # mark for non-given arguments + None = Object.new + def None.to_s + 'None' + end + + Qin = Queue.new + Qout = Queue.new + Qwish = Queue.new + Qcmd = Queue.new + PORT = open(format("|%s -n %s", wish_path, File.basename($0)), "w+"); + + $tk_not_init = TRUE + + def Tk.init + $tk_not_init = FALSE + Thread.start do + loop do + while line = PORT.gets + line.chop! + if line =~ /^[=!]/ + Qwish.push line + else + Qcmd.push line + end + end + exit + end + end + + Thread.start do + ary = [PORT] + loop do + str = Qin.pop + print str, "\n" if $DEBUG + tk_write 'if [catch {%s} var] {puts "!$var"} {puts "=$var@@"};flush stdout', str + Qout.push(tk_recv) + end + end + end + + $tk_event_queue = [] + def tk_recv() + val = nil + $_ = Qwish.pop + loop do + if /^=(.*)@@$/ + val = $1 + break + elsif /^=/ + val = $' + "\n" + while TRUE + PORT.readline + if ~/@@$/ + val += $' + return val + else + v>al += $_ + end + end + elsif /^!/ + $@ = error_at + msg = $' + if msg =~ /unknown option "-(.*)"/ + fail NameError, format("undefined method `%s' for %s(%s)", $1, self, self.type) #`' + else + fail format("%s - %s", self.type, msg) + end + end + Qcmd.push line + end + + fail 'wish closed' if PORT.closed? +# tk_split_list(val) + val + end + + def tk_call(*args) + Tk.init if $tk_not_init + args = args.collect{|s| + next if s == None + if s.kind_of?(Hash) + s = hash_kv(s).join(" ") + else + if not s + s = "0" + elsif s == TRUE + s = "1" + elsif s.kind_of?(TkObject) + s = s.path + else + s = s.to_s + s.gsub!(/[{}]/, '\\\\\0') + end + "{#{s}}" + end + } + str = args.join(" ") + Qin.push str + return Qout.pop + end + + def tk_write(*args) + PORT.printf *args; PORT.print "\n" + PORT.flush + end + module_function :tk_write, :tk_recv + tk_write '\ +wm withdraw . +proc rb_out args { + puts [format %%s $args] + flush stdout +} +proc tkerror args { exit } +proc keepalive {} { rb_out alive; after 120000 keepalive} +after 120000 keepalive' + + READ_TH = {} + def file_readable(port, cmd) + if cmd == nil + if READ_TH[port].has_key? + READ_TH[port].exit + READ_TH[port] = nil + end + else + READ_TH[port] = Thread.start{ + loop do + TkUtil.eval_cmd cmd + end + } + end + end + + WRITE_TH = {} + def file_writable(port, cmd) + if cmd == nil + if WRITE_TH[port].has_key? + WRITE_TH[port].exit + end + else + WRITE_TH[port] = Thread.start{ + loop do + TkUtil.eval_cmd cmd + end + } + end + end + module_function :file_readable, :file_writable + + def tk_tcl2ruby(val) + case val + when /^-?\d+$/ + val.to_i + when /^\./ + $tk_window_list[val] + when /^rb_out (c\d+)/ + $tk_cmdtbl[$1] + when / / + val.split.collect{|elt| + tk_tcl2ruby(elt) + } + when /^-?\d+\.\d*$/ + val.to_f + else + val + end + end + + def tk_split_list(str) + idx = str.index('{') + return tk_tcl2ruby(str) if not idx + + list = tk_tcl2ruby(str[0,idx]) + str = str[idx+1..-1] + i = -1 + brace = 1 + str.each_byte {|c| + i += 1 + brace += 1 if c == ?{ + brace -= 1 if c == ?} + break if brace == 0 + } + if str[0, i] == ' ' + list.push ' ' + else + list.push tk_split_list(str[0, i]) + end + list += tk_split_list(str[i+1..-1]) + list + end + private :tk_tcl2ruby, :tk_split_list + + def dispatch(line) + if line =~ /^c\d+/ + cmd = $& + fail "no command `#{cmd}'" if not $tk_cmdtbl[cmd] + args = tk_split_list($') + TkUtil.eval_cmd $tk_cmdtbl[cmd], *args + elsif line =~ /^alive$/ + # keep alive, do nothing + else + fail "malformed line <#{line}>" + end + end + module_function :dispatch + + def error_at + n = 1 + while c = caller(n) + break if c !~ /tk\.rb:/ + n+=1 + end + c + end + + def bool(val) + case bool + when "1", 1, 'yes', 'true' + TRUE + else + FALSE + end + end + def number(val) + case val + when /^-?\d+$/ + val.to_i + when /^-?\d+\.\d*$/ + val.to_f + else + val + end + end + def string(val) + if val == "{}" + '' + elsif val[0] == ?{ + val[1..-2] + else + val + end + end + def list(val) + tk_split_list(val) + end + def window(val) + $tk_window_list[val] + end + def procedure(val) + if val =~ /^rb_out (c\d+)/ + $tk_cmdtbl[$1] + else + nil + end + end + private :bool, :number, :string, :list, :window, :procedure + + def hash_kv(keys) + conf = [] + if keys + for k, v in keys + conf.push("-#{k}") + v = install_cmd(v) if v.type == Proc + conf.push(v) + end + end + conf + end + private :tk_call, :error_at, :hash_kv + + $tk_cmdid = 0 + def install_cmd(cmd) + return '' if cmd == '' # uninstall cmd + id = format("c%.4d", $tk_cmdid) + $tk_cmdid += 1 + $tk_cmdtbl[id] = cmd + @cmdtbl = [] if not @cmdtbl + @cmdtbl.push id + return format('rb_out %s', id) + end + def uninstall_cmd(id) + $tk_cmdtbl[id] = nil + end + private :install_cmd, :uninstall_cmd + + $tk_window_list = {} + class Event + def initialize(seq,b,f,h,k,s,t,w,x,y,aa,ee,kk,nn,ww,tt,xx,yy) + @serial = seq + @num = b + @focus = (f == 1) + @height = h + @keycode = k + @state = s + @time = t + @width = w + @x = x + @y = y + @char = aa + @send_event = (ee == 1) + @keysym = kk + @keysym_num = nn + @type = tt + @widget = ww + @x_root = xx + @y_root = yy + end + attr :serial + attr :num + attr :focus + attr :height + attr :keycode + attr :state + attr :time + attr :width + attr :x + attr :y + attr :char + attr :send_event + attr :keysym + attr :keysym_num + attr :type + attr :widget + attr :x_root + attr :y_root + end + + def install_bind(cmd, args=nil) + if args + id = install_cmd(proc{|arg| + TkUtil.eval_cmd cmd, *arg + }) + id + " " + args + else + id = install_cmd(proc{|arg| + TkUtil.eval_cmd cmd, Event.new(*arg) + }) + id + " %# %b %f %h %k %s %t %w %x %y %A %E %K %N %W %T %X %Y" + end + end + + def _bind(path, context, cmd, args=nil) + begin + id = install_bind(cmd, args) + tk_call 'bind', path, "<#{context}>", id + rescue + $tk_cmdtbl[id] = nil + fail + end + end + private :install_bind, :_bind + + def bind_all(context, cmd=Proc.new, args=nil) + _bind 'all', context, cmd, args + end + + def pack(*args) + TkPack.configure *args + end + + $tk_cmdtbl = {} + + Qafter = Queue.new + def after(ms, cmd=Proc.new) + unless $tk_after_thread + $tk_after_thread = Thread.start{ + loop do + cmd = Qafter.pop + TkUtil.eval_cmd cmd + end + } + end + Thread.start do + sleep Float(ms)/1000 + Qafter.push cmd + end + end + + def update(idle=nil) + if idle + tk_call 'update', 'idletasks' + else + tk_call 'update' + end + end + + def root + $tk_root + end + + def bell + tk_call 'bell' + end + + def mainloop + begin + tk_call 'after', 'idle', 'wm deiconify .' + loop do + dispatch Qcmd.pop + end + ensure + Tk.tk_exit + end + end + module_function :after, :update, :dispatch, :mainloop, :root, :bell + + module Scrollable + def xscrollcommand(cmd) + configure_cmd 'xscrollcommand', cmd + end + def yscrollcommand(cmd) + configure_cmd 'yscrollcommand', cmd + end + end + + module Wm + def aspect(*args) + w = window(tk_call('wm', 'grid', path, *args)) + w.split.collect{|s|s.to_i} if args.length == 0 + end + def client(name=None) + tk_call 'wm', 'client', path, name + end + def colormapwindows(*args) + list(tk_call('wm', 'colormapwindows', path, *args)) + end + def wm_command(value=None) + string(tk_call('wm', 'command', path, value)) + end + def deiconify + tk_call 'wm', 'deiconify', path + end + def focusmodel(*args) + tk_call 'wm', 'focusmodel', path, *args + end + def frame + tk_call 'wm', 'frame', path + end + def geometry(*args) + list(tk_call('wm', 'geometry', path, *args)) + end + def grid(*args) + w = tk_call('wm', 'grid', path, *args) + list(w) if args.size == 0 + end + def group(*args) + tk_call 'wm', 'path', path, *args + end + def iconbitmap(*args) + tk_call 'wm', 'bitmap', path, *args + end + def iconify + tk_call 'wm', 'iconify' + end + def iconmask(*args) + tk_call 'wm', 'iconmask', path, *args + end + def iconname(*args) + tk_call 'wm', 'iconname', path, *args + end + def iconposition(*args) + w = tk_call('wm', 'iconposition', path, *args) + list(w) if args.size == 0 + end + def iconwindow(*args) + tk_call 'wm', 'iconwindow', path, *args + end + def maxsize(*args) + w = tk_call('wm', 'maxsize', path, *args) + list(w) if not args.size == 0 + end + def minsize(*args) + w = tk_call('wm', 'minsize', path, *args) + list(w) if args.size == 0 + end + def overrideredirect(bool=None) + if bool == None + bool(tk_call('wm', 'overrideredirect', path)) + else + tk_call 'wm', 'overrideredirect', path, bool + end + end + def positionfrom(*args) + tk_call 'wm', 'positionfrom', path, *args + end + def protocol(name, func=None) + func = install_cmd(func) if not func == None + tk_call 'wm', 'command', path, name, func + end + def resizable(*args) + w = tk_call('wm', 'resizable', path, *args) + if args.length == 0 + list(w).collect{|e| bool(e)} + end + end + def sizefrom(*args) + list(tk_call('wm', 'sizefrom', path, *args)) + end + def state + tk_call 'wm', 'state', path + end + def title(*args) + tk_call 'wm', 'title', path, *args + end + def transient(*args) + tk_call 'wm', 'transient', path, *args + end + def withdraw + tk_call 'wm', 'withdraw', path + end + end +end |