summaryrefslogtreecommitdiff
path: root/sample/drb/dcdbiff.rb
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2019-08-12 15:13:09 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2019-08-12 15:14:01 +0900
commit0d0ff8277fcea4584aa33b8b180a4ade7b90590e (patch)
tree442a19169a7bb251ec53a7141bf4fb6164541aea /sample/drb/dcdbiff.rb
parentb1ef14176b3716e3900672a9563b94aa3abedb2d (diff)
rb_trap_exec has been removed since 1.9
Diffstat (limited to 'sample/drb/dcdbiff.rb')
0 files changed, 0 insertions, 0 deletions
td class='graph'>
-rw-r--r--README6
-rw-r--r--README.EXT97
-rw-r--r--README.EXT.ja6
-rw-r--r--README.ja6
-rw-r--r--array.c1174
-rw-r--r--bcc32/Makefile.sub87
-rwxr-xr-xbcc32/configure.bat92
-rwxr-xr-x[-rw-r--r--]bcc32/mkexports.rb2
-rw-r--r--bcc32/setup.mak78
-rw-r--r--bignum.c579
-rw-r--r--bin/irb4
-rw-r--r--bin/rdoc2
-rw-r--r--class.c57
-rw-r--r--common.mk264
-rw-r--r--compar.c4
-rw-r--r--configure.in484
-rw-r--r--cygwin/GNUmakefile.in2
-rw-r--r--defines.h44
-rw-r--r--dir.c1346
-rw-r--r--dln.c90
-rw-r--r--dln.h4
-rw-r--r--doc/NEWS-1.8.0 (renamed from doc/NEWS)0
-rw-r--r--doc/forwardable.rd4
-rw-r--r--doc/forwardable.rd.ja4
-rw-r--r--doc/irb/irb-tools.rd.ja4
-rw-r--r--doc/irb/irb.rd4
-rw-r--r--doc/irb/irb.rd.ja4
-rw-r--r--doc/shell.rd4
-rw-r--r--doc/shell.rd.ja4
-rw-r--r--enum.c1254
-rw-r--r--enumerator.c450
-rw-r--r--env.h4
-rw-r--r--error.c41
-rw-r--r--eval.c1957
-rw-r--r--ext/Setup1
-rw-r--r--ext/Setup.atheos1
-rw-r--r--ext/Setup.dj1
-rw-r--r--ext/Setup.emx1
-rw-r--r--ext/Setup.nt1
-rw-r--r--ext/Setup.x681
-rw-r--r--ext/Win32API/lib/win32/registry.rb2
-rw-r--r--ext/Win32API/lib/win32/resolv.rb2
-rw-r--r--ext/bigdecimal/bigdecimal.c267
-rw-r--r--ext/bigdecimal/bigdecimal.h12
-rw-r--r--ext/bigdecimal/bigdecimal_en.html9
-rw-r--r--ext/bigdecimal/bigdecimal_ja.html7
-rw-r--r--ext/bigdecimal/extconf.rb8
-rw-r--r--ext/curses/curses.c36
-rw-r--r--ext/curses/extconf.rb2
-rw-r--r--ext/dbm/dbm.c6
-rw-r--r--ext/dbm/extconf.rb60
-rw-r--r--ext/digest/bubblebabble/.cvsignore (renamed from ext/enumerator/.cvsignore)1
-rw-r--r--ext/digest/bubblebabble/bubblebabble.c142
-rw-r--r--ext/digest/bubblebabble/depend3
-rw-r--r--ext/digest/bubblebabble/extconf.rb6
-rw-r--r--ext/digest/defs.h10
-rw-r--r--ext/digest/digest.c707
-rw-r--r--ext/digest/digest.h30
-rw-r--r--ext/digest/digest.txt113
-rw-r--r--ext/digest/digest.txt.ja111
-rw-r--r--ext/digest/extconf.rb6
-rw-r--r--ext/digest/lib/digest.rb50
-rw-r--r--ext/digest/lib/md5.rb19
-rw-r--r--ext/digest/lib/sha1.rb19
-rw-r--r--ext/digest/md5/extconf.rb4
-rw-r--r--ext/digest/md5/md5.c28
-rw-r--r--ext/digest/md5/md5.h11
-rw-r--r--ext/digest/md5/md5init.c25
-rw-r--r--ext/digest/md5/md5ossl.c25
-rw-r--r--ext/digest/md5/md5ossl.h7
-rw-r--r--ext/digest/rmd160/depend2
-rw-r--r--ext/digest/rmd160/extconf.rb6
-rw-r--r--ext/digest/rmd160/rmd160.c11
-rw-r--r--ext/digest/rmd160/rmd160.h18
-rw-r--r--ext/digest/rmd160/rmd160hl.c96
-rw-r--r--ext/digest/rmd160/rmd160init.c28
-rw-r--r--ext/digest/rmd160/rmd160ossl.c43
-rw-r--r--ext/digest/rmd160/rmd160ossl.h6
-rw-r--r--ext/digest/sha1/depend2
-rw-r--r--ext/digest/sha1/extconf.rb6
-rw-r--r--ext/digest/sha1/sha1.c24
-rw-r--r--ext/digest/sha1/sha1.h19
-rw-r--r--ext/digest/sha1/sha1hl.c102
-rw-r--r--ext/digest/sha1/sha1init.c32
-rw-r--r--ext/digest/sha1/sha1ossl.c43
-rw-r--r--ext/digest/sha1/sha1ossl.h9
-rw-r--r--ext/digest/sha2/depend2
-rw-r--r--ext/digest/sha2/extconf.rb5
-rw-r--r--ext/digest/sha2/lib/sha2.rb73
-rw-r--r--ext/digest/sha2/sha2.c26
-rw-r--r--ext/digest/sha2/sha2.h38
-rw-r--r--ext/digest/sha2/sha2hl.c252
-rw-r--r--ext/digest/sha2/sha2init.c25
-rw-r--r--ext/digest/test.sh7
-rw-r--r--ext/dl/dl.c18
-rw-r--r--ext/dl/dl.h2
-rw-r--r--ext/dl/h2rb2
-rw-r--r--ext/dl/handle.c6
-rw-r--r--ext/dl/lib/dl/import.rb4
-rw-r--r--ext/dl/ptr.c40
-rw-r--r--ext/dl/sym.c3
-rw-r--r--ext/enumerator/enumerator.c298
-rw-r--r--ext/enumerator/enumerator.txt102
-rw-r--r--ext/enumerator/extconf.rb2
-rw-r--r--ext/etc/etc.c6
-rw-r--r--ext/extmk.rb108
-rw-r--r--ext/fcntl/fcntl.c2
-rw-r--r--ext/gdbm/gdbm.c444
-rw-r--r--ext/iconv/iconv.c94
-rw-r--r--ext/io/wait/extconf.rb2
-rw-r--r--ext/io/wait/wait.c8
-rw-r--r--ext/nkf/lib/kconv.rb10
-rw-r--r--ext/nkf/nkf-utf8/nkf.c1111
-rw-r--r--ext/nkf/nkf-utf8/utf8tbl.c2
-rw-r--r--ext/nkf/nkf.c14
-rw-r--r--ext/openssl/extconf.rb28
-rw-r--r--ext/openssl/lib/net/ftptls.rb4
-rw-r--r--ext/openssl/lib/net/telnets.rb4
-rw-r--r--ext/openssl/lib/openssl.rb10
-rw-r--r--ext/openssl/lib/openssl/bn.rb6
-rw-r--r--ext/openssl/lib/openssl/buffering.rb6
-rw-r--r--ext/openssl/lib/openssl/cipher.rb37
-rw-r--r--ext/openssl/lib/openssl/config.rb316
-rw-r--r--ext/openssl/lib/openssl/digest.rb20
-rw-r--r--ext/openssl/lib/openssl/pkcs7.rb25
-rw-r--r--ext/openssl/lib/openssl/ssl-internal.rb179
-rw-r--r--ext/openssl/lib/openssl/ssl.rb136
-rw-r--r--ext/openssl/lib/openssl/x509-internal.rb153
-rw-r--r--ext/openssl/lib/openssl/x509.rb155
-rw-r--r--ext/openssl/openssl_missing.c14
-rw-r--r--ext/openssl/openssl_missing.h77
-rw-r--r--ext/openssl/ossl.c74
-rw-r--r--ext/openssl/ossl.h55
-rw-r--r--ext/openssl/ossl_asn1.c113
-rw-r--r--ext/openssl/ossl_asn1.h2
-rw-r--r--ext/openssl/ossl_bio.c25
-rw-r--r--ext/openssl/ossl_bio.h2
-rw-r--r--ext/openssl/ossl_bn.c233
-rw-r--r--ext/openssl/ossl_bn.h7
-rw-r--r--ext/openssl/ossl_cipher.c255
-rw-r--r--ext/openssl/ossl_cipher.h3
-rw-r--r--ext/openssl/ossl_config.c419
-rw-r--r--ext/openssl/ossl_config.h2
-rw-r--r--ext/openssl/ossl_digest.c201
-rw-r--r--ext/openssl/ossl_digest.h3
-rw-r--r--ext/openssl/ossl_engine.c32
-rw-r--r--ext/openssl/ossl_engine.h2
-rw-r--r--ext/openssl/ossl_hmac.c76
-rw-r--r--ext/openssl/ossl_hmac.h2
-rw-r--r--ext/openssl/ossl_ns_spki.c15
-rw-r--r--ext/openssl/ossl_ns_spki.h2
-rw-r--r--ext/openssl/ossl_ocsp.c38
-rw-r--r--ext/openssl/ossl_ocsp.h2
-rw-r--r--ext/openssl/ossl_pkcs12.c78
-rw-r--r--ext/openssl/ossl_pkcs12.h3
-rw-r--r--ext/openssl/ossl_pkcs5.c99
-rw-r--r--ext/openssl/ossl_pkcs7.c106
-rw-r--r--ext/openssl/ossl_pkcs7.h3
-rw-r--r--ext/openssl/ossl_pkey.c30
-rw-r--r--ext/openssl/ossl_pkey.h23
-rw-r--r--ext/openssl/ossl_pkey_dh.c116
-rw-r--r--ext/openssl/ossl_pkey_dsa.c109
-rw-r--r--ext/openssl/ossl_pkey_ec.c1593
-rw-r--r--ext/openssl/ossl_pkey_rsa.c142
-rw-r--r--ext/openssl/ossl_rand.c94
-rw-r--r--ext/openssl/ossl_rand.h2
-rw-r--r--ext/openssl/ossl_ssl.c658
-rw-r--r--ext/openssl/ossl_ssl.h17
-rw-r--r--ext/openssl/ossl_ssl_session.c307
-rw-r--r--ext/openssl/ossl_version.h2
-rw-r--r--ext/openssl/ossl_x509.c2
-rw-r--r--ext/openssl/ossl_x509.h2
-rw-r--r--ext/openssl/ossl_x509attr.c43
-rw-r--r--ext/openssl/ossl_x509cert.c111
-rw-r--r--ext/openssl/ossl_x509crl.c22
-rw-r--r--ext/openssl/ossl_x509ext.c32
-rw-r--r--ext/openssl/ossl_x509name.c71
-rw-r--r--ext/openssl/ossl_x509req.c12
-rw-r--r--ext/openssl/ossl_x509revoked.c10
-rw-r--r--ext/openssl/ossl_x509store.c19
-rw-r--r--ext/openssl/ruby_missing.h29
-rw-r--r--ext/pty/expect_sample.rb15
-rw-r--r--ext/pty/lib/expect.rb2
-rw-r--r--ext/pty/pty.c98
-rw-r--r--ext/purelib.rb10
-rw-r--r--ext/racc/cparse/cparse.c4
-rw-r--r--ext/racc/cparse/extconf.rb2
-rw-r--r--ext/readline/extconf.rb5
-rw-r--r--ext/readline/readline.c31
-rw-r--r--ext/sdbm/_sdbm.c4
-rw-r--r--ext/sdbm/init.c4
-rw-r--r--ext/socket/addrinfo.h5
-rw-r--r--ext/socket/extconf.rb47
-rw-r--r--ext/socket/getaddrinfo.c13
-rw-r--r--ext/socket/getnameinfo.c4
-rw-r--r--ext/socket/socket.c194
-rw-r--r--ext/socket/sockport.h4
-rw-r--r--ext/stringio/README4
-rw-r--r--ext/stringio/stringio.c96
-rw-r--r--ext/strscan/strscan.c6
-rw-r--r--ext/syck/bytecode.c4
-rw-r--r--ext/syck/emitter.c4
-rw-r--r--ext/syck/handler.c4
-rw-r--r--ext/syck/implicit.c4
-rw-r--r--ext/syck/node.c4
-rw-r--r--ext/syck/rubyext.c20
-rw-r--r--ext/syck/syck.c4
-rw-r--r--ext/syck/syck.h4
-rw-r--r--ext/syck/token.c4
-rw-r--r--ext/syck/yaml2byte.c4
-rw-r--r--ext/syslog/extconf.rb2
-rw-r--r--ext/syslog/syslog.c5
-rw-r--r--ext/syslog/syslog.txt7
-rw-r--r--ext/syslog/test.rb2
-rw-r--r--ext/thread/extconf.rb9
-rw-r--r--ext/thread/lib/thread.rb5
-rw-r--r--ext/thread/thread.c1239
-rw-r--r--ext/tk/ChangeLog.tkextlib66
-rw-r--r--ext/tk/MANUAL_tcltklib.eng24
-rw-r--r--ext/tk/MANUAL_tcltklib.eucj22
-rw-r--r--ext/tk/README.1st13
-rw-r--r--ext/tk/README.tcltklib25
-rw-r--r--ext/tk/config_list.in41
-rw-r--r--ext/tk/extconf.rb2005
-rw-r--r--ext/tk/lib/multi-tk.rb200
-rw-r--r--ext/tk/lib/tcltk.rb2
-rw-r--r--ext/tk/lib/tk.rb1230
-rw-r--r--ext/tk/lib/tk/after.rb2
-rw-r--r--ext/tk/lib/tk/autoload.rb358
-rw-r--r--ext/tk/lib/tk/bindtag.rb83
-rw-r--r--ext/tk/lib/tk/button.rb5
-rw-r--r--ext/tk/lib/tk/canvas.rb60
-rw-r--r--ext/tk/lib/tk/canvastag.rb117
-rw-r--r--ext/tk/lib/tk/checkbutton.rb9
-rw-r--r--ext/tk/lib/tk/composite.rb70
-rw-r--r--ext/tk/lib/tk/encodedstr.rb84
-rw-r--r--ext/tk/lib/tk/entry.rb6
-rw-r--r--ext/tk/lib/tk/event.rb62
-rw-r--r--ext/tk/lib/tk/font.rb742
-rw-r--r--ext/tk/lib/tk/frame.rb5
-rw-r--r--ext/tk/lib/tk/grid.rb49
-rw-r--r--ext/tk/lib/tk/image.rb62
-rw-r--r--ext/tk/lib/tk/itemconfig.rb177
-rw-r--r--ext/tk/lib/tk/itemfont.rb33
-rw-r--r--ext/tk/lib/tk/label.rb5
-rw-r--r--ext/tk/lib/tk/labelframe.rb8
-rw-r--r--ext/tk/lib/tk/listbox.rb5
-rw-r--r--ext/tk/lib/tk/macpkg.rb9
-rw-r--r--ext/tk/lib/tk/menu.rb91
-rw-r--r--ext/tk/lib/tk/menubar.rb2
-rw-r--r--ext/tk/lib/tk/menuspec.rb26
-rw-r--r--ext/tk/lib/tk/message.rb5
-rw-r--r--ext/tk/lib/tk/msgcat.rb6
-rw-r--r--ext/tk/lib/tk/namespace.rb149
-rw-r--r--ext/tk/lib/tk/optiondb.rb16
-rw-r--r--ext/tk/lib/tk/pack.rb17
-rw-r--r--ext/tk/lib/tk/package.rb4
-rw-r--r--ext/tk/lib/tk/palette.rb2
-rw-r--r--ext/tk/lib/tk/panedwindow.rb32
-rw-r--r--ext/tk/lib/tk/radiobutton.rb9
-rw-r--r--ext/tk/lib/tk/root.rb37
-rw-r--r--ext/tk/lib/tk/scale.rb33
-rw-r--r--ext/tk/lib/tk/scrollable.rb11
-rw-r--r--ext/tk/lib/tk/scrollbar.rb65
-rw-r--r--ext/tk/lib/tk/scrollbox.rb7
-rw-r--r--ext/tk/lib/tk/spinbox.rb24
-rw-r--r--ext/tk/lib/tk/text.rb178
-rw-r--r--ext/tk/lib/tk/textimage.rb14
-rw-r--r--ext/tk/lib/tk/textmark.rb102
-rw-r--r--ext/tk/lib/tk/texttag.rb113
-rw-r--r--ext/tk/lib/tk/textwindow.rb13
-rw-r--r--ext/tk/lib/tk/timer.rb57
-rw-r--r--ext/tk/lib/tk/toplevel.rb13
-rw-r--r--ext/tk/lib/tk/ttk_selector.rb76
-rw-r--r--ext/tk/lib/tk/txtwin_abst.rb2
-rw-r--r--ext/tk/lib/tk/validation.rb25
-rw-r--r--ext/tk/lib/tk/variable.rb488
-rw-r--r--ext/tk/lib/tk/virtevent.rb77
-rw-r--r--ext/tk/lib/tk/winpkg.rb18
-rw-r--r--ext/tk/lib/tk/wm.rb476
-rw-r--r--ext/tk/lib/tkclass.rb2
-rw-r--r--ext/tk/lib/tkextlib/SUPPORT_STATUS42
-rw-r--r--ext/tk/lib/tkextlib/blt.rb8
-rw-r--r--ext/tk/lib/tkextlib/blt/bitmap.rb21
-rw-r--r--ext/tk/lib/tkextlib/blt/busy.rb2
-rw-r--r--ext/tk/lib/tkextlib/blt/component.rb452
-rw-r--r--ext/tk/lib/tkextlib/blt/container.rb20
-rw-r--r--ext/tk/lib/tkextlib/blt/dragdrop.rb54
-rw-r--r--ext/tk/lib/tkextlib/blt/eps.rb2
-rw-r--r--ext/tk/lib/tkextlib/blt/htext.rb1
-rw-r--r--ext/tk/lib/tkextlib/blt/table.rb119
-rw-r--r--ext/tk/lib/tkextlib/blt/tabset.rb81
-rw-r--r--ext/tk/lib/tkextlib/blt/ted.rb9
-rw-r--r--ext/tk/lib/tkextlib/blt/tile/button.rb2
-rw-r--r--ext/tk/lib/tkextlib/blt/tile/checkbutton.rb4
-rw-r--r--ext/tk/lib/tkextlib/blt/tile/frame.rb2
-rw-r--r--ext/tk/lib/tkextlib/blt/tile/label.rb2
-rw-r--r--ext/tk/lib/tkextlib/blt/tile/radiobutton.rb4
-rw-r--r--ext/tk/lib/tkextlib/blt/tile/scrollbar.rb2
-rw-r--r--ext/tk/lib/tkextlib/blt/tile/toplevel.rb2
-rw-r--r--ext/tk/lib/tkextlib/blt/tree.rb341
-rw-r--r--ext/tk/lib/tkextlib/blt/treeview.rb228
-rw-r--r--ext/tk/lib/tkextlib/blt/unix_dnd.rb16
-rw-r--r--ext/tk/lib/tkextlib/blt/vector.rb49
-rw-r--r--ext/tk/lib/tkextlib/blt/watch.rb47
-rw-r--r--ext/tk/lib/tkextlib/bwidget/button.rb2
-rw-r--r--ext/tk/lib/tkextlib/bwidget/buttonbox.rb20
-rw-r--r--ext/tk/lib/tkextlib/bwidget/combobox.rb8
-rw-r--r--ext/tk/lib/tkextlib/bwidget/dialog.rb33
-rw-r--r--ext/tk/lib/tkextlib/bwidget/dynamichelp.rb7
-rw-r--r--ext/tk/lib/tkextlib/bwidget/entry.rb2
-rw-r--r--ext/tk/lib/tkextlib/bwidget/label.rb2
-rw-r--r--ext/tk/lib/tkextlib/bwidget/labelentry.rb2
-rw-r--r--ext/tk/lib/tkextlib/bwidget/labelframe.rb8
-rw-r--r--ext/tk/lib/tkextlib/bwidget/listbox.rb37
-rw-r--r--ext/tk/lib/tkextlib/bwidget/mainframe.rb48
-rw-r--r--ext/tk/lib/tkextlib/bwidget/messagedlg.rb16
-rw-r--r--ext/tk/lib/tkextlib/bwidget/notebook.rb24
-rw-r--r--ext/tk/lib/tkextlib/bwidget/pagesmanager.rb16
-rw-r--r--ext/tk/lib/tkextlib/bwidget/panedwindow.rb8
-rw-r--r--ext/tk/lib/tkextlib/bwidget/panelframe.rb8
-rw-r--r--ext/tk/lib/tkextlib/bwidget/progressdlg.rb4
-rw-r--r--ext/tk/lib/tkextlib/bwidget/scrollableframe.rb8
-rw-r--r--ext/tk/lib/tkextlib/bwidget/scrolledwindow.rb8
-rw-r--r--ext/tk/lib/tkextlib/bwidget/selectcolor.rb28
-rw-r--r--ext/tk/lib/tkextlib/bwidget/selectfont.rb7
-rw-r--r--ext/tk/lib/tkextlib/bwidget/spinbox.rb2
-rw-r--r--ext/tk/lib/tkextlib/bwidget/statusbar.rb8
-rw-r--r--ext/tk/lib/tkextlib/bwidget/titleframe.rb8
-rw-r--r--ext/tk/lib/tkextlib/bwidget/tree.rb37
-rw-r--r--ext/tk/lib/tkextlib/bwidget/widget.rb20
-rw-r--r--ext/tk/lib/tkextlib/itcl/incr_tcl.rb12
-rw-r--r--ext/tk/lib/tkextlib/itk/incr_tk.rb44
-rw-r--r--ext/tk/lib/tkextlib/iwidgets/buttonbox.rb5
-rw-r--r--ext/tk/lib/tkextlib/iwidgets/calendar.rb19
-rw-r--r--ext/tk/lib/tkextlib/iwidgets/checkbox.rb23
-rw-r--r--ext/tk/lib/tkextlib/iwidgets/dialogshell.rb5
-rw-r--r--ext/tk/lib/tkextlib/iwidgets/entryfield.rb19
-rw-r--r--ext/tk/lib/tkextlib/iwidgets/hierarchy.rb58
-rw-r--r--ext/tk/lib/tkextlib/iwidgets/menubar.rb5
-rw-r--r--ext/tk/lib/tkextlib/iwidgets/messagebox.rb5
-rw-r--r--ext/tk/lib/tkextlib/iwidgets/notebook.rb16
-rw-r--r--ext/tk/lib/tkextlib/iwidgets/panedwindow.rb5
-rw-r--r--ext/tk/lib/tkextlib/iwidgets/radiobox.rb16
-rw-r--r--ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb12
-rw-r--r--ext/tk/lib/tkextlib/iwidgets/scrolledlistbox.rb2
-rw-r--r--ext/tk/lib/tkextlib/iwidgets/scrolledtext.rb30
-rw-r--r--ext/tk/lib/tkextlib/iwidgets/selectionbox.rb2
-rw-r--r--ext/tk/lib/tkextlib/iwidgets/selectiondialog.rb2
-rw-r--r--ext/tk/lib/tkextlib/iwidgets/spinner.rb19
-rw-r--r--ext/tk/lib/tkextlib/iwidgets/tabnotebook.rb21
-rw-r--r--ext/tk/lib/tkextlib/iwidgets/tabset.rb49
-rw-r--r--ext/tk/lib/tkextlib/tcllib/autoscroll.rb2
-rw-r--r--ext/tk/lib/tkextlib/tcllib/ctext.rb2
-rw-r--r--ext/tk/lib/tkextlib/tcllib/datefield.rb2
-rw-r--r--ext/tk/lib/tkextlib/tcllib/getstring.rb5
-rw-r--r--ext/tk/lib/tkextlib/tcllib/ico.rb6
-rw-r--r--ext/tk/lib/tkextlib/tcllib/ip_entry.rb2
-rw-r--r--ext/tk/lib/tkextlib/tcllib/plotchart.rb77
-rw-r--r--ext/tk/lib/tkextlib/tcllib/swaplist.rb5
-rw-r--r--ext/tk/lib/tkextlib/tcllib/tablelist.rb2
-rw-r--r--ext/tk/lib/tkextlib/tcllib/tablelist_core.rb16
-rw-r--r--ext/tk/lib/tkextlib/tcllib/tkpiechart.rb14
-rw-r--r--ext/tk/lib/tkextlib/tile.rb260
-rw-r--r--ext/tk/lib/tkextlib/tile/dialog.rb16
-rw-r--r--ext/tk/lib/tkextlib/tile/sizegrip.rb29
-rw-r--r--ext/tk/lib/tkextlib/tile/style.rb241
-rw-r--r--ext/tk/lib/tkextlib/tile/tbutton.rb7
-rw-r--r--ext/tk/lib/tkextlib/tile/tcheckbutton.rb8
-rw-r--r--ext/tk/lib/tkextlib/tile/tcombobox.rb9
-rw-r--r--ext/tk/lib/tkextlib/tile/tentry.rb12
-rw-r--r--ext/tk/lib/tkextlib/tile/tframe.rb7
-rw-r--r--ext/tk/lib/tkextlib/tile/tlabel.rb7
-rw-r--r--ext/tk/lib/tkextlib/tile/tlabelframe.rb8
-rw-r--r--ext/tk/lib/tkextlib/tile/tmenubutton.rb12
-rw-r--r--ext/tk/lib/tkextlib/tile/tnotebook.rb41
-rw-r--r--ext/tk/lib/tkextlib/tile/tpaned.rb55
-rw-r--r--ext/tk/lib/tkextlib/tile/tprogressbar.rb3
-rw-r--r--ext/tk/lib/tkextlib/tile/tradiobutton.rb8
-rw-r--r--ext/tk/lib/tkextlib/tile/treeview.rb1212
-rw-r--r--ext/tk/lib/tkextlib/tile/tscale.rb7
-rw-r--r--ext/tk/lib/tkextlib/tile/tscrollbar.rb28
-rw-r--r--ext/tk/lib/tkextlib/tile/tseparator.rb3
-rw-r--r--ext/tk/lib/tkextlib/tkDND/shape.rb32
-rw-r--r--ext/tk/lib/tkextlib/tkDND/tkdnd.rb18
-rw-r--r--ext/tk/lib/tkextlib/tkHTML/htmlwidget.rb17
-rw-r--r--ext/tk/lib/tkextlib/tktable/tktable.rb188
-rw-r--r--ext/tk/lib/tkextlib/tktrans/tktrans.rb4
-rw-r--r--ext/tk/lib/tkextlib/treectrl/tktreectrl.rb300
-rw-r--r--ext/tk/lib/tkextlib/version.rb6
-rw-r--r--ext/tk/lib/tkextlib/vu/pie.rb77
-rw-r--r--ext/tk/lib/tkextlib/vu/spinbox.rb2
-rw-r--r--ext/tk/lib/tkextlib/winico/winico.rb57
-rw-r--r--ext/tk/old-extconf.rb440
-rw-r--r--ext/tk/sample/binstr_usage.rb12
-rw-r--r--ext/tk/sample/demos-en/anilabel.rb10
-rw-r--r--ext/tk/sample/demos-en/aniwave.rb9
-rw-r--r--ext/tk/sample/demos-en/arrow.rb26
-rw-r--r--ext/tk/sample/demos-en/bind.rb33
-rw-r--r--ext/tk/sample/demos-en/bitmap.rb10
-rw-r--r--ext/tk/sample/demos-en/button.rb2
-rw-r--r--ext/tk/sample/demos-en/check.rb14
-rw-r--r--ext/tk/sample/demos-en/check2.rb14
-rw-r--r--ext/tk/sample/demos-en/clrpick.rb22
-rw-r--r--ext/tk/sample/demos-en/colors.rb18
-rw-r--r--ext/tk/sample/demos-en/combo.rb96
-rw-r--r--ext/tk/sample/demos-en/cscroll.rb14
-rw-r--r--ext/tk/sample/demos-en/ctext.rb53
-rw-r--r--ext/tk/sample/demos-en/entry1.rb12
-rw-r--r--ext/tk/sample/demos-en/entry2.rb8
-rw-r--r--ext/tk/sample/demos-en/entry3.rb50
-rw-r--r--ext/tk/sample/demos-en/filebox.rb17
-rw-r--r--ext/tk/sample/demos-en/floor.rb14
-rw-r--r--ext/tk/sample/demos-en/floor2.rb14
-rw-r--r--ext/tk/sample/demos-en/form.rb8
-rw-r--r--ext/tk/sample/demos-en/goldberg.rb23
-rw-r--r--ext/tk/sample/demos-en/hello6
-rw-r--r--ext/tk/sample/demos-en/hscale.rb29
-rw-r--r--ext/tk/sample/demos-en/icon.rb20
-rw-r--r--ext/tk/sample/demos-en/image1.rb13
-rw-r--r--ext/tk/sample/demos-en/image2.rb22
-rw-r--r--ext/tk/sample/demos-en/image3.rb29
-rw-r--r--ext/tk/sample/demos-en/items.rb17
-rw-r--r--ext/tk/sample/demos-en/knightstour.rb271
-rw-r--r--ext/tk/sample/demos-en/label.rb13
-rw-r--r--ext/tk/sample/demos-en/labelframe.rb8
-rw-r--r--ext/tk/sample/demos-en/mclist.rb117
-rw-r--r--ext/tk/sample/demos-en/menu.rb12
-rw-r--r--ext/tk/sample/demos-en/menu84.rb8
-rw-r--r--ext/tk/sample/demos-en/menubu.rb10
-rw-r--r--ext/tk/sample/demos-en/msgbox.rb10
-rw-r--r--ext/tk/sample/demos-en/msgbox2.rb91
-rw-r--r--ext/tk/sample/demos-en/paned1.rb14
-rw-r--r--ext/tk/sample/demos-en/paned2.rb8
-rw-r--r--ext/tk/sample/demos-en/patch_1.1c193
-rw-r--r--ext/tk/sample/demos-en/pendulum.rb43
-rw-r--r--ext/tk/sample/demos-en/plot.rb8
-rw-r--r--ext/tk/sample/demos-en/puzzle.rb32
-rw-r--r--ext/tk/sample/demos-en/radio.rb12
-rw-r--r--ext/tk/sample/demos-en/radio2.rb17
-rw-r--r--ext/tk/sample/demos-en/radio3.rb19
-rw-r--r--ext/tk/sample/demos-en/rolodex-j323
-rw-r--r--ext/tk/sample/demos-en/ruler.rb8
-rw-r--r--ext/tk/sample/demos-en/sayings.rb8
-rw-r--r--ext/tk/sample/demos-en/search.rb19
-rw-r--r--ext/tk/sample/demos-en/spin.rb12
-rw-r--r--ext/tk/sample/demos-en/states.rb8
-rw-r--r--ext/tk/sample/demos-en/style.rb42
-rw-r--r--ext/tk/sample/demos-en/text.rb8
-rw-r--r--ext/tk/sample/demos-en/textpeer.rb76
-rw-r--r--ext/tk/sample/demos-en/toolbar.rb130
-rw-r--r--ext/tk/sample/demos-en/tree.rb119
-rw-r--r--ext/tk/sample/demos-en/ttkbut.rb139
-rw-r--r--ext/tk/sample/demos-en/ttkmenu.rb85
-rw-r--r--ext/tk/sample/demos-en/ttknote.rb89
-rw-r--r--ext/tk/sample/demos-en/ttkpane.rb213
-rw-r--r--ext/tk/sample/demos-en/ttkprogress.rb66
-rw-r--r--ext/tk/sample/demos-en/twind.rb14
-rw-r--r--ext/tk/sample/demos-en/twind2.rb6
-rw-r--r--ext/tk/sample/demos-en/unicodeout.rb14
-rw-r--r--ext/tk/sample/demos-en/vscale.rb29
-rw-r--r--ext/tk/sample/demos-en/widget232
-rw-r--r--ext/tk/sample/demos-jp/anilabel.rb11
-rw-r--r--ext/tk/sample/demos-jp/aniwave.rb10
-rw-r--r--ext/tk/sample/demos-jp/arrow.rb27
-rw-r--r--ext/tk/sample/demos-jp/bind.rb34
-rw-r--r--ext/tk/sample/demos-jp/bitmap.rb11
-rw-r--r--ext/tk/sample/demos-jp/button.rb4
-rw-r--r--ext/tk/sample/demos-jp/check.rb15
-rw-r--r--ext/tk/sample/demos-jp/check2.rb15
-rw-r--r--ext/tk/sample/demos-jp/clrpick.rb21
-rw-r--r--ext/tk/sample/demos-jp/colors.rb19
-rw-r--r--ext/tk/sample/demos-jp/combo.rb98
-rw-r--r--ext/tk/sample/demos-jp/cscroll.rb15
-rw-r--r--ext/tk/sample/demos-jp/ctext.rb54
-rw-r--r--ext/tk/sample/demos-jp/dialog1.rb1
-rw-r--r--ext/tk/sample/demos-jp/dialog2.rb1
-rw-r--r--ext/tk/sample/demos-jp/entry1.rb13
-rw-r--r--ext/tk/sample/demos-jp/entry2.rb9
-rw-r--r--ext/tk/sample/demos-jp/entry3.rb49
-rw-r--r--ext/tk/sample/demos-jp/filebox.rb18
-rw-r--r--ext/tk/sample/demos-jp/floor.rb15
-rw-r--r--ext/tk/sample/demos-jp/floor2.rb15
-rw-r--r--ext/tk/sample/demos-jp/form.rb9
-rw-r--r--ext/tk/sample/demos-jp/goldberg.rb24
-rw-r--r--ext/tk/sample/demos-jp/hello1
-rw-r--r--ext/tk/sample/demos-jp/hscale.rb29
-rw-r--r--ext/tk/sample/demos-jp/icon.rb21
-rw-r--r--ext/tk/sample/demos-jp/image1.rb14
-rw-r--r--ext/tk/sample/demos-jp/image2.rb24
-rw-r--r--ext/tk/sample/demos-jp/image3.rb18
-rw-r--r--ext/tk/sample/demos-jp/items.rb18
-rw-r--r--ext/tk/sample/demos-jp/ixset21
-rw-r--r--ext/tk/sample/demos-jp/knightstour.rb273
-rw-r--r--ext/tk/sample/demos-jp/label.rb14
-rw-r--r--ext/tk/sample/demos-jp/labelframe.rb10
-rw-r--r--ext/tk/sample/demos-jp/mclist.rb121
-rw-r--r--ext/tk/sample/demos-jp/menu.rb15
-rw-r--r--ext/tk/sample/demos-jp/menu84.rb9
-rw-r--r--ext/tk/sample/demos-jp/menu8x.rb13
-rw-r--r--ext/tk/sample/demos-jp/menubu.rb11
-rw-r--r--ext/tk/sample/demos-jp/msgbox.rb15
-rw-r--r--ext/tk/sample/demos-jp/msgbox2.rb90
-rw-r--r--ext/tk/sample/demos-jp/paned1.rb16
-rw-r--r--ext/tk/sample/demos-jp/paned2.rb10
-rw-r--r--ext/tk/sample/demos-jp/pendulum.rb44
-rw-r--r--ext/tk/sample/demos-jp/plot.rb15
-rw-r--r--ext/tk/sample/demos-jp/puzzle.rb33
-rw-r--r--ext/tk/sample/demos-jp/radio.rb13
-rw-r--r--ext/tk/sample/demos-jp/radio2.rb19
-rw-r--r--ext/tk/sample/demos-jp/radio3.rb21
-rw-r--r--ext/tk/sample/demos-jp/rolodex-j1
-rw-r--r--ext/tk/sample/demos-jp/ruler.rb9
-rw-r--r--ext/tk/sample/demos-jp/sayings.rb9
-rw-r--r--ext/tk/sample/demos-jp/search.rb20
-rw-r--r--ext/tk/sample/demos-jp/spin.rb16
-rw-r--r--ext/tk/sample/demos-jp/states.rb9
-rw-r--r--ext/tk/sample/demos-jp/style.rb42
-rw-r--r--ext/tk/sample/demos-jp/tcolor1
-rw-r--r--ext/tk/sample/demos-jp/text.rb9
-rw-r--r--ext/tk/sample/demos-jp/textpeer.rb82
-rw-r--r--ext/tk/sample/demos-jp/toolbar.rb136
-rw-r--r--ext/tk/sample/demos-jp/tree.rb120
-rw-r--r--ext/tk/sample/demos-jp/ttkbut.rb145
-rw-r--r--ext/tk/sample/demos-jp/ttkmenu.rb91
-rw-r--r--ext/tk/sample/demos-jp/ttknote.rb97
-rw-r--r--ext/tk/sample/demos-jp/ttkpane.rb216
-rw-r--r--ext/tk/sample/demos-jp/ttkprogress.rb71
-rw-r--r--ext/tk/sample/demos-jp/twind.rb13
-rw-r--r--ext/tk/sample/demos-jp/twind2.rb7
-rw-r--r--ext/tk/sample/demos-jp/unicodeout.rb16
-rw-r--r--ext/tk/sample/demos-jp/vscale.rb30
-rw-r--r--ext/tk/sample/demos-jp/widget278
-rw-r--r--ext/tk/sample/editable_listbox.rb69
-rw-r--r--ext/tk/sample/encstr_usage.rb5
-rw-r--r--ext/tk/sample/figmemo_sample.rb456
-rw-r--r--ext/tk/sample/images/teapot.ppm49
-rw-r--r--ext/tk/sample/irbtkw.rbw146
-rw-r--r--ext/tk/sample/tcltklib/sample2.rb2
-rw-r--r--ext/tk/sample/tkextlib/tile/demo.rb39
-rw-r--r--ext/tk/sample/tkextlib/tile/repeater.tcl2
-rw-r--r--ext/tk/sample/tkextlib/tile/themes/blue/pkgIndex.tcl2
-rw-r--r--ext/tk/sample/tkextlib/tile/themes/keramik/keramik.tcl2
-rw-r--r--ext/tk/sample/tkextlib/tile/themes/keramik/pkgIndex.tcl2
-rw-r--r--ext/tk/sample/tkextlib/tile/themes/kroc.rb30
-rw-r--r--ext/tk/sample/tkextlib/tile/themes/kroc/pkgIndex.tcl2
-rw-r--r--ext/tk/sample/tkextlib/tile/themes/plastik/pkgIndex.tcl2
-rw-r--r--ext/tk/sample/tkextlib/tile/themes/plastik/plastik.tcl2
-rw-r--r--ext/tk/sample/tkextlib/tile/toolbutton.tcl2
-rw-r--r--ext/tk/sample/tkextlib/tkHTML/page3/index.html2
-rw-r--r--ext/tk/sample/tkextlib/treectrl/demo.rb7
-rw-r--r--ext/tk/sample/tkextlib/vu/canvSticker2.rb12
-rw-r--r--ext/tk/sample/tkrttimer.rb13
-rw-r--r--ext/tk/sample/tksleep_sample.rb29
-rw-r--r--ext/tk/sample/tktextio.rb557
-rw-r--r--ext/tk/sample/ttk_wrapper.rb154
-rw-r--r--ext/tk/stubs.c78
-rw-r--r--ext/tk/tcltklib.c2692
-rw-r--r--ext/tk/tkutil/extconf.rb11
-rw-r--r--ext/tk/tkutil/tkutil.c710
-rw-r--r--ext/win32ole/extconf.rb6
-rw-r--r--ext/win32ole/sample/olegen.rb4
-rw-r--r--ext/win32ole/tests/testOLEEVENT.rb91
-rw-r--r--ext/win32ole/tests/testWIN32OLE.rb3
-rw-r--r--ext/win32ole/tests/test_win32ole_event.rb133
-rw-r--r--ext/win32ole/tests/testall.rb1
-rw-r--r--ext/win32ole/win32ole.c426
-rw-r--r--ext/zlib/doc/zlib.rd2
-rw-r--r--ext/zlib/extconf.rb6
-rw-r--r--ext/zlib/zlib.c28
-rw-r--r--file.c447
-rw-r--r--gc.c394
-rw-r--r--hash.c596
-rw-r--r--ia64.s33
-rw-r--r--inits.c6
-rwxr-xr-x[-rw-r--r--]instruby.rb373
-rw-r--r--intern.h48
-rw-r--r--io.c509
-rw-r--r--keywords2
-rw-r--r--lex.c2
-rw-r--r--lib/.document3
-rw-r--r--lib/README4
-rw-r--r--lib/abbrev.rb2
-rw-r--r--lib/base64.rb2
-rw-r--r--lib/benchmark.rb11
-rw-r--r--lib/cgi.rb72
-rw-r--r--lib/cgi/session.rb50
-rw-r--r--lib/cgi/session/pstore.rb2
-rw-r--r--lib/complex.rb38
-rw-r--r--lib/csv.rb2
-rw-r--r--lib/date.rb999
-rw-r--r--lib/date/format.rb1595
-rw-r--r--lib/delegate.rb61
-rw-r--r--lib/drb/acl.rb2
-rw-r--r--lib/drb/drb.rb39
-rw-r--r--lib/drb/extservm.rb41
-rw-r--r--lib/drb/unix.rb2
-rw-r--r--lib/erb.rb292
-rw-r--r--lib/fileutils.rb148
-rw-r--r--lib/forwardable.rb6
-rw-r--r--lib/generator.rb40
-rw-r--r--lib/getopts.rb6
-rw-r--r--lib/ipaddr.rb148
-rw-r--r--lib/irb.rb38
-rw-r--r--lib/irb/cmd/chws.rb4
-rw-r--r--lib/irb/cmd/fork.rb6
-rw-r--r--lib/irb/cmd/help.rb4
-rw-r--r--lib/irb/cmd/load.rb4
-rw-r--r--lib/irb/cmd/nop.rb6
-rw-r--r--lib/irb/cmd/pushws.rb4
-rw-r--r--lib/irb/cmd/subirb.rb4
-rw-r--r--lib/irb/completion.rb6
-rw-r--r--lib/irb/context.rb4
-rw-r--r--lib/irb/ext/change-ws.rb4
-rw-r--r--lib/irb/ext/history.rb6
-rw-r--r--lib/irb/ext/loader.rb6
-rw-r--r--lib/irb/ext/math-mode.rb4
-rw-r--r--lib/irb/ext/multi-irb.rb14
-rw-r--r--lib/irb/ext/save-history.rb50
-rw-r--r--lib/irb/ext/tracer.rb4
-rw-r--r--lib/irb/ext/use-loader.rb4
-rw-r--r--lib/irb/ext/workspaces.rb4
-rw-r--r--lib/irb/extend-command.rb15
-rw-r--r--lib/irb/frame.rb4
-rw-r--r--lib/irb/help.rb6
-rw-r--r--lib/irb/init.rb6
-rw-r--r--lib/irb/input-method.rb6
-rw-r--r--lib/irb/lc/error.rb4
-rw-r--r--lib/irb/lc/help-message4
-rw-r--r--lib/irb/lc/ja/error.rb4
-rw-r--r--lib/irb/lc/ja/help-message4
-rw-r--r--lib/irb/locale.rb12
-rw-r--r--lib/irb/notifier.rb6
-rw-r--r--lib/irb/output-method.rb6
-rw-r--r--lib/irb/ruby-lex.rb8
-rw-r--r--lib/irb/ruby-token.rb4
-rw-r--r--lib/irb/slex.rb8
-rw-r--r--lib/irb/version.rb4
-rw-r--r--lib/irb/workspace.rb4
-rw-r--r--lib/irb/ws-for-case-2.rb4
-rw-r--r--lib/irb/xmp.rb6
-rw-r--r--lib/jcode.rb2
-rw-r--r--lib/logger.rb7
-rw-r--r--lib/matrix.rb20
-rw-r--r--lib/mkmf.rb481
-rw-r--r--lib/monitor.rb10
-rw-r--r--lib/net/ftp.rb27
-rw-r--r--lib/net/http.rb24
-rw-r--r--lib/net/https.rb8
-rw-r--r--lib/net/imap.rb102
-rw-r--r--lib/net/pop.rb241
-rw-r--r--lib/net/protocol.rb6
-rw-r--r--lib/net/smtp.rb651
-rw-r--r--lib/net/telnet.rb24
-rw-r--r--lib/open-uri.rb2
-rw-r--r--lib/open3.rb51
-rw-r--r--lib/optparse.rb181
-rw-r--r--lib/ostruct.rb49
-rw-r--r--lib/parsearg.rb6
-rw-r--r--lib/parsedate.rb44
-rw-r--r--lib/pathname.rb27
-rw-r--r--lib/ping.rb49
-rw-r--r--lib/pp.rb13
-rw-r--r--lib/prettyprint.rb12
-rw-r--r--lib/pstore.rb25
-rw-r--r--lib/rational.rb80
-rw-r--r--lib/rdoc/generators/ri_generator.rb2
-rw-r--r--lib/rdoc/options.rb13
-rw-r--r--lib/rdoc/parsers/parse_c.rb272
-rw-r--r--lib/rdoc/parsers/parse_f95.rb8
-rw-r--r--lib/rdoc/parsers/parse_rb.rb10
-rw-r--r--lib/rdoc/rdoc.rb54
-rw-r--r--lib/rdoc/ri/ri_formatter.rb4
-rw-r--r--lib/rdoc/ri/ri_options.rb34
-rw-r--r--lib/rdoc/ri/ri_paths.rb27
-rw-r--r--lib/resolv-replace.rb3
-rw-r--r--lib/resolv.rb1287
-rw-r--r--lib/rexml/attlistdecl.rb2
-rw-r--r--lib/rexml/attribute.rb38
-rw-r--r--lib/rexml/cdata.rb21
-rw-r--r--lib/rexml/comment.rb28
-rw-r--r--lib/rexml/doctype.rb27
-rw-r--r--lib/rexml/document.rb113
-rw-r--r--lib/rexml/element.rb2260
-rw-r--r--lib/rexml/encoding.rb31
-rw-r--r--lib/rexml/encodings/CP-1252.rb13
-rw-r--r--lib/rexml/encodings/ISO-8859-15.rb9
-rw-r--r--lib/rexml/encodings/SHIFT-JIS.rb4
-rw-r--r--lib/rexml/encodings/UNILE.rb2
-rw-r--r--lib/rexml/encodings/UTF-16.rb3
-rw-r--r--lib/rexml/entity.rb7
-rw-r--r--lib/rexml/formatters/default.rb109
-rw-r--r--lib/rexml/formatters/pretty.rb138
-rw-r--r--lib/rexml/formatters/transitive.rb56
-rw-r--r--lib/rexml/functions.rb29
-rw-r--r--lib/rexml/instruction.rb4
-rw-r--r--lib/rexml/node.rb25
-rw-r--r--lib/rexml/parsers/baseparser.rb87
-rw-r--r--lib/rexml/parsers/sax2parser.rb8
-rw-r--r--lib/rexml/parsers/treeparser.rb9
-rw-r--r--lib/rexml/parsers/xpathparser.rb10
-rw-r--r--lib/rexml/rexml.rb13
-rw-r--r--lib/rexml/sax2listener.rb2
-rw-r--r--lib/rexml/source.rb380
-rw-r--r--lib/rexml/text.rb66
-rw-r--r--lib/rexml/undefinednamespaceexception.rb8
-rw-r--r--lib/rexml/xmldecl.rb11
-rw-r--r--lib/rexml/xpath.rb16
-rw-r--r--lib/rexml/xpath_parser.rb103
-rw-r--r--lib/rinda/ring.rb4
-rw-r--r--lib/rinda/tuplespace.rb100
-rw-r--r--lib/rss.rb7
-rw-r--r--lib/rss/0.9.rb23
-rw-r--r--lib/rss/1.0.rb13
-rw-r--r--lib/rss/2.0.rb2
-rw-r--r--lib/rss/atom.rb749
-rw-r--r--lib/rss/content.rb25
-rw-r--r--lib/rss/content/1.0.rb10
-rw-r--r--lib/rss/content/2.0.rb12
-rw-r--r--lib/rss/converter.rb8
-rw-r--r--lib/rss/dublincore.rb39
-rw-r--r--lib/rss/dublincore/1.0.rb13
-rw-r--r--lib/rss/dublincore/2.0.rb13
-rw-r--r--lib/rss/dublincore/atom.rb17
-rw-r--r--lib/rss/image.rb10
-rw-r--r--lib/rss/itunes.rb410
-rw-r--r--lib/rss/maker.rb25
-rw-r--r--lib/rss/maker/0.9.rb375
-rw-r--r--lib/rss/maker/1.0.rb332
-rw-r--r--lib/rss/maker/2.0.rb147
-rw-r--r--lib/rss/maker/atom.rb172
-rw-r--r--lib/rss/maker/base.rb883
-rw-r--r--lib/rss/maker/content.rb14
-rw-r--r--lib/rss/maker/dublincore.rb145
-rw-r--r--lib/rss/maker/entry.rb163
-rw-r--r--lib/rss/maker/feed.rb429
-rw-r--r--lib/rss/maker/image.rb116
-rw-r--r--lib/rss/maker/itunes.rb242
-rw-r--r--lib/rss/maker/slash.rb33
-rw-r--r--lib/rss/maker/syndication.rb13
-rw-r--r--lib/rss/maker/taxonomy.rb118
-rw-r--r--lib/rss/maker/trackback.rb115
-rw-r--r--lib/rss/parser.rb167
-rw-r--r--lib/rss/rss.rb735
-rw-r--r--lib/rss/slash.rb49
-rw-r--r--lib/rss/syndication.rb9
-rw-r--r--lib/rss/taxonomy.rb2
-rw-r--r--lib/rss/utils.rb78
-rw-r--r--lib/rss/xml-stylesheet.rb4
-rw-r--r--lib/rss/xml.rb71
-rw-r--r--lib/scanf.rb10
-rw-r--r--lib/securerandom.rb145
-rw-r--r--lib/set.rb65
-rw-r--r--lib/shell/builtin-command.rb4
-rw-r--r--lib/shell/command-processor.rb11
-rw-r--r--lib/shell/error.rb4
-rw-r--r--lib/shell/filter.rb4
-rw-r--r--lib/shell/process-controller.rb4
-rw-r--r--lib/shell/system-command.rb4
-rw-r--r--lib/shell/version.rb4
-rw-r--r--lib/shellwords.rb146
-rw-r--r--lib/singleton.rb61
-rw-r--r--lib/soap/mimemessage.rb2
-rw-r--r--lib/sync.rb11
-rw-r--r--lib/tempfile.rb28
-rw-r--r--lib/test/unit.rb7
-rw-r--r--lib/test/unit/autorunner.rb24
-rw-r--r--lib/test/unit/collector/dir.rb25
-rw-r--r--lib/test/unit/testcase.rb14
-rw-r--r--lib/thread.rb15
-rw-r--r--lib/thwait.rb3
-rw-r--r--lib/time.rb28
-rw-r--r--lib/timeout.rb37
-rw-r--r--lib/tmpdir.rb108
-rw-r--r--lib/uri.rb3
-rw-r--r--lib/uri/common.rb12
-rw-r--r--lib/uri/ftp.rb88
-rw-r--r--lib/uri/generic.rb151
-rw-r--r--lib/uri/http.rb51
-rw-r--r--lib/uri/https.rb6
-rw-r--r--lib/uri/ldap.rb2
-rw-r--r--lib/uri/ldaps.rb12
-rw-r--r--lib/uri/mailto.rb47
-rw-r--r--lib/weakref.rb30
-rw-r--r--lib/webrick/accesslog.rb12
-rw-r--r--lib/webrick/cgi.rb2
-rw-r--r--lib/webrick/cookie.rb6
-rw-r--r--lib/webrick/httpproxy.rb2
-rw-r--r--lib/webrick/httprequest.rb9
-rw-r--r--lib/webrick/httpresponse.rb4
-rw-r--r--lib/webrick/https.rb1
-rw-r--r--lib/webrick/httpservlet/cgihandler.rb4
-rw-r--r--lib/webrick/httpservlet/filehandler.rb4
-rw-r--r--lib/webrick/httpstatus.rb32
-rw-r--r--lib/webrick/httputils.rb20
-rw-r--r--lib/webrick/ssl.rb6
-rw-r--r--lib/xmlrpc/base64.rb2
-rw-r--r--lib/xmlrpc/client.rb21
-rw-r--r--lib/xmlrpc/config.rb2
-rw-r--r--lib/xmlrpc/create.rb4
-rw-r--r--lib/xmlrpc/datetime.rb2
-rw-r--r--lib/xmlrpc/httpserver.rb2
-rw-r--r--lib/xmlrpc/marshal.rb2
-rw-r--r--lib/xmlrpc/parser.rb6
-rw-r--r--lib/xmlrpc/server.rb12
-rw-r--r--lib/xmlrpc/utils.rb4
-rw-r--r--lib/yaml.rb6
-rw-r--r--lib/yaml/baseemitter.rb2
-rw-r--r--lib/yaml/basenode.rb2
-rw-r--r--lib/yaml/encoding.rb6
-rw-r--r--lib/yaml/rubytypes.rb20
-rw-r--r--lib/yaml/store.rb20
-rw-r--r--lib/yaml/tag.rb2
-rw-r--r--lib/yaml/types.rb8
-rw-r--r--main.c13
-rw-r--r--marshal.c141
-rw-r--r--math.c8
-rwxr-xr-xmdoc2man.rb2
-rw-r--r--misc/README3
-rw-r--r--misc/inf-ruby.el10
-rw-r--r--misc/rdebug.el136
-rw-r--r--misc/ruby-mode.el47
-rw-r--r--misc/ruby-style.el66
-rw-r--r--missing.h13
-rw-r--r--missing/acosh.c4
-rw-r--r--missing/crypt.c34
-rw-r--r--missing/flock.c5
-rw-r--r--missing/isinf.c7
-rw-r--r--missing/strftime.c56
-rw-r--r--missing/strtod.c2
-rw-r--r--missing/vsnprintf.c2
-rwxr-xr-x[-rw-r--r--]mkconfig.rb53
-rw-r--r--node.h120
-rw-r--r--numeric.c594
-rw-r--r--object.c251
-rw-r--r--pack.c1092
-rw-r--r--parse.y287
-rw-r--r--prec.c4
-rw-r--r--process.c66
-rw-r--r--random.c38
-rw-r--r--range.c105
-rw-r--r--re.c224
-rw-r--r--re.h5
-rw-r--r--regex.c87
-rw-r--r--regex.h4
-rw-r--r--ruby.c104
-rw-r--r--ruby.h84
-rw-r--r--rubyio.h29
-rw-r--r--rubysig.h12
-rwxr-xr-x[-rw-r--r--]rubytest.rb0
-rwxr-xr-xrunruby.rb22
-rw-r--r--sample/README3
-rw-r--r--sample/biorhythm.rb4
-rw-r--r--sample/cal.rb84
-rw-r--r--sample/cbreak.rb4
-rw-r--r--sample/dualstack-httpd.rb2
-rw-r--r--sample/erb/erb4html.rb60
-rw-r--r--sample/eval.rb2
-rw-r--r--sample/from.rb2
-rw-r--r--sample/goodfriday.rb48
-rw-r--r--sample/openssl/c_rehash.rb4
-rw-r--r--sample/philos.rb2
-rw-r--r--sample/regx.rb2
-rwxr-xr-xsample/rss/blend.rb6
-rwxr-xr-xsample/rss/convert.rb2
-rwxr-xr-x[-rw-r--r--]sample/rss/list_description.rb13
-rwxr-xr-xsample/rss/re_read.rb10
-rwxr-xr-x[-rw-r--r--]sample/rss/rss_recent.rb20
-rw-r--r--sample/test.rb64
-rw-r--r--sample/time.rb16
-rw-r--r--signal.c167
-rw-r--r--sprintf.c47
-rw-r--r--string.c535
-rw-r--r--struct.c32
-rw-r--r--test/dbm/test_dbm.rb4
-rw-r--r--test/digest/test_digest.rb30
-rw-r--r--test/drb/drbtest.rb2
-rw-r--r--test/erb/hello.erb4
-rw-r--r--test/erb/test_erb.rb390
-rw-r--r--test/fileutils/fileasserts.rb8
-rw-r--r--test/fileutils/test_dryrun.rb2
-rw-r--r--test/fileutils/test_fileutils.rb2
-rw-r--r--test/fileutils/test_nowrite.rb2
-rw-r--r--test/fileutils/test_verbose.rb2
-rw-r--r--test/gdbm/test_gdbm.rb8
-rw-r--r--test/iconv/test_basic.rb52
-rw-r--r--test/iconv/test_option.rb31
-rw-r--r--test/iconv/test_partial.rb41
-rw-r--r--test/iconv/utils.rb26
-rw-r--r--test/logger/test_logger.rb4
-rw-r--r--test/matrix/test_matrix.rb43
-rw-r--r--test/matrix/test_vector.rb43
-rw-r--r--test/monitor/test_monitor.rb29
-rw-r--r--test/net/http/test_connection.rb33
-rw-r--r--test/net/http/test_https_proxy.rb9
-rw-r--r--test/net/http/test_post_io.rb32
-rw-r--r--test/net/imap/test_imap.rb27
-rw-r--r--test/net/pop/test_pop.rb132
-rw-r--r--test/nkf/test_nkf.rb5
-rw-r--r--test/openssl/test_asn1.rb14
-rw-r--r--test/openssl/test_bn.rb21
-rw-r--r--test/openssl/test_config.rb290
-rw-r--r--test/openssl/test_ec.rb111
-rw-r--r--test/openssl/test_ssl.rb351
-rw-r--r--test/openssl/test_x509cert.rb39
-rw-r--r--test/openssl/test_x509crl.rb28
-rw-r--r--test/openssl/test_x509req.rb38
-rw-r--r--test/openssl/utils.rb9
-rw-r--r--test/optparse/test_getopts.rb31
-rw-r--r--test/optparse/test_summary.rb21
-rw-r--r--test/ostruct/test_ostruct.rb43
-rw-r--r--test/pathname/test_pathname.rb35
-rw-r--r--test/rdoc/parsers/test_parse_c.rb261
-rw-r--r--test/resolv/test_addr.rb16
-rw-r--r--test/rexml/test_document.rb66
-rw-r--r--test/rinda/test_rinda.rb119
-rw-r--r--test/rss/dot.pngbin0 -> 111 bytes-rw-r--r--test/rss/rss-assertions.rb1894
-rw-r--r--test/rss/rss-testcase.rb208
-rw-r--r--test/rss/test_1.0.rb61
-rw-r--r--test/rss/test_2.0.rb28
-rw-r--r--test/rss/test_atom.rb681
-rw-r--r--test/rss/test_content.rb68
-rw-r--r--test/rss/test_dublincore.rb316
-rw-r--r--test/rss/test_image.rb49
-rw-r--r--test/rss/test_inherit.rb5
-rw-r--r--test/rss/test_itunes.rb347
-rw-r--r--test/rss/test_maker_0.9.rb164
-rw-r--r--test/rss/test_maker_1.0.rb205
-rw-r--r--test/rss/test_maker_2.0.rb56
-rw-r--r--test/rss/test_maker_atom_entry.rb367
-rw-r--r--test/rss/test_maker_atom_feed.rb389
-rw-r--r--test/rss/test_maker_content.rb13
-rw-r--r--test/rss/test_maker_dc.rb9
-rw-r--r--test/rss/test_maker_itunes.rb471
-rw-r--r--test/rss/test_maker_slash.rb37
-rw-r--r--test/rss/test_maker_sy.rb1
-rw-r--r--test/rss/test_maker_xml-stylesheet.rb8
-rw-r--r--test/rss/test_parser.rb26
-rw-r--r--test/rss/test_parser_1.0.rb10
-rw-r--r--test/rss/test_parser_atom_entry.rb163
-rw-r--r--test/rss/test_parser_atom_feed.rb276
-rw-r--r--test/rss/test_setup_maker_0.9.rb25
-rw-r--r--test/rss/test_setup_maker_1.0.rb26
-rw-r--r--test/rss/test_setup_maker_atom_entry.rb409
-rw-r--r--test/rss/test_setup_maker_atom_feed.rb445
-rw-r--r--test/rss/test_setup_maker_itunes.rb144
-rw-r--r--test/rss/test_setup_maker_slash.rb38
-rw-r--r--test/rss/test_slash.rb64
-rw-r--r--test/rss/test_syndication.rb4
-rw-r--r--test/rss/test_taxonomy.rb16
-rw-r--r--test/rss/test_to_s.rb232
-rw-r--r--test/rss/test_version.rb2
-rw-r--r--test/rss/test_xml-stylesheet.rb6
-rw-r--r--test/ruby/bug2519.rb1
-rw-r--r--test/ruby/marshaltestlib.rb6
-rw-r--r--test/ruby/suicide.rb2
-rw-r--r--test/ruby/test_array.rb1159
-rw-r--r--test/ruby/test_beginendblock.rb47
-rw-r--r--test/ruby/test_bignum.rb19
-rw-r--r--test/ruby/test_enum.rb258
-rw-r--r--test/ruby/test_enumerator.rb105
-rw-r--r--test/ruby/test_exception.rb22
-rw-r--r--test/ruby/test_file_exhaustive.rb690
-rw-r--r--test/ruby/test_fixnum.rb26
-rw-r--r--test/ruby/test_float.rb34
-rw-r--r--test/ruby/test_gc.rb4
-rw-r--r--test/ruby/test_hash.rb14
-rw-r--r--test/ruby/test_integer.rb653
-rw-r--r--test/ruby/test_io.rb52
-rw-r--r--test/ruby/test_iterator.rb12
-rw-r--r--test/ruby/test_marshal.rb35
-rw-r--r--test/ruby/test_method.rb180
-rw-r--r--test/ruby/test_objectspace.rb2
-rw-r--r--test/ruby/test_pack.rb261
-rw-r--r--test/ruby/test_pipe.rb14
-rw-r--r--test/ruby/test_proc.rb15
-rw-r--r--test/ruby/test_range.rb9
-rw-r--r--test/ruby/test_regexp.rb465
-rw-r--r--test/ruby/test_require.rb27
-rw-r--r--test/ruby/test_settracefunc.rb6
-rw-r--r--test/ruby/test_signal.rb7
-rw-r--r--test/ruby/test_sleep.rb10
-rw-r--r--test/ruby/test_string.rb13
-rw-r--r--test/ruby/test_super.rb60
-rw-r--r--test/ruby/test_symbol.rb15
-rw-r--r--test/ruby/test_time.rb21
-rw-r--r--test/runner.rb6
-rw-r--r--test/stringio/test_stringio.rb13
-rw-r--r--test/strscan/test_stringscanner.rb13
-rw-r--r--test/test_securerandom.rb178
-rw-r--r--test/testunit/collector/test_dir.rb29
-rwxr-xr-xtest/thread/lbtest.rb51
-rw-r--r--test/thread/test_thread.rb90
-rw-r--r--test/uri/test_common.rb5
-rw-r--r--test/uri/test_ftp.rb22
-rw-r--r--test/uri/test_generic.rb91
-rw-r--r--test/webrick/test_accesslog.rb10
-rw-r--r--test/webrick/test_cookie.rb31
-rw-r--r--test/webrick/test_filehandler.rb68
-rw-r--r--test/webrick/utils.rb10
-rw-r--r--[-rwxr-xr-x]test/webrick/webrick_long_filename.cgi0
-rw-r--r--test/xmlrpc/test_cookie.rb96
-rw-r--r--test/yaml/test_yaml.rb10
-rw-r--r--test/yaml/test_yamlstore.rb74
-rw-r--r--test/zlib/test_zlib.rb514
-rw-r--r--time.c38
-rw-r--r--util.c3573
-rw-r--r--util.h4
-rw-r--r--variable.c167
-rw-r--r--version.c35
-rw-r--r--version.h26
-rw-r--r--win32/Makefile.sub248
-rw-r--r--win32/README.win328
-rwxr-xr-xwin32/configure.bat39
-rw-r--r--win32/dir.h4
-rwxr-xr-x[-rw-r--r--]win32/mkexports.rb17
-rwxr-xr-x[-rw-r--r--]win32/resource.rb26
-rw-r--r--win32/setup.mak38
-rw-r--r--win32/win32.c744
-rw-r--r--win32/win32.h174
-rw-r--r--wince/Makefile.sub489
-rw-r--r--wince/mkconfig_wce.rb7
-rw-r--r--wince/mkexports.rb35
-rw-r--r--wince/resource.rb96
-rw-r--r--x68/_dtos18.c2
-rw-r--r--x68/_round.c2
-rw-r--r--x68/fconvert.c2
-rw-r--r--x68/select.c2
1034 files changed, 81200 insertions, 20377 deletions
diff --git a/.cvsignore b/.cvsignore
index 9fd96ca149..a72211d03f 100644
--- a/.cvsignore
+++ b/.cvsignore
@@ -3,12 +3,14 @@
*.rej
*.sav
*~
+.*.list
+.*.time
.ccmalloc
.ppack
.ext
.git
.svn
-.rbconfig.time
+.pc
COPYING.LIB
ChangeLog.pre-alpha
ChangeLog.pre1_1
@@ -26,32 +28,20 @@ config.h.in
config.log
config.status
configure
-foo.rb
libruby.so.*
miniruby
-miniruby.elhash
-miniruby.elhash2
-miniruby.orig2
-miniruby.plhash
-miniruby.plhash2
-modex.rb
newdate.rb
newver.rb
parse.c
-parse.y.try
-pitest.rb
+patches
ppack
preview
rbconfig.rb
-rename2.h
repack
riscos
rubicon
ruby
ruby-man.rd.gz
-rubyunit
-st.c.power
-this that
tmp
web
y.output
diff --git a/ChangeLog b/ChangeLog
index bcc0744c7e..ce54d1244d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,72 +1,2992 @@
-Sun Jun 8 01:17:45 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+Thu Jun 30 12:52:56 2011 WATANABE Hirofumi <eban@ruby-lang.org>
- * {bcc32,win32}/Makefile.sub (COMMON_MACROS): workaround for old SDK's
- bug. [ruby-core:12584]
+ * ext/tk/extconf.rb (intptr_t, uintptr_t): support for the latest ActiveTcl with mingw.
-Sun Jun 8 00:56:44 2008 GOTOU Yuuzou <gotoyuzo@notwork.org>
+Sun Jun 26 17:52:32 2011 Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
- * lib/net/http.rb, lib/open-uri.rb: remove
- Net::HTTP#enable_post_connection_check. [ruby-dev:31960]
+ * ext/openssl/ossl_ssl.c: By trunk@31346, function check of SSLv2 is executed.
+ However, the problem is not revised in this.
+ This adds the control of using function of SSLv2 in made macro by function check.
- * lib/net/imap.rb: hostname should be verified against server's
- indentity as persented in the server's certificate. [ruby-dev:31960]
+Sun Jun 26 17:52:32 2011 Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
- * ext/openssl/lib/net/telnets.rb, ext/openssl/lib/net/ftptls.rb: ditto.
+ * ext/openssl/extconf.rb: Should check SSLv2_*method.
+ openssl compiled with "no-ssl2" the extconf don't fail
+ when running `make' having this compilation errors.
+ Patched by Laurent Arnoud. fixes #4562, #4556
-Thu Jun 5 16:19:27 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+Sun Jun 26 17:46:43 2011 URABE Shyouhei <shyouhei@ruby-lang.org>
- * win32/win32.c (make_cmdvector): adjust escaped successive
- double-quote handling. (merge from trunk)
+ * ext/tk/extconf.rb: copy from trunk, as requested by Hidetoshi NAGAI.
-Thu Jun 5 12:24:25 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+Thu Jun 23 18:38:43 2011 Hiroshi Nakamura <nahi@ruby-lang.org>
- * win32/win32.c (init_env): initialize HOME and USER environment
- variables unless set. [ruby-core:12328] (merge from trunk)
+ backported r26281 from ruby_1_8
- * win32/win32.c (NtInitialize, getlogin): ditto.
+ * lib/webrick/accesslog.rb (WEBrick::AccessLog.format): log parameter
+ embedding did not work. See #4913.
- * configure.in, win32/Makefile.sub (LIBS): need to link shell32
- library for SH* functions on mswin32 and mingw32.
+ * test/webrick/test_accesslog.rb: Add for test it.
-Thu Jun 5 12:21:06 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+Thu Jun 16 22:55:02 2011 Hiroshi Nakamura <nahi@ruby-lang.org>
- * gc.c (id2ref): valid id should not refer T_VALUE nor T_ICLASS.
- [ruby-dev:31911]
+ * test/test_securerandom.rb: Add testcase. This testcase does NOT aim
+ to test cryptographically strongness and randomness. It includes
+ the test for PID recycle issue of OpenSSL described in #4579 but
+ it's disabled by default.
-Wed Jun 4 16:39:56 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Mon Jun 13 18:33:04 2011 Tanaka Akira <akr@fsij.org>
- * Makefile.in (ext/extinit.o): use $(OUTFLAG) as well as other
- objects. [ruby-Bugs-14228]
+ * lib/securerandom.rb (SecureRandom.random_bytes): modify PRNG state
+ to prevent random number sequence repeatation at forked
+ child process which has same pid.
+ reported by Eric Wong. [ruby-core:35765]
-Tue Jun 3 16:13:40 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Thu Jun 2 18:33:51 2011 URABE Shyouhei <shyouhei@ruby-lang.org>
- * parse.y (yyerror): limit error message length. [ruby-dev:31848]
+ * variable.c (rb_const_get_0): Fix previous change. There were
+ possibilities when an autoload-specified library lacks
+ definition of the constant it was bound to. Once after such
+ library had already beed loaded, the autoload engine shall not
+ reload it. Instead the interpreter have to consider such
+ constant nonexistent. It results in a const_missing situation.
- * regex.c (re_mbc_startpos): separated from re_adjust_startpos.
+ * variable.c (rb_autoload_load): ditto.
-Tue Jun 3 15:27:11 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+ * variable.c (autoload_node): ditto.
- * gc.c (os_obj_of, os_each_obj): hide objects to be finalized.
- [ruby-dev:31810]
+Thu Jun 2 18:28:58 2011 URABE Shyouhei <shyouhei@ruby-lang.org>
-Wed Jun 4 19:15:57 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+ * variable.c (rb_autoload_load): There is a race condition while
+ autoloading. When two or more threads touch a single autoloaded
+ constant at a time, one of them does the require, but others
+ behave oddly. To fix this situation we now refrain from
+ deleting the autoload table while someone is doing the autoload.
+ That deletion is deferred to a point where a require ended
+ successfully. Doing so make it possible for multiple threads to
+ enter autoloading at the same time but the require is protected
+ against multiple simultaneous entrance anyway so all but one
+ thread gets blocked at that point. So with it, touching a
+ constant that gets autoloaded cause those threads to block until
+ there is another one that does the same thing.
+ [ruby-core:36308] (#921)
- * eval.c (remove_method): should not remove undef place holder.
- [ruby-dev:31817]
+ * variable.c (rb_const_get_0): ditto.
-Tue Jun 3 15:05:48 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+ * variable.c (autoload_node): ditto.
- * process.c (struct rb_exec_arg): proc should be a VALUE.
+ * variable.c (autoload_delete): ditto.
- * process.c (rb_f_exec): suppress a warning.
+Mon May 30 10:58:17 2011 Hiroshi Nakamura <nahi@ruby-lang.org>
- * process.c (rb_detach_process): cast for the platforms where size of
- pointer differs from size of int.
+ * lib/logger.rb (Logger::ProgName): do not depend on subversion
+ keyword ($Id$). ProgName with revision number was written in the
+ header line of each logfile for ease of tracking what version user
+ is using in troubleshooting. Logger is already stable enough.
- * process.c (rb_f_exec, rb_f_system): should not exceptions after
- fork. [ruby-core:08262]
+Sat May 21 07:33:54 2011 Yusuke Endoh <mame@tsg.ne.jp>
+
+ * ext/zlib/zlib.c (zstream_append_input2): add RB_GC_GUARD.
+ This caused failure when test/csv is executed with GC.stress = true.
+
+Sat May 21 05:43:03 2011 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * eval.c (rb_thread_atfork): When a ruby process forks, its random
+ seed shall be reinitialized to prevent CVE-2003-0900 situation.
+ This bug affects for 1.8 and earlier series, but not for 1.9.
+ fixed [ruby-core:34944].
+
+ * io.c (pipe_open): ditto.
+
+ * random.c (rb_reset_random_seed): ditto.
+
+ * intern.h (rb_reset_random_seed): ditto.
+
+Sat May 21 04:55:15 2011 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/uri/generic.rb (#route_from_path): Fix a bug where
+ URI('http://h/b/').route_to('http://h/b') wrongly returned './'
+ (should be '../b'). [Bug #4476]
+
+Sat May 21 04:54:20 2011 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/fileutils.rb (FileUtils#touch): Fix corrupted output.
+ ref [ruby-dev:43401]
+
+Sat May 21 02:10:09 2011 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * re.h (RMATCH_REGS): parenthesize cast expression. suggested
+ from Nikolai Weibull in [ruby-core:35825].
+
+Sat May 21 01:32:08 2011 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ backported r31286 from trunk
+
+ * numeric.c (ruby_float_step): wrong loop condition.
+ fixes [ruby-core:35753], reported by Joey Zhou.
+
+ * test/ruby/test_range.rb (TestRange#test_step_ruby_core_35753):
+ test above change.
+
+Sat May 21 00:55:21 2011 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/zlib/zlib.c (gzfile_check_footer): ISIZE (Input SIZE) in gzip's
+ header is the size of uncompressed input data modulo 2^32.
+ [ruby-core:34481] http://www.ietf.org/rfc/rfc1952.txt
+
+Fri May 20 23:46:44 2011 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/socket/{getaddrinfo,getnameinfo}.c: include winsock2.h only when
+ specified to use winsock2 by user.
+ this problem is reported by kosaki.
+
+Fri May 20 23:23:45 2011 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/socket/socket.c (make_addrinfo): skip IPv6 addresses when ruby
+ doesn't support IPv6 but system supports it.
+ [ruby-dev:42944] (#4230)
+
+Fri May 20 23:10:07 2011 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/README.win32: note to need NT based OS to build ruby.
+
+ * win32/{configure.bat,setup.mak}: backport current build method from
+ trunk. [ruby-dev:42893] (#4206)
+
+Fri May 20 23:06:31 2011 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * Backported the fix at
+ Mon Sep 13 09:23:58 2010 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/openssl/ossl_bn.c (ossl_bn_is_prime): fix comparison
+ with rb_scan_args. Before this fix, OpenSSL::BN#prime?
+ is fully broken.
+
+Fri May 20 23:06:31 2011 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * Backported the fix at
+ Mon Oct 4 09:30:42 2010 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/openssl/lib/openssl/bn.rb (Integer#to_bn): OpenSSL::BN.new
+ accepts only Strings, so call Integer#to_s(16).
+ 16 is for an optimization. [ruby-dev:42336]
+
+Fri Feb 18 21:18:55 2011 Shugo Maeda <shugo@ruby-lang.org>
+
+ * test/ruby/test_exception.rb (TestException::test_to_s_taintness_propagation):
+ Test for below.
+
+Fri Feb 18 21:18:55 2011 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * error.c (exc_to_s): untainted strings can be tainted via
+ Exception#to_s, which enables attackers to overwrite sane strings.
+ Reported by: Yusuke Endoh <mame at tsg.ne.jp>.
+
+ * error.c (name_err_to_s): ditto.
+
+Fri Feb 18 21:17:22 2011 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/fileutils.rb (FileUtils::remove_entry_secure): there is a
+ race condition in the case where the given path is a directory,
+ and some other user can move that directory, and create a
+ symlink while this method is executing.
+ Reported by: Nicholas Jefferson <nicholas at pythonic.com.au>
+
+Fri Feb 18 19:46:46 2011 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (init_stdhandle): backport mistake of r29382.
+ some code are needless in ruby 1.8.
+ [ruby-core:34579]
+
+Fri Feb 18 19:22:17 2011 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * configure.in: revert revision r29854. This revision introduced
+ binary incompatibilities on some circumstances. The bug that
+ revision was fixing gets reopened by this reversion.
+ [ruby-dev:43152] cf. [Bug #2553]
+
+Thu Dec 23 12:22:35 2010 Tanaka Akira <akr@fsij.org>
+
+ * lib/resolv.rb (Resolv::IPv4::Regex): make it only accept 0 to 255.
+ [ruby-core:29501]
+
+Tue Dec 21 01:43:01 2010 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * lib/webrick/https.rb: uninitialized instance variables.
+ Backport a part of r20864 for ruby_1_8.
+
+Sat Dec 4 11:35:15 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (init_mkmf): needs default library path even if
+ cross compiling.
+
+Sat Dec 4 11:25:02 2010 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * re.c (rb_reg_regcomp): should succeed the taint status from the
+ origin. [ruby-core:33338]
+
+Thu Dec 2 21:13:42 2010 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * Makefile.in (fake.rb): need to expand the topdir in case of it
+ being relative, a patch from Luis Lavena <luislavena at gmail.com>.
+ [ruby-core:33466]
+
+Wed Nov 24 18:24:26 2010 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/socket/extconf.rb: backported entirely from ruby_1_8, with small
+ modifications for the difference of mkmf.rb.
+
+Wed Nov 24 16:24:24 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * mkconfig.rb (patchlevel): config.status may not contain
+ PATCHLEVEL even if other version numbers exist.
+
+Wed Nov 24 16:18:02 2010 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * win32/Makefile.sub ($(RCFILES)): no revision.h in this
+ branch, a patch from Luis Lavena <luislavena at gmail.com>.
+ [ruby-core:33310]
+
+ * cygwin/GNUmakefile.in ($(RCFILES)): ditto.
+
+Wed Nov 24 15:44:11 2010 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/socket/extconf.rb (getaddrinfo): should initialize winsock on
+ windows.
+
+Wed Nov 24 13:55:21 2010 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/setup.mak: use findstr.exe instead of find.exe, because all
+ target build platforms should have findstr.exe, and, find.exe often
+ means another command such as cygwin's.
+
+Wed Nov 24 13:27:34 2010 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * ext/stringio/stringio.c (strio_getline): fix for "" as separator.
+ [ruby-dev:34591] (Backport r17739 by Yusuke Endoh from trunk).
+
+Wed Nov 24 13:27:20 2010 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * lib/net/pop.rb (Net::POP3#set_all_uids): speed
+ up. a patch from <m-sumi AT techfirm.co.jp> [ruby-list:45047]
+
+Tue Nov 23 20:48:10 2010 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/imap.rb (initialize): sets sync_close to true.
+ Thanks, Hiroshi NAKAMURA. [ruby-core:31753]
+
+Tue Nov 23 17:09:14 2010 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * lib/pathname.rb (relative_path_from): backport r23093 and r25440
+ from ruby_1_9_2. [ruby-core:32415]
+
+Mon Nov 22 14:13:45 2010 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: fix checking version of GCC.
+
+Mon Nov 22 14:13:45 2010 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: NONAMELESSUNION defined only if gcc
+ version is older than 3.4.4. [ruby-core:31567] [Bug #3637]
+ * ext/win32ole/extconf.rb: ditto.
+
+Fri Nov 19 19:28:00 2010 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * Makefile.in (fake.rb): hook needed to fake mkmf.rb.
+ #2531 [ruby-core:27327]
+
+Mon Oct 18 10:21:01 2010 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/net/http.rb (transport_request): @socket may be nil.
+ patched by Egbert Eich [ruby-core:32829]
+
+Fri Oct 8 10:51:56 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (RBCONFIG): depends on version.h due to
+ RUBY_PATCHLEVEL. [ruby-core:32709]
+
+Thu Oct 7 18:10:35 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * cygwin/GNUmakefile.in, win32/Makefile.sub (RCFILES): depend on
+ real config.rb file. [ruby-core:32709]
+
+Sun Oct 3 18:30:23 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (rb_intern): should check symbol table overflow.
+ #3900 [ruby-dev:42330]
+
+Fri Oct 1 15:12:05 2010 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (init_stdhandle): redirect unopened IOs to NUL.
+ backport r11362 from trunk. [ruby-core:31445]
+
+Mon Aug 23 11:42:41 2010 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * ext/openssl/ossl_asn1.c (obj_to_asn1bool): fixed ASN1::Boolean
+ encoding issue for OpenSSL 1.0.0 compatibility.
+ ASN1::Boolean.new(false).to_der wrongly generated "\1\1\377" which
+ means 'true'. [BUG:3735]
+
+ ASN1_TYPE_set of OpenSSL <= 0.9.8 treats value 0x100 as 'false' but
+ OpenSSL >= 1.0.0 treats it as 'true'. ruby-ossl was using 0x100 for
+ 'false' for backward compatibility. Just use 0x0 for the case
+ OpenSSL >= OpenSSL 0.9.7.
+
+ * test/openssl/test_asn1.rb: test added.
+
+Tue Aug 10 17:35:49 2010 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/webrick/httprequest.rb (WEBrick::HTTPRequest::parse_uri):
+ rollup leading slashes. [ruby-core:31657]
+ patched by Jamison Wilde
+ NOTE: //authority/path is valid relative URI both RFC2396 and
+ RFC3986. So when give a relative URI-like string to URI lib,
+ users must care leading slashes.
+
+Fri Jul 30 08:51:51 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (file_expand_path): home directory must be absolute.
+ [ruby-core:31537]
+
+Fri Jul 30 08:33:20 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (file_expand_path): should check if could find user.
+ [ruby-core:31538]
+
+Thu Jul 29 22:43:57 2010 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * lib/webrick/ssl.rb (WEBrick::Utils.create_self_signed_cert): wrongly
+ created dummy SSL certificate with version == 3 (no such version) and
+ serial == 0 (must be >0).
+
+Sat Jul 24 15:44:29 2010 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (fev_initialize): initialize pTypeInfo.
+ [ruby-core:31304][Bug #3576].
+
+Tue Jul 13 21:46:38 2010 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * ext/openssl/ossl_config.c, ext/openssl/lib/openssl/config.rb,
+ ext/openssl/lib/openssl.rb: reimplement OpenSSL::Config in Ruby. Now
+ it should work on windows.
+
+ * test/openssl/test_config.rb: added tests for OpenSSL::Config#dup.
+
+Mon Jul 12 22:26:00 2010 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * ext/openssl/ossl_config.c (ossl_config_copy): wrongly updating the
+ given object with uninitialized CONF data. now
+ OpenSSL::Config#clone works as expected; cloning the config instead of
+ SEGV or empty definition.
+
+ * test/openssl/test_config.rb: added tests for Config#clone.
+
+Thu Jul 8 13:43:13 2010 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * test/openssl/test_config.c: added tests for all Config methods.
+
+Wed Jul 7 13:24:24 2010 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * file.c (ruby_find_basename): set correct baselen.
+
+Fri Jul 2 23:34:45 2010 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * file.c (ruby_find_basename, ruby_find_extname): split from
+ rb_file_s_basename() and rb_file_s_extname().
+
+ * util.c (ruby_add_suffix): support arbitrary length of the suffix
+ to get rid of the potential buffer overflow.
+ reported by tarui.
+
+Sat Jul 10 10:51:29 2010 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * configure.in: fix use_context condition inversion.
+ [Bug #2553][ruby-core:31164]. Thanks, Andre Nathan.
+
+Wed Jun 23 21:36:45 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: avoid getcontext() overhead if possible.
+ [ruby-core:27380][Bug #2553]
+ Thanks, Joe Damato, Dan Peterson and Patrick Mohr.
+
+Wed Jan 13 06:54:44 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: check for if struct timezone is defined.
+
+ * missing.h (struct timezone): define if not defined.
+
+ * win32/win32.h (struct timezone): defined in the newer w32api.
+ [ruby-core:27515]
+
+Sun Aug 15 19:59:58 2010 Yuki Sonoda (Yugui) <yugui@yugui.jp>
+
+ * lib/webrick/httpresponse.rb (WEBrick::HTTPResponse#set_error):
+ Fix for possible cross-site scripting (CVE-2010-0541).
+ Found by Apple, reported by Hideki Yamane.
+ Patch by Hirokazu Nishio <nishio.hirokazu AT gmail.com>.
+
+Sat Jul 17 15:19:58 2010 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * configure.in: Change AC_PREREQ from 2.58 to 2.60 because
+ AC_CASE macro require 2.60 or later. Thanks, Mitsuru SHIMAMURA.
+ [Bug #3579] [ruby-dev:41856]
+
+Wed Jun 23 22:22:42 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/optparse/test_summary.rb: fixed superclass so that it run
+ solely.
+
+Wed Jun 23 21:54:17 2010 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * marshal.c, test/ruby/test_marshal.rb: Revert r25230. This test
+ is troublesome.
+
+Mon Jun 21 18:12:15 2010 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/openssl/extconf.rb: check some functions added at OpenSSL 1.0.0.
+
+ * ext/openssl/ossl_engine.c (ossl_engine_s_load): use engines which
+ exists.
+
+Mon Jun 21 18:12:15 2010 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * ext/openssl/ossl_config.c: defined own IMPLEMENT_LHASH_DOALL_ARG_FN_098
+ macro according to IMPLEMENT_LHASH_DOALL_ARG_FN in OpenSSL 0.9.8m.
+ OpenSSL 1.0.0beta5 has a slightly different definiton so it could
+ be a temporal workaround for 0.9.8 and 1.0.0 dual support.
+
+ * ext/openssl/ossl_pkcs5.c (ossl_pkcs5_pbkdf2_hmac): follows function
+ definition in OpenSSL 1.0.0beta5. PKCS5_PBKDF2_HMAC is from 1.0.0
+ (0.9.8 only has PKCS5_PBKDF2_HMAC_SHA1)
+
+ * ext/openssl/ossl_ssl_session.c (ossl_ssl_session_eq): do not use
+ SSL_SESSION_cmp and implement equality func by ousrself. See the
+ comment.
+
+Mon Jun 21 18:12:15 2010 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * ext/openssl/ossl_ssl_session.c
+ (ossl_ssl_session_{get,set}_time{,out}): fixed a bug introduced by
+ backporting. (see [ruby-dev:40573]) use long in according to
+ OpenSSL API. (SSL_SESSION_{get,set}_time{,out})
+
+Mon Jun 21 18:12:15 2010 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * ext/openssl/ossl_x509name.c: added X509::Name#hash_old as a wrapper
+ for X509_NAME_hash_old in OpenSSL 1.0.0.
+
+ * test/openssl/test_x509name.rb (test_hash): make test pass with
+ OpenSSL 1.0.0.
+
+Mon Jun 21 18:12:15 2010 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * test/openssl/test_x509*: make tests pass with OpenSSL 1.0.0b5.
+ * PKey::PKey#verify raises an exception when a given PKey does not
+ match with signature.
+ * PKey::DSA#sign accepts SHA1, SHA256 other than DSS1.
+
+Mon Jun 21 18:12:15 2010 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * backport the commit from trunk:
+ Sun Feb 28 11:49:35 2010 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * openssl/ossl.c (OSSL_IMPL_SK2ARY): for OpenSSL 1.0.
+ patched by Jeroen van Meeuwen at [ruby-core:25210]
+ fixed by Nobuyoshi Nakada [ruby-core:25238],
+ Hongli Lai [ruby-core:27417],
+ and Motohiro KOSAKI [ruby-core:28063]
+
+ * ext/openssl/ossl_ssl.c (ossl_ssl_method_tab),
+ (ossl_ssl_cipher_to_ary): constified.
+
+ * ext/openssl/ossl_pkcs7.c (pkcs7_get_certs, pkcs7_get_crls):
+ split pkcs7_get_certs_or_crls.
+
+Mon Jun 21 18:12:15 2010 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * test/openssl/test_ec.rb: added test_dsa_sign_asn1_FIPS186_3. dgst is
+ truncated with ec_key.group.order.size after openssl 0.9.8m for
+ FIPS 186-3 compliance.
+
+ WARNING: ruby-openssl aims to wrap an OpenSSL so when you're using
+ openssl 0.9.8l or earlier version, EC.dsa_sign_asn1 raises
+ OpenSSL::PKey::ECError as before and EC.dsa_verify_asn1 just returns
+ false when you pass dgst longer than expected (no truncation
+ performed).
+
+ * ext/openssl/ossl_pkey_ec.c: rdoc typo fixed.
+
+Wed Jun 16 16:01:42 2010 Tanaka Akira <akr@fsij.org>
+
+ * lib/pathname.rb (Pathname#sub): suppress a warning.
+ [ruby-dev:38488]
+
+Wed Jun 16 15:21:12 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/webrick/utils.rb (TestWEBrick#start_server): add log for
+ test_filehandler.rb
+
+Wed Jun 16 15:21:12 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/net/http.rb (Net::HTTPHeader#{content_range,range_length}):
+ use inclusive range same as the header representation.
+
+Thu Jun 10 14:39:35 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/iconv/test_option.rb: removed particular implementation specific tests.
+ [ruby-dev:40078]
+
+Thu Jun 10 14:22:09 2010 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * lib/webrick/httpstatus.rb (WEBrick::HTTPStatus::Status::initialize):
+ accept 0 or more arguments. [ruby-core:28692]
+
+Thu Jun 10 13:37:35 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_load): initialize orig_func. [ruby-core:27296]
+
+Tue Jun 8 18:57:48 2010 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/Makefile.sub (config.status): no need to embbed manifest if not exist.
+
+Tue Jun 8 18:38:36 2010 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * include/ruby/win32.h: include errno.h before defining errnos.
+
+ * include/ruby/win32.h: check definition existance before defining
+ errno macros.
+
+ * win32/win32.c (errmap): define winsock errors mappings.
+ these are VC++10 support, merge from trunk (r27236, r27258).
+
+Tue Jun 8 18:31:02 2010 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * regexp.c (re_compile_pattern): allow zero times match for
+ non-greedy range repeatation. [ruby-core:30613]
+
+Tue Jun 8 18:08:18 2010 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * Makefile.in (fake.rb): double the backslash.
+
+Tue Jun 8 18:08:15 2010 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * configure.in: should replace COMMON_HEADERS if --with-winsock2 is
+ specified. [ruby-dev:41521]
+
+Tue Jun 8 17:49:18 2010 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * io.c, eval.c, process.c: remove all condition of r26371.
+ now, all platform use the same way. [Bug #3278][ruby-core:30167]
+
+Tue Jun 8 17:45:36 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/iconv/iconv.c (rb_iconv_sys_fail): fix number of arguments.
+ a patch by Masaya TARUI <tarui AT prx.jp>.
+
+Tue Jun 8 17:45:36 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/iconv/iconv.c (rb_iconv_sys_fail): raise BrokenLibrary if
+ errno is not set. [ruby-dev:41317]
+
+Tue Jun 8 17:32:37 2010 Tanaka Akira <akr@fsij.org>
+
+ * pack.c (pack_pack): call rb_quad_pack to preserve RangeError.
+
+Tue Jun 8 17:32:37 2010 Tanaka Akira <akr@fsij.org>
+
+ * pack.c: backport integer pack/unpack from 1.9 for [ruby-core:21937].
+
+ * configure.in: backport RUBY_DEFINT and fixed size integer checks.
+
+ * ruby.h: include stdint.h if available.
+
+ * bignum.c (rb_big_pack): defined..
+ (rb_big_unpack): defined.
+
+ * intern.h (rb_big_pack): declared.
+ (rb_big_unpack): declared.
+
+Tue Jun 8 16:52:35 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * regex.c (read_special): get rid of overrun.
+
+Tue Jun 8 16:51:48 2010 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/imap.rb: backported exception handling from trunk.
+ [ruby-core:29745]
+
+Tue Jun 8 16:42:48 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/bigdecimal/bigdecimal.c (VpAlloc): ensure buf does not get
+ collected. based on a patch masaya tarui at [ruby-dev:41213].
+
+Tue Jun 8 16:08:00 2010 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/imap.rb (fetch_internal): do not quote message data item
+ names. Thanks, Eric Hodel. [ruby-core:23508] backported form
+ trunk.
+
+Tue Jun 8 15:45:52 2010 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/imap (encode_utf7): encode & properly. Thanks, Kengo
+ Matsuyama. [ruby-dev:38063] backported from trunk.
+
+Tue Jun 8 15:43:43 2010 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (ole_val2variant): fix the core dump
+ when converting Array object to VT_ARRAY variant. [ruby-core:28446]
+ [Bug #2836]
+
+Tue Jun 8 15:34:15 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (rb_file_s_extname): skip last directory separators.
+ [ruby-core:29627]
+
+Tue Jun 8 15:33:30 2010 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * lib/fileutils.rb (FileUtils::cp_r): dup needed here; options are
+ destroyed otherwise.
+
+Tue Jun 8 15:27:00 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (search_required): expand home relative path first.
+ [ruby-core:29610]
+
+Tue Jun 8 15:23:10 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/timeout.rb (Timeout#timeout): propagate errors to the
+ caller. [ruby-dev:41010]'
+
+Tue Jun 8 15:15:18 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/net/smtp.rb (Net::SMTP#rcptto_list): fixed typo.
+ [ruby-core:29809]
+
+Tue Jun 8 15:15:18 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/net/smtp.rb (Net::SMTP#rcptto_list): continue when at least
+ one RCPT is accepted. based on a patch from Kero van Gelder at
+ [ruby-core:26190].
+
+Tue Jun 8 15:14:11 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * LEGAL: separated the section for parse.c. contributed by Paul
+ Betteridge in [ruby-core:29472].
+
+Tue Jun 8 14:00:33 2010 Keiju Ishitsuka <keiju@ruby-lang.org>
+
+ * ext/rational/lib/rational.rb: fix [Bug #1397].
+
+Tue Jun 8 13:40:04 2010 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date.rb (Date#>>): fixed. [ruby-core:28011]
+
+Tue Jun 8 12:37:56 2010 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * io.c, eval.c, process.c: add linux to r26371's condition.
+ patched by Motohiro KOSAKI [ruby-core:28151]
+
+Tue Jun 8 12:37:56 2010 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * eval.c (thread_timer, rb_thread_stop_timer): check the timing of
+ stopping timer. patch from KOSAKI Motohiro <kosaki.motohiro _AT_
+ jp.fujitsu.com> via IRC.
+
+ * eval.c (rb_thread_start_timer): NetBSD5 seems to be hung when calling
+ pthread_create() from pthread_atfork()'s parent handler.
+
+ * io.c (pipe_open): workaround for NetBSD5. stop timer thread before
+ fork(), and restart it after fork() on parent, and on child if
+ needed.
+
+ * process.c (rb_f_fork, rb_f_system): ditto.
+
+ these changes are tested by naruse. fixed [ruby-dev:40074]
+
+Mon Jun 7 19:23:04 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/nkf/nkf-utf8/nkf.c (numchar_getc): get rid of buffer
+ overflow. [ruby-dev:40606]
+
+Mon Jun 7 18:57:02 2010 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * ext/openssl/ossl_ssl_session.c
+ (ossl_ssl_session_{get,set}_time{,out}): fixed a bug introduced by
+ backporting. (see [ruby-dev:40573]) use long in according to
+ OpenSSL API. (SSL_SESSION_{get,set}_time{,out})
+
+Tue May 25 08:42:42 2010 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * ext/openssl: backport fixes in 1.9.
+
+ * r25019 by marcandre
+ * ossl_ocsp.c (ossl_ocspres_to_der): Bug fix in Response#to_def.
+ Patch by Chris Chandler [ruby-core:18411]
+
+ * r25017 by marcandre
+ * ossl_config.c (ossl_config_add_value_m,
+ ossl_config_set_section): Check if frozen (or untrusted for
+ $SECURE >= 4) [ruby-core:18377]
+
+ * r22925 by nobu
+ * ext/openssl/openssl_missing.h (i2d_of_void): cast for callbacks.
+ [ruby-core:22860]
+
+ * ext/openssl/ossl_engine.c (ossl_engine_s_by_id): suppress a
+ warning.
+
+ * ext/openssl/ossl_ssl.c (ossl_sslctx_flush_sessions): time_t may
+ be larger than long.
+
+ * ext/openssl/ossl_ssl_session.c (ossl_ssl_session_get_time),
+ (ossl_ssl_session_get_timeout): use TIMET2NUM() to convert
+ time_t.
+
+ * r22924 by nobu
+ * ext/openssl/ossl_x509ext.c (ossl_x509ext_set_value): should use
+ OPENSSL_free instead of free. a patch from Charlie Savage at
+ [ruby-core:22858].
+
+ * r22918 by akr
+ * ext/openssl: suppress warnings.
+
+ * ext/openssl/ossl.h (OSSL_Debug): don't use gcc extention for
+ variadic macro.
+
+ * r22666 by akr
+ * ext/openssl/lib/openssl/buffering.rb: define Buffering module
+ under OpenSSL. [ruby-dev:37906]
+
+ * r22440 by nobu
+ * ext/openssl/ossl_ocsp.c (ossl_ocspbres_verify): OCSP_basic_verify
+ returns positive value on success, not non-zero.
+ [ruby-core:21762]
+
+ * r22378 by akr
+ * ext/openssl: avoid cyclic require.
+
+ * ext/openssl/lib/openssl/ssl-internal.rb: renamed from ssl.rb
+
+ * ext/openssl/lib/openssl/x509-internal.rb: renamed from x509.rb.
+ [ruby-dev:38018]
+
+ * r22101 by nobu
+ * ext/openssl/ossl_cipher.c (add_cipher_name_to_ary): used
+ conditionally.
+
+ * r21510 by akr
+ * ext/openssl/ossl.c (ossl_raise): abolish a warning.
+
+ * r21208 by akr
+ * ext/openssl/ossl_digest.c (GetDigestPtr): use StringValueCStr
+ instead of STR2CSTR.
+
+ * ext/openssl/ossl_pkey_ec.c (ossl_ec_key_initialize): ditto.
+ (ossl_ec_group_initialize): ditto.
+
+ * r19420 by mame
+ * ext/openssl/ossl_pkey_ec.c (ossl_ec_key_to_string): comment out
+ fragments of unused code.
+
+ * r18975 by nobu
+ * ext/openssl/ossl_ocsp.c (ossl_ocspres_initialize): fix for
+ initialization of r18168.
+
+ * r18971 by nobu
+ * ext/openssl/ossl_config.c (Init_ossl_config): removed C99ism.
+
+ * r18944 by matz
+ * ext/openssl/ossl_config.c (Init_ossl_config): memory leak fixed.
+ a patch <shinichiro.hamaji at gmail.com> in [ruby-dev:35880].
+
+ * ext/openssl/ossl_x509ext.c (ossl_x509ext_set_value): ditto.
+
+ * r18917 by nobu
+ * ext/openssl/ossl_x509attr.c (ossl_x509attr_initialize): fix for
+ initialization of r18168.
+
+ * ext/openssl/ossl_ocsp.c (ossl_ocspreq_initialize): ditto.
+
+ * ext/openssl/ossl_x509name.c (ossl_x509name_initialize): ditto.
+
+ * r18283 by nobu
+ * ext/openssl/ossl_asn1.c (ossl_asn1_get_asn1type): suppress
+ warnings on platforms which int size differs from pointer size.
+
+ * r18181 by nobu
+ * ext/openssl/openssl_missing.h (d2i_of_void): define for older
+ versions. [ruby-dev:35637]
+
+ * r18168 by nobu
+ * ext/openssl: suppress warnings.
+
+Sat May 22 22:31:36 2010 Tanaka Akira <akr@fsij.org>
+
+ * lib/resolv.rb: fix [ruby-core:28320] reported by Paul Clegg.
+ (Resolv::DNS::Requester#request): raise ResolvTimeout consistently
+ for timeout.
+
+Sat May 22 22:14:11 2010 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/readline/readline.c (Init_readline): initialize
+ check rl_catch_signals and rl_catch_sigwinch.
+ [ruby-core:28238] [ruby-core:28242]
+
+ * ext/readline/extconf.rb: check rl_catch_signals and
+ rl_catch_sigwinch.
+
+Sat May 22 21:54:58 2010 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * test/net/http/test_connection.rb (TestHTTP::HTTPConnectionTest#test_connection_refused_in_request):
+ Wrong exception to assert.
+
+Sat May 22 21:03:16 2010 Tanaka Akira <akr@fsij.org>
+
+ * io.c (rb_io_modenum_mode): return "r" for O_RDONLY|O_APPEND.
+ [ruby-dev:40379]
+
+Sat May 22 20:51:39 2010 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * lib/resolv.rb (Resolv::DNS::Config#nameserver_port): 1.8.7
+ specific tweaks
+
+Sat May 22 20:51:09 2010 Tanaka Akira <akr@fsij.org>
+
+ * lib/resolv.rb: fix [ruby-core:28144] reported by Hans de Graaff.
+ (Resolv::DNS#make_requester): pass nameserver_port to
+ UnconnectedUDP.new.
+ (Resolv::DNS.bind_random_port): change the is_ipv6 argument to
+ bind_host.
+ (Resolv::DNS::Requester#initialize): change instance variable to
+ store multiple sockets.
+ (Resolv::DNS::Requester#request): pass readable sockets to
+ recv_reply.
+ (Resolv::DNS::Requester#close): close all sockets.
+ (Resolv::DNS::Requester::UnconnectedUDP#initialize): allocate
+ a socket for each address family of name servers.
+ (Resolv::DNS::Requester::UnconnectedUDP#recv_reply): read from the
+ passwd readable socket.
+ (Resolv::DNS::Requester::UnconnectedUDP#sender): use appropriate
+ socket for the target nameserver.
+ (Resolv::DNS::Requester::ConnectedUDP): follow the instance variable
+ change.
+ (Resolv::DNS::Requester::TCP#sender): ditto.
+ (Resolv::DNS::Config#nameserver_port): new method.
+
+Sat May 22 19:46:27 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/net/http.rb (Net::HTTP#request): close @socket only after
+ started. [ruby-core:28028]
+
+Sat May 22 19:36:38 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (proc_invoke): reverted r25975. [ruby-dev:39931]
+ [ruby-dev:40059]
+
+ * eval.c (rb_mod_define_method): return original block but not
+ bound block. [ruby-core:26984]
+
+Thu May 20 16:28:17 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/webrick/httpservlet/filehandler.rb (make_partial_content):
+ add bytes-unit. [ruby-dev:40030]
+
+Thu May 20 16:17:37 2010 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * ext/zlib/zlib.c: backport r18029 and r21861 from trunk.
+ * r18029 ext/zlib/zlib.c (rb_deflate_params): flush before
+ deflateParams. [ruby-core:17675] (by mame)
+ * r21861 ext/zlib/zlib.c (zstream_run): desperately guard the
+ variable. [ruby-core:20576] (by usa)
+
+ * test/zlib/test_zlib.rb: backport deflate tests from trunk.
+
+Thu May 20 15:59:14 2010 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rss/maker/base.rb, test/rss/test_maker_0.9.rb:
+ accept any time format in maker. [ruby-core:26923]
+
+Thu May 20 15:54:08 2010 Akinori MUSHA <knu@iDaemons.org>
+
+ * eval.c (recursive_push): Taint internal hash to prevent
+ unexpected SecurityError; fixes #1864.
+
+Thu May 20 15:39:26 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (io_fwrite): preserve errno. [ruby-core:27425]
+
+Tue Apr 20 08:04:37 2010 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * io.c (rb_io_s_read): close the IO if an exception is raised on
+ seeking. [ruby-core:27429]
+
+Mon Apr 19 22:43:28 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ruby.h (RB_GC_GUARD_PTR): workaround for gcc optimization.
+ [ruby-core:27402]
+
+Tue Apr 20 06:40:53 2010 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/uri/generic.rb (URI::Generic::eql): Check the class of the
+ compared object. Based on a patch by Peter McLain [ruby-core:27019]
+
+Fri Apr 2 03:27:22 2010 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * lib/net/http.rb (HTTPGenericRequest#send_request_with_body_stream):
+ increased encoding chunk size for POST request with body_stream
+ (1K -> 16K). patched by Brian Candler. #1284.
+
+ * test/net/http/test_post_io.rb: added for the patch. It's good if a
+ patch comes with a test.
+
+Thu Apr 1 05:32:17 2010 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * string.c (rb_str_inspect): wrong result of UTF-8 inspect because of
+ the mistake of calculation. reported by eban via IRC.
+
+Sun Jan 10 19:00:31 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/webrick/accesslog.rb : Escape needed.
+
+ * lib/webrick/httpstatus.rb : ditto.
+
+ * lib/webrick/httprequest.rb : ditto.
+
+ * lib/webrick/httputils.rb : ditto.
+
+Thu Dec 24 18:04:27 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: default ac_cv_prog_CC to CC.
+
+Thu Dec 24 17:56:32 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/extmk.rb: MINIRUBY is given via make-flag.
+
+Thu Dec 24 17:56:32 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (EXTMK_ARGS): needs MINIRUBY for cross-compile.
+ [ruby-core:20131]
+
+Thu Dec 24 17:56:32 2009 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * common.mk (EXTMK_ARGS): shouldn't use ``\"'' because cmd.exe eat
+ ''\'' in such quotes.
+
+Thu Dec 24 17:56:32 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (EXTMK_ARGS): needs MINIRUBY for cross-compile.
+ [ruby-core:20131]
+
+Thu Dec 24 17:56:32 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * mkconfig.rb (patchlevel): config.status may not contain
+ PATCHLEVEL even if other version numbers exist.
+
+Thu Dec 24 17:50:35 2009 Yusuke Endoh <mame@tsg.ne.jp>
+
+ * ext/stringio/stringio.c (strio_init): rewind when reopened.
+
+Thu Dec 24 17:06:13 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (run_final): runs finalizers with the object terminated.
+
+ * gc.c (rb_gc_call_finalizer_at_exit): ObjectSpace::finalizers needs
+ to scan whole object space, although deprecated.
+
+Thu Dec 24 17:06:13 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (chain_finalized_object): deletes finalizers to be invoked from
+ finalizer_table.
+
+ * gc.c (rb_gc_call_finalizer_at_exit): warns when could not invoke
+ finalizers.
+
+Mon Dec 21 16:09:09 2009 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/Makefile.sub (LD_SHARED1): typo.
+
+Wed Dec 16 20:17:40 2009 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (CreateChild): allocate temporary buffer and use it
+ instead of directly modify the passed string. [ruby-dev:39635]
+
+Wed Dec 16 19:49:47 2009 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * instruby.rb (with_destdir): revert. [ruby-dev:39885]
+
+Mon Dec 14 13:28:48 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/test/unit.rb (Test::Unit.run=, Test::Unit.run?): fixed rdoc.
+ [ruby-core:25034]
+
+Mon Dec 14 13:21:32 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/open3.rb (Open3#popen3): fixed and improved rdoc. [ruby-core:25658]
+
+Mon Dec 14 13:09:01 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (LIBPATHFLAG): use numbered specifier if RPATHFLAG
+ is set. [ruby-talk:322136]
+
+Mon Dec 14 12:53:56 2009 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/bigdecimal.rb: fix comparison operators [ruby-core:26646]
+
+Mon Dec 14 12:40:10 2009 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * object.c (rb_Float): Allow results of to_f to be NaN
+ [ruby-core:26733]
+
+Mon Dec 14 12:35:21 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (proc_invoke): unbound block created by define_method
+ cannot call super. [ruby-core:26984]
+
+Mon Dec 14 12:06:39 2009 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/digest/digest.c (rb_digest_instance_method_unimpl): Do not
+ call rb_inspect() on an object that does not implement necessary
+ methods; reported by NaHi.
+
+Mon Dec 14 11:47:31 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_method_missing): adjusted format and argument number.
+
+ * eval.c (rb_call): fixed for super in cached method.
+ [ruby-dev:39757]
+
+Mon Dec 14 11:40:35 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (ruby_setenv): get rid of crash in Solaris 8 and 10.
+ [ruby-core:26668]
+
+Mon Dec 14 11:31:58 2009 Takeyuki FUJIOKA <xibbar@ruby-lang.org>
+
+ * lib/cgi.rb: fix command-line option of
+ non-interactive terminal. [ruby-core:23016]
+
+Mon Dec 14 03:36:20 2009 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * eval.c (method_inspect, method_name, mnew): Bug fix when
+ method created from an alias.
+ Based on a patch by Peter Vanbroekhoven [ruby-core:22040]
+
+Mon Dec 14 02:27:32 2009 Yusuke Endoh <mame@tsg.ne.jp>
+
+ * hash.c (rb_hash): always return a fixnum value because a return
+ value of rb_hash may be used as a hash value itself and bignums have
+ no unique VALUE.
+
+ * test/ruby/test_hash.rb: add a test for above.
+
+Mon Dec 14 00:42:55 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_inspect): get rid of adding garbage to shor
+ UTF-8 string. [ruby-dev:39550]
+
+Sun Dec 13 23:54:22 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * marshal.c (marshal_load): should set taintness. [ruby-dev:39723]
+
+Sun Dec 13 23:54:22 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * marshal.c (struct {dump,load}_arg): manage with dfree, instead
+ of using local variable which may be moved by context switch.
+ [ruby-dev:39425]
+
+Wed Nov 25 17:42:33 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (io_fwrite): adjust stdio file position after direct write on
+ BSDish platforms. [ruby-core:26300]
+
+Wed Nov 25 17:39:28 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/ostruct/test_ostruct.rb (test_frozen): added assertions.
+
+Wed Nov 25 16:43:24 2009 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * lib/monitor.rb (MonitorMixin.mon_release): ensure the scheduled
+ thread to be alive when a thread is releasing a monitor. #2240
+
+Wed Nov 25 16:28:11 2009 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/rexml/element.rb (text=): false should be converted to string.
+ A patch by Teruo Oshida [ruby-dev:38351]
+
+Wed Nov 25 16:18:37 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_clear_cache_for_undef): clear entries for inherited
+ methods. [ruby-core:26074]
+
+Tue Nov 24 16:15:18 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/iconv/iconv.c (iconv_create): cannot retry with given block.
+ [ruby-dev:39487]
+
+Tue Nov 24 16:12:33 2009 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/imap.rb (resp_text_code): accepts response codes without
+ text. backported from trunk. [ruby-core:24194]
+
+Tue Nov 24 16:09:41 2009 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/ftp.rb (getaddress): rescue exceptions. [ruby-dev:39451]
+
+Tue Nov 24 15:51:07 2009 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * ext/curses/curses.c: Many functions of module Curses could cause a
+ crash if the ncurses library was not properly initialized.
+ Fix pointed out by Alexander Beisig [ruby-core:22592]
+ Functions fixed: attroff, attron, attrset, bkgd, bkgdset,
+ can_change_color, close_screen, closed, color_content, curs_set,
+ def_prog_mode, delch, deleteln, getmouse, getstr, has_colors,
+ init_color, init_pair, insertln, keyname, mouseinterval, mousemask,
+ pair_content, pair_number, reset_prog_mode, resizeterm, scrl,
+ setscrreg, standend, standout, start_color, timeout, ungetmouse
+
+Fri Nov 20 15:49:59 2009 Tanaka Akira <akr@fsij.org>
+
+ * lib/resolv.rb (Resolv::DNS.bind_random_port): bind to "::" for IPv6.
+ (Resolv::DNS::ConnectedUDP#initialize): specify is_ipv6 argument of
+ bind_random_port.
+ [ruby-core:25970]
+
+Thu Nov 19 18:03:31 2009 Takeyuki FUJIOKA <xibbar@ruby-lang.org>
+
+ * lib/cgi.rb (CGI.unescapeHTML): fix for hex values 80-FF,
+ single-byte hex entity encodings from 80-FF are valid HTML.
+ [ruby-core:25702]
+
+Thu Nov 19 15:34:40 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * io.c (rb_io_fptr_finalize): free fptr to avoid memory leaks.
+ fixed: #2009 [ruby-core:25173] [ruby-dev:39410]
+
+Thu Nov 19 15:27:17 2009 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/net/http.rb (transport_request): Handle timeout error by
+ closing socket if exception raised. [ruby-core:20976]
+
+Wed Nov 18 14:14:38 2009 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * ext/openssl/ossl_config.c (ossl_config_add_value_m,
+ ossl_config_set_section): Check if frozen (or untainted for $SECURE >=
+ 4) [ruby-core:18377]
+
+Wed Nov 18 14:13:14 2009 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * instruby.rb: win32/win32.h exists in srcdir.
+ reported by arton ( http://www.artonx.org/diary/20090919.html#p01 )
+
+Wed Nov 18 14:13:14 2009 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (subtract): if the parameters are same value, should
+ return zero.
+
+Wed Nov 18 14:13:14 2009 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_select): of course, need to initialize rest.
+
+Wed Nov 18 14:13:14 2009 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_select): wait specified time on select.
+
+Wed Nov 18 14:13:14 2009 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_select): on 1.8, we don't need to poll sockets,
+ because our select is never called from multiple threads.
+
+Tue Nov 17 16:22:22 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_thread_start_0, rb_thread_start_1): should call star
+ timer after added new thread to thread list. [ruby-core:25613]
+
+Tue Nov 17 16:22:22 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_thread_start_timer): start to catch SIGVTALRM together
+ with timer thread. [ruby-core:25606]
+
+ * eval.c (rb_thread_atfork): stop timer thread.
+
+Tue Nov 17 16:04:02 2009 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/cgi/cookie.rb (value): Keep CGI::Cookie#value in sync with the
+ cookie itself. A patch by Arthur Schreiber [ruby-core:17634]
+
+Tue Nov 17 15:49:00 2009 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/irb/ext/multi-irb.rb: Fix arguments handling for shell commands
+ in irb; a patch by Yusuke Endoh [ruby-dev:35075]
+
+Tue Nov 17 15:32:27 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (rb_io_binmode): check if closed regardless platforms.
+ [ruby-core:25363]
+
+Tue Nov 17 15:31:09 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (round): added declaration. [ruby-dev:39222]
+
+Mon Nov 16 19:58:02 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (gc_sweep): makes new room if object space is full of
+ finalized objects and has no free objects. [ruby-dev:39201]
+
+Mon Nov 16 19:45:27 2009 Tanaka Akira <akr@fsij.org>
+
+ * util.c: suppress strict-aliasing warning with gcc-4.4.0 -O2 to fix
+ infinite loop by ruby -e "1.402e-45" .
+
+Mon Nov 16 19:28:23 2009 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_to_i): revert a part of
+ r23645, which was not a bug fix. [ruby-dev:39474]
+
+Fri Sep 11 11:56:53 2009 Akinori MUSHA <knu@iDaemons.org>
+
+ * class.c (rb_singleton_class_clone): Qnil must be used for a null
+ class reference when we use NIL_P() to check class reference
+ validity. The bug was exposed by the spec test of Sequel.
+
+ * eval.c (ruby_init): Use NEW_CREF().
+
+Thu Sep 10 10:53:03 2009 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * io.c (rb_sysopen): workaround for MSVCRT's bug.
+ [ruby-core:24838]
+
+Mon Sep 7 19:52:44 2009 Tanaka Akira <akr@fsij.org>
+
+ * eval.c (rb_thread_schedule): need select for WAIT_SELECT, even if
+ already timeout. [ruby-dev:38971]
+ (WAIT_DONE): defined for mark threads which can be runnable.
+
+Mon Sep 7 19:52:44 2009 Tanaka Akira <akr@fsij.org>
+
+ * eval.c (rb_thread_schedule): refine previous change.
+
+Mon Sep 7 19:52:44 2009 Tanaka Akira <akr@fsij.org>
+
+ * eval.c (rb_thread_schedule): fix condition for making thread
+ runnable. [ruby-core:23515]
+
+Sun Sep 6 19:47:10 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_exc_raise, rb_exc_fatal): require exception object.
+ [ruby-core:24767]
+
+Sun Sep 6 01:34:03 2009 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_connect): return value was broken when some
+ error occurred.
+ [ruby-core:24234]
+
+Fri Sep 4 10:03:22 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (argf_eof): go to the next file if called after ARGF.close
+ or ARGF.skip. a patch from Mike Kasick at [ruby-core:24561].
+
+Sun Aug 9 17:43:44 2009 Keiju Ishitsuka <keiju@ruby-lang.org>
+
+ * lib/irb.rb, lib/irb/init.rb, lib/irb/ext/save-history.rb: add
+ IRB::irb_at_exit. no use finalizer saving history. [ruby-dev-38563]
+
+Wed Aug 5 15:29:54 2009 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * io.c (rb_io_flush): fsync() after buffer is flushed on win32.
+ backported from trunk. [ruby-core:20043]
+
+
+Tue Aug 4 11:00:30 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * re.h (RMATCH_REGS): added for compatibility.
+
+Mon Aug 3 14:46:53 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/complex.rb (Numeric#arg): should return NaN for NaN.
+ [ruby-core:24116]
+
+Thu Jul 30 09:27:44 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (big_lshift, big_rshift): return Bignum always withou
+ normalization. [ruby-dev:38680]
+
+Wed Jul 29 11:19:47 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * io.c (argf_close): always call #close method. [ruby-core:23853]
+
+ * io.c (argf_skip): should close only when current_file is available.
+
+Sat Jul 25 21:26:18 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * enum.c (first_i): Enumerator#first should consume only what is
+ needed. a patch from Marc-Andre Lafortune. [ruby-core:23661]
+
+ * enum.c (take_i): ditto.
+
+ * enum.c (enum_first): call to_int once for an argument. a patch
+ from Marc-Andre Lafortune.
+
+Fri Jul 24 17:19:40 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/cgi.rb (HTTP_STATUS): typo fixed. [ruby-dev:38538]
+
+Wed Jul 22 23:39:34 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/rexml/text.rb (REXML::Text.normalize): call to_s for input.
+ [ruby-talk:337069]
+
+Tue Jul 21 18:21:47 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (SRC_EXT): should be flat.
+ http://twitter.com/_tad_/status/1825862632
+
+Sat Jul 18 00:44:43 2009 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * gc.c (rb_gc_call_finalizer_at_exit): finalizer_table can be NULL.
+ [ruby-core:24395]
+
+Thu Jul 16 09:35:06 2009 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/delegate.rb (Delegator#method_missing)
+ (DelegateClass()#method_missing): Properly pass a given block
+ through. [ruby-dev:38390]
+
+Wed Jul 15 11:40:34 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (rb_file_join): recursive array has no meaning as path
+ name. [ruby-core:23329]
+
+Tue Jul 14 19:57:28 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (get_ts): use readtime clock. [ruby-dev:38354]
+
+ * eval.c (rb_thread_stop_timer): clear thread_init while locking.
+
+Tue Jul 14 19:57:28 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_thread_start_timer): guard condition was inverted.
+ [ruby-dev:38319]
+
+Tue Jul 14 19:57:28 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (safe_mutex_lock): pthread_cleanup_push() must not be
+ inside parens.
+
+Mon Jul 13 01:36:54 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * time.c (time_timeval): rounds subsecond toward zero.
+
+Mon Jul 13 01:36:54 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * time.c (time_timeval): check out-of-range. [ruby-core:23282]
+ [Bug #1396]
+
+Thu Jul 9 17:58:03 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (proc_invoke): shares dmethod scope local variables.
+ a patch from coderrr at [ruby-core:23050]
+
+ * gc.c (obj_free): do not free cloned scope local variables.
+
+Wed Jul 8 19:28:03 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_thread_remove): stops timer thread unless other
+ threads exist. [ruby-core:18444]
+
+Mon Jul 6 16:01:38 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_eval): checks for interrupt, stack and finalizers too.
+ [ruby-dev:38208], [Bug #1329]
+
+ * eval.c (eval): replaces the message if frozen.
+
+Sun Jul 5 03:50:52 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/test/unit.rb: use Kernel.exit to get rid of using
+ IRB::ExtendCommandBundle#exit. a patch from Dmitry Vazhov by
+ [ruby-core:22986].
+
+Fri Jul 3 09:05:38 2009 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * lib/drb/drb.rb (open_server_inaddr_any): fixed multiple network
+ families problem. a patch from Charl Matthee at [ruby-core:21033].
+
+Wed Jul 1 15:46:30 2009 Tanaka Akira <akr@fsij.org>
+
+ * lib/pathname.rb (Pathname#sub): set $~ in block.binding.
+ [ruby-dev:38173]
+
+Mon Jun 29 13:18:42 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/fileutils.rb (FileUtils#fu_get_gid): stringify group
+ argument before making regexp match. [ruby-dev:38155]
+
+Fri Jun 12 16:36:44 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * ext/bigdecimal/bigdecimal.c (VpToString): fixed a bug introduced
+ in r23613. [ruby-talk:338957]
+
+Mon Jun 8 10:58:41 2009 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * eval.c (rb_thread_schedule): mswin32 doesn't have F_GETFD, so check
+ with another method.
+
+Mon Jun 8 08:15:36 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * ext/bigdecimal/bigdecimal.c (VpAlloc): avoid ALLOCA_N() to avoid
+ segmentation fault caused by (insanely) long decimal values.
+ backported from 1.9. CVE-2009-1904
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_dump, BigDecimal_to_i,
+ BigDecimal_to_f, BigDecimal_to_s, BigDecimal_split,
+ BigDecimal_inspect): ditto.
+
+Mon Jun 8 08:15:36 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_to_f): returns Inf if
+ exp is bigger than DBL_MANT_DIG.
+
+Wed Jun 3 21:16:30 2009 Tanaka Akira <akr@fsij.org>
+
+ * file.c: include fcntl.h for O_RDONLY on Solaris.
+
+Wed Jun 3 21:09:56 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * util.c (rv_strdup): macro to duplicate nul-terminated string.
+ [ruby-core:22852]
+
+ * util.c (ruby_dtoa): allocates one more byte to get rid of buffer
+ overrun. a patch from Charlie Savage at [ruby-core:22604].
+
+Wed Jun 3 21:09:56 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * util.c (ruby_dtoa): allocates one more byte to get rid of buffer
+ overrun. a patch from Charlie Savage at [ruby-core:22604].
+
+Wed Jun 3 21:05:44 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/bigdecimal/bigdecimal.c (gfDebug): uncommented out.
+ [ruby-core:22600]
+
+Wed Jun 3 20:54:23 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_eval): needs to guard intermediate string objects.
+ based on a patch from Brent Roman <brent AT mbari.org> a
+ [ruby-core:22584].
+
+Tue May 26 21:24:01 2009 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * Makefile.in (update-rubyspec, test-rubyspec): Catch up to
+ rubyspec merge. A patch by Brian Ford at [ruby-core:21032]
+
+Tue May 26 21:21:49 2009 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/soap/mimemessage.rb (MIMEMessage#to_s): Fix a fatal
+ method name typo. [Bug #1173]
+
+Tue May 26 21:16:55 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (rb_file_s_extname): fix for spaces before extention.
+ [ruby-dev:38044]
+
+Tue May 26 21:09:21 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (_CrtDbgReportW): prevent from false positive
+ assertions in msvcrtd. [ruby-core:22116]
+
+Tue May 26 21:02:13 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/ostruct.rb (OpenStruct#new_ostruct_member): checks if frozen.
+ [ruby-talk:328195], [ruby-core:22142]
+
+Tue May 26 21:00:08 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/ostruct.rb (OpenStruct#inspect): fixed the recursion check.
+ Patch by Kornelius Kalnbach. [ruby-core:20992].
+
+ * test/ostruct/test_ostruct.rb: test for inspect.
+ Patch by Kornelius Kalnbach. [ruby-core:20992].
+
+Tue May 26 20:50:32 2009 Tanaka Akira <akr@fsij.org>
+
+ * eval.c (rb_thread_schedule): handle EBADF of select as well.
+ [ruby-core:21264]
+
+Wed Apr 8 18:59:52 2009 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (subtruct): check tv_sec.
+
+Thu Apr 2 16:06:17 2009 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * test/rss/test_atom.rb (RSS::TestAtomCore::assert_atom_content_inline_other_base64_to_s):
+ ditto. [ruby-dev:38248]
+
+Thu Apr 2 15:43:46 2009 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rss/rss-assertions.rb (RSS::Assertions::assert_atom_content_inline_other_text):
+ newlines are valid for Base64 data. [ruby-dev:38248]
+
+Thu Apr 2 14:17:09 2009 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * test/openssl/test_ssl.rb (OpenSSL#test_client_session):
+ Debian's openssl 0.9.8g-13 failed at assert(ssl.session_reused?),
+ when use default SSLContext. [ruby-dev:36167]
+ backported r19268 from trunk. [ruby-core:22843]
+
+Thu Mar 31 18:18:18 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (mkintpath): new function which converts native path
+ to format acceptable in Makefile.
+
+ * lib/mkmf.rb (configuration): leaves PATH_SEPARATOR unchanged.
+
+ * lib/mkmf.rb (configuration): convers srcdir, topdir and hdrdir.
+ a patch by Alexey Borzenkov <snaury AT gmail.com> at
+ [ruby-core:21448].
+
+Fri Mar 27 19:22:02 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (run_final): frees zombies only. [ruby-dev:38171]
+
+Fri Mar 27 19:22:02 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (rb_gc_call_finalizer_at_exit): leave Thread objects
+ unfinalized. [ruby-dev:38168]
+
+Fri Mar 27 19:22:02 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (run_final): calls free function. [ruby-core:22578]
+
+Mon Mar 23 19:17:06 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/thread/thread.c (rb_queue_pop, rb_queue_push): should not lock
+ mutex if got an exception while waiting, and should ensure unlocked
+ after signaled. [ruby-dev:37545]
+
+Mon Mar 23 18:26:57 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_thread_value): missed to change at r17874. [ruby-core:17595]
+
+Mon Mar 23 18:26:57 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_thread_join): new API.
+
+ * ext/thread/thread.c (wait_mutex, lock_mutex): wait until the locking
+ thread exits. [ruby-dev:34856]
+
+Mon Mar 23 17:41:49 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (file_load_ok): checks if regular file, except for the
+ platform disallows to open directories, e.g. dosish.
+ [ruby-dev:38097], [Bug #1221]
+
+Mon Mar 9 20:59:24 2009 Shugo Maeda <shugo@ruby-lang.org>
+
+ * ext/openssl/ossl_ocsp.c (ossl_ocspbres_verify): OCSP_basic_verify
+ returns positive value on success, not non-zero. [ruby-core:21762]
+ backported r22440 from trunk.
+
+Mon Mar 9 10:02:15 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * re.c (match_check): check if MatchData is initialized.
+ [ruby-core:18749]
+
+Mon Mar 9 09:56:34 2009 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/rexml/rexml.rb: incremented Ruby::VERSION. Thanks, Jeremy
+ Kemper. [ruby-core:20113]
+
+Mon Mar 9 09:52:53 2009 Tanaka Akira <akr@fsij.org>
+
+ * io.c (io_getpartial): fflush after read for updating pos in FILE.
+ not portable, I guess. [ruby-core:21561]
+
+Mon Mar 9 09:04:39 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (define_final): cannot define finalizer for immediate
+ values. [ruby-core:21500]
+
+ * gc.c (define_final): freezes or hides internal values.
+
+Mon Mar 9 08:54:47 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * parse.y (IS_BEG): EXPR_CLASS should be treated like EXPR_BEG.
+ [ruby-core:21453]
+
+Wed Feb 25 15:15:52 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * node.h (rb_thread_raised_clear): should not clear flags other than
+ raised flags. a patch by Tomoyuki Chikanaga <chikanag AT
+ nippon-control-system.co.jp> at [ruby-dev:37794]. [ruby-dev:37776]
+
+Wed Feb 25 15:05:48 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/socket/extconf.rb (gai_strerror): checks if available and if
+ returns const pointer.
+
+ * ext/socket/getaddrinfo.c (gai_strerror): defines only if non
+ available. [ruby-core:21328]
+
+Wed Feb 25 14:57:18 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (open_dir_handle): extracted from rb_w32_opendir.
+
+ * win32/win32.c (winnt_stat): gets rid of strange behavior of
+ GetFileAttributes(). [ruby-core:21269]
+
+Tue Feb 24 02:44:39 2009 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * lib/erb.rb (PercentScanner): remove PercentScanner. fixed % after
+ %> bug. [ruby-dev:37751] [Bug #997]
+
+ * test/erb/test_erb.rb: ditto
+
+Tue Feb 24 02:35:29 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (rb_hash_s_create): set nil as the value if assoc length
+ is not enough. [ruby-core:21249]
+
+Sun Feb 22 22:08:45 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (stack_extend): streamlined rb_thread_restore_context()
+ to ensure O(1) time. based on a patch by Brent Roman <brent AT
+ mbari.org>.
+
+Sun Feb 22 22:03:40 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (cc_mark): frees the continuation's stack if its thread
+ is dead to avoid recursive gc that segfaults. [ruby-core:13889]
+ a patch by Brent Roman <brent AT mbari.org>.
+
+ * eval.c (rb_cont_check): checks for valid continuation instance.
+
+ * eval.c (rb_callcc): assigns th->thread before scope_dup() to
+ avoid segfaults if this scope_dup() triggers a gc pass.
+ a patch by Brent Roman <brent AT mbari.org>.
+
+Sun Feb 22 21:43:34 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (ruby_float_step): extracted from num_step().
+
+ * range.c (range_step): uses ruby_float_step() for float range.
+ [ruby-dev:37691]
+
+Sun Feb 22 00:49:36 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/extmk.rb (extmake): does not use both of makefile.rb and
+ extconf.rb at the same time.
+
+ * lib/mkmf.rb (DLLIB): depends on Makefile. [ruby-core:21096]
+
+Sun Feb 22 00:19:05 2009 Tanaka Akira <akr@fsij.org>
+
+ * eval.c (rb_thread_schedule): Don't change status of threads which
+ don't run next even if select notify readability/writability.
+ [ruby-core:20446]
+
+Fri Feb 20 20:43:13 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/optparse.rb (OptionParser::List#summarize): gives priority
+ to latter switches. [ruby-dev:36692]
+
+ * lib/optparse.rb (OptionParser#summarize): do not append
+ unnecessary line terminator.
+
+Fri Feb 20 19:35:08 2009 Takeyuki FUJIOKA <xibbar@ruby-lang.org>
+
+ * lib/cgi/session.rb: ignore session_id options fixed.[Bug #605]
+
+Fri Feb 20 18:06:40 2009 James Edward Gray II <jeg2@ruby-lang.org>
+
+ Merged 20854 from trunk.
+
+ * lib/xmlrpc/server.rb: Restricting method inspection to show only
+ non-inherited public methods. [ruby-core:20603]
+
+ * lib/xmlrpc/server.rb: Fixing method inspection so it doesn't
+ trigger XMLRPC::FaultException when used. [ruby-core:20604]
+
+Fri Feb 20 01:41:08 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/sync.rb (Sync_m#sync_try_lock): wrong variable name fixed.
+ a patch from [ruby-core:20561]
+
+ * lib/sync.rb (Sync_m::Err.Fail): turn off Thread.critical before
+ exit.
+
+Thu Feb 19 18:02:10 2009 Yuki Sonoda (Yugui) <yugui@yugui.jp>
+
+ * pack.c (pack_pack): fixed odd act of 'm*', 'M*', and 'P*'.
+ just ignores '*' in these cases.
+ [ruby-dev:37289]
+
+Thu Feb 19 17:26:11 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * pack.c (pack_pack): fixed length for odd length string.
+ [ruby-dev:37283]
+
+Thu Feb 19 17:13:13 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_yield_0): Qundef means no argument. [ruby-Bugs-22525]
+
+Wed Feb 18 22:28:00 2009 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_isatty): check whether fd is valid.
+
+Wed Feb 18 22:24:23 2009 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (waitpid): fix bug of checking child slot.
+
+ * win32/win32.c (FindChildSlotByHandle): new.
+
+Wed Feb 18 22:17:04 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * pack.c (pack_pack): propagate taint status from format string to
+ result string.
+
+Wed Feb 18 22:07:44 2009 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * ext/gdbm/gdbm.c: do not set members of RSTRING(str) directly.
+ [ruby-dev:37182]
+
+ * ext/gdbm/gdbm.c (rb_gdbm_nextkey): fix memory leak.
+
+Tue Feb 17 11:58:58 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (str_independent): no independent string points null_str.
+ [ruby-core:20082]
+
+Mon Feb 16 23:30:24 2009 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/lib/tkextlib/blt.rb, ext/tk/lib/tkextlib/blt/vector.rb:
+ fix NameError bug.
+
+Mon Feb 16 23:08:22 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_s_alloc, rb_str_replace): use null_str as well as
+ rb_string_value so that extension libraries do not segfault.
+ [ruby-core:19971]
+
+ * string.c (rb_str_replace): reduced unnecessary malloc and copy.
+
+Mon Feb 16 22:45:41 2009 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * test/rinda/test_rinda.rb: fixed fails occasionally [ruby-dev:37119].
+ thanks, shinichiro.h.
+
+Mon Feb 16 22:36:37 2009 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * lib/drb/drb.rb (DRbConn::alive?): fixed NoMethodError problem
+ from NaHi [ruby-dev:37110].
+
+Sun Feb 15 04:21:42 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/net/ftp.rb (Net::FTP#open_socket): SOCKSsocket is obsolete.
+ a patch from Alan Johnson <alan.wayne.johnson at gmail.com> in
+ [ruby-core:19982].
+
+Fri Feb 13 19:18:42 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/logger.rb (ProgName): fixed for svn, based on a patch from
+ Nobuhiro IMAI at [ruby-dev:37108].
+
+Sun Feb 15 04:17:40 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/webrick/httprequest.rb (WEBrick::HTTPRequest#read_request_line):
+ use non-greedy match for path retrieval to avoid huge recursion
+ for insanely long path.
+
+Fri Feb 13 19:04:54 2009 Keiju Ishitsuka <keiju@ruby-lang.org>
+
+ * shell/command-processor.rb: undefined method `top_level_test' in
+ Shell#test. [ruby-list:45634]
+
+Tue Feb 10 20:00:52 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (load_lock): makes circular require deadlock.
+ [ruby-core:19821]
+
+Tue Feb 10 19:40:58 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_feature_p): returns found feature name if loading.
+ [ruby-core:19798]
+
+ * eval.c (search_required): ditto.
+
+Wed Feb 11 23:37:35 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * ext/bigdecimal/bigdecimal.c (VpMidRound): Round method bug
+ pointed by Ryan Platte fixed(Patch to the patch from "NATORI
+ Shin"). [ruby-talk:273360]
+ back ported from 1.9. fix [ruby-core:19791]
+
+Mon Feb 9 17:35:38 2009 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_accept): secure fd before accept because if
+ error causes in securing, cannot restore the state of accepted
+ socket.
+ fixed [ruby-core:19728]
+
+Mon Feb 9 13:42:15 2009 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (ifs_open_socket): should retry without proto_buffer
+ if cannot find the suitable protocol. a patch from Heesob Park.
+ fixed [ruby-core:19713]
+
+Mon Feb 9 13:40:21 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * ext/stringio/stringio.c (strio_ungetc): should allow ungetc at
+ the top of the buffer. ref #701
+
+Thu Feb 5 09:38:48 2009 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/nkf/nkf-utf8/nkf.c (h_conv): can't guess UTF-8 input in
+ conversion. [ruby-list:45609]
+
+Thu Feb 5 09:03:21 2009 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/rexml/entity.rb (unnormalized): do not call
+ document.record_entity_expansion if document is nil.
+ see <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=502535>.
+ Thanks, Naohisa Goto. backported from trunk.
+
+ * test/rexml/test_document.rb: ditto.
+
+Thu Feb 5 08:55:24 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (rb_ary_join): do not repeat self in a recursive array.
+ [ruby-dev:37019]
+
+Wed Feb 4 14:26:58 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * dir.c (dir_globs): need taint check. reported by steve
+ <oksteev at gmail.com>
+
+Tue Feb 3 14:35:26 2009 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * lib/net/pop.rb: check for invalid APOP timestamp. (CVE-2007-1558)
+ [ruby-dev:36631]
+
+ * test/net/pop/test_pop.rb: ditto.
+
+Mon Feb 2 20:03:58 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * time.c (time_mdump, time_mload): preserves GMT status.
+ [ruby-core:19252]
+
+Mon Feb 2 11:34:51 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * variable.c (autoload_delete, autoload_file): should not delete
+ autoload table, since it may be shared with duplicated modules.
+ [ruby-core:19181]
+
+Thu Jan 29 11:54:22 2009 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date.rb (today,now): should produce own instances.
+ [ruby-talk:317020]
+
+Wed Jan 28 22:51:55 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_mod_modfunc): method undefined in included module
+ may not have nd_body. [ruby-core:18738]
+
+Wed Jan 28 20:53:27 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * marshal.c (marshal_dump): fixed for check_dump_arg.
+
+Tue Jan 27 17:30:11 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * marshal.c (marshal_dump): initializes dump_arg before any funcall.
+ [ruby-dev:36648]
+
+Tue Jan 27 15:17:35 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/socket/socket.c (host_str): numeric address should be unsigned.
+ [ruby-core:18971]
+
+Mon Jan 26 11:12:03 2009 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * lib/tmpdir.rb: setup buffer with nul characters instead of spaces.
+ fixed [ruby-dev:36493]
+
+Sun Jan 25 00:07:23 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/rexml/formatters/pretty.rb (REXML::Formatters::Pretty#wrap):
+ abandon wrapping if the line contains no space. [ruby-dev:36045]
+ fix: #342
+
+Sun Jan 25 00:02:23 2009 Yuki Sonoda (Yugui) <yugui@yugui.jp>
+
+ * lib/matrix.rb (Vector#eql?): typo of the method name as "eqn?".
+ (Vector#eqn?): removed. Defined by mistake.
+ Fixes [ruby-dev:36294]. Reported by weda <weda AT
+ issp.u-tokyo.ac.jp> and an anonymous user.
+
+ * test/matrix/test_matrix.rb: added.
+
+ * test/matrix/test_vector.rb: added.
+
+Fri Jan 23 11:49:45 2009 Shugo Maeda <shugo@ruby-lang.org>
+
+ * NEWS: added an entry for REXML.
+
+ * lib/rexml/document.rb: fixed typo.
+
+Fri Jan 23 11:49:45 2009 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/rexml/document.rb: limit entity expansion. Thanks, Luka
+ Treiber, Mitja Kolsek, and Michael Koziarski. backported from
+ trunk r19033, r19317, r19318.
+
+ * lib/rexml/entity.rb: ditto.
+
+ * test/rexml/test_document.rb: ditto.
-Wed May 21 01:32:56 2008 GOTOU Yuuzou <gotoyuzo@notwork.org>
+Thu Jan 22 15:19:39 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * marshal.c (marshal_load): arg.data is no longer a VALUE but a
+ st_table, and freed in load_ensure. pointed out by pegacorn.
+ [ruby-dev:37008]
+
+Thu Jan 22 15:19:39 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (rb_mark_set): new function to mark keys.
+
+ * marshal.c (struct dump_arg, struct load_arg): added wrappers to mark
+ data entries. backport from trunk r13527,r13528,r13961,r16533.
+ [ruby-dev:36082]
+
+Wed Jan 21 11:12:55 2009 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (filetime_to_timeval): new function, split from
+ gettimeofday().
+
+ * win32/win32.c (gettimeofday): use above function.
+
+ * win32/win32.c (filetime_to_unixtime): ditto. [ruby-dev:36135]
+
+Wed Jan 21 11:12:55 2009 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (gettimeofday): tv_usec is usec, not msec.
+ [ruby-dev:36094]
+
+Wed Jan 21 11:12:55 2009 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (gettimeofday): calc tv_sec and tv_usec from system
+ time by myself. [ruby-dev:36084]
+
+Wed Jan 21 11:12:55 2009 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (gettimeofday): shouldn't use mktime(2) because it's
+ buggy about handling summer time.
+ reported by Yoshikawa <yoshixool AT gmail.com> at [ruby-dev:36071]
+
+Tue Jan 20 12:23:38 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/scanf.rb (Scanf::FormatSpecifier#initialize): %i should accept
+ single digit decimal. [ruby-core:18355]
+
+Mon Jan 19 18:25:28 2009 Tanaka Akira <akr@fsij.org>
+
+ * configure.in (rb_cv_broken_glibc_ia64_erfc): renamed from
+ rb_broken_glibc_ia64_erfc.
+ [ruby-core:18228]
+
+Sat Jan 17 12:16:10 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * random.c (Init_Random): always initialize seed.
+
+Fri Jan 16 10:59:31 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * class.c (clone_method): should copy cbase in cref as well.
+ [ruby-dev:35116]
+
+ * node.h (NEW_CREF): new NEW_ macro.
+
+ * eval.c (PUSH_CREF): use NEW_CREF().
+
+Thu Jan 15 14:34:32 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (STACK_LEVEL_MAX, ruby_stack_length): returns size_t.
+ [ruby-core:18207]
+Wed Jan 14 10:39:56 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * stable/ext/socket/socket.c (NI_MAXHOST, NI_MAXSERV): fixed invalid
+ preprocessor directives. a patch from Peter Bowen at
+ [ruby-core:18211].
+
+Tue Jan 13 04:40:30 2009 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/ftp.rb (login): raise FTPReplyError if passwd or acct
+ is not supplied. backported from trunk. fixed [ruby-core:18058].
+
+Mon Jan 12 00:23:37 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (gc_sweep, obj_free, run_final): defer finalizers of IO and
+ Data. [ruby-dev:35578]
+
+ * gc.c (rb_gc_call_finalizer_at_exit): self-referencing finalizers
+ cannot be invoked. [ruby-dev:35681]
+
+Sun Jan 11 11:33:27 2009 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/ftp.rb (chdir): handle 5xx errors correctly.
+ backported from trunk. fixed [ruby-core:18057].
+
+Fri Jan 9 19:25:25 2009 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/imap.rb (disconnect): do not refer SSL::SSLSocket for
+ environments without OpenSSL. backported from trunk.
+ fixed [ruby-dev:35755].
+
+Thu Jan 8 13:24:23 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (deferred_nodes, compstmt, arg, fixup_nodes, range_op): fix
+ up fixnum range literal in conditional as automagical line number
+ comparison. [ruby-core:12124], [ruby-dev:35731]
+
+Wed Jan 7 10:09:46 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (timeofday): use monotonic clock. based on a patch
+ from zimbatm <zimbatm@oree.ch> in [ruby-core:16627].
+
+Tue Jan 6 09:03:35 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (yylex): 8 and 9 in octal integer should cause compile
+ error. [ruby-dev:35729]
+
+Mon Jan 5 11:14:39 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_thread_schedule): runs deferred finalizers.
+
+ * gc.c (gc_sweep): sets rb_thread_pending to run deferred finalizers.
+
+ * rubysig.h (CHECK_INTS): now checks rb_thread_pending even on
+ platforms where setitimer is not available. [ruby-core:18045]
+
+Mon Jan 5 11:14:39 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * rubysig.h (CHECK_INTS): gives the chance to perform to deferred
+ finalizers before explicit GC.start or the process termination.
+ [ruby-core:18045]
+
+Sun Jan 4 04:49:01 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_telldir): just returns loc.
+
+ * win32/win32.c (rb_w32_rewinddir): needs to intialize loc.
+ [ruby-core:18041]
+
+Sun Jan 4 04:45:26 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_select): recalc the rest of timeout for each
+ iterations. [ruby-core:18015]
+
+Fri Jan 2 03:08:47 2009 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rss/: use PNG instead of zlib as binary data. [ruby-dev:35666]
+
+Tue Nov 11 01:07:32 2008 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * configure.in: fix SEGV on Mac OS X 10.5.3 with --enable-pthread.
+ a patch from Wataru Kimura in Bug #193 [ruby-core:17333].
+
+Mon Aug 11 09:37:17 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * ext/dl/dl.c (rb_str_to_ptr): should propagate taint to dlptr.
+
+ * ext/dl/dl.c (rb_ary_to_ptr): ditto.
+
+ * ext/dl/sym.c (rb_dlsym_call): should check taint of DLPtrData as
+ well.
+
+Fri Aug 8 10:53:52 2008 Tanaka Akira <akr@fsij.org>
+
+ * lib/resolv.rb: randomize source port and transaction id.
+ CVE-2008-1447.
+
+ * lib/resolv-replace.rb (UDPSocket#bind): don't resolv host if host is
+ "".
+
+Mon Aug 4 14:49:35 2008 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * lib/net/smtp.rb (Net::SMTP::rcptto): fix a typo. a patch from
+ Masao Takaku <masao at nii.ac.jp>
+ fix [ruby-dev:35489].
+
+Mon Aug 4 14:13:15 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * regex.c (xmalloc, xrealloc, xfree): not to use ruby managed memory.
+
+ * regex.c (DOUBLE_STACK, re_compile_fastmap0, re_adjust_startpos),
+ (re_search, re_match_exec): check if failed to allocate memory.
+
+Mon Aug 4 13:53:42 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (rb_big2str0, bigsqr): made interruptible. [ruby-Bugs-20622]
+
+Mon Aug 4 13:31:41 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * numeric.c (check_uint, rb_num2uint, rb_fix2uint): fixed wrong check
+ about 64bit positive value.
+Mon Aug 4 13:31:41 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * numeric.c (check_uint, rb_num2uint, rb_fix2uint): strict check.
+ fixed [ruby-dev:33683]
+
+Thu Jul 17 21:42:07 2008 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * lib/net/smtp.rb (Net::SMTP::start): revert to avoid RFC2821
+ violation. [ruby-dev:35487]
+
+Thu Jul 17 21:32:49 2008 Tanaka Akira <akr@fsij.org>
+
+ * string.c (rb_str_format_m): make tmp volatile to avoid possible GC
+ problem.
+
+Thu Jul 17 21:30:55 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/optparse.rb (OptionParser#environment): requires shellwords.
+ [ruby-dev:35466]
+
+Thu Jul 17 02:05:10 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/xmlrpc/client.rb (XMLRPC::Client#do_rpc): requires
+ webrick/cookie. [ ruby-Bugs-21139 ]
+
+Thu Jul 17 01:38:31 2008 Yusuke Endoh <mame@tsg.ne.jp>
+
+ * ext/zlib/zlib.c (rb_gzfile_set_mtime): fix typo. [ruby-core:17713]
+
+Sun Jul 13 00:08:16 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/ipaddr.rb (IPAddr#initialize): get rid of ArgumentError in
+ IPAddr#to_range. a patch from okkez <okkez000 AT gmail.com> in
+ [ruby-dev:35091].
+
+Sun Jul 13 00:04:38 2008 Tanaka Akira <akr@fsij.org>
+
+ * configure.in (erfc): erfc of glibc comes with Debian GNU/Linux Etch
+ on IA64 is broken. erfc(10000.0) aborts.
+ use missing/erf.c instead.
+ http://sources.redhat.com/ml/libc-hacker/2005-08/msg00008.html
+
+Thu Jul 10 18:50:48 2008 Tanaka Akira <akr@fsij.org>
+
+ * common.mk (SPEC_GIT_BASE): update RubySpec GIT URL.
+
+Thu Jul 10 18:46:28 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (rb_file_s_extname): fix for file name with spaces.
+ [ruby-talk:307404]
+
+Thu Jul 10 18:42:37 2008 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * lib/erb.rb (PercentScanner#scan): fix %% line bug. [ruby-core:17491]
+
+ * test/erb/test_erb.rb (test_percent): ditto.
+
+Thu Jul 10 18:40:22 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/net/ftp.rb (Net::FTP#sendport): use divmod. [ruby-core:17557]
+
+Thu Jul 10 18:36:53 2008 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * ruby.c: Mac OS X needs origargc times of '\0' in
+ origargv. [ruby-dev:35308]
+
+Thu Jul 10 13:53:08 2008 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/ruby.h (POSFIXABLE): use FIXNUM_MAX+1 instead of
+ FIXNUM_MAX to make it possible to convert to double accurately.
+ It assumes FLT_RADIX is 2.
+ fix RubyForge bug #14102.
+ backported from 1.9.
+
+Mon Jul 7 16:21:38 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/net/smtp.rb (Net::SMTP::start): use 'localhost' instead of
+ 'localhost.localdomain'. [ruby-dev:35333]
+
+ * lib/net/smtp.rb (Net::SMTP::SMTP.start): ditto.
+
+Mon Jul 7 15:02:13 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_longjmp): duplicate the thrown exception to set backtrace
+ if it was frozen. clear all raised flags.
+
+ * eval.c (stack_check): leave clearing flag to rb_longjmp.
+
+ * eval.c (rb_thread_set_raised, rb_thread_reset_raised): use generic
+ flags.
+
+ * eval.c (Init_Proc), gc.c (Init_GC): freeze preallocated special exceptions.
+
+ * gc.c (rb_memerror): use thread raised flag instead of static flag,
+ and raise nomem_error without backtrace if failed to make backtrace.
+ [ruby-dev:34724]
+
+ * gc.c (ruby_xmalloc): increase malloc_increase only if malloc
+ succeeds. failed malloc size can be huge. it may increase
+ malloc_limit too big which cause less GC and memory full.
+ (ruby_xrealloc): ditto.
+
+Mon Jul 7 12:23:05 2008 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: avoid creating Ruby object during
+ GC. thanks to arton <artonx AT yahoo.co.jp>. [ruby-dev:35313]
+
+ * ext/win32ole/tests: add test_win32ole_event.rb, remove
+ testOLEEVENT.rb
+
+ * ext/win32ole/tests/testWIN32OLE.rb(test_convert_bignum):
+ fix test.
+
+Mon Jul 7 12:23:05 2008 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * gc.c: add rb_during_gc(). based on a patch from arton <artonx AT
+ yahoo.co.jp> at [ruby-dev:35313].
+
+ * intern.h: ditto.
+
+Thu Jul 3 20:13:20 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * marshal.c (w_object, marshal_dump, r_object0, marshal_load): search
+ public methods only. [ruby-core:17283]
+
+ * object.c (convert_type): ditto.
+
+ * lib/singleton.rb (Singleton#_dump): conversion method should be
+ public.
+
+Wed Jul 2 19:06:43 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/cgi.rb (CGI::QueryExtension.read_multipart): blanks inside
+ double quotes are allowed. [ruby-list:45140]
+
+Wed Jul 2 19:03:37 2008 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (num_coerce): call rb_Float(x) first. don't depend on
+ evaluation order of function arguments.
+
+Wed Jul 2 18:57:19 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * ext/syslog/syslog.c (syslog_write): syslog operations should be
+ protected from $SAFE level 4. a patch from Keita Yamaguchi
+ <keita.yamaguchi at gmail.com>.
+
+ * ext/syslog/syslog.c (mSyslog_close): ditto.
+
+ * ext/syslog/syslog.c (mSyslog_set_mask): ditto.
+
+Wed Jul 2 18:26:20 2008 Tanaka Akira <akr@fsij.org>
+
+ * math.c (domain_check): fix preprocess condition.
+
+Wed Jul 2 18:22:52 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/tmpdir.rb (@@systmpdir): prior LOCAL_APPDATA if possible, and
+ should be clean. based on a patch from arton <artonx AT
+ yahoo.co.jp> at [ruby-dev:35269]
+
+Wed Jul 2 18:16:19 2008 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (date2time_str): fix the overflow in
+ some situation. [ruby-bugs-20793]
+
+Tue Jul 1 15:11:14 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (rb_ary_fill): check if beg is too big.
+
+Mon Jun 30 20:35:32 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (str_buf_cat): check for self concatenation.
+
+Sun Jun 29 21:39:54 2008 Tanaka Akira <akr@fsij.org>
+
+ * eval.c (rb_obj_respond_to): use RTEST to test the result of
+ respond_to? method.
+
+Sun Jun 29 21:20:17 2008 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * array.c (rb_ary_fill): (compatibility) do not raise
+ ArgumentError on negative length. This behaviour shall change
+ in a future release.
+
+Sun Jun 29 20:08:11 2008 Tanaka Akira <akr@fsij.org>
+
+ * time.c (time_timeval): fix rounding negative float.
+
+Sun Jun 29 19:19:08 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/inlinetest.rb (InlineTest.in_progname): workaround for frozen
+ $0. [ruby-dev:35261]
+
+ * lib/test/unit/ui/console/testrunner.rb (TestRunner#finished): ditto.
+
+Sun Jun 29 19:19:08 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ruby.c (set_arg0, ruby_prog_init): freeze $0. a patch from Keita
+ Yamaguchi <keita.yamaguchi at gmail.com>.
+
+Sun Jun 29 18:33:33 2008 Tanaka Akira <akr@fsij.org>
+
+ * process.c: include sys/resource.h if HAVE_SYS_RESOURCE_H is defined.
+ pointed by TOYOFUKU Chikanobu. [ruby-dev:35258]
+
+Sun Jun 29 18:26:01 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * variable.c (rb_f_trace_var): should not be allowed at safe level 4.
+ a patch from Keita Yamaguchi <keita.yamaguchi at gmail.com>.
+
+ * eval.c (rb_call0): wrong condition to check insecure method.
+ a patch from Keita Yamaguchi <keita.yamaguchi at gmail.com>.
+
+Sun Jun 29 18:22:52 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (rb_ary_fill): not depend on unspecified behavior at integer
+ overflow. reported by Vincenzo Iozzo <snagg AT openssl.it>.
+
+Sun Jun 29 18:22:06 2008 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c(ole_invoke): fix memory leak.
+ [ruby-bugs-20792]
+
+Sun Jun 29 18:19:11 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * eval.c (PUSH_FRAME, PUSH_CLASS): Add volatile to avoid a
+ possible optimization bug on OS X/PPC. This at least makes
+ build with gcc -O1 and `make test' pass.
+
+Sun Jun 29 17:24:43 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/rdoc/parsers/parse_rb.rb (RDoc#collect_first_comment): skip
+ magic comment.
+
+Sun Jun 29 17:22:09 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/stringio/stringio.c (strio_each, strio_readlines): IO#each and
+ IO#readlines do not affect $_. [ruby-core:17277]
+
+Sun Jun 29 17:19:59 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/stringio/stringio.c (strio_readline, strio_each)
+ (strio_readlines): set lastline. [ruby-core:17257]
+
+Sun Jun 29 17:15:49 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/openssl/ossl.h: include winsock.h if USE_WINSOCK2 is not defined.
+ a patch from arton <artonx at yahoo.co.jp> in [ruby-dev:35078]
+
+Sun Jun 29 17:09:48 2008 wanabe <s.wanabe@gmail.com>
+
+ * util.c (ruby_strtod): ruby_strtod don't allow a trailing
+ decimal point like "7.". [ruby-dev:34835] [ruby-dev:35009]
+
+Sat Jun 28 19:23:40 2008 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * class.c (clone_method): use rb_copy_node_scope.
+ fixed [ruby-list:45102]
+ fixed [ruby-core:17393]
+
+Sat Jun 28 18:49:50 2008 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * class.c: revert to r15855.
+
+Fri Jun 20 18:25:18 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_buf_append): should infect.
+
+Fri Jun 20 16:33:09 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (rb_ary_store, rb_ary_splice): not depend on unspecified
+ behavior at integer overflow.
+
+ * string.c (str_buf_cat): ditto.
+
+Wed Jun 18 22:24:46 2008 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * array.c (ary_new, rb_ary_initialize, rb_ary_store,
+ rb_ary_aplice, rb_ary_times): integer overflows should be
+ checked. based on patches from Drew Yao <ayao at apple.com>
+ fixed CVE-2008-2726
+
+ * string.c (rb_str_buf_append): fixed unsafe use of alloca,
+ which led memory corruption. based on a patch from Drew Yao
+ <ayao at apple.com> fixed CVE-2008-2726
+
+ * sprintf.c (rb_str_format): backported from trunk.
+
+ * intern.h: ditto.
+
+Tue Jun 17 15:09:46 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (file_expand_path): no need to expand root path which has no
+ short file name. [ruby-dev:35095]
+
+Sun Jun 15 19:27:40 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * configure.in: Fix $LOAD_PATH. Properly expand vendor_ruby
+ directories; submitted by Takahiro Kambe <taca at
+ back-street.net> in [ruby-dev:35099].
+
+Mon Jun 9 17:56:30 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/set.rb (Set#delete_if): Call to_a.
+ (SortedSet#delete_if, TC_SortedSet#test_sortedset): Use super to
+ yield elements in sorted order; [ruby-core:17144] by Arthur
+ Schreiber.
+ (SortedSet#each, SortedSet#each, TC_Set#test_each)
+ (TC_SortedSet#test_sortedset): Return self; [ruby-dev:35002] by
+ Arthur Schreiber.
+
+Mon Jun 9 03:28:05 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/zlib/zlib.c (rb_deflate_initialize, Init_zlib): Fix up
+ initialize_copy; [ruby-list:45016], [ruby-list:45018].
+
+Mon Jun 9 03:26:03 2008 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * NEWS: Mention new constants.
+
+Mon Jun 9 03:24:18 2008 Tanaka Akira <akr@fsij.org>
+
+ * hash.c (hash_i): make Hash#hash order insensitive.
+
+Mon Jun 9 03:22:43 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (VENDOR_DIR): use LIBDIR instead of PREFIX as well as
+ SITE_DIR. a patch from Richard Brown <rbrown AT exherbo.org> in
+ [ruby-core:17129].
+
+Mon Jun 9 03:21:20 2008 Tanaka Akira <akr@fsij.org>
+
+ * gc.c (os_obj_of): assure to not free the scanning heap.
+
+Mon Jun 9 03:20:12 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * io.c (rb_open_file, rb_io_s_sysopen): fmode should be unsigned int.
+ fixed [ruby-dev:34979]
+
+Fri Jun 6 21:16:55 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/Makefile.sub (COMMON_HEADERS): include ws2tcpip.h.
+
+ * ext/socket/addrinfo.h (addrinfo, getaddrinfo, getnameinfo,
+ freehostent, freeaddrinfo): undef before define because these are
+ macros in some versions of Windows SDK.
+
+ * win32/setup.mak: maybe commit miss.
+
+Fri Jun 6 19:34:22 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * mkconfig.rb: hide build path from rbconfig.rb.
+
+ * util.c (ruby_strtod, dtoa): initialize more variables for error
+ handling.
+
+ * io.c (rscheck), marshal.c (w_nbyte, w_bytes, w_unique),
+ (path2class, path2module): constified.
+
+ * pack.c (pack_unpack), process.c (rb_syswait): suppress warnings.
+
+ * suppress warnings on cygwin, mingw and mswin.
+
+Fri Jun 6 19:23:53 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (file_expand_path): fix for non-existent files and SFN of
+ symlinks. [ruby-talk:303736]
+
+Fri Jun 6 18:25:43 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/iconv: Tests fixed.
+
+Fri Jun 6 17:04:56 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * win32/win32.h: include ws2tcpip.h. fixed [ruby-Bugs-20528]
+
+ * lib/time.rb (Time.xmlschema): don't use float. fix
+ http://rubyforge.org/tracker/index.php?func=detail&group_id=426&atid=1698&aid=20504
+
+ * object.c (rb_obj_alloc): RDoc updated. a patch from Gaston
+ Ramos <ramos.gaston at gmail.com> in [ruby-core:17073].
+
+ * lib/rdoc.rb: massive spelling correction patch from Evan Farrar
+ <evanfarrar at gmail.com> in [ruby-doc:1382] applied.
+
+ * ext/openssl/ossl_ssl_session.c (ossl_ssl_session_initialize):
+ Add a null check for ssl; submitted by akira yamada
+ in [ruby-dev:34950].
+
+ * ext/openssl/ossl_ssl.c (Init_ossl_ssl): Define OP_NO_TICKET if
+ SSL_OP_NO_TICKET is present; submitted by akira yamada
+ in [ruby-dev:34944].
+
+ * test/openssl/test_ssl.rb (OpenSSL#test_server_session): Add a
+ workaround for the case where OpenSSL is configured with
+ --enable-tlsext; submitted by akira yamada in [ruby-dev:34944].
+
+Fri Jun 6 16:58:23 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/iconv/iconv.c (iconv_iconv): fix for length argument and now
+ allows range. [ruby-core:17092] [ruby-core:17115]
+
+Wed Jun 4 17:22:30 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * NEWS: Fix typos and move misplaced entries.
+ NEWS: Somehow optflags and warnflags were not actually included
+ in this release.
+
+Tue Jun 3 19:33:22 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * enumerator.c (enumerator_init_copy): Take care of
+ initialize_copy as well as initialize.
+
+ * test/ruby/test_enumerator.rb: Pull in the test suite for
+ enumerator from trunk.
+
+Tue Jun 3 12:51:57 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * enumerator.c (enumerator_allocate, enumerator_ptr): Properly
+ detect if the object is initialized and raise error when
+ appropriate.
+ (enumerator_initialize): Fix a typo in rdoc. [ruby-core:17052]
+
+Tue Jun 3 10:16:40 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/erb.rb (ERB::Compiler::TrimScanner#scan_line): Fix a bug
+ where tokens are not yilelded one by one.
+ (ERB::Compiler::TrimScanner#explicit_trim_line): Fix without-
+ strscan problems. [ruby_core:17028].
+
+ * test/erb/test_erb.rb (TestERBCore#_test_01)
+ (TestERBCore#test_02_safe_04): The expected value should come
+ first for assert_equal().
+ (TestERBCoreWOStrScan): Add test class for without-strscan.
+
+Mon Jun 2 19:47:16 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/delegate.rb (DelegateClass, Delegator#respond_to?):
+ respond_to? must take optional second argument. This was a
+ latent bug exposed by a recent internal change of marshal.c to
+ call respond_to? with a second argument; submitted by Jeremy
+ Kemper <jeremy at bitsweat.net> in [ruby-core:17045].
+
+Sat May 31 23:53:35 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * .: Release as Ruby 1.8.7.
+
+Sat May 31 23:33:34 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * README, README.ja: Add a note about default C flags.
+
+Sat May 31 22:11:15 2008 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * version.c (ruby_description, ruby_copyright): backported from
+ 1.9. bug#19002, [ruby-dev:34883]
+
+ * error.c (report_bug): uses ruby_description.
+
+Sat May 31 20:56:04 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * array.c (rb_ary_delete_if): should return enumerator if no block
+ is given. [ruby-dev:34901]
+
+Sat May 31 18:28:17 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * suppress warnings with -Wwrite-string.
+
+Sat May 31 15:58:08 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * Makefile.in, configure.in (warnflags): defaulted to -Wall
+ -Wno-parentheses with gcc. [ruby-dev:34810]
+
+Fri May 30 05:28:18 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * enum.c (count_i, count_iter_i, count_all_i): add prototypes for VC.
+
+Fri May 30 04:32:07 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * enum.c (count_i, count_iter_i): Sync with trunk.
+ enum.c (enum_count, count_all_i, Init_Enumerable),
+ array.c (rb_ary_count): Sync with trunk. If no argument or
+ block is given, count the number of all elements.
+
+Fri May 30 03:12:18 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/openssl/ossl_bn.c (ossl_bn_s_rand, ossl_bn_s_pseudo_rand):
+ Int should be enough here.
+
+Fri May 30 02:35:00 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/openssl/ossl_bn.c (ossl_bn_s_rand, ossl_bn_s_pseudo_rand),
+ ext/openssl/ossl_pkey_dh.c (ossl_dh_s_generate)
+ (ossl_dh_initialize),
+ ext/openssl/ossl_pkey_dsa.c (ossl_dsa_s_generate),
+ ext/openssl/ossl_rand.c (ossl_rand_bytes)
+ (ossl_rand_pseudo_bytes, ossl_rand_egd_bytes),
+ ext/openssl/ossl_x509store.c (ossl_x509stctx_set_error): Do not
+ use FIX2INT() without checking the value type. Use NUM2INT()
+ instead; found by akr in [ruby-dev:34890].
+
+Thu May 29 20:07:45 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * configure.in, win32/Makefile.sub, mkconfig.rb, instruby.rb,
+ ruby.c, lib/mkmf.rb, README.EXT, README.EXT.ja: Backport the
+ vendor_ruby directory support.
+
+Thu May 29 17:52:31 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/zlib/extconf.rb: search zlib1, and regard mswin32 later than VC6
+ as WIN32. [ruby-core:16984]
+
+Wed May 28 17:54:29 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * string.c (rb_str_start_with): Remove an unused variable.
+ (rb_str_upto_m): Fix a prototype.
+
+Wed May 28 17:48:28 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * range.c (range_step): Fix brokenness when a non-integer numeric
+ value is specified as step. [rubyspec]
+ (range_step): Make use of String#step internally if a string (or
+ string-alike) range is given.
+
+ * string.c (rb_str_upto_m, Init_String): Add an optional second
+ argument to specify if the last value should be included.
+
+Wed May 28 16:53:39 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * array.c (rb_ary_slice_bang): Call rb_ary_modify_check() at the
+ beginning. [rubyspec]
+
+Wed May 28 16:12:44 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/webrick/httpservlet/cgihandler.rb (WEBrick::HTTPServlet::CGIHandler#do_GET):
+ Set the HTTP status code to 302 if a Location header field is
+ present and the status code is not valid as a client
+ redirection. cf. RFC 3875 6.2.3, 6.2.4.
+
+Wed May 28 15:18:16 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/singleton.rb (SingletonClassMethods): _load should be public.
+
+Wed May 28 12:52:41 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * marshal.c (w_object, marshal_dump, r_object0, marshal_load): search
+ private methods too. [ruby-dev:34671]
+
+ * object.c (convert_type): ditto.
+
+Tue May 27 23:26:49 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * error.c (rb_bug): description from rb_bug() should include
+ patchlevel. [ruby-dev:34826]
+
+Tue May 27 20:19:22 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * array.c (rb_ary_slice_bang): Return an empty array instead of
+ nil when pos is valid and len is adjusted from a valid value to
+ zero; caught by RubySpec.
+
+Tue May 27 19:45:20 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * numeric.c (flo_divmod): Revert the behavior change; do not
+ suppress an exception when div is NaN or Inf. [ruby-dev:34857]
+
+Tue May 27 19:24:40 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * enum.c (enum_to_a): Pass arguments through to #each().
+ (enum_sort): Follow the enum_to_a signature change.
+ (enum_reverse_each): Add #reverse_each().
+
+Tue May 27 18:54:02 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/stringio/stringio.c (strio_each_char, Init_stringio): Add
+ StringIO#{each_char,chars}.
+
+Tue May 27 17:59:34 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/stringio/stringio.c (strio_each): Return an enumerator if no
+ block is given.
+ (strio_each_byte): Return an enumerator if no block is given,
+ and return self if one is given as the rdoc says.
+
+ * io.c (rb_io_each_byte): Fix rdoc. IO#each_byte returns self,
+ not nil.
+
+Tue May 27 16:02:58 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * eval.c (rb_mod_module_exec, Init_eval): Add
+ Module#{module_exec,class_exec}.
+
+Tue May 27 15:36:37 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * io.c (rb_io_each_char, argf_each_char, Init_IO):
+ Add {IO#,ARGF.}{each_char,chars}.
+
+Tue May 27 13:46:52 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/stringio/stringio.c (Init_stringio): Define
+ StringIO#{getbyte,readbyte}.
+
+Tue May 27 13:38:51 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * io.c (Init_IO): Define {IO#,ARGF.}{getbyte,readbyte}.
+
+Tue May 27 13:26:15 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/stringio/stringio.c (Init_stringio): Define #bytes and
+ #lines.
+
+Tue May 27 13:20:35 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * io.c: (rb_io_lines, rb_io_bytes, Init_IO): Define
+ IO#{lines,bytes} and ARGF.{lines,bytes}.
+
+Tue May 27 12:13:17 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * file.c (BUFCHECK): wrong condition. [ruby-core:16921]
+
+ * file.c (file_expand_buf): shouldn't use buflen for length of string.
+
+Mon May 26 18:24:48 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (BUFCHECK): no resize if enough room.
+
+ * file.c (file_expand_path): use BUFCHECK.
+
+Mon May 26 16:46:19 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * file.c (ntfs_tail): filename which starts with '.' is valid.
+
+ * file.c (file_expand_path): cygwin symlink support.
+
+Mon May 26 12:16:43 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * .: Release as Ruby 1.8.7-preview4.
+
+Mon May 26 12:12:26 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * marshal.c (dump_ensure, load_ensure): should return values.
+
+ * eval.c (yield_under, yield_under_i, yield_args_under_i)
+ (specific_eval, rb_obj_instance_exec, Init_eval): Implement
+ Object#instance_exec(), a 1.9 feature.
+
+Mon May 26 11:53:21 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * eval.c (rb_yield_0, proc_invoke, proc_arity): allow passing a
+ block to a Proc. [ruby-dev:23533]; by nobu; backported from
+ 1.9. This implementation in current shape is known to be
+ buggy/broken, especially with nested block invocation. Take
+ this as an experimental feature.
+
+ * parse.y (block_par, block_var): ditto.
+
+Mon May 26 08:00:52 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * marshal.c (r_object0, Init_marshal): Fix the garbled s_call
+ definition; fixes [ruby-dev:34843].
+
+Mon May 26 03:16:20 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * hash.c (rb_hash_default): Fix rdoc.
+ (rb_hash_each, env_each_value, env_each_pair): Return an
+ enumerator if no block is given.
+ (rb_hash_update): Update rdoc.
+ (envix): Conditionalize the definition itself.
+ (rb_f_getenv, env_fetch, env_keys, env_values, env_values_at)
+ (env_select, env_inspect, env_to_a, env_empty_p, env_has_key)
+ (env_has_value, env_index, env_indexes, env_to_hash, env_shift)
+ (env_update): Require secure level 4.
+ (env_each_value, env_each_i): Delay variable initialization.
+ (env_each_key, env_each_value, env_reject_bang)
+ (env_clear, env_replace): Omit duplicated secure level check.
+ (env_has_value): Do to_str conversion.
+
+Sun May 25 19:48:12 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * hash.c (env_delete_if): Return an enumerator if no block is
+ given.
+ (env_each_key): Delay a variable initialization after
+ RETURN_ENUMERATOR().
+
+Sun May 25 05:07:19 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * array.c (rb_ary_slice_bang): Be consistent with Array#slice()
+ and String#slice!(). Just return nil when a negative length or
+ out of boundary index is given instead of raising an exception
+ via internal functions.
+ (rb_ary_slice_bang): should not use rb_ary_subseq() which shares
+ internal pointer. splice modifies the receiver right after
+ subseq. [ruby-dev:34005]
+ (rb_ary_slice_bang): should adjust length before making
+ sub-array.
+
+ * enumerator.c (Init_Enumerator): Override
+ Enumerable::Enumerator#each_with_index with #with_index.
+
+Sun May 25 03:13:09 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * eval.c (Init_Thread): Initialize recursive_key.
+
+Sun May 25 02:45:49 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * error.c (syserr_eqq): Use en.
+
+Sat May 24 22:32:49 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * object.c (rb_cstr_to_dbl): should clear errno before calling
+ strtod(3). [ruby-dev:34834]
+
+Sat May 24 22:27:44 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * marshal.c (marshal_load): should initialize arg.data used for
+ reentrant check. [ruby-dev:34837]
+
+Sat May 24 00:34:59 2008 Tanaka Akira <akr@fsij.org>
+
+ * lib/rational.rb (Rational#to_i): fix rdoc. Rational(-7,4).to_i
+ should be -1.
+
+Fri May 23 20:22:44 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * marshal.c (reentrant_check): check reentrance via callcc.
+ [ruby-dev:34802]
+
+Fri May 23 16:46:28 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * enumerator.c (proc_call): Remove an unused static function.
+
+Fri May 23 13:46:09 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (cflags): commit miss.
+
+Fri May 23 09:52:21 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (MINIRUBY), common.mk (RUBYOPT): add purelib.rb.
+ [ruby-core:16642]
+
+ * ext/extmk.rb: load purelib.rb only when not cross compiling.
+
+Fri May 23 08:47:02 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * error.c (syserr_eqq): === should be able to handle delegated
+ objects as well.
+
+Fri May 23 04:22:19 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/tcltklib.c, ext/tk/tkutil/tkutil.c: fix memory leak.
+
+ * ext/tk/lib/tk.rb: avoid trouble when finalize TclTkIp.
+
+ * ext/tk/lib/tk.rb, ext/tk/lib/tk/*: help to fix troubles when
+ use Ttk widgets on old Tk scripts.
+
+ * ext/tk/sample/*: update and add demo scripts. some of them are
+ introduction about new features of Tcl/Tk8.5.
+
+Fri May 23 03:48:10 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * class.c (clone_method): Just use ruby_cref as cref.
+
+Fri May 23 01:03:23 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * class.c (rb_singleton_class_clone): Pass Qnil, not 0.
+
+Fri May 23 00:51:48 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * class.c (clone_method): Totally revamp the previous fix which
+ was incorrect.
+ (rb_mod_init_copy): Ditto.
+ (singleton_class_clone_int): Ditto.
+
+Fri May 23 00:48:10 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * eval.c (rb_copy_node_scope), node.h: Rename from copy_node_scope
+ and export.
+
+Thu May 22 21:24:15 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * parse.y (top_local_setup): fixed memory leak bug based on a
+ patch from Roger Pack <rogerpack2005 at gmail.com> in
+ [ruby-core:16610].
+
+Thu May 22 14:20:54 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (flatten): check if reentered. [ruby-dev:34798]
+
+Thu May 22 08:28:49 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * array.c (flatten): free memo hash table before raising exception.
+ [ruby-dev:34789]
+
+Thu May 22 06:30:10 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * array.c (flatten): fix memory leak.
+
+Thu May 22 05:45:30 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * proc.c (proc_dup): should copy safe_level from src proc
+ properly. a patch from Keita Yamaguchi
+ <keita.yamaguchi at gmail.com>
+
+Wed May 21 23:31:44 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_get_method_body, rb_alias, rb_eval): should not cache
+ uninitialized value, since search_method doesn't set origin if the
+ method wasn't found.
+
+ * eval.c (search_method, remove_method, error_print, rb_alias)
+ (rb_eval, rb_rescue2, search_required, Init_eval, rb_thread_create),
+ gc.c (rb_source_filename, Init_stack), io.c (rb_io_getline),
+ parse.y (rb_id2name, rb_parser_free): suppress warnings.
+
+Wed May 21 12:34:51 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (rb_hash_delete): rdoc fix based on a patch from Gaston Ramos
+ <ramos.gaston AT gmail.com>. [ruby-core:16825]
+
+Tue May 20 13:15:46 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * file.c (lchmod_internal): Remove a compiler warning.
+
+Mon May 19 18:22:35 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/openssl/ossl_pkcs5.c (ossl_pkcs5_pbkdf2_hmac): Fix the type
+ of md; pointed out by Takahiro Kambe <taca at back-street.net>
+ in [ruby-dev:34748].
+
+Mon May 19 14:20:13 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * sprintf.c (rb_f_sprintf): fixed SEGV on win32 with "% 0e" % 1.0/0.0.
+
+Mon May 19 13:29:58 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * process.c (rb_f_system): set last_status when status == -1 because
+ there is no path to set it on win32. this patch is derived from
+ [ruby-core:16787], submitted by Luis Lavena <luislavena at gmail.com>
+
+Mon May 19 13:01:05 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk ({MSPEC,RUBYSPEC}_GIT_URL): moved from Makefine.in.
+
+ * {win32,bcc32}/Makefile.sub (update-rubyspec): added.
+
+Mon May 19 11:53:45 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/openssl/openssl_missing.c (HMAC_CTX_copy): adopted
+ prototype change in openssl bundled with newer OpenBSD.
+ a patch from Takahiro Kambe <taca at back-street.net> in
+ [ruby-dev:34691].
+
+Mon May 19 06:36:37 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * .: Release as Ruby 1.8.7-preview3.
+
+Sun May 18 22:26:51 2008 GOTOU Yuuzou <gotoyuzo@notwork.org>
* lib/webrick/httpservlet/filehandler.rb: should normalize path
name in path_info to prevent script disclosure vulnerability on
@@ -82,26 +3002,54 @@ Wed May 21 01:32:56 2008 GOTOU Yuuzou <gotoyuzo@notwork.org>
* lib/webrick/httpservlet/cgi_runner.rb: accept interpreter
command line arguments.
-Sun May 18 01:57:44 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * file.c (isdirsep): backslash is valid path separator on cygwin too.
- backported from 1.8 HEAD.
-
Sat May 17 23:53:57 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
* file.c (file_expand_path): fix for short file name on Cygwin.
-Sat May 17 23:50:29 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Sat May 17 11:29:11 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (rb_file_s_extname): first dot is not an extension name.
+
+Sat May 17 10:18:44 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * re.c (rb_reg_search): need to free allocated buffer in re_register.
+
+Fri May 16 17:01:44 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/Makefile.sub (test-rubyspec): added.
+
+Fri May 16 16:22:40 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/tcltklib.c: sometimes freeze when receive Interrupt signal.
+
+Fri May 16 14:54:56 2008 Tanaka Akira <akr@fsij.org>
+
+ * Makefile.in (update-rubyspec): move rubyspec to srcdir.
+ (test-rubyspec): ditto.
+
+Fri May 16 14:25:22 2008 Tanaka Akira <akr@fsij.org>
+
+ * Makefile.in (test-rubyspec): use RUNRUBY. suggested by nobu.
+
+Fri May 16 13:01:43 2008 Tanaka Akira <akr@fsij.org>
+
+ * Makefile.in (update-rubyspec): new target to download rubyspec.
+ (test-rubyspec): new target to run rubyspec. this doesn't work
+ before install.
- * file.c (OpenFile): prevent conflict on Windows.
+Fri May 16 08:15:52 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
- * file.c (USE_NTFS): fixed merge miss.
+ * ext/tk/lib/tk.rb: fix memory (object) leak bug.
-Sat May 17 12:36:46 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+ * ext/tk/sample/demos-jp/aniwave.rb, ext/tk/sample/demos-en/aniwave.rb:
+ bug fix.
- * file.c (file_expand_path): rb_str_set_len is not backported.
+Thu May 15 17:00:22 2008 Akinori MUSHA <knu@iDaemons.org>
-Sat May 17 12:15:48 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+ * string.c (Init_String): Define #bytesize as an alias for #size
+ for compatibility with 1.9.
+
+Thu May 15 15:33:59 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
* file.c (file_expand_path): support for alternative data stream
and ignored trailing garbages of NTFS.
@@ -110,7 +3058,1127 @@ Sat May 17 12:15:48 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
* file.c (rb_file_s_extname): ditto.
-Mon Mar 3 23:36:41 2008 GOTOU Yuuzou <gotoyuzo@notwork.org>
+Wed May 14 19:24:59 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * array.c (rb_ary_count): Override Enumerable#count for better
+ performance.
+ (rb_ary_nitems): Undo the backport. Use #count {} instead.
+
+ * enumerator.c (enumerator_iter_i): Remove an unused function.
+ (enumerator_with_index, enumerator_each): Remove unused
+ variables.
+
+Wed May 14 17:15:11 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/tk/tkutil/extronf.rb: check stdndup() because it's not standard
+ function of C.
+
+ * ext/tk/tkutil/tkutil.c (cbsubst_table_setup): use malloc() and
+ strncpy() instead of strndup() if not available.
+
+Wed May 14 09:52:02 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/tkutil/tkutil.c: improve handling callback-subst-keys.
+ Now, support longnam-keys (e.g. '%CTT' on tkdnd-2.0; however, still
+ not support tkdnd-2.0 on tkextlib), and symbols of parameters (e.g.
+ :widget=>'%W', :keycode=>'%k', '%x'=>:x, '%X'=>:root_x, and so on;
+ those are attributes of event object). It means that Ruby/Tk accepts
+ not only "widget.bind(ev, '%W', '%k', ...){|w, k, ...| ... }", but
+ also "widget.bind(ev, :widget, :keycode, ...){|w, k, ...| ... }".
+ It is potentially incompatible, when user passes symbols to the
+ arguments of the callback block (the block receives the symbols as
+ strings). I think that is very rare case (probably, used by Ruby/Tk
+ experts only). When causes such trouble, please give strings instead
+ of such symbol parameters (e.g. call Symbol#to_s method).
+
+ * ext/tk/lib/tk/event.rb, ext/tk/lib/tk/validation.rb,
+ ext/tk/lib/tkextlib/blt/treeview.rb,
+ ext/tk/lib/tkextlib/winico/winico.rb: ditto.
+
+ * ext/tk/tkutil/tkutil.c: strings are available on subst_tables on
+ TkUtil::CallbackSubst class (it is useful on Ruby 1.9).
+
+ * ext/tk/lib/tk/spinbox.rb, ext/tk/lib/tkextlib/iwidgets/hierarchy.rb,
+ ext/tk/lib/tkextlib/iwidgets/spinner.rb,
+ ext/tk/lib/tkextlib/iwidgets/entryfield.rb,
+ ext/tk/lib/tkextlib/iwidgets/calendar.rb,
+ ext/tk/lib/tkextlib/blt/dragdrop.rb,
+ ext/tk/lib/tkextlib/tkDND/tkdnd.rb,
+ ext/tk/lib/tkextlib/treectrl/tktreectrl.rb,
+ ext/tk/lib/tkextlib/tktable/tktable.rb: disable code piece became
+ unnecessary by reason of the changes of ext/tk/tkutil/tkutil.c.
+
+Tue May 13 15:10:50 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * enumerator.c: Update rdoc.
+ (enumerator_initialize): Discourage the use.
+ (enum_each_slice, enum_each_cons, enumerator_each)
+ (enumerator_with_index): Add a note about a call without a block.
+
+ * NEWS: Intentionally omit enum_slice and enum_cons, which are
+ removed in 1.9.
+
+Tue May 13 07:56:36 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * string.c (rb_str_cat): fixed buffer overrun reported by
+ Christopher Thompson <cthompson at nexopia.com> in [ruby-core:16746]
+
+Mon May 12 13:57:19 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * eval.c (is_defined): add NODE_OP_ASGN_{OR,AND}. "defined?(a||=1)"
+ should not operate assignment. [ruby-dev:34645]
+
+Mon May 12 12:59:23 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/lib/tk/wm.rb: Wm#overrideredirect overwrites arguemnt to
+ an invalid value.
+
+ * ext/tk/sample/ttk_wrapper.rb: support "if __FILE__ == $0" idiom.
+
+Mon May 12 12:36:55 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_select): backport from trunk.
+ [ruby-talk:300743]
+
+Mon May 12 12:33:21 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (RUBYLIB, RUBYOPT): clear.
+
+Mon May 12 10:41:10 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/delegate.rb (SimpleDelegator::dup): removed needless argument.
+ [ruby-list:44910]
+
+ * lib/delegate.rb (clone, dup): keep relationship with the target
+ object.
+
+Sun May 11 23:19:39 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enum.c (all_iter_i, any_iter_i): reduced duplicated code.
+
+Sun May 11 17:57:36 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (MINIRUBY): should not include extension library path.
+
+Sun May 11 10:36:10 2008 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * eval.c (method_name, method_owner): New methods; backported
+ from 1.9. (UnboundMethod#name, UnboundMethod#owner)
+
+Sun May 11 02:48:13 2008 <nagai@orca16.orcabay.ddo.jp>
+
+ * ext/tk/lib/tk/pack.rb, ext/tk/lib/tk/grid.rb: fail to do pack/grid
+ without options.
+
+ * ext/tk/lib/tk.rb: add TkWindow#grid_anchor, grid_column, grid_row.
+
+Sat May 10 18:19:16 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * string.c (rb_str_each_line): RDoc updated. [ruby-dev:34586]
+
+Sat May 10 13:17:56 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/lib/tk/pack.rb, ext/tk/lib/tk/grid.rb: increase supported
+ parameter patterns of configure method.
+
+Sat May 10 09:16:13 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * util.c (ruby_strtod): backported from 1.9. a patch from Satoshi
+ Nakagawa <psychs at limechat.net> in [ruby-dev:34625].
+ fixed: [ruby-dev:34623]
+
+Fri May 9 23:33:25 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/lib/tk/wm.rb: methods of Tk::Wm_for_General module cannot
+ pass the given block to methods of Tk::Wm module.
+
+ * ext/tk/lib/tk/grid.rb: lack of module-method definitions.
+
+ * ext/tk/lib/tkextlib/tile.rb: lack of autoload definitions.
+
+ * ext/tk/lib/tkextlib/tile/tnotebook.rb: cannot use kanji (not UTF-8)
+ characters for headings.
+
+ * ext/tk/tcltklib.c: maybe a little more stable about @encoding value
+ of TclTkIp object.
+
+Wed May 7 08:46:44 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * struct.c (rb_struct_s_def): to_str should be called only once.
+ [ruby-core:16647]
+
+Wed May 7 00:54:25 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * ext/zlib/zlib.c (gzreader_gets): may cause infinite loop.
+ a patch from Kouya <kouyataifu4 at gmail.com> in
+ [ruby-reference-manual:762].
+
+Sun May 4 09:35:51 2008 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * sample/erb/erb4html.rb (ERB4Html) : add example of ERB#set_eoutvar.
+ ERB4Html is an auto-quote ERB.
+
+Sat May 3 22:52:48 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/lib/tkextlib/tile.rb, ext/tk/lib/tkextlib/tile/style.rb,
+ ext/tk/sample/ttk_wrapper.rb: improve treating and control themes.
+ add Tk::Tile.themes and Tk::Tile.set_theme(theme).
+
+Fri May 2 14:52:33 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * misc/ruby-mode.el: move fontifying code from hook. a patch from
+ Phil Hagelberg <phil at hagelb.org> in [ruby-core:16636].
+
+Fri May 2 13:47:51 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * re.c (match_select): restore previous behavior of MatchData#select.
+ RDoc updated as well, mentioning the plan to remove this method
+ in the future. [ruby-dev:34556]
+
+Fri May 2 13:04:04 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * ext/dbm/dbm.c (Init_dbm): defines DBM::VERSION even when
+ DB_VERSION_STRING is not available. [ruby-dev:34569]
+
+Thu May 1 23:57:06 2008 James Edward Gray II <jeg2@ruby-lang.org>
+
+ Merged 16257 from trunk.
+
+ * lib/net/telnet.rb: This patch from Brian Candler adds a FailEOF mode which
+ can be activated to have net/telnet raise EOFError exceptions when the
+ remote connection is closed. The default behavior remains unchanged though.
+
+Thu May 1 23:43:21 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * range.c (range_step): check if step can be converted to an integer.
+ [ruby-dev:34558]
+
+ * range.c (range_step): allow float step bigger than zero but less
+ than one. [ruby-dev:34557]
+
+Wed Apr 30 20:22:40 2008 James Edward Gray II <jeg2@ruby-lang.org>
+
+ Merged 16241 from trunk.
+
+ * lib/net/telnet.rb: Fixing a bug where line endings would not be properly
+ escaped when the two character ending was broken up into separate TCP
+ packets. Issue reported and patched by Brian Candler.
+
+Wed Apr 30 17:47:21 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * re.c (rb_reg_search): use local variable. a patch from wanabe
+ <s.wanabe AT gmail.com> in [ruby-dev:34537]. [ruby-dev:34492]
+
+Sat Apr 26 19:40:34 2008 Guy Decoux <decoux@moulon.inra.fr>
+
+ * class.c (struct clone_method_data): Add cref.
+ (clone_method): Properly handle NODE_BMETHOD and NODE_DMETHOD.
+ (rb_singleton_class_clone, singleton_class_clone_int): Set a
+ proper value to klass and propagate cref. [ruby-core:16238]
+
+ * eval.c (rb_block_dup, rb_method_dup), intern.h: Add duplicator
+ methods for use from class.c#clone_method().
+
+Fri Apr 25 15:46:37 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/lib/tk.rb, ext/tk/lib/tk/scrollbar.rb, ext/tk/lib/tk/scale.rb:
+ improve unknonw-option check when create a widget.
+
+ * ext/tk/lib/tkextlib/blt/unix_dnd.rb, ext/tk/lib/tkextlib/blt/ted.rb,
+ ext/tk/lib/tkextlib/treectrl/tktreectrl.rb: bug fix on 'cget'.
+
+ * ext/tk/lib/tk/menuspec.rb: option check will fail when
+ TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ is true.
+
+ * ext/tk/lib/tk/palette.rb: bug fix.
+
+Fri Apr 25 12:37:54 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (flatten): returns an instance of same class.
+ [ruby-core:16554]
+
+Thu Apr 24 23:47:50 2008 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * lib/net/pop.rb: backported from 1.9. bug#19003
+
+ * ext/openssl/lib/openssl/ssl.rb: set_params; backported from 1.9.
+ bug#19552, [ruby-dev:34402]
+
+ * ext/openssl/ossl_ssl.c: ditto.
+
+ * test/openssl/test_ssl.rb: ditto.
+
+Thu Apr 24 17:06:34 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * eval.c (THREAD_SAVE_CONTEXT): remove unnecessary
+ FLUSH_REGISTER_WINDOWS before calling setjmp(). [ruby-core:16285]
+
+Thu Apr 24 14:15:11 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dln.c (dln_find_1): prior files with extensions to files sans
+ extensions. [ruby-core:16517]
+
+Wed Apr 23 15:39:31 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * eval.c (bind_eval): Add Binding#eval, a shorthand method for
+ eval(str, binding, ..); backported from 1.9.
+
+Wed Apr 23 15:28:52 2008 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * test/gdbm/test_gdbm.rb (TestGDBM#test_s_open_no_create): failed
+ notice moved from comment to assertion message. [ruby-dev:29127]
+
+Wed Apr 23 14:00:05 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/mkmf.rb (create_makefile): Add a missing dependency on the
+ target directory for each .rb file. This will hopefully fix
+ parallel make (-jN). Tested on FreeBSD.
+
+Wed Apr 23 11:49:54 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/set.rb (Set#each, SortedSet#each, TC_Set#test_each): Return
+ an enumerator if no block is given.
+
+Wed Apr 23 00:42:49 2008 Tanaka Akira <akr@fsij.org>
+
+ * eval.c (error_print): show full stack grace except SystemStackError.
+ backport from 1.9. [ruby-dev:31014]
+
+Wed Apr 23 00:18:45 2008 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * test/ruby/test_symbol.rb (TestSymbol#test_to_proc): Improve
+ tests of Symbol#to_proc.
+
+Tue Apr 22 22:43:05 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * eval.c (rb_proc_new, YIELD_FUNC_LAMBDA): Add a new nd_state
+ YIELD_FUNC_LAMBDA which avoids automatic `avalue' conversion for
+ arguments. This fixes a bug where [1,[2,3]].map(&:object_id)
+ fails.
+
+ * intern.h, object.c: Hide rb_proc_new() from intern.h. It should
+ not be considered an official API function yet.
+
+Tue Apr 22 21:24:32 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * eval.c (rb_proc_new): Turn the BLOCK_LAMBDA flag on.
+
+ * object.c (sym_to_proc), test/ruby/test_symbol.rb: Add back
+ Symbol#to_proc, now that it passes the tests.
+
+Tue Apr 22 19:35:03 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * enumerator.c (enumerator_initialize): Remove an undocumented
+ feature (passing a block to the constructor) that's broken.
+ This is not what I intended.
+
+Tue Apr 22 17:49:46 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * sprintf.c (rb_f_sprintf): should protect temporary string from
+ GC. [ruby-dev:34480]
+
+Tue Apr 22 17:12:05 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * regex.c (re_search): string might be NULL. [ruby-core:16478]
+
+Tue Apr 22 16:44:00 2008 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * object.c (rb_obj_tap): Correct documentation; pointed out by
+ okkez in [ruby-dev:34472].
+
+Tue Apr 22 10:05:51 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * file.c (eaccess): workaround for recent msvcrt's behavior.
+ [ruby-core:16460]
+
+Mon Apr 21 16:06:47 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * enumerator.c (enumerator_init): preserve the method name in ID.
+
+ * enumerator.c (enumerator_each): need not to call rb_to_id().
+
+ * enumerator.c (enumerator_with_index): ditto.
+
+Mon Apr 21 17:19:52 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * eval.c (rb_f_method_name): New gloval function: __method__;
+ backported from matzruby / 1.9.
+
+ * eval.c (rb_frame_this_func), intern.h: New internal function.
+
+ * intern.h (RETURN_ENUMERATOR): Use rb_frame_this_func() instead
+ of rb_frame_last_func(), to accommodate the behavior to that of
+ 1.9.
+
+Mon Apr 21 15:54:48 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/tempfile.rb (Tempfile::_close): check @data before modifying
+ it; backported from 1.9. [ruby-dev:34094]
+
+ * lib/tempfile.rb (Tempfile::close): clear @data and @tmpname.
+
+Mon Apr 21 10:17:17 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * time.c: should include <errno.h> to refer errno.
+
+Mon Apr 21 10:02:43 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * hash.c (recursive_hash): prototype.
+
+Mon Apr 21 10:00:51 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * time.c (rb_strftime): check errno to detect strftime(3)'s error.
+ this is workaround for recent version of MSVCRT.
+ [ruby-dev:34456]
+
+Sun Apr 20 21:10:04 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * .: Release as Ruby 1.8.7-preview2.
+
+Sun Apr 20 21:02:06 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * enumerator.c: Resolve the method every time an enumeration
+ method is run, not once when the enumerator is initialized as it
+ was before, so that method_missing() and method (re)definition
+ afterwards are both in effect; pointed out in: [ruby-core:16441]
+
+Sun Apr 20 17:59:25 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * object.c, NEWS, test/ruby/test_symbol.rb: Revert Symbol#to_proc
+ since it does not pass the tests.
+
+Sun Apr 20 14:29:35 2008 Technorama Ltd. <oss-ruby@technorama.net>
+
+ * ext/openssl/ossl_ssl.c: initialize session class.
+
+Sat Apr 19 20:54:42 2008 akira yamada <akira@arika.org>
+
+ * lib/uri/ftp.rb, lib/uri/generic.rb, test/uri/test_common.rb,
+ test/uri/test_ftp.rb, test/uri/test_generic.rb: backported from 1.9.
+ [ruby-dev:31318]
+
+Sat Apr 19 20:35:02 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/yaml/baseemitter.rb, lib/yaml/encoding.rb: performance
+ tuning around String#gsub.
+
+ * lib/yaml/tag.rb: Replace nodoc with stopdoc so Module methods get
+ documented.
+
+ * lib/yaml/store.rb (YAML::load): modified to support empty
+ database.
+
+ * lib/yaml/store.rb (YAML::Store::marshal_dump_supports_canonical_option?):
+ add a method to support faster PStore.
+
+Sat Apr 19 20:16:52 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/yaml/types.rb: Likewise, pass self to YAML::quick_emit;
+ merged from 1.9.
+
+ * lib/yaml.rb (quick_emit): use combination of object_id and hash to
+ identify repeated object references, since GC will reuse memory of
+ objects during output of YAML. [ruby-Bugs-8548] [ruby-Bugs-3698];
+ merged from 1.9.
+
+Sat Apr 19 20:05:39 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * array.c (rb_ary_equal, rb_ary_eql, rb_ary_hash, rb_ary_cmp):
+ Make Array#eql?, #hash, #== and #<=> use rb_exec_recursive() and
+ handle recursive data properly.
+
+ * hash.c (hash_equal, rb_hash_hash): Make Hash#eql?, #hash and #==
+ use rb_exec_recursive() and handle recursive data properly.
+
+Sat Apr 19 19:26:09 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * intern.h, eval.c (rb_exec_recursive): New internal function to
+ help perform recursive operation; backported from 1.9.
+
+Sat Apr 19 18:42:04 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * intern.h, hash.c (rb_hash_lookup): New internal function to
+ check if a key exists in a hash, ignoring #default; backported
+ from 1.9.
+
+Fri Apr 18 18:56:57 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/syck/rubyext.c (syck_genericresolver_node_import): should
+ not set instance variable "@kind" before initializing it.
+ [ruby-dev:32677]
+
+ * ext/syck/rubyext.c (syck_resolver_initialize,
+ syck_resolver_detect_implicit, syck_emitter_emit): remove unused
+ variables.
+
+Fri Apr 18 18:54:57 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/syck/rubyext.c: Node#value defined twice.
+
+ * lib/yaml/: several method redefinitions causing warnings.
+
+Fri Apr 18 16:36:16 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/rexml/node.rb (REXML::Node::indent): should initialize rv
+ variable. a patch from Tadayoshi Funaba <tadf AT dotrb.org> in
+ [ruby-dev:32783].
+
+Fri Apr 18 16:01:37 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/rexml: Merge fixes since 1.8.6 made solely on the ruby_1_8_6
+ branch.
+
+Wed Apr 16 06:11:49 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * test/ruby/test_settracefunc.rb (TestSetTraceFunc#test_event):
+ Fix tests to reflect the following changes: r15833, r15759.
+
+Wed Apr 16 05:03:48 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * .: Release as Ruby 1.8.7-preview1.
+
+Wed Apr 16 02:09:14 2008 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/xmlrpc/client.rb: fix cookie handling. [ruby-dev:34403]
+
+ * test/xmlrpc/test_cookie.rb: add a test for the above fix.
+
+Tue Apr 15 23:48:28 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * version.h: Branch off ruby_1_8_7 from ruby_1_8 in preparation
+ for the forthcoming 1.8.7 release.
+
+Tue Apr 15 23:40:39 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/syck/rubyext.c (rb_syck_mktime): Avoid buffer overflow.
+
+Tue Apr 15 20:32:03 2008 Tanaka Akira <akr@fsij.org>
+
+ * re.c (match_inspect): backported from 1.9.
+
+Tue Apr 15 19:03:28 2008 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * eval.c (method_receiver, method_name, method_owner): New
+ methods; backported from 1.9. bug#19007
+
+Tue Apr 15 18:39:14 2008 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * lib/uri.rb, lib/uri/ldaps.rb: added LDAPS
+ scheme; backported from 1.9. bug#19015, [ruby-dev:31896]
+
+Tue Apr 15 17:45:43 2008 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * lib/net/smtp.rb: backported from 1.9. bug#19003
+
+Tue Apr 15 17:06:12 2008 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * test/ruby/test_symbol.rb (TestSymbol#test_to_proc): add tests.
+
+Tue Apr 15 16:58:55 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/lib/tk/menuspec.rb: option check will fail when
+ TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__ is true.
+
+ * ext/tk/lib/tk/palette.rb: bug fix.
+
+Tue Apr 15 16:47:48 2008 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * signal.c, gc.c: New methods: GC.stress, GC.stress=;
+ backported from 1.9. a patch from Tadashi Saito
+ in [ruby-dev:34394] and bug#19000
+
+Tue Apr 15 12:35:44 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * rubyio.h (rb_io_t): renamed from OpenFile.
+
+ * ruby.h (struct RHash), file.c, gc.c, io.c, ext/dl/dl.c,
+ ext/io/wait/wait.c, ext/pty/pty.c, ext/readline/readline.c,
+ ext/socket/socket.c: ditto.
+
+ * win32/win32.h: removed workaround for OpenFile.
+
+Tue Apr 15 00:15:29 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/lib/tk/text.rb: typo. call a wrong method.
+
+ * ext/tk/lib/tk/itemconfig.rb: ditto.
+
+ * ext/tk/sample/ttk_wrapper.rb: bug fix.
+
+ * ext/tk/sample/tktextio.rb: add binding for 'Ctrl-u' at console mode.
+
+ * ext/tk/lib/tk.rb, ext/tk/lib/tk/itemfont.rb, ext/tk/lib/font.rb:
+ support __IGNORE_UNKNOWN_CONFIGURE_OPTION__ about font options.
+
+ * ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb,
+ ext/tk/lib/tkextlib/iwidgets/scrolledlistbox.rb,
+ ext/tk/lib/tkextlib/iwidgets/scrolledtext.rb: bug fix.
+
+ * ext/tk/lib/tkextlib/tile/tpaned.rb: improve TPaned#add.
+
+ * ext/tk/lib/tk/timer.rb: add TkTimer#at_end(proc) to register the
+ procedure which called at end of the timer.
+
+Mon Apr 14 19:54:21 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * array.c (rb_ary_flatten, rb_ary_flatten_bang): Take an optional
+ argument that determines the level of recursion to flatten;
+ backported from 1.9.
+
+ * array.c (rb_ary_shuffle_bang, rb_ary_shuffle, rb_ary_choice,
+ rb_ary_cycle, rb_ary_permutation, rb_ary_combination,
+ rb_ary_product, rb_ary_take, rb_ary_take_while, rb_ary_drop,
+ rb_ary_drop_while): New methods: Array#shuffle, #shuffle!,
+ #choice, #cycle, #permutation, #combination, #product, #take,
+ #take_while, #drop, #drop_while; backported from 1.9.
+
+Mon Apr 14 19:52:35 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * ruby.h: New macro: RB_GC_GUARD().
+
+Mon Apr 14 19:49:35 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * random.c (rb_genrand_int32, rb_genrand_real), intern.h: Export.
+
+ * string.c (rb_str_tmp_new), intern.h: New function.
+
+Mon Apr 14 19:18:55 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * enum.c (inject_i, inject_op_i): prototype.
+
+Mon Apr 14 19:10:47 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * enum.c New methods: Enumerable#take, #take_while, #drop and
+ #drop_while; backported from 1.9.
+
+Mon Apr 14 18:50:15 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * enum.c: New methods: Enumerable#one?, #none?, #minmax, #min_by,
+ #max_by, #minmax_by and #cycle; backported from 1.9.
+
+ * enum.c (enum_find_index): Add support for find_index(obj);
+ [ruby-dev:34313]; backported from 1.9.
+
+ * enum.c (enum_inject): Add support for Enumerable#inject(:binop);
+ backported from 1.9.
+
+ * enum.c: Alias Enumerable#reject to #inject; backported from 1.9.
+
+Mon Apr 14 18:14:19 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * enum.c (enum_find, enum_reject): Return an enumerator if no
+ block is given; backported from 1.9.
+
+ * io.c (rb_io_each_line, rb_io_each_byte, rb_io_s_foreach,
+ argf_each_line, argf_each_byte): Ditto.
+
+ * string.c (str_gsub): Ditto.
+
+Mon Apr 14 18:10:05 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * enum.c (find_index_i, find_index_iter_i): add prototype for VC.
+
+Mon Apr 14 17:55:30 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * array.c (rb_ary_collect_bang, rb_ary_select): Return an
+ enumerator if no block is given; backported from 1.9.
+
+ * dir.c (dir_each, dir_foreach): Ditto.
+
+ * enum.c (enum_partition, enum_sort_by): Ditto.
+
+ * gc.c (os_each_obj): Ditto.
+
+ * hash.c (rb_hash_delete_if, rb_hash_reject_bang, rb_hash_select,
+ rb_hash_each_value, rb_hash_each_key, rb_hash_each_pair,
+ env_each_key, env_each_value, env_each, env_each_pair,
+ env_reject_bang, env_delete_if, env_select): Ditto.
+
+ * numeric.c (num_step, int_upto, int_downto, int_dotimes): Ditto.
+
+Mon Apr 14 16:42:53 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * ruby.h (rb_block_call_func): Fix prototype.
+
+ * enumerator.c (enumerator_iter_i, enumerator_each_i): Ditto.
+
+Mon Apr 14 15:49:05 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * enum.c (enum_count, enum_find_index): New methods:
+ Enumerable#count and #find_index; backported from 1.9.
+
+Mon Apr 14 14:16:08 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * enumerator.c (enumerator_mark, enumerator_iter_i, enumerator_each_i,
+ enumerator_allocate): add prototype.
+
+ * enumerator.c (enumerator_each_i): declare unused two arguments.
+
+Mon Apr 14 13:58:32 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * string.c (rb_str_each_char): New methods: String#chars and
+ #each_char; backported from 1.9.
+
+Mon Apr 14 13:42:20 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * string.c (rb_str_each_line, rb_str_each_byte): Reflect
+ enumerator integration. #lines and #bytes are now aliases to
+ #each_line and #each_byte, respectively.
+
+Mon Apr 14 13:19:36 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * range.c (range_each, range_step): Return an enumerator if no
+ block is given; backported from 1.9.
+
+ * struct.c (rb_struct_each, rb_struct_each_pair): Ditto.
+
+Mon Apr 14 13:07:59 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * string.c (rb_str_partition, rb_str_rpartition,
+ rb_str_start_with, rb_str_end_with): New methods:
+ String#partition, #rpartition, #start_with? and #end_with?;
+ backported from 1.9. These methods are $KCODE aware unlike
+ #index, #rindex and #include?.
+
+Sun Apr 13 15:55:52 2008 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * object.c (sym_to_proc): new method Symbol#to_proc; backported
+ from 1.9. bug#19012
+
+Fri Apr 11 19:14:30 2008 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * object.c (rb_obj_tap): new method Object#tap; backported from
+ 1.9. bug#19008
+
+Fri Apr 11 18:58:09 2008 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * process.c: new method Process.exec; backported from 1.9. bug#19006
+
+Fri Apr 11 12:43:56 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/lib/tkextlib/tile.rb, ext/tk/lib/tkextlib/tile/style.rb,
+ ext/tk/sample/tkextlib/tile/demo.rb: previous patch is not complete.
+
+Fri Apr 11 10:22:54 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/lib/tkextlib/tile.rb:
+ __define_LoadImages_proc_for_compatibility__! do nothing when the
+ Tcl command exists.
+
+ * ext/tk/lib/tkextlib/tile/style.rb:
+ __define_wrapper_proc_for_compatibility__! do nothing when the Tcl
+ command exists.
+
+ * ext/tk/sample/tkextlib/tile/demo.rb: don't create 'step' theme if
+ it already exists.
+
+Fri Apr 11 08:05:12 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * marshal.c (w_object): add volatile to avoid potential GC bug. a
+ patch from Tomoyuki Chikanaga <chikanag at nippon-control-system.co.jp>
+ in [ruby-dev:34311].
+
+Thu Apr 10 20:29:13 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/rdebug.el, misc/README: Remove rdebug.el as per request
+ from the maintainer and mention the ruby-debug project at
+ RubyForge in README; bug#19043.
+
+Thu Apr 10 20:08:37 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * enum.c (enum_first, enum_group_by): New methods:
+ Enumerable#first and #group_by; backported from 1.9.
+
+Thu Apr 10 19:49:10 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * enumerator.c (rb_eStopIteration), eval.c (rb_f_loop), ruby.h:
+ Add a new exception class StopIteration, which breaks Kernel#loop
+ iteration when raised; backported from 1.9.
+
+ * enumerator.c (enumerator_next, enumerator_rewind): Implement
+ #next and #rewind using the "generator" library.
+
+ * lib/generator.rb: Implement Enumerable::Enumerator#next and
+ #rewind.
+
+Thu Apr 10 19:29:48 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * array.c (rb_ary_first, rb_ary_last): Return a shared array when
+ possible.
+
+ * array.c (rb_ary_pop, rb_ary_pop_m, rb_ary_shift, rb_ary_shift_m):
+ Array#pop and Array#shift can take an optional argument
+ specifying the number of elements to remove and return;
+ backported from 1.9.
+
+Thu Apr 10 14:00:44 2008 Tanaka Akira <akr@fsij.org>
+
+ * lib/resolv.rb (Resolv::DNS#each_address): backport from 1.9 for
+ CNAME. [ruby-dev:34200]
+
+Thu Apr 10 01:42:25 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * enum.c (iterate_method): add prototype to avoid warning on VC++.
+
+Wed Apr 9 23:12:41 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/tcltklib.c: SEGV when tcltk-stubs is enabled.
+
+ * ext/tk/tcltklib.c: avoid error on a shared object.
+
+ * ext/tk/extconf.rb: support --with-tcltkversion
+
+ * ext/tk/README.tcltklib: add document about --with-tcltkversion
+
+ * ext/tk/sample/demos-jp/widget, ext/tk/sample/demos-en/widget,
+ ext/tk/sample/demos-jp/style.rb, ext/tk/sample/demos-en/style.rb,
+ ext/tk/sample/demos-jp/bind.rb, ext/tk/sample/demos-en/bind.rb:
+ bug fix.
+
+Wed Apr 9 21:54:45 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * array.c (rb_ary_pop): Do not reallocate too often; backported
+ from 1.9.
+
+Wed Apr 9 21:13:05 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * array.c (rb_ary_each, rb_ary_each_index, rb_ary_reverse_each,
+ rb_ary_reject, rb_ary_reject_bang): Array#each, #each_index,
+ #reverse_each, #reject, #reject! and #delete_if return an
+ enumerator if no block is given; backported from 1.9.
+
+Wed Apr 9 20:47:16 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * array.c (rb_ary_index, rb_ary_index): Array#index and #rindex
+ can take a block instead of an argument; backported from 1.9.
+
+Wed Apr 9 19:58:31 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * enumerator.c, inits.c (rb_call_inits), ruby.h, intern.h,
+ ext/enumerator, common.mk (OBJS, enumerator.$(OBJEXT)): Make the
+ enumerator module built-in.
+
+ * enumerator.c: New method: Enumerable::Enumerator#with_index.
+
+ * enum.c (enum_each_with_index): Enumerable#each_with_index now
+ returns an enumerator instead of raising an exception if no
+ block is given. Enumerable#enum_with_index, formerly defined in
+ the enumerator module, is kept as an alias to each_with_index
+ for backward compatibility.
+
+Wed Apr 9 19:43:51 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * eval.c (rb_obj_method, rb_proc_call), intern.h: Export.
+
+Tue Apr 8 11:11:28 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * eval.c (EXEC_TAG): remove unnecessary FLUSH_REGISTER_WINDOWS for
+ better performance on SPARC. [ruby-core:16159]
+
+Tue Apr 8 10:49:54 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * re.c (rb_reg_quote): should always copy the quoting string.
+ [ruby-core:16235]
+
+Mon Apr 7 21:35:08 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * array.c (rb_ary_nitems): Backport Array#nitems with a block;
+ suggested by Bertram Scharpf <lists@bertram-scharpf.de> in
+ [ruby-talk:134083].
+
+Sun Apr 6 09:45:00 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (dir_tell): check if closed. [ruby-core:16223]
+
+Sat Apr 5 10:05:00 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * object.c (rb_check_to_integer): backported for range_step.
+
+Fri Apr 4 05:57:11 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/net/pop.rb (Net::POP3::do_finish): clear @n_mails and
+ @n_bytes as well. [ruby-core:16144]
+
+Fri Apr 4 02:17:06 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * range.c (range_step): should not round step into integer if
+ begin and end are numeric. [ruby-core:15990]
+
+Tue Apr 1 14:43:38 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: get rid of empty expansion.
+
+ * {bcc,win}32/Makefile (config.h): need to define RUBY_SETJMP, etc.
+
+Tue Apr 1 11:36:19 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: _setjmp is available but _longjmp is not on mingw.
+
+Tue Apr 1 03:20:40 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (RUBY_SETJMP, RUBY_LONGJMP, RUBY_JMP_BUF): prefers
+ _setjmp over setjmp and sigsetjmp. [ruby-core:16023]
+ __builtin_setjmp cannot handle a variable.
+
+ * configure.in (--with-setjmp-type): new option to override the
+ default rule in the above.
+
+ * eval_intern.h (ruby_setjmp, ruby_longjmp), gc.c (rb_setjmp),
+ vm_core.h (rb_jmpbuf_t): use RUBY_SETJMP, RUBY_LONGJMP and
+ RUBY_JMP_BUF.
+
+Tue Apr 1 01:55:52 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/resolv.rb (Resolv::Config.default_config_hash): requires
+ win32/resolv to use Win32::Resolv. [ruby-dev:34138]
+
+Mon Mar 31 14:51:11 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * bignum.c (rb_big_div): Bignum#div should return integer for
+ floating number operand.
+
+Sun Mar 30 07:00:32 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/tk/tcltklib.c: rb_hash_lookup has not been backported yet.
+
+Sat Mar 29 14:18:41 2008 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/*: full update Ruby/Tk to support Ruby(1.9|1.8) and Tc/Tk8.5.
+
+ * ext/tk/lib/tkextlib/tile.rb: [incompatible] remove TileWidgets'
+ instate/state/identify method to avoid the conflict with standard
+ widget options. Those methods are renamed to ttk_instate/ttk_state/
+ ttk_identify (tile_instate/tile_state/tile_identify are available
+ too). Although I don't recommend, if you realy need old methods,
+ please define "Tk::USE_OBSOLETE_TILE_STATE_METHOD = true" before
+ "require 'tkextlib/tile'".
+
+ * ext/tk/lib/tkextlib/tile.rb: "Tk::Tile::__Import_Tile_Widgets__!"
+ is obsolete. It outputs warning. To control default widget set,
+ use "Tk.default_widget_set = :Ttk".
+
+ * ext/tk/lib/tk.rb: __IGNORE_UNKNOWN_CONFIGURE_OPTION__ method and
+ __set_IGNORE_UNKNOWN_CONFIGURE_OPTION__!(mode) method are defind
+ as module methods of TkConfigMethod. It may help users to wrap old
+ Ruby/Tk scripts (use standard widgets) to force to use Ttk widgets.
+ Ttk widgets don't have some options of standard widgets which are
+ control the view of widgets. When set ignore-mode true, configure
+ method tries to ignoure such unknown options with no exception.
+ Of course, it may raise other troubles on the GUI design.
+ So, those are a little danger methods.
+
+ * ext/tk/lib/tk/itemconfig.rb: __IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ method and __set_IGNORE_UNKNOWN_CONFIGURE_OPTION__!(mode) method
+ are defind as module methods of TkItemConfigMethod as the same
+ purpose as TkConfigMethod's ones.
+
+ * ext/tk/sample/ttk_wrapper.rb: A new example. This is a tool for
+ wrapping old Ruby/Tk scripts (which use standard widgets) to use
+ Ttk (Tile) widgets as default.
+
+ * ext/tk/sample/tkextlib/tile/demo.rb: use ttk_instate/ttk_state
+ method instead of instate/state method.
+
+ * ext/tk/lib/tk/root, ext/tk/lib/tk/namespace.rb,
+ ext/tk/lib/tk/text.rb, ext/tk/lib/tkextlib/*: some 'instance_eval's
+ are replaced to "instance_exec(self)".
+
+ * ext/tk/lib/tk/event.rb: bug fix on KEY_TBL and PROC_TBL (?x is not
+ a character code on Ruby1.9).
+
+ * ext/tk/lib/tk/variable.rb: support new style of operation argument
+ on Tcl/Tk's 'trace' command for variables.
+
+ * ext/tk/sample/demos-jp/widget, ext/tk/sample/demos-en/widget: bug fix
+
+ * ext/tk/sammple/demos-jp/textpeer.rb,
+ ext/tk/sammple/demos-en/textpeer.rb: new widget demo.
+
+ * ext/tk/tcltklib.c: decrase SEGV troubles (probably)
+
+ * ext/tk/lib/tk.rb: remove Thread.critical access if Ruby1.9
+
+ * ext/tk/lib/tk/multi-tk.rb: support Ruby1.9 (probably)
+
+ * ext/tk/lib/tkextlib/tile.rb: add method to define Tcl/Tk command
+ to make Tcl/Tk theme sources (based on different version of Tile
+ extension) available.
+ (Tk::Tile::__define_LoadImages_proc_for_comaptibility__)
+
+ * ext/tk/lib/tk.rb, ext/tk/lib/tk/wm.rb: support dockable frames
+ (Tcl/Tk8.5 feature). 'wm' command can treat many kinds of widgets
+ as toplevel widgets.
+
+ * ext/tk/lib/tkextlib/tile/style.rb: ditto.
+ (Tk::Tile::Style.__define_wrapper_proc_for_compatibility__)
+
+ * ext/tk/lib/tk/font.rb: add actual_hash and metrics_hash to get
+ properties as a hash. metrics_hash method returns a boolean value
+ for 'fixed' option. But metrics method returns numeric value
+ (0 or 1) for 'fixed' option, because of backward compatibility.
+
+ * ext/tk/lib/tk/timer.rb: somtimes fail to set callback procedure.
+
+ * ext/tk/lib/tk.rb: add Tk.sleep and Tk.wakeup method. Tk.sleep
+ doesn't block the eventloop. It will be better to use the method
+ in event callbacks.
+
+ * ext/tk/sample/tksleep_sample.rb: sample script about Tk.sleep.
+
+Sat Mar 29 04:08:59 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * class.c (clone_method): should copy cref as well.
+ [ruby-core:15833]
+
+Mon Mar 24 20:07:42 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * eval.c (rb_eval): Call trace hook for if expression after the
+ condition has been evaluated, not before; submitted by Rocky
+ Bernstein in #18722.
+
+Mon Mar 24 19:44:53 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * parse.y (yycompile): Always prepare a new array for each file's
+ SCRIPT_LINES__ storage, instead of appending source lines every
+ time a file is re-loaded; submitted by Rocky Bernstein in
+ #18517.
+
+Mon Mar 24 10:25:54 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: sitearch should use target_cpu. [ruby-core:15986]
+
+Mon Mar 24 01:24:24 2008 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * lib/erb.rb (result): use proc instead of Thread. [ruby-dev:33692]
+
+Fri Mar 21 21:26:52 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/resolv.rb (Resolv::Hosts): should not use win32/resolv on cygwin.
+ [ruby-dev:29945], [ruby-dev:34095]
+
+ * lib/win32/registry.rb (Win32::Registry.expand_environ): try upcased
+ name too for cygwin. [ruby-dev:29945]
+
+ * lib/win32/resolv.rb (Win32::Resolv.get_hosts_path): use expand_path.
+
+Fri Mar 21 21:10:00 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/ipaddr.rb: Say that I am the current maintainer.
+
+ * lib/set.rb: Ditto.
+
+ * lib/shellwords.rb: Ditto.
+
+ * ext/syslog/syslog.txt: Ditto.
+
+Fri Mar 21 09:24:28 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * instruby.rb (open_for_install): write block result and rewrite only
+ if changed from existing file.
+
+Wed Mar 19 21:01:08 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (dir_inspect, dir_path, dir_tell): check for frozen and closed
+ is not needed. [ruby-dev:32640]
+
+Wed Mar 19 20:25:40 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (Init_Dir): define inspect method. [ruby-core:15960]
+
+Wed Mar 19 14:59:12 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * misc/ruby-style.el (ruby-style-{case,label}-indent): fix for labels
+ inside blocks in switch and function top level.
+
+Wed Mar 19 14:36:40 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (rb_cstr_to_inum): treat successive underscores as
+ nondigit. [ruby-dev:34089]
+
+Wed Mar 19 00:01:23 2008 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * lib/erb.rb (ERB::Compiler): Make some minor code optimization.
+
+Mon Mar 17 17:11:13 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * misc/ruby-mode.el (ruby-mode): should use `run-mode-hooks' instead
+ of calling `run-hooks' directly to run the mode hook. patch from
+ Chiyuan Zhang <pluskid AT gmail.com> in [ruby-core:15915]
+
+Mon Mar 17 16:41:08 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: unset GREP_OPTIONS. [ruby-core:15918]
+
+Fri Mar 14 16:59:23 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (RUBY_LIB_PREFIX): fix for prefix.
+
+Fri Mar 14 16:35:11 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/cgi.rb (CGI::Cookie::initialize): performance patch from
+ Makoto Kuwata <kwa@kuwata-lab.com> in [ruby-dev:34048].
+
+Fri Mar 14 15:49:05 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (RUBY_LIB_PREFIX): use libdir.
+
+Fri Mar 14 10:12:29 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (RUBY_CHECK_VARTYPE): should not indent preprocessor
+ directives.
+
+Thu Mar 13 00:37:20 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_call0): yields the last executed node line number at
+ return event. [ruby-core:15855]
+
+Wed Mar 12 02:12:20 2008 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * lib/delegate.rb: check $@ to avoid NoMethodError.
+
+Tue Mar 11 19:48:09 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (fix_coerce): try conversion before type check.
+ [ruby-core:15838]
+
+Tue Mar 11 17:03:23 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/delegate.rb (Delegator#initialize, DelegateClass): skip correct
+ backtrace. [ruby-dev:34019]
+
+Tue Mar 11 16:43:53 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_cmdvector): terminate shrunken command line.
+
+Tue Mar 11 12:39:03 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (clean-local): removes MINOBJS.
+
+Sat Mar 8 18:50:57 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (isdirsep): backslash is valid path separator on cygwin too.
+
+Fri Mar 7 19:56:10 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb: rdoc added. [ruby-Patches-9762]
+
+Thu Mar 6 15:10:21 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * {bcc32,win32}/Makefile.sub (RUNRUBY): use $(PROGRAM) instead of
+ ruby$(EXEEXT).
+ suggested by KIMURA Koichi <kimura.koichi at canon.co.jp>.
+ [ruby-dev:34000]
+
+Thu Mar 6 12:15:06 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (opt_block_param): command can start just after block param
+ definition. [ruby-list:44479]
+
+Thu Mar 6 00:34:11 2008 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * lib/erb.rb: update RDoc. Thanks Makoto Kuwata [ruby-dev:33702]
+
+Mon Mar 3 23:28:34 2008 GOTOU Yuuzou <gotoyuzo@notwork.org>
* lib/webrick/httpservlet/filehandler.rb: should normalize path
separators in path_info to prevent directory traversal attacks
@@ -120,7 +4188,1050 @@ Mon Mar 3 23:36:41 2008 GOTOU Yuuzou <gotoyuzo@notwork.org>
* lib/webrick/httpservlet/filehandler.rb: pathnames which have
not to be published should be checked case-insensitively.
-Sun Sep 23 21:57:25 2007 GOTOU Yuuzou <gotoyuzo@notwork.org>
+Mon Mar 3 16:14:24 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (rb_any_hash): shrinks all results in Fixnum range.
+ [ruby-core:15713]
+
+Sat Mar 1 02:35:08 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (big2str_find_n1): check integer overflow.
+
+Tue Feb 26 16:06:00 2008 Technorama Ltd. <oss-ruby@technorama.net>
+
+ * ext/openssl/ossl_pkey_{ec,dh,dsa,rsa}.c: Remove useless warnings.
+
+ * ext/openssl/ossl_asn1.c: Simplify code.
+
+ * ext/openssl/ossl_ssl_session.c Fix compiler warnings.
+ Undefine #id if SSL_SESSION_get_id is not supported.
+
+Tue Feb 26 15:43:42 2008 Tanaka Akira <akr@fsij.org>
+
+ * parse.y (tokadd_escape): refactored. [ruby-core:15657]
+
+Mon Feb 25 17:30:29 2008 Technorama Ltd. <oss-ruby@technorama.net>
+
+ * ext/openssl/digest.c ext/openssl/lib/openssl/digest.rb:
+ Commit patch #9280 from Akinori MUSHA.
+ Simplify the OpenSSL::Digest class and make use of the
+ existing Digest framework.
+ Enhance performance.
+
+Mon Feb 25 13:40:03 2008 Tanaka Akira <akr@fsij.org>
+
+ * process.c (Init_process): share bignum objects for RLIM_INFINITY,
+ RLIM_SAVED_MAX and RLIM_SAVED_CUR if they are equal.
+
+Sun Feb 24 23:29:48 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk, {bcc,win}32/Makefile.sub (clean-local): remove
+ intermediate files.
+
+Sun Feb 24 03:52:58 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * util.c (valid_filename): use O_EXCL to get rid of clobbering
+ existing files in race conditions.
+
+Fri Feb 22 19:50:19 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (BIGZEROP): fix for longer Bignum zeros. [ruby-Bugs-17454]
+
+Fri Feb 22 16:09:53 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (rb_big_lshift, rb_big_rshift, rb_big_aref): removed excess
+ arguments.
+
+Thu Feb 21 00:01:34 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (RPATHFLAG): -R option of HP-UX ld is not for runtime
+ load path. [ruby-list:44600]
+
+Wed Feb 20 23:55:19 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_map_errno): exported.
+
+Wed Feb 20 13:08:52 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * instruby.rb (parse_args): added --dir-mode, --script-mode and
+ --cmd-type options. [ruby-dev:33816]
+
+ * instruby.rb (parse_args): added bin-arch and bin-comm to install
+ type, for compiled files and script files.
+
+ * instruby.rb (parse_args): deal with make style command line macros,
+ and count as long syle options if prefixed with INSTALL_.
+
+ * instruby.rb (makedirs): use $dir_mode. [ruby-dev:33805]
+
+ * instruby.rb (open_for_install): set file mode, which is now
+ permission mode instead of access mode.
+
+ * instruby.rb (bin-comm): installs scripts with replacing shebang
+ lines.
+
+Tue Feb 19 18:34:32 2008 Tanaka Akira <akr@fsij.org>
+
+ * gc.c (STACK_LENGTH) [SPARC] : 0x80 offset removed. [ruby-dev:33857]
+
+Tue Feb 19 14:27:32 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/readline/readline.c (readline_event): prevent polling. based on
+ a patch from error errorsson in [ruby-Bugs-17675].
+
+Tue Feb 19 12:08:29 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (yycompile): clear ruby_eval_tree_begin if parse failed.
+
+Mon Feb 18 16:23:45 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (yycompile): clear ruby_eval_tree_begin too before parse.
+
+Mon Feb 18 10:17:42 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/pty/lib/expect.rb (IO#expect): check if peer is closed.
+ [ruby-Bugs-17940]
+
+Fri Feb 15 20:37:06 2008 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/rational.rb (floor, ceil, truncate, round): do not use
+ definitions of Numeric.
+
+ * lib/rational.rb (to_i): should returns truncated self.
+
+ * lib/complex.rb (numerator): requires
+ Integer#{numerator,denominator}.
+
+ * lib/complex.rb (quo): do not use definition of Numeric.
+
+ * lib/complex.rb (div, divmod, floor, ceil, truncate, round):
+ undef'ed.
+
+Fri Feb 15 15:23:12 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/iconv/iconv.c (iconv_convert): check upper bound. a patch from
+ Daniel Luz at [ruby-Bugs-17910].
+
+Fri Feb 15 02:42:25 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (ftruncate): check if available.
+
+ * file.c (rb_file_truncate): check if ftruncate instead of truncate.
+
+Fri Feb 15 02:40:54 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (sigsetmask): check when signal semantics is not POSIX.
+
+ * signal.c (USE_TRAP_MASK): set true if sigprocmask or sigsetmask is
+ available.
+
+Thu Feb 14 17:44:32 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * ext/dl/ptr.c (dlmem_each_i): typo fixed. a patch from IKOMA
+ Yoshiki <ikoma AT mb.i-chubu.ne.jp> in [ruby-dev:33776].
+
+Thu Feb 14 16:02:51 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (rb_file_s_utime): inhibits with secure level 2 or higher.
+
+Thu Feb 14 01:43:16 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/timeout.rb (Timeout::timeout): made sensitive to location on the
+ stack. [ruby-core:15458]
+
+Thu Feb 14 00:49:53 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (INSTRUBY_ARGS): pass mode to install. [ruby-dev:33766]
+
+ * instruby.rb (parse_args): added --data-mode and --prog-mode options.
+
+Tue Feb 12 11:33:26 2008 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * test/erb/test_erb.rb(TestERBCore): import from erb-2.0.4.
+
+ * test/erb/hello.erb: ditto
+
+Mon Feb 11 17:25:21 2008 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rss/rss.rb (RSS::VERSION), test/rss/test_version.rb, NEWS:
+ 0.2.3 -> 0.2.4.
+
+ * lib/rss/maker.rb, lib/rss/maker/, test/rss/test_maker_2.0.rb:
+ fixed a bug that RSS::Maker.make("0.9")'s item doesn't make some
+ elements if description is missed.
+ Reported by Michael Auzenne. Thanks!!!
+
+ * lib/rss/maker/0.9.rb, test/rss/test_maker_0.9.rb:
+ RSS::Maker.make("0.9") generates RSS 0.92 not RSS 0.91.
+
+Mon Feb 11 16:57:00 2008 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * ChangeLog: format-time-string under C locale. [ruby-dev:33261]
+
+Mon Feb 11 16:31:47 2008 URABE Shyouhei <shyouhei@ice.uec.ac.jp>
+
+ * gc.c (rb_newobj): prohibit call of rb_newobj() during gc.
+ Submitted by Sylvain Joyeux [ruby-core:12099].
+
+ * ext/dl/ptr.c: do not use LONG2NUM() inside dlptr_free().
+ Slightly modified fix bassed on a patch by Sylvain Joyeux
+ [ruby-core:12099] [ ruby-bugs-11859 ] [ ruby-bugs-11882 ]
+ [ ruby-patches-13151 ].
+
+Mon Feb 11 00:22:55 2008 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/benchmark.rb (Job::Benchmark#item): fix typo.
+
+Sat Feb 9 23:22:52 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/bigdecimal/extconf.rb: simplified the condition.
+
+Sat Feb 9 17:51:24 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_to_f): use strtod() for more
+ precision. [ruby-talk:290296]
+
+ * ext/bigdecimal/bigdecimal.c (BASE_FIG): made constant.
+
+ * ext/bigdecimal/extconf.rb: ditto. [ruby-dev:33658]
+
+Sat Feb 9 00:44:52 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/irb.rb (IRB::Irb::eval_input): rescues Interrupt and other than
+ SystemExit and SignalException. [ruby-core:15359]
+
+Fri Feb 8 15:09:21 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (xsystem): expand macros like as make.
+
+Tue Feb 5 11:14:11 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (INSTALL_DIRS, install_dirs): added BINDIR.
+
+ * lib/mkmf.rb (install_files): rejects files matching to
+ $NONINSTALLFILES.
+
+ * lib/mkmf.rb (init_mkmf): defaults $NONINSTALLFILES to backup and
+ temporary filse.
+
+Mon Feb 4 16:44:24 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (darwin): NSIG is not defined if _XOPEN_SOURCE > 500L.
+ [ruby-dev:33584]
+
+Sat Feb 2 20:06:42 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/benchmark.rb (Benchmark::realtime): make Benchmark#realtime
+ a bit faster. a patch from Alexander Dymo <dymo AT ukrpost.ua> in
+ [ruby-core:15337].
+
+Sat Feb 2 09:53:39 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (darwin): disabled fat-binary support which confuses
+ configure much, since ``universal'' implies hidden cross-compiling.
+ TODO: ruby and libruby.bundle might be possible to bound with `lipo'
+ after builds for each archs. Anyway, config.h and rbconfig.rb must
+ be separated definitely at least.
+
+Fri Feb 1 21:42:37 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (darwin): _XOPEN_SOURCE is necessary to make ucontext_t
+ consistent with the library implementation of MacOS X 10.5.
+ [ruby-dev:33461]
+
+ * configure.in (darwin): ucontext on PowerPC MacOS X 10.5 is broken.
+
+Thu Jan 31 08:31:19 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (ext/extmk.rb, instruby.rb): inlined $(MAKE) so that can
+ be executed even with -n.
+
+Thu Jan 31 07:00:19 2008 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * lib/rinda/tuplespace.rb (bin_for_find): should find a symbol by
+ Symbol class.
+
+ * test/rinda/test_rinda.rb (test_symbol_tuple): ditto.
+
+Wed Jan 30 22:07:58 2008 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date.rb: refined deprecated methods.
+
+Wed Jan 30 22:06:54 2008 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * bignum.c (rb_cstr_to_inum): '0_2' is a valid representation.
+
+Tue Jan 29 22:40:12 2008 Yusuke Endoh <mame@tsg.ne.jp>
+
+ * range.c (step_i): rb_funcall receives VALUE as an argument.
+
+Tue Jan 29 11:53:05 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: rm largefile.h.
+
+Mon Jan 28 01:21:15 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * io.c (rb_open_file): should check NUL in path.
+ <http://www.rubyist.net/~matz/20080125.html#c01>.
+
+ * io.c (rb_io_s_popen): ditto.
+
+ * io.c (rb_io_reopen): ditto.
+
+ * io.c (next_argv): ditto.
+
+ * io.c (rb_io_s_foreach): ditto.
+
+ * io.c (rb_io_s_readlines): ditto.
+
+ * io.c (rb_io_s_read): ditto.
+
+Fri Jan 25 22:33:38 2008 Yusuke Endoh <mame@tsg.ne.jp>
+
+ * math.c: fix comment. [ruby-dev:33276]
+
+Fri Jan 25 10:31:58 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * */*.bat: set svn:mime-type to text/batch.
+
+Thu Jan 24 19:36:22 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/uri/generic.rb (URI::Generic::inspect): use Kernel#to_s instead
+ object_id with printf. [ruby-dev:33347]
+
+Tue Jan 22 11:22:47 2008 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/setup.mak ($(ARCH)): if a macro is appended by $(APPEND),
+ a space will be inserted on the top of the line.
+
+ * win32/Makefile.sub (MKFILES): stop make process if Makefile is
+ updated.
+
+Mon Jan 21 17:34:41 2008 Akinori MUSHA <knu@iDaemons.org>
+
+ * io.c (rb_io_mode_flags, rb_io_mode_modenum): Ignore encoding
+ options for forward compatibility.
+
+Mon Jan 21 12:50:02 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c, gc.c (setjmp): sigsetjmp is a macro on cygwin.
+
+Sat Jan 19 11:21:53 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (sigsetjmp): check if available.
+
+ * eval.c, gc.c (setjmp): do not use _setjmp if sigsetjmp is available.
+
+Sat Jan 19 11:10:11 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: Remove wrong assumptions about Cygwin. a patch from
+ Corinna Vinschen in [ruby-Bugs-17018].
+
+Thu Jan 17 21:06:01 2008 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date.rb (Date::Infinity#<=>): didn't work. A patch from
+ Dirkjan Bussink <d.bussink AT gmail.com> [ruby-core:15098].
+ This is a bug obviously. However it didn't affect the library's
+ functions.
+
+ * lib/date.rb, lib/date/format.rb: some trivial changes.
+
+Tue Jan 15 15:09:28 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/setup.mak: strip out empty lines from CPP output.
+
+Tue Jan 15 03:41:42 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (eval): check if backtrace is empty. [ruby-core:15040]
+
+Tue Jan 15 01:28:47 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk: simplified dummy objects dependencies.
+
+Mon Jan 14 16:12:58 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/shellwords.rb: scape should be an alias to shellescape. a
+ patch from Masahiro Kawato <m-kawato AT mwb.biglobe.ne.jp> in
+ [ruby-dev:33060].
+
+Mon Jan 14 09:32:40 2008 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/time.rb: do not reference Time directly from the inside of
+ definitions. [ruby-dev:33059]
+
+Sat Jan 12 18:27:41 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_define_alloc_func, rb_undef_alloc_func): should
+ define/undef on a signleton class. [ruby-core:09959]
+
+Sat Jan 12 12:04:14 2008 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date.rb, lib/date/format.rb: tuning for performance.
+
+Fri Jan 11 12:35:56 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: moved broken syscall checks from process.c etc.
+
+ * defines.h (WORDS_BIGENDIAN): honor __BIG_ENDIAN__ than the result of
+ configure.
+
+ * dln.c: use dlopen on Mac OS X 10.3 or later. backport from trunk.
+
+ * lib/rdoc/options.rb (check_diagram): more precise check, darwin
+ is not Windows but minwg is on it.
+
+Thu Jan 10 10:53:50 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_open_osfhandle): reverted to old definition.
+ [ ruby-Bugs-16948 ]
+
+Tue Jan 8 20:02:08 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win{32,ce}/Makefile.sub: merged.
+
+Sun Jan 6 09:39:02 2008 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date.rb, lib/date/format.rb: introduced some constants
+ (for internal use).
+
+ * sample/cal.rb: trivial adjustments.
+
+Fri Jan 4 23:08:48 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * time.c (time_arg): use converted object. [ruby-core:14759]
+
+Fri Jan 4 01:20:21 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32.h: only VC6 needs extern "C++" for math.h. [ruby-talk:285660]
+
+Thu Jan 3 11:28:58 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (fptr_finalize): clear errno first. [ruby-talk:284492]
+
+Wed Jan 2 10:18:56 2008 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * sample/time.rb: use Process.times instead of Time.times.
+
+Wed Jan 2 09:18:11 2008 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * sample/goodfriday.rb: examples for date are enough. retired.
+
+Wed Jan 2 09:06:55 2008 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * sample/cal.rb: just updated with the newest version.
+
+Mon Dec 31 06:50:38 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * trunk/common.mk: not use -I$(srcdir)/lib with $(MINIRUBY) for cross
+ compiling.
+
+ * configure.in, {win,bcc}32/Makefile.sub (MINIRUBY): -I$(srcdir)/lib
+ moved.
+
+Sun Dec 30 22:48:37 2007 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date.rb (_valid_time?): I'm not sure to recommend such an
+ expression. but anyway it is acceptable now. [ruby-core:14580]
+
+Fri Dec 28 16:36:33 2007 NARUSE, Yui <naruse@airemix.com>
+
+ * lib/resolv.rb (Resolv::DNS#each_address): now returns IPv6 address.
+
+Fri Dec 28 13:21:32 2007 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rss/rss.rb, test/rss/test_version.rb, NEWS: 0.2.2 -> 0.2.3.
+
+ * lib/rss/parser.rb, test/rss/test_parser.rb: supported "-" in tag name.
+ Reported by Ray Chen. Thanks.
+
+Thu Dec 27 23:56:01 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * mkconfig.rb: should not use the libraries under the source directory
+ at cross compiling.
+
+Thu Dec 27 11:02:45 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * intern.h, string.c (rb_str_set_len): added for upgrading path from
+ 1.8 to 1.9. [ruby-dev:32807]
+
+ * string.c (rb_str_lines, rb_str_bytes): ditto.
+
+Thu Dec 27 10:47:32 2007 Technorama Ltd. <oss-ruby@technorama.net>
+
+ * ext/openssl/ossl_ssl.c: Only show a warning if the default
+ DH callback is actually used.
+
+ * ext/openssl/ossl_rand.c: New method: random_add().
+
+Wed Dec 26 22:27:45 2007 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/resolv.rb (Resolv::DNS::Name.==): fix for other is array of
+ Resolv::DNS::Label::Str.
+
+ * lib/resolv.rb (Resolv::DNS::MessageEncoder#put_label): String#string
+ is not defined, so replace to_s.
+
+ * lib/resolv.rb (Resolv::IPv6#to_name): ip6.int is obsoleted by
+ int.arpa.
+
+Mon Dec 24 16:18:57 2007 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rdoc/ri/ri_options.rb: Fix ri --help listing of gem ri paths.
+ Merge of r14567 and r14569 from trunk.
+
+ * lib/rdoc/ri/ri_paths.rb: Fix duplication of ri data for multiple
+ gems. Merge of r14567 from trunk
+
+Mon Dec 24 12:35:03 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win{32,ce}/Makefile.sub (MFLAGS): defaulted to -l.
+
+Mon Dec 24 11:56:31 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * {bcc32,win{32,ce}}/Makefile.sub (SET_MAKE): set MFLAGS which is not
+ set by default, to get rid of chaotic situation of MFLAGS/MAKEFLAGS.
+
+Sat Dec 22 14:49:46 2007 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date.rb: don't freeze nil even if 1.8 will not be aware of
+ the issue. [ruby-dev:32677]
+
+Wed Dec 19 13:57:43 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (TIMEZONE_VOID): check whether timezone requires zero
+ arguments. [ruby-dev:32631]
+
+Wed Dec 19 12:01:42 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (f_rest_arg): check if duplicated. [ruby-core:14140]
+
+Wed Dec 19 10:52:29 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (rb_cstr_to_inum): an underscore succeeding after octal
+ prefix is allowed. [ruby-core:14139]
+
+Mon Dec 17 13:43:15 2007 Tanaka Akira <akr@fsij.org>
+
+ * gc.c (stack_end_address): use local variable address instead of
+ __builtin_frame_address(0) to avoid SEGV on SunOS 5.11 on x86 with
+ gcc (GCC) 3.4.3 (csl-sol210-3_4-20050802).
+ stack_end_address returned a frame address of garbage_collect
+ since stack_end_address doesn't create its own frame.
+ So a VALUE stored in a callee saved register, %edi, pushed into
+ the stack at the beginning of garbage_collect was not marked.
+
+Mon Dec 17 12:21:25 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * Makefile.in (RUNRUBY): added RUNRUBYOPT.
+
+Fri Dec 14 12:36:35 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (RUBY_CHECK_VARTYPE): check if a variable is defined
+ and its type.
+
+ * configure.in (timezone, altzone): check for recent cygwin.
+
+ * missing/strftime.c (strftime): fix for timezone. [ruby-dev:32536]
+
+ * lib/mkmf.rb (try_var): should fail for functions.
+
+ * ext/readline/extconf.rb: should use have_func for functions instead
+ of have_var.
+
+Tue Dec 11 00:04:05 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * array.c (rb_ary_slice_bang): If an invalid negative index (<
+ -size) is given, do not raise an exception but return nil just
+ like slice() does.
+
+ * test/ruby/test_array.rb (TestArray::test_slice,
+ TestArray::test_slice!): Pull in test cases from trunk.
+
+Mon Dec 10 21:47:53 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * transcode.c (str_transcode): allow non-registered encodings.
+ [ruby-dev:32520]
+
+Mon Dec 10 21:00:30 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * array.c (rb_ary_slice_bang): should return nil if position out
+ of range. a patch from Akinori MUSHA <knu AT iDaemons.org>.
+ [ruby-dev:32518]
+
+Mon Dec 10 18:28:06 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/uri/common.rb (URI::REGEXP::PATTERN): typo in REG_NAME
+ regular expression. a patch from Ueda Satoshi
+ <s-ueda AT livedoor.jp>. [ruby-dev:32514]
+
+Sun Dec 9 12:39:01 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/cgi.rb (read_multipart): exclude blanks from header values.
+ [ruby-list:44327]
+
+Wed Dec 5 23:38:50 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * range.c (range_each): followed step_i change.
+
+Wed Dec 5 18:08:45 2007 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (int_odd_p): new method Integer#odd?.
+ (int_even_p): new method Integer#even?.
+ (int_pred): new method Integer#pred.
+ (fix_odd_p): new method Fixnum#odd?.
+ (fix_even_p): new method Fixnum#even?.
+
+Wed Dec 5 15:15:21 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * range.c (step_i, range_step): support non-fixnum steps.
+ [ruby-talk:282100]
+
+Tue Dec 4 11:23:50 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (rb_cstr_to_inum): trailing spaces may exist at sqeezing
+ preceeding 0s. [ruby-core:13873]
+
+Sun Dec 2 22:43:45 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (error_print): put newline unless multiple line message ends
+ with a newline. [ruby-dev:32429]
+
+Sun Dec 2 15:49:20 2007 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rss/rss.rb, test/rss/test_version.rb, NEWS: 0.2.1 -> 0.2.2.
+
+ * lib/rss/maker/itunes.rb: fixed new_itunes_category.
+ * lib/rss/maker/taxonomy.rb: new_taxo_topic -> new_topic because
+ of consistency.
+
+ * test/rss/test_maker_itunes.rb, test/rss/test_itunes.rb: removed
+ needless UTF-8 characters.
+
+Sun Dec 2 01:12:15 2007 James Edward Gray II <jeg2@ruby-lang.org>
+
+ Merged 14070 from trunk.
+
+ * lib/xmlrpc/server.rb (XMLRPC::Server#server): Improve signal handling so
+ pressing control-c in the controlling terminal or sending SIGTERM stops
+ the XML-RPC server.
+
+Sat Dec 1 15:13:33 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/resolv.rb: documentation update. backported from 1.9.
+ [ruby-core:13273]
+
+Sat Dec 1 03:30:47 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (newline_node): set line from outermost node before removing
+ NODE_BEGIN. [ruby-dev:32406]
+
+Fri Nov 30 21:53:28 2007 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rss/rss.rb, test/rss/test_version.rb: 0.2.0 -> 0.2.1.
+
+ * lib/rss/content.rb, lib/rss/content/1.0.rb,
+ lib/rss/content/2.0.rb, lib/rss/maker/content.rb,
+ test/rss/rss-testcase.rb, test/rss/test_content.rb,
+ test/rss/test_maker_content.rb: supported content:encoded with RSS
+ 2.0.
+ Suggested by Sam Lown. Thanks.
+
+ * NEWS: added the above changes.
+
+Thu Nov 29 16:59:10 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (stmt): remove unnecessary NODE_BEGIN. [ruby-core:13814]
+
+Wed Nov 28 14:43:14 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/extmk.rb (extract_makefile): use dldflags instead of DLDFLAGS to
+ get rid of mixing $LDFLAGS and $ARCH_FLAG.
+
+ * lib/mkmf.rb (configuration): ditto.
+
+ * lib/mkmf.rb (create_makefile): support for extensions which has no
+ shared object.
+
+Wed Nov 28 09:51:42 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (rb_big2str0): do not clobber space for sign.
+
+ * sprintf.c (remove_sign_bits): extends sign bit first.
+
+Wed Nov 21 01:04:12 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * object.c (nil_plus): remove unused function. [ruby-core:13737]
+
+Sun Nov 18 14:03:44 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_alias): do not call hook functions until initialization
+ finishes. [ruby-talk:279538]
+
+Sun Nov 18 09:09:48 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (String#tr_cpp): make preprocessor identifiers.
+
+Sat Nov 17 13:58:11 2007 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (ole_invoke): bug fix. [ruby-talk:279100]
+
+Fri Nov 16 17:41:34 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/iconv/iconv.c (Document-class): moved the simplest example to
+ the top.
+
+ * ext/iconv/iconv.c (iconv_s_iconv): Document-method: needs class
+ prefix for class method. [ruby-core:13542]
+
+ * ext/iconv/iconv.c (iconv_iconv): also instance method needs to be
+ qualified.
+
+Fri Nov 16 11:16:41 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/yaml/rubytypes.rb (String#is_binary_data?): use Integer#fdiv.
+
+Thu Nov 15 19:50:46 2007 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/curses/extconf.rb: check macro if cannot find func.
+ [ruby-list:44224]
+
+Thu Nov 15 12:19:14 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/cgi/session.rb (CGI::Session::FileStore::restore): use
+ lockfile for exclusive locks. a patch from <tommy AT tmtm.org>.
+ [ruby-dev:32296]
+
+Wed Nov 14 01:52:59 2007 Tanaka Akira <akr@fsij.org>
+
+ * missing/isinf.c (isinf): don't define if the macro is defined.
+
+Wed Nov 14 01:34:42 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (round): fallback definition.
+
+ * numeric.c (flo_divmod, flo_round): use round() always.
+ [ruby-dev:32269]
+
+Tue Nov 13 22:02:23 2007 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * lib/drb/drb.rb: remove Thread.exclusive.
+
+ * lib/drb/extservm.rb: ditto.
+
+Tue Nov 13 16:33:07 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (flodivmod): work around for infinity.
+
+ * numeric.c (flo_divmod): work around for platforms have no round().
+ [ruby-dev:32247]
+
+Tue Nov 13 13:58:51 2007 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (numeric.c): Integer#ord implemented. [ruby-dev:32206]
+
+Tue Nov 13 02:57:04 2007 URABE Shyouhei <shyouhei@ice.uec.ac.jp>
+
+ * numeric.c (flo_divmod): round to the nearest integer.
+ [ ruby-Bugs-14540 ]
+
+Mon Nov 12 16:52:29 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (create_makefile): rdoc about srcprefix. a patch from
+ Daniel Berger <djberg96 AT gmail.com> in [ruby-core:13378].
+
+Mon Nov 12 13:53:06 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * misc/ruby-mode.el (ruby-parse-partial): handle stringified
+ symbols properly using ruby-forward-string.
+
+Mon Nov 12 12:38:31 2007 Tanaka Akira <akr@fsij.org>
+
+ * Makefile.in (lex.c): don't remove lex.c at first.
+
+Fri Nov 9 07:26:04 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * random.c: update MT URL.[ruby-core:13305].
+
+Wed Nov 7 03:32:38 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/rexml/encodings/SHIFT-JIS.rb (REXML::Encoding): place -x for
+ nkf conversion. a patch from <moonwolf AT moonwolf.com>.
+ [ruby-dev:32183]
+
+Mon Nov 5 05:17:04 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/optparse.rb (OptionParser::Switch::summarize): fix for long form
+ option with very long argument. a patch from Kobayashi Noritada
+ <nori1 AT dolphin.c.u-tokyo.ac.jp> in [ruby-list:44179].
+
+Mon Nov 5 01:20:33 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * parse.y (call_args): remove "parenthesize argument(s) for future
+ version" warning. when I added this warning, I had a plan to
+ reimplement the parser that is simpler than the current one.
+ since we abandoned the plan, warning no longer required.
+
+Fri Nov 2 00:13:51 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * array.c (rb_ary_assoc): check and convert inner arrays (assocs)
+ using #to_ary.
+
+ * hash.c (rb_hash_s_create): check and convert argument hash
+ using #to_hash.
+
+ * hash.c (rb_hash_s_create): Hash#[] now takes assocs as source of
+ hash conversion.
+
+Thu Nov 1 23:47:43 2007 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * lib/drb/drb.rb (DRbTCPSocket): Improving with multiple network
+ interface.
+
+ * test/drb/drbtest.rb: ditto.
+
+Fri Oct 26 17:14:14 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (fix_pow): returns 1.0 for 0**0.0.
+
+ * numeric.c (fix_pow): returns infinity for 0**-1. [ruby-dev:32084]
+
+Wed Oct 25 07:18:09 2007 James Edward Gray II <jeg2@ruby-lang.org>
+
+ Merged 13781 from trunk.
+
+ * lib/net/telnet.rb (Net::Telnet#login): Allowing "passphrase" in
+ addition to "password" for Telnet login prompts. [ruby-Bugs-10746]
+
+Wed Oct 25 06:46:21 2007 James Edward Gray II <jeg2@ruby-lang.org>
+
+ Merged 13779 from trunk.
+
+ * lib/net/telnet.rb (Net::Telnet#login): Making the password prompt
+ pattern case insensitive. [ruby-Bugs-10746]
+
+Thu Oct 25 14:19:33 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (rb_io_tell, rb_io_seek): check errno too. [ruby-dev:32093]
+
+Wed Oct 25 08:03:53 2007 James Edward Gray II <jeg2@ruby-lang.org>
+
+ Merged 13767, 13768, 13769, and 13770 from trunk.
+
+ * lib/xmlrpc/parser.rb (XMLRPC::Convert::dateTime): Fixing a bug that
+ caused time zone conversion to fail for some ISO 8601 date formats.
+ [ruby-Bugs-12677]
+
+ * lib/xmlrpc/client.rb (XMLRPC::Client#do_rpc): Explicitly start
+ the HTTP connection to support keepalive requests. [ruby-Bugs-9353]
+
+ * lib/xmlrpc/client.rb (XMLRPC::Client#do_rpc): Improving the error
+ message for Content-Type check failures. [ruby-core:12163]
+
+ * lib/xmlrpc/utils.rb (XMLRPC::ParseContentType#parse_content_type):
+ Making Content-Type checks case insensitive. [ruby-Bugs-3367]
+
+Sun Oct 21 21:16:43 2007 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rss.rb, lib/rss/, test/rss/, sample/rss/: merged from trunk.
+ - 0.1.6 -> 2.0.0.
+ - fixed image module URI. Thanks to Dmitry Borodaenko.
+ - supported Atom.
+ - supported ITunes module.
+ - supported Slash module.
+
+ * NEWS: added an entry for RSS Parser.
+
+Thu Oct 18 10:57:06 2007 Tanaka Akira <akr@fsij.org>
+
+ * ruby.h (RCLASS_IV_TBL): defined.
+ (RCLASS_M_TBL): ditto.
+ (RCLASS_SUPER): ditto.
+ (RMODULE_IV_TBL): ditto.
+ (RMODULE_M_TBL): ditto.
+ (RMODULE_SUPER): ditto.
+
+Mon Oct 15 22:08:55 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * NEWS: Merge some of the sub-sections, as the differences were
+ unclear.
+
+Mon Oct 15 21:57:07 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * NEWS: Mention ipaddr enhancements.
+
+ * lib/ipaddr.rb (in_addr, in6_addr, addr_mask): Make some minor
+ code optimization.
+
+ * lib/ipaddr.rb (<=>): Implement IPAddr#<=> and make IPAddr
+ comparable.
+
+ * lib/ipaddr.rb (succ): Implement IPAddr#succ. You can now create
+ a range between two IPAddr's, which (Range) object is
+ enumerable.
+
+ * lib/ipaddr.rb (to_range): A new method to create a Range object
+ for the (network) address.
+
+ * lib/ipaddr.rb (coerce_other): Support type coercion and make &,
+ |, == and include? accept a string or an integer instead of an
+ IPAddr object as the argument.
+
+ * lib/ipaddr.rb (initialize): Give better error messages.
+
+ * lib/ipaddr.rb: Improve documentation.
+
+Mon Oct 15 21:24:25 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * NEWS: Mention shellwords and tempfile enhancements.
+
+ * NEWS: Move the entry about Tk::X_Scrollable to a better section.
+
+Mon Oct 15 17:28:20 2007 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/openssl/lib/openssl/buffering.rb (read, readpartial): revert
+ r12496. handling EOF is a little differnt in ruby 1.8 and ruby 1.9.
+ [ruby-dev:31979]
+
+Mon Oct 15 11:45:12 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * marshal.c (r_bytes0): refined length check. [ruby-dev:32059]
+
+Mon Oct 15 09:58:07 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * marshal.c (r_bytes0): check if source has enough data.
+ [ruby-dev:32054]
+
+Mon Oct 15 01:15:09 2007 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/socket.c (s_accept_nonblock): make accepted fd
+ nonblocking. [ruby-talk:274079]
+
+Sun Oct 14 04:08:34 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (AC_SYS_LARGEFILE): keep results also in command
+ options, to vail out of mismatch. [ruby-list:44114]
+
+ * mkconfig.rb, lib/mkmf.rb (configuration): add DEFS.
+
+Sun Oct 14 03:55:52 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/mkexports.rb: deal with __fastcall name decorations.
+ [ruby-list:44111]
+
+Sat Oct 13 09:02:16 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * {bcc,win}32/mkexports.rb: explicit data. [ruby-list:44108]
+
+Sat Oct 13 00:35:03 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/rexml/source.rb (REXML::SourceFactory::SourceFactory): typo
+ fixed. [ruby-list:44099]
+
+Fri Oct 12 11:22:15 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * re.c (match_values_at): make #select to be alias to #values_at
+ to adapt RDoc description. [ruby-core:12588]
+
+Thu Oct 11 14:32:46 2007 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * {bcc32,win32}/Makefile.sub (COMMON_MACROS): workaround for old SDK's
+ bug. [ruby-core:12584]
+
+Wed Oct 10 23:34:45 2007 Tanaka Akira <akr@fsij.org>
+
+ * lib/securerandom.rb: new file. [ruby-dev:31928]
+
+ * lib/cgi/session.rb (create_new_id): use securerandom if available.
+
+Tue Oct 9 01:01:55 2007 Tanaka Akira <akr@fsij.org>
+
+ * re.c (rb_reg_s_union_m): Regexp.union accepts single
+ argument which is an array of patterns. [ruby-list:44084]
+
+Mon Oct 8 20:06:23 2007 GOTOU Yuuzou <gotoyuzo@notwork.org>
+
+ * lib/net/http.rb, lib/open-uri.rb: remove
+ Net::HTTP#enable_post_connection_check. [ruby-dev:31960]
+
+ * lib/net/imap.rb: hostname should be verified against server's
+ indentity as persented in the server's certificate. [ruby-dev:31960]
+
+ * ext/openssl/lib/net/telnets.rb, ext/openssl/lib/net/ftptls.rb: ditto.
+
+Sat Oct 6 23:14:54 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * string.c (rb_str_to_i): update RDoc since base can be any value
+ between 2 and 36. [ruby-talk:272879]
+
+Fri Oct 5 15:44:50 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/shellwords.rb: Add shellescape() and shelljoin().
+
+ * lib/shellwords.rb: Rename shellwords() to shellsplit() and make
+ the former an alias to the latter.
+
+ * lib/shellwords.rb: Add escape(), split(), join() as class
+ methods, which are aliases to their respective long names
+ prefixed with `shell'.
+
+ * lib/shellwords.rb: Add String#shellescape(), String#shellsplit()
+ and Array#shelljoin() for convenience.
+
+Fri Oct 5 15:40:04 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/tempfile.rb (Tempfile::make_tmpname): Allow to specify a
+ suffix for a temporary file name.
+
+ * lib/tempfile.rb (Tempfile::make_tmpname): Make temporary file
+ names less predictable by including a random string.
+ [inspired by: akr]
+
+Tue Oct 2 21:20:14 2007 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (make_cmdvector): adjust escaped successive
+ double-quote handling. (merge from trunk)
+
+Tue Oct 2 20:35:24 2007 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (init_env): initialize HOME and USER environment
+ variables unless set. [ruby-core:12328] (merge from trunk)
+
+ * win32/win32.c (NtInitialize, getlogin): ditto.
+
+ * configure.in, win32/Makefile.sub (LIBS): need to link shell32
+ library for SH* functions on mswin32 and mingw32.
+
+Mon Oct 1 12:50:59 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * gc.c (id2ref): valid id should not refer T_VALUE nor T_ICLASS.
+ [ruby-dev:31911]
+
+Wed Sep 26 23:54:37 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/extmk.rb (extmake), lib/mkmf.rb (configuration): top_srcdir
+ should not prefixed with DESTDIR.
+
+Wed Sep 26 08:36:31 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * Makefile.in (ext/extinit.o): use $(OUTFLAG) as well as other
+ objects. [ruby-Bugs-14228]
+
+Wed Sep 26 05:12:17 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (yyerror): limit error message length. [ruby-dev:31848]
+
+ * regex.c (re_mbc_startpos): separated from re_adjust_startpos.
+
+Tue Sep 25 13:47:38 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * eval.c (remove_method): should not remove undef place holder.
+ [ruby-dev:31817]
+
+Mon Sep 24 16:52:11 2007 Urabe Shyouhei <shyouhei@ruby-lang.org>
+
+ * lib/net/http.rb: fix typo.
+
+Sun Sep 23 21:57:25 2007 GOTOU Yuuzou <gotoyuzo@notwork.org>
* lib/net/http.rb: an SSL verification (the server hostname should
be matched with its certificate's commonName) is added.
@@ -132,35 +5243,91 @@ Sun Sep 23 21:57:25 2007 GOTOU Yuuzou <gotoyuzo@notwork.org>
perform SSL post connection check.
* ext/openssl/lib/openssl/ssl.c
- (OpenSSL::SSL::SSLSocket#post_connection_check): refine error message.
+ (OpenSSL::SSL::SSLSocket#post_connection_check): refine error message.
-Sun Sep 23 06:08:38 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Sun Sep 23 09:05:05 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
- * ext/stringio/stringio.c (strio_init): separate from strio_initialize
- to share with strio_reopen properly. [ruby-Bugs-13919]
+ * gc.c (os_obj_of, os_each_obj): hide objects to be finalized.
+ [ruby-dev:31810]
+
+Sun Sep 23 08:58:01 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval_method.ci (rb_attr): should not use alloca for unknowen size
+ input. [ruby-dev:31816]
+
+ * parse.y (rb_intern_str): prevent str from optimization.
Sun Sep 23 05:42:35 2007 URABE Shyouhei <shyouhei@ruby-lang.org>
* lib/rdoc/options.rb (Options::check_diagram): dot -V output
changed. [ ruby-Bugs-11978 ], Thanks Florian Frank.
-Mon Sep 17 04:47:02 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+Sat Sep 22 06:02:11 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/optparse.rb (OptionParser::List::summarize): use each_line if
+ defined rather than each. [ruby-Patches-14096]
+
+Sat Sep 22 05:19:49 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/stringio/stringio.c (strio_init): separate from strio_initialize
+ to share with strio_reopen properly. [ruby-Bugs-13919]
+
+Fri Sep 21 15:46:20 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * process.c (struct rb_exec_arg): proc should be a VALUE.
+
+ * process.c (rb_f_exec): suppress a warning.
+
+Fri Sep 21 03:05:35 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c, intern.h, ext/thread/thread.c: should not free queue while
+ any live threads are waiting. [ruby-dev:30653]
+
+Thu Sep 20 17:24:59 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * process.c (rb_detach_process): cast for the platforms where size of
+ pointer differs from size of int.
+
+ * process.c (rb_f_exec, rb_f_system): should not exceptions after
+ fork. [ruby-core:08262]
+
+Fri Sep 14 00:34:25 2007 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * lib/drb/extservm.rb (invoke_service): use Thread.exclusive instead of
+ Thread.critical
+
+Wed Sep 12 23:12:22 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
* ruby.c (proc_options): -W should be allowed in RUBYOPT
environment variable. [ruby-core:12118]
-Mon Sep 17 04:31:46 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+Mon Sep 10 01:05:25 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
* range.c (range_step): fixed integer overflow. [ruby-dev:31763]
-Fri Sep 7 14:57:36 2007 URABE Shyouhei <shyouhei@ice.uec.ac.jp>
+Sun Sep 9 09:14:45 2007 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date/format.rb (_strptime): now also attaches an element
+ which denotes leftover substring if exists.
+
+Sat Sep 8 10:22:20 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * struct.c (rb_struct_s_members): should raise TypeError instead
+ of call rb_bug(). [ruby-dev:31709]
- * ruby.c (rubylib_mangled_path): eliminate RSTRING_PTR
- [ruby-dev:31679]
+ * marshal.c (r_object0): no nil check require any more.
- * ruby.c(push_include_cygwin): ditto.
+Sat Sep 8 09:38:19 2007 Tadayoshi Funaba <tadf@dotrb.org>
-Fri Sep 7 14:32:38 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+ * lib/date/format.rb (str[fp]time): now check specifications more
+ strictly.
+
+Fri Sep 7 05:36:19 2007 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * test/rinda/test_rinda.rb (MockClock): correct synchronous problems
+ of the MultiThreading. [ruby-dev:31692]
+
+Wed Sep 5 22:02:27 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
* array.c (rb_ary_subseq): need integer overflow check.
[ruby-dev:31736]
@@ -172,13 +5339,23 @@ Fri Sep 7 14:32:38 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
* string.c (rb_str_splice): integer overflow for length.
[ruby-dev:31739]
-Fri Sep 7 14:27:33 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+Sun Sep 2 00:48:15 2007 Tadayoshi Funaba <tadf@dotrb.org>
- * eval.c (mnew): should preserve noex as safe_level.
+ * lib/date/format.rb (_parse): improved parsing of ordinal dates.
- * eval.c (rb_call0): tighten security check condition..
+ * lib/date/format.rb (_parse): use named character classes in some
+ regular expressions.
+
+Sat Sep 1 08:13:36 2007 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-Fri Sep 7 14:19:16 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+ * ext/win32ole/win32ole.c: add WIN32OLE#ole_activex_initialize.
+
+Thu Aug 30 13:13:13 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (try_const, have_const): check for a const is defined.
+ [ruby-core:04422]
+
+Thu Aug 30 13:10:57 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* configure.in (group_member): check if presents.
@@ -186,24 +5363,79 @@ Fri Sep 7 14:19:16 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* file.c (group_member): use system routine if available.
-Fri Sep 7 14:14:19 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+Thu Aug 30 08:24:18 2007 Tanaka Akira <akr@fsij.org>
+
+ * ruby.h (RHASH_TBL): defined for compatibility to 1.9.
+ * (RHASH_ITER_LEV): ditto.
+ * (RHASH_IFNONE): ditto.
+ * (RHASH_SIZE): ditto.
+ * (RHASH_EMPTY_P): ditto.
+
+Wed Aug 29 13:05:59 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
* include/ruby/defines.h (flush_register_windows): call "ta 0x03"
even on Linux/Sparc. [ruby-dev:31674]
-Fri Sep 7 14:12:37 2007 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+Tue Aug 28 23:26:12 2007 Masaki Suketa <masaki.suketa@nifty.ne.jp>
- * ext/win32ole/win32ole.c (ole_type_progid, reg_enum_key,
- reg_get_val, ole_wc2mb): fix the bug. Thanks, arton.
+ * ext/win32ole/win32ole.c (ole_type_progid, reg_enum_key,
+ reg_get_val, ole_wc2mb): fix the bug. Thanks, arton.
[ruby-dev:31576]
-Fri Sep 7 14:02:10 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Mon Aug 27 19:10:50 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * ext/etc/etc.c (etc_getlogin): update documentation to note
+ security issue. [ruby-Bugs-11821]
+
+Tue Aug 21 21:09:48 2007 Tanaka Akira <akr@fsij.org>
+
+ * lib/tmpdir.rb (Dir.mktmpdir): make directory suffix specifiable.
+
+Tue Aug 21 13:57:04 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (st_foreach_func, rb_foreach_func): typedefed.
+
+Mon Aug 20 17:25:33 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * eval.c (mnew): should preserve noex as safe_level.
+
+ * eval.c (rb_call0): tighten security check condition..
+
+Sat Aug 18 21:32:20 2007 Tanaka Akira <akr@fsij.org>
+
+ * lib/tmpdir.rb (Dir.mktmpdir): new method.
+ [ruby-dev:31462]
+
+Sat Aug 18 17:44:42 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/tk/tcltklib.c (Init_tcltklib): use rb_set_end_proc().
+
+Sat Aug 18 15:59:52 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* process.c (detach_process_watcher): should not pass the pointer
to an auto variable to the thread to be created. pointed and
fix by KUBO Takehiro <kubo at jiubao.org> [ruby-dev:30618]
-Fri Sep 7 13:52:36 2007 Tanaka Akira <akr@fsij.org>
+Sat Aug 18 12:24:30 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * sample/test.rb, test/ruby/test_system.rb(valid_syntax?): keep
+ comment lines first.
+
+Thu Aug 16 20:40:50 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * bignum.c (bigtrunc): RBIGNUM(x)->len may be zero. out of bound
+ access. [ruby-dev:31404]
+
+Thu Aug 16 16:46:07 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (aix): enable shared by default.
+
+ * configure.in (aix): for 64bit-mode AIX. [ruby-dev:31401]
+ + use CC for LDSHARED if non-gcc,
+ + moved -G option from *LDFLAGS to LDSHARED,
+ + set -brtl only in XLDFLAGS.
+
+Thu Aug 16 13:06:08 2007 Tanaka Akira <akr@fsij.org>
* bignum.c (big_lshift): make shift offset long type.
(big_rshift): ditto.
@@ -211,7 +5443,12 @@ Fri Sep 7 13:52:36 2007 Tanaka Akira <akr@fsij.org>
(big_rshift): ditto.
[ruby-dev:31434]
-Thu Aug 16 08:44:55 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Thu Aug 16 04:09:19 2007 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * lib/rinda/tuplespace.rb (Rinda::TupleSpace#start_keeper): improve
+ keeper thread.
+
+Wed Aug 15 13:50:10 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* hash.c (rb_hash_delete_key): delete the entry without calling block.
@@ -220,32 +5457,39 @@ Thu Aug 16 08:44:55 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* hash.c (delete_if_i): use rb_hash_delete_key() so that the block
isn't called twice. [ruby-core:11556]
-Thu Aug 16 08:43:50 2007 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+Sun Arg 12 03:56:30 2007 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
* lib/rinda/tuplespace.rb: fix Rinda::TupleSpace keeper thread bug.
- the thread is started too early. [ruby-talk:264062]
+ the thread is started too early. [ruby-talk:264062]
* test/rinda/test_rinda.rb: ditto.
-Thu Aug 16 08:40:38 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Sat Aug 11 07:34:10 2007 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date/format.rb: reverted some wrongly erased "o" options
+ (pointed out by nobu).
+
+Tue Aug 7 14:58:39 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* ext/pty/pty.c (establishShell): handshaking before close slave
device. [ruby-talk:263410]
-Thu Aug 16 08:29:39 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+ * ext/pty/pty.c (MasterDevice, SlaveDevice, deviceNo): constified.
+
+ * ext/pty/pty.c (SlaveName): removed static buffer.
+
+ * ext/pty/expect_sample.rb: support for autologin.
+
+Tue Aug 7 12:45:13 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* configure.in (ac_cv_func_isinf): set yes also on OpenSolaris.
[ruby-Bugs-12859]
-Thu Aug 16 08:28:16 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Mon Aug 6 17:36:29 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* lib/rexml/encodings/{ISO-8859-15,CP-1252}.rb: fixed invalid syntax.
-Thu Aug 16 08:26:08 2007 Tadayoshi Funaba <tadf@dotrb.org>
-
- * lib/README: fixed a typo.
-
-Thu Aug 16 08:20:50 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Fri Aug 3 11:05:54 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* ext/extmk.rb (extmake): save all CONFIG values.
@@ -255,15 +5499,37 @@ Thu Aug 16 08:20:50 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* ext/extmk.rb: remove rdoc at clean, and installed list file at
distclean, respectively.
-Thu Aug 16 07:58:18 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Fri Aug 3 07:09:05 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb: more verbose message. [ruby-Bugs-12766]
+
+ * lib/mkmf.rb (have_type): suppress a warning with -Wall.
+
+ * lib/mkmf.rb (find_type): new method.
+
+Thu Aug 2 13:46:39 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* sprintf.c (rb_f_sprintf): should not check positional number as
width. [ruby-core:11838]
-Thu Aug 16 07:52:24 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Mon Jul 30 11:16:40 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (rb_big_aref): check for Bignum index range.
+ [ruby-dev:31271]
+
+Sat Jul 28 09:35:41 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * ext/digest/lib/digest.rb (Digest::self.const_missing): avoid
+ infinite recursive const_missing call. [ruby-talk:262193]
+
+Thu Jul 26 13:57:45 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dln.c (load_1, dln_find_1): constified.
* dln.c (conv_to_posix_path): removed.
+ * ruby.c (usage): constified.
+
* ruby.c (rubylib_mangled_path, rubylib_mangled_path2): return
VALUE instead of a pointer to static buffer.
@@ -272,17 +5538,12 @@ Thu Aug 16 07:52:24 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* ruby.c (ruby_init_loadpath): not convert built-in paths.
-Thu Aug 16 07:51:37 2007 Akinori MUSHA <knu@iDaemons.org>
-
- * defines.h: Pull the RUBY_MBCHAR_MAXSIZE definition from trunk,
- which is necessary for dir.c to compile on djgpp and emx.
-
-Thu Aug 16 07:42:10 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Sun Jul 22 16:07:12 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* intern.h (is_ruby_native_thread): removed since declared as an int
function in ruby.h already.
-Thu Aug 16 07:40:41 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Sun Jul 22 14:33:40 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* file.c (rb_file_s_rename): deleted code to get rid of a bug of
old Cygwin.
@@ -309,30 +5570,45 @@ Thu Aug 16 07:40:41 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
folevariable_ole_type, folevariable_ole_type_detail,
folevariable_value, folemethod_visible): missing return value.
-Thu Aug 16 07:32:13 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Sat Jul 21 17:48:26 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* lib/mkmf.rb (create_makefile): make OBJS depend on RUBY_EXTCONF_H
only if extconf.h is created.
-Thu Aug 16 07:29:33 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+ * bcc32/{Makefile.sub,configure.bat,setup.mak: configure_args
+ support.
+
+ * bcc32/setup.mak: check runtime version.
+
+ * win32/win32.c (rb_w32_open_osfhandle): prototype has changed
+ in bcc 5.82.
* {win32,wince,bcc32}/setup.mak (-version-): no RUBY_EXTERN magic.
-Thu Aug 16 06:43:03 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+ * win32/resource.rb: include patchlevel number.
+
+Sat Jul 21 12:06:48 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* lib/mkmf.rb (init_mkmf): should remove mkmf.log too.
-Thu Aug 16 06:40:58 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Sat Jul 21 01:53:17 2007 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date/format.rb (Date._parse): completes calendar week based year.
+
+ * lib/date/format.rb (Date._parse): detects year of ordinal date in
+ extended format.
+
+Fri Jul 20 15:22:51 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* ext/openssl/ossl_config.c (ossl_config_set_section): do not
initialize aggregations with dynamic values. [ruby-talk:259306]
-Thu Aug 16 06:39:19 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Thu Jul 19 19:24:14 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* eval.c (get_backtrace): check the result more.
[ruby-dev:31261] [ruby-bugs-12398]
-Thu Aug 16 06:32:25 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Thu Jul 19 14:38:45 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* bignum.c (rb_big_lshift, rb_big_rshift): separated functions
to get rid of infinite recursion. fixed calculation in edge
@@ -340,36 +5616,53 @@ Thu Aug 16 06:32:25 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* numeric.c (rb_fix_lshift, rb_fix_rshift): ditto.
-Thu Aug 16 06:26:58 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Wed Jul 18 16:57:41 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* bignum.c (rb_big_pow): refine overflow check. [ruby-dev:31242]
-Thu Aug 16 06:25:48 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+Wed Jul 18 08:47:09 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
* time.c (time_succ): Time#succ should return a time object in the
same timezone mode to the original. [ruby-talk:260256]
-Thu Aug 16 06:24:39 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+Tue Jul 17 00:50:53 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
- * numeric.c (fix_pow): integer power calculation: 0**n => 0,
+ * numeric.c (fix_pow): integer power calculation: 0**n => 0,
1**n => 1, -1**n => 1 (n: even) / -1 (n: odd).
-Thu Aug 16 06:11:34 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+ * test/ruby/test_fixnum.rb (TestFixnum::test_pow): update test
+ suite. pow(-3, 2^64) gives NaN when pow(3, 2^64) gives Inf.
+
+Mon Jul 16 23:07:51 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
* lib/base64.rb (Base64::b64encode): should not specify /o option
for regular expression. [ruby-dev:31221]
-Thu Aug 16 06:08:53 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Mon Jul 16 18:29:33 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_rindex_m): accept string-like object convertible
+ with #to_str method, as well as rb_str_index_m. [ruby-core:11692]
+
+Mon Jul 16 05:45:53 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* sprintf.c (rb_f_sprintf): more checks for format argument.
[ruby-core:11569], [ruby-core:11570], [ruby-core:11571],
[ruby-core:11573]
-Thu Aug 16 05:39:31 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Mon Jul 16 00:26:10 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (rb_big_pow): removed invariant variable. [ruby-dev:31236]
+
+Sun Jul 15 23:59:57 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (rb_big_neg): SIGNED_VALUE isn't in 1.8.
- * bignum.c (bignorm): do not empty Bignum. [ruby-dev:31229]
+Sun Jul 15 22:24:49 2007 pegacorn <subscriber.jp AT gmail.com>
-Thu Aug 16 05:12:05 2007 pegacorn <subscriber.jp AT gmail.com>
+ * ext/digest/digest.c (rb_digest_instance_update,
+ rb_digest_instance_finish, rb_digest_instance_reset,
+ rb_digest_instance_block_length): %s in rb_raise() expects char*.
+ [ruby-dev:31222]
* ext/openssl/ossl.h: include ossl_pkcs5.h. [ruby-dev:31231]
@@ -390,89 +5683,198 @@ Thu Aug 16 05:12:05 2007 pegacorn <subscriber.jp AT gmail.com>
* win32.h (rb_w32_getcwd): prototype added. [ruby-dev:31232]
-Thu Aug 16 05:02:39 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Sun Jul 15 21:07:43 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (bigtrunc): do not empty Bignum. [ruby-dev:31229]
+
+Sun Jul 15 19:05:28 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* bignum.c (rb_cstr_to_inum): check leading non-digits.
[ruby-core:11691]
-Thu Aug 16 05:00:01 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+Sun Jul 15 04:42:20 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (get2comp): do nothing for empty Bignum. [ruby-dev:31225]
+
+Sat Jul 14 14:04:06 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enum.c (sort_by_cmp): check if reentered. [ruby-dev:24291]
+
+Sat Jul 14 12:44:14 2007 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * test/openssl/test_pkcs7.rb: reverted the previous patch. it should
+ be as it was to check interface compatibility. sorry for bothering
+ with this.
+
+Sat Jul 14 12:16:17 2007 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
+ * test/openssl/test_pkcs7.rb: follow the library change. applied a
+ patch from <zn at mbf.nifty.com> [ruby-dev:31214].
+ NOTE: r12496 imports the latest openssl libs from trunk to ruby_1_8
+ though its's not ChangeLog-ed. maintainer should aware that.
+
+Sat Jul 14 02:51:52 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
* numeric.c (fix_pow): 0**2 should not raise floating point
exception. [ruby-dev:31216]
-Thu Aug 16 04:56:35 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Sat Jul 14 02:25:48 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * numeric.c (int_pow): wrong overflow detection. [ruby-dev:31213]
+
+ * numeric.c (int_pow): wrong overflow detection. [ruby-dev:31215]
+
+Fri Jul 13 16:10:00 2007 Tanaka Akira <akr@fsij.org>
+
+ * lib/open-uri.rb (URI::Generic#find_proxy): use ENV.to_hash to access
+ http_proxy environment variable to avoid case insensitive
+ environment search.
+
+Fri Jul 13 15:02:15 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* win32/win32.c (CreateChild): enclose command line except for
command.com which can not handle quotes. [ruby-talk:258939]
-Thu Aug 16 04:54:45 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Fri Jul 13 10:10:46 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* lib/mkmf.rb (link_command, cc_command, cpp_command): do not expand
::CONFIG which is an alias of MAKEFILE_CONFIG.
-Thu Aug 16 04:53:21 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Thu Jul 12 17:03:15 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* struct.c (rb_struct_init_copy): disallow changing the size.
[ruby-dev:31168]
-Thu Aug 16 04:52:11 2007 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+Wed Jul 11 23:38:14 2007 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
* random.c: documentation fix. srand(0) initializes PRNG with '0',
not with random_seed.
-Thu Aug 16 04:49:10 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Tue Jul 10 14:50:01 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* bcc32/{Makefile.sub,setup.mak}: remove surplus slash from srcdir.
-Thu Aug 16 04:40:37 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Fri Jul 6 15:22:58 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_interrupt): suppress a gcc's officious warning.
+
+Thu Jul 5 16:44:28 2007 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * numeric.c (int_pow): fix previous nubu's commit.
+
+ * test/ruby/test_fixnum.rb: new test.
+
+Thu Jul 5 15:56:06 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (int_pow): even number multiplication never be negative.
+
+Mon Jul 2 14:34:43 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* sprintf.c (rb_f_sprintf): sign bit extension should not be done
if FPLUS flag is specified. [ruby-list:39224]
-Thu Aug 16 04:39:15 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+Sat Jun 30 16:05:41 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
* array.c (rb_ary_initialize): should call rb_ary_modify() first.
[ruby-core:11562]
-Thu Aug 16 04:38:39 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Sat Jun 30 00:17:00 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* parse.y (yylex): return non-valid token for an invalid
- instance/class variable name. a patch from from Yusuke ENDOH
+ instance/class variable name. a patch from Yusuke ENDOH
<mame AT tsg.ne.jp>. [ruby-dev:31095]
-Thu Aug 16 04:36:41 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Fri Jun 29 11:23:09 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* parse.y (dsym): return non-null NODE even if yyerror(). based on a
- patch from from Yusuke ENDOH <mame AT tsg.ne.jp>. [ruby-dev:31085]
+ patch from Yusuke ENDOH <mame AT tsg.ne.jp>. [ruby-dev:31085]
-Thu Aug 16 04:34:56 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Tue Jun 26 16:35:21 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * process.c (ruby_setreuid, ruby_setregid): rename to get rid of name
+ clash.
* process.c (proc_exec_v, rb_proc_exec): preserve errno.
-Thu Aug 16 04:30:45 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Sat Jun 23 00:37:46 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * hash.c (rb_hash_select): remove unnecessary varargs for
+ rb_hash_select. a patch from Daniel Berger
+ <Daniel.Berger at qwest.com>. [ruby-core:11527]
+
+ * hash.c: ditto.
+
+Mon Jun 18 08:47:54 2007 Technorama Ltd. <oss-ruby@technorama.net>
+
+ * ext/openssl/{extconf.rb,ossl_ssl_session.c}:
+ Fix ruby-Bugs-11513.
+
+ * ext/openssl/ossl_pkey_ec.c
+ New methods EC::Point.[eql,make_affine!,invert!,on_curve?,infinity?]
+ By default output the same key form as the openssl command.
+
+ * ext/openssl/ossl_rand.c
+ New method Random.status?
+
+Mon Jun 18 13:54:36 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (ruby_cleanup): return EXIT_FAILURE if any exceptions occured
+ in at_exit blocks. [ruby-core:11263]
+
+Mon Jun 18 01:14:10 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* variable.c (rb_path2class): get rid of dangling pointer caused by
optimized out value.
-Thu Aug 16 04:24:28 2007 NAKAMURA Usaku <usa@ruby-lang.org>
+ * variable.c (rb_global_entry, rb_f_untrace_var, rb_alias_variable,
+ rb_generic_ivar_table, generic_ivar_get, generic_ivar_set,
+ generic_ivar_defined, generic_ivar_remove, rb_mark_generic_ivar,
+ rb_free_generic_ivar, rb_copy_generic_ivar,
+ rb_obj_instance_variables): suppress warnings.
+
+Fri Jun 15 22:33:29 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (realclean): separate local and ext.
+
+ * ext/extmk.rb: not remove unrelated directories.
+
+Fri Jun 15 17:01:20 2007 NAKAMURA Usaku <usa@ruby-lang.org>
* ext/dl/lib/dl/win32.rb: seems that dl doesn't accept void argument.
fixed [ruby-bugs:PR#5489].
-Thu Aug 16 04:23:44 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Thu Jun 14 17:09:48 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser): handle more
extensions. [ruby-dev:30972]
-Thu Aug 16 04:14:17 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Wed Jun 13 06:05:12 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
- * process.c (ruby_setreuid, ruby_setregid): rename to get rid of name
- clash.
-Thu Aug 16 04:11:17 2007 Ryan Davis <ryand@zenspider.com>
+ * configure.in (darwin): prohibit loading extension libraries to
+ miniruby.
+
+Wed Jun 13 05:47:58 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_kill_thread): renamed in order to get rid of conflict
+ with a BeOS system function. [ruby-core:10830]
+
+Tue Jun 12 14:53:51 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (Logging.quiet, Logging.message): added quiet flag and
+ use it. [ruby-core:10909]
+
+ * lib/mkmf.rb (find_header): use header names in the message.
+
+Sun Jun 10 13:47:36 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
- * lib/rexml/dtd/dtd.rb: Fixed typo in code. Fixes bug #10420
+ * test/ruby/test_beginendblock.rb (test_should_propagate_signaled):
+ get rid of invoking shell. [ruby-dev:30942]
-Thu Aug 16 04:08:20 2007 Shugo Maeda <shugo@ruby-lang.org>
+Thu Jun 7 19:02:48 2007 Tanaka Akira <akr@fsij.org>
+
+ * lib/pp.rb: call original "method" method instead of redefined one.
+
+Mon Jun 4 11:11:12 2007 Shugo Maeda <shugo@ruby-lang.org>
* lib/net/imap.rb (ResponseParser#next_token): fixed
error message. (backported from HEAD)
@@ -481,58 +5883,219 @@ Thu Aug 16 04:08:20 2007 Shugo Maeda <shugo@ruby-lang.org>
the condition not to refer @token.symbol unexpectedly.
Thanks, Dick Monahan. (backported from HEAD)
-Thu Aug 16 04:05:20 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+Thu May 31 17:27:53 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
- * marshal.c (w_extended): erroneous check condition when dump
- method is defined. [ruby-core:10646]
+ * lib/benchmark.rb (Benchmark::Job::item): avoid modifying the
+ argument unintentionally. [ruby-talk:253676]
+
+Thu May 31 02:12:32 2007 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * lib/rinda/tuplespace.rb (Rinda::TupleBag): create index on tuple bag
+ by first column.
+
+Wed May 30 13:27:40 2007 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/ftp.rb (Net::FTP#transfercmd): skip 2XX
+ responses for some FTP servers. (backported from HEAD)
+
+Wed May 30 05:17:55 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_eval): get rid of SEGV at ZSUPER in a block
+ [ruby-dev:30836]
+
+Wed May 30 04:29:43 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
-Sat Jun 9 10:40:00 2007 URABE Shyouhei <shyouhei@ruby-lang.org>
+ * eval.c (thread_timer): timer thread should not receive any
+ signals. submitted by Sylvain Joyeux. [ruby-core:08546]
- * stable version 1.8.5-p52 released.
+Wed May 30 04:18:37 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
-Thu Jun 7 14:53:46 2007 URABE Shyouhei <shyouhei@ruby-lang.org>
+ * eval.c (rb_eval_cmd): just return if no exceptions.
+ [ruby-dev:30820]
- * eval.c (method_inspect): show proper class name.
- [ruby-talk:248647], Thanks Calamitas.
+Tue May 29 11:01:06 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
-Mon May 28 19:37:24 2007 NAKAMURA Usaku <usa@ruby-lang.org>
+ * win32/win32.c (rb_w32_opendir): store attributes of the second
+ entries or later too.
- * win32/win32.c (move_to_next_entry): revert r12338. not necessary
- on ruby_1_8_5.
+ * win32/win32.c (rb_w32_opendir, rb_w32_readdir): eliminate magic
+ numbers.
-Sun May 27 05:52:37 2007 URABE Shyouhei <shyouhei@ruby-lang.org>
+Mon May 28 02:54:05 2007 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
- * eval.c (mnew): call of super via a method object should work again.
- [ruby-talk:248647], Thanks Calamitas.
+ * lib/rinda/tuplespace.rb (Rinda::TupleBag#delete): use rindex and
+ delete_at instead of delete for little improvement.
- * test/ruby/test_method.rb (TestMethod::test_method_super): test for
- above fix.
+Sat May 26 00:05:22 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/ruby/test_beginendblock.rb (test_should_propagate_signaled):
+ skip tests for exitstatus and termsig on the platforms where
+ signals not supported.
Wed May 23 06:51:46 2007 URABE Shyouhei <shyouhei@ruby-lang.org>
* lib/cgi.rb (CGI#[]): get rid of exceptions being raised.
[ruby-dev:30740], Thanks Kentaro KAWAMOTO.
-Wed May 23 06:14:15 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Wed May 23 05:49:49 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/extmk.rb, ext/purelib.rb, lib/mkmf.rb, runruby.rb: clear default
+ load path to get rid of load pre-installed extensions/libraries.
+ [ruby-core:11017]
+
+Sat May 19 10:29:18 2007 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date/format.rb (Date._parse): detects some OFX dates
+ (Of course not fully).
+
+Fri May 18 23:07:33 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * array.c (rb_ary_first): call rb_ary_subseq() instead of pushing
+ values by itself. [ruby-talk:252062]
+
+ * array.c (rb_ary_first): add negative length check.
+
+Fri May 18 17:10:31 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* win32/win32.c (move_to_next_entry): loc also must move forward.
[ruby-talk:251987]
-Wed May 23 05:55:04 2007 NAKAMURA Usaku <usa@ruby-lang.org>
+Fri May 18 03:02:40 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/mkexports.rb: preserve prefixed underscores for WINAPI
+ symbols.
+
+ * wince/mkconfig_wce.rb, wince/mkexports.rb: obsolete.
+
+Thu May 17 17:03:11 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * misc/ruby-style.el (ruby-style-label-indent): for yacc rules.
+
+Tue May 15 14:54:07 2007 NAKAMURA Usaku <usa@ruby-lang.org>
* win32/win32.c (init_stdhandle): stderr should be without buffering,
but mswin32 use buffering when stderr is not connected to tty.
-Wed May 23 03:33:55 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Mon May 14 13:28:03 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/thread/thread.c (wait_list): supress a warning.
+
+Thu May 10 15:21:51 2007 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/iconv/iconv.c (iconv_s_conv): rdoc fix.
+
+Thu May 10 10:14:14 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_thread_priority): rdoc fix; the initial value is
+ inherited from the creating thread. [ruby-core:10607]
+
+Wed May 9 12:28:57 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (Init_Bignum), numeric.c (Init_Numeric): added fdiv as
+ aliases of quo. [ruby-dev:30771]
+
+Wed May 9 11:55:15 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (rb_big_quo): now calculate in integer. [ruby-dev:30753]
+
+Wed May 9 11:51:06 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (rb_big_pow): reduce multiplying for even number.
+
+ * bignum.c (rb_big_pow): truncate all zero BDIGITs. [ruby-dev:30733]
+
+ * bignum.c (rb_big_pow): improvement by calculating from MSB and using
+ factorization. <http://yowaken.dip.jp/tdiary/20070426.html#p01>
+
+ * numeric.c (int_pow): calculate power in Fixnum as possible.
+ [ruby-dev:30726]
+
+Tue May 8 23:42:51 2007 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date/format.rb (Date._parse): revised treatment of
+ hyphened/separatorless dates.
+
+ * lib/date/format.rb: some trivial adjustments.
+
+Tue May 8 20:25:05 2007 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date/format.rb: reverted.
+
+Sat May 5 16:26:33 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/date/format.rb (Format::Bag#method_missing): get rid of
+ modifying orginal argument. [ruby-core:11090]
+
+Mon Apr 30 01:17:51 2007 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * lib/rinda/tuplespace.rb (TupleSpace#create_entry, TupleBag#push,
+ delete): extract method, and rename parameter.
+
+Fri Apr 27 02:00:17 2007 Ryan Davis <ryand-ruby@zenspider.com>
+
+ * signal.c: Fixed backwards compatibility for 'raise Interrupt'.
+
+ * lib/yaml/tag.rb: Running rdoc over the 1.8.6 tree skips
+ Module. Patch from James Britt
+
+Thu Apr 26 13:54:51 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * misc/ruby-style.el: new file. C/C++ style for ruby source code.
+
+Wed Apr 25 19:49:16 2007 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/socket.c (unix_send_io, unix_recv_io): use CMSG_DATA to
+ align file descriptor appropriately.
+
+Tue Apr 24 09:33:57 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (do_stat, do_lstat, do_opendir): should not warn ENOTDIR.
+ [ruby-talk:248288]
+
+Mon Apr 23 22:14:42 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/extmk.rb ($ruby): add extout directory to include path.
+ [ruby-core:11003]
+
+ * lib/mkmf.rb (libpathflag): not to append RPATHFLAG to current
+ directory.
+
+ * lib/mkmf.rb (init_mkmf): add current directory to default
+ library path with highest priority. [ruby-core:10960]
+
+ * lib/mkmf.rb (LINK_SO): LIBPATH to be placed before DLDFLAGS.
+
+Fri Apr 20 16:05:22 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (LIBPATHFLAG, RPATHFLAG): no needs to be quoted,
+ it is done by libpathflag in mkmf.rb.
+
+Fri Apr 20 12:27:04 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/optparse.rb: fix to override conv proc.
+
+Fri Apr 20 12:17:05 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (ruby_cleanup): inversed the order of errinfos.
+
+Thu Apr 19 14:53:32 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* lib/monitor.rb (ConditionVariable#wait, mon_enter, mon_exit_for_cond):
ensures Thread.critical to be false. [ruby-talk:248300]
-Wed May 23 03:25:13 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Wed Apr 18 10:41:21 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* util.c (ruby_strtod): exponent is radix 10. [ruby-talk:248272]
-Wed May 23 02:09:32 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+Wed Apr 18 02:30:24 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (LDFLAGS): prepend -L. instead appending it to
+ XLDFLAGS. [ruby-core:10933]
+
+ * configure.in (Makefile): remove $U for automake from MISSING.
+ [ruby-talk:248171]
+
+Tue Apr 17 16:46:46 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
* eval.c (rb_yield_0): should not clear state on TAG_NEXT when
it's invoked from within lambda body. [ruby-talk:248136]
@@ -540,34 +6103,143 @@ Wed May 23 02:09:32 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
* eval.c (proc_invoke): handle TAG_NEXT which would be caused by
next in the lambda body as well.
-Wed May 23 01:55:49 2007 NAKAMURA Usaku <usa@ruby-lang.org>
+Mon Apr 16 22:56:01 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * ext/pty/expect_sample.rb: avoid symbolic link representation for
+ expect. a patch from Kazuhiro NISHIYAMA <zn at mbf.nifty.com>.
+ [ruby-dev:30714]
+
+Mon Apr 16 22:51:11 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * sample: replace TRUE, FALSE with true, false respectively.
+ a patch from Kazuhiro NISHIYAMA <zn at mbf.nifty.com>.
+ [ruby-dev:30713]
+
+Mon Apr 16 17:08:02 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/optparse.rb (make_switch): do not clobber converter if pattern
+ has no convert method. reported by sheepman in [ruby-dev:30709].
+
+Mon Apr 16 16:49:32 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/stringio/stringio.c (strio_seek): consistent behavior with
+ IO#seek. patch by sheepman in [ruby-dev:30710].
+
+Mon Apr 16 16:34:08 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * parse.y (parser_yylex): should set command_start after block
+ starting "do"s and braces. [ruby-core:10916]
+
+Sun Apr 15 09:19:57 2007 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date/format.rb: added some zone names.
+
+ * lib/date/format.rb (_parse): now interprets doted numerical
+ dates as a big endian (except dd.mm.yyyy).
+
+Tue Apr 10 17:37:36 2007 NAKAMURA Usaku <usa@ruby-lang.org>
* win32/win32.c (rb_w32_fclose, rb_w32_close): need to save errno
before calling original fclose()/close().
-Wed May 23 01:42:29 2007 Shugo Maeda <shugo@ruby-lang.org>
+Mon Apr 9 09:30:44 2007 Shugo Maeda <shugo@ruby-lang.org>
* lib/net/imap.rb (disconnect): call shutdown for
SSLSocket. Thanks, Technorama Ltd.
-Wed May 23 01:28:14 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Thu Apr 5 00:42:48 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* error.c (rb_notimplement), io.c (pipe_open): removed definite
articles and UNIX manual section from messages. [ruby-dev:30690]
+Wed Apr 4 17:09:17 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (pipe_open): refined the message of NotImplementedError.
+ [ruby-dev:30685]
+
+Wed Apr 4 10:18:04 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
* io.c (pipe_open): raise NotImplementedError for command "-" on
platforms where fork(2) is not available. [ruby-dev:30681]
-Wed May 23 00:06:19 2007 NAKAMURA Usaku <usa@ruby-lang.org>
+Tue Apr 3 15:45:41 2007 NAKAMURA Usaku <usa@ruby-lang.org>
* ext/socket/socket.c (s_recv, s_recvfrom): some systems (such as
windows) doesn't set fromlen if the socket is connection-oriented.
reported by Bram Whillock in [ruby-core:10512] [ruby-Bugs#9061]
+Sat Mar 24 23:40:29 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * node.h (struct rb_thread.locals): explicit as struct.
+ [ruby-core:10585]
+
+ * eval.c, node.h (enum rb_thread_status, struct rb_thread,
+ rb_curr_thread, rb_main_thread): prefixed. [ruby-core:10586]
+
+ * file.c (chompdirsep): made an unprefixed name static.
+
+ * io.c (io_fread): ditto.
+
+Sat Mar 24 01:54:03 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (ruby_cleanup): exit by SystemExit and SignalException in END
+ block. [ruby-core:10609]
+
+ * test/ruby/test_beginendblock.rb (test_should_propagate_exit_code):
+ test for exit in END block. [ruby-core:10760]
+
+ * test/ruby/test_beginendblock.rb (test_should_propagate_signaled):
+ test for signal in END block.
+
+Thu Mar 22 23:13:17 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_provided): check for extension library if SOEXT is
+ explicitly given. [ruby-dev:30657]
+
+Thu Mar 22 10:29:25 2007 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/ruby/test_bignum.rb (test_to_s): add tests for Bignum#to_s.
+
+Wed Mar 21 17:04:30 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (rb_big2str0): round up for the most significant digit.
+ [ruby-core:10686]
+
+Wed Mar 21 07:21:24 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/thread/thread.c (remove_one): Preserve List invariants;
+ submitted by: MenTaLguY <mental AT rydia.net>
+ in [ruby-core:10598] and [ruby-bugs:PR#9388].
+
+Tue Mar 20 22:54:50 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * marshal.c (w_extended): erroneous check condition when dump
+ method is defined. [ruby-core:10646]
+
Tue Mar 20 15:37:24 2007 URABE Shyouhei <shyouhei@ruby-lang.org>
* distruby.rb: Add zip generation.
+Tue Mar 20 11:28:41 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/matrix.rb (Matrix::inverse_from): adding partial pivoting to
+ the Gauss-Jordan algorithm, making it stable. a patch from
+ Peter Vanbroekhoven. [ruby-core:10641]
+
+Mon Mar 19 11:39:29 2007 Minero Aoki <aamine@loveruby.net>
+
+ * lib/net/protocol.rb (rbuf_read): extend buffer size for speed.
+
+Sun Mar 18 04:23:52 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * NEWS: Add a note about the new `date' library defining
+ Time#to_date and Time#to_datetime private methods.
+
+ * NEWS: Inform that the old `thread' library is considered to be
+ stable.
+
+ * NEWS: Sort library entries in alphabetical order.
+
Fri Mar 16 21:48:11 2007 Akinori MUSHA <knu@iDaemons.org>
* ext/dl/dl.c (rb_ary2cary): Fix a bug in type validation;
@@ -581,40 +6253,101 @@ Fri Mar 16 18:28:06 2007 Akinori MUSHA <knu@iDaemons.org>
reported by: UEDA Hiroyuki <ueda AT netforest.ad.jp>
in [ruby-dev:30586].
+Fri Mar 16 16:33:58 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/thread/thread.c (unlock_mutex_inner): Make sure that the
+ given mutex is actually owned by the caller; submitted by:
+ Sylvain Joyeux <sylvain.joyeux AT m4x.org> in [ruby-core:10598].
+
+Fri Mar 16 16:21:35 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/thread/thread.c (wait_condvar, lock_mutex): Fix a problem in
+ ConditionVariable#wait that occurs when two threads that are
+ trying to access the condition variable are also in concurrence
+ for the given mutex; submitted by: Sylvain Joyeux
+ <sylvain.joyeux AT m4x.org> and MenTaLguY <mental AT rydia.net>
+ in [ruby-core:10598].
+
+Fri Mar 16 16:17:27 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * test/thread/test_thread.rb: Add a test script for the `thread'
+ library. This should result in failure as of now with
+ ext/thread; submitted by: Sylvain Joyeux <sylvain.joyeux AT
+ m4x.org> in [ruby-core:10598].
+
Wed Mar 14 12:30:00 2007 Shigeo Kobayashi <shigeo@tinyforest.jp>
* ext/bigdecimal/bigdecimal.c: BigDecimal("-.31") is now
treated as ("-0.31") not as ("0.31").
-Fri Mar 16 18:05:40 2007 Akinori MUSHA <knu@iDaemons.org>
+Tue Mar 13 09:25:10 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (clear-installed-list): separated from install-prereq.
+
+Tue Mar 13 06:38:43 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * NEWS: Reword and improve entries.
+
+Tue Mar 13 06:03:46 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * stable version 1.8.6 released from the ruby_1_8_6 branch.
+
+Tue Mar 13 03:24:07 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * runruby.rb: added --pure (turned on by default) and --debugger
+ options.
+
+Tue Mar 13 02:50:28 2007 Akinori MUSHA <knu@iDaemons.org>
* lib/cgi.rb (CGI::header): IIS >= 5.0 does not need the nph
assumption any more; submitted by MIYASAKA Masaru <alkaid AT
coral.ocn.ne.jp> in [ruby-dev:30537].
-Tue Mar 13 17:29:43 2007 URABE Shyouhei <shyouhei@ruby-lang.org>
+Mon Mar 12 11:07:44 2007 Akinori MUSHA <knu@iDaemons.org>
- * stable version 1.8.5-p35 released.
+ * ext/openssl/ossl_asn1.c (Init_ossl_asn1): Let rdoc know about
+ externally defined modules; submitted by Technorama
+ Ltd. <oss-ruby AT technorama.net> in [ruby-bugs:PR#4704].
-Tue Mar 13 14:42:10 2007 URABE Shyouhei <shyouhei@ruby-lang.org>
+ * ext/openssl/ossl_bn.c (Init_ossl_bn): Ditto.
- * test/fileutils/fileasserts.rb: Fix wrong error message.
+ * ext/openssl/ossl_cipher.c (Init_ossl_cipher): Ditto.
- * lib/fileutils.rb (FileUtils::mv): Type Error; should utilize
- Strings instead of Symbols here.
+ * ext/openssl/ossl_digest.c (Init_ossl_digest): Ditto.
-Mon Mar 12 17:22:44 2007 NAKAMURA Usaku <usa@ruby-lang.org>
+ * ext/openssl/ossl_hmac.c (Init_ossl_hmac): Ditto.
- * lib/fileutils.rb (FileUtils::mv): fix incomplete backport of
- FileUtils.mv changes at r11988
+ * ext/openssl/ossl_pkey.c (Init_ossl_pkey): Ditto.
-Mon Mar 12 16:09:28 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+ * ext/openssl/ossl_pkey_dh.c (Init_ossl_dh): Ditto.
- * mkconfig.rb (patchlevel): read from version.h.
+ * ext/openssl/ossl_pkey_dsa.c (Init_ossl_dsa): Ditto.
+
+ * ext/openssl/ossl_pkey_rsa.c (Init_ossl_rsa): Ditto.
+
+ * ext/openssl/ossl_rand.c (Init_ossl_rand): Ditto.
+
+ * ext/openssl/ossl_ssl.c (Init_ossl_ssl): Ditto.
+
+Mon Mar 12 01:05:17 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/dl/sym.c (rb_dlsym_inspect): Use "0x%x" rather for pointers.
+ This might not be very right but it is commonly used in other
+ parts of the code; submitted by sheepman <sheepman AT
+ sheepman.sakura.ne.jp> in [ruby-dev:30532].
+
+ * ext/dl/ptr.c (rb_dlptr_inspect): Ditto.
+
+Mon Mar 12 00:59:19 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/dl/lib/dl/import.rb (DL::Importable::Internal::import,
+ DL::Importable::Internal::callback): Avoid race condition for an
+ instance variable; submitted by sheepman <sheepman AT
+ sheepman.sakura.ne.jp> in [ruby-dev:30530].
Sun Mar 11 18:57:50 2007 Akinori MUSHA <knu@iDaemons.org>
- * misc/README: Add a note about ruby-electric.el.
+ * misc/README: Add a note about ruby-electric.el.
* misc/ruby-mode.el (ruby-non-block-do-re): Fix
ruby-non-block-do-re. [ruby-core:03719]
@@ -632,24 +6365,118 @@ Sun Mar 11 17:45:51 2007 Akinori MUSHA <knu@iDaemons.org>
it; submitted by sheepman <sheepman AT sheepman.sakura.ne.jp>
in [ruby-dev:30524].
+Sun Mar 11 12:09:37 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (error_handle): no message when exiting by signal.
+
+ * eval.c (ruby_cleanup): re-send signal. [ruby-dev:30516]
+
+ * eval.c (rb_thread_interrupt): instantiate SignalException.
+
+ * eval.c (rb_thread_signal_raise): now takes signal number instead
+ of signal name.
+
+ * intern.h (rb_thread_signal_raise, ruby_default_signal): prototypes.
+
+ * signal.c (esignal_init): takes a signal number and an optional
+ signal name.
+
+ * signal.c (interrupt_init): pass SIGINT always.
+
+ * signal.c (ruby_default_signal): invoke system default signal
+ handler.
+
+ * signal.c (rb_signal_exec, trap): handle SIGTERM. [ruby-dev:30505]
+
+Tue Mar 6 19:08:46 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/digest/lib/md5.rb (MD5::new, MD5::md5): Do not modify
+ Digest::MD5.
+
+ * ext/digest/lib/sha1.rb (SHA1::new, SHA1::sha1): Ditto.
+
Tue Mar 6 18:58:37 2007 Keiju Ishitsuka <keiju@ruby-lang.org>
-
+
* lib/shell/process-controller.rb: fix thread synchronization
problem for [ruby-dev:30477].
-
-Sun Mar 4 23:53:27 2007 Minero Aoki <aamine@loveruby.net>
+
+Tue Mar 6 18:44:26 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/digest/lib/md5.rb (MD5::new, MD5::md5): Catch up with
+ Digest's API changes; noted by: Kazuhiro Yoshida <moriq AT
+ moriq.com> in [ruby-dev:30500].
+
+ * ext/digest/lib/sha1.rb (SHA1::new, SHA1::sha1): Ditto.
+
+Tue Mar 6 18:24:19 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * time.c (time_to_s): Back out the format changes; discussed
+ in [ruby-dev:30495].
+
+Tue Mar 6 11:53:25 2007 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/sample/irbtkw.rbw: fails to exit process.
+
+Mon Mar 5 20:14:49 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * time.c (time_to_s): Correct the wrong format which did not
+ really conform to RFC 2822; pointed out by: OHARA Shigeki <os at
+ iij.ad.jp> in [ruby-dev:30487].
+
+Sun Mar 4 23:38:07 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (rb_stat_s_utime): fixed a commit miss for the platforms
+ where utimes() does not exist.
+
+ * lib/fileutils.rb (touch): ditto.
+
+Sun Mar 4 14:46:56 2007 WATANABE Hirofumi <eban@ruby-lang.org>
+
+ * util.c (push_element): should return a int value.
+
+Sun Mar 4 01:05:57 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/set.rb (Set#^, Set#&): Correct documentation. Those methods
+ return sets, not arrays; noted by Oliver Frank Wittich <nietz AT
+ mangabrain.de>.
+
+Sat Mar 3 23:01:07 2007 Minero Aoki <aamine@loveruby.net>
* lib/fileutils.rb (mv): could not move a directory between
different filesystems. [ruby-dev:30411]
-Sat Mar 3 21:41:31 2007 Akinori MUSHA <knu@iDaemons.org>
+Sat Mar 3 22:57:11 2007 Minero Aoki <aamine@loveruby.net>
+
+ * lib/fileutils.rb (touch): last commit causes error if :mtime
+ option was not given.
+
+Sat Mar 3 22:37:02 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (rb_file_s_utime): allow nil to set the current time.
+
+ * lib/fileutils.rb (touch): ditto, and added :mtime and :nocreate
+ options. fixed: [ruby-talk:219037]
+
+Sat Mar 3 21:17:35 2007 Akinori MUSHA <knu@iDaemons.org>
* eval.c (stack_check): Unset inline to fix build with GCC 3.4.6;
submitted by: NISHIMATSU Takeshi <t_nissie AT yahoo.co.jp> in
[ruby-list:43218].
cf. http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24556
-Sat Mar 3 16:30:39 2007 Akinori MUSHA <knu@iDaemons.org>
+Sat Mar 3 19:05:31 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/thread/thread.c (push_list): Use ALLOC().
+
+ * ext/thread/thread.c (rb_mutex_alloc): Ditto.
+
+ * ext/thread/thread.c (rb_condvar_alloc): Ditto.
+
+Sat Mar 3 18:53:11 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * NEWS: Add a note for String#intern.
+
+Sat Mar 3 16:23:13 2007 Akinori MUSHA <knu@iDaemons.org>
* env.h (SCOPE_CLONE): Introduce a new scope flag to prevent a
local_tbl region from getting freed many times; submitted by
@@ -662,17 +6489,78 @@ Sat Mar 3 16:30:39 2007 Akinori MUSHA <knu@iDaemons.org>
* parse.y (top_local_setup_gen): Ditto.
-Sat Mar 3 15:41:33 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Sat Mar 3 16:07:02 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * object.c (rb_obj_ivar_set): RDoc updated according to a
+ suggestion from Brian Candler <B.Candler AT pobox.com>.
+ [ruby-core:10469]
+
+Thu Mar 1 21:38:07 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* parse.y (stmt, arg): should not omit lhs of OP_ASGN1 even if
+ empty. [ruby-dev:30455]
+
+Thu Mar 1 08:55:38 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_feature_p): check loading_tbl if the given ext is
empty. [ruby-dev:30452]
+ * eval.c (rb_feature_p): fix possible buffer overrun.
+
+Thu Mar 1 03:30:21 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/digest/digest.c (get_digest_base_metadata): Allow inheriting
+ Digest::Base subclasses, which was unintentionally made
+ impossible while restructuring Digest classes.
+
+Thu Mar 1 02:05:17 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * mkconfig.rb (patchlevel): read from version.h.
+
+Thu Mar 1 00:09:39 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_provided): return true only for features loaded from
+ .rb files, and not search actual library type. [ruby-dev:30414]
+
+Wed Feb 28 21:15:00 2007 WATANABE Hirofumi <eban@ruby-lang.org>
+
+ * configure.in (ac_cv_func_fcntl): fcntl support for MinGW.
+
+ * missing/flock.c: workaround for MinGW.
+
Wed Feb 28 20:51:32 2007 URABE Shyouhei <shyouhei@ruby-lang.org>
* pack.c (pack_unpack): properly ignore non-base64 octets such as
UTF-8 encoded BOMs; submitted by SOUMA Yutaka <holon@radastery.jp>
to fix [ruby-core:10437]
+Wed Feb 28 18:59:57 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * NEWS: Add NEWS, a document file to keep user visible feature
+ changes between releases.
+
+Wed Feb 28 18:35:50 2007 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/openssl/extconf.rb: no need to check unistd.h and sys/time.h.
+ they are already checked at configure.
+ reported by KOBAYASHI Yasuhiro [ruby-list:43225]
+
+Wed Feb 28 18:34:48 2007 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * lib/mkmf.rb ($DEFLIBPATH): default library paths ($(topdir), etc)
+ should be the first elements of library paths list.
+ reported by KOBAYASHI Yasuhiro [ruby-list:43225]
+
+Wed Feb 28 18:31:32 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * doc/NEWS-1.8.0: Rename NEWS to NEWS-1.8.0. This is way too old
+ NEWS.
+
+Wed Feb 28 01:22:58 2007 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/{dbm,gdbm}/test_{dbm,gdbm}.rb: shouldn't use host_os. use
+ target_os instead. reported by KOBAYASHI Yasuhiro [ruby-list:43225]
+
Wed Feb 28 00:08:11 2007 URABE Shyouhei <shyouhei@ice.uec.ac.jp>
* mkconfig.rb (RbConfig): add CONFIG['PATCHLEVEL']
@@ -681,43 +6569,305 @@ Wed Feb 28 00:08:11 2007 URABE Shyouhei <shyouhei@ice.uec.ac.jp>
* distruby.rb: new file
-Tue Feb 27 21:19:35 2007 NAKAMURA Usaku <usa@ruby-lang.org>
+Tue Feb 27 22:18:45 2007 WATANABE Hirofumi <eban@ruby-lang.org>
+
+ * configure.in (--enable-auto-image-base): avoid the neccessity to
+ rebase the shared libs as much as possible;
+ submitted by Corinna Vinschen <spam at vinschen.de> in
+ [ruby-talk:240964].
+
+Tue Feb 27 21:36:47 2007 WATANABE Hirofumi <eban@ruby-lang.org>
+
+ * util.c (__crt0_glob_function): use ruby_glob() instead of rb_globi().
+
+Tue Feb 27 21:33:04 2007 WATANABE Hirofumi <eban@ruby-lang.org>
+
+ * configure.in (ac_cv_func_setrlimit): workaround for djgpp.
+
+Tue Feb 27 19:38:52 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/base64.rb (Base64::b64encode): Fix documentation; submitted
+ by David Symonds <dsymonds@gmail.com> in [ruby-core:10432].
+
+Tue Feb 27 19:36:57 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * regex.c (calculate_must_string, slow_search, re_search): Silence
+ warnings regarding char * vs. unsigned char * mismatch;
+ submitted by Lyle Johnson <lyle.johnson@gmail.com>
+ in [ruby-core:10416].
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_load): Ditto.
+
+ * ext/digest/sha1/sha1ossl.c (SHA1_Finish): Ditto.
+
+ * ext/digest/rmd160/rmd160ossl.c (RMD160_Finish): Ditto.
+
+ * ext/digest/digest.c (rb_digest_base_finish,
+ rb_digest_base_update): Ditto.
+
+ * ext/nkf/nkf.c (rb_str_resize, rb_nkf_kconv, rb_nkf_guess1,
+ rb_nkf_guess2): Ditto.
+
+Tue Feb 27 03:40:09 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/thread/thread.c (wait_list_cleanup, rb_mutex_try_lock):
+ Eliminate rb_thread_critical switching where unnecessary;
+ implied by shugo in [ruby-dev:30412].
+
+ * ext/thread/thread.c (set_critical): Merge in
+ thread_exclusive_ensure().
+
+ * ext/thread/thread.c: Consistently use 0 and 1 for
+ rb_thread_critical values.
+
+Mon Feb 26 15:18:23 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/thread/thread.c: Use xmalloc()/xfree() instead of
+ malloc()/free(); pointed out by shugo in [ruby-dev:30412].
+
+Sun Feb 25 23:02:55 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/test/unit/autorunner.rb (Test::Unit::AutoRunner::initialize):
+ Initialize @workdir properly to silence a warning under -w.
+ Submitted by <tommy at tmtm.org> in [ruby-dev:30400].
+
+Sun Feb 25 02:47:43 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * defines.h: Pull the RUBY_MBCHAR_MAXSIZE definition from trunk,
+ which is necessary for dir.c to compile on djgpp and emx.
+
+Sat Feb 24 10:42:01 2007 Minero Aoki <aamine@loveruby.net>
+
+ * ext/racc/cparse/cparse.c (cparse_params_mark): remove useless
+ rb_gc_mark. Thanks Tomoyuki Chikanaga. [ruby-dev:30405]
+
+Fri Feb 23 15:10:46 2007 NAKAMURA Usaku <usa@ruby-lang.org>
* win32/win32.c (set_pioinfo_extra): new function for VC++8 SP1
workaround. [ruby-core:10259]
* win32/win32.c (NtInitialize): call above function.
-Mon Feb 26 09:57:58 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+Fri Feb 23 14:19:40 2007 NAKAMURA Usaku <usa@ruby-lang.org>
- * signal.c (ruby_signal): don't set SA_RESTART. a backport from
- the HEAD. [ruby-talk:220937] [ruby-talk:147220]
+ * signal.c (sighandler): need to tell to be interrupted to main
+ context when handler is installed.
+
+ * win32/win32.[ch] (rb_win32_interrupted): new function to listen
+ interrupt.
+
+Fri Feb 23 13:02:17 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * numeric.c (fix_cmp, fix_equal): Remove FIX2LONG() to optimize.
+ suggested in
+ http://t-a-w.blogspot.com/2007/02/making-ruby-faster.html.
+ [ruby-talk:240223]
+
+Fri Feb 23 12:43:17 2007 James Edward Gray II <james@grayproductions.net>
+
+ * lib/xmlrpc/client.rb (XMLRPC::Client::do_rpc): Make the
+ Content-Length parameter optional for responses in
+ xmlrpc/client.rb; suggested by Daniel Berger
+ <Daniel.Berger@qwest.com> and approved by the maintainer.
+
+ * lib/xmlrpc/create.rb (XMLRPC::Create::conv2value): Add DateTime
+ support to xmlrpc; approved by the maintainer.
+
+Mon Feb 19 18:22:52 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in, defines.h, eval.c (rb_feature_p, rb_provided,
+ load_wait, search_required, rb_require_safe), ext/extmk.rb: Fix
+ a bug where a statically linked extension cannot be autoloaded.
+ [ruby-dev:30023] / [ruby-dev:30239]
+
+Mon Feb 19 17:14:28 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * ext/socket/socket.c (unix_peeraddr): wrong syscall name in error
+ message for #peeraddr. a patch from Sam Roberts
+ <sroberts at uniserve.com>. [ruby-core:10366]
+
+Sun Feb 18 19:35:21 2007 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date/format.rb: updated based on date2 4.0.3.
+
+Fri Feb 16 11:18:21 2007 Eric Hodel <drbrain@segment7.net>
+
+ * lib/.document: Apply patch for irb, e2mmap and README by Hugh Sasse
+ <hgs at dmu.ac.uk> from [ruby-core:10135]
+
+ * lib/prettyprint.rb: Suppress RDoc for PrettyPrint test suite.
+
+Thu Feb 15 20:26:30 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/uri/ftp.rb: Revert the previous change pending discussion.
+
+Thu Feb 15 18:08:17 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * dir.c (glob_helper): Fix the function declaration.
+
+Thu Feb 15 17:13:32 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * version.h: Welcome to the post-1.8.6 world. Radical changes are
+ inhibited in the ruby_1_8 branch until the 1.8.6 final release
+ goes out of the door.
+
+Thu Feb 15 16:44:14 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/uri/generic.rb (URI::Generic::userinfo): Considering how
+ `scheme://user:@...', `scheme://:password@...' and
+ `scheme://:@...' are parsed, an empty user name or password
+ should be allowed and represented as it is.
+
+Thu Feb 15 11:46:05 2007 KIMURA Koichi <hogemuta@gmail.com>
+
+ * dir.c, win32/win32.c, win32/dir.h, ruby.h, intern.h: Bring
+ encoding aware globbing support in from trunk. Dir.[] and
+ Dir.glob() can now take many patterns in an array. Minor fixes
+ will follow.
+
+Thu Feb 15 11:00:26 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/uri/generic.rb (URI::Generic::userinfo): should support
+ empty password. [ruby-core:10290]
+
+ * lib/uri/generic.rb (URI::Generic::set_password): password can be
+ cleared by nil. [ruby-core:10290]
+
+ * lib/uri/common.rb (escape): regard second string argument as a
+ character set properly. [ruby-dev:27692]
+
+ * lib/uri/ftp.rb: Attempt to conform to RFC 1738 with regard to
+ relative/absolute paths.
+
+ * lib/uri: Lovely RDOC patches from mathew (metaATpoboxDOTcom).
+
+Thu Feb 15 10:57:38 2007 Tietew <tietew@tietew.net>>
+
+ * lib/cgi.rb (CGI::unescapeHTML): invalid decoding for single
+ unescaped ampersand. a patch from Tietew
+ <tietew+ruby-dev at tietew.net> in [ruby-dev:30292].
+ fixed: [ruby-dev:30289]
+
+Thu Feb 15 10:48:40 2007 MenTaLguY <mental@rydia.net>
+
+ * ext/thread/thread.c: Handle interrupted waits correctly.
+ [ruby-bugs:PR#8663]
+
+Wed Feb 14 19:22:15 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/digest/lib/digest.rb (Digest::self.const_missing): Drop
+ autoloads for sha2 classes in favor of handling in
+ const_missing(), to work around a problem exposed on OS X.
Tue Feb 13 02:21:12 2007 Sam Roberts <sroberts@uniserve.com>
* io.c (rb_f_syscall): Fix buffer overflow with syscall
arguments. [ruby-bugs:PR#8541]
-Sat Feb 10 09:33:47 2007 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+Sun Feb 11 07:46:45 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/cgi.rb (CGI::QueryExtension::read_multipart): Properly parse
+ a quoted-string in a Content-Disposition value.
+
+Sun Feb 11 06:27:54 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * configure.in, ext/thread/extconf.rb, lib/thread.rb: Add a
+ configure option `--disable-fastthread', to choose the original,
+ pure ruby version of the "thread" library instead of the new,
+ much faster implementation in ext/thread.
+
+Sun Feb 11 06:22:20 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/Setup: Add thread except for platforms without threads
+ support.
+
+Sun Feb 11 06:15:16 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/thread/lib/thread.rb: Add a replacement of thread.rb that
+ loads this extension.
+
+Sun Feb 11 05:39:47 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/thread.rb: Remove an ineffective part of the code.
- * ext/win32ole/win32ole.c (ole_variant2val): sorry, fix the enbug.
+Sun Feb 11 05:32:54 2007 Akinori MUSHA <knu@iDaemons.org>
-Sat Feb 10 09:08:01 2007 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+ * ext/thread/thread.c (rb_thread_exclusive): Implement
+ Thread.exclusive.
+
+Sun Feb 11 05:26:51 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/thread/thread.c: Get rid of use of a dummy function.
+
+Sun Feb 11 01:45:31 2007 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/thread/thread.c (Init_thread): Define missing aliases:
+ Queue#enq and SizedQueue#enq.
+
+Sat Feb 10 09:27:35 2007 Masaki Suketa <masaki.suketa@nifty.ne.jp>
* ext/win32ole/win32ole.c (ole_variant2val): fix compile error
on VC++.
-Sat Feb 10 08:38:30 2007 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+Sat Feb 10 07:41:52 2007 Masaki Suketa <masaki.suketa@nifty.ne.jp>
* ext/win32ole/win32ole.c (ole_variant2val): fix the bug when
SAFEARRAY pointer is NULL.
-Tue Feb 6 20:41:39 2007 NAKAMURA Usaku <usa@ruby-lang.org>
+Sat Feb 10 00:13:11 2007 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/lib/tk.rb: fix typo (TkConfigMethod::__confinfo_cmd,
+ __conv_keyonly_opts).
+
+Fri Feb 9 20:44:53 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/thread: Make style fixes (mostly de-K&R'ism) to match the
+ rest of the source code.
+
+ * ext/thread: Make USE_MEM_POOLS an extconf option.
+
+Fri Feb 9 20:43:01 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/thread: Import the "fastthread" implementation by MenTaLguY
+ in the original form. This module is not hooked into the build
+ yet since it needs some style fixes and adjustments.
+
+Fri Feb 9 15:46:09 2007 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/bigdecimal: Synchronize with trunk. Better function
+ prototypes, removal of a useless method `!=', and document
+ updates.
+
+Tue Feb 06 22:06:45 2007 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/nkf/nkf-utf8/{nkf.c,utf8tbl.c}:
+ imported nkf 2007-01-28.
+ * Fixed: can't decode MIME encode JIS string.
+ * Fixed: Fullwitdh-halfwidth conversion.
+ * Support DoCoMo's and Softbank's EMOJI
+ * Support CP932, CP5022x, eucJP-ms UDC
+ * Support UTF-32 encoding
+ * Support beyond BMP
+ [ruby-dev:29700] [ruby-dev:29922] [ruby-dev:30144]
+
+Wed Jan 31 14:52:09 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * eval.c (rb_iterate): need to PUSH_ITER in proper order.
+ [ruby-core:10125]
+
+ * test/ruby/test_iterator.rb (TestIterator::test_block_given_within_iterator):
+ add new test. [ruby-core:10125]
+
+Tue Jan 30 14:58:51 2007 NAKAMURA Usaku <usa@ruby-lang.org>
* string.c (rb_str_sub_bang): calling rb_str_modify() should be just
before actually modifying the string.
fixed: [ruby-dev:30211] (originally reported by zunda)
+Tue Jan 30 12:05:35 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * mkconfig.rb: autoconf 2.61 support. [ruby-core:10016]
+
Sat Jan 27 15:20:11 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
* parse.y (dyna_var_lookup): should not alter dvar->val not to
@@ -725,68 +6875,216 @@ Sat Jan 27 15:20:11 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
* parse.y (dyna_init): ditto.
+Fri Jan 26 12:03:39 2007 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/lib/tk.rb (TkConfigMethod#__confinfo_cmd,
+ __conv_keyonly_optkeys): make them private [ruby-dev:30074].
+
+ * ext/tk/lib/tk/txtwin_abst.rb: fix typo [ruby-dev:30073].
+
+ * ext/tk/lib/tk/canvas.rb (TkCanvas#scan_dragto): lack of an argument.
+
+ * ext/tk/lib/tk/canvas.rb: clarify the including module name
+ [ruby-dev:30080].
+
+ * ext/tk/lib/tk/scrollable.rb: change primary name of modules
+ [ruby-dev:30080].
+
Wed Jan 24 18:05:39 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
* misc/ruby-mode.el (ruby-font-lock-syntactic-keywords): fix
regexp font-lock bug. [ruby-talk:235758]
-Sun Jan 14 07:26:44 2007 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+Tue Jan 23 11:02:33 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/webrick/httprequest.rb (WEBrick::HTTPRequest::read_line):
+
+Tue Jan 23 18:26:12 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/cgi.rb (CGI::QueryExtension::read_multipart): use == instead
+ of ===. [ruby-dev:30176]
+
+Tue Jan 23 10:48:17 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * hash.c: added documentation for Hash about how it uses eql? and
+ hash methods for the keys. [ruby-core:09995]
+
+Mon Jan 22 14:57:25 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * ext/socket/socket.c: fix errors in socket sample code.
+ [ruby-core:09992]
- * ext/win32ole/win32ole.c (ole_free, ole_type_free,
- olemethod_free, olevariable_free, oleparam_free,
+Sat Jan 13 23:54:48 2007 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (ole_free, ole_type_free,
+ olemethod_free, olevariable_free, oleparam_free,
ole_event_free): fix memory leak. [ruby-core:09846]
-Tue Jan 9 12:29:20 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Fri Jan 12 11:13:55 2007 Nobuyoshi Nakada <nobu@ruby-lang.org>
* ext/etc/etc.c (etc_getpwuid, etc_getgrgid): fix to correctly
- convert uid/gid from VALUE.
+ convert uid/gid from VALUE. (backport of r11521)
- * ext/etc/etc.c (etc_getpwuid): ditto.
+Wed Jan 10 18:57:57 2007 Minero Aoki <aamine@loveruby.net>
-Mon Dec 25 20:08:28 2006 URABE Shyouhei <shyouhei@ruby-lang.org>
+ * ext/strscan/strscan.c (strscan_do_scan): should set kcode option
+ before match. [ruby-dev:29914]
- * ext/openssl/ossl.h: fixed compilation problem on gcc 3.2.
- [ruby-talk:214786]
+ * test/strscan/test_stringscanner.rb: test it.
-Mon Dec 25 10:40:40 2006 URABE Shyouhei <shyouhei@ruby-lang.org>
+ * re.c: export kcode_set_option and kcode_reset_option (with "rb_"
+ prefix).
- * stable version 1.8.5-p12 released.
+ * intern.h: ditto.
-Sat Dec 16 04:02:10 2006 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+Tue Jan 9 17:45:17 2007 NAKAMURA Usaku <usa@ruby-lang.org>
- * ext/tk/tcltklib.c: shouldn't run the killed thread at callback.
- [ruby-talk: 227408]
+ * file.c (rb_find_file): should not call fpath_check() with NULL.
+ fixed: [ruby-core:09867]
-Fri Dec 15 17:21:14 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+Tue Jan 9 03:54:38 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
- * lib/rdoc/ri/ri_options.rb: prevent NameError. [ruby-dev:29597]
+ * string.c (rb_str_upto): String#upto from empty string makes
+ inifinite loop. [ruby-core:09864]
-Thu Dec 14 23:37:38 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Sun Jan 7 12:13:26 2007 Eric Hodel <drbrain@segment7.net>
- * dir.c (glob_helper): get rid of possible memory leak.
+ * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser#find_class_comment):
+ Look for class and module comments above rb_define_class and
+ rb_define_module. Patch by Daniel Berger <djberg96 at gmail.com>
- * win32/win32.c (cmdglob, rb_w32_cmdvector, rb_w32_opendir,
- rb_w32_get_environ): not to use GC before initialization.
+Sun Jan 7 10:32:12 2007 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser#handle_constants):
+ Properly handle escaping of : in comments.
+ * test/rdoc/parsers/test_parse_c.rb:
+ Test RDoc::C_Parser#do_classes and Rdoc::C_Parser#find_class_comment.
+
+Sun Jan 7 09:33:02 2007 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date/format.rb: updated based on date2 4.0.1.
+
+Wed Jan 3 11:36:51 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * io.c (ruby_dup): start GC on ENOMEM as well.
+
+Mon Jan 1 06:13:11 2007 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rdoc/parsers/c_parser.rb: Make Rdoc accessible. Update constant
+ value information.
+
+Mon Jan 1 06:13:11 2007 Eric Hodel <drbrain@segment7.net>
+
+ * ext/bigdecimal/bigdecimal.c: Update constant comments to provide
+ values for RDoc.
+
+Mon Jan 1 06:05:55 2007 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser#handle_constansts):
+ Allow RDoc comment to give friendly value for rb_define_const. Patch
+ by Daniel Berger <djberg96 at gmail.com>, [ruby-patches-7499].
+ * lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser#handle_constansts): Fix
+ whitespace handling in constant comments.
+
+Sun Dec 31 00:31:16 2006 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date.rb, lib/date/format.rb: updated based on date2 4.0.
+
+Thu Dec 14 18:29:13 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * ext/readline/readline.c: NetBSD editline does not have
+ rl_username_completion_function() and rl_completion_matches().
+ a patch from Takahiro Kambe <taca at back-street.net>.
+ [ruby-dev:30008]
+
+Thu Dec 14 18:20:43 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
-Wed Dec 6 19:53:41 2006 WATANABE Hirofumi <eban@ruby-lang.org>
+ * lib/irb/locale.rb (IRB::Locale::puts): typo fixed. a patch from
+ NAKAMURA Usaku <usa@ruby-lang.org>. [ruby-dev:30012]
+
+Mon Dec 11 11:58:36 2006 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/digest/sha2/lib/sha2.rb: Moved one level up from under
+ the superfluous subdirectory digest/.
+
+Mon Dec 11 11:46:18 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * variable.c (rb_define_const): typo fixed.
+
+Mon Dec 11 09:36:29 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * string.c (rb_str_aset): index double decode problem.
+ [ruby-core:09695]
+
+Sat Dec 9 21:39:24 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (ruby_cleanup): keep the exception till after END blocks.
+ [ruby-core:09675]
+
+Sat Dec 9 11:22:00 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/irb/locale.rb (IRB::Locale::search_file): ues File.exist?
+ instead of File.exists?. a patch from Yutaka Kanemoto
+ <kinpoco at gmail.com> in [ruby-dev:30000].
+
+Thu Dec 7 09:29:02 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/weakref.rb (WeakRef::__setobj__): should support
+ marshaling. [ruby-talk:228508]
+
+ * lib/delegate.rb (Delegator::marshal_load): need to call
+ __setobj__.
+
+Wed Dec 6 23:56:14 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * Makefile.in, common.mk (NULLCMD): moved for platforms that empty
+ command does not run. fixed: [ruby-dev:29994]
+
+Wed Dec 6 17:17:26 2006 WATANABE Hirofumi <eban@ruby-lang.org>
* configure.in (SITE_DIR): fixed to emtpy RUBY_SITE_LIB in config.h on
NetBSD. fixed: [ruby-dev:29358]
+Tue Dec 5 00:59:05 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * misc/ruby-mode.el (ruby-parse-partial): need to parse "/=" as
+ self assignment operator, not regex. [ruby-talk:227324]
+
+Mon Dec 4 10:48:03 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * ruby.h (OFFT2NUM): use LONG2NUM() if sizeof(long) equals to
+ sizeof(off_t).
+
Mon Dec 4 10:43:46 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
* parse.y (dyna_init_gen): dvar initialization only if dvar is
assigned inner block. [ruby-talk:227402]
-Mon Dec 4 10:22:26 2006 URABE Shyouhei <shyouhei@ice.uec.ac.jp>
-
- * stable version 1.8.5-p2 released.
-
-Sun Dec 3 17:11:12 2006 Shugo Maeda <shugo@ruby-lang.org>
+Mon Dec 4 08:32:49 2006 Shugo Maeda <shugo@ruby-lang.org>
* lib/cgi.rb (CGI::QueryExtension::read_multipart): should quote
boundary. JVN#84798830
+Sat Dec 2 07:09:04 2006 GOTOU Yuuzou <gotoyuzo@notwork.org>
+
+ * ext/openssl/ossl_ocsp.c: OpenSSL::OCSP::OSCPError should be
+ subclass of OpenSSL::OpenSSLError. [ruby-dev:29980]
+
+Fri Dec 1 17:01:49 2006 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * gc.c (ruby_init_stack): decrease "stack level too deep" in Windows.
+ merge from trunk.
+
+Fri Dec 1 16:31:53 2006 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/tcltklib.c: shouldn't run the killed thread at callback.
+ [ruby-talk: 227408]
+
+Mon Nov 27 17:18:27 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * sprintf.c (rb_f_sprintf): need not to truncate string if no
+ width specifier given for %s. [ruby-dev:29952]
+
Sun Nov 26 16:36:46 2006 URABE Shyouhei <shyouhei@ruby-lang.org>
* version.h: addition of RUBY_PATCHLEVEL.
@@ -797,26 +7095,891 @@ Fri Nov 24 10:17:51 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
* bignum.c (bignorm): avoid segmentation. a patch from Hiroyuki
Ito <ZXB01226@nifty.com>. [ruby-list:43012]
+Thu Nov 23 10:38:40 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * eval.c (rb_mod_define_method): set implicit visibility only when
+ it's called for the target class (ruby_cbase).
+
+Wed Nov 22 16:00:49 2006 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/extconf.rb: support --with-X11/--without-X11 option.
+
+ * ext/tk/README.tcltklib: add description about --with-X11-* option
+ [ruby-talk:225166] and --with-X11/--without-X11 option.
+
+ * ext/tk/tkutil/extconf.rb: able to be called manually
+ [ruby-talk:225950].
+
+Wed Nov 15 23:22:54 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (test_grpowned, rb_stat_grpowned): should honor
+ supplementary group IDs. [ruby-core:09546]
+
+Thu Nov 9 03:15:22 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * eval.c (BEGIN_CALLARGS): ruby_block may be NULL even when
+ ITER_PRE.
+
+Tue Nov 7 18:34:34 2006 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/digest/lib/digest/hmac.rb: Keep this out of the 1.8 tree
+ until we reach a consensus that HMAC should be put under Digest.
+
+Tue Nov 7 18:05:01 2006 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/lib/tk/itemconfig.rb: minor bug fix.
+
+Mon Nov 6 20:11:20 2006 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rss/0.9.rb (RSS::Rss): removed needless include.
+
+Mon Nov 6 15:41:55 2006 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/lib/tk/itemconfig.rb: ext/tk/lib/tk/itemconfig.rb: bug
+ fix on 'itemconfiginfo' method, and modify to make it easy to
+ override 'itemconfiginfo' method.
+
+ * ext/tk/lib/tkextlib/tile/treeview.rb : support Tile 0.7.8.
+
+ * ext/tk/lib/tkextlib/version.rb : [new] add Tk::Tkextlib_RELEASE_DATE
+ to get the information from scripts.
+
+ * ext/tk/lib/tk.rb: load 'tkextlib/version.rb', and update RELEASE_DATE
+
+ * ext/tk/lib/tkextlib/SUPPORT_STATUS: update.
+
+ * ext/tk/sample/editable_listbox.rb: [new] the listbox with editable
+ items. It's one of the example about usage of Place geometry manager.
+
+ * ext/tk/sample/tktextio.rb: improve the functions of TkTextIO class.
+ Those are required by 'irbtkw.rbw'.
+
+ * ext/tk/sample/irbtkw.rbw: [new] IRB on Ruby/Tk. It doesn't need any
+ real console. IRB works on a text widget without I/O blocking. That
+ is, thread switching on IRB will work properly, even if on Windows.
+
+Sun Nov 5 19:53:49 2006 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date.rb: updated based on date2 3.9.7.
+
+Sat Nov 4 13:13:57 2006 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/imap.rb: accept NOMODSEQ. [ruby-core:9002]
+ (backported from HEAD)
+
+Fri Nov 3 00:16:37 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * ext/socket/socket.c (ruby_getnameinfo__aix): AF_INET6 workaround
+ for AIX. a patch from Yutaka Kanemoto <kinpoco AT gmail.com>.
+ [ruby-dev:29744]
+
Thu Nov 2 15:43:39 2006 NAKAMURA Usaku <usa@ruby-lang.org>
* parse.y (primary): should set NODE even when compstmt is NULL.
merge from trunk. fixed: [ruby-dev:29732]
+Thu Nov 2 14:48:30 2006 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/set.rb (Set#^): Fix XOR operation against a container that
+ holds duplicate values. [issue: #6444]
+
+Wed Nov 1 02:41:38 2006 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/digest/lib/digest/hmac.rb (Digest::HMAC::update): Minor
+ optimization.
+
+ * ext/digest/digest.c (rb_digest_instance_equal): Allow comparing
+ a digest instance with another of a different class.
+
+Wed Nov 1 01:05:13 2006 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * eval.c (rb_call0): fixed bug of zsuper with both of opt and rest.
+ fixed: [ruby-list:42928]
+
+ * test/ruby/test_super.rb: add tests to check above bug.
+
+Tue Oct 31 17:03:21 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * time.c (time_dup): duplicate the class of original time.
+ [ruby-core:09357]
+
+ * lib/time.rb (Time::make_time, Time::rfc2822, Time::httpdate):
+ should respect subclasses. [ruby-core:09357]
+
+Mon Oct 30 23:40:52 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * Makefile.in (miniruby): add XLDFLAGS.
+
+ * configure.in (aix): use -bE option for miniruby. [ruby-dev:29698]
+
+ * dir.c (glob_helper): get rid of possible memory leak.
+
+ * win32/win32.c (cmdglob, rb_w32_cmdvector, rb_w32_opendir,
+ rb_w32_get_environ): not to use GC before initialization.
+
+Mon Oct 30 19:29:20 2006 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * bignum.c (rb_big2str0): use better approximation.
+
+Mon Oct 30 18:35:33 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * bignum.c (rb_big2str0): wrong allocation length. a patch from
+ U.Nakamura <usa at garbagecollect.jp> [ruby-dev:29710]
+
+Mon Oct 30 12:34:02 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * eval.c (rb_eval): fix commit miss. [ruby-dev:29707]
+
+Mon Oct 30 12:20:58 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * bignum.c (rb_big2str0): a bug in length adjustment.
+
+Mon Oct 30 11:15:40 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * sprintf.c (rb_str_format): should preserve leading zero
+ information for negative %b and %x. [ruby-talk:221347]
+
+Thu Oct 26 21:05:58 2006 GOTOU Yuuzou <gotoyuzo@notwork.org>
+
+ * ext/openssl/ossl_pkcs7.c (ossl_pkcs7_verify): should clear error.
+ (fix http://bugs.debian.org/394336)
+
+ * ext/openssl/ossl_ns_spki.c (ossl_spki_initialize): ditto.
+
+Thu Oct 26 15:21:10 2006 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/digest/digest.c (Init_digest): typo.
+
+Wed Oct 25 17:23:28 2006 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/digest, test/digest/test_digest.rb: Merge from trunk:
+ - Introduce versioning in Digest::Base API, and prefix C
+ constants with RUBY_ and C type names with rb_ to avoid name
+ clash in writing extensions.
+ - Introduce Digest::Class and Digest::Instance for ease of
+ implementing subclasses and add-ons.
+ - Digest::Instance module requires and assumes that any instance
+ be resettable and clonable. An instance method #new() is
+ added so digest instances work just like digest classes.
+ - The constructor does no longer take an initial string to feed;
+ digest() and hexdigest() now do, instead. This allows digest
+ classes to take their own hashing parameters.
+ - Make some changes to digest() and hexdigest() class methods,
+ which now take extra arguments, which are passed through to
+ the constructor in an internal call.
+ - Add #digest_length/size/length() and #block_length(),
+ - Add the Digest::SHA2 class to wrap up SHA2 variants: SHA256,
+ SHA384 and SHA512, hoping this module would make a decent
+ example of a digest subclass written in Ruby.
+ - Rip BubbleBabble support out of the base class and have a
+ separate module named digest/bubblebabble.
+ - Remove RD documents in favor of newly written and embedded
+ RDoc documentation.
+
+Wed Oct 25 08:03:23 2006 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date/format.rb: updated based on date2 3.9.6.
+ [ruby-core:09323]
+
+Sun Oct 22 14:48:31 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * signal.c (ruby_signal): don't set SA_RESTART. a backport from
+ the HEAD. [ruby-talk:220937] [ruby-talk:147220]
+
+ * signal.c (Init_signal): avoid duplicated installation of SIGCHLD
+ handler.
+
+Sun Oct 22 16:47:56 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_substr): should be infected with only original
+ string, but not the shared string. fixed: [ruby-core:09152]
+
+ * string.c (rb_str_new4): keep shared string untainted when orignal
+ string is tainted. fixed: [ruby-dev:29672]
+
+Sun Oct 22 05:20:34 2006 URABE Shyouhei <shyouhei@ice.uec.ac.jp>
+
+ * configure.in: alloca is broken; use C_ALLOCA instead.
+ [ruby-dev:29416]
+
+Fri Oct 20 10:47:43 2006 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * lib/mkmf.rb: fixed the bug of handling COMMON_MACROS.
+
+Fri Oct 20 08:42:38 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (NULLCMD): dummy command.
+
+ * bcc32/Makefile.sub (post-install-*): Borland make cannot ignore
+ command-less double-colon rules. [ruby-dev:29676]
+
+Fri Oct 20 00:37:07 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bcc32/Makefile.sub ($(LIBRUBY_SO)): execute pre-link hook.
+
+ * ext/extmk.rb: workaround for Borland make.
+
+Wed Oct 18 23:02:40 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (rb_ary_shift): shorten copy size. fixed: [ruby-list:42907]
+
+ * signal.c (Init_signal): handle SIGTERM. fixed: [ruby-list:42895]
+
+ * win32/win32.c (rb_w32_utime): allow NULL to set the current time.
+ [ruby-talk:219248]
+
+Wed Oct 18 00:55:33 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_yylex): use particular enums. [ruby-core:09221]
+
+Mon Oct 16 08:30:43 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * mkconfig.rb: *OBJS are not needed for extension libraries.
+
+ * {bcc32,wince,win32}/Makefile.sub (config.status): fixed typo,
+ missing comma.
+
+Sun Oct 15 01:03:08 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/test/unit/collector/dir.rb (Collector::Dir#collect): append base
+ directory but not prepend.
+
+ * lib/test/unit/collector/dir.rb (Collector::Dir#collect_file): do not
+ join with dot. fixed: [ruby-core:09179]
+
+Sat Oct 14 23:39:50 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * parse.y (singleton): no need to re-create NODE_SELF() again.
+ [ruby-core:09177]
+
+Sat Oct 14 23:25:31 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * parse.y (parser_warning, parser_warn): some error message may
+ contain format specifiers. a patch from Akinori MUSHA <knu at
+ iDaemons.org>. [ruby-dev:29657]
+
+ * ext/bigdecimal/bigdecimal.c (VpException): ditto.
+
+ * ext/dl/handle.c (rb_dlhandle_initialize): ditto.
+
+ * ext/gdbm/gdbm.c (rb_gdbm_fatal): ditto.
+
+Sat Oct 14 08:24:45 2006 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/digest/lib/digest/hmac: Back out the addition of digest/hmac
+ for now because the API is too premature for a stable branch.
+
+Sat Oct 14 00:55:08 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bcc32/Makefile.sub (post-install-ext): no longer needed.
+
+ * bcc32/configure.bat: get rid of a quirk of Borland make, which
+ sets empty macro in command line to "1".
+
+Fri Oct 13 22:50:43 2006 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date.rb: updated based on date2 3.9.5.
+
+Fri Oct 13 22:33:28 2006 Minero Aoki <aamine@loveruby.net>
+
+ * lib/fileutils.rb (FileUtils.cp_r): dereference_root=true is
+ default in Ruby 1.8. This line is wrongly removed in last commit.
+
+Fri Oct 13 18:19:31 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * object.c: Class#inherited RDoc added. a patch from Daniel
+ Berger <djberg96 at gmail.com> [ruby-core:08942]
+
+Fri Oct 13 02:30:12 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/test/unit/collector/dir.rb (Collector::Dir#collect): prepend
+ base directory to load path.
+
+ * lib/test/unit/collector/dir.rb (Collector::Dir#collect_file): should
+ use the given File-like interface, but not File directly.
+
+ * test/testunit/collector/test_dir.rb (TestDir::FileSystem): implement
+ File-like methods correctly.
+
+Fri Oct 13 01:48:42 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/date.rb (Date::self.complete_hash): need to check if g is
+ nil before dereference. [ruby-core:09116]
+
+Fri Oct 13 00:34:26 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * object.c (rb_mod_cvar_defined): wrong id check. a patch from
+ Mauricio Fernandez <mfp at acm.org>. [ruby-core:09158]
+
+ * object.c (rb_mod_cvar_get): typo fixed. [ruby-core:09168]
+
+ * object.c (rb_mod_cvar_set): ditto.
+
+Wed Oct 11 22:21:41 2006 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/digest: Merge from trunk; metadata location changed,
+ Digest::Base#reset() added, Digest::Base#equal() changed, and
+ digest/hmac added with some modifications made for ruby 1.8.
+
+Tue Oct 10 17:24:12 2006 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * {bcc32,win32,wince}/Makefile.sub (config.status): shouldn't use
+ copy command instead of install. use -run install.
+
+Tue Oct 10 16:49:16 2006 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/digest/digest.c (hexdigest_str_new, bubblebabble_str_new):
+ Perform StringValue() checks properly.
+
+ * ext/digest/digest.c: Use RSTRING_{PTR,LEN} macros.
+
+Tue Oct 10 13:49:53 2006 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/digest: Merge from trunk; apply all changes since the
+ initial import, except for the removal of compatibility stub
+ libraries (md5.rb and sha1.rb).
+
+Mon Oct 9 23:46:29 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/parsedate.rb: documentation patch from Konrad Meyer
+ <konrad.meyer@gmail.com>. [ruby-doc:1238]
+
+ * lib/open3.rb, lib/ping.rb: ditto.
+
+Mon Oct 9 22:56:12 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/rexml/encoding.rb (REXML::Encoding::check_encoding): spaces
+ are allowed around equal sign. [ruby-core:09032]
+
+ * lib/rexml/parsers/baseparser.rb (REXML::Parsers::BaseParser): ditto.
+
+Sat Oct 7 23:53:08 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * string.c (rb_str_scan): small documentation fix.
+ [ruby-core:09007]
+
+Sat Oct 7 23:44:33 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * bignum.c (rb_big_rshift): a bug in right shift of negative
+ bignums. [ruby-core:09020]
+
+Sat Oct 7 00:27:58 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * class.c (rb_include_module): remove unnecessary check.
+ [ruby-talk:218402]
+
+Fri Oct 6 04:30:30 2006 Akinori MUSHA <knu@iDaemons.org>
+
+ * sample/openssl/c_rehash.rb: Use digest/md5 instead of obsolete md5.
+
+Wed Oct 4 18:47:25 2006 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/lib/tkextlib/*: bugfix and update
+ (see ext/tk/ChangeLog.tkextlib).
+
+Wed Oct 4 17:25:14 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * eval.c (rb_call): check protected visibility based on real self,
+ not ruby_frame->self. [ruby-talk:217822]
+
+Wed Oct 4 08:52:30 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/optparse/test_getopts.rb: changed the class name of test case
+ to get rid of conflict with test_optparse.rb.
+
+Tue Oct 3 23:32:27 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/test/unit/testcase.rb (Test::Unit::TestCase.suite): test name
+ must be string. fixed: [ruby-core:08978]
+
+Mon Oct 2 23:47:55 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/test/unit/autorunner.rb (Test::Unit::AutoRunner::COLLECTORS):
+ base directory should be lower precedence. fixed: [ruby-dev:29622]
+
+ * lib/test/unit/autorunner.rb (Test::Unit::AutoRunner#options): typo.
+
+ * lib/test/unit/collector/dir.rb (Test::Unit::Collector::Dir#collect_file):
+ load expanded path. fixed: [ruby-dev:29621]
+
+Mon Oct 2 15:49:19 2006 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * instruby.rb: batfile should be CRLF'ed.
+
+Mon Oct 2 01:24:26 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (test-all): separate directory where running test cases
+ from source tree.
+
+ * lib/test/unit/autorunner.rb (options): added --basedir, --workdir
+ and --load-path options.
+
+ * lib/test/unit/collector/dir.rb (recursive_collect, collect_file):
+ base directory support.
+
+Sun Oct 1 23:56:52 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * Makefile.in, common.mk, ext/extmk.rb, win{32,ce}/Makefile.in: keep
+ LIBRUBY_SO unless need to be removed.
+
+Sun Oct 1 23:12:19 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/optparse.rb (OptionParser#make_switch): pass arguments directly.
+
+Sat Sep 30 15:12:25 2006 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date.rb, lib/date/format.rb: updated based on date2 3.9.4.
+
+Fri Sep 29 12:11:04 2006 WATANABE Hirofumi <eban@ruby-lang.org>
+
+ * jcode.rb (succ!): call original succ! if $KCODE == 'n'.
+ fixed: [ruby-talk:216845]
+
+Fri Sep 29 11:43:40 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (try_func): revert fallback checking undeclared function.
+ fixed: [ruby-core:08949]
+
+Fri Sep 29 09:56:56 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/extmk.rb: extout is needed for also clean.
+ fixed: [ruby-core:08944]
+
+ * lib/optparse.rb (OptionParser::Switch#conv_arg): unsplat by
+ Proc#call if no conversion is given.
+
+Thu Sep 28 23:59:31 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * node.h (struct thread): declare win32_exception_list on cygwin and
+ win32 regardless if it is implemented. Provisional fix for
+ [ruby-core:08917].
+
+Thu Sep 28 20:53:16 2006 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * lib/tmpdir.rb: use return value of getdir.call for length.
+
+Wed Sep 27 01:04:49 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (try_func): check function pointer first and macro next.
+
+ * lib/mkmf.rb (have_type): simplified with typedef and sizeof.
+
+Tue Sep 26 23:57:03 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/optparse.rb (OptionParser#getopts): use strings as key.
+ fixed: [ruby-dev:29614]
+
+Tue Sep 26 15:31:26 2006 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * {win32,wince}/Makefile.sub (CPP): check predefined value.
+
+Tue Sep 26 07:55:16 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * array.c (rb_ary_shift): should not move memory region if array
+ body is shared. a patch from Kent Sibilev <ksruby at gmail.com>.
+ [ruby-core:08922]
+
+Mon Sep 25 22:26:26 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (rb_path_end): skip root directory. fixed: [ruby-core:08913]
+
+ * lib/mkmf.rb (init_mkmf): set default $LDFLAGS. Patch by Michal
+ Suchanek <hramrach at centrum.cz>. [ruby-talk:216256]
+
+Mon Sep 25 08:14:43 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * array.c (rb_ary_shift): should clear shifting top element.
+ [ruby-talk:216055]
+
+ * array.c (rb_ary_shift): avoid creating shared object if array
+ size is small.
+
+Mon Sep 25 08:11:35 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * random.c (rb_f_rand): RDoc typo fix. a patch from Frederick
+ Cheung <fred at 82ask.com>. [ruby-talk:216047]
+
+Sun Sep 24 22:28:20 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * runruby.rb: extension library scripts moved into common directory.
+
+Sun Sep 24 14:59:50 2006 Tanaka Akira <akr@fsij.org>
+
+ * node.h (struct thread): ia64 support is broken by sandbox patch.
+
+Sun Sep 24 12:11:16 2006 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date.rb, lib/date/format.rb: updated based on date2 3.9.3.
+
+Sat Sep 23 23:24:57 2006 why the lucky stiff <why@ruby-lang.org>
+
+ * eval.c (rb_thread_save_context, rb_thread_restore_context):
+ sandbox hook to save and restore sandbox state.
+
+ * eval.c (thread_no_ensure): added THREAD_NO_ENSURE thread flag.
+
+ * eval.c (rb_thread_kill_bang): Thread#kill! uses the above flag
+ to circumvent ensure, in order to prevent endless loops.
+ [ruby-core:08768]
+
+ * eval.c (rb_thread_kill): fix Thread#kill docs, which returns
+ the thread object in all cases.
+
+ * node.h: expose the rb_jmpbuf_t and rb_thread_t structs, along
+ with the thread flags. used by the sandbox extension.
+
+ * ruby.h: extern rb_eThreadError, so sandbox can swap it.
+
Sat Sep 23 21:34:15 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
* lib/cgi.rb (CGI::QueryExtension::read_multipart): CGI content
may be empty. a patch from Jamis Buck <jamis at 37signals.com>.
+Sat Sep 23 08:35:53 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/rdoc/ri/ri_options.rb: prevent NameError. [ruby-dev:29597]
+
+Sat Sep 23 01:04:20 2006 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date.rb, lib/date/format.rb: updated based on date2 3.9.2.
+
+Fri Sep 22 02:06:26 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * .cvsignore: ignore timestamp files and installed list file.
+
+Fri Sep 22 01:36:34 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * instruby.rb: include FileUtils unconditionally.
+
+Thu Sep 21 22:56:20 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (no-install): not install rdoc actually.
+
+ * common.mk (install-doc, no-install-doc): use instruby.rb.
+
+ * instruby.rb: rdoc installation.
+
+ * ext/extmk.rb: expand ruby executable names.
+
+Thu Sep 21 13:55:07 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * ext/etc/etc.c (etc_getpwuid): uid integer should be wraped in
+ uid_t value. [ruby-core:08897]
+
+ * ext/etc/etc.c (etc_getpwuid): uid_t may be bigger than plain
+ 'int' type.
+
+Wed Sep 20 23:17:41 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (pre-install-doc): create data directory before install.
+
+ * lib/mkmf.rb (dir_re): fixed typo.
+
+ * lib/mkmf.rb (install_dirs): remove extra slash.
+
+Wed Sep 20 09:53:38 2006 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * {bcc32,win32,wince}/Makefile.sub (INSTALLED_LIST): need to define
+ this macro to install.
+
+Wed Sep 20 09:43:10 2006 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/imap.rb: allow extra spaces in responses.
+ Thanks, Tom Soderlund. (backported from HEAD)
+
+Wed Sep 20 09:25:39 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * ext/gdbm/gdbm.c: add RDoc documentation. a patch from Peter
+ Adolphs <futzilogik at users dot sourceforge dot net>.
+ [ruby-doc:1223]
+
+Tue Sep 19 01:28:00 2006 Minero Aoki <aamine@loveruby.net>
+
+ * lib/fileutils.rb: backport from HEAD (rev 1.71).
+
+ * lib/fileutils.rb (FileUtils.cp_r): new option
+ :remove_destination.
+
+Tue Sep 19 00:42:15 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * object.c (rb_obj_ivar_defined, rb_mod_cvar_defined): new methods,
+ Kernel#instance_variable_defined? and Module#class_variable_defined?.
+ [ruby-dev:29587]
+
+ * lib/date/format.rb (Date::Bag#method_missing): use new method,
+ instance_variable_defined? to check if an instance variable is
+ defined. fixed: [ruby-dev:29554]
+ -- This didn't fix anything.
+
+Sun Sep 17 23:44:58 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/rdoc/rdoc.rb (RDoc::RDoc#document): scan only files modified
+ after the previous generation.
+
+Sun Sep 17 17:42:13 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (install-doc): reverted.
+
+ * instruby.rb: stores file name list without destdir prefix.
+
+ * lib/rdoc/generators/ri_generator.rb: do not chdir twice.
+
+Sat Sep 16 23:14:29 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * ext/pty/pty.c (establishShell): remove remaining unused line.
+
+Sat Sep 16 16:40:44 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * Makefile.in, common.in, instruby.rb, ext/extmk.rb, lib/mkmf.rb:
+ use instruby.rb to install extensions instead of ext/extmk.rb.
+
+ * instruby.rb: store installed list into the file.
+
+ * ext/dbm/extconf.rb: allow multiple candidates for dbm-type.
+
+ * ext/io/wait/extconf.rb: suspicious checking_for.
+
+ * ext/pty/pty.c (establishShell): parent pid is not used.
+
+ * ext/pty/pty.c (freeDevice): not used.
+
+ * ext/pty/pty.c (get_device_once): removed garbage right brace.
+
+ * lib/mkmf.rb (checking_for): improved the messages.
+
+Thu Sep 14 16:11:15 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * string.c (rb_str_intern): raise SecurityError only when $SAFE
+ level is greater than zero. [ruby-core:08862]
+
+ * parse.y (rb_interned_p): new function to check if a string is
+ already interned.
+
+ * object.c (str_to_id): use rb_str_intern().
+
+Wed Sep 13 18:43:05 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * README.EXT: English adjustment. [ruby-core:08851] and
+ [ruby-core:08852]
+
+Wed Sep 13 18:25:18 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * misc/ruby-mode.el (ruby-parse-partial): better here-doc support.
+ a patch from Marshall T. Vandegrift <llasram at gmail.com>.
+ [ruby-core:08804]
+
+Wed Sep 13 16:43:36 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * string.c (rb_str_intern): prohibit interning tainted string.
+
+Wed Sep 13 01:14:21 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/optparse.rb (OptionParser#getopts): works with pre-registered
+ options. [ruby-core:08826]
+
+Sun Sep 10 20:27:13 2006 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date.rb, lib/date/format.rb: updated based on date2 3.9.1.
+
+Tue Jan 10 09:18:03 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (stack_extend): fixed prototype.
+
+ * eval.c (rb_require_safe): prevent extension from loading twice.
+ fixed: [ruby-dev:29523]
+
+Sat Sep 9 23:50:38 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * bignum.c (rb_big_mul0): bignum multiplication without
+ normalization.
+
+ * bignum.c (rb_big_pow): use rb_big_mul0(). [ruby-dev:29547]
+
+Sat Sep 9 14:08:38 2006 Eric Hodel <drbrain@segment7.net>
+
+ * lib/test/unit/testcase.rb (Test::Unit::TestCase#run): Rescue
+ Exception in Test::Unit::TestCase#run. [ruby-core:08783]
+
+Sat Sep 9 04:55:59 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/pstore.rb: open all in binary mode, and get rid of the quirk of
+ msvcrt. fixed: [ruby-dev:29518]
+
+Sat Sep 9 04:54:42 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * Makefile.in, win32/Makefile.sub (MINIRUBY): append MINIRUBYOPT.
+
+ * mkconfig.rb, ext/extmk.rb, lib/mkmf.rb, win32/mkexports.rb: suppress
+ warnings with $VERBOSE.
+
+ * ext/extmk.rb: Proc#call does not pass the block in 1.8.
+
+ * win32/resource.rb: add more info.
+
+Fri Sep 8 10:03:59 2006 GOTOU Yuuzou <gotoyuzo@notwork.org>
+
+ * lib/webrick/cookie.rb (WEBrick::Cookie.parse_set_cookies): new
+ method to parse multiple cookies per Set-Cookie header.
+ Thanks to Aaron Patterson <aaron_patterson at speakeasy.net>.
+ [ruby-core:08802]
+
+Fri Sep 8 08:59:30 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/Makefile.sub, win32/configure.bat win32/setup.mak: program
+ name transform.
+
+Fri Sep 8 01:33:08 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * ruby.h (RSTRING_PTR): add migration macro.
+
+ * ruby.h (RARRAY_PTR): ditto.
+
+Thu Sep 7 23:27:05 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (path_check_0, fpath_check): disable path check on cygwin.
+ [ruby-talk:213074]
+
+Wed Sep 06 12:05:19 2006 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/nkf/lib/kconv.rb (Kconv::RegexpEucjp): fix regexp for euc-jp
+ [ruby-dev:29344]
+
+ * ext/nkf/lib/kconv.rb (Kconv::toeuc): remove -m0 [ruby-dev:29505]
+
+Tue Sep 5 06:47:22 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * time.c (time_to_s): variable declaration after an execution
+ statement.
+
+Tue Sep 5 05:56:51 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (flo_hash): improve collision. fixed: [ruby-dev:29352]
+
+Tue Sep 5 05:49:41 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (path_check_0): check if sticky bit is set on parent
+ directories for executable path. fixed: [ruby-dev:29415]
+
+Tue Sep 5 05:03:46 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * numeric.c (fix_plus): addition in Fixnum will never overflow
+ long. a patch from Ondrej Bilka <neleai at seznam.cz>.
+ [ruby-core:08794]
+
+ * numeric.c (fix_minus): ditto.
+
+ * bignum.c (rb_big_pow): eagerly truncate resulting bignum.
+ [ruby-core:08794]
+
+Mon Sep 4 23:15:34 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * time.c (time_to_s): make it conform to RFC2822 date format.
+ [ruby-dev:29467]
+
Mon Sep 4 21:43:57 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
* ext/dbm/extconf.rb: create makefile according to the result of check
for dbm header. fixed: [ruby-dev:29445]
+Mon Sep 4 21:42:35 2006 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date.rb, lib/date/format.rb: updated based on date2 3.9.
+
+Mon Sep 4 21:14:20 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * time.c (time_strftime): include nul character. fixed: [ruby-dev:29422]
+
+Mon Sep 4 16:29:33 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/cgi.rb (CGI::out): specify -m0 -x option for nkf.
+ [ruby-dev:29284]
+
+Mon Sep 4 16:13:23 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * io.c (pipe_open): command name should not contain null bytes.
+ [ruby-dev:29421]
+
+ * process.c (proc_spawn): ditto.
+
+ * process.c (proc_spawn_n): ditto.
+
+ * process.c (rb_f_system): ditto.
+
+Sun Sep 3 15:32:44 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb: get rid of nil.to_s.
+
+Sun Sep 3 06:24:38 2006 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/socket.c (ruby_connect): sockerrlen should be socklen_t.
+
+Sun Sep 3 04:40:42 2006 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: check arpa/inet.h for ntohs.
+
+ * ext/socket/socket.c: include arpa/inet.h if available.
+
+Sun Sep 3 02:34:55 2006 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * lib/drb/unix.rb (DRbUNIXSocket#close): don't get path if client mode.
+ [ruby-dev:29417]
+
+Sun Sep 3 01:45:17 2006 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * lib/drb/acl.rb (ACLEntry#initialize): examine whether '*' is
+ included before IPAddr.new. [ruby-dev:29406]
+
+Sat Sep 2 13:23:01 2006 Tanaka Akira <akr@fsij.org>
+
+ * common.mk (ia64.o): use the compiler driver to assemble ia64.s
+ to use appropriate ABI.
+
+Sat Sep 2 03:36:22 2006 Tanaka Akira <akr@fsij.org>
+
+ * common.mk, configure.in, defines.h, eval.c, gc.c, main.c,
+ numeric.c, ruby.h, ia64.s: backport IA64 HP-UX support.
+
+Fri Sep 1 13:52:57 2006 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/lib/tk/font.rb: TkFont#current_configinfo() doesn't work
+ on Tcl/Tk8.x.
+
+Thu Aug 31 12:46:55 2006 why the lucky stiff <why@ruby-lang.org>
+
+ * eval.c (ruby_init): rename top_cref to ruby_top_cref and export,
+ along with ruby_cref, for use by the sandbox. [ruby-core:08762]
+
+ * node.h: ditto.
+
Tue Aug 29 19:10:10 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
* hash.c (rb_hash_s_create): fixed memory leak, based on the patch
by Kent Sibilev <ksruby at gmail.com>. fixed: [ruby-talk:211233]
+Mon Aug 28 11:36:02 2006 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rdoc/parsers/parse_rb.rb: Fix typo. Submitted by
+ <calamitas at gmail.com>. [ruby-core:08724]
+
+Mon Aug 28 07:53:44 2006 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rdoc/ri/ri_formatter.rb: Don't unescape HTML in HtmlFormatter.
+ Submitted by Kent Sibilev <ksruby at gmail.com>. [ruby-core:08392].
+
+Mon Aug 28 07:25:45 2006 Eric Hodel <drbrain@segment7.net>
+
+ * file.c (File#size?): Fix documentation submitted by Rick Ohnemus.
+ ruby-Bugs-5529. [ruby-core:08725]
+
+Sat Aug 26 08:07:13 2006 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * lib/date.rb, lib/date/format.rb: updated based on date2 3.8.2.
+
+Fri Aug 25 22:32:04 2006 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/rexml/source.rb (REXML::IOSource#initialize): encoding have to
+ be set with the accessor. fixed: [ruby-list:42737]
+
Fri Aug 25 17:15:17 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
* stable version 1.8.5 released.
@@ -829,7 +7992,7 @@ Tue Aug 22 18:47:51 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
* lib/rdoc/parsers/parse_c.rb (RDoc::C_Parser::handle_method):
rdoc documents C module methods as instance methods. a patch in
- [ruby-core:08536].
+ [ruby-core:08536].
Sat Aug 19 14:15:02 2006 NAKAMURA Usaku <usa@ruby-lang.org>
@@ -1156,7 +8319,7 @@ Thu Jul 20 15:07:14 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
Thu Jul 20 00:06:29 2006 Keiju Ishitsuka <keiju@ishitsuka.com>
* lib/irb/completion.rb: support for completion of numeric
- number. [ruby-dev: 29038]
+ number. [ruby-dev: 29038]
Wed Jul 19 23:53:05 2006 Kouhei Sutou <kou@cozmixng.org>
@@ -1270,7 +8433,7 @@ Thu Jul 13 22:23:56 2006 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
Thu Jul 13 20:32:19 2006 Kouhei Sutou <kou@cozmixng.org>
* lib/rss/parser.rb: updated documents by a patch from
- Hugh Sasse <hgs at dmu.ac.uk>. [ruby-core:8194]
+ Hugh Sasse <hgs at dmu.ac.uk>. [ruby-core:8194]
Wed Jul 12 13:54:09 2006 Yukihiro Matsumoto <matz@ruby-lang.org>
@@ -4343,8 +11506,8 @@ Sat Sep 17 09:45:26 2005 Yukihiro Matsumoto <matz@ruby-lang.org>
Sat Sep 17 08:35:39 2005 Kouhei Sutou <kou@cozmixng.org>
* lib/rss/maker/base.rb (RSS::Maker::ItemsBase#normalize): fixed
- strange RSS::Maker::Item#max_size behavior.
- Thanks to Kazuhiko <kazuhiko@fdiary.net>.
+ strange RSS::Maker::Item#max_size behavior.
+ Thanks to Kazuhiko <kazuhiko@fdiary.net>.
* test/rss/test_maker_1.0.rb (RSS::TestMaker10#test_items): ditto.
@@ -5102,6 +12265,7 @@ Mon Aug 1 01:17:40 2005 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
* test/drb/ut_drb.rb: ditto.
Mon Aug 1 00:07:32 2005 Keiju Ishitsuka <keiju@ruby-lang.org>
+
* lib/irb/context.rb: fix `irb --readline` option. [ruby-list:40955]
Fri Jul 29 09:59:38 2005 Nobuyoshi Nakada <nobu@ruby-lang.org>
@@ -5586,6 +12750,7 @@ Fri Jul 1 00:18:40 2005 Yukihiro Matsumoto <matz@ruby-lang.org>
destination object. [ruby-talk:146894]
Thu Jun 30 19:00:21 2005 Keiju Ishitsuka <keiju@ruby-lang.org>
+
* lib/irb/ruby-lex.rb (RubyLex::identify_number): alternative implements
for [ruby-dev:26410]. And support a numeric form of 0d99999.
@@ -6557,7 +13722,6 @@ Sat Apr 9 11:59:57 2005 Kouhei Sutou <kou@cozmixng.org>
- gave a name to 'x'.
- undef_method -> remove_method for avoiding a warning in ruby 1.6.
-
* lib/rss/parser.rb: @@setter -> @@setters.
* lib/rss/parser.rb
@@ -6585,34 +13749,28 @@ Sat Apr 9 11:59:57 2005 Kouhei Sutou <kou@cozmixng.org>
elements. (ex. have childlen elements, have some attributes and
a child element and so on.)
-
* lib/rss/dublincore.rb: supported multiple Dublin Core items.
* lib/rss/maker/dublincore.rb: ditto.
* lib/rss/maker/image.rb: supproted new Dublin Core API.
-
* lib/rss/maker/base.rb: added default current_element implementation.
-
* lib/rss/trackback.rb (RSS::TrackBackUtils.new_with_value_if_need):
moved to RSS::Utils.
* lib/rss/utils.rb (RSS::Utils.new_with_value_if_need):
moved from RSS::TrackBackUtils.
-
* lib/rss/maker/image.rb: fixed invalid argument of
add_need_initialize_variable bug.
* lib/rss/maker/trackback.rb: ditto.
-
* lib/rss/rss.rb (Hash#merge): added for ruby 1.6.
* lib/rss/rss.rb (RSS::BaseModel.date_writer): changed to accept nil
for date value.
-
* test/test_dublincore.rb: added tests for plural accessor and
multiple Dublin Core items.
@@ -6628,7 +13786,6 @@ Sat Apr 9 11:59:57 2005 Kouhei Sutou <kou@cozmixng.org>
* test/rss/test_maker_dc.rb (test_date): added a test for #date=
and #dc_date=.
-
* sample/rss/tdiary_plugin/rss-recent.rb:
new option: @options['rss-recent.use-image-link']:
use image as link instread of text if available.
@@ -7619,7 +14776,7 @@ Wed Feb 2 21:56:01 2005 Kouhei Sutou <kou@cozmixng.org>
Tue Feb 1 22:48:48 2005 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
* lib/drb/drb.rb (DRb::DRbObject#respond_to?): check marshal_dump and
- _dump.
+ _dump.
Tue Feb 1 00:20:23 2005 Nobuyoshi Nakada <nobu@ruby-lang.org>
@@ -8526,7 +15683,7 @@ Wed Dec 15 18:57:01 2004 Yukihiro Matsumoto <matz@ruby-lang.org>
Wed Dec 15 18:48:42 2004 Shugo Maeda <shugo@ruby-lang.org>
* ext/curses/curses.c (window_subwin): call NUM2INT() before
- GetWINDOW(). (backported from CVS HEAD)
+ GetWINDOW(). (backported from CVS HEAD)
Wed Dec 15 17:03:50 2004 NAKAMURA Usaku <usa@ruby-lang.org>
@@ -9149,7 +16306,7 @@ Thu Nov 18 18:41:08 2004 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
* test/ruby/test_stringchar.rb (test_bang): added.
* string.c (rb_str_upcase_bang, rb_str_capitalize_bang)
- (rb_str_swapcase_bang): missing rb_str_modify(). [ruby-dev:24915]
+ (rb_str_swapcase_bang): missing rb_str_modify(). [ruby-dev:24915]
Thu Nov 18 00:21:15 2004 Yukihiro Matsumoto <matz@ruby-lang.org>
@@ -9765,7 +16922,7 @@ Mon Oct 18 15:58:01 2004 NAKAMURA Usaku <usa@ruby-lang.org>
Fri Oct 29 16:34:19 2004 Daiki Ueno <ueno@unixuser.org>
* misc/ruby-mode.el (ruby-parse-partial): Parse the rest of the
- line after opening heredoc identifier. [ruby-dev:24635]
+ line after opening heredoc identifier. [ruby-dev:24635]
Mon Oct 18 07:26:21 2004 Nobuyoshi Nakada <nobu@ruby-lang.org>
@@ -9961,7 +17118,7 @@ Mon Oct 4 12:53:45 2004 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
Sun Oct 3 21:20:03 2004 Shugo Maeda <shugo@ruby-lang.org>
* lib/net/imap.rb (TEXT_REGEXP): allow 8-bit characters for the german
- version of Microsoft Exchange Server. (backported from HEAD)
+ version of Microsoft Exchange Server. (backported from HEAD)
* lib/net/imap.rb (RTEXT_REGEXP): ditto.
@@ -10286,7 +17443,6 @@ Sun Sep 12 02:41:58 2004 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* ext/tcltklib/tcltklib.c: add TclTkIp#allow_ruby_exit? and
allow_ruby_exit=
-
* ext/tk/lib/multi-tk.rb: ditto.
* ext/tk/lib/remote-tk.rb: ditto.
@@ -10767,9 +17923,9 @@ Sun Jul 18 03:21:42 2004 Akinori MUSHA <knu@iDaemons.org>
Sun Jul 18 03:12:11 2004 Shugo Maeda <shugo@ruby-lang.org>
* lib/net/imap.rb (receive_responses): return if a LOGOUT response
- received. (backported from HEAD)
+ received. (backported from HEAD)
* lib/net/imap.rb (send_string_data): wait command continuation
- requests before sending octet data of literals. (backported from HEAD)
+ requests before sending octet data of literals. (backported from HEAD)
Sat Jul 17 23:54:59 2004 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
@@ -10840,7 +17996,7 @@ Thu Jul 15 23:53:38 2004 Nobuyoshi Nakada <nobu@ruby-lang.org>
Thu Jul 15 22:59:48 2004 Shugo Maeda <shugo@ruby-lang.org>
* ext/readline/extconf.rb: added dir_config for curses, ncurses,
- termcap. (backported from HEAD)
+ termcap. (backported from HEAD)
Thu Jul 15 20:29:15 2004 Hirokazu Yamamoto <ocean@m2.ccsnet.ne.jp>
@@ -10872,7 +18028,6 @@ Thu Jul 15 10:15:04 2004 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* ext/tk/sample/tkextlib/: add samples of Iwidget and TkTable
-
Wed Jul 14 18:08:37 2004 GOTOU Yuuzou <gotoyuzo@notwork.org>
* ext/openssl/ossl_asn1.c (ossl_asn1cons_to_der): fix type of
@@ -11361,7 +18516,7 @@ Tue Jun 22 21:11:36 2004 Masaki Suketa <masaki.suketa@nifty.ne.jp>
Tue Jun 22 16:47:42 2004 Shugo Maeda <shugo@ruby-lang.org>
* lib/net/ftp.rb (MDTM_REGEXP): fix for demon's ftp server.
- Thanks, Rutger Nijlunsing.
+ Thanks, Rutger Nijlunsing.
Mon Jun 21 10:19:23 2004 NAKAMURA Usaku <usa@ruby-lang.org>
@@ -13349,7 +20504,6 @@ Tue Dec 30 12:30:30 2003 Dave Thomas <dave@pragprog.com>
class and a method have the same name, finding Xxx.abc was trying
to find 'abc' in method 'Xxx', not class 'Xxx'.
-
Tue Dec 30 08:32:32 2003 Dave Thomas <dave@pragprog.com>
* lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_method):
@@ -13357,7 +20511,6 @@ Tue Dec 30 08:32:32 2003 Dave Thomas <dave@pragprog.com>
def each_entry(&b) Dir.foreach(@path) {|f| yield P.new(f) } end
-
Tue Dec 30 08:32:32 2003 Dave Thomas <dave@pragprog.com>
* lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_method):
@@ -15263,6 +22416,7 @@ Sat Nov 8 13:49:50 2003 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* configure.in: improvement of pthread check
Sat Nov 8 13:28:46 2003 Takaaki Tateishi <ttate@ttsky.net>
+
* ext/dl/sym.c: Add DL.win32_last_error and DL.last_error.
Thanks, Kaoru Shirai.
@@ -18100,6 +25254,7 @@ Tue Aug 12 02:48:56 2003 Yukihiro Matsumoto <matz@ruby-lang.org>
* eval.c (THREAD_ALLOC): initialize IA64 members.
Mon Aug 11 22:31:50 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
+
* lib/debug.rb(debug_command): inspection command should inspect
resulting value even if it's nil. [ruby-dev:21180] by OMAE, jun
<jun66j5@ybb.ne.jp>.
@@ -18300,9 +25455,10 @@ For the changes before 1.8.0, see doc/ChangeLog-1.8.0
Local variables:
add-log-time-format: (lambda ()
(let* ((time (current-time))
+ (system-time-locale "C")
(diff (+ (cadr time) 32400))
(lo (% diff 65536))
- (hi (+ (car time) (/ diff 65536))))
+ (hi (+ (car time) (/ diff 65536))))
(format-time-string "%a %b %e %H:%M:%S %Y" (list hi lo) t)))
indent-tabs-mode: t
tab-width: 8
diff --git a/LEGAL b/LEGAL
index 908eb270f5..c66513b4b5 100644
--- a/LEGAL
+++ b/LEGAL
@@ -45,7 +45,6 @@ configure:
config.guess:
config.sub:
-parse.c:
As long as you distribute these files with the file configure, they
are covered under the Ruby's license.
@@ -72,6 +71,43 @@ parse.c:
configuration script generated by Autoconf, you may include it under
the same distribution terms that you use for the rest of that program.
+parse.c:
+
+ This file is licensed under the GPL, but is incorporated into Ruby and
+ redistributed under the terms of the Ruby license, as permitted by the
+ exception to the GPL below.
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+ /* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
util.c (partly):
win32/win32.[ch]:
diff --git a/Makefile.in b/Makefile.in
index 8fd59babcd..6271138fbb 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,4 +1,5 @@
SHELL = /bin/sh
+NULLCMD = :
#### Start of system configuration section. ####
@@ -34,6 +35,9 @@ RIDATADIR = $(DESTDIR)$(datadir)/ri/$(MAJOR).$(MINOR)/system
empty =
OUTFLAG = @OUTFLAG@$(empty)
CFLAGS = @CFLAGS@ @XCFLAGS@ @ARCH_FLAG@
+cflags = @cflags@
+optflags = @optflags@
+debugflags = @debugflags@
CPPFLAGS = -I. -I$(srcdir) @CPPFLAGS@
LDFLAGS = @STATIC@ $(CFLAGS) @LDFLAGS@
EXTLDFLAGS =
@@ -52,8 +56,8 @@ RUBY_SO_NAME=@RUBY_SO_NAME@
EXEEXT = @EXEEXT@
PROGRAM=$(RUBY_INSTALL_NAME)$(EXEEXT)
RUBY = $(RUBY_INSTALL_NAME)
-MINIRUBY = @MINIRUBY@
-RUNRUBY = @RUNRUBY@
+MINIRUBY = @MINIRUBY@ $(MINIRUBYOPT)
+RUNRUBY = @RUNRUBY@ $(RUNRUBYOPT) --
#### End of system configuration section. ####
@@ -85,7 +89,7 @@ ASFLAGS = @ASFLAGS@
OBJEXT = @OBJEXT@
MANTYPE = @MANTYPE@
-PREINSTALL = @PREINSTALL@
+INSTALLED_LIST= .installed.list
#### End of variables
all:
@@ -97,7 +101,7 @@ all:
miniruby$(EXEEXT):
@$(RM) $@
- $(PURIFY) $(CC) $(MAINOBJ) $(MINIOBJS) $(LIBRUBY_A) $(LIBS) $(OUTFLAG)$@ $(LDFLAGS) $(MAINLIBS)
+ $(PURIFY) $(CC) $(LDFLAGS) $(XLDFLAGS) $(MAINLIBS) $(MAINOBJ) $(MINIOBJS) $(LIBRUBY_A) $(LIBS) $(OUTFLAG)$@
$(PROGRAM):
@$(RM) $@
@@ -112,6 +116,7 @@ $(LIBRUBY_A):
@-$(RANLIB) $@ 2> /dev/null || true
$(LIBRUBY_SO):
+ @-$(PRE_LIBRUBY_UPDATE)
$(LDSHARED) $(DLDFLAGS) $(OBJS) $(DLDOBJS) $(SOLIBS) $(OUTFLAG)$@
@-$(MINIRUBY) -e 'ARGV.each{|link| File.delete link if File.exist? link; \
File.symlink "$(LIBRUBY_SO)", link}' \
@@ -129,9 +134,16 @@ fake.rb: Makefile
if RUBY_PLATFORM =~ /mswin|bccwin|mingw/; \
class File; \
remove_const :ALT_SEPARATOR; \
- ALT_SEPARATOR = "\\"; \
+ ALT_SEPARATOR = "\\\\"; \
end; \
end; \
+ prehook = proc do |e|; \
+ builddir = File.expand_path(File.dirname(__FILE__)); \
+ Config::MAKEFILE_CONFIG["top_srcdir"] = $$top_srcdir = \
+ File.expand_path("@top_srcdir@", builddir) unless e; \
+ untrace_var(:$$extmk, prehook); \
+ end; \
+ trace_var(:$$extmk, prehook); \
' > $@
Makefile: $(srcdir)/Makefile.in
@@ -153,9 +165,12 @@ $(srcdir)/configure: $(srcdir)/configure.in
cd $(srcdir) && $(AUTOCONF)
lex.c: keywords
- @-$(RM) $@
- gperf -p -j1 -i 1 -g -o -t -N rb_reserved_word -k1,3,$$ $? > $@ || \
- cp "$(srcdir)/$@" .
+ ( gperf -C -p -j1 -i 1 -g -o -t -N rb_reserved_word -k1,3,$$ $? > $@.tmp && mv $@.tmp $@ ) || \
+ if test -f $@; then \
+ touch $@ && echo $@ touched.; \
+ else \
+ cp $(srcdir)/lex.c $@ && echo $@ copied.; \
+ fi
.y.c:
$(YACC) $<
@@ -176,3 +191,19 @@ distclean-local::
ext/extinit.$(OBJEXT): ext/extinit.c $(SETUP)
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(OUTFLAG)$@ -c ext/extinit.c
+
+update-rubyspec:
+ if [ -d $(srcdir)/rubyspec ]; then \
+ cd $(srcdir)/rubyspec/mspec; \
+ git pull; \
+ cd ../spec; \
+ git pull; \
+ else \
+ mkdir $(srcdir)/rubyspec; \
+ git clone $(MSPEC_GIT_URL) $(srcdir)/rubyspec/mspec; \
+ git clone $(RUBYSPEC_GIT_URL) $(srcdir)/rubyspec/spec; \
+ fi
+
+test-rubyspec:
+ @if [ ! -d $(srcdir)/rubyspec ]; then echo No rubyspec here. make update-rubyspec first.; exit 1; fi
+ RUBY_EXE="$(RUNRUBY)" $(RUNRUBY) $(srcdir)/rubyspec/mspec/bin/mspec-run --background --prefix $(srcdir)/rubyspec/spec -B $(srcdir)/rubyspec/spec/ruby.$(MAJOR).$(MINOR).mspec
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000000..1ef8a1b453
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,648 @@
+= NEWS
+
+This document is a list of user visible feature changes made between
+releases except for bug fixes.
+
+Note that each entry is kept so brief that no reason behind or
+reference information is supplied with. For a full list of changes
+with all sufficient information, see the ChangeLog file.
+
+* REXML
+
+ * REXML::Document.entity_expansion_limit=
+
+ New method to set the entity expansion limit. By default the limit is
+ set to 10000. See the following URL for details.
+
+ http://www.ruby-lang.org/en/news/2008/08/23/dos-vulnerability-in-rexml/
+
+== Changes since the 1.8.6 release
+
+=== Configuration changes
+
+* vendor_ruby directory
+
+ A new library directory named `vendor_ruby' is introduced in
+ addition to `site_ruby'. The idea is to separate libraries
+ installed by the package system (`vendor') from manually (`site')
+ installed libraries preventing the former from getting overwritten
+ by the latter, while preserving the user option to override vendor
+ libraries with site libraries. (`site_ruby' takes precedence over
+ `vendor_ruby')
+
+ If you are a package maintainer, make each library package configure
+ the library passing the `--vendor' option to `extconf.rb' so that
+ the library files will get installed under `vendor_ruby'.
+
+ You can change the directory locations using configure options such
+ as `--with-sitedir=DIR' and `--with-vendordir=DIR'.
+
+=== Global constants
+
+* new constants
+
+ * RUBY_COPYRIGHT
+ * RUBY_DESCRIPTION
+
+=== Library updates (outstanding ones only)
+
+* new library
+
+ * securerandom
+
+* builtin classes
+
+ * Array#flatten
+ * Array#flatten!
+
+ Takes an optional argument that determines the level of recursion
+ to flatten.
+
+ * Array#eql?
+ * Array#hash
+ * Array#==
+ * Array#<=>
+
+ Handle recursive data properly.
+
+ * Array#index
+ * Array#rindex
+
+ Take a block instead of an argument.
+
+ * Array#collect!
+ * Array#map!
+ * Array#each
+ * Array#each_index
+ * Array#reverse_each
+ * Array#reject
+ * Array#reject!
+ * Array#delete_if
+ * Array#select
+
+ Return an enumerator if no block is given.
+
+ Note that #map and #collect still return an array unlike Ruby 1.9
+ to keep compatibility.
+
+ * Array#pop
+ * Array#shift
+
+ Take an optional argument specifying the number of elements to
+ remove.
+
+ * Array#choice
+ * Array#combination
+ * Array#cycle
+ * Array#drop
+ * Array#drop_while
+ * Array#permutation
+ * Array#product
+ * Array#shuffle
+ * Array#shuffle!
+ * Array#take,
+ * Array#take_while
+
+ New methods.
+
+ * Binding#eval
+
+ New method.
+
+ * Dir#each
+ * Dir#foreach
+
+ Return an enumerator if no block is given.
+
+ * Enumerable::Enumerator
+
+ New class for various enumeration defined by the enumerator library.
+
+ * Enumerable#each_slice
+ * Enumerable#each_cons
+ * Object#to_enum
+ * Object#enum_for
+
+ New methods for various enumeration defined by the enumerator library.
+
+ * Enumerable#count
+ * Enumerable#cycle
+ * Enumerable#drop
+ * Enumerable#drop_while
+ * Enumerable#find_index
+ * Enumerable#first
+ * Enumerable#group_by
+ * Enumerable#max_by
+ * Enumerable#min_by
+ * Enumerable#minmax
+ * Enumerable#minmax_by
+ * Enumerable#none?
+ * Enumerable#one?
+ * Enumerable#take
+ * Enumerable#take_while
+
+ New methods.
+
+ * Enumerable#find
+ * Enumerable#find_all
+ * Enumerable#partition
+ * Enumerable#reject
+ * Enumerable#select
+ * Enumerable#sort_by
+
+ Return an enumerator if no block is given.
+
+ Note that #map and #collect still return an array unlike Ruby 1.9
+ to keep compatibility.
+
+ * Enumerable#inject
+
+ Accepts a binary operator instead of a block.
+
+ * Enumerable#reduce
+
+ New alias to #inject.
+
+ * Enumerable#to_a
+
+ Can take optional arguments and pass them to #each.
+
+ * Hash#eql?
+ * Hash#hash
+ * Hash#==
+
+ Handle recursive data properly.
+
+ * Hash#delete_if
+ * Hash#each
+ * Hash#each_key
+ * Hash#each_pair
+ * Hash#each_value
+ * Hash#reject!
+ * Hash#select
+ * ENV.delete_if
+ * ENV.each
+ * ENV.each_key
+ * ENV.each_pair
+ * ENV.each_value
+ * ENV.reject!
+ * ENV.select
+
+ Return an enumerator if no block is given.
+
+ * GC.stress
+ * GC.stress=
+
+ New methods.
+
+ * Integer#ord
+ * Integer#odd?
+ * Integer#even?
+ * Integer#pred
+
+ New methods.
+
+ * Integer#downto
+ * Integer#times
+ * Integer#upto
+
+ Return an enumerator if no block is given.
+
+ * IO#each
+ * IO#each_line
+ * IO#each_byte
+ * IO.foreach
+ * ARGF.each
+ * ARGF.each_line
+ * ARGF.each_byte
+
+ Return an enumerator if no block is given.
+
+ * IO#bytes
+ * IO#chars
+ * IO#each_char
+ * IO#getbyte
+ * IO#lines
+ * IO#readbyte
+ * ARGF.bytes
+ * ARGF.chars
+ * ARGF.each_char
+ * ARGF.getbyte
+ * ARGF.lines
+ * ARGF.readbyte
+
+ New methods.
+
+ * Method#name
+ * Method#owner
+ * Method#receiver
+ * UnboundMethod#name
+ * UnboundMethod#owner
+
+ New methods.
+
+ * Module#class_exec
+ * Module#module_exec
+
+ New methods.
+
+ * Numeric#step
+
+ Return an enumerator if no block is given.
+
+ * Object#instance_exec
+ * Object#tap
+
+ New methods.
+
+ * ObjectSpace.each_object
+
+ Return an enumerator if no block is given.
+
+ * Process.exec implemented.
+
+ * Range#each
+ * Range#step
+
+ Return an enumerator if no block is given.
+
+ * Regexp.union accepts an array of patterns.
+
+ * String#bytes
+
+ New method
+
+ * String#bytesize
+
+ New method, returning the size in bytes. (alias length and size)
+
+ * String#chars
+ * String#each_char
+ * String#lines
+ * String#partition
+ * String#rpartition
+ * String#start_with?
+ * String#end_with?
+
+ New methods. These are $KCODE aware unlike #index, #rindex and
+ #include?.
+
+ * String#each_byte
+ * String#each
+ * String#each_line
+ * String#gsub(pattern)
+
+ Return an enumerator if no block is given.
+
+ * String#upto
+
+ An optional second argument is added to specify if the last value
+ should be included.
+
+ * StopIteration
+
+ New exception class that causes Kernel#loop to stop iteration when
+ raised.
+
+ * Struct#each
+ * Struct#each_pair
+
+ Return an enumerator if no block is given.
+
+ * Symbol#to_proc
+
+ New method.
+
+ * __method__
+
+ New global function that returns the name of the current method as
+ a Symbol.
+
+* enumerator
+
+ * Enumerator is now a built-in module. The #next and #rewind
+ methods are implemented using the "generator" library. Use with
+ care and be aware of the performance loss.
+
+* ipaddr
+
+ * New methods
+ * IPAddr#<=>
+ * IPAddr#succ
+
+ IPAddr objects are now comparable and enumerable having these
+ methods. This also means that it is possible to have a Range
+ object between two IPAddr objects.
+
+ * IPAddr#to_range
+
+ A new method to create a Range object for the (network) address.
+
+ * Type coercion support
+ * IPAddr#&
+ * IPAddr#|
+ * IPAddr#==
+ * IPAddr#include?
+
+ These methods now accept a string or an integer instead of an
+ IPAddr object as the argument.
+
+* net/smtp
+
+ * Support SSL/TLS.
+
+* openssl
+
+ * New classes
+ * OpenSSL::PKey::EC
+ * OpenSSL::PKey::EC::Group
+ * OpenSSL::PKey::EC::Point
+ * OpenSSL::PKey::PKCS5
+ * OpenSSL::SSL::Session
+
+ * Documentation!
+
+ * Various new methods (see documentation).
+
+ * Remove redundant module namespace in Cipher, Digest, PKCS7, PKCS12.
+ Compatibility classes are provided which will be removed in Ruby 1.9.
+
+* shellwords
+
+ * Add methods for escaping shell-unsafe characters:
+ * Shellwords.join
+ * Shellwords.escape
+ * Array#shelljoin
+ * String#shellescape
+
+ * Add shorthand methods:
+ * Shellwords.split (alias shellwords)
+ * String#shellsplit
+
+* stringio
+
+ * StringIO#getbyte
+ * StringIO#readbyte
+
+ New methods. (aliases for compatibility with 1.9)
+
+ * StringIO#each_char
+ * StringIO#chars
+
+ New methods.
+
+ * StringIO#each
+ * StringIO#each_line
+ * StringIO#each_byte
+
+ Return an enumerator if no block is given.
+
+* tempfile
+
+ * Tempfile.open and Tempfile.new now accept a suffix for the
+ temporary file to be created. To specify a suffix, pass an array
+ of [basename, suffix] as the first argument.
+
+ Tempfile.open(['image', 'jpg']) { |tempfile| ... }
+
+* tmpdir
+
+ * New method:
+
+ * Dir.mktmpdir
+
+* uri
+
+ * added LDAPS scheme.
+ * Change for RFC3986:
+ * FTP
+ * URI('ftp://example.com/foo').path #=> 'foo'
+ * URI('ftp://example.com/%2Ffoo').path #=> '/foo'
+ * URI::FTP.build([nil, 'example.com', nil, '/foo', 'i').to_s #=> 'ftp://example.com/%2Ffoo;type=i'
+ * URI merge
+ * URI('http://a/b/c/d;p?q').merge('?y') == URI('http://a/b/c/d;p?y')
+ * URI('http://a/b/c/d;p?q').merge('/./g') == URI('http://a/g')
+ * URI('http://a/b/c/d;p?q').merge('/../g') == URI('http://a/g')
+ * URI('http://a/b/c/d;p?q').merge('../../../g') == URI('http://a/g')
+ * URI('http://a/b/c/d;p?q').merge('../../../../g') == URI('http://a/g')
+
+* rss
+
+ * 0.1.6 -> 0.2.4
+
+ * Fix image module URI
+
+ * Atom support
+
+ * ITunes module support
+
+ * Slash module support
+
+ * content:encoded with RSS 2.0 support
+
+=== Interpreter Implementation
+
+* passing a block to a Proc [experimental]
+
+ This implementation in current shape is known to be buggy/broken,
+ especially with nested block invocation. Take this as an
+ experimental feature.
+
+* stack trace
+
+ On non-SystemStackError exception, full stack trace is shown.
+
+=== Compatibility issues (excluding feature bug fixes)
+
+* String#slice! had some unintentional bugs and they have been fixed
+ because either they disagreed with documentation or their respective
+ behavior of #slice. Unfortunately, this causes some
+ incompatibilities in the following (somewhat rare) cases.
+
+ * #slice! no longer expands the array when an out-of-boundary value
+ is given.
+
+ # Ruby 1.8.6
+ a = [1,2]
+ a.slice!(4,0) #=> nil
+ a #=> [1,2,nil,nil]
+
+ # Ruby 1.8.7
+ a = [1,2]
+ a.slice!(4,0) #=> nil
+ a #=> [1,2]
+
+ * #slice! no longer raises an exception but returns nil when a
+ negative length or out-of-boundary negative position is given.
+
+ # Ruby 1.8.6
+ a = [1,2]
+ a.slice!(1,-1) #=> (raises IndexError)
+ a.slice!(-5,1) #=> (raises IndexError)
+
+ # Ruby 1.8.7
+ a = [1,2]
+ a.slice!(1,-1) #=> nil
+ a.slice!(-5,1) #=> nil
+
+* String#to_i, String#hex and String#oct no longer accept a sequence
+ of underscores (`__') as part of a number.
+
+ # Ruby 1.8.6
+ '1__0'.to_i #=> 10
+ '1__0'.to_i(2) #=> 2 # 0b10
+ '1__0'.oct #=> 8 # 010
+ '1__0'.hex #=> 16 # 0x10
+
+ # Ruby 1.8.7
+ '1__0'.to_i #=> 1
+ '1__0'.to_i(2) #=> 1
+ '1__0'.oct #=> 1
+ '1__0'.hex #=> 1
+
+ The old behavior was inconsistent with Ruby syntax and considered as
+ a bug.
+
+* date
+
+ * Date.parse
+
+ '##.##.##' (where each '#' is a digit) is now taken as 'YY.MM.DD'
+ instead of 'MM.DD.YY'. While the change may confuse you, you can
+ always use Date.strptime() when you know what you are dealing
+ with.
+
+* stringio
+
+ * StringIO#each_byte
+
+ The return value changed from nil to self. This is what the
+ document says and the same as each_line() does.
+
+* tempfile
+
+ * The file name format has changed. No dots are included by default
+ in temporary file names any more. See above for how to specify a
+ suffix.
+
+* uri
+
+ * See above for details.
+
+== Changes since the 1.8.5 release
+
+=== New platforms/build tools support
+
+* IA64 HP-UX
+
+* Visual C++ 8 SP1
+
+* autoconf 2.6x
+
+=== Global constants
+
+* RUBY_PATCHLEVEL
+
+ New constant since 1.8.5-p1.
+
+=== Library updates (outstanding ones only)
+
+* builtin classes
+
+ * New method: Kernel#instance_variable_defined?
+
+ * New method: Module#class_variable_defined?
+
+ * New feature: Dir::glob() can now take an array of glob patterns.
+
+* date
+
+ * Updated based on date2 4.0.3.
+
+* digest
+
+ * New internal APIs for C and Ruby.
+
+ * Support for autoloading.
+
+ require 'digest'
+
+ # autoloads digest/md5
+ md = Digest::MD5.digest("string")
+
+ * New digest class methods: file
+
+ * New digest instance methods: clone, reset, new, inspect,
+ digest_length (alias size or length), block_length()
+
+ * New library: digest/bubblebabble
+
+ * New function: Digest(name)
+
+* fileutils
+
+ * New option for FileUtils.cp_r(): :remove_destination
+
+* nkf
+
+ * Updated based on nkf as of 2007-01-28.
+
+* thread
+
+ * Replaced with much faster mutex implementation in C. The former
+ implementation, which is slow but considered to be stable, is
+ available with a configure option `--disable-fastthread'.
+
+* tk
+
+ * Updated Tile extension support based on Tile 0.7.8.
+
+ * Support --without-X11 configure option for non-X11 versions of
+ Tcl/Tk (e.g. Tcl/Tk Aqua).
+
+ * New sample script: irbtkw.rbw -- IRB on Ruby/Tk. It has no trouble
+ about STDIN blocking on Windows.
+
+* webrick
+
+ * New method: WEBrick::Cookie.parse_set_cookies()
+
+=== Compatibility issues (excluding feature bug fixes)
+
+* builtin classes
+
+ * String#intern now raises SecurityError when $SAFE level is greater
+ than zero.
+
+* date
+
+ * Time#to_date and Time#to_datetime are added as private methods.
+ They cause name conflict error in ActiveSupport 1.4.1 and prior,
+ which comes with Rails 1.2.2 and prior. Updating ActiveSupport
+ and/or Rails to the latest versions fixes the problem.
+
+* digest
+
+ * The constructor does no longer take an initial string to feed.
+ The following examples show how to migrate:
+
+ # Before
+ md = Digest::MD5.new("string")
+ # After (works with any version)
+ md = Digest::MD5.new.update("string")
+
+ # Before
+ hd = Digest::MD5.new("string").hexdigest
+ # After (works with any version)
+ hd = Digest::MD5.hexdigest("string")
+
+* fileutils
+
+ * A minor implementation change breaks Rake <=0.7.1.
+ Updating Rake to 0.7.2 or higher fixes the problem.
+
+* tk
+
+ * Tk::X_Scrollable (Y_Scrollable) is renamed to Tk::XScrollable
+ (YScrollable). Tk::X_Scrollable (Y_Scrollable) is still available,
+ but it is an alias name.
diff --git a/README b/README
index cf836415ad..1b79781367 100644
--- a/README
+++ b/README
@@ -29,7 +29,7 @@ The Ruby distribution files can be found in the following FTP site:
The latest source code of this version series can be checked out
through SVN with the following command:
- $ svn co http://svn.ruby-lang.org/repos/ruby/branches/ruby_1_8_6/
+ $ svn co http://svn.ruby-lang.org/repos/ruby/branches/ruby_1_8/
The trunk of the Ruby source tree can be checked out with the
following command:
@@ -70,6 +70,10 @@ This is what you need to do to compile and install Ruby:
2. Run ./configure, which will generate config.h and Makefile.
+ Some C compiler flags may be added by default depending on your
+ environment. Specify optflags=.. and warnflags=.. as necessary
+ to override them.
+
3. Edit defines.h if you need. Usually this step will not be needed.
4. Remove comment mark(#) before the module names from ext/Setup (or
diff --git a/README.EXT b/README.EXT
index e5d39911ca..637b19d25b 100644
--- a/README.EXT
+++ b/README.EXT
@@ -8,8 +8,8 @@ In C, variables have types and data do not have types. In contrast,
Ruby variables do not have a static type, and data themselves have
types, so data will need to be converted between the languages.
-Data in Ruby are represented by C type `VALUE'. Each VALUE data has
-its data-type.
+Data in Ruby are represented by the C type `VALUE'. Each VALUE data
+has its data-type.
To retrieve C data from a VALUE, you need to:
@@ -91,26 +91,26 @@ The data for type T_NIL, T_FALSE, T_TRUE are nil, true, false
respectively. They are singletons for the data type.
The T_FIXNUM data is a 31bit length fixed integer (63bit length on
-some machines), which can be convert to a C integer by using the
+some machines), which can be converted to a C integer by using the
FIX2INT() macro. There is also NUM2INT() which converts any Ruby
numbers into C integers. The NUM2INT() macro includes a type check, so
an exception will be raised if the conversion failed. NUM2DBL() can
-be used to retrieve the double float value in same way.
+be used to retrieve the double float value in the same way.
-To get char* from a VALUE, version 1.7 recommend to use new macros
-StringValue() and StringValuePtr(). StringValue(var) replaces var's
-value to the result of "var.to_str()". StringValuePtr(var) does same
-replacement and returns char* representation of var. These macros
-will skip the replacement if var is a String. Notice that the macros
-requires to take only lvalue as their argument, to change the value
-of var in the replacement.
+In version 1.7 or later it is recommended that you use the new macros
+StringValue() and StringValuePtr() to get a char* from a VALUE.
+StringValue(var) replaces var's value with the result of "var.to_str()".
+StringValuePtr(var) does same replacement and returns char*
+representation of var. These macros will skip the replacement if var is
+a String. Notice that the macros take only the lvalue as their
+argument, to change the value of var in place.
-In version 1.6 or earlier, STR2CSTR() was used to do same thing
-but now it is obsoleted in version 1.7 because of STR2CSTR() has
-a risk of dangling pointer problem in to_str() impliclit conversion.
+In version 1.6 or earlier, STR2CSTR() was used to do the same thing
+but now it is deprecated in version 1.7, because STR2CSTR() has a risk
+of a dangling pointer problem in the to_str() impliclit conversion.
Other data types have corresponding C structures, e.g. struct RArray
-for T_ARRAY etc. The VALUE of the type which has corresponding structure
+for T_ARRAY etc. The VALUE of the type which has the corresponding structure
can be cast to retrieve the pointer to the struct. The casting macro
will be of the form RXXXX for each data type; for instance, RARRAY(obj).
See "ruby.h".
@@ -205,7 +205,7 @@ interpreter. Some (not all) of the useful functions are listed below:
rb_ary_unshift(VALUE ary, VALUE val)
Array operations. The first argument to each functions must be an
- array. They may dump core if other types given.
+ array. They may dump core if other types are given.
2. Extending Ruby with C
@@ -244,7 +244,7 @@ To define methods or singleton methods, use these functions:
VALUE (*func)(), int argc)
The `argc' represents the number of the arguments to the C function,
-which must be less than 17. But I believe you don't need that much. :-)
+which must be less than 17. But I doubt you'll need that many.
If `argc' is negative, it specifies the calling sequence, not number of
the arguments.
@@ -272,7 +272,7 @@ private methods:
The other is to define module functions, which are private AND singleton
methods of the module. For example, sqrt is the module function
-defined in Math module. It can be call in the form like:
+defined in Math module. It can be called in the following way:
Math.sqrt(4)
@@ -291,7 +291,7 @@ in the Kernel module, can be defined using:
void rb_define_global_function(const char *name, VALUE (*func)(), int argc)
-To define alias to the method,
+To define an alias for the method,
void rb_define_alias(VALUE module, const char* new, const char* old);
@@ -321,7 +321,7 @@ There are several ways to invoke Ruby's features from C code.
2.2.1 Evaluate Ruby Programs in a String
The easiest way to use Ruby's functionality from a C program is to
-evaluate the string as Ruby program. This function will do the job.
+evaluate the string as Ruby program. This function will do the job:
VALUE rb_eval_string(const char *str)
@@ -434,7 +434,7 @@ The prototypes of the getter and setter functions are as follows:
(*getter)(ID id, void *data, struct global_entry* entry);
(*setter)(VALUE val, ID id, void *data, struct global_entry* entry);
-3.3 Encapsulate C data into Ruby object
+3.3 Encapsulate C data into a Ruby object
To wrap and objectify a C pointer as a Ruby object (so called
DATA), use Data_Wrap_Struct().
@@ -619,7 +619,7 @@ are not exported to the Ruby world. You need to protect them by
If the file named extconf.rb exists, it will be executed to generate
Makefile.
-extconf.rb is the file for check compilation conditions etc. You
+extconf.rb is the file for checking compilation conditions etc. You
need to put
require 'mkmf'
@@ -639,12 +639,12 @@ The value of the variables below will affect the Makefile.
$LDFLAGS: included in LDFLAGS make variable (such as -L)
$objs: list of object file names
-In normal, object files list is automatically generated by searching
-source files, but you need directs them explicitly if any sources will
+Normally, the object files list is automatically generated by searching
+source files, but you must define them explicitly if any sources will
be generated while building.
If a compilation condition is not fulfilled, you should not call
-``create_makefile''. The Makefile will not generated, compilation will
+``create_makefile''. The Makefile will not be generated, compilation will
not be done.
(5) prepare depend (optional)
@@ -654,7 +654,7 @@ check dependencies. You can make this file by invoking
% gcc -MM *.c > depend
-It's no harm. Prepare it.
+It's harmless. Prepare it.
(6) generate Makefile
@@ -662,6 +662,11 @@ Try generating the Makefile by:
ruby extconf.rb
+If the library should be installed under vendor_ruby directory
+instead of site_ruby directory, use --vendor option as follows.
+
+ ruby extconf.rb --vendor
+
You don't need this step if you put the extension library under the ext
directory of the ruby source tree. In that case, compilation of the
interpreter will do this step for you.
@@ -673,12 +678,12 @@ Type
make
to compile your extension. You don't need this step either if you have
-put extension library under the ext directory of the ruby source tree.
+put the extension library under the ext directory of the ruby source tree.
(8) debug
You may need to rb_debug the extension. Extensions can be linked
-statically by the adding directory name in the ext/Setup file so that
+statically by adding the directory name in the ext/Setup file so that
you can inspect the extension with the debugger.
(9) done, now you have the extension library
@@ -843,15 +848,15 @@ it can't be seen from Ruby programs.
void rb_define_readonly_variable(const char *name, VALUE *var)
Defines a read-only global variable. Works just like
-rb_define_variable(), except defined variable is read-only.
+rb_define_variable(), except the defined variable is read-only.
void rb_define_virtual_variable(const char *name,
VALUE (*getter)(), VALUE (*setter)())
Defines a virtual variable, whose behavior is defined by a pair of C
functions. The getter function is called when the variable is
-referred. The setter function is called when the value is set to the
-variable. The prototype for getter/setter functions are:
+referenced. The setter function is called when the variable is set to a
+value. The prototype for getter/setter functions are:
VALUE getter(ID id)
void setter(VALUE val, ID id)
@@ -1011,7 +1016,7 @@ Terminates the interpreter immediately. This function should be
called under the situation caused by the bug in the interpreter. No
exception handling nor ensure execution will be done.
-** Initialize and Starts the Interpreter
+** Initialize and Start the Interpreter
The embedding API functions are below (not needed for extension libraries):
@@ -1031,6 +1036,32 @@ Starts execution of the interpreter.
Specifies the name of the script ($0).
+** Hooks for the Interpreter Events
+
+ void rb_add_event_hook(rb_event_hook_func_t func, rb_event_t events)
+
+Adds a hook function for the specified interpreter events.
+events should be Or'ed value of:
+
+ RUBY_EVENT_LINE
+ RUBY_EVENT_CLASS
+ RUBY_EVENT_END
+ RUBY_EVENT_CALL
+ RUBY_EVENT_RETURN
+ RUBY_EVENT_C_CALL
+ RUBY_EVENT_C_RETURN
+ RUBY_EVENT_RAISE
+ RUBY_EVENT_ALL
+
+The definition of rb_event_hook_func_t is below:
+
+ typedef void (*rb_event_hook_func_t)(rb_event_t event, NODE *node,
+ VALUE self, ID id, VALUE klass)
+
+ int rb_remove_event_hook(rb_event_hook_func_t func)
+
+Removes the specified hook function.
+
Appendix C. Functions Available in extconf.rb
These functions are available in extconf.rb:
@@ -1122,7 +1153,7 @@ Returns an array of the added directories ([include_dir, lib_dir]).
pkg_config(pkg)
-Obtains the information of pkg by pkg-config command. The actual
+Obtains the information for pkg by pkg-config command. The actual
command name can be overriden by --with-pkg-config command line
option.
diff --git a/README.EXT.ja b/README.EXT.ja
index 30c4d520ba..73425c2cdb 100644
--- a/README.EXT.ja
+++ b/README.EXT.ja
@@ -765,6 +765,12 @@ Makefile¤ò¼ÂºÝ¤ËÀ¸À®¤¹¤ë¤¿¤á¤Ë¤Ï
¤È¤·¤Æ¤¯¤À¤µ¤¤¡¥
+site_ruby ¥Ç¥£¥ì¥¯¥È¥ê¤Ç¤Ê¤¯¡¢
+vendor_ruby ¥Ç¥£¥ì¥¯¥È¥ê¤Ë¥¤¥ó¥¹¥È¡¼¥ë¤¹¤ë¾ì¹ç¤Ë¤Ï
+°Ê²¼¤Î¤è¤¦¤Ë --vendor ¥ª¥×¥·¥ç¥ó¤ò²Ã¤¨¤Æ¤¯¤À¤µ¤¤¡¥
+
+ ruby extconf.rb --vendor
+
¥Ç¥£¥ì¥¯¥È¥ê¤òext°Ê²¼¤ËÍѰդ·¤¿¾ì¹ç¤Ë¤ÏRubyÁ´ÂΤÎmake¤Î»þ¤Ë
¼«Æ°Åª¤ËMakefile¤¬À¸À®¤µ¤ì¤Þ¤¹¤Î¤Ç¡¤¤³¤Î¥¹¥Æ¥Ã¥×¤ÏÉÔÍפǤ¹¡¥
diff --git a/README.ja b/README.ja
index df8cfc03f4..71ce4ee12c 100644
--- a/README.ja
+++ b/README.ja
@@ -36,7 +36,7 @@ Ruby¤Ï¥Æ¥­¥¹¥È½èÍý´Ø·¸¤ÎǽÎϤʤɤËÍ¥¤ì¡¤Perl¤ÈƱ¤¸¤¯¤é¤¤¶¯ÎÏ
ËÜ¥Ö¥é¥ó¥Á¤ÎRuby¤ÎºÇ¿·¤Î¥½¡¼¥¹¥³¡¼¥É¤Ï¼¡¤Î¥³¥Þ¥ó¥É¤Ç¼èÆÀ¤Ç¤­¤Þ¤¹¡¥
- $ svn co http://svn.ruby-lang.org/repos/ruby/branches/ruby_1_8_6/
+ $ svn co http://svn.ruby-lang.org/repos/ruby/branches/ruby_1_8/
³«È¯Àèü¤Î¥½¡¼¥¹¥³¡¼¥É¤Ï¼¡¤Î¥³¥Þ¥ó¥É¤Ç¼èÆÀ¤Ç¤­¤Þ¤¹¡¥
@@ -92,6 +92,10 @@ Ruby³ÈÄ¥¥â¥¸¥å¡¼¥ë¤Ë¤Ä¤¤¤ÆÏ䷹礦ruby-ext¥á¡¼¥ê¥ó¥°¥ê¥¹¥È¤È
2. configure¤ò¼Â¹Ô¤·¤ÆMakefile¤Ê¤É¤òÀ¸À®¤¹¤ë
+ ´Ä¶­¤Ë¤è¤Ã¤Æ¤Ï¥Ç¥Õ¥©¥ë¥È¤ÎC¥³¥ó¥Ñ¥¤¥éÍÑ¥ª¥×¥·¥ç¥ó¤¬ÉÕ¤­
+ ¤Þ¤¹¡¥configure¥ª¥×¥·¥ç¥ó¤Ç optflags=.. warnflags=.. Åù
+ ¤Ç¾å½ñ¤­¤Ç¤­¤Þ¤¹¡¥
+
3. (ɬÍפʤé¤Ð)defines.h¤òÊÔ½¸¤¹¤ë
¿ʬ¡¤É¬Í×̵¤¤¤È»×¤¤¤Þ¤¹¡¥
diff --git a/array.c b/array.c
index baae2706e5..89f74d01ff 100644
--- a/array.c
+++ b/array.c
@@ -2,8 +2,8 @@
array.c -
- $Author: akr $
- $Date: 2006/06/24 14:53:36 $
+ $Author$
+ $Date$
created at: Fri Aug 6 09:46:12 JST 1993
Copyright (C) 1993-2003 Yukihiro Matsumoto
@@ -20,6 +20,7 @@ VALUE rb_cArray;
static ID id_cmp;
#define ARY_DEFAULT_SIZE 16
+#define ARY_MAX_SIZE (LONG_MAX / sizeof(VALUE))
void
rb_mem_clear(mem, size)
@@ -120,7 +121,7 @@ ary_new(klass, len)
if (len < 0) {
rb_raise(rb_eArgError, "negative array size (or size too big)");
}
- if (len > 0 && len * sizeof(VALUE) <= len) {
+ if (len > ARY_MAX_SIZE) {
rb_raise(rb_eArgError, "array size too big");
}
if (len == 0) len++;
@@ -195,6 +196,27 @@ rb_ary_new4(n, elts)
return ary;
}
+static VALUE
+ary_make_shared(ary)
+ VALUE ary;
+{
+ if (!FL_TEST(ary, ELTS_SHARED)) {
+ NEWOBJ(shared, struct RArray);
+ OBJSETUP(shared, rb_cArray, T_ARRAY);
+
+ shared->len = RARRAY(ary)->len;
+ shared->ptr = RARRAY(ary)->ptr;
+ shared->aux.capa = RARRAY(ary)->aux.capa;
+ RARRAY(ary)->aux.shared = (VALUE)shared;
+ FL_SET(ary, ELTS_SHARED);
+ OBJ_FREEZE(shared);
+ return (VALUE)shared;
+ }
+ else {
+ return RARRAY(ary)->aux.shared;
+ }
+}
+
VALUE
rb_assoc_new(car, cdr)
VALUE car, cdr;
@@ -293,7 +315,7 @@ rb_ary_initialize(argc, argv, ary)
if (len < 0) {
rb_raise(rb_eArgError, "negative array size");
}
- if (len > 0 && len * (long)sizeof(VALUE) <= len) {
+ if (len > ARY_MAX_SIZE) {
rb_raise(rb_eArgError, "array size too big");
}
if (len > RARRAY(ary)->aux.capa) {
@@ -358,6 +380,9 @@ rb_ary_store(ary, idx, val)
idx - RARRAY(ary)->len);
}
}
+ else if (idx >= ARY_MAX_SIZE) {
+ rb_raise(rb_eIndexError, "index %ld too big", idx);
+ }
rb_ary_modify(ary);
if (idx >= RARRAY(ary)->aux.capa) {
@@ -366,10 +391,10 @@ rb_ary_store(ary, idx, val)
if (new_capa < ARY_DEFAULT_SIZE) {
new_capa = ARY_DEFAULT_SIZE;
}
- new_capa += idx;
- if (new_capa * (long)sizeof(VALUE) <= new_capa) {
- rb_raise(rb_eArgError, "index too big");
+ if (new_capa >= ARY_MAX_SIZE - idx) {
+ new_capa = (ARY_MAX_SIZE - idx) / 2;
}
+ new_capa += idx;
REALLOC_N(RARRAY(ary)->ptr, VALUE, new_capa);
RARRAY(ary)->aux.capa = new_capa;
}
@@ -384,6 +409,50 @@ rb_ary_store(ary, idx, val)
RARRAY(ary)->ptr[idx] = val;
}
+static VALUE
+ary_shared_array(klass, ary)
+ VALUE klass;
+ VALUE ary;
+{
+ VALUE val = ary_alloc(klass);
+
+ ary_make_shared(ary);
+ RARRAY(val)->ptr = RARRAY(ary)->ptr;
+ RARRAY(val)->len = RARRAY(ary)->len;
+ RARRAY(val)->aux.shared = RARRAY(ary)->aux.shared;
+ FL_SET(val, ELTS_SHARED);
+ return val;
+}
+
+static VALUE
+ary_shared_first(argc, argv, ary, last)
+ int argc;
+ VALUE *argv;
+ VALUE ary;
+ int last;
+{
+ VALUE nv, result;
+ long n;
+ long offset = 0;
+
+ rb_scan_args(argc, argv, "1", &nv);
+ n = NUM2LONG(nv);
+ if (n > RARRAY(ary)->len) {
+ n = RARRAY(ary)->len;
+ }
+ else if (n < 0) {
+ rb_raise(rb_eArgError, "negative array size");
+ }
+ if (last) {
+ offset = RARRAY(ary)->len - n;
+ }
+ result = ary_shared_array(rb_cArray, ary);
+ RARRAY(result)->ptr += offset;
+ RARRAY(result)->len = n;
+
+ return result;
+}
+
/*
* call-seq:
* array << obj -> array
@@ -431,18 +500,6 @@ rb_ary_push_m(argc, argv, ary)
return ary;
}
-/*
- * call-seq:
- * array.pop -> obj or nil
- *
- * Removes the last element from <i>self</i> and returns it, or
- * <code>nil</code> if the array is empty.
- *
- * a = [ "a", "m", "z" ]
- * a.pop #=> "z"
- * a #=> ["a", "m"]
- */
-
VALUE
rb_ary_pop(ary)
VALUE ary;
@@ -450,7 +507,7 @@ rb_ary_pop(ary)
rb_ary_modify_check(ary);
if (RARRAY(ary)->len == 0) return Qnil;
if (!FL_TEST(ary, ELTS_SHARED) &&
- RARRAY(ary)->len * 2 < RARRAY(ary)->aux.capa &&
+ RARRAY(ary)->len * 3 < RARRAY(ary)->aux.capa &&
RARRAY(ary)->aux.capa > ARY_DEFAULT_SIZE) {
RARRAY(ary)->aux.capa = RARRAY(ary)->len * 2;
REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa);
@@ -458,54 +515,112 @@ rb_ary_pop(ary)
return RARRAY(ary)->ptr[--RARRAY(ary)->len];
}
+/*
+ * call-seq:
+ * array.pop -> obj or nil
+ * array.pop(n) -> array
+ *
+ * Removes the last element from <i>self</i> and returns it, or
+ * <code>nil</code> if the array is empty.
+ *
+ * If a number _n_ is given, returns an array of the last n elements
+ * (or less) just like <code>array.slice!(-n, n)</code> does.
+ *
+ * a = [ "a", "b", "c", "d" ]
+ * a.pop #=> "d"
+ * a.pop(2) #=> ["b", "c"]
+ * a #=> ["a"]
+ */
+
static VALUE
-ary_make_shared(ary)
+rb_ary_pop_m(argc, argv, ary)
+ int argc;
+ VALUE *argv;
VALUE ary;
{
- if (!FL_TEST(ary, ELTS_SHARED)) {
- NEWOBJ(shared, struct RArray);
- OBJSETUP(shared, rb_cArray, T_ARRAY);
+ VALUE result;
- shared->len = RARRAY(ary)->len;
- shared->ptr = RARRAY(ary)->ptr;
- shared->aux.capa = RARRAY(ary)->aux.capa;
- RARRAY(ary)->aux.shared = (VALUE)shared;
- FL_SET(ary, ELTS_SHARED);
- OBJ_FREEZE(shared);
- return (VALUE)shared;
+ if (argc == 0) {
+ return rb_ary_pop(ary);
}
- else {
- return RARRAY(ary)->aux.shared;
+
+ rb_ary_modify_check(ary);
+ result = ary_shared_first(argc, argv, ary, Qtrue);
+ RARRAY(ary)->len -= RARRAY(result)->len;
+ return result;
+}
+
+VALUE
+rb_ary_shift(ary)
+ VALUE ary;
+{
+ VALUE top;
+
+ rb_ary_modify_check(ary);
+ if (RARRAY(ary)->len == 0) return Qnil;
+ top = RARRAY(ary)->ptr[0];
+ if (!FL_TEST(ary, ELTS_SHARED)) {
+ if (RARRAY(ary)->len < ARY_DEFAULT_SIZE) {
+ MEMMOVE(RARRAY(ary)->ptr, RARRAY(ary)->ptr+1, VALUE, RARRAY(ary)->len-1);
+ RARRAY(ary)->len--;
+ return top;
+ }
+ RARRAY(ary)->ptr[0] = Qnil;
+ ary_make_shared(ary);
}
+ RARRAY(ary)->ptr++; /* shift ptr */
+ RARRAY(ary)->len--;
+
+ return top;
}
/*
* call-seq:
- * array.shift -> obj or nil
+ * array.shift -> obj or nil
+ * array.shift(n) -> array
*
* Returns the first element of <i>self</i> and removes it (shifting all
* other elements down by one). Returns <code>nil</code> if the array
* is empty.
+ *
+ * If a number _n_ is given, returns an array of the first n elements
+ * (or less) just like <code>array.slice!(0, n)</code> does.
*
* args = [ "-m", "-q", "filename" ]
- * args.shift #=> "-m"
- * args #=> ["-q", "filename"]
+ * args.shift #=> "-m"
+ * args #=> ["-q", "filename"]
+ *
+ * args = [ "-m", "-q", "filename" ]
+ * args.shift(2) #=> ["-m", "-q"]
+ * args #=> ["filename"]
*/
-VALUE
-rb_ary_shift(ary)
+static VALUE
+rb_ary_shift_m(argc, argv, ary)
+ int argc;
+ VALUE *argv;
VALUE ary;
{
- VALUE top;
+ VALUE result;
+ long n;
+
+ if (argc == 0) {
+ return rb_ary_shift(ary);
+ }
rb_ary_modify_check(ary);
- if (RARRAY(ary)->len == 0) return Qnil;
- top = RARRAY(ary)->ptr[0];
- ary_make_shared(ary);
- RARRAY(ary)->ptr++; /* shift ptr */
- RARRAY(ary)->len--;
+ result = ary_shared_first(argc, argv, ary, Qfalse);
+ n = RARRAY(result)->len;
+ if (FL_TEST(ary, ELTS_SHARED)) {
+ RARRAY(ary)->ptr += n;
+ RARRAY(ary)->len -= n;
+ }
+ else {
+ MEMMOVE(RARRAY(ary)->ptr, RARRAY(ary)->ptr+n, VALUE, RARRAY(ary)->len-n);
+ RARRAY(ary)->len -= n;
+ }
- return top;
+ return result;
}
VALUE
@@ -740,17 +855,7 @@ rb_ary_first(argc, argv, ary)
return RARRAY(ary)->ptr[0];
}
else {
- VALUE nv, result;
- long n, i;
-
- rb_scan_args(argc, argv, "01", &nv);
- n = NUM2LONG(nv);
- if (n > RARRAY(ary)->len) n = RARRAY(ary)->len;
- result = rb_ary_new2(n);
- for (i=0; i<n; i++) {
- rb_ary_push(result, RARRAY(ary)->ptr[i]);
- }
- return result;
+ return ary_shared_first(argc, argv, ary, Qfalse);
}
}
@@ -776,17 +881,7 @@ rb_ary_last(argc, argv, ary)
return RARRAY(ary)->ptr[RARRAY(ary)->len-1];
}
else {
- VALUE nv, result;
- long n, i;
-
- rb_scan_args(argc, argv, "01", &nv);
- n = NUM2LONG(nv);
- if (n > RARRAY(ary)->len) n = RARRAY(ary)->len;
- result = rb_ary_new2(n);
- for (i=RARRAY(ary)->len-n; n--; i++) {
- rb_ary_push(result, RARRAY(ary)->ptr[i]);
- }
- return result;
+ return ary_shared_first(argc, argv, ary, Qtrue);
}
}
@@ -842,24 +937,41 @@ rb_ary_fetch(argc, argv, ary)
/*
* call-seq:
- * array.index(obj) -> int or nil
+ * array.index(obj) -> int or nil
+ * array.index {|item| block} -> int or nil
*
- * Returns the index of the first object in <i>self</i> such that is
- * <code>==</code> to <i>obj</i>. Returns <code>nil</code> if
- * no match is found.
+ * Returns the index of the first object in <i>self</i> such that is
+ * <code>==</code> to <i>obj</i>. If a block is given instead of an
+ * argument, returns first object for which <em>block</em> is true.
+ * Returns <code>nil</code> if no match is found.
*
* a = [ "a", "b", "c" ]
- * a.index("b") #=> 1
- * a.index("z") #=> nil
+ * a.index("b") #=> 1
+ * a.index("z") #=> nil
+ * a.index{|x|x=="b"} #=> 1
+ *
+ * This is an alias of <code>#find_index</code>.
*/
static VALUE
-rb_ary_index(ary, val)
+rb_ary_index(argc, argv, ary)
+ int argc;
+ VALUE *argv;
VALUE ary;
- VALUE val;
{
+ VALUE val;
long i;
+ if (argc == 0) {
+ RETURN_ENUMERATOR(ary, 0, 0);
+ for (i=0; i<RARRAY(ary)->len; i++) {
+ if (RTEST(rb_yield(RARRAY(ary)->ptr[i]))) {
+ return LONG2NUM(i);
+ }
+ }
+ return Qnil;
+ }
+ rb_scan_args(argc, argv, "01", &val);
for (i=0; i<RARRAY(ary)->len; i++) {
if (rb_equal(RARRAY(ary)->ptr[i], val))
return LONG2NUM(i);
@@ -871,29 +983,44 @@ rb_ary_index(ary, val)
* call-seq:
* array.rindex(obj) -> int or nil
*
- * Returns the index of the last object in <i>array</i>
- * <code>==</code> to <i>obj</i>. Returns <code>nil</code> if
- * no match is found.
+ * Returns the index of the last object in <i>array</i>
+ * <code>==</code> to <i>obj</i>. If a block is given instead of an
+ * argument, returns first object for which <em>block</em> is
+ * true. Returns <code>nil</code> if no match is found.
*
* a = [ "a", "b", "b", "b", "c" ]
- * a.rindex("b") #=> 3
- * a.rindex("z") #=> nil
+ * a.rindex("b") #=> 3
+ * a.rindex("z") #=> nil
+ * a.rindex{|x|x=="b"} #=> 3
*/
static VALUE
-rb_ary_rindex(ary, val)
+rb_ary_rindex(argc, argv, ary)
+ int argc;
+ VALUE *argv;
VALUE ary;
- VALUE val;
{
+ VALUE val;
long i = RARRAY(ary)->len;
+ if (argc == 0) {
+ RETURN_ENUMERATOR(ary, 0, 0);
+ while (i--) {
+ if (RTEST(rb_yield(RARRAY(ary)->ptr[i])))
+ return LONG2NUM(i);
+ if (i > RARRAY(ary)->len) {
+ i = RARRAY(ary)->len;
+ }
+ }
+ return Qnil;
+ }
+ rb_scan_args(argc, argv, "01", &val);
while (i--) {
+ if (rb_equal(RARRAY(ary)->ptr[i], val))
+ return LONG2NUM(i);
if (i > RARRAY(ary)->len) {
i = RARRAY(ary)->len;
- continue;
}
- if (rb_equal(RARRAY(ary)->ptr[i], val))
- return LONG2NUM(i);
}
return Qnil;
}
@@ -967,6 +1094,9 @@ rb_ary_splice(ary, beg, len, rpl)
rb_ary_modify(ary);
if (beg >= RARRAY(ary)->len) {
+ if (beg > ARY_MAX_SIZE - rlen) {
+ rb_raise(rb_eIndexError, "index %ld too big", beg);
+ }
len = beg + rlen;
if (len >= RARRAY(ary)->aux.capa) {
REALLOC_N(RARRAY(ary)->ptr, VALUE, len);
@@ -1126,6 +1256,7 @@ rb_ary_each(ary)
{
long i;
+ RETURN_ENUMERATOR(ary, 0, 0);
for (i=0; i<RARRAY(ary)->len; i++) {
rb_yield(RARRAY(ary)->ptr[i]);
}
@@ -1153,6 +1284,7 @@ rb_ary_each_index(ary)
{
long i;
+ RETURN_ENUMERATOR(ary, 0, 0);
for (i=0; i<RARRAY(ary)->len; i++) {
rb_yield(LONG2NUM(i));
}
@@ -1178,8 +1310,10 @@ static VALUE
rb_ary_reverse_each(ary)
VALUE ary;
{
- long len = RARRAY(ary)->len;
+ long len;
+ RETURN_ENUMERATOR(ary, 0, 0);
+ len = RARRAY(ary)->len;
while (len--) {
rb_yield(RARRAY(ary)->ptr[len]);
if (RARRAY(ary)->len < len) {
@@ -1271,7 +1405,7 @@ rb_ary_join(ary, sep)
case T_STRING:
break;
case T_ARRAY:
- if (rb_inspecting_p(tmp)) {
+ if (tmp == ary || rb_inspecting_p(tmp)) {
tmp = rb_str_new2("[...]");
}
else {
@@ -1726,6 +1860,7 @@ rb_ary_collect_bang(ary)
{
long i;
+ RETURN_ENUMERATOR(ary, 0, 0);
rb_ary_modify(ary);
for (i = 0; i < RARRAY(ary)->len; i++) {
rb_ary_store(ary, i, rb_yield(RARRAY(ary)->ptr[i]));
@@ -1810,6 +1945,7 @@ rb_ary_select(ary)
VALUE result;
long i;
+ RETURN_ENUMERATOR(ary, 0, 0);
result = rb_ary_new2(RARRAY(ary)->len);
for (i = 0; i < RARRAY(ary)->len; i++) {
if (RTEST(rb_yield(RARRAY(ary)->ptr[i]))) {
@@ -1949,22 +2085,42 @@ rb_ary_slice_bang(argc, argv, ary)
VALUE ary;
{
VALUE arg1, arg2;
- long pos, len;
+ long pos, len, orig_len;
+ rb_ary_modify_check(ary);
if (rb_scan_args(argc, argv, "11", &arg1, &arg2) == 2) {
pos = NUM2LONG(arg1);
len = NUM2LONG(arg2);
delete_pos_len:
+ if (len < 0) return Qnil;
+ orig_len = RARRAY_LEN(ary);
if (pos < 0) {
- pos = RARRAY(ary)->len + pos;
+ pos += orig_len;
+ if (pos < 0) return Qnil;
+ }
+ else if (orig_len < pos) return Qnil;
+ if (orig_len < pos + len) {
+ len = orig_len - pos;
}
- arg2 = rb_ary_subseq(ary, pos, len);
- rb_ary_splice(ary, pos, len, Qnil); /* Qnil/rb_ary_new2(0) */
+ if (len == 0) return rb_ary_new2(0);
+ arg2 = rb_ary_new4(len, RARRAY_PTR(ary)+pos);
+ RBASIC(arg2)->klass = rb_obj_class(ary);
+ rb_ary_splice(ary, pos, len, Qnil); /* Qundef in 1.9 */
return arg2;
}
- if (!FIXNUM_P(arg1) && rb_range_beg_len(arg1, &pos, &len, RARRAY(ary)->len, 1)) {
- goto delete_pos_len;
+ if (!FIXNUM_P(arg1)) {
+ switch (rb_range_beg_len(arg1, &pos, &len, RARRAY_LEN(ary), 0)) {
+ case Qtrue:
+ /* valid range */
+ goto delete_pos_len;
+ case Qnil:
+ /* invalid range */
+ return Qnil;
+ default:
+ /* not a range */
+ break;
+ }
}
return rb_ary_delete_at(ary, NUM2LONG(arg1));
@@ -1986,6 +2142,7 @@ rb_ary_reject_bang(ary)
{
long i1, i2;
+ RETURN_ENUMERATOR(ary, 0, 0);
rb_ary_modify(ary);
for (i1 = i2 = 0; i1 < RARRAY(ary)->len; i1++) {
VALUE v = RARRAY(ary)->ptr[i1];
@@ -2014,6 +2171,7 @@ static VALUE
rb_ary_reject(ary)
VALUE ary;
{
+ RETURN_ENUMERATOR(ary, 0, 0);
ary = rb_ary_dup(ary);
rb_ary_reject_bang(ary);
return ary;
@@ -2034,6 +2192,7 @@ static VALUE
rb_ary_delete_if(ary)
VALUE ary;
{
+ RETURN_ENUMERATOR(ary, 0, 0);
rb_ary_reject_bang(ary);
return ary;
}
@@ -2257,10 +2416,13 @@ rb_ary_fill(argc, argv, ary)
break;
}
rb_ary_modify(ary);
- end = beg + len;
- if (end < 0) {
+ if (len < 0) {
+ return ary;
+ }
+ if (beg >= ARY_MAX_SIZE || len > ARY_MAX_SIZE - beg) {
rb_raise(rb_eArgError, "argument too big");
}
+ end = beg + len;
if (end > RARRAY(ary)->len) {
if (end >= RARRAY(ary)->aux.capa) {
REALLOC_N(RARRAY(ary)->ptr, VALUE, end);
@@ -2370,7 +2532,7 @@ rb_ary_times(ary, times)
if (len < 0) {
rb_raise(rb_eArgError, "negative argument");
}
- if (LONG_MAX/len < RARRAY(ary)->len) {
+ if (ARY_MAX_SIZE/len < RARRAY(ary)->len) {
rb_raise(rb_eArgError, "argument too big");
}
len *= RARRAY(ary)->len;
@@ -2414,9 +2576,8 @@ rb_ary_assoc(ary, key)
VALUE v;
for (i = 0; i < RARRAY(ary)->len; ++i) {
- v = RARRAY(ary)->ptr[i];
- if (TYPE(v) == T_ARRAY &&
- RARRAY(v)->len > 0 &&
+ v = rb_check_array_type(RARRAY(ary)->ptr[i]);
+ if (!NIL_P(v) && RARRAY(v)->len > 0 &&
rb_equal(RARRAY(v)->ptr[0], key))
return v;
}
@@ -2454,6 +2615,22 @@ rb_ary_rassoc(ary, value)
return Qnil;
}
+static VALUE recursive_equal _((VALUE, VALUE, int));
+static VALUE
+recursive_equal(ary1, ary2, recur)
+ VALUE ary1, ary2;
+ int recur;
+{
+ long i;
+
+ if (recur) return Qfalse;
+ for (i=0; i<RARRAY(ary1)->len; i++) {
+ if (!rb_equal(rb_ary_elt(ary1, i), rb_ary_elt(ary2, i)))
+ return Qfalse;
+ }
+ return Qtrue;
+}
+
/*
* call-seq:
* array == other_array -> bool
@@ -2472,8 +2649,6 @@ static VALUE
rb_ary_equal(ary1, ary2)
VALUE ary1, ary2;
{
- long i;
-
if (ary1 == ary2) return Qtrue;
if (TYPE(ary2) != T_ARRAY) {
if (!rb_respond_to(ary2, rb_intern("to_ary"))) {
@@ -2482,8 +2657,20 @@ rb_ary_equal(ary1, ary2)
return rb_equal(ary2, ary1);
}
if (RARRAY(ary1)->len != RARRAY(ary2)->len) return Qfalse;
+ return rb_exec_recursive(recursive_equal, ary1, ary2);
+}
+
+static VALUE recursive_eql _((VALUE, VALUE, int));
+static VALUE
+recursive_eql(ary1, ary2, recur)
+ VALUE ary1, ary2;
+ int recur;
+{
+ long i;
+
+ if (recur) return Qfalse;
for (i=0; i<RARRAY(ary1)->len; i++) {
- if (!rb_equal(rb_ary_elt(ary1, i), rb_ary_elt(ary2, i)))
+ if (!rb_eql(rb_ary_elt(ary1, i), rb_ary_elt(ary2, i)))
return Qfalse;
}
return Qtrue;
@@ -2501,33 +2688,26 @@ static VALUE
rb_ary_eql(ary1, ary2)
VALUE ary1, ary2;
{
- long i;
-
if (ary1 == ary2) return Qtrue;
if (TYPE(ary2) != T_ARRAY) return Qfalse;
if (RARRAY(ary1)->len != RARRAY(ary2)->len) return Qfalse;
- for (i=0; i<RARRAY(ary1)->len; i++) {
- if (!rb_eql(rb_ary_elt(ary1, i), rb_ary_elt(ary2, i)))
- return Qfalse;
- }
- return Qtrue;
+ return rb_exec_recursive(recursive_eql, ary1, ary2);
}
-/*
- * call-seq:
- * array.hash -> fixnum
- *
- * Compute a hash-code for this array. Two arrays with the same content
- * will have the same hash code (and will compare using <code>eql?</code>).
- */
-
+static VALUE recursive_hash _((VALUE, VALUE, int));
static VALUE
-rb_ary_hash(ary)
+recursive_hash(ary, dummy, recur)
VALUE ary;
+ VALUE dummy;
+ int recur;
{
long i, h;
VALUE n;
+ if (recur) {
+ return LONG2FIX(0);
+ }
+
h = RARRAY(ary)->len;
for (i=0; i<RARRAY(ary)->len; i++) {
h = (h << 1) | (h<0 ? 1 : 0);
@@ -2539,6 +2719,21 @@ rb_ary_hash(ary)
/*
* call-seq:
+ * array.hash -> fixnum
+ *
+ * Compute a hash-code for this array. Two arrays with the same content
+ * will have the same hash code (and will compare using <code>eql?</code>).
+ */
+
+static VALUE
+rb_ary_hash(ary)
+ VALUE ary;
+{
+ return rb_exec_recursive(recursive_hash, ary, 0);
+}
+
+/*
+ * call-seq:
* array.include?(obj) -> true or false
*
* Returns <code>true</code> if the given object is present in
@@ -2566,6 +2761,29 @@ rb_ary_includes(ary, item)
}
+static VALUE recursive_cmp _((VALUE, VALUE, int));
+static VALUE
+recursive_cmp(ary1, ary2, recur)
+ VALUE ary1;
+ VALUE ary2;
+ int recur;
+{
+ long i, len;
+
+ if (recur) return Qnil;
+ len = RARRAY(ary1)->len;
+ if (len > RARRAY(ary2)->len) {
+ len = RARRAY(ary2)->len;
+ }
+ for (i=0; i<len; i++) {
+ VALUE v = rb_funcall(rb_ary_elt(ary1, i), id_cmp, 1, rb_ary_elt(ary2, i));
+ if (v != INT2FIX(0)) {
+ return v;
+ }
+ }
+ return Qundef;
+}
+
/*
* call-seq:
* array <=> other_array -> -1, 0, +1
@@ -2590,19 +2808,13 @@ VALUE
rb_ary_cmp(ary1, ary2)
VALUE ary1, ary2;
{
- long i, len;
+ long len;
+ VALUE v;
ary2 = to_ary(ary2);
- len = RARRAY(ary1)->len;
- if (len > RARRAY(ary2)->len) {
- len = RARRAY(ary2)->len;
- }
- for (i=0; i<len; i++) {
- VALUE v = rb_funcall(rb_ary_elt(ary1, i), id_cmp, 1, rb_ary_elt(ary2, i));
- if (v != INT2FIX(0)) {
- return v;
- }
- }
+ if (ary1 == ary2) return INT2FIX(0);
+ v = rb_exec_recursive(recursive_cmp, ary1, ary2);
+ if (v != Qundef) return v;
len = RARRAY(ary1)->len - RARRAY(ary2)->len;
if (len == 0) return INT2FIX(0);
if (len > 0) return INT2FIX(1);
@@ -2842,6 +3054,7 @@ rb_ary_compact(ary)
* array.nitems -> int
*
* Returns the number of non-<code>nil</code> elements in _self_.
+ *
* May be zero.
*
* [ 1, nil, 3, nil, 5 ].nitems #=> 3
@@ -2854,110 +3067,691 @@ rb_ary_nitems(ary)
long n = 0;
VALUE *p, *pend;
- p = RARRAY(ary)->ptr;
- pend = p + RARRAY(ary)->len;
-
- while (p < pend) {
+ for (p = RARRAY(ary)->ptr, pend = p + RARRAY(ary)->len; p < pend; p++) {
if (!NIL_P(*p)) n++;
- p++;
}
return LONG2NUM(n);
}
-static long
-flatten(ary, idx, ary2, memo)
+/*
+ * call-seq:
+ * array.count -> int
+ * array.count(obj) -> int
+ * array.count { |item| block } -> int
+ *
+ * Returns the number of elements. If an argument is given, counts
+ * the number of elements which equals to <i>obj</i>. If a block is
+ * given, counts the number of elements yielding a true value.
+ *
+ * ary = [1, 2, 4, 2]
+ * ary.count # => 4
+ * ary.count(2) # => 2
+ * ary.count{|x|x%2==0} # => 3
+ *
+ */
+
+static VALUE
+rb_ary_count(argc, argv, ary)
+ int argc;
+ VALUE *argv;
VALUE ary;
- long idx;
- VALUE ary2, memo;
{
- VALUE id;
- long i = idx;
- long n, lim = idx + RARRAY(ary2)->len;
+ long n = 0;
+
+ if (argc == 0) {
+ VALUE *p, *pend;
- id = rb_obj_id(ary2);
- if (rb_ary_includes(memo, id)) {
- rb_raise(rb_eArgError, "tried to flatten recursive array");
+ if (!rb_block_given_p())
+ return LONG2NUM(RARRAY_LEN(ary));
+
+ for (p = RARRAY_PTR(ary), pend = p + RARRAY_LEN(ary); p < pend; p++) {
+ if (RTEST(rb_yield(*p))) n++;
+ }
}
- rb_ary_push(memo, id);
- rb_ary_splice(ary, idx, 1, ary2);
- while (i < lim) {
- VALUE tmp;
+ else {
+ VALUE obj, *p, *pend;
- tmp = rb_check_array_type(rb_ary_elt(ary, i));
- if (!NIL_P(tmp)) {
- n = flatten(ary, i, tmp, memo);
- i += n; lim += n;
+ rb_scan_args(argc, argv, "1", &obj);
+ if (rb_block_given_p()) {
+ rb_warn("given block not used");
+ }
+ for (p = RARRAY_PTR(ary), pend = p + RARRAY_LEN(ary); p < pend; p++) {
+ if (rb_equal(*p, obj)) n++;
+ }
+ }
+
+ return LONG2NUM(n);
+}
+
+static VALUE
+flatten(ary, level, modified)
+ VALUE ary;
+ int level;
+ int *modified;
+{
+ long i = 0;
+ VALUE stack, result, tmp, elt;
+ st_table *memo;
+ st_data_t id;
+
+ stack = ary_new(0, ARY_DEFAULT_SIZE);
+ result = ary_new(0, RARRAY_LEN(ary));
+ memo = st_init_numtable();
+ st_insert(memo, (st_data_t)ary, (st_data_t)Qtrue);
+ *modified = 0;
+
+ while (1) {
+ while (i < RARRAY(ary)->len) {
+ elt = RARRAY(ary)->ptr[i++];
+ tmp = rb_check_array_type(elt);
+ if (RBASIC(result)->klass) {
+ rb_raise(rb_eRuntimeError, "flatten reentered");
+ }
+ if (NIL_P(tmp) || (level >= 0 && RARRAY(stack)->len / 2 >= level)) {
+ rb_ary_push(result, elt);
+ }
+ else {
+ *modified = 1;
+ id = (st_data_t)tmp;
+ if (st_lookup(memo, id, 0)) {
+ st_free_table(memo);
+ rb_raise(rb_eArgError, "tried to flatten recursive array");
+ }
+ st_insert(memo, id, (st_data_t)Qtrue);
+ rb_ary_push(stack, ary);
+ rb_ary_push(stack, LONG2NUM(i));
+ ary = tmp;
+ i = 0;
+ }
+ }
+ if (RARRAY(stack)->len == 0) {
+ break;
}
- i++;
+ id = (st_data_t)ary;
+ st_delete(memo, &id, 0);
+ tmp = rb_ary_pop(stack);
+ i = NUM2LONG(tmp);
+ ary = rb_ary_pop(stack);
}
- rb_ary_pop(memo);
- return lim - idx - 1; /* returns number of increased items */
+ st_free_table(memo);
+
+ RBASIC(result)->klass = rb_class_of(ary);
+ return result;
}
/*
* call-seq:
* array.flatten! -> array or nil
+ * array.flatten!(level) -> array or nil
*
* Flattens _self_ in place.
* Returns <code>nil</code> if no modifications were made (i.e.,
- * <i>array</i> contains no subarrays.)
+ * <i>array</i> contains no subarrays.) If the optional <i>level</i>
+ * argument determines the level of recursion to flatten.
*
* a = [ 1, 2, [3, [4, 5] ] ]
* a.flatten! #=> [1, 2, 3, 4, 5]
* a.flatten! #=> nil
* a #=> [1, 2, 3, 4, 5]
+ * a = [ 1, 2, [3, [4, 5] ] ]
+ * a.flatten!(1) #=> [1, 2, 3, [4, 5]]
*/
static VALUE
-rb_ary_flatten_bang(ary)
+rb_ary_flatten_bang(argc, argv, ary)
+ int argc;
+ VALUE *argv;
VALUE ary;
{
- long i = 0;
- int mod = 0;
- VALUE memo = Qnil;
+ int mod = 0, level = -1;
+ VALUE result, lv;
- while (i<RARRAY(ary)->len) {
- VALUE ary2 = RARRAY(ary)->ptr[i];
- VALUE tmp;
+ rb_scan_args(argc, argv, "01", &lv);
+ if (!NIL_P(lv)) level = NUM2INT(lv);
+ if (level == 0) return ary;
- tmp = rb_check_array_type(ary2);
- if (!NIL_P(tmp)) {
- if (NIL_P(memo)) {
- memo = rb_ary_new();
- }
- i += flatten(ary, i, tmp, memo);
- mod = 1;
- }
- i++;
- }
+ result = flatten(ary, level, &mod);
if (mod == 0) return Qnil;
+ rb_ary_replace(ary, result);
+
return ary;
}
/*
* call-seq:
* array.flatten -> an_array
+ * array.flatten(level) -> an_array
*
* Returns a new array that is a one-dimensional flattening of this
* array (recursively). That is, for every element that is an array,
- * extract its elements into the new array.
+ * extract its elements into the new array. If the optional
+ * <i>level</i> argument determines the level of recursion to flatten.
*
* s = [ 1, 2, 3 ] #=> [1, 2, 3]
* t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]]
* a = [ s, t, 9, 10 ] #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10]
- * a.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10
+ * a.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ * a = [ 1, 2, [3, [4, 5] ] ]
+ * a.flatten(1) #=> [1, 2, 3, [4, 5]]
*/
static VALUE
-rb_ary_flatten(ary)
+rb_ary_flatten(argc, argv, ary)
+ int argc;
+ VALUE *argv;
VALUE ary;
{
+ int mod = 0, level = -1;
+ VALUE result, lv;
+
+ rb_scan_args(argc, argv, "01", &lv);
+ if (!NIL_P(lv)) level = NUM2INT(lv);
+ if (level == 0) return ary;
+
+ result = flatten(ary, level, &mod);
+ if (OBJ_TAINTED(ary)) OBJ_TAINT(result);
+
+ return result;
+}
+
+/*
+ * call-seq:
+ * array.shuffle! -> array or nil
+ *
+ * Shuffles elements in _self_ in place.
+ */
+
+
+static VALUE
+rb_ary_shuffle_bang(ary)
+ VALUE ary;
+{
+ long i = RARRAY(ary)->len;
+
+ rb_ary_modify(ary);
+ while (i) {
+ long j = rb_genrand_real()*i;
+ VALUE tmp = RARRAY(ary)->ptr[--i];
+ RARRAY(ary)->ptr[i] = RARRAY(ary)->ptr[j];
+ RARRAY(ary)->ptr[j] = tmp;
+ }
+ return ary;
+}
+
+
+/*
+ * call-seq:
+ * array.shuffle -> an_array
+ *
+ * Returns a new array with elements of this array shuffled.
+ *
+ * a = [ 1, 2, 3 ] #=> [1, 2, 3]
+ * a.shuffle #=> [2, 3, 1]
+ */
+
+static VALUE
+rb_ary_shuffle(VALUE ary)
+{
ary = rb_ary_dup(ary);
- rb_ary_flatten_bang(ary);
+ rb_ary_shuffle_bang(ary);
+ return ary;
+}
+
+
+/*
+ * call-seq:
+ * array.choice -> obj
+ *
+ * Choose a random element from an array.
+ */
+
+
+static VALUE
+rb_ary_choice(ary)
+ VALUE ary;
+{
+ long i, j;
+
+ i = RARRAY(ary)->len;
+ if (i == 0) return Qnil;
+ j = rb_genrand_real()*i;
+ return RARRAY(ary)->ptr[j];
+}
+
+
+/*
+ * call-seq:
+ * ary.cycle {|obj| block }
+ * ary.cycle(n) {|obj| block }
+ *
+ * Calls <i>block</i> for each element repeatedly _n_ times or
+ * forever if none or nil is given. If a non-positive number is
+ * given or the array is empty, does nothing. Returns nil if the
+ * loop has finished without getting interrupted.
+ *
+ * a = ["a", "b", "c"]
+ * a.cycle {|x| puts x } # print, a, b, c, a, b, c,.. forever.
+ * a.cycle(2) {|x| puts x } # print, a, b, c, a, b, c.
+ *
+ */
+
+static VALUE
+rb_ary_cycle(argc, argv, ary)
+ int argc;
+ VALUE *argv;
+ VALUE ary;
+{
+ long n, i;
+ VALUE nv = Qnil;
+
+ rb_scan_args(argc, argv, "01", &nv);
+
+ RETURN_ENUMERATOR(ary, argc, argv);
+ if (NIL_P(nv)) {
+ n = -1;
+ }
+ else {
+ n = NUM2LONG(nv);
+ if (n <= 0) return Qnil;
+ }
+
+ while (RARRAY(ary)->len > 0 && (n < 0 || 0 < n--)) {
+ for (i=0; i<RARRAY(ary)->len; i++) {
+ rb_yield(RARRAY(ary)->ptr[i]);
+ }
+ }
+ return Qnil;
+}
+
+#define tmpbuf(n, size) rb_str_tmp_new((n)*(size))
+
+/*
+ * Recursively compute permutations of r elements of the set [0..n-1].
+ * When we have a complete permutation of array indexes, copy the values
+ * at those indexes into a new array and yield that array.
+ *
+ * n: the size of the set
+ * r: the number of elements in each permutation
+ * p: the array (of size r) that we're filling in
+ * index: what index we're filling in now
+ * used: an array of booleans: whether a given index is already used
+ * values: the Ruby array that holds the actual values to permute
+ */
+static void
+permute0(n, r, p, index, used, values)
+ long n, r, *p, index;
+ int *used;
+ VALUE values;
+{
+ long i,j;
+ for (i = 0; i < n; i++) {
+ if (used[i] == 0) {
+ p[index] = i;
+ if (index < r-1) { /* if not done yet */
+ used[i] = 1; /* mark index used */
+ permute0(n, r, p, index+1, /* recurse */
+ used, values);
+ used[i] = 0; /* index unused */
+ }
+ else {
+ /* We have a complete permutation of array indexes */
+ /* Build a ruby array of the corresponding values */
+ /* And yield it to the associated block */
+ VALUE result = rb_ary_new2(r);
+ VALUE *result_array = RARRAY(result)->ptr;
+ const VALUE *values_array = RARRAY(values)->ptr;
+
+ for (j = 0; j < r; j++) result_array[j] = values_array[p[j]];
+ RARRAY(result)->len = r;
+ rb_yield(result);
+ }
+ }
+ }
+}
+
+/*
+ * call-seq:
+ * ary.permutation { |p| block } -> array
+ * ary.permutation -> enumerator
+ * ary.permutation(n) { |p| block } -> array
+ * ary.permutation(n) -> enumerator
+ *
+ * When invoked with a block, yield all permutations of length <i>n</i>
+ * of the elements of <i>ary</i>, then return the array itself.
+ * If <i>n</i> is not specified, yield all permutations of all elements.
+ * The implementation makes no guarantees about the order in which
+ * the permutations are yielded.
+ *
+ * When invoked without a block, return an enumerator object instead.
+ *
+ * Examples:
+ *
+ * a = [1, 2, 3]
+ * a.permutation.to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
+ * a.permutation(1).to_a #=> [[1],[2],[3]]
+ * a.permutation(2).to_a #=> [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]]
+ * a.permutation(3).to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
+ * a.permutation(0).to_a #=> [[]] # one permutation of length 0
+ * a.permutation(4).to_a #=> [] # no permutations of length 4
+ */
+
+static VALUE
+rb_ary_permutation(argc, argv, ary)
+ int argc;
+ VALUE *argv;
+ VALUE ary;
+{
+ VALUE num;
+ long r, n, i;
+
+ n = RARRAY(ary)->len; /* Array length */
+ RETURN_ENUMERATOR(ary, argc, argv); /* Return enumerator if no block */
+ rb_scan_args(argc, argv, "01", &num);
+ r = NIL_P(num) ? n : NUM2LONG(num); /* Permutation size from argument */
+
+ if (r < 0 || n < r) {
+ /* no permutations: yield nothing */
+ }
+ else if (r == 0) { /* exactly one permutation: the zero-length array */
+ rb_yield(rb_ary_new2(0));
+ }
+ else if (r == 1) { /* this is a special, easy case */
+ for (i = 0; i < RARRAY(ary)->len; i++) {
+ rb_yield(rb_ary_new3(1, RARRAY(ary)->ptr[i]));
+ }
+ }
+ else { /* this is the general case */
+ volatile VALUE t0 = tmpbuf(n,sizeof(long));
+ long *p = (long*)RSTRING(t0)->ptr;
+ volatile VALUE t1 = tmpbuf(n,sizeof(int));
+ int *used = (int*)RSTRING(t1)->ptr;
+ VALUE ary0 = ary_make_shared(ary); /* private defensive copy of ary */
+
+ for (i = 0; i < n; i++) used[i] = 0; /* initialize array */
+
+ permute0(n, r, p, 0, used, ary0); /* compute and yield permutations */
+ RB_GC_GUARD(t0);
+ RB_GC_GUARD(t1);
+ }
return ary;
}
+static long
+combi_len(n, k)
+ long n, k;
+{
+ long i, val = 1;
+
+ if (k*2 > n) k = n-k;
+ if (k == 0) return 1;
+ if (k < 0) return 0;
+ val = 1;
+ for (i=1; i <= k; i++,n--) {
+ long m = val;
+ val *= n;
+ if (val < m) {
+ rb_raise(rb_eRangeError, "too big for combination");
+ }
+ val /= i;
+ }
+ return val;
+}
+
+/*
+ * call-seq:
+ * ary.combination(n) { |c| block } -> ary
+ * ary.combination(n) -> enumerator
+ *
+ * When invoked with a block, yields all combinations of length <i>n</i>
+ * of elements from <i>ary</i> and then returns <i>ary</i> itself.
+ * The implementation makes no guarantees about the order in which
+ * the combinations are yielded.
+ *
+ * When invoked without a block, returns an enumerator object instead.
+ *
+ * Examples:
+ *
+ * a = [1, 2, 3, 4]
+ * a.combination(1).to_a #=> [[1],[2],[3],[4]]
+ * a.combination(2).to_a #=> [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
+ * a.combination(3).to_a #=> [[1,2,3],[1,2,4],[1,3,4],[2,3,4]]
+ * a.combination(4).to_a #=> [[1,2,3,4]]
+ * a.combination(0).to_a #=> [[]] # one combination of length 0
+ * a.combination(5).to_a #=> [] # no combinations of length 5
+ *
+ */
+
+static VALUE
+rb_ary_combination(ary, num)
+ VALUE ary;
+ VALUE num;
+{
+ long n, i, len;
+
+ n = NUM2LONG(num);
+ RETURN_ENUMERATOR(ary, 1, &num);
+ len = RARRAY(ary)->len;
+ if (n < 0 || len < n) {
+ /* yield nothing */
+ }
+ else if (n == 0) {
+ rb_yield(rb_ary_new2(0));
+ }
+ else if (n == 1) {
+ for (i = 0; i < len; i++) {
+ rb_yield(rb_ary_new3(1, RARRAY(ary)->ptr[i]));
+ }
+ }
+ else {
+ volatile VALUE t0 = tmpbuf(n+1, sizeof(long));
+ long *stack = (long*)RSTRING(t0)->ptr;
+ long nlen = combi_len(len, n);
+ volatile VALUE cc = rb_ary_new2(n);
+ VALUE *chosen = RARRAY(cc)->ptr;
+ long lev = 0;
+
+ RBASIC(cc)->klass = 0;
+ MEMZERO(stack, long, n);
+ stack[0] = -1;
+ for (i = 0; i < nlen; i++) {
+ chosen[lev] = RARRAY(ary)->ptr[stack[lev+1]];
+ for (lev++; lev < n; lev++) {
+ chosen[lev] = RARRAY(ary)->ptr[stack[lev+1] = stack[lev]+1];
+ }
+ rb_yield(rb_ary_new4(n, chosen));
+ do {
+ stack[lev--]++;
+ } while (lev && (stack[lev+1]+n == len+lev+1));
+ }
+ }
+ return ary;
+}
+
+/*
+ * call-seq:
+ * ary.product(other_ary, ...)
+ *
+ * Returns an array of all combinations of elements from all arrays.
+ * The length of the returned array is the product of the length
+ * of ary and the argument arrays
+ *
+ * [1,2,3].product([4,5]) # => [[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]]
+ * [1,2].product([1,2]) # => [[1,1],[1,2],[2,1],[2,2]]
+ * [1,2].product([3,4],[5,6]) # => [[1,3,5],[1,3,6],[1,4,5],[1,4,6],
+ * # [2,3,5],[2,3,6],[2,4,5],[2,4,6]]
+ * [1,2].product() # => [[1],[2]]
+ * [1,2].product([]) # => []
+ */
+
+static VALUE
+rb_ary_product(argc, argv, ary)
+ int argc;
+ VALUE *argv;
+ VALUE ary;
+{
+ int n = argc+1; /* How many arrays we're operating on */
+ volatile VALUE t0 = tmpbuf(n, sizeof(VALUE));
+ volatile VALUE t1 = tmpbuf(n, sizeof(int));
+ VALUE *arrays = (VALUE*)RSTRING(t0)->ptr; /* The arrays we're computing the product of */
+ int *counters = (int*)RSTRING(t1)->ptr; /* The current position in each one */
+ VALUE result; /* The array we'll be returning */
+ long i,j;
+ long resultlen = 1;
+
+ RBASIC(t0)->klass = 0;
+ RBASIC(t1)->klass = 0;
+
+ /* initialize the arrays of arrays */
+ arrays[0] = ary;
+ for (i = 1; i < n; i++) arrays[i] = to_ary(argv[i-1]);
+
+ /* initialize the counters for the arrays */
+ for (i = 0; i < n; i++) counters[i] = 0;
+
+ /* Compute the length of the result array; return [] if any is empty */
+ for (i = 0; i < n; i++) {
+ long k = RARRAY(arrays[i])->len, l = resultlen;
+ if (k == 0) return rb_ary_new2(0);
+ resultlen *= k;
+ if (resultlen < k || resultlen < l || resultlen / k != l) {
+ rb_raise(rb_eRangeError, "too big to product");
+ }
+ }
+
+ /* Otherwise, allocate and fill in an array of results */
+ result = rb_ary_new2(resultlen);
+ for (i = 0; i < resultlen; i++) {
+ int m;
+ /* fill in one subarray */
+ VALUE subarray = rb_ary_new2(n);
+ for (j = 0; j < n; j++) {
+ rb_ary_push(subarray, rb_ary_entry(arrays[j], counters[j]));
+ }
+
+ /* put it on the result array */
+ rb_ary_push(result, subarray);
+
+ /*
+ * Increment the last counter. If it overflows, reset to 0
+ * and increment the one before it.
+ */
+ m = n-1;
+ counters[m]++;
+ while (m > 0 && counters[m] == RARRAY(arrays[m])->len) {
+ counters[m] = 0;
+ m--;
+ counters[m]++;
+ }
+ }
+
+ return result;
+}
+
+/*
+ * call-seq:
+ * ary.take(n) => array
+ *
+ * Returns first n elements from <i>ary</i>.
+ *
+ * a = [1, 2, 3, 4, 5, 0]
+ * a.take(3) # => [1, 2, 3]
+ *
+ */
+
+static VALUE
+rb_ary_take(obj, n)
+ VALUE obj;
+ VALUE n;
+{
+ long len = NUM2LONG(n);
+ if (len < 0) {
+ rb_raise(rb_eArgError, "attempt to take negative size");
+ }
+
+ return rb_ary_subseq(obj, 0, len);
+}
+
+/*
+ * call-seq:
+ * ary.take_while {|arr| block } => array
+ *
+ * Passes elements to the block until the block returns nil or false,
+ * then stops iterating and returns an array of all prior elements.
+ *
+ * a = [1, 2, 3, 4, 5, 0]
+ * a.take_while {|i| i < 3 } # => [1, 2]
+ *
+ */
+
+static VALUE
+rb_ary_take_while(ary)
+ VALUE ary;
+{
+ long i;
+
+ RETURN_ENUMERATOR(ary, 0, 0);
+ for (i = 0; i < RARRAY(ary)->len; i++) {
+ if (!RTEST(rb_yield(RARRAY(ary)->ptr[i]))) break;
+ }
+ return rb_ary_take(ary, LONG2FIX(i));
+}
+
+/*
+ * call-seq:
+ * ary.drop(n) => array
+ *
+ * Drops first n elements from <i>ary</i>, and returns rest elements
+ * in an array.
+ *
+ * a = [1, 2, 3, 4, 5, 0]
+ * a.drop(3) # => [4, 5, 0]
+ *
+ */
+
+static VALUE
+rb_ary_drop(ary, n)
+ VALUE ary;
+ VALUE n;
+{
+ VALUE result;
+ long pos = NUM2LONG(n);
+ if (pos < 0) {
+ rb_raise(rb_eArgError, "attempt to drop negative size");
+ }
+
+ result = rb_ary_subseq(ary, pos, RARRAY(ary)->len);
+ if (result == Qnil) result = rb_ary_new();
+ return result;
+}
+
+/*
+ * call-seq:
+ * ary.drop_while {|arr| block } => array
+ *
+ * Drops elements up to, but not including, the first element for
+ * which the block returns nil or false and returns an array
+ * containing the remaining elements.
+ *
+ * a = [1, 2, 3, 4, 5, 0]
+ * a.drop_while {|i| i < 3 } # => [3, 4, 5, 0]
+ *
+ */
+
+static VALUE
+rb_ary_drop_while(ary)
+ VALUE ary;
+{
+ long i;
+
+ RETURN_ENUMERATOR(ary, 0, 0);
+ for (i = 0; i < RARRAY(ary)->len; i++) {
+ if (!RTEST(rb_yield(RARRAY(ary)->ptr[i]))) break;
+ }
+ return rb_ary_drop(ary, LONG2FIX(i));
+}
+
+
/* Arrays are ordered, integer-indexed collections of any object.
* Array indexing starts at 0, as in C or Java. A negative index is
@@ -2996,8 +3790,8 @@ Init_Array()
rb_define_method(rb_cArray, "concat", rb_ary_concat, 1);
rb_define_method(rb_cArray, "<<", rb_ary_push, 1);
rb_define_method(rb_cArray, "push", rb_ary_push_m, -1);
- rb_define_method(rb_cArray, "pop", rb_ary_pop, 0);
- rb_define_method(rb_cArray, "shift", rb_ary_shift, 0);
+ rb_define_method(rb_cArray, "pop", rb_ary_pop_m, -1);
+ rb_define_method(rb_cArray, "shift", rb_ary_shift_m, -1);
rb_define_method(rb_cArray, "unshift", rb_ary_unshift_m, -1);
rb_define_method(rb_cArray, "insert", rb_ary_insert, -1);
rb_define_method(rb_cArray, "each", rb_ary_each, 0);
@@ -3006,8 +3800,9 @@ Init_Array()
rb_define_method(rb_cArray, "length", rb_ary_length, 0);
rb_define_alias(rb_cArray, "size", "length");
rb_define_method(rb_cArray, "empty?", rb_ary_empty_p, 0);
- rb_define_method(rb_cArray, "index", rb_ary_index, 1);
- rb_define_method(rb_cArray, "rindex", rb_ary_rindex, 1);
+ rb_define_method(rb_cArray, "find_index", rb_ary_index, -1);
+ rb_define_method(rb_cArray, "index", rb_ary_index, -1);
+ rb_define_method(rb_cArray, "rindex", rb_ary_rindex, -1);
rb_define_method(rb_cArray, "indexes", rb_ary_indexes, -1);
rb_define_method(rb_cArray, "indices", rb_ary_indexes, -1);
rb_define_method(rb_cArray, "join", rb_ary_join_m, -1);
@@ -3051,9 +3846,22 @@ Init_Array()
rb_define_method(rb_cArray, "uniq!", rb_ary_uniq_bang, 0);
rb_define_method(rb_cArray, "compact", rb_ary_compact, 0);
rb_define_method(rb_cArray, "compact!", rb_ary_compact_bang, 0);
- rb_define_method(rb_cArray, "flatten", rb_ary_flatten, 0);
- rb_define_method(rb_cArray, "flatten!", rb_ary_flatten_bang, 0);
+ rb_define_method(rb_cArray, "flatten", rb_ary_flatten, -1);
+ rb_define_method(rb_cArray, "flatten!", rb_ary_flatten_bang, -1);
rb_define_method(rb_cArray, "nitems", rb_ary_nitems, 0);
+ rb_define_method(rb_cArray, "count", rb_ary_count, -1);
+ rb_define_method(rb_cArray, "shuffle!", rb_ary_shuffle_bang, 0);
+ rb_define_method(rb_cArray, "shuffle", rb_ary_shuffle, 0);
+ rb_define_method(rb_cArray, "choice", rb_ary_choice, 0);
+ rb_define_method(rb_cArray, "cycle", rb_ary_cycle, -1);
+ rb_define_method(rb_cArray, "permutation", rb_ary_permutation, -1);
+ rb_define_method(rb_cArray, "combination", rb_ary_combination, 1);
+ rb_define_method(rb_cArray, "product", rb_ary_product, -1);
+
+ rb_define_method(rb_cArray, "take", rb_ary_take, 1);
+ rb_define_method(rb_cArray, "take_while", rb_ary_take_while, 0);
+ rb_define_method(rb_cArray, "drop", rb_ary_drop, 1);
+ rb_define_method(rb_cArray, "drop_while", rb_ary_drop_while, 0);
id_cmp = rb_intern("<=>");
inspect_key = rb_intern("__inspect_key__");
diff --git a/bcc32/Makefile.sub b/bcc32/Makefile.sub
index de7a2beeb8..713b5c69df 100644
--- a/bcc32/Makefile.sub
+++ b/bcc32/Makefile.sub
@@ -4,8 +4,12 @@ SHELL = $(COMSPEC)
MKFILES = Makefile
#### Start of system configuration section. ####
+!ifndef OS
OS = bccwin32
-RT = $(OS)
+!endif
+!if !defined(RT)
+!error RT not defined. Retry from configure pass.
+!endif
## variables may be overridden by $(compile_dir)/Makefile
!ifndef srcdir
@@ -137,7 +141,7 @@ STACK = 0x2000000
XCFLAGS = -DRUBY_EXPORT -I. -I$(srcdir) -I$(srcdir)/missing
-ARFLAGS = /a
+ARFLAGS = /a /p32
LD = ilink32 -q -Gn
LDSHARED = $(LD)
XLDFLAGS = -Tpe c0x32.obj
@@ -153,8 +157,8 @@ EXEEXT = .exe
PROGRAM=$(RUBY_INSTALL_NAME)$(EXEEXT)
WPROGRAM=$(RUBYW_INSTALL_NAME)$(EXEEXT)
RUBYDEF = $(RUBY_SO_NAME).def
-MINIRUBY = .\miniruby$(EXEEXT)
-RUNRUBY = .\ruby$(EXEEXT) "$(srcdir)/runruby.rb" --extout="$(EXTOUT)" --
+MINIRUBY = .\miniruby$(EXEEXT) -I$(srcdir)/lib $(MINIRUBYOPT)
+RUNRUBY = .\$(PROGRAM) "$(srcdir)/runruby.rb" --extout="$(EXTOUT)" --
ORGLIBPATH = $(LIB)
@@ -169,6 +173,8 @@ PREP = miniruby$(EXEEXT)
OBJEXT = obj
+INSTALLED_LIST= .installed.list
+
WINMAINOBJ = winmain.$(OBJEXT)
MINIOBJS = dmydln.$(OBJEXT)
@@ -195,7 +201,13 @@ rubyw: $(WPROGRAM)
!include $(srcdir)/common.mk
-PHONY: Makefile
+$(MKFILES): $(srcdir)/bcc32/Makefile.sub $(srcdir)/bcc32/configure.bat $(srcdir)/bcc32/setup.mak
+ $(COMSPEC) /C $(srcdir:/=\)\bcc32\configure.bat $(configure_args)
+ @echo $(MKFILES) should be updated, re-run $(MAKE).
+ @$(MAKE) > nul -q -f &&|
+PHONY: nul
+ @exit
+|
CONFIG_H = ./.config.h.time
@@ -251,6 +263,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/bcc32/Makefile.sub
\#define HAVE_STRTOD 1
\#define HAVE_STRTOL 1
\#define HAVE_STRTOUL 1
+\#define HAVE_VSNPRINTF 1
\#define HAVE_ISNAN 1
\#define HAVE_FINITE 1
\#define HAVE_HYPOT 1
@@ -270,6 +283,9 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/bcc32/Makefile.sub
\#define RSHIFT(x,y) ((x)>>(int)y)
\#define FILE_COUNT level
\#define FILE_READPTR curp
+\#define RUBY_SETJMP(env) _setjmp(env)
+\#define RUBY_LONGJMP(env,val) longjmp(env,val)
+\#define RUBY_JMP_BUF jmp_buf
\#define inline __inline
\#define NEED_IO_SEEK_BETWEEN_RW 1
\#define STACK_GROW_DIRECTION -1
@@ -278,9 +294,12 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/bcc32/Makefile.sub
\#define RUBY_LIB "/lib/ruby/$(MAJOR).$(MINOR)"
\#define RUBY_SITE_LIB "/lib/ruby/site_ruby"
\#define RUBY_SITE_LIB2 "/lib/ruby/site_ruby/$(MAJOR).$(MINOR)"
+\#define RUBY_VENDOR_LIB "/lib/ruby/vendor_ruby"
+\#define RUBY_VENDOR_LIB2 "/lib/ruby/vendor_ruby/$(MAJOR).$(MINOR)"
\#define RUBY_PLATFORM "$(ARCH)-$(OS)"
\#define RUBY_ARCHLIB "/lib/ruby/$(MAJOR).$(MINOR)/$(ARCH)-$(OS)"
\#define RUBY_SITE_ARCHLIB "/lib/ruby/site_ruby/$(MAJOR).$(MINOR)/$(ARCH)-$(OS)"
+\#define RUBY_VENDOR_ARCHLIB "/lib/ruby/vendor_ruby/$(MAJOR).$(MINOR)/$(ARCH)-$(OS)"
|
@exit > $@
@@ -334,11 +353,8 @@ s,@RANLIB@,,;t t
s,@AR@,$(AR),;t t
s,@ARFLAGS@,$(ARFLAGS) ,;t t
s,@LN_S@,$(LN_S),;t t
-s,@SET_MAKE@,$(SET_MAKE),;t t
+s,@SET_MAKE@,MFLAGS = -$$(MAKEFLAGS),;t t
s,@CP@,copy > nul,;t t
-s,@INSTALL@,copy > nul,;t t
-s,@INSTALL_PROG@,$$(INSTALL),;t t
-s,@INSTALL_DATA@,$$(INSTALL),;t t
s,@LIBOBJS@, acosh.obj crypt.obj erf.obj win32.obj,;t t
s,@ALLOCA@,$(ALLOCA),;t t
s,@DEFAULT_KCODE@,$(DEFAULT_KCODE),;t t
@@ -396,6 +412,7 @@ s,@EXPORT_PREFIX@,_,;t t
s,@arch@,$(ARCH)-$(OS),;t t
s,@sitearch@,$(ARCH)-$(OS),;t t
s,@sitedir@,$${prefix}/lib/ruby/site_ruby,;t t
+s,@vendordir@,$${prefix}/lib/ruby/vendor_ruby,;t t
s,@configure_args@,--enable-shared $(configure_args),;t t
s,@configure_input@,$$configure_input,;t t
s,@srcdir@,$(srcdir),;t t
@@ -421,6 +438,7 @@ $(LIBRUBY_A): $(OBJS) $(DMYEXT)
$(LIBRUBY_SO): $(LIBRUBY_A) $(DLDOBJS) $(RUBYDEF) $(RUBY_SO_NAME).res
@echo $(DLDOBJS)
+ @$(PRE_LIBRUBY_UPDATE)
$(LIBRUBY_LDSHARED) $(LIBRUBY_DLDFLAGS) $(DLDOBJS:/=\),$(LIBRUBY_SO),nul,$(LIBRUBY_A) $(LIBS),$(RUBYDEF),$(RUBY_SO_NAME).res
$(LIBRUBY): $(LIBRUBY_SO)
@@ -435,19 +453,60 @@ $(RUBY_INSTALL_NAME).rc $(RUBYW_INSTALL_NAME).rc $(RUBY_SO_NAME).rc: rbconfig.rb
-so_name=$(RUBY_SO_NAME) \
. $(icondirs) $(srcdir)/win32
-post-install-ext::
- $(MINIRUBY) -I$(srcdir)lib -rrbconfig -rfileutils \
- -e "FileUtils.rm_f(Dir[ARGV[0]+Config::CONFIG['archdir']+'/**/*.tds'])" "$(DESTDIR:\=/)"
+post-install-bin::
+ @$(NULLCMD)
+post-install-lib::
+ @$(NULLCMD)
+post-install-ext-comm::
+ @$(NULLCMD)
+post-install-ext-arch::
+ @$(NULLCMD)
+post-install-man::
+ @$(NULLCMD)
+post-install-doc::
+ @$(NULLCMD)
clean-local::
- @$(RM) ext\extinit.c ext\extinit.$(OBJEXT) *.tds *.il? $(RUBY_SO_NAME).lib
+ @$(RM) $(WINMAINOBJ) ext\extinit.c ext\extinit.$(OBJEXT) *.tds *.il? $(RUBY_SO_NAME).lib
@$(RM) $(RUBY_INSTALL_NAME).res $(RUBYW_INSTALL_NAME).res $(RUBY_SO_NAME).res
+ @$(RM) *.map *.pdb *.ilk *.exp $(RUBYDEF)
distclean-local::
@$(RM) ext\config.cache $(RBCONFIG:/=\)
- @$(RM) *.map *.pdb *.ilk *.exp $(RUBYDEF)
@$(RM) $(RUBY_INSTALL_NAME).rc $(RUBYW_INSTALL_NAME).rc $(RUBY_SO_NAME).rc
+update-rubyspec:
+ @echo SPEC_EXISTS=0 > $@.mk
+ @if exist $(srcdir:/=\)\rubyspec\nul echo SPEC_EXISTS=1 >> $@.mk
+ @type >> $@.mk &&|
+$()update-rubyspec:
+$() @del $@.mk
+$()!if $$(SPEC_EXISTS)
+$() cd $(srcdir:/=\)\rubyspec\mspec
+$() git pull
+$() cd ..\spec\rubyspec
+$() git pull
+$()!else
+$() git clone $(MSPEC_GIT_URL) $(srcdir)/rubyspec/mspec
+$() git clone $(RUBYSPEC_GIT_URL) $(srcdir)/rubyspec/spec/rubyspec
+$()!endif
+|
+ @$(MAKE) -$(MAKEFLAGS)$(MFLAGS) -f $@.mk
+
+test-rubyspec:
+ @echo SPEC_EXISTS=0 > $@.mk
+ @if exist $(srcdir:/=\)\rubyspec\nul echo SPEC_EXISTS=1 >> $@.mk
+ @type >> $@.mk &&|
+$()test-rubyspec:
+$()!if $$(SPEC_EXISTS)
+$() $(RUNRUBY) $(srcdir)/rubyspec/mspec/bin/mspec -r$(srcdir)/ext/purelib.rb $(srcdir)/rubyspec/spec/rubyspec/$(MAJOR).$(MINOR)
+$()!else
+$() @echo No rubyspec here. put rubyspec to srcdir first.
+$() @cd $(srcdir:/=\)\rubyspec
+$()!endif
+|
+ @$(MAKE) -$(MAKEFLAGS) -f $@.mk
+
ext/extinit.obj: ext/extinit.c $(SETUP)
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -o$@ -c ext/extinit.c
diff --git a/bcc32/configure.bat b/bcc32/configure.bat
index 123a3f23c8..95575cbc60 100755
--- a/bcc32/configure.bat
+++ b/bcc32/configure.bat
@@ -6,70 +6,110 @@
echo> ~tmp~.mak ####
echo>> ~tmp~.mak conf = %0
echo>> ~tmp~.mak $(conf:\=/): nul
-echo>> ~tmp~.mak @del ~tmp~.mak
+echo>> ~tmp~.mak @del ~setup~.mak
echo>> ~tmp~.mak @-$(MAKE) -l$(MAKEFLAGS) -f $(@D)setup.mak \
+if exist pathlist.tmp del pathlist.tmp
+if exist confargs.mk del confargs.mk
:loop
if "%1" == "" goto :end
if "%1" == "--prefix" goto :prefix
+if "%1" == "prefix" goto :prefix
if "%1" == "--srcdir" goto :srcdir
if "%1" == "srcdir" goto :srcdir
if "%1" == "--target" goto :target
if "%1" == "target" goto :target
if "%1" == "--with-static-linked-ext" goto :extstatic
if "%1" == "--program-suffix" goto :suffix
-if "%1" == "--program-name" goto :progname
+if "%1" == "RUBY_SUFFIX" goto :suffix
+if "%1" == "--program-name" goto :installname
+if "%1" == "--install-name" goto :installname
+if "%1" == "RUBY_INSTALL_NAME" goto :installname
+if "%1" == "--so-name" goto :soname
+if "%1" == "RUBY_SO_NAME" goto :soname
if "%1" == "--enable-install-doc" goto :enable-rdoc
if "%1" == "--disable-install-doc" goto :disable-rdoc
if "%1" == "--extout" goto :extout
+if "%1" == "EXTOUT" goto :extout
+if "%1" == "--path" goto :path
if "%1" == "-h" goto :help
if "%1" == "--help" goto :help
- echo>> ~tmp~.mak "%1" \
+ echo>>confargs.tmp %1 \
shift
goto :loop
:srcdir
- echo>> ~tmp~.mak -D"srcdir=%2" \
+ echo>> ~tmp~.mak -Dsrcdir=%2 \
+ echo>>confargs.tmp --srcdir=%2 \
shift
shift
goto :loop
:prefix
- echo>> ~tmp~.mak -D"prefix=%2" \
+ echo>> ~tmp~.mak -Dprefix=%2 \
+ echo>>confargs.tmp %1=%2 \
shift
shift
goto :loop
:suffix
- echo>> ~tmp~.mak -D"RUBY_SUFFIX=%2" \
+ echo>>confargs.mk !ifndef RUBY_SUFFIX
+ echo>>confargs.mk RUBY_SUFFIX = %2
+ echo>>confargs.mk !endif
+ echo>>confargs.tmp %1=%2 \
shift
shift
goto :loop
:installname
- echo>> ~tmp~.mak -D"RUBY_INSTALL_NAME=%2" \
+ echo>>confargs.mk !ifndef RUBY_INSTALL_NAME
+ echo>>confargs.mk RUBY_INSTALL_NAME = %2
+ echo>>confargs.mk !endif
+ echo>>confargs.tmp %1=%2 \
shift
shift
goto :loop
:soname
- echo>> ~tmp~.mak -D"RUBY_SO_NAME=%2" \
+ echo>>confargs.mk !ifndef RUBY_SO_NAME
+ echo>>confargs.mk RUBY_SO_NAME = %2
+ echo>>confargs.mk !endif
+ echo>>confargs.tmp %1=%2 \
shift
shift
goto :loop
:target
- echo>> ~tmp~.mak "%2" \
+ echo>> ~tmp~.mak %2 \
+ echo>>confargs.tmp --target=%2 \
shift
shift
goto :loop
:extstatic
- echo>> ~tmp~.mak -D"EXTSTATIC=static" \
+ echo>>confargs.mk !ifndef EXTSTATIC
+ echo>>confargs.mk EXTSTATIC = static
+ echo>>confargs.mk !endif
+ echo>>confargs.tmp %1 \
shift
goto :loop
:enable-rdoc
- echo>> ~tmp~.mak -D"RDOCTARGET=install-doc" \
+ echo>>confargs.mk !ifndef RDOCTARGET
+ echo>>confargs.mk RDOCTARGET = install-doc
+ echo>>confargs.mk !endif
+ echo>>confargs.tmp %1 \
shift
goto :loop
:disable-rdoc
- echo>> ~tmp~.mak -D"RDOCTARGET=install-nodoc" \
+ echo>>confargs.mk !ifndef RDOCTARGET
+ echo>>confargs.mk RDOCTARGET = install-nodoc
+ echo>>confargs.mk !endif
+ echo>>confargs.tmp %1 \
shift
goto :loop
:extout
- echo>> ~tmp~.mak "EXTOUT=%2" \
+ echo>>confargs.mk !ifndef EXTOUT
+ echo>>confargs.mk EXTOUT = %2
+ echo>>confargs.mk !endif
+ echo>>confargs.tmp %1=%2 \
+ shift
+ shift
+goto :loop
+:path
+ echo>>pathlist.tmp %2;\
+ echo>>confargs.tmp %1=%2 \
shift
shift
goto :loop
@@ -83,10 +123,30 @@ goto :loop
echo --target=TARGET configure for TARGET [i386-bccwin32]
echo Optional Package:
echo --with-static-linked-ext link external modules statically
- echo --enable-install-doc install rdoc indexes during install
+ echo --disable-install-doc install rdoc indexes during install
+ del *.tmp
del ~tmp~.mak
goto :exit
:end
-echo>> ~tmp~.mak bcc32dir="$(@D)"
-make -s -f ~tmp~.mak
+echo>> ~tmp~.mak -Dbcc32dir=$(@D)
+if not exist confargs.tmp goto :noconfargs
+ echo>>confargs.mk configure_args = \
+ type>>confargs.mk confargs.tmp
+ echo.>>confargs.mk
+ echo>>confargs.mk ####
+:noconfargs
+if not exist pathlist.tmp goto :nopathlist
+ echo>>confargs.mk pathlist = \
+ type>>confargs.mk pathlist.tmp
+ echo.>>confargs.mk
+ echo>>confargs.mk ####
+ echo>>confargs.mk PATH = $(pathlist:;=/bin;)$(PATH)
+ echo>>confargs.mk INCLUDE = $(pathlist:;=/include;)
+ echo>>confargs.mk LIB = $(pathlist:;=/lib;)
+:nopathlist
+if exist confargs.mk copy confargs.mk ~setup~.mak > nul
+type>>~setup~.mak ~tmp~.mak
+del *.tmp > nul
+del ~tmp~.mak > nul
+make -s -f ~setup~.mak
:exit
diff --git a/bcc32/mkexports.rb b/bcc32/mkexports.rb
index e34b441e2f..dc523e2541 100644..100755
--- a/bcc32/mkexports.rb
+++ b/bcc32/mkexports.rb
@@ -1,5 +1,7 @@
#!./miniruby -s
+$name = $library = $description = nil
+
SYM = {}
STDIN.reopen(open("nul"))
ARGV.each do |obj|
diff --git a/bcc32/setup.mak b/bcc32/setup.mak
index b7a2539d0a..483292ed51 100644
--- a/bcc32/setup.mak
+++ b/bcc32/setup.mak
@@ -30,7 +30,9 @@ i586-$(OS): -prologue- -i586- -epilogue-
i686-$(OS): -prologue- -i686- -epilogue-
alpha-$(OS): -prologue- -alpha- -epilogue-
--prologue-: nul
+-prologue-: -basic-vars- -version- -system-vars-
+
+-basic-vars-: nul
@echo Creating $(MAKEFILE)
@type > $(MAKEFILE) &&|
\#\#\# Makefile for ruby $(OS) \#\#\#
@@ -40,36 +42,68 @@ $(BANG)endif
$(BANG)ifndef prefix
prefix = $(prefix:\=/)
$(BANG)endif
-$(BANG)ifndef EXTSTATIC
-EXTSTATIC = $(EXTSTATIC)
-$(BANG)endif
-!if defined(RDOCTARGET)
-$(BANG)ifndef RDOCTARGET
-RDOCTARGET = $(RDOCTARGET)
-$(BANG)endif
-!endif
-!if defined(EXTOUT)
-$(BANG)ifndef EXTOUT
-EXTOUT = $(EXTOUT)
-$(BANG)endif
+|
+!if exist(confargs.mk)
+ @type confargs.mk >> $(MAKEFILE)
+ @del confargs.mk
!endif
+
+-system-vars-: -runtime- -bormm-
+
+-bormm-: nul
+ @-ilink32 -q -Gn -x usebormm.lib > nul
+ @-if exist usebormm.tds $(APPEND) MEMLIB = usebormm.lib
+ @if exist usebormm.* del usebormm.*
+
+-osname-: nul
+ @echo OS = >>$(MAKEFILE)
+
+-runtime-: nul
+ type > conftest.c &&|
+\#include <stdio.h>
+int main(){printf("");return 0;}
|
- @type > usebormm.bat &&|
-@echo off
-ilink32 -Gn -x usebormm.lib > nul
-if exist usebormm.tds echo MEMLIB = usebormm.lib
+ bcc32 conftest.c cw32i.lib > nul
+ tdump conftest.exe < nul > conftest.i
+ grep "^Imports from CC" conftest.i > conftest.c
+ cpp32 -P- -DFile=\# -DImports=RTNAME -Dfrom== conftest.c > nul
+ $(MAKE) > nul -DBANG=$(BANG) -f &&|
+-runtime-: nul
+$(BANG)include conftest.i
+RT = $$(RTNAME:.DLL=)
+OS = $$(RT:CC32=)
+-runtime-:
+ del conftest.*
+$(BANG)if "$$(OS)" == "50"
+ echo OS = bccwin32 >> $(MAKEFILE)
+$(BANG)else
+ echo OS = bccwin32_$$(OS) >> $(MAKEFILE)
+$(BANG)endif
|
- @usebormm.bat >> $(MAKEFILE)
- @del usebormm.*
+ @echo RT = $$(OS) >> $(MAKEFILE)
+-version-: nul
@cpp32 -I$(srcdir) -P- -o$(MAKEFILE) > nul &&|
\#include "version.h"
MAJOR = RUBY_VERSION_MAJOR
MINOR = RUBY_VERSION_MINOR
TEENY = RUBY_VERSION_TEENY
+
+BORLANDC = __BORLANDC__
|
- @type $(MAKEFILE).i >> $(MAKEFILE)
+ @$(MAKE) > nul -DBANG=$(BANG) -f &&,
+-version-: nul
+$(BANG)include $(MAKEFILE)
+$(BANG)include $(MAKEFILE).i
+-version-:
@del $(MAKEFILE).i
+ @type >> $(MAKEFILE) &&|
+MAJOR = $$(MAJOR)
+MINOR = $$(MINOR)
+TEENY = $$(TEENY)
+BORLANDC = $$(BORLANDC)
+|
+,
-generic-: nul
!if defined(PROCESSOR_ARCHITECTURE) || defined(PROCESSOR_LEVEL)
@@ -84,7 +118,6 @@ $(BANG)ifndef PROCESSOR_LEVEL
PROCESSOR_LEVEL = $(PROCESSOR_LEVEL)
$(BANG)endif
!endif
-
|
!endif
@@ -117,8 +150,6 @@ $(BANG)endif
-epilogue-: nul
@type >> $(MAKEFILE) &&|
-\# OS = $(OS)
-\# RT = $(RT)
\# RUBY_INSTALL_NAME = ruby
\# RUBY_SO_NAME = $$(RT)-$$(RUBY_INSTALL_NAME)$$(MAJOR)$$(MINOR)
\# CFLAGS = -q $$(DEBUGFLAGS) $$(OPTFLAGS) $$(PROCESSOR_FLAG) -w- -wsus -wcpt -wdup -wext -wrng -wrpt -wzdi
@@ -129,5 +160,4 @@ $(BANG)endif
\# EXTLIBS = cw32.lib import32.lib user32.lib kernel32.lib
$(BANG)include $$(srcdir)/bcc32/Makefile.sub
|
- @$(srcdir:/=\)\win32\rm.bat config.h config.status
@echo type "`$(MAKE)'" to make ruby for $(OS).
diff --git a/bignum.c b/bignum.c
index cbcea24818..b9f552c4be 100644
--- a/bignum.c
+++ b/bignum.c
@@ -2,8 +2,8 @@
bignum.c -
- $Author: shyouhei $
- $Date: 2006/12/06 10:14:12 $
+ $Author$
+ $Date$
created at: Fri Jun 10 00:48:55 JST 1994
Copyright (C) 1993-2003 Yukihiro Matsumoto
@@ -11,8 +11,10 @@
**********************************************************************/
#include "ruby.h"
+#include "rubysig.h"
#include <math.h>
+#include <float.h>
#include <ctype.h>
#ifdef HAVE_IEEEFP_H
#include <ieeefp.h>
@@ -36,7 +38,21 @@ VALUE rb_cBignum;
#define BIGLO(x) ((BDIGIT)((x) & (BIGRAD-1)))
#define BDIGMAX ((BDIGIT)-1)
-#define BIGZEROP(x) (RBIGNUM(x)->len == 0 || (RBIGNUM(x)->len == 1 && BDIGITS(x)[0] == 0))
+#define BIGZEROP(x) (RBIGNUM(x)->len == 0 || \
+ (BDIGITS(x)[0] == 0 && \
+ (RBIGNUM(x)->len == 1 || bigzero_p(x))))
+
+static int bigzero_p(VALUE);
+static int
+bigzero_p(x)
+ VALUE x;
+{
+ long i;
+ for (i = 0; i < RBIGNUM(x)->len; ++i) {
+ if (BDIGITS(x)[i]) return 0;
+ }
+ return 1;
+}
static VALUE
bignew_1(klass, len, sign)
@@ -97,35 +113,52 @@ rb_big_2comp(x) /* get 2's complement */
}
static VALUE
-bignorm(x)
+bigtrunc(x)
VALUE x;
{
- if (FIXNUM_P(x)) {
- return x;
- }
- else if (TYPE(x) == T_BIGNUM) {
- long len = RBIGNUM(x)->len;
- BDIGIT *ds = BDIGITS(x);
+ long len = RBIGNUM(x)->len;
+ BDIGIT *ds = BDIGITS(x);
+
+ if (len == 0) return x;
+ while (--len && !ds[len]);
+ RBIGNUM(x)->len = ++len;
+ return x;
+}
- while (--len && !ds[len]) ;
- RBIGNUM(x)->len = ++len;
+static VALUE
+bigfixize(x)
+ VALUE x;
+{
+ long len = RBIGNUM(x)->len;
+ BDIGIT *ds = BDIGITS(x);
- if (len*SIZEOF_BDIGITS <= sizeof(VALUE)) {
- long num = 0;
- while (len--) {
- num = BIGUP(num) + ds[len];
+ if (len*SIZEOF_BDIGITS <= sizeof(VALUE)) {
+ long num = 0;
+ while (len--) {
+ num = BIGUP(num) + ds[len];
+ }
+ if (num >= 0) {
+ if (RBIGNUM(x)->sign) {
+ if (POSFIXABLE(num)) return LONG2FIX(num);
}
- if (num >= 0) {
- if (RBIGNUM(x)->sign) {
- if (POSFIXABLE(num)) return LONG2FIX(num);
- }
- else if (NEGFIXABLE(-(long)num)) return LONG2FIX(-(long)num);
+ else {
+ if (NEGFIXABLE(-(long)num)) return LONG2FIX(-(long)num);
}
}
}
return x;
}
+static VALUE
+bignorm(x)
+ VALUE x;
+{
+ if (!FIXNUM_P(x) && TYPE(x) == T_BIGNUM) {
+ x = bigfixize(bigtrunc(x));
+ }
+ return x;
+}
+
VALUE
rb_big_norm(x)
VALUE x;
@@ -189,7 +222,110 @@ rb_int2inum(n)
return rb_int2big(n);
}
-#ifdef HAVE_LONG_LONG
+#if SIZEOF_LONG % SIZEOF_BDIGITS != 0
+# error unexpected SIZEOF_LONG : SIZEOF_BDIGITS ratio
+#endif
+
+/*
+ * buf is an array of long integers.
+ * buf is ordered from least significant word to most significant word.
+ * buf[0] is the least significant word and
+ * buf[num_longs-1] is the most significant word.
+ * This means words in buf is little endian.
+ * However each word in buf is native endian.
+ * (buf[i]&1) is the least significant bit and
+ * (buf[i]&(1<<(SIZEOF_LONG*CHAR_BIT-1))) is the most significant bit
+ * for each 0 <= i < num_longs.
+ * So buf is little endian at whole on a little endian machine.
+ * But buf is mixed endian on a big endian machine.
+ */
+void
+rb_big_pack(VALUE val, unsigned long *buf, long num_longs)
+{
+ val = rb_to_int(val);
+ if (num_longs == 0)
+ return;
+ if (FIXNUM_P(val)) {
+ long i;
+ long tmp = FIX2LONG(val);
+ buf[0] = (unsigned long)tmp;
+ tmp = tmp < 0 ? ~0L : 0;
+ for (i = 1; i < num_longs; i++)
+ buf[i] = (unsigned long)tmp;
+ return;
+ }
+ else {
+ long len = RBIGNUM_LEN(val);
+ BDIGIT *ds = BDIGITS(val), *dend = ds + len;
+ long i, j;
+ for (i = 0; i < num_longs && ds < dend; i++) {
+ unsigned long l = 0;
+ for (j = 0; j < DIGSPERLONG && ds < dend; j++, ds++) {
+ l |= ((unsigned long)*ds << (j * BITSPERDIG));
+ }
+ buf[i] = l;
+ }
+ for (; i < num_longs; i++)
+ buf[i] = 0;
+ if (RBIGNUM_NEGATIVE_P(val)) {
+ for (i = 0; i < num_longs; i++) {
+ buf[i] = ~buf[i];
+ }
+ for (i = 0; i < num_longs; i++) {
+ buf[i]++;
+ if (buf[i] != 0)
+ return;
+ }
+ }
+ }
+}
+
+/* See rb_big_pack comment for endianness of buf. */
+VALUE
+rb_big_unpack(unsigned long *buf, long num_longs)
+{
+ while (2 <= num_longs) {
+ if (buf[num_longs-1] == 0 && (long)buf[num_longs-2] >= 0)
+ num_longs--;
+ else if (buf[num_longs-1] == ~0UL && (long)buf[num_longs-2] < 0)
+ num_longs--;
+ else
+ break;
+ }
+ if (num_longs == 0)
+ return INT2FIX(0);
+ else if (num_longs == 1)
+ return LONG2NUM((long)buf[0]);
+ else {
+ VALUE big;
+ BDIGIT *ds;
+ long len = num_longs * DIGSPERLONG;
+ long i;
+ big = bignew(len, 1);
+ ds = BDIGITS(big);
+ for (i = 0; i < num_longs; i++) {
+ unsigned long d = buf[i];
+#if SIZEOF_LONG == SIZEOF_BDIGITS
+ *ds++ = d;
+#else
+ int j;
+ for (j = 0; j < DIGSPERLONG; j++) {
+ *ds++ = BIGLO(d);
+ d = BIGDN(d);
+ }
+#endif
+ }
+ if ((long)buf[num_longs-1] < 0) {
+ get2comp(big);
+ RBIGNUM_SET_SIGN(big, 0);
+ }
+ return bignorm(big);
+ }
+}
+
+#define QUAD_SIZE 8
+
+#if SIZEOF_LONG_LONG == QUAD_SIZE && SIZEOF_BDIGITS*2 == SIZEOF_LONG_LONG
void
rb_quad_pack(buf, val)
@@ -262,7 +398,19 @@ rb_quad_unpack(buf, sign)
#else
-#define QUAD_SIZE 8
+static int
+quad_buf_complement(char *buf, size_t len)
+{
+ size_t i;
+ for (i = 0; i < len; i++)
+ buf[i] = ~buf[i];
+ for (i = 0; i < len; i++) {
+ buf[i]++;
+ if (buf[i] != 0)
+ return 0;
+ }
+ return 1;
+}
void
rb_quad_pack(buf, val)
@@ -281,12 +429,8 @@ rb_quad_pack(buf, val)
rb_raise(rb_eRangeError, "bignum too big to convert into `quad int'");
}
memcpy(buf, (char*)BDIGITS(val), len);
- if (!RBIGNUM(val)->sign) {
- len = QUAD_SIZE;
- while (len--) {
- *buf = ~*buf;
- buf++;
- }
+ if (RBIGNUM_NEGATIVE_P(val)) {
+ quad_buf_complement(buf, QUAD_SIZE);
}
}
@@ -301,14 +445,10 @@ rb_quad_unpack(buf, sign)
memcpy((char*)BDIGITS(big), buf, QUAD_SIZE);
if (sign && BNEG(buf)) {
- long len = QUAD_SIZE;
char *tmp = (char*)BDIGITS(big);
RBIGNUM(big)->sign = 0;
- while (len--) {
- *tmp = ~*tmp;
- tmp++;
- }
+ quad_buf_complement(tmp, QUAD_SIZE);
}
return bignorm(big);
@@ -430,8 +570,15 @@ rb_cstr_to_inum(str, base, badcheck)
break;
}
if (*str == '0') { /* squeeze preceeding 0s */
- while (*++str == '0');
- if (!*str) --str;
+ int us = 0;
+ while ((c = *++str) == '0' || c == '_') {
+ if (c == '_') {
+ if (++us >= 2)
+ break;
+ } else
+ us = 0;
+ }
+ if (!(c = *str) || ISSPACE(c)) --str;
}
c = *str;
c = conv_digit(c);
@@ -473,10 +620,11 @@ rb_cstr_to_inum(str, base, badcheck)
for (i=len;i--;) zds[i]=0;
while ((c = *str++) != 0) {
if (c == '_') {
- if (badcheck) {
- if (nondigit) goto bad;
- nondigit = c;
+ if (nondigit) {
+ if (badcheck) goto bad;
+ break;
}
+ nondigit = c;
continue;
}
else if ((c = conv_digit(c)) < 0) {
@@ -538,7 +686,7 @@ rb_str_to_inum(str, base, badcheck)
s = p;
}
}
- return rb_cstr_to_inum(s, base, badcheck);
+ return rb_cstr_to_inum(s, base, badcheck);
}
#if HAVE_LONG_LONG
@@ -600,7 +748,7 @@ rb_ll2inum(n)
}
#endif /* HAVE_LONG_LONG */
-
+
VALUE
rb_cstr2inum(str, base)
const char *str;
@@ -619,15 +767,16 @@ rb_str2inum(str, base)
const char ruby_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
VALUE
-rb_big2str(x, base)
+rb_big2str0(x, base, trim)
VALUE x;
int base;
+ int trim;
{
volatile VALUE t;
BDIGIT *ds;
long i, j, hbase;
VALUE ss;
- char *s, c;
+ char *s;
if (FIXNUM_P(x)) {
return rb_fix2str(x, base);
@@ -636,34 +785,37 @@ rb_big2str(x, base)
if (BIGZEROP(x)) {
return rb_str_new2("0");
}
+ if (i >= LONG_MAX/SIZEOF_BDIGITS/CHAR_BIT) {
+ rb_raise(rb_eRangeError, "bignum too big to convert into `string'");
+ }
j = SIZEOF_BDIGITS*CHAR_BIT*i;
switch (base) {
case 2: break;
case 3:
- j = j * 647L / 1024;
+ j = j * 53L / 84 + 1;
break;
case 4: case 5: case 6: case 7:
- j /= 2;
+ j = (j + 1) / 2;
break;
case 8: case 9:
- j /= 3;
+ j = (j + 2) / 3;
break;
case 10: case 11: case 12: case 13: case 14: case 15:
- j = j * 241L / 800;
+ j = j * 28L / 93 + 1;
break;
case 16: case 17: case 18: case 19: case 20: case 21:
case 22: case 23: case 24: case 25: case 26: case 27:
case 28: case 29: case 30: case 31:
- j /= 4;
+ j = (j + 3) / 4;
break;
case 32: case 33: case 34: case 35: case 36:
- j /= 5;
+ j = (j + 4) / 5;
break;
default:
rb_raise(rb_eArgError, "illegal radix %d", base);
break;
}
- j += 2;
+ j++; /* space for sign */
hbase = base * base;
#if SIZEOF_BDIGITS > 2
@@ -672,11 +824,12 @@ rb_big2str(x, base)
t = rb_big_clone(x);
ds = BDIGITS(t);
- ss = rb_str_new(0, j);
+ ss = rb_str_new(0, j+1);
s = RSTRING(ss)->ptr;
s[0] = RBIGNUM(x)->sign ? '+' : '-';
- while (i && j) {
+ TRAP_BEG;
+ while (i && j > 1) {
long k = i;
BDIGIT_DBL num = 0;
@@ -685,30 +838,44 @@ rb_big2str(x, base)
ds[k] = (BDIGIT)(num / hbase);
num %= hbase;
}
- if (ds[i-1] == 0) i--;
+ if (trim && ds[i-1] == 0) i--;
k = SIZEOF_BDIGITS;
while (k--) {
- c = (char)(num % base);
- s[--j] = ruby_digitmap[(int)c];
+ s[--j] = ruby_digitmap[num % base];
num /= base;
- if (i == 0 && num == 0) break;
+ if (!trim && j <= 1) break;
+ if (trim && i == 0 && num == 0) break;
}
}
- while (s[j] == '0') j++;
- RSTRING(ss)->len -= RBIGNUM(x)->sign?j:j-1;
- memmove(RBIGNUM(x)->sign?s:s+1, s+j, RSTRING(ss)->len);
+ if (trim) {while (s[j] == '0') j++;}
+ i = RSTRING(ss)->len - j;
+ if (RBIGNUM(x)->sign) {
+ memmove(s, s+j, i);
+ RSTRING(ss)->len = i-1;
+ }
+ else {
+ memmove(s+1, s+j, i);
+ RSTRING(ss)->len = i;
+ }
s[RSTRING(ss)->len] = '\0';
+ TRAP_END;
return ss;
}
+VALUE
+rb_big2str(VALUE x, int base)
+{
+ return rb_big2str0(x, base, Qtrue);
+}
+
/*
* call-seq:
* big.to_s(base=10) => string
- *
+ *
* Returns a string containing the representation of <i>big</i> radix
* <i>base</i> (2 through 36).
- *
+ *
* 12345654321.to_s #=> "12345654321"
* 12345654321.to_s(2) #=> "1011011111110110111011110000110001"
* 12345654321.to_s(8) #=> "133766736061"
@@ -752,15 +919,15 @@ big2ulong(x, type)
}
unsigned long
-rb_big2ulong_pack(x)
- VALUE x;
-{
+rb_big2ulong_pack(x)
+ VALUE x;
+{
unsigned long num = big2ulong(x, "unsigned long");
if (!RBIGNUM(x)->sign) {
return -num;
}
return num;
-}
+}
unsigned long
rb_big2ulong(x)
@@ -878,8 +1045,8 @@ rb_dbl2big(d)
return bignorm(dbl2big(d));
}
-double
-rb_big2dbl(x)
+static double
+big2dbl(x)
VALUE x;
{
double d = 0.0;
@@ -889,21 +1056,30 @@ rb_big2dbl(x)
while (i--) {
d = ds[i] + BIGRAD*d;
}
+ if (!RBIGNUM(x)->sign) d = -d;
+ return d;
+}
+
+double
+rb_big2dbl(x)
+ VALUE x;
+{
+ double d = big2dbl(x);
+
if (isinf(d)) {
rb_warn("Bignum out of Float range");
d = HUGE_VAL;
}
- if (!RBIGNUM(x)->sign) d = -d;
return d;
}
/*
* call-seq:
* big.to_f -> float
- *
+ *
* Converts <i>big</i> to a <code>Float</code>. If <i>big</i> doesn't
* fit in a <code>Float</code>, the result is infinity.
- *
+ *
*/
static VALUE
@@ -916,11 +1092,11 @@ rb_big_to_f(x)
/*
* call-seq:
* big <=> numeric => -1, 0, +1
- *
+ *
* Comparison---Returns -1, 0, or +1 depending on whether <i>big</i> is
* less than, equal to, or greater than <i>numeric</i>. This is the
* basis for the tests in <code>Comparable</code>.
- *
+ *
*/
static VALUE
@@ -961,11 +1137,11 @@ rb_big_cmp(x, y)
/*
* call-seq:
* big == obj => true or false
- *
+ *
* Returns <code>true</code> only if <i>obj</i> has the same value
* as <i>big</i>. Contrast this with <code>Bignum#eql?</code>, which
* requires <i>obj</i> to be a <code>Bignum</code>.
- *
+ *
* 68719476736 == 68719476736.0 #=> true
*/
@@ -1000,11 +1176,11 @@ rb_big_eq(x, y)
/*
* call-seq:
* big.eql?(obj) => true or false
- *
+ *
* Returns <code>true</code> only if <i>obj</i> is a
* <code>Bignum</code> with the same value as <i>big</i>. Contrast this
* with <code>Bignum#==</code>, which performs type conversions.
- *
+ *
* 68719476736.eql?(68719476736.0) #=> false
*/
@@ -1045,7 +1221,7 @@ rb_big_uminus(x)
* length, the result acts as if it had an infinite number of one
* bits to the left. In hex representations, this is displayed
* as two periods to the left of the digits.
- *
+ *
* sprintf("%X", ~0x1122334455) #=> "..FEEDDCCBBAA"
*/
@@ -1076,7 +1252,7 @@ bigsub(x, y)
BDIGIT *zds;
BDIGIT_DBL_SIGNED num;
long i = RBIGNUM(x)->len;
-
+
/* if x is larger than y, swap */
if (RBIGNUM(x)->len < RBIGNUM(y)->len) {
z = x; x = y; y = z; /* swap x y */
@@ -1097,11 +1273,11 @@ bigsub(x, y)
z = bignew(RBIGNUM(x)->len, z==0);
zds = BDIGITS(z);
- for (i = 0, num = 0; i < RBIGNUM(y)->len; i++) {
+ for (i = 0, num = 0; i < RBIGNUM(y)->len; i++) {
num += (BDIGIT_DBL_SIGNED)BDIGITS(x)[i] - BDIGITS(y)[i];
zds[i] = BIGLO(num);
num = BIGDN(num);
- }
+ }
while (num && i < RBIGNUM(x)->len) {
num += BDIGITS(x)[i];
zds[i++] = BIGLO(num);
@@ -1111,7 +1287,7 @@ bigsub(x, y)
zds[i] = BDIGITS(x)[i];
i++;
}
-
+
return z;
}
@@ -1212,15 +1388,8 @@ rb_big_minus(x, y)
}
}
-/*
- * call-seq:
- * big * other => Numeric
- *
- * Multiplies big and other, returning the result.
- */
-
VALUE
-rb_big_mul(x, y)
+rb_big_mul0(x, y)
VALUE x, y;
{
long i, j;
@@ -1249,7 +1418,7 @@ rb_big_mul(x, y)
zds = BDIGITS(z);
while (j--) zds[j] = 0;
for (i = 0; i < RBIGNUM(x)->len; i++) {
- BDIGIT_DBL dd = BDIGITS(x)[i];
+ BDIGIT_DBL dd = BDIGITS(x)[i];
if (dd == 0) continue;
n = 0;
for (j = 0; j < RBIGNUM(y)->len; j++) {
@@ -1263,7 +1432,21 @@ rb_big_mul(x, y)
}
}
- return bignorm(z);
+ return z;
+}
+
+/*
+ * call-seq:
+ * big * other => Numeric
+ *
+ * Multiplies big and other, returning the result.
+ */
+
+VALUE
+rb_big_mul(x, y)
+ VALUE x, y;
+{
+ return bignorm(rb_big_mul0(x, y));
}
static void
@@ -1312,7 +1495,7 @@ bigdivrem(x, y, divp, modp)
dd = 0;
q = yds[ny-1];
- while ((q & (1<<(BITSPERDIG-1))) == 0) {
+ while ((q & (1U<<(BITSPERDIG-1))) == 0) {
q <<= 1;
dd++;
}
@@ -1436,9 +1619,6 @@ rb_big_div(x, y)
case T_BIGNUM:
break;
- case T_FLOAT:
- return rb_float_new(rb_big2dbl(x) / RFLOAT(y)->value);
-
default:
return rb_num_coerce_bin(x, y);
}
@@ -1481,9 +1661,9 @@ rb_big_modulo(x, y)
/*
* call-seq:
* big.remainder(numeric) => number
- *
+ *
* Returns the remainder after dividing <i>big</i> by <i>numeric</i>.
- *
+ *
* -1234567890987654321.remainder(13731) #=> -6966
* -1234567890987654321.remainder(13731.24) #=> -9906.22531493148
*/
@@ -1509,6 +1689,27 @@ rb_big_remainder(x, y)
return bignorm(z);
}
+static int
+bdigbitsize(BDIGIT x)
+{
+ int size = 1;
+ int nb = BITSPERDIG / 2;
+ BDIGIT bits = (~0 << nb);
+
+ if (!x) return 0;
+ while (x > 1) {
+ if (x & bits) {
+ size += nb;
+ x >>= nb;
+ }
+ x &= ~bits;
+ nb /= 2;
+ bits >>= nb;
+ }
+
+ return size;
+}
+
static VALUE big_lshift _((VALUE, unsigned long));
static VALUE big_rshift _((VALUE, unsigned long));
@@ -1526,9 +1727,9 @@ static VALUE big_shift(x, n)
/*
* call-seq:
* big.divmod(numeric) => array
- *
+ *
* See <code>Numeric#divmod</code>.
- *
+ *
*/
VALUE
rb_big_divmod(x, y)
@@ -1555,22 +1756,51 @@ rb_big_divmod(x, y)
/*
* call-seq:
* big.quo(numeric) -> float
- *
+ * big.fdiv(numeric) -> float
+ *
* Returns the floating point result of dividing <i>big</i> by
* <i>numeric</i>.
- *
+ *
* -1234567890987654321.quo(13731) #=> -89910996357705.5
* -1234567890987654321.quo(13731.24) #=> -89909424858035.7
- *
+ *
*/
static VALUE
rb_big_quo(x, y)
VALUE x, y;
{
- double dx = rb_big2dbl(x);
+ double dx = big2dbl(x);
double dy;
+ if (isinf(dx)) {
+#define DBL_BIGDIG ((DBL_MANT_DIG + BITSPERDIG) / BITSPERDIG)
+ VALUE z;
+ int ex, ey;
+
+ ex = (RBIGNUM(bigtrunc(x))->len - 1) * BITSPERDIG;
+ ex += bdigbitsize(BDIGITS(x)[RBIGNUM(x)->len - 1]);
+ ex -= 2 * DBL_BIGDIG * BITSPERDIG;
+ if (ex) x = big_shift(x, ex);
+
+ switch (TYPE(y)) {
+ case T_FIXNUM:
+ y = rb_int2big(FIX2LONG(y));
+ case T_BIGNUM: {
+ ey = (RBIGNUM(bigtrunc(y))->len - 1) * BITSPERDIG;
+ ey += bdigbitsize(BDIGITS(y)[RBIGNUM(y)->len - 1]);
+ ey -= DBL_BIGDIG * BITSPERDIG;
+ if (ey) y = big_shift(y, ey);
+ bignum:
+ bigdivrem(x, y, &z, 0);
+ return rb_float_new(ldexp(big2dbl(z), ex - ey));
+ }
+ case T_FLOAT:
+ y = dbl2big(ldexp(frexp(RFLOAT(y)->value, &ey), DBL_MANT_DIG));
+ ey -= DBL_MANT_DIG;
+ goto bignum;
+ }
+ }
switch (TYPE(y)) {
case T_FIXNUM:
dy = (double)FIX2LONG(y);
@@ -1590,6 +1820,52 @@ rb_big_quo(x, y)
return rb_float_new(dx / dy);
}
+static VALUE
+bigsqr(x)
+ VALUE x;
+{
+ long len = RBIGNUM(x)->len, k = len / 2, i;
+ VALUE a, b, a2, z;
+ BDIGIT_DBL num;
+
+ if (len < 4000 / BITSPERDIG) {
+ return rb_big_mul0(x, x);
+ }
+
+ a = bignew(len - k, 1);
+ MEMCPY(BDIGITS(a), BDIGITS(x) + k, BDIGIT, len - k);
+ b = bignew(k, 1);
+ MEMCPY(BDIGITS(b), BDIGITS(x), BDIGIT, k);
+
+ a2 = bigtrunc(bigsqr(a));
+ z = bigsqr(b);
+ REALLOC_N(RBIGNUM(z)->digits, BDIGIT, (len = 2 * k + RBIGNUM(a2)->len) + 1);
+ while (RBIGNUM(z)->len < 2 * k) BDIGITS(z)[RBIGNUM(z)->len++] = 0;
+ MEMCPY(BDIGITS(z) + 2 * k, BDIGITS(a2), BDIGIT, RBIGNUM(a2)->len);
+ RBIGNUM(z)->len = len;
+ a2 = bigtrunc(rb_big_mul0(a, b));
+ len = RBIGNUM(a2)->len;
+ TRAP_BEG;
+ for (i = 0, num = 0; i < len; i++) {
+ num += (BDIGIT_DBL)BDIGITS(z)[i + k] + ((BDIGIT_DBL)BDIGITS(a2)[i] << 1);
+ BDIGITS(z)[i + k] = BIGLO(num);
+ num = BIGDN(num);
+ }
+ TRAP_END;
+ if (num) {
+ len = RBIGNUM(z)->len;
+ for (i += k; i < len && num; ++i) {
+ num += (BDIGIT_DBL)BDIGITS(z)[i];
+ BDIGITS(z)[i] = BIGLO(num);
+ num = BIGDN(num);
+ }
+ if (num) {
+ BDIGITS(z)[RBIGNUM(z)->len++] = BIGLO(num);
+ }
+ }
+ return bigtrunc(z);
+}
+
/*
* call-seq:
* big ** exponent #=> numeric
@@ -1609,7 +1885,7 @@ rb_big_pow(x, y)
{
double d;
long yy;
-
+
if (y == INT2FIX(0)) return INT2FIX(1);
switch (TYPE(y)) {
case T_FLOAT:
@@ -1624,7 +1900,8 @@ rb_big_pow(x, y)
case T_FIXNUM:
yy = FIX2LONG(y);
if (yy > 0) {
- VALUE z = x;
+ VALUE z = 0;
+ long mask;
const long BIGLEN_LIMIT = 1024*1024 / SIZEOF_BDIGITS;
if ((RBIGNUM(x)->len > BIGLEN_LIMIT) ||
@@ -1633,14 +1910,11 @@ rb_big_pow(x, y)
d = (double)yy;
break;
}
- for (;;) {
- yy -= 1;
- if (yy == 0) break;
- while (yy % 2 == 0) {
- yy /= 2;
- x = rb_big_mul(x, x);
+ for (mask = FIXNUM_MAX + 1; mask; mask >>= 1) {
+ if (z) z = bigtrunc(bigsqr(z));
+ if (yy & mask) {
+ z = z ? bigtrunc(rb_big_mul0(z, x)) : x;
}
- z = rb_big_mul(z, x);
}
return bignorm(z);
}
@@ -1865,14 +2139,14 @@ rb_big_lshift(x, y)
if (!NIL_P(t)) return t;
neg = 1;
}
- shift = big2ulong(y, "long", Qtrue);
+ shift = big2ulong(y, "long");
break;
}
y = rb_to_int(y);
}
- if (neg) return big_rshift(x, shift);
- return big_lshift(x, shift);
+ x = neg ? big_rshift(x, shift) : big_lshift(x, shift);
+ return bignorm(x);
}
static VALUE
@@ -1900,7 +2174,7 @@ big_lshift(x, shift)
num = BIGDN(num);
}
*zds = BIGLO(num);
- return bignorm(z);
+ return z;
}
/*
@@ -1934,14 +2208,14 @@ rb_big_rshift(x, y)
else {
neg = 1;
}
- shift = big2ulong(y, "long", Qtrue);
+ shift = big2ulong(y, "long");
break;
}
y = rb_to_int(y);
}
- if (neg) return big_lshift(x, shift);
- return big_rshift(x, shift);
+ x = neg ? big_lshift(x, shift) : big_rshift(x, shift);
+ return bignorm(x);
}
static VALUE
@@ -1969,6 +2243,10 @@ big_rshift(x, shift)
}
xds = BDIGITS(x);
i = RBIGNUM(x)->len; j = i - s1;
+ if (j == 0) {
+ if (RBIGNUM(x)->sign) return INT2FIX(0);
+ else return INT2FIX(-1);
+ }
z = bignew(j, RBIGNUM(x)->sign);
if (!RBIGNUM(x)->sign) {
num = ((BDIGIT_DBL)~0) << BITSPERDIG;
@@ -1982,26 +2260,26 @@ big_rshift(x, shift)
if (!RBIGNUM(x)->sign) {
get2comp(z);
}
- return bignorm(z);
+ return z;
}
/*
* call-seq:
* big[n] -> 0, 1
- *
+ *
* Bit Reference---Returns the <em>n</em>th bit in the (assumed) binary
* representation of <i>big</i>, where <i>big</i>[0] is the least
* significant bit.
- *
+ *
* a = 9**15
* 50.downto(0) do |n|
* print a[n]
* end
- *
+ *
* <em>produces:</em>
- *
+ *
* 000101110110100000111000011110010100111100010111001
- *
+ *
*/
static VALUE
@@ -2009,29 +2287,39 @@ rb_big_aref(x, y)
VALUE x, y;
{
BDIGIT *xds;
- int shift;
- long s1, s2;
+ BDIGIT_DBL num;
+ unsigned long shift;
+ long i, s1, s2;
if (TYPE(y) == T_BIGNUM) {
- if (!RBIGNUM(y)->sign || RBIGNUM(x)->sign)
+ if (!RBIGNUM(y)->sign)
return INT2FIX(0);
- return INT2FIX(1);
+ if (RBIGNUM(bigtrunc(y))->len > SIZEOF_LONG/SIZEOF_BDIGITS) {
+ out_of_range:
+ return RBIGNUM(x)->sign ? INT2FIX(0) : INT2FIX(1);
+ }
+ shift = big2ulong(y, "long");
+ }
+ else {
+ i = NUM2LONG(y);
+ if (i < 0) return INT2FIX(0);
+ shift = (VALUE)i;
}
- shift = NUM2INT(y);
- if (shift < 0) return INT2FIX(0);
s1 = shift/BITSPERDIG;
s2 = shift%BITSPERDIG;
+ if (s1 >= RBIGNUM(x)->len) goto out_of_range;
if (!RBIGNUM(x)->sign) {
- if (s1 >= RBIGNUM(x)->len) return INT2FIX(1);
- x = rb_big_clone(x);
- get2comp(x);
+ xds = BDIGITS(x);
+ i = 0; num = 1;
+ while (num += ~xds[i], ++i <= s1) {
+ num = BIGDN(num);
+ }
}
else {
- if (s1 >= RBIGNUM(x)->len) return INT2FIX(0);
+ num = BDIGITS(x)[s1];
}
- xds = BDIGITS(x);
- if (xds[s1] & (1<<s2))
+ if (num & ((BDIGIT_DBL)1<<s2))
return INT2FIX(1);
return INT2FIX(0);
}
@@ -2082,9 +2370,9 @@ rb_big_coerce(x, y)
/*
* call-seq:
* big.abs -> aBignum
- *
+ *
* Returns the absolute value of <i>big</i>.
- *
+ *
* -1234567890987654321.abs #=> 1234567890987654321
*/
@@ -2112,7 +2400,7 @@ rb_big_rand(max, rand_buf)
}
v = bignew(len,1);
len--;
- BDIGITS(v)[len] = BDIGITS(max)[len] * rand_buf[len];
+ BDIGITS(v)[len] = BDIGITS(max)[len] * rand_buf[len];
while (len--) {
BDIGITS(v)[len] = ((BDIGIT)~0) * rand_buf[len];
}
@@ -2123,10 +2411,10 @@ rb_big_rand(max, rand_buf)
/*
* call-seq:
* big.size -> integer
- *
+ *
* Returns the number of bytes in the machine representation of
* <i>big</i>.
- *
+ *
* (256**10 - 1).size #=> 12
* (256**20 - 1).size #=> 20
* (256**40 - 1).size #=> 40
@@ -2146,15 +2434,15 @@ rb_big_size(big)
* Fixnum. When a calculation involving
* Bignum objects returns a result that will fit in a
* Fixnum, the result is automatically converted.
- *
+ *
* For the purposes of the bitwise operations and <code>[]</code>, a
* Bignum is treated as if it were an infinite-length
* bitstring with 2's complement representation.
- *
+ *
* While Fixnum values are immediate, Bignum
* objects are not---assignment and parameter passing work with
* references to objects, not the objects themselves.
- *
+ *
*/
void
@@ -2175,6 +2463,7 @@ Init_Bignum()
rb_define_method(rb_cBignum, "modulo", rb_big_modulo, 1);
rb_define_method(rb_cBignum, "remainder", rb_big_remainder, 1);
rb_define_method(rb_cBignum, "quo", rb_big_quo, 1);
+ rb_define_method(rb_cBignum, "fdiv", rb_big_quo, 1);
rb_define_method(rb_cBignum, "**", rb_big_pow, 1);
rb_define_method(rb_cBignum, "&", rb_big_and, 1);
rb_define_method(rb_cBignum, "|", rb_big_or, 1);
diff --git a/bin/irb b/bin/irb
index 13474a932b..f277bc4b69 100644
--- a/bin/irb
+++ b/bin/irb
@@ -2,8 +2,8 @@
#
# irb.rb - intaractive ruby
# $Release Version: 0.9.5 $
-# $Revision: 1.2.2.1 $
-# $Date: 2005/04/19 19:24:56 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
diff --git a/bin/rdoc b/bin/rdoc
index d08ce838f6..fe619137fd 100644
--- a/bin/rdoc
+++ b/bin/rdoc
@@ -6,7 +6,7 @@
# Copyright (c) 2003 Dave Thomas
# Released under the same terms as Ruby
#
-# $Revision: 1.1 $
+# $Revision$
## Transitional Hack ####
#
diff --git a/class.c b/class.c
index 9e41b1e260..054be60d53 100644
--- a/class.c
+++ b/class.c
@@ -2,8 +2,8 @@
class.c -
- $Author: nobu $
- $Date: 2005/09/28 14:42:46 $
+ $Author$
+ $Date$
created at: Tue Aug 10 15:05:44 JST 1993
Copyright (C) 1993-2003 Yukihiro Matsumoto
@@ -48,13 +48,26 @@ rb_class_new(super)
return rb_class_boot(super);
}
+struct clone_method_data {
+ st_table *tbl;
+ VALUE klass;
+};
+
static int
-clone_method(mid, body, tbl)
+clone_method(mid, body, data)
ID mid;
NODE *body;
- st_table *tbl;
+ struct clone_method_data *data;
{
- st_insert(tbl, mid, (st_data_t)NEW_METHOD(body->nd_body, body->nd_noex));
+ NODE *fbody = body->nd_body;
+
+ if (fbody && nd_type(fbody) == NODE_SCOPE) {
+ NODE *cref = (NODE*)fbody->nd_rval;
+
+ if (cref) cref = cref->nd_next;
+ fbody = rb_copy_node_scope(fbody, NEW_CREF(data->klass, cref));
+ }
+ st_insert(data->tbl, mid, (st_data_t)NEW_METHOD(fbody, body->nd_noex));
return ST_CONTINUE;
}
@@ -65,7 +78,8 @@ rb_mod_init_copy(clone, orig)
{
rb_obj_init_copy(clone, orig);
if (!FL_TEST(CLASS_OF(clone), FL_SINGLETON)) {
- RBASIC(clone)->klass = rb_singleton_class_clone(orig);
+ RBASIC(clone)->klass = RBASIC(orig)->klass;
+ RBASIC(clone)->klass = rb_singleton_class_clone(clone);
}
RCLASS(clone)->super = RCLASS(orig)->super;
if (RCLASS(orig)->iv_tbl) {
@@ -78,9 +92,12 @@ rb_mod_init_copy(clone, orig)
st_delete(RCLASS(clone)->iv_tbl, (st_data_t*)&id, 0);
}
if (RCLASS(orig)->m_tbl) {
- RCLASS(clone)->m_tbl = st_init_numtable();
- st_foreach(RCLASS(orig)->m_tbl, clone_method,
- (st_data_t)RCLASS(clone)->m_tbl);
+ struct clone_method_data data;
+
+ data.tbl = RCLASS(clone)->m_tbl = st_init_numtable();
+ data.klass = (VALUE)clone;
+
+ st_foreach(RCLASS(orig)->m_tbl, clone_method, (st_data_t)&data);
}
return clone;
@@ -126,9 +143,22 @@ rb_singleton_class_clone(obj)
if (RCLASS(klass)->iv_tbl) {
clone->iv_tbl = st_copy(RCLASS(klass)->iv_tbl);
}
- clone->m_tbl = st_init_numtable();
- st_foreach(RCLASS(klass)->m_tbl, clone_method,
- (st_data_t)clone->m_tbl);
+ {
+ struct clone_method_data data;
+
+ data.tbl = clone->m_tbl = st_init_numtable();
+ switch (TYPE(obj)) {
+ case T_CLASS:
+ case T_MODULE:
+ data.klass = obj;
+ break;
+ default:
+ data.klass = Qnil;
+ break;
+ }
+
+ st_foreach(RCLASS(klass)->m_tbl, clone_method, (st_data_t)&data);
+ }
rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone);
FL_SET(clone, FL_SINGLETON);
return (VALUE)clone;
@@ -379,9 +409,6 @@ rb_include_module(klass, module)
rb_secure(4);
}
- if (NIL_P(module)) return;
- if (klass == module) return;
-
if (TYPE(module) != T_MODULE) {
Check_Type(module, T_MODULE);
}
diff --git a/common.mk b/common.mk
index 3584b83e35..a57cc9b320 100644
--- a/common.mk
+++ b/common.mk
@@ -1,13 +1,20 @@
bin: $(PROGRAM) $(WPROGRAM)
-lib: $(LIBRUBY);
-dll: $(LIBRUBY_SO);
+lib: $(LIBRUBY)
+dll: $(LIBRUBY_SO)
-RUBYOPT =
+RUBYLIB = -
+RUBYOPT = -
+
+SPEC_GIT_BASE = git://github.com/rubyspec
+MSPEC_GIT_URL = $(SPEC_GIT_BASE)/mspec.git
+RUBYSPEC_GIT_URL = $(SPEC_GIT_BASE)/rubyspec.git
STATIC_RUBY = static-ruby
EXTCONF = extconf.rb
RBCONFIG = ./.rbconfig.time
+LIBRUBY_EXTS = ./.libruby-with-ext.time
+RDOCOUT = $(EXTOUT)/rdoc
DMYEXT = dmyext.$(OBJEXT)
MAINOBJ = main.$(OBJEXT)
@@ -21,6 +28,7 @@ OBJS = array.$(OBJEXT) \
dir.$(OBJEXT) \
dln.$(OBJEXT) \
enum.$(OBJEXT) \
+ enumerator.$(OBJEXT) \
error.$(OBJEXT) \
eval.$(OBJEXT) \
file.$(OBJEXT) \
@@ -53,13 +61,26 @@ OBJS = array.$(OBJEXT) \
$(MISSING)
SCRIPT_ARGS = --dest-dir="$(DESTDIR)" \
- --make="$(MAKE)" \
+ --extout="$(EXTOUT)" \
--mflags="$(MFLAGS)" \
--make-flags="$(MAKEFLAGS)"
-EXTMK_ARGS = $(SCRIPT_ARGS) --extout="$(EXTOUT)" --extension $(EXTS) --extstatic $(EXTSTATIC) --
+EXTMK_ARGS = $(SCRIPT_ARGS) --extension $(EXTS) --extstatic $(EXTSTATIC) \
+ --make-flags="MINIRUBY='$(MINIRUBY)'" --
+INSTRUBY_ARGS = $(SCRIPT_ARGS) \
+ --data-mode=$(INSTALL_DATA_MODE) \
+ --prog-mode=$(INSTALL_PROG_MODE) \
+ --installed-list $(INSTALLED_LIST)
+INSTALL_PROG_MODE = 0755
+INSTALL_DATA_MODE = 0644
+
+PRE_LIBRUBY_UPDATE = $(MINIRUBY) -e 'ARGV[1] or File.unlink(ARGV[0]) rescue nil' -- \
+ $(LIBRUBY_EXTS) $(LIBRUBY_SO_UPDATE)
+
+TESTSDIR = $(srcdir)/test
+TESTWORKDIR = testwork
all: $(MKFILES) $(PREP) $(RBCONFIG) $(LIBRUBY)
- @$(MINIRUBY) $(srcdir)/ext/extmk.rb $(EXTMK_ARGS)
+ @$(MINIRUBY) $(srcdir)/ext/extmk.rb --make="$(MAKE)" $(EXTMK_ARGS)
prog: $(PROGRAM) $(WPROGRAM)
miniruby$(EXEEXT): config.status $(LIBRUBY_A) $(MAINOBJ) $(MINIOBJS) $(OBJS) $(DMYEXT)
@@ -68,7 +89,10 @@ $(PROGRAM): $(LIBRUBY) $(MAINOBJ) $(OBJS) $(EXTOBJS) $(SETUP) $(PREP)
$(LIBRUBY_A): $(OBJS) $(DMYEXT) $(ARCHFILE)
-$(LIBRUBY_SO): $(OBJS) $(DLDOBJS) $(LIBRUBY_A) $(PREP)
+$(LIBRUBY_SO): $(OBJS) $(DLDOBJS) $(LIBRUBY_A) $(PREP) $(LIBRUBY_SO_UPDATE)
+
+$(LIBRUBY_EXTS):
+ @exit > $@
$(STATIC_RUBY)$(EXEEXT): $(MAINOBJ) $(DLDOBJS) $(EXTOBJS) $(LIBRUBY_A)
@$(RM) $@
@@ -80,64 +104,201 @@ ruby.imp: $(OBJS)
install: install-nodoc $(RDOCTARGET)
install-all: install-nodoc install-doc
-install-nodoc: install-local install-ext
+install-nodoc: pre-install-nodoc do-install-nodoc post-install-nodoc
+pre-install-nodoc:: pre-install-local pre-install-ext
+do-install-nodoc:
+ $(MINIRUBY) $(srcdir)/instruby.rb --make="$(MAKE)" $(INSTRUBY_ARGS) --mantype="$(MANTYPE)"
+post-install-nodoc:: post-install-local post-install-ext
+
install-local: pre-install-local do-install-local post-install-local
-install-ext: pre-install-ext do-install-ext post-install-ext
+pre-install-local:: pre-install-bin pre-install-lib pre-install-man
+do-install-local:
+ $(MINIRUBY) $(srcdir)/instruby.rb --make="$(MAKE)" $(INSTRUBY_ARGS) --install=local --mantype="$(MANTYPE)"
+loadpath: $(PREP)
+ $(MINIRUBY) -e 'p $$:'
-do-install-local: $(RBCONFIG)
- $(MINIRUBY) $(srcdir)/instruby.rb $(SCRIPT_ARGS) --mantype="$(MANTYPE)"
-do-install-ext: $(RBCONFIG)
- $(MINIRUBY) $(srcdir)/ext/extmk.rb $(EXTMK_ARGS) install
+post-install-local:: post-install-bin post-install-lib post-install-man
-install-bin: $(RBCONFIG)
- $(MINIRUBY) $(srcdir)/instruby.rb $(SCRIPT_ARGS) --install=bin
-install-lib: $(RBCONFIG)
- $(MINIRUBY) $(srcdir)/instruby.rb $(SCRIPT_ARGS) --install=lib
-install-man: $(RBCONFIG)
- $(MINIRUBY) $(srcdir)/instruby.rb $(SCRIPT_ARGS) --install=man --mantype="$(MANTYPE)"
+install-ext: pre-install-ext do-install-ext post-install-ext
+pre-install-ext:: pre-install-ext-arch pre-install-ext-comm
+do-install-ext:
+ $(MINIRUBY) $(srcdir)/instruby.rb --make="$(MAKE)" $(INSTRUBY_ARGS) --install=ext
+post-install-ext:: post-install-ext-arch post-install-ext-comm
+
+install-arch: pre-install-arch do-install-arch post-install-arch
+pre-install-arch:: pre-install-bin pre-install-ext-arch
+do-install-arch:
+ $(MINIRUBY) $(srcdir)/instruby.rb --make="$(MAKE)" $(INSTRUBY_ARGS) --install=bin --install=ext-arch
+post-install-arch:: post-install-bin post-install-ext-arch
+
+install-comm: pre-install-comm do-install-comm post-install-comm
+pre-install-comm:: pre-install-lib pre-install-ext-comm pre-install-man
+do-install-comm:
+ $(MINIRUBY) $(srcdir)/instruby.rb --make="$(MAKE)" $(INSTRUBY_ARGS) --install=lib --install=ext-comm --install=man
+post-install-comm:: post-install-lib post-install-ext-comm post-install-man
+
+install-bin: pre-install-bin do-install-bin post-install-bin
+pre-install-bin:: install-prereq
+do-install-bin:
+ $(MINIRUBY) $(srcdir)/instruby.rb --make="$(MAKE)" $(INSTRUBY_ARGS) --install=bin
+post-install-bin::
+ @$(NULLCMD)
+
+install-lib: pre-install-lib do-install-lib post-install-lib
+pre-install-lib:: install-prereq
+do-install-lib:
+ $(MINIRUBY) $(srcdir)/instruby.rb --make="$(MAKE)" $(INSTRUBY_ARGS) --install=lib
+post-install-lib::
+ @$(NULLCMD)
+
+install-ext-comm: pre-install-ext-comm do-install-ext-comm post-install-ext-comm
+pre-install-ext-comm:: install-prereq
+do-install-ext-comm:
+ $(MINIRUBY) $(srcdir)/instruby.rb --make="$(MAKE)" $(INSTRUBY_ARGS) --install=ext-comm
+post-install-ext-comm::
+ @$(NULLCMD)
+
+install-ext-arch: pre-install-ext-arch do-install-ext-arch post-install-ext-arch
+pre-install-ext-arch:: install-prereq
+do-install-ext-arch:
+ $(MINIRUBY) $(srcdir)/instruby.rb --make="$(MAKE)" $(INSTRUBY_ARGS) --install=ext-arch
+post-install-ext-arch::
+ @$(NULLCMD)
+
+install-man: pre-install-man do-install-man post-install-man
+pre-install-man:: install-prereq
+do-install-man:
+ $(MINIRUBY) $(srcdir)/instruby.rb --make="$(MAKE)" $(INSTRUBY_ARGS) --install=man --mantype="$(MANTYPE)"
+post-install-man::
+ @$(NULLCMD)
+
+what-where: no-install
+no-install: no-install-nodoc no-install-doc
+what-where-all: no-install-all
+no-install-all: no-install-nodoc
+
+what-where-nodoc: no-install-nodoc
+no-install-nodoc: pre-no-install-nodoc dont-install-nodoc post-no-install-nodoc
+pre-no-install-nodoc:: pre-no-install-local pre-no-install-ext
+dont-install-nodoc:
+ $(MINIRUBY) $(srcdir)/instruby.rb -n --make="$(MAKE)" $(INSTRUBY_ARGS) --mantype="$(MANTYPE)"
+post-no-install-nodoc:: post-no-install-local post-no-install-ext
-what-where-all no-install-all: no-install no-install-doc
-what-where no-install: no-install-local no-install-ext
what-where-local: no-install-local
-no-install-local: $(RBCONFIG)
- $(MINIRUBY) $(srcdir)/instruby.rb -n $(SCRIPT_ARGS) --mantype="$(MANTYPE)"
-what-where-ext: no-install-ext
-no-install-ext: $(RBCONFIG)
- $(MINIRUBY) $(srcdir)/ext/extmk.rb -n $(EXTMK_ARGS) install
+no-install-local: pre-no-install-local dont-install-local post-no-install-local
+pre-no-install-local:: pre-no-install-bin pre-no-install-lib pre-no-install-man
+dont-install-local:
+ $(MINIRUBY) $(srcdir)/instruby.rb -n --make="$(MAKE)" $(INSTRUBY_ARGS) --install=local --mantype="$(MANTYPE)"
+post-no-install-local:: post-no-install-bin post-no-install-lib post-no-install-man
-install-doc: pre-install-doc do-install-doc post-install-doc
+what-where-ext: no-install-ext
+no-install-ext: pre-no-install-ext dont-install-ext post-no-install-ext
+pre-no-install-ext:: pre-no-install-ext-arch pre-no-install-ext-comm
+dont-install-ext:
+ $(MINIRUBY) $(srcdir)/instruby.rb -n --make="$(MAKE)" $(INSTRUBY_ARGS) --install=ext
+post-no-install-ext:: post-no-install-ext-arch post-no-install-ext-comm
+
+what-where-arch: no-install-arch
+no-install-arch: pre-no-install-arch dont-install-arch post-no-install-arch
+pre-no-install-arch:: pre-no-install-bin pre-no-install-ext-arch
+dont-install-arch:
+ $(MINIRUBY) $(srcdir)/instruby.rb -n --make="$(MAKE)" $(INSTRUBY_ARGS) --install=bin --install=ext-arch
+post-no-install-arch:: post-no-install-lib post-no-install-man post-no-install-ext-arch
+
+what-where-comm: no-install-comm
+no-install-comm: pre-no-install-comm dont-install-comm post-no-install-comm
+pre-no-install-comm:: pre-no-install-lib pre-no-install-ext-comm pre-no-install-man
+dont-install-comm:
+ $(MINIRUBY) $(srcdir)/instruby.rb -n --make="$(MAKE)" $(INSTRUBY_ARGS) --install=lib --install=ext-comm --install=man
+post-no-install-comm:: post-no-install-lib post-no-install-ext-comm post-no-install-man
+
+what-where-bin: no-install-bin
+no-install-bin: pre-no-install-bin dont-install-bin post-no-install-bin
+pre-no-install-bin:: install-prereq
+dont-install-bin:
+ $(MINIRUBY) $(srcdir)/instruby.rb -n --make="$(MAKE)" $(INSTRUBY_ARGS) --install=bin
+post-no-install-bin::
+ @$(NULLCMD)
+
+what-where-lib: no-install-lib
+no-install-lib: pre-no-install-lib dont-install-lib post-no-install-lib
+pre-no-install-lib:: install-prereq
+dont-install-lib:
+ $(MINIRUBY) $(srcdir)/instruby.rb -n --make="$(MAKE)" $(INSTRUBY_ARGS) --install=lib
+post-no-install-lib::
+ @$(NULLCMD)
+
+what-where-ext-comm: no-install-ext-comm
+no-install-ext-comm: pre-no-install-ext-comm dont-install-ext-comm post-no-install-ext-comm
+pre-no-install-ext-comm:: install-prereq
+dont-install-ext-comm:
+ $(MINIRUBY) $(srcdir)/instruby.rb -n --make="$(MAKE)" $(INSTRUBY_ARGS) --install=ext-comm
+post-no-install-ext-comm::
+ @$(NULLCMD)
+
+what-where-ext-arch: no-install-ext-arch
+no-install-ext-arch: pre-no-install-ext-arch dont-install-ext-arch post-no-install-ext-arch
+pre-no-install-ext-arch:: install-prereq
+dont-install-ext-arch:
+ $(MINIRUBY) $(srcdir)/instruby.rb -n --make="$(MAKE)" $(INSTRUBY_ARGS) --install=ext-arch
+post-no-install-ext-arch::
+ @$(NULLCMD)
+
+what-where-man: no-install-man
+no-install-man: pre-no-install-man dont-install-man post-no-install-man
+pre-no-install-man:: install-prereq
+dont-install-man:
+ $(MINIRUBY) $(srcdir)/instruby.rb -n --make="$(MAKE)" $(INSTRUBY_ARGS) --install=man --mantype="$(MANTYPE)"
+post-no-install-man::
+ @$(NULLCMD)
+
+install-doc: rdoc pre-install-doc do-install-doc post-install-doc
+pre-install-doc:: install-prereq
do-install-doc: $(PROGRAM)
+ $(MINIRUBY) $(srcdir)/instruby.rb --make="$(MAKE)" $(INSTRUBY_ARGS) --install=rdoc --rdoc-output="$(RDOCOUT)"
+post-install-doc::
+ @$(NULLCMD)
+
+rdoc: $(PROGRAM) PHONY
@echo Generating RDoc documentation
- $(RUNRUBY) "$(srcdir)/bin/rdoc" --all --ri --op "$(RIDATADIR)" "$(srcdir)"
+ $(RUNRUBY) "$(srcdir)/bin/rdoc" --all --ri --op "$(RDOCOUT)" "$(srcdir)"
+
+what-where-doc: no-install-doc
+no-install-doc: pre-no-install-doc dont-install-doc post-no-install-doc
+pre-no-install-doc:: install-prereq
+dont-install-doc::
+ $(MINIRUBY) $(srcdir)/instruby.rb -n --make="$(MAKE)" $(INSTRUBY_ARGS) --install=rdoc --rdoc-output="$(RDOCOUT)"
+post-no-install-doc::
+ @$(NULLCMD)
-pre-install: pre-install-local pre-install-ext
-pre-install-local:: PHONY
- $(PREINSTALL)
-pre-install-ext:: PHONY
-pre-install-doc:: PHONY
+CLEAR_INSTALLED_LIST = clear-installed-list
-post-install: post-install-local post-install-ext
-post-install-local:: PHONY
-post-install-ext:: PHONY
-post-install-doc:: PHONY
+install-prereq: $(CLEAR_INSTALLED_LIST)
+
+clear-installed-list:
+ @exit > $(INSTALLED_LIST)
clean: clean-ext clean-local
clean-local::
- @$(RM) $(OBJS) $(MAINOBJ) $(WINMAINOBJ) $(LIBRUBY_A) $(LIBRUBY_SO) $(LIBRUBY) $(LIBRUBY_ALIASES)
- @$(RM) $(PROGRAM) $(WPROGRAM) miniruby$(EXEEXT) dmyext.$(OBJEXT) $(ARCHFILE)
+ @$(RM) $(OBJS) $(MINIOBJS) $(MAINOBJ) $(LIBRUBY_A) $(LIBRUBY_SO) $(LIBRUBY) $(LIBRUBY_ALIASES)
+ @$(RM) $(PROGRAM) $(WPROGRAM) miniruby$(EXEEXT) dmyext.$(OBJEXT) $(ARCHFILE) .*.time
+ @$(RM) y.tab.c y.output
clean-ext:
- @-$(MINIRUBY) $(srcdir)/ext/extmk.rb $(EXTMK_ARGS) clean
+ @-$(MINIRUBY) $(srcdir)/ext/extmk.rb --make="$(MAKE)" $(EXTMK_ARGS) clean
distclean: distclean-ext distclean-local
distclean-local:: clean-local
@$(RM) $(MKFILES) config.h rbconfig.rb
@$(RM) config.cache config.log config.status
- @$(RM) *~ *.bak *.stackdump core *.core gmon.out y.tab.c y.output $(PREP)
+ @$(RM) *~ *.bak *.stackdump core *.core gmon.out $(PREP)
distclean-ext:
- @-$(MINIRUBY) $(srcdir)/ext/extmk.rb $(EXTMK_ARGS) distclean
+ @-$(MINIRUBY) $(srcdir)/ext/extmk.rb --make="$(MAKE)" $(EXTMK_ARGS) distclean
-realclean:: distclean
+realclean:: realclean-ext realclean-local
+realclean-local:: distclean-local
@$(RM) parse.c lex.c
+realclean-ext::
+ @-$(MINIRUBY) $(srcdir)/ext/extmk.rb --make="$(MAKE)" $(EXTMK_ARGS) realclean
check: test test-all
@@ -145,13 +306,13 @@ test: miniruby$(EXEEXT) $(RBCONFIG) $(PROGRAM) PHONY
@$(MINIRUBY) $(srcdir)/rubytest.rb
test-all:
- $(RUNRUBY) -C "$(srcdir)/test" runner.rb --runner=$(TESTUI) $(TESTS)
+ $(RUNRUBY) "$(srcdir)/test/runner.rb" --basedir="$(TESTSDIR)" --runner=$(TESTUI) $(TESTS)
extconf:
- $(MINIRUBY) -I$(srcdir)/lib -run -e mkdir -- -p "$(EXTCONFDIR)"
+ $(MINIRUBY) -run -e mkdir -- -p "$(EXTCONFDIR)"
$(RUNRUBY) -C "$(EXTCONFDIR)" $(EXTCONF) $(EXTCONFARGS)
-$(RBCONFIG): $(srcdir)/mkconfig.rb config.status $(PREP)
+$(RBCONFIG): $(srcdir)/mkconfig.rb config.status $(srcdir)/version.h $(PREP)
@$(MINIRUBY) $(srcdir)/mkconfig.rb -timestamp=$@ \
-install_name=$(RUBY_INSTALL_NAME) \
-so_name=$(RUBY_SO_NAME) rbconfig.rb
@@ -189,6 +350,8 @@ nt.$(OBJEXT): {$(VPATH)}nt.c
x68.$(OBJEXT): {$(VPATH)}x68.c
os2.$(OBJEXT): {$(VPATH)}os2.c
dl_os2.$(OBJEXT): {$(VPATH)}dl_os2.c
+ia64.$(OBJEXT): {$(VPATH)}ia64.s
+ $(CC) $(CFLAGS) -c $<
# when I use -I., there is confliction at "OpenFile"
# so, set . into environment varible "include"
@@ -200,7 +363,8 @@ array.$(OBJEXT): {$(VPATH)}array.c {$(VPATH)}ruby.h config.h \
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
{$(VPATH)}util.h {$(VPATH)}st.h
bignum.$(OBJEXT): {$(VPATH)}bignum.c {$(VPATH)}ruby.h config.h \
- {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h
+ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
+ {$(VPATH)}rubysig.h
class.$(OBJEXT): {$(VPATH)}class.c {$(VPATH)}ruby.h config.h \
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
{$(VPATH)}rubysig.h {$(VPATH)}node.h {$(VPATH)}st.h
@@ -212,13 +376,13 @@ dir.$(OBJEXT): {$(VPATH)}dir.c {$(VPATH)}ruby.h config.h \
dln.$(OBJEXT): {$(VPATH)}dln.c {$(VPATH)}ruby.h config.h \
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
{$(VPATH)}dln.h
-dmydln.$(OBJEXT): {$(VPATH)}dmydln.c {$(VPATH)}dln.c {$(VPATH)}ruby.h \
- config.h {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
- {$(VPATH)}dln.h
+dmydln.$(OBJEXT): {$(VPATH)}dmydln.c dln.$(OBJEXT)
dmyext.$(OBJEXT): {$(VPATH)}dmyext.c
enum.$(OBJEXT): {$(VPATH)}enum.c {$(VPATH)}ruby.h config.h \
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
{$(VPATH)}node.h {$(VPATH)}util.h
+enumerator.$(OBJEXT): {$(VPATH)}enumerator.c {$(VPATH)}ruby.h config.h \
+ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h
error.$(OBJEXT): {$(VPATH)}error.c {$(VPATH)}ruby.h config.h \
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
{$(VPATH)}env.h {$(VPATH)}st.h
diff --git a/compar.c b/compar.c
index 3cd3216b77..1488b2c65d 100644
--- a/compar.c
+++ b/compar.c
@@ -2,8 +2,8 @@
compar.c -
- $Author: dave $
- $Date: 2003/12/19 00:01:18 $
+ $Author$
+ $Date$
created at: Thu Aug 26 14:39:48 JST 1993
Copyright (C) 1993-2003 Yukihiro Matsumoto
diff --git a/configure.in b/configure.in
index 3dbb527849..62b34a8c62 100644
--- a/configure.in
+++ b/configure.in
@@ -1,7 +1,7 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT()
-AC_PREREQ(2.58)
+AC_PREREQ(2.60)
AC_DEFUN([RUBY_MINGW32],
[case "$host_os" in
@@ -44,10 +44,20 @@ fi
GNU_LD=$rb_cv_prog_gnu_ld
AC_SUBST(GNU_LD)])
+unset GREP_OPTIONS
rb_version=`grep RUBY_VERSION $srcdir/version.h`
MAJOR=`expr "$rb_version" : '#define RUBY_VERSION "\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*"'`
MINOR=`expr "$rb_version" : '#define RUBY_VERSION "[0-9][0-9]*\.\([0-9][0-9]*\)\.[0-9][0-9]*"'`
TEENY=`expr "$rb_version" : '#define RUBY_VERSION "[0-9][0-9]*\.[0-9][0-9]*\.\([0-9][0-9]*\)"'`
+if test "$MAJOR" = ""; then
+ AC_MSG_ERROR(could not determine MAJOR number from version.h)
+fi
+if test "$MINOR" = ""; then
+ AC_MSG_ERROR(could not determine MINOR number from version.h)
+fi
+if test "$TEENY" = ""; then
+ AC_MSG_ERROR(could not determine TEENY number from version.h)
+fi
AC_SUBST(MAJOR)
AC_SUBST(MINOR)
AC_SUBST(TEENY)
@@ -67,6 +77,7 @@ then
AC_MSG_ERROR(cached CC is different -- throw away $cache_file
(it is also a good idea to do 'make clean' before compiling))
fi
+test -z "$CC" || ac_cv_prog_CC="$CC"
if test "$program_prefix" = NONE; then
program_prefix=
@@ -75,6 +86,7 @@ AC_CANONICAL_TARGET
target_os=`echo $target_os | sed 's/linux-gnu$/linux/;s/linux-gnu/linux-/'`
ac_install_sh='' # unusable for extension libraries.
+ifelse(currently,disabled, [
dnl checks for fat-binary
AC_ARG_ENABLE(fat-binary,
[ --enable-fat-binary=ARCHS
@@ -128,6 +140,7 @@ if test "$fat_binary" != no; then
done
AC_DEFINE(NEXT_FAT_BINARY)
fi
+], [fat_binary=no])
case $target_cpu in
i?86) frame_address=yes;;
@@ -149,6 +162,11 @@ if test x"${build}" != x"${host}"; then
fi
AC_PROG_CC
AC_PROG_GCC_TRADITIONAL
+if test "$GCC" = yes; then
+ linker_flag=-Wl,
+else
+ linker_flag=
+fi
RUBY_PROG_GNU_LD
RUBY_CPPOUTFILE
@@ -199,6 +217,9 @@ cygwin*|mingw*)
esac], [with_winsock2=no])
if test "$with_winsock2" = yes; then
AC_DEFINE(USE_WINSOCK2)
+ COMMON_HEADERS="ws2tcpip.h winsock2.h windows.h"
+ else
+ COMMON_HEADERS="windows.h winsock.h"
fi
esac
: ${enable_shared=yes}
@@ -229,7 +250,12 @@ else
fi
dnl check for large file stuff
+mv confdefs.h confdefs1.h
+: > confdefs.h
AC_SYS_LARGEFILE
+mv confdefs.h largefile.h
+mv confdefs1.h confdefs.h
+cat largefile.h >> confdefs.h
AC_CHECK_TYPES([long long, off_t])
@@ -286,16 +312,42 @@ if test "$rb_cv_stdarg" = yes; then
AC_DEFINE(HAVE_STDARG_PROTOTYPES)
fi
-AC_CACHE_CHECK([for noreturn], rb_cv_noreturn,
-[rb_cv_noreturn=x
-for mac in "x __attribute__ ((noreturn))" "__declspec(noreturn) x" x; do
+AC_DEFUN([RUBY_FUNC_ATTRIBUTE], [dnl
+m4_ifval([$2], dnl
+ [AS_VAR_PUSHDEF([attrib],[$2])], dnl
+ [AS_VAR_PUSHDEF([attrib],[FUNC_]AS_TR_CPP($1))] dnl
+)dnl
+m4_ifval([$3], dnl
+ [AS_VAR_PUSHDEF([rbcv],[$3])], dnl
+ [AS_VAR_PUSHDEF([rbcv],[rb_cv_func_][$1])]dnl
+)dnl
+AC_CACHE_CHECK(for [$1] function attribute, rbcv,
+[rbcv=x
+if test "${ac_c_werror_flag+set}"; then
+ rb_c_werror_flag="$ac_c_werror_flag"
+else
+ unset rb_c_werror_flag
+fi
+ac_c_werror_flag=yes
+for mac in "__attribute__ (($1)) x" "x __attribute__ (($1))" "__declspec($1) x" x; do
AC_TRY_COMPILE(
- [#define NORETURN(x) $mac
-NORETURN(void exit(int x));],
- [],
- [rb_cv_noreturn="$mac"; break])
-done])
-AC_DEFINE_UNQUOTED([NORETURN(x)], $rb_cv_noreturn)
+ [#define ]attrib[(x) $mac
+ ]attrib[(void conftest_attribute_check(void));], [],
+ [rbcv="$mac"; break])
+done
+if test "${rb_c_werror_flag+set}"; then
+ ac_c_werror_flag="$rb_c_werror_flag"
+else
+ unset ac_c_werror_flag
+fi
+])
+AC_DEFINE_UNQUOTED(attrib[(x)], $rbcv)
+AS_VAR_POPDEF([attrib])
+AS_VAR_POPDEF([rbcv])
+])
+
+RUBY_FUNC_ATTRIBUTE(noreturn, NORETURN)
+RUBY_FUNC_ATTRIBUTE(noinline, NOINLINE)
AC_CACHE_CHECK([for RUBY_EXTERN], rb_cv_ruby_extern,
[rb_cv_ruby_extern=no
@@ -324,23 +376,39 @@ AC_ARG_ENABLE(pthread,
[ --enable-pthread use pthread library.],
[enable_pthread=$enableval], [enable_pthread=no])
+AC_ARG_ENABLE(fastthread,
+ [ --disable-fastthread do not use the fastthread mutex], [
+ : handled by ext/thread/extconf.rb
+ ])
+
dnl Checks for libraries.
case "$target_os" in
nextstep*) ;;
openstep*) ;;
rhapsody*) ;;
-darwin*) LIBS="-lobjc $LIBS";;
+darwin*) LIBS="-lobjc $LIBS"
+ CPPFLAGS="$CPPFLAGS -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE"
+ AC_TRY_CPP([#include <AvailabilityMacros.h>
+ #if MAC_OS_X_VERSION_MAX_ALLOWED <= 1040
+ #error pre OS X 10.4
+ [!<===== pre OS X 10.4 =====>]
+ #endif
+ ],
+ [
+ test "x$target_cpu" = xpowerpc && ac_cv_header_ucontext_h=no
+ ],
+ [
+ AC_DEFINE(BROKEN_SETREUID, 1)
+ AC_DEFINE(BROKEN_SETREGID, 1)
+ ])
+ ;;
hpux*) LIBS="-lm $LIBS"
ac_cv_c_inline=no;;
human*) ac_cv_func_getpgrp_void=yes
ac_cv_func_setitimer=no
;;
beos*) ac_cv_func_link=no;;
-cygwin*) rb_cv_have_daylight=no
- ac_cv_var_tzname=no
- ac_cv_func__setjmp=no
- ac_cv_func_setitimer=no
- ;;
+cygwin*) ;;
mingw*) if test "$with_winsock2" = yes; then
LIBS="-lws2_32 $LIBS"
else
@@ -374,6 +442,7 @@ mingw*) if test "$with_winsock2" = yes; then
rb_cv_binary_elf=no
rb_cv_negative_time_t=no
enable_pthread=no
+ ac_cv_func_fcntl=yes
;;
os2-emx*) LIBS="-lm $LIBS"
ac_cv_lib_dir_opendir=no;;
@@ -381,8 +450,11 @@ msdosdjgpp*) LIBS="-lm $LIBS"
ac_cv_func_getpgrp_void=yes
ac_cv_func_setitimer=no
ac_cv_sizeof_rlim_t=4
+ ac_cv_func_setrlimit=no
;;
bsdi*) LIBS="-lm $LIBS"
+ AC_DEFINE(BROKEN_SETREUID, 1)
+ AC_DEFINE(BROKEN_SETREGID, 1)
ac_cv_sizeof_rlim_t=8;;
freebsd*) LIBS="-lm $LIBS"
AC_CACHE_CHECK([whether -lxpg4 has to be linked],
@@ -433,6 +505,7 @@ esac
AC_CHECK_LIB(crypt, crypt)
AC_CHECK_LIB(dl, dlopen) # Dynamic linking for SunOS/Solaris and SYSV
AC_CHECK_LIB(dld, shl_load) # Dynamic linking for HP-UX
+AC_CHECK_LIB(rt, clock_gettime) # GNU/Linux
case "$target_cpu" in
alpha*) case "$target_os"::"$GCC" in
@@ -449,7 +522,7 @@ AC_CHECK_HEADERS(stdlib.h string.h unistd.h limits.h sys/file.h sys/ioctl.h sys/
fcntl.h sys/fcntl.h sys/select.h sys/time.h sys/times.h sys/param.h\
syscall.h pwd.h grp.h a.out.h utime.h memory.h direct.h sys/resource.h \
sys/mkdev.h sys/utime.h netinet/in_systm.h float.h ieeefp.h pthread.h \
- ucontext.h intrinsics.h)
+ ucontext.h intrinsics.h time.h)
dnl Check additional types.
AC_CHECK_SIZEOF(rlim_t, 0, [
@@ -474,25 +547,150 @@ AC_STRUCT_ST_BLKSIZE
AC_STRUCT_ST_BLOCKS
AC_STRUCT_ST_RDEV
+dnl RUBY_DEFINT TYPENAME, SIZE, [SIGNED-OR-UNSIGNED], [INCLUDES = DEFAULT-INCLUDES]
+AC_DEFUN([RUBY_DEFINT], [dnl
+AC_CACHE_CHECK([for $1], [rb_cv_type_$1],
+[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT([$4])
+typedef $1 t; int s = sizeof(t) == 42;])],
+ [rb_cv_type_$1=yes],
+ [AS_CASE([m4_bmatch([$2], [^[1-9][0-9]*$], $2, [$ac_cv_sizeof_]AS_TR_SH($2))],
+ ["1"], [ rb_cv_type_$1="m4_if([$3], [], [signed ], [$3 ])char"],
+ ["$ac_cv_sizeof_short"], [ rb_cv_type_$1="m4_if([$3], [], [], [$3 ])short"],
+ ["$ac_cv_sizeof_int"], [ rb_cv_type_$1="m4_if([$3], [], [], [$3 ])int"],
+ ["$ac_cv_sizeof_long"], [ rb_cv_type_$1="m4_if([$3], [], [], [$3 ])long"],
+ ["$ac_cv_sizeof_long_long"], [ rb_cv_type_$1="m4_if([$3], [], [], [$3 ])long long"],
+ ["$ac_cv_sizeof___int64"], [ rb_cv_type_$1="m4_if([$3], [], [], [$3 ])__int64"],
+ [ rb_cv_type_$1=no])])])
+if test "${rb_cv_type_$1}" != no; then
+ AC_DEFINE([HAVE_]AS_TR_CPP($1), 1)
+ if test "${rb_cv_type_$1}" = yes; then
+ m4_bmatch([$2], [^[1-9][0-9]*$], [AC_CHECK_SIZEOF([$1], 0, [AC_INCLUDES_DEFAULT([$4])])],
+ [RUBY_CHECK_SIZEOF([$1], [$2], [], [AC_INCLUDES_DEFAULT([$4])])])
+ else
+ AC_DEFINE_UNQUOTED($1, [$rb_cv_type_$1])
+ AC_DEFINE_UNQUOTED([SIZEOF_]AS_TR_CPP($1), [SIZEOF_]AS_TR_CPP([$rb_cv_type_$1]))
+ fi
+fi
+])
+
+RUBY_DEFINT(int8_t, 1)
+RUBY_DEFINT(uint8_t, 1, unsigned)
+RUBY_DEFINT(int16_t, 2)
+RUBY_DEFINT(uint16_t, 2, unsigned)
+RUBY_DEFINT(int32_t, 4)
+RUBY_DEFINT(uint32_t, 4, unsigned)
+RUBY_DEFINT(int64_t, 8)
+RUBY_DEFINT(uint64_t, 8, unsigned)
+RUBY_DEFINT(int128_t, 16)
+RUBY_DEFINT(uint128_t, 16, unsigned)
+AC_CHECK_TYPES([struct timezone], [], [], [@%:@ifdef HAVE_TIME_H
+@%:@ include <time.h>
+@%:@endif
+@%:@ifdef HAVE_SYS_TIME_H
+@%:@ include <sys/time.h>
+@%:@endif])
+
dnl Checks for library functions.
AC_TYPE_GETGROUPS
AC_TYPE_SIGNAL
-AC_FUNC_ALLOCA
+case "${target_cpu}-${target_os}" in
+powerpc-darwin*)
+ AC_LIBSOURCES(alloca.c)
+ AC_SUBST([ALLOCA], [\${LIBOBJDIR}alloca.${ac_objext}])
+ AC_DEFINE(C_ALLOCA)
+ AC_DEFINE_UNQUOTED(alloca, alloca)
+ ;;
+*)
+ AC_FUNC_ALLOCA
+ ;;
+esac
AC_FUNC_MEMCMP
AC_FUNC_FSEEKO
AC_CHECK_FUNCS(ftello)
+
+# http://sources.redhat.com/ml/libc-hacker/2005-08/msg00008.html
+# Debian GNU/Linux Etch's libc6.1 2.3.6.ds1-13etch5 has this problem.
+# Debian GNU/Linux Lenny's libc6.1 2.7-10 has no problem.
+AC_CACHE_CHECK(for broken erfc of glibc-2.3.6 on IA64, rb_cv_broken_glibc_ia64_erfc,
+ [AC_TRY_RUN([
+#include <math.h>
+int
+main()
+{
+ erfc(10000.0);
+ return 0;
+}
+],
+ rb_cv_broken_glibc_ia64_erfc=no,
+ rb_cv_broken_glibc_ia64_erfc=yes,
+ rb_cv_broken_glibc_ia64_erfc=no)])
+case $rb_cv_broken_glibc_ia64_erfc in
+ yes) ac_cv_func_erf=no;;
+esac
+
AC_REPLACE_FUNCS(dup2 memmove strcasecmp strncasecmp strerror strftime\
strchr strstr strtoul crypt flock vsnprintf\
isnan finite isinf hypot acosh erf)
AC_CHECK_FUNCS(fmod killpg wait4 waitpid syscall chroot fsync getcwd eaccess\
- truncate chsize times utimes fcntl lockf lstat symlink link\
+ truncate ftruncate chsize times utimes fcntl lockf lstat symlink link\
readlink setitimer setruid seteuid setreuid setresuid\
setproctitle setrgid setegid setregid setresgid issetugid pause\
lchown lchmod getpgrp setpgrp getpgid setpgid initgroups\
getgroups setgroups getpriority getrlimit setrlimit sysconf\
group_member dlopen sigprocmask\
- sigaction _setjmp setsid telldir seekdir fchmod mktime timegm\
- cosh sinh tanh setuid setgid setenv unsetenv)
+ sigaction sigsetjmp _setjmp _longjmp setsid telldir seekdir fchmod\
+ mktime timegm gettimeofday\
+ cosh sinh tanh round setuid setgid setenv unsetenv)
+
+AC_CACHE_CHECK(for __builtin_setjmp, ac_cv_func___builtin_setjmp,
+[AC_TRY_LINK([@%:@include <setjmp.h>
+ jmp_buf jb; void t(v) int v; {__builtin_longjmp(jb, v);}],
+ [__builtin_setjmp(jb);],
+ [ac_cv_func___builtin_setjmp=yes],
+ [ac_cv_func___builtin_setjmp=no])
+])
+
+test x$ac_cv_func__longjmp = xno && ac_cv_func__setjmp=no
+
+AC_MSG_CHECKING(for setjmp type)
+AC_ARG_WITH(setjmp-type,
+ [ --with-setjmp-type select setjmp type], [
+ case $withval in
+ __builtin_setjmp) setjmp_prefix=__builtin_;;
+ _setjmp) setjmp_prefix=_;;
+ sigsetjmp) setjmp_prefix=sig;;
+ setjmp) setjmp_prefix=;;
+ '') unset setjmp_prefix;;
+ *) AC_MSG_ERROR(invalid setjmp type: $withval);;
+ esac], [unset setjmp_prefix])
+if test ${setjmp_prefix+set}; then
+ if test "${setjmp_prefix}" && eval test '$ac_cv_func_'${setjmp_prefix}setjmp = no; then
+ AC_MSG_ERROR(${setjmp_prefix}setjmp is not available)
+ fi
+elif test "$ac_cv_func___builtin_setjmp" = yes; then
+ setjmp_prefix=__builtin_
+elif test "$ac_cv_func__setjmp" = yes; then
+ setjmp_prefix=_
+elif test "$ac_cv_func_sigsetjmp" = yes; then
+ case $target_os in
+ solaris*|cygwin*)
+ setjmp_prefix=;;
+ *)
+ setjmp_prefix=sig;;
+ esac
+else
+ setjmp_prefix=
+fi
+if test x$setjmp_prefix = xsig; then
+ setjmp_sigmask=yes
+else
+ unset setjmp_sigmask
+fi
+AC_MSG_RESULT(${setjmp_prefix}setjmp)
+AC_DEFINE_UNQUOTED([RUBY_SETJMP(env)], [${setjmp_prefix}setjmp(env${setjmp_sigmask+,0})])
+AC_DEFINE_UNQUOTED([RUBY_LONGJMP(env,val)], [${setjmp_prefix}longjmp(env,val)])
+AC_DEFINE_UNQUOTED(RUBY_JMP_BUF, ${setjmp_sigmask+${setjmp_prefix}}jmp_buf)
+
AC_ARG_ENABLE(setreuid,
[ --enable-setreuid use setreuid()/setregid() according to need even if obsolete.],
[use_setreuid=$enableval])
@@ -518,6 +716,50 @@ AC_CACHE_CHECK(for external int daylight, rb_cv_have_daylight,
if test "$rb_cv_have_daylight" = yes; then
AC_DEFINE(HAVE_DAYLIGHT)
fi
+AC_DEFUN([RUBY_CHECK_VARTYPE], [dnl
+AC_CACHE_CHECK([for external $1], rb_cv_var_$1,
+ [rb_cv_var_$1=no
+ AC_TRY_COMPILE([
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 1
+#endif
+$2
+;
+const volatile void *volatile t;],
+ [t = &(&$1)[0];],
+ [for t in $3; do
+ AC_TRY_COMPILE([
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 1
+#endif
+$2
+;
+extern $t $1;
+const volatile void *volatile t;],
+ [t = &(&$1)[0];],
+ [rb_cv_var_$1=$t; break])
+ done])])
+if test "[$rb_cv_var_]$1" != no; then
+ AC_DEFINE([HAVE_VAR_]m4_toupper($1))
+ AC_DEFINE_UNQUOTED([TYPEOF_VAR_]m4_toupper($1), $rb_cv_var_$1)
+fi])
+RUBY_CHECK_VARTYPE(timezone, [@%:@include <time.h>], [long int])
+RUBY_CHECK_VARTYPE(altzone, [@%:@include <time.h>], [long int])
+if test "$rb_cv_var_timezone" = no; then
+ AC_CHECK_FUNCS(timezone)
+ if test "$ac_cv_func_timezone" = yes; then
+ AC_CACHE_CHECK([whether timezone requires zero arguments], rb_cv_func_timezone_void,
+ [AC_TRY_COMPILE([@%:@include <time.h>],
+ [(void)timezone(0, 0);],
+ [rb_cv_func_timezone_void=no],
+ [rb_cv_func_timezone_void=yes])]
+ )
+ if test $rb_cv_func_timezone_void = yes; then
+ AC_DEFINE(TIMEZONE_VOID)
+ fi
+ fi
+fi
+
AC_CACHE_CHECK(for negative time_t for gmtime(3), rb_cv_negative_time_t,
[AC_TRY_RUN([
#include <time.h>
@@ -559,6 +801,7 @@ fi
if test "$ac_cv_func_sigprocmask" = yes && test "$ac_cv_func_sigaction" = yes; then
AC_DEFINE(POSIX_SIGNAL)
else
+ AC_CHECK_FUNCS(sigsetmask)
AC_CACHE_CHECK(for BSD signal semantics, rb_cv_bsd_signal,
[AC_TRY_RUN([
#include <stdio.h>
@@ -581,7 +824,7 @@ main()
],
rb_cv_bsd_signal=yes,
rb_cv_bsd_signal=no,
- rb_cv_bsd_signal=no)])
+ rb_cv_bsd_signal=$ac_cv_func_sigsetmask)])
if test "$rb_cv_bsd_signal" = yes; then
AC_DEFINE(BSD_SIGNAL)
fi
@@ -596,6 +839,21 @@ AC_C_CHAR_UNSIGNED
AC_C_INLINE
AC_C_VOLATILE
+if test x"$target_cpu" = xia64; then
+ AC_LIBOBJ([ia64])
+ AC_CACHE_CHECK(for __libc_ia64_register_backing_store_base,
+ rb_cv___libc_ia64_register_backing_store_base,
+ [rb_cv___libc_ia64_register_backing_store_base=no
+ AC_TRY_LINK(
+ [extern unsigned long __libc_ia64_register_backing_store_base;],
+ [unsigned long p = __libc_ia64_register_backing_store_base;
+ printf("%ld\n", p);],
+ [rb_cv___libc_ia64_register_backing_store_base=yes])])
+ if test $rb_cv___libc_ia64_register_backing_store_base = yes; then
+ AC_DEFINE(HAVE___LIBC_IA64_REGISTER_BACKING_STORE_BASE)
+ fi
+fi
+
AC_CACHE_CHECK(whether right shift preserve sign bit, rb_cv_rshift_sign,
[AC_TRY_RUN([
int
@@ -828,7 +1086,7 @@ if test x"$enable_pthread" = xyes; then
fi
fi
if test x"$ac_cv_header_ucontext_h" = xyes; then
- if test x"$target_cpu" = xia64 -o x"$rb_with_pthread" = xyes; then
+ if test x"$rb_with_pthread" = xyes; then
AC_CHECK_FUNCS(getcontext setcontext)
fi
fi
@@ -902,7 +1160,6 @@ AC_SUBST(DLEXT2)dnl
AC_SUBST(LIBEXT)dnl
STATIC=
-: ${LIBPATHFLAG=' -L"%s"'}
: ${PATHFLAG=''}
if test "$with_dln_a_out" != yes; then
@@ -927,11 +1184,22 @@ if test "$with_dln_a_out" != yes; then
esac
fi
+
+ AC_ARG_ENABLE(rpath,
+ [ --disable-rpath embed run path into extension libraries.],
+ [enable_rpath=$enableval], [enable_rpath="$rb_cv_binary_elf"])
+ if test "$enable_rpath" = yes; then
+ RPATHFLAG=" ${linker_flag}-R%1\$-s"
+ fi
+
case "$target_os" in
hpux*) DLDFLAGS="$DLDFLAGS -E"
: ${LDSHARED='ld -b'}
XLDFLAGS="$XLDFLAGS -Wl,-E"
: ${LIBPATHENV=SHLIB_PATH}
+ if test "$rb_cv_prog_gnu_ld" = no; then
+ RPATHFLAG=' +b %1$-s'
+ fi
rb_cv_dlopen=yes;;
solaris*) if test "$GCC" = yes; then
: ${LDSHARED='$(CC) -shared'}
@@ -966,7 +1234,7 @@ if test "$with_dln_a_out" != yes; then
rb_cv_dlopen=yes ;;
interix*) : ${LDSHARED="$CC -shared"}
XLDFLAGS="$XLDFLAGS -Wl,-E"
- LIBPATHFLAG=" -L'%1\$-s'"
+ LIBPATHFLAG=" -L%1\$-s"
rb_cv_dlopen=yes ;;
freebsd*|dragonfly*) : ${LDSHARED="$CC -shared"}
if test "$rb_cv_binary_elf" = yes; then
@@ -995,14 +1263,13 @@ if test "$with_dln_a_out" != yes; then
: ${LIBPATHENV=DYLD_LIBRARY_PATH}
rb_cv_dlopen=yes ;;
aix*) if test "$GCC" = yes; then
- : ${LDSHARED='gcc -shared'}
- DLDFLAGS='-Wl,-G -eInit_$(TARGET)'
- LDFLAGS='-Wl,-brtl -Wl,-bE:ruby.imp'
- else
- : ${LDSHARED='/usr/ccs/bin/ld'}
- DLDFLAGS='-G -eInit_$(TARGET)'
- LDFLAGS="-brtl -bE:ruby.imp"
- fi
+ : ${LDSHARED='$(CC) -shared'}
+ else
+ : ${LDSHARED='$(CC)'}
+ fi
+ LDSHARED="$LDSHARED ${linker_flag}-G"
+ DLDFLAGS='-eInit_$(TARGET)'
+ XLDFLAGS="${linker_flag}-bE:ruby.imp ${linker_flag}-brtl"
: ${ARCHFILE="ruby.imp"}
TRY_LINK='$(CC) $(LDFLAGS) -oconftest $(INCFLAGS) -I$(hdrdir) $(CPPFLAGS)'
TRY_LINK="$TRY_LINK"' $(CFLAGS) $(src) $(LIBPATH) $(LOCAL_LIBS) $(LIBS)'
@@ -1031,7 +1298,7 @@ if test "$with_dln_a_out" != yes; then
rb_cv_dlopen=yes;;
cygwin*|mingw*) : ${LDSHARED="${CC} -shared -s"}
XLDFLAGS="$XLDFLAGS -Wl,--stack,0x02000000"
- DLDFLAGS="${DLDFLAGS} -Wl,--enable-auto-import,--export-all"
+ DLDFLAGS="${DLDFLAGS} -Wl,--enable-auto-image-base,--enable-auto-import,--export-all"
: ${LIBPATHENV=""}
rb_cv_dlopen=yes ;;
hiuxmpp) : ${LDSHARED='ld -r'} ;;
@@ -1042,19 +1309,13 @@ if test "$with_dln_a_out" != yes; then
*) : ${LDSHARED='ld'} ;;
esac
AC_MSG_RESULT($rb_cv_dlopen)
-
- AC_ARG_ENABLE(rpath,
- [ --disable-rpath embed run path into extension libraries.],
- [enable_rpath=$enableval], [enable_rpath="$rb_cv_binary_elf"])
- if test "$enable_rpath" = yes; then
- LIBPATHFLAG=" -L'%1\$-s'"
- if test "$GCC" = yes; then
- RPATHFLAG=" -Wl,-R'%1\$-s'"
- else
- RPATHFLAG=" -R'%1\$-s'"
- fi
- fi
fi
+case ${RPATHFLAG} in
+*'%1$'*)
+ : ${LIBPATHFLAG=' -L%1$-s'};;
+*)
+ : ${LIBPATHFLAG=' -L%s'};;
+esac
AC_SUBST(LINK_SO)
AC_SUBST(LIBPATHFLAG)
AC_SUBST(RPATHFLAG)
@@ -1087,30 +1348,24 @@ if test "$dln_a_out_works" = yes; then
STATIC=-Bstatic
fi
DLEXT=so
- AC_DEFINE(DLEXT, ".so")
CCDLFLAGS=
else
case "$target_os" in
- hpux*) DLEXT=sl
- AC_DEFINE(DLEXT, ".sl");;
- nextstep*) DLEXT=bundle
- AC_DEFINE(DLEXT, ".bundle");;
- openstep*) DLEXT=bundle
- AC_DEFINE(DLEXT, ".bundle");;
- rhapsody*) DLEXT=bundle
- AC_DEFINE(DLEXT, ".bundle");;
- darwin*) DLEXT=bundle
- AC_DEFINE(DLEXT, ".bundle");;
- os2-emx*) DLEXT=dll
- AC_DEFINE(DLEXT, ".dll");;
- cygwin*|mingw*) DLEXT=so
- AC_DEFINE(DLEXT, ".so")
- DLEXT2=dll
- AC_DEFINE(DLEXT2, ".dll");;
- *) DLEXT=so
- AC_DEFINE(DLEXT, ".so");;
+ hpux*) DLEXT=sl;;
+ nextstep*|openstep*|rhapsody*|darwin*)
+ DLEXT=bundle;;
+ os2-emx*) DLEXT=dll;;
+ cygwin*|mingw*)
+ DLEXT=so DLEXT2=dll;;
+ *) DLEXT=so;;
esac
fi
+len=2 # .rb
+n=`expr "$DLEXT" : '.*'`; test "$n" -gt "$len" && len=$n
+n=`expr "$DLEXT2" : '.*'`; test "$n" -gt "$len" && len=$n
+AC_DEFINE_UNQUOTED(DLEXT_MAXLEN, `expr $len + 1`)
+test ".$DLEXT" = "." || AC_DEFINE_UNQUOTED(DLEXT, ".$DLEXT")
+test ".$DLEXT2" = "." || AC_DEFINE_UNQUOTED(DLEXT2, ".$DLEXT2")
AC_SUBST(STRIP)dnl
if test "$with_dln_a_out" = yes; then
@@ -1146,7 +1401,7 @@ case "$target_os" in
human*)
AC_CHECK_LIB(signal, _harderr)
AC_CHECK_LIB(hmem, hmemset)
- AC_CHECK_FUNCS(select gettimeofday)
+ AC_CHECK_FUNCS(select)
AC_CACHE_CHECK(whether PD libc _dtos18 fail to convert big number,
rb_cv_missing__dtos18,
[AC_TRY_RUN(
@@ -1219,9 +1474,10 @@ if test x"$cross_compiling" = xyes; then
PREP=fake.rb
RUNRUBY='$(MINIRUBY) -I`cd $(srcdir)/lib; pwd`'
else
- MINIRUBY='./miniruby$(EXEEXT)'
+ MINIRUBY='./miniruby$(EXEEXT) -I$(srcdir)/lib'
+ MINIRUBY="$MINIRUBY"' -I$(EXTOUT)/common -I./- -r$(srcdir)/ext/purelib.rb'
PREP='miniruby$(EXEEXT)'
- RUNRUBY='$(MINIRUBY) $(srcdir)/runruby.rb --extout=$(EXTOUT) --'
+ RUNRUBY='$(MINIRUBY) $(srcdir)/runruby.rb --extout=$(EXTOUT)'
fi
AC_SUBST(MINIRUBY)
AC_SUBST(PREP)
@@ -1308,14 +1564,8 @@ if test "$enable_shared" = 'yes'; then
LIBRUBY_ALIASES='lib$(RUBY_SO_NAME).sl.$(MAJOR).$(MINOR) lib$(RUBY_SO_NAME).sl'
;;
aix*)
- if test "$GCC" = yes; then
- LIBRUBY_LDSHARED='$(CC) -shared'
- LIBRUBY_DLDFLAGS='-Wl,-G -Wl,-bE:ruby.imp -Wl,-bnoentry'
- else
- LIBRUBY_LDSHARED='/usr/ccs/bin/ld'
- LIBRUBY_DLDFLAGS='-G -bE:ruby.imp -bnoentry'
- fi
- LIBRUBYARG_SHARED='-L${libdir} -lruby'
+ LIBRUBY_DLDFLAGS="${linker_flag}-bnoentry $XLDFLAGS"
+ LIBRUBYARG_SHARED='-L${libdir} -l${RUBY_SO_NAME}'
SOLIBS='-lm -lc'
;;
beos*)
@@ -1332,21 +1582,17 @@ if test "$enable_shared" = 'yes'; then
LIBRUBY_ALIASES='lib$(RUBY_SO_NAME).$(MAJOR).$(MINOR).dylib lib$(RUBY_SO_NAME).dylib'
;;
interix*)
- LIBRUBYARG_SHARED='-L${libdir} -L. -l$(RUBY_SO_NAME)'
+ LIBRUBYARG_SHARED='-L. -L${libdir} -l$(RUBY_SO_NAME)'
;;
*)
;;
esac
fi
if test "$enable_rpath" = yes; then
- if test "$GCC" = yes; then
- LIBRUBYARG_SHARED='-Wl,-R -Wl,$(libdir) -L$(libdir) -L. '"$LIBRUBYARG_SHARED"
- else
- LIBRUBYARG_SHARED='-R $(libdir) -L$(libdir) -L. '"$LIBRUBYARG_SHARED"
- fi
+ LIBRUBYARG_SHARED="${linker_flag}-R ${linker_flag}\$(libdir) -L\$(libdir) $LIBRUBYARG_SHARED"
fi
-XLDFLAGS="$XLDFLAGS -L."
+LDFLAGS="-L. $LDFLAGS"
AC_SUBST(ARCHFILE)
dnl build rdoc index if requested
@@ -1382,6 +1628,7 @@ case "$target_os" in
;;
darwin*)
CFLAGS="$CFLAGS -pipe -fno-common"
+ MINIOBJS=dmydln.o
;;
os2-emx)
CFLAGS="$CFLAGS -DOS2 -Zmts"
@@ -1404,7 +1651,7 @@ case "$target_os" in
rm -f /tmp/main.o
CFLAGS="$CFLAGS -std"
fi
- ;;
+ ;;
beos*)
case "$target_cpu" in
powerpc*)
@@ -1419,7 +1666,6 @@ case "$target_os" in
LIBRUBY_SO='cyg$(RUBY_SO_NAME)'${MAJOR}${MINOR}.dll
LIBRUBY='lib$(RUBY_SO_NAME).dll.a'
fi
- AC_LIBOBJ([strftime])
;;
mingw*)
RUBY_SO_NAME=${rb_cv_msvcrt}-'$(RUBY_INSTALL_NAME)'${MAJOR}${MINOR}
@@ -1430,7 +1676,6 @@ case "$target_os" in
AC_LIBOBJ([win32])
COMMON_LIBS=m
# COMMON_MACROS="WIN32_LEAN_AND_MEAN="
- COMMON_HEADERS="windows.h winsock.h"
;;
esac
LIBRUBY_DLDFLAGS="${DLDFLAGS}"' -Wl,--out-implib=$(LIBRUBY)'
@@ -1453,9 +1698,6 @@ case "$target_os" in
esac
MINIOBJS=dmydln.o
;;
- aix*)
- PREINSTALL='@$(RM) -r $(prefix)/lib/$(LIBRUBY_A) $(prefix)/lib/$(LIBRUBY_SO) $(prefix)/lib/ruby/$(MAJOR).$(MINOR)/$(arch)'
- ;;
*)
;;
esac
@@ -1464,6 +1706,13 @@ case "$build_os" in
*msdosdjgpp*) FIRSTMAKEFILE=GNUmakefile:djgpp/GNUmakefile.in;;
esac
+CPPFLAGS="$CPPFLAGS "'$(DEFS)'
+test -z "$CFLAGS" || CFLAGS="$CFLAGS "; CFLAGS="$CFLAGS"'${cflags}'
+test -z "$CPPFLAGS" || CPPFLAGS="$CPPFLAGS "; CPPFLAGS="$CPPFLAGS"'${cppflags}'
+AC_SUBST(cppflags, [])dnl
+AC_SUBST(cflags, ['${optflags} ${debugflags}'])dnl
+AC_SUBST(optflags)dnl
+AC_SUBST(debugflags)dnl
AC_SUBST(XCFLAGS)dnl
AC_SUBST(XLDFLAGS)dnl
AC_SUBST(LIBRUBY_LDSHARED)
@@ -1488,7 +1737,6 @@ AC_SUBST(COMMON_MACROS)
AC_SUBST(COMMON_HEADERS)
AC_SUBST(EXPORT_PREFIX)
AC_SUBST(MINIOBJS)
-AC_SUBST(PREINSTALL)
MAKEFILES="Makefile `echo $FIRSTMAKEFILE | sed 's/:.*//'`"
MAKEFILES="`echo $MAKEFILES`"
@@ -1509,37 +1757,53 @@ case "$target_os" in
rubyw_install_name="$RUBYW_INSTALL_NAME"
;;
esac
-case "$target_os" in
- cygwin*|mingw*|*djgpp*|os2-emx*)
- RUBY_LIB_PREFIX="/lib/ruby"
- ;;
- *)
- RUBY_LIB_PREFIX="${prefix}/lib/ruby"
- ;;
-esac
-RUBY_LIB_PATH="${RUBY_LIB_PREFIX}/${MAJOR}.${MINOR}"
+RUBY_LIB_PREFIX=`eval echo \\"${libdir}/ruby\\"`
AC_ARG_WITH(sitedir,
- [ --with-sitedir=DIR site libraries in DIR [PREFIX/lib/ruby/site_ruby]],
+ [ --with-sitedir=DIR site libraries in DIR [[LIBDIR/ruby/site_ruby]]],
[sitedir=$withval],
- [sitedir='${prefix}/lib/ruby/site_ruby'])
+ [sitedir='${libdir}/ruby/site_ruby'])
SITE_DIR=`eval echo \\"${sitedir}\\"`
+
case "$target_os" in
cygwin*|mingw*|*djgpp*|os2-emx*)
- RUBY_SITE_LIB_PATH="`expr "$SITE_DIR" : "$prefix\(/.*\)"`" ||
- RUBY_SITE_LIB_PATH="$SITE_DIR";;
+ RUBY_LIB_PREFIX="`eval echo "$RUBY_LIB_PREFIX" | sed 's|^NONE/|/|;s|^'"$prefix"'/|/|'`"
+ RUBY_SITE_LIB_PATH="`eval echo "$SITE_DIR" | sed 's|^NONE/|/|;s|^'"$prefix"'/|/|'`"
+ ;;
*)
- RUBY_SITE_LIB_PATH="$SITE_DIR";;
+ RUBY_LIB_PREFIX="`eval echo \\"$RUBY_LIB_PREFIX\\" | sed 's|^NONE/|'"$prefix"'/|'`"
+ RUBY_SITE_LIB_PATH="`eval echo \\"$SITE_DIR\\" | sed 's|^NONE/|'"$prefix"'/|'`"
+ ;;
esac
+RUBY_LIB_PATH="${RUBY_LIB_PREFIX}/${MAJOR}.${MINOR}"
RUBY_SITE_LIB_PATH2="${RUBY_SITE_LIB_PATH}/${MAJOR}.${MINOR}"
AC_DEFINE_UNQUOTED(RUBY_LIB, "${RUBY_LIB_PATH}")
AC_DEFINE_UNQUOTED(RUBY_SITE_LIB, "${RUBY_SITE_LIB_PATH}")
AC_DEFINE_UNQUOTED(RUBY_SITE_LIB2, "${RUBY_SITE_LIB_PATH2}")
+AC_ARG_WITH(vendordir,
+ [ --with-vendordir=DIR vendor libraries in DIR [[LIBDIR/ruby/vendor_ruby]]],
+ [vendordir=$withval],
+ [vendordir='${libdir}/ruby/vendor_ruby'])
+VENDOR_DIR=`eval echo \\"${vendordir}\\"`
+case "$target_os" in
+ cygwin*|mingw*|*djgpp*|os2-emx*)
+ RUBY_VENDOR_LIB_PATH="`eval echo "$VENDOR_DIR" | sed 's|^NONE/|/|;s|^'"$prefix"'/|/|'`"
+ ;;
+ *)
+ RUBY_VENDOR_LIB_PATH="`eval echo \\"$VENDOR_DIR\\" | sed 's|^NONE/|'"$prefix"'/|'`"
+ ;;
+esac
+RUBY_VENDOR_LIB_PATH2="${RUBY_VENDOR_LIB_PATH}/${MAJOR}.${MINOR}"
+
+AC_DEFINE_UNQUOTED(RUBY_VENDOR_LIB, "${RUBY_VENDOR_LIB_PATH}")
+AC_DEFINE_UNQUOTED(RUBY_VENDOR_LIB2, "${RUBY_VENDOR_LIB_PATH2}")
+
AC_SUBST(arch)dnl
AC_SUBST(sitearch)dnl
AC_SUBST(sitedir)dnl
+AC_SUBST(vendordir)dnl
configure_args=$ac_configure_args
AC_SUBST(configure_args)dnl
@@ -1552,6 +1816,8 @@ if test "$fat_binary" != no ; then
AC_DEFINE_UNQUOTED(RUBY_SITE_THIN_ARCHLIB,
"${RUBY_SITE_LIB_PATH}/" __ARCHITECTURE__ "-${target_os}")
+ AC_DEFINE_UNQUOTED(RUBY_VENDOR_THIN_ARCHLIB,
+ "${RUBY_VENDOR_LIB_PATH}/" __ARCHITECTURE__ "-${target_os}")
AC_DEFINE_UNQUOTED(RUBY_PLATFORM, __ARCHITECTURE__ "-${target_os}")
else
arch="${target_cpu}-${target_os}"
@@ -1559,12 +1825,13 @@ else
fi
case "$target_os" in
- mingw*) sitearch="i386-$rb_cv_msvcrt" ;;
+ mingw*) sitearch="$target_cpu-$rb_cv_msvcrt" ;;
*) sitearch="${arch}" ;;
esac
AC_DEFINE_UNQUOTED(RUBY_ARCHLIB, "${RUBY_LIB_PATH}/${arch}")
AC_DEFINE_UNQUOTED(RUBY_SITE_ARCHLIB, "${RUBY_SITE_LIB_PATH2}/${sitearch}")
+AC_DEFINE_UNQUOTED(RUBY_VENDOR_ARCHLIB, "${RUBY_VENDOR_LIB_PATH2}/${sitearch}")
AC_ARG_WITH(search-path,
[ --with-search-path=DIR specify the additional search path],
@@ -1601,12 +1868,15 @@ else
echo "creating config.h"
tr -d '\015' < confdefs.h > config.h
fi
-: > confdefs.h
+tr -d '\015' < largefile.h > confdefs.h
+rm largefile.h
AC_CONFIG_FILES($FIRSTMAKEFILE)
AC_CONFIG_FILES(Makefile, [{
+ sed '/^MISSING/s/\$U\././g' Makefile
echo; test x"$EXEEXT" = x || echo 'miniruby: miniruby$(EXEEXT)'
test "$RUBY_INSTALL_NAME$EXEEXT" = ruby || echo 'ruby: $(PROGRAM);'
sed ['s/{\$([^(){}]*)[^{}]*}//g'] ${srcdir}/common.mk
-} >> Makefile], [RUBY_INSTALL_NAME=$RUBY_INSTALL_NAME EXEEXT=$EXEEXT])
+ } >> confmk$$.tmp && mv -f confmk$$.tmp Makefile],
+[RUBY_INSTALL_NAME=$RUBY_INSTALL_NAME EXEEXT=$EXEEXT])
AC_OUTPUT
diff --git a/cygwin/GNUmakefile.in b/cygwin/GNUmakefile.in
index 03208df11c..734d8702a6 100644
--- a/cygwin/GNUmakefile.in
+++ b/cygwin/GNUmakefile.in
@@ -38,7 +38,7 @@ $(RUBY_EXP) $(LIBRUBY_SO): $(DLL_BASE_NAME).res.@OBJEXT@
%.res.@OBJEXT@: %.rc
@WINDRES@ --include-dir . --include-dir $(<D) --include-dir $(srcdir)/win32 $< $@
-$(RCFILES): $(RBCONFIG)
+$(RCFILES): $(RBCONFIG) $(srcdir)/version.h $(srcdir)/win32/resource.rb
@$(MINIRUBY) $(srcdir)/win32/resource.rb \
-ruby_name=$(RUBY_INSTALL_NAME) -rubyw_name=$(RUBYW_INSTALL_NAME) \
-so_name=$(DLL_BASE_NAME) \
diff --git a/defines.h b/defines.h
index ef80989925..f39097fea4 100644
--- a/defines.h
+++ b/defines.h
@@ -2,8 +2,8 @@
defines.h -
- $Author: nobu $
- $Date: 2005/10/25 16:59:57 $
+ $Author$
+ $Date$
created at: Wed May 18 00:21:44 JST 1994
************************************************/
@@ -102,6 +102,16 @@ void xfree _((void*));
#endif
#endif
+#if defined(__NeXT__) || defined(__APPLE__)
+/* Do not trust WORDS_BIGENDIAN from configure since -arch compiler flag may
+ result in a different endian. Instead trust __BIG_ENDIAN__ and
+ __LITTLE_ENDIAN__ which are set correctly by -arch. */
+#undef WORDS_BIGENDIAN
+#ifdef __BIG_ENDIAN__
+#define WORDS_BIGENDIAN
+#endif
+#endif
+
#ifdef __NeXT__
/* NextStep, OpenStep, Rhapsody */
#ifndef S_IRUSR
@@ -155,13 +165,6 @@ void xfree _((void*));
#ifndef S_ISREG
#define S_ISREG(mode) (((mode) & (0170000)) == (0100000))
#endif
-/* Do not trust WORDS_BIGENDIAN from configure since -arch compiler flag may
- result in a different endian. Instead trust __BIG_ENDIAN__ and
- __LITTLE_ENDIAN__ which are set correctly by -arch. */
-#undef WORDS_BIGENDIAN
-#ifdef __BIG_ENDIAN__
-#define WORDS_BIGENDIAN
-#endif
#ifndef __APPLE__
/* NextStep, OpenStep (but not Rhapsody) */
#ifndef GETPGRP_VOID
@@ -224,13 +227,10 @@ flush_register_windows(void)
;
}
# define FLUSH_REGISTER_WINDOWS flush_register_windows()
-#elif defined(__ia64__)
-void flush_register_windows(void)
-# if defined(__GNUC__) && (( __GNUC__ == 3 && __GNUC_MINOR__ > 0 ) || __GNUC__ > 3)
-__attribute__ ((noinline))
-# endif
- ;
-# define FLUSH_REGISTER_WINDOWS flush_register_windows()
+#elif defined(__ia64)
+void *rb_ia64_bsp(void);
+void rb_ia64_flushrs(void);
+# define FLUSH_REGISTER_WINDOWS rb_ia64_flushrs()
#else
# define FLUSH_REGISTER_WINDOWS ((void)0)
#endif
@@ -254,6 +254,18 @@ __attribute__ ((noinline))
#define ENV_IGNORECASE
#endif
+#ifndef CASEFOLD_FILESYSTEM
+# if defined DOSISH || defined __VMS
+# define CASEFOLD_FILESYSTEM 1
+# else
+# define CASEFOLD_FILESYSTEM 0
+# endif
+#endif
+
+#ifndef DLEXT_MAXLEN
+#define DLEXT_MAXLEN 4
+#endif
+
#ifndef RUBY_PLATFORM
#define RUBY_PLATFORM "unknown-unknown"
#endif
diff --git a/dir.c b/dir.c
index 0798b3f76f..710299e7b6 100644
--- a/dir.c
+++ b/dir.c
@@ -2,8 +2,8 @@
dir.c -
- $Author: shyouhei $
- $Date: 2006/12/14 14:50:13 $
+ $Author$
+ $Date$
created at: Wed Jan 5 09:51:01 JST 1994
Copyright (C) 1993-2003 Yukihiro Matsumoto
@@ -89,153 +89,261 @@ char *strchr _((char*,char));
#define FNM_ERROR 2
#define downcase(c) (nocase && ISUPPER(c) ? tolower(c) : (c))
+#define compare(c1, c2) (((unsigned char)(c1)) - ((unsigned char)(c2)))
+
+/* caution: in case *p == '\0'
+ Next(p) == p + 1 in single byte environment
+ Next(p) == p in multi byte environment
+*/
+#if defined(CharNext)
+# define Next(p) CharNext(p)
+#elif defined(DJGPP)
+# define Next(p) ((p) + mblen(p, RUBY_MBCHAR_MAXSIZE))
+#elif defined(__EMX__)
+# define Next(p) ((p) + emx_mblen(p))
+static inline int
+emx_mblen(const char *p)
+{
+ int n = mblen(p, RUBY_MBCHAR_MAXSIZE);
+ return (n < 0) ? 1 : n;
+}
+#endif
-#ifndef CharNext /* defined as CharNext[AW] on Windows. */
-# if defined(DJGPP)
-# define CharNext(p) ((p) + mblen(p, MB_CUR_MAX))
-# else
-# define CharNext(p) ((p) + 1)
-# endif
+#ifndef Next /* single byte environment */
+# define Next(p) ((p) + 1)
+# define Inc(p) (++(p))
+# define Compare(p1, p2) (compare(downcase(*(p1)), downcase(*(p2))))
+#else /* multi byte environment */
+# define Inc(p) ((p) = Next(p))
+# define Compare(p1, p2) (CompareImpl(p1, p2, nocase))
+static int
+CompareImpl(const char *p1, const char *p2, int nocase)
+{
+ const int len1 = Next(p1) - p1;
+ const int len2 = Next(p2) - p2;
+#ifdef _WIN32
+ char buf1[10], buf2[10]; /* large enough? */
#endif
-#if defined DOSISH
-#define isdirsep(c) ((c) == '/' || (c) == '\\')
-#else
-#define isdirsep(c) ((c) == '/')
+ if (len1 < 0 || len2 < 0) {
+ rb_fatal("CompareImpl: negative len");
+ }
+
+ if (len1 == 0) return len2;
+ if (len2 == 0) return -len1;
+
+#ifdef _WIN32
+ if (nocase && rb_w32_iswinnt()) {
+ if (len1 > 1) {
+ if (len1 >= sizeof(buf1)) {
+ rb_fatal("CompareImpl: too large len");
+ }
+ memcpy(buf1, p1, len1);
+ buf1[len1] = '\0';
+ CharLower(buf1);
+ p1 = buf1; /* trick */
+ }
+ if (len2 > 1) {
+ if (len2 >= sizeof(buf2)) {
+ rb_fatal("CompareImpl: too large len");
+ }
+ memcpy(buf2, p2, len2);
+ buf2[len2] = '\0';
+ CharLower(buf2);
+ p2 = buf2; /* trick */
+ }
+ }
#endif
+ if (len1 == 1)
+ if (len2 == 1)
+ return compare(downcase(*p1), downcase(*p2));
+ else {
+ const int ret = compare(downcase(*p1), *p2);
+ return ret ? ret : -1;
+ }
+ else
+ if (len2 == 1) {
+ const int ret = compare(*p1, downcase(*p2));
+ return ret ? ret : 1;
+ }
+ else {
+ const int ret = memcmp(p1, p2, len1 < len2 ? len1 : len2);
+ return ret ? ret : len1 - len2;
+ }
+}
+#endif /* environment */
static char *
-range(pat, test, flags)
- const char *pat;
- int test;
+bracket(p, s, flags)
+ const char *p; /* pattern (next to '[') */
+ const char *s; /* string */
int flags;
{
- int not, ok = 0;
- int nocase = flags & FNM_CASEFOLD;
- int escape = !(flags & FNM_NOESCAPE);
+ const int nocase = flags & FNM_CASEFOLD;
+ const int escape = !(flags & FNM_NOESCAPE);
- not = *pat == '!' || *pat == '^';
- if (not)
- pat++;
+ int ok = 0, not = 0;
- test = downcase(test);
+ if (*p == '!' || *p == '^') {
+ not = 1;
+ p++;
+ }
- while (*pat != ']') {
- int cstart, cend;
- if (escape && *pat == '\\')
- pat++;
- cstart = cend = *pat++;
- if (!cstart)
+ while (*p != ']') {
+ const char *t1 = p;
+ if (escape && *t1 == '\\')
+ t1++;
+ if (!*t1)
return NULL;
- if (*pat == '-' && pat[1] != ']') {
- pat++;
- if (escape && *pat == '\\')
- pat++;
- cend = *pat++;
- if (!cend)
+ p = Next(t1);
+ if (p[0] == '-' && p[1] != ']') {
+ const char *t2 = p + 1;
+ if (escape && *t2 == '\\')
+ t2++;
+ if (!*t2)
return NULL;
+ p = Next(t2);
+ if (!ok && Compare(t1, s) <= 0 && Compare(s, t2) <= 0)
+ ok = 1;
}
- if (downcase(cstart) <= test && test <= downcase(cend))
- ok = 1;
+ else
+ if (!ok && Compare(t1, s) == 0)
+ ok = 1;
}
- return ok == not ? NULL : (char *)pat + 1;
+
+ return ok == not ? NULL : (char *)p + 1;
}
-#define ISDIRSEP(c) (pathname && isdirsep(c))
-#define PERIOD(s) (period && *(s) == '.' && \
- ((s) == string || ISDIRSEP((s)[-1])))
+/* If FNM_PATHNAME is set, only path element will be matched. (upto '/' or '\0')
+ Otherwise, entire string will be matched.
+ End marker itself won't be compared.
+ And if function succeeds, *pcur reaches end marker.
+*/
+#define UNESCAPE(p) (escape && *(p) == '\\' ? (p) + 1 : (p))
+#define ISEND(p) (!*(p) || (pathname && *(p) == '/'))
+#define RETURN(val) return *pcur = p, *scur = s, (val);
+
static int
-fnmatch(pat, string, flags)
- const char *pat;
- const char *string;
+fnmatch_helper(pcur, scur, flags)
+ const char **pcur; /* pattern */
+ const char **scur; /* string */
int flags;
{
- int c;
- int test;
- const char *s = string;
- int escape = !(flags & FNM_NOESCAPE);
- int pathname = flags & FNM_PATHNAME;
- int period = !(flags & FNM_DOTMATCH);
- int nocase = flags & FNM_CASEFOLD;
+ const int period = !(flags & FNM_DOTMATCH);
+ const int pathname = flags & FNM_PATHNAME;
+ const int escape = !(flags & FNM_NOESCAPE);
+ const int nocase = flags & FNM_CASEFOLD;
- while ((c = *pat++) != '\0') {
- switch (c) {
- case '?':
- if (!*s || ISDIRSEP(*s) || PERIOD(s))
- return FNM_NOMATCH;
- s++;
- break;
- case '*':
- while ((c = *pat++) == '*')
- ;
+ const char *ptmp = 0;
+ const char *stmp = 0;
- if (PERIOD(s))
- return FNM_NOMATCH;
+ const char *p = *pcur;
+ const char *s = *scur;
- if (!c) {
- if (pathname && *rb_path_next(s))
- return FNM_NOMATCH;
- else
- return 0;
- }
- else if (ISDIRSEP(c)) {
- s = rb_path_next(s);
- if (*s) {
- s++;
- break;
- }
- return FNM_NOMATCH;
- }
+ if (period && *s == '.' && *UNESCAPE(p) != '.') /* leading period */
+ RETURN(FNM_NOMATCH);
- test = escape && c == '\\' ? *pat : c;
- test = downcase(test);
- pat--;
- while (*s) {
- if ((c == '?' || c == '[' || downcase(*s) == test) &&
- !fnmatch(pat, s, flags | FNM_DOTMATCH))
- return 0;
- else if (ISDIRSEP(*s))
- break;
- s++;
+ while (1) {
+ switch (*p) {
+ case '*':
+ do { p++; } while (*p == '*');
+ if (ISEND(UNESCAPE(p))) {
+ p = UNESCAPE(p);
+ RETURN(0);
}
- return FNM_NOMATCH;
+ if (ISEND(s))
+ RETURN(FNM_NOMATCH);
+ ptmp = p;
+ stmp = s;
+ continue;
- case '[':
- if (!*s || ISDIRSEP(*s) || PERIOD(s))
- return FNM_NOMATCH;
- pat = range(pat, *s, flags);
- if (pat == NULL)
- return FNM_NOMATCH;
- s++;
- break;
+ case '?':
+ if (ISEND(s))
+ RETURN(FNM_NOMATCH);
+ p++;
+ Inc(s);
+ continue;
- case '\\':
- if (escape
-#if defined DOSISH
- && *pat && strchr("*?[]\\", *pat)
-#endif
- ) {
- c = *pat;
- if (!c)
- c = '\\';
- else
- pat++;
+ case '[': {
+ const char *t;
+ if (ISEND(s))
+ RETURN(FNM_NOMATCH);
+ if ((t = bracket(p + 1, s, flags)) != 0) {
+ p = t;
+ Inc(s);
+ continue;
}
- /* FALLTHROUGH */
+ goto failed;
+ }
+ }
- default:
-#if defined DOSISH
- if (ISDIRSEP(c) && isdirsep(*s))
- ;
- else
-#endif
- if(downcase(c) != downcase(*s))
- return FNM_NOMATCH;
- s++;
- break;
+ /* ordinary */
+ p = UNESCAPE(p);
+ if (ISEND(s))
+ RETURN(ISEND(p) ? 0 : FNM_NOMATCH);
+ if (ISEND(p))
+ goto failed;
+ if (Compare(p, s) != 0)
+ goto failed;
+ Inc(p);
+ Inc(s);
+ continue;
+
+ failed: /* try next '*' position */
+ if (ptmp && stmp) {
+ p = ptmp;
+ Inc(stmp); /* !ISEND(*stmp) */
+ s = stmp;
+ continue;
+ }
+ RETURN(FNM_NOMATCH);
+ }
+}
+
+static int
+fnmatch(p, s, flags)
+ const char *p; /* pattern */
+ const char *s; /* string */
+ int flags;
+{
+ const int period = !(flags & FNM_DOTMATCH);
+ const int pathname = flags & FNM_PATHNAME;
+
+ const char *ptmp = 0;
+ const char *stmp = 0;
+
+ if (pathname) {
+ while (1) {
+ if (p[0] == '*' && p[1] == '*' && p[2] == '/') {
+ do { p += 3; } while (p[0] == '*' && p[1] == '*' && p[2] == '/');
+ ptmp = p;
+ stmp = s;
+ }
+ if (fnmatch_helper(&p, &s, flags) == 0) {
+ while (*s && *s != '/') Inc(s);
+ if (*p && *s) {
+ p++;
+ s++;
+ continue;
+ }
+ if (!*p && !*s)
+ return 0;
+ }
+ /* failed : try next recursion */
+ if (ptmp && stmp && !(period && *stmp == '.')) {
+ while (*stmp && *stmp != '/') Inc(stmp);
+ if (*stmp) {
+ p = ptmp;
+ stmp++;
+ s = stmp;
+ continue;
+ }
+ }
+ return FNM_NOMATCH;
}
}
- return !*s ? 0 : FNM_NOMATCH;
+ else
+ return fnmatch_helper(&p, &s, flags);
}
VALUE rb_cDir;
@@ -355,6 +463,29 @@ dir_check(dir)
/*
* call-seq:
+ * dir.inspect => string
+ *
+ * Return a string describing this Dir object.
+ */
+static VALUE
+dir_inspect(dir)
+ VALUE dir;
+{
+ struct dir_data *dirp;
+
+ Data_Get_Struct(dir, struct dir_data, dirp);
+ if (dirp->path) {
+ const char *c = rb_obj_classname(dir);
+ int len = strlen(c) + strlen(dirp->path) + 4;
+ VALUE s = rb_str_new(0, len);
+ snprintf(RSTRING_PTR(s), len+1, "#<%s:%s>", c, dirp->path);
+ return s;
+ }
+ return rb_funcall(dir, rb_intern("to_s"), 0, 0);
+}
+
+/*
+ * call-seq:
* dir.path => string or nil
*
* Returns the path parameter passed to <em>dir</em>'s constructor.
@@ -368,7 +499,7 @@ dir_path(dir)
{
struct dir_data *dirp;
- GetDIR(dir, dirp);
+ Data_Get_Struct(dir, struct dir_data, dirp);
if (!dirp->path) return Qnil;
return rb_str_new2(dirp->path);
}
@@ -431,6 +562,7 @@ dir_each(dir)
struct dir_data *dirp;
struct dirent *dp;
+ RETURN_ENUMERATOR(dir, 0, 0);
GetDIR(dir, dirp);
rewinddir(dirp->dir);
for (dp = readdir(dirp->dir); dp != NULL; dp = readdir(dirp->dir)) {
@@ -538,6 +670,9 @@ dir_rewind(dir)
{
struct dir_data *dirp;
+ if (rb_safe_level() >= 4 && !OBJ_TAINTED(dir)) {
+ rb_raise(rb_eSecurityError, "Insecure: can't close");
+ }
GetDIR(dir, dirp);
rewinddir(dirp->dir);
return dir;
@@ -559,9 +694,6 @@ dir_close(dir)
{
struct dir_data *dirp;
- if (rb_safe_level() >= 4 && !OBJ_TAINTED(dir)) {
- rb_raise(rb_eSecurityError, "Insecure: can't close");
- }
GetDIR(dir, dirp);
closedir(dirp->dir);
dirp->dir = NULL;
@@ -819,109 +951,252 @@ sys_warning_1(mesg)
rb_sys_warning("%s", mesg);
}
-#define GLOB_VERBOSE (1U << (sizeof(int) * CHAR_BIT - 1))
+#define GLOB_VERBOSE (1UL << (sizeof(int) * CHAR_BIT - 1))
#define sys_warning(val) \
(void)((flags & GLOB_VERBOSE) && rb_protect((VALUE (*)_((VALUE)))sys_warning_1, (VALUE)(val), 0))
#define GLOB_ALLOC(type) (type *)malloc(sizeof(type))
#define GLOB_ALLOC_N(type, n) (type *)malloc(sizeof(type) * (n))
-#define GLOB_REALLOC_N(var, type, n) (type *)realloc((var), sizeof(type) * (n))
#define GLOB_JUMP_TAG(status) ((status == -1) ? rb_memerror() : rb_jump_tag(status))
+/*
+ * ENOTDIR can be returned by stat(2) if a non-leaf element of the path
+ * is not a directory.
+ */
+#define to_be_ignored(e) ((e) == ENOENT || (e) == ENOTDIR)
+
+/* System call with warning */
+static int
+do_stat(const char *path, struct stat *pst, int flags)
+
+{
+ int ret = stat(path, pst);
+ if (ret < 0 && !to_be_ignored(errno))
+ sys_warning(path);
+
+ return ret;
+}
+
+static int
+do_lstat(const char *path, struct stat *pst, int flags)
+{
+ int ret = lstat(path, pst);
+ if (ret < 0 && !to_be_ignored(errno))
+ sys_warning(path);
+
+ return ret;
+}
+
+static DIR *
+do_opendir(const char *path, int flags)
+{
+ DIR *dirp = opendir(path);
+ if (dirp == NULL && !to_be_ignored(errno))
+ sys_warning(path);
+
+ return dirp;
+}
+
/* Return nonzero if S has any special globbing chars in it. */
static int
-has_magic(s, send, flags)
- const char *s, *send;
+has_magic(s, flags)
+ const char *s;
int flags;
{
- register const char *p = s;
- register char c;
- int open = 0;
const int escape = !(flags & FNM_NOESCAPE);
const int nocase = flags & FNM_CASEFOLD;
- while ((c = *p++) != '\0') {
+ register const char *p = s;
+ register char c;
+
+ while ((c = *p++) != 0) {
switch (c) {
- case '?':
case '*':
- return Qtrue;
-
- case '[': /* Only accept an open brace if there is a close */
- open++; /* brace to match it. Bracket expressions must be */
- continue; /* complete, according to Posix.2 */
- case ']':
- if (open)
- return Qtrue;
- continue;
+ case '?':
+ case '[':
+ return 1;
case '\\':
- if (escape && *p++ == '\0')
- return Qfalse;
- break;
+ if (escape && !(c = *p++))
+ return 0;
+ continue;
default:
if (!FNM_SYSCASE && ISALPHA(c) && nocase)
- return Qtrue;
+ return 1;
}
- if (send && p >= send) break;
+ p = Next(p-1);
}
- return Qfalse;
+
+ return 0;
}
-static char*
-extract_path(p, pend)
- const char *p, *pend;
+/* Find separator in globbing pattern. */
+static char *
+find_dirsep(const char *s, int flags)
{
- char *alloc;
- int len;
-
- len = pend - p;
- alloc = GLOB_ALLOC_N(char, len+1);
- if (!alloc) return NULL;
- memcpy(alloc, p, len);
- if (len > 1 && pend[-1] == '/'
-#if defined DOSISH_DRIVE_LETTER
- && pend[-2] != ':'
-#endif
- ) {
- alloc[len-1] = 0;
- }
- else {
- alloc[len] = 0;
- }
+ const int escape = !(flags & FNM_NOESCAPE);
- return alloc;
-}
+ register const char *p = s;
+ register char c;
+ int open = 0;
-static char*
-extract_elem(path)
- const char *path;
-{
- const char *pend;
+ while ((c = *p++) != 0) {
+ switch (c) {
+ case '[':
+ open = 1;
+ continue;
+ case ']':
+ open = 0;
+ continue;
+
+ case '/':
+ if (!open)
+ return (char *)p-1;
+ continue;
+
+ case '\\':
+ if (escape && !(c = *p++))
+ return (char *)p-1;
+ continue;
+ }
- pend = strchr(path, '/');
- if (!pend) pend = path + strlen(path);
+ p = Next(p-1);
+ }
- return extract_path(path, pend);
+ return (char *)p-1;
}
+/* Remove escaping backslashes */
static void
remove_backslashes(p)
char *p;
{
- char *pend = p + strlen(p);
char *t = p;
+ char *s = p;
- while (p < pend) {
+ while (*p) {
if (*p == '\\') {
- if (++p == pend) break;
+ if (t != s)
+ memmove(t, s, p - s);
+ t += p - s;
+ s = ++p;
+ if (!*p) break;
+ }
+ Inc(p);
+ }
+
+ while (*p++);
+
+ if (t != s)
+ memmove(t, s, p - s); /* move '\0' too */
+}
+
+/* Globing pattern */
+enum glob_pattern_type { PLAIN, MAGICAL, RECURSIVE, MATCH_ALL, MATCH_DIR };
+
+struct glob_pattern {
+ char *str;
+ enum glob_pattern_type type;
+ struct glob_pattern *next;
+};
+
+static void glob_free_pattern(struct glob_pattern *list);
+
+static struct glob_pattern *
+glob_make_pattern(const char *p, int flags)
+{
+ struct glob_pattern *list, *tmp, **tail = &list;
+ int dirsep = 0; /* pattern is terminated with '/' */
+
+ while (*p) {
+ tmp = GLOB_ALLOC(struct glob_pattern);
+ if (!tmp) goto error;
+ if (p[0] == '*' && p[1] == '*' && p[2] == '/') {
+ /* fold continuous RECURSIVEs (needed in glob_helper) */
+ do { p += 3; } while (p[0] == '*' && p[1] == '*' && p[2] == '/');
+ tmp->type = RECURSIVE;
+ tmp->str = 0;
+ dirsep = 1;
+ }
+ else {
+ const char *m = find_dirsep(p, flags);
+ char *buf = GLOB_ALLOC_N(char, m-p+1);
+ if (!buf) {
+ free(tmp);
+ goto error;
+ }
+ memcpy(buf, p, m-p);
+ buf[m-p] = '\0';
+ tmp->type = has_magic(buf, flags) ? MAGICAL : PLAIN;
+ tmp->str = buf;
+ if (*m) {
+ dirsep = 1;
+ p = m + 1;
+ }
+ else {
+ dirsep = 0;
+ p = m;
+ }
}
- *t++ = *p++;
+ *tail = tmp;
+ tail = &tmp->next;
+ }
+
+ tmp = GLOB_ALLOC(struct glob_pattern);
+ if (!tmp) {
+ error:
+ *tail = 0;
+ glob_free_pattern(list);
+ return 0;
}
- *t = '\0';
+ tmp->type = dirsep ? MATCH_DIR : MATCH_ALL;
+ tmp->str = 0;
+ *tail = tmp;
+ tmp->next = 0;
+
+ return list;
}
+static void
+glob_free_pattern(struct glob_pattern *list)
+{
+ while (list) {
+ struct glob_pattern *tmp = list;
+ list = list->next;
+ if (tmp->str)
+ free(tmp->str);
+ free(tmp);
+ }
+}
+
+static char *
+join_path(const char *path, int dirsep, const char *name)
+{
+ long len = strlen(path);
+ char *buf = GLOB_ALLOC_N(char, len+strlen(name)+(dirsep?1:0)+1);
+
+ if (!buf) return 0;
+ memcpy(buf, path, len);
+ if (dirsep) {
+ strcpy(buf+len, "/");
+ len++;
+ }
+ strcpy(buf+len, name);
+ return buf;
+}
+
+enum answer { YES, NO, UNKNOWN };
+
+#ifndef S_ISLNK
+# ifndef S_IFLNK
+# define S_ISLNK(m) (0)
+# else
+# define S_ISLNK(m) ((m & S_IFMT) == S_IFLNK)
+# endif
+#endif
+
#ifndef S_ISDIR
# define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
#endif
@@ -946,235 +1221,239 @@ glob_func_caller(val)
#define glob_call_func(func, path, arg) (*func)(path, arg)
-static int glob_helper _((const char *path, const char *sub, int flags, int (*func)(const char *,VALUE), VALUE arg));
+static int glob_helper _((const char *, int, enum answer, enum answer, struct glob_pattern **, struct glob_pattern **, int, ruby_glob_func *, VALUE));
static int
-glob_helper(path, sub, flags, func, arg)
+glob_helper(path, dirsep, exist, isdir, beg, end, flags, func, arg)
const char *path;
- const char *sub;
+ int dirsep; /* '/' should be placed before appending child entry's name to 'path'. */
+ enum answer exist; /* Does 'path' indicate an existing entry? */
+ enum answer isdir; /* Does 'path' indicate a directory or a symlink to a directory? */
+ struct glob_pattern **beg;
+ struct glob_pattern **end;
int flags;
- int (*func) _((const char *, VALUE));
+ ruby_glob_func *func;
VALUE arg;
{
struct stat st;
- const char *p, *m;
int status = 0;
- char *buf = 0;
- char *newpath = 0;
- char *newbuf;
-
- p = sub ? sub : path;
- if (!has_magic(p, 0, flags)) {
-#if !defined DOSISH
- if (!(flags & FNM_NOESCAPE))
-#endif
- {
- newpath = strdup(path);
- if (!newpath) return -1;
- if (sub) {
- p = newpath + (sub - path);
- remove_backslashes(newpath + (sub - path));
- sub = p;
+ struct glob_pattern **cur, **new_beg, **new_end;
+ int plain = 0, magical = 0, recursive = 0, match_all = 0, match_dir = 0;
+ int escape = !(flags & FNM_NOESCAPE);
+
+ for (cur = beg; cur < end; ++cur) {
+ struct glob_pattern *p = *cur;
+ if (p->type == RECURSIVE) {
+ recursive = 1;
+ p = p->next;
+ }
+ switch (p->type) {
+ case PLAIN:
+ plain = 1;
+ break;
+ case MAGICAL:
+ magical = 1;
+ break;
+ case MATCH_ALL:
+ match_all = 1;
+ break;
+ case MATCH_DIR:
+ match_dir = 1;
+ break;
+ case RECURSIVE:
+ rb_bug("continuous RECURSIVEs");
+ }
+ }
+
+ if (*path) {
+ if (match_all && exist == UNKNOWN) {
+ if (do_lstat(path, &st, flags) == 0) {
+ exist = YES;
+ isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO;
}
else {
- remove_backslashes(newpath);
- p = path = newpath;
+ exist = NO;
+ isdir = NO;
}
}
- if (lstat(path, &st) == 0) {
+ if (match_dir && isdir == UNKNOWN) {
+ if (do_stat(path, &st, flags) == 0) {
+ exist = YES;
+ isdir = S_ISDIR(st.st_mode) ? YES : NO;
+ }
+ else {
+ exist = NO;
+ isdir = NO;
+ }
+ }
+ if (match_all && exist == YES) {
status = glob_call_func(func, path, arg);
+ if (status) return status;
}
- else if (errno != ENOENT) {
- /* In case stat error is other than ENOENT and
- we may want to know what is wrong. */
- sys_warning(path);
+ if (match_dir && isdir == YES) {
+ char *tmp = join_path(path, dirsep, "");
+ if (!tmp) return -1;
+ status = glob_call_func(func, tmp, arg);
+ free(tmp);
+ if (status) return status;
}
- if (newpath) free(newpath);
- return status;
}
- while (p && !status) {
- if (*p == '/') p++;
- m = strchr(p, '/');
- if (has_magic(p, m, flags)) {
- char *dir, *base, *magic;
- DIR *dirp;
- struct dirent *dp;
- int recursive = 0;
-
- struct d_link {
- char *path;
- struct d_link *next;
- } *tmp, *link, **tail = &link;
-
- base = extract_path(path, p);
- if (!base) {
+ if (exist == NO || isdir == NO) return 0;
+
+ if (magical || recursive) {
+ struct dirent *dp;
+ DIR *dirp = do_opendir(*path ? path : ".", flags);
+ if (dirp == NULL) return 0;
+
+ for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
+ char *buf = join_path(path, dirsep, dp->d_name);
+ enum answer new_isdir = UNKNOWN;
+
+ if (!buf) {
status = -1;
break;
}
- if (path == p) dir = ".";
- else dir = base;
+ if (recursive && strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0
+ && fnmatch("*", dp->d_name, flags) == 0) {
+#ifndef _WIN32
+ if (do_lstat(buf, &st, flags) == 0)
+ new_isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO;
+ else
+ new_isdir = NO;
+#else
+ new_isdir = dp->d_isdir ? (!dp->d_isrep ? YES : UNKNOWN) : NO;
+#endif
+ }
- magic = extract_elem(p);
- if (!magic) {
+ new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, (end - beg) * 2);
+ if (!new_beg) {
status = -1;
break;
}
- if (stat(dir, &st) < 0) {
- if (errno != ENOENT)
- sys_warning(dir);
- free(base);
- free(magic);
- break;
- }
- if (S_ISDIR(st.st_mode)) {
- if (m && strcmp(magic, "**") == 0) {
- int n = strlen(base);
- recursive = 1;
- newbuf = GLOB_REALLOC_N(buf, char, n+strlen(m)+3);
- if (!newbuf) {
- status = -1;
- goto finalize;
- }
- buf = newbuf;
- sprintf(buf, "%s%s", base, *base ? m : m+1);
- status = glob_helper(buf, buf+n, flags, func, arg);
- if (status) goto finalize;
+
+ for (cur = beg; cur < end; ++cur) {
+ struct glob_pattern *p = *cur;
+ if (p->type == RECURSIVE) {
+ if (new_isdir == YES) /* not symlink but real directory */
+ *new_end++ = p; /* append recursive pattern */
+ p = p->next; /* 0 times recursion */
}
- dirp = opendir(dir);
- if (dirp == NULL) {
- sys_warning(dir);
- free(base);
- free(magic);
- break;
+ if (p->type == PLAIN || p->type == MAGICAL) {
+ if (fnmatch(p->str, dp->d_name, flags) == 0)
+ *new_end++ = p->next;
}
}
- else {
- free(base);
- free(magic);
- break;
- }
-#if defined DOSISH_DRIVE_LETTER
-#define BASE (*base && !((isdirsep(*base) && !base[1]) || (base[1] == ':' && isdirsep(base[2]) && !base[3])))
-#else
-#define BASE (*base && !(isdirsep(*base) && !base[1]))
-#endif
+ status = glob_helper(buf, 1, YES, new_isdir, new_beg, new_end, flags, func, arg);
+ free(buf);
+ free(new_beg);
+ if (status) break;
+ }
- for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
- if (recursive) {
- if (strcmp(".", dp->d_name) == 0 || strcmp("..", dp->d_name) == 0)
- continue;
- if (fnmatch("*", dp->d_name, flags) != 0)
- continue;
- newbuf = GLOB_REALLOC_N(buf, char, strlen(base)+NAMLEN(dp)+strlen(m)+6);
- if (!newbuf) {
- status = -1;
- break;
- }
- buf = newbuf;
- sprintf(buf, "%s%s%s", base, (BASE) ? "/" : "", dp->d_name);
- if (lstat(buf, &st) < 0) {
- if (errno != ENOENT)
- sys_warning(buf);
- continue;
- }
- if (S_ISDIR(st.st_mode)) {
- char *t = buf+strlen(buf);
- strcpy(t, "/**");
- strcpy(t+3, m);
- status = glob_helper(buf, t, flags, func, arg);
- if (status) break;
- continue;
- }
- continue;
+ closedir(dirp);
+ }
+ else if (plain) {
+ struct glob_pattern **copy_beg, **copy_end, **cur2;
+
+ copy_beg = copy_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg);
+ if (!copy_beg) return -1;
+ for (cur = beg; cur < end; ++cur)
+ *copy_end++ = (*cur)->type == PLAIN ? *cur : 0;
+
+ for (cur = copy_beg; cur < copy_end; ++cur) {
+ if (*cur) {
+ char *buf;
+ char *name;
+ name = GLOB_ALLOC_N(char, strlen((*cur)->str) + 1);
+ if (!name) {
+ status = -1;
+ break;
}
- if (fnmatch(magic, dp->d_name, flags) == 0) {
- newbuf = GLOB_REALLOC_N(buf, char, strlen(base)+NAMLEN(dp)+2);
- if (!newbuf) {
- status = -1;
- break;
- }
- buf = newbuf;
- sprintf(buf, "%s%s%s", base, (BASE) ? "/" : "", dp->d_name);
- if (!m) {
- status = glob_call_func(func, buf, arg);
- if (status) break;
- continue;
- }
- tmp = GLOB_ALLOC(struct d_link);
- if (!tmp) {
- status = -1;
- break;
- }
- tmp->path = buf;
- buf = 0;
- *tail = tmp;
- tail = &tmp->next;
+ strcpy(name, (*cur)->str);
+ if (escape) remove_backslashes(name);
+
+ new_beg = new_end = GLOB_ALLOC_N(struct glob_pattern *, end - beg);
+ if (!new_beg) {
+ free(name);
+ status = -1;
+ break;
}
- }
- closedir(dirp);
- finalize:
- *tail = 0;
- free(base);
- free(magic);
- if (link) {
- while (link) {
- if (status == 0) {
- if (stat(link->path, &st) == 0) {
- if (S_ISDIR(st.st_mode)) {
- int len = strlen(link->path);
- int mlen = strlen(m);
-
- newbuf = GLOB_REALLOC_N(buf, char, len+mlen+1);
- if (!newbuf) {
- status = -1;
- goto next_elem;
- }
- buf = newbuf;
- sprintf(buf, "%s%s", link->path, m);
- status = glob_helper(buf, buf+len, flags, func, arg);
- }
- }
- else {
- sys_warning(link->path);
- }
+ *new_end++ = (*cur)->next;
+ for (cur2 = cur + 1; cur2 < copy_end; ++cur2) {
+ if (*cur2 && fnmatch((*cur2)->str, name, flags) == 0) {
+ *new_end++ = (*cur2)->next;
+ *cur2 = 0;
}
- next_elem:
- tmp = link;
- link = link->next;
- free(tmp->path);
- free(tmp);
}
- break;
+
+ buf = join_path(path, dirsep, name);
+ free(name);
+ if (!buf) {
+ free(new_beg);
+ status = -1;
+ break;
+ }
+ status = glob_helper(buf, 1, UNKNOWN, UNKNOWN, new_beg, new_end, flags, func, arg);
+ free(buf);
+ free(new_beg);
+ if (status) break;
}
}
- p = m;
+
+ free(copy_beg);
}
- if (buf) free(buf);
- if (newpath) free(newpath);
+
return status;
}
-int
-ruby_glob(path, flags, func, arg)
+static int
+ruby_glob0(path, flags, func, arg)
const char *path;
int flags;
- int (*func) _((const char *, VALUE));
+ ruby_glob_func *func;
VALUE arg;
{
+ struct glob_pattern *list;
+ const char *root, *start;
+ char *buf;
+ int n;
+ int status;
+
+ start = root = path;
flags |= FNM_SYSCASE;
- return glob_helper(path, 0, flags & ~GLOB_VERBOSE, func, arg);
+#if defined DOSISH
+ root = rb_path_skip_prefix(root);
+#endif
+
+ if (root && *root == '/') root++;
+
+ n = root - start;
+ buf = GLOB_ALLOC_N(char, n + 1);
+ if (!buf) return -1;
+ MEMCPY(buf, start, char, n);
+ buf[n] = '\0';
+
+ list = glob_make_pattern(root, flags);
+ if (!list) {
+ free(buf);
+ return -1;
+ }
+ status = glob_helper(buf, 0, UNKNOWN, UNKNOWN, &list, &list + 1, flags, func, arg);
+ glob_free_pattern(list);
+ free(buf);
+
+ return status;
}
int
-ruby_globi(path, flags, func, arg)
+ruby_glob(path, flags, func, arg)
const char *path;
int flags;
- int (*func) _((const char *, VALUE));
+ ruby_glob_func *func;
VALUE arg;
{
- return glob_helper(path, 0, flags | FNM_CASEFOLD, func, arg);
+ return ruby_glob0(path, flags & ~GLOB_VERBOSE, func, arg);
}
static int rb_glob_caller _((const char *, VALUE));
@@ -1204,8 +1483,11 @@ rb_glob2(path, flags, func, arg)
args.func = func;
args.v = arg;
- flags |= FNM_SYSCASE;
- return glob_helper(path, 0, flags | GLOB_VERBOSE, rb_glob_caller, (VALUE)&args);
+ if (flags & FNM_SYSCASE) {
+ rb_warning("Dir.glob() ignores File::FNM_CASEFOLD");
+ }
+
+ return ruby_glob0(path, flags | GLOB_VERBOSE, rb_glob_caller, (VALUE)&args);
}
void
@@ -1215,19 +1497,10 @@ rb_glob(path, func, arg)
VALUE arg;
{
int status = rb_glob2(path, 0, func, arg);
- if (status) rb_jump_tag(status);
-}
-
-void
-rb_globi(path, func, arg)
- const char *path;
- void (*func) _((const char*, VALUE));
- VALUE arg;
-{
- int status = rb_glob2(path, FNM_CASEFOLD, func, arg);
- if (status) rb_jump_tag(status);
+ if (status) GLOB_JUMP_TAG(status);
}
+static void push_pattern _((const char* path, VALUE ary));
static void
push_pattern(path, ary)
const char *path;
@@ -1236,155 +1509,196 @@ push_pattern(path, ary)
rb_ary_push(ary, rb_tainted_str_new2(path));
}
-static int
-push_globs(ary, s, flags)
- VALUE ary;
- const char *s;
- int flags;
-{
- return rb_glob2(s, flags, push_pattern, ary);
-}
-
-static int
-push_braces(ary, str, flags)
- VALUE ary;
+int
+ruby_brace_expand(str, flags, func, arg)
const char *str;
int flags;
+ ruby_glob_func *func;
+ VALUE arg;
{
- char *buf = 0;
- char *b, *newbuf;
- const char *s, *p, *t;
- const char *lbrace, *rbrace;
- int nest = 0;
- int status = 0;
+ const int escape = !(flags & FNM_NOESCAPE);
+ const char *p = str;
+ const char *s = p;
+ const char *lbrace = 0, *rbrace = 0;
+ int nest = 0, status = 0;
- s = p = str;
- lbrace = rbrace = 0;
while (*p) {
- if (*p == '{') {
+ if (*p == '{' && nest++ == 0) {
lbrace = p;
- break;
}
- p++;
- }
- while (*p) {
- if (*p == '{') nest++;
- if (*p == '}' && --nest == 0) {
+ if (*p == '}' && --nest <= 0) {
rbrace = p;
break;
}
- p++;
+ if (*p == '\\' && escape) {
+ if (!*++p) break;
+ }
+ Inc(p);
}
if (lbrace && rbrace) {
- int len = strlen(s);
+ char *buf = GLOB_ALLOC_N(char, strlen(s) + 1);
+ long shift;
+
+ if (!buf) return -1;
+ memcpy(buf, s, lbrace-s);
+ shift = (lbrace-s);
p = lbrace;
- while (*p != '}') {
- t = p + 1;
- for (p = t; *p!='}' && *p!=','; p++) {
- /* skip inner braces */
- if (*p == '{') {
- nest = 1;
- while (*++p != '}' || --nest) {
- if (*p == '{') nest++;
- }
+ while (p < rbrace) {
+ const char *t = ++p;
+ nest = 0;
+ while (p < rbrace && !(*p == ',' && nest == 0)) {
+ if (*p == '{') nest++;
+ if (*p == '}') nest--;
+ if (*p == '\\' && escape) {
+ if (++p == rbrace) break;
}
+ Inc(p);
}
- newbuf = GLOB_REALLOC_N(buf, char, len+1);
- if (!newbuf) {
- status = -1;
- break;
- }
- buf = newbuf;
- memcpy(buf, s, lbrace-s);
- b = buf + (lbrace-s);
- memcpy(b, t, p-t);
- strcpy(b+(p-t), rbrace+1);
- status = push_braces(ary, buf, flags);
+ memcpy(buf+shift, t, p-t);
+ strcpy(buf+shift+(p-t), rbrace+1);
+ status = ruby_brace_expand(buf, flags, func, arg);
if (status) break;
}
+ free(buf);
}
- else {
- status = push_globs(ary, str, flags);
+ else if (!lbrace && !rbrace) {
+ status = (*func)(s, arg);
}
- if (buf) free(buf);
return status;
}
-#define isdelim(c) ((c)=='\0')
+struct brace_args {
+ ruby_glob_func *func;
+ VALUE value;
+ int flags;
+};
+
+static int glob_brace _((const char *, VALUE));
+static int
+glob_brace(path, val)
+ const char *path;
+ VALUE val;
+{
+ struct brace_args *arg = (struct brace_args *)val;
+
+ return ruby_glob0(path, arg->flags, arg->func, arg->value);
+}
+
+static int
+ruby_brace_glob0(str, flags, func, arg)
+ const char *str;
+ int flags;
+ ruby_glob_func *func;
+ VALUE arg;
+{
+ struct brace_args args;
+
+ args.func = func;
+ args.value = arg;
+ args.flags = flags;
+ return ruby_brace_expand(str, flags, glob_brace, (VALUE)&args);
+}
+
+int
+ruby_brace_glob(str, flags, func, arg)
+ const char *str;
+ int flags;
+ ruby_glob_func *func;
+ VALUE arg;
+{
+ return ruby_brace_glob0(str, flags & ~GLOB_VERBOSE, func, arg);
+}
+
+static int
+push_glob(VALUE ary, const char *str, int flags)
+{
+ struct glob_args args;
+
+ args.func = push_pattern;
+ args.v = ary;
+ return ruby_brace_glob0(str, flags | GLOB_VERBOSE, rb_glob_caller, (VALUE)&args);
+}
static VALUE
-rb_push_glob(str, flags)
+rb_push_glob(str, flags) /* '\0' is delimiter */
VALUE str;
int flags;
{
- const char *p, *pend, *buf;
- int nest, maxnest;
- int status = 0;
- int noescape = flags & FNM_NOESCAPE;
+ long offset = 0;
VALUE ary;
ary = rb_ary_new();
SafeStringValue(str);
- p = RSTRING(str)->ptr;
- pend = p + RSTRING(str)->len;
-
- while (p < pend) {
- nest = maxnest = 0;
- while (p < pend && isdelim(*p)) p++;
- buf = p;
- while (p < pend && !isdelim(*p)) {
- if (*p == '{') nest++, maxnest++;
- if (*p == '}') nest--;
- if (!noescape && *p == '\\') {
- if (++p == pend) break;
- }
+
+ while (offset < RSTRING_LEN(str)) {
+ int status = push_glob(ary, RSTRING(str)->ptr + offset, flags);
+ char *p, *pend;
+ if (status) GLOB_JUMP_TAG(status);
+ if (offset >= RSTRING_LEN(str)) break;
+ p = RSTRING(str)->ptr + offset;
+ p += strlen(p) + 1;
+ pend = RSTRING(str)->ptr + RSTRING_LEN(str);
+ while (p < pend && !*p)
p++;
- }
- if (maxnest == 0) {
- status = push_globs(ary, buf, flags);
- if (status) break;
- }
- else if (nest == 0) {
- status = push_braces(ary, buf, flags);
- if (status) break;
- }
- /* else unmatched braces */
+ offset = p - RSTRING(str)->ptr;
}
- if (status) GLOB_JUMP_TAG(status);
- if (rb_block_given_p()) {
- rb_ary_each(ary);
- return Qnil;
+
+ return ary;
+}
+
+static VALUE
+dir_globs(argc, argv, flags)
+ long argc;
+ VALUE *argv;
+ int flags;
+{
+ VALUE ary = rb_ary_new();
+ long i;
+
+ for (i = 0; i < argc; ++i) {
+ int status;
+ VALUE str = argv[i];
+ SafeStringValue(str);
+ status = push_glob(ary, RSTRING(str)->ptr, flags);
+ if (status) GLOB_JUMP_TAG(status);
}
+
return ary;
}
/*
* call-seq:
- * Dir[ string ] => array
+ * Dir[ array ] => array
+ * Dir[ string [, string ...] ] => array
*
* Equivalent to calling
- * <em>dir</em>.<code>glob(</code><i>string,</i><code>0)</code>.
+ * <code>Dir.glob(</code><i>array,</i><code>0)</code> and
+ * <code>Dir.glob([</code><i>string,...</i><code>],0)</code>.
*
*/
static VALUE
-dir_s_aref(obj, str)
- VALUE obj, str;
-{
- return rb_push_glob(str, 0);
-}
+dir_s_aref(int argc, VALUE *argv, VALUE obj)
+ {
+ if (argc == 1) {
+ return rb_push_glob(argv[0], 0);
+ }
+ return dir_globs(argc, argv, 0);
+ }
/*
* call-seq:
- * Dir.glob( string, [flags] ) => array
- * Dir.glob( string, [flags] ) {| filename | block } => nil
+ * Dir.glob( pattern, [flags] ) => array
+ * Dir.glob( pattern, [flags] ) {| filename | block } => nil
*
- * Returns the filenames found by expanding the pattern given in
- * <i>string</i>, either as an <i>array</i> or as parameters to the
- * block. Note that this pattern is not a regexp (it's closer to a
- * shell glob). See <code>File::fnmatch</code> for the meaning of
- * the <i>flags</i> parameter.
+ * Returns the filenames found by expanding <i>pattern</i> which is
+ * an +Array+ of the patterns or the pattern +String+, either as an
+ * <i>array</i> or as parameters to the block. Note that this pattern
+ * is not a regexp (it's closer to a shell glob). See
+ * <code>File::fnmatch</code> for the meaning of the <i>flags</i>
+ * parameter. Note that case sensitivity depends on your system (so
+ * <code>File::FNM_CASEFOLD</code> is ignored)
*
* <code>*</code>:: Matches any file. Can be restricted by
* other values in the glob. <code>*</code>
@@ -1439,7 +1753,7 @@ dir_s_glob(argc, argv, obj)
VALUE *argv;
VALUE obj;
{
- VALUE str, rflags;
+ VALUE str, rflags, ary;
int flags;
if (rb_scan_args(argc, argv, "11", &str, &rflags) == 2)
@@ -1447,7 +1761,20 @@ dir_s_glob(argc, argv, obj)
else
flags = 0;
- return rb_push_glob(str, flags);
+ ary = rb_check_array_type(str);
+ if (NIL_P(ary)) {
+ ary = rb_push_glob(str, flags);
+ }
+ else {
+ volatile VALUE v = ary;
+ ary = dir_globs(RARRAY_LEN(v), RARRAY_PTR(v), flags);
+ }
+
+ if (rb_block_given_p()) {
+ rb_ary_each(ary);
+ return Qnil;
+ }
+ return ary;
}
static VALUE
@@ -1488,6 +1815,7 @@ dir_foreach(io, dirname)
{
VALUE dir;
+ RETURN_ENUMERATOR(io, 1, &dirname);
dir = dir_open_dir(dirname);
rb_ensure(dir_each, dir, dir_close, dir);
return Qnil;
@@ -1534,6 +1862,8 @@ dir_entries(io, dirname)
* have <code>c</code> in them (including at
* the beginning or end). Equivalent to
* <code>/ .* /x</code> in regexp.
+ * <code>**</code>:: Matches directories recursively or files
+ * expansively.
* <code>?</code>:: Matches any one character. Equivalent to
* <code>/.{1}/</code> in regexp.
* <code>[set]</code>:: Matches any one character in +set+.
@@ -1546,31 +1876,52 @@ dir_entries(io, dirname)
* parameters. The same glob pattern and flags are used by
* <code>Dir::glob</code>.
*
- * File.fnmatch('cat', 'cat') #=> true
- * File.fnmatch('cat', 'category') #=> false
- * File.fnmatch('c{at,ub}s', 'cats') #=> false
- * File.fnmatch('c{at,ub}s', 'cubs') #=> false
- * File.fnmatch('c{at,ub}s', 'cat') #=> false
+ * File.fnmatch('cat', 'cat') #=> true : match entire string
+ * File.fnmatch('cat', 'category') #=> false : only match partial string
+ * File.fnmatch('c{at,ub}s', 'cats') #=> false : { } isn't supported
+ *
+ * File.fnmatch('c?t', 'cat') #=> true : '?' match only 1 character
+ * File.fnmatch('c??t', 'cat') #=> false : ditto
+ * File.fnmatch('c*', 'cats') #=> true : '*' match 0 or more characters
+ * File.fnmatch('c*t', 'c/a/b/t') #=> true : ditto
+ * File.fnmatch('ca[a-z]', 'cat') #=> true : inclusive bracket expression
+ * File.fnmatch('ca[^t]', 'cat') #=> false : exclusive bracket expression ('^' or '!')
+ *
+ * File.fnmatch('cat', 'CAT') #=> false : case sensitive
+ * File.fnmatch('cat', 'CAT', File::FNM_CASEFOLD) #=> true : case insensitive
+ *
+ * File.fnmatch('?', '/', File::FNM_PATHNAME) #=> false : wildcard doesn't match '/' on FNM_PATHNAME
+ * File.fnmatch('*', '/', File::FNM_PATHNAME) #=> false : ditto
+ * File.fnmatch('[/]', '/', File::FNM_PATHNAME) #=> false : ditto
+ *
+ * File.fnmatch('\?', '?') #=> true : escaped wildcard becomes ordinary
+ * File.fnmatch('\a', 'a') #=> true : escaped ordinary remains ordinary
+ * File.fnmatch('\a', '\a', File::FNM_NOESCAPE) #=> true : FNM_NOESACPE makes '\' ordinary
+ * File.fnmatch('[\?]', '?') #=> true : can escape inside bracket expression
+ *
+ * File.fnmatch('*', '.profile') #=> false : wildcard doesn't match leading
+ * File.fnmatch('*', '.profile', File::FNM_DOTMATCH) #=> true period by default.
+ * File.fnmatch('.*', '.profile') #=> true
+ *
+ * rbfiles = '**' '/' '*.rb' # you don't have to do like this. just write in single string.
+ * File.fnmatch(rbfiles, 'main.rb') #=> false
+ * File.fnmatch(rbfiles, './main.rb') #=> false
+ * File.fnmatch(rbfiles, 'lib/song.rb') #=> true
+ * File.fnmatch('**.rb', 'main.rb') #=> true
+ * File.fnmatch('**.rb', './main.rb') #=> false
+ * File.fnmatch('**.rb', 'lib/song.rb') #=> true
+ * File.fnmatch('*', 'dave/.profile') #=> true
*
- * File.fnmatch('c?t', 'cat') #=> true
- * File.fnmatch('c\?t', 'cat') #=> false
- * File.fnmatch('c??t', 'cat') #=> false
- * File.fnmatch('c*', 'cats') #=> true
- * File.fnmatch('c/ * FIXME * /t', 'c/a/b/c/t') #=> true
- * File.fnmatch('c*t', 'cat') #=> true
- * File.fnmatch('c\at', 'cat') #=> true
- * File.fnmatch('c\at', 'cat', File::FNM_NOESCAPE) #=> false
- * File.fnmatch('a?b', 'a/b') #=> true
- * File.fnmatch('a?b', 'a/b', File::FNM_PATHNAME) #=> false
+ * pattern = '*' '/' '*'
+ * File.fnmatch(pattern, 'dave/.profile', File::FNM_PATHNAME) #=> false
+ * File.fnmatch(pattern, 'dave/.profile', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true
*
- * File.fnmatch('*', '.profile') #=> false
- * File.fnmatch('*', '.profile', File::FNM_DOTMATCH) #=> true
- * File.fnmatch('*', 'dave/.profile') #=> true
- * File.fnmatch('*', 'dave/.profile', File::FNM_DOTMATCH) #=> true
- * File.fnmatch('*', 'dave/.profile', File::FNM_PATHNAME) #=> false
- * File.fnmatch('* / FIXME *', 'dave/.profile', File::FNM_PATHNAME) #=> false
- * STRICT = File::FNM_PATHNAME | File::FNM_DOTMATCH
- * File.fnmatch('* / FIXME *', 'dave/.profile', STRICT) #=> true
+ * pattern = '**' '/' 'foo'
+ * File.fnmatch(pattern, 'a/b/c/foo', File::FNM_PATHNAME) #=> true
+ * File.fnmatch(pattern, '/a/b/c/foo', File::FNM_PATHNAME) #=> true
+ * File.fnmatch(pattern, 'c:/a/b/c/foo', File::FNM_PATHNAME) #=> true
+ * File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME) #=> false
+ * File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true
*/
static VALUE
file_s_fnmatch(argc, argv, obj)
@@ -1621,6 +1972,7 @@ Init_Dir()
rb_define_method(rb_cDir,"initialize", dir_initialize, 1);
rb_define_method(rb_cDir,"path", dir_path, 0);
+ rb_define_method(rb_cDir,"inspect", dir_inspect, 0);
rb_define_method(rb_cDir,"read", dir_read, 0);
rb_define_method(rb_cDir,"each", dir_each, 0);
rb_define_method(rb_cDir,"rewind", dir_rewind, 0);
@@ -1640,7 +1992,7 @@ Init_Dir()
rb_define_singleton_method(rb_cDir,"unlink", dir_s_rmdir, 1);
rb_define_singleton_method(rb_cDir,"glob", dir_s_glob, -1);
- rb_define_singleton_method(rb_cDir,"[]", dir_s_aref, 1);
+ rb_define_singleton_method(rb_cDir,"[]", dir_s_aref, -1);
rb_define_singleton_method(rb_cFile,"fnmatch", file_s_fnmatch, -1);
rb_define_singleton_method(rb_cFile,"fnmatch?", file_s_fnmatch, -1);
diff --git a/dln.c b/dln.c
index fd59bdab8e..5ba25b6415 100644
--- a/dln.c
+++ b/dln.c
@@ -2,8 +2,8 @@
dln.c -
- $Author: matz $
- $Date: 2006/08/07 03:43:39 $
+ $Author$
+ $Date$
created at: Tue Jan 18 17:05:06 JST 1994
Copyright (C) 1993-2003 Yukihiro Matsumoto
@@ -81,19 +81,28 @@ char *getenv();
# include "macruby_private.h"
#endif
+#if defined(__APPLE__) && defined(__MACH__) /* Mac OS X */
+# if defined(HAVE_DLOPEN)
+ /* Mac OS X with dlopen (10.3 or later) */
+# define MACOSX_DLOPEN
+# else
+# define MACOSX_DYLD
+# endif
+#endif
+
#ifdef __BEOS__
# include <image.h>
#endif
#ifndef NO_DLN_LOAD
-#if defined(HAVE_DLOPEN) && !defined(USE_DLN_A_OUT) && !defined(_AIX) && !defined(__APPLE__) && !defined(_UNICOSMP)
+#if defined(HAVE_DLOPEN) && !defined(USE_DLN_A_OUT) && !defined(_AIX) && !defined(MACOSX_DYLD) && !defined(_UNICOSMP)
/* dynamic load with dlopen() */
# define USE_DLN_DLOPEN
#endif
#ifndef FUNCNAME_PATTERN
-# if defined(__hp9000s300) || (defined(__NetBSD__) && !defined(__ELF__)) || defined(__BORLANDC__) || (defined(__FreeBSD__) && !defined(__ELF__)) || (defined(__OpenBSD__) && !defined(__ELF__)) || defined(NeXT) || defined(__WATCOMC__) || defined(__APPLE__)
+# if defined(__hp9000s300) || (defined(__NetBSD__) && !defined(__ELF__)) || defined(__BORLANDC__) || (defined(__FreeBSD__) && !defined(__ELF__)) || (defined(__OpenBSD__) && !defined(__ELF__)) || defined(NeXT) || defined(__WATCOMC__) || defined(MACOSX_DYLD)
# define FUNCNAME_PATTERN "_Init_%s"
# else
# define FUNCNAME_PATTERN "Init_%s"
@@ -636,7 +645,7 @@ load_1(fd, disp, need_init)
long disp;
const char *need_init;
{
- static char *libc = LIBC_NAME;
+ static const char *libc = LIBC_NAME;
struct exec hdr;
struct relocation_info *reloc = NULL;
long block = 0;
@@ -1141,7 +1150,7 @@ dln_sym(name)
#endif
#endif
#else
-#ifdef __APPLE__
+#ifdef MACOSX_DYLD
#include <mach-o/dyld.h>
#endif
#endif
@@ -1403,7 +1412,7 @@ dln_load(file)
}
#endif /* _AIX */
-#if defined(NeXT) || defined(__APPLE__)
+#if defined(NeXT) || defined(MACOSX_DYLD)
#define DLN_DEFINED
/*----------------------------------------------------
By SHIROYAMA Takayuki Psi@fortune.nest.or.jp
@@ -1527,7 +1536,7 @@ dln_load(file)
}
#endif /* __BEOS__*/
-#ifdef __MACOS__
+#ifdef __MACOS__ /* Mac OS 9 or before */
# define DLN_DEFINED
{
OSErr err;
@@ -1680,31 +1689,31 @@ static char fbuf[MAXPATHLEN];
static char *
dln_find_1(fname, path, exe_flag)
- char *fname;
- char *path;
+ const char *fname;
+ const char *path;
int exe_flag; /* non 0 if looking for executable. */
{
- register char *dp;
- register char *ep;
+ register const char *dp;
+ register const char *ep;
register char *bp;
struct stat st;
#ifdef __MACOS__
const char* mac_fullpath;
#endif
- if (!fname) return fname;
- if (fname[0] == '/') return fname;
+ if (!fname) return (char *)fname;
+ if (fname[0] == '/') return (char *)fname;
if (strncmp("./", fname, 2) == 0 || strncmp("../", fname, 3) == 0)
- return fname;
- if (exe_flag && strchr(fname, '/')) return fname;
+ return (char *)fname;
+ if (exe_flag && strchr(fname, '/')) return (char *)fname;
#ifdef DOSISH
- if (fname[0] == '\\') return fname;
+ if (fname[0] == '\\') return (char *)fname;
# ifdef DOSISH_DRIVE_LETTER
- if (strlen(fname) > 2 && fname[1] == ':') return fname;
+ if (strlen(fname) > 2 && fname[1] == ':') return (char *)fname;
# endif
if (strncmp(".\\", fname, 2) == 0 || strncmp("..\\", fname, 3) == 0)
- return fname;
- if (exe_flag && strchr(fname, '\\')) return fname;
+ return (char *)fname;
+ if (exe_flag && strchr(fname, '\\')) return (char *)fname;
#endif
for (dp = path;; dp = ++ep) {
@@ -1772,26 +1781,9 @@ dln_find_1(fname, path, exe_flag)
}
memcpy(bp, fname, i + 1);
-#ifndef __MACOS__
- if (stat(fbuf, &st) == 0) {
- if (exe_flag == 0) return fbuf;
- /* looking for executable */
- if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0)
- return fbuf;
- }
-#else
- if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf)) {
- if (exe_flag == 0) return mac_fullpath;
- /* looking for executable */
- if (stat(mac_fullpath, &st) == 0) {
- if (!S_ISDIR(st.st_mode) && eaccess(mac_fullpath, X_OK) == 0)
- return mac_fullpath;
- }
- }
-#endif
#if defined(DOSISH)
if (exe_flag) {
- static const char *extension[] = {
+ static const char extension[][5] = {
#if defined(MSDOS)
".com", ".exe", ".bat",
#if defined(DJGPP)
@@ -1804,11 +1796,10 @@ dln_find_1(fname, path, exe_flag)
".r", ".R", ".x", ".X", ".bat", ".BAT",
/* __human68k__ */
#endif
- (char *) NULL
};
int j;
- for (j = 0; extension[j]; j++) {
+ for (j = 0; j < sizeof(extension) / sizeof(extension[0]); j++) {
if (fspace < strlen(extension[j])) {
fprintf(stderr, "openpath: pathname too long (ignored)\n");
fprintf(stderr, "\tDirectory \"%.*s\"\n", (int) (bp - fbuf), fbuf);
@@ -1825,9 +1816,28 @@ dln_find_1(fname, path, exe_flag)
#endif
}
+ goto next;
}
#endif /* MSDOS or _WIN32 or __human68k__ or __EMX__ */
+#ifndef __MACOS__
+ if (stat(fbuf, &st) == 0) {
+ if (exe_flag == 0) return fbuf;
+ /* looking for executable */
+ if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0)
+ return fbuf;
+ }
+#else
+ if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf)) {
+ if (exe_flag == 0) return mac_fullpath;
+ /* looking for executable */
+ if (stat(mac_fullpath, &st) == 0) {
+ if (!S_ISDIR(st.st_mode) && eaccess(mac_fullpath, X_OK) == 0)
+ return mac_fullpath;
+ }
+ }
+#endif
+
next:
/* if not, and no other alternatives, life is bleak */
if (*ep == '\0') {
diff --git a/dln.h b/dln.h
index 3d52ea2827..182cf9f9f4 100644
--- a/dln.h
+++ b/dln.h
@@ -2,8 +2,8 @@
dln.h -
- $Author: michal $
- $Date: 2003/01/16 07:34:01 $
+ $Author$
+ $Date$
created at: Wed Jan 19 16:53:09 JST 1994
Copyright (C) 1993-2003 Yukihiro Matsumoto
diff --git a/doc/NEWS b/doc/NEWS-1.8.0
index b4445fa59f..b4445fa59f 100644
--- a/doc/NEWS
+++ b/doc/NEWS-1.8.0
diff --git a/doc/forwardable.rd b/doc/forwardable.rd
index f9c8234761..7272c374b6 100644
--- a/doc/forwardable.rd
+++ b/doc/forwardable.rd
@@ -1,8 +1,8 @@
-- forwardable.rb
$Release Version: 1.1 $
- $Revision: 1.2 $
- $Date: 2001/05/07 23:52:57 $
+ $Revision$
+ $Date$
Original version by Tosh
=begin
diff --git a/doc/forwardable.rd.ja b/doc/forwardable.rd.ja
index a56823dd1a..d928fddc5e 100644
--- a/doc/forwardable.rd.ja
+++ b/doc/forwardable.rd.ja
@@ -1,7 +1,7 @@
-- forwatable.rb
$Release Version: 1.1 $
- $Revision: 1.1 $
- $Date: 2001/07/19 05:42:06 $
+ $Revision$
+ $Date$
=begin
= Forwardable
diff --git a/doc/irb/irb-tools.rd.ja b/doc/irb/irb-tools.rd.ja
index 38145576dc..64d9ab29c8 100644
--- a/doc/irb/irb-tools.rd.ja
+++ b/doc/irb/irb-tools.rd.ja
@@ -1,7 +1,7 @@
irb´ØÏ¢¤ª¤Þ¤±¥³¥Þ¥ó¥É¤È¥é¥¤¥Ö¥é¥ê
$Release Version: 0.7.1 $
- $Revision: 1.1 $
- $Date: 2001/07/19 05:42:06 $
+ $Revision$
+ $Date$
by Keiju ISHITSUKA(Nihon Rational Co.,Ltd.)
=begin
diff --git a/doc/irb/irb.rd b/doc/irb/irb.rd
index f56e8b60e0..a42cd46680 100644
--- a/doc/irb/irb.rd
+++ b/doc/irb/irb.rd
@@ -1,7 +1,7 @@
irb -- interactive ruby
$Release Version: 0.9 $
- $Revision: 1.6 $
- $Date: 2003/07/31 16:34:07 $
+ $Revision$
+ $Date$
by Keiju ISHITSUKA(keiju@ishitsuka.com)
by gotoken-san who is original translater from japanese version
diff --git a/doc/irb/irb.rd.ja b/doc/irb/irb.rd.ja
index aa3c0e13aa..338dcc644e 100644
--- a/doc/irb/irb.rd.ja
+++ b/doc/irb/irb.rd.ja
@@ -1,7 +1,7 @@
irb -- interactive ruby
$Release Version: 0.9.5 $
- $Revision: 1.3.2.1 $
- $Date: 2005/04/19 19:24:56 $
+ $Revision$
+ $Date$
by Keiju ISHITSUKA(keiju@ruby-lang.org)
=begin
= irb¤È¤Ï?
diff --git a/doc/shell.rd b/doc/shell.rd
index ae6855cbd8..02ee1b020a 100644
--- a/doc/shell.rd
+++ b/doc/shell.rd
@@ -1,7 +1,7 @@
-- shell.rb
$Release Version: 0.6.0 $
- $Revision: 1.2 $
- $Date: 2001/05/17 10:09:49 $
+ $Revision$
+ $Date$
by Keiju ISHITSUKA(keiju@ishitsuka.com)
=begin
diff --git a/doc/shell.rd.ja b/doc/shell.rd.ja
index aab9e5c7d2..073e71ea42 100644
--- a/doc/shell.rd.ja
+++ b/doc/shell.rd.ja
@@ -1,7 +1,7 @@
-- shell.rb
$Release Version: 0.6.0 $
- $Revision: 1.1 $
- $Date: 2001/07/19 05:42:06 $
+ $Revision$
+ $Date$
by Keiju ISHITSUKA(keiju@ishitsuka.com)
=begin
diff --git a/enum.c b/enum.c
index 112a5f820b..a4863eaa96 100644
--- a/enum.c
+++ b/enum.c
@@ -2,8 +2,8 @@
enum.c -
- $Author: drbrain $
- $Date: 2006/06/15 01:24:40 $
+ $Author$
+ $Date$
created at: Fri Oct 1 15:15:19 JST 1993
Copyright (C) 1993-2003 Yukihiro Matsumoto
@@ -15,7 +15,43 @@
#include "util.h"
VALUE rb_mEnumerable;
-static ID id_each, id_eqq, id_cmp;
+static ID id_each, id_eqq, id_cmp, id_size;
+
+struct iter_method_arg {
+ VALUE obj;
+ ID mid;
+ int argc;
+ VALUE *argv;
+};
+
+static VALUE iterate_method _((VALUE obj));
+static VALUE
+iterate_method(obj)
+ VALUE obj;
+{
+ struct iter_method_arg *arg;
+
+ arg = (struct iter_method_arg *)obj;
+ return rb_funcall2(arg->obj, arg->mid, arg->argc, arg->argv);
+}
+
+VALUE
+rb_block_call(obj, mid, argc, argv, bl_proc, data2)
+ VALUE obj;
+ ID mid;
+ int argc;
+ VALUE *argv;
+ VALUE (*bl_proc) (ANYARGS);
+ VALUE data2;
+{
+ struct iter_method_arg arg;
+
+ arg.obj = obj;
+ arg.mid = mid;
+ arg.argc = argc;
+ arg.argv = argv;
+ return rb_iterate(iterate_method, (VALUE)&arg, bl_proc, data2);
+}
VALUE
rb_each(obj)
@@ -48,18 +84,18 @@ grep_iter_i(i, arg)
* call-seq:
* enum.grep(pattern) => array
* enum.grep(pattern) {| obj | block } => array
- *
+ *
* Returns an array of every element in <i>enum</i> for which
* <code>Pattern === element</code>. If the optional <em>block</em> is
* supplied, each matching element is passed to it, and the block's
* result is stored in the output array.
- *
+ *
* (1..100).grep 38..44 #=> [38, 39, 40, 41, 42, 43, 44]
* c = IO.constants
* c.grep(/SEEK/) #=> ["SEEK_END", "SEEK_SET", "SEEK_CUR"]
* res = c.grep(/SEEK/) {|v| IO.const_get(v) }
* res #=> [2, 0, 1]
- *
+ *
*/
static VALUE
@@ -73,10 +109,99 @@ enum_grep(obj, pat)
arg[1] = ary;
rb_iterate(rb_each, obj, rb_block_given_p() ? grep_iter_i : grep_i, (VALUE)arg);
-
+
return ary;
}
+static VALUE count_i _((VALUE, VALUE));
+static VALUE
+count_i(i, memop)
+ VALUE i, memop;
+{
+ VALUE *memo = (VALUE*)memop;
+
+ if (rb_equal(i, memo[1])) {
+ memo[0]++;
+ }
+ return Qnil;
+}
+
+static VALUE count_iter_i _((VALUE, VALUE));
+static VALUE
+count_iter_i(i, memop)
+ VALUE i, memop;
+{
+ VALUE *memo = (VALUE*)memop;
+
+ if (RTEST(rb_yield(i))) {
+ memo[0]++;
+ }
+ return Qnil;
+}
+
+static VALUE count_all_i _((VALUE, VALUE));
+static VALUE
+count_all_i(i, memop)
+ VALUE i, memop;
+{
+ VALUE *memo = (VALUE*)memop;
+
+ memo[0]++;
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * enum.count => int
+ * enum.count(item) => int
+ * enum.count {| obj | block } => int
+ *
+ * Returns the number of items in <i>enum</i>, where #size is called
+ * if it responds to it, otherwise the items are counted through
+ * enumeration. If an argument is given, counts the number of items
+ * in <i>enum</i>, for which equals to <i>item</i>. If a block is
+ * given, counts the number of elements yielding a true value.
+ *
+ * ary = [1, 2, 4, 2]
+ * ary.count # => 4
+ * ary.count(2) # => 2
+ * ary.count{|x|x%2==0} # => 3
+ *
+ */
+
+static VALUE
+enum_count(argc, argv, obj)
+ int argc;
+ VALUE *argv;
+ VALUE obj;
+{
+ VALUE memo[2]; /* [count, condition value] */
+ rb_block_call_func *func;
+
+ if (argc == 0) {
+ if (rb_block_given_p()) {
+ func = count_iter_i;
+ }
+ else {
+ if (rb_respond_to(obj, id_size)) {
+ return rb_funcall(obj, id_size, 0, 0);
+ }
+ func = count_all_i;
+ }
+ }
+ else {
+ rb_scan_args(argc, argv, "1", &memo[1]);
+ if (rb_block_given_p()) {
+ rb_warn("given block not used");
+ }
+ func = count_i;
+ }
+
+ memo[0] = 0;
+ rb_block_call(obj, id_each, 0, 0, func, (VALUE)&memo);
+ return INT2NUM(memo[0]);
+}
+
static VALUE
find_i(i, memo)
VALUE i;
@@ -93,15 +218,15 @@ find_i(i, memo)
* call-seq:
* enum.detect(ifnone = nil) {| obj | block } => obj or nil
* enum.find(ifnone = nil) {| obj | block } => obj or nil
- *
+ *
* Passes each entry in <i>enum</i> to <em>block</em>. Returns the
* first for which <em>block</em> is not <code>false</code>. If no
* object matches, calls <i>ifnone</i> and returns its result when it
* is specified, or returns <code>nil</code>
- *
+ *
* (1..10).detect {|i| i % 5 == 0 and i % 7 == 0 } #=> nil
* (1..100).detect {|i| i % 5 == 0 and i % 7 == 0 } #=> 35
- *
+ *
*/
static VALUE
@@ -114,6 +239,7 @@ enum_find(argc, argv, obj)
VALUE if_none;
rb_scan_args(argc, argv, "01", &if_none);
+ RETURN_ENUMERATOR(obj, argc, argv);
rb_iterate(rb_each, obj, find_i, (VALUE)&memo);
if (memo != Qundef) {
return memo;
@@ -124,6 +250,81 @@ enum_find(argc, argv, obj)
return Qnil;
}
+static VALUE find_index_i _((VALUE, VALUE));
+static VALUE
+find_index_i(i, memop)
+ VALUE i;
+ VALUE memop;
+{
+ VALUE *memo = (VALUE*)memop;
+
+ if (rb_equal(i, memo[2])) {
+ memo[0] = UINT2NUM(memo[1]);
+ rb_iter_break();
+ }
+ memo[1]++;
+ return Qnil;
+}
+
+static VALUE find_index_iter_i _((VALUE, VALUE));
+static VALUE
+find_index_iter_i(i, memop)
+ VALUE i;
+ VALUE memop;
+{
+ VALUE *memo = (VALUE*)memop;
+
+ if (RTEST(rb_yield(i))) {
+ memo[0] = UINT2NUM(memo[1]);
+ rb_iter_break();
+ }
+ memo[1]++;
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * enum.find_index(value) => int or nil
+ * enum.find_index {| obj | block } => int or nil
+ *
+ * Compares each entry in <i>enum</i> with <em>value</em> or passes
+ * to <em>block</em>. Returns the index for the first for which the
+ * evaluated value is non-false. If no object matches, returns
+ * <code>nil</code>
+ *
+ * (1..10).find_index {|i| i % 5 == 0 and i % 7 == 0 } #=> nil
+ * (1..100).find_index {|i| i % 5 == 0 and i % 7 == 0 } #=> 34
+ * (1..100).find_index(50) #=> 49
+ *
+ */
+
+static VALUE
+enum_find_index(argc, argv, obj)
+ int argc;
+ VALUE *argv;
+ VALUE obj;
+{
+ VALUE memo[3]; /* [return value, current index, condition value] */
+ rb_block_call_func *func;
+
+ if (argc == 0) {
+ RETURN_ENUMERATOR(obj, 0, 0);
+ func = find_index_iter_i;
+ }
+ else {
+ rb_scan_args(argc, argv, "1", &memo[2]);
+ if (rb_block_given_p()) {
+ rb_warn("given block not used");
+ }
+ func = find_index_i;
+ }
+
+ memo[0] = Qnil;
+ memo[1] = 0;
+ rb_block_call(obj, id_each, 0, 0, func, (VALUE)memo);
+ return memo[0];
+}
+
static VALUE
find_all_i(i, ary)
VALUE i, ary;
@@ -138,13 +339,13 @@ find_all_i(i, ary)
* call-seq:
* enum.find_all {| obj | block } => array
* enum.select {| obj | block } => array
- *
+ *
* Returns an array containing all elements of <i>enum</i> for which
* <em>block</em> is not <code>false</code> (see also
* <code>Enumerable#reject</code>).
- *
+ *
* (1..10).find_all {|i| i % 3 == 0 } #=> [3, 6, 9]
- *
+ *
*/
static VALUE
@@ -152,7 +353,8 @@ enum_find_all(obj)
VALUE obj;
{
VALUE ary = rb_ary_new();
-
+
+ RETURN_ENUMERATOR(obj, 0, 0);
rb_iterate(rb_each, obj, find_all_i, ary);
return ary;
@@ -171,12 +373,12 @@ reject_i(i, ary)
/*
* call-seq:
* enum.reject {| obj | block } => array
- *
+ *
* Returns an array for all elements of <i>enum</i> for which
* <em>block</em> is false (see also <code>Enumerable#find_all</code>).
- *
+ *
* (1..10).reject {|i| i % 3 == 0 } #=> [1, 2, 4, 5, 7, 8, 10]
- *
+ *
*/
static VALUE
@@ -184,7 +386,8 @@ enum_reject(obj)
VALUE obj;
{
VALUE ary = rb_ary_new();
-
+
+ RETURN_ENUMERATOR(obj, 0, 0);
rb_iterate(rb_each, obj, reject_i, ary);
return ary;
@@ -212,13 +415,13 @@ collect_all(i, ary)
* call-seq:
* enum.collect {| obj | block } => array
* enum.map {| obj | block } => array
- *
+ *
* Returns a new array with the results of running <em>block</em> once
* for every element in <i>enum</i>.
- *
+ *
* (1..4).collect {|i| i*i } #=> [1, 4, 9, 16]
* (1..4).collect { "cat" } #=> ["cat", "cat", "cat", "cat"]
- *
+ *
*/
static VALUE
@@ -236,80 +439,135 @@ enum_collect(obj)
* call-seq:
* enum.to_a => array
* enum.entries => array
- *
+ *
* Returns an array containing the items in <i>enum</i>.
- *
+ *
* (1..7).to_a #=> [1, 2, 3, 4, 5, 6, 7]
* { 'a'=>1, 'b'=>2, 'c'=>3 }.to_a #=> [["a", 1], ["b", 2], ["c", 3]]
*/
static VALUE
-enum_to_a(obj)
+enum_to_a(argc, argv, obj)
+ int argc;
+ VALUE *argv;
VALUE obj;
{
VALUE ary = rb_ary_new();
- rb_iterate(rb_each, obj, collect_all, ary);
+ rb_block_call(obj, id_each, argc, argv, collect_all, ary);
return ary;
}
+static VALUE inject_i _((VALUE, VALUE));
static VALUE
-inject_i(i, memo)
+inject_i(i, p)
VALUE i;
- VALUE *memo;
+ VALUE p;
{
- if (*memo == Qundef) {
- *memo = i;
+ VALUE *memo = (VALUE *)p;
+ if (memo[0] == Qundef) {
+ memo[0] = i;
+ }
+ else {
+ memo[0] = rb_yield_values(2, memo[0], i);
+ }
+ return Qnil;
+}
+
+static VALUE inject_op_i _((VALUE, VALUE));
+static VALUE
+inject_op_i(i, p)
+ VALUE i;
+ VALUE p;
+{
+ VALUE *memo = (VALUE *)p;
+
+ if (memo[0] == Qundef) {
+ memo[0] = i;
}
else {
- *memo = rb_yield_values(2, *memo, i);
+ memo[0] = rb_funcall(memo[0], (ID)memo[1], 1, i);
}
return Qnil;
}
/*
* call-seq:
+ * enum.inject(initial, sym) => obj
+ * enum.inject(sym) => obj
* enum.inject(initial) {| memo, obj | block } => obj
* enum.inject {| memo, obj | block } => obj
- *
- * Combines the elements of <i>enum</i> by applying the block to an
- * accumulator value (<i>memo</i>) and each element in turn. At each
- * step, <i>memo</i> is set to the value returned by the block. The
- * first form lets you supply an initial value for <i>memo</i>. The
- * second form uses the first element of the collection as a the
- * initial value (and skips that element while iterating).
- *
+ *
+ * enum.reduce(initial, sym) => obj
+ * enum.reduce(sym) => obj
+ * enum.reduce(initial) {| memo, obj | block } => obj
+ * enum.reduce {| memo, obj | block } => obj
+ *
+ * Combines all elements of <i>enum</i> by applying a binary
+ * operation, specified by a block or a symbol that names a
+ * method or operator.
+ *
+ * If you specify a block, then for each element in <i>enum<i>
+ * the block is passed an accumulator value (<i>memo</i>) and the element.
+ * If you specify a symbol instead, then each element in the collection
+ * will be passed to the named method of <i>memo</i>.
+ * In either case, the result becomes the new value for <i>memo</i>.
+ * At the end of the iteration, the final value of <i>memo</i> is the
+ * return value fo the method.
+ *
+ * If you do not explicitly specify an <i>initial</i> value for <i>memo</i>,
+ * then uses the first element of collection is used as the initial value
+ * of <i>memo</i>.
+ *
+ * Examples:
+ *
* # Sum some numbers
- * (5..10).inject {|sum, n| sum + n } #=> 45
+ * (5..10).reduce(:+) #=> 45
+ * # Same using a block and inject
+ * (5..10).inject {|sum, n| sum + n } #=> 45
* # Multiply some numbers
- * (5..10).inject(1) {|product, n| product * n } #=> 151200
- *
+ * (5..10).reduce(1, :*) #=> 151200
+ * # Same using a block
+ * (5..10).inject(1) {|product, n| product * n } #=> 151200
* # find the longest word
* longest = %w{ cat sheep bear }.inject do |memo,word|
* memo.length > word.length ? memo : word
* end
- * longest #=> "sheep"
- *
- * # find the length of the longest word
- * longest = %w{ cat sheep bear }.inject(0) do |memo,word|
- * memo >= word.length ? memo : word.length
- * end
- * longest #=> 5
- *
+ * longest #=> "sheep"
+ *
*/
-
static VALUE
enum_inject(argc, argv, obj)
int argc;
- VALUE *argv, obj;
+ VALUE *argv;
+ VALUE obj;
{
- VALUE memo = Qundef;
-
- if (rb_scan_args(argc, argv, "01", &memo) == 0)
- memo = Qundef;
- rb_iterate(rb_each, obj, inject_i, (VALUE)&memo);
- if (memo == Qundef) return Qnil;
- return memo;
+ VALUE memo[2];
+ rb_block_call_func *iter = inject_i;
+
+ switch (rb_scan_args(argc, argv, "02", &memo[0], &memo[1])) {
+ case 0:
+ memo[0] = Qundef;
+ break;
+ case 1:
+ if (rb_block_given_p()) {
+ break;
+ }
+ memo[1] = (VALUE)rb_to_id(memo[0]);
+ memo[0] = Qundef;
+ iter = inject_op_i;
+ break;
+ case 2:
+ if (rb_block_given_p()) {
+ rb_warning("given block not used");
+ }
+ memo[1] = (VALUE)rb_to_id(memo[1]);
+ iter = inject_op_i;
+ break;
+ }
+ rb_block_call(obj, id_each, 0, 0, iter, (VALUE)memo);
+ if (memo[0] == Qundef) return Qnil;
+ return memo[0];
}
static VALUE
@@ -328,13 +586,13 @@ partition_i(i, ary)
/*
* call-seq:
* enum.partition {| obj | block } => [ true_array, false_array ]
- *
+ *
* Returns two arrays, the first containing the elements of
* <i>enum</i> for which the block evaluates to true, the second
* containing the rest.
- *
+ *
* (1..6).partition {|i| (i&1).zero?} #=> [[2, 4, 6], [1, 3, 5]]
- *
+ *
*/
static VALUE
@@ -343,6 +601,8 @@ enum_partition(obj)
{
VALUE ary[2];
+ RETURN_ENUMERATOR(obj, 0, 0);
+
ary[0] = rb_ary_new();
ary[1] = rb_ary_new();
rb_iterate(rb_each, obj, partition_i, (VALUE)ary);
@@ -350,11 +610,114 @@ enum_partition(obj)
return rb_assoc_new(ary[0], ary[1]);
}
+static VALUE
+group_by_i(i, hash)
+ VALUE i;
+ VALUE hash;
+{
+ VALUE group = rb_yield(i);
+ VALUE values;
+
+ values = rb_hash_aref(hash, group);
+ if (NIL_P(values)) {
+ values = rb_ary_new3(1, i);
+ rb_hash_aset(hash, group, values);
+ }
+ else {
+ rb_ary_push(values, i);
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * enum.group_by {| obj | block } => a_hash
+ *
+ * Returns a hash, which keys are evaluated result from the
+ * block, and values are arrays of elements in <i>enum</i>
+ * corresponding to the key.
+ *
+ * (1..6).group_by {|i| i%3} #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}
+ *
+ */
+
+static VALUE
+enum_group_by(obj)
+ VALUE obj;
+{
+ VALUE hash;
+
+ RETURN_ENUMERATOR(obj, 0, 0);
+
+ hash = rb_hash_new();
+ rb_block_call(obj, id_each, 0, 0, group_by_i, hash);
+
+ return hash;
+}
+
+static VALUE
+first_i(i, ary)
+ VALUE i;
+ VALUE *ary;
+{
+ if (NIL_P(ary[0])) {
+ ary[1] = i;
+ rb_iter_break();
+ }
+ else {
+ long n = NUM2LONG(ary[0]);
+
+ rb_ary_push(ary[1], i);
+ n--;
+ if (n <= 0) {
+ rb_iter_break();
+ }
+ ary[0] = INT2NUM(n);
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * enum.first -> obj or nil
+ * enum.first(n) -> an_array
+ *
+ * Returns the first element, or the first +n+ elements, of the enumerable.
+ * If the enumerable is empty, the first form returns <code>nil</code>, and the
+ * second form returns an empty array.
+ *
+ */
+
+static VALUE
+enum_first(argc, argv, obj)
+ int argc;
+ VALUE *argv;
+ VALUE obj;
+{
+ VALUE n, ary[2];
+
+ if (argc == 0) {
+ ary[0] = ary[1] = Qnil;
+ }
+ else {
+ long len;
+ rb_scan_args(argc, argv, "01", &n);
+ len = NUM2LONG(n);
+ if (len == 0) return rb_ary_new2(0);
+ ary[0] = INT2NUM(len);
+ ary[1] = rb_ary_new2(len);
+ }
+ rb_block_call(obj, id_each, 0, 0, first_i, (VALUE)ary);
+
+ return ary[1];
+}
+
+
/*
* call-seq:
* enum.sort => array
* enum.sort {| a, b | block } => array
- *
+ *
* Returns an array containing the items in <i>enum</i> sorted,
* either according to their own <code><=></code> method, or by using
* the results of the supplied block. The block should return -1, 0, or
@@ -362,7 +725,7 @@ enum_partition(obj)
* Ruby 1.8, the method <code>Enumerable#sort_by</code> implements a
* built-in Schwartzian Transform, useful when key computation or
* comparison is expensive..
- *
+ *
* %w(rhea kea flea).sort #=> ["flea", "kea", "rhea"]
* (1..10).sort {|a,b| b <=> a} #=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
*/
@@ -371,7 +734,7 @@ static VALUE
enum_sort(obj)
VALUE obj;
{
- return rb_ary_sort(enum_to_a(obj));
+ return rb_ary_sort(enum_to_a(0, 0, obj));
}
static VALUE
@@ -391,65 +754,70 @@ sort_by_i(i, ary)
}
static int
-sort_by_cmp(aa, bb)
+sort_by_cmp(aa, bb, data)
NODE **aa, **bb;
+ void *data;
{
VALUE a = aa[0]->u1.value;
VALUE b = bb[0]->u1.value;
+ VALUE ary = (VALUE)data;
+ if (RBASIC(ary)->klass) {
+ rb_raise(rb_eRuntimeError, "sort_by reentered");
+ }
return rb_cmpint(rb_funcall(a, id_cmp, 1, b), a, b);
}
/*
* call-seq:
* enum.sort_by {| obj | block } => array
- *
+ *
* Sorts <i>enum</i> using a set of keys generated by mapping the
* values in <i>enum</i> through the given block.
- *
+ *
* %w{ apple pear fig }.sort_by {|word| word.length}
#=> ["fig", "pear", "apple"]
- *
+ *
* The current implementation of <code>sort_by</code> generates an
* array of tuples containing the original collection element and the
* mapped value. This makes <code>sort_by</code> fairly expensive when
* the keysets are simple
- *
+ *
* require 'benchmark'
* include Benchmark
- *
+ *
* a = (1..100000).map {rand(100000)}
- *
+ *
* bm(10) do |b|
* b.report("Sort") { a.sort }
* b.report("Sort by") { a.sort_by {|a| a} }
* end
- *
+ *
* <em>produces:</em>
- *
+ *
* user system total real
* Sort 0.180000 0.000000 0.180000 ( 0.175469)
* Sort by 1.980000 0.040000 2.020000 ( 2.013586)
- *
+ *
* However, consider the case where comparing the keys is a non-trivial
* operation. The following code sorts some files on modification time
* using the basic <code>sort</code> method.
- *
+ *
* files = Dir["*"]
* sorted = files.sort {|a,b| File.new(a).mtime <=> File.new(b).mtime}
* sorted #=> ["mon", "tues", "wed", "thurs"]
- *
+ *
* This sort is inefficient: it generates two new <code>File</code>
* objects during every comparison. A slightly better technique is to
* use the <code>Kernel#test</code> method to generate the modification
* times directly.
- *
+ *
* files = Dir["*"]
* sorted = files.sort { |a,b|
* test(?M, a) <=> test(?M, b)
* }
* sorted #=> ["mon", "tues", "wed", "thurs"]
- *
+ *
* This still generates many unnecessary <code>Time</code> objects. A
* more efficient technique is to cache the sort keys (modification
* times in this case) before the sort. Perl users often call this
@@ -457,14 +825,14 @@ sort_by_cmp(aa, bb)
* construct a temporary array, where each element is an array
* containing our sort key along with the filename. We sort this array,
* and then extract the filename from the result.
- *
+ *
* sorted = Dir["*"].collect { |f|
* [test(?M, f), f]
* }.sort.collect { |f| f[1] }
* sorted #=> ["mon", "tues", "wed", "thurs"]
- *
+ *
* This is exactly what <code>sort_by</code> does internally.
- *
+ *
* sorted = Dir["*"].sort_by {|f| test(?M, f)}
* sorted #=> ["mon", "tues", "wed", "thurs"]
*/
@@ -476,6 +844,8 @@ enum_sort_by(obj)
VALUE ary;
long i;
+ RETURN_ENUMERATOR(obj, 0, 0);
+
if (TYPE(obj) == T_ARRAY) {
ary = rb_ary_new2(RARRAY(obj)->len);
}
@@ -485,7 +855,8 @@ enum_sort_by(obj)
RBASIC(ary)->klass = 0;
rb_iterate(rb_each, obj, sort_by_i, ary);
if (RARRAY(ary)->len > 1) {
- qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE), sort_by_cmp, 0);
+ qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE),
+ sort_by_cmp, (void *)ary);
}
if (RBASIC(ary)->klass) {
rb_raise(rb_eRuntimeError, "sort_by reentered");
@@ -498,11 +869,11 @@ enum_sort_by(obj)
}
static VALUE
-all_iter_i(i, memo)
+all_i(i, memo)
VALUE i;
VALUE *memo;
{
- if (!RTEST(rb_yield(i))) {
+ if (!RTEST(i)) {
*memo = Qfalse;
rb_iter_break();
}
@@ -510,32 +881,28 @@ all_iter_i(i, memo)
}
static VALUE
-all_i(i, memo)
+all_iter_i(i, memo)
VALUE i;
VALUE *memo;
{
- if (!RTEST(i)) {
- *memo = Qfalse;
- rb_iter_break();
- }
- return Qnil;
+ return all_i(rb_yield(i), memo);
}
/*
* call-seq:
* enum.all? [{|obj| block } ] => true or false
- *
+ *
* Passes each element of the collection to the given block. The method
* returns <code>true</code> if the block never returns
* <code>false</code> or <code>nil</code>. If the block is not given,
* Ruby adds an implicit block of <code>{|obj| obj}</code> (that is
* <code>all?</code> will return <code>true</code> only if none of the
* collection members are <code>false</code> or <code>nil</code>.)
- *
+ *
* %w{ ant bear cat}.all? {|word| word.length >= 3} #=> true
* %w{ ant bear cat}.all? {|word| word.length >= 4} #=> false
* [ nil, true, 99 ].all? #=> false
- *
+ *
*/
static VALUE
@@ -549,11 +916,11 @@ enum_all(obj)
}
static VALUE
-any_iter_i(i, memo)
+any_i(i, memo)
VALUE i;
VALUE *memo;
{
- if (RTEST(rb_yield(i))) {
+ if (RTEST(i)) {
*memo = Qtrue;
rb_iter_break();
}
@@ -561,21 +928,17 @@ any_iter_i(i, memo)
}
static VALUE
-any_i(i, memo)
+any_iter_i(i, memo)
VALUE i;
VALUE *memo;
{
- if (RTEST(i)) {
- *memo = Qtrue;
- rb_iter_break();
- }
- return Qnil;
+ return any_i(rb_yield(i), memo);
}
/*
* call-seq:
* enum.any? [{|obj| block } ] => true or false
- *
+ *
* Passes each element of the collection to the given block. The method
* returns <code>true</code> if the block ever returns a value other
* than <code>false</code> or <code>nil</code>. If the block is not
@@ -583,11 +946,11 @@ any_i(i, memo)
* is <code>any?</code> will return <code>true</code> if at least one
* of the collection members is not <code>false</code> or
* <code>nil</code>.
- *
+ *
* %w{ ant bear cat}.any? {|word| word.length >= 3} #=> true
* %w{ ant bear cat}.any? {|word| word.length >= 4} #=> true
* [ nil, true, 99 ].any? #=> true
- *
+ *
*/
static VALUE
@@ -601,6 +964,105 @@ enum_any(obj)
}
static VALUE
+one_i(i, memo)
+ VALUE i;
+ VALUE *memo;
+{
+ if (RTEST(i)) {
+ if (*memo == Qundef) {
+ *memo = Qtrue;
+ }
+ else if (*memo == Qtrue) {
+ *memo = Qfalse;
+ rb_iter_break();
+ }
+ }
+ return Qnil;
+}
+
+static VALUE
+one_iter_i(i, memo)
+ VALUE i;
+ VALUE *memo;
+{
+ return one_i(rb_yield(i), memo);
+}
+
+/*
+ * call-seq:
+ * enum.one? [{|obj| block }] => true or false
+ *
+ * Passes each element of the collection to the given block. The method
+ * returns <code>true</code> if the block returns <code>true</code>
+ * exactly once. If the block is not given, <code>one?</code> will return
+ * <code>true</code> only if exactly one of the collection members is
+ * true.
+ *
+ * %w{ant bear cat}.one? {|word| word.length == 4} #=> true
+ * %w{ant bear cat}.one? {|word| word.length > 4} #=> false
+ * %w{ant bear cat}.one? {|word| word.length < 4} #=> false
+ * [ nil, true, 99 ].one? #=> false
+ * [ nil, true, false ].one? #=> true
+ *
+ */
+
+static VALUE
+enum_one(obj)
+ VALUE obj;
+{
+ VALUE result = Qundef;
+
+ rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? one_iter_i : one_i, (VALUE)&result);
+ if (result == Qundef) return Qfalse;
+ return result;
+}
+
+static VALUE
+none_i(i, memo)
+ VALUE i;
+ VALUE *memo;
+{
+ if (RTEST(i)) {
+ *memo = Qfalse;
+ rb_iter_break();
+ }
+ return Qnil;
+}
+
+static VALUE
+none_iter_i(i, memo)
+ VALUE i;
+ VALUE *memo;
+{
+ return none_i(rb_yield(i), memo);
+}
+
+/*
+ * call-seq:
+ * enum.none? [{|obj| block }] => true or false
+ *
+ * Passes each element of the collection to the given block. The method
+ * returns <code>true</code> if the block never returns <code>true</code>
+ * for all elements. If the block is not given, <code>none?</code> will return
+ * <code>true</code> only if none of the collection members is true.
+ *
+ * %w{ant bear cat}.none? {|word| word.length == 5} #=> true
+ * %w{ant bear cat}.none? {|word| word.length >= 4} #=> false
+ * [].none? #=> true
+ * [nil].none? #=> true
+ * [nil,false].none? #=> true
+ */
+static VALUE
+enum_none(obj)
+ VALUE obj;
+{
+ VALUE result = Qtrue;
+
+ rb_block_call(obj, id_each, 0, 0, rb_block_given_p() ? none_iter_i : none_i, (VALUE)&result);
+ return result;
+}
+
+static VALUE
min_i(i, memo)
VALUE i;
VALUE *memo;
@@ -643,11 +1105,11 @@ min_ii(i, memo)
* call-seq:
* enum.min => obj
* enum.min {| a,b | block } => obj
- *
+ *
* Returns the object in <i>enum</i> with the minimum value. The
* first form assumes all objects implement <code>Comparable</code>;
* the second uses the block to return <em>a <=> b</em>.
- *
+ *
* a = %w(albatross dog horse)
* a.min #=> "albatross"
* a.min {|a,b| a.length <=> b.length } #=> "dog"
@@ -668,11 +1130,11 @@ enum_min(obj)
* call-seq:
* enum.max => obj
* enum.max {| a,b | block } => obj
- *
+ *
* Returns the object in <i>enum</i> with the maximum value. The
* first form assumes all objects implement <code>Comparable</code>;
* the second uses the block to return <em>a <=> b</em>.
- *
+ *
* a = %w(albatross dog horse)
* a.max #=> "horse"
* a.max {|a,b| a.length <=> b.length } #=> "albatross"
@@ -720,15 +1182,15 @@ max_ii(i, memo)
* call-seq:
* enum.max => obj
* enum.max {|a,b| block } => obj
- *
+ *
* Returns the object in _enum_ with the maximum value. The
* first form assumes all objects implement <code>Comparable</code>;
* the second uses the block to return <em>a <=> b</em>.
- *
+ *
* a = %w(albatross dog horse)
* a.max #=> "horse"
* a.max {|a,b| a.length <=> b.length } #=> "albatross"
- */
+ */
static VALUE
enum_max(obj)
@@ -742,6 +1204,240 @@ enum_max(obj)
}
static VALUE
+minmax_i(i, memo)
+ VALUE i;
+ VALUE *memo;
+{
+ int n;
+
+ if (memo[0] == Qundef) {
+ memo[0] = i;
+ memo[1] = i;
+ }
+ else {
+ n = rb_cmpint(rb_funcall(i, id_cmp, 1, memo[0]), i, memo[0]);
+ if (n < 0) {
+ memo[0] = i;
+ }
+ n = rb_cmpint(rb_funcall(i, id_cmp, 1, memo[1]), i, memo[1]);
+ if (n > 0) {
+ memo[1] = i;
+ }
+ }
+ return Qnil;
+}
+
+static VALUE
+minmax_ii(i, memo)
+ VALUE i;
+ VALUE *memo;
+{
+ int n;
+
+ if (memo[0] == Qundef) {
+ memo[0] = i;
+ memo[1] = i;
+ }
+ else {
+ VALUE ary = memo[2];
+
+ RARRAY(ary)->ptr[0] = i;
+ RARRAY(ary)->ptr[1] = memo[0];
+ n = rb_cmpint(rb_yield(ary), i, memo[0]);
+ if (n < 0) {
+ memo[0] = i;
+ }
+ RARRAY(ary)->ptr[0] = i;
+ RARRAY(ary)->ptr[1] = memo[1];
+ n = rb_cmpint(rb_yield(ary), i, memo[1]);
+ if (n > 0) {
+ memo[1] = i;
+ }
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * enum.minmax => [min,max]
+ * enum.minmax {|a,b| block } => [min,max]
+ *
+ * Returns two elements array which contains the minimum and the
+ * maximum value in the enumerable. The first form assumes all
+ * objects implement <code>Comparable</code>; the second uses the
+ * block to return <em>a <=> b</em>.
+ *
+ * a = %w(albatross dog horse)
+ * a.minmax #=> ["albatross", "horse"]
+ * a.minmax {|a,b| a.length <=> b.length } #=> ["dog", "albatross"]
+ */
+
+static VALUE
+enum_minmax(obj)
+ VALUE obj;
+{
+ VALUE result[3];
+ VALUE ary = rb_ary_new3(2, Qnil, Qnil);
+
+ result[0] = Qundef;
+ if (rb_block_given_p()) {
+ result[2] = ary;
+ rb_block_call(obj, id_each, 0, 0, minmax_ii, (VALUE)result);
+ }
+ else {
+ rb_block_call(obj, id_each, 0, 0, minmax_i, (VALUE)result);
+ }
+ if (result[0] != Qundef) {
+ RARRAY(ary)->ptr[0] = result[0];
+ RARRAY(ary)->ptr[1] = result[1];
+ }
+ return ary;
+}
+
+static VALUE
+min_by_i(i, memo)
+ VALUE i;
+ VALUE *memo;
+{
+ VALUE v;
+
+ v = rb_yield(i);
+ if (memo[0] == Qundef) {
+ memo[0] = v;
+ memo[1] = i;
+ }
+ else if (rb_cmpint(rb_funcall(v, id_cmp, 1, memo[0]), v, memo[0]) < 0) {
+ memo[0] = v;
+ memo[1] = i;
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * enum.min_by {| obj| block } => obj
+ *
+ * Returns the object in <i>enum</i> that gives the minimum
+ * value from the given block.
+ *
+ * a = %w(albatross dog horse)
+ * a.min_by {|x| x.length } #=> "dog"
+ */
+
+static VALUE
+enum_min_by(obj)
+ VALUE obj;
+{
+ VALUE memo[2];
+
+ RETURN_ENUMERATOR(obj, 0, 0);
+
+ memo[0] = Qundef;
+ memo[1] = Qnil;
+ rb_block_call(obj, id_each, 0, 0, min_by_i, (VALUE)memo);
+ return memo[1];
+}
+
+static VALUE
+max_by_i(i, memo)
+ VALUE i;
+ VALUE *memo;
+{
+ VALUE v;
+
+ v = rb_yield(i);
+ if (memo[0] == Qundef) {
+ memo[0] = v;
+ memo[1] = i;
+ }
+ else if (rb_cmpint(rb_funcall(v, id_cmp, 1, memo[0]), v, memo[0]) > 0) {
+ memo[0] = v;
+ memo[1] = i;
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * enum.max_by {| obj| block } => obj
+ *
+ * Returns the object in <i>enum</i> that gives the maximum
+ * value from the given block.
+ *
+ * a = %w(albatross dog horse)
+ * a.max_by {|x| x.length } #=> "albatross"
+ */
+
+static VALUE
+enum_max_by(obj)
+ VALUE obj;
+{
+ VALUE memo[2];
+
+ RETURN_ENUMERATOR(obj, 0, 0);
+
+ memo[0] = Qundef;
+ memo[1] = Qnil;
+ rb_block_call(obj, id_each, 0, 0, max_by_i, (VALUE)memo);
+ return memo[1];
+}
+
+static VALUE
+minmax_by_i(i, memo)
+ VALUE i;
+ VALUE *memo;
+{
+ VALUE v;
+
+ v = rb_yield(i);
+ if (memo[0] == Qundef) {
+ memo[0] = v;
+ memo[1] = v;
+ memo[2] = i;
+ memo[3] = i;
+ }
+ else {
+ if (rb_cmpint(rb_funcall(v, id_cmp, 1, memo[0]), v, memo[0]) < 0) {
+ memo[0] = v;
+ memo[2] = i;
+ }
+ if (rb_cmpint(rb_funcall(v, id_cmp, 1, memo[1]), v, memo[1]) > 0) {
+ memo[1] = v;
+ memo[3] = i;
+ }
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * enum.minmax_by {| obj| block } => [min, max]
+ *
+ * Returns two elements array array containing the objects in
+ * <i>enum</i> that gives the minimum and maximum values respectively
+ * from the given block.
+ *
+ * a = %w(albatross dog horse)
+ * a.minmax_by {|x| x.length } #=> ["dog", "albatross"]
+ */
+
+static VALUE
+enum_minmax_by(obj)
+ VALUE obj;
+{
+ VALUE memo[4];
+
+ RETURN_ENUMERATOR(obj, 0, 0);
+
+ memo[0] = Qundef;
+ memo[1] = Qundef;
+ memo[2] = Qnil;
+ memo[3] = Qnil;
+ rb_block_call(obj, id_each, 0, 0, minmax_by_i, (VALUE)memo);
+ return rb_assoc_new(memo[2], memo[3]);
+}
+
+static VALUE
member_i(item, memo)
VALUE item;
VALUE *memo;
@@ -757,13 +1453,13 @@ member_i(item, memo)
* call-seq:
* enum.include?(obj) => true or false
* enum.member?(obj) => true or false
- *
+ *
* Returns <code>true</code> if any member of <i>enum</i> equals
* <i>obj</i>. Equality is tested using <code>==</code>.
- *
+ *
* IO.constants.include? "SEEK_SET" #=> true
* IO.constants.include? "SEEK_NO_FURTHER" #=> false
- *
+ *
*/
static VALUE
@@ -791,29 +1487,56 @@ each_with_index_i(val, memo)
/*
* call-seq:
* enum.each_with_index {|obj, i| block } -> enum
- *
+ *
* Calls <em>block</em> with two arguments, the item and its index, for
* each item in <i>enum</i>.
- *
+ *
* hash = Hash.new
* %w(cat dog wombat).each_with_index {|item, index|
* hash[item] = index
* }
* hash #=> {"cat"=>0, "wombat"=>2, "dog"=>1}
- *
+ *
*/
static VALUE
enum_each_with_index(obj)
VALUE obj;
{
- VALUE memo = 0;
+ VALUE memo;
- rb_need_block();
+ RETURN_ENUMERATOR(obj, 0, 0);
+
+ memo = 0;
rb_iterate(rb_each, obj, each_with_index_i, (VALUE)&memo);
return obj;
}
+/*
+ * call-seq:
+ * enum.reverse_each {|item| block }
+ *
+ * Traverses <i>enum</i> in reverse order.
+ */
+
+static VALUE
+enum_reverse_each(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE ary;
+ long i;
+
+ RETURN_ENUMERATOR(obj, argc, argv);
+
+ ary = enum_to_a(argc, argv, obj);
+
+ for (i = RARRAY_LEN(ary); --i >= 0; ) {
+ rb_yield(RARRAY_PTR(ary)[i]);
+ }
+
+ return obj;
+}
+
+
static VALUE
zip_i(val, memo)
VALUE val;
@@ -843,7 +1566,7 @@ zip_i(val, memo)
* call-seq:
* enum.zip(arg, ...) => array
* enum.zip(arg, ...) {|arr| block } => nil
- *
+ *
* Converts any arguments to arrays, then merges elements of
* <i>enum</i> with corresponding elements from each argument. This
* generates a sequence of <code>enum#size</code> <em>n</em>-element
@@ -852,14 +1575,14 @@ zip_i(val, memo)
* <code>nil</code> values are supplied. If a block given, it is
* invoked for each output array, otherwise an array of arrays is
* returned.
- *
+ *
* a = [ 4, 5, 6 ]
* b = [ 7, 8, 9 ]
- *
+ *
* (1..3).zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
* "cat\ndog".zip([1]) #=> [["cat\n", 1], ["dog", nil]]
* (1..3).zip #=> [[1], [2], [3]]
- *
+ *
*/
static VALUE
@@ -884,6 +1607,228 @@ enum_zip(argc, argv, obj)
return result;
}
+static VALUE
+take_i(i, arg)
+ VALUE i;
+ VALUE *arg;
+{
+ rb_ary_push(arg[0], i);
+ if (--arg[1] == 0) rb_iter_break();
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * enum.take(n) => array
+ *
+ * Returns first n elements from <i>enum</i>.
+ *
+ * a = [1, 2, 3, 4, 5, 0]
+ * a.take(3) # => [1, 2, 3]
+ *
+ */
+
+static VALUE
+enum_take(obj, n)
+ VALUE obj;
+ VALUE n;
+{
+ VALUE args[2];
+ long len = NUM2LONG(n);
+
+ if (len < 0) {
+ rb_raise(rb_eArgError, "attempt to take negative size");
+ }
+
+ if (len == 0) return rb_ary_new2(0);
+ args[1] = len;
+ args[0] = rb_ary_new();
+ rb_block_call(obj, id_each, 0, 0, take_i, (VALUE)args);
+ return args[0];
+}
+
+
+static VALUE
+take_while_i(i, ary)
+ VALUE i;
+ VALUE *ary;
+{
+ if (!RTEST(rb_yield(i))) rb_iter_break();
+ rb_ary_push(*ary, i);
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * enum.take_while {|arr| block } => array
+ *
+ * Passes elements to the block until the block returns nil or false,
+ * then stops iterating and returns an array of all prior elements.
+ *
+ * a = [1, 2, 3, 4, 5, 0]
+ * a.take_while {|i| i < 3 } # => [1, 2]
+ *
+ */
+
+static VALUE
+enum_take_while(obj)
+ VALUE obj;
+{
+ VALUE ary;
+
+ RETURN_ENUMERATOR(obj, 0, 0);
+ ary = rb_ary_new();
+ rb_block_call(obj, id_each, 0, 0, take_while_i, (VALUE)&ary);
+ return ary;
+}
+
+static VALUE
+drop_i(i, arg)
+ VALUE i;
+ VALUE *arg;
+{
+ if (arg[1] == 0) {
+ rb_ary_push(arg[0], i);
+ }
+ else {
+ arg[1]--;
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * enum.drop(n) => array
+ *
+ * Drops first n elements from <i>enum</i>, and returns rest elements
+ * in an array.
+ *
+ * a = [1, 2, 3, 4, 5, 0]
+ * a.drop(3) # => [4, 5, 0]
+ *
+ */
+
+static VALUE
+enum_drop(obj, n)
+ VALUE obj;
+ VALUE n;
+{
+ VALUE args[2];
+ long len = NUM2LONG(n);
+
+ if (len < 0) {
+ rb_raise(rb_eArgError, "attempt to drop negative size");
+ }
+
+ args[1] = len;
+ args[0] = rb_ary_new();
+ rb_block_call(obj, id_each, 0, 0, drop_i, (VALUE)args);
+ return args[0];
+}
+
+
+static VALUE
+drop_while_i(i, args)
+ VALUE i;
+ VALUE *args;
+{
+ if (!args[1] && !RTEST(rb_yield(i))) {
+ args[1] = Qtrue;
+ }
+ if (args[1]) {
+ rb_ary_push(args[0], i);
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * enum.drop_while {|arr| block } => array
+ *
+ * Drops elements up to, but not including, the first element for
+ * which the block returns nil or false and returns an array
+ * containing the remaining elements.
+ *
+ * a = [1, 2, 3, 4, 5, 0]
+ * a.drop_while {|i| i < 3 } # => [3, 4, 5, 0]
+ *
+ */
+
+static VALUE
+enum_drop_while(obj)
+ VALUE obj;
+{
+ VALUE args[2];
+
+ RETURN_ENUMERATOR(obj, 0, 0);
+ args[0] = rb_ary_new();
+ args[1] = Qfalse;
+ rb_block_call(obj, id_each, 0, 0, drop_while_i, (VALUE)args);
+ return args[0];
+}
+
+static VALUE
+cycle_i(i, ary)
+ VALUE i;
+ VALUE ary;
+{
+ rb_ary_push(ary, i);
+ rb_yield(i);
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * enum.cycle {|obj| block }
+ * enum.cycle(n) {|obj| block }
+ *
+ * Calls <i>block</i> for each element of <i>enum</i> repeatedly _n_
+ * times or forever if none or nil is given. If a non-positive
+ * number is given or the collection is empty, does nothing. Returns
+ * nil if the loop has finished without getting interrupted.
+ *
+ * Enumerable#cycle saves elements in an internal array so changes
+ * to <i>enum</i> after the first pass have no effect.
+ *
+ * a = ["a", "b", "c"]
+ * a.cycle {|x| puts x } # print, a, b, c, a, b, c,.. forever.
+ * a.cycle(2) {|x| puts x } # print, a, b, c, a, b, c.
+ *
+ */
+
+static VALUE
+enum_cycle(argc, argv, obj)
+ int argc;
+ VALUE *argv;
+ VALUE obj;
+{
+ VALUE ary;
+ VALUE nv = Qnil;
+ long n, i, len;
+
+ rb_scan_args(argc, argv, "01", &nv);
+
+ RETURN_ENUMERATOR(obj, argc, argv);
+ if (NIL_P(nv)) {
+ n = -1;
+ }
+ else {
+ n = NUM2LONG(nv);
+ if (n <= 0) return Qnil;
+ }
+ ary = rb_ary_new();
+ RBASIC(ary)->klass = 0;
+ rb_block_call(obj, id_each, 0, 0, cycle_i, ary);
+ len = RARRAY(ary)->len;
+ if (len == 0) return Qnil;
+ while (n < 0 || 0 < --n) {
+ for (i=0; i<len; i++) {
+ rb_yield(RARRAY(ary)->ptr[i]);
+ }
+ }
+ return Qnil; /* not reached */
+}
+
/*
* The <code>Enumerable</code> mixin provides collection classes with
* several traversal and searching methods, and with the ability to
@@ -900,32 +1845,51 @@ Init_Enumerable()
{
rb_mEnumerable = rb_define_module("Enumerable");
- rb_define_method(rb_mEnumerable,"to_a", enum_to_a, 0);
- rb_define_method(rb_mEnumerable,"entries", enum_to_a, 0);
-
- rb_define_method(rb_mEnumerable,"sort", enum_sort, 0);
- rb_define_method(rb_mEnumerable,"sort_by", enum_sort_by, 0);
- rb_define_method(rb_mEnumerable,"grep", enum_grep, 1);
- rb_define_method(rb_mEnumerable,"find", enum_find, -1);
- rb_define_method(rb_mEnumerable,"detect", enum_find, -1);
- rb_define_method(rb_mEnumerable,"find_all", enum_find_all, 0);
- rb_define_method(rb_mEnumerable,"select", enum_find_all, 0);
- rb_define_method(rb_mEnumerable,"reject", enum_reject, 0);
- rb_define_method(rb_mEnumerable,"collect", enum_collect, 0);
- rb_define_method(rb_mEnumerable,"map", enum_collect, 0);
- rb_define_method(rb_mEnumerable,"inject", enum_inject, -1);
- rb_define_method(rb_mEnumerable,"partition", enum_partition, 0);
- rb_define_method(rb_mEnumerable,"all?", enum_all, 0);
- rb_define_method(rb_mEnumerable,"any?", enum_any, 0);
- rb_define_method(rb_mEnumerable,"min", enum_min, 0);
- rb_define_method(rb_mEnumerable,"max", enum_max, 0);
- rb_define_method(rb_mEnumerable,"member?", enum_member, 1);
- rb_define_method(rb_mEnumerable,"include?", enum_member, 1);
- rb_define_method(rb_mEnumerable,"each_with_index", enum_each_with_index, 0);
+ rb_define_method(rb_mEnumerable, "to_a", enum_to_a, -1);
+ rb_define_method(rb_mEnumerable, "entries", enum_to_a, -1);
+
+ rb_define_method(rb_mEnumerable, "sort", enum_sort, 0);
+ rb_define_method(rb_mEnumerable, "sort_by", enum_sort_by, 0);
+ rb_define_method(rb_mEnumerable, "grep", enum_grep, 1);
+ rb_define_method(rb_mEnumerable, "count", enum_count, -1);
+ rb_define_method(rb_mEnumerable, "find", enum_find, -1);
+ rb_define_method(rb_mEnumerable, "detect", enum_find, -1);
+ rb_define_method(rb_mEnumerable, "find_index", enum_find_index, -1);
+ rb_define_method(rb_mEnumerable, "find_all", enum_find_all, 0);
+ rb_define_method(rb_mEnumerable, "select", enum_find_all, 0);
+ rb_define_method(rb_mEnumerable, "reject", enum_reject, 0);
+ rb_define_method(rb_mEnumerable, "collect", enum_collect, 0);
+ rb_define_method(rb_mEnumerable, "map", enum_collect, 0);
+ rb_define_method(rb_mEnumerable, "inject", enum_inject, -1);
+ rb_define_method(rb_mEnumerable, "reduce", enum_inject, -1);
+ rb_define_method(rb_mEnumerable, "partition", enum_partition, 0);
+ rb_define_method(rb_mEnumerable, "group_by", enum_group_by, 0);
+ rb_define_method(rb_mEnumerable, "first", enum_first, -1);
+ rb_define_method(rb_mEnumerable, "all?", enum_all, 0);
+ rb_define_method(rb_mEnumerable, "any?", enum_any, 0);
+ rb_define_method(rb_mEnumerable, "one?", enum_one, 0);
+ rb_define_method(rb_mEnumerable, "none?", enum_none, 0);
+ rb_define_method(rb_mEnumerable, "min", enum_min, 0);
+ rb_define_method(rb_mEnumerable, "max", enum_max, 0);
+ rb_define_method(rb_mEnumerable, "minmax", enum_minmax, 0);
+ rb_define_method(rb_mEnumerable, "min_by", enum_min_by, 0);
+ rb_define_method(rb_mEnumerable, "max_by", enum_max_by, 0);
+ rb_define_method(rb_mEnumerable, "minmax_by", enum_minmax_by, 0);
+ rb_define_method(rb_mEnumerable, "member?", enum_member, 1);
+ rb_define_method(rb_mEnumerable, "include?", enum_member, 1);
+ rb_define_method(rb_mEnumerable, "each_with_index", enum_each_with_index, 0);
+ rb_define_method(rb_mEnumerable, "enum_with_index", enum_each_with_index, 0);
+ rb_define_method(rb_mEnumerable, "reverse_each", enum_reverse_each, -1);
rb_define_method(rb_mEnumerable, "zip", enum_zip, -1);
+ rb_define_method(rb_mEnumerable, "take", enum_take, 1);
+ rb_define_method(rb_mEnumerable, "take_while", enum_take_while, 0);
+ rb_define_method(rb_mEnumerable, "drop", enum_drop, 1);
+ rb_define_method(rb_mEnumerable, "drop_while", enum_drop_while, 0);
+ rb_define_method(rb_mEnumerable, "cycle", enum_cycle, -1);
id_eqq = rb_intern("===");
id_each = rb_intern("each");
id_cmp = rb_intern("<=>");
+ id_size = rb_intern("size");
}
diff --git a/enumerator.c b/enumerator.c
new file mode 100644
index 0000000000..f95d931b62
--- /dev/null
+++ b/enumerator.c
@@ -0,0 +1,450 @@
+/************************************************
+
+ enumerator.c - provides Enumerator class
+
+ $Author$
+
+ Copyright (C) 2001-2003 Akinori MUSHA
+
+ $Idaemons: /home/cvs/rb/enumerator/enumerator.c,v 1.1.1.1 2001/07/15 10:12:48 knu Exp $
+ $RoughId: enumerator.c,v 1.6 2003/07/27 11:03:24 nobu Exp $
+ $Id$
+
+************************************************/
+
+#include "ruby.h"
+
+/*
+ * Document-class: Enumerable::Enumerator
+ *
+ * A class which provides a method `each' to be used as an Enumerable
+ * object.
+ */
+VALUE rb_cEnumerator;
+static VALUE sym_each;
+
+VALUE rb_eStopIteration;
+
+struct enumerator {
+ VALUE obj;
+ ID meth;
+ VALUE proc;
+ VALUE args;
+ rb_block_call_func *iter;
+};
+
+static void enumerator_mark _((void *));
+static void
+enumerator_mark(p)
+ void *p;
+{
+ struct enumerator *ptr = p;
+ rb_gc_mark(ptr->obj);
+ rb_gc_mark(ptr->args);
+}
+
+static struct enumerator *
+enumerator_ptr(obj)
+ VALUE obj;
+{
+ struct enumerator *ptr;
+
+ Data_Get_Struct(obj, struct enumerator, ptr);
+ if (RDATA(obj)->dmark != enumerator_mark) {
+ rb_raise(rb_eTypeError,
+ "wrong argument type %s (expected Enumerable::Enumerator)",
+ rb_obj_classname(obj));
+ }
+ if (!ptr || ptr->obj == Qundef) {
+ rb_raise(rb_eArgError, "uninitialized enumerator");
+ }
+ return ptr;
+}
+
+/*
+ * call-seq:
+ * obj.to_enum(method = :each, *args)
+ * obj.enum_for(method = :each, *args)
+ *
+ * Returns Enumerable::Enumerator.new(self, method, *args).
+ *
+ * e.g.:
+ *
+ * str = "xyz"
+ *
+ * enum = str.enum_for(:each_byte)
+ * a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"]
+ *
+ * # protects an array from being modified
+ * a = [1, 2, 3]
+ * some_method(a.to_enum)
+ *
+ */
+static VALUE
+obj_to_enum(argc, argv, obj)
+ int argc;
+ VALUE *argv;
+ VALUE obj;
+{
+ VALUE meth = sym_each;
+
+ if (argc > 0) {
+ --argc;
+ meth = *argv++;
+ }
+ return rb_enumeratorize(obj, meth, argc, argv);
+}
+
+static VALUE
+each_slice_i(val, memo)
+ VALUE val;
+ VALUE *memo;
+{
+ VALUE ary = memo[0];
+ VALUE v = Qnil;
+ long size = (long)memo[1];
+
+ rb_ary_push(ary, val);
+
+ if (RARRAY_LEN(ary) == size) {
+ v = rb_yield(ary);
+ memo[0] = rb_ary_new2(size);
+ }
+
+ return v;
+}
+
+/*
+ * call-seq:
+ * e.each_slice(n) {...}
+ * e.each_slice(n)
+ *
+ * Iterates the given block for each slice of <n> elements. If no
+ * block is given, returns an enumerator.
+ *
+ * e.g.:
+ * (1..10).each_slice(3) {|a| p a}
+ * # outputs below
+ * [1, 2, 3]
+ * [4, 5, 6]
+ * [7, 8, 9]
+ * [10]
+ *
+ */
+static VALUE
+enum_each_slice(obj, n)
+ VALUE obj, n;
+{
+ long size = NUM2LONG(n);
+ VALUE args[2], ary;
+
+ if (size <= 0) rb_raise(rb_eArgError, "invalid slice size");
+ RETURN_ENUMERATOR(obj, 1, &n);
+ args[0] = rb_ary_new2(size);
+ args[1] = (VALUE)size;
+
+ rb_block_call(obj, SYM2ID(sym_each), 0, 0, each_slice_i, (VALUE)args);
+
+ ary = args[0];
+ if (RARRAY_LEN(ary) > 0) rb_yield(ary);
+
+ return Qnil;
+}
+
+static VALUE
+each_cons_i(val, memo)
+ VALUE val;
+ VALUE *memo;
+{
+ VALUE ary = memo[0];
+ VALUE v = Qnil;
+ long size = (long)memo[1];
+
+ if (RARRAY_LEN(ary) == size) {
+ rb_ary_shift(ary);
+ }
+ rb_ary_push(ary, val);
+ if (RARRAY_LEN(ary) == size) {
+ v = rb_yield(rb_ary_dup(ary));
+ }
+ return v;
+}
+
+/*
+ * call-seq:
+ * each_cons(n) {...}
+ * each_cons(n)
+ *
+ * Iterates the given block for each array of consecutive <n>
+ * elements. If no block is given, returns an enumerator.a
+ *
+ * e.g.:
+ * (1..10).each_cons(3) {|a| p a}
+ * # outputs below
+ * [1, 2, 3]
+ * [2, 3, 4]
+ * [3, 4, 5]
+ * [4, 5, 6]
+ * [5, 6, 7]
+ * [6, 7, 8]
+ * [7, 8, 9]
+ * [8, 9, 10]
+ *
+ */
+static VALUE
+enum_each_cons(obj, n)
+ VALUE obj, n;
+{
+ long size = NUM2LONG(n);
+ VALUE args[2];
+
+ if (size <= 0) rb_raise(rb_eArgError, "invalid size");
+ RETURN_ENUMERATOR(obj, 1, &n);
+ args[0] = rb_ary_new2(size);
+ args[1] = (VALUE)size;
+
+ rb_block_call(obj, SYM2ID(sym_each), 0, 0, each_cons_i, (VALUE)args);
+
+ return Qnil;
+}
+
+static VALUE enumerator_allocate _((VALUE));
+static VALUE
+enumerator_allocate(klass)
+ VALUE klass;
+{
+ struct enumerator *ptr;
+ VALUE enum_obj;
+
+ enum_obj = Data_Make_Struct(klass, struct enumerator,
+ enumerator_mark, -1, ptr);
+ ptr->obj = Qundef;
+
+ return enum_obj;
+}
+
+static VALUE enumerator_each_i _((VALUE, VALUE));
+static VALUE
+enumerator_each_i(v, enum_obj)
+ VALUE v;
+ VALUE enum_obj;
+{
+ return rb_yield(v);
+}
+
+static VALUE
+enumerator_init(enum_obj, obj, meth, argc, argv)
+ VALUE enum_obj;
+ VALUE obj;
+ VALUE meth;
+ int argc;
+ VALUE *argv;
+{
+ struct enumerator *ptr;
+
+ Data_Get_Struct(enum_obj, struct enumerator, ptr);
+
+ if (!ptr) {
+ rb_raise(rb_eArgError, "unallocated enumerator");
+ }
+
+ ptr->obj = obj;
+ ptr->meth = rb_to_id(meth);
+ ptr->iter = enumerator_each_i;
+ if (argc) ptr->args = rb_ary_new4(argc, argv);
+
+ return enum_obj;
+}
+
+/*
+ * call-seq:
+ * Enumerable::Enumerator.new(obj, method = :each, *args)
+ *
+ * Creates a new Enumerable::Enumerator object, which is to be
+ * used as an Enumerable object using the given object's given
+ * method with the given arguments.
+ *
+ * Use of this method is discouraged. Use Kernel#enum_for() instead.
+ */
+static VALUE
+enumerator_initialize(argc, argv, obj)
+ int argc;
+ VALUE *argv;
+ VALUE obj;
+{
+ VALUE recv, meth = sym_each;
+
+ if (argc == 0)
+ rb_raise(rb_eArgError, "wrong number of argument (0 for 1)");
+ recv = *argv++;
+ if (--argc) {
+ meth = *argv++;
+ --argc;
+ }
+ return enumerator_init(obj, recv, meth, argc, argv);
+}
+
+/* :nodoc: */
+static VALUE
+enumerator_init_copy(obj, orig)
+ VALUE obj;
+ VALUE orig;
+{
+ struct enumerator *ptr0, *ptr1;
+
+ ptr0 = enumerator_ptr(orig);
+
+ Data_Get_Struct(obj, struct enumerator, ptr1);
+
+ if (!ptr1) {
+ rb_raise(rb_eArgError, "unallocated enumerator");
+ }
+
+ ptr1->obj = ptr0->obj;
+ ptr1->meth = ptr0->meth;
+ ptr1->iter = ptr0->iter;
+ ptr1->args = ptr0->args;
+
+ return obj;
+}
+
+VALUE
+rb_enumeratorize(obj, meth, argc, argv)
+ VALUE obj;
+ VALUE meth;
+ int argc;
+ VALUE *argv;
+{
+ return enumerator_init(enumerator_allocate(rb_cEnumerator), obj, meth, argc, argv);
+}
+
+/*
+ * call-seq:
+ * enum.each {...}
+ *
+ * Iterates the given block using the object and the method specified
+ * in the first place. If no block is given, returns self.
+ *
+ */
+static VALUE
+enumerator_each(obj)
+ VALUE obj;
+{
+ struct enumerator *e;
+ int argc = 0;
+ VALUE *argv = 0;
+
+ if (!rb_block_given_p()) return obj;
+ e = enumerator_ptr(obj);
+ if (e->args) {
+ argc = RARRAY_LEN(e->args);
+ argv = RARRAY_PTR(e->args);
+ }
+ return rb_block_call(e->obj, e->meth, argc, argv, e->iter, (VALUE)e);
+}
+
+static VALUE
+enumerator_with_index_i(val, memo)
+ VALUE val;
+ VALUE *memo;
+{
+ val = rb_yield_values(2, val, INT2FIX(*memo));
+ ++*memo;
+ return val;
+}
+
+/*
+ * call-seq:
+ * e.with_index {|(*args), idx| ... }
+ * e.with_index
+ *
+ * Iterates the given block for each elements with an index, which
+ * start from 0. If no block is given, returns an enumerator.
+ *
+ */
+static VALUE
+enumerator_with_index(obj)
+ VALUE obj;
+{
+ struct enumerator *e = enumerator_ptr(obj);
+ VALUE memo = 0;
+ int argc = 0;
+ VALUE *argv = 0;
+
+ RETURN_ENUMERATOR(obj, 0, 0);
+ if (e->args) {
+ argc = RARRAY_LEN(e->args);
+ argv = RARRAY_PTR(e->args);
+ }
+ return rb_block_call(e->obj, e->meth, argc, argv,
+ enumerator_with_index_i, (VALUE)&memo);
+}
+
+/*
+ * call-seq:
+ * e.next => object
+ *
+ * Returns the next object in the enumerator, and move the internal
+ * position forward. When the position reached at the end, internal
+ * position is rewinded then StopIteration is raised.
+ *
+ * Note that enumeration sequence by next method does not affect other
+ * non-external enumeration methods, unless underlying iteration
+ * methods itself has side-effect, e.g. IO#each_line.
+ *
+ * Caution: Calling this method causes the "generator" library to be
+ * loaded.
+ */
+
+static VALUE
+enumerator_next(obj)
+ VALUE obj;
+{
+ rb_require("generator");
+ return rb_funcall(obj, rb_intern("next"), 0, 0);
+}
+
+/*
+ * call-seq:
+ * e.rewind => e
+ *
+ * Rewinds the enumeration sequence by the next method.
+ */
+
+static VALUE
+enumerator_rewind(obj)
+ VALUE obj;
+{
+ rb_require("generator");
+ return rb_funcall(obj, rb_intern("rewind"), 0, 0);
+}
+
+void
+Init_Enumerator()
+{
+ rb_define_method(rb_mKernel, "to_enum", obj_to_enum, -1);
+ rb_define_method(rb_mKernel, "enum_for", obj_to_enum, -1);
+
+ rb_define_method(rb_mEnumerable, "each_slice", enum_each_slice, 1);
+ rb_define_method(rb_mEnumerable, "enum_slice", enum_each_slice, 1);
+ rb_define_method(rb_mEnumerable, "each_cons", enum_each_cons, 1);
+ rb_define_method(rb_mEnumerable, "enum_cons", enum_each_cons, 1);
+
+ rb_cEnumerator = rb_define_class_under(rb_mEnumerable, "Enumerator", rb_cObject);
+ rb_include_module(rb_cEnumerator, rb_mEnumerable);
+
+ rb_define_alloc_func(rb_cEnumerator, enumerator_allocate);
+ rb_define_method(rb_cEnumerator, "initialize", enumerator_initialize, -1);
+ rb_define_method(rb_cEnumerator, "initialize_copy", enumerator_init_copy, 1);
+ rb_define_method(rb_cEnumerator, "each", enumerator_each, 0);
+ rb_define_method(rb_cEnumerator, "each_with_index", enumerator_with_index, 0);
+ rb_define_method(rb_cEnumerator, "with_index", enumerator_with_index, 0);
+ rb_define_method(rb_cEnumerator, "next", enumerator_next, 0);
+ rb_define_method(rb_cEnumerator, "rewind", enumerator_rewind, 0);
+
+ rb_eStopIteration = rb_define_class("StopIteration", rb_eIndexError);
+
+ sym_each = ID2SYM(rb_intern("each"));
+
+ rb_provide("enumerator.so"); /* for backward compatibility */
+}
diff --git a/env.h b/env.h
index 196090f387..c50103f71e 100644
--- a/env.h
+++ b/env.h
@@ -2,8 +2,8 @@
env.h -
- $Author: matz $
- $Date: 2006/02/13 09:10:55 $
+ $Author$
+ $Date$
created at: Mon Jul 11 11:53:03 JST 1994
Copyright (C) 1993-2003 Yukihiro Matsumoto
diff --git a/error.c b/error.c
index 6ebc927853..59b445e915 100644
--- a/error.c
+++ b/error.c
@@ -2,8 +2,8 @@
error.c -
- $Author: matz $
- $Date: 2006/07/20 07:04:13 $
+ $Author$
+ $Date$
created at: Mon Aug 9 16:11:34 JST 1993
Copyright (C) 1993-2003 Yukihiro Matsumoto
@@ -29,7 +29,7 @@
#define EXIT_SUCCESS 0
#endif
-extern const char ruby_version[], ruby_release_date[], ruby_platform[];
+extern const char *ruby_description;
int ruby_nerrs;
@@ -208,8 +208,7 @@ rb_bug(fmt, va_alist)
va_init_list(args, fmt);
vfprintf(out, fmt, args);
va_end(args);
- fprintf(out, "\nruby %s (%s) [%s]\n\n",
- ruby_version, ruby_release_date, ruby_platform);
+ fprintf(out, "\n%s\n\n", ruby_description);
}
abort();
}
@@ -258,7 +257,7 @@ rb_check_type(x, t)
if (TYPE(x) != t) {
while (type->type >= 0) {
if (type->type == t) {
- char *etype;
+ const char *etype;
if (NIL_P(x)) {
etype = "nil";
@@ -334,7 +333,7 @@ rb_exc_new3(etype, str)
VALUE etype, str;
{
StringValue(str);
- return rb_exc_new(etype, RSTRING(str)->ptr, RSTRING(str)->len);
+ return rb_funcall(etype, rb_intern("new"), 1, str);
}
/*
@@ -404,7 +403,6 @@ exc_to_s(exc)
VALUE mesg = rb_attr_get(exc, rb_intern("mesg"));
if (NIL_P(mesg)) return rb_class_name(CLASS_OF(exc));
- if (OBJ_TAINTED(exc)) OBJ_TAINT(mesg);
return mesg;
}
@@ -499,7 +497,7 @@ rb_check_backtrace(bt)
VALUE bt;
{
long i;
- static char *err = "backtrace must be Array of String";
+ static const char err[] = "backtrace must be Array of String";
if (!NIL_P(bt)) {
int t = TYPE(bt);
@@ -668,10 +666,9 @@ name_err_to_s(exc)
if (NIL_P(mesg)) return rb_class_name(CLASS_OF(exc));
StringValue(str);
if (str != mesg) {
- rb_iv_set(exc, "mesg", mesg = str);
+ OBJ_INFECT(str, mesg);
}
- if (OBJ_TAINTED(exc)) OBJ_TAINT(mesg);
- return mesg;
+ return str;
}
/*
@@ -728,7 +725,7 @@ name_err_mesg_to_str(obj)
mesg = ptr[0];
if (NIL_P(mesg)) return Qnil;
else {
- char *desc = 0;
+ const char *desc = 0;
VALUE d = 0, args[3];
obj = ptr[1];
@@ -882,7 +879,7 @@ syserr_initialize(argc, argv, self)
#if !defined(_WIN32) && !defined(__VMS)
char *strerror();
#endif
- char *err;
+ const char *err;
VALUE mesg, error;
VALUE klass = rb_obj_class(self);
@@ -952,18 +949,16 @@ syserr_eqq(self, exc)
VALUE self, exc;
{
VALUE num, e;
+ ID en = rb_intern("errno");
- if (!rb_obj_is_kind_of(exc, rb_eSystemCallError)) return Qfalse;
- if (self == rb_eSystemCallError) return Qtrue;
+ if (!rb_obj_is_kind_of(exc, rb_eSystemCallError)) {
+ if (!rb_respond_to(exc, en)) return Qfalse;
+ }
+ else if (self == rb_eSystemCallError) return Qtrue;
- num = rb_attr_get(exc, rb_intern("errno"));
+ num = rb_attr_get(exc, en);
if (NIL_P(num)) {
- VALUE klass = CLASS_OF(exc);
-
- while (TYPE(klass) == T_ICLASS || FL_TEST(klass, FL_SINGLETON)) {
- klass = (VALUE)RCLASS(klass)->super;
- }
- num = rb_const_get(klass, rb_intern("Errno"));
+ num = rb_funcall(exc, en, 0, 0);
}
e = rb_const_get(self, rb_intern("Errno"));
if (FIXNUM_P(num) ? num == e : rb_equal(num, e))
diff --git a/eval.c b/eval.c
index 132d2809cb..7886e17d1a 100644
--- a/eval.c
+++ b/eval.c
@@ -2,8 +2,8 @@
eval.c -
- $Author: shyouhei $
- $Date: 2007/01/27 15:45:49 $
+ $Author$
+ $Date$
created at: Thu Jun 10 14:22:17 JST 1993
Copyright (C) 1993-2003 Yukihiro Matsumoto
@@ -29,11 +29,6 @@
#endif
#include <stdio.h>
-#if defined(HAVE_GETCONTEXT) && defined(HAVE_SETCONTEXT)
-#include <ucontext.h>
-#define USE_CONTEXT
-#endif
-#include <setjmp.h>
#include "st.h"
#include "dln.h"
@@ -77,7 +72,18 @@ char *strrchr _((const char*,const char));
#include <unistd.h>
#endif
-#ifdef __BEOS__
+#include <time.h>
+
+#if defined(HAVE_FCNTL_H) || defined(_WIN32)
+#include <fcntl.h>
+#elif defined(HAVE_SYS_FCNTL_H)
+#include <sys/fcntl.h>
+#endif
+#ifdef __CYGWIN__
+#include <io.h>
+#endif
+
+#if defined(__BEOS__) && !defined(BONE)
#include <net/socket.h>
#endif
@@ -90,10 +96,6 @@ char *strrchr _((const char*,const char));
#endif
#ifdef USE_CONTEXT
-typedef struct {
- ucontext_t context;
- volatile int status;
-} rb_jmpbuf_t[1];
NORETURN(static void rb_jump_context(rb_jmpbuf_t, int));
static inline void
@@ -195,19 +197,18 @@ static int volatile freebsd_clear_carry_flag = 0;
# define POST_GETCONTEXT 0
# endif
# define ruby_longjmp(env, val) rb_jump_context(env, val)
-# define ruby_setjmp(j) ((j)->status = 0, \
+# define ruby_setjmp(just_before_setjmp, j) ((j)->status = 0, \
+ (just_before_setjmp), \
PRE_GETCONTEXT, \
getcontext(&(j)->context), \
POST_GETCONTEXT, \
(j)->status)
#else
-typedef jmp_buf rb_jmpbuf_t;
-# if !defined(setjmp) && defined(HAVE__SETJMP)
-# define ruby_setjmp(env) _setjmp(env)
-# define ruby_longjmp(env,val) _longjmp(env,val)
-# else
-# define ruby_setjmp(env) setjmp(env)
-# define ruby_longjmp(env,val) longjmp(env,val)
+# define ruby_setjmp(just_before_setjmp, env) \
+ ((just_before_setjmp), RUBY_SETJMP(env))
+# define ruby_longjmp(env,val) RUBY_LONGJMP(env,val)
+# ifdef __CYGWIN__
+int _setjmp(), _longjmp();
# endif
#endif
@@ -232,6 +233,7 @@ static VALUE rb_f_binding _((VALUE));
static void rb_f_END _((void));
static VALUE rb_f_block_given_p _((void));
static VALUE block_pass _((VALUE,NODE*));
+static void eval_check_tick _((void));
VALUE rb_cMethod;
static VALUE method_call _((int, VALUE*, VALUE));
@@ -250,6 +252,8 @@ static int scope_vmode;
#define SCOPE_SET(f) (scope_vmode=(f))
#define SCOPE_TEST(f) (scope_vmode&(f))
+VALUE (*ruby_sandbox_save)_((rb_thread_t));
+VALUE (*ruby_sandbox_restore)_((rb_thread_t));
NODE* ruby_current_node;
int ruby_safe_level = 0;
/* safe-level:
@@ -366,7 +370,8 @@ rb_clear_cache_for_undef(klass, id)
ent = cache; end = ent + CACHE_SIZE;
while (ent < end) {
if (ent->mid == id &&
- RCLASS(ent->origin)->m_tbl == RCLASS(klass)->m_tbl) {
+ (ent->klass == klass ||
+ RCLASS(ent->origin)->m_tbl == RCLASS(klass)->m_tbl)) {
ent->mid = 0;
}
ent++;
@@ -458,7 +463,8 @@ rb_define_alloc_func(klass, func)
VALUE (*func) _((VALUE));
{
Check_Type(klass, T_CLASS);
- rb_add_method(CLASS_OF(klass), ID_ALLOCATOR, NEW_CFUNC(func, 0), NOEX_PRIVATE);
+ rb_add_method(rb_singleton_class(klass), ID_ALLOCATOR, NEW_CFUNC(func, 0),
+ NOEX_PRIVATE);
}
void
@@ -466,7 +472,7 @@ rb_undef_alloc_func(klass)
VALUE klass;
{
Check_Type(klass, T_CLASS);
- rb_add_method(CLASS_OF(klass), ID_ALLOCATOR, 0, NOEX_UNDEF);
+ rb_add_method(rb_singleton_class(klass), ID_ALLOCATOR, 0, NOEX_UNDEF);
}
static NODE*
@@ -474,16 +480,16 @@ search_method(klass, id, origin)
VALUE klass, *origin;
ID id;
{
- NODE *body;
+ st_data_t body;
if (!klass) return 0;
- while (!st_lookup(RCLASS(klass)->m_tbl, id, (st_data_t *)&body)) {
+ while (!st_lookup(RCLASS(klass)->m_tbl, id, &body)) {
klass = RCLASS(klass)->super;
if (!klass) return 0;
}
if (origin) *origin = klass;
- return body;
+ return (NODE *)body;
}
static NODE*
@@ -494,7 +500,7 @@ rb_get_method_body(klassp, idp, noexp)
{
ID id = *idp;
VALUE klass = *klassp;
- VALUE origin;
+ VALUE origin = 0;
NODE * volatile body;
struct cache_entry *ent;
@@ -562,7 +568,8 @@ remove_method(klass, mid)
VALUE klass;
ID mid;
{
- NODE *body;
+ st_data_t data;
+ NODE *body = 0;
if (klass == rb_cObject) {
rb_secure(4);
@@ -574,10 +581,11 @@ remove_method(klass, mid)
if (mid == __id__ || mid == __send__ || mid == init) {
rb_warn("removing `%s' may cause serious problem", rb_id2name(mid));
}
- if (st_lookup(RCLASS(klass)->m_tbl, mid, (st_data_t *)&body)) {
+ if (st_lookup(RCLASS(klass)->m_tbl, mid, &data)) {
+ body = (NODE *)data;
if (!body || !body->nd_body) body = 0;
else {
- st_delete(RCLASS(klass)->m_tbl, &mid, (st_data_t *)&body);
+ st_delete(RCLASS(klass)->m_tbl, &mid, &data);
}
}
if (!body) {
@@ -763,7 +771,7 @@ static struct SCOPE *top_scope;
static unsigned long frame_unique = 0;
#define PUSH_FRAME() do { \
- struct FRAME _frame; \
+ volatile struct FRAME _frame; \
_frame.prev = ruby_frame; \
_frame.tmp = 0; \
_frame.node = ruby_current_node; \
@@ -1032,7 +1040,7 @@ static struct tag *prot_tag;
#define PROT_LAMBDA INT2FIX(2) /* 5 */
#define PROT_YIELD INT2FIX(3) /* 7 */
-#define EXEC_TAG() (FLUSH_REGISTER_WINDOWS, ruby_setjmp(prot_tag->buf))
+#define EXEC_TAG() ruby_setjmp(((void)0), prot_tag->buf)
#define JUMP_TAG(st) do { \
ruby_frame = prot_tag->frame; \
@@ -1060,15 +1068,15 @@ VALUE ruby_class;
static VALUE ruby_wrapper; /* security wrapper */
#define PUSH_CLASS(c) do { \
- VALUE _class = ruby_class; \
+ volatile VALUE _class = ruby_class; \
ruby_class = (c)
#define POP_CLASS() ruby_class = _class; \
} while (0)
-static NODE *ruby_cref = 0;
-static NODE *top_cref;
-#define PUSH_CREF(c) ruby_cref = NEW_NODE(NODE_CREF,(c),0,ruby_cref)
+NODE *ruby_cref = 0;
+NODE *ruby_top_cref;
+#define PUSH_CREF(c) ruby_cref = NEW_CREF(c,ruby_cref)
#define POP_CREF() ruby_cref = ruby_cref->nd_next
#define PUSH_SCOPE() do { \
@@ -1083,9 +1091,11 @@ static NODE *top_cref;
ruby_scope = _scope; \
scope_vmode = SCOPE_PUBLIC
-typedef struct thread * rb_thread_t;
-static rb_thread_t curr_thread = 0;
-static rb_thread_t main_thread;
+rb_thread_t rb_curr_thread;
+rb_thread_t rb_main_thread;
+#define main_thread rb_main_thread
+#define curr_thread rb_curr_thread
+
static void scope_dup _((struct SCOPE *));
#define POP_SCOPE() \
@@ -1106,8 +1116,8 @@ static void scope_dup _((struct SCOPE *));
} while (0)
static VALUE rb_eval _((VALUE,NODE*));
-static VALUE eval _((VALUE,VALUE,VALUE,char*,int));
-static NODE *compile _((VALUE, char*, int));
+static VALUE eval _((VALUE,VALUE,VALUE,const char*,int));
+static NODE *compile _((VALUE, const char*, int));
static VALUE rb_yield_0 _((VALUE, VALUE, VALUE, int, int));
@@ -1116,8 +1126,9 @@ static VALUE rb_yield_0 _((VALUE, VALUE, VALUE, int, int));
#define YIELD_PUBLIC_DEF 4
#define YIELD_FUNC_AVALUE 1
#define YIELD_FUNC_SVALUE 2
+#define YIELD_FUNC_LAMBDA 3
-static VALUE rb_call _((VALUE,VALUE,ID,int,const VALUE*,int));
+static VALUE rb_call _((VALUE,VALUE,ID,int,const VALUE*,int,VALUE));
static VALUE module_setup _((VALUE,NODE*));
static VALUE massign _((VALUE,NODE*,VALUE,int));
@@ -1229,7 +1240,7 @@ error_print()
{
VALUE errat = Qnil; /* OK */
volatile VALUE eclass, e;
- char *einfo;
+ const char *einfo;
long elen;
if (NIL_P(ruby_errinfo)) return;
@@ -1290,7 +1301,7 @@ error_print()
long len = elen;
if (RSTRING(epath)->ptr[0] == '#') epath = 0;
- if (tail = memchr(einfo, '\n', elen)) {
+ if ((tail = memchr(einfo, '\n', elen)) != 0) {
len = tail - einfo;
tail++; /* skip newline */
}
@@ -1301,8 +1312,9 @@ error_print()
warn_print2(RSTRING(epath)->ptr, RSTRING(epath)->len);
warn_print(")\n");
}
- if (tail) {
+ if (tail && elen>len+1) {
warn_print2(tail, elen-len-1);
+ if (einfo[elen-1] != '\n') warn_print2("\n", 1);
}
}
}
@@ -1310,6 +1322,7 @@ error_print()
if (!NIL_P(errat)) {
long i;
struct RArray *ep = RARRAY(errat);
+ int truncate = eclass == rb_eSysStackError;
#define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5)
#define TRACE_HEAD 8
@@ -1320,7 +1333,7 @@ error_print()
if (TYPE(ep->ptr[i]) == T_STRING) {
warn_printf("\tfrom %s\n", RSTRING(ep->ptr[i])->ptr);
}
- if (i == TRACE_HEAD && ep->len > TRACE_MAX) {
+ if (truncate && i == TRACE_HEAD && ep->len > TRACE_MAX) {
warn_printf("\t ... %ld levels...\n",
ep->len - TRACE_HEAD - TRACE_TAIL);
i = ep->len - TRACE_TAIL;
@@ -1398,8 +1411,8 @@ ruby_init()
rb_call_inits();
ruby_class = rb_cObject;
ruby_frame->self = ruby_top_self;
- top_cref = rb_node_newnode(NODE_CREF,rb_cObject,0,0);
- ruby_cref = top_cref;
+ ruby_top_cref = NEW_CREF(rb_cObject, 0);
+ ruby_cref = ruby_top_cref;
rb_define_global_const("TOPLEVEL_BINDING", rb_f_binding(ruby_top_self));
#ifdef __MACOS__
_macruby_init();
@@ -1441,8 +1454,7 @@ int ruby_in_eval;
static void rb_thread_cleanup _((void));
static void rb_thread_wait_other_threads _((void));
-static int thread_set_raised();
-static int thread_reset_raised();
+static int thread_no_ensure _((void));
static VALUE exception_error;
static VALUE sysstack_error;
@@ -1460,8 +1472,10 @@ error_handle(ex)
int ex;
{
int status = EXIT_FAILURE;
+ rb_thread_t th = curr_thread;
- if (thread_set_raised()) return EXIT_FAILURE;
+ if (rb_thread_set_raised(th))
+ return EXIT_FAILURE;
switch (ex & TAG_MASK) {
case 0:
status = EXIT_SUCCESS;
@@ -1503,6 +1517,9 @@ error_handle(ex)
if (rb_obj_is_kind_of(ruby_errinfo, rb_eSystemExit)) {
status = sysexit_status(ruby_errinfo);
}
+ else if (rb_obj_is_instance_of(ruby_errinfo, rb_eSignal)) {
+ /* no message when exiting by signal */
+ }
else {
error_print();
}
@@ -1511,7 +1528,7 @@ error_handle(ex)
rb_bug("Unknown longjmp status %d", ex);
break;
}
- thread_reset_raised();
+ rb_thread_reset_raised(th);
return status;
}
@@ -1570,12 +1587,14 @@ ruby_cleanup(ex)
int ex;
{
int state;
- volatile VALUE err = ruby_errinfo;
+ volatile VALUE errs[2];
+ int nerr;
+ errs[1] = ruby_errinfo;
ruby_safe_level = 0;
- Init_stack((void*)&state);
+ Init_stack((void *)&state);
ruby_finalize_0();
- if (ruby_errinfo) err = ruby_errinfo;
+ errs[0] = ruby_errinfo;
PUSH_TAG(PROT_NONE);
PUSH_ITER(ITER_NOT);
if ((state = EXEC_TAG()) == 0) {
@@ -1586,15 +1605,39 @@ ruby_cleanup(ex)
ex = state;
}
POP_ITER();
- ruby_errinfo = err;
+ ruby_errinfo = errs[1];
ex = error_handle(ex);
ruby_finalize_1();
POP_TAG();
- if (err && rb_obj_is_kind_of(err, rb_eSystemExit)) {
- VALUE st = rb_iv_get(err, "status");
- return NUM2INT(st);
+ for (nerr = 0; nerr < sizeof(errs) / sizeof(errs[0]); ++nerr) {
+ VALUE err = errs[nerr];
+
+ if (!RTEST(err)) continue;
+
+ if (rb_obj_is_kind_of(err, rb_eSystemExit)) {
+ return sysexit_status(err);
+ }
+ else if (rb_obj_is_kind_of(err, rb_eSignal)) {
+ VALUE sig = rb_iv_get(err, "signo");
+ ruby_default_signal(NUM2INT(sig));
+ }
+ else if (ex == 0) {
+ ex = 1;
+ }
}
+
+#if EXIT_SUCCESS != 0 || EXIT_FAILURE != 1
+ switch (ex) {
+#if EXIT_SUCCESS != 0
+ case 0: return EXIT_SUCCESS;
+#endif
+#if EXIT_FAILURE != 1
+ case 1: return EXIT_FAILURE;
+#endif
+ }
+#endif
+
return ex;
}
@@ -1858,7 +1901,7 @@ rb_eval_cmd(cmd, arg, level)
POP_TAG();
POP_FRAME();
- jump_tag_but_local_jump(state, val);
+ if (state) jump_tag_but_local_jump(state, val);
return val;
}
@@ -2001,7 +2044,7 @@ void
rb_frozen_class_p(klass)
VALUE klass;
{
- char *desc = "something(?!)";
+ const char *desc = "something(?!)";
if (OBJ_FROZEN(klass)) {
if (FL_TEST(klass, FL_SINGLETON))
@@ -2039,7 +2082,7 @@ rb_undef(klass, id)
}
body = search_method(klass, id, &origin);
if (!body || !body->nd_body) {
- char *s0 = " class";
+ const char *s0 = " class";
VALUE c = klass;
if (FL_TEST(c, FL_SINGLETON)) {
@@ -2130,9 +2173,10 @@ rb_alias(klass, name, def)
VALUE klass;
ID name, def;
{
- VALUE origin;
+ VALUE origin = 0;
NODE *orig, *body, *node;
VALUE singleton = 0;
+ st_data_t data;
rb_frozen_class_p(klass);
if (name == def) return;
@@ -2160,7 +2204,8 @@ rb_alias(klass, name, def)
}
rb_clear_cache_by_id(name);
- if (RTEST(ruby_verbose) && st_lookup(RCLASS(klass)->m_tbl, name, (st_data_t *)&node)) {
+ if (RTEST(ruby_verbose) && st_lookup(RCLASS(klass)->m_tbl, name, &data)) {
+ node = (NODE *)data;
if (node->nd_cnt == 0 && node->nd_body) {
rb_warning("discarding old %s", rb_id2name(name));
}
@@ -2168,6 +2213,9 @@ rb_alias(klass, name, def)
st_insert(RCLASS(klass)->m_tbl, name,
(st_data_t)NEW_METHOD(NEW_FBODY(body, def, origin),
NOEX_WITH_SAFE(orig->nd_noex)));
+
+ if (!ruby_running) return;
+
if (singleton) {
rb_funcall(singleton, singleton_added, 1, ID2SYM(name));
}
@@ -2206,8 +2254,8 @@ rb_mod_alias_method(mod, newname, oldname)
return mod;
}
-static NODE*
-copy_node_scope(node, rval)
+NODE *
+rb_copy_node_scope(node, rval)
NODE *node;
NODE *rval;
{
@@ -2273,7 +2321,7 @@ copy_node_scope(node, rval)
int tmp_iter = ruby_iter->iter;\
switch (tmp_iter) {\
case ITER_PRE:\
- ruby_block = ruby_block->outer;\
+ if (ruby_block) ruby_block = ruby_block->outer;\
case ITER_PAS:\
tmp_iter = ITER_NOT;\
}\
@@ -2286,9 +2334,9 @@ copy_node_scope(node, rval)
#define MATCH_DATA *rb_svar(node->nd_cnt)
-static char* is_defined _((VALUE, NODE*, char*));
+static const char* is_defined _((VALUE, NODE*, char*));
-static char*
+static const char*
arg_defined(self, node, buf, type)
VALUE self;
NODE *node;
@@ -2315,7 +2363,7 @@ arg_defined(self, node, buf, type)
return type;
}
-static char*
+static const char*
is_defined(self, node, buf)
VALUE self;
NODE *node; /* OK */
@@ -2408,6 +2456,8 @@ is_defined(self, node, buf)
case NODE_ATTRSET:
case NODE_OP_ASGN1:
case NODE_OP_ASGN2:
+ case NODE_OP_ASGN_OR:
+ case NODE_OP_ASGN_AND:
case NODE_MASGN:
case NODE_LASGN:
case NODE_DASGN:
@@ -2633,27 +2683,27 @@ set_trace_func(obj, trace)
return trace;
}
-static char *
+static const char *
get_event_name(rb_event_t event)
{
switch (event) {
- case RUBY_EVENT_LINE:
+ case RUBY_EVENT_LINE:
return "line";
- case RUBY_EVENT_CLASS:
+ case RUBY_EVENT_CLASS:
return "class";
- case RUBY_EVENT_END:
+ case RUBY_EVENT_END:
return "end";
- case RUBY_EVENT_CALL:
+ case RUBY_EVENT_CALL:
return "call";
- case RUBY_EVENT_RETURN:
+ case RUBY_EVENT_RETURN:
return "return";
- case RUBY_EVENT_C_CALL:
+ case RUBY_EVENT_C_CALL:
return "c-call";
- case RUBY_EVENT_C_RETURN:
+ case RUBY_EVENT_C_RETURN:
return "c-return";
- case RUBY_EVENT_RAISE:
+ case RUBY_EVENT_RAISE:
return "raise";
- default:
+ default:
return "unknown";
}
}
@@ -2670,7 +2720,8 @@ call_trace_func(event, node, self, id, klass)
struct FRAME *prev;
NODE *node_save;
VALUE srcfile;
- char *event_name;
+ const char *event_name;
+ rb_thread_t th = curr_thread;
if (!trace_func) return;
if (tracing) return;
@@ -2702,7 +2753,7 @@ call_trace_func(event, node, self, id, klass)
}
}
PUSH_TAG(PROT_NONE);
- raised = thread_reset_raised();
+ raised = rb_thread_reset_raised(th);
if ((state = EXEC_TAG()) == 0) {
srcfile = rb_str_new2(ruby_sourcefile?ruby_sourcefile:"(ruby)");
event_name = get_event_name(event);
@@ -2714,7 +2765,7 @@ call_trace_func(event, node, self, id, klass)
klass),
Qundef, 0);
}
- if (raised) thread_set_raised();
+ if (raised) rb_thread_set_raised(th);
POP_TAG();
POP_FRAME();
@@ -2906,12 +2957,14 @@ rb_eval(self, n)
NODE * volatile node = n;
int state;
volatile VALUE result = Qnil;
+ st_data_t data;
#define RETURN(v) do { \
result = (v); \
goto finish; \
} while (0)
+ eval_check_tick();
again:
if (!node) RETURN(Qnil);
@@ -3005,13 +3058,16 @@ rb_eval(self, n)
RETURN(Qfalse);
case NODE_IF:
- EXEC_EVENT_HOOK(RUBY_EVENT_LINE, node, self,
- ruby_frame->last_func,
- ruby_frame->last_class);
if (RTEST(rb_eval(self, node->nd_cond))) {
+ EXEC_EVENT_HOOK(RUBY_EVENT_LINE, node, self,
+ ruby_frame->last_func,
+ ruby_frame->last_class);
node = node->nd_body;
}
else {
+ EXEC_EVENT_HOOK(RUBY_EVENT_LINE, node, self,
+ ruby_frame->last_func,
+ ruby_frame->last_class);
node = node->nd_else;
}
goto again;
@@ -3188,7 +3244,7 @@ rb_eval(self, n)
END_CALLARGS;
ruby_current_node = node;
SET_CURRENT_SOURCE();
- result = rb_call(CLASS_OF(recv),recv,each,0,0,0);
+ result = rb_call(CLASS_OF(recv),recv,each,0,0,0,self);
}
POP_ITER();
}
@@ -3314,7 +3370,7 @@ rb_eval(self, n)
result = rb_eval(self, node->nd_head);
}
POP_TAG();
- if (node->nd_ensr) {
+ if (node->nd_ensr && !thread_no_ensure()) {
VALUE retval = prot_tag->retval; /* save retval */
VALUE errinfo = ruby_errinfo;
@@ -3429,7 +3485,7 @@ rb_eval(self, n)
ruby_current_node = node;
SET_CURRENT_SOURCE();
- rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,scope);
+ rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,scope,self);
result = argv[argc-1];
}
break;
@@ -3447,7 +3503,7 @@ rb_eval(self, n)
ruby_current_node = node;
SET_CURRENT_SOURCE();
- result = rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0);
+ result = rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0,self);
}
break;
@@ -3462,13 +3518,13 @@ rb_eval(self, n)
ruby_current_node = node;
SET_CURRENT_SOURCE();
- result = rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,1);
+ result = rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,1,self);
}
break;
case NODE_VCALL:
SET_CURRENT_SOURCE();
- result = rb_call(CLASS_OF(self),self,node->nd_mid,0,0,2);
+ result = rb_call(CLASS_OF(self),self,node->nd_mid,0,0,2,self);
break;
case NODE_SUPER:
@@ -3497,6 +3553,10 @@ rb_eval(self, n)
}
argv = RARRAY(RBASIC(ruby_scope)->klass)->ptr;
}
+ else if (!ruby_scope->local_vars) {
+ argc = 0;
+ argv = 0;
+ }
else {
argv = ruby_scope->local_vars + 2;
}
@@ -3841,11 +3901,13 @@ rb_eval(self, n)
case NODE_DREGX:
result = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len,
node->nd_cflag);
+ RB_GC_GUARD(str); /* ensure str is not GC'd in rb_reg_new */
break;
case NODE_DREGX_ONCE: /* regexp expand once */
result = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len,
node->nd_cflag);
nd_set_type(node, NODE_LIT);
+ RB_GC_GUARD(str); /* ensure str is not GC'd in rb_reg_new */
node->nd_lit = result;
break;
case NODE_LIT:
@@ -3875,7 +3937,7 @@ rb_eval(self, n)
case NODE_DEFN:
if (node->nd_defn) {
NODE *body, *defn;
- VALUE origin;
+ VALUE origin = 0;
int noex;
if (NIL_P(ruby_class)) {
@@ -3909,7 +3971,7 @@ rb_eval(self, n)
noex |= NOEX_NOSUPER;
}
- defn = copy_node_scope(node->nd_defn, ruby_cref);
+ defn = rb_copy_node_scope(node->nd_defn, ruby_cref);
rb_add_method(ruby_class, node->nd_mid, defn, noex);
if (scope_vmode == SCOPE_MODFUNC) {
rb_add_method(rb_singleton_class(ruby_class),
@@ -3937,7 +3999,8 @@ rb_eval(self, n)
if (OBJ_FROZEN(recv)) rb_error_frozen("object");
klass = rb_singleton_class(recv);
- if (st_lookup(RCLASS(klass)->m_tbl, node->nd_mid, (st_data_t *)&body)) {
+ if (st_lookup(RCLASS(klass)->m_tbl, node->nd_mid, &data)) {
+ body = (NODE *)data;
if (ruby_safe_level >= 4) {
rb_raise(rb_eSecurityError, "redefining method prohibited");
}
@@ -3945,7 +4008,7 @@ rb_eval(self, n)
rb_warning("redefine %s", rb_id2name(node->nd_mid));
}
}
- defn = copy_node_scope(node->nd_defn, ruby_cref);
+ defn = rb_copy_node_scope(node->nd_defn, ruby_cref);
rb_add_method(klass, node->nd_mid, defn,
NOEX_PUBLIC|(body?body->nd_noex&NOEX_UNDEF:0));
result = Qnil;
@@ -4089,7 +4152,7 @@ rb_eval(self, n)
case NODE_DEFINED:
{
char buf[20];
- char *desc = is_defined(self, node->nd_head, buf);
+ const char *desc = is_defined(self, node->nd_head, buf);
if (desc) result = rb_str_new2(desc);
else result = Qnil;
@@ -4186,7 +4249,7 @@ rb_obj_respond_to(obj, id, priv)
int n = 0;
args[n++] = ID2SYM(id);
if (priv) args[n++] = Qtrue;
- return rb_funcall2(obj, respond_to, n, args);
+ return RTEST(rb_funcall2(obj, respond_to, n, args));
}
}
@@ -4524,8 +4587,9 @@ rb_longjmp(tag, mesg)
VALUE mesg;
{
VALUE at;
+ rb_thread_t th = curr_thread;
- if (thread_set_raised()) {
+ if (rb_thread_set_raised(th)) {
ruby_errinfo = exception_error;
JUMP_TAG(TAG_FATAL);
}
@@ -4539,6 +4603,9 @@ rb_longjmp(tag, mesg)
at = get_backtrace(mesg);
if (NIL_P(at)) {
at = make_backtrace();
+ if (OBJ_FROZEN(mesg)) {
+ mesg = rb_obj_dup(mesg);
+ }
set_backtrace(mesg, at);
}
}
@@ -4564,7 +4631,7 @@ rb_longjmp(tag, mesg)
ruby_errinfo = mesg;
}
else if (status) {
- thread_reset_raised();
+ rb_thread_reset_raised(th);
JUMP_TAG(status);
}
}
@@ -4579,14 +4646,24 @@ rb_longjmp(tag, mesg)
if (!prot_tag) {
error_print();
}
- thread_reset_raised();
+ rb_thread_raised_clear(th);
JUMP_TAG(tag);
}
void
+rb_exc_jump(mesg)
+ VALUE mesg;
+{
+ rb_thread_raised_clear(rb_curr_thread);
+ ruby_errinfo = mesg;
+ JUMP_TAG(TAG_RAISE);
+}
+
+void
rb_exc_raise(mesg)
VALUE mesg;
{
+ mesg = rb_make_exception(1, &mesg);
rb_longjmp(TAG_RAISE, mesg);
}
@@ -4594,13 +4671,15 @@ void
rb_exc_fatal(mesg)
VALUE mesg;
{
+ mesg = rb_make_exception(1, &mesg);
rb_longjmp(TAG_FATAL, mesg);
}
void
rb_interrupt()
{
- rb_raise(rb_eInterrupt, "");
+ static const char fmt[1] = {'\0'};
+ rb_raise(rb_eInterrupt, fmt);
}
/*
@@ -4747,7 +4826,7 @@ rb_f_block_given_p()
return Qfalse;
}
-static VALUE rb_eThreadError;
+VALUE rb_eThreadError;
NORETURN(static void proc_jump_error(int, VALUE));
static void
@@ -4756,7 +4835,7 @@ proc_jump_error(state, result)
VALUE result;
{
char mesg[32];
- char *statement;
+ const char *statement;
switch (state) {
case TAG_BREAK:
@@ -4870,7 +4949,7 @@ rb_yield_0(val, self, klass, flags, avalue)
VALUE val, self, klass; /* OK */
int flags, avalue;
{
- NODE *node;
+ NODE *node, *var;
volatile VALUE result = Qnil;
volatile VALUE old_cref;
volatile VALUE old_wrapper;
@@ -4912,27 +4991,35 @@ rb_yield_0(val, self, klass, flags, avalue)
self = block->self;
}
node = block->body;
+ var = block->var;
- if (block->var) {
+ if (var) {
PUSH_TAG(PROT_NONE);
if ((state = EXEC_TAG()) == 0) {
- if (block->var == (NODE*)1) { /* no parameter || */
+ NODE *bvar = NULL;
+ block_var:
+ if (var == (NODE*)1) { /* no parameter || */
if (lambda && RARRAY(val)->len != 0) {
rb_raise(rb_eArgError, "wrong number of arguments (%ld for 0)",
RARRAY(val)->len);
}
}
- else if (block->var == (NODE*)2) {
+ else if (var == (NODE*)2) {
if (TYPE(val) == T_ARRAY && RARRAY(val)->len != 0) {
rb_raise(rb_eArgError, "wrong number of arguments (%ld for 0)",
RARRAY(val)->len);
}
}
- else if (nd_type(block->var) == NODE_MASGN) {
+ else if (!bvar && nd_type(var) == NODE_BLOCK_PASS) {
+ bvar = var->nd_body;
+ var = var->nd_args;
+ goto block_var;
+ }
+ else if (nd_type(var) == NODE_MASGN) {
if (!avalue) {
- val = svalue_to_mrhs(val, block->var->nd_head);
+ val = svalue_to_mrhs(val, var->nd_head);
}
- massign(self, block->var, val, lambda);
+ massign(self, var, val, lambda);
}
else {
int len = 0;
@@ -4953,13 +5040,21 @@ rb_yield_0(val, self, klass, flags, avalue)
val = Qnil;
multi_values:
{
- ruby_current_node = block->var;
+ ruby_current_node = var;
rb_warn("multiple values for a block parameter (%d for 1)\n\tfrom %s:%d",
len, cnode->nd_file, nd_line(cnode));
ruby_current_node = cnode;
}
}
- assign(self, block->var, val, lambda);
+ assign(self, var, val, lambda);
+ }
+ if (bvar) {
+ VALUE blk;
+ if (flags & YIELD_PROC_CALL)
+ blk = block->block_obj;
+ else
+ blk = rb_block_proc();
+ assign(self, bvar, blk, 0);
}
}
POP_TAG();
@@ -4976,12 +5071,18 @@ rb_yield_0(val, self, klass, flags, avalue)
if ((state = EXEC_TAG()) == 0) {
redo:
if (nd_type(node) == NODE_CFUNC || nd_type(node) == NODE_IFUNC) {
- if (node->nd_state == YIELD_FUNC_AVALUE) {
+ switch (node->nd_state) {
+ case YIELD_FUNC_LAMBDA:
+ if (!avalue) {
+ val = (val == Qundef) ? rb_ary_new2(0) : rb_ary_new3(1, val);
+ }
+ break;
+ case YIELD_FUNC_AVALUE:
if (!avalue) {
val = svalue_to_avalue(val);
}
- }
- else {
+ break;
+ default:
if (avalue) {
val = avalue_to_svalue(val);
}
@@ -5119,6 +5220,16 @@ rb_yield_splat(values)
return rb_yield_0(values, 0, 0, 0, avalue);
}
+static VALUE
+loop_i()
+{
+ for (;;) {
+ rb_yield_0(Qundef, 0, 0, 0, Qfalse);
+ CHECK_INTS;
+ }
+ return Qnil;
+}
+
/*
* call-seq:
* loop {|| block }
@@ -5131,15 +5242,14 @@ rb_yield_splat(values)
* break if !line or line =~ /^qQ/
* # ...
* end
+ *
+ * StopIteration raised in the block breaks the loop.
*/
static VALUE
rb_f_loop()
{
- for (;;) {
- rb_yield_0(Qundef, 0, 0, 0, Qfalse);
- CHECK_INTS;
- }
+ rb_rescue2(loop_i, (VALUE)0, 0, 0, rb_eStopIteration, (VALUE)0);
return Qnil; /* dummy */
}
@@ -5266,7 +5376,7 @@ assign(self, lhs, val, pcall)
/* attr set */
ruby_current_node = lhs;
SET_CURRENT_SOURCE();
- rb_call(CLASS_OF(recv), recv, lhs->nd_mid, 1, &val, scope);
+ rb_call(CLASS_OF(recv), recv, lhs->nd_mid, 1, &val, scope, self);
}
else {
/* array set */
@@ -5277,7 +5387,7 @@ assign(self, lhs, val, pcall)
ruby_current_node = lhs;
SET_CURRENT_SOURCE();
rb_call(CLASS_OF(recv), recv, lhs->nd_mid,
- RARRAY(args)->len, RARRAY(args)->ptr, scope);
+ RARRAY(args)->len, RARRAY(args)->ptr, scope, self);
}
}
break;
@@ -5298,9 +5408,9 @@ rb_iterate(it_proc, data1, bl_proc, data2)
NODE *node = NEW_IFUNC(bl_proc, data2);
VALUE self = ruby_top_self;
- PUSH_ITER(ITER_PRE);
PUSH_TAG(PROT_LOOP);
PUSH_BLOCK(0, node);
+ PUSH_ITER(ITER_PRE);
state = EXEC_TAG();
if (state == 0) {
iter_retry:
@@ -5314,9 +5424,9 @@ rb_iterate(it_proc, data1, bl_proc, data2)
state = 0;
goto iter_retry;
}
+ POP_ITER();
POP_BLOCK();
POP_TAG();
- POP_ITER();
switch (state) {
case 0:
@@ -5384,7 +5494,7 @@ rb_rescue2(b_proc, data1, r_proc, data2, va_alist)
if (handle) break;
handle = Qfalse;
va_init_list(args, data2);
- while (eclass = va_arg(args, VALUE)) {
+ while ((eclass = va_arg(args, VALUE)) != 0) {
if (rb_obj_is_kind_of(ruby_errinfo, eclass)) {
handle = Qtrue;
break;
@@ -5462,7 +5572,9 @@ rb_ensure(b_proc, data1, e_proc, data2)
}
POP_TAG();
retval = prot_tag ? prot_tag->retval : Qnil; /* save retval */
- (*e_proc)(data2);
+ if (!thread_no_ensure()) {
+ (*e_proc)(data2);
+ }
if (prot_tag) return_value(retval);
if (state) JUMP_TAG(state);
return result;
@@ -5497,18 +5609,22 @@ rb_with_disable_interrupt(proc, data)
static void
stack_check()
{
- static int overflowing = 0;
+ rb_thread_t th = rb_curr_thread;
- if (!overflowing && ruby_stack_check()) {
- int state;
- overflowing = 1;
- PUSH_TAG(PROT_NONE);
- if ((state = EXEC_TAG()) == 0) {
- rb_exc_raise(sysstack_error);
- }
- POP_TAG();
- overflowing = 0;
- JUMP_TAG(state);
+ if (!rb_thread_raised_p(th, RAISED_STACKOVERFLOW) && ruby_stack_check()) {
+ rb_thread_raised_set(th, RAISED_STACKOVERFLOW);
+ rb_exc_raise(sysstack_error);
+ }
+}
+
+static void
+eval_check_tick()
+{
+ static int tick;
+ if ((++tick & 0xff) == 0) {
+ CHECK_INTS; /* better than nothing */
+ stack_check();
+ rb_gc_finalize_deferred();
}
}
@@ -5557,7 +5673,7 @@ rb_method_missing(argc, argv, obj)
{
ID id;
VALUE exc = rb_eNoMethodError;
- char *format = 0;
+ const char *format = 0;
NODE *cnode = ruby_current_node;
if (argc == 0 || !SYMBOL_P(argv[0])) {
@@ -5579,7 +5695,7 @@ rb_method_missing(argc, argv, obj)
exc = rb_eNameError;
}
else if (last_call_status & CSTAT_SUPER) {
- format = "super: no superclass method `%s'";
+ format = "super: no superclass method `%s' for %s";
}
if (!format) {
format = "undefined method `%s' for %s";
@@ -5743,12 +5859,10 @@ rb_call0(klass, recv, id, oid, argc, argv, body, flags)
NODE *b2; /* OK */
volatile VALUE result = Qnil;
int itr;
- static int tick;
TMP_PROTECT;
volatile int safe = -1;
- if (NOEX_SAFE(flags) > ruby_safe_level &&
- ruby_safe_level == 0 && NOEX_SAFE(flags) > 2) {
+ if (NOEX_SAFE(flags) > ruby_safe_level && NOEX_SAFE(flags) > 2) {
rb_raise(rb_eSecurityError, "calling insecure method: %s",
rb_id2name(id));
}
@@ -5763,11 +5877,7 @@ rb_call0(klass, recv, id, oid, argc, argv, body, flags)
break;
}
- if ((++tick & 0xff) == 0) {
- CHECK_INTS; /* better than nothing */
- stack_check();
- rb_gc_finalize_deferred();
- }
+ eval_check_tick();
if (argc < 0) {
VALUE tmp;
VALUE *nargv;
@@ -5851,7 +5961,7 @@ rb_call0(klass, recv, id, oid, argc, argv, body, flags)
}
result = proc_invoke(body->nd_cval, rb_ary_new4(argc, argv), recv, klass);
if (event_hooks) {
- EXEC_EVENT_HOOK(RUBY_EVENT_RETURN, body, recv, id, klass);
+ EXEC_EVENT_HOOK(RUBY_EVENT_RETURN, ruby_current_node, recv, id, klass);
}
break;
@@ -5935,14 +6045,21 @@ rb_call0(klass, recv, id, oid, argc, argv, body, flags)
while (opt && argc) {
assign(recv, opt->nd_head, *argv, 1);
argv++; argc--;
+ ++i;
opt = opt->nd_next;
}
if (opt) {
rb_eval(recv, opt);
+ while (opt) {
+ opt = opt->nd_next;
+ ++i;
+ }
}
+ }
+ if (!node->nd_rest) {
i = nopt;
}
- if (node->nd_rest) {
+ else {
VALUE v;
if (argc > 0) {
@@ -5967,7 +6084,7 @@ rb_call0(klass, recv, id, oid, argc, argv, body, flags)
}
POP_TAG();
if (event_hooks) {
- EXEC_EVENT_HOOK(RUBY_EVENT_RETURN, body, recv, id, klass);
+ EXEC_EVENT_HOOK(RUBY_EVENT_RETURN, ruby_current_node, recv, id, klass);
}
POP_VARS();
POP_CLASS();
@@ -6003,12 +6120,13 @@ rb_call0(klass, recv, id, oid, argc, argv, body, flags)
}
static VALUE
-rb_call(klass, recv, mid, argc, argv, scope)
+rb_call(klass, recv, mid, argc, argv, scope, self)
VALUE klass, recv;
ID mid;
int argc; /* OK */
const VALUE *argv; /* OK */
int scope;
+ VALUE self;
{
NODE *body; /* OK */
int noex;
@@ -6023,13 +6141,14 @@ rb_call(klass, recv, mid, argc, argv, scope)
ent = cache + EXPR1(klass, mid);
if (ent->mid == mid && ent->klass == klass) {
if (!ent->method)
- return method_missing(recv, mid, argc, argv, scope==2?CSTAT_VCALL:0);
+ goto nomethod;
klass = ent->origin;
id = ent->mid0;
noex = ent->noex;
body = ent->method;
}
else if ((body = rb_get_method_body(&klass, &id, &noex)) == 0) {
+ nomethod:
if (scope == 3) {
return method_missing(recv, mid, argc, argv, CSTAT_SUPER);
}
@@ -6045,10 +6164,11 @@ rb_call(klass, recv, mid, argc, argv, scope)
if (noex & NOEX_PROTECTED) {
VALUE defined_class = klass;
+ if (self == Qundef) self = ruby_frame->self;
if (TYPE(defined_class) == T_ICLASS) {
defined_class = RBASIC(defined_class)->klass;
}
- if (!rb_obj_is_kind_of(ruby_frame->self, rb_class_real(defined_class)))
+ if (!rb_obj_is_kind_of(self, rb_class_real(defined_class)))
return method_missing(recv, mid, argc, argv, CSTAT_PROT);
}
}
@@ -6068,7 +6188,7 @@ rb_apply(recv, mid, args)
argc = RARRAY(args)->len; /* Assigns LONG, but argc is INT */
argv = ALLOCA_N(VALUE, argc);
MEMCPY(argv, RARRAY(args)->ptr, VALUE, argc);
- return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 1);
+ return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 1, Qundef);
}
/*
@@ -6101,7 +6221,7 @@ rb_f_send(argc, argv, recv)
vid = *argv++; argc--;
PUSH_ITER(rb_block_given_p()?ITER_PRE:ITER_NOT);
- vid = rb_call(CLASS_OF(recv), recv, rb_to_id(vid), argc, argv, 1);
+ vid = rb_call(CLASS_OF(recv), recv, rb_to_id(vid), argc, argv, 1, Qundef);
POP_ITER();
return vid;
@@ -6130,7 +6250,7 @@ vafuncall(recv, mid, n, ar)
argv = 0;
}
- return rb_call(CLASS_OF(recv), recv, mid, n, argv, 1);
+ return rb_call(CLASS_OF(recv), recv, mid, n, argv, 1, Qundef);
}
VALUE
@@ -6189,7 +6309,7 @@ rb_funcall2(recv, mid, argc, argv)
int argc;
const VALUE *argv;
{
- return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 1);
+ return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 1, Qundef);
}
VALUE
@@ -6199,7 +6319,7 @@ rb_funcall3(recv, mid, argc, argv)
int argc;
const VALUE *argv;
{
- return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 0);
+ return rb_call(CLASS_OF(recv), recv, mid, argc, argv, 0, Qundef);
}
VALUE
@@ -6221,7 +6341,7 @@ rb_call_super(argc, argv)
}
PUSH_ITER(ruby_iter->iter ? ITER_PRE : ITER_NOT);
- result = rb_call(RCLASS(klass)->super, self, ruby_frame->orig_func, argc, argv, 3);
+ result = rb_call(RCLASS(klass)->super, self, ruby_frame->orig_func, argc, argv, 3, Qundef);
POP_ITER();
return result;
@@ -6349,10 +6469,16 @@ rb_frame_last_func()
return ruby_frame->last_func;
}
+ID
+rb_frame_this_func()
+{
+ return ruby_frame->orig_func;
+}
+
static NODE*
compile(src, file, line)
VALUE src;
- char *file;
+ const char *file;
int line;
{
NODE *node;
@@ -6372,7 +6498,7 @@ compile(src, file, line)
static VALUE
eval(self, src, scope, file, line)
VALUE self, src, scope;
- char *file;
+ const char *file;
int line;
{
struct BLOCK *data = NULL;
@@ -6486,16 +6612,25 @@ eval(self, src, scope, file, line)
if (state) {
if (state == TAG_RAISE) {
if (strcmp(file, "(eval)") == 0) {
- VALUE mesg, errat;
+ VALUE mesg, errat, bt2;
+ ID id_mesg;
+ id_mesg = rb_intern("mesg");
errat = get_backtrace(ruby_errinfo);
- mesg = rb_attr_get(ruby_errinfo, rb_intern("mesg"));
- if (!NIL_P(errat) && TYPE(errat) == T_ARRAY) {
+ mesg = rb_attr_get(ruby_errinfo, id_mesg);
+ if (!NIL_P(errat) && TYPE(errat) == T_ARRAY &&
+ (bt2 = backtrace(-2), RARRAY_LEN(bt2) > 0)) {
if (!NIL_P(mesg) && TYPE(mesg) == T_STRING) {
- rb_str_update(mesg, 0, 0, rb_str_new2(": "));
- rb_str_update(mesg, 0, 0, RARRAY(errat)->ptr[0]);
+ if (OBJ_FROZEN(mesg)) {
+ VALUE m = rb_str_cat(rb_str_dup(RARRAY_PTR(errat)[0]), ": ", 2);
+ rb_ivar_set(ruby_errinfo, id_mesg, rb_str_append(m, mesg));
+ }
+ else {
+ rb_str_update(mesg, 0, 0, rb_str_new2(": "));
+ rb_str_update(mesg, 0, 0, RARRAY_PTR(errat)[0]);
+ }
}
- RARRAY(errat)->ptr[0] = RARRAY(backtrace(-2))->ptr[0];
+ RARRAY_PTR(errat)[0] = RARRAY_PTR(bt2)[0];
}
}
rb_exc_raise(ruby_errinfo);
@@ -6532,7 +6667,7 @@ rb_f_eval(argc, argv, self)
VALUE self;
{
VALUE src, scope, vfile, vline;
- char *file = "(eval)";
+ const char *file = "(eval)";
int line = 1;
rb_scan_args(argc, argv, "13", &src, &scope, &vfile, &vline);
@@ -6649,12 +6784,28 @@ yield_under_i(self)
return rb_yield_0(self, self, ruby_class, YIELD_PUBLIC_DEF, Qfalse);
}
+static VALUE
+yield_args_under_i(vinfo)
+ VALUE vinfo;
+{
+ VALUE *info = (VALUE *)vinfo;
+
+ return rb_yield_0(info[0], info[1], ruby_class, YIELD_PUBLIC_DEF, Qtrue);
+}
+
/* block eval under the class/module context */
static VALUE
-yield_under(under, self)
- VALUE under, self;
+yield_under(under, self, args)
+ VALUE under, self, args;
{
- return exec_under(yield_under_i, under, 0, self);
+ if (args == Qundef) {
+ return exec_under(yield_under_i, under, 0, self);
+ }
+ else {
+ VALUE info[2] = { args, self };
+
+ return exec_under(yield_args_under_i, under, 0, (VALUE)info);
+ }
}
static VALUE
@@ -6667,10 +6818,10 @@ specific_eval(argc, argv, klass, self)
if (argc > 0) {
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc);
}
- return yield_under(klass, self);
+ return yield_under(klass, self, Qundef);
}
else {
- char *file = "(eval)";
+ const char *file = "(eval)";
int line = 1;
if (argc == 0) {
@@ -6739,6 +6890,41 @@ rb_obj_instance_eval(argc, argv, self)
/*
* call-seq:
+ * obj.instance_exec(arg...) {|var...| block } => obj
+ *
+ * Executes the given block within the context of the receiver
+ * (_obj_). In order to set the context, the variable +self+ is set
+ * to _obj_ while the code is executing, giving the code access to
+ * _obj_'s instance variables. Arguments are passed as block parameters.
+ *
+ * class KlassWithSecret
+ * def initialize
+ * @secret = 99
+ * end
+ * end
+ * k = KlassWithSecret.new
+ * k.instance_exec(5) {|x| @secret+x } #=> 104
+ */
+
+VALUE
+rb_obj_instance_exec(argc, argv, self)
+ int argc;
+ VALUE *argv;
+ VALUE self;
+{
+ VALUE klass;
+
+ if (SPECIAL_CONST_P(self)) {
+ klass = Qnil;
+ }
+ else {
+ klass = rb_singleton_class(self);
+ }
+ return yield_under(klass, self, rb_ary_new4(argc, argv));
+}
+
+/*
+ * call-seq:
* mod.class_eval(string [, filename [, lineno]]) => obj
* mod.module_eval {|| block } => obj
*
@@ -6770,6 +6956,35 @@ rb_mod_module_eval(argc, argv, mod)
return specific_eval(argc, argv, mod, mod);
}
+/*
+ * call-seq:
+ * mod.module_exec(arg...) {|var...| block } => obj
+ * mod.class_exec(arg...) {|var...| block } => obj
+ *
+ * Evaluates the given block in the context of the class/module.
+ * The method defined in the block will belong to the receiver.
+ *
+ * class Thing
+ * end
+ * Thing.class_exec{
+ * def hello() "Hello there!" end
+ * }
+ * puts Thing.new.hello()
+ *
+ * <em>produces:</em>
+ *
+ * Hello there!
+ */
+
+VALUE
+rb_mod_module_exec(argc, argv, mod)
+ int argc;
+ VALUE *argv;
+ VALUE mod;
+{
+ return yield_under(mod, mod, rb_ary_new4(argc, argv));
+}
+
VALUE rb_load_path;
NORETURN(static void load_failed _((VALUE)));
@@ -6787,7 +7002,6 @@ rb_load(fname, wrap)
volatile VALUE self = ruby_top_self;
NODE *volatile last_node;
NODE *saved_cref = ruby_cref;
- TMP_PROTECT;
if (wrap && ruby_safe_level >= 4) {
StringValue(fname);
@@ -6805,7 +7019,7 @@ rb_load(fname, wrap)
ruby_errinfo = Qnil; /* ensure */
PUSH_VARS();
PUSH_CLASS(ruby_wrapper);
- ruby_cref = top_cref;
+ ruby_cref = ruby_top_cref;
if (!wrap) {
rb_secure(4); /* should alter global state */
ruby_class = rb_cObject;
@@ -6821,6 +7035,7 @@ rb_load(fname, wrap)
PUSH_ITER(ITER_NOT);
PUSH_FRAME();
ruby_frame->last_func = 0;
+ ruby_frame->orig_func = 0;
ruby_frame->last_class = 0;
ruby_frame->self = self;
PUSH_SCOPE();
@@ -6931,13 +7146,25 @@ static st_table *loading_tbl;
#define IS_DLEXT(e) (strcmp(e, DLEXT) == 0)
#endif
-static char *
-rb_feature_p(feature, ext, rb)
- const char *feature, *ext;
+
+static const char *const loadable_ext[] = {
+ ".rb", DLEXT,
+#ifdef DLEXT2
+ DLEXT2,
+#endif
+ 0
+};
+
+static int rb_feature_p _((const char **, const char *, int));
+static int search_required _((VALUE, VALUE *, VALUE *));
+
+static int
+rb_feature_p(ftptr, ext, rb)
+ const char **ftptr, *ext;
int rb;
{
VALUE v;
- char *f, *e;
+ const char *f, *e, *feature = *ftptr;
long i, len, elen;
if (ext) {
@@ -6948,51 +7175,68 @@ rb_feature_p(feature, ext, rb)
len = strlen(feature);
elen = 0;
}
- for (i = 0; i < RARRAY(rb_features)->len; ++i) {
- v = RARRAY(rb_features)->ptr[i];
+ for (i = 0; i < RARRAY_LEN(rb_features); ++i) {
+ v = RARRAY_PTR(rb_features)[i];
f = StringValuePtr(v);
- if (strncmp(f, feature, len) != 0) continue;
+ if (RSTRING_LEN(v) < len || strncmp(f, feature, len) != 0)
+ continue;
if (!*(e = f + len)) {
if (ext) continue;
- return e;
+ *ftptr = 0;
+ return 'u';
}
if (*e != '.') continue;
if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) {
- return e;
+ *ftptr = 0;
+ return 's';
}
if ((rb || !ext) && (strcmp(e, ".rb") == 0)) {
- return e;
+ *ftptr = 0;
+ return 'r';
+ }
+ }
+ if (loading_tbl) {
+ if (st_lookup(loading_tbl, (st_data_t)feature, (st_data_t *)ftptr)) {
+ if (!ext) return 'u';
+ return strcmp(ext, ".rb") ? 's' : 'r';
+ }
+ else {
+ char *buf;
+
+ if (ext && *ext) return 0;
+ buf = ALLOCA_N(char, len + DLEXT_MAXLEN + 1);
+ MEMCPY(buf, feature, char, len);
+ for (i = 0; (e = loadable_ext[i]) != 0; i++) {
+ strncpy(buf + len, e, DLEXT_MAXLEN + 1);
+ if (st_lookup(loading_tbl, (st_data_t)buf, (st_data_t *)ftptr)) {
+ return i ? 's' : 'r';
+ }
+ }
}
}
return 0;
}
-
-static const char *const loadable_ext[] = {
- ".rb", DLEXT,
-#ifdef DLEXT2
- DLEXT2,
-#endif
- 0
-};
+#define rb_feature_p(feature, ext, rb) rb_feature_p(&feature, ext, rb)
int
rb_provided(feature)
const char *feature;
{
- int i;
- char *buf;
+ const char *ext = strrchr(feature, '.');
- if (rb_feature_p(feature, 0, Qfalse))
- return Qtrue;
- if (!loading_tbl) return Qfalse;
- if (st_lookup(loading_tbl, (st_data_t)feature, 0)) return Qtrue;
- buf = ALLOCA_N(char, strlen(feature)+8);
- strcpy(buf, feature);
- for (i=0; ; i++) {
- if (!loadable_ext[i]) break;
- strcpy(buf+strlen(feature), loadable_ext[i]);
- if (st_lookup(loading_tbl, (st_data_t)buf, 0)) return Qtrue;
+ if (ext && !strchr(ext, '/')) {
+ if (strcmp(".rb", ext) == 0) {
+ if (rb_feature_p(feature, ext, Qtrue)) return Qtrue;
+ return Qfalse;
+ }
+ else if (IS_SOEXT(ext) || IS_DLEXT(ext)) {
+ if (rb_feature_p(feature, ext, Qfalse)) return Qtrue;
+ return Qfalse;
+ }
}
+ if (rb_feature_p(feature, feature + strlen(feature), Qtrue))
+ return Qtrue;
+
return Qfalse;
}
@@ -7010,19 +7254,42 @@ rb_provide(feature)
rb_provide_feature(rb_str_new2(feature));
}
-static int
-load_wait(ftptr)
- char *ftptr;
+static char *
+load_lock(ftptr)
+ const char *ftptr;
{
st_data_t th;
- if (!loading_tbl) return Qfalse;
- if (!st_lookup(loading_tbl, (st_data_t)ftptr, &th)) return Qfalse;
+ if (!loading_tbl ||
+ !st_lookup(loading_tbl, (st_data_t)ftptr, &th))
+ {
+ /* loading ruby library should be serialized. */
+ if (!loading_tbl) {
+ loading_tbl = st_init_strtable();
+ }
+ /* partial state */
+ ftptr = ruby_strdup(ftptr);
+ st_insert(loading_tbl, (st_data_t)ftptr, (st_data_t)curr_thread);
+ return (char *)ftptr;
+ }
do {
- if ((rb_thread_t)th == curr_thread) return Qtrue;
- CHECK_INTS;
+ rb_thread_t owner = (rb_thread_t)th;
+ if (owner == curr_thread) return 0;
+ rb_thread_join(owner->thread, -1.0);
} while (st_lookup(loading_tbl, (st_data_t)ftptr, &th));
- return Qtrue;
+ return 0;
+}
+
+static void
+load_unlock(const char *ftptr)
+{
+ if (ftptr) {
+ st_data_t key = (st_data_t)ftptr;
+
+ if (st_delete(loading_tbl, &key, 0)) {
+ free((char *)key);
+ }
+ }
}
/*
@@ -7059,21 +7326,31 @@ search_required(fname, featurep, path)
VALUE fname, *featurep, *path;
{
VALUE tmp;
- char *ext, *ftptr;
+ const char *ext, *ftptr;
int type;
+ if (*(ftptr = RSTRING_PTR(fname)) == '~') {
+ fname = rb_file_expand_path(fname, Qnil);
+ ftptr = RSTRING_PTR(fname);
+ }
*featurep = fname;
*path = 0;
- ext = strrchr(ftptr = RSTRING(fname)->ptr, '.');
+ ext = strrchr(ftptr, '.');
if (ext && !strchr(ext, '/')) {
if (strcmp(".rb", ext) == 0) {
- if (rb_feature_p(ftptr, ext, Qtrue)) return 'r';
- if (*path = rb_find_file(fname)) return 'r';
+ if (rb_feature_p(ftptr, ext, Qtrue)) {
+ if (ftptr) *path = rb_str_new2(ftptr);
+ return 'r';
+ }
+ if ((*path = rb_find_file(fname)) != 0) return 'r';
return 0;
}
else if (IS_SOEXT(ext)) {
- if (rb_feature_p(ftptr, ext, Qfalse)) return 's';
- tmp = rb_str_new(RSTRING(fname)->ptr, ext-RSTRING(fname)->ptr);
+ if (rb_feature_p(ftptr, ext, Qfalse)) {
+ if (ftptr) *path = rb_str_new2(ftptr);
+ return 's';
+ }
+ tmp = rb_str_new(RSTRING_PTR(fname), ext-RSTRING_PTR(fname));
*featurep = tmp;
#ifdef DLEXT2
OBJ_FREEZE(tmp);
@@ -7085,30 +7362,34 @@ search_required(fname, featurep, path)
#else
rb_str_cat2(tmp, DLEXT);
OBJ_FREEZE(tmp);
- if (*path = rb_find_file(tmp)) {
+ if ((*path = rb_find_file(tmp)) != 0) {
return 's';
}
#endif
}
else if (IS_DLEXT(ext)) {
- if (rb_feature_p(ftptr, ext, Qfalse)) return 's';
- if (*path = rb_find_file(fname)) return 's';
+ if (rb_feature_p(ftptr, ext, Qfalse)) {
+ if (ftptr) *path = rb_str_new2(ftptr);
+ return 's';
+ }
+ if ((*path = rb_find_file(fname)) != 0) return 's';
}
}
tmp = fname;
- switch (type = rb_find_file_ext(&tmp, loadable_ext)) {
+ type = rb_find_file_ext(&tmp, loadable_ext);
+ *featurep = tmp;
+ switch (type) {
case 0:
- if ((ext = rb_feature_p(ftptr, 0, Qfalse))) {
- type = strcmp(".rb", ext);
- break;
- }
- return 0;
+ type = rb_feature_p(ftptr, 0, Qfalse);
+ if (type && ftptr) *path = rb_str_new2(ftptr);
+ return type;
default:
- *featurep = tmp;
ext = strrchr(ftptr = RSTRING(tmp)->ptr, '.');
- if (rb_feature_p(ftptr, ext, !--type)) break;
- *path = rb_find_file(tmp);
+ if (!rb_feature_p(ftptr, ext, !--type))
+ *path = rb_find_file(tmp);
+ else if (ftptr)
+ *path = rb_str_new2(ftptr);
}
return type ? 's' : 'r';
}
@@ -7153,20 +7434,13 @@ rb_require_safe(fname, safe)
ruby_safe_level = safe;
found = search_required(fname, &feature, &path);
if (found) {
- if (!path || load_wait(RSTRING(feature)->ptr)) {
+ if (!path || !(ftptr = load_lock(RSTRING_PTR(feature)))) {
result = Qfalse;
}
else {
ruby_safe_level = 0;
switch (found) {
case 'r':
- /* loading ruby library should be serialized. */
- if (!loading_tbl) {
- loading_tbl = st_init_strtable();
- }
- /* partial state */
- ftptr = ruby_strdup(RSTRING(feature)->ptr);
- st_insert(loading_tbl, (st_data_t)ftptr, (st_data_t)curr_thread);
rb_load(path, 0);
break;
@@ -7191,11 +7465,7 @@ rb_require_safe(fname, safe)
ruby_frame->last_func = saved.func;
SCOPE_SET(saved.vmode);
ruby_safe_level = saved.safe;
- if (ftptr) {
- if (st_delete(loading_tbl, (st_data_t *)&ftptr, 0)) { /* loading done */
- free(ftptr);
- }
- }
+ load_unlock(ftptr);
if (state) JUMP_TAG(state);
if (NIL_P(result)) {
load_failed(fname);
@@ -7214,6 +7484,24 @@ rb_require(fname)
return rb_require_safe(fn, ruby_safe_level);
}
+void
+ruby_init_ext(name, init)
+ const char *name;
+ void (*init) _((void));
+{
+ ruby_current_node = 0;
+ ruby_sourcefile = rb_source_filename(name);
+ ruby_sourceline = 0;
+ ruby_frame->last_func = 0;
+ ruby_frame->orig_func = 0;
+ SCOPE_SET(SCOPE_PUBLIC);
+ if (load_lock(name)) {
+ (*init)();
+ rb_provide(name);
+ load_unlock(name);
+ }
+}
+
static void
secure_visibility(self)
VALUE self;
@@ -7462,7 +7750,7 @@ rb_mod_modfunc(argc, argv, module)
body = search_method(rb_cObject, id, &m);
}
if (body == 0 || body->nd_body == 0) {
- rb_bug("undefined method `%s'; can't happen", rb_id2name(id));
+ print_undef(module, id);
}
if (nd_type(body->nd_body) != NODE_ZSUPER) {
break; /* normal case: need not to follow 'super' link */
@@ -7880,6 +8168,37 @@ rb_exec_end_proc()
ruby_safe_level = safe;
}
+/*
+ * call-seq:
+ * __method__ => symbol
+ *
+ * Returns the name of the current method as a Symbol.
+ * If called from inside of an aliased method it will return the original
+ * nonaliased name.
+ * If called outside of a method, it returns <code>nil</code>.
+ *
+ * def foo
+ * __method__
+ * end
+ * alias bar foo
+ *
+ * foo # => :foo
+ * bar # => :foo
+ *
+ */
+
+static VALUE
+rb_f_method_name()
+{
+ struct FRAME* prev = ruby_frame->prev;
+ if (prev && prev->orig_func) {
+ return ID2SYM(prev->orig_func);
+ }
+ else {
+ return Qnil;
+ }
+}
+
void
Init_eval()
{
@@ -7901,11 +8220,11 @@ Init_eval()
__id__ = rb_intern("__id__");
__send__ = rb_intern("__send__");
- rb_global_variable((VALUE*)&top_scope);
- rb_global_variable((VALUE*)&ruby_eval_tree_begin);
+ rb_global_variable((void *)&top_scope);
+ rb_global_variable((void *)&ruby_eval_tree_begin);
- rb_global_variable((VALUE*)&ruby_eval_tree);
- rb_global_variable((VALUE*)&ruby_dyna_vars);
+ rb_global_variable((void *)&ruby_eval_tree);
+ rb_global_variable((void *)&ruby_dyna_vars);
rb_define_virtual_variable("$@", errat_getter, errat_setter);
rb_define_hooked_variable("$!", &ruby_errinfo, 0, errinfo_setter);
@@ -7918,7 +8237,7 @@ Init_eval()
rb_define_method(rb_mKernel, "respond_to?", obj_respond_to, -1);
respond_to = rb_intern("respond_to?");
- rb_global_variable((VALUE*)&basic_respond_to);
+ rb_global_variable((void *)&basic_respond_to);
basic_respond_to = rb_method_node(rb_cObject, respond_to);
rb_define_global_function("raise", rb_f_raise, -1);
@@ -7936,9 +8255,12 @@ Init_eval()
rb_define_global_function("global_variables", rb_f_global_variables, 0); /* in variable.c */
rb_define_global_function("local_variables", rb_f_local_variables, 0);
+ rb_define_global_function("__method__", rb_f_method_name, 0);
+
rb_define_method(rb_mKernel, "send", rb_f_send, -1);
rb_define_method(rb_mKernel, "__send__", rb_f_send, -1);
rb_define_method(rb_mKernel, "instance_eval", rb_obj_instance_eval, -1);
+ rb_define_method(rb_mKernel, "instance_exec", rb_obj_instance_exec, -1);
rb_define_private_method(rb_cModule, "append_features", rb_mod_append_features, 1);
rb_define_private_method(rb_cModule, "extend_object", rb_mod_extend_object, 1);
@@ -7954,7 +8276,9 @@ Init_eval()
rb_define_method(rb_cModule, "public_class_method", rb_mod_public_method, -1);
rb_define_method(rb_cModule, "private_class_method", rb_mod_private_method, -1);
rb_define_method(rb_cModule, "module_eval", rb_mod_module_eval, -1);
+ rb_define_method(rb_cModule, "module_exec", rb_mod_module_exec, -1);
rb_define_method(rb_cModule, "class_eval", rb_mod_module_eval, -1);
+ rb_define_method(rb_cModule, "class_exec", rb_mod_module_exec, -1);
rb_undef_method(rb_cClass, "module_function");
@@ -8243,20 +8567,42 @@ proc_clone(self)
* MISSING: documentation
*/
+#define PROC_TSHIFT (FL_USHIFT+1)
+#define PROC_TMASK (FL_USER1|FL_USER2|FL_USER3)
+#define PROC_TMAX (PROC_TMASK >> PROC_TSHIFT)
+
+static int proc_get_safe_level(VALUE);
+
static VALUE
proc_dup(self)
VALUE self;
{
struct BLOCK *orig, *data;
VALUE bind;
+ int safe = proc_get_safe_level(self);
Data_Get_Struct(self, struct BLOCK, orig);
bind = Data_Make_Struct(rb_obj_class(self),struct BLOCK,blk_mark,blk_free,data);
blk_dup(data, orig);
+ if (safe > PROC_TMAX) safe = PROC_TMAX;
+ FL_SET(bind, (safe << PROC_TSHIFT) & PROC_TMASK);
return bind;
}
+VALUE
+rb_block_dup(self, klass, cref)
+ VALUE self, klass, cref;
+{
+ struct BLOCK *block;
+ VALUE obj = proc_dup(self);
+ Data_Get_Struct(obj, struct BLOCK, block);
+ block->klass = klass;
+ block->cref = NEW_NODE(nd_type(block->cref), cref, block->cref->u2.node,
+ block->cref->u3.node);
+ return obj;
+}
+
/*
* call-seq:
* binding -> a_binding
@@ -8314,9 +8660,34 @@ rb_f_binding(self)
return bind;
}
-#define PROC_TSHIFT (FL_USHIFT+1)
-#define PROC_TMASK (FL_USER1|FL_USER2|FL_USER3)
-#define PROC_TMAX (PROC_TMASK >> PROC_TSHIFT)
+/*
+ * call-seq:
+ * binding.eval(string [, filename [,lineno]]) => obj
+ *
+ * Evaluates the Ruby expression(s) in <em>string</em>, in the
+ * <em>binding</em>'s context. If the optional <em>filename</em> and
+ * <em>lineno</em> parameters are present, they will be used when
+ * reporting syntax errors.
+ *
+ * def getBinding(param)
+ * return binding
+ * end
+ * b = getBinding("hello")
+ * b.eval("param") #=> "hello"
+ */
+
+static VALUE
+bind_eval(argc, argv, bindval)
+ int argc;
+ VALUE *argv;
+ VALUE bindval;
+{
+ VALUE args[4];
+
+ rb_scan_args(argc, argv, "12", &args[0], &args[2], &args[3]);
+ args[1] = bindval;
+ return rb_f_eval(argc+1, args, Qnil /* self will be searched in eval */);
+}
#define SAFE_LEVEL_MAX PROC_TMASK
@@ -8479,13 +8850,12 @@ proc_invoke(proc, args, self, klass)
volatile VALUE old_wrapper = ruby_wrapper;
volatile int pcall, avalue = Qtrue;
volatile VALUE tmp = args;
+ VALUE bvar = Qnil;
if (rb_block_given_p() && ruby_frame->last_func) {
if (klass != ruby_frame->last_class)
klass = rb_obj_class(proc);
- rb_warning("block for %s#%s is useless",
- rb_class2name(klass),
- rb_id2name(ruby_frame->last_func));
+ bvar = rb_block_proc();
}
Data_Get_Struct(proc, struct BLOCK, data);
@@ -8501,6 +8871,7 @@ proc_invoke(proc, args, self, klass)
/* PUSH BLOCK from data */
old_block = ruby_block;
_block = *data;
+ _block.block_obj = bvar;
if (self != Qundef) _block.frame.self = self;
if (klass) _block.frame.last_class = klass;
_block.frame.argc = RARRAY(tmp)->len;
@@ -8510,7 +8881,7 @@ proc_invoke(proc, args, self, klass)
OBJSETUP(scope, tmp, T_SCOPE);
scope->local_tbl = _block.scope->local_tbl;
scope->local_vars = _block.scope->local_vars;
- scope->flags |= SCOPE_CLONE;
+ scope->flags |= SCOPE_CLONE | (_block.scope->flags & SCOPE_MALLOC);
_block.scope = scope;
}
/* modify current frame */
@@ -8521,7 +8892,8 @@ proc_invoke(proc, args, self, klass)
state = EXEC_TAG();
if (state == 0) {
proc_set_safe_level(proc);
- result = rb_yield_0(args, self, (self!=Qundef)?CLASS_OF(self):0, pcall, avalue);
+ result = rb_yield_0(args, self, (self!=Qundef)?CLASS_OF(self):0,
+ pcall | YIELD_PROC_CALL, avalue);
}
else if (TAG_DST()) {
result = prot_tag->retval;
@@ -8590,8 +8962,8 @@ proc_invoke(proc, args, self, klass)
* from prog.rb:5
*/
-static VALUE
-proc_call(proc, args)
+VALUE
+rb_proc_call(proc, args)
VALUE proc, args; /* OK */
{
return proc_invoke(proc, args, Qundef, 0);
@@ -8625,30 +8997,36 @@ proc_arity(proc)
VALUE proc;
{
struct BLOCK *data;
- NODE *list;
+ NODE *var, *list;
int n;
Data_Get_Struct(proc, struct BLOCK, data);
- if (data->var == 0) {
+ var = data->var;
+ if (var == 0) {
if (data->body && nd_type(data->body) == NODE_IFUNC &&
data->body->nd_cfnc == bmcall) {
return method_arity(data->body->nd_tval);
}
return INT2FIX(-1);
}
- if (data->var == (NODE*)1) return INT2FIX(0);
- if (data->var == (NODE*)2) return INT2FIX(0);
- switch (nd_type(data->var)) {
+ if (var == (NODE*)1) return INT2FIX(0);
+ if (var == (NODE*)2) return INT2FIX(0);
+ if (nd_type(var) == NODE_BLOCK_ARG) {
+ var = var->nd_args;
+ if (var == (NODE*)1) return INT2FIX(0);
+ if (var == (NODE*)2) return INT2FIX(0);
+ }
+ switch (nd_type(var)) {
default:
return INT2FIX(1);
case NODE_MASGN:
- list = data->var->nd_head;
+ list = var->nd_head;
n = 0;
while (list) {
n++;
list = list->nd_next;
}
- if (data->var->nd_args) return INT2FIX(-n-1);
+ if (var->nd_args) return INT2FIX(-n-1);
return INT2FIX(n);
}
}
@@ -8696,7 +9074,7 @@ proc_to_s(self)
{
struct BLOCK *data;
NODE *node;
- char *cname = rb_obj_classname(self);
+ const char *cname = rb_obj_classname(self);
const int w = (sizeof(VALUE) * CHAR_BIT) / 4;
long len = strlen(cname)+6+w; /* 6:tags 16:addr */
VALUE str;
@@ -8897,8 +9275,8 @@ mnew(klass, obj, id, mklass)
ID oid = id;
again:
- if ((body = rb_get_method_body(&klass, &id, &noex)) == 0) {
- print_undef(rklass, oid);
+ if ((body = rb_get_method_body(&klass, &oid, &noex)) == 0) {
+ print_undef(rklass, id);
}
if (nd_type(body) == NODE_ZSUPER) {
@@ -8910,6 +9288,7 @@ mnew(klass, obj, id, mklass)
(FL_TEST(rklass, FL_SINGLETON) || TYPE(rklass) == T_ICLASS)) {
rklass = RCLASS(rklass)->super;
}
+ if (TYPE(klass) == T_ICLASS) klass = RBASIC(klass)->klass;
method = Data_Make_Struct(mklass, struct METHOD, bm_mark, free, data);
data->klass = klass;
data->recv = obj;
@@ -9009,6 +9388,57 @@ method_unbind(obj)
/*
* call-seq:
+ * meth.receiver => object
+ *
+ * Returns the bound receiver of the method object.
+ */
+
+static VALUE
+method_receiver(obj)
+ VALUE obj;
+{
+ struct METHOD *data;
+
+ Data_Get_Struct(obj, struct METHOD, data);
+ return data->recv;
+}
+
+/*
+ * call-seq:
+ * meth.name => string
+ *
+ * Returns the name of the method.
+ */
+
+static VALUE
+method_name(obj)
+ VALUE obj;
+{
+ struct METHOD *data;
+
+ Data_Get_Struct(obj, struct METHOD, data);
+ return rb_str_new2(rb_id2name(data->id));
+}
+
+/*
+ * call-seq:
+ * meth.owner => class_or_module
+ *
+ * Returns the class or module that defines the method.
+ */
+
+static VALUE
+method_owner(obj)
+ VALUE obj;
+{
+ struct METHOD *data;
+
+ Data_Get_Struct(obj, struct METHOD, data);
+ return data->klass;
+}
+
+/*
+ * call-seq:
* obj.method(sym) => method
*
* Looks up the named method as a receiver in <i>obj</i>, returning a
@@ -9035,7 +9465,7 @@ method_unbind(obj)
* m.call #=> "Hello, @iv = Fred"
*/
-static VALUE
+VALUE
rb_obj_method(obj, vid)
VALUE obj;
VALUE vid;
@@ -9102,6 +9532,29 @@ method_clone(self)
return clone;
}
+VALUE
+rb_method_dup(self, klass, cref)
+ VALUE self;
+ VALUE klass;
+ VALUE cref;
+{
+ VALUE clone;
+ struct METHOD *orig, *data;
+
+ Data_Get_Struct(self, struct METHOD, orig);
+ clone = Data_Make_Struct(CLASS_OF(self),struct METHOD, bm_mark, free, data);
+ *data = *orig;
+ data->rklass = klass;
+ if (data->body->nd_rval) {
+ NODE *tmp = NEW_NODE(nd_type(data->body->u2.node), cref,
+ data->body->u2.node->u2.node,
+ data->body->u2.node->u3.node);
+ data->body = NEW_NODE(nd_type(data->body), data->body->u1.node, tmp,
+ data->body->u3.node);
+ }
+ return clone;
+}
+
/*
* call-seq:
* meth.call(args, ...) => obj
@@ -9355,7 +9808,7 @@ method_inspect(method)
struct METHOD *data;
VALUE str;
const char *s;
- char *sharp = "#";
+ const char *sharp = "#";
Data_Get_Struct(method, struct METHOD, data);
str = rb_str_buf_new2("#<");
@@ -9384,17 +9837,13 @@ method_inspect(method)
else {
rb_str_buf_cat2(str, rb_class2name(data->rklass));
if (data->rklass != data->klass) {
- VALUE klass = data -> klass;
- if (TYPE(klass) == T_ICLASS) {
- klass = RBASIC(klass)->klass;
- }
rb_str_buf_cat2(str, "(");
- rb_str_buf_cat2(str, rb_class2name(klass));
+ rb_str_buf_cat2(str, rb_class2name(data->klass));
rb_str_buf_cat2(str, ")");
}
}
rb_str_buf_cat2(str, sharp);
- rb_str_buf_cat2(str, rb_id2name(data->oid));
+ rb_str_buf_cat2(str, rb_id2name(data->id));
rb_str_buf_cat2(str, ">");
return str;
@@ -9438,7 +9887,8 @@ rb_proc_new(func, val)
VALUE proc = rb_iterate((VALUE(*)_((VALUE)))mproc, 0, func, val);
Data_Get_Struct(proc, struct BLOCK, data);
- data->body->nd_state = YIELD_FUNC_AVALUE;
+ data->body->nd_state = YIELD_FUNC_LAMBDA;
+ data->flags |= BLOCK_LAMBDA;
return proc;
}
@@ -9521,7 +9971,7 @@ rb_mod_define_method(argc, argv, mod)
VALUE mod;
{
ID id;
- VALUE body;
+ VALUE body, orig;
NODE *node;
int noex;
@@ -9540,6 +9990,7 @@ rb_mod_define_method(argc, argv, mod)
else {
rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc);
}
+ orig = body;
if (RDATA(body)->dmark == (RUBY_DATA_FUNC)bm_mark) {
node = NEW_DMETHOD(method_unbind(body));
}
@@ -9558,17 +10009,17 @@ rb_mod_define_method(argc, argv, mod)
rb_raise(rb_eTypeError, "wrong argument type (expected Proc/Method)");
}
- if (SCOPE_TEST(SCOPE_PRIVATE)) {
- noex = NOEX_PRIVATE;
- }
- else if (SCOPE_TEST(SCOPE_PROTECTED)) {
- noex = NOEX_PROTECTED;
- }
- else {
- noex = NOEX_PUBLIC;
+ noex = NOEX_PUBLIC;
+ if (ruby_cbase == mod) {
+ if (SCOPE_TEST(SCOPE_PRIVATE)) {
+ noex = NOEX_PRIVATE;
+ }
+ else if (SCOPE_TEST(SCOPE_PROTECTED)) {
+ noex = NOEX_PROTECTED;
+ }
}
rb_add_method(mod, id, node, noex);
- return body;
+ return orig;
}
/*
@@ -9597,12 +10048,17 @@ Init_Proc()
rb_define_method(rb_eLocalJumpError, "reason", localjump_reason, 0);
rb_global_variable(&exception_error);
- exception_error = rb_exc_new2(rb_eFatal, "exception reentered");
+ exception_error = rb_exc_new3(rb_eFatal,
+ rb_obj_freeze(rb_str_new2("exception reentered")));
+ OBJ_TAINT(exception_error);
+ OBJ_FREEZE(exception_error);
rb_eSysStackError = rb_define_class("SystemStackError", rb_eStandardError);
rb_global_variable(&sysstack_error);
- sysstack_error = rb_exc_new2(rb_eSysStackError, "stack level too deep");
+ sysstack_error = rb_exc_new3(rb_eSysStackError,
+ rb_obj_freeze(rb_str_new2("stack level too deep")));
OBJ_TAINT(sysstack_error);
+ OBJ_FREEZE(sysstack_error);
rb_cProc = rb_define_class("Proc", rb_cObject);
rb_undef_alloc_func(rb_cProc);
@@ -9610,9 +10066,9 @@ Init_Proc()
rb_define_method(rb_cProc, "clone", proc_clone, 0);
rb_define_method(rb_cProc, "dup", proc_dup, 0);
- rb_define_method(rb_cProc, "call", proc_call, -2);
+ rb_define_method(rb_cProc, "call", rb_proc_call, -2);
rb_define_method(rb_cProc, "arity", proc_arity, 0);
- rb_define_method(rb_cProc, "[]", proc_call, -2);
+ rb_define_method(rb_cProc, "[]", rb_proc_call, -2);
rb_define_method(rb_cProc, "==", proc_eq, 1);
rb_define_method(rb_cProc, "to_s", proc_to_s, 0);
rb_define_method(rb_cProc, "to_proc", proc_to_self, 0);
@@ -9632,6 +10088,9 @@ Init_Proc()
rb_define_method(rb_cMethod, "inspect", method_inspect, 0);
rb_define_method(rb_cMethod, "to_s", method_inspect, 0);
rb_define_method(rb_cMethod, "to_proc", method_proc, 0);
+ rb_define_method(rb_cMethod, "receiver", method_receiver, 0);
+ rb_define_method(rb_cMethod, "name", method_name, 0);
+ rb_define_method(rb_cMethod, "owner", method_owner, 0);
rb_define_method(rb_cMethod, "unbind", method_unbind, 0);
rb_define_method(rb_mKernel, "method", rb_obj_method, 1);
@@ -9643,6 +10102,8 @@ Init_Proc()
rb_define_method(rb_cUnboundMethod, "arity", method_arity, 0);
rb_define_method(rb_cUnboundMethod, "inspect", method_inspect, 0);
rb_define_method(rb_cUnboundMethod, "to_s", method_inspect, 0);
+ rb_define_method(rb_cUnboundMethod, "name", method_name, 0);
+ rb_define_method(rb_cUnboundMethod, "owner", method_owner, 0);
rb_define_method(rb_cUnboundMethod, "bind", umethod_bind, 1);
rb_define_method(rb_cModule, "instance_method", rb_mod_method, 1);
}
@@ -9690,22 +10151,10 @@ Init_Binding()
rb_undef_method(CLASS_OF(rb_cBinding), "new");
rb_define_method(rb_cBinding, "clone", proc_clone, 0);
rb_define_method(rb_cBinding, "dup", proc_dup, 0);
+ rb_define_method(rb_cBinding, "eval", bind_eval, -1);
rb_define_global_function("binding", rb_f_binding, 0);
}
-#ifdef __ia64__
-#if defined(__FreeBSD__)
-/*
- * FreeBSD/ia64 currently does not have a way for a process to get the
- * base address for the RSE backing store, so hardcode it.
- */
-#define __libc_ia64_register_backing_store_base (4ULL<<61)
-#else
-#pragma weak __libc_ia64_register_backing_store_base
-extern unsigned long __libc_ia64_register_backing_store_base;
-#endif
-#endif
-
/* Windows SEH refers data on the stack. */
#undef SAVE_WIN32_EXCEPTION_LIST
#if defined _WIN32 || defined __CYGWIN__
@@ -9770,18 +10219,12 @@ VALUE rb_cThread;
extern VALUE rb_last_status;
-enum thread_status {
- THREAD_TO_KILL,
- THREAD_RUNNABLE,
- THREAD_STOPPED,
- THREAD_KILLED,
-};
-
#define WAIT_FD (1<<0)
#define WAIT_SELECT (1<<1)
#define WAIT_TIME (1<<2)
#define WAIT_JOIN (1<<3)
#define WAIT_PID (1<<4)
+#define WAIT_DONE (1<<5)
/* +infty, for this purpose */
#define DELAY_INFTY 1E30
@@ -9794,70 +10237,9 @@ enum thread_status {
# endif
#endif
-/* typedef struct thread * rb_thread_t; */
-
-struct thread {
- struct thread *next, *prev;
- rb_jmpbuf_t context;
-#ifdef SAVE_WIN32_EXCEPTION_LIST
- DWORD win32_exception_list;
-#endif
-
- VALUE result;
-
- long stk_len;
- long stk_max;
- VALUE *stk_ptr;
- VALUE *stk_pos;
-#ifdef __ia64__
- VALUE *bstr_ptr;
- long bstr_len;
-#endif
-
- struct FRAME *frame;
- struct SCOPE *scope;
- struct RVarmap *dyna_vars;
- struct BLOCK *block;
- struct iter *iter;
- struct tag *tag;
- VALUE klass;
- VALUE wrapper;
- NODE *cref;
-
- int flags; /* misc. states (vmode/rb_trap_immediate/raised) */
-
- NODE *node;
-
- int tracing;
- VALUE errinfo;
- VALUE last_status;
- VALUE last_line;
- VALUE last_match;
-
- int safe;
-
- enum thread_status status;
- int wait_for;
- int fd;
- fd_set readfds;
- fd_set writefds;
- fd_set exceptfds;
- int select_value;
- double delay;
- rb_thread_t join;
-
- int abort;
- int priority;
- VALUE thgroup;
-
- st_table *locals;
-
- VALUE thread;
-};
-
-#define THREAD_RAISED 0x200 /* temporary flag */
#define THREAD_TERMINATING 0x400 /* persistent flag */
-#define THREAD_FLAGS_MASK 0x400 /* mask for persistent flags */
+#define THREAD_NO_ENSURE 0x800 /* persistent flag */
+#define THREAD_FLAGS_MASK 0xfc00 /* mask for persistent flags */
#define FOREACH_THREAD_FROM(f,x) x = f; do { x = x->next;
#define END_FOREACH_FROM(f,x) } while (x != f)
@@ -9876,7 +10258,7 @@ struct thread_status_t {
int safe;
- enum thread_status status;
+ enum rb_thread_status status;
int wait_for;
int fd;
fd_set readfds;
@@ -9909,22 +10291,34 @@ struct thread_status_t {
(dst)->join = (src)->join, \
0)
-static int
-thread_set_raised()
+int
+rb_thread_set_raised(th)
+ rb_thread_t th;
{
- if (curr_thread->flags & THREAD_RAISED) return 1;
- curr_thread->flags |= THREAD_RAISED;
+ if (th->flags & RAISED_EXCEPTION) {
+ return 1;
+ }
+ th->flags |= RAISED_EXCEPTION;
return 0;
}
-static int
-thread_reset_raised()
+int
+rb_thread_reset_raised(th)
+ rb_thread_t th;
{
- if (!(curr_thread->flags & THREAD_RAISED)) return 0;
- curr_thread->flags &= ~THREAD_RAISED;
+ if (!(th->flags & RAISED_EXCEPTION)) {
+ return 0;
+ }
+ th->flags &= ~RAISED_EXCEPTION;
return 1;
}
+static int
+thread_no_ensure()
+{
+ return ((curr_thread->flags & THREAD_NO_ENSURE) == THREAD_NO_ENSURE);
+}
+
static void rb_thread_ready _((rb_thread_t));
static VALUE run_trap_eval _((VALUE));
@@ -9972,7 +10366,7 @@ rb_trap_eval(cmd, sig, safe)
static const char *
thread_status_name(status)
- enum thread_status status;
+ enum rb_thread_status status;
{
switch (status) {
case THREAD_RUNNABLE:
@@ -10026,6 +10420,13 @@ static double
timeofday()
{
struct timeval tv;
+#ifdef CLOCK_MONOTONIC
+ struct timespec tp;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
+ return (double)tp.tv_sec + (double)tp.tv_nsec * 1e-9;
+ }
+#endif
gettimeofday(&tv, NULL);
return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6;
}
@@ -10055,6 +10456,7 @@ thread_mark(th)
rb_gc_mark(th->last_match);
rb_mark_tbl(th->locals);
rb_gc_mark(th->thgroup);
+ rb_gc_mark_maybe(th->sandbox);
/* mark data in copied stack */
if (th == curr_thread) return;
@@ -10065,9 +10467,9 @@ thread_mark(th)
#if defined(THINK_C) || defined(__human68k__)
rb_gc_mark_locations(th->stk_ptr+2, th->stk_ptr+th->stk_len+2);
#endif
-#ifdef __ia64__
+#ifdef __ia64
if (th->bstr_ptr) {
- rb_gc_mark_locations(th->bstr_ptr, th->bstr_ptr+th->bstr_len);
+ rb_gc_mark_locations(th->bstr_ptr, th->bstr_ptr+th->bstr_len);
}
#endif
}
@@ -10147,16 +10549,23 @@ rb_gc_abort_threads()
} END_FOREACH_FROM(main_thread, th);
}
-static void
-thread_free(th)
+static inline void
+stack_free(th)
rb_thread_t th;
{
if (th->stk_ptr) free(th->stk_ptr);
th->stk_ptr = 0;
-#ifdef __ia64__
+#ifdef __ia64
if (th->bstr_ptr) free(th->bstr_ptr);
th->bstr_ptr = 0;
#endif
+}
+
+static void
+thread_free(th)
+ rb_thread_t th;
+{
+ stack_free(th);
if (th->locals) st_free_table(th->locals);
if (th->status != THREAD_KILLED) {
if (th->prev) th->prev->next = th->next;
@@ -10182,7 +10591,6 @@ static VALUE th_raise_exception;
static NODE *th_raise_node;
static VALUE th_cmd;
static int th_sig, th_safe;
-static char *th_signm;
#define RESTORE_NORMAL 1
#define RESTORE_FATAL 2
@@ -10193,13 +10601,16 @@ static char *th_signm;
#define RESTORE_EXIT 7
extern VALUE *rb_gc_stack_start;
+#ifdef __ia64
+extern VALUE *rb_gc_register_stack_start;
+#endif
static void
rb_thread_save_context(th)
rb_thread_t th;
{
VALUE *pos;
- int len;
+ size_t len;
static VALUE tval;
len = ruby_stack_length(&pos);
@@ -10214,22 +10625,19 @@ rb_thread_save_context(th)
th->stk_len = len;
FLUSH_REGISTER_WINDOWS;
MEMCPY(th->stk_ptr, th->stk_pos, VALUE, th->stk_len);
-#ifdef __ia64__
- {
- ucontext_t ctx;
- VALUE *top, *bot;
-
- getcontext(&ctx);
- bot = (VALUE*)__libc_ia64_register_backing_store_base;
-#if defined(__FreeBSD__)
- top = (VALUE*)ctx.uc_mcontext.mc_special.bspstore;
-#else
- top = (VALUE*)ctx.uc_mcontext.sc_ar_bsp;
-#endif
- th->bstr_len = top - bot;
- REALLOC_N(th->bstr_ptr, VALUE, th->bstr_len);
- MEMCPY(th->bstr_ptr, (VALUE*)__libc_ia64_register_backing_store_base, VALUE, th->bstr_len);
- }
+#ifdef __ia64
+ th->bstr_pos = rb_gc_register_stack_start;
+ len = (VALUE*)rb_ia64_bsp() - th->bstr_pos;
+ th->bstr_len = 0;
+ if (len > th->bstr_max) {
+ VALUE *ptr = realloc(th->bstr_ptr, sizeof(VALUE) * len);
+ if (!ptr) rb_memerror();
+ th->bstr_ptr = ptr;
+ th->bstr_max = len;
+ }
+ th->bstr_len = len;
+ rb_ia64_flushrs();
+ MEMCPY(th->bstr_ptr, th->bstr_pos, VALUE, th->bstr_len);
#endif
#ifdef SAVE_WIN32_EXCEPTION_LIST
th->win32_exception_list = win32_get_exception_list();
@@ -10259,6 +10667,9 @@ rb_thread_save_context(th)
th->safe = ruby_safe_level;
th->node = ruby_current_node;
+ if (ruby_sandbox_save != NULL) {
+ ruby_sandbox_save(th);
+ }
}
static int
@@ -10284,7 +10695,7 @@ rb_thread_switch(n)
rb_raise_jump(th_raise_exception);
break;
case RESTORE_SIGNAL:
- rb_raise(rb_eSignal, "SIG%s", th_signm);
+ rb_thread_signal_raise(th_sig);
break;
case RESTORE_EXIT:
ruby_errinfo = th_raise_exception;
@@ -10302,53 +10713,23 @@ rb_thread_switch(n)
}
#define THREAD_SAVE_CONTEXT(th) \
- (rb_thread_save_context(th),\
- rb_thread_switch((FLUSH_REGISTER_WINDOWS, ruby_setjmp((th)->context))))
+ (rb_thread_switch(ruby_setjmp(rb_thread_save_context(th), (th)->context)))
NORETURN(static void rb_thread_restore_context _((rb_thread_t,int)));
+NORETURN(NOINLINE(static void rb_thread_restore_context_0(rb_thread_t,int)));
+NORETURN(NOINLINE(static void stack_extend(rb_thread_t, int)));
-# if defined(_MSC_VER) && _MSC_VER >= 1300
-__declspec(noinline) static void stack_extend(rb_thread_t, int);
-# endif
static void
-stack_extend(th, exit)
- rb_thread_t th;
- int exit;
+rb_thread_restore_context_0(rb_thread_t th, int exit)
{
- VALUE space[1024];
-
- memset(space, 0, 1); /* prevent array from optimization */
- rb_thread_restore_context(th, exit);
-}
-
-static void
-rb_thread_restore_context(th, exit)
- rb_thread_t th;
- int exit;
-{
- VALUE v;
static rb_thread_t tmp;
static int ex;
static VALUE tval;
- if (!th->stk_ptr) rb_bug("unsaved context");
-
-#if STACK_GROW_DIRECTION < 0
- if (&v > th->stk_pos) stack_extend(th, exit);
-#elif STACK_GROW_DIRECTION > 0
- if (&v < th->stk_pos + th->stk_len) stack_extend(th, exit);
-#else
- if (&v < rb_gc_stack_start) {
- /* Stack grows downward */
- if (&v > th->stk_pos) stack_extend(th, exit);
- }
- else {
- /* Stack grows upward */
- if (&v < th->stk_pos + th->stk_len) stack_extend(th, exit);
- }
-#endif
-
rb_trap_immediate = 0; /* inhibit interrupts from here */
+ if (ruby_sandbox_restore != NULL) {
+ ruby_sandbox_restore(th);
+ }
ruby_frame = th->frame;
ruby_scope = th->scope;
ruby_class = th->klass;
@@ -10373,8 +10754,8 @@ rb_thread_restore_context(th, exit)
ex = exit;
FLUSH_REGISTER_WINDOWS;
MEMCPY(tmp->stk_pos, tmp->stk_ptr, VALUE, tmp->stk_len);
-#ifdef __ia64__
- MEMCPY((VALUE*)__libc_ia64_register_backing_store_base, tmp->bstr_ptr, VALUE, tmp->bstr_len);
+#ifdef __ia64
+ MEMCPY(tmp->bstr_pos, tmp->bstr_ptr, VALUE, tmp->bstr_len);
#endif
tval = rb_lastline_get();
@@ -10387,6 +10768,89 @@ rb_thread_restore_context(th, exit)
ruby_longjmp(tmp->context, ex);
}
+#ifdef __ia64
+#define C(a) rse_##a##0, rse_##a##1, rse_##a##2, rse_##a##3, rse_##a##4
+#define E(a) rse_##a##0= rse_##a##1= rse_##a##2= rse_##a##3= rse_##a##4
+static volatile int C(a), C(b), C(c), C(d), C(e);
+static volatile int C(f), C(g), C(h), C(i), C(j);
+static volatile int C(k), C(l), C(m), C(n), C(o);
+static volatile int C(p), C(q), C(r), C(s), C(t);
+int rb_dummy_false = 0;
+NORETURN(NOINLINE(static void register_stack_extend(rb_thread_t, int, VALUE *)));
+static void
+register_stack_extend(rb_thread_t th, int exit, VALUE *curr_bsp)
+{
+ if (rb_dummy_false) {
+ /* use registers as much as possible */
+ E(a) = E(b) = E(c) = E(d) = E(e) =
+ E(f) = E(g) = E(h) = E(i) = E(j) =
+ E(k) = E(l) = E(m) = E(n) = E(o) =
+ E(p) = E(q) = E(r) = E(s) = E(t) = 0;
+ E(a) = E(b) = E(c) = E(d) = E(e) =
+ E(f) = E(g) = E(h) = E(i) = E(j) =
+ E(k) = E(l) = E(m) = E(n) = E(o) =
+ E(p) = E(q) = E(r) = E(s) = E(t) = 0;
+ }
+ if (curr_bsp < th->bstr_pos+th->bstr_len) {
+ register_stack_extend(th, exit, (VALUE*)rb_ia64_bsp());
+ }
+ stack_extend(th, exit);
+}
+#undef C
+#undef E
+#endif
+
+static void
+stack_extend(rb_thread_t th, int exit)
+{
+#define STACK_PAD_SIZE 1024
+ volatile VALUE space[STACK_PAD_SIZE], *sp = space;
+
+#if !STACK_GROW_DIRECTION
+ if (space < rb_gc_stack_start) {
+ /* Stack grows downward */
+#endif
+#if STACK_GROW_DIRECTION <= 0
+ if (space > th->stk_pos) {
+# ifdef HAVE_ALLOCA
+ sp = ALLOCA_N(VALUE, &space[0] - th->stk_pos);
+# else
+ stack_extend(th, exit);
+# endif
+ }
+#endif
+#if !STACK_GROW_DIRECTION
+ }
+ else {
+ /* Stack grows upward */
+#endif
+#if STACK_GROW_DIRECTION >= 0
+ if (&space[STACK_PAD_SIZE] < th->stk_pos + th->stk_len) {
+# ifdef HAVE_ALLOCA
+ sp = ALLOCA_N(VALUE, th->stk_pos + th->stk_len - &space[STACK_PAD_SIZE]);
+# else
+ stack_extend(th, exit);
+# endif
+ }
+#endif
+#if !STACK_GROW_DIRECTION
+ }
+#endif
+ rb_thread_restore_context_0(th, exit);
+}
+#ifdef __ia64
+#define stack_extend(th, exit) register_stack_extend(th, exit, (VALUE*)rb_ia64_bsp())
+#endif
+
+static void
+rb_thread_restore_context(th, exit)
+ rb_thread_t th;
+ int exit;
+{
+ if (!th->stk_ptr) rb_bug("unsaved context");
+ stack_extend(th, exit);
+}
+
static void
rb_thread_ready(th)
rb_thread_t th;
@@ -10403,8 +10867,7 @@ rb_thread_die(th)
{
th->thgroup = 0;
th->status = THREAD_KILLED;
- if (th->stk_ptr) free(th->stk_ptr);
- th->stk_ptr = 0;
+ stack_free(th);
}
static void
@@ -10417,6 +10880,13 @@ rb_thread_remove(th)
rb_thread_die(th);
th->prev->next = th->next;
th->next->prev = th->prev;
+
+#if defined(_THREAD_SAFE) || defined(HAVE_SETITIMER)
+ /* if this is the last ruby thread, stop timer signals */
+ if (th->next == th->prev && th->next == main_thread) {
+ rb_thread_stop_timer();
+ }
+#endif
}
static int
@@ -10564,6 +11034,7 @@ rb_thread_schedule()
}
#endif
rb_thread_pending = 0;
+ rb_gc_finalize_deferred();
if (curr_thread == curr_thread->next
&& curr_thread->status == THREAD_RUNNABLE)
return;
@@ -10584,6 +11055,7 @@ rb_thread_schedule()
now = -1.0;
FOREACH_THREAD_FROM(curr, th) {
+ th->wait_for &= ~WAIT_DONE;
if (!found && th->status <= THREAD_RUNNABLE) {
found = 1;
}
@@ -10616,7 +11088,12 @@ rb_thread_schedule()
if (now < 0.0) now = timeofday();
th_delay = th->delay - now;
if (th_delay <= 0.0) {
- th->status = THREAD_RUNNABLE;
+ if (th->wait_for & WAIT_SELECT) {
+ need_select = 1;
+ }
+ else {
+ th->status = THREAD_RUNNABLE;
+ }
found = 1;
}
else if (th_delay < delay) {
@@ -10657,20 +11134,64 @@ rb_thread_schedule()
#ifdef ERESTART
if (e == ERESTART) goto again;
#endif
- FOREACH_THREAD_FROM(curr, th) {
- if (th->wait_for & WAIT_SELECT) {
- int v = 0;
-
- v |= find_bad_fds(&readfds, &th->readfds, th->fd);
- v |= find_bad_fds(&writefds, &th->writefds, th->fd);
- v |= find_bad_fds(&exceptfds, &th->exceptfds, th->fd);
- if (v) {
- th->select_value = n;
- n = max;
- }
- }
- }
- END_FOREACH_FROM(curr, th);
+ if (e == EBADF) {
+ int badfd = -1;
+ int fd;
+ int dummy;
+ for (fd = 0; fd <= max; fd++) {
+ if ((FD_ISSET(fd, &readfds) ||
+ FD_ISSET(fd, &writefds) ||
+ FD_ISSET(fd, &exceptfds)) &&
+#ifndef _WIN32
+ fcntl(fd, F_GETFD, &dummy) == -1 &&
+#else
+ rb_w32_get_osfhandle(fd) == -1 &&
+#endif
+ errno == EBADF) {
+ badfd = fd;
+ break;
+ }
+ }
+ if (badfd != -1) {
+ FOREACH_THREAD_FROM(curr, th) {
+ if (th->wait_for & WAIT_FD) {
+ if (th->fd == badfd) {
+ found = 1;
+ th->status = THREAD_RUNNABLE;
+ th->fd = 0;
+ break;
+ }
+ }
+ if (th->wait_for & WAIT_SELECT) {
+ if (FD_ISSET(badfd, &th->readfds) ||
+ FD_ISSET(badfd, &th->writefds) ||
+ FD_ISSET(badfd, &th->exceptfds)) {
+ found = 1;
+ th->status = THREAD_RUNNABLE;
+ th->select_value = -EBADF;
+ break;
+ }
+ }
+ }
+ END_FOREACH_FROM(curr, th);
+ }
+ }
+ else {
+ FOREACH_THREAD_FROM(curr, th) {
+ if (th->wait_for & WAIT_SELECT) {
+ int v = 0;
+
+ v |= find_bad_fds(&readfds, &th->readfds, th->fd);
+ v |= find_bad_fds(&writefds, &th->writefds, th->fd);
+ v |= find_bad_fds(&exceptfds, &th->exceptfds, th->fd);
+ if (v) {
+ th->select_value = n;
+ n = max;
+ }
+ }
+ }
+ END_FOREACH_FROM(curr, th);
+ }
}
if (select_timeout && n == 0) {
if (now < 0.0) now = timeofday();
@@ -10691,28 +11212,22 @@ rb_thread_schedule()
if (n > 0) {
now = -1.0;
/* Some descriptors are ready.
- Make the corresponding threads runnable. */
+ * The corresponding threads are runnable as next.
+ * Mark them with WAIT_DONE.
+ * Don't change the status to runnable here because
+ * threads which don't run next should not be changed.
+ */
FOREACH_THREAD_FROM(curr, th) {
if ((th->wait_for&WAIT_FD) && FD_ISSET(th->fd, &readfds)) {
- /* Wake up only one thread per fd. */
- FD_CLR(th->fd, &readfds);
- th->status = THREAD_RUNNABLE;
- th->fd = 0;
- th->wait_for = 0;
+ th->wait_for |= WAIT_DONE;
found = 1;
}
if ((th->wait_for&WAIT_SELECT) &&
(match_fds(&readfds, &th->readfds, max) ||
match_fds(&writefds, &th->writefds, max) ||
match_fds(&exceptfds, &th->exceptfds, max))) {
- /* Wake up only one thread per fd. */
- th->status = THREAD_RUNNABLE;
- th->wait_for = 0;
- n = intersect_fds(&readfds, &th->readfds, max) +
- intersect_fds(&writefds, &th->writefds, max) +
- intersect_fds(&exceptfds, &th->exceptfds, max);
- th->select_value = n;
- found = 1;
+ th->wait_for |= WAIT_DONE;
+ found = 1;
}
}
END_FOREACH_FROM(curr, th);
@@ -10728,13 +11243,28 @@ rb_thread_schedule()
next = th;
break;
}
- if (th->status == THREAD_RUNNABLE && th->stk_ptr) {
- if (!next || next->priority < th->priority)
- next = th;
+ if ((th->status == THREAD_RUNNABLE || (th->wait_for & WAIT_DONE)) && th->stk_ptr) {
+ if (!next || next->priority < th->priority) {
+ next = th;
+ }
}
}
END_FOREACH_FROM(curr, th);
+ if (next && (next->wait_for & WAIT_DONE)) {
+ next->status = THREAD_RUNNABLE;
+ if (next->wait_for&WAIT_FD) {
+ next->fd = 0;
+ }
+ else { /* next->wait_for&WAIT_SELECT */
+ n = intersect_fds(&readfds, &next->readfds, max) +
+ intersect_fds(&writefds, &next->writefds, max) +
+ intersect_fds(&exceptfds, &next->exceptfds, max);
+ next->select_value = n;
+ }
+ next->wait_for = 0;
+ }
+
if (!next) {
/* raise fatal error to main thread */
curr_thread->node = ruby_current_node;
@@ -10744,15 +11274,16 @@ rb_thread_schedule()
TRAP_END;
}
FOREACH_THREAD_FROM(curr, th) {
+ int wait_for = th->wait_for & ~WAIT_DONE;
warn_printf("deadlock 0x%lx: %s:",
th->thread, thread_status_name(th->status));
- if (th->wait_for & WAIT_FD) warn_printf("F(%d)", th->fd);
- if (th->wait_for & WAIT_SELECT) warn_printf("S");
- if (th->wait_for & WAIT_TIME) warn_printf("T(%f)", th->delay);
- if (th->wait_for & WAIT_JOIN)
+ if (wait_for & WAIT_FD) warn_printf("F(%d)", th->fd);
+ if (wait_for & WAIT_SELECT) warn_printf("S");
+ if (wait_for & WAIT_TIME) warn_printf("T(%f)", th->delay);
+ if (wait_for & WAIT_JOIN)
warn_printf("J(0x%lx)", th->join ? th->join->thread : 0);
- if (th->wait_for & WAIT_PID) warn_printf("P");
- if (!th->wait_for) warn_printf("-");
+ if (wait_for & WAIT_PID) warn_printf("P");
+ if (!wait_for) warn_printf("-");
warn_printf(" %s - %s:%d\n",
th==main_thread ? "(main)" : "",
th->node->nd_file, nd_line(th->node));
@@ -10973,17 +11504,22 @@ rb_thread_select(max, read, write, except, timeout)
if (read) *read = curr_thread->readfds;
if (write) *write = curr_thread->writefds;
if (except) *except = curr_thread->exceptfds;
+ if (curr_thread->select_value < 0) {
+ errno = -curr_thread->select_value;
+ return -1;
+ }
return curr_thread->select_value;
}
-static int rb_thread_join _((rb_thread_t, double));
+static int rb_thread_join0 _((rb_thread_t, double));
+int rb_thread_join _((VALUE, double));
static int
-rb_thread_join(th, limit)
+rb_thread_join0(th, limit)
rb_thread_t th;
double limit;
{
- enum thread_status last_status = THREAD_RUNNABLE;
+ enum rb_thread_status last_status = THREAD_RUNNABLE;
if (rb_thread_critical) rb_thread_deadlock();
if (!rb_thread_dead(th)) {
@@ -11006,7 +11542,7 @@ rb_thread_join(th, limit)
if (!rb_thread_dead(th)) return Qfalse;
}
- if (!NIL_P(th->errinfo) && (th->flags & THREAD_RAISED)) {
+ if (!NIL_P(th->errinfo) && (th->flags & RAISED_EXCEPTION)) {
VALUE oldbt = get_backtrace(th->errinfo);
VALUE errat = make_backtrace();
VALUE errinfo = rb_obj_dup(th->errinfo);
@@ -11021,6 +11557,15 @@ rb_thread_join(th, limit)
return Qtrue;
}
+int
+rb_thread_join(thread, limit)
+ VALUE thread;
+ double limit;
+{
+ if (limit < 0) limit = DELAY_INFTY;
+ return rb_thread_join0(rb_thread_check(thread), limit);
+}
+
/*
* call-seq:
@@ -11070,11 +11615,10 @@ rb_thread_join_m(argc, argv, thread)
{
VALUE limit;
double delay = DELAY_INFTY;
- rb_thread_t th = rb_thread_check(thread);
rb_scan_args(argc, argv, "01", &limit);
if (!NIL_P(limit)) delay = rb_num2dbl(limit);
- if (!rb_thread_join(th, delay))
+ if (!rb_thread_join0(rb_thread_check(thread), delay))
return Qnil;
return thread;
}
@@ -11173,10 +11717,19 @@ VALUE
rb_thread_wakeup(thread)
VALUE thread;
{
+ if (!RTEST(rb_thread_wakeup_alive(thread)))
+ rb_raise(rb_eThreadError, "killed thread");
+ return thread;
+}
+
+VALUE
+rb_thread_wakeup_alive(thread)
+ VALUE thread;
+{
rb_thread_t th = rb_thread_check(thread);
if (th->status == THREAD_KILLED)
- rb_raise(rb_eThreadError, "killed thread");
+ return Qnil;
rb_thread_ready(th);
return thread;
@@ -11214,16 +11767,34 @@ rb_thread_run(thread)
}
+static void
+rb_kill_thread(th, flags)
+ rb_thread_t th;
+ int flags;
+{
+ if (th != curr_thread && th->safe < 4) {
+ rb_secure(4);
+ }
+ if (th->status == THREAD_TO_KILL || th->status == THREAD_KILLED)
+ return;
+ if (th == th->next || th == main_thread) rb_exit(EXIT_SUCCESS);
+
+ rb_thread_ready(th);
+ th->flags |= flags;
+ th->status = THREAD_TO_KILL;
+ if (!rb_thread_critical) rb_thread_schedule();
+}
+
+
/*
* call-seq:
- * thr.exit => thr or nil
- * thr.kill => thr or nil
- * thr.terminate => thr or nil
+ * thr.exit => thr
+ * thr.kill => thr
+ * thr.terminate => thr
*
- * Terminates <i>thr</i> and schedules another thread to be run. If this thread
- * is already marked to be killed, <code>exit</code> returns the
- * <code>Thread</code>. If this is the main thread, or the last thread, exits
- * the process.
+ * Terminates <i>thr</i> and schedules another thread to be run, returning
+ * the terminated <code>Thread</code>. If this is the main thread, or the
+ * last thread, exits the process.
*/
VALUE
@@ -11232,22 +11803,35 @@ rb_thread_kill(thread)
{
rb_thread_t th = rb_thread_check(thread);
- if (th != curr_thread && th->safe < 4) {
- rb_secure(4);
- }
- if (th->status == THREAD_TO_KILL || th->status == THREAD_KILLED)
- return thread;
- if (th == th->next || th == main_thread) rb_exit(EXIT_SUCCESS);
-
- rb_thread_ready(th);
- th->status = THREAD_TO_KILL;
- if (!rb_thread_critical) rb_thread_schedule();
+ rb_kill_thread(th, 0);
return thread;
}
/*
* call-seq:
+ * thr.exit! => thr
+ * thr.kill! => thr
+ * thr.terminate! => thr
+ *
+ * Terminates <i>thr</i> without calling ensure clauses and schedules
+ * another thread to be run, returning the terminated <code>Thread</code>.
+ * If this is the main thread, or the last thread, exits the process.
+ *
+ * See <code>Thread#exit</code> for the safer version.
+ */
+
+static VALUE
+rb_thread_kill_bang(thread)
+ VALUE thread;
+{
+ rb_thread_t th = rb_thread_check(thread);
+ rb_kill_thread(th, THREAD_NO_ENSURE);
+ return thread;
+}
+
+/*
+ * call-seq:
* Thread.kill(thread) => thread
*
* Causes the given <em>thread</em> to exit (see <code>Thread::exit</code>).
@@ -11335,7 +11919,7 @@ rb_thread_pass()
VALUE
rb_thread_stop()
{
- enum thread_status last_status = THREAD_RUNNABLE;
+ enum rb_thread_status last_status = THREAD_RUNNABLE;
rb_thread_critical = 0;
if (curr_thread == curr_thread->next) {
@@ -11400,10 +11984,12 @@ rb_thread_sleep_forever()
/*
* call-seq:
* thr.priority => integer
- *
- * Returns the priority of <i>thr</i>. Default is zero; higher-priority threads
- * will run before lower-priority threads.
- *
+ *
+ * Returns the priority of <i>thr</i>. Default is inherited from the
+ * current thread which creating the new thread, or zero for the
+ * initial main thread; higher-priority threads will run before
+ * lower-priority threads.
+ *
* Thread.current.priority #=> 0
*/
@@ -11418,10 +12004,10 @@ rb_thread_priority(thread)
/*
* call-seq:
* thr.priority= integer => thr
- *
+ *
* Sets the priority of <i>thr</i> to <i>integer</i>. Higher-priority threads
* will run before lower-priority threads.
- *
+ *
* count1 = count2 = 0
* a = Thread.new do
* loop { count1 += 1 }
@@ -11592,14 +12178,14 @@ rb_thread_group(thread)
return group;
}
-#ifdef __ia64__
+#ifdef __ia64
# define IA64_INIT(x) x
#else
# define IA64_INIT(x)
#endif
#define THREAD_ALLOC(th) do {\
- th = ALLOC(struct thread);\
+ th = ALLOC(struct rb_thread);\
\
th->next = 0;\
th->prev = 0;\
@@ -11614,6 +12200,7 @@ rb_thread_group(thread)
th->wait_for = 0;\
IA64_INIT(th->bstr_ptr = 0);\
IA64_INIT(th->bstr_len = 0);\
+ IA64_INIT(th->bstr_max = 0);\
FD_ZERO(&th->readfds);\
FD_ZERO(&th->writefds);\
FD_ZERO(&th->exceptfds);\
@@ -11639,6 +12226,11 @@ rb_thread_group(thread)
th->thgroup = thgroup_default;\
th->locals = 0;\
th->thread = 0;\
+ if (curr_thread == 0) {\
+ th->sandbox = Qnil;\
+ } else {\
+ th->sandbox = curr_thread->sandbox;\
+ }\
} while (0)
static rb_thread_t
@@ -11658,7 +12250,13 @@ rb_thread_alloc(klass)
return th;
}
-static int thread_init = 0;
+static int thread_init;
+
+#if defined(POSIX_SIGNAL)
+#define CATCH_VTALRM() posix_signal(SIGVTALRM, catch_timer)
+#else
+#define CATCH_VTALRM() signal(SIGVTALRM, catch_timer)
+#endif
#if defined(_THREAD_SAFE)
static void
@@ -11671,25 +12269,63 @@ catch_timer(sig)
/* cause EINTR */
}
-static pthread_t time_thread;
+#define PER_NANO 1000000000
+
+static struct timespec *
+get_ts(struct timespec *to, long ns)
+{
+ struct timeval tv;
+
+#ifdef CLOCK_REALTIME
+ if (clock_gettime(CLOCK_REALTIME, to) != 0)
+#endif
+ {
+ gettimeofday(&tv, NULL);
+ to->tv_sec = tv.tv_sec;
+ to->tv_nsec = tv.tv_usec * 1000;
+ }
+ if ((to->tv_nsec += ns) >= PER_NANO) {
+ to->tv_sec += to->tv_nsec / PER_NANO;
+ to->tv_nsec %= PER_NANO;
+ }
+ return to;
+}
+
+static struct timer_thread {
+ pthread_cond_t cond;
+ pthread_mutex_t lock;
+ pthread_t thread;
+} time_thread = {PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER};
+
+static int timer_stopping;
+
+#define safe_mutex_lock(lock) \
+ pthread_mutex_lock(lock); \
+ pthread_cleanup_push((void (*)_((void *)))pthread_mutex_unlock, lock)
static void*
thread_timer(dummy)
void *dummy;
{
- for (;;) {
-#ifdef HAVE_NANOSLEEP
- struct timespec req, rem;
+ struct timer_thread *running = ((void **)dummy)[0];
+ pthread_cond_t *start = ((void **)dummy)[1];
+ struct timespec to;
+ int err;
+
+ sigset_t all_signals;
+
+ sigfillset(&all_signals);
+ pthread_sigmask(SIG_BLOCK, &all_signals, 0);
+
+ safe_mutex_lock(&running->lock);
+ pthread_cond_signal(start);
+
+#define WAIT_FOR_10MS() \
+ pthread_cond_timedwait(&running->cond, &running->lock, get_ts(&to, PER_NANO/100))
+ while ((err = WAIT_FOR_10MS()) == EINTR || err == ETIMEDOUT) {
+ if (timer_stopping)
+ break;
- req.tv_sec = 0;
- req.tv_nsec = 10000000;
- nanosleep(&req, &rem);
-#else
- struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 10000;
- select(0, NULL, NULL, NULL, &tv);
-#endif
if (!rb_thread_critical) {
rb_thread_pending = 1;
if (rb_trap_immediate) {
@@ -11697,16 +12333,42 @@ thread_timer(dummy)
}
}
}
+
+ pthread_cleanup_pop(1);
+
+ return NULL;
}
void
rb_thread_start_timer()
{
+ void *args[2];
+ static pthread_cond_t start = PTHREAD_COND_INITIALIZER;
+
+ if (thread_init) return;
+ if (rb_thread_alone()) return;
+ CATCH_VTALRM();
+ args[0] = &time_thread;
+ args[1] = &start;
+ safe_mutex_lock(&time_thread.lock);
+ if (pthread_create(&time_thread.thread, 0, thread_timer, args) == 0) {
+ thread_init = 1;
+ pthread_cond_wait(&start, &time_thread.lock);
+ }
+ pthread_cleanup_pop(1);
}
void
rb_thread_stop_timer()
{
+ if (!thread_init) return;
+ safe_mutex_lock(&time_thread.lock);
+ timer_stopping = 1;
+ pthread_cond_signal(&time_thread.cond);
+ thread_init = 0;
+ pthread_cleanup_pop(1);
+ pthread_join(time_thread.thread, NULL);
+ timer_stopping = 0;
}
#elif defined(HAVE_SETITIMER)
static void
@@ -11727,11 +12389,14 @@ rb_thread_start_timer()
{
struct itimerval tval;
- if (!thread_init) return;
+ if (thread_init) return;
+ if (rb_thread_alone()) return;
+ CATCH_VTALRM();
tval.it_interval.tv_sec = 0;
tval.it_interval.tv_usec = 10000;
tval.it_value = tval.it_interval;
setitimer(ITIMER_VIRTUAL, &tval, NULL);
+ thread_init = 1;
}
void
@@ -11744,11 +12409,20 @@ rb_thread_stop_timer()
tval.it_interval.tv_usec = 0;
tval.it_value = tval.it_interval;
setitimer(ITIMER_VIRTUAL, &tval, NULL);
+ thread_init = 0;
}
#else /* !(_THREAD_SAFE || HAVE_SETITIMER) */
int rb_thread_tick = THREAD_TICK;
#endif
+#if defined(HAVE_SETITIMER) || defined(_THREAD_SAFE)
+#define START_TIMER() (thread_init ? (void)0 : rb_thread_start_timer())
+#define STOP_TIMER() (rb_thread_stop_timer())
+#else
+#define START_TIMER() ((void)0)
+#define STOP_TIMER() ((void)0)
+#endif
+
static VALUE
rb_thread_start_0(fn, arg, th)
VALUE (*fn)();
@@ -11758,7 +12432,7 @@ rb_thread_start_0(fn, arg, th)
volatile rb_thread_t th_save = th;
volatile VALUE thread = th->thread;
struct BLOCK *volatile saved_block = 0;
- enum thread_status status;
+ enum rb_thread_status status;
int state;
if (OBJ_FROZEN(curr_thread->thgroup)) {
@@ -11766,23 +12440,6 @@ rb_thread_start_0(fn, arg, th)
"can't start a new thread (frozen ThreadGroup)");
}
- if (!thread_init) {
- thread_init = 1;
-#if defined(HAVE_SETITIMER) || defined(_THREAD_SAFE)
-#if defined(POSIX_SIGNAL)
- posix_signal(SIGVTALRM, catch_timer);
-#else
- signal(SIGVTALRM, catch_timer);
-#endif
-
-#ifdef _THREAD_SAFE
- pthread_create(&time_thread, 0, thread_timer, 0);
-#else
- rb_thread_start_timer();
-#endif
-#endif
- }
-
if (THREAD_SAVE_CONTEXT(curr_thread)) {
return thread;
}
@@ -11805,6 +12462,7 @@ rb_thread_start_0(fn, arg, th)
th->priority = curr_thread->priority;
th->thgroup = curr_thread->thgroup;
}
+ START_TIMER();
PUSH_TAG(PROT_THREAD);
if ((state = EXEC_TAG()) == 0) {
@@ -11829,7 +12487,7 @@ rb_thread_start_0(fn, arg, th)
}
if (state && status != THREAD_TO_KILL && !NIL_P(ruby_errinfo)) {
- th->flags |= THREAD_RAISED;
+ th->flags |= RAISED_EXCEPTION;
if (state == TAG_FATAL) {
/* fatal error within this thread, need to stop whole script */
main_thread->errinfo = ruby_errinfo;
@@ -11866,7 +12524,7 @@ rb_thread_create(fn, arg)
VALUE (*fn)();
void *arg;
{
- Init_stack((VALUE*)&arg);
+ Init_stack((void *)&arg);
return rb_thread_start_0(fn, arg, rb_thread_alloc(rb_cThread));
}
@@ -12011,7 +12669,7 @@ rb_thread_value(thread)
{
rb_thread_t th = rb_thread_check(thread);
- while (!rb_thread_join(th, DELAY_INFTY));
+ while (!rb_thread_join0(th, DELAY_INFTY));
return th->result;
}
@@ -12047,7 +12705,7 @@ rb_thread_status(thread)
rb_thread_t th = rb_thread_check(thread);
if (rb_thread_dead(th)) {
- if (!NIL_P(th->errinfo) && (th->flags & THREAD_RAISED))
+ if (!NIL_P(th->errinfo) && (th->flags & RAISED_EXCEPTION))
return Qnil;
return Qfalse;
}
@@ -12068,7 +12726,7 @@ rb_thread_status(thread)
* thr.alive? #=> false
*/
-static VALUE
+VALUE
rb_thread_alive_p(thread)
VALUE thread;
{
@@ -12205,13 +12863,15 @@ rb_thread_interrupt()
void
rb_thread_signal_raise(sig)
- char *sig;
+ int sig;
{
- if (sig == 0) return; /* should not happen */
rb_thread_critical = 0;
if (curr_thread == main_thread) {
+ VALUE argv[1];
+
rb_thread_ready(curr_thread);
- rb_raise(rb_eSignal, "SIG%s", sig);
+ argv[0] = INT2FIX(sig);
+ rb_exc_raise(rb_class_new_instance(1, argv, rb_eSignal));
}
rb_thread_ready(main_thread);
if (!rb_thread_dead(curr_thread)) {
@@ -12219,7 +12879,7 @@ rb_thread_signal_raise(sig)
return;
}
}
- th_signm = sig;
+ th_sig = sig;
curr_thread = main_thread;
rb_thread_restore_context(curr_thread, RESTORE_SIGNAL);
}
@@ -12499,7 +13159,7 @@ static VALUE
rb_thread_inspect(thread)
VALUE thread;
{
- char *cname = rb_obj_classname(thread);
+ const char *cname = rb_obj_classname(thread);
rb_thread_t th = rb_thread_check(thread);
const char *status = thread_status_name(th->status);
VALUE str;
@@ -12518,6 +13178,7 @@ rb_thread_atfork()
{
rb_thread_t th;
+ rb_reset_random_seed();
if (rb_thread_alone()) return;
FOREACH_THREAD(th) {
if (th != curr_thread) {
@@ -12528,8 +13189,41 @@ rb_thread_atfork()
main_thread = curr_thread;
curr_thread->next = curr_thread;
curr_thread->prev = curr_thread;
+ STOP_TIMER();
+}
+
+
+static void
+cc_purge(cc)
+ rb_thread_t cc;
+{
+ /* free continuation's stack if it has just died */
+ if (NIL_P(cc->thread)) return;
+ if (rb_thread_check(cc->thread)->status == THREAD_KILLED) {
+ cc->thread = Qnil;
+ rb_thread_die(cc); /* can't possibly activate this stack */
+ }
}
+static void
+cc_mark(cc)
+ rb_thread_t cc;
+{
+ /* mark this continuation's stack only if its parent thread is still alive */
+ cc_purge(cc);
+ thread_mark(cc);
+}
+
+static rb_thread_t
+rb_cont_check(data)
+ VALUE data;
+{
+ if (TYPE(data) != T_DATA || RDATA(data)->dmark != (RUBY_DATA_FUNC)cc_mark) {
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected Continuation)",
+ rb_obj_classname(data));
+ }
+ return (rb_thread_t)RDATA(data)->data;
+}
/*
* Document-class: Continuation
@@ -12605,14 +13299,16 @@ rb_callcc(self)
struct RVarmap *vars;
THREAD_ALLOC(th);
- cont = Data_Wrap_Struct(rb_cCont, thread_mark, thread_free, th);
+ /* must finish th initialization before any possible gc.
+ * brent@mbari.org */
+ th->thread = curr_thread->thread;
+ th->thgroup = cont_protect;
+ cont = Data_Wrap_Struct(rb_cCont, cc_mark, thread_free, th);
scope_dup(ruby_scope);
for (tag=prot_tag; tag; tag=tag->prev) {
scope_dup(tag->scope);
}
- th->thread = curr_thread->thread;
- th->thgroup = cont_protect;
for (vars = ruby_dyna_vars; vars; vars = vars->next) {
if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break;
@@ -12649,7 +13345,7 @@ rb_cont_call(argc, argv, cont)
VALUE *argv;
VALUE cont;
{
- rb_thread_t th = rb_thread_check(cont);
+ rb_thread_t th = rb_cont_check(cont);
if (th->thread != curr_thread->thread) {
rb_raise(rb_eRuntimeError, "continuation called across threads");
@@ -12825,10 +13521,6 @@ thgroup_add(group, thread)
rb_secure(4);
th = rb_thread_check(thread);
- if (!th->next || !th->prev) {
- rb_raise(rb_eTypeError, "wrong argument type %s (expected Thread)",
- rb_obj_classname(thread));
- }
if (OBJ_FROZEN(group)) {
rb_raise(rb_eThreadError, "can't move to the frozen thread group");
@@ -12854,6 +13546,111 @@ thgroup_add(group, thread)
}
+/* variables for recursive traversals */
+static ID recursive_key;
+
+static VALUE
+recursive_check(hash, obj)
+ VALUE hash;
+ VALUE obj;
+{
+ if (NIL_P(hash) || TYPE(hash) != T_HASH) {
+ return Qfalse;
+ }
+ else {
+ VALUE list = rb_hash_aref(hash, ID2SYM(rb_frame_last_func()));
+
+ if (NIL_P(list) || TYPE(list) != T_HASH)
+ return Qfalse;
+ if (NIL_P(rb_hash_lookup(list, obj)))
+ return Qfalse;
+ return Qtrue;
+ }
+}
+
+static VALUE
+recursive_push(hash, obj)
+ VALUE hash;
+ VALUE obj;
+{
+ VALUE list, sym;
+
+ sym = ID2SYM(rb_frame_last_func());
+ if (NIL_P(hash) || TYPE(hash) != T_HASH) {
+ hash = rb_hash_new();
+ OBJ_TAINT(hash);
+ rb_thread_local_aset(rb_thread_current(), recursive_key, hash);
+ list = Qnil;
+ }
+ else {
+ list = rb_hash_aref(hash, sym);
+ }
+ if (NIL_P(list) || TYPE(list) != T_HASH) {
+ list = rb_hash_new();
+ OBJ_TAINT(list);
+ rb_hash_aset(hash, sym, list);
+ }
+ rb_hash_aset(list, obj, Qtrue);
+ return hash;
+}
+
+static void
+recursive_pop(hash, obj)
+ VALUE hash;
+ VALUE obj;
+{
+ VALUE list, sym;
+
+ sym = ID2SYM(rb_frame_last_func());
+ if (NIL_P(hash) || TYPE(hash) != T_HASH) {
+ VALUE symname;
+ VALUE thrname;
+ symname = rb_inspect(sym);
+ thrname = rb_inspect(rb_thread_current());
+
+ rb_raise(rb_eTypeError, "invalid inspect_tbl hash for %s in %s",
+ StringValuePtr(symname), StringValuePtr(thrname));
+ }
+ list = rb_hash_aref(hash, sym);
+ if (NIL_P(list) || TYPE(list) != T_HASH) {
+ VALUE symname = rb_inspect(sym);
+ VALUE thrname = rb_inspect(rb_thread_current());
+ rb_raise(rb_eTypeError, "invalid inspect_tbl list for %s in %s",
+ StringValuePtr(symname), StringValuePtr(thrname));
+ }
+ rb_hash_delete(list, obj);
+}
+
+VALUE
+rb_exec_recursive(func, obj, arg)
+ VALUE (*func) _((VALUE, VALUE, int));
+ VALUE obj;
+ VALUE arg;
+{
+ VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key);
+ VALUE objid = rb_obj_id(obj);
+
+ if (recursive_check(hash, objid)) {
+ return (*func) (obj, arg, Qtrue);
+ }
+ else {
+ VALUE result = Qundef;
+ int state;
+
+ hash = recursive_push(hash, objid);
+ PUSH_TAG(PROT_NONE);
+ if ((state = EXEC_TAG()) == 0) {
+ result = (*func) (obj, arg, Qfalse);
+ }
+ POP_TAG();
+ recursive_pop(hash, objid);
+ if (state)
+ JUMP_TAG(state);
+ return result;
+ }
+}
+
+
/*
* +Thread+ encapsulates the behavior of a thread of
* execution, including the main thread of the Ruby script.
@@ -12868,6 +13665,7 @@ Init_Thread()
{
VALUE cThGroup;
+ recursive_key = rb_intern("__recursive_key__");
rb_eThreadError = rb_define_class("ThreadError", rb_eStandardError);
rb_cThread = rb_define_class("Thread", rb_cObject);
rb_undef_alloc_func(rb_cThread);
@@ -12896,6 +13694,9 @@ Init_Thread()
rb_define_method(rb_cThread, "kill", rb_thread_kill, 0);
rb_define_method(rb_cThread, "terminate", rb_thread_kill, 0);
rb_define_method(rb_cThread, "exit", rb_thread_kill, 0);
+ rb_define_method(rb_cThread, "kill!", rb_thread_kill_bang, 0);
+ rb_define_method(rb_cThread, "terminate!", rb_thread_kill_bang, 0);
+ rb_define_method(rb_cThread, "exit!", rb_thread_kill_bang, 0);
rb_define_method(rb_cThread, "value", rb_thread_value, 0);
rb_define_method(rb_cThread, "status", rb_thread_status, 0);
rb_define_method(rb_cThread, "join", rb_thread_join_m, -1);
@@ -13067,13 +13868,3 @@ rb_throw(tag, val)
argv[1] = val;
rb_f_throw(2, argv);
}
-
-/* flush_register_windows must not be inlined because flushrs doesn't flush
- * current frame in register stack. */
-#ifdef __ia64__
-void flush_register_windows(void)
-{
- __asm__ ("flushrs");
-}
-#endif
-
diff --git a/ext/Setup b/ext/Setup
index 7b214abde3..d0d6317a5e 100644
--- a/ext/Setup
+++ b/ext/Setup
@@ -28,6 +28,7 @@
#syck
#syslog
#tcltklib
+#thread
#tk
#win32ole
#zlib
diff --git a/ext/Setup.atheos b/ext/Setup.atheos
index 9b1bdecb95..6bda3a4cfb 100644
--- a/ext/Setup.atheos
+++ b/ext/Setup.atheos
@@ -28,6 +28,7 @@ strscan
syck
syslog
#tcltklib
+thread
#tk
#win32ole
zlib
diff --git a/ext/Setup.dj b/ext/Setup.dj
index f2ed3a4f16..4f94788886 100644
--- a/ext/Setup.dj
+++ b/ext/Setup.dj
@@ -28,6 +28,7 @@ strscan
syck
#syslog
#tcltklib
+thread
#tk
#win32ole
zlib
diff --git a/ext/Setup.emx b/ext/Setup.emx
index 7ea04543c5..afc5923577 100644
--- a/ext/Setup.emx
+++ b/ext/Setup.emx
@@ -28,6 +28,7 @@ strscan
#syck
#syslog
#tcltklib
+thread
#tk
#win32ole
#zlib
diff --git a/ext/Setup.nt b/ext/Setup.nt
index 7a330f801a..9f8abf9b8d 100644
--- a/ext/Setup.nt
+++ b/ext/Setup.nt
@@ -28,6 +28,7 @@ strscan
syck
#syslog
#tcltklib
+thread
#tk
win32ole
#zlib
diff --git a/ext/Setup.x68 b/ext/Setup.x68
index 9b9563d941..0966e737e9 100644
--- a/ext/Setup.x68
+++ b/ext/Setup.x68
@@ -28,6 +28,7 @@ strscan
#syck
#syslog
#tcltklib
+thread
#tk
#win32ole
#zlib
diff --git a/ext/Win32API/lib/win32/registry.rb b/ext/Win32API/lib/win32/registry.rb
index 2671551a33..9a2f3827b7 100644
--- a/ext/Win32API/lib/win32/registry.rb
+++ b/ext/Win32API/lib/win32/registry.rb
@@ -493,7 +493,7 @@ module Win32
# utility functions
#
def self.expand_environ(str)
- str.gsub(/%([^%]+)%/) { ENV[$1] || $& }
+ str.gsub(/%([^%]+)%/) { ENV[$1] || ENV[$1.upcase] || $& }
end
@@type2name = { }
diff --git a/ext/Win32API/lib/win32/resolv.rb b/ext/Win32API/lib/win32/resolv.rb
index 6534d20760..92336fac28 100644
--- a/ext/Win32API/lib/win32/resolv.rb
+++ b/ext/Win32API/lib/win32/resolv.rb
@@ -11,7 +11,7 @@ module Win32
def self.get_hosts_path
path = get_hosts_dir
- path = File.join(path.gsub(/\\/, File::SEPARATOR), 'hosts')
+ path = File.expand_path('hosts', path)
File.exist?(path) ? path : nil
end
diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c
index fd0cd65418..7846c0d771 100644
--- a/ext/bigdecimal/bigdecimal.c
+++ b/ext/bigdecimal/bigdecimal.c
@@ -224,14 +224,14 @@ GetVpValue(VALUE v, int must)
#ifdef ENABLE_NUMERIC_STRING
case T_STRING:
SafeStringValue(v);
- return VpCreateRbObject(strlen(RSTRING(v)->ptr) + VpBaseFig() + 1,
- RSTRING(v)->ptr);
+ return VpCreateRbObject(strlen(RSTRING_PTR(v)) + VpBaseFig() + 1,
+ RSTRING_PTR(v));
#endif /* ENABLE_NUMERIC_STRING */
case T_BIGNUM:
bg = rb_big2str(v, 10);
- return VpCreateRbObject(strlen(RSTRING(bg)->ptr) + VpBaseFig() + 1,
- RSTRING(bg)->ptr);
+ return VpCreateRbObject(strlen(RSTRING_PTR(bg)) + VpBaseFig() + 1,
+ RSTRING_PTR(bg));
default:
goto SomeOneMayDoIt;
}
@@ -240,7 +240,7 @@ SomeOneMayDoIt:
if(must) {
rb_raise(rb_eTypeError, "%s can't be coerced into BigDecimal",
rb_special_const_p(v)?
- RSTRING(rb_inspect(v))->ptr:
+ RSTRING_PTR(rb_inspect(v)):
rb_obj_classname(v)
);
}
@@ -306,17 +306,19 @@ static VALUE
BigDecimal_dump(int argc, VALUE *argv, VALUE self)
{
ENTER(5);
- char sz[50];
Real *vp;
char *psz;
VALUE dummy;
+ volatile VALUE dump;
+
rb_scan_args(argc, argv, "01", &dummy);
GUARD_OBJ(vp,GetVpValue(self,1));
- sprintf(sz,"%lu:",VpMaxPrec(vp)*VpBaseFig());
- psz = ALLOCA_N(char,(unsigned int)VpNumOfChars(vp,"E")+strlen(sz));
- sprintf(psz,"%s",sz);
+ dump = rb_str_new(0,VpNumOfChars(vp,"E")+50);
+ psz = RSTRING_PTR(dump);
+ sprintf(psz,"%lu:",VpMaxPrec(vp)*VpBaseFig());
VpToString(vp, psz+strlen(psz), 0, 0);
- return rb_str_new2(psz);
+ rb_str_resize(dump, strlen(psz));
+ return dump;
}
/*
@@ -332,7 +334,7 @@ BigDecimal_load(VALUE self, VALUE str)
unsigned long m=0;
SafeStringValue(str);
- pch = RSTRING(str)->ptr;
+ pch = (unsigned char *)RSTRING_PTR(str);
/* First get max prec */
while((*pch)!=(unsigned char)'\0' && (ch=*pch++)!=(unsigned char)':') {
if(!ISDIGIT(ch)) {
@@ -341,7 +343,7 @@ BigDecimal_load(VALUE self, VALUE str)
m = m*10 + (unsigned long)(ch-'0');
}
if(m>VpBaseFig()) m -= VpBaseFig();
- GUARD_OBJ(pv,VpNewRbClass(m,pch,self));
+ GUARD_OBJ(pv,VpNewRbClass(m,(char *)pch,self));
m /= VpBaseFig();
if(m && pv->MaxPrec>m) pv->MaxPrec = m+1;
return ToValue(pv);
@@ -474,7 +476,7 @@ VpNewRbClass(U_LONG mx, char *str, VALUE klass)
}
VP_EXPORT Real *
-VpCreateRbObject(U_LONG mx, char *str)
+VpCreateRbObject(U_LONG mx, const char *str)
{
Real *pv = VpAlloc(mx,str);
pv->obj = (VALUE)Data_Wrap_Struct(rb_cBigDecimal, 0, BigDecimal_delete, pv);
@@ -520,6 +522,7 @@ BigDecimal_to_i(VALUE self)
ENTER(5);
int e,n,i,nf;
U_LONG v,b,j;
+ volatile VALUE str;
char *psz,*pch;
Real *p;
@@ -544,7 +547,8 @@ BigDecimal_to_i(VALUE self)
e = VpGetSign(p)*p->frac[0];
return INT2FIX(e);
}
- psz = ALLOCA_N(char,(unsigned int)(e+nf+2));
+ str = rb_str_new(0, e+nf+2);
+ psz = RSTRING_PTR(str);
n = (e+nf-1)/nf;
pch = psz;
@@ -586,19 +590,26 @@ BigDecimal_to_f(VALUE self)
{
ENTER(1);
Real *p;
- double d, d2;
+ double d;
S_LONG e;
+ char *buf;
+ volatile VALUE str;
GUARD_OBJ(p,GetVpValue(self,1));
if(VpVtoD(&d, &e, p)!=1) return rb_float_new(d);
+ if (e > DBL_MAX_10_EXP) goto erange;
+ str = rb_str_new(0, VpNumOfChars(p,"E"));
+ buf = RSTRING_PTR(str);
+ VpToString(p, buf, 0, 0);
errno = 0;
- d2 = pow(10.0,(double)e);
- if((errno == ERANGE && e>0) || (d2>1.0 && (fabs(d) > (DBL_MAX / d2)))) {
+ d = strtod(buf, 0);
+ if(errno == ERANGE) {
+ erange:
VpException(VP_EXCEPTION_OVERFLOW,"BigDecimal to Float conversion",0);
- if(d>0.0) return rb_float_new(DBL_MAX);
- else return rb_float_new(-DBL_MAX);
+ if(d>0.0) d = VpGetDoublePosInf();
+ else d = VpGetDoubleNegInf();
}
- return rb_float_new(d*d2);
+ return rb_float_new(d);
}
/* The coerce method provides support for Ruby type coercion. It is not
@@ -723,15 +734,21 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
Real *a, *b;
GUARD_OBJ(a,GetVpValue(self,1));
b = GetVpValue(r,0);
- if(!b) return rb_num_coerce_cmp(self,r);
+ if(!b) {
+ switch(op)
+ {
+ case '*': return rb_num_coerce_cmp(self,r); /* any op */
+ case '=': return RTEST(rb_num_coerce_cmp(self,r)) ? Qtrue : Qfalse;
+ default: return rb_num_coerce_relop(self,r);
+ }
+ }
SAVE(b);
e = VpComp(a, b);
- if(e==999) return Qnil;
+ if(e==999) return (op == '*') ? Qnil : Qfalse;
switch(op)
{
case '*': return INT2FIX(e); /* any op */
case '=': if(e==0) return Qtrue ; return Qfalse;
- case '!': if(e!=0) return Qtrue ; return Qfalse;
case 'G': if(e>=0) return Qtrue ; return Qfalse;
case '>': if(e> 0) return Qtrue ; return Qfalse;
case 'L': if(e<=0) return Qtrue ; return Qfalse;
@@ -781,17 +798,6 @@ BigDecimal_eq(VALUE self, VALUE r)
return BigDecimalCmp(self, r, '=');
}
-/* Returns true if the values are not equal in value. Values may be coerced
- * to perform the comparison:
- *
- * BigDecimal.new('1.0') != 1.0 -> false
- */
-static VALUE
-BigDecimal_ne(VALUE self, VALUE r)
-{
- return BigDecimalCmp(self, r, '!');
-}
-
/* call-seq:
* a < b
*
@@ -1062,7 +1068,7 @@ static VALUE
BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
{
VALUE f;
- Real *d,*rv;
+ Real *d,*rv=0;
f = BigDecimal_divremain(self,r,&d,&rv);
if(f!=(VALUE)0) return f;
return ToValue(rv);
@@ -1276,7 +1282,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
{
ENTER(5);
Real *c, *a;
- int iLoc;
+ int iLoc = 0;
U_LONG mx;
VALUE vLoc;
VALUE vRound;
@@ -1499,6 +1505,7 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
int fmt=0; /* 0:E format */
int fPlus=0; /* =0:default,=1: set ' ' before digits ,set '+' before digits. */
Real *vp;
+ volatile VALUE str;
char *psz;
char ch;
U_LONG nc;
@@ -1510,13 +1517,13 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
if(rb_scan_args(argc,argv,"01",&f)==1) {
if(TYPE(f)==T_STRING) {
SafeStringValue(f);
- psz = RSTRING(f)->ptr;
+ psz = RSTRING_PTR(f);
if(*psz==' ') {
fPlus = 1; psz++;
} else if(*psz=='+') {
fPlus = 2; psz++;
}
- while(ch=*psz++) {
+ while((ch=*psz++)!=0) {
if(ISSPACE(ch)) continue;
if(!ISDIGIT(ch)) {
if(ch=='F' || ch=='f') fmt = 1; /* F format */
@@ -1535,14 +1542,16 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
}
if(mc>0) nc += (nc + mc - 1) / mc + 1;
- psz = ALLOCA_N(char,(unsigned int)nc);
+ str = rb_str_new(0, nc);
+ psz = RSTRING_PTR(str);
if(fmt) {
VpToFString(vp, psz, mc, fPlus);
} else {
VpToString (vp, psz, mc, fPlus);
}
- return rb_str_new2(psz);
+ rb_str_resize(str, strlen(psz));
+ return str;
}
/* Splits a BigDecimal number into four parts, returned as an array of values.
@@ -1574,24 +1583,29 @@ BigDecimal_split(VALUE self)
{
ENTER(5);
Real *vp;
- VALUE obj,obj1;
+ VALUE obj,str;
S_LONG e;
S_LONG s;
char *psz1;
GUARD_OBJ(vp,GetVpValue(self,1));
- psz1 = ALLOCA_N(char,(unsigned int)VpNumOfChars(vp,"E"));
+ str = rb_str_new(0, VpNumOfChars(vp,"E"));
+ psz1 = RSTRING_PTR(str);
VpSzMantissa(vp,psz1);
s = 1;
if(psz1[0]=='-') {
- s = -1; ++psz1;
+ int len = strlen(psz1+1);
+
+ memmove(psz1, psz1+1, len);
+ psz1[len] = '\0';
+ s = -1;
}
if(psz1[0]=='N') s=0; /* NaN */
e = VpExponent10(vp);
- obj1 = rb_str_new2(psz1);
obj = rb_ary_new2(4);
rb_ary_push(obj, INT2FIX(s));
- rb_ary_push(obj, obj1);
+ rb_ary_push(obj, str);
+ rb_str_resize(str, strlen(psz1));
rb_ary_push(obj, INT2FIX(10));
rb_ary_push(obj, INT2NUM(e));
return obj;
@@ -1624,20 +1638,22 @@ BigDecimal_inspect(VALUE self)
{
ENTER(5);
Real *vp;
- VALUE obj;
+ volatile VALUE obj;
unsigned int nc;
- char *psz1;
- char *pszAll;
+ char *psz, *tmp;
GUARD_OBJ(vp,GetVpValue(self,1));
nc = VpNumOfChars(vp,"E");
nc +=(nc + 9) / 10;
- psz1 = ALLOCA_N(char,nc);
- pszAll = ALLOCA_N(char,nc+256);
- VpToString(vp, psz1, 10, 0);
- sprintf(pszAll,"#<BigDecimal:%lx,'%s',%lu(%lu)>",self,psz1,VpPrec(vp)*VpBaseFig(),VpMaxPrec(vp)*VpBaseFig());
- obj = rb_str_new2(pszAll);
+ obj = rb_str_new(0, nc+256);
+ psz = RSTRING_PTR(obj);
+ sprintf(psz,"#<BigDecimal:%lx,'",self);
+ tmp = psz + strlen(psz);
+ VpToString(vp, tmp, 10, 0);
+ tmp += strlen(tmp);
+ sprintf(tmp,"',%lu(%lu)>",VpPrec(vp)*VpBaseFig(),VpMaxPrec(vp)*VpBaseFig());
+ rb_str_resize(obj, strlen(psz));
return obj;
}
@@ -1687,7 +1703,7 @@ BigDecimal_global_new(int argc, VALUE *argv, VALUE self)
mf = GetPositiveInt(nFig);
}
SafeStringValue(iniValue);
- GUARD_OBJ(pv,VpCreateRbObject(mf, RSTRING(iniValue)->ptr));
+ GUARD_OBJ(pv,VpCreateRbObject(mf, RSTRING_PTR(iniValue)));
return ToValue(pv);
}
@@ -1718,7 +1734,7 @@ BigDecimal_new(int argc, VALUE *argv, VALUE self)
mf = GetPositiveInt(nFig);
}
SafeStringValue(iniValue);
- GUARD_OBJ(pv,VpNewRbClass(mf, RSTRING(iniValue)->ptr,self));
+ GUARD_OBJ(pv,VpNewRbClass(mf, RSTRING_PTR(iniValue),self));
return ToValue(pv);
}
@@ -1811,76 +1827,94 @@ Init_bigdecimal(void)
/* Exceptions */
/*
- * Determines whether overflow, underflow or zero divide result in
+ * 0xff: Determines whether overflow, underflow or zero divide result in
* an exception being thrown. See BigDecimal.mode.
*/
rb_define_const(rb_cBigDecimal, "EXCEPTION_ALL",INT2FIX(VP_EXCEPTION_ALL));
/*
- * Determines what happens when the result of a computation is not a
+ * 0x02: Determines what happens when the result of a computation is not a
* number (NaN). See BigDecimal.mode.
*/
rb_define_const(rb_cBigDecimal, "EXCEPTION_NaN",INT2FIX(VP_EXCEPTION_NaN));
/*
- * Determines what happens when the result of a computation is infinity.
- * See BigDecimal.mode.
+ * 0x01: Determines what happens when the result of a computation is
+ * infinity. See BigDecimal.mode.
*/
rb_define_const(rb_cBigDecimal, "EXCEPTION_INFINITY",INT2FIX(VP_EXCEPTION_INFINITY));
/*
- * Determines what happens when the result of a computation is an underflow
- * (a result too small to be represented). See BigDecimal.mode.
+ * 0x04: Determines what happens when the result of a computation is an
+ * underflow (a result too small to be represented). See BigDecimal.mode.
*/
rb_define_const(rb_cBigDecimal, "EXCEPTION_UNDERFLOW",INT2FIX(VP_EXCEPTION_UNDERFLOW));
/*
- * Determines what happens when the result of a computation is an underflow
- * (a result too large to be represented). See BigDecimal.mode.
+ * 0x01: Determines what happens when the result of a computation is an
+ * underflow (a result too large to be represented). See BigDecimal.mode.
*/
rb_define_const(rb_cBigDecimal, "EXCEPTION_OVERFLOW",INT2FIX(VP_EXCEPTION_OVERFLOW));
/*
- * Determines what happens when a division by zero is performed.
+ * 0x01: Determines what happens when a division by zero is performed.
* See BigDecimal.mode.
*/
rb_define_const(rb_cBigDecimal, "EXCEPTION_ZERODIVIDE",INT2FIX(VP_EXCEPTION_ZERODIVIDE));
/*
- * Determines what happens when a result must be rounded in order to
- * fit in the appropriate number of significant digits. See
+ * 0x100: Determines what happens when a result must be rounded in order to
+ * fit in the appropriate number of significant digits. See
* BigDecimal.mode.
*/
rb_define_const(rb_cBigDecimal, "ROUND_MODE",INT2FIX(VP_ROUND_MODE));
- /* Indicates that values should be rounded away from zero. See BigDecimal.mode. */
+ /* 1: Indicates that values should be rounded away from zero. See
+ * BigDecimal.mode.
+ */
rb_define_const(rb_cBigDecimal, "ROUND_UP",INT2FIX(VP_ROUND_UP));
- /* Indicates that values should be rounded towards zero. See BigDecimal.mode. */
+
+ /* 2: Indicates that values should be rounded towards zero. See
+ * BigDecimal.mode.
+ */
rb_define_const(rb_cBigDecimal, "ROUND_DOWN",INT2FIX(VP_ROUND_DOWN));
- /* Indicates that digits >= 5 should be rounded up, others rounded down. See BigDecimal.mode. */
+
+ /* 3: Indicates that digits >= 5 should be rounded up, others rounded down.
+ * See BigDecimal.mode. */
rb_define_const(rb_cBigDecimal, "ROUND_HALF_UP",INT2FIX(VP_ROUND_HALF_UP));
- /* Indicates that digits >= 6 should be rounded up, others rounded down. See BigDecimal.mode. */
+
+ /* 4: Indicates that digits >= 6 should be rounded up, others rounded down.
+ * See BigDecimal.mode.
+ */
rb_define_const(rb_cBigDecimal, "ROUND_HALF_DOWN",INT2FIX(VP_ROUND_HALF_DOWN));
- /* Round towards +infinity. See BigDecimal.mode. */
+ /* 5: Round towards +infinity. See BigDecimal.mode. */
rb_define_const(rb_cBigDecimal, "ROUND_CEILING",INT2FIX(VP_ROUND_CEIL));
- /* Round towards -infinity. See BigDecimal.mode. */
+
+ /* 6: Round towards -infinity. See BigDecimal.mode. */
rb_define_const(rb_cBigDecimal, "ROUND_FLOOR",INT2FIX(VP_ROUND_FLOOR));
- /* Round towards the even neighbor. See BigDecimal.mode. */
+
+ /* 7: Round towards the even neighbor. See BigDecimal.mode. */
rb_define_const(rb_cBigDecimal, "ROUND_HALF_EVEN",INT2FIX(VP_ROUND_HALF_EVEN));
- /* Indicates that a value is not a number. See BigDecimal.sign. */
+ /* 0: Indicates that a value is not a number. See BigDecimal.sign. */
rb_define_const(rb_cBigDecimal, "SIGN_NaN",INT2FIX(VP_SIGN_NaN));
- /* Indicates that a value is +0. See BigDecimal.sign. */
+
+ /* 1: Indicates that a value is +0. See BigDecimal.sign. */
rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_ZERO",INT2FIX(VP_SIGN_POSITIVE_ZERO));
- /* Indicates that a value is -0. See BigDecimal.sign. */
+
+ /* -1: Indicates that a value is -0. See BigDecimal.sign. */
rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_ZERO",INT2FIX(VP_SIGN_NEGATIVE_ZERO));
- /* Indicates that a value is positive and finite. See BigDecimal.sign. */
+
+ /* 2: Indicates that a value is positive and finite. See BigDecimal.sign. */
rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_FINITE",INT2FIX(VP_SIGN_POSITIVE_FINITE));
- /* Indicates that a value is negative and finite. See BigDecimal.sign. */
+
+ /* -2: Indicates that a value is negative and finite. See BigDecimal.sign. */
rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_FINITE",INT2FIX(VP_SIGN_NEGATIVE_FINITE));
- /* Indicates that a value is positive and infinite. See BigDecimal.sign. */
+
+ /* 3: Indicates that a value is positive and infinite. See BigDecimal.sign. */
rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_INFINITE",INT2FIX(VP_SIGN_POSITIVE_INFINITE));
- /* Indicates that a value is negative and infinite. See BigDecimal.sign. */
+
+ /* -3: Indicates that a value is negative and infinite. See BigDecimal.sign. */
rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_INFINITE",INT2FIX(VP_SIGN_NEGATIVE_INFINITE));
/* instance methods */
@@ -1921,7 +1955,6 @@ Init_bigdecimal(void)
rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
rb_define_method(rb_cBigDecimal, "eql?", BigDecimal_eq, 1);
- rb_define_method(rb_cBigDecimal, "!=", BigDecimal_ne, 1);
rb_define_method(rb_cBigDecimal, "<", BigDecimal_lt, 1);
rb_define_method(rb_cBigDecimal, "<=", BigDecimal_le, 1);
rb_define_method(rb_cBigDecimal, ">", BigDecimal_gt, 1);
@@ -1949,24 +1982,34 @@ Init_bigdecimal(void)
*
*/
#ifdef _DEBUG
-/*static int gfDebug = 1;*/ /* Debug switch */
+static int gfDebug = 1; /* Debug switch */
static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */
#endif /* _DEBUG */
static U_LONG gnPrecLimit = 0; /* Global upper limit of the precision newly allocated */
static U_LONG gfRoundMode = VP_ROUND_HALF_UP; /* Mode for general rounding operation */
+#ifndef BASE_FIG
static U_LONG BASE_FIG = 4; /* =log10(BASE) */
static U_LONG BASE = 10000L; /* Base value(value must be 10**BASE_FIG) */
/* The value of BASE**2 + BASE must be represented */
/* within one U_LONG. */
static U_LONG HALF_BASE = 5000L;/* =BASE/2 */
-static S_LONG DBLE_FIG = 8; /* figure of double */
static U_LONG BASE1 = 1000L; /* =BASE/10 */
+#else
+#ifndef BASE
+#error BASE_FIG is defined but BASE is not
+#endif
+#define HALF_BASE (BASE/2)
+#define BASE1 (BASE/10)
+#endif
+#ifndef DBLE_FIG
+#define DBLE_FIG (DBL_DIG+1) /* figure of double */
+#endif
static Real *VpConstOne; /* constant 1.0 */
static Real *VpPt5; /* constant 0.5 */
-static U_LONG maxnr = 100; /* Maximum iterations for calcurating sqrt. */
+#define maxnr 100UL /* Maximum iterations for calcurating sqrt. */
/* used in VpSqrt() */
/* ETC */
@@ -2083,8 +2126,8 @@ VpSetRoundMode(unsigned long n)
* (to let the compiler know they may be changed in outside
* (... but not actually..)).
*/
-volatile double gZero_ABCED9B1_CE73__00400511F31D = 0.0;
-volatile double gOne_ABCED9B4_CE73__00400511F31D = 1.0;
+volatile const double gZero_ABCED9B1_CE73__00400511F31D = 0.0;
+volatile const double gOne_ABCED9B4_CE73__00400511F31D = 1.0;
static double
Zero(void)
{
@@ -2169,7 +2212,7 @@ VpIsNegDoubleZero(double v)
}
VP_EXPORT int
-VpException(unsigned short f,char *str,int always)
+VpException(unsigned short f, const char *str,int always)
{
VALUE exc;
int fatal=0;
@@ -2206,8 +2249,8 @@ VpException(unsigned short f,char *str,int always)
return 0; /* 0 Means VpException() raised no exception */
raise:
- if(fatal) rb_fatal(str);
- else rb_raise(exc,str);
+ if(fatal) rb_fatal("%s", str);
+ else rb_raise(exc, "%s", str);
return 0;
}
@@ -2311,7 +2354,7 @@ NaN:
* returns number of chars needed to represent vp in specified format.
*/
VP_EXPORT U_LONG
-VpNumOfChars(Real *vp,char *pszFmt)
+VpNumOfChars(Real *vp,const char *pszFmt)
{
S_INT ex;
U_LONG nc;
@@ -2356,16 +2399,15 @@ VpNumOfChars(Real *vp,char *pszFmt)
VP_EXPORT U_LONG
VpInit(U_LONG BaseVal)
{
- U_LONG w;
- double v;
-
/* Setup +/- Inf NaN -0 */
VpGetDoubleNaN();
VpGetDoublePosInf();
VpGetDoubleNegInf();
VpGetDoubleNegZero();
+#ifndef BASE_FIG
if(BaseVal <= 0) {
+ U_LONG w;
/* Base <= 0, then determine Base by calcuration. */
BASE = 1;
while(
@@ -2382,6 +2424,8 @@ VpInit(U_LONG BaseVal)
BASE1 = BASE / 10;
BASE_FIG = 0;
while(BaseVal /= 10) ++BASE_FIG;
+#endif
+
/* Allocates Vp constants. */
VpConstOne = VpAlloc((U_LONG)1, "1");
VpPt5 = VpAlloc((U_LONG)1, ".5");
@@ -2390,15 +2434,6 @@ VpInit(U_LONG BaseVal)
gnAlloc = 0;
#endif /* _DEBUG */
- /* Determine # of digits available in one 'double'. */
-
- v = 1.0;
- DBLE_FIG = 0;
- while(v + 1.0 > 1.0) {
- ++DBLE_FIG;
- v /= 10;
- }
-
#ifdef _DEBUG
if(gfDebug) {
printf("VpInit: BaseVal = %lu\n", BaseVal);
@@ -2414,7 +2449,7 @@ VpInit(U_LONG BaseVal)
}
VP_EXPORT Real *
-VpOne()
+VpOne(void)
{
return VpConstOne;
}
@@ -2464,13 +2499,14 @@ overflow:
* NULL be returned if memory allocation is failed,or any error.
*/
VP_EXPORT Real *
-VpAlloc(U_LONG mx, char *szVal)
+VpAlloc(U_LONG mx, const char *szVal)
{
U_LONG i, ni, ipn, ipf, nf, ipe, ne, nalloc;
char v,*psz;
int sign=1;
Real *vp = NULL;
U_LONG mf = VpGetPrecLimit();
+ VALUE buf;
mx = (mx + BASE_FIG - 1) / BASE_FIG + 1; /* Determine allocation unit. */
if(szVal) {
@@ -2498,10 +2534,11 @@ VpAlloc(U_LONG mx, char *szVal)
/* Skip all '_' after digit: 2006-6-30 */
ni = 0;
- psz = ALLOCA_N(char,strlen(szVal)+1);
+ buf = rb_str_tmp_new(strlen(szVal)+1);
+ psz = RSTRING_PTR(buf);
i = 0;
ipn = 0;
- while(psz[i]=szVal[ipn]) {
+ while((psz[i]=szVal[ipn])!=0) {
if(ISDIGIT(psz[i])) ++ni;
if(psz[i]=='_') {
if(ni>0) {ipn++;continue;}
@@ -2544,7 +2581,7 @@ VpAlloc(U_LONG mx, char *szVal)
else if(szVal[i] == '+') ++i;
/* Skip digits */
ni = 0; /* digits in mantissa */
- while(v = szVal[i]) {
+ while((v = szVal[i]) != 0) {
if(!ISDIGIT(v)) break;
++i;
++ni;
@@ -2558,7 +2595,7 @@ VpAlloc(U_LONG mx, char *szVal)
if(szVal[i] == '.') { /* xxx. */
++i;
ipf = i;
- while(v = szVal[i]) { /* get fraction part. */
+ while((v = szVal[i]) != 0) { /* get fraction part. */
if(!ISDIGIT(v)) break;
++i;
++nf;
@@ -2576,7 +2613,7 @@ VpAlloc(U_LONG mx, char *szVal)
ipe = i;
v = szVal[i];
if((v == '-') ||(v == '+')) ++i;
- while(v=szVal[i]) {
+ while((v=szVal[i])!=0) {
if(!ISDIGIT(v)) break;
++i;
++ne;
@@ -2596,6 +2633,7 @@ VpAlloc(U_LONG mx, char *szVal)
vp->MaxPrec = mx; /* set max precision */
VpSetZero(vp,sign);
VpCtoV(vp, &(szVal[ipn]), ni, &(szVal[ipf]), nf, &(szVal[ipe]), ne);
+ rb_str_resize(buf, 0);
return vp;
}
@@ -3590,7 +3628,7 @@ VPrint(FILE *fp, char *cntl_chr, Real *a)
nc += fprintf(fp, "0.");
n = a->Prec;
for(i=0;i < n;++i) {
- m = BASE1;
+ m = BASE1;
e = a->frac[i];
while(m) {
nn = e / m;
@@ -3879,7 +3917,7 @@ VpToFString(Real *a,char *psz,int fFmt,int fPlus)
* ne ... number of characters in exp_chr[],not including '+/-'.
*/
VP_EXPORT int
-VpCtoV(Real *a, char *int_chr, U_LONG ni, char *frac, U_LONG nf, char *exp_chr, U_LONG ne)
+VpCtoV(Real *a, const char *int_chr, U_LONG ni, const char *frac, U_LONG nf, const char *exp_chr, U_LONG ne)
{
U_LONG i, j, ind_a, ma, mi, me;
U_LONG loc;
@@ -4334,6 +4372,11 @@ VpMidRound(Real *y, int f, int nf)
nf += y->exponent*((int)BASE_FIG);
exptoadd=0;
if (nf < 0) {
+ /* rounding position too left(large). */
+ if((f!=VP_ROUND_CEIL) && (f!=VP_ROUND_FLOOR)) {
+ VpSetZero(y,VpGetSign(y)); /* truncate everything */
+ return 0;
+ }
exptoadd = -nf;
nf = 0;
}
@@ -4428,7 +4471,7 @@ VpLeftRound(Real *y, int f, int nf)
if(!VpHasVal(y)) return 0; /* Unable to round */
v = y->frac[0];
nf -= VpExponent(y)*BASE_FIG;
- while(v=v/10) nf--;
+ while((v /= 10) != 0) nf--;
nf += (BASE_FIG-1);
return VpMidRound(y,f,nf);
}
diff --git a/ext/bigdecimal/bigdecimal.h b/ext/bigdecimal/bigdecimal.h
index aabc551a76..4f77feab00 100644
--- a/ext/bigdecimal/bigdecimal.h
+++ b/ext/bigdecimal/bigdecimal.h
@@ -105,7 +105,7 @@ typedef struct {
VP_EXPORT Real *
VpNewRbClass(U_LONG mx,char *str,VALUE klass);
-VP_EXPORT Real *VpCreateRbObject(U_LONG mx,char *str);
+VP_EXPORT Real *VpCreateRbObject(U_LONG mx,const char *str);
VP_EXPORT U_LONG VpBaseFig(void);
VP_EXPORT U_LONG VpDblFig(void);
@@ -126,13 +126,13 @@ VP_EXPORT int VpIsRoundMode(unsigned long n);
VP_EXPORT unsigned long VpGetRoundMode(void);
VP_EXPORT unsigned long VpSetRoundMode(unsigned long n);
-VP_EXPORT int VpException(unsigned short f,char *str,int always);
+VP_EXPORT int VpException(unsigned short f,const char *str,int always);
VP_EXPORT int VpIsNegDoubleZero(double v);
-VP_EXPORT U_LONG VpNumOfChars(Real *vp,char *pszFmt);
+VP_EXPORT U_LONG VpNumOfChars(Real *vp,const char *pszFmt);
VP_EXPORT U_LONG VpInit(U_LONG BaseVal);
VP_EXPORT void *VpMemAlloc(U_LONG mb);
VP_EXPORT void VpFree(Real *pv);
-VP_EXPORT Real *VpAlloc(U_LONG mx, char *szVal);
+VP_EXPORT Real *VpAlloc(U_LONG mx, const char *szVal);
VP_EXPORT int VpAsgn(Real *c,Real *a,int isw);
VP_EXPORT int VpAddSub(Real *c,Real *a,Real *b,int operation);
VP_EXPORT int VpMult(Real *c,Real *a,Real *b);
@@ -143,7 +143,7 @@ VP_EXPORT void VpSzMantissa(Real *a,char *psz);
VP_EXPORT int VpToSpecialString(Real *a,char *psz,int fPlus);
VP_EXPORT void VpToString(Real *a,char *psz,int fFmt,int fPlus);
VP_EXPORT void VpToFString(Real *a,char *psz,int fFmt,int fPlus);
-VP_EXPORT int VpCtoV(Real *a,char *int_chr,U_LONG ni,char *frac,U_LONG nf,char *exp_chr,U_LONG ne);
+VP_EXPORT int VpCtoV(Real *a,const char *int_chr,U_LONG ni,const char *frac,U_LONG nf,const char *exp_chr,U_LONG ne);
VP_EXPORT int VpVtoD(double *d,S_LONG *e,Real *m);
VP_EXPORT void VpDtoV(Real *m,double d);
VP_EXPORT void VpItoV(Real *m,S_INT ival);
@@ -155,7 +155,7 @@ VP_EXPORT void VpFrac(Real *y,Real *x);
VP_EXPORT int VpPower(Real *y,Real *x,S_INT n);
/* VP constants */
-VP_EXPORT Real *VpOne();
+VP_EXPORT Real *VpOne(void);
/*
* ------------------
diff --git a/ext/bigdecimal/bigdecimal_en.html b/ext/bigdecimal/bigdecimal_en.html
index 02c88df43e..c2b86faef6 100644
--- a/ext/bigdecimal/bigdecimal_en.html
+++ b/ext/bigdecimal/bigdecimal_en.html
@@ -379,7 +379,7 @@ after every n digits for readability.
<CODE><PRE>
BigDecimal("0.1234567890123456789").to_s(10) # ==> "0.1234567890 123456789E0"
</PRE></CODE>
-n can be an string representing a positive integer number.
+n can be a string representing a positive integer number.
<CODE><PRE>
BigDecimal("0.1234567890123456789").to_s("10") # ==> "0.1234567890 123456789E0"
</PRE></CODE>
@@ -678,10 +678,9 @@ structure.
</DL>
<H3>Disadvantage of decimal representation</H3>
-Advantages stated so far can also be disadvantages if the input from outside is
- represented in binary.
-Translation error from decimal to binary or vice versa is inevitable.
-So,translation from Float(binary) to BigDecimal(decimal) is not alway done exactly.
+Because most computers have no internal decimal representaion.
+Once you use BigDecimal,you need to keep using it without
+considering computation cost if exact computation is required.
<H4>Which is the first input?</H4>
Because most people uses decimal notatin for numeric data representation,
diff --git a/ext/bigdecimal/bigdecimal_ja.html b/ext/bigdecimal/bigdecimal_ja.html
index 8fd95a6fe3..37bbcbbb09 100644
--- a/ext/bigdecimal/bigdecimal_ja.html
+++ b/ext/bigdecimal/bigdecimal_ja.html
@@ -676,10 +676,11 @@ exponent=1Asign=2 ‚Ȃ甒l‚ª 1234.56784321 ‚Å‚ ‚é‚̂͌©‚ê‚Î’¼‚®‚É•ª‚©‚è‚Ü‚·B
<H3>10i‚̃fƒƒŠƒbƒg</H3>
ŽÀ‚Í¡‚܂ł̃ƒŠƒbƒg‚ÍA‚»‚̂܂܃fƒƒŠƒbƒg‚É‚à‚È‚è‚Ü‚·B
-‚»‚à‚»‚àA10i‚ð2iA2i‚ð10i‚ɕϊ·‚·‚邿‚¤‚È‘€ì‚͕ϊ·Œë·
+‚»‚à‚»‚àA10i‚ð2i‚ɕϊ·‚·‚邿‚¤‚È‘€ì‚͕ϊ·Œë·
‚𔺂¤ê‡‚ð‰ñ”ð‚·‚é‚±‚Ƃ͂ł«‚Ü‚¹‚ñB
-Šù‚ÉŒvŽZ‹@“à•”‚ÉŽæ‚螂܂ꂽ2i”’l‚ð BigDecimal ‚Ì“à•”•\Œ»‚É
-•ÏŠ·‚·‚邯‚«‚ɂ͌뷂ª”ð‚¯‚ç‚ê‚È‚¢ê‡‚ª‚ ‚è‚Ü‚·B
+‘åŠT‚̃Rƒ“ƒsƒ…[ƒ^‚Í10i‚Ì“à•”•\Œ»‚ðŽ‚Á‚Ä‚¢‚È‚¢‚Ì‚ÅA
+BigDecimal ‚ð—˜—p‚µ‚Č뷖³‚µ‚ÌŒvŽZ‚ð‚·‚éꇂÍAŒvŽZ‘¬“x
+‚𖳎‹‚µ‚Ä‚àÅŒã‚܂ŠBigDecimal ‚ðŽg—p‘±‚¯‚é•K—v‚ª‚ ‚è‚Ü‚·B
<H3>ʼn‚͉½‚©H</H3>
Ž©•ª‚ÅŒvŽZ‚·‚邯‚«‚ɂ킴‚í‚´2i”‚ðŽg‚¤l‚͋ɂ߂Ă܂ê‚Å‚·B
diff --git a/ext/bigdecimal/extconf.rb b/ext/bigdecimal/extconf.rb
index a68a656044..0c8b98e4a3 100644
--- a/ext/bigdecimal/extconf.rb
+++ b/ext/bigdecimal/extconf.rb
@@ -1,2 +1,10 @@
require 'mkmf'
+
+base_fig = 0
+src = "(BASE * (BASE+1)) / BASE == (BASE+1)"
+while try_static_assert(src, nil, "-DBASE=10#{'0'*base_fig}UL")
+ base_fig += 1
+end
+$defs << "-DBASE=1#{'0'*base_fig}UL" << "-DBASE_FIG=#{base_fig}"
+
create_makefile('bigdecimal')
diff --git a/ext/curses/curses.c b/ext/curses/curses.c
index 4e84b0837f..b405d29b17 100644
--- a/ext/curses/curses.c
+++ b/ext/curses/curses.c
@@ -1,5 +1,5 @@
/* -*- C -*-
- * $Id: curses.c,v 1.24.2.8 2006/07/18 05:08:34 matz Exp $
+ * $Id$
*
* ext/curses/curses.c
*
@@ -141,6 +141,7 @@ curses_init_screen()
static VALUE
curses_close_screen()
{
+ curses_stdscr();
#ifdef HAVE_ISENDWIN
if (!isendwin())
#endif
@@ -167,6 +168,7 @@ static VALUE
curses_closed()
{
#ifdef HAVE_ISENDWIN
+ curses_stdscr();
if (isendwin()) {
return Qtrue;
}
@@ -355,6 +357,7 @@ static VALUE
curses_standout(obj)
VALUE obj;
{
+ curses_stdscr();
standout();
return Qnil;
}
@@ -364,6 +367,7 @@ static VALUE
curses_standend(obj)
VALUE obj;
{
+ curses_stdscr();
standend();
return Qnil;
}
@@ -429,6 +433,7 @@ curses_getstr(obj)
{
char rtn[1024]; /* This should be big enough.. I hope */
+ curses_stdscr();
rb_read_check(stdin);
#if defined(HAVE_GETNSTR)
getnstr(rtn,1023);
@@ -443,6 +448,7 @@ static VALUE
curses_delch(obj)
VALUE obj;
{
+ curses_stdscr();
delch();
return Qnil;
}
@@ -452,6 +458,7 @@ static VALUE
curses_deleteln(obj)
VALUE obj;
{
+ curses_stdscr();
#if defined(HAVE_DELETELN) || defined(deleteln)
deleteln();
#endif
@@ -463,6 +470,7 @@ static VALUE
curses_insertln(obj)
VALUE obj;
{
+ curses_stdscr();
#if defined(HAVE_INSERTLN) || defined(insertln)
insertln();
#endif
@@ -478,6 +486,7 @@ curses_keyname(obj, c)
#ifdef HAVE_KEYNAME
const char *name;
+ curses_stdscr();
name = keyname(NUM2INT(c));
if (name) {
return rb_str_new2(name);
@@ -506,6 +515,7 @@ curses_curs_set(VALUE obj, VALUE visibility)
{
#ifdef HAVE_CURS_SET
int n;
+ curses_stdscr();
return (n = curs_set(NUM2INT(visibility)) != ERR) ? INT2FIX(n) : Qnil;
#else
return Qnil;
@@ -517,6 +527,7 @@ curses_scrl(VALUE obj, VALUE n)
{
/* may have to raise exception on ERR */
#ifdef HAVE_SCRL
+ curses_stdscr();
return (scrl(NUM2INT(n)) == OK) ? Qtrue : Qfalse;
#else
return Qfalse;
@@ -528,6 +539,7 @@ curses_setscrreg(VALUE obj, VALUE top, VALUE bottom)
{
/* may have to raise exception on ERR */
#ifdef HAVE_SETSCRREG
+ curses_stdscr();
return (setscrreg(NUM2INT(top), NUM2INT(bottom)) == OK) ? Qtrue : Qfalse;
#else
return Qfalse;
@@ -537,6 +549,7 @@ curses_setscrreg(VALUE obj, VALUE top, VALUE bottom)
static VALUE
curses_attroff(VALUE obj, VALUE attrs)
{
+ curses_stdscr();
return window_attroff(rb_stdscr,attrs);
/* return INT2FIX(attroff(NUM2INT(attrs))); */
}
@@ -544,6 +557,7 @@ curses_attroff(VALUE obj, VALUE attrs)
static VALUE
curses_attron(VALUE obj, VALUE attrs)
{
+ curses_stdscr();
return window_attron(rb_stdscr,attrs);
/* return INT2FIX(attroff(NUM2INT(attrs))); */
}
@@ -551,6 +565,7 @@ curses_attron(VALUE obj, VALUE attrs)
static VALUE
curses_attrset(VALUE obj, VALUE attrs)
{
+ curses_stdscr();
return window_attrset(rb_stdscr,attrs);
/* return INT2FIX(attroff(NUM2INT(attrs))); */
}
@@ -559,6 +574,7 @@ static VALUE
curses_bkgdset(VALUE obj, VALUE ch)
{
#ifdef HAVE_BKGDSET
+ curses_stdscr();
bkgdset(NUM2CH(ch));
#endif
return Qnil;
@@ -568,6 +584,7 @@ static VALUE
curses_bkgd(VALUE obj, VALUE ch)
{
#ifdef HAVE_BKGD
+ curses_stdscr();
return (bkgd(NUM2CH(ch)) == OK) ? Qtrue : Qfalse;
#else
return Qfalse;
@@ -578,6 +595,7 @@ static VALUE
curses_resizeterm(VALUE obj, VALUE lin, VALUE col)
{
#if defined(HAVE_RESIZETERM)
+ curses_stdscr();
return (resizeterm(NUM2INT(lin),NUM2INT(col)) == OK) ? Qtrue : Qfalse;
#else
return Qnil;
@@ -589,6 +607,7 @@ static VALUE
curses_start_color(VALUE obj)
{
/* may have to raise exception on ERR */
+ curses_stdscr();
return (start_color() == OK) ? Qtrue : Qfalse;
}
@@ -596,6 +615,7 @@ static VALUE
curses_init_pair(VALUE obj, VALUE pair, VALUE f, VALUE b)
{
/* may have to raise exception on ERR */
+ curses_stdscr();
return (init_pair(NUM2INT(pair),NUM2INT(f),NUM2INT(b)) == OK) ? Qtrue : Qfalse;
}
@@ -603,6 +623,7 @@ static VALUE
curses_init_color(VALUE obj, VALUE color, VALUE r, VALUE g, VALUE b)
{
/* may have to raise exception on ERR */
+ curses_stdscr();
return (init_color(NUM2INT(color),NUM2INT(r),
NUM2INT(g),NUM2INT(b)) == OK) ? Qtrue : Qfalse;
}
@@ -610,12 +631,14 @@ curses_init_color(VALUE obj, VALUE color, VALUE r, VALUE g, VALUE b)
static VALUE
curses_has_colors(VALUE obj)
{
+ curses_stdscr();
return has_colors() ? Qtrue : Qfalse;
}
static VALUE
curses_can_change_color(VALUE obj)
{
+ curses_stdscr();
return can_change_color() ? Qtrue : Qfalse;
}
@@ -624,6 +647,7 @@ curses_color_content(VALUE obj, VALUE color)
{
short r,g,b;
+ curses_stdscr();
color_content(NUM2INT(color),&r,&g,&b);
return rb_ary_new3(3,INT2FIX(r),INT2FIX(g),INT2FIX(b));
}
@@ -633,6 +657,7 @@ curses_pair_content(VALUE obj, VALUE pair)
{
short f,b;
+ curses_stdscr();
pair_content(NUM2INT(pair),&f,&b);
return rb_ary_new3(2,INT2FIX(f),INT2FIX(b));
}
@@ -646,6 +671,7 @@ curses_color_pair(VALUE obj, VALUE attrs)
static VALUE
curses_pair_number(VALUE obj, VALUE attrs)
{
+ curses_stdscr();
return INT2FIX(PAIR_NUMBER(NUM2INT(attrs)));
}
#endif /* USE_COLOR */
@@ -681,6 +707,7 @@ curses_getmouse(VALUE obj)
struct mousedata *mdata;
VALUE val;
+ curses_stdscr();
val = Data_Make_Struct(cMouseEvent,struct mousedata,
0,curses_mousedata_free,mdata);
mdata->mevent = (MEVENT*)xmalloc(sizeof(MEVENT));
@@ -692,6 +719,7 @@ curses_ungetmouse(VALUE obj, VALUE mevent)
{
struct mousedata *mdata;
+ curses_stdscr();
GetMOUSE(mevent,mdata);
return (ungetmouse(mdata->mevent) == OK) ? Qtrue : Qfalse;
}
@@ -699,12 +727,14 @@ curses_ungetmouse(VALUE obj, VALUE mevent)
static VALUE
curses_mouseinterval(VALUE obj, VALUE interval)
{
+ curses_stdscr();
return mouseinterval(NUM2INT(interval)) ? Qtrue : Qfalse;
}
static VALUE
curses_mousemask(VALUE obj, VALUE mask)
{
+ curses_stdscr();
return INT2NUM(mousemask(NUM2UINT(mask),NULL));
}
@@ -728,6 +758,7 @@ static VALUE
curses_timeout(VALUE obj, VALUE delay)
{
#ifdef HAVE_TIMEOUT
+ curses_stdscr();
timeout(NUM2INT(delay));
return Qnil;
#else
@@ -739,6 +770,7 @@ static VALUE
curses_def_prog_mode(VALUE obj)
{
#ifdef HAVE_DEF_PROG_MODE
+ curses_stdscr();
return def_prog_mode() == OK ? Qtrue : Qfalse;
#else
rb_notimplement();
@@ -749,6 +781,7 @@ static VALUE
curses_reset_prog_mode(VALUE obj)
{
#ifdef HAVE_RESET_PROG_MODE
+ curses_stdscr();
return reset_prog_mode() == OK ? Qtrue : Qfalse;
#else
rb_notimplement();
@@ -1255,7 +1288,6 @@ window_color_set(VALUE obj, VALUE col)
GetWINDOW(obj, winp);
res = wcolor_set(winp->window, NUM2INT(col), NULL);
return (res == OK) ? Qtrue : Qfalse;
- return Qfalse;
}
#endif /* USE_COLOR */
diff --git a/ext/curses/extconf.rb b/ext/curses/extconf.rb
index 01fe971093..0124bbbf4a 100644
--- a/ext/curses/extconf.rb
+++ b/ext/curses/extconf.rb
@@ -20,7 +20,7 @@ end
if make
for f in %w(beep bkgd bkgdset curs_set deleteln doupdate flash getbkgd getnstr init isendwin keyname keypad resizeterm scrl set setscrreg ungetch wattroff wattron wattrset wbkgd wbkgdset wdeleteln wgetnstr wresize wscrl wsetscrreg def_prog_mode reset_prog_mode timeout wtimeout nodelay init_color wcolor_set)
- have_func(f)
+ have_func(f) || (have_macro(f, curses) && $defs.push(format("-DHAVE_%s", f.upcase)))
end
flag = "-D_XOPEN_SOURCE_EXTENDED"
src = "int test_var[(sizeof(char*)>sizeof(int))*2-1];"
diff --git a/ext/dbm/dbm.c b/ext/dbm/dbm.c
index 83e6a9893b..0247387fdc 100644
--- a/ext/dbm/dbm.c
+++ b/ext/dbm/dbm.c
@@ -2,8 +2,8 @@
dbm.c -
- $Author: usa $
- $Date: 2005/06/20 07:53:19 $
+ $Author$
+ $Date$
created at: Mon Jan 24 15:59:52 JST 1994
Copyright (C) 1995-2001 Yukihiro Matsumoto
@@ -812,5 +812,7 @@ Init_dbm()
#ifdef DB_VERSION_STRING
rb_define_const(rb_cDBM, "VERSION", rb_str_new2(DB_VERSION_STRING));
+#else
+ rb_define_const(rb_cDBM, "VERSION", rb_str_new2("unknown"));
#endif
}
diff --git a/ext/dbm/extconf.rb b/ext/dbm/extconf.rb
index 52ec688952..0074ab605b 100644
--- a/ext/dbm/extconf.rb
+++ b/ext/dbm/extconf.rb
@@ -2,9 +2,13 @@ require 'mkmf'
dir_config("dbm")
-dblib = with_config("dbm-type", nil)
+if dblib = with_config("dbm-type", nil)
+ dblib = dblib.split(/[ ,]+/)
+else
+ dblib = %w(db db2 db1 dbm gdbm gdbm_compat qdbm)
+end
-$dbm_conf_headers = {
+headers = {
"db" => ["db.h"],
"db1" => ["db1/ndbm.h", "db1.h", "ndbm.h"],
"db2" => ["db2/db.h", "db2.h", "db.h"],
@@ -14,48 +18,36 @@ $dbm_conf_headers = {
"qdbm" => ["relic.h"],
}
-def db_check(db)
- $dbm_conf_db_prefix = ""
- $dbm_conf_have_gdbm = false
- hsearch = ""
+def headers.db_check(db)
+ db_prefix = nil
+ have_gdbm = false
+ hsearch = nil
case db
when /^db2?$/
- $dbm_conf_db_prefix = "__db_n"
+ db_prefix = "__db_n"
hsearch = "-DDB_DBM_HSEARCH "
when "gdbm"
- $dbm_conf_have_gdbm = true
+ have_gdbm = true
when "gdbm_compat"
- $dbm_conf_have_gdbm = true
+ have_gdbm = true
have_library("gdbm") or return false
end
-
- if have_library(db, db_prefix("dbm_open")) || have_func(db_prefix("dbm_open"))
- for hdr in $dbm_conf_headers.fetch(db, ["ndbm.h"])
- if have_header(hdr.dup) and have_type("DBM", hdr.dup, hsearch)
- $defs << hsearch << '-DDBM_HDR="<'+hdr+'>"'
- return true
- end
- end
- end
- return false
-end
-
-def db_prefix(func)
- $dbm_conf_db_prefix+func
-end
-
-if dblib
- dbm_hdr = db_check(dblib)
-else
- dbm_hdr = %w(db db2 db1 dbm gdbm gdbm_compat qdbm).any? do |dblib|
- db_check(dblib)
+ db_prefix ||= ""
+
+ if (have_library(db, db_prefix+"dbm_open") || have_func(db_prefix+"dbm_open")) and
+ hdr = self.fetch(db, ["ndbm.h"]).find {|hdr| have_type("DBM", hdr, hsearch)}
+ have_func(db_prefix+"dbm_clearerr") unless have_gdbm
+ $defs << hsearch if hsearch
+ $defs << '-DDBM_HDR="<'+hdr+'>"'
+ true
+ else
+ false
end
end
-have_header("cdefs.h")
-have_header("sys/cdefs.h")
-if dbm_hdr and have_func(db_prefix("dbm_open"))
- have_func(db_prefix("dbm_clearerr")) unless $dbm_conf_have_gdbm
+if dblib.any? {|db| headers.db_check(db)}
+ have_header("cdefs.h")
+ have_header("sys/cdefs.h")
create_makefile("dbm")
end
diff --git a/ext/enumerator/.cvsignore b/ext/digest/bubblebabble/.cvsignore
index fc802ff1c2..4088712231 100644
--- a/ext/enumerator/.cvsignore
+++ b/ext/digest/bubblebabble/.cvsignore
@@ -1,2 +1,3 @@
Makefile
mkmf.log
+*.def
diff --git a/ext/digest/bubblebabble/bubblebabble.c b/ext/digest/bubblebabble/bubblebabble.c
new file mode 100644
index 0000000000..3a03ceced0
--- /dev/null
+++ b/ext/digest/bubblebabble/bubblebabble.c
@@ -0,0 +1,142 @@
+/************************************************
+
+ bubblebabble.c - BubbleBabble encoding support
+
+ $Author$
+ created at: Fri Oct 13 18:31:42 JST 2006
+
+ Copyright (C) 2006 Akinori MUSHA
+
+ $Id$
+
+************************************************/
+
+#include "ruby.h"
+#include "digest.h"
+
+static ID id_digest;
+
+static VALUE
+bubblebabble_str_new(VALUE str_digest)
+{
+ char *digest;
+ size_t digest_len;
+ VALUE str;
+ char *p;
+ int i, j, seed = 1;
+ static const char vowels[] = {
+ 'a', 'e', 'i', 'o', 'u', 'y'
+ };
+ static const char consonants[] = {
+ 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm', 'n',
+ 'p', 'r', 's', 't', 'v', 'z', 'x'
+ };
+
+ StringValue(str_digest);
+ digest = RSTRING_PTR(str_digest);
+ digest_len = RSTRING_LEN(str_digest);
+
+ if ((LONG_MAX - 2) / 3 < (digest_len | 1)) {
+ rb_raise(rb_eRuntimeError, "digest string too long");
+ }
+
+ str = rb_str_new(0, (digest_len | 1) * 3 + 2);
+ p = RSTRING_PTR(str);
+
+ i = j = 0;
+ p[j++] = 'x';
+
+ for (;;) {
+ unsigned char byte1, byte2;
+
+ if (i >= digest_len) {
+ p[j++] = vowels[seed % 6];
+ p[j++] = consonants[16];
+ p[j++] = vowels[seed / 6];
+ break;
+ }
+
+ byte1 = digest[i++];
+ p[j++] = vowels[(((byte1 >> 6) & 3) + seed) % 6];
+ p[j++] = consonants[(byte1 >> 2) & 15];
+ p[j++] = vowels[((byte1 & 3) + (seed / 6)) % 6];
+
+ if (i >= digest_len) {
+ break;
+ }
+
+ byte2 = digest[i++];
+ p[j++] = consonants[(byte2 >> 4) & 15];
+ p[j++] = '-';
+ p[j++] = consonants[byte2 & 15];
+
+ seed = (seed * 5 + byte1 * 7 + byte2) % 36;
+ }
+
+ p[j] = 'x';
+
+ return str;
+}
+
+/*
+ * call-seq:
+ * Digest.bubblebabble(string) -> bubblebabble_string
+ *
+ * Returns a BubbleBabble encoded version of a given _string_.
+ */
+static VALUE
+rb_digest_s_bubblebabble(VALUE klass, VALUE str)
+{
+ return bubblebabble_str_new(str);
+}
+
+/*
+ * call-seq:
+ * Digest::Class.bubblebabble(string, ...) -> hash_string
+ *
+ * Returns the BubbleBabble encoded hash value of a given _string_.
+ */
+static VALUE
+rb_digest_class_s_bubblebabble(int argc, VALUE *argv, VALUE klass)
+{
+ return bubblebabble_str_new(rb_funcall2(klass, id_digest, argc, argv));
+}
+
+/*
+ * call-seq:
+ * digest_obj.bubblebabble -> hash_string
+ *
+ * Returns the resulting hash value in a Bubblebabble encoded form.
+ */
+static VALUE
+rb_digest_instance_bubblebabble(VALUE self)
+{
+ return bubblebabble_str_new(rb_funcall(self, id_digest, 0));
+}
+
+/*
+ * This module adds some methods to Digest classes to perform
+ * BubbleBabble encoding.
+ */
+void
+Init_bubblebabble(void)
+{
+ VALUE mDigest, mDigest_Instance, cDigest_Class;
+
+ rb_require("digest");
+
+ mDigest = rb_path2class("Digest");
+ mDigest_Instance = rb_path2class("Digest::Instance");
+ cDigest_Class = rb_path2class("Digest::Class");
+
+ /* Digest::bubblebabble() */
+ rb_define_module_function(mDigest, "bubblebabble", rb_digest_s_bubblebabble, 1);
+
+ /* Digest::Class::bubblebabble() */
+ rb_define_singleton_method(cDigest_Class, "bubblebabble", rb_digest_class_s_bubblebabble, -1);
+
+ /* Digest::Instance#bubblebabble() */
+ rb_define_method(mDigest_Instance, "bubblebabble", rb_digest_instance_bubblebabble, 0);
+
+ id_digest = rb_intern("digest");
+}
diff --git a/ext/digest/bubblebabble/depend b/ext/digest/bubblebabble/depend
new file mode 100644
index 0000000000..b20148ded4
--- /dev/null
+++ b/ext/digest/bubblebabble/depend
@@ -0,0 +1,3 @@
+bubblebabble.o: bubblebabble.c $(srcdir)/../digest.h $(hdrdir)/ruby.h \
+ $(topdir)/config.h $(hdrdir)/defines.h $(hdrdir)/intern.h \
+ $(srcdir)/../defs.h
diff --git a/ext/digest/bubblebabble/extconf.rb b/ext/digest/bubblebabble/extconf.rb
new file mode 100644
index 0000000000..53cb83934a
--- /dev/null
+++ b/ext/digest/bubblebabble/extconf.rb
@@ -0,0 +1,6 @@
+require 'mkmf'
+
+$defs << "-DHAVE_CONFIG_H"
+$INCFLAGS << " -I$(srcdir)/.."
+
+create_makefile('digest/bubblebabble')
diff --git a/ext/digest/defs.h b/ext/digest/defs.h
index d51c627cf9..b9a3470e65 100644
--- a/ext/digest/defs.h
+++ b/ext/digest/defs.h
@@ -1,5 +1,5 @@
/* -*- C -*-
- * $Id: defs.h,v 1.7 2003/06/01 15:39:52 eban Exp $
+ * $Id$
*/
#ifndef DEFS_H
@@ -23,12 +23,8 @@
typedef unsigned int uint32_t;
# if SIZEOF_LONG == 8
typedef unsigned long uint64_t;
-# elif defined(__GNUC__)
- typedef unsigned long long uint64_t;
-# elif defined(_MSC_VER)
- typedef unsigned _int64 uint64_t;
-# elif defined(__BORLANDC__)
- typedef unsigned __int64 uint64_t;
+# elif SIZEOF_LONG_LONG == 8
+ typedef unsigned LONG_LONG uint64_t;
# else
# define NO_UINT64_T
# endif
diff --git a/ext/digest/digest.c b/ext/digest/digest.c
index 957fe4f6ea..52ec7d7750 100644
--- a/ext/digest/digest.c
+++ b/ext/digest/digest.c
@@ -2,157 +2,500 @@
digest.c -
- $Author: matz $
+ $Author$
created at: Fri May 25 08:57:27 JST 2001
Copyright (C) 1995-2001 Yukihiro Matsumoto
- Copyright (C) 2001 Akinori MUSHA
+ Copyright (C) 2001-2006 Akinori MUSHA
$RoughId: digest.c,v 1.16 2001/07/13 15:38:27 knu Exp $
- $Id: digest.c,v 1.14.2.2 2005/12/12 00:36:51 matz Exp $
+ $Id$
************************************************/
+#include "digest.h"
+
+static VALUE rb_mDigest;
+static VALUE rb_mDigest_Instance;
+static VALUE rb_cDigest_Class;
+static VALUE rb_cDigest_Base;
+
+static ID id_reset, id_update, id_finish, id_digest, id_hexdigest, id_digest_length;
+static ID id_metadata;
+
+RUBY_EXTERN void Init_digest_base(void);
+
/*
- * This module provides an interface to the following hash algorithms:
+ * Document-module: Digest
*
- * - the MD5 Message-Digest Algorithm by the RSA Data Security,
- * Inc., described in RFC 1321
- *
- * - the SHA-1 Secure Hash Algorithm by NIST (the US' National
- * Institute of Standards and Technology), described in FIPS PUB
- * 180-1.
+ * This module provides a framework for message digest libraries.
+ */
+
+static VALUE
+hexencode_str_new(VALUE str_digest)
+{
+ char *digest;
+ size_t digest_len;
+ int i;
+ VALUE str;
+ char *p;
+ static const char hex[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+
+ StringValue(str_digest);
+ digest = RSTRING_PTR(str_digest);
+ digest_len = RSTRING_LEN(str_digest);
+
+ if (LONG_MAX / 2 < digest_len) {
+ rb_raise(rb_eRuntimeError, "digest string too long");
+ }
+
+ str = rb_str_new(0, digest_len * 2);
+
+ for (i = 0, p = RSTRING_PTR(str); i < digest_len; i++) {
+ unsigned char byte = digest[i];
+
+ p[i + i] = hex[byte >> 4];
+ p[i + i + 1] = hex[byte & 0x0f];
+ }
+
+ return str;
+}
+
+/*
+ * call-seq:
+ * Digest.hexencode(string) -> hexencoded_string
*
- * - the SHA-256/384/512 Secure Hash Algorithm by NIST (the US'
- * National Institute of Standards and Technology), described in
- * FIPS PUB 180-2.
+ * Generates a hex-encoded version of a given _string_.
+ */
+static VALUE
+rb_digest_s_hexencode(VALUE klass, VALUE str)
+{
+ return hexencode_str_new(str);
+}
+
+/*
+ * Document-module: Digest::Instance
*
- * - the RIPEMD-160 cryptographic hash function, designed by Hans
- * Dobbertin, Antoon Bosselaers, and Bart Preneel.
+ * This module provides instance methods for a digest implementation
+ * object to calculate message digest values.
*/
-#include "digest.h"
+static void
+rb_digest_instance_method_unimpl(VALUE self, const char *method)
+{
+ VALUE klass = rb_obj_class(self);
-static VALUE mDigest, cDigest_Base;
-static ID id_metadata;
+ rb_raise(rb_eRuntimeError, "%s does not implement %s()",
+ rb_obj_classname(self), method);
+}
/*
- * Digest::Base
+ * call-seq:
+ * digest_obj.update(string) -> digest_obj
+ * digest_obj << string -> digest_obj
+ *
+ * Updates the digest using a given _string_ and returns self.
+ *
+ * The update() method and the left-shift operator are overridden by
+ * each implementation subclass. (One should be an alias for the
+ * other)
*/
+static VALUE
+rb_digest_instance_update(VALUE self, VALUE str)
+{
+ rb_digest_instance_method_unimpl(self, "update");
+}
-static algo_t *
-get_digest_base_metadata(klass)
- VALUE klass;
+/*
+ * call-seq:
+ * digest_obj.instance_eval { finish } -> digest_obj
+ *
+ * Finishes the digest and returns the resulting hash value.
+ *
+ * This method is overridden by each implementation subclass and often
+ * made private, because some of those subclasses may leave internal
+ * data uninitialized. Do not call this method from outside. Use
+ * #digest!() instead, which ensures that internal data be reset for
+ * security reasons.
+ */
+static VALUE
+rb_digest_instance_finish(VALUE self)
{
- VALUE obj;
- algo_t *algo;
+ rb_digest_instance_method_unimpl(self, "finish");
+}
- if (rb_cvar_defined(klass, id_metadata) == Qfalse) {
- rb_notimplement();
- }
+/*
+ * call-seq:
+ * digest_obj.reset -> digest_obj
+ *
+ * Resets the digest to the initial state and returns self.
+ *
+ * This method is overridden by each implementation subclass.
+ */
+static VALUE
+rb_digest_instance_reset(VALUE self)
+{
+ rb_digest_instance_method_unimpl(self, "reset");
+}
- obj = rb_cvar_get(klass, id_metadata);
+/*
+ * call-seq:
+ * digest_obj.new -> another_digest_obj
+ *
+ * Returns a new, initialized copy of the digest object. Equivalent
+ * to digest_obj.clone().reset().
+ */
+static VALUE
+rb_digest_instance_new(VALUE self)
+{
+ VALUE clone = rb_obj_clone(self);
+ rb_funcall(clone, id_reset, 0);
+ return clone;
+}
- Data_Get_Struct(obj, algo_t, algo);
+/*
+ * call-seq:
+ * digest_obj.digest -> string
+ * digest_obj.digest(string) -> string
+ *
+ * If none is given, returns the resulting hash value of the digest,
+ * keeping the digest's state.
+ *
+ * If a _string_ is given, returns the hash value for the given
+ * _string_, resetting the digest to the initial state before and
+ * after the process.
+ */
+static VALUE
+rb_digest_instance_digest(int argc, VALUE *argv, VALUE self)
+{
+ VALUE str, value;
+
+ if (rb_scan_args(argc, argv, "01", &str) > 0) {
+ rb_funcall(self, id_reset, 0);
+ rb_funcall(self, id_update, 1, str);
+ value = rb_funcall(self, id_finish, 0);
+ rb_funcall(self, id_reset, 0);
+ } else {
+ VALUE clone = rb_obj_clone(self);
+
+ value = rb_funcall(clone, id_finish, 0);
+ rb_funcall(clone, id_reset, 0);
+ }
- return algo;
+ return value;
}
-static VALUE rb_digest_base_alloc _((VALUE));
+/*
+ * call-seq:
+ * digest_obj.digest! -> string
+ *
+ * Returns the resulting hash value and resets the digest to the
+ * initial state.
+ */
static VALUE
-rb_digest_base_alloc(klass)
- VALUE klass;
+rb_digest_instance_digest_bang(VALUE self)
{
- algo_t *algo;
- VALUE obj;
- void *pctx;
+ VALUE value = rb_funcall(self, id_finish, 0);
+ rb_funcall(self, id_reset, 0);
- if (klass == cDigest_Base) {
- rb_raise(rb_eNotImpError, "Digest::Base is an abstract class");
+ return value;
+}
+
+/*
+ * call-seq:
+ * digest_obj.hexdigest -> string
+ * digest_obj.hexdigest(string) -> string
+ *
+ * If none is given, returns the resulting hash value of the digest in
+ * a hex-encoded form, keeping the digest's state.
+ *
+ * If a _string_ is given, returns the hash value for the given
+ * _string_ in a hex-encoded form, resetting the digest to the initial
+ * state before and after the process.
+ */
+static VALUE
+rb_digest_instance_hexdigest(int argc, VALUE *argv, VALUE self)
+{
+ VALUE str, value;
+
+ if (rb_scan_args(argc, argv, "01", &str) > 0) {
+ rb_funcall(self, id_reset, 0);
+ rb_funcall(self, id_update, 1, str);
+ value = rb_funcall(self, id_finish, 0);
+ rb_funcall(self, id_reset, 0);
+ } else {
+ VALUE clone = rb_obj_clone(self);
+
+ value = rb_funcall(clone, id_finish, 0);
+ rb_funcall(clone, id_reset, 0);
}
- algo = get_digest_base_metadata(klass);
+ return hexencode_str_new(value);
+}
- /* XXX: An uninitialized buffer leads ALGO_Equal() to fail */
- pctx = xcalloc(algo->ctx_size, 1);
- algo->init_func(pctx);
+/*
+ * call-seq:
+ * digest_obj.hexdigest! -> string
+ *
+ * Returns the resulting hash value and resets the digest to the
+ * initial state.
+ */
+static VALUE
+rb_digest_instance_hexdigest_bang(VALUE self)
+{
+ VALUE value = rb_funcall(self, id_finish, 0);
+ rb_funcall(self, id_reset, 0);
- obj = Data_Wrap_Struct(klass, 0, free, pctx);
+ return hexencode_str_new(value);
+}
- return obj;
+/*
+ * call-seq:
+ * digest_obj.to_s -> string
+ *
+ * Returns digest_obj.hexdigest().
+ */
+static VALUE
+rb_digest_instance_to_s(VALUE self)
+{
+ return rb_funcall(self, id_hexdigest, 0);
}
+/*
+ * call-seq:
+ * digest_obj.inspect -> string
+ *
+ * Creates a printable version of the digest object.
+ */
static VALUE
-rb_digest_base_s_digest(klass, str)
- VALUE klass;
+rb_digest_instance_inspect(VALUE self)
+{
VALUE str;
+ size_t digest_len = 32; /* about this size at least */
+ char *cname;
+
+ cname = rb_obj_classname(self);
+
+ /* #<Digest::ClassName: xxxxx...xxxx> */
+ str = rb_str_buf_new(2 + strlen(cname) + 2 + digest_len * 2 + 1);
+ rb_str_buf_cat2(str, "#<");
+ rb_str_buf_cat2(str, cname);
+ rb_str_buf_cat2(str, ": ");
+ rb_str_buf_append(str, rb_digest_instance_hexdigest(0, 0, self));
+ rb_str_buf_cat2(str, ">");
+ return str;
+}
+
+/*
+ * call-seq:
+ * digest_obj == another_digest_obj -> boolean
+ * digest_obj == string -> boolean
+ *
+ * If a string is given, checks whether it is equal to the hex-encoded
+ * hash value of the digest object. If another digest instance is
+ * given, checks whether they have the same hash value. Otherwise
+ * returns false.
+ */
+static VALUE
+rb_digest_instance_equal(VALUE self, VALUE other)
{
- algo_t *algo;
- void *pctx;
- size_t len;
- unsigned char *digest;
- volatile VALUE obj = rb_digest_base_alloc(klass);
+ VALUE str1, str2;
- algo = get_digest_base_metadata(klass);
- Data_Get_Struct(obj, void, pctx);
+ if (rb_obj_is_kind_of(other, rb_mDigest_Instance) == Qtrue) {
+ str1 = rb_digest_instance_digest(0, 0, self);
+ str2 = rb_digest_instance_digest(0, 0, other);
+ } else {
+ str1 = rb_digest_instance_to_s(self);
+ str2 = other;
+ }
- StringValue(str);
- algo->update_func(pctx, RSTRING(str)->ptr, RSTRING(str)->len);
+ /* never blindly assume that subclass methods return strings */
+ StringValue(str1);
+ StringValue(str2);
- len = algo->digest_len;
+ if (RSTRING_LEN(str1) == RSTRING_LEN(str2) &&
+ rb_str_cmp(str1, str2) == 0) {
+ return Qtrue;
+ }
+ return Qfalse;
+}
- digest = xmalloc(len);
- algo->final_func(digest, pctx);
+/*
+ * call-seq:
+ * digest_obj.digest_length -> integer
+ *
+ * Returns the length of the hash value of the digest.
+ *
+ * This method should be overridden by each implementation subclass.
+ * If not, digest_obj.digest().length() is returned.
+ */
+static VALUE
+rb_digest_instance_digest_length(VALUE self)
+{
+ /* subclasses really should redefine this method */
+ VALUE digest = rb_digest_instance_digest(0, 0, self);
- obj = rb_str_new(digest, len);
+ /* never blindly assume that #digest() returns a string */
+ StringValue(digest);
+ return INT2NUM(RSTRING_LEN(digest));
+}
- free(digest);
+/*
+ * call-seq:
+ * digest_obj.length -> integer
+ * digest_obj.size -> integer
+ *
+ * Returns digest_obj.digest_length().
+ */
+static VALUE
+rb_digest_instance_length(VALUE self)
+{
+ return rb_funcall(self, id_digest_length, 0);
+}
- return obj;
+/*
+ * call-seq:
+ * digest_obj.block_length -> integer
+ *
+ * Returns the block length of the digest.
+ *
+ * This method is overridden by each implementation subclass.
+ */
+static VALUE
+rb_digest_instance_block_length(VALUE self)
+{
+ rb_digest_instance_method_unimpl(self, "block_length");
}
+/*
+ * Document-class: Digest::Class
+ *
+ * This module stands as a base class for digest implementation
+ * classes.
+ */
+
+/*
+ * call-seq:
+ * Digest::Class.digest(string, *parameters) -> hash_string
+ *
+ * Returns the hash value of a given _string_. This is equivalent to
+ * Digest::Class.new(*parameters).digest(string), where extra
+ * _parameters_, if any, are passed through to the constructor and the
+ * _string_ is passed to #digest().
+ */
static VALUE
-rb_digest_base_s_hexdigest(klass, str)
- VALUE klass;
- VALUE str;
+rb_digest_class_s_digest(int argc, VALUE *argv, VALUE klass)
{
- algo_t *algo;
- void *pctx;
- size_t len;
- unsigned char *hexdigest;
- volatile VALUE obj = rb_digest_base_alloc(klass);
+ VALUE str;
+ volatile VALUE obj;
- algo = get_digest_base_metadata(klass);
- Data_Get_Struct(obj, void, pctx);
+ if (argc < 1) {
+ rb_raise(rb_eArgError, "no data given");
+ }
+
+ str = *argv++;
+ argc--;
StringValue(str);
- algo->update_func(pctx, RSTRING(str)->ptr, RSTRING(str)->len);
- len = algo->digest_len * 2;
+ obj = rb_obj_alloc(klass);
+ rb_obj_call_init(obj, argc, argv);
+
+ return rb_funcall(obj, id_digest, 1, str);
+}
+
+/*
+ * call-seq:
+ * Digest::Class.hexdigest(string[, ...]) -> hash_string
+ *
+ * Returns the hex-encoded hash value of a given _string_. This is
+ * almost equivalent to
+ * Digest.hexencode(Digest::Class.new(*parameters).digest(string)).
+ */
+static VALUE
+rb_digest_class_s_hexdigest(int argc, VALUE *argv, VALUE klass)
+{
+ return hexencode_str_new(rb_funcall2(klass, id_digest, argc, argv));
+}
+
+/*
+ * Document-class: Digest::Base
+ *
+ * This abstract class provides a common interface to message digest
+ * implementation classes written in C.
+ */
+
+static rb_digest_metadata_t *
+get_digest_base_metadata(VALUE klass)
+{
+ VALUE p;
+ VALUE obj;
+ rb_digest_metadata_t *algo;
+
+ for (p = klass; p; p = RCLASS(p)->super) {
+ if (rb_ivar_defined(p, id_metadata)) {
+ obj = rb_ivar_get(p, id_metadata);
+ break;
+ }
+ }
+
+ if (!p)
+ rb_raise(rb_eRuntimeError, "Digest::Base cannot be directly inherited in Ruby");
+
+ Data_Get_Struct(obj, rb_digest_metadata_t, algo);
+
+ switch (algo->api_version) {
+ case 2:
+ break;
+
+ /*
+ * put conversion here if possible when API is updated
+ */
+
+ default:
+ rb_raise(rb_eRuntimeError, "Incompatible digest API version");
+ }
+
+ return algo;
+}
- hexdigest = xmalloc(len + 1); /* +1 is for '\0' */
- algo->end_func(pctx, hexdigest);
+static VALUE
+rb_digest_base_alloc(VALUE klass)
+{
+ rb_digest_metadata_t *algo;
+ VALUE obj;
+ void *pctx;
- obj = rb_str_new(hexdigest, len);
+ if (klass == rb_cDigest_Base) {
+ rb_raise(rb_eNotImpError, "Digest::Base is an abstract class");
+ }
- free(hexdigest);
+ algo = get_digest_base_metadata(klass);
+
+ pctx = xmalloc(algo->ctx_size);
+ algo->init_func(pctx);
+
+ obj = Data_Wrap_Struct(klass, 0, free, pctx);
return obj;
}
+/* :nodoc: */
static VALUE
-rb_digest_base_copy(copy, obj)
- VALUE copy, obj;
+rb_digest_base_copy(VALUE copy, VALUE obj)
{
- algo_t *algo;
+ rb_digest_metadata_t *algo;
void *pctx1, *pctx2;
if (copy == obj) return copy;
+
rb_check_frozen(copy);
+
algo = get_digest_base_metadata(rb_obj_class(copy));
- if (algo != get_digest_base_metadata(rb_obj_class(obj))) {
- rb_raise(rb_eTypeError, "wrong argument class");
- }
+
Data_Get_Struct(obj, void, pctx1);
Data_Get_Struct(copy, void, pctx2);
memcpy(pctx2, pctx1, algo->ctx_size);
@@ -160,157 +503,149 @@ rb_digest_base_copy(copy, obj)
return copy;
}
+/* :nodoc: */
static VALUE
-rb_digest_base_update(self, str)
- VALUE self, str;
+rb_digest_base_reset(VALUE self)
{
- algo_t *algo;
+ rb_digest_metadata_t *algo;
void *pctx;
- StringValue(str);
algo = get_digest_base_metadata(rb_obj_class(self));
+
Data_Get_Struct(self, void, pctx);
- algo->update_func(pctx, RSTRING(str)->ptr, RSTRING(str)->len);
+ algo->init_func(pctx);
return self;
}
+/* :nodoc: */
static VALUE
-rb_digest_base_init(argc, argv, self)
- int argc;
- VALUE* argv;
- VALUE self;
+rb_digest_base_update(VALUE self, VALUE str)
{
- VALUE arg;
+ rb_digest_metadata_t *algo;
+ void *pctx;
+
+ algo = get_digest_base_metadata(rb_obj_class(self));
- rb_scan_args(argc, argv, "01", &arg);
+ Data_Get_Struct(self, void, pctx);
- if (!NIL_P(arg)) rb_digest_base_update(self, arg);
+ StringValue(str);
+ algo->update_func(pctx, (unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str));
return self;
}
+/* :nodoc: */
static VALUE
-rb_digest_base_digest(self)
- VALUE self;
+rb_digest_base_finish(VALUE self)
{
- algo_t *algo;
- void *pctx1, *pctx2;
- unsigned char *digest;
- size_t len;
+ rb_digest_metadata_t *algo;
+ void *pctx;
VALUE str;
algo = get_digest_base_metadata(rb_obj_class(self));
- Data_Get_Struct(self, void, pctx1);
-
- len = algo->ctx_size;
-
- pctx2 = xmalloc(len);
- memcpy(pctx2, pctx1, len);
- len = algo->digest_len;
-
- digest = xmalloc(len);
- algo->final_func(digest, pctx2);
+ Data_Get_Struct(self, void, pctx);
- str = rb_str_new(digest, len);
+ str = rb_str_new(0, algo->digest_len);
+ algo->finish_func(pctx, (unsigned char *)RSTRING_PTR(str));
- free(digest);
- free(pctx2);
+ /* avoid potential coredump caused by use of a finished context */
+ algo->init_func(pctx);
return str;
}
+/* :nodoc: */
static VALUE
-rb_digest_base_hexdigest(self)
- VALUE self;
+rb_digest_base_digest_length(VALUE self)
{
- algo_t *algo;
- void *pctx1, *pctx2;
- unsigned char *hexdigest;
- size_t len;
- VALUE str;
+ rb_digest_metadata_t *algo;
algo = get_digest_base_metadata(rb_obj_class(self));
- Data_Get_Struct(self, void, pctx1);
-
- len = algo->ctx_size;
-
- pctx2 = xmalloc(len);
- memcpy(pctx2, pctx1, len);
-
- len = algo->digest_len * 2;
- hexdigest = xmalloc(len + 1); /* +1 is for '\0' */
- algo->end_func(pctx2, hexdigest);
-
- str = rb_str_new(hexdigest, len);
-
- free(hexdigest);
- free(pctx2);
-
- return str;
+ return INT2NUM(algo->digest_len);
}
+/* :nodoc: */
static VALUE
-rb_digest_base_equal(self, other)
- VALUE self, other;
+rb_digest_base_block_length(VALUE self)
{
- algo_t *algo;
- VALUE klass;
- VALUE str1, str2;
-
- klass = rb_obj_class(self);
- algo = get_digest_base_metadata(klass);
+ rb_digest_metadata_t *algo;
- if (rb_obj_class(other) == klass) {
- void *pctx1, *pctx2;
-
- Data_Get_Struct(self, void, pctx1);
- Data_Get_Struct(other, void, pctx2);
-
- return algo->equal_func(pctx1, pctx2) ? Qtrue : Qfalse;
- }
-
- StringValue(other);
- str2 = other;
-
- if (RSTRING(str2)->len == algo->digest_len)
- str1 = rb_digest_base_digest(self);
- else
- str1 = rb_digest_base_hexdigest(self);
-
- if (RSTRING(str1)->len == RSTRING(str2)->len
- && rb_str_cmp(str1, str2) == 0)
- return Qtrue;
+ algo = get_digest_base_metadata(rb_obj_class(self));
- return Qfalse;
+ return INT2NUM(algo->block_len);
}
-/*
- * Init
- */
-
void
-Init_digest()
+Init_digest(void)
{
- mDigest = rb_define_module("Digest");
+ id_reset = rb_intern("reset");
+ id_update = rb_intern("update");
+ id_finish = rb_intern("finish");
+ id_digest = rb_intern("digest");
+ id_hexdigest = rb_intern("hexdigest");
+ id_digest_length = rb_intern("digest_length");
+
+ /*
+ * module Digest
+ */
+ rb_mDigest = rb_define_module("Digest");
+
+ /* module functions */
+ rb_define_module_function(rb_mDigest, "hexencode", rb_digest_s_hexencode, 1);
+
+ /*
+ * module Digest::Instance
+ */
+ rb_mDigest_Instance = rb_define_module_under(rb_mDigest, "Instance");
+
+ /* instance methods that should be overridden */
+ rb_define_method(rb_mDigest_Instance, "update", rb_digest_instance_update, 1);
+ rb_define_method(rb_mDigest_Instance, "<<", rb_digest_instance_update, 1);
+ rb_define_private_method(rb_mDigest_Instance, "finish", rb_digest_instance_finish, 0);
+ rb_define_method(rb_mDigest_Instance, "reset", rb_digest_instance_reset, 0);
+ rb_define_method(rb_mDigest_Instance, "digest_length", rb_digest_instance_digest_length, 0);
+ rb_define_method(rb_mDigest_Instance, "block_length", rb_digest_instance_block_length, 0);
+
+ /* instance methods that may be overridden */
+ rb_define_method(rb_mDigest_Instance, "==", rb_digest_instance_equal, 1);
+ rb_define_method(rb_mDigest_Instance, "inspect", rb_digest_instance_inspect, 0);
+
+ /* instance methods that need not usually be overridden */
+ rb_define_method(rb_mDigest_Instance, "new", rb_digest_instance_new, 0);
+ rb_define_method(rb_mDigest_Instance, "digest", rb_digest_instance_digest, -1);
+ rb_define_method(rb_mDigest_Instance, "digest!", rb_digest_instance_digest_bang, 0);
+ rb_define_method(rb_mDigest_Instance, "hexdigest", rb_digest_instance_hexdigest, -1);
+ rb_define_method(rb_mDigest_Instance, "hexdigest!", rb_digest_instance_hexdigest_bang, 0);
+ rb_define_method(rb_mDigest_Instance, "to_s", rb_digest_instance_to_s, 0);
+ rb_define_method(rb_mDigest_Instance, "length", rb_digest_instance_length, 0);
+ rb_define_method(rb_mDigest_Instance, "size", rb_digest_instance_length, 0);
+
+ /*
+ * class Digest::Class
+ */
+ rb_cDigest_Class = rb_define_class_under(rb_mDigest, "Class", rb_cObject);
+ rb_include_module(rb_cDigest_Class, rb_mDigest_Instance);
+
+ /* class methods */
+ rb_define_singleton_method(rb_cDigest_Class, "digest", rb_digest_class_s_digest, -1);
+ rb_define_singleton_method(rb_cDigest_Class, "hexdigest", rb_digest_class_s_hexdigest, -1);
- cDigest_Base = rb_define_class_under(mDigest, "Base", rb_cObject);
+ id_metadata = rb_intern("metadata");
- rb_define_alloc_func(cDigest_Base, rb_digest_base_alloc);
- rb_define_singleton_method(cDigest_Base, "digest", rb_digest_base_s_digest, 1);
- rb_define_singleton_method(cDigest_Base, "hexdigest", rb_digest_base_s_hexdigest, 1);
+ /* class Digest::Base < Digest::Class */
+ rb_cDigest_Base = rb_define_class_under(rb_mDigest, "Base", rb_cDigest_Class);
- rb_define_method(cDigest_Base, "initialize", rb_digest_base_init, -1);
- rb_define_method(cDigest_Base, "initialize_copy", rb_digest_base_copy, 1);
- rb_define_method(cDigest_Base, "update", rb_digest_base_update, 1);
- rb_define_method(cDigest_Base, "<<", rb_digest_base_update, 1);
- rb_define_method(cDigest_Base, "digest", rb_digest_base_digest, 0);
- rb_define_method(cDigest_Base, "hexdigest", rb_digest_base_hexdigest, 0);
- rb_define_method(cDigest_Base, "to_s", rb_digest_base_hexdigest, 0);
- rb_define_method(cDigest_Base, "==", rb_digest_base_equal, 1);
+ rb_define_alloc_func(rb_cDigest_Base, rb_digest_base_alloc);
- id_metadata = rb_intern("metadata");
+ rb_define_method(rb_cDigest_Base, "initialize_copy", rb_digest_base_copy, 1);
+ rb_define_method(rb_cDigest_Base, "reset", rb_digest_base_reset, 0);
+ rb_define_method(rb_cDigest_Base, "update", rb_digest_base_update, 1);
+ rb_define_method(rb_cDigest_Base, "<<", rb_digest_base_update, 1);
+ rb_define_private_method(rb_cDigest_Base, "finish", rb_digest_base_finish, 0);
+ rb_define_method(rb_cDigest_Base, "digest_length", rb_digest_base_digest_length, 0);
+ rb_define_method(rb_cDigest_Base, "block_length", rb_digest_base_block_length, 0);
}
diff --git a/ext/digest/digest.h b/ext/digest/digest.h
index 578be0a3c4..6e4906c859 100644
--- a/ext/digest/digest.h
+++ b/ext/digest/digest.h
@@ -1,32 +1,32 @@
/************************************************
- digest.c -
+ digest.h - header file for ruby digest modules
- $Author: knu $
+ $Author$
created at: Fri May 25 08:54:56 JST 2001
- Copyright (C) 2001 Akinori MUSHA
+ Copyright (C) 2001-2006 Akinori MUSHA
$RoughId: digest.h,v 1.3 2001/07/13 15:38:27 knu Exp $
- $Id: digest.h,v 1.1 2001/07/13 20:06:13 knu Exp $
+ $Id$
************************************************/
#include "ruby.h"
-typedef void (*hash_init_func_t) _((void *));
-typedef void (*hash_update_func_t) _((void *, unsigned char *, size_t));
-typedef void (*hash_end_func_t) _((void *, unsigned char *));
-typedef void (*hash_final_func_t) _((unsigned char *, void *));
-typedef int (*hash_equal_func_t) _((void *, void *));
+#define RUBY_DIGEST_API_VERSION 2
+
+typedef void (*rb_digest_hash_init_func_t)(void *);
+typedef void (*rb_digest_hash_update_func_t)(void *, unsigned char *, size_t);
+typedef void (*rb_digest_hash_finish_func_t)(void *, unsigned char *);
typedef struct {
+ int api_version;
size_t digest_len;
+ size_t block_len;
size_t ctx_size;
- hash_init_func_t init_func;
- hash_update_func_t update_func;
- hash_end_func_t end_func;
- hash_final_func_t final_func;
- hash_equal_func_t equal_func;
-} algo_t;
+ rb_digest_hash_init_func_t init_func;
+ rb_digest_hash_update_func_t update_func;
+ rb_digest_hash_finish_func_t finish_func;
+} rb_digest_metadata_t;
diff --git a/ext/digest/digest.txt b/ext/digest/digest.txt
deleted file mode 100644
index 4969a9da90..0000000000
--- a/ext/digest/digest.txt
+++ /dev/null
@@ -1,113 +0,0 @@
-.\" digest.txt - -*- Indented-Text -*- created at: Fri May 25 08:13:50 JST 2001
-$RoughId: digest.txt,v 1.9 2001/07/13 19:46:51 knu Exp $
-$Id: digest.txt,v 1.1 2001/07/13 20:06:13 knu Exp $
-
-** MD5(Class)
-
-A class to implement the MD5 Message-Digest Algorithm by RSA Data
-Security, Inc., described in RFC1321.
-
-Superclass: Digest::Base
-
-require 'digest/md5'
-
-** SHA1(Class)
-
-A class to implement the SHA-1 Secure Hash Algorithm by NIST (the US'
-National Institute of Standards and Technology), described in FIPS PUB
-180-1.
-
-Superclass: Digest::Base
-
-require 'digest/sha1'
-
-** SHA256(Class)
-** SHA384(Class)
-** SHA512(Class)
-
-Classes to implement the SHA-256/384/512 Secure Hash Algorithm(s) by
-NIST (the US' National Institute of Standards and Technology),
-described in FIPS PUB 180-2.
-
-Superclass: Digest::Base
-
-require 'digest/sha2'
-
-** RMD160(Class)
-
-A class to implement the RIPEMD-160 cryptographic hash function,
-designed by Hans Dobbertin, Antoon Bosselaers, and Bart Preneel.
-
-Superclass: Digest::Base
-
-require 'digest/rmd160'
-
-
-Those above classes provide a common interface as shown below.
-
-
-Class Methods:
-
- new([str])
-
- Creates a new digest object. If a string argument is given,
- it is added to the object. (see update.)
-
- digest(str)
-
- Immediately calculates and return the hash of the given
- strings as a string. Equivalent to new(str).digest.
-
- hexdigest(str)
-
- Immediately calculates and return the hash of the given
- strings as a string of hexadecimal digits. Equivalent to
- new(str).hexdigest.
-
-Methods:
-
- clone
-
- Creates a copy of the digest object.
-
- digest
-
- Returns the hash of the added strings as a string of 16 bytes
- for MD5, 20 bytes for SHA1 and RMD160, 32 bytes for SHA256, 48
- bytes for SHA384, and 64 bytes for SHA512.
-
- hexdigest
- to_s
-
- Returns the hash of the added strings as a string of 32
- hexadecimal digits for MD5, 40 hexadecimal digits for SHA1 and
- RMD160, 64 hexadecimal digits for SHA256, 96 hexadecimal
- digits for SHA384, and 128 hexadecimal digits for SHA512.
- This method is equal to:
-
- def hexdigest
- digest.unpack("H*")[0]
- end
-
- update(str)
- << str
-
- Appends the string str to the digest object. Repeated calls
- are equivalent to a single call with the concatenation of all
- the arguments, i.e. m.update(a); m.update(b) is equivalent to
- m.update(a + b) and m << a << b is equivalent to m << a + b.
-
- == md
-
- Checks if the object is equal to the given digest object.
-
- == str
-
- Regards the value as either a digest value or a hexdigest
- value (depending on the length) and checks if the object is
- equal to the given string.
-
--------------------------------------------------------
-Local variables:
-fill-column: 70
-end:
diff --git a/ext/digest/digest.txt.ja b/ext/digest/digest.txt.ja
deleted file mode 100644
index 7078c83573..0000000000
--- a/ext/digest/digest.txt.ja
+++ /dev/null
@@ -1,111 +0,0 @@
-.\" digest.txt.ja - -*- Indented-Text -*- created at: Fri May 25 08:22:19 JST 2001
-$RoughId: digest.txt.jp,v 1.8 2001/07/13 15:38:27 knu Exp $
-$Id: digest.txt.ja,v 1.1 2001/07/19 05:42:07 knu Exp $
-
-** MD5(¥¯¥é¥¹)
-
-RFC1321¤Ëµ­½Ò¤µ¤ì¤Æ¤¤¤ëRSA Data Security, Inc. ¤Î MD5 Message-Digest
-Algorithm¤ò¼ÂÁõ¤¹¤ë¥¯¥é¥¹¡£
-
-Superclass: Digest::Base
-
-require 'digest/md5'
-
-** SHA1(¥¯¥é¥¹)
-
-FIPS PUB 180-1¤Ëµ­½Ò¤µ¤ì¤Æ¤¤¤ëNIST (the US' National Institute of
-Standards and Technology) ¤Î SHA-1 Secure Hash Algorithm¤ò¼ÂÁõ¤¹¤ë¥¯¥é¥¹¡£
-
-Superclass: Digest::Base
-
-require 'digest/sha1'
-
-** SHA256(¥¯¥é¥¹)
-** SHA384(¥¯¥é¥¹)
-** SHA512(¥¯¥é¥¹)
-
-FIPS PUB 180-2¤Ëµ­½Ò¤µ¤ì¤Æ¤¤¤ëNIST (the US' National Institute of
-Standards and Technology) ¤Î SHA-256/384/512 Secure Hash Algorithm¤ò
-¼ÂÁõ¤¹¤ë¥¯¥é¥¹¡£
-
-Superclass: Digest::Base
-
-require 'digest/sha2'
-
-** RMD160(¥¯¥é¥¹)
-
-Hans Dobbertin, Antoon Bosselaers, Bart Preneel ¤Ë¤è¤Ã¤ÆÀ߷פµ¤ì¤¿
-RIPEMD-160 ¥Ï¥Ã¥·¥å´Ø¿ô¤ò¼ÂÁõ¤¹¤ë¥¯¥é¥¹¡£
-
-Superclass: Digest::Base
-
-require 'digest/rmd160'
-
-
-¤³¤ì¤é¤Î¥¯¥é¥¹¤Ï°Ê²¼¤Î¤è¤¦¤Ê¶¦Ä̤Υ¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤òÄ󶡤¹¤ë¡£
-
-
-Class Methods:
-
- new([str])
-
- ¿·¤·¤¤¥À¥¤¥¸¥§¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤òÀ¸À®¤¹¤ë¡¥Ê¸»úÎó°ú¿ô¤¬Í¿¤¨¤é¤ì¤ë
- ¤È¤½¤ì¤òÄɲ乤ë(see update)¡£
-
- digest(str)
-
- Í¿¤¨¤é¤ì¤¿Ê¸»úÎó¤ËÂФ¹¤ë¥Ï¥Ã¥·¥åÃͤòʸ»úÎó¤ÇÊÖ¤¹¡£
- new(str).digest ¤ÈÅù²Á¡£
-
- hexdigest(str)
-
- Í¿¤¨¤é¤ì¤¿Ê¸»úÎó¤ËÂФ¹¤ë¥Ï¥Ã¥·¥åÃͤò¡¢ASCII¥³¡¼¥É¤ò»È¤Ã¤Æ
- 16¿Ê¿ô¤ÎÎó¤ò¼¨¤¹Ê¸»úÎó¤Ë¥¨¥ó¥³¡¼¥É¤·¤ÆÊÖ¤¹¡£
- new(str).hexdigest ¤ÈÅù²Á¡£
-
-Methods:
-
- clone
-
- ¥À¥¤¥¸¥§¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤ÎÊ£À½¤òºî¤ë¡£
-
- digest
-
- º£¤Þ¤Ç¤ËÄɲä·¤¿Ê¸»úÎó¤ËÂФ¹¤ë¥Ï¥Ã¥·¥åÃͤòʸ»úÎó¤ÇÊÖ¤¹¡£MD5¤Ç¤Ï
- 16¥Ð¥¤¥ÈĹ¡¢SHA1¤ª¤è¤ÓRMD160¤Ç¤Ï20¥Ð¥¤¥ÈĹ¡¢SHA256¤Ç¤Ï32¥Ð¥¤¥ÈĹ¡¢
- SHA384¤Ç¤Ï48¥Ð¥¤¥ÈĹ¡¢SHA512¤Ç¤Ï64¥Ð¥¤¥ÈĹ¤È¤Ê¤ë¡£
-
- hexdigest
- to_s
-
- º£¤Þ¤Ç¤ËÄɲä·¤¿Ê¸»úÎó¤ËÂФ¹¤ë¥Ï¥Ã¥·¥åÃͤò¡¢ASCII¥³¡¼¥É¤ò»È¤Ã¤Æ
- 16¿Ê¿ô¤ÎÎó¤ò¼¨¤¹Ê¸»úÎó¤Ë¥¨¥ó¥³¡¼¥É¤·¤ÆÊÖ¤¹¡£MD5¤Ç¤Ï32¥Ð¥¤¥ÈĹ¡¢
- SHA1¤ª¤è¤ÓRMD160¤Ç¤Ï40¥Ð¥¤¥ÈĹ¡¢SHA256¤Ç¤Ï64¥Ð¥¤¥ÈĹ¡¢SHA384¤Ç¤Ï
- 96¥Ð¥¤¥ÈĹ¡¢SHA512¤Ç¤Ï128¥Ð¥¤¥ÈĹ¤È¤Ê¤ë¡£Ruby¤Ç½ñ¤¯¤È°Ê²¼¤ÈƱ¤¸¡£
-
- def hexdigest
- digest.unpack("H*")[0]
- end
-
- update(str)
- << str
-
- ʸ»úÎó¤òÄɲ乤롣ʣ¿ô²óupdate¤ò¸Æ¤Ö¤³¤È¤Ïʸ»úÎó¤òÏ¢·ë¤·¤Æ
- update¤ò¸Æ¤Ö¤³¤È¤ÈÅù¤·¤¤¡£¤¹¤Ê¤ï¤Á m.update(a); m.update(b) ¤Ï
- m.update(a + b) ¤È¡¢ m << a << b ¤Ï m << a + b ¤È¤½¤ì¤¾¤ìÅù²Á
- ¤Ç¤¢¤ë¡£
-
- == md
-
- Í¿¤¨¤é¤ì¤¿¥À¥¤¥¸¥§¥¹¥È¥ª¥Ö¥¸¥§¥¯¥È¤ÈÈæ³Ó¤¹¤ë¡£
-
- == str
-
- Í¿¤¨¤é¤ì¤¿Ê¸»úÎó¤ò digest ÃÍ¡¢¤â¤·¤¯¤Ï hexdigest ÃͤÈÈæ³Ó¤¹¤ë¡£
- ¤¤¤º¤ì¤ÎÃͤȸ«¤ë¤«¤ÏÍ¿¤¨¤é¤ì¤¿Ê¸»úÎó¤ÎŤµ¤Ë¤è¤Ã¤Æ¼«Æ°È½ÊÌ
- ¤µ¤ì¤ë¡£
-
--------------------------------------------------------
-Local variables:
-fill-column: 70
-end:
diff --git a/ext/digest/extconf.rb b/ext/digest/extconf.rb
index 3e35bf5064..cf9127ecc0 100644
--- a/ext/digest/extconf.rb
+++ b/ext/digest/extconf.rb
@@ -1,6 +1,10 @@
# $RoughId: extconf.rb,v 1.6 2001/07/13 15:38:27 knu Exp $
-# $Id: extconf.rb,v 1.1 2001/07/13 20:06:13 knu Exp $
+# $Id$
require "mkmf"
+$INSTALLFILES = {
+ "digest.h" => "$(RUBYARCHDIR)"
+}
+
create_makefile("digest")
diff --git a/ext/digest/lib/digest.rb b/ext/digest/lib/digest.rb
new file mode 100644
index 0000000000..0c4ee3c2cc
--- /dev/null
+++ b/ext/digest/lib/digest.rb
@@ -0,0 +1,50 @@
+require 'digest.so'
+
+module Digest
+ def self.const_missing(name)
+ case name
+ when :SHA256, :SHA384, :SHA512
+ lib = 'digest/sha2.so'
+ else
+ lib = File.join('digest', name.to_s.downcase)
+ end
+
+ begin
+ require lib
+ rescue LoadError => e
+ raise LoadError, "library not found for class Digest::#{name} -- #{lib}", caller(1)
+ end
+ unless Digest.const_defined?(name)
+ raise NameError, "uninitialized constant Digest::#{name}", caller(1)
+ end
+ Digest.const_get(name)
+ end
+
+ class ::Digest::Class
+ # creates a digest object and reads a given file, _name_.
+ #
+ # p Digest::SHA256.file("X11R6.8.2-src.tar.bz2").hexdigest
+ # # => "f02e3c85572dc9ad7cb77c2a638e3be24cc1b5bea9fdbb0b0299c9668475c534"
+ def self.file(name)
+ new.file(name)
+ end
+ end
+
+ module Instance
+ # updates the digest with the contents of a given file _name_ and
+ # returns self.
+ def file(name)
+ File.open(name, "rb") {|f|
+ buf = ""
+ while f.read(16384, buf)
+ update buf
+ end
+ }
+ self
+ end
+ end
+end
+
+def Digest(name)
+ Digest.const_get(name)
+end
diff --git a/ext/digest/lib/md5.rb b/ext/digest/lib/md5.rb
index 6867fdc71b..c399f2de1d 100644
--- a/ext/digest/lib/md5.rb
+++ b/ext/digest/lib/md5.rb
@@ -1,14 +1,23 @@
# just for compatibility; requiring "md5" is obsoleted
#
# $RoughId: md5.rb,v 1.4 2001/07/13 15:38:27 knu Exp $
-# $Id: md5.rb,v 1.1 2001/07/13 20:06:14 knu Exp $
+# $Id$
require 'digest/md5'
-MD5 = Digest::MD5
+class MD5 < Digest::MD5
+ class << self
+ alias orig_new new
+ def new(str = nil)
+ if str
+ orig_new.update(str)
+ else
+ orig_new
+ end
+ end
-class MD5
- def self.md5(*args)
- new(*args)
+ def md5(*args)
+ new(*args)
+ end
end
end
diff --git a/ext/digest/lib/sha1.rb b/ext/digest/lib/sha1.rb
index 12fb5cdfa4..4446e12e8d 100644
--- a/ext/digest/lib/sha1.rb
+++ b/ext/digest/lib/sha1.rb
@@ -1,14 +1,23 @@
# just for compatibility; requiring "sha1" is obsoleted
#
# $RoughId: sha1.rb,v 1.4 2001/07/13 15:38:27 knu Exp $
-# $Id: sha1.rb,v 1.1 2001/07/13 20:06:14 knu Exp $
+# $Id$
require 'digest/sha1'
-SHA1 = Digest::SHA1
+class SHA1 < Digest::SHA1
+ class << self
+ alias orig_new new
+ def new(str = nil)
+ if str
+ orig_new.update(str)
+ else
+ orig_new
+ end
+ end
-class SHA1
- def self.sha1(*args)
- new(*args)
+ def sha1(*args)
+ new(*args)
+ end
end
end
diff --git a/ext/digest/md5/extconf.rb b/ext/digest/md5/extconf.rb
index ea29c9c5f8..018f8ccb02 100644
--- a/ext/digest/md5/extconf.rb
+++ b/ext/digest/md5/extconf.rb
@@ -1,5 +1,5 @@
# $RoughId: extconf.rb,v 1.3 2001/08/14 19:54:51 knu Exp $
-# $Id: extconf.rb,v 1.4.2.2 2006/05/25 23:44:05 nobu Exp $
+# $Id$
require "mkmf"
@@ -24,4 +24,6 @@ have_header("inttypes.h")
have_header("unistd.h")
+$preload = %w[digest]
+
create_makefile("digest/md5")
diff --git a/ext/digest/md5/md5.c b/ext/digest/md5/md5.c
index ed32cf95c1..993bc47a06 100644
--- a/ext/digest/md5/md5.c
+++ b/ext/digest/md5/md5.c
@@ -41,9 +41,15 @@
1999-05-03 lpd Original version.
*/
+/*
+ This code was modified for use in Ruby.
+
+ - Akinori MUSHA <knu@idaemons.org>
+ */
+
/*$OrigId: md5c.c,v 1.2 2001/03/26 08:57:14 matz Exp $ */
/*$RoughId: md5.c,v 1.2 2001/07/13 19:48:41 knu Exp $ */
-/*$Id: md5.c,v 1.1 2001/07/13 20:06:14 knu Exp $ */
+/*$Id$ */
#include "md5.h"
@@ -391,7 +397,7 @@ MD5_Update(MD5_CTX *pms, const uint8_t *data, size_t nbytes)
}
void
-MD5_Final(uint8_t *digest, MD5_CTX *pms)
+MD5_Finish(MD5_CTX *pms, uint8_t *digest)
{
static const uint8_t pad[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -412,21 +418,3 @@ MD5_Final(uint8_t *digest, MD5_CTX *pms)
for (i = 0; i < 16; ++i)
digest[i] = (uint8_t)(pms->state[i >> 2] >> ((i & 3) << 3));
}
-
-void
-MD5_End(MD5_CTX *pctx, uint8_t *hexdigest)
-{
- unsigned char digest[16];
- size_t i;
-
- MD5_Final(digest, pctx);
-
- for (i = 0; i < 16; i++)
- sprintf(hexdigest + i * 2, "%02x", digest[i]);
-}
-
-int MD5_Equal(MD5_CTX* pctx1, MD5_CTX* pctx2) {
- return memcmp(pctx1->count, pctx2->count, sizeof(pctx1->count)) == 0
- && memcmp(pctx1->state, pctx2->state, sizeof(pctx1->state)) == 0
- && memcmp(pctx1->buffer, pctx2->buffer, sizeof(pctx1->buffer)) == 0;
-}
diff --git a/ext/digest/md5/md5.h b/ext/digest/md5/md5.h
index 736e034512..f4580ef5e7 100644
--- a/ext/digest/md5/md5.h
+++ b/ext/digest/md5/md5.h
@@ -41,7 +41,7 @@
/* $OrigId: md5.h,v 1.2 2001/03/26 08:57:14 matz Exp $ */
/* $RoughId: md5.h,v 1.3 2002/02/24 08:14:31 knu Exp $ */
-/* $Id: md5.h,v 1.2 2002/02/24 08:20:22 knu Exp $ */
+/* $Id$ */
#ifndef MD5_INCLUDED
# define MD5_INCLUDED
@@ -63,18 +63,15 @@ typedef struct md5_state_s {
} MD5_CTX;
#ifdef RUBY
+/* avoid name clash */
#define MD5_Init rb_Digest_MD5_Init
#define MD5_Update rb_Digest_MD5_Update
-#define MD5_Final rb_Digest_MD5_Final
-#define MD5_End rb_Digest_MD5_End
-#define MD5_Equal rb_Digest_MD5_Equal
+#define MD5_Finish rb_Digest_MD5_Finish
#endif
void MD5_Init _((MD5_CTX *pms));
void MD5_Update _((MD5_CTX *pms, const uint8_t *data, size_t nbytes));
-void MD5_Final _((uint8_t *digest, MD5_CTX *pms));
-void MD5_End _((MD5_CTX *pctx, uint8_t *hexdigest));
-int MD5_Equal _((MD5_CTX *pctx1, MD5_CTX *pctx2));
+void MD5_Finish _((MD5_CTX *pms, uint8_t *digest));
#define MD5_BLOCK_LENGTH 64
#define MD5_DIGEST_LENGTH 16
diff --git a/ext/digest/md5/md5init.c b/ext/digest/md5/md5init.c
index 52f5de540f..17658f4fce 100644
--- a/ext/digest/md5/md5init.c
+++ b/ext/digest/md5/md5init.c
@@ -1,5 +1,5 @@
/* $RoughId: md5init.c,v 1.2 2001/07/13 19:49:10 knu Exp $ */
-/* $Id: md5init.c,v 1.5 2002/09/26 16:27:23 knu Exp $ */
+/* $Id$ */
#include "digest.h"
#if defined(HAVE_OPENSSL_MD5_H)
@@ -8,28 +8,33 @@
#include "md5.h"
#endif
-static algo_t md5 = {
+static rb_digest_metadata_t md5 = {
+ RUBY_DIGEST_API_VERSION,
MD5_DIGEST_LENGTH,
+ MD5_BLOCK_LENGTH,
sizeof(MD5_CTX),
- (hash_init_func_t)MD5_Init,
- (hash_update_func_t)MD5_Update,
- (hash_end_func_t)MD5_End,
- (hash_final_func_t)MD5_Final,
- (hash_equal_func_t)MD5_Equal,
+ (rb_digest_hash_init_func_t)MD5_Init,
+ (rb_digest_hash_update_func_t)MD5_Update,
+ (rb_digest_hash_finish_func_t)MD5_Finish,
};
+/*
+ * A class for calculating message digests using the MD5
+ * Message-Digest Algorithm by RSA Data Security, Inc., described in
+ * RFC1321.
+ */
void
Init_md5()
{
VALUE mDigest, cDigest_Base, cDigest_MD5;
- rb_require("digest.so");
+ rb_require("digest");
mDigest = rb_path2class("Digest");
cDigest_Base = rb_path2class("Digest::Base");
cDigest_MD5 = rb_define_class_under(mDigest, "MD5", cDigest_Base);
- rb_cvar_set(cDigest_MD5, rb_intern("metadata"),
- Data_Wrap_Struct(rb_cObject, 0, 0, &md5), Qtrue);
+ rb_ivar_set(cDigest_MD5, rb_intern("metadata"),
+ Data_Wrap_Struct(rb_cObject, 0, 0, &md5));
}
diff --git a/ext/digest/md5/md5ossl.c b/ext/digest/md5/md5ossl.c
index 4af7d19ba5..d94ae2cd2f 100644
--- a/ext/digest/md5/md5ossl.c
+++ b/ext/digest/md5/md5ossl.c
@@ -1,30 +1,9 @@
-/* $Id: md5ossl.c,v 1.2 2003/01/06 11:47:53 knu Exp $ */
+/* $Id$ */
#include "md5ossl.h"
-#include <sys/types.h>
-#include <stdio.h>
-#include <string.h>
void
-MD5_End(MD5_CTX *pctx, unsigned char *hexdigest)
+MD5_Finish(MD5_CTX *pctx, unsigned char *digest)
{
- unsigned char digest[16];
- size_t i;
-
MD5_Final(digest, pctx);
-
- for (i = 0; i < 16; i++)
- sprintf(hexdigest + i * 2, "%02x", digest[i]);
-}
-
-int
-MD5_Equal(MD5_CTX* pctx1, MD5_CTX* pctx2) {
- return pctx1->num == pctx2->num
- && pctx1->A == pctx2->A
- && pctx1->B == pctx2->B
- && pctx1->C == pctx2->C
- && pctx1->D == pctx2->D
- && pctx1->Nl == pctx2->Nl
- && pctx1->Nh == pctx2->Nh
- && memcmp(pctx1->data, pctx2->data, sizeof(pctx1->data)) == 0;
}
diff --git a/ext/digest/md5/md5ossl.h b/ext/digest/md5/md5ossl.h
index 401ef3418d..1680c4f5c9 100644
--- a/ext/digest/md5/md5ossl.h
+++ b/ext/digest/md5/md5ossl.h
@@ -1,4 +1,4 @@
-/* $Id: md5ossl.h,v 1.1.2.1 2005/08/30 10:43:34 gotoyuzo Exp $ */
+/* $Id$ */
#ifndef MD5OSSL_H_INCLUDED
#define MD5OSSL_H_INCLUDED
@@ -6,7 +6,8 @@
#include <stddef.h>
#include <openssl/md5.h>
-void MD5_End(MD5_CTX *pctx, unsigned char *hexdigest);
-int MD5_Equal(MD5_CTX *pctx1, MD5_CTX *pctx2);
+#define MD5_BLOCK_LENGTH MD5_CBLOCK
+
+void MD5_Finish(MD5_CTX *pctx, unsigned char *digest);
#endif
diff --git a/ext/digest/rmd160/depend b/ext/digest/rmd160/depend
index 0ca79c5f40..a21d7188dc 100644
--- a/ext/digest/rmd160/depend
+++ b/ext/digest/rmd160/depend
@@ -1,7 +1,5 @@
rmd160.o: rmd160.c rmd160.h $(srcdir)/../defs.h $(hdrdir)/ruby.h \
$(topdir)/config.h $(hdrdir)/defines.h $(hdrdir)/intern.h
-rmd160hl.o: rmd160hl.c rmd160.h $(srcdir)/../defs.h $(hdrdir)/ruby.h \
- $(topdir)/config.h $(hdrdir)/defines.h $(hdrdir)/intern.h
rmd160init.o: rmd160init.c $(srcdir)/../digest.h $(hdrdir)/ruby.h \
$(topdir)/config.h $(hdrdir)/defines.h $(hdrdir)/intern.h \
rmd160.h $(srcdir)/../defs.h
diff --git a/ext/digest/rmd160/extconf.rb b/ext/digest/rmd160/extconf.rb
index 232a3a5e06..09359944f2 100644
--- a/ext/digest/rmd160/extconf.rb
+++ b/ext/digest/rmd160/extconf.rb
@@ -1,5 +1,5 @@
# $RoughId: extconf.rb,v 1.3 2001/08/14 19:54:51 knu Exp $
-# $Id: extconf.rb,v 1.4.2.2 2006/05/25 23:44:05 nobu Exp $
+# $Id$
require "mkmf"
@@ -14,7 +14,7 @@ if !with_config("bundled-rmd160") &&
have_library("crypto") && have_header("openssl/ripemd.h")
$objs << "rmd160ossl.#{$OBJEXT}"
else
- $objs << "rmd160.#{$OBJEXT}" << "rmd160hl.#{$OBJEXT}"
+ $objs << "rmd160.#{$OBJEXT}"
end
have_header("sys/cdefs.h")
@@ -23,4 +23,6 @@ have_header("inttypes.h")
have_header("unistd.h")
+$preload = %w[digest]
+
create_makefile("digest/rmd160")
diff --git a/ext/digest/rmd160/rmd160.c b/ext/digest/rmd160/rmd160.c
index 9562a6fe67..88918728cd 100644
--- a/ext/digest/rmd160/rmd160.c
+++ b/ext/digest/rmd160/rmd160.c
@@ -1,6 +1,6 @@
/* $NetBSD: rmd160.c,v 1.1.1.1 2001/03/06 11:21:05 agc Exp $ */
/* $RoughId: rmd160.c,v 1.2 2001/07/13 19:49:10 knu Exp $ */
-/* $Id: rmd160.c,v 1.1 2001/07/13 20:06:14 knu Exp $ */
+/* $Id$ */
/********************************************************************\
*
@@ -409,7 +409,7 @@ RMD160_Update(RMD160_CTX *context, const uint8_t *data, size_t nbytes)
/********************************************************************/
void
-RMD160_Final(uint8_t digest[20], RMD160_CTX *context)
+RMD160_Finish(RMD160_CTX *context, uint8_t digest[20])
{
uint32_t i;
uint32_t X[16];
@@ -454,11 +454,4 @@ RMD160_Final(uint8_t digest[20], RMD160_CTX *context)
}
}
-int RMD160_Equal(RMD160_CTX* pctx1, RMD160_CTX* pctx2) {
- return pctx1->buflen == pctx2->buflen
- && memcmp(pctx1->length, pctx2->length, sizeof(pctx1->length)) == 0
- && memcmp(pctx1->state, pctx2->state, sizeof(pctx1->state)) == 0
- && memcmp(pctx1->bbuffer, pctx2->bbuffer, sizeof(pctx1->bbuffer)) == 0;
-}
-
/************************ end of file rmd160.c **********************/
diff --git a/ext/digest/rmd160/rmd160.h b/ext/digest/rmd160/rmd160.h
index 7df190413e..54d1ca9140 100644
--- a/ext/digest/rmd160/rmd160.h
+++ b/ext/digest/rmd160/rmd160.h
@@ -1,6 +1,6 @@
/* $NetBSD: rmd160.h,v 1.2 2000/07/07 10:47:06 ad Exp $ */
/* $RoughId: rmd160.h,v 1.3 2002/02/24 08:14:31 knu Exp $ */
-/* $Id: rmd160.h,v 1.2 2002/02/24 08:20:22 knu Exp $ */
+/* $Id$ */
/********************************************************************\
*
@@ -39,26 +39,14 @@ typedef struct {
#define RMD160_Init rb_Digest_RMD160_Init
#define RMD160_Transform rb_Digest_RMD160_Transform
#define RMD160_Update rb_Digest_RMD160_Update
-#define RMD160_Final rb_Digest_RMD160_Final
-#define RMD160_Equal rb_Digest_RMD160_Equal
-#ifndef _KERNEL
-#define RMD160_End rb_Digest_RMD160_End
-#define RMD160_File rb_Digest_RMD160_File
-#define RMD160_Data rb_Digest_RMD160_Data
-#endif /* _KERNEL */
+#define RMD160_Finish rb_Digest_RMD160_Finish
#endif
__BEGIN_DECLS
void RMD160_Init _((RMD160_CTX *));
void RMD160_Transform _((uint32_t[5], const uint32_t[16]));
void RMD160_Update _((RMD160_CTX *, const uint8_t *, size_t));
-void RMD160_Final _((uint8_t[20], RMD160_CTX *));
-int RMD160_Equal _((RMD160_CTX *, RMD160_CTX *));
-#ifndef _KERNEL
-char *RMD160_End _((RMD160_CTX *, char *));
-char *RMD160_File _((char *, char *));
-char *RMD160_Data _((const uint8_t *, size_t, char *));
-#endif /* _KERNEL */
+void RMD160_Finish _((RMD160_CTX *, uint8_t[20]));
__END_DECLS
#define RMD160_BLOCK_LENGTH 64
diff --git a/ext/digest/rmd160/rmd160hl.c b/ext/digest/rmd160/rmd160hl.c
deleted file mode 100644
index 14299d7c7a..0000000000
--- a/ext/digest/rmd160/rmd160hl.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/* $NetBSD: rmd160hl.c,v 1.1.1.1 2001/03/06 11:21:05 agc Exp $ */
-/* $RoughId: rmd160hl.c,v 1.2 2001/07/13 19:49:10 knu Exp $ */
-/* $Id: rmd160hl.c,v 1.1 2001/07/13 20:06:14 knu Exp $ */
-
-/* rmd160hl.c
- * ----------------------------------------------------------------------------
- * "THE BEER-WARE LICENSE" (Revision 42):
- * <phk@login.dkuug.dk> wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
- * ----------------------------------------------------------------------------
- *
- * from OpenBSD: rmd160hl.c,v 1.2 1999/08/17 09:13:12 millert Exp $
- */
-
-#include "rmd160.h"
-
-#ifndef lint
-/* __RCSID("$NetBSD: rmd160hl.c,v 1.1.1.1 2001/03/06 11:21:05 agc Exp $"); */
-#endif /* not lint */
-
-/* #include "namespace.h" */
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#if defined(HAVE_UNISTD_H)
-# include <unistd.h>
-#endif
-
-#ifndef _DIAGASSERT
-#define _DIAGASSERT(cond) assert(cond)
-#endif
-
-
-char *
-RMD160_End(RMD160_CTX *ctx, char *buf)
-{
- size_t i;
- char *p = buf;
- uint8_t digest[20];
- static const char hex[]="0123456789abcdef";
-
- _DIAGASSERT(ctx != NULL);
- /* buf may be NULL */
-
- if (p == NULL && (p = malloc(41)) == NULL)
- return 0;
-
- RMD160_Final(digest,ctx);
- for (i = 0; i < 20; i++) {
- p[i + i] = hex[(uint32_t)digest[i] >> 4];
- p[i + i + 1] = hex[digest[i] & 0x0f];
- }
- p[i + i] = '\0';
- return(p);
-}
-
-char *
-RMD160_File(char *filename, char *buf)
-{
- uint8_t buffer[BUFSIZ];
- RMD160_CTX ctx;
- int fd, num, oerrno;
-
- _DIAGASSERT(filename != NULL);
- /* XXX: buf may be NULL ? */
-
- RMD160_Init(&ctx);
-
- if ((fd = open(filename, O_RDONLY)) < 0)
- return(0);
-
- while ((num = read(fd, buffer, sizeof(buffer))) > 0)
- RMD160_Update(&ctx, buffer, (size_t)num);
-
- oerrno = errno;
- close(fd);
- errno = oerrno;
- return(num < 0 ? 0 : RMD160_End(&ctx, buf));
-}
-
-char *
-RMD160_Data(const uint8_t *data, size_t len, char *buf)
-{
- RMD160_CTX ctx;
-
- _DIAGASSERT(data != NULL);
- /* XXX: buf may be NULL ? */
-
- RMD160_Init(&ctx);
- RMD160_Update(&ctx, data, len);
- return(RMD160_End(&ctx, buf));
-}
diff --git a/ext/digest/rmd160/rmd160init.c b/ext/digest/rmd160/rmd160init.c
index 3aa7847019..763867df86 100644
--- a/ext/digest/rmd160/rmd160init.c
+++ b/ext/digest/rmd160/rmd160init.c
@@ -1,5 +1,5 @@
/* $RoughId: rmd160init.c,v 1.3 2001/07/13 20:00:43 knu Exp $ */
-/* $Id: rmd160init.c,v 1.3 2002/09/26 17:26:46 knu Exp $ */
+/* $Id$ */
#include "digest.h"
#if defined(HAVE_OPENSSL_RIPEMD_H)
@@ -8,31 +8,33 @@
#include "rmd160.h"
#endif
-static algo_t rmd160 = {
+static rb_digest_metadata_t rmd160 = {
+ RUBY_DIGEST_API_VERSION,
RMD160_DIGEST_LENGTH,
+ RMD160_BLOCK_LENGTH,
sizeof(RMD160_CTX),
- (hash_init_func_t)RMD160_Init,
- (hash_update_func_t)RMD160_Update,
- (hash_end_func_t)RMD160_End,
- (hash_final_func_t)RMD160_Final,
- (hash_equal_func_t)RMD160_Equal,
+ (rb_digest_hash_init_func_t)RMD160_Init,
+ (rb_digest_hash_update_func_t)RMD160_Update,
+ (rb_digest_hash_finish_func_t)RMD160_Finish,
};
+/*
+ * A class for calculating message digests using RIPEMD-160
+ * cryptographic hash function, designed by Hans Dobbertin, Antoon
+ * Bosselaers, and Bart Preneel.
+ */
void
Init_rmd160()
{
VALUE mDigest, cDigest_Base, cDigest_RMD160;
- ID id_metadata;
- rb_require("digest.so");
+ rb_require("digest");
mDigest = rb_path2class("Digest");
cDigest_Base = rb_path2class("Digest::Base");
cDigest_RMD160 = rb_define_class_under(mDigest, "RMD160", cDigest_Base);
- id_metadata = rb_intern("metadata");
-
- rb_cvar_set(cDigest_RMD160, id_metadata,
- Data_Wrap_Struct(rb_cObject, 0, 0, &rmd160), Qtrue);
+ rb_ivar_set(cDigest_RMD160, rb_intern("metadata"),
+ Data_Wrap_Struct(rb_cObject, 0, 0, &rmd160));
}
diff --git a/ext/digest/rmd160/rmd160ossl.c b/ext/digest/rmd160/rmd160ossl.c
index 1a8436dfb8..f24e63e3d8 100644
--- a/ext/digest/rmd160/rmd160ossl.c
+++ b/ext/digest/rmd160/rmd160ossl.c
@@ -1,45 +1,8 @@
-/* $Id: rmd160ossl.c,v 1.1.2.1 2006/08/07 09:01:27 matz Exp $ */
+/* $Id$ */
#include "defs.h"
#include "rmd160ossl.h"
-#include <assert.h>
-#include <stdlib.h>
-#ifndef _DIAGASSERT
-#define _DIAGASSERT(cond) assert(cond)
-#endif
-
-char *
-RMD160_End(RMD160_CTX *ctx, char *buf)
-{
- size_t i;
- char *p = buf;
- uint8_t digest[20];
- static const char hex[]="0123456789abcdef";
-
- _DIAGASSERT(ctx != NULL);
- /* buf may be NULL */
-
- if (p == NULL && (p = malloc(41)) == NULL)
- return 0;
-
- RMD160_Final(digest,ctx);
- for (i = 0; i < 20; i++) {
- p[i + i] = hex[(uint32_t)digest[i] >> 4];
- p[i + i + 1] = hex[digest[i] & 0x0f];
- }
- p[i + i] = '\0';
- return(p);
-}
-
-int RMD160_Equal(RMD160_CTX* pctx1, RMD160_CTX* pctx2) {
- return pctx1->num == pctx2->num
- && pctx1->A == pctx2->A
- && pctx1->B == pctx2->B
- && pctx1->C == pctx2->C
- && pctx1->D == pctx2->D
- && pctx1->E == pctx2->E
- && pctx1->Nl == pctx2->Nl
- && pctx1->Nh == pctx2->Nh
- && memcmp(pctx1->data, pctx2->data, sizeof(pctx1->data)) == 0;
+void RMD160_Finish(RMD160_CTX *ctx, char *buf) {
+ RIPEMD160_Final((unsigned char *)buf, ctx);
}
diff --git a/ext/digest/rmd160/rmd160ossl.h b/ext/digest/rmd160/rmd160ossl.h
index 30840ca598..3df38a01c0 100644
--- a/ext/digest/rmd160/rmd160ossl.h
+++ b/ext/digest/rmd160/rmd160ossl.h
@@ -1,4 +1,4 @@
-/* $Id: rmd160ossl.h,v 1.1.2.1 2005/08/30 10:43:35 gotoyuzo Exp $ */
+/* $Id$ */
#ifndef RMD160OSSL_H_INCLUDED
#define RMD160OSSL_H_INCLUDED
@@ -10,12 +10,10 @@
#define RMD160_Init RIPEMD160_Init
#define RMD160_Update RIPEMD160_Update
-#define RMD160_Final RIPEMD160_Final
#define RMD160_BLOCK_LENGTH RIPEMD160_CBLOCK
#define RMD160_DIGEST_LENGTH RIPEMD160_DIGEST_LENGTH
-char *RMD160_End(RMD160_CTX *ctx, char *buf);
-int RMD160_Equal(RMD160_CTX *pctx1, RMD160_CTX *pctx2);
+void RMD160_Finish(RMD160_CTX *ctx, char *buf);
#endif
diff --git a/ext/digest/sha1/depend b/ext/digest/sha1/depend
index a159f456d3..61607844d0 100644
--- a/ext/digest/sha1/depend
+++ b/ext/digest/sha1/depend
@@ -1,7 +1,5 @@
sha1.o: sha1.c sha1.h $(srcdir)/../defs.h $(hdrdir)/ruby.h \
$(topdir)/config.h $(hdrdir)/defines.h $(hdrdir)/intern.h
-sha1hl.o: sha1hl.c sha1.h $(srcdir)/../defs.h $(hdrdir)/ruby.h \
- $(topdir)/config.h $(hdrdir)/defines.h $(hdrdir)/intern.h
sha1init.o: sha1init.c $(srcdir)/../digest.h $(hdrdir)/ruby.h \
$(topdir)/config.h $(hdrdir)/defines.h $(hdrdir)/intern.h \
sha1.h $(srcdir)/../defs.h
diff --git a/ext/digest/sha1/extconf.rb b/ext/digest/sha1/extconf.rb
index 861c5563f9..87b74c34af 100644
--- a/ext/digest/sha1/extconf.rb
+++ b/ext/digest/sha1/extconf.rb
@@ -1,5 +1,5 @@
# $RoughId: extconf.rb,v 1.3 2001/08/14 19:54:51 knu Exp $
-# $Id: extconf.rb,v 1.5.2.1 2006/05/25 23:44:05 nobu Exp $
+# $Id$
require "mkmf"
@@ -14,7 +14,7 @@ if !with_config("bundled-sha1") &&
have_library("crypto") && have_header("openssl/sha.h")
$objs << "sha1ossl.#{$OBJEXT}"
else
- $objs << "sha1.#{$OBJEXT}" << "sha1hl.#{$OBJEXT}"
+ $objs << "sha1.#{$OBJEXT}"
end
have_header("sys/cdefs.h")
@@ -23,4 +23,6 @@ have_header("inttypes.h")
have_header("unistd.h")
+$preload = %w[digest]
+
create_makefile("digest/sha1")
diff --git a/ext/digest/sha1/sha1.c b/ext/digest/sha1/sha1.c
index ba926e1fad..6196ca6b82 100644
--- a/ext/digest/sha1/sha1.c
+++ b/ext/digest/sha1/sha1.c
@@ -1,7 +1,7 @@
/* $NetBSD: sha1.c,v 1.2 2001/03/22 09:51:48 agc Exp $ */
/* $OpenBSD: sha1.c,v 1.9 1997/07/23 21:12:32 kstailey Exp $ */
/* $RoughId: sha1.c,v 1.2 2001/07/13 19:49:10 knu Exp $ */
-/* $Id: sha1.c,v 1.1 2001/07/13 20:06:14 knu Exp $ */
+/* $Id$ */
/*
* SHA-1 in C
@@ -129,9 +129,7 @@ do_R4(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LON
/*
* Hash a single 512-bit block. This is the core of the algorithm.
*/
-void SHA1_Transform(state, buffer)
- uint32_t state[5];
- const uint8_t buffer[64];
+void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
{
uint32_t a, b, c, d, e;
CHAR64LONG16 *block;
@@ -201,8 +199,7 @@ void SHA1_Transform(state, buffer)
/*
* SHA1_Init - Initialize new context
*/
-void SHA1_Init(context)
- SHA1_CTX *context;
+void SHA1_Init(SHA1_CTX *context)
{
_DIAGASSERT(context != 0);
@@ -220,10 +217,7 @@ void SHA1_Init(context)
/*
* Run your data through this.
*/
-void SHA1_Update(context, data, len)
- SHA1_CTX *context;
- const uint8_t *data;
- size_t len;
+void SHA1_Update(SHA1_CTX *context, const uint8_t *data, size_t len)
{
uint32_t i, j;
@@ -250,9 +244,7 @@ void SHA1_Update(context, data, len)
/*
* Add padding and return the message digest.
*/
-void SHA1_Final(digest, context)
- uint8_t digest[20];
- SHA1_CTX* context;
+void SHA1_Finish(SHA1_CTX* context, uint8_t digest[20])
{
size_t i;
uint8_t finalcount[8];
@@ -275,9 +267,3 @@ void SHA1_Final(digest, context)
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
}
}
-
-int SHA1_Equal(SHA1_CTX* pctx1, SHA1_CTX* pctx2) {
- return memcmp(pctx1->count, pctx2->count, sizeof(pctx1->count)) == 0
- && memcmp(pctx1->state, pctx2->state, sizeof(pctx1->state)) == 0
- && memcmp(pctx1->buffer, pctx2->buffer, sizeof(pctx1->buffer)) == 0;
-}
diff --git a/ext/digest/sha1/sha1.h b/ext/digest/sha1/sha1.h
index 5a1143ea0d..60e3b01fe2 100644
--- a/ext/digest/sha1/sha1.h
+++ b/ext/digest/sha1/sha1.h
@@ -1,6 +1,6 @@
/* $NetBSD: sha1.h,v 1.2 1998/05/29 22:55:44 thorpej Exp $ */
/* $RoughId: sha1.h,v 1.3 2002/02/24 08:14:32 knu Exp $ */
-/* $Id: sha1.h,v 1.2 2002/02/24 08:20:22 knu Exp $ */
+/* $Id$ */
/*
* SHA-1 in C
@@ -20,28 +20,17 @@ typedef struct {
} SHA1_CTX;
#ifdef RUBY
+/* avoid name clash */
#define SHA1_Transform rb_Digest_SHA1_Transform
#define SHA1_Init rb_Digest_SHA1_Init
#define SHA1_Update rb_Digest_SHA1_Update
-#define SHA1_Final rb_Digest_SHA1_Final
-#define SHA1_Equal rb_Digest_SHA1_Equal
-#ifndef _KERNEL
-#define SHA1_End rb_Digest_SHA1_End
-#define SHA1_File rb_Digest_SHA1_File
-#define SHA1_Data rb_Digest_SHA1_Data
-#endif /* _KERNEL */
+#define SHA1_Finish rb_Digest_SHA1_Finish
#endif
void SHA1_Transform _((uint32_t state[5], const uint8_t buffer[64]));
void SHA1_Init _((SHA1_CTX *context));
void SHA1_Update _((SHA1_CTX *context, const uint8_t *data, size_t len));
-void SHA1_Final _((uint8_t digest[20], SHA1_CTX *context));
-int SHA1_Equal _((SHA1_CTX *pctx1, SHA1_CTX *pctx2));
-#ifndef _KERNEL
-char *SHA1_End _((SHA1_CTX *, char *));
-char *SHA1_File _((char *, char *));
-char *SHA1_Data _((const uint8_t *, size_t, char *));
-#endif /* _KERNEL */
+void SHA1_Finish _((SHA1_CTX *context, uint8_t digest[20]));
#define SHA1_BLOCK_LENGTH 64
#define SHA1_DIGEST_LENGTH 20
diff --git a/ext/digest/sha1/sha1hl.c b/ext/digest/sha1/sha1hl.c
deleted file mode 100644
index 47b802085d..0000000000
--- a/ext/digest/sha1/sha1hl.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/* $NetBSD: sha1hl.c,v 1.2 2001/03/10 15:55:14 tron Exp $ */
-/* $RoughId: sha1hl.c,v 1.2 2001/07/13 19:49:10 knu Exp $ */
-/* $Id: sha1hl.c,v 1.1 2001/07/13 20:06:14 knu Exp $ */
-
-/* sha1hl.c
- * ----------------------------------------------------------------------------
- * "THE BEER-WARE LICENSE" (Revision 42):
- * <phk@login.dkuug.dk> wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
- * ----------------------------------------------------------------------------
- */
-
-/* #include "namespace.h" */
-
-#include "sha1.h"
-#include <fcntl.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#if defined(HAVE_UNISTD_H)
-# include <unistd.h>
-#endif
-
-#if defined(LIBC_SCCS) && !defined(lint)
-/* __RCSID("$NetBSD: sha1hl.c,v 1.2 2001/03/10 15:55:14 tron Exp $"); */
-#endif /* LIBC_SCCS and not lint */
-
-#ifndef _DIAGASSERT
-#define _DIAGASSERT(cond) assert(cond)
-#endif
-
-
-/* ARGSUSED */
-char *
-SHA1_End(ctx, buf)
- SHA1_CTX *ctx;
- char *buf;
-{
- int i;
- char *p = buf;
- uint8_t digest[20];
- static const char hex[]="0123456789abcdef";
-
- _DIAGASSERT(ctx != NULL);
- /* buf may be NULL */
-
- if (p == NULL && (p = malloc(41)) == NULL)
- return 0;
-
- SHA1_Final(digest,ctx);
- for (i = 0; i < 20; i++) {
- p[i + i] = hex[((uint32_t)digest[i]) >> 4];
- p[i + i + 1] = hex[digest[i] & 0x0f];
- }
- p[i + i] = '\0';
- return(p);
-}
-
-char *
-SHA1_File (filename, buf)
- char *filename;
- char *buf;
-{
- uint8_t buffer[BUFSIZ];
- SHA1_CTX ctx;
- int fd, num, oerrno;
-
- _DIAGASSERT(filename != NULL);
- /* XXX: buf may be NULL ? */
-
- SHA1_Init(&ctx);
-
- if ((fd = open(filename,O_RDONLY)) < 0)
- return(0);
-
- while ((num = read(fd, buffer, sizeof(buffer))) > 0)
- SHA1_Update(&ctx, buffer, (size_t)num);
-
- oerrno = errno;
- close(fd);
- errno = oerrno;
- return(num < 0 ? 0 : SHA1_End(&ctx, buf));
-}
-
-char *
-SHA1_Data (data, len, buf)
- const uint8_t *data;
- size_t len;
- char *buf;
-{
- SHA1_CTX ctx;
-
- _DIAGASSERT(data != NULL);
- /* XXX: buf may be NULL ? */
-
- SHA1_Init(&ctx);
- SHA1_Update(&ctx, data, len);
- return(SHA1_End(&ctx, buf));
-}
diff --git a/ext/digest/sha1/sha1init.c b/ext/digest/sha1/sha1init.c
index 829a363921..b2146f05a9 100644
--- a/ext/digest/sha1/sha1init.c
+++ b/ext/digest/sha1/sha1init.c
@@ -1,5 +1,5 @@
/* $RoughId: sha1init.c,v 1.2 2001/07/13 19:49:10 knu Exp $ */
-/* $Id: sha1init.c,v 1.3 2002/09/26 17:44:33 knu Exp $ */
+/* $Id$ */
#include "digest.h"
#if defined(HAVE_OPENSSL_SHA_H)
@@ -8,31 +8,33 @@
#include "sha1.h"
#endif
-static algo_t sha1 = {
+static rb_digest_metadata_t sha1 = {
+ RUBY_DIGEST_API_VERSION,
SHA1_DIGEST_LENGTH,
+ SHA1_BLOCK_LENGTH,
sizeof(SHA1_CTX),
- (hash_init_func_t)SHA1_Init,
- (hash_update_func_t)SHA1_Update,
- (hash_end_func_t)SHA1_End,
- (hash_final_func_t)SHA1_Final,
- (hash_equal_func_t)SHA1_Equal,
+ (rb_digest_hash_init_func_t)SHA1_Init,
+ (rb_digest_hash_update_func_t)SHA1_Update,
+ (rb_digest_hash_finish_func_t)SHA1_Finish,
};
+/*
+ * A class for calculating message digests using the SHA-1 Secure Hash
+ * Algorithm by NIST (the US' National Institute of Standards and
+ * Technology), described in FIPS PUB 180-1.
+ */
void
Init_sha1()
{
VALUE mDigest, cDigest_Base, cDigest_SHA1;
- ID id_metadata;
-
- rb_require("digest.so");
-
+
+ rb_require("digest");
+
mDigest = rb_path2class("Digest");
cDigest_Base = rb_path2class("Digest::Base");
cDigest_SHA1 = rb_define_class_under(mDigest, "SHA1", cDigest_Base);
- id_metadata = rb_intern("metadata");
-
- rb_cvar_set(cDigest_SHA1, id_metadata,
- Data_Wrap_Struct(rb_cObject, 0, 0, &sha1), Qtrue);
+ rb_ivar_set(cDigest_SHA1, rb_intern("metadata"),
+ Data_Wrap_Struct(rb_cObject, 0, 0, &sha1));
}
diff --git a/ext/digest/sha1/sha1ossl.c b/ext/digest/sha1/sha1ossl.c
index 72c6eb4092..452cf35084 100644
--- a/ext/digest/sha1/sha1ossl.c
+++ b/ext/digest/sha1/sha1ossl.c
@@ -1,45 +1,10 @@
-/* $Id: sha1ossl.c,v 1.1.2.1 2006/08/07 09:01:27 matz Exp $ */
+/* $Id$ */
#include "defs.h"
#include "sha1ossl.h"
-#include <assert.h>
-#include <stdlib.h>
-#ifndef _DIAGASSERT
-#define _DIAGASSERT(cond) assert(cond)
-#endif
-
-char *
-SHA1_End(SHA1_CTX *ctx, char *buf)
+void
+SHA1_Finish(SHA1_CTX *ctx, char *buf)
{
- int i;
- char *p = buf;
- uint8_t digest[20];
- static const char hex[]="0123456789abcdef";
-
- _DIAGASSERT(ctx != NULL);
- /* buf may be NULL */
-
- if (p == NULL && (p = malloc(41)) == NULL)
- return 0;
-
- SHA1_Final(digest,ctx);
- for (i = 0; i < 20; i++) {
- p[i + i] = hex[((uint32_t)digest[i]) >> 4];
- p[i + i + 1] = hex[digest[i] & 0x0f];
- }
- p[i + i] = '\0';
- return(p);
-}
-
-int SHA1_Equal(SHA1_CTX* pctx1, SHA1_CTX* pctx2) {
- return pctx1->num == pctx2->num
- && pctx1->h0 == pctx2->h0
- && pctx1->h1 == pctx2->h1
- && pctx1->h2 == pctx2->h2
- && pctx1->h3 == pctx2->h3
- && pctx1->h4 == pctx2->h4
- && pctx1->Nl == pctx2->Nl
- && pctx1->Nh == pctx2->Nh
- && memcmp(pctx1->data, pctx2->data, sizeof(pctx1->data)) == 0;
+ SHA1_Final((unsigned char *)buf, ctx);
}
diff --git a/ext/digest/sha1/sha1ossl.h b/ext/digest/sha1/sha1ossl.h
index 24b84b4274..8f9984cc64 100644
--- a/ext/digest/sha1/sha1ossl.h
+++ b/ext/digest/sha1/sha1ossl.h
@@ -1,4 +1,4 @@
-/* $Id: sha1ossl.h,v 1.1.2.1 2005/08/30 10:43:36 gotoyuzo Exp $ */
+/* $Id$ */
#ifndef SHA1OSSL_H_INCLUDED
#define SHA1OSSL_H_INCLUDED
@@ -8,10 +8,13 @@
#define SHA1_CTX SHA_CTX
+#ifdef SHA_BLOCK_LENGTH
#define SHA1_BLOCK_LENGTH SHA_BLOCK_LENGTH
+#else
+#define SHA1_BLOCK_LENGTH SHA_CBLOCK
+#endif
#define SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH
-char *SHA1_End(SHA1_CTX *ctx, char *buf);
-int SHA1_Equal(SHA1_CTX *pctx1, SHA1_CTX *pctx2);
+void SHA1_Finish(SHA1_CTX *ctx, char *buf);
#endif
diff --git a/ext/digest/sha2/depend b/ext/digest/sha2/depend
index 2587415fdc..225d6ad52b 100644
--- a/ext/digest/sha2/depend
+++ b/ext/digest/sha2/depend
@@ -1,7 +1,5 @@
sha2.o: sha2.c sha2.h $(srcdir)/../defs.h $(hdrdir)/ruby.h \
$(topdir)/config.h $(hdrdir)/defines.h $(hdrdir)/intern.h
-sha2hl.o: sha2hl.c sha2.h $(srcdir)/../defs.h $(hdrdir)/ruby.h \
- $(topdir)/config.h $(hdrdir)/defines.h $(hdrdir)/intern.h
sha2init.o: sha2init.c $(srcdir)/../digest.h $(hdrdir)/ruby.h \
$(topdir)/config.h $(hdrdir)/defines.h $(hdrdir)/intern.h \
sha2.h $(srcdir)/../defs.h
diff --git a/ext/digest/sha2/extconf.rb b/ext/digest/sha2/extconf.rb
index 5d078f4bd6..c084a51a64 100644
--- a/ext/digest/sha2/extconf.rb
+++ b/ext/digest/sha2/extconf.rb
@@ -1,5 +1,5 @@
# $RoughId: extconf.rb,v 1.4 2001/08/14 19:54:51 knu Exp $
-# $Id: extconf.rb,v 1.7.2.2 2006/05/25 23:44:06 nobu Exp $
+# $Id$
require "mkmf"
@@ -8,7 +8,6 @@ $INCFLAGS << " -I$(srcdir)/.."
$objs = [
"sha2.#{$OBJEXT}",
- "sha2hl.#{$OBJEXT}",
"sha2init.#{$OBJEXT}",
]
@@ -18,6 +17,8 @@ have_header("inttypes.h")
have_header("unistd.h")
+$preload = %w[digest]
+
if have_type("uint64_t", "defs.h", $defs.join(' '))
create_makefile("digest/sha2")
end
diff --git a/ext/digest/sha2/lib/sha2.rb b/ext/digest/sha2/lib/sha2.rb
new file mode 100644
index 0000000000..52dd639f9b
--- /dev/null
+++ b/ext/digest/sha2/lib/sha2.rb
@@ -0,0 +1,73 @@
+#--
+# sha2.rb - defines Digest::SHA2 class which wraps up the SHA256,
+# SHA384, and SHA512 classes.
+#++
+# Copyright (c) 2006 Akinori MUSHA <knu@iDaemons.org>
+#
+# All rights reserved. You can redistribute and/or modify it under the same
+# terms as Ruby.
+#
+# $Id$
+
+require 'digest'
+
+module Digest
+ #
+ # A meta digest provider class for SHA256, SHA384 and SHA512.
+ #
+ class SHA2 < Digest::Class
+ # call-seq:
+ # Digest::SHA2.new(bitlen = 256) -> digest_obj
+ #
+ # Creates a new SHA2 hash object with a given bit length.
+ def initialize(bitlen = 256)
+ case bitlen
+ when 256
+ @sha2 = Digest::SHA256.new
+ when 384
+ @sha2 = Digest::SHA384.new
+ when 512
+ @sha2 = Digest::SHA512.new
+ else
+ raise ArgumentError, "unsupported bit length: %s" % bitlen.inspect
+ end
+ @bitlen = bitlen
+ end
+
+ # :nodoc:
+ def reset
+ @sha2.reset
+ self
+ end
+
+ # :nodoc:
+ def update(str)
+ @sha2.update(str)
+ self
+ end
+ alias << update
+
+ def finish
+ @sha2.digest!
+ end
+ private :finish
+
+ def block_length
+ @sha2.block_length
+ end
+
+ def digest_length
+ @sha2.digest_length
+ end
+
+ # :nodoc:
+ def initialize_copy(other)
+ @sha2 = other.instance_eval { @sha2.clone }
+ end
+
+ # :nodoc:
+ def inspect
+ "#<%s:%d %s>" % [self.class.name, @bitlen, hexdigest]
+ end
+ end
+end
diff --git a/ext/digest/sha2/sha2.c b/ext/digest/sha2/sha2.c
index 22e7d59cd3..aca9ee926f 100644
--- a/ext/digest/sha2/sha2.c
+++ b/ext/digest/sha2/sha2.c
@@ -34,7 +34,7 @@
*/
/* $RoughId: sha2.c,v 1.3 2002/02/26 22:03:36 knu Exp $ */
-/* $Id: sha2.c,v 1.4.2.1 2005/12/24 09:58:56 matz Exp $ */
+/* $Id$ */
#include "sha2.h"
#include <stdio.h>
@@ -515,7 +515,7 @@ void SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) {
usedspace = freespace = 0;
}
-void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) {
+void SHA256_Finish(SHA256_CTX* context, sha2_byte digest[]) {
sha2_word32 *d = (sha2_word32*)digest;
unsigned int usedspace;
@@ -578,12 +578,6 @@ void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) {
usedspace = 0;
}
-int SHA256_Equal(SHA256_CTX* pctx1, SHA256_CTX* pctx2) {
- return pctx1->bitcount == pctx2->bitcount
- && memcmp(pctx1->state, pctx2->state, sizeof(pctx1->state)) == 0
- && memcmp(pctx1->buffer, pctx2->buffer, sizeof(pctx1->buffer)) == 0;
-}
-
/*** SHA-512: *********************************************************/
void SHA512_Init(SHA512_CTX* context) {
if (context == (SHA512_CTX*)0) {
@@ -852,7 +846,7 @@ void SHA512_Last(SHA512_CTX* context) {
SHA512_Transform(context, (const sha2_word64*)context->buffer);
}
-void SHA512_Final(sha2_byte digest[], SHA512_CTX* context) {
+void SHA512_Finish(SHA512_CTX* context, sha2_byte digest[]) {
sha2_word64 *d = (sha2_word64*)digest;
/* Sanity check: */
@@ -881,12 +875,6 @@ void SHA512_Final(sha2_byte digest[], SHA512_CTX* context) {
MEMSET_BZERO(context, sizeof(SHA512_CTX));
}
-int SHA512_Equal(SHA512_CTX* pctx1, SHA512_CTX* pctx2) {
- return memcmp(pctx1->bitcount, pctx2->bitcount, sizeof(pctx1->bitcount)) == 0
- && memcmp(pctx1->state, pctx2->state, sizeof(pctx1->state)) == 0
- && memcmp(pctx1->buffer, pctx2->buffer, sizeof(pctx1->buffer)) == 0;
-}
-
/*** SHA-384: *********************************************************/
void SHA384_Init(SHA384_CTX* context) {
if (context == (SHA384_CTX*)0) {
@@ -901,7 +889,7 @@ void SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len) {
SHA512_Update((SHA512_CTX*)context, data, len);
}
-void SHA384_Final(sha2_byte digest[], SHA384_CTX* context) {
+void SHA384_Finish(SHA384_CTX* context, sha2_byte digest[]) {
sha2_word64 *d = (sha2_word64*)digest;
/* Sanity check: */
@@ -929,9 +917,3 @@ void SHA384_Final(sha2_byte digest[], SHA384_CTX* context) {
/* Zero out state data */
MEMSET_BZERO(context, sizeof(SHA384_CTX));
}
-
-int SHA384_Equal(SHA384_CTX* pctx1, SHA384_CTX* pctx2) {
- return memcmp(pctx1->bitcount, pctx2->bitcount, sizeof(pctx1->bitcount)) == 0
- && memcmp(pctx1->state, pctx2->state, sizeof(pctx1->state)) == 0
- && memcmp(pctx1->buffer, pctx2->buffer, sizeof(pctx1->buffer)) == 0;
-}
diff --git a/ext/digest/sha2/sha2.h b/ext/digest/sha2/sha2.h
index 7ccf012b77..917d415b73 100644
--- a/ext/digest/sha2/sha2.h
+++ b/ext/digest/sha2/sha2.h
@@ -34,7 +34,7 @@
*/
/* $RoughId: sha2.h,v 1.3 2002/02/24 08:14:32 knu Exp $ */
-/* $Id: sha2.h,v 1.2 2002/02/24 08:20:22 knu Exp $ */
+/* $Id$ */
#ifndef __SHA2_H__
#define __SHA2_H__
@@ -77,53 +77,29 @@ typedef SHA512_CTX SHA384_CTX;
#ifdef RUBY
#define SHA256_Init rb_Digest_SHA256_Init
#define SHA256_Update rb_Digest_SHA256_Update
-#define SHA256_Final rb_Digest_SHA256_Final
-#define SHA256_End rb_Digest_SHA256_End
-#define SHA256_Data rb_Digest_SHA256_Data
-#define SHA256_File rb_Digest_SHA256_File
-#define SHA256_Equal rb_Digest_SHA256_Equal
+#define SHA256_Finish rb_Digest_SHA256_Finish
#define SHA384_Init rb_Digest_SHA384_Init
#define SHA384_Update rb_Digest_SHA384_Update
-#define SHA384_Final rb_Digest_SHA384_Final
-#define SHA384_End rb_Digest_SHA384_End
-#define SHA384_Data rb_Digest_SHA384_Data
-#define SHA384_File rb_Digest_SHA384_File
-#define SHA384_Equal rb_Digest_SHA384_Equal
+#define SHA384_Finish rb_Digest_SHA384_Finish
#define SHA512_Init rb_Digest_SHA512_Init
#define SHA512_Update rb_Digest_SHA512_Update
-#define SHA512_Final rb_Digest_SHA512_Final
-#define SHA512_End rb_Digest_SHA512_End
-#define SHA512_Data rb_Digest_SHA512_Data
-#define SHA512_File rb_Digest_SHA512_File
-#define SHA512_Equal rb_Digest_SHA512_Equal
+#define SHA512_Finish rb_Digest_SHA512_Finish
#endif
/*** SHA-256/384/512 Function Prototypes ******************************/
void SHA256_Init _((SHA256_CTX *));
void SHA256_Update _((SHA256_CTX*, const uint8_t*, size_t));
-void SHA256_Final _((uint8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*));
-char* SHA256_End _((SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]));
-char* SHA256_Data _((const uint8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]));
-char *SHA256_File _((char *, char *));
-int SHA256_Equal _((SHA256_CTX*, SHA256_CTX*));
+void SHA256_Finish _((SHA256_CTX*, uint8_t[SHA256_DIGEST_LENGTH]));
void SHA384_Init _((SHA384_CTX*));
void SHA384_Update _((SHA384_CTX*, const uint8_t*, size_t));
-void SHA384_Final _((uint8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*));
-char* SHA384_End _((SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH]));
-char* SHA384_Data _((const uint8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH]));
-char *SHA384_File _((char *, char *));
-int SHA384_Equal _((SHA384_CTX*, SHA384_CTX*));
+void SHA384_Finish _((SHA384_CTX*, uint8_t[SHA384_DIGEST_LENGTH]));
void SHA512_Init _((SHA512_CTX*));
void SHA512_Update _((SHA512_CTX*, const uint8_t*, size_t));
-void SHA512_Final _((uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*));
-char* SHA512_End _((SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]));
-char* SHA512_Data _((const uint8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]));
-char *SHA512_File _((char *, char *));
-int SHA512_Equal _((SHA512_CTX*, SHA512_CTX*));
+void SHA512_Finish _((SHA512_CTX*, uint8_t[SHA512_DIGEST_LENGTH]));
#ifdef __cplusplus
}
diff --git a/ext/digest/sha2/sha2hl.c b/ext/digest/sha2/sha2hl.c
deleted file mode 100644
index 8f09bd6e5a..0000000000
--- a/ext/digest/sha2/sha2hl.c
+++ /dev/null
@@ -1,252 +0,0 @@
-/* $NetBSD: sha2hl.c,v 1.1 2001/03/12 09:08:40 agc Exp $ */
-/* $RoughId: sha2hl.c,v 1.2 2001/07/13 19:49:10 knu Exp $ */
-/* $Id: sha2hl.c,v 1.1 2001/07/13 20:06:14 knu Exp $ */
-
-/*
- * sha2hl.c
- * This code includes some functions taken from sha2.c, hence the
- * following licence reproduction.
- *
- * This code is not a verbatim copy, since some routines have been added,
- * and some bugs have been fixed.
- *
- * Version 1.0.0beta1
- *
- * Written by Aaron D. Gifford <me@aarongifford.com>
- *
- * Copyright 2000 Aaron D. Gifford. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holder nor the names of contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
-#include "sha2.h"
-
-#ifndef lint
-/* __RCSID("$NetBSD: sha2hl.c,v 1.1 2001/03/12 09:08:40 agc Exp $"); */
-#endif /* not lint */
-
-/* #include "namespace.h" */
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#if defined(HAVE_UNISTD_H)
-# include <unistd.h>
-#endif
-
-#ifndef _DIAGASSERT
-#define _DIAGASSERT(cond) assert(cond)
-#endif
-
-/*
- * Constant used by SHA256/384/512_End() functions for converting the
- * digest to a readable hexadecimal character string:
- */
-static const char sha2_hex_digits[] = "0123456789abcdef";
-
-char *
-SHA256_File(char *filename, char *buf)
-{
- uint8_t buffer[BUFSIZ * 20];
- SHA256_CTX ctx;
- int fd, num, oerrno;
-
- _DIAGASSERT(filename != NULL);
- /* XXX: buf may be NULL ? */
-
- SHA256_Init(&ctx);
-
- if ((fd = open(filename, O_RDONLY)) < 0)
- return (0);
-
- while ((num = read(fd, buffer, sizeof(buffer))) > 0)
- SHA256_Update(&ctx, buffer, (size_t) num);
-
- oerrno = errno;
- close(fd);
- errno = oerrno;
- return (num < 0 ? 0 : SHA256_End(&ctx, buf));
-}
-
-
-char *
-SHA256_End(SHA256_CTX *ctx, char buffer[])
-{
- uint8_t digest[SHA256_DIGEST_LENGTH], *d = digest;
- uint8_t *ret;
- int i;
-
- /* Sanity check: */
- assert(ctx != NULL);
-
- if ((ret = buffer) != NULL) {
- SHA256_Final(digest, ctx);
-
- for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
- *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
- *buffer++ = sha2_hex_digits[*d & 0x0f];
- d++;
- }
- *buffer = (char) 0;
- } else {
- (void) memset(ctx, 0, sizeof(SHA256_CTX));
- }
- (void) memset(digest, 0, SHA256_DIGEST_LENGTH);
- return ret;
-}
-
-char *
-SHA256_Data(const uint8_t * data, size_t len, char *digest)
-{
- SHA256_CTX ctx;
-
- SHA256_Init(&ctx);
- SHA256_Update(&ctx, data, len);
- return SHA256_End(&ctx, digest);
-}
-
-char *
-SHA384_File(char *filename, char *buf)
-{
- SHA384_CTX ctx;
- uint8_t buffer[BUFSIZ * 20];
- int fd, num, oerrno;
-
- _DIAGASSERT(filename != NULL);
- /* XXX: buf may be NULL ? */
-
- SHA384_Init(&ctx);
-
- if ((fd = open(filename, O_RDONLY)) < 0)
- return (0);
-
- while ((num = read(fd, buffer, sizeof(buffer))) > 0)
- SHA384_Update(&ctx, buffer, (size_t) num);
-
- oerrno = errno;
- close(fd);
- errno = oerrno;
- return (num < 0 ? 0 : SHA384_End(&ctx, buf));
-}
-
-char *
-SHA384_End(SHA384_CTX * ctx, char buffer[])
-{
- uint8_t digest[SHA384_DIGEST_LENGTH], *d = digest;
- uint8_t *ret;
- int i;
-
- /* Sanity check: */
- assert(ctx != NULL);
-
- if ((ret = buffer) != NULL) {
- SHA384_Final(digest, ctx);
-
- for (i = 0; i < SHA384_DIGEST_LENGTH; i++) {
- *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
- *buffer++ = sha2_hex_digits[*d & 0x0f];
- d++;
- }
- *buffer = (char) 0;
- } else {
- (void) memset(ctx, 0, sizeof(SHA384_CTX));
- }
- (void) memset(digest, 0, SHA384_DIGEST_LENGTH);
- return ret;
-}
-
-char *
-SHA384_Data(const uint8_t * data, size_t len, char *digest)
-{
- SHA384_CTX ctx;
-
- SHA384_Init(&ctx);
- SHA384_Update(&ctx, data, len);
- return SHA384_End(&ctx, digest);
-}
-
-char *
-SHA512_File(char *filename, char *buf)
-{
- SHA512_CTX ctx;
- uint8_t buffer[BUFSIZ * 20];
- int fd, num, oerrno;
-
- _DIAGASSERT(filename != NULL);
- /* XXX: buf may be NULL ? */
-
- SHA512_Init(&ctx);
-
- if ((fd = open(filename, O_RDONLY)) < 0)
- return (0);
-
- while ((num = read(fd, buffer, sizeof(buffer))) > 0)
- SHA512_Update(&ctx, buffer, (size_t) num);
-
- oerrno = errno;
- close(fd);
- errno = oerrno;
- return (num < 0 ? 0 : SHA512_End(&ctx, buf));
-}
-
-char *
-SHA512_End(SHA512_CTX * ctx, char buffer[])
-{
- uint8_t digest[SHA512_DIGEST_LENGTH], *d = digest;
- uint8_t *ret;
- int i;
-
- /* Sanity check: */
- assert(ctx != NULL);
-
- if ((ret = buffer) != NULL) {
- SHA512_Final(digest, ctx);
-
- for (i = 0; i < SHA512_DIGEST_LENGTH; i++) {
- *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
- *buffer++ = sha2_hex_digits[*d & 0x0f];
- d++;
- }
- *buffer = (char) 0;
- } else {
- (void) memset(ctx, 0, sizeof(SHA512_CTX));
- }
- (void) memset(digest, 0, SHA512_DIGEST_LENGTH);
- return ret;
-}
-
-char *
-SHA512_Data(const uint8_t * data, size_t len, char *digest)
-{
- SHA512_CTX ctx;
-
- SHA512_Init(&ctx);
- SHA512_Update(&ctx, data, len);
- return SHA512_End(&ctx, digest);
-}
diff --git a/ext/digest/sha2/sha2init.c b/ext/digest/sha2/sha2init.c
index 9c0f9854fb..c83a29316a 100644
--- a/ext/digest/sha2/sha2init.c
+++ b/ext/digest/sha2/sha2init.c
@@ -1,5 +1,5 @@
/* $RoughId: sha2init.c,v 1.3 2001/07/13 20:00:43 knu Exp $ */
-/* $Id: sha2init.c,v 1.2 2002/02/17 12:43:44 nobu Exp $ */
+/* $Id$ */
#include "digest.h"
#include "sha2.h"
@@ -7,18 +7,23 @@
#define FOREACH_BITLEN(func) func(256) func(384) func(512)
#define DEFINE_ALGO_METADATA(bitlen) \
-static algo_t sha##bitlen = { \
+static rb_digest_metadata_t sha##bitlen = { \
+ RUBY_DIGEST_API_VERSION, \
SHA##bitlen##_DIGEST_LENGTH, \
+ SHA##bitlen##_BLOCK_LENGTH, \
sizeof(SHA##bitlen##_CTX), \
- (hash_init_func_t)SHA##bitlen##_Init, \
- (hash_update_func_t)SHA##bitlen##_Update, \
- (hash_end_func_t)SHA##bitlen##_End, \
- (hash_final_func_t)SHA##bitlen##_Final, \
- (hash_equal_func_t)SHA##bitlen##_Equal, \
+ (rb_digest_hash_init_func_t)SHA##bitlen##_Init, \
+ (rb_digest_hash_update_func_t)SHA##bitlen##_Update, \
+ (rb_digest_hash_finish_func_t)SHA##bitlen##_Finish, \
};
FOREACH_BITLEN(DEFINE_ALGO_METADATA)
+/*
+ * Classes for calculating message digests using the SHA-256/384/512
+ * Secure Hash Algorithm(s) by NIST (the US' National Institute of
+ * Standards and Technology), described in FIPS PUB 180-2.
+ */
void
Init_sha2()
{
@@ -30,7 +35,7 @@ Init_sha2()
FOREACH_BITLEN(DECLARE_ALGO_CLASS)
- rb_require("digest.so");
+ rb_require("digest");
id_metadata = rb_intern("metadata");
@@ -40,8 +45,8 @@ Init_sha2()
#define DEFINE_ALGO_CLASS(bitlen) \
cDigest_SHA##bitlen = rb_define_class_under(mDigest, "SHA" #bitlen, cDigest_Base); \
\
- rb_cvar_set(cDigest_SHA##bitlen, id_metadata, \
- Data_Wrap_Struct(rb_cObject, 0, 0, &sha##bitlen), Qtrue);
+ rb_ivar_set(cDigest_SHA##bitlen, id_metadata, \
+ Data_Wrap_Struct(rb_cObject, 0, 0, &sha##bitlen));
FOREACH_BITLEN(DEFINE_ALGO_CLASS)
}
diff --git a/ext/digest/test.sh b/ext/digest/test.sh
index 2ae2688e4d..328c7575e6 100644
--- a/ext/digest/test.sh
+++ b/ext/digest/test.sh
@@ -1,7 +1,7 @@
#!/bin/sh
#
# $RoughId: test.sh,v 1.5 2001/07/13 15:38:27 knu Exp $
-# $Id: test.sh,v 1.2 2002/09/26 17:55:16 knu Exp $
+# $Id$
RUBY=${RUBY:=ruby}
MAKE=${MAKE:=make}
@@ -11,8 +11,6 @@ ${RUBY} extconf.rb --with-cflags="${CFLAGS}"
${MAKE} clean
${MAKE}
-mkdir -p lib/digest
-
for algo in md5 rmd160 sha1 sha2; do
args=--with-cflags="${CFLAGS}"
@@ -27,7 +25,6 @@ for algo in md5 rmd160 sha1 sha2; do
ln -sf ../../$algo/$algo.so lib/digest/
done
-${RUBY} -I. -I./lib test.rb
+${RUBY} -I. -I./lib ../../test/digest/test_digest.rb
rm lib/digest/*.so
-rmdir lib/digest
diff --git a/ext/dl/dl.c b/ext/dl/dl.c
index 71c353bda3..f65247be86 100644
--- a/ext/dl/dl.c
+++ b/ext/dl/dl.c
@@ -1,5 +1,5 @@
/*
- * $Id: dl.c,v 1.20.2.5 2005/12/16 13:32:06 ttate Exp $
+ * $Id$
*/
#include <ruby.h>
@@ -522,12 +522,15 @@ rb_str_to_ptr(VALUE self)
{
char *ptr;
int len;
+ VALUE p;
len = RSTRING(self)->len;
ptr = (char*)dlmalloc(len + 1);
memcpy(ptr, RSTRING(self)->ptr, len);
ptr[len] = '\0';
- return rb_dlptr_new((void*)ptr,len,dlfree);
+ p = rb_dlptr_new((void*)ptr,len,dlfree);
+ OBJ_INFECT(p, self);
+ return p;
}
VALUE
@@ -545,13 +548,18 @@ rb_ary_to_ptr(int argc, VALUE argv[], VALUE self)
ptr = rb_ary2cary(0, self, &size);
break;
}
- return ptr ? rb_dlptr_new(ptr, size, dlfree) : Qnil;
+ if (ptr) {
+ VALUE p = rb_dlptr_new(ptr, size, dlfree);
+ OBJ_INFECT(p, self);
+ return p;
+ }
+ return Qnil;
}
VALUE
rb_io_to_ptr(VALUE self)
{
- OpenFile *fptr;
+ rb_io_t *fptr;
FILE *fp;
GetOpenFile(self, fptr);
@@ -563,7 +571,7 @@ rb_io_to_ptr(VALUE self)
VALUE
rb_dl_dlopen(int argc, VALUE argv[], VALUE self)
{
- rb_secure(4);
+ rb_secure(2);
return rb_class_new_instance(argc, argv, rb_cDLHandle);
}
diff --git a/ext/dl/dl.h b/ext/dl/dl.h
index 9e4e01eea5..1faa316cf1 100644
--- a/ext/dl/dl.h
+++ b/ext/dl/dl.h
@@ -1,5 +1,5 @@
/* -*- C -*-
- * $Id: dl.h,v 1.9 2003/12/01 23:02:44 ttate Exp $
+ * $Id$
*/
#ifndef RUBY_DL_H
diff --git a/ext/dl/h2rb b/ext/dl/h2rb
index d5ebd6ee2c..00fbd60c82 100644
--- a/ext/dl/h2rb
+++ b/ext/dl/h2rb
@@ -1,6 +1,6 @@
#!/usr/bin/env ruby
# -*- ruby -*-
-# $Id: h2rb,v 1.1 2002/04/02 10:56:13 ttate Exp $
+# $Id$
require 'mkmf'
require 'ftools'
diff --git a/ext/dl/handle.c b/ext/dl/handle.c
index 1e8c17e501..69d47caac0 100644
--- a/ext/dl/handle.c
+++ b/ext/dl/handle.c
@@ -1,5 +1,5 @@
/* -*- C -*-
- * $Id: handle.c,v 1.11.2.1 2005/02/28 02:45:17 matz Exp $
+ * $Id$
*/
#include <ruby.h>
@@ -66,12 +66,12 @@ rb_dlhandle_initialize(int argc, VALUE argv[], VALUE self)
ptr = dlopen(clib, cflag);
#if defined(HAVE_DLERROR)
if (!ptr && (err = dlerror())) {
- rb_raise(rb_eRuntimeError, err);
+ rb_raise(rb_eRuntimeError, "%s", err);
}
#else
if (!ptr) {
err = dlerror();
- rb_raise(rb_eRuntimeError, err);
+ rb_raise(rb_eRuntimeError, "%s", err);
}
#endif
Data_Get_Struct(self, struct dl_handle, dlhandle);
diff --git a/ext/dl/lib/dl/import.rb b/ext/dl/lib/dl/import.rb
index 63c9b2c050..01ee2490e8 100644
--- a/ext/dl/lib/dl/import.rb
+++ b/ext/dl/lib/dl/import.rb
@@ -87,7 +87,7 @@ module DL
" rs = dec.call(rs) if (dec && rs)",
" @retval = r",
" @args = rs",
- " @retval",
+ " r",
"}",
].join("\n"))
@@ -169,7 +169,7 @@ module DL
" rs = dec.call(rs) if dec",
" @retval = r",
" @args = rs",
- " return @retval",
+ " return r",
"end",
"module_function :#{mname}",
].join("\n")
diff --git a/ext/dl/ptr.c b/ext/dl/ptr.c
index 574d4241bf..01eb31da20 100644
--- a/ext/dl/ptr.c
+++ b/ext/dl/ptr.c
@@ -1,33 +1,25 @@
/* -*- C -*-
- * $Id: ptr.c,v 1.19.2.1 2006/05/25 16:37:57 ttate Exp $
+ * $Id$
*/
#include <ruby.h>
#include <ctype.h>
-#include <version.h> /* for ruby version code */
+#include "st.h"
#include "dl.h"
VALUE rb_cDLPtrData;
VALUE rb_mDLMemorySpace;
-static VALUE DLMemoryTable;
+static st_table* st_memory_table;
#ifndef T_SYMBOL
# define T_SYMBOL T_FIXNUM
#endif
-#if RUBY_VERSION_CODE < 171
-static VALUE
-rb_hash_delete(VALUE hash, VALUE key)
-{
- return rb_funcall(hash, rb_intern("delete"), 1, key);
-}
-#endif
-
static void
rb_dlmem_delete(void *ptr)
{
rb_secure(4);
- rb_hash_delete(DLMemoryTable, DLLONG2NUM(ptr));
+ st_delete(st_memory_table, (st_data_t*)&ptr, NULL);
}
static void
@@ -37,7 +29,7 @@ rb_dlmem_aset(void *ptr, VALUE obj)
rb_dlmem_delete(ptr);
}
else{
- rb_hash_aset(DLMemoryTable, DLLONG2NUM(ptr), DLLONG2NUM(obj));
+ st_insert(st_memory_table, (st_data_t)ptr, (st_data_t)obj);
}
}
@@ -46,8 +38,8 @@ rb_dlmem_aref(void *ptr)
{
VALUE val;
- val = rb_hash_aref(DLMemoryTable, DLLONG2NUM(ptr));
- return val == Qnil ? Qnil : (VALUE)DLNUM2LONG(val);
+ if(!st_lookup(st_memory_table, (st_data_t)ptr, &val)) return Qnil;
+ return val == Qundef ? Qnil : val;
}
void
@@ -344,7 +336,7 @@ rb_dlptr_to_array(int argc, VALUE argv[], VALUE self)
n = data->size / sizeof(void*);
break;
case 'S': case 's':
- for (n=0; ((void**)(data->ptr))[n]; n++) {};
+ n = data->size / sizeof(char*);
break;
default:
n = 0;
@@ -1010,20 +1002,18 @@ rb_dlptr_size(int argc, VALUE argv[], VALUE self)
}
}
-static VALUE
-dlmem_each_i(VALUE assoc, void *data)
+static int
+dlmem_each_i(void* key, VALUE value, void* arg)
{
- VALUE key, val;
- key = rb_ary_entry(assoc, 0);
- val = rb_ary_entry(assoc, 1);
- rb_yield(rb_assoc_new(key,(VALUE)DLNUM2LONG(val)));
+ VALUE vkey = DLLONG2NUM(key);
+ rb_yield(rb_assoc_new(vkey, value));
return Qnil;
}
VALUE
rb_dlmem_each(VALUE self)
{
- rb_iterate(rb_each, DLMemoryTable, dlmem_each_i, 0);
+ st_foreach(st_memory_table, dlmem_each_i, 0);
return Qnil;
}
@@ -1062,7 +1052,7 @@ Init_dlptr()
rb_define_method(rb_cDLPtrData, "size=", rb_dlptr_size, -1);
rb_mDLMemorySpace = rb_define_module_under(rb_mDL, "MemorySpace");
- DLMemoryTable = rb_hash_new();
- rb_define_const(rb_mDLMemorySpace, "MemoryTable", DLMemoryTable);
+ st_memory_table = st_init_numtable();
+ rb_define_const(rb_mDLMemorySpace, "MemoryTable", Qnil); /* historical */
rb_define_module_function(rb_mDLMemorySpace, "each", rb_dlmem_each, 0);
}
diff --git a/ext/dl/sym.c b/ext/dl/sym.c
index 2ca16a8698..933fb7f4f0 100644
--- a/ext/dl/sym.c
+++ b/ext/dl/sym.c
@@ -1,5 +1,5 @@
/* -*- C -*-
- * $Id: sym.c,v 1.24.2.3 2005/06/15 23:39:27 ocean Exp $
+ * $Id$
*/
#include <ruby.h>
@@ -492,6 +492,7 @@ rb_dlsym_call(int argc, VALUE argv[], VALUE self)
rb_raise(rb_eDLTypeError, "unexpected type of argument #%d", i);
}
}
+ rb_check_safe_obj(pval);
Data_Get_Struct(pval, struct ptr_data, data);
ANY2P(args[i]) = DLVOIDP(data->ptr);
}
diff --git a/ext/enumerator/enumerator.c b/ext/enumerator/enumerator.c
deleted file mode 100644
index 7b8f109e38..0000000000
--- a/ext/enumerator/enumerator.c
+++ /dev/null
@@ -1,298 +0,0 @@
-/************************************************
-
- enumerator.c - provides Enumerator class
-
- $Author: matz $
-
- Copyright (C) 2001-2003 Akinori MUSHA
-
- $Idaemons: /home/cvs/rb/enumerator/enumerator.c,v 1.1.1.1 2001/07/15 10:12:48 knu Exp $
- $RoughId: enumerator.c,v 1.6 2003/07/27 11:03:24 nobu Exp $
- $Id: enumerator.c,v 1.3.2.3 2005/10/24 00:07:00 matz Exp $
-
-************************************************/
-
-#include "ruby.h"
-#include "node.h"
-
-/*
- * Document-class: Enumerable::Enumerator
- *
- * A class which provides a method `each' to be used as an Enumerable
- * object.
- */
-static VALUE rb_cEnumerator;
-static ID sym_each, sym_each_with_index, sym_each_slice, sym_each_cons;
-static ID id_new, id_enum_obj, id_enum_method, id_enum_args;
-
-/*
- * call-seq:
- * obj.to_enum(method = :each, *args)
- * obj.enum_for(method = :each, *args)
- *
- * Returns Enumerable::Enumerator.new(self, method, *args).
- *
- * e.g.:
- * str = "xyz"
- *
- * enum = str.enum_for(:each_byte)
- * a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"]
- *
- * # protects an array from being modified
- * a = [1, 2, 3]
- * some_method(a.to_enum)
- *
- */
-static VALUE
-obj_to_enum(obj, enum_args)
- VALUE obj, enum_args;
-{
- rb_ary_unshift(enum_args, obj);
-
- return rb_apply(rb_cEnumerator, id_new, enum_args);
-}
-
-/*
- * call-seq:
- * enum_with_index
- *
- * Returns Enumerable::Enumerator.new(self, :each_with_index).
- *
- */
-static VALUE
-enumerator_enum_with_index(obj)
- VALUE obj;
-{
- return rb_funcall(rb_cEnumerator, id_new, 2, obj, sym_each_with_index);
-}
-
-static VALUE
-each_slice_i(val, memo)
- VALUE val;
- NODE *memo;
-{
- VALUE ary = memo->u1.value;
- long size = memo->u3.cnt;
-
- rb_ary_push(ary, val);
-
- if (RARRAY(ary)->len == size) {
- rb_yield(ary);
- memo->u1.value = rb_ary_new2(size);
- }
-
- return Qnil;
-}
-
-/*
- * call-seq:
- * e.each_slice(n) {...}
- *
- * Iterates the given block for each slice of <n> elements.
- *
- * e.g.:
- * (1..10).each_slice(3) {|a| p a}
- * # outputs below
- * [1, 2, 3]
- * [4, 5, 6]
- * [7, 8, 9]
- * [10]
- *
- */
-static VALUE
-enum_each_slice(obj, n)
- VALUE obj, n;
-{
- long size = NUM2LONG(n);
- NODE *memo;
- VALUE ary;
-
- if (size <= 0) rb_raise(rb_eArgError, "invalid slice size");
-
- memo = rb_node_newnode(NODE_MEMO, rb_ary_new2(size), 0, size);
-
- rb_iterate(rb_each, obj, each_slice_i, (VALUE)memo);
-
- ary = memo->u1.value;
- if (RARRAY(ary)->len > 0) rb_yield(ary);
-
- return Qnil;
-}
-
-/*
- * call-seq:
- * e.enum_slice(n)
- *
- * Returns Enumerable::Enumerator.new(self, :each_slice, n).
- *
- */
-static VALUE
-enumerator_enum_slice(obj, n)
- VALUE obj, n;
-{
- return rb_funcall(rb_cEnumerator, id_new, 3, obj, sym_each_slice, n);
-}
-
-static VALUE
-each_cons_i(val, memo)
- VALUE val;
- NODE *memo;
-{
- VALUE ary = memo->u1.value;
- long size = memo->u3.cnt;
-
- if (RARRAY(ary)->len == size) {
- rb_ary_shift(ary);
- }
- rb_ary_push(ary, val);
- if (RARRAY(ary)->len == size) {
- rb_yield(rb_ary_dup(ary));
- }
- return Qnil;
-}
-
-/*
- * call-seq:
- * each_cons(n) {...}
- *
- * Iterates the given block for each array of consecutive <n>
- * elements.
- *
- * e.g.:
- * (1..10).each_cons(3) {|a| p a}
- * # outputs below
- * [1, 2, 3]
- * [2, 3, 4]
- * [3, 4, 5]
- * [4, 5, 6]
- * [5, 6, 7]
- * [6, 7, 8]
- * [7, 8, 9]
- * [8, 9, 10]
- *
- */
-static VALUE
-enum_each_cons(obj, n)
- VALUE obj, n;
-{
- long size = NUM2LONG(n);
- NODE *memo;
-
- if (size <= 0) rb_raise(rb_eArgError, "invalid size");
- memo = rb_node_newnode(NODE_MEMO, rb_ary_new2(size), 0, size);
-
- rb_iterate(rb_each, obj, each_cons_i, (VALUE)memo);
-
- return Qnil;
-}
-
-/*
- * call-seq:
- * e.enum_cons(n)
- *
- * Returns Enumerable::Enumerator.new(self, :each_cons, n).
- *
- */
-static VALUE
-enumerator_enum_cons(obj, n)
- VALUE obj, n;
-{
- return rb_funcall(rb_cEnumerator, id_new, 3, obj, sym_each_cons, n);
-}
-
-/*
- * call-seq:
- * Enumerable::Enumerator.new(obj, method = :each, *args)
- *
- * Creates a new Enumerable::Enumerator object, which is to be
- * used as an Enumerable object using the given object's given
- * method with the given arguments.
- *
- * e.g.:
- * str = "xyz"
- *
- * enum = Enumerable::Enumerator.new(str, :each_byte)
- * a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"]
- *
- */
-static VALUE
-enumerator_initialize(argc, argv, obj)
- int argc;
- VALUE *argv;
- VALUE obj;
-{
- VALUE enum_obj, enum_method, enum_args;
-
- rb_scan_args(argc, argv, "11*", &enum_obj, &enum_method, &enum_args);
-
- if (enum_method == Qnil)
- enum_method = sym_each;
-
- rb_ivar_set(obj, id_enum_obj, enum_obj);
- rb_ivar_set(obj, id_enum_method, enum_method);
- rb_ivar_set(obj, id_enum_args, enum_args);
-
- return Qnil;
-}
-
-static VALUE
-enumerator_iter(memo)
- NODE *memo;
-{
- return rb_apply(memo->u1.value, memo->u2.id, memo->u3.value);
-}
-
-/*
- * call-seq:
- * enum.each {...}
- *
- * Iterates the given block using the object and the method specified
- * in the first place.
- *
- */
-static VALUE
-enumerator_each(obj)
- VALUE obj;
-{
- VALUE val;
-
- obj = (VALUE)rb_node_newnode(NODE_MEMO,
- rb_ivar_get(obj, id_enum_obj),
- rb_to_id(rb_ivar_get(obj, id_enum_method)),
- rb_ivar_get(obj, id_enum_args));
- val = rb_iterate((VALUE (*)_((VALUE)))enumerator_iter, obj, rb_yield, 0);
- return val;
-}
-
-void
-Init_enumerator()
-{
- VALUE rb_mEnumerable;
-
- rb_define_method(rb_mKernel, "to_enum", obj_to_enum, -2);
- rb_define_method(rb_mKernel, "enum_for", obj_to_enum, -2);
-
- rb_mEnumerable = rb_path2class("Enumerable");
-
- rb_define_method(rb_mEnumerable, "enum_with_index", enumerator_enum_with_index, 0);
- rb_define_method(rb_mEnumerable, "each_slice", enum_each_slice, 1);
- rb_define_method(rb_mEnumerable, "enum_slice", enumerator_enum_slice, 1);
- rb_define_method(rb_mEnumerable, "each_cons", enum_each_cons, 1);
- rb_define_method(rb_mEnumerable, "enum_cons", enumerator_enum_cons, 1);
-
- rb_cEnumerator = rb_define_class_under(rb_mEnumerable, "Enumerator", rb_cObject);
- rb_include_module(rb_cEnumerator, rb_mEnumerable);
-
- rb_define_method(rb_cEnumerator, "initialize", enumerator_initialize, -1);
- rb_define_method(rb_cEnumerator, "each", enumerator_each, 0);
-
- sym_each = ID2SYM(rb_intern("each"));
- sym_each_with_index = ID2SYM(rb_intern("each_with_index"));
- sym_each_slice = ID2SYM(rb_intern("each_slice"));
- sym_each_cons = ID2SYM(rb_intern("each_cons"));
-
- id_new = rb_intern("new");
- id_enum_obj = rb_intern("enum_obj");
- id_enum_method = rb_intern("enum_method");
- id_enum_args = rb_intern("enum_args");
-}
diff --git a/ext/enumerator/enumerator.txt b/ext/enumerator/enumerator.txt
deleted file mode 100644
index 1b84c0c088..0000000000
--- a/ext/enumerator/enumerator.txt
+++ /dev/null
@@ -1,102 +0,0 @@
-.\" enumerator.txt - -*- Indented-Text -*-
-$Idaemons: /home/cvs/rb/enumerator/enumerator.txt,v 1.2 2001/07/15 10:19:24 knu Exp $
-$RoughId: enumerator.txt,v 1.5 2003/02/20 12:24:51 knu Exp $
-$Id: enumerator.txt,v 1.2 2003/10/17 14:09:43 knu Exp $
-
-** Enumerable::Enumerator(Class)
-
-A class which provides a method `each' to be used as an Enumerable
-object.
-
-Superclass: Object
-
-Mix-ins: Enumerable
-
-require 'enumerator'
-
-Class Methods:
-
- new(obj, method = :each, *args)
-
- Creates a new Enumerable::Enumerator object, which is to be
- used as an Enumerable object using the given object's given
- method with the given arguments.
-
- e.g.:
- str = "xyz"
-
- enum = Enumerable::Enumerator.new(str, :each_byte)
- a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"]
-
-Methods:
-
- each {...}
-
- Iterates the given block using the object and the method
- specified in the first place.
-
-
-Requiring this module also adds some methods to the Object class:
-
- to_enum(method = :each, *args)
- enum_for(method = :each, *args)
-
- Returns Enumerable::Enumerator.new(self, method, *args).
-
- e.g.:
- str = "xyz"
-
- enum = str.enum_for(:each_byte)
- a = enum.map {|b| '%02x' % b } #=> ["78", "79", "7a"]
-
- # protects an array from being modified
- a = [1, 2, 3]
- some_method(a.to_enum)
-
-And the Enumerable module.
-
- each_slice(n) {...}
-
- Iterates the given block for each slice of <n> elements.
-
- e.g.:
- (1..10).each_slice(3) {|a| p a}
- # outputs below
- [1, 2, 3]
- [4, 5, 6]
- [7, 8, 9]
- [10]
-
- enum_slice(n)
-
- Returns Enumerable::Enumerator.new(self, :each_slice, n).
-
- each_cons(n) {...}
-
- Iterates the given block for each array of consecutive <n>
- elements.
-
- e.g.:
- (1..10).each_cons(3) {|a| p a}
- # outputs below
- [1, 2, 3]
- [2, 3, 4]
- [3, 4, 5]
- [4, 5, 6]
- [5, 6, 7]
- [6, 7, 8]
- [7, 8, 9]
- [8, 9, 10]
-
- enum_cons(n)
-
- Returns Enumerable::Enumerator.new(self, :each_cons, n).
-
- enum_with_index
-
- Returns Enumerable::Enumerator.new(self, :each_with_index).
-
--------------------------------------------------------
-Local variables:
-fill-column: 70
-end:
diff --git a/ext/enumerator/extconf.rb b/ext/enumerator/extconf.rb
deleted file mode 100644
index 94e2ee38b2..0000000000
--- a/ext/enumerator/extconf.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-require 'mkmf'
-create_makefile('enumerator')
diff --git a/ext/etc/etc.c b/ext/etc/etc.c
index 084405408f..ecb9e16411 100644
--- a/ext/etc/etc.c
+++ b/ext/etc/etc.c
@@ -2,8 +2,8 @@
etc.c -
- $Author: shyouhei $
- $Date: 2007/01/09 12:24:20 $
+ $Author$
+ $Date$
created at: Tue Mar 22 18:39:19 JST 1994
************************************************/
@@ -35,6 +35,8 @@ char *getenv();
char *getlogin();
/* Returns the short user name of the currently logged in user.
+ * Unfortunately, it is often rather easy to fool getlogin().
+ * Avoid getlogin() for security-related purposes.
*
* e.g.
* Etc.getlogin -> 'guest'
diff --git a/ext/extmk.rb b/ext/extmk.rb
index 86d59b0946..df2e4c069e 100644
--- a/ext/extmk.rb
+++ b/ext/extmk.rb
@@ -1,13 +1,19 @@
#! /usr/local/bin/ruby
# -*- ruby -*-
+$extension = nil
+$extstatic = nil
$force_static = nil
$install = nil
$destdir = nil
+$dryrun = false
$clean = nil
$nodynamic = nil
$extinit = nil
$extobjs = nil
+$extflags = ""
+$extlibs = nil
+$extpath = nil
$ignore = nil
$message = nil
@@ -73,12 +79,14 @@ def extract_makefile(makefile, keep = true)
$static ||= m[/^EXTSTATIC[ \t]*=[ \t]*(\S+)/, 1] || false
/^STATIC_LIB[ \t]*=[ \t]*\S+/ =~ m or $static = nil
$preload = Shellwords.shellwords(m[/^preload[ \t]*=[ \t]*(.*)/, 1] || "")
- $DLDFLAGS += " " + (m[/^DLDFLAGS[ \t]*=[ \t]*(.*)/, 1] || "")
+ $DLDFLAGS += " " + (m[/^dldflags[ \t]*=[ \t]*(.*)/, 1] || "")
if s = m[/^LIBS[ \t]*=[ \t]*(.*)/, 1]
s.sub!(/^#{Regexp.quote($LIBRUBYARG)} */, "")
s.sub!(/ *#{Regexp.quote($LIBS)}$/, "")
$libs = s
end
+ $objs = (m[/^OBJS[ \t]*=[ \t](.*)/, 1] || "").split
+ $srcs = (m[/^SRCS[ \t]*=[ \t](.*)/, 1] || "").split
$LOCAL_LIBS = m[/^LOCAL_LIBS[ \t]*=[ \t]*(.*)/, 1] || ""
$LIBPATH = Shellwords.shellwords(m[/^libpath[ \t]*=[ \t]*(.*)/, 1] || "") - %w[$(libdir) $(topdir)]
true
@@ -113,6 +121,8 @@ def extmake(target)
$mdir = target
$srcdir = File.join($top_srcdir, "ext", $mdir)
$preload = nil
+ $objs = ""
+ $srcs = ""
$compiled[target] = false
makefile = "./Makefile"
ok = File.exist?(makefile)
@@ -125,7 +135,6 @@ def extmake(target)
"topdir" => $topdir,
}
mkconfig = {
- "top_srcdir" => ($hdrdir == top_srcdir) ? top_srcdir : "$(topdir)"+top_srcdir[2..-1],
"hdrdir" => "$(top_srcdir)",
"srcdir" => "$(top_srcdir)/ext/#{$mdir}",
"topdir" => $topdir,
@@ -145,18 +154,17 @@ def extmake(target)
begin
$extconf_h = nil
ok &&= extract_makefile(makefile)
+ conf = ["#{$srcdir}/makefile.rb", "#{$srcdir}/extconf.rb"].find {|f| File.exist?(f)}
if (($extconf_h && !File.exist?($extconf_h)) ||
!(t = modified?(makefile, MTIMES)) ||
- %W"#{$srcdir}/makefile.rb #{$srcdir}/extconf.rb #{$srcdir}/depend".any? {|f| modified?(f, [t])})
+ [conf, "#{$srcdir}/depend"].any? {|f| modified?(f, [t])})
then
ok = false
init_mkmf
Logging::logfile 'mkmf.log'
rm_f makefile
- if File.exist?($0 = "#{$srcdir}/makefile.rb")
- load $0
- elsif File.exist?($0 = "#{$srcdir}/extconf.rb")
- load $0
+ if conf
+ load $0 = conf
else
create_makefile(target)
end
@@ -289,7 +297,7 @@ def parse_args()
$mflags.unshift(*rest) unless rest.empty?
def $mflags.set?(flag)
- grep(/\A-(?!-).*#{'%c' % flag}/i) { return true }
+ grep(/\A-(?!-).*#{flag.chr}/i) { return true }
false
end
def $mflags.defined?(var)
@@ -316,9 +324,9 @@ parse_args()
if target = ARGV.shift and /^[a-z-]+$/ =~ target
$mflags.push(target)
- target = target.sub(/^(dist|real)(?=(?:clean)?$)/, '')
case target
- when /clean/
+ when /^(dist|real)?(clean)$/
+ target = $2
$ignore ||= true
$clean = $1 ? $1[0] : true
when /^install\b/
@@ -339,14 +347,22 @@ end
EXEEXT = CONFIG['EXEEXT']
if CROSS_COMPILING
- $ruby = CONFIG['MINIRUBY']
+ $ruby = $mflags.defined?("MINIRUBY") || CONFIG['MINIRUBY']
elsif sep = config_string('BUILD_FILE_SEPARATOR')
$ruby = "$(topdir:/=#{sep})#{sep}miniruby" + EXEEXT
else
$ruby = '$(topdir)/miniruby' + EXEEXT
end
-$ruby << " -I'$(topdir)' -I'$(top_srcdir)/lib'"
+$ruby << " -I'$(topdir)'"
+unless CROSS_COMPILING
+ $ruby << " -I'$(top_srcdir)/lib'"
+ $ruby << " -I'$(extout)/$(arch)' -I'$(extout)/common'" if $extout
+ $ruby << " -I./- -I'$(top_srcdir)/ext' -rpurelib.rb"
+ ENV["RUBYLIB"] = "-"
+ ENV["RUBYOPT"] = "-rpurelib.rb"
+end
$config_h = '$(topdir)/config.h'
+$mflags << "ruby=#$ruby"
MTIMES = [__FILE__, 'rbconfig.rb', srcdir+'/lib/mkmf.rb'].collect {|f| File.mtime(f)}
@@ -395,12 +411,12 @@ else
elsif (w = w.grep(String)).empty?
proc {true}
else
- w.collect {|opt| opt.split(/,/)}.flatten.method(:any?)
+ proc {|c1| w.collect {|opt| opt.split(/,/)}.flatten.any?(&c1)}
end
}
cond = proc {|ext|
cond1 = proc {|n| File.fnmatch(n, ext, File::FNM_PATHNAME)}
- withes.call(&cond1) or !withouts.call(&cond1)
+ withes.call(cond1) or !withouts.call(cond1)
}
exts |= Dir.glob("#{ext_prefix}/*/**/extconf.rb").collect {|d|
d = File.dirname(d)
@@ -412,15 +428,7 @@ else
end
if $extout
- Config.expand(extout = "#$extout", Config::CONFIG.merge("topdir"=>$topdir))
- if $install
- dest = Config.expand($rubylibdir.dup)
- unless $destdir.empty?
- dest.sub!($dest_prefix_pattern, Config.expand($destdir.dup))
- end
- FileUtils.cp_r(extout+"/.", dest, :verbose => true, :noop => $dryrun)
- exit
- end
+ extout = Config.expand("#{$extout}", Config::CONFIG.merge("topdir"=>$topdir))
unless $ignore
FileUtils.mkpath(extout)
end
@@ -449,14 +457,27 @@ if $ignore
Dir.chdir ".."
if $clean
Dir.rmdir('ext') rescue nil
- FileUtils.rm_rf(extout) if $extout
+ if $extout
+ FileUtils.rm_rf([extout+"/common", extout+"/include/ruby", extout+"/rdoc"])
+ FileUtils.rm_rf(extout+"/"+CONFIG["arch"])
+ if $clean != true
+ FileUtils.rm_rf(extout+"/include/"+CONFIG["arch"])
+ FileUtils.rm_f($mflags.defined?("INSTALLED_LIST")||ENV["INSTALLED_LIST"]||".installed.list")
+ Dir.rmdir(extout+"/include") rescue nil
+ Dir.rmdir(extout) rescue nil
+ end
+ end
end
exit
end
-if $extlist.size > 0
- $extinit ||= ""
- $extobjs ||= ""
+$extinit ||= ""
+$extobjs ||= ""
+$extpath ||= []
+$extflags ||= ""
+$extlibs ||= []
+unless $extlist.empty?
+ $extinit << "\n" unless $extinit.empty?
list = $extlist.dup
built = []
while e = list.shift
@@ -470,28 +491,33 @@ if $extlist.size > 0
end
f = format("%s/%s.%s", s, i, $LIBEXT)
if File.exist?(f)
- $extinit += "\tinit(Init_#{i}, \"#{t}.so\");\n"
- $extobjs += "ext/#{f} "
+ $extinit << " init(Init_#{i}, \"#{t}.so\");\n"
+ $extobjs << "ext/#{f} "
built << t
end
end
src = %{\
-extern char *ruby_sourcefile, *rb_source_filename();
-#define init(func, name) (ruby_sourcefile = src = rb_source_filename(name), func(), rb_provide(src))
-void Init_ext() {\n\tchar* src;\n#$extinit}
+#include "ruby.h"
+
+#define init(func, name) {void func _((void)); ruby_init_ext(name, func);}
+
+void ruby_init_ext _((const char *name, void (*init)(void)));
+
+void Init_ext _((void))\n{\n#$extinit}
}
if !modified?(extinit.c, MTIMES) || IO.read(extinit.c) != src
open(extinit.c, "w") {|f| f.print src}
end
- $extobjs = "ext/#{extinit.o} " + $extobjs
+ $extobjs = "ext/#{extinit.o} #{$extobjs}"
if RUBY_PLATFORM =~ /m68k-human|beos/
$extflags.delete("-L/usr/local/lib")
end
$extpath.delete("$(topdir)")
$extflags = libpathflag($extpath) << " " << $extflags.strip
conf = [
+ ['LIBRUBY_SO_UPDATE', '$(LIBRUBY_EXTS)'],
['SETUP', $setup],
[enable_config("shared", $enable_shared) ? 'DLDOBJS' : 'EXTOBJS', $extobjs],
['EXTLIBS', $extlibs.join(' ')], ['EXTLDFLAGS', $extflags]
@@ -508,7 +534,7 @@ rubies = []
%w[RUBY RUBYW STATIC_RUBY].each {|r|
n = r
if r = arg_config("--"+r.downcase) || config_string(r+"_INSTALL_NAME")
- rubies << r+EXEEXT
+ rubies << Config.expand(r+=EXEEXT)
$mflags << "#{n}=#{r}"
end
}
@@ -517,15 +543,21 @@ Dir.chdir ".."
unless $destdir.to_s.empty?
$mflags.defined?("DESTDIR") or $mflags << "DESTDIR=#{$destdir}"
end
-unless $extlist.empty?
- rm_f(Config::CONFIG["LIBRUBY_SO"])
-end
puts "making #{rubies.join(', ')}"
$stdout.flush
$mflags.concat(rubies)
if $nmake == ?b
- $mflags.collect {|flag| flag.sub!(/\A(?=\w+=)/, "-D")}
+ unless (vars = $mflags.grep(/\A\w+=/n)).empty?
+ open(mkf = "libruby.mk", "wb") do |tmf|
+ tmf.puts("!include Makefile")
+ tmf.puts
+ tmf.puts(*vars.map {|v| v.sub(/=/, " = ")})
+ tmf.puts("PRE_LIBRUBY_UPDATE = del #{mkf}")
+ end
+ $mflags.unshift("-f#{mkf}")
+ vars.each {|flag| flag.sub!(/\A/, "-D")}
+ end
end
system($make, *sysquote($mflags)) or exit($?.exitstatus)
diff --git a/ext/fcntl/fcntl.c b/ext/fcntl/fcntl.c
index 8f9cb43d0c..57cca103f4 100644
--- a/ext/fcntl/fcntl.c
+++ b/ext/fcntl/fcntl.c
@@ -2,7 +2,7 @@
fcntl.c -
- $Author: matz $
+ $Author$
created at: Mon Apr 7 18:53:05 JST 1997
Copyright (C) 1997-2001 Yukihiro Matsumoto
diff --git a/ext/gdbm/gdbm.c b/ext/gdbm/gdbm.c
index 691d512460..2057101206 100644
--- a/ext/gdbm/gdbm.c
+++ b/ext/gdbm/gdbm.c
@@ -2,10 +2,12 @@
gdbm.c -
- $Author: usa $
- $Date: 2005/06/20 07:53:20 $
+ $Author$
+ $Date$
modified at: Mon Jan 24 15:59:52 JST 1994
+ Documentation by Peter Adolphs < futzilogik at users dot sourceforge dot net >
+
************************************************/
#include "ruby.h"
@@ -14,6 +16,62 @@
#include <fcntl.h>
#include <errno.h>
+/*
+ * Document-class: GDBM
+ *
+ * == Summary
+ *
+ * Ruby extension for GNU dbm (gdbm) -- a simple database engine for storing
+ * key-value pairs on disk.
+ *
+ * == Description
+ *
+ * GNU dbm is a library for simple databases. A database is a file that stores
+ * key-value pairs. Gdbm allows the user to store, retrieve, and delete data by
+ * key. It furthermore allows a non-sorted traversal of all key-value pairs.
+ * A gdbm database thus provides the same functionality as a hash. As
+ * with objects of the Hash class, elements can be accessed with <tt>[]</tt>.
+ * Furthermore, GDBM mixes in the Enumerable module, thus providing convenient
+ * methods such as #find, #collect, #map, etc.
+ *
+ * A process is allowed to open several different databases at the same time.
+ * A process can open a database as a "reader" or a "writer". Whereas a reader
+ * has only read-access to the database, a writer has read- and write-access.
+ * A database can be accessed either by any number of readers or by exactly one
+ * writer at the same time.
+ *
+ * == Examples
+ *
+ * 1. Opening/creating a database, and filling it with some entries:
+ *
+ * require 'gdbm'
+ *
+ * gdbm = GDBM.new("fruitstore.db")
+ * gdbm["ananas"] = "3"
+ * gdbm["banana"] = "8"
+ * gdbm["cranberry"] = "4909"
+ * gdbm.close
+ *
+ * 2. Reading out a database:
+ *
+ * require 'gdbm'
+ *
+ * gdbm = GDBM.new("fruitstore.db")
+ * gdbm.each_pair do |key, value|
+ * print "#{key}: #{value}\n"
+ * end
+ * gdbm.close
+ *
+ * produces
+ *
+ * banana: 8
+ * ananas: 3
+ * cranberry: 4909
+ *
+ * == Links
+ *
+ * * http://www.gnu.org/software/gdbm/
+ */
static VALUE rb_cGDBM, rb_eGDBMError, rb_eGDBMFatalError;
#define RUBY_GDBM_RW_BIT 0x20000000
@@ -24,7 +82,7 @@ static void
rb_gdbm_fatal(msg)
char *msg;
{
- rb_raise(rb_eGDBMFatalError, msg);
+ rb_raise(rb_eGDBMFatalError, "%s", msg);
}
struct dbmdata {
@@ -54,11 +112,17 @@ free_dbm(dbmp)
struct dbmdata *dbmp;
{
if (dbmp) {
- if (dbmp->di_dbm) gdbm_close(dbmp->di_dbm);
- free(dbmp);
+ if (dbmp->di_dbm) gdbm_close(dbmp->di_dbm);
+ free(dbmp);
}
}
+/*
+ * call-seq:
+ * gdbm.close -> nil
+ *
+ * Closes the associated database file.
+ */
static VALUE
fgdbm_close(obj)
VALUE obj;
@@ -72,6 +136,12 @@ fgdbm_close(obj)
return Qnil;
}
+/*
+ * call-seq:
+ * gdbm.closed? -> true or false
+ *
+ * Returns true if the associated database file has been closed.
+ */
static VALUE
fgdbm_closed(obj)
VALUE obj;
@@ -80,9 +150,9 @@ fgdbm_closed(obj)
Data_Get_Struct(obj, struct dbmdata, dbmp);
if (dbmp == 0)
- return Qtrue;
+ return Qtrue;
if (dbmp->di_dbm == 0)
- return Qtrue;
+ return Qtrue;
return Qfalse;
}
@@ -96,6 +166,29 @@ fgdbm_s_alloc(klass)
return Data_Wrap_Struct(klass, 0, free_dbm, 0);
}
+/*
+ * call-seq:
+ * GDBM.new(filename, mode = 0666, flags = nil)
+ *
+ * Creates a new GDBM instance by opening a gdbm file named _filename_.
+ * If the file does not exist, a new file with file mode _mode_ will be
+ * created. _flags_ may be one of the following:
+ * * *READER* - open as a reader
+ * * *WRITER* - open as a writer
+ * * *WRCREAT* - open as a writer; if the database does not exist, create a new one
+ * * *NEWDB* - open as a writer; overwrite any existing databases
+ *
+ * The values *WRITER*, *WRCREAT* and *NEWDB* may be combined with the following
+ * values by bitwise or:
+ * * *SYNC* - cause all database operations to be synchronized to the disk
+ * * *NOLOCK* - do not lock the database file
+ *
+ * If no _flags_ are specified, the GDBM object will try to open the database
+ * file as a writer and will create it if it does not already exist
+ * (cf. flag <tt>WRCREAT</tt>). If this fails (for instance, if another process
+ * has already opened the database as a reader), it will try to open the
+ * database file as a reader (cf. flag <tt>READER</tt>).
+ */
static VALUE
fgdbm_initialize(argc, argv, obj)
int argc;
@@ -108,13 +201,13 @@ fgdbm_initialize(argc, argv, obj)
int mode, flags = 0;
if (rb_scan_args(argc, argv, "12", &file, &vmode, &vflags) == 1) {
- mode = 0666; /* default value */
+ mode = 0666; /* default value */
}
else if (NIL_P(vmode)) {
- mode = -1; /* return nil if DB not exist */
+ mode = -1; /* return nil if DB does not exist */
}
else {
- mode = NUM2INT(vmode);
+ mode = NUM2INT(vmode);
}
if (!NIL_P(vflags))
@@ -160,6 +253,25 @@ fgdbm_initialize(argc, argv, obj)
return obj;
}
+/*
+ * call-seq:
+ * GDBM.open(filename, mode = 0666, flags = nil)
+ * GDBM.open(filename, mode = 0666, flags = nil) { |gdbm| ... }
+ *
+ * If called without a block, this is synonymous to GDBM::new.
+ * If a block is given, the new GDBM instance will be passed to the block
+ * as a parameter, and the corresponding database file will be closed
+ * after the execution of the block code has been finished.
+ *
+ * Example for an open call with a block:
+ *
+ * require 'gdbm'
+ * GDBM.open("fruitstore.db") do |gdbm|
+ * gdbm.each_pair do |key, value|
+ * print "#{key}: #{value}\n"
+ * end
+ * end
+ */
static VALUE
fgdbm_s_open(argc, argv, klass)
int argc;
@@ -191,14 +303,10 @@ rb_gdbm_fetch(dbm, key)
if (val.dptr == 0)
return Qnil;
- str = rb_obj_alloc(rb_cString);
- RSTRING(str)->len = val.dsize;
- RSTRING(str)->aux.capa = val.dsize;
- RSTRING(str)->ptr = REALLOC_N(val.dptr,char,val.dsize+1);
- RSTRING(str)->ptr[val.dsize] = '\0';
-
+ str = rb_str_new(val.dptr, val.dsize);
+ free(val.dptr);
OBJ_TAINT(str);
- return (VALUE)str;
+ return str;
}
static VALUE
@@ -237,12 +345,8 @@ rb_gdbm_firstkey(dbm)
if (key.dptr == 0)
return Qnil;
- str = rb_obj_alloc(rb_cString);
- RSTRING(str)->len = key.dsize;
- RSTRING(str)->aux.capa = key.dsize;
- RSTRING(str)->ptr = REALLOC_N(key.dptr,char,key.dsize+1);
- RSTRING(str)->ptr[RSTRING(str)->len] = '\0';
-
+ str = rb_str_new(key.dptr, key.dsize);
+ free(key.dptr);
OBJ_TAINT(str);
return str;
}
@@ -261,12 +365,8 @@ rb_gdbm_nextkey(dbm, keystr)
if (key2.dptr == 0)
return Qnil;
- str = rb_obj_alloc(rb_cString);
- RSTRING(str)->len = key2.dsize;
- RSTRING(str)->aux.capa = key2.dsize;
- RSTRING(str)->ptr = REALLOC_N(key2.dptr,char,key2.dsize+1);
- RSTRING(str)->ptr[RSTRING(str)->len] = '\0';
-
+ str = rb_str_new(key2.dptr, key2.dsize);
+ free(key2.dptr);
OBJ_TAINT(str);
return str;
}
@@ -286,6 +386,12 @@ fgdbm_fetch(obj, keystr, ifnone)
return valstr;
}
+/*
+ * call-seq:
+ * gdbm[key] -> value
+ *
+ * Retrieves the _value_ corresponding to _key_.
+ */
static VALUE
fgdbm_aref(obj, keystr)
VALUE obj, keystr;
@@ -293,6 +399,13 @@ fgdbm_aref(obj, keystr)
return rb_gdbm_fetch3(obj, keystr);
}
+/*
+ * call-seq:
+ * gdbm.fetch(key [, default]) -> value
+ *
+ * Retrieves the _value_ corresponding to _key_. If there is no value
+ * associated with _key_, _default_ will be returned instead.
+ */
static VALUE
fgdbm_fetch_m(argc, argv, obj)
int argc;
@@ -304,11 +417,18 @@ fgdbm_fetch_m(argc, argv, obj)
rb_scan_args(argc, argv, "11", &keystr, &ifnone);
valstr = fgdbm_fetch(obj, keystr, ifnone);
if (argc == 1 && !rb_block_given_p() && NIL_P(valstr))
- rb_raise(rb_eIndexError, "key not found");
+ rb_raise(rb_eIndexError, "key not found");
return valstr;
}
+/*
+ * call-seq:
+ * gdbm.index(value) -> key
+ *
+ * Returns the _key_ for a given _value_. If several keys may map to the
+ * same value, the key that is found first will be returned.
+ */
static VALUE
fgdbm_index(obj, valstr)
VALUE obj, valstr;
@@ -350,6 +470,13 @@ fgdbm_indexes(argc, argv, obj)
return new;
}
+/*
+ * call-seq:
+ * gdbm.select { |value| block } -> array
+ *
+ * Returns a new array of all values of the database for which _block_
+ * evaluates to true.
+ */
static VALUE
fgdbm_select(argc, argv, obj)
int argc;
@@ -390,6 +517,12 @@ fgdbm_select(argc, argv, obj)
return new;
}
+/*
+ * call-seq:
+ * gdbm.values_at(key, ...) -> array
+ *
+ * Returns an array of the values associated with each specified _key_.
+ */
static VALUE
fgdbm_values_at(argc, argv, obj)
int argc;
@@ -429,19 +562,26 @@ rb_gdbm_delete(obj, keystr)
GetDBM2(obj, dbmp, dbm);
if (!gdbm_exists(dbm, key)) {
- return Qnil;
+ return Qnil;
}
if (gdbm_delete(dbm, key)) {
- dbmp->di_size = -1;
- rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
+ dbmp->di_size = -1;
+ rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
}
else if (dbmp->di_size >= 0) {
- dbmp->di_size--;
+ dbmp->di_size--;
}
return obj;
}
+/*
+ * call-seq:
+ * gdbm.delete(key) -> value or nil
+ *
+ * Removes the key-value-pair with the specified _key_ from this database and
+ * returns the corresponding _value_. Returns nil if the database is empty.
+ */
static VALUE
fgdbm_delete(obj, keystr)
VALUE obj, keystr;
@@ -453,6 +593,13 @@ fgdbm_delete(obj, keystr)
return valstr;
}
+/*
+ * call-seq:
+ * gdbm.shift -> (key, value) or nil
+ *
+ * Removes a key-value-pair from this database and returns it as a
+ * two-item array [ _key_, _value_ ]. Returns nil if the database is empty.
+ */
static VALUE
fgdbm_shift(obj)
VALUE obj;
@@ -471,6 +618,13 @@ fgdbm_shift(obj)
return rb_assoc_new(keystr, valstr);
}
+/*
+ * call-seq:
+ * gdbm.delete_if { |key, value| block } -> gdbm
+ * gdbm.reject! { |key, value| block } -> gdbm
+ *
+ * Deletes every key-value pair from _gdbm_ for which _block_ evaluates to true.
+ */
static VALUE
fgdbm_delete_if(obj)
VALUE obj;
@@ -489,11 +643,11 @@ fgdbm_delete_if(obj)
for (keystr = rb_gdbm_firstkey(dbm); RTEST(keystr);
keystr = rb_gdbm_nextkey(dbm, keystr)) {
- valstr = rb_gdbm_fetch2(dbm, keystr);
+ valstr = rb_gdbm_fetch2(dbm, keystr);
ret = rb_protect(rb_yield, rb_assoc_new(keystr, valstr), &status);
if (status != 0) break;
- if (RTEST(ret)) rb_ary_push(ary, keystr);
- GetDBM2(obj, dbmp, dbm);
+ if (RTEST(ret)) rb_ary_push(ary, keystr);
+ GetDBM2(obj, dbmp, dbm);
}
for (i = 0; i < RARRAY(ary)->len; i++)
@@ -504,6 +658,12 @@ fgdbm_delete_if(obj)
return obj;
}
+/*
+ * call-seq:
+ * gdbm.clear -> gdbm
+ *
+ * Removes all the key-value pairs within _gdbm_.
+ */
static VALUE
fgdbm_clear(obj)
VALUE obj;
@@ -518,11 +678,11 @@ fgdbm_clear(obj)
#if 0
while (key = gdbm_firstkey(dbm), key.dptr) {
- if (gdbm_delete(dbm, key)) {
- free(key.dptr);
- rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
- }
- free(key.dptr);
+ if (gdbm_delete(dbm, key)) {
+ free(key.dptr);
+ rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
+ }
+ free(key.dptr);
}
#else
while (key = gdbm_firstkey(dbm), key.dptr) {
@@ -542,6 +702,13 @@ fgdbm_clear(obj)
return obj;
}
+/*
+ * call-seq:
+ * gdbm.invert -> hash
+ *
+ * Returns a hash created by using _gdbm_'s values as keys, and the keys
+ * as values.
+ */
static VALUE
fgdbm_invert(obj)
VALUE obj;
@@ -584,6 +751,14 @@ update_i(pair, dbm)
return Qnil;
}
+/*
+ * call-seq:
+ * gdbm.update(other) -> gdbm
+ *
+ * Adds the key-value pairs of _other_ to _gdbm_, overwriting entries with
+ * duplicate keys with those from _other_. _other_ must have an each_pair
+ * method.
+ */
static VALUE
fgdbm_update(obj, other)
VALUE obj, other;
@@ -592,6 +767,13 @@ fgdbm_update(obj, other)
return obj;
}
+/*
+ * call-seq:
+ * gdbm.replace(other) -> gdbm
+ *
+ * Replaces the content of _gdbm_ with the key-value pairs of _other_.
+ * _other_ must have an each_pair method.
+ */
static VALUE
fgdbm_replace(obj, other)
VALUE obj, other;
@@ -601,6 +783,13 @@ fgdbm_replace(obj, other)
return obj;
}
+/*
+ * call-seq:
+ * gdbm[key]= value -> value
+ * gdbm.store(key, value) -> value
+ *
+ * Associates the value _value_ with the specified _key_.
+ */
static VALUE
fgdbm_store(obj, keystr, valstr)
VALUE obj, keystr, valstr;
@@ -622,13 +811,20 @@ fgdbm_store(obj, keystr, valstr)
GetDBM2(obj, dbmp, dbm);
dbmp->di_size = -1;
if (gdbm_store(dbm, key, val, GDBM_REPLACE)) {
- if (errno == EPERM) rb_sys_fail(0);
- rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
+ if (errno == EPERM) rb_sys_fail(0);
+ rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
}
return valstr;
}
+/*
+ * call-seq:
+ * gdbm.length -> fixnum
+ * gdbm.size -> fixnum
+ *
+ * Returns the number of key-value pairs in this database.
+ */
static VALUE
fgdbm_length(obj)
VALUE obj;
@@ -651,6 +847,12 @@ fgdbm_length(obj)
return INT2FIX(i);
}
+/*
+ * call-seq:
+ * gdbm.empty? -> true or false
+ *
+ * Returns true if the database is empty.
+ */
static VALUE
fgdbm_empty_p(obj)
VALUE obj;
@@ -675,6 +877,13 @@ fgdbm_empty_p(obj)
return Qfalse;
}
+/*
+ * call-seq:
+ * gdbm.each_value { |value| block } -> gdbm
+ *
+ * Executes _block_ for each key in the database, passing the corresponding
+ * _value_ as a parameter.
+ */
static VALUE
fgdbm_each_value(obj)
VALUE obj;
@@ -693,6 +902,13 @@ fgdbm_each_value(obj)
return obj;
}
+/*
+ * call-seq:
+ * gdbm.each_key { |key| block } -> gdbm
+ *
+ * Executes _block_ for each key in the database, passing the
+ * _key_ as a parameter.
+ */
static VALUE
fgdbm_each_key(obj)
VALUE obj;
@@ -711,6 +927,13 @@ fgdbm_each_key(obj)
return obj;
}
+/*
+ * call-seq:
+ * gdbm.each_pair { |key, value| block } -> gdbm
+ *
+ * Executes _block_ for each key in the database, passing the _key_ and the
+ * correspoding _value_ as a parameter.
+ */
static VALUE
fgdbm_each_pair(obj)
VALUE obj;
@@ -724,12 +947,18 @@ fgdbm_each_pair(obj)
keystr = rb_gdbm_nextkey(dbm, keystr)) {
rb_yield(rb_assoc_new(keystr, rb_gdbm_fetch2(dbm, keystr)));
- GetDBM2(obj, dbmp, dbm);
+ GetDBM2(obj, dbmp, dbm);
}
return obj;
}
+/*
+ * call-seq:
+ * gdbm.keys -> array
+ *
+ * Returns an array of all keys of this database.
+ */
static VALUE
fgdbm_keys(obj)
VALUE obj;
@@ -749,6 +978,12 @@ fgdbm_keys(obj)
return ary;
}
+/*
+ * call-seq:
+ * gdbm.values -> array
+ *
+ * Returns an array of all values of this database.
+ */
static VALUE
fgdbm_values(obj)
VALUE obj;
@@ -762,14 +997,22 @@ fgdbm_values(obj)
ary = rb_ary_new();
for (key = gdbm_firstkey(dbm); key.dptr; key = nextkey) {
nextkey = gdbm_nextkey(dbm, key);
- valstr = rb_gdbm_fetch(dbm, key);
+ valstr = rb_gdbm_fetch(dbm, key);
free(key.dptr);
- rb_ary_push(ary, valstr);
+ rb_ary_push(ary, valstr);
}
return ary;
}
+/*
+ * call-seq:
+ * gdbm.has_key?(k) -> true or false
+ * gdbm.key?(k) -> true or false
+ *
+ * Returns true if the given key _k_ exists within the database.
+ * Returns false otherwise.
+ */
static VALUE
fgdbm_has_key(obj, keystr)
VALUE obj, keystr;
@@ -788,6 +1031,14 @@ fgdbm_has_key(obj, keystr)
return Qfalse;
}
+/*
+ * call-seq:
+ * gdbm.has_value?(v) -> true or false
+ * gdbm.value?(v) -> true or false
+ *
+ * Returns true if the given value _v_ exists within the database.
+ * Returns false otherwise.
+ */
static VALUE
fgdbm_has_value(obj, valstr)
VALUE obj, valstr;
@@ -813,6 +1064,12 @@ fgdbm_has_value(obj, valstr)
return Qfalse;
}
+/*
+ * call-seq:
+ * gdbm.to_a -> array
+ *
+ * Returns an array of all key-value pairs contained in the database.
+ */
static VALUE
fgdbm_to_a(obj)
VALUE obj;
@@ -832,6 +1089,14 @@ fgdbm_to_a(obj)
return ary;
}
+/*
+ * call-seq:
+ * gdbm.reorganize -> gdbm
+ *
+ * Reorganizes the database file. This operation removes reserved space of
+ * elements that have already been deleted. It is only useful after a lot of
+ * deletions in the database.
+ */
static VALUE
fgdbm_reorganize(obj)
VALUE obj;
@@ -845,6 +1110,16 @@ fgdbm_reorganize(obj)
return obj;
}
+/*
+ * call-seq:
+ * gdbm.sync -> gdbm
+ *
+ * Unless the _gdbm_ object has been opened with the *SYNC* flag, it is not
+ * guarenteed that database modification operations are immediately applied to
+ * the database file. This method ensures that all recent modifications
+ * to the database are written to the file. Blocks until all writing operations
+ * to the disk have been finished.
+ */
static VALUE
fgdbm_sync(obj)
VALUE obj;
@@ -858,6 +1133,12 @@ fgdbm_sync(obj)
return obj;
}
+/*
+ * call-seq:
+ * gdbm.cachesize = size -> size
+ *
+ * Sets the size of the internal bucket cache to _size_.
+ */
static VALUE
fgdbm_set_cachesize(obj, val)
VALUE obj, val;
@@ -869,11 +1150,21 @@ fgdbm_set_cachesize(obj, val)
GetDBM2(obj, dbmp, dbm);
optval = FIX2INT(val);
if (gdbm_setopt(dbm, GDBM_CACHESIZE, &optval, sizeof(optval)) == -1) {
- rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
+ rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
}
return val;
}
+/*
+ * call-seq:
+ * gdbm.fastmode = boolean -> boolean
+ *
+ * Turns the database's fast mode on or off. If fast mode is turned on, gdbm
+ * does not wait for writes to be flushed to the disk before continuing.
+ *
+ * This option is obsolete for gdbm >= 1.8 since fast mode is turned on by
+ * default. See also: #syncmode=
+ */
static VALUE
fgdbm_set_fastmode(obj, val)
VALUE obj, val;
@@ -888,11 +1179,24 @@ fgdbm_set_fastmode(obj, val)
optval = 1;
if (gdbm_setopt(dbm, GDBM_FASTMODE, &optval, sizeof(optval)) == -1) {
- rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
+ rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
}
return val;
}
+/*
+ * call-seq:
+ * gdbm.syncmode = boolean -> boolean
+ *
+ * Turns the database's synchronization mode on or off. If the synchronization
+ * mode is turned on, the database's in-memory state will be synchronized to
+ * disk after every database modification operation. If the synchronization
+ * mode is turned off, GDBM does not wait for writes to be flushed to the disk
+ * before continuing.
+ *
+ * This option is only available for gdbm >= 1.8 where syncmode is turned off
+ * by default. See also: #fastmode=
+ */
static VALUE
fgdbm_set_syncmode(obj, val)
VALUE obj, val;
@@ -911,12 +1215,18 @@ fgdbm_set_syncmode(obj, val)
optval = 1;
if (gdbm_setopt(dbm, GDBM_FASTMODE, &optval, sizeof(optval)) == -1) {
- rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
+ rb_raise(rb_eGDBMError, "%s", gdbm_strerror(gdbm_errno));
}
return val;
#endif
}
+/*
+ * call-seq:
+ * gdbm.to_hash -> hash
+ *
+ * Returns a hash of all key-value pairs contained in the database.
+ */
static VALUE
fgdbm_to_hash(obj)
VALUE obj;
@@ -936,6 +1246,13 @@ fgdbm_to_hash(obj)
return hash;
}
+/*
+ * call-seq:
+ * gdbm.reject { |key, value| block } -> hash
+ *
+ * Returns a hash copy of _gdbm_ where all key-value pairs from _gdbm_ for
+ * which _block_ evaluates to true are removed. See also: #delete_if
+ */
static VALUE
fgdbm_reject(obj)
VALUE obj;
@@ -981,15 +1298,15 @@ Init_gdbm()
rb_define_method(rb_cGDBM, "reject!", fgdbm_delete_if, 0);
rb_define_method(rb_cGDBM, "reject", fgdbm_reject, 0);
rb_define_method(rb_cGDBM, "clear", fgdbm_clear, 0);
- rb_define_method(rb_cGDBM,"invert", fgdbm_invert, 0);
- rb_define_method(rb_cGDBM,"update", fgdbm_update, 1);
- rb_define_method(rb_cGDBM,"replace", fgdbm_replace, 1);
- rb_define_method(rb_cGDBM,"reorganize", fgdbm_reorganize, 0);
- rb_define_method(rb_cGDBM,"sync", fgdbm_sync, 0);
- /* rb_define_method(rb_cGDBM,"setopt", fgdbm_setopt, 2); */
- rb_define_method(rb_cGDBM,"cachesize=", fgdbm_set_cachesize, 1);
- rb_define_method(rb_cGDBM,"fastmode=", fgdbm_set_fastmode, 1);
- rb_define_method(rb_cGDBM,"syncmode=", fgdbm_set_syncmode, 1);
+ rb_define_method(rb_cGDBM, "invert", fgdbm_invert, 0);
+ rb_define_method(rb_cGDBM, "update", fgdbm_update, 1);
+ rb_define_method(rb_cGDBM, "replace", fgdbm_replace, 1);
+ rb_define_method(rb_cGDBM, "reorganize", fgdbm_reorganize, 0);
+ rb_define_method(rb_cGDBM, "sync", fgdbm_sync, 0);
+ /* rb_define_method(rb_cGDBM, "setopt", fgdbm_setopt, 2); */
+ rb_define_method(rb_cGDBM, "cachesize=", fgdbm_set_cachesize, 1);
+ rb_define_method(rb_cGDBM, "fastmode=", fgdbm_set_fastmode, 1);
+ rb_define_method(rb_cGDBM, "syncmode=", fgdbm_set_syncmode, 1);
rb_define_method(rb_cGDBM, "include?", fgdbm_has_key, 1);
rb_define_method(rb_cGDBM, "has_key?", fgdbm_has_key, 1);
@@ -1001,22 +1318,29 @@ Init_gdbm()
rb_define_method(rb_cGDBM, "to_a", fgdbm_to_a, 0);
rb_define_method(rb_cGDBM, "to_hash", fgdbm_to_hash, 0);
- /* flags for gdbm_open() */
+ /* flag for #new and #open: open database as a reader */
rb_define_const(rb_cGDBM, "READER", INT2FIX(GDBM_READER|RUBY_GDBM_RW_BIT));
+ /* flag for #new and #open: open database as a writer */
rb_define_const(rb_cGDBM, "WRITER", INT2FIX(GDBM_WRITER|RUBY_GDBM_RW_BIT));
+ /* flag for #new and #open: open database as a writer; if the database does not exist, create a new one */
rb_define_const(rb_cGDBM, "WRCREAT", INT2FIX(GDBM_WRCREAT|RUBY_GDBM_RW_BIT));
+ /* flag for #new and #open: open database as a writer; overwrite any existing databases */
rb_define_const(rb_cGDBM, "NEWDB", INT2FIX(GDBM_NEWDB|RUBY_GDBM_RW_BIT));
+ /* flag for #new and #open. this flag is obsolete for gdbm >= 1.8 */
rb_define_const(rb_cGDBM, "FAST", INT2FIX(GDBM_FAST));
/* this flag is obsolete in gdbm 1.8.
On gdbm 1.8, fast mode is default behavior. */
/* gdbm version 1.8 specific */
#if defined(GDBM_SYNC)
+ /* flag for #new and #open. only for gdbm >= 1.8 */
rb_define_const(rb_cGDBM, "SYNC", INT2FIX(GDBM_SYNC));
#endif
#if defined(GDBM_NOLOCK)
+ /* flag for #new and #open */
rb_define_const(rb_cGDBM, "NOLOCK", INT2FIX(GDBM_NOLOCK));
#endif
+ /* version of the gdbm library*/
rb_define_const(rb_cGDBM, "VERSION", rb_str_new2(gdbm_version));
}
diff --git a/ext/iconv/iconv.c b/ext/iconv/iconv.c
index 918dd51630..677c10e3ad 100644
--- a/ext/iconv/iconv.c
+++ b/ext/iconv/iconv.c
@@ -3,8 +3,8 @@
iconv.c -
- $Author: matz $
- $Date: 2005/12/12 00:36:51 $
+ $Author$
+ $Date$
created at: Wed Dec 1 20:28:09 JST 1999
All the files in this distribution are covered under the Ruby's
@@ -43,7 +43,11 @@
*
* == Examples
*
- * 1. Instantiate a new Iconv and use method Iconv#iconv.
+ * 1. Simple conversion between two charsets.
+ *
+ * converted_text = Iconv.conv('iso-8859-15', 'utf-8', text)
+ *
+ * 2. Instantiate a new Iconv and use method Iconv#iconv.
*
* cd = Iconv.new(to, from)
* begin
@@ -53,20 +57,16 @@
* cd.close
* end
*
- * 2. Invoke Iconv.open with a block.
+ * 3. Invoke Iconv.open with a block.
*
* Iconv.open(to, from) do |cd|
* input.each { |s| output << cd.iconv(s) }
* output << cd.iconv(nil)
* end
*
- * 3. Shorthand for (2).
+ * 4. Shorthand for (3).
*
* Iconv.iconv(to, from, *input.to_a)
- *
- * 4. Simple conversion between two charsets.
- *
- * converted_text = Iconv.new('iso-8859-15', 'utf-8').iconv(text)
*/
/* Invalid value for iconv_t is -1 but 0 for VALUE, I hope VALUE is
@@ -92,6 +92,7 @@ static VALUE rb_eIconvBrokenLibrary;
static ID rb_success, rb_failed;
static VALUE iconv_fail _((VALUE error, VALUE success, VALUE failed, struct iconv_env_t* env, const char *mesg));
+static VALUE iconv_fail_retry _((VALUE error, VALUE success, VALUE failed, struct iconv_env_t* env, const char *mesg));
static VALUE iconv_failure_initialize _((VALUE error, VALUE mesg, VALUE success, VALUE failed));
static VALUE iconv_failure_success _((VALUE self));
static VALUE iconv_failure_failed _((VALUE self));
@@ -101,7 +102,7 @@ static void iconv_dfree _((void *cd));
static VALUE iconv_free _((VALUE cd));
static VALUE iconv_try _((iconv_t cd, const char **inptr, size_t *inlen, char **outptr, size_t *outlen));
static VALUE rb_str_derive _((VALUE str, const char* ptr, int len));
-static VALUE iconv_convert _((iconv_t cd, VALUE str, int start, int length, struct iconv_env_t* env));
+static VALUE iconv_convert _((iconv_t cd, VALUE str, long start, long length, struct iconv_env_t* env));
static VALUE iconv_s_allocate _((VALUE klass));
static VALUE iconv_initialize _((VALUE self, VALUE to, VALUE from));
static VALUE iconv_s_open _((VALUE self, VALUE to, VALUE from));
@@ -145,6 +146,18 @@ map_charset
return StringValuePtr(*code);
}
+NORETURN(static void rb_iconv_sys_fail(const char *s));
+static void
+rb_iconv_sys_fail(const char *s)
+{
+ if (errno == 0) {
+ rb_exc_raise(iconv_fail(rb_eIconvBrokenLibrary, Qnil, Qnil, NULL, s));
+ }
+ rb_sys_fail(s);
+}
+
+#define rb_sys_fail(s) rb_iconv_sys_fail(s)
+
static iconv_t
iconv_create
#ifdef HAVE_PROTOTYPES
@@ -170,7 +183,7 @@ iconv_create
}
if (cd == (iconv_t)-1) {
int inval = errno == EINVAL;
- char *s = inval ? "invalid encoding " : "iconv";
+ const char *s = inval ? "invalid encoding " : "iconv";
volatile VALUE msg = rb_str_new(0, strlen(s) + RSTRING(to)->len +
RSTRING(from)->len + 8);
@@ -179,8 +192,8 @@ iconv_create
s = RSTRING(msg)->ptr;
RSTRING(msg)->len = strlen(s);
if (!inval) rb_sys_fail(s);
- iconv_fail(rb_eIconvInvalidEncoding,
- Qnil, rb_ary_new3(2, to, from), NULL, s);
+ rb_exc_raise(iconv_fail(rb_eIconvInvalidEncoding, Qnil,
+ rb_ary_new3(2, to, from), NULL, s));
}
}
@@ -328,7 +341,13 @@ iconv_fail
args[2] = rb_ary_new4(env->argc, env->argv);
}
}
- error = rb_class_new_instance(3, args, error);
+ return rb_class_new_instance(3, args, error);
+}
+
+static VALUE
+iconv_fail_retry(VALUE error, VALUE success, VALUE failed, struct iconv_env_t* env, const char *mesg)
+{
+ error = iconv_fail(error, success, failed, env, mesg);
if (!rb_block_given_p()) rb_exc_raise(error);
ruby_errinfo = error;
return rb_yield(failed);
@@ -362,13 +381,13 @@ rb_str_derive
static VALUE
iconv_convert
#ifdef HAVE_PROTOTYPES
- (iconv_t cd, VALUE str, int start, int length, struct iconv_env_t* env)
+ (iconv_t cd, VALUE str, long start, long length, struct iconv_env_t* env)
#else /* HAVE_PROTOTYPES */
(cd, str, start, length, env)
iconv_t cd;
VALUE str;
- int start;
- int length;
+ long start;
+ long length;
struct iconv_env_t *env;
#endif /* HAVE_PROTOTYPES */
{
@@ -394,7 +413,7 @@ iconv_convert
error = iconv_try(cd, &inptr, &inlen, &outptr, &outlen);
if (RTEST(error)) {
unsigned int i;
- rescue = iconv_fail(error, Qnil, Qnil, env, 0);
+ rescue = iconv_fail_retry(error, Qnil, Qnil, env, 0);
if (TYPE(rescue) == T_ARRAY) {
str = RARRAY(rescue)->len > 0 ? RARRAY(rescue)->ptr[0] : Qnil;
}
@@ -417,14 +436,9 @@ iconv_convert
slen = RSTRING(str)->len;
inptr = RSTRING(str)->ptr;
- if (start < 0 ? (start += slen) < 0 : start >= slen)
- length = 0;
- else if (length < 0 && (length += slen + 1) < 0)
- length = 0;
- else if ((length -= start) < 0)
- length = 0;
- else
- inptr += start;
+ inptr += start;
+ if (length < 0 || length > start + slen)
+ length = slen - start;
}
instart = inptr;
inlen = length;
@@ -478,7 +492,7 @@ iconv_convert
else if (inptr > instart)
rb_str_cat(ret, instart, inptr - instart);
str = rb_str_derive(str, inptr, inlen);
- rescue = iconv_fail(error, ret, str, env, errmsg);
+ rescue = iconv_fail_retry(error, ret, str, env, errmsg);
if (TYPE(rescue) == T_ARRAY) {
if ((len = RARRAY(rescue)->len) > 0)
rb_str_concat(ret, RARRAY(rescue)->ptr[0]);
@@ -606,7 +620,7 @@ iconv_s_convert
}
/*
- * Document-method: iconv
+ * Document-method: Iconv::iconv
* call-seq: Iconv.iconv(to, from, *strs)
*
* Shorthand for
@@ -649,7 +663,7 @@ iconv_s_iconv
/*
* Document-method: Iconv::conv
- * call-seq: Iconv.iconv(to, from, *strs)
+ * call-seq: Iconv.conv(to, from, str)
*
* Shorthand for
* Iconv.iconv(to, from, str).join
@@ -715,7 +729,7 @@ iconv_finish
}
/*
- * Document-method: iconv
+ * Document-method: Iconv#iconv
* call-seq: iconv(str, start=0, length=-1)
*
* Converts string and returns the result.
@@ -754,14 +768,22 @@ iconv_iconv
{
VALUE str, n1, n2;
VALUE cd = check_iconv(self);
+ long start = 0, length = 0, slen = 0;
- n1 = n2 = Qnil;
rb_scan_args(argc, argv, "12", &str, &n1, &n2);
+ if (!NIL_P(str)) slen = RSTRING_LEN(StringValue(str));
+ if (argc != 2 || !RTEST(rb_range_beg_len(n1, &start, &length, slen, 0))) {
+ if (NIL_P(n1) || ((start = NUM2LONG(n1)) < 0 ? (start += slen) >= 0 : start < slen)) {
+ if (NIL_P(n2)) {
+ length = -1;
+ }
+ else if ((length = NUM2LONG(n2)) >= slen - start) {
+ length = slen - start;
+ }
+ }
+ }
- return iconv_convert(VALUE2ICONV(cd), str,
- NIL_P(n1) ? 0 : NUM2INT(n1),
- NIL_P(n2) ? -1 : NUM2INT(n2),
- NULL);
+ return iconv_convert(VALUE2ICONV(cd), str, start, length, NULL);
}
/*
@@ -825,7 +847,7 @@ iconv_failure_inspect
VALUE self;
#endif /* HAVE_PROTOTYPES */
{
- char *cname = rb_class2name(CLASS_OF(self));
+ const char *cname = rb_class2name(CLASS_OF(self));
VALUE success = rb_attr_get(self, rb_success);
VALUE failed = rb_attr_get(self, rb_failed);
VALUE str = rb_str_buf_cat2(rb_str_new2("#<"), cname);
diff --git a/ext/io/wait/extconf.rb b/ext/io/wait/extconf.rb
index 1352ef202e..e8181d25f5 100644
--- a/ext/io/wait/extconf.rb
+++ b/ext/io/wait/extconf.rb
@@ -3,7 +3,7 @@ target = "io/wait"
unless macro_defined?("DOSISH", "#include <ruby.h>")
fionread = %w[sys/ioctl.h sys/filio.h].find do |h|
- checking_for("FIONREAD") {have_macro("FIONREAD", h)}
+ have_macro("FIONREAD", h)
end
if fionread
$defs << "-DFIONREAD_HEADER=\"<#{fionread}>\""
diff --git a/ext/io/wait/wait.c b/ext/io/wait/wait.c
index 0e48f705d2..02cb54a014 100644
--- a/ext/io/wait/wait.c
+++ b/ext/io/wait/wait.c
@@ -2,8 +2,8 @@
io/wait.c -
- $Author: nobu $
- $Date: 2005/07/18 03:24:04 $
+ $Author$
+ $Date$
created at: Tue Aug 28 09:08:06 JST 2001
All the files in this distribution are covered under the Ruby's
@@ -56,7 +56,7 @@ static VALUE
io_ready_p(io)
VALUE io;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
FILE *fp;
ioctl_arg n;
@@ -84,7 +84,7 @@ io_wait(argc, argv, io)
VALUE *argv;
VALUE io;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
fd_set rd;
FILE *fp;
int fd;
diff --git a/ext/nkf/lib/kconv.rb b/ext/nkf/lib/kconv.rb
index 711a3c10a1..4ffe8d984e 100644
--- a/ext/nkf/lib/kconv.rb
+++ b/ext/nkf/lib/kconv.rb
@@ -1,7 +1,7 @@
#
# kconv.rb - Kanji Converter.
#
-# $Id: kconv.rb,v 1.3.6.6 2006/06/19 14:52:54 naruse Exp $
+# $Id$
#
# ----
#
@@ -49,7 +49,7 @@ module Kconv
#
# Revision of kconv.rb
- REVISION = %q$Revision: 1.3.6.6 $
+ REVISION = %q$Revision$
#Regexp of Encoding
@@ -63,8 +63,8 @@ module Kconv
RegexpEucjp = /\A(?:
[\x00-\x7f] |
\x8e [\xa1-\xdf] |
- \x8f [\xa1-\xdf] [\xa1-\xfe] |
- [\xa1-\xdf] [\xa1-\xfe]
+ \x8f [\xa1-\xfe] [\xa1-\xfe] |
+ [\xa1-\xfe] [\xa1-\xfe]
)*\z/nx
# Regexp of UTF-8 string (private constant)
@@ -156,7 +156,7 @@ module Kconv
# convert halfwidth katakana to fullwidth katakana.
# If you don't want it, use NKF.nkf('-exm0', str).
def toeuc(str)
- ::NKF::nkf('-em0', str)
+ ::NKF::nkf('-em', str)
end
module_function :toeuc
diff --git a/ext/nkf/nkf-utf8/nkf.c b/ext/nkf/nkf-utf8/nkf.c
index 0d82562326..168cbdbf8b 100644
--- a/ext/nkf/nkf-utf8/nkf.c
+++ b/ext/nkf/nkf-utf8/nkf.c
@@ -39,15 +39,15 @@
** E-Mail: furukawa@tcp-ip.or.jp
** $B$^$G8fO"Mm$r$*4j$$$7$^$9!#(B
***********************************************************************/
-/* $Id: nkf.c,v 1.2.2.11 2006/06/19 14:52:55 naruse Exp $ */
-#define NKF_VERSION "2.0.7"
-#define NKF_RELEASE_DATE "2006-06-13"
+/* $Id$ */
+#define NKF_VERSION "2.0.8"
+#define NKF_RELEASE_DATE "2008-11-08"
#include "config.h"
#include "utf8tbl.h"
#define COPY_RIGHT \
"Copyright (C) 1987, FUJITSU LTD. (I.Ichikawa),2000 S. Kono, COW\n" \
- "Copyright (C) 2002-2006 Kono, Furukawa, Naruse, mastodon"
+ "Copyright (C) 2002-2008 Kono, Furukawa, Naruse, mastodon"
/*
@@ -62,7 +62,7 @@
**
** t no operation
**
-** j Outout code is JIS 7 bit (DEFAULT SELECT)
+** j Output code is JIS 7 bit (DEFAULT SELECT)
** s Output code is MS Kanji (DEFAULT SELECT)
** e Output code is AT&T JIS (DEFAULT SELECT)
** w Output code is AT&T JIS (DEFAULT SELECT)
@@ -219,6 +219,7 @@ void djgpp_setbinmode(FILE *fp)
/* Input Assumption */
#define JIS_INPUT 4
+#define EUC_INPUT 16
#define SJIS_INPUT 5
#define LATIN1_INPUT 6
#define FIXED_MIME 7
@@ -232,8 +233,15 @@ void djgpp_setbinmode(FILE *fp)
#define UTF8 12
#define UTF8_INPUT 13
-#define UTF16BE_INPUT 14
-#define UTF16LE_INPUT 15
+#define UTF16_INPUT 1015
+#define UTF32_INPUT 1017
+
+/* byte order */
+
+#define ENDIAN_BIG 1234
+#define ENDIAN_LITTLE 4321
+#define ENDIAN_2143 2143
+#define ENDIAN_3412 3412
#define WISH_TRUE 15
@@ -353,8 +361,8 @@ static int ms_ucs_map_f = UCS_MAP_ASCII;
/* no NEC special, NEC-selected IBM extended and IBM extended characters */
static int no_cp932ext_f = FALSE;
/* ignore ZERO WIDTH NO-BREAK SPACE */
-static int ignore_zwnbsp_f = TRUE;
static int no_best_fit_chars_f = FALSE;
+static int input_endian = ENDIAN_BIG;
static nkf_char unicode_subchar = '?'; /* the regular substitution character */
static void nkf_each_char_to_hex(void (*f)(nkf_char c2,nkf_char c1), nkf_char c);
static void encode_fallback_html(nkf_char c);
@@ -366,18 +374,21 @@ static void (*encode_fallback)(nkf_char c) = NULL;
static nkf_char w2e_conv(nkf_char c2,nkf_char c1,nkf_char c0,nkf_char *p2,nkf_char *p1);
static nkf_char w_iconv(nkf_char c2,nkf_char c1,nkf_char c0);
static nkf_char w_iconv16(nkf_char c2,nkf_char c1,nkf_char c0);
+static nkf_char w_iconv32(nkf_char c2,nkf_char c1,nkf_char c0);
static nkf_char unicode_to_jis_common(nkf_char c2,nkf_char c1,nkf_char c0,nkf_char *p2,nkf_char *p1);
static nkf_char w_iconv_common(nkf_char c1,nkf_char c0,const unsigned short *const *pp,nkf_char psize,nkf_char *p2,nkf_char *p1);
static void w16w_conv(nkf_char val, nkf_char *p2, nkf_char *p1, nkf_char *p0);
static nkf_char ww16_conv(nkf_char c2, nkf_char c1, nkf_char c0);
static nkf_char w16e_conv(nkf_char val,nkf_char *p2,nkf_char *p1);
+static void w_status(struct input_code *, nkf_char);
#endif
#ifdef UTF8_OUTPUT_ENABLE
-static int unicode_bom_f= 0; /* Output Unicode BOM */
-static int w_oconv16_LE = 0; /* utf-16 little endian */
+static int output_bom_f = FALSE;
+static int output_endian = ENDIAN_BIG;
static nkf_char e2w_conv(nkf_char c2,nkf_char c1);
static void w_oconv(nkf_char c2,nkf_char c1);
static void w_oconv16(nkf_char c2,nkf_char c1);
+static void w_oconv32(nkf_char c2,nkf_char c1);
#endif
static void e_oconv(nkf_char c2,nkf_char c1);
static nkf_char e2s_conv(nkf_char c2, nkf_char c1, nkf_char *p2, nkf_char *p1);
@@ -437,7 +448,7 @@ static unsigned char stdibuf[IOBUF_SIZE];
static unsigned char stdobuf[IOBUF_SIZE];
#endif
static unsigned char hold_buf[HOLD_SIZE*2];
-static int hold_count;
+static int hold_count = 0;
/* MIME preprocessor fifo */
@@ -501,10 +512,10 @@ static nkf_char url_ungetc(nkf_char c,FILE *f);
#endif
#define PREFIX_EUCG3 NKF_INT32_C(0x8F00)
#define CLASS_MASK NKF_INT32_C(0xFF000000)
-#define CLASS_UTF16 NKF_INT32_C(0x01000000)
+#define CLASS_UNICODE NKF_INT32_C(0x01000000)
#define VALUE_MASK NKF_INT32_C(0x00FFFFFF)
#define UNICODE_MAX NKF_INT32_C(0x0010FFFF)
-#define is_unicode_capsule(c) ((c & CLASS_MASK) == CLASS_UTF16)
+#define is_unicode_capsule(c) ((c & CLASS_MASK) == CLASS_UNICODE)
#define is_unicode_bmp(c) ((c & VALUE_MASK) <= NKF_INT32_C(0xFFFF))
#ifdef NUMCHAR_OPTION
@@ -537,7 +548,7 @@ static int exec_f = 0;
#ifdef SHIFTJIS_CP932
/* invert IBM extended characters to others */
-static int cp51932_f = TRUE;
+static int cp51932_f = FALSE;
/* invert NEC-selected IBM extended characters to IBM extended characters */
static int cp932inv_f = TRUE;
@@ -565,18 +576,13 @@ static void status_check(struct input_code *ptr, nkf_char c);
static void e_status(struct input_code *, nkf_char);
static void s_status(struct input_code *, nkf_char);
-#ifdef UTF8_INPUT_ENABLE
-static void w_status(struct input_code *, nkf_char);
-static void w16_status(struct input_code *, nkf_char);
-static int utf16_mode = UTF16BE_INPUT;
-#endif
-
struct input_code input_code_list[] = {
{"EUC-JP", 0, 0, 0, {0, 0, 0}, e_status, e_iconv, 0},
{"Shift_JIS", 0, 0, 0, {0, 0, 0}, s_status, s_iconv, 0},
#ifdef UTF8_INPUT_ENABLE
{"UTF-8", 0, 0, 0, {0, 0, 0}, w_status, w_iconv, 0},
- {"UTF-16", 0, 0, 0, {0, 0, 0}, w16_status, w_iconv16, 0},
+ {"UTF-16", 0, 0, 0, {0, 0, 0}, NULL, w_iconv16, 0},
+ {"UTF-32", 0, 0, 0, {0, 0, 0}, NULL, w_iconv32, 0},
#endif
{0}
};
@@ -848,6 +854,7 @@ int main(int argc, char **argv)
}
} else {
int nfiles = argc;
+ int is_argument_error = FALSE;
while (argc--) {
is_inputcode_mixed = FALSE;
is_inputcode_set = FALSE;
@@ -857,7 +864,9 @@ int main(int argc, char **argv)
#endif
if ((fin = fopen((origfname = *argv++), "r")) == NULL) {
perror(*--argv);
- return(-1);
+ *argv++;
+ is_argument_error = TRUE;
+ continue;
} else {
#ifdef OVERWRITE
int fd = 0;
@@ -1005,6 +1014,8 @@ int main(int argc, char **argv)
#endif
}
}
+ if (is_argument_error)
+ return(-1);
}
#ifdef EASYWIN /*Easy Win */
if (file_out_f == FALSE)
@@ -1185,13 +1196,19 @@ void options(unsigned char *cp)
codeset[i] = nkf_toupper(p[i]);
}
codeset[i] = 0;
- if(strcmp(codeset, "ISO-2022-JP") == 0 ||
- strcmp(codeset, "X-ISO2022JP-CP932") == 0 ||
+ if(strcmp(codeset, "ISO-2022-JP") == 0){
+ input_f = JIS_INPUT;
+ }else if(strcmp(codeset, "X-ISO2022JP-CP932") == 0 ||
strcmp(codeset, "CP50220") == 0 ||
strcmp(codeset, "CP50221") == 0 ||
- strcmp(codeset, "CP50222") == 0 ||
- strcmp(codeset, "ISO-2022-JP-MS") == 0){
+ strcmp(codeset, "CP50222") == 0){
input_f = JIS_INPUT;
+#ifdef SHIFTJIS_CP932
+ cp51932_f = TRUE;
+#endif
+#ifdef UTF8_OUTPUT_ENABLE
+ ms_ucs_map_f = UCS_MAP_CP932;
+#endif
}else if(strcmp(codeset, "ISO-2022-JP-1") == 0){
input_f = JIS_INPUT;
#ifdef X0212_ENABLE
@@ -1205,13 +1222,11 @@ void options(unsigned char *cp)
x0213_f = TRUE;
}else if(strcmp(codeset, "SHIFT_JIS") == 0){
input_f = SJIS_INPUT;
- if (x0201_f==NO_X0201) x0201_f=TRUE;
}else if(strcmp(codeset, "WINDOWS-31J") == 0 ||
strcmp(codeset, "CSWINDOWS31J") == 0 ||
strcmp(codeset, "CP932") == 0 ||
strcmp(codeset, "MS932") == 0){
input_f = SJIS_INPUT;
- x0201_f = FALSE;
#ifdef SHIFTJIS_CP932
cp51932_f = TRUE;
#endif
@@ -1220,10 +1235,9 @@ void options(unsigned char *cp)
#endif
}else if(strcmp(codeset, "EUCJP") == 0 ||
strcmp(codeset, "EUC-JP") == 0){
- input_f = JIS_INPUT;
+ input_f = EUC_INPUT;
}else if(strcmp(codeset, "CP51932") == 0){
- input_f = JIS_INPUT;
- x0201_f = FALSE;
+ input_f = EUC_INPUT;
#ifdef SHIFTJIS_CP932
cp51932_f = TRUE;
#endif
@@ -1233,8 +1247,7 @@ void options(unsigned char *cp)
}else if(strcmp(codeset, "EUC-JP-MS") == 0 ||
strcmp(codeset, "EUCJP-MS") == 0 ||
strcmp(codeset, "EUCJPMS") == 0){
- input_f = JIS_INPUT;
- x0201_f = FALSE;
+ input_f = EUC_INPUT;
#ifdef SHIFTJIS_CP932
cp51932_f = FALSE;
#endif
@@ -1243,8 +1256,7 @@ void options(unsigned char *cp)
#endif
}else if(strcmp(codeset, "EUC-JP-ASCII") == 0 ||
strcmp(codeset, "EUCJP-ASCII") == 0){
- input_f = JIS_INPUT;
- x0201_f = FALSE;
+ input_f = EUC_INPUT;
#ifdef SHIFTJIS_CP932
cp51932_f = FALSE;
#endif
@@ -1257,17 +1269,13 @@ void options(unsigned char *cp)
x0213_f = TRUE;
#ifdef SHIFTJIS_CP932
cp51932_f = FALSE;
- cp932inv_f = FALSE;
#endif
- if (x0201_f==NO_X0201) x0201_f=TRUE;
}else if(strcmp(codeset, "EUC-JISX0213") == 0 ||
strcmp(codeset, "EUC-JIS-2004") == 0){
- input_f = JIS_INPUT;
- x0201_f = FALSE;
+ input_f = EUC_INPUT;
x0213_f = TRUE;
#ifdef SHIFTJIS_CP932
cp51932_f = FALSE;
- cp932inv_f = FALSE;
#endif
#ifdef UTF8_INPUT_ENABLE
}else if(strcmp(codeset, "UTF-8") == 0 ||
@@ -1280,61 +1288,78 @@ void options(unsigned char *cp)
input_f = UTF8_INPUT;
nfc_f = TRUE;
#endif
- }else if(strcmp(codeset, "UTF-16") == 0){
- input_f = UTF16BE_INPUT;
- utf16_mode = UTF16BE_INPUT;
- }else if(strcmp(codeset, "UTF-16BE") == 0 ||
+ }else if(strcmp(codeset, "UTF-16") == 0 ||
+ strcmp(codeset, "UTF-16BE") == 0 ||
strcmp(codeset, "UTF-16BE-BOM") == 0){
- input_f = UTF16BE_INPUT;
- utf16_mode = UTF16BE_INPUT;
+ input_f = UTF16_INPUT;
+ input_endian = ENDIAN_BIG;
}else if(strcmp(codeset, "UTF-16LE") == 0 ||
strcmp(codeset, "UTF-16LE-BOM") == 0){
- input_f = UTF16LE_INPUT;
- utf16_mode = UTF16LE_INPUT;
+ input_f = UTF16_INPUT;
+ input_endian = ENDIAN_LITTLE;
+ }else if(strcmp(codeset, "UTF-32") == 0 ||
+ strcmp(codeset, "UTF-32BE") == 0 ||
+ strcmp(codeset, "UTF-32BE-BOM") == 0){
+ input_f = UTF32_INPUT;
+ input_endian = ENDIAN_BIG;
+ }else if(strcmp(codeset, "UTF-32LE") == 0 ||
+ strcmp(codeset, "UTF-32LE-BOM") == 0){
+ input_f = UTF32_INPUT;
+ input_endian = ENDIAN_LITTLE;
#endif
}
continue;
}
if (strcmp(long_option[i].name, "oc=") == 0){
+ x0201_f = FALSE;
for (i=0; i < 16 && SPACE < p[i] && p[i] < DEL; i++){
codeset[i] = nkf_toupper(p[i]);
}
codeset[i] = 0;
- if(strcmp(codeset, "ISO-2022-JP") == 0 ||
- strcmp(codeset, "CP50220") == 0){
+ if(strcmp(codeset, "ISO-2022-JP") == 0){
output_conv = j_oconv;
}else if(strcmp(codeset, "X-ISO2022JP-CP932") == 0){
output_conv = j_oconv;
no_cp932ext_f = TRUE;
- }else if(strcmp(codeset, "CP50221") == 0 ||
- strcmp(codeset, "ISO-2022-JP-MS") == 0){
- output_conv = j_oconv;
- x0201_f = FALSE;
- }else if(strcmp(codeset, "ISO-2022-JP-1") == 0){
+#ifdef SHIFTJIS_CP932
+ cp932inv_f = FALSE;
+#endif
+#ifdef UTF8_OUTPUT_ENABLE
+ ms_ucs_map_f = UCS_MAP_CP932;
+#endif
+ }else if(strcmp(codeset, "CP50220") == 0){
output_conv = j_oconv;
-#ifdef X0212_ENABLE
- x0212_f = TRUE;
+ x0201_f = TRUE;
+#ifdef SHIFTJIS_CP932
+ cp932inv_f = FALSE;
#endif
+#ifdef UTF8_OUTPUT_ENABLE
+ ms_ucs_map_f = UCS_MAP_CP932;
+#endif
+ }else if(strcmp(codeset, "CP50221") == 0){
+ output_conv = j_oconv;
#ifdef SHIFTJIS_CP932
- cp51932_f = FALSE;
+ cp932inv_f = FALSE;
#endif
- }else if(strcmp(codeset, "ISO-2022-JP-3") == 0){
+#ifdef UTF8_OUTPUT_ENABLE
+ ms_ucs_map_f = UCS_MAP_CP932;
+#endif
+ }else if(strcmp(codeset, "ISO-2022-JP-1") == 0){
output_conv = j_oconv;
#ifdef X0212_ENABLE
x0212_f = TRUE;
#endif
- x0213_f = TRUE;
#ifdef SHIFTJIS_CP932
- cp51932_f = FALSE;
+ cp932inv_f = FALSE;
#endif
- }else if(strcmp(codeset, "ISO-2022-JP-MS") == 0){
+ }else if(strcmp(codeset, "ISO-2022-JP-3") == 0){
output_conv = j_oconv;
- x0201_f = FALSE;
#ifdef X0212_ENABLE
x0212_f = TRUE;
#endif
+ x0213_f = TRUE;
#ifdef SHIFTJIS_CP932
- cp51932_f = FALSE;
+ cp932inv_f = FALSE;
#endif
}else if(strcmp(codeset, "SHIFT_JIS") == 0){
output_conv = s_oconv;
@@ -1343,11 +1368,6 @@ void options(unsigned char *cp)
strcmp(codeset, "CP932") == 0 ||
strcmp(codeset, "MS932") == 0){
output_conv = s_oconv;
- x0201_f = FALSE;
-#ifdef SHIFTJIS_CP932
- cp51932_f = TRUE;
- cp932inv_f = TRUE;
-#endif
#ifdef UTF8_OUTPUT_ENABLE
ms_ucs_map_f = UCS_MAP_CP932;
#endif
@@ -1356,9 +1376,8 @@ void options(unsigned char *cp)
output_conv = e_oconv;
}else if(strcmp(codeset, "CP51932") == 0){
output_conv = e_oconv;
- x0201_f = FALSE;
#ifdef SHIFTJIS_CP932
- cp51932_f = TRUE;
+ cp932inv_f = FALSE;
#endif
#ifdef UTF8_OUTPUT_ENABLE
ms_ucs_map_f = UCS_MAP_CP932;
@@ -1367,26 +1386,18 @@ void options(unsigned char *cp)
strcmp(codeset, "EUCJP-MS") == 0 ||
strcmp(codeset, "EUCJPMS") == 0){
output_conv = e_oconv;
- x0201_f = FALSE;
#ifdef X0212_ENABLE
x0212_f = TRUE;
#endif
-#ifdef SHIFTJIS_CP932
- cp51932_f = FALSE;
-#endif
#ifdef UTF8_OUTPUT_ENABLE
ms_ucs_map_f = UCS_MAP_MS;
#endif
}else if(strcmp(codeset, "EUC-JP-ASCII") == 0 ||
strcmp(codeset, "EUCJP-ASCII") == 0){
output_conv = e_oconv;
- x0201_f = FALSE;
#ifdef X0212_ENABLE
x0212_f = TRUE;
#endif
-#ifdef SHIFTJIS_CP932
- cp51932_f = FALSE;
-#endif
#ifdef UTF8_OUTPUT_ENABLE
ms_ucs_map_f = UCS_MAP_ASCII;
#endif
@@ -1405,32 +1416,42 @@ void options(unsigned char *cp)
#endif
x0213_f = TRUE;
#ifdef SHIFTJIS_CP932
- cp51932_f = FALSE;
+ cp932inv_f = FALSE;
#endif
#ifdef UTF8_OUTPUT_ENABLE
}else if(strcmp(codeset, "UTF-8") == 0){
output_conv = w_oconv;
}else if(strcmp(codeset, "UTF-8N") == 0){
output_conv = w_oconv;
- unicode_bom_f=1;
}else if(strcmp(codeset, "UTF-8-BOM") == 0){
output_conv = w_oconv;
- unicode_bom_f=2;
+ output_bom_f = TRUE;
}else if(strcmp(codeset, "UTF-16BE") == 0){
- output_conv = w_oconv16;
- unicode_bom_f=1;
+ output_conv = w_oconv16;
}else if(strcmp(codeset, "UTF-16") == 0 ||
strcmp(codeset, "UTF-16BE-BOM") == 0){
- output_conv = w_oconv16;
- unicode_bom_f=2;
+ output_conv = w_oconv16;
+ output_bom_f = TRUE;
}else if(strcmp(codeset, "UTF-16LE") == 0){
- output_conv = w_oconv16;
- w_oconv16_LE = 1;
- unicode_bom_f=1;
+ output_conv = w_oconv16;
+ output_endian = ENDIAN_LITTLE;
}else if(strcmp(codeset, "UTF-16LE-BOM") == 0){
- output_conv = w_oconv16;
- w_oconv16_LE = 1;
- unicode_bom_f=2;
+ output_conv = w_oconv16;
+ output_endian = ENDIAN_LITTLE;
+ output_bom_f = TRUE;
+ }else if(strcmp(codeset, "UTF-32") == 0 ||
+ strcmp(codeset, "UTF-32BE") == 0){
+ output_conv = w_oconv32;
+ }else if(strcmp(codeset, "UTF-32BE-BOM") == 0){
+ output_conv = w_oconv32;
+ output_bom_f = TRUE;
+ }else if(strcmp(codeset, "UTF-32LE") == 0){
+ output_conv = w_oconv32;
+ output_endian = ENDIAN_LITTLE;
+ }else if(strcmp(codeset, "UTF-32LE-BOM") == 0){
+ output_conv = w_oconv32;
+ output_endian = ENDIAN_LITTLE;
+ output_bom_f = TRUE;
#endif
}
continue;
@@ -1649,6 +1670,7 @@ void options(unsigned char *cp)
continue;
case 'e': /* AT&T EUC output */
output_conv = e_oconv;
+ cp932inv_f = FALSE;
continue;
case 's': /* SJIS output */
output_conv = s_oconv;
@@ -1695,57 +1717,72 @@ void options(unsigned char *cp)
#endif
#ifdef UTF8_OUTPUT_ENABLE
case 'w': /* UTF-8 output */
- if ('1'== cp[0] && '6'==cp[1]) {
- output_conv = w_oconv16; cp+=2;
+ if (cp[0] == '8') {
+ output_conv = w_oconv; cp++;
+ if (cp[0] == '0'){
+ cp++;
+ } else {
+ output_bom_f = TRUE;
+ }
+ } else {
+ if ('1'== cp[0] && '6'==cp[1]) {
+ output_conv = w_oconv16; cp+=2;
+ } else if ('3'== cp[0] && '2'==cp[1]) {
+ output_conv = w_oconv32; cp+=2;
+ } else {
+ output_conv = w_oconv;
+ continue;
+ }
if (cp[0]=='L') {
- unicode_bom_f=2; cp++;
- w_oconv16_LE = 1;
- if (cp[0] == '0'){
- unicode_bom_f=1; cp++;
- }
+ cp++;
+ output_endian = ENDIAN_LITTLE;
} else if (cp[0] == 'B') {
- unicode_bom_f=2; cp++;
- if (cp[0] == '0'){
- unicode_bom_f=1; cp++;
- }
- }
- } else if (cp[0] == '8') {
- output_conv = w_oconv; cp++;
- unicode_bom_f=2;
+ cp++;
+ } else {
+ continue;
+ }
if (cp[0] == '0'){
- unicode_bom_f=1; cp++;
+ cp++;
+ } else {
+ output_bom_f = TRUE;
}
- } else
- output_conv = w_oconv;
+ }
continue;
#endif
#ifdef UTF8_INPUT_ENABLE
- case 'W': /* UTF-8 input */
- if ('1'== cp[0] && '6'==cp[1]) {
- input_f = UTF16BE_INPUT;
- utf16_mode = UTF16BE_INPUT;
- cp += 2;
+ case 'W': /* UTF input */
+ if (cp[0] == '8') {
+ cp++;
+ input_f = UTF8_INPUT;
+ }else{
+ if ('1'== cp[0] && '6'==cp[1]) {
+ cp += 2;
+ input_f = UTF16_INPUT;
+ input_endian = ENDIAN_BIG;
+ } else if ('3'== cp[0] && '2'==cp[1]) {
+ cp += 2;
+ input_f = UTF32_INPUT;
+ input_endian = ENDIAN_BIG;
+ } else {
+ input_f = UTF8_INPUT;
+ continue;
+ }
if (cp[0]=='L') {
cp++;
- input_f = UTF16LE_INPUT;
- utf16_mode = UTF16LE_INPUT;
+ input_endian = ENDIAN_LITTLE;
} else if (cp[0] == 'B') {
cp++;
- input_f = UTF16BE_INPUT;
- utf16_mode = UTF16BE_INPUT;
}
- } else if (cp[0] == '8') {
- cp++;
- input_f = UTF8_INPUT;
- } else
- input_f = UTF8_INPUT;
+ }
continue;
#endif
/* Input code assumption */
case 'J': /* JIS input */
- case 'E': /* AT&T EUC input */
input_f = JIS_INPUT;
continue;
+ case 'E': /* AT&T EUC input */
+ input_f = EUC_INPUT;
+ continue;
case 'S': /* MS Kanji input */
input_f = SJIS_INPUT;
if (x0201_f==NO_X0201) x0201_f=TRUE;
@@ -1874,12 +1911,7 @@ void options(unsigned char *cp)
}
}
-#ifdef ANSI_C_PROTOTYPE
struct input_code * find_inputcode_byfunc(nkf_char (*iconv_func)(nkf_char c2,nkf_char c1,nkf_char c0))
-#else
-struct input_code * find_inputcode_byfunc(iconv_func)
- nkf_char (*iconv_func)();
-#endif
{
if (iconv_func){
struct input_code *p = input_code_list;
@@ -2135,52 +2167,6 @@ void e_status(struct input_code *ptr, nkf_char c)
}
#ifdef UTF8_INPUT_ENABLE
-void w16_status(struct input_code *ptr, nkf_char c)
-{
- switch (ptr->stat){
- case -1:
- break;
- case 0:
- if (ptr->_file_stat == 0){
- if (c == 0xfe || c == 0xff){
- ptr->stat = c;
- status_push_ch(ptr, c);
- ptr->_file_stat = 1;
- }else{
- status_disable(ptr);
- ptr->_file_stat = -1;
- }
- }else if (ptr->_file_stat > 0){
- ptr->stat = 1;
- status_push_ch(ptr, c);
- }else if (ptr->_file_stat < 0){
- status_disable(ptr);
- }
- break;
-
- case 1:
- if (c == EOF){
- status_disable(ptr);
- ptr->_file_stat = -1;
- }else{
- status_push_ch(ptr, c);
- status_clear(ptr);
- }
- break;
-
- case 0xfe:
- case 0xff:
- if (ptr->stat != c && (c == 0xfe || c == 0xff)){
- status_push_ch(ptr, c);
- status_clear(ptr);
- }else{
- status_disable(ptr);
- ptr->_file_stat = -1;
- }
- break;
- }
-}
-
void w_status(struct input_code *ptr, nkf_char c)
{
switch (ptr->stat){
@@ -2200,6 +2186,9 @@ void w_status(struct input_code *ptr, nkf_char c)
}else if (0xe0 <= c && c <= 0xef){
ptr->stat = 2;
status_push_ch(ptr, c);
+ }else if (0xf0 <= c && c <= 0xf4){
+ ptr->stat = 3;
+ status_push_ch(ptr, c);
}else{
status_disable(ptr);
}
@@ -2222,6 +2211,17 @@ void w_status(struct input_code *ptr, nkf_char c)
status_disable(ptr);
}
break;
+ case 3:
+ if (0x80 <= c && c <= 0xbf){
+ if (ptr->index < ptr->stat){
+ status_push_ch(ptr, c);
+ } else {
+ status_clear(ptr);
+ }
+ }else{
+ status_disable(ptr);
+ }
+ break;
}
}
#endif
@@ -2232,6 +2232,12 @@ void code_status(nkf_char c)
struct input_code *result = 0;
struct input_code *p = input_code_list;
while (p->name){
+ if (!p->status_func) {
+ ++p;
+ continue;
+ }
+ if (!p->status_func)
+ continue;
(p->status_func)(p, c);
if (p->stat > 0){
action_flag = 0;
@@ -2374,17 +2380,17 @@ void module_connection(void)
i_bgetc = i_getc; i_getc = broken_getc;
i_bungetc = i_ungetc; i_ungetc = broken_ungetc;
}
- if (input_f == JIS_INPUT || input_f == LATIN1_INPUT) {
+ if (input_f == JIS_INPUT || input_f == EUC_INPUT || input_f == LATIN1_INPUT) {
set_iconv(-TRUE, e_iconv);
} else if (input_f == SJIS_INPUT) {
set_iconv(-TRUE, s_iconv);
#ifdef UTF8_INPUT_ENABLE
} else if (input_f == UTF8_INPUT) {
set_iconv(-TRUE, w_iconv);
- } else if (input_f == UTF16BE_INPUT) {
- set_iconv(-TRUE, w_iconv16);
- } else if (input_f == UTF16LE_INPUT) {
+ } else if (input_f == UTF16_INPUT) {
set_iconv(-TRUE, w_iconv16);
+ } else if (input_f == UTF32_INPUT) {
+ set_iconv(-TRUE, w_iconv32);
#endif
} else {
set_iconv(FALSE, e_iconv);
@@ -2399,27 +2405,133 @@ void module_connection(void)
}
/*
+ * Check and Ignore BOM
+ */
+void check_bom(FILE *f)
+{
+ int c2;
+ switch(c2 = (*i_getc)(f)){
+ case 0x00:
+ if((c2 = (*i_getc)(f)) == 0x00){
+ if((c2 = (*i_getc)(f)) == 0xFE){
+ if((c2 = (*i_getc)(f)) == 0xFF){
+ if(!input_f){
+ set_iconv(TRUE, w_iconv32);
+ }
+ if (iconv == w_iconv32) {
+ input_endian = ENDIAN_BIG;
+ return;
+ }
+ (*i_ungetc)(0xFF,f);
+ }else (*i_ungetc)(c2,f);
+ (*i_ungetc)(0xFE,f);
+ }else if(c2 == 0xFF){
+ if((c2 = (*i_getc)(f)) == 0xFE){
+ if(!input_f){
+ set_iconv(TRUE, w_iconv32);
+ }
+ if (iconv == w_iconv32) {
+ input_endian = ENDIAN_2143;
+ return;
+ }
+ (*i_ungetc)(0xFF,f);
+ }else (*i_ungetc)(c2,f);
+ (*i_ungetc)(0xFF,f);
+ }else (*i_ungetc)(c2,f);
+ (*i_ungetc)(0x00,f);
+ }else (*i_ungetc)(c2,f);
+ (*i_ungetc)(0x00,f);
+ break;
+ case 0xEF:
+ if((c2 = (*i_getc)(f)) == 0xBB){
+ if((c2 = (*i_getc)(f)) == 0xBF){
+ if(!input_f){
+ set_iconv(TRUE, w_iconv);
+ }
+ if (iconv == w_iconv) {
+ return;
+ }
+ (*i_ungetc)(0xBF,f);
+ }else (*i_ungetc)(c2,f);
+ (*i_ungetc)(0xBB,f);
+ }else (*i_ungetc)(c2,f);
+ (*i_ungetc)(0xEF,f);
+ break;
+ case 0xFE:
+ if((c2 = (*i_getc)(f)) == 0xFF){
+ if((c2 = (*i_getc)(f)) == 0x00){
+ if((c2 = (*i_getc)(f)) == 0x00){
+ if(!input_f){
+ set_iconv(TRUE, w_iconv32);
+ }
+ if (iconv == w_iconv32) {
+ input_endian = ENDIAN_3412;
+ return;
+ }
+ (*i_ungetc)(0x00,f);
+ }else (*i_ungetc)(c2,f);
+ (*i_ungetc)(0x00,f);
+ }else (*i_ungetc)(c2,f);
+ if(!input_f){
+ set_iconv(TRUE, w_iconv16);
+ }
+ if (iconv == w_iconv16) {
+ input_endian = ENDIAN_BIG;
+ return;
+ }
+ (*i_ungetc)(0xFF,f);
+ }else (*i_ungetc)(c2,f);
+ (*i_ungetc)(0xFE,f);
+ break;
+ case 0xFF:
+ if((c2 = (*i_getc)(f)) == 0xFE){
+ if((c2 = (*i_getc)(f)) == 0x00){
+ if((c2 = (*i_getc)(f)) == 0x00){
+ if(!input_f){
+ set_iconv(TRUE, w_iconv32);
+ }
+ if (iconv == w_iconv32) {
+ input_endian = ENDIAN_LITTLE;
+ return;
+ }
+ (*i_ungetc)(0x00,f);
+ }else (*i_ungetc)(c2,f);
+ (*i_ungetc)(0x00,f);
+ }else (*i_ungetc)(c2,f);
+ if(!input_f){
+ set_iconv(TRUE, w_iconv16);
+ }
+ if (iconv == w_iconv16) {
+ input_endian = ENDIAN_LITTLE;
+ return;
+ }
+ (*i_ungetc)(0xFE,f);
+ }else (*i_ungetc)(c2,f);
+ (*i_ungetc)(0xFF,f);
+ break;
+ default:
+ (*i_ungetc)(c2,f);
+ break;
+ }
+}
+
+/*
Conversion main loop. Code detection only.
*/
nkf_char kanji_convert(FILE *f)
{
- nkf_char c1,
- c2, c3;
+ nkf_char c3, c2=0, c1, c0=0;
int is_8bit = FALSE;
- module_connection();
- c2 = 0;
-
- if(input_f == SJIS_INPUT
+ if(input_f == SJIS_INPUT || input_f == EUC_INPUT
#ifdef UTF8_INPUT_ENABLE
- || input_f == UTF8_INPUT || input_f == UTF16BE_INPUT || input_f == UTF16LE_INPUT
+ || input_f == UTF8_INPUT || input_f == UTF16_INPUT
#endif
){
is_8bit = TRUE;
}
-
input_mode = ASCII;
output_mode = ASCII;
shift_mode = FALSE;
@@ -2428,6 +2540,9 @@ nkf_char kanji_convert(FILE *f)
#define SEND ; /* output c1 and c2, get next */
#define LAST break /* end of loop, go closing */
+ module_connection();
+ check_bom(f);
+
while ((c1 = (*i_getc)(f)) != EOF) {
#ifdef INPUT_CODE_FIX
if (!input_f)
@@ -2435,7 +2550,7 @@ nkf_char kanji_convert(FILE *f)
code_status(c1);
if (c2) {
/* second byte */
- if (c2 > DEL) {
+ if (c2 > ((input_f == JIS_INPUT && ms_ucs_map_f) ? 0x92 : DEL)) {
/* in case of 8th bit is on */
if (!estab_f&&!mime_decode_mode) {
/* in case of not established yet */
@@ -2445,14 +2560,16 @@ nkf_char kanji_convert(FILE *f)
else
c2 = 0;
NEXT;
- } else
- /* in case of already established */
- if (c1 < AT) {
- /* ignore bogus code */
- c2 = 0;
- NEXT;
- } else
- SEND;
+ } else {
+ /* in case of already established */
+ if (c1 < AT) {
+ /* ignore bogus code and not CP5022x UCD */
+ c2 = 0;
+ NEXT;
+ } else {
+ SEND;
+ }
+ }
} else
/* second byte, 7 bit code */
/* it might be kanji shitfted */
@@ -2464,25 +2581,68 @@ nkf_char kanji_convert(FILE *f)
SEND;
} else {
/* first byte */
- if (
#ifdef UTF8_INPUT_ENABLE
- iconv == w_iconv16
-#else
- 0
-#endif
- ) {
- c2 = c1;
- c1 = (*i_getc)(f);
+ if (iconv == w_iconv16) {
+ if (input_endian == ENDIAN_BIG) {
+ c2 = c1;
+ if ((c1 = (*i_getc)(f)) != EOF) {
+ if (0xD8 <= c2 && c2 <= 0xDB) {
+ if ((c0 = (*i_getc)(f)) != EOF) {
+ c0 <<= 8;
+ if ((c3 = (*i_getc)(f)) != EOF) {
+ c0 |= c3;
+ } else c2 = EOF;
+ } else c2 = EOF;
+ }
+ } else c2 = EOF;
+ } else {
+ if ((c2 = (*i_getc)(f)) != EOF) {
+ if (0xD8 <= c2 && c2 <= 0xDB) {
+ if ((c3 = (*i_getc)(f)) != EOF) {
+ if ((c0 = (*i_getc)(f)) != EOF) {
+ c0 <<= 8;
+ c0 |= c3;
+ } else c2 = EOF;
+ } else c2 = EOF;
+ }
+ } else c2 = EOF;
+ }
SEND;
+ } else if(iconv == w_iconv32){
+ int c3 = c1;
+ if((c2 = (*i_getc)(f)) != EOF &&
+ (c1 = (*i_getc)(f)) != EOF &&
+ (c0 = (*i_getc)(f)) != EOF){
+ switch(input_endian){
+ case ENDIAN_BIG:
+ c1 = (c2&0xFF)<<16 | (c1&0xFF)<<8 | (c0&0xFF);
+ break;
+ case ENDIAN_LITTLE:
+ c1 = (c3&0xFF) | (c2&0xFF)<<8 | (c1&0xFF)<<16;
+ break;
+ case ENDIAN_2143:
+ c1 = (c3&0xFF)<<16 | (c1&0xFF) | (c0&0xFF)<<8;
+ break;
+ case ENDIAN_3412:
+ c1 = (c3&0xFF)<<8 | (c2&0xFF) | (c0&0xFF)<<16;
+ break;
+ }
+ c2 = 0;
+ }else{
+ c2 = EOF;
+ }
+ SEND;
+ } else
+#endif
#ifdef NUMCHAR_OPTION
- } else if (is_unicode_capsule(c1)){
+ if (is_unicode_capsule(c1)){
SEND;
+ } else
#endif
- } else if (c1 > DEL) {
+ if (c1 > ((input_f == JIS_INPUT && ms_ucs_map_f) ? 0x92 : DEL)) {
/* 8 bit code */
if (!estab_f && !iso8859_f) {
/* not established yet */
- if (!is_8bit) is_8bit = TRUE;
c2 = c1;
NEXT;
} else { /* estab_f==TRUE */
@@ -2573,13 +2733,13 @@ nkf_char kanji_convert(FILE *f)
/* normal ASCII code */
SEND;
}
- } else if (!is_8bit && c1 == SI) {
+ } else if (c1 == SI && (!is_8bit || mime_decode_mode)) {
shift_mode = FALSE;
NEXT;
- } else if (!is_8bit && c1 == SO) {
+ } else if (c1 == SO && (!is_8bit || mime_decode_mode)) {
shift_mode = TRUE;
NEXT;
- } else if (!is_8bit && c1 == ESC ) {
+ } else if (c1 == ESC && (!is_8bit || mime_decode_mode)) {
if ((c1 = (*i_getc)(f)) == EOF) {
/* (*oconv)(0, ESC); don't send bogus code */
LAST;
@@ -2687,6 +2847,44 @@ nkf_char kanji_convert(FILE *f)
(*oconv)(0, ESC);
SEND;
}
+ } else if (c1 == ESC && iconv == s_iconv) {
+ /* ESC in Shift_JIS */
+ if ((c1 = (*i_getc)(f)) == EOF) {
+ /* (*oconv)(0, ESC); don't send bogus code */
+ LAST;
+ } else if (c1 == '$') {
+ /* J-PHONE emoji */
+ if ((c1 = (*i_getc)(f)) == EOF) {
+ /*
+ (*oconv)(0, ESC); don't send bogus code
+ (*oconv)(0, '$'); */
+ LAST;
+ } else {
+ if (('E' <= c1 && c1 <= 'G') ||
+ ('O' <= c1 && c1 <= 'Q')) {
+ /*
+ NUM : 0 1 2 3 4 5
+ BYTE: G E F O P Q
+ C%7 : 1 6 0 2 3 4
+ C%7 : 0 1 2 3 4 5 6
+ NUM : 2 0 3 4 5 X 1
+ */
+ static const int jphone_emoji_first_table[7] = {2, 0, 3, 4, 5, 0, 1};
+ c0 = (jphone_emoji_first_table[c1 % 7] << 8) - SPACE + 0xE000 + CLASS_UNICODE;
+ while ((c1 = (*i_getc)(f)) != EOF) {
+ if (SPACE <= c1 && c1 <= 'z') {
+ (*oconv)(0, c1 + c0);
+ } else break; /* c1 == SO */
+ }
+ }
+ }
+ if (c1 == EOF) LAST;
+ NEXT;
+ } else {
+ /* lonely ESC */
+ (*oconv)(0, ESC);
+ SEND;
+ }
} else if ((c1 == NL || c1 == CR) && broken_f&4) {
input_mode = ASCII; set_iconv(FALSE, 0);
SEND;
@@ -2716,22 +2914,47 @@ nkf_char kanji_convert(FILE *f)
}
c1 = CR;
SEND;
+ } else if (c1 == DEL && input_mode == X0208 ) {
+ /* CP5022x */
+ c2 = c1;
+ NEXT;
} else
SEND;
}
/* send: */
switch(input_mode){
case ASCII:
- if ((*iconv)(c2, c1, 0) < 0){ /* can be EUC/SJIS */
- nkf_char c0 = (*i_getc)(f);
- if (c0 != EOF){
+ switch ((*iconv)(c2, c1, c0)) { /* can be EUC / SJIS / UTF-8 / UTF-16 */
+ case -2:
+ /* 4 bytes UTF-8 */
+ if ((c0 = (*i_getc)(f)) != EOF) {
+ code_status(c0);
+ c0 <<= 8;
+ if ((c3 = (*i_getc)(f)) != EOF) {
+ code_status(c3);
+ (*iconv)(c2, c1, c0|c3);
+ }
+ }
+ break;
+ case -1:
+ /* 3 bytes EUC or UTF-8 */
+ if ((c0 = (*i_getc)(f)) != EOF) {
code_status(c0);
(*iconv)(c2, c1, c0);
}
+ break;
}
break;
case X0208:
case X0213_1:
+ if (ms_ucs_map_f &&
+ 0x7F <= c2 && c2 <= 0x92 &&
+ 0x21 <= c1 && c1 <= 0x7E) {
+ /* CP932 UDC */
+ if(c1 == 0x7F) return 0;
+ c1 = (c2 - 0x7F) * 94 + c1 - 0x21 + 0xE000 + CLASS_UNICODE;
+ c2 = 0;
+ }
(*oconv)(c2, c1); /* this is JIS, not SJIS/EUC case */
break;
#ifdef X0212_ENABLE
@@ -2747,6 +2970,7 @@ nkf_char kanji_convert(FILE *f)
}
c2 = 0;
+ c0 = 0;
continue;
/* goto next_word */
}
@@ -2771,7 +2995,8 @@ nkf_char kanji_convert(FILE *f)
nkf_char
h_conv(FILE *f, nkf_char c2, nkf_char c1)
{
- nkf_char wc,c3;
+ nkf_char ret, c3, c0;
+ int hold_index;
/** it must NOT be in the kanji shifte sequence */
@@ -2800,12 +3025,12 @@ h_conv(FILE *f, nkf_char c2, nkf_char c1)
code_status(c1);
}
while (p->name){
- if (p->score < result->score){
+ if (p->status_func && p->score < result->score){
result = p;
}
++p;
}
- set_iconv(FALSE, result->iconv_func);
+ set_iconv(TRUE, result->iconv_func);
}
@@ -2818,10 +3043,10 @@ h_conv(FILE *f, nkf_char c2, nkf_char c1)
** Kanji codes by oconv and leave estab_f unchanged.
**/
- c3=c1;
- wc = 0;
- while (wc < hold_count){
- c2 = hold_buf[wc++];
+ ret = c1;
+ hold_index = 0;
+ while (hold_index < hold_count){
+ c2 = hold_buf[hold_index++];
if (c2 <= DEL
#ifdef NUMCHAR_OPTION
|| is_unicode_capsule(c2)
@@ -2833,8 +3058,8 @@ h_conv(FILE *f, nkf_char c2, nkf_char c1)
(*iconv)(X0201, c2, 0);
continue;
}
- if (wc < hold_count){
- c1 = hold_buf[wc++];
+ if (hold_index < hold_count){
+ c1 = hold_buf[hold_index++];
}else{
c1 = (*i_getc)(f);
if (c1 == EOF){
@@ -2843,28 +3068,48 @@ h_conv(FILE *f, nkf_char c2, nkf_char c1)
}
code_status(c1);
}
- if ((*iconv)(c2, c1, 0) < 0){
- nkf_char c0;
- if (wc < hold_count){
- c0 = hold_buf[wc++];
- }else{
- c0 = (*i_getc)(f);
- if (c0 == EOF){
- c3 = EOF;
- break;
- }
+ c0 = 0;
+ switch ((*iconv)(c2, c1, 0)) { /* can be EUC/SJIS/UTF-8 */
+ case -2:
+ /* 4 bytes UTF-8 */
+ if (hold_index < hold_count){
+ c0 = hold_buf[hold_index++];
+ } else if ((c0 = (*i_getc)(f)) == EOF) {
+ ret = EOF;
+ break;
+ } else {
+ code_status(c0);
+ c0 <<= 8;
+ if (hold_index < hold_count){
+ c3 = hold_buf[hold_index++];
+ } else if ((c3 = (*i_getc)(f)) == EOF) {
+ c0 = ret = EOF;
+ break;
+ } else {
+ code_status(c3);
+ (*iconv)(c2, c1, c0|c3);
+ }
+ }
+ break;
+ case -1:
+ /* 3 bytes EUC or UTF-8 */
+ if (hold_index < hold_count){
+ c0 = hold_buf[hold_index++];
+ } else if ((c0 = (*i_getc)(f)) == EOF) {
+ ret = EOF;
+ break;
+ } else {
code_status(c0);
}
(*iconv)(c2, c1, c0);
- }
+ break;
+ }
+ if (c0 == EOF) break;
}
- return c3;
+ return ret;
}
-
-
-nkf_char
-push_hold_buf(nkf_char c2)
+nkf_char push_hold_buf(nkf_char c2)
{
if (hold_count >= HOLD_SIZE*2)
return (EOF);
@@ -2879,7 +3124,7 @@ nkf_char s2e_conv(nkf_char c2, nkf_char c1, nkf_char *p2, nkf_char *p1)
#endif
static const nkf_char shift_jisx0213_s1a3_table[5][2] ={ { 1, 8}, { 3, 4}, { 5,12}, {13,14}, {15, 0} };
#ifdef SHIFTJIS_CP932
- if (cp51932_f && is_ibmext_in_sjis(c2)){
+ if (!cp932inv_f && is_ibmext_in_sjis(c2)){
#if 0
extern const unsigned short shiftjis_cp932[3][189];
#endif
@@ -2889,6 +3134,17 @@ nkf_char s2e_conv(nkf_char c2, nkf_char c1, nkf_char *p2, nkf_char *p1)
c1 = val & 0xff;
}
}
+ if (cp932inv_f
+ && CP932INV_TABLE_BEGIN <= c2 && c2 <= CP932INV_TABLE_END){
+#if 0
+ extern const unsigned short cp932inv[2][189];
+#endif
+ nkf_char c = cp932inv[c2 - CP932INV_TABLE_BEGIN][c1 - 0x40];
+ if (c){
+ c2 = c >> 8;
+ c1 = c & 0xff;
+ }
+ }
#endif /* SHIFTJIS_CP932 */
#ifdef X0212_ENABLE
if (!x0213_f && is_ibmext_in_sjis(c2)){
@@ -2898,7 +3154,7 @@ nkf_char s2e_conv(nkf_char c2, nkf_char c1, nkf_char *p2, nkf_char *p1)
val = shiftjis_x0212[c2 - 0xfa][c1 - 0x40];
if (val){
if (val > 0x7FFF){
- c2 = PREFIX_EUCG3 | (val >> 8);
+ c2 = PREFIX_EUCG3 | ((val >> 8) & 0x7f);
c1 = val & 0xff;
}else{
c2 = val >> 8;
@@ -2943,6 +3199,11 @@ nkf_char s_iconv(nkf_char c2, nkf_char c1, nkf_char c0)
c1 &= 0x7f;
} else if ((c2 == EOF) || (c2 == 0) || c2 < SPACE) {
/* NOP */
+ } else if (!x0213_f && 0xF0 <= c2 && c2 <= 0xF9 && 0x40 <= c1 && c1 <= 0xFC) {
+ /* CP932 UDC */
+ if(c1 == 0x7F) return 0;
+ c1 = (c2 - 0xF0) * 188 + (c1 - 0x40 - (0x7E < c1)) + 0xE000 + CLASS_UNICODE;
+ c2 = 0;
} else {
nkf_char ret = s2e_conv(c2, c1, &c2, &c1);
if (ret) return ret;
@@ -2960,20 +3221,26 @@ nkf_char e_iconv(nkf_char c2, nkf_char c1, nkf_char c0)
if (c0 == 0){
return -1;
}
- c2 = (c2 << 8) | (c1 & 0x7f);
- c1 = c0 & 0x7f;
+ if (!cp51932_f && !x0213_f && 0xF5 <= c1 && c1 <= 0xFE && 0xA1 <= c0 && c0 <= 0xFE) {
+ /* encoding is eucJP-ms, so invert to Unicode Private User Area */
+ c1 = (c1 - 0xF5) * 94 + c0 - 0xA1 + 0xE3AC + CLASS_UNICODE;
+ c2 = 0;
+ } else {
+ c2 = (c2 << 8) | (c1 & 0x7f);
+ c1 = c0 & 0x7f;
#ifdef SHIFTJIS_CP932
- if (cp51932_f){
- nkf_char s2, s1;
- if (e2s_conv(c2, c1, &s2, &s1) == 0){
- s2e_conv(s2, s1, &c2, &c1);
- if (c2 < 0x100){
- c1 &= 0x7f;
- c2 &= 0x7f;
- }
- }
- }
+ if (cp51932_f){
+ nkf_char s2, s1;
+ if (e2s_conv(c2, c1, &s2, &s1) == 0){
+ s2e_conv(s2, s1, &c2, &c1);
+ if (c2 < 0x100){
+ c1 &= 0x7f;
+ c2 &= 0x7f;
+ }
+ }
+ }
#endif /* SHIFTJIS_CP932 */
+ }
#endif /* X0212_ENABLE */
} else if (c2 == SSO){
c2 = X0201;
@@ -2981,8 +3248,26 @@ nkf_char e_iconv(nkf_char c2, nkf_char c1, nkf_char c0)
} else if ((c2 == EOF) || (c2 == 0) || c2 < SPACE) {
/* NOP */
} else {
- c1 &= 0x7f;
- c2 &= 0x7f;
+ if (!cp51932_f && ms_ucs_map_f && 0xF5 <= c2 && c2 <= 0xFE && 0xA1 <= c1 && c1 <= 0xFE) {
+ /* encoding is eucJP-ms, so invert to Unicode Private User Area */
+ c1 = (c2 - 0xF5) * 94 + c1 - 0xA1 + 0xE000 + CLASS_UNICODE;
+ c2 = 0;
+ } else {
+ c1 &= 0x7f;
+ c2 &= 0x7f;
+#ifdef SHIFTJIS_CP932
+ if (cp51932_f && 0x79 <= c2 && c2 <= 0x7c){
+ nkf_char s2, s1;
+ if (e2s_conv(c2, c1, &s2, &s1) == 0){
+ s2e_conv(s2, s1, &c2, &c1);
+ if (c2 < 0x100){
+ c1 &= 0x7f;
+ c2 &= 0x7f;
+ }
+ }
+ }
+#endif /* SHIFTJIS_CP932 */
+ }
}
(*oconv)(c2, c1);
return 0;
@@ -3001,7 +3286,7 @@ nkf_char w2e_conv(nkf_char c2, nkf_char c1, nkf_char c0, nkf_char *p2, nkf_char
#ifdef NUMCHAR_OPTION
if (ret > 0){
if (p2) *p2 = 0;
- if (p1) *p1 = CLASS_UTF16 | ww16_conv(c2, c1, c0);
+ if (p1) *p1 = CLASS_UNICODE | ww16_conv(c2, c1, c0);
ret = 0;
}
#endif
@@ -3012,43 +3297,63 @@ nkf_char w2e_conv(nkf_char c2, nkf_char c1, nkf_char c0, nkf_char *p2, nkf_char
nkf_char w_iconv(nkf_char c2, nkf_char c1, nkf_char c0)
{
nkf_char ret = 0;
+ static const int w_iconv_utf8_1st_byte[] =
+ { /* 0xC0 - 0xFF */
+ 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 32, 33, 33,
+ 40, 41, 41, 41, 42, 43, 43, 43, 50, 50, 50, 50, 60, 60, 70, 70};
- /* throw away ZERO WIDTH NO-BREAK SPACE (U+FEFF) */
- if(ignore_zwnbsp_f){
- ignore_zwnbsp_f = FALSE;
- if(c2 == 0xef && c1 == 0xbb && c0 == 0xbf)
- return 0;
- }
-
- if (c2 == 0) /* 0x00-0x7f */
- c1 &= 0x7F; /* 1byte */
- else if (c0 == 0){
- if ((c2 & 0xe0) == 0xc0){ /* 0xc0-0xdf */
- /* 2ytes */
- if((c2 & 0xFE) == 0xC0 || c1 < 0x80 || 0xBF < c1) return 0;
- }else if ((c2 & 0xf0) == 0xe0) /* 0xe0-0xef */
- return -1; /* 3bytes */
-#ifdef __COMMENT__
- else if (0xf0 <= c2)
- return 0; /* 4,5,6bytes */
- else if ((c2 & 0xc0) == 0x80) /* 0x80-0xbf */
- return 0; /* trail byte */
-#endif
- else return 0;
- }else{
- /* must be 3bytes */
- if(c2 == 0xE0){
- if(c1 < 0xA0 || 0xBF < c1 || c0 < 0x80 || 0xBF < c0)
+ if (c2 < 0 || 0xff < c2) {
+ }else if (c2 == 0) { /* 0 : 1 byte*/
+ c0 = 0;
+ } else if ((c2 & 0xc0) == 0x80) { /* 0x80-0xbf : trail byte */
+ return 0;
+ } else{
+ switch (w_iconv_utf8_1st_byte[c2 - 0xC0]) {
+ case 21:
+ if (c1 < 0x80 || 0xBF < c1) return 0;
+ break;
+ case 30:
+ if (c0 == 0) return -1;
+ if (c1 < 0xA0 || 0xBF < c1 || (c0 & 0xc0) != 0x80)
+ return 0;
+ break;
+ case 31:
+ case 33:
+ if (c0 == 0) return -1;
+ if ((c1 & 0xc0) != 0x80 || (c0 & 0xc0) != 0x80)
+ return 0;
+ break;
+ case 32:
+ if (c0 == 0) return -1;
+ if (c1 < 0x80 || 0x9F < c1 || (c0 & 0xc0) != 0x80)
+ return 0;
+ break;
+ case 40:
+ if (c0 == 0) return -2;
+ if (c1 < 0x90 || 0xBF < c1 || (c0 & 0xc0c0) != 0x8080)
return 0;
- }else if(c2 == 0xED){
- if(c1 < 0x80 || 0x9F < c1 || c0 < 0x80 || 0xBF < c0)
+ break;
+ case 41:
+ if (c0 == 0) return -2;
+ if (c1 < 0x80 || 0xBF < c1 || (c0 & 0xc0c0) != 0x8080)
return 0;
- }else if((c2 & 0xf0) == 0xe0){
- if(c1 < 0x80 || 0xBF < c1 || c0 < 0x80 || 0xBF < c0)
+ break;
+ case 42:
+ if (c0 == 0) return -2;
+ if (c1 < 0x80 || 0x8F < c1 || (c0 & 0xc0c0) != 0x8080)
return 0;
- }else return 0;
+ break;
+ default:
+ return 0;
+ break;
+ }
}
if (c2 == 0 || c2 == EOF){
+ } else if ((c2 & 0xf8) == 0xf0) { /* 4 bytes */
+ c1 = CLASS_UNICODE | ww16_conv(c2, c1, c0);
+ c2 = 0;
} else {
ret = w2e_conv(c2, c1, c0, &c2, &c1);
}
@@ -3075,6 +3380,10 @@ void w16w_conv(nkf_char val, nkf_char *p2, nkf_char *p1, nkf_char *p0)
*p2 = 0xe0 | (val >> 12);
*p1 = 0x80 | ((val >> 6) & 0x3f);
*p0 = 0x80 | (val & 0x3f);
+ } else if (val <= NKF_INT32_C(0x10FFFF)) {
+ *p2 = 0xe0 | (val >> 16);
+ *p1 = 0x80 | ((val >> 12) & 0x3f);
+ *p0 = 0x8080 | ((val << 2) & 0x3f00)| (val & 0x3f);
} else {
*p2 = 0;
*p1 = 0;
@@ -3087,8 +3396,14 @@ void w16w_conv(nkf_char val, nkf_char *p2, nkf_char *p1, nkf_char *p0)
nkf_char ww16_conv(nkf_char c2, nkf_char c1, nkf_char c0)
{
nkf_char val;
- if (c2 >= 0xf0){
+ if (c2 >= 0xf8) {
val = -1;
+ } else if (c2 >= 0xf0){
+ /* c2: 1st, c1: 2nd, c0: 3rd/4th */
+ val = (c2 & 0x0f) << 18;
+ val |= (c1 & 0x3f) << 12;
+ val |= (c0 & 0x3f00) >> 2;
+ val |= (c0 & 0x3f);
}else if (c2 >= 0xe0){
val = (c2 & 0x0f) << 12;
val |= (c1 & 0x3f) << 6;
@@ -3116,7 +3431,7 @@ nkf_char w16e_conv(nkf_char val, nkf_char *p2, nkf_char *p1)
#ifdef NUMCHAR_OPTION
if (ret > 0){
*p2 = 0;
- *p1 = CLASS_UTF16 | val;
+ *p1 = CLASS_UNICODE | val;
ret = 0;
}
#endif
@@ -3128,27 +3443,19 @@ nkf_char w16e_conv(nkf_char val, nkf_char *p2, nkf_char *p1)
#ifdef UTF8_INPUT_ENABLE
nkf_char w_iconv16(nkf_char c2, nkf_char c1, nkf_char c0)
{
- nkf_char ret;
-
- /* throw away ZERO WIDTH NO-BREAK SPACE (U+FEFF) */
- if(ignore_zwnbsp_f){
- ignore_zwnbsp_f = FALSE;
- if (c2==0376 && c1==0377){
- utf16_mode = UTF16BE_INPUT;
- return 0;
- }else if(c2==0377 && c1==0376){
- utf16_mode = UTF16LE_INPUT;
- return 0;
- }
- }
- if (c2 != EOF && utf16_mode == UTF16LE_INPUT) {
- nkf_char tmp;
- tmp=c1; c1=c2; c2=tmp;
- }
+ nkf_char ret = 0;
if ((c2==0 && c1 < 0x80) || c2==EOF) {
(*oconv)(c2, c1);
return 0;
- }else if((c2>>3)==27){ /* surrogate pair */
+ }else if (0xD8 <= c2 && c2 <= 0xDB) {
+ if (c0 < NKF_INT32_C(0xDC00) || NKF_INT32_C(0xDFFF) < c0)
+ return -2;
+ c1 = CLASS_UNICODE | ((c2 << 18) + (c1 << 10) + c0 - NKF_INT32_C(0x35FDC00));
+ c2 = 0;
+ }else if ((c2>>3) == 27) { /* unpaired surrogate */
+ /*
+ return 2;
+ */
return 1;
}else ret = w16e_conv(((c2 & 0xff)<<8) + c1, &c2, &c1);
if (ret) return ret;
@@ -3156,6 +3463,22 @@ nkf_char w_iconv16(nkf_char c2, nkf_char c1, nkf_char c0)
return 0;
}
+nkf_char w_iconv32(nkf_char c2, nkf_char c1, nkf_char c0)
+{
+ int ret = 0;
+
+ if ((c2 == 0 && c1 < 0x80) || c2==EOF) {
+ } else if (is_unicode_bmp(c1)) {
+ ret = w16e_conv(c1, &c2, &c1);
+ } else {
+ c2 = 0;
+ c1 = CLASS_UNICODE | c1;
+ }
+ if (ret) return ret;
+ (*oconv)(c2, c1);
+ return 0;
+}
+
nkf_char unicode_to_jis_common(nkf_char c2, nkf_char c1, nkf_char c0, nkf_char *p2, nkf_char *p1)
{
#if 0
@@ -3204,7 +3527,7 @@ nkf_char unicode_to_jis_common(nkf_char c2, nkf_char c1, nkf_char c0, nkf_char *
if(no_best_fit_chars_table_932_C3[c1&0x3F]) return 1;
break;
}
- }else if(cp51932_f){
+ }else if(!cp932inv_f){
switch(c2){
case 0xC2:
if(no_best_fit_chars_table_C2[c1&0x3F]) return 1;
@@ -3260,7 +3583,7 @@ nkf_char unicode_to_jis_common(nkf_char c2, nkf_char c1, nkf_char c0, nkf_char *
if(c0 == 0x8D) return 1;
break;
case 0xBD:
- if(c0 == 0x9E && cp51932_f) return 1;
+ if(c0 == 0x9E && !cp932inv_f) return 1;
break;
case 0xBF:
if(0xA0 <= c0 && c0 <= 0xA5) return 1;
@@ -3277,7 +3600,7 @@ nkf_char unicode_to_jis_common(nkf_char c2, nkf_char c1, nkf_char c0, nkf_char *
ret = w_iconv_common(c1, c0, ppp[c2 - 0xE0], sizeof_utf8_to_euc_C2, p2, p1);
}else return -1;
#ifdef SHIFTJIS_CP932
- if (!ret && cp51932_f && is_eucg3(*p2)) {
+ if (!ret && !cp932inv_f && is_eucg3(*p2)) {
nkf_char s2, s1;
if (e2s_conv(*p2, *p1, &s2, &s1) == 0) {
s2e_conv(s2, s1, p2, p1);
@@ -3456,16 +3779,17 @@ void w_oconv(nkf_char c2, nkf_char c1)
{
nkf_char c0;
nkf_char val;
- if (c2 == EOF) {
- (*o_putc)(EOF);
- return;
- }
- if (unicode_bom_f==2) {
- (*o_putc)('\357');
+ if (output_bom_f) {
+ output_bom_f = FALSE;
+ (*o_putc)('\357');
(*o_putc)('\273');
(*o_putc)('\277');
- unicode_bom_f=1;
+ }
+
+ if (c2 == EOF) {
+ (*o_putc)(EOF);
+ return;
}
#ifdef NUMCHAR_OPTION
@@ -3481,7 +3805,7 @@ void w_oconv(nkf_char c2, nkf_char c1)
(*o_putc)(0x80 | ((val >> 6) & 0x3f));
(*o_putc)(0x80 | (val & 0x3f));
} else if (val <= NKF_INT32_C(0x10FFFF)) {
- (*o_putc)(0xE0 | ( val>>18));
+ (*o_putc)(0xF0 | ( val>>18));
(*o_putc)(0x80 | ((val>>12) & 0x3f));
(*o_putc)(0x80 | ((val>> 6) & 0x3f));
(*o_putc)(0x80 | ( val & 0x3f));
@@ -3512,20 +3836,20 @@ void w_oconv(nkf_char c2, nkf_char c1)
void w_oconv16(nkf_char c2, nkf_char c1)
{
- if (c2 == EOF) {
- (*o_putc)(EOF);
- return;
- }
-
- if (unicode_bom_f==2) {
- if (w_oconv16_LE){
+ if (output_bom_f) {
+ output_bom_f = FALSE;
+ if (output_endian == ENDIAN_LITTLE){
(*o_putc)((unsigned char)'\377');
(*o_putc)('\376');
}else{
(*o_putc)('\376');
(*o_putc)((unsigned char)'\377');
}
- unicode_bom_f=1;
+ }
+
+ if (c2 == EOF) {
+ (*o_putc)(EOF);
+ return;
}
if (c2 == ISO8859_1) {
@@ -3541,7 +3865,7 @@ void w_oconv16(nkf_char c2, nkf_char c1)
if (c1 <= UNICODE_MAX) {
c2 = (c1 >> 10) + NKF_INT32_C(0xD7C0); /* high surrogate */
c1 = (c1 & 0x3FF) + NKF_INT32_C(0xDC00); /* low surrogate */
- if (w_oconv16_LE){
+ if (output_endian == ENDIAN_LITTLE){
(*o_putc)(c2 & 0xff);
(*o_putc)((c2 >> 8) & 0xff);
(*o_putc)(c1 & 0xff);
@@ -3560,8 +3884,9 @@ void w_oconv16(nkf_char c2, nkf_char c1)
nkf_char val = e2w_conv(c2, c1);
c2 = (val >> 8) & 0xff;
c1 = val & 0xff;
+ if (!val) return;
}
- if (w_oconv16_LE){
+ if (output_endian == ENDIAN_LITTLE){
(*o_putc)(c1);
(*o_putc)(c2);
}else{
@@ -3570,6 +3895,50 @@ void w_oconv16(nkf_char c2, nkf_char c1)
}
}
+void w_oconv32(nkf_char c2, nkf_char c1)
+{
+ if (output_bom_f) {
+ output_bom_f = FALSE;
+ if (output_endian == ENDIAN_LITTLE){
+ (*o_putc)((unsigned char)'\377');
+ (*o_putc)('\376');
+ (*o_putc)('\000');
+ (*o_putc)('\000');
+ }else{
+ (*o_putc)('\000');
+ (*o_putc)('\000');
+ (*o_putc)('\376');
+ (*o_putc)((unsigned char)'\377');
+ }
+ }
+
+ if (c2 == EOF) {
+ (*o_putc)(EOF);
+ return;
+ }
+
+ if (c2 == ISO8859_1) {
+ c1 |= 0x80;
+#ifdef NUMCHAR_OPTION
+ } else if (c2 == 0 && is_unicode_capsule(c1)) {
+ c1 &= VALUE_MASK;
+#endif
+ } else if (c2) {
+ c1 = e2w_conv(c2, c1);
+ if (!c1) return;
+ }
+ if (output_endian == ENDIAN_LITTLE){
+ (*o_putc)( c1 & NKF_INT32_C(0x000000FF));
+ (*o_putc)((c1 & NKF_INT32_C(0x0000FF00)) >> 8);
+ (*o_putc)((c1 & NKF_INT32_C(0x00FF0000)) >> 16);
+ (*o_putc)('\000');
+ }else{
+ (*o_putc)('\000');
+ (*o_putc)((c1 & NKF_INT32_C(0x00FF0000)) >> 16);
+ (*o_putc)((c1 & NKF_INT32_C(0x0000FF00)) >> 8);
+ (*o_putc)( c1 & NKF_INT32_C(0x000000FF));
+ }
+}
#endif
void e_oconv(nkf_char c2, nkf_char c1)
@@ -3578,8 +3947,26 @@ void e_oconv(nkf_char c2, nkf_char c1)
if (c2 == 0 && is_unicode_capsule(c1)){
w16e_conv(c1, &c2, &c1);
if (c2 == 0 && is_unicode_capsule(c1)){
- if(encode_fallback)(*encode_fallback)(c1);
- return;
+ c2 = c1 & VALUE_MASK;
+ if (x0212_f && 0xE000 <= c2 && c2 <= 0xE757) {
+ /* eucJP-ms UDC */
+ c1 &= 0xFFF;
+ c2 = c1 / 94;
+ c2 += c2 < 10 ? 0x75 : 0x8FEB;
+ c1 = 0x21 + c1 % 94;
+ if (is_eucg3(c2)){
+ (*o_putc)(0x8f);
+ (*o_putc)((c2 & 0x7f) | 0x080);
+ (*o_putc)(c1 | 0x080);
+ }else{
+ (*o_putc)((c2 & 0x7f) | 0x080);
+ (*o_putc)(c1 | 0x080);
+ }
+ return;
+ } else {
+ if (encode_fallback) (*encode_fallback)(c1);
+ return;
+ }
}
}
#endif
@@ -3599,7 +3986,7 @@ void e_oconv(nkf_char c2, nkf_char c1)
} else if (is_eucg3(c2)){
output_mode = JAPANESE_EUC;
#ifdef SHIFTJIS_CP932
- if (cp51932_f){
+ if (!cp932inv_f){
nkf_char s2, s1;
if (e2s_conv(c2, c1, &s2, &s1) == 0){
s2e_conv(s2, s1, &c2, &c1);
@@ -3665,7 +4052,7 @@ nkf_char e2s_conv(nkf_char c2, nkf_char c1, nkf_char *p2, nkf_char *p1)
{
nkf_char ndx;
if (is_eucg3(c2)){
- ndx = c2 & 0xff;
+ ndx = c2 & 0x7f;
if (x0213_f){
if((0x21 <= ndx && ndx <= 0x2F)){
if (p2) *p2 = ((ndx - 1) >> 1) + 0xec - ndx / 8 * 3;
@@ -3712,9 +4099,21 @@ void s_oconv(nkf_char c2, nkf_char c1)
if (c2 == 0 && is_unicode_capsule(c1)){
w16e_conv(c1, &c2, &c1);
if (c2 == 0 && is_unicode_capsule(c1)){
- if(encode_fallback)(*encode_fallback)(c1);
- return;
- }
+ c2 = c1 & VALUE_MASK;
+ if (!x0213_f && 0xE000 <= c2 && c2 <= 0xE757) {
+ /* CP932 UDC */
+ c1 &= 0xFFF;
+ c2 = c1 / 188 + 0xF0;
+ c1 = c1 % 188;
+ c1 += 0x40 + (c1 > 0x3e);
+ (*o_putc)(c2);
+ (*o_putc)(c1);
+ return;
+ } else {
+ if(encode_fallback)(*encode_fallback)(c1);
+ return;
+ }
+ }
}
#endif
if (c2 == EOF) {
@@ -3773,8 +4172,16 @@ void j_oconv(nkf_char c2, nkf_char c1)
if (c2 == 0 && is_unicode_capsule(c1)){
w16e_conv(c1, &c2, &c1);
if (c2 == 0 && is_unicode_capsule(c1)){
- if(encode_fallback)(*encode_fallback)(c1);
- return;
+ c2 = c1 & VALUE_MASK;
+ if (ms_ucs_map_f && 0xE000 <= c2 && c2 <= 0xE757) {
+ /* CP5022x UDC */
+ c1 &= 0xFFF;
+ c2 = 0x7F + c1 / 94;
+ c1 = 0x21 + c1 % 94;
+ } else {
+ if (encode_fallback) (*encode_fallback)(c1);
+ return;
+ }
}
}
#endif
@@ -3831,7 +4238,9 @@ void j_oconv(nkf_char c2, nkf_char c1)
}
(*o_putc)(c1);
} else {
- if(c2<0x20 || 0x7e<c2 || c1<0x20 || 0x7e<c1) return;
+ if(ms_ucs_map_f
+ ? c2<0x20 || 0x92<c2 || c1<0x20 || 0x7e<c1
+ : c2<0x20 || 0x7e<c2 || c1<0x20 || 0x7e<c1) return;
if(x0213_f){
if (output_mode!=X0213_1) {
output_mode = X0213_1;
@@ -4235,7 +4644,7 @@ void hira_conv(nkf_char c2, nkf_char c1)
return;
} else if (c1 == 0x74 && (output_conv == w_oconv || output_conv == w_oconv16)) {
c2 = 0;
- c1 = CLASS_UTF16 | 0x3094;
+ c1 = CLASS_UNICODE | 0x3094;
(*o_hira_conv)(c2,c1);
return;
}
@@ -4246,7 +4655,7 @@ void hira_conv(nkf_char c2, nkf_char c1)
}
}
if (hira_f & 2) {
- if (c2 == 0 && c1 == (CLASS_UTF16 | 0x3094)) {
+ if (c2 == 0 && c1 == (CLASS_UNICODE | 0x3094)) {
c2 = 0x25;
c1 = 0x74;
} else if (c2 == 0x24 && 0x20 < c1 && c1 < 0x74) {
@@ -4595,7 +5004,7 @@ nkf_char numchar_getc(FILE *f)
nkf_char (*g)(FILE *) = i_ngetc;
nkf_char (*u)(nkf_char c ,FILE *f) = i_nungetc;
int i = 0, j;
- nkf_char buf[8];
+ nkf_char buf[10];
long c = -1;
buf[i] = (*g)(f);
@@ -4634,7 +5043,7 @@ nkf_char numchar_getc(FILE *f)
}
}
if (c != -1){
- return CLASS_UTF16 | c;
+ return CLASS_UNICODE | c;
}
while (i > 0){
(*u)(buf[i], f);
@@ -5409,14 +5818,14 @@ void reinit(void)
#endif
#ifdef UTF8_INPUT_ENABLE
no_cp932ext_f = FALSE;
- ignore_zwnbsp_f = TRUE;
no_best_fit_chars_f = FALSE;
encode_fallback = NULL;
unicode_subchar = '?';
+ input_endian = ENDIAN_BIG;
#endif
#ifdef UTF8_OUTPUT_ENABLE
- unicode_bom_f = 0;
- w_oconv16_LE = 0;
+ output_bom_f = FALSE;
+ output_endian = ENDIAN_BIG;
#endif
#ifdef UNICODE_NORMALIZATION
nfc_f = FALSE;
@@ -5450,9 +5859,7 @@ void reinit(void)
prefix_table[i] = 0;
}
}
-#ifdef UTF8_INPUT_ENABLE
- utf16_mode = UTF16BE_INPUT;
-#endif
+ hold_count = 0;
mimeout_buf_count = 0;
mimeout_mode = 0;
base64_count = 0;
@@ -5525,16 +5932,16 @@ void usage(void)
fprintf(stderr,"Flags:\n");
fprintf(stderr,"b,u Output is buffered (DEFAULT),Output is unbuffered\n");
#ifdef DEFAULT_CODE_SJIS
- fprintf(stderr,"j,s,e,w Outout code is JIS 7 bit, Shift_JIS (DEFAULT), EUC-JP, UTF-8N\n");
+ fprintf(stderr,"j,s,e,w Output code is JIS 7 bit, Shift_JIS (DEFAULT), EUC-JP, UTF-8N\n");
#endif
#ifdef DEFAULT_CODE_JIS
- fprintf(stderr,"j,s,e,w Outout code is JIS 7 bit (DEFAULT), Shift JIS, EUC-JP, UTF-8N\n");
+ fprintf(stderr,"j,s,e,w Output code is JIS 7 bit (DEFAULT), Shift JIS, EUC-JP, UTF-8N\n");
#endif
#ifdef DEFAULT_CODE_EUC
- fprintf(stderr,"j,s,e,w Outout code is JIS 7 bit, Shift JIS, EUC-JP (DEFAULT), UTF-8N\n");
+ fprintf(stderr,"j,s,e,w Output code is JIS 7 bit, Shift JIS, EUC-JP (DEFAULT), UTF-8N\n");
#endif
#ifdef DEFAULT_CODE_UTF8
- fprintf(stderr,"j,s,e,w Outout code is JIS 7 bit, Shift JIS, EUC-JP, UTF-8N (DEFAULT)\n");
+ fprintf(stderr,"j,s,e,w Output code is JIS 7 bit, Shift JIS, EUC-JP, UTF-8N (DEFAULT)\n");
#endif
#ifdef UTF8_OUTPUT_ENABLE
fprintf(stderr," After 'w' you can add more options. -w[ 8 [0], 16 [[BL] [0]] ]\n");
diff --git a/ext/nkf/nkf-utf8/utf8tbl.c b/ext/nkf/nkf-utf8/utf8tbl.c
index 9e59956a0a..e43ad553d6 100644
--- a/ext/nkf/nkf-utf8/utf8tbl.c
+++ b/ext/nkf/nkf-utf8/utf8tbl.c
@@ -7544,7 +7544,7 @@ const unsigned short cp932inv[2][189] = {
0xFBFC, 0xFC40, 0xFC41, 0xFC42, 0xFC43, 0xFC44, 0xFC45, 0xFC46,
0xFC47, 0xFC48, 0xFC49, 0xFC4A, 0xFC4B, 0, 0, 0xFA40,
0xFA41, 0xFA42, 0xFA43, 0xFA44, 0xFA45, 0xFA46, 0xFA47, 0xFA48,
- 0xFA49, 0, 0xFA55, 0xFA56, 0xFA57,
+ 0xFA49, 0x81CA, 0xFA55, 0xFA56, 0xFA57,
},
};
#endif /* SHIFTJIS_CP932 */
diff --git a/ext/nkf/nkf.c b/ext/nkf/nkf.c
index 8bcb6d15f7..2bb0340a64 100644
--- a/ext/nkf/nkf.c
+++ b/ext/nkf/nkf.c
@@ -3,11 +3,11 @@
*
* original nkf2.x is maintained at http://sourceforge.jp/projects/nkf/
*
- * $Id: nkf.c,v 1.9.2.4 2006/03/27 13:28:14 naruse Exp $
+ * $Id$
*
*/
-#define RUBY_NKF_REVISION "$Revision: 1.9.2.4 $"
+#define RUBY_NKF_REVISION "$Revision$"
#define RUBY_NKF_VERSION NKF_VERSION " (" NKF_RELEASE_DATE ")"
#include "ruby.h"
@@ -63,7 +63,7 @@ rb_nkf_putchar(c)
o_len += incsize;
rb_str_resize(result, o_len);
incsize *= 2;
- output = RSTRING(result)->ptr;
+ output = (unsigned char *)RSTRING(result)->ptr;
}
output[output_ctr++] = c;
@@ -158,13 +158,13 @@ rb_nkf_kconv(obj, opt, src)
input_ctr = 0;
StringValue(src);
- input = RSTRING(src)->ptr;
+ input = (unsigned char *)RSTRING(src)->ptr;
i_len = RSTRING(src)->len;
result = rb_str_new(0, i_len*3 + 10);
v = result;
output_ctr = 0;
- output = RSTRING(result)->ptr;
+ output = (unsigned char *)RSTRING(result)->ptr;
o_len = RSTRING(result)->len;
*output = '\0';
@@ -213,7 +213,7 @@ rb_nkf_guess1(obj, src)
int sequence_counter = 0;
StringValue(src);
- p = RSTRING(src)->ptr;
+ p = (unsigned char *)RSTRING(src)->ptr;
pend = p + RSTRING(src)->len;
if (p == pend) return INT2FIX(_UNKNOWN);
@@ -328,7 +328,7 @@ rb_nkf_guess2(obj, src)
input_ctr = 0;
StringValue(src);
- input = RSTRING(src)->ptr;
+ input = (unsigned char *)RSTRING(src)->ptr;
i_len = RSTRING(src)->len;
if(x0201_f == WISH_TRUE)
diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
index b2c5ca5ef8..3f9ef511f3 100644
--- a/ext/openssl/extconf.rb
+++ b/ext/openssl/extconf.rb
@@ -1,5 +1,5 @@
=begin
-= $RCSfile: extconf.rb,v $ -- Generator for Makefile
+= $RCSfile$ -- Generator for Makefile
= Info
'OpenSSL for Ruby 2' project
@@ -11,7 +11,7 @@
(See the file 'LICENCE'.)
= Version
- $Id: extconf.rb,v 1.21.2.9 2006/06/20 11:18:15 gotoyuzo Exp $
+ $Id$
=end
require "mkmf"
@@ -36,8 +36,6 @@ end
message "=== Checking for system dependent stuff... ===\n"
have_library("nsl", "t_open")
have_library("socket", "socket")
-have_header("unistd.h")
-have_header("sys/time.h")
have_header("assert.h")
message "=== Checking for required stuff... ===\n"
@@ -61,6 +59,8 @@ unless have_header("openssl/conf_api.h")
exit 1
end
+%w"rb_str_set_len rb_block_call".each {|func| have_func(func, "ruby.h")}
+
message "=== Checking for OpenSSL features... ===\n"
have_func("ERR_peek_last_error")
have_func("BN_mod_add")
@@ -83,19 +83,29 @@ have_func("HMAC_CTX_cleanup")
have_func("HMAC_CTX_copy")
have_func("HMAC_CTX_init")
have_func("PEM_def_callback")
+have_func("PKCS5_PBKDF2_HMAC")
+have_func("PKCS5_PBKDF2_HMAC_SHA1")
have_func("X509V3_set_nconf")
have_func("X509V3_EXT_nconf_nid")
have_func("X509_CRL_add0_revoked")
have_func("X509_CRL_set_issuer_name")
have_func("X509_CRL_set_version")
have_func("X509_CRL_sort")
+have_func("X509_NAME_hash_old")
have_func("X509_STORE_get_ex_data")
have_func("X509_STORE_set_ex_data")
have_func("OBJ_NAME_do_all_sorted")
+have_func("SSL_SESSION_get_id")
have_func("OPENSSL_cleanse")
-if try_compile("#define FOO(a, ...) foo(a, ##__VA_ARGS__)\n int x(){FOO(1);FOO(1,2);FOO(1,2,3);}\n")
+if try_compile("#define FOO(...) foo(__VA_ARGS__)\n int x(){FOO(1);FOO(1,2);FOO(1,2,3);}\n")
$defs.push("-DHAVE_VA_ARGS_MACRO")
end
+have_func("SSLv2_method")
+have_func("SSLv2_server_method")
+have_func("SSLv2_client_method")
+unless have_func("SSL_set_tlsext_host_name", ['openssl/ssl.h'])
+ have_macro("SSL_set_tlsext_host_name", ['openssl/ssl.h']) && $defs.push("-DHAVE_SSL_SET_TLSEXT_HOST_NAME")
+end
if have_header("openssl/engine.h")
have_func("ENGINE_add")
have_func("ENGINE_load_builtin_engines")
@@ -103,6 +113,14 @@ if have_header("openssl/engine.h")
have_func("ENGINE_get_digest")
have_func("ENGINE_get_cipher")
have_func("ENGINE_cleanup")
+ have_func("ENGINE_load_4758cca")
+ have_func("ENGINE_load_aep")
+ have_func("ENGINE_load_atalla")
+ have_func("ENGINE_load_chil")
+ have_func("ENGINE_load_cswift")
+ have_func("ENGINE_load_nuron")
+ have_func("ENGINE_load_sureware")
+ have_func("ENGINE_load_ubsec")
end
if try_compile(<<SRC)
#include <openssl/opensslv.h>
diff --git a/ext/openssl/lib/net/ftptls.rb b/ext/openssl/lib/net/ftptls.rb
index e82eff72fa..a21c1f6c3c 100644
--- a/ext/openssl/lib/net/ftptls.rb
+++ b/ext/openssl/lib/net/ftptls.rb
@@ -1,5 +1,5 @@
=begin
-= $RCSfile: ftptls.rb,v $ -- SSL/TLS enhancement for Net::HTTP.
+= $RCSfile$ -- SSL/TLS enhancement for Net::HTTP.
= Info
'OpenSSL for Ruby 2' project
@@ -13,7 +13,7 @@
= Requirements
= Version
- $Id: ftptls.rb,v 1.1 2003/07/23 16:11:30 gotoyuzo Exp $
+ $Id$
= Notes
Tested on FreeBSD 5-CURRENT and 4-STABLE
diff --git a/ext/openssl/lib/net/telnets.rb b/ext/openssl/lib/net/telnets.rb
index c869b5da1c..2b69280432 100644
--- a/ext/openssl/lib/net/telnets.rb
+++ b/ext/openssl/lib/net/telnets.rb
@@ -1,5 +1,5 @@
=begin
-= $RCSfile: telnets.rb,v $ -- SSL/TLS enhancement for Net::Telnet.
+= $RCSfile$ -- SSL/TLS enhancement for Net::Telnet.
= Info
'OpenSSL for Ruby 2' project
@@ -11,7 +11,7 @@
(See the file 'LICENCE'.)
= Version
- $Id: telnets.rb,v 1.1.2.1 2004/12/20 03:49:16 gotoyuzo Exp $
+ $Id$
2001/11/06: Contiributed to Ruby/OpenSSL project.
diff --git a/ext/openssl/lib/openssl.rb b/ext/openssl/lib/openssl.rb
index 58fd3887e3..5c27fcb3b5 100644
--- a/ext/openssl/lib/openssl.rb
+++ b/ext/openssl/lib/openssl.rb
@@ -1,5 +1,5 @@
=begin
-= $RCSfile: openssl.rb,v $ -- Loader for all OpenSSL C-space and Ruby-space definitions
+= $RCSfile$ -- Loader for all OpenSSL C-space and Ruby-space definitions
= Info
'OpenSSL for Ruby 2' project
@@ -11,14 +11,16 @@
(See the file 'LICENCE'.)
= Version
- $Id: openssl.rb,v 1.1 2003/07/23 16:11:29 gotoyuzo Exp $
+ $Id$
=end
require 'openssl.so'
require 'openssl/bn'
require 'openssl/cipher'
+require 'openssl/config'
require 'openssl/digest'
-require 'openssl/ssl'
-require 'openssl/x509'
+require 'openssl/pkcs7'
+require 'openssl/ssl-internal'
+require 'openssl/x509-internal'
diff --git a/ext/openssl/lib/openssl/bn.rb b/ext/openssl/lib/openssl/bn.rb
index 4a1595c7ab..624c13715c 100644
--- a/ext/openssl/lib/openssl/bn.rb
+++ b/ext/openssl/lib/openssl/bn.rb
@@ -1,5 +1,5 @@
=begin
-= $RCSfile: bn.rb,v $ -- Ruby-space definitions that completes C-space funcs for BN
+= $RCSfile$ -- Ruby-space definitions that completes C-space funcs for BN
= Info
'OpenSSL for Ruby 2' project
@@ -11,7 +11,7 @@
(See the file 'LICENCE'.)
= Version
- $Id: bn.rb,v 1.1 2003/07/23 16:11:30 gotoyuzo Exp $
+ $Id$
=end
##
@@ -29,7 +29,7 @@ end # OpenSSL
#
class Integer
def to_bn
- OpenSSL::BN::new(self)
+ OpenSSL::BN::new(self.to_s(16), 16)
end
end # Integer
diff --git a/ext/openssl/lib/openssl/buffering.rb b/ext/openssl/lib/openssl/buffering.rb
index 9eeb19d959..c83b92b79e 100644
--- a/ext/openssl/lib/openssl/buffering.rb
+++ b/ext/openssl/lib/openssl/buffering.rb
@@ -1,5 +1,5 @@
=begin
-= $RCSfile: buffering.rb,v $ -- Buffering mix-in module.
+= $RCSfile$ -- Buffering mix-in module.
= Info
'OpenSSL for Ruby 2' project
@@ -11,9 +11,10 @@
(See the file 'LICENCE'.)
= Version
- $Id: buffering.rb,v 1.5.2.4 2005/09/04 22:03:24 gotoyuzo Exp $
+ $Id$
=end
+module OpenSSL
module Buffering
include Enumerable
attr_accessor :sync
@@ -237,3 +238,4 @@ module Buffering
sysclose
end
end
+end
diff --git a/ext/openssl/lib/openssl/cipher.rb b/ext/openssl/lib/openssl/cipher.rb
index 7825e5e9e6..290e9c1d2d 100644
--- a/ext/openssl/lib/openssl/cipher.rb
+++ b/ext/openssl/lib/openssl/cipher.rb
@@ -1,5 +1,5 @@
=begin
-= $RCSfile: cipher.rb,v $ -- Ruby-space predefined Cipher subclasses
+= $RCSfile$ -- Ruby-space predefined Cipher subclasses
= Info
'OpenSSL for Ruby 2' project
@@ -11,7 +11,7 @@
(See the file 'LICENCE'.)
= Version
- $Id: cipher.rb,v 1.1.2.2 2006/06/20 11:18:15 gotoyuzo Exp $
+ $Id$
=end
##
@@ -19,7 +19,7 @@
#require 'openssl'
module OpenSSL
- module Cipher
+ class Cipher
%w(AES CAST5 BF DES IDEA RC2 RC4 RC5).each{|name|
klass = Class.new(Cipher){
define_method(:initialize){|*args|
@@ -41,18 +41,25 @@ module OpenSSL
const_set("AES#{keylen}", klass)
}
- class Cipher
- def random_key
- str = OpenSSL::Random.random_bytes(self.key_len)
- self.key = str
- return str
- end
-
- def random_iv
- str = OpenSSL::Random.random_bytes(self.iv_len)
- self.iv = str
- return str
- end
+ # Generate, set, and return a random key.
+ # You must call cipher.encrypt or cipher.decrypt before calling this method.
+ def random_key
+ str = OpenSSL::Random.random_bytes(self.key_len)
+ self.key = str
+ return str
+ end
+
+ # Generate, set, and return a random iv.
+ # You must call cipher.encrypt or cipher.decrypt before calling this method.
+ def random_iv
+ str = OpenSSL::Random.random_bytes(self.iv_len)
+ self.iv = str
+ return str
+ end
+
+ # This class is only provided for backwards compatibility. Use OpenSSL::Digest in the future.
+ class Cipher < Cipher
+ # add warning
end
end # Cipher
end # OpenSSL
diff --git a/ext/openssl/lib/openssl/config.rb b/ext/openssl/lib/openssl/config.rb
new file mode 100644
index 0000000000..21c98b7b18
--- /dev/null
+++ b/ext/openssl/lib/openssl/config.rb
@@ -0,0 +1,316 @@
+=begin
+= Ruby-space definitions that completes C-space funcs for Config
+
+= Info
+ Copyright (C) 2010 Hiroshi Nakamura <nahi@ruby-lang.org>
+
+= Licence
+ This program is licenced under the same licence as Ruby.
+ (See the file 'LICENCE'.)
+
+=end
+
+##
+# Should we care what if somebody require this file directly?
+#require 'openssl'
+require 'stringio'
+
+module OpenSSL
+ class Config
+ include Enumerable
+
+ class << self
+ def parse(str)
+ c = new()
+ parse_config(StringIO.new(str)).each do |section, hash|
+ c[section] = hash
+ end
+ c
+ end
+
+ alias load new
+
+ def parse_config(io)
+ begin
+ parse_config_lines(io)
+ rescue ConfigError => e
+ e.message.replace("error in line #{io.lineno}: " + e.message)
+ raise
+ end
+ end
+
+ def get_key_string(data, section, key) # :nodoc:
+ if v = data[section] && data[section][key]
+ return v
+ elsif section == 'ENV'
+ if v = ENV[key]
+ return v
+ end
+ end
+ if v = data['default'] && data['default'][key]
+ return v
+ end
+ end
+
+ private
+
+ def parse_config_lines(io)
+ section = 'default'
+ data = {section => {}}
+ while definition = get_definition(io)
+ definition = clear_comments(definition)
+ next if definition.empty?
+ if definition[0] == ?[
+ if /\[([^\]]*)\]/ =~ definition
+ section = $1.strip
+ data[section] ||= {}
+ else
+ raise ConfigError, "missing close square bracket"
+ end
+ else
+ if /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/ =~ definition
+ if $2
+ section = $1
+ key = $2
+ else
+ key = $1
+ end
+ value = unescape_value(data, section, $3)
+ (data[section] ||= {})[key] = value.strip
+ else
+ raise ConfigError, "missing equal sign"
+ end
+ end
+ end
+ data
+ end
+
+ # escape with backslash
+ QUOTE_REGEXP_SQ = /\A([^'\\]*(?:\\.[^'\\]*)*)'/
+ # escape with backslash and doubled dq
+ QUOTE_REGEXP_DQ = /\A([^"\\]*(?:""[^"\\]*|\\.[^"\\]*)*)"/
+ # escaped char map
+ ESCAPE_MAP = {
+ "r" => "\r",
+ "n" => "\n",
+ "b" => "\b",
+ "t" => "\t",
+ }
+
+ def unescape_value(data, section, value)
+ scanned = []
+ while m = value.match(/['"\\$]/)
+ scanned << m.pre_match
+ c = m[0]
+ value = m.post_match
+ case c
+ when "'"
+ if m = value.match(QUOTE_REGEXP_SQ)
+ scanned << m[1].gsub(/\\(.)/, '\\1')
+ value = m.post_match
+ else
+ break
+ end
+ when '"'
+ if m = value.match(QUOTE_REGEXP_DQ)
+ scanned << m[1].gsub(/""/, '').gsub(/\\(.)/, '\\1')
+ value = m.post_match
+ else
+ break
+ end
+ when "\\"
+ c = value.slice!(0, 1)
+ scanned << (ESCAPE_MAP[c] || c)
+ when "$"
+ ref, value = extract_reference(value)
+ refsec = section
+ if ref.index('::')
+ refsec, ref = ref.split('::', 2)
+ end
+ if v = get_key_string(data, refsec, ref)
+ scanned << v
+ else
+ raise ConfigError, "variable has no value"
+ end
+ else
+ raise 'must not reaced'
+ end
+ end
+ scanned << value
+ scanned.join
+ end
+
+ def extract_reference(value)
+ rest = ''
+ if m = value.match(/\(([^)]*)\)|\{([^}]*)\}/)
+ value = m[1] || m[2]
+ rest = m.post_match
+ elsif [?(, ?{].include?(value[0])
+ raise ConfigError, "no close brace"
+ end
+ if m = value.match(/[a-zA-Z0-9_]*(?:::[a-zA-Z0-9_]*)?/)
+ return m[0], m.post_match + rest
+ else
+ raise
+ end
+ end
+
+ def clear_comments(line)
+ # FCOMMENT
+ if m = line.match(/\A([\t\n\f ]*);.*\z/)
+ return m[1]
+ end
+ # COMMENT
+ scanned = []
+ while m = line.match(/[#'"\\]/)
+ scanned << m.pre_match
+ c = m[0]
+ line = m.post_match
+ case c
+ when '#'
+ line = nil
+ break
+ when "'", '"'
+ regexp = (c == "'") ? QUOTE_REGEXP_SQ : QUOTE_REGEXP_DQ
+ scanned << c
+ if m = line.match(regexp)
+ scanned << m[0]
+ line = m.post_match
+ else
+ scanned << line
+ line = nil
+ break
+ end
+ when "\\"
+ scanned << c
+ scanned << line.slice!(0, 1)
+ else
+ raise 'must not reaced'
+ end
+ end
+ scanned << line
+ scanned.join
+ end
+
+ def get_definition(io)
+ if line = get_line(io)
+ while /[^\\]\\\z/ =~ line
+ if extra = get_line(io)
+ line += extra
+ else
+ break
+ end
+ end
+ return line.strip
+ end
+ end
+
+ def get_line(io)
+ if line = io.gets
+ line.gsub(/[\r\n]*/, '')
+ end
+ end
+ end
+
+ def initialize(filename = nil)
+ @data = {}
+ if filename
+ File.open(filename.to_s) do |file|
+ Config.parse_config(file).each do |section, hash|
+ self[section] = hash
+ end
+ end
+ end
+ end
+
+ def get_value(section, key)
+ if section.nil?
+ raise TypeError.new('nil not allowed')
+ end
+ section = 'default' if section.empty?
+ get_key_string(section, key)
+ end
+
+ def value(arg1, arg2 = nil)
+ warn('Config#value is deprecated; use Config#get_value')
+ if arg2.nil?
+ section, key = 'default', arg1
+ else
+ section, key = arg1, arg2
+ end
+ section ||= 'default'
+ section = 'default' if section.empty?
+ get_key_string(section, key)
+ end
+
+ def add_value(section, key, value)
+ check_modify
+ (@data[section] ||= {})[key] = value
+ end
+
+ def [](section)
+ @data[section] || {}
+ end
+
+ def section(name)
+ warn('Config#section is deprecated; use Config#[]')
+ @data[name] || {}
+ end
+
+ def []=(section, pairs)
+ check_modify
+ @data[section] ||= {}
+ pairs.each do |key, value|
+ self.add_value(section, key, value)
+ end
+ end
+
+ def sections
+ @data.keys
+ end
+
+ def to_s
+ ary = []
+ @data.keys.sort.each do |section|
+ ary << "[ #{section} ]\n"
+ @data[section].keys.each do |key|
+ ary << "#{key}=#{@data[section][key]}\n"
+ end
+ ary << "\n"
+ end
+ ary.join
+ end
+
+ def each
+ @data.each do |section, hash|
+ hash.each do |key, value|
+ yield(section, key, value)
+ end
+ end
+ end
+
+ def inspect
+ "#<#{self.class.name} sections=#{sections.inspect}>"
+ end
+
+ protected
+
+ def data
+ @data
+ end
+
+ private
+
+ def initialize_copy(other)
+ @data = other.data.dup
+ end
+
+ def check_modify
+ raise TypeError.new("Insecure: can't modify OpenSSL config") if frozen?
+ end
+
+ def get_key_string(section, key)
+ Config.get_key_string(@data, section, key)
+ end
+ end
+end
diff --git a/ext/openssl/lib/openssl/digest.rb b/ext/openssl/lib/openssl/digest.rb
index 6f2c998ff6..e603c41de4 100644
--- a/ext/openssl/lib/openssl/digest.rb
+++ b/ext/openssl/lib/openssl/digest.rb
@@ -1,5 +1,5 @@
=begin
-= $RCSfile: digest.rb,v $ -- Ruby-space predefined Digest subclasses
+= $RCSfile$ -- Ruby-space predefined Digest subclasses
= Info
'OpenSSL for Ruby 2' project
@@ -11,7 +11,7 @@
(See the file 'LICENCE'.)
= Version
- $Id: digest.rb,v 1.1.2.2 2006/06/20 11:18:15 gotoyuzo Exp $
+ $Id$
=end
##
@@ -19,13 +19,17 @@
#require 'openssl'
module OpenSSL
- module Digest
+ class Digest
alg = %w(DSS DSS1 MD2 MD4 MD5 MDC2 RIPEMD160 SHA SHA1)
if OPENSSL_VERSION_NUMBER > 0x00908000
alg += %w(SHA224 SHA256 SHA384 SHA512)
end
+ def self.digest(name, data)
+ super(data, name)
+ end
+
alg.each{|name|
klass = Class.new(Digest){
define_method(:initialize){|*data|
@@ -36,7 +40,7 @@ module OpenSSL
super(name, data.first)
}
}
- singleton = (class <<klass; self; end)
+ singleton = (class << klass; self; end)
singleton.class_eval{
define_method(:digest){|data| Digest.digest(name, data) }
define_method(:hexdigest){|data| Digest.hexdigest(name, data) }
@@ -44,6 +48,14 @@ module OpenSSL
const_set(name, klass)
}
+ # This class is only provided for backwards compatibility. Use OpenSSL::Digest in the future.
+ class Digest < Digest
+ def initialize(*args)
+ # add warning
+ super(*args)
+ end
+ end
+
end # Digest
end # OpenSSL
diff --git a/ext/openssl/lib/openssl/pkcs7.rb b/ext/openssl/lib/openssl/pkcs7.rb
new file mode 100644
index 0000000000..1f88c1de5e
--- /dev/null
+++ b/ext/openssl/lib/openssl/pkcs7.rb
@@ -0,0 +1,25 @@
+=begin
+= $RCSfile$ -- PKCS7
+
+= Licence
+ This program is licenced under the same licence as Ruby.
+ (See the file 'LICENCE'.)
+
+= Version
+ $Id: digest.rb 12148 2007-04-05 05:59:22Z technorama $
+=end
+
+module OpenSSL
+ class PKCS7
+ # This class is only provided for backwards compatibility. Use OpenSSL::PKCS7 in the future.
+ class PKCS7 < PKCS7
+ def initialize(*args)
+ super(*args)
+
+ warn("Warning: OpenSSL::PKCS7::PKCS7 is deprecated after Ruby 1.9; use OpenSSL::PKCS7 instead")
+ end
+ end
+
+ end # PKCS7
+end # OpenSSL
+
diff --git a/ext/openssl/lib/openssl/ssl-internal.rb b/ext/openssl/lib/openssl/ssl-internal.rb
new file mode 100644
index 0000000000..abf0e8dfe3
--- /dev/null
+++ b/ext/openssl/lib/openssl/ssl-internal.rb
@@ -0,0 +1,179 @@
+=begin
+= $RCSfile$ -- Ruby-space definitions that completes C-space funcs for SSL
+
+= Info
+ 'OpenSSL for Ruby 2' project
+ Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org>
+ All rights reserved.
+
+= Licence
+ This program is licenced under the same licence as Ruby.
+ (See the file 'LICENCE'.)
+
+= Version
+ $Id$
+=end
+
+require "openssl/buffering"
+require "fcntl"
+
+module OpenSSL
+ module SSL
+ class SSLContext
+ DEFAULT_PARAMS = {
+ :ssl_version => "SSLv23",
+ :verify_mode => OpenSSL::SSL::VERIFY_PEER,
+ :ciphers => "ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW",
+ :options => OpenSSL::SSL::OP_ALL,
+ }
+
+ DEFAULT_CERT_STORE = OpenSSL::X509::Store.new
+ DEFAULT_CERT_STORE.set_default_paths
+ if defined?(OpenSSL::X509::V_FLAG_CRL_CHECK_ALL)
+ DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
+ end
+
+ def set_params(params={})
+ params = DEFAULT_PARAMS.merge(params)
+ # ssl_version need to be set at first.
+ self.ssl_version = params.delete(:ssl_version)
+ params.each{|name, value| self.__send__("#{name}=", value) }
+ if self.verify_mode != OpenSSL::SSL::VERIFY_NONE
+ unless self.ca_file or self.ca_path or self.cert_store
+ self.cert_store = DEFAULT_CERT_STORE
+ end
+ end
+ return params
+ end
+ end
+
+ module SocketForwarder
+ def addr
+ to_io.addr
+ end
+
+ def peeraddr
+ to_io.peeraddr
+ end
+
+ def setsockopt(level, optname, optval)
+ to_io.setsockopt(level, optname, optval)
+ end
+
+ def getsockopt(level, optname)
+ to_io.getsockopt(level, optname)
+ end
+
+ def fcntl(*args)
+ to_io.fcntl(*args)
+ end
+
+ def closed?
+ to_io.closed?
+ end
+
+ def do_not_reverse_lookup=(flag)
+ to_io.do_not_reverse_lookup = flag
+ end
+ end
+
+ module Nonblock
+ def initialize(*args)
+ flag = File::NONBLOCK
+ flag |= @io.fcntl(Fcntl::F_GETFL) if defined?(Fcntl::F_GETFL)
+ @io.fcntl(Fcntl::F_SETFL, flag)
+ super
+ end
+ end
+
+ def verify_certificate_identity(cert, hostname)
+ should_verify_common_name = true
+ cert.extensions.each{|ext|
+ next if ext.oid != "subjectAltName"
+ ext.value.split(/,\s+/).each{|general_name|
+ if /\ADNS:(.*)/ =~ general_name
+ should_verify_common_name = false
+ reg = Regexp.escape($1).gsub(/\\\*/, "[^.]+")
+ return true if /\A#{reg}\z/i =~ hostname
+ elsif /\AIP Address:(.*)/ =~ general_name
+ should_verify_common_name = false
+ return true if $1 == hostname
+ end
+ }
+ }
+ if should_verify_common_name
+ cert.subject.to_a.each{|oid, value|
+ if oid == "CN"
+ reg = Regexp.escape(value).gsub(/\\\*/, "[^.]+")
+ return true if /\A#{reg}\z/i =~ hostname
+ end
+ }
+ end
+ return false
+ end
+ module_function :verify_certificate_identity
+
+ class SSLSocket
+ include Buffering
+ include SocketForwarder
+ include Nonblock
+
+ def post_connection_check(hostname)
+ unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname)
+ raise SSLError, "hostname was not match with the server certificate"
+ end
+ return true
+ end
+
+ def session
+ SSL::Session.new(self)
+ rescue SSL::Session::SessionError
+ nil
+ end
+ end
+
+ class SSLServer
+ include SocketForwarder
+ attr_accessor :start_immediately
+
+ def initialize(svr, ctx)
+ @svr = svr
+ @ctx = ctx
+ unless ctx.session_id_context
+ session_id = OpenSSL::Digest::MD5.hexdigest($0)
+ @ctx.session_id_context = session_id
+ end
+ @start_immediately = true
+ end
+
+ def to_io
+ @svr
+ end
+
+ def listen(backlog=5)
+ @svr.listen(backlog)
+ end
+
+ def shutdown(how=Socket::SHUT_RDWR)
+ @svr.shutdown(how)
+ end
+
+ def accept
+ sock = @svr.accept
+ begin
+ ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
+ ssl.sync_close = true
+ ssl.accept if @start_immediately
+ ssl
+ rescue SSLError => ex
+ sock.close
+ raise ex
+ end
+ end
+
+ def close
+ @svr.close
+ end
+ end
+ end
+end
diff --git a/ext/openssl/lib/openssl/ssl.rb b/ext/openssl/lib/openssl/ssl.rb
index d1007ce6d0..3f17f5aa29 100644
--- a/ext/openssl/lib/openssl/ssl.rb
+++ b/ext/openssl/lib/openssl/ssl.rb
@@ -1,135 +1 @@
-=begin
-= $RCSfile: ssl.rb,v $ -- Ruby-space definitions that completes C-space funcs for SSL
-
-= Info
- 'OpenSSL for Ruby 2' project
- Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org>
- All rights reserved.
-
-= Licence
- This program is licenced under the same licence as Ruby.
- (See the file 'LICENCE'.)
-
-= Version
- $Id: ssl.rb,v 1.5.2.6 2006/05/23 18:14:05 gotoyuzo Exp $
-=end
-
-require "openssl"
-require "openssl/buffering"
-require "fcntl"
-
-module OpenSSL
- module SSL
- module SocketForwarder
- def addr
- to_io.addr
- end
-
- def peeraddr
- to_io.peeraddr
- end
-
- def setsockopt(level, optname, optval)
- to_io.setsockopt(level, optname, optval)
- end
-
- def getsockopt(level, optname)
- to_io.getsockopt(level, optname)
- end
-
- def fcntl(*args)
- to_io.fcntl(*args)
- end
-
- def closed?
- to_io.closed?
- end
-
- def do_not_reverse_lookup=(flag)
- to_io.do_not_reverse_lookup = flag
- end
- end
-
- module Nonblock
- def initialize(*args)
- flag = File::NONBLOCK
- flag |= @io.fcntl(Fcntl::F_GETFL) if defined?(Fcntl::F_GETFL)
- @io.fcntl(Fcntl::F_SETFL, flag)
- super
- end
- end
-
- class SSLSocket
- include Buffering
- include SocketForwarder
- include Nonblock
-
- def post_connection_check(hostname)
- check_common_name = true
- cert = peer_cert
- cert.extensions.each{|ext|
- next if ext.oid != "subjectAltName"
- ext.value.split(/,\s+/).each{|general_name|
- if /\ADNS:(.*)/ =~ general_name
- check_common_name = false
- reg = Regexp.escape($1).gsub(/\\\*/, "[^.]+")
- return true if /\A#{reg}\z/i =~ hostname
- elsif /\AIP Address:(.*)/ =~ general_name
- check_common_name = false
- return true if $1 == hostname
- end
- }
- }
- if check_common_name
- cert.subject.to_a.each{|oid, value|
- if oid == "CN"
- reg = Regexp.escape(value).gsub(/\\\*/, "[^.]+")
- return true if /\A#{reg}\z/i =~ hostname
- end
- }
- end
- raise SSLError, "hostname was not match with the server certificate"
- end
- end
-
- class SSLServer
- include SocketForwarder
- attr_accessor :start_immediately
-
- def initialize(svr, ctx)
- @svr = svr
- @ctx = ctx
- unless ctx.session_id_context
- session_id = OpenSSL::Digest::MD5.hexdigest($0)
- @ctx.session_id_context = session_id
- end
- @start_immediately = true
- end
-
- def to_io
- @svr
- end
-
- def listen(backlog=5)
- @svr.listen(backlog)
- end
-
- def accept
- sock = @svr.accept
- begin
- ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
- ssl.sync_close = true
- ssl.accept if @start_immediately
- ssl
- rescue SSLError => ex
- sock.close
- raise ex
- end
- end
-
- def close
- @svr.close
- end
- end
- end
-end
+require 'openssl'
diff --git a/ext/openssl/lib/openssl/x509-internal.rb b/ext/openssl/lib/openssl/x509-internal.rb
new file mode 100644
index 0000000000..6aff4ca10d
--- /dev/null
+++ b/ext/openssl/lib/openssl/x509-internal.rb
@@ -0,0 +1,153 @@
+=begin
+= $RCSfile$ -- Ruby-space definitions that completes C-space funcs for X509 and subclasses
+
+= Info
+ 'OpenSSL for Ruby 2' project
+ Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ All rights reserved.
+
+= Licence
+ This program is licenced under the same licence as Ruby.
+ (See the file 'LICENCE'.)
+
+= Version
+ $Id$
+=end
+
+module OpenSSL
+ module X509
+ class ExtensionFactory
+ def create_extension(*arg)
+ if arg.size > 1
+ create_ext(*arg)
+ else
+ send("create_ext_from_"+arg[0].class.name.downcase, arg[0])
+ end
+ end
+
+ def create_ext_from_array(ary)
+ raise ExtensionError, "unexpected array form" if ary.size > 3
+ create_ext(ary[0], ary[1], ary[2])
+ end
+
+ def create_ext_from_string(str) # "oid = critical, value"
+ oid, value = str.split(/=/, 2)
+ oid.strip!
+ value.strip!
+ create_ext(oid, value)
+ end
+
+ def create_ext_from_hash(hash)
+ create_ext(hash["oid"], hash["value"], hash["critical"])
+ end
+ end
+
+ class Extension
+ def to_s # "oid = critical, value"
+ str = self.oid
+ str << " = "
+ str << "critical, " if self.critical?
+ str << self.value.gsub(/\n/, ", ")
+ end
+
+ def to_h # {"oid"=>sn|ln, "value"=>value, "critical"=>true|false}
+ {"oid"=>self.oid,"value"=>self.value,"critical"=>self.critical?}
+ end
+
+ def to_a
+ [ self.oid, self.value, self.critical? ]
+ end
+ end
+
+ class Name
+ module RFC2253DN
+ Special = ',=+<>#;'
+ HexChar = /[0-9a-fA-F]/
+ HexPair = /#{HexChar}#{HexChar}/
+ HexString = /#{HexPair}+/
+ Pair = /\\(?:[#{Special}]|\\|"|#{HexPair})/
+ StringChar = /[^#{Special}\\"]/
+ QuoteChar = /[^\\"]/
+ AttributeType = /[a-zA-Z][0-9a-zA-Z]*|[0-9]+(?:\.[0-9]+)*/
+ AttributeValue = /
+ (?!["#])((?:#{StringChar}|#{Pair})*)|
+ \#(#{HexString})|
+ "((?:#{QuoteChar}|#{Pair})*)"
+ /x
+ TypeAndValue = /\A(#{AttributeType})=#{AttributeValue}/
+
+ module_function
+
+ def expand_pair(str)
+ return nil unless str
+ return str.gsub(Pair){
+ pair = $&
+ case pair.size
+ when 2 then pair[1,1]
+ when 3 then Integer("0x#{pair[1,2]}").chr
+ else raise OpenSSL::X509::NameError, "invalid pair: #{str}"
+ end
+ }
+ end
+
+ def expand_hexstring(str)
+ return nil unless str
+ der = str.gsub(HexPair){$&.to_i(16).chr }
+ a1 = OpenSSL::ASN1.decode(der)
+ return a1.value, a1.tag
+ end
+
+ def expand_value(str1, str2, str3)
+ value = expand_pair(str1)
+ value, tag = expand_hexstring(str2) unless value
+ value = expand_pair(str3) unless value
+ return value, tag
+ end
+
+ def scan(dn)
+ str = dn
+ ary = []
+ while true
+ if md = TypeAndValue.match(str)
+ matched = md.to_s
+ remain = md.post_match
+ type = md[1]
+ value, tag = expand_value(md[2], md[3], md[4]) rescue nil
+ if value
+ type_and_value = [type, value]
+ type_and_value.push(tag) if tag
+ ary.unshift(type_and_value)
+ if remain.length > 2 && remain[0] == ?,
+ str = remain[1..-1]
+ next
+ elsif remain.length > 2 && remain[0] == ?+
+ raise OpenSSL::X509::NameError,
+ "multi-valued RDN is not supported: #{dn}"
+ elsif remain.empty?
+ break
+ end
+ end
+ end
+ msg_dn = dn[0, dn.length - str.length] + " =>" + str
+ raise OpenSSL::X509::NameError, "malformed RDN: #{msg_dn}"
+ end
+ return ary
+ end
+ end
+
+ class <<self
+ def parse_rfc2253(str, template=OBJECT_TYPE_TEMPLATE)
+ ary = OpenSSL::X509::Name::RFC2253DN.scan(str)
+ self.new(ary, template)
+ end
+
+ def parse_openssl(str, template=OBJECT_TYPE_TEMPLATE)
+ ary = str.scan(/\s*([^\/,]+)\s*/).collect{|i| i[0].split("=", 2) }
+ self.new(ary, template)
+ end
+
+ alias parse parse_openssl
+ end
+ end
+ end
+end
diff --git a/ext/openssl/lib/openssl/x509.rb b/ext/openssl/lib/openssl/x509.rb
index 2ad3f8e96e..3f17f5aa29 100644
--- a/ext/openssl/lib/openssl/x509.rb
+++ b/ext/openssl/lib/openssl/x509.rb
@@ -1,154 +1 @@
-=begin
-= $RCSfile: x509.rb,v $ -- Ruby-space definitions that completes C-space funcs for X509 and subclasses
-
-= Info
- 'OpenSSL for Ruby 2' project
- Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
- All rights reserved.
-
-= Licence
- This program is licenced under the same licence as Ruby.
- (See the file 'LICENCE'.)
-
-= Version
- $Id: x509.rb,v 1.4.2.2 2004/12/19 08:28:33 gotoyuzo Exp $
-=end
-
-require "openssl"
-
-module OpenSSL
- module X509
- class ExtensionFactory
- def create_extension(*arg)
- if arg.size > 1
- create_ext(*arg)
- else
- send("create_ext_from_"+arg[0].class.name.downcase, arg[0])
- end
- end
-
- def create_ext_from_array(ary)
- raise ExtensionError, "unexpected array form" if ary.size > 3
- create_ext(ary[0], ary[1], ary[2])
- end
-
- def create_ext_from_string(str) # "oid = critical, value"
- oid, value = str.split(/=/, 2)
- oid.strip!
- value.strip!
- create_ext(oid, value)
- end
-
- def create_ext_from_hash(hash)
- create_ext(hash["oid"], hash["value"], hash["critical"])
- end
- end
-
- class Extension
- def to_s # "oid = critical, value"
- str = self.oid
- str << " = "
- str << "critical, " if self.critical?
- str << self.value.gsub(/\n/, ", ")
- end
-
- def to_h # {"oid"=>sn|ln, "value"=>value, "critical"=>true|false}
- {"oid"=>self.oid,"value"=>self.value,"critical"=>self.critical?}
- end
-
- def to_a
- [ self.oid, self.value, self.critical? ]
- end
- end
-
- class Name
- module RFC2253DN
- Special = ',=+<>#;'
- HexChar = /[0-9a-fA-F]/
- HexPair = /#{HexChar}#{HexChar}/
- HexString = /#{HexPair}+/
- Pair = /\\(?:[#{Special}]|\\|"|#{HexPair})/
- StringChar = /[^#{Special}\\"]/
- QuoteChar = /[^\\"]/
- AttributeType = /[a-zA-Z][0-9a-zA-Z]*|[0-9]+(?:\.[0-9]+)*/
- AttributeValue = /
- (?!["#])((?:#{StringChar}|#{Pair})*)|
- \#(#{HexString})|
- "((?:#{QuoteChar}|#{Pair})*)"
- /x
- TypeAndValue = /\A(#{AttributeType})=#{AttributeValue}/
-
- module_function
-
- def expand_pair(str)
- return nil unless str
- return str.gsub(Pair){|pair|
- case pair.size
- when 2 then pair[1,1]
- when 3 then Integer("0x#{pair[1,2]}").chr
- else raise OpenSSL::X509::NameError, "invalid pair: #{str}"
- end
- }
- end
-
- def expand_hexstring(str)
- return nil unless str
- der = str.gsub(HexPair){|hex| Integer("0x#{hex}").chr }
- a1 = OpenSSL::ASN1.decode(der)
- return a1.value, a1.tag
- end
-
- def expand_value(str1, str2, str3)
- value = expand_pair(str1)
- value, tag = expand_hexstring(str2) unless value
- value = expand_pair(str3) unless value
- return value, tag
- end
-
- def scan(dn)
- str = dn
- ary = []
- while true
- if md = TypeAndValue.match(str)
- matched = md.to_s
- remain = md.post_match
- type = md[1]
- value, tag = expand_value(md[2], md[3], md[4]) rescue nil
- if value
- type_and_value = [type, value]
- type_and_value.push(tag) if tag
- ary.unshift(type_and_value)
- if remain.length > 2 && remain[0] == ?,
- str = remain[1..-1]
- next
- elsif remain.length > 2 && remain[0] == ?+
- raise OpenSSL::X509::NameError,
- "multi-valued RDN is not supported: #{dn}"
- elsif remain.empty?
- break
- end
- end
- end
- msg_dn = dn[0, dn.length - str.length] + " =>" + str
- raise OpenSSL::X509::NameError, "malformed RDN: #{msg_dn}"
- end
- return ary
- end
- end
-
- class <<self
- def parse_rfc2253(str, template=OBJECT_TYPE_TEMPLATE)
- ary = OpenSSL::X509::Name::RFC2253DN.scan(str)
- self.new(ary, template)
- end
-
- def parse_openssl(str, template=OBJECT_TYPE_TEMPLATE)
- ary = str.scan(/\s*([^\/,]+)\s*/).collect{|i| i[0].split("=", 2) }
- self.new(ary, template)
- end
-
- alias parse parse_openssl
- end
- end
- end
-end
+require 'openssl'
diff --git a/ext/openssl/openssl_missing.c b/ext/openssl/openssl_missing.c
index 2c005f41e5..724f36b8ae 100644
--- a/ext/openssl/openssl_missing.c
+++ b/ext/openssl/openssl_missing.c
@@ -1,5 +1,5 @@
/*
- * $Id: openssl_missing.c,v 1.2.2.4 2006/06/02 10:02:56 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -22,17 +22,15 @@
#include "openssl_missing.h"
#if !defined(HAVE_HMAC_CTX_COPY)
-int
+void
HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in)
{
- if (!out || !in) return 0;
+ if (!out || !in) return;
memcpy(out, in, sizeof(HMAC_CTX));
- if (!EVP_MD_CTX_copy(&out->md_ctx, &in->md_ctx)
- || !EVP_MD_CTX_copy(&out->i_ctx, &in->i_ctx)
- || !EVP_MD_CTX_copy(&out->o_ctx, &in->o_ctx))
- return 0;
- return 1;
+ EVP_MD_CTX_copy(&out->md_ctx, &in->md_ctx);
+ EVP_MD_CTX_copy(&out->i_ctx, &in->i_ctx);
+ EVP_MD_CTX_copy(&out->o_ctx, &in->o_ctx);
}
#endif /* HAVE_HMAC_CTX_COPY */
#endif /* NO_HMAC */
diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h
index 8d580f5ee8..db1630530e 100644
--- a/ext/openssl/openssl_missing.h
+++ b/ext/openssl/openssl_missing.h
@@ -1,5 +1,5 @@
/*
- * $Id: openssl_missing.h,v 1.2.2.2 2005/04/15 19:16:18 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -15,6 +15,13 @@
extern "C" {
#endif
+#ifndef TYPEDEF_D2I_OF
+typedef char *d2i_of_void();
+#endif
+#ifndef TYPEDEF_I2D_OF
+typedef int i2d_of_void();
+#endif
+
/*
* These functions are not included in headers of OPENSSL <= 0.9.6b
*/
@@ -26,44 +33,63 @@ extern "C" {
#if !defined(PEM_write_bio_DSAPublicKey)
# define PEM_write_bio_DSAPublicKey(bp,x) \
- PEM_ASN1_write_bio((int (*)())i2d_DSAPublicKey,\
+ PEM_ASN1_write_bio((i2d_of_void *)i2d_DSAPublicKey,\
PEM_STRING_DSA_PUBLIC,\
bp,(char *)x, NULL, NULL, 0, NULL, NULL)
#endif
#if !defined(DSAPrivateKey_dup)
-# define DSAPrivateKey_dup(dsa) (DSA *)ASN1_dup((int (*)())i2d_DSAPrivateKey, \
+# define DSAPrivateKey_dup(dsa) (DSA *)ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey, \
(char *(*)())d2i_DSAPrivateKey,(char *)dsa)
#endif
#if !defined(DSAPublicKey_dup)
-# define DSAPublicKey_dup(dsa) (DSA *)ASN1_dup((int (*)())i2d_DSAPublicKey, \
+# define DSAPublicKey_dup(dsa) (DSA *)ASN1_dup((i2d_of_void *)i2d_DSAPublicKey, \
(char *(*)())d2i_DSAPublicKey,(char *)dsa)
#endif
#if !defined(X509_REVOKED_dup)
-# define X509_REVOKED_dup(rev) (X509_REVOKED *)ASN1_dup((int (*)())i2d_X509_REVOKED, \
+# define X509_REVOKED_dup(rev) (X509_REVOKED *)ASN1_dup((i2d_of_void *)i2d_X509_REVOKED, \
(char *(*)())d2i_X509_REVOKED, (char *)rev)
#endif
#if !defined(PKCS7_SIGNER_INFO_dup)
-# define PKCS7_SIGNER_INFO_dup(si) (PKCS7_SIGNER_INFO *)ASN1_dup((int (*)())i2d_PKCS7_SIGNER_INFO, \
+# define PKCS7_SIGNER_INFO_dup(si) (PKCS7_SIGNER_INFO *)ASN1_dup((i2d_of_void *)i2d_PKCS7_SIGNER_INFO, \
(char *(*)())d2i_PKCS7_SIGNER_INFO, (char *)si)
#endif
#if !defined(PKCS7_RECIP_INFO_dup)
-# define PKCS7_RECIP_INFO_dup(ri) (PKCS7_RECIP_INFO *)ASN1_dup((int (*)())i2d_PKCS7_RECIP_INFO, \
+# define PKCS7_RECIP_INFO_dup(ri) (PKCS7_RECIP_INFO *)ASN1_dup((i2d_of_void *)i2d_PKCS7_RECIP_INFO, \
(char *(*)())d2i_PKCS7_RECIP_INFO, (char *)ri)
#endif
+#if !defined(HAVE_EVP_MD_CTX_INIT)
void HMAC_CTX_init(HMAC_CTX *ctx);
-int HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in);
+#endif
+
+#if !defined(HAVE_HMAC_CTX_COPY)
+void HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in);
+#endif
+
+#if !defined(HAVE_HMAC_CTX_CLEANUP)
void HMAC_CTX_cleanup(HMAC_CTX *ctx);
+#endif
+#if !defined(HAVE_EVP_MD_CTX_CREATE)
EVP_MD_CTX *EVP_MD_CTX_create(void);
+#endif
+
+#if !defined(HAVE_EVP_MD_CTX_INIT)
void EVP_MD_CTX_init(EVP_MD_CTX *ctx);
+#endif
+
+#if !defined(HAVE_EVP_MD_CTX_CLEANUP)
int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx);
+#endif
+
+#if !defined(HAVE_EVP_MD_CTX_DESTROY)
void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx);
+#endif
#if !defined(HAVE_EVP_CIPHER_CTX_COPY)
int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, EVP_CIPHER_CTX *in);
@@ -107,19 +133,54 @@ int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, EVP_CIPHER_CTX *in);
#define OPENSSL_cleanse(p, l) memset(p, 0, l)
#endif
+#if !defined(HAVE_X509_STORE_SET_EX_DATA)
void *X509_STORE_get_ex_data(X509_STORE *str, int idx);
int X509_STORE_set_ex_data(X509_STORE *str, int idx, void *data);
+#endif
+
+#if !defined(HAVE_X509_CRL_SET_VERSION)
int X509_CRL_set_version(X509_CRL *x, long version);
+#endif
+
+#if !defined(HAVE_X509_CRL_SET_ISSUER_NAME)
int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name);
+#endif
+
+#if !defined(HAVE_X509_CRL_SORT)
int X509_CRL_sort(X509_CRL *c);
+#endif
+
+#if !defined(HAVE_X509_CRL_ADD0_REVOKED)
int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev);
+#endif
+
+#if !defined(HAVE_BN_MOD_SQR)
int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx);
+#endif
+
+#if !defined(HAVE_BN_MOD_ADD)
int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx);
+#endif
+
+#if !defined(HAVE_BN_MOD_SUB)
int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx);
+#endif
+
+#if !defined(HAVE_BN_RAND_RANGE)
int BN_rand_range(BIGNUM *r, BIGNUM *range);
+#endif
+
+#if !defined(HAVE_BN_PSEUDO_RAND_RANGE)
int BN_pseudo_rand_range(BIGNUM *r, BIGNUM *range);
+#endif
+
+#if !defined(HAVE_CONF_GET1_DEFAULT_CONFIG_FILE)
char *CONF_get1_default_config_file(void);
+#endif
+
+#if !defined(HAVE_PEM_DEF_CALLBACK)
int PEM_def_callback(char *buf, int num, int w, void *key);
+#endif
#if defined(__cplusplus)
}
diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c
index 01c5ca2a04..7aa2c0d449 100644
--- a/ext/openssl/ossl.c
+++ b/ext/openssl/ossl.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl.c,v 1.11.2.6 2005/11/01 01:52:13 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -59,7 +59,7 @@ ossl_x509_ary2sk0(VALUE ary)
sk = sk_X509_new_null();
if (!sk) ossl_raise(eOSSLError, NULL);
- for (i = 0; i < RARRAY(ary)->len; i++) {
+ for (i = 0; i < RARRAY_LEN(ary); i++) {
val = rb_ary_entry(ary, i);
if (!rb_obj_is_kind_of(val, cX509Cert)) {
sk_X509_pop_free(sk, X509_free);
@@ -92,7 +92,7 @@ ossl_x509_ary2sk(VALUE ary)
#define OSSL_IMPL_SK2ARY(name, type) \
VALUE \
-ossl_##name##_sk2ary(STACK *sk) \
+ossl_##name##_sk2ary(STACK_OF(type) *sk) \
{ \
type *t; \
int i, num; \
@@ -102,7 +102,7 @@ ossl_##name##_sk2ary(STACK *sk) \
OSSL_Debug("empty sk!"); \
return Qnil; \
} \
- num = sk_num(sk); \
+ num = sk_##type##_num(sk); \
if (num < 0) { \
OSSL_Debug("items in sk < -1???"); \
return rb_ary_new(); \
@@ -110,7 +110,7 @@ ossl_##name##_sk2ary(STACK *sk) \
ary = rb_ary_new2(num); \
\
for (i=0; i<num; i++) { \
- t = (type *)sk_value(sk, i); \
+ t = sk_##type##_value(sk, i); \
rb_ary_push(ary, ossl_##name##_new(t)); \
} \
return ary; \
@@ -131,7 +131,7 @@ ossl_buf2str(char *buf, int len)
int status = 0;
str = rb_protect((VALUE(*)_((VALUE)))ossl_str_new, len, &status);
- if(!NIL_P(str)) memcpy(RSTRING(str)->ptr, buf, len);
+ if(!NIL_P(str)) memcpy(RSTRING_PTR(str), buf, len);
OPENSSL_free(buf);
if(status) rb_jump_tag(status);
@@ -170,7 +170,7 @@ ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd)
rflag = flag ? Qtrue : Qfalse;
pass = rb_protect(ossl_pem_passwd_cb0, rflag, &status);
if (status) return -1; /* exception was raised. */
- len = RSTRING(pass)->len;
+ len = RSTRING_LEN(pass);
if (len < 4) { /* 4 is OpenSSL hardcoded limit */
rb_warning("password must be longer than 4 bytes");
continue;
@@ -179,7 +179,7 @@ ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd)
rb_warning("password must be shorter then %d bytes", max_len-1);
continue;
}
- memcpy(buf, RSTRING(pass)->ptr, len);
+ memcpy(buf, RSTRING_PTR(pass), len);
break;
}
return len;
@@ -272,10 +272,9 @@ ossl_to_der_if_possible(VALUE obj)
/*
* Errors
*/
-void
-ossl_raise(VALUE exc, const char *fmt, ...)
+static VALUE
+ossl_make_error(VALUE exc, const char *fmt, va_list args)
{
- va_list args;
char buf[BUFSIZ];
const char *msg;
long e;
@@ -287,17 +286,14 @@ ossl_raise(VALUE exc, const char *fmt, ...)
e = ERR_peek_error();
#endif
if (fmt) {
- va_start(args, fmt);
len = vsnprintf(buf, BUFSIZ, fmt, args);
- va_end(args);
}
if (len < BUFSIZ && e) {
if (dOSSL == Qtrue) /* FULL INFO */
msg = ERR_error_string(e, NULL);
else
msg = ERR_reason_error_string(e);
- fmt = len ? ": %s" : "%s";
- len += snprintf(buf+len, BUFSIZ-len, fmt, msg);
+ len += snprintf(buf+len, BUFSIZ-len, "%s%s", (len ? ": " : ""), msg);
}
if (dOSSL == Qtrue){ /* show all errors on the stack */
while ((e = ERR_get_error()) != 0){
@@ -307,10 +303,40 @@ ossl_raise(VALUE exc, const char *fmt, ...)
ERR_clear_error();
if(len > BUFSIZ) len = strlen(buf);
- rb_exc_raise(rb_exc_new(exc, buf, len));
+ return rb_exc_new(exc, buf, len);
+}
+
+void
+ossl_raise(VALUE exc, const char *fmt, ...)
+{
+ va_list args;
+ VALUE err;
+ va_start(args, fmt);
+ err = ossl_make_error(exc, fmt, args);
+ va_end(args);
+ rb_exc_raise(err);
}
VALUE
+ossl_exc_new(VALUE exc, const char *fmt, ...)
+{
+ va_list args;
+ VALUE err;
+ va_start(args, fmt);
+ err = ossl_make_error(exc, fmt, args);
+ va_end(args);
+ return err;
+}
+
+/*
+ * call-seq:
+ * OpenSSL.errors -> [String...]
+ *
+ * See any remaining errors held in queue.
+ *
+ * Any errors you see here are probably due to a bug in ruby's OpenSSL implementation.
+ */
+VALUE
ossl_get_errors()
{
VALUE ary;
@@ -345,12 +371,23 @@ ossl_debug(const char *fmt, ...)
}
#endif
+/*
+ * call-seq:
+ * OpenSSL.debug -> true | false
+ */
static VALUE
ossl_debug_get(VALUE self)
{
return dOSSL;
}
+/*
+ * call-seq:
+ * OpenSSL.debug = boolean -> boolean
+ *
+ * Turns on or off CRYPTO_MEM_CHECK.
+ * Also shows some debugging message on stderr.
+ */
static VALUE
ossl_debug_set(VALUE self, VALUE val)
{
@@ -427,8 +464,8 @@ Init_openssl()
/*
* Verify callback Proc index for ext-data
*/
- ossl_verify_cb_idx =
- X509_STORE_CTX_get_ex_new_index(0, "ossl_verify_cb_idx", 0, 0, 0);
+ if ((ossl_verify_cb_idx = X509_STORE_CTX_get_ex_new_index(0, "ossl_verify_cb_idx", 0, 0, 0)) < 0)
+ ossl_raise(eOSSLError, "X509_STORE_CTX_get_ex_new_index");
/*
* Init debug core
@@ -454,6 +491,7 @@ Init_openssl()
Init_ossl_ns_spki();
Init_ossl_pkcs12();
Init_ossl_pkcs7();
+ Init_ossl_pkcs5();
Init_ossl_pkey();
Init_ossl_rand();
Init_ossl_ssl();
diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h
index 336b468eb2..9944a862e4 100644
--- a/ext/openssl/ossl.h
+++ b/ext/openssl/ossl.h
@@ -1,5 +1,5 @@
/*
- * $Id: ossl.h,v 1.14.2.4.2.1 2006/12/25 11:16:49 shyouhei Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -17,11 +17,19 @@
extern "C" {
#endif
+#if 0
+ mOSSL = rb_define_module("OpenSSL");
+ mX509 = rb_define_module_under(mOSSL, "X509");
+#endif
+
/*
- *_FILE_OFFSET_BITS needs to be defined before some system headers on
- * Solaris.
- */
-#include "config.h"
+* OpenSSL has defined RFILE and Ruby has defined RFILE - so undef it!
+*/
+#if defined(RFILE) /*&& !defined(OSSL_DEBUG)*/
+# undef RFILE
+#endif
+#include <ruby.h>
+#include <rubyio.h>
/*
* Check the OpenSSL version
@@ -37,8 +45,12 @@ extern "C" {
#endif
#if defined(_WIN32)
-# define OpenFile WINAPI_OpenFile
# define OSSL_NO_CONF_API 1
+# ifdef USE_WINSOCK2
+# include <winsock2.h>
+# else
+# include <winsock.h>
+# endif
#endif
#include <errno.h>
#include <openssl/err.h>
@@ -61,18 +73,6 @@ extern "C" {
# define OSSL_OCSP_ENABLED
# include <openssl/ocsp.h>
#endif
-#if defined(_WIN32)
-# undef OpenFile
-#endif
-
-/*
- * OpenSSL has defined RFILE and Ruby has defined RFILE - so undef it!
- */
-#if defined(RFILE) /*&& !defined(OSSL_DEBUG)*/
-# undef RFILE
-#endif
-#include <ruby.h>
-#include <rubyio.h>
/*
* Common Module
@@ -108,6 +108,13 @@ extern VALUE eOSSLError;
} while (0)
/*
+ * Compatibility
+ */
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+#define STACK _STACK
+#endif
+
+/*
* String to HEXString conversion
*/
int string2hex(char *, int, char **, int *);
@@ -123,11 +130,10 @@ VALUE ossl_x509crl_sk2ary(STACK_OF(X509_CRL) *crl);
VALUE ossl_buf2str(char *buf, int len);
#define ossl_str_adjust(str, p) \
do{\
- int len = RSTRING(str)->len;\
- int newlen = (p) - (unsigned char*)RSTRING(str)->ptr;\
+ int len = RSTRING_LEN(str);\
+ int newlen = (p) - (unsigned char*)RSTRING_PTR(str);\
assert(newlen <= len);\
- RSTRING(str)->len = newlen;\
- RSTRING(str)->ptr[newlen] = 0;\
+ rb_str_set_len(str, newlen);\
}while(0)
/*
@@ -140,6 +146,7 @@ int ossl_pem_passwd_cb(char *, int, int, void *);
*/
#define OSSL_ErrMsg() ERR_reason_error_string(ERR_get_error())
NORETURN(void ossl_raise(VALUE, const char *, ...));
+VALUE ossl_exc_new(VALUE, const char *, ...);
/*
* Verify callback
@@ -168,10 +175,10 @@ VALUE ossl_to_der_if_possible(VALUE);
extern VALUE dOSSL;
#if defined(HAVE_VA_ARGS_MACRO)
-#define OSSL_Debug(fmt, ...) do { \
+#define OSSL_Debug(...) do { \
if (dOSSL == Qtrue) { \
fprintf(stderr, "OSSL_DEBUG: "); \
- fprintf(stderr, fmt, ##__VA_ARGS__); \
+ fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, " [%s:%d]\n", __FILE__, __LINE__); \
} \
} while (0)
diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c
index 6bc5b88e8f..92f6bf77f5 100644
--- a/ext/openssl/ossl_asn1.c
+++ b/ext/openssl/ossl_asn1.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_asn1.c,v 1.5.2.9 2006/04/29 13:52:15 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' team members
* Copyright (C) 2003
* All rights reserved.
@@ -196,7 +196,11 @@ static ID sUNIVERSAL, sAPPLICATION, sCONTEXT_SPECIFIC, sPRIVATE;
static ASN1_BOOLEAN
obj_to_asn1bool(VALUE obj)
{
+#if OPENSSL_VERSION_NUMBER < 0x00907000L
return RTEST(obj) ? 0xff : 0x100;
+#else
+ return RTEST(obj) ? 0xff : 0x0;
+#endif
}
static ASN1_INTEGER*
@@ -214,7 +218,7 @@ obj_to_asn1bstr(VALUE obj, long unused_bits)
StringValue(obj);
if(!(bstr = ASN1_BIT_STRING_new()))
ossl_raise(eASN1Error, NULL);
- ASN1_BIT_STRING_set(bstr, RSTRING(obj)->ptr, RSTRING(obj)->len);
+ ASN1_BIT_STRING_set(bstr, RSTRING_PTR(obj), RSTRING_LEN(obj));
bstr->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); /* clear */
bstr->flags |= ASN1_STRING_FLAG_BITS_LEFT|(unused_bits&0x07);
@@ -229,7 +233,7 @@ obj_to_asn1str(VALUE obj)
StringValue(obj);
if(!(str = ASN1_STRING_new()))
ossl_raise(eASN1Error, NULL);
- ASN1_STRING_set(str, RSTRING(obj)->ptr, RSTRING(obj)->len);
+ ASN1_STRING_set(str, RSTRING_PTR(obj), RSTRING_LEN(obj));
return str;
}
@@ -253,8 +257,8 @@ obj_to_asn1obj(VALUE obj)
ASN1_OBJECT *a1obj;
StringValue(obj);
- a1obj = OBJ_txt2obj(RSTRING(obj)->ptr, 0);
- if(!a1obj) a1obj = OBJ_txt2obj(RSTRING(obj)->ptr, 1);
+ a1obj = OBJ_txt2obj(RSTRING_PTR(obj), 0);
+ if(!a1obj) a1obj = OBJ_txt2obj(RSTRING_PTR(obj), 1);
if(!a1obj) ossl_raise(eASN1Error, "invalid OBJECT ID");
return a1obj;
@@ -295,7 +299,7 @@ obj_to_asn1derstr(VALUE obj)
str = ossl_to_der(obj);
if(!(a1str = ASN1_STRING_new()))
ossl_raise(eASN1Error, NULL);
- ASN1_STRING_set(a1str, RSTRING(str)->ptr, RSTRING(str)->len);
+ ASN1_STRING_set(a1str, RSTRING_PTR(str), RSTRING_LEN(str));
return a1str;
}
@@ -306,14 +310,14 @@ obj_to_asn1derstr(VALUE obj)
static VALUE
decode_bool(unsigned char* der, int length)
{
- int bool;
+ int val;
unsigned char *p;
p = der;
- if((bool = d2i_ASN1_BOOLEAN(NULL, &p, length)) < 0)
+ if((val = d2i_ASN1_BOOLEAN(NULL, &p, length)) < 0)
ossl_raise(eASN1Error, NULL);
- return bool ? Qtrue : Qfalse;
+ return val ? Qtrue : Qfalse;
}
static VALUE
@@ -339,7 +343,7 @@ static VALUE
decode_bstr(unsigned char* der, int length, long *unused_bits)
{
ASN1_BIT_STRING *bstr;
- unsigned char *p, *buf;
+ const unsigned char *p;
long len;
VALUE ret;
@@ -347,16 +351,11 @@ decode_bstr(unsigned char* der, int length, long *unused_bits)
if(!(bstr = d2i_ASN1_BIT_STRING(NULL, &p, length)))
ossl_raise(eASN1Error, NULL);
len = bstr->length;
- if(!(buf = OPENSSL_malloc(len))){
- ASN1_BIT_STRING_free(bstr);
- ossl_raise(eASN1Error, NULL);
- }
*unused_bits = 0;
if(bstr->flags & ASN1_STRING_FLAG_BITS_LEFT)
*unused_bits = bstr->flags & 0x07;
- memcpy(buf, bstr->data, len);
+ ret = rb_str_new((const char *)bstr->data, len);
ASN1_BIT_STRING_free(bstr);
- ret = ossl_buf2str(buf, len);
return ret;
}
@@ -445,7 +444,7 @@ decode_time(unsigned char* der, int length)
/********/
typedef struct {
- char *name;
+ const char *name;
VALUE *klass;
} ossl_asn1_info_t;
@@ -500,7 +499,7 @@ ossl_asn1_get_asn1type(VALUE obj)
value = ossl_asn1_get_value(obj);
switch(tag){
case V_ASN1_BOOLEAN:
- ptr = (void*)obj_to_asn1bool(value);
+ ptr = (void*)(VALUE)obj_to_asn1bool(value);
free_func = NULL;
break;
case V_ASN1_INTEGER: /* FALLTHROUGH */
@@ -678,7 +677,7 @@ static VALUE
join_der(VALUE enumerable)
{
VALUE str = rb_str_new(0, 0);
- rb_iterate(rb_each, enumerable, join_der_i, str);
+ rb_block_call(enumerable, rb_intern("each"), 0, 0, join_der_i, str);
return str;
}
@@ -699,13 +698,13 @@ ossl_asn1data_to_der(VALUE self)
tag = ossl_asn1_tag(self);
tag_class = ossl_asn1_tag_class(self);
- if((length = ASN1_object_size(1, RSTRING(value)->len, tag)) <= 0)
+ if((length = ASN1_object_size(1, RSTRING_LEN(value), tag)) <= 0)
ossl_raise(eASN1Error, NULL);
der = rb_str_new(0, length);
- p = RSTRING(der)->ptr;
- ASN1_put_object(&p, is_cons, RSTRING(value)->len, tag, tag_class);
- memcpy(p, RSTRING(value)->ptr, RSTRING(value)->len);
- p += RSTRING(value)->len;
+ p = RSTRING_PTR(der);
+ ASN1_put_object(&p, is_cons, RSTRING_LEN(value), tag, tag_class);
+ memcpy(p, RSTRING_PTR(value), RSTRING_LEN(value));
+ p += RSTRING_LEN(value);
ossl_str_adjust(der, p);
return der;
@@ -824,8 +823,8 @@ ossl_asn1_traverse(VALUE self, VALUE obj)
obj = ossl_to_der_if_possible(obj);
tmp = rb_str_new4(StringValue(obj));
- p = RSTRING(tmp)->ptr;
- ossl_asn1_decode0(&p, RSTRING(tmp)->len, &offset, 0, 0, 1);
+ p = RSTRING_PTR(tmp);
+ ossl_asn1_decode0(&p, RSTRING_LEN(tmp), &offset, 0, 0, 1);
return Qnil;
}
@@ -840,8 +839,8 @@ ossl_asn1_decode(VALUE self, VALUE obj)
obj = ossl_to_der_if_possible(obj);
tmp = rb_str_new4(StringValue(obj));
- p = RSTRING(tmp)->ptr;
- ary = ossl_asn1_decode0(&p, RSTRING(tmp)->len, &offset, 0, 1, 0);
+ p = RSTRING_PTR(tmp);
+ ary = ossl_asn1_decode0(&p, RSTRING_LEN(tmp), &offset, 0, 1, 0);
ret = rb_ary_entry(ary, 0);
return ret;
@@ -857,8 +856,8 @@ ossl_asn1_decode_all(VALUE self, VALUE obj)
obj = ossl_to_der_if_possible(obj);
tmp = rb_str_new4(StringValue(obj));
- p = RSTRING(tmp)->ptr;
- ret = ossl_asn1_decode0(&p, RSTRING(tmp)->len, &offset, 0, 0, 0);
+ p = RSTRING_PTR(tmp);
+ ret = ossl_asn1_decode0(&p, RSTRING_LEN(tmp), &offset, 0, 0, 0);
return ret;
}
@@ -925,7 +924,7 @@ ossl_asn1prim_to_der(VALUE self)
{
ASN1_TYPE *asn1;
int tn, tc, explicit;
- long length, reallen;
+ long len, reallen;
unsigned char *buf, *p;
VALUE str;
@@ -934,26 +933,24 @@ ossl_asn1prim_to_der(VALUE self)
explicit = ossl_asn1_is_explicit(self);
asn1 = ossl_asn1_get_asn1type(self);
- length = ASN1_object_size(1, ossl_i2d_ASN1_TYPE(asn1, NULL), tn);
- if(!(buf = OPENSSL_malloc(length))){
+ len = ASN1_object_size(1, ossl_i2d_ASN1_TYPE(asn1, NULL), tn);
+ if(!(buf = OPENSSL_malloc(len))){
ossl_ASN1_TYPE_free(asn1);
ossl_raise(eASN1Error, "cannot alloc buffer");
}
p = buf;
- if(tc == V_ASN1_UNIVERSAL) ossl_i2d_ASN1_TYPE(asn1, &p);
- else{
- if(explicit){
- ASN1_put_object(&p, 1, ossl_i2d_ASN1_TYPE(asn1, NULL), tn, tc);
- ossl_i2d_ASN1_TYPE(asn1, &p);
- }
- else{
- ossl_i2d_ASN1_TYPE(asn1, &p);
- *buf = tc | tn | (*buf & V_ASN1_CONSTRUCTED);
- }
+ if (tc == V_ASN1_UNIVERSAL) {
+ ossl_i2d_ASN1_TYPE(asn1, &p);
+ } else if (explicit) {
+ ASN1_put_object(&p, 1, ossl_i2d_ASN1_TYPE(asn1, NULL), tn, tc);
+ ossl_i2d_ASN1_TYPE(asn1, &p);
+ } else {
+ ossl_i2d_ASN1_TYPE(asn1, &p);
+ *buf = tc | tn | (*buf & V_ASN1_CONSTRUCTED);
}
ossl_ASN1_TYPE_free(asn1);
reallen = p - buf;
- assert(reallen <= length);
+ assert(reallen <= len);
str = ossl_buf2str(buf, reallen); /* buf will be free in ossl_buf2str */
return str;
@@ -973,21 +970,21 @@ ossl_asn1cons_to_der(VALUE self)
explicit = ossl_asn1_is_explicit(self);
value = join_der(ossl_asn1_get_value(self));
- seq_len = ASN1_object_size(1, RSTRING(value)->len, tag);
+ seq_len = ASN1_object_size(1, RSTRING_LEN(value), tag);
length = ASN1_object_size(1, seq_len, tn);
str = rb_str_new(0, length);
- p = RSTRING(str)->ptr;
+ p = RSTRING_PTR(str);
if(tc == V_ASN1_UNIVERSAL)
- ASN1_put_object(&p, 1, RSTRING(value)->len, tn, tc);
+ ASN1_put_object(&p, 1, RSTRING_LEN(value), tn, tc);
else{
if(explicit){
ASN1_put_object(&p, 1, seq_len, tn, tc);
- ASN1_put_object(&p, 1, RSTRING(value)->len, tag, V_ASN1_UNIVERSAL);
+ ASN1_put_object(&p, 1, RSTRING_LEN(value), tag, V_ASN1_UNIVERSAL);
}
- else ASN1_put_object(&p, 1, RSTRING(value)->len, tn, tc);
+ else ASN1_put_object(&p, 1, RSTRING_LEN(value), tn, tc);
}
- memcpy(p, RSTRING(value)->ptr, RSTRING(value)->len);
- p += RSTRING(value)->len;
+ memcpy(p, RSTRING_PTR(value), RSTRING_LEN(value));
+ p += RSTRING_LEN(value);
ossl_str_adjust(str, p);
return str;
@@ -1007,7 +1004,7 @@ ossl_asn1obj_s_register(VALUE self, VALUE oid, VALUE sn, VALUE ln)
StringValue(sn);
StringValue(ln);
- if(!OBJ_create(RSTRING(oid)->ptr, RSTRING(sn)->ptr, RSTRING(ln)->ptr))
+ if(!OBJ_create(RSTRING_PTR(oid), RSTRING_PTR(sn), RSTRING_PTR(ln)))
ossl_raise(eASN1Error, NULL);
return Qtrue;
@@ -1087,6 +1084,10 @@ Init_ossl_asn1()
VALUE ary;
int i;
+#if 0 /* let rdoc know about mOSSL */
+ mOSSL = rb_define_module("OpenSSL");
+#endif
+
sUNIVERSAL = rb_intern("UNIVERSAL");
sCONTEXT_SPECIFIC = rb_intern("CONTEXT_SPECIFIC");
sAPPLICATION = rb_intern("APPLICATION");
@@ -1108,9 +1109,9 @@ Init_ossl_asn1()
}
cASN1Data = rb_define_class_under(mASN1, "ASN1Data", rb_cObject);
- rb_attr(cASN1Data, rb_intern("value"), 1, 1, Qtrue);
- rb_attr(cASN1Data, rb_intern("tag"), 1, 1, Qtrue);
- rb_attr(cASN1Data, rb_intern("tag_class"), 1, 1, Qtrue);
+ rb_attr(cASN1Data, rb_intern("value"), 1, 1, 0);
+ rb_attr(cASN1Data, rb_intern("tag"), 1, 1, 0);
+ rb_attr(cASN1Data, rb_intern("tag_class"), 1, 1, 0);
rb_define_method(cASN1Data, "initialize", ossl_asn1data_initialize, 3);
rb_define_method(cASN1Data, "to_der", ossl_asn1data_to_der, 0);
@@ -1162,5 +1163,5 @@ do{\
rb_define_method(cASN1ObjectId, "oid", ossl_asn1obj_get_oid, 0);
rb_define_alias(cASN1ObjectId, "short_name", "sn");
rb_define_alias(cASN1ObjectId, "long_name", "ln");
- rb_attr(cASN1BitString, rb_intern("unused_bits"), 1, 1, Qtrue);
+ rb_attr(cASN1BitString, rb_intern("unused_bits"), 1, 1, 0);
}
diff --git a/ext/openssl/ossl_asn1.h b/ext/openssl/ossl_asn1.h
index 6a1c97b902..8aad9f970d 100644
--- a/ext/openssl/ossl_asn1.h
+++ b/ext/openssl/ossl_asn1.h
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_asn1.h,v 1.3.2.1 2005/09/10 01:17:00 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' team members
* Copyright (C) 2003
* All rights reserved.
diff --git a/ext/openssl/ossl_bio.c b/ext/openssl/ossl_bio.c
index 4e3248eb1d..6db1fb9a62 100644
--- a/ext/openssl/ossl_bio.c
+++ b/ext/openssl/ossl_bio.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_bio.c,v 1.2.2.1 2005/06/19 16:29:17 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' team members
* Copyright (C) 2003
* All rights reserved.
@@ -19,16 +19,29 @@ ossl_obj2bio(VALUE obj)
BIO *bio;
if (TYPE(obj) == T_FILE) {
- OpenFile *fptr;
+ rb_io_t *fptr;
+ FILE *fp;
+ int fd;
+
GetOpenFile(obj, fptr);
rb_io_check_readable(fptr);
- bio = BIO_new_fp(fptr->f, BIO_NOCLOSE);
- }
+ if ((fd = dup(FPTR_TO_FD(fptr))) < 0){
+ rb_sys_fail(0);
+ }
+ if (!(fp = fdopen(fd, "r"))){
+ close(fd);
+ rb_sys_fail(0);
+ }
+ if (!(bio = BIO_new_fp(fp, BIO_CLOSE))){
+ fclose(fp);
+ ossl_raise(eOSSLError, NULL);
+ }
+ }
else {
StringValue(obj);
- bio = BIO_new_mem_buf(RSTRING(obj)->ptr, RSTRING(obj)->len);
+ bio = BIO_new_mem_buf(RSTRING_PTR(obj), RSTRING_LEN(obj));
+ if (!bio) ossl_raise(eOSSLError, NULL);
}
- if (!bio) ossl_raise(eOSSLError, NULL);
return bio;
}
diff --git a/ext/openssl/ossl_bio.h b/ext/openssl/ossl_bio.h
index ca312679fa..2d8f675c5b 100644
--- a/ext/openssl/ossl_bio.h
+++ b/ext/openssl/ossl_bio.h
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_bio.h,v 1.2 2003/09/17 09:05:01 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' team members
* Copyright (C) 2003
* All rights reserved.
diff --git a/ext/openssl/ossl_bn.c b/ext/openssl/ossl_bn.c
index fb86c8721c..be43b0eacd 100644
--- a/ext/openssl/ossl_bn.c
+++ b/ext/openssl/ossl_bn.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_bn.c,v 1.5.2.1 2004/12/15 01:54:39 matz Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Technorama team <oss-ruby@technorama.net>
* All rights reserved.
@@ -40,7 +40,7 @@ VALUE eBNError;
* Public
*/
VALUE
-ossl_bn_new(BIGNUM *bn)
+ossl_bn_new(const BIGNUM *bn)
{
BIGNUM *newbn;
VALUE obj;
@@ -100,6 +100,13 @@ ossl_bn_alloc(VALUE klass)
return obj;
}
+/*
+ * call-seq:
+ * BN.new => aBN
+ * BN.new(bn) => aBN
+ * BN.new(string) => aBN
+ * BN.new(string, 0 | 2 | 10 | 16) => aBN
+ */
static VALUE
ossl_bn_initialize(int argc, VALUE *argv, VALUE self)
{
@@ -124,31 +131,44 @@ ossl_bn_initialize(int argc, VALUE *argv, VALUE self)
switch (base) {
case 0:
- if (!BN_mpi2bn(RSTRING(str)->ptr, RSTRING(str)->len, bn)) {
+ if (!BN_mpi2bn(RSTRING_PTR(str), RSTRING_LEN(str), bn)) {
ossl_raise(eBNError, NULL);
}
break;
case 2:
- if (!BN_bin2bn(RSTRING(str)->ptr, RSTRING(str)->len, bn)) {
+ if (!BN_bin2bn(RSTRING_PTR(str), RSTRING_LEN(str), bn)) {
ossl_raise(eBNError, NULL);
}
break;
case 10:
- if (!BN_dec2bn(&bn, RSTRING(str)->ptr)) {
+ if (!BN_dec2bn(&bn, RSTRING_PTR(str))) {
ossl_raise(eBNError, NULL);
}
break;
case 16:
- if (!BN_hex2bn(&bn, RSTRING(str)->ptr)) {
+ if (!BN_hex2bn(&bn, RSTRING_PTR(str))) {
ossl_raise(eBNError, NULL);
}
break;
default:
- ossl_raise(rb_eArgError, "illegal radix %d", base);
+ ossl_raise(rb_eArgError, "invalid radix %d", base);
}
return self;
}
+/*
+ * call-seq:
+ * bn.to_s => string
+ * bn.to_s(base) => string
+ *
+ * === Parameters
+ * * +base+ - integer
+ * * * Valid values:
+ * * * * 0 - MPI
+ * * * * 2 - binary
+ * * * * 10 - the default
+ * * * * 16 - hex
+ */
static VALUE
ossl_bn_to_s(int argc, VALUE *argv, VALUE self)
{
@@ -165,13 +185,13 @@ ossl_bn_to_s(int argc, VALUE *argv, VALUE self)
case 0:
len = BN_bn2mpi(bn, NULL);
str = rb_str_new(0, len);
- if (BN_bn2mpi(bn, RSTRING(str)->ptr) != len)
+ if (BN_bn2mpi(bn, RSTRING_PTR(str)) != len)
ossl_raise(eBNError, NULL);
break;
case 2:
len = BN_num_bytes(bn);
str = rb_str_new(0, len);
- if (BN_bn2bin(bn, RSTRING(str)->ptr) != len)
+ if (BN_bn2bin(bn, RSTRING_PTR(str)) != len)
ossl_raise(eBNError, NULL);
break;
case 10:
@@ -183,12 +203,16 @@ ossl_bn_to_s(int argc, VALUE *argv, VALUE self)
str = ossl_buf2str(buf, strlen(buf));
break;
default:
- ossl_raise(rb_eArgError, "illegal radix %d", base);
+ ossl_raise(rb_eArgError, "invalid radix %d", base);
}
return str;
}
+/*
+ * call-seq:
+ * bn.to_i => integer
+ */
static VALUE
ossl_bn_to_i(VALUE self)
{
@@ -233,6 +257,11 @@ ossl_bn_coerce(VALUE self, VALUE other)
}
#define BIGNUM_BOOL1(func) \
+ /* \
+ * call-seq: \
+ * bn.##func -> true | false \
+ * \
+ */ \
static VALUE \
ossl_bn_##func(VALUE self) \
{ \
@@ -243,11 +272,16 @@ ossl_bn_coerce(VALUE self, VALUE other)
} \
return Qfalse; \
}
-BIGNUM_BOOL1(is_zero);
-BIGNUM_BOOL1(is_one);
-BIGNUM_BOOL1(is_odd);
+BIGNUM_BOOL1(is_zero)
+BIGNUM_BOOL1(is_one)
+BIGNUM_BOOL1(is_odd)
#define BIGNUM_1c(func) \
+ /* \
+ * call-seq: \
+ * bn.##func -> aBN \
+ * \
+ */ \
static VALUE \
ossl_bn_##func(VALUE self) \
{ \
@@ -264,9 +298,14 @@ BIGNUM_BOOL1(is_odd);
WrapBN(CLASS_OF(self), obj, result); \
return obj; \
}
-BIGNUM_1c(sqr);
+BIGNUM_1c(sqr)
#define BIGNUM_2(func) \
+ /* \
+ * call-seq: \
+ * bn.##func(bn2) -> aBN \
+ * \
+ */ \
static VALUE \
ossl_bn_##func(VALUE self, VALUE other) \
{ \
@@ -283,10 +322,15 @@ BIGNUM_1c(sqr);
WrapBN(CLASS_OF(self), obj, result); \
return obj; \
}
-BIGNUM_2(add);
-BIGNUM_2(sub);
+BIGNUM_2(add)
+BIGNUM_2(sub)
#define BIGNUM_2c(func) \
+ /* \
+ * call-seq: \
+ * bn.##func(bn2) -> aBN \
+ * \
+ */ \
static VALUE \
ossl_bn_##func(VALUE self, VALUE other) \
{ \
@@ -303,13 +347,17 @@ BIGNUM_2(sub);
WrapBN(CLASS_OF(self), obj, result); \
return obj; \
}
-BIGNUM_2c(mul);
-BIGNUM_2c(mod);
-BIGNUM_2c(exp);
-BIGNUM_2c(gcd);
-BIGNUM_2c(mod_sqr);
-BIGNUM_2c(mod_inverse);
+BIGNUM_2c(mul)
+BIGNUM_2c(mod)
+BIGNUM_2c(exp)
+BIGNUM_2c(gcd)
+BIGNUM_2c(mod_sqr)
+BIGNUM_2c(mod_inverse)
+/*
+ * call-seq:
+ * bn1 / bn2 => [result, remainder]
+ */
static VALUE
ossl_bn_div(VALUE self, VALUE other)
{
@@ -337,6 +385,11 @@ ossl_bn_div(VALUE self, VALUE other)
}
#define BIGNUM_3c(func) \
+ /* \
+ * call-seq: \
+ * bn.##func(bn1, bn2) -> aBN \
+ * \
+ */ \
static VALUE \
ossl_bn_##func(VALUE self, VALUE other1, VALUE other2) \
{ \
@@ -354,12 +407,17 @@ ossl_bn_div(VALUE self, VALUE other)
WrapBN(CLASS_OF(self), obj, result); \
return obj; \
}
-BIGNUM_3c(mod_add);
-BIGNUM_3c(mod_sub);
-BIGNUM_3c(mod_mul);
-BIGNUM_3c(mod_exp);
+BIGNUM_3c(mod_add)
+BIGNUM_3c(mod_sub)
+BIGNUM_3c(mod_mul)
+BIGNUM_3c(mod_exp)
#define BIGNUM_BIT(func) \
+ /* \
+ * call-seq: \
+ * bn.##func(bit) -> self \
+ * \
+ */ \
static VALUE \
ossl_bn_##func(VALUE self, VALUE bit) \
{ \
@@ -370,10 +428,14 @@ BIGNUM_3c(mod_exp);
} \
return self; \
}
-BIGNUM_BIT(set_bit);
-BIGNUM_BIT(clear_bit);
-BIGNUM_BIT(mask_bits);
+BIGNUM_BIT(set_bit)
+BIGNUM_BIT(clear_bit)
+BIGNUM_BIT(mask_bits)
+/*
+ * call-seq:
+ * bn.bit_set?(bit) => true | false
+ */
static VALUE
ossl_bn_is_bit_set(VALUE self, VALUE bit)
{
@@ -389,6 +451,11 @@ ossl_bn_is_bit_set(VALUE self, VALUE bit)
}
#define BIGNUM_SHIFT(func) \
+ /* \
+ * call-seq: \
+ * bn.##func(bits) -> aBN \
+ * \
+ */ \
static VALUE \
ossl_bn_##func(VALUE self, VALUE bits) \
{ \
@@ -407,10 +474,35 @@ ossl_bn_is_bit_set(VALUE self, VALUE bit)
WrapBN(CLASS_OF(self), obj, result); \
return obj; \
}
-BIGNUM_SHIFT(lshift);
-BIGNUM_SHIFT(rshift);
+BIGNUM_SHIFT(lshift)
+BIGNUM_SHIFT(rshift)
+
+#define BIGNUM_SELF_SHIFT(func) \
+ /* \
+ * call-seq: \
+ * bn.##func!(bits) -> self \
+ * \
+ */ \
+ static VALUE \
+ ossl_bn_self_##func(VALUE self, VALUE bits) \
+ { \
+ BIGNUM *bn; \
+ int b; \
+ b = NUM2INT(bits); \
+ GetBN(self, bn); \
+ if (!BN_##func(bn, bn, b)) \
+ ossl_raise(eBNError, NULL); \
+ return self; \
+ }
+BIGNUM_SELF_SHIFT(lshift)
+BIGNUM_SELF_SHIFT(rshift)
#define BIGNUM_RAND(func) \
+ /* \
+ * call-seq: \
+ * BN.##func(bits [, fill [, odd]]) -> aBN \
+ * \
+ */ \
static VALUE \
ossl_bn_s_##func(int argc, VALUE *argv, VALUE klass) \
{ \
@@ -423,7 +515,7 @@ BIGNUM_SHIFT(rshift);
bottom = (odd == Qtrue) ? 1 : 0; \
/* FALLTHROUGH */ \
case 2: \
- top = FIX2INT(fill); \
+ top = NUM2INT(fill); \
} \
b = NUM2INT(bits); \
if (!(result = BN_new())) { \
@@ -436,10 +528,15 @@ BIGNUM_SHIFT(rshift);
WrapBN(klass, obj, result); \
return obj; \
}
-BIGNUM_RAND(rand);
-BIGNUM_RAND(pseudo_rand);
+BIGNUM_RAND(rand)
+BIGNUM_RAND(pseudo_rand)
#define BIGNUM_RAND_RANGE(func) \
+ /* \
+ * call-seq: \
+ * BN.##func(range) -> aBN \
+ * \
+ */ \
static VALUE \
ossl_bn_s_##func##_range(VALUE klass, VALUE range) \
{ \
@@ -455,9 +552,19 @@ BIGNUM_RAND(pseudo_rand);
WrapBN(klass, obj, result); \
return obj; \
}
-BIGNUM_RAND_RANGE(rand);
-BIGNUM_RAND_RANGE(pseudo_rand);
+BIGNUM_RAND_RANGE(rand)
+BIGNUM_RAND_RANGE(pseudo_rand)
+/*
+ * call-seq:
+ * BN.generate_prime(bits, [, safe [, add [, rem]]]) => bn
+ *
+ * === Parameters
+ * * +bits+ - integer
+ * * +safe+ - boolean
+ * * +add+ - BN
+ * * +rem+ - BN
+ */
static VALUE
ossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass)
{
@@ -473,12 +580,8 @@ ossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass)
safe = 0;
}
if (!NIL_P(vadd)) {
- if (NIL_P(vrem)) {
- ossl_raise(rb_eArgError,
- "if ADD is specified, REM must be also given");
- }
add = GetBNPtr(vadd);
- rem = GetBNPtr(vrem);
+ rem = NIL_P(vrem) ? NULL : GetBNPtr(vrem);
}
if (!(result = BN_new())) {
ossl_raise(eBNError, NULL);
@@ -489,10 +592,15 @@ ossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass)
}
WrapBN(klass, obj, result);
- return obj;
+ return obj;
}
#define BIGNUM_NUM(func) \
+ /* \
+ * call-seq: \
+ * bn.##func -> integer \
+ * \
+ */ \
static VALUE \
ossl_bn_##func(VALUE self) \
{ \
@@ -500,8 +608,8 @@ ossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass)
GetBN(self, bn); \
return INT2FIX(BN_##func(bn)); \
}
-BIGNUM_NUM(num_bytes);
-BIGNUM_NUM(num_bits);
+BIGNUM_NUM(num_bytes)
+BIGNUM_NUM(num_bits)
static VALUE
ossl_bn_copy(VALUE self, VALUE other)
@@ -522,6 +630,11 @@ ossl_bn_copy(VALUE self, VALUE other)
}
#define BIGNUM_CMP(func) \
+ /* \
+ * call-seq: \
+ * bn.##func(bn2) -> integer \
+ * \
+ */ \
static VALUE \
ossl_bn_##func(VALUE self, VALUE other) \
{ \
@@ -529,8 +642,8 @@ ossl_bn_copy(VALUE self, VALUE other)
GetBN(self, bn1); \
return INT2FIX(BN_##func(bn1, bn2)); \
}
-BIGNUM_CMP(cmp);
-BIGNUM_CMP(ucmp);
+BIGNUM_CMP(cmp)
+BIGNUM_CMP(ucmp)
static VALUE
ossl_bn_eql(VALUE self, VALUE other)
@@ -541,6 +654,14 @@ ossl_bn_eql(VALUE self, VALUE other)
return Qfalse;
}
+/*
+ * call-seq:
+ * bn.prime? => true | false
+ * bn.prime?(checks) => true | false
+ *
+ * === Parameters
+ * * +checks+ - integer
+ */
static VALUE
ossl_bn_is_prime(int argc, VALUE *argv, VALUE self)
{
@@ -548,7 +669,7 @@ ossl_bn_is_prime(int argc, VALUE *argv, VALUE self)
VALUE vchecks;
int checks = BN_prime_checks;
- if (rb_scan_args(argc, argv, "01", &vchecks) == 0) {
+ if (rb_scan_args(argc, argv, "01", &vchecks) == 1) {
checks = NUM2INT(vchecks);
}
GetBN(self, bn);
@@ -564,6 +685,16 @@ ossl_bn_is_prime(int argc, VALUE *argv, VALUE self)
return Qnil;
}
+/*
+ * call-seq:
+ * bn.prime_fasttest? => true | false
+ * bn.prime_fasttest?(checks) => true | false
+ * bn.prime_fasttest?(checks, trial_div) => true | false
+ *
+ * === Parameters
+ * * +checks+ - integer
+ * * +trial_div+ - boolean
+ */
static VALUE
ossl_bn_is_prime_fasttest(int argc, VALUE *argv, VALUE self)
{
@@ -600,6 +731,10 @@ ossl_bn_is_prime_fasttest(int argc, VALUE *argv, VALUE self)
void
Init_ossl_bn()
{
+#if 0 /* let rdoc know about mOSSL */
+ mOSSL = rb_define_module("OpenSSL");
+#endif
+
if (!(ossl_bn_ctx = BN_CTX_new())) {
ossl_raise(rb_eRuntimeError, "Cannot init BN_CTX");
}
@@ -672,8 +807,10 @@ Init_ossl_bn()
rb_define_method(cBN, "bit_set?", ossl_bn_is_bit_set, 1);
rb_define_method(cBN, "mask_bits!", ossl_bn_mask_bits, 1);
rb_define_method(cBN, "<<", ossl_bn_lshift, 1);
- /* lshift1 - DON'T IMPL. */
rb_define_method(cBN, ">>", ossl_bn_rshift, 1);
+ rb_define_method(cBN, "lshift!", ossl_bn_self_lshift, 1);
+ rb_define_method(cBN, "rshift!", ossl_bn_self_rshift, 1);
+ /* lshift1 - DON'T IMPL. */
/* rshift1 - DON'T IMPL. */
/*
diff --git a/ext/openssl/ossl_bn.h b/ext/openssl/ossl_bn.h
index bccdbc0cd6..d6c396227b 100644
--- a/ext/openssl/ossl_bn.h
+++ b/ext/openssl/ossl_bn.h
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_bn.h,v 1.1 2003/07/23 16:11:29 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -14,9 +14,12 @@
extern VALUE cBN;
extern VALUE eBNError;
-VALUE ossl_bn_new(BIGNUM *);
+extern BN_CTX *ossl_bn_ctx;
+
+VALUE ossl_bn_new(const BIGNUM *);
BIGNUM *GetBNPtr(VALUE);
void Init_ossl_bn(void);
+
#endif /* _OSS_BN_H_ */
diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c
index 8d96d0b35a..a2a052ca6b 100644
--- a/ext/openssl/ossl_cipher.c
+++ b/ext/openssl/ossl_cipher.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_cipher.c,v 1.4.2.6 2006/06/20 11:18:15 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -26,7 +26,6 @@
/*
* Classes
*/
-VALUE mCipher;
VALUE cCipher;
VALUE eCipherError;
@@ -68,7 +67,7 @@ ossl_cipher_free(EVP_CIPHER_CTX *ctx)
{
if (ctx) {
EVP_CIPHER_CTX_cleanup(ctx);
- free(ctx);
+ ruby_xfree(ctx);
}
}
@@ -84,6 +83,14 @@ ossl_cipher_alloc(VALUE klass)
return obj;
}
+/*
+ * call-seq:
+ * Cipher.new(string) -> cipher
+ *
+ * The string must contain a valid cipher name like "AES-128-CBC" or "3DES".
+ *
+ * A list of cipher names is available by calling OpenSSL::Cipher.ciphers.
+ */
static VALUE
ossl_cipher_initialize(VALUE self, VALUE str)
{
@@ -117,13 +124,21 @@ ossl_cipher_copy(VALUE self, VALUE other)
return self;
}
+#ifdef HAVE_OBJ_NAME_DO_ALL_SORTED
static void*
add_cipher_name_to_ary(const OBJ_NAME *name, VALUE ary)
{
rb_ary_push(ary, rb_str_new2(name->name));
return NULL;
}
+#endif
+/*
+ * call-seq:
+ * Cipher.ciphers -> array[string...]
+ *
+ * Returns the names of all available ciphers in an array.
+ */
static VALUE
ossl_s_ciphers(VALUE self)
{
@@ -141,6 +156,12 @@ ossl_s_ciphers(VALUE self)
#endif
}
+/*
+ * call-seq:
+ * cipher.reset -> self
+ *
+ * Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, -1).
+ */
static VALUE
ossl_cipher_reset(VALUE self)
{
@@ -167,22 +188,23 @@ ossl_cipher_init(int argc, VALUE *argv, VALUE self, int mode)
* We deprecated the arguments for this method, but we decided
* keeping this behaviour for backward compatibility.
*/
+ char *cname = rb_class2name(rb_obj_class(self));
+ rb_warn("argumtents for %s#encrypt and %s#decrypt were deprecated; "
+ "use %s#pkcs5_keyivgen to derive key and IV",
+ cname, cname, cname);
StringValue(pass);
GetCipher(self, ctx);
if (NIL_P(init_v)) memcpy(iv, "OpenSSL for Ruby rulez!", sizeof(iv));
else{
- char *cname = rb_class2name(rb_obj_class(self));
- rb_warning("key derivation by %s#encrypt is deprecated; "
- "use %s::pkcs5_keyivgen instead", cname, cname);
StringValue(init_v);
- if (EVP_MAX_IV_LENGTH > RSTRING(init_v)->len) {
+ if (EVP_MAX_IV_LENGTH > RSTRING_LEN(init_v)) {
memset(iv, 0, EVP_MAX_IV_LENGTH);
- memcpy(iv, RSTRING(init_v)->ptr, RSTRING(init_v)->len);
+ memcpy(iv, RSTRING_PTR(init_v), RSTRING_LEN(init_v));
}
- else memcpy(iv, RSTRING(init_v)->ptr, sizeof(iv));
+ else memcpy(iv, RSTRING_PTR(init_v), sizeof(iv));
}
EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), EVP_md5(), iv,
- RSTRING(pass)->ptr, RSTRING(pass)->len, 1, key, NULL);
+ RSTRING_PTR(pass), RSTRING_LEN(pass), 1, key, NULL);
p_key = key;
p_iv = iv;
}
@@ -196,18 +218,54 @@ ossl_cipher_init(int argc, VALUE *argv, VALUE self, int mode)
return self;
}
+/*
+ * call-seq:
+ * cipher.encrypt -> self
+ *
+ * Make sure to call .encrypt or .decrypt before using any of the following methods:
+ * * [key=, iv=, random_key, random_iv, pkcs5_keyivgen]
+ *
+ * Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 1).
+ */
static VALUE
ossl_cipher_encrypt(int argc, VALUE *argv, VALUE self)
{
return ossl_cipher_init(argc, argv, self, 1);
}
+/*
+ * call-seq:
+ * cipher.decrypt -> self
+ *
+ * Make sure to call .encrypt or .decrypt before using any of the following methods:
+ * * [key=, iv=, random_key, random_iv, pkcs5_keyivgen]
+ *
+ * Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 0).
+ */
static VALUE
ossl_cipher_decrypt(int argc, VALUE *argv, VALUE self)
{
return ossl_cipher_init(argc, argv, self, 0);
}
+/*
+ * call-seq:
+ * cipher.pkcs5_keyivgen(pass [, salt [, iterations [, digest]]] ) -> nil
+ *
+ * Generates and sets the key/iv based on a password.
+ *
+ * WARNING: This method is only PKCS5 v1.5 compliant when using RC2, RC4-40, or DES
+ * with MD5 or SHA1. Using anything else (like AES) will generate the key/iv using an
+ * OpenSSL specific method. Use a PKCS5 v2 key generation method instead.
+ *
+ * === Parameters
+ * +salt+ must be an 8 byte string if provided.
+ * +iterations+ is a integer with a default of 2048.
+ * +digest+ is a Digest object that defaults to 'MD5'
+ *
+ * A minimum of 1000 iterations is recommended.
+ *
+ */
static VALUE
ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self)
{
@@ -221,15 +279,15 @@ ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self)
StringValue(vpass);
if(!NIL_P(vsalt)){
StringValue(vsalt);
- if(RSTRING(vsalt)->len != PKCS5_SALT_LEN)
+ if(RSTRING_LEN(vsalt) != PKCS5_SALT_LEN)
rb_raise(eCipherError, "salt must be an 8-octet string");
- salt = RSTRING(vsalt)->ptr;
+ salt = RSTRING_PTR(vsalt);
}
iter = NIL_P(viter) ? 2048 : NUM2INT(viter);
digest = NIL_P(vdigest) ? EVP_md5() : GetDigestPtr(vdigest);
GetCipher(self, ctx);
EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), digest, salt,
- RSTRING(vpass)->ptr, RSTRING(vpass)->len, iter, key, iv);
+ RSTRING_PTR(vpass), RSTRING_LEN(vpass), iter, key, iv);
if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, -1) != 1)
ossl_raise(eCipherError, NULL);
OPENSSL_cleanse(key, sizeof key);
@@ -238,39 +296,75 @@ ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self)
return Qnil;
}
+
+/*
+ * call-seq:
+ * cipher << data -> string
+ *
+ * === Parameters
+ * +data+ is a nonempty string.
+ *
+ * This method is deprecated and not available in 1.9.x or later.
+ */
+static VALUE
+ossl_cipher_update_deprecated(VALUE self, VALUE data)
+{
+ char *cname;
+
+ cname = rb_class2name(rb_obj_class(self));
+ rb_warning("%s#<< is deprecated; use %s#update instead", cname, cname);
+ return rb_funcall(self, rb_intern("update"), 1, data);
+}
+
+
+/*
+ * call-seq:
+ * cipher.update(data [, buffer]) -> string or buffer
+ *
+ * === Parameters
+ * +data+ is a nonempty string.
+ * +buffer+ is an optional string to store the result.
+ */
static VALUE
-ossl_cipher_update(VALUE self, VALUE data)
+ossl_cipher_update(int argc, VALUE *argv, VALUE self)
{
EVP_CIPHER_CTX *ctx;
char *in;
int in_len, out_len;
- VALUE str;
+ VALUE data, str;
+
+ rb_scan_args(argc, argv, "11", &data, &str);
StringValue(data);
- in = RSTRING(data)->ptr;
- if ((in_len = RSTRING(data)->len) == 0)
+ in = RSTRING_PTR(data);
+ if ((in_len = RSTRING_LEN(data)) == 0)
rb_raise(rb_eArgError, "data must not be empty");
GetCipher(self, ctx);
- str = rb_str_new(0, in_len+EVP_CIPHER_CTX_block_size(ctx));
- if (!EVP_CipherUpdate(ctx, RSTRING(str)->ptr, &out_len, in, in_len))
- ossl_raise(eCipherError, NULL);
- assert(out_len < RSTRING(str)->len);
- RSTRING(str)->len = out_len;
- RSTRING(str)->ptr[out_len] = 0;
+ out_len = in_len+EVP_CIPHER_CTX_block_size(ctx);
- return str;
-}
+ if (NIL_P(str)) {
+ str = rb_str_new(0, out_len);
+ } else {
+ StringValue(str);
+ rb_str_resize(str, out_len);
+ }
-static VALUE
-ossl_cipher_update_deprecated(VALUE self, VALUE data)
-{
- char *cname;
+ if (!EVP_CipherUpdate(ctx, RSTRING_PTR(str), &out_len, in, in_len))
+ ossl_raise(eCipherError, NULL);
+ assert(out_len < RSTRING_LEN(str));
+ rb_str_set_len(str, out_len);
- cname = rb_class2name(rb_obj_class(self));
- rb_warning("%s#<< is deprecated; use %s#update instead", cname, cname);
- return ossl_cipher_update(self, data);
+ return str;
}
+/*
+ * call-seq:
+ * cipher.final -> aString
+ *
+ * Returns the remaining data held in the cipher object. Further calls to update() or final() will return garbage.
+ *
+ * See EVP_CipherFinal_ex for further information.
+ */
static VALUE
ossl_cipher_final(VALUE self)
{
@@ -280,15 +374,20 @@ ossl_cipher_final(VALUE self)
GetCipher(self, ctx);
str = rb_str_new(0, EVP_CIPHER_CTX_block_size(ctx));
- if (!EVP_CipherFinal_ex(ctx, RSTRING(str)->ptr, &out_len))
+ if (!EVP_CipherFinal_ex(ctx, RSTRING_PTR(str), &out_len))
ossl_raise(eCipherError, NULL);
- assert(out_len <= RSTRING(str)->len);
- RSTRING(str)->len = out_len;
- RSTRING(str)->ptr[out_len] = 0;
+ assert(out_len <= RSTRING_LEN(str));
+ rb_str_set_len(str, out_len);
return str;
}
+/*
+ * call-seq:
+ * cipher.name -> string
+ *
+ * Returns the name of the cipher which may differ slightly from the original name provided.
+ */
static VALUE
ossl_cipher_name(VALUE self)
{
@@ -299,6 +398,14 @@ ossl_cipher_name(VALUE self)
return rb_str_new2(EVP_CIPHER_name(EVP_CIPHER_CTX_cipher(ctx)));
}
+/*
+ * call-seq:
+ * cipher.key = string -> string
+ *
+ * Sets the cipher key.
+ *
+ * Only call this method after calling cipher.encrypt or cipher.decrypt.
+ */
static VALUE
ossl_cipher_set_key(VALUE self, VALUE key)
{
@@ -307,15 +414,23 @@ ossl_cipher_set_key(VALUE self, VALUE key)
StringValue(key);
GetCipher(self, ctx);
- if (RSTRING(key)->len < EVP_CIPHER_CTX_key_length(ctx))
+ if (RSTRING_LEN(key) < EVP_CIPHER_CTX_key_length(ctx))
ossl_raise(eCipherError, "key length too short");
- if (EVP_CipherInit_ex(ctx, NULL, NULL, RSTRING(key)->ptr, NULL, -1) != 1)
+ if (EVP_CipherInit_ex(ctx, NULL, NULL, RSTRING_PTR(key), NULL, -1) != 1)
ossl_raise(eCipherError, NULL);
return key;
}
+/*
+ * call-seq:
+ * cipher.iv = string -> string
+ *
+ * Sets the cipher iv.
+ *
+ * Only call this method after calling cipher.encrypt or cipher.decrypt.
+ */
static VALUE
ossl_cipher_set_iv(VALUE self, VALUE iv)
{
@@ -324,20 +439,32 @@ ossl_cipher_set_iv(VALUE self, VALUE iv)
StringValue(iv);
GetCipher(self, ctx);
- if (RSTRING(iv)->len < EVP_CIPHER_CTX_iv_length(ctx))
+ if (RSTRING_LEN(iv) < EVP_CIPHER_CTX_iv_length(ctx))
ossl_raise(eCipherError, "iv length too short");
- if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, RSTRING(iv)->ptr, -1) != 1)
+ if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, RSTRING_PTR(iv), -1) != 1)
ossl_raise(eCipherError, NULL);
return iv;
}
+
+/*
+ * call-seq:
+ * cipher.key_length = integer -> integer
+ *
+ * Sets the key length of the cipher. If the cipher is a fixed length cipher then attempting to set the key
+ * length to any value other than the fixed value is an error.
+ *
+ * Under normal circumstances you do not need to call this method (and probably shouldn't).
+ *
+ * See EVP_CIPHER_CTX_set_key_length for further information.
+ */
static VALUE
ossl_cipher_set_key_length(VALUE self, VALUE key_length)
{
- EVP_CIPHER_CTX *ctx;
int len = NUM2INT(key_length);
+ EVP_CIPHER_CTX *ctx;
GetCipher(self, ctx);
if (EVP_CIPHER_CTX_set_key_length(ctx, len) != 1)
@@ -346,6 +473,16 @@ ossl_cipher_set_key_length(VALUE self, VALUE key_length)
return key_length;
}
+/*
+ * call-seq:
+ * cipher.padding = integer -> integer
+ *
+ * Enables or disables padding. By default encryption operations are padded using standard block padding and the
+ * padding is checked and removed when decrypting. If the pad parameter is zero then no padding is performed, the
+ * total amount of data encrypted or decrypted must then be a multiple of the block size or an error will occur.
+ *
+ * See EVP_CIPHER_CTX_set_padding for further information.
+ */
static VALUE
ossl_cipher_set_padding(VALUE self, VALUE padding)
{
@@ -374,26 +511,51 @@ CIPHER_0ARG_INT(key_length)
CIPHER_0ARG_INT(iv_length)
CIPHER_0ARG_INT(block_size)
+#if 0
+/*
+ * call-seq:
+ * cipher.key_length -> integer
+ *
+ */
+static VALUE ossl_cipher_key_length() { }
+/*
+ * call-seq:
+ * cipher.iv_length -> integer
+ *
+ */
+static VALUE ossl_cipher_iv_length() { }
+/*
+ * call-seq:
+ * cipher.block_size -> integer
+ *
+ */
+static VALUE ossl_cipher_block_size() { }
+#endif
+
/*
* INIT
*/
void
Init_ossl_cipher(void)
{
- mCipher = rb_define_module_under(mOSSL, "Cipher");
- eCipherError = rb_define_class_under(mOSSL, "CipherError", eOSSLError);
- cCipher = rb_define_class_under(mCipher, "Cipher", rb_cObject);
+#if 0 /* let rdoc know about mOSSL */
+ mOSSL = rb_define_module("OpenSSL");
+#endif
+ cCipher = rb_define_class_under(mOSSL, "Cipher", rb_cObject);
+ eCipherError = rb_define_class_under(cCipher, "CipherError", eOSSLError);
rb_define_alloc_func(cCipher, ossl_cipher_alloc);
rb_define_copy_func(cCipher, ossl_cipher_copy);
- rb_define_module_function(mCipher, "ciphers", ossl_s_ciphers, 0);
+ rb_define_module_function(cCipher, "ciphers", ossl_s_ciphers, 0);
rb_define_method(cCipher, "initialize", ossl_cipher_initialize, 1);
rb_define_method(cCipher, "reset", ossl_cipher_reset, 0);
rb_define_method(cCipher, "encrypt", ossl_cipher_encrypt, -1);
rb_define_method(cCipher, "decrypt", ossl_cipher_decrypt, -1);
rb_define_method(cCipher, "pkcs5_keyivgen", ossl_cipher_pkcs5_keyivgen, -1);
- rb_define_method(cCipher, "update", ossl_cipher_update, 1);
+ rb_define_method(cCipher, "update", ossl_cipher_update, -1);
+#if RUBY_VERSION_CODE < 190
rb_define_method(cCipher, "<<", ossl_cipher_update_deprecated, 1);
+#endif
rb_define_method(cCipher, "final", ossl_cipher_final, 0);
rb_define_method(cCipher, "name", ossl_cipher_name, 0);
rb_define_method(cCipher, "key=", ossl_cipher_set_key, 1);
@@ -404,3 +566,4 @@ Init_ossl_cipher(void)
rb_define_method(cCipher, "block_size", ossl_cipher_block_size, 0);
rb_define_method(cCipher, "padding=", ossl_cipher_set_padding, 1);
}
+
diff --git a/ext/openssl/ossl_cipher.h b/ext/openssl/ossl_cipher.h
index 870927c37c..bed4fa853b 100644
--- a/ext/openssl/ossl_cipher.h
+++ b/ext/openssl/ossl_cipher.h
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_cipher.h,v 1.2 2003/09/05 09:08:40 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -11,7 +11,6 @@
#if !defined(_OSSL_CIPHER_H_)
#define _OSSL_CIPHER_H_
-extern VALUE mCipher;
extern VALUE cCipher;
extern VALUE eCipherError;
diff --git a/ext/openssl/ossl_config.c b/ext/openssl/ossl_config.c
index 64998bb86a..5bde9cf768 100644
--- a/ext/openssl/ossl_config.c
+++ b/ext/openssl/ossl_config.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_config.c,v 1.8.2.3 2004/12/15 01:54:39 matz Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -10,22 +10,6 @@
*/
#include "ossl.h"
-#define WrapConfig(klass, obj, conf) do { \
- if (!conf) { \
- ossl_raise(rb_eRuntimeError, "Config wasn't intitialized!"); \
- } \
- obj = Data_Wrap_Struct(klass, 0, NCONF_free, conf); \
-} while (0)
-#define GetConfig(obj, conf) do { \
- Data_Get_Struct(obj, CONF, conf); \
- if (!conf) { \
- ossl_raise(rb_eRuntimeError, "Config wasn't intitialized!"); \
- } \
-} while (0)
-#define SafeGetConfig(obj, conf) do { \
- OSSL_Check_Kind(obj, cConfig); \
- GetConfig(obj, conf); \
-} while(0);
/*
* Classes
@@ -39,46 +23,31 @@ VALUE eConfigError;
static CONF *parse_config(VALUE, CONF*);
+/*
+ * GetConfigPtr is a public C-level function for getting OpenSSL CONF struct
+ * from an OpenSSL::Config(eConfig) instance. We decided to implement
+ * OpenSSL::Config in Ruby level but we need to pass native CONF struct for
+ * some OpenSSL features such as X509V3_EXT_*.
+ */
CONF *
GetConfigPtr(VALUE obj)
{
CONF *conf;
-
- SafeGetConfig(obj, conf);
-
- return conf;
-}
-
-CONF *
-DupConfigPtr(VALUE obj)
-{
VALUE str;
-
- OSSL_Check_Kind(obj, cConfig);
- str = rb_funcall(obj, rb_intern("to_s"), 0);
-
- return parse_config(str, NULL);
-}
-
-/*
- * Private
- */
-static CONF *
-parse_config(VALUE str, CONF *dst)
-{
- CONF *conf;
BIO *bio;
long eline = -1;
+ OSSL_Check_Kind(obj, cConfig);
+ str = rb_funcall(obj, rb_intern("to_s"), 0);
bio = ossl_obj2bio(str);
- conf = dst ? dst : NCONF_new(NULL);
+ conf = NCONF_new(NULL);
if(!conf){
BIO_free(bio);
ossl_raise(eConfigError, NULL);
}
if(!NCONF_load_bio(conf, bio, &eline)){
BIO_free(bio);
- if(!dst) NCONF_free(conf);
+ NCONF_free(conf);
if (eline <= 0) ossl_raise(eConfigError, "wrong config format");
else ossl_raise(eConfigError, "error in line %d", eline);
ossl_raise(eConfigError, NULL);
@@ -88,375 +57,19 @@ parse_config(VALUE str, CONF *dst)
return conf;
}
-static VALUE
-ossl_config_s_parse(VALUE klass, VALUE str)
-{
- CONF *conf;
- VALUE obj;
-
- conf = parse_config(str, NULL);
- WrapConfig(klass, obj, conf);
-
- return obj;
-}
-
-static VALUE
-ossl_config_s_alloc(VALUE klass)
-{
- CONF *conf;
- VALUE obj;
-
- if(!(conf = NCONF_new(NULL)))
- ossl_raise(eConfigError, NULL);
- WrapConfig(klass, obj, conf);
-
- return obj;
-}
-
-static VALUE
-ossl_config_copy(VALUE self, VALUE other)
-{
- VALUE str;
- CONF *conf;
-
- str = rb_funcall(self, rb_intern("to_s"), 0);
- GetConfig(other, conf);
- parse_config(str, conf);
-
- return self;
-}
-
-static VALUE
-ossl_config_initialize(int argc, VALUE *argv, VALUE self)
-{
- CONF *conf;
- long eline = -1;
- char *filename;
- VALUE path;
-
- rb_scan_args(argc, argv, "01", &path);
- if(!NIL_P(path)){
- SafeStringValue(path);
- filename = StringValuePtr(path);
- GetConfig(self, conf);
- if (!NCONF_load(conf, filename, &eline)){
- if (eline <= 0)
- ossl_raise(eConfigError, "wrong config file %s", filename);
- else
- ossl_raise(eConfigError, "error in %s:%d", filename, eline);
- }
- }
-#ifdef OSSL_NO_CONF_API
- else rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)");
-#else
- else {
- GetConfig(self, conf);
- _CONF_new_data(conf);
- }
-#endif
-
- return self;
-}
-
-static VALUE
-ossl_config_add_value(VALUE self, VALUE section, VALUE name, VALUE value)
-{
-#ifdef OSSL_NO_CONF_API
- rb_notimplement();
-#else
- CONF *conf;
- CONF_VALUE *sv, *cv;
-
- StringValue(section);
- StringValue(name);
- StringValue(value);
- GetConfig(self, conf);
- if(!(sv = _CONF_get_section(conf, RSTRING(section)->ptr))){
- if(!(sv = _CONF_new_section(conf, RSTRING(section)->ptr))){
- ossl_raise(eConfigError, NULL);
- }
- }
- if(!(cv = OPENSSL_malloc(sizeof(CONF_VALUE)))){
- ossl_raise(eConfigError, NULL);
- }
- cv->name = BUF_strdup(RSTRING(name)->ptr);
- cv->value = BUF_strdup(RSTRING(value)->ptr);
- if(!cv->name || !cv->value || !_CONF_add_string(conf, sv, cv)){
- OPENSSL_free(cv->name);
- OPENSSL_free(cv->value);
- OPENSSL_free(cv);
- ossl_raise(eConfigError, "_CONF_add_string failure");
- }
-
- return value;
-#endif
-}
-
-static VALUE
-ossl_config_get_value(VALUE self, VALUE section, VALUE name)
-{
- CONF *conf;
- char *str;
-
- StringValue(section);
- StringValue(name);
- GetConfig(self, conf);
- str = NCONF_get_string(conf, RSTRING(section)->ptr, RSTRING(name)->ptr);
- if(!str){
- ERR_clear_error();
- return Qnil;
- }
-
- return rb_str_new2(str);
-}
-
-static VALUE
-ossl_config_get_value_old(int argc, VALUE *argv, VALUE self)
-{
- VALUE section, name;
-
- rb_scan_args(argc, argv, "11", &section, &name);
-
- /* support conf.value(nil, "HOME") -> conf.get_value("", "HOME") */
- if (NIL_P(section)) section = rb_str_new2("");
- /* support conf.value("HOME") -> conf.get_value("", "HOME") */
- if (NIL_P(name)) {
- name = section;
- section = rb_str_new2("");
- }
- /* NOTE: Don't care about conf.get_value(nil, nil) */
- rb_warn("Config#value is deprecated; use Config#get_value");
- return ossl_config_get_value(self, section, name);
-}
-
-static VALUE
-set_conf_section_i(VALUE i, VALUE *arg)
-{
- VALUE name, value;
-
- Check_Type(i, T_ARRAY);
- name = rb_ary_entry(i, 0);
- value = rb_ary_entry(i, 1);
- ossl_config_add_value(arg[0], arg[1], name, value);
-
- return Qnil;
-}
-
-static VALUE
-ossl_config_set_section(VALUE self, VALUE section, VALUE hash)
-{
- VALUE arg[2];
-
- arg[0] = self;
- arg[1] = section;
- rb_iterate(rb_each, hash, set_conf_section_i, (VALUE)arg);
- return hash;
-}
-
-/*
- * Get all numbers as strings - use str.to_i to convert
- * long number = CONF_get_number(confp->config, sect, StringValuePtr(item));
- */
-static VALUE
-ossl_config_get_section(VALUE self, VALUE section)
-{
- CONF *conf;
- STACK_OF(CONF_VALUE) *sk;
- CONF_VALUE *entry;
- int i, entries;
- VALUE hash;
-
- hash = rb_hash_new();
- StringValue(section);
- GetConfig(self, conf);
- if (!(sk = NCONF_get_section(conf, StringValuePtr(section)))) {
- ERR_clear_error();
- return hash;
- }
- if ((entries = sk_CONF_VALUE_num(sk)) < 0) {
- OSSL_Debug("# of items in section is < 0?!?");
- return hash;
- }
- for (i=0; i<entries; i++) {
- entry = sk_CONF_VALUE_value(sk, i);
- rb_hash_aset(hash, rb_str_new2(entry->name), rb_str_new2(entry->value));
- }
-
- return hash;
-}
-
-static VALUE
-ossl_config_get_section_old(VALUE self, VALUE section)
-{
- rb_warn("Config#section is deprecated; use Config#[]");
- return ossl_config_get_section(self, section);
-}
-
-#ifdef IMPLEMENT_LHASH_DOALL_ARG_FN
-static void
-get_conf_section(CONF_VALUE *cv, VALUE ary)
-{
- if(cv->name) return;
- rb_ary_push(ary, rb_str_new2(cv->section));
-}
-
-static IMPLEMENT_LHASH_DOALL_ARG_FN(get_conf_section, CONF_VALUE*, VALUE);
-
-static VALUE
-ossl_config_get_sections(VALUE self)
-{
- CONF *conf;
- VALUE ary;
-
- GetConfig(self, conf);
- ary = rb_ary_new();
- lh_doall_arg(conf->data, LHASH_DOALL_ARG_FN(get_conf_section), (void*)ary);
-
- return ary;
-}
-
-static void
-dump_conf_value(CONF_VALUE *cv, VALUE str)
-{
- STACK_OF(CONF_VALUE) *sk;
- CONF_VALUE *v;
- int i, num;
-
- if (cv->name) return;
- sk = (STACK_OF(CONF_VALUE)*)cv->value;
- num = sk_CONF_VALUE_num(sk);
- rb_str_cat2(str, "[ ");
- rb_str_cat2(str, cv->section);
- rb_str_cat2(str, " ]\n");
- for(i = 0; i < num; i++){
- v = sk_CONF_VALUE_value(sk, i);
- rb_str_cat2(str, v->name ? v->name : "None");
- rb_str_cat2(str, "=");
- rb_str_cat2(str, v->value ? v->value : "None");
- rb_str_cat2(str, "\n");
- }
- rb_str_cat2(str, "\n");
-}
-
-static IMPLEMENT_LHASH_DOALL_ARG_FN(dump_conf_value, CONF_VALUE*, VALUE);
-
-static VALUE
-dump_conf(CONF *conf)
-{
- VALUE str;
-
- str = rb_str_new(0, 0);
- lh_doall_arg(conf->data, LHASH_DOALL_ARG_FN(dump_conf_value), (void*)str);
-
- return str;
-}
-
-static VALUE
-ossl_config_to_s(VALUE self)
-{
- CONF *conf;
-
- GetConfig(self, conf);
-
- return dump_conf(conf);
-}
-
-static void
-each_conf_value(CONF_VALUE *cv, void* dummy)
-{
- STACK_OF(CONF_VALUE) *sk;
- CONF_VALUE *v;
- VALUE section, name, value, args;
- int i, num;
-
- if (cv->name) return;
- sk = (STACK_OF(CONF_VALUE)*)cv->value;
- num = sk_CONF_VALUE_num(sk);
- section = rb_str_new2(cv->section);
- for(i = 0; i < num; i++){
- v = sk_CONF_VALUE_value(sk, i);
- name = v->name ? rb_str_new2(v->name) : Qnil;
- value = v->value ? rb_str_new2(v->value) : Qnil;
- args = rb_ary_new3(3, section, name, value);
- rb_yield(args);
- }
-}
-
-static IMPLEMENT_LHASH_DOALL_ARG_FN(each_conf_value, CONF_VALUE*, void*);
-
-static VALUE
-ossl_config_each(VALUE self)
-{
- CONF *conf;
-
- GetConfig(self, conf);
- lh_doall_arg(conf->data, LHASH_DOALL_ARG_FN(each_conf_value), (void*)NULL);
-
- return self;
-}
-#else
-static VALUE
-ossl_config_get_sections(VALUE self)
-{
- rb_warn("#sections don't work with %s", OPENSSL_VERSION_TEXT);
- return rb_ary_new();
-}
-
-static VALUE
-ossl_config_to_s(VALUE self)
-{
- rb_warn("#to_s don't work with %s", OPENSSL_VERSION_TEXT);
- return rb_str_new(0, 0);
-}
-
-static VALUE
-ossl_config_each(VALUE self)
-{
- rb_warn("#each don't work with %s", OPENSSL_VERSION_TEXT);
- return self;
-}
-#endif
-
-static VALUE
-ossl_config_inspect(VALUE self)
-{
- VALUE str, ary = ossl_config_get_sections(self);
- char *cname = rb_class2name(rb_obj_class(self));
-
- str = rb_str_new2("#<");
- rb_str_cat2(str, cname);
- rb_str_cat2(str, " sections=");
- rb_str_append(str, rb_inspect(ary));
- rb_str_cat2(str, ">");
-
- return str;
-}
-
/*
* INIT
*/
void
Init_ossl_config()
{
+ char *default_config_file;
eConfigError = rb_define_class_under(mOSSL, "ConfigError", eOSSLError);
cConfig = rb_define_class_under(mOSSL, "Config", rb_cObject);
+ default_config_file = CONF_get1_default_config_file();
rb_define_const(cConfig, "DEFAULT_CONFIG_FILE",
- rb_str_new2(CONF_get1_default_config_file()));
- rb_include_module(cConfig, rb_mEnumerable);
- rb_define_singleton_method(cConfig, "parse", ossl_config_s_parse, 1);
- rb_define_alias(CLASS_OF(cConfig), "load", "new");
- rb_define_alloc_func(cConfig, ossl_config_s_alloc);
- rb_define_copy_func(cConfig, ossl_config_copy);
- rb_define_method(cConfig, "initialize", ossl_config_initialize, -1);
- rb_define_method(cConfig, "get_value", ossl_config_get_value, 2);
- rb_define_method(cConfig, "value", ossl_config_get_value_old, -1);
- rb_define_method(cConfig, "add_value", ossl_config_add_value, 3);
- rb_define_method(cConfig, "[]", ossl_config_get_section, 1);
- rb_define_method(cConfig, "section", ossl_config_get_section_old, 1);
- rb_define_method(cConfig, "[]=", ossl_config_set_section, 2);
- rb_define_method(cConfig, "sections", ossl_config_get_sections, 0);
- rb_define_method(cConfig, "to_s", ossl_config_to_s, 0);
- rb_define_method(cConfig, "each", ossl_config_each, 0);
- rb_define_method(cConfig, "inspect", ossl_config_inspect, 0);
+ rb_str_new2(default_config_file));
+ OPENSSL_free(default_config_file);
+ /* methods are defined by openssl/config.rb */
}
diff --git a/ext/openssl/ossl_config.h b/ext/openssl/ossl_config.h
index 452d430b5e..cb226b27e5 100644
--- a/ext/openssl/ossl_config.h
+++ b/ext/openssl/ossl_config.h
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_config.h,v 1.2 2003/09/08 10:31:38 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
diff --git a/ext/openssl/ossl_digest.c b/ext/openssl/ossl_digest.c
index 8b9c273f4d..879d399fe7 100644
--- a/ext/openssl/ossl_digest.c
+++ b/ext/openssl/ossl_digest.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_digest.c,v 1.4.2.2 2004/12/15 01:54:39 matz Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -24,7 +24,6 @@
/*
* Classes
*/
-VALUE mDigest;
VALUE cDigest;
VALUE eDigestError;
@@ -36,11 +35,23 @@ static VALUE ossl_digest_alloc(VALUE klass);
const EVP_MD *
GetDigestPtr(VALUE obj)
{
- EVP_MD_CTX *ctx;
+ const EVP_MD *md;
+
+ if (TYPE(obj) == T_STRING) {
+ const char *name = STR2CSTR(obj);
+
+ md = EVP_get_digestbyname(name);
+ if (!md)
+ ossl_raise(rb_eRuntimeError, "Unsupported digest algorithm (%s).", name);
+ } else {
+ EVP_MD_CTX *ctx;
- SafeGetDigest(obj, ctx);
+ SafeGetDigest(obj, ctx);
- return EVP_MD_CTX_md(ctx); /*== ctx->digest*/
+ md = EVP_MD_CTX_md(ctx);
+ }
+
+ return md;
}
VALUE
@@ -51,7 +62,6 @@ ossl_digest_new(const EVP_MD *md)
ret = ossl_digest_alloc(cDigest);
GetDigest(ret, ctx);
- EVP_MD_CTX_init(ctx);
EVP_DigestInit_ex(ctx, md, NULL);
return ret;
@@ -69,14 +79,18 @@ ossl_digest_alloc(VALUE klass)
ctx = EVP_MD_CTX_create();
if (ctx == NULL)
ossl_raise(rb_eRuntimeError, "EVP_MD_CTX_create() failed");
- EVP_MD_CTX_init(ctx);
obj = Data_Wrap_Struct(klass, 0, EVP_MD_CTX_destroy, ctx);
-
+
return obj;
}
VALUE ossl_digest_update(VALUE, VALUE);
+/*
+ * call-seq:
+ * Digest.new(string) -> digest
+ *
+ */
static VALUE
ossl_digest_initialize(int argc, VALUE *argv, VALUE self)
{
@@ -86,14 +100,9 @@ ossl_digest_initialize(int argc, VALUE *argv, VALUE self)
VALUE type, data;
rb_scan_args(argc, argv, "11", &type, &data);
- StringValue(type);
+ md = GetDigestPtr(type);
if (!NIL_P(data)) StringValue(data);
- name = StringValuePtr(type);
-
- md = EVP_get_digestbyname(name);
- if (!md) {
- ossl_raise(rb_eRuntimeError, "Unsupported digest algorithm (%s).", name);
- }
+
GetDigest(self, ctx);
EVP_DigestInit_ex(ctx, md, NULL);
@@ -118,6 +127,11 @@ ossl_digest_copy(VALUE self, VALUE other)
return self;
}
+/*
+ * call-seq:
+ * digest.reset -> self
+ *
+ */
static VALUE
ossl_digest_reset(VALUE self)
{
@@ -129,6 +143,11 @@ ossl_digest_reset(VALUE self)
return self;
}
+/*
+ * call-seq:
+ * digest.update(string) -> aString
+ *
+ */
VALUE
ossl_digest_update(VALUE self, VALUE data)
{
@@ -136,126 +155,77 @@ ossl_digest_update(VALUE self, VALUE data)
StringValue(data);
GetDigest(self, ctx);
- EVP_DigestUpdate(ctx, RSTRING(data)->ptr, RSTRING(data)->len);
+ EVP_DigestUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data));
return self;
}
-static void
-digest_final(EVP_MD_CTX *ctx, char **buf, int *buf_len)
-{
- EVP_MD_CTX final;
-
- if (!EVP_MD_CTX_copy(&final, ctx)) {
- ossl_raise(eDigestError, NULL);
- }
- if (!(*buf = OPENSSL_malloc(EVP_MD_CTX_size(&final)))) {
- EVP_MD_CTX_cleanup(&final);
- ossl_raise(eDigestError, "Cannot allocate mem for digest");
- }
- EVP_DigestFinal_ex(&final, *buf, buf_len);
- EVP_MD_CTX_cleanup(&final);
-}
-
+/*
+ * call-seq:
+ * digest.finish -> aString
+ *
+ */
static VALUE
-ossl_digest_digest(VALUE self)
+ossl_digest_finish(int argc, VALUE *argv, VALUE self)
{
EVP_MD_CTX *ctx;
- char *buf;
- int buf_len;
- VALUE digest;
-
- GetDigest(self, ctx);
- digest_final(ctx, &buf, &buf_len);
- digest = ossl_buf2str(buf, buf_len);
-
- return digest;
-}
+ VALUE str;
-static VALUE
-ossl_digest_hexdigest(VALUE self)
-{
- EVP_MD_CTX *ctx;
- char *buf, *hexbuf;
- int buf_len;
- VALUE hexdigest;
+ rb_scan_args(argc, argv, "01", &str);
GetDigest(self, ctx);
- digest_final(ctx, &buf, &buf_len);
- if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * buf_len) {
- OPENSSL_free(buf);
- ossl_raise(eDigestError, "Memory alloc error");
- }
- OPENSSL_free(buf);
- hexdigest = ossl_buf2str(hexbuf, 2 * buf_len);
-
- return hexdigest;
-}
-
-static VALUE
-ossl_digest_s_digest(VALUE klass, VALUE str, VALUE data)
-{
- VALUE obj = rb_class_new_instance(1, &str, klass);
-
- ossl_digest_update(obj, data);
- return ossl_digest_digest(obj);
-}
-
-static VALUE
-ossl_digest_s_hexdigest(VALUE klass, VALUE str, VALUE data)
-{
- VALUE obj = rb_class_new_instance(1, &str, klass);
+ if (NIL_P(str)) {
+ str = rb_str_new(NULL, EVP_MD_CTX_size(ctx));
+ } else {
+ StringValue(str);
+ rb_str_resize(str, EVP_MD_CTX_size(ctx));
+ }
- ossl_digest_update(obj, data);
+ EVP_DigestFinal_ex(ctx, RSTRING_PTR(str), NULL);
- return ossl_digest_hexdigest(obj);
+ return str;
}
+/*
+ * call-seq:
+ * digest.name -> string
+ *
+ */
static VALUE
-ossl_digest_equal(VALUE self, VALUE other)
+ossl_digest_name(VALUE self)
{
EVP_MD_CTX *ctx;
- VALUE str1, str2;
- if (rb_obj_is_kind_of(other, cDigest) == Qtrue) {
- str2 = ossl_digest_digest(other);
- } else {
- StringValue(other);
- str2 = other;
- }
GetDigest(self, ctx);
- if (RSTRING(str2)->len == EVP_MD_CTX_size(ctx)) {
- str1 = ossl_digest_digest(self);
- } else {
- str1 = ossl_digest_hexdigest(self);
- }
- if (RSTRING(str1)->len == RSTRING(str2)->len
- && rb_str_cmp(str1, str2) == 0) {
- return Qtrue;
- }
- return Qfalse;
+ return rb_str_new2(EVP_MD_name(EVP_MD_CTX_md(ctx)));
}
+/*
+ * call-seq:
+ * digest.digest_size -> integer
+ *
+ * Returns the output size of the digest.
+ */
static VALUE
-ossl_digest_name(VALUE self)
+ossl_digest_size(VALUE self)
{
EVP_MD_CTX *ctx;
GetDigest(self, ctx);
- return rb_str_new2(EVP_MD_name(EVP_MD_CTX_md(ctx)));
+ return INT2NUM(EVP_MD_CTX_size(ctx));
}
static VALUE
-ossl_digest_size(VALUE self)
+ossl_digest_block_length(VALUE self)
{
EVP_MD_CTX *ctx;
GetDigest(self, ctx);
- return INT2NUM(EVP_MD_CTX_size(ctx));
+ return INT2NUM(EVP_MD_CTX_block_size(ctx));
}
/*
@@ -264,31 +234,26 @@ ossl_digest_size(VALUE self)
void
Init_ossl_digest()
{
- mDigest = rb_define_module_under(mOSSL, "Digest");
-
- eDigestError = rb_define_class_under(mDigest, "DigestError", eOSSLError);
-
- cDigest = rb_define_class_under(mDigest, "Digest", rb_cObject);
+ rb_require("openssl");
+ rb_require("digest");
+
+#if 0 /* let rdoc know about mOSSL */
+ mOSSL = rb_define_module("OpenSSL");
+#endif
+
+ cDigest = rb_define_class_under(mOSSL, "Digest", rb_path2class("Digest::Class"));
+ eDigestError = rb_define_class_under(cDigest, "DigestError", eOSSLError);
rb_define_alloc_func(cDigest, ossl_digest_alloc);
- rb_define_singleton_method(cDigest, "digest", ossl_digest_s_digest, 2);
- rb_define_singleton_method(cDigest, "hexdigest", ossl_digest_s_hexdigest, 2);
-
+
rb_define_method(cDigest, "initialize", ossl_digest_initialize, -1);
- rb_define_method(cDigest, "reset", ossl_digest_reset, 0);
-
rb_define_copy_func(cDigest, ossl_digest_copy);
-
- rb_define_method(cDigest, "digest", ossl_digest_digest, 0);
- rb_define_method(cDigest, "hexdigest", ossl_digest_hexdigest, 0);
- rb_define_alias(cDigest, "inspect", "hexdigest");
- rb_define_alias(cDigest, "to_s", "hexdigest");
-
+ rb_define_method(cDigest, "reset", ossl_digest_reset, 0);
rb_define_method(cDigest, "update", ossl_digest_update, 1);
rb_define_alias(cDigest, "<<", "update");
-
- rb_define_method(cDigest, "==", ossl_digest_equal, 1);
-
+ rb_define_private_method(cDigest, "finish", ossl_digest_finish, -1);
+ rb_define_method(cDigest, "digest_length", ossl_digest_size, 0);
+ rb_define_method(cDigest, "block_length", ossl_digest_block_length, 0);
+
rb_define_method(cDigest, "name", ossl_digest_name, 0);
- rb_define_method(cDigest, "size", ossl_digest_size, 0);
}
diff --git a/ext/openssl/ossl_digest.h b/ext/openssl/ossl_digest.h
index b35bd217b3..8cc5b1bc56 100644
--- a/ext/openssl/ossl_digest.h
+++ b/ext/openssl/ossl_digest.h
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_digest.h,v 1.2 2003/09/05 09:08:40 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -11,7 +11,6 @@
#if !defined(_OSSL_DIGEST_H_)
#define _OSSL_DIGEST_H_
-extern VALUE mDigest;
extern VALUE cDigest;
extern VALUE eDigestError;
diff --git a/ext/openssl/ossl_engine.c b/ext/openssl/ossl_engine.c
index 6cc0183c0e..c6fc603a1e 100644
--- a/ext/openssl/ossl_engine.c
+++ b/ext/openssl/ossl_engine.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_engine.c,v 1.4.2.6 2005/09/18 22:56:11 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2003 GOTOU Yuuzou <gotoyuzo@notwork.org>
* All rights reserved.
@@ -40,7 +40,7 @@ VALUE eEngineError;
*/
#define OSSL_ENGINE_LOAD_IF_MATCH(x) \
do{\
- if(!strcmp(#x, RSTRING(name)->ptr)){\
+ if(!strcmp(#x, RSTRING_PTR(name))){\
ENGINE_load_##x();\
return Qtrue;\
}\
@@ -61,21 +61,39 @@ ossl_engine_s_load(int argc, VALUE *argv, VALUE klass)
}
StringValue(name);
#ifndef OPENSSL_NO_STATIC_ENGINE
+#if HAVE_ENGINE_LOAD_DYNAMIC
OSSL_ENGINE_LOAD_IF_MATCH(dynamic);
+#endif
+#if HAVE_ENGINE_LOAD_CSWIFT
OSSL_ENGINE_LOAD_IF_MATCH(cswift);
+#endif
+#if HAVE_ENGINE_LOAD_CHIL
OSSL_ENGINE_LOAD_IF_MATCH(chil);
+#endif
+#if HAVE_ENGINE_LOAD_ATALLA
OSSL_ENGINE_LOAD_IF_MATCH(atalla);
+#endif
+#if HAVE_ENGINE_LOAD_NURON
OSSL_ENGINE_LOAD_IF_MATCH(nuron);
+#endif
+#if HAVE_ENGINE_LOAD_UBSEC
OSSL_ENGINE_LOAD_IF_MATCH(ubsec);
+#endif
+#if HAVE_ENGINE_LOAD_AEP
OSSL_ENGINE_LOAD_IF_MATCH(aep);
+#endif
+#if HAVE_ENGINE_LOAD_SUREWARE
OSSL_ENGINE_LOAD_IF_MATCH(sureware);
+#endif
+#if HAVE_ENGINE_LOAD_4758CCA
OSSL_ENGINE_LOAD_IF_MATCH(4758cca);
#endif
+#endif
#ifdef HAVE_ENGINE_LOAD_OPENBSD_DEV_CRYPTO
OSSL_ENGINE_LOAD_IF_MATCH(openbsd_dev_crypto);
#endif
OSSL_ENGINE_LOAD_IF_MATCH(openssl);
- rb_warning("no such builtin loader for `%s'", RSTRING(name)->ptr);
+ rb_warning("no such builtin loader for `%s'", RSTRING_PTR(name));
return Qnil;
#endif /* HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
}
@@ -112,14 +130,14 @@ ossl_engine_s_by_id(VALUE klass, VALUE id)
StringValue(id);
ossl_engine_s_load(1, &id, klass);
- if(!(e = ENGINE_by_id(RSTRING(id)->ptr)))
+ if(!(e = ENGINE_by_id(RSTRING_PTR(id))))
ossl_raise(eEngineError, NULL);
WrapEngine(klass, obj, e);
if(rb_block_given_p()) rb_yield(obj);
if(!ENGINE_init(e))
ossl_raise(eEngineError, NULL);
ENGINE_ctrl(e, ENGINE_CTRL_SET_PASSWORD_CALLBACK,
- 0, NULL, (void(*)())ossl_pem_passwd_cb);
+ 0, NULL, (void(*)(void))ossl_pem_passwd_cb);
ERR_clear_error();
return obj;
@@ -281,8 +299,8 @@ ossl_engine_ctrl_cmd(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "11", &cmd, &val);
StringValue(cmd);
if (!NIL_P(val)) StringValue(val);
- ret = ENGINE_ctrl_cmd_string(e, RSTRING(cmd)->ptr,
- NIL_P(val) ? NULL : RSTRING(val)->ptr, 0);
+ ret = ENGINE_ctrl_cmd_string(e, RSTRING_PTR(cmd),
+ NIL_P(val) ? NULL : RSTRING_PTR(val), 0);
if (!ret) ossl_raise(eEngineError, NULL);
return self;
diff --git a/ext/openssl/ossl_engine.h b/ext/openssl/ossl_engine.h
index ccc426481a..ea2f256912 100644
--- a/ext/openssl/ossl_engine.h
+++ b/ext/openssl/ossl_engine.h
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_engine.h,v 1.1 2003/10/02 08:47:11 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2003 Michal Rokos <m.rokos@sh.cvut.cz>
* Copyright (C) 2003 GOTOU Yuuzou <gotoyuzo@notwork.org>
diff --git a/ext/openssl/ossl_hmac.c b/ext/openssl/ossl_hmac.c
index cd66ab6e2c..f8098bb9c3 100644
--- a/ext/openssl/ossl_hmac.c
+++ b/ext/openssl/ossl_hmac.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_hmac.c,v 1.4.2.2 2004/12/15 01:54:39 matz Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -42,7 +42,7 @@ static void
ossl_hmac_free(HMAC_CTX *ctx)
{
HMAC_CTX_cleanup(ctx);
- free(ctx);
+ ruby_xfree(ctx);
}
static VALUE
@@ -57,6 +57,12 @@ ossl_hmac_alloc(VALUE klass)
return obj;
}
+
+/*
+ * call-seq:
+ * HMAC.new(key, digest) -> hmac
+ *
+ */
static VALUE
ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest)
{
@@ -64,7 +70,7 @@ ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest)
StringValue(key);
GetHMAC(self, ctx);
- HMAC_Init_ex(ctx, RSTRING(key)->ptr, RSTRING(key)->len,
+ HMAC_Init_ex(ctx, RSTRING_PTR(key), RSTRING_LEN(key),
GetDigestPtr(digest), NULL);
return self;
@@ -81,12 +87,15 @@ ossl_hmac_copy(VALUE self, VALUE other)
GetHMAC(self, ctx1);
SafeGetHMAC(other, ctx2);
- if (!HMAC_CTX_copy(ctx1, ctx2)) {
- ossl_raise(eHMACError, NULL);
- }
+ HMAC_CTX_copy(ctx1, ctx2);
return self;
}
+/*
+ * call-seq:
+ * hmac.update(string) -> self
+ *
+ */
static VALUE
ossl_hmac_update(VALUE self, VALUE data)
{
@@ -94,7 +103,7 @@ ossl_hmac_update(VALUE self, VALUE data)
StringValue(data);
GetHMAC(self, ctx);
- HMAC_Update(ctx, RSTRING(data)->ptr, RSTRING(data)->len);
+ HMAC_Update(ctx, RSTRING_PTR(data), RSTRING_LEN(data));
return self;
}
@@ -104,9 +113,7 @@ hmac_final(HMAC_CTX *ctx, char **buf, int *buf_len)
{
HMAC_CTX final;
- if (!HMAC_CTX_copy(&final, ctx)) {
- ossl_raise(eHMACError, NULL);
- }
+ HMAC_CTX_copy(&final, ctx);
if (!(*buf = OPENSSL_malloc(HMAC_size(&final)))) {
HMAC_CTX_cleanup(&final);
OSSL_Debug("Allocating %d mem", HMAC_size(&final));
@@ -116,6 +123,11 @@ hmac_final(HMAC_CTX *ctx, char **buf, int *buf_len)
HMAC_CTX_cleanup(&final);
}
+/*
+ * call-seq:
+ * hmac.digest -> aString
+ *
+ */
static VALUE
ossl_hmac_digest(VALUE self)
{
@@ -131,6 +143,11 @@ ossl_hmac_digest(VALUE self)
return digest;
}
+/*
+ * call-seq:
+ * hmac.hexdigest -> aString
+ *
+ */
static VALUE
ossl_hmac_hexdigest(VALUE self)
{
@@ -151,6 +168,27 @@ ossl_hmac_hexdigest(VALUE self)
return hexdigest;
}
+/*
+ * call-seq:
+ * hmac.reset -> self
+ *
+ */
+static VALUE
+ossl_hmac_reset(VALUE self)
+{
+ HMAC_CTX *ctx;
+
+ GetHMAC(self, ctx);
+ HMAC_Init_ex(ctx, NULL, 0, NULL, NULL);
+
+ return self;
+}
+
+/*
+ * call-seq:
+ * HMAC.digest(digest, key, data) -> aString
+ *
+ */
static VALUE
ossl_hmac_s_digest(VALUE klass, VALUE digest, VALUE key, VALUE data)
{
@@ -159,12 +197,17 @@ ossl_hmac_s_digest(VALUE klass, VALUE digest, VALUE key, VALUE data)
StringValue(key);
StringValue(data);
- buf = HMAC(GetDigestPtr(digest), RSTRING(key)->ptr, RSTRING(key)->len,
- RSTRING(data)->ptr, RSTRING(data)->len, NULL, &buf_len);
+ buf = HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LEN(key),
+ RSTRING_PTR(data), RSTRING_LEN(data), NULL, &buf_len);
return rb_str_new(buf, buf_len);
}
+/*
+ * call-seq:
+ * HMAC.digest(digest, key, data) -> aString
+ *
+ */
static VALUE
ossl_hmac_s_hexdigest(VALUE klass, VALUE digest, VALUE key, VALUE data)
{
@@ -175,8 +218,8 @@ ossl_hmac_s_hexdigest(VALUE klass, VALUE digest, VALUE key, VALUE data)
StringValue(key);
StringValue(data);
- buf = HMAC(GetDigestPtr(digest), RSTRING(key)->ptr, RSTRING(key)->len,
- RSTRING(data)->ptr, RSTRING(data)->len, NULL, &buf_len);
+ buf = HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LEN(key),
+ RSTRING_PTR(data), RSTRING_LEN(data), NULL, &buf_len);
if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * buf_len) {
ossl_raise(eHMACError, "Cannot convert buf to hexbuf");
}
@@ -191,6 +234,10 @@ ossl_hmac_s_hexdigest(VALUE klass, VALUE digest, VALUE key, VALUE data)
void
Init_ossl_hmac()
{
+#if 0 /* let rdoc know about mOSSL */
+ mOSSL = rb_define_module("OpenSSL");
+#endif
+
eHMACError = rb_define_class_under(mOSSL, "HMACError", eOSSLError);
cHMAC = rb_define_class_under(mOSSL, "HMAC", rb_cObject);
@@ -202,6 +249,7 @@ Init_ossl_hmac()
rb_define_method(cHMAC, "initialize", ossl_hmac_initialize, 2);
rb_define_copy_func(cHMAC, ossl_hmac_copy);
+ rb_define_method(cHMAC, "reset", ossl_hmac_reset, 0);
rb_define_method(cHMAC, "update", ossl_hmac_update, 1);
rb_define_alias(cHMAC, "<<", "update");
rb_define_method(cHMAC, "digest", ossl_hmac_digest, 0);
diff --git a/ext/openssl/ossl_hmac.h b/ext/openssl/ossl_hmac.h
index 2c8d69c177..1a2978b39a 100644
--- a/ext/openssl/ossl_hmac.h
+++ b/ext/openssl/ossl_hmac.h
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_hmac.h,v 1.1 2003/07/23 16:11:29 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
diff --git a/ext/openssl/ossl_ns_spki.c b/ext/openssl/ossl_ns_spki.c
index bd8c59faf9..738a203d93 100644
--- a/ext/openssl/ossl_ns_spki.c
+++ b/ext/openssl/ossl_ns_spki.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_ns_spki.c,v 1.3.2.5 2006/03/17 10:10:53 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -62,14 +62,15 @@ ossl_spki_initialize(int argc, VALUE *argv, VALUE self)
return self;
}
StringValue(buffer);
- if (!(spki = NETSCAPE_SPKI_b64_decode(RSTRING(buffer)->ptr, -1))) {
- p = RSTRING(buffer)->ptr;
- if (!(spki = d2i_NETSCAPE_SPKI(NULL, &p, RSTRING(buffer)->len))) {
+ if (!(spki = NETSCAPE_SPKI_b64_decode(RSTRING_PTR(buffer), -1))) {
+ p = RSTRING_PTR(buffer);
+ if (!(spki = d2i_NETSCAPE_SPKI(NULL, &p, RSTRING_LEN(buffer)))) {
ossl_raise(eSPKIError, NULL);
}
}
NETSCAPE_SPKI_free(DATA_PTR(self));
DATA_PTR(self) = spki;
+ ERR_clear_error();
return self;
}
@@ -86,7 +87,7 @@ ossl_spki_to_der(VALUE self)
if ((len = i2d_NETSCAPE_SPKI(spki, NULL)) <= 0)
ossl_raise(eX509CertError, NULL);
str = rb_str_new(0, len);
- p = RSTRING(str)->ptr;
+ p = RSTRING_PTR(str);
if (i2d_NETSCAPE_SPKI(spki, &p) <= 0)
ossl_raise(eX509CertError, NULL);
ossl_str_adjust(str, p);
@@ -182,8 +183,8 @@ ossl_spki_set_challenge(VALUE self, VALUE str)
StringValue(str);
GetSPKI(self, spki);
- if (!ASN1_STRING_set(spki->spkac->challenge, RSTRING(str)->ptr,
- RSTRING(str)->len)) {
+ if (!ASN1_STRING_set(spki->spkac->challenge, RSTRING_PTR(str),
+ RSTRING_LEN(str))) {
ossl_raise(eSPKIError, NULL);
}
diff --git a/ext/openssl/ossl_ns_spki.h b/ext/openssl/ossl_ns_spki.h
index 2ca1fdcd62..9977035a9c 100644
--- a/ext/openssl/ossl_ns_spki.h
+++ b/ext/openssl/ossl_ns_spki.h
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_ns_spki.h,v 1.1 2003/07/23 16:11:29 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
diff --git a/ext/openssl/ossl_ocsp.c b/ext/openssl/ossl_ocsp.c
index f2097b967e..a6618ffede 100644
--- a/ext/openssl/ossl_ocsp.c
+++ b/ext/openssl/ossl_ocsp.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_ocsp.c,v 1.4.2.2 2005/01/22 20:28:02 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2003 Michal Rokos <m.rokos@sh.cvut.cz>
* Copyright (C) 2003 GOTOU Yuuzou <gotoyuzo@notwork.org>
@@ -109,9 +109,9 @@ ossl_ocspreq_initialize(int argc, VALUE *argv, VALUE self)
if(!NIL_P(arg)){
arg = ossl_to_der_if_possible(arg);
StringValue(arg);
- p = (unsigned char*)RSTRING(arg)->ptr;
+ p = (unsigned char*)RSTRING_PTR(arg);
if(!d2i_OCSP_REQUEST((OCSP_REQUEST**)&DATA_PTR(self), &p,
- RSTRING(arg)->len)){
+ RSTRING_LEN(arg))){
ossl_raise(eOCSPError, "cannot load DER encoded request");
}
}
@@ -134,7 +134,7 @@ ossl_ocspreq_add_nonce(int argc, VALUE *argv, VALUE self)
else{
StringValue(val);
GetOCSPReq(self, req);
- ret = OCSP_request_add1_nonce(req, RSTRING(val)->ptr, RSTRING(val)->len);
+ ret = OCSP_request_add1_nonce(req, RSTRING_PTR(val), RSTRING_LEN(val));
}
if(!ret) ossl_raise(eOCSPError, NULL);
@@ -265,7 +265,7 @@ ossl_ocspreq_to_der(VALUE self)
if((len = i2d_OCSP_REQUEST(req, NULL)) <= 0)
ossl_raise(eOCSPError, NULL);
str = rb_str_new(0, len);
- p = RSTRING(str)->ptr;
+ p = RSTRING_PTR(str);
if(i2d_OCSP_REQUEST(req, &p) <= 0)
ossl_raise(eOCSPError, NULL);
ossl_str_adjust(str, p);
@@ -316,9 +316,9 @@ ossl_ocspres_initialize(int argc, VALUE *argv, VALUE self)
if(!NIL_P(arg)){
arg = ossl_to_der_if_possible(arg);
StringValue(arg);
- p = RSTRING(arg)->ptr;
+ p = RSTRING_PTR(arg);
if(!d2i_OCSP_RESPONSE((OCSP_RESPONSE**)&DATA_PTR(self), &p,
- RSTRING(arg)->len)){
+ RSTRING_LEN(arg))){
ossl_raise(eOCSPError, "cannot load DER encoded response");
}
}
@@ -377,8 +377,8 @@ ossl_ocspres_to_der(VALUE self)
if((len = i2d_OCSP_RESPONSE(res, NULL)) <= 0)
ossl_raise(eOCSPError, NULL);
str = rb_str_new(0, len);
- p = RSTRING(str)->ptr;
- if(i2d_OCSP_RESPONSE(res, NULL) <= 0)
+ p = RSTRING_PTR(str);
+ if(i2d_OCSP_RESPONSE(res, &p) <= 0)
ossl_raise(eOCSPError, NULL);
ossl_str_adjust(str, p);
@@ -436,7 +436,7 @@ ossl_ocspbres_add_nonce(int argc, VALUE *argv, VALUE self)
else{
StringValue(val);
GetOCSPBasicRes(self, bs);
- ret = OCSP_basic_add1_nonce(bs, RSTRING(val)->ptr, RSTRING(val)->len);
+ ret = OCSP_basic_add1_nonce(bs, RSTRING_PTR(val), RSTRING_LEN(val));
}
if(!ret) ossl_raise(eOCSPError, NULL);
@@ -461,8 +461,8 @@ ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status,
if(!NIL_P(ext)){
/* All ary's members should be X509Extension */
Check_Type(ext, T_ARRAY);
- for (i = 0; i < RARRAY(ext)->len; i++)
- OSSL_Check_Kind(RARRAY(ext)->ptr[i], cX509Ext);
+ for (i = 0; i < RARRAY_LEN(ext); i++)
+ OSSL_Check_Kind(RARRAY_PTR(ext)[i], cX509Ext);
}
error = 0;
@@ -490,8 +490,8 @@ ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status,
X509_EXTENSION *x509ext;
sk_X509_EXTENSION_pop_free(single->singleExtensions, X509_EXTENSION_free);
single->singleExtensions = NULL;
- for(i = 0; i < RARRAY(ext)->len; i++){
- x509ext = DupX509ExtPtr(RARRAY(ext)->ptr[i]);
+ for(i = 0; i < RARRAY_LEN(ext); i++){
+ x509ext = DupX509ExtPtr(RARRAY_PTR(ext)[i]);
if(!OCSP_SINGLERESP_add_ext(single, x509ext, -1)){
X509_EXTENSION_free(x509ext);
error = 1;
@@ -589,22 +589,22 @@ ossl_ocspbres_sign(int argc, VALUE *argv, VALUE self)
static VALUE
ossl_ocspbres_verify(int argc, VALUE *argv, VALUE self)
{
- VALUE certs, store, flags;
+ VALUE certs, store, flags, result;
OCSP_BASICRESP *bs;
STACK_OF(X509) *x509s;
X509_STORE *x509st;
- int flg, result;
+ int flg;
rb_scan_args(argc, argv, "21", &certs, &store, &flags);
x509st = GetX509StorePtr(store);
flg = NIL_P(flags) ? 0 : INT2NUM(flags);
x509s = ossl_x509_ary2sk(certs);
GetOCSPBasicRes(self, bs);
- result = OCSP_basic_verify(bs, x509s, x509st, flg);
+ result = OCSP_basic_verify(bs, x509s, x509st, flg) > 0 ? Qtrue : Qfalse;
sk_X509_pop_free(x509s, X509_free);
if(!result) rb_warn("%s", ERR_error_string(ERR_peek_error(), NULL));
- return result ? Qtrue : Qfalse;
+ return result;
}
/*
@@ -681,7 +681,7 @@ Init_ossl_ocsp()
{
mOCSP = rb_define_module_under(mOSSL, "OCSP");
- eOCSPError = rb_define_class_under(mOCSP, "OCSPError", rb_cObject);
+ eOCSPError = rb_define_class_under(mOCSP, "OCSPError", eOSSLError);
cOCSPReq = rb_define_class_under(mOCSP, "Request", rb_cObject);
rb_define_alloc_func(cOCSPReq, ossl_ocspreq_alloc);
diff --git a/ext/openssl/ossl_ocsp.h b/ext/openssl/ossl_ocsp.h
index 244fbb2a74..65b4f2e23f 100644
--- a/ext/openssl/ossl_ocsp.h
+++ b/ext/openssl/ossl_ocsp.h
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_ocsp.h,v 1.1 2003/07/23 16:11:29 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2003 Michal Rokos <m.rokos@sh.cvut.cz>
* Copyright (C) 2003 GOTOU Yuuzou <gotoyuzo@notwork.org>
diff --git a/ext/openssl/ossl_pkcs12.c b/ext/openssl/ossl_pkcs12.c
index e4b334c67e..2ec69ba8db 100644
--- a/ext/openssl/ossl_pkcs12.c
+++ b/ext/openssl/ossl_pkcs12.c
@@ -1,7 +1,7 @@
/*
* This program is licenced under the same licence as Ruby.
* (See the file 'LICENCE'.)
- * $Id: ossl_pkcs12.c,v 1.2 2003/12/15 00:30:12 usa Exp $
+ * $Id$
*/
#include "ossl.h"
@@ -30,7 +30,6 @@
/*
* Classes
*/
-VALUE mPKCS12;
VALUE cPKCS12;
VALUE ePKCS12Error;
@@ -49,32 +48,85 @@ ossl_pkcs12_s_allocate(VALUE klass)
return obj;
}
+/*
+ * call-seq:
+ * PKCS12.create(pass, name, key, cert [, ca, [, key_pbe [, cert_pbe [, key_iter [, mac_iter [, keytype]]]]]])
+ *
+ * === Parameters
+ * * +pass+ - string
+ * * +name+ - A string describing the key.
+ * * +key+ - Any PKey.
+ * * +cert+ - A X509::Certificate.
+ * * * The public_key portion of the certificate must contain a valid public key.
+ * * * The not_before and not_after fields must be filled in.
+ * * +ca+ - An optional array of X509::Certificate's.
+ * * +key_pbe+ - string
+ * * +cert_pbe+ - string
+ * * +key_iter+ - integer
+ * * +mac_iter+ - integer
+ * * +keytype+ - An integer representing an MSIE specific extension.
+ *
+ * Any optional arguments may be supplied as nil to preserve the OpenSSL defaults.
+ *
+ * See the OpenSSL documentation for PKCS12_create().
+ */
static VALUE
ossl_pkcs12_s_create(int argc, VALUE *argv, VALUE self)
{
- VALUE pass, name, pkey, cert, ca;
+ VALUE pass, name, pkey, cert, ca, key_nid, cert_nid, key_iter, mac_iter, keytype;
VALUE obj;
char *passphrase, *friendlyname;
EVP_PKEY *key;
X509 *x509;
STACK_OF(X509) *x509s;
+ int nkey = 0, ncert = 0, kiter = 0, miter = 0, ktype = 0;
PKCS12 *p12;
- rb_scan_args(argc, argv, "41", &pass, &name, &pkey, &cert, &ca);
+ rb_scan_args(argc, argv, "46", &pass, &name, &pkey, &cert, &ca, &key_nid, &cert_nid, &key_iter, &mac_iter, &keytype);
passphrase = NIL_P(pass) ? NULL : StringValuePtr(pass);
friendlyname = NIL_P(name) ? NULL : StringValuePtr(name);
key = GetPKeyPtr(pkey);
x509 = GetX509CertPtr(cert);
x509s = NIL_P(ca) ? NULL : ossl_x509_ary2sk(ca);
+/* TODO: make a VALUE to nid function */
+ if (!NIL_P(key_nid)) {
+ if ((nkey = OBJ_txt2nid(StringValuePtr(key_nid))) == NID_undef)
+ rb_raise(rb_eArgError, "Unknown PBE algorithm %s", StringValuePtr(key_nid));
+ }
+ if (!NIL_P(cert_nid)) {
+ if ((ncert = OBJ_txt2nid(StringValuePtr(cert_nid))) == NID_undef)
+ rb_raise(rb_eArgError, "Unknown PBE algorithm %s", StringValuePtr(cert_nid));
+ }
+ if (!NIL_P(key_iter))
+ kiter = NUM2INT(key_iter);
+ if (!NIL_P(mac_iter))
+ miter = NUM2INT(mac_iter);
+ if (!NIL_P(keytype))
+ ktype = NUM2INT(keytype);
+
p12 = PKCS12_create(passphrase, friendlyname, key, x509, x509s,
- 0, 0, 0, 0, 0);
+ nkey, ncert, kiter, miter, ktype);
sk_X509_pop_free(x509s, X509_free);
if(!p12) ossl_raise(ePKCS12Error, NULL);
WrapPKCS12(cPKCS12, obj, p12);
+ ossl_pkcs12_set_key(obj, pkey);
+ ossl_pkcs12_set_cert(obj, cert);
+ ossl_pkcs12_set_ca_certs(obj, ca);
+
return obj;
}
+/*
+ * call-seq:
+ * PKCS12.new -> pkcs12
+ * PKCS12.new(str) -> pkcs12
+ * PKCS12.new(str, pass) -> pkcs12
+ *
+ * === Parameters
+ * * +str+ - Must be a DER encoded PKCS12 string.
+ * * +pass+ - string
+ */
static VALUE
ossl_pkcs12_initialize(int argc, VALUE *argv, VALUE self)
{
@@ -94,7 +146,7 @@ ossl_pkcs12_initialize(int argc, VALUE *argv, VALUE self)
pkey = cert = ca = Qnil;
if(!PKCS12_parse((PKCS12*)DATA_PTR(self), passphrase, &key, &x509, &x509s))
- ossl_raise(ePKCS12Error, NULL);
+ ossl_raise(ePKCS12Error, "PKCS12_parse");
pkey = rb_protect((VALUE(*)_((VALUE)))ossl_pkey_new, (VALUE)key,
&st); /* NO DUP */
if(st) goto err;
@@ -129,7 +181,7 @@ ossl_pkcs12_to_der(VALUE self)
if((len = i2d_PKCS12(p12, NULL)) <= 0)
ossl_raise(ePKCS12Error, NULL);
str = rb_str_new(0, len);
- p = RSTRING(str)->ptr;
+ p = RSTRING_PTR(str);
if(i2d_PKCS12(p12, &p) <= 0)
ossl_raise(ePKCS12Error, NULL);
ossl_str_adjust(str, p);
@@ -140,10 +192,14 @@ ossl_pkcs12_to_der(VALUE self)
void
Init_ossl_pkcs12()
{
- mPKCS12 = rb_define_module_under(mOSSL, "PKCS12");
- cPKCS12 = rb_define_class_under(mPKCS12, "PKCS12", rb_cObject);
- ePKCS12Error = rb_define_class_under(mPKCS12, "PKCS12Error", eOSSLError);
- rb_define_module_function(mPKCS12, "create", ossl_pkcs12_s_create, -1);
+ /*
+ * Defines a file format commonly used to store private keys with
+ * accompanying public key certificates, protected with a password-based
+ * symmetric key.
+ */
+ cPKCS12 = rb_define_class_under(mOSSL, "PKCS12", rb_cObject);
+ ePKCS12Error = rb_define_class_under(cPKCS12, "PKCS12Error", eOSSLError);
+ rb_define_singleton_method(cPKCS12, "create", ossl_pkcs12_s_create, -1);
rb_define_alloc_func(cPKCS12, ossl_pkcs12_s_allocate);
rb_attr(cPKCS12, rb_intern("key"), 1, 0, Qfalse);
diff --git a/ext/openssl/ossl_pkcs12.h b/ext/openssl/ossl_pkcs12.h
index 95b29de9b5..24d25d00bb 100644
--- a/ext/openssl/ossl_pkcs12.h
+++ b/ext/openssl/ossl_pkcs12.h
@@ -1,12 +1,11 @@
/*
* This program is licenced under the same licence as Ruby.
* (See the file 'LICENCE'.)
- * $Id: ossl_pkcs12.h,v 1.1.2.1 2005/06/19 16:29:17 gotoyuzo Exp $
+ * $Id$
*/
#if !defined(_OSSL_PKCS12_H_)
#define _OSSL_PKCS12_H_
-extern VALUE mPKCS12;
extern VALUE cPKCS12;
extern VALUE ePKCS12Error;
diff --git a/ext/openssl/ossl_pkcs5.c b/ext/openssl/ossl_pkcs5.c
new file mode 100644
index 0000000000..39ba013839
--- /dev/null
+++ b/ext/openssl/ossl_pkcs5.c
@@ -0,0 +1,99 @@
+/*
+ * $Id$
+ * Copyright (C) 2007 Technorama Ltd. <oss-ruby@technorama.net>
+ */
+#include "ossl.h"
+
+VALUE mPKCS5;
+VALUE ePKCS5;
+
+/*
+ * call-seq:
+ * PKCS5.pbkdf2_hmac(pass, salt, iter, keylen, digest) => string
+ *
+ * === Parameters
+ * * +pass+ - string
+ * * +salt+ - string
+ * * +iter+ - integer - should be greater than 1000. 2000 is better.
+ * * +keylen+ - integer
+ * * +digest+ - a string or OpenSSL::Digest object.
+ *
+ * Available in OpenSSL 0.9.9?.
+ *
+ * Digests other than SHA1 may not be supported by other cryptography libraries.
+ */
+static VALUE
+ossl_pkcs5_pbkdf2_hmac(VALUE self, VALUE pass, VALUE salt, VALUE iter, VALUE keylen, VALUE digest)
+{
+#ifdef HAVE_PKCS5_PBKDF2_HMAC
+ VALUE str;
+ const EVP_MD *md;
+ int len = NUM2INT(keylen);
+ unsigned char* salt_p;
+ unsigned char* str_p;
+
+ StringValue(pass);
+ StringValue(salt);
+ md = GetDigestPtr(digest);
+ str = rb_str_new(0, len);
+ salt_p = (unsigned char*)RSTRING_PTR(salt);
+ str_p = (unsigned char*)RSTRING_PTR(str);
+
+ if (PKCS5_PBKDF2_HMAC(RSTRING_PTR(pass), RSTRING_LEN(pass), salt_p, RSTRING_LEN(salt), NUM2INT(iter), md, len, str_p) != 1)
+ ossl_raise(ePKCS5, "PKCS5_PBKDF2_HMAC");
+
+ return str;
+#else
+ rb_notimplement();
+#endif
+}
+
+
+/*
+ * call-seq:
+ * PKCS5.pbkdf2_hmac_sha1(pass, salt, iter, keylen) => string
+ *
+ * === Parameters
+ * * +pass+ - string
+ * * +salt+ - string
+ * * +iter+ - integer - should be greater than 1000. 2000 is better.
+ * * +keylen+ - integer
+ *
+ * This method is available almost any version OpenSSL.
+ *
+ * Conforms to rfc2898.
+ */
+static VALUE
+ossl_pkcs5_pbkdf2_hmac_sha1(VALUE self, VALUE pass, VALUE salt, VALUE iter, VALUE keylen)
+{
+#ifdef HAVE_PKCS5_PBKDF2_HMAC_SHA1
+ VALUE str;
+ int len = NUM2INT(keylen);
+
+ StringValue(pass);
+ StringValue(salt);
+
+ str = rb_str_new(0, len);
+
+ if (PKCS5_PBKDF2_HMAC_SHA1(RSTRING_PTR(pass), RSTRING_LEN(pass), RSTRING_PTR(salt), RSTRING_LEN(salt), NUM2INT(iter), len, RSTRING_PTR(str)) != 1)
+ ossl_raise(ePKCS5, "PKCS5_PBKDF2_HMAC_SHA1");
+
+ return str;
+#else
+ rb_notimplement();
+#endif
+}
+
+void
+Init_ossl_pkcs5()
+{
+ /*
+ * Password-based Encryption
+ *
+ */
+ mPKCS5 = rb_define_module_under(mOSSL, "PKCS5");
+ ePKCS5 = rb_define_class_under(mPKCS5, "PKCS5Error", eOSSLError);
+
+ rb_define_module_function(mPKCS5, "pbkdf2_hmac", ossl_pkcs5_pbkdf2_hmac, 5);
+ rb_define_module_function(mPKCS5, "pbkdf2_hmac_sha1", ossl_pkcs5_pbkdf2_hmac_sha1, 4);
+}
diff --git a/ext/openssl/ossl_pkcs7.c b/ext/openssl/ossl_pkcs7.c
index 0fa85299aa..5177f5c1e5 100644
--- a/ext/openssl/ossl_pkcs7.c
+++ b/ext/openssl/ossl_pkcs7.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_pkcs7.c,v 1.5.2.3 2005/09/10 01:11:15 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -71,7 +71,6 @@
/*
* Classes
*/
-VALUE mPKCS7;
VALUE cPKCS7;
VALUE cPKCS7Signer;
VALUE cPKCS7Recipient;
@@ -134,7 +133,8 @@ DupPKCS7RecipientPtr(VALUE obj)
}
/*
- * Private
+ * call-seq:
+ * PKCS7.read_smime(string) => pkcs7
*/
static VALUE
ossl_pkcs7_s_read_smime(VALUE klass, VALUE arg)
@@ -156,6 +156,10 @@ ossl_pkcs7_s_read_smime(VALUE klass, VALUE arg)
return ret;
}
+/*
+ * call-seq:
+ * PKCS7.write_smime(pkcs7 [, data [, flags]]) => string
+ */
static VALUE
ossl_pkcs7_s_write_smime(int argc, VALUE *argv, VALUE klass)
{
@@ -187,6 +191,10 @@ ossl_pkcs7_s_write_smime(int argc, VALUE *argv, VALUE klass)
return str;
}
+/*
+ * call-seq:
+ * PKCS7.sign(cert, key, data, [, certs [, flags]]) => pkcs7
+ */
static VALUE
ossl_pkcs7_s_sign(int argc, VALUE *argv, VALUE klass)
{
@@ -226,6 +234,10 @@ ossl_pkcs7_s_sign(int argc, VALUE *argv, VALUE klass)
return ret;
}
+/*
+ * call-seq:
+ * PKCS7.encrypt(certs, data, [, cipher [, flags]]) => pkcs7
+ */
static VALUE
ossl_pkcs7_s_encrypt(int argc, VALUE *argv, VALUE klass)
{
@@ -287,6 +299,13 @@ ossl_pkcs7_alloc(VALUE klass)
return obj;
}
+/*
+ * call-seq:
+ * PKCS7.new => pkcs7
+ * PKCS7.new(string) => pkcs7
+ *
+ * Many methods in this class aren't documented.
+ */
static VALUE
ossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self)
{
@@ -335,7 +354,7 @@ static int
ossl_pkcs7_sym2typeid(VALUE sym)
{
int i, ret = Qnil;
- char *s;
+ const char *s;
static struct {
const char *name;
@@ -364,6 +383,10 @@ ossl_pkcs7_sym2typeid(VALUE sym)
return ret;
}
+/*
+ * call-seq:
+ * pkcs7.type = type => type
+ */
static VALUE
ossl_pkcs7_set_type(VALUE self, VALUE type)
{
@@ -376,6 +399,10 @@ ossl_pkcs7_set_type(VALUE self, VALUE type)
return type;
}
+/*
+ * call-seq:
+ * pkcs7.type => string or nil
+ */
static VALUE
ossl_pkcs7_get_type(VALUE self)
{
@@ -543,12 +570,11 @@ ossl_pkcs7_add_certificate(VALUE self, VALUE cert)
return self;
}
-static STACK *
-pkcs7_get_certs_or_crls(VALUE self, int want_certs)
+static STACK_OF(X509) *
+pkcs7_get_certs(VALUE self)
{
PKCS7 *pkcs7;
STACK_OF(X509) *certs;
- STACK_OF(X509_CRL) *crls;
int i;
GetPKCS7(self, pkcs7);
@@ -556,17 +582,38 @@ pkcs7_get_certs_or_crls(VALUE self, int want_certs)
switch(i){
case NID_pkcs7_signed:
certs = pkcs7->d.sign->cert;
- crls = pkcs7->d.sign->crl;
break;
case NID_pkcs7_signedAndEnveloped:
certs = pkcs7->d.signed_and_enveloped->cert;
+ break;
+ default:
+ certs = NULL;
+ }
+
+ return certs;
+}
+
+static STACK_OF(X509_CRL) *
+pkcs7_get_crls(VALUE self)
+{
+ PKCS7 *pkcs7;
+ STACK_OF(X509_CRL) *crls;
+ int i;
+
+ GetPKCS7(self, pkcs7);
+ i = OBJ_obj2nid(pkcs7->type);
+ switch(i){
+ case NID_pkcs7_signed:
+ crls = pkcs7->d.sign->crl;
+ break;
+ case NID_pkcs7_signedAndEnveloped:
crls = pkcs7->d.signed_and_enveloped->crl;
break;
default:
- certs = crls = NULL;
+ crls = NULL;
}
- return want_certs ? certs : crls;
+ return crls;
}
static VALUE
@@ -581,9 +628,9 @@ ossl_pkcs7_set_certificates(VALUE self, VALUE ary)
STACK_OF(X509) *certs;
X509 *cert;
- certs = pkcs7_get_certs_or_crls(self, 1);
+ certs = pkcs7_get_certs(self);
while((cert = sk_X509_pop(certs))) X509_free(cert);
- rb_iterate(rb_each, ary, ossl_pkcs7_set_certs_i, self);
+ rb_block_call(ary, rb_intern("each"), 0, 0, ossl_pkcs7_set_certs_i, self);
return ary;
}
@@ -591,7 +638,7 @@ ossl_pkcs7_set_certificates(VALUE self, VALUE ary)
static VALUE
ossl_pkcs7_get_certificates(VALUE self)
{
- return ossl_x509_sk2ary(pkcs7_get_certs_or_crls(self, 1));
+ return ossl_x509_sk2ary(pkcs7_get_certs(self));
}
static VALUE
@@ -621,9 +668,9 @@ ossl_pkcs7_set_crls(VALUE self, VALUE ary)
STACK_OF(X509_CRL) *crls;
X509_CRL *crl;
- crls = pkcs7_get_certs_or_crls(self, 0);
+ crls = pkcs7_get_crls(self);
while((crl = sk_X509_CRL_pop(crls))) X509_CRL_free(crl);
- rb_iterate(rb_each, ary, ossl_pkcs7_set_crls_i, self);
+ rb_block_call(ary, rb_intern("each"), 0, 0, ossl_pkcs7_set_crls_i, self);
return ary;
}
@@ -631,7 +678,7 @@ ossl_pkcs7_set_crls(VALUE self, VALUE ary)
static VALUE
ossl_pkcs7_get_crls(VALUE self)
{
- return ossl_x509crl_sk2ary(pkcs7_get_certs_or_crls(self, 0));
+ return ossl_x509crl_sk2ary(pkcs7_get_crls(self));
}
static VALUE
@@ -667,8 +714,10 @@ ossl_pkcs7_verify(int argc, VALUE *argv, VALUE self)
}
ok = PKCS7_verify(p7, x509s, x509st, in, out, flg);
BIO_free(in);
+ if (ok < 0) ossl_raise(ePKCS7Error, NULL);
msg = ERR_reason_error_string(ERR_get_error());
ossl_pkcs7_set_err_string(self, msg ? rb_str_new2(msg) : Qnil);
+ ERR_clear_error();
data = ossl_membio2str(out);
ossl_pkcs7_set_data(self, data);
sk_X509_pop_free(x509s, X509_free);
@@ -749,7 +798,7 @@ ossl_pkcs7_to_der(VALUE self)
if((len = i2d_PKCS7(pkcs7, NULL)) <= 0)
ossl_raise(ePKCS7Error, NULL);
str = rb_str_new(0, len);
- p = RSTRING(str)->ptr;
+ p = RSTRING_PTR(str);
if(i2d_PKCS7(pkcs7, &p) <= 0)
ossl_raise(ePKCS7Error, NULL);
ossl_str_adjust(str, p);
@@ -924,15 +973,12 @@ ossl_pkcs7ri_get_enc_key(VALUE self)
void
Init_ossl_pkcs7()
{
- mPKCS7 = rb_define_module_under(mOSSL, "PKCS7");
-
- ePKCS7Error = rb_define_class_under(mPKCS7, "PKCS7Error", eOSSLError);
-
- cPKCS7 = rb_define_class_under(mPKCS7, "PKCS7", rb_cObject);
- rb_define_singleton_method(mPKCS7, "read_smime", ossl_pkcs7_s_read_smime, 1);
- rb_define_singleton_method(mPKCS7, "write_smime", ossl_pkcs7_s_write_smime, -1);
- rb_define_singleton_method(mPKCS7, "sign", ossl_pkcs7_s_sign, -1);
- rb_define_singleton_method(mPKCS7, "encrypt", ossl_pkcs7_s_encrypt, -1);
+ cPKCS7 = rb_define_class_under(mOSSL, "PKCS7", rb_cObject);
+ ePKCS7Error = rb_define_class_under(cPKCS7, "PKCS7Error", eOSSLError);
+ rb_define_singleton_method(cPKCS7, "read_smime", ossl_pkcs7_s_read_smime, 1);
+ rb_define_singleton_method(cPKCS7, "write_smime", ossl_pkcs7_s_write_smime, -1);
+ rb_define_singleton_method(cPKCS7, "sign", ossl_pkcs7_s_sign, -1);
+ rb_define_singleton_method(cPKCS7, "encrypt", ossl_pkcs7_s_encrypt, -1);
rb_attr(cPKCS7, rb_intern("data"), 1, 0, Qfalse);
rb_attr(cPKCS7, rb_intern("error_string"), 1, 1, Qfalse);
rb_define_alloc_func(cPKCS7, ossl_pkcs7_alloc);
@@ -962,8 +1008,8 @@ Init_ossl_pkcs7()
rb_define_alias(cPKCS7, "to_s", "to_pem");
rb_define_method(cPKCS7, "to_der", ossl_pkcs7_to_der, 0);
- cPKCS7Signer = rb_define_class_under(mPKCS7, "SignerInfo", rb_cObject);
- rb_define_const(mPKCS7, "Signer", cPKCS7Signer);
+ cPKCS7Signer = rb_define_class_under(cPKCS7, "SignerInfo", rb_cObject);
+ rb_define_const(cPKCS7, "Signer", cPKCS7Signer);
rb_define_alloc_func(cPKCS7Signer, ossl_pkcs7si_alloc);
rb_define_method(cPKCS7Signer, "initialize", ossl_pkcs7si_initialize,3);
rb_define_method(cPKCS7Signer, "issuer", ossl_pkcs7si_get_issuer, 0);
@@ -971,14 +1017,14 @@ Init_ossl_pkcs7()
rb_define_method(cPKCS7Signer, "serial", ossl_pkcs7si_get_serial,0);
rb_define_method(cPKCS7Signer,"signed_time",ossl_pkcs7si_get_signed_time,0);
- cPKCS7Recipient = rb_define_class_under(mPKCS7,"RecipientInfo",rb_cObject);
+ cPKCS7Recipient = rb_define_class_under(cPKCS7,"RecipientInfo",rb_cObject);
rb_define_alloc_func(cPKCS7Recipient, ossl_pkcs7ri_alloc);
rb_define_method(cPKCS7Recipient, "initialize", ossl_pkcs7ri_initialize,1);
rb_define_method(cPKCS7Recipient, "issuer", ossl_pkcs7ri_get_issuer,0);
rb_define_method(cPKCS7Recipient, "serial", ossl_pkcs7ri_get_serial,0);
rb_define_method(cPKCS7Recipient, "enc_key", ossl_pkcs7ri_get_enc_key,0);
-#define DefPKCS7Const(x) rb_define_const(mPKCS7, #x, INT2NUM(PKCS7_##x))
+#define DefPKCS7Const(x) rb_define_const(cPKCS7, #x, INT2NUM(PKCS7_##x))
DefPKCS7Const(TEXT);
DefPKCS7Const(NOCERTS);
diff --git a/ext/openssl/ossl_pkcs7.h b/ext/openssl/ossl_pkcs7.h
index fdf0d9fb34..371c421103 100644
--- a/ext/openssl/ossl_pkcs7.h
+++ b/ext/openssl/ossl_pkcs7.h
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_pkcs7.h,v 1.1.2.1 2005/09/10 01:17:00 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -11,7 +11,6 @@
#if !defined(_OSSL_PKCS7_H_)
#define _OSSL_PKCS7_H_
-extern VALUE mPKCS7;
extern VALUE cPKCS7;
extern VALUE cPKCS7Signer;
extern VALUE cPKCS7Recipient;
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index 5a061597f6..8f68189881 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_pkey.c,v 1.4.2.2 2005/04/08 09:26:54 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -55,6 +55,10 @@ ossl_pkey_new(EVP_PKEY *pkey)
case EVP_PKEY_DH:
return ossl_dh_new(pkey);
#endif
+#if !defined(OPENSSL_NO_EC) && (OPENSSL_VERSION_NUMBER >= 0x0090802fL)
+ case EVP_PKEY_EC:
+ return ossl_ec_new(pkey);
+#endif
default:
ossl_raise(ePKeyError, "unsupported key type");
}
@@ -68,7 +72,7 @@ ossl_pkey_new_from_file(VALUE filename)
EVP_PKEY *pkey;
SafeStringValue(filename);
- if (!(fp = fopen(RSTRING(filename)->ptr, "r"))) {
+ if (!(fp = fopen(RSTRING_PTR(filename), "r"))) {
ossl_raise(ePKeyError, "%s", strerror(errno));
}
@@ -108,7 +112,7 @@ EVP_PKEY *
DupPKeyPtr(VALUE obj)
{
EVP_PKEY *pkey;
-
+
SafeGetPKey(obj, pkey);
CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
@@ -169,13 +173,12 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
GetPKey(self, pkey);
EVP_SignInit(&ctx, GetDigestPtr(digest));
StringValue(data);
- EVP_SignUpdate(&ctx, RSTRING(data)->ptr, RSTRING(data)->len);
+ EVP_SignUpdate(&ctx, RSTRING_PTR(data), RSTRING_LEN(data));
str = rb_str_new(0, EVP_PKEY_size(pkey)+16);
- if (!EVP_SignFinal(&ctx, RSTRING(str)->ptr, &buf_len, pkey))
+ if (!EVP_SignFinal(&ctx, RSTRING_PTR(str), &buf_len, pkey))
ossl_raise(ePKeyError, NULL);
- assert(buf_len <= RSTRING(str)->len);
- RSTRING(str)->len = buf_len;
- RSTRING(str)->ptr[buf_len] = 0;
+ assert((long)buf_len <= RSTRING_LEN(str));
+ rb_str_set_len(str, buf_len);
return str;
}
@@ -190,8 +193,8 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
EVP_VerifyInit(&ctx, GetDigestPtr(digest));
StringValue(sig);
StringValue(data);
- EVP_VerifyUpdate(&ctx, RSTRING(data)->ptr, RSTRING(data)->len);
- switch (EVP_VerifyFinal(&ctx, RSTRING(sig)->ptr, RSTRING(sig)->len, pkey)) {
+ EVP_VerifyUpdate(&ctx, RSTRING_PTR(data), RSTRING_LEN(data));
+ switch (EVP_VerifyFinal(&ctx, RSTRING_PTR(sig), RSTRING_LEN(sig), pkey)) {
case 0:
return Qfalse;
case 1:
@@ -208,6 +211,10 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
void
Init_ossl_pkey()
{
+#if 0 /* let rdoc know about mOSSL */
+ mOSSL = rb_define_module("OpenSSL");
+#endif
+
mPKey = rb_define_module_under(mOSSL, "PKey");
ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
@@ -223,10 +230,11 @@ Init_ossl_pkey()
id_private_q = rb_intern("private?");
/*
- * INIT rsa, dsa
+ * INIT rsa, dsa, dh, ec
*/
Init_ossl_rsa();
Init_ossl_dsa();
Init_ossl_dh();
+ Init_ossl_ec();
}
diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h
index 224f0f4634..67ff1fddd0 100644
--- a/ext/openssl/ossl_pkey.h
+++ b/ext/openssl/ossl_pkey.h
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_pkey.h,v 1.2.2.2 2005/09/18 22:56:11 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -77,7 +77,24 @@ extern DH *OSSL_DEFAULT_DH_1024;
VALUE ossl_dh_new(EVP_PKEY *);
void Init_ossl_dh(void);
+/*
+ * EC
+ */
+extern VALUE cEC;
+extern VALUE eECError;
+extern VALUE cEC_GROUP;
+extern VALUE eEC_GROUP;
+extern VALUE cEC_POINT;
+extern VALUE eEC_POINT;
+VALUE ossl_ec_new(EVP_PKEY *);
+void Init_ossl_ec(void);
+
+
#define OSSL_PKEY_BN(keytype, name) \
+/* \
+ * call-seq: \
+ * key.##name -> aBN \
+ */ \
static VALUE ossl_##keytype##_get_##name(VALUE self) \
{ \
EVP_PKEY *pkey; \
@@ -89,6 +106,10 @@ static VALUE ossl_##keytype##_get_##name(VALUE self) \
return Qnil; \
return ossl_bn_new(bn); \
} \
+/* \
+ * call-seq: \
+ * key.##name = bn -> bn \
+ */ \
static VALUE ossl_##keytype##_set_##name(VALUE self, VALUE bignum) \
{ \
EVP_PKEY *pkey; \
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
index 79692f2f47..3412305a5e 100644
--- a/ext/openssl/ossl_pkey_dh.c
+++ b/ext/openssl/ossl_pkey_dh.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_pkey_dh.c,v 1.4.2.3 2005/04/08 09:26:54 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -99,6 +99,15 @@ dh_generate(int size, int gen)
return dh;
}
+/*
+ * call-seq:
+ * DH.generate(size [, generator]) -> dh
+ *
+ * === Parameters
+ * * +size+ is an integer representing the desired key size. Keys smaller than 1024 should be considered insecure.
+ * * +generator+ is a small number > 1, typically 2 or 5.
+ *
+ */
static VALUE
ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass)
{
@@ -107,9 +116,9 @@ ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass)
VALUE size, gen, obj;
if (rb_scan_args(argc, argv, "11", &size, &gen) == 2) {
- g = FIX2INT(gen);
+ g = NUM2INT(gen);
}
- dh = dh_generate(FIX2INT(size), g);
+ dh = dh_generate(NUM2INT(size), g);
obj = dh_instance(klass, dh);
if (obj == Qfalse) {
DH_free(dh);
@@ -119,6 +128,21 @@ ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass)
return obj;
}
+/*
+ * call-seq:
+ * DH.new([size [, generator] | string]) -> dh
+ *
+ * === Parameters
+ * * +size+ is an integer representing the desired key size. Keys smaller than 1024 should be considered insecure.
+ * * +generator+ is a small number > 1, typically 2 or 5.
+ * * +string+ contains the DER or PEM encoded key.
+ *
+ * === Examples
+ * * DH.new -> dh
+ * * DH.new(1024) -> dh
+ * * DH.new(1024, 5) -> dh
+ * * DH.new(File.read('key.pem')) -> dh
+ */
static VALUE
ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
{
@@ -134,7 +158,7 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
}
else if (FIXNUM_P(arg)) {
if (!NIL_P(gen)) {
- g = FIX2INT(gen);
+ g = NUM2INT(gen);
}
if (!(dh = dh_generate(FIX2INT(arg), g))) {
ossl_raise(eDHError, NULL);
@@ -158,19 +182,26 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
return self;
}
+/*
+ * call-seq:
+ * dh.public? -> true | false
+ *
+ */
static VALUE
ossl_dh_is_public(VALUE self)
{
EVP_PKEY *pkey;
GetPKeyDH(self, pkey);
- /*
- * Do we need to check dhp->dh->public_pkey?
- * return Qtrue;
- */
+
return (pkey->pkey.dh->pub_key) ? Qtrue : Qfalse;
}
+/*
+ * call-seq:
+ * dh.private? -> true | false
+ *
+ */
static VALUE
ossl_dh_is_private(VALUE self)
{
@@ -181,6 +212,11 @@ ossl_dh_is_private(VALUE self)
return (DH_PRIVATE(pkey->pkey.dh)) ? Qtrue : Qfalse;
}
+/*
+ * call-seq:
+ * dh.to_pem -> aString
+ *
+ */
static VALUE
ossl_dh_export(VALUE self)
{
@@ -201,6 +237,11 @@ ossl_dh_export(VALUE self)
return str;
}
+/*
+ * call-seq:
+ * dh.to_der -> aString
+ *
+ */
static VALUE
ossl_dh_to_der(VALUE self)
{
@@ -213,7 +254,7 @@ ossl_dh_to_der(VALUE self)
if((len = i2d_DHparams(pkey->pkey.dh, NULL)) <= 0)
ossl_raise(eDHError, NULL);
str = rb_str_new(0, len);
- p = RSTRING(str)->ptr;
+ p = RSTRING_PTR(str);
if(i2d_DHparams(pkey->pkey.dh, &p) < 0)
ossl_raise(eDHError, NULL);
ossl_str_adjust(str, p);
@@ -222,6 +263,9 @@ ossl_dh_to_der(VALUE self)
}
/*
+ * call-seq:
+ * dh.params -> hash
+ *
* Stores all parameters of key to the hash
* INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
* Don't use :-)) (I's up to you)
@@ -245,6 +289,9 @@ ossl_dh_get_params(VALUE self)
}
/*
+ * call-seq:
+ * dh.to_text -> aString
+ *
* Prints all parameters of key to buffer
* INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
* Don't use :-)) (I's up to you)
@@ -270,7 +317,10 @@ ossl_dh_to_text(VALUE self)
}
/*
- * Makes new instance DH PUBLIC_KEY from PRIVATE_KEY
+ * call-seq:
+ * dh.public_key -> aDH
+ *
+ * Makes new instance DH PUBLIC_KEY from PRIVATE_KEY
*/
static VALUE
ossl_dh_to_public_key(VALUE self)
@@ -290,6 +340,11 @@ ossl_dh_to_public_key(VALUE self)
return obj;
}
+/*
+ * call-seq:
+ * dh.check_params -> true | false
+ *
+ */
static VALUE
ossl_dh_check_params(VALUE self)
{
@@ -307,6 +362,11 @@ ossl_dh_check_params(VALUE self)
return codes == 0 ? Qtrue : Qfalse;
}
+/*
+ * call-seq:
+ * dh.generate_key -> self
+ *
+ */
static VALUE
ossl_dh_generate_key(VALUE self)
{
@@ -321,6 +381,18 @@ ossl_dh_generate_key(VALUE self)
return self;
}
+/*
+ * call-seq:
+ * dh.compute_key(pub_bn) -> aString
+ *
+ * === Parameters
+ * * +pub_bn+ is a OpenSSL::BN.
+ *
+ * Returns aString containing a shared secret computed from the other parties public value.
+ *
+ * See DH_compute_key() for further information.
+ *
+ */
static VALUE
ossl_dh_compute_key(VALUE self, VALUE pub)
{
@@ -335,19 +407,18 @@ ossl_dh_compute_key(VALUE self, VALUE pub)
pub_key = GetBNPtr(pub);
len = DH_size(dh);
str = rb_str_new(0, len);
- if ((len = DH_compute_key(RSTRING(str)->ptr, pub_key, dh)) < 0) {
+ if ((len = DH_compute_key(RSTRING_PTR(str), pub_key, dh)) < 0) {
ossl_raise(eDHError, NULL);
}
- RSTRING(str)->len = len;
- RSTRING(str)->ptr[len] = 0;
+ rb_str_set_len(str, len);
return str;
}
-OSSL_PKEY_BN(dh, p);
-OSSL_PKEY_BN(dh, g);
-OSSL_PKEY_BN(dh, pub_key);
-OSSL_PKEY_BN(dh, priv_key);
+OSSL_PKEY_BN(dh, p)
+OSSL_PKEY_BN(dh, g)
+OSSL_PKEY_BN(dh, pub_key)
+OSSL_PKEY_BN(dh, priv_key)
/*
* -----BEGIN DH PARAMETERS-----
@@ -367,7 +438,7 @@ static unsigned char DEFAULT_DH_512_PRIM[] = {
};
static unsigned char DEFAULT_DH_512_GEN[] = { 0x02 };
DH *OSSL_DEFAULT_DH_512 = NULL;
-
+
/*
* -----BEGIN DH PARAMETERS-----
* MIGHAoGBAJ0lOVy0VIr/JebWn0zDwY2h+rqITFOpdNr6ugsgvkDXuucdcChhYExJ
@@ -406,7 +477,7 @@ ossl_create_dh(unsigned char *p, size_t plen, unsigned char *g, size_t glen)
dh->g = BN_bin2bn(g, glen, NULL);
if (dh->p == NULL || dh->g == NULL){
DH_free(dh);
- ossl_raise(eDHError, NULL);
+ ossl_raise(eDHError, NULL);
}
return dh;
@@ -418,6 +489,11 @@ ossl_create_dh(unsigned char *p, size_t plen, unsigned char *g, size_t glen)
void
Init_ossl_dh()
{
+#if 0 /* let rdoc know about mOSSL and mPKey */
+ mOSSL = rb_define_module("OpenSSL");
+ mPKey = rb_define_module_under(mOSSL, "PKey");
+#endif
+
eDHError = rb_define_class_under(mPKey, "DHError", ePKeyError);
cDH = rb_define_class_under(mPKey, "DH", cPKey);
rb_define_singleton_method(cDH, "generate", ossl_dh_s_generate, -1);
@@ -448,11 +524,9 @@ Init_ossl_dh()
}
#else /* defined NO_DH */
-# warning >>> OpenSSL is compiled without DH support <<<
void
Init_ossl_dh()
{
- rb_warning("OpenSSL is compiled without DH support");
}
#endif /* NO_DH */
diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c
index 2a6060fe77..a1f1397787 100644
--- a/ext/openssl/ossl_pkey_dsa.c
+++ b/ext/openssl/ossl_pkey_dsa.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_pkey_dsa.c,v 1.5.2.3 2005/09/18 22:56:11 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -99,10 +99,18 @@ dsa_generate(int size)
return dsa;
}
+/*
+ * call-seq:
+ * DSA.generate(size) -> dsa
+ *
+ * === Parameters
+ * * +size+ is an integer representing the desired key size.
+ *
+ */
static VALUE
ossl_dsa_s_generate(VALUE klass, VALUE size)
{
- DSA *dsa = dsa_generate(FIX2INT(size)); /* err handled by dsa_instance */
+ DSA *dsa = dsa_generate(NUM2INT(size)); /* err handled by dsa_instance */
VALUE obj = dsa_instance(klass, dsa);
if (obj == Qfalse) {
@@ -113,6 +121,22 @@ ossl_dsa_s_generate(VALUE klass, VALUE size)
return obj;
}
+/*
+ * call-seq:
+ * DSA.new([size | string [, pass]) -> dsa
+ *
+ * === Parameters
+ * * +size+ is an integer representing the desired key size.
+ * * +string+ contains a DER or PEM encoded key.
+ * * +pass+ is a string that contains a optional password.
+ *
+ * === Examples
+ * * DSA.new -> dsa
+ * * DSA.new(1024) -> dsa
+ * * DSA.new(File.read('dsa.pem')) -> dsa
+ * * DSA.new(File.read('dsa.pem'), 'mypassword') -> dsa
+ *
+ */
static VALUE
ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
{
@@ -163,6 +187,11 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
return self;
}
+/*
+ * call-seq:
+ * dsa.public? -> true | false
+ *
+ */
static VALUE
ossl_dsa_is_public(VALUE self)
{
@@ -170,13 +199,14 @@ ossl_dsa_is_public(VALUE self)
GetPKeyDSA(self, pkey);
- /*
- * Do we need to check dsap->dsa->public_pkey?
- * return Qtrue;
- */
return (pkey->pkey.dsa->pub_key) ? Qtrue : Qfalse;
}
+/*
+ * call-seq:
+ * dsa.private? -> true | false
+ *
+ */
static VALUE
ossl_dsa_is_private(VALUE self)
{
@@ -187,6 +217,19 @@ ossl_dsa_is_private(VALUE self)
return (DSA_PRIVATE(self, pkey->pkey.dsa)) ? Qtrue : Qfalse;
}
+/*
+ * call-seq:
+ * dsa.to_pem([cipher, password]) -> aString
+ *
+ * === Parameters
+ * +cipher+ is an OpenSSL::Cipher.
+ * +password+ is a string containing your password.
+ *
+ * === Examples
+ * * DSA.to_pem -> aString
+ * * DSA.to_pem(cipher, 'mypassword') -> aString
+ *
+ */
static VALUE
ossl_dsa_export(int argc, VALUE *argv, VALUE self)
{
@@ -224,6 +267,11 @@ ossl_dsa_export(int argc, VALUE *argv, VALUE self)
return str;
}
+/*
+ * call-seq:
+ * dsa.to_der -> aString
+ *
+ */
static VALUE
ossl_dsa_to_der(VALUE self)
{
@@ -241,7 +289,7 @@ ossl_dsa_to_der(VALUE self)
if((len = i2d_func(pkey->pkey.dsa, NULL)) <= 0)
ossl_raise(eDSAError, NULL);
str = rb_str_new(0, len);
- p = RSTRING(str)->ptr;
+ p = RSTRING_PTR(str);
if(i2d_func(pkey->pkey.dsa, &p) < 0)
ossl_raise(eDSAError, NULL);
ossl_str_adjust(str, p);
@@ -250,6 +298,9 @@ ossl_dsa_to_der(VALUE self)
}
/*
+ * call-seq:
+ * dsa.params -> hash
+ *
* Stores all parameters of key to the hash
* INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
* Don't use :-)) (I's up to you)
@@ -274,6 +325,9 @@ ossl_dsa_get_params(VALUE self)
}
/*
+ * call-seq:
+ * dsa.to_text -> aString
+ *
* Prints all parameters of key to buffer
* INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
* Don't use :-)) (I's up to you)
@@ -299,6 +353,9 @@ ossl_dsa_to_text(VALUE self)
}
/*
+ * call-seq:
+ * dsa.public_key -> aDSA
+ *
* Makes new instance DSA PUBLIC_KEY from PRIVATE_KEY
*/
static VALUE
@@ -321,6 +378,11 @@ ossl_dsa_to_public_key(VALUE self)
#define ossl_dsa_buf_size(pkey) (DSA_size((pkey)->pkey.dsa)+16)
+/*
+ * call-seq:
+ * dsa.syssign(string) -> aString
+ *
+ */
static VALUE
ossl_dsa_sign(VALUE self, VALUE data)
{
@@ -334,16 +396,20 @@ ossl_dsa_sign(VALUE self, VALUE data)
ossl_raise(eDSAError, "Private DSA key needed!");
}
str = rb_str_new(0, ossl_dsa_buf_size(pkey));
- if (!DSA_sign(0, RSTRING(data)->ptr, RSTRING(data)->len, RSTRING(str)->ptr,
+ if (!DSA_sign(0, RSTRING_PTR(data), RSTRING_LEN(data), RSTRING_PTR(str),
&buf_len, pkey->pkey.dsa)) { /* type is ignored (0) */
ossl_raise(eDSAError, NULL);
}
- RSTRING(str)->len = buf_len;
- RSTRING(str)->ptr[buf_len] = 0;
+ rb_str_set_len(str, buf_len);
return str;
}
+/*
+ * call-seq:
+ * dsa.sysverify(digest, sig) -> true | false
+ *
+ */
static VALUE
ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig)
{
@@ -354,8 +420,8 @@ ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig)
StringValue(digest);
StringValue(sig);
/* type is ignored (0) */
- ret = DSA_verify(0, RSTRING(digest)->ptr, RSTRING(digest)->len,
- RSTRING(sig)->ptr, RSTRING(sig)->len, pkey->pkey.dsa);
+ ret = DSA_verify(0, RSTRING_PTR(digest), RSTRING_LEN(digest),
+ RSTRING_PTR(sig), RSTRING_LEN(sig), pkey->pkey.dsa);
if (ret < 0) {
ossl_raise(eDSAError, NULL);
}
@@ -366,11 +432,11 @@ ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig)
return Qfalse;
}
-OSSL_PKEY_BN(dsa, p);
-OSSL_PKEY_BN(dsa, q);
-OSSL_PKEY_BN(dsa, g);
-OSSL_PKEY_BN(dsa, pub_key);
-OSSL_PKEY_BN(dsa, priv_key);
+OSSL_PKEY_BN(dsa, p)
+OSSL_PKEY_BN(dsa, q)
+OSSL_PKEY_BN(dsa, g)
+OSSL_PKEY_BN(dsa, pub_key)
+OSSL_PKEY_BN(dsa, priv_key)
/*
* INIT
@@ -378,6 +444,11 @@ OSSL_PKEY_BN(dsa, priv_key);
void
Init_ossl_dsa()
{
+#if 0 /* let rdoc know about mOSSL and mPKey */
+ mOSSL = rb_define_module("OpenSSL");
+ mPKey = rb_define_module_under(mOSSL, "PKey");
+#endif
+
eDSAError = rb_define_class_under(mPKey, "DSAError", ePKeyError);
cDSA = rb_define_class_under(mPKey, "DSA", cPKey);
@@ -406,12 +477,8 @@ Init_ossl_dsa()
}
#else /* defined NO_DSA */
-# warning >>> OpenSSL is compiled without DSA support <<<
-
void
Init_ossl_dsa()
{
- rb_warning("OpenSSL is compiled without DSA support");
}
-
#endif /* NO_DSA */
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
new file mode 100644
index 0000000000..cbdad3f12b
--- /dev/null
+++ b/ext/openssl/ossl_pkey_ec.c
@@ -0,0 +1,1593 @@
+/*
+ * Copyright (C) 2006-2007 Technorama Ltd. <oss-ruby@technorama.net>
+ */
+
+#include "ossl.h"
+
+#if !defined(OPENSSL_NO_EC) && (OPENSSL_VERSION_NUMBER >= 0x0090802fL)
+
+typedef struct {
+ EC_GROUP *group;
+ int dont_free;
+} ossl_ec_group;
+
+typedef struct {
+ EC_POINT *point;
+ int dont_free;
+} ossl_ec_point;
+
+
+#define EXPORT_PEM 0
+#define EXPORT_DER 1
+
+
+#define GetPKeyEC(obj, pkey) do { \
+ GetPKey(obj, pkey); \
+ if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) { \
+ ossl_raise(rb_eRuntimeError, "THIS IS NOT A EC PKEY!"); \
+ } \
+} while (0)
+
+#define SafeGet_ec_group(obj, group) do { \
+ OSSL_Check_Kind(obj, cEC_GROUP); \
+ Data_Get_Struct(obj, ossl_ec_group, group); \
+} while(0)
+
+#define Get_EC_KEY(obj, key) do { \
+ EVP_PKEY *pkey; \
+ GetPKeyEC(obj, pkey); \
+ key = pkey->pkey.ec; \
+} while(0)
+
+#define Require_EC_KEY(obj, key) do { \
+ Get_EC_KEY(obj, key); \
+ if (key == NULL) \
+ rb_raise(eECError, "EC_KEY is not initialized"); \
+} while(0)
+
+#define SafeRequire_EC_KEY(obj, key) do { \
+ OSSL_Check_Kind(obj, cEC); \
+ Require_EC_KEY(obj, key); \
+} while (0)
+
+#define Get_EC_GROUP(obj, g) do { \
+ ossl_ec_group *ec_group; \
+ Data_Get_Struct(obj, ossl_ec_group, ec_group); \
+ if (ec_group == NULL) \
+ rb_raise(eEC_GROUP, "missing ossl_ec_group structure"); \
+ g = ec_group->group; \
+} while(0)
+
+#define Require_EC_GROUP(obj, group) do { \
+ Get_EC_GROUP(obj, group); \
+ if (group == NULL) \
+ rb_raise(eEC_GROUP, "EC_GROUP is not initialized"); \
+} while(0)
+
+#define SafeRequire_EC_GROUP(obj, group) do { \
+ OSSL_Check_Kind(obj, cEC_GROUP); \
+ Require_EC_GROUP(obj, group); \
+} while(0)
+
+#define Get_EC_POINT(obj, p) do { \
+ ossl_ec_point *ec_point; \
+ Data_Get_Struct(obj, ossl_ec_point, ec_point); \
+ if (ec_point == NULL) \
+ rb_raise(eEC_POINT, "missing ossl_ec_point structure"); \
+ p = ec_point->point; \
+} while(0)
+
+#define Require_EC_POINT(obj, point) do { \
+ Get_EC_POINT(obj, point); \
+ if (point == NULL) \
+ rb_raise(eEC_POINT, "EC_POINT is not initialized"); \
+} while(0)
+
+#define SafeRequire_EC_POINT(obj, point) do { \
+ OSSL_Check_Kind(obj, cEC_POINT); \
+ Require_EC_POINT(obj, point); \
+} while(0)
+
+VALUE cEC;
+VALUE eECError;
+VALUE cEC_GROUP;
+VALUE eEC_GROUP;
+VALUE cEC_POINT;
+VALUE eEC_POINT;
+
+static ID s_GFp;
+static ID s_GFp_simple;
+static ID s_GFp_mont;
+static ID s_GFp_nist;
+static ID s_GF2m;
+static ID s_GF2m_simple;
+
+static ID ID_uncompressed;
+static ID ID_compressed;
+static ID ID_hybrid;
+
+static VALUE ec_instance(VALUE klass, EC_KEY *ec)
+{
+ EVP_PKEY *pkey;
+ VALUE obj;
+
+ if (!ec) {
+ return Qfalse;
+ }
+ if (!(pkey = EVP_PKEY_new())) {
+ return Qfalse;
+ }
+ if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) {
+ EVP_PKEY_free(pkey);
+ return Qfalse;
+ }
+ WrapPKey(klass, obj, pkey);
+
+ return obj;
+}
+
+VALUE ossl_ec_new(EVP_PKEY *pkey)
+{
+ VALUE obj;
+
+ if (!pkey) {
+ obj = ec_instance(cEC, EC_KEY_new());
+ } else {
+ if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) {
+ ossl_raise(rb_eTypeError, "Not a EC key!");
+ }
+ WrapPKey(cEC, obj, pkey);
+ }
+ if (obj == Qfalse) {
+ ossl_raise(eECError, NULL);
+ }
+
+ return obj;
+}
+
+
+/* call-seq:
+ * OpenSSL::PKey::EC.new()
+ * OpenSSL::PKey::EC.new(ec_key)
+ * OpenSSL::PKey::EC.new(ec_group)
+ * OpenSSL::PKey::EC.new("secp112r1")
+ * OpenSSL::PKey::EC.new(pem_string)
+ * OpenSSL::PKey::EC.new(der_string)
+ *
+ * See the OpenSSL documentation for:
+ * EC_KEY_*
+ */
+static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
+{
+ EVP_PKEY *pkey;
+ EC_KEY *ec = NULL;
+ VALUE arg, pass;
+ VALUE group = Qnil;
+
+ GetPKey(self, pkey);
+ if (pkey->pkey.ec)
+ rb_raise(eECError, "EC_KEY already initialized");
+
+ rb_scan_args(argc, argv, "02", &arg, &pass);
+
+ if (NIL_P(arg)) {
+ ec = EC_KEY_new();
+ } else {
+ if (rb_obj_is_kind_of(arg, cEC)) {
+ EC_KEY *other_ec = NULL;
+
+ SafeRequire_EC_KEY(arg, other_ec);
+ ec = EC_KEY_dup(other_ec);
+ } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) {
+ ec = EC_KEY_new();
+ group = arg;
+ } else {
+ BIO *in = ossl_obj2bio(arg);
+
+ ec = PEM_read_bio_ECPrivateKey(in, NULL, NULL, NULL);
+ if (!ec) {
+ BIO_reset(in);
+ ec = PEM_read_bio_EC_PUBKEY(in, NULL, NULL, NULL);
+ }
+ if (!ec) {
+ BIO_reset(in);
+ ec = d2i_ECPrivateKey_bio(in, NULL);
+ }
+ if (!ec) {
+ BIO_reset(in);
+ ec = d2i_EC_PUBKEY_bio(in, NULL);
+ }
+
+ BIO_free(in);
+
+ if (ec == NULL) {
+ const char *name = STR2CSTR(arg);
+ int nid = OBJ_sn2nid(name);
+
+ if (nid == NID_undef)
+ ossl_raise(eECError, "unknown curve name (%s)\n", name);
+
+ if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL)
+ ossl_raise(eECError, "unable to create curve (%s)\n", name);
+
+ EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE);
+ EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED);
+ }
+ }
+ }
+
+ if (ec == NULL)
+ ossl_raise(eECError, NULL);
+
+ if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) {
+ EC_KEY_free(ec);
+ ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
+ }
+
+ rb_iv_set(self, "@group", Qnil);
+
+ if (!NIL_P(group))
+ rb_funcall(self, rb_intern("group="), 1, arg);
+
+ return self;
+}
+
+/*
+ * call-seq:
+ * key.group => group
+ *
+ * Returns a constant <code>OpenSSL::EC::Group</code> that is tied to the key.
+ * Modifying the returned group can make the key invalid.
+ */
+static VALUE ossl_ec_key_get_group(VALUE self)
+{
+ VALUE group_v;
+ EC_KEY *ec;
+ ossl_ec_group *ec_group;
+ EC_GROUP *group;
+
+ Require_EC_KEY(self, ec);
+
+ group_v = rb_iv_get(self, "@group");
+ if (!NIL_P(group_v))
+ return group_v;
+
+ if ((group = (EC_GROUP *)EC_KEY_get0_group(ec)) != NULL) {
+ group_v = rb_obj_alloc(cEC_GROUP);
+ SafeGet_ec_group(group_v, ec_group);
+ ec_group->group = group;
+ ec_group->dont_free = 1;
+ rb_iv_set(group_v, "@key", self);
+ rb_iv_set(self, "@group", group_v);
+ return group_v;
+ }
+
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * key.group = group => group
+ *
+ * Returns the same object passed, not the group object associated with the key.
+ * If you wish to access the group object tied to the key call key.group after setting
+ * the group.
+ *
+ * Setting the group will immediately destroy any previously assigned group object.
+ * The group is internally copied by OpenSSL. Modifying the original group after
+ * assignment will not effect the internal key structure.
+ * (your changes may be lost). BE CAREFUL.
+ *
+ * EC_KEY_set_group calls EC_GROUP_free(key->group) then EC_GROUP_dup(), not EC_GROUP_copy.
+ * This documentation is accurate for OpenSSL 0.9.8b.
+ */
+static VALUE ossl_ec_key_set_group(VALUE self, VALUE group_v)
+{
+ VALUE old_group_v;
+ EC_KEY *ec;
+ EC_GROUP *group;
+
+ Require_EC_KEY(self, ec);
+ SafeRequire_EC_GROUP(group_v, group);
+
+ old_group_v = rb_iv_get(self, "@group");
+ if (!NIL_P(old_group_v)) {
+ ossl_ec_group *old_ec_group;
+ SafeGet_ec_group(old_group_v, old_ec_group);
+
+ old_ec_group->group = NULL;
+ old_ec_group->dont_free = 0;
+ rb_iv_set(old_group_v, "@key", Qnil);
+ }
+
+ rb_iv_set(self, "@group", Qnil);
+
+ if (EC_KEY_set_group(ec, group) != 1)
+ ossl_raise(eECError, "EC_KEY_set_group");
+
+ return group_v;
+}
+
+/*
+ * call-seq:
+ * key.private_key => OpenSSL::BN
+ *
+ * See the OpenSSL documentation for EC_KEY_get0_private_key()
+ */
+static VALUE ossl_ec_key_get_private_key(VALUE self)
+{
+ EC_KEY *ec;
+ const BIGNUM *bn;
+
+ Require_EC_KEY(self, ec);
+
+ if ((bn = EC_KEY_get0_private_key(ec)) == NULL)
+ return Qnil;
+
+ return ossl_bn_new(bn);
+}
+
+/*
+ * call-seq:
+ * key.private_key = openssl_bn
+ *
+ * See the OpenSSL documentation for EC_KEY_set_private_key()
+ */
+static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key)
+{
+ EC_KEY *ec;
+ BIGNUM *bn = NULL;
+
+ Require_EC_KEY(self, ec);
+ if (!NIL_P(private_key))
+ bn = GetBNPtr(private_key);
+
+ switch (EC_KEY_set_private_key(ec, bn)) {
+ case 1:
+ break;
+ case 0:
+ if (bn == NULL)
+ break;
+ default:
+ ossl_raise(eECError, "EC_KEY_set_private_key");
+ }
+
+ return private_key;
+}
+
+
+static VALUE ossl_ec_point_dup(const EC_POINT *point, VALUE group_v)
+{
+ VALUE obj;
+ const EC_GROUP *group;
+ ossl_ec_point *new_point;
+
+ obj = rb_obj_alloc(cEC_POINT);
+ Data_Get_Struct(obj, ossl_ec_point, new_point);
+
+ SafeRequire_EC_GROUP(group_v, group);
+
+ new_point->point = EC_POINT_dup(point, group);
+ if (new_point->point == NULL)
+ ossl_raise(eEC_POINT, "EC_POINT_dup");
+ rb_iv_set(obj, "@group", group_v);
+
+ return obj;
+}
+
+/*
+ * call-seq:
+ * key.public_key => OpenSSL::PKey::EC::Point
+ *
+ * See the OpenSSL documentation for EC_KEY_get0_public_key()
+ */
+static VALUE ossl_ec_key_get_public_key(VALUE self)
+{
+ EC_KEY *ec;
+ const EC_POINT *point;
+ VALUE group;
+
+ Require_EC_KEY(self, ec);
+
+ if ((point = EC_KEY_get0_public_key(ec)) == NULL)
+ return Qnil;
+
+ group = rb_funcall(self, rb_intern("group"), 0);
+ if (NIL_P(group))
+ ossl_raise(eECError, "EC_KEY_get0_get0_group (has public_key but no group???");
+
+ return ossl_ec_point_dup(point, group);
+}
+
+/*
+ * call-seq:
+ * key.public_key = ec_point
+ *
+ * See the OpenSSL documentation for EC_KEY_set_public_key()
+ */
+static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key)
+{
+ EC_KEY *ec;
+ EC_POINT *point = NULL;
+
+ Require_EC_KEY(self, ec);
+ if (!NIL_P(public_key))
+ SafeRequire_EC_POINT(public_key, point);
+
+ switch (EC_KEY_set_public_key(ec, point)) {
+ case 1:
+ break;
+ case 0:
+ if (point == NULL)
+ break;
+ default:
+ ossl_raise(eECError, "EC_KEY_set_public_key");
+ }
+
+ return public_key;
+}
+
+/*
+ * call-seq:
+ * key.public_key? => true or false
+ *
+ * Both public_key? and private_key? may return false at the same time unlike other PKey classes.
+ */
+static VALUE ossl_ec_key_is_public_key(VALUE self)
+{
+ EC_KEY *ec;
+
+ Require_EC_KEY(self, ec);
+
+ return (EC_KEY_get0_public_key(ec) ? Qtrue : Qfalse);
+}
+
+/*
+ * call-seq:
+ * key.private_key? => true or false
+ *
+ * Both public_key? and private_key? may return false at the same time unlike other PKey classes.
+ */
+static VALUE ossl_ec_key_is_private_key(VALUE self)
+{
+ EC_KEY *ec;
+
+ Require_EC_KEY(self, ec);
+
+ return (EC_KEY_get0_private_key(ec) ? Qtrue : Qfalse);
+}
+
+static VALUE ossl_ec_key_to_string(VALUE self, int format)
+{
+ EC_KEY *ec;
+ BIO *out;
+ int i = -1;
+ int private = 0;
+#if 0 /* unused now */
+ EVP_CIPHER *cipher = NULL;
+ char *password = NULL;
+#endif
+ VALUE str;
+
+ Require_EC_KEY(self, ec);
+
+ if (EC_KEY_get0_public_key(ec) == NULL)
+ rb_raise(eECError, "can't export - no public key set");
+
+ if (EC_KEY_check_key(ec) != 1)
+ ossl_raise(eECError, "can't export - EC_KEY_check_key failed");
+
+ if (EC_KEY_get0_private_key(ec))
+ private = 1;
+
+ if (!(out = BIO_new(BIO_s_mem())))
+ ossl_raise(eECError, "BIO_new(BIO_s_mem())");
+
+ switch(format) {
+ case EXPORT_PEM:
+ if (private) {
+#if 0 /* unused now */
+ if (cipher || password)
+/* BUG: finish cipher/password key export */
+ rb_notimplement();
+ i = PEM_write_bio_ECPrivateKey(out, ec, cipher, NULL, 0, NULL, password);
+#endif
+ i = PEM_write_bio_ECPrivateKey(out, ec, NULL, NULL, 0, NULL, NULL);
+ } else {
+#if 0 /* unused now */
+ if (cipher || password)
+ rb_raise(rb_eArgError, "encryption is not supported when exporting this key type");
+#endif
+
+ i = PEM_write_bio_EC_PUBKEY(out, ec);
+ }
+
+ break;
+ case EXPORT_DER:
+ if (private) {
+#if 0 /* unused now */
+ if (cipher || password)
+ rb_raise(rb_eArgError, "encryption is not supported when exporting this key type");
+#endif
+
+ i = i2d_ECPrivateKey_bio(out, ec);
+ } else {
+#if 0 /* unused now */
+ if (cipher || password)
+ rb_raise(rb_eArgError, "encryption is not supported when exporting this key type");
+#endif
+
+ i = i2d_EC_PUBKEY_bio(out, ec);
+ }
+
+ break;
+ default:
+ BIO_free(out);
+ rb_raise(rb_eRuntimeError, "unknown format (internal error)");
+ }
+
+ if (i != 1) {
+ BIO_free(out);
+ ossl_raise(eECError, "outlen=%d", i);
+ }
+
+ str = ossl_membio2str(out);
+
+ return str;
+}
+
+/*
+ * call-seq:
+ * key.to_pem => String
+ *
+ * See the OpenSSL documentation for PEM_write_bio_ECPrivateKey()
+ */
+static VALUE ossl_ec_key_to_pem(VALUE self)
+{
+ return ossl_ec_key_to_string(self, EXPORT_PEM);
+}
+
+/*
+ * call-seq:
+ * key.to_der => String
+ *
+ * See the OpenSSL documentation for i2d_ECPrivateKey_bio()
+ */
+static VALUE ossl_ec_key_to_der(VALUE self)
+{
+ return ossl_ec_key_to_string(self, EXPORT_DER);
+}
+
+/*
+ * call-seq:
+ * key.to_text => String
+ *
+ * See the OpenSSL documentation for EC_KEY_print()
+ */
+static VALUE ossl_ec_key_to_text(VALUE self)
+{
+ EC_KEY *ec;
+ BIO *out;
+ VALUE str;
+
+ Require_EC_KEY(self, ec);
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ ossl_raise(eECError, "BIO_new(BIO_s_mem())");
+ }
+ if (!EC_KEY_print(out, ec, 0)) {
+ BIO_free(out);
+ ossl_raise(eECError, "EC_KEY_print");
+ }
+ str = ossl_membio2str(out);
+
+ return str;
+}
+
+/*
+ * call-seq:
+ * key.generate_key => self
+ *
+ * See the OpenSSL documentation for EC_KEY_generate_key()
+ */
+static VALUE ossl_ec_key_generate_key(VALUE self)
+{
+ EC_KEY *ec;
+
+ Require_EC_KEY(self, ec);
+
+ if (EC_KEY_generate_key(ec) != 1)
+ ossl_raise(eECError, "EC_KEY_generate_key");
+
+ return self;
+}
+
+/*
+ * call-seq:
+ * key.check_key => true
+ *
+ * Raises an exception if the key is invalid.
+ *
+ * See the OpenSSL documentation for EC_KEY_check_key()
+ */
+static VALUE ossl_ec_key_check_key(VALUE self)
+{
+ EC_KEY *ec;
+
+ Require_EC_KEY(self, ec);
+
+ if (EC_KEY_check_key(ec) != 1)
+ ossl_raise(eECError, "EC_KEY_check_key");
+
+ return Qtrue;
+}
+
+/*
+ * call-seq:
+ * key.dh_compute_key(pubkey) => String
+ *
+ * See the OpenSSL documentation for ECDH_compute_key()
+ */
+static VALUE ossl_ec_key_dh_compute_key(VALUE self, VALUE pubkey)
+{
+ EC_KEY *ec;
+ EC_POINT *point;
+ int buf_len;
+ VALUE str;
+
+ Require_EC_KEY(self, ec);
+ SafeRequire_EC_POINT(pubkey, point);
+
+/* BUG: need a way to figure out the maximum string size */
+ buf_len = 1024;
+ str = rb_str_new(0, buf_len);
+/* BUG: take KDF as a block */
+ buf_len = ECDH_compute_key(RSTRING_PTR(str), buf_len, point, ec, NULL);
+ if (buf_len < 0)
+ ossl_raise(eECError, "ECDH_compute_key");
+
+ rb_str_resize(str, buf_len);
+
+ return str;
+}
+
+/* sign_setup */
+
+/*
+ * call-seq:
+ * key.dsa_sign_asn1(data) => String
+ *
+ * See the OpenSSL documentation for ECDSA_sign()
+ */
+static VALUE ossl_ec_key_dsa_sign_asn1(VALUE self, VALUE data)
+{
+ EC_KEY *ec;
+ unsigned int buf_len;
+ VALUE str;
+
+ Require_EC_KEY(self, ec);
+ StringValue(data);
+
+ if (EC_KEY_get0_private_key(ec) == NULL)
+ ossl_raise(eECError, "Private EC key needed!");
+
+ str = rb_str_new(0, ECDSA_size(ec) + 16);
+ if (ECDSA_sign(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LEN(data), (unsigned char *) RSTRING_PTR(str), &buf_len, ec) != 1)
+ ossl_raise(eECError, "ECDSA_sign");
+
+ rb_str_resize(str, buf_len);
+
+ return str;
+}
+
+/*
+ * call-seq:
+ * key.dsa_verify_asn1(data, sig) => true or false
+ *
+ * See the OpenSSL documentation for ECDSA_verify()
+ */
+static VALUE ossl_ec_key_dsa_verify_asn1(VALUE self, VALUE data, VALUE sig)
+{
+ EC_KEY *ec;
+
+ Require_EC_KEY(self, ec);
+ StringValue(data);
+ StringValue(sig);
+
+ switch (ECDSA_verify(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LEN(data), (unsigned char *) RSTRING_PTR(sig), RSTRING_LEN(sig), ec)) {
+ case 1: return Qtrue;
+ case 0: return Qfalse;
+ default: break;
+ }
+
+ ossl_raise(eECError, "ECDSA_verify");
+}
+
+static void ossl_ec_group_free(ossl_ec_group *ec_group)
+{
+ if (!ec_group->dont_free && ec_group->group)
+ EC_GROUP_clear_free(ec_group->group);
+ ruby_xfree(ec_group);
+}
+
+static VALUE ossl_ec_group_alloc(VALUE klass)
+{
+ ossl_ec_group *ec_group;
+ VALUE obj;
+
+ obj = Data_Make_Struct(klass, ossl_ec_group, 0, ossl_ec_group_free, ec_group);
+
+ return obj;
+}
+
+/* call-seq:
+ * OpenSSL::PKey::EC::Group.new("secp112r1")
+ * OpenSSL::PKey::EC::Group.new(ec_group)
+ * OpenSSL::PKey::EC::Group.new(pem_string)
+ * OpenSSL::PKey::EC::Group.new(der_string)
+ * OpenSSL::PKey::EC::Group.new(pem_file)
+ * OpenSSL::PKey::EC::Group.new(der_file)
+ * OpenSSL::PKey::EC::Group.new(:GFp_simple)
+ * OpenSSL::PKey::EC::Group.new(:GFp_mult)
+ * OpenSSL::PKey::EC::Group.new(:GFp_nist)
+ * OpenSSL::PKey::EC::Group.new(:GF2m_simple)
+ * OpenSSL::PKey::EC::Group.new(:GFp, bignum_p, bignum_a, bignum_b)
+ * OpenSSL::PKey::EC::Group.new(:GF2m, bignum_p, bignum_a, bignum_b)
+ *
+ * See the OpenSSL documentation for EC_GROUP_*
+ */
+static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
+{
+ VALUE arg1, arg2, arg3, arg4;
+ ossl_ec_group *ec_group;
+ EC_GROUP *group = NULL;
+
+ Data_Get_Struct(self, ossl_ec_group, ec_group);
+ if (ec_group->group != NULL)
+ rb_raise(rb_eRuntimeError, "EC_GROUP is already initialized");
+
+ switch (rb_scan_args(argc, argv, "13", &arg1, &arg2, &arg3, &arg4)) {
+ case 1:
+ if (SYMBOL_P(arg1)) {
+ const EC_METHOD *method = NULL;
+ ID id = SYM2ID(arg1);
+
+ if (id == s_GFp_simple) {
+ method = EC_GFp_simple_method();
+ } else if (id == s_GFp_mont) {
+ method = EC_GFp_mont_method();
+ } else if (id == s_GFp_nist) {
+ method = EC_GFp_nist_method();
+ } else if (id == s_GF2m_simple) {
+ method = EC_GF2m_simple_method();
+ }
+
+ if (method) {
+ if ((group = EC_GROUP_new(method)) == NULL)
+ ossl_raise(eEC_GROUP, "EC_GROUP_new");
+ } else {
+ rb_raise(rb_eArgError, "unknown symbol, must be :GFp_simple, :GFp_mont, :GFp_nist or :GF2m_simple");
+ }
+ } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {
+ const EC_GROUP *arg1_group;
+
+ SafeRequire_EC_GROUP(arg1, arg1_group);
+ if ((group = EC_GROUP_dup(arg1_group)) == NULL)
+ ossl_raise(eEC_GROUP, "EC_GROUP_dup");
+ } else {
+ BIO *in = ossl_obj2bio(arg1);
+
+ group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL);
+ if (!group) {
+ BIO_reset(in);
+ group = d2i_ECPKParameters_bio(in, NULL);
+ }
+
+ BIO_free(in);
+
+ if (!group) {
+ const char *name = STR2CSTR(arg1);
+ int nid = OBJ_sn2nid(name);
+
+ if (nid == NID_undef)
+ ossl_raise(eEC_GROUP, "unknown curve name (%s)", name);
+
+ group = EC_GROUP_new_by_curve_name(nid);
+ if (group == NULL)
+ ossl_raise(eEC_GROUP, "unable to create curve (%s)", name);
+
+ EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
+ EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);
+ }
+ }
+
+ break;
+ case 4:
+ if (SYMBOL_P(arg1)) {
+ ID id = SYM2ID(arg1);
+ EC_GROUP *(*new_curve)(const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *) = NULL;
+ const BIGNUM *p = GetBNPtr(arg2);
+ const BIGNUM *a = GetBNPtr(arg3);
+ const BIGNUM *b = GetBNPtr(arg4);
+
+ if (id == s_GFp) {
+ new_curve = EC_GROUP_new_curve_GFp;
+ } else if (id == s_GF2m) {
+ new_curve = EC_GROUP_new_curve_GF2m;
+ } else {
+ rb_raise(rb_eArgError, "unknown symbol, must be :GFp or :GF2m");
+ }
+
+ if ((group = new_curve(p, a, b, ossl_bn_ctx)) == NULL)
+ ossl_raise(eEC_GROUP, "EC_GROUP_new_by_GF*");
+ } else {
+ rb_raise(rb_eArgError, "unknown argument, must be :GFp or :GF2m");
+ }
+
+ break;
+ default:
+ rb_raise(rb_eArgError, "wrong number of arguments");
+ }
+
+ if (group == NULL)
+ ossl_raise(eEC_GROUP, "");
+
+ ec_group->group = group;
+
+ return self;
+}
+
+/* call-seq:
+ * group1 == group2 => true | false
+ *
+ */
+static VALUE ossl_ec_group_eql(VALUE a, VALUE b)
+{
+ EC_GROUP *group1 = NULL, *group2 = NULL;
+
+ Require_EC_GROUP(a, group1);
+ SafeRequire_EC_GROUP(b, group2);
+
+ if (EC_GROUP_cmp(group1, group2, ossl_bn_ctx) == 1)
+ return Qfalse;
+
+ return Qtrue;
+}
+
+/* call-seq:
+ * group.generator => ec_point
+ *
+ * See the OpenSSL documentation for EC_GROUP_get0_generator()
+ */
+static VALUE ossl_ec_group_get_generator(VALUE self)
+{
+ VALUE point_obj;
+ EC_GROUP *group = NULL;
+
+ Require_EC_GROUP(self, group);
+
+ point_obj = ossl_ec_point_dup(EC_GROUP_get0_generator(group), self);
+
+ return point_obj;
+}
+
+/* call-seq:
+ * group.set_generator(generator, order, cofactor) => self
+ *
+ * See the OpenSSL documentation for EC_GROUP_set_generator()
+ */
+static VALUE ossl_ec_group_set_generator(VALUE self, VALUE generator, VALUE order, VALUE cofactor)
+{
+ EC_GROUP *group = NULL;
+ const EC_POINT *point;
+ const BIGNUM *o, *co;
+
+ Require_EC_GROUP(self, group);
+ SafeRequire_EC_POINT(generator, point);
+ o = GetBNPtr(order);
+ co = GetBNPtr(cofactor);
+
+ if (EC_GROUP_set_generator(group, point, o, co) != 1)
+ ossl_raise(eEC_GROUP, "EC_GROUP_set_generator");
+
+ return self;
+}
+
+/* call-seq:
+ * group.get_order => order_bn
+ *
+ * See the OpenSSL documentation for EC_GROUP_get_order()
+ */
+static VALUE ossl_ec_group_get_order(VALUE self)
+{
+ VALUE bn_obj;
+ BIGNUM *bn;
+ EC_GROUP *group = NULL;
+
+ Require_EC_GROUP(self, group);
+
+ bn_obj = ossl_bn_new(NULL);
+ bn = GetBNPtr(bn_obj);
+
+ if (EC_GROUP_get_order(group, bn, ossl_bn_ctx) != 1)
+ ossl_raise(eEC_GROUP, "EC_GROUP_get_order");
+
+ return bn_obj;
+}
+
+/* call-seq:
+ * group.get_cofactor => cofactor_bn
+ *
+ * See the OpenSSL documentation for EC_GROUP_get_cofactor()
+ */
+static VALUE ossl_ec_group_get_cofactor(VALUE self)
+{
+ VALUE bn_obj;
+ BIGNUM *bn;
+ EC_GROUP *group = NULL;
+
+ Require_EC_GROUP(self, group);
+
+ bn_obj = ossl_bn_new(NULL);
+ bn = GetBNPtr(bn_obj);
+
+ if (EC_GROUP_get_cofactor(group, bn, ossl_bn_ctx) != 1)
+ ossl_raise(eEC_GROUP, "EC_GROUP_get_cofactor");
+
+ return bn_obj;
+}
+
+/* call-seq:
+ * group.curve_name => String
+ *
+ * See the OpenSSL documentation for EC_GROUP_get_curve_name()
+ */
+static VALUE ossl_ec_group_get_curve_name(VALUE self)
+{
+ EC_GROUP *group = NULL;
+ int nid;
+
+ Get_EC_GROUP(self, group);
+ if (group == NULL)
+ return Qnil;
+
+ nid = EC_GROUP_get_curve_name(group);
+
+/* BUG: an nid or asn1 object should be returned, maybe. */
+ return rb_str_new2(OBJ_nid2sn(nid));
+}
+
+/* call-seq:
+ * EC.builtin_curves => [[name, comment], ...]
+ *
+ * See the OpenSSL documentation for EC_builtin_curves()
+ */
+static VALUE ossl_s_builtin_curves(VALUE self)
+{
+ EC_builtin_curve *curves = NULL;
+ int n;
+ int crv_len = EC_get_builtin_curves(NULL, 0);
+ VALUE ary, ret;
+
+ curves = ALLOCA_N(EC_builtin_curve, crv_len);
+ if (curves == NULL)
+ return Qnil;
+ if (!EC_get_builtin_curves(curves, crv_len))
+ ossl_raise(rb_eRuntimeError, "EC_get_builtin_curves");
+
+ ret = rb_ary_new2(crv_len);
+
+ for (n = 0; n < crv_len; n++) {
+ const char *sname = OBJ_nid2sn(curves[n].nid);
+ const char *comment = curves[n].comment;
+
+ ary = rb_ary_new2(2);
+ rb_ary_push(ary, rb_str_new2(sname));
+ rb_ary_push(ary, comment ? rb_str_new2(comment) : Qnil);
+ rb_ary_push(ret, ary);
+ }
+
+ return ret;
+}
+
+/* call-seq:
+ * group.asn1_flag => Fixnum
+ *
+ * See the OpenSSL documentation for EC_GROUP_get_asn1_flag()
+ */
+static VALUE ossl_ec_group_get_asn1_flag(VALUE self)
+{
+ EC_GROUP *group = NULL;
+ int flag;
+
+ Require_EC_GROUP(self, group);
+
+ flag = EC_GROUP_get_asn1_flag(group);
+
+ return INT2FIX(flag);
+}
+
+/* call-seq:
+ * group.asn1_flag = Fixnum => Fixnum
+ *
+ * See the OpenSSL documentation for EC_GROUP_set_asn1_flag()
+ */
+static VALUE ossl_ec_group_set_asn1_flag(VALUE self, VALUE flag_v)
+{
+ EC_GROUP *group = NULL;
+
+ Require_EC_GROUP(self, group);
+
+ EC_GROUP_set_asn1_flag(group, NUM2INT(flag_v));
+
+ return flag_v;
+}
+
+/* call-seq:
+ * group.point_conversion_form => :uncompressed | :compressed | :hybrid
+ *
+ * See the OpenSSL documentation for EC_GROUP_get_point_conversion_form()
+ */
+static VALUE ossl_ec_group_get_point_conversion_form(VALUE self)
+{
+ EC_GROUP *group = NULL;
+ point_conversion_form_t form;
+ VALUE ret;
+
+ Require_EC_GROUP(self, group);
+
+ form = EC_GROUP_get_point_conversion_form(group);
+
+ switch (form) {
+ case POINT_CONVERSION_UNCOMPRESSED: ret = ID_uncompressed; break;
+ case POINT_CONVERSION_COMPRESSED: ret = ID_compressed; break;
+ case POINT_CONVERSION_HYBRID: ret = ID_hybrid; break;
+ default: rb_raise(eEC_GROUP, "unsupported point conversion form: %d, this module should be updated", form);
+ }
+
+ return ID2SYM(ret);
+}
+
+/* call-seq:
+ * group.point_conversion_form = form => form
+ *
+ * See the OpenSSL documentation for EC_GROUP_set_point_conversion_form()
+ */
+static VALUE ossl_ec_group_set_point_conversion_form(VALUE self, VALUE form_v)
+{
+ EC_GROUP *group = NULL;
+ point_conversion_form_t form;
+ ID form_id = SYM2ID(form_v);
+
+ Require_EC_GROUP(self, group);
+
+ if (form_id == ID_uncompressed) {
+ form = POINT_CONVERSION_UNCOMPRESSED;
+ } else if (form_id == ID_compressed) {
+ form = POINT_CONVERSION_COMPRESSED;
+ } else if (form_id == ID_hybrid) {
+ form = POINT_CONVERSION_HYBRID;
+ } else {
+ rb_raise(rb_eArgError, "form must be :compressed, :uncompressed, or :hybrid");
+ }
+
+ EC_GROUP_set_point_conversion_form(group, form);
+
+ return form_v;
+}
+
+/* call-seq:
+ * group.seed => String or nil
+ *
+ * See the OpenSSL documentation for EC_GROUP_get0_seed()
+ */
+static VALUE ossl_ec_group_get_seed(VALUE self)
+{
+ EC_GROUP *group = NULL;
+ size_t seed_len;
+
+ Require_EC_GROUP(self, group);
+
+ seed_len = EC_GROUP_get_seed_len(group);
+
+ if (seed_len == 0)
+ return Qnil;
+
+ return rb_str_new(EC_GROUP_get0_seed(group), seed_len);
+}
+
+/* call-seq:
+ * group.seed = seed => seed
+ *
+ * See the OpenSSL documentation for EC_GROUP_set_seed()
+ */
+static VALUE ossl_ec_group_set_seed(VALUE self, VALUE seed)
+{
+ EC_GROUP *group = NULL;
+
+ Require_EC_GROUP(self, group);
+ StringValue(seed);
+
+ if (EC_GROUP_set_seed(group, RSTRING_PTR(seed), RSTRING_LEN(seed)) != RSTRING_LEN(seed))
+ ossl_raise(eEC_GROUP, "EC_GROUP_set_seed");
+
+ return seed;
+}
+
+/* get/set curve GFp, GF2m */
+
+/* call-seq:
+ * group.degree => Fixnum
+ *
+ * See the OpenSSL documentation for EC_GROUP_get_degree()
+ */
+static VALUE ossl_ec_group_get_degree(VALUE self)
+{
+ EC_GROUP *group = NULL;
+
+ Require_EC_GROUP(self, group);
+
+ return INT2NUM(EC_GROUP_get_degree(group));
+}
+
+static VALUE ossl_ec_group_to_string(VALUE self, int format)
+{
+ EC_GROUP *group;
+ BIO *out;
+ int i = -1;
+ VALUE str;
+
+ Get_EC_GROUP(self, group);
+
+ if (!(out = BIO_new(BIO_s_mem())))
+ ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
+
+ switch(format) {
+ case EXPORT_PEM:
+ i = PEM_write_bio_ECPKParameters(out, group);
+ break;
+ case EXPORT_DER:
+ i = i2d_ECPKParameters_bio(out, group);
+ break;
+ default:
+ BIO_free(out);
+ rb_raise(rb_eRuntimeError, "unknown format (internal error)");
+ }
+
+ if (i != 1) {
+ BIO_free(out);
+ ossl_raise(eECError, NULL);
+ }
+
+ str = ossl_membio2str(out);
+
+ return str;
+}
+
+/* call-seq:
+ * group.to_pem => String
+ *
+ * See the OpenSSL documentation for PEM_write_bio_ECPKParameters()
+ */
+static VALUE ossl_ec_group_to_pem(VALUE self)
+{
+ return ossl_ec_group_to_string(self, EXPORT_PEM);
+}
+
+/* call-seq:
+ * group.to_der => String
+ *
+ * See the OpenSSL documentation for i2d_ECPKParameters_bio()
+ */
+static VALUE ossl_ec_group_to_der(VALUE self)
+{
+ return ossl_ec_group_to_string(self, EXPORT_DER);
+}
+
+/* call-seq:
+ * group.to_text => String
+ *
+ * See the OpenSSL documentation for ECPKParameters_print()
+ */
+static VALUE ossl_ec_group_to_text(VALUE self)
+{
+ EC_GROUP *group;
+ BIO *out;
+ VALUE str;
+
+ Require_EC_GROUP(self, group);
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
+ }
+ if (!ECPKParameters_print(out, group, 0)) {
+ BIO_free(out);
+ ossl_raise(eEC_GROUP, NULL);
+ }
+ str = ossl_membio2str(out);
+
+ return str;
+}
+
+
+static void ossl_ec_point_free(ossl_ec_point *ec_point)
+{
+ if (!ec_point->dont_free && ec_point->point)
+ EC_POINT_clear_free(ec_point->point);
+ ruby_xfree(ec_point);
+}
+
+static VALUE ossl_ec_point_alloc(VALUE klass)
+{
+ ossl_ec_point *ec_point;
+ VALUE obj;
+
+ obj = Data_Make_Struct(klass, ossl_ec_point, 0, ossl_ec_point_free, ec_point);
+
+ return obj;
+}
+
+/*
+ * call-seq:
+ * OpenSSL::PKey::EC::Point.new(point)
+ * OpenSSL::PKey::EC::Point.new(group)
+ * OpenSSL::PKey::EC::Point.new(group, bn)
+ *
+ * See the OpenSSL documentation for EC_POINT_*
+ */
+static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self)
+{
+ ossl_ec_point *ec_point;
+ EC_POINT *point = NULL;
+ VALUE arg1, arg2;
+ VALUE group_v = Qnil;
+ const EC_GROUP *group = NULL;
+
+ Data_Get_Struct(self, ossl_ec_point, ec_point);
+ if (ec_point->point)
+ rb_raise(eEC_POINT, "EC_POINT already initialized");
+
+ switch (rb_scan_args(argc, argv, "11", &arg1, &arg2)) {
+ case 1:
+ if (rb_obj_is_kind_of(arg1, cEC_POINT)) {
+ const EC_POINT *arg_point;
+
+ group_v = rb_iv_get(arg1, "@group");
+ SafeRequire_EC_GROUP(group_v, group);
+ SafeRequire_EC_POINT(arg1, arg_point);
+
+ point = EC_POINT_dup(arg_point, group);
+ } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {
+ group_v = arg1;
+ SafeRequire_EC_GROUP(group_v, group);
+
+ point = EC_POINT_new(group);
+ } else {
+ rb_raise(eEC_POINT, "wrong argument type: must be OpenSSL::PKey::EC::Point or OpenSSL::Pkey::EC::Group");
+ }
+
+ break;
+ case 2:
+ if (!rb_obj_is_kind_of(arg1, cEC_GROUP))
+ rb_raise(rb_eArgError, "1st argument must be OpenSSL::PKey::EC::Group");
+ group_v = arg1;
+ SafeRequire_EC_GROUP(group_v, group);
+
+ if (rb_obj_is_kind_of(arg2, cBN)) {
+ const BIGNUM *bn = GetBNPtr(arg2);
+
+ point = EC_POINT_bn2point(group, bn, NULL, ossl_bn_ctx);
+ } else {
+ BIO *in = ossl_obj2bio(arg1);
+
+/* BUG: finish me */
+
+ BIO_free(in);
+
+ if (point == NULL) {
+ ossl_raise(eEC_POINT, "unknown type for 2nd arg");
+ }
+ }
+ break;
+ default:
+ rb_raise(rb_eArgError, "wrong number of arguments");
+ }
+
+ if (point == NULL)
+ ossl_raise(eEC_POINT, NULL);
+
+ if (NIL_P(group_v))
+ rb_raise(rb_eRuntimeError, "missing group (internal error)");
+
+ ec_point->point = point;
+
+ rb_iv_set(self, "@group", group_v);
+
+ return self;
+}
+
+/*
+ * call-seq:
+ * point1 == point2 => true | false
+ *
+ */
+static VALUE ossl_ec_point_eql(VALUE a, VALUE b)
+{
+ EC_POINT *point1, *point2;
+ VALUE group_v1 = rb_iv_get(a, "@group");
+ VALUE group_v2 = rb_iv_get(b, "@group");
+ const EC_GROUP *group;
+
+ if (ossl_ec_group_eql(group_v1, group_v2) == Qfalse)
+ return Qfalse;
+
+ Require_EC_POINT(a, point1);
+ SafeRequire_EC_POINT(b, point2);
+ SafeRequire_EC_GROUP(group_v1, group);
+
+ if (EC_POINT_cmp(group, point1, point2, ossl_bn_ctx) == 1)
+ return Qfalse;
+
+ return Qtrue;
+}
+
+/*
+ * call-seq:
+ * point.infinity? => true | false
+ *
+ */
+static VALUE ossl_ec_point_is_at_infinity(VALUE self)
+{
+ EC_POINT *point;
+ VALUE group_v = rb_iv_get(self, "@group");
+ const EC_GROUP *group;
+
+ Require_EC_POINT(self, point);
+ SafeRequire_EC_GROUP(group_v, group);
+
+ switch (EC_POINT_is_at_infinity(group, point)) {
+ case 1: return Qtrue;
+ case 0: return Qfalse;
+ default: ossl_raise(cEC_POINT, "EC_POINT_is_at_infinity");
+ }
+}
+
+/*
+ * call-seq:
+ * point.on_curve? => true | false
+ *
+ */
+static VALUE ossl_ec_point_is_on_curve(VALUE self)
+{
+ EC_POINT *point;
+ VALUE group_v = rb_iv_get(self, "@group");
+ const EC_GROUP *group;
+
+ Require_EC_POINT(self, point);
+ SafeRequire_EC_GROUP(group_v, group);
+
+ switch (EC_POINT_is_on_curve(group, point, ossl_bn_ctx)) {
+ case 1: return Qtrue;
+ case 0: return Qfalse;
+ default: ossl_raise(cEC_POINT, "EC_POINT_is_on_curve");
+ }
+}
+
+/*
+ * call-seq:
+ * point.make_affine! => self
+ *
+ */
+static VALUE ossl_ec_point_make_affine(VALUE self)
+{
+ EC_POINT *point;
+ VALUE group_v = rb_iv_get(self, "@group");
+ const EC_GROUP *group;
+
+ Require_EC_POINT(self, point);
+ SafeRequire_EC_GROUP(group_v, group);
+
+ if (EC_POINT_make_affine(group, point, ossl_bn_ctx) != 1)
+ ossl_raise(cEC_POINT, "EC_POINT_make_affine");
+
+ return self;
+}
+
+/*
+ * call-seq:
+ * point.invert! => self
+ *
+ */
+static VALUE ossl_ec_point_invert(VALUE self)
+{
+ EC_POINT *point;
+ VALUE group_v = rb_iv_get(self, "@group");
+ const EC_GROUP *group;
+
+ Require_EC_POINT(self, point);
+ SafeRequire_EC_GROUP(group_v, group);
+
+ if (EC_POINT_invert(group, point, ossl_bn_ctx) != 1)
+ ossl_raise(cEC_POINT, "EC_POINT_invert");
+
+ return self;
+}
+
+/*
+ * call-seq:
+ * point.set_to_infinity! => self
+ *
+ */
+static VALUE ossl_ec_point_set_to_infinity(VALUE self)
+{
+ EC_POINT *point;
+ VALUE group_v = rb_iv_get(self, "@group");
+ const EC_GROUP *group;
+
+ Require_EC_POINT(self, point);
+ SafeRequire_EC_GROUP(group_v, group);
+
+ if (EC_POINT_set_to_infinity(group, point) != 1)
+ ossl_raise(cEC_POINT, "EC_POINT_set_to_infinity");
+
+ return self;
+}
+
+/*
+ * call-seq:
+ * point.to_bn => OpenSSL::BN
+ *
+ * See the OpenSSL documentation for EC_POINT_point2bn()
+ */
+static VALUE ossl_ec_point_to_bn(VALUE self)
+{
+ EC_POINT *point;
+ VALUE bn_obj;
+ VALUE group_v = rb_iv_get(self, "@group");
+ const EC_GROUP *group;
+ point_conversion_form_t form;
+ BIGNUM *bn;
+
+ Require_EC_POINT(self, point);
+ SafeRequire_EC_GROUP(group_v, group);
+
+ form = EC_GROUP_get_point_conversion_form(group);
+
+ bn_obj = rb_obj_alloc(cBN);
+ bn = GetBNPtr(bn_obj);
+
+ if (EC_POINT_point2bn(group, point, form, bn, ossl_bn_ctx) == NULL)
+ ossl_raise(eEC_POINT, "EC_POINT_point2bn");
+
+ return bn_obj;
+}
+
+static void no_copy(VALUE klass)
+{
+ rb_undef_method(klass, "copy");
+ rb_undef_method(klass, "clone");
+ rb_undef_method(klass, "dup");
+ rb_undef_method(klass, "initialize_copy");
+}
+
+void Init_ossl_ec()
+{
+#ifdef DONT_NEED_RDOC_WORKAROUND
+ mOSSL = rb_define_module("OpenSSL");
+ mPKey = rb_define_module_under(mOSSL, "PKey");
+#endif
+
+ eECError = rb_define_class_under(mPKey, "ECError", ePKeyError);
+
+ cEC = rb_define_class_under(mPKey, "EC", cPKey);
+ cEC_GROUP = rb_define_class_under(cEC, "Group", rb_cObject);
+ cEC_POINT = rb_define_class_under(cEC, "Point", rb_cObject);
+ eEC_GROUP = rb_define_class_under(cEC_GROUP, "Error", eOSSLError);
+ eEC_POINT = rb_define_class_under(cEC_POINT, "Error", eOSSLError);
+
+ s_GFp = rb_intern("GFp");
+ s_GF2m = rb_intern("GF2m");
+ s_GFp_simple = rb_intern("GFp_simple");
+ s_GFp_mont = rb_intern("GFp_mont");
+ s_GFp_nist = rb_intern("GFp_nist");
+ s_GF2m_simple = rb_intern("GF2m_simple");
+
+ ID_uncompressed = rb_intern("uncompressed");
+ ID_compressed = rb_intern("compressed");
+ ID_hybrid = rb_intern("hybrid");
+
+#ifdef OPENSSL_EC_NAMED_CURVE
+ rb_define_const(cEC, "NAMED_CURVE", ULONG2NUM(OPENSSL_EC_NAMED_CURVE));
+#endif
+
+ rb_define_singleton_method(cEC, "builtin_curves", ossl_s_builtin_curves, 0);
+
+ rb_define_method(cEC, "initialize", ossl_ec_key_initialize, -1);
+/* copy/dup/cmp */
+
+ rb_define_method(cEC, "group", ossl_ec_key_get_group, 0);
+ rb_define_method(cEC, "group=", ossl_ec_key_set_group, 1);
+ rb_define_method(cEC, "private_key", ossl_ec_key_get_private_key, 0);
+ rb_define_method(cEC, "private_key=", ossl_ec_key_set_private_key, 1);
+ rb_define_method(cEC, "public_key", ossl_ec_key_get_public_key, 0);
+ rb_define_method(cEC, "public_key=", ossl_ec_key_set_public_key, 1);
+ rb_define_method(cEC, "private_key?", ossl_ec_key_is_private_key, 0);
+ rb_define_method(cEC, "public_key?", ossl_ec_key_is_public_key, 0);
+/* rb_define_method(cEC, "", ossl_ec_key_get_, 0);
+ rb_define_method(cEC, "=", ossl_ec_key_set_ 1);
+ set/get enc_flags
+ set/get _conv_from
+ set/get asn1_flag (can use ruby to call self.group.asn1_flag)
+ set/get precompute_mult
+*/
+ rb_define_method(cEC, "generate_key", ossl_ec_key_generate_key, 0);
+ rb_define_method(cEC, "check_key", ossl_ec_key_check_key, 0);
+
+ rb_define_method(cEC, "dh_compute_key", ossl_ec_key_dh_compute_key, 1);
+ rb_define_method(cEC, "dsa_sign_asn1", ossl_ec_key_dsa_sign_asn1, 1);
+ rb_define_method(cEC, "dsa_verify_asn1", ossl_ec_key_dsa_verify_asn1, 2);
+/* do_sign/do_verify */
+
+ rb_define_method(cEC, "to_pem", ossl_ec_key_to_pem, 0);
+ rb_define_method(cEC, "to_der", ossl_ec_key_to_der, 0);
+ rb_define_method(cEC, "to_text", ossl_ec_key_to_text, 0);
+
+
+ rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc);
+ rb_define_method(cEC_GROUP, "initialize", ossl_ec_group_initialize, -1);
+ rb_define_method(cEC_GROUP, "eql?", ossl_ec_group_eql, 1);
+ rb_define_alias(cEC_GROUP, "==", "eql?");
+/* copy/dup/cmp */
+
+ rb_define_method(cEC_GROUP, "generator", ossl_ec_group_get_generator, 0);
+ rb_define_method(cEC_GROUP, "set_generator", ossl_ec_group_set_generator, 3);
+ rb_define_method(cEC_GROUP, "order", ossl_ec_group_get_order, 0);
+ rb_define_method(cEC_GROUP, "cofactor", ossl_ec_group_get_cofactor, 0);
+
+ rb_define_method(cEC_GROUP, "curve_name", ossl_ec_group_get_curve_name, 0);
+/* rb_define_method(cEC_GROUP, "curve_name=", ossl_ec_group_set_curve_name, 1); */
+
+ rb_define_method(cEC_GROUP, "asn1_flag", ossl_ec_group_get_asn1_flag, 0);
+ rb_define_method(cEC_GROUP, "asn1_flag=", ossl_ec_group_set_asn1_flag, 1);
+
+ rb_define_method(cEC_GROUP, "point_conversion_form", ossl_ec_group_get_point_conversion_form, 0);
+ rb_define_method(cEC_GROUP, "point_conversion_form=", ossl_ec_group_set_point_conversion_form, 1);
+
+ rb_define_method(cEC_GROUP, "seed", ossl_ec_group_get_seed, 0);
+ rb_define_method(cEC_GROUP, "seed=", ossl_ec_group_set_seed, 1);
+
+/* get/set GFp, GF2m */
+
+ rb_define_method(cEC_GROUP, "degree", ossl_ec_group_get_degree, 0);
+
+/* check* */
+
+
+ rb_define_method(cEC_GROUP, "to_pem", ossl_ec_group_to_pem, 0);
+ rb_define_method(cEC_GROUP, "to_der", ossl_ec_group_to_der, 0);
+ rb_define_method(cEC_GROUP, "to_text", ossl_ec_group_to_text, 0);
+
+
+ rb_define_alloc_func(cEC_POINT, ossl_ec_point_alloc);
+ rb_define_method(cEC_POINT, "initialize", ossl_ec_point_initialize, -1);
+ rb_attr(cEC_POINT, rb_intern("group"), 1, 0, 0);
+ rb_define_method(cEC_POINT, "eql?", ossl_ec_point_eql, 1);
+ rb_define_alias(cEC_POINT, "==", "eql?");
+
+ rb_define_method(cEC_POINT, "infinity?", ossl_ec_point_is_at_infinity, 0);
+ rb_define_method(cEC_POINT, "on_curve?", ossl_ec_point_is_on_curve, 0);
+ rb_define_method(cEC_POINT, "make_affine!", ossl_ec_point_make_affine, 0);
+ rb_define_method(cEC_POINT, "invert!", ossl_ec_point_invert, 0);
+ rb_define_method(cEC_POINT, "set_to_infinity!", ossl_ec_point_set_to_infinity, 0);
+/* all the other methods */
+
+ rb_define_method(cEC_POINT, "to_bn", ossl_ec_point_to_bn, 0);
+
+ no_copy(cEC);
+ no_copy(cEC_GROUP);
+ no_copy(cEC_POINT);
+}
+
+#else /* defined NO_EC */
+void Init_ossl_ec()
+{
+}
+#endif /* NO_EC */
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c
index 69d69c76f4..320bbf5207 100644
--- a/ext/openssl/ossl_pkey_rsa.c
+++ b/ext/openssl/ossl_pkey_rsa.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_pkey_rsa.c,v 1.5.2.4 2005/09/18 22:56:11 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -84,9 +84,19 @@ rsa_generate(int size, int exp)
NULL);
}
+/*
+ * call-seq:
+ * RSA.generate(size [, exponent]) -> rsa
+ *
+ * === Parameters
+ * * +size+ is an integer representing the desired key size. Keys smaller than 1024 should be considered insecure.
+ * * +exponent+ is an odd number normally 3, 17, or 65537.
+ *
+ */
static VALUE
ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass)
{
+/* why does this method exist? why can't initialize take an optional exponent? */
RSA *rsa;
VALUE size, exp;
VALUE obj;
@@ -104,6 +114,20 @@ ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass)
return obj;
}
+/*
+ * call-seq:
+ * RSA.new([size | encoded_key] [, pass]) -> rsa
+ *
+ * === Parameters
+ * * +size+ is an integer representing the desired key size.
+ * * +encoded_key+ is a string containing PEM or DER encoded key.
+ * * +pass+ is an optional string with the password to decrypt the encoded key.
+ *
+ * === Examples
+ * * RSA.new(2048) -> rsa
+ * * RSA.new(File.read("rsa.pem")) -> rsa
+ * * RSA.new(File.read("rsa.pem"), "mypassword") -> rsa
+ */
static VALUE
ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
{
@@ -157,6 +181,13 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
return self;
}
+/*
+ * call-seq:
+ * rsa.public? -> true
+ *
+ * The return value is always true since every private key is also a public key.
+ *
+ */
static VALUE
ossl_rsa_is_public(VALUE self)
{
@@ -164,12 +195,16 @@ ossl_rsa_is_public(VALUE self)
GetPKeyRSA(self, pkey);
/*
- * SURPRISE! :-))
- * Every key is public at the same time!
+ * This method should check for n and e. BUG.
*/
return Qtrue;
}
+/*
+ * call-seq:
+ * rsa.private? -> true | false
+ *
+ */
static VALUE
ossl_rsa_is_private(VALUE self)
{
@@ -180,6 +215,18 @@ ossl_rsa_is_private(VALUE self)
return (RSA_PRIVATE(self, pkey->pkey.rsa)) ? Qtrue : Qfalse;
}
+/*
+ * call-seq:
+ * rsa.to_pem([cipher, pass]) -> aString
+ *
+ * === Parameters
+ * * +cipher+ is a Cipher object.
+ * * +pass+ is a string.
+ *
+ * === Examples
+ * * rsa.to_pem -> aString
+ * * rsa.to_pem(cipher, pass) -> aString
+ */
static VALUE
ossl_rsa_export(int argc, VALUE *argv, VALUE self)
{
@@ -219,6 +266,11 @@ ossl_rsa_export(int argc, VALUE *argv, VALUE self)
return str;
}
+/*
+ * call-seq:
+ * rsa.to_der -> aString
+ *
+ */
static VALUE
ossl_rsa_to_der(VALUE self)
{
@@ -236,7 +288,7 @@ ossl_rsa_to_der(VALUE self)
if((len = i2d_func(pkey->pkey.rsa, NULL)) <= 0)
ossl_raise(eRSAError, NULL);
str = rb_str_new(0, len);
- p = RSTRING(str)->ptr;
+ p = RSTRING_PTR(str);
if(i2d_func(pkey->pkey.rsa, &p) < 0)
ossl_raise(eRSAError, NULL);
ossl_str_adjust(str, p);
@@ -246,6 +298,11 @@ ossl_rsa_to_der(VALUE self)
#define ossl_rsa_buf_size(pkey) (RSA_size((pkey)->pkey.rsa)+16)
+/*
+ * call-seq:
+ * rsa.public_encrypt(string [, padding]) -> aString
+ *
+ */
static VALUE
ossl_rsa_public_encrypt(int argc, VALUE *argv, VALUE self)
{
@@ -258,16 +315,20 @@ ossl_rsa_public_encrypt(int argc, VALUE *argv, VALUE self)
pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding);
StringValue(buffer);
str = rb_str_new(0, ossl_rsa_buf_size(pkey));
- buf_len = RSA_public_encrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr,
- RSTRING(str)->ptr, pkey->pkey.rsa,
+ buf_len = RSA_public_encrypt(RSTRING_LEN(buffer), RSTRING_PTR(buffer),
+ RSTRING_PTR(str), pkey->pkey.rsa,
pad);
if (buf_len < 0) ossl_raise(eRSAError, NULL);
- RSTRING(str)->len = buf_len;
- RSTRING(str)->ptr[buf_len] = 0;
+ rb_str_set_len(str, buf_len);
return str;
}
+/*
+ * call-seq:
+ * rsa.public_decrypt(string [, padding]) -> aString
+ *
+ */
static VALUE
ossl_rsa_public_decrypt(int argc, VALUE *argv, VALUE self)
{
@@ -280,16 +341,20 @@ ossl_rsa_public_decrypt(int argc, VALUE *argv, VALUE self)
pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding);
StringValue(buffer);
str = rb_str_new(0, ossl_rsa_buf_size(pkey));
- buf_len = RSA_public_decrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr,
- RSTRING(str)->ptr, pkey->pkey.rsa,
+ buf_len = RSA_public_decrypt(RSTRING_LEN(buffer), RSTRING_PTR(buffer),
+ RSTRING_PTR(str), pkey->pkey.rsa,
pad);
if (buf_len < 0) ossl_raise(eRSAError, NULL);
- RSTRING(str)->len = buf_len;
- RSTRING(str)->ptr[buf_len] = 0;
+ rb_str_set_len(str, buf_len);
return str;
}
+/*
+ * call-seq:
+ * rsa.private_encrypt(string [, padding]) -> aString
+ *
+ */
static VALUE
ossl_rsa_private_encrypt(int argc, VALUE *argv, VALUE self)
{
@@ -305,16 +370,21 @@ ossl_rsa_private_encrypt(int argc, VALUE *argv, VALUE self)
pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding);
StringValue(buffer);
str = rb_str_new(0, ossl_rsa_buf_size(pkey));
- buf_len = RSA_private_encrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr,
- RSTRING(str)->ptr, pkey->pkey.rsa,
+ buf_len = RSA_private_encrypt(RSTRING_LEN(buffer), RSTRING_PTR(buffer),
+ RSTRING_PTR(str), pkey->pkey.rsa,
pad);
if (buf_len < 0) ossl_raise(eRSAError, NULL);
- RSTRING(str)->len = buf_len;
- RSTRING(str)->ptr[buf_len] = 0;
+ rb_str_set_len(str, buf_len);
return str;
}
+
+/*
+ * call-seq:
+ * rsa.private_decrypt(string [, padding]) -> aString
+ *
+ */
static VALUE
ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self)
{
@@ -330,17 +400,19 @@ ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self)
pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding);
StringValue(buffer);
str = rb_str_new(0, ossl_rsa_buf_size(pkey));
- buf_len = RSA_private_decrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr,
- RSTRING(str)->ptr, pkey->pkey.rsa,
+ buf_len = RSA_private_decrypt(RSTRING_LEN(buffer), RSTRING_PTR(buffer),
+ RSTRING_PTR(str), pkey->pkey.rsa,
pad);
if (buf_len < 0) ossl_raise(eRSAError, NULL);
- RSTRING(str)->len = buf_len;
- RSTRING(str)->ptr[buf_len] = 0;
+ rb_str_set_len(str, buf_len);
return str;
}
/*
+ * call-seq:
+ * rsa.params -> hash
+ *
* Stores all parameters of key to the hash
* INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
* Don't use :-)) (I's up to you)
@@ -368,6 +440,9 @@ ossl_rsa_get_params(VALUE self)
}
/*
+ * call-seq:
+ * rsa.to_text -> aString
+ *
* Prints all parameters of key to buffer
* INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
* Don't use :-)) (It's up to you)
@@ -393,6 +468,9 @@ ossl_rsa_to_text(VALUE self)
}
/*
+ * call-seq:
+ * rsa.public_key -> aRSA
+ *
* Makes new instance RSA PUBLIC_KEY from PRIVATE_KEY
*/
static VALUE
@@ -415,7 +493,6 @@ ossl_rsa_to_public_key(VALUE self)
/*
* TODO: Test me
-extern BN_CTX *ossl_bn_ctx;
static VALUE
ossl_rsa_blinding_on(VALUE self)
@@ -442,14 +519,14 @@ ossl_rsa_blinding_off(VALUE self)
}
*/
-OSSL_PKEY_BN(rsa, n);
-OSSL_PKEY_BN(rsa, e);
-OSSL_PKEY_BN(rsa, d);
-OSSL_PKEY_BN(rsa, p);
-OSSL_PKEY_BN(rsa, q);
-OSSL_PKEY_BN(rsa, dmp1);
-OSSL_PKEY_BN(rsa, dmq1);
-OSSL_PKEY_BN(rsa, iqmp);
+OSSL_PKEY_BN(rsa, n)
+OSSL_PKEY_BN(rsa, e)
+OSSL_PKEY_BN(rsa, d)
+OSSL_PKEY_BN(rsa, p)
+OSSL_PKEY_BN(rsa, q)
+OSSL_PKEY_BN(rsa, dmp1)
+OSSL_PKEY_BN(rsa, dmq1)
+OSSL_PKEY_BN(rsa, iqmp)
/*
* INIT
@@ -459,6 +536,11 @@ OSSL_PKEY_BN(rsa, iqmp);
void
Init_ossl_rsa()
{
+#if 0 /* let rdoc know about mOSSL and mPKey */
+ mOSSL = rb_define_module("OpenSSL");
+ mPKey = rb_define_module_under(mOSSL, "PKey");
+#endif
+
eRSAError = rb_define_class_under(mPKey, "RSAError", ePKeyError);
cRSA = rb_define_class_under(mPKey, "RSA", cPKey);
@@ -503,11 +585,9 @@ Init_ossl_rsa()
}
#else /* defined NO_RSA */
-# warning >>> OpenSSL is compiled without RSA support <<<
void
Init_ossl_rsa()
{
- rb_warning("OpenSSL is compiled without RSA support");
}
#endif /* NO_RSA */
diff --git a/ext/openssl/ossl_rand.c b/ext/openssl/ossl_rand.c
index ffd68966ca..ad830fbc98 100644
--- a/ext/openssl/ossl_rand.c
+++ b/ext/openssl/ossl_rand.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_rand.c,v 1.2 2003/09/17 09:05:02 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -27,84 +27,150 @@ VALUE eRandomError;
/*
* Private
*/
+
+/*
+ * call-seq:
+ * seed(str) -> str
+ *
+ */
static VALUE
ossl_rand_seed(VALUE self, VALUE str)
{
StringValue(str);
- RAND_seed(RSTRING(str)->ptr, RSTRING(str)->len);
+ RAND_seed(RSTRING_PTR(str), RSTRING_LEN(str));
return str;
}
+/*
+ * call-seq:
+ * add(str, entropy) -> self
+ *
+ */
+static VALUE
+ossl_rand_add(VALUE self, VALUE str, VALUE entropy)
+{
+ StringValue(str);
+ RAND_add(RSTRING_PTR(str), RSTRING_LEN(str), NUM2DBL(entropy));
+
+ return self;
+}
+
+/*
+ * call-seq:
+ * load_random_file(filename) -> true
+ *
+ */
static VALUE
ossl_rand_load_file(VALUE self, VALUE filename)
{
SafeStringValue(filename);
- if(!RAND_load_file(RSTRING(filename)->ptr, -1)) {
+ if(!RAND_load_file(RSTRING_PTR(filename), -1)) {
ossl_raise(eRandomError, NULL);
}
return Qtrue;
}
+/*
+ * call-seq:
+ * write_random_file(filename) -> true
+ *
+ */
static VALUE
ossl_rand_write_file(VALUE self, VALUE filename)
{
SafeStringValue(filename);
- if (RAND_write_file(RSTRING(filename)->ptr) == -1) {
+ if (RAND_write_file(RSTRING_PTR(filename)) == -1) {
ossl_raise(eRandomError, NULL);
}
return Qtrue;
}
+/*
+ * call-seq:
+ * random_bytes(length) -> aString
+ *
+ */
static VALUE
ossl_rand_bytes(VALUE self, VALUE len)
{
VALUE str;
-
- str = rb_str_new(0, FIX2INT(len));
- if (!RAND_bytes(RSTRING(str)->ptr, FIX2INT(len))) {
+ int n = NUM2INT(len);
+
+ str = rb_str_new(0, n);
+ if (!RAND_bytes(RSTRING_PTR(str), n)) {
ossl_raise(eRandomError, NULL);
}
return str;
}
+/*
+ * call-seq:
+ * pseudo_bytes(length) -> aString
+ *
+ */
static VALUE
ossl_rand_pseudo_bytes(VALUE self, VALUE len)
{
VALUE str;
+ int n = NUM2INT(len);
- str = rb_str_new(0, FIX2INT(len));
- if (!RAND_pseudo_bytes(RSTRING(str)->ptr, FIX2INT(len))) {
+ str = rb_str_new(0, n);
+ if (!RAND_pseudo_bytes(RSTRING_PTR(str), n)) {
ossl_raise(eRandomError, NULL);
}
return str;
}
+/*
+ * call-seq:
+ * egd(filename) -> true
+ *
+ */
static VALUE
ossl_rand_egd(VALUE self, VALUE filename)
{
SafeStringValue(filename);
- if(!RAND_egd(RSTRING(filename)->ptr)) {
+ if(!RAND_egd(RSTRING_PTR(filename))) {
ossl_raise(eRandomError, NULL);
}
return Qtrue;
}
+/*
+ * call-seq:
+ * egd_bytes(filename, length) -> true
+ *
+ */
static VALUE
ossl_rand_egd_bytes(VALUE self, VALUE filename, VALUE len)
{
+ long n = NUM2INT(len);
+
SafeStringValue(filename);
- if (!RAND_egd_bytes(RSTRING(filename)->ptr, FIX2INT(len))) {
+ if (!RAND_egd_bytes(RSTRING_PTR(filename), n)) {
ossl_raise(eRandomError, NULL);
}
return Qtrue;
}
+/*
+ * call-seq:
+ * status? => true | false
+ *
+ * Return true if the PRNG has been seeded with enough data, false otherwise.
+ */
+static VALUE
+ossl_rand_status(VALUE self)
+{
+ return RAND_status() ? Qtrue : Qfalse;
+}
+
#define DEFMETH(class, name, func, argc) \
rb_define_method(class, name, func, argc); \
rb_define_singleton_method(class, name, func, argc);
@@ -115,16 +181,22 @@ ossl_rand_egd_bytes(VALUE self, VALUE filename, VALUE len)
void
Init_ossl_rand()
{
+#if 0 /* let rdoc know about mOSSL */
+ mOSSL = rb_define_module("OpenSSL");
+#endif
+
mRandom = rb_define_module_under(mOSSL, "Random");
eRandomError = rb_define_class_under(mRandom, "RandomError", eOSSLError);
DEFMETH(mRandom, "seed", ossl_rand_seed, 1);
+ DEFMETH(mRandom, "random_add", ossl_rand_add, 2);
DEFMETH(mRandom, "load_random_file", ossl_rand_load_file, 1);
DEFMETH(mRandom, "write_random_file", ossl_rand_write_file, 1);
DEFMETH(mRandom, "random_bytes", ossl_rand_bytes, 1);
DEFMETH(mRandom, "pseudo_bytes", ossl_rand_pseudo_bytes, 1);
DEFMETH(mRandom, "egd", ossl_rand_egd, 1);
DEFMETH(mRandom, "egd_bytes", ossl_rand_egd_bytes, 2);
+ DEFMETH(mRandom, "status?", ossl_rand_status, 0)
}
diff --git a/ext/openssl/ossl_rand.h b/ext/openssl/ossl_rand.h
index 4895267fb6..ce2ae0d129 100644
--- a/ext/openssl/ossl_rand.h
+++ b/ext/openssl/ossl_rand.h
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_rand.h,v 1.1 2003/07/23 16:11:29 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
index e4889d6d3f..668408fd28 100644
--- a/ext/openssl/ossl_ssl.c
+++ b/ext/openssl/ossl_ssl.c
@@ -1,8 +1,9 @@
/*
- * $Id: ossl_ssl.c,v 1.13.2.11 2006/03/17 10:10:53 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2000-2002 GOTOU Yuuzou <gotoyuzo@notwork.org>
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * Copyright (C) 2001-2007 Technorama Ltd. <oss-ruby@technorama.net>
* All rights reserved.
*/
/*
@@ -30,9 +31,6 @@ VALUE eSSLError;
VALUE cSSLContext;
VALUE cSSLSocket;
-/*
- * SSLContext class
- */
#define ossl_sslctx_set_cert(o,v) rb_iv_set((o),"@cert",(v))
#define ossl_sslctx_set_key(o,v) rb_iv_set((o),"@key",(v))
#define ossl_sslctx_set_client_ca(o,v) rb_iv_set((o),"@client_ca",(v))
@@ -65,11 +63,12 @@ VALUE cSSLSocket;
#define ossl_sslctx_get_tmp_dh_cb(o) rb_iv_get((o),"@tmp_dh_callback")
#define ossl_sslctx_get_sess_id_ctx(o) rb_iv_get((o),"@session_id_context")
-static char *ossl_sslctx_attrs[] = {
+static const char *ossl_sslctx_attrs[] = {
"cert", "key", "client_ca", "ca_file", "ca_path",
"timeout", "verify_mode", "verify_depth",
"verify_callback", "options", "cert_store", "extra_chain_cert",
"client_cert_cb", "tmp_dh_callback", "session_id_context",
+ "session_get_cb", "session_new_cb", "session_remove_cb",
};
#define ossl_ssl_get_io(o) rb_iv_get((o),"@io")
@@ -86,8 +85,10 @@ static char *ossl_sslctx_attrs[] = {
#define ossl_ssl_set_key(o,v) rb_iv_set((o),"@key",(v))
#define ossl_ssl_set_tmp_dh(o,v) rb_iv_set((o),"@tmp_dh",(v))
-static char *ossl_ssl_attr_readers[] = { "io", "context", };
-static char *ossl_ssl_attrs[] = { "sync_close", };
+static const char *ossl_ssl_attr_readers[] = { "io", "context", };
+static const char *ossl_ssl_attrs[] = { "sync_close", };
+
+ID ID_callback_state;
/*
* SSLContext class
@@ -100,9 +101,12 @@ struct {
OSSL_SSL_METHOD_ENTRY(TLSv1),
OSSL_SSL_METHOD_ENTRY(TLSv1_server),
OSSL_SSL_METHOD_ENTRY(TLSv1_client),
+#if defined(HAVE_SSLV2_METHOD) && defined(HAVE_SSLV2_SERVER_METHOD) && \
+ defined(HAVE_SSLV2_CLIENT_METHOD)
OSSL_SSL_METHOD_ENTRY(SSLv2),
OSSL_SSL_METHOD_ENTRY(SSLv2_server),
OSSL_SSL_METHOD_ENTRY(SSLv2_client),
+#endif
OSSL_SSL_METHOD_ENTRY(SSLv3),
OSSL_SSL_METHOD_ENTRY(SSLv3_server),
OSSL_SSL_METHOD_ENTRY(SSLv3_client),
@@ -141,22 +145,13 @@ ossl_sslctx_s_alloc(VALUE klass)
}
static VALUE
-ossl_sslctx_initialize(int argc, VALUE *argv, VALUE self)
+ossl_sslctx_set_ssl_version(VALUE self, VALUE ssl_method)
{
- VALUE ssl_method;
SSL_METHOD *method = NULL;
- SSL_CTX *ctx;
+ const char *s;
int i;
- char *s;
- for(i = 0; i < numberof(ossl_sslctx_attrs); i++){
- char buf[32];
- snprintf(buf, sizeof(buf), "@%s", ossl_sslctx_attrs[i]);
- rb_iv_set(self, buf, Qnil);
- }
- if (rb_scan_args(argc, argv, "01", &ssl_method) == 0){
- return self;
- }
+ SSL_CTX *ctx;
if(TYPE(ssl_method) == T_SYMBOL)
s = rb_id2name(SYM2ID(ssl_method));
else
@@ -175,6 +170,33 @@ ossl_sslctx_initialize(int argc, VALUE *argv, VALUE self)
ossl_raise(eSSLError, "SSL_CTX_set_ssl_version:");
}
+ return ssl_method;
+}
+
+/*
+ * call-seq:
+ * SSLContext.new => ctx
+ * SSLContext.new(:TLSv1) => ctx
+ * SSLContext.new("SSLv23_client") => ctx
+ *
+ * You can get a list of valid methods with OpenSSL::SSL::SSLContext::METHODS
+ */
+static VALUE
+ossl_sslctx_initialize(int argc, VALUE *argv, VALUE self)
+{
+ VALUE ssl_method;
+ int i;
+
+ for(i = 0; i < numberof(ossl_sslctx_attrs); i++){
+ char buf[32];
+ snprintf(buf, sizeof(buf), "@%s", ossl_sslctx_attrs[i]);
+ rb_iv_set(self, buf, Qnil);
+ }
+ if (rb_scan_args(argc, argv, "01", &ssl_method) == 0){
+ return self;
+ }
+ ossl_sslctx_set_ssl_version(self, ssl_method);
+
return self;
}
@@ -251,6 +273,8 @@ ossl_tmp_dh_callback(SSL *ssl, int is_export, int keylength)
static DH*
ossl_default_tmp_dh_callback(SSL *ssl, int is_export, int keylength)
{
+ rb_warning("using default DH parameters.");
+
switch(keylength){
case 512:
return OSSL_DEFAULT_DH_512;
@@ -274,6 +298,143 @@ ossl_ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
}
static VALUE
+ossl_call_session_get_cb(VALUE ary)
+{
+ VALUE ssl_obj, sslctx_obj, cb, ret;
+
+ Check_Type(ary, T_ARRAY);
+ ssl_obj = rb_ary_entry(ary, 0);
+
+ sslctx_obj = rb_iv_get(ssl_obj, "@context");
+ if (NIL_P(sslctx_obj)) return Qnil;
+ cb = rb_iv_get(sslctx_obj, "@session_get_cb");
+ if (NIL_P(cb)) return Qnil;
+
+ return rb_funcall(cb, rb_intern("call"), 1, ary);
+}
+
+/* this method is currently only called for servers (in OpenSSL <= 0.9.8e) */
+static SSL_SESSION *
+ossl_sslctx_session_get_cb(SSL *ssl, unsigned char *buf, int len, int *copy)
+{
+ VALUE ary, ssl_obj, ret_obj;
+ SSL_SESSION *sess;
+ void *ptr;
+ int state = 0;
+
+ OSSL_Debug("SSL SESSION get callback entered");
+ if ((ptr = SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)) == NULL)
+ return NULL;
+ ssl_obj = (VALUE)ptr;
+ ary = rb_ary_new2(2);
+ rb_ary_push(ary, ssl_obj);
+ rb_ary_push(ary, rb_str_new(buf, len));
+
+ ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_session_get_cb, ary, &state);
+ if (state) {
+ rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state));
+ return NULL;
+ }
+ if (!rb_obj_is_instance_of(ret_obj, cSSLSession))
+ return NULL;
+
+ SafeGetSSLSession(ret_obj, sess);
+ *copy = 1;
+
+ return sess;
+}
+
+static VALUE
+ossl_call_session_new_cb(VALUE ary)
+{
+ VALUE ssl_obj, sslctx_obj, cb, ret;
+
+ Check_Type(ary, T_ARRAY);
+ ssl_obj = rb_ary_entry(ary, 0);
+
+ sslctx_obj = rb_iv_get(ssl_obj, "@context");
+ if (NIL_P(sslctx_obj)) return Qnil;
+ cb = rb_iv_get(sslctx_obj, "@session_new_cb");
+ if (NIL_P(cb)) return Qnil;
+
+ return rb_funcall(cb, rb_intern("call"), 1, ary);
+}
+
+/* return 1 normal. return 0 removes the session */
+static int
+ossl_sslctx_session_new_cb(SSL *ssl, SSL_SESSION *sess)
+{
+ VALUE ary, ssl_obj, sess_obj, ret_obj;
+ void *ptr;
+ int state = 0;
+
+ OSSL_Debug("SSL SESSION new callback entered");
+
+ if ((ptr = SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)) == NULL)
+ return 1;
+ ssl_obj = (VALUE)ptr;
+ sess_obj = rb_obj_alloc(cSSLSession);
+ CRYPTO_add(&sess->references, 1, CRYPTO_LOCK_SSL_SESSION);
+ DATA_PTR(sess_obj) = sess;
+
+ ary = rb_ary_new2(2);
+ rb_ary_push(ary, ssl_obj);
+ rb_ary_push(ary, sess_obj);
+
+ ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_session_new_cb, ary, &state);
+ if (state) {
+ rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state));
+ return 0; /* what should be returned here??? */
+ }
+
+ return RTEST(ret_obj) ? 1 : 0;
+}
+
+static VALUE
+ossl_call_session_remove_cb(VALUE ary)
+{
+ VALUE sslctx_obj, cb, ret;
+
+ Check_Type(ary, T_ARRAY);
+ sslctx_obj = rb_ary_entry(ary, 0);
+
+ cb = rb_iv_get(sslctx_obj, "@session_remove_cb");
+ if (NIL_P(cb)) return Qnil;
+
+ return rb_funcall(cb, rb_intern("call"), 1, ary);
+}
+
+static void
+ossl_sslctx_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess)
+{
+ VALUE ary, sslctx_obj, sess_obj, ret_obj;
+ void *ptr;
+ int state = 0;
+
+ OSSL_Debug("SSL SESSION remove callback entered");
+
+ if ((ptr = SSL_CTX_get_ex_data(ctx, ossl_ssl_ex_ptr_idx)) == NULL)
+ return;
+ sslctx_obj = (VALUE)ptr;
+ sess_obj = rb_obj_alloc(cSSLSession);
+ CRYPTO_add(&sess->references, 1, CRYPTO_LOCK_SSL_SESSION);
+ DATA_PTR(sess_obj) = sess;
+
+ ary = rb_ary_new2(2);
+ rb_ary_push(ary, sslctx_obj);
+ rb_ary_push(ary, sess_obj);
+
+ ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_session_new_cb, ary, &state);
+ if (state) {
+/*
+ the SSL_CTX is frozen, nowhere to save state.
+ there is no common accessor method to check it either.
+ rb_ivar_set(sslctx_obj, ID_callback_state, INT2NUM(state));
+*/
+ }
+}
+
+static VALUE
ossl_sslctx_add_extra_chain_cert_i(VALUE i, VALUE arg)
{
X509 *x509;
@@ -288,6 +449,14 @@ ossl_sslctx_add_extra_chain_cert_i(VALUE i, VALUE arg)
return i;
}
+/*
+ * call-seq:
+ * ctx.setup => Qtrue # first time
+ * ctx.setup => nil # thereafter
+ *
+ * This method is called automatically when a new SSLSocket is created.
+ * Normally you do not need to call this method (unless you are writing an extension in C).
+ */
static VALUE
ossl_sslctx_setup(VALUE self)
{
@@ -307,10 +476,10 @@ ossl_sslctx_setup(VALUE self)
SSL_CTX_set_tmp_dh_callback(ctx, ossl_tmp_dh_callback);
}
else{
- rb_warning("using default DH parameters.");
SSL_CTX_set_tmp_dh_callback(ctx, ossl_default_tmp_dh_callback);
}
#endif
+ SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_ptr_idx, (void*)self);
val = ossl_sslctx_get_cert_store(self);
if(!NIL_P(val)){
@@ -327,7 +496,7 @@ ossl_sslctx_setup(VALUE self)
val = ossl_sslctx_get_extra_cert(self);
if(!NIL_P(val)){
- rb_iterate(rb_each, val, ossl_sslctx_add_extra_chain_cert_i, self);
+ rb_block_call(val, rb_intern("each"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, self);
}
/* private key may be bundled in certificate file. */
@@ -352,8 +521,8 @@ ossl_sslctx_setup(VALUE self)
val = ossl_sslctx_get_client_ca(self);
if(!NIL_P(val)){
if(TYPE(val) == T_ARRAY){
- for(i = 0; i < RARRAY(val)->len; i++){
- client_ca = GetX509CertPtr(RARRAY(val)->ptr[i]);
+ for(i = 0; i < RARRAY_LEN(val); i++){
+ client_ca = GetX509CertPtr(RARRAY_PTR(val)[i]);
if (!SSL_CTX_add_client_CA(ctx, client_ca)){
/* Copies X509_NAME => FREE it. */
ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
@@ -397,12 +566,24 @@ ossl_sslctx_setup(VALUE self)
val = ossl_sslctx_get_sess_id_ctx(self);
if (!NIL_P(val)){
StringValue(val);
- if (!SSL_CTX_set_session_id_context(ctx, RSTRING(val)->ptr,
- RSTRING(val)->len)){
- ossl_raise(eSSLError, "SSL_CTX_set_session_id_context:");
+ if (!SSL_CTX_set_session_id_context(ctx, RSTRING_PTR(val),
+ RSTRING_LEN(val))){
+ ossl_raise(eSSLError, "SSL_CTX_set_session_id_context:");
}
}
+ if (RTEST(rb_iv_get(self, "@session_get_cb"))) {
+ SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb);
+ OSSL_Debug("SSL SESSION get callback added");
+ }
+ if (RTEST(rb_iv_get(self, "@session_new_cb"))) {
+ SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb);
+ OSSL_Debug("SSL SESSION new callback added");
+ }
+ if (RTEST(rb_iv_get(self, "@session_remove_cb"))) {
+ SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb);
+ OSSL_Debug("SSL SESSION remove callback added");
+ }
return Qtrue;
}
@@ -422,6 +603,10 @@ ossl_ssl_cipher_to_ary(SSL_CIPHER *cipher)
return ary;
}
+/*
+ * call-seq:
+ * ctx.ciphers => [[name, version, bits, alg_bits], ...]
+ */
static VALUE
ossl_sslctx_get_ciphers(VALUE self)
{
@@ -450,6 +635,12 @@ ossl_sslctx_get_ciphers(VALUE self)
return ary;
}
+/*
+ * call-seq:
+ * ctx.ciphers = "cipher1:cipher2:..."
+ * ctx.ciphers = [name, ...]
+ * ctx.ciphers = [[name, version, bits, alg_bits], ...]
+ */
static VALUE
ossl_sslctx_set_ciphers(VALUE self, VALUE v)
{
@@ -462,12 +653,12 @@ ossl_sslctx_set_ciphers(VALUE self, VALUE v)
return v;
else if (TYPE(v) == T_ARRAY) {
str = rb_str_new(0, 0);
- for (i = 0; i < RARRAY(v)->len; i++) {
+ for (i = 0; i < RARRAY_LEN(v); i++) {
elem = rb_ary_entry(v, i);
if (TYPE(elem) == T_ARRAY) elem = rb_ary_entry(elem, 0);
elem = rb_String(elem);
rb_str_append(str, elem);
- if (i < RARRAY(v)->len-1) rb_str_cat2(str, ":");
+ if (i < RARRAY_LEN(v)-1) rb_str_cat2(str, ":");
}
} else {
str = v;
@@ -479,13 +670,173 @@ ossl_sslctx_set_ciphers(VALUE self, VALUE v)
ossl_raise(eSSLError, "SSL_CTX is not initialized.");
return Qnil;
}
- if (!SSL_CTX_set_cipher_list(ctx, RSTRING(str)->ptr)) {
+ if (!SSL_CTX_set_cipher_list(ctx, RSTRING_PTR(str))) {
ossl_raise(eSSLError, "SSL_CTX_set_cipher_list:");
}
return v;
}
+
+/*
+ * call-seq:
+ * ctx.session_add(session) -> true | false
+ *
+ */
+static VALUE
+ossl_sslctx_session_add(VALUE self, VALUE arg)
+{
+ SSL_CTX *ctx;
+ SSL_SESSION *sess;
+
+ Data_Get_Struct(self, SSL_CTX, ctx);
+ SafeGetSSLSession(arg, sess);
+
+ return SSL_CTX_add_session(ctx, sess) == 1 ? Qtrue : Qfalse;
+}
+
+/*
+ * call-seq:
+ * ctx.session_remove(session) -> true | false
+ *
+ */
+static VALUE
+ossl_sslctx_session_remove(VALUE self, VALUE arg)
+{
+ SSL_CTX *ctx;
+ SSL_SESSION *sess;
+
+ Data_Get_Struct(self, SSL_CTX, ctx);
+ SafeGetSSLSession(arg, sess);
+
+ return SSL_CTX_remove_session(ctx, sess) == 1 ? Qtrue : Qfalse;
+}
+
+/*
+ * call-seq:
+ * ctx.session_cache_mode -> integer
+ *
+ */
+static VALUE
+ossl_sslctx_get_session_cache_mode(VALUE self)
+{
+ SSL_CTX *ctx;
+
+ Data_Get_Struct(self, SSL_CTX, ctx);
+
+ return LONG2NUM(SSL_CTX_get_session_cache_mode(ctx));
+}
+
+/*
+ * call-seq:
+ * ctx.session_cache_mode=(integer) -> integer
+ *
+ */
+static VALUE
+ossl_sslctx_set_session_cache_mode(VALUE self, VALUE arg)
+{
+ SSL_CTX *ctx;
+
+ Data_Get_Struct(self, SSL_CTX, ctx);
+
+ SSL_CTX_set_session_cache_mode(ctx, NUM2LONG(arg));
+
+ return arg;
+}
+
+/*
+ * call-seq:
+ * ctx.session_cache_size -> integer
+ *
+ */
+static VALUE
+ossl_sslctx_get_session_cache_size(VALUE self)
+{
+ SSL_CTX *ctx;
+
+ Data_Get_Struct(self, SSL_CTX, ctx);
+
+ return LONG2NUM(SSL_CTX_sess_get_cache_size(ctx));
+}
+
+/*
+ * call-seq:
+ * ctx.session_cache_size=(integer) -> integer
+ *
+ */
+static VALUE
+ossl_sslctx_set_session_cache_size(VALUE self, VALUE arg)
+{
+ SSL_CTX *ctx;
+
+ Data_Get_Struct(self, SSL_CTX, ctx);
+
+ SSL_CTX_sess_set_cache_size(ctx, NUM2LONG(arg));
+
+ return arg;
+}
+
+/*
+ * call-seq:
+ * ctx.session_cache_stats -> Hash
+ *
+ */
+static VALUE
+ossl_sslctx_get_session_cache_stats(VALUE self)
+{
+ SSL_CTX *ctx;
+ VALUE hash;
+
+ Data_Get_Struct(self, SSL_CTX, ctx);
+
+ hash = rb_hash_new();
+ rb_hash_aset(hash, ID2SYM(rb_intern("cache_num")), LONG2NUM(SSL_CTX_sess_number(ctx)));
+ rb_hash_aset(hash, ID2SYM(rb_intern("connect")), LONG2NUM(SSL_CTX_sess_connect(ctx)));
+ rb_hash_aset(hash, ID2SYM(rb_intern("connect_good")), LONG2NUM(SSL_CTX_sess_connect_good(ctx)));
+ rb_hash_aset(hash, ID2SYM(rb_intern("connect_renegotiate")), LONG2NUM(SSL_CTX_sess_connect_renegotiate(ctx)));
+ rb_hash_aset(hash, ID2SYM(rb_intern("accept")), LONG2NUM(SSL_CTX_sess_accept(ctx)));
+ rb_hash_aset(hash, ID2SYM(rb_intern("accept_good")), LONG2NUM(SSL_CTX_sess_accept_good(ctx)));
+ rb_hash_aset(hash, ID2SYM(rb_intern("accept_renegotiate")), LONG2NUM(SSL_CTX_sess_accept_renegotiate(ctx)));
+ rb_hash_aset(hash, ID2SYM(rb_intern("cache_hits")), LONG2NUM(SSL_CTX_sess_hits(ctx)));
+ rb_hash_aset(hash, ID2SYM(rb_intern("cb_hits")), LONG2NUM(SSL_CTX_sess_cb_hits(ctx)));
+ rb_hash_aset(hash, ID2SYM(rb_intern("cache_misses")), LONG2NUM(SSL_CTX_sess_misses(ctx)));
+ rb_hash_aset(hash, ID2SYM(rb_intern("cache_full")), LONG2NUM(SSL_CTX_sess_cache_full(ctx)));
+ rb_hash_aset(hash, ID2SYM(rb_intern("timeouts")), LONG2NUM(SSL_CTX_sess_timeouts(ctx)));
+
+ return hash;
+}
+
+
+/*
+ * call-seq:
+ * ctx.flush_sessions(time | nil) -> self
+ *
+ */
+static VALUE
+ossl_sslctx_flush_sessions(int argc, VALUE *argv, VALUE self)
+{
+ VALUE arg1;
+ SSL_CTX *ctx;
+ time_t tm = 0;
+ int cb_state;
+
+ rb_scan_args(argc, argv, "01", &arg1);
+
+ Data_Get_Struct(self, SSL_CTX, ctx);
+
+ if (NIL_P(arg1)) {
+ tm = time(0);
+ } else if (rb_obj_is_instance_of(arg1, rb_cTime)) {
+ tm = NUM2LONG(rb_funcall(arg1, rb_intern("to_i"), 0));
+ } else {
+ rb_raise(rb_eArgError, "arg must be Time or nil");
+ }
+
+ SSL_CTX_flush_sessions(ctx, (long)tm);
+
+ return self;
+}
+
/*
* SSLSocket class
*/
@@ -511,6 +862,20 @@ ossl_ssl_s_alloc(VALUE klass)
return Data_Wrap_Struct(klass, 0, ossl_ssl_free, NULL);
}
+/*
+ * call-seq:
+ * SSLSocket.new(io) => aSSLSocket
+ * SSLSocket.new(io, ctx) => aSSLSocket
+ *
+ * === Parameters
+ * * +io+ is a real ruby IO object. Not an IO like object that responds to read/write.
+ * * +ctx+ is an OpenSSLSSL::SSLContext.
+ *
+ * The OpenSSL::Buffering module provides additional IO methods.
+ *
+ * This method will freeze the SSLContext if one is provided;
+ * however, session management is still allowed in the frozen SSLContext.
+ */
static VALUE
ossl_ssl_initialize(int argc, VALUE *argv, VALUE self)
{
@@ -536,7 +901,7 @@ ossl_ssl_setup(VALUE self)
VALUE io, v_ctx, cb;
SSL_CTX *ctx;
SSL *ssl;
- OpenFile *fptr;
+ rb_io_t *fptr;
Data_Get_Struct(self, SSL, ssl);
if(!ssl){
@@ -553,7 +918,7 @@ ossl_ssl_setup(VALUE self)
GetOpenFile(io, fptr);
rb_io_check_readable(fptr);
rb_io_check_writable(fptr);
- SSL_set_fd(ssl, TO_SOCKET(fileno(fptr->f)));
+ SSL_set_fd(ssl, TO_SOCKET(FPTR_TO_FD(fptr)));
SSL_set_ex_data(ssl, ossl_ssl_ex_ptr_idx, (void*)self);
cb = ossl_sslctx_get_verify_cb(v_ctx);
SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void*)cb);
@@ -567,61 +932,85 @@ ossl_ssl_setup(VALUE self)
}
#ifdef _WIN32
-#define ssl_get_error(ssl, ret) \
- (errno = WSAGetLastError(), SSL_get_error(ssl, ret))
+#define ssl_get_error(ssl, ret) (errno = WSAGetLastError(), SSL_get_error(ssl, ret))
#else
#define ssl_get_error(ssl, ret) SSL_get_error(ssl, ret)
#endif
static VALUE
-ossl_start_ssl(VALUE self, int (*func)())
+ossl_start_ssl(VALUE self, int (*func)(), const char *funcname)
{
SSL *ssl;
- OpenFile *fptr;
- int ret;
+ rb_io_t *fptr;
+ int ret, ret2;
+ VALUE cb_state;
+
+ rb_ivar_set(self, ID_callback_state, Qnil);
Data_Get_Struct(self, SSL, ssl);
GetOpenFile(ossl_ssl_get_io(self), fptr);
for(;;){
if((ret = func(ssl)) > 0) break;
- switch(ssl_get_error(ssl, ret)){
+ switch((ret2 = ssl_get_error(ssl, ret))){
case SSL_ERROR_WANT_WRITE:
- rb_io_wait_writable(fileno(fptr->f));
+ rb_io_wait_writable(FPTR_TO_FD(fptr));
continue;
case SSL_ERROR_WANT_READ:
- rb_io_wait_readable(fileno(fptr->f));
+ rb_io_wait_readable(FPTR_TO_FD(fptr));
continue;
case SSL_ERROR_SYSCALL:
- if (errno) rb_sys_fail(0);
+ if (errno) rb_sys_fail(funcname);
+ ossl_raise(eSSLError, "%s SYSCALL returned=%d errno=%d state=%s", funcname, ret2, errno, SSL_state_string_long(ssl));
default:
- ossl_raise(eSSLError, NULL);
+ ossl_raise(eSSLError, "%s returned=%d errno=%d state=%s", funcname, ret2, errno, SSL_state_string_long(ssl));
}
}
+ cb_state = rb_ivar_get(self, ID_callback_state);
+ if (!NIL_P(cb_state))
+ rb_jump_tag(NUM2INT(cb_state));
+
return self;
}
+/*
+ * call-seq:
+ * ssl.connect => self
+ */
static VALUE
ossl_ssl_connect(VALUE self)
{
ossl_ssl_setup(self);
- return ossl_start_ssl(self, SSL_connect);
+ return ossl_start_ssl(self, SSL_connect, "SSL_connect");
}
+/*
+ * call-seq:
+ * ssl.accept => self
+ */
static VALUE
ossl_ssl_accept(VALUE self)
{
ossl_ssl_setup(self);
- return ossl_start_ssl(self, SSL_accept);
+ return ossl_start_ssl(self, SSL_accept, "SSL_accept");
}
+/*
+ * call-seq:
+ * ssl.sysread(length) => string
+ * ssl.sysread(length, buffer) => buffer
+ *
+ * === Parameters
+ * * +length+ is a positive integer.
+ * * +buffer+ is a string used to store the result.
+ */
static VALUE
ossl_ssl_read(int argc, VALUE *argv, VALUE self)
{
SSL *ssl;
int ilen, nread = 0;
VALUE len, str;
- OpenFile *fptr;
+ rb_io_t *fptr;
rb_scan_args(argc, argv, "11", &len, &str);
ilen = NUM2INT(len);
@@ -637,19 +1026,19 @@ ossl_ssl_read(int argc, VALUE *argv, VALUE self)
GetOpenFile(ossl_ssl_get_io(self), fptr);
if (ssl) {
if(SSL_pending(ssl) <= 0)
- rb_thread_wait_fd(fileno(fptr->f));
+ rb_thread_wait_fd(FPTR_TO_FD(fptr));
for (;;){
- nread = SSL_read(ssl, RSTRING(str)->ptr, RSTRING(str)->len);
+ nread = SSL_read(ssl, RSTRING_PTR(str), RSTRING_LEN(str));
switch(ssl_get_error(ssl, nread)){
case SSL_ERROR_NONE:
goto end;
case SSL_ERROR_ZERO_RETURN:
rb_eof_error();
case SSL_ERROR_WANT_WRITE:
- rb_io_wait_writable(fileno(fptr->f));
+ rb_io_wait_writable(FPTR_TO_FD(fptr));
continue;
case SSL_ERROR_WANT_READ:
- rb_io_wait_readable(fileno(fptr->f));
+ rb_io_wait_readable(FPTR_TO_FD(fptr));
continue;
case SSL_ERROR_SYSCALL:
if(ERR_peek_error() == 0 && nread == 0) rb_eof_error();
@@ -666,19 +1055,22 @@ ossl_ssl_read(int argc, VALUE *argv, VALUE self)
}
end:
- RSTRING(str)->len = nread;
- RSTRING(str)->ptr[nread] = 0;
+ rb_str_set_len(str, nread);
OBJ_TAINT(str);
return str;
}
+/*
+ * call-seq:
+ * ssl.syswrite(string) => integer
+ */
static VALUE
ossl_ssl_write(VALUE self, VALUE str)
{
SSL *ssl;
int nwrite = 0;
- OpenFile *fptr;
+ rb_io_t *fptr;
StringValue(str);
Data_Get_Struct(self, SSL, ssl);
@@ -686,15 +1078,15 @@ ossl_ssl_write(VALUE self, VALUE str)
if (ssl) {
for (;;){
- nwrite = SSL_write(ssl, RSTRING(str)->ptr, RSTRING(str)->len);
+ nwrite = SSL_write(ssl, RSTRING_PTR(str), RSTRING_LEN(str));
switch(ssl_get_error(ssl, nwrite)){
case SSL_ERROR_NONE:
goto end;
case SSL_ERROR_WANT_WRITE:
- rb_io_wait_writable(fileno(fptr->f));
+ rb_io_wait_writable(FPTR_TO_FD(fptr));
continue;
case SSL_ERROR_WANT_READ:
- rb_io_wait_readable(fileno(fptr->f));
+ rb_io_wait_readable(FPTR_TO_FD(fptr));
continue;
case SSL_ERROR_SYSCALL:
if (errno) rb_sys_fail(0);
@@ -713,6 +1105,10 @@ ossl_ssl_write(VALUE self, VALUE str)
return INT2NUM(nwrite);
}
+/*
+ * call-seq:
+ * ssl.sysclose => nil
+ */
static VALUE
ossl_ssl_close(VALUE self)
{
@@ -726,6 +1122,10 @@ ossl_ssl_close(VALUE self)
return Qnil;
}
+/*
+ * call-seq:
+ * ssl.cert => cert or nil
+ */
static VALUE
ossl_ssl_get_cert(VALUE self)
{
@@ -750,6 +1150,10 @@ ossl_ssl_get_cert(VALUE self)
return ossl_x509_new(cert);
}
+/*
+ * call-seq:
+ * ssl.peer_cert => cert or nil
+ */
static VALUE
ossl_ssl_get_peer_cert(VALUE self)
{
@@ -775,6 +1179,10 @@ ossl_ssl_get_peer_cert(VALUE self)
return obj;
}
+/*
+ * call-seq:
+ * ssl.peer_cert_chain => [cert, ...] or nil
+ */
static VALUE
ossl_ssl_get_peer_cert_chain(VALUE self)
{
@@ -791,16 +1199,20 @@ ossl_ssl_get_peer_cert_chain(VALUE self)
}
chain = SSL_get_peer_cert_chain(ssl);
if(!chain) return Qnil;
- num = sk_num(chain);
+ num = sk_X509_num(chain);
ary = rb_ary_new2(num);
for (i = 0; i < num; i++){
- cert = (X509*)sk_value(chain, i);
+ cert = sk_X509_value(chain, i);
rb_ary_push(ary, ossl_x509_new(cert));
}
return ary;
}
+/*
+ * call-seq:
+ * ssl.cipher => [name, version, bits, alg_bits]
+ */
static VALUE
ossl_ssl_get_cipher(VALUE self)
{
@@ -817,6 +1229,10 @@ ossl_ssl_get_cipher(VALUE self)
return ossl_ssl_cipher_to_ary(cipher);
}
+/*
+ * call-seq:
+ * ssl.state => string
+ */
static VALUE
ossl_ssl_get_state(VALUE self)
{
@@ -836,6 +1252,10 @@ ossl_ssl_get_state(VALUE self)
return ret;
}
+/*
+ * call-seq:
+ * ssl.pending => integer
+ */
static VALUE
ossl_ssl_pending(VALUE self)
{
@@ -850,10 +1270,82 @@ ossl_ssl_pending(VALUE self)
return INT2NUM(SSL_pending(ssl));
}
+/*
+ * call-seq:
+ * ssl.session_reused? -> true | false
+ *
+ */
+static VALUE
+ossl_ssl_session_reused(VALUE self)
+{
+ SSL *ssl;
+
+ Data_Get_Struct(self, SSL, ssl);
+ if (!ssl) {
+ rb_warning("SSL session is not started yet.");
+ return Qnil;
+ }
+
+ switch(SSL_session_reused(ssl)) {
+ case 1: return Qtrue;
+ case 0: return Qfalse;
+ default: ossl_raise(eSSLError, "SSL_session_reused");
+ }
+}
+
+/*
+ * call-seq:
+ * ssl.session = session -> session
+ *
+ */
+static VALUE
+ossl_ssl_set_session(VALUE self, VALUE arg1)
+{
+ SSL *ssl;
+ SSL_SESSION *sess;
+
+/* why is ossl_ssl_setup delayed? */
+ ossl_ssl_setup(self);
+
+ Data_Get_Struct(self, SSL, ssl);
+ if (!ssl) {
+ rb_warning("SSL session is not started yet.");
+ return Qnil;
+ }
+
+ SafeGetSSLSession(arg1, sess);
+
+ if (SSL_set_session(ssl, sess) != 1)
+ ossl_raise(eSSLError, "SSL_set_session");
+
+ return arg1;
+}
+
+static VALUE
+ossl_ssl_get_verify_result(VALUE self)
+{
+ SSL *ssl;
+
+ Data_Get_Struct(self, SSL, ssl);
+ if (!ssl) {
+ rb_warning("SSL session is not started yet.");
+ return Qnil;
+ }
+
+ return INT2FIX(SSL_get_verify_result(ssl));
+}
+
void
Init_ossl_ssl()
{
int i;
+ VALUE ary;
+
+#if 0 /* let rdoc know about mOSSL */
+ mOSSL = rb_define_module("OpenSSL");
+#endif
+
+ ID_callback_state = rb_intern("@callback_state");
ossl_ssl_ex_vcb_idx = SSL_get_ex_new_index(0,"ossl_ssl_ex_vcb_idx",0,0,0);
ossl_ssl_ex_store_p = SSL_get_ex_new_index(0,"ossl_ssl_ex_store_p",0,0,0);
@@ -866,16 +1358,60 @@ Init_ossl_ssl()
mSSL = rb_define_module_under(mOSSL, "SSL");
eSSLError = rb_define_class_under(mSSL, "SSLError", eOSSLError);
- /* class SSLContext */
+ Init_ossl_ssl_session();
+
+ /* class SSLContext
+ *
+ * The following attributes are available but don't show up in rdoc.
+ * All attributes must be set before calling SSLSocket.new(io, ctx).
+ * * ssl_version, cert, key, client_ca, ca_file, ca_path, timeout,
+ * * verify_mode, verify_depth client_cert_cb, tmp_dh_callback,
+ * * session_id_context, session_add_cb, session_new_cb, session_remove_cb
+ */
cSSLContext = rb_define_class_under(mSSL, "SSLContext", rb_cObject);
rb_define_alloc_func(cSSLContext, ossl_sslctx_s_alloc);
for(i = 0; i < numberof(ossl_sslctx_attrs); i++)
rb_attr(cSSLContext, rb_intern(ossl_sslctx_attrs[i]), 1, 1, Qfalse);
+ rb_define_alias(cSSLContext, "ssl_timeout", "timeout");
rb_define_method(cSSLContext, "initialize", ossl_sslctx_initialize, -1);
+ rb_define_method(cSSLContext, "ssl_version=", ossl_sslctx_set_ssl_version, 1);
rb_define_method(cSSLContext, "ciphers", ossl_sslctx_get_ciphers, 0);
rb_define_method(cSSLContext, "ciphers=", ossl_sslctx_set_ciphers, 1);
- /* class SSLSocket */
+ rb_define_method(cSSLContext, "setup", ossl_sslctx_setup, 0);
+
+
+ rb_define_const(cSSLContext, "SESSION_CACHE_OFF", LONG2FIX(SSL_SESS_CACHE_OFF));
+ rb_define_const(cSSLContext, "SESSION_CACHE_CLIENT", LONG2FIX(SSL_SESS_CACHE_CLIENT)); /* doesn't actually do anything in 0.9.8e */
+ rb_define_const(cSSLContext, "SESSION_CACHE_SERVER", LONG2FIX(SSL_SESS_CACHE_SERVER));
+ rb_define_const(cSSLContext, "SESSION_CACHE_BOTH", LONG2FIX(SSL_SESS_CACHE_BOTH)); /* no different than CACHE_SERVER in 0.9.8e */
+ rb_define_const(cSSLContext, "SESSION_CACHE_NO_AUTO_CLEAR", LONG2FIX(SSL_SESS_CACHE_NO_AUTO_CLEAR));
+ rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL_LOOKUP", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL_LOOKUP));
+ rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL_STORE", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL_STORE));
+ rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL));
+ rb_define_method(cSSLContext, "session_add", ossl_sslctx_session_add, 1);
+ rb_define_method(cSSLContext, "session_remove", ossl_sslctx_session_remove, 1);
+ rb_define_method(cSSLContext, "session_cache_mode", ossl_sslctx_get_session_cache_mode, 0);
+ rb_define_method(cSSLContext, "session_cache_mode=", ossl_sslctx_set_session_cache_mode, 1);
+ rb_define_method(cSSLContext, "session_cache_size", ossl_sslctx_get_session_cache_size, 0);
+ rb_define_method(cSSLContext, "session_cache_size=", ossl_sslctx_set_session_cache_size, 1);
+ rb_define_method(cSSLContext, "session_cache_stats", ossl_sslctx_get_session_cache_stats, 0);
+ rb_define_method(cSSLContext, "flush_sessions", ossl_sslctx_flush_sessions, -1);
+
+ ary = rb_ary_new2(numberof(ossl_ssl_method_tab));
+ for (i = 0; i < numberof(ossl_ssl_method_tab); i++) {
+ rb_ary_push(ary, ID2SYM(rb_intern(ossl_ssl_method_tab[i].name)));
+ }
+ rb_obj_freeze(ary);
+ /* holds a list of available SSL/TLS methods */
+ rb_define_const(cSSLContext, "METHODS", ary);
+
+ /* class SSLSocket
+ *
+ * The following attributes are available but don't show up in rdoc.
+ * * io, context, sync_close
+ *
+ */
cSSLSocket = rb_define_class_under(mSSL, "SSLSocket", rb_cObject);
rb_define_alloc_func(cSSLSocket, ossl_ssl_s_alloc);
for(i = 0; i < numberof(ossl_ssl_attr_readers); i++)
@@ -895,6 +1431,9 @@ Init_ossl_ssl()
rb_define_method(cSSLSocket, "cipher", ossl_ssl_get_cipher, 0);
rb_define_method(cSSLSocket, "state", ossl_ssl_get_state, 0);
rb_define_method(cSSLSocket, "pending", ossl_ssl_pending, 0);
+ rb_define_method(cSSLSocket, "session_reused?", ossl_ssl_session_reused, 0);
+ rb_define_method(cSSLSocket, "session=", ossl_ssl_set_session, 1);
+ rb_define_method(cSSLSocket, "verify_result", ossl_ssl_get_verify_result, 0);
#define ossl_ssl_def_const(x) rb_define_const(mSSL, #x, INT2FIX(SSL_##x))
@@ -930,6 +1469,9 @@ Init_ossl_ssl()
ossl_ssl_def_const(OP_NO_SSLv2);
ossl_ssl_def_const(OP_NO_SSLv3);
ossl_ssl_def_const(OP_NO_TLSv1);
+#if defined(SSL_OP_NO_TICKET)
+ ossl_ssl_def_const(OP_NO_TICKET);
+#endif
ossl_ssl_def_const(OP_PKCS1_CHECK_1);
ossl_ssl_def_const(OP_PKCS1_CHECK_2);
ossl_ssl_def_const(OP_NETSCAPE_CA_DN_BUG);
diff --git a/ext/openssl/ossl_ssl.h b/ext/openssl/ossl_ssl.h
index ba9ddb1985..487f41216c 100644
--- a/ext/openssl/ossl_ssl.h
+++ b/ext/openssl/ossl_ssl.h
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_ssl.h,v 1.1 2003/07/23 16:11:29 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -11,11 +11,26 @@
#if !defined(_OSSL_SSL_H_)
#define _OSSL_SSL_H_
+#define GetSSLSession(obj, sess) do { \
+ Data_Get_Struct(obj, SSL_SESSION, sess); \
+ if (!sess) { \
+ ossl_raise(rb_eRuntimeError, "SSL Session wasn't initialized."); \
+ } \
+} while (0)
+
+#define SafeGetSSLSession(obj, sess) do { \
+ OSSL_Check_Kind(obj, cSSLSession); \
+ GetSSLSession(obj, sess); \
+} while (0)
+
extern VALUE mSSL;
extern VALUE eSSLError;
extern VALUE cSSLSocket;
extern VALUE cSSLContext;
+extern VALUE cSSLSession;
void Init_ossl_ssl(void);
+void Init_ossl_ssl_session(void);
#endif /* _OSSL_SSL_H_ */
+
diff --git a/ext/openssl/ossl_ssl_session.c b/ext/openssl/ossl_ssl_session.c
new file mode 100644
index 0000000000..b416e76920
--- /dev/null
+++ b/ext/openssl/ossl_ssl_session.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2004-2007 Technorama Ltd. <oss-ruby@technorama.net>
+ */
+
+#include "ossl.h"
+
+#define GetSSLSession(obj, sess) do { \
+ Data_Get_Struct(obj, SSL_SESSION, sess); \
+ if (!sess) { \
+ ossl_raise(rb_eRuntimeError, "SSL Session wasn't initialized."); \
+ } \
+} while (0)
+
+#define SafeGetSSLSession(obj, sess) do { \
+ OSSL_Check_Kind(obj, cSSLSession); \
+ GetSSLSession(obj, sess); \
+} while (0)
+
+
+VALUE cSSLSession;
+static VALUE eSSLSession;
+
+static VALUE ossl_ssl_session_alloc(VALUE klass)
+{
+ return Data_Wrap_Struct(klass, 0, SSL_SESSION_free, NULL);
+}
+
+/*
+ * call-seq:
+ * Session.new(SSLSocket | string) => session
+ *
+ * === Parameters
+ * +SSLSocket+ is an OpenSSL::SSL::SSLSocket
+ * +string+ must be a DER or PEM encoded Session.
+*/
+static VALUE ossl_ssl_session_initialize(VALUE self, VALUE arg1)
+{
+ SSL_SESSION *ctx = NULL;
+ VALUE obj;
+ unsigned char *p;
+
+ if (RDATA(self)->data)
+ ossl_raise(eSSLSession, "SSL Session already initialized");
+
+ if (rb_obj_is_instance_of(arg1, cSSLSocket)) {
+ SSL *ssl;
+
+ Data_Get_Struct(arg1, SSL, ssl);
+
+ if (!ssl || (ctx = SSL_get1_session(ssl)) == NULL)
+ ossl_raise(eSSLSession, "no session available");
+ } else {
+ BIO *in = ossl_obj2bio(arg1);
+
+ ctx = PEM_read_bio_SSL_SESSION(in, NULL, NULL, NULL);
+
+ if (!ctx) {
+ BIO_reset(in);
+ ctx = d2i_SSL_SESSION_bio(in, NULL);
+ }
+
+ BIO_free(in);
+
+ if (!ctx)
+ ossl_raise(rb_eArgError, "unknown type");
+ }
+
+ /* should not happen */
+ if (ctx == NULL)
+ ossl_raise(eSSLSession, "ctx not set - internal error");
+
+ RDATA(self)->data = ctx;
+
+ return self;
+}
+
+/*
+ * call-seq:
+ * session1 == session2 -> boolean
+ *
+*/
+static VALUE ossl_ssl_session_eq(VALUE val1, VALUE val2)
+{
+ SSL_SESSION *ctx1, *ctx2;
+
+ GetSSLSession(val1, ctx1);
+ SafeGetSSLSession(val2, ctx2);
+
+ /*
+ * OpenSSL 1.0.0betas do not have non-static SSL_SESSION_cmp.
+ * ssl_session_cmp (was SSL_SESSION_cmp in 0.9.8) is for lhash
+ * comparing so we should not depend on it. Just compare sessions
+ * by version and id.
+ */
+ if ((ctx1->ssl_version == ctx2->ssl_version) &&
+ (ctx1->session_id_length == ctx2->session_id_length) &&
+ (memcmp(ctx1->session_id, ctx2->session_id, ctx1->session_id_length) == 0)) {
+ return Qtrue;
+ } else {
+ return Qfalse;
+ }
+}
+
+/*
+ * call-seq:
+ * session.time -> Time
+ *
+*/
+static VALUE ossl_ssl_session_get_time(VALUE self)
+{
+ SSL_SESSION *ctx;
+ long t;
+
+ GetSSLSession(self, ctx);
+
+ t = SSL_SESSION_get_time(ctx);
+
+ if (t == 0)
+ return Qnil;
+
+ return rb_funcall(rb_cTime, rb_intern("at"), 1, LONG2NUM(t));
+}
+
+/*
+ * call-seq:
+ * session.timeout -> integer
+ *
+ * How long until the session expires in seconds.
+ *
+*/
+static VALUE ossl_ssl_session_get_timeout(VALUE self)
+{
+ SSL_SESSION *ctx;
+ long t;
+
+ GetSSLSession(self, ctx);
+
+ t = SSL_SESSION_get_timeout(ctx);
+
+ return LONG2NUM(t);
+}
+
+#define SSLSESSION_SET_TIME(func) \
+ static VALUE ossl_ssl_session_set_##func(VALUE self, VALUE time_v) \
+ { \
+ SSL_SESSION *ctx; \
+ long t; \
+ \
+ GetSSLSession(self, ctx); \
+ \
+ if (rb_obj_is_instance_of(time_v, rb_cTime)) { \
+ time_v = rb_funcall(time_v, rb_intern("to_i"), 0); \
+ } else if (FIXNUM_P(time_v)) { \
+ ; \
+ } else { \
+ rb_raise(rb_eArgError, "unknown type"); \
+ } \
+ \
+ t = NUM2LONG(time_v); \
+ \
+ SSL_SESSION_set_##func(ctx, t); \
+ \
+ return ossl_ssl_session_get_##func(self); \
+ }
+
+SSLSESSION_SET_TIME(time)
+SSLSESSION_SET_TIME(timeout)
+
+#ifdef HAVE_SSL_SESSION_GET_ID
+/*
+ * call-seq:
+ * session.id -> aString
+ *
+ * Returns the Session ID.
+*/
+static VALUE ossl_ssl_session_get_id(VALUE self)
+{
+ SSL_SESSION *ctx;
+ const unsigned char *p = NULL;
+ unsigned int i = 0;
+
+ GetSSLSession(self, ctx);
+
+ p = SSL_SESSION_get_id(ctx, &i);
+
+ return rb_str_new((const char *) p, i);
+}
+#endif
+
+/*
+ * call-seq:
+ * session.to_der -> aString
+ *
+ * Returns an ASN1 encoded String that contains the Session object.
+*/
+static VALUE ossl_ssl_session_to_der(VALUE self)
+{
+ SSL_SESSION *ctx;
+ unsigned char buf[1024*10], *p;
+ int len;
+
+ GetSSLSession(self, ctx);
+
+ p = buf;
+ len = i2d_SSL_SESSION(ctx, &p);
+
+ if (len <= 0)
+ ossl_raise(eSSLSession, "i2d_SSL_SESSION");
+ else if (len >= sizeof(buf))
+ ossl_raise(eSSLSession, "i2d_SSL_SESSION too large");
+
+ return rb_str_new((const char *) p, len);
+}
+
+/*
+ * call-seq:
+ * session.to_pem -> String
+ *
+ * Returns a PEM encoded String that contains the Session object.
+*/
+static VALUE ossl_ssl_session_to_pem(VALUE self)
+{
+ SSL_SESSION *ctx;
+ BIO *out;
+ BUF_MEM *buf;
+ VALUE str;
+ int i;
+
+ GetSSLSession(self, ctx);
+
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ ossl_raise(eSSLSession, "BIO_s_mem()");
+ }
+
+ if (!(i=PEM_write_bio_SSL_SESSION(out, ctx))) {
+ BIO_free(out);
+ ossl_raise(eSSLSession, "SSL_SESSION_print()");
+ }
+
+ BIO_get_mem_ptr(out, &buf);
+ str = rb_str_new(buf->data, buf->length);
+ BIO_free(out);
+
+ return str;
+}
+
+
+/*
+ * call-seq:
+ * session.to_text -> String
+ *
+ * Shows everything in the Session object.
+*/
+static VALUE ossl_ssl_session_to_text(VALUE self)
+{
+ SSL_SESSION *ctx;
+ BIO *out;
+ BUF_MEM *buf;
+ VALUE str;
+
+ GetSSLSession(self, ctx);
+
+ if (!(out = BIO_new(BIO_s_mem()))) {
+ ossl_raise(eSSLSession, "BIO_s_mem()");
+ }
+
+ if (!SSL_SESSION_print(out, ctx)) {
+ BIO_free(out);
+ ossl_raise(eSSLSession, "SSL_SESSION_print()");
+ }
+
+ BIO_get_mem_ptr(out, &buf);
+ str = rb_str_new(buf->data, buf->length);
+ BIO_free(out);
+
+ return str;
+}
+
+
+void Init_ossl_ssl_session(void)
+{
+#if 0 /* let rdoc know about mOSSL */
+ mOSSL = rb_define_module("OpenSSL");
+ mSSL = rb_define_module_under(mOSSL, "SSL");
+#endif
+ cSSLSession = rb_define_class_under(mSSL, "Session", rb_cObject);
+ eSSLSession = rb_define_class_under(cSSLSession, "SessionError", eOSSLError);
+
+ rb_define_alloc_func(cSSLSession, ossl_ssl_session_alloc);
+ rb_define_method(cSSLSession, "initialize", ossl_ssl_session_initialize, 1);
+
+ rb_define_method(cSSLSession, "==", ossl_ssl_session_eq, 1);
+
+ rb_define_method(cSSLSession, "time", ossl_ssl_session_get_time, 0);
+ rb_define_method(cSSLSession, "time=", ossl_ssl_session_set_time, 1);
+ rb_define_method(cSSLSession, "timeout", ossl_ssl_session_get_timeout, 0);
+ rb_define_method(cSSLSession, "timeout=", ossl_ssl_session_set_timeout, 1);
+
+#ifdef HAVE_SSL_SESSION_GET_ID
+ rb_define_method(cSSLSession, "id", ossl_ssl_session_get_id, 0);
+#else
+ rb_undef_method(cSSLSession, "id");
+#endif
+ rb_define_method(cSSLSession, "to_der", ossl_ssl_session_to_der, 0);
+ rb_define_method(cSSLSession, "to_pem", ossl_ssl_session_to_pem, 0);
+ rb_define_method(cSSLSession, "to_text", ossl_ssl_session_to_text, 0);
+}
diff --git a/ext/openssl/ossl_version.h b/ext/openssl/ossl_version.h
index 6d43cdccbf..63878e0d8e 100644
--- a/ext/openssl/ossl_version.h
+++ b/ext/openssl/ossl_version.h
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_version.h,v 1.1 2003/07/23 16:11:29 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
diff --git a/ext/openssl/ossl_x509.c b/ext/openssl/ossl_x509.c
index fa90e92d11..fd1d9b6c7e 100644
--- a/ext/openssl/ossl_x509.c
+++ b/ext/openssl/ossl_x509.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_x509.c,v 1.2 2003/09/08 10:31:38 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
diff --git a/ext/openssl/ossl_x509.h b/ext/openssl/ossl_x509.h
index 8d1f77b302..1a43569073 100644
--- a/ext/openssl/ossl_x509.h
+++ b/ext/openssl/ossl_x509.h
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_x509.h,v 1.2 2003/11/01 09:24:55 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
diff --git a/ext/openssl/ossl_x509attr.c b/ext/openssl/ossl_x509attr.c
index 91a0795209..949785a80b 100644
--- a/ext/openssl/ossl_x509attr.c
+++ b/ext/openssl/ossl_x509attr.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_x509attr.c,v 1.4.2.2 2004/12/15 01:54:38 matz Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -84,6 +84,10 @@ ossl_x509attr_alloc(VALUE klass)
return obj;
}
+/*
+ * call-seq:
+ * Attribute.new(oid [, value]) => attr
+ */
static VALUE
ossl_x509attr_initialize(int argc, VALUE *argv, VALUE self)
{
@@ -95,9 +99,9 @@ ossl_x509attr_initialize(int argc, VALUE *argv, VALUE self)
if(rb_scan_args(argc, argv, "11", &oid, &value) == 1){
oid = ossl_to_der_if_possible(oid);
StringValue(oid);
- p = RSTRING(oid)->ptr;
+ p = RSTRING_PTR(oid);
if(!d2i_X509_ATTRIBUTE((X509_ATTRIBUTE**)&DATA_PTR(self),
- &p, RSTRING(oid)->len)){
+ &p, RSTRING_LEN(oid))){
ossl_raise(eX509AttrError, NULL);
}
return self;
@@ -108,6 +112,10 @@ ossl_x509attr_initialize(int argc, VALUE *argv, VALUE self)
return self;
}
+/*
+ * call-seq:
+ * attr.oid = string => string
+ */
static VALUE
ossl_x509attr_set_oid(VALUE self, VALUE oid)
{
@@ -125,6 +133,10 @@ ossl_x509attr_set_oid(VALUE self, VALUE oid)
return oid;
}
+/*
+ * call-seq:
+ * attr.oid => string
+ */
static VALUE
ossl_x509attr_get_oid(VALUE self)
{
@@ -156,6 +168,10 @@ ossl_x509attr_get_oid(VALUE self)
# define OSSL_X509ATTR_SET_SINGLE(attr) ((attr)->set = 0)
#endif
+/*
+ * call-seq:
+ * attr.value = asn1 => asn1
+ */
static VALUE
ossl_x509attr_set_value(VALUE self, VALUE value)
{
@@ -179,6 +195,10 @@ ossl_x509attr_set_value(VALUE self, VALUE value)
return value;
}
+/*
+ * call-seq:
+ * attr.value => asn1
+ */
static VALUE
ossl_x509attr_get_value(VALUE self)
{
@@ -192,15 +212,16 @@ ossl_x509attr_get_value(VALUE self)
if(OSSL_X509ATTR_IS_SINGLE(attr)){
length = i2d_ASN1_TYPE(attr->value.single, NULL);
str = rb_str_new(0, length);
- p = RSTRING(str)->ptr;
+ p = RSTRING_PTR(str);
i2d_ASN1_TYPE(attr->value.single, &p);
ossl_str_adjust(str, p);
}
else{
- length = i2d_ASN1_SET_OF_ASN1_TYPE(attr->value.set, NULL,
- i2d_ASN1_TYPE, V_ASN1_SET, V_ASN1_UNIVERSAL, 0);
+ length = i2d_ASN1_SET_OF_ASN1_TYPE(attr->value.set,
+ (unsigned char **) NULL, i2d_ASN1_TYPE,
+ V_ASN1_SET, V_ASN1_UNIVERSAL, 0);
str = rb_str_new(0, length);
- p = RSTRING(str)->ptr;
+ p = RSTRING_PTR(str);
i2d_ASN1_SET_OF_ASN1_TYPE(attr->value.set, &p,
i2d_ASN1_TYPE, V_ASN1_SET, V_ASN1_UNIVERSAL, 0);
ossl_str_adjust(str, p);
@@ -210,6 +231,10 @@ ossl_x509attr_get_value(VALUE self)
return asn1;
}
+/*
+ * call-seq:
+ * attr.to_der => string
+ */
static VALUE
ossl_x509attr_to_der(VALUE self)
{
@@ -222,10 +247,10 @@ ossl_x509attr_to_der(VALUE self)
if((len = i2d_X509_ATTRIBUTE(attr, NULL)) <= 0)
ossl_raise(eX509AttrError, NULL);
str = rb_str_new(0, len);
- p = RSTRING(str)->ptr;
+ p = RSTRING_PTR(str);
if(i2d_X509_ATTRIBUTE(attr, &p) <= 0)
ossl_raise(eX509AttrError, NULL);
- RSTRING(str)->len = p - (unsigned char*)RSTRING(str)->ptr;
+ rb_str_set_len(str, p - (unsigned char*)RSTRING_PTR(str));
return str;
}
diff --git a/ext/openssl/ossl_x509cert.c b/ext/openssl/ossl_x509cert.c
index 3ac9c894da..b97f27ffa9 100644
--- a/ext/openssl/ossl_x509cert.c
+++ b/ext/openssl/ossl_x509cert.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_x509cert.c,v 1.3.2.1 2004/12/15 01:54:38 matz Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -63,7 +63,7 @@ ossl_x509_new_from_file(VALUE filename)
VALUE obj;
SafeStringValue(filename);
- if (!(fp = fopen(RSTRING(filename)->ptr, "r"))) {
+ if (!(fp = fopen(RSTRING_PTR(filename), "r"))) {
ossl_raise(eX509CertError, "%s", strerror(errno));
}
x509 = PEM_read_X509(fp, NULL, NULL, NULL);
@@ -125,6 +125,11 @@ ossl_x509_alloc(VALUE klass)
return obj;
}
+/*
+ * call-seq:
+ * Certificate.new => cert
+ * Certificate.new(string) => cert
+ */
static VALUE
ossl_x509_initialize(int argc, VALUE *argv, VALUE self)
{
@@ -169,6 +174,10 @@ ossl_x509_copy(VALUE self, VALUE other)
return self;
}
+/*
+ * call-seq:
+ * cert.to_der => string
+ */
static VALUE
ossl_x509_to_der(VALUE self)
{
@@ -181,7 +190,7 @@ ossl_x509_to_der(VALUE self)
if ((len = i2d_X509(x509, NULL)) <= 0)
ossl_raise(eX509CertError, NULL);
str = rb_str_new(0, len);
- p = RSTRING(str)->ptr;
+ p = RSTRING_PTR(str);
if (i2d_X509(x509, &p) <= 0)
ossl_raise(eX509CertError, NULL);
ossl_str_adjust(str, p);
@@ -189,6 +198,10 @@ ossl_x509_to_der(VALUE self)
return str;
}
+/*
+ * call-seq:
+ * cert.to_pem => string
+ */
static VALUE
ossl_x509_to_pem(VALUE self)
{
@@ -209,6 +222,10 @@ ossl_x509_to_pem(VALUE self)
return str;
}
+/*
+ * call-seq:
+ * cert.to_text => string
+ */
static VALUE
ossl_x509_to_text(VALUE self)
{
@@ -252,6 +269,10 @@ ossl_x509_to_req(VALUE self)
}
#endif
+/*
+ * call-seq:
+ * cert.version => integer
+ */
static VALUE
ossl_x509_get_version(VALUE self)
{
@@ -262,6 +283,10 @@ ossl_x509_get_version(VALUE self)
return LONG2NUM(X509_get_version(x509));
}
+/*
+ * call-seq:
+ * cert.version = integer => integer
+ */
static VALUE
ossl_x509_set_version(VALUE self, VALUE version)
{
@@ -279,6 +304,10 @@ ossl_x509_set_version(VALUE self, VALUE version)
return version;
}
+/*
+ * call-seq:
+ * cert.serial => integer
+ */
static VALUE
ossl_x509_get_serial(VALUE self)
{
@@ -289,6 +318,10 @@ ossl_x509_get_serial(VALUE self)
return asn1integer_to_num(X509_get_serialNumber(x509));
}
+/*
+ * call-seq:
+ * cert.serial = integer => integer
+ */
static VALUE
ossl_x509_set_serial(VALUE self, VALUE num)
{
@@ -302,6 +335,10 @@ ossl_x509_set_serial(VALUE self, VALUE num)
return num;
}
+/*
+ * call-seq:
+ * cert.signature_algorithm => string
+ */
static VALUE
ossl_x509_get_signature_algorithm(VALUE self)
{
@@ -322,6 +359,10 @@ ossl_x509_get_signature_algorithm(VALUE self)
return str;
}
+/*
+ * call-seq:
+ * cert.subject => name
+ */
static VALUE
ossl_x509_get_subject(VALUE self)
{
@@ -336,6 +377,10 @@ ossl_x509_get_subject(VALUE self)
return ossl_x509name_new(name);
}
+/*
+ * call-seq:
+ * cert.subject = name => name
+ */
static VALUE
ossl_x509_set_subject(VALUE self, VALUE subject)
{
@@ -349,6 +394,10 @@ ossl_x509_set_subject(VALUE self, VALUE subject)
return subject;
}
+/*
+ * call-seq:
+ * cert.issuer => name
+ */
static VALUE
ossl_x509_get_issuer(VALUE self)
{
@@ -363,6 +412,10 @@ ossl_x509_get_issuer(VALUE self)
return ossl_x509name_new(name);
}
+/*
+ * call-seq:
+ * cert.issuer = name => name
+ */
static VALUE
ossl_x509_set_issuer(VALUE self, VALUE issuer)
{
@@ -376,6 +429,10 @@ ossl_x509_set_issuer(VALUE self, VALUE issuer)
return issuer;
}
+/*
+ * call-seq:
+ * cert.not_before => time
+ */
static VALUE
ossl_x509_get_not_before(VALUE self)
{
@@ -390,6 +447,10 @@ ossl_x509_get_not_before(VALUE self)
return asn1time_to_time(asn1time);
}
+/*
+ * call-seq:
+ * cert.not_before = time => time
+ */
static VALUE
ossl_x509_set_not_before(VALUE self, VALUE time)
{
@@ -405,6 +466,10 @@ ossl_x509_set_not_before(VALUE self, VALUE time)
return time;
}
+/*
+ * call-seq:
+ * cert.not_after => time
+ */
static VALUE
ossl_x509_get_not_after(VALUE self)
{
@@ -419,6 +484,10 @@ ossl_x509_get_not_after(VALUE self)
return asn1time_to_time(asn1time);
}
+/*
+ * call-seq:
+ * cert.not_before = time => time
+ */
static VALUE
ossl_x509_set_not_after(VALUE self, VALUE time)
{
@@ -434,6 +503,10 @@ ossl_x509_set_not_after(VALUE self, VALUE time)
return time;
}
+/*
+ * call-seq:
+ * cert.public_key => key
+ */
static VALUE
ossl_x509_get_public_key(VALUE self)
{
@@ -448,6 +521,10 @@ ossl_x509_get_public_key(VALUE self)
return ossl_pkey_new(pkey); /* NO DUP - OK */
}
+/*
+ * call-seq:
+ * cert.public_key = key => key
+ */
static VALUE
ossl_x509_set_public_key(VALUE self, VALUE key)
{
@@ -461,6 +538,10 @@ ossl_x509_set_public_key(VALUE self, VALUE key)
return key;
}
+/*
+ * call-seq:
+ * cert.sign(key, digest) => self
+ */
static VALUE
ossl_x509_sign(VALUE self, VALUE key, VALUE digest)
{
@@ -479,6 +560,9 @@ ossl_x509_sign(VALUE self, VALUE key, VALUE digest)
}
/*
+ * call-seq:
+ * cert.verify(key) => true | false
+ *
* Checks that cert signature is made with PRIVversion of this PUBLIC 'key'
*/
static VALUE
@@ -501,6 +585,9 @@ ossl_x509_verify(VALUE self, VALUE key)
}
/*
+ * call-seq:
+ * cert.check_private_key(key)
+ *
* Checks if 'key' is PRIV key for this cert
*/
static VALUE
@@ -521,7 +608,8 @@ ossl_x509_check_private_key(VALUE self, VALUE key)
}
/*
- * Gets X509v3 extensions as array of X509Ext objects
+ * call-seq:
+ * cert.extensions => [extension...]
*/
static VALUE
ossl_x509_get_extensions(VALUE self)
@@ -546,7 +634,8 @@ ossl_x509_get_extensions(VALUE self)
}
/*
- * Sets X509_EXTENSIONs
+ * call-seq:
+ * cert.extensions = [ext...] => [ext...]
*/
static VALUE
ossl_x509_set_extensions(VALUE self, VALUE ary)
@@ -557,14 +646,14 @@ ossl_x509_set_extensions(VALUE self, VALUE ary)
Check_Type(ary, T_ARRAY);
/* All ary's members should be X509Extension */
- for (i=0; i<RARRAY(ary)->len; i++) {
- OSSL_Check_Kind(RARRAY(ary)->ptr[i], cX509Ext);
+ for (i=0; i<RARRAY_LEN(ary); i++) {
+ OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Ext);
}
GetX509(self, x509);
sk_X509_EXTENSION_pop_free(x509->cert_info->extensions, X509_EXTENSION_free);
x509->cert_info->extensions = NULL;
- for (i=0; i<RARRAY(ary)->len; i++) {
- ext = DupX509ExtPtr(RARRAY(ary)->ptr[i]);
+ for (i=0; i<RARRAY_LEN(ary); i++) {
+ ext = DupX509ExtPtr(RARRAY_PTR(ary)[i]);
if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext - FREE it */
X509_EXTENSION_free(ext);
@@ -576,6 +665,10 @@ ossl_x509_set_extensions(VALUE self, VALUE ary)
return ary;
}
+/*
+ * call-seq:
+ * cert.add_extension(extension) => extension
+ */
static VALUE
ossl_x509_add_extension(VALUE self, VALUE extension)
{
diff --git a/ext/openssl/ossl_x509crl.c b/ext/openssl/ossl_x509crl.c
index 62d27fe7a4..e6d0c2eb3c 100644
--- a/ext/openssl/ossl_x509crl.c
+++ b/ext/openssl/ossl_x509crl.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_x509crl.c,v 1.3.2.1 2004/12/15 01:54:38 matz Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -262,7 +262,7 @@ ossl_x509crl_get_revoked(VALUE self)
VALUE ary, revoked;
GetX509CRL(self, crl);
- num = sk_X509_CRL_num(X509_CRL_get_REVOKED(crl));
+ num = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
if (num < 0) {
OSSL_Debug("num < 0???");
return rb_ary_new();
@@ -270,7 +270,7 @@ ossl_x509crl_get_revoked(VALUE self)
ary = rb_ary_new2(num);
for(i=0; i<num; i++) {
/* NO DUP - don't free! */
- rev = (X509_REVOKED *)sk_X509_CRL_value(X509_CRL_get_REVOKED(crl), i);
+ rev = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
revoked = ossl_x509revoked_new(rev);
rb_ary_push(ary, revoked);
}
@@ -287,14 +287,14 @@ ossl_x509crl_set_revoked(VALUE self, VALUE ary)
Check_Type(ary, T_ARRAY);
/* All ary members should be X509 Revoked */
- for (i=0; i<RARRAY(ary)->len; i++) {
- OSSL_Check_Kind(RARRAY(ary)->ptr[i], cX509Rev);
+ for (i=0; i<RARRAY_LEN(ary); i++) {
+ OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Rev);
}
GetX509CRL(self, crl);
sk_X509_REVOKED_pop_free(crl->crl->revoked, X509_REVOKED_free);
crl->crl->revoked = NULL;
- for (i=0; i<RARRAY(ary)->len; i++) {
- rev = DupX509RevokedPtr(RARRAY(ary)->ptr[i]);
+ for (i=0; i<RARRAY_LEN(ary); i++) {
+ rev = DupX509RevokedPtr(RARRAY_PTR(ary)[i]);
if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */
ossl_raise(eX509CRLError, NULL);
}
@@ -461,14 +461,14 @@ ossl_x509crl_set_extensions(VALUE self, VALUE ary)
Check_Type(ary, T_ARRAY);
/* All ary members should be X509 Extensions */
- for (i=0; i<RARRAY(ary)->len; i++) {
- OSSL_Check_Kind(RARRAY(ary)->ptr[i], cX509Ext);
+ for (i=0; i<RARRAY_LEN(ary); i++) {
+ OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Ext);
}
GetX509CRL(self, crl);
sk_X509_EXTENSION_pop_free(crl->crl->extensions, X509_EXTENSION_free);
crl->crl->extensions = NULL;
- for (i=0; i<RARRAY(ary)->len; i++) {
- ext = DupX509ExtPtr(RARRAY(ary)->ptr[i]);
+ for (i=0; i<RARRAY_LEN(ary); i++) {
+ ext = DupX509ExtPtr(RARRAY_PTR(ary)[i]);
if(!X509_CRL_add_ext(crl, ext, -1)) { /* DUPs ext - FREE it */
X509_EXTENSION_free(ext);
ossl_raise(eX509CRLError, NULL);
diff --git a/ext/openssl/ossl_x509ext.c b/ext/openssl/ossl_x509ext.c
index 219f30d7e3..591ae953bb 100644
--- a/ext/openssl/ossl_x509ext.c
+++ b/ext/openssl/ossl_x509ext.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_x509ext.c,v 1.8.2.3 2005/11/22 22:28:51 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -198,6 +198,7 @@ ossl_x509extfactory_initialize(int argc, VALUE *argv, VALUE self)
ossl_x509extfactory_set_subject_req(self, subject_req);
if (!NIL_P(crl))
ossl_x509extfactory_set_crl(self, crl);
+ rb_iv_set(self, "@config", Qnil);
return self;
}
@@ -229,23 +230,23 @@ ossl_x509extfactory_create_ext(int argc, VALUE *argv, VALUE self)
StringValue(value);
if(NIL_P(critical)) critical = Qfalse;
- nid = OBJ_ln2nid(RSTRING(oid)->ptr);
- if(!nid) nid = OBJ_sn2nid(RSTRING(oid)->ptr);
- if(!nid) ossl_raise(eX509ExtError, "unknown OID `%s'", RSTRING(oid)->ptr);
+ nid = OBJ_ln2nid(RSTRING_PTR(oid));
+ if(!nid) nid = OBJ_sn2nid(RSTRING_PTR(oid));
+ if(!nid) ossl_raise(eX509ExtError, "unknown OID `%s'", RSTRING_PTR(oid));
valstr = rb_str_new2(RTEST(critical) ? "critical," : "");
rb_str_append(valstr, value);
GetX509ExtFactory(self, ctx);
#ifdef HAVE_X509V3_EXT_NCONF_NID
rconf = rb_iv_get(self, "@config");
conf = NIL_P(rconf) ? NULL : GetConfigPtr(rconf);
- ext = X509V3_EXT_nconf_nid(conf, ctx, nid, RSTRING(valstr)->ptr);
+ ext = X509V3_EXT_nconf_nid(conf, ctx, nid, RSTRING_PTR(valstr));
#else
if (!empty_lhash) empty_lhash = lh_new(NULL, NULL);
- ext = X509V3_EXT_conf_nid(empty_lhash, ctx, nid, RSTRING(valstr)->ptr);
+ ext = X509V3_EXT_conf_nid(empty_lhash, ctx, nid, RSTRING_PTR(valstr));
#endif
if (!ext){
ossl_raise(eX509ExtError, "%s = %s",
- RSTRING(oid)->ptr, RSTRING(value)->ptr);
+ RSTRING_PTR(oid), RSTRING_PTR(value));
}
WrapX509Ext(cX509Ext, obj, ext);
@@ -280,9 +281,9 @@ ossl_x509ext_initialize(int argc, VALUE *argv, VALUE self)
if(rb_scan_args(argc, argv, "12", &oid, &value, &critical) == 1){
oid = ossl_to_der_if_possible(oid);
StringValue(oid);
- p = RSTRING(oid)->ptr;
+ p = RSTRING_PTR(oid);
if(!d2i_X509_EXTENSION((X509_EXTENSION**)&DATA_PTR(self),
- &p, RSTRING(oid)->len))
+ &p, RSTRING_LEN(oid)))
ossl_raise(eX509ExtError, NULL);
return self;
}
@@ -319,18 +320,19 @@ ossl_x509ext_set_value(VALUE self, VALUE data)
data = ossl_to_der_if_possible(data);
StringValue(data);
- if(!(s = OPENSSL_malloc(RSTRING(data)->len)))
+ if(!(s = OPENSSL_malloc(RSTRING_LEN(data))))
ossl_raise(eX509ExtError, "malloc error");
- memcpy(s, RSTRING(data)->ptr, RSTRING(data)->len);
+ memcpy(s, RSTRING_PTR(data), RSTRING_LEN(data));
if(!(asn1s = ASN1_OCTET_STRING_new())){
- free(s);
+ OPENSSL_free(s);
ossl_raise(eX509ExtError, NULL);
}
- if(!M_ASN1_OCTET_STRING_set(asn1s, s, RSTRING(data)->len)){
- free(s);
+ if(!M_ASN1_OCTET_STRING_set(asn1s, s, RSTRING_LEN(data))){
+ OPENSSL_free(s);
ASN1_OCTET_STRING_free(asn1s);
ossl_raise(eX509ExtError, NULL);
}
+ OPENSSL_free(s);
GetX509Ext(self, ext);
X509_EXTENSION_set_data(ext, asn1s);
@@ -409,7 +411,7 @@ ossl_x509ext_to_der(VALUE obj)
if((len = i2d_X509_EXTENSION(ext, NULL)) <= 0)
ossl_raise(eX509ExtError, NULL);
str = rb_str_new(0, len);
- p = RSTRING(str)->ptr;
+ p = RSTRING_PTR(str);
if(i2d_X509_EXTENSION(ext, &p) < 0)
ossl_raise(eX509ExtError, NULL);
ossl_str_adjust(str, p);
diff --git a/ext/openssl/ossl_x509name.c b/ext/openssl/ossl_x509name.c
index 1a456f2c48..55f5b58d64 100644
--- a/ext/openssl/ossl_x509name.c
+++ b/ext/openssl/ossl_x509name.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_x509name.c,v 1.4.2.8 2004/12/27 07:55:56 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -109,6 +109,13 @@ ossl_x509name_init_i(VALUE i, VALUE args)
return Qnil;
}
+/*
+ * call-seq:
+ * X509::Name.new => name
+ * X509::Name.new(string) => name
+ * X509::Name.new(dn) => name
+ * X509::Name.new(dn, template) => name
+ */
static VALUE
ossl_x509name_initialize(int argc, VALUE *argv, VALUE self)
{
@@ -125,14 +132,17 @@ ossl_x509name_initialize(int argc, VALUE *argv, VALUE self)
VALUE args;
if(NIL_P(template)) template = OBJECT_TYPE_TEMPLATE;
args = rb_ary_new3(2, self, template);
- rb_iterate(rb_each, tmp, ossl_x509name_init_i, args);
+ rb_block_call(tmp, rb_intern("each"), 0, 0, ossl_x509name_init_i, args);
}
else{
unsigned char *p;
VALUE str = ossl_to_der_if_possible(arg);
+ X509_NAME *x;
StringValue(str);
- p = RSTRING(str)->ptr;
- if(!d2i_X509_NAME((X509_NAME**)&DATA_PTR(self), &p, RSTRING(str)->len)){
+ p = (unsigned char *)RSTRING_PTR(str);
+ x = d2i_X509_NAME(&name, &p, RSTRING_LEN(str));
+ DATA_PTR(self) = name;
+ if(!x){
ossl_raise(eX509NameError, NULL);
}
}
@@ -141,6 +151,10 @@ ossl_x509name_initialize(int argc, VALUE *argv, VALUE self)
return self;
}
+/*
+ * call-seq:
+ * name.add_entry(oid, value [, type]) => self
+ */
static
VALUE ossl_x509name_add_entry(int argc, VALUE *argv, VALUE self)
{
@@ -152,8 +166,8 @@ VALUE ossl_x509name_add_entry(int argc, VALUE *argv, VALUE self)
StringValue(value);
if(NIL_P(type)) type = rb_aref(OBJECT_TYPE_TEMPLATE, oid);
GetX509Name(self, name);
- if (!X509_NAME_add_entry_by_txt(name, RSTRING(oid)->ptr, NUM2INT(type),
- RSTRING(value)->ptr, RSTRING(value)->len, -1, 0)) {
+ if (!X509_NAME_add_entry_by_txt(name, RSTRING_PTR(oid), NUM2INT(type),
+ RSTRING_PTR(value), RSTRING_LEN(value), -1, 0)) {
ossl_raise(eX509NameError, NULL);
}
@@ -175,9 +189,14 @@ ossl_x509name_to_s_old(VALUE self)
return str;
}
+/*
+ * call-seq:
+ * name.to_s => string
+ * name.to_s(integer) => string
+ */
static VALUE
ossl_x509name_to_s(int argc, VALUE *argv, VALUE self)
-{
+{
X509_NAME *name;
VALUE flag, str;
BIO *out;
@@ -199,6 +218,10 @@ ossl_x509name_to_s(int argc, VALUE *argv, VALUE self)
return str;
}
+/*
+ * call-seq:
+ * name.to_a => [[name, data, type], ...]
+ */
static VALUE
ossl_x509name_to_a(VALUE self)
{
@@ -266,6 +289,10 @@ ossl_x509name_eql(VALUE self, VALUE other)
return (result == 0) ? Qtrue : Qfalse;
}
+/*
+ * call-seq:
+ * name.hash => integer
+ */
static VALUE
ossl_x509name_hash(VALUE self)
{
@@ -279,6 +306,31 @@ ossl_x509name_hash(VALUE self)
return ULONG2NUM(hash);
}
+#ifdef HAVE_X509_NAME_HASH_OLD
+/*
+ * call-seq:
+ * name.hash_old => integer
+ *
+ * hash_old returns MD5 based hash used in OpenSSL 0.9.X.
+ */
+static VALUE
+ossl_x509name_hash_old(VALUE self)
+{
+ X509_NAME *name;
+ unsigned long hash;
+
+ GetX509Name(self, name);
+
+ hash = X509_NAME_hash_old(name);
+
+ return ULONG2NUM(hash);
+}
+#endif
+
+/*
+ * call-seq:
+ * name.to_der => string
+ */
static VALUE
ossl_x509name_to_der(VALUE self)
{
@@ -291,7 +343,7 @@ ossl_x509name_to_der(VALUE self)
if((len = i2d_X509_NAME(name, NULL)) <= 0)
ossl_raise(eX509NameError, NULL);
str = rb_str_new(0, len);
- p = RSTRING(str)->ptr;
+ p = RSTRING_PTR(str);
if(i2d_X509_NAME(name, &p) <= 0)
ossl_raise(eX509NameError, NULL);
ossl_str_adjust(str, p);
@@ -320,6 +372,9 @@ Init_ossl_x509name()
rb_define_alias(cX509Name, "<=>", "cmp");
rb_define_method(cX509Name, "eql?", ossl_x509name_eql, 1);
rb_define_method(cX509Name, "hash", ossl_x509name_hash, 0);
+#ifdef HAVE_X509_NAME_HASH_OLD
+ rb_define_method(cX509Name, "hash_old", ossl_x509name_hash_old, 0);
+#endif
rb_define_method(cX509Name, "to_der", ossl_x509name_to_der, 0);
utf8str = INT2NUM(V_ASN1_UTF8STRING);
diff --git a/ext/openssl/ossl_x509req.c b/ext/openssl/ossl_x509req.c
index c1b1a3e619..13a42dddaf 100644
--- a/ext/openssl/ossl_x509req.c
+++ b/ext/openssl/ossl_x509req.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_x509req.c,v 1.5.2.2 2005/09/10 00:54:29 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -171,7 +171,7 @@ ossl_x509req_to_der(VALUE self)
if ((len = i2d_X509_REQ(req, NULL)) <= 0)
ossl_raise(eX509CertError, NULL);
str = rb_str_new(0, len);
- p = RSTRING(str)->ptr;
+ p = RSTRING_PTR(str);
if (i2d_X509_REQ(req, &p) <= 0)
ossl_raise(eX509ReqError, NULL);
ossl_str_adjust(str, p);
@@ -403,14 +403,14 @@ ossl_x509req_set_attributes(VALUE self, VALUE ary)
VALUE item;
Check_Type(ary, T_ARRAY);
- for (i=0;i<RARRAY(ary)->len; i++) {
- OSSL_Check_Kind(RARRAY(ary)->ptr[i], cX509Attr);
+ for (i=0;i<RARRAY_LEN(ary); i++) {
+ OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Attr);
}
GetX509Req(self, req);
sk_X509_ATTRIBUTE_pop_free(req->req_info->attributes, X509_ATTRIBUTE_free);
req->req_info->attributes = NULL;
- for (i=0;i<RARRAY(ary)->len; i++) {
- item = RARRAY(ary)->ptr[i];
+ for (i=0;i<RARRAY_LEN(ary); i++) {
+ item = RARRAY_PTR(ary)[i];
attr = DupX509AttrPtr(item);
if (!X509_REQ_add1_attr(req, attr)) {
ossl_raise(eX509ReqError, NULL);
diff --git a/ext/openssl/ossl_x509revoked.c b/ext/openssl/ossl_x509revoked.c
index a0f2f00aa5..d0f816bad4 100644
--- a/ext/openssl/ossl_x509revoked.c
+++ b/ext/openssl/ossl_x509revoked.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_x509revoked.c,v 1.2.2.1 2004/12/15 01:54:38 matz Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -175,14 +175,14 @@ ossl_x509revoked_set_extensions(VALUE self, VALUE ary)
VALUE item;
Check_Type(ary, T_ARRAY);
- for (i=0; i<RARRAY(ary)->len; i++) {
- OSSL_Check_Kind(RARRAY(ary)->ptr[i], cX509Ext);
+ for (i=0; i<RARRAY_LEN(ary); i++) {
+ OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Ext);
}
GetX509Rev(self, rev);
sk_X509_EXTENSION_pop_free(rev->extensions, X509_EXTENSION_free);
rev->extensions = NULL;
- for (i=0; i<RARRAY(ary)->len; i++) {
- item = RARRAY(ary)->ptr[i];
+ for (i=0; i<RARRAY_LEN(ary); i++) {
+ item = RARRAY_PTR(ary)[i];
ext = DupX509ExtPtr(item);
if(!X509_REVOKED_add_ext(rev, ext, -1)) {
ossl_raise(eX509RevError, NULL);
diff --git a/ext/openssl/ossl_x509store.c b/ext/openssl/ossl_x509store.c
index 360769e612..769ce8a91a 100644
--- a/ext/openssl/ossl_x509store.c
+++ b/ext/openssl/ossl_x509store.c
@@ -1,5 +1,5 @@
/*
- * $Id: ossl_x509store.c,v 1.2.2.5 2005/09/10 00:54:29 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -118,11 +118,18 @@ ossl_x509store_set_vfy_cb(VALUE self, VALUE cb)
return cb;
}
+
+/*
+ * call-seq:
+ * X509::Store.new => store
+ *
+ */
static VALUE
ossl_x509store_initialize(int argc, VALUE *argv, VALUE self)
{
X509_STORE *store;
+/* BUG: This method takes any number of arguments but appears to ignore them. */
GetX509Store(self, store);
X509_STORE_set_verify_cb_func(store, ossl_verify_cb);
ossl_x509store_set_vfy_cb(self, Qnil);
@@ -206,7 +213,7 @@ ossl_x509store_add_file(VALUE self, VALUE file)
if(file != Qnil){
Check_SafeStr(file);
- path = RSTRING(file)->ptr;
+ path = RSTRING_PTR(file);
}
GetX509Store(self, store);
lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
@@ -227,7 +234,7 @@ ossl_x509store_add_path(VALUE self, VALUE dir)
if(dir != Qnil){
Check_SafeStr(dir);
- path = RSTRING(dir)->ptr;
+ path = RSTRING_PTR(dir);
}
GetX509Store(self, store);
lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
@@ -451,7 +458,7 @@ ossl_x509stctx_set_error(VALUE self, VALUE err)
X509_STORE_CTX *ctx;
GetX509StCtx(self, ctx);
- X509_STORE_CTX_set_error(ctx, FIX2INT(err));
+ X509_STORE_CTX_set_error(ctx, NUM2INT(err));
return err;
}
@@ -550,6 +557,10 @@ ossl_x509stctx_set_trust(VALUE self, VALUE trust)
return trust;
}
+/*
+ * call-seq:
+ * storectx.time = time => time
+ */
static VALUE
ossl_x509stctx_set_time(VALUE self, VALUE time)
{
diff --git a/ext/openssl/ruby_missing.h b/ext/openssl/ruby_missing.h
index f673bb157a..64b76f26b4 100644
--- a/ext/openssl/ruby_missing.h
+++ b/ext/openssl/ruby_missing.h
@@ -1,5 +1,5 @@
/*
- * $Id: ruby_missing.h,v 1.3 2003/09/06 08:56:57 gotoyuzo Exp $
+ * $Id$
* 'OpenSSL for Ruby' project
* Copyright (C) 2001-2003 Michal Rokos <m.rokos@sh.cvut.cz>
* All rights reserved.
@@ -9,10 +9,33 @@
* (See the file 'LICENCE'.)
*/
#if !defined(_OSSL_RUBY_MISSING_H_)
-#define _OSS_RUBY_MISSING_H_
+#define _OSSL_RUBY_MISSING_H_
#define rb_define_copy_func(klass, func) \
rb_define_method(klass, "initialize_copy", func, 1)
-#endif /* _OSS_RUBY_MISSING_H_ */
+#ifndef GetReadFile
+#define FPTR_TO_FD(fptr) (fptr->fd)
+#else
+#define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr)))
+#endif
+
+#ifndef HAVE_RB_IO_T
+#define rb_io_t OpenFile
+#endif
+
+#ifndef HAVE_RB_STR_SET_LEN
+/* these methods should probably be backported to 1.8 */
+#define rb_str_set_len(str, length) do { \
+ RSTRING(str)->ptr[length] = 0; \
+ RSTRING(str)->len = length; \
+} while(0)
+#endif /* ! HAVE_RB_STR_SET_LEN */
+
+#ifndef HAVE_RB_BLOCK_CALL
+/* the openssl module doesn't use arg[3-4] and arg2 is always rb_each */
+#define rb_block_call(arg1, arg2, arg3, arg4, arg5, arg6) rb_iterate(rb_each, arg1, arg5, arg6)
+#endif /* ! HAVE_RB_BLOCK_CALL */
+
+#endif /* _OSSL_RUBY_MISSING_H_ */
diff --git a/ext/pty/expect_sample.rb b/ext/pty/expect_sample.rb
index bf8a2352fe..2a2e29f866 100644
--- a/ext/pty/expect_sample.rb
+++ b/ext/pty/expect_sample.rb
@@ -15,10 +15,6 @@ PTY.spawn("ftp ftp.ruby-lang.org") do |r_f,w_f,pid|
$expect_verbose = false
- r_f.expect(/^Name.*: /) do
- w_f.print "ftp\n"
- end
-
if !ENV['USER'].nil?
username = ENV['USER']
elsif !ENV['LOGNAME'].nil?
@@ -27,19 +23,16 @@ PTY.spawn("ftp ftp.ruby-lang.org") do |r_f,w_f,pid|
username = 'guest'
end
- r_f.expect('word:') do
- w_f.print username+"@\n"
- end
- r_f.expect("> ") do
- w_f.print "cd pub/ruby\n"
+ r_f.expect(/^(Name).*: |(word):|> /) do
+ w_f.puts($1 ? "ftp" : $2 ? "#{username}@" : "cd pub/ruby")
end
r_f.expect("> ") do
w_f.print "dir\n"
end
- r_f.expect("> ") do |output|
+ r_f.expect(/[^\-]> /) do |output|
for x in output[0].split("\n")
- if x =~ /(ruby.*\.tar\.gz)/ then
+ if x =~ /(ruby.*?\.tar\.gz)/ then
fnames.push $1
end
end
diff --git a/ext/pty/lib/expect.rb b/ext/pty/lib/expect.rb
index aa9ab895d3..08191b05b9 100644
--- a/ext/pty/lib/expect.rb
+++ b/ext/pty/lib/expect.rb
@@ -10,7 +10,7 @@ class IO
e_pat = pat
end
while true
- if IO.select([self],nil,nil,timeout).nil? then
+ if !IO.select([self],nil,nil,timeout) or eof? then
result = nil
break
end
diff --git a/ext/pty/pty.c b/ext/pty/pty.c
index 93fb5c0118..939335242f 100644
--- a/ext/pty/pty.c
+++ b/ext/pty/pty.c
@@ -39,10 +39,10 @@
#if !defined(HAVE_OPENPTY)
#if defined(__hpux)
-static
-char *MasterDevice = "/dev/ptym/pty%s",
- *SlaveDevice = "/dev/pty/tty%s",
- *deviceNo[] = {
+static const
+char MasterDevice[] = "/dev/ptym/pty%s",
+ SlaveDevice[] = "/dev/pty/tty%s",
+ *const deviceNo[] = {
"p0","p1","p2","p3","p4","p5","p6","p7",
"p8","p9","pa","pb","pc","pd","pe","pf",
"q0","q1","q2","q3","q4","q5","q6","q7",
@@ -62,10 +62,10 @@ char *MasterDevice = "/dev/ptym/pty%s",
0,
};
#elif defined(_IBMESA) /* AIX/ESA */
-static
-char *MasterDevice = "/dev/ptyp%s",
- *SlaveDevice = "/dev/ttyp%s",
- *deviceNo[] = {
+static const
+char MasterDevice[] = "/dev/ptyp%s",
+ SlaveDevice[] = "/dev/ttyp%s",
+ *const deviceNo[] = {
"00","01","02","03","04","05","06","07","08","09","0a","0b","0c","0d","0e","0f",
"10","11","12","13","14","15","16","17","18","19","1a","1b","1c","1d","1e","1f",
"20","21","22","23","24","25","26","27","28","29","2a","2b","2c","2d","2e","2f",
@@ -84,10 +84,10 @@ char *MasterDevice = "/dev/ptyp%s",
"f0","f1","f2","f3","f4","f5","f6","f7","f8","f9","fa","fb","fc","fd","fe","ff",
};
#elif !defined(HAVE_PTSNAME)
-static
-char *MasterDevice = "/dev/pty%s",
- *SlaveDevice = "/dev/tty%s",
- *deviceNo[] = {
+static const
+char MasterDevice[] = "/dev/pty%s",
+ SlaveDevice[] = "/dev/tty%s",
+ *const deviceNo[] = {
"p0","p1","p2","p3","p4","p5","p6","p7",
"p8","p9","pa","pb","pc","pd","pe","pf",
"q0","q1","q2","q3","q4","q5","q6","q7",
@@ -101,8 +101,6 @@ char *MasterDevice = "/dev/pty%s",
#endif
#endif /* !defined(HAVE_OPENPTY) */
-static char SlaveName[DEVICELEN];
-
#ifndef HAVE_SETEUID
# ifdef HAVE_SETREUID
# define seteuid(e) setreuid(-1, (e))
@@ -139,7 +137,7 @@ raise_from_wait(state, info)
char buf[1024];
VALUE exc;
- snprintf(buf, sizeof(buf), "pty - %s: %d", state, info->child_pid);
+ snprintf(buf, sizeof(buf), "pty - %s: %ld", state, (long)info->child_pid);
exc = rb_exc_new2(eChildExited, buf);
rb_iv_set(exc, "status", rb_last_status);
rb_funcall(info->thread, rb_intern("raise"), 1, exc);
@@ -155,17 +153,15 @@ pty_syswait(info)
cpid = rb_waitpid(info->child_pid, &status, WUNTRACED);
if (cpid == -1) return Qnil;
-#if defined(IF_STOPPED)
- if (IF_STOPPED(status)) { /* suspend */
- raise_from_wait("stopped", info);
- }
-#elif defined(WIFSTOPPED)
- if (WIFSTOPPED(status)) { /* suspend */
- raise_from_wait("stopped", info);
- }
+#if defined(WIFSTOPPED)
+#elif defined(IF_STOPPED)
+#define WIFSTOPPED(status) IF_STOPPED(status)
#else
---->> Either IF_STOPPED or WIFSTOPPED is needed <<----
#endif /* WIFSTOPPED | IF_STOPPED */
+ if (WIFSTOPPED(status)) { /* suspend */
+ raise_from_wait("stopped", info);
+ }
else if (kill(info->child_pid, 0) == 0) {
raise_from_wait("changed", info);
}
@@ -176,27 +172,31 @@ pty_syswait(info)
}
}
-static void getDevice _((int*, int*));
+static void getDevice _((int*, int*, char [DEVICELEN]));
struct exec_info {
int argc;
VALUE *argv;
};
+static VALUE pty_exec _((VALUE v));
+
static VALUE
-pty_exec(arg)
- struct exec_info *arg;
+pty_exec(v)
+ VALUE v;
{
+ struct exec_info *arg = (struct exec_info *)v;
return rb_f_exec(arg->argc, arg->argv);
}
static void
-establishShell(argc, argv, info)
+establishShell(argc, argv, info, SlaveName)
int argc;
VALUE *argv;
struct pty_info *info;
-{
- static int i,master,slave,currentPid;
+ char SlaveName[DEVICELEN];
+{
+ int i,master,slave;
char *p, tmp, *getenv();
struct passwd *pwent;
VALUE v;
@@ -220,10 +220,9 @@ establishShell(argc, argv, info)
argc = 1;
argv = &v;
}
- getDevice(&master,&slave);
+ getDevice(&master, &slave, SlaveName);
info->thread = rb_thread_current();
- currentPid = getpid();
if((i = fork()) < 0) {
close(master);
close(slave);
@@ -231,8 +230,6 @@ establishShell(argc, argv, info)
}
if(i == 0) { /* child */
- currentPid = getpid();
-
/*
* Set free from process group and controlling terminal
*/
@@ -244,7 +241,7 @@ establishShell(argc, argv, info)
if (setpgrp() == -1)
perror("setpgrp()");
# else /* SETGRP_VOID */
- if (setpgrp(0, currentPid) == -1)
+ if (setpgrp(0, getpid()) == -1)
rb_sys_fail("setpgrp()");
if ((i = open("/dev/tty", O_RDONLY)) < 0)
rb_sys_fail("/dev/tty");
@@ -307,8 +304,9 @@ pty_finalize_syswait(info)
}
static int
-get_device_once(master, slave, fail)
+get_device_once(master, slave, SlaveName, fail)
int *master, *slave, fail;
+ char SlaveName[DEVICELEN];
{
#if defined HAVE_OPENPTY
/*
@@ -331,10 +329,9 @@ get_device_once(master, slave, fail)
}
*slave = open(name, O_RDWR);
- strcpy(SlaveName, name);
+ strncpy(SlaveName, name, sizeof SlaveName);
return 0;
-}
#else /* HAVE__GETPTY */
int i,j;
@@ -360,7 +357,7 @@ get_device_once(master, slave, fail)
#endif
*master = i;
*slave = j;
- strcpy(SlaveName, pn);
+ strncpy(SlaveName, pn, sizeof SlaveName);
return 0;
#if defined I_PUSH && !defined linux
}
@@ -379,10 +376,10 @@ get_device_once(master, slave, fail)
char MasterName[DEVICELEN];
for (p = deviceNo; *p != NULL; p++) {
- sprintf(MasterName,MasterDevice,*p);
+ snprintf(MasterName, sizeof MasterName, MasterDevice, *p);
if ((i = open(MasterName,O_RDWR,0)) >= 0) {
*master = i;
- sprintf(SlaveName,SlaveDevice,*p);
+ snprintf(SlaveName, sizeof SlaveName, SlaveDevice, *p);
if ((j = open(SlaveName,O_RDWR,0)) >= 0) {
*slave = j;
chown(SlaveName, getuid(), getgid());
@@ -399,22 +396,16 @@ get_device_once(master, slave, fail)
}
static void
-getDevice(master, slave)
+getDevice(master, slave, slavename)
int *master, *slave;
+ char slavename[DEVICELEN];
{
- if (get_device_once(master, slave, 0)) {
+ if (get_device_once(master, slave, slavename, 0)) {
rb_gc();
- get_device_once(master, slave, 1);
+ get_device_once(master, slave, slavename, 1);
}
}
-static void
-freeDevice()
-{
- chmod(SlaveName, 0666);
- chown(SlaveName, 0, 0);
-}
-
/* ruby function: getpty */
static VALUE
pty_getpty(argc, argv, self)
@@ -425,14 +416,15 @@ pty_getpty(argc, argv, self)
VALUE res;
struct pty_info info;
struct pty_info thinfo;
- OpenFile *wfptr,*rfptr;
+ rb_io_t *wfptr,*rfptr;
VALUE rport = rb_obj_alloc(rb_cFile);
VALUE wport = rb_obj_alloc(rb_cFile);
-
+ char SlaveName[DEVICELEN];
+
MakeOpenFile(rport, rfptr);
MakeOpenFile(wport, wfptr);
- establishShell(argc, argv, &info);
+ establishShell(argc, argv, &info, SlaveName);
rfptr->mode = rb_io_mode_flags("r");
rfptr->f = fdopen(info.fd, "r");
diff --git a/ext/purelib.rb b/ext/purelib.rb
new file mode 100644
index 0000000000..dbe514c34a
--- /dev/null
+++ b/ext/purelib.rb
@@ -0,0 +1,10 @@
+nul = nil
+$:.each_with_index {|path, index|
+ if /\A(?:\.\/)*-\z/ =~ path
+ nul = index
+ break
+ end
+}
+if nul
+ $:[nul..-1] = ["."]
+end
diff --git a/ext/racc/cparse/cparse.c b/ext/racc/cparse/cparse.c
index 197a0eb40b..18a26f670f 100644
--- a/ext/racc/cparse/cparse.c
+++ b/ext/racc/cparse/cparse.c
@@ -393,10 +393,6 @@ cparse_params_mark(void *ptr)
rb_gc_mark(v->goto_check);
rb_gc_mark(v->goto_default);
rb_gc_mark(v->goto_pointer);
- rb_gc_mark(v->goto_pointer);
- rb_gc_mark(v->goto_pointer);
- rb_gc_mark(v->goto_pointer);
- rb_gc_mark(v->goto_pointer);
rb_gc_mark(v->reduce_table);
rb_gc_mark(v->token_table);
rb_gc_mark(v->state);
diff --git a/ext/racc/cparse/extconf.rb b/ext/racc/cparse/extconf.rb
index 8516c2998a..dd953a7e15 100644
--- a/ext/racc/cparse/extconf.rb
+++ b/ext/racc/cparse/extconf.rb
@@ -1,4 +1,4 @@
-# $Id: extconf.rb,v 1.1 2002/03/22 07:20:31 aamine Exp $
+# $Id$
require 'mkmf'
create_makefile 'racc/cparse'
diff --git a/ext/readline/extconf.rb b/ext/readline/extconf.rb
index b67a443dad..b820c0b32f 100644
--- a/ext/readline/extconf.rb
+++ b/ext/readline/extconf.rb
@@ -42,7 +42,9 @@ else
end
end
-have_readline_var("rl_filename_completion_function")
+have_func("rl_filename_completion_function")
+have_func("rl_username_completion_function")
+have_func("rl_completion_matches")
have_readline_var("rl_deprep_term_function")
have_readline_var("rl_completion_append_character")
have_readline_var("rl_basic_word_break_characters")
@@ -57,7 +59,6 @@ have_func("rl_cleanup_after_signal")
have_func("rl_clear_signals")
have_func("rl_vi_editing_mode")
have_func("rl_emacs_editing_mode")
-have_func("rl_clear_signals")
have_func("replace_history_entry")
have_func("remove_history")
create_makefile("readline")
diff --git a/ext/readline/readline.c b/ext/readline/readline.c
index 4f840ee2c0..637cb9950b 100644
--- a/ext/readline/readline.c
+++ b/ext/readline/readline.c
@@ -34,21 +34,40 @@ static ID completion_proc, completion_case_fold;
#ifndef HAVE_RL_FILENAME_COMPLETION_FUNCTION
# define rl_filename_completion_function filename_completion_function
+#endif
+#ifndef HAVE_RL_USERNAME_COMPLETION_FUNCTION
# define rl_username_completion_function username_completion_function
+#endif
+#ifndef HAVE_RL_COMPLETION_MATCHES
# define rl_completion_matches completion_matches
#endif
-static int readline_event(void);
static char **readline_attempted_completion_function(const char *text,
int start, int end);
+#ifdef HAVE_RL_EVENT_HOOK
+#ifdef DOSISH
+#define BUSY_WAIT 1
+#else
+#define BUSY_WAIT 0
+#endif
+
+static int readline_event(void);
static int
readline_event()
{
- CHECK_INTS;
+#if BUSY_WAIT
rb_thread_schedule();
+#else
+ fd_set rset;
+
+ FD_ZERO(&rset);
+ FD_SET(fileno(rl_instream), &rset);
+ rb_thread_select(fileno(rl_instream) + 1, &rset, NULL, NULL, NULL);
return 0;
+#endif
}
+#endif
static VALUE
readline_readline(argc, argv, self)
@@ -60,7 +79,7 @@ readline_readline(argc, argv, self)
char *prompt = NULL;
char *buff;
int status;
- OpenFile *ofp, *ifp;
+ rb_io_t *ofp, *ifp;
rb_secure(4);
if (rb_scan_args(argc, argv, "02", &tmp, &add_hist) > 0) {
@@ -814,6 +833,12 @@ Init_readline()
#ifdef HAVE_RL_EVENT_HOOK
rl_event_hook = readline_event;
#endif
+#ifdef HAVE_RL_CATCH_SIGNALS
+ rl_catch_signals = 0;
+#endif
+#ifdef HAVE_RL_CATCH_SIGWINCH
+ rl_catch_sigwinch = 0;
+#endif
#ifdef HAVE_RL_CLEAR_SIGNALS
rl_clear_signals();
#endif
diff --git a/ext/sdbm/_sdbm.c b/ext/sdbm/_sdbm.c
index 7ffcf8579c..5b34824afc 100644
--- a/ext/sdbm/_sdbm.c
+++ b/ext/sdbm/_sdbm.c
@@ -8,7 +8,7 @@
*/
#ifndef lint
-/*char sdbm_rcsid[] = "$Id: _sdbm.c,v 1.5.2.1 2005/09/08 05:59:41 matz Exp $";*/
+/*char sdbm_rcsid[] = "$Id$";*/
#endif
#include "sdbm.h"
@@ -626,7 +626,7 @@ register DBM *db;
*/
#ifndef lint
-/*char pair_rcsid[] = "$Id: _sdbm.c,v 1.5.2.1 2005/09/08 05:59:41 matz Exp $";*/
+/*char pair_rcsid[] = "$Id$";*/
#endif
#ifndef BSD42
diff --git a/ext/sdbm/init.c b/ext/sdbm/init.c
index ef4fb8ffbf..acadc9b26a 100644
--- a/ext/sdbm/init.c
+++ b/ext/sdbm/init.c
@@ -2,8 +2,8 @@
sdbminit.c -
- $Author: ocean $
- $Date: 2005/06/25 05:42:41 $
+ $Author$
+ $Date$
created at: Fri May 7 08:34:24 JST 1999
Copyright (C) 1995-2001 Yukihiro Matsumoto
diff --git a/ext/socket/addrinfo.h b/ext/socket/addrinfo.h
index a22615ee00..e93adafba6 100644
--- a/ext/socket/addrinfo.h
+++ b/ext/socket/addrinfo.h
@@ -61,10 +61,15 @@
#undef NI_NUMERICSERV
#undef NI_DGRAM
+#undef addrinfo
#define addrinfo addrinfo__compat
+#undef getaddrinfo
#define getaddrinfo getaddrinfo__compat
+#undef getnameinfo
#define getnameinfo getnameinfo__compat
+#undef freehostent
#define freehostent freehostent__compat
+#undef freeaddrinfo
#define freeaddrinfo freeaddrinfo__compat
#ifndef __P
diff --git a/ext/socket/extconf.rb b/ext/socket/extconf.rb
index 41b715e0af..23003637e0 100644
--- a/ext/socket/extconf.rb
+++ b/ext/socket/extconf.rb
@@ -33,6 +33,9 @@ if /solaris/ =~ RUBY_PLATFORM and !try_compile("")
# bug of gcc 3.0 on Solaris 8 ?
headers << "sys/feature_tests.h"
end
+if have_header("arpa/inet.h")
+ headers << "arpa/inet.h"
+end
ipv6 = false
default_ipv6 = /cygwin/ !~ RUBY_PLATFORM
@@ -40,6 +43,7 @@ if enable_config("ipv6", default_ipv6)
if checking_for("ipv6") {try_link(<<EOF)}
#include <sys/types.h>
#include <sys/socket.h>
+int
main()
{
socket(AF_INET6, SOCK_STREAM, 0);
@@ -116,8 +120,9 @@ if have_func("sendmsg") | have_func("recvmsg")
have_struct_member('struct msghdr', 'msg_accrights', ['sys/types.h', 'sys/socket.h'])
end
-getaddr_info_ok = enable_config("wide-getaddrinfo") do
- checking_for("wide getaddrinfo") {try_run(<<EOF)}
+getaddr_info_ok = (enable_config("wide-getaddrinfo") && :wide) ||
+ (checking_for("wide getaddrinfo") {try_run(<<EOF)} && :os)
+#{COMMON_HEADERS}
#{cpp_include(headers)}
#include <stdlib.h>
@@ -132,11 +137,17 @@ getaddr_info_ok = enable_config("wide-getaddrinfo") do
#define AF_LOCAL AF_UNIX
#endif
+int
main()
{
int passive, gaierr, inet4 = 0, inet6 = 0;
struct addrinfo hints, *ai, *aitop;
char straddr[INET6_ADDRSTRLEN], strport[16];
+#ifdef _WIN32
+ WSADATA retdata;
+
+ WSAStartup(MAKEWORD(2, 0), &retdata);
+#endif
for (passive = 0; passive <= 1; passive++) {
memset(&hints, 0, sizeof(hints));
@@ -153,6 +164,10 @@ main()
if (ai->ai_addr == NULL)
goto bad;
#if defined(_AIX)
+ if (ai->ai_family == AF_INET6 && passive) {
+ inet6++;
+ continue;
+ }
ai->ai_addr->sa_len = ai->ai_addrlen;
ai->ai_addr->sa_family = ai->ai_family;
#endif
@@ -215,7 +230,6 @@ main()
exit(EXIT_FAILURE);
}
EOF
-end
if ipv6 and not getaddr_info_ok
abort <<EOS
@@ -240,11 +254,33 @@ Fatal: invalid value for --with-lookup-order-hack (expected INET, INET6 or UNSPE
EOS
end
+have_type("struct addrinfo", headers)
+have_func("freehostent")
+have_func("freeaddrinfo")
+if have_func("gai_strerror")
+ if checking_for("gai_strerror() returns const pointer") {!try_compile(<<EOF)}
+#{COMMON_HEADERS}
+#{cpp_include(headers)}
+#include <stdlib.h>
+void
+conftest_gai_strerror_is_const()
+{
+ *gai_strerror(0) = 0;
+}
+EOF
+ $defs << "-DGAI_STRERROR_CONST"
+ end
+end
+
$objs = ["socket.#{$OBJEXT}"]
-unless getaddr_info_ok and have_func("getnameinfo", "netdb.h") and have_func("getaddrinfo", "netdb.h")
+if getaddr_info_ok == :wide or
+ !have_func("getnameinfo", headers) or !have_func("getaddrinfo", headers)
if have_struct_member("struct in6_addr", "s6_addr8", headers)
- $defs[-1] = "-DHAVE_ADDR8"
+ $defs[-1] = "s6_addr=s6_addr8"
+ end
+ if ipv6 == "kame" && have_struct_member("struct in6_addr", "s6_addr32", headers)
+ $defs[-1] = "-DFAITH"
end
$CPPFLAGS="-I. "+$CPPFLAGS
$objs += ["getaddrinfo.#{$OBJEXT}"]
@@ -252,7 +288,6 @@ unless getaddr_info_ok and have_func("getnameinfo", "netdb.h") and have_func("ge
have_func("inet_ntop") or have_func("inet_ntoa")
have_func("inet_pton") or have_func("inet_aton")
have_func("getservbyport")
- have_header("arpa/inet.h")
have_header("arpa/nameser.h")
have_header("resolv.h")
end
diff --git a/ext/socket/getaddrinfo.c b/ext/socket/getaddrinfo.c
index 9fb4ebcb06..8381038867 100644
--- a/ext/socket/getaddrinfo.c
+++ b/ext/socket/getaddrinfo.c
@@ -39,6 +39,9 @@
*/
#include "config.h"
+#ifdef RUBY_EXTCONF_H
+#include RUBY_EXTCONF_H
+#endif
#include <sys/types.h>
#if !defined(_WIN32) && !defined(__VMS)
#include <sys/param.h>
@@ -68,7 +71,11 @@
#include <in.h>
#include <netdb.h>
#else
+#if USE_WINSOCK2
#include <winsock2.h>
+#else
+#include <winsock.h>
+#endif
#include <io.h>
#endif
#include <string.h>
@@ -199,7 +206,8 @@ if (pai->ai_flags & AI_CANONNAME) {\
#define ERR(err) { error = (err); goto bad; }
-#if defined __UCLIBC__
+#ifndef HAVE_GAI_STRERROR
+#ifdef GAI_STRERROR_CONST
const
#endif
char *
@@ -210,6 +218,7 @@ gai_strerror(ecode)
ecode = EAI_MAX;
return (char *)ai_errlist[ecode];
}
+#endif
void
freeaddrinfo(ai)
@@ -388,7 +397,7 @@ getaddrinfo(hostname, servname, hints, res)
port = htons((unsigned short)atoi(servname));
} else {
struct servent *sp;
- char *proto;
+ const char *proto;
proto = NULL;
switch (pai->ai_socktype) {
diff --git a/ext/socket/getnameinfo.c b/ext/socket/getnameinfo.c
index 66f7e8818a..7bbeebf7d8 100644
--- a/ext/socket/getnameinfo.c
+++ b/ext/socket/getnameinfo.c
@@ -56,7 +56,11 @@
#endif
#endif
#ifdef _WIN32
+#if USE_WINSOCK2
#include <winsock2.h>
+#else
+#include <winsock.h>
+#endif
#define snprintf _snprintf
#endif
diff --git a/ext/socket/socket.c b/ext/socket/socket.c
index 5c91c390ec..e38d665e6e 100644
--- a/ext/socket/socket.c
+++ b/ext/socket/socket.c
@@ -2,8 +2,8 @@
socket.c -
- $Author: matz $
- $Date: 2006/08/07 07:50:28 $
+ $Author$
+ $Date$
created at: Thu Mar 31 12:21:29 JST 1994
Copyright (C) 1993-2001 Yukihiro Matsumoto
@@ -42,6 +42,9 @@
#ifdef HAVE_NETINET_UDP_H
# include <netinet/udp.h>
#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
#include <netdb.h>
#endif
#include <errno.h>
@@ -195,6 +198,34 @@ ruby_getaddrinfo__aix(nodename, servname, hints, res)
}
#undef getaddrinfo
#define getaddrinfo(node,serv,hints,res) ruby_getaddrinfo__aix((node),(serv),(hints),(res))
+static int
+ruby_getnameinfo__aix(sa, salen, host, hostlen, serv, servlen, flags)
+ const struct sockaddr *sa;
+ size_t salen;
+ char *host;
+ size_t hostlen;
+ char *serv;
+ size_t servlen;
+ int flags;
+{
+ struct sockaddr_in6 *sa6;
+ u_int32_t *a6;
+
+ if (sa->sa_family == AF_INET6) {
+ sa6 = (struct sockaddr_in6 *)sa;
+ a6 = sa6->sin6_addr.u6_addr.u6_addr32;
+
+ if (a6[0] == 0 && a6[1] == 0 && a6[2] == 0 && a6[3] == 0) {
+ strncpy(host, "::", hostlen);
+ snprintf(serv, servlen, "%d", sa6->sin6_port);
+ return 0;
+ }
+ }
+ return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
+}
+#undef getnameinfo
+#define getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) \
+ ruby_getnameinfo__aix((sa), (salen), (host), (hostlen), (serv), (servlen), (flags))
#ifndef CMSG_SPACE
# define CMSG_SPACE(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + _CMSG_ALIGN(len))
#endif
@@ -213,7 +244,7 @@ init_sock(sock, fd)
VALUE sock;
int fd;
{
- OpenFile *fp;
+ rb_io_t *fp;
MakeOpenFile(sock, fp);
fp->f = rb_fdopen(fd, "r");
@@ -228,7 +259,7 @@ static VALUE
bsock_s_for_fd(klass, fd)
VALUE klass, fd;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
VALUE sock = init_sock(rb_obj_alloc(klass), NUM2INT(fd));
GetOpenFile(sock, fptr);
@@ -244,7 +275,7 @@ bsock_shutdown(argc, argv, sock)
{
VALUE howto;
int how;
- OpenFile *fptr;
+ rb_io_t *fptr;
if (rb_safe_level() >= 4 && !OBJ_TAINTED(sock)) {
rb_raise(rb_eSecurityError, "Insecure: can't shutdown socket");
@@ -269,7 +300,7 @@ static VALUE
bsock_close_read(sock)
VALUE sock;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
if (rb_safe_level() >= 4 && !OBJ_TAINTED(sock)) {
rb_raise(rb_eSecurityError, "Insecure: can't close socket");
@@ -288,7 +319,7 @@ static VALUE
bsock_close_write(sock)
VALUE sock;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
if (rb_safe_level() >= 4 && !OBJ_TAINTED(sock)) {
rb_raise(rb_eSecurityError, "Insecure: can't close socket");
@@ -353,7 +384,7 @@ bsock_setsockopt(sock, lev, optname, val)
VALUE sock, lev, optname, val;
{
int level, option;
- OpenFile *fptr;
+ rb_io_t *fptr;
int i;
char *v;
int vlen;
@@ -436,7 +467,7 @@ bsock_getsockopt(sock, lev, optname)
int level, option;
socklen_t len;
char *buf;
- OpenFile *fptr;
+ rb_io_t *fptr;
level = NUM2INT(lev);
option = NUM2INT(optname);
@@ -460,7 +491,7 @@ bsock_getsockname(sock)
{
char buf[1024];
socklen_t len = sizeof buf;
- OpenFile *fptr;
+ rb_io_t *fptr;
GetOpenFile(sock, fptr);
if (getsockname(fileno(fptr->f), (struct sockaddr*)buf, &len) < 0)
@@ -474,7 +505,7 @@ bsock_getpeername(sock)
{
char buf[1024];
socklen_t len = sizeof buf;
- OpenFile *fptr;
+ rb_io_t *fptr;
GetOpenFile(sock, fptr);
if (getpeername(fileno(fptr->f), (struct sockaddr*)buf, &len) < 0)
@@ -490,7 +521,7 @@ bsock_send(argc, argv, sock)
{
VALUE mesg, to;
VALUE flags;
- OpenFile *fptr;
+ rb_io_t *fptr;
FILE *f;
int fd, n;
@@ -543,7 +574,7 @@ s_recvfrom(sock, argc, argv, from)
VALUE *argv;
enum sock_recv_type from;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
VALUE str;
char buf[1024];
socklen_t alen = sizeof buf;
@@ -613,7 +644,7 @@ s_recvfrom(sock, argc, argv, from)
static VALUE
s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
{
- OpenFile *fptr;
+ rb_io_t *fptr;
VALUE str;
char buf[1024];
socklen_t alen = sizeof buf;
@@ -809,7 +840,7 @@ host_str(host, hbuf, len)
return NULL;
}
else if (rb_obj_is_kind_of(host, rb_cInteger)) {
- long i = NUM2LONG(host);
+ unsigned long i = NUM2ULONG(host);
make_inetaddr(htonl(i), hbuf, len);
return hbuf;
@@ -862,10 +893,10 @@ port_str(port, pbuf, len)
}
#ifndef NI_MAXHOST
-# define 1025
+# define NI_MAXHOST 1025
#endif
#ifndef NI_MAXSERV
-# define 32
+# define NI_MAXSERV 32
#endif
static struct addrinfo*
@@ -1054,7 +1085,8 @@ ruby_connect(fd, sockaddr, len, socks)
int mode;
#if WAIT_IN_PROGRESS > 0
int wait_in_progress = -1;
- int sockerr, sockerrlen;
+ int sockerr;
+ socklen_t sockerrlen;
#endif
#if defined(HAVE_FCNTL)
@@ -1274,6 +1306,14 @@ init_inetsock(sock, remote_host, remote_serv, local_host, local_serv, type)
inetsock_cleanup, (VALUE)&arg);
}
+/*
+ * call-seq:
+ * TCPSocket.new(remote_host, remote_port, local_host=nil, local_port=nil)
+ *
+ * Opens a TCP connection to +remote_host+ on +remote_port+. If +local_host+
+ * and +local_port+ are specified, then those parameters are used on the local
+ * end to establish the connection.
+ */
static VALUE
tcp_init(argc, argv, sock)
int argc;
@@ -1310,7 +1350,7 @@ static VALUE
socks_s_close(sock)
VALUE sock;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
if (rb_safe_level() >= 4 && !OBJ_TAINTED(sock)) {
rb_raise(rb_eSecurityError, "Insecure: can't close socket");
@@ -1424,8 +1464,26 @@ tcp_svr_init(argc, argv, sock)
return init_inetsock(sock, Qnil, arg1, Qnil, Qnil, INET_SERVER);
}
+static void
+make_fd_nonblock(int fd)
+{
+ int flags;
+#ifdef F_GETFL
+ flags = fcntl(fd, F_GETFL);
+ if (flags == -1) {
+ rb_sys_fail(0);
+ }
+#else
+ flags = 0;
+#endif
+ flags |= O_NONBLOCK;
+ if (fcntl(fd, F_SETFL, flags) == -1) {
+ rb_sys_fail(0);
+ }
+}
+
static VALUE
-s_accept_nonblock(VALUE klass, OpenFile *fptr, struct sockaddr *sockaddr, socklen_t *len)
+s_accept_nonblock(VALUE klass, rb_io_t *fptr, struct sockaddr *sockaddr, socklen_t *len)
{
int fd2;
@@ -1435,6 +1493,7 @@ s_accept_nonblock(VALUE klass, OpenFile *fptr, struct sockaddr *sockaddr, sockle
if (fd2 < 0) {
rb_sys_fail("accept(2)");
}
+ make_fd_nonblock(fd2);
return init_sock(rb_obj_alloc(klass), fd2);
}
@@ -1483,7 +1542,7 @@ static VALUE
tcp_accept(sock)
VALUE sock;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
struct sockaddr_storage from;
socklen_t fromlen;
@@ -1506,7 +1565,7 @@ tcp_accept(sock)
* serv = TCPServer.new(2202)
* begin
* sock = serv.accept_nonblock
- * rescue Errno::EAGAIN, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR
+ * rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR
* IO.select([serv])
* retry
* end
@@ -1526,7 +1585,7 @@ static VALUE
tcp_accept_nonblock(sock)
VALUE sock;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
struct sockaddr_storage from;
socklen_t fromlen;
@@ -1540,7 +1599,7 @@ static VALUE
tcp_sysaccept(sock)
VALUE sock;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
struct sockaddr_storage from;
socklen_t fromlen;
@@ -1571,7 +1630,7 @@ init_unixsock(sock, path, server)
{
struct sockaddr_un sockaddr;
int fd, status;
- OpenFile *fptr;
+ rb_io_t *fptr;
SafeStringValue(path);
fd = ruby_socket(AF_UNIX, SOCK_STREAM, 0);
@@ -1623,7 +1682,7 @@ static VALUE
ip_addr(sock)
VALUE sock;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
struct sockaddr_storage addr;
socklen_t len = sizeof addr;
@@ -1638,7 +1697,7 @@ static VALUE
ip_peeraddr(sock)
VALUE sock;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
struct sockaddr_storage addr;
socklen_t len = sizeof addr;
@@ -1719,7 +1778,7 @@ static VALUE
udp_connect(sock, host, port)
VALUE sock, host, port;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
struct udp_arg arg;
VALUE ret;
@@ -1737,7 +1796,7 @@ static VALUE
udp_bind(sock, host, port)
VALUE sock, host, port;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
struct addrinfo *res0, *res;
rb_secure(3);
@@ -1762,7 +1821,7 @@ udp_send(argc, argv, sock)
VALUE sock;
{
VALUE mesg, flags, host, port;
- OpenFile *fptr;
+ rb_io_t *fptr;
FILE *f;
int n;
struct addrinfo *res0, *res;
@@ -1861,7 +1920,7 @@ static VALUE
unix_path(sock)
VALUE sock;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
GetOpenFile(sock, fptr);
if (fptr->path == 0) {
@@ -1908,7 +1967,7 @@ unix_send_io(sock, val)
{
#if defined(HAVE_SENDMSG) && (FD_PASSING_BY_MSG_CONTROL || FD_PASSING_BY_MSG_ACCRIGHTS)
int fd;
- OpenFile *fptr;
+ rb_io_t *fptr;
struct msghdr msg;
struct iovec vec[1];
char buf[1];
@@ -1916,12 +1975,12 @@ unix_send_io(sock, val)
#if FD_PASSING_BY_MSG_CONTROL
struct {
struct cmsghdr hdr;
- int fd;
+ char pad[8+sizeof(int)+8];
} cmsg;
#endif
if (rb_obj_is_kind_of(val, rb_cIO)) {
- OpenFile *valfptr;
+ rb_io_t *valfptr;
GetOpenFile(val, valfptr);
fd = fileno(valfptr->f);
}
@@ -1946,12 +2005,13 @@ unix_send_io(sock, val)
#if FD_PASSING_BY_MSG_CONTROL
msg.msg_control = (caddr_t)&cmsg;
- msg.msg_controllen = CMSG_SPACE(sizeof(int));
+ msg.msg_controllen = CMSG_LEN(sizeof(int));
msg.msg_flags = 0;
+ MEMZERO((char*)&cmsg, char, sizeof(cmsg));
cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(int));
cmsg.hdr.cmsg_level = SOL_SOCKET;
cmsg.hdr.cmsg_type = SCM_RIGHTS;
- cmsg.fd = fd;
+ *(int *)CMSG_DATA(&cmsg.hdr) = fd;
#else
msg.msg_accrights = (caddr_t)&fd;
msg.msg_accrightslen = sizeof(fd);
@@ -1988,7 +2048,7 @@ unix_recv_io(argc, argv, sock)
{
#if defined(HAVE_RECVMSG) && (FD_PASSING_BY_MSG_CONTROL || FD_PASSING_BY_MSG_ACCRIGHTS)
VALUE klass, mode;
- OpenFile *fptr;
+ rb_io_t *fptr;
struct msghdr msg;
struct iovec vec[2];
char buf[1];
@@ -1997,7 +2057,7 @@ unix_recv_io(argc, argv, sock)
#if FD_PASSING_BY_MSG_CONTROL
struct {
struct cmsghdr hdr;
- int fd;
+ char pad[8+sizeof(int)+8];
} cmsg;
#endif
@@ -2026,7 +2086,7 @@ unix_recv_io(argc, argv, sock)
cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(int));
cmsg.hdr.cmsg_level = SOL_SOCKET;
cmsg.hdr.cmsg_type = SCM_RIGHTS;
- cmsg.fd = -1;
+ *(int *)CMSG_DATA(&cmsg.hdr) = -1;
#else
msg.msg_accrights = (caddr_t)&fd;
msg.msg_accrightslen = sizeof(fd);
@@ -2039,22 +2099,22 @@ unix_recv_io(argc, argv, sock)
#if FD_PASSING_BY_MSG_CONTROL
if (msg.msg_controllen != CMSG_SPACE(sizeof(int))) {
rb_raise(rb_eSocket,
- "file descriptor was not passed (msg_controllen : %d != %d)",
+ "file descriptor was not passed (msg_controllen=%d, %d expected)",
msg.msg_controllen, CMSG_SPACE(sizeof(int)));
}
- if (cmsg.hdr.cmsg_len != CMSG_SPACE(0) + sizeof(int)) {
+ if (cmsg.hdr.cmsg_len != CMSG_LEN(sizeof(int))) {
rb_raise(rb_eSocket,
- "file descriptor was not passed (cmsg_len : %d != %d)",
- cmsg.hdr.cmsg_len, CMSG_SPACE(0) + sizeof(int));
+ "file descriptor was not passed (cmsg_len=%d, %d expected)",
+ cmsg.hdr.cmsg_len, CMSG_LEN(sizeof(int)));
}
if (cmsg.hdr.cmsg_level != SOL_SOCKET) {
rb_raise(rb_eSocket,
- "file descriptor was not passed (cmsg_level : %d != %d)",
+ "file descriptor was not passed (cmsg_level=%d, %d expected)",
cmsg.hdr.cmsg_level, SOL_SOCKET);
}
if (cmsg.hdr.cmsg_type != SCM_RIGHTS) {
rb_raise(rb_eSocket,
- "file descriptor was not passed (cmsg_type : %d != %d)",
+ "file descriptor was not passed (cmsg_type=%d, %d expected)",
cmsg.hdr.cmsg_type, SCM_RIGHTS);
}
#else
@@ -2066,7 +2126,7 @@ unix_recv_io(argc, argv, sock)
#endif
#if FD_PASSING_BY_MSG_CONTROL
- fd = cmsg.fd;
+ fd = *(int *)CMSG_DATA(&cmsg.hdr);
#endif
if (klass == Qnil)
@@ -2092,7 +2152,7 @@ static VALUE
unix_accept(sock)
VALUE sock;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
struct sockaddr_un from;
socklen_t fromlen;
@@ -2115,7 +2175,7 @@ unix_accept(sock)
* serv = UNIXServer.new("/tmp/sock")
* begin
* sock = serv.accept_nonblock
- * rescue Errno::EAGAIN, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR
+ * rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR
* IO.select([serv])
* retry
* end
@@ -2135,7 +2195,7 @@ static VALUE
unix_accept_nonblock(sock)
VALUE sock;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
struct sockaddr_un from;
socklen_t fromlen;
@@ -2149,7 +2209,7 @@ static VALUE
unix_sysaccept(sock)
VALUE sock;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
struct sockaddr_un from;
socklen_t fromlen;
@@ -2171,7 +2231,7 @@ static VALUE
unix_addr(sock)
VALUE sock;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
struct sockaddr_un addr;
socklen_t len = sizeof addr;
@@ -2186,14 +2246,14 @@ static VALUE
unix_peeraddr(sock)
VALUE sock;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
struct sockaddr_un addr;
socklen_t len = sizeof addr;
GetOpenFile(sock, fptr);
if (getpeername(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0)
- rb_sys_fail("getsockname(2)");
+ rb_sys_fail("getpeername(2)");
return unixaddr(&addr, len);
}
#endif
@@ -2466,7 +2526,7 @@ static VALUE
sock_connect(sock, addr)
VALUE sock, addr;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
int fd;
StringValue(addr);
@@ -2522,7 +2582,7 @@ static VALUE
sock_connect_nonblock(sock, addr)
VALUE sock, addr;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
int n;
StringValue(addr);
@@ -2620,7 +2680,7 @@ static VALUE
sock_bind(sock, addr)
VALUE sock, addr;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
StringValue(addr);
GetOpenFile(sock, fptr);
@@ -2704,7 +2764,7 @@ static VALUE
sock_listen(sock, log)
VALUE sock, log;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
int backlog;
rb_secure(4);
@@ -2861,7 +2921,7 @@ sock_recvfrom(argc, argv, sock)
* client, client_sockaddr = socket.accept
* begin
* pair = client.recvfrom_nonblock(20)
- * rescue Errno::EAGAIN
+ * rescue Errno::EAGAIN, Errno::EWOULDBLOCK
* IO.select([client])
* retry
* end
@@ -2911,7 +2971,7 @@ sock_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock)
* socket.bind( sockaddr )
* socket.listen( 5 )
* client, client_sockaddr = socket.accept
- * puts "The client said, '#{socket.readline.chomp}'"
+ * puts "The client said, '#{client.readline.chomp}'"
* client.puts "Hello from script one!"
* socket.close
*
@@ -2980,7 +3040,7 @@ static VALUE
sock_accept(sock)
VALUE sock;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
VALUE sock2;
char buf[1024];
socklen_t len = sizeof buf;
@@ -3012,11 +3072,11 @@ sock_accept(sock)
* socket.listen(5)
* begin
* client_socket, client_sockaddr = socket.accept_nonblock
- * rescue Errno::EAGAIN, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR
+ * rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR
* IO.select([socket])
* retry
* end
- * puts "The client said, '#{socket.readline.chomp}'"
+ * puts "The client said, '#{client_socket.readline.chomp}'"
* client_socket.puts "Hello from script one!"
* socket.close
*
@@ -3043,7 +3103,7 @@ static VALUE
sock_accept_nonblock(sock)
VALUE sock;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
VALUE sock2;
char buf[1024];
socklen_t len = sizeof buf;
@@ -3071,8 +3131,8 @@ sock_accept_nonblock(sock)
* socket.bind( sockaddr )
* socket.listen( 5 )
* client_fd, client_sockaddr = socket.sysaccept
- * puts "The client said, '#{socket.readline.chomp}'"
* client_socket = Socket.for_fd( client_fd )
+ * puts "The client said, '#{client_socket.readline.chomp}'"
* client_socket.puts "Hello from script one!"
* socket.close
*
@@ -3096,7 +3156,7 @@ static VALUE
sock_sysaccept(sock)
VALUE sock;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
VALUE sock2;
char buf[1024];
socklen_t len = sizeof buf;
@@ -3158,6 +3218,10 @@ make_addrinfo(res0)
}
base = rb_ary_new();
for (res = res0; res; res = res->ai_next) {
+#if defined(AF_INET6) && !defined(INET6) /* workaround for Windows */
+ if (res->ai_addr->sa_family == AF_INET6)
+ continue;
+#endif
ary = ipaddr(res->ai_addr);
rb_ary_push(ary, INT2FIX(res->ai_family));
rb_ary_push(ary, INT2FIX(res->ai_socktype));
diff --git a/ext/socket/sockport.h b/ext/socket/sockport.h
index 8c7bebf558..e1cddf53f4 100644
--- a/ext/socket/sockport.h
+++ b/ext/socket/sockport.h
@@ -2,8 +2,8 @@
sockport.h -
- $Author: eban $
- $Date: 2000/08/24 06:29:30 $
+ $Author$
+ $Date$
created at: Fri Apr 30 23:19:34 JST 1999
************************************************/
diff --git a/ext/stringio/README b/ext/stringio/README
index 190052309c..c4031f7e97 100644
--- a/ext/stringio/README
+++ b/ext/stringio/README
@@ -1,6 +1,6 @@
-*- rd -*-
-$Author: nobu $
-$Date: 2002/02/19 13:16:24 $
+$Author$
+$Date$
=begin
diff --git a/ext/stringio/stringio.c b/ext/stringio/stringio.c
index fcc596d5f0..14ae2dc117 100644
--- a/ext/stringio/stringio.c
+++ b/ext/stringio/stringio.c
@@ -2,8 +2,8 @@
stringio.c -
- $Author: nobu $
- $Date: 2005/08/13 09:36:12 $
+ $Author$
+ $Date$
$RoughId: stringio.c,v 1.13 2002/03/14 03:24:18 nobu Exp $
created at: Tue Feb 19 04:10:38 JST 2002
@@ -14,6 +14,7 @@
#include "ruby.h"
#include "rubyio.h"
+#include "re.h"
#if defined(HAVE_FCNTL_H) || defined(_WIN32)
#include <fcntl.h>
#elif defined(HAVE_SYS_FCNTL_H)
@@ -162,6 +163,7 @@ static VALUE strio_rewind _((VALUE));
static VALUE strio_seek _((int, VALUE *, VALUE));
static VALUE strio_get_sync _((VALUE));
static VALUE strio_each_byte _((VALUE));
+static VALUE strio_each_char _((VALUE));
static VALUE strio_getc _((VALUE));
static VALUE strio_ungetc _((VALUE, VALUE));
static VALUE strio_readchar _((VALUE));
@@ -267,6 +269,8 @@ strio_init(argc, argv, ptr)
break;
}
ptr->string = string;
+ ptr->pos = 0;
+ ptr->lineno = 0;
}
static VALUE
@@ -657,6 +661,9 @@ strio_seek(argc, argv, self)
rb_scan_args(argc, argv, "11", NULL, &whence);
offset = NUM2LONG(argv[0]);
+ if (CLOSED(ptr)) {
+ rb_raise(rb_eIOError, "closed stream");
+ }
switch (NIL_P(whence) ? 0 : NUM2LONG(whence)) {
case 0:
break;
@@ -667,7 +674,7 @@ strio_seek(argc, argv, self)
offset += RSTRING(ptr->string)->len;
break;
default:
- rb_raise(rb_eArgError, "invalid whence %ld", NUM2LONG(whence));
+ error_inval("invalid whence");
}
if (offset < 0) {
error_inval(0);
@@ -707,11 +714,14 @@ strio_each_byte(self)
VALUE self;
{
struct StringIO *ptr = readable(StringIO(self));
- while (ptr->pos < RSTRING(ptr->string)->len) {
- char c = RSTRING(ptr->string)->ptr[ptr->pos++];
+
+ RETURN_ENUMERATOR(self, 0, 0);
+
+ while (ptr->pos < RSTRING_LEN(ptr->string)) {
+ char c = RSTRING_PTR(ptr->string)[ptr->pos++];
rb_yield(CHR2FIX(c));
}
- return Qnil;
+ return self;
}
/*
@@ -771,15 +781,24 @@ strio_ungetc(self, ch)
int cc = NUM2INT(ch);
long len, pos = ptr->pos;
- if (cc != EOF && pos > 0) {
- if ((len = RSTRING(ptr->string)->len) < pos-- ||
- (unsigned char)RSTRING(ptr->string)->ptr[pos] !=
- (unsigned char)cc) {
- strio_extend(ptr, pos, 1);
- RSTRING(ptr->string)->ptr[pos] = cc;
- OBJ_INFECT(ptr->string, self);
+ if (cc != EOF) {
+ len = RSTRING(ptr->string)->len;
+ if (pos == 0) {
+ char *p;
+ rb_str_resize(ptr->string, len + 1);
+ p = RSTRING(ptr->string)->ptr;
+ memmove(p + 1, p, len);
+ }
+ else {
+ if (len < pos-- ||
+ (unsigned char)RSTRING(ptr->string)->ptr[pos] !=
+ (unsigned char)cc) {
+ strio_extend(ptr, pos, 1);
+ }
+ --ptr->pos;
}
- --ptr->pos;
+ RSTRING(ptr->string)->ptr[pos] = cc;
+ OBJ_INFECT(ptr->string, self);
ptr->flags &= ~STRIO_EOF;
}
return Qnil;
@@ -800,6 +819,41 @@ strio_readchar(self)
return c;
}
+/*
+ * call-seq:
+ * strio.each_char {|char| block } -> strio
+ *
+ * See IO#each_char.
+ */
+static VALUE
+strio_each_char(self)
+ VALUE self;
+{
+ struct StringIO *sio;
+ VALUE str;
+ const char *ptr;
+ size_t len;
+
+ RETURN_ENUMERATOR(self, 0, 0);
+
+ sio = readable(StringIO(self));
+ str = sio->string;
+ ptr = RSTRING_PTR(str);
+ len = RSTRING_LEN(str);
+
+ while (sio->pos < len) {
+ int pos = sio->pos;
+ char c = ptr[pos];
+ int n = mbclen(c);
+
+ if (len < pos + n) n = len - pos;
+
+ sio->pos += n;
+ rb_yield(rb_str_substr(str, pos, n));
+ }
+ return self;
+}
+
static void
bm_init_skip(skip, pat, m)
long *skip;
@@ -879,7 +933,7 @@ strio_getline(argc, argv, ptr)
s = p;
while ((p = memchr(p, '\n', e - p)) && (p != e)) {
if (*++p == '\n') {
- e = p;
+ e = p + 1;
break;
}
}
@@ -947,7 +1001,7 @@ strio_readline(argc, argv, self)
VALUE *argv;
VALUE self;
{
- VALUE line = strio_getline(argc, argv, readable(StringIO(self)));
+ VALUE line = strio_gets(argc, argv, self);
if (NIL_P(line)) rb_eof_error();
return line;
}
@@ -968,6 +1022,8 @@ strio_each(argc, argv, self)
struct StringIO *ptr = StringIO(self);
VALUE line;
+ RETURN_ENUMERATOR(self, argc, argv);
+
while (!NIL_P(line = strio_getline(argc, argv, readable(ptr)))) {
rb_yield(line);
}
@@ -1291,11 +1347,17 @@ Init_stringio()
rb_define_method(StringIO, "path", strio_path, 0);
rb_define_method(StringIO, "each", strio_each, -1);
- rb_define_method(StringIO, "each_byte", strio_each_byte, 0);
rb_define_method(StringIO, "each_line", strio_each, -1);
+ rb_define_method(StringIO, "lines", strio_each, -1);
+ rb_define_method(StringIO, "each_byte", strio_each_byte, 0);
+ rb_define_method(StringIO, "bytes", strio_each_byte, 0);
+ rb_define_method(StringIO, "each_char", strio_each_char, 0);
+ rb_define_method(StringIO, "chars", strio_each_char, 0);
rb_define_method(StringIO, "getc", strio_getc, 0);
+ rb_define_method(StringIO, "getbyte", strio_getc, 0);
rb_define_method(StringIO, "ungetc", strio_ungetc, 1);
rb_define_method(StringIO, "readchar", strio_readchar, 0);
+ rb_define_method(StringIO, "readbyte", strio_readchar, 0);
rb_define_method(StringIO, "gets", strio_gets, -1);
rb_define_method(StringIO, "readline", strio_readline, -1);
rb_define_method(StringIO, "readlines", strio_readlines, -1);
diff --git a/ext/strscan/strscan.c b/ext/strscan/strscan.c
index 5e5ab5db1f..b5ee20282c 100644
--- a/ext/strscan/strscan.c
+++ b/ext/strscan/strscan.c
@@ -1,5 +1,5 @@
/*
- $Id: strscan.c,v 1.7.2.8 2006/07/26 09:37:00 aamine Exp $
+ $Id$
Copyright (c) 1999-2006 Minero Aoki
@@ -403,6 +403,7 @@ strscan_do_scan(VALUE self, VALUE regex, int succptr, int getstr, int headonly)
if (S_RESTLEN(p) < 0) {
return Qnil;
}
+ rb_kcode_set_option(regex);
if (headonly) {
ret = re_match(RREGEXP(regex)->ptr,
CURPTR(p), S_RESTLEN(p),
@@ -416,6 +417,7 @@ strscan_do_scan(VALUE self, VALUE regex, int succptr, int getstr, int headonly)
S_RESTLEN(p),
&(p->regs));
}
+ rb_kcode_reset_option();
if (ret == -2) rb_raise(ScanError, "regexp buffer overflow");
if (ret < 0) {
@@ -1256,7 +1258,7 @@ Init_strscan(void)
tmp = rb_str_new2(STRSCAN_VERSION);
rb_obj_freeze(tmp);
rb_const_set(StringScanner, rb_intern("Version"), tmp);
- tmp = rb_str_new2("$Id: strscan.c,v 1.7.2.8 2006/07/26 09:37:00 aamine Exp $");
+ tmp = rb_str_new2("$Id$");
rb_obj_freeze(tmp);
rb_const_set(StringScanner, rb_intern("Id"), tmp);
diff --git a/ext/syck/bytecode.c b/ext/syck/bytecode.c
index acda3b15a4..567aaf52a8 100644
--- a/ext/syck/bytecode.c
+++ b/ext/syck/bytecode.c
@@ -3,8 +3,8 @@
/*
* bytecode.re
*
- * $Author: why $
- * $Date: 2005/09/20 06:46:43 $
+ * $Author$
+ * $Date$
*
* Copyright (C) 2003 why the lucky stiff
*/
diff --git a/ext/syck/emitter.c b/ext/syck/emitter.c
index 8d32784cd5..9c8ab8d49b 100644
--- a/ext/syck/emitter.c
+++ b/ext/syck/emitter.c
@@ -1,8 +1,8 @@
/*
* emitter.c
*
- * $Author: matz $
- * $Date: 2006/05/03 17:29:34 $
+ * $Author$
+ * $Date$
*
* Copyright (C) 2003 why the lucky stiff
*
diff --git a/ext/syck/handler.c b/ext/syck/handler.c
index 26fb258318..56fe838fbd 100644
--- a/ext/syck/handler.c
+++ b/ext/syck/handler.c
@@ -1,8 +1,8 @@
/*
* handler.c
*
- * $Author: why $
- * $Date: 2005/09/20 06:46:43 $
+ * $Author$
+ * $Date$
*
* Copyright (C) 2003 why the lucky stiff
*/
diff --git a/ext/syck/implicit.c b/ext/syck/implicit.c
index 0f922f4d1b..d356faf7d9 100644
--- a/ext/syck/implicit.c
+++ b/ext/syck/implicit.c
@@ -3,8 +3,8 @@
/*
* implicit.re
*
- * $Author: ocean $
- * $Date: 2005/10/26 00:28:39 $
+ * $Author$
+ * $Date$
*
* Copyright (C) 2003 why the lucky stiff
*/
diff --git a/ext/syck/node.c b/ext/syck/node.c
index 724f747e99..28fc78c077 100644
--- a/ext/syck/node.c
+++ b/ext/syck/node.c
@@ -1,8 +1,8 @@
/*
* node.c
*
- * $Author: matz $
- * $Date: 2005/09/16 09:35:23 $
+ * $Author$
+ * $Date$
*
* Copyright (C) 2003 why the lucky stiff
*/
diff --git a/ext/syck/rubyext.c b/ext/syck/rubyext.c
index e2de4bbfd0..76e8279601 100644
--- a/ext/syck/rubyext.c
+++ b/ext/syck/rubyext.c
@@ -2,8 +2,8 @@
/*
* rubyext.c
*
- * $Author: ocean $
- * $Date: 2006/01/30 15:11:57 $
+ * $Author$
+ * $Date$
*
* Copyright (C) 2003-2005 why the lucky stiff
*/
@@ -268,9 +268,13 @@ rb_syck_mktime(str, len)
{
char padded[] = "000000";
char *end = ptr + 1;
+ char *p = end;
while ( isdigit( *end ) ) end++;
- MEMCPY(padded, ptr + 1, char, end - (ptr + 1));
- usec = strtol(padded, NULL, 10);
+ if (end - p < sizeof(padded)) {
+ MEMCPY(padded, ptr + 1, char, end - (ptr + 1));
+ p = padded;
+ }
+ usec = strtol(p, NULL, 10);
}
else
{
@@ -913,7 +917,6 @@ static VALUE
syck_resolver_initialize( self )
VALUE self;
{
- VALUE tags = rb_hash_new();
rb_ivar_set(self, s_tags, rb_hash_new());
return self;
}
@@ -948,7 +951,6 @@ VALUE
syck_resolver_detect_implicit( self, val )
VALUE self, val;
{
- char *type_id;
return rb_str_new2( "" );
}
@@ -1304,7 +1306,6 @@ syck_genericresolver_node_import( self, node )
break;
case syck_seq_kind:
- rb_iv_set(obj, "@kind", sym_seq);
v = rb_ary_new2( syck_seq_count( n ) );
for ( i = 0; i < syck_seq_count( n ); i++ )
{
@@ -1315,10 +1316,10 @@ syck_genericresolver_node_import( self, node )
style = sym_inline;
}
obj = rb_funcall( cSeq, s_new, 3, t, v, style );
+ rb_iv_set(obj, "@kind", sym_seq);
break;
case syck_map_kind:
- rb_iv_set(obj, "@kind", sym_map);
v = rb_hash_new();
for ( i = 0; i < syck_map_count( n ); i++ )
{
@@ -1329,6 +1330,7 @@ syck_genericresolver_node_import( self, node )
style = sym_inline;
}
obj = rb_funcall( cMap, s_new, 3, t, v, style );
+ rb_iv_set(obj, "@kind", sym_map);
break;
}
@@ -2024,7 +2026,6 @@ syck_emitter_emit( argc, argv, self )
VALUE self;
{
VALUE oid, proc;
- char *anchor_name;
SyckEmitter *emitter;
struct emitter_xtra *bonus;
SYMID symple;
@@ -2280,7 +2281,6 @@ Init_syck()
*/
cScalar = rb_define_class_under( rb_syck, "Scalar", cNode );
rb_define_alloc_func( cScalar, syck_scalar_alloc );
- rb_define_attr( cNode, "value", 1, 0 );
rb_define_method( cScalar, "initialize", syck_scalar_initialize, 3 );
rb_define_method( cScalar, "value=", syck_scalar_value_set, 1 );
rb_define_method( cScalar, "style=", syck_scalar_style_set, 1 );
diff --git a/ext/syck/syck.c b/ext/syck/syck.c
index ac5427bc1b..a83c8813c1 100644
--- a/ext/syck/syck.c
+++ b/ext/syck/syck.c
@@ -1,8 +1,8 @@
/*
* syck.c
*
- * $Author: matz $
- * $Date: 2006/08/07 08:09:34 $
+ * $Author$
+ * $Date$
*
* Copyright (C) 2003 why the lucky stiff
*/
diff --git a/ext/syck/syck.h b/ext/syck/syck.h
index bc383ff2de..e7d07e9c0d 100644
--- a/ext/syck/syck.h
+++ b/ext/syck/syck.h
@@ -1,8 +1,8 @@
/*
* syck.h
*
- * $Author: ocean $
- * $Date: 2005/12/20 04:13:26 $
+ * $Author$
+ * $Date$
*
* Copyright (C) 2003 why the lucky stiff
*/
diff --git a/ext/syck/token.c b/ext/syck/token.c
index e7b0414f74..3c6cd1a9cf 100644
--- a/ext/syck/token.c
+++ b/ext/syck/token.c
@@ -3,8 +3,8 @@
/*
* token.re
*
- * $Author: why $
- * $Date: 2005/09/20 23:56:24 $
+ * $Author$
+ * $Date$
*
* Copyright (C) 2003 why the lucky stiff
*/
diff --git a/ext/syck/yaml2byte.c b/ext/syck/yaml2byte.c
index 01a3aaf652..821a3cd5b5 100644
--- a/ext/syck/yaml2byte.c
+++ b/ext/syck/yaml2byte.c
@@ -1,8 +1,8 @@
/*
* yaml2byte.c
*
- * $Author: matz $
- * $Date: 2006/05/03 17:41:10 $
+ * $Author$
+ * $Date$
*
* Copyright (C) 2003 why the lucky stiff, clark evans
*
diff --git a/ext/syslog/extconf.rb b/ext/syslog/extconf.rb
index d47ed8fd61..0fa0bc339b 100644
--- a/ext/syslog/extconf.rb
+++ b/ext/syslog/extconf.rb
@@ -1,5 +1,5 @@
# $RoughId: extconf.rb,v 1.3 2001/11/24 17:49:26 knu Exp $
-# $Id: extconf.rb,v 1.1 2001/11/26 12:00:40 knu Exp $
+# $Id$
require 'mkmf'
diff --git a/ext/syslog/syslog.c b/ext/syslog/syslog.c
index 99e4215a95..ecc49318f7 100644
--- a/ext/syslog/syslog.c
+++ b/ext/syslog/syslog.c
@@ -4,7 +4,7 @@
* <amos+ruby@utdallas.edu>
*
* $RoughId: syslog.c,v 1.21 2002/02/25 12:21:17 knu Exp $
- * $Id: syslog.c,v 1.8.2.1 2004/04/05 07:45:24 matz Exp $
+ * $Id$
*/
#include "ruby.h"
@@ -22,6 +22,7 @@ static void syslog_write(int pri, int argc, VALUE *argv)
{
VALUE str;
+ rb_secure(4);
if (argc < 1) {
rb_raise(rb_eArgError, "no log message supplied");
}
@@ -38,6 +39,7 @@ static void syslog_write(int pri, int argc, VALUE *argv)
/* Syslog module methods */
static VALUE mSyslog_close(VALUE self)
{
+ rb_secure(4);
if (!syslog_opened) {
rb_raise(rb_eRuntimeError, "syslog not opened");
}
@@ -132,6 +134,7 @@ static VALUE mSyslog_get_mask(VALUE self)
static VALUE mSyslog_set_mask(VALUE self, VALUE mask)
{
+ rb_secure(4);
if (!syslog_opened) {
rb_raise(rb_eRuntimeError, "must open syslog before setting log mask");
}
diff --git a/ext/syslog/syslog.txt b/ext/syslog/syslog.txt
index b134ed2a40..35bd4cb057 100644
--- a/ext/syslog/syslog.txt
+++ b/ext/syslog/syslog.txt
@@ -1,13 +1,16 @@
.\" syslog.txt - -*- Indented-Text -*-
$RoughId: syslog.txt,v 1.18 2002/02/25 08:20:14 knu Exp $
-$Id: syslog.txt,v 1.2 2002/02/25 12:13:30 knu Exp $
+$Id$
UNIX Syslog extension for Ruby
Amos Gouaux, University of Texas at Dallas
<amos+ruby@utdallas.edu>
&
Akinori MUSHA
-<knu@ruby-lang.org>
+<knu@iDaemons.org>
+
+Contact:
+ - Akinori MUSHA <knu@iDaemons.org> (current maintainer)
** Syslog(Module)
diff --git a/ext/syslog/test.rb b/ext/syslog/test.rb
index 907602c21d..cfa33eff8f 100644
--- a/ext/syslog/test.rb
+++ b/ext/syslog/test.rb
@@ -1,6 +1,6 @@
#!/usr/bin/env ruby
# $RoughId: test.rb,v 1.9 2002/02/25 08:20:14 knu Exp $
-# $Id: test.rb,v 1.4 2002/11/27 08:36:22 knu Exp $
+# $Id$
# Please only run this test on machines reasonable for testing.
# If in doubt, ask your admin.
diff --git a/ext/thread/extconf.rb b/ext/thread/extconf.rb
new file mode 100644
index 0000000000..2f984efc6d
--- /dev/null
+++ b/ext/thread/extconf.rb
@@ -0,0 +1,9 @@
+require 'mkmf'
+
+enable_config('fastthread', true) or exit
+
+if with_config('mem-pools', true)
+ $CPPFLAGS << ' -DUSE_MEM_POOLS'
+end
+
+create_makefile("thread")
diff --git a/ext/thread/lib/thread.rb b/ext/thread/lib/thread.rb
new file mode 100644
index 0000000000..6c533aba39
--- /dev/null
+++ b/ext/thread/lib/thread.rb
@@ -0,0 +1,5 @@
+unless defined? Thread
+ fail "Thread not available for this ruby interpreter"
+end
+
+require 'thread.so'
diff --git a/ext/thread/thread.c b/ext/thread/thread.c
new file mode 100644
index 0000000000..298d7d08ca
--- /dev/null
+++ b/ext/thread/thread.c
@@ -0,0 +1,1239 @@
+/*
+ * Optimized Ruby Mutex implementation, loosely based on thread.rb by
+ * Yukihiro Matsumoto <matz@ruby-lang.org>
+ *
+ * Copyright 2006-2007 MenTaLguY <mental@rydia.net>
+ *
+ * RDoc taken from original.
+ *
+ * This file is made available under the same terms as Ruby.
+ */
+
+#include <ruby.h>
+#include <intern.h>
+#include <rubysig.h>
+
+static VALUE rb_cMutex;
+static VALUE rb_cConditionVariable;
+static VALUE rb_cQueue;
+static VALUE rb_cSizedQueue;
+
+static VALUE set_critical(VALUE value);
+
+static VALUE
+thread_exclusive(VALUE (*func)(ANYARGS), VALUE arg)
+{
+ VALUE critical = rb_thread_critical;
+
+ rb_thread_critical = 1;
+ return rb_ensure(func, arg, set_critical, (VALUE)critical);
+}
+
+/*
+ * call-seq:
+ * Thread.exclusive { block } => obj
+ *
+ * Wraps a block in Thread.critical, restoring the original value
+ * upon exit from the critical section, and returns the value of the
+ * block.
+ */
+
+static VALUE
+rb_thread_exclusive(void)
+{
+ return thread_exclusive(rb_yield, Qundef);
+}
+
+typedef struct _Entry {
+ VALUE value;
+ struct _Entry *next;
+} Entry;
+
+typedef struct _List {
+ Entry *entries;
+ Entry *last_entry;
+ Entry *entry_pool;
+ unsigned long size;
+} List;
+
+static void
+init_list(List *list)
+{
+ list->entries = NULL;
+ list->last_entry = NULL;
+ list->entry_pool = NULL;
+ list->size = 0;
+}
+
+static void
+mark_list(List *list)
+{
+ Entry *entry;
+ for (entry = list->entries; entry; entry = entry->next) {
+ rb_gc_mark(entry->value);
+ }
+}
+
+static void
+free_entries(Entry *first)
+{
+ Entry *next;
+ while (first) {
+ next = first->next;
+ xfree(first);
+ first = next;
+ }
+}
+
+static void
+finalize_list(List *list)
+{
+ free_entries(list->entries);
+ free_entries(list->entry_pool);
+}
+
+static void
+push_list(List *list, VALUE value)
+{
+ Entry *entry;
+
+ if (list->entry_pool) {
+ entry = list->entry_pool;
+ list->entry_pool = entry->next;
+ } else {
+ entry = ALLOC(Entry);
+ }
+
+ entry->value = value;
+ entry->next = NULL;
+
+ if (list->last_entry) {
+ list->last_entry->next = entry;
+ } else {
+ list->entries = entry;
+ }
+ list->last_entry = entry;
+
+ ++list->size;
+}
+
+static void
+push_multiple_list(List *list, VALUE *values, unsigned count)
+{
+ unsigned i;
+ for (i = 0; i < count; i++) {
+ push_list(list, values[i]);
+ }
+}
+
+static void
+recycle_entries(List *list, Entry *first_entry, Entry *last_entry)
+{
+#ifdef USE_MEM_POOLS
+ last_entry->next = list->entry_pool;
+ list->entry_pool = first_entry;
+#else
+ last_entry->next = NULL;
+ free_entries(first_entry);
+#endif
+}
+
+static VALUE
+shift_list(List *list)
+{
+ Entry *entry;
+ VALUE value;
+
+ entry = list->entries;
+ if (!entry) return Qnil;
+
+ list->entries = entry->next;
+ if (entry == list->last_entry) {
+ list->last_entry = NULL;
+ }
+
+ --list->size;
+
+ value = entry->value;
+ recycle_entries(list, entry, entry);
+
+ return value;
+}
+
+static void
+remove_one(List *list, VALUE value)
+{
+ Entry **ref;
+ Entry *prev;
+ Entry *entry;
+
+ for (ref = &list->entries, prev = NULL, entry = list->entries;
+ entry != NULL;
+ ref = &entry->next, prev = entry, entry = entry->next) {
+ if (entry->value == value) {
+ *ref = entry->next;
+ list->size--;
+ if (!entry->next) {
+ list->last_entry = prev;
+ }
+ recycle_entries(list, entry, entry);
+ break;
+ }
+ }
+}
+
+static void
+clear_list(List *list)
+{
+ if (list->last_entry) {
+ recycle_entries(list, list->entries, list->last_entry);
+ list->entries = NULL;
+ list->last_entry = NULL;
+ list->size = 0;
+ }
+}
+
+static VALUE
+array_from_list(List const *list)
+{
+ VALUE ary;
+ Entry *entry;
+ ary = rb_ary_new();
+ for (entry = list->entries; entry; entry = entry->next) {
+ rb_ary_push(ary, entry->value);
+ }
+ return ary;
+}
+
+static VALUE
+wake_thread(VALUE thread)
+{
+ return rb_thread_wakeup_alive(thread);
+}
+
+static VALUE
+run_thread(VALUE thread)
+{
+ thread = wake_thread(thread);
+ if (RTEST(thread) && !rb_thread_critical)
+ rb_thread_schedule();
+ return thread;
+}
+
+static VALUE
+wake_one(List *list)
+{
+ VALUE waking;
+
+ waking = Qnil;
+ while (list->entries && !RTEST(waking)) {
+ waking = wake_thread(shift_list(list));
+ }
+
+ return waking;
+}
+
+static VALUE
+wake_all(List *list)
+{
+ while (list->entries) {
+ wake_one(list);
+ }
+ return Qnil;
+}
+
+extern int rb_thread_join _((VALUE thread, double limit));
+#define DELAY_INFTY 1E30
+
+static VALUE
+wait_list_inner(VALUE arg)
+{
+ push_list((List *)arg, rb_thread_current());
+ rb_thread_stop();
+ return Qnil;
+}
+
+static VALUE
+wait_list_cleanup(VALUE arg)
+{
+ /* cleanup in case of spurious wakeups */
+ remove_one((List *)arg, rb_thread_current());
+ return Qnil;
+}
+
+static VALUE
+wait_list(List *list)
+{
+ return rb_ensure(wait_list_inner, (VALUE)list, wait_list_cleanup, (VALUE)list);
+}
+
+static void
+kill_waiting_threads(List *waiting)
+{
+ Entry *entry;
+
+ for (entry = waiting->entries; entry; entry = entry->next) {
+ rb_thread_kill(entry->value);
+ }
+}
+
+/*
+ * Document-class: Mutex
+ *
+ * Mutex implements a simple semaphore that can be used to coordinate access to
+ * shared data from multiple concurrent threads.
+ *
+ * Example:
+ *
+ * require 'thread'
+ * semaphore = Mutex.new
+ *
+ * a = Thread.new {
+ * semaphore.synchronize {
+ * # access shared resource
+ * }
+ * }
+ *
+ * b = Thread.new {
+ * semaphore.synchronize {
+ * # access shared resource
+ * }
+ * }
+ *
+ */
+
+typedef struct _Mutex {
+ VALUE owner;
+ List waiting;
+} Mutex;
+
+#define MUTEX_LOCKED_P(mutex) (RTEST((mutex)->owner) && rb_thread_alive_p((mutex)->owner))
+
+static void
+mark_mutex(Mutex *mutex)
+{
+ rb_gc_mark(mutex->owner);
+ mark_list(&mutex->waiting);
+}
+
+static void
+finalize_mutex(Mutex *mutex)
+{
+ finalize_list(&mutex->waiting);
+}
+
+static void
+free_mutex(Mutex *mutex)
+{
+ kill_waiting_threads(&mutex->waiting);
+ finalize_mutex(mutex);
+ xfree(mutex);
+}
+
+static void
+init_mutex(Mutex *mutex)
+{
+ mutex->owner = Qnil;
+ init_list(&mutex->waiting);
+}
+
+/*
+ * Document-method: new
+ * call-seq: Mutex.new
+ *
+ * Creates a new Mutex
+ *
+ */
+
+static VALUE
+rb_mutex_alloc(VALUE klass)
+{
+ Mutex *mutex;
+ mutex = ALLOC(Mutex);
+ init_mutex(mutex);
+ return Data_Wrap_Struct(klass, mark_mutex, free_mutex, mutex);
+}
+
+/*
+ * Document-method: locked?
+ * call-seq: locked?
+ *
+ * Returns +true+ if this lock is currently held by some thread.
+ *
+ */
+
+static VALUE
+rb_mutex_locked_p(VALUE self)
+{
+ Mutex *mutex;
+ Data_Get_Struct(self, Mutex, mutex);
+ return MUTEX_LOCKED_P(mutex) ? Qtrue : Qfalse;
+}
+
+/*
+ * Document-method: try_lock
+ * call-seq: try_lock
+ *
+ * Attempts to obtain the lock and returns immediately. Returns +true+ if the
+ * lock was granted.
+ *
+ */
+
+static VALUE
+rb_mutex_try_lock(VALUE self)
+{
+ Mutex *mutex;
+
+ Data_Get_Struct(self, Mutex, mutex);
+
+ if (MUTEX_LOCKED_P(mutex))
+ return Qfalse;
+
+ mutex->owner = rb_thread_current();
+ return Qtrue;
+}
+
+static VALUE
+wait_mutex(VALUE arg)
+{
+ Mutex *mutex = (Mutex *)arg;
+ VALUE current = rb_thread_current();
+
+ push_list(&mutex->waiting, current);
+ do {
+ rb_thread_critical = 0;
+ rb_thread_join(mutex->owner, DELAY_INFTY);
+ rb_thread_critical = 1;
+ if (!MUTEX_LOCKED_P(mutex)) {
+ mutex->owner = current;
+ break;
+ }
+ } while (mutex->owner != current);
+ return Qnil;
+}
+
+/*
+ * Document-method: lock
+ * call-seq: lock
+ *
+ * Attempts to grab the lock and waits if it isn't available.
+ *
+ */
+
+static VALUE
+lock_mutex(Mutex *mutex)
+{
+ VALUE current;
+ current = rb_thread_current();
+
+ rb_thread_critical = 1;
+
+ if (!MUTEX_LOCKED_P(mutex)) {
+ mutex->owner = current;
+ }
+ else {
+ rb_ensure(wait_mutex, (VALUE)mutex, wait_list_cleanup, (VALUE)&mutex->waiting);
+ }
+
+ rb_thread_critical = 0;
+ return Qnil;
+}
+
+static VALUE
+lock_mutex_call(VALUE mutex)
+{
+ return lock_mutex((Mutex *)mutex);
+}
+
+static VALUE
+rb_mutex_lock(VALUE self)
+{
+ Mutex *mutex;
+ Data_Get_Struct(self, Mutex, mutex);
+ lock_mutex(mutex);
+ return self;
+}
+
+/*
+ * Document-method: unlock
+ *
+ * Releases the lock. Returns +nil+ if ref wasn't locked.
+ *
+ */
+
+static VALUE
+unlock_mutex_inner(Mutex *mutex)
+{
+ VALUE waking;
+
+ if (mutex->owner != rb_thread_current()) {
+ rb_raise(rb_eThreadError, "not owner");
+ }
+
+ waking = wake_one(&mutex->waiting);
+ mutex->owner = waking;
+
+ return waking;
+}
+
+static VALUE
+set_critical(VALUE value)
+{
+ rb_thread_critical = (int)value;
+ return Qundef;
+}
+
+static VALUE
+unlock_mutex(Mutex *mutex)
+{
+ VALUE waking = thread_exclusive(unlock_mutex_inner, (VALUE)mutex);
+
+ if (!RTEST(waking)) {
+ return Qfalse;
+ }
+
+ run_thread(waking);
+
+ return Qtrue;
+}
+
+static VALUE
+unlock_mutex_call(VALUE mutex)
+{
+ return unlock_mutex((Mutex *)mutex);
+}
+
+static VALUE
+rb_mutex_unlock(VALUE self)
+{
+ Mutex *mutex;
+ Data_Get_Struct(self, Mutex, mutex);
+
+ if (RTEST(unlock_mutex(mutex))) {
+ return self;
+ } else {
+ return Qnil;
+ }
+}
+
+/*
+ * Document-method: exclusive_unlock
+ * call-seq: exclusive_unlock { ... }
+ *
+ * If the mutex is locked, unlocks the mutex, wakes one waiting thread, and
+ * yields in a critical section.
+ *
+ */
+
+static VALUE
+rb_mutex_exclusive_unlock_inner(Mutex *mutex)
+{
+ VALUE waking;
+ waking = unlock_mutex_inner(mutex);
+ rb_yield(Qundef);
+ return waking;
+}
+
+static VALUE
+rb_mutex_exclusive_unlock(VALUE self)
+{
+ Mutex *mutex;
+ VALUE waking;
+ Data_Get_Struct(self, Mutex, mutex);
+
+ waking = thread_exclusive(rb_mutex_exclusive_unlock_inner, (VALUE)mutex);
+
+ if (!RTEST(waking)) {
+ return Qnil;
+ }
+
+ run_thread(waking);
+
+ return self;
+}
+
+/*
+ * Document-method: synchronize
+ * call-seq: synchronize { ... }
+ *
+ * Obtains a lock, runs the block, and releases the lock when the block
+ * completes. See the example under Mutex.
+ *
+ */
+
+static VALUE
+rb_mutex_synchronize(VALUE self)
+{
+ rb_mutex_lock(self);
+ return rb_ensure(rb_yield, Qundef, rb_mutex_unlock, self);
+}
+
+/*
+ * Document-class: ConditionVariable
+ *
+ * ConditionVariable objects augment class Mutex. Using condition variables,
+ * it is possible to suspend while in the middle of a critical section until a
+ * resource becomes available.
+ *
+ * Example:
+ *
+ * require 'thread'
+ *
+ * mutex = Mutex.new
+ * resource = ConditionVariable.new
+ *
+ * a = Thread.new {
+ * mutex.synchronize {
+ * # Thread 'a' now needs the resource
+ * resource.wait(mutex)
+ * # 'a' can now have the resource
+ * }
+ * }
+ *
+ * b = Thread.new {
+ * mutex.synchronize {
+ * # Thread 'b' has finished using the resource
+ * resource.signal
+ * }
+ * }
+ *
+ */
+
+typedef struct _ConditionVariable {
+ List waiting;
+} ConditionVariable;
+
+static void
+mark_condvar(ConditionVariable *condvar)
+{
+ mark_list(&condvar->waiting);
+}
+
+static void
+finalize_condvar(ConditionVariable *condvar)
+{
+ finalize_list(&condvar->waiting);
+}
+
+static void
+free_condvar(ConditionVariable *condvar)
+{
+ kill_waiting_threads(&condvar->waiting);
+ finalize_condvar(condvar);
+ xfree(condvar);
+}
+
+static void
+init_condvar(ConditionVariable *condvar)
+{
+ init_list(&condvar->waiting);
+}
+
+/*
+ * Document-method: new
+ * call-seq: ConditionVariable.new
+ *
+ * Creates a new ConditionVariable
+ *
+ */
+
+static VALUE
+rb_condvar_alloc(VALUE klass)
+{
+ ConditionVariable *condvar;
+
+ condvar = ALLOC(ConditionVariable);
+ init_condvar(condvar);
+
+ return Data_Wrap_Struct(klass, mark_condvar, free_condvar, condvar);
+}
+
+/*
+ * Document-method: wait
+ * call-seq: wait
+ *
+ * Releases the lock held in +mutex+ and waits; reacquires the lock on wakeup.
+ *
+ */
+
+static void condvar_wakeup(Mutex *mutex);
+
+static void
+wait_condvar(ConditionVariable *condvar, Mutex *mutex)
+{
+ condvar_wakeup(mutex);
+ rb_ensure(wait_list, (VALUE)&condvar->waiting, lock_mutex_call, (VALUE)mutex);
+}
+
+static void
+condvar_wakeup(Mutex *mutex)
+{
+ VALUE waking;
+
+ rb_thread_critical = 1;
+ if (rb_thread_current() != mutex->owner) {
+ rb_thread_critical = 0;
+ rb_raise(rb_eThreadError, "not owner of the synchronization mutex");
+ }
+ waking = unlock_mutex_inner(mutex);
+ if (RTEST(waking)) {
+ wake_thread(waking);
+ }
+}
+
+static VALUE
+legacy_exclusive_unlock(VALUE mutex)
+{
+ return rb_funcall(mutex, rb_intern("exclusive_unlock"), 0);
+}
+
+typedef struct {
+ ConditionVariable *condvar;
+ VALUE mutex;
+} legacy_wait_args;
+
+static VALUE
+legacy_wait(VALUE unused, legacy_wait_args *args)
+{
+ wait_list(&args->condvar->waiting);
+ rb_funcall(args->mutex, rb_intern("lock"), 0);
+ return Qnil;
+}
+
+static VALUE
+rb_condvar_wait(VALUE self, VALUE mutex_v)
+{
+ ConditionVariable *condvar;
+ Data_Get_Struct(self, ConditionVariable, condvar);
+
+ if (CLASS_OF(mutex_v) != rb_cMutex) {
+ /* interoperate with legacy mutex */
+ legacy_wait_args args;
+ args.condvar = condvar;
+ args.mutex = mutex_v;
+ rb_iterate(legacy_exclusive_unlock, mutex_v, legacy_wait, (VALUE)&args);
+ } else {
+ Mutex *mutex;
+ Data_Get_Struct(mutex_v, Mutex, mutex);
+ wait_condvar(condvar, mutex);
+ }
+
+ return self;
+}
+
+/*
+ * Document-method: broadcast
+ * call-seq: broadcast
+ *
+ * Wakes up all threads waiting for this condition.
+ *
+ */
+
+static VALUE
+rb_condvar_broadcast(VALUE self)
+{
+ ConditionVariable *condvar;
+
+ Data_Get_Struct(self, ConditionVariable, condvar);
+
+ thread_exclusive(wake_all, (VALUE)&condvar->waiting);
+ rb_thread_schedule();
+
+ return self;
+}
+
+/*
+ * Document-method: signal
+ * call-seq: signal
+ *
+ * Wakes up the first thread in line waiting for this condition.
+ *
+ */
+
+static void
+signal_condvar(ConditionVariable *condvar)
+{
+ VALUE waking = thread_exclusive(wake_one, (VALUE)&condvar->waiting);
+
+ if (RTEST(waking)) {
+ run_thread(waking);
+ }
+}
+
+static VALUE
+signal_condvar_call(VALUE condvar)
+{
+ signal_condvar((ConditionVariable *)condvar);
+ return Qundef;
+}
+
+static VALUE
+rb_condvar_signal(VALUE self)
+{
+ ConditionVariable *condvar;
+ Data_Get_Struct(self, ConditionVariable, condvar);
+ signal_condvar(condvar);
+ return self;
+}
+
+/*
+ * Document-class: Queue
+ *
+ * This class provides a way to synchronize communication between threads.
+ *
+ * Example:
+ *
+ * require 'thread'
+ *
+ * queue = Queue.new
+ *
+ * producer = Thread.new do
+ * 5.times do |i|
+ * sleep rand(i) # simulate expense
+ * queue << i
+ * puts "#{i} produced"
+ * end
+ * end
+ *
+ * consumer = Thread.new do
+ * 5.times do |i|
+ * value = queue.pop
+ * sleep rand(i/2) # simulate expense
+ * puts "consumed #{value}"
+ * end
+ * end
+ *
+ * consumer.join
+ *
+ */
+
+typedef struct _Queue {
+ Mutex mutex;
+ ConditionVariable value_available;
+ ConditionVariable space_available;
+ List values;
+ unsigned long capacity;
+} Queue;
+
+static void
+mark_queue(Queue *queue)
+{
+ mark_mutex(&queue->mutex);
+ mark_condvar(&queue->value_available);
+ mark_condvar(&queue->space_available);
+ mark_list(&queue->values);
+}
+
+static void
+finalize_queue(Queue *queue)
+{
+ finalize_mutex(&queue->mutex);
+ finalize_condvar(&queue->value_available);
+ finalize_condvar(&queue->space_available);
+ finalize_list(&queue->values);
+}
+
+static void
+free_queue(Queue *queue)
+{
+ kill_waiting_threads(&queue->mutex.waiting);
+ kill_waiting_threads(&queue->space_available.waiting);
+ kill_waiting_threads(&queue->value_available.waiting);
+ finalize_queue(queue);
+ xfree(queue);
+}
+
+static void
+init_queue(Queue *queue)
+{
+ init_mutex(&queue->mutex);
+ init_condvar(&queue->value_available);
+ init_condvar(&queue->space_available);
+ init_list(&queue->values);
+ queue->capacity = 0;
+}
+
+/*
+ * Document-method: new
+ * call-seq: new
+ *
+ * Creates a new queue.
+ *
+ */
+
+static VALUE
+rb_queue_alloc(VALUE klass)
+{
+ Queue *queue;
+ queue = ALLOC(Queue);
+ init_queue(queue);
+ return Data_Wrap_Struct(klass, mark_queue, free_queue, queue);
+}
+
+static VALUE
+rb_queue_marshal_load(VALUE self, VALUE data)
+{
+ Queue *queue;
+ VALUE array;
+ Data_Get_Struct(self, Queue, queue);
+
+ array = rb_marshal_load(data);
+ if (TYPE(array) != T_ARRAY) {
+ rb_raise(rb_eTypeError, "expected Array of queue data");
+ }
+ if (RARRAY(array)->len < 1) {
+ rb_raise(rb_eArgError, "missing capacity value");
+ }
+ queue->capacity = NUM2ULONG(rb_ary_shift(array));
+ push_multiple_list(&queue->values, RARRAY(array)->ptr, (unsigned)RARRAY(array)->len);
+
+ return self;
+}
+
+static VALUE
+rb_queue_marshal_dump(VALUE self)
+{
+ Queue *queue;
+ VALUE array;
+ Data_Get_Struct(self, Queue, queue);
+
+ array = array_from_list(&queue->values);
+ rb_ary_unshift(array, ULONG2NUM(queue->capacity));
+ return rb_marshal_dump(array, Qnil);
+}
+
+/*
+ * Document-method: clear
+ * call-seq: clear
+ *
+ * Removes all objects from the queue.
+ *
+ */
+
+static VALUE
+rb_queue_clear(VALUE self)
+{
+ Queue *queue;
+ Data_Get_Struct(self, Queue, queue);
+
+ lock_mutex(&queue->mutex);
+ clear_list(&queue->values);
+ signal_condvar(&queue->space_available);
+ unlock_mutex(&queue->mutex);
+
+ return self;
+}
+
+/*
+ * Document-method: empty?
+ * call-seq: empty?
+ *
+ * Returns +true+ if the queue is empty.
+ *
+ */
+
+static VALUE
+rb_queue_empty_p(VALUE self)
+{
+ Queue *queue;
+ VALUE result;
+ Data_Get_Struct(self, Queue, queue);
+
+ lock_mutex(&queue->mutex);
+ result = queue->values.size == 0 ? Qtrue : Qfalse;
+ unlock_mutex(&queue->mutex);
+
+ return result;
+}
+
+/*
+ * Document-method: length
+ * call-seq: length
+ *
+ * Returns the length of the queue.
+ *
+ */
+
+static VALUE
+rb_queue_length(VALUE self)
+{
+ Queue *queue;
+ VALUE result;
+ Data_Get_Struct(self, Queue, queue);
+
+ lock_mutex(&queue->mutex);
+ result = ULONG2NUM(queue->values.size);
+ unlock_mutex(&queue->mutex);
+
+ return result;
+}
+
+/*
+ * Document-method: num_waiting
+ * call-seq: num_waiting
+ *
+ * Returns the number of threads waiting on the queue.
+ *
+ */
+
+static VALUE
+rb_queue_num_waiting(VALUE self)
+{
+ Queue *queue;
+ VALUE result;
+ Data_Get_Struct(self, Queue, queue);
+
+ lock_mutex(&queue->mutex);
+ result = ULONG2NUM(queue->value_available.waiting.size +
+ queue->space_available.waiting.size);
+ unlock_mutex(&queue->mutex);
+
+ return result;
+}
+
+static void
+wait_queue(ConditionVariable *condvar, Mutex *mutex)
+{
+ condvar_wakeup(mutex);
+ wait_list(&condvar->waiting);
+ lock_mutex(mutex);
+}
+
+static VALUE queue_pop_inner(VALUE arg);
+
+/*
+ * Document-method: pop
+ * call_seq: pop(non_block=false)
+ *
+ * Retrieves data from the queue. If the queue is empty, the calling thread is
+ * suspended until data is pushed onto the queue. If +non_block+ is true, the
+ * thread isn't suspended, and an exception is raised.
+ *
+ */
+
+static VALUE
+rb_queue_pop(int argc, VALUE *argv, VALUE self)
+{
+ Queue *queue;
+ int should_block;
+ Data_Get_Struct(self, Queue, queue);
+
+ if (argc == 0) {
+ should_block = 1;
+ } else if (argc == 1) {
+ should_block = !RTEST(argv[0]);
+ } else {
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc);
+ }
+
+ lock_mutex(&queue->mutex);
+ if (!queue->values.entries && !should_block) {
+ unlock_mutex(&queue->mutex);
+ rb_raise(rb_eThreadError, "queue empty");
+ }
+
+ while (!queue->values.entries) {
+ wait_queue(&queue->value_available, &queue->mutex);
+ }
+
+ return rb_ensure(queue_pop_inner, (VALUE)queue,
+ unlock_mutex_call, (VALUE)&queue->mutex);
+}
+
+static VALUE
+queue_pop_inner(VALUE arg)
+{
+ Queue *queue = (Queue *)arg;
+ VALUE result = shift_list(&queue->values);
+ if (queue->capacity && queue->values.size < queue->capacity) {
+ signal_condvar(&queue->space_available);
+ }
+ return result;
+}
+
+/*
+ * Document-method: push
+ * call-seq: push(obj)
+ *
+ * Pushes +obj+ to the queue.
+ *
+ */
+
+static VALUE
+rb_queue_push(VALUE self, VALUE value)
+{
+ Queue *queue;
+ Data_Get_Struct(self, Queue, queue);
+
+ lock_mutex(&queue->mutex);
+ while (queue->capacity && queue->values.size >= queue->capacity) {
+ wait_queue(&queue->space_available, &queue->mutex);
+ }
+ push_list(&queue->values, value);
+ rb_ensure(signal_condvar_call, (VALUE)&queue->value_available,
+ unlock_mutex_call, (VALUE)&queue->mutex);
+
+ return self;
+}
+
+/*
+ * Document-class: SizedQueue
+ *
+ * This class represents queues of specified size capacity. The push operation
+ * may be blocked if the capacity is full.
+ *
+ * See Queue for an example of how a SizedQueue works.
+ *
+ */
+
+/*
+ * Document-method: new
+ * call-seq: new
+ *
+ * Creates a fixed-length queue with a maximum size of +max+.
+ *
+ */
+
+/*
+ * Document-method: max
+ * call-seq: max
+ *
+ * Returns the maximum size of the queue.
+ *
+ */
+
+static VALUE
+rb_sized_queue_max(VALUE self)
+{
+ Queue *queue;
+ VALUE result;
+ Data_Get_Struct(self, Queue, queue);
+
+ lock_mutex(&queue->mutex);
+ result = ULONG2NUM(queue->capacity);
+ unlock_mutex(&queue->mutex);
+
+ return result;
+}
+
+/*
+ * Document-method: max=
+ * call-seq: max=(size)
+ *
+ * Sets the maximum size of the queue.
+ *
+ */
+
+static VALUE
+rb_sized_queue_max_set(VALUE self, VALUE value)
+{
+ Queue *queue;
+ unsigned long new_capacity;
+ unsigned long difference;
+ Data_Get_Struct(self, Queue, queue);
+
+ new_capacity = NUM2ULONG(value);
+
+ if (new_capacity < 1) {
+ rb_raise(rb_eArgError, "value must be positive");
+ }
+
+ lock_mutex(&queue->mutex);
+ if (queue->capacity && new_capacity > queue->capacity) {
+ difference = new_capacity - queue->capacity;
+ } else {
+ difference = 0;
+ }
+ queue->capacity = new_capacity;
+ for (; difference > 0; --difference) {
+ signal_condvar(&queue->space_available);
+ }
+ unlock_mutex(&queue->mutex);
+
+ return self;
+}
+
+/*
+ * Document-method: push
+ * call-seq: push(obj)
+ *
+ * Pushes +obj+ to the queue. If there is no space left in the queue, waits
+ * until space becomes available.
+ *
+ */
+
+/*
+ * Document-method: pop
+ * call-seq: pop(non_block=false)
+ *
+ * Retrieves data from the queue and runs a waiting thread, if any.
+ *
+ */
+
+/* for marshalling mutexes and condvars */
+
+static VALUE
+dummy_load(VALUE self, VALUE string)
+{
+ return Qnil;
+}
+
+static VALUE
+dummy_dump(VALUE self)
+{
+ return rb_str_new2("");
+}
+
+void
+Init_thread(void)
+{
+ rb_define_singleton_method(rb_cThread, "exclusive", rb_thread_exclusive, 0);
+
+ rb_cMutex = rb_define_class("Mutex", rb_cObject);
+ rb_define_alloc_func(rb_cMutex, rb_mutex_alloc);
+ rb_define_method(rb_cMutex, "marshal_load", dummy_load, 1);
+ rb_define_method(rb_cMutex, "marshal_dump", dummy_dump, 0);
+ rb_define_method(rb_cMutex, "locked?", rb_mutex_locked_p, 0);
+ rb_define_method(rb_cMutex, "try_lock", rb_mutex_try_lock, 0);
+ rb_define_method(rb_cMutex, "lock", rb_mutex_lock, 0);
+ rb_define_method(rb_cMutex, "unlock", rb_mutex_unlock, 0);
+ rb_define_method(rb_cMutex, "exclusive_unlock", rb_mutex_exclusive_unlock, 0);
+ rb_define_method(rb_cMutex, "synchronize", rb_mutex_synchronize, 0);
+
+ rb_cConditionVariable = rb_define_class("ConditionVariable", rb_cObject);
+ rb_define_alloc_func(rb_cConditionVariable, rb_condvar_alloc);
+ rb_define_method(rb_cConditionVariable, "marshal_load", dummy_load, 1);
+ rb_define_method(rb_cConditionVariable, "marshal_dump", dummy_dump, 0);
+ rb_define_method(rb_cConditionVariable, "wait", rb_condvar_wait, 1);
+ rb_define_method(rb_cConditionVariable, "broadcast", rb_condvar_broadcast, 0);
+ rb_define_method(rb_cConditionVariable, "signal", rb_condvar_signal, 0);
+
+ rb_cQueue = rb_define_class("Queue", rb_cObject);
+ rb_define_alloc_func(rb_cQueue, rb_queue_alloc);
+ rb_define_method(rb_cQueue, "marshal_load", rb_queue_marshal_load, 1);
+ rb_define_method(rb_cQueue, "marshal_dump", rb_queue_marshal_dump, 0);
+ rb_define_method(rb_cQueue, "clear", rb_queue_clear, 0);
+ rb_define_method(rb_cQueue, "empty?", rb_queue_empty_p, 0);
+ rb_define_method(rb_cQueue, "length", rb_queue_length, 0);
+ rb_define_method(rb_cQueue, "num_waiting", rb_queue_num_waiting, 0);
+ rb_define_method(rb_cQueue, "pop", rb_queue_pop, -1);
+ rb_define_method(rb_cQueue, "push", rb_queue_push, 1);
+ rb_alias(rb_cQueue, rb_intern("enq"), rb_intern("push"));
+ rb_alias(rb_cQueue, rb_intern("<<"), rb_intern("push"));
+ rb_alias(rb_cQueue, rb_intern("deq"), rb_intern("pop"));
+ rb_alias(rb_cQueue, rb_intern("shift"), rb_intern("pop"));
+ rb_alias(rb_cQueue, rb_intern("size"), rb_intern("length"));
+
+ rb_cSizedQueue = rb_define_class("SizedQueue", rb_cQueue);
+ rb_define_method(rb_cSizedQueue, "initialize", rb_sized_queue_max_set, 1);
+ rb_define_method(rb_cSizedQueue, "num_waiting", rb_queue_num_waiting, 0);
+ rb_define_method(rb_cSizedQueue, "pop", rb_queue_pop, -1);
+ rb_define_method(rb_cSizedQueue, "push", rb_queue_push, 1);
+ rb_define_method(rb_cSizedQueue, "max", rb_sized_queue_max, 0);
+ rb_define_method(rb_cSizedQueue, "max=", rb_sized_queue_max_set, 1);
+ rb_alias(rb_cSizedQueue, rb_intern("enq"), rb_intern("push"));
+ rb_alias(rb_cSizedQueue, rb_intern("<<"), rb_intern("push"));
+ rb_alias(rb_cSizedQueue, rb_intern("deq"), rb_intern("pop"));
+ rb_alias(rb_cSizedQueue, rb_intern("shift"), rb_intern("pop"));
+}
+
diff --git a/ext/tk/ChangeLog.tkextlib b/ext/tk/ChangeLog.tkextlib
index fa5524da01..8c5d01a954 100644
--- a/ext/tk/ChangeLog.tkextlib
+++ b/ext/tk/ChangeLog.tkextlib
@@ -1,3 +1,69 @@
+2008-05-12 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/lib/tkextlib/tkDND/shape.rb: wrong package name.
+
+--------------< ... some changes ... >------------------
+
+2007-05-26 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/lib/tkextlib/tcllib/tablelist.rb: fix typo.
+
+ * ext/tk/lib/tkextlib/tile/dialog.rb: forget to give an argument.
+
+ * ext/tk/lib/tkextlib/version.rb: update RELEASE_DATE.
+
+2007-01-26 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * ext/tk/lib/tkextlib/iwidgets/checkbox.rb: wrong number of arguments
+ [ruby-Bugs-7776].
+
+ * ext/tk/lib/tkextlib/iwidgets/radiobox.rb: ditto.
+
+ * ext/tk/lib/tkextlib/blt/tile/checkbutton.rb: change primary name
+ of class [ruby-dev:30080].
+
+ * ext/tk/lib/tkextlib/blt/tile/radiobutton.rb: ditto.
+
+2006-11-07 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * lib/tkextlib/tile/treeview.rb : minor bug fix.
+
+ * lib/tkextlib/blt/table.rb: fix bugs which forbade use of
+ '::blt::table' command. Now, probably, it'll works properly.
+
+2006-11-06 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * lib/tkextlib/version.rb: keep release date of tkextlib on
+ "Tk::Tkextlib_RELEASE_DATE".
+
+ * lib/tkextlib/tile/treeview.rb : support Tile 0.7.8.
+ Now, you can handle tree items as objects.
+
+2006-10-04 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * lib/tkextlib/tile.rb, lib/tkextlib/tile/* : support Tile 0.7.6.
+
+2006-10-03 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * lib/tkextlib/SUPPORT_STATUS: [ruby-talk:211939] check links
+ of extensions.
+
+ * lib/tkextlib/blt/container.rb: define instance methods properly.
+
+ * lib/tkextlib/tile/tcombobox.rb: bug fix [ruby-talk:213003].
+
+ * lib/tkextlib/tile/tnotebook.rb: ditto.
+
+ * lib/tkextlib/tile/treeview.rb: ditto.
+
+ * lib/tkextlib/tile/sizegrip.rb: [new] add 'ttk::sizegrip' widget.
+
+2006-08-31 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
+
+ * lib/tkextlib/blt.rb: double dashes (--) option doesn't work
+ properly on some versions of BLT (wrong description on the
+ manual of `blt::bgexec'?).
+
2005-12-11 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* lib/tkextlib/SUPPORT_STATUS: update to support libraries in
diff --git a/ext/tk/MANUAL_tcltklib.eng b/ext/tk/MANUAL_tcltklib.eng
index 1db61f228e..6fa775b7de 100644
--- a/ext/tk/MANUAL_tcltklib.eng
+++ b/ext/tk/MANUAL_tcltklib.eng
@@ -125,7 +125,24 @@ module TclTklib
: Tcl7.6 doesn't have this flag. So PARSE_VARNAME is
: defined as 0.
+ module TclTkLib::RELEASE_TYPE
+ : Defines release type number of Tcl/Tk
+
+ ALPHA
+ : ALPHA release
+
+ BETA
+ : BETA release
+
+ FINAL
+ : FINAL release
+
[module methods]
+ get_version()
+ : return an array of major, minor, release-type number,
+ : number, release-type name, and patchlevel of current
+ : Tcl/Tk library.
+
mainloop(check_root = true)
: Starts the eventloop. If 'check_root' is true, this method
: doesn't return when a root widget exists.
@@ -431,6 +448,10 @@ class TclTkIp
: slave interpreter, same to the TclTkLib module method with
: the same name.
+ encoding_table
+ : For Ruby m17n. Return encoding relation table between Ruby's
+ : Encoding object and Tcl's encoding name.
+
class TkCallbackBreak < StandardError
class TkCallbackContinue < StandardError
: They are exception classes to break or continue the Tk callback
@@ -441,5 +462,8 @@ class TkCallbackContinue < StandardError
: If raise TkCallbackContinue, returns 'continue' code (Then the Tk
: interpreter will break the operateion for the current bindtag and
: starts the operation for the next buindtag for the current event).
+ : However, current tcltklib supports Ruby's 'break' and 'next' to
+ : get the same effect. That is, those classes are obsolete. Those
+ : exist for backward compatibility.
(eof)
diff --git a/ext/tk/MANUAL_tcltklib.eucj b/ext/tk/MANUAL_tcltklib.eucj
index 5dd36726ba..7df42997b4 100644
--- a/ext/tk/MANUAL_tcltklib.eucj
+++ b/ext/tk/MANUAL_tcltklib.eucj
@@ -221,7 +221,23 @@ require "tcltklib" ¤¹¤ë¤È, °Ê²¼¤Î¥â¥¸¥å¡¼¥ë, ¥¯¥é¥¹¤¬ÍøÍѲÄǽ¤Ç¤¹.
: ¤«¤éÃê½Ð¤µ¤ì¤ë¤Ï¤º¤Ç¤¢¤ë¤«¤é¡¤index_name °ú¿ô¤Ï nil ¤È
: ¤»¤Í¤Ð¤Ê¤é¤Ê¤¤¡¥
+ ¥â¥¸¥å¡¼¥ë TclTkLib::RELEASE_TYPE
+ : Tcl/Tk ¤Î¥ê¥ê¡¼¥¹¥¿¥¤¥×ÈÖ¹æ¤ÎÄêµÁ
+
+ Äê¿ô ALPHA
+ : ALPHA ¥ê¥ê¡¼¥¹
+
+ Äê¿ô BETA
+ : BETA ¥ê¥ê¡¼¥¹
+
+ Äê¿ô FINAL
+ : FINAL ¥ê¥ê¡¼¥¹
+
¥â¥¸¥å¡¼¥ë¥á¥½¥Ã¥É
+ get_version()
+ : Tcl/Tk ¤Î major, minor, release-type ÈÖ¹æ, release-type ̾,
+ : patchlevel ¤òÇÛÎó¤Ë¤·¤ÆÊÖ¤¹¡¥
+
mainloop(check_root = true)
: ¥¤¥Ù¥ó¥È¥ë¡¼¥×¤òµ¯Æ°¤¹¤ë¡¥check_root ¤¬ true ¤Ç¤¢¤ì¤Ð¡¤
: root widget ¤¬Â¸ºß¤¹¤ë¸Â¤ê¡¤¤³¤Î¥á¥½¥Ã¥É¤Ï½ªÎ»¤·¤Ê¤¤¡¥
@@ -543,6 +559,9 @@ require "tcltklib" ¤¹¤ë¤È, °Ê²¼¤Î¥â¥¸¥å¡¼¥ë, ¥¯¥é¥¹¤¬ÍøÍѲÄǽ¤Ç¤¹.
: ¥¹¥ì¡¼¥Ö IP ¤Î¾ì¹ç¤Ë¤ÏÃͤÎÀßÄ꤬µö¤µ¤ì¤Ê¤¤ (̵»ë¤µ¤ì¤ë)¡¥
: ¤½¤ì°Ê³°¤ÎÅÀ¤Ç¤Ï°ú¿ô¤ò´Þ¤á¤Æ TclTkLib ¤ÎƱ̾¥á¥½¥Ã¥É¤ËƱ¤¸¡¥
+ encoding_table
+ : Ruby m17n ÍÑ¤Ë Ruby ¤È Tk ¤È¤Î´Ö¤Î encoding Âбþɽ¤òÊÖ¤¹¡¥
+
¥¯¥é¥¹ TkCallbackBreak < StandardError
¥¯¥é¥¹ TkCallbackContinue < StandardError
: ¤³¤ì¤é¤Ï¥¤¥Ù¥ó¥È¥³¡¼¥ë¥Ð¥Ã¥¯¤Ë¤ª¤¤¤Æ¡¤¥³¡¼¥ë¥Ð¥Ã¥¯½èÍý¤òŬÀÚ¤ËÃæ
@@ -553,5 +572,8 @@ require "tcltklib" ¤¹¤ë¤È, °Ê²¼¤Î¥â¥¸¥å¡¼¥ë, ¥¯¥é¥¹¤¬ÍøÍѲÄǽ¤Ç¤¹.
: ¥É¤òÊÖ¤¹É¬Íפ¬¤¢¤ë¡¥Ruby ¤Î¼ê³¤­¤¬ÉáÄ̤ËÃͤòÊÖ¤¹¤Î¤Ç¤Ï¡¤¤½¤ì¤¬Éá
: Ä̤ÎÌá¤êÃͤǤ¢¤ë¤Î¤«Èݤ«¤ò¶èÊ̤¬¤Ç¤­¤Ê¤¤¤¿¤á¡¤Î㳰ȯÀ¸¤òÍøÍѤ·¤¿
: ¼ÂÁõ¤ò¹Ô¤Ã¤Æ¤¤¤ë¡¥
+ : ¤¿¤À¤·¸½ºß¤Ç¤Ï¡¤¥³¡¼¥ë¥Ð¥Ã¥¯¼ê³¤­¤ò Ruby ¤Î break, next ¤Ç½ªÎ»¤¹
+ : ¤ë¤³¤È¤ÇƱÅù¤Î·ë²Ì¤òÆÀ¤ë¤³¤È¤¬¤Ç¤­¤ë¤è¤¦¤Ë¤Ê¤Ã¤Æ¤¤¤ë¡¥¤½¤ì¤æ¤¨¡¤
+ : ¤³¤ì¤é¤ÏɬÍפʤ¤¤â¤Î¤Ç¤Ï¤¢¤ë¤¬¡¤¸ß´¹À­¤Î¤¿¤á¤Ë»Ä¤·¤Æ¤¢¤ë¡¥
(eof)
diff --git a/ext/tk/README.1st b/ext/tk/README.1st
index df6c819d26..fce5b0242b 100644
--- a/ext/tk/README.1st
+++ b/ext/tk/README.1st
@@ -1,7 +1,6 @@
If you want to use Ruby/Tk (tk.rb and so on), you must have tcltklib.so
-which is working correctly. If you fail to call 'require "tcltklib"',
-you may not have tcltklib.so. When you have some troubles on compiling
-tcltklib, please read README files on tcltklib.
+which is working correctly. When you have some troubles on compiling,
+please read README.tcltklib and README.ActiveTcl.
Even if there is a tcltklib.so on your Ruby library directry, it will not
work without Tcl/Tk libraries (e.g. libtcl8.4.so) on your environment.
You must also check that your Tcl/Tk is installed properly.
@@ -9,11 +8,9 @@ You must also check that your Tcl/Tk is installed properly.
--------------------------------------------
( the following is written in EUC-JP )
-Ruby/Tk (tk.rb ¤Ê¤É) ¤ò»È¤¤¤¿¤¤¾ì¹ç¤Ë¤Ï¡¤tcltklib.so ¤¬Àµ¤·¤¯Æ°¤¤¤Æ
-¤¤¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó¡¥¤â¤· 'require "tcltklib"' ¤Ë¼ºÇÔ¤¹¤ë¤è¤¦¤Ê¤é¡¤
-tcltklib.so ¤¬¥¤¥ó¥¹¥È¡¼¥ë¤µ¤ì¤Æ¤¤¤Ê¤¤¤Î¤«¤â¤·¤ì¤Þ¤»¤ó¡¥tcltklib ¤Î
-¥³¥ó¥Ñ¥¤¥ë»þ¤Ë²¿¤«ÌäÂ꤬À¸¤¸¤Æ¤¤¤ë¾ì¹ç¤Ï¡¤tcltklib ¤Î README ¥Õ¥¡¥¤¥ë
-¤ò¸«¤Æ¤¯¤À¤µ¤¤¡¥
+Ruby/Tk (tk.rb ¤Ê¤É) ¤ò»È¤¤¤¿¤¤¾ì¹ç¤Ë¤Ï¡¤tcltklib.so ¤¬Àµ¤·¤¯Æ°¤¤¤Æ¤¤¤Ê
+¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó¡¥¥³¥ó¥Ñ¥¤¥ë»þ¤Ë²¿¤«ÌäÂ꤬À¸¤¸¤¿¾ì¹ç¤Ï¡¤README.tcltklib
+¤ä README.ActiveTcl ¤ò¸«¤Æ¤¯¤À¤µ¤¤¡¥
¤¿¤È¤¨ Ruby ¤Î¥é¥¤¥Ö¥é¥ê¥Ç¥£¥ì¥¯¥È¥ê¤Ë tcltklib.so ¤¬Â¸ºß¤·¤Æ¤¤¤¿¤È¤·¤Æ
¤â¡¤¼Â¹Ô´Ä¶­¤Ë Tcl/Tk ¥é¥¤¥Ö¥é¥ê (libtcl8.4.so ¤Ê¤É) ¤¬¤Ê¤±¤ì¤Ðµ¡Ç½¤·¤Þ
¤»¤ó¡¥Tcl/Tk ¤¬Àµ¤·¤¯¥¤¥ó¥¹¥È¡¼¥ë¤µ¤ì¤Æ¤¤¤ë¤«¤â¥Á¥§¥Ã¥¯¤·¤Æ¤¯¤À¤µ¤¤¡¥
diff --git a/ext/tk/README.tcltklib b/ext/tk/README.tcltklib
index 5d1da48a45..8c6dd5178f 100644
--- a/ext/tk/README.tcltklib
+++ b/ext/tk/README.tcltklib
@@ -5,10 +5,14 @@ Tcl/Tk libraries or header files are installed but are not found, you can
give the information by arguments of the 'configure' script. Please give
some or all of the following options.
+ --with-tcltkversion=<version>
+ force version of Tcl/Tk libaray
+ (e.g. libtcl8.4g.so ==> --with-tcltkversion=8.4g)
+
--with-tcllib=<libname> (e.g. libtcl8.4.so ==> --with-tcllib=tcl8.4)
--with-tklib=<libname> (e.g. libtk8.4.so ==> --with-tklib=tk8.4)
- --enable-tcltk_stubs (if you force to enable stubs)
+ --enable-tcltk-stubs (if you force to enable stubs)
--with-tcl-dir=<path>
equal to "--with-tcl-include=<path>/include --with-tcl-lib=<path>/lib"
@@ -16,18 +20,18 @@ some or all of the following options.
--with-tk-dir=<path>
equal to "--with-tk-include=<path>/include --with-tk-lib=<path>/lib"
- --with-tcl-include=<dir> the directry containts 'tcl.h'
- --with-tk-include=<dir> the directry containts 'tk.h'
+ --with-tcl-include=<dir> the directry contains 'tcl.h'
+ --with-tk-include=<dir> the directry contains 'tk.h'
- --with-tcl-lib=<dir> the directry containts 'libtcl<version>.so'
- --with-tk-lib=<dir> the directry containts 'libtk<version>.so'
+ --with-tcl-lib=<dir> the directry contains 'libtcl<version>.so'
+ --with-tk-lib=<dir> the directry contains 'libtk<version>.so'
--enable-mac-tcltk-framework (MacOS X) use Tcl/Tk framework
(Obsolete. Please use '--enable-tcltk-framework'.)
--enable-tcltk-framework use Tcl/Tk framework
- --with-tcltk-framework=<dir> the directory containts Tcl/Tk framework;
+ --with-tcltk-framework=<dir> the directory contains Tcl/Tk framework;
"<dir>/Tcl.framework" and "<dir>/Tk.framework".
When this option is given, it is assumed that
--enable-tcltk-framework option is given also.
@@ -41,6 +45,15 @@ some or all of the following options.
(e.g. "/Library/Frameworks/Tk.framework/Headers")
+ --with-X11 / --without-X11 use / not use the X Window System
+
+ --with-X11-dir=<path>
+ equal to "--with-X11-include=<path>/include --with-X11-lib=<path>/lib"
+
+ --with-X11-include=<dir> the directry contais X11 header files
+ --with-X11-lib=<dir> the directry contais X11 libraries
+
+
If you forgot to give the options when do 'configure' on toplevel
directry of Ruby sources, please try something like as the followings.
diff --git a/ext/tk/config_list.in b/ext/tk/config_list.in
new file mode 100644
index 0000000000..143a7b5df6
--- /dev/null
+++ b/ext/tk/config_list.in
@@ -0,0 +1,41 @@
+##############################################
+# configure options for Ruby/Tk
+# release date: 2011-06-05
+##############################################
+with tk-old-extconf
+with ActiveTcl
+with tk-shlib-search-path
+enable tcltk-stubs
+with tcltkversion
+enable tcl-h-ver-check
+enable tk-h-ver-check
+with tcl-build-dir
+with tk-build-dir
+with tcl-config
+with tk-config
+with tclConfig-dir
+with tkConfig-dir
+with tclConfig-file
+with tkConfig-file
+with tcllib
+with tklib
+with tcl-dir
+with tk-dir
+with tcl-include
+with tk-include
+with tcl-lib
+with tk-lib
+enable mac-tcltk-framework
+enable tcltk-framework
+with tcltk-framework
+with tcl-framework-dir
+with tk-framework-dir
+with tcl-framework-header
+with tk-framework-header
+with X11
+with X11-dir
+with X11-include
+with X11-lib
+enable pthread
+enable tcl-thread
+enable space-on-tk-libpath
diff --git a/ext/tk/extconf.rb b/ext/tk/extconf.rb
index 8c8d833481..8035fa7b21 100644
--- a/ext/tk/extconf.rb
+++ b/ext/tk/extconf.rb
@@ -1,54 +1,1035 @@
+##############################################################
# extconf.rb for tcltklib
-
+# release date: 2010-07-30
+##############################################################
require 'mkmf'
-is_win32 = (/mswin32|mingw|cygwin|bccwin32/ =~ RUBY_PLATFORM)
-#is_macosx = (/darwin/ =~ RUBY_PLATFORM)
+TkLib_Config = {}
+TkLib_Config['search_versions'] =
+ # %w[8.9 8.8 8.7 8.6 8.5 8.4 8.3 8.2 8.1 8.0 7.6 4.2]
+ # %w[8.7 8.6 8.5 8.4 8.3 8.2 8.1 8.0]
+ %w[8.7 8.6 8.5 8.4 8.0] # to shorten search steps
+
+TkLib_Config['major_nums'] = '87'
+
+
+##############################################################
+# use old extconf.rb ?
+##############################################################
+if with_config('tk-old-extconf')
+ require File.join(File.dirname(__FILE__), 'old-extconf.rb')
+ exit
+end
+
+
+##############################################################
+# check configs
+##############################################################
+($cleanfiles ||= "") << 'config_list'
+config_list_file = 'config_list'
+config_list_file_source = File.join(File.dirname(__FILE__),'config_list.in')
+if !File.exist?(config_list_file) ||
+ File.ctime(config_list_file_source) > File.ctime(config_list_file)
+ old_config_list_file = config_list_file_source
+else
+ old_config_list_file = config_list_file
+end
+
+current_configs = {'with'=>{}, 'enable'=>{}}
+
+# setup keys by config_list.in
+IO.foreach(config_list_file_source){|line|
+ line.chomp!
+ line.lstrip!
+ next if line.empty? || line =~ /^\#/ #
+ mode, key, value = line.split(/\s+/, 3)
+ value ||= ""
+ current_configs[mode][key] = value rescue nil
+}
+
+# define current value of keys
+IO.foreach(old_config_list_file){|line|
+ line.chomp!
+ line.lstrip!
+ next if line.empty? || line =~ /^\#/ #
+ mode, key, value = line.split(/\s+/, 3)
+ value ||= ""
+ if current_configs[mode] && current_configs[mode].has_key?(key)
+ current_configs[mode][key] = value
+ end
+}
+
+update_flag = false
+current_configs['with'].each_key{|key|
+ if (value = with_config(key).to_s) != current_configs['with'][key]
+ update_flag = true
+ current_configs['with'][key] = value
+ end
+}
+current_configs['enable'].each_key{|key|
+ if (value = enable_config(key).to_s) != current_configs['enable'][key]
+ update_flag = true
+ current_configs['enable'][key] = value
+ end
+}
+
+# update current_configs
+if update_flag || !File.exist?(config_list_file)
+ open(config_list_file, 'w'){|fobj|
+ fobj.print("# values of current configure options (generated by extconf.rb)\n");
+ ['with', 'enable'].each{|mode|
+ current_configs[mode].each_key{|key|
+ fobj.print("#{mode} #{key} #{current_configs[mode][key]}\n")
+ }
+ }
+ }
+end
+
+if update_flag
+ puts "Configure options for Ruby/Tk may be updated."
+ puts "So, delete files which depend on old configs."
+ File.delete(*Dir.glob("*.#{CONFIG['DLEXT']}", File::FNM_CASEFOLD))
+ File.delete(*Dir.glob("*.#{$OBJEXT}", File::FNM_CASEFOLD))
+ File.delete('Makefile') rescue nil
+
+else
+ makefile = 'Makefile'
+ if File.exist?(makefile) &&
+ File.ctime(config_list_file) > File.ctime(makefile)
+ # no need to update Makefile
+ exit
+ end
+end
+
+
+##############################################################
+# fuctions
+##############################################################
+def is_win32?
+ /mswin|mingw|cygwin|bccwin/ =~ RUBY_PLATFORM
+end
+
+def is_macosx?
+ /darwin/ =~ RUBY_PLATFORM
+end
+
+def maybe_64bit?
+ /64|universal/ =~ RUBY_PLATFORM
+end
+
+def check_tcltk_version(version)
+ return [nil, nil] unless version.kind_of? String
+
+ tclver, tkver = version.split(',')
+ tclver = tclver.strip
+ return [tclver, tkver.strip] if tkver
+
+ dot = major = minor_dot = minor = plvl_dot = plvl = ext = nil
+ if tclver =~ /^(\d)(\.?)(\d)(\.?)(\d*)(.*)$/
+ major = $1; minor_dot = $2; minor = $3; plvl_dot = $4; plvl = $5; ext = $6
+ dot = ! minor_dot.empty?
+ if plvl_dot.empty? && ! plvl.empty?
+ minor << plvl
+ end
+ elsif tclver =~ /^(\d)(\.?)(\d?)(.*)$/
+ major = $1; minor_dot = $2; minor = $3; ext = $4
+ dot = ! minor_dot.empty?
+ else # unknown -> believe user
+ return [tclver, tkver]
+ end
+
+ # check Tcl7.6 / Tk4.2 ?
+ if major == "7" # Tcl7.6 ( not support Tclversion < 7.6 )
+ # Tk4.2
+ tkver = "4" + ((dot)? ".": "") + ((minor.empty)? "": "2") + ext
+ elsif major == "4" # Tk4.2 ( not support Tkversion < 4.2 )
+ # Tcl7.6
+ tkver = tclver
+ tclver = "7" + ((dot)? ".": "") + ((minor.empty)? "": "6") + ext
+ end
+
+ tkver = tclver unless tkver
+
+ [tclver, tkver]
+end
+
+def get_shlib_versions(major = 8, minor_max = 9, minor_min = 0, ext = "")
+ if tclcfg = TkLib_Config["tclConfig_info"]
+ major = tclcfg['TCL_MAJOR_VERSION'].to_i
+ minor_min = tclcfg['TCL_MINOR_VERSION'].to_i
+
+ elsif TkLib_Config["tcltkversion"]
+ tclver, tkver = TkLib_Config["tcltkversion"]
+ if tclver =~ /8\.?(\d)(.*)/
+ minor_min = $1.to_i
+ ext = $2
+ else
+ # unsupported version
+ return [""]
+ end
+ end
+
+ # if disable-stubs, version is fixed.
+ minor_max = minor_min unless TkLib_Config["tcltk-stubs"]
+
+ vers = []
+ minor_max.downto(minor_min){|minor|
+ vers << "#{major}.#{minor}#{ext}" unless ext.empty?
+ vers << "#{major}.#{minor}"
+ }
+
+ vers << ""
+end
+
+def get_shlib_path_head
+ path_head = []
+ path_dirs = []
+
+ if TkLib_Config["ActiveTcl"].kind_of?(String) # glob path
+ # path_head << TkLib_Config["ActiveTcl"]
+ path_head.concat Dir.glob(TkLib_Config["ActiveTcl"], File::FNM_CASEFOLD).sort.reverse
+ # path_dirs.concat Dir.glob(File.join(TkLib_Config["ActiveTcl"], 'lib'), File::FNM_CASEFOLD).sort.reverse
+ end
+
+ if CROSS_COMPILING
+ elsif is_win32?
+ if TkLib_Config["ActiveTcl"]
+ path_head.concat ["c:/ActiveTcl", "c:/Program Files/ActiveTcl",
+ "c:/Program Files (x86)/ActiveTcl"]
+ end
+ path_head.concat [
+ "c:/Tcl", "c:/Program Files/Tcl", "c:/Program Files (x86)/Tcl",
+ "/Tcl", "/Program Files/Tcl", "/Program Files (x86)/Tcl"
+ ]
+ path_head.uniq!
+ #path_head.each{|dir| path_dirs << dir.dup if File.directory? dir}
+ path_head.each{|dir| path_dirs << File.expand_path(dir) if File.directory? dir}
+
+ # for MinGW
+ ["/usr/local/lib64", "/usr/lib64", "/usr/local/lib", "/usr/lib"].each{|dir|
+ #path_dirs << dir if File.directory? dir
+ path_dirs << File.expand_path(dir) if File.directory? dir
+ }
+ path_dirs |= ENV['LIBRARY_PATH'].split(';').find_all{|dir| File.directory? dir}.map{|dir| File.expand_path(dir)} if ENV['LIBRARY_PATH']
+ path_dirs |= ENV['PATH'].split(';').find_all{|dir| File.directory? dir}.map{|dir| File.expand_path(dir)} if ENV['PATH']
-def find_framework(tcl_hdr, tk_hdr)
- if framework_dir = with_config("tcltk-framework")
- paths = [framework_dir]
else
- unless tcl_hdr || tk_hdr ||
- enable_config("tcltk-framework", false) ||
- enable_config("mac-tcltk-framework", false)
- return false
+ [
+ '/opt', '/pkg', '/share',
+ '/usr/local/opt', '/usr/local/pkg', '/usr/local/share', '/usr/local',
+ '/usr/opt', '/usr/pkg', '/usr/share', '/usr/contrib', '/usr'
+ ].each{|dir|
+ next unless File.directory?(dir)
+
+ path_dirs << "#{dir}/lib64" if maybe_64bit?
+ path_dirs << "#{dir}/lib"
+ path_dirs << "#{dir}" unless Dir.glob("#{dir}/lib*.*", File::FNM_CASEFOLD).empty?
+
+ dirnames = []
+ if TkLib_Config["ActiveTcl"]
+ dirnames.concat ["ActiveTcl"]
+ end
+ dirnames.concat ["TclTk","Tcl_Tk","Tcl-Tk"]
+
+ dirnames.each{|name|
+ path_dirs << "#{dir}/#{name}" if File.directory?("#{dir}/#{name}")
+ path_head << "#{dir}/#{name}" unless Dir.glob("#{dir}/#{name}[-89_]*", File::FNM_CASEFOLD).empty?
+ }
+ }
+ end
+
+ unless TkLib_Config["space-on-tk-libpath"]
+ path_head.delete_if{|path| path =~ / /}
+ path_dirs.delete_if{|path| path =~ / /}
+ end
+
+ [path_head, path_dirs]
+end
+
+def find_macosx_framework
+ use_framework = is_macosx? && TkLib_Config["ActiveTcl"]
+
+ use_framework ||= (tcl_hdr = with_config("tcl-framework-header"))
+ use_framework ||= (tk_hdr = with_config("tk-framework-header"))
+ tcl_hdr = nil unless tcl_hdr.kind_of? String
+ tk_hdr = nil unless tk_hdr.kind_of? String
+ TkLib_Config["tcl-framework-header"] = tcl_hdr
+ TkLib_Config["tk-framework-header"] = tk_hdr
+
+ use_framework ||= (tcl_dir = with_config("tcl-framework-dir"))
+ tcl_dir = nil unless tcl_dir.kind_of? String
+ if !tcl_dir && tcl_hdr
+ # e.g. /Library/Frameworks/Tcl.framework/Headers
+ # ==> /Library/Frameworks/Tcl.framework
+ tcl_dir = File.dirname(tcl_hdr.strip.chomp('/'))
+ end
+ TkLib_Config["tcl-framework-dir"] = tcl_dir
+
+ use_framework ||= (tk_dir = with_config("tk-framework-dir"))
+ tk_dir = nil unless tk_dir.kind_of? String
+ if !tk_dir && tk_hdr
+ # e.g. /Library/Frameworks/Tk.framework/Headers
+ # ==> /Library/Frameworks/Tk.framework
+ tk_dir = File.dirname(tk_hdr.strip.chomp('/'))
+ end
+ TkLib_Config["tk-framework-dir"] = tk_dir
+
+ if tcl_dir && !tk_dir
+ tk_dir = File.join(File.dirname(tcl_dir), 'Tk.framework')
+ TkLib_Config["tk-framework-dir"] = tk_dir
+ elsif !tcl_dir && tk_dir
+ tcl_dir = File.join(File.dirname(tk_dir), 'Tcl.framework')
+ TkLib_Config["tcl-framework-dir"] = tcl_dir
+ end
+ if tcl_dir && tk_dir
+ TkLib_Config["tcltk-framework"] = File.dirname(tcl_dir) unless TkLib_Config["tcltk-framework"]
+ return [tcl_dir, tk_dir]
+ end
+
+ # framework is disabled?
+ if with_config("tcltk-framework") == false ||
+ enable_config("tcltk-framework") == false
+ return false
+ end
+
+ use_framework ||= (framework_dir = with_config("tcltk-framework"))
+ if framework_dir.kind_of? String
+ TkLib_Config["tcltk-framework"] = framework_dir.strip.chomp('/')
+ return [File.join(TkLib_Config["tcltk-framework"], 'Tcl.framework'),
+ File.join(TkLib_Config["tcltk-framework"], 'Tk.framework')]
+ end
+
+ unless enable_config("tcltk-framework", use_framework) ||
+ enable_config("mac-tcltk-framework", use_framework)
+ TkLib_Config["tcltk-framework"] = false
+ return false
+ end
+
+ paths = [
+ #"~/Library/Frameworks",
+ "/Library/Frameworks",
+ "/Network/Library/Frameworks", "/System/Library/Frameworks"
+ ]
+ paths.reverse! unless TkLib_Config["ActiveTcl"] # system has higher priority
+
+ paths.map{|dir| dir.strip.chomp('/')}.each{|dir|
+ next unless File.directory?(tcldir = File.join(dir, "Tcl.framework"))
+ next unless File.directory?(tkdir = File.join(dir, "Tk.framework"))
+ TkLib_Config["tcltk-framework"] = dir
+ return [tcldir, tkdir]
+ }
+
+ nil
+end
+
+def collect_tcltk_defs(tcl_defs_str, tk_defs_str)
+ conflicts = [
+ 'PACKAGE_NAME', 'PACKAGE_TARNAME', 'PACKAGE_VERSION',
+ 'PACKAGE_STRING', 'PACKAGE_BUGREPORT'
+ ]
+
+ begin
+ # Ruby 1.9.x or later
+ arch_config_h = RbConfig.expand($arch_hdrdir + "/ruby/config.h")
+ if File.exist?(arch_config_h)
+ keys = []
+ IO.foreach(arch_config_h){|line|
+ if line =~ /^#define +([^ ]+)/
+ keys << $1
+ end
+ }
+ conflicts = keys
end
- paths = ["/Library/Frameworks", "/System/Library/Frameworks"]
+ rescue
+ # ignore, use default
+ end
+
+ if tcl_defs_str
+ tcl_defs = tcl_defs_str.split(/ ?-D/).map{|s|
+ s =~ /^([^=]+)(.*)$/
+ [$1, $2]
+ }
+ else
+ tcl_defs = []
end
- checking_for('Tcl/Tk Framework') {
- paths.find{|dir|
- dir.strip!
- dir.chomp!('/')
- (tcl_hdr || FileTest.directory?(dir + "/Tcl.framework/") ) &&
- (tk_hdr || FileTest.directory?(dir + "/Tk.framework/") )
+ if tk_defs_str
+ tk_defs = tk_defs_str.split(/ ?-D/).map{|s|
+ s =~ /^([^=]+)(.*)$/
+ [$1, $2]
}
+ else
+ tk_defs = []
+ end
+
+ defs = tcl_defs | tk_defs
+
+ defs.delete_if{|name,value|
+ conflicts.include?(name) ||
+ ( (vtcl = tcl_defs.assoc(name)) && (vtk = tk_defs.assoc(name)) &&
+ vtcl != vtk )
}
+
+ defs.map{|ary| s = ary.join(''); (s.strip.empty?)? "": "-D" << s}
end
-tcl_framework_header = with_config("tcl-framework-header")
-tk_framework_header = with_config("tk-framework-header")
+def parse_tclConfig(file)
+ # check tclConfig.sh/tkConfig.sh
+ tbl = Hash.new{|h,k| h[k] = ""}
+ return tbl unless file
+ IO.foreach(file){|line|
+ line.strip!
+ next if line !~ /^([^\#=][^=]*)=(['"]|)(.*)\2$/
+ key, val = $1, $3
+ tbl[key] = val.gsub(/\$\{([^}]+)\}/){|s|
+ subst = $1
+ (tbl[subst])? tbl[subst]: s
+ } rescue nil
+ }
+ tbl
+end
-tcltk_framework = find_framework(tcl_framework_header, tk_framework_header)
+def get_libpath(lib_flag, lib_spec)
+ # get libpath from {TCL,Tk}_LIB_FLAG and {TCL,Tk}_LIB_SPEC
+ lib_spec.gsub(/(#{lib_flag}|-L)/, "").strip
+end
-unless is_win32
- have_library("nsl", "t_open")
- have_library("socket", "socket")
- have_library("dl", "dlopen")
- have_library("m", "log")
+def get_tclConfig_dirs
+ config_dir = []
+
+ if CROSS_COMPILING
+ elsif is_win32?
+ if TkLib_Config["ActiveTcl"]
+ dirs = []
+ if TkLib_Config["ActiveTcl"].kind_of?(String)
+ dirs << File.join(TkLib_Config["ActiveTcl"], 'lib')
+ end
+ dirs.concat [
+ "c:/ActiveTcl*/lib", "c:/Tcl*/lib",
+ "c:/Program Files*/ActiveTcl*/lib", "c:/Program Files*/Tcl*/lib",
+ "/ActiveTcl*/lib", "/Tcl*/lib",
+ "/Program Files*/ActiveTcl*/lib", "/Program Files*/Tcl*/lib"
+ ]
+ else
+ dirs = [
+ "c:/Tcl*/lib", "c:/Program Files*/Tcl*/lib",
+ "/Tcl*/lib", "/Program Files*/Tcl*/lib"
+ ]
+ end
+ dirs = dirs.collect{|d| Dir.glob(d, File::FNM_CASEFOLD)}.flatten.uniq
+
+ dirs |= ENV['LIBRARY_PATH'].split(';') if ENV['LIBRARY_PATH']
+ dirs |= ENV['PATH'].split(';') if ENV['PATH']
+
+ exeext = RbConfig::CONFIG['EXEEXT']
+ ENV['PATH'].split(File::PATH_SEPARATOR).each{|dir|
+ dir.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
+ next if Dir.glob(File.join(dir, "{tclsh,wish}*#{exeext}"), File::FNM_CASEFOLD).empty?
+ dirs << File.expand_path(File.join(dir, '..', 'lib'))
+ dirs << dir
+ # dirs << File.expand_path(File.join(dir, '..'))
+ }
+
+ unless TkLib_Config["space-on-tk-libpath"]
+ dirs.delete_if{|path| path =~ / /}
+ end
+
+ config_dir.concat(dirs.zip(dirs))
+
+ else
+ if framework = find_macosx_framework()
+ config_dir.unshift(framework)
+ end
+
+ if activeTcl = TkLib_Config['ActiveTcl']
+ # check latest version at first
+ if is_macosx?
+ base = File.expand_path(activeTcl)
+ config_dir << [
+ File.join(base, 'Tcl.framework'), File.join(base, 'Tk.framework')
+ ]
+
+ config_dir << [
+ File.join(base, 'Tcl.framework', 'Versions', 'Current'),
+ File.join(base, 'Tk.framework', 'Versions', 'Current')
+ ]
+
+ Dir.glob(File.join(base, 'Tcl.framework',
+ 'Versions', '*')).sort.reverse.each{|dir|
+ next if dir =~ /Current/
+ config_dir << [dir, dir.gsub(/Tcl/, 'Tk')]
+ }
+ else
+ config_dir.concat(Dir.glob(File.join(activeTcl, 'lib'), File::FNM_CASEFOLD).sort.reverse)
+ end
+ end
+
+ config_dir << RbConfig::CONFIG['libdir']
+
+ ((maybe_64bit?)? ['lib64', 'lib']: ['lib']).each{|dir|
+ config_dir.concat [
+ File.join(RbConfig::CONFIG['exec_prefix'], dir),
+ File.join(RbConfig::CONFIG['prefix'], dir),
+ "/usr/local/opt/#{dir}", "/usr/local/pkg/#{dir}",
+ "/usr/local/share/#{dir}", "/usr/local/#{dir}",
+ "/usr/opt/#{dir}", "/usr/pkg/#{dir}", "/usr/share/#{dir}",
+ "/usr/contrib/#{dir}", "/usr/#{dir}"
+ ]
+ }
+
+ config_dir.concat [
+ '/opt', '/pkg', '/share',
+ '/usr/local/opt', '/usr/local/pkg', '/usr/local/share', '/usr/local',
+ '/usr/opt', '/usr/pkg', '/usr/share', '/usr/contrib', '/usr'
+ ].map{|dir|
+ Dir.glob(dir + "/{tcltk,tcl,tk}[#{TkLib_Config['major_nums']}*/lib",
+ File::FNM_CASEFOLD)
+ Dir.glob(dir + "/{tcltk,tcl,tk}[#{TkLib_Config['major_nums']}*",
+ File::FNM_CASEFOLD)
+ Dir.glob(dir + '/{tcltk,tcl,tk}/lib', File::FNM_CASEFOLD)
+ Dir.glob(dir + '/{tcltk,tcl,tk}', File::FNM_CASEFOLD)
+ }.flatten!
+
+ exeext = RbConfig::CONFIG['EXEEXT']
+ ENV['PATH'].split(File::PATH_SEPARATOR).each{|dir|
+ dir.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
+ next if Dir.glob(File.join(dir, "{tclsh,wish}*#{exeext}"), File::FNM_CASEFOLD).empty?
+ config_dir << File.expand_path(File.join(dir, '..', 'lib'))
+ }
+
+ # for MacOS X
+ paths = [
+ #"~/Library/Tcl",
+ "/Library/Tcl", "/Network/Library/Tcl", "/System/Library/Tcl"
+ ]
+ paths.reverse! unless TkLib_Config["ActiveTcl"]
+
+ paths.each{|path|
+ config_dir << path
+ config_dir.concat(Dir.glob(File.join(path, '{tcl,tk}*'), File::FNM_CASEFOLD).sort.reverse.find_all{|d| File.directory?(d)})
+ }
+
+ paths = [
+ #"~/Library/Frameworks",
+ "/Library/Frameworks",
+ "/Network/Library/Frameworks", "/System/Library/Frameworks"
+ ]
+ paths.reverse! unless TkLib_Config["ActiveTcl"]
+
+ paths.each{|frmwk|
+ base = File.expand_path(frmwk)
+ config_dir << [
+ File.join(base, 'Tcl.framework'), File.join(base, 'Tk.framework')
+ ]
+
+ config_dir << [
+ File.join(base, 'Tcl.framework', 'Versions', 'Current'),
+ File.join(base, 'Tk.framework', 'Versions', 'Current')
+ ]
+
+ Dir.glob(File.join(base, 'Tcl.framework',
+ 'Versions', '*')).sort.reverse.each{|dir|
+ next if dir =~ /Current/
+ config_dir << [dir, dir.gsub(/Tcl/, 'Tk')]
+ }
+ }
+ end
+
+ config_dir
end
-dir_config("tk")
-dir_config("tcl")
-dir_config("X11")
+def get_ext_list()
+ exts = [CONFIG['DLEXT']]
+ exts.concat %w(dll lib) if is_win32?
+ exts.concat %w(bundle dylib) if is_macosx? || /nextstep|openstep|rhapsody/ =~ RUBY_PLATFORM
-tklib = with_config("tklib")
-tcllib = with_config("tcllib")
-stubs = enable_config("tcltk_stubs") || with_config("tcltk_stubs")
+ if enable_config("shared") == false
+ [CONFIG['LIBEXT'], "a"].concat exts
+ else
+ exts.concat [CONFIG['LIBEXT'], "a"]
+ end
+
+ if is_win32?
+ exts.map!{|ext| [ext.downcase, ext.upcase]}.flatten!
+ end
+
+ exts
+end
+
+def libcheck_for_tclConfig(tcldir, tkdir, tclconf, tkconf)
+ tcllib_ok = tklib_ok = false
+
+ if TkLib_Config["tcltk-stubs"]
+ stub = "stub"
+ tclfunc = "Tcl_InitStubs"
+ tkfunc = "Tk_InitStubs"
+ else
+ stub = ""
+ tclfunc = "Tcl_FindExecutable"
+ tkfunc = "Tk_Init"
+ end
+
+ incflags = ($INCFLAGS ||= "").dup
+ libpath = ($LIBPATH ||= []).dup
+ libs_param = ($libs ||= "").dup
+ tcllibs = nil
+ mkmf_param = nil
+
+ tclver, tkver = TkLib_Config["tcltkversion"]
+ exts = "(" + get_ext_list.join('|') + ")"
+
+ if tclver
+ tcl_glob = "*tcl#{stub}#{tclver}.*"
+ tcl_regexp = /^.*(tcl#{stub}#{tclver}.*)\.(#{exts}).*$/
+ elsif tclconf
+ tcl_glob = "*tcl#{stub}#{tclconf['TCL_MAJOR_VERSION']}{.,}#{tclconf['TCL_MINOR_VERSION']}*.*"
+ tcl_regexp = /^.*(tcl#{stub}#{tclconf['TCL_MAJOR_VERSION']}(?:\.|)#{tclconf['TCL_MINOR_VERSION']}.*)\.(#{exts}).*$/
+ end
+ if tkver
+ tk_glob = "*tk#{stub}#{tkver}.*"
+ tk_regexp = /^.*(tk#{stub}#{tkver}.*)\.(#{exts}).*$/
+ elsif tkconf
+ tk_glob = "*tk#{stub}#{tkconf['TK_MAJOR_VERSION']}{.,}#{tkconf['TK_MINOR_VERSION']}*.*"
+ tk_regexp = /^.*(tk#{stub}#{tkconf['TK_MAJOR_VERSION']}(?:\.|)#{tkconf['TK_MINOR_VERSION']}.*)\.#{exts}.*$/
+ end
+
+ tcllib_ok ||= !tclconf || Dir.glob(File.join(tcldir, tcl_glob), File::FNM_CASEFOLD).find{|file|
+ if file =~ tcl_regexp
+ libname = $1
+ ext = $2.downcase
+ begin
+ $INCFLAGS = incflags.dup << " " << tclconf["TCL_INCLUDE_SPEC"]
+ #puts "check #{file} #{$1} #{tclfunc} #{tcldir}"
+ #find_library($1, tclfunc, tcldir)
+ if (tclconf && tclconf["TCL_SHARED_BUILD"] == "0") ||
+ (ext != CONFIG['DLEXT'] && ext == CONFIG['LIBEXT']) || ext == "a"
+ # static link
+ tcllibs = $libs + " -DSTATIC_BUILD " + file.quote
+
+ # FIX ME: avoid pathname trouble (fail to find) on MinGW.
+ # e.g. TCL_INCLUDE_SPEC describes "-I/usr/local/include",
+ # but compiler can find "-IC:/msys/1.0/local/include" only.
+ $INCFLAGS << " -I" << File.join(File.dirname(File.dirname(file)),"include") if is_win32?
+ else
+ tcllibs = append_library($libs, libname)
+ tcllibs = "-L#{tcldir.quote} -Wl,-R#{tcldir.quote} " + tcllibs
+
+ # FIX ME: avoid pathname trouble (fail to find) on MinGW.
+ $INCFLAGS << " -I" << File.join(File.dirname(tcldir),"include") if is_win32?
+ end
+
+ $LIBPATH = libpath | [tcldir]
+ try_func(tclfunc, tcllibs, ["tcl.h"]) ||
+ ( try_func(tclfunc, tcllibs << " " << tclconf['TCL_LIBS'], ["tcl.h"]) if tclconf['TCL_LIBS'] )
+
+ ensure
+ mkmf_param = {
+ 'PATH' => file,
+ 'LIBNAME' => libname,
+ 'libs' => tcllibs.dup,
+ 'INCFLAGS' => $INCFLAGS.dup,
+ 'LIBPATH' => $LIBPATH.dup,
+ }
+ $LIBPATH = libpath.dup
+ $libs = libs_param.dup
+ end
+ end
+ }
+ tclconf['MKMF_PARAMS'] = mkmf_param if tclconf && tcllib_ok
+
+ tklib_ok ||= !tkconf || Dir.glob(File.join(tkdir, tk_glob), File::FNM_CASEFOLD).find{|file|
+ if file =~ tk_regexp
+ libname = $1
+ ext = $2.downcase
+ begin
+ #puts "check #{file} #{$1} #{tkfunc} #{tkdir}"
+ # find_library($1, tkfunc, tkdir)
+ if (tkconf && tkconf["TCL_SHARED_BUILD"] == "0") ||
+ (ext != CONFIG['DLEXT'] && ext == CONFIG['LIBEXT']) || ext == "a"
+ # static link
+ tklibs = " -DSTATIC_BUILD " + file.quote
+
+ # FIX ME: avoid pathname trouble (fail to find) on MinGW.
+ $INCFLAGS << " -I" << File.join(File.dirname(File.dirname(file)),"include") if is_win32?
+ else
+ tklibs = append_library("", libname)
+ #tklibs = append_library("", $1)
+ tklibs = "-L#{tkdir.quote} -Wl,-R#{tkdir.quote} " + tklibs
+
+ # FIX ME: avoid pathname trouble (fail to find) on MinGW.
+ $INCFLAGS << " -I" << File.join(File.dirname(tcldir),"include") if is_win32?
+ end
+
+ tklibs << " " << tcllibs if tcllibs
+ tmp_tklibs = tklibs.dup
+ $LIBPATH = libpath | [tkdir]
+ try_func(tkfunc, tklibs, ["tcl.h", "tk.h"]) ||
+ ( try_func(tkfunc, tklibs << " " << tkconf['TK_LIBS'], ["tcl.h", "tk.h"]) if tkconf['TK_LIBS'] ) ||
+ ( try_func(tkfunc, (tklibs = tmp_tklibs.dup) << " " << tkconf['TK_XLIBSW'], ["tcl.h", "tk.h"]) if tkconf['TK_XLIBSW'] ) ||
+ ( try_func(tkfunc, tklibs << " " << tkconf['TK_LIBS'], ["tcl.h", "tk.h"]) if tkconf['TK_LIBS'] )
+
+ ensure
+ mkmf_param = {
+ 'PATH' => file,
+ 'LIBNAME' => libname,
+ 'libs' => tklibs.dup,
+ 'INCFLAGS' => $INCFLAGS.dup,
+ 'LIBPATH' => $LIBPATH.dup,
+ }
+ $LIBPATH = libpath.dup
+ $libs = libs_param.dup
+ end
+ end
+ }
+
+ $INCFLAGS = incflags.dup
+ tkconf['MKMF_PARAMS'] = mkmf_param if tkconf && tklib_ok
+
+ [tcllib_ok, tklib_ok]
+end
+
+def search_tclConfig(*paths) # libdir list or [tcl-libdir|file, tk-libdir|file]
+ TkLib_Config["tclConfig_paths"] = []
+
+ paths.compact!
+ if paths.empty?
+ config_dir = get_tclConfig_dirs
+ elsif paths.length == 1 && !paths[0][0] && !paths[0][1]
+ config_dir = get_tclConfig_dirs.map{|dir|
+ if dir.kind_of? Array
+ [ (paths[0][0] == false)? nil: dir[0],
+ (paths[0][1] == false)? nil: dir[1] ]
+ else
+ [ (paths[0][0] == false)? nil: dir,
+ (paths[0][1] == false)? nil: dir ]
+ end
+ }
+ else
+ # fixed tclConfig
+ config_dir = []
+ paths.each{|path|
+ if path.kind_of?(Array)
+ config_dir << path
+ else
+ dirs = Dir.glob(path, File::FNM_CASEFOLD)
+ config_dir.concat(dirs.zip(dirs))
+ end
+ }
+ end
+
+ tclver, tkver = TkLib_Config['tcltkversion']
+ if tclver && tclver =~ /^\D*(\d)\.?(\d)?/ # ignore PATCH_LEVEL
+ tclver_major = $1
+ tclver_minor = $2
+ else
+ tclver_major = nil
+ tclver_minor = nil
+ end
+ if tkver && tkver =~ /^\D*(\d)\.?(\d)?/ # ignore PATCH_LEVEL
+ tkver_major = $1
+ tkver_minor = $2
+ else
+ tkver_major = nil
+ tkver_minor = nil
+ end
+
+ conf = nil
+
+ config_dir.uniq!
+ config_dir.map{|dir|
+ if dir.kind_of? Array
+ [ (dir[0])? dir[0].strip.chomp('/'): nil,
+ (dir[1])? dir[1].strip.chomp('/'): nil ]
+ else
+ dir.strip.chomp('/')
+ end
+ }.each{|dir|
+ print(".") # progress
+ # print("check #{dir} ==>");
+ if dir.kind_of? Array
+ tcldir, tkdir = dir
+ else
+ tcldir = tkdir = dir
+ end
+
+ tails = ['Config-shared.sh', 'config-shared.sh', 'Config.sh', 'config.sh']
+
+ if tcldir
+ if File.file?(tcldir)
+ tclcfg_files = [tcldir] * tails.length
+ else
+ tclcfg_files = tails.map{|f| File.join(tcldir, 'tcl' << f)}
+ end
+ else
+ tclcfg_files = [nil] * tails.length
+ end
+
+ if tkdir
+ if File.file?(tkdir)
+ tkcfg_files = [tkdir] * tails.length
+ else
+ tkcfg_files = tails.map{|f| File.join(tkdir, 'tk' << f)}
+ end
+ else
+ tkcfg_files = [nil] * tails.length
+ end
+
+ tclcfg_files.zip(tkcfg_files).map{|tclpath, tkpath|
+ [ (tclpath && File.exist?(tclpath))? File.expand_path(tclpath): tclpath,
+ (tkpath && File.exist?(tkpath))? File.expand_path(tkpath): tkpath ]
+ }.uniq.each{|tclpath, tkpath|
+ next if tclpath && !File.exist?(tclpath)
+ next if tkpath && !File.exist?(tkpath)
+
+ # parse tclConfig.sh/tkConfig.sh
+ tclconf = (tclpath)? parse_tclConfig(tclpath): nil
+ next if tclconf && tclver && ((tclver_major && tclver_major != tclconf['TCL_MAJOR_VERSION']) || (tclver_minor && tclver_minor != tclconf['TCL_MINOR_VERSION']))
+
+ tkconf = (tkpath)? parse_tclConfig(tkpath): nil
+ next if tkconf && tkver && ((tkver_major && tkver_major != tkconf['TK_MAJOR_VERSION']) || (tkver_minor && tkver_minor != tkconf['TK_MINOR_VERSION']))
+
+ # nativethread check
+ if !TkLib_Config["ruby_with_thread"]
+ if tclconf
+ if tclconf['TCL_THREADS'] == '1'
+ puts "\nWARNING: found #{tclpath.inspect}, but it WITH nativethread-support under ruby WITHOUT nativethread-support. So, ignore it."
+ TkLib_Config["tcl-NG-path"] << File.dirname(tclpath)
+ next
+ end
+ else
+ puts "\nWARNING: When not refer tclConfig.sh, cannot check native-thread support on Tcl/Tk libraries. Ruby, which is used now, does NOT support native-thread. So, if Tcl/Tk libraries support native-thread, it will NOT work properly."
+ end
+ end
+
+ # find tclConfig.sh & tkConfig.sh
+ conf = [tclconf, tkconf] unless conf
+
+ # check Tcl library
+ if is_macosx? && TkLib_Config["tcltk-framework"]
+ # if use framework, not check (believe it is installed properly)
+ tcllib_ok = tklib_ok = true
+ else
+ tcllib_ok, tklib_ok =
+ libcheck_for_tclConfig((tclpath)? File.dirname(tclpath): nil,
+ (tkpath)? File.dirname(tkpath): nil,
+ tclconf, tkconf)
+ end
+
+ unless tcllib_ok && tklib_ok
+ unless tcllib_ok
+ puts "\nWARNING: found #{tclpath.inspect}, but cannot find valid Tcl library for the tclConfig.sh. So, ignore it."
+ TkLib_Config["tcl-NG-path"] << File.dirname(tclpath)
+ end
+ unless tklib_ok
+ puts "\nWARNING: found #{tkpath.inspect}, but cannot find valid Tk library for the tkConfig.sh. So, ignore it."
+ TkLib_Config["tk-NG-path"] << File.dirname(tkpath)
+ end
+ next
+ end
+
+ #return [tclpath, tkpath]
+ # print(" #{[tclpath, tkpath].inspect}");
+ TkLib_Config["tclConfig_paths"] << [tclpath, tkpath]
+ }
+
+ # print("\n");
+ }
+
+ if is_macosx? && TkLib_Config["tcltk-stubs"]
+ CONFIG['LDSHARED'] << " -Xlinker -bind_at_load"
+ if config_string('LDSHAREDXX')
+ config_string('LDSHAREDXX') << " -Xlinker -bind_at_load"
+ end
+ end
+
+ if TkLib_Config["tclConfig_paths"].empty?
+ [nil, nil]
+ else
+ # find tclConfig.sh and tkConfig.sh
+ TkLib_Config["tclConfig_info"], TkLib_Config["tkConfig_info"] = conf
+ TkLib_Config["tclConfig_paths"][0]
+ end
+end
+
+def get_tclConfig(tclConfig_file, tkConfig_file, tclConfig_dir, tkConfig_dir)
+ use_tclConfig = tclConfig_file != false && tclConfig_dir != false
+ use_tkConfig = tkConfig_file != false && tkConfig_dir != false
+
+ unless use_tclConfig || use_tkConfig
+ puts("Don't use [tclConfig.sh, tkConfig.sh]")
+ return [nil, nil]
+ end
+
+ tclConfig_file = nil unless tclConfig_file.kind_of? String
+ tkConfig_file = nil unless tkConfig_file.kind_of? String
+ tclConfig_dir = nil unless tclConfig_dir.kind_of? String
+ tkConfig_dir = nil unless tkConfig_dir.kind_of? String
+
+ if use_tclConfig && !tclConfig_dir
+ if tclConfig_file
+ tclConfig_dir = File.dirname(tclConfig_file)
+ elsif tkConfig_dir
+ tclConfig_dir = tkConfig_dir
+ end
+ end
+ if use_tkConfig && !tkConfig_dir
+ if tkConfig_file
+ tkConfig_dir = File.dirname(tkConfig_file)
+ elsif tclConfig_dir
+ tkConfig_dir = tclConfig_dir
+ end
+ end
+ tkConfig_dir ||= tclConfig_dir
+
+ if use_tclConfig
+ TkLib_Config["tclConfig-file"] = tclConfig_file
+ TkLib_Config["tclConfig-dir"] = tclConfig_dir
+ else
+ tclConfig_file = false
+ tclConfig_dir = false
+ end
+ if use_tkConfig
+ TkLib_Config["tkConfig-file"] = tkConfig_file
+ TkLib_Config["tkConfig-dir"] = tkConfig_dir
+ else
+ tkConfig_file = false
+ tkConfig_dir = false
+ end
+
+ print ("Don't use tclConfig.sh (specified by configure option).\n") unless use_tclConfig
+ print ("Don't use tkConfig.sh (specified by configure option).\n") unless use_tkConfig
+ print("Search ")
+ print("tclConfig.sh", (tclConfig_dir)? " (in #{tclConfig_dir})": "") if use_tclConfig
+ print((use_tclConfig)? " and ": "", "tkConfig.sh", (tkConfig_dir)? " (in #{tkConfig_dir})": "") if use_tkConfig
+ print(".")
+
+ if tclConfig_dir || tkConfig_dir || !use_tclConfig || !use_tkConfig
+ tclConfig, tkConfig =
+ search_tclConfig([ ((tclConfig_file)? tclConfig_file: tclConfig_dir),
+ ((tkConfig_file)? tkConfig_file: tkConfig_dir) ])
+ else
+ tclConfig, tkConfig = search_tclConfig()
+ end
+ print("\n")
+ # TclConfig_Info = TkLib_Config["tclConfig_info"]
+ # TkConfig_Info = TkLib_Config["tkConfig_info"]
+
+ if tclConfig || tkConfig
+ dirs = TkLib_Config["tclConfig_paths"].map{|tclpath, tkpath|
+ [ (tclpath)? File.dirname(tclpath): nil,
+ (tkpath)? File.dirname(tkpath): nil ]
+ }
+ dirs |= dirs
+ puts("Valid [tclConfig.sh, tkConfig.sh] are found in #{dirs.inspect}")
+ puts("Use [tclConfig.sh, tkConfig.sh] == #{[tclConfig, tkConfig].inspect}")
+ $LIBPATH ||= []
+ $LIBPATH |= [File.dirname(tclConfig)] if tclConfig
+ $LIBPATH |= [File.dirname(tkConfig)] if tkConfig
+ #TkLib_Config["tclConfig_paths"].each{|tclcfg, tkcfg|
+ # $LIBPATH |= [File.dirname(tclcfg)] | [File.dirname(tkcfg)]
+ #}
+ else
+ puts("Fail to find [tclConfig.sh, tkConfig.sh]")
+ end
+
+ [tclConfig, tkConfig]
+end
+
+def check_tcl_NG_path(path_list)
+ path_list.find_all{|path| not TkLib_Config["tcl-NG-path"].include?(path) }
+end
+
+def check_tk_NG_path(path_list)
+ path_list.find_all{|path| not TkLib_Config["tk-NG-path"].include?(path) }
+end
+
+def check_NG_path(path_list)
+ path_list.find_all{|path|
+ not (TkLib_Config["tcl-NG-path"].include?(path) &&
+ TkLib_Config["tk-NG-path"].include?(path))
+ }
+end
+
+def check_shlib_search_path(paths)
+ if !paths || paths.empty?
+ path_list = []
+
+ #if TkLib_Config["ActiveTcl"]
+ # path_list.concat Dir.glob(TkLib_Config["ActiveTcl"], File::FNM_CASEFOLD).sort.reverse
+ #end
+ if TkLib_Config["ActiveTcl"].kind_of?(String) # glob path
+ path_list.concat Dir.glob(TkLib_Config["ActiveTcl"], File::FNM_CASEFOLD).sort.reverse
+ end
+
+ vers = get_shlib_versions
+ path_head, path_dirs = get_shlib_path_head
+
+ path_list.concat vers.map{|ver|
+ path_head.map{|head|
+ if ver.empty?
+ head + "/lib"
+ else
+ dirs = []
+
+ if Dir.glob(head, File::FNM_CASEFOLD).find{|dir| dir == head}
+ dirs << head + "/lib"
+ end
+
+ if !Dir.glob(head + "-*", File::FNM_CASEFOLD).empty?
+ dirs << head + "-#{ver}/lib" if !Dir.glob(head + "-[89].*", File::FNM_CASEFOLD).empty?
+ dirs << head + "-#{ver.delete('.')}/lib" if !Dir.glob(head + "-[89][0-9]*", File::FNM_CASEFOLD).empty?
+ end
+
+ if !Dir.glob(head + "[_-]*", File::FNM_CASEFOLD).empty?
+ dirs << head + "_#{ver}/lib" if !Dir.glob(head + "_[89].*", File::FNM_CASEFOLD).empty?
+ dirs << head + "-#{ver}/lib" if !Dir.glob(head + "-[89].*", File::FNM_CASEFOLD).empty?
+ dirs << head + "_#{ver.delete('.')}/lib" if !Dir.glob(head + "_[89][0-9]*", File::FNM_CASEFOLD).empty?
+ dirs << head + "-#{ver.delete('.')}/lib" if !Dir.glob(head + "-[89][0-9]*", File::FNM_CASEFOLD).empty?
+ end
+
+ dirs
+ end
+ }
+ }.flatten!
+
+ path_list.concat path_dirs
+
+ else
+ # paths is a string with PATH environment style
+ path_list = paths.split((is_win32?)? ';': ':')
+ end
+
+ path_list = check_NG_path(path_list)
+ path_list.map!{|path| path.strip}
+
+ if !CROSS_COMPILING and (is_win32? || is_macosx?)
+ # exist-dir only
+ path_list.delete_if{|path| Dir.glob(File.join(path, "*.{a,so,dll,lib}")).empty?}
+ end
+
+ # keep paths for searching dynamic libs
+ #$LIBPATH |= path_list
+ path_list.uniq
+end
+
+def search_vers_on_path(vers, path, *heads)
+ exts = get_ext_list.join(',')
+ files = Dir.glob(File.join(path, "*{#{heads.join(',')}}*.{#{exts}}"), File::FNM_CASEFOLD)
+ vers.find_all{|ver| files.find{|f| f =~ /(#{ver}|#{ver.delete('.')})/} }
+end
+
+def find_tcl(tcllib, stubs, version, *opt_paths)
+ if TclConfig_Info['MKMF_PARAMS']
+ # already checked existence of tcl library based on tclConfig.sh
+ ($INCFLAGS ||= "") << " " << TclConfig_Info['MKMF_PARAMS']['INCFLAGS']
+ $LIBPATH ||= []; $LIBPATH |= TclConfig_Info['MKMF_PARAMS']['LIBPATH']
+ ($libs ||= "") << " " << TclConfig_Info['MKMF_PARAMS']['libs']
+ return [true, nil, nil, nil]
+ end
+ # else, no available tclConfig.sh on the system
+
+ print "Search Tcl library"
-def find_tcl(tcllib, stubs)
- paths = ["/usr/local/lib", "/usr/pkg/lib", "/usr/lib"]
if stubs
func = "Tcl_InitStubs"
lib = "tclstub"
@@ -56,22 +1037,143 @@ def find_tcl(tcllib, stubs)
func = "Tcl_FindExecutable"
lib = "tcl"
end
- if tcllib
- find_library(tcllib, func, *paths)
- elsif find_library(lib, func, *paths)
- true
+
+ if version && ! version.empty?
+ versions = [version]
else
- %w[8.5 8.4 8.3 8.2 8.1 8.0 7.6].find { |ver|
- find_library("#{lib}#{ver}", func, *paths) or
- find_library("#{lib}#{ver.delete('.')}", func, *paths) or
- find_library("tcl#{ver}", func, *paths) or
- find_library("tcl#{ver.delete('.')}", func, *paths)
+ versions = TkLib_Config['search_versions']
+ end
+
+ default_paths = []
+
+ default_paths.concat [
+ RbConfig::CONFIG['libdir'],
+ File.join(RbConfig::CONFIG['exec_prefix'], 'lib'),
+ File.join(RbConfig::CONFIG['prefix'], 'lib'),
+ "/usr/local/lib", "/usr/pkg/lib", "/usr/contrib/lib", "/usr/lib"
+ ].find_all{|dir| File.directory?(dir)} unless CROSS_COMPILING
+
+ if TkLib_Config["ActiveTcl"].kind_of?(String) # glob path
+ default_paths.concat Dir.glob(TkLib_Config["ActiveTcl"]).sort.reverse.map{|d| d << "/lib"}
+ end
+
+ if !CROSS_COMPILING and is_win32?
+ default_paths.concat [
+ "c:/Tcl/lib","c:/Program Files/Tcl/lib","c:/Program Files (x86)/Tcl/lib",
+ "/Tcl/lib","/Program Files/Tcl/lib","/Program Files (x86)/Tcl/lib"
+ ].find_all{|dir| File.directory?(dir)}.map{|dir| File.expand_path(dir)}
+
+ # for MinGW
+ ["/usr/local/lib64", "/usr/lib64", "/usr/local/lib", "/usr/lib"].each{|dir|
+ default_paths << File.expand_path(dir) if File.directory? dir
}
+
+ default_paths |= ENV['LIBRARY_PATH'].split(';').find_all{|dir| File.directory? dir}.map{|dir| File.expand_path(dir)} if ENV['LIBRARY_PATH']
+ default_paths |= ENV['PATH'].split(';').find_all{|dir| File.directory? dir}.map{|dir| File.expand_path(dir)} if ENV['PATH']
+ end
+
+ default_paths |= TkLib_Config["checked_shlib_dirs"]
+
+ unless TkLib_Config["space-on-tk-libpath"]
+ default_paths.delete_if{|path| path =~ / /}
end
+
+ if (paths = opt_paths.compact).empty?
+ paths = check_tcl_NG_path(default_paths)
+ end
+
+ incflags = ($INCFLAGS ||= "").dup
+ libpath = ($LIBPATH ||= []).dup
+ libs_param = ($libs ||= "").dup
+ tcllibs = nil
+
+ exts = "(" + get_ext_list.join('|') + ")"
+
+ paths.map{|path|
+ lib_w_sufx = lib
+ begin
+ $LIBPATH |= [path]
+ inc = [File.join(File.dirname(path),"include"), File.dirname(path)]
+ inc.each{|f| $INCFLAGS << " -I" << f }
+
+ if tcllib
+ print(".")
+ if have_library(tcllib, func, ["tcl.h"])
+ return [true, path, lib_w_sufx, nil, *inc]
+ end
+ else
+ sufx_list = ['', 't', 'g', 's', 'x']
+ search_vers_on_path(versions, path, lib, 'tcl').find{|ver|
+ dir_enum = Dir.foreach(path)
+ no_dot_ver = ver.delete('.')
+ libnames = ["#{lib}#{ver}", "#{lib}#{no_dot_ver}"]
+ libnames << "tcl#{ver}" << "tcl#{no_dot_ver}" if lib != "tcl"
+ libnames.find{|libname|
+ sufx_list.find{|sufx|
+ print(".")
+ dir_enum.map{|fname|
+ if fname =~ /^.*(#{libname}.*#{sufx})\.(#{exts}).*$/
+ [fname, $1, $2]
+ end
+ }.compact.find{|fname, lib_w_sufx, ext|
+ ext.downcase!
+ if (ext != CONFIG['DLEXT'] && ext == CONFIG['LIBEXT']) ||
+ ext == "a"
+ # static link
+ tcllibs = libs_param + " -DSTATIC_BUILD " + fname.quote
+ else
+ tcllibs = append_library($libs, lib_w_sufx)
+ tcllibs = "-L#{path.quote} -Wl,-R#{path.quote} " + tcllibs
+ end
+ if try_func(func, tcllibs, ["tcl.h"])
+ return [true, path, nil, tcllibs, *inc]
+ end
+ }
+ }
+ }
+ }
+ if (!version && (print(".");try_func(func, libs_param, ["tcl.h"])))
+ return [true, path, lib_w_sufx, nil, *inc]
+ end
+ end
+ ensure
+ $LIBPATH = libpath.dup
+ $libs = libs_param.dup
+ $INCFLAGS = incflags.dup
+ end
+ }
+
+ print("\n") # progress
+ [false, nil, nil, nil]
+end
+
+def parse_TK_LIBS(tklibs)
+ sfx = "lib|shlib|dll|so"
+ re = /(("|')[^"']+\.(#{sfx})\2|[^"' ]+\.(#{sfx})|-l("|')[^"']+\5|-l[^" ]+)/#'
+
+ tklibs.scan(re).map{|lib,|
+ if lib =~ /^("|')([^"]+)\.(#{sfx})\1/
+ "\"-l#{$2}\""
+ elsif lib =~ /([^" ]+)\.(#{sfx})/
+ "-l#{$1}"
+ else
+ lib
+ end
+ }.join(' ')
end
-def find_tk(tklib, stubs)
- paths = ["/usr/local/lib", "/usr/pkg/lib", "/usr/lib"]
+def find_tk(tklib, stubs, version, *opt_paths)
+ if TkConfig_Info['MKMF_PARAMS']
+ # already checked existence of tcl library based on tkConfig.sh
+ ($INCFLAGS ||= "") << " " << TkConfig_Info['MKMF_PARAMS']['INCFLAGS']
+ $LIBPATH ||= []; $LIBPATH |= TkConfig_Info['MKMF_PARAMS']['LIBPATH']
+ ($libs ||= "") << " " << TkConfig_Info['MKMF_PARAMS']['libs']
+ return [true, nil, nil, nil]
+ end
+ # else, no available tkConfig.sh on the system
+
+ print "Search Tk library"
+
if stubs
func = "Tk_InitStubs"
lib = "tkstub"
@@ -79,18 +1181,385 @@ def find_tk(tklib, stubs)
func = "Tk_Init"
lib = "tk"
end
- if tklib
- find_library(tklib, func, *paths)
- elsif find_library(lib, func, *paths)
- true
+
+ if version && ! version.empty?
+ versions = [version]
else
- %w[8.5 8.4 8.3 8.2 8.1 8.0 4.2].find { |ver|
- find_library("#{lib}#{ver}", func, *paths) or
- find_library("#{lib}#{ver.delete('.')}", func, *paths) or
- find_library("tk#{ver}", func, *paths) or
- find_library("tk#{ver.delete('.')}", func, *paths)
+ versions = TkLib_Config['search_versions']
+ end
+
+ default_paths = []
+
+ default_paths.concat [
+ RbConfig::CONFIG['libdir'],
+ File.join(RbConfig::CONFIG['exec_prefix'], 'lib'),
+ File.join(RbConfig::CONFIG['prefix'], 'lib'),
+ "/usr/local/lib", "/usr/pkg/lib", "/usr/contrib/lib", "/usr/lib"
+ ].find_all{|dir| File.directory?(dir)} unless CROSS_COMPILING
+
+ if !CROSS_COMPILING and is_win32?
+ default_paths.concat [
+ "c:/Tcl/lib","c:/Program Files/Tcl/lib","c:/Program Files (x86)/Tcl/lib",
+ "/Tcl/lib","/Program Files/Tcl/lib","/Program Files (x86)/Tcl/lib"
+ ].find_all{|dir| File.directory?(dir)}
+
+ # for MinGW
+ ["/usr/local/lib64", "/usr/lib64", "/usr/local/lib", "/usr/lib"].each{|dir|
+ default_paths << File.expand_path(dir) if File.directory? dir
}
+
+ default_paths |= ENV['LIBRARY_PATH'].split(';').find_all{|dir| File.directory? dir}.map{|dir| File.expand_path(dir)} if ENV['LIBRARY_PATH']
+ default_paths |= ENV['PATH'].split(';').find_all{|dir| File.directory? dir}.map{|dir| File.expand_path(dir)} if ENV['PATH']
+ end
+
+ default_paths |= TkLib_Config["checked_shlib_dirs"]
+
+ unless TkLib_Config["space-on-tk-libpath"]
+ default_paths.delete_if{|path| path =~ / /}
+ end
+
+ if (paths = opt_paths.compact).empty?
+ paths = check_tk_NG_path(default_paths)
+ end
+
+ incflags = ($INCFLAGS ||= "").dup
+ libpath = ($LIBPATH ||= []).dup
+ libs_param = ($libs ||= "").dup
+ tcllibs = nil
+
+ exts = "(" + get_ext_list.join('|') + ")"
+
+ paths.map{|path|
+ lib_w_sufx = lib
+ begin
+ $LIBPATH |= [path]
+ inc = [File.join(File.dirname(path),"include"), File.dirname(path)]
+ inc.each{|f| $INCFLAGS << " -I" << f }
+
+ if tklib
+ print(".")
+ if have_library(tklib, func, ["tcl.h", "tk.h"])
+ return [true, path, lib_w_sufx, nil, *inc]
+ end
+ else
+ sufx_list = ['', 't', 'g', 's', 'x']
+ search_vers_on_path(versions, path, lib, 'tk').find{|ver|
+ dir_enum = Dir.foreach(path)
+ no_dot_ver = ver.delete('.')
+ libnames = ["#{lib}#{ver}", "#{lib}#{no_dot_ver}"]
+ libnames << "tk#{ver}" << "tk#{no_dot_ver}" if lib != "tk"
+ libnames.find{|libname|
+ sufx_list.find{|sufx|
+ print(".")
+ dir_enum.map{|fname|
+ if fname =~ /^.*(#{libname}.*#{sufx})\.(#{exts}).*$/
+ [fname, $1, $2]
+ end
+ }.compact.find{|fname, lib_w_sufx, ext|
+ if (ext != CONFIG['DLEXT'] && ext == CONFIG['LIBEXT']) ||
+ ext == "a"
+ # static link
+ tklibs = libs_param + " -DSTATIC_BUILD " + fname.quote
+ else
+ tklibs = append_library($libs, lib_w_sufx)
+ tklibs = "-L#{path.quote} -Wl,-R#{path.quote} " + tklibs
+ end
+ if try_func(func, tklibs, ["tcl.h", "tk.h"])
+ return [true, path, nil, tklibs, *inc]
+ end
+ }
+ }
+ }
+ }
+ if (!version && (print(".");try_func(func, libs_param, ["tcl.h", "tk.h"])))
+ return [true, path, lib_w_sufx, nil, *inc]
+ end
+ end
+ ensure
+ $LIBPATH = libpath
+ $libs = libs_param
+ $INCFLAGS = incflags.dup
+ end
+ }
+
+ print("\n") # progress
+ [false, nil, nil, nil]
+end
+
+def find_tcltk_library(tcllib, tklib, stubs, tclversion, tkversion,
+ tcl_opt_paths, tk_opt_paths)
+ st,path,lib,libs,*inc = find_tcl(tcllib, stubs, tclversion, *tcl_opt_paths)
+ unless st
+ puts("Warning:: cannot find Tcl library. tcltklib will not be compiled (tcltklib is disabled on your Ruby. That is, Ruby/Tk will not work). Please check configure options.")
+ return false
+ else
+ ($LIBPATH ||= []; $LIBPATH |= [path]) if path
+ $libs = append_library($libs, lib) if lib
+ ($libs ||= "") << " " << libs if libs
+ $INCFLAGS ||= ""
+ inc.each{|f| $INCFLAGS << " -I" << f}
end
+
+ st,path,lib,libs,*inc = find_tk(tklib, stubs, tkversion, *tk_opt_paths)
+ unless st
+ puts("Warning:: cannot find Tk library. tcltklib will not be compiled (tcltklib is disabled on your Ruby. That is, Ruby/Tk will not work). Please check configure options.")
+ return false
+ else
+ ($LIBPATH ||= []; $LIBPATH |= [path]) if path
+ $libs = append_library($libs, lib) if lib && !lib.empty?
+ ($libs ||= "") << " " << libs if libs
+ $INCFLAGS ||= ""
+ inc.each{|f| $INCFLAGS << " -I" << f}
+ end
+
+ true
+end
+
+def find_tcltk_header(tclver, tkver)
+ base_dir = []
+
+ base_dir.concat [
+ File.join(RbConfig::CONFIG['prefix'], 'include'),
+ "/usr/local/include", "/usr/pkg/include", "/usr/contrib/include",
+ "/usr/include"
+ ].find_all{|dir| File.directory?(dir)}.map{|dir| File.expand_path(dir)}
+
+ if !CROSS_COMPILING && is_win32?
+ base_dir.concat [
+ "c:/Tcl/include","c:/Program Files/Tcl/include",
+ "c:/Program Files (x86)/Tcl/include",
+ "/Tcl/include","/Program Files/Tcl/include",
+ "/Program Files (x86)/Tcl/include"
+ ].find_all{|dir| File.directory?(dir)}.map{|dir| File.expand_path(dir)}
+
+ if ENV['CPATH']
+ base_dir |= ENV['CPATH'].split(';').find_all{|dir| File.directory?(dir)}.map{|dir| File.expand_path(dir)}
+ end
+ end
+
+ base_dir |= TkLib_Config["checked_shlib_dirs"]
+
+ unless TkLib_Config["space-on-tk-libpath"]
+ base_dir.delete_if{|path| path =~ / /}
+ end
+
+ # tcl.h
+ if TclConfig_Info['MKMF_PARAMS']
+ # already checked existence of tcl headers based on tclConfig.sh
+ have_tcl_h = true
+ else
+ print "\nSearch tcl.h"
+ if enable_config("tcl-h-ver-check", true) &&
+ tclver && tclver =~ /^\D*(\d)\.?(\d)/
+ major = $1; minor = $2
+ else
+ major = minor = nil
+ end
+ print(".") # progress
+ if major && minor
+ # version check on tcl.h
+ have_tcl_h = try_cpp("#include <tcl.h>\n#if TCL_MAJOR_VERSION != #{major} || TCL_MINOR_VERSION != #{minor}\n#error VERSION does not match\n#endif")
+ else
+ have_tcl_h = have_header('tcl.h')
+ end
+ unless have_tcl_h
+ if tclver && ! tclver.empty?
+ versions = [tclver]
+ else
+ versions = TkLib_Config['search_versions']
+ end
+ paths = base_dir.dup
+ (versions + [""]).each{|ver|
+ paths.concat(base_dir.map{|dir|
+ [
+ dir + '/tcl' + ver,
+ dir + '/tcl' + ver + '/include',
+ dir + '/tcl' + ver.delete('.'),
+ dir + '/tcl' + ver.delete('.') + '/include'
+ ]
+ }.flatten)
+ }
+ paths = paths.map{|dir|
+ (File.directory?(dir))? File.expand_path(dir): nil
+ }.compact.uniq
+
+ code = "#include <tcl.h>\n"
+ code << "#if TCL_MAJOR_VERSION != #{major}\n#error MAJOR_VERSION does not match\n#endif\n" if major
+ code << "#if TCL_MINOR_VERSION != #{minor}\n#error MINOR_VERSION does not match\n#endif\n" if minor
+ have_tcl_h = paths.find{|path|
+ print(".") # progress
+ inc_opt = " -I#{path.quote}"
+ if try_cpp(code, inc_opt)
+ ($INCFLAGS ||= "") << inc_opt
+ true
+ else
+ false
+ end
+ }
+ end
+ end
+
+ # tk.h
+ if TkConfig_Info['MKMF_PARAMS']
+ # already checked existence of tk headers based on tkConfig.sh
+ have_tk_h = true
+ else
+ print "\nSearch tk.h"
+ if enable_config("tk-h-ver-check", true) &&
+ tkver && tkver =~ /^\D*(\d)\.?(\d)/
+ major = $1; minor = $2
+ else
+ major = minor = nil
+ end
+ print(".") # progress
+ if major && minor
+ # version check on tk.h
+ have_tk_h = try_cpp("#include <tk.h>\n#if TK_MAJOR_VERSION != #{major} || TK_MINOR_VERSION != #{minor}\n#error VERSION does not match\n#endif")
+ else
+ have_tk_h = have_header('tk.h')
+ end
+ unless have_tk_h
+ if tkver && ! tkver.empty?
+ versions = [tkver]
+ else
+ versions = TkLib_Config['search_versions']
+ end
+ paths = base_dir.dup
+ (versions + [""]).each{|ver|
+ paths.concat(base_dir.map{|dir|
+ [
+ dir + '/tk' + ver,
+ dir + '/tk' + ver + '/include',
+ dir + '/tk' + ver.delete('.'),
+ dir + '/tk' + ver.delete('.') + '/include'
+ ]
+ }.flatten)
+ }
+ paths = paths.map{|dir|
+ (File.directory?(dir))? File.expand_path(dir): nil
+ }.compact.uniq
+
+ code = "#include <tcl.h>\n#include <tk.h>\n"
+ code << "#if TK_MAJOR_VERSION != #{major}\n#error MAJOR_VERSION does not match\n#endif\n" if major
+ code << "#if TK_MINOR_VERSION != #{minor}\n#error MINOR_VERSION does not match\n#endif\n" if minor
+ have_tk_h = paths.find{|path|
+ print(".") # progress
+ inc_opt = " -I#{path.quote}"
+ if try_cpp(code, inc_opt)
+ ($INCFLAGS ||= "") << inc_opt
+ true
+ else
+ false
+ end
+ }
+ end
+ end
+
+ puts "Can't find \"tcl.h\"." unless have_tcl_h
+ puts "Can't find \"tk.h\"." unless have_tk_h
+ have_tcl_h && have_tk_h
+end
+
+def setup_for_macosx_framework(tclver, tkver)
+ # use framework, but no tclConfig.sh
+ unless $LDFLAGS && $LDFLAGS.include?('-framework')
+ ($LDFLAGS ||= "") << ' -framework Tk -framework Tcl'
+ end
+
+ if TkLib_Config["tcl-framework-header"]
+ TclConfig_Info['TCL_INCLUDE_SPEC'][0,0] =
+ " -I#{TkLib_Config["tcl-framework-header"].quote} "
+ else
+ tcl_base = File.join(TkLib_Config["tcltk-framework"], 'Tcl.framework')
+ if tclver
+ TclConfig_Info['TCL_INCLUDE_SPEC'] <<
+ " -I#{File.join(tcl_base, 'Versions', tclver, 'Headers').quote} "
+ end
+
+ TclConfig_Info['TCL_INCLUDE_SPEC'] << File.join(tcl_base, 'Headers')
+
+ unless tclver
+ dir = Dir.glob(File.join(tcl_base, 'Versions', '*', 'Headers'),
+ File::FNM_CASEFOLD).sort.reverse[0]
+ TclConfig_Info['TCL_INCLUDE_SPEC'] << "-I#{dir.quote} " if dir
+ end
+ end
+
+ if TkLib_Config["tk-framework-header"]
+ TkConfig_Info['TK_INCLUDE_SPEC'][0,0] =
+ " -I#{TkLib_Config["tk-framework-header"].quote} "
+ else
+ tk_base = File.join(TkLib_Config["tcltk-framework"], 'Tk.framework')
+ if tkver
+ TkConfig_Info['TK_INCLUDE_SPEC'] <<
+ " -I#{File.join(tk_base, 'Versions', tkver, 'Headers').quote} "
+ end
+
+ TkConfig_Info['TK_INCLUDE_SPEC'] << File.join(tk_base, 'Headers')
+
+ unless tkver
+ dir = Dir.glob(File.join(tk_base, 'Versions', '*', 'Headers'),
+ File::FNM_CASEFOLD).sort.reverse[0]
+ TkConfig_Info['TK_INCLUDE_SPEC'] << "-I#{dir.quote} " if dir
+ end
+ end
+end
+
+def find_X11(*opt_paths)
+ defaults =
+ [ "/usr/X11*/lib", "/usr/lib/X11*", "/usr/local/X11*", "/usr/openwin/lib" ]
+ paths = []
+ opt_paths.compact.each{|path| paths.concat(Dir.glob(path.strip.chomp('/'), File::FNM_CASEFOLD))}
+ defaults.compact.each{|path| paths.concat(Dir.glob(path.strip.chomp('/'), File::FNM_CASEFOLD))}
+ st = find_library("X11", "XOpenDisplay", *paths)
+ unless st
+ puts("Warning:: cannot find X11 library. tcltklib will not be compiled (tcltklib is disabled on your Ruby. That is, Ruby/Tk will not work). Please check configure options. If your Tcl/Tk don't require X11, please try --without-X11.")
+ end
+ st
+end
+
+def search_X_libraries
+ use_tkConfig = false
+ if TkConfig_Info['config_file_path']
+ # use definitions on tkConfig.sh
+ if (TkConfig_Info['TK_XINCLUDES'] &&
+ !TkConfig_Info['TK_XINCLUDES'].strip.empty?) ||
+ (TkConfig_Info['TK_XLIBSW'] && !TkConfig_Info['TK_XLIBSW'].strip.empty?)
+ use_tkConfig = true
+ #use_X = true && with_config("X11", ! is_win32?)
+ use_X = with_config("X11", true)
+ else
+ #use_X = false || with_config("X11", false)
+ use_X = with_config("X11", false)
+ end
+ else
+ # depend on configure options
+ use_X = with_config("X11", !(is_win32? || TkLib_Config["tcltk-framework"]))
+ end
+
+ if TkConfig_Info['TK_XINCLUDES'] &&
+ !TkConfig_Info['TK_XINCLUDES'].strip.empty?
+ ($INCFLAGS ||= "") << " " << TkConfig_Info['TK_XINCLUDES'].strip
+ end
+
+ if use_X
+ puts("Use X11 libraries (or use TK_XINCLUDES/TK_XLIBSW information on tkConfig.sh).")
+ x11_idir, x11_ldir = dir_config("X11")
+ x11_ldir2 = with_config("X11-lib")
+ unless find_X11(x11_ldir2, x11_ldir)
+ puts("Can't find X11 libraries. ")
+ if use_tkConfig &&
+ TkConfig_Info['TK_XLIBSW'] && !TkConfig_Info['TK_XLIBSW'].strip.empty?
+ puts("But, try to use TK_XLIBSW information (believe tkCOnfig.sh).")
+ ($libs ||= "") << " " << TkConfig_Info['TK_XLIBSW'] << " "
+ else
+ puts("So, can't make tcltklib.so which is required by Ruby/Tk.")
+ exit
+ end
+ end
+ end
+
+ use_X
end
def pthread_check()
@@ -107,74 +1576,50 @@ def pthread_check()
tcl_enable_thread = nil
end
- if (tclConfig = with_config("tclConfig-file"))
+ if TclConfig_Info['config_file_path']
if tcl_enable_thread == true
- puts("Warning: --with-tclConfig-file option is ignored, because --enable-tcl-thread option is given.")
+ puts("Warning: definiton of tclConfig.sh is ignored, because --enable-tcl-thread option is given.")
elsif tcl_enable_thread == false
- puts("Warning: --with-tclConfig-file option is ignored, because --disable-tcl-thread option is given.")
+ puts("Warning: definition of tclConfig.sh is ignored, because --disable-tcl-thread option is given.")
else
# tcl-thread is unknown and tclConfig.sh is given
- begin
- open(tclConfig, "r") do |cfg|
- while line = cfg.gets()
- if line =~ /^\s*TCL_THREADS=(0|1)/
- tcl_enable_thread = ($1 == "1")
- break
- end
-
- if line =~ /^\s*TCL_MAJOR_VERSION=("|')(\d+)\1/
- tcl_major_ver = $2
- if tcl_major_ver =~ /^[1-7]$/
- tcl_enable_thread = false
- break
- end
- if tcl_major_ver == "8" && tcl_minor_ver == "0"
- tcl_enable_thread = false
- break
- end
- end
-
- if line =~ /^\s*TCL_MINOR_VERSION=("|')(\d+)\1/
- tcl_minor_ver = $2
- if tcl_major_ver == "8" && tcl_minor_ver == "0"
- tcl_enable_thread = false
- break
- end
- end
- end
+ if TclConfig_Info['TCL_THREADS']
+ tcl_enable_thread = (TclConfig_Info['TCL_THREADS'] == "1")
+ else
+ tcl_major_ver = TclConfig_Info['TCL_MAJOR_VERSION'].to_i
+ tcl_minor_ver = TclConfig_Info['TCL_MINOR_VERSION'].to_i
+ if tcl_major_ver < 8 || (tcl_major_ver == 8 && tcl_minor_ver == 0)
+ tcl_enable_thread = false
end
+ end
- if tcl_enable_thread == nil
- # not find definition
- if tcl_major_ver
- puts("Warning: '#{tclConfig}' doesn't include TCL_THREADS definition.")
- else
- puts("Warning: '#{tclConfig}' may not be a tclConfig file.")
- end
- tclConfig = false
+ if tcl_enable_thread == nil
+ # cannot find definition
+ if tcl_major_ver
+ puts("Warning: '#{TclConfig_Info['config_file_path']}' doesn't include TCL_THREADS definition.")
+ else
+ puts("Warning: '#{TclConfig_Info['config_file_path']}' may not be a tclConfig file.")
end
- rescue Exception
- puts("Warning: fail to read '#{tclConfig}'!! --> ignore the file")
- tclConfig = false
+ #tclConfig = false
end
end
end
- if tcl_enable_thread == nil && !tclConfig
+ if tcl_enable_thread == nil && !TclConfig_Info['config_file_path']
# tcl-thread is unknown and tclConfig is unavailable
begin
- try_run_available = try_run("int main() { exit(0); }")
+ try_run("int main() { exit(0); }")
rescue Exception
# cannot try_run. Is CROSS-COMPILE environment?
puts(%Q'\
*****************************************************************************
**
-** PTHREAD SUPPORT CHECK WARNING:
+** NATIVETHREAD SUPPORT CHECK WARNING:
**
-** We cannot check the consistency of pthread support between Ruby
-** and the Tcl/Tk library in your environment (are you perhaps
-** cross-compiling?). If pthread support for these 2 packages is
-** inconsistent you may find you get errors when running Ruby/Tk
+** We cannot check the consistency of nativethread support between
+** Ruby and the Tcl/Tk library in your environment (are you perhaps
+** cross-compiling?). If nativethread support for these 2 packages
+** is inconsistent you may find you get errors when running Ruby/Tk
** (e.g. hangs or segmentation faults). We strongly recommend
** you to check the consistency manually.
**
@@ -188,7 +1633,7 @@ def pthread_check()
# tcl-thread is unknown
if try_run(<<EOF)
#include <tcl.h>
-int main() {
+int main() {
Tcl_Interp *ip;
ip = Tcl_CreateInterp();
exit((Tcl_Eval(ip, "set tcl_platform(threaded)") == TCL_OK)? 0: 1);
@@ -207,26 +1652,29 @@ EOF
end
# check pthread mode
- if (macro_defined?('HAVE_NATIVETHREAD', '#include "ruby.h"'))
+ if (TkLib_Config["ruby_with_thread"])
+ $CPPFLAGS ||= ""
+
# ruby -> enable
unless tcl_enable_thread
# ruby -> enable && tcl -> disable
puts(%Q'\
*****************************************************************************
**
-** PTHREAD SUPPORT MODE WARNING:
+** NATIVETHREAD SUPPORT MODE WARNING:
**
** Ruby is compiled with --enable-pthread, but your Tcl/Tk library
-** seems to be compiled without pthread support. Although you can
-** create the tcltklib library, this combination may cause errors
-** (e.g. hangs or segmentation faults). If you have no reason to
-** keep the current pthread support status, we recommend you reconfigure
-** and recompile the libraries so that both or neither support pthreads.
+** seems to be compiled without nativethread support. Although you can
+** create the tcltklib library, this combination may cause errors (e.g.
+** hangs or segmentation faults). If you have no reason to keep the
+** current nativethread support status, we recommend you reconfigure and
+** recompile the libraries so that both or neither support nativethreads.
**
-** If you want change the status of pthread support, please recompile
-** Ruby without "--enable-pthread" configure option or recompile Tcl/Tk
-** with "--enable-threads" configure option (if your Tcl/Tk is later
-** than or equal to Tcl/Tk 8.1).
+** If you want change the status of nativethread support, please recompile
+** Ruby without "--enable-pthread" configure option (If you use Ruby 1.9.x
+** or later, you cannot remove this option, because it requires native-
+** thread support.) or recompile Tcl/Tk with "--enable-threads" configure
+** option (if your Tcl/Tk is later than or equal to Tcl/Tk 8.1).
**
*****************************************************************************
')
@@ -248,13 +1696,13 @@ EOF
puts(%Q'\
*****************************************************************************
**
-** PTHREAD SUPPORT MODE ERROR:
+** NATIVETHREAD SUPPORT MODE ERROR:
**
-** Ruby is not compiled with --enable-pthread, but your Tcl/Tk
-** library seems to be compiled with pthread support. This
+** Ruby is not compiled with --enable-pthread, but your Tcl/Tk
+** library seems to be compiled with nativethread support. This
** combination may cause frequent hang or segmentation fault
** errors when Ruby/Tk is working. We recommend that you NEVER
-** create the library with such a combination of pthread support.
+** create the library with such a combination of nativethread support.
**
** Please recompile Ruby with the "--enable-pthread" configure option
** or recompile Tcl/Tk with the "--disable-threads" configure option.
@@ -271,39 +1719,314 @@ EOF
end
end
-if tcltk_framework ||
- (have_header("tcl.h") && have_header("tk.h") &&
- (is_win32 || find_library("X11", "XOpenDisplay",
- "/usr/X11/lib", "/usr/lib/X11", "/usr/X11R6/lib", "/usr/openwin/lib")) &&
- find_tcl(tcllib, stubs) &&
- find_tk(tklib, stubs))
- $CPPFLAGS += ' -DUSE_TCL_STUBS -DUSE_TK_STUBS' if stubs
- $CPPFLAGS += ' -D_WIN32' if /cygwin/ =~ RUBY_PLATFORM
+##############################################################
+# main
+##############################################################
+# check header file
+print("check functions.")
+have_func("ruby_native_thread_p", "ruby.h")
+print(".") # progress
+have_func("rb_errinfo", "ruby.h")
+print(".") # progress
+have_func("rb_safe_level", "ruby.h")
+print(".") # progress
+have_func("rb_hash_lookup", "ruby.h")
+print(".") # progress
+have_func("rb_proc_new", "ruby.h")
+print(".") # progress
+have_func("rb_obj_untrust", "ruby.h")
+print(".") # progress
+have_func("rb_obj_taint", "ruby.h")
+print(".") # progress
+have_func("rb_set_safe_level_force", "ruby.h")
+print(".") # progress
+have_func("rb_sourcefile", "ruby.h")
+print("\n") # progress
+
+print("check struct members.")
+have_struct_member("struct RArray", "ptr", "ruby.h")
+print(".") # progress
+have_struct_member("struct RArray", "len", "ruby.h")
+print("\n") # progress
- if tcltk_framework
- if tcl_framework_header
- $CPPFLAGS += " -I#{tcl_framework_header}"
+# check libraries
+unless is_win32?
+ print("check libraries.")
+ have_library("nsl", "t_open")
+ print(".") # progress
+ have_library("socket", "socket")
+ print(".") # progress
+ have_library("dl", "dlopen")
+ print(".") # progress
+ have_library("m", "log", "math.h")
+ print("\n") # progress
+end
+$CPPFLAGS ||= ""
+$CPPFLAGS += ' -D_WIN32' if /cygwin/ =~ RUBY_PLATFORM
+
+# Does ruby have nativethread ?
+TkLib_Config["ruby_with_thread"] =
+ macro_defined?('HAVE_NATIVETHREAD', '#include "ruby.h"')
+
+
+#---------------------------------------------------
+TclConfig_Info = {}
+TkConfig_Info = {}
+
+# use Tcl/Tk build dir? (has highest priority)
+TkLib_Config["tcl-build-dir"] = with_config("tcl-build-dir")
+TkLib_Config["tk-build-dir"] = with_config("tk-build-dir")
+if TkLib_Config["tcl-build-dir"]
+ puts("use Tcl build (pre-install) dir \"#{TkLib_Config["tcl-build-dir"]}\"")
+ TkLib_Config["tcl-build-dir"] = File.expand_path(TkLib_Config["tcl-build-dir"])
+ base = File.dirname(TkLib_Config["tcl-build-dir"])
+ ($INCFLAGS ||= "") << " -I#{File.join(base, "generic").quote} -I#{TkLib_Config["tcl-build-dir"].quote}"
+ $LIBPATH ||= []; $LIBPATH |= [TkLib_Config["tcl-build-dir"]]
+end
+if TkLib_Config["tk-build-dir"]
+ puts("use Tk build (pre-install) dir \"#{TkLib_Config["tk-build-dir"]}\"")
+ TkLib_Config["tk-build-dir"] = File.expand_path(TkLib_Config["tk-build-dir"])
+ base = File.dirname(TkLib_Config["tk-build-dir"])
+ ($INCFLAGS ||= "") << " -I#{File.join(base, "generic").quote} -I#{TkLib_Config["tk-build-dir"].quote}"
+ $LIBPATH ||= []; $LIBPATH |= [TkLib_Config["tk-build-dir"]]
+end
+
+# check requirement of Tcl/tk version
+tcltk_version = with_config("tcltkversion")
+TkLib_Config["tcltkversion"] = check_tcltk_version(tcltk_version)
+
+if TkLib_Config["tcl-build-dir"]
+ if (cfgfile = with_config("tclConfig-file", Dir.glob(File.join(TkLib_Config["tcl-build-dir"], "tclConfig*.sh"), File::FNM_CASEFOLD)[0]))
+ TclConfig_Info['config_file_path'] = cfgfile
+ TkLib_Config["tclConfig_info"] = cfginfo = parse_tclConfig(cfgfile)
+ if tclver = TkLib_Config["tcltkversion"][0]
+ TkLib_Config["tcltkversion"][0].sub!(/\d(\.?)\d/, "#{cfginfo['TCL_MAJOR_VERSION']}\\1#{cfginfo['TCL_MINOR_VERSION']}")
+ else
+ TkLib_Config["tcltkversion"][0] = "#{cfginfo['TCL_MAJOR_VERSION']}.#{cfginfo['TCL_MINOR_VERSION']}"
+ end
+ end
+end
+if TkLib_Config["tk-build-dir"]
+ if (cfgfile = with_config("tkConfig-file", Dir.glob(File.join(TkLib_Config["tk-build-dir"], "tkConfig*.sh"), File::FNM_CASEFOLD)[0]))
+ TkConfig_Info['config_file_path'] = cfgfile
+ TkLib_Config["tkConfig_info"] = cfginfo = parse_tclConfig(cfgfile)
+ if TkLib_Config["tcltkversion"][1]
+ TkLib_Config["tcltkversion"][1].sub!(/\d(\.?)\d/, "#{cfginfo['TK_MAJOR_VERSION']}\\1#{cfginfo['TK_MINOR_VERSION']}")
else
- $CPPFLAGS += " -I#{tcltk_framework}/Tcl.framework/Headers"
+ TkLib_Config["tcltkversion"][1] = "#{cfginfo['TK_MAJOR_VERSION']}.#{cfginfo['TK_MINOR_VERSION']}"
end
+ end
+end
+
+tclver, tkver = TkLib_Config["tcltkversion"]
+puts("Specified Tcl/Tk version is #{[tclver, tkver].inspect}") if tclver||tkver
- if tk_framework_header
- $CPPFLAGS += " -I#{tk_framework_header}"
+# use ActiveTcl ?
+#if activeTcl = with_config("ActiveTcl")
+#if activeTcl = with_config("ActiveTcl", true)
+if activeTcl = with_config("ActiveTcl", !(TkLib_Config["tcl-build-dir"] && TkLib_Config["tk-build-dir"]))
+ puts("Use ActiveTcl libraries (if available).")
+ unless activeTcl.kind_of? String
+ # set default ActiveTcl path
+ if CROSS_COMPILING
+ elsif is_win32?
+ activeTcl = 'c:/Tcl*'
+ elsif is_macosx?
+ activeTcl = '/Library/Frameworks'
else
- $CPPFLAGS += " -I#{tcltk_framework}/Tk.framework/Headers"
+ activeTcl = '/opt/ActiveTcl*'
end
+ end
+end
+TkLib_Config["ActiveTcl"] = activeTcl
- $LDFLAGS += ' -framework Tk -framework Tcl'
+# allow space chars on a libpath
+TkLib_Config["space-on-tk-libpath"] =
+ enable_config("space-on-tk-libpath", ! is_win32?)
+
+# enable Tcl/Tk stubs?
+=begin
+if TclConfig_Info['TCL_STUB_LIB_SPEC'] && TkConfig_Info['TK_STUB_LIB_SPEC'] &&
+ !TclConfig_Info['TCL_STUB_LIB_SPEC'].strip.empty? &&
+ !TkConfig_Info['TK_STUB_LIB_SPEC'].strip.empty?
+ stubs = true
+ unless (st = enable_config("tcltk-stubs")).nil?
+ stubs &&= st
+ end
+ unless (st = with_config("tcltk-stubs")).nil?
+ stubs &&= st
end
+else
+ stubs = enable_config("tcltk-stubs") || with_config("tcltk-stubs")
+end
+=end
+stubs = enable_config("tcltk-stubs") || with_config("tcltk-stubs")
+if (TkLib_Config["tcltk-stubs"] = stubs)
+ puts("Compile with Tcl/Tk stubs.")
+ $CPPFLAGS ||= ""; $CPPFLAGS += ' -DUSE_TCL_STUBS -DUSE_TK_STUBS'
+end
- if stubs or pthread_check
- # create Makefile
+# directory configuration of Tcl/Tk libraries
+if TkLib_Config["tcl-build-dir"]
+ tcl_idir = File.join(File.dirname(TkLib_Config["tcl-build-dir"]),"generic")
+ tcl_ldir = TkLib_Config["tcl-build-dir"]
+else
+ tcl_idir, tcl_ldir = dir_config("tcl")
+end
+if TkLib_Config["tk-build-dir"]
+ tk_idir = File.join(File.dirname(TkLib_Config["tk-build-dir"]),"generic")
+ tk_ldir = TkLib_Config["tk-build-dir"]
+else
+ tk_idir, tk_ldir = dir_config("tk")
+end
- # for SUPPORT_STATUS
- $INSTALLFILES ||= []
- $INSTALLFILES << ["lib/tkextlib/SUPPORT_STATUS", "$(RUBYLIBDIR)", "lib"]
+tcl_idir = tk_idir unless tcl_idir
+tcl_ldir = tk_ldir unless tcl_ldir
+tk_idir = tcl_idir unless tk_idir
+tk_ldir = tcl_ldir unless tk_ldir
- # create
- create_makefile("tcltklib")
+TclConfig_Info['TCL_INCLUDE_SPEC'] ||= ""
+TkConfig_Info['TK_INCLUDE_SPEC'] ||= ""
+TclConfig_Info['TCL_INCLUDE_SPEC'][0,0] = "-I#{tcl_idir.quote} " if tcl_idir
+TkConfig_Info['TK_INCLUDE_SPEC'][0,0] = "-I#{tk_idir.quote} " if tk_idir
+
+# get tclConfig.sh/tkConfig.sh
+TkLib_Config["tcl-NG-path"] = []
+TkLib_Config["tk-NG-path"] = []
+tclcfg, tkcfg =
+ get_tclConfig(
+ TclConfig_Info['config_file_path'] || with_config("tclConfig-file", true),
+ TkConfig_Info['config_file_path'] || with_config("tkConfig-file", true),
+ (TclConfig_Info['config_file_path'])?
+ File.dirname(TclConfig_Info['config_file_path']) :
+ with_config("tclConfig-dir", tcl_ldir || true),
+ (TkConfig_Info['config_file_path'])?
+ File.dirname(TkConfig_Info['config_file_path']) :
+ with_config("tkConfig-dir", tk_ldir || true)
+ )
+TclConfig_Info.merge!(TkLib_Config["tclConfig_info"]) if TkLib_Config["tclConfig_info"]
+TkConfig_Info.merge!(TkLib_Config["tkConfig_info"]) if TkLib_Config["tkConfig_info"]
+TclConfig_Info['config_file_path'] ||= tclcfg
+TkConfig_Info['config_file_path'] ||= tkcfg
+
+tk_cfg_dir = File.dirname(TkConfig_Info['config_file_path']) rescue nil
+tcl_cfg_dir = File.dirname(TclConfig_Info['config_file_path']) rescue nil
+
+tk_ldir_list = [tk_ldir, tk_cfg_dir].uniq
+tcl_ldir_list = [tcl_ldir, tcl_cfg_dir].uniq
+
+if TkConfig_Info['config_file_path']
+ if TkLib_Config["tk-build-dir"]
+ spec_dir = get_libpath(TkConfig_Info['TK_LIB_FLAG'], TkConfig_Info['TK_BUILD_LIB_SPEC'])
+ else
+ spec_dir = get_libpath(TkConfig_Info['TK_LIB_FLAG'], TkConfig_Info['TK_LIB_SPEC'])
end
+ tk_ldir_list << spec_dir if File.directory?(spec_dir)
+end
+if TclConfig_Info['config_file_path']
+ if TkLib_Config["tcl-build-dir"]
+ spec_dir = get_libpath(TclConfig_Info['TCL_LIB_FLAG'], TclConfig_Info['TCL_BUILD_LIB_SPEC'])
+ else
+ spec_dir = get_libpath(TclConfig_Info['TCL_LIB_FLAG'], TclConfig_Info['TCL_LIB_SPEC'])
+ end
+ tcl_ldir_list << spec_dir if File.directory?(spec_dir)
+end
+
+# check tk_shlib_search_path
+TkLib_Config["checked_shlib_dirs"] =
+ check_shlib_search_path(with_config('tk-shlib-search-path'))
+
+# set TCL_DEFS and TK_DEFS
+$CPPFLAGS ||= ""
+# $CPPFLAGS += " #{TclConfig_Info['TCL_DEFS']}"
+# $CPPFLAGS += " #{TkConfig_Info['TK_DEFS']}"
+$defs += collect_tcltk_defs(TclConfig_Info['TCL_DEFS'], TkConfig_Info['TK_DEFS'])
+
+# MacOS X Frameworks?
+if TkLib_Config["tcltk-framework"]
+ puts("Use MacOS X Frameworks.")
+ ($LDFLAGS ||= "") << " -L#{TkLib_Config["tcl-build-dir"].quote} -Wl,-R#{TkLib_Config["tcl-build-dir"].quote}" if TkLib_Config["tcl-build-dir"]
+
+ if tcl_cfg_dir
+ TclConfig_Info['TCL_LIBS'] ||= ""
+ ($INCFLAGS ||= "") << ' ' << TclConfig_Info['TCL_INCLUDE_SPEC']
+ $LDFLAGS << ' ' << TclConfig_Info['TCL_LIBS']
+ if stubs
+ if TkLib_Config["tcl-build-dir"] &&
+ TclConfig_Info['TCL_BUILD_STUB_LIB_SPEC'] &&
+ !TclConfig_Info['TCL_BUILD_STUB_LIB_SPEC'].strip.empty?
+ $LDFLAGS << ' ' << TclConfig_Info['TCL_BUILD_STUB_LIB_SPEC']
+ else
+ $LDFLAGS << ' ' << TclConfig_Info['TCL_STUB_LIB_SPEC']
+ end
+ else
+ if TkLib_Config["tcl-build-dir"] &&
+ TclConfig_Info['TCL_BUILD_LIB_SPEC'] &&
+ !TclConfig_Info['TCL_BUILD_LIB_SPEC'].strip.empty?
+ $LDFLAGS << ' ' << TclConfig_Info['TCL_BUILD_LIB_SPEC']
+ else
+ $LDFLAGS << ' ' << TclConfig_Info['TCL_LIB_SPEC']
+ end
+ end
+ end
+
+ $LDFLAGS << " -L#{TkLib_Config["tk-build-dir"].quote} -Wl,-R#{TkLib_Config["tk-build-dir"].quote}" if TkLib_Config["tk-build-dir"]
+
+ if tk_cfg_dir
+ TkConfig_Info['TK_LIBS'] ||= ""
+ ($INCFLAGS ||= "") << ' ' << TkConfig_Info['TK_INCLUDE_SPEC']
+ $LDFLAGS << ' ' << TkConfig_Info['TK_LIBS']
+ if stubs
+ if TkLib_Config["tk-build-dir"] &&
+ TclConfig_Info['TK_BUILD_STUB_LIB_SPEC'] &&
+ !TclConfig_Info['TK_BUILD_STUB_LIB_SPEC'].strip.empty?
+ $LDFLAGS << ' ' << TkConfig_Info['TK_BUILD_STUB_LIB_SPEC']
+ else
+ $LDFLAGS << ' ' << TkConfig_Info['TK_STUB_LIB_SPEC']
+ end
+ else
+ if TkLib_Config["tk-build-dir"] &&
+ TclConfig_Info['TK_BUILD_LIB_SPEC'] &&
+ !TclConfig_Info['TK_BUILD_LIB_SPEC'].strip.empty?
+ $LDFLAGS << ' ' << TkConfig_Info['TK_BUILD_LIB_SPEC']
+ else
+ $LDFLAGS << ' ' << TkConfig_Info['TK_LIB_SPEC']
+ end
+ end
+ end
+ setup_for_macosx_framework(tclver, tkver) if tcl_cfg_dir && tk_cfg_dir
+end
+
+# name of Tcl/Tk libraries
+tklib = with_config("tklib")
+tcllib = with_config("tcllib")
+
+# search X libraries
+use_X = search_X_libraries
+
+
+#---------------------------------------------------
+if (TkLib_Config["tcltk-framework"] ||
+ ( find_tcltk_header(tclver, tkver) &&
+ find_tcltk_library(tcllib, tklib, stubs, tclver, tkver,
+ tcl_ldir_list, tk_ldir_list) ) ) &&
+ (stubs || pthread_check())
+ # create Makefile
+
+ # for SUPPORT_STATUS
+ $INSTALLFILES ||= []
+ $INSTALLFILES << ["lib/tkextlib/SUPPORT_STATUS", "$(RUBYLIBDIR)", "lib"]
+
+ # remove harmful definitions.
+ $defs.delete_if{|x|/^-Du?intptr_t=/ =~ x}
+
+ # create
+ $defs << %[-DRUBY_VERSION=\\"#{RUBY_VERSION}\\"]
+ $defs << %[-DRUBY_RELEASE_DATE=\\"#{RUBY_RELEASE_DATE}\\"]
+
+ create_makefile("tcltklib")
+
+ puts "\nFind Tcl/Tk libraries. Make tcltklib.so which is required by Ruby/Tk."
+else
+ puts "\nCan't find proper Tcl/Tk libraries. So, can't make tcltklib.so which is required by Ruby/Tk."
end
diff --git a/ext/tk/lib/multi-tk.rb b/ext/tk/lib/multi-tk.rb
index 78ed1aa6ee..ec718678f0 100644
--- a/ext/tk/lib/multi-tk.rb
+++ b/ext/tk/lib/multi-tk.rb
@@ -114,7 +114,14 @@ MultiTkIp_OK.freeze
class MultiTkIp
BASE_DIR = File.dirname(__FILE__)
- @@SLAVE_IP_ID = ['slave'.freeze, '0'.taint].freeze
+ WITH_RUBY_VM = Object.const_defined?(:VM) && ::VM.class == Class
+ WITH_ENCODING = Object.const_defined?(:Encoding) && ::Encoding.class == Class
+
+ (@@SLAVE_IP_ID = ['slave'.freeze, '0'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
@@IP_TABLE = {}.taint unless defined?(@@IP_TABLE)
@@ -126,14 +133,18 @@ class MultiTkIp
unless defined?(@@TK_CMD_TBL)
@@TK_CMD_TBL = Object.new.taint
- @@TK_CMD_TBL.instance_variable_set('@tbl', {}.taint)
+ # @@TK_CMD_TBL.instance_variable_set('@tbl', {}.taint)
+ @@TK_CMD_TBL.instance_variable_set('@tbl', Hash.new{|hash,key|
+ fail IndexError,
+ "unknown command ID '#{key}'"
+ }.taint)
class << @@TK_CMD_TBL
allow = [
- '__send__', '__id__', 'freeze', 'inspect', 'kind_of?',
+ '__send__', '__id__', 'freeze', 'inspect', 'kind_of?', 'object_id',
'[]', '[]=', 'delete', 'each', 'has_key?'
]
- instance_methods.each{|m| undef_method(m) unless allow.index(m)}
+ instance_methods.each{|m| undef_method(m) unless allow.index(m.to_s)}
def kind_of?(klass)
@tbl.kind_of?(klass)
@@ -206,7 +217,7 @@ class MultiTkIp
def initialize(ip, cmd)
@ip = ip
@cmd = cmd
- freeze
+ self.freeze
end
attr_reader :ip, :cmd
def inspect
@@ -573,7 +584,11 @@ class MultiTkIp
# raise exception
begin
bt = _toUTF8(e.backtrace.join("\n"))
- bt.instance_variable_set(:@encoding, 'utf-8')
+ if MultiTkIp::WITH_ENCODING
+ bt.force_encoding('utf-8')
+ else
+ bt.instance_variable_set(:@encoding, 'utf-8')
+ end
rescue Exception
bt = e.backtrace.join("\n")
end
@@ -695,6 +710,11 @@ class MultiTkIp
######################################
+ unless self.const_defined? :RUN_EVENTLOOP_ON_MAIN_THREAD
+ ### Ruby 1.9 !!!!!!!!!!!!!!!!!!!!!!!!!!
+ RUN_EVENTLOOP_ON_MAIN_THREAD = false
+ end
+
if self.const_defined? :DEFAULT_MASTER_NAME
name = DEFAULT_MASTER_NAME.to_s
else
@@ -723,7 +743,41 @@ class MultiTkIp
fail ArgumentError, "expecting a Hash object for the 2nd argument"
end
- @interp = TclTkIp.new(name, _keys2opts(keys))
+ if !WITH_RUBY_VM || RUN_EVENTLOOP_ON_MAIN_THREAD ### check Ruby 1.9 !!!!!!!
+ @interp = TclTkIp.new(name, _keys2opts(keys))
+ else ### Ruby 1.9 !!!!!!!!!!!
+ @interp_thread = Thread.new{
+ current = Thread.current
+ current[:interp] = interp = TclTkIp.new(name, _keys2opts(keys))
+ #sleep
+ current[:mutex] = mutex = Mutex.new
+ current[:root_check] = cond_var = ConditionVariable.new
+
+ begin
+ current[:status] = interp.mainloop(true)
+ rescue Exception=>e
+ current[:status] = e
+ ensure
+ mutex.synchronize{ cond_var.broadcast }
+ end
+ current[:status] = interp.mainloop(false)
+ }
+ until @interp_thread[:interp]
+ Thread.pass
+ end
+ # INTERP_THREAD.run
+ @interp = @interp_thread[:interp]
+
+ def self.mainloop(check_root = true)
+ begin
+ TclTkLib.set_eventloop_window_mode(true)
+ @interp_thread.value
+ ensure
+ TclTkLib.set_eventloop_window_mode(false)
+ end
+ end
+ end
+
@ip_name = nil
@callback_status = [].taint
@@ -853,22 +907,26 @@ class MultiTkIp
Thread.new{
current = Thread.current
loop {
- mtx, ret, table, script = @init_ip_env_queue.deq
- begin
+ mtx, cond, ret, table, script = @init_ip_env_queue.deq
+ begin
ret[0] = table.each{|tg, ip| ip._init_ip_env(script) }
rescue Exception => e
ret[0] = e
ensure
- mtx.unlock
+ mtx.synchronize{ cond.signal }
end
+ mtx = cond = ret = table = script = nil # clear variables for GC
}
}
def self.__init_ip_env__(table, script)
ret = []
- mtx = Mutex.new.lock
- @init_ip_env_queue.enq([mtx, ret, table, script])
- mtx.lock
+ mtx = (Thread.current[:MultiTk_ip_Mutex] ||= Mutex.new)
+ cond = (Thread.current[:MultiTk_ip_CondVar] ||= ConditionVariable.new)
+ mtx.synchronize{
+ @init_ip_env_queue.enq([mtx, cond, ret, table, script])
+ cond.wait(mtx)
+ }
if ret[0].kind_of?(Exception)
raise ret[0]
else
@@ -947,9 +1005,11 @@ class MultiTkIp
private :_parse_slaveopts
def _create_slave_ip_name
- name = @@SLAVE_IP_ID.join('')
- @@SLAVE_IP_ID[1].succ!
- name.freeze
+ @@SLAVE_IP_ID.mutex.synchronize{
+ name = @@SLAVE_IP_ID.join('')
+ @@SLAVE_IP_ID[1].succ!
+ name.freeze
+ }
end
private :_create_slave_ip_name
@@ -1206,7 +1266,20 @@ class MultiTkIp
if safeip == nil
# create master-ip
- @interp = TclTkIp.new(name, _keys2opts(tk_opts))
+ unless WITH_RUBY_VM
+ @interp = TclTkIp.new(name, _keys2opts(tk_opts))
+ else ### Ruby 1.9 !!!!!!!!!!!
+ @interp_thread = Thread.new{
+ Thread.current[:interp] = interp = TclTkIp.new(name, _keys2opts(tk_opts))
+ #sleep
+ TclTkLib.mainloop(true)
+ }
+ until @interp_thread[:interp]
+ Thread.pass
+ end
+ # INTERP_THREAD.run
+ @interp = @interp_thread[:interp]
+ end
@ip_name = nil
if safe
@@ -1221,6 +1294,8 @@ class MultiTkIp
@safe_base = true
@interp, @ip_name = master.__create_safe_slave_obj(safe_opts,
name, tk_opts)
+ # @interp_thread = nil if RUBY_VERSION < '1.9.0' ### !!!!!!!!!!!
+ @interp_thread = nil unless WITH_RUBY_VM ### Ruby 1.9 !!!!!!!!!!!
if safe
safe = master.safe_level if safe < master.safe_level
@safe_level = [safe]
@@ -1229,6 +1304,8 @@ class MultiTkIp
end
else
@interp, @ip_name = master.__create_trusted_slave_obj(name, tk_opts)
+ # @interp_thread = nil if RUBY_VERSION < '1.9.0' ### !!!!!!!!!!!
+ @interp_thread = nil unless WITH_RUBY_VM ### Ruby 1.9 !!!!!!!!!!!
if safe
safe = master.safe_level if safe < master.safe_level
@safe_level = [safe]
@@ -1263,11 +1340,11 @@ class MultiTkIp
@@DEFAULT_MASTER.assign_receiver_and_watchdog(self)
@@IP_TABLE[@threadgroup] = self
- _init_ip_internal(@@INIT_IP_ENV, @@ADD_TK_PROCS)
@@TK_TABLE_LIST.size.times{
(tbl = {}).tainted? || tbl.taint
@tk_table_list << tbl
}
+ _init_ip_internal(@@INIT_IP_ENV, @@ADD_TK_PROCS)
class << self
undef :instance_eval
@@ -1345,8 +1422,13 @@ class << MultiTkIp
alias __new new
private :__new
-
def new_master(safe=nil, keys={})
+ if MultiTkIp::WITH_RUBY_VM
+ #### TODO !!!!!!
+ fail RuntimeError,
+ 'sorry, still not support multiple master-interpreters on Ruby VM'
+ end
+
if safe.kind_of?(Hash)
keys = safe
elsif safe.kind_of?(Integer)
@@ -1563,8 +1645,13 @@ class MultiTkIp
return if slave?
names.each{|name|
name = name.to_s
+
+ return if @interp.deleted?
@interp._invoke('rename', name, '')
+
+ return if @interp.deleted?
@interp._invoke('interp', 'slaves').split.each{|slave|
+ return if @interp.deleted?
@interp._invoke('interp', 'alias', slave, name, '') rescue nil
}
}
@@ -1614,11 +1701,16 @@ class MultiTkIp
id = @@TK_TABLE_LIST.size
obj = Object.new
@@TK_TABLE_LIST << obj
- obj.instance_eval <<-EOD
+ obj.instance_variable_set(:@id, id)
+ obj.instance_variable_set(:@mutex, Mutex.new)
+ obj.instance_eval{
+ def self.mutex
+ @mutex
+ end
def self.method_missing(m, *args)
- MultiTkIp.tk_object_table(#{id}).__send__(m, *args)
+ MultiTkIp.tk_object_table(@id).__send__(m, *args)
end
- EOD
+ }
obj.freeze
@@IP_TABLE.each{|tg, ip| ip._add_new_tables }
return obj
@@ -2338,6 +2430,11 @@ end
class MultiTkIp
def mainloop(check_root = true, restart_on_dead = true)
raise SecurityError, "no permission to manipulate" unless self.manipulable?
+
+ if WITH_RUBY_VM ### Ruby 1.9 !!!!!!!!!!!
+ return @interp_thread.value if @interp_thread
+ end
+
#return self if self.slave?
#return self if self != @@DEFAULT_MASTER
if self != @@DEFAULT_MASTER
@@ -2746,9 +2843,10 @@ class MultiTkIp
i = -1
brace = 1
str.each_byte {|c|
+ c = c.chr
i += 1
- brace += 1 if c == ?{
- brace -= 1 if c == ?}
+ brace += 1 if c == '{'
+ brace -= 1 if c == '}'
break if brace == 0
}
if i == 0
@@ -3187,15 +3285,44 @@ end
# encoding convert
+class << MultiTkIp
+ def encoding_table
+ __getip.encoding_table
+ end
+end
class MultiTkIp
- def encoding
+ def encoding_table
+ @interp.encoding_table
+ end
+
+ def force_default_encoding=(mode)
raise SecurityError, "no permission to manipulate" unless self.manipulable?
- @interp.encoding
+ @interp.force_default_encoding = mode
end
+ def force_default_encoding?
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
+ @interp.force_default_encoding?
+ end
+
+ def default_encoding=(enc)
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
+ @interp.default_encoding = enc
+ end
+
def encoding=(enc)
raise SecurityError, "no permission to manipulate" unless self.manipulable?
@interp.encoding = enc
end
+ def encoding_name
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
+ @interp.encoding_name
+ end
+ def encoding_obj
+ raise SecurityError, "no permission to manipulate" unless self.manipulable?
+ @interp.encoding_obj
+ end
+ alias encoding encoding_name
+ alias default_encoding encoding_name
def encoding_convertfrom(str, enc=None)
raise SecurityError, "no permission to manipulate" unless self.manipulable?
@@ -3212,13 +3339,30 @@ end
# remove methods for security
+if MultiTkIp::WITH_RUBY_VM &&
+ ! MultiTkIp::RUN_EVENTLOOP_ON_MAIN_THREAD ### check Ruby 1.9 !!!!!!!
+ class MultiTkIp
+ INTERP_THREAD = @@DEFAULT_MASTER.instance_variable_get('@interp_thread')
+ INTERP_MUTEX = INTERP_THREAD[:mutex]
+ INTERP_ROOT_CHECK = INTERP_THREAD[:root_check]
+ end
+ module TkCore
+ INTERP_THREAD = MultiTkIp::INTERP_THREAD
+ INTERP_MUTEX = MultiTkIp::INTERP_MUTEX
+ INTERP_ROOT_CHECK = MultiTkIp::INTERP_ROOT_CHECK
+ end
+ class MultiTkIp
+ remove_const(:INTERP_THREAD)
+ remove_const(:INTERP_MUTEX)
+ remove_const(:INTERP_ROOT_CHECK)
+ end
+end
+
class MultiTkIp
# undef_method :instance_eval
undef_method :instance_variable_get
undef_method :instance_variable_set
end
-
-
# end of MultiTkIp definition
# defend against modification
diff --git a/ext/tk/lib/tcltk.rb b/ext/tk/lib/tcltk.rb
index 1a6694dbff..7f6f41605d 100644
--- a/ext/tk/lib/tcltk.rb
+++ b/ext/tk/lib/tcltk.rb
@@ -265,7 +265,7 @@ class TclTkWidget < TclTkCommand
# (used in TclTkInterpreter#initialize())
# need two arguments
- fail("illegal # of parameter") if args.size != 2
+ fail("invalid # of parameter") if args.size != 2
# ip: interpreter(TclTkIp)
# exp: tcl/tk representation
diff --git a/ext/tk/lib/tk.rb b/ext/tk/lib/tk.rb
index eba2f72f29..c5d5b804d2 100644
--- a/ext/tk/lib/tk.rb
+++ b/ext/tk/lib/tk.rb
@@ -1,6 +1,5 @@
#
# tk.rb - Tk interface module using tcltklib
-# $Date: 2006/07/14 04:10:49 $
# by Yukihiro Matsumoto <matz@netlab.jp>
# use Shigehiro's tcltklib
@@ -10,6 +9,9 @@ require 'tkutil'
# autoload
require 'tk/autoload'
+# for Mutex
+require 'thread'
+
class TclTkIp
# backup original (without encoding) _eval and _invoke
alias _eval_without_enc _eval
@@ -37,7 +39,12 @@ module TkComm
#Tk_CMDTBL = {}
#Tk_WINDOWS = {}
- Tk_IDs = ["00000".taint, "00000".taint].freeze # [0]-cmdid, [1]-winid
+ Tk_IDs = ["00000".taint, "00000".taint] # [0]-cmdid, [1]-winid
+ Tk_IDs.instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
# for backward compatibility
Tk_CMDTBL = Object.new
@@ -218,7 +225,9 @@ module TkComm
TkCore::INTERP.tk_windows[val]?
TkCore::INTERP.tk_windows[val] : _genobj_for_tkwidget(val)
when /\Ai(_\d+_)?\d+\z/
- TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val
+ TkImage::Tk_IMGTBL.mutex.synchronize{
+ TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val
+ }
when /\A-?\d+\.?\d*(e[-+]?\d+)?\z/
val.to_f
when /\\ /
@@ -335,6 +344,8 @@ if USE_TCLs_LIST_FUNCTIONS
if dst_enc != true && dst_enc != false
if (s_enc = s.instance_variable_get(:@encoding))
s_enc = s_enc.to_s
+ elsif TkCore::WITH_ENCODING
+ s_enc = s.encoding.name
else
s_enc = sys_enc
end
@@ -347,11 +358,20 @@ if USE_TCLs_LIST_FUNCTIONS
if sys_enc && dst_enc
dst.map!{|s| _toUTF8(s)}
ret = TkCore::INTERP._merge_tklist(*dst)
- if dst_enc.kind_of?(String)
- ret = _fromUTF8(ret, dst_enc)
- ret.instance_variable_set(:@encoding, dst_enc)
- else
- ret.instance_variable_set(:@encoding, 'utf-8')
+ if TkCore::WITH_ENCODING
+ if dst_enc.kind_of?(String)
+ ret = _fromUTF8(ret, dst_enc)
+ ret.force_encoding(dst_enc)
+ else
+ ret.force_encoding('utf-8')
+ end
+ else # without encoding
+ if dst_enc.kind_of?(String)
+ ret = _fromUTF8(ret, dst_enc)
+ ret.instance_variable_set(:@encoding, dst_enc)
+ else
+ ret.instance_variable_set(:@encoding, 'utf-8')
+ end
end
ret
else
@@ -411,46 +431,6 @@ else
tk_split_sublist(token, depth - 1)
}
end
-=begin
- def tk_split_list(str)
- return [] if str == ""
- idx = str.index('{')
- while idx and idx > 0 and str[idx-1] == ?\\
- idx = str.index('{', idx+1)
- end
- unless idx
- list = tk_tcl2ruby(str)
- unless Array === list
- list = [list]
- end
- return list
- end
-
- list = tk_tcl2ruby(str[0,idx])
- list = [] if list == ""
- str = str[idx+1..-1]
- i = -1
- escape = false
- brace = 1
- str.each_byte {|c|
- i += 1
- brace += 1 if c == ?{ && !escape
- brace -= 1 if c == ?} && !escape
- escape = (c == ?\\)
- break if brace == 0
- }
- if str.size == i + 1
- return tk_split_list(str[0, i])
- end
- 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
-=end
def tk_split_simplelist(str, src_enc=true, dst_enc=true)
return [] if str == ""
@@ -601,7 +581,9 @@ end
end
def image_obj(val)
if val =~ /^i(_\d+_)?\d+$/
- TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val
+ TkImage::Tk_IMGTBL.mutex.synchronize{
+ TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val
+ }
else
val
end
@@ -783,15 +765,17 @@ end
id = "c" + TkCore::INTERP._ip_id_ + TkComm::Tk_IDs[0]
end
def _next_cmd_id
- id = _curr_cmd_id
- #Tk_IDs[0] += 1
- TkComm::Tk_IDs[0].succ!
- id
+ TkComm::Tk_IDs.mutex.synchronize{
+ id = _curr_cmd_id
+ #Tk_IDs[0] += 1
+ TkComm::Tk_IDs[0].succ!
+ id
+ }
end
private :_curr_cmd_id, :_next_cmd_id
module_function :_curr_cmd_id, :_next_cmd_id
- def install_cmd(cmd)
+ def TkComm.install_cmd(cmd, local_cmdtbl=nil)
return '' if cmd == ''
begin
ns = TkCore::INTERP._invoke_without_enc('namespace', 'current')
@@ -810,6 +794,15 @@ end
@cmdtbl = [] unless defined? @cmdtbl
@cmdtbl.taint unless @cmdtbl.tainted?
@cmdtbl.push id
+
+ if local_cmdtbl && local_cmdtbl.kind_of?(Array)
+ begin
+ local_cmdtbl << id
+ rescue Exception
+ # ignore
+ end
+ end
+
#return Kernel.format("rb_out %s", id);
if ns
'rb_out' << TkCore::INTERP._ip_id_ << ' ' << ns << ' ' << id
@@ -817,14 +810,30 @@ end
'rb_out' << TkCore::INTERP._ip_id_ << ' ' << id
end
end
- def uninstall_cmd(id)
+ def TkComm.uninstall_cmd(id, local_cmdtbl=nil)
#id = $1 if /rb_out\S* (c(_\d+_)?\d+)/ =~ id
id = $4 if id =~ /rb_out\S*(?:\s+(::\S*|[{](::.*)[}]|["](::.*)["]))? (c(_\d+_)?(\d+))/
+
+ if local_cmdtbl && local_cmdtbl.kind_of?(Array)
+ begin
+ local_cmdtbl.delete(id)
+ rescue Exception
+ # ignore
+ end
+ end
+ @cmdtbl.delete(id)
+
#Tk_CMDTBL.delete(id)
TkCore::INTERP.tk_cmd_tbl.delete(id)
end
# private :install_cmd, :uninstall_cmd
- module_function :install_cmd, :uninstall_cmd
+ # module_function :install_cmd, :uninstall_cmd
+ def install_cmd(cmd)
+ TkComm.install_cmd(cmd, @cmdtbl)
+ end
+ def uninstall_cmd(id)
+ TkComm.uninstall_cmd(id, @cmdtbl)
+ end
=begin
def install_win(ppath,name=nil)
@@ -856,8 +865,10 @@ end
return TkCore::INTERP.tk_windows[@path] = self
end
else
- name = "w" + TkCore::INTERP._ip_id_ + Tk_IDs[1]
- Tk_IDs[1].succ!
+ Tk_IDs.mutex.synchronize{
+ name = "w" + TkCore::INTERP._ip_id_ + Tk_IDs[1]
+ Tk_IDs[1].succ!
+ }
end
if !ppath or ppath == '.'
@path = '.' + name
@@ -936,7 +947,12 @@ module TkComm
def _bindinfo(what, context=nil)
if context
- tk_call_without_enc(*what+["<#{tk_event_sequence(context)}>"]) .collect {|cmdline|
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ enum_obj = tk_call_without_enc(*what+["<#{tk_event_sequence(context)}>"]).each_line
+ else
+ enum_obj = tk_call_without_enc(*what+["<#{tk_event_sequence(context)}>"])
+ end
+ enum_obj.collect {|cmdline|
=begin
if cmdline =~ /^rb_out\S* (c(?:_\d+_)?\d+)\s+(.*)$/
#[Tk_CMDTBL[$1], $2]
@@ -1082,6 +1098,14 @@ module TkCore
include TkComm
extend TkComm
+ WITH_RUBY_VM = Object.const_defined?(:VM) && ::VM.class == Class
+ WITH_ENCODING = Object.const_defined?(:Encoding) && ::Encoding.class == Class
+
+ unless self.const_defined? :RUN_EVENTLOOP_ON_MAIN_THREAD
+ ### Ruby 1.9 !!!!!!!!!!!!!!!!!!!!!!!!!!
+ RUN_EVENTLOOP_ON_MAIN_THREAD = false
+ end
+
unless self.const_defined? :INTERP
if self.const_defined? :IP_NAME
name = IP_NAME.to_s
@@ -1099,14 +1123,49 @@ module TkCore
opts = ''
end
- INTERP = TclTkIp.new(name, opts)
+ if !WITH_RUBY_VM || RUN_EVENTLOOP_ON_MAIN_THREAD ### check Ruby 1.9 !!!!!!!
+ INTERP = TclTkIp.new(name, opts)
+ else
+ INTERP_MUTEX = Mutex.new
+ INTERP_ROOT_CHECK = ConditionVariable.new
+ INTERP_THREAD = Thread.new{
+ begin
+ Thread.current[:interp] = interp = TclTkIp.new(name, opts)
+ rescue => e
+ Thread.current[:interp] = e
+ raise e
+ end
+ Thread.current[:status] = nil
+ #sleep
+
+ begin
+ Thread.current[:status] = TclTkLib.mainloop(true)
+ rescue Exception=>e
+ Thread.current[:status] = e
+ ensure
+ INTERP_MUTEX.synchronize{ INTERP_ROOT_CHECK.broadcast }
+ end
+ Thread.current[:status] = TclTkLib.mainloop(false)
+ }
+
+ until INTERP_THREAD[:interp]
+ Thread.pass
+ end
+ # INTERP_THREAD.run
+ raise INTERP_THREAD[:interp] if INTERP_THREAD[:interp].kind_of? Exception
+
+ INTERP = INTERP_THREAD[:interp]
+ end
def INTERP.__getip
self
end
INTERP.instance_eval{
- @tk_cmd_tbl = {}.taint
+ # @tk_cmd_tbl = {}.taint
+ @tk_cmd_tbl = Hash.new{|hash, key|
+ fail IndexError, "unknown command ID '#{key}'"
+ }.taint
def @tk_cmd_tbl.[]=(idx,val)
if self.has_key?(idx) && Thread.current.group != ThreadGroup::Default
fail SecurityError,"cannot change the entried command"
@@ -1157,6 +1216,10 @@ module TkCore
class Tk_OBJECT_TABLE
def initialize(id)
@id = id
+ @mutex = Mutex.new
+ end
+ def mutex
+ @mutex
end
def method_missing(m, *args, &b)
TkCore::INTERP.tk_object_table(@id).__send__(m, *args, &b)
@@ -1235,7 +1298,7 @@ module TkCore
}) << ' %W')
INTERP.add_tk_procs(TclTkLib::FINALIZE_PROC_NAME, '',
- "bind all <#{WIDGET_DESTROY_HOOK}> {}")
+ "catch { bind all <#{WIDGET_DESTROY_HOOK}> {} }")
INTERP.add_tk_procs('rb_out', 'ns args', <<-'EOL')
if [regexp {^::} $ns] {
@@ -1342,7 +1405,11 @@ module TkCore
"\n---< backtrace of Ruby side >-----\n" +
_toUTF8(e.backtrace.join("\n")) +
"\n---< backtrace of Tk side >-------"
- msg.instance_variable_set(:@encoding, 'utf-8')
+ if TkCore::WITH_ENCODING
+ msg.force_encoding('utf-8')
+ else
+ msg.instance_variable_set(:@encoding, 'utf-8')
+ end
rescue Exception
msg = e.class.inspect + ': ' + e.message + "\n" +
"\n---< backtrace of Ruby side >-----\n" +
@@ -1398,6 +1465,13 @@ module TkCore
end
def after(ms, cmd=Proc.new)
+ cmdid = install_cmd(proc{ret = cmd.call;uninstall_cmd(cmdid); ret})
+ after_id = tk_call_without_enc("after",ms,cmdid)
+ after_id.instance_variable_set('@cmdid', cmdid)
+ after_id
+ end
+=begin
+ def after(ms, cmd=Proc.new)
crit_bup = Thread.critical
Thread.critical = true
@@ -1420,8 +1494,16 @@ module TkCore
# tk_call("after",ms,cmdid)
# end
end
+=end
def after_idle(cmd=Proc.new)
+ cmdid = install_cmd(proc{ret = cmd.call;uninstall_cmd(cmdid); ret})
+ after_id = tk_call_without_enc('after','idle',cmdid)
+ after_id.instance_variable_set('@cmdid', cmdid)
+ after_id
+ end
+=begin
+ def after_idle(cmd=Proc.new)
crit_bup = Thread.critical
Thread.critical = true
@@ -1432,9 +1514,15 @@ module TkCore
tk_call_without_enc('after','idle',cmdid)
end
+=end
def after_cancel(afterId)
tk_call_without_enc('after','cancel',afterId)
+ if (cmdid = afterId.instance_variable_get('@cmdid'))
+ afterId.instance_variable_set('@cmdid', nil)
+ uninstall_cmd(cmdid)
+ end
+ afterId
end
def windowingsystem
@@ -1554,7 +1642,27 @@ module TkCore
end
def mainloop(check_root = true)
- TclTkLib.mainloop(check_root)
+ if !TkCore::WITH_RUBY_VM || TkCore::RUN_EVENTLOOP_ON_MAIN_THREAD
+ TclTkLib.mainloop(check_root)
+ else ### Ruby 1.9 !!!!!
+ begin
+ TclTkLib.set_eventloop_window_mode(true)
+ if check_root
+ INTERP_MUTEX.synchronize{
+ INTERP_ROOT_CHECK.wait(INTERP_MUTEX)
+ status = INTERP_THREAD[:status]
+ if status
+ INTERP_THREAD[:status] = nil
+ raise status if status.kind_of?(Exception)
+ end
+ }
+ else
+ INTERP_THREAD.value
+ end
+ ensure
+ TclTkLib.set_eventloop_window_mode(false)
+ end
+ end
end
def mainloop_thread?
@@ -1562,7 +1670,12 @@ module TkCore
# nil : there is no mainloop
# false : mainloop is running on the other thread
# ( At then, it is dangerous to call Tk interpreter directly. )
- TclTkLib.mainloop_thread?
+ if !TkCore::WITH_RUBY_VM || TkCore::RUN_EVENTLOOP_ON_MAIN_THREAD
+ ### Ruby 1.9 !!!!!!!!!!!
+ TclTkLib.mainloop_thread?
+ else
+ Thread.current == INTERP_THREAD
+ end
end
def mainloop_exist?
@@ -1914,7 +2027,7 @@ module Tk
end
def root
- TkRoot.new
+ Tk::Root.new
end
def Tk.load_tclscript(file, enc=nil)
@@ -2030,6 +2143,27 @@ module Tk
tk_call_without_enc('destroy', '.')
end
+ ################################################
+
+ def Tk.sleep(ms = nil, id = nil)
+ if id
+ var = (id.kind_of?(TkVariable))? id: TkVarAccess.new(id.to_s)
+ else
+ var = TkVariable.new
+ end
+
+ var.value = tk_call_without_enc('after', ms, proc{ var.value = 0 }) if ms
+ var.thread_wait
+ ms
+ end
+
+ def Tk.wakeup(id)
+ ((id.kind_of?(TkVariable))? id: TkVarAccess.new(id.to_s)).value = 0
+ nil
+ end
+
+ ################################################
+
def Tk.pack(*args)
TkPack.configure(*args)
end
@@ -2205,16 +2339,432 @@ end
# convert kanji string to/from utf-8
###########################################
if (/^(8\.[1-9]|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK)
+ module Tk
+ module Encoding
+ extend Encoding
+
+ TkCommandNames = ['encoding'.freeze].freeze
+
+ #############################################
+
+ if TkCore::WITH_ENCODING ### Ruby 1.9
+ RubyEncoding = ::Encoding
+
+ # for saving GC cost
+ #ENCNAMES_CMD = ['encoding'.freeze, 'names'.freeze]
+ BINARY_NAME = 'binary'.freeze
+ UTF8_NAME = 'utf-8'.freeze
+ DEFAULT_EXTERNAL_NAME = RubyEncoding.default_external.name.freeze
+
+ BINARY = RubyEncoding.find(BINARY_NAME)
+ UNKNOWN = RubyEncoding.find('ASCII-8BIT')
+
+ ### start of creating ENCODING_TABLE
+ ENCODING_TABLE = TkCore::INTERP.encoding_table
+=begin
+ ENCODING_TABLE = {
+ 'binary' => BINARY,
+ # 'UNKNOWN-8BIT' => UNKNOWN,
+ }
+
+ list = TkCore::INTERP._invoke_without_enc(ENCNAMES_CMD[0],
+ ENCNAMES_CMD[1])
+ TkCore::INTERP._split_tklist(list).each{|name|
+ begin
+ enc = RubyEncoding.find(name)
+ rescue ArgumentError
+ case name
+ when 'identity'
+ enc = BINARY
+ when 'shiftjis'
+ enc = RubyEncoding.find('Shift_JIS')
+ when 'unicode'
+ enc = RubyEncoding.find('UTF-8')
+ #if Tk.tk_call('set', 'tcl_platform(byteOrder)') =='littleEndian'
+ # enc = RubyEncoding.find('UTF-16LE')
+ #else
+ # enc = RubyEncoding.find('UTF-16BE')
+ #end
+ when 'symbol'
+ # single byte data
+ enc = RubyEncoding.find('ASCII-8BIT') ### ???
+ else
+ # unsupported on Ruby, but supported on Tk
+ enc = TkCore::INTERP.create_dummy_encoding_for_tk(name)
+ end
+ end
+ ENCODING_TABLE[name.freeze] = enc
+ }
+=end
+=begin
+ def ENCODING_TABLE.get_name(enc)
+ orig_enc = enc
+
+ # unles enc, use system default
+ # 1st: Ruby/Tk default encoding
+ # 2nd: Tcl/Tk default encoding
+ # 3rd: Ruby's default_external
+ enc ||= TkCore::INTERP.encoding
+ enc ||= TclTkLib.encoding_system
+ enc ||= DEFAULT_EXTERNAL_NAME
+
+ if enc.kind_of?(RubyEncoding)
+ # Ruby's Encoding object
+ if (name = self.key(enc))
+ return name
+ end
+
+ # Is it new ?
+ list = TkCore::INTERP._invoke_without_enc(ENCNAMES_CMD[0],
+ ENCNAMES_CMD[1])
+ TkComm.simplelist(list).each{|name|
+ if ((enc == RubyEncoding.find(name)) rescue false)
+ # new relation!! update table
+ self[name.freeze] = enc
+ return name
+ end
+ }
+ else
+ # String or Symbol ?
+ if self[name = enc.to_s]
+ return name
+ end
+
+ # Is it new ?
+ if (enc_obj = (RubyEncoding.find(name) rescue false))
+ list = TkCore::INTERP._invoke_without_enc(ENCNAMES_CMD[0],
+ ENCNAMES_CMD[1])
+ if TkComm.simplelist(list).index(name)
+ # Tk's encoding name ?
+ self[name.freeze] = enc_obj # new relation!! update table
+ return name
+ else
+ # Ruby's encoding name ?
+ if (name = self.key(enc_obj))
+ return name
+ end
+ end
+ end
+ end
+
+ fail ArgumentError, "unsupported Tk encoding '#{orig_enc}'"
+ end
+
+ def ENCODING_TABLE.get_obj(enc)
+ # returns the encoding object.
+ # If 'enc' is the encoding name on Tk only, it returns nil.
+ ((obj = self[self.get_name(enc)]).kind_of?(RubyEncoding))? obj: nil
+ end
+=end
+ ### end of creating ENCODING_TABLE
+
+ end
+
+ #############################################
+
+ if TkCore::WITH_ENCODING
+ ################################
+ ### Ruby 1.9
+ ################################
+ def force_default_encoding(mode)
+ TkCore::INTERP.force_default_encoding = mode
+ end
+
+ def force_default_encoding?
+ TkCore::INTERP.force_default_encoding?
+ end
+
+ def default_encoding=(enc)
+ TkCore::INTERP.default_encoding = Tk::Encoding::ENCODING_TABLE.get_name(enc)
+ end
+
+ def encoding=(enc)
+ TkCore::INTERP.encoding = Tk::Encoding::ENCODING_TABLE.get_name(enc)
+ end
+
+ def encoding_name
+ Tk::Encoding::ENCODING_TABLE.get_name(TkCore::INTERP.encoding)
+ end
+ def encoding_obj
+ Tk::Encoding::ENCODING_TABLE.get_obj(TkCore::INTERP.encoding)
+ end
+ alias encoding encoding_name
+ alias default_encoding encoding_name
+
+ def tk_encoding_names
+ TkComm.simplelist(TkCore::INTERP._invoke_without_enc(Tk::Encoding::ENCNAMES_CMD[0], Tk::Encoding::ENCNAMES_CMD[1]))
+ end
+ def encoding_names
+ self.tk_encoding_names.find_all{|name|
+ Tk::Encoding::ENCODING_TABLE.get_name(name) rescue false
+ }
+ end
+ def encoding_objs
+ self.tk_encoding_names.map!{|name|
+ Tk::Encoding::ENCODING_TABLE.get_obj(name) rescue nil
+ }.compact
+ end
+
+ def encoding_system=(enc)
+ TclTkLib.encoding_system = Tk::Encoding::ENCODING_TABLE.get_name(enc)
+ end
+
+ def encoding_system_name
+ Tk::Encoding::ENCODING_TABLE.get_name(TclTkLib.encoding_system)
+ end
+ def encoding_system_obj
+ Tk::Encoding::ENCODING_TABLE.get_obj(TclTkLib.encoding_system)
+ end
+ alias encoding_system encoding_system_name
+
+ ################################
+ else
+ ################################
+ ### Ruby 1.8-
+ ################################
+ def force_default_encoding=(mode)
+ true
+ end
+
+ def force_default_encoding?
+ true
+ end
+
+ def default_encoding=(enc)
+ TkCore::INTERP.default_encoding = enc
+ end
+
+ def encoding=(enc)
+ TkCore::INTERP.encoding = enc
+ end
+
+ def encoding_obj
+ TkCore::INTERP.encoding
+ end
+ def encoding_name
+ TkCore::INTERP.encoding
+ end
+ alias encoding encoding_name
+ alias default_encoding encoding_name
+
+ def tk_encoding_names
+ TkComm.simplelist(Tk.tk_call('encoding', 'names'))
+ end
+ def encoding_objs
+ self.tk_encoding_names
+ end
+ def encoding_names
+ self.tk_encoding_names
+ end
+
+ def encoding_system=(enc)
+ TclTkLib.encoding_system = enc
+ end
+
+ def encoding_system_name
+ TclTkLib.encoding_system
+ end
+ def encoding_system_obj
+ TclTkLib.encoding_system
+ end
+ alias encoding_system encoding_system_name
+
+ ################################
+ end
+
+ def encoding_convertfrom(str, enc=nil)
+ enc = encoding_system_name unless enc
+ str = str.dup
+ if TkCore::WITH_ENCODING
+ if str.kind_of?(Tk::EncodedString)
+ str.__instance_variable_set('@encoding', nil)
+ else
+ str.instance_variable_set('@encoding', nil)
+ end
+ str.force_encoding('binary')
+ else
+ str.instance_variable_set('@encoding', 'binary')
+ end
+ ret = TkCore::INTERP._invoke_without_enc('encoding', 'convertfrom',
+ enc, str)
+ if TkCore::WITH_ENCODING
+ ret.force_encoding('utf-8')
+ else
+ Tk::UTF8_String.new(ret)
+ end
+ ret
+ end
+ alias encoding_convert_from encoding_convertfrom
+
+ def encoding_convertto(str, enc=nil)
+ # str must be a UTF-8 string
+ enc = encoding_system_name unless enc
+ ret = TkCore::INTERP._invoke_without_enc('encoding', 'convertto',
+ enc, str)
+ #ret.instance_variable_set('@encoding', 'binary')
+ if TkCore::WITH_ENCODING
+ #ret.force_encoding(Tk::Encoding::ENCODING_TABLE.get_obj('binary'))
+ ret.force_encoding(Tk::Encoding::ENCODING_TABLE.get_obj(enc))
+ end
+ ret
+ end
+ alias encoding_convert_to encoding_convertto
+
+ def encoding_dirs
+ # Tcl8.5 feature
+ TkComm.simplelist(Tk.tk_call_without_enc('encoding', 'dirs'))
+ end
+
+ def encoding_dirs=(dir_list) # an array or a Tcl's list string
+ # Tcl8.5 feature
+ Tk.tk_call_without_enc('encoding', 'dirs', dir_list)
+ end
+ end
+
+ extend Encoding
+ end
+
class TclTkIp
+ def force_default_encoding=(mode)
+ @force_default_encoding = (mode)? true: false
+ end
+
+ def force_default_encoding?
+ @force_default_encoding ||= false
+ end
+
+ def default_encoding=(name)
+ name = name.name if name.kind_of?(::Encoding) if Tk::WITH_ENCODING
+ @encoding = name
+ end
+
# from tkencoding.rb by ttate@jaist.ac.jp
- attr_accessor :encoding
+ #attr_accessor :encoding
+ def encoding=(name)
+ self.force_default_encoding = true # for comaptibility
+ self.default_encoding = name
+ end
- alias __eval _eval
- alias __invoke _invoke
+ def encoding_name
+ (@encoding)? @encoding.dup: nil
+ end
+ alias encoding encoding_name
+ alias default_encoding encoding_name
+
+ def encoding_obj
+ if Tk::WITH_ENCODING
+ Tk::Encoding.tcl2rb_encoding(@encoding)
+ else
+ (@encoding)? @encoding.dup: nil
+ end
+ end
alias __toUTF8 _toUTF8
alias __fromUTF8 _fromUTF8
+ if Object.const_defined?(:Encoding) && ::Encoding.class == Class
+ # with Encoding (Ruby 1.9+)
+ #
+ # use functions on Tcl as default.
+ # but when unsupported encoding on Tcl, use methods on Ruby.
+ #
+ def _toUTF8(str, enc = nil)
+ if enc
+ # use given encoding
+ begin
+ enc_name = Tk::Encoding::ENCODING_TABLE.get_name(enc)
+ rescue
+ # unknown encoding for Tk -> try to convert encoding on Ruby
+ str = str.dup.force_encoding(enc)
+ str.encode!(Tk::Encoding::UTF8_NAME) # modify self !!
+ return str # if no error, probably succeed converting
+ end
+ end
+
+ enc_name ||= str.instance_variable_get(:@encoding)
+
+ enc_name ||=
+ Tk::Encoding::ENCODING_TABLE.get_name(str.encoding) rescue nil
+
+ unless enc_name
+ # str.encoding isn't supported by Tk -> try to convert on Ruby
+ begin
+ return str.encode(Tk::Encoding::UTF8_NAME) # new string
+ rescue
+ # error -> ignore, try to use default encoding of Ruby/Tk
+ end
+ end
+
+ #enc_name ||=
+ # Tk::Encoding::ENCODING_TABLE.get_name(Tk.encoding) rescue nil
+ enc_name ||= Tk::Encoding::ENCODING_TABLE.get_name(nil)
+
+ # is 'binary' encoding?
+ if enc_name == Tk::Encoding::BINARY_NAME
+ return str.dup.force_encoding(Tk::Encoding::BINARY_NAME)
+ end
+
+ # force default encoding?
+ if ! str.kind_of?(Tk::EncodedString) && self.force_default_encoding?
+ enc_name = Tk::Encoding::ENCODING_TABLE.get_name(Tk.default_encoding)
+ end
+
+ encstr = __toUTF8(str, enc_name)
+ encstr.force_encoding(Tk::Encoding::UTF8_NAME)
+ encstr
+ end
+ def _fromUTF8(str, enc = nil)
+ # str must be UTF-8 or binary.
+ enc_name = str.instance_variable_get(:@encoding)
+ enc_name ||=
+ Tk::Encoding::ENCODING_TABLE.get_name(str.encoding) rescue nil
+
+ # is 'binary' encoding?
+ if enc_name == Tk::Encoding::BINARY_NAME
+ return str.dup.force_encoding(Tk::Encoding::BINARY_NAME)
+ end
+
+ # get target encoding name (if enc == nil, use default encoding)
+ begin
+ enc_name = Tk::Encoding::ENCODING_TABLE.get_name(enc)
+ rescue
+ # then, enc != nil
+ # unknown encoding for Tk -> try to convert encoding on Ruby
+ str = str.dup.force_encoding(Tk::Encoding::UTF8_NAME)
+ str.encode!(enc) # modify self !!
+ return str # if no error, probably succeed converting
+ end
+
+ encstr = __fromUTF8(str, enc_name)
+ encstr.force_encoding(Tk::Encoding::ENCODING_TABLE.get_obj(enc_name))
+ encstr
+ end
+ ###
+ else
+ # without Encoding (Ruby 1.8)
+ def _toUTF8(str, encoding = nil)
+ __toUTF8(str, encoding)
+ end
+ def _fromUTF8(str, encoding = nil)
+ __fromUTF8(str, encoding)
+ end
+ ###
+ end
+
+ alias __eval _eval
+ alias __invoke _invoke
+
+ def _eval(cmd)
+ _fromUTF8(__eval(_toUTF8(cmd)))
+ end
+
+ def _invoke(*cmds)
+ _fromUTF8(__invoke(*(cmds.collect{|cmd| _toUTF8(cmd)})))
+ end
+
+ alias _eval_with_enc _eval
+ alias _invoke_with_enc _invoke
+
=begin
#### --> definition is moved to TclTkIp module
@@ -2264,17 +2814,6 @@ if (/^(8\.[1-9]|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK)
end
=end
- def _eval(cmd)
- _fromUTF8(__eval(_toUTF8(cmd)))
- end
-
- def _invoke(*cmds)
- _fromUTF8(__invoke(*(cmds.collect{|cmd| _toUTF8(cmd)})))
- end
-
- alias _eval_with_enc _eval
- alias _invoke_with_enc _invoke
-
=begin
def _eval(cmd)
if defined?(@encoding) && @encoding != 'utf-8'
@@ -2331,127 +2870,214 @@ if (/^(8\.[1-9]|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK)
module TclTkLib
class << self
- alias _encoding encoding
- alias _encoding= encoding=
- def encoding=(name)
- TkCore::INTERP.encoding = name
+ def force_default_encoding=(mode)
+ TkCore::INTERP.force_default_encoding = mode
end
- def encoding
- TkCore::INTERP.encoding
- end
- end
- end
- module Tk
- module Encoding
- extend Encoding
+ def force_default_encoding?
+ TkCore::INTERP.force_default_encoding?
+ end
- TkCommandNames = ['encoding'.freeze].freeze
+ def default_encoding=(name)
+ TkCore::INTERP.default_encoding = name
+ end
+ alias _encoding encoding
+ alias _encoding= encoding=
def encoding=(name)
+ name = name.name if name.kind_of?(::Encoding) if Tk::WITH_ENCODING
TkCore::INTERP.encoding = name
end
- def encoding
+ def encoding_name
TkCore::INTERP.encoding
end
+ alias encoding encoding_name
+ alias default_encoding encoding_name
- def encoding_names
- TkComm.simplelist(Tk.tk_call('encoding', 'names'))
+ def encoding_obj
+ if Tk::WITH_ENCODING
+ Tk::Encoding.tcl2rb_encoding(TkCore::INTERP.encoding)
+ else
+ TkCore::INTERP.encoding
+ end
end
+ end
+ end
- def encoding_system
- Tk.tk_call('encoding', 'system')
+ # estimate encoding
+ unless TkCore::WITH_ENCODING
+ case $KCODE
+ when /^e/i # EUC
+ Tk.encoding = 'euc-jp'
+ Tk.encoding_system = 'euc-jp'
+ when /^s/i # SJIS
+ begin
+ if Tk.encoding_system == 'cp932'
+ Tk.encoding = 'cp932'
+ else
+ Tk.encoding = 'shiftjis'
+ Tk.encoding_system = 'shiftjis'
+ end
+ rescue StandardError, NameError
+ Tk.encoding = 'shiftjis'
+ Tk.encoding_system = 'shiftjis'
end
-
- def encoding_system=(enc)
- Tk.tk_call('encoding', 'system', enc)
+ when /^u/i # UTF8
+ Tk.encoding = 'utf-8'
+ Tk.encoding_system = 'utf-8'
+ else # NONE
+ if defined? DEFAULT_TK_ENCODING
+ Tk.encoding_system = DEFAULT_TK_ENCODING
end
-
- def encoding_convertfrom(str, enc=nil)
- # str is an usual enc string or a Tcl's internal string expression
- # in enc (which is returned from 'encoding_convertto' method).
- # the return value is a UTF-8 string.
- enc = encoding_system unless enc
- ret = TkCore::INTERP.__invoke('encoding', 'convertfrom', enc, str)
- ret.instance_variable_set('@encoding', 'utf-8')
- ret
+ begin
+ Tk.encoding = Tk.encoding_system
+ rescue StandardError, NameError
+ Tk.encoding = 'utf-8'
+ Tk.encoding_system = 'utf-8'
end
- alias encoding_convert_from encoding_convertfrom
+ end
- def encoding_convertto(str, enc=nil)
- # str must be a UTF-8 string.
- # The return value is a Tcl's internal string expression in enc.
- # To get an usual enc string, use Tk.fromUTF8(ret_val, enc).
- enc = encoding_system unless enc
- ret = TkCore::INTERP.__invoke('encoding', 'convertto', enc, str)
- ret.instance_variable_set('@encoding', 'binary')
- ret
- end
- alias encoding_convert_to encoding_convertto
+ else ### Ruby 1.9 !!!!!!!!!!!!
+ loc_enc_obj = ::Encoding.find(::Encoding.locale_charmap)
+ ext_enc_obj = ::Encoding.default_external
+ tksys_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(Tk.encoding_system)
+ # p [Tk.encoding, Tk.encoding_system, loc_enc_obj, ext_enc_obj]
- def encoding_dirs
- # Tcl8.5 feature
- TkComm.simplelist(Tk.tk_call_without_enc('encoding', 'dirs'))
+=begin
+ if ext_enc_obj == Tk::Encoding::UNKNOWN
+ if defind? DEFAULT_TK_ENCODING
+ if DEFAULT_TK_ENCODING.kind_of?(::Encoding)
+ tk_enc_name = DEFAULT_TK_ENCODING.name
+ tksys_enc_name = DEFAULT_TK_ENCODING.name
+ else
+ tk_enc_name = DEFAULT_TK_ENCODING
+ tksys_enc_name = DEFAULT_TK_ENCODING
+ end
+ else
+ tk_enc_name = loc_enc_obj.name
+ tksys_enc_name = loc_enc_obj.name
end
+ else
+ tk_enc_name = ext_enc_obj.name
+ tksys_enc_name = ext_enc_obj.name
+ end
- def encoding_dirs=(dir_list) # an array or a Tcl's list string
- # Tcl8.5 feature
- Tk.tk_call_without_enc('encoding', 'dirs', dir_list)
+ # Tk.encoding = tk_enc_name
+ Tk.default_encoding = tk_enc_name
+ Tk.encoding_system = tksys_enc_name
+=end
+
+ if ext_enc_obj == Tk::Encoding::UNKNOWN
+ if loc_enc_obj == Tk::Encoding::UNKNOWN
+ # use Tk.encoding_system
+ else
+ # use locale_charmap
+ begin
+ loc_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(loc_enc_obj)
+ if loc_enc_name && loc_enc_name != tksys_enc_name
+ # use locale_charmap
+ Tk.encoding_system = loc_enc_name
+ else
+ # use Tk.encoding_system
+ end
+ rescue ArgumentError
+ # unsupported encoding on Tk -> use Tk.encoding_system
+ end
+ end
+ else
+ begin
+ ext_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(ext_enc_obj)
+ if ext_enc_name && ext_enc_name != tksys_enc_name
+ # use default_external
+ Tk.encoding_system = ext_enc_name
+ else
+ # use Tk.encoding_system
+ end
+ rescue ArgumentError
+ # unsupported encoding on Tk -> use Tk.encoding_system
end
end
- extend Encoding
- end
+ # setup Tk.encoding
+ enc_name = nil
- # estimate encoding
- case $KCODE
- when /^e/i # EUC
- Tk.encoding = 'euc-jp'
- Tk.encoding_system = 'euc-jp'
- when /^s/i # SJIS
begin
- if Tk.encoding_system == 'cp932'
- Tk.encoding = 'cp932'
- else
- Tk.encoding = 'shiftjis'
- Tk.encoding_system = 'shiftjis'
+ default_def = DEFAULT_TK_ENCODING
+ if ::Encoding.find(default_def.to_s) != Tk::Encoding::UNKNOWN
+ enc_name = Tk::Encoding::ENCODING_TABLE.get_name(default_def)
end
- rescue StandardError, NameError
- Tk.encoding = 'shiftjis'
- Tk.encoding_system = 'shiftjis'
- end
- when /^u/i # UTF8
- Tk.encoding = 'utf-8'
- Tk.encoding_system = 'utf-8'
- else # NONE
- if defined? DEFAULT_TK_ENCODING
- Tk.encoding_system = DEFAULT_TK_ENCODING
+ rescue NameError
+ # ignore
+ enc_name = nil
+ rescue ArgumentError
+ enc_name = nil
+ fail ArgumentError,
+ "DEFAULT_TK_ENCODING has an unknown encoding #{default_def}"
end
- begin
- Tk.encoding = Tk.encoding_system
- rescue StandardError, NameError
- Tk.encoding = 'utf-8'
- Tk.encoding_system = 'utf-8'
+
+ unless enc_name
+ if ext_enc_obj == Tk::Encoding::UNKNOWN
+ if loc_enc_obj == Tk::Encoding::UNKNOWN
+ # use Tk.encoding_system
+ enc_name = tksys_enc_name
+ else
+ # use locale_charmap
+ begin
+ loc_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(loc_enc_obj)
+ if loc_enc_name && loc_enc_name != tksys_enc_name
+ # use locale_charmap
+ enc_name = loc_enc_name
+ else
+ # use Tk.encoding_system
+ enc_name = tksys_enc_name
+ end
+ rescue ArgumentError
+ # unsupported encoding on Tk -> use Tk.encoding_system
+ enc_name = tksys_enc_name
+ end
+ end
+ else
+ begin
+ ext_enc_name = Tk::Encoding::ENCODING_TABLE.get_name(ext_enc_obj)
+ if ext_enc_name && ext_enc_name != tksys_enc_name
+ # use default_external
+ enc_name = ext_enc_name
+ else
+ # use Tk.encoding_system
+ enc_name = tksys_enc_name
+ end
+ rescue ArgumentError
+ # unsupported encoding on Tk -> use Tk.encoding_system
+ enc_name = tksys_enc_name
+ end
+ end
end
+
+ Tk.default_encoding = (enc_name)? enc_name: tksys_enc_name
end
else
# dummy methods
- class TclTkIp
- attr_accessor :encoding
-
- alias __eval _eval
- alias __invoke _invoke
-
- alias _eval_with_enc _eval
- alias _invoke_with_enc _invoke
- end
-
module Tk
module Encoding
extend Encoding
+ def force_default_encoding=(mode)
+ nil
+ end
+
+ def force_default_encoding?
+ nil
+ end
+
+ def default_encoding=(enc)
+ nil
+ end
+ def default_encoding
+ nil
+ end
+
def encoding=(name)
nil
end
@@ -2487,6 +3113,16 @@ else
extend Encoding
end
+
+ class TclTkIp
+ attr_accessor :encoding
+
+ alias __eval _eval
+ alias __invoke _invoke
+
+ alias _eval_with_enc _eval
+ alias _invoke_with_enc _invoke
+ end
end
@@ -2609,7 +3245,15 @@ module TkTreatFont
next
else
fnt = hash_kv(fnt) if fnt.kind_of?(Hash)
- tk_call(*(__config_cmd << "-#{optkey}" << fnt))
+ unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ tk_call(*(__config_cmd << "-#{optkey}" << fnt))
+ else
+ begin
+ tk_call(*(__config_cmd << "-#{optkey}" << fnt))
+ rescue
+ # ignore
+ end
+ end
end
end
next
@@ -2663,7 +3307,15 @@ module TkTreatFont
fobj = fontobj # create a new TkFont object
else
ltn = hash_kv(ltn) if ltn.kind_of?(Hash)
- tk_call(*(__config_cmd << "-#{optkey}" << ltn))
+ unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ tk_call(*(__config_cmd << "-#{optkey}" << ltn))
+ else
+ begin
+ tk_call(*(__config_cmd << "-#{optkey}" << ltn))
+ rescue => e
+ # ignore
+ end
+ end
next
end
@@ -2715,7 +3367,15 @@ module TkTreatFont
fobj = fontobj # create a new TkFont object
else
knj = hash_kv(knj) if knj.kind_of?(Hash)
- tk_call(*(__config_cmd << "-#{optkey}" << knj))
+ unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ tk_call(*(__config_cmd << "-#{optkey}" << knj))
+ else
+ begin
+ tk_call(*(__config_cmd << "-#{optkey}" << knj))
+ rescue => e
+ # ignore
+ end
+ end
next
end
@@ -2816,6 +3476,14 @@ module TkConfigMethod
include TkUtil
include TkTreatFont
+ def TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ @mode || false
+ end
+ def TkConfigMethod.__set_IGNORE_UNKNOWN_CONFIGURE_OPTION__!(mode)
+ fail SecurityError, "can't change the mode" if $SAFE>=4
+ @mode = (mode)? true: false
+ end
+
def __cget_cmd
[self.path, 'cget']
end
@@ -2829,7 +3497,7 @@ module TkConfigMethod
def __confinfo_cmd
__config_cmd
end
- private :__config_cmd
+ private :__confinfo_cmd
def __configinfo_struct
{:key=>0, :alias=>1, :db_name=>1, :db_class=>2,
@@ -2837,6 +3505,11 @@ module TkConfigMethod
end
private :__configinfo_struct
+ def __optkey_aliases
+ {}
+ end
+ private :__optkey_aliases
+
def __numval_optkeys
[]
end
@@ -2926,6 +3599,7 @@ module TkConfigMethod
}
keys2
end
+ private :__conv_keyonly_opts
def config_hash_kv(keys, enc_mode = nil, conf = nil)
hash_kv(__conv_keyonly_opts(keys), enc_mode, conf)
@@ -2942,7 +3616,7 @@ module TkConfigMethod
val
end
- def cget(slot)
+ def __cget_core(slot)
orig_slot = slot
slot = slot.to_s
@@ -2950,6 +3624,11 @@ module TkConfigMethod
fail ArgumentError, "Invalid option `#{orig_slot.inspect}'"
end
+ alias_name, real_name = __optkey_aliases.find{|k, v| k.to_s == slot}
+ if real_name
+ slot = real_name.to_s
+ end
+
if ( method = _symbolkey2str(__val2ruby_optkeys())[slot] )
optval = tk_call_without_enc(*(__cget_cmd << "-#{slot}"))
begin
@@ -3018,11 +3697,41 @@ module TkConfigMethod
tk_tcl2ruby(tk_call_without_enc(*(__cget_cmd << "-#{slot}")), true)
end
end
+ private :__cget_core
- def configure(slot, value=None)
+ def cget(slot)
+ unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ __cget_core(slot)
+ else
+ begin
+ __cget_core(slot)
+ rescue => e
+ if current_configinfo.has_key?(slot.to_s)
+ # error on known option
+ fail e
+ else
+ # unknown option
+ nil
+ end
+ end
+ end
+ end
+ def cget_strict(slot)
+ # never use TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ __cget_core(slot)
+ end
+
+ def __configure_core(slot, value=None)
if slot.kind_of? Hash
slot = _symbolkey2str(slot)
+ __optkey_aliases.each{|alias_name, real_name|
+ alias_name = alias_name.to_s
+ if slot.has_key?(alias_name)
+ slot[real_name.to_s] = slot.delete(alias_name)
+ end
+ }
+
__methodcall_optkeys.each{|key, method|
value = slot.delete(key.to_s)
self.__send__(method, value) if value
@@ -3059,6 +3768,11 @@ module TkConfigMethod
fail ArgumentError, "Invalid option `#{orig_slot.inspect}'"
end
+ alias_name, real_name = __optkey_aliases.find{|k, v| k.to_s == slot}
+ if real_name
+ slot = real_name.to_s
+ end
+
if ( conf = __keyonly_optkeys.find{|k, v| k.to_s == slot} )
defkey, undefkey = conf
if value
@@ -3082,12 +3796,55 @@ module TkConfigMethod
end
self
end
+ private :__configure_core
+
+ def __check_available_configure_options(keys)
+ availables = self.current_configinfo.keys
+
+ # add non-standard keys
+ availables |= __font_optkeys.map{|k|
+ [k.to_s, "latin#{k}", "ascii#{k}", "kanji#{k}"]
+ }.flatten
+ availables |= __methodcall_optkeys.keys.map{|k| k.to_s}
+ availables |= __keyonly_optkeys.keys.map{|k| k.to_s}
+
+ keys = _symbolkey2str(keys)
+ keys.delete_if{|k, v| !(availables.include?(k))}
+ end
+
+ def configure(slot, value=None)
+ unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ __configure_core(slot, value)
+ else
+ if slot.kind_of?(Hash)
+ begin
+ __configure_core(slot)
+ rescue
+ slot = __check_available_configure_options(slot)
+ __configure_core(slot) unless slot.empty?
+ end
+ else
+ begin
+ __configure_core(slot, value)
+ rescue => e
+ if current_configinfo.has_key?(slot.to_s)
+ # error on known option
+ fail e
+ else
+ # unknown option
+ nil
+ end
+ end
+ end
+ end
+ self
+ end
def configure_cmd(slot, value)
configure(slot, install_cmd(value))
end
- def configinfo(slot = nil)
+ def __configinfo_core(slot = nil)
if TkComm::GET_CONFIGINFO_AS_ARRAY
if (slot &&
slot.to_s =~ /^(|latin|ascii|kanji)(#{__font_optkeys.join('|')})$/)
@@ -3098,6 +3855,10 @@ module TkConfigMethod
conf[__configinfo_struct[:key]][1..-1]
if ( ! __configinfo_struct[:alias] \
|| conf.size > __configinfo_struct[:alias] + 1 )
+ fnt = conf[__configinfo_struct[:default_value]]
+ if TkFont.is_system_font?(fnt)
+ conf[__configinfo_struct[:default_value]] = TkNamedFont.new(fnt)
+ end
conf[__configinfo_struct[:current_value]] = fontobj(fontkey)
elsif ( __configinfo_struct[:alias] \
&& conf.size == __configinfo_struct[:alias] + 1 \
@@ -3109,6 +3870,12 @@ module TkConfigMethod
else
if slot
slot = slot.to_s
+
+ alias_name, real_name = __optkey_aliases.find{|k, v| k.to_s == slot}
+ if real_name
+ slot = real_name.to_s
+ end
+
case slot
when /^(#{__val2ruby_optkeys().keys.join('|')})$/
method = _symbolkey2str(__val2ruby_optkeys())[slot]
@@ -3434,6 +4201,11 @@ module TkConfigMethod
fontconf = ret.assoc(optkey)
if fontconf && fontconf.size > 2
ret.delete_if{|inf| inf[0] =~ /^(|latin|ascii|kanji)#{optkey}$/}
+ fnt = fontconf[__configinfo_struct[:default_value]]
+ if TkFont.is_system_font?(fnt)
+ fontconf[__configinfo_struct[:default_value]] \
+ = TkNamedFont.new(fnt)
+ end
fontconf[__configinfo_struct[:current_value]] = fontobj(optkey)
ret.push(fontconf)
end
@@ -3458,6 +4230,10 @@ module TkConfigMethod
if ( ! __configinfo_struct[:alias] \
|| conf.size > __configinfo_struct[:alias] + 1 )
+ fnt = conf[__configinfo_struct[:default_value]]
+ if TkFont.is_system_font?(fnt)
+ conf[__configinfo_struct[:default_value]] = TkNamedFont.new(fnt)
+ end
conf[__configinfo_struct[:current_value]] = fontobj(fontkey)
{ conf.shift => conf }
elsif ( __configinfo_struct[:alias] \
@@ -3473,6 +4249,12 @@ module TkConfigMethod
else
if slot
slot = slot.to_s
+
+ alias_name, real_name = __optkey_aliases.find{|k, v| k.to_s == slot}
+ if real_name
+ slot = real_name.to_s
+ end
+
case slot
when /^(#{__val2ruby_optkeys().keys.join('|')})$/
method = _symbolkey2str(__val2ruby_optkeys())[slot]
@@ -3805,6 +4587,11 @@ module TkConfigMethod
ret.delete('latin' << optkey)
ret.delete('ascii' << optkey)
ret.delete('kanji' << optkey)
+ fnt = fontconf[__configinfo_struct[:default_value]]
+ if TkFont.is_system_font?(fnt)
+ fontconf[__configinfo_struct[:default_value]] \
+ = TkNamedFont.new(fnt)
+ end
fontconf[__configinfo_struct[:current_value]] = fontobj(optkey)
ret[optkey] = fontconf
end
@@ -3819,6 +4606,19 @@ module TkConfigMethod
end
end
end
+ private :__configinfo_core
+
+ def configinfo(slot = nil)
+ if slot && TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ begin
+ __configinfo_core(slot)
+ rescue
+ Array.new(__configinfo_struct.values.max).unshift(slot.to_s)
+ end
+ else
+ __configinfo_core(slot)
+ end
+ end
def current_configinfo(slot = nil)
if TkComm::GET_CONFIGINFO_AS_ARRAY
@@ -3918,7 +4718,12 @@ class TkObject<TkKernel
begin
cget(name)
rescue
- super(id, *args)
+ if self.kind_of?(TkWindow)
+ fail NameError,
+ "unknown option '#{id}' for #{self.inspect} (deleted widget?)"
+ else
+ super(id, *args)
+ end
# fail NameError,
# "undefined local variable or method `#{name}' for #{self.to_s}",
# error_at
@@ -3973,6 +4778,15 @@ end
class TkWindow<TkObject
include TkWinfo
extend TkBindCore
+ include Tk::Wm_for_General
+
+ @@WIDGET_INSPECT_FULL = false
+ def TkWindow._widget_inspect_full_?
+ @@WIDGET_INSPECT_FULL
+ end
+ def TkWindow._widget_inspect_full_=(mode)
+ @@WIDGET_INSPECT_FULL = (mode && true) || false
+ end
TkCommandNames = [].freeze
## ==> If TkCommandNames[0] is a string (not a null string),
@@ -4036,6 +4850,13 @@ class TkWindow<TkObject
fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey)
}
+ __optkey_aliases.each{|alias_name, real_name|
+ alias_name = alias_name.to_s
+ if keys.has_key?(alias_name)
+ keys[real_name.to_s] = keys.delete(alias_name)
+ end
+ }
+
__methodcall_optkeys.each{|key|
key = key.to_s
methodkeys[key] = keys.delete(key) if keys.key?(key)
@@ -4068,13 +4889,48 @@ class TkWindow<TkObject
end
if keys and keys != None
- tk_call_without_enc(cmd, @path, *hash_kv(keys, true))
+ unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ tk_call_without_enc(cmd, @path, *hash_kv(keys, true))
+ else
+ begin
+ tk_call_without_enc(cmd, @path, *hash_kv(keys, true))
+ rescue => e
+ tk_call_without_enc(cmd, @path)
+ keys = __check_available_configure_options(keys)
+ unless keys.empty?
+ begin
+ # try to configure
+ configure(keys)
+ rescue
+ # fail => includes options adaptable when creattion only?
+ begin
+ tk_call_without_enc('destroy', @path)
+ rescue
+ # cannot rescue options error
+ fail e
+ else
+ # re-create widget
+ tk_call_without_enc(cmd, @path, *hash_kv(keys, true))
+ end
+ end
+ end
+ end
+ end
else
tk_call_without_enc(cmd, @path)
end
end
private :create_self
+ def inspect
+ if @@WIDGET_INSPECT_FULL
+ super
+ else
+ str = super
+ str[0..(str.index(' '))] << '@path=' << @path.inspect << '>'
+ end
+ end
+
def exist?
TkWinfo.exist?(self)
end
@@ -4196,6 +5052,15 @@ class TkWindow<TkObject
self
end
+ def grid_anchor(anchor=None)
+ if anchor == None
+ TkGrid.anchor(self)
+ else
+ TkGrid.anchor(self, anchor)
+ self
+ end
+ end
+
def grid_forget
#tk_call('grid', 'forget', epath)
TkGrid.forget(self)
@@ -4227,12 +5092,14 @@ class TkWindow<TkObject
TkGrid.columnconfigure(self, index, keys)
end
alias grid_columnconfigure grid_columnconfig
+ alias grid_column grid_columnconfig
def grid_rowconfig(index, keys)
#tk_call('grid', 'rowconfigure', epath, index, *hash_kv(keys))
TkGrid.rowconfigure(self, index, keys)
end
alias grid_rowconfigure grid_rowconfig
+ alias grid_row grid_rowconfig
def grid_columnconfiginfo(index, slot=nil)
#if slot
@@ -4475,11 +5342,13 @@ class TkWindow<TkObject
end
children.each{|path, obj|
- if defined?(@cmdtbl)
- for id in @cmdtbl
- uninstall_cmd id
+ obj.instance_eval{
+ if defined?(@cmdtbl)
+ for id in @cmdtbl
+ uninstall_cmd id
+ end
end
- end
+ }
TkCore::INTERP.tk_windows.delete(path)
}
@@ -4584,7 +5453,7 @@ class TkWindow<TkObject
bindtags(bindtags().unshift(tag))
end
end
-
+TkWidget = TkWindow
# freeze core modules
#TclTkLib.freeze
@@ -4597,7 +5466,7 @@ end
#Tk.freeze
module Tk
- RELEASE_DATE = '2006-07-14'.freeze
+ RELEASE_DATE = '2008-05-23'.freeze
autoload :AUTO_PATH, 'tk/variable'
autoload :TCL_PACKAGE_PATH, 'tk/variable'
@@ -4609,6 +5478,7 @@ end
# call setup script for Tk extension libraries (base configuration)
begin
+ require 'tkextlib/version.rb'
require 'tkextlib/setup.rb'
rescue LoadError
# ignore
diff --git a/ext/tk/lib/tk/after.rb b/ext/tk/lib/tk/after.rb
index 24a048ee32..8c58210331 100644
--- a/ext/tk/lib/tk/after.rb
+++ b/ext/tk/lib/tk/after.rb
@@ -1,6 +1,6 @@
#
# tk/after.rb : methods for Tcl/Tk after command
#
-# $Id: after.rb,v 1.1.2.1 2004/05/01 16:09:49 nagai Exp $
+# $Id$
#
require 'tk/timer'
diff --git a/ext/tk/lib/tk/autoload.rb b/ext/tk/lib/tk/autoload.rb
index 6b3773f4ea..0773f7708d 100644
--- a/ext/tk/lib/tk/autoload.rb
+++ b/ext/tk/lib/tk/autoload.rb
@@ -1,9 +1,19 @@
#
# autoload
#
-
-#######################
+############################################
# geometry manager
+module Tk
+ autoload :Grid, 'tk/grid'
+ def Grid(*args); TkGrid.configure(*args); end
+
+ autoload :Pack, 'tk/pack'
+ def Pack(*args); TkPack.configure(*args); end
+
+ autoload :Place, 'tk/place'
+ def Place(*args); TkPlace.configure(*args); end
+end
+
autoload :TkGrid, 'tk/grid'
def TkGrid(*args); TkGrid.configure(*args); end
@@ -14,19 +24,117 @@ autoload :TkPlace, 'tk/place'
def TkPlace(*args); TkPlace.configure(*args); end
-#######################
-# others
+############################################
+# classes on Tk module
+module Tk
+ autoload :Button, 'tk/button'
+
+ autoload :Canvas, 'tk/canvas'
+
+ autoload :CheckButton, 'tk/checkbutton'
+ autoload :Checkbutton, 'tk/checkbutton'
+
+ autoload :Entry, 'tk/entry'
+
+ autoload :Frame, 'tk/frame'
+
+ autoload :Label, 'tk/label'
+
+ autoload :LabelFrame, 'tk/labelframe'
+ autoload :Labelframe, 'tk/labelframe'
+
+ autoload :Listbox, 'tk/listbox'
+
+ autoload :Menu, 'tk/menu'
+ autoload :MenuClone, 'tk/menu'
+ autoload :CloneMenu, 'tk/menu'
+ autoload :SystemMenu, 'tk/menu'
+ autoload :SysMenu_Help, 'tk/menu'
+ autoload :SysMenu_System, 'tk/menu'
+ autoload :SysMenu_Apple, 'tk/menu'
+ autoload :Menubutton, 'tk/menu'
+ autoload :MenuButton, 'tk/menu'
+ autoload :OptionMenubutton, 'tk/menu'
+ autoload :OptionMenBbutton, 'tk/menu'
+
+ autoload :Message, 'tk/message'
+
+ autoload :PanedWindow, 'tk/panedwindow'
+ autoload :Panedwindow, 'tk/panedwindow'
+
+ autoload :RadioButton, 'tk/radiobutton'
+ autoload :Radiobutton, 'tk/radiobutton'
+
+ autoload :Root, 'tk/root'
+
+ autoload :Scale, 'tk/scale'
+
+ autoload :Scrollbar, 'tk/scrollbar'
+ autoload :XScrollbar, 'tk/scrollbar'
+ autoload :YScrollbar, 'tk/scrollbar'
+
+ autoload :Spinbox, 'tk/spinbox'
+
+ autoload :Text, 'tk/text'
+
+ autoload :Toplevel, 'tk/toplevel'
+end
+
+
+############################################
+# sub-module of Tk
+module Tk
+ autoload :Clock, 'tk/clock'
+
+ autoload :OptionObj, 'tk/optionobj'
+
+ autoload :X_Scrollable, 'tk/scrollable'
+ autoload :Y_Scrollable, 'tk/scrollable'
+ autoload :Scrollable, 'tk/scrollable'
+
+ autoload :Wm, 'tk/wm'
+ autoload :Wm_for_General, 'tk/wm'
+
+ autoload :MacResource, 'tk/macpkg'
+
+ autoload :WinDDE, 'tk/winpkg'
+ autoload :WinRegistry, 'tk/winpkg'
+
+ autoload :ValidateConfigure, 'tk/validation'
+ autoload :ItemValidateConfigure, 'tk/validation'
+
+ autoload :EncodedString, 'tk/encodedstr'
+ def Tk.EncodedString(str, enc = nil); Tk::EncodedString.new(str, enc); end
+
+ autoload :BinaryString, 'tk/encodedstr'
+ def Tk.BinaryString(str); Tk::BinaryString.new(str); end
+
+ autoload :UTF8_String, 'tk/encodedstr'
+ def Tk.UTF8_String(str); Tk::UTF8_String.new(str); end
+
+end
+
+
+############################################
+# toplevel classes/modules (fixed)
autoload :TkBgError, 'tk/bgerror'
autoload :TkBindTag, 'tk/bindtag'
autoload :TkBindTagAll, 'tk/bindtag'
autoload :TkDatabaseClass, 'tk/bindtag'
-autoload :TkButton, 'tk/button'
-
autoload :TkConsole, 'tk/console'
-autoload :TkCanvas, 'tk/canvas'
+autoload :TkcItem, 'tk/canvas'
+autoload :TkcArc, 'tk/canvas'
+autoload :TkcBitmap, 'tk/canvas'
+autoload :TkcImage, 'tk/canvas'
+autoload :TkcLine, 'tk/canvas'
+autoload :TkcOval, 'tk/canvas'
+autoload :TkcPolygon, 'tk/canvas'
+autoload :TkcRectangle, 'tk/canvas'
+autoload :TkcText, 'tk/canvas'
+autoload :TkcWindow, 'tk/canvas'
autoload :TkcTagAccess, 'tk/canvastag'
autoload :TkcTag, 'tk/canvastag'
@@ -36,9 +144,6 @@ autoload :TkcTagAll, 'tk/canvastag'
autoload :TkcTagCurrent, 'tk/canvastag'
autoload :TkcTagGroup, 'tk/canvastag'
-autoload :TkCheckButton, 'tk/checkbutton'
-autoload :TkCheckbutton, 'tk/checkbutton'
-
autoload :TkClipboard, 'tk/clipboard'
autoload :TkComposite, 'tk/composite'
@@ -52,14 +157,10 @@ autoload :TkWarning, 'tk/dialog'
autoload :TkWarning2, 'tk/dialog'
autoload :TkWarningObj, 'tk/dialog'
-autoload :TkEntry, 'tk/entry'
-
autoload :TkEvent, 'tk/event'
autoload :TkFont, 'tk/font'
-autoload :TkTreatTagFont, 'tk/font'
-
-autoload :TkFrame, 'tk/frame'
+autoload :TkNamedFont, 'tk/font'
autoload :TkImage, 'tk/image'
autoload :TkBitmapImage, 'tk/image'
@@ -71,30 +172,12 @@ autoload :TkTreatItemFont, 'tk/itemfont'
autoload :TkKinput, 'tk/kinput'
-autoload :TkLabel, 'tk/label'
-
-autoload :TkLabelFrame, 'tk/labelframe'
-autoload :TkLabelframe, 'tk/labelframe'
-
-autoload :TkListbox, 'tk/listbox'
-
-autoload :TkMacResource, 'tk/macpkg'
-
-autoload :TkMenu, 'tk/menu'
-autoload :TkMenuClone, 'tk/menu'
autoload :TkSystemMenu, 'tk/menu'
-autoload :TkSysMenu_Help, 'tk/menu'
-autoload :TkSysMenu_System, 'tk/menu'
-autoload :TkSysMenu_Apple, 'tk/menu'
-autoload :TkMenubutton, 'tk/menu'
-autoload :TkOptionMenubutton, 'tk/menu'
autoload :TkMenubar, 'tk/menubar'
autoload :TkMenuSpec, 'tk/menuspec'
-autoload :TkMessage, 'tk/message'
-
autoload :TkManageFocus, 'tk/mngfocus'
autoload :TkMsgCatalog, 'tk/msgcat'
@@ -110,53 +193,46 @@ autoload :TkPackage, 'tk/package'
autoload :TkPalette, 'tk/palette'
-autoload :TkPanedWindow, 'tk/panedwindow'
-autoload :TkPanedwindow, 'tk/panedwindow'
-
-autoload :TkRadioButton, 'tk/radiobutton'
-autoload :TkRadiobutton, 'tk/radiobutton'
-
autoload :TkRoot, 'tk/root'
-autoload :TkScale, 'tk/scale'
-
-autoload :TkScrollbar, 'tk/scrollbar'
-autoload :TkXScrollbar, 'tk/scrollbar'
-autoload :TkYScrollbar, 'tk/scrollbar'
-
autoload :TkScrollbox, 'tk/scrollbox'
autoload :TkSelection, 'tk/selection'
-autoload :TkSpinbox, 'tk/spinbox'
-
autoload :TkTreatTagFont, 'tk/tagfont'
-autoload :TkText, 'tk/text'
-
autoload :TkTextImage, 'tk/textimage'
+autoload :TktImage, 'tk/textimage'
autoload :TkTextMark, 'tk/textmark'
autoload :TkTextNamedMark, 'tk/textmark'
autoload :TkTextMarkInsert, 'tk/textmark'
autoload :TkTextMarkCurrent, 'tk/textmark'
autoload :TkTextMarkAnchor, 'tk/textmark'
+autoload :TktMark, 'tk/textmark'
+autoload :TktNamedMark, 'tk/textmark'
+autoload :TktMarkInsert, 'tk/textmark'
+autoload :TktMarkCurrent, 'tk/textmark'
+autoload :TktMarkAnchor, 'tk/textmark'
autoload :TkTextTag, 'tk/texttag'
autoload :TkTextNamedTag, 'tk/texttag'
autoload :TkTextTagSel, 'tk/texttag'
+autoload :TktTag, 'tk/texttag'
+autoload :TktNamedTag, 'tk/texttag'
+autoload :TktTagSel, 'tk/texttag'
autoload :TkTextWindow, 'tk/textwindow'
+autoload :TktWindow, 'tk/textwindow'
autoload :TkAfter, 'tk/timer'
autoload :TkTimer, 'tk/timer'
autoload :TkRTTimer, 'tk/timer'
-autoload :TkToplevel, 'tk/toplevel'
-
autoload :TkTextWin, 'tk/txtwin_abst'
autoload :TkValidation, 'tk/validation'
+autoload :TkValidateCommand, 'tk/validation'
autoload :TkVariable, 'tk/variable'
autoload :TkVarAccess, 'tk/variable'
@@ -166,31 +242,173 @@ autoload :TkNamedVirtualEvent,'tk/virtevent'
autoload :TkWinfo, 'tk/winfo'
-autoload :TkWinDDE, 'tk/winpkg'
-autoload :TkWinRegistry, 'tk/winpkg'
-
autoload :TkXIM, 'tk/xim'
-#######################
-# sub-module of Tk
+############################################
+# toplevel classes/modules (switchable)
module Tk
- autoload :Clock, 'tk/clock'
- autoload :OptionObj, 'tk/optionobj'
- autoload :X_Scrollable, 'tk/scrollable'
- autoload :Y_Scrollable, 'tk/scrollable'
- autoload :Scrollable, 'tk/scrollable'
- autoload :Wm, 'tk/wm'
+ @TOPLEVEL_ALIAS_TABLE = {}
+ @TOPLEVEL_ALIAS_TABLE[:Tk] = {
+ :TkButton => 'tk/button',
- autoload :ValidateConfigure, 'tk/validation'
- autoload :ItemValidateConfigure, 'tk/validation'
+ :TkCanvas => 'tk/canvas',
- autoload :EncodedString, 'tk/encodedstr'
- def Tk.EncodedString(str, enc = nil); Tk::EncodedString.new(str, enc); end
+ :TkCheckButton => 'tk/checkbutton',
+ :TkCheckbutton => 'tk/checkbutton',
- autoload :BinaryString, 'tk/encodedstr'
- def Tk.BinaryString(str); Tk::BinaryString.new(str); end
+ # :TkDialog => 'tk/dialog',
+ # :TkDialog2 => 'tk/dialog',
+ # :TkDialogObj => 'tk/dialog',
+ # :TkWarning => 'tk/dialog',
+ # :TkWarning2 => 'tk/dialog',
+ # :TkWarningObj => 'tk/dialog',
- autoload :UTF8_String, 'tk/encodedstr'
- def Tk.UTF8_String(str); Tk::UTF8_String.new(str); end
+ :TkEntry => 'tk/entry',
+
+ :TkFrame => 'tk/frame',
+
+ :TkLabel => 'tk/label',
+
+ :TkLabelFrame => 'tk/labelframe',
+ :TkLabelframe => 'tk/labelframe',
+
+ :TkListbox => 'tk/listbox',
+
+ :TkMacResource => 'tk/macpkg',
+
+ :TkMenu => 'tk/menu',
+ :TkMenuClone => 'tk/menu',
+ :TkCloneMenu => 'tk/menu',
+ # :TkSystemMenu => 'tk/menu',
+ :TkSysMenu_Help => 'tk/menu',
+ :TkSysMenu_System => 'tk/menu',
+ :TkSysMenu_Apple => 'tk/menu',
+ :TkMenubutton => 'tk/menu',
+ :TkMenuButton => 'tk/menu',
+ :TkOptionMenubutton => 'tk/menu',
+ :TkOptionMenuButton => 'tk/menu',
+
+ :TkMessage => 'tk/message',
+
+ :TkPanedWindow => 'tk/panedwindow',
+ :TkPanedwindow => 'tk/panedwindow',
+
+ :TkRadioButton => 'tk/radiobutton',
+ :TkRadiobutton => 'tk/radiobutton',
+
+ # :TkRoot => 'tk/root',
+
+ :TkScale => 'tk/scale',
+
+ :TkScrollbar => 'tk/scrollbar',
+ :TkXScrollbar => 'tk/scrollbar',
+ :TkYScrollbar => 'tk/scrollbar',
+
+ :TkSpinbox => 'tk/spinbox',
+
+ :TkText => 'tk/text',
+
+ :TkToplevel => 'tk/toplevel',
+
+ :TkWinDDE => 'tk/winpkg',
+ :TkWinRegistry => 'tk/winpkg',
+ }
+
+ @TOPLEVEL_ALIAS_OWNER = {}
+
+ @TOPLEVEL_ALIAS_SETUP_PROC = {}
+
+ @current_default_widget_set = nil
+end
+
+
+############################################
+# methods to control default widget set
+############################################
+
+class << Tk
+ def default_widget_set
+ @current_default_widget_set
+ end
+
+ def default_widget_set=(target)
+ target = target.to_sym
+ return target if target == @current_default_widget_set
+
+ if (cmd = @TOPLEVEL_ALIAS_SETUP_PROC[target])
+ cmd.call(target)
+ end
+
+ _replace_toplevel_aliases(target)
+ end
+
+ def __set_toplevel_aliases__(target, obj, *symbols)
+ @TOPLEVEL_ALIAS_TABLE[target = target.to_sym] ||= {}
+ symbols.each{|sym|
+ @TOPLEVEL_ALIAS_TABLE[target][sym = sym.to_sym] = obj
+ # if @current_default_widget_set == target
+ if @TOPLEVEL_ALIAS_OWNER[sym] == target
+ Object.class_eval{remove_const sym} if Object.const_defined?(sym)
+ Object.const_set(sym, obj)
+ end
+ }
+ end
+
+ ###################################
+ private
+ def _replace_toplevel_aliases(target)
+ # check already autoloaded
+ if (table = @TOPLEVEL_ALIAS_TABLE[current = @current_default_widget_set])
+ table.each{|sym, file|
+ if !Object.autoload?(sym) && Object.const_defined?(sym) &&
+ @TOPLEVEL_ALIAS_TABLE[current][sym].kind_of?(String)
+ # autoload -> class
+ @TOPLEVEL_ALIAS_TABLE[current][sym] = Object.const_get(sym)
+ end
+ }
+ end
+
+ # setup autoloads
+ @TOPLEVEL_ALIAS_TABLE[target].each{|sym, file|
+ Object.class_eval{remove_const sym} if Object.const_defined?(sym)
+ if file.kind_of?(String)
+ # file => autoload target file
+ Object.autoload(sym, file)
+ else
+ # file => loaded class object
+ Object.const_set(sym, file)
+ end
+ @TOPLEVEL_ALIAS_OWNER[sym] = target
+ }
+
+ # update current alias
+ @current_default_widget_set = target
+ end
+end
+
+############################################
+# setup default widget set => :Tk
+Tk.default_widget_set = :Tk
+
+
+############################################
+# depend on the version of Tcl/Tk
+# major, minor, type, type_name, patchlevel = TclTkLib.get_version
+
+############################################
+# Ttk (Tile) support
+=begin
+if major > 8 ||
+ (major == 8 && minor > 5) ||
+ (major == 8 && minor == 5 && type >= TclTkLib::RELEASE_TYPE::BETA)
+ # Tcl/Tk 8.5 beta or later
+ Object.autoload :Ttk, 'tkextlib/tile'
+ Tk.autoload :Tile, 'tkextlib/tile'
+
+ require 'tk/ttk_selector'
end
+=end
+Object.autoload :Ttk, 'tkextlib/tile'
+Tk.autoload :Tile, 'tkextlib/tile'
+require 'tk/ttk_selector'
diff --git a/ext/tk/lib/tk/bindtag.rb b/ext/tk/lib/tk/bindtag.rb
index 9023a08e06..88c8367a88 100644
--- a/ext/tk/lib/tk/bindtag.rb
+++ b/ext/tk/lib/tk/bindtag.rb
@@ -8,30 +8,64 @@ class TkBindTag
#BTagID_TBL = {}
BTagID_TBL = TkCore::INTERP.create_table
- Tk_BINDTAG_ID = ["btag".freeze, "00000".taint].freeze
- TkCore::INTERP.init_ip_env{ BTagID_TBL.clear }
+ (Tk_BINDTAG_ID = ["btag".freeze, "00000".taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
+ TkCore::INTERP.init_ip_env{
+ BTagID_TBL.mutex.synchronize{ BTagID_TBL.clear }
+ }
def TkBindTag.id2obj(id)
- BTagID_TBL[id]? BTagID_TBL[id]: id
+ BTagID_TBL.mutex.synchronize{
+ (BTagID_TBL[id])? BTagID_TBL[id]: id
+ }
end
+=begin
def TkBindTag.new_by_name(name, *args, &b)
- return BTagID_TBL[name] if BTagID_TBL[name]
+ BTagID_TBL.mutex.synchronize{
+ return BTagID_TBL[name] if BTagID_TBL[name]
+ }
+
self.new.instance_eval{
- BTagID_TBL.delete @id
- @id = name
- BTagID_TBL[@id] = self
+ BTagID_TBL.mutex.synchronize{
+ BTagID_TBL.delete @id
+ @id = name
+ BTagID_TBL[@id] = self
+ }
bind(*args, &b) if args != []
self
}
end
+=end
+ def TkBindTag.new_by_name(name, *args, &b)
+ obj = nil
+ BTagID_TBL.mutex.synchronize{
+ if BTagID_TBL[name]
+ obj = BTagID_TBL[name]
+ else
+ (obj = BTagID_TBL[name] = self.allocate).instance_eval{
+ @id = name
+ }
+ end
+ }
+ bind(*args, &b) if obj && args != []
+ obj
+ end
def initialize(*args, &b)
- # @id = Tk_BINDTAG_ID.join('')
- @id = Tk_BINDTAG_ID.join(TkCore::INTERP._ip_id_)
- Tk_BINDTAG_ID[1].succ!
- BTagID_TBL[@id] = self
+ Tk_BINDTAG_ID.mutex.synchronize{
+ # @id = Tk_BINDTAG_ID.join('')
+ @id = Tk_BINDTAG_ID.join(TkCore::INTERP._ip_id_)
+ Tk_BINDTAG_ID[1].succ!
+ }
+ BTagID_TBL.mutex.synchronize{
+ BTagID_TBL[@id] = self
+ }
bind(*args, &b) if args != []
end
@@ -63,14 +97,37 @@ end
class TkDatabaseClass<TkBindTag
+=begin
def self.new(name, *args, &b)
- return BTagID_TBL[name] if BTagID_TBL[name]
+ BTagID_TBL.mutex.synchronize{
+ return BTagID_TBL[name] if BTagID_TBL[name]
+ }
super(name, *args, &b)
end
def initialize(name, *args, &b)
@id = name
- BTagID_TBL[@id] = self
+ BTagID_TBL.mutex.synchronize{
+ BTagID_TBL[@id] = self
+ }
+ bind(*args, &b) if args != []
+ end
+=end
+ def self.new(name, *args, &b)
+ BTagID_TBL.mutex.synchronize{
+ if BTagID_TBL[name]
+ BTagID_TBL[name]
+ else
+ BTagID_TBL[name] = self.allocate.instance_eval{
+ initialize(name, *args, &b)
+ self
+ }
+ end
+ }
+ end
+
+ def initialize(name, *args, &b)
+ @id = name
bind(*args, &b) if args != []
end
diff --git a/ext/tk/lib/tk/button.rb b/ext/tk/lib/tk/button.rb
index 407a47c400..770a5785bb 100644
--- a/ext/tk/lib/tk/button.rb
+++ b/ext/tk/lib/tk/button.rb
@@ -4,7 +4,7 @@
require 'tk'
require 'tk/label'
-class TkButton<TkLabel
+class Tk::Button<Tk::Label
TkCommandNames = ['button'.freeze].freeze
WidgetClassName = 'Button'.freeze
WidgetClassNames[WidgetClassName] = self
@@ -25,3 +25,6 @@ class TkButton<TkLabel
self
end
end
+
+#TkButton = Tk::Button unless Object.const_defined? :TkButton
+Tk.__set_toplevel_aliases__(:Tk, Tk::Button, :TkButton)
diff --git a/ext/tk/lib/tk/canvas.rb b/ext/tk/lib/tk/canvas.rb
index 0f55bff4ed..36ea008a17 100644
--- a/ext/tk/lib/tk/canvas.rb
+++ b/ext/tk/lib/tk/canvas.rb
@@ -1,6 +1,5 @@
#
# tk/canvas.rb - Tk canvas classes
-# $Date: 2005/10/24 00:07:00 $
# by Yukihiro Matsumoto <matz@caelum.co.jp>
#
require 'tk'
@@ -40,9 +39,9 @@ module TkCanvasItemConfig
private :__item_pathname
end
-class TkCanvas<TkWindow
+class Tk::Canvas<TkWindow
include TkCanvasItemConfig
- include Scrollable
+ include Tk::Scrollable
TkCommandNames = ['canvas'.freeze].freeze
WidgetClassName = 'Canvas'.freeze
@@ -169,6 +168,8 @@ class TkCanvas<TkWindow
#tk_tcl2ruby(tk_send_without_enc('canvasy', screen_y, *args))
number(tk_send_without_enc('canvasy', screen_y, *args))
end
+ alias canvas_x canvasx
+ alias canvas_y canvasy
def coords(tag, *args)
if args == []
@@ -186,11 +187,17 @@ class TkCanvas<TkWindow
end
def delete(*args)
- if TkcItem::CItemID_TBL[self.path]
+ tbl = nil
+ TkcItem::CItemID_TBL.mutex.synchronize{
+ tbl = TkcItem::CItemID_TBL[self.path]
+ }
+ if tbl
args.each{|tag|
find('withtag', tag).each{|item|
if item.kind_of?(TkcItem)
- TkcItem::CItemID_TBL[self.path].delete(item.id)
+ TkcItem::CItemID_TBL.mutex.synchronize{
+ tbl.delete(item.id)
+ }
end
}
}
@@ -543,8 +550,8 @@ class TkCanvas<TkWindow
tk_send_without_enc('scan', 'mark', x, y)
self
end
- def scan_dragto(x, y)
- tk_send_without_enc('scan', 'dragto', x, y)
+ def scan_dragto(x, y, gain=None)
+ tk_send_without_enc('scan', 'dragto', x, y, gain)
self
end
@@ -573,6 +580,10 @@ class TkCanvas<TkWindow
end
end
+#TkCanvas = Tk::Canvas unless Object.const_defined? :TkCanvas
+Tk.__set_toplevel_aliases__(:Tk, Tk::Canvas, :TkCanvas)
+
+
class TkcItem<TkObject
extend Tk
include TkcTagAccess
@@ -581,9 +592,12 @@ class TkcItem<TkObject
CItemTypeName = nil
CItemTypeToClass = {}
+
CItemID_TBL = TkCore::INTERP.create_table
- TkCore::INTERP.init_ip_env{ CItemID_TBL.clear }
+ TkCore::INTERP.init_ip_env{
+ CItemID_TBL.mutex.synchronize{ CItemID_TBL.clear }
+ }
def TkcItem.type2class(type)
CItemTypeToClass[type]
@@ -591,8 +605,13 @@ class TkcItem<TkObject
def TkcItem.id2obj(canvas, id)
cpath = canvas.path
- return id unless CItemID_TBL[cpath]
- CItemID_TBL[cpath][id]? CItemID_TBL[cpath][id]: id
+ CItemID_TBL.mutex.synchronize{
+ if CItemID_TBL[cpath]
+ CItemID_TBL[cpath][id]? CItemID_TBL[cpath][id]: id
+ else
+ id
+ end
+ }
end
########################################
@@ -625,6 +644,13 @@ class TkcItem<TkObject
fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey)
}
+ __item_optkey_aliases(nil).each{|alias_name, real_name|
+ alias_name = alias_name.to_s
+ if keys.has_key?(alias_name)
+ keys[real_name.to_s] = keys.delete(alias_name)
+ end
+ }
+
__item_methodcall_optkeys(nil).each{|key|
key = key.to_s
methodkeys[key] = keys.delete(key) if keys.key?(key)
@@ -658,15 +684,17 @@ class TkcItem<TkObject
########################################
def initialize(parent, *args)
- #unless parent.kind_of?(TkCanvas)
- # fail ArgumentError, "expect TkCanvas for 1st argument"
+ #unless parent.kind_of?(Tk::Canvas)
+ # fail ArgumentError, "expect Tk::Canvas for 1st argument"
#end
@parent = @c = parent
@path = parent.path
@id = create_self(*args) # an integer number as 'canvas item id'
- CItemID_TBL[@path] = {} unless CItemID_TBL[@path]
- CItemID_TBL[@path][@id] = self
+ CItemID_TBL.mutex.synchronize{
+ CItemID_TBL[@path] = {} unless CItemID_TBL[@path]
+ CItemID_TBL[@path][@id] = self
+ }
end
def create_self(*args)
self.class.create(@c, *args) # return an integer number as 'canvas item id'
@@ -687,7 +715,9 @@ class TkcItem<TkObject
def delete
@c.delete @id
- CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path]
+ CItemID_TBL.mutex.synchronize{
+ CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path]
+ }
self
end
alias remove delete
diff --git a/ext/tk/lib/tk/canvastag.rb b/ext/tk/lib/tk/canvastag.rb
index a5650ee68b..49796d80b2 100644
--- a/ext/tk/lib/tk/canvastag.rb
+++ b/ext/tk/lib/tk/canvastag.rb
@@ -63,6 +63,9 @@ module TkcTagAccess
def cget(option)
@c.itemcget(@id, option)
end
+ def cget_strict(option)
+ @c.itemcget_strict(@id, option)
+ end
def configure(key, value=None)
@c.itemconfigure(@id, key, value)
@@ -199,14 +202,26 @@ class TkcTag<TkObject
include TkcTagAccess
CTagID_TBL = TkCore::INTERP.create_table
- Tk_CanvasTag_ID = ['ctag'.freeze, '00000'.taint].freeze
- TkCore::INTERP.init_ip_env{ CTagID_TBL.clear }
+ (Tk_CanvasTag_ID = ['ctag'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
+ TkCore::INTERP.init_ip_env{
+ CTagID_TBL.mutex.synchronize{ CTagID_TBL.clear }
+ }
def TkcTag.id2obj(canvas, id)
cpath = canvas.path
- return id unless CTagID_TBL[cpath]
- CTagID_TBL[cpath][id]? CTagID_TBL[cpath][id]: id
+ CTagID_TBL.mutex.synchronize{
+ if CTagID_TBL[cpath]
+ CTagID_TBL[cpath][id]? CTagID_TBL[cpath][id]: id
+ else
+ id
+ end
+ }
end
def initialize(parent, mode=nil, *args)
@@ -215,11 +230,15 @@ class TkcTag<TkObject
#end
@c = parent
@cpath = parent.path
- # @path = @id = Tk_CanvasTag_ID.join('')
- @path = @id = Tk_CanvasTag_ID.join(TkCore::INTERP._ip_id_)
- CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath]
- CTagID_TBL[@cpath][@id] = self
- Tk_CanvasTag_ID[1].succ!
+ Tk_CanvasTag_ID.mutex.synchronize{
+ # @path = @id = Tk_CanvasTag_ID.join('')
+ @path = @id = Tk_CanvasTag_ID.join(TkCore::INTERP._ip_id_)
+ Tk_CanvasTag_ID[1].succ!
+ }
+ CTagID_TBL.mutex.synchronize{
+ CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath]
+ CTagID_TBL[@cpath][@id] = self
+ }
if mode
tk_call_without_enc(@c.path, "addtag", @id, mode, *args)
end
@@ -238,7 +257,9 @@ class TkcTag<TkObject
def delete
@c.delete @id
- CTagID_TBL[@cpath].delete(@id) if CTagID_TBL[@cpath]
+ CTagID_TBL.mutex.synchronize{
+ CTagID_TBL[@cpath].delete(@id) if CTagID_TBL[@cpath]
+ }
self
end
alias remove delete
@@ -288,23 +309,38 @@ class TkcTag<TkObject
end
class TkcTagString<TkcTag
- def self.new(parent, name, *args)
- if CTagID_TBL[parent.path] && CTagID_TBL[parent.path][name]
- return CTagID_TBL[parent.path][name]
- else
- super(parent, name, *args)
+ def self.new(parent, name, mode=nil, *args)
+ obj = nil
+ CTagID_TBL.mutex.synchronize{
+ if CTagID_TBL[parent.path] && CTagID_TBL[parent.path][name]
+ obj = CTagID_TBL[parent.path][name]
+ else
+ # super(parent, name, *args)
+ (obj = self.allocate).instance_eval{
+ @c = parent
+ @cpath = parent.path
+ @path = @id = name
+ CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath]
+ CTagID_TBL[@cpath][@id] = self
+ }
+ end
+ }
+ if obj && mode
+ tk_call_without_enc(@c.path, "addtag", @id, mode, *args)
end
+ obj
end
def initialize(parent, name, mode=nil, *args)
+ # dummy:: not called by 'new' method
+
#unless parent.kind_of?(TkCanvas)
# fail ArgumentError, "expect TkCanvas for 1st argument"
#end
@c = parent
@cpath = parent.path
@path = @id = name
- CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath]
- CTagID_TBL[@cpath][@id] = self
+
if mode
tk_call_without_enc(@c.path, "addtag", @id, mode, *args)
end
@@ -312,7 +348,11 @@ class TkcTagString<TkcTag
end
TkcNamedTag = TkcTagString
-class TkcTagAll<TkcTag
+class TkcTagAll<TkcTagString
+ def self.new(parent)
+ super(parent, 'all')
+ end
+=begin
def initialize(parent)
#unless parent.kind_of?(TkCanvas)
# fail ArgumentError, "expect TkCanvas for 1st argument"
@@ -320,12 +360,19 @@ class TkcTagAll<TkcTag
@c = parent
@cpath = parent.path
@path = @id = 'all'
- CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath]
- CTagID_TBL[@cpath][@id] = self
+ CTagID_TBL.mutex.synchronize{
+ CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath]
+ CTagID_TBL[@cpath][@id] = self
+ }
end
+=end
end
-class TkcTagCurrent<TkcTag
+class TkcTagCurrent<TkcTagString
+ def self.new(parent)
+ super(parent, 'current')
+ end
+=begin
def initialize(parent)
#unless parent.kind_of?(TkCanvas)
# fail ArgumentError, "expect TkCanvas for 1st argument"
@@ -333,13 +380,21 @@ class TkcTagCurrent<TkcTag
@c = parent
@cpath = parent.path
@path = @id = 'current'
- CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath]
- CTagID_TBL[@cpath][@id] = self
+ CTagID_TBL.mutex.synchronize{
+ CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath]
+ CTagID_TBL[@cpath][@id] = self
+ }
end
+=end
end
class TkcGroup<TkcTag
- Tk_cGroup_ID = ['tkcg'.freeze, '00000'.taint].freeze
+ (Tk_cGroup_ID = ['tkcg'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
#def create_self(parent, *args)
def initialize(parent, *args)
#unless parent.kind_of?(TkCanvas)
@@ -347,11 +402,15 @@ class TkcGroup<TkcTag
#end
@c = parent
@cpath = parent.path
- # @path = @id = Tk_cGroup_ID.join('')
- @path = @id = Tk_cGroup_ID.join(TkCore::INTERP._ip_id_)
- CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath]
- CTagID_TBL[@cpath][@id] = self
- Tk_cGroup_ID[1].succ!
+ Tk_cGroup_ID.mutex.synchronize{
+ # @path = @id = Tk_cGroup_ID.join('')
+ @path = @id = Tk_cGroup_ID.join(TkCore::INTERP._ip_id_)
+ Tk_cGroup_ID[1].succ!
+ }
+ CTagID_TBL.mutex.synchronize{
+ CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath]
+ CTagID_TBL[@cpath][@id] = self
+ }
include(*args) if args != []
end
#private :create_self
diff --git a/ext/tk/lib/tk/checkbutton.rb b/ext/tk/lib/tk/checkbutton.rb
index d76d99c0f2..b1186a87ed 100644
--- a/ext/tk/lib/tk/checkbutton.rb
+++ b/ext/tk/lib/tk/checkbutton.rb
@@ -4,7 +4,7 @@
require 'tk'
require 'tk/radiobutton'
-class TkCheckButton<TkRadioButton
+class Tk::CheckButton<Tk::RadioButton
TkCommandNames = ['checkbutton'.freeze].freeze
WidgetClassName = 'Checkbutton'.freeze
WidgetClassNames[WidgetClassName] = self
@@ -22,4 +22,9 @@ class TkCheckButton<TkRadioButton
self
end
end
-TkCheckbutton = TkCheckButton
+
+Tk::Checkbutton = Tk::CheckButton
+#TkCheckButton = Tk::CheckButton unless Object.const_defined? :TkCheckButton
+#TkCheckbutton = Tk::Checkbutton unless Object.const_defined? :TkCheckbutton
+Tk.__set_toplevel_aliases__(:Tk, Tk::CheckButton,
+ :TkCheckButton, :TkCheckbutton)
diff --git a/ext/tk/lib/tk/composite.rb b/ext/tk/lib/tk/composite.rb
index eaed8ed363..883d43c3ea 100644
--- a/ext/tk/lib/tk/composite.rb
+++ b/ext/tk/lib/tk/composite.rb
@@ -34,7 +34,8 @@ module TkComposite
if klass
# WidgetClassName is a known class
- if klass <= TkFrame || klass < TkComposite
+ #if klass <= TkFrame || klass < TkComposite
+ if klass <= TkFrame || klass < Tk::Frame || klass < TkComposite
# klass is valid for the base frame
if self.class <= klass
# use my classname
@@ -50,7 +51,8 @@ module TkComposite
else
# klass is invalid for the base frame
- if self.class < TkFrame || self.class.superclass < TkComposite
+ #if self.class < TkFrame || self.class.superclass < TkComposite
+ if self.class < TkFrame || self.class.superclass < Tk::Frame || self.class.superclass < TkComposite
# my class name is valid for the base frame -> use my classname
base_class_name = self.class.name
if base_class_name == ''
@@ -69,7 +71,8 @@ module TkComposite
else
# no valid WidgetClassName
- if self.class < TkFrame || self.class.superclass < TkComposite
+ #if self.class < TkFrame || self.class.superclass < TkComposite
+ if self.class < TkFrame || self.class.superclass < Tk::Frame || self.class.superclass < TkComposite
# my class name is valid for the base frame -> use my classname
base_class_name = self.class.name
if base_class_name == ''
@@ -108,8 +111,12 @@ module TkComposite
end
if base_class_name
+ # @frame = Tk::Frame.new(parent, :class=>base_class_name)
+ # --> use current TkFrame class
@frame = TkFrame.new(parent, :class=>base_class_name)
else
+ # @frame = Tk::Frame.new(parent)
+ # --> use current TkFrame class
@frame = TkFrame.new(parent)
end
@path = @epath = @frame.path
@@ -133,6 +140,11 @@ module TkComposite
def initialize_composite(*args) end
private :initialize_composite
+ def inspect
+ str = super
+ str.chop << ' @epath=' << @epath.inspect << '>'
+ end
+
def option_methods(*opts)
opts.each{|m_set, m_cget, m_info|
m_set = m_set.to_s
@@ -169,6 +181,57 @@ module TkComposite
delegate_alias(option, option, *wins)
end
+ def __cget_delegates(slot)
+ slot = slot.to_s
+
+ if @option_methods.include?(slot)
+ if @option_methods[slot][:cget]
+ return self.__send__(@option_methods[slot][:cget])
+ else
+ if @option_setting[slot]
+ return @option_setting[slot]
+ else
+ return ''
+ end
+ end
+ end
+
+ tbl = @delegates[slot]
+ tbl = @delegates['DEFAULT'] unless tbl
+
+ begin
+ if tbl
+ opt, wins = tbl[-1]
+ opt = slot if opt == 'DEFAULT'
+ if wins && wins[-1]
+ # return wins[-1].cget(opt)
+ return wins[-1].cget_strict(opt)
+ end
+ end
+ rescue
+ end
+
+ return None
+ end
+ private :__cget_delegates
+
+ def cget(slot)
+ if (ret = __cget_delegates(slot)) == None
+ super(slot)
+ else
+ ret
+ end
+ end
+
+ def cget_strict(slot)
+ if (ret = __cget_delegates(slot)) == None
+ super(slot)
+ else
+ ret
+ end
+ end
+
+=begin
def cget(slot)
slot = slot.to_s
@@ -200,6 +263,7 @@ module TkComposite
super(slot)
end
+=end
def configure(slot, value=None)
if slot.kind_of? Hash
diff --git a/ext/tk/lib/tk/encodedstr.rb b/ext/tk/lib/tk/encodedstr.rb
index 797e514a4c..02de0b0d85 100644
--- a/ext/tk/lib/tk/encodedstr.rb
+++ b/ext/tk/lib/tk/encodedstr.rb
@@ -70,13 +70,89 @@ module Tk
# @encoding = ( enc ||
# ((self.class::Encoding)?
# self.class::Encoding : Tk.encoding_system) )
- @encoding = ( enc ||
- ((self.class::Encoding)?
+ enc ||= (self.class::Encoding)?
self.class::Encoding :
- ((Tk.encoding)? Tk.encoding : Tk.encoding_system) ) )
+ ((Tk.encoding)? Tk.encoding : Tk.encoding_system)
+ if TkCore::WITH_ENCODING
+ unless encobj = Tk::Encoding::ENCODING_TABLE.get_obj(enc)
+ fail ArgumentError, "unsupported Tk encoding '#{enc}'"
+ end
+ self.force_encoding(encobj)
+ else
+ @encoding = enc
+ end
+ end
+
+ if TkCore::WITH_ENCODING
+ alias encoding_obj encoding
+ alias __encoding encoding
+ def encoding
+ Tk::Encoding::ENCODING_TABLE.get_name(super())
+ end
+ else
+ def encoding
+ @encoding
+ end
+ alias encoding_obj encoding
end
- attr_reader :encoding
+ if TkCore::WITH_ENCODING
+ # wrapper methods for compatibility
+ alias __instance_variable_get instance_variable_get
+ alias __instance_variable_set instance_variable_set
+ alias __instance_eval instance_eval
+ alias __instance_variables instance_variables
+
+ def instance_variable_get(key)
+ if (key.to_s == '@encoding')
+ self.encoding
+ else
+ super(key)
+ end
+ end
+
+ def instance_variable_set(key, value)
+ if (key.to_s == '@encoding')
+ if value
+ self.force_encoding(value)
+ else
+ self.force_encoding(Tk::Encoding::UNKNOWN)
+ end
+ value
+ else
+ super(key, value)
+ end
+ end
+
+ def instance_eval(*args, &b)
+ old_enc = @encoding = self.encoding
+
+ ret = super(*args, &b)
+
+ if @encoding
+ if @encoding != old_enc
+ # modified by user
+ self.force_encoding(@encoding)
+ end
+ remove_instance_variable(:@encoding)
+ else
+ begin
+ remove_instance_variable(:@encoding)
+ # user sets to nil -> use current default
+ self.force_encoding(Tk.encoding)
+ rescue NameError
+ # removed by user -> ignore, because user don't use @encoding
+ end
+ end
+ ret
+ end
+ end
+
+ def instance_variables
+ ret = super()
+ ret << :@encoding # fake !!
+ ret
+ end
end
# def Tk.EncodedString(str, enc = nil)
# Tk::EncodedString.new(str, enc)
diff --git a/ext/tk/lib/tk/entry.rb b/ext/tk/lib/tk/entry.rb
index e4d69eb7bf..8ce8def1e7 100644
--- a/ext/tk/lib/tk/entry.rb
+++ b/ext/tk/lib/tk/entry.rb
@@ -1,6 +1,5 @@
#
# tk/entry.rb - Tk entry classes
-# $Date: 2005/10/22 22:16:24 $
# by Yukihiro Matsumoto <matz@caelum.co.jp>
require 'tk'
@@ -8,7 +7,7 @@ require 'tk/label'
require 'tk/scrollable'
require 'tk/validation'
-class TkEntry<TkLabel
+class Tk::Entry<Tk::Label
include X_Scrollable
include TkValidation
@@ -115,3 +114,6 @@ class TkEntry<TkLabel
val
end
end
+
+#TkEntry = Tk::Entry unless Object.const_defined? :TkEntry
+Tk.__set_toplevel_aliases__(:Tk, Tk::Entry, :TkEntry)
diff --git a/ext/tk/lib/tk/event.rb b/ext/tk/lib/tk/event.rb
index 70a1e38bbe..d8aad6248b 100644
--- a/ext/tk/lib/tk/event.rb
+++ b/ext/tk/lib/tk/event.rb
@@ -39,7 +39,9 @@ module TkEvent
RESIZEREQ = 0x200000
CIRCREQ = 0x400000
- MWHEEL = 0x10000000
+ MWHEEL = KEY
+
+ STRING_DATA = 0x80000000 # special flag for 'data' field
ALL = 0xFFFFFFFF
@@ -155,7 +157,7 @@ module TkEvent
'borderwidth' => (Grp::CREATE|Grp::CONFIG),
'button' => Grp::BUTTON,
'count' => Grp::EXPOSE,
- 'data' => Grp::VIRTUAL,
+ 'data' => (Grp::VIRTUAL|Grp::STRING_DATA),
'delta' => Grp::MWHEEL,
'detail' => (Grp::FOCUS|Grp::CROSSING),
'focus' => Grp::CROSSING,
@@ -223,7 +225,8 @@ module TkEvent
rescue
next
end
- next if !val || val == '??'
+ # next if !val || val == '??'
+ next if !val || (val == '??' && (flag & Grp::STRING_DATA))
fields[key] = val
}
@@ -298,34 +301,65 @@ module TkEvent
[ ?b, ?n, :num ],
[ ?c, ?n, :count ],
[ ?d, ?s, :detail ],
+ # ?e
[ ?f, ?b, :focus ],
+ # ?g
[ ?h, ?n, :height ],
[ ?i, ?s, :win_hex ],
+ # ?j
[ ?k, ?n, :keycode ],
+ # ?l
[ ?m, ?s, :mode ],
+ # ?n
[ ?o, ?b, :override ],
[ ?p, ?s, :place ],
+ # ?q
+ # ?r
[ ?s, ?x, :state ],
[ ?t, ?n, :time ],
+ # ?u
+ [ ?v, ?n, :value_mask ],
[ ?w, ?n, :width ],
[ ?x, ?n, :x ],
[ ?y, ?n, :y ],
+ # ?z
[ ?A, ?s, :char ],
[ ?B, ?n, :borderwidth ],
+ # ?C
[ ?D, ?n, :wheel_delta ],
[ ?E, ?b, :send_event ],
+ # ?F
+ # ?G
+ # ?H
+ # ?I
+ # ?J
[ ?K, ?s, :keysym ],
+ # ?L
+ # ?M
[ ?N, ?n, :keysym_num ],
+ # ?O
[ ?P, ?s, :property ],
+ # ?Q
[ ?R, ?s, :rootwin_id ],
[ ?S, ?s, :subwindow ],
[ ?T, ?n, :type ],
+ # ?U
+ # ?V
[ ?W, ?w, :widget ],
[ ?X, ?n, :x_root ],
[ ?Y, ?n, :y_root ],
+ # ?Z
nil
]
+ # [ <'%' subst-key str>, <proc type char>, <instance var (accessor) name>]
+ # the subst-key string will be converted to a bytecode (128+idx).
+ LONGKEY_TBL = [
+ # for example, for %CTT and %CST subst-key on tkdnd-2.0
+ # ['CTT', ?l, :drop_target_type],
+ # ['CST', ?l, :drop_source_type],
+ ]
+
# [ <proc type char>, <proc/method to convert tcl-str to ruby-obj>]
PROC_TBL = [
[ ?n, TkComm.method(:num_or_str) ],
@@ -345,6 +379,24 @@ module TkEvent
nil
]
+=begin
+ # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
+ KEY_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String)
+ end
+ inf
+ }
+
+ PROC_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ end
+ inf
+ }
+=end
+
# setup tables to be used by scan_args, _get_subst_key, _get_all_subst_keys
#
# _get_subst_key() and _get_all_subst_keys() generates key-string
@@ -357,7 +409,8 @@ module TkEvent
# ( which are Tcl strings ) to ruby objects based on the key string
# that is generated by _get_subst_key() or _get_all_subst_keys().
#
- _setup_subst_table(KEY_TBL, PROC_TBL);
+ _setup_subst_table(KEY_TBL, PROC_TBL)
+ # _setup_subst_table(KEY_TBL, LONGKEY_TBL, PROC_TBL) # if use longname-keys
#
# NOTE: The order of parameters which passed to callback procedure is
@@ -405,6 +458,7 @@ module TkEvent
extra_args_tbl = klass._get_extra_args_tbl
if args.compact.size > 0
+ args.map!{|arg| klass._sym2subst(arg)}
args = args.join(' ')
keys = klass._get_subst_key(args)
diff --git a/ext/tk/lib/tk/font.rb b/ext/tk/lib/tk/font.rb
index de02d4957c..62d628c132 100644
--- a/ext/tk/lib/tk/font.rb
+++ b/ext/tk/lib/tk/font.rb
@@ -11,13 +11,18 @@ class TkFont
TkCommandNames = ['font'.freeze].freeze
- Tk_FontID = ["@font".freeze, "00000".taint].freeze
+ (Tk_FontID = ["@font".freeze, "00000".taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
Tk_FontNameTBL = TkCore::INTERP.create_table
Tk_FontUseTBL = TkCore::INTERP.create_table
TkCore::INTERP.init_ip_env{
- Tk_FontNameTBL.clear
- Tk_FontUseTBL.clear
+ Tk_FontNameTBL.mutex.synchronize{ Tk_FontNameTBL.clear }
+ Tk_FontUseTBL.mutex.synchronize{ Tk_FontUseTBL.clear }
}
# option_type : default => string
@@ -31,13 +36,26 @@ class TkFont
MetricType = Hash.new(?n)
MetricType['fixed'] = ?b
+ # system font names
+ SYSTEM_FONT_NAMES = []
+ def SYSTEM_FONT_NAMES.add(font_names)
+ (@mutex ||= Mutex.new).synchronize{
+ self.replace(self | font_names.map{|name| name.to_s})
+ }
+ end
+ def SYSTEM_FONT_NAMES.include?(name)
+ (@mutex ||= Mutex.new).synchronize{
+ super(name.to_s)
+ }
+ end
+
# set default font
case Tk::TK_VERSION
- when /^4\.*/
+ when /^4\..*/
DEFAULT_LATIN_FONT_NAME = 'a14'.freeze
DEFAULT_KANJI_FONT_NAME = 'k14'.freeze
- when /^8\.*/
+ when /^8\.[0-4]/
if JAPANIZED_TK
begin
fontnames = tk_call('font', 'names')
@@ -103,6 +121,15 @@ class TkFont
DEFAULT_LATIN_FONT_NAME = ltn.freeze
DEFAULT_KANJI_FONT_NAME = knj.freeze
+ when /^8\.[5-9]/, /^9\..*/
+ if tk_call('font', 'names') =~ /\bTkDefaultFont\b/
+ DEFAULT_LATIN_FONT_NAME = 'TkDefaultFont'.freeze
+ DEFAULT_KANJI_FONT_NAME = 'TkDefaultFont'.freeze
+ else
+ DEFAULT_LATIN_FONT_NAME = 'Helvetica'.freeze
+ DEFAULT_KANJI_FONT_NAME = 'mincho'.freeze
+ end
+
else # unknown version
DEFAULT_LATIN_FONT_NAME = 'Helvetica'.freeze
DEFAULT_KANJI_FONT_NAME = 'mincho'.freeze
@@ -121,6 +148,7 @@ class TkFont
unless compound.kind_of?(TkFont)
fail ArgumentError, "a TkFont object is expected for the 1st argument"
end
+
@compound = compound
case type
when 'kanji', 'latin', 'ascii'
@@ -145,6 +173,9 @@ class TkFont
def font
@compound.__send__(@type + '_font_id')
end
+ alias font_id font
+ alias name font
+ alias to_s font
def [](slot)
@compound.__send__(@type + '_configinfo', slot)
@@ -163,6 +194,14 @@ class TkFont
###################################
# class methods
###################################
+ def TkFont.is_system_font?(fnt)
+ # true --> system font which is available on the current system
+ # false --> not system font (or unknown system font)
+ # nil --> system font name, but not available on the current system
+ fnt = fnt.to_s
+ SYSTEM_FONT_NAMES.include?(fnt) && self.names.index(fnt) && true
+ end
+
def TkFont.actual(fnt, option=nil)
fnt = '{}' if fnt == ''
if fnt.kind_of?(TkFont)
@@ -171,6 +210,9 @@ class TkFont
actual_core(fnt, nil, option)
end
end
+ def TkFont.actual_hash(fnt, option=nil)
+ Hash[TkFont.actual_hash(fnt, option)]
+ end
def TkFont.actual_displayof(fnt, win, option=nil)
fnt = '{}' if fnt == ''
@@ -181,6 +223,9 @@ class TkFont
actual_core(fnt, win, option)
end
end
+ def TkFont.actual_hash_displayof(fnt, option=nil)
+ Hash[TkFont.actual_hash_displayof(fnt, option)]
+ end
def TkFont.configure(fnt, slot, value=None)
if fnt.kind_of?(TkFont)
@@ -234,6 +279,33 @@ class TkFont
metrics_core(fnt, nil, option)
end
end
+ def TkFont.metrics_hash(fnt, option=nil)
+ if option
+ val = TkFont.metrics(fnt, option)
+ case TkFont::MetricsType[option.to_s]
+ when ?n
+ val = TkComm::num_or_str(val)
+ when ?b
+ val = TkComm::bool(val)
+ else
+ # do nothing
+ end
+ return val
+ end
+
+ h = Hash[TkFont.metrics(fnt)]
+ h.keys.each{|k|
+ case TkFont::MetricsType[k.to_s]
+ when ?n
+ h[k] = TkComm::num_or_str(h[k])
+ when ?b
+ h[k] = TkComm::bool(h[k])
+ else
+ # do nothing
+ end
+ }
+ h
+ end
def TkFont.metrics_displayof(fnt, win, option=nil)
fnt = '{}' if fnt == ''
@@ -244,13 +316,40 @@ class TkFont
metrics_core(fnt, win, option)
end
end
+ def TkFont.metrics_hash_displayof(fnt, win, option=nil)
+ if option
+ val = TkFont.metrics_displayof(fnt, win, option)
+ case TkFont::MetricsType[option.to_s]
+ when ?n
+ val = TkComm::num_or_str(val)
+ when ?b
+ val = TkComm::bool(val)
+ else
+ # do nothing
+ end
+ return val
+ end
+
+ h = Hash[TkFont.metrics_displayof(fnt, win, option)]
+ h.keys.each{|k|
+ case TkFont::MetricsType[k.to_s]
+ when ?n
+ h[k] = TkComm::num_or_str(h[k])
+ when ?b
+ h[k] = TkComm::bool(h[k])
+ else
+ # do nothing
+ end
+ }
+ h
+ end
def TkFont.families(win=nil)
case (Tk::TK_VERSION)
- when /^4\.*/
+ when /^4\..*/
['fixed']
- when /^8\.*/
+ when /^8\..*/
if win
tk_split_simplelist(tk_call('font', 'families', '-displayof', win))
else
@@ -261,13 +360,16 @@ class TkFont
def TkFont.names
case (Tk::TK_VERSION)
- when /^4\.*/
+ when /^4\..*/
r = ['fixed']
r += ['a14', 'k14'] if JAPANIZED_TK
- Tk_FontNameTBL.each_value{|obj| r.push(obj)}
- r | []
+ Tk_FontNameTBL.mutex.synchronize{
+ Tk_FontNameTBL.each_value{|obj| r.push(obj)}
+ }
+ #r | []
+ r.uniq
- when /^8\.*/
+ when /^8\..*/
tk_split_simplelist(tk_call('font', 'names'))
end
@@ -285,10 +387,15 @@ class TkFont
end
def TkFont.get_obj(name)
+ name = name.to_s
if name =~ /^(@font[0-9]+)(|c|l|k)$/
- Tk_FontNameTBL[$1]
+ Tk_FontNameTBL.mutex.synchronize{
+ Tk_FontNameTBL[$1]
+ }
else
- nil
+ Tk_FontNameTBL.mutex.synchronize{
+ Tk_FontNameTBL[name]
+ }
end
end
@@ -298,7 +405,7 @@ class TkFont
path = [win, tag, key].join(';')
case (Tk::TK_VERSION)
- when /^4\.*/
+ when /^4\..*/
regexp = /^-(|kanji)#{key} /
conf_list = tk_split_simplelist(tk_call(*args)).
@@ -324,7 +431,7 @@ class TkFont
TkFont.new(ltn, knj).call_font_configure([path, key], *args)
- when /^8\.*/
+ when /^8\.[0-4]/
regexp = /^-#{key} /
conf_list = tk_split_simplelist(tk_call(*args)).
@@ -360,26 +467,66 @@ class TkFont
compound = []
end
if compound == []
- TkFont.new(fnt).call_font_configure([path, key], *args)
+ if TkFont.is_system_font?(fnt)
+ TkNamedFont.new(fnt).call_font_configure([path, key], *args)
+ else
+ TkFont.new(fnt).call_font_configure([path, key], *args)
+ end
else
TkFont.new(compound[0],
compound[1]).call_font_configure([path, key], *args)
end
end
+
+ when /^8\.[5-9]/, /^9\..*/
+ regexp = /^-#{key} /
+
+ conf_list = tk_split_simplelist(tk_call(*args)).
+ find_all{|prop| prop =~ regexp}.
+ collect{|prop| tk_split_simplelist(prop)}
+
+ if conf_list.size == 0
+ raise RuntimeError, "the widget may not support 'font' option"
+ end
+
+ args << {}
+
+ optkey = "-#{key}"
+
+ info = conf_list.find{|conf| conf[0] == optkey}
+ fnt = info[-1]
+ fnt = nil if fnt == [] || fnt == ""
+
+ unless fnt
+ # create dummy
+ # TkFont.new(nil, nil).call_font_configure([path, key], *args)
+ dummy_fnt = TkFont.allocate
+ dummy_fnt.instance_eval{ init_dummy_fontobj() }
+ dummy_fnt
+ else
+ if TkFont.is_system_font?(fnt)
+ TkNamedFont.new(fnt).call_font_configure([path, key], *args)
+ else
+ TkFont.new(fnt).call_font_configure([path, key], *args)
+ end
+ end
end
end
def TkFont.used_on(path=nil)
- if path
- Tk_FontUseTBL[path]
- else
- Tk_FontUseTBL.values | []
- end
+ Tk_FontUseTBL.mutex.synchronize{
+ if path
+ Tk_FontUseTBL[path]
+ else
+ # Tk_FontUseTBL.values | []
+ Tk_FontUseTBL.values.uniq
+ end
+ }
end
def TkFont.failsafe(font)
begin
- if /^8\.*/ === Tk::TK_VERSION && JAPANIZED_TK
+ if /^8\..*/ === Tk::TK_VERSION && JAPANIZED_TK
tk_call('font', 'failsafe', font)
end
rescue
@@ -392,15 +539,20 @@ class TkFont
private
###################################
def init_dummy_fontobj
- @id = Tk_FontID.join(TkCore::INTERP._ip_id_)
- Tk_FontID[1].succ!
- Tk_FontNameTBL[@id] = self
+ Tk_FontID.mutex.synchronize{
+ @id = Tk_FontID.join(TkCore::INTERP._ip_id_)
+ Tk_FontID[1].succ!
+ }
+ Tk_FontNameTBL.mutex.synchronize{
+ Tk_FontNameTBL[@id] = self
+ }
- @latin_desscendant = nil
- @kanji_desscendant = nil
+ # @latin_desscendant = nil
+ # @kanji_desscendant = nil
+ @descendant = [nil, nil] # [latin, kanji]
case (Tk::TK_VERSION)
- when /^4\.*/
+ when /^4\..*/
@latinfont = ""
@kanjifont = ""
if JAPANIZED_TK
@@ -436,13 +588,23 @@ class TkFont
ltn = '{}' if ltn == ''
knj = '{}' if knj == ''
- # @id = Tk_FontID.join('')
- @id = Tk_FontID.join(TkCore::INTERP._ip_id_)
- Tk_FontID[1].succ!
- Tk_FontNameTBL[@id] = self
+ Tk_FontID.mutex.synchronize{
+ # @id = Tk_FontID.join('')
+ @id = Tk_FontID.join(TkCore::INTERP._ip_id_)
+ Tk_FontID[1].succ!
+ }
+ Tk_FontNameTBL.mutex.synchronize{
+ Tk_FontNameTBL[@id] = self
+ }
+
+ # @latin_desscendant = nil
+ # @kanji_desscendant = nil
+ @descendant = [nil, nil] # [latin, kanji]
- @latin_desscendant = nil
- @kanji_desscendant = nil
+ # @latinfont = @id + 'l'
+ # @kanjifont = @id + 'k'
+ # @compoundfont = @id + 'c'
+ # @fontslot = {}
if knj.kind_of?(Hash) && !keys
keys = knj
@@ -474,7 +636,7 @@ class TkFont
if ltn
if JAPANIZED_TK && !knj
- if Tk::TK_VERSION =~ /^4.*/
+ if Tk::TK_VERSION =~ /^4..*/
knj = DEFAULT_KANJI_FONT_NAME
else
knj = ltn
@@ -625,9 +787,14 @@ class TkFont
if JAPANIZED_TK
@compoundfont = [[@latinfont], [@kanjifont]]
@fontslot = {'font'=>@latinfont, 'kanjifont'=>@kanjifont}
+ # @fontslot.clear
+ # @fontslot['font'] = @latinfont
+ # @fontslot['kanjifont'] = @kanjifont
else
@compoundfont = @latinfont
@fontslot = {'font'=>@latinfont}
+ # @fontslot.clear
+ # @fontslot['font'] = @latinfont
end
end
@@ -753,6 +920,7 @@ class TkFont
end
@fontslot = {'font'=>@compoundfont}
+ # @fontslot['font'] = @compoundfont
begin
tk_call('font', 'create', @compoundfont,
'-compound', [@latinfont, @kanjifont], *hash_kv(keys))
@@ -833,6 +1001,7 @@ class TkFont
end
@fontslot = {'font'=>@compoundfont}
+ # @fontslot['font'] = @compoundfont
tk_call('font', 'configure', @compoundfont, *hash_kv(keys))
end
end
@@ -887,25 +1056,39 @@ class TkFont
keys = _symbolkey2str(args.pop).update(fontslot)
args.concat(hash_kv(keys))
- tk_call(*args)
- Tk_FontUseTBL[[win, tag, optkey].join(';')] = self
+ begin
+ tk_call(*args)
+ rescue => e
+ unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ fail e
+ end
+ end
+ Tk_FontUseTBL.mutex.synchronize{
+ Tk_FontUseTBL[[win, tag, optkey].join(';')] = self
+ }
self
end
def used
ret = []
- Tk_FontUseTBL.each{|key,value|
+ table = nil
+ Tk_FontUseTBL.mutex.synchronize{
+ table = Tk_FontUseTBL.clone # to avoid deadlock
+ }
+ table.each{|key,value|
next unless self == value
if key.include?(';')
win, tag, optkey = key.split(';')
winobj = tk_tcl2ruby(win)
- if winobj.kind_of? TkText
+ #if winobj.kind_of? TkText
+ if winobj.kind_of?(TkText) || winobj.kind_of?(Tk::Text)
if optkey
ret.push([winobj, winobj.tagid2obj(tag), optkey])
else
ret.push([winobj, winobj.tagid2obj(tag)])
end
- elsif winobj.kind_of? TkCanvas
+ #elsif winobj.kind_of? TkCanvas
+ elsif winobj.kind_of?(TkCanvas) || winobj.kind_of?(Tk::Canvas)
if (tagobj = TkcTag.id2obj(winobj, tag)).kind_of? TkcTag
if optkey
ret.push([winobj, tagobj, optkey])
@@ -925,7 +1108,8 @@ class TkFont
ret.push([winobj, tag])
end
end
- elsif winobj.kind_of? TkMenu
+ #elsif winobj.kind_of? TkMenu
+ elsif winobj.kind_of?(TkMenu) || winobj.kind_of?(Tk::Menu)
if optkey
ret.push([winobj, tag, optkey])
else
@@ -957,6 +1141,8 @@ class TkFont
@compoundfont
end
alias font_id font
+ alias name font
+ alias to_s font
def latin_font_id
@latinfont
@@ -964,11 +1150,18 @@ class TkFont
def latin_font
# @latinfont
+ if @descendant[0] # [0] -> latin
+ @descendant[0]
+ else
+ @descendant[0] = DescendantFont.new(self, 'latin')
+ end
+=begin
if @latin_descendant
@latin_descendant
else
@latin_descendant = DescendantFont.new(self, 'latin')
end
+=end
end
alias latinfont latin_font
@@ -978,50 +1171,87 @@ class TkFont
def kanji_font
# @kanjifont
+ if @descendant[1] # [1] -> kanji
+ @descendant[1]
+ else
+ @descendant[1] = DescendantFont.new(self, 'kanji')
+ end
+=begin
if @kanji_descendant
@kanji_descendant
else
@kanji_descendant = DescendantFont.new(self, 'kanji')
end
+=end
end
alias kanjifont kanji_font
def actual(option=nil)
actual_core(@compoundfont, nil, option)
end
+ def actual_hash(option=nil)
+ Hash[actual(option)]
+ end
def actual_displayof(win, option=nil)
win = '.' unless win
actual_core(@compoundfont, win, option)
end
+ def actual_hash_displayof(win, option=nil)
+ Hash[actual_displayof(win, option)]
+ end
def latin_actual(option=nil)
- actual_core(@latinfont, nil, option)
+ if @latinfont == nil
+ actual_core(@compoundfont, nil, option) # use @compoundfont
+ else
+ actual_core(@latinfont, nil, option)
+ end
+ end
+ def latin_actual_hash(option=nil)
+ Hash[latin_actual(option)]
end
def latin_actual_displayof(win, option=nil)
win = '.' unless win
- actual_core(@latinfont, win, option)
+ if @latinfont == nil
+ actual_core(@compoundfont, win, option) # use @compoundfont
+ else
+ actual_core(@latinfont, win, option)
+ end
+ end
+ def latin_actual_hash_displayof(win, option=nil)
+ Hash[latin_actual_displayof(win, option)]
end
def kanji_actual(option=nil)
#if JAPANIZED_TK
- if @kanjifont != ""
+ if @kanjifont == nil
+ actual_core(@compoundfont, nil, option) # use @compoundfont
+ elsif @kanjifont != ""
actual_core(@kanjifont, nil, option)
else
actual_core_tk4x(nil, nil, option)
end
end
+ def kanji_actual_hash(option=nil)
+ Hash[kanji_actual(option)]
+ end
def kanji_actual_displayof(win, option=nil)
#if JAPANIZED_TK
- if @kanjifont != ""
+ if @kanjifont == nil
+ actual_core(@compoundfont, nil, option) # use @compoundfont
+ elsif @kanjifont != ""
win = '.' unless win
actual_core(@kanjifont, win, option)
else
actual_core_tk4x(nil, win, option)
end
end
+ def kanji_actual_hash_displayof(win, option=nil)
+ Hash[kanji_actual_displayof(win, option)]
+ end
def [](slot)
configinfo slot
@@ -1065,10 +1295,15 @@ class TkFont
configinfo(slot)
end
end
+ def latin_current_configinfo(slot=nil)
+ Hash[latin_configinfo(slot)]
+ end
def kanji_configure(slot, value=None)
#if JAPANIZED_TK
- if @kanjifont != ""
+ if @kanjifont == nil
+ configure_core(@compoundfont, slot, value) # use @compoundfont
+ elsif @kanjifont != ""
configure_core(@kanjifont, slot, value)
configure('size'=>configinfo('size')) # to reflect new configuration
else
@@ -1080,13 +1315,18 @@ class TkFont
def kanji_configinfo(slot=nil)
#if JAPANIZED_TK
- if @kanjifont != ""
+ if @kanjifont == nil
+ configure_core(@compoundfont, slot) # use @compoundfont
+ elsif @kanjifont != ""
configinfo_core(@kanjifont, slot)
else
#[]
configinfo(slot)
end
end
+ def kanji_current_configinfo(slot=nil)
+ Hash[kanji_configinfo(slot)]
+ end
def replace(ltn, knj=None)
knj = ltn if knj == None
@@ -1096,12 +1336,30 @@ class TkFont
end
def latin_replace(ltn)
- latin_replace_core(ltn)
- reset_pointadjust
+ if @latinfont
+ latin_replace_core(ltn)
+ reset_pointadjust
+ else
+ # not compound font -> copy properties of ltn
+ latinkeys = {}
+ begin
+ actual_core(ltn).each{|key,val| latinkeys[key] = val}
+ rescue
+ latinkeys = {}
+ end
+ begin
+ tk_call('font', 'configure', @compoundfont, *hash_kv(latinkeys))
+ rescue
+ # not exist? (deleted?) -> create font
+ tk_call('font', 'create', @compoundfont, *hash_kv(latinkeys))
+ end
+ end
+
self
end
def kanji_replace(knj)
+ return self unless @kanjifont # ignore
kanji_replace_core(knj)
reset_pointadjust
self
@@ -1119,41 +1377,215 @@ class TkFont
def metrics(option=nil)
metrics_core(@compoundfont, nil, option)
end
+ def metrics_hash(option=nil)
+ if option
+ val = metrics(option)
+ case TkFont::MetricsType[option.to_s]
+ when ?n
+ val = TkComm::num_or_str(val)
+ when ?b
+ val = TkComm::bool(val)
+ else
+ # do nothing
+ end
+ return val
+ end
+
+ h = Hash[metrics(option)]
+ h.keys.each{|k|
+ case TkFont::MetricsType[k.to_s]
+ when ?n
+ h[k] = TkComm::num_or_str(h[k])
+ when ?b
+ h[k] = TkComm::bool(h[k])
+ else
+ # do nothing
+ end
+ }
+ h
+ end
def metrics_displayof(win, option=nil)
win = '.' unless win
metrics_core(@compoundfont, win, option)
end
+ def metrics_hash_displayof(win, option=nil)
+ if option
+ val = metrics_displayof(win, option)
+ case TkFont::MetricsType[option.to_s]
+ when ?n
+ val = TkComm::num_or_str(val)
+ when ?b
+ val = TkComm::bool(val)
+ else
+ # do nothing
+ end
+ return val
+ end
+
+ h = Hash[metrics_displayof(win, option)]
+ h.keys.each{|k|
+ case TkFont::MetricsType[k.to_s]
+ when ?n
+ h[k] = TkComm::num_or_str(h[k])
+ when ?b
+ h[k] = TkComm::bool(h[k])
+ else
+ # do nothing
+ end
+ }
+ h
+ end
def latin_metrics(option=nil)
- metrics_core(@latinfont, nil, option)
+ if @latinfont == nil
+ metrics_core(@compoundfont, nil, option) # use @compoundfont
+ else
+ metrics_core(@latinfont, nil, option)
+ end
+ end
+ def latin_metrics_hash(option=nil)
+ if option
+ val = latin_metrics(option)
+ case TkFont::MetricsType[option.to_s]
+ when ?n
+ val = TkComm::num_or_str(val)
+ when ?b
+ val = TkComm::bool(val)
+ else
+ # do nothing
+ end
+ return val
+ end
+
+ h = Hash[latin_metrics(option)]
+ h.keys.each{|k|
+ case TkFont::MetricsType[k.to_s]
+ when ?n
+ h[k] = TkComm::num_or_str(h[k])
+ when ?b
+ h[k] = TkComm::bool(h[k])
+ else
+ # do nothing
+ end
+ }
+ h
end
def latin_metrics_displayof(win, option=nil)
win = '.' unless win
- metrics_core(@latinfont, win, option)
+ if @latinfont == nil
+ metrics_core(@compoundfont, win, option) # use @compoundfont
+ else
+ metrics_core(@latinfont, win, option)
+ end
+ end
+ def latin_metrics_hash_displayof(win, option=nil)
+ if option
+ val = latin_metrics_displayof(win, option)
+ case TkFont::MetricsType[option.to_s]
+ when ?n
+ val = TkComm::num_or_str(val)
+ when ?b
+ val = TkComm::bool(val)
+ else
+ # do nothing
+ end
+ return val
+ end
+
+ h = Hash[latin_metrics_displayof(win, option)]
+ h.keys.each{|k|
+ case TkFont::MetricsType[k.to_s]
+ when ?n
+ h[k] = TkComm::num_or_str(h[k])
+ when ?b
+ h[k] = TkComm::bool(h[k])
+ else
+ # do nothing
+ end
+ }
+ h
end
def kanji_metrics(option=nil)
- if JAPANIZED_TK
+ if @latinfont == nil
+ metrics_core(@compoundfont, nil, option) # use @compoundfont
+ elsif JAPANIZED_TK
metrics_core(@kanjifont, nil, option)
else
metrics_core_tk4x(nil, nil, option)
end
end
+ def kanji_metrics_hash(option=nil)
+ if option
+ val = kanji_metrics(option)
+ case TkFont::MetricsType[option.to_s]
+ when ?n
+ val = TkComm::num_or_str(val)
+ when ?b
+ val = TkComm::bool(val)
+ else
+ # do nothing
+ end
+ return val
+ end
+
+ h = Hash[kanji_metrics(option)]
+ h.keys.each{|k|
+ case TkFont::MetricsType[k.to_s]
+ when ?n
+ h[k] = TkComm::num_or_str(h[k])
+ when ?b
+ h[k] = TkComm::bool(h[k])
+ else
+ # do nothing
+ end
+ }
+ h
+ end
def kanji_metrics_displayof(win, option=nil)
- if JAPANIZED_TK
- win = '.' unless win
+ win = '.' unless win
+ if @latinfont == nil
+ metrics_core(@compoundfont, win, option) # use @compoundfont
+ elsif JAPANIZED_TK
metrics_core(@kanjifont, win, option)
else
metrics_core_tk4x(nil, win, option)
end
end
+ def kanji_metrics_hash_displayof(win, option=nil)
+ if option
+ val = kanji_metrics_displayof(win, option)
+ case TkFont::MetricsType[option.to_s]
+ when ?n
+ val = TkComm::num_or_str(val)
+ when ?b
+ val = TkComm::bool(val)
+ else
+ # do nothing
+ end
+ return val
+ end
+
+ h = Hash[kanji_metrics_displayof(win, option)]
+ h.keys.each{|k|
+ case TkFont::MetricsType[k.to_s]
+ when ?n
+ h[k] = TkComm::num_or_str(h[k])
+ when ?b
+ h[k] = TkComm::bool(h[k])
+ else
+ # do nothing
+ end
+ }
+ h
+ end
def reset_pointadjust
begin
- if /^8\.*/ === Tk::TK_VERSION && JAPANIZED_TK
+ if /^8\..*/ === Tk::TK_VERSION && JAPANIZED_TK
configure('pointadjust' => latin_actual.assoc('size')[1].to_f /
kanji_actual.assoc('size')[1].to_f )
end
@@ -1166,7 +1598,7 @@ class TkFont
# private alias
###################################
case (Tk::TK_VERSION)
- when /^4\.*/
+ when /^4\..*/
alias create_latinfont create_latinfont_tk4x
alias create_kanjifont create_kanjifont_tk4x
alias create_compoundfont create_compoundfont_tk4x
@@ -1449,7 +1881,7 @@ module TkFont::CoreMethods
end
else
l = tk_split_simplelist(tk_call('font', 'configure', font))
- r = {}
+ h = {}
while key=l.shift
if key == '-compound'
l.shift
@@ -1458,45 +1890,57 @@ module TkFont::CoreMethods
val = l.shift
case TkFont::OptionType[key]
when ?n
- r.push [key, num_or_str(val)]
+ h[key] = num_or_str(val)
when ?b
- r.push [key, bool(val)]
+ h[key] = bool(val)
else
- r.push [key, val]
+ h[key] = val
end
end
end
- r
+ h
end
end
def delete_core_tk4x
- TkFont::Tk_FontNameTBL.delete(@id)
- TkFont::Tk_FontUseTBL.delete_if{|key,value| value == self}
+ TkFont::Tk_FontNameTBL.mutex.synchronize{
+ TkFont::Tk_FontNameTBL.delete(@id)
+ }
+ TkFont::Tk_FontUseTBL.mutex.synchronize{
+ TkFont::Tk_FontUseTBL.delete_if{|key,value| value == self}
+ }
end
def delete_core_tk8x
begin
- tk_call('font', 'delete', @latinfont)
+ tk_call('font', 'delete', @latinfont) if @latinfont
rescue
end
begin
- tk_call('font', 'delete', @kanjifont)
+ tk_call('font', 'delete', @kanjifont) if @kanjifont
rescue
end
begin
- tk_call('font', 'delete', @compoundfont)
+ tk_call('font', 'delete', @compoundfont) if @compoundfont
rescue
end
- TkFont::Tk_FontNameTBL.delete(@id)
- TkFont::Tk_FontUseTBL.delete_if{|key,value| value == self}
+ TkFont::Tk_FontNameTBL.mutex.synchronize{
+ TkFont::Tk_FontNameTBL.delete(@id)
+ }
+ TkFont::Tk_FontUseTBL.mutex.synchronize{
+ TkFont::Tk_FontUseTBL.delete_if{|key,value| value == self}
+ }
end
def latin_replace_core_tk4x(ltn)
create_latinfont_tk4x(ltn)
@compoundfont[0] = [@latinfont] if JAPANIZED_TK
@fontslot['font'] = @latinfont
- TkFont::Tk_FontUseTBL.dup.each{|w, fobj|
+ table = nil
+ TkFont::Tk_FontUseTBL.mutex.synchronize{
+ table = TkFont::Tk_FontUseTBL.clone
+ }
+ table.each{|w, fobj|
if self == fobj
begin
if w.include?(';')
@@ -1504,11 +1948,14 @@ module TkFont::CoreMethods
optkey = 'font' if optkey == nil || optkey == ''
winobj = tk_tcl2ruby(win)
# winobj.tagfont_configure(tag, {'font'=>@latinfont})
- if winobj.kind_of? TkText
+ #if winobj.kind_of? TkText
+ if winobj.kind_of?(TkText) || winobj.kind_of?(Tk::Text)
tk_call(win, 'tag', 'configure', tag, "-#{optkey}", @latinfont)
- elsif winobj.kind_of? TkCanvas
+ #elsif winobj.kind_of? TkCanvas
+ elsif winobj.kind_of?(TkCanvas) || winobj.kind_of?(Tk::Canvas)
tk_call(win, 'itemconfigure', tag, "-#{optkey}", @latinfont)
- elsif winobj.kind_of? TkMenu
+ #elsif winobj.kind_of? TkMenu
+ elsif winobj.kind_of?(TkMenu) || winobj.kind_of?(Tk::Menu)
tk_call(win, 'entryconfigure', tag, "-#{optkey}", @latinfont)
else
raise RuntimeError, "unknown widget type"
@@ -1518,7 +1965,9 @@ module TkFont::CoreMethods
tk_call(w, 'configure', '-font', @latinfont)
end
rescue
- TkFont::Tk_FontUseTBL.delete(w)
+ TkFont::Tk_FontUseTBL.mutex.synchronize{
+ TkFont::Tk_FontUseTBL.delete(w)
+ }
end
end
}
@@ -1531,7 +1980,11 @@ module TkFont::CoreMethods
create_kanjifont_tk4x(knj)
@compoundfont[1] = [@kanjifont]
@fontslot['kanjifont'] = @kanjifont
- TkFont::Tk_FontUseTBL.dup.each{|w, fobj|
+ table = nil
+ TkFont::Tk_FontUseTBL.mutex.synchronize{
+ table = TkFont::Tk_FontUseTBL.clone
+ }
+ table.dup.each{|w, fobj|
if self == fobj
begin
if w.include?(';')
@@ -1539,11 +1992,14 @@ module TkFont::CoreMethods
optkey = 'kanjifont' unless optkey
winobj = tk_tcl2ruby(win)
# winobj.tagfont_configure(tag, {'kanjifont'=>@kanjifont})
- if winobj.kind_of? TkText
+ #if winobj.kind_of? TkText
+ if winobj.kind_of?(TkText) || winobj.kind_of?(Tk::Text)
tk_call(win, 'tag', 'configure', tag, "-#{optkey}", @kanjifont)
- elsif winobj.kind_of? TkCanvas
+ #elsif winobj.kind_of? TkCanvas
+ elsif winobj.kind_of?(TkCanvas) || winobj.kind_of?(Tk::Canvas)
tk_call(win, 'itemconfigure', tag, "-#{optkey}", @kanjifont)
- elsif winobj.kind_of? TkMenu
+ #elsif winobj.kind_of? TkMenu
+ elsif winobj.kind_of?(TkMenu) || winobj.kind_of?(Tk::Menu)
tk_call(win, 'entryconfigure', tag, "-#{optkey}", @latinfont)
else
raise RuntimeError, "unknown widget type"
@@ -1553,7 +2009,9 @@ module TkFont::CoreMethods
tk_call(w, 'configure', '-kanjifont', @kanjifont)
end
rescue
- TkFont::Tk_FontUseTBL.delete(w)
+ Tk_FontUseTBL.mutex.synchronize{
+ TkFont::Tk_FontUseTBL.delete(w)
+ }
end
end
}
@@ -1618,8 +2076,11 @@ module TkFont::CoreMethods
rescue
latinkeys = {}
end
- if latinkeys != {}
+ begin
tk_call('font', 'configure', @compoundfont, *hash_kv(latinkeys))
+ rescue
+ # not exist? (deleted?) -> create font
+ tk_call('font', 'create', @compoundfont, *hash_kv(latinkeys))
end
end
self
@@ -1711,6 +2172,13 @@ module TkFont::CoreMethods
r = []
while key=l.shift
r.push [key[1..-1], l.shift.to_i]
+=begin
+ if key == '-fixed' # boolean value
+ r.push [key[1..-1], bool(l.shift)]
+ else
+ r.push [key[1..-1], l.shift.to_i]
+ end
+=end
end
r
end
@@ -1720,7 +2188,7 @@ module TkFont::CoreMethods
# private alias
###################################
case (Tk::TK_VERSION)
- when /^4\.*/
+ when /^4\..*/
alias actual_core actual_core_tk4x
alias configure_core configure_core_tk4x
alias configinfo_core configinfo_core_tk4x
@@ -1760,3 +2228,117 @@ class TkFont
include TkFont::CoreMethods
extend TkFont::CoreMethods
end
+
+class TkNamedFont < TkFont
+ # for built-in named fonts
+ def TkNamedFont.find(name)
+ name = name.to_s
+ unless (obj = Tk_FontNameTBL[name])
+ obj = self.new(name) if TkFont.is_system_font?(name)
+ end
+ obj
+ end
+
+ def TkNamedFont.new(name, keys=nil)
+ name = name.to_s
+ obj = nil
+ Tk_FontNameTBL.mutex.synchronize{
+ unless (obj = Tk_FontNameTBL[name])
+ (obj = self.allocate).instance_eval{
+ @id = @compoundfont = name.to_s
+ @latinfont = nil
+ @kanjifont = nil
+ @descendant = [self, self] # [latin, kanji] : dummy
+ Tk_FontNameTBL[@id] = self
+ }
+ end
+ }
+ obj.instance_eval{ initialize(name, keys) }
+ obj
+ end
+
+ ###########################
+ private
+ ###########################
+ def initialize(name, keys=nil)
+ @id = @compoundfont = name.to_s
+
+ # if not exist named font, create it.
+ begin
+ if keys
+ tk_call('font', 'configure', @compoundfont, keys)
+ else
+ tk_call('font', 'configure', @compoundfont)
+ end
+ rescue
+ # the named font doesn't exist -> create
+ if keys
+ tk_call('font', 'create', @compoundfont, keys)
+ else
+ tk_call('font', 'create', @compoundfont)
+ end
+ end
+ end
+
+ def create_latinfont(fnt)
+ # ignore
+ end
+ def create_kanjifont(fnt)
+ # ignore
+ end
+ def create_compoundfont(ltn, knj, keys)
+ # ignore
+ end
+
+ ###########################
+ public
+ ###########################
+ def latin_font_id
+ @compoundfont
+ end
+ def kanji_font_id
+ @compoundfont
+ end
+end
+
+#######################################
+# define system font names
+#######################################
+if Tk::TCL_MAJOR_VERSION > 8 ||
+ (Tk::TCL_MAJOR_VERSION == 8 && Tk::TCL_MINOR_VERSION >= 5)
+ # add standard fonts of Tcl/Tk 8.5+
+ TkFont::SYSTEM_FONT_NAMES.add [
+ 'TkDefaultFont', 'TkTextFont', 'TkFixedFont', 'TkMenuFont',
+ 'TkHeadingFont', 'TkCaptionFont', 'TkSmallCaptionFont',
+ 'TkIconFont', 'TkTooltipFont'
+ ]
+end
+
+# platform-specific fonts
+# -- windows
+TkFont::SYSTEM_FONT_NAMES.add [
+ 'ansifixed', 'ansi', 'device', 'oemfixed', 'systemfixed', 'system'
+]
+
+# -- macintosh, macosx
+TkFont::SYSTEM_FONT_NAMES.add ['system', 'application']
+
+if Tk::TCL_MAJOR_VERSION > 8 ||
+ (Tk::TCL_MAJOR_VERSION == 8 && Tk::TCL_MINOR_VERSION >= 5)
+ TkFont::SYSTEM_FONT_NAMES.add ['menu']
+end
+
+# -- macosx (Aqua theme)
+if Tk::TCL_MAJOR_VERSION > 8 ||
+ (Tk::TCL_MAJOR_VERSION == 8 && Tk::TCL_MINOR_VERSION >= 5)
+ TkFont::SYSTEM_FONT_NAMES.add [
+ 'systemSystemFont', 'systemEmphasizedSystemFont',
+ 'systemSmallSystemFont', 'systemSmallEmphasizedSystemFont',
+ 'systemApplicationFont', 'systemLabelFont', 'systemViewsFont',
+ 'systemMenuTitleFont', 'systemMenuItemFont', 'systemMenuItemMarkFont',
+ 'systemMenuItemCmdKeyFont', 'systemWindowTitleFont',
+ 'systemPushButtonFont', 'systemUtilityWindowTitleFont',
+ 'systemAlertHeaderFont', 'systemToolbarFont', 'systemMiniSystemFont',
+ 'systemDetailSystemFont', 'systemDetailEmphasizedSystemFont'
+ ]
+end
diff --git a/ext/tk/lib/tk/frame.rb b/ext/tk/lib/tk/frame.rb
index 6636fef5b5..263b160f29 100644
--- a/ext/tk/lib/tk/frame.rb
+++ b/ext/tk/lib/tk/frame.rb
@@ -3,7 +3,7 @@
#
require 'tk'
-class TkFrame<TkWindow
+class Tk::Frame<TkWindow
TkCommandNames = ['frame'.freeze].freeze
WidgetClassName = 'Frame'.freeze
WidgetClassNames[WidgetClassName] = self
@@ -126,3 +126,6 @@ class TkFrame<TkWindow
end
end
end
+
+#TkFrame = Tk::Frame unless Object.const_defined? :TkFrame
+Tk.__set_toplevel_aliases__(:Tk, Tk::Frame, :TkFrame)
diff --git a/ext/tk/lib/tk/grid.rb b/ext/tk/lib/tk/grid.rb
index 10fdf3569b..0dfd7263a7 100644
--- a/ext/tk/lib/tk/grid.rb
+++ b/ext/tk/lib/tk/grid.rb
@@ -22,6 +22,7 @@ module TkGrid
list(tk_call_without_enc('grid', 'bbox', *args))
end
+=begin
def configure(win, *args)
if args[-1].kind_of?(Hash)
opts = args.pop
@@ -53,6 +54,48 @@ module TkGrid
tk_call_without_enc('grid', 'configure', *params)
end
end
+=end
+ def configure(*args)
+ if args[-1].kind_of?(Hash)
+ opts = args.pop
+ else
+ opts = {}
+ end
+ fail ArgumentError, 'no widget is given' if args.empty?
+ params = []
+ args.flatten(1).each{|win|
+ case win
+ when '-', ?- # RELATIVE PLACEMENT (increase columnspan)
+ params.push('-')
+ when /^-+$/ # RELATIVE PLACEMENT (increase columnspan)
+ params.concat(win.to_s.split(//))
+ when '^', ?^ # RELATIVE PLACEMENT (increase rowspan)
+ params.push('^')
+ when /^\^+$/ # RELATIVE PLACEMENT (increase rowspan)
+ params.concat(win.to_s.split(//))
+ when 'x', :x, ?x, nil, '' # RELATIVE PLACEMENT (empty column)
+ params.push('x')
+ when /^x+$/ # RELATIVE PLACEMENT (empty column)
+ params.concat(win.to_s.split(//))
+ else
+ params.push(_epath(win))
+ end
+ }
+ opts.each{|k, v|
+ params.push("-#{k}")
+ params.push(_epath(v)) # have to use 'epath' (hash_kv() is unavailable)
+ }
+ if Tk::TCL_MAJOR_VERSION < 8 ||
+ (Tk::TCL_MAJOR_VERSION == 8 && Tk::TCL_MINOR_VERSION <= 3)
+ if params[0] == '-' || params[0] == 'x' || params[0] == '^'
+ tk_call_without_enc('grid', *params)
+ else
+ tk_call_without_enc('grid', 'configure', *params)
+ end
+ else
+ tk_call_without_enc('grid', 'configure', *params)
+ end
+ end
alias grid configure
def columnconfigure(master, index, args)
@@ -61,12 +104,14 @@ module TkGrid
tk_call_without_enc("grid", 'columnconfigure',
master, index, *hash_kv(args))
end
+ alias column columnconfigure
def rowconfigure(master, index, args)
# master = master.epath if master.kind_of?(TkObject)
master = _epath(master)
tk_call_without_enc("grid", 'rowconfigure', master, index, *hash_kv(args))
end
+ alias row rowconfigure
def columnconfiginfo(master, index, slot=nil)
# master = master.epath if master.kind_of?(TkObject)
@@ -189,10 +234,10 @@ module TkGrid
list(tk_call_without_enc('grid', 'slaves', master, *hash_kv(args)))
end
- module_function :bbox, :forget, :propagate, :info
+ module_function :anchor, :bbox, :add, :forget, :propagate, :info
module_function :remove, :size, :slaves, :location
module_function :grid, :configure, :columnconfigure, :rowconfigure
- module_function :columnconfiginfo, :rowconfiginfo
+ module_function :column, :row, :columnconfiginfo, :rowconfiginfo
end
=begin
def TkGrid(win, *args)
diff --git a/ext/tk/lib/tk/image.rb b/ext/tk/lib/tk/image.rb
index 35e2c4e394..dffdc19644 100644
--- a/ext/tk/lib/tk/image.rb
+++ b/ext/tk/lib/tk/image.rb
@@ -10,9 +10,16 @@ class TkImage<TkObject
TkCommandNames = ['image'.freeze].freeze
Tk_IMGTBL = TkCore::INTERP.create_table
- Tk_Image_ID = ['i'.freeze, '00000'.taint].freeze
- TkCore::INTERP.init_ip_env{ Tk_IMGTBL.clear }
+ (Tk_Image_ID = ['i'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
+ TkCore::INTERP.init_ip_env{
+ Tk_IMGTBL.mutex.synchronize{ Tk_IMGTBL.clear }
+ }
def self.new(keys=nil)
if keys.kind_of?(Hash)
@@ -27,7 +34,10 @@ class TkImage<TkObject
obj = name
else
name = _get_eval_string(name)
- obj = Tk_IMGTBL[name]
+ obj = nil
+ Tk_IMGTBL.mutex.synchronize{
+ obj = Tk_IMGTBL[name]
+ }
end
if obj
if !(keys[:without_creating] || keys['without_creating'])
@@ -43,7 +53,13 @@ class TkImage<TkObject
end
end
end
- super(keys)
+ (obj = self.allocate).instance_eval{
+ Tk_IMGTBL.mutex.synchronize{
+ initialize(keys)
+ Tk_IMGTBL[@path] = self
+ }
+ }
+ obj
end
def initialize(keys=nil)
@@ -55,19 +71,22 @@ class TkImage<TkObject
without_creating = keys.delete('without_creating')
end
unless @path
- # @path = Tk_Image_ID.join('')
- @path = Tk_Image_ID.join(TkCore::INTERP._ip_id_)
- Tk_Image_ID[1].succ!
+ Tk_Image_ID.mutex.synchronize{
+ # @path = Tk_Image_ID.join('')
+ @path = Tk_Image_ID.join(TkCore::INTERP._ip_id_)
+ Tk_Image_ID[1].succ!
+ }
end
unless without_creating
tk_call_without_enc('image', 'create',
@type, @path, *hash_kv(keys, true))
end
- Tk_IMGTBL[@path] = self
end
def delete
- Tk_IMGTBL.delete(@id) if @id
+ Tk_IMGTBL.mutex.synchronize{
+ Tk_IMGTBL.delete(@id) if @id
+ }
tk_call_without_enc('image', 'delete', @path)
self
end
@@ -85,8 +104,10 @@ class TkImage<TkObject
end
def TkImage.names
- Tk.tk_call_without_enc('image', 'names').split.collect!{|id|
- (Tk_IMGTBL[id])? Tk_IMGTBL[id] : id
+ Tk_IMGTBL.mutex.synchronize{
+ Tk.tk_call_without_enc('image', 'names').split.collect!{|id|
+ (Tk_IMGTBL[id])? Tk_IMGTBL[id] : id
+ }
}
end
@@ -135,7 +156,7 @@ class TkPhotoImage<TkImage
self
end
- def cget(option)
+ def cget_strict(option)
case option.to_s
when 'data', 'file'
tk_send 'cget', '-' << option.to_s
@@ -143,6 +164,23 @@ class TkPhotoImage<TkImage
tk_tcl2ruby(tk_send('cget', '-' << option.to_s))
end
end
+ def cget(option)
+ unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ cget_strict(option)
+ else
+ begin
+ cget_strict(option)
+ rescue => e
+ if current_configinfo.has_key?(option.to_s)
+ # error on known option
+ fail e
+ else
+ # unknown option
+ nil
+ end
+ end
+ end
+ end
def copy(src, *opts)
if opts.size == 0
diff --git a/ext/tk/lib/tk/itemconfig.rb b/ext/tk/lib/tk/itemconfig.rb
index 0b84be38b8..9c6a98d0f8 100644
--- a/ext/tk/lib/tk/itemconfig.rb
+++ b/ext/tk/lib/tk/itemconfig.rb
@@ -8,6 +8,11 @@ require 'tk/itemfont.rb'
module TkItemConfigOptkeys
include TkUtil
+ def __item_optkey_aliases(id)
+ {}
+ end
+ private :__item_optkey_aliases
+
def __item_numval_optkeys(id)
[]
end
@@ -115,6 +120,14 @@ module TkItemConfigMethod
include TkTreatItemFont
include TkItemConfigOptkeys
+ def TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ @mode || false
+ end
+ def TkItemConfigMethod.__set_IGNORE_UNKNOWN_CONFIGURE_OPTION__!(mode)
+ fail SecurityError, "can't change the mode" if $SAFE>=4
+ @mode = (mode)? true: false
+ end
+
def __item_cget_cmd(id)
# maybe need to override
[self.path, 'itemcget', id]
@@ -149,7 +162,7 @@ module TkItemConfigMethod
################################################
- def itemcget(tagOrId, option)
+ def __itemcget_core(tagOrId, option)
orig_opt = option
option = option.to_s
@@ -157,6 +170,11 @@ module TkItemConfigMethod
fail ArgumentError, "Invalid option `#{orig_opt.inspect}'"
end
+ alias_name, real_name = __item_optkey_aliases(tagid(tagOrId)).find{|k, v| k.to_s == option}
+ if real_name
+ option = real_name.to_s
+ end
+
if ( method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[option] )
optval = tk_call_without_enc(*(__item_cget_cmd(tagid(tagOrId)) << "-#{option}"))
begin
@@ -224,11 +242,45 @@ module TkItemConfigMethod
tk_tcl2ruby(tk_call_without_enc(*(__item_cget_cmd(tagid(tagOrId)) << "-#{option}")), true)
end
end
+ private :__itemcget_core
- def itemconfigure(tagOrId, slot, value=None)
+ def itemcget(tagOrId, option)
+ unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ __itemcget_core(tagOrId, option)
+ else
+ begin
+ __itemcget_core(tagOrId, option)
+ rescue => e
+ begin
+ if __current_itemconfiginfo(tagOrId).has_key?(option.to_s)
+ # not tag error & option is known -> error on known option
+ fail e
+ else
+ # not tag error & option is unknown
+ nil
+ end
+ rescue
+ fail e # tag error
+ end
+ end
+ end
+ end
+ def itemcget_strict(tagOrId, option)
+ # never use TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ __itemcget_core(tagOrId, option)
+ end
+
+ def __itemconfigure_core(tagOrId, slot, value=None)
if slot.kind_of? Hash
slot = _symbolkey2str(slot)
+ __item_optkey_aliases(tagid(tagOrId)).each{|alias_name, real_name|
+ alias_name = alias_name.to_s
+ if slot.has_key?(alias_name)
+ slot[real_name.to_s] = slot.delete(alias_name)
+ end
+ }
+
__item_methodcall_optkeys(tagid(tagOrId)).each{|key, method|
value = slot.delete(key.to_s)
self.__send__(method, tagOrId, value) if value
@@ -265,6 +317,11 @@ module TkItemConfigMethod
fail ArgumentError, "Invalid option `#{orig_slot.inspect}'"
end
+ alias_name, real_name = __item_optkey_aliases(tagid(tagOrId)).find{|k, v| k.to_s == slot}
+ if real_name
+ slot = real_name.to_s
+ end
+
if ( conf = __item_keyonly_optkeys(tagid(tagOrId)).find{|k, v| k.to_s == slot } )
defkey, undefkey = conf
if value
@@ -288,8 +345,58 @@ module TkItemConfigMethod
end
self
end
+ private :__itemconfigure_core
- def itemconfiginfo(tagOrId, slot = nil)
+ def __check_available_itemconfigure_options(tagOrId, keys)
+ id = tagid(tagOrId)
+
+ availables = self.__current_itemconfiginfo(id).keys
+
+ # add non-standard keys
+ availables |= __font_optkeys.map{|k|
+ [k.to_s, "latin#{k}", "ascii#{k}", "kanji#{k}"]
+ }.flatten
+ availables |= __item_methodcall_optkeys(id).keys.map{|k| k.to_s}
+ availables |= __item_keyonly_optkeys(id).keys.map{|k| k.to_s}
+
+ keys = _symbolkey2str(keys)
+
+ keys.delete_if{|k, v| !(availables.include?(k))}
+ end
+
+ def itemconfigure(tagOrId, slot, value=None)
+ unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ __itemconfigure_core(tagOrId, slot, value)
+ else
+ if slot.kind_of?(Hash)
+ begin
+ __itemconfigure_core(tagOrId, slot)
+ rescue
+ slot = __check_available_itemconfigure_options(tagOrId, slot)
+ __itemconfigure_core(tagOrId, slot) unless slot.empty?
+ end
+ else
+ begin
+ __itemconfigure_core(tagOrId, slot, value)
+ rescue => e
+ begin
+ if __current_itemconfiginfo(tagOrId).has_key?(slot.to_s)
+ # not tag error & option is known -> error on known option
+ fail e
+ else
+ # not tag error & option is unknown
+ nil
+ end
+ rescue
+ fail e # tag error
+ end
+ end
+ end
+ end
+ self
+ end
+
+ def __itemconfiginfo_core(tagOrId, slot = nil)
if TkComm::GET_CONFIGINFO_AS_ARRAY
if (slot && slot.to_s =~ /^(|latin|ascii|kanji)(#{__item_font_optkeys(tagid(tagOrId)).join('|')})$/)
fontkey = $2
@@ -299,6 +406,10 @@ module TkItemConfigMethod
conf[__item_configinfo_struct(tagid(tagOrId))[:key]][1..-1]
if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \
|| conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 )
+ fnt = conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]
+ if TkFont.is_system_font?(fnt)
+ conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = TkNamedFont.new(fnt)
+ end
conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = tagfontobj(tagid(tagOrId), fontkey)
elsif ( __item_configinfo_struct(tagid(tagOrId))[:alias] \
&& conf.size == __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 \
@@ -310,6 +421,12 @@ module TkItemConfigMethod
else
if slot
slot = slot.to_s
+
+ alias_name, real_name = __item_optkey_aliases(tagid(tagOrId)).find{|k, v| k.to_s == slot}
+ if real_name
+ slot = real_name.to_s
+ end
+
case slot
when /^(#{__item_val2ruby_optkeys(tagid(tagOrId)).keys.join('|')})$/
method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[slot]
@@ -594,7 +711,7 @@ module TkItemConfigMethod
if v.empty?
conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = nil
else
- conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = TkVarAccess.new
+ conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = TkVarAccess.new(v)
end
end
@@ -635,6 +752,10 @@ module TkItemConfigMethod
fontconf = ret.assoc(optkey)
if fontconf && fontconf.size > 2
ret.delete_if{|inf| inf[0] =~ /^(|latin|ascii|kanji)#{optkey}$/}
+ fnt = fontconf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]
+ if TkFont.is_system_font?(fnt)
+ fontconf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = TkNamedFont.new(fnt)
+ end
fontconf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = tagfontobj(tagid(tagOrId), optkey)
ret.push(fontconf)
end
@@ -658,7 +779,11 @@ module TkItemConfigMethod
if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \
|| conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 )
- conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = fontobj(tagid(tagOrId), fontkey)
+ fnt = conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]
+ if TkFont.is_system_font?(fnt)
+ conf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = TkNamedFont.new(fnt)
+ end
+ conf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = tagfontobj(tagid(tagOrId), fontkey)
{ conf.shift => conf }
elsif ( __item_configinfo_struct(tagid(tagOrId))[:alias] \
&& conf.size == __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 )
@@ -673,6 +798,12 @@ module TkItemConfigMethod
else
if slot
slot = slot.to_s
+
+ alias_name, real_name = __item_optkey_aliases(tagid(tagOrId)).find{|k, v| k.to_s == slot}
+ if real_name
+ slot = real_name.to_s
+ end
+
case slot
when /^(#{__item_val2ruby_optkeys(tagid(tagOrId)).keys.join('|')})$/
method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[slot]
@@ -1006,6 +1137,10 @@ module TkItemConfigMethod
ret.delete('latin' << optkey)
ret.delete('ascii' << optkey)
ret.delete('kanji' << optkey)
+ fnt = fontconf[__item_configinfo_struct(tagid(tagOrId))[:default_value]]
+ if TkFont.is_system_font?(fnt)
+ fontconf[__item_configinfo_struct(tagid(tagOrId))[:default_value]] = TkNamedFont.new(fnt)
+ end
fontconf[__item_configinfo_struct(tagid(tagOrId))[:current_value]] = tagfontobj(tagid(tagOrId), optkey)
ret[optkey] = fontconf
end
@@ -1020,13 +1155,32 @@ module TkItemConfigMethod
end
end
end
+ private :__itemconfiginfo_core
- def current_itemconfiginfo(tagOrId, slot = nil)
+ def itemconfiginfo(tagOrId, slot = nil)
+ if slot && TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ begin
+ __itemconfiginfo_core(tagOrId, slot)
+ rescue => e
+ begin
+ __itemconfiginfo_core(tagOrId)
+ # not tag error -> option is unknown
+ Array.new(__item_configinfo_struct.values.max).unshift(slot.to_s)
+ rescue
+ fail e # tag error
+ end
+ end
+ else
+ __itemconfiginfo_core(tagOrId, slot)
+ end
+ end
+
+ def __current_itemconfiginfo(tagOrId, slot = nil)
if TkComm::GET_CONFIGINFO_AS_ARRAY
if slot
org_slot = slot
begin
- conf = itemconfiginfo(tagOrId, slot)
+ conf = __itemconfiginfo_core(tagOrId, slot)
if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \
|| conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 )
return {conf[0] => conf[-1]}
@@ -1037,20 +1191,25 @@ module TkItemConfigMethod
"there is a configure alias loop about '#{org_slot}'"
else
ret = {}
- itemconfiginfo(tagOrId).each{|conf|
+ __itemconfiginfo_core(tagOrId).each{|conf|
if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \
|| conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 )
ret[conf[0]] = conf[-1]
end
}
+
ret
end
else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
ret = {}
- itemconfiginfo(slot).each{|key, conf|
+ __itemconfiginfo_core(tagOrId, slot).each{|key, conf|
ret[key] = conf[-1] if conf.kind_of?(Array)
}
ret
end
end
+
+ def current_itemconfiginfo(tagOrId, slot = nil)
+ __current_itemconfiginfo(tagOrId, slot)
+ end
end
diff --git a/ext/tk/lib/tk/itemfont.rb b/ext/tk/lib/tk/itemfont.rb
index ab9e3ff6c9..4c5c917c57 100644
--- a/ext/tk/lib/tk/itemfont.rb
+++ b/ext/tk/lib/tk/itemfont.rb
@@ -94,7 +94,16 @@ module TkTreatItemFont
*(__item_config_cmd(tagid(tagOrId)) << {}))
next
else
- tk_call(*(__item_config_cmd(tagid(tagOrId)) << "-#{optkey}" << fnt))
+ fnt = hash_kv(fnt) if fnt.kind_of?(Hash)
+ unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ tk_call(*(__item_config_cmd(tagid(tagOrId)) << "-#{optkey}" << fnt))
+ else
+ begin
+ tk_call(*(__item_config_cmd(tagid(tagOrId)) << "-#{optkey}" << fnt))
+ rescue => e
+ # ignore
+ end
+ end
end
end
next
@@ -147,7 +156,16 @@ module TkTreatItemFont
elsif Tk::JAPANIZED_TK
fobj = fontobj # create a new TkFont object
else
- tk_call(*(__item_config_cmd(tagid(tagOrId)) << "-#{optkey}" << ltn))
+ ltn = hash_kv(ltn) if ltn.kind_of?(Hash)
+ unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ tk_call(*(__item_config_cmd(tagid(tagOrId)) << "-#{optkey}" << ltn))
+ else
+ begin
+ tk_call(*(__item_config_cmd(tagid(tagOrId)) << "-#{optkey}" << ltn))
+ rescue => e
+ # ignore
+ end
+ end
next
end
@@ -198,7 +216,16 @@ module TkTreatItemFont
elsif Tk::JAPANIZED_TK
fobj = fontobj # create a new TkFont object
else
- tk_call(*(__item_config_cmd(tagid(tagOrId)) << "-#{optkey}" << knj))
+ knj = hash_kv(knj) if knj.kind_of?(Hash)
+ unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ tk_call(*(__item_config_cmd(tagid(tagOrId)) << "-#{optkey}" << knj))
+ else
+ begin
+ tk_call(*(__item_config_cmd(tagid(tagOrId)) << "-#{optkey}" << knj))
+ rescue => e
+ # ignore
+ end
+ end
next
end
diff --git a/ext/tk/lib/tk/label.rb b/ext/tk/lib/tk/label.rb
index 8b45db9b30..80b3d778f1 100644
--- a/ext/tk/lib/tk/label.rb
+++ b/ext/tk/lib/tk/label.rb
@@ -3,7 +3,7 @@
#
require 'tk'
-class TkLabel<TkWindow
+class Tk::Label<TkWindow
TkCommandNames = ['label'.freeze].freeze
WidgetClassName = 'Label'.freeze
WidgetClassNames[WidgetClassName] = self
@@ -16,3 +16,6 @@ class TkLabel<TkWindow
#end
#private :create_self
end
+
+#TkLabel = Tk::Label unless Object.const_defined? :TkLabel
+Tk.__set_toplevel_aliases__(:Tk, Tk::Label, :TkLabel)
diff --git a/ext/tk/lib/tk/labelframe.rb b/ext/tk/lib/tk/labelframe.rb
index 73d5603200..995b5b7e72 100644
--- a/ext/tk/lib/tk/labelframe.rb
+++ b/ext/tk/lib/tk/labelframe.rb
@@ -4,7 +4,7 @@
require 'tk'
require 'tk/frame'
-class TkLabelFrame<TkFrame
+class Tk::LabelFrame<Tk::Frame
TkCommandNames = ['labelframe'.freeze].freeze
WidgetClassName = 'Labelframe'.freeze
WidgetClassNames[WidgetClassName] = self
@@ -22,4 +22,8 @@ class TkLabelFrame<TkFrame
end
private :__val2ruby_optkeys
end
-TkLabelframe = TkLabelFrame
+
+Tk::Labelframe = Tk::LabelFrame
+#TkLabelFrame = Tk::LabelFrame unless Object.const_defined? :TkLabelFrame
+#TkLabelframe = Tk::Labelframe unless Object.const_defined? :TkLabelframe
+Tk.__set_toplevel_aliases__(:Tk, Tk::LabelFrame, :TkLabelFrame, :TkLabelframe)
diff --git a/ext/tk/lib/tk/listbox.rb b/ext/tk/lib/tk/listbox.rb
index 41d02d279e..bb039ffb0e 100644
--- a/ext/tk/lib/tk/listbox.rb
+++ b/ext/tk/lib/tk/listbox.rb
@@ -15,7 +15,7 @@ module TkListItemConfig
private :__item_listval_optkeys
end
-class TkListbox<TkTextWin
+class Tk::Listbox<TkTextWin
include TkListItemConfig
include Scrollable
@@ -277,3 +277,6 @@ class TkListbox<TkTextWin
end
=end
end
+
+#TkListbox = Tk::Listbox unless Object.const_defined? :TkListbox
+Tk.__set_toplevel_aliases__(:Tk, Tk::Listbox, :TkListbox)
diff --git a/ext/tk/lib/tk/macpkg.rb b/ext/tk/lib/tk/macpkg.rb
index 1802073f46..67b0a4bb60 100644
--- a/ext/tk/lib/tk/macpkg.rb
+++ b/ext/tk/lib/tk/macpkg.rb
@@ -20,9 +20,14 @@ module Tk
end
end
-module TkMacResource
+module Tk::MacResource
+end
+#TkMacResource = Tk::MacResource
+Tk.__set_toplevel_aliases__(:Tk, Tk::MacResource, :TkMacResource)
+
+module Tk::MacResource
extend Tk
- extend TkMacResource
+ extend Tk::MacResource
TkCommandNames = ['resource'.freeze].freeze
diff --git a/ext/tk/lib/tk/menu.rb b/ext/tk/lib/tk/menu.rb
index ddddc8e53e..3ae0548dd1 100644
--- a/ext/tk/lib/tk/menu.rb
+++ b/ext/tk/lib/tk/menu.rb
@@ -34,15 +34,16 @@ module TkMenuEntryConfig
private :__item_val2ruby_optkeys
alias entrycget itemcget
+ alias entrycget_strict itemcget_strict
alias entryconfigure itemconfigure
alias entryconfiginfo itemconfiginfo
alias current_entryconfiginfo current_itemconfiginfo
- private :itemcget, :itemconfigure
- private :itemconfiginfo, :current_itemconfiginfo
+ private :itemcget, :itemcget_strict
+ private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo
end
-class TkMenu<TkWindow
+class Tk::Menu<TkWindow
include Wm
include TkMenuEntryConfig
extend TkMenuSpec
@@ -140,9 +141,9 @@ class TkMenu<TkWindow
type = keys.delete('type') if keys.has_key?('type')
if keys.empty?
- TkMenuClone.new(self, parent, type)
+ Tk::MenuClone.new(self, parent, type)
else
- TkMenuClone.new(self, parent, type, keys)
+ Tk::MenuClone.new(self, parent, type, keys)
end
end
@@ -202,6 +203,9 @@ class TkMenu<TkWindow
tk_send_without_enc('unpost')
self
end
+ def xposition(index)
+ number(tk_send_without_enc('xposition', _get_eval_enc_str(index)))
+ end
def yposition(index)
number(tk_send_without_enc('yposition', _get_eval_enc_str(index)))
end
@@ -381,8 +385,11 @@ class TkMenu<TkWindow
=end
end
+#TkMenu = Tk::Menu unless Object.const_defined? :TkMenu
+Tk.__set_toplevel_aliases__(:Tk, Tk::Menu, :TkMenu)
+
-class TkMenuClone<TkMenu
+class Tk::MenuClone<Tk::Menu
=begin
def initialize(parent, type=None)
widgetname = nil
@@ -436,9 +443,12 @@ class TkMenuClone<TkMenu
@src_menu
end
end
-TkCloneMenu = TkMenuClone
+Tk::CloneMenu = Tk::MenuClone
+#TkMenuClone = Tk::MenuClone unless Object.const_defined? :TkMenuClone
+#TkCloneMenu = Tk::CloneMenu unless Object.const_defined? :TkCloneMenu
+Tk.__set_toplevel_aliases__(:Tk, Tk::MenuClone, :TkMenuClone, :TkCloneMenu)
-module TkSystemMenu
+module Tk::SystemMenu
def initialize(parent, keys=nil)
if parent.kind_of? Hash
keys = _symbolkey2str(parent)
@@ -461,38 +471,60 @@ module TkSystemMenu
end
end
end
+TkSystemMenu = Tk::SystemMenu
-class TkSysMenu_Help<TkMenu
+class Tk::SysMenu_Help<Tk::Menu
# for all platform
- include TkSystemMenu
+ include Tk::SystemMenu
SYSMENU_NAME = 'help'
end
+#TkSysMenu_Help = Tk::SysMenu_Help unless Object.const_defined? :TkSysMenu_Help
+Tk.__set_toplevel_aliases__(:Tk, Tk::SysMenu_Help, :TkSysMenu_Help)
-class TkSysMenu_System<TkMenu
+class Tk::SysMenu_System<Tk::Menu
# for Windows
- include TkSystemMenu
+ include Tk::SystemMenu
SYSMENU_NAME = 'system'
end
+#TkSysMenu_System = Tk::SysMenu_System unless Object.const_defined? :TkSysMenu_System
+Tk.__set_toplevel_aliases__(:Tk, Tk::SysMenu_System, :TkSysMenu_System)
-class TkSysMenu_Apple<TkMenu
+class Tk::SysMenu_Apple<Tk::Menu
# for Machintosh
- include TkSystemMenu
+ include Tk::SystemMenu
SYSMENU_NAME = 'apple'
end
+#TkSysMenu_Apple = Tk::SysMenu_Apple unless Object.const_defined? :TkSysMenu_Apple
+Tk.__set_toplevel_aliases__(:Tk, Tk::SysMenu_Apple, :TkSysMenu_Apple)
-class TkMenubutton<TkLabel
+class Tk::Menubutton<Tk::Label
TkCommandNames = ['menubutton'.freeze].freeze
WidgetClassName = 'Menubutton'.freeze
WidgetClassNames[WidgetClassName] = self
def create_self(keys)
if keys and keys != None
- # tk_call_without_enc('menubutton', @path, *hash_kv(keys, true))
- tk_call_without_enc(self.class::TkCommandNames[0], @path,
- *hash_kv(keys, true))
+ unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ # tk_call_without_enc('menubutton', @path, *hash_kv(keys, true))
+ tk_call_without_enc(self.class::TkCommandNames[0], @path,
+ *hash_kv(keys, true))
+ else
+ begin
+ tk_call_without_enc(self.class::TkCommandNames[0], @path,
+ *hash_kv(keys, true))
+ rescue
+ tk_call_without_enc(self.class::TkCommandNames[0], @path)
+ keys = __check_available_configure_options(keys)
+ unless keys.empty?
+ tk_call_without_enc('destroy', @path) rescue nil
+ tk_call_without_enc(self.class::TkCommandNames[0], @path,
+ *hash_kv(keys, true))
+ end
+ end
+ end
else
# tk_call_without_enc('menubutton', @path)
tk_call_without_enc(self.class::TkCommandNames[0], @path)
@@ -506,10 +538,13 @@ class TkMenubutton<TkLabel
private :__boolval_optkeys
end
-TkMenuButton = TkMenubutton
+Tk::MenuButton = Tk::Menubutton
+#TkMenubutton = Tk::Menubutton unless Object.const_defined? :TkMenubutton
+#TkMenuButton = Tk::MenuButton unless Object.const_defined? :TkMenuButton
+Tk.__set_toplevel_aliases__(:Tk, Tk::Menubutton, :TkMenubutton, :TkMenuButton)
-class TkOptionMenubutton<TkMenubutton
+class Tk::OptionMenubutton<Tk::Menubutton
TkCommandNames = ['tk_optionMenu'.freeze].freeze
class OptionMenu<TkMenu
@@ -596,6 +631,9 @@ class TkOptionMenubutton<TkMenubutton
@menu.delete(index, last)
self
end
+ def xposition(index)
+ @menu.xposition(index)
+ end
def yposition(index)
@menu.yposition(index)
end
@@ -605,6 +643,9 @@ class TkOptionMenubutton<TkMenubutton
def menucget(key)
@menu.cget(key)
end
+ def menucget_strict(key)
+ @menu.cget_strict(key)
+ end
def menuconfigure(key, val=None)
@menu.configure(key, val)
self
@@ -618,6 +659,9 @@ class TkOptionMenubutton<TkMenubutton
def entrycget(index, key)
@menu.entrycget(index, key)
end
+ def entrycget_strict(index, key)
+ @menu.entrycget_strict(index, key)
+ end
def entryconfigure(index, key, val=None)
@menu.entryconfigure(index, key, val)
self
@@ -629,4 +673,9 @@ class TkOptionMenubutton<TkMenubutton
@menu.current_entryconfiginfo(index, key)
end
end
-TkOptionMenuButton = TkOptionMenubutton
+
+Tk::OptionMenuButton = Tk::OptionMenubutton
+#TkOptionMenubutton = Tk::OptionMenubutton unless Object.const_defined? :TkOptionMenubutton
+#TkOptionMenuButton = Tk::OptionMenuButton unless Object.const_defined? :TkOptionMenuButton
+Tk.__set_toplevel_aliases__(:Tk, Tk::OptionMenubutton,
+ :TkOptionMenubutton, :TkOptionMenuButton)
diff --git a/ext/tk/lib/tk/menubar.rb b/ext/tk/lib/tk/menubar.rb
index 392b6fbd4e..ef9da809b9 100644
--- a/ext/tk/lib/tk/menubar.rb
+++ b/ext/tk/lib/tk/menubar.rb
@@ -89,7 +89,7 @@ require 'tk/frame'
require 'tk/composite'
require 'tk/menuspec'
-class TkMenubar<TkFrame
+class TkMenubar<Tk::Frame
include TkComposite
include TkMenuSpec
diff --git a/ext/tk/lib/tk/menuspec.rb b/ext/tk/lib/tk/menuspec.rb
index 118a4f42b1..2a2eb9ba3c 100644
--- a/ext/tk/lib/tk/menuspec.rb
+++ b/ext/tk/lib/tk/menuspec.rb
@@ -61,8 +61,12 @@ module TkMenuSpec
tearoff = orig_opts.delete('tearoff') if orig_opts.key?('tearoff')
if menu_name
+ #menu = Tk::Menu.new(parent, :widgetname=>menu_name, :tearoff=>tearoff)
+ # --> use current TkMenu class
menu = TkMenu.new(parent, :widgetname=>menu_name, :tearoff=>tearoff)
else
+ #menu = Tk::Menu.new(parent, :tearoff=>tearoff)
+ # --> use current TkMenu class
menu = TkMenu.new(parent, :tearoff=>tearoff)
end
@@ -150,21 +154,22 @@ module TkMenuSpec
def _use_menubar?(parent)
use_menubar = false
- if parent.kind_of?(TkRoot) || parent.kind_of?(TkToplevel)
- return true
+ if parent.kind_of?(Tk::Root) || parent.kind_of?(Tk::Toplevel)
+ true
+ elsif parent.current_configinfo.has_key?('menu')
+ true
else
- begin
- parent.cget('menu')
- return true
- rescue
- end
+ false
end
- false
end
private :_use_menubar?
def _create_menu_for_menubar(parent)
- unless (mbar = parent.menu).kind_of?(TkMenu)
+ #unless (mbar = parent.menu).kind_of?(TkMenu)
+ # --> use current TkMenu class
+ mbar = parent.menu
+ unless mbar.kind_of?(Tk::Menu) || mbar.kind_of?(TkMenu)
+ #mbar = Tk::Menu.new(parent, :tearoff=>false)
mbar = TkMenu.new(parent, :tearoff=>false)
parent.menu(mbar)
end
@@ -190,7 +195,6 @@ module TkMenuSpec
if _use_menubar?(parent)
# menubar by menu entries
-
mbar = _create_menu_for_menubar(parent)
menu_name = nil
@@ -221,6 +225,8 @@ module TkMenuSpec
else
# menubar by menubuttons
+ #mbtn = Tk::Menubutton.new(parent)
+ # --> use current TkMenubutton class
mbtn = TkMenubutton.new(parent)
menu_name = nil
diff --git a/ext/tk/lib/tk/message.rb b/ext/tk/lib/tk/message.rb
index 79121bebb3..946b68c704 100644
--- a/ext/tk/lib/tk/message.rb
+++ b/ext/tk/lib/tk/message.rb
@@ -4,7 +4,7 @@
require 'tk'
require 'tk/label'
-class TkMessage<TkLabel
+class Tk::Message<Tk::Label
TkCommandNames = ['message'.freeze].freeze
WidgetClassName = 'Message'.freeze
WidgetClassNames[WidgetClassName] = self
@@ -17,3 +17,6 @@ class TkMessage<TkLabel
#end
private :create_self
end
+
+#TkMessage = Tk::Message unless Object.const_defined? :TkMessage
+Tk.__set_toplevel_aliases__(:Tk, Tk::Message, :TkMessage)
diff --git a/ext/tk/lib/tk/msgcat.rb b/ext/tk/lib/tk/msgcat.rb
index 061e43fd89..162953f425 100644
--- a/ext/tk/lib/tk/msgcat.rb
+++ b/ext/tk/lib/tk/msgcat.rb
@@ -74,7 +74,11 @@ class TkMsgCatalog < TkObject
"\n---< backtrace of Ruby side >-----\n" +
_toUTF8(e.backtrace.join("\n")) +
"\n---< backtrace of Tk side >-------"
- msg.instance_variable_set(:@encoding, 'utf-8')
+ if TkCore::WITH_ENCODING
+ msg.force_encoding('utf-8')
+ else
+ msg.instance_variable_set(:@encoding, 'utf-8')
+ end
rescue Exception
msg = e.class.inspect + ': ' + e.message + "\n" +
"\n---< backtrace of Ruby side >-----\n" +
diff --git a/ext/tk/lib/tk/namespace.rb b/ext/tk/lib/tk/namespace.rb
index 5bf6474c5b..20a8d65215 100644
--- a/ext/tk/lib/tk/namespace.rb
+++ b/ext/tk/lib/tk/namespace.rb
@@ -12,17 +12,24 @@ class TkNamespace < TkObject
].freeze
Tk_Namespace_ID_TBL = TkCore::INTERP.create_table
- Tk_Namespace_ID = ["ns".freeze, "00000".taint].freeze
+
+ (Tk_Namespace_ID = ["ns".freeze, "00000".taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
Tk_NsCode_RetObjID_TBL = TkCore::INTERP.create_table
TkCore::INTERP.init_ip_env{
- Tk_Namespace_ID_TBL.clear
- Tk_NsCode_RetObjID_TBL.clear
+ Tk_Namespace_ID_TBL.mutex.synchronize{ Tk_Namespace_ID_TBL.clear }
+ Tk_NsCode_RetObjID_TBL.mutex.synchronize{ Tk_NsCode_RetObjID_TBL.clear }
}
def TkNamespace.id2obj(id)
- Tk_Namespace_ID_TBL[id]? Tk_Namespace_ID_TBL[id]: id
+ Tk_Namespace_ID_TBL.mutex.synchronize{
+ Tk_Namespace_ID_TBL[id]? Tk_Namespace_ID_TBL[id]: id
+ }
end
#####################################
@@ -65,11 +72,27 @@ class TkNamespace < TkObject
def cget(slot)
if slot == :namespace || slot == 'namespace'
ns = super(slot)
- if TkNamespace::Tk_Namespace_ID_TBL.key?(ns)
- TkNamespace::Tk_Namespace_ID_TBL[ns]
- else
- ns
- end
+ Tk_Namespace_ID_TBL.mutex.synchronize{
+ if TkNamespace::Tk_Namespace_ID_TBL.key?(ns)
+ TkNamespace::Tk_Namespace_ID_TBL[ns]
+ else
+ ns
+ end
+ }
+ else
+ super(slot)
+ end
+ end
+ def cget_strict(slot)
+ if slot == :namespace || slot == 'namespace'
+ ns = super(slot)
+ Tk_Namespace_ID_TBL.mutex.synchronize{
+ if TkNamespace::Tk_Namespace_ID_TBL.key?(ns)
+ TkNamespace::Tk_Namespace_ID_TBL[ns]
+ else
+ ns
+ end
+ }
else
super(slot)
end
@@ -79,9 +102,11 @@ class TkNamespace < TkObject
if slot
if slot == :namespace || slot == 'namespace'
val = super(slot)
- if TkNamespace::Tk_Namespace_ID_TBL.key?(val)
- val = TkNamespace::Tk_Namespace_ID_TBL[val]
- end
+ Tk_Namespace_ID_TBL.mutex.synchronize{
+ if TkNamespace::Tk_Namespace_ID_TBL.key?(val)
+ val = TkNamespace::Tk_Namespace_ID_TBL[val]
+ end
+ }
else
val = super(slot)
end
@@ -96,19 +121,23 @@ class TkNamespace < TkObject
info = super()
if TkComm::GET_CONFIGINFO_AS_ARRAY
- info.map!{|inf|
- if inf[0] == 'namespace' &&
- TkNamespace::Tk_Namespace_ID_TBL.key?(inf[-1])
- [inf[0], TkNamespace::Tk_Namespace_ID_TBL[inf[-1]]]
- else
- inf
- end
+ Tk_Namespace_ID_TBL.mutex.synchronize{
+ info.map!{|inf|
+ if inf[0] == 'namespace' &&
+ TkNamespace::Tk_Namespace_ID_TBL.key?(inf[-1])
+ [inf[0], TkNamespace::Tk_Namespace_ID_TBL[inf[-1]]]
+ else
+ inf
+ end
+ }
}
else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
val = info['namespace']
- if TkNamespace::Tk_Namespace_ID_TBL.key?(val)
- info['namespace'] = TkNamespace::Tk_Namespace_ID_TBL[val]
- end
+ Tk_Namespace_ID_TBL.mutex.synchronize{
+ if TkNamespace::Tk_Namespace_ID_TBL.key?(val)
+ info['namespace'] = TkNamespace::Tk_Namespace_ID_TBL[val]
+ end
+ }
end
info
@@ -215,9 +244,11 @@ class TkNamespace < TkObject
def initialize(name = nil, parent = nil)
unless name
- # name = Tk_Namespace_ID.join('')
- name = Tk_Namespace_ID.join(TkCore::INTERP._ip_id_)
- Tk_Namespace_ID[1].succ!
+ Tk_Namespace_ID.mutex.synchronize{
+ # name = Tk_Namespace_ID.join('')
+ name = Tk_Namespace_ID.join(TkCore::INTERP._ip_id_)
+ Tk_Namespace_ID[1].succ!
+ }
end
name = __tk_call('namespace', 'current') if name == ''
if parent
@@ -252,7 +283,9 @@ class TkNamespace < TkObject
# create namespace
__tk_call('namespace', 'eval', @fullname, '')
- Tk_Namespace_ID_TBL[@fullname] = self
+ Tk_Namespace_ID_TBL.mutex.synchronize{
+ Tk_Namespace_ID_TBL[@fullname] = self
+ }
end
def self.children(*args)
@@ -260,11 +293,13 @@ class TkNamespace < TkObject
# <pattern> must be glob-style pattern
tk_split_simplelist(tk_call('namespace', 'children', *args)).collect{|ns|
# ns is fullname
- if Tk_Namespace_ID_TBL.key?(ns)
- Tk_Namespace_ID_TBL[ns]
- else
- ns
- end
+ Tk_Namespace_ID_TBL.mutex.synchronize{
+ if Tk_Namespace_ID_TBL.key?(ns)
+ Tk_Namespace_ID_TBL[ns]
+ else
+ ns
+ end
+ }
}
end
def children(pattern=None)
@@ -290,14 +325,24 @@ class TkNamespace < TkObject
def code(script = Proc.new)
if script.kind_of?(String)
cmd = proc{|*args|
- ret = ScopeArgs.new(@fullname,*args).instance_eval(script)
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ obj = ScopeArgs.new(@fullname,*args)
+ ret = obj.instance_exec(obj, script)
+ else
+ ret = ScopeArgs.new(@fullname,*args).instance_eval(script)
+ end
id = ret.object_id
TkNamespace::Tk_NsCode_RetObjID_TBL[id] = ret
id
}
elsif script.kind_of?(Proc)
cmd = proc{|*args|
- ret = ScopeArgs.new(@fullname,*args).instance_eval(&script)
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ obj = ScopeArgs.new(@fullname,*args)
+ ret = obj.instance_exec(obj, &script)
+ else
+ ret = ScopeArgs.new(@fullname,*args).instance_eval(&script)
+ end
id = ret.object_id
TkNamespace::Tk_NsCode_RetObjID_TBL[id] = ret
id
@@ -319,11 +364,13 @@ class TkNamespace < TkObject
def self.current
ns = self.current_path
- if Tk_Namespace_ID_TBL.key?(ns)
- Tk_Namespace_ID_TBL[ns]
- else
- ns
- end
+ Tk_Namespace_ID_TBL.mutex.synchronize{
+ if Tk_Namespace_ID_TBL.key?(ns)
+ Tk_Namespace_ID_TBL[ns]
+ else
+ ns
+ end
+ }
end
def current_namespace
# ns_tk_call('namespace', 'current')
@@ -335,11 +382,13 @@ class TkNamespace < TkObject
def self.delete(*ns_list)
tk_call('namespace', 'delete', *ns_list)
ns_list.each{|ns|
- if ns.kind_of?(TkNamespace)
- Tk_Namespace_ID_TBL.delete(ns.path)
- else
- Tk_Namespace_ID_TBL.delete(ns.to_s)
- end
+ Tk_Namespace_ID_TBL.mutex.synchronize{
+ if ns.kind_of?(TkNamespace)
+ Tk_Namespace_ID_TBL.delete(ns.path)
+ else
+ Tk_Namespace_ID_TBL.delete(ns.to_s)
+ end
+ }
}
end
def delete
@@ -371,7 +420,7 @@ class TkNamespace < TkObject
def self.eval(namespace, cmd = Proc.new, *args)
#tk_call('namespace', 'eval', namespace, cmd, *args)
- TkNamespace.new(namespece).eval(cmd, *args)
+ TkNamespace.new(namespace).eval(cmd, *args)
end
=begin
def eval(cmd = Proc.new, *args)
@@ -444,11 +493,13 @@ class TkNamespace < TkObject
def self.parent(namespace=None)
ns = tk_call('namespace', 'parent', namespace)
- if Tk_Namespace_ID_TBL.key?(ns)
- Tk_Namespace_ID_TBL[ns]
- else
- ns
- end
+ Tk_Namespace_ID_TBL.mutex.synchronize{
+ if Tk_Namespace_ID_TBL.key?(ns)
+ Tk_Namespace_ID_TBL[ns]
+ else
+ ns
+ end
+ }
end
def parent
tk_call('namespace', 'parent', @fullname)
diff --git a/ext/tk/lib/tk/optiondb.rb b/ext/tk/lib/tk/optiondb.rb
index a806f3971d..186811d37d 100644
--- a/ext/tk/lib/tk/optiondb.rb
+++ b/ext/tk/lib/tk/optiondb.rb
@@ -8,7 +8,11 @@ module TkOptionDB
extend Tk
TkCommandNames = ['option'.freeze].freeze
- CmdClassID = ['CMD_CLASS'.freeze, '00000'.taint].freeze
+ (CmdClassID = ['CMD_CLASS'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
module Priority
WidgetDefault = 20
@@ -250,8 +254,10 @@ module TkOptionDB
def __create_new_class(klass, func, safe = 4, add = false, parent = nil)
if klass.kind_of?(TkWindow)
carrier = klass.path
- klass = CmdClassID.join(TkCore::INTERP._ip_id_)
- CmdClassID[1].succ!
+ CmdClassID.mutex.synchronize{
+ klass = CmdClassID.join(TkCore::INTERP._ip_id_)
+ CmdClassID[1].succ!
+ }
parent = nil # ignore parent
else
klass = klass.to_s if klass.kind_of?(Symbol)
@@ -312,7 +318,7 @@ module TkOptionDB
:singleton_methods, :remove_const, :remove_method, :undef_method,
:to_s, :inspect, :display, :method, :methods, :respond_to?,
:instance_variable_get, :instance_variable_set, :instance_method,
- :instance_eval, :instance_variables, :kind_of?, :is_a?,
+ :instance_eval, :instance_exec, :instance_variables, :kind_of?, :is_a?,
:private_methods, :protected_methods, :public_methods ].each{|m|
alias_method(m, :__null_method)
}
@@ -362,7 +368,7 @@ module TkOptionDB
def new_proc_class_random(klass, func, safe = 4, add = false, &b)
eval_under_random_base(){
- TkOption.new_proc_class(klass, func, safe, add, self, &b)
+ TkOptionDB.new_proc_class(klass, func, safe, add, self, &b)
}
end
module_function :new_proc_class_random
diff --git a/ext/tk/lib/tk/pack.rb b/ext/tk/lib/tk/pack.rb
index 8fab363121..220a38e524 100644
--- a/ext/tk/lib/tk/pack.rb
+++ b/ext/tk/lib/tk/pack.rb
@@ -9,6 +9,7 @@ module TkPack
TkCommandNames = ['pack'.freeze].freeze
+=begin
def configure(win, *args)
if args[-1].kind_of?(Hash)
opts = args.pop
@@ -29,6 +30,22 @@ module TkPack
}
tk_call_without_enc("pack", 'configure', *params)
end
+=end
+ def configure(*args)
+ if args[-1].kind_of?(Hash)
+ opts = args.pop
+ else
+ opts = {}
+ end
+ fail ArgumentError, 'no widget is given' if args.empty?
+ params = []
+ args.flatten(1).each{|win| params.push(_epath(win))}
+ opts.each{|k, v|
+ params.push("-#{k}")
+ params.push(_epath(v)) # have to use 'epath' (hash_kv() is unavailable)
+ }
+ tk_call_without_enc("pack", 'configure', *params)
+ end
alias pack configure
def forget(*args)
diff --git a/ext/tk/lib/tk/package.rb b/ext/tk/lib/tk/package.rb
index d1eb27674d..0c329732f5 100644
--- a/ext/tk/lib/tk/package.rb
+++ b/ext/tk/lib/tk/package.rb
@@ -136,4 +136,8 @@ module TkPackage
def vsatisfies(version1, version2)
bool(tk_call('package', 'vsatisfies', version1, version2))
end
+
+ def prefer(setting = None)
+ tk_call('package', 'prefer', setting)
+ end
end
diff --git a/ext/tk/lib/tk/palette.rb b/ext/tk/lib/tk/palette.rb
index 2b6fdf5d90..2d08d50f6a 100644
--- a/ext/tk/lib/tk/palette.rb
+++ b/ext/tk/lib/tk/palette.rb
@@ -15,7 +15,7 @@ module TkPalette
].freeze
def TkPalette.set(*args)
- args = args.to_a.flatten if args.kind_of? Hash
+ args = args[0].to_a.flatten if args[0].kind_of? Hash
tk_call('tk_setPalette', *args)
end
def TkPalette.setPalette(*args)
diff --git a/ext/tk/lib/tk/panedwindow.rb b/ext/tk/lib/tk/panedwindow.rb
index c6cf3cd11f..030144e677 100644
--- a/ext/tk/lib/tk/panedwindow.rb
+++ b/ext/tk/lib/tk/panedwindow.rb
@@ -3,7 +3,7 @@
#
require 'tk'
-class TkPanedWindow<TkWindow
+class Tk::PanedWindow<TkWindow
TkCommandNames = ['panedwindow'.freeze].freeze
WidgetClassName = 'Panedwindow'.freeze
WidgetClassNames[WidgetClassName] = self
@@ -76,11 +76,32 @@ class TkPanedWindow<TkWindow
self
end
- def panecget(win, key)
+ def panecget_strict(win, key)
# win = win.epath if win.kind_of?(TkObject)
win = _epath(win)
tk_tcl2ruby(tk_send_without_enc('panecget', win, "-#{key}"))
end
+ def panecget(win, key)
+ unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ panecget_strict(win, key)
+ else
+ begin
+ panecget_strict(win, key)
+ rescue => e
+ begin
+ if current_paneconfiginfo(win).has_key?(option.to_s)
+ # not tag error & option is known -> error on known option
+ fail e
+ else
+ # not tag error & option is unknown
+ nil
+ end
+ rescue
+ fail e # tag error
+ end
+ end
+ end
+ end
def paneconfigure(win, key, value=nil)
# win = win.epath if win.kind_of?(TkObject)
@@ -229,4 +250,9 @@ class TkPanedWindow<TkWindow
list(tk_send_without_enc('panes'))
end
end
-TkPanedwindow = TkPanedWindow
+
+Tk::Panedwindow = Tk::PanedWindow
+#TkPanedWindow = Tk::PanedWindow unless Object.const_defined? :TkPanedWindow
+#TkPanedwindow = Tk::Panedwindow unless Object.const_defined? :TkPanedwindow
+Tk.__set_toplevel_aliases__(:Tk, Tk::PanedWindow,
+ :TkPanedWindow, :TkPanedwindow)
diff --git a/ext/tk/lib/tk/radiobutton.rb b/ext/tk/lib/tk/radiobutton.rb
index f8f67d709a..1f864ec06b 100644
--- a/ext/tk/lib/tk/radiobutton.rb
+++ b/ext/tk/lib/tk/radiobutton.rb
@@ -4,7 +4,7 @@
require 'tk'
require 'tk/button'
-class TkRadioButton<TkButton
+class Tk::RadioButton<Tk::Button
TkCommandNames = ['radiobutton'.freeze].freeze
WidgetClassName = 'Radiobutton'.freeze
WidgetClassNames[WidgetClassName] = self
@@ -63,4 +63,9 @@ class TkRadioButton<TkButton
end
end
end
-TkRadiobutton = TkRadioButton
+
+Tk::Radiobutton = Tk::RadioButton
+#TkRadioButton = Tk::RadioButton unless Object.const_defined? :TkRadioButton
+#TkRadiobutton = Tk::Radiobutton unless Object.const_defined? :TkRadiobutton
+Tk.__set_toplevel_aliases__(:Tk, Tk::RadioButton,
+ :TkRadioButton, :TkRadiobutton)
diff --git a/ext/tk/lib/tk/root.rb b/ext/tk/lib/tk/root.rb
index 0e5584c7c1..7237b4c614 100644
--- a/ext/tk/lib/tk/root.rb
+++ b/ext/tk/lib/tk/root.rb
@@ -5,7 +5,7 @@ require 'tk'
require 'tk/wm'
require 'tk/menuspec'
-class TkRoot<TkWindow
+class Tk::Root<TkWindow
include Wm
include TkMenuSpec
@@ -14,28 +14,7 @@ class TkRoot<TkWindow
end
private :__methodcall_optkeys
-=begin
- ROOT = []
- def TkRoot.new(keys=nil)
- if ROOT[0]
- Tk_WINDOWS["."] = ROOT[0]
- return ROOT[0]
- end
- new = super(:without_creating=>true, :widgetname=>'.')
- if keys # wm commands
- keys.each{|k,v|
- if v.kind_of? Array
- new.send(k,*v)
- else
- new.send(k,v)
- end
- }
- end
- ROOT[0] = new
- Tk_WINDOWS["."] = new
- end
-=end
- def TkRoot.new(keys=nil, &b)
+ def Root.new(keys=nil, &b)
unless TkCore::INTERP.tk_windows['.']
TkCore::INTERP.tk_windows['.'] =
super(:without_creating=>true, :widgetname=>'.'){}
@@ -62,7 +41,13 @@ class TkRoot<TkWindow
}
end
- root.instance_eval(&b) if block_given?
+ if block_given?
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ root.instance_exec(root, &b)
+ else
+ root.instance_eval(&b)
+ end
+ end
root
end
@@ -102,7 +87,9 @@ class TkRoot<TkWindow
self.menu
end
- def TkRoot.destroy
+ def Root.destroy
TkCore::INTERP._invoke('destroy', '.')
end
end
+
+TkRoot = Tk::Root unless Object.const_defined? :TkRoot
diff --git a/ext/tk/lib/tk/scale.rb b/ext/tk/lib/tk/scale.rb
index 0b703aa055..7e758d92f4 100644
--- a/ext/tk/lib/tk/scale.rb
+++ b/ext/tk/lib/tk/scale.rb
@@ -3,7 +3,7 @@
#
require 'tk'
-class TkScale<TkWindow
+class Tk::Scale<TkWindow
TkCommandNames = ['scale'.freeze].freeze
WidgetClassName = 'Scale'.freeze
WidgetClassNames[WidgetClassName] = self
@@ -14,9 +14,31 @@ class TkScale<TkWindow
cmd = keys.delete('command')
keys['command'] = proc{|val| cmd.call(val.to_f)}
end
- #tk_call_without_enc('scale', @path, *hash_kv(keys, true))
- tk_call_without_enc(self.class::TkCommandNames[0], @path,
- *hash_kv(keys, true))
+ unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ #tk_call_without_enc('scale', @path, *hash_kv(keys, true))
+ tk_call_without_enc(self.class::TkCommandNames[0], @path,
+ *hash_kv(keys, true))
+ else
+ begin
+ tk_call_without_enc(self.class::TkCommandNames[0], @path,
+ *hash_kv(keys, true))
+ rescue
+ tk_call_without_enc(self.class::TkCommandNames[0], @path)
+ keys = __check_available_configure_options(keys)
+ unless keys.empty?
+ begin
+ tk_call_without_enc('destroy', @path)
+ rescue
+ # cannot destroy
+ configure(keys)
+ else
+ # re-create widget
+ tk_call_without_enc(self.class::TkCommandNames[0], @path,
+ *hash_kv(keys, true))
+ end
+ end
+ end
+ end
else
#tk_call_without_enc('scale', @path)
tk_call_without_enc(self.class::TkCommandNames[0], @path)
@@ -84,3 +106,6 @@ class TkScale<TkWindow
val
end
end
+
+#TkScale = Tk::Scale unless Object.const_defined? :TkScale
+Tk.__set_toplevel_aliases__(:Tk, Tk::Scale, :TkScale)
diff --git a/ext/tk/lib/tk/scrollable.rb b/ext/tk/lib/tk/scrollable.rb
index ec27b76467..96959b7a4b 100644
--- a/ext/tk/lib/tk/scrollable.rb
+++ b/ext/tk/lib/tk/scrollable.rb
@@ -4,7 +4,7 @@
require 'tk'
module Tk
- module X_Scrollable
+ module XScrollable
def xscrollcommand(cmd=Proc.new)
configure_cmd 'xscrollcommand', cmd
# Tk.update # avoid scrollbar trouble
@@ -38,7 +38,7 @@ module Tk
end
end
- module Y_Scrollable
+ module YScrollable
def yscrollcommand(cmd=Proc.new)
configure_cmd 'yscrollcommand', cmd
# Tk.update # avoid scrollbar trouble
@@ -72,8 +72,11 @@ module Tk
end
end
+ X_Scrollable = XScrollable
+ Y_Scrollable = YScrollable
+
module Scrollable
- include X_Scrollable
- include Y_Scrollable
+ include XScrollable
+ include YScrollable
end
end
diff --git a/ext/tk/lib/tk/scrollbar.rb b/ext/tk/lib/tk/scrollbar.rb
index 70aadfdd4c..87db46a9f9 100644
--- a/ext/tk/lib/tk/scrollbar.rb
+++ b/ext/tk/lib/tk/scrollbar.rb
@@ -3,7 +3,7 @@
#
require 'tk'
-class TkScrollbar<TkWindow
+class Tk::Scrollbar<TkWindow
TkCommandNames = ['scrollbar'.freeze].freeze
WidgetClassName = 'Scrollbar'.freeze
WidgetClassNames[WidgetClassName] = self
@@ -19,9 +19,31 @@ class TkScrollbar<TkWindow
}
if keys and keys != None
- #tk_call_without_enc('scrollbar', @path, *hash_kv(keys, true))
- tk_call_without_enc(self.class::TkCommandNames[0], @path,
- *hash_kv(keys, true))
+ unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ #tk_call_without_enc('scrollbar', @path, *hash_kv(keys, true))
+ tk_call_without_enc(self.class::TkCommandNames[0], @path,
+ *hash_kv(keys, true))
+ else
+ begin
+ tk_call_without_enc(self.class::TkCommandNames[0], @path,
+ *hash_kv(keys, true))
+ rescue
+ tk_call_without_enc(self.class::TkCommandNames[0], @path)
+ keys = __check_available_configure_options(keys)
+ unless keys.empty?
+ begin
+ tk_call_without_enc('destroy', @path)
+ rescue
+ # cannot destroy
+ configure(keys)
+ else
+ # re-create widget
+ tk_call_without_enc(self.class::TkCommandNames[0], @path,
+ *hash_kv(keys, true))
+ end
+ end
+ end
+ end
else
#tk_call_without_enc('scrollbar', @path)
tk_call_without_enc(self.class::TkCommandNames[0], @path)
@@ -103,9 +125,33 @@ class TkScrollbar<TkWindow
def activate(element=None)
tk_send_without_enc('activate', element)
end
+
+ def moveto(fraction)
+ tk_send_without_enc('moveto', fraction)
+ self
+ end
+
+ def scroll(*args)
+ tk_send_without_enc('scroll', *args)
+ self
+ end
+
+ def scroll_units(num)
+ scroll(num, 'units')
+ self
+ end
+
+ def scroll_pages(num)
+ scroll(num, 'pages')
+ self
+ end
end
-class TkXScrollbar<TkScrollbar
+#TkScrollbar = Tk::Scrollbar unless Object.const_defined? :TkScrollbar
+Tk.__set_toplevel_aliases__(:Tk, Tk::Scrollbar, :TkScrollbar)
+
+
+class Tk::XScrollbar<Tk::Scrollbar
def create_self(keys)
keys = {} unless keys
keys['orient'] = 'horizontal'
@@ -114,7 +160,11 @@ class TkXScrollbar<TkScrollbar
private :create_self
end
-class TkYScrollbar<TkScrollbar
+#TkXScrollbar = Tk::XScrollbar unless Object.const_defined? :TkXScrollbar
+Tk.__set_toplevel_aliases__(:Tk, Tk::XScrollbar, :TkXScrollbar)
+
+
+class Tk::YScrollbar<Tk::Scrollbar
def create_self(keys)
keys = {} unless keys
keys['orient'] = 'vertical'
@@ -122,3 +172,6 @@ class TkYScrollbar<TkScrollbar
end
private :create_self
end
+
+#TkYScrollbar = Tk::YScrollbar unless Object.const_defined? :TkYScrollbar
+Tk.__set_toplevel_aliases__(:Tk, Tk::YScrollbar, :TkYScrollbar)
diff --git a/ext/tk/lib/tk/scrollbox.rb b/ext/tk/lib/tk/scrollbox.rb
index 833505be17..d20742a666 100644
--- a/ext/tk/lib/tk/scrollbox.rb
+++ b/ext/tk/lib/tk/scrollbox.rb
@@ -1,16 +1,19 @@
#
# tk/scrollbox.rb - Tk Listbox with Scrollbar
# as an example of Composite Widget
-# $Date: 2004/10/11 04:51:07 $
# by Yukihiro Matsumoto <matz@netlab.co.jp>
#
require 'tk'
require 'tk/listbox'
-class TkScrollbox<TkListbox
+class TkScrollbox<Tk::Listbox
include TkComposite
def initialize_composite(keys=nil)
+ #list = Tk::Listbox.new(@frame)
+ # -> use current TkListbox class
list = TkListbox.new(@frame)
+ #scroll = Tk::Scrollbar.new(@frame)
+ # -> use current TkScrollbar class
scroll = TkScrollbar.new(@frame)
@path = list.path
diff --git a/ext/tk/lib/tk/spinbox.rb b/ext/tk/lib/tk/spinbox.rb
index 1eed4d1dc4..34dc1904f7 100644
--- a/ext/tk/lib/tk/spinbox.rb
+++ b/ext/tk/lib/tk/spinbox.rb
@@ -1,12 +1,11 @@
#
# tk/spinbox.rb - Tk spinbox classes
-# $Date: 2005/10/22 22:16:24 $
# by Yukihiro Matsumoto <matz@caelum.co.jp>
#
require 'tk'
require 'tk/entry'
-class TkSpinbox<TkEntry
+class Tk::Spinbox<Tk::Entry
TkCommandNames = ['spinbox'.freeze].freeze
WidgetClassName = 'Spinbox'.freeze
WidgetClassNames[WidgetClassName] = self
@@ -38,6 +37,24 @@ class TkSpinbox<TkEntry
nil
]
+=begin
+ # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
+ KEY_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String)
+ end
+ inf
+ }
+
+ PROC_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ end
+ inf
+ }
+=end
+
_setup_subst_table(KEY_TBL, PROC_TBL);
def self.ret_val(val)
@@ -97,3 +114,6 @@ class TkSpinbox<TkEntry
_fromUTF8(tk_send_without_enc('set', _get_eval_enc_str(str)))
end
end
+
+#TkSpinbox = Tk::Spinbox unless Object.const_defined? :TkSpinbox
+Tk.__set_toplevel_aliases__(:Tk, Tk::Spinbox, :TkSpinbox)
diff --git a/ext/tk/lib/tk/text.rb b/ext/tk/lib/tk/text.rb
index 0db10a653f..4ec82bed1d 100644
--- a/ext/tk/lib/tk/text.rb
+++ b/ext/tk/lib/tk/text.rb
@@ -1,6 +1,5 @@
#
# tk/text.rb - Tk text classes
-# $Date: 2005/11/23 12:01:05 $
# by Yukihiro Matsumoto <matz@caelum.co.jp>
require 'tk'
require 'tk/itemfont'
@@ -33,34 +32,40 @@ module TkTextTagConfig
def tag_cget(tagOrId, option)
itemcget(['tag', tagOrId], option)
end
+ def tag_cget_strict(tagOrId, option)
+ itemcget_strict(['tag', tagOrId], option)
+ end
def tag_configure(tagOrId, slot, value=None)
itemconfigure(['tag', tagOrId], slot, value)
end
def tag_configinfo(tagOrId, slot=nil)
- itemconfigure(['tag', tagOrId], slot)
+ itemconfiginfo(['tag', tagOrId], slot)
end
def current_tag_configinfo(tagOrId, slot=nil)
- itemconfigure(['tag', tagOrId], slot)
+ current_itemconfiginfo(['tag', tagOrId], slot)
end
def window_cget(tagOrId, option)
itemcget(['window', tagOrId], option)
end
+ def window_cget_strict(tagOrId, option)
+ itemcget_strict(['window', tagOrId], option)
+ end
def window_configure(tagOrId, slot, value=None)
itemconfigure(['window', tagOrId], slot, value)
end
def window_configinfo(tagOrId, slot=nil)
- itemconfigure(['window', tagOrId], slot)
+ itemconfiginfo(['window', tagOrId], slot)
end
def current_window_configinfo(tagOrId, slot=nil)
- itemconfigure(['window', tagOrId], slot)
+ current_itemconfiginfo(['window', tagOrId], slot)
end
- private :itemcget, :itemconfigure
- private :itemconfiginfo, :current_itemconfiginfo
+ private :itemcget, :itemcget_strict
+ private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo
end
-class TkText<TkTextWin
+class Tk::Text<TkTextWin
ItemConfCMD = ['tag'.freeze, 'configure'.freeze].freeze
#include TkTreatTextTagFont
include TkTextTagConfig
@@ -74,9 +79,9 @@ class TkText<TkTextWin
mod = mod.to_s
if mod =~ /^\s*[+-]?\d/
- TkText::IndexString.new(String.new(id) << ' + ' << mod)
+ Tk::Text::IndexString.new(String.new(id) << ' + ' << mod)
else
- TkText::IndexString.new(String.new(id) << ' ' << mod)
+ Tk::Text::IndexString.new(String.new(id) << ' ' << mod)
end
end
@@ -85,20 +90,20 @@ class TkText<TkTextWin
mod = mod.to_s
if mod =~ /^\s*[+-]?\d/
- TkText::IndexString.new(String.new(id) << ' - ' << mod)
+ Tk::Text::IndexString.new(String.new(id) << ' - ' << mod)
elsif mod =~ /^\s*[-]\s+(\d.*)$/
- TkText::IndexString.new(String.new(id) << ' - -' << $1)
+ Tk::Text::IndexString.new(String.new(id) << ' - -' << $1)
else
- TkText::IndexString.new(String.new(id) << ' ' << mod)
+ Tk::Text::IndexString.new(String.new(id) << ' ' << mod)
end
end
def chars(mod)
fail ArgumentError, 'expect Integer' unless mod.kind_of?(Integer)
if mod < 0
- TkText::IndexString.new(String.new(id) << ' ' << mod.to_s << ' chars')
+ Tk::Text::IndexString.new(String.new(id) << ' ' << mod.to_s << ' chars')
else
- TkText::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' chars')
+ Tk::Text::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' chars')
end
end
alias char chars
@@ -107,9 +112,9 @@ class TkText<TkTextWin
# Tk8.5 feature
fail ArgumentError, 'expect Integer' unless mod.kind_of?(Integer)
if mod < 0
- TkText::IndexString.new(String.new(id) << ' ' << mod.to_s << ' display chars')
+ Tk::Text::IndexString.new(String.new(id) << ' ' << mod.to_s << ' display chars')
else
- TkText::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' display chars')
+ Tk::Text::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' display chars')
end
end
alias display_char display_chars
@@ -118,9 +123,9 @@ class TkText<TkTextWin
# Tk8.5 feature
fail ArgumentError, 'expect Integer' unless mod.kind_of?(Integer)
if mod < 0
- TkText::IndexString.new(String.new(id) << ' ' << mod.to_s << ' any chars')
+ Tk::Text::IndexString.new(String.new(id) << ' ' << mod.to_s << ' any chars')
else
- TkText::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' any chars')
+ Tk::Text::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' any chars')
end
end
alias any_char any_chars
@@ -129,9 +134,9 @@ class TkText<TkTextWin
# Tk8.5 feature
fail ArgumentError, 'expect Integer' unless mod.kind_of?(Integer)
if mod < 0
- TkText::IndexString.new(String.new(id) << ' ' << mod.to_s << ' indices')
+ Tk::Text::IndexString.new(String.new(id) << ' ' << mod.to_s << ' indices')
else
- TkText::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' indices')
+ Tk::Text::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' indices')
end
end
@@ -139,9 +144,9 @@ class TkText<TkTextWin
# Tk8.5 feature
fail ArgumentError, 'expect Integer' unless mod.kind_of?(Integer)
if mod < 0
- TkText::IndexString.new(String.new(id) << ' ' << mod.to_s << ' display indices')
+ Tk::Text::IndexString.new(String.new(id) << ' ' << mod.to_s << ' display indices')
else
- TkText::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' display indices')
+ Tk::Text::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' display indices')
end
end
@@ -149,18 +154,18 @@ class TkText<TkTextWin
# Tk8.5 feature
fail ArgumentError, 'expect Integer' unless mod.kind_of?(Integer)
if mod < 0
- TkText::IndexString.new(String.new(id) << ' ' << mod.to_s << ' any indices')
+ Tk::Text::IndexString.new(String.new(id) << ' ' << mod.to_s << ' any indices')
else
- TkText::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' any indices')
+ Tk::Text::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' any indices')
end
end
def lines(mod)
fail ArgumentError, 'expect Integer' unless mod.kind_of?(Integer)
if mod < 0
- TkText::IndexString.new(String.new(id) << ' ' << mod.to_s << ' lines')
+ Tk::Text::IndexString.new(String.new(id) << ' ' << mod.to_s << ' lines')
else
- TkText::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' lines')
+ Tk::Text::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' lines')
end
end
alias line lines
@@ -169,9 +174,9 @@ class TkText<TkTextWin
# Tk8.5 feature
fail ArgumentError, 'expect Integer' unless mod.kind_of?(Integer)
if mod < 0
- TkText::IndexString.new(String.new(id) << ' ' << mod.to_s << ' display_lines')
+ Tk::Text::IndexString.new(String.new(id) << ' ' << mod.to_s << ' display_lines')
else
- TkText::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' display lines')
+ Tk::Text::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' display lines')
end
end
alias display_line display_lines
@@ -180,43 +185,43 @@ class TkText<TkTextWin
# Tk8.5 feature
fail ArgumentError, 'expect Integer' unless mod.kind_of?(Integer)
if mod < 0
- TkText::IndexString.new(String.new(id) << ' ' << mod.to_s << ' any_lines')
+ Tk::Text::IndexString.new(String.new(id) << ' ' << mod.to_s << ' any_lines')
else
- TkText::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' any lines')
+ Tk::Text::IndexString.new(String.new(id) << ' + ' << mod.to_s << ' any lines')
end
end
alias any_line any_lines
def linestart
- TkText::IndexString.new(String.new(id) << ' linestart')
+ Tk::Text::IndexString.new(String.new(id) << ' linestart')
end
def lineend
- TkText::IndexString.new(String.new(id) << ' lineend')
+ Tk::Text::IndexString.new(String.new(id) << ' lineend')
end
def display_linestart
# Tk8.5 feature
- TkText::IndexString.new(String.new(id) << ' display linestart')
+ Tk::Text::IndexString.new(String.new(id) << ' display linestart')
end
def display_lineend
# Tk8.5 feature
- TkText::IndexString.new(String.new(id) << ' display lineend')
+ Tk::Text::IndexString.new(String.new(id) << ' display lineend')
end
def wordstart
- TkText::IndexString.new(String.new(id) << ' wordstart')
+ Tk::Text::IndexString.new(String.new(id) << ' wordstart')
end
def wordend
- TkText::IndexString.new(String.new(id) << ' wordend')
+ Tk::Text::IndexString.new(String.new(id) << ' wordend')
end
def display_wordstart
# Tk8.5 feature
- TkText::IndexString.new(String.new(id) << ' display wordstart')
+ Tk::Text::IndexString.new(String.new(id) << ' display wordstart')
end
def display_wordend
# Tk8.5 feature
- TkText::IndexString.new(String.new(id) << ' display wordend')
+ Tk::Text::IndexString.new(String.new(id) << ' display wordend')
end
end
@@ -251,7 +256,11 @@ class TkText<TkTextWin
def self.new(*args, &block)
obj = super(*args){}
obj.init_instance_variable
- obj.instance_eval(&block) if defined? yield
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ obj.instance_exec(obj, &block) if defined? yield
+ else
+ obj.instance_eval(&block) if defined? yield
+ end
obj
end
@@ -261,8 +270,12 @@ class TkText<TkTextWin
end
def __destroy_hook__
- TkTextTag::TTagID_TBL.delete(@path)
- TkTextMark::TMarkID_TBL.delete(@path)
+ TkTextTag::TTagID_TBL.mutex.synchronize{
+ TkTextTag::TTagID_TBL.delete(@path)
+ }
+ TkTextTag::TMarkID_TBL.mutex.synchronize{
+ TkTextMark::TMarkID_TBL.delete(@path)
+ }
end
def create_self(keys)
@@ -285,16 +298,16 @@ class TkText<TkTextWin
private :__strval_optkeys
def self.at(x, y)
- TkText::IndexString.at(x, y)
+ Tk::Text::IndexString.at(x, y)
end
def at(x, y)
- TkText::IndexString.at(x, y)
+ Tk::Text::IndexString.at(x, y)
end
def index(idx)
- TkText::IndexString.new(tk_send_without_enc('index',
- _get_eval_enc_str(idx)))
+ Tk::Text::IndexString.new(tk_send_without_enc('index',
+ _get_eval_enc_str(idx)))
end
def get_displaychars(*index)
@@ -396,7 +409,7 @@ class TkText<TkTextWin
end
alias previous_mark mark_previous
- def image_cget(index, slot)
+ def image_cget_strict(index, slot)
case slot.to_s
when 'text', 'label', 'show', 'data', 'file'
_fromUTF8(tk_send_without_enc('image', 'cget',
@@ -408,6 +421,28 @@ class TkText<TkTextWin
end
end
+ def image_cget(index, slot)
+ unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ image_cget_strict(index, slot)
+ else
+ begin
+ image_cget_strict(index, slot)
+ rescue => e
+ begin
+ if current_image_configinfo(index).has_key?(slot.to_s)
+ # not tag error & option is known -> error on known option
+ fail e
+ else
+ # not tag error & option is unknown
+ nil
+ end
+ rescue
+ fail e # tag error
+ end
+ end
+ end
+ end
+
def image_configure(index, slot, value=None)
if slot.kind_of?(Hash)
_fromUTF8(tk_send_without_enc('image', 'configure',
@@ -713,15 +748,17 @@ class TkText<TkTextWin
def tag_delete(*tags)
tk_send_without_enc('tag', 'delete',
*(tags.collect{|tag| _get_eval_enc_str(tag)}))
- if TkTextTag::TTagID_TBL[@path]
- tags.each{|tag|
- if tag.kind_of?(TkTextTag)
- TkTextTag::TTagID_TBL[@path].delete(tag.id)
- else
- TkTextTag::TTagID_TBL[@path].delete(tag)
- end
- }
- end
+ TkTextTag::TTagID_TBL.mutex.synchronize{
+ if TkTextTag::TTagID_TBL[@path]
+ tags.each{|tag|
+ if tag.kind_of?(TkTextTag)
+ TkTextTag::TTagID_TBL[@path].delete(tag.id)
+ else
+ TkTextTag::TTagID_TBL[@path].delete(tag)
+ end
+ }
+ end
+ }
self
end
alias deltag tag_delete
@@ -968,7 +1005,7 @@ class TkText<TkTextWin
false, true)
r = []
while key=l.shift
- r.push [TkText::IndexString.new(key), TkText::IndexString.new(l.shift)]
+ r.push [Tk::Text::IndexString.new(key), Tk::Text::IndexString.new(l.shift)]
end
r
end
@@ -978,7 +1015,7 @@ class TkText<TkTextWin
_get_eval_enc_str(tag),
_get_eval_enc_str(first),
_get_eval_enc_str(last))).collect{|idx|
- TkText::IndexString.new(idx)
+ Tk::Text::IndexString.new(idx)
}
end
@@ -987,7 +1024,7 @@ class TkText<TkTextWin
_get_eval_enc_str(tag),
_get_eval_enc_str(first),
_get_eval_enc_str(last))).collect{|idx|
- TkText::IndexString.new(idx)
+ Tk::Text::IndexString.new(idx)
}
end
@@ -1183,6 +1220,11 @@ class TkText<TkTextWin
end
def _ktext_length(txt)
+ if TkCore::WITH_ENCODING ### Ruby 1.9 !!!!!!!!!!!!!
+ return txt.length
+ end
+ ###########################
+
if $KCODE !~ /n/i
return txt.gsub(/[^\Wa-zA-Z_\d]/, ' ').length
end
@@ -1232,7 +1274,7 @@ class TkText<TkTextWin
if ret == ""
nil
else
- TkText::IndexString.new(ret)
+ Tk::Text::IndexString.new(ret)
end
end
@@ -1267,7 +1309,7 @@ class TkText<TkTextWin
if ret == ""
nil
else
- TkText::IndexString.new(ret)
+ Tk::Text::IndexString.new(ret)
end
end
@@ -1456,10 +1498,10 @@ class TkText<TkTextWin
# retrieve index
idx = str.index(/ /, i)
if idx
- result.push(TkText::IndexString.new(str[i..(idx-1)]))
+ result.push(Tk::Text::IndexString.new(str[i..(idx-1)]))
i = idx + 1
else
- result.push(TkText::IndexString.new(str[i..-1]))
+ result.push(Tk::Text::IndexString.new(str[i..-1]))
break
end
end
@@ -1527,13 +1569,17 @@ class TkText<TkTextWin
end
end
+#TkText = Tk::Text unless Object.const_defined? :TkText
+Tk.__set_toplevel_aliases__(:Tk, Tk::Text, :TkText)
+
+
#######################################
-class TkText::Peer < TkText
+class Tk::Text::Peer < Tk::Text
# Tk8.5 feature
def initialize(text, parent=nil, keys={})
- unless text.kind_of?(TkText)
- fail ArgumentError, "TkText is expected for 1st argument"
+ unless text.kind_of?(Tk::Text)
+ fail ArgumentError, "Tk::Text is expected for 1st argument"
end
@src_text = text
super(parent, keys)
diff --git a/ext/tk/lib/tk/textimage.rb b/ext/tk/lib/tk/textimage.rb
index a29b23c7dd..fb306a9c17 100644
--- a/ext/tk/lib/tk/textimage.rb
+++ b/ext/tk/lib/tk/textimage.rb
@@ -5,11 +5,11 @@ require 'tk'
require 'tk/text'
class TkTextImage<TkObject
- include TkText::IndexModMethods
+ include Tk::Text::IndexModMethods
def initialize(parent, index, keys)
- #unless parent.kind_of?(TkText)
- # fail ArgumentError, "expect TkText for 1st argument"
+ #unless parent.kind_of?(Tk::Text)
+ # fail ArgumentError, "expect Tk::Text for 1st argument"
#end
@t = parent
if index == 'end' || index == :end
@@ -34,7 +34,7 @@ class TkTextImage<TkObject
end
def id
- TkText::IndexString.new(@id)
+ Tk::Text::IndexString.new(@id)
end
def mark
@path
@@ -52,6 +52,10 @@ class TkTextImage<TkObject
@t.image_cget(@index, slot)
end
+ def cget_strict(slot)
+ @t.image_cget_strict(@index, slot)
+ end
+
def configure(slot, value=None)
@t.image_configure(@index, slot, value)
self
@@ -80,3 +84,5 @@ class TkTextImage<TkObject
value
end
end
+
+TktImage = TkTextImage
diff --git a/ext/tk/lib/tk/textmark.rb b/ext/tk/lib/tk/textmark.rb
index 650d95af70..72c1ce1ab4 100644
--- a/ext/tk/lib/tk/textmark.rb
+++ b/ext/tk/lib/tk/textmark.rb
@@ -5,38 +5,54 @@ require 'tk'
require 'tk/text'
class TkTextMark<TkObject
- include TkText::IndexModMethods
+ include Tk::Text::IndexModMethods
TMarkID_TBL = TkCore::INTERP.create_table
- Tk_TextMark_ID = ['mark'.freeze, '00000'.taint].freeze
- TkCore::INTERP.init_ip_env{ TMarkID_TBL.clear }
+ (Tk_TextMark_ID = ['mark'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
+ TkCore::INTERP.init_ip_env{
+ TMarkID_TBL.mutex.synchronize{ TMarkID_TBL.clear }
+ }
def TkTextMark.id2obj(text, id)
tpath = text.path
- return id unless TMarkID_TBL[tpath]
- TMarkID_TBL[tpath][id]? TMarkID_TBL[tpath][id]: id
+ TMarkID_TBL.mutex.synchronize{
+ if TMarkID_TBL[tpath]
+ TMarkID_TBL[tpath][id]? TMarkID_TBL[tpath][id]: id
+ else
+ id
+ end
+ }
end
def initialize(parent, index)
- #unless parent.kind_of?(TkText)
- # fail ArgumentError, "expect TkText for 1st argument"
+ #unless parent.kind_of?(Tk::Text)
+ # fail ArgumentError, "expect Tk::Text for 1st argument"
#end
@parent = @t = parent
@tpath = parent.path
- # @path = @id = Tk_TextMark_ID.join('')
- @path = @id = Tk_TextMark_ID.join(TkCore::INTERP._ip_id_).freeze
- TMarkID_TBL[@id] = self
- TMarkID_TBL[@tpath] = {} unless TMarkID_TBL[@tpath]
- TMarkID_TBL[@tpath][@id] = self
- Tk_TextMark_ID[1].succ!
+ Tk_TextMark_ID.mutex.synchronize{
+ # @path = @id = Tk_TextMark_ID.join('')
+ @path = @id = Tk_TextMark_ID.join(TkCore::INTERP._ip_id_).freeze
+ Tk_TextMark_ID[1].succ!
+ }
+ TMarkID_TBL.mutex.synchronize{
+ TMarkID_TBL[@id] = self
+ TMarkID_TBL[@tpath] = {} unless TMarkID_TBL[@tpath]
+ TMarkID_TBL[@tpath][@id] = self
+ }
tk_call_without_enc(@t.path, 'mark', 'set', @id,
_get_eval_enc_str(index))
@t._addtag id, self
end
def id
- TkText::IndexString.new(@id)
+ Tk::Text::IndexString.new(@id)
end
def exist?
@@ -49,15 +65,15 @@ class TkTextMark<TkObject
end
=begin
- # move to TkText::IndexModMethods module
+ # move to Tk::Text::IndexModMethods module
def +(mod)
return chars(mod) if mod.kind_of?(Numeric)
mod = mod.to_s
if mod =~ /^\s*[+-]?\d/
- TkText::IndexString.new(@id + ' + ' + mod)
+ Tk::Text::IndexString.new(@id + ' + ' + mod)
else
- TkText::IndexString.new(@id + ' ' + mod)
+ Tk::Text::IndexString.new(@id + ' ' + mod)
end
end
@@ -66,11 +82,11 @@ class TkTextMark<TkObject
mod = mod.to_s
if mod =~ /^\s*[+-]?\d/
- TkText::IndexString.new(@id + ' - ' + mod)
+ Tk::Text::IndexString.new(@id + ' - ' + mod)
elsif mod =~ /^\s*[-]\s+(\d.*)$/
- TkText::IndexString.new(@id + ' - -' + $1)
+ Tk::Text::IndexString.new(@id + ' - -' + $1)
else
- TkText::IndexString.new(@id + ' ' + mod)
+ Tk::Text::IndexString.new(@id + ' ' + mod)
end
end
=end
@@ -121,46 +137,68 @@ class TkTextMark<TkObject
end
end
end
+TktMark = TkTextMark
class TkTextNamedMark<TkTextMark
- def self.new(parent, name, *args)
- if TMarkID_TBL[parent.path] && TMarkID_TBL[parent.path][name]
- return TMarkID_TBL[parent.path][name]
- else
- super(parent, name, *args)
- end
+ def self.new(parent, name, index=nil)
+ TMarkID_TBL.mutex.synchronize{
+ if TMarkID_TBL[parent.path] && TMarkID_TBL[parent.path][name]
+ obj = TMarkID_TBL[parent.path][name]
+ else
+ # super(parent, name, *args)
+ (obj = self.allocate).instance_eval{
+ @parent = @t = parent
+ @tpath = parent.path
+ @path = @id = name
+ TMarkID_TBL[@id] = self
+ TMarkID_TBL[@tpath] = {} unless TMarkID_TBL[@tpath]
+ TMarkID_TBL[@tpath][@id] = self unless TMarkID_TBL[@tpath][@id]
+ @t._addtag @id, self
+ }
+ obj
+ end
+
+ if obj && index
+ tk_call_without_enc(parent.path, 'mark', 'set', name,
+ _get_eval_enc_str(index))
+ end
+ obj
+ }
end
def initialize(parent, name, index=nil)
- #unless parent.kind_of?(TkText)
- # fail ArgumentError, "expect TkText for 1st argument"
+ # dummy:: not called by 'new' method
+
+ #unless parent.kind_of?(Tk::Text)
+ # fail ArgumentError, "expect Tk::Text for 1st argument"
#end
@parent = @t = parent
@tpath = parent.path
@path = @id = name
- TMarkID_TBL[@id] = self
- TMarkID_TBL[@tpath] = {} unless TMarkID_TBL[@tpath]
- TMarkID_TBL[@tpath][@id] = self unless TMarkID_TBL[@tpath][@id]
tk_call_without_enc(@t.path, 'mark', 'set', @id,
_get_eval_enc_str(index)) if index
- @t._addtag id, self
+ @t._addtag @id, self
end
end
+TktNamedMark = TkTextNamedMark
class TkTextMarkInsert<TkTextNamedMark
def self.new(parent,*args)
super(parent, 'insert', *args)
end
end
+TktMarkInsert = TkTextMarkInsert
class TkTextMarkCurrent<TkTextNamedMark
def self.new(parent,*args)
super(parent, 'current', *args)
end
end
+TktMarkCurrent = TkTextMarkCurrent
class TkTextMarkAnchor<TkTextNamedMark
def self.new(parent,*args)
super(parent, 'anchor', *args)
end
end
+TktMarkAnchor = TkTextMarkAnchor
diff --git a/ext/tk/lib/tk/texttag.rb b/ext/tk/lib/tk/texttag.rb
index cc2c56210f..b08d923ea1 100644
--- a/ext/tk/lib/tk/texttag.rb
+++ b/ext/tk/lib/tk/texttag.rb
@@ -7,17 +7,29 @@ require 'tk/tagfont'
class TkTextTag<TkObject
include TkTreatTagFont
- include TkText::IndexModMethods
+ include Tk::Text::IndexModMethods
TTagID_TBL = TkCore::INTERP.create_table
- Tk_TextTag_ID = ['tag'.freeze, '00000'.taint].freeze
- TkCore::INTERP.init_ip_env{ TTagID_TBL.clear }
+ (Tk_TextTag_ID = ['tag'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
+ TkCore::INTERP.init_ip_env{
+ TTagID_TBL.mutex.synchronize{ TTagID_TBL.clear }
+ }
def TkTextTag.id2obj(text, id)
tpath = text.path
- return id unless TTagID_TBL[tpath]
- TTagID_TBL[tpath][id]? TTagID_TBL[tpath][id]: id
+ TTagID_TBL.mutex.synchronize{
+ if TTagID_TBL[tpath]
+ TTagID_TBL[tpath][id]? TTagID_TBL[tpath][id]: id
+ else
+ id
+ end
+ }
end
def initialize(parent, *args)
@@ -26,12 +38,16 @@ class TkTextTag<TkObject
#end
@parent = @t = parent
@tpath = parent.path
- # @path = @id = Tk_TextTag_ID.join('')
- @path = @id = Tk_TextTag_ID.join(TkCore::INTERP._ip_id_).freeze
- # TTagID_TBL[@id] = self
- TTagID_TBL[@tpath] = {} unless TTagID_TBL[@tpath]
- TTagID_TBL[@tpath][@id] = self
- Tk_TextTag_ID[1].succ!
+ Tk_TextTag_ID.mutex.synchronize{
+ # @path = @id = Tk_TextTag_ID.join('')
+ @path = @id = Tk_TextTag_ID.join(TkCore::INTERP._ip_id_).freeze
+ Tk_TextTag_ID[1].succ!
+ }
+ TTagID_TBL.mutex.synchronize{
+ TTagID_TBL[@id] = self
+ TTagID_TBL[@tpath] = {} unless TTagID_TBL[@tpath]
+ TTagID_TBL[@tpath][@id] = self
+ }
#tk_call @t.path, "tag", "configure", @id, *hash_kv(keys)
if args != []
keys = args.pop
@@ -47,7 +63,7 @@ class TkTextTag<TkObject
end
def id
- TkText::IndexString.new(@id)
+ Tk::Text::IndexString.new(@id)
end
def exist?
@@ -60,11 +76,11 @@ class TkTextTag<TkObject
end
def first
- TkText::IndexString.new(@id + '.first')
+ Tk::Text::IndexString.new(@id + '.first')
end
def last
- TkText::IndexString.new(@id + '.last')
+ Tk::Text::IndexString.new(@id + '.last')
end
def add(*indices)
@@ -83,7 +99,7 @@ class TkTextTag<TkObject
l = tk_split_simplelist(tk_call_without_enc(@t.path, 'tag', 'ranges', @id))
r = []
while key=l.shift
- r.push [TkText::IndexString.new(key), TkText::IndexString.new(l.shift)]
+ r.push [Tk::Text::IndexString.new(key), Tk::Text::IndexString.new(l.shift)]
end
r
end
@@ -92,7 +108,7 @@ class TkTextTag<TkObject
simplelist(tk_call_without_enc(@t.path, 'tag', 'nextrange', @id,
_get_eval_enc_str(first),
_get_eval_enc_str(last))).collect{|idx|
- TkText::IndexString.new(idx)
+ Tk::Text::IndexString.new(idx)
}
end
@@ -100,7 +116,7 @@ class TkTextTag<TkObject
simplelist(tk_call_without_enc(@t.path, 'tag', 'prevrange', @id,
_get_eval_enc_str(first),
_get_eval_enc_str(last))).collect{|idx|
- TkText::IndexString.new(idx)
+ Tk::Text::IndexString.new(idx)
}
end
@@ -116,6 +132,9 @@ class TkTextTag<TkObject
def cget(key)
@t.tag_cget @id, key
end
+ def cget_strict(key)
+ @t.tag_cget_strict @id, key
+ end
=begin
def cget(key)
case key.to_s
@@ -221,40 +240,58 @@ class TkTextTag<TkObject
def destroy
tk_call_without_enc(@t.path, 'tag', 'delete', @id)
- TTagID_TBL[@tpath].delete(@id) if TTagID_TBL[@tpath]
+ TTagID_TBL.mutex.synchronize{
+ TTagID_TBL[@tpath].delete(@id) if TTagID_TBL[@tpath]
+ }
self
end
end
+TktTag = TkTextTag
class TkTextNamedTag<TkTextTag
def self.new(parent, name, *args)
- if TTagID_TBL[parent.path] && TTagID_TBL[parent.path][name]
- tagobj = TTagID_TBL[parent.path][name]
- if args != []
- keys = args.pop
- if keys.kind_of?(Hash)
- tagobj.add(*args) if args != []
- tagobj.configure(keys)
- else
- args.push keys
- tagobj.add(*args)
- end
+ tagobj = nil
+ TTagID_TBL.mutex.synchronize{
+ if TTagID_TBL[parent.path] && TTagID_TBL[parent.path][name]
+ tagobj = TTagID_TBL[parent.path][name]
+ else
+ # super(parent, name, *args)
+ (tagobj = self.allocate).instance_eval{
+ @parent = @t = parent
+ @tpath = parent.path
+ @path = @id = name
+ TTagID_TBL[@id] = self
+ TTagID_TBL[@tpath] = {} unless TTagID_TBL[@tpath]
+ TTagID_TBL[@tpath][@id] = self unless TTagID_TBL[@tpath][@id]
+ @t._addtag @id, self
+ }
+ end
+ }
+
+ if args != []
+ keys = args.pop
+ if keys.kind_of?(Hash)
+ tagobj.add(*args) if args != []
+ tagobj.configure(keys)
+ else
+ args.push keys
+ tagobj.add(*args)
end
- return tagobj
- else
- super(parent, name, *args)
end
+
+ tagobj
end
def initialize(parent, name, *args)
- #unless parent.kind_of?(TkText)
- # fail ArgumentError, "expect TkText for 1st argument"
+ # dummy:: not called by 'new' method
+
+ #unless parent.kind_of?(Tk::Text)
+ # fail ArgumentError, "expect Tk::Text for 1st argument"
#end
@parent = @t = parent
@tpath = parent.path
@path = @id = name
- TTagID_TBL[@tpath] = {} unless TTagID_TBL[@tpath]
- TTagID_TBL[@tpath][@id] = self unless TTagID_TBL[@tpath][@id]
+
#if mode
# tk_call @t.path, "addtag", @id, *args
#end
@@ -268,12 +305,14 @@ class TkTextNamedTag<TkTextTag
add(*args)
end
end
- @t._addtag id, self
+ @t._addtag @id, self
end
end
+TktNamedTag = TkTextNamedTag
class TkTextTagSel<TkTextNamedTag
def self.new(parent, *args)
super(parent, 'sel', *args)
end
end
+TktTagSel = TkTextTagSel
diff --git a/ext/tk/lib/tk/textwindow.rb b/ext/tk/lib/tk/textwindow.rb
index 605c40addd..004422e4f3 100644
--- a/ext/tk/lib/tk/textwindow.rb
+++ b/ext/tk/lib/tk/textwindow.rb
@@ -5,11 +5,11 @@ require 'tk'
require 'tk/text'
class TkTextWindow<TkObject
- include TkText::IndexModMethods
+ include Tk::Text::IndexModMethods
def initialize(parent, index, keys = {})
- #unless parent.kind_of?(TkText)
- # fail ArgumentError, "expect TkText for 1st argument"
+ #unless parent.kind_of?(Tk::Text)
+ # fail ArgumentError, "expect Tk::Text for 1st argument"
#end
@t = parent
if index == 'end' || index == :end
@@ -55,7 +55,7 @@ class TkTextWindow<TkObject
end
def id
- TkText::IndexString.new(_epath(@id))
+ Tk::Text::IndexString.new(_epath(@id))
end
def mark
@path
@@ -72,6 +72,9 @@ class TkTextWindow<TkObject
def cget(slot)
@t.window_cget(@index, slot)
end
+ def cget_strict(slot)
+ @t.window_cget_strict(@index, slot)
+ end
def configure(slot, value=None)
if slot.kind_of?(Hash)
@@ -147,3 +150,5 @@ class TkTextWindow<TkObject
value
end
end
+
+TktWindow = TkTextWindow
diff --git a/ext/tk/lib/tk/timer.rb b/ext/tk/lib/tk/timer.rb
index 49b7f1b06a..91840d0575 100644
--- a/ext/tk/lib/tk/timer.rb
+++ b/ext/tk/lib/tk/timer.rb
@@ -1,7 +1,7 @@
#
# tk/timer.rb : methods for Tcl/Tk after command
#
-# $Id: timer.rb,v 1.1.2.15 2005/05/08 14:20:53 nagai Exp $
+# $Id$
#
require 'tk'
@@ -11,7 +11,12 @@ class TkTimer
TkCommandNames = ['after'.freeze].freeze
- Tk_CBID = ['a'.freeze, '00000'.taint].freeze
+ (Tk_CBID = ['a'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
Tk_CBTBL = {}.taint
TkCore::INTERP.add_tk_procs('rb_after', 'id', <<-'EOL')
@@ -96,9 +101,9 @@ class TkTimer
return self
end
@after_script = "rb_after #{@id}"
- @after_id = tk_call_without_enc('after', sleep, @after_script)
@current_args = args
@current_script = [sleep, @after_script]
+ @after_id = tk_call_without_enc('after', sleep, @after_script)
self
end
@@ -106,7 +111,8 @@ class TkTimer
if @running == false || @proc_max == 0 || @do_loop == 0
Tk_CBTBL.delete(@id) ;# for GC
@running = false
- @wait_var.value = 0
+ # @wait_var.value = 0
+ __at_end__
return
end
if @current_pos >= @proc_max
@@ -115,7 +121,8 @@ class TkTimer
else
Tk_CBTBL.delete(@id) ;# for GC
@running = false
- @wait_var.value = 0
+ # @wait_var.value = 0
+ __at_end__
return
end
end
@@ -138,12 +145,16 @@ class TkTimer
end
def initialize(*args, &b)
- # @id = Tk_CBID.join('')
- @id = Tk_CBID.join(TkCore::INTERP._ip_id_)
- Tk_CBID[1].succ!
+ Tk_CBID.mutex.synchronize{
+ # @id = Tk_CBID.join('')
+ @id = Tk_CBID.join(TkCore::INTERP._ip_id_)
+ Tk_CBID[1].succ!
+ }
@wait_var = TkVariable.new(0)
+ @at_end_proc = nil
+
@cb_cmd = TkCore::INTERP.get_cb_entry(self.method(:do_callback))
@set_next = true
@@ -203,6 +214,12 @@ class TkTimer
attr_accessor :loop_exec
+ def __at_end__
+ @at_end_proc.call(self) if @at_end_proc
+ @wait_var.value = 0 # for wait
+ end
+ private :__at_end__
+
def cb_call
@cb_cmd.call
end
@@ -420,7 +437,8 @@ class TkTimer
def cancel
@running = false
- @wait_var.value = 0
+ # @wait_var.value = 0
+ __at_end__
tk_call 'after', 'cancel', @after_id if @after_id
@after_id = nil
@@ -464,6 +482,21 @@ class TkTimer
end
end
+ def at_end(*arg, &b)
+ if arg.empty?
+ if b
+ @at_end_proc = b
+ else
+ # no proc
+ return @at_end_proc
+ end
+ else
+ fail ArgumentError, "wrong number of arguments" if arg.length != 1 || b
+ @at_end_proc = arg[0]
+ end
+ self
+ end
+
def wait(on_thread = true, check_root = false)
if $SAFE >= 4
fail SecurityError, "can't wait timer at $SAFE >= 4"
@@ -562,7 +595,8 @@ class TkRTTimer < TkTimer
if @running == false || @proc_max == 0 || @do_loop == 0
Tk_CBTBL.delete(@id) ;# for GC
@running = false
- @wait_var.value = 0
+ # @wait_var.value = 0
+ __at_end__
return
end
if @current_pos >= @proc_max
@@ -571,7 +605,8 @@ class TkRTTimer < TkTimer
else
Tk_CBTBL.delete(@id) ;# for GC
@running = false
- @wait_var.value = 0
+ # @wait_var.value = 0
+ __at_end__
return
end
end
diff --git a/ext/tk/lib/tk/toplevel.rb b/ext/tk/lib/tk/toplevel.rb
index 5e199e1330..bd6e8307f5 100644
--- a/ext/tk/lib/tk/toplevel.rb
+++ b/ext/tk/lib/tk/toplevel.rb
@@ -5,7 +5,7 @@ require 'tk'
require 'tk/wm'
require 'tk/menuspec'
-class TkToplevel<TkWindow
+class Tk::Toplevel<TkWindow
include Wm
include TkMenuSpec
@@ -72,7 +72,7 @@ class TkToplevel<TkWindow
conf_methods = _symbolkey2str(__methodcall_optkeys())
- keys.each{|k,v|
+ keys.each{|k,v| # k is a String
if conf_methods.key?(k)
wm_cmds[conf_methods[k]] = v
elsif Wm.method_defined?(k)
@@ -117,9 +117,10 @@ class TkToplevel<TkWindow
end
if @classname.kind_of? TkBindTag
@db_class = @classname
- @classname = @classname.id
+ keys['class'] = @classname = @classname.id
elsif @classname
@db_class = TkDatabaseClass.new(@classname)
+ keys['class'] = @classname
else
@db_class = self.class
@classname = @db_class::WidgetClassName
@@ -165,9 +166,10 @@ class TkToplevel<TkWindow
end
if @classname.kind_of? TkBindTag
@db_class = @classname
- @classname = @classname.id
+ keys['class'] = @classname = @classname.id
elsif @classname
@db_class = TkDatabaseClass.new(@classname)
+ keys['class'] = @classname
else
@db_class = self.class
@classname = @db_class::WidgetClassName
@@ -255,3 +257,6 @@ class TkToplevel<TkWindow
end
end
end
+
+#TkToplevel = Tk::Toplevel unless Object.const_defined? :TkToplevel
+Tk.__set_toplevel_aliases__(:Tk, Tk::Toplevel, :TkToplevel)
diff --git a/ext/tk/lib/tk/ttk_selector.rb b/ext/tk/lib/tk/ttk_selector.rb
new file mode 100644
index 0000000000..72ed637a38
--- /dev/null
+++ b/ext/tk/lib/tk/ttk_selector.rb
@@ -0,0 +1,76 @@
+#
+# ttk_selector
+#
+######################################
+# toplevel classes/modules
+module Tk
+ @TOPLEVEL_ALIAS_TABLE[:Ttk] = {
+ :TkButton => 'tkextlib/tile/tbutton',
+
+ :TkCheckbutton => 'tkextlib/tile/tcheckbutton',
+ :TkCheckButton => 'tkextlib/tile/tcheckbutton',
+
+ # :TkDialog => 'tkextlib/tile/dialog',
+
+ :TkEntry => 'tkextlib/tile/tentry',
+
+ :TkCombobox => 'tkextlib/tile/tcombobox',
+
+ :TkFrame => 'tkextlib/tile/tframe',
+
+ :TkLabel => 'tkextlib/tile/tlabel',
+
+ :TkLabelframe => 'tkextlib/tile/tlabelframe',
+ :TkLabelFrame => 'tkextlib/tile/tlabelframe',
+
+ :TkMenubutton => 'tkextlib/tile/tmenubutton',
+ :TkMenuButton => 'tkextlib/tile/tmenubutton',
+
+ :TkNotebook => 'tkextlib/tile/tnotebook',
+
+ # :TkPaned => 'tkextlib/tile/tpaned',
+ :TkPanedwindow => 'tkextlib/tile/tpaned',
+ :TkPanedWindow => 'tkextlib/tile/tpaned',
+
+ :TkProgressbar => 'tkextlib/tile/tprogressbar',
+
+ :TkRadiobutton => 'tkextlib/tile/tradiobutton',
+ :TkRadioButton => 'tkextlib/tile/tradiobutton',
+
+ :TkScale => 'tkextlib/tile/tscale',
+ # :TkProgress => 'tkextlib/tile/tscale',
+
+ :TkScrollbar => 'tkextlib/tile/tscrollbar',
+ :TkXScrollbar => 'tkextlib/tile/tscrollbar',
+ :TkYScrollbar => 'tkextlib/tile/tscrollbar',
+
+ :TkSeparator => 'tkextlib/tile/tseparator',
+
+ :TkSizeGrip => 'tkextlib/tile/sizegrip',
+ :TkSizegrip => 'tkextlib/tile/sizegrip',
+
+ # :TkSquare => 'tkextlib/tile/tsquare',
+
+ :TkTreeview => 'tkextlib/tile/treeview',
+ }
+ @TOPLEVEL_ALIAS_TABLE[:Tile] = @TOPLEVEL_ALIAS_TABLE[:Ttk]
+
+ ################################################
+ # register some Ttk widgets as default
+ # (Ttk is a standard library on Tcl/Tk8.5+)
+ @TOPLEVEL_ALIAS_TABLE[:Ttk].each{|sym, file|
+ unless Object.autoload?(sym) || Object.const_defined?(sym)
+ Object.autoload(sym, file)
+ end
+ }
+
+ ################################################
+
+ @TOPLEVEL_ALIAS_SETUP_PROC[:Tile] =
+ @TOPLEVEL_ALIAS_SETUP_PROC[:Ttk] = proc{|mod|
+ unless Tk.autoload?(:Tile) || Tk.const_defined?(:Tile)
+ Object.autoload :Ttk, 'tkextlib/tile'
+ Tk.autoload :Tile, 'tkextlib/tile'
+ end
+ }
+end
diff --git a/ext/tk/lib/tk/txtwin_abst.rb b/ext/tk/lib/tk/txtwin_abst.rb
index 5520360eab..540f806d17 100644
--- a/ext/tk/lib/tk/txtwin_abst.rb
+++ b/ext/tk/lib/tk/txtwin_abst.rb
@@ -4,7 +4,7 @@
require 'tk'
class TkTextWin<TkWindow
- TkCommnadNames = [].freeze
+ TkCommandNames = [].freeze
#def create_self
# fail RuntimeError, "TkTextWin is an abstract class"
#end
diff --git a/ext/tk/lib/tk/validation.rb b/ext/tk/lib/tk/validation.rb
index 0c5b5c61b9..60bd433cdc 100644
--- a/ext/tk/lib/tk/validation.rb
+++ b/ext/tk/lib/tk/validation.rb
@@ -50,7 +50,8 @@ module Tk
key2class.each{|key, klass|
if keys[key].kind_of?(Array)
cmd, *args = keys[key]
- keys[key] = klass.new(cmd, args.join(' '))
+ #keys[key] = klass.new(cmd, args.join(' '))
+ keys[key] = klass.new(cmd, *args)
# elsif keys[key].kind_of?(Proc) || keys[key].kind_of?(Method)
elsif TkComm._callback_entry?(keys[key])
keys[key] = klass.new(keys[key])
@@ -151,7 +152,8 @@ module Tk
key2class.each{|key, klass|
if keys[key].kind_of?(Array)
cmd, *args = keys[key]
- keys[key] = klass.new(cmd, args.join(' '))
+ #keys[key] = klass.new(cmd, args.join(' '))
+ keys[key] = klass.new(cmd, *args)
# elsif keys[key].kind_of?(Proc) || keys[key].kind_of?(Method)
elsif TkComm._callback_entry?(keys[key])
keys[key] = klass.new(keys[key])
@@ -249,6 +251,24 @@ class TkValidateCommand
nil
]
+=begin
+ # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
+ KEY_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String)
+ end
+ inf
+ }
+
+ PROC_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ end
+ inf
+ }
+=end
+
_setup_subst_table(KEY_TBL, PROC_TBL);
#
@@ -277,6 +297,7 @@ class TkValidateCommand
extra_args_tbl = klass._get_extra_args_tbl
if args.compact.size > 0
+ args.map!{|arg| klass._sym2subst(arg)}
args = args.join(' ')
keys = klass._get_subst_key(args)
if cmd.kind_of?(String)
diff --git a/ext/tk/lib/tk/variable.rb b/ext/tk/lib/tk/variable.rb
index e5cacadc1a..f738a96ee7 100644
--- a/ext/tk/lib/tk/variable.rb
+++ b/ext/tk/lib/tk/variable.rb
@@ -16,11 +16,22 @@ class TkVariable
#TkVar_ID_TBL = {}
TkVar_CB_TBL = TkCore::INTERP.create_table
TkVar_ID_TBL = TkCore::INTERP.create_table
- Tk_VARIABLE_ID = ["v".freeze, "00000".taint].freeze
+ (Tk_VARIABLE_ID = ["v".freeze, "00000".taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+ TkCore::INTERP.init_ip_env{
+ TkVar_CB_TBL.mutex.synchronize{ TkVar_CB_TBL.clear }
+ TkVar_ID_TBL.mutex.synchronize{ TkVar_ID_TBL.clear }
+ }
+
+ major, minor, type, type_name, patchlevel = TclTkLib.get_version
+ USE_OLD_TRACE_OPTION_STYLE = (major < 8) || (major == 8 && minor < 4)
#TkCore::INTERP.add_tk_procs('rb_var', 'args',
# "ruby [format \"TkVariable.callback %%Q!%s!\" $args]")
-TkCore::INTERP.add_tk_procs('rb_var', 'args', <<-'EOL')
+ TkCore::INTERP.add_tk_procs('rb_var', 'args', <<-'EOL')
if {[set st [catch {eval {ruby_cmd TkVariable callback} $args} ret]] != 0} {
set idx [string first "\n\n" $ret]
if {$idx > 0} {
@@ -44,10 +55,10 @@ TkCore::INTERP.add_tk_procs('rb_var', 'args', <<-'EOL')
def TkVariable.callback(id, name1, name2, op)
#name1,name2,op = tk_split_list(args)
#name1,name2,op = tk_split_simplelist(args)
- if TkVar_CB_TBL[id]
+ if cb_obj = TkVar_CB_TBL[id]
#_get_eval_string(TkVar_CB_TBL[name1].trace_callback(name2,op))
begin
- _get_eval_string(TkVar_CB_TBL[id].trace_callback(name2, op))
+ _get_eval_string(cb_obj.trace_callback(name2, op))
rescue SystemExit
exit(0)
rescue Interrupt
@@ -59,7 +70,11 @@ TkCore::INTERP.add_tk_procs('rb_var', 'args', <<-'EOL')
"\n---< backtrace of Ruby side >-----\n" +
_toUTF8(e.backtrace.join("\n")) +
"\n---< backtrace of Tk side >-------"
- msg.instance_variable_set(:@encoding, 'utf-8')
+ if TkCore::WITH_ENCODING
+ msg.force_encoding('utf-8')
+ else
+ msg.instance_variable_set(:@encoding, 'utf-8')
+ end
rescue Exception
msg = e.class.inspect + ': ' + e.message + "\n" +
"\n---< backtrace of Ruby side >-----\n" +
@@ -267,11 +282,15 @@ TkCore::INTERP.add_tk_procs('rb_var', 'args', <<-'EOL')
def initialize(val="", type=nil)
# @id = Tk_VARIABLE_ID.join('')
begin
- @id = Tk_VARIABLE_ID.join(TkCore::INTERP._ip_id_)
- Tk_VARIABLE_ID[1].succ!
+ Tk_VARIABLE_ID.mutex.synchronize{
+ @id = Tk_VARIABLE_ID.join(TkCore::INTERP._ip_id_)
+ Tk_VARIABLE_ID[1].succ!
+ }
end until INTERP._invoke_without_enc('info', 'globals', @id).empty?
- TkVar_ID_TBL[@id] = self
+ TkVar_ID_TBL.mutex.synchronize{
+ TkVar_ID_TBL[@id] = self
+ }
@var = @id
@elem = nil
@@ -1263,56 +1282,101 @@ end
end
end
+ def _check_trace_opt(opts)
+ if opts.kind_of?(Array)
+ opt_str = opts.map{|s| s.to_s}.join(' ')
+ else
+ opt_str = opts.to_s
+ end
+
+ fail ArgumentError, 'null trace option' if opt_str.empty?
+
+ if opt_str =~ /[^arwu\s]/
+ # new format (Tcl/Tk8.4+?)
+ if opts.kind_of?(Array)
+ opt_ary = opts.map{|opt| opt.to_s.strip}
+ else
+ opt_ary = opt_str.split(/\s+|\|/)
+ opt_ary.delete('')
+ end
+ if USE_OLD_TRACE_OPTION_STYLE
+ opt_ary.uniq.map{|opt|
+ case opt
+ when 'array'
+ 'a'
+ when 'read'
+ 'r'
+ when 'write'
+ 'w'
+ when 'unset'
+ 'u'
+ else
+ fail ArgumentError, "unsupported trace option '#{opt}' on Tcl/Tk#{Tk::TCL_PATCHLEVEL}"
+ end
+ }.join
+ else
+ opt_ary
+ end
+ else
+ # old format
+ opt_ary = opt_str.delete('^arwu').split(//).uniq
+ if USE_OLD_TRACE_OPTION_STYLE
+ opt_ary.join
+ else
+ opt_ary.map{|c|
+ case c
+ when 'a'
+ 'array'
+ when 'r'
+ 'read'
+ when 'w'
+ 'write'
+ when 'u'
+ 'unset'
+ end
+ }
+ end
+ end
+ end
+ private :_check_trace_opt
+
def trace(opts, cmd = Proc.new)
- @trace_var = [] if @trace_var == nil
- #opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('')
- opts = opts.to_s
- opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('')
- @trace_var.unshift([opts,cmd])
+ opts = _check_trace_opt(opts)
+ (@trace_var ||= []).unshift([opts,cmd])
+
if @trace_opts == nil
TkVar_CB_TBL[@id] = self
- @trace_opts = opts.dup
- Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts,
- 'rb_var ' << @id)
-=begin
- if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION
- # TCL_VERSION >= 8.4
- Tk.tk_call_without_enc('trace', 'add', 'variable',
- @id, @trace_opts, 'rb_var')
+ @trace_opts = opts
+ if USE_OLD_TRACE_OPTION_STYLE
+ Tk.tk_call_without_enc('trace', 'variable',
+ @id, @trace_opts, 'rb_var ' << @id)
else
- # TCL_VERSION <= 8.3
- Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts, 'rb_var')
+ Tk.tk_call_without_enc('trace', 'add', 'variable',
+ @id, @trace_opts, 'rb_var ' << @id)
end
-=end
else
newopts = @trace_opts.dup
- #opts.each_byte{|c| newopts += c.chr unless newopts.index(c)}
- opts.each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)}
- if newopts != @trace_opts
- Tk.tk_call_without_enc('trace', 'vdelete', @id, @trace_opts,
- 'rb_var ' << @id)
- @trace_opts.replace(newopts)
- Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts,
- 'rb_var ' << @id)
-=begin
- if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION
- # TCL_VERSION >= 8.4
- Tk.tk_call_without_enc('trace', 'remove', 'variable',
- @id, @trace_opts, 'rb_var')
- @trace_opts.replace(newopts)
- Tk.tk_call_without_enc('trace', 'add', 'variable',
- @id, @trace_opts, 'rb_var')
- else
- # TCL_VERSION <= 8.3
+ if USE_OLD_TRACE_OPTION_STYLE
+ opts.each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)}
+ if newopts != @trace_opts
Tk.tk_call_without_enc('trace', 'vdelete',
- @id, @trace_opts, 'rb_var')
+ @id, @trace_opts, 'rb_var ' << @id)
@trace_opts.replace(newopts)
Tk.tk_call_without_enc('trace', 'variable',
- @id, @trace_opts, 'rb_var')
+ @id, @trace_opts, 'rb_var ' << @id)
+ end
+ else
+ newopts |= opts
+ unless (newopts - @trace_opts).empty?
+ Tk.tk_call_without_enc('trace', 'remove', 'variable',
+ @id, @trace_opts, 'rb_var ' << @id)
+ @trace_opts.replace(newopts)
+ Tk.tk_call_without_enc('trace', 'add', 'variable',
+ @id, @trace_opts, 'rb_var ' << @id)
end
-=end
end
end
+
self
end
@@ -1321,65 +1385,54 @@ end
fail(RuntimeError,
"invalid for a TkVariable which denotes an element of Tcl's array")
end
- @trace_elem = {} if @trace_elem == nil
- @trace_elem[elem] = [] if @trace_elem[elem] == nil
- opts = opts.to_s
- opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('')
- @trace_elem[elem].unshift([opts,cmd])
+
+ opts = _check_trace_opt(opts)
+
+ ((@trace_elem ||= {})[elem] ||= []).unshift([opts,cmd])
+
if @trace_opts == nil
TkVar_CB_TBL[@id] = self
- @trace_opts = opts.dup
- Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts,
- 'rb_var ' << @id)
-=begin
- if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION
- # TCL_VERSION >= 8.4
+ @trace_opts = opts
+ if USE_OLD_TRACE_OPTION_STYLE
Tk.tk_call_without_enc('trace', 'add', 'variable',
- @id, @trace_opts, 'rb_var')
+ @id, @trace_opts, 'rb_var ' << @id)
else
- # TCL_VERSION <= 8.3
Tk.tk_call_without_enc('trace', 'variable',
- @id, @trace_opts, 'rb_var')
+ @id, @trace_opts, 'rb_var ' << @id)
end
-=end
else
newopts = @trace_opts.dup
- # opts.each_byte{|c| newopts += c.chr unless newopts.index(c)}
- opts.each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)}
- if newopts != @trace_opts
- Tk.tk_call_without_enc('trace', 'vdelete', @id, @trace_opts,
- 'rb_var ' << @id)
- @trace_opts.replace(newopts)
- Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts,
- 'rb_var ' << @id)
-=begin
- if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION
- # TCL_VERSION >= 8.4
- Tk.tk_call_without_enc('trace', 'remove', 'variable',
- @id, @trace_opts, 'rb_var')
- @trace_opts.replace(newopts)
- Tk.tk_call_without_enc('trace', 'add', 'variable',
- @id, @trace_opts, 'rb_var')
- else
- # TCL_VERSION <= 8.3
+ if USE_OLD_TRACE_OPTION_STYLE
+ opts.each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)}
+ if newopts != @trace_opts
Tk.tk_call_without_enc('trace', 'vdelete',
- @id, @trace_opts, 'rb_var')
+ @id, @trace_opts, 'rb_var ' << @id)
@trace_opts.replace(newopts)
Tk.tk_call_without_enc('trace', 'variable',
- @id, @trace_opts, 'rb_var')
+ @id, @trace_opts, 'rb_var ' << @id)
+ end
+ else
+ newopts |= opts
+ unless (newopts - @trace_opts).empty?
+ Tk.tk_call_without_enc('trace', 'remove', 'variable',
+ @id, @trace_opts, 'rb_var ' << @id)
+ @trace_opts.replace(newopts)
+ Tk.tk_call_without_enc('trace', 'add', 'variable',
+ @id, @trace_opts, 'rb_var ' << @id)
end
-=end
end
end
+
self
end
- def trace_vinfo
+ def trace_info
return [] unless @trace_var
@trace_var.dup
end
+ alias trace_vinfo trace_info
- def _trace_vinfo_for_element(elem)
+ def trace_info_for_element(elem)
if @elem
fail(RuntimeError,
"invalid for a TkVariable which denotes an element of Tcl's array")
@@ -1388,141 +1441,180 @@ end
return [] unless @trace_elem[elem]
@trace_elem[elem].dup
end
+ alias trace_vinfo_for_element trace_info_for_element
- def trace_vdelete(opts,cmd)
+ def trace_remove(opts,cmd)
return self unless @trace_var.kind_of? Array
- opts = opts.to_s
- opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('')
+
+ opts = _check_trace_opt(opts)
+
idx = -1
- newopts = ''
- @trace_var.each_with_index{|e,i|
- if idx < 0 && e[0] == opts && e[1] == cmd
- idx = i
- next
- end
- # e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
- e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)}
- }
+ if USE_OLD_TRACE_OPTION_STYLE
+ newopts = ''
+ @trace_var.each_with_index{|e, i|
+ if idx < 0 && e[1] == cmd
+ diff = false
+ ['a', 'r', 'w', 'u'].each{|c|
+ break if (diff = e[0].index(c) ^ opts.index(c))
+ }
+ unless diff
+ #find
+ idx = i
+ next
+ end
+ end
+ e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)}
+ }
+ else
+ newopts = []
+ @trace_var.each_with_index{|e, i|
+ if idx < 0 && e[1] == cmd &&
+ e[0].size == opts.size && (e[0] - opts).empty?
+ # find
+ idx = i
+ next
+ end
+ newopts |= e[0]
+ }
+ end
+
if idx >= 0
@trace_var.delete_at(idx)
else
return self
end
- @trace_elem.each{|elem|
+ (@trace_elem ||= {}).each{|elem|
@trace_elem[elem].each{|e|
- # e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
- e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)}
+ if USE_OLD_TRACE_OPTION_STYLE
+ e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)}
+ else
+ newopts |= e[0]
+ end
}
}
- newopts = newopts.to_s
- newopts = ['r','w','u'].find_all{|c| newopts.index(c)}.join('')
- if newopts != @trace_opts
- Tk.tk_call_without_enc('trace', 'vdelete', @id, @trace_opts,
- 'rb_var ' << @id)
-=begin
- if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION
- # TCL_VERSION >= 8.4
- Tk.tk_call_without_enc('trace', 'remove', 'variable',
- @id, @trace_opts, 'rb_var')
- else
- # TCL_VERSION <= 8.3
+ if USE_OLD_TRACE_OPTION_STYLE
+ diff = false
+ @trace_opts.each_byte{|c| break if (diff = ! newopts.index(c))}
+ if diff
Tk.tk_call_without_enc('trace', 'vdelete',
- @id, @trace_opts, 'rb_var')
+ @id, @trace_opts, 'rb_var ' << @id)
+ @trace_opts.replace(newopts)
+ unless @trace_opts.empty?
+ Tk.tk_call_without_enc('trace', 'variable',
+ @id, @trace_opts, 'rb_var ' << @id)
+ end
end
-=end
- @trace_opts.replace(newopts)
- if @trace_opts != ''
- Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts,
- 'rb_var ' << @id)
-=begin
- if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION
- # TCL_VERSION >= 8.4
+ else
+ unless (@trace_opts - newopts).empty?
+ Tk.tk_call_without_enc('trace', 'remove', 'variable',
+ @id, @trace_opts, 'rb_var ' << @id)
+ @trace_opts.replace(newopts)
+ unless @trace_opts.empty?
Tk.tk_call_without_enc('trace', 'add', 'variable',
- @id, @trace_opts, 'rb_var')
- else
- # TCL_VERSION <= 8.3
- Tk.tk_call_without_enc('trace', 'variable',
- @id, @trace_opts, 'rb_var')
+ @id, @trace_opts, 'rb_var ' << @id)
end
-=end
end
end
self
end
+ alias trace_delete trace_remove
+ alias trace_vdelete trace_remove
- def trace_vdelete_for_element(elem,opts,cmd)
+ def trace_remove_for_element(elem,opts,cmd)
if @elem
fail(RuntimeError,
"invalid for a TkVariable which denotes an element of Tcl's array")
end
return self unless @trace_elem.kind_of? Hash
return self unless @trace_elem[elem].kind_of? Array
- opts = opts.to_s
- opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('')
+
+ opts = _check_trace_opt(opts)
+
idx = -1
- @trace_elem[elem].each_with_index{|e,i|
- if idx < 0 && e[0] == opts && e[1] == cmd
- idx = i
- next
- end
- }
+ if USE_OLD_TRACE_OPTION_STYLE
+ @trace_elem[elem].each_with_index{|e, i|
+ if idx < 0 && e[1] == cmd
+ diff = false
+ ['a', 'r', 'w', 'u'].each{|c|
+ break if (diff = e[0].index(c) ^ opts.index(c))
+ }
+ unless diff
+ #find
+ idx = i
+ next
+ end
+ end
+ }
+ else
+ @trace_elem[elem].each_with_index{|e, i|
+ if idx < 0 && e[1] == cmd &&
+ e[0].size == opts.size && (e[0] - opts).empty?
+ # find
+ idx = i
+ next
+ end
+ }
+ end
+
if idx >= 0
@trace_elem[elem].delete_at(idx)
else
return self
end
- newopts = ''
- @trace_var.each{|e|
- # e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
- e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)}
- }
- @trace_elem.each{|elem|
- @trace_elem[elem].each{|e|
- # e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
- e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)}
+ if USE_OLD_TRACE_OPTION_STYLE
+ newopts = ''
+ @trace_var.each{|e|
+ e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)}
}
- }
+ @trace_elem.each{|elem|
+ @trace_elem[elem].each{|e|
+ e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)}
+ }
+ }
+ else
+ newopts = []
+ @trace_var.each{|e|
+ newopts |= e[0]
+ }
+ @trace_elem.each{|elem|
+ @trace_elem[elem].each{|e|
+ e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c.chr)}
+ }
+ }
+ end
- newopts = newopts.to_s
- newopts = ['r','w','u'].find_all{|c| newopts.index(c)}.join('')
- if newopts != @trace_opts
- Tk.tk_call_without_enc('trace', 'vdelete', @id, @trace_opts,
- 'rb_var ' << @id)
-=begin
- if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION
- # TCL_VERSION >= 8.4
- Tk.tk_call_without_enc('trace', 'remove', 'variable',
- @id, @trace_opts, 'rb_var')
- else
- # TCL_VERSION <= 8.3
+ if USE_OLD_TRACE_OPTION_STYLE
+ diff = false
+ @trace_opts.each_byte{|c| break if (diff = ! newopts.index(c))}
+ if diff
Tk.tk_call_without_enc('trace', 'vdelete',
- @id, @trace_opts, 'rb_var')
+ @id, @trace_opts, 'rb_var ' << @id)
+ @trace_opts.replace(newopts)
+ unless @trace_opts.empty?
+ Tk.tk_call_without_enc('trace', 'variable',
+ @id, @trace_opts, 'rb_var ' << @id)
+ end
end
-=end
- @trace_opts.replace(newopts)
- if @trace_opts != ''
- Tk.tk_call_without_enc('trace', 'variable', @id, @trace_opts,
- 'rb_var ' << @id)
-=begin
- if /^(8\.([4-9]|[1-9][0-9])|9\.|[1-9][0-9])/ =~ Tk::TCL_VERSION
- # TCL_VERSION >= 8.4
+ else
+ unless (@trace_opts - newopts).empty?
+ Tk.tk_call_without_enc('trace', 'remove', 'variable',
+ @id, @trace_opts, 'rb_var ' << @id)
+ @trace_opts.replace(newopts)
+ unless @trace_opts.empty?
Tk.tk_call_without_enc('trace', 'add', 'variable',
- @id, @trace_opts, 'rb_var')
- else
- # TCL_VERSION <= 8.3
- Tk.tk_call_without_enc('trace', 'variable', @id,
- @trace_opts, 'rb_var')
+ @id, @trace_opts, 'rb_var ' << @id)
end
-=end
end
end
self
end
+ alias trace_delete_for_element trace_remove_for_element
+ alias trace_vdelete_for_element trace_remove_for_element
end
class TkVarAccess<TkVariable
@@ -1532,12 +1624,23 @@ class TkVarAccess<TkVariable
return name
end
- if v = TkVar_ID_TBL[name]
- v.value = args[0] unless args.empty?
- return v
- end
+ name = name.to_s
+ v = nil
+ TkVar_ID_TBL.mutex.synchronize{
+ if v = TkVar_ID_TBL[name]
+ v.value = args[0] unless args.empty?
+ return v
+ else
+ (v = self.allocate).instance_eval{
+ @id = name
+ TkVar_ID_TBL[@id] = self
+ @var = @id
+ }
+ end
+ }
- super(name, *args)
+ v.instance_eval{ initialize(name, *args) }
+ v
end
def self.new_hash(name, *args)
@@ -1549,27 +1652,38 @@ class TkVarAccess<TkVariable
return name
end
- if v = TkVar_ID_TBL[name]
- unless v.is_hash?
- fail ArgumentError, "already exist as a scalar variable"
+ name = name.to_s
+ v = nil
+ TkVar_ID_TBL.mutex.synchronize{
+ if v = TkVar_ID_TBL[name]
+ unless v.is_hash?
+ fail ArgumentError, "already exist as a scalar variable"
+ end
+ v.value = args[0] unless args.empty?
+ return v
+ else
+ (v = self.allocate).instance_eval{
+ @id = name
+ TkVar_ID_TBL[@id] = self
+ @var = @id
+ }
end
- v.value = args[0] unless args.empty?
- return v
- end
+ }
INTERP._invoke_without_enc('global', name)
if args.empty? && INTERP._invoke_without_enc('array', 'exist', name) == '0'
- self.new(name, {}) # force creating
+ v.instance_eval{ initialize(name, {}) } # force creating
else
- self.new(name, *args)
+ v.instance_eval{ initialize(name, *args) }
end
+ v
end
def initialize(varname, val=nil)
- @id = varname
- TkVar_ID_TBL[@id] = self
+ # @id = varname
+ # TkVar_ID_TBL[@id] = self
- @var = @id
+ # @var = @id
@elem = nil
@def_default = false
diff --git a/ext/tk/lib/tk/virtevent.rb b/ext/tk/lib/tk/virtevent.rb
index d47e80aecd..ae31ac1f8f 100644
--- a/ext/tk/lib/tk/virtevent.rb
+++ b/ext/tk/lib/tk/virtevent.rb
@@ -9,10 +9,17 @@ class TkVirtualEvent<TkObject
TkCommandNames = ['event'.freeze].freeze
- TkVirtualEventID = ["VirtEvent".freeze, "00000".taint].freeze
+ (TkVirtualEventID = ["VirtEvent".freeze, "00000".taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
TkVirtualEventTBL = TkCore::INTERP.create_table
- TkCore::INTERP.init_ip_env{ TkVirtualEventTBL.clear }
+ TkCore::INTERP.init_ip_env{
+ TkVirtualEventTBL.mutex.synchronize{ TkVirtualEventTBL.clear }
+ }
class PreDefVirtEvent<self
def self.new(event, *sequences)
@@ -21,22 +28,30 @@ class TkVirtualEvent<TkObject
elsif event !~ /^<.*>$/
event = '<' + event + '>'
end
- if TkVirtualEvent::TkVirtualEventTBL.has_key?(event)
- TkVirtualEvent::TkVirtualEventTBL[event]
- else
- super(event, *sequences)
- end
+ TkVirtualEvent::TkVirtualEventTBL.mutex.synchronize{
+ if TkVirtualEvent::TkVirtualEventTBL.has_key?(event)
+ TkVirtualEvent::TkVirtualEventTBL[event]
+ else
+ # super(event, *sequences)
+ (obj = self.allocate).instance_eval{
+ initialize(event, *sequences)
+ TkVirtualEvent::TkVirtualEventTBL[@id] = self
+ }
+ end
+ }
end
def initialize(event, *sequences)
@path = @id = event
- TkVirtualEvent::TkVirtualEventTBL[@id] = self
- add(*sequences)
+ _add_sequences(sequences)
end
end
def TkVirtualEvent.getobj(event)
- obj = TkVirtualEventTBL[event]
+ obj = nil
+ TkVirtualEventTBL.mutex.synchronize{
+ obj = TkVirtualEventTBL[event]
+ }
if obj
obj
else
@@ -55,19 +70,31 @@ class TkVirtualEvent<TkObject
end
def initialize(*sequences)
- # @path = @id = '<' + TkVirtualEventID.join('') + '>'
- @path = @id = '<' + TkVirtualEventID.join(TkCore::INTERP._ip_id_) + '>'
- TkVirtualEventID[1].succ!
- add(*sequences)
+ TkVirtualEventID.mutex.synchronize{
+ # @path = @id = '<' + TkVirtualEventID.join('') + '>'
+ @path = @id = '<' + TkVirtualEventID.join(TkCore::INTERP._ip_id_) + '>'
+ TkVirtualEventID[1].succ!
+ }
+ _add_sequences(sequences)
end
- def add(*sequences)
- if sequences != []
+ def _add_sequences(seq_ary)
+ unless seq_ary.empty?
tk_call_without_enc('event', 'add', "<#{@id}>",
- *(sequences.collect{|seq|
+ *(seq_ary.collect{|seq|
"<#{tk_event_sequence(seq)}>"
}) )
- TkVirtualEventTBL[@id] = self
+ end
+ self
+ end
+ private :_add_sequences
+
+ def add(*sequences)
+ if sequences != []
+ _add_sequences(sequences)
+ TkVirtualEventTBL.mutex.synchronize{
+ TkVirtualEventTBL[@id] = self
+ }
end
self
end
@@ -75,20 +102,26 @@ class TkVirtualEvent<TkObject
def delete(*sequences)
if sequences == []
tk_call_without_enc('event', 'delete', "<#{@id}>")
- TkVirtualEventTBL.delete(@id)
+ TkVirtualEventTBL.mutex.synchronize{
+ TkVirtualEventTBL.delete(@id)
+ }
else
tk_call_without_enc('event', 'delete', "<#{@id}>",
*(sequences.collect{|seq|
"<#{tk_event_sequence(seq)}>"
}) )
- TkVirtualEventTBL.delete(@id) if info == []
+ if tk_call_without_enc('event','info',"<#{@id}>").empty?
+ TkVirtualEventTBL.mutex.synchronize{
+ TkVirtualEventTBL.delete(@id)
+ }
+ end
end
self
end
def info
tk_call_without_enc('event','info',"<#{@id}>").split(/\s+/).collect!{|seq|
- l = seq.scan(/<*[^<>]+>*/).collect!{|subseq|
+ lst = seq.scan(/<*[^<>]+>*/).collect!{|subseq|
case (subseq)
when /^<<[^<>]+>>$/
TkVirtualEvent.getobj(subseq[1..-2])
@@ -98,7 +131,7 @@ class TkVirtualEvent<TkObject
subseq.split('')
end
}.flatten
- (l.size == 1) ? l[0] : l
+ (lst.size == 1) ? lst[0] : lst
}
end
end
diff --git a/ext/tk/lib/tk/winpkg.rb b/ext/tk/lib/tk/winpkg.rb
index 737fb959b5..89fb391c77 100644
--- a/ext/tk/lib/tk/winpkg.rb
+++ b/ext/tk/lib/tk/winpkg.rb
@@ -7,9 +7,14 @@
#
require 'tk'
-module TkWinDDE
+module Tk::WinDDE
+end
+#TkWinDDE = Tk::WinDDE
+Tk.__set_toplevel_aliases__(:Tk, Tk::WinDDE, :TkWinDDE)
+
+module Tk::WinDDE
extend Tk
- extend TkWinDDE
+ extend Tk::WinDDE
TkCommandNames = ['dde'.freeze].freeze
@@ -85,9 +90,14 @@ module TkWinDDE
:poke, :request, :services, :eval
end
-module TkWinRegistry
+module Tk::WinRegistry
+end
+#TkWinRegistry = Tk::WinRegistry
+Tk.__set_toplevel_aliases__(:Tk, Tk::WinRegistry, :TkWinRegistry)
+
+module Tk::WinRegistry
extend Tk
- extend TkWinRegistry
+ extend Tk::WinRegistry
TkCommandNames = ['registry'.freeze].freeze
diff --git a/ext/tk/lib/tk/wm.rb b/ext/tk/lib/tk/wm.rb
index 1f432a3848..0394296189 100644
--- a/ext/tk/lib/tk/wm.rb
+++ b/ext/tk/lib/tk/wm.rb
@@ -5,273 +5,407 @@ require 'tk'
module Tk
module Wm
- include TkComm
+ #include TkComm
+ extend TkCore
TkCommandNames = ['wm'.freeze].freeze
TOPLEVEL_METHODCALL_OPTKEYS = {}
- def aspect(*args)
+ def Wm.aspect(win, *args)
if args.length == 0
- list(tk_call_without_enc('wm', 'aspect', path))
+ list(tk_call_without_enc('wm', 'aspect', win.epath))
else
args = args[0] if args.length == 1 && args[0].kind_of?(Array)
- tk_call('wm', 'aspect', path, *args)
- self
+ tk_call('wm', 'aspect', win.epath, *args)
+ win
end
end
+ def aspect(*args)
+ Wm.aspect(self, *args)
+ end
+ alias wm_aspect aspect
TOPLEVEL_METHODCALL_OPTKEYS['aspect'] = 'aspect'
- def attributes(slot=nil,value=None)
+ def Wm.attributes(win, slot=nil,value=TkComm::None)
if slot == nil
- lst = tk_split_list(tk_call('wm', 'attributes', path))
+ lst = tk_split_list(tk_call('wm', 'attributes', win.epath))
info = {}
while key = lst.shift
info[key[1..-1]] = lst.shift
end
info
elsif slot.kind_of? Hash
- tk_call('wm', 'attributes', path, *hash_kv(slot))
- self
- elsif value == None
- tk_call('wm', 'attributes', path, "-#{slot}")
+ tk_call('wm', 'attributes', win.epath, *hash_kv(slot))
+ win
+ elsif value == TkComm::None
+ tk_call('wm', 'attributes', win.epath, "-#{slot}")
else
- tk_call('wm', 'attributes', path, "-#{slot}", value)
- self
+ tk_call('wm', 'attributes', win.epath, "-#{slot}", value)
+ win
end
end
+ def attributes(slot=nil,value=TkComm::None)
+ Wm.attributes(self, slot, value)
+ end
+ alias wm_attributes attributes
TOPLEVEL_METHODCALL_OPTKEYS['attributes'] = 'attributes'
- def client(name=None)
- if name == None
- tk_call('wm', 'client', path)
+ def Wm.client(win, name=TkComm::None)
+ if name == TkComm::None
+ tk_call('wm', 'client', win.epath)
else
name = '' if name == nil
- tk_call('wm', 'client', path, name)
- self
+ tk_call('wm', 'client', win.epath, name)
+ win
end
end
+ def client(name=TkComm::None)
+ Wm.client(self, name)
+ end
+ alias wm_client client
TOPLEVEL_METHODCALL_OPTKEYS['client'] = 'client'
- def colormapwindows(*args)
+ def Wm.colormapwindows(win, *args)
if args.size == 0
- list(tk_call_without_enc('wm', 'colormapwindows', path))
+ list(tk_call_without_enc('wm', 'colormapwindows', win.epath))
else
args = args[0] if args.length == 1 && args[0].kind_of?(Array)
- tk_call_without_enc('wm', 'colormapwindows', path, *args)
- self
+ tk_call_without_enc('wm', 'colormapwindows', win.epath, *args)
+ win
end
end
+ def colormapwindows(*args)
+ Wm.colormapwindows(self, *args)
+ end
+ alias wm_colormapwindows colormapwindows
TOPLEVEL_METHODCALL_OPTKEYS['colormapwindows'] = 'colormapwindows'
- def wm_command(value=nil)
+ def Wm.command(win, value=nil)
if value
- tk_call('wm', 'command', path, value)
- self
+ tk_call('wm', 'command', epath, value)
+ win
else
- #procedure(tk_call('wm', 'command', path))
- tk_call('wm', 'command', path)
+ #procedure(tk_call('wm', 'command', epath))
+ tk_call('wm', 'command', epath)
end
end
+ def wm_command(value=nil)
+ Wm.command(self, value)
+ end
TOPLEVEL_METHODCALL_OPTKEYS['wm_command'] = 'wm_command'
- def deiconify(ex = true)
+ def Wm.deiconify(win, ex = true)
if ex
- tk_call_without_enc('wm', 'deiconify', path)
+ tk_call_without_enc('wm', 'deiconify', win.epath)
else
- self.iconify
+ Wm.iconify(win)
end
- self
+ win
end
+ def deiconify(ex = true)
+ Wm.deiconify(self, ex)
+ end
+ alias wm_deiconify deiconify
- def focusmodel(mode = nil)
+ def Wm.focusmodel(win, mode = nil)
if mode
- tk_call_without_enc('wm', 'focusmodel', path, mode)
- self
+ tk_call_without_enc('wm', 'focusmodel', win.epath, mode)
+ win
else
- tk_call_without_enc('wm', 'focusmodel', path)
+ tk_call_without_enc('wm', 'focusmodel', win.epath)
end
end
+ def focusmodel(mode = nil)
+ Wm.focusmodel(self, mode)
+ end
+ alias wm_focusmodel focusmodel
TOPLEVEL_METHODCALL_OPTKEYS['focusmodel'] = 'focusmodel'
+ def Wm.forget(win)
+ # Tcl/Tk 8.5+
+ # work with dockable frames
+ tk_call_without_enc('wm', 'forget', win.epath)
+ win
+ end
+ def wm_forget
+ Wm.forget(self)
+ end
+
+ def Wm.frame(win)
+ tk_call_without_enc('wm', 'frame', win.epath)
+ end
def frame
- tk_call_without_enc('wm', 'frame', path)
+ Wm.frame(self)
end
+ alias wm_frame frame
- def geometry(geom=nil)
+ def Wm.geometry(win, geom=nil)
if geom
- tk_call_without_enc('wm', 'geometry', path, geom)
- self
+ tk_call_without_enc('wm', 'geometry', win.epath, geom)
+ win
else
- tk_call_without_enc('wm', 'geometry', path)
+ tk_call_without_enc('wm', 'geometry', win.epath)
end
end
+ def geometry(geom=nil)
+ Wm.geometry(self, geom)
+ end
+ alias wm_geometry geometry
TOPLEVEL_METHODCALL_OPTKEYS['geometry'] = 'geometry'
- def wm_grid(*args)
+ def Wm.grid(win, *args)
if args.size == 0
- list(tk_call_without_enc('wm', 'grid', path))
+ list(tk_call_without_enc('wm', 'grid', win.epath))
else
args = args[0] if args.length == 1 && args[0].kind_of?(Array)
- tk_call_without_enc('wm', 'grid', path, *args)
- self
+ tk_call_without_enc('wm', 'grid', win.epath, *args)
+ win
end
end
+ def wm_grid(*args)
+ Wm.grid(self, *args)
+ end
TOPLEVEL_METHODCALL_OPTKEYS['wm_grid'] = 'wm_grid'
- def group(leader = nil)
+ def Wm.group(win, leader = nil)
if leader
- tk_call('wm', 'group', path, leader)
- self
+ tk_call('wm', 'group', win.epath, leader)
+ win
else
- window(tk_call('wm', 'group', path))
+ window(tk_call('wm', 'group', win.epath))
end
end
+ def group(leader = nil)
+ Wm.group(self, leader)
+ end
+ alias wm_group group
TOPLEVEL_METHODCALL_OPTKEYS['group'] = 'group'
- def iconbitmap(bmp=nil)
+ def Wm.iconbitmap(win, bmp=nil)
if bmp
- tk_call_without_enc('wm', 'iconbitmap', path, bmp)
- self
+ tk_call_without_enc('wm', 'iconbitmap', win.epath, bmp)
+ win
else
- image_obj(tk_call_without_enc('wm', 'iconbitmap', path))
+ image_obj(tk_call_without_enc('wm', 'iconbitmap', win.epath))
end
end
+ def iconbitmap(bmp=nil)
+ Wm.iconbitmap(self, bmp)
+ end
+ alias wm_iconbitmap iconbitmap
TOPLEVEL_METHODCALL_OPTKEYS['iconbitmap'] = 'iconbitmap'
- def iconphoto(*imgs)
+ def Wm.iconphoto(win, *imgs)
if imgs.empty?
- @wm_iconphoto = nil unless defined? @wm_iconphoto
- return @wm_iconphoto
+ win.instance_eval{
+ @wm_iconphoto = nil unless defined? @wm_iconphoto
+ return @wm_iconphoto
+ }
end
imgs = imgs[0] if imgs.length == 1 && imgs[0].kind_of?(Array)
- tk_call_without_enc('wm', 'iconphoto', path, *imgs)
- @wm_iconphoto = imgs
- self
+ tk_call_without_enc('wm', 'iconphoto', win.epath, *imgs)
+ win.instance_eval{ @wm_iconphoto = imgs }
+ win
+ end
+ def iconphoto(*imgs)
+ Wm.iconphoto(self, *imgs)
end
+ alias wm_iconphoto iconphoto
TOPLEVEL_METHODCALL_OPTKEYS['iconphoto'] = 'iconphoto'
- def iconphoto_default(*imgs)
+ def Wm.iconphoto_default(win, *imgs)
imgs = imgs[0] if imgs.length == 1 && imgs[0].kind_of?(Array)
- tk_call_without_enc('wm', 'iconphoto', path, '-default', *imgs)
- self
+ tk_call_without_enc('wm', 'iconphoto', win.epath, '-default', *imgs)
+ win
+ end
+ def iconphoto_default(*imgs)
+ Wm.iconphoto_default(self, *imgs)
end
+ alias wm_iconphoto_default iconphoto_default
- def iconify(ex = true)
+ def Wm.iconify(win, ex = true)
if ex
- tk_call_without_enc('wm', 'iconify', path)
+ tk_call_without_enc('wm', 'iconify', win.epath)
else
- self.deiconify
+ Wm.deiconify(win)
end
- self
+ win
+ end
+ def iconify(ex = true)
+ Wm.iconify(self, ex)
end
+ alias wm_iconify iconify
- def iconmask(bmp=nil)
+ def Wm.iconmask(win, bmp=nil)
if bmp
- tk_call_without_enc('wm', 'iconmask', path, bmp)
- self
+ tk_call_without_enc('wm', 'iconmask', win.epath, bmp)
+ win
else
- image_obj(tk_call_without_enc('wm', 'iconmask', path))
+ image_obj(tk_call_without_enc('wm', 'iconmask', win.epath))
end
end
+ def iconmask(bmp=nil)
+ Wm.iconmask(self, bmp)
+ end
+ alias wm_iconmask iconmask
TOPLEVEL_METHODCALL_OPTKEYS['iconmask'] = 'iconmask'
- def iconname(name=nil)
+ def Wm.iconname(win, name=nil)
if name
- tk_call('wm', 'iconname', path, name)
- self
+ tk_call('wm', 'iconname', win.epath, name)
+ win
else
- tk_call('wm', 'iconname', path)
+ tk_call('wm', 'iconname', win.epath)
end
end
+ def iconname(name=nil)
+ Wm.iconname(self, name)
+ end
+ alias wm_iconname iconname
TOPLEVEL_METHODCALL_OPTKEYS['iconname'] = 'iconname'
- def iconposition(*args)
+ def Wm.iconposition(win, *args)
if args.size == 0
- list(tk_call_without_enc('wm', 'iconposition', path))
+ list(tk_call_without_enc('wm', 'iconposition', win.epath))
else
args = args[0] if args.length == 1 && args[0].kind_of?(Array)
- tk_call_without_enc('wm', 'iconposition', path, *args)
- self
+ tk_call_without_enc('wm', 'iconposition', win.epath, *args)
+ win
end
end
+ def iconposition(*args)
+ Wm.iconposition(self, *args)
+ end
+ alias wm_iconposition iconposition
TOPLEVEL_METHODCALL_OPTKEYS['iconposition'] = 'iconposition'
- def iconwindow(win = nil)
- if win
- tk_call_without_enc('wm', 'iconwindow', path, win)
- self
+ def Wm.iconwindow(win, iconwin = nil)
+ if iconwin
+ tk_call_without_enc('wm', 'iconwindow', win.epath, iconwin)
+ win
else
- w = tk_call_without_enc('wm', 'iconwindow', path)
+ w = tk_call_without_enc('wm', 'iconwindow', win.epath)
(w == '')? nil: window(w)
end
end
+ def iconwindow(iconwin = nil)
+ Wm.iconwindow(self, iconwin)
+ end
+ alias wm_iconwindow iconwindow
TOPLEVEL_METHODCALL_OPTKEYS['iconwindow'] = 'iconwindow'
- def maxsize(*args)
+ def Wm.manage(win)
+ # Tcl/Tk 8.5+ feature
+ tk_call_without_enc('wm', 'manage', win.epath)
+ win
+ end
+ def wm_manage
+ Wm.manage(self)
+ end
+=begin
+ def Wm.manage(win, use_id = nil)
+ # Tcl/Tk 8.5+ feature
+ # --------------------------------------------------------------
+ # In the future release, I want to support to embed the 'win'
+ # into the container which has window-id 'use-id'.
+ # It may give users frexibility on controlling their GUI.
+ # However, it may be difficult for current Tcl/Tk (Tcl/Tk8.5.1),
+ # because it seems to require to modify Tcl/Tk's source code.
+ # --------------------------------------------------------------
+ if use_id
+ tk_call_without_enc('wm', 'manage', win.epath, '-use', use_id)
+ else
+ tk_call_without_enc('wm', 'manage', win.epath)
+ end
+ win
+ end
+=end
+
+ def Wm.maxsize(win, *args)
if args.size == 0
- list(tk_call_without_enc('wm', 'maxsize', path))
+ list(tk_call_without_enc('wm', 'maxsize', win.epath))
else
args = args[0] if args.length == 1 && args[0].kind_of?(Array)
- tk_call_without_enc('wm', 'maxsize', path, *args)
- self
+ tk_call_without_enc('wm', 'maxsize', win.epath, *args)
+ win
end
end
+ def maxsize(*args)
+ Wm.maxsize(self, *args)
+ end
+ alias wm_maxsize maxsize
TOPLEVEL_METHODCALL_OPTKEYS['maxsize'] = 'maxsize'
- def minsize(*args)
+ def Wm.minsize(win, *args)
if args.size == 0
- list(tk_call_without_enc('wm', 'minsize', path))
+ list(tk_call_without_enc('wm', 'minsize', win.epath))
else
args = args[0] if args.length == 1 && args[0].kind_of?(Array)
- tk_call_without_enc('wm', 'minsize', path, *args)
- self
+ tk_call_without_enc('wm', 'minsize', win.path, *args)
+ win
end
end
+ def minsize(*args)
+ Wm.minsize(self, *args)
+ end
+ alias wm_minsize minsize
TOPLEVEL_METHODCALL_OPTKEYS['minsize'] = 'minsize'
- def overrideredirect(mode=None)
- if mode == None
- bool(tk_call_without_enc('wm', 'overrideredirect', path))
+ def Wm.overrideredirect(win, mode=TkComm::None)
+ if mode == TkComm::None
+ bool(tk_call_without_enc('wm', 'overrideredirect', win.epath))
else
- tk_call_without_enc('wm', 'overrideredirect', path, mode)
- self
+ tk_call_without_enc('wm', 'overrideredirect', win.epath, mode)
+ win
end
end
+ def overrideredirect(mode=TkComm::None)
+ Wm.overrideredirect(self, mode)
+ end
+ alias wm_overrideredirect overrideredirect
TOPLEVEL_METHODCALL_OPTKEYS['overrideredirect'] = 'overrideredirect'
- def positionfrom(who=None)
- if who == None
- r = tk_call_without_enc('wm', 'positionfrom', path)
+ def Wm.positionfrom(win, who=TkComm::None)
+ if who == TkComm::None
+ r = tk_call_without_enc('wm', 'positionfrom', win.epath)
(r == "")? nil: r
else
- tk_call_without_enc('wm', 'positionfrom', path, who)
- self
+ tk_call_without_enc('wm', 'positionfrom', win.epath, who)
+ win
end
end
+ def positionfrom(who=TkComm::None)
+ Wm.positionfrom(self, who)
+ end
+ alias wm_positionfrom positionfrom
TOPLEVEL_METHODCALL_OPTKEYS['positionfrom'] = 'positionfrom'
- def protocol(name=nil, cmd=nil, &b)
+ def Wm.protocol(win, name=nil, cmd=nil, &b)
if cmd
- tk_call_without_enc('wm', 'protocol', path, name, cmd)
- self
+ tk_call_without_enc('wm', 'protocol', win.epath, name, cmd)
+ win
elsif b
- tk_call_without_enc('wm', 'protocol', path, name, proc(&b))
- self
+ tk_call_without_enc('wm', 'protocol', win.epath, name, proc(&b))
+ win
elsif name
- result = tk_call_without_enc('wm', 'protocol', path, name)
+ result = tk_call_without_enc('wm', 'protocol', win.epath, name)
(result == "")? nil : tk_tcl2ruby(result)
else
- tk_split_simplelist(tk_call_without_enc('wm', 'protocol', path))
+ tk_split_simplelist(tk_call_without_enc('wm', 'protocol', win.epath))
end
end
+ def protocol(name=nil, cmd=nil, &b)
+ Wm.protocol(self, name, cmd, &b)
+ end
+ alias wm_protocol protocol
- def protocols(kv=nil)
+ def Wm.protocols(win, kv=nil)
unless kv
ret = {}
- self.protocol.each{|name|
- ret[name] = self.protocol(name)
+ Wm.protocol(win).each{|name|
+ ret[name] = Wm.protocol(win, name)
}
return ret
end
@@ -279,82 +413,140 @@ module Tk
unless kv.kind_of?(Hash)
fail ArgumentError, 'expect a hash of protocol=>command'
end
- kv.each{|k, v| self.protocol(k, v)}
- self
+ kv.each{|k, v| Wm.protocol(win, k, v)}
+ win
end
+ def protocols(kv=nil)
+ Wm.protocols(self, kv)
+ end
+ alias wm_protocols protocols
TOPLEVEL_METHODCALL_OPTKEYS['protocols'] = 'protocols'
- def resizable(*args)
+ def Wm.resizable(win, *args)
if args.length == 0
- list(tk_call_without_enc('wm', 'resizable', path)).collect{|e| bool(e)}
+ list(tk_call_without_enc('wm', 'resizable', win.epath)).map!{|e| bool(e)}
else
args = args[0] if args.length == 1 && args[0].kind_of?(Array)
- tk_call_without_enc('wm', 'resizable', path, *args)
- self
+ tk_call_without_enc('wm', 'resizable', win.epath, *args)
+ win
end
end
+ def resizable(*args)
+ Wm.resizable(self, *args)
+ end
+ alias wm_resizable resizable
TOPLEVEL_METHODCALL_OPTKEYS['resizable'] = 'resizable'
- def sizefrom(who=None)
- if who == None
- r = tk_call_without_enc('wm', 'sizefrom', path)
+ def Wm.sizefrom(win, who=TkComm::None)
+ if who == TkComm::None
+ r = tk_call_without_enc('wm', 'sizefrom', win.epath)
(r == "")? nil: r
else
- tk_call_without_enc('wm', 'sizefrom', path, who)
- self
+ tk_call_without_enc('wm', 'sizefrom', win.epath, who)
+ win
end
end
+ def sizefrom(who=TkComm::None)
+ Wm.sizefrom(self, who)
+ end
+ alias wm_sizefrom sizefrom
TOPLEVEL_METHODCALL_OPTKEYS['sizefrom'] = 'sizefrom'
+ def Wm.stackorder(win)
+ list(tk_call('wm', 'stackorder', win.epath))
+ end
def stackorder
- list(tk_call('wm', 'stackorder', path))
+ Wm.stackorder(self)
end
+ alias wm_stackorder stackorder
- def stackorder_isabove(win)
- bool(tk_call('wm', 'stackorder', path, 'isabove', win))
+ def Wm.stackorder_isabove(win, target)
+ bool(tk_call('wm', 'stackorder', win.epath, 'isabove', target))
+ end
+ def Wm.stackorder_is_above(win, target)
+ Wm.stackorder_isabove(win, target)
+ end
+ def stackorder_isabove(target)
+ Wm.stackorder_isabove(self, target)
end
+ alias stackorder_is_above stackorder_isabove
+ alias wm_stackorder_isabove stackorder_isabove
+ alias wm_stackorder_is_above stackorder_isabove
- def stackorder_isbelow(win)
- bool(tk_call('wm', 'stackorder', path, 'isbelow', win))
+ def Wm.stackorder_isbelow(win, target)
+ bool(tk_call('wm', 'stackorder', win.epath, 'isbelow', target))
end
+ def Wm.stackorder_is_below(win, target)
+ Wm.stackorder_isbelow(win, target)
+ end
+ def stackorder_isbelow(target)
+ Wm.stackorder_isbelow(self, target)
+ end
+ alias stackorder_is_below stackorder_isbelow
+ alias wm_stackorder_isbelow stackorder_isbelow
+ alias wm_stackorder_is_below stackorder_isbelow
- def state(st=nil)
+ def Wm.state(win, st=nil)
if st
- tk_call_without_enc('wm', 'state', path, st)
- self
+ tk_call_without_enc('wm', 'state', win.epath, st)
+ win
else
- tk_call_without_enc('wm', 'state', path)
+ tk_call_without_enc('wm', 'state', win.epath)
end
end
+ def state(st=nil)
+ Wm.state(self, st)
+ end
+ alias wm_state state
TOPLEVEL_METHODCALL_OPTKEYS['state'] = 'state'
- def title(str=nil)
+ def Wm.title(win, str=nil)
if str
- tk_call('wm', 'title', path, str)
- self
+ tk_call('wm', 'title', win.epath, str)
+ win
else
- tk_call('wm', 'title', path)
+ tk_call('wm', 'title', win.epath)
end
end
+ def title(str=nil)
+ Wm.title(self, str)
+ end
+ alias wm_title title
TOPLEVEL_METHODCALL_OPTKEYS['title'] = 'title'
- def transient(master=nil)
+ def Wm.transient(win, master=nil)
if master
- tk_call_without_enc('wm', 'transient', path, master)
- self
+ tk_call_without_enc('wm', 'transient', win.epath, master)
+ win
else
- window(tk_call_without_enc('wm', 'transient', path))
+ window(tk_call_without_enc('wm', 'transient', win.epath))
end
end
+ def transient(master=nil)
+ Wm.transient(self, master)
+ end
+ alias wm_transient transient
TOPLEVEL_METHODCALL_OPTKEYS['transient'] = 'transient'
- def withdraw(ex = true)
+ def Wm.withdraw(win, ex = true)
if ex
- tk_call_without_enc('wm', 'withdraw', path)
+ tk_call_without_enc('wm', 'withdraw', win.epath)
else
- self.deiconify
+ Wm.deiconify(win)
end
- self
+ win
end
+ def withdraw(ex = true)
+ Wm.withdraw(self, ex)
+ end
+ alias wm_withdraw withdraw
+ end
+
+ module Wm_for_General
+ Wm.instance_methods.each{|m|
+ if (m = m.to_s) =~ /^wm_(.*)$/
+ eval "def #{m}(*args, &b); Tk::Wm.#{$1}(self, *args, &b); end"
+ end
+ }
end
end
diff --git a/ext/tk/lib/tkclass.rb b/ext/tk/lib/tkclass.rb
index 355b1a1b1d..87f5acc453 100644
--- a/ext/tk/lib/tkclass.rb
+++ b/ext/tk/lib/tkclass.rb
@@ -3,7 +3,7 @@
# Date: 2000/11/27 09:23:36
# by Yukihiro Matsumoto <matz@caelum.co.jp>
#
-# $Id: tkclass.rb,v 1.6.2.1 2004/10/11 04:51:06 nagai Exp $
+# $Id$
require "tk"
diff --git a/ext/tk/lib/tkextlib/SUPPORT_STATUS b/ext/tk/lib/tkextlib/SUPPORT_STATUS
index 8d7b6fc44a..cfbe274c86 100644
--- a/ext/tk/lib/tkextlib/SUPPORT_STATUS
+++ b/ext/tk/lib/tkextlib/SUPPORT_STATUS
@@ -1,7 +1,7 @@
[ current support status of Tcl/Tk extensions ]
- *******<<< RELEASE_DATE of the libraries : 2005/12/11 >>>*******
+ *** RELEASE_DATE of the libraries => see 'tkextlib/version.rb' ***
The following list shows *CURRENT* status when this file was modifyed
at last. If you want to add other Tcl/Tk extensions to the planed list
@@ -56,23 +56,23 @@ script may give you some hints about that.
===< support with some examples (may be beta quality) >=======================
Tcllib 1.8
-Tklib 0.4.1 http://sf.net/projects/tcllib ==> tcllib
+Tklib 0.4.1 http://sourceforge.net/projects/tcllib ==> tcllib
-IWidgets 4.0.2 http://sf.net/projects/incrTcl ==> iwidgets
+IWidgets 4.0.2 http://sourceforge.net/projects/incrtcl ==> iwidgets
-BWidgets 1.7 http://sf.net/projects/tcllib ==> bwidget
+BWidgets 1.7 http://sourceforge.net/projects/tcllib ==> bwidget
-TkTable 2.9 http://sf.net/projects/tktable ==> tktable
+TkTable 2.9 http://sourceforge.net/projects/tktable ==> tktable
* see also <http://www.korus.hu/~fery/ruby/tktable.rb>
written by Ferenc Engard (ferenc@engard.hu)
-vu 2.3.0 http://tktable.sourceforge.net ==> vu
+vu 2.3.0 http://sourceforge.net/projects/tktable ==> vu
-TkHTML 2.0 http://www.hwaci.com/sw/tkhtml/index.html ==> tkHTML
+TkHTML 2.0 http://www.hwaci.com/sw/tkhtml/ ==> tkHTML
ICONS 1.0 http://www.satisoft.com/tcltk/icons/ ==> ICONS
-TkImg 1.3 http://sf.net/projects/tkimg ==> tkimg
+TkImg 1.3 http://sourceforge.net/projects/tkimg ==> tkimg
BLT 2.4z http://sourceforge.net/projects/blt
@@ -81,20 +81,20 @@ BLT 2.4z http://sourceforge.net/projects/blt
==> blt
TkTreeCtrl CVS/Hd(2005-12-02)
- http://tktreectrl.sourceforge.net/ ==> treectrl
+ http://sourceforge.net/projects/tktreectrl ==> treectrl
-Tile CVS/Hd(2005-12-07)
- http://tktable.sourceforge.net/tile/ ==> tile
+Tile 0.8.0/8.5.1
+ http://sourceforge.net/projects/tktable ==> tile
===< support (may be alpha or beta quality) >=================================
IncrTcl CVS/Hd(2005-02-14)
- http://sf.net/projects/incrTcl ==> itcl, itk
+ http://sourceforge.net/projects/incrtcl ==> itcl, itk
TclX CVS/Hd(2005-02-07)
- http://sf.net/projects/tclx
+ http://sourceforge.net/projects/tclx
==> tclx (partial support; infox command and
XPG/3 message catalogs only)
@@ -105,7 +105,7 @@ Trofs 0.4.3 http://math.nist.gov/~DPorter/tcltk/trofs/
===< possibly available (not tested; alpha quality) >=========================
winico 0.6
- http://tktable.sourceforge.net
+ http://sourceforge.net/projects/tktable
==> winico (win32 only)
TkTrans latest(2004-10-11)
@@ -160,17 +160,17 @@ QuickTimeTcl *** http://hem.fyristorg.com/matben/qt/
===< may not support (already exist, out of Ruby/Tk scope, and so on) >=======
-TkCon *** http://sf.net/projects/tkcon
+TkCon *** http://sourceforge.net/projects/tkcon
-Expect *** http://sf.net/projects/expect
+Expect *** http://sourceforge.net/projects/expect
-TclXML *** http://sf.net/projects/tclxml
+TclXML *** http://sourceforge.net/projects/tclxml
-TclXSLT *** http://sf.net/projects/tclxml
+TclXSLT *** http://sourceforge.net/projects/tclxml
-TclDOM *** http://sf.net/projects/tclxml
+TclDOM *** http://sourceforge.net/projects/tclxml
-TclSOAP *** http://sf.net/projects/tclsoap
+TclSOAP *** http://sourceforge.net/projects/tclsoap
Snack *** http://www.speech.kth.se/~kare/snack2.2.tar.gz
* use Snack for Ruby
@@ -182,7 +182,7 @@ tDOM *** http://www.tdom.org
Mk4tcl *** http://www.equi4.com/metakit/tcl.html
-Memchan *** http://memchan.sourceforge.net/
+Memchan *** http://sourceforge.net/projects/memchan
XOTcl *** http://www.xotcl.org/
diff --git a/ext/tk/lib/tkextlib/blt.rb b/ext/tk/lib/tkextlib/blt.rb
index 8ac8605513..8d58c1f1bc 100644
--- a/ext/tk/lib/tkextlib/blt.rb
+++ b/ext/tk/lib/tkextlib/blt.rb
@@ -26,14 +26,14 @@ module Tk
PATCH_LEVEL = tk_call('set', 'blt_patchLevel')
begin
- lib = INTERP._invoke('set', 'blt_library')
+ lib = TkCore::INTERP._invoke('set', 'blt_library')
rescue
lib = ''
end
LIBRARY = TkVarAccess.new('blt_library', lib)
begin
- lib = INTERP._invoke('set', 'blt_libPath')
+ lib = TkCore::INTERP._invoke('set', 'blt_libPath')
rescue
lib = ''
end
@@ -68,7 +68,7 @@ module Tk
params.concat(hash_kv(args.shift, true)) if args[0].kind_of?(Hash)
- params << '--'
+ params << '--' if args[0] =~ /^\s*-[^-]/
params.concat(args)
tk_call('::blt::bgexec', *params)
@@ -85,7 +85,7 @@ module Tk
params.concat(hash_kv(args.shift, true)) if args[0].kind_of?(Hash)
- params << '--'
+ params << '--' if args[0] =~ /^\s*-[^-]/
params.concat(args)
params << '&'
diff --git a/ext/tk/lib/tkextlib/blt/bitmap.rb b/ext/tk/lib/tkextlib/blt/bitmap.rb
index 31cf8d4229..23c6d2d064 100644
--- a/ext/tk/lib/tkextlib/blt/bitmap.rb
+++ b/ext/tk/lib/tkextlib/blt/bitmap.rb
@@ -13,7 +13,16 @@ module Tk::BLT
TkCommandNames = ['::blt::bitmap'.freeze].freeze
BITMAP_ID_TBL = TkCore::INTERP.create_table
- BITMAP_ID = ['blt_bitmap_id'.freeze, '00000'.taint].freeze
+
+ (BITMAP_ID = ['blt_bitmap_id'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
+ TkCore::INTERP.init_ip_env{
+ BITMAP_ID_TBL.mutex.synchronize{ BITMAP_ID_TBL.clear }
+ }
def self.data(name)
dat = tk_simple_list(tk_call('::blt::bitmap', 'data', name))
@@ -64,9 +73,13 @@ module Tk::BLT
if name
@id = name
else
- @id = BITMAP_ID.join(TkCore::INTERP._ip_id_)
- BITMAP_ID[1].succ!
- BITMAP_ID_TBL[@id] = self
+ BITMAP_ID.mutex.synchronize{
+ @id = BITMAP_ID.join(TkCore::INTERP._ip_id_)
+ BITMAP_ID[1].succ!
+ }
+ BITMAP_ID_TBL.mutex.synchronize{
+ BITMAP_ID_TBL[@id] = self
+ }
end
@path = @id
diff --git a/ext/tk/lib/tkextlib/blt/busy.rb b/ext/tk/lib/tkextlib/blt/busy.rb
index 4726e466f4..2f807fcd9c 100644
--- a/ext/tk/lib/tkextlib/blt/busy.rb
+++ b/ext/tk/lib/tkextlib/blt/busy.rb
@@ -19,7 +19,7 @@ module Tk::BLT
class Shield < TkWindow
def self.shield_path(win)
win = window(win) unless win.kind_of?(TkWindow)
- if win.kind_of?(TkToplevel)
+ if win.kind_of?(Tk::Toplevel)
win.path + '._Busy'
else
win.path + '_Busy'
diff --git a/ext/tk/lib/tkextlib/blt/component.rb b/ext/tk/lib/tkextlib/blt/component.rb
index ad78a5430b..b2005b2f2b 100644
--- a/ext/tk/lib/tkextlib/blt/component.rb
+++ b/ext/tk/lib/tkextlib/blt/component.rb
@@ -85,6 +85,9 @@ module Tk::BLT
def axis_cget(id, option)
ret = itemcget(['axis', tagid(id)], option)
end
+ def axis_cget_strict(id, option)
+ ret = itemcget_strict(['axis', tagid(id)], option)
+ end
def axis_configure(*args)
slot = args.pop
if slot.kind_of?(Hash)
@@ -118,6 +121,9 @@ module Tk::BLT
def crosshairs_cget(option)
itemcget('crosshairs', option)
end
+ def crosshairs_cget_strict(option)
+ itemcget_strict('crosshairs', option)
+ end
def crosshairs_configure(slot, value=None)
itemconfigure('crosshairs', slot, value)
end
@@ -131,6 +137,9 @@ module Tk::BLT
def element_cget(id, option)
itemcget(['element', tagid(id)], option)
end
+ def element_cget_strict(id, option)
+ itemcget_strict(['element', tagid(id)], option)
+ end
def element_configure(*args)
slot = args.pop
if slot.kind_of?(Hash)
@@ -152,6 +161,9 @@ module Tk::BLT
def bar_cget(id, option)
itemcget(['bar', tagid(id)], option)
end
+ def bar_cget_strict(id, option)
+ itemcget_strict(['bar', tagid(id)], option)
+ end
def bar_configure(*args)
slot = args.pop
if slot.kind_of?(Hash)
@@ -173,6 +185,9 @@ module Tk::BLT
def line_cget(id, option)
itemcget(['line', tagid(id)], option)
end
+ def line_cget_strict(id, option)
+ itemcget_strict(['line', tagid(id)], option)
+ end
def line_configure(*args)
slot = args.pop
if slot.kind_of?(Hash)
@@ -194,6 +209,9 @@ module Tk::BLT
def gridline_cget(option)
itemcget('grid', option)
end
+ def gridline_cget_strict(option)
+ itemcget_strict('grid', option)
+ end
def gridline_configure(slot, value=None)
itemconfigure('grid', slot, value)
end
@@ -207,6 +225,9 @@ module Tk::BLT
def legend_cget(option)
itemcget('legend', option)
end
+ def legend_cget_strict(option)
+ itemcget_strict('legend', option)
+ end
def legend_configure(slot, value=None)
itemconfigure('legend', slot, value)
end
@@ -220,6 +241,9 @@ module Tk::BLT
def pen_cget(id, option)
itemcget(['pen', tagid(id)], option)
end
+ def pen_cget_strict(id, option)
+ itemcget_strict(['pen', tagid(id)], option)
+ end
def pen_configure(*args)
slot = args.pop
if slot.kind_of?(Hash)
@@ -241,6 +265,9 @@ module Tk::BLT
def postscript_cget(option)
itemcget('postscript', option)
end
+ def postscript_cget_strict(option)
+ itemcget_strict('postscript', option)
+ end
def postscript_configure(slot, value=None)
itemconfigure('postscript', slot, value)
end
@@ -254,6 +281,9 @@ module Tk::BLT
def marker_cget(id, option)
itemcget(['marker', tagid(id)], option)
end
+ def marker_cget_strict(id, option)
+ itemcget_strict(['marker', tagid(id)], option)
+ end
def marker_configure(*args)
slot = args.pop
if slot.kind_of?(Hash)
@@ -273,11 +303,12 @@ module Tk::BLT
end
alias __itemcget itemcget
+ alias __itemcget_strict itemcget_strict
alias __itemconfiginfo itemconfiginfo
alias __current_itemconfiginfo current_itemconfiginfo
private :__itemcget, :__itemconfiginfo, :__current_itemconfiginfo
- def itemcget(tagOrId, option)
+ def itemcget_strict(tagOrId, option)
ret = __itemcget(tagid(tagOrId), option)
if option == 'bindtags' || option == :bindtags
ret.collect{|tag| TkBindTag.id2obj(tag)}
@@ -285,6 +316,27 @@ module Tk::BLT
ret
end
end
+ def itemcget(tagOrId, option)
+ unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ itemcget_strict(tagOrId, option)
+ else
+ begin
+ itemcget_strict(tagOrId, option)
+ rescue => e
+ begin
+ if current_itemconfiginfo(tagOrId).has_key?(option.to_s)
+ # error on known option
+ fail e
+ else
+ # unknown option
+ nil
+ end
+ rescue
+ fail e # tag error
+ end
+ end
+ end
+ end
def itemconfiginfo(tagOrId, slot = nil)
ret = __itemconfiginfo(tagid(tagOrId), slot)
@@ -321,19 +373,30 @@ module Tk::BLT
ret
end
- private :itemcget, :itemconfigure
- private :itemconfiginfo, :current_itemconfiginfo
+ private :itemcget, :itemcget_strict
+ private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo
#################
class Axis < TkObject
- OBJ_ID = ['blt_chart_axis'.freeze, '00000'.taint].freeze
- OBJ_TBL={}
+ (OBJ_ID = ['blt_chart_axis'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
+ AxisID_TBL = TkCore::INTERP.create_table
+
+ TkCore::INTERP.init_ip_env{
+ AxisID_TBL.mutex.synchronize{ AxisID_TBL.clear }
+ }
def self.id2obj(chart, id)
cpath = chart.path
- return id unless OBJ_TBL[cpath]
- OBJ_TBL[cpath][id]? OBJ_TBL[cpath][id]: id
+ AxisID_TBL.mutex.synchronize{
+ return id unless AxisID_TBL[cpath]
+ AxisID_TBL[cpath][id]? AxisID_TBL[cpath][id]: id
+ }
end
def self.new(chart, axis=nil, keys={})
@@ -341,12 +404,48 @@ module Tk::BLT
keys = axis
axis = nil
end
- OBJ_TBL[chart.path] = {} unless OBJ_TBL[chart.path]
- return OBJ_TBL[chart.path][axis] if axis && OBJ_TBL[chart.path][axis]
- super(chart, axis, keys)
+ if keys
+ keys = _symbolkey2str(keys)
+ not_create = keys.delete('without_creating')
+ else
+ not_create = false
+ end
+
+ obj = nil
+ AxisID_TBL.mutex.synchronize{
+ chart_path = chart.path
+ AxisID_TBL[chart_path] ||= {}
+ if axis && AxisID_TBL[chart_path][axis]
+ obj = AxisID_TBL[chart_path][axis]
+ else
+ (obj = self.allocate).instance_eval{
+ if axis
+ @axis = @id = axis.to_s
+ else
+ OBJ_ID.mutex.synchronize{
+ @axis = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze
+ OBJ_ID[1].succ!
+ }
+ end
+ @path = @id
+ @parent = @chart = chart
+ @cpath = @chart.path
+ Axis::AxisID_TBL[@cpath][@axis] = self
+ unless not_create
+ tk_call(@chart, 'axis', 'create', @axis, keys)
+ return obj
+ end
+ }
+ end
+ }
+
+ obj.configure(keys) if obj && ! keys.empty?
+ obj
end
def initialize(chart, axis=nil, keys={})
+ # dummy:: not called by 'new' method
+
if axis.kind_of?(Hash)
keys = axis
axis = nil
@@ -354,13 +453,15 @@ module Tk::BLT
if axis
@axis = @id = axis.to_s
else
- @axis = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze
- OBJ_ID[1].succ!
+ OBJ_ID.mutex.synchronize{
+ @axis = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze
+ OBJ_ID[1].succ!
+ }
end
@path = @id
@parent = @chart = chart
@cpath = @chart.path
- Axis::OBJ_TBL[@cpath][@axis] = self
+ # Axis::AxisID_TBL[@cpath][@axis] = self
keys = _symbolkey2str(keys)
unless keys.delete('without_creating')
# @chart.axis_create(@axis, keys)
@@ -379,6 +480,9 @@ module Tk::BLT
def cget(option)
@chart.axis_cget(@id, option)
end
+ def cget_strict(option)
+ @chart.axis_cget_strict(@id, option)
+ end
def configure(key, value=None)
@chart.axis_configure(@id, key, value)
self
@@ -438,17 +542,34 @@ module Tk::BLT
#################
class Crosshairs < TkObject
- OBJ_TBL={}
+ CrosshairsID_TBL = TkCore::INTERP.create_table
+
+ TkCore::INTERP.init_ip_env{
+ CrosshairsID_TBL.mutex.synchronize{ CrosshairsID_TBL.clear }
+ }
def self.new(chart, keys={})
- return OBJ_TBL[chart.path] if OBJ_TBL[chart.path]
- super(chart, keys)
+ obj = nil
+ CrosshairsID_TBL.mutex.synchronize{
+ unless (obj = CrosshairsID_TBL[chart.path])
+ (obj = self.allocate).instance_eval{
+ @parent = @chart = chart
+ @cpath = @chart.path
+ @path = @id = 'crosshairs'
+ Crosshairs::CrosshairsID_TBL[@cpath] = self
+ }
+ end
+ }
+ chart.crosshair_configure(keys) if obj && ! keys.empty?
+ obj
end
def initialize(chart, keys={})
+ # dummy:: not called by 'new' method
+
@parent = @chart = chart
@cpath = @chart.path
- Crosshairs::OBJ_TBL[@cpath] = self
+ # Crosshairs::CrosshairsID_TBL[@cpath] = self
@chart.crosshair_configure(keys) unless keys.empty?
@path = @id = 'crosshairs'
end
@@ -464,6 +585,9 @@ module Tk::BLT
def cget(option)
@chart.crosshair_cget(option)
end
+ def cget_strict(option)
+ @chart.crosshair_cget_strict(option)
+ end
def configure(key, value=None)
@chart.crosshair_configure(key, value)
self
@@ -500,12 +624,18 @@ module Tk::BLT
ElementTypeName = 'element'
ElementTypeToClass = { ElementTypeName=>self }
+
ElementID_TBL = TkCore::INTERP.create_table
- TkCore::INTERP.init_ip_env{ ElementID_TBL.clear }
+ TkCore::INTERP.init_ip_env{
+ ElementID_TBL.mutex.synchronize{ ElementID_TBL.clear }
+ }
- OBJ_ID = ['blt_chart_element'.freeze, '00000'.taint].freeze
- OBJ_TBL={}
+ (OBJ_ID = ['blt_chart_element'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
def Element.type2class(type)
ElementTypeToClass[type]
@@ -513,8 +643,10 @@ module Tk::BLT
def Element.id2obj(chart, id)
cpath = chart.path
- return id unless OBJ_TBL[cpath]
- OBJ_TBL[cpath][id]? OBJ_TBL[cpath][id]: id
+ ElementID_TBL.mutex.synchronize{
+ return id unless ElementID_TBL[cpath]
+ ElementID_TBL[cpath][id]? ElementID_TBL[cpath][id]: id
+ }
end
def self.new(chart, element=nil, keys={})
@@ -522,14 +654,49 @@ module Tk::BLT
keys = element
element = nil
end
- OBJ_TBL[chart.path] = {} unless OBJ_TBL[chart.path]
- if element && OBJ_TBL[chart.path][element]
- return OBJ_TBL[chart.path][element]
+ if keys
+ keys = _symbolkey2str(keys)
+ not_create = keys.delete('without_creating')
+ else
+ not_create = false
end
- super(chart, element, keys)
+
+ obj = nil
+ ElementID_TBL.mutex.synchronize{
+ chart_path = chart.path
+ ElementID_TBL[chart_path] ||= {}
+ if element && ElementID_TBL[chart_path][element]
+ obj = ElementID_TBL[chart_path][element]
+ else
+ (obj = self.allocate).instance_eval{
+ if element
+ @element = @id = element.to_s
+ else
+ OBJ_ID.mutex.synchronize{
+ @element = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze
+ OBJ_ID[1].succ!
+ }
+ end
+ @path = @id
+ @parent = @chart = chart
+ @cpath = @chart.path
+ @typename = self.class::ElementTypeName
+ Element::ElementID_TBL[@cpath][@element] = self
+ unless not_create
+ tk_call(@chart, @typename, 'create', @element, keys)
+ return obj
+ end
+ }
+ end
+ }
+
+ obj.configure(keys) if obj && ! keys.empty?
+ obj
end
def initialize(chart, element=nil, keys={})
+ # dummy:: not called by 'new' method
+
if element.kind_of?(Hash)
keys = element
element = nil
@@ -537,14 +704,16 @@ module Tk::BLT
if element
@element = @id = element.to_s
else
- @element = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze
- OBJ_ID[1].succ!
+ OBJ_ID.mutex.synchronize{
+ @element = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze
+ OBJ_ID[1].succ!
+ }
end
@path = @id
@parent = @chart = chart
@cpath = @chart.path
@typename = self.class::ElementTypeName
- Element::OBJ_TBL[@cpath][@element] = self
+ # Element::ElementID_TBL[@cpath][@element] = self
keys = _symbolkey2str(keys)
unless keys.delete('without_creating')
# @chart.element_create(@element, keys)
@@ -564,6 +733,9 @@ module Tk::BLT
# @chart.element_cget(@id, option)
@chart.__send__(@typename + '_cget', @id, option)
end
+ def cget_strict(option)
+ @chart.__send__(@typename + '_cget_strict', @id, option)
+ end
def configure(key, value=None)
# @chart.element_configure(@id, key, value)
@chart.__send__(@typename + '_configure', @id, key, value)
@@ -622,17 +794,33 @@ module Tk::BLT
#################
class GridLine < TkObject
- OBJ_TBL={}
+ GridLineID_TBL = TkCore::INTERP.create_table
+ TkCore::INTERP.init_ip_env{
+ GridLineID_TBL.mutex.synchronize{ GridLineID_TBL.clear }
+ }
def self.new(chart, keys={})
- return OBJ_TBL[chart.path] if OBJ_TBL[chart.path]
- super(chart, keys)
+ obj = nil
+ GridLineID_TBL.mutex.synchronize{
+ unless (obj = GridLineID_TBL[chart.path])
+ (obj = self.allocate).instance_eval{
+ @parent = @chart = chart
+ @cpath = @chart.path
+ @path = @id = 'grid'
+ GridLine::GridLineID_TBL[@cpath] = self
+ }
+ end
+ }
+ chart.gridline_configure(keys) if obj && ! keys.empty?
+ obj
end
def initialize(chart, keys={})
+ # dummy:: not called by 'new' method
+
@parent = @chart = chart
@cpath = @chart.path
- GridLine::OBJ_TBL[@cpath] = self
+ # GridLine::GridLineID_TBL[@cpath] = self
@chart.gridline_configure(keys) unless keys.empty?
@path = @id = 'grid'
end
@@ -648,6 +836,9 @@ module Tk::BLT
def cget(option)
@chart.gridline_cget(option)
end
+ def cget_strict(option)
+ @chart.gridline_cget_strict(option)
+ end
def configure(key, value=None)
@chart.gridline_configure(key, value)
self
@@ -676,18 +867,35 @@ module Tk::BLT
#################
class Legend < TkObject
- OBJ_TBL={}
+ LegendID_TBL = TkCore::INTERP.create_table
+
+ TkCore::INTERP.init_ip_env{
+ LegendID_TBL.mutex.synchronize{ LegendID_TBL.clear }
+ }
def self.new(chart, keys={})
- return OBJ_TBL[chart.path] if OBJ_TBL[chart.path]
- super(chart, keys)
+ obj = nil
+ LegenedID_TBL.mutex.synchronize{
+ unless (obj = LegenedID_TBL[chart.path])
+ (obj = self.allocate).instance_eval{
+ @parent = @chart = chart
+ @cpath = @chart.path
+ @path = @id = 'crosshairs'
+ Legend::LegenedID_TBL[@cpath] = self
+ }
+ end
+ }
+ chart.legend_configure(keys) if obj && ! keys.empty?
+ obj
end
def initialize(chart, keys={})
+ # dummy:: not called by 'new' method
+
@parent = @chart = chart
@cpath = @chart.path
- Crosshairs::OBJ_TBL[@cpath] = self
- @chart.crosshair_configure(keys) unless keys.empty?
+ # Legend::LegendID_TBL[@cpath] = self
+ @chart.legend_configure(keys) unless keys.empty?
@path = @id = 'legend'
end
@@ -702,6 +910,9 @@ module Tk::BLT
def cget(option)
@chart.legend_cget(option)
end
+ def cget_strict(option)
+ @chart.legend_cget_strict(option)
+ end
def configure(key, value=None)
@chart.legend_configure(key, value)
self
@@ -729,13 +940,24 @@ module Tk::BLT
#################
class Pen < TkObject
- OBJ_ID = ['blt_chart_pen'.freeze, '00000'.taint].freeze
- OBJ_TBL={}
+ (OBJ_ID = ['blt_chart_pen'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
+ PenID_TBL = TkCore::INTERP.create_table
+
+ TkCore::INTERP.init_ip_env{
+ PenID_TBL.mutex.synchronize{ PenID_TBL.clear }
+ }
def self.id2obj(chart, id)
cpath = chart.path
- return id unless OBJ_TBL[cpath]
- OBJ_TBL[cpath][id]? OBJ_TBL[cpath][id]: id
+ PenID_TBL.mutex.synchronize{
+ return id unless PenID_TBL[cpath]
+ PenID_TBL[cpath][id]? PenID_TBL[cpath][id]: id
+ }
end
def self.new(chart, pen=nil, keys={})
@@ -743,9 +965,43 @@ module Tk::BLT
keys = pen
pen = nil
end
- OBJ_TBL[chart.path] = {} unless OBJ_TBL[chart.path]
- return OBJ_TBL[chart.path][pen] if pen && OBJ_TBL[chart.path][pen]
- super(chart, pen, keys)
+ if keys
+ keys = _symbolkey2str(keys)
+ not_create = keys.delete('without_creating')
+ else
+ not_create = false
+ end
+
+ obj = nil
+ PenID_TBL.mutex.synchronize{
+ chart_path = chart.path
+ PenID_TBL[chart_path] ||= {}
+ if pen && PenID_TBL[chart_path][pen]
+ obj = PenID_TBL[chart_path][pen]
+ else
+ (obj = self.allocate).instance_eval{
+ if pen
+ @pen = @id = pen.to_s
+ else
+ OBJ_ID.mutex.synchronize{
+ @pen = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze
+ OBJ_ID[1].succ!
+ }
+ end
+ @path = @id
+ @parent = @chart = chart
+ @cpath = @chart.path
+ Pen::PenID_TBL[@cpath][@pen] = self
+ unless not_create
+ tk_call(@chart, 'pen', 'create', @pen, keys)
+ return obj
+ end
+ }
+ end
+ }
+
+ obj.configure(keys) if obj && ! keys.empty?
+ obj
end
def initialize(chart, pen=nil, keys={})
@@ -756,13 +1012,15 @@ module Tk::BLT
if pen
@pen = @id = pen.to_s
else
- @pen = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze
- OBJ_ID[1].succ!
+ OBJ_ID.mutex.synchronize{
+ @pen = @id = OBJ_ID.join(TkCore::INTERP._ip_id_).freeze
+ OBJ_ID[1].succ!
+ }
end
@path = @id
@parent = @chart = chart
@cpath = @chart.path
- Pen::OBJ_TBL[@cpath][@pen] = self
+ Pen::PenID_TBL[@cpath][@pen] = self
keys = _symbolkey2str(keys)
unless keys.delete('without_creating')
# @chart.pen_create(@pen, keys)
@@ -781,6 +1039,9 @@ module Tk::BLT
def cget(option)
@chart.pen_cget(@id, option)
end
+ def cget_strict(option)
+ @chart.pen_cget_strict(@id, option)
+ end
def configure(key, value=None)
@chart.pen_configure(@id, key, value)
self
@@ -805,17 +1066,34 @@ module Tk::BLT
#################
class Postscript < TkObject
- OBJ_TBL={}
+ PostscriptID_TBL = TkCore::INTERP.create_table
+
+ TkCore::INTERP.init_ip_env{
+ PostscriptID_TBL.mutex.synchronize{ PostscriptID_TBL.clear }
+ }
def self.new(chart, keys={})
- return OBJ_TBL[chart.path] if OBJ_TBL[chart.path]
- super(chart, keys)
+ obj = nil
+ PostscriptID_TBL.mutex.synchronize{
+ unless (obj = PostscriptID_TBL[chart.path])
+ (obj = self.allocate).instance_eval{
+ @parent = @chart = chart
+ @cpath = @chart.path
+ @path = @id = 'postscript'
+ Postscript::PostscriptID_TBL[@cpath] = self
+ }
+ end
+ }
+ chart.postscript_configure(keys) if obj && ! keys.empty?
+ obj
end
def initialize(chart, keys={})
+ # dummy:: not called by 'new' method
+
@parent = @chart = chart
@cpath = @chart.path
- Postscript::OBJ_TBL[@cpath] = self
+ # Postscript::PostscriptID_TBL[@cpath] = self
@chart.postscript_configure(keys) unless keys.empty?
@path = @id = 'postscript'
end
@@ -831,6 +1109,9 @@ module Tk::BLT
def cget(option)
@chart.postscript_cget(option)
end
+ def cget_strict(option)
+ @chart.postscript_cget_strict(option)
+ end
def configure(key, value=None)
@chart.postscript_configure(key, value)
self
@@ -870,7 +1151,9 @@ module Tk::BLT
MarkerTypeToClass = {}
MarkerID_TBL = TkCore::INTERP.create_table
- TkCore::INTERP.init_ip_env{ MarkerID_TBL.clear }
+ TkCore::INTERP.init_ip_env{
+ MarkerID_TBL.mutex.synchronize{ MarkerID_TBL.clear }
+ }
def Marker.type2class(type)
MarkerTypeToClass[type]
@@ -878,8 +1161,13 @@ module Tk::BLT
def Marker.id2obj(chart, id)
cpath = chart.path
- return id unless MarkerID_TBL[cpath]
- MarkerID_TBL[cpath][id]? MarkerID_TBL[cpath][id]: id
+ MarkerID_TBL.mutex.synchronize{
+ if MarkerID_TBL[cpath]
+ MarkerID_TBL[cpath][id]? MarkerID_TBL[cpath][id]: id
+ else
+ id
+ end
+ }
end
def self._parse_create_args(keys)
@@ -902,6 +1190,13 @@ module Tk::BLT
fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey)
}
+ __item_optkey_aliases(nil).each{|alias_name, real_name|
+ alias_name = alias_name.to_s
+ if keys.has_key?(alias_name)
+ keys[real_name.to_s] = keys.delete(alias_name)
+ end
+ }
+
__item_methodcall_optkeys(nil).each{|key|
key = key.to_s
methodkeys[key] = keys.delete(key) if keys.key?(key)
@@ -943,10 +1238,10 @@ module Tk::BLT
@parent = @chart = chart
@cpath = chart.path
@id = id
- unless Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath]
- Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] = {}
- end
- Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath][@id] = self
+ Tk::BLT::PlotComponent::Marker::MarkerID_TBL.mutex.synchronize{
+ Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] ||= {}
+ Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath][@id] = self
+ }
}
obj
end
@@ -956,10 +1251,10 @@ module Tk::BLT
@cpath = parent.path
@path = @id = create_self(*args) # an integer number as 'item id'
- unless Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath]
- Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] = {}
- end
- Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath][@id] = self
+ Tk::BLT::PlotComponent::Marker::MarkerID_TBL.mutex.synchronize{
+ Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath] ||= {}
+ Tk::BLT::PlotComponent::Marker::MarkerID_TBL[@cpath][@id] = self
+ }
end
def create_self(*args)
self.class.create(@chart, *args) # return an integer as 'item id'
@@ -977,6 +1272,9 @@ module Tk::BLT
def cget(option)
@chart.marker_cget(@id, option)
end
+ def cget_strict(option)
+ @chart.marker_cget_strict(@id, option)
+ end
def configure(key, value=None)
@chart.marker_configure(@id, key, value)
self
@@ -1037,14 +1335,14 @@ module Tk::BLT
#################
def __destroy_hook__
- Axis::OBJ_TBL.delete(@path)
- Crosshairs::OBJ_TBL.delete(@path)
- Element::OBJ_TBL.delete(@path)
- GridLine::OBJ_TBL.delete(@path)
- Legend::OBJ_TBL.delete(@path)
- Pen::OBJ_TBL.delete(@path)
- Postscript::OBJ_TBL.delete(@path)
- Marker::OBJ_TBL.delete(@path)
+ Axis::AxisID_TBL.delete(@path)
+ Crosshairs::CrosshairsID_TBL.delete(@path)
+ Element::ElementID_TBL.delete(@path)
+ GridLine::GridLineID_TBL.delete(@path)
+ Legend::LegendID_TBL.delete(@path)
+ Pen::PenID_TBL.delete(@path)
+ Postscript::PostscriptID_TBL.delete(@path)
+ Marker::MarkerID_TBL.delete(@path)
super()
end
@@ -1559,6 +1857,9 @@ module Tk::BLT
def xaxis_cget(option)
itemcget('xaxis', option)
end
+ def xaxis_cget_strict(option)
+ itemcget_strict('xaxis', option)
+ end
def xaxis_configure(slot, value=None)
if slot.kind_of?(Hash)
slot = _symbolkey2str(slot)
@@ -1628,6 +1929,9 @@ module Tk::BLT
def x2axis_cget(option)
itemcget('x2axis', option)
end
+ def x2axis_cget_strict(option)
+ itemcget_strict('x2axis', option)
+ end
def x2axis_configure(slot, value=None)
if slot.kind_of?(Hash)
slot = _symbolkey2str(slot)
@@ -1697,6 +2001,9 @@ module Tk::BLT
def yaxis_cget(option)
itemcget('yaxis', option)
end
+ def yaxis_cget_strict(option)
+ itemcget_strict('yaxis', option)
+ end
def yaxis_configure(slot, value=None)
if slot.kind_of?(Hash)
slot = _symbolkey2str(slot)
@@ -1766,6 +2073,9 @@ module Tk::BLT
def y2axis_cget(option)
itemcget('y2axis', option)
end
+ def y2axis_cget_strict(option)
+ itemcget_strict('y2axis', option)
+ end
def y2axis_configure(slot, value=None)
if slot.kind_of?(Hash)
slot = _symbolkey2str(slot)
diff --git a/ext/tk/lib/tkextlib/blt/container.rb b/ext/tk/lib/tkextlib/blt/container.rb
index 60ba1dec1e..cdbec21f25 100644
--- a/ext/tk/lib/tkextlib/blt/container.rb
+++ b/ext/tk/lib/tkextlib/blt/container.rb
@@ -11,18 +11,18 @@ module Tk::BLT
TkCommandNames = ['::blt::container'.freeze].freeze
WidgetClassName = 'Container'.freeze
WidgetClassNames[WidgetClassName] = self
- end
- def __strval_optkeys
- super() << 'name'
- end
- private :__strval_optkeys
+ def __strval_optkeys
+ super() << 'name'
+ end
+ private :__strval_optkeys
- def find_command(pat)
- list(tk_send_without_enc(tk_call(self.path, 'find', '-command', pat)))
- end
+ def find_command(pat)
+ Hash[*simplelist(tk_send_without_enc('find', '-command', pat))]
+ end
- def find_name(pat)
- list(tk_send_without_enc(tk_call(self.path, 'find', '-name', pat)))
+ def find_name(pat)
+ Hash[*simplelist(tk_send_without_enc('find', '-name', pat))]
+ end
end
end
diff --git a/ext/tk/lib/tkextlib/blt/dragdrop.rb b/ext/tk/lib/tkextlib/blt/dragdrop.rb
index 68fb9e591a..201548504a 100644
--- a/ext/tk/lib/tkextlib/blt/dragdrop.rb
+++ b/ext/tk/lib/tkextlib/blt/dragdrop.rb
@@ -81,6 +81,24 @@ module Tk::BLT
nil
]
+=begin
+ # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
+ KEY_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String)
+ end
+ inf
+ }
+
+ PROC_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ end
+ inf
+ }
+=end
+
_setup_subst_table(KEY_TBL, PROC_TBL)
def self.ret_val(val)
@@ -107,6 +125,24 @@ module Tk::BLT
nil
]
+=begin
+ # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
+ KEY_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String)
+ end
+ inf
+ }
+
+ PROC_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ end
+ inf
+ }
+=end
+
_setup_subst_table(KEY_TBL, PROC_TBL)
def self.ret_val(val)
@@ -145,6 +181,24 @@ module Tk::BLT
nil
]
+=begin
+ # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
+ KEY_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String)
+ end
+ inf
+ }
+
+ PROC_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ end
+ inf
+ }
+=end
+
_setup_subst_table(KEY_TBL, PROC_TBL)
end
diff --git a/ext/tk/lib/tkextlib/blt/eps.rb b/ext/tk/lib/tkextlib/blt/eps.rb
index 586a42470c..0dba87a7cc 100644
--- a/ext/tk/lib/tkextlib/blt/eps.rb
+++ b/ext/tk/lib/tkextlib/blt/eps.rb
@@ -14,7 +14,7 @@ module Tk::BLT
end
end
-class TkCanvas
+class Tk::Canvas
alias __BLT_EPS_item_strval_optkeys __item_strval_optkeys
def __item_strval_optkeys(id)
__BLT_EPS_item_strval_optkeys(id) + [
diff --git a/ext/tk/lib/tkextlib/blt/htext.rb b/ext/tk/lib/tkextlib/blt/htext.rb
index a0cf3dc036..0d9cb30185 100644
--- a/ext/tk/lib/tkextlib/blt/htext.rb
+++ b/ext/tk/lib/tkextlib/blt/htext.rb
@@ -22,6 +22,7 @@ module Tk::BLT
WidgetClassNames[WidgetClassName] = self
alias window_cget itemcget
+ alias window_cget_strict itemcget_strict
alias window_configure itemconfigure
alias window_configuinfo itemconfiginfo
alias current_window_configuinfo current_itemconfiginfo
diff --git a/ext/tk/lib/tkextlib/blt/table.rb b/ext/tk/lib/tkextlib/blt/table.rb
index fc1bf54e65..dfa10269ed 100644
--- a/ext/tk/lib/tkextlib/blt/table.rb
+++ b/ext/tk/lib/tkextlib/blt/table.rb
@@ -17,97 +17,103 @@ module Tk::BLT
module TableContainer
def blt_table_add(*args)
- Tk::BLT::Table.add(@path, *args)
+ Tk::BLT::Table.add(self, *args)
self
end
def blt_table_arrange()
- Tk::BLT::Table.arrange(@path)
+ Tk::BLT::Table.arrange(self)
self
end
def blt_table_cget(*args)
- Tk::BLT::Table.cget(@path, *args)
+ Tk::BLT::Table.cget(self, *args)
+ end
+ def blt_table_cget_strict(*args)
+ Tk::BLT::Table.cget_strict(self, *args)
end
def blt_table_configure(*args)
- Tk::BLT::Table.configure(@path, *args)
+ Tk::BLT::Table.configure(self, *args)
self
end
def blt_table_configinfo(*args)
- Tk::BLT::Table.configinfo(@path, *args)
+ Tk::BLT::Table.configinfo(self, *args)
end
def blt_table_current_configinfo(*args)
- Tk::BLT::Table.current_configinfo(@path, *args)
+ Tk::BLT::Table.current_configinfo(self, *args)
end
def blt_table_locate(x, y)
- Tk::BLT::Table.locate(@path, x, y)
+ Tk::BLT::Table.locate(self, x, y)
end
def blt_table_delete(*args)
- Tk::BLT::Table.delete(@path, *args)
+ Tk::BLT::Table.delete(self, *args)
self
end
def blt_table_extents(item)
- Tk::BLT::Table.extents(@path, item)
+ Tk::BLT::Table.extents(self, item)
end
def blt_table_insert(*args)
- Tk::BLT::Table.insert(@path, *args)
+ Tk::BLT::Table.insert(self, *args)
self
end
def blt_table_insert_before(*args)
- Tk::BLT::Table.insert_before(@path, *args)
+ Tk::BLT::Table.insert_before(self, *args)
self
end
def blt_table_insert_after(*args)
- Tk::BLT::Table.insert_after(@path, *args)
+ Tk::BLT::Table.insert_after(self, *args)
self
end
def blt_table_join(first, last)
- Tk::BLT::Table.join(@path, first, last)
+ Tk::BLT::Table.join(self, first, last)
self
end
def blt_table_save()
- Tk::BLT::Table.save(@path)
+ Tk::BLT::Table.save(self)
end
def blt_table_search(*args)
- Tk::BLT::Table.search(@path, *args)
+ Tk::BLT::Table.search(self, *args)
end
def blt_table_split(*args)
- Tk::BLT::Table.split(@path, *args)
+ Tk::BLT::Table.split(self, *args)
self
end
def blt_table_itemcget(*args)
- Tk::BLT::Table.itemcget(@path, *args)
+ Tk::BLT::Table.itemcget(self, *args)
+ end
+ def blt_table_itemcget_strict(*args)
+ Tk::BLT::Table.itemcget_strict(self, *args)
end
def blt_table_itemconfigure(*args)
- Tk::BLT::Table.itemconfigure(@path, *args)
+ Tk::BLT::Table.itemconfigure(self, *args)
self
end
def blt_table_itemconfiginfo(*args)
- Tk::BLT::Table.itemconfiginfo(@path, *args)
+ Tk::BLT::Table.itemconfiginfo(self, *args)
end
def blt_table_current_itemconfiginfo(*args)
- Tk::BLT::Table.current_itemconfiginfo(@path, *args)
+ Tk::BLT::Table.current_itemconfiginfo(self, *args)
end
def blt_table_iteminfo(item)
- Tk::BLT::Table.iteminfo(@path, item)
+ Tk::BLT::Table.iteminfo(self, item)
end
end
end
@@ -117,28 +123,32 @@ end
############################################
class << Tk::BLT::Table
def __item_cget_cmd(id) # id := [ container, item ]
- ['::blt::table', 'cget', id[0].path, id[1]]
+ win = (id[0].kind_of?(TkWindow))? id[0].path: id[0].to_s
+ ['::blt::table', 'cget', win, id[1]]
end
private :__item_cget_cmd
def __item_config_cmd(id) # id := [ container, item, ... ]
container, *items = id
- ['::blt::table', 'configure', container.path, *items]
+ win = (container.kind_of?(TkWindow))? container.path: container.to_s
+ ['::blt::table', 'configure', win, *items]
end
private :__item_config_cmd
def __item_pathname(id)
- id[0].path + ';'
+ win = (id[0].kind_of?(TkWindow))? id[0].path: id[0].to_s
+ win + ';'
end
private :__item_pathname
alias __itemcget itemcget
+ alias __itemcget_strict itemcget_strict
alias __itemconfigure itemconfigure
alias __itemconfiginfo itemconfiginfo
alias __current_itemconfiginfo current_itemconfiginfo
- private :__itemcget, :__itemconfigure
- private :__itemconfiginfo, :__current_itemconfiginfo
+ private :__itemcget, :__itemcget_strict
+ private :__itemconfigure, :__itemconfiginfo, :__current_itemconfiginfo
def __boolval_optkeys
super() << 'propagate'
@@ -173,6 +183,9 @@ class << Tk::BLT::Table
def cget(container, option)
__itemcget([container], option)
end
+ def cget_strict(container, option)
+ __itemcget_strict([container], option)
+ end
def configure(container, *args)
__itemconfigure([container], *args)
@@ -189,11 +202,15 @@ class << Tk::BLT::Table
def itemcget(container, item, option)
__itemcget([container, tagid(item)], option)
end
+ def itemcget_strict(container, item, option)
+ __itemcget_strict([container, tagid(item)], option)
+ end
def itemconfigure(container, *args)
if args[-1].kind_of?(Hash)
# container, item, item, ... , hash_optkeys
keys = args.pop
+ fail ArgumentError, 'no item is given' if args.empty?
id = [container]
args.each{|item| id << tagid(item)}
__itemconfigure(id, keys)
@@ -201,10 +218,12 @@ class << Tk::BLT::Table
# container, item, item, ... , option, value
val = args.pop
opt = args.pop
+ fail ArgumentError, 'no item is given' if args.empty?
id = [container]
args.each{|item| id << tagid(item)}
__itemconfigure(id, opt, val)
end
+ container
end
def itemconfiginfo(container, *args)
@@ -222,11 +241,35 @@ class << Tk::BLT::Table
slot = nil
end
+ fail ArgumentError, 'no item is given' if args.empty?
+
id = [container]
args.each{|item| id << tagid(item)}
__itemconfiginfo(id, slot)
end
+ def current_itemconfiginfo(container, *args)
+ slot = args[-1]
+ if slot.kind_of?(String) || slot.kind_of?(Symbol)
+ slot = slot.to_s
+ if slot[0] == ?. || slot =~ /^\d+,\d+$/ || slot =~ /^(c|C|r|R)(\*|\d+)/
+ # widget || row,col || Ci or Ri
+ slot = nil
+ else
+ # option
+ slot = args.pop
+ end
+ else
+ slot = nil
+ end
+
+ fail ArgumentError, 'no item is given' if args.empty?
+
+ id = [container]
+ args.each{|item| id << tagid(item)}
+ __current_itemconfiginfo(id, slot)
+ end
+
def info(container)
ret = {}
inf = list(tk_call('::blt::table', 'info', container))
@@ -238,12 +281,22 @@ class << Tk::BLT::Table
end
def iteminfo(container, item)
- ret = {}
- inf = list(tk_call('::blt::table', 'info', container, tagid(item)))
- until inf.empty?
- opt = inf.slice!(0..1)
- ret[opt[1..-1]] = opt[1]
+ inf = list(tk_call('::blt::table', 'info', container, tagid(item)).chomp)
+
+ ret = []
+ until inf.empty? || (inf[0].kind_of?(String) && inf[0] =~ /^-/)
+ ret << inf.shift
end
+
+ if inf.length > 1
+ keys = {}
+ while inf.length > 1
+ opt = inf.slice!(0..1)
+ keys[opt[0][1..-1]] = opt[1]
+ end
+ ret << keys
+ end
+
ret
end
@@ -253,7 +306,7 @@ class << Tk::BLT::Table
tk_call('::blt::table', container)
begin
class << container
- include Tk::BLT::TABLE::TableContainer
+ include Tk::BLT::Table::TableContainer
end
rescue
warn('fail to include TableContainer methods (frozen object?)')
@@ -276,10 +329,12 @@ class << Tk::BLT::Table
}
tk_call('::blt::table', container, *args)
end
+ container
end
def arrange(container)
tk_call('::blt::table', 'arrange', container)
+ container
end
def delete(container, *args)
diff --git a/ext/tk/lib/tkextlib/blt/tabset.rb b/ext/tk/lib/tkextlib/blt/tabset.rb
index c26b6ee001..ca81ad8f95 100644
--- a/ext/tk/lib/tkextlib/blt/tabset.rb
+++ b/ext/tk/lib/tkextlib/blt/tabset.rb
@@ -12,14 +12,26 @@ module Tk::BLT
include TkTreatItemFont
TabID_TBL = TkCore::INTERP.create_table
- TabsetTab_ID = ['blt_tabset_tab'.freeze, '00000'.taint].freeze
- TkCore::INTERP.init_ip_env{ TabID_TBL.clear }
+ (TabsetTab_ID = ['blt_tabset_tab'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
+ TkCore::INTERP.init_ip_env{
+ TabID_TBL.mutex.synchronize{ TabID_TBL.clear }
+ }
def self.id2obj(tabset, id)
tpath = tabset.path
- return id unless TabID_TBL[tpath]
- TabID_TBL[tpath][id]? TabID_TBL[tpath]: id
+ TabID_TBL.mutex.synchronize{
+ if TabID_TBL[tpath]
+ TabID_TBL[tpath][id]? TabID_TBL[tpath]: id
+ else
+ id
+ end
+ }
end
def self.new(parent, pos=nil, name=nil, keys={})
@@ -32,12 +44,20 @@ module Tk::BLT
keys = name
name = nil
end
-
- if name && TabID_TBL[parent.path] && TabID_TBL[parent.path][name]
- TabID_TBL[parent.path][name]
- else
- super(parent, pos, name, keys)
- end
+ obj = nil
+ TabID_TBL.mutex.synchronize{
+ if name && TabID_TBL[parent.path] && TabID_TBL[parent.path][name]
+ obj = TabID_TBL[parent.path][name]
+ obj.configure if keys && ! keys.empty?
+ else
+ (obj = self.allocate).instance_eval{
+ initialize(parent, pos, name, keys)
+ TabID_TBL[@tpath] = {} unless TabID_TBL[@tpath]
+ TabID_TBL[@tpath][@id] = self
+ }
+ end
+ }
+ obj
end
def initialize(parent, pos, name, keys)
@@ -45,9 +65,6 @@ module Tk::BLT
@tpath = parent.path
if name
@path = @id = name
- TabID_TBL[@tpath] = {} unless TabID_TBL[@tpath]
- TabID_TBL[@tpath][@id] = self
-
unless (list(tk_call(@tpath, 'tab', 'names', @id)).empty?)
if pos
idx = tk_call(@tpath, 'index', '-name', @id)
@@ -58,18 +75,18 @@ module Tk::BLT
end
end
tk_call(@tpath, 'tab', 'configure', @id, keys)
- return
+ else
+ pos = 'end' unless pos
+ tk_call(@tpath, 'insert', pos, @id, keys)
end
-
else
- @path = @id = TabsetTab_ID.join(TkCore::INTERP._ip_id_)
- TabID_TBL[@tpath] = {} unless TabID_TBL[@tpath]
- TabID_TBL[@tpath][@id] = self
- TabsetTab_ID[1].succ!
+ TabsetTab_ID.mutex.synchronize{
+ @path = @id = TabsetTab_ID.join(TkCore::INTERP._ip_id_)
+ TabsetTab_ID[1].succ!
+ }
+ pos = 'end' unless pos
+ tk_call(@tpath, 'insert', pos, @id, keys)
end
-
- pos = 'end' unless pos
- tk_call(@tpath, 'insert', pos, @id, keys)
end
#def bind(context, cmd=Proc.new, *args)
@@ -111,6 +128,9 @@ module Tk::BLT
def cget(*args)
@t.tab_cget(@id, *args)
end
+ def cget_strict(*args)
+ @t.tab_cget_strict(@id, *args)
+ end
def configure(*args)
@t.tab_configure(@id, *args)
end
@@ -123,7 +143,9 @@ module Tk::BLT
def delete()
@t.delete(@id)
- TabID_TBL[@tpath].delete(@id)
+ TabID_TBL.mutex.synchronize{
+ TabID_TBL[@tpath].delete(@id)
+ }
self
end
@@ -184,7 +206,9 @@ module Tk::BLT
WidgetClassNames[WidgetClassName] = self
def __destroy_hook__
- Tk::BLT::Tabset::Tab::TabID_TBL.delete(@path)
+ Tk::BLT::Tabset::Tab::TabID_TBL.mutex.synchronize{
+ Tk::BLT::Tabset::Tab::TabID_TBL.delete(@path)
+ }
end
########################################
@@ -219,6 +243,7 @@ module Tk::BLT
private :__item_pathname
alias tab_cget itemcget
+ alias tab_cget_strict itemcget_strict
alias tab_configure itemconfigure
alias tab_configinfo itemconfiginfo
alias current_tab_configinfo current_itemconfiginfo
@@ -291,11 +316,15 @@ module Tk::BLT
def delete(first, last=None)
tk_send('delete', tagindex(first), tagindex(last))
if first.kind_of?(Tk::BLT::Tabset::Tab)
- TabID_TBL[@path].delete(first.id)
+ TabID_TBL.mutex.synchronize{
+ TabID_TBL[@path].delete(first.id)
+ }
end
# middle tabs of the range are unknown
if last.kind_of?(Tk::BLT::Tabset::Tab)
- TabID_TBL[@path].delete(last.id)
+ TabID_TBL.mutex.synchronize{
+ TabID_TBL[@path].delete(last.id)
+ }
end
self
end
diff --git a/ext/tk/lib/tkextlib/blt/ted.rb b/ext/tk/lib/tkextlib/blt/ted.rb
index 39495842b4..670265fc78 100644
--- a/ext/tk/lib/tkextlib/blt/ted.rb
+++ b/ext/tk/lib/tkextlib/blt/ted.rb
@@ -30,11 +30,14 @@ module Tk::BLT
end
private :__item_config_cmd
- private :itemcget, :itemconfigure
- private :itemconfiginfo, :current_itemconfiginfo
+ private :itemcget, :itemcget_strict
+ private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo
def cget(master, option)
- itemconfigure(master, slot, value)
+ itemcget(master, option)
+ end
+ def cget_strict(master, option)
+ itemcget_strict(master, option)
end
def configure(master, slot, value=None)
itemconfigure(master, slot, value)
diff --git a/ext/tk/lib/tkextlib/blt/tile/button.rb b/ext/tk/lib/tkextlib/blt/tile/button.rb
index dd715c8b98..2e0863cfbe 100644
--- a/ext/tk/lib/tkextlib/blt/tile/button.rb
+++ b/ext/tk/lib/tkextlib/blt/tile/button.rb
@@ -9,7 +9,7 @@ require 'tkextlib/blt/tile.rb'
module Tk::BLT
module Tile
- class Button < TkButton
+ class Button < Tk::Button
TkCommandNames = ['::blt::tile::button'.freeze].freeze
end
end
diff --git a/ext/tk/lib/tkextlib/blt/tile/checkbutton.rb b/ext/tk/lib/tkextlib/blt/tile/checkbutton.rb
index ebe79179a5..da230b5925 100644
--- a/ext/tk/lib/tkextlib/blt/tile/checkbutton.rb
+++ b/ext/tk/lib/tkextlib/blt/tile/checkbutton.rb
@@ -9,9 +9,9 @@ require 'tkextlib/blt/tile.rb'
module Tk::BLT
module Tile
- class Checkbutton < TkCheckbutton
+ class CheckButton < Tk::CheckButton
TkCommandNames = ['::blt::tile::checkbutton'.freeze].freeze
end
- CheckButton = Checkbutton
+ Checkbutton = CheckButton
end
end
diff --git a/ext/tk/lib/tkextlib/blt/tile/frame.rb b/ext/tk/lib/tkextlib/blt/tile/frame.rb
index 10469fd35f..5434af4b72 100644
--- a/ext/tk/lib/tkextlib/blt/tile/frame.rb
+++ b/ext/tk/lib/tkextlib/blt/tile/frame.rb
@@ -9,7 +9,7 @@ require 'tkextlib/blt/tile.rb'
module Tk::BLT
module Tile
- class Frame < TkFrame
+ class Frame < Tk::Frame
TkCommandNames = ['::blt::tile::frame'.freeze].freeze
end
end
diff --git a/ext/tk/lib/tkextlib/blt/tile/label.rb b/ext/tk/lib/tkextlib/blt/tile/label.rb
index ec67babd58..f370c1403b 100644
--- a/ext/tk/lib/tkextlib/blt/tile/label.rb
+++ b/ext/tk/lib/tkextlib/blt/tile/label.rb
@@ -9,7 +9,7 @@ require 'tkextlib/blt/tile.rb'
module Tk::BLT
module Tile
- class Label < TkLabel
+ class Label < Tk::Label
TkCommandNames = ['::blt::tile::label'.freeze].freeze
end
end
diff --git a/ext/tk/lib/tkextlib/blt/tile/radiobutton.rb b/ext/tk/lib/tkextlib/blt/tile/radiobutton.rb
index 7573aa08d6..814f9a5cc4 100644
--- a/ext/tk/lib/tkextlib/blt/tile/radiobutton.rb
+++ b/ext/tk/lib/tkextlib/blt/tile/radiobutton.rb
@@ -9,9 +9,9 @@ require 'tkextlib/blt/tile.rb'
module Tk::BLT
module Tile
- class Radiobutton < TkRadiobutton
+ class RadioButton < Tk::RadioButton
TkCommandNames = ['::blt::tile::radiobutton'.freeze].freeze
end
- RadioButton = Radiobutton
+ Radiobutton = RadioButton
end
end
diff --git a/ext/tk/lib/tkextlib/blt/tile/scrollbar.rb b/ext/tk/lib/tkextlib/blt/tile/scrollbar.rb
index ba3bf316f0..2ae871d518 100644
--- a/ext/tk/lib/tkextlib/blt/tile/scrollbar.rb
+++ b/ext/tk/lib/tkextlib/blt/tile/scrollbar.rb
@@ -9,7 +9,7 @@ require 'tkextlib/blt/tile.rb'
module Tk::BLT
module Tile
- class Scrollbar < TkScrollbar
+ class Scrollbar < Tk::Scrollbar
TkCommandNames = ['::blt::tile::scrollbar'.freeze].freeze
end
end
diff --git a/ext/tk/lib/tkextlib/blt/tile/toplevel.rb b/ext/tk/lib/tkextlib/blt/tile/toplevel.rb
index 6cc2c91415..76d5f86b1b 100644
--- a/ext/tk/lib/tkextlib/blt/tile/toplevel.rb
+++ b/ext/tk/lib/tkextlib/blt/tile/toplevel.rb
@@ -9,7 +9,7 @@ require 'tkextlib/blt/tile.rb'
module Tk::BLT
module Tile
- class Toplevel < TkToplevel
+ class Toplevel < Tk::Toplevel
TkCommandNames = ['::blt::tile::toplevel'.freeze].freeze
end
end
diff --git a/ext/tk/lib/tkextlib/blt/tree.rb b/ext/tk/lib/tkextlib/blt/tree.rb
index 07dc7ef7e8..77b85f1717 100644
--- a/ext/tk/lib/tkextlib/blt/tree.rb
+++ b/ext/tk/lib/tkextlib/blt/tree.rb
@@ -12,53 +12,77 @@ module Tk::BLT
###################################
- class Node < TkObject
+ class Node < TkObject
TreeNodeID_TBL = TkCore::INTERP.create_table
- TkCore::INTERP.init_ip_env{ TreeNodeID_TBL.clear }
+
+ TkCore::INTERP.init_ip_env{
+ TreeNodeID_TBL.mutex.synchronize{ TreeNodeID_TBL.clear }
+ }
def self.id2obj(tree, id)
tpath = tree.path
- return id unless TreeNodeID_TBL[tpath]
- if TreeNodeID_TBL[tpath][id]
- TreeNodeID_TBL[tpath][id]
- else
- begin
- self.new(tree, nil, 'node'=>Integer(id))
- rescue
+ TreeNodeID_TBL.mutex.synchronize{
+ if TreeNodeID_TBL[tpath]
+ if TreeNodeID_TBL[tpath][id]
+ TreeNodeID_TBL[tpath][id]
+ else
+ begin
+ # self.new(tree, nil, 'node'=>Integer(id))
+ id = Integer(id)
+ if bool(tk_call(@tpath, 'exists', id))
+ (obj = self.allocate).instance_eval{
+ @parent = @tree = tree
+ @tpath = tpath
+ @path = @id = id
+ TreeNodeID_TBL[@tpath] = {} unless TreeNodeID_TBL[@tpath]
+ TreeNodeID_TBL[@tpath][@id] = self
+ }
+ obj
+ else
+ id
+ end
+ rescue
+ id
+ end
+ end
+ else
id
end
- end
+ }
end
def self.new(tree, parent, keys={})
keys = _symbolkey2str(keys)
tpath = tree.path
- if (id = keys['node']) && (obj = TreeNodeID_TBL[tpath][id])
- keys.delete('node')
- tk_call(tree.path, 'move', id, parent, keys) if parent
- return obj
- end
+ TreeNodeID_TBL.mutex.synchronize{
+ TreeNodeID_TBL[tpath] ||= {}
+ if (id = keys['node']) && (obj = TreeNodeID_TBL[tpath][id])
+ keys.delete('node')
+ tk_call(tree.path, 'move', id, parent, keys) if parent
+ return obj
+ end
- super(tree, parent, keys)
+ (obj = self.allocate).instance_eval{
+ initialize(tree, parent, keys)
+ TreeNodeID_TBL[tpath][@id] = self
+ }
+ obj
+ }
end
def initialize(tree, parent, keys={})
@parent = @tree = tree
@tpath = @parent.path
- parent = tk_call(@tpath, 'root') unless parent
-
if (id = keys['node']) && bool(tk_call(@tpath, 'exists', id))
@path = @id = id
keys.delete('node')
tk_call(@tpath, 'move', @id, parent, keys) if parent
else
+ parent = tk_call(@tpath, 'root') unless parent
@path = @id = tk_call(@tpath, 'insert', parent, keys)
end
-
- TreeNodeID_TBL[@tpath] = {} unless TreeNodeID_TBL[@tpath]
- TreeNodeID_TBL[@tpath][@id] = self
end
def id
@@ -243,17 +267,42 @@ module Tk::BLT
class Tag < TkObject
TreeTagID_TBL = TkCore::INTERP.create_table
- TkCore::INTERP.init_ip_env{ TreeTagID_TBL.clear }
- TreeTag_ID = ['blt_tree_tag'.freeze, '00000'.taint].freeze
+
+ TkCore::INTERP.init_ip_env{
+ TreeTagID_TBL.mutex.synchronize{ TreeTagID_TBL.clear }
+ }
+
+ (TreeTag_ID = ['blt_tree_tag'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
def self.id2obj(tree, id)
tpath = tree.path
- return id unless TreeTagID_TBL[tpath]
- if TreeTagID_TBL[tpath][id]
- TreeTagID_TBL[tpath][id]
- else
- self.new(tree, id)
- end
+ TreeTagID_TBL.mutex.synchronize{
+ if TreeTagID_TBL[tpath]
+ if TreeTagID_TBL[tpath][id]
+ TreeTagID_TBL[tpath][id]
+ else
+ begin
+ # self.new(tree, id)
+ (obj = self.allocate).instance_eval{
+ @parent = @tree = tree
+ @tpath = @parent.path
+ @path = @id = id.dup.freeze if id
+ TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath]
+ TreeTagID_TBL[@tpath][@id] = self
+ }
+ obj
+ rescue
+ id
+ end
+ end
+ else
+ id
+ end
+ }
end
def initialize(tree, tag_str = nil)
@@ -263,12 +312,15 @@ module Tk::BLT
if tag_str
@path = @id = tag_str.dup.freeze
else
- @path = @id = TreeTag_ID.join(TkCore::INTERP._ip_id_)
- TreeTagID_TBL[@id] = self
- TreeTag_ID[1].succ!
+ TreeTag_ID.mutex.synchronize{
+ @path = @id = TreeTag_ID.join(TkCore::INTERP._ip_id_)
+ TreeTag_ID[1].succ!
+ }
end
- TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath]
- TreeTagID_TBL[@tpath][@id] = self
+ TreeTagID_TBL.mutex.synchronize{
+ TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath]
+ TreeTagID_TBL[@tpath][@id] = self
+ }
end
def id
@@ -287,7 +339,9 @@ module Tk::BLT
def forget()
tk_call(@tpath, 'tag', 'forget', @id)
- TreeTagID_TBL[@tpath].delete(@id)
+ TreeTagID_TBL.mutex.synchronize{
+ TreeTagID_TBL[@tpath].delete(@id)
+ }
self
end
@@ -312,44 +366,63 @@ module Tk::BLT
class Notify < TkObject
NotifyID_TBL = TkCore::INTERP.create_table
- TkCore::INTERP.init_ip_env{ NotifyID_TBL.clear }
+
+ TkCore::INTERP.init_ip_env{
+ NotifyID_TBL.mutex.synchronize{ NotifyID_TBL.clear }
+ }
def self.id2obj(tree, id)
tpath = tree.path
- return id unless NotifyID_TBL[tpath]
- if NotifyID_TBL[tpath][id]
- NotifyID_TBL[tpath][id]
- else
- begin
- self.new([tree, id])
- rescue
- id
+ NotifyID_TBL.mutex.synchronize{
+ if NotifyID_TBL[tpath]
+ if NotifyID_TBL[tpath][id]
+ NotifyID_TBL[tpath][id]
+ else
+ (obj = self.allocate).instance_eval{
+ @parent = @tree = tree
+ @tpath = @parent.path
+ @path = @id = id
+ NotifyID_TBL[@tpath] ||= {}
+ NotifyID_TBL[@tpath][@id] = self
+ }
+ obj
+ end
+ else
+ return id
end
- end
+ }
end
def self.new(tree, *args, &b)
- if tree.kind_of?(Array)
- # not create
- if obj = NotifyID_TBL[tree[0].path][tree[1]]
+ NotifyID_TBL.mutex.synchronize{
+ if tree.kind_of?(Array)
+ # not create
+ tpath = tree[0].path
+ NotifyID_TBL[tpath] ||= {}
+ unless (obj = NotifyID_TBL[tpath][tree[1]])
+ (NotifyID_TBL[tpath][tree[1]] =
+ obj = self.allocate).instance_eval{
+ @parent = @tree = tree[0]
+ @tpath = @parent.path
+ @path = @id = tree[1]
+ }
+ end
return obj
- else
- return super(false, tree[0], tree[1])
end
- end
- super(true, tree, *args, &b)
+ (obj = self.allocate).instance_eval{
+ initialize(tree, *args, &b)
+ NotifyID_TBL[@tpath] ||= {}
+ NotifyID_TBL[@tpath][@id] = self
+ }
+ return obj
+ }
end
- def initialize(create, tree, *args, &b)
+ def initialize(tree, *args, &b)
@parent = @tree = tree
@tpath = @parent.path
- unless create
- @path = @id = args[0]
- return
- end
-
# if args[0].kind_of?(Proc) || args[0].kind_of?(Method)
if TkComm._callback_entry?(args[0])
cmd = args.shift
@@ -378,7 +451,9 @@ module Tk::BLT
def delete()
tk_call(@tpath, 'notify', 'delete', @id)
- NotifyID_TBL[tpath].delete(@id)
+ NotifyID_TBL.mutex.synchronize{
+ NotifyID_TBL[@tpath].delete(@id)
+ }
self
end
@@ -395,44 +470,69 @@ module Tk::BLT
class Trace < TkObject
TraceID_TBL = TkCore::INTERP.create_table
- TkCore::INTERP.init_ip_env{ TraceID_TBL.clear }
+
+ TkCore::INTERP.init_ip_env{
+ TraceID_TBL.mutex.synchronize{ TraceID_TBL.clear }
+ }
def self.id2obj(tree, id)
tpath = tree.path
- return id unless TraceID_TBL[tpath]
- if TraceID_TBL[tpath][id]
- TraceID_TBL[tpath][id]
- else
- begin
- self.new([tree, id])
- rescue
+ TraceID_TBL.mutex.synchronize{
+ if TraceID_TBL[tpath]
+ if TraceID_TBL[tpath][id]
+ TraceID_TBL[tpath][id]
+ else
+ begin
+ # self.new([tree, id])
+ (obj = self.allocate).instance_eval{
+ @parent = @tree = tree
+ @tpath = @parent.path
+ @path = @id = node # == traceID
+ TraceID_TBL[@tpath] ||= {}
+ TraceID_TBL[@tpath][@id] = self
+ }
+ obj
+ rescue
+ id
+ end
+ end
+ else
id
end
- end
+ }
end
def self.new(tree, *args, &b)
- if tree.kind_of?(Array)
- # not create
- if obj = TraceID_TBL[tree[0].path][tree[1]]
+ TraceID_TBL.mutex.synchronize{
+ if tree.kind_of?(Array)
+ # not create
+ tpath = tree[0].path
+ TraceID_TBL[tpath] ||= {}
+ unless (obj = TraceID_TBL[tpath][tree[1]])
+ (TraceID_TBL[tpath][tree[1]] =
+ obj = self.allocate).instance_eval{
+ @parent = @tree = tree
+ @tpath = @parent.path
+ @path = @id = tree[1] # == traceID
+ }
+ end
return obj
- else
- return super(false, tree[0], tree[1])
end
- end
- super(true, tree, *args, &b)
+ # super(true, tree, *args, &b)
+ (obj = self.allocate).instance_eval{
+ initialize(tree, *args, &b)
+ TraceID_TBL[@tpath] ||= {}
+ TraceID_TBL[@tpath][@id] = self
+ }
+ return obj
+ }
end
- def initialize(create, tree, node, key, opts, cmd=nil, &b)
+ def initialize(tree, node, key, opts, cmd=nil, &b)
@parent = @tree = tree
@tpath = @parent.path
- unless create
- @path = @id = node # == traceID
- return
- end
-
if !cmd
if b
cmd = Proc.new(&b)
@@ -459,7 +559,9 @@ module Tk::BLT
def delete()
tk_call(@tpath, 'trace', 'delete', @id)
- TraceID_TBL[tpath].delete(@id)
+ TraceID_TBL.mutex.synchronize{
+ TraceID_TBL[tpath].delete(@id)
+ }
self
end
@@ -475,7 +577,12 @@ module Tk::BLT
###################################
TreeID_TBL = TkCore::INTERP.create_table
- Tree_ID = ['blt_tree'.freeze, '00000'.taint].freeze
+
+ (Tree_ID = ['blt_tree'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
def __keyonly_optkeys
{
@@ -498,7 +605,9 @@ module Tk::BLT
end
def self.id2obj(id)
- TreeID_TBL[id]? TreeID_TBL[id]: id
+ TreeID_TBL.mutex.synchronize{
+ TreeID_TBL[id]? TreeID_TBL[id]: id
+ }
end
def self.names(pat = None)
@@ -513,27 +622,45 @@ module Tk::BLT
end
def self.new(name = nil)
- return TreeID_TBL[name] if name && TreeID_TBL[name]
- super(name)
+ TreeID_TBL.mutex.synchronize{
+ if name && TreeID_TBL[name]
+ TreeID_TBL[name]
+ else
+ (obj = self.allocate).instance_eval{
+ initialize(name)
+ TreeID_TBL[@id] = self
+ }
+ obj
+ end
+ }
end
def initialzie(name = nil)
if name
@path = @id = name
else
- @path = @id = Tree_ID.join(TkCore::INTERP._ip_id_)
- TreeID_TBL[@id] = self
- Tree_ID[1].succ!
+ Tree_ID.mutex.synchronize{
+ @path = @id = Tree_ID.join(TkCore::INTERP._ip_id_)
+ Tree_ID[1].succ!
+ }
end
- TreeID_TBL[@id] = self
+
tk_call('::blt::tree', 'create', @id)
end
def __destroy_hook__
- Tk::BLT::Tree::Node::TreeNodeID_TBL.delete(@path)
- Tk::BLT::Tree::Tag::TreeTagID_TBL.delete(@path)
- Tk::BLT::Tree::Notify::NotifyID_TBL.delete(@path)
- Tk::BLT::Tree::Trace::TraceID_TBL.delete(@path)
+ Tk::BLT::Tree::Node::TreeNodeID_TBL.mutex.synchronize{
+ Tk::BLT::Tree::Node::TreeNodeID_TBL.delete(@path)
+ }
+ Tk::BLT::Tree::Tag::TreeTagID_TBL.mutex.synchronize{
+ Tk::BLT::Tree::Tag::TreeTagID_TBL.delete(@path)
+ }
+ Tk::BLT::Tree::Notify::NotifyID_TBL.mutex.synchronize{
+ Tk::BLT::Tree::Notify::NotifyID_TBL.delete(@path)
+ }
+ Tk::BLT::Tree::Trace::TraceID_TBL.mutex.synchronize{
+ Tk::BLT::Tree::Trace::TraceID_TBL.delete(@path)
+ }
end
def tagid(tag)
@@ -592,12 +719,14 @@ module Tk::BLT
def delete(*nodes)
tk_call('::blt::tree', 'delete', *(nodes.collect{|node| tagid(node)}))
- nodes.each{|node|
- if node.kind_of?(Tk::BLT::Tree::Node)
- Tk::BLT::Tree::Node::TreeNodeID_TBL[@path].delete(node.id)
- else
- Tk::BLT::Tree::Node::TreeNodeID_TBL[@path].delete(node.to_s)
- end
+ Tk::BLT::Tree::Node::TreeNodeID_TBL.mutex.synchronize{
+ nodes.each{|node|
+ if node.kind_of?(Tk::BLT::Tree::Node)
+ Tk::BLT::Tree::Node::TreeNodeID_TBL[@path].delete(node.id)
+ else
+ Tk::BLT::Tree::Node::TreeNodeID_TBL[@path].delete(node.to_s)
+ end
+ }
}
self
end
@@ -728,7 +857,9 @@ module Tk::BLT
id.delete
else
tk_call(@path, 'notify', 'delete', id)
- Tk::BLT::Tree::Notify::NotifyID_TBL[@path].delete(id.to_s)
+ Tk::BLT::Tree::Notify::NotifyID_TBL.mutex.synchronize{
+ Tk::BLT::Tree::Notify::NotifyID_TBL[@path].delete(id.to_s)
+ }
end
self
end
@@ -835,7 +966,9 @@ module Tk::BLT
def tag_forget(tag)
tag = tag.id if tag.kind_of?(Tk::BLT::Tree::Tag)
tk_call(@path, 'tag', 'forget', tag)
- TreeTagID_TBL[@path].delete(tag)
+ TreeTagID_TBL.mutex.synchronize{
+ TreeTagID_TBL[@path].delete(tag)
+ }
self
end
@@ -889,7 +1022,9 @@ module Tk::BLT
def trace_delete(*args)
args = args.collect{|id| tagid(id)}
tk_call(@path, 'trace', 'delete', *args)
- args.each{|id| Tk::BLT::Tree::Trace::TraceID_TBL[@path].delete(id.to_s)}
+ Tk::BLT::Tree::Trace::TraceID_TBL.mutex.synchronize{
+ args.each{|id| Tk::BLT::Tree::Trace::TraceID_TBL[@path].delete(id.to_s)}
+ }
self
end
diff --git a/ext/tk/lib/tkextlib/blt/treeview.rb b/ext/tk/lib/tkextlib/blt/treeview.rb
index 0343d28b9c..c5a5697186 100644
--- a/ext/tk/lib/tkextlib/blt/treeview.rb
+++ b/ext/tk/lib/tkextlib/blt/treeview.rb
@@ -98,6 +98,9 @@ module Tk::BLT::Treeview::ConfigMethod
def column_cget(name, option)
itemcget(['column', name], option)
end
+ def column_cget_strict(name, option)
+ itemcget_strict(['column', name], option)
+ end
def column_configure(name, slot, value=None)
itemconfigure(['column', name], slot, value)
end
@@ -111,6 +114,9 @@ module Tk::BLT::Treeview::ConfigMethod
def button_cget(option)
itemcget('button', option)
end
+ def button_cget_strict(option)
+ itemcget_strict('button', option)
+ end
def button_configure(slot, value=None)
itemconfigure('button', slot, value)
end
@@ -129,6 +135,14 @@ module Tk::BLT::Treeview::ConfigMethod
ret
end
end
+ def entry_cget_strict(option)
+ ret = itemcget_strict('entry', option)
+ if option == 'bindtags' || option == :bindtags
+ ret.collect{|tag| TkBindTag.id2obj(tag)}
+ else
+ ret
+ end
+ end
def entry_configure(slot, value=None)
itemconfigure('entry', slot, value)
end
@@ -170,6 +184,9 @@ module Tk::BLT::Treeview::ConfigMethod
def sort_cget(option)
itemcget('sort', option)
end
+ def sort_cget_strict(option)
+ itemcget_strict('sort', option)
+ end
def sort_configure(slot, value=None)
itemconfigure('sort', slot, value)
end
@@ -183,6 +200,9 @@ module Tk::BLT::Treeview::ConfigMethod
def text_cget(option)
itemcget('text', option)
end
+ def text_cget_strict(option)
+ itemcget_strict('text', option)
+ end
def text_configure(slot, value=None)
itemconfigure('text', slot, value)
end
@@ -193,8 +213,8 @@ module Tk::BLT::Treeview::ConfigMethod
current_itemconfiginfo('text', slot)
end
- private :itemcget, :itemconfigure
- private :itemconfiginfo, :current_itemconfiginfo
+ private :itemcget, :itemcget_strict
+ private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo
end
class Tk::BLT::Treeview
@@ -239,6 +259,24 @@ class Tk::BLT::Treeview
nil
]
+=begin
+ # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
+ KEY_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String)
+ end
+ inf
+ }
+
+ PROC_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ end
+ inf
+ }
+=end
+
_setup_subst_table(KEY_TBL, PROC_TBL);
def self.ret_val(val)
@@ -273,8 +311,12 @@ class Tk::BLT::Treeview
########################
def __destroy_hook__
- Tk::BLT::Treeview::Node::TreeNodeID_TBL.delete(@path)
- Tk::BLT::Treeview::Tag::TreeTagID_TBL.delete(@path)
+ Tk::BLT::Treeview::Node::TreeNodeID_TBL.mutex.synchronize{
+ Tk::BLT::Treeview::Node::TreeNodeID_TBL.delete(@path)
+ }
+ Tk::BLT::Treeview::Tag::TreeTagID_TBL.mutex.synchronize{
+ Tk::BLT::Treeview::Tag::TreeTagID_TBL.delete(@path)
+ }
end
def tagid(tag)
@@ -472,6 +514,24 @@ class Tk::BLT::Treeview
nil
]
+=begin
+ # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
+ KEY_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String)
+ end
+ inf
+ }
+
+ PROC_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ end
+ inf
+ }
+=end
+
_setup_subst_table(KEY_TBL, PROC_TBL);
def self.ret_val(val)
@@ -487,7 +547,8 @@ class Tk::BLT::Treeview
def _find_exec_flag_value(val)
if val.kind_of?(Array)
cmd, *args = val
- FindExecFlagValue.new(cmd, args.join(' '))
+ #FindExecFlagValue.new(cmd, args.join(' '))
+ FindExecFlagValue.new(cmd, *args)
elsif TkComm._callback_entry?(val)
FindExecFlagValue.new(val)
else
@@ -967,22 +1028,47 @@ class Tk::BLT::Treeview::Node < TkObject
include Tk::BLT::Treeview::TagOrID_Methods
TreeNodeID_TBL = TkCore::INTERP.create_table
- TreeNode_ID = ['blt_treeview_node'.freeze, '00000'.taint].freeze
- TkCore::INTERP.init_ip_env{ TreeNodeID_TBL.clear }
+ (TreeNode_ID = ['blt_treeview_node'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
+ TkCore::INTERP.init_ip_env{
+ TreeNodeID_TBL.mutex.synchronize{ TreeNodeID_TBL.clear }
+ }
def self.id2obj(tree, id)
tpath = tree.path
- return id unless TreeNodeID_TBL[tpath]
- if TreeNodeID_TBL[tpath][id]
- TreeNodeID_TBL[tpath][id]
- else
- begin
- self.new(tree, nil, nil, 'node'=>Integer(id))
- rescue
+ TreeNodeID_TBL.mutex.synchronize{
+ if TreeNodeID_TBL[tpath]
+ if TreeNodeID_TBL[tpath][id]
+ TreeNodeID_TBL[tpath][id]
+ else
+ begin
+ # self.new(tree, nil, nil, 'node'=>Integer(id))
+ unless (tk_call(@tpath, 'get', id)).empty?
+ id = Integer(id)
+ (obj = self.allocate).instance_eval{
+ @parent = @tree = tree
+ @tpath = @parent.path
+ @path = @id = id
+ TreeNodeID_TBL[@tpath] ||= {}
+ TreeNodeID_TBL[@tpath][@id] = self
+ }
+ obj
+ else
+ id
+ end
+ rescue
+ id
+ end
+ end
+ else
id
end
- end
+ }
end
def self.new(tree, pos, parent=nil, keys={})
@@ -994,13 +1080,21 @@ class Tk::BLT::Treeview::Node < TkObject
keys = _symbolkey2str(keys)
tpath = tree.path
- if (id = keys['node']) && (obj = TreeNodeID_TBL[tpath][id])
- keys.delete('node')
- tk_call(tree.path, 'move', id, pos, parent) if parent
- return obj
- end
+ TreeNodeID_TBL.mutex.synchronize{
+ TreeNodeID_TBL[tpath] ||= {}
+ if (id = keys['node']) && (obj = TreeNodeID_TBL[tpath][id])
+ keys.delete('node')
+ tk_call(tree.path, 'move', id, pos, parent) if parent
+ return obj
+ end
- super(tree, pos, parent, keys)
+ #super(tree, pos, parent, keys)
+ (obj = self.allocate).instance_eval{
+ initialize(tree, pos, parent, keys)
+ TreeNodeID_TBL[tpath][@id] = self
+ }
+ obj
+ }
end
def initialize(tree, pos, parent, keys)
@@ -1008,11 +1102,18 @@ class Tk::BLT::Treeview::Node < TkObject
@tpath = @parent.path
if (id = keys['node'])
+ # if tk_call(@tpath, 'get', id).empty?
+ # fail RuntimeError, "not exist the node '#{id}'"
+ # end
@path = @id = id
tk_call(@tpath, 'move', @id, pos, tagid(parent)) if parent
+ configure(keys) if keys && ! keys.empty?
else
- name = TreeNode_ID.join(TkCore::INTERP._ip_id_).freeze
- TreeNode_ID[1].succ!
+ name = nil
+ TreeNode_ID.mutex.synchronize{
+ name = TreeNode_ID.join(TkCore::INTERP._ip_id_).freeze
+ TreeNode_ID[1].succ!
+ }
at = keys.delete['at']
@@ -1035,9 +1136,6 @@ class Tk::BLT::Treeview::Node < TkObject
end
@path = @id
end
-
- TreeNodeID_TBL[@tpath] = {} unless TreeNodeID_TBL[@tpath]
- TreeNodeID_TBL[@tpath][@id] = self
end
def id
@@ -1051,37 +1149,66 @@ class Tk::BLT::Treeview::Tag < TkObject
include Tk::BLT::Treeview::TagOrID_Methods
TreeTagID_TBL = TkCore::INTERP.create_table
- TreeTag_ID = ['blt_treeview_tag'.freeze, '00000'.taint].freeze
- TkCore::INTERP.init_ip_env{ TreeTagID_TBL.clear }
+ (TreeTag_ID = ['blt_treeview_tag'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
- def self.id2obj(tree, id)
+ TkCore::INTERP.init_ip_env{
+ TreeTagID_TBL.mutex.synchronize{ TreeTagID_TBL.clear }
+ }
+
+ def self.id2obj(tree, name)
tpath = tree.path
- return id unless TreeTagID_TBL[tpath]
- if TreeTagID_TBL[tpath][id]
- TreeTagID_TBL[tpath][id]
- else
- begin
- self.new(tree, nil, nil, 'name'=>Integer(id))
- rescue
+ TreeTagID_TBL.mutex.synchronize{
+ if TreeTagID_TBL[tpath]
+ if TreeTagID_TBL[tpath][name]
+ TreeTagID_TBL[tpath][name]
+ else
+ #self.new(tree, name)
+ (obj = self.allocate).instance_eval{
+ @parent = @tree = tree
+ @tpath = @parent.path
+ @path = @id = name
+ TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath]
+ TreeTagID_TBL[@tpath][@id] = self
+ }
+ obj
+ end
+ else
id
end
- end
+ }
end
def self.new_by_name(tree, name, *ids)
- if (obj = TreeTagID_TBL[tree.path][name])
- return obj
- end
- new([tree, name], ids)
+ TreeTagID_TBL.mutex.synchronize{
+ unless (obj = TreeTagID_TBL[tree.path][name])
+ (obj = self.allocate).instance_eval{
+ initialize(tree, name, ids)
+ TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath]
+ TreeTagID_TBL[@tpath][@id] = self
+ }
+ end
+ obj
+ }
end
def self.new(tree, *ids)
- if tree.kind_of?(Array)
- super(tree[0], tree[1], ids)
- else
- super(tree, nil, ids)
- end
+ TreeTagID_TBL.mutex.synchronize{
+ (obj = self.allocate).instance_eval{
+ if tree.kind_of?(Array)
+ initialize(tree[0], tree[1], ids)
+ else
+ initialize(tree, nil, ids)
+ end
+ TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath]
+ TreeTagID_TBL[@tpath][@id] = self
+ }
+ obj
+ }
end
def initialize(tree, name, ids)
@@ -1091,13 +1218,12 @@ class Tk::BLT::Treeview::Tag < TkObject
if name
@path = @id = name
else
- @path = @id = TreeTag_ID.join(TkCore::INTERP._ip_id_).freeze
- TreeTag_ID[1].succ!
+ TreeTag_ID.mutex.synchronize{
+ @path = @id = TreeTag_ID.join(TkCore::INTERP._ip_id_).freeze
+ TreeTag_ID[1].succ!
+ }
end
- TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath]
- TreeTagID_TBL[@tpath][@id] = self
-
unless ids.empty?
tk_call(@tpath, 'tag', 'add', @id, *(ids.collect{|id| tagid(id)}))
end
diff --git a/ext/tk/lib/tkextlib/blt/unix_dnd.rb b/ext/tk/lib/tkextlib/blt/unix_dnd.rb
index 3130c1e56f..445002d7a5 100644
--- a/ext/tk/lib/tkextlib/blt/unix_dnd.rb
+++ b/ext/tk/lib/tkextlib/blt/unix_dnd.rb
@@ -30,11 +30,14 @@ module Tk::BLT
end
private :__item_config_cmd
- private :itemcget, :itemconfigure
- private :itemconfiginfo, :current_itemconfiginfo
+ private :itemcget, :itemcget_strict
+ private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo
def cget(win, option)
- itemconfigure(['cget', win], slot, value)
+ itemcget(['cget', win], option)
+ end
+ def cget_strict(win, option)
+ itemcget_strict(['cget', win], option)
end
def configure(win, slot, value=None)
itemconfigure(['configure', win], slot, value)
@@ -46,8 +49,11 @@ module Tk::BLT
current_itemconfiginfo(['configure', win], slot)
end
- def tokwn_cget(win, option)
- itemconfigure(['token', 'cget', win], slot, value)
+ def token_cget(win, option)
+ itemcget(['token', 'cget', win], option)
+ end
+ def token_cget_strict(win, option)
+ itemcget_strict(['token', 'cget', win], option)
end
def token_configure(win, slot, value=None)
itemconfigure(['token', 'configure', win], slot, value)
diff --git a/ext/tk/lib/tkextlib/blt/vector.rb b/ext/tk/lib/tkextlib/blt/vector.rb
index 540b6b9102..97fb1b96ff 100644
--- a/ext/tk/lib/tkextlib/blt/vector.rb
+++ b/ext/tk/lib/tkextlib/blt/vector.rb
@@ -23,14 +23,17 @@ module Tk::BLT
end
def self.names(pat=None)
- simplelist(tk_call('::blt::vector', 'names', pat)).collect{|name|
- if TkVar_ID_TBL[name]
- TkVar_ID_TBL[name]
- elsif name[0..1] == '::' && TkVar_ID_TBL[name[2..-1]]
- TkVar_ID_TBL[name[2..-1]]
- else
- name
- end
+ list = simplelist(tk_call('::blt::vector', 'names', pat))
+ TkVar_ID_TBL.mutex.synchronize{
+ list.collect{|name|
+ if TkVar_ID_TBL[name]
+ TkVar_ID_TBL[name]
+ elsif name[0..1] == '::' && TkVar_ID_TBL[name[2..-1]]
+ TkVar_ID_TBL[name[2..-1]]
+ else
+ name
+ end
+ }
}
end
@@ -46,14 +49,16 @@ module Tk::BLT
size = size.join(':')
end
if size
- @id = INTERP._invoke('::blt::vector', 'create',
- "#auto(#{size})", *hash_kv(keys))
+ @id = TkCore::INTERP._invoke('::blt::vector', 'create',
+ "#auto(#{size})", *hash_kv(keys))
else
- @id = INTERP._invoke('::blt::vector', 'create',
- "#auto", *hash_kv(keys))
+ @id = TkCore::INTERP._invoke('::blt::vector', 'create',
+ "#auto", *hash_kv(keys))
end
- TkVar_ID_TBL[@id] = self
+ TkVar_ID_TBL.mutex.synchronize{
+ TkVar_ID_TBL[@id] = self
+ }
@def_default = false
@default_val = nil
@@ -63,7 +68,7 @@ module Tk::BLT
@trace_opts = nil
# teach Tk-ip that @id is global var
- INTERP._invoke_without_enc('global', @id)
+ TkCore::INTERP._invoke_without_enc('global', @id)
end
def destroy
@@ -221,13 +226,21 @@ module Tk::BLT
class VectorAccess < Vector
def self.new(name)
- return TkVar_ID_TBL[name] if TkVar_ID_TBL[name]
- super(name, size=nil, keys={})
+ TkVar_ID_TBL.mutex.synchronize{
+ if TkVar_ID_TBL[name]
+ TkVar_ID_TBL[name]
+ else
+ (obj = self.allocate).instance_eval{
+ initialize(name)
+ TkVar_ID_TBL[@id] = self
+ }
+ obj
+ end
+ }
end
def initialize(vec_name)
@id = vec_name
- TkVar_ID_TBL[@id] = self
@def_default = false
@default_val = nil
@@ -237,7 +250,7 @@ module Tk::BLT
@trace_opts = nil
# teach Tk-ip that @id is global var
- INTERP._invoke_without_enc('global', @id)
+ TkCore::INTERP._invoke_without_enc('global', @id)
end
end
end
diff --git a/ext/tk/lib/tkextlib/blt/watch.rb b/ext/tk/lib/tkextlib/blt/watch.rb
index ae5e50f126..219ff78e97 100644
--- a/ext/tk/lib/tkextlib/blt/watch.rb
+++ b/ext/tk/lib/tkextlib/blt/watch.rb
@@ -13,11 +13,23 @@ module Tk::BLT
TkCommandNames = ['::blt::watch'.freeze].freeze
WATCH_ID_TBL = TkCore::INTERP.create_table
- BLT_WATCH_ID = ['blt_watch_id'.freeze, '00000'.taint].freeze
+
+ (BLT_WATCH_ID = ['blt_watch_id'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
+ TkCore::INTERP.init_ip_env{
+ WATCH_ID_TBL.mutex.synchronize{ WATCH_ID_TBL.clear }
+ }
def self.names(state = None)
- tk_split_list(tk_call('::blt::watch', 'names', state)).collect{|name|
- WATCH_ID_TBL[name] || name
+ lst = tk_split_list(tk_call('::blt::watch', 'names', state))
+ WATCH_ID_TBL.mutex.synchronize{
+ lst.collect{|name|
+ WATCH_ID_TBL[name] || name
+ }
}
end
@@ -45,13 +57,17 @@ module Tk::BLT
if name
@id = name.to_s
else
- @id = BLT_WATCH_ID.join(TkCore::INTERP._ip_id_)
- BLT_WATCH_ID[1].succ!
+ BLT_WATCH_ID.mutex.synchronize{
+ @id = BLT_WATCH_ID.join(TkCore::INTERP._ip_id_)
+ BLT_WATCH_ID[1].succ!
+ }
end
@path = @id
- WATCH_ID_TBL[@id] = self
+ WATCH_ID_TBL.mutex.synchronize{
+ WATCH_ID_TBL[@id] = self
+ }
tk_call('::blt::watch', 'create', @id, *hash_kv(keys))
end
@@ -130,7 +146,7 @@ module Tk::BLT
end
end
end
- def cget(key)
+ def cget_strict(key)
key = key.to_s
begin
info.assoc(key)[1]
@@ -138,5 +154,22 @@ module Tk::BLT
fail ArgumentError, "unknown option '#{key}'"
end
end
+ def cget(key)
+ unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ cget_strict(key)
+ else
+ begin
+ cget_strict(key)
+ rescue => e
+ if current_configinfo.has_key?(key.to_s)
+ # error on known option
+ fail e
+ else
+ # unknown option
+ nil
+ end
+ end
+ end
+ end
end
end
diff --git a/ext/tk/lib/tkextlib/bwidget/button.rb b/ext/tk/lib/tkextlib/bwidget/button.rb
index 4a9d4a7948..8f3087d098 100644
--- a/ext/tk/lib/tkextlib/bwidget/button.rb
+++ b/ext/tk/lib/tkextlib/bwidget/button.rb
@@ -9,7 +9,7 @@ require 'tkextlib/bwidget.rb'
module Tk
module BWidget
- class Button < TkButton
+ class Button < Tk::Button
end
end
end
diff --git a/ext/tk/lib/tkextlib/bwidget/buttonbox.rb b/ext/tk/lib/tkextlib/bwidget/buttonbox.rb
index ef999239f9..8d6d212189 100644
--- a/ext/tk/lib/tkextlib/bwidget/buttonbox.rb
+++ b/ext/tk/lib/tkextlib/bwidget/buttonbox.rb
@@ -31,7 +31,7 @@ class Tk::BWidget::ButtonBox
name = tagOrId[:name]
return index(name) unless name.empty?
end
- if tagOrId.kind_of?(TkButton)
+ if tagOrId.kind_of?(Tk::Button)
return index(tagOrId[:text])
end
# index(tagOrId.to_s)
@@ -40,7 +40,13 @@ class Tk::BWidget::ButtonBox
def add(keys={}, &b)
win = window(tk_send('add', *hash_kv(keys)))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
@@ -54,7 +60,7 @@ class Tk::BWidget::ButtonBox
name = idx[:name]
idx = name unless name.empty?
end
- if idx.kind_of?(TkButton)
+ if idx.kind_of?(Tk::Button)
idx = idx[:text]
end
number(tk_send('index', idx.to_s))
@@ -62,7 +68,13 @@ class Tk::BWidget::ButtonBox
def insert(idx, keys={}, &b)
win = window(tk_send('insert', tagid(idx), *hash_kv(keys)))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
diff --git a/ext/tk/lib/tkextlib/bwidget/combobox.rb b/ext/tk/lib/tkextlib/bwidget/combobox.rb
index 31f71c3aaf..1c58a4ccb0 100644
--- a/ext/tk/lib/tkextlib/bwidget/combobox.rb
+++ b/ext/tk/lib/tkextlib/bwidget/combobox.rb
@@ -25,7 +25,13 @@ class Tk::BWidget::ComboBox
def get_listbox(&b)
win = window(tk_send_without_enc('getlistbox'))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
diff --git a/ext/tk/lib/tkextlib/bwidget/dialog.rb b/ext/tk/lib/tkextlib/bwidget/dialog.rb
index 2790d88d24..291ca4a962 100644
--- a/ext/tk/lib/tkextlib/bwidget/dialog.rb
+++ b/ext/tk/lib/tkextlib/bwidget/dialog.rb
@@ -59,6 +59,13 @@ class Tk::BWidget::Dialog
end
end
+ def cget_strict(slot)
+ if slot.to_s == 'relative'
+ super('parent')
+ else
+ super(slot)
+ end
+ end
def cget(slot)
if slot.to_s == 'relative'
super('parent')
@@ -103,7 +110,7 @@ class Tk::BWidget::Dialog
name = tagOrId[:name]
return index(name) unless name.empty?
end
- if tagOrId.kind_of?(TkButton)
+ if tagOrId.kind_of?(Tk::Button)
return index(tagOrId[:text])
end
# index(tagOrId.to_s)
@@ -112,19 +119,37 @@ class Tk::BWidget::Dialog
def add(keys={}, &b)
win = window(tk_send('add', *hash_kv(keys)))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
def get_frame(&b)
win = window(tk_send('getframe'))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
def get_buttonbox(&b)
win = window(@path + '.bbox')
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
diff --git a/ext/tk/lib/tkextlib/bwidget/dynamichelp.rb b/ext/tk/lib/tkextlib/bwidget/dynamichelp.rb
index 224304f2ab..846e58062d 100644
--- a/ext/tk/lib/tkextlib/bwidget/dynamichelp.rb
+++ b/ext/tk/lib/tkextlib/bwidget/dynamichelp.rb
@@ -34,6 +34,13 @@ module Tk::BWidget::DynamicHelp
['DynamicHelp::configure']
end
+ def self.cget_strict(slot)
+ slot = slot.to_s
+ info = {}
+ self.current_configinfo.each{|k,v| info[k.to_s] = v if k.to_s == slot}
+ fail RuntimeError, "unknown option \"-#{slot}\"" if info.empty?
+ info.values[0]
+ end
def self.cget(slot)
self.current_configinfo(slot).values[0]
end
diff --git a/ext/tk/lib/tkextlib/bwidget/entry.rb b/ext/tk/lib/tkextlib/bwidget/entry.rb
index aafb4aa7ff..a56890f4e3 100644
--- a/ext/tk/lib/tkextlib/bwidget/entry.rb
+++ b/ext/tk/lib/tkextlib/bwidget/entry.rb
@@ -9,7 +9,7 @@ require 'tkextlib/bwidget.rb'
module Tk
module BWidget
- class Entry < TkEntry
+ class Entry < Tk::Entry
end
end
end
diff --git a/ext/tk/lib/tkextlib/bwidget/label.rb b/ext/tk/lib/tkextlib/bwidget/label.rb
index ce10ecaf8b..88a504aa50 100644
--- a/ext/tk/lib/tkextlib/bwidget/label.rb
+++ b/ext/tk/lib/tkextlib/bwidget/label.rb
@@ -9,7 +9,7 @@ require 'tkextlib/bwidget.rb'
module Tk
module BWidget
- class Label < TkLabel
+ class Label < Tk::Label
end
end
end
diff --git a/ext/tk/lib/tkextlib/bwidget/labelentry.rb b/ext/tk/lib/tkextlib/bwidget/labelentry.rb
index 931feb9b48..95b40946a6 100644
--- a/ext/tk/lib/tkextlib/bwidget/labelentry.rb
+++ b/ext/tk/lib/tkextlib/bwidget/labelentry.rb
@@ -11,7 +11,7 @@ require 'tkextlib/bwidget/entry'
module Tk
module BWidget
- class LabelEntry < TkEntry
+ class LabelEntry < Tk::Entry
end
end
end
diff --git a/ext/tk/lib/tkextlib/bwidget/labelframe.rb b/ext/tk/lib/tkextlib/bwidget/labelframe.rb
index f7b267eebb..dc221806e4 100644
--- a/ext/tk/lib/tkextlib/bwidget/labelframe.rb
+++ b/ext/tk/lib/tkextlib/bwidget/labelframe.rb
@@ -40,7 +40,13 @@ class Tk::BWidget::LabelFrame
end
def get_frame(&b)
win = window(tk_send_without_enc('getframe'))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
end
diff --git a/ext/tk/lib/tkextlib/bwidget/listbox.rb b/ext/tk/lib/tkextlib/bwidget/listbox.rb
index 1267500661..093fcb6fb3 100644
--- a/ext/tk/lib/tkextlib/bwidget/listbox.rb
+++ b/ext/tk/lib/tkextlib/bwidget/listbox.rb
@@ -211,14 +211,26 @@ class Tk::BWidget::ListBox::Item
include TkTreatTagFont
ListItem_TBL = TkCore::INTERP.create_table
- ListItem_ID = ['bw:item'.freeze, '00000'.taint].freeze
- TkCore::INTERP.init_ip_env{ ListItem_TBL.clear }
+ (ListItem_ID = ['bw:item'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
+ TkCore::INTERP.init_ip_env{
+ ListItem_TBL.mutex.synchronize{ ListItem_TBL.clear }
+ }
def self.id2obj(lbox, id)
lpath = lbox.path
- return id unless ListItem_TBL[lpath]
- ListItem_TBL[lpath][id]? ListItem_TBL[lpath][id]: id
+ ListItem_TBL.mutex.synchronize{
+ if ListItem_TBL[lpath]
+ ListItem_TBL[lpath][id]? ListItem_TBL[lpath][id]: id
+ else
+ id
+ end
+ }
end
def initialize(lbox, *args)
@@ -250,13 +262,17 @@ class Tk::BWidget::ListBox::Item
if keys.key?('itemname')
@path = @id = keys.delete('itemname')
else
- @path = @id = ListItem_ID.join(TkCore::INTERP._ip_id_)
- ListItem_ID[1].succ!
+ ListItem_ID.mutex.synchronize{
+ @path = @id = ListItem_ID.join(TkCore::INTERP._ip_id_)
+ ListItem_ID[1].succ!
+ }
end
- ListItem_TBL[@id] = self
- ListItem_TBL[@lpath] = {} unless ListItem_TBL[@lpath]
- ListItem_TBL[@lpath][@id] = self
+ ListItem_TBL.mutex.synchronize{
+ ListItem_TBL[@id] = self
+ ListItem_TBL[@lpath] = {} unless ListItem_TBL[@lpath]
+ ListItem_TBL[@lpath][@id] = self
+ }
@listbox.insert(index, @id, keys)
end
@@ -281,6 +297,9 @@ class Tk::BWidget::ListBox::Item
def cget(key)
@listbox.itemcget(@id, key)
end
+ def cget_strict(key)
+ @listbox.itemcget_strict(@id, key)
+ end
def configure(key, val=None)
@listbox.itemconfigure(@id, key, val)
diff --git a/ext/tk/lib/tkextlib/bwidget/mainframe.rb b/ext/tk/lib/tkextlib/bwidget/mainframe.rb
index c54e878557..de66eaf81e 100644
--- a/ext/tk/lib/tkextlib/bwidget/mainframe.rb
+++ b/ext/tk/lib/tkextlib/bwidget/mainframe.rb
@@ -41,37 +41,73 @@ class Tk::BWidget::MainFrame
def add_indicator(keys={}, &b)
win = window(tk_send('addindicator', *hash_kv(keys)))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
def add_toolbar(&b)
win = window(tk_send('addtoolbar'))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
def get_frame(&b)
win = window(tk_send('getframe'))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
def get_indicator(idx, &b)
win = window(tk_send('getindicator', idx))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
def get_menu(menu_id, &b)
win = window(tk_send('getmenu', menu_id))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
def get_toolbar(idx, &b)
win = window(tk_send('gettoolbar', idx))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
diff --git a/ext/tk/lib/tkextlib/bwidget/messagedlg.rb b/ext/tk/lib/tkextlib/bwidget/messagedlg.rb
index 9c946d0630..b88461baf7 100644
--- a/ext/tk/lib/tkextlib/bwidget/messagedlg.rb
+++ b/ext/tk/lib/tkextlib/bwidget/messagedlg.rb
@@ -65,6 +65,17 @@ class Tk::BWidget::MessageDlg
end
@keys[slot]
end
+ def cget_strict(slot)
+ slot = slot.to_s
+ if slot == 'relative'
+ slot = 'parent'
+ end
+ if winfo_exist?
+ val = super(slot)
+ @keys[slot] = val
+ end
+ @keys[slot]
+ end
def configure(slot, value=None)
if winfo_exist?
@@ -173,6 +184,9 @@ class Tk::BWidget::MessageDlg
end
def create
- num_or_str(tk_call(self.class::TkCommandNames[0], @path, *hash_kv(@keys)))
+ # return the index of the pressed button, or nil if it is destroyed
+ ret = num_or_str(tk_call(self.class::TkCommandNames[0],
+ @path, *hash_kv(@keys)))
+ (ret < 0)? nil: ret
end
end
diff --git a/ext/tk/lib/tkextlib/bwidget/notebook.rb b/ext/tk/lib/tkextlib/bwidget/notebook.rb
index 5146d4915d..423943619c 100644
--- a/ext/tk/lib/tkextlib/bwidget/notebook.rb
+++ b/ext/tk/lib/tkextlib/bwidget/notebook.rb
@@ -89,7 +89,13 @@ class Tk::BWidget::NoteBook
def add(page, &b)
win = window(tk_send('add', tagid(page)))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
@@ -105,7 +111,13 @@ class Tk::BWidget::NoteBook
def get_frame(page, &b)
win = window(tk_send('getframe', tagid(page)))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
@@ -115,7 +127,13 @@ class Tk::BWidget::NoteBook
def insert(index, page, keys={}, &b)
win = window(tk_send('insert', index, tagid(page), *hash_kv(keys)))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
diff --git a/ext/tk/lib/tkextlib/bwidget/pagesmanager.rb b/ext/tk/lib/tkextlib/bwidget/pagesmanager.rb
index fc01284be6..fbc2c11255 100644
--- a/ext/tk/lib/tkextlib/bwidget/pagesmanager.rb
+++ b/ext/tk/lib/tkextlib/bwidget/pagesmanager.rb
@@ -26,7 +26,13 @@ class Tk::BWidget::PagesManager
def add(page, &b)
win = window(tk_send('add', tagid(page)))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
@@ -42,7 +48,13 @@ class Tk::BWidget::PagesManager
def get_frame(page, &b)
win = window(tk_send('getframe', tagid(page)))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
diff --git a/ext/tk/lib/tkextlib/bwidget/panedwindow.rb b/ext/tk/lib/tkextlib/bwidget/panedwindow.rb
index 19982c6095..4d979fd523 100644
--- a/ext/tk/lib/tkextlib/bwidget/panedwindow.rb
+++ b/ext/tk/lib/tkextlib/bwidget/panedwindow.rb
@@ -25,7 +25,13 @@ class Tk::BWidget::PanedWindow
def get_frame(idx, &b)
win = window(tk_send_without_enc('getframe', idx))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
end
diff --git a/ext/tk/lib/tkextlib/bwidget/panelframe.rb b/ext/tk/lib/tkextlib/bwidget/panelframe.rb
index 13f8817d74..84bae0768b 100644
--- a/ext/tk/lib/tkextlib/bwidget/panelframe.rb
+++ b/ext/tk/lib/tkextlib/bwidget/panelframe.rb
@@ -36,7 +36,13 @@ class Tk::BWidget::PanelFrame
def get_frame(&b)
win = window(tk_send_without_enc('getframe'))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
diff --git a/ext/tk/lib/tkextlib/bwidget/progressdlg.rb b/ext/tk/lib/tkextlib/bwidget/progressdlg.rb
index fbf00f3b00..32600255d5 100644
--- a/ext/tk/lib/tkextlib/bwidget/progressdlg.rb
+++ b/ext/tk/lib/tkextlib/bwidget/progressdlg.rb
@@ -51,4 +51,8 @@ class Tk::BWidget::ProgressDlg
def value= (val)
@keys['variable'].value = val
end
+
+ def create
+ window(tk_call(self.class::TkCommandNames[0], @path, *hash_kv(@keys)))
+ end
end
diff --git a/ext/tk/lib/tkextlib/bwidget/scrollableframe.rb b/ext/tk/lib/tkextlib/bwidget/scrollableframe.rb
index a3986681a5..010c960ec5 100644
--- a/ext/tk/lib/tkextlib/bwidget/scrollableframe.rb
+++ b/ext/tk/lib/tkextlib/bwidget/scrollableframe.rb
@@ -23,7 +23,13 @@ class Tk::BWidget::ScrollableFrame
def get_frame(&b)
win = window(tk_send_without_enc('getframe'))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
diff --git a/ext/tk/lib/tkextlib/bwidget/scrolledwindow.rb b/ext/tk/lib/tkextlib/bwidget/scrolledwindow.rb
index e9e53235b7..3599fd8459 100644
--- a/ext/tk/lib/tkextlib/bwidget/scrolledwindow.rb
+++ b/ext/tk/lib/tkextlib/bwidget/scrolledwindow.rb
@@ -21,7 +21,13 @@ class Tk::BWidget::ScrolledWindow
def get_frame(&b)
win = window(tk_send_without_enc('getframe'))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
diff --git a/ext/tk/lib/tkextlib/bwidget/selectcolor.rb b/ext/tk/lib/tkextlib/bwidget/selectcolor.rb
index 742a84cd84..0f9014f8de 100644
--- a/ext/tk/lib/tkextlib/bwidget/selectcolor.rb
+++ b/ext/tk/lib/tkextlib/bwidget/selectcolor.rb
@@ -10,6 +10,11 @@ require 'tkextlib/bwidget/messagedlg'
module Tk
module BWidget
class SelectColor < Tk::BWidget::MessageDlg
+ class Dialog < Tk::BWidget::SelectColor
+ end
+ class Menubutton < Tk::Menubutton
+ end
+ MenuButton = Menubutton
end
end
end
@@ -43,3 +48,26 @@ class Tk::BWidget::SelectColor
tk_call('SelectColor::setcolor', idx, color)
end
end
+
+class Tk::BWidget::SelectColor::Dialog
+ def create_self(keys)
+ super(keys)
+ @keys['type'] = 'dialog'
+ end
+
+ def create
+ @keys['type'] = 'dialog' # 'dialog' type returns color
+ tk_call(Tk::BWidget::SelectColor::TkCommandNames[0],
+ @path, *hash_kv(@keys))
+ end
+end
+
+class Tk::BWidget::SelectColor::Menubutton
+ def create_self(keys)
+ keys = {} unless keys
+ keys = _symbolkey2str(keys)
+ keys['type'] = 'menubutton' # 'toolbar' type returns widget path
+ window(tk_call(Tk::BWidget::SelectColor::TkCommandNames[0],
+ @path, *hash_kv(keys)))
+ end
+end
diff --git a/ext/tk/lib/tkextlib/bwidget/selectfont.rb b/ext/tk/lib/tkextlib/bwidget/selectfont.rb
index 478787602a..e53eb3b5bc 100644
--- a/ext/tk/lib/tkextlib/bwidget/selectfont.rb
+++ b/ext/tk/lib/tkextlib/bwidget/selectfont.rb
@@ -66,7 +66,7 @@ class Tk::BWidget::SelectFont::Dialog
end
def create
- @keys['type'] = 'dialog'
+ @keys['type'] = 'dialog' # 'dialog' type returns font name
tk_call(Tk::BWidget::SelectFont::TkCommandNames[0], @path, *hash_kv(@keys))
end
end
@@ -79,7 +79,8 @@ class Tk::BWidget::SelectFont::Toolbar
def create_self(keys)
keys = {} unless keys
keys = _symbolkey2str(keys)
- keys['type'] = 'toolbar'
- tk_call(Tk::BWidget::SelectFont::TkCommandNames[0], @path, *hash_kv(keys))
+ keys['type'] = 'toolbar' # 'toolbar' type returns widget path
+ window(tk_call(Tk::BWidget::SelectFont::TkCommandNames[0],
+ @path, *hash_kv(keys)))
end
end
diff --git a/ext/tk/lib/tkextlib/bwidget/spinbox.rb b/ext/tk/lib/tkextlib/bwidget/spinbox.rb
index ca4c046e5c..48358baa5c 100644
--- a/ext/tk/lib/tkextlib/bwidget/spinbox.rb
+++ b/ext/tk/lib/tkextlib/bwidget/spinbox.rb
@@ -10,7 +10,7 @@ require 'tkextlib/bwidget/entry'
module Tk
module BWidget
- class SpinBox < TkEntry
+ class SpinBox < Tk::Entry
end
end
end
diff --git a/ext/tk/lib/tkextlib/bwidget/statusbar.rb b/ext/tk/lib/tkextlib/bwidget/statusbar.rb
index df16e4c0b7..39c678d37e 100644
--- a/ext/tk/lib/tkextlib/bwidget/statusbar.rb
+++ b/ext/tk/lib/tkextlib/bwidget/statusbar.rb
@@ -36,7 +36,13 @@ class Tk::BWidget::StatusBar
def get_frame(&b)
win = window(tk_send_without_enc('getframe'))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
diff --git a/ext/tk/lib/tkextlib/bwidget/titleframe.rb b/ext/tk/lib/tkextlib/bwidget/titleframe.rb
index f519490430..68534e66e9 100644
--- a/ext/tk/lib/tkextlib/bwidget/titleframe.rb
+++ b/ext/tk/lib/tkextlib/bwidget/titleframe.rb
@@ -21,7 +21,13 @@ class Tk::BWidget::TitleFrame
def get_frame(&b)
win = window(tk_send_without_enc('getframe'))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
end
diff --git a/ext/tk/lib/tkextlib/bwidget/tree.rb b/ext/tk/lib/tkextlib/bwidget/tree.rb
index e7178debe2..aed4512a73 100644
--- a/ext/tk/lib/tkextlib/bwidget/tree.rb
+++ b/ext/tk/lib/tkextlib/bwidget/tree.rb
@@ -263,14 +263,26 @@ class Tk::BWidget::Tree::Node
include TkTreatTagFont
TreeNode_TBL = TkCore::INTERP.create_table
- TreeNode_ID = ['bw:node'.freeze, '00000'.taint].freeze
- TkCore::INTERP.init_ip_env{ TreeNode_TBL.clear }
+ (TreeNode_ID = ['bw:node'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
+ TkCore::INTERP.init_ip_env{
+ TreeNode_TBL.mutex.synchronize{ TreeNode_TBL.clear }
+ }
def self.id2obj(tree, id)
tpath = tree.path
- return id unless TreeNode_TBL[tpath]
- TreeNode_TBL[tpath][id]? TreeNode_TBL[tpath][id]: id
+ TreeNode_TBL.mutex.synchronize{
+ if TreeNode_TBL[tpath]
+ TreeNode_TBL[tpath][id]? TreeNode_TBL[tpath][id]: id
+ else
+ id
+ end
+ }
end
def initialize(tree, *args)
@@ -311,13 +323,17 @@ class Tk::BWidget::Tree::Node
if keys.key?('nodename')
@path = @id = keys.delete('nodename')
else
- @path = @id = TreeNode_ID.join(TkCore::INTERP._ip_id_)
- TreeNode_ID[1].succ!
+ TreeNode_ID.mutex.synchronize{
+ @path = @id = TreeNode_ID.join(TkCore::INTERP._ip_id_)
+ TreeNode_ID[1].succ!
+ }
end
- TreeNode_TBL[@id] = self
- TreeNode_TBL[@tpath] = {} unless TreeNode_TBL[@tpath]
- TreeNode_TBL[@tpath][@id] = self
+ TreeNode_TBL.mutex.synchronize{
+ TreeNode_TBL[@id] = self
+ TreeNode_TBL[@tpath] = {} unless TreeNode_TBL[@tpath]
+ TreeNode_TBL[@tpath][@id] = self
+ }
@tree.insert(index, parent, @id, keys)
end
@@ -342,6 +358,9 @@ class Tk::BWidget::Tree::Node
def cget(key)
@tree.itemcget(@id, key)
end
+ def cget_strict(key)
+ @tree.itemcget_strict(@id, key)
+ end
def configure(key, val=None)
@tree.itemconfigure(@id, key, val)
diff --git a/ext/tk/lib/tkextlib/bwidget/widget.rb b/ext/tk/lib/tkextlib/bwidget/widget.rb
index 568e503a8b..a93364b567 100644
--- a/ext/tk/lib/tkextlib/bwidget/widget.rb
+++ b/ext/tk/lib/tkextlib/bwidget/widget.rb
@@ -29,6 +29,13 @@ module Tk::BWidget::Widget
['Widget::configure']
end
+ def self.cget_strict(slot)
+ slot = slot.to_s
+ info = {}
+ self.current_configinfo.each{|k,v| info[k.to_s] = v if k.to_s == slot}
+ fail RuntimeError, "unknown option \"-#{slot}\"" if info.empty?
+ info.values[0]
+ end
def self.cget(slot)
self.current_configinfo(slot).values[0]
end
@@ -43,7 +50,13 @@ module Tk::BWidget::Widget
def self.create(klass, path, rename=None, &b)
win = window(tk_call('Widget::create', klass, path, rename))
- win.instance_eval(&b) if b
+ if b
+ if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ win.instance_exec(self, &b)
+ else
+ win.instance_eval(&b)
+ end
+ end
win
end
@@ -99,9 +112,12 @@ module Tk::BWidget::Widget
tk_call('Widget::setoption', win, option, value)
end
- def self.sub_cget(win, subwidget)
+ def self.sub_cget_strict(win, subwidget)
tk_call('Widget::subcget', win, subwidget)
end
+ def self.sub_cget(win, subwidget)
+ self.sub_cget_strict(win, subwidget)
+ end
def self.sync_options(klass, subclass, subpath, options)
tk_call('Widget::syncoptions', klass, subclass, subpath, options)
diff --git a/ext/tk/lib/tkextlib/itcl/incr_tcl.rb b/ext/tk/lib/tkextlib/itcl/incr_tcl.rb
index 07abf3a7bf..2b75d62eb9 100644
--- a/ext/tk/lib/tkextlib/itcl/incr_tcl.rb
+++ b/ext/tk/lib/tkextlib/itcl/incr_tcl.rb
@@ -40,16 +40,22 @@ module Tk
class ItclObject < TkObject
ITCL_CLASSNAME = ''.freeze
- ITCL_OBJ_ID = ['itclobj'.freeze, '00000'.taint].freeze
+ (ITCL_OBJ_ID = ['itclobj'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
ITCL_OBJ_TBL = {}.taint
def initialize(*args)
if (@klass = self.class::ITCL_CLASSNAME).empty?
fail RuntimeError, 'unknown itcl class (abstract class?)'
end
- @id = Tk::Itcl::ItclObject::TCL_OBJ_ID.join(TkCore::INTERP._ip_id_)
+ Tk::Itcl::ItclObject::ITCL_OBJ_ID.mutex.synchronize{
+ @id = Tk::Itcl::ItclObject::TCL_OBJ_ID.join(TkCore::INTERP._ip_id_)
+ Tk::Itcl::ItclObject::ITCL_OBJ_ID[1].succ!
+ }
@path = @id
- Tk::Itcl::ItclObject::ITCL_OBJ_ID[1].succ!
end
def self.call_proc(name, *args)
diff --git a/ext/tk/lib/tkextlib/itk/incr_tk.rb b/ext/tk/lib/tkextlib/itk/incr_tk.rb
index 0626536e36..e06deb552c 100644
--- a/ext/tk/lib/tkextlib/itk/incr_tk.rb
+++ b/ext/tk/lib/tkextlib/itk/incr_tk.rb
@@ -145,9 +145,16 @@ module Tk
private :__config_cmd
ComponentID_TBL = TkCore::INTERP.create_table
- Itk_Component_ID = ['itk:component'.freeze, '00000'.taint].freeze
- TkCore::INTERP.init_ip_env{ ComponentID_TBL.clear }
+ (Itk_Component_ID = ['itk:component'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
+ TkCore::INTERP.init_ip_env{
+ ComponentID_TBL.mutex.synchronize{ ComponentID_TBL.clear }
+ }
def self.id2obj(master, id)
if master.kind_of?(TkObject)
@@ -155,8 +162,13 @@ module Tk
else
master = master.to_s
end
- return id unless ComponentID_TBL.key?(master)
- (ComponentID_TBL.key?(id))? ComponentID_TBL[master][id]: id
+ ComponentID_TBL.mutex.synchronize{
+ if ComponentID_TBL.key?(master)
+ (ComponentID_TBL[master].key?(id))? ComponentID_TBL[master][id]: id
+ else
+ id
+ end
+ }
end
def self.new(master, component=nil)
@@ -171,17 +183,21 @@ module Tk
elsif component
component = component.to_s
else
- component = Itk_Component_ID.join(TkCore::INTERP._ip_id_)
- Itk_Component_ID[1].succ!
+ Itk_Component_ID.mutex.synchronize{
+ component = Itk_Component_ID.join(TkCore::INTERP._ip_id_)
+ Itk_Component_ID[1].succ!
+ }
end
- if ComponentID_TBL.key?(master)
- if ComponentID_TBL[master].key?(component)
- return ComponentID_TBL[master][component]
+ ComponentID_TBL.mutex.synchronize{
+ if ComponentID_TBL.key?(master)
+ if ComponentID_TBL[master].key?(component)
+ return ComponentID_TBL[master][component]
+ end
+ else
+ ComponentID_TBL[master] = {}
end
- else
- ComponentID_TBL[master] = {}
- end
+ }
super(master, component)
end
@@ -190,7 +206,9 @@ module Tk
@master = master
@component = component
- ComponentID_TBL[@master][@component] = self
+ ComponentID_TBL.mutex.synchronize{
+ ComponentID_TBL[@master][@component] = self
+ }
begin
@widget = window(tk_call(@master, 'component', @component))
diff --git a/ext/tk/lib/tkextlib/iwidgets/buttonbox.rb b/ext/tk/lib/tkextlib/iwidgets/buttonbox.rb
index a055e07ac9..05d58c386f 100644
--- a/ext/tk/lib/tkextlib/iwidgets/buttonbox.rb
+++ b/ext/tk/lib/tkextlib/iwidgets/buttonbox.rb
@@ -47,12 +47,13 @@ class Tk::Iwidgets::Buttonbox
end
alias buttoncget itemcget
+ alias buttoncget_strict itemcget_strict
alias buttonconfigure itemconfigure
alias buttonconfiginfo itemconfiginfo
alias current_buttonconfiginfo current_itemconfiginfo
- private :itemcget, :itemconfigure
- private :itemconfiginfo, :current_itemconfiginfo
+ private :itemcget, :itemcget_strict
+ private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo
####################################
diff --git a/ext/tk/lib/tkextlib/iwidgets/calendar.rb b/ext/tk/lib/tkextlib/iwidgets/calendar.rb
index 0152f8593a..8495f0e29b 100644
--- a/ext/tk/lib/tkextlib/iwidgets/calendar.rb
+++ b/ext/tk/lib/tkextlib/iwidgets/calendar.rb
@@ -45,6 +45,25 @@ class Tk::Iwidgets::Calendar
class ValidateArgs < TkUtil::CallbackSubst
KEY_TBL = [ [?d, ?s, :date], nil ]
PROC_TBL = [ [?s, TkComm.method(:string) ], nil ]
+
+=begin
+ # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
+ KEY_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String)
+ end
+ inf
+ }
+
+ PROC_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ end
+ inf
+ }
+=end
+
_setup_subst_table(KEY_TBL, PROC_TBL);
def self.ret_val(val)
diff --git a/ext/tk/lib/tkextlib/iwidgets/checkbox.rb b/ext/tk/lib/tkextlib/iwidgets/checkbox.rb
index abd23299a8..c85d356c55 100644
--- a/ext/tk/lib/tkextlib/iwidgets/checkbox.rb
+++ b/ext/tk/lib/tkextlib/iwidgets/checkbox.rb
@@ -47,12 +47,13 @@ class Tk::Iwidgets::Checkbox
end
alias buttoncget itemcget
+ alias buttoncget_strict itemcget_strict
alias buttonconfigure itemconfigure
alias buttonconfiginfo itemconfiginfo
alias current_buttonconfiginfo current_itemconfiginfo
- private :itemcget, :itemconfigure
- private :itemconfiginfo, :current_itemconfiginfo
+ private :itemcget, :itemcget_strict
+ private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo
####################################
@@ -85,12 +86,24 @@ class Tk::Iwidgets::Checkbox
self
end
- def get(idx)
- simplelist(tk_call(@path, 'get', index(idx))).collect{|id|
- Tk::Itk::Component.id2obj(id)
+ def get_tags
+ simplelist(tk_call_without_enc(@path, 'get'))
+ end
+
+ def get_objs
+ simplelist(tk_call_without_enc(@path, 'get')).collect{|id|
+ Tk::Itk::Component.id2obj(self, id)
}
end
+ def get(idx=nil)
+ if idx
+ bool(tk_call_without_enc(@path, 'get', index(idx)))
+ else
+ get_tags
+ end
+ end
+
def index(idx)
number(tk_call(@path, 'index', tagid(idx)))
end
diff --git a/ext/tk/lib/tkextlib/iwidgets/dialogshell.rb b/ext/tk/lib/tkextlib/iwidgets/dialogshell.rb
index d6c668621d..8d43cc07ab 100644
--- a/ext/tk/lib/tkextlib/iwidgets/dialogshell.rb
+++ b/ext/tk/lib/tkextlib/iwidgets/dialogshell.rb
@@ -47,12 +47,13 @@ class Tk::Iwidgets::Dialogshell
end
alias buttoncget itemcget
+ alias buttoncget_strict itemcget_strict
alias buttonconfigure itemconfigure
alias buttonconfiginfo itemconfiginfo
alias current_buttonconfiginfo current_itemconfiginfo
- private :itemcget, :itemconfigure
- private :itemconfiginfo, :current_itemconfiginfo
+ private :itemcget, :itemcget_strict
+ private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo
####################################
diff --git a/ext/tk/lib/tkextlib/iwidgets/entryfield.rb b/ext/tk/lib/tkextlib/iwidgets/entryfield.rb
index 6aa933ce06..d53df216bf 100644
--- a/ext/tk/lib/tkextlib/iwidgets/entryfield.rb
+++ b/ext/tk/lib/tkextlib/iwidgets/entryfield.rb
@@ -42,6 +42,25 @@ class Tk::Iwidgets::Entryfield
[ ?w, TkComm.method(:window) ],
nil
]
+
+=begin
+ # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
+ KEY_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String)
+ end
+ inf
+ }
+
+ PROC_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ end
+ inf
+ }
+=end
+
_setup_subst_table(KEY_TBL, PROC_TBL);
end
diff --git a/ext/tk/lib/tkextlib/iwidgets/hierarchy.rb b/ext/tk/lib/tkextlib/iwidgets/hierarchy.rb
index 4cc6aeecbd..d9220fecbf 100644
--- a/ext/tk/lib/tkextlib/iwidgets/hierarchy.rb
+++ b/ext/tk/lib/tkextlib/iwidgets/hierarchy.rb
@@ -30,6 +30,25 @@ class Tk::Iwidgets::Hierarchy
class ValidateArgs < TkUtil::CallbackSubst
KEY_TBL = [ [?n, ?s, :node], nil ]
PROC_TBL = [ [?s, TkComm.method(:string) ], nil ]
+
+=begin
+ # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
+ KEY_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String)
+ end
+ inf
+ }
+
+ PROC_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ end
+ inf
+ }
+=end
+
_setup_subst_table(KEY_TBL, PROC_TBL);
def self.ret_val(val)
@@ -57,6 +76,24 @@ class Tk::Iwidgets::Hierarchy
nil
]
+=begin
+ # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
+ KEY_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String)
+ end
+ inf
+ }
+
+ PROC_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ end
+ inf
+ }
+=end
+
_setup_subst_table(KEY_TBL, PROC_TBL);
def self.ret_val(val)
@@ -78,6 +115,25 @@ class Tk::Iwidgets::Hierarchy
nil
]
PROC_TBL = [ [ ?s, TkComm.method(:string) ], nil ]
+
+=begin
+ # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
+ KEY_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String)
+ end
+ inf
+ }
+
+ PROC_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ end
+ inf
+ }
+=end
+
_setup_subst_table(KEY_TBL, PROC_TBL);
def self.ret_val(val)
@@ -207,7 +263,7 @@ class Tk::Iwidgets::Hierarchy
self
end
- # based on TkText widget
+ # based on Tk::Text widget
def bbox(index)
list(tk_send_without_enc('bbox', _get_eval_enc_str(index)))
diff --git a/ext/tk/lib/tkextlib/iwidgets/menubar.rb b/ext/tk/lib/tkextlib/iwidgets/menubar.rb
index dea3d34c2a..5aaefbe50d 100644
--- a/ext/tk/lib/tkextlib/iwidgets/menubar.rb
+++ b/ext/tk/lib/tkextlib/iwidgets/menubar.rb
@@ -62,12 +62,13 @@ class Tk::Iwidgets::Menubar
end
alias menucget itemcget
+ alias menucget_strict itemcget_strict
alias menuconfigure itemconfigure
alias menuconfiginfo itemconfiginfo
alias current_menuconfiginfo current_itemconfiginfo
- private :itemcget, :itemconfigure
- private :itemconfiginfo, :current_itemconfiginfo
+ private :itemcget, :itemcget_strict
+ private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo
####################################
diff --git a/ext/tk/lib/tkextlib/iwidgets/messagebox.rb b/ext/tk/lib/tkextlib/iwidgets/messagebox.rb
index 2bbbec7666..98ac32900c 100644
--- a/ext/tk/lib/tkextlib/iwidgets/messagebox.rb
+++ b/ext/tk/lib/tkextlib/iwidgets/messagebox.rb
@@ -47,12 +47,13 @@ class Tk::Iwidgets::Messagebox
private :__item_boolval_optkeys
alias typecget itemcget
+ alias typecget_strict itemcget_strict
alias typeconfigure itemconfigure
alias typeconfiginfo itemconfiginfo
alias current_typeconfiginfo current_itemconfiginfo
- private :itemcget, :itemconfigure
- private :itemconfiginfo, :current_itemconfiginfo
+ private :itemcget, :itemcget_strict
+ private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo
####################################
diff --git a/ext/tk/lib/tkextlib/iwidgets/notebook.rb b/ext/tk/lib/tkextlib/iwidgets/notebook.rb
index 0f9d713ea1..03b50633df 100644
--- a/ext/tk/lib/tkextlib/iwidgets/notebook.rb
+++ b/ext/tk/lib/tkextlib/iwidgets/notebook.rb
@@ -42,12 +42,13 @@ class Tk::Iwidgets::Notebook
end
alias pagecget itemcget
+ alias pagecget_strict itemcget_strict
alias pageconfigure itemconfigure
alias pageconfiginfo itemconfiginfo
alias current_pageconfiginfo current_itemconfiginfo
- private :itemcget, :itemconfigure
- private :itemconfiginfo, :current_itemconfiginfo
+ private :itemcget, :itemcget_strict
+ private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo
####################################
@@ -146,7 +147,12 @@ class Tk::Iwidgets::Notebook
def view(*idxs)
if idxs.size == 0
- window(tk_send_without_enc('view'))
+ idx = num_or_str(tk_send_without_enc('view'))
+ if idx.kind_of?(Fixnum) && idx < 0
+ nil
+ else
+ idx
+ end
else
tk_send_without_enc('view', *idxs)
self
@@ -160,8 +166,8 @@ class Tk::Iwidgets::Notebook
end
alias xview_moveto view_moveto
alias yview_moveto view_moveto
- def view_scroll(*idxs)
- view('scroll', *idxs)
+ def view_scroll(index, what='pages')
+ view('scroll', index, what)
end
alias xview_scroll view_scroll
alias yview_scroll view_scroll
diff --git a/ext/tk/lib/tkextlib/iwidgets/panedwindow.rb b/ext/tk/lib/tkextlib/iwidgets/panedwindow.rb
index 035df0a5b8..3bf73d69fe 100644
--- a/ext/tk/lib/tkextlib/iwidgets/panedwindow.rb
+++ b/ext/tk/lib/tkextlib/iwidgets/panedwindow.rb
@@ -42,12 +42,13 @@ class Tk::Iwidgets::Panedwindow
end
alias panecget itemcget
+ alias panecget_strict itemcget_strict
alias paneconfigure itemconfigure
alias paneconfiginfo itemconfiginfo
alias current_paneconfiginfo current_itemconfiginfo
- private :itemcget, :itemconfigure
- private :itemconfiginfo, :current_itemconfiginfo
+ private :itemcget, :itemcget_strict
+ private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo
####################################
diff --git a/ext/tk/lib/tkextlib/iwidgets/radiobox.rb b/ext/tk/lib/tkextlib/iwidgets/radiobox.rb
index d4316754f2..e9d9521252 100644
--- a/ext/tk/lib/tkextlib/iwidgets/radiobox.rb
+++ b/ext/tk/lib/tkextlib/iwidgets/radiobox.rb
@@ -47,12 +47,13 @@ class Tk::Iwidgets::Radiobox
end
alias buttoncget itemcget
+ alias buttoncget_strict itemcget_strict
alias buttonconfigure itemconfigure
alias buttonconfiginfo itemconfiginfo
alias current_buttonconfiginfo current_itemconfiginfo
- private :itemcget, :itemconfigure
- private :itemconfiginfo, :current_itemconfiginfo
+ private :itemcget, :itemcget_strict
+ private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo
####################################
@@ -85,10 +86,13 @@ class Tk::Iwidgets::Radiobox
self
end
- def get(idx)
- simplelist(tk_call(@path, 'get', index(idx))).collect{|id|
- Tk::Itk::Component.id2obj(id)
- }
+ def get_tag
+ ((tag = tk_call_without_enc(@path, 'get')).empty?)? nil: tag
+ end
+ alias get get_tag
+
+ def get_obj
+ (tag = get_tag)? Tk::Itk::Component.id2obj(self, tag): nil
end
def index(idx)
diff --git a/ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb b/ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb
index 407c8f2aad..67ad67d07e 100644
--- a/ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb
+++ b/ext/tk/lib/tkextlib/iwidgets/scrolledcanvas.rb
@@ -37,7 +37,7 @@ class Tk::Iwidgets::Scrolledcanvas
end
def method_missing(id, *args)
- if @canvas.methods.include?(id.id2name)
+ if @canvas.respond_to?(id)
@canvas.__send__(id, *args)
else
super(id, *args)
@@ -171,10 +171,16 @@ class Tk::Iwidgets::Scrolledcanvas
end
def delete(*args)
- if TkcItem::CItemID_TBL[self.path]
+ tbl = nil
+ TkcItem::CItemID_TBL.mutex.synchronize{
+ tbl = TkcItem::CItemID_TBL[self.path]
+ }
+ if tbl
find('withtag', *args).each{|item|
if item.kind_of?(TkcItem)
- TkcItem::CItemID_TBL[self.path].delete(item.id)
+ TkcItem::CItemID_TBL.mutex.synchronize{
+ tbl.delete(item.id)
+ }
end
}
end
diff --git a/ext/tk/lib/tkextlib/iwidgets/scrolledlistbox.rb b/ext/tk/lib/tkextlib/iwidgets/scrolledlistbox.rb
index cd1f6f0f79..7543d557e3 100644
--- a/ext/tk/lib/tkextlib/iwidgets/scrolledlistbox.rb
+++ b/ext/tk/lib/tkextlib/iwidgets/scrolledlistbox.rb
@@ -42,7 +42,7 @@ class Tk::Iwidgets::Scrolledlistbox
end
def method_missing(id, *args)
- if @listbox.methods.include?(id.id2name)
+ if @listbox.respond_to?(id)
@listbox.__send__(id, *args)
else
super(id, *args)
diff --git a/ext/tk/lib/tkextlib/iwidgets/scrolledtext.rb b/ext/tk/lib/tkextlib/iwidgets/scrolledtext.rb
index fdafc8dc7f..d6436d202a 100644
--- a/ext/tk/lib/tkextlib/iwidgets/scrolledtext.rb
+++ b/ext/tk/lib/tkextlib/iwidgets/scrolledtext.rb
@@ -37,7 +37,7 @@ class Tk::Iwidgets::Scrolledtext
end
def method_missing(id, *args)
- if @text.methods.include?(id.id2name)
+ if @text.respond_to?(id)
@text.__send__(id, *args)
else
super(id, *args)
@@ -116,7 +116,7 @@ class Tk::Iwidgets::Scrolledtext
get('-displaychars', *index)
end
- def image_cget(index, slot)
+ def image_cget_strict(index, slot)
case slot.to_s
when 'text', 'label', 'show', 'data', 'file'
_fromUTF8(tk_send_without_enc('image', 'cget',
@@ -127,6 +127,27 @@ class Tk::Iwidgets::Scrolledtext
"-#{slot}")))
end
end
+ def image_cget(index, slot)
+ unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ image_cget_strict(index, slot)
+ else
+ begin
+ image_cget_strict(index, slot)
+ rescue => e
+ begin
+ if current_image_configinfo.has_key?(slot.to_s)
+ # error on known option
+ fail e
+ else
+ # unknown option
+ nil
+ end
+ rescue
+ fail e # tag error
+ end
+ end
+ end
+ end
def image_configure(index, slot, value=None)
if slot.kind_of? Hash
@@ -322,6 +343,11 @@ class Tk::Iwidgets::Scrolledtext
def _ktext_length(txt)
+ if TkCore::WITH_ENCODING ### Ruby 1.9 !!!!!!!!!!!!!
+ return txt.length
+ end
+ ###########################
+
if $KCODE !~ /n/i
return txt.gsub(/[^\Wa-zA-Z_\d]/, ' ').length
end
diff --git a/ext/tk/lib/tkextlib/iwidgets/selectionbox.rb b/ext/tk/lib/tkextlib/iwidgets/selectionbox.rb
index bb81fcca5e..bf9b5ec30a 100644
--- a/ext/tk/lib/tkextlib/iwidgets/selectionbox.rb
+++ b/ext/tk/lib/tkextlib/iwidgets/selectionbox.rb
@@ -59,7 +59,7 @@ class Tk::Iwidgets::Selectionbox
self
end
- # based on TkListbox ( and TkTextWin )
+ # based on Tk::Listbox ( and TkTextWin )
def curselection
list(tk_send_without_enc('curselection'))
end
diff --git a/ext/tk/lib/tkextlib/iwidgets/selectiondialog.rb b/ext/tk/lib/tkextlib/iwidgets/selectiondialog.rb
index ab790e97a6..f772ecf8c2 100644
--- a/ext/tk/lib/tkextlib/iwidgets/selectiondialog.rb
+++ b/ext/tk/lib/tkextlib/iwidgets/selectiondialog.rb
@@ -49,7 +49,7 @@ class Tk::Iwidgets::Selectiondialog
self
end
- # based on TkListbox ( and TkTextWin )
+ # based on Tk::Listbox ( and TkTextWin )
def curselection
list(tk_send_without_enc('curselection'))
end
diff --git a/ext/tk/lib/tkextlib/iwidgets/spinner.rb b/ext/tk/lib/tkextlib/iwidgets/spinner.rb
index 174b9bd506..aeee5c9038 100644
--- a/ext/tk/lib/tkextlib/iwidgets/spinner.rb
+++ b/ext/tk/lib/tkextlib/iwidgets/spinner.rb
@@ -37,6 +37,25 @@ class Tk::Iwidgets::Spinner
[ ?w, TkComm.method(:window) ],
nil
]
+
+=begin
+ # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
+ KEY_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String)
+ end
+ inf
+ }
+
+ PROC_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ end
+ inf
+ }
+=end
+
_setup_subst_table(KEY_TBL, PROC_TBL);
end
diff --git a/ext/tk/lib/tkextlib/iwidgets/tabnotebook.rb b/ext/tk/lib/tkextlib/iwidgets/tabnotebook.rb
index 0d9715f87b..dbb90e5102 100644
--- a/ext/tk/lib/tkextlib/iwidgets/tabnotebook.rb
+++ b/ext/tk/lib/tkextlib/iwidgets/tabnotebook.rb
@@ -47,12 +47,13 @@ class Tk::Iwidgets::Tabnotebook
end
alias pagecget itemcget
+ alias pagecget_strict itemcget_strict
alias pageconfigure itemconfigure
alias pageconfiginfo itemconfiginfo
alias current_pageconfiginfo current_itemconfiginfo
- private :itemcget, :itemconfigure
- private :itemconfiginfo, :current_itemconfiginfo
+ private :itemcget, :itemcget_strict
+ private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo
####################################
@@ -116,6 +117,11 @@ class Tk::Iwidgets::Tabnotebook
self
end
+ def show_tab(idx)
+ @tabset.show_tab(idx)
+ self
+ end
+
def scrollcommand(cmd=Proc.new)
configure_cmd 'scrollcommand', cmd
self
@@ -147,7 +153,12 @@ class Tk::Iwidgets::Tabnotebook
def view(*index)
if index.size == 0
- window(tk_send_without_enc('view'))
+ idx = num_or_str(tk_send_without_enc('view'))
+ if idx.kind_of?(Fixnum) && idx < 0
+ nil
+ else
+ idx
+ end
else
tk_send_without_enc('view', *index)
self
@@ -161,8 +172,8 @@ class Tk::Iwidgets::Tabnotebook
end
alias xview_moveto view_moveto
alias yview_moveto view_moveto
- def view_scroll(*index)
- view('scroll', *index)
+ def view_scroll(index, what='pages')
+ view('scroll', index, what)
end
alias xview_scroll view_scroll
alias yview_scroll view_scroll
diff --git a/ext/tk/lib/tkextlib/iwidgets/tabset.rb b/ext/tk/lib/tkextlib/iwidgets/tabset.rb
index 54e56d0514..300ba9dee0 100644
--- a/ext/tk/lib/tkextlib/iwidgets/tabset.rb
+++ b/ext/tk/lib/tkextlib/iwidgets/tabset.rb
@@ -42,12 +42,13 @@ class Tk::Iwidgets::Tabset
end
alias tabcget itemcget
+ alias tabcget_strict itemcget_strict
alias tabconfigure itemconfigure
alias tabconfiginfo itemconfiginfo
alias current_tabconfiginfo current_itemconfiginfo
- private :itemcget, :itemconfigure
- private :itemconfiginfo, :current_itemconfiginfo
+ private :itemcget, :itemcget_strict
+ private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo
####################################
@@ -96,4 +97,48 @@ class Tk::Iwidgets::Tabset
tk_call(@path, 'select', index(idx))
self
end
+
+ def show_tab(idx)
+ if index(idx) == 0
+ self.start = 0
+ return
+ end
+
+ reutrn unless @canvas ||= self.winfo_children[0]
+
+ delta = 1 if (delta = cget(:gap)) == 'overlap' ||
+ (delta = self.winfo_pixels(delta) + 1) <= 0
+
+ case cget(:tabpos)
+ when 's', 'n'
+ if (head = tabcget(idx, :left)) < 0
+ self.start -= head
+ return
+ end
+ tabs_size = @canvas.winfo_width
+ tab_start, tab_end = @canvas .
+ find_overlapping(head, 0, head + delta, @canvas.winfo_height) .
+ find_all{|id| @canvas.itemtype(id) == TkcPolygon} .
+ map!{|id| bbox = @canvas.bbox(id); [bbox[0], bbox[2]]} . max
+
+ when 'e', 'w'
+ if (head = tabcget(idx, :top)) < 0
+ self.start -= head
+ return
+ end
+ tabs_size = @canvas.winfo_height
+ tab_start, tab_end = @canvas .
+ find_overlapping(0, head, @canvas.winfo_width, head + delta) .
+ find_all{|id| @canvas.itemtype(id) == TkcPolygon} .
+ map!{|id| bbox = @canvas.bbox(id); [bbox[1], bbox[3]]} . max
+ end
+
+ if (size = tab_end - tab_start + 1) > tabs_size
+ self.start -= tab_start
+ elsif head + size > tabs_size
+ self.start -= head + size - tabs_size
+ end
+
+ self
+ end
end
diff --git a/ext/tk/lib/tkextlib/tcllib/autoscroll.rb b/ext/tk/lib/tkextlib/tcllib/autoscroll.rb
index 6940a9174c..7db3c2e2b7 100644
--- a/ext/tk/lib/tkextlib/tcllib/autoscroll.rb
+++ b/ext/tk/lib/tkextlib/tcllib/autoscroll.rb
@@ -108,7 +108,7 @@ module Tk
end
end
-class TkScrollbar
+class Tk::Scrollbar
def autoscroll
# Arranges for the already existing scrollbar to be mapped
# and unmapped as needed.
diff --git a/ext/tk/lib/tkextlib/tcllib/ctext.rb b/ext/tk/lib/tkextlib/tcllib/ctext.rb
index 70a45dd8e7..9014037f3d 100644
--- a/ext/tk/lib/tkextlib/tcllib/ctext.rb
+++ b/ext/tk/lib/tkextlib/tcllib/ctext.rb
@@ -15,7 +15,7 @@ TkPackage.require('ctext')
module Tk
module Tcllib
- class CText < TkText
+ class CText < Tk::Text
PACKAGE_NAME = 'ctext'.freeze
def self.package_name
PACKAGE_NAME
diff --git a/ext/tk/lib/tkextlib/tcllib/datefield.rb b/ext/tk/lib/tkextlib/tcllib/datefield.rb
index bd84488101..2244dd7a9a 100644
--- a/ext/tk/lib/tkextlib/tcllib/datefield.rb
+++ b/ext/tk/lib/tkextlib/tcllib/datefield.rb
@@ -24,7 +24,7 @@ TkPackage.require('datefield')
module Tk
module Tcllib
- class Datefield < TkEntry
+ class Datefield < Tk::Entry
PACKAGE_NAME = 'datefield'.freeze
def self.package_name
PACKAGE_NAME
diff --git a/ext/tk/lib/tkextlib/tcllib/getstring.rb b/ext/tk/lib/tkextlib/tcllib/getstring.rb
index bf5e54e8cf..fc5d8b26d9 100644
--- a/ext/tk/lib/tkextlib/tcllib/getstring.rb
+++ b/ext/tk/lib/tkextlib/tcllib/getstring.rb
@@ -87,7 +87,7 @@ class Tk::Tcllib::GetString_Dialog
@variable.value
end
- def cget(slot)
+ def cget_strict(slot)
slot = slot.to_s
if slot == 'text'
@text
@@ -95,6 +95,9 @@ class Tk::Tcllib::GetString_Dialog
@keys[slot]
end
end
+ def cget(slot)
+ cget_strict(slot)
+ end
def configure(slot, value=None)
if slot.kind_of?(Hash)
diff --git a/ext/tk/lib/tkextlib/tcllib/ico.rb b/ext/tk/lib/tkextlib/tcllib/ico.rb
index 3beeb11a4d..8c92926a4c 100644
--- a/ext/tk/lib/tkextlib/tcllib/ico.rb
+++ b/ext/tk/lib/tkextlib/tcllib/ico.rb
@@ -94,8 +94,10 @@ class Tk::Tcllib::ICO
if keys.key?('name')
@path = keys['name'].to_s
else
- @path = Tk_Image_ID.join(TkCore::INTERP._ip_id_)
- Tk_Image_ID[1].succ!
+ Tk_Image_ID.mutex.synchronize{
+ @path = Tk_Image_ID.join(TkCore::INTERP._ip_id_)
+ Tk_Image_ID[1].succ!
+ }
end
tk_call_without_enc('::ico::getIcon', file, index, '-name', @path,
'-format', 'image', *hash_kv(keys, true))
diff --git a/ext/tk/lib/tkextlib/tcllib/ip_entry.rb b/ext/tk/lib/tkextlib/tcllib/ip_entry.rb
index 8c9e0bd683..c4b8240c04 100644
--- a/ext/tk/lib/tkextlib/tcllib/ip_entry.rb
+++ b/ext/tk/lib/tkextlib/tcllib/ip_entry.rb
@@ -18,7 +18,7 @@ TkPackage.require('ipentry')
module Tk
module Tcllib
- class IP_Entry < TkEntry
+ class IP_Entry < Tk::Entry
PACKAGE_NAME = 'ipentry'.freeze
def self.package_name
PACKAGE_NAME
diff --git a/ext/tk/lib/tkextlib/tcllib/plotchart.rb b/ext/tk/lib/tkextlib/tcllib/plotchart.rb
index f5f344ceb3..06ab20f3e6 100644
--- a/ext/tk/lib/tkextlib/tcllib/plotchart.rb
+++ b/ext/tk/lib/tkextlib/tcllib/plotchart.rb
@@ -225,7 +225,7 @@ module Tk::Tcllib::Plotchart
end
############################
- class XYPlot < TkCanvas
+ class XYPlot < Tk::Canvas
include ChartMethod
TkCommandNames = [
@@ -247,7 +247,7 @@ module Tk::Tcllib::Plotchart
@xaxis = args.shift
@yaxis = args.shift
- if parent.kind_of?(TkCanvas)
+ if parent.kind_of?(Tk::Canvas)
@path = parent.path
else
super(parent, *args) # create canvas widget
@@ -265,7 +265,9 @@ module Tk::Tcllib::Plotchart
private :_create_chart
def __destroy_hook__
- Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path)
+ Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.mutex.synchronize{
+ Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path)
+ }
end
def plot(series, x, y)
@@ -337,7 +339,7 @@ module Tk::Tcllib::Plotchart
end
############################
- class PolarPlot < TkCanvas
+ class PolarPlot < Tk::Canvas
include ChartMethod
TkCommandNames = [
@@ -356,7 +358,7 @@ module Tk::Tcllib::Plotchart
@radius_data = args.shift
- if parent.kind_of?(TkCanvas)
+ if parent.kind_of?(Tk::Canvas)
@path = parent.path
else
super(parent, *args) # create canvas widget
@@ -374,7 +376,9 @@ module Tk::Tcllib::Plotchart
private :_create_chart
def __destroy_hook__
- Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path)
+ Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.mutex.synchronize{
+ Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path)
+ }
end
def plot(series, radius, angle)
@@ -395,7 +399,7 @@ module Tk::Tcllib::Plotchart
Polarplot = PolarPlot
############################
- class IsometricPlot < TkCanvas
+ class IsometricPlot < Tk::Canvas
include ChartMethod
TkCommandNames = [
@@ -430,7 +434,7 @@ module Tk::Tcllib::Plotchart
@stepsize = args.shift
end
- if parent.kind_of?(TkCanvas)
+ if parent.kind_of?(Tk::Canvas)
@path = parent.path
else
super(parent, *args) # create canvas widget
@@ -475,7 +479,7 @@ module Tk::Tcllib::Plotchart
Isometricplot = IsometricPlot
############################
- class Plot3D < TkCanvas
+ class Plot3D < Tk::Canvas
include ChartMethod
TkCommandNames = [
@@ -500,7 +504,7 @@ module Tk::Tcllib::Plotchart
@yaxis = args.shift
@zaxis = args.shift
- if parent.kind_of?(TkCanvas)
+ if parent.kind_of?(Tk::Canvas)
@path = parent.path
else
super(parent, *args) # create canvas widget
@@ -557,7 +561,7 @@ module Tk::Tcllib::Plotchart
end
############################
- class Piechart < TkCanvas
+ class Piechart < Tk::Canvas
include ChartMethod
TkCommandNames = [
@@ -566,7 +570,7 @@ module Tk::Tcllib::Plotchart
].freeze
def initialize(*args) # args := ([parent] [, keys])
- if args[0].kind_of?(TkCanvas)
+ if args[0].kind_of?(Tk::Canvas)
parent = args.shift
@path = parent.path
else
@@ -588,7 +592,7 @@ module Tk::Tcllib::Plotchart
end
############################
- class Barchart < TkCanvas
+ class Barchart < Tk::Canvas
include ChartMethod
TkCommandNames = [
@@ -626,7 +630,7 @@ module Tk::Tcllib::Plotchart
@series_size = args.shift
end
- if parent.kind_of?(TkCanvas)
+ if parent.kind_of?(Tk::Canvas)
@path = parent.path
else
super(parent, *args) # create canvas widget
@@ -645,7 +649,9 @@ module Tk::Tcllib::Plotchart
private :_create_chart
def __destroy_hook__
- Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path)
+ Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.mutex.synchronize{
+ Tk::Tcllib::Plotchart::PlotSeries::SeriesID_TBL.delete(@path)
+ }
end
def plot(series, dat, col=None)
@@ -672,7 +678,7 @@ module Tk::Tcllib::Plotchart
end
############################
- class Timechart < TkCanvas
+ class Timechart < Tk::Canvas
include ChartMethod
TkCommandNames = [
@@ -699,7 +705,7 @@ module Tk::Tcllib::Plotchart
@time_end = args.shift
@items = args.shift
- if parent.kind_of?(TkCanvas)
+ if parent.kind_of?(Tk::Canvas)
@path = parent.path
else
super(parent, *args) # create canvas widget
@@ -733,7 +739,7 @@ module Tk::Tcllib::Plotchart
end
############################
- class Gnattchart < TkCanvas
+ class Gnattchart < Tk::Canvas
include ChartMethod
TkCommandNames = [
@@ -772,7 +778,7 @@ module Tk::Tcllib::Plotchart
@text_width = None
end
- if parent.kind_of?(TkCanvas)
+ if parent.kind_of?(Tk::Canvas)
@path = parent.path
else
super(parent, *args) # create canvas widget
@@ -834,23 +840,38 @@ module Tk::Tcllib::Plotchart
############################
class PlotSeries < TkObject
SeriesID_TBL = TkCore::INTERP.create_table
- Series_ID = ['series'.freeze, '00000'.taint].freeze
- TkCore::INTERP.init_ip_env{ SeriesID_TBL.clear }
+
+ (Series_ID = ['series'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+ TkCore::INTERP.init_ip_env{
+ SeriesID_TBL.mutex.synchronize{ SeriesID_TBL.clear }
+ }
def self.id2obj(chart, id)
path = chart.path
- return id unless SeriesID_TBL[path]
- SeriesID_TBL[path][id]? SeriesID_TBL[path][id]: id
+ SeriesID_TBL.mutex.synchronize{
+ if SeriesID_TBL[path]
+ SeriesID_TBL[path][id]? SeriesID_TBL[path][id]: id
+ else
+ id
+ end
+ }
end
def initialize(chart, keys=nil)
@parent = @chart_obj = chart
@ppath = @chart_obj.path
- @path = @series = @id = Series_ID.join(TkCore::INTERP._ip_id_)
- # SeriesID_TBL[@id] = self
- SeriesID_TBL[@ppath] = {} unless SeriesID_TBL[@ppath]
- SeriesID_TBL[@ppath][@id] = self
- Series_ID[1].succ!
+ Series_ID.mutex.synchronize{
+ @path = @series = @id = Series_ID.join(TkCore::INTERP._ip_id_)
+ Series_ID[1].succ!
+ }
+ SeriesID_TBL.mutex.synchronize{
+ SeriesID_TBL[@ppath] ||= {}
+ SeriesID_TBL[@ppath][@id] = self
+ }
dataconfig(keys) if keys.kind_of?(Hash)
end
diff --git a/ext/tk/lib/tkextlib/tcllib/swaplist.rb b/ext/tk/lib/tkextlib/tcllib/swaplist.rb
index 97de0a27c1..1c813e36da 100644
--- a/ext/tk/lib/tkextlib/tcllib/swaplist.rb
+++ b/ext/tk/lib/tkextlib/tcllib/swaplist.rb
@@ -90,7 +90,7 @@ class Tk::Tcllib::Swaplist_Dialog
end
alias selected value
- def cget(slot)
+ def cget_strict(slot)
slot = slot.to_s
if slot == 'complete_list'
@complete_list
@@ -100,6 +100,9 @@ class Tk::Tcllib::Swaplist_Dialog
@keys[slot]
end
end
+ def cget(slot)
+ cget_strict(slot)
+ end
def configure(slot, value=None)
if slot.kind_of?(Hash)
diff --git a/ext/tk/lib/tkextlib/tcllib/tablelist.rb b/ext/tk/lib/tkextlib/tcllib/tablelist.rb
index 42435a1971..efeb8fbbac 100644
--- a/ext/tk/lib/tkextlib/tcllib/tablelist.rb
+++ b/ext/tk/lib/tkextlib/tcllib/tablelist.rb
@@ -23,5 +23,5 @@ else
# TkPackage.require('Tablelist', '4.2')
TkPackage.require('Tablelist')
- requrie 'tkextlib/tcllib/tablelist_core'
+ require 'tkextlib/tcllib/tablelist_core'
end
diff --git a/ext/tk/lib/tkextlib/tcllib/tablelist_core.rb b/ext/tk/lib/tkextlib/tcllib/tablelist_core.rb
index a939a58331..d7a6c97210 100644
--- a/ext/tk/lib/tkextlib/tcllib/tablelist_core.rb
+++ b/ext/tk/lib/tkextlib/tcllib/tablelist_core.rb
@@ -70,6 +70,9 @@ module Tk::Tcllib::TablelistItemConfig
def cell_cget(tagOrId, option)
itemcget(['cell', tagOrId], option)
end
+ def cell_cget_strict(tagOrId, option)
+ itemcget_strict(['cell', tagOrId], option)
+ end
def cell_configure(tagOrId, slot, value=None)
itemconfigure(['cell', tagOrId], slot, value)
end
@@ -80,6 +83,7 @@ module Tk::Tcllib::TablelistItemConfig
current_itemconfiginfo(['cell', tagOrId], slot)
end
alias cellcget cell_cget
+ alias cellcget_strict cell_cget_strict
alias cellconfigure cell_configure
alias cellconfiginfo cell_configinfo
alias current_cellconfiginfo current_cell_configinfo
@@ -87,6 +91,9 @@ module Tk::Tcllib::TablelistItemConfig
def column_cget(tagOrId, option)
itemcget(['column', tagOrId], option)
end
+ def column_cget_strict(tagOrId, option)
+ itemcget_strict(['column', tagOrId], option)
+ end
def column_configure(tagOrId, slot, value=None)
itemconfigure(['column', tagOrId], slot, value)
end
@@ -97,6 +104,7 @@ module Tk::Tcllib::TablelistItemConfig
current_itemconfiginfo(['column', tagOrId], slot)
end
alias columncget column_cget
+ alias columncget_strict column_cget_strict
alias columnconfigure column_configure
alias columnconfiginfo column_configinfo
alias current_columnconfiginfo current_column_configinfo
@@ -104,6 +112,9 @@ module Tk::Tcllib::TablelistItemConfig
def row_cget(tagOrId, option)
itemcget(['row', tagOrId], option)
end
+ def row_cget_strict(tagOrId, option)
+ itemcget_strict(['row', tagOrId], option)
+ end
def row_configure(tagOrId, slot, value=None)
itemconfigure(['row', tagOrId], slot, value)
end
@@ -114,12 +125,13 @@ module Tk::Tcllib::TablelistItemConfig
current_itemconfiginfo(['row', tagOrId], slot)
end
alias rowcget row_cget
+ alias rowcget_strict row_cget_strict
alias rowconfigure row_configure
alias rowconfiginfo row_configinfo
alias current_rowconfiginfo current_row_configinfo
- private :itemcget, :itemconfigure
- private :itemconfiginfo, :current_itemconfiginfo
+ private :itemcget, :itemcget_strict
+ private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo
end
class Tk::Tcllib::Tablelist
diff --git a/ext/tk/lib/tkextlib/tcllib/tkpiechart.rb b/ext/tk/lib/tkextlib/tcllib/tkpiechart.rb
index 92dde65ce7..b366e0198b 100644
--- a/ext/tk/lib/tkextlib/tcllib/tkpiechart.rb
+++ b/ext/tk/lib/tkextlib/tcllib/tkpiechart.rb
@@ -125,7 +125,9 @@ module Tk::Tcllib::Tkpiechart
def delete
tk_call_without_enc('::stooop::delete', @tag_key)
- CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path]
+ CItemID_TBL.mutex.synchronize{
+ CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path]
+ }
self
end
@@ -184,8 +186,10 @@ module Tk::Tcllib::Tkpiechart
@id = "slices(#{@tag_key})"
@tag = TkcNamedTag.new(@pie.canvas, @id)
- CItemID_TBL[@path] = {} unless CItemID_TBL[@path]
- CItemID_TBL[@path][@id] = self
+ CItemID_TBL.mutex.synchronize{
+ CItemID_TBL[@path] = {} unless CItemID_TBL[@path]
+ CItemID_TBL[@path][@id] = self
+ }
end
def tag_key
@@ -200,7 +204,9 @@ module Tk::Tcllib::Tkpiechart
def delete
tk_call_without_enc('pie::deleteSlice', @pie.tag_key, @tag_key)
- CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path]
+ CItemID_TBL.mutex.synchronize{
+ CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path]
+ }
@pie._delete_slice(self)
self
end
diff --git a/ext/tk/lib/tkextlib/tile.rb b/ext/tk/lib/tkextlib/tile.rb
index 690f93f029..60ea012cc0 100644
--- a/ext/tk/lib/tkextlib/tile.rb
+++ b/ext/tk/lib/tkextlib/tile.rb
@@ -4,6 +4,7 @@
#
require 'tk'
+require 'tk/ttk_selector'
# call setup script for general 'tkextlib' libraries
require 'tkextlib/setup.rb'
@@ -15,33 +16,66 @@ require 'tkextlib/tile/setup.rb'
# TkPackage.require('tile', '0.4')
# TkPackage.require('tile', '0.6')
# TkPackage.require('tile', '0.7')
-verstr = TkPackage.require('tile')
+if Tk::TK_MAJOR_VERSION > 8 ||
+ (Tk::TK_MAJOR_VERSION == 8 && Tk::TK_MINOR_VERSION >= 5)
+ TkPackage.require('tile') # for compatibility (version check of 'tile')
+ verstr = TkPackage.require('Ttk')
+else
+ verstr = TkPackage.require('tile')
+end
+
ver = verstr.split('.')
-if ver[0].to_i == 0 && ver[1].to_i <= 4
- # version 0.4 or former
- module Tk
- module Tile
- USE_TILE_NAMESPACE = true
- USE_TTK_NAMESPACE = false
- TILE_SPEC_VERSION_ID = 0
+if ver[0].to_i == 0
+ # Tile extension package
+ if ver[1].to_i <= 4
+ # version 0.4 or former
+ module Tk
+ module Tile
+ USE_TILE_NAMESPACE = true
+ USE_TTK_NAMESPACE = false
+ TILE_SPEC_VERSION_ID = 0
+ end
end
- end
-elsif ver[0].to_i == 0 && ver[1].to_i <= 6
- # version 0.5 -- version 0.6
- module Tk
- module Tile
- USE_TILE_NAMESPACE = true
- USE_TTK_NAMESPACE = true
- TILE_SPEC_VERSION_ID = 5
+ elsif ver[1].to_i <= 6
+ # version 0.5 -- version 0.6
+ module Tk
+ module Tile
+ USE_TILE_NAMESPACE = true
+ USE_TTK_NAMESPACE = true
+ TILE_SPEC_VERSION_ID = 5
+ end
+ end
+ elsif ver[1].to_i <= 7
+ module Tk
+ module Tile
+ USE_TILE_NAMESPACE = false
+ USE_TTK_NAMESPACE = true
+ TILE_SPEC_VERSION_ID = 7
+ end
+ end
+ else
+ # version 0.8 or later
+ module Tk
+ module Tile
+ USE_TILE_NAMESPACE = false
+ USE_TTK_NAMESPACE = true
+ TILE_SPEC_VERSION_ID = 8
+ end
end
end
+
+ module Tk::Tile
+ PACKAGE_NAME = 'tile'.freeze
+ end
else
- # version 0.7 or later
+ # Ttk package merged Tcl/Tk core (Tcl/Tk 8.5+)
module Tk
module Tile
USE_TILE_NAMESPACE = false
USE_TTK_NAMESPACE = true
- TILE_SPEC_VERSION_ID = 7
+ TILE_SPEC_VERSION_ID = 8
+
+ PACKAGE_NAME = 'Ttk'.freeze
end
end
end
@@ -51,30 +85,114 @@ module Tk
module Tile
TkComm::TkExtlibAutoloadModule.unshift(self)
- PACKAGE_NAME = 'tile'.freeze
def self.package_name
PACKAGE_NAME
end
def self.package_version
begin
- TkPackage.require('tile')
+ TkPackage.require(PACKAGE_NAME)
rescue
''
end
end
def self.__Import_Tile_Widgets__!
+ warn 'Warning: "Tk::Tile::__Import_Tile_Widgets__!" is obsolete.' <<
+ ' To control default widget set, use "Tk.default_widget_set = :Ttk"'
Tk.tk_call('namespace', 'import', '-force', 'ttk::*')
end
- def self.load_images(imgdir, pat=TkComm::None)
- images = Hash[*TkComm.simplelist(Tk.tk_call('::tile::LoadImages',
- imgdir, pat))]
- images.keys.each{|k|
- images[k] = TkPhotoImage.new(:imagename=>images[k],
- :without_creating=>true)
+ def self.__define_LoadImages_proc_for_compatibility__!
+ # Ttk 8.5 (Tile 0.8) lost 'LoadImages' utility procedure.
+ # So, some old scripts doen't work, because those scripts use the
+ # procedure to define local styles.
+ # Of course, rewriting such Tcl/Tk scripts isn't difficult for
+ # Tcl/Tk users. However, it may be troublesome for Ruby/Tk users
+ # who use such Tcl/Tk scripts as it is.
+ # This method may help Ruby/Tk users who don't want to modify old
+ # Tcl/Tk scripts for the latest version of Ttk (Tile) extension.
+ # This method defines a comaptible 'LoadImages' procedure on the
+ # Tcl/Tk interpreter working under Ruby/Tk.
+ # Please give attention to use this method. It may conflict with
+ # some definitions on Tcl/Tk scripts.
+ klass_name = self.name
+ proc_name = 'LoadImages'
+ if Tk::Tile::USE_TTK_NAMESPACE
+ ns_list = ['::tile']
+ if Tk.info(:commands, "::ttk::#{proc_name}").empty?
+ ns_list << '::ttk'
+ end
+ else # Tk::Tile::USE_TILE_NAMESPACE
+ ns_list = ['::ttk']
+ if Tk.info(:commands, "::tile::#{proc_name}").empty?
+ ns_list << '::tile'
+ end
+ end
+
+ ns_list.each{|ns|
+ cmd = "#{ns}::#{proc_name}"
+ unless Tk.info(:commands, cmd).empty?
+ #fail RuntimeError, "can't define '#{cmd}' command (already exist)"
+
+ # do nothing !!!
+ warn "Warning: can't define '#{cmd}' command (already exist)" if $DEBUG
+ next
+ end
+ TkNamespace.eval(ns){
+ TkCore::INTERP.add_tk_procs(proc_name, 'imgdir {patterns {*.gif}}',
+ <<-'EOS')
+ foreach pattern $patterns {
+ foreach file [glob -directory $imgdir $pattern] {
+ set img [file tail [file rootname $file]]
+ if {![info exists images($img)]} {
+ set images($img) [image create photo -file $file]
+ }
+ }
+ }
+ return [array get images]
+ EOS
+ }
}
+ end
+
+ def self.load_images(imgdir, pat=nil)
+ if Tk::Tile::TILE_SPEC_VERSION_ID < 8
+ if Tk::Tile::USE_TTK_NAMESPACE
+ cmd = '::ttk::LoadImages'
+ else # Tk::Tile::USE_TILE_NAMESPACE
+ cmd = '::tile::LoadImages'
+ end
+ pat ||= TkComm::None
+ images = Hash[*TkComm.simplelist(Tk.tk_call(cmd, imgdir, pat))]
+ images.keys.each{|k|
+ images[k] = TkPhotoImage.new(:imagename=>images[k],
+ :without_creating=>true)
+ }
+ else ## TILE_SPEC_VERSION_ID >= 8
+ pat ||= '*.gif'
+ if pat.kind_of?(Array)
+ pat_list = pat
+ else
+ pat_list = [ pat ]
+ end
+ Dir.chdir(imgdir){
+ pat_list.each{|pat|
+ Dir.glob(pat).each{|f|
+ img = File.basename(f, '.*')
+ unless TkComm.bool(Tk.info('exists', "images(#{img})"))
+ Tk.tk_call('set', "images(#{img})",
+ Tk.tk_call('image', 'create', 'photo', '-file', f))
+ end
+ }
+ }
+ }
+ images = Hash[*TkComm.simplelist(Tk.tk_call('array', 'get', 'images'))]
+ images.keys.each{|k|
+ images[k] = TkPhotoImage.new(:imagename=>images[k],
+ :without_creating=>true)
+ }
+ end
images
end
@@ -83,12 +201,53 @@ module Tk
args.map!{|arg| TkComm._get_eval_string(arg)}.join('.')
end
- module KeyNav
- def self.enableMnemonics(w)
- Tk.tk_call('::keynav::enableMnemonics', w)
+ def self.themes(glob_ptn = nil)
+ if TILE_SPEC_VERSION_ID < 8 && Tk.info(:commands, '::ttk::themes').empty?
+ fail RuntimeError, 'not support glob option' if glob_ptn
+ cmd = ['::tile::availableThemes']
+ else
+ glob_ptn = '*' unless glob_ptn
+ cmd = ['::ttk::themes', glob_ptn]
+ end
+
+ begin
+ TkComm.simplelist(Tk.tk_call_without_enc(*cmd))
+ rescue
+ TkComm.simplelist(Tk.tk_call('lsearch', '-all', '-inline',
+ Tk::Tile::Style.theme_names,
+ glob_ptn))
+ end
+ end
+
+ def self.set_theme(theme)
+ if TILE_SPEC_VERSION_ID < 8 && Tk.info(:commands, '::ttk::setTheme').empty?
+ cmd = '::tile::setTheme'
+ else
+ cmd = '::ttk::setTheme'
+ end
+
+ begin
+ Tk.tk_call_without_enc(cmd, theme)
+ rescue
+ Tk::Tile::Style.theme_use(theme)
end
- def self.defaultButton(w)
- Tk.tk_call('::keynav::defaultButton', w)
+ end
+
+ module KeyNav
+ if Tk::Tile::TILE_SPEC_VERSION_ID < 8
+ def self.enableMnemonics(w)
+ Tk.tk_call('::keynav::enableMnemonics', w)
+ end
+ def self.defaultButton(w)
+ Tk.tk_call('::keynav::defaultButton', w)
+ end
+ else # dummy
+ def self.enableMnemonics(w)
+ ""
+ end
+ def self.defaultButton(w)
+ ""
+ end
end
end
@@ -103,6 +262,12 @@ module Tk
Menu = 'TkMenuFont'
SmallCaption = 'TkSmallCaptionFont'
Icon = 'TkIconFont'
+
+ TkFont::SYSTEM_FONT_NAMES.add [
+ 'TkDefaultFont', 'TkTextFont', 'TkHeadingFont',
+ 'TkCaptionFont', 'TkTooltipFont', 'TkFixedFont',
+ 'TkMenuFont', 'TkSmallCaptionFont', 'TkIconFont'
+ ]
end
module ParseStyleLayout
@@ -141,7 +306,7 @@ module Tk
end
private :__val2ruby_optkeys
- def instate(state, script=nil, &b)
+ def ttk_instate(state, script=nil, &b)
if script
tk_send('instate', state, script)
elsif b
@@ -150,14 +315,30 @@ module Tk
bool(tk_send('instate', state))
end
end
+ alias tile_instate ttk_instate
- def state(state=nil)
+ def ttk_state(state=nil)
if state
tk_send('state', state)
else
list(tk_send('state'))
end
end
+ alias tile_state ttk_state
+
+ def ttk_identify(x, y)
+ ret = tk_send_without_enc('identify', x, y)
+ (ret.empty?)? nil: ret
+ end
+ alias tile_identify ttk_identify
+
+ # remove instate/state/identify method
+ # to avoid the conflict with widget options
+ if Tk.const_defined?(:USE_OBSOLETE_TILE_STATE_METHOD) && Tk::USE_OBSOLETE_TILE_STATE_METHOD
+ alias instate ttk_instate
+ alias state ttk_state
+ alias identify ttk_identify
+ end
end
######################################
@@ -183,18 +364,24 @@ module Tk
autoload :TLabelframe, 'tkextlib/tile/tlabelframe'
autoload :Labelframe, 'tkextlib/tile/tlabelframe'
+ autoload :TLabelFrame, 'tkextlib/tile/tlabelframe'
+ autoload :LabelFrame, 'tkextlib/tile/tlabelframe'
autoload :TLabel, 'tkextlib/tile/tlabel'
autoload :Label, 'tkextlib/tile/tlabel'
autoload :TMenubutton, 'tkextlib/tile/tmenubutton'
autoload :Menubutton, 'tkextlib/tile/tmenubutton'
+ autoload :TMenuButton, 'tkextlib/tile/tmenubutton'
+ autoload :MenuButton, 'tkextlib/tile/tmenubutton'
autoload :TNotebook, 'tkextlib/tile/tnotebook'
autoload :Notebook, 'tkextlib/tile/tnotebook'
autoload :TPaned, 'tkextlib/tile/tpaned'
autoload :Paned, 'tkextlib/tile/tpaned'
+ autoload :PanedWindow, 'tkextlib/tile/tpaned'
+ autoload :Panedwindow, 'tkextlib/tile/tpaned'
autoload :TProgressbar, 'tkextlib/tile/tprogressbar'
autoload :Progressbar, 'tkextlib/tile/tprogressbar'
@@ -211,6 +398,8 @@ module Tk
autoload :TScrollbar, 'tkextlib/tile/tscrollbar'
autoload :Scrollbar, 'tkextlib/tile/tscrollbar'
+ autoload :XScrollbar, 'tkextlib/tile/tscrollbar'
+ autoload :YScrollbar, 'tkextlib/tile/tscrollbar'
autoload :TSeparator, 'tkextlib/tile/tseparator'
autoload :Separator, 'tkextlib/tile/tseparator'
@@ -218,8 +407,13 @@ module Tk
autoload :TSquare, 'tkextlib/tile/tsquare'
autoload :Square, 'tkextlib/tile/tsquare'
+ autoload :SizeGrip, 'tkextlib/tile/sizegrip'
+ autoload :Sizegrip, 'tkextlib/tile/sizegrip'
+
autoload :Treeview, 'tkextlib/tile/treeview'
autoload :Style, 'tkextlib/tile/style'
end
end
+
+Ttk = Tk::Tile
diff --git a/ext/tk/lib/tkextlib/tile/dialog.rb b/ext/tk/lib/tkextlib/tile/dialog.rb
index f8ddf62598..ef2d1fe577 100644
--- a/ext/tk/lib/tkextlib/tile/dialog.rb
+++ b/ext/tk/lib/tkextlib/tile/dialog.rb
@@ -51,12 +51,24 @@ class Tk::Tile::Dialog
alias display show
def client_frame
- window(tk_call_without_enc('::ttk::dialog::clientframe'))
+ window(tk_call_without_enc('::ttk::dialog::clientframe', @path))
end
+ def cget_strict(slot)
+ @keys[slot.to_s]
+ end
+ def cget(slot)
+ @keys[slot.to_s]
+ end
+=begin
def cget(slot)
- @keys[slot]
+ unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ cget_strict(slot)
+ else
+ cget_strict(slot) rescue nil
+ end
end
+=end
def configure(slot, value=None)
if slot.kind_of?(Hash)
diff --git a/ext/tk/lib/tkextlib/tile/sizegrip.rb b/ext/tk/lib/tkextlib/tile/sizegrip.rb
new file mode 100644
index 0000000000..c5068919a4
--- /dev/null
+++ b/ext/tk/lib/tkextlib/tile/sizegrip.rb
@@ -0,0 +1,29 @@
+#
+# ttk::sizegrip widget
+# by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)
+#
+require 'tk'
+require 'tkextlib/tile.rb'
+
+module Tk
+ module Tile
+ class SizeGrip < TkWindow
+ end
+ Sizegrip = SizeGrip
+ end
+end
+
+Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Sizegrip, :TkSizegrip, :TkSizeGrip)
+
+
+class Tk::Tile::SizeGrip < TkWindow
+ include Tk::Tile::TileWidget
+
+ TkCommandNames = ['::ttk::sizegrip'.freeze].freeze
+ WidgetClassName = 'TSizegrip'.freeze
+ WidgetClassNames[WidgetClassName] = self
+
+ def self.style(*args)
+ [self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.')
+ end
+end
diff --git a/ext/tk/lib/tkextlib/tile/style.rb b/ext/tk/lib/tkextlib/tile/style.rb
index 485a36d7d6..ca7ee99c32 100644
--- a/ext/tk/lib/tkextlib/tile/style.rb
+++ b/ext/tk/lib/tkextlib/tile/style.rb
@@ -17,6 +17,145 @@ module Tk::Tile::Style
end
class << Tk::Tile::Style
+ if Tk::Tile::TILE_SPEC_VERSION_ID < 8
+ TkCommandNames = ['style'.freeze].freeze
+
+ # --- Tk::Tile::Style.__define_wrapper_proc_for_compatibility__! ---
+ # On Ttk (Tile) extension, 'style' command has imcompatible changes
+ # depend on the version of the extention. It requires modifying the
+ # Tcl/Tk scripts to define local styles. The rule for modification
+ # is a simple one. But, if users want to keep compatibility between
+ # versions of the extension, they will have to contrive to do that.
+ # It may be troublesome, especially for Ruby/Tk users.
+ # This method may help such work. This method make some definitions
+ # on the Tcl/Tk interpreter to work with different version of style
+ # command format. Please give attention to use this method. It may
+ # conflict with some definitions on Tcl/Tk scripts.
+ if Tk::Tile::TILE_SPEC_VERSION_ID < 7
+ def __define_wrapper_proc_for_compatibility__!
+ __define_themes_and_setTheme_proc__!
+
+ unless Tk.info(:commands, '::ttk::style').empty?
+ # fail RuntimeError,
+ # "can't define '::ttk::style' command (already exist)"
+
+ # do nothing !!!
+ warn "Warning: can't define '::ttk::style' command (already exist)" if $DEBUG
+ return
+ end
+ TkCore::INTERP.add_tk_procs('::ttk::style', 'args', <<-'EOS')
+ if [string equal [lrange $args 0 1] {element create}] {
+ if [string equal [lindex $args 3] image] {
+ set spec [lindex $args 4]
+ set map [lrange $spec 1 end]
+ if [llength $map] {
+ # return [eval [concat [list ::style element create [lindex $args 2] image [lindex $spec 0] -map $map] [lrange $args 5 end]]]
+ return [uplevel 1 [list ::style element create [lindex $args 2] image [lindex $spec 0] -map $map] [lrange $args 5 end]]
+ }
+ }
+ }
+ # return [eval "::style $args"]
+ return [uplevel 1 ::style $args]
+ EOS
+ #########################
+ end
+ else ### TILE_SPEC_VERSION_ID == 7
+ def __define_wrapper_proc_for_compatibility__!
+ __define_themes_and_setTheme_proc__!
+
+ unless Tk.info(:commands, '::ttk::style').empty?
+ # fail RuntimeError,
+ # "can't define '::ttk::style' command (already exist)"
+
+ # do nothing !!!
+ warn "Warning: can't define '::ttk::style' command (already exist)" if $DEBUG
+ return
+ end
+ TkCore::INTERP.add_tk_procs('::ttk::style', 'args', <<-'EOS')
+ if [string equal [lrange $args 0 1] {element create}] {
+ if [string equal [lindex $args 3] image] {
+ set spec [lindex $args 4]
+ set map [lrange $spec 1 end]
+ if [llength $map] {
+ # return [eval [concat [list ::style element create [lindex $args 2] image [lindex $spec 0] -map $map] [lrange $args 5 end]]]
+ return [uplevel 1 [list ::style element create [lindex $args 2] image [lindex $spec 0] -map $map] [lrange $args 5 end]]]
+ }
+ }
+ } elseif [string equal [lindex $args 0] default] {
+ # return [eval "::style [lreplace $args 0 0 configure]"]
+ return [uplevel 1 ::style [lreplace $args 0 0 configure]]
+ }
+ # return [eval "::style $args"]
+ return [uplevel 1 ::style $args]
+ EOS
+ #########################
+ end
+ end
+ else ### TILE_SPEC_VERSION_ID >= 8
+ TkCommandNames = ['::ttk::style'.freeze].freeze
+
+ def __define_wrapper_proc_for_compatibility__!
+ __define_themes_and_setTheme_proc__!
+
+ unless Tk.info(:commands, '::style').empty?
+ # fail RuntimeError, "can't define '::style' command (already exist)"
+
+ # do nothing !!!
+ warn "Warning: can't define '::style' command (already exist)" if $DEBUG
+ return
+ end
+ TkCore::INTERP.add_tk_procs('::style', 'args', <<-'EOS')
+ if [string equal [lrange $args 0 1] {element create}] {
+ if [string equal [lindex $args 3] image] {
+ set name [lindex $args 4]
+ set opts [lrange $args 5 end]
+ set idx [lsearch $opts -map]
+ if {$idx >= 0 && [expr $idx % 2 == 0]} {
+ # return [eval [concat [list ::ttk::style element create [lindex $args 2] image [concat $name [lindex $opts [expr $idx + 1]]]] [lreplace $opts $idx [expr $idx + 1]]]]
+ return [uplevel 1 [list ::ttk::style element create [lindex $args 2] image [concat $name [lindex $opts [expr $idx + 1]]]] [lreplace $opts $idx [expr $idx + 1]]]
+ }
+ }
+ } elseif [string equal [lindex $args 0] default] {
+ # return [eval "::ttk::style [lreplace $args 0 0 configure]"]
+ return [uplevel 1 ::ttk::style [lreplace $args 0 0 configure]]
+ }
+ # return [eval "::ttk::style $args"]
+ return [uplevel 1 ::ttk::style $args]
+ EOS
+ #########################
+ end
+ end
+
+ def __define_themes_and_setTheme_proc__!
+ TkCore::INTERP.add_tk_procs('::ttk::themes', '{ptn *}', <<-'EOS')
+ #set themes [list]
+ set themes [::ttk::style theme names]
+ foreach pkg [lsearch -inline -all -glob [package names] ttk::theme::$ptn] {
+ set theme [namespace tail $pkg]
+ if {[lsearch -exact $themes $theme] < 0} {
+ lappend themes $theme
+ }
+ }
+ foreach pkg [lsearch -inline -all -glob [package names] tile::theme::$ptn] {
+ set theme [namespace tail $pkg]
+ if {[lsearch -exact $themes $theme] < 0} {
+ lappend themes $theme
+ }
+ }
+ return $themes
+ EOS
+ #########################
+ TkCore::INTERP.add_tk_procs('::ttk::setTheme', 'theme', <<-'EOS')
+ variable currentTheme
+ if {[lsearch -exact [::ttk::style theme names] $theme] < 0} {
+ package require [lsearch -inline -regexp [package names] (ttk|tile)::theme::$theme]
+ }
+ ::ttk::style theme use $theme
+ set currentTheme $theme
+ EOS
+ end
+ private :__define_themes_and_setTheme_proc__!
+
def configure(style=nil, keys=nil)
if style.kind_of?(Hash)
keys = style
@@ -31,9 +170,9 @@ class << Tk::Tile::Style
end
if keys && keys != None
- tk_call('style', sub_cmd, style, *hash_kv(keys))
+ tk_call(TkCommandNames[0], sub_cmd, style, *hash_kv(keys))
else
- tk_call('style', sub_cmd, style)
+ tk_call(TkCommandNames[0], sub_cmd, style)
end
end
alias default configure
@@ -46,11 +185,34 @@ class << Tk::Tile::Style
style = '.' unless style
if keys && keys != None
- tk_call('style', 'map', style, *hash_kv(keys))
+ if keys.kind_of?(Hash)
+ tk_call(TkCommandNames[0], 'map', style, *hash_kv(keys))
+ else
+ simplelist(tk_call(TkCommandNames[0], 'map', style, '-' << keys.to_s))
+ end
else
- tk_call('style', 'map', style)
+ ret = {}
+ Hash[*(simplelist(tk_call(TkCommandNames[0], 'map', style)))].each{|k, v|
+ ret[k[1..-1]] = list(v)
+ }
+ ret
end
end
+ alias map_configure map
+
+ def map_configinfo(style=nil, key=None)
+ style = '.' unless style
+ map(style, key)
+ end
+
+ def map_default_configinfo(key=None)
+ map('.', key)
+ end
+
+ def lookup(style, opt, state=None, fallback_value=None)
+ tk_call(TkCommandNames[0], 'lookup', style,
+ '-' << opt.to_s, state, fallback_value)
+ end
include Tk::Tile::ParseStyleLayout
@@ -62,42 +224,93 @@ class << Tk::Tile::Style
style = '.' unless style
if spec
- tk_call('style', 'layout', style, spec)
+ tk_call(TkCommandNames[0], 'layout', style, spec)
else
- _style_layout(list(tk_call('style', 'layout', style)))
+ _style_layout(list(tk_call(TkCommandNames[0], 'layout', style)))
end
end
def element_create(name, type, *args)
- tk_call('style', 'element', 'create', name, type, *args)
+ if type == 'image' || type == :image
+ element_create_image(name, *args)
+ else
+ tk_call(TkCommandNames[0], 'element', 'create', name, type, *args)
+ end
+ end
+
+ def element_create_image(name, *args)
+ fail ArgumentError, 'Must supply a base image' unless (spec = args.shift)
+ if (opts = args.shift)
+ if opts.kind_of?(Hash)
+ opts = _symbolkey2str(opts)
+ else
+ fail ArgumentError, 'bad option'
+ end
+ end
+ fail ArgumentError, 'too many arguments' unless args.empty?
+
+ if spec.kind_of?(Array)
+ # probably, command format is tile 0.8+ (Tcl/Tk8.5+) style
+ if Tk::Tile::TILE_SPEC_VERSION_ID >= 8
+ if opts
+ tk_call(TkCommandNames[0],
+ 'element', 'create', name, 'image', spec, opts)
+ else
+ tk_call(TkCommandNames[0], 'element', 'create', name, 'image', spec)
+ end
+ else
+ fail ArgumentError, 'illegal arguments' if opts.key?('map')
+ base = spec.shift
+ opts['map'] = spec
+ tk_call(TkCommandNames[0],
+ 'element', 'create', name, 'image', base, opts)
+ end
+ else
+ # probably, command format is tile 0.7.8 or older style
+ if Tk::Tile::TILE_SPEC_VERSION_ID >= 8
+ spec = [spec, *(opts.delete('map'))] if opts.key?('map')
+ end
+ if opts
+ tk_call(TkCommandNames[0],
+ 'element', 'create', name, 'image', spec, opts)
+ else
+ tk_call(TkCommandNames[0], 'element', 'create', name, 'image', spec)
+ end
+ end
end
def element_names()
- list(tk_call('style', 'element', 'names'))
+ list(tk_call(TkCommandNames[0], 'element', 'names'))
end
def element_options(elem)
- simplelist(tk_call('style', 'element', 'options', elem))
+ simplelist(tk_call(TkCommandNames[0], 'element', 'options', elem))
end
def theme_create(name, keys=nil)
+ name = name.to_s
if keys && keys != None
- tk_call('style', 'theme', 'create', name, *hash_kv(keys))
+ tk_call(TkCommandNames[0], 'theme', 'create', name, *hash_kv(keys))
else
- tk_call('style', 'theme', 'create', name)
+ tk_call(TkCommandNames[0], 'theme', 'create', name)
end
+ name
end
def theme_settings(name, cmd=nil, &b)
+ name = name.to_s
cmd = Proc.new(&b) if !cmd && b
- tk_call('style', 'theme', 'settings', name, cmd)
+ tk_call(TkCommandNames[0], 'theme', 'settings', name, cmd)
+ name
end
def theme_names()
- list(tk_call('style', 'theme', 'names'))
+ list(tk_call(TkCommandNames[0], 'theme', 'names'))
end
def theme_use(name)
- tk_call('style', 'theme', 'use', name)
+ name = name.to_s
+ tk_call(TkCommandNames[0], 'theme', 'use', name)
+ name
end
end
diff --git a/ext/tk/lib/tkextlib/tile/tbutton.rb b/ext/tk/lib/tkextlib/tile/tbutton.rb
index 1142a27100..5d7db10fe9 100644
--- a/ext/tk/lib/tkextlib/tile/tbutton.rb
+++ b/ext/tk/lib/tkextlib/tile/tbutton.rb
@@ -7,13 +7,16 @@ require 'tkextlib/tile.rb'
module Tk
module Tile
- class TButton < TkButton
+ class TButton < Tk::Button
end
Button = TButton
end
end
-class Tk::Tile::TButton < TkButton
+Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Button, :TkButton)
+
+
+class Tk::Tile::TButton < Tk::Button
include Tk::Tile::TileWidget
if Tk::Tile::USE_TTK_NAMESPACE
diff --git a/ext/tk/lib/tkextlib/tile/tcheckbutton.rb b/ext/tk/lib/tkextlib/tile/tcheckbutton.rb
index fce799683d..172225fcec 100644
--- a/ext/tk/lib/tkextlib/tile/tcheckbutton.rb
+++ b/ext/tk/lib/tkextlib/tile/tcheckbutton.rb
@@ -7,7 +7,7 @@ require 'tkextlib/tile.rb'
module Tk
module Tile
- class TCheckButton < TkCheckButton
+ class TCheckButton < Tk::CheckButton
end
TCheckbutton = TCheckButton
CheckButton = TCheckButton
@@ -15,7 +15,11 @@ module Tk
end
end
-class Tk::Tile::TCheckButton < TkCheckButton
+Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Checkbutton,
+ :TkCheckbutton, :TkCheckButton)
+
+
+class Tk::Tile::TCheckButton < Tk::CheckButton
include Tk::Tile::TileWidget
if Tk::Tile::USE_TTK_NAMESPACE
diff --git a/ext/tk/lib/tkextlib/tile/tcombobox.rb b/ext/tk/lib/tkextlib/tile/tcombobox.rb
index c63ab94dbe..b64372f1c9 100644
--- a/ext/tk/lib/tkextlib/tile/tcombobox.rb
+++ b/ext/tk/lib/tkextlib/tile/tcombobox.rb
@@ -13,6 +13,9 @@ module Tk
end
end
+Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Combobox, :TkCombobox)
+
+
class Tk::Tile::TCombobox < Tk::Tile::TEntry
include Tk::Tile::TileWidget
@@ -39,16 +42,12 @@ class Tk::Tile::TCombobox < Tk::Tile::TEntry
end
def current
- number(tk_send_without_enc('current', idx))
+ number(tk_send_without_enc('current'))
end
def current=(idx)
tk_send_without_enc('current', idx)
end
- def identify(x, y)
- tk_send_without_enc('identify', x, y)
- end
-
def set(val)
tk_send('set', val)
end
diff --git a/ext/tk/lib/tkextlib/tile/tentry.rb b/ext/tk/lib/tkextlib/tile/tentry.rb
index 4d57ce7756..0bea98dcd9 100644
--- a/ext/tk/lib/tkextlib/tile/tentry.rb
+++ b/ext/tk/lib/tkextlib/tile/tentry.rb
@@ -7,13 +7,16 @@ require 'tkextlib/tile.rb'
module Tk
module Tile
- class TEntry < TkEntry
+ class TEntry < Tk::Entry
end
Entry = TEntry
end
end
-class Tk::Tile::TEntry < TkEntry
+Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Entry, :TkEntry)
+
+
+class Tk::Tile::TEntry < Tk::Entry
include Tk::Tile::TileWidget
if Tk::Tile::USE_TTK_NAMESPACE
@@ -24,6 +27,11 @@ class Tk::Tile::TEntry < TkEntry
WidgetClassName = 'TEntry'.freeze
WidgetClassNames[WidgetClassName] = self
+ def __optkey_aliases
+ {:vcmd=>:validatecommand, :invcmd=>:invalidcommand}
+ end
+ private :__optkey_aliases
+
def __boolval_optkeys
super() << 'exportselection'
end
diff --git a/ext/tk/lib/tkextlib/tile/tframe.rb b/ext/tk/lib/tkextlib/tile/tframe.rb
index 691c9c42af..3b5f98bb6e 100644
--- a/ext/tk/lib/tkextlib/tile/tframe.rb
+++ b/ext/tk/lib/tkextlib/tile/tframe.rb
@@ -7,13 +7,16 @@ require 'tkextlib/tile.rb'
module Tk
module Tile
- class TFrame < TkFrame
+ class TFrame < Tk::Frame
end
Frame = TFrame
end
end
-class Tk::Tile::TFrame < TkFrame
+Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Frame, :TkFrame)
+
+
+class Tk::Tile::TFrame < Tk::Frame
include Tk::Tile::TileWidget
if Tk::Tile::USE_TTK_NAMESPACE
diff --git a/ext/tk/lib/tkextlib/tile/tlabel.rb b/ext/tk/lib/tkextlib/tile/tlabel.rb
index 4111d1906a..7d074d3842 100644
--- a/ext/tk/lib/tkextlib/tile/tlabel.rb
+++ b/ext/tk/lib/tkextlib/tile/tlabel.rb
@@ -7,13 +7,16 @@ require 'tkextlib/tile.rb'
module Tk
module Tile
- class TLabel < TkLabel
+ class TLabel < Tk::Label
end
Label = TLabel
end
end
-class Tk::Tile::TLabel < TkLabel
+Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Label, :TkLabel)
+
+
+class Tk::Tile::TLabel < Tk::Label
include Tk::Tile::TileWidget
if Tk::Tile::USE_TTK_NAMESPACE
diff --git a/ext/tk/lib/tkextlib/tile/tlabelframe.rb b/ext/tk/lib/tkextlib/tile/tlabelframe.rb
index 8981232b25..cff66d8658 100644
--- a/ext/tk/lib/tkextlib/tile/tlabelframe.rb
+++ b/ext/tk/lib/tkextlib/tile/tlabelframe.rb
@@ -9,10 +9,16 @@ module Tk
module Tile
class TLabelframe < Tk::Tile::TFrame
end
- Labelframe = TLabelframe
+ TLabelFrame = TLabelframe
+ Labelframe = TLabelframe
+ LabelFrame = TLabelframe
end
end
+Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Labelframe,
+ :TkLabelframe, :TkLabelFrame)
+
+
class Tk::Tile::TLabelframe < Tk::Tile::TFrame
include Tk::Tile::TileWidget
diff --git a/ext/tk/lib/tkextlib/tile/tmenubutton.rb b/ext/tk/lib/tkextlib/tile/tmenubutton.rb
index 4b81fa1c81..7c6ab28e52 100644
--- a/ext/tk/lib/tkextlib/tile/tmenubutton.rb
+++ b/ext/tk/lib/tkextlib/tile/tmenubutton.rb
@@ -7,13 +7,19 @@ require 'tkextlib/tile.rb'
module Tk
module Tile
- class TMenubutton < TkMenubutton
+ class TMenubutton < Tk::Menubutton
end
- Menubutton = TMenubutton
+ TMenuButton = TMenubutton
+ Menubutton = TMenubutton
+ MenuButton = TMenubutton
end
end
-class Tk::Tile::TMenubutton < TkMenubutton
+Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Menubutton,
+ :TkMenubutton, :TkMenuButton)
+
+
+class Tk::Tile::TMenubutton < Tk::Menubutton
include Tk::Tile::TileWidget
if Tk::Tile::USE_TTK_NAMESPACE
diff --git a/ext/tk/lib/tkextlib/tile/tnotebook.rb b/ext/tk/lib/tkextlib/tile/tnotebook.rb
index abaed8ee9c..4d65e363da 100644
--- a/ext/tk/lib/tkextlib/tile/tnotebook.rb
+++ b/ext/tk/lib/tkextlib/tile/tnotebook.rb
@@ -13,6 +13,9 @@ module Tk
end
end
+Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Notebook, :TkNotebook)
+
+
class Tk::Tile::TNotebook < TkWindow
################################
include TkItemConfigMethod
@@ -27,24 +30,46 @@ class Tk::Tile::TNotebook < TkWindow
end
private :__item_config_cmd
- def __item_listval_optkeys
+ def __item_listval_optkeys(id)
[]
end
private :__item_listval_optkeys
- def __item_methodcall_optkeys # { key=>method, ... }
+ def __item_methodcall_optkeys(id) # { key=>method, ... }
{}
end
- private :__item_listval_optkeys
+ private :__item_methodcall_optkeys
#alias tabcget itemcget
+ #alias tabcget_strict itemcget_strict
alias tabconfigure itemconfigure
alias tabconfiginfo itemconfiginfo
alias current_tabconfiginfo current_itemconfiginfo
- def tabcget(tagOrId, option)
+ def tabcget_strict(tagOrId, option)
tabconfigure(tagOrId, option)[-1]
end
+ def tabcget(tagOrId, option)
+ unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ tabcget_strict(tagOrId, option)
+ else
+ begin
+ tabcget_strict(tagOrId, option)
+ rescue => e
+ begin
+ if current_tabconfiginfo(tagOrId).has_key?(option.to_s)
+ # not tag error & option is known -> error on known option
+ fail e
+ else
+ # not tag error & option is unknown
+ nil
+ end
+ rescue
+ fail e # tag error
+ end
+ end
+ end
+ end
################################
include Tk::Tile::TileWidget
@@ -74,9 +99,9 @@ class Tk::Tile::TNotebook < TkWindow
def add(child, keys=nil)
if keys && keys != None
- tk_send_without_enc('add', _epath(child), *hash_kv(keys))
+ tk_send('add', _epath(child), *hash_kv(keys))
else
- tk_send_without_enc('add', _epath(child))
+ tk_send('add', _epath(child))
end
self
end
@@ -104,6 +129,10 @@ class Tk::Tile::TNotebook < TkWindow
self
end
+ def selected
+ window(tk_send_without_enc('select'))
+ end
+
def tabs
list(tk_send('tabs'))
end
diff --git a/ext/tk/lib/tkextlib/tile/tpaned.rb b/ext/tk/lib/tkextlib/tile/tpaned.rb
index 11178b19d3..d96ff43973 100644
--- a/ext/tk/lib/tkextlib/tile/tpaned.rb
+++ b/ext/tk/lib/tkextlib/tile/tpaned.rb
@@ -9,15 +9,23 @@ module Tk
module Tile
class TPaned < TkWindow
end
- Paned = TPaned
+ PanedWindow = Panedwindow = Paned = TPaned
end
end
+Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Panedwindow,
+ :TkPanedwindow, :TkPanedWindow)
+
+
class Tk::Tile::TPaned < TkWindow
include Tk::Tile::TileWidget
if Tk::Tile::USE_TTK_NAMESPACE
- TkCommandNames = ['::ttk::paned'.freeze].freeze
+ if Tk::Tile::TILE_SPEC_VERSION_ID < 8
+ TkCommandNames = ['::ttk::paned'.freeze].freeze
+ else
+ TkCommandNames = ['::ttk::panedwindow'.freeze].freeze
+ end
else
TkCommandNames = ['::tpaned'.freeze].freeze
end
@@ -28,9 +36,21 @@ class Tk::Tile::TPaned < TkWindow
[self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.')
end
- def add(win, keys)
- win = _epath(win)
- tk_send_without_enc('add', win, *hash_kv(keys))
+ def add(*args)
+ keys = args.pop
+ fail ArgumentError, "no window in arguments" unless keys
+
+ if keys && keys.kind_of?(Hash)
+ fail ArgumentError, "no window in arguments" if args == []
+ opts = hash_kv(keys)
+ else
+ args.push(keys) if keys
+ opts = []
+ end
+
+ args.each{|win|
+ tk_send_without_enc('add', _epath(win), *opts)
+ }
self
end
@@ -46,10 +66,33 @@ class Tk::Tile::TPaned < TkWindow
self
end
- def panecget(pane, slot)
+ def panecget_strict(pane, slot)
pane = _epath(pane)
tk_tcl2ruby(tk_send_without_enc('pane', pane, "-#{slot}"))
end
+ alias pane_cget_strict panecget_strict
+
+ def panecget(pane, slot)
+ unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ panecget_strict(pane, slot)
+ else
+ begin
+ panecget_strict(pane, slot)
+ rescue => e
+ begin
+ if current_paneconfiginfo(pane).has_key?(slot.to_s)
+ # not tag error & option is known -> error on known option
+ fail e
+ else
+ # not tag error & option is unknown
+ nil
+ end
+ rescue
+ fail e # tag error
+ end
+ end
+ end
+ end
alias pane_cget panecget
def paneconfigure(pane, key, value=nil)
diff --git a/ext/tk/lib/tkextlib/tile/tprogressbar.rb b/ext/tk/lib/tkextlib/tile/tprogressbar.rb
index 36c1c75c23..f786d370dd 100644
--- a/ext/tk/lib/tkextlib/tile/tprogressbar.rb
+++ b/ext/tk/lib/tkextlib/tile/tprogressbar.rb
@@ -13,6 +13,9 @@ module Tk
end
end
+Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Progressbar, :TkProgressbar)
+
+
class Tk::Tile::TProgressbar
include Tk::Tile::TileWidget
diff --git a/ext/tk/lib/tkextlib/tile/tradiobutton.rb b/ext/tk/lib/tkextlib/tile/tradiobutton.rb
index e2f614cb97..d653a6d256 100644
--- a/ext/tk/lib/tkextlib/tile/tradiobutton.rb
+++ b/ext/tk/lib/tkextlib/tile/tradiobutton.rb
@@ -7,7 +7,7 @@ require 'tkextlib/tile.rb'
module Tk
module Tile
- class TRadioButton < TkRadioButton
+ class TRadioButton < Tk::RadioButton
end
TRadiobutton = TRadioButton
RadioButton = TRadioButton
@@ -15,7 +15,11 @@ module Tk
end
end
-class Tk::Tile::TRadioButton < TkRadioButton
+Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Radiobutton,
+ :TkRadiobutton, :TkRadioButton)
+
+
+class Tk::Tile::TRadioButton < Tk::RadioButton
include Tk::Tile::TileWidget
if Tk::Tile::USE_TTK_NAMESPACE
diff --git a/ext/tk/lib/tkextlib/tile/treeview.rb b/ext/tk/lib/tkextlib/tile/treeview.rb
index d3ffbbfa6b..c978a1a07b 100644
--- a/ext/tk/lib/tkextlib/tile/treeview.rb
+++ b/ext/tk/lib/tkextlib/tile/treeview.rb
@@ -9,129 +9,999 @@ module Tk
module Tile
class Treeview < TkWindow
end
+ end
+end
- module TreeviewConfig
- include TkItemConfigMethod
+Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Treeview, :TkTreeview)
- def __item_cget_cmd(id)
- [self.path, id[0], id[1]]
- end
- private :__item_cget_cmd
- def __item_config_cmd(id)
- [self.path, id[0], id[1]]
- end
- private :__item_config_cmd
-
- def __item_numstrval_optkeys(id)
- case id[0]
- when :item, 'item'
- ['width']
- when :column, 'column'
- super(id[1])
- when :heading, 'heading'
- super(id[1])
- end
- end
- private :__item_numstrval_optkeys
-
- def __item_strval_optkeys(id)
- case id[0]
- when :item, 'item'
- super(id) + ['id']
- when :column, 'column'
- super(id[1])
- when :heading, 'heading'
- super(id[1])
- end
- end
- private :__item_strval_optkeys
-
- def __item_boolval_optkeys(id)
- case id[0]
- when :item, 'item'
- ['open']
- when :column, 'column'
- super(id[1])
- when :heading, 'heading'
- super(id[1])
+module Tk::Tile::TreeviewConfig
+ include TkItemConfigMethod
+
+ def __item_configinfo_struct(id)
+ # maybe need to override
+ {:key=>0, :alias=>nil, :db_name=>nil, :db_class=>nil,
+ :default_value=>nil, :current_value=>1}
+ end
+ private :__item_configinfo_struct
+
+ def __itemconfiginfo_core(tagOrId, slot = nil)
+ if TkComm::GET_CONFIGINFO_AS_ARRAY
+ if (slot && slot.to_s =~ /^(|latin|ascii|kanji)(#{__item_font_optkeys(tagid(tagOrId)).join('|')})$/)
+ fontkey = $2
+ return [slot.to_s, tagfontobj(tagid(tagOrId), fontkey)]
+ else
+ if slot
+ slot = slot.to_s
+
+ alias_name, real_name = __item_optkey_aliases(tagid(tagOrId)).find{|k, v| k.to_s == slot}
+ if real_name
+ slot = real_name.to_s
+ end
+
+ case slot
+ when /^(#{__tile_specific_item_optkeys(tagid(tagOrId)).join('|')})$/
+ begin
+ # On tile-0.7.{2-8}, 'state' options has no '-' at its head.
+ val = tk_call(*(__item_confinfo_cmd(tagid(tagOrId)) << slot))
+ rescue
+ # Maybe, 'state' option has '-' in future.
+ val = tk_call(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
+ end
+ return [slot, val]
+
+ when /^(#{__item_val2ruby_optkeys(tagid(tagOrId)).keys.join('|')})$/
+ method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[slot]
+ optval = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
+ begin
+ val = method.call(tagOrId, optval)
+ rescue => e
+ warn("Warning:: #{e.message} (when #{method}lcall(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG
+ val = optval
+ end
+ return [slot, val]
+
+ when /^(#{__item_methodcall_optkeys(tagid(tagOrId)).keys.join('|')})$/
+ method = _symbolkey2str(__item_methodcall_optkeys(tagid(tagOrId)))[slot]
+ return [slot, self.__send__(method, tagOrId)]
+
+ when /^(#{__item_numval_optkeys(tagid(tagOrId)).join('|')})$/
+ begin
+ val = number(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
+ rescue
+ val = nil
+ end
+ return [slot, val]
+
+ when /^(#{__item_numstrval_optkeys(tagid(tagOrId)).join('|')})$/
+ val = num_or_str(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
+ return [slot, val]
+
+ when /^(#{__item_boolval_optkeys(tagid(tagOrId)).join('|')})$/
+ begin
+ val = bool(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
+ rescue
+ val = nil
+ end
+ return [slot, val]
+
+ when /^(#{__item_listval_optkeys(tagid(tagOrId)).join('|')})$/
+ val = simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
+ return [slot, val]
+
+ when /^(#{__item_numlistval_optkeys(tagid(tagOrId)).join('|')})$/
+ val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
+ if val =~ /^[0-9]/
+ return [slot, list(val)]
+ else
+ return [slot, val]
+ end
+
+ when /^(#{__item_strval_optkeys(tagid(tagOrId)).join('|')})$/
+ val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
+ return [slot, val]
+
+ when /^(#{__item_tkvariable_optkeys(tagid(tagOrId)).join('|')})$/
+ val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
+ if val.empty?
+ return [slot, nil]
+ else
+ return [slot, TkVarAccess.new(val)]
+ end
+
+ else
+ val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
+ if val.index('{')
+ return [slot, tk_split_list(val)]
+ else
+ return [slot, tk_tcl2ruby(val)]
+ end
+ end
+
+ else # ! slot
+ ret = Hash[*(tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)))), false, false))].to_a.collect{|conf|
+ conf[0] = conf[0][1..-1] if conf[0][0] == ?-
+ case conf[0]
+ when /^(#{__item_val2ruby_optkeys(tagid(tagOrId)).keys.join('|')})$/
+ method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[conf[0]]
+ optval = conf[1]
+ begin
+ val = method.call(tagOrId, optval)
+ rescue => e
+ warn("Warning:: #{e.message} (when #{method}.call(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG
+ val = optval
+ end
+ conf[1] = val
+
+ when /^(#{__item_strval_optkeys(tagid(tagOrId)).join('|')})$/
+ # do nothing
+
+ when /^(#{__item_numval_optkeys(tagid(tagOrId)).join('|')})$/
+ begin
+ conf[1] = number(conf[1])
+ rescue
+ conf[1] = nil
+ end
+
+ when /^(#{__item_numstrval_optkeys(tagid(tagOrId)).join('|')})$/
+ conf[1] = num_or_str(conf[1])
+
+ when /^(#{__item_boolval_optkeys(tagid(tagOrId)).join('|')})$/
+ begin
+ conf[1] = bool(conf[1])
+ rescue
+ conf[1] = nil
+ end
+
+ when /^(#{__item_listval_optkeys(tagid(tagOrId)).join('|')})$/
+ conf[1] = simplelist(conf[1])
+
+ when /^(#{__item_numlistval_optkeys(tagid(tagOrId)).join('|')})$/
+ if conf[1] =~ /^[0-9]/
+ conf[1] = list(conf[1])
+ end
+
+ when /^(#{__item_tkvariable_optkeys(tagid(tagOrId)).join('|')})$/
+ if conf[1].empty?
+ conf[1] = nil
+ else
+ conf[1] = TkVarAccess.new(conf[1])
+ end
+
+ else
+ if conf[1].index('{')
+ conf[1] = tk_split_list(conf[1])
+ else
+ conf[1] = tk_tcl2ruby(conf[1])
+ end
+ end
+
+ conf
+ }
+
+ __item_font_optkeys(tagid(tagOrId)).each{|optkey|
+ optkey = optkey.to_s
+ fontconf = ret.assoc(optkey)
+ if fontconf
+ ret.delete_if{|inf| inf[0] =~ /^(|latin|ascii|kanji)#{optkey}$/}
+ fontconf[1] = tagfontobj(tagid(tagOrId), optkey)
+ ret.push(fontconf)
+ end
+ }
+
+ __item_methodcall_optkeys(tagid(tagOrId)).each{|optkey, method|
+ ret << [optkey.to_s, self.__send__(method, tagOrId)]
+ }
+
+ ret
end
end
- private :__item_boolval_optkeys
-
- def __item_listval_optkeys(id)
- case id[0]
- when :item, 'item'
- ['values']
- when :column, 'column'
- []
- when :heading, 'heading'
- []
+
+ else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
+ if (slot && slot.to_s =~ /^(|latin|ascii|kanji)(#{__item_font_optkeys(tagid(tagOrId)).join('|')})$/)
+ fontkey = $2
+ return {slot.to_s => tagfontobj(tagid(tagOrId), fontkey)}
+ else
+ if slot
+ slot = slot.to_s
+
+ alias_name, real_name = __item_optkey_aliases(tagid(tagOrId)).find{|k, v| k.to_s == slot}
+ if real_name
+ slot = real_name.to_s
+ end
+
+ case slot
+ when /^(#{__tile_specific_item_optkeys(tagid(tagOrId)).join('|')})$/
+ begin
+ # On tile-0.7.{2-8}, 'state' option has no '-' at its head.
+ val = tk_call(*(__item_confinfo_cmd(tagid(tagOrId)) << slot))
+ rescue
+ # Maybe, 'state' option has '-' in future.
+ val = tk_call(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
+ end
+ return {slot => val}
+
+ when /^(#{__item_val2ruby_optkeys(tagid(tagOrId)).keys.join('|')})$/
+ method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[slot]
+ optval = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
+ begin
+ val = method.call(tagOrId, optval)
+ rescue => e
+ warn("Warning:: #{e.message} (when #{method}lcall(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG
+ val = optval
+ end
+ return {slot => val}
+
+ when /^(#{__item_methodcall_optkeys(tagid(tagOrId)).keys.join('|')})$/
+ method = _symbolkey2str(__item_methodcall_optkeys(tagid(tagOrId)))[slot]
+ return {slot => self.__send__(method, tagOrId)}
+
+ when /^(#{__item_numval_optkeys(tagid(tagOrId)).join('|')})$/
+ begin
+ val = number(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
+ rescue
+ val = nil
+ end
+ return {slot => val}
+
+ when /^(#{__item_numstrval_optkeys(tagid(tagOrId)).join('|')})$/
+ val = num_or_str(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
+ return {slot => val}
+
+ when /^(#{__item_boolval_optkeys(tagid(tagOrId)).join('|')})$/
+ begin
+ val = bool(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
+ rescue
+ val = nil
+ end
+ return {slot => val}
+
+ when /^(#{__item_listval_optkeys(tagid(tagOrId)).join('|')})$/
+ val = simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
+ return {slot => val}
+
+ when /^(#{__item_numlistval_optkeys(tagid(tagOrId)).join('|')})$/
+ val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
+ if val =~ /^[0-9]/
+ return {slot => list(val)}
+ else
+ return {slot => val}
+ end
+
+ when /^(#{__item_strval_optkeys(tagid(tagOrId)).join('|')})$/
+ val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
+ return {slot => val}
+
+ when /^(#{__item_tkvariable_optkeys(tagid(tagOrId)).join('|')})$/
+ val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
+ if val.empty?
+ return {slot => nil}
+ else
+ return {slot => TkVarAccess.new(val)}
+ end
+
+ else
+ val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
+ if val.index('{')
+ return {slot => tk_split_list(val)}
+ else
+ return {slot => tk_tcl2ruby(val)}
+ end
+ end
+
+ else # ! slot
+ ret = {}
+ ret = Hash[*(tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)))), false, false))].to_a.collect{|conf|
+ conf[0] = conf[0][1..-1] if conf[0][0] == ?-
+
+ optkey = conf[0]
+ case optkey
+ when /^(#{__item_val2ruby_optkeys(tagid(tagOrId)).keys.join('|')})$/
+ method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[optkey]
+ optval = conf[1]
+ begin
+ val = method.call(tagOrId, optval)
+ rescue => e
+ warn("Warning:: #{e.message} (when #{method}.call(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG
+ val = optval
+ end
+ conf[1] = val
+
+ when /^(#{__item_strval_optkeys(tagid(tagOrId)).join('|')})$/
+ # do nothing
+
+ when /^(#{__item_numval_optkeys(tagid(tagOrId)).join('|')})$/
+ begin
+ conf[1] = number(conf[1])
+ rescue
+ conf[1] = nil
+ end
+
+ when /^(#{__item_numstrval_optkeys(tagid(tagOrId)).join('|')})$/
+ conf[1] = num_or_str(conf[1])
+
+ when /^(#{__item_boolval_optkeys(tagid(tagOrId)).join('|')})$/
+ begin
+ conf[1] = bool(conf[1])
+ rescue
+ conf[1] = nil
+ end
+
+ when /^(#{__item_listval_optkeys(tagid(tagOrId)).join('|')})$/
+ conf[1] = simplelist(conf[1])
+
+ when /^(#{__item_numlistval_optkeys(tagid(tagOrId)).join('|')})$/
+ if conf[1] =~ /^[0-9]/
+ conf[1] = list(conf[1])
+ end
+
+ when /^(#{__item_tkvariable_optkeys(tagid(tagOrId)).join('|')})$/
+ if conf[1].empty?
+ conf[1] = nil
+ else
+ conf[1] = TkVarAccess.new(conf[1])
+ end
+
+ else
+ if conf[1].index('{')
+ return [slot, tk_split_list(conf[1])]
+ else
+ return [slot, tk_tcl2ruby(conf[1])]
+ end
+ end
+
+ ret[conf[0]] = conf[1]
+ }
+
+ __item_font_optkeys(tagid(tagOrId)).each{|optkey|
+ optkey = optkey.to_s
+ fontconf = ret[optkey]
+ if fontconf.kind_of?(Array)
+ ret.delete(optkey)
+ ret.delete('latin' << optkey)
+ ret.delete('ascii' << optkey)
+ ret.delete('kanji' << optkey)
+ fontconf[1] = tagfontobj(tagid(tagOrId), optkey)
+ ret[optkey] = fontconf
+ end
+ }
+
+ __item_methodcall_optkeys(tagid(tagOrId)).each{|optkey, method|
+ ret[optkey.to_s] = self.__send__(method, tagOrId)
+ }
+
+ ret
end
end
- private :__item_listval_optkeys
+ end
+ end
+
+ ###################
- alias __itemcget itemcget
- alias __itemconfigure itemconfigure
- alias __itemconfiginfo itemconfiginfo
- alias __current_itemconfiginfo current_itemconfiginfo
+ def __item_cget_cmd(id)
+ [self.path, id[0], id[1]]
+ end
+ private :__item_cget_cmd
- private :__itemcget, :__itemconfigure
- private :__itemconfiginfo, :__current_itemconfiginfo
+ def __item_config_cmd(id)
+ [self.path, id[0], id[1]]
+ end
+ private :__item_config_cmd
- # Treeview Item
- def itemcget(tagOrId, option)
- __itemcget([:item, tagOrId], option)
- end
- def itemconfigure(tagOrId, slot, value=None)
- __itemconfigure([:item, tagOrId], slot, value)
- end
- def itemconfiginfo(tagOrId, slot=nil)
- __itemconfiginfo([:item, tagOrId], slot)
- end
- def current_itemconfiginfo(tagOrId, slot=nil)
- __current_itemconfiginfo([:item, tagOrId], slot)
- end
+ def __item_numstrval_optkeys(id)
+ case id[0]
+ when :item, 'item'
+ ['width']
+ when :column, 'column'
+ super(id[1]) + ['minwidth']
+ when :tag, 'tag'
+ super(id[1])
+ when :heading, 'heading'
+ super(id[1])
+ else
+ super(id[1])
+ end
+ end
+ private :__item_numstrval_optkeys
- # Treeview Column
- def columncget(tagOrId, option)
- __itemcget([:column, tagOrId], option)
+ def __item_strval_optkeys(id)
+ case id[0]
+ when :item, 'item'
+ super(id) + ['id']
+ when :column, 'column'
+ super(id[1])
+ when :tag, 'tag'
+ super(id[1])
+ when :heading, 'heading'
+ super(id[1])
+ else
+ super(id[1])
+ end
+ end
+ private :__item_strval_optkeys
+
+ def __item_boolval_optkeys(id)
+ case id[0]
+ when :item, 'item'
+ ['open']
+ when :column, 'column'
+ super(id[1]) + ['stretch']
+ when :tag, 'tag'
+ super(id[1])
+ when :heading, 'heading'
+ super(id[1])
+ end
+ end
+ private :__item_boolval_optkeys
+
+ def __item_listval_optkeys(id)
+ case id[0]
+ when :item, 'item'
+ ['values']
+ when :column, 'column'
+ []
+ when :heading, 'heading'
+ []
+ else
+ []
+ end
+ end
+ private :__item_listval_optkeys
+
+ def __item_val2ruby_optkeys(id)
+ case id[0]
+ when :item, 'item'
+ {
+ 'tags'=>proc{|arg_id, val|
+ simplelist(val).collect{|tag|
+ Tk::Tile::Treeview::Tag.id2obj(self, tag)
+ }
+ }
+ }
+ when :column, 'column'
+ {}
+ when :heading, 'heading'
+ {}
+ else
+ {}
+ end
+ end
+ private :__item_val2ruby_optkeys
+
+ def __tile_specific_item_optkeys(id)
+ case id[0]
+ when :item, 'item'
+ []
+ when :column, 'column'
+ []
+ when :heading, 'heading'
+ ['state'] # On tile-0.7.{2-8}, 'state' options has no '-' at its head.
+ else
+ []
+ end
+ end
+ private :__item_val2ruby_optkeys
+
+ def itemconfiginfo(tagOrId, slot = nil)
+ __itemconfiginfo_core(tagOrId, slot)
+ end
+
+ def current_itemconfiginfo(tagOrId, slot = nil)
+ if TkComm::GET_CONFIGINFO_AS_ARRAY
+ if slot
+ org_slot = slot
+ begin
+ conf = __itemconfiginfo_core(tagOrId, slot)
+ if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \
+ || conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 )
+ return {conf[0] => conf[-1]}
+ end
+ slot = conf[__item_configinfo_struct(tagid(tagOrId))[:alias]]
+ end while(org_slot != slot)
+ fail RuntimeError,
+ "there is a configure alias loop about '#{org_slot}'"
+ else
+ ret = {}
+ __itemconfiginfo_core(tagOrId).each{|conf|
+ if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \
+ || conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 )
+ ret[conf[0]] = conf[-1]
+ end
+ }
+ ret
end
- def columnconfigure(tagOrId, slot, value=None)
- __itemconfigure([:column, tagOrId], slot, value)
+ else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
+ ret = {}
+ __itemconfiginfo_core(tagOrId, slot).each{|key, conf|
+ ret[key] = conf[-1] if conf.kind_of?(Array)
+ }
+ ret
+ end
+ end
+
+ alias __itemcget itemcget
+ alias __itemcget_strict itemcget_strict
+ alias __itemconfigure itemconfigure
+ alias __itemconfiginfo itemconfiginfo
+ alias __current_itemconfiginfo current_itemconfiginfo
+
+ private :__itemcget, :__itemcget_strict
+ private :__itemconfigure, :__itemconfiginfo, :__current_itemconfiginfo
+
+ # Treeview Item
+ def itemcget(tagOrId, option)
+ __itemcget([:item, tagOrId], option)
+ end
+ def itemcget_strict(tagOrId, option)
+ __itemcget_strict([:item, tagOrId], option)
+ end
+ def itemconfigure(tagOrId, slot, value=None)
+ __itemconfigure([:item, tagOrId], slot, value)
+ end
+ def itemconfiginfo(tagOrId, slot=nil)
+ __itemconfiginfo([:item, tagOrId], slot)
+ end
+ def current_itemconfiginfo(tagOrId, slot=nil)
+ __current_itemconfiginfo([:item, tagOrId], slot)
+ end
+
+ # Treeview Column
+ def columncget(tagOrId, option)
+ __itemcget([:column, tagOrId], option)
+ end
+ def columncget_strict(tagOrId, option)
+ __itemcget_strict([:column, tagOrId], option)
+ end
+ def columnconfigure(tagOrId, slot, value=None)
+ __itemconfigure([:column, tagOrId], slot, value)
+ end
+ def columnconfiginfo(tagOrId, slot=nil)
+ __itemconfiginfo([:column, tagOrId], slot)
+ end
+ def current_columnconfiginfo(tagOrId, slot=nil)
+ __current_itemconfiginfo([:column, tagOrId], slot)
+ end
+ alias column_cget columncget
+ alias column_cget_strict columncget_strict
+ alias column_configure columnconfigure
+ alias column_configinfo columnconfiginfo
+ alias current_column_configinfo current_columnconfiginfo
+
+ # Treeview Heading
+ def headingcget_strict(tagOrId, option)
+ if __tile_specific_item_optkeys([:heading, tagOrId]).index(option.to_s)
+ begin
+ # On tile-0.7.{2-8}, 'state' options has no '-' at its head.
+ tk_call(*(__item_cget_cmd([:heading, tagOrId]) << option.to_s))
+ rescue
+ # Maybe, 'state' option has '-' in future.
+ tk_call(*(__item_cget_cmd([:heading, tagOrId]) << "-#{option}"))
end
- def columnconfiginfo(tagOrId, slot=nil)
- __itemconfiginfo([:column, tagOrId], slot)
+ else
+ __itemcget_strict([:heading, tagOrId], option)
+ end
+ end
+ def headingcget(tagOrId, option)
+ unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
+ headingcget_strict(tagOrId, option)
+ else
+ begin
+ headingcget_strict(tagOrId, option)
+ rescue => e
+ begin
+ if current_headingconfiginfo(tagOrId).has_key?(option.to_s)
+ # not tag error & option is known -> error on known option
+ fail e
+ else
+ # not tag error & option is unknown
+ nil
+ end
+ rescue
+ fail e # tag error
+ end
end
- def current_columnconfiginfo(tagOrId, slot=nil)
- __current_itemconfiginfo([:column, tagOrId], slot)
+ end
+ end
+ def headingconfigure(tagOrId, slot, value=None)
+ if slot.kind_of?(Hash)
+ slot = _symbolkey2str(slot)
+ sp_kv = []
+ __tile_specific_item_optkeys([:heading, tagOrId]).each{|k|
+ sp_kv << k << _get_eval_string(slot.delete(k)) if slot.has_key?(k)
+ }
+ tk_call(*(__item_config_cmd([:heading, tagOrId]).concat(sp_kv)))
+ tk_call(*(__item_config_cmd([:heading, tagOrId]).concat(hash_kv(slot))))
+ elsif __tile_specific_item_optkeys([:heading, tagOrId]).index(slot.to_s)
+ begin
+ # On tile-0.7.{2-8}, 'state' options has no '-' at its head.
+ tk_call(*(__item_cget_cmd([:heading, tagOrId]) << slot.to_s << value))
+ rescue
+ # Maybe, 'state' option has '-' in future.
+ tk_call(*(__item_cget_cmd([:heading, tagOrId]) << "-#{slot}" << value))
end
- alias column_cget columncget
- alias column_configure columnconfigure
- alias column_configinfo columnconfiginfo
- alias current_column_configinfo current_columnconfiginfo
-
- # Treeview Heading
- def headingcget(tagOrId, option)
- __itemcget([:heading, tagOrId], option)
+ else
+ __itemconfigure([:heading, tagOrId], slot, value)
+ end
+ self
+ end
+ def headingconfiginfo(tagOrId, slot=nil)
+ __itemconfiginfo([:heading, tagOrId], slot)
+ end
+ def current_headingconfiginfo(tagOrId, slot=nil)
+ __current_itemconfiginfo([:heading, tagOrId], slot)
+ end
+ alias heading_cget headingcget
+ alias heading_cget_strict headingcget_strict
+ alias heading_configure headingconfigure
+ alias heading_configinfo headingconfiginfo
+ alias current_heading_configinfo current_headingconfiginfo
+
+ # Treeview Tag
+ def tagcget(tagOrId, option)
+ __itemcget([:tag, tagOrId], option)
+ end
+ def tagcget_strict(tagOrId, option)
+ __itemcget_strict([:tag, tagOrId], option)
+ end
+ def tagconfigure(tagOrId, slot, value=None)
+ __itemconfigure([:tag, tagOrId], slot, value)
+ end
+ def tagconfiginfo(tagOrId, slot=nil)
+ __itemconfiginfo([:tag, tagOrId], slot)
+ end
+ def current_tagconfiginfo(tagOrId, slot=nil)
+ __current_itemconfiginfo([:tag, tagOrId], slot)
+ end
+ alias tag_cget tagcget
+ alias tag_cget_strict tagcget_strict
+ alias tag_configure tagconfigure
+ alias tag_configinfo tagconfiginfo
+ alias current_tag_configinfo current_tagconfiginfo
+end
+
+########################
+
+class Tk::Tile::Treeview::Item < TkObject
+ ItemID_TBL = TkCore::INTERP.create_table
+
+ TkCore::INTERP.init_ip_env{
+ Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{
+ Tk::Tile::Treeview::Item::ItemID_TBL.clear
+ }
+ }
+
+ def self.id2obj(tree, id)
+ tpath = tree.path
+ Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{
+ if Tk::Tile::Treeview::Item::ItemID_TBL[tpath]
+ (Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id])? \
+ Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id]: id
+ else
+ id
end
- def headingconfigure(tagOrId, slot, value=None)
- __itemconfigure([:heading, tagOrId], slot, value)
+ }
+ end
+
+ def self.assign(tree, id)
+ tpath = tree.path
+ obj = nil
+ Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{
+ if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] &&
+ Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id]
+ return Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id]
end
- def headingconfiginfo(tagOrId, slot=nil)
- __itemconfiginfo([:heading, tagOrId], slot)
+
+ obj = self.allocate
+ obj.instance_eval{
+ @parent = @t = tree
+ @tpath = tpath
+ @path = @id = id
+ }
+ Tk::Tile::Treeview::Item::ItemID_TBL[tpath] ||= {}
+ Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] = obj
+ }
+ obj
+ end
+
+ def _insert_item(tree, parent_item, idx, keys={})
+ keys = _symbolkey2str(keys)
+ id = keys.delete('id')
+ if id
+ num_or_str(tk_call(tree, 'insert',
+ parent_item, idx, '-id', id, *hash_kv(keys)))
+ else
+ num_or_str(tk_call(tree, 'insert', parent_item, idx, *hash_kv(keys)))
+ end
+ end
+ private :_insert_item
+
+ def initialize(tree, parent_item = '', idx = 'end', keys = {})
+ if parent_item.kind_of?(Hash)
+ keys = parent_item
+ idx = 'end'
+ parent_item = ''
+ elsif idx.kind_of?(Hash)
+ keys = idx
+ idx = 'end'
+ end
+
+ @parent = @t = tree
+ @tpath = tree.path
+ @path = @id = _insert_item(@t, parent_item, idx, keys)
+ Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{
+ ItemID_TBL[@tpath] = {} unless ItemID_TBL[@tpath]
+ ItemID_TBL[@tpath][@id] = self
+ }
+ end
+ def id
+ @id
+ end
+
+ def cget(option)
+ @t.itemcget(@id, option)
+ end
+ def cget_strict(option)
+ @t.itemcget_strict(@id, option)
+ end
+
+ def configure(key, value=None)
+ @t.itemconfigure(@id, key, value)
+ self
+ end
+
+ def configinfo(key=nil)
+ @t.itemconfiginfo(@id, key)
+ end
+
+ def current_configinfo(key=nil)
+ @t.current_itemconfiginfo(@id, key)
+ end
+
+ def open?
+ cget('open')
+ end
+ def open
+ configure('open', true)
+ self
+ end
+ def close
+ configure('open', false)
+ self
+ end
+
+ def bbox(column=None)
+ @t.bbox(@id, column)
+ end
+
+ def children
+ @t.children(@id)
+ end
+ def set_children(*items)
+ @t.set_children(@id, *items)
+ self
+ end
+
+ def delete
+ @t.delete(@id)
+ self
+ end
+
+ def detach
+ @t.detach(@id)
+ self
+ end
+
+ def exist?
+ @t.exist?(@id)
+ end
+
+ def focus
+ @t.focus_item(@id)
+ end
+
+ def index
+ @t.index(@id)
+ end
+
+ def insert(idx='end', keys={})
+ @t.insert(@id, idx, keys)
+ end
+
+ def move(parent, idx)
+ @t.move(@id, parent, idx)
+ self
+ end
+
+ def next_item
+ @t.next_item(@id)
+ end
+
+ def parent_item
+ @t.parent_item(@id)
+ end
+
+ def prev_item
+ @t.prev_item(@id)
+ end
+
+ def see
+ @t.see(@id)
+ self
+ end
+
+ def selection_add
+ @t.selection_add(@id)
+ self
+ end
+
+ def selection_remove
+ @t.selection_remove(@id)
+ self
+ end
+
+ def selection_set
+ @t.selection_set(@id)
+ self
+ end
+
+ def selection_toggle
+ @t.selection_toggle(@id)
+ self
+ end
+
+ def get_directory
+ @t.get_directory(@id)
+ end
+ alias get_dictionary get_directory
+
+ def get(col)
+ @t.get(@id, col)
+ end
+
+ def set(col, value)
+ @t.set(@id, col, value)
+ end
+end
+
+########################
+
+class Tk::Tile::Treeview::Root < Tk::Tile::Treeview::Item
+ def self.new(tree, keys = {})
+ tpath = tree.path
+ obj = nil
+ Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{
+ if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] &&
+ Tk::Tile::Treeview::Item::ItemID_TBL[tpath]['']
+ obj = Tk::Tile::Treeview::Item::ItemID_TBL[tpath]['']
+ else
+ #super(tree, keys)
+ (obj = self.allocate).instance_eval{
+ @parent = @t = tree
+ @tpath = tree.path
+ @path = @id = ''
+ Tk::Tile::Treeview::Item::ItemID_TBL[@tpath] ||= {}
+ Tk::Tile::Treeview::Item::ItemID_TBL[@tpath][@id] = self
+ }
end
- def current_headingconfiginfo(tagOrId, slot=nil)
- __current_itemconfiginfo([:heading, tagOrId], slot)
+ }
+ obj.configure(keys) if keys && ! keys.empty?
+ obj
+ end
+
+ def initialize(tree, keys = {})
+ # dummy:: not called by 'new' method
+ @parent = @t = tree
+ @tpath = tree.path
+ @path = @id = ''
+ Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{
+ Tk::Tile::Treeview::Item::ItemID_TBL[@tpath] ||= {}
+ Tk::Tile::Treeview::Item::ItemID_TBL[@tpath][@id] = self
+ }
+ end
+end
+
+########################
+
+class Tk::Tile::Treeview::Tag < TkObject
+ include TkTreatTagFont
+
+ TagID_TBL = TkCore::INTERP.create_table
+
+ (Tag_ID = ['tile_treeview_tag'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
+ TkCore::INTERP.init_ip_env{
+ Tk::Tile::Treeview::Tag::TagID_TBL.mutex.synchronize{
+ Tk::Tile::Treeview::Tag::TagID_TBL.clear
+ }
+ }
+
+ def self.id2obj(tree, id)
+ tpath = tree.path
+ Tk::Tile::Treeview::Tag::TagID_TBL.mutex.synchronize{
+ if Tk::Tile::Treeview::Tag::TagID_TBL[tpath]
+ (Tk::Tile::Treeview::Tag::TagID_TBL[tpath][id])? \
+ Tk::Tile::Treeview::Tag::TagID_TBL[tpath][id]: id
+ else
+ id
end
- alias heading_cget headingcget
- alias heading_configure headingconfigure
- alias heading_configinfo headingconfiginfo
- alias current_heading_configinfo current_headingconfiginfo
+ }
+ end
+
+ def initialize(tree, keys=nil)
+ @parent = @t = tree
+ @tpath = tree.path
+ Tag_ID.mutex.synchronize{
+ @path = @id = Tag_ID.join(TkCore::INTERP._ip_id_)
+ Tag_ID[1].succ!
+ }
+ TagID_TBL.mutex.synchronize{
+ TagID_TBL[@tpath] = {} unless TagID_TBL[@tpath]
+ TagID_TBL[@tpath][@id] = self
+ }
+ if keys && keys != None
+ tk_call_without_enc(@tpath, 'tag', 'configure', *hash_kv(keys, true))
+ end
+ end
+ def id
+ @id
+ end
+
+ def bind(seq, *args)
+ if TkComm._callback_entry?(args[0]) || !block_given?
+ cmd = args.shift
+ else
+ cmd = Proc.new
+ end
+ @t.tag_bind(@id, seq, cmd, *args)
+ self
+ end
+
+ def bind_append(seq, *args)
+ if TkComm._callback_entry?(args[0]) || !block_given?
+ cmd = args.shift
+ else
+ cmd = Proc.new
end
+ @t.tag_bind_append(@id, seq, cmd, *args)
+ self
+ end
+
+ def bind_remove(seq)
+ @t.tag_bind_remove(@id, seq)
+ self
+ end
+
+ def bindinfo(seq=nil)
+ @t.tag_bindinfo(@id, seq)
+ end
+
+ def cget(option)
+ @t.tagcget(@id, option)
+ end
+ def cget_strict(option)
+ @t.tagcget_strict(@id, option)
+ end
+
+ def configure(key, value=None)
+ @t.tagconfigure(@id, key, value)
+ self
+ end
+
+ def configinfo(key=nil)
+ @t.tagconfiginfo(@id, key)
+ end
+
+ def current_configinfo(key=nil)
+ @t.current_tagconfiginfo(@id, key)
end
end
+########################
+
class Tk::Tile::Treeview < TkWindow
include Tk::Tile::TileWidget
include Scrollable
@@ -146,20 +1016,42 @@ class Tk::Tile::Treeview < TkWindow
WidgetClassName = 'Treeview'.freeze
WidgetClassNames[WidgetClassName] = self
+ def __destroy_hook__
+ Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{
+ Tk::Tile::Treeview::Item::ItemID_TBL.delete(@path)
+ }
+ Tk::Tile::Treeview::Tag::ItemID_TBL.mutex.synchronize{
+ Tk::Tile::Treeview::Tag::ItemID_TBL.delete(@path)
+ }
+ end
+
def self.style(*args)
[self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.')
end
def tagid(id)
- if id.kind_of?(Array)
+ if id.kind_of?(Tk::Tile::Treeview::Item) ||
+ id.kind_of?(Tk::Tile::Treeview::Tag)
+ id.id
+ elsif id.kind_of?(Array)
[id[0], _get_eval_string(id[1])]
else
_get_eval_string(id)
end
end
+ def root
+ Tk::Tile::Treeview::Root.new(self)
+ end
+
+ def bbox(item, column=None)
+ list(tk_send('item', 'bbox', item, column))
+ end
+
def children(item)
- simplelist(tk_send_without_enc('children', item))
+ simplelist(tk_send_without_enc('children', item)).collect{|id|
+ Tk::Tile::Treeview::Item.id2obj(self, id)
+ }
end
def set_children(item, *items)
tk_send_without_enc('children', item,
@@ -181,55 +1073,84 @@ class Tk::Tile::Treeview < TkWindow
bool(tk_send_without_enc('exists', _get_eval_enc_str(item)))
end
- def focus_item(item = None)
- tk_send('focus', item)
+ def focus_item(item = nil)
+ if item
+ tk_send('focus', item)
+ item
+ else
+ id = tk_send('focus')
+ (id.empty?)? nil: Tk::Tile::Treeview::Item.id2obj(self, id)
+ end
end
def identify(x, y)
+ # tile-0.7.2 or previous
ret = simplelist(tk_send('identify', x, y))
case ret[0]
- when 'heading', 'separator', 'cell'
+ when 'heading', 'separator'
+ ret[-1] = num_or_str(ret[-1])
+ when 'cell'
+ ret[1] = Tk::Tile::Treeview::Item.id2obj(self, ret[1])
ret[-1] = num_or_str(ret[-1])
+ when 'item', 'row'
+ ret[1] = Tk::Tile::Treeview::Item.id2obj(self, ret[1])
end
end
- def index(item)
- number(tk_send('index', item))
+ def row_identify(x, y)
+ id = tk_send('identify', 'row', x, y)
+ (id.empty?)? nil: Tk::Tile::Treeview::Item.id2obj(self, id)
end
- def insert(parent, idx, keys={})
- keys = _symbolkey2str(keys)
- id = keys.delete('id')
- if id
- tk_send('insert', parent, idx, '-id', id, *hash_kv(keys))
- else
- tk_send('insert', parent, idx, *hash_kv(keys))
- end
- self
+ def column_identify(x, y)
+ tk_send('identify', 'column', x, y)
end
- def instate(spec, cmd=Proc.new)
- tk_send('instate', spec, cmd)
+ def index(item)
+ number(tk_send('index', item))
end
- def state(spec=None)
- tk_send('state', spec)
+
+ # def insert(parent, idx='end', keys={})
+ # keys = _symbolkey2str(keys)
+ # id = keys.delete('id')
+ # if id
+ # num_or_str(tk_send('insert', parent, idx, '-id', id, *hash_kv(keys)))
+ # else
+ # num_or_str(tk_send('insert', parent, idx, *hash_kv(keys)))
+ # end
+ # end
+ def insert(parent, idx='end', keys={})
+ Tk::Tile::Treeview::Item.new(self, parent, idx, keys)
end
+ # def instate(spec, cmd=Proc.new)
+ # tk_send('instate', spec, cmd)
+ # end
+ # def state(spec=None)
+ # tk_send('state', spec)
+ # end
+
def move(item, parent, idx)
tk_send('move', item, parent, idx)
self
end
- def next(item)
- tk_send('next', item)
+ def next_item(item)
+ id = tk_send('next', item)
+ (id.empty?)? nil: Tk::Tile::Treeview::Item.id2obj(self, id)
end
- def parent(item)
- tk_send('parent', item)
+ def parent_item(item)
+ if (id = tk_send('parent', item)).empty?
+ Tk::Tile::Treeview::Root.new(self)
+ else
+ Tk::Tile::Treeview::Item.id2obj(self, id)
+ end
end
- def prev(item)
- tk_send('prev', item)
+ def prev_item(item)
+ id = tk_send('prev', item)
+ (id.empty?)? nil: Tk::Tile::Treeview::Item.id2obj(self, id)
end
def see(item)
@@ -238,7 +1159,9 @@ class Tk::Tile::Treeview < TkWindow
end
def selection
- simplelist(tk_send('selection'))
+ simplelist(tk_send('selection')).collect{|id|
+ Tk::Tile::Treeview::Item.id2obj(self, id)
+ }
end
alias selection_get selection
@@ -270,6 +1193,8 @@ class Tk::Tile::Treeview < TkWindow
end
ret
end
+ alias get_dictionary get_directory
+
def get(item, col)
tk_send('set', item, col)
end
@@ -277,4 +1202,37 @@ class Tk::Tile::Treeview < TkWindow
tk_send('set', item, col, value)
self
end
+
+ def tag_bind(tag, seq, *args)
+ if TkComm._callback_entry?(args[0]) || !block_given?
+ cmd = args.shift
+ else
+ cmd = Proc.new
+ end
+ _bind([@path, 'tag', 'bind', tag], seq, cmd, *args)
+ self
+ end
+ alias tagbind tag_bind
+
+ def tag_bind_append(tag, seq, *args)
+ if TkComm._callback_entry?(args[0]) || !block_given?
+ cmd = args.shift
+ else
+ cmd = Proc.new
+ end
+ _bind_append([@path, 'tag', 'bind', tag], seq, cmd, *args)
+ self
+ end
+ alias tagbind_append tag_bind_append
+
+ def tag_bind_remove(tag, seq)
+ _bind_remove([@path, 'tag', 'bind', tag], seq)
+ self
+ end
+ alias tagbind_remove tag_bind_remove
+
+ def tag_bindinfo(tag, context=nil)
+ _bindinfo([@path, 'tag', 'bind', tag], context)
+ end
+ alias tagbindinfo tag_bindinfo
end
diff --git a/ext/tk/lib/tkextlib/tile/tscale.rb b/ext/tk/lib/tkextlib/tile/tscale.rb
index 7ec72e3515..2c46fd9bd4 100644
--- a/ext/tk/lib/tkextlib/tile/tscale.rb
+++ b/ext/tk/lib/tkextlib/tile/tscale.rb
@@ -7,7 +7,7 @@ require 'tkextlib/tile.rb'
module Tk
module Tile
- class TScale < TkScale
+ class TScale < Tk::Scale
end
Scale = TScale
@@ -17,7 +17,10 @@ module Tk
end
end
-class Tk::Tile::TScale < TkScale
+Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Scale, :TkScale)
+
+
+class Tk::Tile::TScale < Tk::Scale
include Tk::Tile::TileWidget
if Tk::Tile::USE_TTK_NAMESPACE
diff --git a/ext/tk/lib/tkextlib/tile/tscrollbar.rb b/ext/tk/lib/tkextlib/tile/tscrollbar.rb
index bd49ae18e3..163b8f4713 100644
--- a/ext/tk/lib/tkextlib/tile/tscrollbar.rb
+++ b/ext/tk/lib/tkextlib/tile/tscrollbar.rb
@@ -7,13 +7,16 @@ require 'tkextlib/tile.rb'
module Tk
module Tile
- class TScrollbar < TkScrollbar
+ class TScrollbar < Tk::Scrollbar
end
Scrollbar = TScrollbar
end
end
-class Tk::Tile::TScrollbar < TkScrollbar
+Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Scrollbar, :TkScrollbar)
+
+
+class Tk::Tile::TScrollbar < Tk::Scrollbar
include Tk::Tile::TileWidget
if Tk::Tile::USE_TTK_NAMESPACE
@@ -28,3 +31,24 @@ class Tk::Tile::TScrollbar < TkScrollbar
[self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.')
end
end
+
+class Tk::Tile::XScrollbar < Tk::Tile::TScrollbar
+ def create_self(keys)
+ keys = {} unless keys
+ keys['orient'] = 'horizontal'
+ super(keys)
+ end
+ private :create_self
+end
+
+class Tk::Tile::YScrollbar < Tk::Tile::TScrollbar
+ def create_self(keys)
+ keys = {} unless keys
+ keys['orient'] = 'vertical'
+ super(keys)
+ end
+ private :create_self
+end
+
+Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::XScrollbar, :TkXScrollbar)
+Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::YScrollbar, :TkYScrollbar)
diff --git a/ext/tk/lib/tkextlib/tile/tseparator.rb b/ext/tk/lib/tkextlib/tile/tseparator.rb
index ca731d4e5b..30fae2c525 100644
--- a/ext/tk/lib/tkextlib/tile/tseparator.rb
+++ b/ext/tk/lib/tkextlib/tile/tseparator.rb
@@ -13,6 +13,9 @@ module Tk
end
end
+Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Separator, :TkSeparator)
+
+
class Tk::Tile::TSeparator < TkWindow
include Tk::Tile::TileWidget
diff --git a/ext/tk/lib/tkextlib/tkDND/shape.rb b/ext/tk/lib/tkextlib/tkDND/shape.rb
index 570c93b0d9..d44068ed33 100644
--- a/ext/tk/lib/tkextlib/tkDND/shape.rb
+++ b/ext/tk/lib/tkextlib/tkDND/shape.rb
@@ -11,15 +11,15 @@ require 'tkextlib/setup.rb'
# call setup script
require 'tkextlib/tkDND/setup.rb'
-# TkPackage.require('shape', '0.3')
-TkPackage.require('shape')
+# TkPackage.require('Shape', '0.3')
+TkPackage.require('Shape')
module Tk
module TkDND
module Shape
extend TkCore
- PACKAGE_NAME = 'shape'.freeze
+ PACKAGE_NAME = 'Shape'.freeze
def self.package_name
PACKAGE_NAME
end
@@ -27,26 +27,28 @@ module Tk
=begin
def self.package_version
begin
- TkPackage.require('shape')
+ TkPackage.require('Shape')
rescue
''
end
end
=end
- def self.package_version
- Tk.tk_call('set', 'shape_version')
- end
- alias shape_version package_version
+ class << self
+ def package_version
+ Tk.tk_call('set', 'shape_version')
+ end
+ alias shape_version package_version
- def self.package_patchlevel
- Tk.tk_call('set', 'shape_patchlevel')
- end
- alias shape_patchlevel package_patchlevel
+ def package_patchlevel
+ Tk.tk_call('set', 'shape_patchLevel')
+ end
+ alias shape_patchlevel package_patchlevel
- def self.version
- tk_call('shape', 'version')
+ def version
+ tk_call('shape', 'version')
+ end
+ alias xshape_version version
end
- alias xshape_version version
############################
diff --git a/ext/tk/lib/tkextlib/tkDND/tkdnd.rb b/ext/tk/lib/tkextlib/tkDND/tkdnd.rb
index a040532eb6..9a9b2dc42c 100644
--- a/ext/tk/lib/tkextlib/tkDND/tkdnd.rb
+++ b/ext/tk/lib/tkextlib/tkDND/tkdnd.rb
@@ -57,6 +57,24 @@ module Tk
nil
]
+=begin
+ # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
+ KEY_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String)
+ end
+ inf
+ }
+
+ PROC_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ end
+ inf
+ }
+=end
+
# setup tables
_setup_subst_table(KEY_TBL, PROC_TBL);
end
diff --git a/ext/tk/lib/tkextlib/tkHTML/htmlwidget.rb b/ext/tk/lib/tkextlib/tkHTML/htmlwidget.rb
index 8527f61df1..d893a83cf2 100644
--- a/ext/tk/lib/tkextlib/tkHTML/htmlwidget.rb
+++ b/ext/tk/lib/tkextlib/tkHTML/htmlwidget.rb
@@ -39,7 +39,10 @@ class Tk::HTML_Widget::ClippingWindow
WidgetClassNames[WidgetClassName] = self
HtmlClip_TBL = TkCore::INTERP.create_table
- TkCore::INTERP.init_ip_env{ HtmlClip_TBL.clear }
+
+ TkCore::INTERP.init_ip_env{
+ HtmlClip_TBL.mutex.synchronize{ HtmlClip_TBL.clear }
+ }
def self.new(parent, keys={})
if parent.kind_of?(Hash)
@@ -54,7 +57,9 @@ class Tk::HTML_Widget::ClippingWindow
else
ppath = ''
end
- return HtmlClip_TBL[ppath] if HtmlClip_TBL[ppath]
+ HtmlClip_TBL.mutex.synchronize{
+ return HtmlClip_TBL[ppath] if HtmlClip_TBL[ppath]
+ }
widgetname = keys.delete('widgetname')
if widgetname =~ /^(.*)\.[^.]+$/
@@ -62,7 +67,9 @@ class Tk::HTML_Widget::ClippingWindow
if ppath2[0] != ?.
ppath2 = ppath + '.' + ppath2
end
- return HtmlClip_TBL[ppath2] if HtmlClip_TBL[ppath2]
+ HtmlClip_TBL.mutex.synchronize{
+ return HtmlClip_TBL[ppath2] if HtmlClip_TBL[ppath2]
+ }
ppath = ppath2
end
@@ -79,7 +86,9 @@ class Tk::HTML_Widget::ClippingWindow
@parent = parent
@ppath = parent.path
@path = @id = @ppath + '.x'
- HtmlClip_TBL[@ppath] = self
+ HtmlClip_TBL.mutex.synchronize{
+ HtmlClip_TBL[@ppath] = self
+ }
end
def method_missing(m, *args, &b)
diff --git a/ext/tk/lib/tkextlib/tktable/tktable.rb b/ext/tk/lib/tkextlib/tktable/tktable.rb
index 4edaabc847..f6cf24b40f 100644
--- a/ext/tk/lib/tkextlib/tktable/tktable.rb
+++ b/ext/tk/lib/tkextlib/tktable/tktable.rb
@@ -77,6 +77,9 @@ module Tk::TkTable::ConfigMethod
def tag_cget(tagOrId, option)
itemcget(['tag', tagid(tagOrId)], option)
end
+ def tag_cget_strict(tagOrId, option)
+ itemcget_strict(['tag', tagid(tagOrId)], option)
+ end
def tag_configure(tagOrId, slot, value=None)
itemconfigure(['tag', tagid(tagOrId)], slot, value)
end
@@ -90,6 +93,9 @@ module Tk::TkTable::ConfigMethod
def window_cget(tagOrId, option)
itemcget(['window', tagid(tagOrId)], option)
end
+ def window_cget_strict(tagOrId, option)
+ itemcget_strict(['window', tagid(tagOrId)], option)
+ end
def window_configure(tagOrId, slot, value=None)
if slot == :window || slot == 'window'
value = _epath(value)
@@ -108,8 +114,8 @@ module Tk::TkTable::ConfigMethod
current_itemconfiginfo(['window', tagid(tagOrId)], slot)
end
- private :itemcget, :itemconfigure
- private :itemconfiginfo, :current_itemconfiginfo
+ private :itemcget, :itemcget_strict
+ private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo
end
#####################################################
@@ -118,23 +124,39 @@ class Tk::TkTable::CellTag
include TkTreatTagFont
CellTagID_TBL = TkCore::INTERP.create_table
- CellTag_ID = ['tktbl:celltag'.freeze, '00000'.taint].freeze
- TkCore::INTERP.init_ip_env{ CellTagID_TBL.clear }
+ (CellTag_ID = ['tktbl:celltag'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
+ TkCore::INTERP.init_ip_env{
+ CellTagID_TBL.mutex.synchronize{ CellTagID_TBL.clear }
+ }
def self.id2obj(table, id)
tpath = table.path
- return id unless CellTagID_TBL[tpath]
- CellTagID_TBL[tpath][id]? CellTagID_TBL[tpath][id] : id
+ CellTagID_TBL.mutex.synchronize{
+ if CellTagID_TBL[tpath]
+ CellTagID_TBL[tpath][id]? CellTagID_TBL[tpath][id] : id
+ else
+ id
+ end
+ }
end
def initialize(parent, keys=nil)
@parent = @t = parent
@tpath - parent.path
- @path = @id = CellTag_ID.join(TkCore::INTERP._ip_id_)
- CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath]
- CellTagID_TBL[@tpath][@id] = self
- CellTag_ID[1].succ!
+ CellTag_ID.mutex.synchronize{
+ @path = @id = CellTag_ID.join(TkCore::INTERP._ip_id_)
+ CellTag_ID[1].succ!
+ }
+ CellTagID_TBL.mutex.synchronize{
+ CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath]
+ CellTagID_TBL[@tpath][@id] = self
+ }
configure(keys) if keys
end
@@ -144,7 +166,9 @@ class Tk::TkTable::CellTag
def destroy
tk_call(@tpath, 'tag', 'delete', @id)
- CellTagID_TBL[@tpath].delete(@id) if CellTagID_TBL[@tpath]
+ CellTagID_TBL.mutex.synchronize{
+ CellTagID_TBL[@tpath].delete(@id) if CellTagID_TBL[@tpath]
+ }
self
end
alias delete destroy
@@ -176,6 +200,9 @@ class Tk::TkTable::CellTag
def cget(key)
@t.tag_cget(@id, key)
end
+ def cget_strict(key)
+ @t.tag_cget_strict(@id, key)
+ end
def configure(key, val=None)
@t.tag_configure(@id, key, val)
end
@@ -189,22 +216,35 @@ end
class Tk::TkTable::NamedCellTag < Tk::TkTable::CellTag
def self.new(parent, name, keys=nil)
- if CellTagID_TBL[parent.path] && CellTagID_TBL[parent.path][name]
- cell = CellTagID_TBL[parent.path][name]
- cell.configure(keys) if keys
- return cell
- else
- super(parent, name, keys)
- end
+ obj = nil
+ CellTagID_TBL.mutex.synchronize{
+ if CellTagID_TBL[parent.path] && CellTagID_TBL[parent.path][name]
+ obj = CellTagID_TBL[parent.path][name]
+ else
+ #super(parent, name, keys)
+ (obj = self.allocate).instance_eval{
+ @parent = @t = parent
+ @tpath = parent.path
+ @path = @id = name
+ CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath]
+ CellTagID_TBL[@tpath][@id] = self
+ }
+ end
+ }
+ obj.configure(keys) if keys && ! keys.empty?
+ obj
end
def initialize(parent, name, keys=nil)
+ # dummy:: not called by 'new' method
@parent = @t = parent
- @tpath - parent.path
+ @tpath = parent.path
@path = @id = name
- CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath]
- CellTagID_TBL[@tpath][@id] = self
- configure(keys) if keys
+ CellTagID_TBL.mutex.synchronize{
+ CellTagID_TBL[@tpath] = {} unless CellTagID_TBL[@tpath]
+ CellTagID_TBL[@tpath][@id] = self
+ }
+ configure(keys) if keys && ! keys.empty?
end
end
@@ -220,7 +260,9 @@ class Tk::TkTable
include Tk::ValidateConfigure
def __destroy_hook__
- Tk::TkTable::CelTag::CellTagID_TBL.delete(@path)
+ Tk::TkTable::CelTag::CellTagID_TBL.mutex.synchronize{
+ Tk::TkTable::CelTag::CellTagID_TBL.delete(@path)
+ }
end
def __boolval_optkeys
@@ -258,6 +300,24 @@ class Tk::TkTable
nil
]
+=begin
+ # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
+ KEY_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String)
+ end
+ inf
+ }
+
+ PROC_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ end
+ inf
+ }
+=end
+
_setup_subst_table(KEY_TBL, PROC_TBL);
def self.ret_val(val)
@@ -291,6 +351,24 @@ class Tk::TkTable
nil
]
+=begin
+ # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
+ KEY_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String)
+ end
+ inf
+ }
+
+ PROC_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ end
+ inf
+ }
+=end
+
_setup_subst_table(KEY_TBL, PROC_TBL);
def self.ret_val(val)
@@ -322,6 +400,24 @@ class Tk::TkTable
nil
]
+=begin
+ # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
+ KEY_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String)
+ end
+ inf
+ }
+
+ PROC_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ end
+ inf
+ }
+=end
+
_setup_subst_table(KEY_TBL, PROC_TBL);
def self.ret_val(val)
@@ -356,6 +452,24 @@ class Tk::TkTable
nil
]
+=begin
+ # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
+ KEY_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String)
+ end
+ inf
+ }
+
+ PROC_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ end
+ inf
+ }
+=end
+
_setup_subst_table(KEY_TBL, PROC_TBL);
end
@@ -746,15 +860,17 @@ class Tk::TkTable
end
def tagid2obj(tagid)
- if Tk::TkTable::CellTag::CellTagID_TBL.key?(@path)
- if Tk::TkTable::CellTag::CellTagID_TBL[@path].key?(tagid)
- Tk::TkTable::CellTag::CellTagID_TBL[@path][tagid]
+ Tk::TkTable::CellTag::CellTagID_TBL.mutex.synchronize{
+ if Tk::TkTable::CellTag::CellTagID_TBL.key?(@path)
+ if Tk::TkTable::CellTag::CellTagID_TBL[@path].key?(tagid)
+ Tk::TkTable::CellTag::CellTagID_TBL[@path][tagid]
+ else
+ tagid
+ end
else
tagid
end
- else
- tagid
- end
+ }
end
def tag_cell(tag, *cells)
@@ -775,13 +891,15 @@ class Tk::TkTable
end
def tag_delete(tag)
tk_send('tag', 'delete', tagid(tag))
- if Tk::TkTable::CellTag::CellTagID_TBL[@path]
- if tag.kind_of? Tk::TkTable::CellTag
- Tk::TkTable::CellTag::CellTagID_TBL[@path].delete(tag.id)
- else
- Tk::TkTable::CellTag::CellTagID_TBL[@path].delete(tag)
+ Tk::TkTable::CellTag::CellTagID_TBL.mutex.synchronize{
+ if Tk::TkTable::CellTag::CellTagID_TBL[@path]
+ if tag.kind_of? Tk::TkTable::CellTag
+ Tk::TkTable::CellTag::CellTagID_TBL[@path].delete(tag.id)
+ else
+ Tk::TkTable::CellTag::CellTagID_TBL[@path].delete(tag)
+ end
end
- end
+ }
self
end
def tag_exist?(tag)
diff --git a/ext/tk/lib/tkextlib/tktrans/tktrans.rb b/ext/tk/lib/tkextlib/tktrans/tktrans.rb
index 665c57af0c..e051c09211 100644
--- a/ext/tk/lib/tkextlib/tktrans/tktrans.rb
+++ b/ext/tk/lib/tkextlib/tktrans/tktrans.rb
@@ -39,7 +39,7 @@ class TkWindow
end
end
-class TkRoot
+class Tk::Root
undef tktrans_set_image, tktrans_get_image
def tktrans_set_image(img)
@@ -51,7 +51,7 @@ class TkRoot
end
end
-class TkToplevel
+class Tk::Toplevel
undef tktrans_set_image, tktrans_get_image
def tktrans_set_image(img)
diff --git a/ext/tk/lib/tkextlib/treectrl/tktreectrl.rb b/ext/tk/lib/tkextlib/treectrl/tktreectrl.rb
index 12f7cffabf..e10e6e299e 100644
--- a/ext/tk/lib/tkextlib/treectrl/tktreectrl.rb
+++ b/ext/tk/lib/tkextlib/treectrl/tktreectrl.rb
@@ -137,6 +137,24 @@ class Tk::TreeCtrl::NotifyEvent
nil
]
+=begin
+ # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
+ KEY_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String)
+ end
+ inf
+ }
+
+ PROC_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ end
+ inf
+ }
+=end
+
# setup tables to be used by scan_args, _get_subst_key, _get_all_subst_keys
#
# _get_subst_key() and _get_all_subst_keys() generates key-string
@@ -399,6 +417,9 @@ module Tk::TreeCtrl::ConfigMethod
def column_cget(tagOrId, option)
itemcget(['column', tagOrId], option)
end
+ def column_cget_strict(tagOrId, option)
+ itemcget_strict(['column', tagOrId], option)
+ end
def column_configure(tagOrId, slot, value=None)
itemconfigure(['column', tagOrId], slot, value)
end
@@ -412,6 +433,9 @@ module Tk::TreeCtrl::ConfigMethod
def column_dragcget(option)
itemcget(['column', 'drag'], option)
end
+ def column_dragcget_strict(option)
+ itemcget_strict(['column', 'drag'], option)
+ end
def column_dragconfigure(slot, value=None)
itemconfigure(['column', 'drag'], slot, value)
end
@@ -425,6 +449,9 @@ module Tk::TreeCtrl::ConfigMethod
def debug_cget(option)
itemcget('debug', option)
end
+ def debug_cget_strict(option)
+ itemcget_strict('debug', option)
+ end
def debug_configure(slot, value=None)
itemconfigure('debug', slot, value)
end
@@ -438,6 +465,9 @@ module Tk::TreeCtrl::ConfigMethod
def dragimage_cget(option)
itemcget('dragimage', option)
end
+ def dragimage_cget_strict(option)
+ itemcget_strict('dragimage', option)
+ end
def dragimage_configure(slot, value=None)
itemconfigure('dragimage', slot, value)
end
@@ -451,6 +481,9 @@ module Tk::TreeCtrl::ConfigMethod
def element_cget(tagOrId, option)
itemcget(['element', tagOrId], option)
end
+ def element_cget_strict(tagOrId, option)
+ itemcget_strict(['element', tagOrId], option)
+ end
def element_configure(tagOrId, slot, value=None)
itemconfigure(['element', tagOrId], slot, value)
end
@@ -464,6 +497,9 @@ module Tk::TreeCtrl::ConfigMethod
def item_cget(tagOrId, option)
itemcget(['item', tagOrId], option)
end
+ def item_cget_strict(tagOrId, option)
+ itemcget_strict(['item', tagOrId], option)
+ end
def item_configure(tagOrId, slot, value=None)
itemconfigure(['item', tagOrId], slot, value)
end
@@ -477,6 +513,9 @@ module Tk::TreeCtrl::ConfigMethod
def item_element_cget(item, column, elem, option)
itemcget([['item', 'element'], [item, column, elem]], option)
end
+ def item_element_cget_strict(item, column, elem, option)
+ itemcget_strict([['item', 'element'], [item, column, elem]], option)
+ end
def item_element_configure(item, column, elem, slot, value=None)
itemconfigure([['item', 'element'], [item, column, elem]], slot, value)
end
@@ -490,6 +529,9 @@ module Tk::TreeCtrl::ConfigMethod
def marquee_cget(option)
itemcget('marquee', option)
end
+ def marquee_cget_strict(option)
+ itemcget_strict('marquee', option)
+ end
def marquee_configure(slot, value=None)
itemconfigure('marquee', slot, value)
end
@@ -502,7 +544,19 @@ module Tk::TreeCtrl::ConfigMethod
def notify_cget(win, pattern, option)
pattern = "<#{pattern}>"
- itemconfigure(['notify', [win, pattern]], option)
+ # "notify" doesn't have cget subcommand.
+ current_itemconfiginfo(['notify', [win, pattern]])[option.to_s]
+ end
+ def notify_cget_strict(win, pattern, option)
+ pattern = "<#{pattern}>"
+ # "notify" doesn't have cget subcommand.
+ info = current_itemconfiginfo(['notify', [win, pattern]])
+ option = option.to_s
+ unless info.has_key?(option)
+ fail RuntimeError, "unknown option \"#{option}\""
+ else
+ info[option]
+ end
end
def notify_configure(win, pattern, slot, value=None)
pattern = "<#{pattern}>"
@@ -512,11 +566,17 @@ module Tk::TreeCtrl::ConfigMethod
pattern = "<#{pattern}>"
itemconfiginfo(['notify', [win, pattern]], slot)
end
- alias current_notify_configinfo notify_configinfo
+ def current_notify_configinfo(tagOrId, slot=nil)
+ pattern = "<#{pattern}>"
+ current_itemconfiginfo(['notify', [win, pattern]], slot)
+ end
def style_cget(tagOrId, option)
itemcget(['style', tagOrId], option)
end
+ def style_cget_strict(tagOrId, option)
+ itemcget_strict(['style', tagOrId], option)
+ end
def style_configure(tagOrId, slot, value=None)
itemconfigure(['style', tagOrId], slot, value)
end
@@ -527,8 +587,8 @@ module Tk::TreeCtrl::ConfigMethod
current_itemconfiginfo(['style', tagOrId], slot)
end
- private :itemcget, :itemconfigure
- private :itemconfiginfo, :current_itemconfiginfo
+ private :itemcget, :itemcget_strict
+ private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo
end
##############################################
@@ -544,10 +604,18 @@ class Tk::TreeCtrl
#########################
def __destroy_hook__
- Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.delete(@path)
- Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.delete(@path)
- Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.delete(@path)
- Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.delete(@path)
+ Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{
+ Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.delete(@path)
+ }
+ Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{
+ Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.delete(@path)
+ }
+ Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{
+ Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.delete(@path)
+ }
+ Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{
+ Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.delete(@path)
+ }
end
#########################
@@ -638,9 +706,11 @@ class Tk::TreeCtrl
end
def column_delete(idx)
- if Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[self.path]
- Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[self.path].delete(idx)
- end
+ Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{
+ if Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[self.path]
+ Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[self.path].delete(idx)
+ end
+ }
tk_send('column', 'delete', idx)
self
end
@@ -750,11 +820,13 @@ class Tk::TreeCtrl
end
def element_delete(*elems)
- if Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[self.path]
- elems.each{|elem|
- Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[self.path].delete(elem)
- }
- end
+ Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{
+ if Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[self.path]
+ elems.each{|elem|
+ Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[self.path].delete(elem)
+ }
+ end
+ }
tk_send('element', 'delete', *elems)
self
end
@@ -885,22 +957,25 @@ class Tk::TreeCtrl
def _erase_children(item)
item_children(item).each{|i| _erase_children(i)}
+ # table is already locked
Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path].delete(item)
end
private :_erase_children
def item_delete(first, last=None)
- if Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path]
- if first == 'all' || first == :all || last == 'all' || last == :all
- Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path].clear
- elsif last == None
- _erase_children(first)
- else
- self.range(first, last).each{|id|
- _erase_children(id)
- }
+ Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{
+ if Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path]
+ if first == 'all' || first == :all || last == 'all' || last == :all
+ Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[self.path].clear
+ elsif last == None
+ _erase_children(first)
+ else
+ self.range(first, last).each{|id|
+ _erase_children(id)
+ }
+ end
end
- end
+ }
tk_send('item', 'delete', first, last)
self
end
@@ -1520,11 +1595,13 @@ class Tk::TreeCtrl
end
def style_delete(*args)
- if Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[self.path]
- args.each{|sty|
- Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[self.path].delete(sty)
- }
- end
+ Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{
+ if Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[self.path]
+ args.each{|sty|
+ Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[self.path].delete(sty)
+ }
+ end
+ }
tk_send('style', 'delete', *args)
self
end
@@ -1608,15 +1685,29 @@ end
class Tk::TreeCtrl::Column < TkObject
TreeCtrlColumnID_TBL = TkCore::INTERP.create_table
- TreeCtrlColumnID = ['treectrl_column'.freeze, '00000'.taint].freeze
- TkCore::INTERP.init_ip_env{Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.clear}
+ (TreeCtrlColumnID = ['treectrl_column'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
+ TkCore::INTERP.init_ip_env{
+ Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{
+ Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.clear
+ }
+ }
def self.id2obj(tree, id)
tpath = tree.path
- return id unless Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath]
- Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath][id]? \
- Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath][id] : id
+ Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{
+ if Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath]
+ Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath][id]? \
+ Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[tpath][id] : id
+ else
+ id
+ end
+ }
end
def initialize(parent, keys={})
@@ -1625,17 +1716,19 @@ class Tk::TreeCtrl::Column < TkObject
keys = _symbolkey2str(keys)
- @path = @id =
- keys.delete('tag') ||
- Tk::TreeCtrl::Column::TreeCtrlColumnID.join(TkCore::INTERP._ip_id_)
+ Tk::TreeCtrl::Column::TreeCtrlColumnID.mutex.synchronize{
+ @path = @id =
+ keys.delete('tag') ||
+ Tk::TreeCtrl::Column::TreeCtrlColumnID.join(TkCore::INTERP._ip_id_)
+ Tk::TreeCtrl::Column::TreeCtrlColumnID[1].succ!
+ }
keys['tag'] = @id
- unless Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[@tpath]
- Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[@tpath] = {}
- end
- Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[@tpath][@id] = self
- Tk::TreeCtrl::Column::TreeCtrlColumnID[1].succ!
+ Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL.mutex.synchronize{
+ Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[@tpath] ||= {}
+ Tk::TreeCtrl::Column::TreeCtrlColumnID_TBL[@tpath][@id] = self
+ }
@tree.column_create(keys)
end
@@ -1651,6 +1744,9 @@ class Tk::TreeCtrl::Column < TkObject
def cget(opt)
@tree.column_cget(@tree.column_index(@id), opt)
end
+ def cget_strict(opt)
+ @tree.column_cget_strict(@tree.column_index(@id), opt)
+ end
def configure(*args)
@tree.column_configure(@tree.column_index(@id), *args)
@@ -1692,11 +1788,18 @@ end
class Tk::TreeCtrl::Element < TkObject
TreeCtrlElementID_TBL = TkCore::INTERP.create_table
- TreeCtrlElementID = ['treectrl_element'.freeze, '00000'.taint].freeze
+
+ (TreeCtrlElementID = ['treectrl_element'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
TreeCtrlElemTypeToClass = {}
TkCore::INTERP.init_ip_env{
- Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.clear
+ Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{
+ Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.clear
+ }
}
def self.type2class(type)
@@ -1705,22 +1808,30 @@ class Tk::TreeCtrl::Element < TkObject
def self.id2obj(tree, id)
tpath = tree.path
- return id unless Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath]
- Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath][id]? \
+ Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{
+ if Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath]
+ Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath][id]? \
Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[tpath][id] : id
+ else
+ id
+ end
+ }
end
def initialize(parent, type, keys=nil)
@tree = parent
@tpath = parent.path
@type = type.to_s
- @path = @id =
- Tk::TreeCtrl::Element::TreeCtrlElementID.join(TkCore::INTERP._ip_id_)
- unless Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[@tpath]
- Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[@tpath] = {}
- end
- Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[@tpath][@id] = self
- Tk::TreeCtrl::Element::TreeCtrlElementID[1].succ!
+ Tk::TreeCtrl::Element::TreeCtrlElementID.mutex.synchronize{
+ @path = @id =
+ Tk::TreeCtrl::Element::TreeCtrlElementID.join(TkCore::INTERP._ip_id_)
+ Tk::TreeCtrl::Element::TreeCtrlElementID[1].succ!
+ }
+
+ Tk::TreeCtrl::Element::TreeCtrlElementID_TBL.mutex.synchronize{
+ Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[@tpath] ||= {}
+ Tk::TreeCtrl::Element::TreeCtrlElementID_TBL[@tpath][@id] = self
+ }
@tree.element_create(@id, @type, keys)
end
@@ -1736,6 +1847,9 @@ class Tk::TreeCtrl::Element < TkObject
def cget(opt)
@tree.element_cget(@id, opt)
end
+ def cget_strict(opt)
+ @tree.element_cget_strict(@id, opt)
+ end
def configure(*args)
@tree.element_configure(@id, *args)
@@ -1800,13 +1914,22 @@ end
class Tk::TreeCtrl::Item < TkObject
TreeCtrlItemID_TBL = TkCore::INTERP.create_table
- TkCore::INTERP.init_ip_env{Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.clear}
+ TkCore::INTERP.init_ip_env{
+ Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{
+ Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.clear
+ }
+ }
def self.id2obj(tree, id)
tpath = tree.path
- return id unless Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath]
- Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath][id]? \
- Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath][id] : id
+ Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{
+ if Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath]
+ Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath][id]? \
+ Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[tpath][id] : id
+ else
+ id
+ end
+ }
end
def initialize(parent, keys={})
@@ -1814,10 +1937,10 @@ class Tk::TreeCtrl::Item < TkObject
@tpath = parent.path
@path = @id = @tree.item_create(keys)
- unless Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[@tpath]
- Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[@tpath] = {}
- end
- Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[@tpath][@id] = self
+ Tk::TreeCtrl::Item::TreeCtrlItemID_TBL.mutex.synchronize{
+ Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[@tpath] ||= {}
+ Tk::TreeCtrl::Item::TreeCtrlItemID_TBL[@tpath][@id] = self
+ }
end
def id
@@ -1858,6 +1981,9 @@ class Tk::TreeCtrl::Item < TkObject
def cget(opt)
@tree.item_cget(@id, opt)
end
+ def cget_strict(opt)
+ @tree.item_cget_strict(@id, opt)
+ end
def configure(*args)
@tree.item_configure(@id, *args)
@@ -1891,6 +2017,9 @@ class Tk::TreeCtrl::Item < TkObject
def element_cget(opt)
@tree.item_element_cget(@id, opt)
end
+ def element_cget_strict(opt)
+ @tree.item_element_cget_strict(@id, opt)
+ end
def element_configure(*args)
@tree.item_element_configure(@id, *args)
@@ -2088,27 +2217,45 @@ end
class Tk::TreeCtrl::Style < TkObject
TreeCtrlStyleID_TBL = TkCore::INTERP.create_table
- TreeCtrlStyleID = ['treectrl_style'.freeze, '00000'.taint].freeze
- TkCore::INTERP.init_ip_env{ Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.clear }
+ (TreeCtrlStyleID = ['treectrl_style'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
+ TkCore::INTERP.init_ip_env{
+ Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{
+ Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.clear
+ }
+ }
def self.id2obj(tree, id)
tpath = tree.path
- return id unless Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath]
- Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath][id]? \
- Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath][id] : id
+ Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{
+ if Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath]
+ Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath][id]? \
+ Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[tpath][id] : id
+ else
+ id
+ end
+ }
end
def initialize(parent, keys=nil)
@tree = parent
@tpath = parent.path
- @path = @id =
- Tk::TreeCtrl::Style::TreeCtrlStyleID.join(TkCore::INTERP._ip_id_)
- unless Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[@tpath]
- Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[@tpath] = {}
- end
- Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[@tpath][@id] = self
- Tk::TreeCtrl::Style::TreeCtrlStyleID[1].succ!
+
+ Tk::TreeCtrl::Style::TreeCtrlStyleID.mutex.synchronize{
+ @path = @id =
+ Tk::TreeCtrl::Style::TreeCtrlStyleID.join(TkCore::INTERP._ip_id_)
+ Tk::TreeCtrl::Style::TreeCtrlStyleID[1].succ!
+ }
+
+ Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL.mutex.synchronize{
+ Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[@tpath] ||= {}
+ Tk::TreeCtrl::Style::TreeCtrlStyleID_TBL[@tpath][@id] = self
+ }
@tree.style_create(@id, keys)
end
@@ -2124,6 +2271,9 @@ class Tk::TreeCtrl::Style < TkObject
def cget(opt)
@tree.style_cget(@id, opt)
end
+ def cget_strict(opt)
+ @tree.style_cget_strict(@id, opt)
+ end
def configure(*args)
@tree.style_configure(@id, *args)
diff --git a/ext/tk/lib/tkextlib/version.rb b/ext/tk/lib/tkextlib/version.rb
new file mode 100644
index 0000000000..434ed11a2e
--- /dev/null
+++ b/ext/tk/lib/tkextlib/version.rb
@@ -0,0 +1,6 @@
+#
+# release date of tkextlib
+#
+module Tk
+ Tkextlib_RELEASE_DATE = '2008-05-23'.freeze
+end
diff --git a/ext/tk/lib/tkextlib/vu/pie.rb b/ext/tk/lib/tkextlib/vu/pie.rb
index 78f3fa54da..c1fb6857bf 100644
--- a/ext/tk/lib/tkextlib/vu/pie.rb
+++ b/ext/tk/lib/tkextlib/vu/pie.rb
@@ -116,13 +116,26 @@ end
class Tk::Vu::PieSlice
SliceID_TBL = TkCore::INTERP.create_table
- Pie_Slice_ID = ['vu:pie'.freeze, '00000'.taint].freeze
- TkCore::INTERP.init_ip_env{ SliceID_TBL.clear }
+
+ (Pie_Slice_ID = ['vu:pie'.freeze, '00000'.taint]).instance_eval{
+ @mutex = Mutex.new
+ def mutex; @mutex; end
+ freeze
+ }
+
+ TkCore::INTERP.init_ip_env{
+ SliceID_TBL.mutex.synchronize{ SliceID_TBL.clear }
+ }
def self.id2obj(pie, id)
pie_path = pie.path
- return id unless SliceID_TBL[pie_path]
- SliceID_TBL[pie_path][id]? SliceID_TBL[pie_path][id]: id
+ SliceID_TBL.mutex.synchronize{
+ if SliceID_TBL[pie_path]
+ SliceID_TBL[pie_path][id]? SliceID_TBL[pie_path][id]: id
+ else
+ id
+ end
+ }
end
def initialize(parent, *args)
@@ -131,10 +144,14 @@ class Tk::Vu::PieSlice
end
@parent = @pie = parent
@ppath = parent.path
- @path = @id = Pie_Slice_ID.join(TkCore::INTERP._ip_id_)
- SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath]
- SliceID_TBL[@ppath][@id] = self
- Pie_Slice_ID[1].succ!
+ Pie_Slice_ID.mutex.synchronize{
+ @path = @id = Pie_Slice_ID.join(TkCore::INTERP._ip_id_)
+ Pie_Slice_ID[1].succ!
+ }
+ SliceID_TBL.mutex.synchronize{
+ SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath]
+ SliceID_TBL[@ppath][@id] = self
+ }
if args[-1].kind_of?(Hash)
keys = args.unshift
@@ -160,6 +177,10 @@ class Tk::Vu::PieSlice
@pie.itemcget(@id, slot)
end
+ def cget_strict(slot)
+ @pie.itemcget_strict(@id, slot)
+ end
+
def configure(*args)
@pie.itemconfigure(@id, *args)
self
@@ -209,22 +230,48 @@ end
class Tk::Vu::NamedPieSlice
def self.new(parent, name, *args)
- if SliceID_TBL[parent.path] && SliceID_TBL[parent.path][name]
- return SliceID_TBL[parent.path][name]
- else
- super(parent, name, *args)
- end
+ obj = nil
+ SliceID_TBL.mutex.synchronize{
+ if SliceID_TBL[parent.path] && SliceID_TBL[parent.path][name]
+ obj = SliceID_TBL[parent.path][name]
+ else
+ #super(parent, name, *args)
+ unless parent.kind_of?(Tk::Vu::Pie)
+ fail ArgumentError, "expect a Tk::Vu::Pie instance for 1st argument"
+ end
+ obj = self.allocate
+ obj.instance_eval{
+ @parent = @pie = parent
+ @ppath = parent.path
+ @path = @id = name.to_s
+ SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath]
+ SliceID_TBL[@ppath][@id] = self
+ }
+ end
+ }
+ obj.instance_eval{
+ if args[-1].kind_of?(Hash)
+ keys = args.unshift
+ end
+ @pie.set(@id, *args)
+ configure(keys)
+ }
+
+ obj
end
def initialize(parent, name, *args)
+ # dummy:: not called by 'new' method
unless parent.kind_of?(Tk::Vu::Pie)
fail ArgumentError, "expect a Tk::Vu::Pie instance for 1st argument"
end
@parent = @pie = parent
@ppath = parent.path
@path = @id = name.to_s
- SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath]
- SliceID_TBL[@ppath][@id] = self
+ SliceID_TBL.mutex.synchronize{
+ SliceID_TBL[@ppath] = {} unless SliceID_TBL[@ppath]
+ SliceID_TBL[@ppath][@id] = self
+ }
if args[-1].kind_of?(Hash)
keys = args.unshift
diff --git a/ext/tk/lib/tkextlib/vu/spinbox.rb b/ext/tk/lib/tkextlib/vu/spinbox.rb
index b6499645a3..a7e40ea319 100644
--- a/ext/tk/lib/tkextlib/vu/spinbox.rb
+++ b/ext/tk/lib/tkextlib/vu/spinbox.rb
@@ -17,6 +17,6 @@ end
module Tk
module Vu
- Spinbox = TkSpinbox
+ Spinbox = Tk::Spinbox
end
end
diff --git a/ext/tk/lib/tkextlib/winico/winico.rb b/ext/tk/lib/tkextlib/winico/winico.rb
index c53a3ff48c..00316fd441 100644
--- a/ext/tk/lib/tkextlib/winico/winico.rb
+++ b/ext/tk/lib/tkextlib/winico/winico.rb
@@ -34,10 +34,15 @@ end
class Tk::Winico
WinicoID_TBL = TkCore::INTERP.create_table
- TkCore::INTERP.init_ip_env{ WinicoID_TBL.clear }
+
+ TkCore::INTERP.init_ip_env{
+ WinicoID_TBL.mutex.synchronize{ WinicoID_TBL.clear }
+ }
def self.id2obj(id)
- (WinicoID_TBL.key?(id))? WinicoID_TBL[id] : id
+ WinicoID_TBL.mutex.synchronize{
+ (WinicoID_TBL.key?(id))? WinicoID_TBL[id] : id
+ }
end
def self.info
@@ -81,7 +86,9 @@ class Tk::Winico
"must be given proper information from where loading icons"
end
@path = @id
- WinicoID_TBL[@id] = self
+ WinicoID_TBL.mutex.synchronize{
+ WinicoID_TBL[@id] = self
+ }
end
def id
@@ -96,7 +103,9 @@ class Tk::Winico
def delete
tk_call('winico', 'delete', @id)
- WinicoID_TBL.delete(@id)
+ WinicoID_TBL.mutex.synchronize{
+ WinicoID_TBL.delete(@id)
+ }
self
end
alias destroy delete
@@ -126,15 +135,39 @@ class Tk::Winico
[ ?n, TkComm.method(:number) ],
[ ?s, TkComm.method(:string) ],
[ ?x, proc{|id|
- if Tk::Winico::WinicoID_TBL.key?(id)
- Tk::Winico::WinicoID_TBL[id]
- else
- Tk::Winico.new(nil, nil, id)
- end
+ Tk::Winico::WinicoID_TBL.mutex.synchronize{
+ if Tk::Winico::WinicoID_TBL.key?(id)
+ obj = Tk::Winico::WinicoID_TBL[id]
+ else
+ # Tk::Winico.new(nil, nil, id)
+ obj = Tk::Winico.allocate
+ obj.instance_eval{ @path = @id = id }
+ Tk::Winico::WinicoID_TBL[id] = obj
+ end
+ obj
+ }
} ],
nil
]
+=begin
+ # for Ruby m17n :: ?x --> String --> char-code ( getbyte(0) )
+ KEY_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ inf[1] = inf[1].getbyte(0) if inf[1].kind_of?(String)
+ end
+ inf
+ }
+
+ PROC_TBL.map!{|inf|
+ if inf.kind_of?(Array)
+ inf[0] = inf[0].getbyte(0) if inf[0].kind_of?(String)
+ end
+ inf
+ }
+=end
+
_setup_subst_table(KEY_TBL, PROC_TBL);
def self.ret_val(val)
@@ -154,7 +187,8 @@ class Tk::Winico
Winico_callback._config_keys.each{|k|
if keys[k].kind_of?(Array)
cmd, *args = keys[k]
- keys[k] = Winico_callback.new(cmd, args.join(' '))
+ #keys[k] = Winico_callback.new(cmd, args.join(' '))
+ keys[k] = Winico_callback.new(cmd, *args)
# elsif keys[k].kind_of?(Proc)
elsif TkComm._callback_entry?(keys[k])
keys[k] = Winico_callback.new(keys[k])
@@ -170,7 +204,8 @@ class Tk::Winico
Winico_callback._config_keys.each{|k|
if keys[k].kind_of?(Array)
cmd, *args = keys[k]
- keys[k] = Winico_callback.new(cmd, args.join(' '))
+ #keys[k] = Winico_callback.new(cmd, args.join(' '))
+ keys[k] = Winico_callback.new(cmd, *args)
# elsif keys[k].kind_of?(Proc)
elsif TkComm._callback_entry?(keys[k])
keys[k] = Winico_callback.new(keys[k])
diff --git a/ext/tk/old-extconf.rb b/ext/tk/old-extconf.rb
new file mode 100644
index 0000000000..ebc83a0c0b
--- /dev/null
+++ b/ext/tk/old-extconf.rb
@@ -0,0 +1,440 @@
+# extconf.rb for tcltklib
+
+require 'mkmf'
+
+is_win32 = (/mswin|mingw|cygwin|bccwin/ =~ RUBY_PLATFORM)
+#is_macosx = (/darwin/ =~ RUBY_PLATFORM)
+
+have_func("ruby_native_thread_p", "ruby.h")
+have_func("rb_errinfo", "ruby.h")
+have_func("rb_safe_level", "ruby.h")
+have_struct_member("struct RArray", "ptr", "ruby.h")
+have_struct_member("struct RArray", "len", "ruby.h")
+
+def find_framework(tcl_hdr, tk_hdr)
+ if framework_dir = with_config("tcltk-framework")
+ paths = [framework_dir]
+ else
+ unless tcl_hdr || tk_hdr ||
+ enable_config("tcltk-framework", false) ||
+ enable_config("mac-tcltk-framework", false)
+ return false
+ end
+ paths = ["/Library/Frameworks", "/System/Library/Frameworks"]
+ end
+
+ checking_for('Tcl/Tk Framework') {
+ paths.find{|dir|
+ dir.strip!
+ dir.chomp!('/')
+ (tcl_hdr || FileTest.directory?(dir + "/Tcl.framework/") ) &&
+ (tk_hdr || FileTest.directory?(dir + "/Tk.framework/") )
+ }
+ }
+end
+
+tcl_framework_header = with_config("tcl-framework-header")
+tk_framework_header = with_config("tk-framework-header")
+
+tcltk_framework = find_framework(tcl_framework_header, tk_framework_header)
+
+unless is_win32
+ have_library("nsl", "t_open")
+ have_library("socket", "socket")
+ have_library("dl", "dlopen")
+ have_library("m", "log")
+end
+
+tk_idir, tk_ldir = dir_config("tk")
+tcl_idir, tcl_ldir = dir_config("tcl")
+x11_idir, x11_ldir = dir_config("X11")
+
+tk_ldir2 = with_config("tk-lib")
+tcl_ldir2 = with_config("tcl-lib")
+x11_ldir2 = with_config("X11-lib")
+
+tk_ldir_list = [tk_ldir2, tk_ldir]
+tcl_ldir_list = [tcl_ldir2, tcl_ldir]
+
+tklib = with_config("tklib")
+tcllib = with_config("tcllib")
+stubs = enable_config("tcltk_stubs") || with_config("tcltk_stubs")
+
+tcltk_version = with_config("tcltkversion")
+
+use_X = with_config("X11", (! is_win32))
+
+def parse_tclConfig(file)
+ # check tclConfig.sh/tkConfig.sh
+ tbl = {}
+ IO.foreach(file){|line|
+ line.strip!
+ next if line !~ /^([^\#=][^=]*)=(['"]|)(.*)\2$/
+ key, val = $1, $3
+ tbl[key] = val.gsub(/\$\{([^}]+)\}/){|s| tbl[$1]} rescue nil
+ }
+ tbl
+end
+
+def check_tcltk_version(version)
+ return [nil, nil] unless version
+
+ version = version.strip
+
+ tclver = version.dup
+ tkver = version.dup
+
+ major = dot = minor = dot = plvl = ext = nil
+
+ if version =~ /^(\d)(\.?)(\d)(\.?)(\d*)(.*)$/
+ major = $1; minor_dot = $2; minor = $3; plvl_dot = $4; plvl = $5; ext = $6
+ dot = ! minor_dot.empty?
+ if plvl_dot.empty? && ! plvl.empty?
+ minor << plvl
+ end
+ elsif version =~ /^(\d)(\.?)(\d?)(.*)$/
+ major = $1; minor_dot = $2; minor = $3; ext = $4
+ dot = ! minor_dot.empty?
+ else # unknown -> believe user
+ return [tclver, tkver]
+ end
+
+ # check Tcl7.6 / Tk4.2 ?
+ if major == "7" # Tcl7.6 ( not support Tclversion < 7.6 )
+ # Tk4.2
+ tkver = "4" + ((dot)? ".": "") + ((minor.empty)? "": "2") + ext
+ elsif major == "4" # Tk4.2 ( not support Tkversion < 4.2 )
+ # Tcl7.6
+ tclver = "7" + ((dot)? ".": "") + ((minor.empty)? "": "6") + ext
+ end
+
+ [tclver, tkver]
+end
+
+def find_tcl(tcllib, stubs, version, *opt_paths)
+ default_paths = ["/usr/local/lib", "/usr/pkg/lib", "/usr/lib"]
+ default_paths << "/Tcl/lib" # default for ActiveTcl
+
+ if (paths = opt_paths.compact).empty?
+ paths = default_paths
+ end
+
+ if stubs
+ func = "Tcl_InitStubs"
+ lib = "tclstub"
+ else
+ func = "Tcl_FindExecutable"
+ lib = "tcl"
+ end
+
+ if version && ! version.empty?
+ versions = [version]
+ else
+ versions = %w[8.7 8.6 8.5 8.4 8.3 8.2 8.1 8.0 7.6]
+ end
+
+ if tcllib
+ st = find_library(tcllib, func, *paths)
+ else
+ st = versions.find { |ver|
+ find_library("#{lib}#{ver}", func, *paths) or
+ find_library("#{lib}#{ver.delete('.')}", func, *paths) or
+ find_library("#{lib}#{ver}g", func, *paths) or
+ find_library("#{lib}#{ver.delete('.')}g", func, *paths) or
+ find_library("tcl#{ver}", func, *paths) or
+ find_library("tcl#{ver.delete('.')}", func, *paths) or
+ find_library("tcl#{ver}g", func, *paths) or
+ find_library("tcl#{ver.delete('.')}g", func, *paths)
+ } || (!version && find_library(lib, func, *paths))
+ end
+
+ unless st
+ puts("Warning:: cannot find Tcl library. tcltklib will not be compiled (tcltklib is disabled on your Ruby == Ruby/Tk will not work). Please check configure options.")
+ end
+ st
+end
+
+def find_tk(tklib, stubs, version, *opt_paths)
+ default_paths = ["/usr/local/lib", "/usr/pkg/lib", "/usr/lib"]
+ default_paths << "/Tcl/lib" # default for ActiveTcl
+
+ if (paths = opt_paths.compact).empty?
+ paths = default_paths
+ end
+
+ if stubs
+ func = "Tk_InitStubs"
+ lib = "tkstub"
+ else
+ func = "Tk_Init"
+ lib = "tk"
+ end
+
+ if version && ! version.empty?
+ versions = [version]
+ else
+ versions = %w[8.7 8.6 8.5 8.4 8.3 8.2 8.1 8.0 4.2]
+ end
+
+ if tklib
+ st = find_library(tklib, func, *paths)
+ else
+ st = versions.find { |ver|
+ find_library("#{lib}#{ver}", func, *paths) or
+ find_library("#{lib}#{ver.delete('.')}", func, *paths) or
+ find_library("#{lib}#{ver}g", func, *paths) or
+ find_library("#{lib}#{ver.delete('.')}g", func, *paths) or
+ find_library("tk#{ver}", func, *paths) or
+ find_library("tk#{ver.delete('.')}", func, *paths) or
+ find_library("tk#{ver}g", func, *paths) or
+ find_library("tk#{ver.delete('.')}g", func, *paths)
+ } || (!version && find_library(lib, func, *paths))
+ end
+
+ unless st
+ puts("Warning:: cannot find Tk library. tcltklib will not be compiled (tcltklib is disabled on your Ruby == Ruby/Tk will not work). Please check configure options.")
+ end
+ st
+end
+
+def find_tcltk_header(tclver, tkver)
+ base_dir = ['/usr/local/include', '/usr/pkg/include', '/usr/include']
+ base_dir << '/Tcl/include' # default for ActiveTcl
+
+ unless have_tcl_h = have_header('tcl.h')
+ if tclver && ! tclver.empty?
+ versions = [tclver]
+ else
+ versions = %w[8.7 8.6 8.5 8.4 8.3 8.2 8.1 8.0 7.6]
+ end
+ paths = base_dir.dup
+ versions.each{|ver| paths.concat(base_dir.map{|dir| dir + '/tcl' + ver})}
+ have_tcl_h = find_header('tcl.h', *paths)
+ end
+
+ unless have_tk_h = have_header("tk.h")
+ if tkver && ! tkver.empty?
+ versions = [tkver]
+ else
+ versions = %w[8.7 8.6 8.5 8.4 8.3 8.2 8.1 8.0 4.2]
+ end
+ paths = base_dir.dup
+ versions.each{|ver| paths.concat(base_dir.map{|dir| dir + '/tk' + ver})}
+ have_tk_h = find_header('tk.h', *paths)
+ end
+
+ have_tcl_h && have_tk_h
+end
+
+def find_X11(*opt_paths)
+ default_paths =
+ [ "/usr/X11/lib", "/usr/lib/X11", "/usr/X11R6/lib", "/usr/openwin/lib" ]
+ paths = opt_paths.compact.concat(default_paths)
+ st = find_library("X11", "XOpenDisplay", *paths)
+ unless st
+ puts("Warning:: cannot find X11 library. tcltklib will not be compiled (tcltklib is disabled on your Ruby == Ruby/Tk will not work). Please check configure options. If your Tcl/Tk don't require X11, please try --without-X11.")
+ end
+ st
+end
+
+def pthread_check()
+ tcl_major_ver = nil
+ tcl_minor_ver = nil
+
+ # Is tcl-thread given by user ?
+ case enable_config("tcl-thread")
+ when true
+ tcl_enable_thread = true
+ when false
+ tcl_enable_thread = false
+ else
+ tcl_enable_thread = nil
+ end
+
+ if (tclConfig = with_config("tclConfig-file"))
+ if tcl_enable_thread == true
+ puts("Warning: --with-tclConfig-file option is ignored, because --enable-tcl-thread option is given.")
+ elsif tcl_enable_thread == false
+ puts("Warning: --with-tclConfig-file option is ignored, because --disable-tcl-thread option is given.")
+ else
+ # tcl-thread is unknown and tclConfig.sh is given
+ begin
+ tbl = parse_tclConfig(tclConfig)
+ if tbl['TCL_THREADS']
+ tcl_enable_thread = (tbl['TCL_THREADS'] == "1")
+ else
+ tcl_major_ver = tbl['TCL_MAJOR_VERSION'].to_i
+ tcl_minor_ver = tbl['TCL_MINOR_VERSION'].to_i
+ if tcl_major_ver < 8 || (tcl_major_ver == 8 && tcl_minor_ver == 0)
+ tcl_enable_thread = false
+ end
+ end
+
+ if tcl_enable_thread == nil
+ # cannot find definition
+ if tcl_major_ver
+ puts("Warning: '#{tclConfig}' doesn't include TCL_THREADS definition.")
+ else
+ puts("Warning: '#{tclConfig}' may not be a tclConfig file.")
+ end
+ tclConfig = false
+ end
+ rescue Exception
+ puts("Warning: fail to read '#{tclConfig}'!! --> ignore the file")
+ tclConfig = false
+ end
+ end
+ end
+
+ if tcl_enable_thread == nil && !tclConfig
+ # tcl-thread is unknown and tclConfig is unavailable
+ begin
+ try_run_available = try_run("int main() { exit(0); }")
+ rescue Exception
+ # cannot try_run. Is CROSS-COMPILE environment?
+ puts(%Q'\
+*****************************************************************************
+**
+** PTHREAD SUPPORT CHECK WARNING:
+**
+** We cannot check the consistency of pthread support between Ruby
+** and the Tcl/Tk library in your environment (are you perhaps
+** cross-compiling?). If pthread support for these 2 packages is
+** inconsistent you may find you get errors when running Ruby/Tk
+** (e.g. hangs or segmentation faults). We strongly recommend
+** you to check the consistency manually.
+**
+*****************************************************************************
+')
+ return true
+ end
+ end
+
+ if tcl_enable_thread == nil
+ # tcl-thread is unknown
+ if try_run(<<EOF)
+#include <tcl.h>
+int main() {
+ Tcl_Interp *ip;
+ ip = Tcl_CreateInterp();
+ exit((Tcl_Eval(ip, "set tcl_platform(threaded)") == TCL_OK)? 0: 1);
+}
+EOF
+ tcl_enable_thread = true
+ elsif try_run(<<EOF)
+#include <tcl.h>
+static Tcl_ThreadDataKey dataKey;
+int main() { exit((Tcl_GetThreadData(&dataKey, 1) == dataKey)? 1: 0); }
+EOF
+ tcl_enable_thread = true
+ else
+ tcl_enable_thread = false
+ end
+ end
+
+ # check pthread mode
+ if (macro_defined?('HAVE_NATIVETHREAD', '#include "ruby.h"'))
+ # ruby -> enable
+ unless tcl_enable_thread
+ # ruby -> enable && tcl -> disable
+ puts(%Q'\
+*****************************************************************************
+**
+** PTHREAD SUPPORT MODE WARNING:
+**
+** Ruby is compiled with --enable-pthread, but your Tcl/Tk library
+** seems to be compiled without pthread support. Although you can
+** create the tcltklib library, this combination may cause errors
+** (e.g. hangs or segmentation faults). If you have no reason to
+** keep the current pthread support status, we recommend you reconfigure
+** and recompile the libraries so that both or neither support pthreads.
+**
+** If you want change the status of pthread support, please recompile
+** Ruby without "--enable-pthread" configure option or recompile Tcl/Tk
+** with "--enable-threads" configure option (if your Tcl/Tk is later
+** than or equal to Tcl/Tk 8.1).
+**
+*****************************************************************************
+')
+ end
+
+ # ruby -> enable && tcl -> enable/disable
+ if tcl_enable_thread
+ $CPPFLAGS += ' -DWITH_TCL_ENABLE_THREAD=1'
+ else
+ $CPPFLAGS += ' -DWITH_TCL_ENABLE_THREAD=0'
+ end
+
+ return true
+
+ else
+ # ruby -> disable
+ if tcl_enable_thread
+ # ruby -> disable && tcl -> enable
+ puts(%Q'\
+*****************************************************************************
+**
+** PTHREAD SUPPORT MODE ERROR:
+**
+** Ruby is not compiled with --enable-pthread, but your Tcl/Tk
+** library seems to be compiled with pthread support. This
+** combination may cause frequent hang or segmentation fault
+** errors when Ruby/Tk is working. We recommend that you NEVER
+** create the library with such a combination of pthread support.
+**
+** Please recompile Ruby with the "--enable-pthread" configure option
+** or recompile Tcl/Tk with the "--disable-threads" configure option.
+**
+*****************************************************************************
+')
+ $CPPFLAGS += ' -DWITH_TCL_ENABLE_THREAD=1'
+ return false
+ else
+ # ruby -> disable && tcl -> disable
+ $CPPFLAGS += ' -DWITH_TCL_ENABLE_THREAD=0'
+ return true
+ end
+ end
+end
+
+tclver, tkver = check_tcltk_version(tcltk_version)
+
+if ( tcltk_framework ||
+ ( find_tcltk_header(tclver, tkver) &&
+ ( !use_X || find_X11(x11_ldir2, x11_ldir) ) &&
+ find_tcl(tcllib, stubs, tclver, *tcl_ldir_list) &&
+ find_tk(tklib, stubs, tkver, *tk_ldir_list) ) )
+ $CPPFLAGS += ' -DUSE_TCL_STUBS -DUSE_TK_STUBS' if stubs
+ $CPPFLAGS += ' -D_WIN32' if /cygwin/ =~ RUBY_PLATFORM
+
+ if tcltk_framework
+ if tcl_framework_header
+ $CPPFLAGS += " -I#{tcl_framework_header}"
+ else
+ $CPPFLAGS += " -I#{tcltk_framework}/Tcl.framework/Headers"
+ end
+
+ if tk_framework_header
+ $CPPFLAGS += " -I#{tk_framework_header}"
+ else
+ $CPPFLAGS += " -I#{tcltk_framework}/Tk.framework/Headers"
+ end
+
+ $LDFLAGS += ' -framework Tk -framework Tcl'
+ end
+
+ if stubs or pthread_check
+ # create Makefile
+
+ # for SUPPORT_STATUS
+ $INSTALLFILES ||= []
+ $INSTALLFILES << ["lib/tkextlib/SUPPORT_STATUS", "$(RUBYLIBDIR)", "lib"]
+
+ have_func("rb_hash_lookup", "ruby.h")
+
+ # create
+ $defs << %[-DRUBY_VERSION=\\"#{RUBY_VERSION}\\"]
+ $defs << %[-DRUBY_RELEASE_DATE=\\"#{RUBY_RELEASE_DATE}\\"]
+ create_makefile("tcltklib")
+ end
+end
diff --git a/ext/tk/sample/binstr_usage.rb b/ext/tk/sample/binstr_usage.rb
index 91692856f9..be8399ba51 100644
--- a/ext/tk/sample/binstr_usage.rb
+++ b/ext/tk/sample/binstr_usage.rb
@@ -16,7 +16,7 @@ to avoid such troubles. Please see the source code of this sample. \
A Tk::BinaryString instance is used to create the image for the center button.
EOM
-ImgFile=['images','tcllogo.gif'].join(File::Separator)
+ImgFile=[File.dirname(__FILE__), 'images','tcllogo.gif'].join(File::Separator)
ph1 = TkPhotoImage.new(:file=>ImgFile)
p ph1.configinfo
@@ -28,12 +28,18 @@ ph2 = TkPhotoImage.new(:data=>b_str)
p ph2.configinfo
p ph2.data(:grayscale=>true)
-ph3 = TkPhotoImage.new()
-ph3.put(ph2.data(:grayscale=>true))
+ph3 = TkPhotoImage.new(:palette=>256)
+ph3.put(ph2.data)
+
+ph4 = TkPhotoImage.new()
+ph4.put(ph2.data(:grayscale=>true))
+
+#p [b_str.encoding, b_str.rb_encoding]
f = TkFrame.new.pack
TkButton.new(:parent=>f, :image=>ph1, :command=>proc{exit}).pack(:side=>:left)
TkButton.new(:parent=>f, :image=>ph2, :command=>proc{exit}).pack(:side=>:left)
TkButton.new(:parent=>f, :image=>ph3, :command=>proc{exit}).pack(:side=>:left)
+TkButton.new(:parent=>f, :image=>ph4, :command=>proc{exit}).pack(:side=>:left)
Tk.mainloop
diff --git a/ext/tk/sample/demos-en/anilabel.rb b/ext/tk/sample/demos-en/anilabel.rb
index f063bc53a4..0b9bc7357e 100644
--- a/ext/tk/sample/demos-en/anilabel.rb
+++ b/ext/tk/sample/demos-en/anilabel.rb
@@ -15,8 +15,10 @@ $anilabel_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($anilabel_demo).pack(:fill=>:both, :expand=>true)
+
# label
-msg = TkLabel.new($anilabel_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -25,7 +27,7 @@ msg = TkLabel.new($anilabel_demo) {
msg.pack('side'=>'top')
# frame
-TkFrame.new($anilabel_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -43,8 +45,8 @@ TkFrame.new($anilabel_demo) {|frame|
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# create frame for label demo
-f_left = TkLabelFrame.new($anilabel_demo, :text=>'Scrolling Texts')
-f_right = TkLabelFrame.new($anilabel_demo, :text=>'GIF Image')
+f_left = TkLabelFrame.new(base_frame, :text=>'Scrolling Texts')
+f_right = TkLabelFrame.new(base_frame, :text=>'GIF Image')
Tk.pack(f_left, f_right, 'side'=>'left', 'expand'=>'yes', 'fill'=>'both',
'padx'=>10, 'pady'=>10)
diff --git a/ext/tk/sample/demos-en/aniwave.rb b/ext/tk/sample/demos-en/aniwave.rb
index ebe27b875f..63a04a7b98 100644
--- a/ext/tk/sample/demos-en/aniwave.rb
+++ b/ext/tk/sample/demos-en/aniwave.rb
@@ -16,8 +16,10 @@ $aniwave_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($aniwave_demo).pack(:fill=>:both, :expand=>true)
+
# create label
-msg = TkLabel.new($aniwave_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -26,7 +28,7 @@ msg = TkLabel.new($aniwave_demo) {
msg.pack('side'=>'top')
# create frame
-TkFrame.new($aniwave_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -58,6 +60,7 @@ class AnimatedWaveDemo
@backupCoords = []
n = 0
(-10..300).step(5){|n| @waveCoords << [n, 100]; @backupCoords << [n, 100] }
+ n = 305
@waveCoords << [n, 0]; @backupCoords << [n, 0]
@waveCoords << [n+5, 200]; @backupCoords << [n+5, 200]
@coordsLen = @waveCoords.length
@@ -112,4 +115,4 @@ class AnimatedWaveDemo
end
# Start the animation processing
-AnimatedWaveDemo.new($aniwave_demo, :left).move
+AnimatedWaveDemo.new(base_frame, :left).move
diff --git a/ext/tk/sample/demos-en/arrow.rb b/ext/tk/sample/demos-en/arrow.rb
index b62e1966eb..055cd2af3c 100644
--- a/ext/tk/sample/demos-en/arrow.rb
+++ b/ext/tk/sample/demos-en/arrow.rb
@@ -77,11 +77,19 @@ def arrowSetup(c)
'arrow'=>'both', 'arrowshape'=>v.smallTips)
TkcText.new(c, v.x2-5*v.b, tmp+5, 'text'=>v.b, 'anchor'=>'n')
- TkcText.new(c, v.x1, 310, 'text'=>"'width'=>#{v.width}", 'anchor'=>'w',
- 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*')
- TkcText.new(c, v.x1, 330,
- 'text'=>"'arrowshape'=>[#{v.a}, #{v.b}, #{v.c}]", 'anchor'=>'w',
- 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*')
+ if $tk_version =~ /^4.*/
+ TkcText.new(c, v.x1, 310, 'text'=>"'width'=>#{v.width}", 'anchor'=>'w',
+ 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*')
+ TkcText.new(c, v.x1, 330,
+ 'text'=>"'arrowshape'=>[#{v.a}, #{v.b}, #{v.c}]",'anchor'=>'w',
+ 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*')
+ else
+ TkcText.new(c, v.x1, 310, 'text'=>"'width'=>#{v.width}", 'anchor'=>'w',
+ 'font'=>'Helvetica 18')
+ TkcText.new(c, v.x1, 330,
+ 'text'=>"'arrowshape'=>[#{v.a}, #{v.b}, #{v.c}]",
+ 'anchor'=>'w', 'font'=>'Helvetica 18')
+ end
v.count += 1
end
@@ -99,14 +107,16 @@ $arrow_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($arrow_demo).pack(:fill=>:both, :expand=>true)
+
# label
-TkLabel.new($arrow_demo, 'font'=>$font, 'wraplength'=>'5i', 'justify'=>'left',
+TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'5i', 'justify'=>'left',
'text'=>"This widget allows you to experiment with different widths and arrowhead shapes for lines in canvases. To change the line width or the shape of the arrowhead, drag any of the three boxes attached to the oversized arrow. The arrows on the right give examples at normal scale. The text at the bottom shows the configuration options as you'd enter them for a canvas line item."){
pack('side'=>'top')
}
# frame
-$arrow_buttons = TkFrame.new($arrow_demo) {|frame|
+$arrow_buttons = TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -124,7 +134,7 @@ $arrow_buttons = TkFrame.new($arrow_demo) {|frame|
$arrow_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# canvas
-$arrow_canvas = TkCanvas.new($arrow_demo, 'width'=>500, 'height'=>350,
+$arrow_canvas = TkCanvas.new(base_frame, 'width'=>500, 'height'=>350,
'relief'=>'sunken', 'borderwidth'=>2)
$arrow_canvas.pack('expand'=>'yes', 'fill'=>'both')
diff --git a/ext/tk/sample/demos-en/bind.rb b/ext/tk/sample/demos-en/bind.rb
index aabe7f0849..665592a2bc 100644
--- a/ext/tk/sample/demos-en/bind.rb
+++ b/ext/tk/sample/demos-en/bind.rb
@@ -19,8 +19,10 @@ $bind_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($bind_demo).pack(:fill=>:both, :expand=>true)
+
# frame
-TkFrame.new($bind_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -43,14 +45,14 @@ def tag_binding_for_bind_demo(tag, enter_style, leave_style)
end
# text
-TkText.new($bind_demo){|t|
+txt = TkText.new(base_frame){|t|
#
setgrid 'true'
- width 60
- height 24
+ #width 60
+ #height 24
font $font
wrap 'word'
- TkScrollbar.new($bind_demo) {|s|
+ TkScrollbar.new(base_frame) {|s|
pack('side'=>'right', 'fill'=>'y')
command proc{|*args| t.yview(*args)}
t.yscrollcommand proc{|first,last| s.set first,last}
@@ -94,35 +96,32 @@ TkText.new($bind_demo){|t|
}
d1.bind('1',
proc{
- eval(`cat #{[$demo_dir,'items.rb'].join(File::Separator)}`,
- _null_binding)
+ eval_samplecode(`cat #{[$demo_dir,'items.rb'].join(File::Separator)}`, 'items.rb')
})
d2.bind('1',
proc{
- eval(`cat #{[$demo_dir,'plot.rb'].join(File::Separator)}`,
- _null_binding)
+ eval_samplecode(`cat #{[$demo_dir,'plot.rb'].join(File::Separator)}`, 'plot.rb')
})
d3.bind('1',
proc{
- eval(`cat #{[$demo_dir,'ctext.rb'].join(File::Separator)}`,
- _null_binding)
+ eval_samplecode(`cat #{[$demo_dir,'ctext.rb'].join(File::Separator)}`, 'ctext.rb')
})
d4.bind('1',
proc{
- eval(`cat #{[$demo_dir,'arrow.rb'].join(File::Separator)}`,
- _null_binding)
+ eval_samplecode(`cat #{[$demo_dir,'arrow.rb'].join(File::Separator)}`, 'arrow.rb')
})
d5.bind('1',
proc{
- eval(`cat #{[$demo_dir,'ruler.rb'].join(File::Separator)}`,
- _null_binding)
+ eval_samplecode(`cat #{[$demo_dir,'ruler.rb'].join(File::Separator)}`, 'ruler.rb')
})
d6.bind('1',
proc{
- eval(`cat #{[$demo_dir,'cscroll.rb'].join(File::Separator)}`,
- _null_binding)
+ eval_samplecode(`cat #{[$demo_dir,'cscroll.rb'].join(File::Separator)}`, 'cscroll.rb')
})
TkTextMarkInsert.new(t, '0.0')
configure('state','disabled')
}
+
+txt.width 60
+txt.height 24
diff --git a/ext/tk/sample/demos-en/bitmap.rb b/ext/tk/sample/demos-en/bitmap.rb
index 7fd551c7a5..133adb0543 100644
--- a/ext/tk/sample/demos-en/bitmap.rb
+++ b/ext/tk/sample/demos-en/bitmap.rb
@@ -21,7 +21,7 @@ def bitmapRow(w,*args)
TkFrame.new(row){|base|
pack('side'=>'left', 'fill'=>'both', 'pady'=>'.25c', 'padx'=>'.25c')
TkLabel.new(base, 'text'=>bitmap, 'width'=>9).pack('side'=>'bottom')
- TkLabel.new(base, 'bitmap'=>bitmap).pack('side'=>'bottom')
+ Tk::Label.new(base, 'bitmap'=>bitmap).pack('side'=>'bottom')
}
end
}
@@ -40,14 +40,16 @@ $bitmap_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($bitmap_demo).pack(:fill=>:both, :expand=>true)
+
# label
-TkLabel.new($bitmap_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left',
+TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left',
'text'=>"This window displays all of Tk's built-in bitmaps, along with the names you can use for them in Tcl scripts."){
pack('side'=>'top')
}
# frame
-$bitmap_buttons = TkFrame.new($bitmap_demo) {|frame|
+$bitmap_buttons = TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -65,7 +67,7 @@ $bitmap_buttons = TkFrame.new($bitmap_demo) {|frame|
$bitmap_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# frame
-TkFrame.new($bitmap_demo){|f|
+TkFrame.new(base_frame){|f|
bitmapRow(f,'error','gray25','gray50','hourglass')
bitmapRow(f,'info','question','questhead','warning')
pack('side'=>'top', 'expand'=>'yes', 'fill'=>'both')
diff --git a/ext/tk/sample/demos-en/button.rb b/ext/tk/sample/demos-en/button.rb
index 6614d99c92..5c03bd499b 100644
--- a/ext/tk/sample/demos-en/button.rb
+++ b/ext/tk/sample/demos-en/button.rb
@@ -29,7 +29,7 @@ msg = TkLabel.new($button_demo) {
msg.pack('side'=>'top')
# frame
-$button_buttons = TkFrame.new($button_demo) {|frame|
+$button_buttons = Tk::Frame.new($button_demo) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
diff --git a/ext/tk/sample/demos-en/check.rb b/ext/tk/sample/demos-en/check.rb
index 971a8fea73..2951962a79 100644
--- a/ext/tk/sample/demos-en/check.rb
+++ b/ext/tk/sample/demos-en/check.rb
@@ -19,8 +19,10 @@ $check_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($check_demo).pack(:fill=>:both, :expand=>true)
+
# label
-msg = TkLabel.new($check_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -34,7 +36,7 @@ brakes = TkVariable.new(0)
sober = TkVariable.new(0)
# frame
-TkFrame.new($check_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -54,7 +56,7 @@ TkFrame.new($check_demo) {|frame|
TkButton.new(frame) {
text 'See Variables'
command proc{
- showVars($check_demo,
+ showVars(base_frame,
['wipers', wipers], ['brakes', brakes], ['sober', sober])
}
}.pack('side'=>'left', 'expand'=>'yes')
@@ -63,8 +65,8 @@ TkFrame.new($check_demo) {|frame|
# checkbutton
-[ TkCheckButton.new($check_demo, 'text'=>'Wipers OK', 'variable'=>wipers),
- TkCheckButton.new($check_demo, 'text'=>'Brakes OK', 'variable'=>brakes),
- TkCheckButton.new($check_demo, 'text'=>'Driver Sober', 'variable'=>sober)
+[ TkCheckButton.new(base_frame, 'text'=>'Wipers OK', 'variable'=>wipers),
+ TkCheckButton.new(base_frame, 'text'=>'Brakes OK', 'variable'=>brakes),
+ TkCheckButton.new(base_frame, 'text'=>'Driver Sober', 'variable'=>sober)
].each{|w| w.relief('flat'); w.pack('side'=>'top', 'pady'=>2, 'anchor'=>'w')}
diff --git a/ext/tk/sample/demos-en/check2.rb b/ext/tk/sample/demos-en/check2.rb
index 97d61fba0c..faea748a87 100644
--- a/ext/tk/sample/demos-en/check2.rb
+++ b/ext/tk/sample/demos-en/check2.rb
@@ -15,8 +15,10 @@ $check2_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($check2_demo).pack(:fill=>:both, :expand=>true)
+
# label
-msg = TkLabel.new($check2_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -31,7 +33,7 @@ brakes = TkVariable.new(0)
sober = TkVariable.new(0)
# frame
-TkFrame.new($check2_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkGrid(TkFrame.new(frame, :height=>2, :relief=>:sunken, :bd=>2),
:columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
TkGrid('x',
@@ -59,15 +61,15 @@ TkFrame.new($check2_demo) {|frame|
# checkbutton
-TkCheckButton.new($check2_demo, :text=>'Safety Check', :variable=>safety,
+TkCheckButton.new(base_frame, :text=>'Safety Check', :variable=>safety,
:relief=>:flat, :onvalue=>'all', :offvalue=>'none',
:tristatevalue=>'partial'){
pack('side'=>'top', 'pady'=>2, 'anchor'=>'w')
}
-[ TkCheckButton.new($check2_demo, 'text'=>'Wipers OK', 'variable'=>wipers),
- TkCheckButton.new($check2_demo, 'text'=>'Brakes OK', 'variable'=>brakes),
- TkCheckButton.new($check2_demo, 'text'=>'Driver Sober', 'variable'=>sober)
+[ TkCheckButton.new(base_frame, 'text'=>'Wipers OK', 'variable'=>wipers),
+ TkCheckButton.new(base_frame, 'text'=>'Brakes OK', 'variable'=>brakes),
+ TkCheckButton.new(base_frame, 'text'=>'Driver Sober', 'variable'=>sober)
].each{|w|
w.relief('flat')
w.pack('side'=>'top', 'padx'=>15, 'pady'=>2, 'anchor'=>'w')
diff --git a/ext/tk/sample/demos-en/clrpick.rb b/ext/tk/sample/demos-en/clrpick.rb
index 9486fde314..431439d55d 100644
--- a/ext/tk/sample/demos-en/clrpick.rb
+++ b/ext/tk/sample/demos-en/clrpick.rb
@@ -4,6 +4,8 @@
#
# widget demo prompts the user to select a color (called by 'widget')
#
+# Note: don't support ttk_wrapper. work with standard widgets only.
+#
# toplevel widget
if defined?($clrpick_demo) && $clrpick_demo
@@ -18,13 +20,18 @@ $clrpick_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($clrpick_demo).pack(:fill=>:both, :expand=>true)
+
# label
-TkLabel.new($clrpick_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left',
+#TkLabel.new($clrpick_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left',
+Tk::Label.new($clrpick_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left',
'text'=>"Press the buttons below to choose the foreground and background colors for the widgets in this window.").pack('side'=>'top')
# frame
-TkFrame.new($clrpick_demo) {|frame|
- TkButton.new(frame) {
+#TkFrame.new($clrpick_demo) {|frame|
+Tk::Frame.new($clrpick_demo) {|frame|
+ # TkButton.new(frame) {
+ Tk::Button.new(frame) {
text 'Dismiss'
command proc{
tmppath = $clrpick_demo
@@ -33,20 +40,23 @@ TkFrame.new($clrpick_demo) {|frame|
}
}.pack('side'=>'left', 'expand'=>'yes')
- TkButton.new(frame) {
+ # TkButton.new(frame) {
+ Tk::Button.new(frame) {
text 'Show Code'
command proc{showCode 'clrpick'}
}.pack('side'=>'left', 'expand'=>'yes')
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# button
-TkButton.new($clrpick_demo, 'text'=>'Set background color ...') {|b|
+# TkButton.new($clrpick_demo, 'text'=>'Set background color ...') {|b|
+Tk::Button.new($clrpick_demo, 'text'=>'Set background color ...') {|b|
command(proc{setColor $clrpick_demo, b, 'background',
['background', 'highlightbackground']})
pack('side'=>'top', 'anchor'=>'c', 'pady'=>'2m')
}
-TkButton.new($clrpick_demo, 'text'=>'Set foreground color ...') {|b|
+# TkButton.new($clrpick_demo, 'text'=>'Set foreground color ...') {|b|
+Tk::Button.new($clrpick_demo, 'text'=>'Set foreground color ...') {|b|
command(proc{setColor $clrpick_demo, b, 'foreground', ['foreground']})
pack('side'=>'top', 'anchor'=>'c', 'pady'=>'2m')
}
diff --git a/ext/tk/sample/demos-en/colors.rb b/ext/tk/sample/demos-en/colors.rb
index 66fb0afa36..4300a660ae 100644
--- a/ext/tk/sample/demos-en/colors.rb
+++ b/ext/tk/sample/demos-en/colors.rb
@@ -20,8 +20,10 @@ $colors_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($colors_demo).pack(:fill=>:both, :expand=>true)
+
# label
-msg = TkLabel.new($colors_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -30,7 +32,7 @@ msg = TkLabel.new($colors_demo) {
msg.pack('side'=>'top')
# frame
-TkFrame.new($colors_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -49,7 +51,7 @@ TkFrame.new($colors_demo) {|frame|
# frame
colors_lbox = nil
-TkFrame.new($colors_demo, 'borderwidth'=>10) {|w|
+TkFrame.new(base_frame, 'borderwidth'=>10) {|w|
s = TkScrollbar.new(w)
colors_lbox = TkListbox.new(w) {
setgrid 1
@@ -62,7 +64,15 @@ TkFrame.new($colors_demo, 'borderwidth'=>10) {|w|
colors_lbox.pack('side'=>'left', 'expand'=>1, 'fill'=>'both')
}.pack('side'=>'top', 'expand'=>'yes', 'fill'=>'y')
-colors_lbox.bind('Double-1', proc{TkPalette.setPalette TkSelection.get})
+#colors_lbox.bind('Double-1', proc{TkPalette.setPalette TkSelection.get})
+colors_lbox.bind('Double-1', proc{
+ begin
+ TkPalette.setPalette TkSelection.get
+ rescue => e
+ p e
+ Tk.tk_call_without_enc('destroy', '.___tk_set_palette')
+ end
+ })
ins_data = [
'gray60','gray70','gray80','gray85','gray90','gray95',
diff --git a/ext/tk/sample/demos-en/combo.rb b/ext/tk/sample/demos-en/combo.rb
new file mode 100644
index 0000000000..0907d9e8ec
--- /dev/null
+++ b/ext/tk/sample/demos-en/combo.rb
@@ -0,0 +1,96 @@
+# combo.rb --
+#
+# This demonstration script creates several combobox widgets.
+#
+# based on "Id: combo.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp"
+
+if defined?($combo_demo) && $combo_demo
+ $combo_demo.destroy
+ $combo_demo = nil
+end
+
+$combo_demo = TkToplevel.new {|w|
+ title("Combobox Demonstration")
+ iconname("combo")
+ positionWindow(w)
+}
+
+base_frame = TkFrame.new($combo_demo).pack(:fill=>:both, :expand=>true)
+
+Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'5i', :justify=>:left,
+ :text=><<EOL).pack(:side=>:top, :fill=>:x)
+Three different combo-boxes are displayed below. \
+You can add characters to the first \
+one by pointing, clicking and typing, just as with an entry; pressing \
+Return will cause the current value to be added to the list that is \
+selectable from the drop-down list, and you can choose other values \
+by pressing the Down key, using the arrow keys to pick another one, \
+and pressing Return again. The second combo-box is fixed to a \
+particular value, and cannot be modified at all. The third one only \
+allows you to select values from its drop-down list of Australian \
+cities.
+EOL
+
+## variables
+firstValue = TkVariable.new
+secondValue = TkVariable.new
+ozCity = TkVariable.new
+
+## See Code / Dismiss buttons
+Ttk::Frame.new(base_frame) {|frame|
+ sep = Ttk::Separator.new(frame)
+ Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
+ TkGrid('x',
+ Ttk::Button.new(frame, :text=>'See Variables',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{
+ showVars(base_frame,
+ ['firstVariable', firstValue],
+ ['secondVariable', secondValue],
+ ['ozCity', ozCity])
+ }),
+ Ttk::Button.new(frame, :text=>'See Code',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{showCode 'combo'}),
+ Ttk::Button.new(frame, :text=>'Dismiss',
+ :image=>$image['delete'], :compound=>:left,
+ :command=>proc{
+ $combo_demo.destroy
+ $combo_demo = nil
+ }),
+ :padx=>4, :pady=>4)
+ grid_columnconfigure(0, :weight=>1)
+ pack(:side=>:bottom, :fill=>:x)
+}
+
+frame = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true)
+
+australianCities = [
+ 'Canberra', 'Sydney', 'Melbourne', 'Perth', 'Adelaide', 'Brisbane',
+ 'Hobart', 'Darwin', 'Alice Springs'
+]
+
+
+secondValue.value = 'unchangable'
+ozCity.value = 'Sydney'
+
+Tk.pack(Ttk::Labelframe.new(frame, :text=>'Fully Editable'){|f|
+ Ttk::Combobox.new(f, :textvariable=>firstValue){|b|
+ b.bind('Return', '%W'){|w|
+ w.values <<= w.value unless w.values.include?(w.value)
+ }
+ }.pack(:pady=>5, :padx=>10)
+ },
+
+ Ttk::LabelFrame.new(frame, :text=>'Disabled'){|f|
+ Ttk::Combobox.new(f, :textvariable=>secondValue, :state=>:disabled) .
+ pack(:pady=>5, :padx=>10)
+ },
+
+ Ttk::LabelFrame.new(frame, :text=>'Defined List Only'){|f|
+ Ttk::Combobox.new(f, :textvariable=>ozCity, :state=>:readonly,
+ :values=>australianCities) .
+ pack(:pady=>5, :padx=>10)
+ },
+
+ :side=>:top, :pady=>5, :padx=>10)
diff --git a/ext/tk/sample/demos-en/cscroll.rb b/ext/tk/sample/demos-en/cscroll.rb
index 0838dfbe08..259ed3bd8c 100644
--- a/ext/tk/sample/demos-en/cscroll.rb
+++ b/ext/tk/sample/demos-en/cscroll.rb
@@ -19,14 +19,16 @@ $cscroll_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($cscroll_demo).pack(:fill=>:both, :expand=>true)
+
# label
-TkLabel.new($cscroll_demo, 'font'=>$font, 'wraplength'=>'4i',
+TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'4i',
'justify'=>'left', 'text'=>"This window displays a canvas widget that can be scrolled either using the scrollbars or by dragging with button 2 in the canvas. If you click button 1 on one of the rectangles, its indices will be printed on stdout."){
pack('side'=>'top')
}
# frame
-$cscroll_buttons = TkFrame.new($cscroll_demo) {|frame|
+$cscroll_buttons = TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -45,7 +47,7 @@ $cscroll_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# frame
unless $tk_version =~ /^4\.[01]/
- $cscroll_grid = TkFrame.new($cscroll_demo) {
+ $cscroll_grid = TkFrame.new(base_frame) {
pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>1)
}
TkGrid.rowconfigure($cscroll_grid, 0, 'weight'=>1, 'minsize'=>0)
@@ -53,7 +55,7 @@ unless $tk_version =~ /^4\.[01]/
end
# canvas
-$cscroll_canvas = TkCanvas.new($cscroll_demo,
+$cscroll_canvas = TkCanvas.new(base_frame,
'relief'=>'sunken', 'borderwidth'=>2,
'scrollregion'=>['-11c', '-11c', '50c', '20c']
) {|c|
@@ -64,7 +66,7 @@ $cscroll_canvas = TkCanvas.new($cscroll_demo,
'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news')
end
- TkScrollbar.new($cscroll_demo, 'command'=>proc{|*args| c.yview(*args)}) {|vs|
+ TkScrollbar.new(base_frame, 'command'=>proc{|*args| c.yview(*args)}) {|vs|
c.yscrollcommand(proc{|first,last| vs.set first,last})
if $tk_version =~ /^4\.[01]/
pack('side'=>'right', 'fill'=>'y')
@@ -74,7 +76,7 @@ $cscroll_canvas = TkCanvas.new($cscroll_demo,
end
}
- TkScrollbar.new($cscroll_demo, 'orient'=>'horiz',
+ TkScrollbar.new(base_frame, 'orient'=>'horiz',
'command'=>proc{|*args| c.xview(*args)}) {|hs|
c.xscrollcommand(proc{|first,last| hs.set first,last})
if $tk_version =~ /^4\.[01]/
diff --git a/ext/tk/sample/demos-en/ctext.rb b/ext/tk/sample/demos-en/ctext.rb
index dbb5e32638..01374b0321 100644
--- a/ext/tk/sample/demos-en/ctext.rb
+++ b/ext/tk/sample/demos-en/ctext.rb
@@ -19,8 +19,10 @@ $ctext_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($ctext_demo).pack(:fill=>:both, :expand=>true)
+
# label
-TkLabel.new($ctext_demo, 'font'=>$font, 'wraplength'=>'5i', 'justify'=>'left',
+TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'5i', 'justify'=>'left',
'text'=>"This window displays a string of text to demonstrate the text facilities of canvas widgets. You can click in the boxes to adjust the position of the text relative to its positioning point or change its justification. The text also supports the following simple bindings for editing:
1. You can point, click, and type.
2. You can also select with button 1.
@@ -33,7 +35,7 @@ TkLabel.new($ctext_demo, 'font'=>$font, 'wraplength'=>'5i', 'justify'=>'left',
}
# frame
-$ctext_buttons = TkFrame.new($ctext_demo) {|frame|
+$ctext_buttons = TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -51,24 +53,33 @@ $ctext_buttons = TkFrame.new($ctext_demo) {|frame|
$ctext_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# canvas
-$ctext_canvas = TkCanvas.new($ctext_demo, 'relief'=>'flat',
+$ctext_canvas = TkCanvas.new(base_frame, 'relief'=>'flat',
'borderwidth'=>0, 'width'=>500, 'height'=>350)
$ctext_canvas.pack('side'=>'top', 'expand'=>'yes', 'fill'=>'both')
# font
-textFont = '-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*'
+if $tk_version =~ /^4.*/
+ textFont = '-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*'
+else
+ textFont = 'Helvetica 24'
+end
# canvas
TkcRectangle.new($ctext_canvas, 245, 195, 255, 205,
'outline'=>'black', 'fill'=>'red')
+ctag_text_param = {
+ 'text'=>"This is just a string of text to demonstrate the text facilities of canvas widgets. Bindings have been been defined to support editing (see above).",
+ 'width'=>440, 'anchor'=>'n', 'justify'=>'left'
+}
+if $tk_version =~ /^4.*/
+ ctag_text_param['font'] = '-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*'
+else
+ ctag_text_param['font'] = 'Helvetica 24'
+end
+
$ctag_text = TkcTag.new($ctext_canvas)
-$ctag_text.withtag(TkcText.new($ctext_canvas, 250, 200,
- 'text'=>"This is just a string of text to demonstrate the text facilities of canvas widgets. Bindings have been been defined to support editing (see above).",
- 'width'=>440, 'anchor'=>'n',
- 'font'=>'-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*',
- 'kanjifont'=>'-*--24-*-jisx0208.1983-0',
- 'justify'=>'left') )
+$ctag_text.withtag(TkcText.new($ctext_canvas, 250, 200, ctag_text_param))
$ctag_text.bind('1', proc{|x,y| textB1Press $ctext_canvas,x,y}, "%x %y")
$ctag_text.bind('B1-Motion', proc{|x,y| textB1Move $ctext_canvas,x,y}, "%x %y")
@@ -110,9 +121,14 @@ mkTextConfig $ctext_canvas, x+60, y+60, 'anchor', 'nw', color
item = TkcRectangle.new($ctext_canvas, x+40, y+40, x+50, y+50,
'outline'=>'black', 'fill'=>'red')
item.bind('1', proc{$ctag_text.configure 'anchor', 'center'})
-TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Text Position', 'anchor'=>'s',
- 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*',
- 'fill'=>'brown')
+if $tk_version =~ /^4.*/
+ TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Text Position',
+ 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*',
+ 'anchor'=>'s', 'fill'=>'brown')
+else
+ TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Text Position',
+ 'font'=>'Times 24', 'anchor'=>'s', 'fill'=>'brown')
+end
# Lastly, create some items that allow the text's justification to be
# changed.
@@ -123,9 +139,14 @@ color = 'SeaGreen2'
mkTextConfig $ctext_canvas, x, y, 'justify', 'left', color
mkTextConfig $ctext_canvas, x+30, y, 'justify', 'center', color
mkTextConfig $ctext_canvas, x+60, y, 'justify', 'right', color
-TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Justification', 'anchor'=>'s',
- 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*',
- 'fill'=>'brown')
+if $tk_version =~ /^4.*/
+ TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Justification',
+ 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*',
+ 'anchor'=>'s', 'fill'=>'brown')
+else
+ TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Justification',
+ 'font'=>'Times 24', 'anchor'=>'s', 'fill'=>'brown')
+end
$ctext_canvas.itembind('config', 'Enter', proc{textEnter $ctext_canvas})
$ctext_canvas.itembind('config', 'Leave',
diff --git a/ext/tk/sample/demos-en/entry1.rb b/ext/tk/sample/demos-en/entry1.rb
index 29bc693395..6f5b10fb71 100644
--- a/ext/tk/sample/demos-en/entry1.rb
+++ b/ext/tk/sample/demos-en/entry1.rb
@@ -15,8 +15,10 @@ $entry1_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($entry1_demo).pack(:fill=>:both, :expand=>true)
+
# label
-msg = TkLabel.new($entry1_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '5i'
justify 'left'
@@ -25,7 +27,7 @@ msg = TkLabel.new($entry1_demo) {
msg.pack('side'=>'top')
# frame
-TkFrame.new($entry1_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -42,9 +44,9 @@ TkFrame.new($entry1_demo) {|frame|
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
#
-e1 = TkEntry.new($entry1_demo, 'relief'=>'sunken')
-e2 = TkEntry.new($entry1_demo, 'relief'=>'sunken')
-e3 = TkEntry.new($entry1_demo, 'relief'=>'sunken')
+e1 = TkEntry.new(base_frame, 'relief'=>'sunken')
+e2 = TkEntry.new(base_frame, 'relief'=>'sunken')
+e3 = TkEntry.new(base_frame, 'relief'=>'sunken')
[e1,e2,e3].each{|w| w.pack('side'=>'top', 'padx'=>10, 'pady'=>5, 'fill'=>'x')}
#
diff --git a/ext/tk/sample/demos-en/entry2.rb b/ext/tk/sample/demos-en/entry2.rb
index d4e58d7dd5..d67d04b56d 100644
--- a/ext/tk/sample/demos-en/entry2.rb
+++ b/ext/tk/sample/demos-en/entry2.rb
@@ -19,8 +19,10 @@ $entry2_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($entry2_demo).pack(:fill=>:both, :expand=>true)
+
# label
-msg = TkLabel.new($entry2_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '5i'
justify 'left'
@@ -29,7 +31,7 @@ msg = TkLabel.new($entry2_demo) {
msg.pack('side'=>'top')
# frame
-TkFrame.new($entry2_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -46,7 +48,7 @@ TkFrame.new($entry2_demo) {|frame|
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# frame
-TkFrame.new($entry2_demo, 'borderwidth'=>10) {|w|
+TkFrame.new(base_frame, 'borderwidth'=>10) {|w|
# entry 1
s1 = TkScrollbar.new(w, 'relief'=>'sunken', 'orient'=>'horiz')
e1 = TkEntry.new(w, 'relief'=>'sunken') {
diff --git a/ext/tk/sample/demos-en/entry3.rb b/ext/tk/sample/demos-en/entry3.rb
index 415b45f86c..f7df3a5653 100644
--- a/ext/tk/sample/demos-en/entry3.rb
+++ b/ext/tk/sample/demos-en/entry3.rb
@@ -17,7 +17,9 @@ $entry3_demo = TkToplevel.new {|w|
positionWindow(w)
}
-TkLabel.new($entry3_demo,
+base_frame = TkFrame.new($entry3_demo).pack(:fill=>:both, :expand=>true)
+
+TkLabel.new(base_frame,
:font=>$font, :wraplength=>'5i', :justify=>:left,
:text=><<EOL).pack(:side=>:top)
Four different entries are displayed below. You can add characters \
@@ -28,13 +30,13 @@ problem. The second only accepts strings with fewer than ten \
characters and sounds the bell when an attempt to go over the limit \
is made. The third accepts US phone numbers, mapping letters to \
their digit equivalent and sounding the bell on encountering an \
-illegal character or if trying to type over a character that is not \
+invalid character or if trying to type over a character that is not \
a digit. The fourth is a password field that accepts up to eight \
characters (silently ignoring further ones), and displaying them as \
asterisk characters.
EOL
-TkFrame.new($entry3_demo){|f|
+TkFrame.new(base_frame){|f|
pack(:side=>:bottom, :fill=>:x, :pady=>'2m')
TkButton.new(f, :text=>'Dismiss', :width=>15, :command=>proc{
@@ -60,23 +62,41 @@ TkFrame.new($entry3_demo){|f|
# count - Counter to control the number of times flashed
def focusAndFlash(widget, fg, bg, count=5)
return if count <= 0
- TkTimer.new(200, count,
- proc{widget.configure(:foreground=>bg, :background=>fg)},
- proc{widget.configure(:foreground=>fg, :background=>bg)}
- ).start
+ if fg && !fg.empty? && bg && !bg.empty?
+ TkTimer.new(200, count,
+ proc{widget.configure(:foreground=>bg, :background=>fg)},
+ proc{widget.configure(:foreground=>fg, :background=>bg)}
+ ).start
+ else
+ # TkTimer.new(150, 3){Tk.bell}.start
+ Tk.bell
+ TkTimer.new(200, count,
+ proc{widget.configure(:foreground=>'white',
+ :background=>'black')},
+ proc{widget.configure(:foreground=>'black',
+ :background=>'white')}
+ ).at_end{begin
+ widget.configure(:foreground=>fg,
+ :background=>bg)
+ rescue
+ # ignore
+ end}.start
+ end
widget.focus(true)
end
-l1 = TkLabelFrame.new($entry3_demo, :text=>"Integer Entry")
+l1 = TkLabelFrame.new(base_frame, :text=>"Integer Entry")
TkEntry.new(l1, :validate=>:focus,
:vcmd=>[
proc{|s| s == '' || /^[+-]?\d+$/ =~ s }, '%P'
]) {|e|
- invalidcommand [proc{|w| focusAndFlash(w, e.fg, e.bg)}, '%W']
+ fg = e.foreground
+ bg = e.background
+ invalidcommand [proc{|w| focusAndFlash(w, fg, bg)}, '%W']
pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m')
}
-l2 = TkLabelFrame.new($entry3_demo, :text=>"Length-Constrained Entry")
+l2 = TkLabelFrame.new(base_frame, :text=>"Length-Constrained Entry")
TkEntry.new(l2, :validate=>:key, :invcmd=>proc{Tk.bell},
:vcmd=>[proc{|s| s.length < 10}, '%P']
).pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m')
@@ -158,14 +178,14 @@ def validatePhoneChange(widget, vmode, idx, char)
widget.insert(idx, $phoneNumberMap[char] || char)
Tk.after_idle(proc{phoneSkipRight(widget, -1)})
return true
- # Tk.update(true) # Don't work 'update' inter validation callback.
- # It depends on Tcl/Tk side (tested on Tcl/Tk8.5a1).
+ # Tk.update(true) # <- Don't work 'update' inter validation callback.
+ # It depends on Tcl/Tk side (tested on Tcl/Tk8.5a1).
end
return false
end
-l3 = TkLabelFrame.new($entry3_demo, :text=>"US Phone-Number Entry")
+l3 = TkLabelFrame.new(base_frame, :text=>"US Phone-Number Entry")
TkEntry.new(l3, :validate=>:key, :invcmd=>proc{Tk.bell},
:textvariable=>entry3content,
:vcmd=>[
@@ -184,14 +204,14 @@ TkEntry.new(l3, :validate=>:key, :invcmd=>proc{Tk.bell},
pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m')
}
-l4 = TkLabelFrame.new($entry3_demo, :text=>"Password Entry")
+l4 = TkLabelFrame.new(base_frame, :text=>"Password Entry")
TkEntry.new(l4, :validate=>:key, :show=>'*',
:vcmd=>[
proc{|s| s.length <= 8},
'%P'
]).pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m')
-TkFrame.new($entry3_demo){|f|
+TkFrame.new(base_frame){|f|
lower
TkGrid.configure(l1, l2, :in=>f, :padx=>'3m', :pady=>'1m', :sticky=>:ew)
TkGrid.configure(l3, l4, :in=>f, :padx=>'3m', :pady=>'1m', :sticky=>:ew)
diff --git a/ext/tk/sample/demos-en/filebox.rb b/ext/tk/sample/demos-en/filebox.rb
index 36b19de557..676c347409 100644
--- a/ext/tk/sample/demos-en/filebox.rb
+++ b/ext/tk/sample/demos-en/filebox.rb
@@ -17,12 +17,14 @@ $filebox_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($filebox_demo).pack(:fill=>:both, :expand=>true)
+
# label
-TkLabel.new($filebox_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left',
+TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left',
'text'=>"Enter a file name in the entry box or click on the \"Browse\" buttons to select a file name using the file selection dialog.").pack('side'=>'top')
# frame
-TkFrame.new($filebox_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -40,7 +42,7 @@ TkFrame.new($filebox_demo) {|frame|
# frame
['open', 'save'].each{|type|
- TkFrame.new($filebox_demo) {|f|
+ TkFrame.new(base_frame) {|f|
TkLabel.new(f, 'text'=>"Select a file to #{type}: ", 'anchor'=>'e')\
.pack('side'=>'left')
@@ -48,7 +50,7 @@ TkFrame.new($filebox_demo) {|frame|
pack('side'=>'left', 'expand'=>'yes', 'fill'=>'x')
TkButton.new(f, 'text'=>'Browse ...',
- 'command'=>proc{fileDialog $filebox_demo,e,type})\
+ 'command'=>proc{fileDialog base_frame,e,type})\
.pack('side'=>'left')
}
@@ -58,7 +60,7 @@ TkFrame.new($filebox_demo) {|frame|
$tk_strictMotif = TkVarAccess.new('tk_strictMotif')
if ($tk_platform['platform'] == 'unix')
- TkCheckButton.new($filebox_demo,
+ TkCheckButton.new(base_frame,
'text'=>'Use Motif Style Dialog',
'variable'=>$tk_strictMotif,
'onvalue'=>1, 'offvalue'=>0 ).pack('anchor'=>'c')
@@ -91,7 +93,10 @@ def fileDialog(w,ent,operation)
if file != ""
ent.delete 0, 'end'
ent.insert 0, file
- ent.xview 'end'
+ # ent.xview 'end'
+ Tk.update_idletasks # need this for Tk::Tile::Entry
+ # (to find right position of 'xview').
+ ent.xview(ent.index('end'))
end
end
diff --git a/ext/tk/sample/demos-en/floor.rb b/ext/tk/sample/demos-en/floor.rb
index 53adcf96b6..7023f2a72e 100644
--- a/ext/tk/sample/demos-en/floor.rb
+++ b/ext/tk/sample/demos-en/floor.rb
@@ -1590,14 +1590,16 @@ $floor_demo = TkToplevel.new {|w|
minsize(100,100)
}
+base_frame = TkFrame.new($floor_demo).pack(:fill=>:both, :expand=>true)
+
# label
-TkLabel.new($floor_demo, 'font'=>$font, 'wraplength'=>'8i', 'justify'=>'left',
+TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'8i', 'justify'=>'left',
'text'=>"This window contains a canvas widget showing the floorplan of Digital Equipment Corporation's Western Research Laboratory. It has three levels. At any given time one of the levels is active, meaning that you can see its room structure. To activate a level, click the left mouse button anywhere on it. As the mouse moves over the active level, the room under the mouse lights up and its room number appears in the \"Room:\" entry. You can also type a room number in the entry and the room will light up."){
pack('side'=>'top')
}
# frame
-$floor_buttons = TkFrame.new($floor_demo) {|frame|
+$floor_buttons = TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -1620,17 +1622,17 @@ $floorItems = {}
# canvas
if $tk_version =~ /^4\.[01]/
- $floor_canvas_frame = TkFrame.new($floor_demo,'bd'=>2,'relief'=>'sunken',
+ $floor_canvas_frame = TkFrame.new(base_frame,'bd'=>2,'relief'=>'sunken',
'highlightthickness'=>2)
$floor_canvas = TkCanvas.new($floor_canvas_frame,
'width'=>900, 'height'=>500, 'borderwidth'=>0,
'highlightthickness'=>0) {|c|
- TkScrollbar.new($floor_demo, 'orient'=>'horiz',
+ TkScrollbar.new(base_frame, 'orient'=>'horiz',
'command'=>proc{|*args| c.xview(*args)}){|hs|
c.xscrollcommand(proc{|first,last| hs.set first,last})
pack('side'=>'bottom', 'fill'=>'x')
}
- TkScrollbar.new($floor_demo, 'command'=>proc{|*args| c.yview(*args)}){|vs|
+ TkScrollbar.new(base_frame, 'command'=>proc{|*args| c.yview(*args)}){|vs|
c.yscrollcommand(proc{|first,last| vs.set first,last})
pack('side'=>'right', 'fill'=>'y')
}
@@ -1639,7 +1641,7 @@ if $tk_version =~ /^4\.[01]/
$floor_canvas.pack('expand'=>'yes', 'fill'=>'both')
else
- TkFrame.new($floor_demo) {|f|
+ TkFrame.new(base_frame) {|f|
pack('side'=>'top', 'fill'=>'both', 'expand'=>'yes')
h = TkScrollbar.new(f, 'highlightthickness'=>0, 'orient'=>'horizontal')
diff --git a/ext/tk/sample/demos-en/floor2.rb b/ext/tk/sample/demos-en/floor2.rb
index efaf9e250d..88b07aeee4 100644
--- a/ext/tk/sample/demos-en/floor2.rb
+++ b/ext/tk/sample/demos-en/floor2.rb
@@ -1590,14 +1590,16 @@ $floor2_demo = TkToplevel.new {|w|
minsize(100,100)
}
+base_frame = TkFrame.new($floor2_demo).pack(:fill=>:both, :expand=>true)
+
# label
-TkLabel.new($floor2_demo, 'font'=>$font, 'wraplength'=>'8i', 'justify'=>'left',
+TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'8i', 'justify'=>'left',
'text'=>"This window contains a canvas widget showing the floorplan of Digital Equipment Corporation's Western Research Laboratory. It has three levels. At any given time one of the levels is active, meaning that you can see its room structure. To activate a level, click the left mouse button anywhere on it. As the mouse moves over the active level, the room under the mouse lights up and its room number appears in the \"Room:\" entry. You can also type a room number in the entry and the room will light up."){
pack('side'=>'top')
}
# frame
-$floor2_buttons = TkFrame.new($floor2_demo) {|frame|
+$floor2_buttons = TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -1620,17 +1622,17 @@ $floorItems2 = {}
# canvas
if $tk_version =~ /^4\.[01]/
- $floor2_canvas_frame = TkFrame.new($floor2_demo,'bd'=>2,'relief'=>'sunken',
+ $floor2_canvas_frame = TkFrame.new(base_frame,'bd'=>2,'relief'=>'sunken',
'highlightthickness'=>2)
$floor2_canvas = TkCanvas.new($floor2_canvas_frame,
'width'=>900, 'height'=>500, 'borderwidth'=>0,
'highlightthickness'=>0) {|c|
- TkScrollbar.new($floor2_demo, 'orient'=>'horiz',
+ TkScrollbar.new(base_frame, 'orient'=>'horiz',
'command'=>proc{|*args| c.xview(*args)}){|hs|
c.xscrollcommand(proc{|first,last| hs.set first,last})
pack('side'=>'bottom', 'fill'=>'x')
}
- TkScrollbar.new($floor2_demo, 'command'=>proc{|*args| c.yview(*args)}){|vs|
+ TkScrollbar.new(base_frame, 'command'=>proc{|*args| c.yview(*args)}){|vs|
c.yscrollcommand(proc{|first,last| vs.set first,last})
pack('side'=>'right', 'fill'=>'y')
}
@@ -1639,7 +1641,7 @@ if $tk_version =~ /^4\.[01]/
$floor2_canvas.pack('expand'=>'yes', 'fill'=>'both')
else
- TkFrame.new($floor2_demo) {|f|
+ TkFrame.new(base_frame) {|f|
pack('side'=>'top', 'fill'=>'both', 'expand'=>'yes')
h = TkScrollbar.new(f, 'highlightthickness'=>0, 'orient'=>'horizontal')
diff --git a/ext/tk/sample/demos-en/form.rb b/ext/tk/sample/demos-en/form.rb
index dbb14302dc..3119752b1c 100644
--- a/ext/tk/sample/demos-en/form.rb
+++ b/ext/tk/sample/demos-en/form.rb
@@ -15,8 +15,10 @@ $form_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($form_demo).pack(:fill=>:both, :expand=>true)
+
# label
-msg = TkLabel.new($form_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -25,7 +27,7 @@ msg = TkLabel.new($form_demo) {
msg.pack('side'=>'top', 'fill'=>'x')
# frame
-TkFrame.new($form_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -44,7 +46,7 @@ TkFrame.new($form_demo) {|frame|
# entry
form_data = []
(1..5).each{|i|
- f = TkFrame.new($form_demo, 'bd'=>2)
+ f = TkFrame.new(base_frame, 'bd'=>2)
e = TkEntry.new(f, 'relief'=>'sunken', 'width'=>40)
l = TkLabel.new(f)
e.pack('side'=>'right')
diff --git a/ext/tk/sample/demos-en/goldberg.rb b/ext/tk/sample/demos-en/goldberg.rb
index 8d3f6d14f7..c6fa37c09c 100644
--- a/ext/tk/sample/demos-en/goldberg.rb
+++ b/ext/tk/sample/demos-en/goldberg.rb
@@ -54,6 +54,8 @@ $goldberg_demo = TkToplevel.new {|w|
# positionWindow(w)
}
+base_frame = TkFrame.new($goldberg_demo).pack(:fill=>:both, :expand=>true)
+
=begin
# label
msg = TkLabel.new($goldberg_demo) {
@@ -175,7 +177,8 @@ class TkGoldberg_Demo
do_ctrl_frame
do_detail_frame
- msg = TkLabel.new(@parent, :bg=>@C['bg'], :fg=>'white') {
+ # msg = TkLabel.new(@parent, :bg=>@C['bg'], :fg=>'white') {
+ msg = Tk::Label.new(@parent, :bg=>@C['bg'], :fg=>'white') {
font 'Arial 10'
wraplength 600
justify 'left'
@@ -185,7 +188,8 @@ class TkGoldberg_Demo
frame = TkFrame.new(@parent, :bg=>@C['bg'])
- TkButton.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) {
+ # TkButton.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) {
+ Tk::Button.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) {
text 'Dismiss'
command proc{
tmppath = $goldberg_demo
@@ -194,12 +198,14 @@ class TkGoldberg_Demo
}
}.pack('side'=>'left')
- TkButton.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) {
+ # TkButton.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) {
+ Tk::Button.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) {
text 'See Code'
command proc{showCode 'goldberg'}
}.pack('side'=>'left', 'padx'=>5)
- @show = TkButton.new(frame, :text=>'>>', :command=>proc{show_ctrl},
+ # @show = TkButton.new(frame, :text=>'>>', :command=>proc{show_ctrl},
+ @show = Tk::Button.new(frame, :text=>'>>', :command=>proc{show_ctrl},
:bg=>@C['bg'], :activebackground=>@C['bg'])
@show.pack('side'=>'left')
frame.place(:in=>@canvas, :relx=>1, :rely=>0, :anchor=>:ne)
@@ -208,10 +214,11 @@ class TkGoldberg_Demo
end
def do_ctrl_frame
- @start = TkButton.new(@parent, :text=>'Start', :bd=>6,
+ @start = Tk::Button.new(@parent, :text=>'Start', :bd=>6,
:command=>proc{do_button(0)})
- @start.font(@start['font'].weight('bold'))
- font = @start['font']
+ if font = @start['font']
+ @start.font(font.weight('bold'))
+ end
@pause = TkCheckbutton.new(@parent, :text=>'Pause', :font=>font,
:command=>proc{do_button(1)}, :relief=>:raised,
@@ -1996,4 +2003,4 @@ class TkGoldberg_Demo
end
end
-TkGoldberg_Demo.new($goldberg_demo)
+TkGoldberg_Demo.new(base_frame)
diff --git a/ext/tk/sample/demos-en/hello b/ext/tk/sample/demos-en/hello
index f06eabe518..5e86ad7e3e 100644
--- a/ext/tk/sample/demos-en/hello
+++ b/ext/tk/sample/demos-en/hello
@@ -1,9 +1,9 @@
#!/usr/bin/env ruby
require 'tk'
-unless /^8\.[1-9]/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK
- require 'tkencoding'
-end
+#unless /^8\.[1-9]/ =~ Tk::TCL_VERSION && !Tk::JAPANIZED_TK
+# require 'tkencoding'
+#end
TkButton.new(nil,
'text'=>"Hello Ruby world!",
diff --git a/ext/tk/sample/demos-en/hscale.rb b/ext/tk/sample/demos-en/hscale.rb
index 14e395b61a..e660216967 100644
--- a/ext/tk/sample/demos-en/hscale.rb
+++ b/ext/tk/sample/demos-en/hscale.rb
@@ -11,8 +11,9 @@ $hscale_demo = TkToplevel.new {|w|
}
positionWindow($hscale_demo)
+base_frame = TkFrame.new($hscale_demo).pack(:fill=>:both, :expand=>true)
-msg = TkLabel.new($hscale_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '3.5i'
justify 'left'
@@ -20,7 +21,7 @@ msg = TkLabel.new($hscale_demo) {
}
msg.pack('side'=>'top')
-TkFrame.new($hscale_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc {
@@ -36,7 +37,18 @@ TkFrame.new($hscale_demo) {|frame|
}.pack('side'=>'left', 'expand'=>'yes')
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
-TkFrame.new($hscale_demo) {|frame|
+
+def setWidth(w, width)
+ width = width + 21
+ x2 = width - 30
+ if x2 < 21
+ x2 = 21
+ end
+ w.coords 'poly',20,15,20,35,x2,35,x2,45,width,25,x2,5,x2,15,20,15
+ w.coords 'line',20,15,20,35,x2,35,x2,45,width,25,x2,5,x2,15,20,15
+end
+
+TkFrame.new(base_frame) {|frame|
canvas = TkCanvas.new(frame) {|c|
width 50
height 50
@@ -61,14 +73,3 @@ TkFrame.new($hscale_demo) {|frame|
}.pack('side'=>'bottom', 'expand'=>'yes', 'anchor'=>'n')
scale.set 75
}.pack('side'=>'top', 'fill'=>'x')
-
-
-def setWidth(w, width)
- width = width + 21
- x2 = width - 30
- if x2 < 21
- x2 = 21
- end
- w.coords 'poly',20,15,20,35,x2,35,x2,45,width,25,x2,5,x2,15,20,15
- w.coords 'line',20,15,20,35,x2,35,x2,45,width,25,x2,5,x2,15,20,15
-end
diff --git a/ext/tk/sample/demos-en/icon.rb b/ext/tk/sample/demos-en/icon.rb
index 58aca2df07..a3921d2333 100644
--- a/ext/tk/sample/demos-en/icon.rb
+++ b/ext/tk/sample/demos-en/icon.rb
@@ -19,8 +19,10 @@ $icon_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($icon_demo).pack(:fill=>:both, :expand=>true)
+
# label
-msg = TkLabel.new($icon_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '5i'
justify 'left'
@@ -29,7 +31,7 @@ msg = TkLabel.new($icon_demo) {
msg.pack('side'=>'top')
# frame
-TkFrame.new($icon_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -63,16 +65,18 @@ TkBitmapImage.new('file'=>[$demo_dir,'..',
letters = TkVariable.new
# frame
-TkFrame.new($icon_demo, 'borderwidth'=>10){|w|
+TkFrame.new(base_frame, 'borderwidth'=>10){|w|
TkFrame.new(w) {|f|
- TkRadioButton.new(f){
+ # TkRadioButton.new(f){
+ Tk::RadioButton.new(f){
bitmap '@' + [$demo_dir,'..',
'images','letters.xbm'].join(File::Separator)
variable letters
value 'full'
}.pack('side'=>'top', 'expand'=>'yes')
- TkRadioButton.new(f){
+ # TkRadioButton.new(f){
+ Tk::RadioButton.new(f){
bitmap '@' + [$demo_dir,'..',
'images','noletter.xbm'].join(File::Separator)
variable letters
@@ -81,14 +85,16 @@ TkFrame.new($icon_demo, 'borderwidth'=>10){|w|
}.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'5m')
- TkCheckButton.new(w) {
+ # TkCheckButton.new(w) {
+ Tk::CheckButton.new(w) {
image flagdown
selectimage flagup
indicatoron 0
selectcolor self['background']
}.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'5m')
- TkCheckButton.new(w) {
+ # TkCheckButton.new(w) {
+ Tk::CheckButton.new(w) {
bitmap '@' + [$demo_dir,'..',
'images','letters.xbm'].join(File::Separator)
indicatoron 0
diff --git a/ext/tk/sample/demos-en/image1.rb b/ext/tk/sample/demos-en/image1.rb
index 05c9705c9c..a9072bb308 100644
--- a/ext/tk/sample/demos-en/image1.rb
+++ b/ext/tk/sample/demos-en/image1.rb
@@ -18,8 +18,10 @@ $image1_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($image1_demo).pack(:fill=>:both, :expand=>true)
+
# label
-msg = TkLabel.new($image1_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -28,7 +30,7 @@ msg = TkLabel.new($image1_demo) {
msg.pack('side'=>'top')
# frame
-TkFrame.new($image1_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -54,7 +56,10 @@ TkPhotoImage.new('file'=>[$demo_dir,'..',
'images','earthris.gif'].join(File::Separator))
# label
-[ TkLabel.new($image1_demo, 'image'=>image1a, 'bd'=>1, 'relief'=>'sunken'),
- TkLabel.new($image1_demo, 'image'=>image1b, 'bd'=>1, 'relief'=>'sunken')
+#[ TkLabel.new(base_frame, 'image'=>image1a, 'bd'=>1, 'relief'=>'sunken'),
+# TkLabel.new(base_frame, 'image'=>image1b, 'bd'=>1, 'relief'=>'sunken')
+#].each{|w| w.pack('side'=>'top', 'padx'=>'.5m', 'pady'=>'.5m')}
+[ Tk::Label.new(base_frame, 'image'=>image1a, 'bd'=>1, 'relief'=>'sunken'),
+ Tk::Label.new(base_frame, 'image'=>image1b, 'bd'=>1, 'relief'=>'sunken')
].each{|w| w.pack('side'=>'top', 'padx'=>'.5m', 'pady'=>'.5m')}
diff --git a/ext/tk/sample/demos-en/image2.rb b/ext/tk/sample/demos-en/image2.rb
index 1aff7173be..1975dd6b02 100644
--- a/ext/tk/sample/demos-en/image2.rb
+++ b/ext/tk/sample/demos-en/image2.rb
@@ -19,8 +19,10 @@ $image2_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($image2_demo).pack(:fill=>:both, :expand=>true)
+
# label
-msg = TkLabel.new($image2_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -29,7 +31,7 @@ msg = TkLabel.new($image2_demo) {
msg.pack('side'=>'top')
# frame
-TkFrame.new($image2_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -53,21 +55,21 @@ $dirName = TkVariable.new([$demo_dir,'..','images'].join(File::Separator))
$image2a = TkPhotoImage.new
#
-TkLabel.new($image2_demo, 'text'=>'Directory:')\
+TkLabel.new(base_frame, 'text'=>'Directory:')\
.pack('side'=>'top', 'anchor'=>'w')
-image2_e = TkEntry.new($image2_demo) {
+image2_e = TkEntry.new(base_frame) {
width 30
textvariable $dirName
}.pack('side'=>'top', 'anchor'=>'w')
-TkFrame.new($image2_demo, 'height'=>'3m', 'width'=>20)\
+TkFrame.new(base_frame, 'height'=>'3m', 'width'=>20)\
.pack('side'=>'top', 'anchor'=>'w')
-TkLabel.new($image2_demo, 'text'=>'File:')\
+TkLabel.new(base_frame, 'text'=>'File:')\
.pack('side'=>'top', 'anchor'=>'w')
-TkFrame.new($image2_demo){|w|
+TkFrame.new(base_frame){|w|
s = TkScrollbar.new(w)
l = TkListbox.new(w) {
width 20
@@ -86,9 +88,9 @@ TkFrame.new($image2_demo){|w|
}.pack('side'=>'top', 'anchor'=>'w')
# image
-[ TkFrame.new($image2_demo, 'height'=>'3m', 'width'=>20),
- TkLabel.new($image2_demo, 'text'=>'Image:'),
- TkLabel.new($image2_demo, 'image'=>$image2a)
+[ TkFrame.new(base_frame, 'height'=>'3m', 'width'=>20),
+ TkLabel.new(base_frame, 'text'=>'Image:'),
+ TkLabel.new(base_frame, 'image'=>$image2a)
].each{|w| w.pack('side'=>'top', 'anchor'=>'w')}
#
diff --git a/ext/tk/sample/demos-en/image3.rb b/ext/tk/sample/demos-en/image3.rb
index e46d3796f2..43afab7ecd 100644
--- a/ext/tk/sample/demos-en/image3.rb
+++ b/ext/tk/sample/demos-en/image3.rb
@@ -19,27 +19,29 @@ $image3_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($image3_demo).pack(:fill=>:both, :expand=>true)
+
#
-def loadDir(w)
+def loadDir3(w)
w.delete(0,'end')
Dir.glob([$dirName,'*'].join(File::Separator)).sort.each{|f|
w.insert('end',File.basename(f))
}
end
-# selectAndLoadDir --
+# selectAndLoadDir3 --
# This procedure pops up a dialog to ask for a directory to load into
# the listobx and (if the user presses OK) reloads the directory
# listbox from the directory named in the demo's entry.
#
# Arguments:
# w - Name of the toplevel window of the demo.
-def selectAndLoadDir(w, lbox)
+def selectAndLoadDir3(w, lbox)
dir = Tk.chooseDirectory(:initialdir=>$dirName.value,
:parent=>w, :mustexist=>true)
if dir.length > 0
$dirName.value = dir
- loadDir(lbox)
+ loadDir3(lbox)
end
end
@@ -49,7 +51,7 @@ end
# label
-msg = TkLabel.new($image3_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -58,7 +60,7 @@ msg = TkLabel.new($image3_demo) {
msg.pack('side'=>'top')
# frame
-TkFrame.new($image3_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -86,11 +88,11 @@ end
$image3a = TkPhotoImage.new
#
-image3_f = TkFrame.new($image3_demo).pack(:fill=>:both, :expand=>true)
+image3_f = TkFrame.new(base_frame).pack(:fill=>:both, :expand=>true)
-image3_df = TkLabelFrame.new($image3_demo, :text=>'Directory:')
+image3_df = TkLabelFrame.new(base_frame, :text=>'Directory:')
-image3_ff = TkLabelFrame.new($image3_demo, :text=>'File:',
+image3_ff = TkLabelFrame.new(base_frame, :text=>'File:',
:padx=>'2m', :pady=>'2m')
image3_lbx = TkListbox.new(image3_ff, :width=>20, :height=>10) {
pack(:side=>:left, :fill=>:y, :expand=>true)
@@ -102,16 +104,17 @@ image3_lbx = TkListbox.new(image3_ff, :width=>20, :height=>10) {
image3_ent = TkEntry.new(image3_df, :width=>30, :textvariable=>$dirName){
pack(:side=>:left, :fill=>:both, :padx=>'2m', :pady=>'2m', :expand=>true)
- bind('Return', proc{loadDir(image3_lbx)})
+ bind('Return', proc{loadDir3(image3_lbx)})
}
TkButton.new(image3_df, :pady=>0, :padx=>'2m', :text=>"Select Dir.",
- :command=>proc{selectAndLoadDir(image3_ent, image3_lbx)}) {
+ :command=>proc{selectAndLoadDir3(image3_ent, image3_lbx)}) {
pack(:side=>:left, :fill=>:y, :padx=>[0, '2m'], :pady=>'2m')
}
-image3_if = TkLabelFrame.new($image3_demo, :text=>'Image:') {|f|
- TkLabel.new(f, :image=>$image3a).pack(:padx=>'2m', :pady=>'2m')
+image3_if = TkLabelFrame.new(base_frame, :text=>'Image:') {|f|
+ # TkLabel.new(f, :image=>$image3a).pack(:padx=>'2m', :pady=>'2m')
+ Tk::Label.new(f, :image=>$image3a).pack(:padx=>'2m', :pady=>'2m')
}
Tk.grid(image3_df, '-',
diff --git a/ext/tk/sample/demos-en/items.rb b/ext/tk/sample/demos-en/items.rb
index 8ab7668a07..3fd44fd4f4 100644
--- a/ext/tk/sample/demos-en/items.rb
+++ b/ext/tk/sample/demos-en/items.rb
@@ -19,8 +19,10 @@ $items_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($items_demo).pack(:fill=>:both, :expand=>true)
+
# label
-TkLabel.new($items_demo) {
+TkLabel.new(base_frame) {
font $font
wraplength '5i'
justify 'left'
@@ -28,7 +30,7 @@ TkLabel.new($items_demo) {
}.pack('side'=>'top')
# frame
-TkFrame.new($items_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -46,7 +48,7 @@ TkFrame.new($items_demo) {|frame|
# frame
cvs = nil
-TkFrame.new($items_demo) {|cf|
+TkFrame.new(base_frame) {|cf|
# canvas
cvs = TkCanvas.new(cf) {|c|
focus
@@ -94,8 +96,13 @@ TkcLine.new(cvs, '0c', '16c', '30c', '16c', 'width'=>2)
TkcLine.new(cvs, '10c', '0c', '10c', '24c', 'width'=>2)
TkcLine.new(cvs, '20c', '0c', '20c', '24c', 'width'=>2)
-font1 = '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*'
-font2 = '-Adobe-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*'
+if $tk_version =~ /^4.*/
+ font1 = '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*'
+ font2 = '-Adobe-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*'
+else
+ font1 = 'Helvetica 12'
+ font2 = 'Helvetica 24 bold'
+end
if TkWinfo.depth($root).to_i > 1
blue = 'DeepSkyBlue3'
red = 'red'
diff --git a/ext/tk/sample/demos-en/knightstour.rb b/ext/tk/sample/demos-en/knightstour.rb
new file mode 100644
index 0000000000..618fce5f02
--- /dev/null
+++ b/ext/tk/sample/demos-en/knightstour.rb
@@ -0,0 +1,271 @@
+# Based on the widget demo of Tcl/Tk8.5.2
+# The following is the original copyright text.
+#----------------------------------------------------------------------------
+# Copyright (C) 2008 Pat Thoyts <patthoyts@users.sourceforge.net>
+#
+# Calculate a Knight's tour of a chessboard.
+#
+# This uses Warnsdorff's rule to calculate the next square each
+# time. This specifies that the next square should be the one that
+# has the least number of available moves.
+#
+# Using this rule it is possible to get to a position where
+# there are no squares available to move into. In this implementation
+# this occurs when the starting square is d6.
+#
+# To solve this fault an enhancement to the rule is that if we
+# have a choice of squares with an equal score, we should choose
+# the one nearest the edge of the board.
+#
+# If the call to the Edgemost function is commented out you can see
+# this occur.
+#
+# You can drag the knight to a specific square to start if you wish.
+# If you let it repeat then it will choose random start positions
+# for each new tour.
+#----------------------------------------------------------------------------
+require 'tk'
+
+class Knights_Tour
+ # Return a list of accessible squares from a given square
+ def valid_moves(square)
+ moves = []
+ [
+ [-1,-2], [-2,-1], [-2,1], [-1,2], [1,2], [2,1], [2,-1], [1,-2]
+ ].each{|col_delta, row_delta|
+ col = (square % 8) + col_delta
+ row = (square.div(8)) + row_delta
+ moves << (row * 8 + col) if row > -1 && row < 8 && col > -1 && col < 8
+ }
+ moves
+ end
+
+ # Return the number of available moves for this square
+ def check_square(square)
+ valid_moves(square).find_all{|pos| ! @visited.include?(pos)}.length
+ end
+
+ # Select the next square to move to. Returns -1 if there are no available
+ # squares remaining that we can move to.
+ def next_square(square)
+ minimum = 9
+ nxt = -1
+ valid_moves(square).each{|pos|
+ unless @visited.include?(pos)
+ cnt = check_square(pos)
+ if cnt < minimum
+ minimum = cnt
+ nxt = pos
+ elsif cnt == minimum
+ nxt = edgemost(nxt, pos)
+ end
+ end
+ }
+ nxt
+ end
+
+ # Select the square nearest the edge of the board
+ def edgemost(nxt, pos)
+ col_A = 3 - ((3.5 - nxt % 8).abs.to_i)
+ col_B = 3 - ((3.5 - pos % 8).abs.to_i)
+ row_A = 3 - ((3.5 - nxt.div(8)).abs.to_i)
+ row_B = 3 - ((3.5 - pos.div(8)).abs.to_i)
+ (col_A * row_A < col_B * row_B)? nxt : pos
+ end
+
+ # Display a square number as a standard chess square notation.
+ def _N(square)
+ '%c%d' % [(97 + square % 8), (square.div(8) + 1)]
+ end
+
+ # Perform a Knight's move and schedule the next move.
+ def move_piece(last, square)
+ @log.insert(:end, "#{@visited.length}. #{_N last} -> #{_N square}\n", '')
+ @log.see(:end)
+ @board.itemconfigure(1+last, :state=>:normal, :outline=>'black')
+ @board.itemconfigure(1+square, :state=>:normal, :outline=>'red')
+ @knight.coords(@board.coords(1+square)[0..1])
+ @visited << square
+ if (nxt = next_square(square)) != -1
+ @after_id = Tk.after(@delay.numeric){move_piece(square, nxt) rescue nil}
+ else
+ @start_btn.state :normal
+ if @visited.length == 64
+ if @initial == square
+ @log.insert :end, 'Closed tour!'
+ else
+ @log.insert :end, "Success\n", {}
+ Tk.after(@delay.numeric * 2){tour(rand(64))} if @continuous.bool
+ end
+ else
+ @log.insert :end, "FAILED!\n", {}
+ end
+ end
+ end
+
+ # Begin a new tour of the board given a random start position
+ def tour(square = nil)
+ @visited.clear
+ @log.clear
+ @start_btn.state :disabled
+ 1.upto(64){|n|
+ @board.itemconfigure(n, :state=>:disabled, :outline=>'black')
+ }
+ unless square
+ square = @board.find_closest(*(@knight.coords << 0 << 65))[0].to_i - 1
+ end
+ @initial = square
+ Tk.after_idle{ move_piece(@initial, @initial) rescue nil }
+ end
+
+ def _stop
+ Tk.after_cancel(@after_id) rescue nil
+ end
+
+ def _exit
+ _stop
+ $knightstour.destroy
+ end
+
+ def set_delay(new)
+ @delay.numeric = new.to_i
+ end
+
+ def drag_start(w, x, y)
+ w.dtag('selected')
+ w.addtag('selected', :withtag, 'current')
+ @dragging = [x, y]
+ end
+
+ def drag_motion(w, x, y)
+ return unless @dragging
+ w.move('selected', x - @dragging[0], y - @dragging[1])
+ @dragging = [x, y]
+ end
+
+ def drag_end(w, x, y)
+ square = w.find_closest(x, y, 0, 65)
+ w.coords('selected', w.coords(square)[0..1])
+ w.dtag('selected')
+ @dragging = nil
+ end
+
+ def make_SeeDismiss
+ ## See Code / Dismiss
+ frame = Ttk::Frame.new($knightstour)
+ sep = Ttk::Separator.new(frame)
+ Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
+ TkGrid('x',
+ Ttk::Button.new(frame, :text=>'See Code',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{showCode 'knightstour'}),
+ Ttk::Button.new(frame, :text=>'Dismiss',
+ :image=>$image['delete'], :compound=>:left,
+ :command=>proc{
+ $knightstour.destroy
+ $knightstour = nil
+ }),
+ :padx=>4, :pady=>4)
+ frame.grid_columnconfigure(0, :weight=>1)
+ frame
+ end
+
+ def create_gui(parent = nil)
+ $knightstour.destroy rescue nil
+ $knightstour = Tk::Toplevel.new(parent, :title=>"Knight's tour")
+ $knightstour.withdraw
+ base_f = Ttk::Frame.new($knightstour)
+ @board = Tk::Canvas.new(base_f, :width=>240, :height=>240)
+ @log = Tk::Text.new(base_f, :width=>12, :height=>1,
+ :font=>'Arial 8', :background=>'white')
+ scr = @log.yscrollbar(Ttk::Scrollbar.new(base_f))
+
+ @visited = []
+ @delay = TkVariable.new(600)
+ @continuous = TkVariable.new(false)
+
+ tool_f = Ttk::Frame.new($knightstour)
+ label = Ttk::Label.new(tool_f, :text=>'Speed')
+ scale = Ttk::Scale.new(tool_f, :from=>8, :to=>2000, :variable=>@delay,
+ :command=>proc{|n| set_delay(n)})
+ check = Ttk::Checkbutton.new(tool_f, :text=>'Repeat',
+ :variable=>@continuous)
+ @start_btn = Ttk::Button.new(tool_f, :text=>'Start',
+ :command=>proc{tour()})
+ @exit_btn = Ttk::Button.new(tool_f, :text=>'Exit',
+ :command=>proc{_exit()})
+
+ 7.downto(0){|row|
+ 0.upto(7){|col|
+ if ((col & 1) ^ (row & 1)).zero?
+ fill = 'bisque'
+ dfill = 'bisque3'
+ else
+ fill = 'tan3'
+ dfill = 'tan4'
+ end
+ coords = [col * 30 + 4, row * 30 + 4, col * 30 + 30, row * 30 + 30]
+ @board.create(TkcRectangle, coords,
+ :fill=>fill, :disabledfill=>dfill,
+ :width=>2, :state=>:disabled)
+ }
+ }
+
+ @knight_font = TkFont.new(:size=>-24)
+ @knight = TkcText.new(@board, 0, 0, :font=>@knight_font,
+ :text=>Tk::UTF8_String.new('\u265e'),
+ :anchor=>'nw', # :tags=>'knight',
+ :fill=>'black', :activefill=>'#600000')
+ @knight.coords(@board.coords(rand(64)+1)[0..1])
+ @knight.bind('ButtonPress-1', '%W %x %y'){|w,x,y| drag_start(w,x,y)}
+ @knight.bind('Motion', '%W %x %y'){|w,x,y| drag_motion(w,x,y)}
+ @knight.bind('ButtonRelease-1', '%W %x %y'){|w,x,y| drag_end(w,x,y)}
+
+ Tk.grid(@board, @log, scr, :sticky=>'news')
+ base_f.grid_rowconfigure(0, :weight=>1)
+ base_f.grid_columnconfigure(0, :weight=>1)
+
+ Tk.grid(base_f, '-', '-', '-', '-', '-', :sticky=>'news')
+ widgets = [label, scale, check, @start_btn]
+ sg = nil
+ unless $RubyTk_WidgetDemo
+ widgets << @exit_btn
+ if Tk.windowingsystem != 'aqua'
+ #widgets.unshift(Ttk::SizeGrip.new(tool_f))
+ Ttk::SizeGrip.new(tool_f).pack(:side=>:right, :anchor=>'se')
+ end
+ end
+ Tk.pack(widgets, :side=>:right)
+ if Tk.windowingsystem == 'aqua'
+ TkPack.configure(widgets, :padx=>[4, 4], :pady=>[12, 12])
+ TkPack.configure(widgets[0], :padx=>[4, 24])
+ TkPack.configure(widgets[-1], :padx=>[16, 4])
+ end
+
+ Tk.grid(tool_f, '-', '-', '-', '-', '-', :sticky=>'ew')
+
+ if $RubyTk_WidgetDemo
+ Tk.grid(make_SeeDismiss(), '-', '-', '-', '-', '-', :sticky=>'ew')
+ end
+
+ $knightstour.grid_rowconfigure(0, :weight=>1)
+ $knightstour.grid_columnconfigure(0, :weight=>1)
+
+ $knightstour.bind('Control-F2'){TkConsole.show}
+ $knightstour.bind('Return'){@start_btn.invoke}
+ $knightstour.bind('Escape'){@exit_btn.invoke}
+ $knightstour.bind('Destroy'){ _stop }
+ $knightstour.protocol('WM_DELETE_WINDOW'){ _exit }
+
+ $knightstour.deiconify
+ $knightstour.tkwait_destroy
+ end
+
+ def initialize(parent = nil)
+ create_gui(parent)
+ end
+end
+
+Tk.root.withdraw unless $RubyTk_WidgetDemo
+Thread.new{Tk.mainloop} if __FILE__ == $0
+Knights_Tour.new
diff --git a/ext/tk/sample/demos-en/label.rb b/ext/tk/sample/demos-en/label.rb
index 55e07a5ebc..91e41e4a22 100644
--- a/ext/tk/sample/demos-en/label.rb
+++ b/ext/tk/sample/demos-en/label.rb
@@ -19,8 +19,10 @@ $label_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($label_demo).pack(:fill=>:both, :expand=>true)
+
# label
-msg = TkLabel.new($label_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -29,7 +31,7 @@ msg = TkLabel.new($label_demo) {
msg.pack('side'=>'top')
# frame
-TkFrame.new($label_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -47,8 +49,8 @@ TkFrame.new($label_demo) {|frame|
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# label demo
-f_left = TkFrame.new($label_demo)
-f_right = TkFrame.new($label_demo)
+f_left = TkFrame.new(base_frame)
+f_right = TkFrame.new(base_frame)
[f_left, f_right].each{|w| w.pack('side'=>'left', 'expand'=>'yes',
'padx'=>10, 'pady'=>10, 'fill'=>'both')}
@@ -59,7 +61,8 @@ f_right = TkFrame.new($label_demo)
TkLabel.new(f_left, 'text'=>'Third label, sunken', 'relief'=>'sunken')
].each{|w| w.pack('side'=>'top', 'expand'=>'yes', 'pady'=>2, 'anchor'=>'w')}
-TkLabel.new(f_right) {
+# TkLabel.new(f_right) {
+Tk::Label.new(f_right) {
bitmap('@' + [$demo_dir,'..','images','face.xbm'].join(File::Separator))
borderwidth 2
relief 'sunken'
diff --git a/ext/tk/sample/demos-en/labelframe.rb b/ext/tk/sample/demos-en/labelframe.rb
index 842a4f6c04..c912ff4c52 100644
--- a/ext/tk/sample/demos-en/labelframe.rb
+++ b/ext/tk/sample/demos-en/labelframe.rb
@@ -17,8 +17,10 @@ $labelframe_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($labelframe_demo).pack(:fill=>:both, :expand=>true)
+
# Some information
-TkLabel.new($labelframe_demo,
+TkLabel.new(base_frame,
:font=>$font, :wraplength=>'4i', :justify=>:left,
:text=><<EOL).pack(:side=>:top)
Labelframes are used to group related widgets together. \
@@ -29,7 +31,7 @@ which supports a 'labelframe' widget.
EOL
# The bottom buttons
-TkFrame.new($labelframe_demo){|f|
+TkFrame.new(base_frame){|f|
pack(:side=>:bottom, :fill=>:x, :pady=>'2m')
TkButton.new(f, :text=>'Dismiss', :width=>15, :command=>proc{
@@ -43,7 +45,7 @@ TkFrame.new($labelframe_demo){|f|
}
# Demo area
-w = TkFrame.new($labelframe_demo).pack(:side=>:bottom, :fill=>:both,
+w = TkFrame.new(base_frame).pack(:side=>:bottom, :fill=>:both,
:expand=>true)
# A group of radiobuttons in a labelframe
diff --git a/ext/tk/sample/demos-en/mclist.rb b/ext/tk/sample/demos-en/mclist.rb
new file mode 100644
index 0000000000..a849eba515
--- /dev/null
+++ b/ext/tk/sample/demos-en/mclist.rb
@@ -0,0 +1,117 @@
+# mclist.rb --
+#
+# This demonstration script creates a toplevel window containing a Ttk
+# tree widget configured as a multi-column listbox.
+#
+# based on "Id: mclist.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp"
+
+if defined?($mclist_demo) && $mclist_demo
+ $mclist_demo.destroy
+ $mclist_demo = nil
+end
+
+$mclist_demo = TkToplevel.new {|w|
+ title("Multi-Column List")
+ iconname("mclist")
+ positionWindow(w)
+}
+
+base_frame = TkFrame.new($mclist_demo).pack(:fill=>:both, :expand=>true)
+
+## Explanatory text
+Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i',
+ :justify=>:left, :anchor=>'n', :padding=>[10, 2, 10, 6],
+ :text=><<EOL).pack(:fill=>:x)
+Ttk is the new Tk themed widget set. \
+One of the widgets it includes is a tree widget, \
+which can be configured to display multiple columns of informational data \
+without displaying the tree itself. \
+This is a simple way to build a listbox that has multiple columns. \
+Clicking on the heading for a column will sort the data by that column. \
+You can also change the width of the columns \
+by dragging the boundary between them.
+EOL
+
+## See Code / Dismiss
+Ttk::Frame.new(base_frame) {|frame|
+ sep = Ttk::Separator.new(frame)
+ Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
+ TkGrid('x',
+ Ttk::Button.new(frame, :text=>'See Code',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{showCode 'mclist'}),
+ Ttk::Button.new(frame, :text=>'Dismiss',
+ :image=>$image['delete'], :compound=>:left,
+ :command=>proc{
+ $mclist_demo.destroy
+ $mclist_demo = nil
+ }),
+ :padx=>4, :pady=>4)
+ grid_columnconfigure(0, :weight=>1)
+ pack(:side=>:bottom, :fill=>:x)
+}
+
+container = Ttk::Frame.new(base_frame)
+tree = Ttk::Treeview.new(base_frame, :columns=>%w(country capital currency),
+ :show=>:headings)
+if Tk.windowingsystem != 'aqua'
+ vsb = tree.yscrollbar(Ttk::Scrollbar.new(base_frame))
+ hsb = tree.xscrollbar(Ttk::Scrollbar.new(base_frame))
+else
+ vsb = tree.yscrollbar(Tk::Scrollbar.new(base_frame))
+ hsb = tree.xscrollbar(Tk::Scrollbar.new(base_frame))
+end
+
+container.pack(:fill=>:both, :expand=>true)
+Tk.grid(tree, vsb, :in=>container, :sticky=>'nsew')
+Tk.grid(hsb, :in=>container, :sticky=>'nsew')
+container.grid_columnconfigure(0, :weight=>1)
+container.grid_rowconfigure(0, :weight=>1)
+
+## The data we're going to insert
+data = [
+ ['Argentina', 'Buenos Aires', 'ARS'],
+ ['Australia', 'Canberra', 'AUD'],
+ ['Brazil', 'Brazilia', 'BRL'],
+ ['Canada', 'Ottawa', 'CAD'],
+ ['China', 'Beijing', 'CNY'],
+ ['France', 'Paris', 'EUR'],
+ ['Germany', 'Berlin', 'EUR'],
+ ['India', 'New Delhi', 'INR'],
+ ['Italy', 'Rome', 'EUR'],
+ ['Japan', 'Tokyo', 'JPY'],
+ ['Mexico', 'Mexico City', 'MXN'],
+ ['Russia', 'Moscow', 'RUB'],
+ ['South Africa', 'Pretoria', 'ZAR'],
+ ['United Kingdom', 'London', 'GBP'],
+ ['United States', 'Washington, D.C.', 'USD'],
+]
+
+## Code to insert the data nicely
+font = Ttk::Style.lookup(tree[:style], :font)
+cols = %w(country capital currency)
+cols.zip(%w(Country Capital Currency)).each{|col, name|
+ tree.heading_configure(col, :text=>name,
+ :command=>proc{sort_by(tree, col, false)})
+ tree.column_configure(col, :width=>TkFont.measure(font, name))
+}
+
+data.each{|country, capital, currency|
+ #tree.insert('', :end, :values=>[country, capital, currency])
+ tree.insert(nil, :end, :values=>[country, capital, currency])
+ cols.zip([country, capital, currency]).each{|col, val|
+ len = TkFont.measure(font, "#{val} ")
+ if tree.column_cget(col, :width) < len
+ tree.column_configure(col, :width=>len)
+ end
+ }
+}
+
+## Code to do the sorting of the tree contents when clicked on
+def sort_by(tree, col, direction)
+ tree.children(nil).map!{|row| [tree.get(row, col), row.id]} .
+ sort(&((direction)? proc{|x, y| y <=> x}: proc{|x, y| x <=> y})) .
+ each_with_index{|info, idx| tree.move(info[1], nil, idx)}
+
+ tree.heading_configure(col, :command=>proc{sort_by(tree, col, ! direction)})
+end
diff --git a/ext/tk/sample/demos-en/menu.rb b/ext/tk/sample/demos-en/menu.rb
index 8370d2f5f0..bf6c22cb9d 100644
--- a/ext/tk/sample/demos-en/menu.rb
+++ b/ext/tk/sample/demos-en/menu.rb
@@ -15,8 +15,10 @@ $menu_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($menu_demo).pack(:fill=>:both, :expand=>true)
+
# menu frame
-$menu_frame = TkFrame.new($menu_demo, 'relief'=>'raised', 'bd'=>2)
+$menu_frame = TkFrame.new(base_frame, 'relief'=>'raised', 'bd'=>2)
$menu_frame.pack('side'=>'top', 'fill'=>'x')
begin
@@ -26,7 +28,7 @@ rescue
end
# label
-TkLabel.new($menu_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left') {
+TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left') {
if $tk_platform['platform'] == 'macintosh' ||
windowingsystem == "classic" || windowingsystem == "aqua"
text("This window contains a menubar with cascaded menus. You can invoke entries with an accelerator by typing Command+x, where \"x\" is the character next to the command key symbol. The rightmost menu can be torn off into a palette by dragging outside of its bounds and releasing the mouse.")
@@ -36,7 +38,7 @@ TkLabel.new($menu_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left') {
}.pack('side'=>'top')
# frame
-TkFrame.new($menu_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -105,7 +107,7 @@ TkMenubutton.new($menu_frame, 'text'=>'Cascades', 'underline'=>0) {|m|
'accelerator'=>"#{modifier}+G", 'underline'=>6)
$menu_demo.bind("#{modifier}-g", proc{print "Goodbye\n"})
- TkMenu.new(m, 'tearoff'=>false) {|cascade_check|
+ TkMenu.new(cascade_menu, 'tearoff'=>false) {|cascade_check|
cascade_menu.add('cascade', 'label'=>'Check buttons',
'menu'=>cascade_check, 'underline'=>0)
oil = TkVariable.new(0)
@@ -127,7 +129,7 @@ TkMenubutton.new($menu_frame, 'text'=>'Cascades', 'underline'=>0) {|m|
invoke 3
}
- TkMenu.new(m, 'tearoff'=>false) {|cascade_radio|
+ TkMenu.new(cascade_menu, 'tearoff'=>false) {|cascade_radio|
cascade_menu.add('cascade', 'label'=>'Radio buttons',
'menu'=>cascade_radio, 'underline'=>0)
pointSize = TkVariable.new
diff --git a/ext/tk/sample/demos-en/menu84.rb b/ext/tk/sample/demos-en/menu84.rb
index cb616d8461..4029ce5541 100644
--- a/ext/tk/sample/demos-en/menu84.rb
+++ b/ext/tk/sample/demos-en/menu84.rb
@@ -15,6 +15,8 @@ $menu84_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($menu84_demo).pack(:fill=>:both, :expand=>true)
+
begin
windowingsystem = Tk.windowingsystem()
rescue
@@ -22,7 +24,7 @@ rescue
end
# label
-TkLabel.new($menu84_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left') {
+TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left') {
if $tk_platform['platform'] == 'macintosh' ||
windowingsystem == "classic" || windowingsystem == "aqua"
text("This window contains a menubar with cascaded menus. You can invoke entries with an accelerator by typing Command+x, where \"x\" is the character next to the command key symbol. The rightmost menu can be torn off into a palette by dragging outside of its bounds and releasing the mouse.")
@@ -33,7 +35,7 @@ TkLabel.new($menu84_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left') {
menustatus = TkVariable.new(" ")
-TkFrame.new($menu84_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkLabel.new(frame, 'textvariable'=>menustatus, 'relief'=>'sunken',
'bd'=>1, 'font'=>['Helvetica', '10'],
'anchor'=>'w').pack('side'=>'left', 'padx'=>2,
@@ -43,7 +45,7 @@ TkFrame.new($menu84_demo) {|frame|
# frame
-TkFrame.new($menu84_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
diff --git a/ext/tk/sample/demos-en/menubu.rb b/ext/tk/sample/demos-en/menubu.rb
index e2ddd07bc6..b37367e515 100644
--- a/ext/tk/sample/demos-en/menubu.rb
+++ b/ext/tk/sample/demos-en/menubu.rb
@@ -37,16 +37,18 @@ $menubu_demo = TkToplevel.new {|w|
positionWindow($menubu_demo)
+base_frame = TkFrame.new($menubu_demo).pack(:fill=>:both, :expand=>true)
+
# version check
if $tk_version.to_f < 8.0
# label
-TkLabel.new($menubu_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left') {
+TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left') {
text("This is a demonstration of menubuttons. The \"Below\" menubutton pops its menu below the button; the \"Right\" button pops to the right, etc. There are two option menus directly below this text; one is just a standard menu and the other is a 16-color palette.")
}.pack('side'=>'top')
# frame
-TkFrame.new($menubu_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -64,7 +66,7 @@ TkFrame.new($menubu_demo) {|frame|
else ; # Tk8.x
-body = TkFrame.new($menubu_demo)
+body = TkFrame.new(base_frame)
body.pack('expand'=>'yes', 'fill'=>'both')
below = TkMenubutton.new(body) {
@@ -159,7 +161,7 @@ center = TkFrame.new(body) {
grid('row'=>1, 'column'=>1, 'sticky'=>'news')
}
-TkFrame.new($menubu_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc {
diff --git a/ext/tk/sample/demos-en/msgbox.rb b/ext/tk/sample/demos-en/msgbox.rb
index aab1b619cf..62b1f2b985 100644
--- a/ext/tk/sample/demos-en/msgbox.rb
+++ b/ext/tk/sample/demos-en/msgbox.rb
@@ -18,12 +18,14 @@ $msgbox_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($msgbox_demo).pack(:fill=>:both, :expand=>true)
+
# label
-TkLabel.new($msgbox_demo, 'font'=>$font, 'wraplength'=>'4i', 'justify'=>'left',
+TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'4i', 'justify'=>'left',
'text'=>"Choose the icon and type option of the message box. Then press the \"Message Box\" button to see the message box.").pack('side'=>'top')
# frame
-TkFrame.new($msgbox_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -45,8 +47,8 @@ TkFrame.new($msgbox_demo) {|frame|
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# frame
-$msgbox_leftframe = TkFrame.new($msgbox_demo)
-$msgbox_rightframe = TkFrame.new($msgbox_demo)
+$msgbox_leftframe = TkFrame.new(base_frame)
+$msgbox_rightframe = TkFrame.new(base_frame)
$msgbox_leftframe .pack('side'=>'left', 'expand'=>'yes', 'fill'=>'y',
'pady'=>'.5c', 'padx'=>'.5c')
$msgbox_rightframe.pack('side'=>'left', 'expand'=>'yes', 'fill'=>'y',
diff --git a/ext/tk/sample/demos-en/msgbox2.rb b/ext/tk/sample/demos-en/msgbox2.rb
new file mode 100644
index 0000000000..6fe6c778b3
--- /dev/null
+++ b/ext/tk/sample/demos-en/msgbox2.rb
@@ -0,0 +1,91 @@
+# msgbox2.rb
+#
+# This demonstration script creates message boxes of various type
+#
+# message boxes widget demo (called by 'widget')
+#
+
+# toplevel widget
+if defined?($msgbox2_demo) && $msgbox2_demo
+ $msgbox2_demo.destroy
+ $msgbox2_demo = nil
+end
+
+# demo toplevel widget
+$msgbox2_demo = TkToplevel.new {|w|
+ title("Message Box Demonstration")
+ iconname("messagebox")
+ positionWindow(w)
+}
+
+base_frame = TkFrame.new($msgbox2_demo).pack(:fill=>:both, :expand=>true)
+
+# label
+TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'4i', 'justify'=>'left',
+ 'text'=>"Choose the icon and type option of the message box. Then press the \"Message Box\" button to see the message box with both of a message and a detail.").pack('side'=>'top')
+
+# frame
+TkFrame.new(base_frame) {|frame|
+ TkButton.new(frame) {
+ text 'Dismiss'
+ command proc{
+ tmppath = $msgbox2_demo
+ $msgbox2_demo = nil
+ tmppath.destroy
+ }
+ }.pack('side'=>'left', 'expand'=>'yes')
+
+ TkButton.new(frame) {
+ text 'Show Code'
+ command proc{showCode 'msgbox2'}
+ }.pack('side'=>'left', 'expand'=>'yes')
+
+ TkButton.new(frame) {
+ text 'Message Box'
+ command proc{showMessageBox $msgbox2_demo}
+ }.pack('side'=>'left', 'expand'=>'yes')
+}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
+
+# frame
+$msgbox_leftframe = TkFrame.new(base_frame)
+$msgbox_rightframe = TkFrame.new(base_frame)
+$msgbox_leftframe .pack('side'=>'left', 'expand'=>'yes', 'fill'=>'y',
+ 'pady'=>'.5c', 'padx'=>'.5c')
+$msgbox_rightframe.pack('side'=>'left', 'expand'=>'yes', 'fill'=>'y',
+ 'pady'=>'.5c', 'padx'=>'.5c')
+
+TkLabel.new($msgbox_leftframe, 'text'=>'Icon').pack('side'=>'top')
+TkFrame.new($msgbox_leftframe, 'relief'=>'ridge', 'bd'=>1, 'height'=>2)\
+.pack('side'=>'top', 'fill'=>'x', 'expand'=>'no')
+
+$msgboxIcon = TkVariable.new('info')
+['error', 'info', 'question', 'warning'].each {|icon|
+ TkRadioButton.new($msgbox_leftframe, 'text'=>icon, 'variable'=>$msgboxIcon,
+ 'relief'=>'flat', 'value'=>icon, 'width'=>16,
+ 'anchor'=>'w').pack('side'=>'top', 'pady'=>2,
+ 'anchor'=>'w', 'fill'=>'x')
+}
+
+TkLabel.new($msgbox_rightframe, 'text'=>'Type').pack('side'=>'top')
+TkFrame.new($msgbox_rightframe, 'relief'=>'ridge', 'bd'=>1, 'height'=>2)\
+.pack('side'=>'top', 'fill'=>'x', 'expand'=>'no')
+
+$msgboxType = TkVariable.new('ok')
+['abortretryignore', 'ok', 'okcancel',
+ 'retrycancel', 'yesno', 'yesnocancel'].each {|type|
+ TkRadioButton.new($msgbox_rightframe, 'text'=>type, 'variable'=>$msgboxType,
+ 'relief'=>'flat', 'value'=>type, 'width'=>16,
+ 'anchor'=>'w').pack('side'=>'top', 'pady'=>2,
+ 'anchor'=>'w', 'fill'=>'x')
+}
+
+def showMessageBox(w)
+ button = Tk.messageBox('icon'=>$msgboxIcon.value, 'type'=>$msgboxType.value,
+ 'title'=>'Message', 'parent'=>w,
+ 'message'=>"\"#{$msgboxType.value}\" Type MessageBox",
+ 'detail'=>"This is a \"#{$msgboxType.value}\" type messagebox with the \"#{$msgboxIcon.value}\" icon. Please click one of the following button.")
+
+ Tk.messageBox('icon'=>'info', 'type'=>'ok', 'parent'=>w,
+ 'message'=>"You have selected \"#{button}\"")
+end
+
diff --git a/ext/tk/sample/demos-en/paned1.rb b/ext/tk/sample/demos-en/paned1.rb
index 48ba86de02..26941b84a8 100644
--- a/ext/tk/sample/demos-en/paned1.rb
+++ b/ext/tk/sample/demos-en/paned1.rb
@@ -16,7 +16,9 @@ $paned1_demo = TkToplevel.new {|w|
positionWindow(w)
}
-TkLabel.new($paned1_demo,
+base_frame = TkFrame.new($paned1_demo).pack(:fill=>:both, :expand=>true)
+
+TkLabel.new(base_frame,
:font=>$font, :wraplength=>'4i', :justify=>:left,
:text=><<EOL).pack(:side=>:top)
The sash between the two coloured windows below can be used to divide the area between them. Use the left mouse button to resize without redrawing by just moving the sash, and use the middle mouse button to resize opaquely (always redrawing the windows in each position.)
@@ -24,7 +26,7 @@ If your Tk library linked to Ruby doesn't include a 'panedwindow', this demo doe
EOL
# The bottom buttons
-TkFrame.new($paned1_demo){|f|
+TkFrame.new(base_frame){|f|
pack(:side=>:bottom, :fill=>:x, :pady=>'2m')
TkButton.new(f, :text=>'Dismiss', :width=>15, :command=>proc{
@@ -37,9 +39,9 @@ TkFrame.new($paned1_demo){|f|
}).pack(:side=>:left, :expand=>true)
}
-TkPanedwindow.new($paned1_demo){|f|
- pack(:side=>:top, :expand=>true, :fill=>:both, :pady=>2, :padx=>'2m')
+TkPanedwindow.new(base_frame, :orient=>:horizontal){|f|
+ add(Tk::Label.new(f, :text=>"This is the\nleft side", :bg=>'yellow'),
+ Tk::Label.new(f, :text=>"This is the\nright side", :bg=>'cyan'))
- add(TkLabel.new(f, :text=>"This is the\nleft side", :bg=>'yellow'),
- TkLabel.new(f, :text=>"This is the\nright side", :bg=>'cyan'))
+ pack(:side=>:top, :expand=>true, :fill=>:both, :pady=>2, :padx=>'2m')
}
diff --git a/ext/tk/sample/demos-en/paned2.rb b/ext/tk/sample/demos-en/paned2.rb
index 5911cadab6..0e62013886 100644
--- a/ext/tk/sample/demos-en/paned2.rb
+++ b/ext/tk/sample/demos-en/paned2.rb
@@ -16,7 +16,9 @@ $paned2_demo = TkToplevel.new {|w|
positionWindow(w)
}
-TkLabel.new($paned2_demo,
+base_frame = TkFrame.new($paned2_demo).pack(:fill=>:both, :expand=>true)
+
+TkLabel.new(base_frame,
:font=>$font, :wraplength=>'4i', :justify=>:left,
:text=><<EOL).pack(:side=>:top)
The sash between the two scrolled windows below can be used to divide the area between them. Use the left mouse button to resize without redrawing by just moving the sash, and use the middle mouse button to resize opaquely (always redrawing the windows in each position.)
@@ -24,7 +26,7 @@ If your Tk library linked to Ruby doesn't include a 'panedwindow', this demo doe
EOL
# The bottom buttons
-TkFrame.new($paned2_demo){|f|
+TkFrame.new(base_frame){|f|
pack(:side=>:bottom, :fill=>:x, :pady=>'2m')
TkButton.new(f, :text=>'Dismiss', :width=>15, :command=>proc{
@@ -61,7 +63,7 @@ paneList.value = [ # ruby's array --> tcl's list
]
# Create the pane itself
-TkPanedwindow.new($paned2_demo, :orient=>:vertical){|f|
+TkPanedwindow.new(base_frame, :orient=>:vertical){|f|
pack(:side=>:top, :expand=>true, :fill=>:both, :pady=>2, :padx=>'2m')
add(TkFrame.new(f){|paned2_top|
diff --git a/ext/tk/sample/demos-en/patch_1.1c1 b/ext/tk/sample/demos-en/patch_1.1c1
deleted file mode 100644
index d3952e71eb..0000000000
--- a/ext/tk/sample/demos-en/patch_1.1c1
+++ /dev/null
@@ -1,93 +0,0 @@
---- /usr/src/ruby-1.1c1/lib/tkcanvas.rb Tue Jul 21 18:18:02 1998
-+++ tkcanvas.rb Fri Jul 24 20:38:24 1998
-@@ -310,7 +310,7 @@
- || key == 'latinfont' || key == 'asciifont' )
- tagfont_configure(tagid(tagOrId), {key=>value})
- else
-- tk_call 'itemconfigure', tagid(tagOrId), "-#{key}", value
-+ tk_send 'itemconfigure', tagid(tagOrId), "-#{key}", value
- end
- end
- end
---- /usr/src/ruby-1.1c1/lib/tkfont.rb Fri Jul 17 23:43:28 1998
-+++ tkfont.rb Fri Jul 24 17:46:22 1998
-@@ -42,7 +42,7 @@
- r | []
-
- when /^8\.*/
-- list(tk_call('font', 'names'))
-+ tk_split_simplelist(tk_call('font', 'names'))
-
- end
- end
-@@ -89,10 +89,14 @@
- if fnt == []
- TkFont.new(nil, nil).call_font_configure(path, *(args + [{}]))
- else
-- compound = Hash[*list(tk_call('font', 'configure',
-- fnt))].collect{|key,value|
-- [key[1..-1], value]
-- }.assoc('compound')[1]
-+ begin
-+ compound = Hash[*list(tk_call('font', 'configure',
-+ fnt))].collect{|key,value|
-+ [key[1..-1], value]
-+ }.assoc('compound')[1]
-+ rescue
-+ compound = []
-+ end
- if compound == []
- TkFont.new(fnt, DEFAULT_KANJI_FONT_NAME) \
- .call_font_configure(path, *(args + [{}]))
-@@ -156,14 +160,19 @@
- elsif font.kind_of? Array
- finfo = {}
- finfo['family'] = font[0].to_s
-- if font[1] && font[1] != '0' && font[1] =~ /^(|\+|-)([0-9]+)$/
-- if $1 == '-'
-- finfo['pixels'] = font[1].to_s
-+ if font[1]
-+ fsize = font[1].to_s
-+ if fsize != '0' && fsize =~ /^(|\+|-)([0-9]+)$/
-+ if $1 == '-'
-+ finfo['pixels'] = $2
-+ else
-+ finfo['points'] = $2
-+ end
- else
-- finfo['points'] = font[1].to_s
-+ finfo['points'] = '13'
- end
- end
-- finfo[2..-1].each{|style|
-+ font[2..-1].each{|style|
- case (style)
- when 'normal'
- finfo['weight'] = style
-@@ -199,16 +208,19 @@
- elsif font.kind_of? Array
- finfo = {}
- finfo['family'] = font[0].to_s
-- if font[1] && font[1] != '0' && font[1] =~ /^(|\+|-)([0-9]+)$/
-- if $1 == '-'
-- finfo['pixels'] = $2
-+ if font[1]
-+ fsize = font[1].to_s
-+ if fsize != '0' && fsize =~ /^(|\+|-)([0-9]+)$/
-+ if $1 == '-'
-+ finfo['pixels'] = $2
-+ else
-+ finfo['points'] = $2
-+ end
- else
-- finfo['points'] = $2
-+ finfo['points'] = '13'
- end
-- else
-- finfo['points'] = '13'
- end
-- finfo[2..-1].each{|style|
-+ font[2..-1].each{|style|
- case (style)
- when 'normal'
- finfo['weight'] = style
diff --git a/ext/tk/sample/demos-en/pendulum.rb b/ext/tk/sample/demos-en/pendulum.rb
index 36bb44edec..5f7d361170 100644
--- a/ext/tk/sample/demos-en/pendulum.rb
+++ b/ext/tk/sample/demos-en/pendulum.rb
@@ -18,8 +18,10 @@ $pendulum_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($pendulum_demo).pack(:fill=>:both, :expand=>true)
+
# create label
-msg = TkLabel.new($pendulum_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -28,7 +30,7 @@ msg = TkLabel.new($pendulum_demo) {
msg.pack('side'=>'top')
# create frame
-TkFrame.new($pendulum_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -49,9 +51,11 @@ TkFrame.new($pendulum_demo) {|frame|
class PendulumAnimationDemo
def initialize(frame)
# Create some structural widgets
- pane = TkPanedWindow.new(frame).pack(:fill=>:both, :expand=>true)
- pane.add(@lf1 = TkLabelFrame.new(pane, :text=>'Pendulum Simulation'))
- pane.add(@lf2 = TkLabelFrame.new(pane, :text=>'Phase Space'))
+ @pane = TkPanedWindow.new(frame, :orient=>:horizontal).pack(:fill=>:both, :expand=>true)
+# @pane.add(@lf1 = TkLabelFrame.new(@pane, :text=>'Pendulum Simulation'))
+# @pane.add(@lf2 = TkLabelFrame.new(@pane, :text=>'Phase Space'))
+ @lf1 = TkLabelFrame.new(@pane, :text=>'Pendulum Simulation')
+ @lf2 = TkLabelFrame.new(@pane, :text=>'Phase Space')
# Create the canvas containing the graphical representation of the
# simulated system.
@@ -99,23 +103,24 @@ class PendulumAnimationDemo
@dTheta = 0.0
@length = 150
- # init display
- showPendulum
-
# animation loop
@timer = TkTimer.new(15){ repeat }
# binding
@c.bindtags_unshift(btag = TkBindTag.new)
btag.bind('Destroy'){ @timer.stop }
- btag.bind('1', proc{|x, y| @timer.stop; showPendulum(x, y)}, '%x %y')
- btag.bind('B1-Motion', proc{|x, y| showPendulum(x, y)}, '%x %y')
+ btag.bind('1', proc{|x, y| @timer.stop; showPendulum(x.to_i, y.to_i)},
+ '%x %y')
+ btag.bind('B1-Motion', proc{|x, y| showPendulum(x.to_i, y.to_i)}, '%x %y')
btag.bind('ButtonRelease-1',
- proc{|x, y| showPendulum(x, y); @timer.start }, '%x %y')
+ proc{|x, y| showPendulum(x.to_i, y.to_i); @timer.start },
+ '%x %y')
- btag.bind('Configure', proc{|w| @plate.coords(0, 25, w, 25)}, '%w')
+ btag.bind('Configure', proc{|w| @plate.coords(0, 25, w.to_i, 25)}, '%w')
@k.bind('Configure', proc{|h, w|
+ h = h.to_i
+ w = w.to_i
@psh = h/2;
@psw = w/2
@x_axis.coords(2, @psh, w-2, @psh)
@@ -124,6 +129,14 @@ class PendulumAnimationDemo
@label_dtheta.coords(w-6, @psh+4)
}, '%h %w')
+ # add
+ Tk.update
+ @pane.add(@lf1)
+ @pane.add(@lf2)
+
+ # init display
+ showPendulum
+
# animation start
@timer.start(500)
end
@@ -154,6 +167,10 @@ class PendulumAnimationDemo
# rate at which the angle is changing (the first derivative with
# respect to time.)
def showPhase
+ unless @psw && @psh
+ @psw = @k.width/2
+ @psh = @k.height/2
+ end
@points << @theta + @psw << -20*@dTheta + @psh
if @points.length > 100
@points = @points[-100..-1]
@@ -220,4 +237,4 @@ class PendulumAnimationDemo
end
# Start the animation processing
-PendulumAnimationDemo.new($pendulum_demo)
+PendulumAnimationDemo.new(base_frame)
diff --git a/ext/tk/sample/demos-en/plot.rb b/ext/tk/sample/demos-en/plot.rb
index 6d01deeef5..628c9df584 100644
--- a/ext/tk/sample/demos-en/plot.rb
+++ b/ext/tk/sample/demos-en/plot.rb
@@ -19,14 +19,16 @@ $plot_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($plot_demo).pack(:fill=>:both, :expand=>true)
+
# label
-TkLabel.new($plot_demo, 'font'=>$font, 'wraplength'=>'4i', 'justify'=>'left',
+TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'4i', 'justify'=>'left',
'text'=>"This window displays a canvas widget containing a simple 2-dimensional plot. You can doctor the data by dragging any of the points with mouse button 1."){
pack('side'=>'top')
}
# frame
-$plot_buttons = TkFrame.new($plot_demo) {|frame|
+$plot_buttons = TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -47,7 +49,7 @@ $plot_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
plotFont = '-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*'
# canvas
-$plot_canvas = TkCanvas.new($plot_demo,'relief'=>'raised','width'=>450,'height'=>300)
+$plot_canvas = TkCanvas.new(base_frame,'relief'=>'raised','width'=>450,'height'=>300)
$plot_canvas.pack('side'=>'top', 'fill'=>'x')
# plot
diff --git a/ext/tk/sample/demos-en/puzzle.rb b/ext/tk/sample/demos-en/puzzle.rb
index 0885cf2975..43c61f519f 100644
--- a/ext/tk/sample/demos-en/puzzle.rb
+++ b/ext/tk/sample/demos-en/puzzle.rb
@@ -19,8 +19,10 @@ $puzzle_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($puzzle_demo).pack(:fill=>:both, :expand=>true)
+
# label
-msg = TkLabel.new($puzzle_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -29,7 +31,7 @@ msg = TkLabel.new($puzzle_demo) {
msg.pack('side'=>'top')
# frame
-TkFrame.new($puzzle_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -52,18 +54,27 @@ TkFrame.new($puzzle_demo) {|frame|
# scrollbar widget and using its trough color.
begin
if Tk.windowingsystem() == 'aqua'
- frameSize = 160
+ frameWidth = 168
+ frameHeight = 168
+ elsif Tk.default_widget_set == :Ttk
+ frameWidth = 148
+ frameHeight = 124
else
- frameSize = 120
+ frameWidth = 120
+ frameHeight = 120
end
rescue
- frameSize = 120
+ frameWidth = 120
+ frameHeight = 120
end
+
+# depend_on_button_width = true
+depend_on_button_width = false
-s = TkScrollbar.new($puzzle_demo)
-base = TkFrame.new($puzzle_demo) {
- width frameSize
- height frameSize
+s = TkScrollbar.new(base_frame)
+base = TkFrame.new(base_frame) {
+ width frameWidth
+ height frameHeight
borderwidth 2
relief 'sunken'
bg s['troughcolor']
@@ -87,6 +98,9 @@ order = [3,1,6,2,5,7,15,13,4,11,8,9,14,10,12]
text num
highlightthickness 0
command def_puzzleswitch_proc(w, num)
+ if depend_on_button_width && (w.winfo_reqwidth * 4 > base.width)
+ base.width = w.winfo_reqwidth * 4
+ end
}.place('relx'=>$xpos[num], 'rely'=>$ypos[num],
'relwidth'=>0.25, 'relheight'=>0.25)
}
diff --git a/ext/tk/sample/demos-en/radio.rb b/ext/tk/sample/demos-en/radio.rb
index 96cdc4c54a..25cfac2134 100644
--- a/ext/tk/sample/demos-en/radio.rb
+++ b/ext/tk/sample/demos-en/radio.rb
@@ -19,8 +19,10 @@ $radio_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($radio_demo).pack(:fill=>:both, :expand=>true)
+
# label
-msg = TkLabel.new($radio_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -33,7 +35,7 @@ size = TkVariable.new
color = TkVariable.new
# frame
-TkFrame.new($radio_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -52,14 +54,14 @@ TkFrame.new($radio_demo) {|frame|
TkButton.new(frame) {
text 'See Variables'
command proc{
- showVars($radio_demo, ['size', size], ['color', color])
+ showVars(base_frame, ['size', size], ['color', color])
}
}.pack('side'=>'left', 'expand'=>'yes')
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# frame
-f_left = TkFrame.new($radio_demo)
-f_right = TkFrame.new($radio_demo)
+f_left = TkFrame.new(base_frame)
+f_right = TkFrame.new(base_frame)
f_left.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'.5c', 'pady'=>'.5c')
f_right.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'.5c', 'pady'=>'.5c')
diff --git a/ext/tk/sample/demos-en/radio2.rb b/ext/tk/sample/demos-en/radio2.rb
index 2b56ccc9b1..6c02aef0cf 100644
--- a/ext/tk/sample/demos-en/radio2.rb
+++ b/ext/tk/sample/demos-en/radio2.rb
@@ -19,8 +19,10 @@ $radio2_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($radio2_demo).pack(:fill=>:both, :expand=>true)
+
# label
-msg = TkLabel.new($radio2_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '5i'
justify 'left'
@@ -34,7 +36,7 @@ color = TkVariable.new
align = TkVariable.new
# frame
-TkFrame.new($radio2_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -53,18 +55,18 @@ TkFrame.new($radio2_demo) {|frame|
TkButton.new(frame) {
text 'See Variables'
command proc{
- showVars($radio2_demo,
+ showVars(base_frame,
['size', size], ['color', color], ['compound', align])
}
}.pack('side'=>'left', 'expand'=>'yes')
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# frame
-f_left = TkLabelFrame.new($radio2_demo, 'text'=>'Point Size',
+f_left = TkLabelFrame.new(base_frame, 'text'=>'Point Size',
'pady'=>2, 'padx'=>2)
-f_mid = TkLabelFrame.new($radio2_demo, 'text'=>'Color',
+f_mid = TkLabelFrame.new(base_frame, 'text'=>'Color',
'pady'=>2, 'padx'=>2)
-f_right = TkLabelFrame.new($radio2_demo, 'text'=>'Alignment',
+f_right = TkLabelFrame.new(base_frame, 'text'=>'Alignment',
'pady'=>2, 'padx'=>2)
f_left.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'.5c', 'pady'=>'.5c')
f_mid.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'.5c', 'pady'=>'.5c')
@@ -90,7 +92,8 @@ f_right.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'.5c', 'pady'=>'.5c')
}.pack('side'=>'top', 'pady'=>2, 'fill'=>'x')
}
-label = TkLabel.new(f_right, 'text'=>'Label', 'bitmap'=>'questhead',
+# label = TkLabel.new(f_right, 'text'=>'Label', 'bitmap'=>'questhead',
+label = Tk::Label.new(f_right, 'text'=>'Label', 'bitmap'=>'questhead',
'compound'=>'left')
label.configure('width'=>TkWinfo.reqwidth(label), 'compound'=>'top')
label.height(TkWinfo.reqheight(label))
diff --git a/ext/tk/sample/demos-en/radio3.rb b/ext/tk/sample/demos-en/radio3.rb
index 70c4abb3b5..9c9d75ef4a 100644
--- a/ext/tk/sample/demos-en/radio3.rb
+++ b/ext/tk/sample/demos-en/radio3.rb
@@ -19,8 +19,10 @@ $radio3_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($radio3_demo).pack(:fill=>:both, :expand=>true)
+
# label
-msg = TkLabel.new($radio3_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '5i'
justify 'left'
@@ -34,14 +36,14 @@ color = TkVariable.new
align = TkVariable.new
# frame
-TkFrame.new($radio3_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkGrid(TkFrame.new(frame, :height=>2, :relief=>:sunken, :bd=>2),
:columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
TkGrid('x',
TkButton.new(frame, :text=>'See Variables',
:image=>$image['view'], :compound=>:left,
:command=>proc{
- showVars($radio3_demo, ['size', size],
+ showVars(base_frame, ['size', size],
['color', color], ['compound', align])
}),
TkButton.new(frame, :text=>'See Code',
@@ -61,17 +63,17 @@ TkFrame.new($radio3_demo) {|frame|
}
# frame
-f_left = TkLabelFrame.new($radio3_demo, 'text'=>'Point Size',
+f_left = TkLabelFrame.new(base_frame, 'text'=>'Point Size',
'pady'=>2, 'padx'=>2)
-f_mid = TkLabelFrame.new($radio3_demo, 'text'=>'Color',
+f_mid = TkLabelFrame.new(base_frame, 'text'=>'Color',
'pady'=>2, 'padx'=>2)
-f_right = TkLabelFrame.new($radio3_demo, 'text'=>'Alignment',
+f_right = TkLabelFrame.new(base_frame, 'text'=>'Alignment',
'pady'=>2, 'padx'=>2)
f_left .grid('column'=>0, 'row'=>1, 'pady'=>'.5c', 'padx'=>'.5c', 'rowspan'=>2)
f_mid .grid('column'=>1, 'row'=>1, 'pady'=>'.5c', 'padx'=>'.5c', 'rowspan'=>2)
f_right.grid('column'=>2, 'row'=>1, 'pady'=>'.5c', 'padx'=>'.5c')
-TkButton.new($radio3_demo, 'text'=>'Tristate',
+TkButton.new(base_frame, 'text'=>'Tristate',
'command'=>proc{size.value = 'multi'; color.value = 'multi'}){
grid('column'=>2, 'row'=>2, 'pady'=>'.5c', 'padx'=>'.5c')
}
@@ -99,7 +101,8 @@ TkButton.new($radio3_demo, 'text'=>'Tristate',
}.pack('side'=>'top', 'pady'=>2, 'fill'=>'x')
}
-label = TkLabel.new(f_right, 'text'=>'Label', 'bitmap'=>'questhead',
+# label = TkLabel.new(f_right, 'text'=>'Label', 'bitmap'=>'questhead',
+label = Tk::Label.new(f_right, 'text'=>'Label', 'bitmap'=>'questhead',
'compound'=>'left')
label.configure('width'=>TkWinfo.reqwidth(label), 'compound'=>'top')
label.height(TkWinfo.reqheight(label))
diff --git a/ext/tk/sample/demos-en/rolodex-j b/ext/tk/sample/demos-en/rolodex-j
deleted file mode 100644
index 27e2bc9da0..0000000000
--- a/ext/tk/sample/demos-en/rolodex-j
+++ /dev/null
@@ -1,323 +0,0 @@
-#!/usr/bin/env ruby
-#
-# rolodex --
-# ¤³¤Î¥¹¥¯¥ê¥×¥È¤Ï Tom LaStrange ¤Î rolodex ¤Î°ìÉô¤Ç¤¹¡£
-#
-# Copyright (C) 1998 by Takaaki Tateishi <ttate@jaist.ac.jp>
-# Time-stamp: "03/08/02 14:02:04 nagai"
-#
-
-require "tk"
-
-Tk.encoding = "euc-jp"
-$font = TkFont.new('k14')
-
-def show_help(topic,x=0,y=0)
- if( topic.is_a?(TkWindow) )
- w = TkWinfo.containing(x,y)
- if( w.is_a?(TkWindow) )
- if( TkWinfo.exist?(w) )
- topic = w
- end
- end
- end
-
- if( $helpTopics.include?(topic) )
- msg = $helpTopics[topic]
- else
- msg = "¤³¤Î¥È¥Ô¥Ã¥¯¤Ë¤Ä¤¤¤Æ¤Î¥Ø¥ë¥×¤Ï¤Þ¤À»ÈÍѤǤ­¤Þ¤»¤ó"
- end
- TkDialog.new("title"=>"Rolodex Help",
- "message"=>"¡Ö#{topic}¡×\n\n#{msg}",
- "font"=>$font,
- "default_button"=>0,
- "buttons"=>["OK"])
-end
-
-def fillCard
- clearAction
- $root.frame.entry[1].insert(0, "ΩÀÐ ¹§¾´")
- $root.frame.entry[2].insert(0, "923-1292 ÀÐÀ")
- $root.frame.entry[3].insert(0, "ä¸ýÄ® °°Âæ 1-1")
- $root.frame.entry[4].insert(0, "ËÌΦÀèü²Ê³Øµ»½ÑÂç³Ø±¡Âç³Ø")
- $root.frame.entry[5].insert(0,"private")
- $root.frame.entry[6].insert(0,"***-***-****")
- $root.frame.entry[7].insert(0,"***-***-****")
-end
-
-def addAction
- for i in 1..7
- STDERR.print format("%-12s %s\n",
- RolodexFrame::LABEL[i],
- $root.frame.entry[i].value)
- end
-end
-
-def clearAction
- for i in 1..7
- $root.frame.entry[i].delete(0,"end")
- end
-end
-
-def fileAction
- TkDialog.new("title"=>"File Selection",
- "message"=>"¤³¤ì¤Ï¥Õ¥¡¥¤¥ëÁªÂò¥À¥¤¥¢¥í¥°¤Î¥À¥ß¡¼¤Ç¤¹¡£\n",
- "font"=>$font,
- "default_button"=>0,
- "buttons"=>["OK"])
- STDERR.print "dummy file name\n"
-end
-
-def deleteAction
- result = TkDialog.new("title"=>"Confirm Action",
- "message"=>"¤è¤í¤·¤¤¤Ç¤¹¤«¡©",
- "font"=>$font,
- "default_button"=>0,
- "buttons"=>["¥­¥ã¥ó¥»¥ë"])
- if( result.value == 0 )
- clearAction
- end
-end
-
-
-class RolodexFrame < TkFrame
- attr_reader :entry, :label
-
- LABEL = ["","̾Á°:","½»½ê","","","ÅÅÏÃ(¼«Âð):","ÅÅÏÃ(²ñ¼Ò):","Fax:"]
-
- def initialize(parent=nil,keys=nil)
- super(parent,keys)
- self["relief"] = "flat"
- @i = []
- @label = []
- @entry = []
- for i in 1..7
- @i[i] = TkFrame.new(self)
- @i[i].pack("side"=>"top",
- "pady"=>2,
- "anchor"=>"e")
- @label[i] = TkLabel.new(@i[i],
- "text"=>LABEL[i],
- "anchor"=>"e",
- "font" => $font)
- @entry[i] = TkEntry.new(@i[i],
- "width"=>30,
- "relief"=>"sunken",
- "font" => $font)
- @entry[i].pack("side"=>"right")
- @label[i].pack("side"=>"right")
- end
- end
-end
-
-class RolodexButtons < TkFrame
- attr_reader :clear, :add, :search, :delete
-
- def initialize(parent,keys=nil)
- super(parent,keys)
- @clear = TkButton.new(self,
- "text" => "¥¯¥ê¥¢¡¼",
- "font" => $font)
- @add = TkButton.new(self,
- "text" => "ÄɲÃ",
- "font" => $font)
- @search = TkButton.new(self,
- "text" => "¸¡º÷",
- "font" => $font)
- @delete = TkButton.new(self,
- "text" => "¾Ãµî",
- "font" => $font)
- for w in [@clear,@add,@search,@delete]
- w.pack("side"=>"left", "padx"=>2)
- end
- end
-end
-
-class RolodexMenuFrame < TkFrame
- attr_reader :file_menu, :help_menu, :file, :help
-
- def initialize(parent,keys=nil)
- super(parent,keys)
- configure("relief"=>"raised",
- "borderwidth"=>1)
-
- @file = TkMenubutton.new(self,
- "text"=> "¥Õ¥¡¥¤¥ë",
- "font"=> $font,
- "underline"=>0)
- @file_menu = TkMenu.new(@file)
- @file_menu.add("command",
- "label" => "ÆÉ¤ß¹þ¤ß ...",
- "font" => $font,
- "command" => proc{fileAction},
- "underline" => 0)
- @file_menu.add("command",
- "label" => "½ªÎ»",
- "font" => $font,
- "command" => proc{$root.destroy},
- "underline" => 0)
- @file.menu(@file_menu)
- @file.pack("side"=>"left")
-
- @help = TkMenubutton.new(self,
- "text"=> "¥Ø¥ë¥×",
- "font"=> $font,
- "underline"=>0)
- @help_menu = TkMenu.new(@help)
- @help_menu.add("command",
- "label"=> "¥³¥ó¥Æ¥­¥¹¥È¤Ë¤Ä¤¤¤Æ",
- "font" => $font,
- "command"=>proc{show_help("¥³¥ó¥Æ¥­¥¹¥È")},
- "underline"=>3)
- @help_menu.add("command",
- "label"=> "¥Ø¥ë¥×¤Ë¤Ä¤¤¤Æ",
- "font" => $font,
- "command"=>proc{show_help("¥Ø¥ë¥×")},
- "underline"=>3)
- @help_menu.add("command",
- "label"=> "¥¦¥£¥ó¥É¥¦¤Ë¤Ä¤¤¤Æ",
- "font" => $font,
- "command"=>proc{show_help("¥¦¥£¥ó¥É¥¦")},
- "underline"=>3)
- @help_menu.add("command",
- "label"=> "¥­¡¼Áàºî¤Ë¤Ä¤¤¤Æ",
- "font" => $font,
- "command"=>proc{show_help("¥­¡¼Áàºî")},
- "underline"=>3)
- @help_menu.add("command",
- "label"=> "¥Ð¡¼¥¸¥ç¥ó¾ðÊó",
- "font" => $font,
- "command"=>proc{show_help("¥Ð¡¼¥¸¥ç¥ó¾ðÊó")},
- "underline"=>3)
- @help.menu(@help_menu)
- @help.pack("side"=>"right")
- end
-end
-
-class Rolodex < TkRoot
- attr_reader :frame, :buttons, :menu
-
- def initialize(*args)
- super(*args)
- @frame = RolodexFrame.new(self)
- @frame.pack("side"=>"top",
- "fill"=>"y",
- "anchor"=>"center")
- @buttons = RolodexButtons.new(self)
- @buttons.pack("side"=>"bottom",
- "pady"=>2,
- "anchor"=>"center")
- @menu = RolodexMenuFrame.new(self)
- @menu.pack("before"=>@frame,
- "side"=>"top",
- "fill"=>"x")
- end
-end
-
-$root = Rolodex.new
-
-$root.buttons.delete.configure("command"=>proc{deleteAction})
-$root.buttons.add.configure("command"=>proc{addAction})
-$root.buttons.clear.configure("command"=>proc{clearAction})
-$root.buttons.search.configure("command"=>proc{addAction; fillCard})
-
-$root.buttons.clear.configure("text"=> "¥¯¥ê¥¢¡¼ Ctrl+C", "font" => $font)
-$root.bind("Control-c",proc{clearAction})
-
-$root.buttons.add.configure("text"=> "Äɲà Ctrl+A", "font" => $font)
-$root.bind("Control-a",proc{addAction})
-
-$root.buttons.search.configure("text"=> "¸¡º÷ Ctrl+S", "font" => $font)
-$root.bind("Control-s",proc{addAction; fillCard})
-
-$root.buttons.delete.configure("text"=> "¾Ãµî Ctrl+D", "font" => $font)
-$root.bind("Control-d",proc{deleteAction})
-
-$root.menu.file_menu.entryconfigure(1, "accel"=>"Ctrl+F")
-$root.bind("Control-f",proc{fileAction})
-
-$root.menu.file_menu.entryconfigure(2, "accel"=>"Ctrl+Q")
-$root.bind("Control-q",proc{$root.destroy})
-
-$root.frame.entry[1].focus
-
-$root.bind("Any-F1",
- proc{|event| show_help(event.widget, event.x_root, event.y_root)})
-$root.bind("Any-Help",
- proc{|event| show_help(event.widget, event.x_root, event.y_root)})
-
-
-$helpTopics = {}
-
-$helpTopics[$root.menu.file] = <<EOF
-¤³¤ì¤Ï¡Ö¥Õ¥¡¥¤¥ë¡×¥á¥Ë¥å¡¼¤Ç¤¹¡£¡ÖÆÉ¤ß¹þ¤ß¡×¤ä¡Ö½ªÎ»¡×¤Ê¤É¤ò
-¹Ô¤Ê¤¦¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£
-EOF
-
-$helpTopics[$root.menu.file_menu.index(0)] = <<EOF
-¥Õ¥¡¥¤¥ë¤ÎÆÉ¤ß¹þ¤ß¤ò¹Ô¤Ê¤¦¤È¤­¤Ë»È¤¤¤Þ¤¹¡£
-EOF
-
-$helpTopics[$root.menu.file_menu.index(1)] = <<EOF
-¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¤ò½ªÎ»¤¹¤ë¤È¤­¤Ë»È¤¤¤Þ¤¹¡£
-EOF
-
-$helpTopics[$root.frame.entry[1]] = <<EOF
-̾Á°¤òµ­Æþ¤¹¤ë¥¨¥ó¥È¥ê¤Ç¤¹¡£
-EOF
-
-$helpTopics[$root.frame.entry[2]] = <<EOF
-½»½ê¤òµ­Æþ¤¹¤ë¥¨¥ó¥È¥ê¤Ç¤¹¡£
-EOF
-
-$helpTopics[$root.frame.entry[3]] = <<EOF
-½»½ê¤òµ­Æþ¤¹¤ë¥¨¥ó¥È¥ê¤Ç¤¹¡£
-EOF
-
-$helpTopics[$root.frame.entry[4]] = <<EOF
-½»½ê¤òµ­Æþ¤¹¤ë¥¨¥ó¥È¥ê¤Ç¤¹¡£
-EOF
-
-$helpTopics[$root.frame.entry[5]] = <<EOF
-¼«Âð¤ÎÅÅÏÃÈÖ¹æ¤òµ­Æþ¤¹¤ë¥¨¥ó¥È¥ê¤Ç¤¹¡£¸ø³«\
-¤·¤¿¤¯¤Ê¤¤¤È¤­¤Ï private ¤Èµ­Æþ¤·¤Þ¤¹¡£
-EOF
-
-$helpTopics[$root.frame.entry[6]] = <<EOF
-²ñ¼Ò¤ÎÅÅÏÃÈÖ¹æ¤òµ­Æþ¤¹¤ë¥¨¥ó¥È¥ê¤Ç¤¹¡£
-EOF
-
-$helpTopics[$root.frame.entry[7]] = <<EOF
-FAXÈÖ¹æ¤òµ­Æþ¤¹¤ë¥¨¥ó¥È¥ê¤Ç¤¹¡£
-EOF
-
-$helpTopics["¥³¥ó¥Æ¥­¥¹¥È"] = <<EOF
-Ruby/Tk¤Ç¤Ïgrab¤Îµ¡¹½¤¬¤Ê¤¤¤¿¤á¤³¤Î¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¤Ç¤Ï\
-¥³¥ó¥Æ¥­¥¹¥È¥Ø¥ë¥×¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£
-¤·¤«¤·Æ±¤¸¤è¤¦¤Ê¸ú²Ì¤òbind¤È¥Þ¥¦¥¹¤Î°ÌÃÖ¤ÎWedget¤òÃΤë\
-¤³¤È¤ÇÆÀ¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£
-EOF
-
-$helpTopics["¥Ø¥ë¥×"] = <<EOF
-¥Þ¥¦¥¹¤ò¥¦¥£¥ó¥É¥¦¤Ë¤¢¤ï¤»¤ÆF1¥­¡¼¤ò²¡¤¹¤³¤È¤Ë¤è¤Ã¤Æ\
-¤½¤Î¥Ø¥ë¥×¤ò¸«¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£
-EOF
-
-$helpTopics["¥¦¥£¥ó¥É¥¦"] = <<EOF
-¤³¤Î¥¦¥£¥ó¥É¥¦¤Ï¥À¥ß¡¼¤Ç¤¹¡£
-EOF
-
-$helpTopics["¥­¡¼Áàºî"] = <<EOF
-Ctrl+A: ÄɲÃ
-Ctrl+C: ¥¯¥ê¥¢¡¼
-Ctrl+D: ¾Ãµî
-Ctrl+F: ¥Õ¥¡¥¤¥ëÁªÂò
-Ctrl+Q: ½ªÎ»
-Ctrl+S: ¸¡º÷
-EOF
-
-$helpTopics["¥Ð¡¼¥¸¥ç¥ó¾ðÊó"] = <<EOF
-¥Ð¡¼¥¸¥ç¥ó¤Ï 1.0.1e ¤Ç¤¹¡£
-EOF
-
-Tk.mainloop
diff --git a/ext/tk/sample/demos-en/ruler.rb b/ext/tk/sample/demos-en/ruler.rb
index 4299d57b4f..26cd4f3b1c 100644
--- a/ext/tk/sample/demos-en/ruler.rb
+++ b/ext/tk/sample/demos-en/ruler.rb
@@ -32,14 +32,16 @@ $ruler_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($ruler_demo).pack(:fill=>:both, :expand=>true)
+
# label
-TkLabel.new($ruler_demo, 'font'=>$font, 'wraplength'=>'5i', 'justify'=>'left',
+TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'5i', 'justify'=>'left',
'text'=>"This canvas widget shows a mock-up of a ruler. You can create tab stops by dragging them out of the well to the right of the ruler. You can also drag existing tab stops. If you drag a tab stop far enough up or down so that it turns dim, it will be deleted when you release the mouse button."){
pack('side'=>'top')
}
# frame
-$ruler_buttons = TkFrame.new($ruler_demo) {|frame|
+$ruler_buttons = TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -57,7 +59,7 @@ $ruler_buttons = TkFrame.new($ruler_demo) {|frame|
$ruler_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# canvas
-$ruler_canvas = TkCanvas.new($ruler_demo, 'width'=>'14.8c', 'height'=>'2.5c')
+$ruler_canvas = TkCanvas.new(base_frame, 'width'=>'14.8c', 'height'=>'2.5c')
$ruler_canvas.pack('side'=>'top', 'fill'=>'x')
#
diff --git a/ext/tk/sample/demos-en/sayings.rb b/ext/tk/sample/demos-en/sayings.rb
index cef0f4ecf4..06ec7c1e75 100644
--- a/ext/tk/sample/demos-en/sayings.rb
+++ b/ext/tk/sample/demos-en/sayings.rb
@@ -20,8 +20,10 @@ $sayings_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($sayings_demo).pack(:fill=>:both, :expand=>true)
+
# label
-msg = TkLabel.new($sayings_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -30,7 +32,7 @@ msg = TkLabel.new($sayings_demo) {
msg.pack('side'=>'top')
# frame
-TkFrame.new($sayings_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -49,7 +51,7 @@ TkFrame.new($sayings_demo) {|frame|
# frame
sayings_lbox = nil
-TkFrame.new($sayings_demo, 'borderwidth'=>10) {|w|
+TkFrame.new(base_frame, 'borderwidth'=>10) {|w|
sv = TkScrollbar.new(w)
sh = TkScrollbar.new(w, 'orient'=>'horizontal')
sayings_lbox = TkListbox.new(w) {
diff --git a/ext/tk/sample/demos-en/search.rb b/ext/tk/sample/demos-en/search.rb
index 3d3b4aecc8..e1fc565e9d 100644
--- a/ext/tk/sample/demos-en/search.rb
+++ b/ext/tk/sample/demos-en/search.rb
@@ -79,8 +79,10 @@ $search_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($search_demo).pack(:fill=>:both, :expand=>true)
+
# frame
-$search_buttons = TkFrame.new($search_demo) {|frame|
+$search_buttons = TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -98,7 +100,7 @@ $search_buttons = TkFrame.new($search_demo) {|frame|
$search_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# frame
-TkFrame.new($search_demo) {|f|
+TkFrame.new(base_frame) {|f|
TkLabel.new(f, 'text'=>'File name:',
'width'=>13, 'anchor'=>'w').pack('side'=>'left')
$search_fileName = TkVariable.new
@@ -115,7 +117,7 @@ TkFrame.new($search_demo) {|f|
.pack('side'=>'left', 'pady'=>5, 'padx'=>10)
}.pack('side'=>'top', 'fill'=>'x')
-TkFrame.new($search_demo) {|f|
+TkFrame.new(base_frame) {|f|
TkLabel.new(f, 'text'=>'Search string:',
'width'=>13, 'anchor'=>'w').pack('side'=>'left')
$search_searchString = TkVariable.new
@@ -133,14 +135,14 @@ TkFrame.new($search_demo) {|f|
}
}.pack('side'=>'top', 'fill'=>'x')
-$search_text = TkText.new($search_demo, 'setgrid'=>true, 'wrap'=>'word') {|t|
+$search_text = TkText.new(base_frame, 'setgrid'=>true, 'wrap'=>'word') {|t|
$search_Tag = TkTextTag.new(t)
- TkScrollbar.new($search_demo, 'command'=>proc{|*args| t.yview(*args)}) {|sc|
+ TkScrollbar.new(base_frame, 'command'=>proc{|*args| t.yview(*args)}) {|sc|
t.yscrollcommand(proc{|first,last| sc.set first,last})
pack('side'=>'right', 'fill'=>'y')
}
pack('expand'=>'yes', 'fill'=>'both')
-}
+}
# Set up display styles for text highlighting.
@@ -173,8 +175,13 @@ type a string in the lower entry and type <Return> or click on \
\"Load File\". This will cause all of the instances of the string to \
be tagged with the tag \"search\", and it will arrange for the tag\'s \
display attributes to change to make all of the strings blink.")
+$search_text.insert('end', "\
+The current directory to load a file is \"#{Dir.pwd}\".\
+")
$search_text.set_insert '0.0'
$search_fileName.value = ''
$search_searchString.value = ''
+$search_text.width = 60
+$search_text.height = 20
diff --git a/ext/tk/sample/demos-en/spin.rb b/ext/tk/sample/demos-en/spin.rb
index 58616b1e02..c2a3a8949b 100644
--- a/ext/tk/sample/demos-en/spin.rb
+++ b/ext/tk/sample/demos-en/spin.rb
@@ -15,7 +15,9 @@ $spin_demo = TkToplevel.new {|w|
positionWindow(w)
}
-TkLabel.new($spin_demo,
+base_frame = TkFrame.new($spin_demo).pack(:fill=>:both, :expand=>true)
+
+TkLabel.new(base_frame,
:font=>$font, :wraplength=>'5i', :justify=>:left,
:text=><<EOL).pack(:side=>:top)
Three different spin-boxes are displayed below. \
@@ -34,7 +36,7 @@ this demo doesn't work. Please use later version of Tk \
which supports a 'spinbox' widget.
EOL
-TkFrame.new($spin_demo){|f|
+TkFrame.new(base_frame){|f|
pack(:side=>:bottom, :fill=>:x, :pady=>'2m')
TkButton.new(f, :text=>'Dismiss', :width=>15, :command=>proc{
@@ -53,11 +55,11 @@ australianCities = [
]
[
- TkSpinbox.new($spin_demo, :from=>1, :to=>10, :width=>10, :validate=>:key,
+ TkSpinbox.new(base_frame, :from=>1, :to=>10, :width=>10, :validate=>:key,
:validatecommand=>[
proc{|s| s == '' || /^[+-]?\d+$/ =~ s }, '%P'
]),
- TkSpinbox.new($spin_demo, :from=>0, :to=>3, :increment=>0.5,
+ TkSpinbox.new(base_frame, :from=>0, :to=>3, :increment=>0.5,
:format=>'%05.2f', :width=>10),
- TkSpinbox.new($spin_demo, :values=>australianCities, :width=>10)
+ TkSpinbox.new(base_frame, :values=>australianCities, :width=>10)
].each{|sbox| sbox.pack(:side=>:top, :pady=>5, :padx=>10)}
diff --git a/ext/tk/sample/demos-en/states.rb b/ext/tk/sample/demos-en/states.rb
index d38c1245af..add0e84800 100644
--- a/ext/tk/sample/demos-en/states.rb
+++ b/ext/tk/sample/demos-en/states.rb
@@ -19,8 +19,10 @@ $states_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($states_demo).pack(:fill=>:both, :expand=>true)
+
# label
-msg = TkLabel.new($states_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -29,7 +31,7 @@ msg = TkLabel.new($states_demo) {
msg.pack('side'=>'top')
# frame
-TkFrame.new($states_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -48,7 +50,7 @@ TkFrame.new($states_demo) {|frame|
# frame
states_lbox = nil
-TkFrame.new($states_demo, 'borderwidth'=>'.5c') {|w|
+TkFrame.new(base_frame, 'borderwidth'=>'.5c') {|w|
s = TkScrollbar.new(w)
states_lbox = TkListbox.new(w) {
setgrid 1
diff --git a/ext/tk/sample/demos-en/style.rb b/ext/tk/sample/demos-en/style.rb
index 5ed11aa459..c2fed23926 100644
--- a/ext/tk/sample/demos-en/style.rb
+++ b/ext/tk/sample/demos-en/style.rb
@@ -19,8 +19,10 @@ $style_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($style_demo).pack(:fill=>:both, :expand=>true)
+
# frame
-TkFrame.new($style_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -37,13 +39,14 @@ TkFrame.new($style_demo) {|frame|
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# text
-TkText.new($style_demo){|t|
+txt = TkText.new(base_frame){|t|
#
setgrid 'true'
- width 70
- height 32
+ #width 70
+ #height 32
wrap 'word'
- TkScrollbar.new($style_demo) {|s|
+ font $font
+ TkScrollbar.new(base_frame) {|s|
pack('side'=>'right', 'fill'=>'y')
command proc{|*args| t.yview(*args)}
t.yscrollcommand proc{|first,last| s.set first,last}
@@ -51,11 +54,20 @@ TkText.new($style_demo){|t|
pack('expand'=>'yes', 'fill'=>'both')
#
- style_tag_bold = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-O-Normal--*-120-*-*-*-*-*-*')
- style_tag_big = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-R-Normal--*-140-*-*-*-*-*-*', 'kanjifont'=>$msg_kanji_font)
+ family = 'Courier'
+
+ if $tk_version =~ /^4.*/
+ style_tag_bold = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-O-Normal--*-120-*-*-*-*-*-*')
+ style_tag_big = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-R-Normal--*-140-*-*-*-*-*-*', 'kanjifont'=>$msg_kanji_font)
style_tag_verybig = TkTextTag.new(t, 'font'=>'-*-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*')
-# style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*', 'kanjifont'=>$kanji_font)
+ # style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*', 'kanjifont'=>$kanji_font)
style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*')
+ else
+ style_tag_bold = TkTextTag.new(t, 'font'=>[family, 12, :bold, :italic])
+ style_tag_big = TkTextTag.new(t, 'font'=>[family, 14, :bold])
+ style_tag_verybig = TkTextTag.new(t, 'font'=>['Helvetica', 24, :bold])
+ style_tag_small = TkTextTag.new(t, 'font'=>'Times 8 bold')
+ end
###
# case($tk_version)
# when /^4.*/
@@ -109,8 +121,13 @@ TkText.new($style_demo){|t|
style_tag_overstrike = TkTextTag.new(t, 'overstrike'=>'on')
style_tag_right = TkTextTag.new(t, 'justify'=>'right')
style_tag_center = TkTextTag.new(t, 'justify'=>'center')
- style_tag_super = TkTextTag.new(t, 'offset'=>'4p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*')
- style_tag_sub = TkTextTag.new(t, 'offset'=>'-2p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*')
+ if $tk_version =~ /^4.*/
+ style_tag_super = TkTextTag.new(t, 'offset'=>'4p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*')
+ style_tag_sub = TkTextTag.new(t, 'offset'=>'-2p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*')
+ else
+ style_tag_super = TkTextTag.new(t, 'offset'=>'4p', 'font'=>[family, 10])
+ style_tag_sub = TkTextTag.new(t, 'offset'=>'-2p', 'font'=>[family, 10])
+ end
style_tag_margins = TkTextTag.new(t, 'lmargin1'=>'12m', 'lmargin2'=>'6m',
'rmargin'=>'10m')
style_tag_spacing = TkTextTag.new(t, 'spacing1'=>'10p', 'spacing2'=>'2p',
@@ -132,7 +149,8 @@ available display styles are:
insert('end', " You can choose any X font, ")
insert('end', "large", style_tag_verybig)
insert('end', " or ")
- insert('end', "small.\n")
+ insert('end', "small", style_tag_small)
+ insert('end', ".\n")
insert('end', "\n2. Color.", style_tag_big)
insert('end', " You can change either the ")
insert('end', "background", style_tag_color1)
@@ -209,3 +227,5 @@ available display styles are:
}
+txt.width 70
+txt.height 32
diff --git a/ext/tk/sample/demos-en/text.rb b/ext/tk/sample/demos-en/text.rb
index 4bb4b6bc7e..3ce8cdfda8 100644
--- a/ext/tk/sample/demos-en/text.rb
+++ b/ext/tk/sample/demos-en/text.rb
@@ -19,6 +19,8 @@ $text_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($text_demo).pack(:fill=>:both, :expand=>true)
+
# version check
if ((Tk::TK_VERSION.split('.').collect{|n| n.to_i} <=> [8,4]) < 0)
undo_support = false
@@ -27,7 +29,7 @@ else
end
# frame
-TkFrame.new($text_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -44,7 +46,7 @@ TkFrame.new($text_demo) {|frame|
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# text
-TkText.new($text_demo){|t|
+TkText.new(base_frame){|t|
relief 'sunken'
bd 2
setgrid 1
@@ -53,7 +55,7 @@ TkText.new($text_demo){|t|
undo true
autoseparators true
end
- TkScrollbar.new($text_demo) {|s|
+ TkScrollbar.new(base_frame) {|s|
pack('side'=>'right', 'fill'=>'y')
command proc{|*args| t.yview(*args)}
t.yscrollcommand proc{|first,last| s.set first,last}
diff --git a/ext/tk/sample/demos-en/textpeer.rb b/ext/tk/sample/demos-en/textpeer.rb
new file mode 100644
index 0000000000..c25ce15e5c
--- /dev/null
+++ b/ext/tk/sample/demos-en/textpeer.rb
@@ -0,0 +1,76 @@
+#
+# text widget peering demo (called by 'widget')
+#
+# based on Tcl/Tk8.5.0 widget demos
+
+if defined?($textpeer_demo) && $textpeer_demo
+ $textpeer_demo.destroy
+ $textpeer_demo = nil
+end
+
+# demo toplevel widget
+$textpeer_demo = TkToplevel.new {|w|
+ title("Text Wdget Peering Demonstration")
+ iconname("textpeer")
+ positionWindow(w)
+}
+
+base_frame = TkFrame.new($textpeer_demo).pack(:fill=>:both, :expand=>true)
+
+count = [0]
+
+## Define a widget that we peer from; it won't ever actually be shown though
+first = TkText.new(base_frame, :widgetname=>"text#{count[0] += 1}")
+first.insert :end,"This is a coupled pair of text widgets; they are peers to "
+first.insert :end,"each other. They have the same underlying data model, but "
+first.insert :end,"can show different locations, have different current edit "
+first.insert :end,"locations, and have different selections. You can also "
+first.insert :end,"create additional peers of any of these text widgets using "
+first.insert :end,"the Make Peer button beside the text widget to clone, and "
+first.insert :end,"delete a particular peer widget using the Delete Peer "
+first.insert :end,"button."
+
+Tk.update_idletasks ## for 'first' widget
+
+## Procedures to make and kill clones; most of this is just so that the demo
+## looks nice...
+def makeClone(count, win, txt)
+ cnt = (count[0] += 1)
+ peer = TkText::Peer.new(txt, win, :widgetname=>"text#{cnt}")
+ sbar = TkScrollbar.new(win, :widgetname=>"sb#{cnt}")
+ peer.yscrollbar sbar
+ b1 = TkButton.new(win, :widgetname=>"clone#{cnt}", :text=>'Make Peer',
+ :command=>proc{makeClone(count, win, peer)})
+ b2 = TkButton.new(win, :widgetname=>"kill#{cnt}", :text=>'Delete Peer',
+ :command=>proc{killClone(win, cnt)})
+ row = cnt * 2
+ TkGrid.configure(peer, sbar, b1, :sticky=>'nsew', :row=>row)
+ TkGrid.configure('^', '^', b2, :sticky=>'nsew', :row=>(row+=1))
+ TkGrid.configure(b1, b2, :sticky=>'new')
+ TkGrid.rowconfigure(win, b2, :weight=>1)
+end
+
+def killClone(win, cnt)
+ Tk.destroy("#{win.path}.text#{cnt}", "#{win.path}.sb#{cnt}",
+ "#{win.path}.clone#{cnt}", "#{win.path}.kill#{cnt}")
+end
+
+## Now set up the GUI
+makeClone(count, base_frame, first)
+makeClone(count, base_frame, first)
+first.destroy
+
+## See Code / Dismiss buttons
+TkFrame.new(base_frame){|f|
+ TkButton.new(f, :text=>'Dismiss', :width=>15, :command=>proc{
+ $textpeer_demo.destroy
+ $textpeer_demo = nil
+ }).pack(:side=>:left, :expand=>true)
+
+ TkButton.new(f, :text=>'See Code', :width=>15, :command=>proc{
+ showCode 'textpeer'
+ }).pack(:side=>:left, :expand=>true)
+
+ TkGrid.configure(f, '-', '-', :sticky=>'ew', :row=>5000)
+}
+TkGrid.columnconfigure(base_frame, 0, :weight=>1)
diff --git a/ext/tk/sample/demos-en/toolbar.rb b/ext/tk/sample/demos-en/toolbar.rb
new file mode 100644
index 0000000000..5cf863717b
--- /dev/null
+++ b/ext/tk/sample/demos-en/toolbar.rb
@@ -0,0 +1,130 @@
+# toolbar.rb --
+#
+# This demonstration script creates a toolbar that can be torn off.
+#
+# based on "Id: toolbar.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp"
+
+if defined?($toolbar_demo) && $toolbar_demo
+ $toolbar_demo.destroy
+ $toolbar_demo = nil
+end
+
+$toolbar_demo = TkToplevel.new {|w|
+ title("Ttk Menu Buttons")
+ iconname("toolbar")
+ positionWindow(w)
+}
+
+base_frame = Ttk::Frame.new($toolbar_demo).pack(:fill=>:both, :expand=>true)
+
+if Tk.windowingsystem != 'aqua'
+ msg = Ttk::Label.new(base_frame, :wraplength=>'4i',
+ :text=>Tk::UTF8_String.new(<<EOL))
+This is a demonstration of how to do \
+a toolbar that is styled correctly \
+and which can be torn off (this feature reqrires Tcl/Tk8.5). \
+The buttons are configured to be \\u201Ctoolbar style\\u201D buttons by \
+telling them that they are to use the Toolbutton style. At the left \
+end of the toolbar is a simple marker that the cursor changes to a \
+movement icon over; drag that away from the toolbar to tear off the \
+whole toolbar into a separate toplevel widget. When the dragged-off \
+toolbar is no longer needed, just close it like any normal toplevel \
+and it will reattach to the window it was torn off from.
+EOL
+else
+ msg = Ttk::Label.new(base_frame, :wraplength=>'4i',
+ :text=>Tk::UTF8_String.new(<<EOL))
+This is a demonstration of how to do \
+a toolbar that is styled correctly. The buttons are configured to \
+be \\u201Ctoolbar style\\u201D buttons by telling them that they are \
+to use the Toolbutton style.
+EOL
+end
+
+## Set up the toolbar hull
+tbar_base = Tk::Frame.new(base_frame, # Must be a starndard Tk frame!
+ :widgetname=>'toolbar') # for window title
+sep = Ttk::Separator.new(base_frame)
+to_base = Ttk::Frame.new(tbar_base, :cursor=>'fleur')
+if Tk.windowingsystem != 'aqua'
+ to = Ttk::Separator.new(to_base, :orient=>:vertical)
+ to2 = Ttk::Separator.new(to_base, :orient=>:vertical)
+ to.pack(:fill=>:y, :expand=>true, :padx=>2, :side=>:left)
+ to2.pack(:fill=>:y, :expand=>true, :side=>:left)
+end
+
+contents = Ttk::Frame.new(tbar_base)
+Tk.grid(to_base, contents, :sticky=>'nsew')
+tbar_base.grid_columnconfigure(contents, :weight=>1)
+contents.grid_columnconfigure(1000, :weight=>1)
+
+if Tk.windowingsystem != 'aqua'
+ ## Bindings so that the toolbar can be torn off and reattached
+ to_base.bind('B1-Motion', '%X %Y'){|x, y| tbar_base.tearoff(to_base, x, y)}
+ to. bind('B1-Motion', '%X %Y'){|x, y| tbar_base.tearoff(to_base, x, y)}
+ to2. bind('B1-Motion', '%X %Y'){|x, y| tbar_base.tearoff(to_base, x, y)}
+ def tbar_base.tearoff(w, x, y)
+ on_win = TkWinfo.containing(x, y)
+ return unless (on_win && on_win.path =~ /^#{@path}(\.|$)/)
+ self.grid_remove
+ w.grid_remove
+ self.wm_manage
+ # self.wm_title('Toolbar') # if you don't want to use its widget name as a window title.
+ self.wm_protocol('WM_DELETE_WINDOW'){ self.untearoff(self) }
+ end
+ def tbar_base.untearoff(w)
+ self.wm_forget
+ w.grid
+ self.grid
+ end
+end
+
+## Some content for the rest of the toplevel
+text = TkText.new(base_frame, :width=>40, :height=>10)
+
+## Toolbar contents
+tb_btn = Ttk::Button.new(tbar_base, :text=>'Button', :style=>'Toolbutton',
+ :command=>proc{text.insert(:end, "Button Pressed\n")})
+tb_chk = Ttk::Checkbutton.new(tbar_base, :text=>'Check', :style=>'Toolbutton',
+ :variable=>(check = TkVariable.new),
+ :command=>proc{
+ text.insert(:end, "Check is #{check.value}\n")
+ })
+tb_mbtn = Ttk::Menubutton.new(tbar_base, :text=>'Menu')
+tb_combo = Ttk::Combobox.new(tbar_base, :value=>TkFont.families,
+ :state=>:readonly)
+tb_mbtn.menu(menu = Tk::Menu.new(tb_mbtn))
+menu.add(:command, :label=>'Just', :command=>proc{text.insert(:end, "Just\n")})
+menu.add(:command, :label=>'An', :command=>proc{text.insert(:end, "An\n")})
+menu.add(:command, :label=>'Example',
+ :command=>proc{text.insert(:end, "Example\n")})
+tb_combo.bind('<ComboboxSelected>'){ text.font.family = tb_combo.get }
+
+## Arrange contents
+Tk.grid(tb_btn, tb_chk, tb_mbtn, tb_combo,
+ :in=>contents, :padx=>2, :sticky=>'ns')
+Tk.grid(tbar_base, :sticky=>'ew')
+Tk.grid(sep, :sticky=>'ew')
+Tk.grid(msg, :sticky=>'ew')
+Tk.grid(text, :sticky=>'nsew')
+base_frame.grid_rowconfigure(text, :weight=>1)
+base_frame.grid_columnconfigure(text, :weight=>1)
+
+## See Code / Dismiss buttons
+Ttk::Frame.new(base_frame) {|frame|
+ sep = Ttk::Separator.new(frame)
+ Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
+ TkGrid('x',
+ Ttk::Button.new(frame, :text=>'See Code',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{showCode 'toolbar'}),
+ Ttk::Button.new(frame, :text=>'Dismiss',
+ :image=>$image['delete'], :compound=>:left,
+ :command=>proc{
+ $toolbar_demo.destroy
+ $toolbar_demo = nil
+ }),
+ :padx=>4, :pady=>4)
+ grid_columnconfigure(0, :weight=>1)
+ Tk.grid(frame, :sticky=>'ew')
+}
diff --git a/ext/tk/sample/demos-en/tree.rb b/ext/tk/sample/demos-en/tree.rb
new file mode 100644
index 0000000000..0c7f0e71a2
--- /dev/null
+++ b/ext/tk/sample/demos-en/tree.rb
@@ -0,0 +1,119 @@
+# tree.rb --
+#
+# This demonstration script creates a toplevel window containing a Ttk
+# tree widget.
+#
+# based on "Id: tree.tcl,v 1.4 2007/12/13 15:27:07 dgp Exp"
+
+if defined?($tree_demo) && $tree_demo
+ $tree_demo.destroy
+ $tree_demo = nil
+end
+
+$tree_demo = TkToplevel.new {|w|
+ title("Directory Browser")
+ iconname("tree")
+ positionWindow(w)
+}
+
+base_frame = TkFrame.new($tree_demo).pack(:fill=>:both, :expand=>true)
+
+## Explanatory text
+Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i',
+ :justify=>:left, :anchor=>'n', :padding=>[10, 2, 10, 6],
+ :text=><<EOL).pack(:fill=>:x)
+Ttk is the new Tk themed widget set. \
+One of the widgets it includes is a tree widget, \
+which allows the user to browse a hierarchical data-set such as a filesystem. \
+The tree widget not only allows for the tree part itself, \
+but it also supports an arbitrary number of additional columns \
+which can show additional data (in this case, the size of the files \
+found in your filesystem). \
+You can also change the width of the columns \
+by dragging the boundary between them.
+EOL
+
+## See Code / Dismiss
+Ttk::Frame.new(base_frame) {|frame|
+ sep = Ttk::Separator.new(frame)
+ Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
+ TkGrid('x',
+ Ttk::Button.new(frame, :text=>'See Code',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{showCode 'tree'}),
+ Ttk::Button.new(frame, :text=>'Dismiss',
+ :image=>$image['delete'], :compound=>:left,
+ :command=>proc{
+ $tree_demo.destroy
+ $tree_demo = nil
+ }),
+ :padx=>4, :pady=>4)
+ grid_columnconfigure(0, :weight=>1)
+ pack(:side=>:bottom, :fill=>:x)
+}
+
+## Code to populate the roots of the tree (can be more than one on Windows)
+def populate_roots(tree)
+ TkComm.simplelist(Tk.tk_call('file', 'volumes')).sort.each{|dir|
+ populate_tree(tree, tree.insert(nil, :end, :text=>dir,
+ :values=>[dir, 'directory']))
+ }
+end
+
+## Code to populate a node of the tree
+def populate_tree(tree, node)
+ return if tree.get(node, :type) != 'directory'
+
+ path = tree.get(node, :fullpath)
+ tree.delete(tree.children(node))
+ Dir.glob("#{path}/*").sort.each{|f|
+ type = File.ftype(f)
+ id = tree.insert(node, :end,
+ :text=>File.basename(f), :values=>[f, type]).id
+ if type == 'directory'
+ ## Make it so that this node is openable
+ tree.insert(id, 0, :text=>'dummy')
+ tree.itemconfigure(id, :text=>File.basename(f))
+ elsif type == 'file'
+ size = File.size(f)
+ if size >= 1024*1024*1024
+ size = '%.1f GB' % (size.to_f/1024/1024/1024)
+ elsif size >= 1024*1024
+ size = '%.1f MB' % (size.to_f/1024/1024)
+ elsif size >= 1024
+ size = '%.1f KB' % (size.to_f/1024)
+ else
+ size = '%.1f bytes' % (size.to_f/1024)
+ end
+ tree.set(id, :size, size)
+ end
+ }
+
+ # Stop this code from rerunning on the current node
+ tree.set(node, :type, 'processed_directory')
+end
+
+## Create the tree and set it up
+tree = Ttk::Treeview.new(base_frame, :columns=>%w(fullpath type size),
+ :displaycolumns=>['size'])
+if Tk.windowingsystem != 'aqua'
+ vsb = tree.yscrollbar(Ttk::Scrollbar.new(base_frame))
+ hsb = tree.xscrollbar(Ttk::Scrollbar.new(base_frame))
+else
+ vsb = tree.yscrollbar(Tk::Scrollbar.new(base_frame))
+ hsb = tree.xscrollbar(Tk::Scrollbar.new(base_frame))
+end
+
+tree.heading_configure('#0', :text=>'Directory Structure')
+tree.heading_configure('size', :text=>'File Size')
+tree.column_configure('size', :stretch=>0, :width=>70)
+populate_roots(tree)
+tree.bind('<TreeviewOpen>', '%W'){|w| populate_tree(w, w.focus_item)}
+
+## Arrange the tree and its scrollbars in the toplevel
+container = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true)
+container.lower
+Tk.grid(tree, vsb, :in=>container, :sticky=>'nsew')
+Tk.grid(hsb, :in=>container, :sticky=>'nsew')
+container.grid_columnconfigure(0, :weight=>1)
+container.grid_rowconfigure(0, :weight=>1)
diff --git a/ext/tk/sample/demos-en/ttkbut.rb b/ext/tk/sample/demos-en/ttkbut.rb
new file mode 100644
index 0000000000..b5780f589a
--- /dev/null
+++ b/ext/tk/sample/demos-en/ttkbut.rb
@@ -0,0 +1,139 @@
+# ttkbut.rb
+#
+# This demonstration script creates a toplevel window containing several
+# simple Ttk widgets, such as labels, labelframes, buttons, checkbuttons and
+# radiobuttons.
+#
+# based on "Id: ttkbut.tcl,v 1.4 2007/12/13 15:27:07 dgp Exp"
+
+if defined?($ttkbut_demo) && $ttkbut_demo
+ $ttkbut_demo.destroy
+ $ttkbut_demo = nil
+end
+
+$ttkbut_demo = TkToplevel.new {|w|
+ title("Simple Ttk Widgets")
+ iconname("ttkbut")
+ positionWindow(w)
+}
+
+base_frame = TkFrame.new($ttkbut_demo).pack(:fill=>:both, :expand=>true)
+
+Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left,
+ :text=><<EOL).pack(:side=>:top, :fill=>:x)
+Ttk is the new Tk themed widget set. This is a Ttk themed label, \
+and below are three groups of Ttk widgets in Ttk labelframes. \
+The first group are all buttons that set the current application theme \
+when pressed. The second group contains three sets of checkbuttons, \
+with a separator widget between the sets. Note that the "Enabled" \
+button controls whether all the other themed widgets in this toplevel are \
+in the disabled state. The third group has a collection of linked \
+radiobuttons.
+EOL
+
+## Add buttons for setting the theme
+buttons = Ttk::Labelframe.new(base_frame, :text=>'Buttons')
+# Ttk::Style.theme_names.each{|theme|
+# Ttk::Button.new(buttons, :text=>theme,
+# :command=>proc{Ttk::Style.theme_use theme}).pack(:pady=>2)
+# }
+Ttk.themes.each{|theme|
+ Ttk::Button.new(buttons, :text=>theme,
+ :command=>proc{Ttk.set_theme theme}).pack(:pady=>2)
+}
+
+## Helper procedure for the top checkbutton
+def setState(root, value, *excepts)
+ return if excepts.member?(root)
+
+ ## Non-Ttk widgets (e.g. the toplevel) will fail, so make it silent
+ begin
+ root.state = value
+ rescue
+ end
+
+ ## Recursively invoke on all children of this root that are in the same
+ ## toplevel widget
+ root.winfo_children.each{|w|
+ setState(w, value, *excepts) if w.winfo_toplevel == root.winfo_toplevel
+ }
+end
+
+## Set up the checkbutton group
+checks = Ttk::Labelframe.new(base_frame, :text=>'Checkbuttons')
+enabled = TkVariable.new(true)
+e = Ttk::Checkbutton.new(checks, :text=>'Enabled', :variable=>enabled,
+ :command=>proc{
+ setState($ttkbut_demo,
+ ((enabled.bool)? "!disabled" : "disabled"),
+ e)
+ })
+
+## See ttk_widget(n) for other possible state flags
+sep1 = Ttk::Separator.new(checks)
+sep2 = Ttk::Separator.new(checks)
+
+cheese = TkVariable.new
+tomato = TkVariable.new
+basil = TkVariable.new
+oregano = TkVariable.new
+
+c1 = Ttk::Checkbutton.new(checks, :text=>'Cheese', :variable=>cheese)
+c2 = Ttk::Checkbutton.new(checks, :text=>'Tomato', :variable=>tomato)
+c3 = Ttk::Checkbutton.new(checks, :text=>'Basil', :variable=>basil)
+c4 = Ttk::Checkbutton.new(checks, :text=>'Oregano', :variable=>oregano)
+
+Tk.pack(e, sep1, c1, c2, sep2, c3, c4, :fill=>:x, :pady=>2)
+
+## Set up the radiobutton group
+radios = Ttk::Labelframe.new(base_frame, :text=>'Radiobuttons')
+
+happyness = TkVariable.new
+
+r1 = Ttk::Radiobutton.new(radios, :variable=>happyness,
+ :text=>'Great', :value=>'great')
+r2 = Ttk::Radiobutton.new(radios, :variable=>happyness,
+ :text=>'Good', :value=>'good')
+r3 = Ttk::Radiobutton.new(radios, :variable=>happyness,
+ :text=>'Ok', :value=>'ok')
+r4 = Ttk::Radiobutton.new(radios, :variable=>happyness,
+ :text=>'Poor', :value=>'poor')
+r5 = Ttk::Radiobutton.new(radios, :variable=>happyness,
+ :text=>'Awful', :value=>'awful')
+
+Tk.pack(r1, r2, r3, r4, r5, :fill=>:x, :padx=>3, :pady=>2)
+
+## See Code / Dismiss
+Ttk::Frame.new(base_frame) {|frame|
+ sep = Ttk::Separator.new(frame)
+ Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
+ TkGrid('x',
+ Ttk::Button.new(frame, :text=>'See Variables',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{
+ showVars(base_frame, ['enabled', enabled],
+ ['cheese', cheese], ['tomato', tomato],
+ ['basil', basil], ['oregano', oregano],
+ ['happyness', happyness])
+ }),
+ Ttk::Button.new(frame, :text=>'See Code',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{showCode 'ttkbut'}),
+ Ttk::Button.new(frame, :text=>'Dismiss',
+ :image=>$image['delete'], :compound=>:left,
+ :command=>proc{
+ tmppath = $ttkbut_demo
+ $ttkbut_demo = nil
+ $showVarsWin[tmppath.path] = nil
+ tmppath.destroy
+ }),
+ :padx=>4, :pady=>4)
+ grid_columnconfigure(0, :weight=>1)
+ pack(:side=>:bottom, :fill=>:x, :expand=>true)
+}
+
+## Arrange things neatly
+f = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true)
+f.lower
+Tk.grid(buttons, checks, radios, :in=>f, :sticky=>'nwe', :pady=>2, :padx=>3)
+f.grid_columnconfigure([0, 1, 2], :weight=>1, :uniform=>:yes)
diff --git a/ext/tk/sample/demos-en/ttkmenu.rb b/ext/tk/sample/demos-en/ttkmenu.rb
new file mode 100644
index 0000000000..75ecdb09c4
--- /dev/null
+++ b/ext/tk/sample/demos-en/ttkmenu.rb
@@ -0,0 +1,85 @@
+# ttkmenu.rb --
+#
+# This demonstration script creates a toplevel window containing several Ttk
+# menubutton widgets.
+#
+# based on "Id: ttkmenu.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp"
+
+if defined?($ttkmenu_demo) && $ttkmenu_demo
+ $ttkmenu_demo.destroy
+ $ttkmenu_demo = nil
+end
+
+$ttkmenu_demo = TkToplevel.new {|w|
+ title("Ttk Menu Buttons")
+ iconname("ttkmenu")
+ positionWindow(w)
+}
+
+base_frame = Ttk::Frame.new($ttkmenu_demo).pack(:fill=>:both, :expand=>true)
+
+Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left,
+ :text=><<EOL).pack(:side=>:top, :fill=>:x)
+Ttk is the new Tk themed widget set, \
+and one widget that is available in themed form is the menubutton. \
+Below are some themed menu buttons \
+that allow you to pick the current theme in use. \
+Notice how picking a theme changes the way \
+that the menu buttons themselves look, \
+and that the central menu button is styled differently \
+(in a way that is normally suitable for toolbars). \
+However, there are no themed menus; the standard Tk menus were judged \
+to have a sufficiently good look-and-feel on all platforms, \
+especially as they are implemented as native controls in many places.
+EOL
+
+Ttk::Separator.new(base_frame).pack(:side=>:top, :fill=>:x)
+
+## See Code / Dismiss
+Ttk::Frame.new($ttkmenu_demo) {|frame|
+ sep = Ttk::Separator.new(frame)
+ Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
+ TkGrid('x',
+ Ttk::Button.new(frame, :text=>'See Code',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{showCode 'ttkmenu'}),
+ Ttk::Button.new(frame, :text=>'Dismiss',
+ :image=>$image['delete'], :compound=>:left,
+ :command=>proc{
+ $ttkmenu_demo.destroy
+ $ttkmenu_demo = nil
+ }),
+ :padx=>4, :pady=>4)
+ grid_columnconfigure(0, :weight=>1)
+ pack(:side=>:bottom, :fill=>:x)
+}
+
+b1 = Ttk::Menubutton.new(base_frame,:text=>'Select a theme',:direction=>:above)
+b2 = Ttk::Menubutton.new(base_frame,:text=>'Select a theme',:direction=>:left)
+b3 = Ttk::Menubutton.new(base_frame,:text=>'Select a theme',:direction=>:right)
+b4 = Ttk::Menubutton.new(base_frame,:text=>'Select a theme',:direction=>:flush,
+ :style=>Ttk::Menubutton.style('Toolbutton'))
+b5 = Ttk::Menubutton.new(base_frame,:text=>'Select a theme',:direction=>:below)
+
+b1.menu(m1 = Tk::Menu.new(b1, :tearoff=>false))
+b2.menu(m2 = Tk::Menu.new(b2, :tearoff=>false))
+b3.menu(m3 = Tk::Menu.new(b3, :tearoff=>false))
+b4.menu(m4 = Tk::Menu.new(b4, :tearoff=>false))
+b5.menu(m5 = Tk::Menu.new(b5, :tearoff=>false))
+
+Ttk.themes.each{|theme|
+ m1.add(:command, :label=>theme, :command=>proc{Ttk.set_theme theme})
+ m2.add(:command, :label=>theme, :command=>proc{Ttk.set_theme theme})
+ m3.add(:command, :label=>theme, :command=>proc{Ttk.set_theme theme})
+ m4.add(:command, :label=>theme, :command=>proc{Ttk.set_theme theme})
+ m5.add(:command, :label=>theme, :command=>proc{Ttk.set_theme theme})
+}
+
+f = Ttk::Frame.new(base_frame).pack(:fill=>:x)
+f1 = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true)
+f.lower
+
+f.grid_anchor(:center)
+TkGrid('x', b1, 'x', :in=>f, :padx=>3, :pady=>2)
+TkGrid(b2, b4, b3, :in=>f, :padx=>3, :pady=>2)
+TkGrid('x', b5, 'x', :in=>f, :padx=>3, :pady=>2)
diff --git a/ext/tk/sample/demos-en/ttknote.rb b/ext/tk/sample/demos-en/ttknote.rb
new file mode 100644
index 0000000000..c2a22b447a
--- /dev/null
+++ b/ext/tk/sample/demos-en/ttknote.rb
@@ -0,0 +1,89 @@
+# ttknote.rb --
+#
+# This demonstration script creates a toplevel window containing a Ttk
+# notebook widget.
+#
+# based on "Id: ttknote.tcl,v 1.5 2007/12/13 15:27:07 dgp Exp"
+
+if defined?($ttknote_demo) && $ttknote_demo
+ $ttknote_demo.destroy
+ $ttknote_demo = nil
+end
+
+$ttknote_demo = TkToplevel.new {|w|
+ title("Ttk Notebook Widget")
+ iconname("ttknote")
+ positionWindow(w)
+}
+
+## See Code / Dismiss
+Ttk::Frame.new($ttknote_demo) {|frame|
+ sep = Ttk::Separator.new(frame)
+ Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
+ TkGrid('x',
+ Ttk::Button.new(frame, :text=>'See Code',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{showCode 'ttknote'}),
+ Ttk::Button.new(frame, :text=>'Dismiss',
+ :image=>$image['delete'], :compound=>:left,
+ :command=>proc{
+ $ttknote_demo.destroy
+ $ttknote_demo = nil
+ }),
+ :padx=>4, :pady=>4)
+ grid_columnconfigure(0, :weight=>1)
+ pack(:side=>:bottom, :fill=>:x)
+}
+
+base_frame = Ttk::Frame.new($ttknote_demo).pack(:fill=>:both, :expand=>true)
+
+## Make the notebook and set up Ctrl+Tab traversal
+notebook = Ttk::Notebook.new(base_frame).pack(:fill=>:both, :expand=>true,
+ :padx=>2, :pady=>3)
+notebook.enable_traversal
+
+## Popuplate the first pane
+f_msg = Ttk::Frame.new(notebook)
+msg_m = Ttk::Label.new(f_msg, :font=>$font, :wraplength=>'4i',
+ :justify=>:left, :anchor=>'n', :text=><<EOL)
+Ttk is the new Tk themed widget set. \
+One of the widgets it includes is the notebook widget, \
+which provides a set of tabs that allow the selection of a group of panels, \
+each with distinct content. \
+They are a feature of many modern user interfaces. \
+Not only can the tabs be selected with the mouse, \
+but they can also be switched between using Ctrl+Tab \
+when the notebook page heading itself is selected. \
+Note that the second tab is disabled, and cannot be selected.
+EOL
+neat = TkVariable.new
+after_id = nil
+msg_b = Ttk::Button.new(f_msg, :text=>'Neat!', :underline=>0,
+ :command=>proc{
+ neat.value = 'Yeah, I know...'
+ Tk.after_cancel(after_id) if after_id
+ after_id = Tk.after(500){neat.value = ''}
+ })
+msg_b.winfo_toplevel.bind('Alt-n'){ msg_b.focus; msg_b.invoke }
+msg_l = Ttk::Label.new(f_msg, :textvariable=>neat)
+notebook.add(f_msg, :text=>'Description', :underline=>0, :padding=>2)
+Tk.grid(msg_m, '-', :sticky=>'new', :pady=>2)
+Tk.grid(msg_b, msg_l, :pady=>[2, 4])
+f_msg.grid_rowconfigure(1, :weight=>1)
+f_msg.grid_columnconfigure([0, 1], :weight=>1, :uniform=>1)
+
+## Populate the second pane. Note that the content doesn't really matter
+f_disabled = Ttk::Frame.new(notebook)
+notebook.add(f_disabled, :text=>'Disabled', :state=>:disabled)
+
+## Popuplate the third pane
+f_editor = Ttk::Frame.new(notebook)
+notebook.add(f_editor, :text=>'Text Editor', :underline=>0)
+editor_t = Tk::Text.new(f_editor, :width=>40, :height=>10, :wrap=>:char)
+if Tk.windowingsystem != 'aqua'
+ editor_s = editor_t.yscrollbar(Ttk::Scrollbar.new(f_editor))
+else
+ editor_s = editor_t.yscrollbar(Tk::Scrollbar.new(f_editor))
+end
+editor_s.pack(:side=>:right, :fill=>:y, :padx=>[0,2], :pady=>2)
+editor_t.pack(:fill=>:both, :expand=>true, :padx=>[2,0], :pady=>2)
diff --git a/ext/tk/sample/demos-en/ttkpane.rb b/ext/tk/sample/demos-en/ttkpane.rb
new file mode 100644
index 0000000000..56df613db4
--- /dev/null
+++ b/ext/tk/sample/demos-en/ttkpane.rb
@@ -0,0 +1,213 @@
+# ttkpane.rb --
+#
+# This demonstration script creates a Ttk pane with some content.
+#
+# based on "Id: ttkpane.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp"
+
+if defined?($ttkpane_demo) && $ttkpane_demo
+ $ttkpane_demo.destroy
+ $ttkpane_demo = nil
+end
+
+$ttkpane_demo = TkToplevel.new {|w|
+ title("Themed Nested Panes")
+ iconname("ttkpane")
+ positionWindow(w)
+}
+
+base_frame = TkFrame.new($ttkpane_demo).pack(:fill=>:both, :expand=>true)
+
+Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left,
+ :text=><<EOL).pack(:side=>:top, :fill=>:x)
+This demonstration shows off a nested set of themed paned windows. \
+Their sizes can be changed by grabbing the area \
+between each contained pane and dragging the divider.
+EOL
+
+Ttk::Separator.new(base_frame).pack(:side=>:top, :fill=>:x)
+
+## See Code / Dismiss
+Ttk::Frame.new(base_frame) {|frame|
+ sep = Ttk::Separator.new(frame)
+ Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
+ TkGrid('x',
+ Ttk::Button.new(frame, :text=>'See Code',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{showCode 'ttkpane'}),
+ Ttk::Button.new(frame, :text=>'Dismiss',
+ :image=>$image['delete'], :compound=>:left,
+ :command=>proc{
+ $ttkpane_demo.destroy
+ $ttkpane_demo = nil
+ }),
+ :padx=>4, :pady=>4)
+ grid_columnconfigure(0, :weight=>1)
+ pack(:side=>:bottom, :fill=>:x)
+}
+
+frame = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true)
+
+outer = Ttk::Panedwindow.new(frame, :orient=>:horizontal)
+outer.add(in_left = Ttk::Panedwindow.new(outer, :orient=>:vertical))
+outer.add(in_right = Ttk::Panedwindow.new(outer, :orient=>:vertical))
+in_left.add(left_top = Ttk::Labelframe.new(in_left, :text=>'Button'))
+in_left.add(left_bot = Ttk::Labelframe.new(in_left, :text=>'Clocks'))
+in_right.add(right_top = Ttk::Labelframe.new(in_right, :text=>'Progress'))
+in_right.add(right_bot = Ttk::Labelframe.new(in_right, :text=>'Text'))
+if Tk.windowingsystem == 'aqua'
+ [left_top, left_bot, right_top, right_bot].each{|w| w.padding(3) }
+end
+
+# Fill the button pane
+Ttk::Button.new(left_top, :text=>'Press Me',
+ :command=>proc{
+ Tk.messageBox(:type=>'ok', :icon=>'info', :message=>'Ouch!',
+ :detail=>'That hurt...', :parent=>base_frame,
+ :title=>'Button Pressed')
+ }).pack(:padx=>2, :pady=>5)
+
+
+zones_list = [
+ [':Europe/Berlin'],
+ [':America/Argentina/Buenos_Aires', ':America/Buenos_Aires'],
+ [':Africa/Johannesburg'],
+ [':Europe/London'],
+ [':America/Los_Angeles'],
+ [':Europe/Moscow'],
+ [':America/New_York'],
+ [':Asia/Singapore'],
+ [':Australia/Sydney'],
+ [':Asia/Tokyo'],
+]
+
+zones = []
+
+# Check tzinfo support
+if $tk_major_ver > 8 || ($tk_major_ver == 8 && $tk_minor_ver >= 5)
+ tzinfo = :tcl
+
+ # Force a pre-load of all the timezones needed; otherwise can end up
+ # poor-looking synch problems!
+ zones_list.each{|list|
+ list.each{|zone|
+ begin
+ Tk.tk_call('clock', 'format', '0', '-timezone', zone)
+ rescue RuntimeError
+ # ignore
+ else
+ zones << [zone, zone[%r<[^/:]+$>].tr('_', ' ')]
+ break
+ end
+ }
+ }
+
+else
+ begin
+ require 'tzinfo'
+ tzinfo = :tzinfo
+ rescue Exception
+ begin
+ require 'tzfile'
+ tzinfo = :tzfile
+ rescue Exception
+ tzinfo = nil
+ end
+ end
+
+ case tzinfo
+ when :tzinfo
+ zones_list.each{|list|
+ list.each{|zone|
+ begin
+ tz = TZInfo::Timezone.get(zone[%r<[^:]+$>])
+ rescue Exception
+ # ignore
+ else
+ zones << [tz, zone[%r<[^/:]+$>].tr('_', ' ')]
+ break
+ end
+ }
+ }
+
+ when :tzfile
+ zones_list.each{|list|
+ list.each{|zone|
+ begin
+ tz = TZFile.create(zone[%r<[^:]+$>])
+ rescue Exception
+ # ignore
+ else
+ zones << [tz, zone[%r<[^/:]+$>].tr('_', ' ')]
+ break
+ end
+ }
+ }
+
+ else
+ [ -7, -4, -2, -1, 0, +1, +3, +8, +9, +10 ].each{|zone|
+ zones << [zone, 'UTC%+03d00' % zone]
+ }
+ end
+end
+
+time = TkVariable.new_hash
+
+case tzinfo
+when :tcl
+ update_proc = proc{|now, tz, label|
+ time[label] = Tk.tk_call('clock', 'format', now.tv_sec,
+ '-timezone', tz, '-format', '%T')
+ }
+when :tzinfo
+ update_proc = proc{|now, tz, label|
+ time[label] = tz.utc_to_local(now).strftime('%H:%M:%S')
+ }
+when :tzfile
+ update_proc = proc{|now, tz, label|
+ time[label] = tz.at(now.tv_sec).strftime('%H:%M:%S')
+ }
+else
+ update_proc = proc{|now, tz, label|
+ time[label] = (now + (tz * 3600)).strftime('%H:%M:%S')
+ }
+end
+
+# Fill the clocks pane
+zones.each_with_index{|(zone, label), idx|
+ Ttk::Separator.new(left_bot).pack(:fill=>:x) if idx > 0
+ Ttk::Label.new(left_bot, :text=>label, :anchor=>'w').pack(:fill=>:x)
+ Ttk::Label.new(left_bot, :textvariable=>time.ref(label),
+ :anchor=>'w').pack(:fill=>:x)
+}
+
+# Timer start
+every = proc{
+ now = Time.now.utc
+ zones.each{|zone, label| update_proc.call(now, zone, label) }
+}
+TkRTTimer.new(1000, -1, every).start(0, every)
+
+# Fill the progress pane
+Ttk::Progressbar.new(right_top, :mode=>:indeterminate).pack(:fill=>:both, :expand=>true).start
+
+# Fill the text pane
+if Tk.windowingsystem != 'aqua'
+ # The trick with the ttk::frame makes the text widget look like it fits with
+ # the current Ttk theme despite not being a themed widget itself. It is done
+ # by styling the frame like an entry, turning off the border in the text
+ # widget, and putting the text widget in the frame with enough space to allow
+ # the surrounding border to show through (2 pixels seems to be enough).
+ f = Ttk::Frame.new(right_bot, :style=>Ttk::Entry)
+ txt = TkText.new(frame, :wrap=>:word, :width=>30, :borderwidth=>0)
+ txt.pack(:fill=>:both, :expand=>true, :in=>f, :pady=>2, :padx=>2)
+ scr = txt.yscrollbar(Ttk::Scrollbar.new(frame))
+ scr.pack(:side=>:right, :fill=>:y, :in=>right_bot)
+ f.pack(:fill=>:both, :expand=>true)
+ outer.pack(:fill=>:both, :expand=>true)
+else
+ txt = TkText.new(frame, :wrap=>:word, :width=>30, :borderwidth=>0)
+ scr = txt.yscrollbar(TkScrollbar.new(frame))
+ scr.pack(:side=>:right, :fill=>:y, :in=>right_bot)
+ txt.pack(:fill=>:both, :expand=>true, :in=>right_bot)
+ outer.pack(:fill=>:both, :expand=>true, :padx=>10, :pady=>[6, 10])
+end
diff --git a/ext/tk/sample/demos-en/ttkprogress.rb b/ext/tk/sample/demos-en/ttkprogress.rb
new file mode 100644
index 0000000000..3eb9a64a4a
--- /dev/null
+++ b/ext/tk/sample/demos-en/ttkprogress.rb
@@ -0,0 +1,66 @@
+# ttkprogress.rb --
+#
+# This demonstration script creates several progress bar widgets.
+#
+# based on "Id: ttkprogress.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp"
+
+if defined?($ttkprogress_demo) && $ttkprogress_demo
+ $ttkprogress_demo.destroy
+ $ttkprogress_demo = nil
+end
+
+$ttkprogress_demo = TkToplevel.new {|w|
+ title("Progress Bar Demonstration")
+ iconname("ttkprogress")
+ positionWindow(w)
+}
+
+base_frame = TkFrame.new($ttkprogress_demo).pack(:fill=>:both, :expand=>true)
+
+Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left,
+ :text=>Tk::UTF8_String.new(<<EOL)).pack(:side=>:top, :fill=>:x)
+Below are two progress bars. \
+The top one is a \\u201Cdeterminate\\u201D progress bar, \
+which is used for showing how far through a defined task the program has got. \
+The bottom one is an \\u201Cindeterminate\\u201D progress bar, \
+which is used to show that the program is busy \
+but does not know how long for. Both are run here in self-animated mode, \
+which can be turned on and off using the buttons underneath.
+EOL
+
+## See Code / Dismiss buttons
+Ttk::Frame.new(base_frame) {|frame|
+ sep = Ttk::Separator.new(frame)
+ Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
+ TkGrid('x',
+ Ttk::Button.new(frame, :text=>'See Code',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{showCode 'ttkprogress'}),
+ Ttk::Button.new(frame, :text=>'Dismiss',
+ :image=>$image['delete'], :compound=>:left,
+ :command=>proc{
+ $ttkprogress_demo.destroy
+ $ttkprogress_demo = nil
+ }),
+ :padx=>4, :pady=>4)
+ grid_columnconfigure(0, :weight=>1)
+ pack(:side=>:bottom, :fill=>:x)
+}
+
+frame = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true)
+
+p1 = Ttk::Progressbar.new(frame, :mode=>:determinate)
+p2 = Ttk::Progressbar.new(frame, :mode=>:indeterminate)
+
+start = Ttk::Button.new(frame, :text=>'Start Progress',
+ :command=>proc{ p1.start; p2.start })
+stop = Ttk::Button.new(frame, :text=>'Stop Progress',
+ :command=>proc{ p1.stop; p2.stop })
+
+Tk.grid(p1, '-', :pady=>5, :padx=>10)
+Tk.grid(p2, '-', :pady=>5, :padx=>10)
+Tk.grid(start, stop, :padx=>10, :pady=>5)
+start.grid_configure(:sticky=>'e')
+stop.grid_configure(:sticky=>'w')
+frame.grid_columnconfigure(:all, :weight=>1)
+
diff --git a/ext/tk/sample/demos-en/twind.rb b/ext/tk/sample/demos-en/twind.rb
index 24a4bcf706..65ee712ff7 100644
--- a/ext/tk/sample/demos-en/twind.rb
+++ b/ext/tk/sample/demos-en/twind.rb
@@ -19,8 +19,10 @@ $twind_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($twind_demo).pack(:fill=>:both, :expand=>true)
+
# frame
-$twind_buttons = TkFrame.new($twind_demo) {|frame|
+$twind_buttons = TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc{
@@ -39,13 +41,13 @@ $twind_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# frame
$twind_text = nil
-TkFrame.new($twind_demo, 'highlightthickness'=>2, 'borderwidth'=>2,
+TkFrame.new(base_frame, 'highlightthickness'=>2, 'borderwidth'=>2,
'relief'=>'sunken') {|f|
$twind_text = TkText.new(f, 'setgrid'=>'true', 'font'=>$font,
'width'=>'70', 'height'=>35, 'wrap'=>'word',
'highlightthickness'=>0, 'borderwidth'=>0 ){|t|
TkScrollbar.new(f) {|s|
- command proc{|*args| t.yview(args)}
+ command proc{|*args| t.yview(*args)}
t.yscrollcommand proc{|first,last| s.set first,last}
}.pack('side'=>'right', 'fill'=>'y')
}.pack('expand'=>'yes', 'fill'=>'both')
@@ -206,7 +208,11 @@ def textWindPlot (t)
cursor 'top_left_arrow'
}
- font = '-Adobe-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*'
+ if $tk_version =~ /^4.*/
+ font = '-Adobe-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*'
+ else
+ font = 'Helvetica 18'
+ end
TkcLine.new($twind_plot, 100, 250, 400, 250, 'width'=>2)
TkcLine.new($twind_plot, 100, 250, 100, 50, 'width'=>2)
diff --git a/ext/tk/sample/demos-en/twind2.rb b/ext/tk/sample/demos-en/twind2.rb
index c42e0999d7..43990c1151 100644
--- a/ext/tk/sample/demos-en/twind2.rb
+++ b/ext/tk/sample/demos-en/twind2.rb
@@ -15,8 +15,10 @@ $twind2_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($twind2_demo).pack(:fill=>:both, :expand=>true)
+
# frame
-$twind2_buttons = TkFrame.new($twind2_demo) {|frame|
+$twind2_buttons = TkFrame.new(base_frame) {|frame|
TkGrid(TkFrame.new(frame, :height=>2, :relief=>:sunken, :bd=>2),
:columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
TkGrid('x',
@@ -38,7 +40,7 @@ $twind2_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# frame
$twind2_text = nil
-TkFrame.new($twind2_demo, 'highlightthickness'=>2, 'borderwidth'=>2,
+TkFrame.new(base_frame, 'highlightthickness'=>2, 'borderwidth'=>2,
'relief'=>'sunken') {|f|
$twind2_text = TkText.new(f, 'setgrid'=>true, 'font'=>$font,
# 'width'=>'70', 'height'=>35, 'wrap'=>'word',
diff --git a/ext/tk/sample/demos-en/unicodeout.rb b/ext/tk/sample/demos-en/unicodeout.rb
index 07e3bf52b5..9c230a2536 100644
--- a/ext/tk/sample/demos-en/unicodeout.rb
+++ b/ext/tk/sample/demos-en/unicodeout.rb
@@ -16,7 +16,9 @@ $unicodeout_demo = TkToplevel.new {|w|
positionWindow(w)
}
-TkLabel.new($unicodeout_demo,
+base_frame = TkFrame.new($unicodeout_demo).pack(:fill=>:both, :expand=>true)
+
+TkLabel.new(base_frame,
:font=>$font, :wraplength=>'5.4i', :justify=>:left,
:text=><<EOL).pack(:side=>:top)
This is a sample of Tk's support for languages that use non-Western \
@@ -36,7 +38,7 @@ The strings are converted to the encoded string objects \
And the Tk::UTF8_String objects are passed to the label widgets.
EOL
-TkFrame.new($unicodeout_demo){|f|
+TkFrame.new(base_frame){|f|
pack(:side=>:bottom, :fill=>:x, :pady=>'2m')
TkButton.new(f, :text=>'Dismiss', :width=>15, :command=>proc{
@@ -49,7 +51,7 @@ TkFrame.new($unicodeout_demo){|f|
}).pack(:side=>:left, :expand=>true)
}
-wait_msg = TkLabel.new($unicodeout_demo,
+wait_msg = TkLabel.new(base_frame,
:text=>"Please wait while loading fonts...",
:font=>"Helvetica 12 italic").pack
@@ -63,8 +65,8 @@ class Unicodeout_SampleFrame < TkFrame
# @@font = 'Newspaper 12'
# @@font = '{New century schoolbook} 12'
- def initialize()
- super($unicodeout_demo)
+ def initialize(base)
+ super(base)
grid_columnconfig(1, :weight=>1)
end
@@ -79,7 +81,7 @@ class Unicodeout_SampleFrame < TkFrame
l.grid_config(:padx, '1m')
end
end
-f = Unicodeout_SampleFrame.new
+f = Unicodeout_SampleFrame.new(base_frame)
f.pack(:expand=>true, :fill=>:both, :padx=>'2m', :pady=>'1m')
# Processing when some characters are missing might take a while, so make
diff --git a/ext/tk/sample/demos-en/vscale.rb b/ext/tk/sample/demos-en/vscale.rb
index 636b85813b..b05ed12072 100644
--- a/ext/tk/sample/demos-en/vscale.rb
+++ b/ext/tk/sample/demos-en/vscale.rb
@@ -15,7 +15,9 @@ $vscale_demo = TkToplevel.new {|w|
}
positionWindow($vscale_demo)
-msg = TkLabel.new($vscale_demo) {
+base_frame = TkFrame.new($vscale_demo).pack(:fill=>:both, :expand=>true)
+
+msg = TkLabel.new(base_frame) {
font $font
wraplength '3.5i'
justify 'left'
@@ -23,7 +25,7 @@ msg = TkLabel.new($vscale_demo) {
}
msg.pack('side'=>'top', 'padx'=>'.5c')
-TkFrame.new($vscale_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
text 'Dismiss'
command proc {
@@ -39,7 +41,17 @@ TkFrame.new($vscale_demo) {|frame|
}.pack('side'=>'left', 'expand'=>'yes')
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
-TkFrame.new($vscale_demo) {|frame|
+def setHeight(w, height)
+ height = height + 21
+ y2 = height - 30
+ if y2 < 21
+ y2 = 21
+ end
+ w.coords 'poly',15,20,35,20,35,y2,45,y2,25,height,5,y2,15,y2,15,20
+ w.coords 'line',15,20,35,20,35,y2,45,y2,25,height,5,y2,15,y2,15,20
+end
+
+TkFrame.new(base_frame) {|frame|
borderwidth 10
canvas = TkCanvas.new(frame) {|c|
width 50
@@ -65,14 +77,3 @@ TkFrame.new($vscale_demo) {|frame|
}.pack('side'=>'left', 'anchor'=>'ne')
scale.set 75
}.pack
-
-
-def setHeight(w, height)
- height = height + 21
- y2 = height - 30
- if y2 < 21
- y2 = 21
- end
- w.coords 'poly',15,20,35,20,35,y2,45,y2,25,height,5,y2,15,y2,15,20
- w.coords 'line',15,20,35,20,35,y2,45,y2,25,height,5,y2,15,y2,15,20
-end
diff --git a/ext/tk/sample/demos-en/widget b/ext/tk/sample/demos-en/widget
index 3c50582211..9a0605d8b9 100644
--- a/ext/tk/sample/demos-en/widget
+++ b/ext/tk/sample/demos-en/widget
@@ -14,6 +14,8 @@ require 'tk'
### $DEBUG=1 ##########
+$RubyTk_WidgetDemo = true
+
#----------------------------------------------------------------
# The code below create the main window, consisting of a menu bar
# and a text widget that explains how to use the program, plus lists
@@ -21,7 +23,8 @@ require 'tk'
#----------------------------------------------------------------
# widget demo directory
-$demo_dir = File.dirname($0)
+# $demo_dir = File.dirname($0)
+$demo_dir = File.dirname(__FILE__)
# root
$root = TkRoot.new{title "Ruby/Tk Widget Demonstration"}
@@ -102,14 +105,22 @@ EOD
end
#
-TkMenubar.new($root,
- [[['File', 0],
- ['About ... ', proc{aboutBox}, 0, '<F1>'],
- '---',
- ['Quit', proc{exit}, 0, 'Meta-Q']
- ]]).pack('side'=>'top', 'fill'=>'x')
+if $tk_major_ver >= 8
+ $root.add_menubar([[['File', 0],
+ ['About ... ', proc{aboutBox}, 0, '<F1>'],
+ '---',
+ ['Quit', proc{exit}, 0, 'Ctrl-Q']
+ ]])
+else
+ TkMenubar.new($root,
+ [[['File', 0],
+ ['About ... ', proc{aboutBox}, 0, '<F1>'],
+ '---',
+ ['Quit', proc{exit}, 0, 'Ctrl-Q']
+ ]]).pack('side'=>'top', 'fill'=>'x')
+end
$root.bind('F1', proc{aboutBox})
-$root.bind('Meta-q', proc{exit})
+$root.bind('Control-q', proc{exit})
=begin
TkFrame.new($root){|frame|
@@ -164,12 +175,17 @@ else
textFrame.pack('expand'=>'yes', 'fill'=>'both')
statusBar = TkFrame.new($root) {|f|
+ if $tk_version =~ /^4.*/
+ statusfont = '-*-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*'
+ else
+ statusfont = 'Helvetica 10'
+ end
$statusBarLabel = \
TkLabel.new(f, 'text'=>" ", 'relief'=>'sunken', 'bd'=>1, 'anchor'=>'w',
- 'font'=>'-*-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') \
+ 'font'=>statusfont) \
.pack('side'=>'left', 'padx'=>2, 'expand'=>'yes', 'fill'=>'both')
TkLabel.new(f, 'width'=>8, 'relief'=>'sunken', 'bd'=>1, 'anchor'=>'w',
- 'font'=>'-*-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') \
+ 'font'=>statusfont) \
.pack('side'=>'left', 'padx'=>2)
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>2)
end
@@ -178,7 +194,11 @@ end
# section titles and demo descriptions. Also define the bindings for
# tags.
-tag_title = TkTextTag.new(txt, 'font'=>'-*-Helvetica-Bold-R-Normal--*-180-*-*-*-*-*-*')
+if $tk_version =~ /^4.*/
+ tag_title = TkTextTag.new(txt, 'font'=>'-*-Helvetica-Bold-R-Normal--*-180-*-*-*-*-*-*')
+else
+ tag_title = TkTextTag.new(txt, 'font'=>'Helvetica 18 bold')
+end
# We put some "space" characters to the left and right of each demo description
# so that the descriptions are highlighted only when the mouse cursor
@@ -247,7 +267,10 @@ the demonstration. Once the demonstration window appears, you can \
click the "See Code" button to see the Ruby/Tk code that created the \
demonstration. If you wish, you can edit the code and click the \
"Rerun Demo" button in the code window to reinvoke the demonstration \
-with the modified code.
+with the modified code. \
+Don't worry about breaking the source code. \
+Your modifications are not reflected on the original file. \
+Please try many kind of changes.
Some demo scripts require the recent version of Tk library \
(e.g. Tk8.4 or later) \
@@ -256,6 +279,20 @@ required by the demo script, the demo doesn't work. \
In such a case, please re-compile tcltklib with the later Tk library \
which supports the required functions.
+If your Tk supports Ttk (Tile) extension (included or installed), \
+please try the demo of Ttk extension (sample/tkextlib/tile/demo.rb) too.
+( Probably, Ttk extension \
+#{
+begin
+ require 'tkextlib/tile'
+ "is already installed on your environment"
+rescue
+ "is not installed on your environment yet"
+end
+}\
+. )
+Ttk extension is a standard feature of Tk8.5 or later.
+
EOT
@@ -289,6 +326,8 @@ txt.insert('end', "13. A simple user interface for viewing images. (if supported
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "14. Labelled frames (if supported)\n", tag_demo, "demo-labelframe")
txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "15. The simple Themed Tk widgets (require Tile/Ttk extension)\n", tag_demo, "demo-ttkbut")
+txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "\n")
txt.insert('end', "Listboxes\n", tag_title)
@@ -299,6 +338,10 @@ txt.insert('end', "2. Colors: change the color scheme for the application.\n", "
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "3. A collection of famous sayings.\n", tag_demo, "demo-sayings")
txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "4. A multi-column list of contries. (require Tile/Ttk extension)\n", tag_demo, "demo-mclist")
+txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "5. A directory browser tree. (require Tile/Ttk extension)\n", tag_demo, "demo-tree")
+txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "\n")
txt.insert('end', "Entries and Spin-boxes\n", tag_title)
@@ -313,7 +356,9 @@ txt.insert('end',
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "4. Spin-boxes. (if supported)\n", tag_demo, "demo-spin")
txt.insert('end', " \n ", tag_demospace)
-txt.insert('end', "5. Simple Rolodex-like form.\n", tag_demo, "demo-form")
+txt.insert('end', "5. Combo-boxes. (require Tile/Ttk extension)\n", tag_demo, "demo-combo")
+txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "6. Simple Rolodex-like form.\n", tag_demo, "demo-form")
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "\n")
@@ -331,6 +376,8 @@ txt.insert('end', "5. A text widget with embedded windows. (if supported)\n", ta
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "6. A search tool built with a text widget.\n", tag_demo, "demo-search")
txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "7. Peering text widgets. (if supported)\n", tag_demo, "demo-textpeer")
+txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "\n")
txt.insert('end', "Canvases\n", tag_title)
@@ -351,31 +398,43 @@ txt.insert('end', "7. A building floor plan. (another way to create canvas items
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "8. A simple scrollable canvas.\n", tag_demo, "demo-cscroll")
txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "9. A Knight's tour of the chess board. (require Tile/Ttk extension)\n", tag_demo, "demo-knightstour")
+txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "\n")
-txt.insert('end', "Scales\n", tag_title)
+txt.insert('end', "Scales and Progress Bars\n", tag_title)
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "1. Vertical scale.\n", tag_demo.id, "demo-vscale")
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "2. Horizontal scale.\n", tag_demo.id, "demo-hscale")
txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "3. Progress bar. (require Tile/Ttk extension)\n", tag_demo.id, "demo-ttkprogress")
+txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "\n")
-txt.insert('end', "Paned Windows\n", tag_title)
+txt.insert('end', "Paned Windows and Notebooks\n", tag_title)
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "1. Horizontal paned window. (if supported)\n", tag_demo.id, "demo-paned1")
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "2. Vertical paned window. (if supported)\n", tag_demo.id, "demo-paned2")
txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "3. Themed nested panes. (require Tile/Ttk extension)\n", tag_demo.id, "demo-ttkpane")
+txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "4. Notebook widget. (require Tile/Ttk extension)\n", tag_demo.id, "demo-ttknote")
+txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "\n")
-txt.insert('end', "Menus\n", tag_title)
+txt.insert('end', "Menus and Toolbars\n", tag_title)
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "1. Menus and cascades.\n", tag_demo, "demo-menu")
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "2. Menus and cascades. (if supported)\n", tag_demo, "demo-menu84")
txt.insert('end', " \n ", tag_demospace)
-txt.insert('end', "3. Menubuttons\n", tag_demo, "demo-menubu")
+txt.insert('end', "3. Menubuttons.\n", tag_demo, "demo-menubu")
+txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "4. Themed menu buttons. (require Tile/Ttk extension)\n", tag_demo, "demo-ttkmenu")
+txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "5. Themed toolbar. (require Tile/Ttk extension)\n", tag_demo, "demo-toolbar")
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "\n")
@@ -383,9 +442,11 @@ txt.insert('end', "Common Dialogs\n", tag_title)
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "1. Message boxes.\n", tag_demo, "demo-msgbox")
txt.insert('end', " \n ", tag_demospace)
-txt.insert('end', "2. File selection dialog.\n", tag_demo, "demo-filebox")
+txt.insert('end', "2. Message boxes with detail text. (if supported)\n", tag_demo, "demo-msgbox2")
txt.insert('end', " \n ", tag_demospace)
-txt.insert('end', "3. Color picker.\n", tag_demo, "demo-clrpick")
+txt.insert('end', "3. File selection dialog.\n", tag_demo, "demo-filebox")
+txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "4. Color picker.\n", tag_demo, "demo-clrpick")
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "\n")
@@ -441,11 +502,16 @@ def showVars1(parent, *args)
end
w = TkToplevel.new(parent) {|w|
title "Variable values"
- TkLabel.new(w) {
+ base = TkFrame.new(w).pack(:fill=>:both, :expand=>true)
+ TkLabel.new(base) {
text "Variable values:"
width 20
anchor 'center'
- font '-Adobe-helvetica-medium-r-normal--*-180-*-*-*-*-*-*'
+ if $tk_version =~ /^4.*/
+ font '-Adobe-helvetica-medium-r-normal--*-180-*-*-*-*-*-*'
+ else
+ font 'Helvetica 14'
+ end
}.pack('side'=>'top', 'fill'=>'x')
len = 1
args.each{|vnam,vbody|
@@ -459,7 +525,7 @@ def showVars1(parent, *args)
.pack('side'=>'left', 'expand'=>'yes', 'fill'=>'x')
}.pack('side'=>'top', 'anchor'=>'w', 'fill'=>'x')
}
- TkButton.new(w) {
+ TkButton.new(base) {
text "OK"
command proc{w.destroy}
}.pack('side'=>'bottom', 'pady'=>2)
@@ -474,10 +540,12 @@ def showVars2(parent, *args)
rescue
end
end
- $showVarsWin[parent.path] = TkToplevel.new(parent) {|w|
+ $showVarsWin[parent.path] = TkToplevel.new(parent) {|top|
title "Variable values"
- TkLabelFrame.new(w, :text=>"Variable values:",
+ base = TkFrame.new(top).pack(:fill=>:both, :expand=>true)
+
+ TkLabelFrame.new(base, :text=>"Variable values:",
:font=>{:family=>'Helvetica', :size=>14}){|f|
args.each{|vnam,vbody|
TkGrid(TkLabel.new(f, :text=>"#{vnam}: ", :anchor=>'w'),
@@ -489,15 +557,15 @@ def showVars2(parent, *args)
f.grid_columnconfig(1, :weight=>1)
f.grid_rowconfig(100, :weight=>1)
}
- TkButton.new(w, :text=>"OK", :width=>8, :default=>:active,
- :command=>proc{w.destroy}){|b|
- w.bind('Return', proc{b.invoke})
- w.bind('Escape', proc{b.invoke})
+ TkButton.new(base, :text=>"OK", :width=>8, :default=>:active,
+ :command=>proc{top.destroy}){|b|
+ top.bind('Return', proc{b.invoke})
+ top.bind('Escape', proc{b.invoke})
b.grid(:sticky=>'e', :padx=>4, :pady=>[6, 4])
}
- w.grid_columnconfig(0, :weight=>1)
- w.grid_rowconfig(0, :weight=>1)
+ base.grid_columnconfig(0, :weight=>1)
+ base.grid_rowconfig(0, :weight=>1)
}
end
@@ -591,8 +659,27 @@ def _null_binding
end
private :_null_binding
-def eval_samplecode(code)
- Thread.new{ _null_binding.pseudo_toplevel_eval{ eval(code) } }.run
+def eval_samplecode(code, file=nil)
+ #eval(code)
+ #_null_binding.pseudo_toplevel_eval{ eval(code) }
+ #Thread.new{ _null_binding.pseudo_toplevel_eval{ eval(code) } }
+ Thread.new{
+ _null_binding.pseudo_toplevel_eval{
+ begin
+ if file
+ eval(code, binding, "(eval:#{file})")
+ else
+ eval(code)
+ end
+ rescue Exception=>e
+ #p e
+ TkBgError.show(e.class.inspect + ': ' + e.message + "\n" +
+ "\n---< backtrace of Ruby side >-----\n" +
+ e.backtrace.join("\n") +
+ "\n---< backtrace of Tk side >-------")
+ end
+ }
+ }
Tk.update
end
@@ -612,7 +699,7 @@ def invoke(txt, idx)
Tk.update
# eval(IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join, _null_binding)
# Tk.update
- eval_samplecode(IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join)
+ eval_samplecode(IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join, tag[5..-1] + '.rb')
txt.cursor(cursor)
$tag_visited.add("#{idx} linestart +1 chars", "#{idx} lineend +1 chars")
@@ -669,20 +756,32 @@ def showCode1(demo)
if $code_window == nil || TkWinfo.exist?($code_window) == false
$code_window = TkToplevel.new(nil)
f = TkFrame.new($code_window)
+
TkButton.new(f) {
text "Dismiss"
command proc{
$code_window.destroy
$code_window = nil
}
- }.pack('side'=>'left', 'expand'=>'yes', 'pady'=>2)
+ }.pack('side'=>'right', 'expand'=>'false', 'pady'=>2, 'padx'=>25)
TkButton.new(f) {
text "Rerun Demo"
# command proc{eval($code_text.get('1.0','end'), _null_binding)}
- command proc{eval_samplecode($code_text.get('1.0','end'))}
- }.pack('side'=>'left', 'expand'=>'yes', 'pady'=>2)
-# f.pack('side'=>'bottom', 'expand'=>'yes', 'fill'=>'x')
- f.pack('side'=>'bottom', 'fill'=>'x')
+ command proc{eval_samplecode($code_text.get('1.0','end'), '<viewer>')}
+ }.pack('side'=>'right', 'expand'=>'false', 'pady'=>2)
+
+ TkLabel.new(f,'text'=>'line:').pack('side'=>'left')
+ linenum =TkLabel.new(f,'text'=>'').pack('side'=>'left')
+ TkLabel.new(f,'text'=>' pos:').pack('side'=>'left')
+ posnum =TkLabel.new(f,'text'=>'').pack('side'=>'left')
+
+ $set_linenum = proc{|w|
+ line, pos = w.index('insert').split('.')
+ linenum.text = line
+ posnum.text = pos
+ }
+
+ f.pack('side'=>'bottom', 'expand'=>'true', 'fill'=>'x')
if $tk_version =~ /^4\.[01]/
s = TkScrollbar.new($code_window, 'orient'=>'vertical')
@@ -727,10 +826,21 @@ def showCode1(demo)
TkGrid.columnconfigure(f, 0, 'weight'=>1, 'minsize'=>0)
}
end
+
+ btag = TkBindTag.new
+
+ btag.bind('Key', $set_linenum, '%W')
+ btag.bind('Button', $set_linenum, '%W')
+
+ btags = $code_text.bindtags
+ btags.insert(btags.index($code_text.class) + 1, btag)
+ $code_text.bindtags = btags
+
else
$code_window.deiconify
$code_window.raise
end
+
$code_window.title("Demo code: #{file}")
$code_window.iconname(file)
# fid = open(file, 'r')
@@ -741,6 +851,9 @@ def showCode1(demo)
#$code_mark = TkTextMark.new($code_text, '1.0')
#$code_text.set_insert('1.0')
TkTextMarkInsert.new($code_text,'1.0')
+
+ $set_linenum.call($code_text)
+
fid.close
end
@@ -761,7 +874,19 @@ def showCode2(demo)
tf.grid_columnconfigure(0, :weight=>1)
bf = TkFrame.new($code_window)
-
+
+ lf = TkFrame.new(bf)
+ TkLabel.new(lf, :text=>'line:').pack(:side=>:left)
+ linenum =TkLabel.new(lf, :text=>'').pack(:side=>:left)
+ TkLabel.new(lf, :text=>' pos:').pack(:side=>:left)
+ posnum =TkLabel.new(lf, :text=>'').pack(:side=>:left)
+
+ $set_linenum = proc{|w|
+ line, pos = w.index('insert').split('.')
+ linenum.text = line
+ posnum.text = pos
+ }
+
b_dis = TkButton.new(bf, :text=>'Dismiss', :default=>:active,
:command=>proc{
$code_window.destroy
@@ -774,12 +899,12 @@ def showCode2(demo)
b_run = TkButton.new(bf, :text=>'Rerun Demo',
:command=>proc{
# eval($code_text.get('1.0','end'), _null_binding)
- eval_samplecode($code_text.get('1.0','end'))
+ eval_samplecode($code_text.get('1.0','end'), '<viewer>')
},
:image=>$image['refresh'], :compound=>:left)
- TkGrid('x', b_run, b_prn, b_dis, :padx=>4, :pady=>[6,4])
- bf.grid_columnconfigure(0, :weight=>1)
+ TkGrid(lf, 'x', b_run, b_prn, b_dis, :padx=>4, :pady=>[6,4])
+ bf.grid_columnconfigure(1, :weight=>1)
TkGrid(tf, :sticky=>'news')
TkGrid(bf, :sticky=>'ew')
@@ -792,6 +917,17 @@ def showCode2(demo)
$code_window.bindinfo('Return').each{|cmd, arg|
$code_window.bind_append('Escape', cmd, arg)
}
+
+ btag = TkBindTag.new
+
+ btag.bind('Key', $set_linenum, '%W')
+ btag.bind('Button', $set_linenum, '%W')
+ btag.bind('Configure', $set_linenum, '%W')
+
+ btags = $code_text.bindtags
+ btags.insert(btags.index($code_text.class) + 1, btag)
+ $code_text.bindtags = btags
+
else
$code_window.deiconify
$code_window.raise
@@ -803,6 +939,9 @@ def showCode2(demo)
$code_text.delete('1.0', 'end')
$code_text.insert('1.0', fid.read)
TkTextMarkInsert.new($code_text,'1.0')
+
+ $set_linenum.call($code_text)
+
fid.close
end
@@ -896,12 +1035,13 @@ end
#
def aboutBox
Tk.messageBox('icon'=>'info', 'type'=>'ok', 'title'=>'About Widget Demo',
- 'message'=>"Ruby/Tk widget demonstration Ver.1.6.0-en\n\n" +
+ 'message'=>"Ruby/Tk widget demonstration Ver.1.7.0-en\n\n" +
"based on demos of Tk8.1 -- 8.5 " +
- "( Copyright:: " +
+ "( Copyright of Tcl/Tk demos:: " +
"(c) 1996-1997 Sun Microsystems, Inc. / " +
"(c) 1997-2000 Ajuba Solutions, Inc. / " +
- "(c) 2001-2003 Donal K. Fellows )\n\n" +
+ "(c) 2001-2007 Donal K. Fellows / " +
+ "(c) 2002-2007 Daniel A. Steffen )\n\n" +
"Your Ruby & Tk Version ::\n" +
"Ruby#{RUBY_VERSION}(#{RUBY_RELEASE_DATE})[#{RUBY_PLATFORM}] / Tk#{$tk_patchlevel}#{(Tk::JAPANIZED_TK)? '-jp': ''}\n\n" +
"Ruby/Tk release date :: tcltklib #{TclTkLib::RELEASE_DATE}; tk #{Tk::RELEASE_DATE}")
@@ -923,7 +1063,7 @@ ARGV.each{|cmd|
end
#eval(IO.readlines("#{[$demo_dir, cmd].join(File::Separator)}.rb").join,
# _null_binding)
- eval_samplecode(IO.readlines("#{[$demo_dir, cmd].join(File::Separator)}.rb").join)
+ eval_samplecode(IO.readlines("#{[$demo_dir, cmd].join(File::Separator)}.rb").join, cmd + '.rb')
}
if no_launcher
$root.withdraw # hide root window
diff --git a/ext/tk/sample/demos-jp/anilabel.rb b/ext/tk/sample/demos-jp/anilabel.rb
index 97781fbe77..aee57f9f6a 100644
--- a/ext/tk/sample/demos-jp/anilabel.rb
+++ b/ext/tk/sample/demos-jp/anilabel.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# animated label widget demo (called by 'widget')
#
@@ -16,8 +17,10 @@ $anilabel_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($anilabel_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-msg = TkLabel.new($anilabel_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -26,7 +29,7 @@ msg = TkLabel.new($anilabel_demo) {
msg.pack('side'=>'top')
# frame À¸À®
-TkFrame.new($anilabel_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -45,8 +48,8 @@ TkFrame.new($anilabel_demo) {|frame|
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# label demo Íѥե졼¥àÀ¸À®
-f_left = TkLabelFrame.new($anilabel_demo, :text=>'Scrolling Texts')
-f_right = TkLabelFrame.new($anilabel_demo, :text=>'GIF Image')
+f_left = TkLabelFrame.new(base_frame, :text=>'Scrolling Texts')
+f_right = TkLabelFrame.new(base_frame, :text=>'GIF Image')
Tk.pack(f_left, f_right, 'side'=>'left', 'expand'=>'yes', 'fill'=>'both',
'padx'=>10, 'pady'=>10)
diff --git a/ext/tk/sample/demos-jp/aniwave.rb b/ext/tk/sample/demos-jp/aniwave.rb
index 81e2d76b30..8fa14f65fe 100644
--- a/ext/tk/sample/demos-jp/aniwave.rb
+++ b/ext/tk/sample/demos-jp/aniwave.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# animated wave demo (called by 'widget')
#
@@ -16,8 +17,10 @@ $aniwave_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($aniwave_demo).pack(:fill=>:both, :expand=>true)
+
# create label
-msg = TkLabel.new($aniwave_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -26,7 +29,7 @@ msg = TkLabel.new($aniwave_demo) {
msg.pack('side'=>'top')
# create frame
-TkFrame.new($aniwave_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -59,6 +62,7 @@ class AnimatedWaveDemo
@backupCoords = []
n = 0
(-10..300).step(5){|n| @waveCoords << [n, 100]; @backupCoords << [n, 100] }
+ n = 305
@waveCoords << [n, 0]; @backupCoords << [n, 0]
@waveCoords << [n+5, 200]; @backupCoords << [n+5, 200]
@coordsLen = @waveCoords.length
@@ -113,4 +117,4 @@ class AnimatedWaveDemo
end
# Start the animation processing
-AnimatedWaveDemo.new($aniwave_demo, :left).move
+AnimatedWaveDemo.new(base_frame, :left).move
diff --git a/ext/tk/sample/demos-jp/arrow.rb b/ext/tk/sample/demos-jp/arrow.rb
index 477a0abf6f..3c49e67b09 100644
--- a/ext/tk/sample/demos-jp/arrow.rb
+++ b/ext/tk/sample/demos-jp/arrow.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# arrowhead widget demo (called by 'widget')
#
@@ -73,11 +74,19 @@ def arrowSetup(c)
'arrow'=>'both', 'arrowshape'=>v.smallTips)
TkcText.new(c, v.x2-5*v.b, tmp+5, 'text'=>v.b, 'anchor'=>'n')
- TkcText.new(c, v.x1, 310, 'text'=>"'width'=>#{v.width}", 'anchor'=>'w',
- 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*')
- TkcText.new(c, v.x1, 330,
- 'text'=>"'arrowshape'=>[#{v.a}, #{v.b}, #{v.c}]", 'anchor'=>'w',
- 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*')
+ if $tk_version =~ /^4.*/
+ TkcText.new(c, v.x1, 310, 'text'=>"'width'=>#{v.width}", 'anchor'=>'w',
+ 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*')
+ TkcText.new(c, v.x1, 330,
+ 'text'=>"'arrowshape'=>[#{v.a}, #{v.b}, #{v.c}]",'anchor'=>'w',
+ 'font'=>'-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*')
+ else
+ TkcText.new(c, v.x1, 310, 'text'=>"'width'=>#{v.width}", 'anchor'=>'w',
+ 'font'=>'Helvetica 18')
+ TkcText.new(c, v.x1, 330,
+ 'text'=>"'arrowshape'=>[#{v.a}, #{v.b}, #{v.c}]",
+ 'anchor'=>'w', 'font'=>'Helvetica 18')
+ end
v.count += 1
end
@@ -95,14 +104,16 @@ $arrow_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($arrow_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-TkLabel.new($arrow_demo, 'font'=>$font, 'wraplength'=>'5i', 'justify'=>'left',
+TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'5i', 'justify'=>'left',
'text'=>"¤³¤Î widget ¤Ç¡¢¥­¥ã¥ó¥Ð¥¹¤Ç»È¤ï¤ì¤ë¥é¥¤¥ó¤Ë¤Ä¤¤¤ÆÍÍ¡¹¤ÊÉý¤äÌð°õ¤ÎƬ¤Î·Á¤ò»î¤·¤Æ¤ß¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£Àþ¤ÎÉý¤äÌð°õ¤Î·Á¤òÊѤ¨¤ë¤Ë¤Ï¡¢³ÈÂ礵¤ì¤¿Ìð°õ¤Ë¤Ä¤¤¤Æ¤¤¤ë 3¤Ä¤Î»Í³Ñ¤ò¥É¥é¥Ã¥°¤·¤Æ¤¯¤À¤µ¤¤¡£±¦Â¦¤ÎÌð°õ¤ÏÉáÄ̤ÎÂ礭¤µ¤Ç¤Î¥µ¥ó¥×¥ë¤ò¼¨¤·¤Æ¤¤¤Þ¤¹¡£²¼¤Î¥Æ¥­¥¹¥È¤Ï¥é¥¤¥ó¥¢¥¤¥Æ¥à¤ËÂФ¹¤ëÀßÄꥪ¥×¥·¥ç¥ó¤Ç¤¹¡£"){
pack('side'=>'top')
}
# frame À¸À®
-$arrow_buttons = TkFrame.new($arrow_demo) {|frame|
+$arrow_buttons = TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -121,7 +132,7 @@ $arrow_buttons = TkFrame.new($arrow_demo) {|frame|
$arrow_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# canvas ÀßÄê
-$arrow_canvas = TkCanvas.new($arrow_demo, 'width'=>500, 'height'=>350,
+$arrow_canvas = TkCanvas.new(base_frame, 'width'=>500, 'height'=>350,
'relief'=>'sunken', 'borderwidth'=>2)
$arrow_canvas.pack('expand'=>'yes', 'fill'=>'both')
diff --git a/ext/tk/sample/demos-jp/bind.rb b/ext/tk/sample/demos-jp/bind.rb
index e1e23b9893..a1bcfdd2e7 100644
--- a/ext/tk/sample/demos-jp/bind.rb
+++ b/ext/tk/sample/demos-jp/bind.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# text (tag bindings) widget demo (called by 'widget')
#
@@ -15,8 +16,10 @@ $bind_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($bind_demo).pack(:fill=>:both, :expand=>true)
+
# frame À¸À®
-TkFrame.new($bind_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -40,14 +43,14 @@ def tag_binding_for_bind_demo(tag, enter_style, leave_style)
end
# text À¸À®
-TkText.new($bind_demo){|t|
+txt = TkText.new(base_frame){|t|
# À¸À®
setgrid 'true'
- width 60
- height 24
+ #width 60
+ #height 24
font $font
wrap 'word'
- TkScrollbar.new($bind_demo) {|s|
+ TkScrollbar.new(base_frame) {|s|
pack('side'=>'right', 'fill'=>'y')
command proc{|*args| t.yview(*args)}
t.yscrollcommand proc{|first,last| s.set first,last}
@@ -91,35 +94,32 @@ TkText.new($bind_demo){|t|
}
d1.bind('1',
proc{
- eval(`cat #{[$demo_dir,'items.rb'].join(File::Separator)}`,
- _null_binding)
+ eval_samplecode(`cat #{[$demo_dir,'items.rb'].join(File::Separator)}`, 'items.rb')
})
d2.bind('1',
proc{
- eval(`cat #{[$demo_dir,'plot.rb'].join(File::Separator)}`,
- _null_binding)
+ eval_samplecode(`cat #{[$demo_dir,'plot.rb'].join(File::Separator)}`, 'plot.rb')
})
d3.bind('1',
proc{
- eval(`cat #{[$demo_dir,'ctext.rb'].join(File::Separator)}`,
- _null_binding)
+ eval_samplecode(`cat #{[$demo_dir,'ctext.rb'].join(File::Separator)}`, 'ctext.rb')
})
d4.bind('1',
proc{
- eval(`cat #{[$demo_dir,'arrow.rb'].join(File::Separator)}`,
- _null_binding)
+ eval_samplecode(`cat #{[$demo_dir,'arrow.rb'].join(File::Separator)}`, 'arrow.rb')
})
d5.bind('1',
proc{
- eval(`cat #{[$demo_dir,'ruler.rb'].join(File::Separator)}`,
- _null_binding)
+ eval_samplecode(`cat #{[$demo_dir,'ruler.rb'].join(File::Separator)}`, 'ruler.rb')
})
d6.bind('1',
proc{
- eval(`cat #{[$demo_dir,'cscroll.rb'].join(File::Separator)}`,
- _null_binding)
+ eval_samplecode(`cat #{[$demo_dir,'cscroll.rb'].join(File::Separator)}`, 'cscroll.rb')
})
TkTextMarkInsert.new(t, '0.0')
configure('state','disabled')
}
+
+txt.width 60
+txt.height 24
diff --git a/ext/tk/sample/demos-jp/bitmap.rb b/ext/tk/sample/demos-jp/bitmap.rb
index b71c67d3fd..b6b0e54bbe 100644
--- a/ext/tk/sample/demos-jp/bitmap.rb
+++ b/ext/tk/sample/demos-jp/bitmap.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# bitmap widget demo (called by 'widget')
#
@@ -18,7 +19,7 @@ def bitmapRow(w,*args)
TkFrame.new(row){|base|
pack('side'=>'left', 'fill'=>'both', 'pady'=>'.25c', 'padx'=>'.25c')
TkLabel.new(base, 'text'=>bitmap, 'width'=>9).pack('side'=>'bottom')
- TkLabel.new(base, 'bitmap'=>bitmap).pack('side'=>'bottom')
+ Tk::Label.new(base, 'bitmap'=>bitmap).pack('side'=>'bottom')
}
end
}
@@ -37,14 +38,16 @@ $bitmap_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($bitmap_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-TkLabel.new($bitmap_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left',
+TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left',
'text'=>"¤³¤Î¥¦¥£¥ó¥É¥¦¤Ë¤Ï¡¢Tk ¤ËÁȤ߹þ¤Þ¤ì¤¿¤¹¤Ù¤Æ¤Î¥Ó¥Ã¥È¥Þ¥Ã¥×¤¬¡¢¤½¤ì¤é¤Î̾Á°¤È¶¦¤Ëɽ¼¨¤µ¤ì¤Æ¤¤¤Þ¤¹¡£Tcl ¤Î¥¹¥¯¥ê¥×¥ÈÃæ¤Ç¤Ï¡¢¤½¤ì¤¾¤ì¤Î̾Á°¤òÍѤ¤¤Æ»²¾È¤·¤Þ¤¹¡£"){
pack('side'=>'top')
}
# frame À¸À®
-$bitmap_buttons = TkFrame.new($bitmap_demo) {|frame|
+$bitmap_buttons = TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -63,7 +66,7 @@ $bitmap_buttons = TkFrame.new($bitmap_demo) {|frame|
$bitmap_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# frame ÀßÄê
-TkFrame.new($bitmap_demo){|f|
+TkFrame.new(base_frame){|f|
bitmapRow(f,'error','gray25','gray50','hourglass')
bitmapRow(f,'info','question','questhead','warning')
pack('side'=>'top', 'expand'=>'yes', 'fill'=>'both')
diff --git a/ext/tk/sample/demos-jp/button.rb b/ext/tk/sample/demos-jp/button.rb
index 20f8cae299..18e42008c9 100644
--- a/ext/tk/sample/demos-jp/button.rb
+++ b/ext/tk/sample/demos-jp/button.rb
@@ -1,6 +1,8 @@
+# -*- coding: euc-jp -*-
#
# button widget demo (called by 'widget')
#
+#
# toplevel widget ¤¬Â¸ºß¤¹¤ì¤Ðºï½ü¤¹¤ë
if defined?($button_demo) && $button_demo
@@ -25,7 +27,7 @@ msg = TkLabel.new($button_demo) {
msg.pack('side'=>'top')
# frame À¸À®
-$button_buttons = TkFrame.new($button_demo) {|frame|
+$button_buttons = Tk::Frame.new($button_demo) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
diff --git a/ext/tk/sample/demos-jp/check.rb b/ext/tk/sample/demos-jp/check.rb
index be675b9042..b953e7f623 100644
--- a/ext/tk/sample/demos-jp/check.rb
+++ b/ext/tk/sample/demos-jp/check.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# checkbutton widget demo (called by 'widget')
#
@@ -15,8 +16,10 @@ $check_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($check_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-msg = TkLabel.new($check_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -30,7 +33,7 @@ brakes = TkVariable.new(0)
sober = TkVariable.new(0)
# frame À¸À®
-TkFrame.new($check_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -51,7 +54,7 @@ TkFrame.new($check_demo) {|frame|
TkButton.new(frame) {
text 'ÊÑ¿ô»²¾È'
command proc{
- showVars($check_demo,
+ showVars(base_frame,
['wipers', wipers], ['brakes', brakes], ['sober', sober])
}
}.pack('side'=>'left', 'expand'=>'yes')
@@ -60,8 +63,8 @@ TkFrame.new($check_demo) {|frame|
# checkbutton À¸À®
-[ TkCheckButton.new($check_demo, 'text'=>'¥ï¥¤¥Ñ¡¼ OK', 'variable'=>wipers),
- TkCheckButton.new($check_demo, 'text'=>'¥Ö¥ì¡¼¥­ OK', 'variable'=>brakes),
- TkCheckButton.new($check_demo, 'text'=>'±¿Å¾¼ê ÁÇÌÌ', 'variable'=>sober)
+[ TkCheckButton.new(base_frame, 'text'=>'¥ï¥¤¥Ñ¡¼ OK', 'variable'=>wipers),
+ TkCheckButton.new(base_frame, 'text'=>'¥Ö¥ì¡¼¥­ OK', 'variable'=>brakes),
+ TkCheckButton.new(base_frame, 'text'=>'±¿Å¾¼ê ÁÇÌÌ', 'variable'=>sober)
].each{|w| w.relief('flat'); w.pack('side'=>'top', 'pady'=>2, 'anchor'=>'w')}
diff --git a/ext/tk/sample/demos-jp/check2.rb b/ext/tk/sample/demos-jp/check2.rb
index f681a4d684..7f7cb9e932 100644
--- a/ext/tk/sample/demos-jp/check2.rb
+++ b/ext/tk/sample/demos-jp/check2.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# checkbutton widget demo2 (called by 'widget')
#
@@ -15,8 +16,10 @@ $check2_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($check2_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-msg = TkLabel.new($check2_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -31,7 +34,7 @@ brakes = TkVariable.new(0)
sober = TkVariable.new(0)
# frame À¸À®
-TkFrame.new($check2_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkGrid(TkFrame.new(frame, :height=>2, :relief=>:sunken, :bd=>2),
:columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
TkGrid('x',
@@ -59,15 +62,15 @@ TkFrame.new($check2_demo) {|frame|
# checkbutton À¸À®
-TkCheckButton.new($check2_demo, :text=>'°ÂÁ´À­¸¡ºº', :variable=>safety,
+TkCheckButton.new(base_frame, :text=>'°ÂÁ´À­¸¡ºº', :variable=>safety,
:relief=>:flat, :onvalue=>'all', :offvalue=>'none',
:tristatevalue=>'partial'){
pack('side'=>'top', 'pady'=>2, 'anchor'=>'w')
}
-[ TkCheckButton.new($check2_demo, 'text'=>'¥ï¥¤¥Ñ¡¼ OK', 'variable'=>wipers),
- TkCheckButton.new($check2_demo, 'text'=>'¥Ö¥ì¡¼¥­ OK', 'variable'=>brakes),
- TkCheckButton.new($check2_demo, 'text'=>'±¿Å¾¼ê ÁÇÌÌ', 'variable'=>sober)
+[ TkCheckButton.new(base_frame, 'text'=>'¥ï¥¤¥Ñ¡¼ OK', 'variable'=>wipers),
+ TkCheckButton.new(base_frame, 'text'=>'¥Ö¥ì¡¼¥­ OK', 'variable'=>brakes),
+ TkCheckButton.new(base_frame, 'text'=>'±¿Å¾¼ê ÁÇÌÌ', 'variable'=>sober)
].each{|w|
w.relief('flat')
w.pack('side'=>'top', 'padx'=>15, 'pady'=>2, 'anchor'=>'w')
diff --git a/ext/tk/sample/demos-jp/clrpick.rb b/ext/tk/sample/demos-jp/clrpick.rb
index de8cd80fcd..ce6b99ab94 100644
--- a/ext/tk/sample/demos-jp/clrpick.rb
+++ b/ext/tk/sample/demos-jp/clrpick.rb
@@ -1,6 +1,9 @@
+# -*- coding: euc-jp -*-
#
# widget demo prompts the user to select a color (called by 'widget')
#
+# Note: don't support ttk_wrapper. work with standard widgets only.
+#
# toplevel widget ¤¬Â¸ºß¤¹¤ì¤Ðºï½ü¤¹¤ë
if defined?($clrpick_demo) && $clrpick_demo
@@ -16,12 +19,15 @@ $clrpick_demo = TkToplevel.new {|w|
}
# label À¸À®
-TkLabel.new($clrpick_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left',
+#TkLabel.new($clrpick_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left',
+Tk::Label.new($clrpick_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left',
'text'=>"°Ê²¼¤Î¥Ü¥¿¥ó¤ò²¡¤·¤Æ¡¢¤³¤Î¥¦¥£¥ó¥É¥¦¾å¤Ë¤¢¤ë¥¦¥£¥¸¥§¥Ã¥È¤ÎÁ°·Ê¿§¤ÈÇØ·Ê¿§¤òÁªÂò¤·¤Æ²¼¤µ¤¤¡£").pack('side'=>'top')
# frame À¸À®
-TkFrame.new($clrpick_demo) {|frame|
- TkButton.new(frame) {
+# TkFrame.new($clrpick_demo) {|frame|
+Tk::Frame.new($clrpick_demo) {|frame|
+ # TkButton.new(frame) {
+ Tk::Button.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
command proc{
@@ -31,20 +37,23 @@ TkFrame.new($clrpick_demo) {|frame|
}
}.pack('side'=>'left', 'expand'=>'yes')
- TkButton.new(frame) {
+ # TkButton.new(frame) {
+ Tk::Button.new(frame) {
text '¥³¡¼¥É»²¾È'
command proc{showCode 'clrpick'}
}.pack('side'=>'left', 'expand'=>'yes')
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# button À¸À®
-TkButton.new($clrpick_demo, 'text'=>'ÇØ·Ê¿§¤òÀßÄê ...') {|b|
+# TkButton.new($clrpick_demo, 'text'=>'ÇØ·Ê¿§¤òÀßÄê ...') {|b|
+Tk::Button.new($clrpick_demo, 'text'=>'ÇØ·Ê¿§¤òÀßÄê ...') {|b|
command(proc{setColor $clrpick_demo, b, 'background',
['background', 'highlightbackground']})
pack('side'=>'top', 'anchor'=>'c', 'pady'=>'2m')
}
-TkButton.new($clrpick_demo, 'text'=>'Á°·Ê¿§¤òÀßÄê ...') {|b|
+# TkButton.new($clrpick_demo, 'text'=>'Á°·Ê¿§¤òÀßÄê ...') {|b|
+Tk::Button.new($clrpick_demo, 'text'=>'Á°·Ê¿§¤òÀßÄê ...') {|b|
command(proc{setColor $clrpick_demo, b, 'foreground', ['foreground']})
pack('side'=>'top', 'anchor'=>'c', 'pady'=>'2m')
}
diff --git a/ext/tk/sample/demos-jp/colors.rb b/ext/tk/sample/demos-jp/colors.rb
index c6128f9c00..91817a947b 100644
--- a/ext/tk/sample/demos-jp/colors.rb
+++ b/ext/tk/sample/demos-jp/colors.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# listbox widget demo 'colors' (called by 'widget')
#
@@ -15,8 +16,10 @@ $colors_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($colors_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-msg = TkLabel.new($colors_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -25,7 +28,7 @@ msg = TkLabel.new($colors_demo) {
msg.pack('side'=>'top')
# frame À¸À®
-TkFrame.new($colors_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -45,7 +48,7 @@ TkFrame.new($colors_demo) {|frame|
# frame À¸À®
colors_lbox = nil
-TkFrame.new($colors_demo, 'borderwidth'=>10) {|w|
+TkFrame.new(base_frame, 'borderwidth'=>10) {|w|
s = TkScrollbar.new(w)
colors_lbox = TkListbox.new(w) {
setgrid 1
@@ -58,7 +61,15 @@ TkFrame.new($colors_demo, 'borderwidth'=>10) {|w|
colors_lbox.pack('side'=>'left', 'expand'=>1, 'fill'=>'both')
}.pack('side'=>'top', 'expand'=>'yes', 'fill'=>'y')
-colors_lbox.bind('Double-1', proc{TkPalette.setPalette TkSelection.get})
+#colors_lbox.bind('Double-1', proc{TkPalette.setPalette TkSelection.get})
+colors_lbox.bind('Double-1', proc{
+ begin
+ TkPalette.setPalette TkSelection.get
+ rescue => e
+ p e
+ Tk.tk_call_without_enc('destroy', '.___tk_set_palette')
+ end
+ })
ins_data = [
'gray60','gray70','gray80','gray85','gray90','gray95',
diff --git a/ext/tk/sample/demos-jp/combo.rb b/ext/tk/sample/demos-jp/combo.rb
new file mode 100644
index 0000000000..da00d712ba
--- /dev/null
+++ b/ext/tk/sample/demos-jp/combo.rb
@@ -0,0 +1,98 @@
+# -*- coding: euc-jp -*-
+#
+# combo.rb --
+#
+# This demonstration script creates several combobox widgets.
+#
+# based on "Id: combo.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp"
+
+if defined?($combo_demo) && $combo_demo
+ $combo_demo.destroy
+ $combo_demo = nil
+end
+
+$combo_demo = TkToplevel.new {|w|
+ title("Combobox Demonstration")
+ iconname("combo")
+ positionWindow(w)
+}
+
+base_frame = TkFrame.new($combo_demo).pack(:fill=>:both, :expand=>true)
+
+Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'5i', :justify=>:left,
+ :text=><<EOL).pack(:side=>:top, :fill=>:x)
+°Ê²¼¤Ç¤Ï3¼ïÎà¤Î¥³¥ó¥Ü¥Ü¥Ã¥¯¥¹¤¬É½¼¨¤µ¤ì¤Æ¤¤¤Þ¤¹¡¥\
+ºÇ½é¤Î¤â¤Î¤Ï¡¤¥¨¥ó¥È¥ê¥¦¥£¥¸¥§¥Ã¥È¤ÈƱ¤¸Íͤˡ¤\
+¥Ý¥¤¥ó¥È¤·¤¿¤ê¡¤¥¯¥ê¥Ã¥¯¤·¤¿¤ê¡¤¥¿¥¤¥×¤·¤¿¤ê¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡¥\
+¤Þ¤¿¡¤Return¥­¡¼¤òÆþÎϤ¹¤ì¤Ð¸½ºß¤ÎÃͤ¬¥ê¥¹¥È¤ËÄɲ䵤졤\
+¥É¥í¥Ã¥×¥À¥¦¥ó¥ê¥¹¥È¤«¤éÁªÂò¤¹¤ë¤³¤È¤¬¤Ç¤­¤ë¤è¤¦¤Ë¤Ê¤ê¤Þ¤¹¡¥\
+¢­(²¼¸þ¤­Ìð°õ)¥­¡¼¤ò²¡¤·¤ÆÉ½¼¨¤µ¤ì¤¿¥ê¥¹¥È¤«¤é\
+Ìð°õ¥­¡¼¤Ç¾¤Î¸õÊä¤òÁª¤ó¤ÇReturn¥­¡¼¤ò²¡¤»¤Ð¡¤ÃͤòÁªÂò¤Ç¤­¤Þ¤¹¡¥\
+2ÈÖÌܤΥ³¥ó¥Ü¥Ü¥Ã¥¯¥¹¤ÏÆÃÄê¤ÎÃͤ˸ÇÄꤵ¤ì¤Æ¤ª¤ê¡¤°ìÀÚÊѹ¹¤Ç¤­¤Þ¤»¤ó¡¥\
+3ÈÖÌܤΤâ¤Î¤Ï¥ª¡¼¥¹¥È¥é¥ê¥¢¤ÎÅԻԤΥɥí¥Ã¥×¥À¥¦¥ó¥ê¥¹¥È¤«¤é\
+ÁªÂò¤¹¤ë¤³¤È¤À¤±¤¬²Äǽ¤È¤Ê¤Ã¤Æ¤¤¤Þ¤¹¡¥
+EOL
+
+## variables
+firstValue = TkVariable.new
+secondValue = TkVariable.new
+ozCity = TkVariable.new
+
+## See Code / Dismiss buttons
+Ttk::Frame.new(base_frame) {|frame|
+ sep = Ttk::Separator.new(frame)
+ Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
+ TkGrid('x',
+ Ttk::Button.new(frame, :text=>'ÊÑ¿ô»²¾È',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{
+ showVars(base_frame,
+ ['firstVariable', firstValue],
+ ['secondVariable', secondValue],
+ ['ozCity', ozCity])
+ }),
+ Ttk::Button.new(frame, :text=>'¥³¡¼¥É»²¾È',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{showCode 'combo'}),
+ Ttk::Button.new(frame, :text=>'ÊĤ¸¤ë',
+ :image=>$image['delete'], :compound=>:left,
+ :command=>proc{
+ $combo_demo.destroy
+ $combo_demo = nil
+ }),
+ :padx=>4, :pady=>4)
+ grid_columnconfigure(0, :weight=>1)
+ pack(:side=>:bottom, :fill=>:x)
+}
+
+frame = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true)
+
+australianCities = [
+ '¥­¥ã¥ó¥Ù¥é', '¥·¥É¥Ë¡¼', '¥á¥ë¥Ü¥ë¥ó', '¥Ñ¡¼¥¹', '¥¢¥Ç¥ì¡¼¥É',
+ '¥Ö¥ê¥¹¥Ù¡¼¥ó', '¥Û¥Ð¡¼¥È', '¥À¡¼¥¦¥£¥ó', '¥¢¥ê¥¹ ¥¹¥×¥ê¥ó¥°¥¹'
+]
+
+
+secondValue.value = 'Êѹ¹ÉÔ²Ä'
+ozCity.value = '¥·¥É¥Ë¡¼'
+
+Tk.pack(Ttk::Labelframe.new(frame, :text=>'Fully Editable'){|f|
+ Ttk::Combobox.new(f, :textvariable=>firstValue){|b|
+ b.bind('Return', '%W'){|w|
+ w.values <<= w.value unless w.values.include?(w.value)
+ }
+ }.pack(:pady=>5, :padx=>10)
+ },
+
+ Ttk::LabelFrame.new(frame, :text=>'Disabled'){|f|
+ Ttk::Combobox.new(f, :textvariable=>secondValue, :state=>:disabled) .
+ pack(:pady=>5, :padx=>10)
+ },
+
+ Ttk::LabelFrame.new(frame, :text=>'Defined List Only'){|f|
+ Ttk::Combobox.new(f, :textvariable=>ozCity, :state=>:readonly,
+ :values=>australianCities) .
+ pack(:pady=>5, :padx=>10)
+ },
+
+ :side=>:top, :pady=>5, :padx=>10)
diff --git a/ext/tk/sample/demos-jp/cscroll.rb b/ext/tk/sample/demos-jp/cscroll.rb
index 0d6db69af6..845952679a 100644
--- a/ext/tk/sample/demos-jp/cscroll.rb
+++ b/ext/tk/sample/demos-jp/cscroll.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# simple scrollable canvas widget demo (called by 'widget')
#
@@ -15,14 +16,16 @@ $cscroll_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($cscroll_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-TkLabel.new($cscroll_demo, 'font'=>$font, 'wraplength'=>'4i',
+TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'4i',
'justify'=>'left', 'text'=>"¤³¤Î¥¦¥£¥ó¥É¥¦¤Ë¤Ï¥¹¥¯¥í¡¼¥ë¥Ð¡¼¤ä¥Þ¥¦¥¹¤Î¥Ü¥¿¥ó2 ¤Ç¥¹¥¯¥í¡¼¥ë¤Ç¤­¤ë¥­¥ã¥ó¥Ð¥¹ widget ¤¬É½¼¨¤µ¤ì¤Æ¤¤¤Þ¤¹¡£»Í³Ñ¤Î¾å¤Ç¥Ü¥¿¥ó1 ¤ò¥¯¥ê¥Ã¥¯¤¹¤ë¤È¡¢¤½¤Î¥¤¥ó¥Ç¥Ã¥¯¥¹¤¬É¸½à½ÐÎϤ˽ÐÎϤµ¤ì¤Þ¤¹¡£"){
pack('side'=>'top')
}
# frame À¸À®
-$cscroll_buttons = TkFrame.new($cscroll_demo) {|frame|
+$cscroll_buttons = TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -42,7 +45,7 @@ $cscroll_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# frame ÀßÄê
unless $tk_version =~ /^4\.[01]/
- $cscroll_grid = TkFrame.new($cscroll_demo) {
+ $cscroll_grid = TkFrame.new(base_frame) {
pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>1)
}
TkGrid.rowconfigure($cscroll_grid, 0, 'weight'=>1, 'minsize'=>0)
@@ -50,7 +53,7 @@ unless $tk_version =~ /^4\.[01]/
end
# canvas ÀßÄê
-$cscroll_canvas = TkCanvas.new($cscroll_demo,
+$cscroll_canvas = TkCanvas.new(base_frame,
'relief'=>'sunken', 'borderwidth'=>2,
'scrollregion'=>['-11c', '-11c', '50c', '20c']
) {|c|
@@ -61,7 +64,7 @@ $cscroll_canvas = TkCanvas.new($cscroll_demo,
'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news')
end
- TkScrollbar.new($cscroll_demo, 'command'=>proc{|*args| c.yview(*args)}) {|vs|
+ TkScrollbar.new(base_frame, 'command'=>proc{|*args| c.yview(*args)}) {|vs|
c.yscrollcommand(proc{|first,last| vs.set first,last})
if $tk_version =~ /^4\.[01]/
pack('side'=>'right', 'fill'=>'y')
@@ -71,7 +74,7 @@ $cscroll_canvas = TkCanvas.new($cscroll_demo,
end
}
- TkScrollbar.new($cscroll_demo, 'orient'=>'horiz',
+ TkScrollbar.new(base_frame, 'orient'=>'horiz',
'command'=>proc{|*args| c.xview(*args)}) {|hs|
c.xscrollcommand(proc{|first,last| hs.set first,last})
if $tk_version =~ /^4\.[01]/
diff --git a/ext/tk/sample/demos-jp/ctext.rb b/ext/tk/sample/demos-jp/ctext.rb
index 66e1fe8107..05ca732cfd 100644
--- a/ext/tk/sample/demos-jp/ctext.rb
+++ b/ext/tk/sample/demos-jp/ctext.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# Canvas Text widget demo (called by 'widget')
#
@@ -15,8 +16,10 @@ $ctext_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($ctext_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-TkLabel.new($ctext_demo, 'font'=>$font, 'wraplength'=>'5i', 'justify'=>'left',
+TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'5i', 'justify'=>'left',
'text'=>"¤³¤Î¥¦¥£¥ó¥É¥¦¤Ë¤Ï¥­¥ã¥ó¥Ð¥¹widget¤Î¥Æ¥­¥¹¥Èµ¡Ç½¤ò¥Ç¥â¤¹¤ë¤¿¤á¤Î¥Æ¥­¥¹¥Èʸ»úÎó¤¬É½¼¨¤µ¤ì¤Æ¤¤¤Þ¤¹¡£¥Þ¥¦¥¹¤ò»Í³Ñ¤ÎÃæ¤Ë»ý¤Ã¤Æ¤¤¤­¡¢¥¯¥ê¥Ã¥¯¤¹¤ë¤È°ÌÃÖ¤®¤áÍѤÎÅÀ¤«¤é¤ÎÁêÂаÌÃÖ¤òÊѤ¨¤¿¤ê¡¢¹Ô·¤¨¤òÊѤ¨¤¿¤ê¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£¤Þ¤¿°Ê²¼¤Î¤è¤¦¤ÊÊÔ½¸¤Î¤¿¤á¤Î´Êñ¤Ê¥Ð¥¤¥ó¥Ç¥£¥ó¥°¤ò¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤Þ¤¹¡£
1. ¥Þ¥¦¥¹¤ò»ý¤Ã¤Æ¤¤¤­¡¢¥¯¥ê¥Ã¥¯¤·¡¢ÆþÎϤǤ­¤Þ¤¹¡£
@@ -28,7 +31,7 @@ TkLabel.new($ctext_demo, 'font'=>$font, 'wraplength'=>'5i', 'justify'=>'left',
}
# frame À¸À®
-$ctext_buttons = TkFrame.new($ctext_demo) {|frame|
+$ctext_buttons = TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -47,24 +50,33 @@ $ctext_buttons = TkFrame.new($ctext_demo) {|frame|
$ctext_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# canvas À¸À®
-$ctext_canvas = TkCanvas.new($ctext_demo, 'relief'=>'flat',
+$ctext_canvas = TkCanvas.new(base_frame, 'relief'=>'flat',
'borderwidth'=>0, 'width'=>500, 'height'=>350)
$ctext_canvas.pack('side'=>'top', 'expand'=>'yes', 'fill'=>'both')
# font ÀßÄê
-textFont = '-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*'
+if $tk_version =~ /^4.*/
+ textFont = '-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*'
+else
+ textFont = 'Helvetica 24'
+end
# canvas ÀßÄê
TkcRectangle.new($ctext_canvas, 245, 195, 255, 205,
'outline'=>'black', 'fill'=>'red')
+ctag_text_param = {
+ 'text'=>"¤³¤ì¤Ï¥­¥ã¥ó¥Ð¥¹widget¤Î¥Æ¥­¥¹¥Èµ¡Ç½¤ò¥Ç¥â¤¹¤ë¤¿¤á¤Îʸ»úÎó¤Ç¤¹¡£\n¾å¤Ç½Ò¤Ù¤¿¤è¤¦¤ÊÊÔ½¸¤ò²Äǽ¤È¤¹¤ë¤¿¤á¤Î¥Ð¥¤¥ó¥Ç¥£¥ó¥°¤ò»Ü¤·¤Æ¤¤¤Þ¤¹¡£",
+ 'width'=>440, 'anchor'=>'n', 'justify'=>'left'
+}
+if $tk_version =~ /^4.*/
+ ctag_text_param['font'] = '-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*'
+ ctag_text_param['kanjifont'] = '-*-r-*--24-*-jisx0208.1983-0'
+else
+ ctag_text_param['font'] = 'Helvetica 24'
+end
$ctag_text = TkcTag.new($ctext_canvas)
-$ctag_text.withtag(TkcText.new($ctext_canvas, 250, 200,
- 'text'=>"¤³¤ì¤Ï¥­¥ã¥ó¥Ð¥¹widget¤Î¥Æ¥­¥¹¥Èµ¡Ç½¤ò¥Ç¥â¤¹¤ë¤¿¤á¤Îʸ»úÎó¤Ç¤¹¡£\n¾å¤Ç½Ò¤Ù¤¿¤è¤¦¤ÊÊÔ½¸¤ò²Äǽ¤È¤¹¤ë¤¿¤á¤Î¥Ð¥¤¥ó¥Ç¥£¥ó¥°¤ò»Ü¤·¤Æ¤¤¤Þ¤¹¡£",
- 'width'=>440, 'anchor'=>'n',
- 'font'=>'-*-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*',
- 'kanjifont'=>'-*-r-*--24-*-jisx0208.1983-0',
- 'justify'=>'left') )
+$ctag_text.withtag(TkcText.new($ctext_canvas, 250, 200, ctag_text_param))
$ctag_text.bind('1', proc{|x,y| textB1Press $ctext_canvas,x,y}, "%x %y")
$ctag_text.bind('B1-Motion', proc{|x,y| textB1Move $ctext_canvas,x,y}, "%x %y")
@@ -106,9 +118,14 @@ mkTextConfig $ctext_canvas, x+60, y+60, 'anchor', 'nw', color
item = TkcRectangle.new($ctext_canvas, x+40, y+40, x+50, y+50,
'outline'=>'black', 'fill'=>'red')
item.bind('1', proc{$ctag_text.configure 'anchor', 'center'})
-TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Text Position', 'anchor'=>'s',
- 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*',
- 'fill'=>'brown')
+if $tk_version =~ /^4.*/
+ TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Text Position',
+ 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*',
+ 'anchor'=>'s', 'fill'=>'brown')
+else
+ TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Text Position',
+ 'font'=>'Times 24', 'anchor'=>'s', 'fill'=>'brown')
+end
# Lastly, create some items that allow the text's justification to be
# changed.
@@ -119,9 +136,14 @@ color = 'SeaGreen2'
mkTextConfig $ctext_canvas, x, y, 'justify', 'left', color
mkTextConfig $ctext_canvas, x+30, y, 'justify', 'center', color
mkTextConfig $ctext_canvas, x+60, y, 'justify', 'right', color
-TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Justification', 'anchor'=>'s',
- 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*',
- 'fill'=>'brown')
+if $tk_version =~ /^4.*/
+ TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Justification',
+ 'font'=>'-*-times-medium-r-normal--*-240-*-*-*-*-*-*',
+ 'anchor'=>'s', 'fill'=>'brown')
+else
+ TkcText.new($ctext_canvas, x+45, y-5, 'text'=>'Justification',
+ 'font'=>'Times 24', 'anchor'=>'s', 'fill'=>'brown')
+end
$ctext_canvas.itembind('config', 'Enter', proc{textEnter $ctext_canvas})
$ctext_canvas.itembind('config', 'Leave',
diff --git a/ext/tk/sample/demos-jp/dialog1.rb b/ext/tk/sample/demos-jp/dialog1.rb
index 0d6181bfc6..07e50306ab 100644
--- a/ext/tk/sample/demos-jp/dialog1.rb
+++ b/ext/tk/sample/demos-jp/dialog1.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# a dialog box with a local grab (called by 'widget')
#
diff --git a/ext/tk/sample/demos-jp/dialog2.rb b/ext/tk/sample/demos-jp/dialog2.rb
index a934378dda..f747f8d6a8 100644
--- a/ext/tk/sample/demos-jp/dialog2.rb
+++ b/ext/tk/sample/demos-jp/dialog2.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# a dialog box with a global grab (called by 'widget')
#
diff --git a/ext/tk/sample/demos-jp/entry1.rb b/ext/tk/sample/demos-jp/entry1.rb
index edf3b5f71d..2be29c18d3 100644
--- a/ext/tk/sample/demos-jp/entry1.rb
+++ b/ext/tk/sample/demos-jp/entry1.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# entry (no scrollbars) widget demo (called by 'widget')
#
@@ -15,8 +16,10 @@ $entry1_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($entry1_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-msg = TkLabel.new($entry1_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '5i'
justify 'left'
@@ -25,7 +28,7 @@ msg = TkLabel.new($entry1_demo) {
msg.pack('side'=>'top')
# frame À¸À®
-TkFrame.new($entry1_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -43,9 +46,9 @@ TkFrame.new($entry1_demo) {|frame|
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# entry À¸À®
-e1 = TkEntry.new($entry1_demo, 'relief'=>'sunken')
-e2 = TkEntry.new($entry1_demo, 'relief'=>'sunken')
-e3 = TkEntry.new($entry1_demo, 'relief'=>'sunken')
+e1 = TkEntry.new(base_frame, 'relief'=>'sunken')
+e2 = TkEntry.new(base_frame, 'relief'=>'sunken')
+e3 = TkEntry.new(base_frame, 'relief'=>'sunken')
[e1,e2,e3].each{|w| w.pack('side'=>'top', 'padx'=>10, 'pady'=>5, 'fill'=>'x')}
# ½é´üÃÍÁÞÆþ
diff --git a/ext/tk/sample/demos-jp/entry2.rb b/ext/tk/sample/demos-jp/entry2.rb
index 7d5740e663..2675b5d324 100644
--- a/ext/tk/sample/demos-jp/entry2.rb
+++ b/ext/tk/sample/demos-jp/entry2.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# entry (with scrollbars) widget demo (called by 'widget')
#
@@ -15,8 +16,10 @@ $entry2_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($entry2_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-msg = TkLabel.new($entry2_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '5i'
justify 'left'
@@ -25,7 +28,7 @@ msg = TkLabel.new($entry2_demo) {
msg.pack('side'=>'top')
# frame À¸À®
-TkFrame.new($entry2_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -43,7 +46,7 @@ TkFrame.new($entry2_demo) {|frame|
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# frame À¸À®
-TkFrame.new($entry2_demo, 'borderwidth'=>10) {|w|
+TkFrame.new(base_frame, 'borderwidth'=>10) {|w|
# entry 1
s1 = TkScrollbar.new(w, 'relief'=>'sunken', 'orient'=>'horiz')
e1 = TkEntry.new(w, 'relief'=>'sunken') {
diff --git a/ext/tk/sample/demos-jp/entry3.rb b/ext/tk/sample/demos-jp/entry3.rb
index f57dc13553..6b9cd4cf37 100644
--- a/ext/tk/sample/demos-jp/entry3.rb
+++ b/ext/tk/sample/demos-jp/entry3.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
# entry3.rb --
#
# This demonstration script creates several entry widgets whose
@@ -17,7 +18,9 @@ $entry3_demo = TkToplevel.new {|w|
positionWindow(w)
}
-TkLabel.new($entry3_demo,
+base_frame = TkFrame.new($entry3_demo).pack(:fill=>:both, :expand=>true)
+
+TkLabel.new(base_frame,
:font=>$font, :wraplength=>'5i', :justify=>:left,
:text=><<EOL).pack(:side=>:top)
°Ê²¼¤Ë¤Ï£´¼ïÎà¤Î¥¨¥ó¥È¥ê¥Ü¥Ã¥¯¥¹¤¬É½¼¨¤µ¤ì¤Æ¤¤¤Þ¤¹¡¥³Æ¥¨¥ó¥È¥ê¥Ü¥Ã¥¯¥¹¤Ï¡¤\
@@ -38,7 +41,7 @@ TkLabel.new($entry3_demo,
ÆþÎϤµ¤ì¤¿Ê¸»ú¤Ï¥¢¥¹¥¿¥ê¥¹¥¯µ­¹æ¤ËÃÖ¤­´¹¤¨¤ÆÉ½¼¨¤µ¤ì¤Þ¤¹¡¥
EOL
-TkFrame.new($entry3_demo){|f|
+TkFrame.new(base_frame){|f|
pack(:side=>:bottom, :fill=>:x, :pady=>'2m')
TkButton.new(f, :text=>'ÊĤ¸¤ë', :width=>15, :command=>proc{
@@ -64,23 +67,41 @@ TkFrame.new($entry3_demo){|f|
# count - Counter to control the number of times flashed
def focusAndFlash(widget, fg, bg, count=5)
return if count <= 0
- TkTimer.new(100, count,
- proc{widget.configure(:foreground=>bg, :background=>fg)},
- proc{widget.configure(:foreground=>fg, :background=>bg)}
- ).start
+ if fg && !fg.empty? && bg && !bg.empty?
+ TkTimer.new(200, count,
+ proc{widget.configure(:foreground=>bg, :background=>fg)},
+ proc{widget.configure(:foreground=>fg, :background=>bg)}
+ ).start
+ else
+ # TkTimer.new(150, 3){Tk.bell}.start
+ Tk.bell
+ TkTimer.new(200, count,
+ proc{widget.configure(:foreground=>'white',
+ :background=>'black')},
+ proc{widget.configure(:foreground=>'black',
+ :background=>'white')}
+ ).at_end{begin
+ widget.configure(:foreground=>fg,
+ :background=>bg)
+ rescue
+ # ignore
+ end}.start
+ end
widget.focus(true)
end
-l1 = TkLabelFrame.new($entry3_demo, :text=>"À°¿ô¥¨¥ó¥È¥ê")
+l1 = TkLabelFrame.new(base_frame, :text=>"À°¿ô¥¨¥ó¥È¥ê")
TkEntry.new(l1, :validate=>:focus,
:vcmd=>[
proc{|s| s == '' || /^[+-]?\d+$/ =~ s }, '%P'
]) {|e|
- invalidcommand [proc{|w| focusAndFlash(w, e.fg, e.bg)}, '%W']
+ fg = e.foreground
+ bg = e.background
+ invalidcommand [proc{|w| focusAndFlash(w, fg, bg)}, '%W']
pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m')
}
-l2 = TkLabelFrame.new($entry3_demo, :text=>"ŤµÀ©ÌóÉÕ¤­¥¨¥ó¥È¥ê")
+l2 = TkLabelFrame.new(base_frame, :text=>"ŤµÀ©ÌóÉÕ¤­¥¨¥ó¥È¥ê")
TkEntry.new(l2, :validate=>:key, :invcmd=>proc{Tk.bell},
:vcmd=>[proc{|s| s.length < 10}, '%P']
).pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m')
@@ -161,15 +182,15 @@ def validatePhoneChange(widget, vmode, idx, char)
widget.delete(idx)
widget.insert(idx, $phoneNumberMap[char] || char)
Tk.after_idle(proc{phoneSkipRight(widget, -1)})
- # Tk.update(true) # Don't work 'update' inter validation callback.
- # It depends on Tcl/Tk side (tested on Tcl/Tk8.5a1).
+ # Tk.update(true) # <- Don't work 'update' inter validation callback.
+ # It depends on Tcl/Tk side (tested on Tcl/Tk8.5a1).
return true
end
return false
end
-l3 = TkLabelFrame.new($entry3_demo, :text=>"ÊÆ¹ñÅÅÏÃÈֹ楨¥ó¥È¥ê")
+l3 = TkLabelFrame.new(base_frame, :text=>"ÊÆ¹ñÅÅÏÃÈֹ楨¥ó¥È¥ê")
TkEntry.new(l3, :validate=>:key, :invcmd=>proc{Tk.bell},
:textvariable=>entry3content,
:vcmd=>[
@@ -188,14 +209,14 @@ TkEntry.new(l3, :validate=>:key, :invcmd=>proc{Tk.bell},
pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m')
}
-l4 = TkLabelFrame.new($entry3_demo, :text=>"¥Ñ¥¹¥ï¡¼¥É¥¨¥ó¥È¥ê")
+l4 = TkLabelFrame.new(base_frame, :text=>"¥Ñ¥¹¥ï¡¼¥É¥¨¥ó¥È¥ê")
TkEntry.new(l4, :validate=>:key, :show=>'*',
:vcmd=>[
proc{|s| s.length <= 8},
'%P'
]).pack(:fill=>:x, :expand=>true, :padx=>'1m', :pady=>'1m')
-TkFrame.new($entry3_demo){|f|
+TkFrame.new(base_frame){|f|
lower
TkGrid.configure(l1, l2, :in=>f, :padx=>'3m', :pady=>'1m', :sticky=>:ew)
TkGrid.configure(l3, l4, :in=>f, :padx=>'3m', :pady=>'1m', :sticky=>:ew)
diff --git a/ext/tk/sample/demos-jp/filebox.rb b/ext/tk/sample/demos-jp/filebox.rb
index f3608ab70f..b8846d08a0 100644
--- a/ext/tk/sample/demos-jp/filebox.rb
+++ b/ext/tk/sample/demos-jp/filebox.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# widget demo prompts the user to select a file (called by 'widget')
#
@@ -15,12 +16,14 @@ $filebox_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($filebox_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-TkLabel.new($filebox_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left',
+TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left',
'text'=>"¥¨¥ó¥È¥ê¤Ë¥Õ¥¡¥¤¥ë̾¤òľÀÜÆþÎϤ¹¤ë¤«¡¢\"Browse\" ¥Ü¥¿¥ó¤ò²¡¤·¤Æ¥Õ¥¡¥¤¥ëÁªÂò¥À¥¤¥¢¥í¥°¤«¤é¥Õ¥¡¥¤¥ë̾¤òÁª¤ó¤Ç²¼¤µ¤¤¡£").pack('side'=>'top')
# frame À¸À®
-TkFrame.new($filebox_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -39,7 +42,7 @@ TkFrame.new($filebox_demo) {|frame|
# frame À¸À®
['³«¤¯', 'Êݸ'].each{|type|
- TkFrame.new($filebox_demo) {|f|
+ TkFrame.new(base_frame) {|f|
TkLabel.new(f, 'text'=>"¥Õ¥¡¥¤¥ë¤ò#{type}: ", 'anchor'=>'e')\
.pack('side'=>'left')
@@ -47,7 +50,7 @@ TkFrame.new($filebox_demo) {|frame|
pack('side'=>'left', 'expand'=>'yes', 'fill'=>'x')
TkButton.new(f, 'text'=>'Browse ...',
- 'command'=>proc{fileDialog $filebox_demo,e,type})\
+ 'command'=>proc{fileDialog base_frame,e,type})\
.pack('side'=>'left')
}
@@ -57,7 +60,7 @@ TkFrame.new($filebox_demo) {|frame|
$tk_strictMotif = TkVarAccess.new('tk_strictMotif')
if ($tk_platform['platform'] == 'unix')
- TkCheckButton.new($filebox_demo,
+ TkCheckButton.new(base_frame,
'text'=>'Motif¥¹¥¿¥¤¥ë¤Î¥À¥¤¥¢¥í¥°¤òÍѤ¤¤ë',
'variable'=>$tk_strictMotif,
'onvalue'=>1, 'offvalue'=>0 ).pack('anchor'=>'c')
@@ -90,7 +93,10 @@ def fileDialog(w,ent,operation)
if file != ""
ent.delete 0, 'end'
ent.insert 0, file
- ent.xview 'end'
+ # ent.xview 'end'
+ Tk.update_idletasks # need this for Tk::Tile::Entry
+ # (to find right position of 'xview').
+ ent.xview(ent.index('end'))
end
end
diff --git a/ext/tk/sample/demos-jp/floor.rb b/ext/tk/sample/demos-jp/floor.rb
index b029580bd6..a2ec2e9969 100644
--- a/ext/tk/sample/demos-jp/floor.rb
+++ b/ext/tk/sample/demos-jp/floor.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# floorDisplay widget demo (called by 'widget')
#
@@ -1586,14 +1587,16 @@ $floor_demo = TkToplevel.new {|w|
minsize(100,100)
}
+base_frame = TkFrame.new($floor_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-TkLabel.new($floor_demo, 'font'=>$font, 'wraplength'=>'8i', 'justify'=>'left',
+TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'8i', 'justify'=>'left',
'text'=>"¤³¤Î¥¦¥£¥ó¥É¥¦¤Ë¤Ï¥Ç¥£¥¸¥¿¥ë¥¨¥¯¥¤¥Ã¥×¥á¥ó¥È¼Ò¤Î¥¦¥§¥¹¥¿¥ó¥ê¥µ¡¼¥Á¥é¥Ü¥é¥È¥ê (DECWRL) ¤Î´Ö¼è¤ê¤¬½ñ¤«¤ì¤¿¥­¥ã¥ó¥Ð¥¹ widget ¤¬Æþ¤Ã¤Æ¤¤¤Þ¤¹¡£¤³¤ì¤Ï 3³¬·ú¤Æ¤Ç¡¢¾ï¤Ë¤½¤Î¤¦¤Á¤Î1³¬Ê¬¤¬ÁªÂò¡¢¤Ä¤Þ¤ê¤½¤Î´Ö¼è¤ê¤¬É½¼¨¤µ¤ì¤ë¤è¤¦¤Ë¤Ê¤Ã¤Æ¤¤¤Þ¤¹¡£¤¢¤ë³¬¤òÁªÂò¤¹¤ë¤Ë¤Ï¡¢¤½¤Î¾å¤Ç¥Þ¥¦¥¹¤Îº¸¥Ü¥¿¥ó¤ò¥¯¥ê¥Ã¥¯¤·¤Æ¤¯¤À¤µ¤¤¡£¥Þ¥¦¥¹¤¬ÁªÂò¤µ¤ì¤Æ¤¤¤ë³¬¤Î¾å¤òư¤¯¤È¡¢¤½¤Î²¼¤Ë¤¢¤ëÉô²°¤Î¿§¤¬ÊѤï¤ê¡¢Éô²°Èֹ椬¡ÖÉô²°ÈÖ¹æ:¡×¥¨¥ó¥È¥ê¤Ëɽ¼¨¤µ¤ì¤Þ¤¹¡£¤Þ¤¿¡¢¥¨¥ó¥È¥ê¤ËÉô²°ÈÖ¹æ¤ò½ñ¤¯¤È¤½¤ÎÉô²°¤Î¿§¤¬ÊѤï¤ê¤Þ¤¹¡£"){
pack('side'=>'top')
}
# frame À¸À®
-$floor_buttons = TkFrame.new($floor_demo) {|frame|
+$floor_buttons = TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -1617,17 +1620,17 @@ $floorItems = {}
# canvas ÀßÄê
if $tk_version =~ /^4\.[01]/
- $floor_canvas_frame = TkFrame.new($floor_demo,'bd'=>2,'relief'=>'sunken',
+ $floor_canvas_frame = TkFrame.new(base_frame,'bd'=>2,'relief'=>'sunken',
'highlightthickness'=>2)
$floor_canvas = TkCanvas.new($floor_canvas_frame,
'width'=>900, 'height'=>500, 'borderwidth'=>0,
'highlightthickness'=>0) {|c|
- TkScrollbar.new($floor_demo, 'orient'=>'horiz',
+ TkScrollbar.new(base_frame, 'orient'=>'horiz',
'command'=>proc{|*args| c.xview(*args)}){|hs|
c.xscrollcommand(proc{|first,last| hs.set first,last})
pack('side'=>'bottom', 'fill'=>'x')
}
- TkScrollbar.new($floor_demo, 'command'=>proc{|*args| c.yview(*args)}){|vs|
+ TkScrollbar.new(base_frame, 'command'=>proc{|*args| c.yview(*args)}){|vs|
c.yscrollcommand(proc{|first,last| vs.set first,last})
pack('side'=>'right', 'fill'=>'y')
}
@@ -1636,7 +1639,7 @@ if $tk_version =~ /^4\.[01]/
$floor_canvas.pack('expand'=>'yes', 'fill'=>'both')
else
- TkFrame.new($floor_demo) {|f|
+ TkFrame.new(base_frame) {|f|
pack('side'=>'top', 'fill'=>'both', 'expand'=>'yes')
h = TkScrollbar.new(f, 'highlightthickness'=>0, 'orient'=>'horizontal')
diff --git a/ext/tk/sample/demos-jp/floor2.rb b/ext/tk/sample/demos-jp/floor2.rb
index a20b31d45c..d4381c5543 100644
--- a/ext/tk/sample/demos-jp/floor2.rb
+++ b/ext/tk/sample/demos-jp/floor2.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# floorDisplay widget demo 2 (called by 'widget')
#
@@ -1586,14 +1587,16 @@ $floor2_demo = TkToplevel.new {|w|
minsize(100,100)
}
+base_frame = TkFrame.new($floor2_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-TkLabel.new($floor2_demo, 'font'=>$font, 'wraplength'=>'8i', 'justify'=>'left',
+TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'8i', 'justify'=>'left',
'text'=>"¤³¤Î¥¦¥£¥ó¥É¥¦¤Ë¤Ï¥Ç¥£¥¸¥¿¥ë¥¨¥¯¥¤¥Ã¥×¥á¥ó¥È¼Ò¤Î¥¦¥§¥¹¥¿¥ó¥ê¥µ¡¼¥Á¥é¥Ü¥é¥È¥ê (DECWRL) ¤Î´Ö¼è¤ê¤¬½ñ¤«¤ì¤¿¥­¥ã¥ó¥Ð¥¹ widget ¤¬Æþ¤Ã¤Æ¤¤¤Þ¤¹¡£¤³¤ì¤Ï 3³¬·ú¤Æ¤Ç¡¢¾ï¤Ë¤½¤Î¤¦¤Á¤Î1³¬Ê¬¤¬ÁªÂò¡¢¤Ä¤Þ¤ê¤½¤Î´Ö¼è¤ê¤¬É½¼¨¤µ¤ì¤ë¤è¤¦¤Ë¤Ê¤Ã¤Æ¤¤¤Þ¤¹¡£¤¢¤ë³¬¤òÁªÂò¤¹¤ë¤Ë¤Ï¡¢¤½¤Î¾å¤Ç¥Þ¥¦¥¹¤Îº¸¥Ü¥¿¥ó¤ò¥¯¥ê¥Ã¥¯¤·¤Æ¤¯¤À¤µ¤¤¡£¥Þ¥¦¥¹¤¬ÁªÂò¤µ¤ì¤Æ¤¤¤ë³¬¤Î¾å¤òư¤¯¤È¡¢¤½¤Î²¼¤Ë¤¢¤ëÉô²°¤Î¿§¤¬ÊѤï¤ê¡¢Éô²°Èֹ椬¡ÖÉô²°ÈÖ¹æ:¡×¥¨¥ó¥È¥ê¤Ëɽ¼¨¤µ¤ì¤Þ¤¹¡£¤Þ¤¿¡¢¥¨¥ó¥È¥ê¤ËÉô²°ÈÖ¹æ¤ò½ñ¤¯¤È¤½¤ÎÉô²°¤Î¿§¤¬ÊѤï¤ê¤Þ¤¹¡£"){
pack('side'=>'top')
}
# frame À¸À®
-$floor2_buttons = TkFrame.new($floor2_demo) {|frame|
+$floor2_buttons = TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -1617,17 +1620,17 @@ $floorItems2 = {}
# canvas ÀßÄê
if $tk_version =~ /^4\.[01]/
- $floor2_canvas_frame = TkFrame.new($floor2_demo,'bd'=>2,'relief'=>'sunken',
+ $floor2_canvas_frame = TkFrame.new(base_frame,'bd'=>2,'relief'=>'sunken',
'highlightthickness'=>2)
$floor2_canvas = TkCanvas.new($floor2_canvas_frame,
'width'=>900, 'height'=>500, 'borderwidth'=>0,
'highlightthickness'=>0) {|c|
- TkScrollbar.new($floor2_demo, 'orient'=>'horiz',
+ TkScrollbar.new(base_frame, 'orient'=>'horiz',
'command'=>proc{|*args| c.xview(*args)}){|hs|
c.xscrollcommand(proc{|first,last| hs.set first,last})
pack('side'=>'bottom', 'fill'=>'x')
}
- TkScrollbar.new($floor2_demo, 'command'=>proc{|*args| c.yview(*args)}){|vs|
+ TkScrollbar.new(base_frame, 'command'=>proc{|*args| c.yview(*args)}){|vs|
c.yscrollcommand(proc{|first,last| vs.set first,last})
pack('side'=>'right', 'fill'=>'y')
}
@@ -1636,7 +1639,7 @@ if $tk_version =~ /^4\.[01]/
$floor2_canvas.pack('expand'=>'yes', 'fill'=>'both')
else
- TkFrame.new($floor2_demo) {|f|
+ TkFrame.new(base_frame) {|f|
pack('side'=>'top', 'fill'=>'both', 'expand'=>'yes')
h = TkScrollbar.new(f, 'highlightthickness'=>0, 'orient'=>'horizontal')
diff --git a/ext/tk/sample/demos-jp/form.rb b/ext/tk/sample/demos-jp/form.rb
index fe456d3943..4de7056764 100644
--- a/ext/tk/sample/demos-jp/form.rb
+++ b/ext/tk/sample/demos-jp/form.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# form widget demo (called by 'widget')
#
@@ -15,8 +16,10 @@ $form_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($form_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-msg = TkLabel.new($form_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -25,7 +28,7 @@ msg = TkLabel.new($form_demo) {
msg.pack('side'=>'top', 'fill'=>'x')
# frame À¸À®
-TkFrame.new($form_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -45,7 +48,7 @@ TkFrame.new($form_demo) {|frame|
# entry À¸À®
form_data = []
(1..5).each{|i|
- f = TkFrame.new($form_demo, 'bd'=>2)
+ f = TkFrame.new(base_frame, 'bd'=>2)
e = TkEntry.new(f, 'relief'=>'sunken', 'width'=>40)
l = TkLabel.new(f)
e.pack('side'=>'right')
diff --git a/ext/tk/sample/demos-jp/goldberg.rb b/ext/tk/sample/demos-jp/goldberg.rb
index 592b69f775..a81c7ec70c 100644
--- a/ext/tk/sample/demos-jp/goldberg.rb
+++ b/ext/tk/sample/demos-jp/goldberg.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# Ruby/Tk Goldverg demo (called by 'widget')
#
@@ -54,6 +55,8 @@ $goldberg_demo = TkToplevel.new {|w|
# positionWindow(w)
}
+base_frame = TkFrame.new($goldberg_demo).pack(:fill=>:both, :expand=>true)
+
=begin
# label
msg = TkLabel.new($goldberg_demo) {
@@ -176,7 +179,8 @@ class TkGoldberg_Demo
do_ctrl_frame
do_detail_frame
- msg = TkLabel.new(@parent, :bg=>@C['bg'], :fg=>'white') {
+ # msg = TkLabel.new(@parent, :bg=>@C['bg'], :fg=>'white') {
+ msg = Tk::Label.new(@parent, :bg=>@C['bg'], :fg=>'white') {
font 'Arial 10'
wraplength 600
justify 'left'
@@ -186,7 +190,8 @@ class TkGoldberg_Demo
frame = TkFrame.new(@parent, :bg=>@C['bg'])
- TkButton.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) {
+ # TkButton.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) {
+ Tk::Button.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) {
text 'ÊĤ¸¤ë'
command proc{
tmppath = $goldberg_demo
@@ -195,12 +200,14 @@ class TkGoldberg_Demo
}
}.pack('side'=>'left')
- TkButton.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) {
+ # TkButton.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) {
+ Tk::Button.new(frame, :bg=>@C['bg'], :activebackground=>@C['bg']) {
text '¥³¡¼¥É»²¾È'
command proc{showCode 'goldberg'}
}.pack('side'=>'left', 'padx'=>5)
- @show = TkButton.new(frame, :text=>'>>', :command=>proc{show_ctrl},
+ # @show = TkButton.new(frame, :text=>'>>', :command=>proc{show_ctrl},
+ @show = Tk::Button.new(frame, :text=>'>>', :command=>proc{show_ctrl},
:bg=>@C['bg'], :activebackground=>@C['bg'])
@show.pack('side'=>'left')
frame.place(:in=>@canvas, :relx=>1, :rely=>0, :anchor=>:ne)
@@ -209,10 +216,11 @@ class TkGoldberg_Demo
end
def do_ctrl_frame
- @start = TkButton.new(@parent, :text=>'Start', :bd=>6,
+ @start = Tk::Button.new(@parent, :text=>'Start', :bd=>6,
:command=>proc{do_button(0)})
- @start.font(@start['font'].weight('bold'))
- font = @start['font']
+ if font = @start['font']
+ @start.font(font.weight('bold'))
+ end
@pause = TkCheckbutton.new(@parent, :text=>'Pause', :font=>font,
:command=>proc{do_button(1)}, :relief=>:raised,
@@ -2000,4 +2008,4 @@ class TkGoldberg_Demo
end
end
-TkGoldberg_Demo.new($goldberg_demo)
+TkGoldberg_Demo.new(base_frame)
diff --git a/ext/tk/sample/demos-jp/hello b/ext/tk/sample/demos-jp/hello
index 859ebd950e..08f154d499 100644
--- a/ext/tk/sample/demos-jp/hello
+++ b/ext/tk/sample/demos-jp/hello
@@ -1,4 +1,5 @@
#!/usr/bin/env ruby
+# -*- coding: euc-jp -*-
require 'tk'
TkButton.new(nil,
diff --git a/ext/tk/sample/demos-jp/hscale.rb b/ext/tk/sample/demos-jp/hscale.rb
index 37d215435c..5615aa50bd 100644
--- a/ext/tk/sample/demos-jp/hscale.rb
+++ b/ext/tk/sample/demos-jp/hscale.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
require "tkcanvas"
if defined?($hscale_demo) && $hscale_deom
@@ -11,8 +12,9 @@ $hscale_demo = TkToplevel.new {|w|
}
positionWindow($hscale_demo)
+base_frame = TkFrame.new($hscale_demo).pack(:fill=>:both, :expand=>true)
-msg = TkLabel.new($hscale_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '3.5i'
justify 'left'
@@ -22,7 +24,7 @@ msg = TkLabel.new($hscale_demo) {
}
msg.pack('side'=>'top')
-TkFrame.new($hscale_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -39,7 +41,17 @@ TkFrame.new($hscale_demo) {|frame|
}.pack('side'=>'left', 'expand'=>'yes')
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
-TkFrame.new($hscale_demo) {|frame|
+def setWidth(w, width)
+ width = width + 21
+ x2 = width - 30
+ if x2 < 21
+ x2 = 21
+ end
+ w.coords 'poly',20,15,20,35,x2,35,x2,45,width,25,x2,5,x2,15,20,15
+ w.coords 'line',20,15,20,35,x2,35,x2,45,width,25,x2,5,x2,15,20,15
+end
+
+TkFrame.new(base_frame) {|frame|
canvas = TkCanvas.new(frame) {|c|
width 50
height 50
@@ -64,14 +76,3 @@ TkFrame.new($hscale_demo) {|frame|
}.pack('side'=>'bottom', 'expand'=>'yes', 'anchor'=>'n')
scale.set 75
}.pack('side'=>'top', 'fill'=>'x')
-
-
-def setWidth(w, width)
- width = width + 21
- x2 = width - 30
- if x2 < 21
- x2 = 21
- end
- w.coords 'poly',20,15,20,35,x2,35,x2,45,width,25,x2,5,x2,15,20,15
- w.coords 'line',20,15,20,35,x2,35,x2,45,width,25,x2,5,x2,15,20,15
-end
diff --git a/ext/tk/sample/demos-jp/icon.rb b/ext/tk/sample/demos-jp/icon.rb
index e4fef5cae7..a2ca6651dc 100644
--- a/ext/tk/sample/demos-jp/icon.rb
+++ b/ext/tk/sample/demos-jp/icon.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# iconic button widget demo (called by 'widget')
#
@@ -15,8 +16,10 @@ $icon_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($icon_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-msg = TkLabel.new($icon_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '5i'
justify 'left'
@@ -25,7 +28,7 @@ msg = TkLabel.new($icon_demo) {
msg.pack('side'=>'top')
# frame À¸À®
-TkFrame.new($icon_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -60,16 +63,18 @@ TkBitmapImage.new('file'=>[$demo_dir,'..',
letters = TkVariable.new
# frame À¸À®
-TkFrame.new($icon_demo, 'borderwidth'=>10){|w|
+TkFrame.new(base_frame, 'borderwidth'=>10){|w|
TkFrame.new(w) {|f|
- TkRadioButton.new(f){
+ # TkRadioButton.new(f){
+ Tk::RadioButton.new(f){
bitmap '@' + [$demo_dir,'..',
'images','letters.xbm'].join(File::Separator)
variable letters
value 'full'
}.pack('side'=>'top', 'expand'=>'yes')
- TkRadioButton.new(f){
+ # TkRadioButton.new(f){
+ Tk::RadioButton.new(f){
bitmap '@' + [$demo_dir,'..',
'images','noletter.xbm'].join(File::Separator)
variable letters
@@ -78,14 +83,16 @@ TkFrame.new($icon_demo, 'borderwidth'=>10){|w|
}.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'5m')
- TkCheckButton.new(w) {
+ # TkCheckButton.new(w) {
+ Tk::CheckButton.new(w) {
image flagdown
selectimage flagup
indicatoron 0
selectcolor self['background']
}.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'5m')
- TkCheckButton.new(w) {
+ # TkCheckButton.new(w) {
+ Tk::CheckButton.new(w) {
bitmap '@' + [$demo_dir,'..',
'images','letters.xbm'].join(File::Separator)
indicatoron 0
diff --git a/ext/tk/sample/demos-jp/image1.rb b/ext/tk/sample/demos-jp/image1.rb
index 3d47f844e5..d9435cc1a2 100644
--- a/ext/tk/sample/demos-jp/image1.rb
+++ b/ext/tk/sample/demos-jp/image1.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# two image widgets demo (called by 'widget')
#
@@ -15,8 +16,10 @@ $image1_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($image1_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-msg = TkLabel.new($image1_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -25,7 +28,7 @@ msg = TkLabel.new($image1_demo) {
msg.pack('side'=>'top')
# frame À¸À®
-TkFrame.new($image1_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -52,7 +55,10 @@ TkPhotoImage.new('file'=>[$demo_dir,'..',
'images','earthris.gif'].join(File::Separator))
# label À¸À®
-[ TkLabel.new($image1_demo, 'image'=>image1a, 'bd'=>1, 'relief'=>'sunken'),
- TkLabel.new($image1_demo, 'image'=>image1b, 'bd'=>1, 'relief'=>'sunken')
+#[ TkLabel.new(base_frame, 'image'=>image1a, 'bd'=>1, 'relief'=>'sunken'),
+# TkLabel.new(base_frame, 'image'=>image1b, 'bd'=>1, 'relief'=>'sunken')
+#].each{|w| w.pack('side'=>'top', 'padx'=>'.5m', 'pady'=>'.5m')}
+[ Tk::Label.new(base_frame, 'image'=>image1a, 'bd'=>1, 'relief'=>'sunken'),
+ Tk::Label.new(base_frame, 'image'=>image1b, 'bd'=>1, 'relief'=>'sunken')
].each{|w| w.pack('side'=>'top', 'padx'=>'.5m', 'pady'=>'.5m')}
diff --git a/ext/tk/sample/demos-jp/image2.rb b/ext/tk/sample/demos-jp/image2.rb
index e2e2a2b036..1bb2c9e9c3 100644
--- a/ext/tk/sample/demos-jp/image2.rb
+++ b/ext/tk/sample/demos-jp/image2.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# widget demo 'load image' (called by 'widget')
#
@@ -15,8 +16,10 @@ $image2_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($image2_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-msg = TkLabel.new($image2_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -25,7 +28,7 @@ msg = TkLabel.new($image2_demo) {
msg.pack('side'=>'top')
# frame À¸À®
-TkFrame.new($image2_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -50,21 +53,21 @@ $dirName = TkVariable.new([$demo_dir,'..','images'].join(File::Separator))
$image2a = TkPhotoImage.new
# ¥Õ¥¡¥¤¥ë̾ÆþÎÏÉô
-TkLabel.new($image2_demo, 'text'=>'¥Ç¥£¥ì¥¯¥È¥ê:')\
+TkLabel.new(base_frame, 'text'=>'¥Ç¥£¥ì¥¯¥È¥ê:')\
.pack('side'=>'top', 'anchor'=>'w')
-image2_e = TkEntry.new($image2_demo) {
+image2_e = TkEntry.new(base_frame) {
width 30
textvariable $dirName
}.pack('side'=>'top', 'anchor'=>'w')
-TkFrame.new($image2_demo, 'height'=>'3m', 'width'=>20)\
+TkFrame.new(base_frame, 'height'=>'3m', 'width'=>20)\
.pack('side'=>'top', 'anchor'=>'w')
-TkLabel.new($image2_demo, 'text'=>'¥Õ¥¡¥¤¥ë:')\
+TkLabel.new(base_frame, 'text'=>'¥Õ¥¡¥¤¥ë:')\
.pack('side'=>'top', 'anchor'=>'w')
-TkFrame.new($image2_demo){|w|
+TkFrame.new(base_frame){|w|
s = TkScrollbar.new(w)
l = TkListbox.new(w) {
width 20
@@ -83,9 +86,10 @@ TkFrame.new($image2_demo){|w|
}.pack('side'=>'top', 'anchor'=>'w')
# image ÇÛÃÖ
-[ TkFrame.new($image2_demo, 'height'=>'3m', 'width'=>20),
- TkLabel.new($image2_demo, 'text'=>'²èÁü:'),
- TkLabel.new($image2_demo, 'image'=>$image2a)
+[ TkFrame.new(base_frame, 'height'=>'3m', 'width'=>20),
+ TkLabel.new(base_frame, 'text'=>'²èÁü:'),
+ # TkLabel.new(base_frame, 'image'=>$image2a)
+ Tk::Label.new(base_frame, 'image'=>$image2a)
].each{|w| w.pack('side'=>'top', 'anchor'=>'w')}
# ¥á¥½¥Ã¥ÉÄêµÁ
diff --git a/ext/tk/sample/demos-jp/image3.rb b/ext/tk/sample/demos-jp/image3.rb
index d9f378c116..12b8aafd8e 100644
--- a/ext/tk/sample/demos-jp/image3.rb
+++ b/ext/tk/sample/demos-jp/image3.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
# image3.rb
#
# This demonstration script creates a simple collection of widgets
@@ -19,6 +20,8 @@ $image3_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($image3_demo).pack(:fill=>:both, :expand=>true)
+
#
def loadDir3(w)
w.delete(0,'end')
@@ -49,7 +52,7 @@ end
# label
-msg = TkLabel.new($image3_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -58,7 +61,7 @@ msg = TkLabel.new($image3_demo) {
msg.pack('side'=>'top')
# frame
-TkFrame.new($image3_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -87,11 +90,11 @@ end
$image3a = TkPhotoImage.new
#
-image3_f = TkFrame.new($image3_demo).pack(:fill=>:both, :expand=>true)
+image3_f = TkFrame.new(base_frame).pack(:fill=>:both, :expand=>true)
-image3_df = TkLabelFrame.new($image3_demo, :text=>'¥Ç¥£¥ì¥¯¥È¥ê:')
+image3_df = TkLabelFrame.new(base_frame, :text=>'¥Ç¥£¥ì¥¯¥È¥ê:')
-image3_ff = TkLabelFrame.new($image3_demo, :text=>'¥Õ¥¡¥¤¥ë:',
+image3_ff = TkLabelFrame.new(base_frame, :text=>'¥Õ¥¡¥¤¥ë:',
:padx=>'2m', :pady=>'2m')
image3_lbx = TkListbox.new(image3_ff, :width=>20, :height=>10) {
pack(:side=>:left, :fill=>:y, :expand=>true)
@@ -111,8 +114,9 @@ TkButton.new(image3_df, :pady=>0, :padx=>'2m', :text=>"¥Ç¥£¥ì¥¯¥È¥êÁªÂò",
pack(:side=>:left, :fill=>:y, :padx=>[0, '2m'], :pady=>'2m')
}
-image3_if = TkLabelFrame.new($image3_demo, :text=>'¥¤¥á¡¼¥¸:') {|f|
- TkLabel.new(f, :image=>$image3a).pack(:padx=>'2m', :pady=>'2m')
+image3_if = TkLabelFrame.new(base_frame, :text=>'¥¤¥á¡¼¥¸:') {|f|
+ # TkLabel.new(f, :image=>$image3a).pack(:padx=>'2m', :pady=>'2m')
+ Tk::Label.new(f, :image=>$image3a).pack(:padx=>'2m', :pady=>'2m')
}
Tk.grid(image3_df, '-',
diff --git a/ext/tk/sample/demos-jp/items.rb b/ext/tk/sample/demos-jp/items.rb
index 38774d10d2..64ceeff3ec 100644
--- a/ext/tk/sample/demos-jp/items.rb
+++ b/ext/tk/sample/demos-jp/items.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# canvas item types widget demo (called by 'widget')
#
@@ -15,8 +16,10 @@ $items_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($items_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-TkLabel.new($items_demo) {
+TkLabel.new(base_frame) {
font $font
wraplength '5i'
justify 'left'
@@ -24,7 +27,7 @@ TkLabel.new($items_demo) {
}.pack('side'=>'top')
# frame À¸À®
-TkFrame.new($items_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -43,7 +46,7 @@ TkFrame.new($items_demo) {|frame|
# frame À¸À®
cvs = nil
-TkFrame.new($items_demo) {|cf|
+TkFrame.new(base_frame) {|cf|
# canvas À¸À®
cvs = TkCanvas.new(cf) {|c|
focus
@@ -91,8 +94,13 @@ TkcLine.new(cvs, '0c', '16c', '30c', '16c', 'width'=>2)
TkcLine.new(cvs, '10c', '0c', '10c', '24c', 'width'=>2)
TkcLine.new(cvs, '20c', '0c', '20c', '24c', 'width'=>2)
-font1 = '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*'
-font2 = '-Adobe-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*'
+if $tk_version =~ /^4.*/
+ font1 = '-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*'
+ font2 = '-Adobe-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*'
+else
+ font1 = 'Helvetica 12'
+ font2 = 'Helvetica 24 bold'
+end
if TkWinfo.depth($root).to_i > 1
blue = 'DeepSkyBlue3'
red = 'red'
diff --git a/ext/tk/sample/demos-jp/ixset2 b/ext/tk/sample/demos-jp/ixset2
index 8947daa4b4..5b816e40b1 100644
--- a/ext/tk/sample/demos-jp/ixset2
+++ b/ext/tk/sample/demos-jp/ixset2
@@ -1,4 +1,5 @@
#!/usr/bin/env ruby
+# -*- coding: euc-jp -*-
#
# ixset --
# A nice interface to "xset" to change X server settings
diff --git a/ext/tk/sample/demos-jp/knightstour.rb b/ext/tk/sample/demos-jp/knightstour.rb
new file mode 100644
index 0000000000..d4595ea441
--- /dev/null
+++ b/ext/tk/sample/demos-jp/knightstour.rb
@@ -0,0 +1,273 @@
+# -*- coding: euc-jp -*-
+#
+# Based on the widget demo of Tcl/Tk8.5.2
+# The following is the original copyright text.
+#----------------------------------------------------------------------------
+# Copyright (C) 2008 Pat Thoyts <patthoyts@users.sourceforge.net>
+#
+# Calculate a Knight's tour of a chessboard.
+#
+# This uses Warnsdorff's rule to calculate the next square each
+# time. This specifies that the next square should be the one that
+# has the least number of available moves.
+#
+# Using this rule it is possible to get to a position where
+# there are no squares available to move into. In this implementation
+# this occurs when the starting square is d6.
+#
+# To solve this fault an enhancement to the rule is that if we
+# have a choice of squares with an equal score, we should choose
+# the one nearest the edge of the board.
+#
+# If the call to the Edgemost function is commented out you can see
+# this occur.
+#
+# You can drag the knight to a specific square to start if you wish.
+# If you let it repeat then it will choose random start positions
+# for each new tour.
+#----------------------------------------------------------------------------
+require 'tk'
+
+class Knights_Tour
+ # Return a list of accessible squares from a given square
+ def valid_moves(square)
+ moves = []
+ [
+ [-1,-2], [-2,-1], [-2,1], [-1,2], [1,2], [2,1], [2,-1], [1,-2]
+ ].each{|col_delta, row_delta|
+ col = (square % 8) + col_delta
+ row = (square.div(8)) + row_delta
+ moves << (row * 8 + col) if row > -1 && row < 8 && col > -1 && col < 8
+ }
+ moves
+ end
+
+ # Return the number of available moves for this square
+ def check_square(square)
+ valid_moves(square).find_all{|pos| ! @visited.include?(pos)}.length
+ end
+
+ # Select the next square to move to. Returns -1 if there are no available
+ # squares remaining that we can move to.
+ def next_square(square)
+ minimum = 9
+ nxt = -1
+ valid_moves(square).each{|pos|
+ unless @visited.include?(pos)
+ cnt = check_square(pos)
+ if cnt < minimum
+ minimum = cnt
+ nxt = pos
+ elsif cnt == minimum
+ nxt = edgemost(nxt, pos)
+ end
+ end
+ }
+ nxt
+ end
+
+ # Select the square nearest the edge of the board
+ def edgemost(nxt, pos)
+ col_A = 3 - ((3.5 - nxt % 8).abs.to_i)
+ col_B = 3 - ((3.5 - pos % 8).abs.to_i)
+ row_A = 3 - ((3.5 - nxt.div(8)).abs.to_i)
+ row_B = 3 - ((3.5 - pos.div(8)).abs.to_i)
+ (col_A * row_A < col_B * row_B)? nxt : pos
+ end
+
+ # Display a square number as a standard chess square notation.
+ def _N(square)
+ '%c%d' % [(97 + square % 8), (square.div(8) + 1)]
+ end
+
+ # Perform a Knight's move and schedule the next move.
+ def move_piece(last, square)
+ @log.insert(:end, "#{@visited.length}. #{_N last} -> #{_N square}\n", '')
+ @log.see(:end)
+ @board.itemconfigure(1+last, :state=>:normal, :outline=>'black')
+ @board.itemconfigure(1+square, :state=>:normal, :outline=>'red')
+ @knight.coords(@board.coords(1+square)[0..1])
+ @visited << square
+ if (nxt = next_square(square)) != -1
+ @after_id = Tk.after(@delay.numeric){move_piece(square, nxt) rescue nil}
+ else
+ @start_btn.state :normal
+ if @visited.length == 64
+ if @initial == square
+ @log.insert :end, '¼þÍ·(closed tour)À®¸ù¡ª'
+ else
+ @log.insert :end, "À®¸ù\n", {}
+ Tk.after(@delay.numeric * 2){tour(rand(64))} if @continuous.bool
+ end
+ else
+ @log.insert :end, "¼ºÇÔ¡ª\n", {}
+ end
+ end
+ end
+
+ # Begin a new tour of the board given a random start position
+ def tour(square = nil)
+ @visited.clear
+ @log.clear
+ @start_btn.state :disabled
+ 1.upto(64){|n|
+ @board.itemconfigure(n, :state=>:disabled, :outline=>'black')
+ }
+ unless square
+ square = @board.find_closest(*(@knight.coords << 0 << 65))[0].to_i - 1
+ end
+ @initial = square
+ Tk.after_idle{ move_piece(@initial, @initial) rescue nil }
+ end
+
+ def _stop
+ Tk.after_cancel(@after_id) rescue nil
+ end
+
+ def _exit
+ _stop
+ $knightstour.destroy
+ end
+
+ def set_delay(new)
+ @delay.numeric = new.to_i
+ end
+
+ def drag_start(w, x, y)
+ w.dtag('selected')
+ w.addtag('selected', :withtag, 'current')
+ @dragging = [x, y]
+ end
+
+ def drag_motion(w, x, y)
+ return unless @dragging
+ w.move('selected', x - @dragging[0], y - @dragging[1])
+ @dragging = [x, y]
+ end
+
+ def drag_end(w, x, y)
+ square = w.find_closest(x, y, 0, 65)
+ w.coords('selected', w.coords(square)[0..1])
+ w.dtag('selected')
+ @dragging = nil
+ end
+
+ def make_SeeDismiss
+ ## See Code / Dismiss
+ frame = Ttk::Frame.new($knightstour)
+ sep = Ttk::Separator.new(frame)
+ Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
+ TkGrid('x',
+ Ttk::Button.new(frame, :text=>'¥³¡¼¥É»²¾È',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{showCode 'knightstour'}),
+ Ttk::Button.new(frame, :text=>'ÊĤ¸¤ë',
+ :image=>$image['delete'], :compound=>:left,
+ :command=>proc{
+ $knightstour.destroy
+ $knightstour = nil
+ }),
+ :padx=>4, :pady=>4)
+ frame.grid_columnconfigure(0, :weight=>1)
+ frame
+ end
+
+ def create_gui(parent = nil)
+ $knightstour.destroy rescue nil
+ $knightstour = Tk::Toplevel.new(parent, :title=>"Knight's tour")
+ $knightstour.withdraw
+ base_f = Ttk::Frame.new($knightstour)
+ @board = Tk::Canvas.new(base_f, :width=>240, :height=>240)
+ @log = Tk::Text.new(base_f, :width=>12, :height=>1,
+ :font=>'Arial 8', :background=>'white')
+ scr = @log.yscrollbar(Ttk::Scrollbar.new(base_f))
+
+ @visited = []
+ @delay = TkVariable.new(600)
+ @continuous = TkVariable.new(false)
+
+ tool_f = Ttk::Frame.new($knightstour)
+ label = Ttk::Label.new(tool_f, :text=>'¼Â¹Ô®ÅÙ')
+ scale = Ttk::Scale.new(tool_f, :from=>8, :to=>2000, :variable=>@delay,
+ :command=>proc{|n| set_delay(n)})
+ check = Ttk::Checkbutton.new(tool_f, :text=>'È¿Éü',
+ :variable=>@continuous)
+ @start_btn = Ttk::Button.new(tool_f, :text=>'³«»Ï',
+ :command=>proc{tour()})
+ @exit_btn = Ttk::Button.new(tool_f, :text=>'½ªÎ»',
+ :command=>proc{_exit()})
+
+ 7.downto(0){|row|
+ 0.upto(7){|col|
+ if ((col & 1) ^ (row & 1)).zero?
+ fill = 'bisque'
+ dfill = 'bisque3'
+ else
+ fill = 'tan3'
+ dfill = 'tan4'
+ end
+ coords = [col * 30 + 4, row * 30 + 4, col * 30 + 30, row * 30 + 30]
+ @board.create(TkcRectangle, coords,
+ :fill=>fill, :disabledfill=>dfill,
+ :width=>2, :state=>:disabled)
+ }
+ }
+
+ @knight_font = TkFont.new(:size=>-24)
+ @knight = TkcText.new(@board, 0, 0, :font=>@knight_font,
+ :text=>Tk::UTF8_String.new('\u265e'),
+ :anchor=>'nw', # :tags=>'knight',
+ :fill=>'black', :activefill=>'#600000')
+ @knight.coords(@board.coords(rand(64)+1)[0..1])
+ @knight.bind('ButtonPress-1', '%W %x %y'){|w,x,y| drag_start(w,x,y)}
+ @knight.bind('Motion', '%W %x %y'){|w,x,y| drag_motion(w,x,y)}
+ @knight.bind('ButtonRelease-1', '%W %x %y'){|w,x,y| drag_end(w,x,y)}
+
+ Tk.grid(@board, @log, scr, :sticky=>'news')
+ base_f.grid_rowconfigure(0, :weight=>1)
+ base_f.grid_columnconfigure(0, :weight=>1)
+
+ Tk.grid(base_f, '-', '-', '-', '-', '-', :sticky=>'news')
+ widgets = [label, scale, check, @start_btn]
+ sg = nil
+ unless $RubyTk_WidgetDemo
+ widgets << @exit_btn
+ if Tk.windowingsystem != 'aqua'
+ #widgets.unshift(Ttk::SizeGrip.new(tool_f))
+ Ttk::SizeGrip.new(tool_f).pack(:side=>:right, :anchor=>'se')
+ end
+ end
+ Tk.pack(widgets, :side=>:right)
+ if Tk.windowingsystem == 'aqua'
+ TkPack.configure(widgets, :padx=>[4, 4], :pady=>[12, 12])
+ TkPack.configure(widgets[0], :padx=>[4, 24])
+ TkPack.configure(widgets[-1], :padx=>[16, 4])
+ end
+
+ Tk.grid(tool_f, '-', '-', '-', '-', '-', :sticky=>'ew')
+
+ if $RubyTk_WidgetDemo
+ Tk.grid(make_SeeDismiss(), '-', '-', '-', '-', '-', :sticky=>'ew')
+ end
+
+ $knightstour.grid_rowconfigure(0, :weight=>1)
+ $knightstour.grid_columnconfigure(0, :weight=>1)
+
+ $knightstour.bind('Control-F2'){TkConsole.show}
+ $knightstour.bind('Return'){@start_btn.invoke}
+ $knightstour.bind('Escape'){@exit_btn.invoke}
+ $knightstour.bind('Destroy'){ _stop }
+ $knightstour.protocol('WM_DELETE_WINDOW'){ _exit }
+
+ $knightstour.deiconify
+ $knightstour.tkwait_destroy
+ end
+
+ def initialize(parent = nil)
+ create_gui(parent)
+ end
+end
+
+Tk.root.withdraw unless $RubyTk_WidgetDemo
+Thread.new{Tk.mainloop} if __FILE__ == $0
+Knights_Tour.new
diff --git a/ext/tk/sample/demos-jp/label.rb b/ext/tk/sample/demos-jp/label.rb
index 59626289fc..2e6b3e7e57 100644
--- a/ext/tk/sample/demos-jp/label.rb
+++ b/ext/tk/sample/demos-jp/label.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# label widget demo (called by 'widget')
#
@@ -15,8 +16,10 @@ $label_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($label_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-msg = TkLabel.new($label_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -25,7 +28,7 @@ msg = TkLabel.new($label_demo) {
msg.pack('side'=>'top')
# frame À¸À®
-TkFrame.new($label_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -44,8 +47,8 @@ TkFrame.new($label_demo) {|frame|
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# label demo Íѥե졼¥àÀ¸À®
-f_left = TkFrame.new($label_demo)
-f_right = TkFrame.new($label_demo)
+f_left = TkFrame.new(base_frame)
+f_right = TkFrame.new(base_frame)
[f_left, f_right].each{|w| w.pack('side'=>'left', 'expand'=>'yes',
'padx'=>10, 'pady'=>10, 'fill'=>'both')}
@@ -56,7 +59,8 @@ f_right = TkFrame.new($label_demo)
TkLabel.new(f_left, 'text'=>'3 ÈÖÌÜ¡£ÄÀ¤ó¤Ç¤¤¤Þ¤¹ ', 'relief'=>'sunken')
].each{|w| w.pack('side'=>'top', 'expand'=>'yes', 'pady'=>2, 'anchor'=>'w')}
-TkLabel.new(f_right) {
+# TkLabel.new(f_right) {
+Tk::Label.new(f_right) {
bitmap('@' + [$demo_dir,'..','images','face.xbm'].join(File::Separator))
borderwidth 2
relief 'sunken'
diff --git a/ext/tk/sample/demos-jp/labelframe.rb b/ext/tk/sample/demos-jp/labelframe.rb
index 23c974dcc2..11b0d27308 100644
--- a/ext/tk/sample/demos-jp/labelframe.rb
+++ b/ext/tk/sample/demos-jp/labelframe.rb
@@ -1,3 +1,5 @@
+# -*- coding: euc-jp -*-
+#
# labelframe.rb
#
# This demonstration script creates a toplevel window containing
@@ -17,8 +19,10 @@ $labelframe_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($labelframe_demo).pack(:fill=>:both, :expand=>true)
+
# Some information
-TkLabel.new($labelframe_demo,
+TkLabel.new(base_frame,
:font=>$font, :wraplength=>'4i', :justify=>:left,
:text=><<EOL).pack(:side=>:top)
TkLabelFrame ¥¦¥£¥¸¥§¥Ã¥È¤Ï´ØÏ¢¤¹¤ë widget
@@ -34,7 +38,7 @@ labelframe ¥¦¥£¥¸¥§¥Ã¥È¤ò¼ÂÁõ¤·¤Æ¤¤¤Ê¤¤
EOL
# The bottom buttons
-TkFrame.new($labelframe_demo){|f|
+TkFrame.new(base_frame){|f|
pack(:side=>:bottom, :fill=>:x, :pady=>'2m')
TkButton.new(f, :text=>'ÊĤ¸¤ë', :width=>15, :command=>proc{
@@ -48,7 +52,7 @@ TkFrame.new($labelframe_demo){|f|
}
# Demo area
-w = TkFrame.new($labelframe_demo).pack(:side=>:bottom, :fill=>:both,
+w = TkFrame.new(base_frame).pack(:side=>:bottom, :fill=>:both,
:expand=>true)
# A group of radiobuttons in a labelframe
diff --git a/ext/tk/sample/demos-jp/mclist.rb b/ext/tk/sample/demos-jp/mclist.rb
new file mode 100644
index 0000000000..a7834d2668
--- /dev/null
+++ b/ext/tk/sample/demos-jp/mclist.rb
@@ -0,0 +1,121 @@
+# -*- coding: euc-jp -*-
+#
+# mclist.rb --
+#
+# This demonstration script creates a toplevel window containing a Ttk
+# tree widget configured as a multi-column listbox.
+#
+# based on "Id: mclist.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp"
+
+if defined?($mclist_demo) && $mclist_demo
+ $mclist_demo.destroy
+ $mclist_demo = nil
+end
+
+$mclist_demo = TkToplevel.new {|w|
+ title("Multi-Column List")
+ iconname("mclist")
+ positionWindow(w)
+}
+
+base_frame = TkFrame.new($mclist_demo).pack(:fill=>:both, :expand=>true)
+
+## Explanatory text
+Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i',
+ :justify=>:left, :anchor=>'n', :padding=>[10, 2, 10, 6],
+ :text=><<EOL).pack(:fill=>:x)
+Ttk¤È¤Ï¡¤¥Æ¡¼¥Þ»ØÄê²Äǽ¤Ê¿·¤·¤¤¥¦¥£¥¸¥§¥Ã¥È½¸¹ç¤Ç¤¹¡¥\
+Ttk::Treeview¥¦¥£¥¸¥§¥Ã¥È¤Ï\
+Ttk¥¦¥£¥¸¥§¥Ã¥È¥»¥Ã¥È¤Ë´Þ¤Þ¤ì¤ë¥¦¥£¥¸¥§¥Ã¥È¤Î°ì¤Ä¤Ç¡¤\
+¤½¤ì¤¬ÊÝ»ý¤¹¤ëÌÚ¹½Â¤¤Î¥Ç¡¼¥¿¤½¤Î¤â¤Î¤Þ¤Ç¤Ïɽ¼¨¤¹¤ë¤³¤È¤Ê¤¯¡¤\
+¼¨¤·¤¿¤¤¾ðÊó¤ò¥Þ¥ë¥Á¥«¥é¥à¤Çɽ¼¨¤µ¤»¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡¥
+¤³¤Î¥µ¥ó¥×¥ë¤Ï¡¤Ê£¿ô¤Î¥«¥é¥à¤ò»ý¤Ã¤¿¥ê¥¹¥È¥Ü¥Ã¥¯¥¹¤òºîÀ®¤¹¤ë´Êñ¤ÊÎã¤Ç¤¹¡¥
+³Æ¥«¥é¥à¤Î¥¿¥¤¥È¥ë(heading)¤ò¥¯¥ê¥Ã¥¯¤¹¤ì¤Ð¡¤\
+¤½¤Î¥«¥é¥à¤Î¾ðÊó¤Ë´ð¤Å¤¤¤Æ¥ê¥¹¥È¤ÎʤÙÂØ¤¨¤¬¤Ê¤µ¤ì¤ë¤Ï¤º¤Ç¤¹¡¥\
+¤Þ¤¿¡¤¥«¥é¥à¤Î¥¿¥¤¥È¥ë´Ö¤Î¶èÀÚ¤êÉôʬ¤ò¥É¥é¥Ã¥°¤¹¤ë¤³¤È¤Ç¡¤\
+¥«¥é¥à¤ÎÉý¤òÊѹ¹¤¹¤ë¤³¤È¤â²Äǽ¤Ç¤¹¡¥
+EOL
+
+## See Code / Dismiss
+Ttk::Frame.new(base_frame) {|frame|
+ sep = Ttk::Separator.new(frame)
+ Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
+ TkGrid('x',
+ Ttk::Button.new(frame, :text=>'¥³¡¼¥É»²¾È',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{showCode 'mclist'}),
+ Ttk::Button.new(frame, :text=>'ÊĤ¸¤ë',
+ :image=>$image['delete'], :compound=>:left,
+ :command=>proc{
+ $mclist_demo.destroy
+ $mclist_demo = nil
+ }),
+ :padx=>4, :pady=>4)
+ grid_columnconfigure(0, :weight=>1)
+ pack(:side=>:bottom, :fill=>:x)
+}
+
+container = Ttk::Frame.new(base_frame)
+tree = Ttk::Treeview.new(base_frame, :columns=>%w(country capital currency),
+ :show=>:headings)
+if Tk.windowingsystem != 'aquq'
+ vsb = tree.yscrollbar(Ttk::Scrollbar.new(base_frame))
+ hsb = tree.xscrollbar(Ttk::Scrollbar.new(base_frame))
+else
+ vsb = tree.yscrollbar(Tk::Scrollbar.new(base_frame))
+ hsb = tree.xscrollbar(Tk::Scrollbar.new(base_frame))
+end
+
+container.pack(:fill=>:both, :expand=>true)
+Tk.grid(tree, vsb, :in=>container, :sticky=>'nsew')
+Tk.grid(hsb, :in=>container, :sticky=>'nsew')
+container.grid_columnconfigure(0, :weight=>1)
+container.grid_rowconfigure(0, :weight=>1)
+
+## The data we're going to insert
+data = [
+ ['¥¢¥ë¥¼¥ó¥Á¥ó', '¥Ö¥¨¥Î¥¹¥¢¥¤¥ì¥¹', 'ARS'],
+ ['¥ª¡¼¥¹¥È¥é¥ê¥¢', '¥­¥ã¥ó¥Ù¥é', 'AUD'],
+ ['¥Ö¥é¥¸¥ë', '¥Ö¥é¥¸¥ê¥¢', 'BRL'],
+ ['¥«¥Ê¥À', '¥ª¥¿¥ï', 'CAD'],
+ ['Ãæ¹ñ', 'Ë̵þ', 'CNY'],
+ ['¥Õ¥é¥ó¥¹', '¥Ñ¥ê', 'EUR'],
+ ['¥É¥¤¥Ä', '¥Ù¥ë¥ê¥ó', 'EUR'],
+ ['¥¤¥ó¥É', '¥Ë¥å¡¼¥Ç¥ê¡¼', 'INR'],
+ ['¥¤¥¿¥ê¥¢', '¥í¡¼¥Þ', 'EUR'],
+ ['ÆüËÜ', 'Åìµþ', 'JPY'],
+ ['¥á¥­¥·¥³', '¥á¥­¥·¥³¥·¥Æ¥£', 'MXN'],
+ ['¥í¥·¥¢', '¥â¥¹¥¯¥ï', 'RUB'],
+ ['Æî¥¢¥Õ¥ê¥«', '¥×¥ì¥È¥ê¥¢', 'ZAR'],
+ ['±Ñ¹ñ', '¥í¥ó¥É¥ó', 'GBP'],
+ ['¥¢¥á¥ê¥«', '¥ï¥·¥ó¥È¥ó D.C.', 'USD'],
+]
+
+## Code to insert the data nicely
+font = Ttk::Style.lookup(tree[:style], :font)
+cols = %w(country capital currency)
+cols.zip(%w(¹ñ̾ ¼óÅÔ Ä̲ß)).each{|col, name|
+ tree.heading_configure(col, :text=>name,
+ :command=>proc{sort_by(tree, col, false)})
+ tree.column_configure(col, :width=>TkFont.measure(font, name))
+}
+
+data.each{|country, capital, currency|
+ #tree.insert('', :end, :values=>[country, capital, currency])
+ tree.insert(nil, :end, :values=>[country, capital, currency])
+ cols.zip([country, capital, currency]).each{|col, val|
+ len = TkFont.measure(font, "#{val} ")
+ if tree.column_cget(col, :width) < len
+ tree.column_configure(col, :width=>len)
+ end
+ }
+}
+
+## Code to do the sorting of the tree contents when clicked on
+def sort_by(tree, col, direction)
+ tree.children(nil).map!{|row| [tree.get(row, col), row.id]} .
+ sort(&((direction)? proc{|x, y| y <=> x}: proc{|x, y| x <=> y})) .
+ each_with_index{|info, idx| tree.move(info[1], nil, idx)}
+
+ tree.heading_configure(col, :command=>proc{sort_by(tree, col, ! direction)})
+end
diff --git a/ext/tk/sample/demos-jp/menu.rb b/ext/tk/sample/demos-jp/menu.rb
index add85f7f7b..c3d95176b4 100644
--- a/ext/tk/sample/demos-jp/menu.rb
+++ b/ext/tk/sample/demos-jp/menu.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# menus widget demo (called by 'widget')
#
@@ -15,8 +16,10 @@ $menu_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($menu_demo).pack(:fill=>:both, :expand=>true)
+
# menu frame À¸À®
-$menu_frame = TkFrame.new($menu_demo, 'relief'=>'raised', 'bd'=>2)
+$menu_frame = TkFrame.new(base_frame, 'relief'=>'raised', 'bd'=>2)
$menu_frame.pack('side'=>'top', 'fill'=>'x')
begin
@@ -26,7 +29,7 @@ rescue
end
# label À¸À®
-TkLabel.new($menu_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left') {
+TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left') {
if $tk_platform['platform'] == 'macintosh' ||
windowingsystem == "classic" || windowingsystem == "aqua"
text("¤³¤Î¥¦¥£¥ó¥É¥¦¤ÏÍÍ¡¹¤Ê¥á¥Ë¥å¡¼¤È¥«¥¹¥±¡¼¥É¥á¥Ë¥å¡¼¤«¤é¹½À®¤µ¤ì¤Æ¤¤¤Þ¤¹¡£Command-X ¤òÆþÎϤ¹¤ë¤È¡¢X¤¬¥³¥Þ¥ó¥É¥­¡¼µ­¹æ¤Ë³¤¤¤ÆÉ½¼¨¤µ¤ì¤Æ¤¤¤ëʸ»ú¤Ê¤é¤Ð¡¢¥¢¥¯¥»¥é¥ì¡¼¥¿¤ò»È¤Ã¤¿¹àÌܵ¯Æ°¤ò¹Ô¤¦¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£¥á¥Ë¥å¡¼Í×ÁÇÃæ¡¢ºÇ¸å¤Î¤â¤Î¤Ï¡¢¤½¤Î¥á¥Ë¥å¡¼¤ÎºÇ½é¤Î¹àÌܤòÁªÂò¤¹¤ë¤³¤È¤ÇÆÈΩ¤µ¤»¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£")
@@ -36,7 +39,7 @@ TkLabel.new($menu_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left') {
}.pack('side'=>'top')
# frame À¸À®
-TkFrame.new($menu_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -107,7 +110,8 @@ TkMenubutton.new($menu_frame, 'text'=>'Cascades', 'underline'=>0) {|m|
'accelerator'=>"#{modifier}+G", 'underline'=>6)
$menu_demo.bind("#{modifier}-g", proc{print "Goodbye(¤µ¤è¤¦¤Ê¤é)\n"})
- TkMenu.new(m, 'tearoff'=>false) {|cascade_check|
+ # TkMenu.new(m, 'tearoff'=>false) {|cascade_check|
+ TkMenu.new(cascade_menu, 'tearoff'=>false) {|cascade_check|
cascade_menu.add('cascade', 'label'=>'Check buttons(¥Á¥§¥Ã¥¯¥Ü¥¿¥ó)',
'menu'=>cascade_check, 'underline'=>0)
oil = TkVariable.new(0)
@@ -129,7 +133,8 @@ TkMenubutton.new($menu_frame, 'text'=>'Cascades', 'underline'=>0) {|m|
invoke 3
}
- TkMenu.new(m, 'tearoff'=>false) {|cascade_radio|
+ #TkMenu.new(m, 'tearoff'=>false) {|cascade_radio|
+ TkMenu.new(cascade_menu, 'tearoff'=>false) {|cascade_radio|
cascade_menu.add('cascade', 'label'=>'Radio buttons(¥é¥¸¥ª¥Ü¥¿¥ó)',
'menu'=>cascade_radio, 'underline'=>0)
pointSize = TkVariable.new
diff --git a/ext/tk/sample/demos-jp/menu84.rb b/ext/tk/sample/demos-jp/menu84.rb
index 8c2a815d78..a631bacd43 100644
--- a/ext/tk/sample/demos-jp/menu84.rb
+++ b/ext/tk/sample/demos-jp/menu84.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# menus widget demo (called by 'widget')
#
@@ -15,6 +16,8 @@ $menu84_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($menu84_demo).pack(:fill=>:both, :expand=>true)
+
begin
windowingsystem = Tk.windowingsystem()
rescue
@@ -22,7 +25,7 @@ rescue
end
# label
-TkLabel.new($menu84_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left') {
+TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left') {
if $tk_platform['platform'] == 'macintosh' ||
windowingsystem == "classic" || windowingsystem == "aqua"
text("¤³¤Î¥¦¥£¥ó¥É¥¦¤Ë¤Ï¥«¥¹¥±¡¼¥É¥á¥Ë¥å¡¼¤ò»ý¤Ä¥á¥Ë¥å¡¼¥Ð¡¼¤¬ÉÕ¤±¤é¤ì¤Æ¤¤¤Þ¤¹¡£Command+x ('x'¤Ï¥³¥Þ¥ó¥É¥­¡¼¥·¥ó¥Ü¥ë¤Ë³¤±¤ÆÉ½¼¨¤µ¤ì¤Æ¤¤¤ëʸ»ú¤Ç¤¹) ¤È¥¿¥¤¥×¤¹¤ë¤³¤È¤Ë¤è¤Ã¤Æ¤â¹àÌܤε¡Ç½¤ò¸Æ¤Ó½Ð¤¹¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£ºÇ¸å¤Î¥á¥Ë¥å¡¼¤Ï¡¢¥Þ¥¦¥¹¤Ç¥¦¥£¥ó¥É¥¦¤Î³°¤Ë¥É¥é¥Ã¥°¤¹¤ë¤³¤È¤Ë¤è¤Ã¤Æ¡¢ÆÈΩ¤·¤¿¥Ñ¥ì¥Ã¥È¤È¤Ê¤ë¤è¤¦¤ËÀÚ¤êÊü¤¹¤³¤È¤¬²Äǽ¤Ç¤¹¡£")
@@ -33,7 +36,7 @@ TkLabel.new($menu84_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left') {
menustatus = TkVariable.new(" ")
-TkFrame.new($menu84_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkLabel.new(frame, 'textvariable'=>menustatus, 'relief'=>'sunken',
'bd'=>1, 'font'=>['Helvetica', '10'],
'anchor'=>'w').pack('side'=>'left', 'padx'=>2,
@@ -43,7 +46,7 @@ TkFrame.new($menu84_demo) {|frame|
# frame
-TkFrame.new($menu84_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
diff --git a/ext/tk/sample/demos-jp/menu8x.rb b/ext/tk/sample/demos-jp/menu8x.rb
index 050f0decb4..9249f2491a 100644
--- a/ext/tk/sample/demos-jp/menu8x.rb
+++ b/ext/tk/sample/demos-jp/menu8x.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# menus widget demo (called by 'widget')
#
@@ -15,16 +16,18 @@ $menu8x_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($menu8x_demo).pack(:fill=>:both, :expand=>true)
+
# version check
if $tk_version.to_f < 8.0
# label À¸À®
-TkLabel.new($menu8x_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left') {
+TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left') {
text("¼Â¹Ô¤·¤è¤¦¤È¤·¤¿¥¹¥¯¥ê¥×¥È¤Ï Tk8.0 °Ê¾å¤ÇÍøÍѤǤ­¤ëµ¡Ç½¤òÍøÍѤ·¤Æ¤¤¤ë¤¿¤á¡¢¤¢¤Ê¤¿¤Î Ruby#{VERSION}/Tk#{$tk_version}#{(Tk::JAPANIZED_TK)? 'jp': ''} ¤Ç¤ÏÀµ¾ï¤Ë¼Â¹Ô¤Ç¤­¤Þ¤»¤ó¡£¤è¤Ã¤Æ¥Ç¥â¤Î¼Â¹Ô¤òÃæ»ß¤·¤Þ¤·¤¿¡£¤¿¤À¤·¡¢²¼¤Î¥³¡¼¥É»²¾È¥Ü¥¿¥ó¤ò²¡¤¹¤³¤È¤Ç¡¢¼Â¹Ô¤¬Ãæ»ß¤µ¤ì¤¿¥¹¥¯¥ê¥×¥È¤Î¥½¡¼¥¹¤ò»²¾È¤¹¤ë¤³¤È¤Ï²Äǽ¤Ç¤¹¡£")
}.pack('side'=>'top')
# frame À¸À®
-TkFrame.new($menu8x_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -50,7 +53,7 @@ rescue
end
# label À¸À®
-TkLabel.new($menu8x_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left') {
+TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left') {
if $tk_platform['platform'] == 'macintosh' ||
windowingsystem == "classic" || windowingsystem == "aqua"
text("¤³¤Î¥¦¥£¥ó¥É¥¦¤ÏÍÍ¡¹¤Ê¥á¥Ë¥å¡¼¤È¥«¥¹¥±¡¼¥É¥á¥Ë¥å¡¼¤«¤é¹½À®¤µ¤ì¤Æ¤¤¤Þ¤¹¡£Command-X ¤òÆþÎϤ¹¤ë¤È¡¢X¤¬¥³¥Þ¥ó¥É¥­¡¼µ­¹æ¤Ë³¤¤¤ÆÉ½¼¨¤µ¤ì¤Æ¤¤¤ëʸ»ú¤Ê¤é¤Ð¡¢¥¢¥¯¥»¥é¥ì¡¼¥¿¤ò»È¤Ã¤¿¹àÌܵ¯Æ°¤ò¹Ô¤¦¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£¥á¥Ë¥å¡¼Í×ÁÇÃæ¡¢ºÇ¸å¤Î¤â¤Î¤Ï¡¢¤½¤Î¥á¥Ë¥å¡¼¤ÎºÇ½é¤Î¹àÌܤòÁªÂò¤¹¤ë¤³¤È¤ÇÆÈΩ¤µ¤»¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£")
@@ -61,14 +64,14 @@ TkLabel.new($menu8x_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left') {
# ¾õÂÖɽ¼¨¤ÎÀ¸À®
$menu8xstatus = TkVariable.new(" ")
-TkFrame.new($menu8x_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkLabel.new(frame, 'textvariable'=>$menu8xstatus, 'relief'=>'sunken',
'bd'=>1, 'font'=>['Helvetica', '10'], 'anchor'=>'w')\
.pack('side'=>'left', 'padx'=>2, 'expand'=>'yes', 'fill'=>'both')
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>2)
# frame À¸À®
-TkFrame.new($menu8x_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
diff --git a/ext/tk/sample/demos-jp/menubu.rb b/ext/tk/sample/demos-jp/menubu.rb
index aa90a3087f..90dc367305 100644
--- a/ext/tk/sample/demos-jp/menubu.rb
+++ b/ext/tk/sample/demos-jp/menubu.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
require "tkcanvas"
def optionMenu(menubutton, varName, firstValue, *rest)
@@ -32,16 +33,18 @@ $menubu_demo = TkToplevel.new {|w|
positionWindow($menubu_demo)
+base_frame = TkFrame.new($menubu_demo).pack(:fill=>:both, :expand=>true)
+
# version check
if $tk_version.to_f < 8.0
# label À¸À®
-TkLabel.new($menubu_demo,'font'=>$font,'wraplength'=>'4i','justify'=>'left') {
+TkLabel.new(base_frame,'font'=>$font,'wraplength'=>'4i','justify'=>'left') {
text("¼Â¹Ô¤·¤è¤¦¤È¤·¤¿¥¹¥¯¥ê¥×¥È¤Ï Tk8.0 °Ê¾å¤ÇÍøÍѤǤ­¤ëµ¡Ç½¤òÍøÍѤ·¤Æ¤¤¤ë¤¿¤á¡¢¤¢¤Ê¤¿¤Î Ruby#{VERSION}/Tk#{$tk_version}#{(Tk::JAPANIZED_TK)? 'jp': ''} ¤Ç¤ÏÀµ¾ï¤Ë¼Â¹Ô¤Ç¤­¤Þ¤»¤ó¡£¤è¤Ã¤Æ¥Ç¥â¤Î¼Â¹Ô¤òÃæ»ß¤·¤Þ¤·¤¿¡£¤¿¤À¤·¡¢²¼¤Î¥³¡¼¥É»²¾È¥Ü¥¿¥ó¤ò²¡¤¹¤³¤È¤Ç¡¢¼Â¹Ô¤¬Ãæ»ß¤µ¤ì¤¿¥¹¥¯¥ê¥×¥È¤Î¥½¡¼¥¹¤ò»²¾È¤¹¤ë¤³¤È¤Ï²Äǽ¤Ç¤¹¡£")
}.pack('side'=>'top')
# frame À¸À®
-TkFrame.new($menubu_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -60,7 +63,7 @@ TkFrame.new($menubu_demo) {|frame|
else ; # Tk8.x
-body = TkFrame.new($menubu_demo)
+body = TkFrame.new(base_frame)
body.pack('expand'=>'yes', 'fill'=>'both')
below = TkMenubutton.new(body) {
@@ -155,7 +158,7 @@ center = TkFrame.new(body) {
grid('row'=>1, 'column'=>1, 'sticky'=>'news')
}
-TkFrame.new($menubu_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
diff --git a/ext/tk/sample/demos-jp/msgbox.rb b/ext/tk/sample/demos-jp/msgbox.rb
index 983e6b6589..88380e08bd 100644
--- a/ext/tk/sample/demos-jp/msgbox.rb
+++ b/ext/tk/sample/demos-jp/msgbox.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# message boxes widget demo (called by 'widget')
#
@@ -15,12 +16,14 @@ $msgbox_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($msgbox_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-TkLabel.new($msgbox_demo, 'font'=>$font, 'wraplength'=>'4i', 'justify'=>'left',
- 'text'=>"ɽ¼¨¤¹¤ë¥¢¥¤¥³¥ó¤È¥á¥Ã¥»¡¼¥¸¥Ü¥Ã¥¯¥¹¤Î¼ïÎà¤òÁª¤ó¤Ç²¼¤µ¤¤¡£¤½¤·¤Æ \"¥á¥Ã¥»¡¼¥¸¥Ü¥Ã¥¯¥¹\" ¥Ü¥¿¥ó¤ò²¡¤¹¤È¡¢»ØÄꤷ¤¿¥á¥Ã¥»¡¼¥¸¥Ü¥Ã¥¯¥¹¤¬É½¼¨¤µ¤ì¤Þ¤¹¡£").pack('side'=>'top')
+TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'4i', 'justify'=>'left',
+ 'text'=>"¤Þ¤ºÉ½¼¨¤¹¤ë¥¢¥¤¥³¥ó¤È¥á¥Ã¥»¡¼¥¸¥Ü¥Ã¥¯¥¹¤Î¼ïÎà¤òÁª¤ó¤Ç²¼¤µ¤¤¡£¤½¤Î¸å¤Ë\"¥á¥Ã¥»¡¼¥¸¥Ü¥Ã¥¯¥¹\"¥Ü¥¿¥ó¤ò²¡¤¹¤È¡¢»ØÄꤷ¤¿¥á¥Ã¥»¡¼¥¸¥Ü¥Ã¥¯¥¹¤¬É½¼¨¤µ¤ì¤Þ¤¹¡£").pack('side'=>'top')
# frame À¸À®
-TkFrame.new($msgbox_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -43,8 +46,8 @@ TkFrame.new($msgbox_demo) {|frame|
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# frame À¸À®
-$msgbox_leftframe = TkFrame.new($msgbox_demo)
-$msgbox_rightframe = TkFrame.new($msgbox_demo)
+$msgbox_leftframe = TkFrame.new(base_frame)
+$msgbox_rightframe = TkFrame.new(base_frame)
$msgbox_leftframe .pack('side'=>'left', 'expand'=>'yes', 'fill'=>'y',
'pady'=>'.5c', 'padx'=>'.5c')
$msgbox_rightframe.pack('side'=>'left', 'expand'=>'yes', 'fill'=>'y',
@@ -78,7 +81,7 @@ $msgboxType = TkVariable.new('ok')
def showMessageBox(w)
button = Tk.messageBox('icon'=>$msgboxIcon.value, 'type'=>$msgboxType.value,
'title'=>'Message', 'parent'=>w,
- 'message'=>"¤³¤ì¤Ï \"#{$msgboxType.value}\" ¤È¤¤¤¦¼ïÎà¤Î¥á¥Ã¥»¡¼¥¸¥Ü¥Ã¥¯¥¹¤Ç¡¢\"#{$msgboxIcon.value}\" ¤Î¥¢¥¤¥³¥ó¤¬É½¼¨¤µ¤ì¤Æ¤¤¤Þ¤¹¡£")
+ 'message'=>"¤³¤ì¤Ï\"#{$msgboxType.value}\"¤È¤¤¤¦¼ïÎà¤Î¥á¥Ã¥»¡¼¥¸¥Ü¥Ã¥¯¥¹¤Ç¡¢\"#{$msgboxIcon.value}\"¤Î¥¢¥¤¥³¥ó¤¬É½¼¨¤µ¤ì¤Æ¤¤¤Þ¤¹¡£")
Tk.messageBox('icon'=>'info', 'type'=>'ok', 'parent'=>w,
'message'=>"¤¢¤Ê¤¿¤Ï \"#{button}\" ¤ò²¡¤·¤Þ¤·¤¿¤Í¡£")
diff --git a/ext/tk/sample/demos-jp/msgbox2.rb b/ext/tk/sample/demos-jp/msgbox2.rb
new file mode 100644
index 0000000000..d61f25129a
--- /dev/null
+++ b/ext/tk/sample/demos-jp/msgbox2.rb
@@ -0,0 +1,90 @@
+# -*- coding: euc-jp -*-
+#
+# message boxes widget demo (called by 'widget')
+#
+
+# toplevel widget ¤¬Â¸ºß¤¹¤ì¤Ðºï½ü¤¹¤ë
+if defined?($msgbox2_demo) && $msgbox2_demo
+ $msgbox2_demo.destroy
+ $msgbox2_demo = nil
+end
+
+# demo ÍѤΠtoplevel widget ¤òÀ¸À®
+$msgbox2_demo = TkToplevel.new {|w|
+ title("Message Box Demonstration")
+ iconname("messagebox")
+ positionWindow(w)
+}
+
+base_frame = TkFrame.new($msgbox2_demo).pack(:fill=>:both, :expand=>true)
+
+# label À¸À®
+TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'4i', 'justify'=>'left',
+ 'text'=>"¤Þ¤ºÉ½¼¨¤¹¤ë¥¢¥¤¥³¥ó¤È¥á¥Ã¥»¡¼¥¸¥Ü¥Ã¥¯¥¹¤Î¼ïÎà¤òÁª¤ó¤Ç²¼¤µ¤¤¡£¤½¤Î¸å¤Ë\"¥á¥Ã¥»¡¼¥¸¥Ü¥Ã¥¯¥¹\"¥Ü¥¿¥ó¤ò²¡¤¹¤È¡¢»ØÄꤵ¤ì¤¿·Á¼°¤Ç¡¢¥á¥Ã¥»¡¼¥¸¤È¾ÜºÙ¥Æ¥­¥¹¥È¤È¤ò»ý¤Ã¤¿¥á¥Ã¥»¡¼¥¸¥Ü¥Ã¥¯¥¹¤¬É½¼¨¤µ¤ì¤Þ¤¹¡£").pack('side'=>'top')
+
+# frame À¸À®
+TkFrame.new(base_frame) {|frame|
+ TkButton.new(frame) {
+ #text 'λ²ò'
+ text 'ÊĤ¸¤ë'
+ command proc{
+ tmppath = $msgbox2_demo
+ $msgbox2_demo = nil
+ tmppath.destroy
+ }
+ }.pack('side'=>'left', 'expand'=>'yes')
+
+ TkButton.new(frame) {
+ text '¥³¡¼¥É»²¾È'
+ command proc{showCode 'msgbox2'}
+ }.pack('side'=>'left', 'expand'=>'yes')
+
+ TkButton.new(frame) {
+ text '¥á¥Ã¥»¡¼¥¸¥Ü¥Ã¥¯¥¹'
+ command proc{showMessageBox $msgbox2_demo}
+ }.pack('side'=>'left', 'expand'=>'yes')
+}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
+
+# frame À¸À®
+$msgbox_leftframe = TkFrame.new(base_frame)
+$msgbox_rightframe = TkFrame.new(base_frame)
+$msgbox_leftframe .pack('side'=>'left', 'expand'=>'yes', 'fill'=>'y',
+ 'pady'=>'.5c', 'padx'=>'.5c')
+$msgbox_rightframe.pack('side'=>'left', 'expand'=>'yes', 'fill'=>'y',
+ 'pady'=>'.5c', 'padx'=>'.5c')
+
+TkLabel.new($msgbox_leftframe, 'text'=>'¥¢¥¤¥³¥ó').pack('side'=>'top')
+TkFrame.new($msgbox_leftframe, 'relief'=>'ridge', 'bd'=>1, 'height'=>2)\
+.pack('side'=>'top', 'fill'=>'x', 'expand'=>'no')
+
+$msgboxIcon = TkVariable.new('info')
+['error', 'info', 'question', 'warning'].each {|icon|
+ TkRadioButton.new($msgbox_leftframe, 'text'=>icon, 'variable'=>$msgboxIcon,
+ 'relief'=>'flat', 'value'=>icon, 'width'=>16,
+ 'anchor'=>'w').pack('side'=>'top', 'pady'=>2,
+ 'anchor'=>'w', 'fill'=>'x')
+}
+
+TkLabel.new($msgbox_rightframe, 'text'=>'¼ïÎà').pack('side'=>'top')
+TkFrame.new($msgbox_rightframe, 'relief'=>'ridge', 'bd'=>1, 'height'=>2)\
+.pack('side'=>'top', 'fill'=>'x', 'expand'=>'no')
+
+$msgboxType = TkVariable.new('ok')
+['abortretryignore', 'ok', 'okcancel',
+ 'retrycancel', 'yesno', 'yesnocancel'].each {|type|
+ TkRadioButton.new($msgbox_rightframe, 'text'=>type, 'variable'=>$msgboxType,
+ 'relief'=>'flat', 'value'=>type, 'width'=>16,
+ 'anchor'=>'w').pack('side'=>'top', 'pady'=>2,
+ 'anchor'=>'w', 'fill'=>'x')
+}
+
+def showMessageBox(w)
+ button = Tk.messageBox('icon'=>$msgboxIcon.value, 'type'=>$msgboxType.value,
+ 'title'=>'Message', 'parent'=>w,
+ 'message'=>"\"#{$msgboxType.value}\"¥¿¥¤¥×¤Î¥á¥Ã¥»¡¼¥¸¥Ü¥Ã¥¯¥¹",
+ 'detail'=>"¤³¤ì¤Ï\"#{$msgboxType.value}\"¤È¤¤¤¦¼ïÎà¤Î¥á¥Ã¥»¡¼¥¸¥Ü¥Ã¥¯¥¹¤Ç¡¢\"#{$msgboxIcon.value}\"¤Î¥¢¥¤¥³¥ó¤¬É½¼¨¤µ¤ì¤Æ¤¤¤Þ¤¹¡£²¼¤Î¥Ü¥¿¥ó¤Î¤¤¤º¤ì¤«¤òÁªÂò¤·¤Æ¥¯¥ê¥Ã¥¯¤·¤Æ¤¯¤À¤µ¤¤¡£")
+
+ Tk.messageBox('icon'=>'info', 'type'=>'ok', 'parent'=>w,
+ 'message'=>"¤¢¤Ê¤¿¤Ï \"#{button}\" ¤ò²¡¤·¤Þ¤·¤¿¤Í¡£")
+end
+
diff --git a/ext/tk/sample/demos-jp/paned1.rb b/ext/tk/sample/demos-jp/paned1.rb
index 8d16d03c08..f994e83ff1 100644
--- a/ext/tk/sample/demos-jp/paned1.rb
+++ b/ext/tk/sample/demos-jp/paned1.rb
@@ -1,3 +1,5 @@
+# -*- coding: euc-jp -*-
+#
# paned1.rb
#
# This demonstration script creates a toplevel window containing
@@ -16,7 +18,9 @@ $paned1_demo = TkToplevel.new {|w|
positionWindow(w)
}
-TkLabel.new($paned1_demo,
+base_frame = TkFrame.new($paned1_demo).pack(:fill=>:both, :expand=>true)
+
+TkLabel.new(base_frame,
:font=>$font, :wraplength=>'4i', :justify=>:left,
:text=><<EOL).pack(:side=>:top)
²¼¤Î¿§ÉÕ¤±¤µ¤ì¤¿Æó¤Ä¤Î¥¦¥£¥ó¥É¥¦¤Î´Ö¤Î»ÅÀÚ¤êÏȤϡ¢°ì¤Ä¤ÎÎΰè¤ò¤½¤ì¤¾¤ì¤Î¥¦¥£¥ó¥É¥¦¤Î¤¿¤á¤Ëʬ³ä¤¹¤ë¤¿¤á¤Î¤â¤Î¤Ç¤¹¡£º¸¥Ü¥¿¥ó¤Ç»ÅÀÚ¤ê¤òÁàºî¤¹¤ë¤È¡¢Ê¬³ä¥µ¥¤¥ºÊѹ¹¤ÎÁàºîÅÓÃæ¤Ç¤ÏºÆÉ½¼¨¤Ï¤Ê¤µ¤ì¤º¡¢³ÎÄꤵ¤»¤¿¤È¤­¤Ëɽ¼¨¤¬¹¹¿·¤µ¤ì¤Þ¤¹¡£¥Þ¥¦¥¹¤Ë¤è¤ë»ÅÀÚ¤ê¤ÎÁàºî¤ËÄɿ路¤Æ¥µ¥¤¥º¤òÊѹ¹¤·¤¿É½¼¨¤¬¤Ê¤ï¤ì¤ë¤è¤¦¤Ë¤·¤¿¤¤¾ì¹ç¤Ï¡¢¥Þ¥¦¥¹¤ÎÃæ±û¥Ü¥¿¥ó¤ò»È¤Ã¤Æ¤¯¤À¤µ¤¤¡£
@@ -27,7 +31,7 @@ TkLabel.new($paned1_demo,
EOL
# The bottom buttons
-TkFrame.new($paned1_demo){|f|
+TkFrame.new(base_frame){|f|
pack(:side=>:bottom, :fill=>:x, :pady=>'2m')
TkButton.new(f, :text=>'ÊĤ¸¤ë', :width=>15, :command=>proc{
@@ -40,9 +44,9 @@ TkFrame.new($paned1_demo){|f|
}).pack(:side=>:left, :expand=>true)
}
-TkPanedwindow.new($paned1_demo){|f|
- pack(:side=>:top, :expand=>true, :fill=>:both, :pady=>2, :padx=>'2m')
+TkPanedwindow.new(base_frame, :orient=>:horizontal){|f|
+ add(Tk::Label.new(f, :text=>"This is the\nleft side", :bg=>'yellow'),
+ Tk::Label.new(f, :text=>"This is the\nright side", :bg=>'cyan'))
- add(TkLabel.new(f, :text=>"This is the\nleft side", :bg=>'yellow'),
- TkLabel.new(f, :text=>"This is the\nright side", :bg=>'cyan'))
+ pack(:side=>:top, :expand=>true, :fill=>:both, :pady=>2, :padx=>'2m')
}
diff --git a/ext/tk/sample/demos-jp/paned2.rb b/ext/tk/sample/demos-jp/paned2.rb
index 1e82eddda4..cdc8253402 100644
--- a/ext/tk/sample/demos-jp/paned2.rb
+++ b/ext/tk/sample/demos-jp/paned2.rb
@@ -1,3 +1,5 @@
+# -*- coding: euc-jp -*-
+#
# paned2.rb --
#
# This demonstration script creates a toplevel window containing
@@ -16,7 +18,9 @@ $paned2_demo = TkToplevel.new {|w|
positionWindow(w)
}
-TkLabel.new($paned2_demo,
+base_frame = TkFrame.new($paned2_demo).pack(:fill=>:both, :expand=>true)
+
+TkLabel.new(base_frame,
:font=>$font, :wraplength=>'4i', :justify=>:left,
:text=><<EOL).pack(:side=>:top)
²¼¤Î¥¹¥¯¥í¡¼¥ë¥Ð¡¼ÉÕ¤­¤Î¥¦¥£¥¸¥§¥Ã¥È¤¬ÃÖ¤«¤ì¤¿Æó¤Ä¤Î¥¦¥£¥ó¥É¥¦¤Î´Ö¤Î»ÅÀÚ¤êÏȤϡ¢°ì¤Ä¤ÎÎΰè¤ò¤½¤ì¤¾¤ì¤Î¥¦¥£¥ó¥É¥¦¤Î¤¿¤á¤Ëʬ³ä¤¹¤ë¤¿¤á¤Î¤â¤Î¤Ç¤¹¡£º¸¥Ü¥¿¥ó¤Ç»ÅÀÚ¤ê¤òÁàºî¤¹¤ë¤È¡¢Ê¬³ä¥µ¥¤¥ºÊѹ¹¤ÎÁàºîÅÓÃæ¤Ç¤ÏºÆÉ½¼¨¤Ï¤Ê¤µ¤ì¤º¡¢³ÎÄꤵ¤»¤¿¤È¤­¤Ëɽ¼¨¤¬¹¹¿·¤µ¤ì¤Þ¤¹¡£¥Þ¥¦¥¹¤Ë¤è¤ë»ÅÀÚ¤ê¤ÎÁàºî¤ËÄɿ路¤Æ¥µ¥¤¥º¤òÊѹ¹¤·¤¿É½¼¨¤¬¤Ê¤ï¤ì¤ë¤è¤¦¤Ë¤·¤¿¤¤¾ì¹ç¤Ï¡¢¥Þ¥¦¥¹¤ÎÃæ±û¥Ü¥¿¥ó¤ò»È¤Ã¤Æ¤¯¤À¤µ¤¤¡£
@@ -27,7 +31,7 @@ TkLabel.new($paned2_demo,
EOL
# The bottom buttons
-TkFrame.new($paned2_demo){|f|
+TkFrame.new(base_frame){|f|
pack(:side=>:bottom, :fill=>:x, :pady=>'2m')
TkButton.new(f, :text=>'ÊĤ¸¤ë', :width=>15, :command=>proc{
@@ -64,7 +68,7 @@ paneList.value = [ # ruby's array --> tcl's list
]
# Create the pane itself
-TkPanedwindow.new($paned2_demo, :orient=>:vertical){|f|
+TkPanedwindow.new(base_frame, :orient=>:vertical){|f|
pack(:side=>:top, :expand=>true, :fill=>:both, :pady=>2, :padx=>'2m')
add(TkFrame.new(f){|paned2_top|
diff --git a/ext/tk/sample/demos-jp/pendulum.rb b/ext/tk/sample/demos-jp/pendulum.rb
index d703c74d5a..b115f5be2c 100644
--- a/ext/tk/sample/demos-jp/pendulum.rb
+++ b/ext/tk/sample/demos-jp/pendulum.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# This demonstration illustrates how Tcl/Tk can be used to construct
# simulations of physical systems.
@@ -18,8 +19,10 @@ $pendulum_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($pendulum_demo).pack(:fill=>:both, :expand=>true)
+
# create label
-msg = TkLabel.new($pendulum_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -28,7 +31,7 @@ msg = TkLabel.new($pendulum_demo) {
msg.pack('side'=>'top')
# create frame
-TkFrame.new($pendulum_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -50,9 +53,11 @@ TkFrame.new($pendulum_demo) {|frame|
class PendulumAnimationDemo
def initialize(frame)
# Create some structural widgets
- pane = TkPanedWindow.new(frame).pack(:fill=>:both, :expand=>true)
- pane.add(@lf1 = TkLabelFrame.new(pane, :text=>'Pendulum Simulation'))
- pane.add(@lf2 = TkLabelFrame.new(pane, :text=>'Phase Space'))
+ @pane = TkPanedWindow.new(frame, :orient=>:horizontal).pack(:fill=>:both, :expand=>true)
+# @pane.add(@lf1 = TkLabelFrame.new(@pane, :text=>'Pendulum Simulation'))
+# @pane.add(@lf2 = TkLabelFrame.new(@pane, :text=>'Phase Space'))
+ @lf1 = TkLabelFrame.new(@pane, :text=>'Pendulum Simulation')
+ @lf2 = TkLabelFrame.new(@pane, :text=>'Phase Space')
# Create the canvas containing the graphical representation of the
# simulated system.
@@ -100,23 +105,24 @@ class PendulumAnimationDemo
@dTheta = 0.0
@length = 150
- # init display
- showPendulum
-
# animation loop
@timer = TkTimer.new(15){ repeat }
# binding
@c.bindtags_unshift(btag = TkBindTag.new)
btag.bind('Destroy'){ @timer.stop }
- btag.bind('1', proc{|x, y| @timer.stop; showPendulum(x, y)}, '%x %y')
- btag.bind('B1-Motion', proc{|x, y| showPendulum(x, y)}, '%x %y')
+ btag.bind('1', proc{|x, y| @timer.stop; showPendulum(x.to_i, y.to_i)},
+ '%x %y')
+ btag.bind('B1-Motion', proc{|x, y| showPendulum(x.to_i, y.to_i)}, '%x %y')
btag.bind('ButtonRelease-1',
- proc{|x, y| showPendulum(x, y); @timer.start }, '%x %y')
+ proc{|x, y| showPendulum(x.to_i, y.to_i); @timer.start },
+ '%x %y')
- btag.bind('Configure', proc{|w| @plate.coords(0, 25, w, 25)}, '%w')
+ btag.bind('Configure', proc{|w| @plate.coords(0, 25, w.to_i, 25)}, '%w')
@k.bind('Configure', proc{|h, w|
+ h = h.to_i
+ w = w.to_i
@psh = h/2;
@psw = w/2
@x_axis.coords(2, @psh, w-2, @psh)
@@ -125,6 +131,14 @@ class PendulumAnimationDemo
@label_dtheta.coords(w-6, @psh+4)
}, '%h %w')
+ # add
+ Tk.update
+ @pane.add(@lf1)
+ @pane.add(@lf2)
+
+ # init display
+ showPendulum
+
# animation start
@timer.start(500)
end
@@ -155,6 +169,10 @@ class PendulumAnimationDemo
# rate at which the angle is changing (the first derivative with
# respect to time.)
def showPhase
+ unless @psw && @psh
+ @psw = @k.width/2
+ @psh = @k.height/2
+ end
@points << @theta + @psw << -20*@dTheta + @psh
if @points.length > 100
@points = @points[-100..-1]
@@ -221,4 +239,4 @@ class PendulumAnimationDemo
end
# Start the animation processing
-PendulumAnimationDemo.new($pendulum_demo)
+PendulumAnimationDemo.new(base_frame)
diff --git a/ext/tk/sample/demos-jp/plot.rb b/ext/tk/sample/demos-jp/plot.rb
index 902b144f72..9ff71904cd 100644
--- a/ext/tk/sample/demos-jp/plot.rb
+++ b/ext/tk/sample/demos-jp/plot.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# 2-D plot widget demo (called by 'widget')
#
@@ -15,14 +16,16 @@ $plot_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($plot_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-TkLabel.new($plot_demo, 'font'=>$font, 'wraplength'=>'4i', 'justify'=>'left',
+TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'4i', 'justify'=>'left',
'text'=>"¤³¤Î¥¦¥£¥ó¥É¥¦¤Ï´Êñ¤Ê2¼¡¸µ¤Î¥×¥í¥Ã¥È¤ò´Þ¤ó¤À¥­¥ã¥ó¥Ð¥¹ widget¤Ç¤¹¡£É½¼¨¤µ¤ì¤¿ÅÀ¤ò¥Þ¥¦¥¹¥Ü¥¿¥ó1¤Ç¥É¥é¥Ã¥°¤·¤Æ¥Ç¡¼¥¿¤ò¤¤¤¸¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£"){
pack('side'=>'top')
}
# frame À¸À®
-$plot_buttons = TkFrame.new($plot_demo) {|frame|
+$plot_buttons = TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -41,10 +44,14 @@ $plot_buttons = TkFrame.new($plot_demo) {|frame|
$plot_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# font ÀßÄê
-plotFont = '-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*'
+ if $tk_version =~ /^4.*/
+ plotFont = '-*-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*'
+ else
+ font = 'Helvetica 18'
+ end
# canvas ÀßÄê
-$plot_canvas = TkCanvas.new($plot_demo,'relief'=>'raised','width'=>450,'height'=>300)
+$plot_canvas = TkCanvas.new(base_frame,'relief'=>'raised','width'=>450,'height'=>300)
$plot_canvas.pack('side'=>'top', 'fill'=>'x')
# plot À¸À®
diff --git a/ext/tk/sample/demos-jp/puzzle.rb b/ext/tk/sample/demos-jp/puzzle.rb
index ad69775aab..2febc2c55a 100644
--- a/ext/tk/sample/demos-jp/puzzle.rb
+++ b/ext/tk/sample/demos-jp/puzzle.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# widet demo 'puzzle' (called by 'widget')
#
@@ -15,8 +16,10 @@ $puzzle_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($puzzle_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-msg = TkLabel.new($puzzle_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -25,7 +28,7 @@ msg = TkLabel.new($puzzle_demo) {
msg.pack('side'=>'top')
# frame À¸À®
-TkFrame.new($puzzle_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -50,18 +53,27 @@ TkFrame.new($puzzle_demo) {|frame|
#
begin
if Tk.windowingsystem() == 'aqua'
- frameSize = 160
+ frameWidth = 168
+ frameHeight = 168
+ elsif Tk.default_widget_set == :Ttk
+ frameWidth = 148
+ frameHeight = 124
else
- frameSize = 120
+ frameWidth = 120
+ frameHeight = 120
end
rescue
- frameSize = 120
+ frameWidth = 120
+ frameHeight = 120
end
+
+# depend_on_button_width = true
+depend_on_button_width = false
-s = TkScrollbar.new($puzzle_demo)
-base = TkFrame.new($puzzle_demo) {
- width frameSize
- height frameSize
+s = TkScrollbar.new(base_frame)
+base = TkFrame.new(base_frame) {
+ width frameWidth
+ height frameHeight
borderwidth 2
relief 'sunken'
bg s['troughcolor']
@@ -88,6 +100,9 @@ order = [3,1,6,2,5,7,15,13,4,11,8,9,14,10,12]
text num
highlightthickness 0
command def_puzzleswitch_proc(w, num)
+ if depend_on_button_width && (w.winfo_reqwidth * 4 > base.width)
+ base.width = w.winfo_reqwidth * 4
+ end
}.place('relx'=>$xpos[num], 'rely'=>$ypos[num],
'relwidth'=>0.25, 'relheight'=>0.25)
}
diff --git a/ext/tk/sample/demos-jp/radio.rb b/ext/tk/sample/demos-jp/radio.rb
index 5858b4222a..a61ad46d9b 100644
--- a/ext/tk/sample/demos-jp/radio.rb
+++ b/ext/tk/sample/demos-jp/radio.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# radiobutton widget demo (called by 'widget')
#
@@ -15,8 +16,10 @@ $radio_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($radio_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-msg = TkLabel.new($radio_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -29,7 +32,7 @@ size = TkVariable.new
color = TkVariable.new
# frame À¸À®
-TkFrame.new($radio_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -49,14 +52,14 @@ TkFrame.new($radio_demo) {|frame|
TkButton.new(frame) {
text 'ÊÑ¿ô»²¾È'
command proc{
- showVars($radio_demo, ['size', size], ['color', color])
+ showVars(base_frame, ['size', size], ['color', color])
}
}.pack('side'=>'left', 'expand'=>'yes')
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# frame À¸À®
-f_left = TkFrame.new($radio_demo)
-f_right = TkFrame.new($radio_demo)
+f_left = TkFrame.new(base_frame)
+f_right = TkFrame.new(base_frame)
f_left.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'.5c', 'pady'=>'.5c')
f_right.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'.5c', 'pady'=>'.5c')
diff --git a/ext/tk/sample/demos-jp/radio2.rb b/ext/tk/sample/demos-jp/radio2.rb
index 5ac877d99a..cf53e3e485 100644
--- a/ext/tk/sample/demos-jp/radio2.rb
+++ b/ext/tk/sample/demos-jp/radio2.rb
@@ -1,3 +1,5 @@
+# -*- coding: euc-jp -*-
+#
# radio2.rb
#
# This demonstration script creates a toplevel window containing
@@ -19,8 +21,10 @@ $radio2_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($radio2_demo).pack(:fill=>:both, :expand=>true)
+
# label
-msg = TkLabel.new($radio2_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '5i'
justify 'left'
@@ -34,7 +38,7 @@ color = TkVariable.new
align = TkVariable.new
# frame
-TkFrame.new($radio2_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -54,18 +58,18 @@ TkFrame.new($radio2_demo) {|frame|
TkButton.new(frame) {
text 'ÊÑ¿ô»²¾È'
command proc{
- showVars($radio2_demo,
+ showVars(base_frame,
['size', size], ['color', color], ['compound', align])
}
}.pack('side'=>'left', 'expand'=>'yes')
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# frame
-f_left = TkLabelFrame.new($radio2_demo, 'text'=>'ʸ»ú¥µ¥¤¥º',
+f_left = TkLabelFrame.new(base_frame, 'text'=>'ʸ»ú¥µ¥¤¥º',
'pady'=>2, 'padx'=>2)
-f_mid = TkLabelFrame.new($radio2_demo, 'text'=>'¿§',
+f_mid = TkLabelFrame.new(base_frame, 'text'=>'¿§',
'pady'=>2, 'padx'=>2)
-f_right = TkLabelFrame.new($radio2_demo, 'text'=>'¥Ó¥Ã¥È¥Þ¥Ã¥×ÇÛÃÖ',
+f_right = TkLabelFrame.new(base_frame, 'text'=>'¥Ó¥Ã¥È¥Þ¥Ã¥×ÇÛÃÖ',
'pady'=>2, 'padx'=>2)
f_left.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'.5c', 'pady'=>'.5c')
f_mid.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'.5c', 'pady'=>'.5c')
@@ -91,7 +95,8 @@ f_right.pack('side'=>'left', 'expand'=>'yes', 'padx'=>'.5c', 'pady'=>'.5c')
}.pack('side'=>'top', 'pady'=>2, 'fill'=>'x')
}
-label = TkLabel.new(f_right, 'text'=>'¥é¥Ù¥ë', 'bitmap'=>'questhead',
+# label = TkLabel.new(f_right, 'text'=>'¥é¥Ù¥ë', 'bitmap'=>'questhead',
+label = Tk::Label.new(f_right, 'text'=>'¥é¥Ù¥ë', 'bitmap'=>'questhead',
'compound'=>'left')
label.configure('width'=>TkWinfo.reqwidth(label), 'compound'=>'top')
label.height(TkWinfo.reqheight(label))
diff --git a/ext/tk/sample/demos-jp/radio3.rb b/ext/tk/sample/demos-jp/radio3.rb
index 6e9a0f750b..4bbc1b31f5 100644
--- a/ext/tk/sample/demos-jp/radio3.rb
+++ b/ext/tk/sample/demos-jp/radio3.rb
@@ -1,3 +1,5 @@
+# -*- coding: euc-jp -*-
+#
# radio3.rb
#
# This demonstration script creates a toplevel window containing
@@ -19,8 +21,10 @@ $radio3_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($radio3_demo).pack(:fill=>:both, :expand=>true)
+
# label
-msg = TkLabel.new($radio3_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '5i'
justify 'left'
@@ -34,14 +38,14 @@ color = TkVariable.new
align = TkVariable.new
# frame
-TkFrame.new($radio3_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkGrid(TkFrame.new(frame, :height=>2, :relief=>:sunken, :bd=>2),
:columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
TkGrid('x',
TkButton.new(frame, :text=>'ÊÑ¿ô»²¾È',
:image=>$image['view'], :compound=>:left,
:command=>proc{
- showVars($radio3_demo, ['size', size],
+ showVars(base_frame, ['size', size],
['color', color], ['compound', align])
}),
TkButton.new(frame, :text=>'¥³¡¼¥É»²¾È',
@@ -61,17 +65,17 @@ TkFrame.new($radio3_demo) {|frame|
}
# frame
-f_left = TkLabelFrame.new($radio3_demo, 'text'=>'ʸ»ú¥µ¥¤¥º',
+f_left = TkLabelFrame.new(base_frame, 'text'=>'ʸ»ú¥µ¥¤¥º',
'pady'=>2, 'padx'=>2)
-f_mid = TkLabelFrame.new($radio3_demo, 'text'=>'¿§',
+f_mid = TkLabelFrame.new(base_frame, 'text'=>'¿§',
'pady'=>2, 'padx'=>2)
-f_right = TkLabelFrame.new($radio3_demo, 'text'=>'¥Ó¥Ã¥È¥Þ¥Ã¥×ÇÛÃÖ',
+f_right = TkLabelFrame.new(base_frame, 'text'=>'¥Ó¥Ã¥È¥Þ¥Ã¥×ÇÛÃÖ',
'pady'=>2, 'padx'=>2)
f_left .grid('column'=>0, 'row'=>1, 'pady'=>'.5c', 'padx'=>'.5c', 'rowspan'=>2)
f_mid .grid('column'=>1, 'row'=>1, 'pady'=>'.5c', 'padx'=>'.5c', 'rowspan'=>2)
f_right.grid('column'=>2, 'row'=>1, 'pady'=>'.5c', 'padx'=>'.5c')
-TkButton.new($radio3_demo, 'text'=>'¥È¥é¥¤¥¹¥Æ¡¼¥È',
+TkButton.new(base_frame, 'text'=>'¥È¥é¥¤¥¹¥Æ¡¼¥È',
'command'=>proc{size.value = 'multi'; color.value = 'multi'}){
grid('column'=>2, 'row'=>2, 'pady'=>'.5c', 'padx'=>'.5c')
}
@@ -99,7 +103,8 @@ TkButton.new($radio3_demo, 'text'=>'¥È¥é¥¤¥¹¥Æ¡¼¥È',
}.pack('side'=>'top', 'pady'=>2, 'fill'=>'x')
}
-label = TkLabel.new(f_right, 'text'=>'¥é¥Ù¥ë', 'bitmap'=>'questhead',
+# label = TkLabel.new(f_right, 'text'=>'¥é¥Ù¥ë', 'bitmap'=>'questhead',
+label = Tk::Label.new(f_right, 'text'=>'¥é¥Ù¥ë', 'bitmap'=>'questhead',
'compound'=>'left')
label.configure('width'=>TkWinfo.reqwidth(label), 'compound'=>'top')
label.height(TkWinfo.reqheight(label))
diff --git a/ext/tk/sample/demos-jp/rolodex-j b/ext/tk/sample/demos-jp/rolodex-j
index dcc18cfa51..6c3ea7a484 100644
--- a/ext/tk/sample/demos-jp/rolodex-j
+++ b/ext/tk/sample/demos-jp/rolodex-j
@@ -1,4 +1,5 @@
#!/usr/bin/env ruby
+# -*- coding: euc-jp -*-
#
# rolodex --
# ¤³¤Î¥¹¥¯¥ê¥×¥È¤Ï Tom LaStrange ¤Î rolodex ¤Î°ìÉô¤Ç¤¹¡£
diff --git a/ext/tk/sample/demos-jp/ruler.rb b/ext/tk/sample/demos-jp/ruler.rb
index 94b4c921d3..d6bc9e76d1 100644
--- a/ext/tk/sample/demos-jp/ruler.rb
+++ b/ext/tk/sample/demos-jp/ruler.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# ruler widget demo (called by 'widget')
#
@@ -28,14 +29,16 @@ $ruler_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($ruler_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-TkLabel.new($ruler_demo, 'font'=>$font, 'wraplength'=>'5i', 'justify'=>'left',
+TkLabel.new(base_frame, 'font'=>$font, 'wraplength'=>'5i', 'justify'=>'left',
'text'=>"¤³¤Î¥­¥ã¥ó¥Ð¥¹widget¤Ï¥ë¡¼¥é¡¼¤ÎÌÏ·¿¤Ç¤¹¡£¥ë¡¼¥é¡¼¤Î±¦¤Ë¤¢¤ë¤Î¤Ï¥¿¥Ö¥¹¥È¥Ã¥×¤Î°æ¸Í¤Ç¡¢¤³¤³¤«¤é°ú¤ÃÄ¥¤Ã¤Æ¤¯¤ë¤³¤È¤Ë¤è¤Ã¤Æ¥¿¥Ö¥¹¥È¥Ã¥×¤òºî¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£¤Þ¤¿¡¢¤¹¤Ç¤Ë¤¢¤ë¥¿¥Ö¥¹¥È¥Ã¥×¤òư¤«¤¹¤³¤È¤â¤Ç¤­¤Þ¤¹¡£¥¿¥Ö¥¹¥È¥Ã¥×¤ò¾åÊý¤Þ¤¿¤Ï²¼Êý¤Ë¤«¤¹¤ì¤ÆÉ½¼¨¤µ¤ì¤ë¤Þ¤Ç¥É¥é¥Ã¥°¤¹¤ë¤È¡¢¥Þ¥¦¥¹¥Ü¥¿¥ó¤òÎ¥¤·¤¿»þ¤Ë¤½¤Î¥¿¥Ö¥¹¥È¥Ã¥×¤Ï¾Ã¤¨¤Þ¤¹¡£"){
pack('side'=>'top')
}
# frame À¸À®
-$ruler_buttons = TkFrame.new($ruler_demo) {|frame|
+$ruler_buttons = TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -54,7 +57,7 @@ $ruler_buttons = TkFrame.new($ruler_demo) {|frame|
$ruler_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# canvas ÀßÄê
-$ruler_canvas = TkCanvas.new($ruler_demo, 'width'=>'14.8c', 'height'=>'2.5c')
+$ruler_canvas = TkCanvas.new(base_frame, 'width'=>'14.8c', 'height'=>'2.5c')
$ruler_canvas.pack('side'=>'top', 'fill'=>'x')
# ÃÍÀßÄê
diff --git a/ext/tk/sample/demos-jp/sayings.rb b/ext/tk/sample/demos-jp/sayings.rb
index ce195a0e53..aa24b3a2ad 100644
--- a/ext/tk/sample/demos-jp/sayings.rb
+++ b/ext/tk/sample/demos-jp/sayings.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# listbox widget demo 'sayings' (called by 'widget')
#
@@ -15,8 +16,10 @@ $sayings_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($sayings_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-msg = TkLabel.new($sayings_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -25,7 +28,7 @@ msg = TkLabel.new($sayings_demo) {
msg.pack('side'=>'top')
# frame À¸À®
-TkFrame.new($sayings_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -45,7 +48,7 @@ TkFrame.new($sayings_demo) {|frame|
# frame À¸À®
sayings_lbox = nil
-TkFrame.new($sayings_demo, 'borderwidth'=>10) {|w|
+TkFrame.new(base_frame, 'borderwidth'=>10) {|w|
sv = TkScrollbar.new(w)
sh = TkScrollbar.new(w, 'orient'=>'horizontal')
sayings_lbox = TkListbox.new(w) {
diff --git a/ext/tk/sample/demos-jp/search.rb b/ext/tk/sample/demos-jp/search.rb
index f5268f987f..9838ff5d19 100644
--- a/ext/tk/sample/demos-jp/search.rb
+++ b/ext/tk/sample/demos-jp/search.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# Text Search widget demo (called by 'widget')
#
@@ -74,8 +75,10 @@ $search_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($search_demo).pack(:fill=>:both, :expand=>true)
+
# frame À¸À®
-$search_buttons = TkFrame.new($search_demo) {|frame|
+$search_buttons = TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -94,7 +97,7 @@ $search_buttons = TkFrame.new($search_demo) {|frame|
$search_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# frame À¸À®
-TkFrame.new($search_demo) {|f|
+TkFrame.new(base_frame) {|f|
TkLabel.new(f, 'text'=>'¥Õ¥¡¥¤¥ë̾:',
'width'=>13, 'anchor'=>'w').pack('side'=>'left')
$search_fileName = TkVariable.new
@@ -111,7 +114,7 @@ TkFrame.new($search_demo) {|f|
.pack('side'=>'left', 'pady'=>5, 'padx'=>10)
}.pack('side'=>'top', 'fill'=>'x')
-TkFrame.new($search_demo) {|f|
+TkFrame.new(base_frame) {|f|
TkLabel.new(f, 'text'=>'¸¡º÷ʸ»úÎó:',
'width'=>13, 'anchor'=>'w').pack('side'=>'left')
$search_searchString = TkVariable.new
@@ -129,9 +132,9 @@ TkFrame.new($search_demo) {|f|
}
}.pack('side'=>'top', 'fill'=>'x')
-$search_text = TkText.new($search_demo, 'setgrid'=>true) {|t|
+$search_text = TkText.new(base_frame, 'setgrid'=>true) {|t|
$search_Tag = TkTextTag.new(t)
- TkScrollbar.new($search_demo, 'command'=>proc{|*args| t.yview(*args)}) {|sc|
+ TkScrollbar.new(base_frame, 'command'=>proc{|*args| t.yview(*args)}) {|sc|
t.yscrollcommand(proc{|first,last| sc.set first,last})
pack('side'=>'right', 'fill'=>'y')
}
@@ -168,9 +171,14 @@ $search_text.insert('1.0', "\
¥¨¥ó¥È¥ê¤Ëʸ»úÎó¤òÆþÎϤ·¡¢<¥ê¥¿¡¼¥ó> ¤ò²¡¤¹¤«¡Öȿž¡×¥Ü¥¿¥ó¤ò²¡¤·¤Æ¤¯ \
¤À¤µ¤¤¡£¤¹¤ë¤È¥Õ¥¡¥¤¥ëÃæ¤Î¡¢¸¡º÷ʸ»úÎó¤È°ìÃפ¹¤ëÉôʬ¤ËÁ´¤Æ \"search_Tag\" \
¤È¤¤¤¦¥¿¥°¤¬¤Ä¤±¤é¤ì¡¢¥¿¥°¤Îɽ¼¨Â°À­¤È¤·¤Æ¤½¤Îʸ»úÎó¤¬ÅÀÌǤ¹¤ë¤è¤¦¤Ë \
-ÀßÄꤵ¤ì¤Þ¤¹¡£")
+ÀßÄꤵ¤ì¤Þ¤¹¡£\n")
+$search_text.insert('end', "\
+¥Õ¥¡¥¤¥ëÆÉ¤ß¹þ¤ß¤Î¥«¥ì¥ó¥È¥Ç¥£¥ì¥¯¥È¥ê¤Ï \"#{Dir.pwd}\" ¤Ç¤¹¡£\
+")
$search_text.set_insert '0.0'
$search_fileName.value = ''
$search_searchString.value = ''
+$search_text.width = 60
+$search_text.height = 20
diff --git a/ext/tk/sample/demos-jp/spin.rb b/ext/tk/sample/demos-jp/spin.rb
index c7b8096723..8d4e33cda0 100644
--- a/ext/tk/sample/demos-jp/spin.rb
+++ b/ext/tk/sample/demos-jp/spin.rb
@@ -1,3 +1,5 @@
+# -*- coding: euc-jp -*-
+#
# spin.rb --
#
# This demonstration script creates several spinbox widgets.
@@ -15,10 +17,12 @@ $spin_demo = TkToplevel.new {|w|
positionWindow(w)
}
-TkLabel.new($spin_demo,
+base_frame = TkFrame.new($spin_demo).pack(:fill=>:both, :expand=>true)
+
+TkLabel.new(base_frame,
:font=>$font, :wraplength=>'5i', :justify=>:left,
:text=><<EOL).pack(:side=>:top)
-²¼¤Ë¤Ï£³¼ïÎà¤Î¥¹¥Ô¥ó¥Ü¥Ã¥¯¥¹¤¬É½¼¨¤µ¤ì¤Æ¤¤¤Þ¤¹¡£\
+²¼¤Ë¤Ï£³¼ïÎà¤Î¥¹¥Ô¥ó¥Ü¥Ã¥¯¥¹¤¬É½¼¨¤µ¤ì¤Æ¤¤¤Þ¤¹¡£
¤½¤ì¤¾¤ì¡¢¥Þ¥¦¥¹¤ÇÁªÂò¤·¤ÆÊ¸»ú¤òÆþÎϤ¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£
ÊÔ½¸Áàºî¤È¤·¤Æ¤Ï¡¢Emacs ·Á¼°¤Î¿¤¯¤Ë²Ã¤¨¤Æ¡¢°ìÈÌŪ¤Ê
Motif ·Á¼°¤Î¥­¡¼Áàºî¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Þ¤¹¡£¤¿¤È¤¨¤Ð¡¢
@@ -38,7 +42,7 @@ Backspace ¤È Control-h ¤È¤ÏÆþÎÏ¥«¡¼¥½¥ë¤Îº¸Â¦¤Îʸ»ú¤ò
¤òÁȤ߹ç¤ï¤»¤Æ»î¤¹¤è¤¦¤Ë¤·¤Æ¤¯¤À¤µ¤¤¡£
EOL
-TkFrame.new($spin_demo){|f|
+TkFrame.new(base_frame){|f|
pack(:side=>:bottom, :fill=>:x, :pady=>'2m')
TkButton.new(f, :text=>'ÊĤ¸¤ë', :width=>15, :command=>proc{
@@ -57,11 +61,11 @@ australianCities = [
]
[
- TkSpinbox.new($spin_demo, :from=>1, :to=>10, :width=>10, :validate=>:key,
+ TkSpinbox.new(base_frame, :from=>1, :to=>10, :width=>10, :validate=>:key,
:validatecommand=>[
proc{|s| s == '' || /^[+-]?\d+$/ =~ s }, '%P'
]),
- TkSpinbox.new($spin_demo, :from=>0, :to=>3, :increment=>0.5,
+ TkSpinbox.new(base_frame, :from=>0, :to=>3, :increment=>0.5,
:format=>'%05.2f', :width=>10),
- TkSpinbox.new($spin_demo, :values=>australianCities, :width=>10)
+ TkSpinbox.new(base_frame, :values=>australianCities, :width=>10)
].each{|sbox| sbox.pack(:side=>:top, :pady=>5, :padx=>10)}
diff --git a/ext/tk/sample/demos-jp/states.rb b/ext/tk/sample/demos-jp/states.rb
index dfae821261..5e242b7c38 100644
--- a/ext/tk/sample/demos-jp/states.rb
+++ b/ext/tk/sample/demos-jp/states.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# listbox widget demo 'states' (called by 'widget')
#
@@ -15,8 +16,10 @@ $states_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($states_demo).pack(:fill=>:both, :expand=>true)
+
# label À¸À®
-msg = TkLabel.new($states_demo) {
+msg = TkLabel.new(base_frame) {
font $font
wraplength '4i'
justify 'left'
@@ -25,7 +28,7 @@ msg = TkLabel.new($states_demo) {
msg.pack('side'=>'top')
# frame À¸À®
-TkFrame.new($states_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -45,7 +48,7 @@ TkFrame.new($states_demo) {|frame|
# frame À¸À®
states_lbox = nil
-TkFrame.new($states_demo, 'borderwidth'=>'.5c') {|w|
+TkFrame.new(base_frame, 'borderwidth'=>'.5c') {|w|
s = TkScrollbar.new(w)
states_lbox = TkListbox.new(w) {
setgrid 1
diff --git a/ext/tk/sample/demos-jp/style.rb b/ext/tk/sample/demos-jp/style.rb
index 59e406bc80..66b6de0251 100644
--- a/ext/tk/sample/demos-jp/style.rb
+++ b/ext/tk/sample/demos-jp/style.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# text (display styles) widget demo (called by 'widget')
#
@@ -8,6 +9,7 @@ if defined?($style_demo) && $style_demo
$style_demo = nil
end
+
# demo ÍѤΠtoplevel widget ¤òÀ¸À®
$style_demo = TkToplevel.new {|w|
title("Text Demonstration - Display Styles")
@@ -15,8 +17,10 @@ $style_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($style_demo).pack(:fill=>:both, :expand=>true)
+
# frame À¸À®
-TkFrame.new($style_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -33,14 +37,16 @@ TkFrame.new($style_demo) {|frame|
}.pack('side'=>'left', 'expand'=>'yes')
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
+
# text À¸À®
-TkText.new($style_demo){|t|
+txt = TkText.new(base_frame){|t|
# À¸À®
setgrid 'true'
- width 70
- height 32
+ #width 70
+ #height 32
wrap 'word'
- TkScrollbar.new($style_demo) {|s|
+ font $font
+ TkScrollbar.new(base_frame) {|s|
pack('side'=>'right', 'fill'=>'y')
command proc{|*args| t.yview(*args)}
t.yscrollcommand proc{|first,last| s.set first,last}
@@ -48,11 +54,20 @@ TkText.new($style_demo){|t|
pack('expand'=>'yes', 'fill'=>'both')
# ¥Æ¥­¥¹¥È¥¿¥°ÀßÄê (¥Õ¥©¥ó¥È´ØÏ¢)
- style_tag_bold = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-O-Normal--*-120-*-*-*-*-*-*')
- style_tag_big = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-R-Normal--*-140-*-*-*-*-*-*', 'kanjifont'=>$msg_kanji_font)
+ family = 'Courier'
+
+ if $tk_version =~ /^4.*/
+ style_tag_bold = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-O-Normal--*-120-*-*-*-*-*-*')
+ style_tag_big = TkTextTag.new(t, 'font'=>'-*-Courier-Bold-R-Normal--*-140-*-*-*-*-*-*', 'kanjifont'=>$msg_kanji_font)
style_tag_verybig = TkTextTag.new(t, 'font'=>'-*-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*')
-# style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*', 'kanjifont'=>$kanji_font)
+ # style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*', 'kanjifont'=>$kanji_font)
style_tag_small = TkTextTag.new(t, 'font'=>'-Adobe-Helvetica-Bold-R-Normal-*-100-*')
+ else
+ style_tag_bold = TkTextTag.new(t, 'font'=>[family, 12, :bold, :italic])
+ style_tag_big = TkTextTag.new(t, 'font'=>[family, 14, :bold])
+ style_tag_verybig = TkTextTag.new(t, 'font'=>['Helvetica', 24, :bold])
+ style_tag_small = TkTextTag.new(t, 'font'=>'Times 8 bold')
+ end
###
# case($tk_version)
# when /^4.*/
@@ -106,8 +121,13 @@ TkText.new($style_demo){|t|
style_tag_overstrike = TkTextTag.new(t, 'overstrike'=>'on')
style_tag_right = TkTextTag.new(t, 'justify'=>'right')
style_tag_center = TkTextTag.new(t, 'justify'=>'center')
- style_tag_super = TkTextTag.new(t, 'offset'=>'4p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*')
- style_tag_sub = TkTextTag.new(t, 'offset'=>'-2p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*')
+ if $tk_version =~ /^4.*/
+ style_tag_super = TkTextTag.new(t, 'offset'=>'4p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*')
+ style_tag_sub = TkTextTag.new(t, 'offset'=>'-2p', 'font'=>'-Adobe-Courier-Medium-R-Normal--*-100-*-*-*-*-*-*')
+ else
+ style_tag_super = TkTextTag.new(t, 'offset'=>'4p', 'font'=>[family, 10])
+ style_tag_sub = TkTextTag.new(t, 'offset'=>'-2p', 'font'=>[family, 10])
+ end
style_tag_margins = TkTextTag.new(t, 'lmargin1'=>'12m', 'lmargin2'=>'6m',
'rmargin'=>'10m')
style_tag_spacing = TkTextTag.new(t, 'spacing1'=>'10p', 'spacing2'=>'2p',
@@ -246,3 +266,5 @@ spacing3')
}
+txt.width 70
+txt.height 32
diff --git a/ext/tk/sample/demos-jp/tcolor b/ext/tk/sample/demos-jp/tcolor
index c7f7ec7289..17f7e1347e 100644
--- a/ext/tk/sample/demos-jp/tcolor
+++ b/ext/tk/sample/demos-jp/tcolor
@@ -1,4 +1,5 @@
#!/usr/bin/env ruby
+# -*- coding: euc-jp -*-
#
# tcolor --
# ¤³¤Î¥¹¥¯¥ê¥×¥È¤ÏRGB,HSB,CYM·Á¼°¤ò¥µ¥Ý¡¼¥È¤¹¤ë
diff --git a/ext/tk/sample/demos-jp/text.rb b/ext/tk/sample/demos-jp/text.rb
index 0057d5dbdc..0ae480eb00 100644
--- a/ext/tk/sample/demos-jp/text.rb
+++ b/ext/tk/sample/demos-jp/text.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# text (basic facilities) widget demo (called by 'widget')
#
@@ -15,6 +16,8 @@ $text_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($text_demo).pack(:fill=>:both, :expand=>true)
+
# version check
if ((Tk::TK_VERSION.split('.').collect{|n| n.to_i} <=> [8,4]) < 0)
undo_support = false
@@ -23,7 +26,7 @@ else
end
# frame À¸À®
-TkFrame.new($text_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -41,13 +44,13 @@ TkFrame.new($text_demo) {|frame|
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# text À¸À®
-TkText.new($text_demo){|t|
+TkText.new(base_frame){|t|
# À¸À®
relief 'sunken'
bd 2
setgrid 1
height 30
- TkScrollbar.new($text_demo) {|s|
+ TkScrollbar.new(base_frame) {|s|
pack('side'=>'right', 'fill'=>'y')
command proc{|*args| t.yview(*args)}
t.yscrollcommand proc{|first,last| s.set first,last}
diff --git a/ext/tk/sample/demos-jp/textpeer.rb b/ext/tk/sample/demos-jp/textpeer.rb
new file mode 100644
index 0000000000..4967a99c92
--- /dev/null
+++ b/ext/tk/sample/demos-jp/textpeer.rb
@@ -0,0 +1,82 @@
+# -*- coding: euc-jp -*-
+#
+# text widget peering demo (called by 'widget')
+#
+# based on Tcl/Tk8.5.0 widget demos
+
+if defined?($textpeer_demo) && $textpeer_demo
+ $textpeer_demo.destroy
+ $textpeer_demo = nil
+end
+
+# demo toplevel widget
+$textpeer_demo = TkToplevel.new {|w|
+ title("Text Wdget Peering Demonstration")
+ iconname("textpeer")
+ positionWindow(w)
+}
+
+base_frame = TkFrame.new($textpeer_demo).pack(:fill=>:both, :expand=>true)
+
+count = [0]
+
+## Define a widget that we peer from; it won't ever actually be shown though
+first = TkText.new(base_frame, :widgetname=>"text#{count[0] += 1}")
+first.insert :end,"¤³¤Î¥Ç¥â¤Ï°ì¤Ä¤ÎÁȤòÀ®¤·¤¿¥Æ¥­¥¹¥È¥¦¥£¥¸¥§¥Ã¥È¤ò¼¨¤·¤Þ¤¹¡£"
+first.insert :end,"¤½¤ì¤é¤Î¥Æ¥­¥¹¥È¥¦¥£¥¸¥§¥Ã¥È¤ÏÂÐÅù(¥Ô¥¢;peer)¤Î´Ø·¸¤Ë"
+first.insert :end,"¤Ê¤Ã¤Æ¤¤¤Þ¤¹¡£"
+first.insert :end,"¤½¤ì¤é¤Ï¡¢´ðÈפȤʤë¥Ç¡¼¥¿¥â¥Ç¥ë¤Ï¶¦Ä̤Τâ¤Î¤ò»ý¤Á¤Þ¤¹¤¬¡¢"
+first.insert :end,"²èÌÌɽ¼¨°ÌÃÖ¡¢ÊÔ½¸°ÌÃÖ¡¢ÁªÂòÈϰÏ(selection)¤Ë¤Ä¤¤¤Æ¤Ï"
+first.insert :end,"ÆÈΩ¤Ë»ý¤Ä¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£"
+first.insert :end,"³Æ¥Æ¥­¥¹¥È¥¦¥£¥¸¥§¥Ã¥È¤ÎÏÆ¤Ë¤¢¤ë"
+first.insert :end,"¡Ö¥Ô¥¢(peer)¤ÎºîÀ®¡×¥Ü¥¿¥ó¤ò»È¤¨¤Ð¡¢"
+first.insert :end,"¿·¤¿¤Ê¥Ô¥¢¤òÄɲ乤뤳¤È¤¬²Äǽ¤Ç¤¹¡£"
+first.insert :end,"¤Þ¤¿¡Ö¥Ô¥¢(peer)¤Î¾Ãµî¡×¥Ü¥¿¥ó¤ò»È¤¨¤Ð¡¢"
+first.insert :end,"ÆÃÄê¤Î¥Ô¥¢¥¦¥£¥¸¥§¥Ã¥È¤ò¾Ãµî¤¹¤ë¤³¤È¤â¤Ç¤­¤Þ¤¹¡£"
+
+Tk.update_idletasks ## for 'first' widget
+
+## Procedures to make and kill clones; most of this is just so that the demo
+## looks nice...
+def makeClone(count, win, txt)
+ cnt = (count[0] += 1)
+ peer = TkText::Peer.new(txt, win, :widgetname=>"text#{cnt}")
+ sbar = TkScrollbar.new(win, :widgetname=>"sb#{cnt}")
+ peer.yscrollbar sbar
+ b1 = TkButton.new(win, :widgetname=>"clone#{cnt}",
+ :text=>'¥Ô¥¢(peer)¤ÎºîÀ®',
+ :command=>proc{makeClone(count, win, peer)})
+ b2 = TkButton.new(win, :widgetname=>"kill#{cnt}",
+ :text=>'¥Ô¥¢(peer)¤Î¾Ãµî',
+ :command=>proc{killClone(win, cnt)})
+ row = cnt * 2
+ TkGrid.configure(peer, sbar, b1, :sticky=>'nsew', :row=>row)
+ TkGrid.configure('^', '^', b2, :sticky=>'nsew', :row=>(row+=1))
+ TkGrid.configure(b1, b2, :sticky=>'new')
+ TkGrid.rowconfigure(win, b2, :weight=>1)
+end
+
+def killClone(win, cnt)
+ Tk.destroy("#{win.path}.text#{cnt}", "#{win.path}.sb#{cnt}",
+ "#{win.path}.clone#{cnt}", "#{win.path}.kill#{cnt}")
+end
+
+## Now set up the GUI
+makeClone(count, base_frame, first)
+makeClone(count, base_frame, first)
+first.destroy
+
+## See Code / Dismiss buttons
+TkFrame.new(base_frame){|f|
+ TkButton.new(f, :text=>'ÊĤ¸¤ë', :width=>15, :command=>proc{
+ $textpeer_demo.destroy
+ $textpeer_demo = nil
+ }).pack(:side=>:left, :expand=>true)
+
+ TkButton.new(f, :text=>'¥³¡¼¥É»²¾È', :width=>15, :command=>proc{
+ showCode 'textpeer'
+ }).pack(:side=>:left, :expand=>true)
+
+ TkGrid.configure(f, '-', '-', :sticky=>'ew', :row=>5000)
+}
+TkGrid.columnconfigure(base_frame, 0, :weight=>1)
diff --git a/ext/tk/sample/demos-jp/toolbar.rb b/ext/tk/sample/demos-jp/toolbar.rb
new file mode 100644
index 0000000000..9cb3834c34
--- /dev/null
+++ b/ext/tk/sample/demos-jp/toolbar.rb
@@ -0,0 +1,136 @@
+# -*- coding: euc-jp -*-
+#
+# toolbar.rb --
+#
+# This demonstration script creates a toolbar that can be torn off.
+#
+# based on "Id: toolbar.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp"
+
+if defined?($toolbar_demo) && $toolbar_demo
+ $toolbar_demo.destroy
+ $toolbar_demo = nil
+end
+
+$toolbar_demo = TkToplevel.new {|w|
+ title("Ttk Menu Buttons")
+ iconname("toolbar")
+ positionWindow(w)
+}
+
+base_frame = Ttk::Frame.new($toolbar_demo).pack(:fill=>:both, :expand=>true)
+
+if Tk.windowingsystem != 'aqua'
+ msg = Ttk::Label.new(base_frame, :wraplength=>'4i', :text=><<EOL)
+¤³¤Î¥Ç¥â¤Ç¤Ï¡¤¥Ä¡¼¥ë¥Ð¡¼¤ò¤É¤Î¤è¤¦¤Ë¤·¤ÆÅ¬Àڤ˥ơ¼¥ÞÂбþ¤µ¤»¤ë¤«¡¤\
+¤Þ¤¿¡¤¤É¤Î¤è¤¦¤Ë¤·¤ÆÀÚ¤êÎ¥¤·²Äǽ¤Ë¤¹¤ë¤«¤ò¼¨¤·¤Æ¤¤¤Þ¤¹\
+¡Ê¤¿¤À¤·¡¤¥Ä¡¼¥ë¥Ð¡¼¤ÎÀÚ¤êÎ¥¤·¤Ë¤ÏTcl/Tk8.5°Ê¾å¤Îµ¡Ç½¤¬É¬ÍפǤ¹¡Ë¡¥\
+¥Ä¡¼¥ë¥Ð¡¼¤Î¥Ü¥¿¥ó¤Ï¡¤'Toolbutton'¥¹¥¿¥¤¥ë¤ò»ÈÍѤ¹¤ë¤è¤¦¤ËÌÀ¼¨¤¹¤ë¤³¤È¤Ç¡¤\
+"toolbar style"¥Ü¥¿¥ó¤È¤Ê¤ë¤è¤¦¤Ë°À­ÀßÄꤵ¤ì¤Æ¤¤¤Þ¤¹¡¥\
+¥Ä¡¼¥ë¥Ð¡¼¤Îº¸Ã¼¤Ë¤Ï´Êñ¤Ê¥Þ¡¼¥«¡¼¤¬ÃÖ¤«¤ì¤Æ¤¤¤Þ¤¹¡¥\
+¥Þ¡¼¥«¡¼¾å¤Ë¥Þ¥¦¥¹¥«¡¼¥½¥ë¤¬Íè¤ë¤È°Üư¥¢¥¤¥³¥ó¤Ë¥«¡¼¥½¥ë¤¬ÊѲ½¤·¤Þ¤¹¡¥\
+¤½¤³¤Ç¥Ä¡¼¥ë¥Ð¡¼¤òư¤«¤¹¤è¤¦¤Ë¥É¥é¥Ã¥°¤¹¤ë¤È¡¤\
+¥Ä¡¼¥ë¥Ð¡¼Á´ÂΤòÀÚ¤êÎ¥¤·¤ÆÆÈΩ¤·¤¿¥È¥Ã¥×¥ì¥Ù¥ë¥¦¥£¥¸¥§¥Ã¥È¤Ë\
+¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡¥\
+ÀÚ¤êÎ¥¤·¤¿¥Ä¡¼¥ë¥Ð¡¼¤¬ÉÔÍפȤʤä¿»þ¤Ë¤Ï¡¤\
+°ìÈÌŪ¤Ê¥È¥Ã¥×¥ì¥Ù¥ë¥¦¥£¥¸¥§¥Ã¥È¤ÈƱÍͤËñ½ã¤ËÊĤ¸¤ë¤³¤È¤Ç¡¤
+ºÆ¤Ó¸µ¤Î¥¦¥£¥ó¥É¥¦¤ËÄ¥¤êÉÕ¤±¤é¤ì¤ë¤Ç¤·¤ç¤¦¡¥
+EOL
+else
+ msg = Ttk::Label.new(base_frame, :wraplength=>'4i', :text=><<EOL)
+¤³¤Î¥Ç¥â¤Ç¤Ï¡¤¥Ä¡¼¥ë¥Ð¡¼¤ò¤É¤Î¤è¤¦¤Ë¤·¤ÆÅ¬Àڤ˥ơ¼¥ÞÂбþ¤µ¤»¤ë¤«¤ò\
+¼¨¤·¤Æ¤¤¤Þ¤¹¡¥\
+¥Ä¡¼¥ë¥Ð¡¼¤Î¥Ü¥¿¥ó¤Ï¡¤'Toolbutton'¥¹¥¿¥¤¥ë¤ò»ÈÍѤ¹¤ë¤è¤¦¤ËÌÀ¼¨¤¹¤ë¤³¤È¤Ç¡¤\
+"toolbar style"¥Ü¥¿¥ó¤È¤Ê¤ë¤è¤¦¤Ë°À­ÀßÄꤵ¤ì¤Æ¤¤¤Þ¤¹¡¥
+EOL
+end
+
+## Set up the toolbar hull
+tbar_base = Tk::Frame.new(base_frame, # Tk ɸ½à¤Î frame ¤Ç¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó¡¥
+ :widgetname=>'toolbar') # ¥¦¥£¥ó¥É¥¦¥¿¥¤¥È¥ëʸ»úÎó¤È¤¹¤ë¤¿¤á¤Ë¡¤¥¦¥£¥¸¥§¥Ã¥È̾¤òÌÀ¼¨¤·¤Æ¤¤¤Þ¤¹¡¥
+sep = Ttk::Separator.new(base_frame)
+to_base = Ttk::Frame.new(tbar_base, :cursor=>'fleur')
+if Tk.windowingsystem != 'aqua'
+ to = Ttk::Separator.new(to_base, :orient=>:vertical)
+ to2 = Ttk::Separator.new(to_base, :orient=>:vertical)
+ to.pack(:fill=>:y, :expand=>true, :padx=>2, :side=>:left)
+ to2.pack(:fill=>:y, :expand=>true, :side=>:left)
+end
+
+contents = Ttk::Frame.new(tbar_base)
+Tk.grid(to_base, contents, :sticky=>'nsew')
+tbar_base.grid_columnconfigure(contents, :weight=>1)
+contents.grid_columnconfigure(1000, :weight=>1)
+
+if Tk.windowingsystem != 'aqua'
+ ## Bindings so that the toolbar can be torn off and reattached
+ to_base.bind('B1-Motion', '%X %Y'){|x, y| tbar_base.tearoff(to_base, x, y)}
+ to. bind('B1-Motion', '%X %Y'){|x, y| tbar_base.tearoff(to_base, x, y)}
+ to2. bind('B1-Motion', '%X %Y'){|x, y| tbar_base.tearoff(to_base, x, y)}
+ def tbar_base.tearoff(w, x, y)
+ on_win = TkWinfo.containing(x, y)
+ return unless (on_win && on_win.path =~ /^#{@path}(\.|$)/)
+ self.grid_remove
+ w.grid_remove
+ self.wm_manage
+ # self.wm_title('Toolbar') # ¤â¤·¥¦¥£¥¸¥§¥Ã¥È̾¤ò¥¦¥£¥ó¥É¥¦¥¿¥¤¥È¥ë¤Ë¤·¤¿¤¯¤Ê¤¤¤Ê¤é¡¤¤³¤³¤ÇÀßÄꤷ¤Æ¤¯¤À¤µ¤¤
+ self.wm_protocol('WM_DELETE_WINDOW'){ self.untearoff(self) }
+ end
+ def tbar_base.untearoff(w)
+ self.wm_forget
+ w.grid
+ self.grid
+ end
+end
+
+## Some content for the rest of the toplevel
+text = TkText.new(base_frame, :width=>40, :height=>10)
+
+## Toolbar contents
+tb_btn = Ttk::Button.new(tbar_base, :text=>'¥Ü¥¿¥ó', :style=>'Toolbutton',
+ :command=>proc{
+ text.insert(:end, "¥Ü¥¿¥ó¤¬²¡¤µ¤ì¤Þ¤·¤¿¡¥\n")
+ })
+tb_chk = Ttk::Checkbutton.new(tbar_base, :text=>'¥Á¥§¥Ã¥¯¥Ü¥¿¥ó',
+ :style=>'Toolbutton',
+ :variable=>(check = TkVariable.new),
+ :command=>proc{
+ text.insert(:end, "¥Á¥§¥Ã¥¯¥Ü¥¿¥ó¤ÎÃͤÏ#{check.value}¤Ç¤¹¡¥\n")
+ })
+tb_mbtn = Ttk::Menubutton.new(tbar_base, :text=>'¥á¥Ë¥å¡¼')
+tb_combo = Ttk::Combobox.new(tbar_base, :value=>TkFont.families,
+ :state=>:readonly)
+tb_mbtn.menu(menu = Tk::Menu.new(tb_mbtn))
+menu.add(:command, :label=>'Just', :command=>proc{text.insert(:end, "Just\n")})
+menu.add(:command, :label=>'An', :command=>proc{text.insert(:end, "An\n")})
+menu.add(:command, :label=>'Example',
+ :command=>proc{text.insert(:end, "Example\n")})
+tb_combo.bind('<ComboboxSelected>'){ text.font.family = tb_combo.get }
+
+## Arrange contents
+Tk.grid(tb_btn, tb_chk, tb_mbtn, tb_combo,
+ :in=>contents, :padx=>2, :sticky=>'ns')
+Tk.grid(tbar_base, :sticky=>'ew')
+Tk.grid(sep, :sticky=>'ew')
+Tk.grid(msg, :sticky=>'ew')
+Tk.grid(text, :sticky=>'nsew')
+base_frame.grid_rowconfigure(text, :weight=>1)
+base_frame.grid_columnconfigure(text, :weight=>1)
+
+## See Code / Dismiss buttons
+Ttk::Frame.new(base_frame) {|frame|
+ sep = Ttk::Separator.new(frame)
+ Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
+ TkGrid('x',
+ Ttk::Button.new(frame, :text=>'¥³¡¼¥É»²¾È',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{showCode 'toolbar'}),
+ Ttk::Button.new(frame, :text=>'ÊĤ¸¤ë',
+ :image=>$image['delete'], :compound=>:left,
+ :command=>proc{
+ $toolbar_demo.destroy
+ $toolbar_demo = nil
+ }),
+ :padx=>4, :pady=>4)
+ grid_columnconfigure(0, :weight=>1)
+ Tk.grid(frame, :sticky=>'ew')
+}
diff --git a/ext/tk/sample/demos-jp/tree.rb b/ext/tk/sample/demos-jp/tree.rb
new file mode 100644
index 0000000000..c3b4191144
--- /dev/null
+++ b/ext/tk/sample/demos-jp/tree.rb
@@ -0,0 +1,120 @@
+# -*- coding: euc-jp -*-
+#
+# tree.rb --
+#
+# This demonstration script creates a toplevel window containing a Ttk
+# tree widget.
+#
+# based on "Id: tree.tcl,v 1.4 2007/12/13 15:27:07 dgp Exp"
+
+if defined?($tree_demo) && $tree_demo
+ $tree_demo.destroy
+ $tree_demo = nil
+end
+
+$tree_demo = TkToplevel.new {|w|
+ title("Directory Browser")
+ iconname("tree")
+ positionWindow(w)
+}
+
+base_frame = TkFrame.new($tree_demo).pack(:fill=>:both, :expand=>true)
+
+## Explanatory text
+Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i',
+ :justify=>:left, :anchor=>'n', :padding=>[10, 2, 10, 6],
+ :text=><<EOL).pack(:fill=>:x)
+Ttk¤È¤Ï¡¤¥Æ¡¼¥Þ»ØÄê²Äǽ¤Ê¿·¤·¤¤¥¦¥£¥¸¥§¥Ã¥È½¸¹ç¤Ç¤¹¡¥\
+¤³¤Î¥µ¥ó¥×¥ë¤Ï¡¤¥Õ¥¡¥¤¥ë¥·¥¹¥Æ¥à¤Î¤è¤¦¤Ê³¬ÁØÅª¤Ê¥Ç¡¼¥¿½¸¹ç¤ò\
+»²¾È¤Ç¤­¤ë¤è¤¦¤Ë¤·¤¿Ttk::Treeview¥¦¥£¥¸¥§¥Ã¥È¤ò´Þ¤ó¤Ç¤¤¤Þ¤¹¡¥\
+Ttk::Treeview¥¦¥£¥¸¥§¥Ã¥È¤Ï¡¤ÌÚ¹½Â¤¼«ÂΤÎɽ¼¨¤ò²Äǽ¤Ë¤¹¤ë¤À¤±¤Ç¤Ê¤¯¡¤\
+ÄɲþðÊó(¤³¤Î¥µ¥ó¥×¥ë¤Î¾ì¹ç¤Ï¥Õ¥¡¥¤¥ë¥µ¥¤¥º)¤òɽ¼¨¤¹¤ë¤¿¤á¤Ë\
+Ǥ°Õ¤Î¸Ä¿ô¤ÎÄɲå«¥é¥à¤â°·¤¦¤³¤È¤â¤Ç¤­¤Þ¤¹¡¥\
+¤Þ¤¿¡¤¥«¥é¥à¤Î¥¿¥¤¥È¥ë´Ö¤Î¶èÀÚ¤êÉôʬ¤ò¥É¥é¥Ã¥°¤¹¤ë¤³¤È¤Ç¡¤\
+¥«¥é¥à¤ÎÉý¤òÊѹ¹¤¹¤ë¤³¤È¤â²Äǽ¤Ç¤¹¡¥
+EOL
+
+## See Code / Dismiss
+Ttk::Frame.new(base_frame) {|frame|
+ sep = Ttk::Separator.new(frame)
+ Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
+ TkGrid('x',
+ Ttk::Button.new(frame, :text=>'¥³¡¼¥É»²¾È',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{showCode 'tree'}),
+ Ttk::Button.new(frame, :text=>'ÊĤ¸¤ë',
+ :image=>$image['delete'], :compound=>:left,
+ :command=>proc{
+ $tree_demo.destroy
+ $tree_demo = nil
+ }),
+ :padx=>4, :pady=>4)
+ grid_columnconfigure(0, :weight=>1)
+ pack(:side=>:bottom, :fill=>:x)
+}
+
+## Code to populate the roots of the tree (can be more than one on Windows)
+def populate_roots(tree)
+ TkComm.simplelist(Tk.tk_call('file', 'volumes')).sort.each{|dir|
+ populate_tree(tree, tree.insert(nil, :end, :text=>dir,
+ :values=>[dir, 'directory']))
+ }
+end
+
+## Code to populate a node of the tree
+def populate_tree(tree, node)
+ return if tree.get(node, :type) != 'directory'
+
+ path = tree.get(node, :fullpath)
+ tree.delete(tree.children(node))
+ Dir.glob("#{path}/*").sort.each{|f|
+ type = File.ftype(f)
+ id = tree.insert(node, :end,
+ :text=>File.basename(f), :values=>[f, type]).id
+ if type == 'directory'
+ ## Make it so that this node is openable
+ tree.insert(id, 0, :text=>'dummy')
+ tree.itemconfigure(id, :text=>File.basename(f))
+ elsif type == 'file'
+ size = File.size(f)
+ if size >= 1024*1024*1024
+ size = '%.1f GB' % (size.to_f/1024/1024/1024)
+ elsif size >= 1024*1024
+ size = '%.1f MB' % (size.to_f/1024/1024)
+ elsif size >= 1024
+ size = '%.1f KB' % (size.to_f/1024)
+ else
+ size = '%.1f bytes' % (size.to_f/1024)
+ end
+ tree.set(id, :size, size)
+ end
+ }
+
+ # Stop this code from rerunning on the current node
+ tree.set(node, :type, 'processed_directory')
+end
+
+## Create the tree and set it up
+tree = Ttk::Treeview.new(base_frame, :columns=>%w(fullpath type size),
+ :displaycolumns=>['size'])
+if Tk.windowingsystem != 'aqua'
+ vsb = tree.yscrollbar(Ttk::Scrollbar.new(base_frame))
+ hsb = tree.xscrollbar(Ttk::Scrollbar.new(base_frame))
+else
+ vsb = tree.yscrollbar(Tk::Scrollbar.new(base_frame))
+ hsb = tree.xscrollbar(Tk::Scrollbar.new(base_frame))
+end
+
+tree.heading_configure('#0', :text=>'Directory Structure')
+tree.heading_configure('size', :text=>'File Size')
+tree.column_configure('size', :stretch=>0, :width=>70)
+populate_roots(tree)
+tree.bind('<TreeviewOpen>', '%W'){|w| populate_tree(w, w.focus_item)}
+
+## Arrange the tree and its scrollbars in the toplevel
+container = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true)
+container.lower
+Tk.grid(tree, vsb, :in=>container, :sticky=>'nsew')
+Tk.grid(hsb, :in=>container, :sticky=>'nsew')
+container.grid_columnconfigure(0, :weight=>1)
+container.grid_rowconfigure(0, :weight=>1)
diff --git a/ext/tk/sample/demos-jp/ttkbut.rb b/ext/tk/sample/demos-jp/ttkbut.rb
new file mode 100644
index 0000000000..4d577120bb
--- /dev/null
+++ b/ext/tk/sample/demos-jp/ttkbut.rb
@@ -0,0 +1,145 @@
+# -*- coding: euc-jp -*-
+#
+# ttkbut.rb
+#
+# This demonstration script creates a toplevel window containing several
+# simple Ttk widgets, such as labels, labelframes, buttons, checkbuttons and
+# radiobuttons.
+#
+# based on "Id: ttkbut.tcl,v 1.4 2007/12/13 15:27:07 dgp Exp"
+
+if defined?($ttkbut_demo) && $ttkbut_demo
+ $ttkbut_demo.destroy
+ $ttkbut_demo = nil
+end
+
+$ttkbut_demo = TkToplevel.new {|w|
+ title("Simple Ttk Widgets")
+ iconname("ttkbut")
+ positionWindow(w)
+}
+
+base_frame = TkFrame.new($ttkbut_demo).pack(:fill=>:both, :expand=>true)
+
+Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left,
+ :text=><<EOL).pack(:side=>:top, :fill=>:x)
+Ttk¤È¤Ï¡¤¥Æ¡¼¥Þ»ØÄê²Äǽ¤Ê¿·¤·¤¤¥¦¥£¥¸¥§¥Ã¥È½¸¹ç¤Ç¤¹¡¥\
+º£¡¤¤¢¤Ê¤¿¤¬Ìܤˤ·¤Æ¤¤¤ë¤Î¤ÏTtk¤Î¥Æ¡¼¥Þ²½¥é¥Ù¥ë¤Ç¡¤\
+²¼¤Ë¤ÏTtk¤Î¥é¥Ù¥ë¥Õ¥ì¡¼¥à¤ÎÃæ¤Ë»°¤Ä¤Î¥°¥ë¡¼¥×¤ÎTtk¥¦¥£¥¸¥§¥Ã¥È¤¬\
+ɽ¼¨¤µ¤ì¤Æ¤¤¤Þ¤¹¡¥
+ºÇ½é¤Î¥°¥ë¡¼¥×¤ÏÁ´¤Æ¥Ü¥¿¥ó¤Ç¤¢¤ê¡¤\
+¤½¤ì¤¾¤ì¥¯¥ê¥Ã¥¯¤¹¤ì¤Ð¸½ºß¤Î¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¤Î¥Æ¡¼¥Þ¤¬ÀßÄꤵ¤ì¤Þ¤¹¡¥
+£²ÈÖÌܤΥ°¥ë¡¼¥×¤Ï»°¤Ä¤Î¥Á¥§¥Ã¥¯¥Ü¥¿¥ó½¸¹ç¤Ç¤¹¡¥\
+³Æ½¸¹ç¤Î´Ö¤Ë¤Ï¡¤¥»¥Ñ¥ì¡¼¥¿¥¦¥£¥¸¥§¥Ã¥È¤¬ÃÖ¤«¤ì¤Æ¤¤¤Þ¤¹¡¥\
+¤Ê¤ª¡ÖÍ­¸ú²½¡×¥Ü¥¿¥ó¤Ï¡¤¤³¤Î¥È¥Ã¥×¥ì¥Ù¥ë¥¦¥£¥¸¥§¥Ã¥ÈÆâ¤Î\
+¾¤Î¤¹¤Ù¤Æ¤Î¥Æ¡¼¥Þ²½¥¦¥£¥¸¥§¥Ã¥È¤Î¾õÂÖ(state)¤¬"disabled"¤«¤É¤¦¤«¤ò\
+¥³¥ó¥È¥í¡¼¥ë¤¹¤ë¤³¤È¤ËÃí°Õ¤·¤Æ¤¯¤À¤µ¤¤¡¥
+£³ÈÖÌܤΥ°¥ë¡¼¥×¤Ï´ØÏ¢ÉÕ¤±¤é¤ì¤¿¥é¥¸¥ª¥Ü¥¿¥ó½¸¹ç¤È¤Ê¤Ã¤Æ¤¤¤Þ¤¹¡¥
+EOL
+
+## Add buttons for setting the theme
+buttons = Ttk::Labelframe.new(base_frame, :text=>'¥Ü¥¿¥ó')
+# Ttk::Style.theme_names.each{|theme|
+# Ttk::Button.new(buttons, :text=>theme,
+# :command=>proc{Ttk::Style.theme_use theme}).pack(:pady=>2)
+# }
+Ttk.themes.each{|theme|
+ Ttk::Button.new(buttons, :text=>theme,
+ :command=>proc{Ttk.set_theme theme}).pack(:pady=>2)
+}
+
+## Helper procedure for the top checkbutton
+def setState(root, value, *excepts)
+ return if excepts.member?(root)
+
+ ## Non-Ttk widgets (e.g. the toplevel) will fail, so make it silent
+ begin
+ root.state = value
+ rescue
+ end
+
+ ## Recursively invoke on all children of this root that are in the same
+ ## toplevel widget
+ root.winfo_children.each{|w|
+ setState(w, value, *excepts) if w.winfo_toplevel == root.winfo_toplevel
+ }
+end
+
+## Set up the checkbutton group
+checks = Ttk::Labelframe.new(base_frame, :text=>'¥Á¥§¥Ã¥¯¥Ü¥¿¥ó')
+enabled = TkVariable.new(true)
+e = Ttk::Checkbutton.new(checks, :text=>'Í­¸ú²½', :variable=>enabled,
+ :command=>proc{
+ setState($ttkbut_demo,
+ ((enabled.bool)? "!disabled" : "disabled"),
+ e)
+ })
+
+## See ttk_widget(n) for other possible state flags
+sep1 = Ttk::Separator.new(checks)
+sep2 = Ttk::Separator.new(checks)
+
+cheese = TkVariable.new
+tomato = TkVariable.new
+basil = TkVariable.new
+oregano = TkVariable.new
+
+c1 = Ttk::Checkbutton.new(checks, :text=>'¥Á¡¼¥º', :variable=>cheese)
+c2 = Ttk::Checkbutton.new(checks, :text=>'¥È¥Þ¥È', :variable=>tomato)
+c3 = Ttk::Checkbutton.new(checks, :text=>'¥Ð¥¸¥ë', :variable=>basil)
+c4 = Ttk::Checkbutton.new(checks, :text=>'¥ª¥ì¥¬¥Î', :variable=>oregano)
+
+Tk.pack(e, sep1, c1, c2, sep2, c3, c4, :fill=>:x, :pady=>2)
+
+## Set up the radiobutton group
+radios = Ttk::Labelframe.new(base_frame, :text=>'¥é¥¸¥ª¥Ü¥¿¥ó')
+
+happyness = TkVariable.new
+
+r1 = Ttk::Radiobutton.new(radios, :variable=>happyness,
+ :text=>'Great', :value=>'great')
+r2 = Ttk::Radiobutton.new(radios, :variable=>happyness,
+ :text=>'Good', :value=>'good')
+r3 = Ttk::Radiobutton.new(radios, :variable=>happyness,
+ :text=>'Ok', :value=>'ok')
+r4 = Ttk::Radiobutton.new(radios, :variable=>happyness,
+ :text=>'Poor', :value=>'poor')
+r5 = Ttk::Radiobutton.new(radios, :variable=>happyness,
+ :text=>'Awful', :value=>'awful')
+
+Tk.pack(r1, r2, r3, r4, r5, :fill=>:x, :padx=>3, :pady=>2)
+
+## See Code / Dismiss
+Ttk::Frame.new(base_frame) {|frame|
+ sep = Ttk::Separator.new(frame)
+ Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
+ TkGrid('x',
+ Ttk::Button.new(frame, :text=>'ÊÑ¿ô»²¾È',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{
+ showVars(base_frame, ['Í­¸ú²½', enabled],
+ ['¥Á¡¼¥º', cheese], ['¥È¥Þ¥È', tomato],
+ ['¥Ð¥¸¥ë', basil], ['¥ª¥ì¥¬¥Î', oregano],
+ ['¹¬Ê¡ÅÙ', happyness])
+ }),
+ Ttk::Button.new(frame, :text=>'¥³¡¼¥É»²¾È',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{showCode 'ttkbut'}),
+ Ttk::Button.new(frame, :text=>'ÊĤ¸¤ë',
+ :image=>$image['delete'], :compound=>:left,
+ :command=>proc{
+ tmppath = $ttkbut_demo
+ $ttkbut_demo = nil
+ $showVarsWin[tmppath.path] = nil
+ tmppath.destroy
+ }),
+ :padx=>4, :pady=>4)
+ grid_columnconfigure(0, :weight=>1)
+ pack(:side=>:bottom, :fill=>:x, :expand=>true)
+}
+
+## Arrange things neatly
+f = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true)
+f.lower
+Tk.grid(buttons, checks, radios, :in=>f, :sticky=>'nwe', :pady=>2, :padx=>3)
+f.grid_columnconfigure([0, 1, 2], :weight=>1, :uniform=>:yes)
diff --git a/ext/tk/sample/demos-jp/ttkmenu.rb b/ext/tk/sample/demos-jp/ttkmenu.rb
new file mode 100644
index 0000000000..d349b42d11
--- /dev/null
+++ b/ext/tk/sample/demos-jp/ttkmenu.rb
@@ -0,0 +1,91 @@
+# -*- coding: euc-jp -*-
+#
+# ttkmenu.rb --
+#
+# This demonstration script creates a toplevel window containing several Ttk
+# menubutton widgets.
+#
+# based on "Id: ttkmenu.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp"
+
+if defined?($ttkmenu_demo) && $ttkmenu_demo
+ $ttkmenu_demo.destroy
+ $ttkmenu_demo = nil
+end
+
+$ttkmenu_demo = TkToplevel.new {|w|
+ title("Ttk Menu Buttons")
+ iconname("ttkmenu")
+ positionWindow(w)
+}
+
+base_frame = Ttk::Frame.new($ttkmenu_demo).pack(:fill=>:both, :expand=>true)
+
+Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left,
+ :text=><<EOL).pack(:side=>:top, :fill=>:x)
+Ttk¤È¤Ï¡¤¥Æ¡¼¥Þ»ØÄê²Äǽ¤Ê¿·¤·¤¤¥¦¥£¥¸¥§¥Ã¥È½¸¹ç¤Ç¤¹¡¥\
+¤³¤ì¤Ë¤è¤ê¥Æ¡¼¥Þ¤ËÂбþ¤¹¤ë¤³¤È¤¬¤Ç¤­¤ë¤è¤¦¤Ë¤Ê¤Ã¤¿¥¦¥£¥¸¥§¥Ã¥È¤Î¤Ò¤È¤Ä¤Ë\
+¥á¥Ë¥å¡¼¥Ü¥¿¥ó¤¬¤¢¤ê¤Þ¤¹¡¥\
+°Ê²¼¤Ç¤Ï¡¤¥Æ¡¼¥Þ¤ËÂбþ¤·¤¿¥á¥Ë¥å¡¼¥Ü¥¿¥ó¤¬¤¤¤¯¤Ä¤«É½¼¨¤µ¤ì¤Æ¤¤¤Þ¤¹¡¥\
+¤½¤ì¤é¤ò»È¤Ã¤Æ¡¤¸½ºß»ÈÍÑÃæ¤Î¥Æ¡¼¥Þ¤òÊѹ¹¤¹¤ë¤³¤È¤¬²Äǽ¤Ç¤¹¡¥\
+¥Æ¡¼¥Þ¤ÎÁªÂò¤¬¥á¥Ë¥å¡¼¥Ü¥¿¥ó¼«¿È¤Î¸«³Ý¤±¤òÊѲ½¤µ¤»¤ëÍͻҤ䡤\
+Ãæ±û¤Î¥á¥Ë¥å¡¼¥Ü¥¿¥ó¤À¤±¤¬°Û¤Ê¤ë¥¹¥¿¥¤¥ë\
+(¥Ä¡¼¥ë¥Ð¡¼¤Ç¤Î°ìÈÌŪ¤Êɽ¼¨¤ËŬ¤·¤¿¤â¤Î)¤Çɽ¼¨¤µ¤ì¤Æ¤¤¤ëÍͻҤË\
+ÃíÌܤ·¤Æ¤¯¤À¤µ¤¤¡¥\
+¤Ê¤ª¡¤¥á¥Ë¥å¡¼¥Ü¥¿¥ó¤Ë¤Ä¤¤¤Æ¤Ï¥Æ¡¼¥Þ¤ËÂбþ¤·¤¿¥¦¥£¥¸¥§¥Ã¥È¤¬¤¢¤ê¤Þ¤¹¤¬¡¤\
+¥á¥Ë¥å¡¼¤Ë¤Ä¤¤¤Æ¤Ï¥Æ¡¼¥Þ¤ËÂбþ¤·¤¿¥¦¥£¥¸¥§¥Ã¥È¤Ï´Þ¤Þ¤ì¤Æ¤¤¤Þ¤»¤ó¡¥\
+¤½¤ÎÍýͳ¤Ï¡¤É¸½à¤ÎTk¤Î¥á¥Ë¥å¡¼¥¦¥£¥¸¥§¥Ã¥È¤¬\
+¤¹¤Ù¤Æ¤Î¥×¥é¥Ã¥È¥Û¡¼¥à¤Ç½½Ê¬¤ËÎɹ¥¤Ê¸«³Ý¤±¤ÈÁàºîÀ­¤ò»ý¤Ã¤Æ¤¤¤ë¡¤\
+ÆÃ¤Ë¡¤Â¿¤¯¤Î´Ä¶­¤Ç¤½¤Î´Ä¶­ËÜÍè¤ÎÁàºîÂηϤȤʤë¤è¤¦¤Ë¼ÂÁõ¤µ¤ì¤Æ¤¤¤ë¤È\
+ȽÃǤµ¤ì¤¿¤³¤È¤Ë¤è¤ê¤Þ¤¹¡¥
+EOL
+
+Ttk::Separator.new(base_frame).pack(:side=>:top, :fill=>:x)
+
+## See Code / Dismiss
+Ttk::Frame.new($ttkmenu_demo) {|frame|
+ sep = Ttk::Separator.new(frame)
+ Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
+ TkGrid('x',
+ Ttk::Button.new(frame, :text=>'¥³¡¼¥É»²¾È',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{showCode 'ttkmenu'}),
+ Ttk::Button.new(frame, :text=>'ÊĤ¸¤ë',
+ :image=>$image['delete'], :compound=>:left,
+ :command=>proc{
+ $ttkmenu_demo.destroy
+ $ttkmenu_demo = nil
+ }),
+ :padx=>4, :pady=>4)
+ grid_columnconfigure(0, :weight=>1)
+ pack(:side=>:bottom, :fill=>:x)
+}
+
+b1 = Ttk::Menubutton.new(base_frame,:text=>'¥Æ¡¼¥Þ¤òÁªÂò',:direction=>:above)
+b2 = Ttk::Menubutton.new(base_frame,:text=>'¥Æ¡¼¥Þ¤òÁªÂò',:direction=>:left)
+b3 = Ttk::Menubutton.new(base_frame,:text=>'¥Æ¡¼¥Þ¤òÁªÂò',:direction=>:right)
+b4 = Ttk::Menubutton.new(base_frame,:text=>'¥Æ¡¼¥Þ¤òÁªÂò',:direction=>:flush,
+ :style=>Ttk::Menubutton.style('Toolbutton'))
+b5 = Ttk::Menubutton.new(base_frame,:text=>'¥Æ¡¼¥Þ¤òÁªÂò',:direction=>:below)
+
+b1.menu(m1 = Tk::Menu.new(b1, :tearoff=>false))
+b2.menu(m2 = Tk::Menu.new(b2, :tearoff=>false))
+b3.menu(m3 = Tk::Menu.new(b3, :tearoff=>false))
+b4.menu(m4 = Tk::Menu.new(b4, :tearoff=>false))
+b5.menu(m5 = Tk::Menu.new(b5, :tearoff=>false))
+
+Ttk.themes.each{|theme|
+ m1.add(:command, :label=>theme, :command=>proc{Ttk.set_theme theme})
+ m2.add(:command, :label=>theme, :command=>proc{Ttk.set_theme theme})
+ m3.add(:command, :label=>theme, :command=>proc{Ttk.set_theme theme})
+ m4.add(:command, :label=>theme, :command=>proc{Ttk.set_theme theme})
+ m5.add(:command, :label=>theme, :command=>proc{Ttk.set_theme theme})
+}
+
+f = Ttk::Frame.new(base_frame).pack(:fill=>:x)
+f1 = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true)
+f.lower
+
+f.grid_anchor(:center)
+TkGrid('x', b1, 'x', :in=>f, :padx=>3, :pady=>2)
+TkGrid(b2, b4, b3, :in=>f, :padx=>3, :pady=>2)
+TkGrid('x', b5, 'x', :in=>f, :padx=>3, :pady=>2)
diff --git a/ext/tk/sample/demos-jp/ttknote.rb b/ext/tk/sample/demos-jp/ttknote.rb
new file mode 100644
index 0000000000..09cc7960a3
--- /dev/null
+++ b/ext/tk/sample/demos-jp/ttknote.rb
@@ -0,0 +1,97 @@
+# -*- coding: euc-jp -*-
+#
+# ttknote.rb --
+#
+# This demonstration script creates a toplevel window containing a Ttk
+# notebook widget.
+#
+# based on "Id: ttknote.tcl,v 1.5 2007/12/13 15:27:07 dgp Exp"
+
+if defined?($ttknote_demo) && $ttknote_demo
+ $ttknote_demo.destroy
+ $ttknote_demo = nil
+end
+
+$ttknote_demo = TkToplevel.new {|w|
+ title("Ttk Notebook Widget")
+ iconname("ttknote")
+ positionWindow(w)
+}
+
+## See Code / Dismiss
+Ttk::Frame.new($ttknote_demo) {|frame|
+ sep = Ttk::Separator.new(frame)
+ Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
+ TkGrid('x',
+ Ttk::Button.new(frame, :text=>'¥³¡¼¥É»²¾È',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{showCode 'ttknote'}),
+ Ttk::Button.new(frame, :text=>'ÊĤ¸¤ë',
+ :image=>$image['delete'], :compound=>:left,
+ :command=>proc{
+ $ttknote_demo.destroy
+ $ttknote_demo = nil
+ }),
+ :padx=>4, :pady=>4)
+ grid_columnconfigure(0, :weight=>1)
+ pack(:side=>:bottom, :fill=>:x)
+}
+
+base_frame = Ttk::Frame.new($ttknote_demo).pack(:fill=>:both, :expand=>true)
+
+## Make the notebook and set up Ctrl+Tab traversal
+notebook = Ttk::Notebook.new(base_frame).pack(:fill=>:both, :expand=>true,
+ :padx=>2, :pady=>3)
+notebook.enable_traversal
+
+## Popuplate the first pane
+f_msg = Ttk::Frame.new(notebook)
+msg_m = Ttk::Label.new(f_msg, :font=>$font, :wraplength=>'5i',
+ :justify=>:left, :anchor=>'n', :text=><<EOL)
+Ttk¤È¤Ï¡¤¥Æ¡¼¥Þ»ØÄê²Äǽ¤Ê¿·¤·¤¤¥¦¥£¥¸¥§¥Ã¥È½¸¹ç¤Ç¤¹¡¥\
+¤½¤ÎÃæ¤Ë´Þ¤Þ¤ì¤ë¥¦¥£¥¸¥§¥Ã¥È¤Î¤Ò¤È¤Ä¤Ë¥Î¡¼¥È¥Ö¥Ã¥¯¥¦¥£¥¸¥§¥Ã¥È¤¬¤¢¤ê¤Þ¤¹¡¥\
+¥Î¡¼¥È¥Ö¥Ã¥¯¥¦¥£¥¸¥§¥Ã¥È¤Ï¡¤\
+¸ÄÊÌ¤ÎÆâÍÆ¤ò»ý¤Ã¤¿¥Ñ¥Í¥ë¤«¤é¤ÎÁªÂò¤ò²Äǽ¤Ë¤¹¤ë¤è¤¦¤Ê\
+¥¿¥Ö¤Î½¸¹ç¡Ê¥¿¥Ö¥»¥Ã¥È¡Ë¤òÄê¤á¤Þ¤¹¡¥\
+¥¿¥Ö¥»¥Ã¥È¤ÏºÇ¶á¤Î¿¤¯¤Î¥æ¡¼¥¶¥¤¥ó¥¿¡¼¥Õ¥§¡¼¥¹¤Ç¸«¤é¤ì¤ëµ¡Ç½¤Ç¤¹¡¥\
+¥¿¥Ö¤ÎÁªÂò¤Ï¡¤¥Þ¥¦¥¹¤Ë¤è¤ë¤À¤±¤Ç¤Ê¤¯¡¤\
+¥Î¡¼¥È¥Ö¥Ã¥¯¥¦¥£¥¸¥§¥Ã¥È¤Î¥Ú¡¼¥¸¤Î¸«½Ð¤·¤¬ÁªÂò¤µ¤ì¤Æ¤¤¤ë»þ¤Ç¤¢¤ì¤Ð\
+Ctrl+Tab¥­¡¼¤ÎÆþÎϤˤè¤Ã¤Æ¤â¹Ô¤¦¤³¤È¤¬¤Ç¤­¤Þ¤¹¡¥\
+¤³¤Î¥Ç¥â¤Ç¤Ï¡¤¸«½Ð¤·¤Ç²¼ÀþÉÕ¤­¤Îʸ»ú¤Î¥­¡¼¤ÈAlt¥­¡¼¤È¤òÁȤ߹ç¤ï¤»¤ë¤³¤È¤Ç\
+¥Ú¡¼¥¸¤òÁªÂò¤¹¤ë¤³¤È¤¬¤Ç¤­¤ë¤è¤¦¤Ë¤âÀßÄꤷ¤Æ¤¤¤Þ¤¹¡¥\
+¤¿¤À¤·¡¤£²ÈÖÌܤΥ¿¥Ö¤Ï̵¸ú²½¤µ¤ì¤ÆÁªÂò¤Ç¤­¤Ê¤¤¤è¤¦¤Ë¤Ê¤Ã¤Æ¤¤¤ë¤³¤È¤Ë¤Ï\
+Ãí°Õ¤·¤Æ¤¯¤À¤µ¤¤¡¥
+EOL
+neat = TkVariable.new
+after_id = nil
+msg_b = Ttk::Button.new(f_msg, :text=>'¤¹¤Æ¤­¤À¡ª(Neat!)', :underline=>6,
+ :command=>proc{
+ neat.value = '¤¢¤¡¡¤¤½¤Î¤È¤ª¤ê¤µ¡¥¡¥¡¥'
+ Tk.after_cancel(after_id) if after_id
+ after_id = Tk.after(500){neat.value = ''}
+ })
+msg_b.winfo_toplevel.bind('Alt-n'){ msg_b.focus; msg_b.invoke }
+msg_l = Ttk::Label.new(f_msg, :textvariable=>neat)
+notebook.add(f_msg, :text=>'ÀâÌÀ(Description)', :underline=>3, :padding=>2)
+Tk.grid(msg_m, '-', :sticky=>'new', :pady=>2)
+Tk.grid(msg_b, msg_l, :pady=>[2, 4], :padx=>20)
+msg_b.grid_configure(:sticky=>'e')
+msg_l.grid_configure(:sticky=>'w')
+f_msg.grid_rowconfigure(1, :weight=>1)
+f_msg.grid_columnconfigure([0, 1], :weight=>1, :uniform=>1)
+
+## Populate the second pane. Note that the content doesn't really matter
+f_disabled = Ttk::Frame.new(notebook)
+notebook.add(f_disabled, :text=>'̵¸ú²½¤µ¤ì¤¿¥¿¥Ö', :state=>:disabled)
+
+## Popuplate the third pane
+f_editor = Ttk::Frame.new(notebook)
+notebook.add(f_editor, :text=>'¥Æ¥­¥¹¥È¥¨¥Ç¥£¥¿(Text Editor)', :underline=>9)
+editor_t = Tk::Text.new(f_editor, :width=>40, :height=>10, :wrap=>:char)
+if Tk.windowingsystem != 'aqua'
+ editor_s = editor_t.yscrollbar(Ttk::Scrollbar.new(f_editor))
+else
+ editor_s = editor_t.yscrollbar(Tk::Scrollbar.new(f_editor))
+end
+editor_s.pack(:side=>:right, :fill=>:y, :padx=>[0,2], :pady=>2)
+editor_t.pack(:fill=>:both, :expand=>true, :padx=>[2,0], :pady=>2)
diff --git a/ext/tk/sample/demos-jp/ttkpane.rb b/ext/tk/sample/demos-jp/ttkpane.rb
new file mode 100644
index 0000000000..96670c0e5c
--- /dev/null
+++ b/ext/tk/sample/demos-jp/ttkpane.rb
@@ -0,0 +1,216 @@
+# -*- coding: euc-jp -*-
+#
+# ttkpane.rb --
+#
+# This demonstration script creates a Ttk pane with some content.
+#
+# based on "Id: ttkpane.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp"
+
+if defined?($ttkpane_demo) && $ttkpane_demo
+ $ttkpane_demo.destroy
+ $ttkpane_demo = nil
+end
+
+$ttkpane_demo = TkToplevel.new {|w|
+ title("Themed Nested Panes")
+ iconname("ttkpane")
+ positionWindow(w)
+}
+
+base_frame = TkFrame.new($ttkpane_demo).pack(:fill=>:both, :expand=>true)
+
+Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left,
+ :text=><<EOL).pack(:side=>:top, :fill=>:x)
+¤³¤Î¥Ç¥â¤Ï¡¤Ëä¤á¹þ¤ß´Ø·¸¤Ë¤¢¤ë¥Æ¡¼¥ÞÉÕ¤­¥Ú¥¤¥ó¥É¥¦¥£¥ó¥É¥¦¤ò¼¨¤·¤Æ¤¤¤Þ¤¹¡¥\
+¤½¤ì¤¾¤ì¤ÎÂ礭¤µ¤Ï¡¤´Þ¤Þ¤ì¤Æ¤¤¤ë¥Ú¥¤¥ó¤Î´Ö¤Ë¤¢¤ë¥¨¥ê¥¢¤ò¤Ä¤«¤ó¤Ç\
+¶­³¦¤ò¥É¥é¥Ã¥°¤¹¤ë¤³¤È¤ÇÊѹ¹¤Ç¤­¤Þ¤¹¡¥
+EOL
+
+Ttk::Separator.new(base_frame).pack(:side=>:top, :fill=>:x)
+
+## See Code / Dismiss
+Ttk::Frame.new(base_frame) {|frame|
+ sep = Ttk::Separator.new(frame)
+ Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
+ TkGrid('x',
+ Ttk::Button.new(frame, :text=>'¥³¡¼¥É»²¾È',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{showCode 'ttkpane'}),
+ Ttk::Button.new(frame, :text=>'ÊĤ¸¤ë',
+ :image=>$image['delete'], :compound=>:left,
+ :command=>proc{
+ $ttkpane_demo.destroy
+ $ttkpane_demo = nil
+ }),
+ :padx=>4, :pady=>4)
+ grid_columnconfigure(0, :weight=>1)
+ pack(:side=>:bottom, :fill=>:x)
+}
+
+frame = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true)
+
+outer = Ttk::Panedwindow.new(frame, :orient=>:horizontal)
+outer.add(in_left = Ttk::Panedwindow.new(outer, :orient=>:vertical))
+outer.add(in_right = Ttk::Panedwindow.new(outer, :orient=>:vertical))
+in_left.add(left_top = Ttk::Labelframe.new(in_left, :text=>'¥Ü¥¿¥ó'))
+in_left.add(left_bot = Ttk::Labelframe.new(in_left, :text=>'»þ·×'))
+in_right.add(right_top = Ttk::Labelframe.new(in_right, :text=>'¥×¥í¥°¥ì¥¹'))
+in_right.add(right_bot = Ttk::Labelframe.new(in_right, :text=>'¥Æ¥­¥¹¥È'))
+if Tk.windowingsystem == 'aqua'
+ [left_top, left_bot, right_top, right_bot].each{|w| w.padding(3) }
+end
+
+# Fill the button pane
+Ttk::Button.new(left_top, :text=>'²¡¤·¤Æ¤Í',
+ :command=>proc{
+ Tk.messageBox(:type=>'ok', :icon=>'info',
+ :message=>'¤¤¤Æ¤Æ¡ª',
+ :detail=>'That hurt...', :parent=>base_frame,
+ :title=>'Button Pressed')
+ }).pack(:padx=>2, :pady=>5)
+
+
+zones_list = [
+ [':Europe/Berlin'],
+ [':America/Argentina/Buenos_Aires', ':America/Buenos_Aires'],
+ [':Africa/Johannesburg'],
+ [':Europe/London'],
+ [':America/Los_Angeles'],
+ [':Europe/Moscow'],
+ [':America/New_York'],
+ [':Asia/Singapore'],
+ [':Australia/Sydney'],
+ [':Asia/Tokyo'],
+]
+
+zones = []
+
+# Check tzinfo support
+if $tk_major_ver > 8 || ($tk_major_ver == 8 && $tk_minor_ver >= 5)
+ tzinfo = :tcl
+
+ zones_list.each{|list|
+ list.each{|zone|
+ begin
+ # Force a pre-load of all the timezones needed; otherwise can end up
+ # poor-looking synch problems!
+ Tk.tk_call('clock', 'format', '0', '-timezone', zone)
+ rescue RuntimeError
+ # ignore
+ else
+ zones << [zone, zone[%r<[^/:]+$>].tr('_', ' ')]
+ break
+ end
+ }
+ }
+
+else
+ begin
+ require 'tzinfo'
+ tzinfo = :tzinfo
+ rescue Exception
+ begin
+ require 'tzfile'
+ tzinfo = :tzfile
+ rescue Exception
+ tzinfo = nil
+ end
+ end
+
+ case tzinfo
+ when :tzinfo
+ zones_list.each{|list|
+ list.each{|zone|
+ begin
+ tz = TZInfo::Timezone.get(zone[%r<[^:]+$>])
+ rescue Exception
+ # ignore
+ else
+ zones << [tz, zone[%r<[^/:]+$>].tr('_', ' ')]
+ break
+ end
+ }
+ }
+
+ when :tzfile
+ zones_list.each{|list|
+ list.each{|zone|
+ begin
+ tz = TZFile.create(zone[%r<[^:]+$>])
+ rescue Exception
+ # ignore
+ else
+ zones << [tz, zone[%r<[^/:]+$>].tr('_', ' ')]
+ break
+ end
+ }
+ }
+
+ else
+ [ -7, -4, -2, -1, 0, +1, +3, +8, +9, +10 ].each{|zone|
+ zones << [zone, 'UTC%+03d00' % zone]
+ }
+ end
+end
+
+time = TkVariable.new_hash
+
+case tzinfo
+when :tcl
+ update_proc = proc{|now, tz, label|
+ time[label] = Tk.tk_call('clock', 'format', now.tv_sec,
+ '-timezone', tz, '-format', '%T')
+ }
+when :tzinfo
+ update_proc = proc{|now, tz, label|
+ time[label] = tz.utc_to_local(now).strftime('%H:%M:%S')
+ }
+when :tzfile
+ update_proc = proc{|now, tz, label|
+ time[label] = tz.at(now.tv_sec).strftime('%H:%M:%S')
+ }
+else
+ update_proc = proc{|now, tz, label|
+ time[label] = (now + (tz * 3600)).strftime('%H:%M:%S')
+ }
+end
+
+# Fill the clocks pane
+zones.each_with_index{|(zone, label), idx|
+ Ttk::Separator.new(left_bot).pack(:fill=>:x) if idx > 0
+ Ttk::Label.new(left_bot, :text=>label, :anchor=>'w').pack(:fill=>:x)
+ Ttk::Label.new(left_bot, :textvariable=>time.ref(label),
+ :anchor=>'w').pack(:fill=>:x)
+}
+
+# Timer start
+every = proc{
+ now = Time.now.utc
+ zones.each{|zone, label| update_proc.call(now, zone, label) }
+}
+TkRTTimer.new(1000, -1, every).start(0, every)
+
+# Fill the progress pane
+Ttk::Progressbar.new(right_top, :mode=>:indeterminate).pack(:fill=>:both, :expand=>true).start
+
+# Fill the text pane
+if Tk.windowingsystem != 'aqua'
+ # The trick with the ttk::frame makes the text widget look like it fits with
+ # the current Ttk theme despite not being a themed widget itself. It is done
+ # by styling the frame like an entry, turning off the border in the text
+ # widget, and putting the text widget in the frame with enough space to allow
+ # the surrounding border to show through (2 pixels seems to be enough).
+ f = Ttk::Frame.new(right_bot, :style=>Ttk::Entry)
+ txt = TkText.new(frame, :wrap=>:word, :width=>30, :borderwidth=>0)
+ txt.pack(:fill=>:both, :expand=>true, :in=>f, :pady=>2, :padx=>2)
+ scr = txt.yscrollbar(Ttk::Scrollbar.new(frame))
+ scr.pack(:side=>:right, :fill=>:y, :in=>right_bot)
+ f.pack(:fill=>:both, :expand=>true)
+ outer.pack(:fill=>:both, :expand=>true)
+else
+ txt = TkText.new(frame, :wrap=>:word, :width=>30, :borderwidth=>0)
+ scr = txt.yscrollbar(TkScrollbar.new(frame))
+ scr.pack(:side=>:right, :fill=>:y, :in=>right_bot)
+ txt.pack(:fill=>:both, :expand=>true, :in=>right_bot)
+ outer.pack(:fill=>:both, :expand=>true, :padx=>10, :pady=>[6, 10])
+end
diff --git a/ext/tk/sample/demos-jp/ttkprogress.rb b/ext/tk/sample/demos-jp/ttkprogress.rb
new file mode 100644
index 0000000000..43a9cbcd7e
--- /dev/null
+++ b/ext/tk/sample/demos-jp/ttkprogress.rb
@@ -0,0 +1,71 @@
+# -*- coding: euc-jp -*-
+#
+# ttkprogress.rb --
+#
+# This demonstration script creates several progress bar widgets.
+#
+# based on "Id: ttkprogress.tcl,v 1.3 2007/12/13 15:27:07 dgp Exp"
+
+if defined?($ttkprogress_demo) && $ttkprogress_demo
+ $ttkprogress_demo.destroy
+ $ttkprogress_demo = nil
+end
+
+$ttkprogress_demo = TkToplevel.new {|w|
+ title("Progress Bar Demonstration")
+ iconname("ttkprogress")
+ positionWindow(w)
+}
+
+base_frame = TkFrame.new($ttkprogress_demo).pack(:fill=>:both, :expand=>true)
+
+Ttk::Label.new(base_frame, :font=>$font, :wraplength=>'4i', :justify=>:left,
+ :text=><<EOL).pack(:side=>:top, :fill=>:x)
+²¼¤Ë¤¢¤ë¤Î¤ÏÆó¤Ä¤Î¥×¥í¥°¥ì¥¹¥Ð¡¼¤Ç¤¹¡¥\
+¾å¤Î¤â¤Î¤Ï"determinate"¥¿¥¤¥×¤Î¥×¥í¥°¥ì¥¹¥Ð¡¼¤Ç¡¤\
+Î㤨¤Ð¥×¥í¥°¥é¥à¤¬Í¿¤¨¤é¤ì¤¿¥¿¥¹¥¯¤ò½ªÎ»¤¹¤ë¤Þ¤Ç¤Ë¤É¤Î¤¯¤é¤¤¤«¤«¤ë¤«¤ò\
+¼¨¤¹¤È¤­¤Ê¤É¤ËÍѤ¤¤é¤ì¤Þ¤¹¡¥\
+²¼¤Î¤â¤Î¤Ï"indeterminate"¥¿¥¤¥×¤Î¥×¥í¥°¥ì¥¹¥Ð¡¼¤Ç¡¤\
+Î㤨¤Ð¥×¥í¥°¥é¥à¤¬¼Â¹ÔÃæ(busy)¤Ç¤¢¤ë¤â¤Î¤Î\
+½ªÎ»¤Þ¤Ç¤Ë¤É¤ì¤¯¤é¤¤¤«¤«¤ë¤«¤Ïʬ¤«¤é¤Ê¤¤¤È¤¤¤¦¾õÂÖ¤ò\
+¼¨¤¹¤È¤­¤Ê¤É¤ËÍѤ¤¤é¤ì¤Þ¤¹¡¥\
+¤¤¤º¤ì¤Î¥×¥í¥°¥ì¥¹¥Ð¡¼¤â¡¤¤¹¤°²¼¤Ë¤¢¤ë¥Ü¥¿¥ó¤ò»È¤¦¤³¤È¤Ç\
+¼«Æ°¥¢¥Ë¥á¡¼¥·¥ç¥ó¥â¡¼¥É¤ÎON/OFF¤òÀÚÂØ¤¨¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡¥
+EOL
+
+## See Code / Dismiss buttons
+Ttk::Frame.new(base_frame) {|frame|
+ sep = Ttk::Separator.new(frame)
+ Tk.grid(sep, :columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
+ TkGrid('x',
+ Ttk::Button.new(frame, :text=>'¥³¡¼¥É»²¾È',
+ :image=>$image['view'], :compound=>:left,
+ :command=>proc{showCode 'ttkprogress'}),
+ Ttk::Button.new(frame, :text=>'ÊĤ¸¤ë',
+ :image=>$image['delete'], :compound=>:left,
+ :command=>proc{
+ $ttkprogress_demo.destroy
+ $ttkprogress_demo = nil
+ }),
+ :padx=>4, :pady=>4)
+ grid_columnconfigure(0, :weight=>1)
+ pack(:side=>:bottom, :fill=>:x)
+}
+
+frame = Ttk::Frame.new(base_frame).pack(:fill=>:both, :expand=>true)
+
+p1 = Ttk::Progressbar.new(frame, :mode=>:determinate)
+p2 = Ttk::Progressbar.new(frame, :mode=>:indeterminate)
+
+start = Ttk::Button.new(frame, :text=>'Start Progress',
+ :command=>proc{ p1.start; p2.start })
+stop = Ttk::Button.new(frame, :text=>'Stop Progress',
+ :command=>proc{ p1.stop; p2.stop })
+
+Tk.grid(p1, '-', :pady=>5, :padx=>10)
+Tk.grid(p2, '-', :pady=>5, :padx=>10)
+Tk.grid(start, stop, :padx=>10, :pady=>5)
+start.grid_configure(:sticky=>'e')
+stop.grid_configure(:sticky=>'w')
+frame.grid_columnconfigure(:all, :weight=>1)
+
diff --git a/ext/tk/sample/demos-jp/twind.rb b/ext/tk/sample/demos-jp/twind.rb
index 2b228e4acd..faefaefd6e 100644
--- a/ext/tk/sample/demos-jp/twind.rb
+++ b/ext/tk/sample/demos-jp/twind.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# text (embedded windows) widget demo (called by 'widget')
#
@@ -15,8 +16,10 @@ $twind_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($twind_demo).pack(:fill=>:both, :expand=>true)
+
# frame À¸À®
-$twind_buttons = TkFrame.new($twind_demo) {|frame|
+$twind_buttons = TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -36,7 +39,7 @@ $twind_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# frame À¸À®
$twind_text = nil
-TkFrame.new($twind_demo, 'highlightthickness'=>2, 'borderwidth'=>2,
+TkFrame.new(base_frame, 'highlightthickness'=>2, 'borderwidth'=>2,
'relief'=>'sunken') {|f|
$twind_text = TkText.new(f, 'setgrid'=>'true', 'font'=>$font,
'width'=>'70', 'height'=>35, 'wrap'=>'word',
@@ -206,7 +209,11 @@ def textWindPlot (t)
cursor 'top_left_arrow'
}
- font = '-Adobe-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*'
+ if $tk_version =~ /^4.*/
+ font = '-Adobe-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*'
+ else
+ font = 'Helvetica 18'
+ end
TkcLine.new($twind_plot, 100, 250, 400, 250, 'width'=>2)
TkcLine.new($twind_plot, 100, 250, 100, 50, 'width'=>2)
diff --git a/ext/tk/sample/demos-jp/twind2.rb b/ext/tk/sample/demos-jp/twind2.rb
index b634f07b4b..2a26b28ef6 100644
--- a/ext/tk/sample/demos-jp/twind2.rb
+++ b/ext/tk/sample/demos-jp/twind2.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
#
# text (embedded windows) widget demo 2 (called by 'widget')
#
@@ -15,8 +16,10 @@ $twind2_demo = TkToplevel.new {|w|
positionWindow(w)
}
+base_frame = TkFrame.new($twind2_demo).pack(:fill=>:both, :expand=>true)
+
# frame À¸À®
-$twind2_buttons = TkFrame.new($twind2_demo) {|frame|
+$twind2_buttons = TkFrame.new(base_frame) {|frame|
TkGrid(TkFrame.new(frame, :height=>2, :relief=>:sunken, :bd=>2),
:columnspan=>4, :row=>0, :sticky=>'ew', :pady=>2)
TkGrid('x',
@@ -38,7 +41,7 @@ $twind2_buttons.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
# frame À¸À®
$twind2_text = nil
-TkFrame.new($twind2_demo, 'highlightthickness'=>2, 'borderwidth'=>2,
+TkFrame.new(base_frame, 'highlightthickness'=>2, 'borderwidth'=>2,
'relief'=>'sunken') {|f|
$twind2_text = TkText.new(f, 'setgrid'=>true, 'font'=>$font,
# 'width'=>'70', 'height'=>35, 'wrap'=>'word',
diff --git a/ext/tk/sample/demos-jp/unicodeout.rb b/ext/tk/sample/demos-jp/unicodeout.rb
index 090cdf3059..178077ec08 100644
--- a/ext/tk/sample/demos-jp/unicodeout.rb
+++ b/ext/tk/sample/demos-jp/unicodeout.rb
@@ -1,3 +1,5 @@
+# -*- coding: euc-jp -*-
+#
# unicodeout.rb --
#
# This demonstration script shows how you can produce output (in label
@@ -16,7 +18,9 @@ $unicodeout_demo = TkToplevel.new {|w|
positionWindow(w)
}
-TkLabel.new($unicodeout_demo,
+base_frame = TkFrame.new($unicodeout_demo).pack(:fill=>:both, :expand=>true)
+
+TkLabel.new(base_frame,
:font=>$font, :wraplength=>'5.4i', :justify=>:left,
:text=><<EOL).pack(:side=>:top)
¤³¤ì¤Ï¡¤Tk¤Ë¤ª¤±¤ëÈó²¤ÊÆÊ¸»ú½¸¹ç¤òÍѤ¤¤ë¸À¸ì¤ËÂФ¹¤ë¥µ¥Ý¡¼¥È¤Ë¤Ä¤¤¤Æ¤Î\
@@ -38,7 +42,7 @@ Tcl¤Î¥¨¥¹¥±¡¼¥×ɽ¸½¤òÍѤ¤¤¿UNICODEʸ»úÎó¤Ç½ñ¤«¤ì¤Æ¤¤¤Þ¤¹¡¥\
EOL
#'
-TkFrame.new($unicodeout_demo){|f|
+TkFrame.new(base_frame){|f|
pack(:side=>:bottom, :fill=>:x, :pady=>'2m')
TkButton.new(f, :text=>'ÊĤ¸¤ë', :width=>15, :command=>proc{
@@ -51,7 +55,7 @@ TkFrame.new($unicodeout_demo){|f|
}).pack(:side=>:left, :expand=>true)
}
-wait_msg = TkLabel.new($unicodeout_demo,
+wait_msg = TkLabel.new(base_frame,
:text=>"¥Õ¥©¥ó¥ÈÆÉ¤ß¹þ¤ß¤Î´°Î»¤Þ¤Ç" +
"¤·¤Ð¤é¤¯¤ªÂÔ¤Á²¼¤µ¤¤¡¥¡¥¡¥",
:font=>"Helvetica 12 italic").pack
@@ -66,8 +70,8 @@ class Unicodeout_SampleFrame < TkFrame
# @@font = 'Newspaper 12'
# @@font = '{New century schoolbook} 12'
- def initialize()
- super($unicodeout_demo)
+ def initialize(base)
+ super(base)
grid_columnconfig(1, :weight=>1)
end
@@ -82,7 +86,7 @@ class Unicodeout_SampleFrame < TkFrame
l.grid_config(:padx, '1m')
end
end
-f = Unicodeout_SampleFrame.new
+f = Unicodeout_SampleFrame.new(base_frame)
f.pack(:expand=>true, :fill=>:both, :padx=>'2m', :pady=>'1m')
# Processing when some characters are missing might take a while, so make
diff --git a/ext/tk/sample/demos-jp/vscale.rb b/ext/tk/sample/demos-jp/vscale.rb
index 86f6f7cdee..a1097fd77f 100644
--- a/ext/tk/sample/demos-jp/vscale.rb
+++ b/ext/tk/sample/demos-jp/vscale.rb
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
require "tkcanvas"
if defined?($vscale_demo) && $vscale_demo
@@ -11,7 +12,9 @@ $vscale_demo = TkToplevel.new {|w|
}
positionWindow($vscale_demo)
-msg = TkLabel.new($vscale_demo) {
+base_frame = TkFrame.new($vscale_demo).pack(:fill=>:both, :expand=>true)
+
+msg = TkLabel.new(base_frame) {
font $font
wraplength '3.5i'
justify 'left'
@@ -22,7 +25,7 @@ msg = TkLabel.new($vscale_demo) {
}
msg.pack('side'=>'top', 'padx'=>'.5c')
-TkFrame.new($vscale_demo) {|frame|
+TkFrame.new(base_frame) {|frame|
TkButton.new(frame) {
#text 'λ²ò'
text 'ÊĤ¸¤ë'
@@ -39,7 +42,17 @@ TkFrame.new($vscale_demo) {|frame|
}.pack('side'=>'left', 'expand'=>'yes')
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>'2m')
-TkFrame.new($vscale_demo) {|frame|
+def setHeight(w, height)
+ height = height + 21
+ y2 = height - 30
+ if y2 < 21
+ y2 = 21
+ end
+ w.coords 'poly',15,20,35,20,35,y2,45,y2,25,height,5,y2,15,y2,15,20
+ w.coords 'line',15,20,35,20,35,y2,45,y2,25,height,5,y2,15,y2,15,20
+end
+
+TkFrame.new(base_frame) {|frame|
borderwidth 10
canvas = TkCanvas.new(frame) {|c|
width 50
@@ -65,14 +78,3 @@ TkFrame.new($vscale_demo) {|frame|
}.pack('side'=>'left', 'anchor'=>'ne')
scale.set 75
}.pack
-
-
-def setHeight(w, height)
- height = height + 21
- y2 = height - 30
- if y2 < 21
- y2 = 21
- end
- w.coords 'poly',15,20,35,20,35,y2,45,y2,25,height,5,y2,15,y2,15,20
- w.coords 'line',15,20,35,20,35,y2,45,y2,25,height,5,y2,15,y2,15,20
-end
diff --git a/ext/tk/sample/demos-jp/widget b/ext/tk/sample/demos-jp/widget
index 11495dda54..8eb699e513 100644
--- a/ext/tk/sample/demos-jp/widget
+++ b/ext/tk/sample/demos-jp/widget
@@ -1,14 +1,22 @@
#!/usr/bin/env ruby
+# -*- coding: euc-jp -*-
# ´Á»ú¥³¡¼¥ÉÀßÄê ( tk.rb ¤Î¥í¡¼¥É»þ¤Î encoding ¿äÄê/ÀßÄê¤Ë»È¤ï¤ì¤ë )
-$KCODE = 'euc'
+if RUBY_VERSION < '1.9.0' ### !!!!!!!!!!!!!!
+ $KCODE = 'euc'
+else
+ DEFAULT_TK_ENCODING = 'EUC-JP'
+end
# tk ´Ø·¸¥é¥¤¥Ö¥é¥ê¤ÎÆÉ¤ß¹þ¤ß
require 'tk'
# require 'tkafter'
+$RubyTk_WidgetDemo = true
+
# widget demo directory °ÌÃÖ¤Î³ÍÆÀ
-$demo_dir = File.dirname($0)
+# $demo_dir = File.dirname($0)
+$demo_dir = File.dirname(__FILE__)
# root ¤ÎÀ¸À®
$root = TkRoot.new{title "Ruby/Tk Widget Demonstration"}
@@ -43,15 +51,14 @@ when /^8.*/
$font = TkFont.new('Helvetica -12')
$kanji_font = TkFont.new('Helvetica -12', 'Mincho -12')
TkOption.add('*kanjiFont', knjfont, 'startupFile')
- $msg_kanji_font=TkFont.new('Helvetica 16', 'Gothic 16 bold')
+ $msg_kanji_font=TkFont.new('Helvetica 14 bold', 'Gothic 14 bold')
else
- $font = TkFont.new('-*-Helvetica-Medium-R-Normal--*-140-*-*-*-*-*-*', nil)
+ $font = TkFont.new('Helvetica 14', nil)
knjfont = '-*--16-*-jisx0208.1983-0'
- $kanji_font = TkFont.new('-*-Helvetica-Medium-R-Normal--*-140-*-*-*-*-*-*',
- knjfont)
+ $kanji_font = TkFont.new('Helvetic 14', knjfont)
TkOption.add('*kanjiFont', knjfont, 'startupFile')
- $msg_kanji_font=TkFont.new('-*-Helvetica-Medium-R-Normal--*-140-*-*-*-*-*-*',
+ $msg_kanji_font=TkFont.new('Helvetica 14',
'-*--24-*-jisx0208.1983-0')
end
#######
@@ -116,14 +123,22 @@ EOD
end
# ¥á¥Ë¥å¡¼ÀßÄê
-TkMenubar.new($root,
- [[['File', 0],
- ['About ... ', proc{aboutBox}, 0, '<F1>'],
- '---',
- ['Quit', proc{exit}, 0, 'Meta-Q']
- ]]).pack('side'=>'top', 'fill'=>'x')
+if $tk_major_ver >= 8
+ $root.add_menubar([[['File', 0],
+ ['About ... ', proc{aboutBox}, 0, '<F1>'],
+ '---',
+ ['Quit', proc{exit}, 0, 'Ctrl-Q']
+ ]])
+else
+ TkMenubar.new($root,
+ [[['File', 0],
+ ['About ... ', proc{aboutBox}, 0, '<F1>'],
+ '---',
+ ['Quit', proc{exit}, 0, 'Ctrl-Q']
+ ]]).pack('side'=>'top', 'fill'=>'x')
+end
$root.bind('F1', proc{aboutBox})
-$root.bind('Meta-q', proc{exit})
+$root.bind('Control-q', proc{exit})
=begin
TkFrame.new($root){|frame|
@@ -180,18 +195,27 @@ else
textFrame.pack('expand'=>'yes', 'fill'=>'both')
statusBar = TkFrame.new($root) {|f|
+ if $tk_version =~ /^4.*/
+ statusfont = '-*-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*'
+ else
+ statusfont = 'Helvetica 10'
+ end
$statusBarLabel = \
TkLabel.new(f, 'text'=>" ", 'relief'=>'sunken', 'bd'=>1, 'anchor'=>'w',
- 'font'=>'-*-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') \
+ 'font'=>statusfont) \
.pack('side'=>'left', 'padx'=>2, 'expand'=>'yes', 'fill'=>'both')
TkLabel.new(f, 'width'=>8, 'relief'=>'sunken', 'bd'=>1, 'anchor'=>'w',
- 'font'=>'-*-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*') \
+ 'font'=>statusfont) \
.pack('side'=>'left', 'padx'=>2)
}.pack('side'=>'bottom', 'fill'=>'x', 'pady'=>2)
end
# ¥Æ¥­¥¹¥È¥¿¥°ÀßÄê
-tag_title = TkTextTag.new(txt, 'font'=>'-*-Helvetica-Bold-R-Normal--*-180-*-*-*-*-*-*')
+if $tk_version =~ /^4.*/
+ tag_title = TkTextTag.new(txt, 'font'=>'-*-Helvetica-Bold-R-Normal--*-180-*-*-*-*-*-*')
+else
+ tag_title = TkTextTag.new(txt, 'font'=>'Helvetica 18 bold')
+end
#tag_kanji_title = TkTextTag.new(txt, 'kanjifont'=>$msg_kanji_font)
#tag_middle = TkTextTag.new(txt, 'kanjifont'=>$kanji_font)
tag_kanji_title = TkTextTag.new(txt, 'font'=>$msg_kanji_font)
@@ -262,14 +286,31 @@ txt.insert('end', <<"EOT")
¤ë¤¿¤á¤Ë¡¢"¥³¡¼¥É»²¾È"¥Ü¥¿¥ó¤ò¥¯¥ê¥Ã¥¯¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£¤¢¤Ê¤¿¤¬\
˾¤à¤Ê¤é¡¢¤½¤Î¥³¡¼¥É¤ò½¤Àµ¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡£½¤Àµ¤·¤¿¥³¡¼¥É¤Ç¥Ç¥â\
¥ó¥¹¥È¥ì¡¼¥·¥ç¥ó¤òºÆ¼Â¹Ô¤¹¤ë¤¿¤á¤Ë¤Ï¡¢¥³¡¼¥É¤¬½ñ¤«¤ì¤¿¥¦¥£¥ó¥É¥¦¤Ë\
-¤¢¤ë"¥Ç¥âºÆ¼Â¹Ô" ¥Ü¥¿¥ó¤ò¥¯¥ê¥Ã¥¯¤·¤Æ¤¯¤À¤µ¤¤¡£
-
-°ìÉô¤Î¥Ç¥â¤Ç¤Ï¡¤Èæ³ÓŪºÇ¶á¤Î¥Ð¡¼¥¸¥ç¥ó¤Î Tk ¤Ç¤Ê¤±¤ì¤Ð¥µ¥Ý¡¼¥È¤·¤Æ\
-¤¤¤Ê¤¤µ¡Ç½¤ò»È¤Ã¤Æ¼ÂÁõ¤·¤Æ¤¤¤Þ¤¹(Î㤨¤Ð Tk8.4 °Ê¾å¤Ê¤É)¡¥¤½¤Î¤¿¤á¡¤\
-¤½¤¦¤·¤¿µ¡Ç½¤ò»ý¤¿¤Ê¤¤ Tk ¥é¥¤¥Ö¥é¥ê¤ò»È¤Ã¤Æ¤¤¤ë¾ì¹ç¤Ë¤Ï¡¤¤½¤¦¤·¤¿\
-¥Ç¥â¤ÏÀµ¤·¤¯Æ°¤­¤Þ¤»¤ó¡¥¤½¤Î¤è¤¦¤Êµ¡Ç½¤¬É¬ÍפǤ¢¤ì¤Ð¡¤¤½¤ì¤ò¥µ¥Ý¡¼¥È\
-¤·¤Æ¤¤¤ë Tk ¥é¥¤¥Ö¥é¥ê¤ò»È¤¦¤è¤¦¤Ë¡¤tcltklib ¤ò¥³¥ó¥Ñ¥¤¥ë¤·¤Ê¤ª¤·¤Æ\
-¤¯¤À¤µ¤¤¡¥
+¤¢¤ë"¥Ç¥âºÆ¼Â¹Ô" ¥Ü¥¿¥ó¤ò¥¯¥ê¥Ã¥¯¤·¤Æ¤¯¤À¤µ¤¤¡£\
+¥³¡¼¥É¤ò½¤Àµ¤·¤Æ¤â¥ª¥ê¥¸¥Ê¥ë¤Î¥Õ¥¡¥¤¥ë¤¬½ñ¤­´¹¤¨¤é¤ì¤ë¤³¤È¤Ï\
+¤¢¤ê¤Þ¤»¤ó¤«¤é¡¢¿´ÇÛ¤»¤º¤Ë¿§¡¹¤ÊÊѹ¹¤ò»î¤·¤Æ¤ß¤Æ¤¯¤À¤µ¤¤¡£
+
+°ìÉô¤Î¥Ç¥â¤Ç¤Ï¡¢Èæ³ÓŪºÇ¶á¤Î¥Ð¡¼¥¸¥ç¥ó¤Î Tk ¤Ç¤Ê¤±¤ì¤Ð¥µ¥Ý¡¼¥È¤·¤Æ\
+¤¤¤Ê¤¤µ¡Ç½¤ò»È¤Ã¤Æ¼ÂÁõ¤·¤Æ¤¤¤Þ¤¹(Î㤨¤Ð Tk8.4 °Ê¾å¤Ê¤É)¡£¤½¤Î¤¿¤á¡¢\
+¤½¤¦¤·¤¿µ¡Ç½¤ò»ý¤¿¤Ê¤¤ Tk ¥é¥¤¥Ö¥é¥ê¤ò»È¤Ã¤Æ¤¤¤ë¾ì¹ç¤Ë¤Ï¡¢¤½¤¦¤·¤¿\
+¥Ç¥â¤ÏÀµ¤·¤¯Æ°¤­¤Þ¤»¤ó¡£¤½¤Î¤è¤¦¤Êµ¡Ç½¤¬É¬ÍפǤ¢¤ì¤Ð¡¢¤½¤ì¤ò¥µ¥Ý¡¼¥È\
+¤·¤Æ¤¤¤ë Tk ¥é¥¤¥Ö¥é¥ê¤ò»È¤¦¤è¤¦¤Ë tcltklib ¤ò¥³¥ó¥Ñ¥¤¥ë¤·¤Ê¤ª¤·¤Æ\
+¤¯¤À¤µ¤¤¡£
+
+¤â¤·¤¢¤Ê¤¿¤Î Tk ¤¬ (ºÇ½é¤«¤é´Þ¤à¤«¥¤¥ó¥¹¥È¡¼¥ë¤·¤¿¤«¤Ë¤è¤ê) \
+Ttk (Tile) ³ÈÄ¥¤òÍøÍѤǤ­¤ë¾õÂ֤Ǥ¢¤ë¤Ê¤é¡¢\
+Ttk ³ÈÄ¥¤Î¥Ç¥â (sample/tkextlib/tile/demo.rb) ¤â¤¼¤Ò»î¤·¤Æ¤ß¤Æ¤¯¤À¤µ¤¤¡£
+( ¿ʬ¡¤¸½ºß¤Î¤¢¤Ê¤¿¤Î´Ä¶­¤Ë¤Ï Ttk ³ÈÄ¥¤Ï\
+#{
+begin
+ require 'tkextlib/tile'
+ "¤¹¤Ç¤ËƳÆþ¤µ¤ì¤Æ¤¤¤Þ¤¹"
+rescue
+ "¤Þ¤À¥¤¥ó¥¹¥È¡¼¥ë¤µ¤ì¤Æ¤¤¤Þ¤»¤ó"
+end
+}\
+¡£)
+Ttk ³ÈÄ¥¤Ï¡¢Tk8.5 °Ê¾å¤Ç¤Ïɸ½à¤Îµ¡Ç½¤È¤·¤ÆÁȤ߹þ¤Þ¤ì¤Æ¤¤¤Þ¤¹¡£
EOT
@@ -318,6 +359,9 @@ txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "14. ¥é¥Ù¥ëÉÕ¤­¥Õ¥ì¡¼¥à (µ¡Ç½¤ËÂбþ¤·¤¿¥Ð¡¼¥¸¥ç¥ó¤ÎTk¤¬É¬Í×)\n",
tag_demo, "demo-labelframe")
txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "15. ¥Æ¡¼¥Þ¤ËÂбþ¤·¤¿¥¦¥£¥¸¥§¥Ã¥È¤Î´Êñ¤ÊÎã (Tile/Ttk³ÈÄ¥¤Ø¤ÎÂбþ¤¬É¬Í×)\n",
+ tag_demo, "demo-ttkbut")
+txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "\n")
#txt.insert('end', "¥ê¥¹¥È¥Ü¥Ã¥¯¥¹\n", tag_middle)
@@ -330,6 +374,12 @@ txt.insert('end', "2. ¿§: ¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¤Î¤¿¤á¤ÎÇÛ¿§¤òÊѤ¨¤ë\n",
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "3. ³Ê¸À½¸\n", tag_demo, "demo-sayings")
txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "4. ¹ñ¤Ë¤Ä¤¤¤Æ¤Î¥Þ¥ë¥Á¥«¥é¥à¥ê¥¹¥È (Tile/Ttk³ÈÄ¥¤Ø¤ÎÂбþ¤¬É¬Í×)\n",
+ tag_demo, "demo-mclist")
+txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "5. ¥Ç¥£¥ì¥¯¥È¥ê¥Ö¥é¥¦¥¶ (Tile/Ttk³ÈÄ¥¤Ø¤ÎÂбþ¤¬É¬Í×)\n",
+ tag_demo, "demo-tree")
+txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "\n")
#txt.insert('end', "¥¨¥ó¥È¥ê¤È¥¹¥Ô¥ó¥Ü¥Ã¥¯¥¹\n", tag_middle)
@@ -345,7 +395,10 @@ txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "4. ¥¹¥Ô¥ó¥Ü¥Ã¥¯¥¹ (µ¡Ç½¤ËÂбþ¤·¤¿¥Ð¡¼¥¸¥ç¥ó¤ÎTk¤¬É¬Í×)\n",
tag_demo, "demo-spin")
txt.insert('end', " \n ", tag_demospace)
-txt.insert('end', "5. ´Êñ¤Ê¥Õ¥©¡¼¥à\n", tag_demo, "demo-form")
+txt.insert('end', "5. ¥³¥ó¥Ü¥Ü¥Ã¥¯¥¹ (Tile/Ttk³ÈÄ¥¤Ø¤ÎÂбþ¤¬É¬Í×)\n",
+ tag_demo, "demo-combo")
+txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "6. ´Êñ¤Ê¥Õ¥©¡¼¥à\n", tag_demo, "demo-form")
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "\n")
@@ -367,6 +420,8 @@ txt.insert('end', "5. ¥¦¥£¥ó¥É¥¦¤òËä¤á¹þ¤ó¤À¥Æ¥­¥¹¥È (µ¡Ç½¤ËÂбþ¤·¤¿¥Ð¡¼¥¸¥ç¥ó¤Î
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "6. ¸¡º÷\n", tag_demo, "demo-search")
txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "7. ¥Æ¥­¥¹¥È¥¦¥£¥¸¥§¥Ã¥È¤ÎÂÐÅù²½(peering) (µ¡Ç½¤ËÂбþ¤·¤¿¥Ð¡¼¥¸¥ç¥ó¤ÎTk¤¬É¬Í×)\n", tag_demo, "demo-textpeer")
+txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "\n")
#txt.insert('end', "¥­¥ã¥ó¥Ð¥¹\n", tag_middle)
@@ -389,18 +444,23 @@ txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "8. ¥¹¥¯¥í¡¼¥ë²Äǽ¤Ê¥­¥ã¥ó¥Ð¥¹\n",
tag_demo, "demo-cscroll")
txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "9. ¥Á¥§¥¹¥Ü¡¼¥É¾å¤Îµ³»Î¤Î½ä²ó (Tile/Ttk³ÈÄ¥¤Ø¤ÎÂбþ¤¬É¬Í×)\n",
+ tag_demo, "demo-knightstour")
+txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "\n")
-#txt.insert('end', "¥¹¥±¡¼¥ë\n", tag_middle)
-txt.insert('end', "¥¹¥±¡¼¥ë\n", tag_kanji_title)
+#txt.insert('end', "¥¹¥±¡¼¥ë¤È¥×¥í¥°¥ì¥¹¥Ð¡¼\n", tag_middle)
+txt.insert('end', "¥¹¥±¡¼¥ë¤È¥×¥í¥°¥ì¥¹¥Ð¡¼\n", tag_kanji_title)
+txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "1. ¿âľ¥¹¥±¡¼¥ë\n", tag_demo.id, "demo-vscale")
txt.insert('end', " \n ", tag_demospace)
-txt.insert('end', "1. ¿âľ\n", tag_demo.id, "demo-vscale")
+txt.insert('end', "2. ¿åÊ¿¥¹¥±¡¼¥ë\n", tag_demo.id, "demo-hscale")
txt.insert('end', " \n ", tag_demospace)
-txt.insert('end', "2. ¿åÊ¿\n", tag_demo.id, "demo-hscale")
+txt.insert('end', "3. ¥×¥í¥°¥ì¥¹¥Ð¡¼ (Tile/Ttk³ÈÄ¥¤Ø¤ÎÂбþ¤¬É¬Í×)\n", tag_demo.id, "demo-ttkprogress")
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "\n")
-txt.insert('end', "¥Ú¥¤¥ó¥É¥¦¥£¥ó¥É¥¦\n", tag_kanji_title)
+txt.insert('end', "¥Ú¥¤¥ó¥É¥¦¥£¥ó¥É¥¦¤È¥Î¡¼¥È¥Ö¥Ã¥¯\n", tag_kanji_title)
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "1. ¿åÊ¿Êý¸þ (µ¡Ç½¤ËÂбþ¤·¤¿¥Ð¡¼¥¸¥ç¥ó¤ÎTk¤¬É¬Í×)\n",
tag_demo.id, "demo-paned1")
@@ -408,10 +468,16 @@ txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "2. ¿âľÊý¸þ (µ¡Ç½¤ËÂбþ¤·¤¿¥Ð¡¼¥¸¥ç¥ó¤ÎTk¤¬É¬Í×)\n",
tag_demo.id, "demo-paned2")
txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "3. ¥Æ¡¼¥Þ¤ËÂбþ¤·¤¿Ëä¤á¹þ¤ß¥Ú¥¤¥ó (Tile/Ttk³ÈÄ¥¤Ø¤ÎÂбþ¤¬É¬Í×)\n",
+ tag_demo.id, "demo-ttkpane")
+txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "4. ¥Î¡¼¥È¥Ö¥Ã¥¯¥¦¥£¥¸¥§¥Ã¥È (Tile/Ttk³ÈÄ¥¤Ø¤ÎÂбþ¤¬É¬Í×)\n",
+ tag_demo.id, "demo-ttknote")
+txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "\n")
-#txt.insert('end', "¥á¥Ë¥å¡¼\n", tag_middle)
-txt.insert('end', "¥á¥Ë¥å¡¼\n", tag_kanji_title)
+#txt.insert('end', "¥á¥Ë¥å¡¼¤È¥Ä¡¼¥ë¥Ð¡¼\n", tag_middle)
+txt.insert('end', "¥á¥Ë¥å¡¼¤È¥Ä¡¼¥ë¥Ð¡¼\n", tag_kanji_title)
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "1. ¥á¥Ë¥å¡¼¤È¥«¥¹¥±¡¼¥É¤ò´Þ¤ó¤À¥¦¥£¥ó¥É¥¦\n",
tag_demo, "demo-menu")
@@ -425,6 +491,12 @@ txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "4. ¥á¥Ë¥å¡¼¥Ü¥¿¥ó (Tk8.x ÀìÍÑ)\n",
tag_demo, "demo-menubu")
txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "5. ¥Æ¡¼¥Þ¤ËÂбþ¤·¤¿¥á¥Ë¥å¡¼¥Ü¥¿¥ó (Tile/Ttk³ÈÄ¥¤Ø¤ÎÂбþ¤¬É¬Í×)\n",
+ tag_demo.id, "demo-ttkmenu")
+txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "6. ¥Æ¡¼¥Þ¤ËÂбþ¤·¤¿¥Ä¡¼¥ë¥Ð¡¼ (Tile/Ttk³ÈÄ¥¤Ø¤ÎÂбþ¤¬É¬Í×)\n",
+ tag_demo.id, "demo-toolbar")
+txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "\n")
#txt.insert('end', "¥À¥¤¥¢¥í¥°¥¦¥£¥ó¥É¥¦\n", tag_middle)
@@ -432,9 +504,11 @@ txt.insert('end', "¥À¥¤¥¢¥í¥°¥¦¥£¥ó¥É¥¦\n", tag_kanji_title)
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "1. ¥á¥Ã¥»¡¼¥¸¥Ü¥Ã¥¯¥¹\n", tag_demo, "demo-msgbox")
txt.insert('end', " \n ", tag_demospace)
-txt.insert('end', "2. ¥Õ¥¡¥¤¥ëÁªÂò¥À¥¤¥¢¥í¥°\n", tag_demo, "demo-filebox")
+txt.insert('end', "2. ¾ÜºÙ¥Æ¥­¥¹¥ÈÉÕ¤­¤Î¥á¥Ã¥»¡¼¥¸¥Ü¥Ã¥¯¥¹ (µ¡Ç½¤ËÂбþ¤·¤¿¥Ð¡¼¥¸¥ç¥ó¤ÎTk¤¬É¬Í×)\n", tag_demo, "demo-msgbox2")
txt.insert('end', " \n ", tag_demospace)
-txt.insert('end', "3. ¿§ÁªÂò¥À¥¤¥¢¥í¥°\n", tag_demo, "demo-clrpick")
+txt.insert('end', "3. ¥Õ¥¡¥¤¥ëÁªÂò¥À¥¤¥¢¥í¥°\n", tag_demo, "demo-filebox")
+txt.insert('end', " \n ", tag_demospace)
+txt.insert('end', "4. ¿§ÁªÂò¥À¥¤¥¢¥í¥°\n", tag_demo, "demo-clrpick")
txt.insert('end', " \n ", tag_demospace)
txt.insert('end', "\n")
@@ -483,25 +557,30 @@ def showVars1(parent, *args)
end
top = TkToplevel.new(parent) {|w|
title "Variable values"
- TkLabel.new(w) {
+ base = TkFrame.new(w).pack(:fill=>:both, :expand=>true)
+ TkLabel.new(base) {
text "ÊÑ¿ôÃÍ:"
width 20
anchor 'center'
- font '-Adobe-helvetica-medium-r-normal--*-180-*-*-*-*-*-*'
+ if $tk_version =~ /^4.*/
+ font '-Adobe-helvetica-medium-r-normal--*-180-*-*-*-*-*-*'
+ else
+ font 'Helvetica 14'
+ end
}.pack('side'=>'top', 'fill'=>'x')
len = 1
args.each{|vnam,vbody|
len = vnam.to_s.length if vnam.to_s.length > len
}
args.each{|vnam,vbody|
- TkFrame.new(w){|f|
+ TkFrame.new(base){|f|
#TkLabel.new(f, 'text'=>"#{vnam}: ").pack('side'=>'left')
TkLabel.new(f, 'text'=>"#{vnam}: ",'width'=>len+2).pack('side'=>'left')
TkLabel.new(f, 'textvariable'=>vbody, 'anchor'=>'w')\
.pack('side'=>'left', 'expand'=>'yes', 'fill'=>'x')
}.pack('side'=>'top', 'anchor'=>'w', 'fill'=>'x')
}
- TkButton.new(w) {
+ TkButton.new(base) {
text "λ²ò"
command proc{w.destroy}
}.pack('side'=>'bottom', 'pady'=>2)
@@ -516,10 +595,12 @@ def showVars2(parent, *args)
rescue
end
end
- $showVarsWin[parent.path] = TkToplevel.new(parent) {|w|
+ $showVarsWin[parent.path] = TkToplevel.new(parent) {|top|
title "Variable values"
- TkLabelFrame.new(w, :text=>"ÊÑ¿ôÃÍ:",
+ base = TkFrame.new(top).pack(:fill=>:both, :expand=>true)
+
+ TkLabelFrame.new(base, :text=>"ÊÑ¿ôÃÍ:",
:font=>{:family=>'Helvetica', :size=>14}){|f|
args.each{|vnam,vbody|
TkGrid(TkLabel.new(f, :text=>"#{vnam}: ", :anchor=>'w'),
@@ -531,15 +612,15 @@ def showVars2(parent, *args)
f.grid_columnconfig(1, :weight=>1)
f.grid_rowconfig(100, :weight=>1)
}
- TkButton.new(w, :text=>"λ²ò", :width=>8, :default=>:active,
- :command=>proc{w.destroy}){|b|
- w.bind('Return', proc{b.invoke})
- w.bind('Escape', proc{b.invoke})
+ TkButton.new(base, :text=>"λ²ò", :width=>8, :default=>:active,
+ :command=>proc{top.destroy}){|b|
+ top.bind('Return', proc{b.invoke})
+ top.bind('Escape', proc{b.invoke})
b.grid(:sticky=>'e', :padx=>4, :pady=>[6, 4])
}
- w.grid_columnconfig(0, :weight=>1)
- w.grid_rowconfig(0, :weight=>1)
+ base.grid_columnconfig(0, :weight=>1)
+ base.grid_rowconfig(0, :weight=>1)
}
end
@@ -633,8 +714,27 @@ def _null_binding
end
private :_null_binding
-def eval_samplecode(code)
- Thread.new{ _null_binding.pseudo_toplevel_eval{ eval(code) } }.run
+def eval_samplecode(code, file=nil)
+ #eval(code)
+ #_null_binding.pseudo_toplevel_eval{ eval(code) }
+ #Thread.new{ _null_binding.pseudo_toplevel_eval{ eval(code) } }
+ Thread.new{
+ _null_binding.pseudo_toplevel_eval{
+ begin
+ if file
+ eval(code, binding, "(eval:#{file})")
+ else
+ eval(code)
+ end
+ rescue Exception=>e
+ #p e
+ TkBgError.show(e.message + "\n" +
+ "\n---< backtrace of Ruby side >-----\n" +
+ e.backtrace.join("\n") +
+ "\n---< backtrace of Tk side >-------")
+ end
+ }
+ }
Tk.update
end
@@ -648,7 +748,7 @@ def invoke(txt, idx)
Tk.update
# eval(IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join, _null_binding)
# Tk.update
- eval_samplecode(IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join)
+ eval_samplecode(IO.readlines("#{[$demo_dir, tag[5..-1]].join(File::Separator)}.rb").join, tag[5..-1] + '.rb')
txt.cursor(cursor)
$tag_visited.add("#{idx} linestart +1 chars", "#{idx} lineend +1 chars")
@@ -694,6 +794,7 @@ def showCode1(demo)
if $code_window == nil || TkWinfo.exist?($code_window) == false
$code_window = TkToplevel.new(nil)
f = TkFrame.new($code_window)
+
TkButton.new(f) {
#text "λ²ò"
text "ÊĤ¸¤ë"
@@ -701,14 +802,25 @@ def showCode1(demo)
$code_window.destroy
$code_window = nil
}
- }.pack('side'=>'left', 'expand'=>'yes', 'pady'=>2)
+ }.pack('side'=>'right', 'expand'=>'false', 'pady'=>2)
TkButton.new(f) {
text "ºÆ¼Â¹Ô"
# command proc{eval($code_text.get('1.0','end'), _null_binding)}
- command proc{eval_samplecode($code_text.get('1.0','end'))}
- }.pack('side'=>'left', 'expand'=>'yes', 'pady'=>2)
-# f.pack('side'=>'bottom', 'expand'=>'yes', 'fill'=>'x')
- f.pack('side'=>'bottom', 'fill'=>'x')
+ command proc{eval_samplecode($code_text.get('1.0','end'), '<viewer>')}
+ }.pack('side'=>'right', 'expand'=>'false', 'pady'=>2)
+
+ TkLabel.new(f,'text'=>'line:').pack('side'=>'left')
+ linenum =TkLabel.new(f,'text'=>'').pack('side'=>'left')
+ TkLabel.new(f,'text'=>' pos:').pack('side'=>'left')
+ posnum =TkLabel.new(f,'text'=>'').pack('side'=>'left')
+
+ $set_linenum = proc{|w|
+ line, pos = w.index('insert').split('.')
+ linenum.text = line
+ posnum.text = pos
+ }
+
+ f.pack('side'=>'bottom', 'expand'=>'true', 'fill'=>'x')
if $tk_version =~ /^4\.[01]/
s = TkScrollbar.new($code_window, 'orient'=>'vertical')
@@ -752,10 +864,21 @@ def showCode1(demo)
TkGrid.columnconfigure(f, 0, 'weight'=>1, 'minsize'=>0)
}
end
+
+ btag = TkBindTag.new
+
+ btag.bind('Key', $set_linenum, '%W')
+ btag.bind('Button', $set_linenum, '%W')
+
+ btags = $code_text.bindtags
+ btags.insert(btags.index($code_text.class) + 1, btag)
+ $code_text.bindtags = btags
+
else
$code_window.deiconify
$code_window.raise
end
+
$code_window.title("Demo code: #{file}")
$code_window.iconname(file)
# fid = open(file, 'r')
@@ -766,6 +889,9 @@ def showCode1(demo)
#$code_mark = TkTextMark.new($code_text, '1.0')
#$code_text.set_insert('1.0')
TkTextMarkInsert.new($code_text,'1.0')
+
+ $set_linenum.call($code_text)
+
fid.close
end
@@ -786,7 +912,19 @@ def showCode2(demo)
tf.grid_columnconfigure(0, :weight=>1)
bf = TkFrame.new($code_window)
-
+
+ lf = TkFrame.new(bf)
+ TkLabel.new(lf, :text=>'line:').pack(:side=>:left)
+ linenum =TkLabel.new(lf, :text=>'').pack(:side=>:left)
+ TkLabel.new(lf, :text=>' pos:').pack(:side=>:left)
+ posnum =TkLabel.new(lf, :text=>'').pack(:side=>:left)
+
+ $set_linenum = proc{|w|
+ line, pos = w.index('insert').split('.')
+ linenum.text = line
+ posnum.text = pos
+ }
+
#b_dis = TkButton.new(bf, :text=>'λ²ò', :default=>:active,
b_dis = TkButton.new(bf, :text=>'ÊĤ¸¤ë', :default=>:active,
:command=>proc{
@@ -800,12 +938,12 @@ def showCode2(demo)
b_run = TkButton.new(bf, :text=>'ºÆ¼Â¹Ô',
:command=>proc{
# eval($code_text.get('1.0','end'), _null_binding)
- eval_samplecode($code_text.get('1.0','end'))
+ eval_samplecode($code_text.get('1.0','end'), '<viewer>')
},
:image=>$image['refresh'], :compound=>:left)
- TkGrid('x', b_run, b_prn, b_dis, :padx=>4, :pady=>[6,4])
- bf.grid_columnconfigure(0, :weight=>1)
+ TkGrid(lf, 'x', b_run, b_prn, b_dis, :padx=>4, :pady=>[6,4])
+ bf.grid_columnconfigure(1, :weight=>1)
TkGrid(tf, :sticky=>'news')
TkGrid(bf, :sticky=>'ew')
@@ -818,6 +956,16 @@ def showCode2(demo)
$code_window.bindinfo('Return').each{|cmd, arg|
$code_window.bind_append('Escape', cmd, arg)
}
+
+ btag = TkBindTag.new
+
+ btag.bind('Key', $set_linenum, '%W')
+ btag.bind('Button', $set_linenum, '%W')
+
+ btags = $code_text.bindtags
+ btags.insert(btags.index($code_text.class) + 1, btag)
+ $code_text.bindtags = btags
+
else
$code_window.deiconify
$code_window.raise
@@ -829,6 +977,9 @@ def showCode2(demo)
$code_text.delete('1.0', 'end')
$code_text.insert('1.0', fid.read)
TkTextMarkInsert.new($code_text,'1.0')
+
+ $set_linenum.call($code_text)
+
fid.close
end
@@ -926,12 +1077,13 @@ end
#
def aboutBox
Tk.messageBox('icon'=>'info', 'type'=>'ok', 'title'=>'About Widget Demo',
- 'message'=>"Ruby/Tk ¥¦¥£¥¸¥§¥Ã¥È¥Ç¥â Ver.1.6.0-jp\n\n" +
+ 'message'=>"Ruby/Tk ¥¦¥£¥¸¥§¥Ã¥È¥Ç¥â Ver.1.7.0-jp\n\n" +
"based on demos of Tk8.1 -- 8.5 " +
- "( Copyright:: " +
+ "( Copyright of Tcl/Tk demos:: " +
"(c) 1996-1997 Sun Microsystems, Inc. / " +
"(c) 1997-2000 Ajuba Solutions, Inc. / " +
- "(c) 2001-2003 Donal K. Fellows )\n\n" +
+ "(c) 2001-2007 Donal K. Fellows / " +
+ "(c) 2002-2007 Daniel A. Steffen )\n\n" +
"Your Ruby & Tk Version ::\n" +
"Ruby#{RUBY_VERSION}(#{RUBY_RELEASE_DATE})[#{RUBY_PLATFORM}] / Tk#{$tk_patchlevel}#{(Tk::JAPANIZED_TK)? '-jp': ''}\n\n" +
"Ruby/Tk release date :: tcltklib #{TclTkLib::RELEASE_DATE}; tk #{Tk::RELEASE_DATE}")
@@ -953,7 +1105,7 @@ ARGV.each{|cmd|
end
#eval(IO.readlines("#{[$demo_dir, cmd].join(File::Separator)}.rb").join,
# _null_binding)
- eval_samplecode(IO.readlines("#{[$demo_dir, cmd].join(File::Separator)}.rb").join)
+ eval_samplecode(IO.readlines("#{[$demo_dir, cmd].join(File::Separator)}.rb").join, cmd + '.rb')
}
if no_launcher
$root.withdraw # hide root window
diff --git a/ext/tk/sample/editable_listbox.rb b/ext/tk/sample/editable_listbox.rb
new file mode 100644
index 0000000000..99345da380
--- /dev/null
+++ b/ext/tk/sample/editable_listbox.rb
@@ -0,0 +1,69 @@
+#
+# Editable_TkListbox class
+#
+# When "DoubleClick-1" on a listbox item, the entry box is opend on the
+# item. And when hit "Return" key on the entry box after modifying the
+# text, the entry box is closed and the item is changed. Or when hit
+# "Escape" key, the entry box is closed without modification.
+#
+# by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)
+#
+require 'tk'
+
+class Editable_TkListbox < TkListbox
+ def _ebox_placer(coord_y)
+ idx = self.nearest(coord_y)
+ x, y, w, h = self.bbox(idx)
+ @ebox.place(:x => 0, :relwidth => 1.0,
+ :y => y - self.selectborderwidth,
+ :height => h + 2 * self.selectborderwidth)
+ @ebox.pos = idx
+ @ebox.value = self.listvariable.list[idx]
+ @ebox.focus
+ end
+ private :_ebox_placer
+
+
+ def create_self(keys)
+ super(keys)
+
+ unless self.listvariable
+ self.listvariable = TkVariable.new(self.get(0, :end))
+ end
+
+ @ebox = TkEntry.new(self){
+ @pos = -1
+ def self.pos; @pos; end
+ def self.pos=(idx); @pos = idx; end
+ }
+
+ @ebox.bind('Return'){
+ list = self.listvariable.list
+ list[@ebox.pos] = @ebox.value
+ self.listvariable.value = list
+ @ebox.place_forget
+ @ebox.pos = -1
+ }
+
+ @ebox.bind('Escape'){
+ @ebox.place_forget
+ @ebox.pos = -1
+ }
+
+ self.bind('Double-1', '%y'){|y| _ebox_placer(y) }
+ end
+end
+
+if $0 == __FILE__
+ scr = TkScrollbar.new.pack(:side=>:right, :fill=>:y)
+
+ lbox1 = Editable_TkListbox.new.pack(:side=>:left)
+ lbox2 = Editable_TkListbox.new.pack(:side=>:left)
+
+ scr.assign(lbox1, lbox2)
+
+ lbox1.insert(:end, *%w(a b c d e f g h i j k l m n))
+ lbox2.insert(:end, 0,1,2,3,4,5,6,7,8,9,0,1,2,3)
+
+ Tk.mainloop
+end
diff --git a/ext/tk/sample/encstr_usage.rb b/ext/tk/sample/encstr_usage.rb
index 4285ec861c..b22c2504ac 100644
--- a/ext/tk/sample/encstr_usage.rb
+++ b/ext/tk/sample/encstr_usage.rb
@@ -11,7 +11,7 @@ t1 = TkText.new(:height=>5).pack
t2 = TkText.new(:height=>5).pack
t3 = TkText.new(:height=>5).pack
-src_str = IO.readlines('iso2022-kr.txt').join
+src_str = IO.readlines(File.join(File.dirname(__FILE__),'iso2022-kr.txt')).join
t1.insert('end',
"use neither Tk::EncodedString class nor Tk.encoding= method\n\n")
@@ -23,7 +23,8 @@ t2.insert('end',
t2.insert('end', enc_str)
Tk.encoding = 'iso2022-kr'
-t3.insert('end', "use Tk.encoding = 'iso2022-kr'\n\n")
+t3.insert('end', "use Tk.encoding = 'iso2022-kr' (Tk.force_default_encoding? == #{Tk.force_default_encoding?})\n\n")
+
t3.insert('end', src_str)
Tk.mainloop
diff --git a/ext/tk/sample/figmemo_sample.rb b/ext/tk/sample/figmemo_sample.rb
new file mode 100644
index 0000000000..1b6979d2dd
--- /dev/null
+++ b/ext/tk/sample/figmemo_sample.rb
@@ -0,0 +1,456 @@
+#!/usr/bin/env ruby
+require 'tk'
+
+begin
+ # try to use Img extension
+ require 'tkextlib/tkimg'
+rescue Exception
+ # cannot use Img extention --> ignore
+end
+
+
+############################
+# scrolled_canvas
+class TkScrolledCanvas < TkCanvas
+ include TkComposite
+
+ def initialize_composite(keys={})
+ @h_scr = TkScrollbar.new(@frame)
+ @v_scr = TkScrollbar.new(@frame)
+
+ @canvas = TkCanvas.new(@frame)
+ @path = @canvas.path
+
+ @canvas.xscrollbar(@h_scr)
+ @canvas.yscrollbar(@v_scr)
+
+ TkGrid.rowconfigure(@frame, 0, :weight=>1, :minsize=>0)
+ TkGrid.columnconfigure(@frame, 0, :weight=>1, :minsize=>0)
+
+ @canvas.grid(:row=>0, :column=>0, :sticky=>'news')
+ @h_scr.grid(:row=>1, :column=>0, :sticky=>'ew')
+ @v_scr.grid(:row=>0, :column=>1, :sticky=>'ns')
+
+ delegate('DEFAULT', @canvas)
+ delegate('background', @canvas, @h_scr, @v_scr)
+ delegate('activebackground', @h_scr, @v_scr)
+ delegate('troughcolor', @h_scr, @v_scr)
+ delegate('repeatdelay', @h_scr, @v_scr)
+ delegate('repeatinterval', @h_scr, @v_scr)
+ delegate('borderwidth', @frame)
+ delegate('relief', @frame)
+
+ delegate_alias('canvasborderwidth', 'borderwidth', @canvas)
+ delegate_alias('canvasrelief', 'relief', @canvas)
+
+ delegate_alias('scrollbarborderwidth', 'borderwidth', @h_scr, @v_scr)
+ delegate_alias('scrollbarrelief', 'relief', @h_scr, @v_scr)
+
+ configure(keys) unless keys.empty?
+ end
+end
+
+############################
+class PhotoCanvas < TkScrolledCanvas
+
+USAGE = <<EOT
+--- WHAT IS ---
+You can write comments on the loaded image, and save it as a Postscipt
+file (original image file is not modified). Each comment is drawn as a
+set of an indicator circle, an arrow, and a memo text. See the following
+how to write comments.
+This can save the list of memo texts to another file. It may useful to
+search the saved Postscript file by the comments on them.
+This may not support multibyte characters (multibyte texts are broken on
+a Postscript file). It depends on features of canvas widgets of Tcl/Tk
+libraries linked your Ruby/Tk. If you use Tcl/Tk8.0-jp (Japanized Tcl/Tk),
+you can (possibly) get a Japanese Postscript file.
+
+--- BINDINGS ---
+* Button-1 : draw comments by following steps
+ 1st - Set center of a indicator circle.
+ 2nd - Set head position of an arrow.
+ 3rd - Set tail position of an arrow, and show an entry box.
+ Input a memo text and hit 'Enter' key to entry the comment.
+
+* Button-2-drag : scroll the canvas
+
+* Button-3 : when drawing, cancel current drawing
+
+* Double-Button-3 : delete the clicked comment (text, arrow, and circle)
+EOT
+
+ def initialize(*args)
+ super(*args)
+
+ self.highlightthickness = 0
+ self.selectborderwidth = 0
+
+ @photo = TkPhotoImage.new
+ @img = TkcImage.new(self, 0, 0, :image=>@photo)
+
+ width = self.width
+ height = self.height
+ @scr_region = [-width, -height, width, height]
+ self.scrollregion(@scr_region)
+ self.xview_moveto(0.25)
+ self.yview_moveto(0.25)
+
+ @col = 'red'
+ @font = 'Helvetica -12'
+
+ @memo_id_num = -1
+ @memo_id_head = 'memo_'
+ @memo_id_tag = nil
+ @overlap_d = 2
+
+ @state = TkVariable.new
+ @border = 2
+ @selectborder = 1
+ @delta = @border + @selectborder
+ @entry = TkEntry.new(self, :relief=>:ridge, :borderwidth=>@border,
+ :selectborderwidth=>@selectborder,
+ :highlightthickness=>0)
+ @entry.bind('Return'){@state.value = 0}
+
+ @mode = old_mode = 0
+
+ _state0()
+
+ bind('2', :x, :y){|x,y| scan_mark(x,y)}
+ bind('B2-Motion', :x, :y){|x,y| scan_dragto(x,y)}
+
+ bind('3'){
+ next if (old_mode = @mode) == 0
+ @items.each{|item| item.delete }
+ _state0()
+ }
+
+ bind('Double-3', :widget, :x, :y){|w, x, y|
+ next if old_mode != 0
+ x = w.canvasx(x)
+ y = w.canvasy(y)
+ tag = nil
+ w.find_overlapping(x - @overlap_d, y - @overlap_d,
+ x + @overlap_d, y + @overlap_d).find{|item|
+ ! (item.tags.find{|name|
+ if name =~ /^(#{@memo_id_head}\d+)$/
+ tag = $1
+ end
+ }.empty?)
+ }
+ w.delete(tag) if tag
+ }
+ end
+
+ #-----------------------------------
+ private
+ def _state0() # init
+ @mode = 0
+
+ @memo_id_num += 1
+ @memo_id_tag = @memo_id_head + @memo_id_num.to_s
+
+ @target = nil
+ @items = []
+ @mark = [0, 0]
+ bind_remove('Motion')
+ bind('ButtonRelease-1', proc{|x,y| _state1(x,y)}, '%x', '%y')
+ end
+
+ def _state1(x,y) # set center
+ @mode = 1
+
+ @target = TkcOval.new(self,
+ [canvasx(x), canvasy(y)], [canvasx(x), canvasy(y)],
+ :outline=>@col, :width=>3, :tags=>[@memo_id_tag])
+ @items << @target
+ @mark = [x,y]
+
+ bind('Motion', proc{|x,y| _state2(x,y)}, '%x', '%y')
+ bind('ButtonRelease-1', proc{|x,y| _state3(x,y)}, '%x', '%y')
+ end
+
+ def _state2(x,y) # create circle
+ @mode = 2
+
+ r = Integer(Math.sqrt((x-@mark[0])**2 + (y-@mark[1])**2))
+ @target.coords([canvasx(@mark[0] - r), canvasy(@mark[1] - r)],
+ [canvasx(@mark[0] + r), canvasy(@mark[1] + r)])
+ end
+
+ def _state3(x,y) # set line start
+ @mode = 3
+
+ @target = TkcLine.new(self,
+ [canvasx(x), canvasy(y)], [canvasx(x), canvasy(y)],
+ :arrow=>:first, :arrowshape=>[10, 14, 5],
+ :fill=>@col, :tags=>[@memo_id_tag])
+ @items << @target
+ @mark = [x, y]
+
+ bind('Motion', proc{|x,y| _state4(x,y)}, '%x', '%y')
+ bind('ButtonRelease-1', proc{|x,y| _state5(x,y)}, '%x', '%y')
+ end
+
+ def _state4(x,y) # create line
+ @mode = 4
+
+ @target.coords([canvasx(@mark[0]), canvasy(@mark[1])],
+ [canvasx(x), canvasy(y)])
+ end
+
+ def _state5(x,y) # set text
+ @mode = 5
+
+ if x - @mark[0] >= 0
+ justify = 'left'
+ dx = - @delta
+
+ if y - @mark[1] >= 0
+ anchor = 'nw'
+ dy = - @delta
+ else
+ anchor = 'sw'
+ dy = @delta
+ end
+ else
+ justify = 'right'
+ dx = @delta
+
+ if y - @mark[1] >= 0
+ anchor = 'ne'
+ dy = - @delta
+ else
+ anchor = 'se'
+ dy = @delta
+ end
+ end
+
+ bind_remove('Motion')
+
+ @entry.value = ''
+ @entry.configure(:justify=>justify, :font=>@font, :foreground=>@col)
+
+ ewin = TkcWindow.new(self, [canvasx(x)+dx, canvasy(y)+dy],
+ :window=>@entry, :state=>:normal, :anchor=>anchor,
+ :tags=>[@memo_id_tag])
+
+ @entry.focus
+ @entry.grab
+ @state.wait
+ @entry.grab_release
+
+ ewin.delete
+
+ @target = TkcText.new(self, [canvasx(x), canvasy(y)],
+ :anchor=>anchor, :justify=>justify,
+ :fill=>@col, :font=>@font, :text=>@entry.value,
+ :tags=>[@memo_id_tag])
+
+ _state0()
+ end
+
+ #-----------------------------------
+ public
+ def load_photo(filename)
+ @photo.configure(:file=>filename)
+ end
+
+ def modified?
+ ! ((find_withtag('all') - [@img]).empty?)
+ end
+
+ def fig_erase
+ (find_withtag('all') - [@img]).each{|item| item.delete}
+ end
+
+ def reset_region
+ width = @photo.width
+ height = @photo.height
+
+ if width > @scr_region[2]
+ @scr_region[0] = -width
+ @scr_region[2] = width
+ end
+
+ if height > @scr_region[3]
+ @scr_region[1] = -height
+ @scr_region[3] = height
+ end
+
+ self.scrollregion(@scr_region)
+ self.xview_moveto(0.25)
+ self.yview_moveto(0.25)
+ end
+
+ def get_texts
+ ret = []
+ find_withtag('all').each{|item|
+ if item.kind_of?(TkcText)
+ ret << item[:text]
+ end
+ }
+ ret
+ end
+end
+############################
+
+# define methods for menu
+def open_file(canvas, fname)
+ if canvas.modified?
+ ret = Tk.messageBox(:icon=>'warning',:type=>'okcancel',:default=>'cancel',
+ :message=>'Canvas may be modified. Realy erase? ')
+ return if ret == 'cancel'
+ end
+
+ filetypes = [
+ ['GIF Files', '.gif'],
+ ['GIF Files', [], 'GIFF'],
+ ['PPM Files', '.ppm'],
+ ['PGM Files', '.pgm']
+ ]
+
+ begin
+ if Tk::Img::package_version != ''
+ filetypes << ['JPEG Files', ['.jpg', '.jpeg']]
+ filetypes << ['PNG Files', '.png']
+ filetypes << ['PostScript Files', '.ps']
+ filetypes << ['PDF Files', '.pdf']
+ filetypes << ['Windows Bitmap Files', '.bmp']
+ filetypes << ['Windows Icon Files', '.ico']
+ filetypes << ['PCX Files', '.pcx']
+ filetypes << ['Pixmap Files', '.pixmap']
+ filetypes << ['SGI Files', '.sgi']
+ filetypes << ['Sun Raster Files', '.sun']
+ filetypes << ['TGA Files', '.tga']
+ filetypes << ['TIFF Files', '.tiff']
+ filetypes << ['XBM Files', '.xbm']
+ filetypes << ['XPM Files', '.xpm']
+ end
+ rescue
+ end
+
+ filetypes << ['ALL Files', '*']
+
+ fpath = Tk.getOpenFile(:filetypes=>filetypes)
+ return if fpath.empty?
+
+ begin
+ canvas.load_photo(fpath)
+ rescue => e
+ Tk.messageBox(:icon=>'error', :type=>'ok',
+ :message=>"Fail to read '#{fpath}'.\n#{e.message}")
+ end
+
+ canvas.fig_erase
+ canvas.reset_region
+
+ fname.value = fpath
+end
+
+# --------------------------------
+def save_memo(canvas, fname)
+ initname = fname.value
+ if initname != '-'
+ initname = File.basename(initname, File.extname(initname))
+ fpath = Tk.getSaveFile(:filetypes=>[ ['Text Files', '.txt'],
+ ['ALL Files', '*'] ],
+ :initialfile=>initname)
+ else
+ fpath = Tk.getSaveFile(:filetypes=>[ ['Text Files', '.txt'],
+ ['ALL Files', '*'] ])
+ end
+ return if fpath.empty?
+
+ begin
+ fid = open(fpath, 'w')
+ rescue => e
+ Tk.messageBox(:icon=>'error', :type=>'ok',
+ :message=>"Fail to open '#{fname.value}'.\n#{e.message}")
+ end
+
+ begin
+ canvas.get_texts.each{|txt|
+ fid.print(txt, "\n")
+ }
+ ensure
+ fid.close
+ end
+end
+
+# --------------------------------
+def ps_print(canvas, fname)
+ initname = fname.value
+ if initname != '-'
+ initname = File.basename(initname, File.extname(initname))
+ fpath = Tk.getSaveFile(:filetypes=>[ ['Postscript Files', '.ps'],
+ ['ALL Files', '*'] ],
+ :initialfile=>initname)
+ else
+ fpath = Tk.getSaveFile(:filetypes=>[ ['Postscript Files', '.ps'],
+ ['ALL Files', '*'] ])
+ end
+ return if fpath.empty?
+
+ bbox = canvas.bbox('all')
+ canvas.postscript(:file=>fpath, :x=>bbox[0], :y=>bbox[1],
+ :width=>bbox[2] - bbox[0], :height=>bbox[3] - bbox[1])
+end
+
+# --------------------------------
+def quit(canvas)
+ ret = Tk.messageBox(:icon=>'warning', :type=>'okcancel',
+ :default=>'cancel',
+ :message=>'Realy quit? ')
+ exit if ret == 'ok'
+end
+
+# --------------------------------
+# setup root
+root = TkRoot.new(:title=>'Fig Memo')
+
+# create canvas frame
+canvas = PhotoCanvas.new(root).pack(:fill=>:both, :expand=>true)
+usage_frame = TkFrame.new(root, :relief=>:ridge, :borderwidth=>2)
+hide_btn = TkButton.new(usage_frame, :text=>'hide usage',
+ :font=>{:size=>8}, :pady=>1,
+ :command=>proc{usage_frame.unpack})
+hide_btn.pack(:anchor=>'e', :padx=>5)
+usage = TkLabel.new(usage_frame, :text=>PhotoCanvas::USAGE,
+ :font=>'Helvetica 8', :justify=>:left).pack
+
+show_usage = proc{
+ usage_frame.pack(:before=>canvas, :fill=>:x, :expand=>true)
+}
+
+fname = TkVariable.new('-')
+f = TkFrame.new(root, :relief=>:sunken, :borderwidth=>1).pack(:fill=>:x)
+label = TkLabel.new(f, :textvariable=>fname,
+ :font=>{:size=>-12, :weight=>:bold},
+ :anchor=>'w').pack(:side=>:left, :fill=>:x, :padx=>10)
+
+# create menu
+mspec = [
+ [ ['File', 0],
+ ['Show Usage', proc{show_usage.call}, 5],
+ '---',
+ ['Open Image File', proc{open_file(canvas, fname)}, 0],
+ ['Save Memo Texts', proc{save_memo(canvas, fname)}, 0],
+ '---',
+ ['Save Postscript', proc{ps_print(canvas, fname)}, 5],
+ '---',
+ ['Quit', proc{quit(canvas)}, 0]
+ ]
+]
+root.add_menubar(mspec)
+
+# manage wm_protocol
+root.protocol(:WM_DELETE_WINDOW){quit(canvas)}
+
+# show usage
+show_usage.call
+
+# --------------------------------
+# start eventloop
+Tk.mainloop
diff --git a/ext/tk/sample/images/teapot.ppm b/ext/tk/sample/images/teapot.ppm
index 78afefbf82..b8ab85f3a5 100644
--- a/ext/tk/sample/images/teapot.ppm
+++ b/ext/tk/sample/images/teapot.ppm
@@ -1,8 +1,7 @@
P6
256 256
255
-\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À[7 eOLjQLmSMoTMnSMlRMhPL_9 \À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀnSMtVMzYN~[N~[N\N\O€\O€]O€]O€]O€]O€\O€\O}[NyYNtVM\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀG-wXN}[N€]O„^O†_O†`O‡`Oˆ`Oˆ`OˆaO‰aO‰aO‰aO‰aO‰aO‰aOˆaOˆ`O†_Oƒ^O\N \À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀaMLyYN…_O‰aP‹bPcPŽcPŽdPŽdPdPdPdPdPdPdPdPeP‘eP’eP’eP‘ePdPcP…_OpUM\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀwXN…_OdP“fP•gQ–hQ˜hQ˜iQ™iQ™iQšiQšiQšjQ›jQ›jQœjQœjQœjQœjQœjQ›jQœjQ™iQ“fP‡`O\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀNCJiQL‹bP—hQkQ¡mR¤nR¥oR¥oR¥oR¥oR¥oR¥oR¦oR¦oR¦pR¨pS©qSªqS«rS¬rS«rS©qS¤oRœjQ€]O\KK\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀfOLrUMcPŸlR©qS¯tS²uTµwT·xT¸xT¹yTºyT»zT»zU¼zU¼zU¼zU»zUºyT¸xT¶wT¯tS¡mR‰aOhPL\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\Àa0 cNLqUM€\O”fQ¦pS²wVºzV¿|VÂ}VÄVÆVÇ€VÉ‚WÌ…[Õeæ w÷³‹êª…Ĉg§qT“fQ{ZNYIK9\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀO1{G#‘JkRMqUMtVN–iS¨v\·€d¹bµzZ±vU°uT®sSªqS¤nRœjQ’eP„^OrUMHh>!T4\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀG-V5wE"~I#†M%U+¥e7²l:°g2®b*­a(­`(©^(¥])¡^-›]1ŠS,qC$`9 R3G-\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À@)J/i>!pA"tD"wF$yH&xH&tE$wE#yG%}M+ƒT4S5mE*Z7!K/B*;'\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À‰aO¦oR½{UÇ€VÏ…X<(F-a: e<!h>!j@#k@$h>"d<!c=$hD-fF2[<)K0@);'5$Ë‚VÇ€V¿|U_LKYIK\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À…_O·xTÉ‚Wó«€ûµ‹Ö’k¼|X×>µf-¨^(¡Z'šW&–T&œN>)F-J/b; g>#nD(jB&c<!b=%jH2_A/I0!<(8&5$”J¥Y’S%8&;'?)E,<:HA=HE?IJAISFJYIKXIK\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À£nRÁ}UܘqÊŠe±vU²e,™V&¥V†C
-€@ |> y< u: r9 o7 l6
+\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À[7 eOLjQLmSMoTMnSMlRMhPL_9 \À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀnSMtVMzYN~[N~[N\N\O€\O€]O€]O€]O€]O€\O€\O}[NyYNtVM\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀG-wXN}[N€]O„^O†_O†`O‡`Oˆ`Oˆ`OˆaO‰aO‰aO‰aO‰aO‰aO‰aOˆaOˆ`O†_Oƒ^O\N \À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀaMLyYN…_O‰aP‹bPcPŽcPŽdPŽdPdPdPdPdPdPdPdPeP‘eP’eP’eP‘ePdPcP…_OpUM\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀwXN…_OdP“fP•gQ–hQ˜hQ˜iQ™iQ™iQšiQšiQšjQ›jQ›jQœjQœjQœjQœjQœjQ›jQœjQ™iQ“fP‡`O\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀNCJiQL‹bP—hQkQ¡mR¤nR¥oR¥oR¥oR¥oR¥oR¥oR¦oR¦oR¦pR¨pS©qSªqS«rS¬rS«rS©qS¤oRœjQ€]O\KK\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀfOLrUMcPŸlR©qS¯tS²uTµwT·xT¸xT¹yTºyT»zT»zU¼zU¼zU¼zU»zUºyT¸xT¶wT¯tS¡mR‰aOhPL\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\Àa0 cNLqUM€\O”fQ¦pS²wVºzV¿|VÂ}VÄVÆVÇ€VÉ‚WÌ…[Õeæ w÷³‹êª…Ĉg§qT“fQ{ZNYIK9\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀO1{G#‘JkRMqUMtVN–iS¨v\·€d¹bµzZ±vU°uT®sSªqS¤nRœjQ’eP„^OrUMHh>!T4\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀG-V5wE"~I#†M%U+¥e7²l:°g2®b*­a(­`(©^(¥])¡^-›]1ŠS,qC$`9 R3G-\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À@)J/i>!pA"tD"wF$yH&xH&tE$wE#yG%}M+ƒT4S5mE*Z7!K/B*;'\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À‰aO¦oR½{UÇ€VÏ…X<(F-a: e<!h>!j@#k@$h>"d<!c=$hD-fF2[<)K0@);'5$Ë‚VÇ€V¿|U_LKYIK\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À…_O·xTÉ‚Wó«€ûµ‹Ö’k¼|X×>µf-¨^(¡Z'šW&–T&œN>)F-J/b; g>#nD(jB&c<!b=%jH2_A/I0!<(8&5$”J¥Y’S%8&;'?)E,<:HA=HE?IJAISFJYIKXIK\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À£nRÁ}UܘqÊŠe±vU²e,™V&¥V†C €@ |> y< u: r9 o7 l6
j5
h4
g3
@@ -13,44 +12,20 @@ f3
a0 _/ ]. [- I¡\*ª_(‘LkRMmSMmSMnSMnSMD,R3W5mA"|O0|P1j?"c<!a=%Y7"N1F,;'NCJNCJNDJODJODJODJh>!a: X/K%
g3
a0 Z- \/ T*Q(ŠHµm8kRMmSMnTMoTMpTMpUM15G15G05G04G04GpUMpTM5^9 d<!yF#O+€N,rC#qB"pB#k?"a: Z7 6ODJPDJPEJQEJQEJREJREJREJRFJSFJSFJSFJSFJe<!X/
-^/ V+Q(L&I$r9  TlRMnSM46G47G47G46G46G46G46G46G36G36G25G25G15G04G/4F.3F
-ˆ`O~[NqUM[- ‰HUGJUGJVGJVGJVHJWHJWHJWHKWHKXHKXHKXHKXHKXHKXIKXIKXIKXIKXIKh>!Y0
-
-L&C!:4
+^/ V+Q(L&I$r9  TlRMnSM46G47G47G46G46G46G46G46G36G36G25G25G15G04G/4F.3F
+
X&pUMuWMwXNxXN<:H<:H<:H<:H<;H<;H<;H<;H=;H=;H=;H=;H>;H>;H?<H@<HA=HC>HG@ILBIREJ[JKcNLjQL§pR±uTºzUÃ~VÈWË‚XÖŽcäsÒŽe¼{V²vT¨pSžkR•gQŒbP†_O‚^O]O€\O€\O€\O€\O€]O]O]O]O]O]O]O]O]O]O]O€\O€\O~\N}[N|ZNxXN•T%H$
-›W&rVMvWNyYNzYN|ZN}[N}[N><H?<H?<H?<H?<H?<H@<H@<H@<HA=HA=HB=HC>HE?IG@IIAIKBIODJSFJWHK—hQŸlR§pR°b(¾i*Én+Ù|7Û|6Ïr,Íq+Êp-Ãl+»g)±b(®sS§pS lRšiQ•gQePcPŠaPˆaO‡`O‡`O†_O†_O…_O…_O…_O…_O…_O…_O…_O„_O„^O„^Oƒ^Oƒ^O‚]O]O€\O~[N{ZN•T%
-
-
+›W&rVMvWNyYNzYN|ZN}[N}[N><H?<H?<H?<H?<H?<H@<H@<H@<HA=HA=HB=HC>HE?IG@IIAIKBIODJSFJWHK—hQŸlR§pR°b(¾i*Én+Ù|7Û|6Ïr,Íq+Êp-Ãl+»g)±b(®sS§pS lRšiQ•gQePcPŠaPˆaO‡`O‡`O†_O†_O…_O…_O…_O…_O…_O…_O…_O„_O„^O„^Oƒ^Oƒ^O‚]O]O€\O~[N{ZN•T%
 
@%<-$G?@…pfdNLuWM\NdNL\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀTFJvWN‰aP./01„E}[N]O…_Oˆ`O‰aP‹bPŒbPcPcPŽcPdPdPdPeP‘eP’eP’eP“fP“fQ”fQ•gQ•gQ–gQ–hQ—hQ˜hQ™iQšiQ›jQœjQkQkRžlRŸlRžY&¤\'¨^'µ^½bÀcÃeÇi ÄgÀc½b¼a¹`µ^´]¯X¢[' Z'žY&¢mR¡mR¡mR lRŸlRŸlRžkRkQœkQœjQ›jQšjQšiQ™iQ™iQ˜iQ˜hQ—hQ—hQ—hQ–gQ–gQ•gQ•gQ•gQ”fQ”fQ“fQ“fP’eP‘ePdPcP‰aP—O
 B\À\À\À\À\À\À\À\À\À\À%7!!C*F#P) {dYœze»p€\OgPL\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀSFJ`LKvWNŠaPm6
- 
-\À\À\À\À\À\À\À\À\À B B
-$5 ¬`(¶e)£nRœjQƒ^OJAI\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀXIK^KKdNLhPLuWM‚]OŒbP”fQeP
-m6
-†`OŽcP“fQ—hQ˜hQ™iQšiQšjQ›jQ›jQ›jQœjQœjQœjQœkQkQkQkRžkRžkRžkRžlRŸlRŸlRŸlR lR lR lR¡mR¡mR¡mR¡mRºg)³c(²c(±b(­V¿cÂeÅi!Åi!Àd¼bº`¹`·_·_¶^¢Q§]'ª_(­`(¹f)£nR£nR£nR£nR£nR£nR£nR¢nR¢nR¢nR¢nR¢nR¢nR¢mR¢mR¢mR¢mR¢mR¢mR¢mR¢mR¢mR¢nR¢mR¢mR£nR¢mR¢mR¡mR mRkR—hQˆGa0 ŠbP mRœjQ“fQ‰aP}[NrUMmSM…L$\À\À\À\À\À\À\À\À B B
-#C, 8&H.Z7 §pR›jQ{ZN\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀQEJ[JK`LKdNLhQLqUM{ZN…_OŽcP–gQ—hQ
-‹bP‘eP–hQšiQ›jQœjQkQkQkRžkRžkRžlRžlRŸlRŸlRŸlRŸlRŸlR lR lR lR mR¡mR¡mR¡mR¡mR¡mR¢mR¢mR¢mR¢nR£nRÀj*ºg)·e)¶d)Âd°XÅgÅhÂe¿c½b½b¾bªU­`(®a(¯a(³c(¾i*¤oR¤oR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤oR¤oR¥oR¥oR¥oR¥oR¥oR¥oR¦oR¦oR¥oR¥oR¤nR¡mR›jQŽQ%Z- œjQ£nRŸlR—hQŽdP…_OuWMpTMnSMkRLa: \À\À\À\À\À\À\À B B&D2
-@*S6#G@IPDJ˜hQmSM\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀVGJ]KKbMLeOLiQLlRMvWN\OˆaO‘eP—hQœjQ•gQ
-\À\À\À\À\À B'D+E$(1 J/jH1NCJUGJYIKUGJ\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀXHK]KKbNLfOLiQLkRMmSMoTMqUMxXN\N†_OŒbP’fP˜hQkQ¡mR¥oR§pS¦pR˜hQ¢mR¥oR¨pSªqS«rS«rS«rS«rS«rS«rS«rS«rS«rS«rS«rSªrSªrSªrS«rS«rS«rS«rS«rS«rS«rS«rS«rS«rS«rS«rS«rS«rS«rS«rS¬rS¬rS¬rS¬rS¬rS¬rS¬rS¬sS¬sS­sS­sS­sS­sS­sS­sS®sS®sS®sS®sS®tS¯tS°tS°uS±uS±uT±uT²uT²uT²uT´vTµwT´vT³vT²uT¯tS¢mR¯tS±uT±uS®tS«rS§pR¢mRkQ—hQ‘ePŠaPƒ^O\N{ZNvXNqUMpTMnSMlRMP%\À\À\À\À B#C*E$.E- .!G$Y:%d<"SFJYIKZIKNCJ\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀPDJZIK_LKdNLgPLjQLlRMnSMpTMqUMuWMyYN€\O†`OcP’fP—hQœjQ¡mR¥oR¨qS«rS«rSªrS mR
+ 
+$5 ¬`(¶e)£nRœjQƒ^OJAI\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀXIK^KKdNLhPLuWM‚]OŒbP”fQeP m6
+†`OŽcP“fQ—hQ˜hQ™iQšiQšjQ›jQ›jQ›jQœjQœjQœjQœkQkQkQkRžkRžkRžkRžlRŸlRŸlRŸlR lR lR lR¡mR¡mR¡mR¡mRºg)³c(²c(±b(­V¿cÂeÅi!Åi!Àd¼bº`¹`·_·_¶^¢Q§]'ª_(­`(¹f)£nR£nR£nR£nR£nR£nR£nR¢nR¢nR¢nR¢nR¢nR¢nR¢mR¢mR¢mR¢mR¢mR¢mR¢mR¢mR¢mR¢nR¢mR¢mR£nR¢mR¢mR¡mR mRkR—hQˆGa0 ŠbP mRœjQ“fQ‰aP}[NrUMmSM…L$\À\À\À\À\À\À\À\À B B #C, 8&H.Z7 §pR›jQ{ZN\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀQEJ[JK`LKdNLhQLqUM{ZN…_OŽcP–gQ—hQ
+‹bP‘eP–hQšiQ›jQœjQkQkQkRžkRžkRžlRžlRŸlRŸlRŸlRŸlRŸlR lR lR lR mR¡mR¡mR¡mR¡mR¡mR¢mR¢mR¢mR¢nR£nRÀj*ºg)·e)¶d)Âd°XÅgÅhÂe¿c½b½b¾bªU­`(®a(¯a(³c(¾i*¤oR¤oR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤oR¤oR¥oR¥oR¥oR¥oR¥oR¥oR¦oR¦oR¥oR¥oR¤nR¡mR›jQŽQ%Z- œjQ£nRŸlR—hQŽdP…_OuWMpTMnSMkRLa: \À\À\À\À\À\À\À B B&D2 @*S6#G@IPDJ˜hQmSM\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀVGJ]KKbMLeOLiQLlRMvWN\OˆaO‘eP—hQœjQ•gQ
!C+E'0F.4F7%8%U/lG.SFJZIK]KKZIKB=H\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀREJZJK`LKdNLgPLjQLlRMnSMpTMqUMtWMxXN{ZN~[N]O„^O†`O‰aO‹bPdP•gQ™iQœkQ lR¤nR§pSªrS­sS¯tT²uT´vT¶wT·xT¹yT¹yTºyTºyT¹yT¶xT´vT¬rS¢nR—hQ¿|U¿|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ}UÀ}UÁ}UÁ}UÁ}UÁ}UÂ}UÂ~UÃ~UÃ~VÃ~VÄVÅ€WÆX®a(ŸlRªrS´vT¸yT¼zU¾|UÁ~VÃXÆ‚[Ɇ_΋dÓ‘jÔ“mÔ“nБlÊŒhĆd½_¶{[°vWªsU¦pS¢nRžkRšiQ˜hQ•gQ“fQ‘ePdPŒbP‰aO†_Oƒ^O€\O|ZNxXNsVMpTMnTMmSMjQL€C B)D&/F-3F47G6%>" Y7 kA$YIK]KK^KKSFJ\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀVGJ\KKbMLeOLhPLkRLmSMnTMpTMrUMuWNyYN|ZN\N‚]O„_O‡`OŠaPŒbPŽcPeP“fP—hQ›jQžlR¢nR¥oS©qT¬sT¯uU²vU´wV¶xV¸yV¹yUºzU»zU¼{U½{U¾{U¾|U¿|U¿|U¿|U¿|U¾{U½{U¼{U¼zU»zTºyT¹yT¸xTµwT³vT´vT´vT´vT´wT´wTµwT·xT¹yTºzT¼zU½{U¾{U¿|UÀ|UÂ}UÄVÅ€WÇ‚YÉ„\͈_ÑŒdÙ”láuç£|쩂ſt명æ¦ÞŸ{Õ—sËŽl†d¹^³yZ­uW¨qU¤oSŸlRžkRœjQšiQ˜hQ–gQ”fQ‘ePdPcPŠaP‡`O„^O]O}[NyYNuWMpTMoTMmSMkRLgPL&D#.E,3F46G;'<(D"iB(VGJ]KK`LK[JKB>H\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀNCJYIK^LKcNLfOLiQLkRMmSMoTMqUMsVMvXNzYN}[N€\O‚^O…_Oˆ`OŠaPŒcPdP‘eP“fQ•gQ—hQ™iQkR mS¤oT¨rU¬tW°wY´zZ¸}\»]¾€^À^Á‚^‚^Â\Á€ZÁYÁXÁ~WÁ~WÂ~VÂ~VÂ~VÃ~VÃ~UÃ~UÄ~UÄ~UÄUÄUÅVÅVÅVÅVÆVÆ€VÆ€VÇ€WÇWÈ‚XɃZË…[͇^ЊaÓdØ’iÜ—nâtè£zî©ó¯‡ø´û¸‘üº“û¹“÷¶ñ±Œé©…à¡~Ö˜vËmÇf»€`´z[®vX©rU¥pT£oS¢nS lRžkRœkRšjQ˜iQ–hQ”fQ’ePdPcP‹bPˆ`O…_O‚]O~[NzYNvWNpTMoTMnSMkRMhQLo7 ,2F36G99HC+@ ]8 nA"\JK`ML_LKSFJ\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀSFJ[JK`LKdNLgPLjQLlRMnSMpTMqUMtVMwXNzZN}[N€]Oƒ^O†_OˆaO‹bPcPdP‘eP“fQ•gQ—hQ™iQ›jRžlR mS£oU§rW¬vZ²{]¹€a¿…fÅŠjËnГqÓ•sÕ–sÕ–rÕ–qÕ”oÓ’mÑjÏgÍŠcˈaɆ^È„\Ç‚[ÆYÅ€XÅ€WÅWÅWÅVÅVÅWÅ€WÆ€WÇXÈ‚YɃ[Ê…\͇_ÏŠaÒeÕ‘hÙ•mÝ™qávä¡zç¤}꧀멃몄騃奀ߠ|Ù›wÓ•rÌmƉh¿„c¸~^²yZ®vX¬tWªsV¨qU¦pT¤oS¢nS mRžlRœkR›jQ™iQ—hQ•gQ“fPePŽcP‹bPˆaO…_O‚^O\N{ZNwXNsVMoTMnSMlRMiQL~I#26G99G?<HA*E$ i@$ZIKaMLbML[JK;:H\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀWHJ]KKbMLeOLhPLjRLlSMnTMpTMrUMuWMxXN{ZN~\N]O„^O†`O‰aO‹bPŽcPdP’eP”fQ–gQ˜hQšiQœkRžlS mT£oU¦rWªuZ¯y]´~aºƒfŠlË’sÔšzÜ¡€ã§†è«‰ë®‹í¯Œí®‹ë¬ˆè¨„ã£~ßžyÚ™tÖ•oÒjÎŒfˈbÈ…_ƃ\ÅZÄ€YÃXÂWÂ~WÂ~WÂ~WÃXÀXÄ€YÅZƃ\Ç…^Ɇ`ˈbÌŠdÍ‹fÎgÎŽiÎŽjÎŽjÍŽjËŒiljgÆd¿ƒaº^¸}]¶|\´{[²yZ°xY®vX¬tWªsV¨qU¦pT¤oS¢nS mRžlRkR›jQ™iQ—hQ•gQ“fP‘ePŽdPŒbP‰aO†_Oƒ^O€\O|ZNxXNtVMpTMnSMmSMjQLgPL99G?<HG-E&b;!YIK`MLdOM`LKNCJ\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀŸlRºyTÄ~UÊ‚XʃYÄXº{W­tUšW'¢[(—hQ lRcP€\OhQL\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀNCJYIK^LKcNLfOLiQLkRLmSMoTMqUMrVMvWNyYN|ZN\N‚]O„_O‡`O‰aPŒbPŽcPdP’fP”gQ–hQ˜iQšjRœkRžlS¡nT¤pU§sW«vZ°z]µb»„gŠlÉ‘sИyØžÞ¤…㩊è­ì±ï³‘ﳑ뭊穅⣀ݞzؘtÒ“nÎiɉdÆ…`Â]Á€[¿~Y¾}X½|W½|V¼{V¼{V¼{V¼{V¼{V¼|W¼|W½}X½}Y½~Z½~Z¼~Z»}[º}[º}[º~\º~\º~]º~]¹~]¸~]·}]¶|\´z[²yZ°wY®vX¬tWªsV¨rU¦pT¤oS¢nS mRŸlRkR›jQšiQ˜hQ–gQ“fQ‘ePdPŒcPŠaP‡`O„^O]O}[NyYNuWNpTMnTMmSMkRLhPL|H$D>IQ2P+XHK_LLfQOcNLXIK\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À©qSºyTÃ~VΈ`遲ޜv¾€]ªqS–LŽG|> g3
-S)?*%.—hQ—hQ‘eP‡`OuWM\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀSFJ[JK`LKdNLgPLjQLlRMnSMoTMqUMsVMwXNzYN}[N€\O‚^O…_O‡`OŠaPŒbPŽdP‘eP“fP•gQ—hQ˜iQšjRœkRŸlS¡nT¤pV§sX«vZ°z^¶b¼…gËmÊ’sјzØŸ€Þ¤…㩊è­ê¯ë°ê¯Žè¬‹å¨‡à¤‚Ûž|Ö™wÑ“qÌŽlljgÃ…bÀ‚_½\»}Zº{X¹zW¸yV·yU·xU·xU·xT·xT·xU·xU·xU·yV·yV·yW¸zW¸{X¹{Y¹|Zº}[º}[º}\º~\¹~]¹~]¸}]·|\µ{\´z[²yZ°wY®vX¬tWªsV¨rU¦pT¤oS¢nS¡mRŸlRkRœjQšiQ˜hQ–gQ”fQ’ePdPcPŠbP‡`O…_O‚]O~[NzZNvWNrUMoTMmSMlRMiQLeOLJAIJ(h>!]KKfQOgQN_LKD>I\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À™iQ°tS¸yT¼{UÂYÎŒeï­ˆô´Õ—u¶|\ Z'™LˆD
-|>
-
-+,!.! "`E6†iYŒlZo\“q]•s^^J™va›wbycŸzd {e¤}foTMqUMsVMuWNwXNyYN{ZN|ZN~[N\O]O‚]Oƒ^O…_O†_O‡`Oˆ`O‰aOŠaP‹bPŒbPŒcPcPŽcPŽdPdPdPdPeP‘eP‘eP‘eP’eP’eP’eP’eP’fP’fP’fP“fP’fP’fP’fP’eP’eP’eP‘eP‘eP‘ePePdPdPdPŽdPŽcPcPŒcPŒbP‹bPŠaP‰aOˆ`O‡`O†_O…_Oƒ^O‚]O]O\O~[N|[N{ZNyYNwXN®ƒi¬ƒiª‚i¨i¦€hŒhR‰fQ†dQ‚bP•wfx]Oˆpdkbtd_m`]OEDG?A;:@.S….S….S….S….S…/S…/S…/S…/S…/S…/S…/S…/S…TxªTxªTxªTxªTxªTx«Tx«Tx«Ty«/S†GlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlž…ªÜ…ªÜ…ªÜHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlž…ªÜ…ªÜ£Ö£Ö£Ö£Ö¤Ö¤Ö¤Ö¤Ö¤ÖEi›€¤Ö€¤Ö€¤Ö€¤Ö€¤Ö€¤Ö€¤Ö€¤Ö€¤Ö€¤Ö€¤Ö€¤Ö€¤×€¤×€¤×€¤×€¥×€¥×€¥×Bg™Bg™Bg™Bg™Bg™&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜Af˜Af˜%J|%J|%J|%J|%J|%J|%J|%J|%J|%J|%I|%I|%I|%I|%I|%I|
-+,YA5jPBpSD‹l[o]’q^–t`‚_Kšwbœycžze {f¡}g¤h¨i”lSrVMtWMvWNxXNyYN{ZN|[N~[N\O]O‚]Oƒ^O„_O…_O†`O‡`Oˆ`O‰aPŠaP‹bP‹bPŒbPcPcPŽcPŽcPdPdPdPdPdPdPdPdPePePePePePdPdPdPdPdPdPdPŽcPŽcPcPcPŒbP‹bP‹bPŠaP‰aOˆ`O‡`O†`O…_O„^Oƒ^O‚]O€]O\O~[N|[N{ZNyYNxXN°…j®„j¬„jªƒj¨‚j¦€jŒhSŠgS†eRƒcR|`QŒsf…oe}jcrd`k_]LCDC=@,,3(4F(4F.S….S…/S…/S…/S…/S…/S…/S…/S…TxªTxªTxªTxªTxªTxªTx«Tx«Tx«Ty«Ty«Ty«…ªÜHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlž†ªÜHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžChšChš¤Ö€¤Ö€¤Ö€¤Ö€¤ÖEi›Ei›Ei›€¤Ö€¤Ö€¤Ö€¤Ö€¤Ö€¤Ö€¤×€¤×€¤×€¤×Cg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™Bg™Bg™&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜&J|%J|%J|%J|%J|%J|%J|%J|%J|%J|%J|%J|%I|%I|%I|%I|%I|#5H71O;3V?4iOBoSDsVFo]{[I^Kƒ`L…bN‡dOŸ{f }g¢~h¥€j’kT•mU˜oVšqWrWwXNxXNzYN{ZN}[N~[N\O€]O‚]Oƒ^O„^O…_O…_O†`O‡`Oˆ`O‰aO‰aPŠaP‹bP‹bPŒbPŒbPŒcPcPcPcPŽcPŽcPŽcPŽcPŽcPŽcPŽcPŽcPŽcPŽcPcPcPcPŒcPŒbP‹bP‹bP‹bPŠaP‰aP‰aOˆ`O‡`O†_O…_O„_O„^Oƒ^O]O€\O\N~[N|ZN{ZNyYN›oTšoT™oT—nT¬„lªƒl¨‚ljUŒiTŠhT†fT€cSvi‰rgnfyidqdah^^HBD?<@)+3OZkMYk(5F(5F(5F/S…/S…/S…/S…/S…TxªTxªTxªTxªTxªTxªTx«Tx«Ty«Ty«Ty«Ty«Uy«†ªÜ†ªÜ†ªÜ†ªÜHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlž†ªÜ†ªÜ†ªÜ†ªÜ†ªÜHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžHlžDhšDhšDhšChš&K}&K}&K}&K}&K}&K}ChšChšCgšCgšCgšCgšCgšCgšCg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™&J|&J|&J|&J|&J|&J|Bg™Bg™Bg™Bf™Bf™Bf™Bf™Bf™Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜&J|&J|&J|&J|%J|%J|%J|%J|%J|%J|%J|%J|%J|%J|%J|%I|%I|A99N?;L:2T>4gNBlRD‡k\‹n^z[J~^LaN…cO‡dP‰fQŠgRŒhTjU’lV•nW˜pXšrXsY¶‹q¸qºŽr¼r½r¿s©z[©z[ªz[«{[¬{[¬{ZÅ“rÅ’qÅ’qÅ’pÅ’pÅ‘o­yV­xV¬xU¬wT¬wTŠaPŠbP‹bP‹bP‹bP‹bP‹bP‹bP‹bP‹bP‹bP‹bP‹bP‹bPŠaPŠaPŠaP‰aP‰aOˆaOˆ`O‡`O‡`O†_O…_O„^Oƒ^O‚^O‚]O]O€\O~\N}[N|ZNzYNpTœpU›pUšpU˜oV—oV•nV“mV‘lVkVŒjVˆhVƒfU~cUuj†qh~mfugdkaad\^E@D98?$(2minffm^blV^lMYk(5F(5F/S…TxªTxªTxªTxªTxªTxªTxªTx«Tx«Ty«Ty«Ty«Uy«Uy«†ªÜ†ªÜ†ªÜ†ªÜ†ªÜ†ªÜ†ªÜ†ªÜHlžHlžHlžHlžHlŸHlŸHlŸHlŸHlŸHlŸHlŸHlŸHlŸHlŸHlŸ†ªÝ†ªÝ†ªÝ†ªÝ†ªÝ†ªÝ†ªÝ†ªÝ†ªÝ†ªÝHlŸHlŸHlŸHlŸHlŸHlŸHlŸHlŸHlŸHlŸHlŸHlŸHlŸHlŸHlŸHlŸHlŸHlŸHlŸHlŸHlŸ'K}'K}'K}'K}'K}'K}'K}'K}'K}&K}&K}ChšChšChšChšChšChšChšCgšCgšCgšCgšCgšCgšCg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™&J|Cg™Cg™Cg™Cg™Cg™Bg™Bg™Bg™Bg™Bg™Bg™Bf™Bf™Bf™Bf™Bf™Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜Bf˜&J|&J|&J|&J|&J|&J|&J|%J|%J|%J|%J|%J|%J|%J|Ae˜Ae˜;GY<68I=:I82Q=4XA6~fZ„j\‰m^p`|]L€`NƒcP†eQˆgS¡j£€l¦‚m©„n•oX˜qYšrZt[¶Œr¸sºs¼t½t¾‘t¨z]©{]ª{]«{\«{\¬{\¬{[Ä“sÄ“rÄ’rÄ’qÄ’pÄ‘p¬yWÄoÃnÃmÃlÂŽlÂŽkÁkˆaOˆaOˆaOˆaOˆaOˆaOˆaOˆ`Oˆ`O‡`O‡`O‡`O†`O†_O…_O…_O„_O„^Oƒ^O‚]O]O€]O\O~\N}[N|ZN¶‰l¶‰lµˆmœqV›qVšqV™pW˜pW–oW¬…nª…n§„n¤‚nŸ€n›~n€eW‘xlŠtk‚piykfodcf_`JDG@>C*,5$1MYktr~tstmolinadmX_lNZkMZkTxªTxªTxªTxªTx«Tx«Tx«Ty«Ty«Ty«Uy«Uy«Uy«†ªÝ†ªÝ†ªÝ†ªÝ†ªÝ†ªÝ†«Ý†«Ý†«Ý†«ÝHlŸHlŸHmŸHmŸHmŸHmŸHmŸHmŸHmŸHmŸHmŸHmŸ†«Ý†«Ý†«Ý‡«Ý‡«Ý‡«Ý‡«Ý‡«Ý‡«Ý‡«Ý‡«Ý‡«Ý‡«ÝHmŸHmŸHmŸHmŸHmŸHmŸHmŸHmŸHmŸHmŸHmŸHmŸHmŸHmŸHmŸHmŸHmŸHmŸHmŸHmŸ'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}'K}DhšDhšDhšDhšChšChšChšChšChšChšChšCgšCgšCgšCgšCgšCgšCg™Cg™Cg™Cg™Cg™&J}&J}&J}Cg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™Cg™Bg™Bg™Bg™Bg™Bg™Bg™Bf™Bf™Bf™Bf™Bf˜Bf˜Bf˜Bf˜Bf˜&J|&J|&J|&J|&J|&J|&J|&J|&J|&J|Af˜Af˜Af˜Af˜;GY;GY;GY1'!D:9N?;N;3]I?zdY€h[†l^‹oasc“ue€bQ„dR‡fT l¢m¦ƒn©…o«‡p®ˆq±Šr³‹sžv] w]¹u»u¼‘u¾‘u¿’v¨{^©{^ª|^«|]«|]«{\¬{\¬{[¬{[¬zZ«zZ«yY«yX«xXÂoÂnÂnÁŽmÁŽm¨uT¨uS§tS§tS§tR¦sR¦sQ…_O…_O…_O„^O„^Oƒ^Oƒ^O‚^O‚]O]O€]O¢rS¡rS¡rS¸‰k·‰l·‰l¶‰m¶‰mµ‰m´‰n³‰n›qWšqX™qX®‡o­‡o«†p¨…p¤ƒp pœp—}o{cXv`Vp]U}nishfhaba\_DAF::B$)4
-., 7(8'A1&F4(L8*oXIw]Jpdasfcvhexkg{mi~oj€qll\Xn^Yp`Zpa[qa\rb]rc^sc^sd_ue`wf`xgayhayhayhbxy‘y‘y‘y‘yy~ywgbvfateasd`qd`pc`nb_la_€ut|ssxqrunpZUXVRWROUMMSHIRIC@967-/3'+0(*-ACF?AD;=@#%(
-.+>1(B3)B2&F4'E4)gTGlXJs^OzcTzaPqfethgvjhbVTcWUdXVeYWfZXg[Yh\Zi]Zi][j^\€us€ususts~tt~tt}tt|st{stut~tt|sszrsyqrwpquoqsmpqloXTXTQWPOULLSSJEA<:=99757335./2113)+.'),)+.8:="(
-"6*#5*">2)>0&A2'C3(I8-^OFbRHfUJjXMq^RwcVzfYfRDfQCdN@zdTqijrjksklrklrklrklqjmpjmpjmojmojmnimmimkhliflscYm`Xg\VbYT^VRE>;A<:>98:77645:873220/0,-/)+.*,/#%( &
-
-&3#.$-% .% .& /&!,#,#@70A71XNHXNHWNHWNHZRLYQLYQLXQLWQLWPLUOLSNLQMKOLJMJJ0//.-.,,-&(+"(!'
-
- %' %$#" ! !$
-
-
- 
-
-
-*  
-  ;?E7CU;HY=I[ 
+S)?*%.—hQ—hQ‘eP‡`OuWM\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀSFJ[JK`LKdNLgPLjQLlRMnSMoTMqUMsVMwXNzYN}[N€\O‚^O…_O‡`OŠaPŒbPŽdP‘eP“fP•gQ—hQ˜iQšjRœkRŸlS¡nT¤pV§sX«vZ°z^¶b¼…gËmÊ’sјzØŸ€Þ¤…㩊è­ê¯ë°ê¯Žè¬‹å¨‡à¤‚Ûž|Ö™wÑ“qÌŽlljgÃ…bÀ‚_½\»}Zº{X¹zW¸yV·yU·xU·xU·xT·xT·xU·xU·xU·yV·yV·yW¸zW¸{X¹{Y¹|Zº}[º}[º}\º~\¹~]¹~]¸}]·|\µ{\´z[²yZ°wY®vX¬tWªsV¨rU¦pT¤oS¢nS¡mRŸlRkRœjQšiQ˜hQ–gQ”fQ’ePdPcPŠbP‡`O…_O‚]O~[NzZNvWNrUMoTMmSMlRMiQLeOLJAIJ(h>!]KKfQOgQN_LKD>I\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À™iQ°tS¸yT¼{UÂYÎŒeï­ˆô´Õ—u¶|\ Z'™LˆD |>
+
+ &3#.$-% .% .& /&!,#,#@70A71XNHXNHWNHWNHZRLYQLYQLXQLWQLWPLUOLSNLQMKOLJMJJ0//.-.,,-&(+"(!'
+ %' %$#" ! !$ 
diff --git a/ext/tk/sample/irbtkw.rbw b/ext/tk/sample/irbtkw.rbw
new file mode 100644
index 0000000000..3fb6dde626
--- /dev/null
+++ b/ext/tk/sample/irbtkw.rbw
@@ -0,0 +1,146 @@
+#!/usr/bin/env ruby
+#
+# irbtkw.rb : IRB console with Ruby/Tk
+#
+# by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)
+#
+release = '2008/03/08'
+
+require 'tk'
+begin
+ require 'tktextio'
+rescue LoadError
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'tktextio.rb')
+end
+
+require 'irb'
+
+if TkCore::WITH_ENCODING
+else
+ # $KCODE setup
+ case Tk.encoding
+ when 'shiftjis', 'cp932'
+ $KCODE='SJIS'
+ when 'euc-jp'
+ $KCODE='EUC'
+ when 'utf-8', 'unicode'
+ $KCODE='UTF8'
+ else
+ # unknown
+ end
+end
+
+# console setup
+top = TkToplevel.new(:title=>'IRB console')
+top.protocol(:WM_DELETE_WINDOW){ Tk.exit }
+
+case (Tk.windowingsystem)
+when 'win32'
+ fnt = ['MS Gothic', '-12']
+else
+ fnt = ['courier', '-12']
+end
+
+console = TkTextIO.new(top, :mode=>:console,
+ :width=>80).pack(:side=>:left,
+ :expand=>true, :fill=>:both)
+console.yscrollbar(TkScrollbar.new(top, :width=>10).pack(:before=>console,
+ :side=>:right,
+ :expand=>false,
+ :fill=>:y))
+irb_thread = nil
+ev_loop = Thread.new{
+ Tk.mainloop
+ irb_thread.kill if irb_thread
+}
+
+# window position control
+root = Tk.root
+
+r_x = root.winfo_rootx
+r_y = root.winfo_rooty
+r_w = root.winfo_width
+
+t_x = top.winfo_rootx
+t_y = top.winfo_rooty
+t_w = top.winfo_width
+
+delta = 10
+
+ratio = 0.8
+s_w = (ratio * root.winfo_screenwidth).to_i
+
+if r_x < t_x
+ r_x, t_x = t_x, r_x
+end
+if t_x + t_w + r_w + delta < s_w
+ r_x = t_x + t_w + delta
+elsif t_w + r_w + delta < s_w
+ r_x = s_w - r_w
+ t_x = r_x - t_w
+else
+ r_x = s_w - r_w
+ t_x = 0
+end
+
+root.geometry("+#{r_x}+#{r_y}")
+top.geometry("+#{t_x}+#{t_y}")
+
+root.raise
+console.focus
+
+# I/O setup
+$stdin = console
+$stdout = console
+$stderr = console
+
+# dummy for rubyw.exe on Windows
+def STDIN.tty?
+ true
+end
+
+# IRB setup
+IRB.init_config(nil)
+IRB.conf[:USE_READLINE] = false
+IRB.init_error
+irb = IRB::Irb.new
+IRB.conf[:MAIN_CONTEXT] = irb.context
+
+class IRB::StdioInputMethod
+ def gets
+ prompt = "\n" << @prompt
+ $stdin.instance_eval{
+ flush
+ @prompt = prompt
+ _set_console_line
+ @prompt = nil
+ _see_pos
+ }
+
+ @line[@line_no += 1] = $stdin.gets
+ end
+end
+
+# IRB start
+$stdout.print("*** IRB console on Ruby/Tk (#{release}) ")
+irb_thread = Thread.new{
+ catch(:IRB_EXIT){
+ loop {
+ begin
+ irb.eval_input
+ rescue Exception
+ end
+ }
+ }
+}
+
+console.bind('Control-c'){
+ console.insert('end', "^C\n")
+ irb_thread.raise RubyLex::TerminateLineInput
+}
+
+irb_thread.join
+
+# exit
+ev_thread.kill
+Tk.exit
diff --git a/ext/tk/sample/tcltklib/sample2.rb b/ext/tk/sample/tcltklib/sample2.rb
index 444bb1eef7..110e81ebc4 100644
--- a/ext/tk/sample/tcltklib/sample2.rb
+++ b/ext/tk/sample/tcltklib/sample2.rb
@@ -41,7 +41,7 @@ class Othello
[ 1, -1], [ 1, 0], [ 1, 1]
]
- attr :com_disk, TRUE
+ attr_accessor :com_disk
def initialize(othello)
@othello = othello
diff --git a/ext/tk/sample/tkextlib/tile/demo.rb b/ext/tk/sample/tkextlib/tile/demo.rb
index b604410da4..633a072460 100644
--- a/ext/tk/sample/tkextlib/tile/demo.rb
+++ b/ext/tk/sample/tkextlib/tile/demo.rb
@@ -20,6 +20,14 @@ def version?(ver)
TkPackage.vcompare(Tk::Tile.package_version, ver) >= 0
end
+# define Tcl/Tk procedures for compatibility
+Tk::Tile.__define_LoadImages_proc_for_compatibility__!
+Tk::Tile::Style.__define_wrapper_proc_for_compatibility__!
+
+unless Tk::Tile::Style.theme_names.include?('step')
+ Tk::Tile::Style.theme_create('step')
+end
+
Tk.load_tclscript(File.join(demodir, 'toolbutton.tcl'))
Tk.load_tclscript(File.join(demodir, 'repeater.tcl'))
@@ -55,7 +63,7 @@ $V = TkVariable.new_hash(:THEME => 'default',
:CHOICE => 2)
# Add in any available loadable themes.
-TkPackage.names.find_all{|n| n =~ /^tile::theme::/}.each{|pkg|
+TkPackage.names.find_all{|n| n =~ /^(tile|ttk)::theme::/}.each{|pkg|
name = pkg.split('::')[-1]
unless $THEMELIST.assoc(name)
$THEMELIST << [name, Tk.tk_call('string', 'totitle', name)]
@@ -66,7 +74,8 @@ TkPackage.names.find_all{|n| n =~ /^tile::theme::/}.each{|pkg|
$RUBY_THEMELIST = []
begin
load(File.join(demodir, 'themes', 'kroc.rb'), true)
-rescue
+rescue => e
+raise e
$RUBY_THEMELIST << ['kroc-rb', 'Kroc (by Ruby)', false]
else
$RUBY_THEMELIST << ['kroc-rb', 'Kroc (by Ruby)', true]
@@ -79,8 +88,8 @@ def makeThemeControl(parent)
:variable=>$V.ref(:THEME),
:command=>proc{setTheme(theme)})
b.grid(:sticky=>:ew)
- unless (TkPackage.names.find{|n| n == "tile::theme::#{theme}"})
- b.state(:disabled)
+ unless (TkPackage.names.find{|n| n =~ /(tile|ttk)::theme::#{theme}/})
+ b.ttk_state(:disabled)
end
}
$RUBY_THEMELIST.each{|theme, name, available|
@@ -88,7 +97,7 @@ def makeThemeControl(parent)
:variable=>$V.ref(:THEME),
:command=>proc{setTheme(theme)})
b.grid(:sticky=>:ew)
- b.state(:disabled) unless available
+ b.ttk_state(:disabled) unless available
}
c
end
@@ -98,7 +107,7 @@ def makeThemeMenu(parent)
$THEMELIST.each{|theme, name|
m.add(:radiobutton, :label=>name, :variable=>$V.ref(:THEME),
:value=>theme, :command=>proc{setTheme(theme)})
- unless (TkPackage.names.find{|n| n == "tile::theme::#{theme}"})
+ unless (TkPackage.names.find{|n| n =~ /(tile|ttk)::theme::#{theme}/})
m.entryconfigure(:end, :state=>:disabled)
end
}
@@ -111,8 +120,10 @@ def makeThemeMenu(parent)
end
def setTheme(theme)
- if (TkPackage.names.find{|n| n == "tile::theme::#{theme}"})
- TkPackage.require("tile::theme::#{theme}")
+ if (pkg = TkPackage.names.find{|n| n =~ /(tile|ttk)::theme::#{theme}/})
+ unless Tk::Tile::Style.theme_names.find{|n| n == theme}
+ TkPackage.require(pkg)
+ end
end
Tk::Tile::Style.theme_use(theme)
end
@@ -675,7 +686,7 @@ values = %w(list abc def ghi jkl mno pqr stu vwx yz)
combo, :values=>values, :textvariable=>$V.ref(:COMBO))
cb.pack(:side=>:top, :padx=>2, :pady=>2, :expand=>false, :fill=>:x)
if i == 1
- cb.state :readonly
+ cb.ttk_state :readonly
begin
cb.current = 3 # ignore if unsupported (tile0.4)
rescue
@@ -922,11 +933,11 @@ end
def updateStates
$states_list.each{|st|
begin
- $State[st] = $Widget.window.instate(st)
+ $State[st] = $Widget.window.ttk_instate(st)
rescue
- $states_btns[st].state('disabled')
+ $states_btns[st].ttk_state('disabled')
else
- $states_btns[st].state('!disabled')
+ $states_btns[st].ttk_state('!disabled')
end
}
end
@@ -934,9 +945,9 @@ end
def changeState(st)
if $Widget.value != ''
if $State.bool_element(st)
- $Widget.window.state(st)
+ $Widget.window.ttk_state(st)
else
- $Widget.window.state("!#{st}")
+ $Widget.window.ttk_state("!#{st}")
end
end
end
diff --git a/ext/tk/sample/tkextlib/tile/repeater.tcl b/ext/tk/sample/tkextlib/tile/repeater.tcl
index 1f403de537..652ba8ab17 100644
--- a/ext/tk/sample/tkextlib/tile/repeater.tcl
+++ b/ext/tk/sample/tkextlib/tile/repeater.tcl
@@ -1,5 +1,5 @@
#
-# $Id: repeater.tcl,v 1.1.2.1 2005/08/02 06:51:26 ocean Exp $
+# $Id$
#
# Demonstration of custom classes.
#
diff --git a/ext/tk/sample/tkextlib/tile/themes/blue/pkgIndex.tcl b/ext/tk/sample/tkextlib/tile/themes/blue/pkgIndex.tcl
index 19ddda7c73..4facac70d8 100644
--- a/ext/tk/sample/tkextlib/tile/themes/blue/pkgIndex.tcl
+++ b/ext/tk/sample/tkextlib/tile/themes/blue/pkgIndex.tcl
@@ -1,6 +1,6 @@
# Package index for tile demo pixmap themes.
if {[file isdirectory [file join $dir blue]]} {
- package ifneeded tile::theme::blue 0.0.1 \
+ package ifneeded tile::theme::blue 0.7 \
[list source [file join $dir blue.tcl]]
}
diff --git a/ext/tk/sample/tkextlib/tile/themes/keramik/keramik.tcl b/ext/tk/sample/tkextlib/tile/themes/keramik/keramik.tcl
index c47a67b5a9..79fcd7c04e 100644
--- a/ext/tk/sample/tkextlib/tile/themes/keramik/keramik.tcl
+++ b/ext/tk/sample/tkextlib/tile/themes/keramik/keramik.tcl
@@ -5,7 +5,7 @@
# Copyright (c) 2004 Googie
# Copyright (c) 2004 Pat Thoyts <patthoyts@users.sourceforge.net>
#
-# $Id: keramik.tcl,v 1.1.2.1 2005/11/25 07:04:59 nagai Exp $
+# $Id$
package require Tk 8.4; # minimum version for Tile
package require tile 0.5; # depends upon tile 0.5
diff --git a/ext/tk/sample/tkextlib/tile/themes/keramik/pkgIndex.tcl b/ext/tk/sample/tkextlib/tile/themes/keramik/pkgIndex.tcl
index b66fa7fb31..4bb89aa8a5 100644
--- a/ext/tk/sample/tkextlib/tile/themes/keramik/pkgIndex.tcl
+++ b/ext/tk/sample/tkextlib/tile/themes/keramik/pkgIndex.tcl
@@ -6,7 +6,7 @@
# To use this automatically within tile, the tile-using application should
# use tile::availableThemes and tile::setTheme
#
-# $Id: pkgIndex.tcl,v 1.1.2.1 2005/11/25 07:04:59 nagai Exp $
+# $Id$
if {![file isdirectory [file join $dir keramik]]} { return }
if {![package vsatisfies [package provide Tcl] 8.4]} { return }
diff --git a/ext/tk/sample/tkextlib/tile/themes/kroc.rb b/ext/tk/sample/tkextlib/tile/themes/kroc.rb
index f67ce7a897..27006d847f 100644
--- a/ext/tk/sample/tkextlib/tile/themes/kroc.rb
+++ b/ext/tk/sample/tkextlib/tile/themes/kroc.rb
@@ -95,8 +95,35 @@ def kroc_rb_settings
#
# Elements:
#
- if TkPackage.vcompare(Tk::Tile.package_version, '0.5') >= 0
+ if Tk::Tile::TILE_SPEC_VERSION_ID >= 8
+ Tk::Tile::Style.element_create('Button.button',
+ :image,
+ [ $images['button-n'],
+ :pressed, $images['button-p'],
+ :active, $images['button-h'],
+ ], :border=>3, :sticky=>:ew)
+
+ Tk::Tile::Style.element_create('Checkbutton.indicator',
+ :image,
+ [ $images['check-nu'],
+ [:pressed, :selected],$images['check-nc'],
+ :pressed, $images['check-nu'],
+ [:active, :selected], $images['check-hc'],
+ :active, $images['check-hu'],
+ :selected, $images['check-nc'],
+ ], :sticky=>:w)
+ Tk::Tile::Style.element_create('Radiobutton.indicator',
+ :image,
+ [ $images['radio-nu'],
+ [:pressed,:selected],$images['radio-nc'],
+ :pressed, $images['radio-nu'],
+ [:active,:selected], $images['radio-hc'],
+ :active, $images['radio-hu'],
+ :selected, $images['radio-nc'],
+ ], :sticky=>:w)
+
+ elsif TkPackage.vcompare(Tk::Tile.package_version, '0.5') >= 0
Tk::Tile::Style.element_create('Button.button',
:image, $images['button-n'],
:map=>[
@@ -125,7 +152,6 @@ def kroc_rb_settings
], :sticky=>:w)
else # tile 0.4 or earlier
-
Tk::Tile::Style.element_create('Button.button', :pixmap,
:images=>[
:pressed, $images['button-p'],
diff --git a/ext/tk/sample/tkextlib/tile/themes/kroc/pkgIndex.tcl b/ext/tk/sample/tkextlib/tile/themes/kroc/pkgIndex.tcl
index 4f188b77e0..179077917c 100644
--- a/ext/tk/sample/tkextlib/tile/themes/kroc/pkgIndex.tcl
+++ b/ext/tk/sample/tkextlib/tile/themes/kroc/pkgIndex.tcl
@@ -6,7 +6,7 @@
# To use this automatically within tile, the tile-using application should
# use tile::availableThemes and tile::setTheme
#
-# $Id: pkgIndex.tcl,v 1.1.2.1 2005/11/25 07:05:01 nagai Exp $
+# $Id$
if {![file isdirectory [file join $dir kroc]]} { return }
if {![package vsatisfies [package provide Tcl] 8.4]} { return }
diff --git a/ext/tk/sample/tkextlib/tile/themes/plastik/pkgIndex.tcl b/ext/tk/sample/tkextlib/tile/themes/plastik/pkgIndex.tcl
index f7fd2a899d..e39aff6f44 100644
--- a/ext/tk/sample/tkextlib/tile/themes/plastik/pkgIndex.tcl
+++ b/ext/tk/sample/tkextlib/tile/themes/plastik/pkgIndex.tcl
@@ -6,7 +6,7 @@
# To use this automatically within tile, the tile-using application should
# use tile::availableThemes and tile::setTheme
#
-# $Id: pkgIndex.tcl,v 1.1.2.1 2005/11/25 07:05:02 nagai Exp $
+# $Id$
if {![file isdirectory [file join $dir plastik]]} { return }
if {![package vsatisfies [package provide Tcl] 8.4]} { return }
diff --git a/ext/tk/sample/tkextlib/tile/themes/plastik/plastik.tcl b/ext/tk/sample/tkextlib/tile/themes/plastik/plastik.tcl
index 51fb7244f6..ea6ed74162 100644
--- a/ext/tk/sample/tkextlib/tile/themes/plastik/plastik.tcl
+++ b/ext/tk/sample/tkextlib/tile/themes/plastik/plastik.tcl
@@ -5,7 +5,7 @@
# Copyright (c) 2004 Googie
# Copyright (c) 2005 Pat Thoyts <patthoyts@users.sourceforge.net>
#
-# $Id: plastik.tcl,v 1.1.2.1 2005/11/25 07:05:02 nagai Exp $
+# $Id$
package require Tk 8.4
package require tile 0.5
diff --git a/ext/tk/sample/tkextlib/tile/toolbutton.tcl b/ext/tk/sample/tkextlib/tile/toolbutton.tcl
index 63b805d98b..4e08034e31 100644
--- a/ext/tk/sample/tkextlib/tile/toolbutton.tcl
+++ b/ext/tk/sample/tkextlib/tile/toolbutton.tcl
@@ -1,5 +1,5 @@
#
-# $Id: toolbutton.tcl,v 1.1.2.1 2005/04/09 09:27:28 nagai Exp $
+# $Id$
#
# Demonstration of custom widget styles.
#
diff --git a/ext/tk/sample/tkextlib/tkHTML/page3/index.html b/ext/tk/sample/tkextlib/tkHTML/page3/index.html
index d854bd5b8b..ce92e8a22e 100644
--- a/ext/tk/sample/tkextlib/tkHTML/page3/index.html
+++ b/ext/tk/sample/tkextlib/tkHTML/page3/index.html
@@ -29,7 +29,7 @@
resources related to this tutorial<br>are available online at
<a href="http://www.hwaci.com/tcl2k/">
http://www.hwaci.com/tcl2k/</a></p>
- <p align="center"><small>$Id: index.html,v 1.1.2.1 2004/07/01 09:38:51 nagai Exp $</small></p></td></tr>
+ <p align="center"><small>$Id$</small></p></td></tr>
</table>
</center>
</p>
diff --git a/ext/tk/sample/tkextlib/treectrl/demo.rb b/ext/tk/sample/tkextlib/treectrl/demo.rb
index 50ecde91f0..eed95d0e1c 100644
--- a/ext/tk/sample/tkextlib/treectrl/demo.rb
+++ b/ext/tk/sample/tkextlib/treectrl/demo.rb
@@ -9,11 +9,12 @@ $HasColumnCreate = Tk::TreeCtrl::HasColumnCreateCommand
$Version_1_1_OrLater = (TkPackage.vcompare(Tk::TreeCtrl.package_version, '1.1') >= 0)
-if Hash.instance_methods.include?('key')
- # probably ruby 1.9.x --> use Hash#key
+#if Hash.instance_methods.include?(:key)
+if TkCore::WITH_RUBY_VM ### Ruby 1.9 !!!!
+ # ruby 1.9.x --> use Hash#key
# Because Hash#index show warning "Hash#index is deprecated; use Hash#key".
else
- # probably ruby 1.8.x --> use Hash#index
+ # ruby 1.8.x --> use Hash#index
class Hash
alias key index
end
diff --git a/ext/tk/sample/tkextlib/vu/canvSticker2.rb b/ext/tk/sample/tkextlib/vu/canvSticker2.rb
index f54e748660..548a72c2cb 100644
--- a/ext/tk/sample/tkextlib/vu/canvSticker2.rb
+++ b/ext/tk/sample/tkextlib/vu/canvSticker2.rb
@@ -20,14 +20,16 @@ c.destroy
#---
#--- set STRING {{x0 y0 x1 y1} {...text...} {resize point: center}
-#sti_conf = [ [10, 10, 180, 180], "Sticker äöüß@²³¼½¾", :center ]
-#txt_conf = [ [210, 210], "Text äöüß@²³¼½¾", :center ]
+#sti_conf = [ [10, 10, 180, 180], "Sticker äöüß@²³¼½¾", :center ]
+#txt_conf = [ [210, 210], "Text äöüß@²³¼½¾", :center ]
sti_conf = [ [10, 10, 350, 350],
- Tk::UTF8_String("Sticker äöüß@²³¼½¾"), :center ]
+ Tk::UTF8_String('Sticker \u00E4\u00F6\u00FC\u00DF\u0040\u00B2\u00B3\u00BC\u00BD\u00BE'),
+ :center ]
txt_conf = [ [250, 250],
- Tk::UTF8_String("Text äöüß@²³¼½¾"), :center ]
+ Tk::UTF8_String('Text \u00E4\u00F6\u00FC\u00DF\u0040\u00B2\u00B3\u00BC\u00BD\u00BE'),
+ :center ]
-p sti_conf
+#p sti_conf
fnt = TkFont.new('Helvetica 24 bold')
diff --git a/ext/tk/sample/tkrttimer.rb b/ext/tk/sample/tkrttimer.rb
index 531f4a8d5a..0abd4ecbd2 100644
--- a/ext/tk/sample/tkrttimer.rb
+++ b/ext/tk/sample/tkrttimer.rb
@@ -17,8 +17,17 @@ TkLabel.new(f2, :text=>'use TkRTTimer class').pack
label2 = TkLabel.new(:parent=>f2, :relief=>:raised,
:width=>10).pack(:fill=>:both)
-TkLabel.new(:text=>'Interval setting of each timer is 10 ms.',
- :padx=>10, :pady=>5).pack
+TkLabel.new(:padx=>10, :pady=>5, :justify=>'left', :text=><<EOT).pack
+Interval setting of each timer object is 10 ms.
+Each timer object counts up the value on each callback
+(the value is not the clock data).
+The count of the TkTimer object is delayed by execution
+time of callbacks and inaccuracy of interval.
+On the other hand, the count of the TkRTTimer object is
+not delayed. Its callback interval is not accurate too.
+But it can compute error correction about the time when
+a callback should start.
+EOT
# define the procedure repeated by the TkTimer object
tick = proc{|aobj| #<== TkTimer object
diff --git a/ext/tk/sample/tksleep_sample.rb b/ext/tk/sample/tksleep_sample.rb
new file mode 100644
index 0000000000..23f6eca54e
--- /dev/null
+++ b/ext/tk/sample/tksleep_sample.rb
@@ -0,0 +1,29 @@
+require 'tk'
+
+v = TkVariable.new(0)
+l = TkLabel.new(:textvariable=>v).pack(:pady=>[1, 10])
+
+a = TkButton.new(:text=>"button A :: proc{p ['AAA', v.value]}").pack(:fill=>:x, :pady=>[1, 15], :padx=>15)
+a.command{p ['AAA', v.value]}
+
+TkLabel.new(:text=>'Callback of the button B returns LIFO order').pack
+b = TkButton.new(:text=>"button B :: proc{n = v.value; p ['B:start', n]; Tk.sleep(10000); p ['B:end', n]}").pack(:fill=>:x, :pady=>[1, 15], :padx=>15)
+b.command{n = v.value; p ['B:start', n]; Tk.sleep(10000); p ['B:end', n]}
+
+TkLabel.new(:text=>'Callback of the button C returns FIFO order').pack
+c = TkButton.new(:text=>"button C :: proc{n = v.value; Thread.new{p ['C:start', n]; Tk.sleep(10000); p ['C:end', n]}}").pack(:fill=>:x, :pady=>[1, 15], :padx=>15)
+c.command{n = v.value; Thread.new{p ['C:start', n]; Tk.sleep(10000); p ['C:end', n]}}
+
+TkLabel.new(:text=>'Callback of the button D blocks eventloop (no respond to event)').pack
+d = TkButton.new(:text=>"button D :: proc{n = v.value; p ['D:start', n]; sleep(10); p ['D:end', n]}").pack(:fill=>:x, :pady=>[1,15], :padx=>15)
+d.command{n = v.value; p ['D:start', n]; sleep(10); p ['D:end', n]}
+
+TkLabel.new(:text=>'Callback of the button E is another way to avoid eventloop blocking').pack
+e = TkButton.new(:text=>"button E :: proc{n = v.value; Thread.new{p ['D:start', n]; sleep(10); p ['D:end', n]}}").pack(:fill=>:x, :pady=>[1,15], :padx=>15)
+e.command{n = v.value; Thread.new{p ['D:start', n]; sleep(10); p ['D:end', n]}}
+
+TkButton.new(:text=>'QUIT', :command=>proc{exit}).pack
+
+TkTimer.new(500, -1){v.numeric += 1}.start
+
+Tk.mainloop
diff --git a/ext/tk/sample/tktextio.rb b/ext/tk/sample/tktextio.rb
index cb59c2d9d6..9f012feada 100644
--- a/ext/tk/sample/tktextio.rb
+++ b/ext/tk/sample/tktextio.rb
@@ -1,7 +1,7 @@
#!/usr/bin/env ruby
#
-# sample class of handling I/O stream on a TkText widget
-# by Hidetoshi NAGAI
+# TkTextIO class :: handling I/O stream on a TkText widget
+# by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)
#
# NOTE: TkTextIO supports 'character' (not 'byte') access only.
# So, for example, TkTextIO#getc returns a character, TkTextIO#pos
@@ -14,68 +14,385 @@
# TkTextIO.
#
require 'tk'
+require 'tk/text'
+require 'tk/textmark'
+require 'thread'
class TkTextIO < TkText
+ # keep safe level
+ @@create_queues = proc{ [Queue.new, Mutex.new, Queue.new, Mutex.new] }
+
+ OPT_DEFAULTS = {
+ 'mode' => nil,
+ 'overwrite' => false,
+ 'text' => nil,
+ 'show' => :pos,
+ 'wrap' => 'char',
+ 'sync' => true,
+ 'prompt' => nil,
+ 'prompt_cmd' => nil,
+ 'hist_size' => 1000,
+ }
+
def create_self(keys)
- mode = nil
- ovwt = false
- text = nil
- wrap = 'char'
- show = :pos
-
- if keys.kind_of?(Hash)
- mode = keys.delete('mode')
- ovwt = keys.delete('overwrite')
- text = keys.delete('text')
- show = keys.delete('show') if keys.has_key?('show')
- wrap = keys.delete('wrap') || 'char'
- end
+ opts = _get_io_params((keys.kind_of?(Hash))? keys: {})
super(keys)
- self['wrap'] = wrap
- insert('1.0', text)
+ @count_var = TkVariable.new
- @txtpos = TkTextMark.new(self, '1.0')
- @txtpos.gravity = :left
+ @write_buffer = ''
+ @read_buffer = ''
+ @buf_size = 0
+ @buf_max = 1024
- self.show_mode = show
+ @write_buf_queue, @write_buf_mutex,
+ @read_buf_queue, @read_buf_mutex = @@create_queues.call
- @sync = true
- @overwrite = (ovwt)? true: false
+ @idle_flush = TkTimer.new(:idle, 1, proc{ @flusher.run rescue nil })
+ @timer_flush = TkTimer.new(250, -1, proc{ @flusher.run rescue nil })
+
+ @flusher = Thread.new{ loop { Thread.stop; flush() } }
+
+ @receiver = Thread.new{
+ begin
+ loop {
+ str = @write_buf_queue.deq
+ @write_buf_mutex.synchronize { @write_buffer << str }
+ @idle_flush.start
+ }
+ ensure
+ @flusher.kill
+ end
+ }
+
+ @timer_flush.start
+
+ _setup_io(opts)
+ end
+ private :create_self
+
+ def destroy
+ @flusher.kill rescue nil
+
+ @idle_flush.stop rescue nil
+ @timer_flush.stop rescue nil
+
+ @receiver.kill rescue nil
+
+ super()
+ end
+
+ ####################################
+
+ def _get_io_params(keys)
+ opts = {}
+ self.class.const_get(:OPT_DEFAULTS).each{|k, v|
+ if keys.has_key?(k)
+ opts[k] = keys.delete(k)
+ else
+ opts[k] = v
+ end
+ }
+ opts
+ end
+
+ def _setup_io(opts)
+ unless defined? @txtpos
+ @txtpos = TkTextMark.new(self, '1.0')
+ else
+ @txtpos.set('1.0')
+ end
+ @txtpos.gravity = :left
@lineno = 0
@line_offset = 0
- @count_var = TkVariable.new
+
+ @hist_max = opts['hist_size'].to_i
+ @hist_index = 0
+ @history = Array.new(@hist_max)
+ @history[0] = ''
+
+ self['wrap'] = wrap
+
+ self.show_mode = opts['show']
+
+ self.value = opts['text'] if opts['text']
+
+ @overwrite = (opts['overwrite'])? true: false
+
+ @sync = opts['sync']
+
+ @prompt = opts['prompt']
+ @prompt_cmd = opts['prompt_cmd']
@open = {:r => true, :w => true} # default is 'r+'
- case mode
- when 'r'
+ @console_mode = false
+ @end_of_stream = false
+ @console_buffer = nil
+
+ case opts['mode']
+ when nil
+ # do nothing
+
+ when :console, 'console'
+ @console_mode = true
+ # @console_buffer = TkTextIO.new(:mode=>'r')
+ @console_buffer = self.class.new(:mode=>'r')
+ self.show_mode = :insert
+
+ when 'r', 'rb'
@open[:r] = true; @open[:w] = nil
- when 'r+'
+ when 'r+', 'rb+', 'r+b'
@open[:r] = true; @open[:w] = true
- when 'w'
+ when 'w', 'wb'
@open[:r] = nil; @open[:w] = true
self.value=''
- when 'w+'
+ when 'w+', 'wb+', 'w+b'
@open[:r] = true; @open[:w] = true
self.value=''
- when 'a'
+ when 'a', 'ab'
@open[:r] = nil; @open[:w] = true
- @txtpos = TkTextMark.new(self, 'end - 1 char')
+ @txtpos.set('end - 1 char')
@txtpos.gravity = :right
- when 'a+'
+ when 'a+', 'ab+', 'a+b'
@open[:r] = true; @open[:w] = true
- @txtpos = TkTextMark.new(self, 'end - 1 char')
+ @txtpos.set('end - 1 char')
@txtpos.gravity = :right
+
+ else
+ fail ArgumentError, "unknown mode `#{opts['mode']}'"
+ end
+
+ unless defined? @ins_head
+ @ins_head = TkTextMark.new(self, 'insert')
+ @ins_head.gravity = :left
+ end
+
+ unless defined? @ins_tail
+ @ins_tail = TkTextMark.new(self, 'insert')
+ @ins_tail.gravity = :right
+ end
+
+ unless defined? @tmp_mark
+ @tmp_mark = TkTextMark.new(self, 'insert')
+ @tmp_mark.gravity = :left
+ end
+
+ if @console_mode
+ _set_console_line
+ _setup_console_bindings
end
end
+ private :_get_io_params, :_setup_io
+
+ def _set_console_line
+ @tmp_mark.set(@ins_tail)
+
+ mark_set('insert', 'end')
+
+ prompt = ''
+ prompt << @prompt_cmd.call if @prompt_cmd
+ prompt << @prompt if @prompt
+ insert(@tmp_mark, prompt)
+
+ @ins_head.set(@ins_tail)
+ @ins_tail.set('insert')
+
+ @txtpos.set(@tmp_mark)
+
+ _see_pos
+ end
+
+ def _replace_console_line(str)
+ self.delete(@ins_head, @ins_tail)
+ self.insert(@ins_head, str)
+ end
+
+ def _get_console_line
+ @tmp_mark.set(@ins_tail)
+ s = self.get(@ins_head, @tmp_mark)
+ _set_console_line
+ s
+ end
+ private :_set_console_line, :_replace_console_line, :_get_console_line
+
+ def _cb_up
+ @history[@hist_index].replace(self.get(@ins_head, @ins_tail))
+ @hist_index += 1
+ @hist_index -= 1 if @hist_index >= @hist_max || !@history[@hist_index]
+ _replace_console_line(@history[@hist_index]) if @history[@hist_index]
+ Tk.callback_break
+ end
+ def _cb_down
+ @history[@hist_index].replace(self.get(@ins_head, @ins_tail))
+ @hist_index -= 1
+ @hist_index = 0 if @hist_index < 0
+ _replace_console_line(@history[@hist_index]) if @history[@hist_index]
+ Tk.callback_break
+ end
+ def _cb_left
+ if @console_mode && compare('insert', '<=', @ins_head)
+ mark_set('insert', @ins_head)
+ Tk.callback_break
+ end
+ end
+ def _cb_backspace
+ if @console_mode && compare('insert', '<=', @ins_head)
+ Tk.callback_break
+ end
+ end
+ def _cb_ctrl_a
+ if @console_mode
+ mark_set('insert', @ins_head)
+ Tk.callback_break
+ end
+ end
+ def _cb_ctrl_u
+ if @console_mode
+ mark_set('insert', @ins_head)
+ delete('insert', 'insert lineend')
+ Tk.callback_break
+ end
+ end
+ private :_cb_up, :_cb_down, :_cb_left, :_cb_backspace,
+ :_cb_ctrl_a, :_cb_ctrl_u
+
+ def _setup_console_bindings
+ @bindtag = TkBindTag.new
+
+ tags = self.bindtags
+ tags[tags.index(self)+1, 0] = @bindtag
+ self.bindtags = tags
+
+ @bindtag.bind('Return'){
+ insert('end - 1 char', "\n")
+ if (str = _get_console_line)
+ @read_buf_queue.push(str)
+
+ @history[0].replace(str.chomp)
+ @history.pop
+ @history.unshift('')
+ @hist_index = 0
+ end
+
+ Tk.update
+ Tk.callback_break
+ }
+ @bindtag.bind('Alt-Return'){
+ Tk.callback_continue
+ }
+
+ @bindtag.bind('FocusIn'){
+ if @console_mode
+ mark_set('insert', @ins_tail)
+ Tk.callback_break
+ end
+ }
+
+ ins_mark = TkTextMark.new(self, 'insert')
+
+ @bindtag.bind('ButtonPress'){
+ if @console_mode
+ ins_mark.set('insert')
+ end
+ }
+
+ @bindtag.bind('ButtonRelease-1'){
+ if @console_mode && compare('insert', '<=', @ins_head)
+ mark_set('insert', ins_mark)
+ Tk.callback_break
+ end
+ }
+
+ @bindtag.bind('ButtonRelease-2', '%x %y'){|x, y|
+ if @console_mode
+ # paste a text at 'insert' only
+ x1, y1, x2, y2 = bbox(ins_mark)
+ unless x == x1 && y == y1
+ Tk.event_generate(self, 'ButtonRelease-2', :x=>x1, :y=>y1)
+ Tk.callback_break
+ end
+ end
+ }
+
+ @bindtag.bind('Up'){ _cb_up }
+ @bindtag.bind('Control-p'){ _cb_up }
+
+ @bindtag.bind('Down'){ _cb_down }
+ @bindtag.bind('Control-n'){ _cb_down }
+
+ @bindtag.bind('Left'){ _cb_left }
+ @bindtag.bind('Control-b'){ _cb_left }
+
+ @bindtag.bind('BackSpace'){ _cb_backspace }
+ @bindtag.bind('Control-h'){ _cb_backspace }
+
+ @bindtag.bind('Home'){ _cb_ctrl_a }
+ @bindtag.bind('Control-a'){ _cb_ctrl_a }
+
+ @bindtag.bind('Control-u'){ _cb_ctrl_u }
+ end
+ private :_setup_console_bindings
+
+ def _block_read(size = nil, ret = '', block_mode = true)
+ return '' if size == 0
+ return nil if ! @read_buf_queue && @read_buffer.empty?
+ ret = '' unless ret.kind_of?(String)
+ ret.replace('') unless ret.empty?
+
+ if block_mode == nil # partial
+ if @read_buffer.empty?
+ ret << @read_buffer.slice!(0..-1)
+ return ret
+ end
+ end
+
+ if size.kind_of?(Numeric)
+ loop{
+ @read_buf_mutex.synchronize {
+ buf_len = @read_buffer.length
+ if buf_len >= size
+ ret << @read_buffer.slice!(0, size)
+ return ret
+ else
+ ret << @read_buffer.slice!(0..-1)
+ size -= buf_len
+ return ret unless @read_buf_queue
+ end
+ }
+ @read_buffer << @read_buf_queue.pop
+ }
+ else # readline
+ rs = (size)? size: $/
+ rs = rs.to_s if rs.kind_of?(Regexp)
+ loop{
+ @read_buf_mutex.synchronize {
+ if (str = @read_buffer.slice!(/\A(.*)(#{rs})/m))
+ ret << str
+ return ret
+ else
+ ret << @read_buffer.slice!(0..-1)
+ return ret unless @read_buf_queue
+ end
+ }
+ @read_buffer << @read_buf_queue.pop
+ }
+ end
+ end
+
+ def _block_write
+ ###### currently, not support
+ end
+ private :_block_read, :_block_write
+
+ ####################################
def <<(obj)
_write(obj)
@@ -107,14 +424,15 @@ class TkTextIO < TkText
nil
end
- def closed?
- close_read? && close_write?
- end
- def closed_read?
- !@open[:r]
- end
- def closed_write?
- !@open[:w]
+ def closed?(dir=nil)
+ case dir
+ when :r, 'r'
+ !@open[:r]
+ when :w, 'w'
+ !@open[:w]
+ else
+ !@open[:r] && !@open[:w]
+ end
end
def _check_readable
@@ -129,7 +447,7 @@ class TkTextIO < TkText
def each_line(rs = $/)
_check_readable
- while(s = gets)
+ while(s = self.gets(rs))
yield(s)
end
self
@@ -138,7 +456,7 @@ class TkTextIO < TkText
def each_char
_check_readable
- while(c = getc)
+ while(c = self.getc)
yield(c)
end
self
@@ -151,7 +469,7 @@ class TkTextIO < TkText
alias eof eof?
def fcntl(*args)
- fail NotImplementedError, 'fcntl is not implemented on TkTextIO'
+ fail NotImplementedError, "fcntl is not implemented on #{self.class}"
end
def fsync
@@ -163,11 +481,19 @@ class TkTextIO < TkText
end
def flush
- Tk.update if @open[:w] && @sync
+ Thread.pass
+ if @open[:w] || ! @write_buffer.empty?
+ @write_buf_mutex.synchronize {
+ _sync_write_buf(@write_buffer)
+ @write_buffer[0..-1] = ''
+ }
+ end
self
end
def getc
+ return _block_read(1) if @console_mode
+
_check_readable
return nil if eof?
c = get(@txtpos)
@@ -177,8 +503,10 @@ class TkTextIO < TkText
end
def gets(rs = $/)
+ return _block_read(rs) if @console_mode
+
_check_readable
- return nil if eof?
+ return nil if eof?
_readline(rs)
end
@@ -233,7 +561,6 @@ class TkTextIO < TkText
alias tell pos
def pos=(idx)
- # @txtpos.set((idx.kind_of?(Numeric))? "1.0 + #{idx} char": idx)
seek(idx, IO::SEEK_SET)
idx
end
@@ -306,6 +633,8 @@ class TkTextIO < TkText
private :_read
def read(len=nil, buf=nil)
+ return _block_read(len, buf) if @console_mode
+
_check_readable
if len
return "" if len == 0
@@ -321,6 +650,8 @@ class TkTextIO < TkText
end
def readchar
+ return _block_read(1) if @console_mode
+
_check_readable
fail EOFError if eof?
c = get(@txtpos)
@@ -334,6 +665,7 @@ class TkTextIO < TkText
s = get(@txtpos, 'end - 1 char')
@txtpos.set('end - 1 char')
elsif rs == ''
+ @count_var.value # make it global
idx = tksearch_with_count([:regexp], @count_var,
"\n(\n)+", @txtpos, 'end - 1 char')
if idx
@@ -345,6 +677,7 @@ class TkTextIO < TkText
@txtpos.set('end - 1 char')
end
else
+ @count_var.value # make it global
idx = tksearch_with_count(@count_var, rs, @txtpos, 'end - 1 char')
if idx
s = get(@txtpos, "#{idx} + #{@count_var.value} char")
@@ -363,12 +696,22 @@ class TkTextIO < TkText
private :_readline
def readline(rs = $/)
+ return _block_readline(rs) if @console_mode
+
_check_readable
fail EOFError if eof?
_readline(rs)
end
def readlines(rs = $/)
+ if @console_mode
+ lines = []
+ while (line = _block_readline(rs))
+ lines << line
+ end
+ return lines
+ end
+
_check_readable
lines = []
until(eof?)
@@ -379,7 +722,11 @@ class TkTextIO < TkText
end
def readpartial(maxlen, buf=nil)
+ #return @console_buffer.readpartial(maxlen, buf) if @console_mode
+ return _block_read(maxlen, buf, nil) if @console_mode
+
_check_readable
+ fail EOFError if eof?
s = _read(maxlen)
buf.replace(s) if buf.kind_of?(String)
s
@@ -471,6 +818,8 @@ class TkTextIO < TkText
end
def sysread(len, buf=nil)
+ return _block_read(len, buf) if @console_mode
+
_check_readable
fail EOFError if eof?
s = _read(len)
@@ -492,6 +841,13 @@ class TkTextIO < TkText
end
def ungetc(c)
+ if @console_mode
+ @read_buf_mutex.synchronize {
+ @read_buffer[0,0] = c.chr
+ }
+ return nil
+ end
+
_check_readable
c = c.chr if c.kind_of?(Fixnum)
if compare(@txtpos, '>', '1.0')
@@ -506,8 +862,10 @@ class TkTextIO < TkText
nil
end
+=begin
def _write(obj)
- s = _get_eval_string(obj)
+ #s = _get_eval_string(obj)
+ s = (obj.kind_of?(String))? obj: obj.to_s
n = number(tk_call('string', 'length', s))
delete(@txtpos, @txtpos + "#{n} char") if @overwrite
self.insert(@txtpos, s)
@@ -518,6 +876,37 @@ class TkTextIO < TkText
n
end
private :_write
+=end
+#=begin
+ def _sync_write_buf(s)
+ if (n = number(tk_call('string', 'length', s))) > 0
+ delete(@txtpos, @txtpos + "#{n} char") if @overwrite
+ self.insert(@txtpos, s)
+ #Tk.update
+
+ @txtpos.set(@txtpos + "#{n} char")
+ @txtpos.set('end - 1 char') if compare(@txtpos, '>=', :end)
+
+ @ins_head.set(@txtpos) if compare(@txtpos, '>', @ins_head)
+
+ _see_pos
+ end
+ self
+ end
+ private :_sync_write_buf
+
+ def _write(obj)
+ s = (obj.kind_of?(String))? obj: obj.to_s
+ n = number(tk_call('string', 'length', s))
+ @write_buf_queue.enq(s)
+ if @sync
+ Thread.pass
+ Tk.update
+ end
+ n
+ end
+ private :_write
+#=end
def write(obj)
_check_writable
@@ -529,13 +918,19 @@ end
# TEST
####################
if __FILE__ == $0
+ ev_loop = Thread.new{Tk.mainloop}
+
f = TkFrame.new.pack
- tio = TkTextIO.new(f, :show=>:pos,
+ #tio = TkTextIO.new(f, :show=>:nil,
+ #tio = TkTextIO.new(f, :show=>:pos,
+ tio = TkTextIO.new(f, :show=>:insert,
:text=>">>> This is an initial text line. <<<\n\n"){
- yscrollbar(TkScrollbar.new(f).pack(:side=>:right, :fill=>:y))
+# yscrollbar(TkScrollbar.new(f).pack(:side=>:right, :fill=>:y))
pack(:side=>:left, :fill=>:both, :expand=>true)
}
+ Tk.update
+
$stdin = tio
$stdout = tio
$stderr = tio
@@ -599,5 +994,67 @@ if __FILE__ == $0
tio.seek(0, IO::SEEK_END)
- Tk.mainloop
+ STDOUT.print("tio.sync == #{tio.sync}\n")
+# tio.sync = false
+# STDOUT.print("tio.sync == #{tio.sync}\n")
+
+ (0..10).each{|i|
+ STDOUT.print("#{i}\n")
+ s = ''
+ (0..1000).each{ s << '*' }
+ print(s)
+ }
+ print("\n")
+ print("\n=========================================================\n\n")
+
+ s = ''
+ timer = TkTimer.new(:idle, -1, proc{
+ #STDOUT.print("idle call\n")
+ unless s.empty?
+ print(s)
+ s = ''
+ end
+ }).start
+ (0..10).each{|i|
+ STDOUT.print("#{i}\n")
+ (0..1000).each{ s << '*' }
+ }
+# timer.stop
+ until s.empty?
+ sleep 0.1
+ end
+ timer.stop
+
+=begin
+ tio.sync = false
+ print("\n")
+ #(0..10000).each{ putc('*') }
+ (0..10).each{|i|
+ STDOUT.print("#{i}\n")
+ (0..1000).each{ putc('*') }
+ }
+
+ (0..10).each{|i|
+ STDOUT.print("#{i}\n")
+ s = ''
+ (0..1000).each{ s << '*' }
+ print(s)
+ }
+=end
+
+ num = 0
+# io = TkTextIO.new(:mode=>:console, :prompt=>'').pack
+#=begin
+ io = TkTextIO.new(:mode=>:console,
+ :prompt_cmd=>proc{
+ s = "[#{num}]"
+ num += 1
+ s
+ },
+ :prompt=>'-> ').pack
+#=end
+ Thread.new{loop{sleep 2; io.puts 'hoge'}}
+ Thread.new{loop{p io.gets}}
+
+ ev_loop.join
end
diff --git a/ext/tk/sample/ttk_wrapper.rb b/ext/tk/sample/ttk_wrapper.rb
new file mode 100644
index 0000000000..1580668994
--- /dev/null
+++ b/ext/tk/sample/ttk_wrapper.rb
@@ -0,0 +1,154 @@
+#!/usr/bin/env ruby
+#
+# ttk_wrapper.rb -- use Ttk widgets as default on old Ruby/Tk scripts
+#
+# by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)
+#
+version = '0.1.3'
+#
+##########################################################################
+# parse commandline arguments
+##########################################################################
+require 'optparse'
+opt = OptionParser.new("Usage: #{$0} [options] rubytk_script" << "\n " <<
+ "Ruby/Tk script wrapper. Use Ttk widgets as default.")
+opt.version = version
+
+OPTS = {}
+OPTS[:themedir] = []
+OPTS[:rb_theme] = []
+OPTS[:theme] = 'default'
+
+opt.on('-l', '--list', 'list available theme names'){|v| OPTS[:list] = true}
+opt.on('-t', '--theme theme', 'theme name'){|v| OPTS[:theme] = v}
+opt.on('-d', '--themedir themes_dir', 'directory of theme definitions'){|v|
+ OPTS[:themedir] << v
+}
+opt.on('-r', '--rubytheme rb_theme', 'theme definition file (ruby script)'){|v|
+ OPTS[:rb_theme] << v
+}
+opt.on('-v', '--verbose', 'print verbose messages'){|v| OPTS[:verbose] = true}
+
+opt.parse!(ARGV)
+
+
+##########################################################################
+# load Ttk (Tile) extension
+##########################################################################
+require 'tk'
+
+begin
+ require 'tkextlib/tile'
+ Tk.default_widget_set = :Ttk
+rescue LoadError
+ if OPTS[:verbose]
+ print "warning: fail to load 'Ttk' extension. use standard widgets.\n"
+ end
+end
+
+if OPTS[:verbose]
+ print "current default widget set is '#{Tk.default_widget_set}'\n"
+end
+
+
+##########################################################################
+# define Tcl/Tk procedures for compatibility.
+# those are required when want to use themes included
+# in "sample/tkextlib/tile/demo.rb".
+##########################################################################
+Tk::Tile.__define_LoadImages_proc_for_compatibility__!
+Tk::Tile::Style.__define_wrapper_proc_for_compatibility__!
+
+
+##########################################################################
+# use themes defined on the demo of Ttk (Tile) extension
+##########################################################################
+demodir = File.dirname(__FILE__)
+demo_themesdir = File.expand_path(File.join(demodir, 'tkextlib', 'tile', 'themes'))
+
+Tk::AUTO_PATH.lappend(*OPTS[:themedir]) unless OPTS[:themedir].empty?
+Tk::AUTO_PATH.lappend('.', demodir, demo_themesdir)
+
+OPTS[:themedir] << demo_themesdir
+print "theme-dirs: #{OPTS[:themedir].inspect}\n" if OPTS[:verbose]
+
+OPTS[:themedir].each{|themesdir|
+ if File.directory?(themesdir)
+ Dir.foreach(themesdir){|name|
+ next if name == '.' || name == '..'
+ path = File.join(themesdir, name)
+ Tk::AUTO_PATH.lappend(path) if File.directory?(path)
+ }
+ end
+}
+
+# This forces an update of the available packages list. It's required
+# for package names to find the themes in demos/themes/*.tcl
+Tk.ip_eval("#{TkPackage.unknown_proc} Tcl #{TkPackage.provide('Tcl')}")
+
+# load themes written in Ruby.
+themes_by_ruby = [File.join(demo_themesdir, 'kroc.rb')]
+themes_by_ruby.concat OPTS[:rb_theme]
+print "ruby-themes: #{themes_by_ruby.inspect}\n" if OPTS[:verbose]
+
+themes_by_ruby.each{|f|
+ begin
+ load(f, true)
+ rescue LoadError
+ print "fail to load \"#{f}\"\n" if OPTS[:verbose]
+ end
+}
+
+
+##########################################################################
+# ignore unsupported options of Ttk widgets
+##########################################################################
+TkConfigMethod.__set_IGNORE_UNKNOWN_CONFIGURE_OPTION__! true
+TkItemConfigMethod.__set_IGNORE_UNKNOWN_CONFIGURE_OPTION__! true
+
+
+##########################################################################
+# set theme of widget style
+##########################################################################
+if OPTS[:list] || OPTS[:verbose]
+ print "supported theme names: #{Tk::Tile.themes.inspect}\n"
+ exit if OPTS[:list] && ARGV.empty?
+end
+print "use theme: \"#{OPTS[:theme]}\"\n" if OPTS[:theme] && OPTS[:verbose]
+#setTheme(OPTS[:theme]) if OPTS[:theme]
+Tk::Tile.set_theme(OPTS[:theme]) if OPTS[:theme]
+
+
+##########################################################################
+# replace $0 and $RPAGRAM_NAME
+##########################################################################
+# When the expand_path of the target script is long, ruby sometimes
+# fails to set the path to $0 (the path string is trimmed).
+# The following replaces $0 and $PROGNAME to avoid such trouble.
+progname_obj = $0.dup
+$program_name = progname_obj
+
+alias $REAL_PROGRAM_NAME $0
+alias $PROGRAM_NAME $program_name
+alias $0 $program_name
+
+trace_var(:$program_name){|val|
+ unless progname_obj.object_id == val.object_id
+ progname_obj.replace(val.to_s)
+ $program_name = progname_obj
+ end
+}
+
+
+##########################################################################
+# load script
+##########################################################################
+if (path = ARGV.shift) && (script = File.expand_path(path))
+ print "load script \"#{script}\"\n" if OPTS[:verbose]
+ $0 = script
+ load(script)
+else
+ print "Error: no script is given.\n"
+ print opt.help
+ exit(1)
+end
diff --git a/ext/tk/stubs.c b/ext/tk/stubs.c
index 23ff42a4f4..6d3b330f0e 100644
--- a/ext/tk/stubs.c
+++ b/ext/tk/stubs.c
@@ -1,5 +1,11 @@
-#include "stubs.h"
+/************************************************
+
+ stubs.c - Tcl/Tk stubs support
+
+************************************************/
+
#include "ruby.h"
+#include "stubs.h"
#include <tcl.h>
#include <tk.h>
@@ -86,8 +92,12 @@ static DL_HANDLE tcl_dll = (DL_HANDLE)0;
static DL_HANDLE tk_dll = (DL_HANDLE)0;
int
+#ifdef RUBY_VM
+ruby_open_tcl_dll(char *appname)
+#else
ruby_open_tcl_dll(appname)
char *appname;
+#endif
{
void (*p_Tcl_FindExecutable)(const char *);
int n;
@@ -141,8 +151,8 @@ ruby_open_tk_dll()
char tk_name[20];
if (!tcl_dll) {
- /* int ret = ruby_open_tcl_dll(RSTRING(rb_argv0)->ptr); */
- int ret = ruby_open_tcl_dll(rb_argv0 ? RSTRING(rb_argv0)->ptr : 0);
+ /* int ret = ruby_open_tcl_dll(RSTRING_PTR(rb_argv0)); */
+ int ret = ruby_open_tcl_dll(rb_argv0 ? RSTRING_PTR(rb_argv0) : 0);
if (ret != TCLTK_STUBS_OK) return ret;
}
@@ -169,8 +179,12 @@ ruby_open_tk_dll()
}
int
+#ifdef RUBY_VM
+ruby_open_tcltk_dll(char *appname)
+#else
ruby_open_tcltk_dll(appname)
char *appname;
+#endif
{
return( ruby_open_tcl_dll(appname) || ruby_open_tk_dll() );
}
@@ -189,8 +203,12 @@ tk_stubs_init_p()
Tcl_Interp *
+#ifdef RUBY_VM
+ruby_tcl_create_ip_and_stubs_init(int *st)
+#else
ruby_tcl_create_ip_and_stubs_init(st)
int *st;
+#endif
{
Tcl_Interp *tcl_ip;
@@ -213,8 +231,8 @@ ruby_tcl_create_ip_and_stubs_init(st)
Tcl_Interp *(*p_Tcl_DeleteInterp)();
if (!tcl_dll) {
- /* int ret = ruby_open_tcl_dll(RSTRING(rb_argv0)->ptr); */
- int ret = ruby_open_tcl_dll(rb_argv0 ? RSTRING(rb_argv0)->ptr : 0);
+ /* int ret = ruby_open_tcl_dll(RSTRING_PTR(rb_argv0)); */
+ int ret = ruby_open_tcl_dll(rb_argv0 ? RSTRING_PTR(rb_argv0) : 0);
if (ret != TCLTK_STUBS_OK) {
if (st) *st = ret;
@@ -272,8 +290,12 @@ ruby_tcl_stubs_init()
}
int
+#ifdef RUBY_VM
+ruby_tk_stubs_init(Tcl_Interp *tcl_ip)
+#else
ruby_tk_stubs_init(tcl_ip)
Tcl_Interp *tcl_ip;
+#endif
{
Tcl_ResetResult(tcl_ip);
@@ -308,8 +330,12 @@ ruby_tk_stubs_init(tcl_ip)
}
int
+#ifdef RUBY_VM
+ruby_tk_stubs_safeinit(Tcl_Interp *tcl_ip)
+#else
ruby_tk_stubs_safeinit(tcl_ip)
Tcl_Interp *tcl_ip;
+#endif
{
Tcl_ResetResult(tcl_ip);
@@ -348,8 +374,8 @@ ruby_tcltk_stubs()
int st;
Tcl_Interp *tcl_ip;
- /* st = ruby_open_tcltk_dll(RSTRING(rb_argv0)->ptr); */
- st = ruby_open_tcltk_dll(rb_argv0 ? RSTRING(rb_argv0)->ptr : 0);
+ /* st = ruby_open_tcltk_dll(RSTRING_PTR(rb_argv0)); */
+ st = ruby_open_tcltk_dll(rb_argv0 ? RSTRING_PTR(rb_argv0) : 0);
switch(st) {
case NO_FindExecutable:
return -7;
@@ -395,8 +421,12 @@ static int open_tcl_dll = 0;
static int call_tk_stubs_init = 0;
int
+#ifdef RUBY_VM
+ruby_open_tcl_dll(char *appname)
+#else
ruby_open_tcl_dll(appname)
char *appname;
+#endif
{
if (appname) {
Tcl_FindExecutable(appname);
@@ -408,18 +438,24 @@ ruby_open_tcl_dll(appname)
return TCLTK_STUBS_OK;
}
-int ruby_open_tk_dll()
+int
+ruby_open_tk_dll()
{
if (!open_tcl_dll) {
- /* ruby_open_tcl_dll(RSTRING(rb_argv0)->ptr); */
- ruby_open_tcl_dll(rb_argv0 ? RSTRING(rb_argv0)->ptr : 0);
+ /* ruby_open_tcl_dll(RSTRING_PTR(rb_argv0)); */
+ ruby_open_tcl_dll(rb_argv0 ? RSTRING_PTR(rb_argv0) : 0);
}
return TCLTK_STUBS_OK;
}
-int ruby_open_tcltk_dll(appname)
+int
+#ifdef RUBY_VM
+ruby_open_tcltk_dll(char *appname)
+#else
+ruby_open_tcltk_dll(appname)
char *appname;
+#endif
{
return( ruby_open_tcl_dll(appname) || ruby_open_tk_dll() );
}
@@ -437,14 +473,18 @@ tk_stubs_init_p()
}
Tcl_Interp *
+#ifdef RUBY_VM
+ruby_tcl_create_ip_and_stubs_init(int *st)
+#else
ruby_tcl_create_ip_and_stubs_init(st)
int *st;
+#endif
{
Tcl_Interp *tcl_ip;
if (!open_tcl_dll) {
- /* ruby_open_tcl_dll(RSTRING(rb_argv0)->ptr); */
- ruby_open_tcl_dll(rb_argv0 ? RSTRING(rb_argv0)->ptr : 0);
+ /* ruby_open_tcl_dll(RSTRING_PTR(rb_argv0)); */
+ ruby_open_tcl_dll(rb_argv0 ? RSTRING_PTR(rb_argv0) : 0);
}
if (st) *st = 0;
@@ -466,8 +506,12 @@ ruby_tcl_stubs_init()
}
int
+#ifdef RUBY_VM
+ruby_tk_stubs_init(Tcl_Interp *tcl_ip)
+#else
ruby_tk_stubs_init(tcl_ip)
Tcl_Interp *tcl_ip;
+#endif
{
if (Tk_Init(tcl_ip) == TCL_ERROR)
return FAIL_Tk_Init;
@@ -483,8 +527,12 @@ ruby_tk_stubs_init(tcl_ip)
}
int
+#ifdef RUBY_VM
+ruby_tk_stubs_safeinit(Tcl_Interp *tcl_ip)
+#else
ruby_tk_stubs_safeinit(tcl_ip)
Tcl_Interp *tcl_ip;
+#endif
{
#if TCL_MAJOR_VERSION >= 8
if (Tk_SafeInit(tcl_ip) == TCL_ERROR)
@@ -508,8 +556,8 @@ ruby_tk_stubs_safeinit(tcl_ip)
int
ruby_tcltk_stubs()
{
- /* Tcl_FindExecutable(RSTRING(rb_argv0)->ptr); */
- Tcl_FindExecutable(rb_argv0 ? RSTRING(rb_argv0)->ptr : 0);
+ /* Tcl_FindExecutable(RSTRING_PTR(rb_argv0)); */
+ Tcl_FindExecutable(rb_argv0 ? RSTRING_PTR(rb_argv0) : 0);
return 0;
}
diff --git a/ext/tk/tcltklib.c b/ext/tk/tcltklib.c
index ff1f7640bd..8701cfef27 100644
--- a/ext/tk/tcltklib.c
+++ b/ext/tk/tcltklib.c
@@ -4,11 +4,20 @@
* Oct. 24, 1997 Y. Matsumoto
*/
-#define TCLTKLIB_RELEASE_DATE "2006-12-01"
+#define TCLTKLIB_RELEASE_DATE "2008-05-23"
#include "ruby.h"
+
+#ifdef RUBY_VM
+/* #include "ruby/ruby.h" */
+#include "ruby/signal.h"
+#include "ruby/encoding.h"
+#else
+/* #include "ruby.h" */
#include "rubysig.h"
#include "version.h"
+#endif
+
#undef EXTERN /* avoid conflict with tcl.h of tcl8.2 or before */
#include <stdio.h>
#ifdef HAVE_STDARG_PROTOTYPES
@@ -30,6 +39,24 @@
#define TCL_FINAL_RELEASE 2
#endif
+static struct {
+ int major;
+ int minor;
+ int patchlevel;
+ int type;
+} tcltk_version = {0, 0, 0, 0};
+
+static void
+set_tcltk_version()
+{
+ if (tcltk_version.major) return;
+
+ Tcl_GetVersion(&(tcltk_version.major),
+ &(tcltk_version.minor),
+ &(tcltk_version.patchlevel),
+ &(tcltk_version.type));
+}
+
#if TCL_MAJOR_VERSION >= 8
# ifndef CONST84
# if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION <= 4 /* Tcl8.0.x -- 8.4b1 */
@@ -83,6 +110,26 @@ static void ip_finalize _((Tcl_Interp*));
static int at_exit = 0;
+#ifdef RUBY_VM
+static VALUE cRubyEncoding;
+
+/* encoding */
+static int ENCODING_INDEX_UTF8;
+static int ENCODING_INDEX_BINARY;
+#endif
+static VALUE ENCODING_NAME_UTF8;
+static VALUE ENCODING_NAME_BINARY;
+
+static VALUE create_dummy_encoding_for_tk_core _((VALUE, VALUE, VALUE));
+static VALUE create_dummy_encoding_for_tk _((VALUE, VALUE));
+static int update_encoding_table _((VALUE, VALUE, VALUE));
+static VALUE encoding_table_get_name_core _((VALUE, VALUE, VALUE));
+static VALUE encoding_table_get_obj_core _((VALUE, VALUE, VALUE));
+static VALUE encoding_table_get_name _((VALUE, VALUE));
+static VALUE encoding_table_get_obj _((VALUE, VALUE));
+static VALUE create_encoding_table _((VALUE));
+static VALUE ip_get_encoding_table _((VALUE));
+
/* for callback break & continue */
static VALUE eTkCallbackReturn;
@@ -101,6 +148,9 @@ static VALUE tcltkip_class;
static ID ID_at_enc;
static ID ID_at_interp;
+static ID ID_encoding_name;
+static ID ID_encoding_table;
+
static ID ID_stop_p;
static ID ID_alive_p;
static ID ID_kill;
@@ -121,14 +171,37 @@ static ID ID_inspect;
static VALUE ip_invoke_real _((int, VALUE*, VALUE));
static VALUE ip_invoke _((int, VALUE*, VALUE));
-
+static VALUE ip_invoke_with_position _((int, VALUE*, VALUE, Tcl_QueuePosition));
static VALUE tk_funcall _((VALUE(), int, VALUE*, VALUE));
+/* Tcl's object type */
+#if TCL_MAJOR_VERSION >= 8
+static char *Tcl_ObjTypeName_ByteArray = "bytearray";
+static Tcl_ObjType *Tcl_ObjType_ByteArray;
+
+static char *Tcl_ObjTypeName_String = "string";
+static Tcl_ObjType *Tcl_ObjType_String;
+
+#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1)
+#define IS_TCL_BYTEARRAY(obj) ((obj)->typePtr == Tcl_ObjType_ByteArray)
+#define IS_TCL_STRING(obj) ((obj)->typePtr == Tcl_ObjType_String)
+#define IS_TCL_VALID_STRING(obj) ((obj)->bytes != (char*)NULL)
+#endif
+#endif
+
+#ifndef HAVE_RB_HASH_LOOKUP
+#define rb_hash_lookup rb_hash_aref
+#endif
+
/* safe Tcl_Eval and Tcl_GlobalEval */
static int
+#ifdef RUBY_VM
+tcl_eval(Tcl_Interp *interp, const char *cmd)
+#else
tcl_eval(interp, cmd)
Tcl_Interp *interp;
const char *cmd; /* don't have to be writable */
+#endif
{
char *buf = strdup(cmd);
int ret;
@@ -143,9 +216,13 @@ tcl_eval(interp, cmd)
#define Tcl_Eval tcl_eval
static int
+#ifdef RUBY_VM
+tcl_global_eval(Tcl_Interp *interp, const char *cmd)
+#else
tcl_global_eval(interp, cmd)
Tcl_Interp *interp;
const char *cmd; /* don't have to be writable */
+#endif
{
char *buf = strdup(cmd);
int ret;
@@ -316,12 +393,29 @@ call_queue_mark(struct call_queue *q)
static VALUE eventloop_thread;
+#ifdef RUBY_VM
+Tcl_ThreadId tk_eventloop_thread_id; /* native thread ID of Tcl interpreter */
+#endif
static VALUE eventloop_stack;
+static int window_event_mode = ( ~ TCL_IDLE_EVENTS | TCL_WINDOW_EVENTS );
static VALUE watchdog_thread;
Tcl_Interp *current_interp;
-
+
+/* thread control strategy */
+/* multi-tk works with the following settings only ???
+ : CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE 1
+ : USE_TOGGLE_WINDOW_MODE_FOR_IDLE 0
+ : DO_THREAD_SCHEDULE_AT_CALLBACK_DONE 0
+*/
+#define CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE 1
+#define USE_TOGGLE_WINDOW_MODE_FOR_IDLE 0
+#define DO_THREAD_SCHEDULE_AT_CALLBACK_DONE 0
+
+#if CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE
+static int have_rb_thread_waiting_for_value = 0;
+#endif
/*
* 'event_loop_max' is a maximum events which the eventloop processes in one
@@ -330,12 +424,21 @@ Tcl_Interp *current_interp;
* 'timer_tick' is a limit of one term of thread scheduling.
* If 'timer_tick' == 0, then not use the timer for thread scheduling.
*/
-#define DEFAULT_EVENT_LOOP_MAX 800/*counts*/
-#define DEFAULT_NO_EVENT_TICK 10/*counts*/
-#define DEFAULT_NO_EVENT_WAIT 20/*milliseconds ( 1 -- 999 ) */
-#define WATCHDOG_INTERVAL 10/*milliseconds ( 1 -- 999 ) */
-#define DEFAULT_TIMER_TICK 0/*milliseconds ( 0 -- 999 ) */
-#define NO_THREAD_INTERRUPT_TIME 100/*milliseconds ( 1 -- 999 ) */
+#ifdef RUBY_VM
+#define DEFAULT_EVENT_LOOP_MAX 800/*counts*/
+#define DEFAULT_NO_EVENT_TICK 10/*counts*/
+#define DEFAULT_NO_EVENT_WAIT 10/*milliseconds ( 1 -- 999 ) */
+#define WATCHDOG_INTERVAL 10/*milliseconds ( 1 -- 999 ) */
+#define DEFAULT_TIMER_TICK 0/*milliseconds ( 0 -- 999 ) */
+#define NO_THREAD_INTERRUPT_TIME 100/*milliseconds ( 1 -- 999 ) */
+#else /* ! RUBY_VM */
+#define DEFAULT_EVENT_LOOP_MAX 800/*counts*/
+#define DEFAULT_NO_EVENT_TICK 10/*counts*/
+#define DEFAULT_NO_EVENT_WAIT 20/*milliseconds ( 1 -- 999 ) */
+#define WATCHDOG_INTERVAL 10/*milliseconds ( 1 -- 999 ) */
+#define DEFAULT_TIMER_TICK 0/*milliseconds ( 0 -- 999 ) */
+#define NO_THREAD_INTERRUPT_TIME 100/*milliseconds ( 1 -- 999 ) */
+#endif
static int event_loop_max = DEFAULT_EVENT_LOOP_MAX;
static int no_event_tick = DEFAULT_NO_EVENT_TICK;
@@ -570,6 +673,9 @@ struct tcltkip {
#if TCL_NAMESPACE_DEBUG
Tcl_Namespace *default_ns; /* default namespace */
#endif
+#ifdef RUBY_VM
+ Tcl_ThreadId tk_thread_id; /* native thread ID of Tcl interpreter */
+#endif
int has_orig_exit; /* has original 'exit' command ? */
Tcl_CmdInfo orig_exit_info; /* command info of original 'exit' command */
int ref_count; /* reference count of rbtk_preserve_ip call */
@@ -605,9 +711,9 @@ deleted_ip(ptr)
#endif
) {
DUMP1("ip is deleted");
- return Qtrue;
+ return 1;
}
- return Qfalse;
+ return 0;
}
/* increment/decrement reference count of tcltkip */
@@ -760,6 +866,10 @@ tcltkip_init_tk(interp)
}
#endif
+#ifdef RUBY_VM
+ ptr->tk_thread_id = Tcl_GetCurrentThread();
+#endif
+
return Qnil;
}
@@ -767,6 +877,7 @@ tcltkip_init_tk(interp)
/* treat excetiopn on Tcl side */
static VALUE rbtk_pending_exception;
static int rbtk_eventloop_depth = 0;
+static int rbtk_internal_eventloop_handler = 0;
static int
@@ -776,7 +887,9 @@ pending_exception_check0()
if (!NIL_P(exc) && rb_obj_is_kind_of(exc, rb_eException)) {
DUMP1("find a pending exception");
- if (rbtk_eventloop_depth > 0) {
+ if (rbtk_eventloop_depth > 0
+ || rbtk_internal_eventloop_handler > 0
+ ) {
return 1; /* pending */
} else {
rbtk_pending_exception = Qnil;
@@ -809,7 +922,9 @@ pending_exception_check1(thr_crit_bup, ptr)
if (!NIL_P(exc) && rb_obj_is_kind_of(exc, rb_eException)) {
DUMP1("find a pending exception");
- if (rbtk_eventloop_depth > 0) {
+ if (rbtk_eventloop_depth > 0
+ || rbtk_internal_eventloop_handler > 0
+ ) {
return 1; /* pending */
} else {
rbtk_pending_exception = Qnil;
@@ -848,8 +963,10 @@ call_original_exit(ptr, state)
int thr_crit_bup;
Tcl_CmdInfo *info;
#if TCL_MAJOR_VERSION >= 8
+ Tcl_Obj *cmd_obj;
Tcl_Obj *state_obj;
#endif
+ DUMP1("original_exit is called");
if (!(ptr->has_orig_exit)) return;
@@ -867,20 +984,55 @@ call_original_exit(ptr, state)
if (info->isNativeObjectProc) {
Tcl_Obj **argv;
+#define USE_RUBY_ALLOC 0
+#if USE_RUBY_ALLOC
argv = (Tcl_Obj **)ALLOC_N(Tcl_Obj *, 3);
- argv[0] = Tcl_NewStringObj("exit", 4);
+#else /* not USE_RUBY_ALLOC */
+ argv = (Tcl_Obj **)ckalloc(sizeof(Tcl_Obj *) * 3);
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)argv); /* XXXXXXXX */
+#endif
+#endif
+ cmd_obj = Tcl_NewStringObj("exit", 4);
+ Tcl_IncrRefCount(cmd_obj);
+
+ argv[0] = cmd_obj;
argv[1] = state_obj;
argv[2] = (Tcl_Obj *)NULL;
ptr->return_value
= (*(info->objProc))(info->objClientData, ptr->ip, 2, argv);
+ Tcl_DecrRefCount(cmd_obj);
+
+#if USE_RUBY_ALLOC
free(argv);
+#else /* not USE_RUBY_ALLOC */
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)argv); /* XXXXXXXX */
+#else
+ /* free(argv); */
+ ckfree((char*)argv);
+#endif
+#endif
+#endif
+#undef USE_RUBY_ALLOC
} else {
/* string interface */
char **argv;
- argv = (char **)ALLOC_N(char *, 3);
+#define USE_RUBY_ALLOC 0
+#if USE_RUBY_ALLOC
+ argv = (char **)ALLOC_N(char *, 3); /* XXXXXXXXXX */
+#else /* not USE_RUBY_ALLOC */
+ argv = (char **)ckalloc(sizeof(char *) * 3);
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)argv); /* XXXXXXXX */
+#endif
+#endif
argv[0] = "exit";
/* argv[1] = Tcl_GetString(state_obj); */
argv[1] = Tcl_GetStringFromObj(state_obj, (int*)NULL);
@@ -889,7 +1041,21 @@ call_original_exit(ptr, state)
ptr->return_value = (*(info->proc))(info->clientData, ptr->ip,
2, (CONST84 char **)argv);
+#if USE_RUBY_ALLOC
free(argv);
+#else /* not USE_RUBY_ALLOC */
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)argv); /* XXXXXXXX */
+#else
+ /* free(argv); */
+ ckfree((char*)argv);
+#endif
+#endif
+#endif
+#undef USE_RUBY_ALLOC
}
Tcl_DecrRefCount(state_obj);
@@ -898,17 +1064,40 @@ call_original_exit(ptr, state)
{
/* string interface */
char **argv;
+#define USE_RUBY_ALLOC 0
+#if USE_RUBY_ALLOC
argv = (char **)ALLOC_N(char *, 3);
+#else /* not USE_RUBY_ALLOC */
+ argv = (char **)ckalloc(sizeof(char *) * 3);
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)argv); /* XXXXXXXX */
+#endif
+#endif
argv[0] = "exit";
- argv[1] = RSTRING(rb_fix2str(INT2NUM(state), 10))->ptr;
+ argv[1] = RSTRING_PTR(rb_fix2str(INT2NUM(state), 10));
argv[2] = (char *)NULL;
ptr->return_value = (*(info->proc))(info->clientData, ptr->ip,
2, argv);
+#if USE_RUBY_ALLOC
free(argv);
+#else /* not USE_RUBY_ALLOC */
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)argv); /* XXXXXXXX */
+#else
+ /* free(argv); */
+ ckfree(argv);
+#endif
+#endif
+#endif
+#undef USE_RUBY_ALLOC
}
#endif
+ DUMP1("complete original_exit");
rb_thread_critical = thr_crit_bup;
}
@@ -949,6 +1138,53 @@ _timer_for_tcl(clientData)
/* tick_counter += event_loop_max; */
}
+#ifdef RUBY_VM
+#if USE_TOGGLE_WINDOW_MODE_FOR_IDLE
+static int
+toggle_eventloop_window_mode_for_idle()
+{
+ if (window_event_mode & TCL_IDLE_EVENTS) {
+ /* idle -> event */
+ window_event_mode |= TCL_WINDOW_EVENTS;
+ window_event_mode &= ~TCL_IDLE_EVENTS;
+ return 1;
+ } else {
+ /* event -> idle */
+ window_event_mode |= TCL_IDLE_EVENTS;
+ window_event_mode &= ~TCL_WINDOW_EVENTS;
+ return 0;
+ }
+}
+#endif
+#endif
+
+static VALUE
+set_eventloop_window_mode(self, mode)
+ VALUE self;
+ VALUE mode;
+{
+ rb_secure(4);
+
+ if (RTEST(mode)) {
+ window_event_mode = ~0;
+ } else {
+ window_event_mode = ~(TCL_WINDOW_EVENTS | TCL_IDLE_EVENTS);
+ }
+
+ return mode;
+}
+
+static VALUE
+get_eventloop_window_mode(self)
+ VALUE self;
+{
+ if ( ~window_event_mode ) {
+ return Qfalse;
+ } else {
+ return Qtrue;
+ }
+}
+
static VALUE
set_eventloop_tick(self, tick)
VALUE self;
@@ -1137,15 +1373,15 @@ set_max_block_time(self, time)
case T_BIGNUM:
/* time is micro-second value */
divmod = rb_funcall(time, rb_intern("divmod"), 1, LONG2NUM(1000000));
- tcl_time.sec = NUM2LONG(RARRAY(divmod)->ptr[0]);
- tcl_time.usec = NUM2LONG(RARRAY(divmod)->ptr[1]);
+ tcl_time.sec = NUM2LONG(RARRAY_PTR(divmod)[0]);
+ tcl_time.usec = NUM2LONG(RARRAY_PTR(divmod)[1]);
break;
case T_FLOAT:
/* time is second value */
divmod = rb_funcall(time, rb_intern("divmod"), 1, INT2FIX(1));
- tcl_time.sec = NUM2LONG(RARRAY(divmod)->ptr[0]);
- tcl_time.usec = (long)(NUM2DBL(RARRAY(divmod)->ptr[1]) * 1000000);
+ tcl_time.sec = NUM2LONG(RARRAY_PTR(divmod)[0]);
+ tcl_time.usec = (long)(NUM2DBL(RARRAY_PTR(divmod)[1]) * 1000000);
default:
{
@@ -1229,8 +1465,10 @@ ip_evloop_abort_on_exc_set(self, val)
}
static VALUE
-lib_num_of_mainwindows(self)
+lib_num_of_mainwindows_core(self, argc, argv)
VALUE self;
+ int argc; /* dummy */
+ VALUE *argv; /* dummy */
{
if (tk_stubs_init_p()) {
return INT2FIX(Tk_GetNumMainWindows());
@@ -1239,7 +1477,41 @@ lib_num_of_mainwindows(self)
}
}
+static VALUE
+lib_num_of_mainwindows(self)
+ VALUE self;
+{
+#ifdef RUBY_VM /* Ruby 1.9+ !!! */
+ return tk_funcall(lib_num_of_mainwindows_core, 0, (VALUE*)NULL, self);
+#else
+ return lib_num_of_mainwindows_core(self, 0, (VALUE*)NULL);
+#endif
+}
+
+
+#ifdef RUBY_VM /* Ruby 1.9+ !!! */
+static VALUE
+call_DoOneEvent_core(flag_val)
+ VALUE flag_val;
+{
+ int flag;
+
+ flag = FIX2INT(flag_val);
+ if (Tcl_DoOneEvent(flag)) {
+ return Qtrue;
+ } else {
+ return Qfalse;
+ }
+}
+
+static VALUE
+call_DoOneEvent(flag_val)
+ VALUE flag_val;
+{
+ return tk_funcall(call_DoOneEvent_core, 0, (VALUE*)NULL, flag_val);
+}
+#else /* Ruby 1.8- */
static VALUE
call_DoOneEvent(flag_val)
VALUE flag_val;
@@ -1253,6 +1525,8 @@ call_DoOneEvent(flag_val)
return Qfalse;
}
}
+#endif
+
static VALUE
eventloop_sleep(dummy)
@@ -1264,22 +1538,77 @@ eventloop_sleep(dummy)
t.tv_usec = (time_t)(no_event_wait*1000.0);
#ifdef HAVE_NATIVETHREAD
+#ifdef RUBY_VM
+#if 0
+ if (!ruby_native_thread_p()) {
+ rb_bug("cross-thread violation on eventloop_sleep()");
+ }
+#endif
+#else
if (!is_ruby_native_thread()) {
rb_bug("cross-thread violation on eventloop_sleep()");
}
#endif
+#endif
+ DUMP2("eventloop_sleep: rb_thread_wait_for() at thread : %lx", rb_thread_current());
rb_thread_wait_for(t);
+ DUMP2("eventloop_sleep: finish at thread : %lx", rb_thread_current());
#ifdef HAVE_NATIVETHREAD
+#ifdef RUBY_VM
+#if 0
+ if (!ruby_native_thread_p()) {
+ rb_bug("cross-thread violation on eventloop_sleep()");
+ }
+#endif
+#else
if (!is_ruby_native_thread()) {
rb_bug("cross-thread violation on eventloop_sleep()");
}
#endif
+#endif
return Qnil;
}
+#define USE_EVLOOP_THREAD_ALONE_CHECK_FLAG 0
+
+#if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG
+static int
+get_thread_alone_check_flag()
+{
+#ifdef RUBY_VM
+ return 0;
+#else
+ set_tcltk_version();
+
+ if (tcltk_version.major < 8) {
+ /* Tcl/Tk 7.x */
+ return 1;
+ } else if (tcltk_version.major == 8) {
+ if (tcltk_version.minor < 5) {
+ /* Tcl/Tk 8.0 - 8.4 */
+ return 1;
+ } else if (tcltk_version.minor == 5) {
+ if (tcltk_version.type < TCL_FINAL_RELEASE) {
+ /* Tcl/Tk 8.5a? - 8.5b? */
+ return 1;
+ } else {
+ /* Tcl/Tk 8.5.x */
+ return 0;
+ }
+ } else {
+ /* Tcl/Tk 8.6 - 8.9 ?? */
+ return 0;
+ }
+ } else {
+ /* Tcl/Tk 9+ ?? */
+ return 0;
+ }
+#endif
+}
+#endif
static int
lib_eventloop_core(check_root, update_flag, check_var, interp)
@@ -1295,7 +1624,9 @@ lib_eventloop_core(check_root, update_flag, check_var, interp)
int thr_crit_bup;
int status;
int depth = rbtk_eventloop_depth;
-
+#if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG
+ int thread_alone_check_flag = 1;
+#endif
if (update_flag) DUMP1("update loop start!!");
@@ -1314,15 +1645,25 @@ lib_eventloop_core(check_root, update_flag, check_var, interp)
timer_token = (Tcl_TimerToken)NULL;
}
+#if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG
+ /* version check */
+ thread_alone_check_flag = get_thread_alone_check_flag();
+#endif
+
for(;;) {
+#if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG
+ if (thread_alone_check_flag && rb_thread_alone()) {
+#else
if (rb_thread_alone()) {
+#endif
DUMP1("no other thread");
event_loop_wait_event = 0;
if (update_flag) {
event_flag = update_flag | TCL_DONT_WAIT; /* for safety */
} else {
- event_flag = TCL_ALL_EVENTS;
+ event_flag = TCL_ALL_EVENTS;
+ /* event_flag = TCL_ALL_EVENTS | TCL_DONT_WAIT; */
}
if (timer_tick == 0 && update_flag == 0) {
@@ -1349,11 +1690,19 @@ lib_eventloop_core(check_root, update_flag, check_var, interp)
if (status) {
switch (status) {
case TAG_RAISE:
+#ifdef RUBY_VM
+ if (NIL_P(rb_errinfo())) {
+#else
if (NIL_P(ruby_errinfo)) {
+#endif
rbtk_pending_exception
= rb_exc_new2(rb_eException, "unknown exception");
} else {
+#ifdef RUBY_VM
+ rbtk_pending_exception = rb_errinfo();
+#else
rbtk_pending_exception = ruby_errinfo;
+#endif
if (!NIL_P(rbtk_pending_exception)) {
if (rbtk_eventloop_depth == 0) {
@@ -1368,10 +1717,18 @@ lib_eventloop_core(check_root, update_flag, check_var, interp)
break;
case TAG_FATAL:
+#ifdef RUBY_VM
+ if (NIL_P(rb_errinfo())) {
+#else
if (NIL_P(ruby_errinfo)) {
+#endif
rb_exc_raise(rb_exc_new2(rb_eFatal, "FATAL"));
} else {
+#ifdef RUBY_VM
+ rb_exc_raise(rb_errinfo());
+#else
rb_exc_raise(ruby_errinfo);
+#endif
}
}
}
@@ -1462,19 +1819,56 @@ lib_eventloop_core(check_root, update_flag, check_var, interp)
if (NIL_P(eventloop_thread) || current == eventloop_thread) {
int st;
int status;
-
+#ifdef RUBY_VM
+ if (update_flag) {
+ st = RTEST(rb_protect(call_DoOneEvent,
+ INT2FIX(event_flag), &status));
+ } else {
+ st = RTEST(rb_protect(call_DoOneEvent,
+ INT2FIX(event_flag & window_event_mode),
+ &status));
+#if USE_TOGGLE_WINDOW_MODE_FOR_IDLE
+ if (!st) {
+ if (toggle_eventloop_window_mode_for_idle()) {
+ /* idle-mode -> event-mode*/
+ tick_counter = event_loop_max;
+ } else {
+ /* event-mode -> idle-mode */
+ tick_counter = 0;
+ }
+ }
+#endif
+ }
+#else
/* st = Tcl_DoOneEvent(event_flag); */
st = RTEST(rb_protect(call_DoOneEvent,
INT2FIX(event_flag), &status));
+#endif
+
+#if CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE
+ if (have_rb_thread_waiting_for_value) {
+ have_rb_thread_waiting_for_value = 0;
+ rb_thread_schedule();
+ }
+#endif
+
if (status) {
switch (status) {
case TAG_RAISE:
+#ifdef RUBY_VM
+ if (NIL_P(rb_errinfo())) {
+#else
if (NIL_P(ruby_errinfo)) {
+#endif
rbtk_pending_exception
= rb_exc_new2(rb_eException,
"unknown exception");
} else {
+#ifdef RUBY_VM
+ rbtk_pending_exception = rb_errinfo();
+#else
rbtk_pending_exception = ruby_errinfo;
+#endif
if (!NIL_P(rbtk_pending_exception)) {
if (rbtk_eventloop_depth == 0) {
@@ -1489,10 +1883,18 @@ lib_eventloop_core(check_root, update_flag, check_var, interp)
break;
case TAG_FATAL:
+#ifdef RUBY_VM
+ if (NIL_P(rb_errinfo())) {
+#else
if (NIL_P(ruby_errinfo)) {
+#endif
rb_exc_raise(rb_exc_new2(rb_eFatal, "FATAL"));
} else {
+#ifdef RUBY_VM
+ rb_exc_raise(rb_errinfo());
+#else
rb_exc_raise(ruby_errinfo);
+#endif
}
}
}
@@ -1536,17 +1938,26 @@ lib_eventloop_core(check_root, update_flag, check_var, interp)
tick_counter += no_event_tick;
/* rb_thread_wait_for(t); */
+
rb_protect(eventloop_sleep, Qnil, &status);
if (status) {
switch (status) {
case TAG_RAISE:
+#ifdef RUBY_VM
+ if (NIL_P(rb_errinfo())) {
+#else
if (NIL_P(ruby_errinfo)) {
+#endif
rbtk_pending_exception
= rb_exc_new2(rb_eException,
"unknown exception");
} else {
+#ifdef RUBY_VM
+ rbtk_pending_exception = rb_errinfo();
+#else
rbtk_pending_exception = ruby_errinfo;
+#endif
if (!NIL_P(rbtk_pending_exception)) {
if (rbtk_eventloop_depth == 0) {
@@ -1561,11 +1972,19 @@ lib_eventloop_core(check_root, update_flag, check_var, interp)
break;
case TAG_FATAL:
+#ifdef RUBY_VM
+ if (NIL_P(rb_errinfo())) {
+#else
if (NIL_P(ruby_errinfo)) {
+#endif
rb_exc_raise(rb_exc_new2(rb_eFatal,
"FATAL"));
} else {
+#ifdef RUBY_VM
+ rb_exc_raise(rb_errinfo());
+#else
rb_exc_raise(ruby_errinfo);
+#endif
}
}
}
@@ -1574,7 +1993,8 @@ lib_eventloop_core(check_root, update_flag, check_var, interp)
} else {
DUMP2("sleep eventloop %lx", current);
DUMP2("eventloop thread is %lx", eventloop_thread);
- rb_thread_stop();
+ /* rb_thread_stop(); */
+ rb_thread_sleep_forever();
}
if (!NIL_P(watchdog_thread) && eventloop_thread != current) {
@@ -1619,10 +2039,17 @@ lib_eventloop_core(check_root, update_flag, check_var, interp)
break; /* switch to other thread */
}
}
+
+ DUMP1("thread scheduling");
+ rb_thread_schedule();
}
DUMP1("trap check & thread scheduling");
+#ifdef RUBY_VM
+ /* if (update_flag == 0) CHECK_INTS; */ /*XXXXXXXXXXXXX TODO !!!! */
+#else
if (update_flag == 0) CHECK_INTS;
+#endif
}
return 1;
@@ -1669,19 +2096,35 @@ lib_eventloop_main(args)
switch (status) {
case TAG_RAISE:
+#ifdef RUBY_VM
+ if (NIL_P(rb_errinfo())) {
+#else
if (NIL_P(ruby_errinfo)) {
+#endif
rbtk_pending_exception
= rb_exc_new2(rb_eException, "unknown exception");
} else {
+#ifdef RUBY_VM
+ rbtk_pending_exception = rb_errinfo();
+#else
rbtk_pending_exception = ruby_errinfo;
+#endif
}
return Qnil;
case TAG_FATAL:
+#ifdef RUBY_VM
+ if (NIL_P(rb_errinfo())) {
+#else
if (NIL_P(ruby_errinfo)) {
+#endif
rbtk_pending_exception = rb_exc_new2(rb_eFatal, "FATAL");
} else {
+#ifdef RUBY_VM
+ rbtk_pending_exception = rb_errinfo();
+#else
rbtk_pending_exception = ruby_errinfo;
+#endif
}
return Qnil;
}
@@ -1705,6 +2148,7 @@ lib_eventloop_ensure(args)
rb_thread_critical = ptr->thr_crit_bup;
free(ptr);
+ /* ckfree((char*)ptr); */
return Qnil;
}
@@ -1726,7 +2170,8 @@ lib_eventloop_ensure(args)
break;
}
- if (RTEST(rb_funcall(eventloop_thread, ID_alive_p, 0, 0))) {
+ /* if (RTEST(rb_funcall(eventloop_thread, ID_alive_p, 0, 0))) { */
+ if (RTEST(rb_thread_alive_p(eventloop_thread))) {
DUMP2("eventloop-enshure: wake up parent %lx", eventloop_thread);
rb_thread_wakeup(eventloop_thread);
@@ -1734,9 +2179,16 @@ lib_eventloop_ensure(args)
}
}
+#ifdef RUBY_VM
+ if (NIL_P(eventloop_thread)) {
+ tk_eventloop_thread_id = (Tcl_ThreadId) 0;
+ }
+#endif
+
rb_thread_critical = ptr->thr_crit_bup;
free(ptr);
+ /* ckfree((char*)ptr);*/
DUMP2("finish current eventloop %lx", current_evloop);
return Qnil;
@@ -1751,10 +2203,14 @@ lib_eventloop_launcher(check_root, update_flag, check_var, interp)
{
volatile VALUE parent_evloop = eventloop_thread;
struct evloop_params *args = ALLOC(struct evloop_params);
+ /* struct evloop_params *args = (struct evloop_params *)ckalloc(sizeof(struct evloop_params)); */
tcl_stubs_check();
eventloop_thread = rb_thread_current();
+#ifdef RUBY_VM
+ tk_eventloop_thread_id = Tcl_GetCurrentThread();
+#endif
if (parent_evloop == eventloop_thread) {
DUMP2("eventloop: recursive call on %lx", parent_evloop);
@@ -1905,6 +2361,9 @@ lib_watchdog_ensure(arg)
VALUE arg;
{
eventloop_thread = Qnil; /* stop eventloops */
+#ifdef RUBY_VM
+ tk_eventloop_thread_id = (Tcl_ThreadId) 0;
+#endif
return Qnil;
}
@@ -1916,6 +2375,11 @@ lib_mainloop_watchdog(argc, argv, self)
{
VALUE check_rootwidget;
+#ifdef RUBY_VM
+ rb_raise(rb_eNotImpError,
+ "eventloop_watchdog is not implemented on Ruby VM.");
+#endif
+
if (rb_scan_args(argc, argv, "01", &check_rootwidget) == 0) {
check_rootwidget = Qtrue;
} else if (RTEST(check_rootwidget)) {
@@ -2010,8 +2474,10 @@ lib_thread_callback(argc, argv, self)
}
q = (struct thread_call_proc_arg *)ALLOC(struct thread_call_proc_arg);
+ /* q = (struct thread_call_proc_arg *)ckalloc(sizeof(struct thread_call_proc_arg)); */
q->proc = proc;
q->done = (int*)ALLOC(int);
+ /* q->done = (int*)ckalloc(sizeof(int)); */
*(q->done) = 0;
/* create call-proc thread */
@@ -2023,7 +2489,8 @@ lib_thread_callback(argc, argv, self)
foundEvent = RTEST(lib_eventloop_launcher(/* not check root-widget */0, 0,
q->done, (Tcl_Interp*)NULL));
- if (RTEST(rb_funcall(th, ID_alive_p, 0))) {
+ /* if (RTEST(rb_funcall(th, ID_alive_p, 0))) { */
+ if (RTEST(rb_thread_alive_p(th))) {
rb_funcall(th, ID_kill, 0);
ret = Qnil;
} else {
@@ -2032,12 +2499,21 @@ lib_thread_callback(argc, argv, self)
free(q->done);
free(q);
+ /* ckfree((char*)q->done); */
+ /* ckfree((char*)q); */
if (NIL_P(rbtk_pending_exception)) {
+#ifdef RUBY_VM
+ /* return rb_errinfo(); */
+ if (status) {
+ rb_exc_raise(rb_errinfo());
+ }
+#else
/* return ruby_errinfo; */
if (status) {
rb_exc_raise(ruby_errinfo);
}
+#endif
} else {
VALUE exc = rbtk_pending_exception;
rbtk_pending_exception = Qnil;
@@ -2155,28 +2631,35 @@ ip_set_exc_message(interp, exc)
if (NIL_P(enc)) {
encoding = (Tcl_Encoding)NULL;
} else if (TYPE(enc) == T_STRING) {
- encoding = Tcl_GetEncoding(interp, RSTRING(enc)->ptr);
+ /* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); */
+ encoding = Tcl_GetEncoding((Tcl_Interp*)NULL, RSTRING_PTR(enc));
} else {
enc = rb_funcall(enc, ID_to_s, 0, 0);
- encoding = Tcl_GetEncoding(interp, RSTRING(enc)->ptr);
+ /* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); */
+ encoding = Tcl_GetEncoding((Tcl_Interp*)NULL, RSTRING_PTR(enc));
}
/* to avoid a garbled error message dialog */
- buf = ALLOC_N(char, (RSTRING(msg)->len)+1);
- memcpy(buf, RSTRING(msg)->ptr, RSTRING(msg)->len);
- buf[RSTRING(msg)->len] = 0;
+ /* buf = ALLOC_N(char, (RSTRING(msg)->len)+1);*/
+ /* memcpy(buf, RSTRING(msg)->ptr, RSTRING(msg)->len);*/
+ /* buf[RSTRING(msg)->len] = 0; */
+ buf = ALLOC_N(char, RSTRING_LEN(msg)+1);
+ /* buf = ckalloc(sizeof(char)*((RSTRING_LEN(msg))+1)); */
+ memcpy(buf, RSTRING_PTR(msg), RSTRING_LEN(msg));
+ buf[RSTRING_LEN(msg)] = 0;
Tcl_DStringInit(&dstr);
Tcl_DStringFree(&dstr);
- Tcl_ExternalToUtfDString(encoding, buf, RSTRING(msg)->len, &dstr);
+ Tcl_ExternalToUtfDString(encoding, buf, RSTRING_LEN(msg), &dstr);
Tcl_AppendResult(interp, Tcl_DStringValue(&dstr), (char*)NULL);
DUMP2("error message:%s", Tcl_DStringValue(&dstr));
Tcl_DStringFree(&dstr);
free(buf);
+ /* ckfree(buf); */
#else /* TCL_VERSION <= 8.0 */
- Tcl_AppendResult(interp, RSTRING(msg)->ptr, (char*)NULL);
+ Tcl_AppendResult(interp, RSTRING_PTR(msg), (char*)NULL);
#endif
rb_thread_critical = thr_crit_bup;
@@ -2221,12 +2704,15 @@ tcl_protect_core(interp, proc, data) /* should not raise exception */
int status = 0;
int thr_crit_bup = rb_thread_critical;
+ Tcl_ResetResult(interp);
+
rb_thread_critical = Qfalse;
ret = rb_protect(proc, data, &status);
rb_thread_critical = Qtrue;
if (status) {
char *buf;
- VALUE old_gc, type, str;
+ VALUE old_gc;
+ volatile VALUE type, str;
old_gc = rb_gc_disable();
@@ -2242,58 +2728,104 @@ tcl_protect_core(interp, proc, data) /* should not raise exception */
goto error;
error:
str = rb_str_new2("LocalJumpError: ");
+#ifdef RUBY_VM
+ rb_str_append(str, rb_obj_as_string(rb_errinfo()));
+#else
rb_str_append(str, rb_obj_as_string(ruby_errinfo));
+#endif
exc = rb_exc_new3(type, str);
break;
case TAG_RETRY:
+#ifdef RUBY_VM
+ if (NIL_P(rb_errinfo())) {
+#else
if (NIL_P(ruby_errinfo)) {
+#endif
DUMP1("rb_protect: retry");
exc = rb_exc_new2(eTkCallbackRetry, "retry jump error");
} else {
+#ifdef RUBY_VM
+ exc = rb_errinfo();
+#else
exc = ruby_errinfo;
+#endif
}
break;
case TAG_REDO:
+#ifdef RUBY_VM
+ if (NIL_P(rb_errinfo())) {
+#else
if (NIL_P(ruby_errinfo)) {
+#endif
DUMP1("rb_protect: redo");
exc = rb_exc_new2(eTkCallbackRedo, "redo jump error");
} else {
+#ifdef RUBY_VM
+ exc = rb_errinfo();
+#else
exc = ruby_errinfo;
+#endif
}
break;
case TAG_RAISE:
+#ifdef RUBY_VM
+ if (NIL_P(rb_errinfo())) {
+#else
if (NIL_P(ruby_errinfo)) {
+#endif
exc = rb_exc_new2(rb_eException, "unknown exception");
} else {
+#ifdef RUBY_VM
+ exc = rb_errinfo();
+#else
exc = ruby_errinfo;
+#endif
}
break;
case TAG_FATAL:
+#ifdef RUBY_VM
+ if (NIL_P(rb_errinfo())) {
+#else
if (NIL_P(ruby_errinfo)) {
+#endif
exc = rb_exc_new2(rb_eFatal, "FATAL");
} else {
+#ifdef RUBY_VM
+ exc = rb_errinfo();
+#else
exc = ruby_errinfo;
+#endif
}
break;
case TAG_THROW:
+#ifdef RUBY_VM
+ if (NIL_P(rb_errinfo())) {
+#else
if (NIL_P(ruby_errinfo)) {
+#endif
DUMP1("rb_protect: throw");
exc = rb_exc_new2(eTkCallbackThrow, "throw jump error");
} else {
+#ifdef RUBY_VM
+ exc = rb_errinfo();
+#else
exc = ruby_errinfo;
+#endif
}
break;
default:
buf = ALLOC_N(char, 256);
+ /* buf = ckalloc(sizeof(char) * 256); */
sprintf(buf, "unknown loncaljmp status %d", status);
exc = rb_exc_new2(rb_eException, buf);
free(buf);
+ /* ckfree(buf); */
break;
}
@@ -2371,12 +2903,12 @@ tcl_protect_core(interp, proc, data) /* should not raise exception */
ret = TkStringValue(ret);
DUMP1("Tcl_AppendResult");
- Tcl_AppendResult(interp, RSTRING(ret)->ptr, (char *)NULL);
+ Tcl_AppendResult(interp, RSTRING_PTR(ret), (char *)NULL);
rb_thread_critical = thr_crit_bup;
}
- DUMP2("(result) %s", NIL_P(ret) ? "nil" : RSTRING(ret)->ptr);
+ DUMP2("(result) %s", NIL_P(ret) ? "nil" : RSTRING_PTR(ret));
return TCL_OK;
}
@@ -2391,10 +2923,18 @@ tcl_protect(interp, proc, data)
int code;
#ifdef HAVE_NATIVETHREAD
+#ifdef RUBY_VM
+#if 0
+ if (!ruby_native_thread_p()) {
+ rb_bug("cross-thread violation on tcl_protect()");
+ }
+#endif
+#else
if (!is_ruby_native_thread()) {
rb_bug("cross-thread violation on tcl_protect()");
}
#endif
+#endif
rb_trap_immediate = 0;
code = tcl_protect_core(interp, proc, data);
@@ -2456,6 +2996,7 @@ ip_ruby_eval(clientData, interp, argc, argv)
str = Tcl_GetStringFromObj(argv[1], &len);
arg = ALLOC_N(char, len + 1);
+ /* arg = ckalloc(sizeof(char) * (len + 1)); */
memcpy(arg, str, len);
arg[len] = 0;
@@ -2473,6 +3014,7 @@ ip_ruby_eval(clientData, interp, argc, argv)
#if TCL_MAJOR_VERSION >= 8
free(arg);
+ /* ckfree(arg); */
#endif
return code;
@@ -2497,6 +3039,96 @@ ip_ruby_cmd_core(arg)
return ret;
}
+#define SUPPORT_NESTED_CONST_AS_IP_RUBY_CMD_RECEIVER 1
+
+static VALUE
+ip_ruby_cmd_receiver_const_get(name)
+ char *name;
+{
+ volatile VALUE klass = rb_cObject;
+ char *head, *tail;
+ int state;
+
+#if SUPPORT_NESTED_CONST_AS_IP_RUBY_CMD_RECEIVER
+ klass = rb_eval_string_protect(name, &state);
+ if (state) {
+ return Qnil;
+ } else {
+ return klass;
+ }
+#else
+ return rb_const_get(klass, rb_intern(name));
+#endif
+
+ /* TODO!!!!!! */
+ /* support nest of classes/modules */
+
+ /* return rb_eval_string(name); */
+ /* return rb_eval_string_protect(name, &state); */
+
+#if 0 /* doesn't work!! (fail to autoload?) */
+ /* duplicate */
+ head = name = strdup(name);
+
+ /* has '::' at head ? */
+ if (*head == ':') head += 2;
+ tail = head;
+
+ /* search */
+ while(*tail) {
+ if (*tail == ':') {
+ *tail = '\0';
+ klass = rb_const_get(klass, rb_intern(head));
+ tail += 2;
+ head = tail;
+ } else {
+ tail++;
+ }
+ }
+
+ free(name);
+ return rb_const_get(klass, rb_intern(head));
+#endif
+}
+
+static VALUE
+ip_ruby_cmd_receiver_get(str)
+ char *str;
+{
+ volatile VALUE receiver;
+ volatile VALUE klass = rb_cObject;
+ int state;
+
+ if (str[0] == ':' || ('A' <= str[0] && str[0] <= 'Z')) {
+ /* class | module | constant */
+#if SUPPORT_NESTED_CONST_AS_IP_RUBY_CMD_RECEIVER
+ receiver = ip_ruby_cmd_receiver_const_get(str);
+#else
+ receiver = rb_protect(ip_ruby_cmd_receiver_const_get, (VALUE)str, &state);
+ if (state) return Qnil;
+#endif
+ } else if (str[0] == '$') {
+ /* global variable */
+ receiver = rb_gv_get(str);
+ } else {
+ /* global variable omitted '$' */
+ char *buf;
+ int len;
+
+ len = strlen(str);
+ buf = ALLOC_N(char, len + 2);
+ /* buf = ckalloc(sizeof(char) * (len + 2)); */
+ buf[0] = '$';
+ memcpy(buf + 1, str, len);
+ buf[len + 1] = 0;
+ receiver = rb_gv_get(buf);
+ free(buf);
+ /* ckfree(buf); */
+ }
+
+ return receiver;
+}
+
/* ruby_cmd receiver method arg ... */
static int
#if TCL_MAJOR_VERSION >= 8
@@ -2542,9 +3174,6 @@ ip_ruby_cmd(clientData, interp, argc, argv)
#endif
}
- /* allocate */
- arg = ALLOC(struct cmd_body_arg);
-
/* get arguments from Tcl objects */
thr_crit_bup = rb_thread_critical;
rb_thread_critical = Qtrue;
@@ -2557,24 +3186,8 @@ ip_ruby_cmd(clientData, interp, argc, argv)
str = argv[1];
#endif
DUMP2("receiver:%s",str);
- if (str[0] == ':' || ('A' <= str[0] && str[0] <= 'Z')) {
- /* class | module | constant */
- receiver = rb_const_get(rb_cObject, rb_intern(str));
- } else if (str[0] == '$') {
- /* global variable */
- receiver = rb_gv_get(str);
- } else {
- /* global variable omitted '$' */
- char *buf;
-
- len = strlen(str);
- buf = ALLOC_N(char, len + 2);
- buf[0] = '$';
- memcpy(buf + 1, str, len);
- buf[len + 1] = 0;
- receiver = rb_gv_get(buf);
- free(buf);
- }
+ /* receiver = rb_protect(ip_ruby_cmd_receiver_get, (VALUE)str, &code); */
+ receiver = ip_ruby_cmd_receiver_get(str);
if (NIL_P(receiver)) {
#if 0
rb_raise(rb_eArgError,
@@ -2585,6 +3198,7 @@ ip_ruby_cmd(clientData, interp, argc, argv)
str, "'", (char *)NULL);
rbtk_pending_exception = rb_exc_new2(rb_eArgError,
Tcl_GetStringResult(interp));
+ if (old_gc == Qfalse) rb_gc_enable();
return TCL_ERROR;
#endif
}
@@ -2599,21 +3213,36 @@ ip_ruby_cmd(clientData, interp, argc, argv)
/* get args */
args = rb_ary_new2(argc - 2);
+#ifdef RUBY_VM
+#else
RARRAY(args)->len = 0;
+#endif
for(i = 3; i < argc; i++) {
#if TCL_MAJOR_VERSION >= 8
str = Tcl_GetStringFromObj(argv[i], &len);
DUMP2("arg:%s",str);
+#ifdef RUBY_VM
+ rb_ary_push(args, rb_tainted_str_new(str, len));
+#else
RARRAY(args)->ptr[RARRAY(args)->len++] = rb_tainted_str_new(str, len);
+#endif
#else /* TCL_MAJOR_VERSION < 8 */
DUMP2("arg:%s",argv[i]);
+#ifdef RUBY_VM
+ rb_ary_push(args, rb_tainted_str_new2(argv[i]));
+#else
RARRAY(args)->ptr[RARRAY(args)->len++] = rb_tainted_str_new2(argv[i]);
#endif
+#endif
}
if (old_gc == Qfalse) rb_gc_enable();
rb_thread_critical = thr_crit_bup;
+ /* allocate */
+ arg = ALLOC(struct cmd_body_arg);
+ /* arg = (struct cmd_body_arg *)ckalloc(sizeof(struct cmd_body_arg)); */
+
arg->receiver = receiver;
arg->method = method;
arg->args = args;
@@ -2622,6 +3251,7 @@ ip_ruby_cmd(clientData, interp, argc, argv)
code = tcl_protect(interp, ip_ruby_cmd_core, (VALUE)arg);
free(arg);
+ /* ckfree((char*)arg); */
return code;
}
@@ -2799,10 +3429,20 @@ ip_rbUpdateCommand(clientData, interp, objc, objv)
return TCL_ERROR;
}
#ifdef HAVE_NATIVETHREAD
+#ifdef RUBY_VM
+#if 0
+ if (!ruby_native_thread_p()) {
+ rb_bug("cross-thread violation on ip_ruby_eval()");
+ }
+#endif
+#else
if (!is_ruby_native_thread()) {
rb_bug("cross-thread violation on ip_ruby_eval()");
}
#endif
+#endif
+
+ Tcl_ResetResult(interp);
if (objc == 1) {
flags = TCL_DONT_WAIT;
@@ -2946,10 +3586,18 @@ ip_rb_threadUpdateCommand(clientData, interp, objc, objv)
return TCL_ERROR;
}
#ifdef HAVE_NATIVETHREAD
+#ifdef RUBY_VM
+#if 0
+ if (!ruby_native_thread_p()) {
+ rb_bug("cross-thread violation on ip_rb_threadUpdateCommand()");
+ }
+#endif
+#else
if (!is_ruby_native_thread()) {
- rb_bug("cross-thread violation on ip_ruby_eval()");
+ rb_bug("cross-thread violation on ip_rb_threadUpdateCommand()");
}
#endif
+#endif
if (rb_thread_alone()
|| NIL_P(eventloop_thread) || eventloop_thread == current_thread) {
@@ -2964,6 +3612,8 @@ ip_rb_threadUpdateCommand(clientData, interp, objc, objv)
DUMP1("start Ruby's 'thread_update' body");
+ Tcl_ResetResult(interp);
+
if (objc == 1) {
flags = TCL_DONT_WAIT;
@@ -3010,8 +3660,11 @@ ip_rb_threadUpdateCommand(clientData, interp, objc, objv)
DUMP1("pass argument check");
- param = (struct th_update_param *)Tcl_Alloc(sizeof(struct th_update_param));
- Tcl_Preserve(param);
+ /* param = (struct th_update_param *)Tcl_Alloc(sizeof(struct th_update_param)); */
+ param = (struct th_update_param *)ckalloc(sizeof(struct th_update_param));
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)param);
+#endif
param->thread = current_thread;
param->done = 0;
@@ -3020,11 +3673,20 @@ ip_rb_threadUpdateCommand(clientData, interp, objc, objv)
while(!param->done) {
DUMP1("wait for complete idle proc");
- rb_thread_stop();
+ /* rb_thread_stop(); */
+ rb_thread_sleep_forever();
}
- Tcl_Release(param);
- Tcl_Free((char *)param);
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)param);
+#else
+ /* Tcl_Free((char *)param); */
+ ckfree((char *)param);
+#endif
+#endif
DUMP1("finish Ruby's 'thread_update'");
return TCL_OK;
@@ -3123,10 +3785,20 @@ ip_rbVwaitCommand(clientData, interp, objc, objv)
Tcl_Preserve(interp);
#ifdef HAVE_NATIVETHREAD
+#ifdef RUBY_VM
+#if 0
+ if (!ruby_native_thread_p()) {
+ rb_bug("cross-thread violation on ip_rbVwaitCommand()");
+ }
+#endif
+#else
if (!is_ruby_native_thread()) {
- rb_bug("cross-thread violation on ip_ruby_eval()");
+ rb_bug("cross-thread violation on ip_rbVwaitCommand()");
}
#endif
+#endif
+
+ Tcl_ResetResult(interp);
if (objc != 2) {
#ifdef Tcl_WrongNumArgs
@@ -3363,6 +4035,7 @@ ip_rbTkWaitCommand(clientData, interp, objc, objv)
#endif
Tcl_Preserve(interp);
+ Tcl_ResetResult(interp);
if (objc != 3) {
#ifdef Tcl_WrongNumArgs
@@ -3516,6 +4189,7 @@ ip_rbTkWaitCommand(clientData, interp, objc, objv)
thr_crit_bup = rb_thread_critical;
rb_thread_critical = Qtrue;
+ /* This function works on the Tk eventloop thread only. */
if (!tk_stubs_init_p() || Tk_MainWindow(interp) == (Tk_Window)NULL) {
window = NULL;
} else {
@@ -3523,7 +4197,7 @@ ip_rbTkWaitCommand(clientData, interp, objc, objv)
}
if (window == NULL) {
- Tcl_AppendResult(interp, "tkwait: ",
+ Tcl_AppendResult(interp, ": tkwait: ",
"no main-window (not Tk application?)",
(char*)NULL);
rb_thread_critical = thr_crit_bup;
@@ -3612,7 +4286,8 @@ ip_rbTkWaitCommand(clientData, interp, objc, objv)
case TKWAIT_WINDOW:
thr_crit_bup = rb_thread_critical;
rb_thread_critical = Qtrue;
-
+
+ /* This function works on the Tk eventloop thread only. */
if (!tk_stubs_init_p() || Tk_MainWindow(interp) == (Tk_Window)NULL) {
window = NULL;
} else {
@@ -3624,7 +4299,7 @@ ip_rbTkWaitCommand(clientData, interp, objc, objv)
#endif
if (window == NULL) {
- Tcl_AppendResult(interp, "tkwait: ",
+ Tcl_AppendResult(interp, ": tkwait: ",
"no main-window (not Tk application?)",
(char*)NULL);
rb_thread_critical = thr_crit_bup;
@@ -3717,7 +4392,7 @@ rb_threadVwaitProc(clientData, interp, name1, name2, flags)
} else {
param->done = 1;
}
- rb_thread_wakeup(param->thread);
+ if (param->done != 0) rb_thread_wakeup(param->thread);
return (char *)NULL;
}
@@ -3739,7 +4414,7 @@ rb_threadWaitVisibilityProc(clientData, eventPtr)
if (eventPtr->type == DestroyNotify) {
param->done = TKWAIT_MODE_DESTROY;
}
- rb_thread_wakeup(param->thread);
+ if (param->done != 0) rb_thread_wakeup(param->thread);
}
static void rb_threadWaitWindowProc _((ClientData, XEvent *));
@@ -3753,7 +4428,7 @@ rb_threadWaitWindowProc(clientData, eventPtr)
if (eventPtr->type == DestroyNotify) {
param->done = TKWAIT_MODE_DESTROY;
}
- rb_thread_wakeup(param->thread);
+ if (param->done != 0) rb_thread_wakeup(param->thread);
}
#if TCL_MAJOR_VERSION >= 8
@@ -3796,6 +4471,7 @@ ip_rb_threadVwaitCommand(clientData, interp, objc, objv)
}
Tcl_Preserve(interp);
+ Tcl_ResetResult(interp);
if (objc != 2) {
#ifdef Tcl_WrongNumArgs
@@ -3830,8 +4506,11 @@ ip_rb_threadVwaitCommand(clientData, interp, objc, objv)
thr_crit_bup = rb_thread_critical;
rb_thread_critical = Qtrue;
- param = (struct th_vwait_param *)Tcl_Alloc(sizeof(struct th_vwait_param));
- Tcl_Preserve(param);
+ /* param = (struct th_vwait_param *)Tcl_Alloc(sizeof(struct th_vwait_param)); */
+ param = (struct th_vwait_param *)ckalloc(sizeof(struct th_vwait_param));
+#if 1 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)param);
+#endif
param->thread = current_thread;
param->done = 0;
@@ -3849,8 +4528,16 @@ ip_rb_threadVwaitCommand(clientData, interp, objc, objv)
rb_thread_critical = thr_crit_bup;
if (ret != TCL_OK) {
- Tcl_Release(param);
- Tcl_Free((char *)param);
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 1 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)param);
+#else
+ /* Tcl_Free((char *)param); */
+ ckfree((char *)param);
+#endif
+#endif
#if TCL_MAJOR_VERSION >= 8
Tcl_DecrRefCount(objv[1]);
@@ -3859,9 +4546,9 @@ ip_rb_threadVwaitCommand(clientData, interp, objc, objv)
return TCL_ERROR;
}
- /* if (!param->done) { */
while(!param->done) {
- rb_thread_stop();
+ /* rb_thread_stop(); */
+ rb_thread_sleep_forever();
}
thr_crit_bup = rb_thread_critical;
@@ -3873,8 +4560,16 @@ ip_rb_threadVwaitCommand(clientData, interp, objc, objv)
rb_threadVwaitProc, (ClientData) param);
}
- Tcl_Release(param);
- Tcl_Free((char *)param);
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 1 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)param);
+#else
+ /* Tcl_Free((char *)param); */
+ ckfree((char *)param);
+#endif
+#endif
rb_thread_critical = thr_crit_bup;
@@ -3933,6 +4628,8 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv)
Tcl_Preserve(interp);
Tcl_Preserve(tkwin);
+ Tcl_ResetResult(interp);
+
if (objc != 3) {
#ifdef Tcl_WrongNumArgs
Tcl_WrongNumArgs(interp, 1, objv, "variable|visibility|window name");
@@ -4015,8 +4712,11 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv)
nameString = objv[2];
#endif
- param = (struct th_vwait_param *)Tcl_Alloc(sizeof(struct th_vwait_param));
- Tcl_Preserve(param);
+ /* param = (struct th_vwait_param *)Tcl_Alloc(sizeof(struct th_vwait_param)); */
+ param = (struct th_vwait_param *)ckalloc(sizeof(struct th_vwait_param));
+#if 1 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)param);
+#endif
param->thread = current_thread;
param->done = 0;
@@ -4040,8 +4740,16 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv)
rb_thread_critical = thr_crit_bup;
if (ret != TCL_OK) {
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 1 /* use Tcl_Preserve/Release */
Tcl_Release(param);
- Tcl_Free((char *)param);
+#else
+ /* Tcl_Free((char *)param); */
+ ckfree((char *)param);
+#endif
+#endif
#if TCL_MAJOR_VERSION >= 8
Tcl_DecrRefCount(objv[2]);
@@ -4052,9 +4760,9 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv)
return TCL_ERROR;
}
- /* if (!param->done) { */
while(!param->done) {
- rb_thread_stop();
+ /* rb_thread_stop(); */
+ rb_thread_sleep_forever();
}
thr_crit_bup = rb_thread_critical;
@@ -4078,21 +4786,43 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv)
thr_crit_bup = rb_thread_critical;
rb_thread_critical = Qtrue;
+#if 0 /* variable 'tkwin' must keep the token of MainWindow */
if (!tk_stubs_init_p() || Tk_MainWindow(interp) == (Tk_Window)NULL) {
window = NULL;
} else {
window = Tk_NameToWindow(interp, nameString, tkwin);
}
+#else
+ if (!tk_stubs_init_p() || tkwin == (Tk_Window)NULL) {
+ window = NULL;
+ } else {
+ /* Tk_NameToWindow() returns right token on non-eventloop thread */
+ Tcl_CmdInfo info;
+ if (Tcl_GetCommandInfo(interp, ".", &info)) { /* check root */
+ window = Tk_NameToWindow(interp, nameString, tkwin);
+ } else {
+ window = NULL;
+ }
+ }
+#endif
if (window == NULL) {
- Tcl_AppendResult(interp, "thread_tkwait: ",
+ Tcl_AppendResult(interp, ": thread_tkwait: ",
"no main-window (not Tk application?)",
(char*)NULL);
rb_thread_critical = thr_crit_bup;
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 1 /* use Tcl_Preserve/Release */
Tcl_Release(param);
- Tcl_Free((char *)param);
+#else
+ /* Tcl_Free((char *)param); */
+ ckfree((char *)param);
+#endif
+#endif
#if TCL_MAJOR_VERSION >= 8
Tcl_DecrRefCount(objv[2]);
@@ -4109,15 +4839,10 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv)
rb_thread_critical = thr_crit_bup;
- /* if (!param->done) { */
- /*
- while(!param->done) {
- rb_thread_stop();
- }
- */
while(param->done != TKWAIT_MODE_VISIBILITY) {
if (param->done == TKWAIT_MODE_DESTROY) break;
- rb_thread_stop();
+ /* rb_thread_stop(); */
+ rb_thread_sleep_forever();
}
thr_crit_bup = rb_thread_critical;
@@ -4141,8 +4866,16 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv)
Tcl_Release(window);
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 1 /* use Tcl_Preserve/Release */
Tcl_Release(param);
- Tcl_Free((char *)param);
+#else
+ /* Tcl_Free((char *)param); */
+ ckfree((char *)param);
+#endif
+#endif
#if TCL_MAJOR_VERSION >= 8
Tcl_DecrRefCount(objv[2]);
@@ -4167,25 +4900,47 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv)
thr_crit_bup = rb_thread_critical;
rb_thread_critical = Qtrue;
+#if 0 /* variable 'tkwin' must keep the token of MainWindow */
if (!tk_stubs_init_p() || Tk_MainWindow(interp) == (Tk_Window)NULL) {
window = NULL;
} else {
window = Tk_NameToWindow(interp, nameString, tkwin);
}
+#else
+ if (!tk_stubs_init_p() || tkwin == (Tk_Window)NULL) {
+ window = NULL;
+ } else {
+ /* Tk_NameToWindow() returns right token on non-eventloop thread */
+ Tcl_CmdInfo info;
+ if (Tcl_GetCommandInfo(interp, ".", &info)) { /* check root */
+ window = Tk_NameToWindow(interp, nameString, tkwin);
+ } else {
+ window = NULL;
+ }
+ }
+#endif
#if TCL_MAJOR_VERSION >= 8
Tcl_DecrRefCount(objv[2]);
#endif
if (window == NULL) {
- Tcl_AppendResult(interp, "thread_tkwait: ",
+ Tcl_AppendResult(interp, ": thread_tkwait: ",
"no main-window (not Tk application?)",
(char*)NULL);
rb_thread_critical = thr_crit_bup;
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 1 /* use Tcl_Preserve/Release */
Tcl_Release(param);
- Tcl_Free((char *)param);
+#else
+ /* Tcl_Free((char *)param); */
+ ckfree((char *)param);
+#endif
+#endif
Tcl_Release(tkwin);
Tcl_Release(interp);
@@ -4199,14 +4954,9 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv)
rb_thread_critical = thr_crit_bup;
- /* if (!param->done) { */
- /*
- while(!param->done) {
- rb_thread_stop();
- }
- */
while(param->done != TKWAIT_MODE_DESTROY) {
- rb_thread_stop();
+ /* rb_thread_stop(); */
+ rb_thread_sleep_forever();
}
Tcl_Release(window);
@@ -4224,8 +4974,16 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv)
break;
} /* end of 'switch' statement */
- Tcl_Release(param);
- Tcl_Free((char *)param);
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 1 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)param);
+#else
+ /* Tcl_Free((char *)param); */
+ ckfree((char *)param);
+#endif
+#endif
/*
* Clear out the interpreter's result, since it may have been set
@@ -4250,7 +5008,7 @@ ip_thread_vwait(self, var)
argv[0] = cmd_str;
argv[1] = var;
- return ip_invoke_real(2, argv, self);
+ return ip_invoke_with_position(2, argv, self, TCL_QUEUE_TAIL);
}
static VALUE
@@ -4266,7 +5024,7 @@ ip_thread_tkwait(self, mode, target)
argv[1] = mode;
argv[2] = target;
- return ip_invoke_real(3, argv, self);
+ return ip_invoke_with_position(3, argv, self, TCL_QUEUE_TAIL);
}
@@ -4456,23 +5214,43 @@ ip_finalize(ip)
Tcl_CreateCommand(ip, "ruby_cmd", ip_null_proc,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
#endif
+ /*
+ rb_thread_critical = thr_crit_bup;
+ return;
+ */
}
/* delete root widget */
-#if 0
+#if 1
DUMP1("check `destroy'");
if (Tcl_GetCommandInfo(ip, "destroy", &info)) {
- DUMP1("call `destroy'");
- Tcl_GlobalEval(ip, "destroy .");
+ DUMP1("call `destroy .'");
+ Tcl_GlobalEval(ip, "catch {destroy .}");
}
#endif
#if 1
DUMP1("destroy root widget");
if (tk_stubs_init_p() && Tk_MainWindow(ip) != (Tk_Window)NULL) {
+ /*
+ * On Ruby VM, this code piece may be not called, because
+ * Tk_MainWindow() returns NULL on a native thread except
+ * the thread which initialize Tk environment.
+ * Of course, that is a problem. But maybe not so serious.
+ * All widgets are destroyed when the Tcl interp is deleted.
+ * At then, Ruby may raise exceptions on the delete hook
+ * callbacks which registered for the deleted widgets, and
+ * may fail to clear objects which depends on the widgets.
+ * Although it is the problem, it is possibly avoidable by
+ * rescuing exceptions and the finalize hook of the interp.
+ */
+ Tk_Window win = Tk_MainWindow(ip);
+
DUMP1("call Tk_DestroyWindow");
ruby_debug = Qfalse;
ruby_verbose = Qnil;
- Tk_DestroyWindow(Tk_MainWindow(ip));
+ if (! (((Tk_FakeWin*)win)->flags & TK_ALREADY_DEAD)) {
+ Tk_DestroyWindow(win);
+ }
ruby_debug = rb_debug_bup;
ruby_verbose = rb_verbose_bup;
}
@@ -4495,7 +5273,7 @@ ip_finalize(ip)
DUMP1("cancel after callbacks");
ruby_debug = Qfalse;
ruby_verbose = Qnil;
- Tcl_GlobalEval(ip, "foreach id [after info] {after cancel $id}");
+ Tcl_GlobalEval(ip, "catch {foreach id [after info] {after cancel $id}}");
ruby_debug = rb_debug_bup;
ruby_verbose = rb_verbose_bup;
}
@@ -4530,6 +5308,7 @@ ip_free(ptr)
DUMP2("slave IP(%lx) should not be deleted",
(unsigned long)ptr->ip);
free(ptr);
+ /* ckfree((char*)ptr); */
rb_thread_critical = thr_crit_bup;
return;
}
@@ -4537,6 +5316,7 @@ ip_free(ptr)
if (ptr->ip == (Tcl_Interp*)NULL) {
DUMP1("ip_free is called for deleted IP");
free(ptr);
+ /* ckfree((char*)ptr); */
rb_thread_critical = thr_crit_bup;
return;
}
@@ -4547,6 +5327,7 @@ ip_free(ptr)
ptr->ip = (Tcl_Interp*)NULL;
free(ptr);
+ /* ckfree((char*)ptr); */
rb_thread_critical = thr_crit_bup;
}
@@ -4668,7 +5449,11 @@ ip_rbNamespaceObjCmd(clientData, interp, objc, objv)
int i;
char **argv;
- argv = (char **)Tcl_Alloc(sizeof(char *) * (objc + 1));
+ /* argv = (char **)Tcl_Alloc(sizeof(char *) * (objc + 1)); */
+ argv = (char **)ckalloc(sizeof(char *) * (objc + 1));
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)argv); /* XXXXXXXX */
+#endif
for(i = 0; i < objc; i++) {
/* argv[i] = Tcl_GetString(objv[i]); */
@@ -4679,7 +5464,16 @@ ip_rbNamespaceObjCmd(clientData, interp, objc, objv)
ret = (*(info.proc))(info.clientData, interp,
objc, (CONST84 char **)argv);
- Tcl_Free((char*)argv);
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)argv); /* XXXXXXXX */
+#else
+ /* Tcl_Free((char*)argv); */
+ ckfree((char*)argv);
+#endif
+#endif
}
DUMP2("namespace wrapper exit depth == %d", rbtk_eventloop_depth);
@@ -4750,16 +5544,29 @@ ip_init(argc, argv, self)
Tk_Window mainWin = (Tk_Window)NULL;
/* security check */
+#ifdef RUBY_VM
+ if (rb_safe_level() >= 4) {
+#else
if (ruby_safe_level >= 4) {
+#endif
rb_raise(rb_eSecurityError,
"Cannot create a TclTkIp object at level %d",
- ruby_safe_level);
+#ifdef RUBY_VM
+ rb_safe_level()
+#else
+ ruby_safe_level
+#endif
+ );
}
/* create object */
Data_Get_Struct(self, struct tcltkip, ptr);
ptr = ALLOC(struct tcltkip);
+ /* ptr = (struct tcltkip *)ckalloc(sizeof(struct tcltkip)); */
DATA_PTR(self) = ptr;
+#ifdef RUBY_VM
+ ptr->tk_thread_id = 0;
+#endif
ptr->ref_count = 0;
ptr->allow_ruby_exit = 1;
ptr->return_value = 0;
@@ -4867,6 +5674,10 @@ ip_init(argc, argv, self)
(Tcl_PackageInitProc *) NULL);
#endif
+#ifdef RUBY_VM
+ /* set Tk thread ID */
+ ptr->tk_thread_id = Tcl_GetCurrentThread();
+#endif
/* get main window */
mainWin = Tk_MainWindow(ptr->ip);
Tk_Preserve((ClientData)mainWin);
@@ -4942,6 +5753,7 @@ ip_create_slave_core(interp, argc, argv)
{
struct tcltkip *master = get_ip(interp);
struct tcltkip *slave = ALLOC(struct tcltkip);
+ /* struct tcltkip *slave = (struct tcltkip *)ckalloc(sizeof(struct tcltkip)); */
VALUE safemode;
VALUE name;
int safe;
@@ -4984,6 +5796,10 @@ ip_create_slave_core(interp, argc, argv)
#endif
/* create slave-ip */
+#ifdef RUBY_VM
+ /* slave->tk_thread_id = 0; */
+ slave->tk_thread_id = master->tk_thread_id; /* == current thread */
+#endif
slave->ref_count = 0;
slave->allow_ruby_exit = 0;
slave->return_value = 0;
@@ -5272,6 +6088,12 @@ ip_allow_ruby_exit_set(self, val)
"insecure operation on a safe interpreter");
}
+ /*
+ * Because of cross-threading, the following line may fail to find
+ * the MainWindow, even if the Tcl/Tk interpreter has one or more.
+ * But it has no problem. Current implementation of both type of
+ * the "exit" command don't need maiinWin token.
+ */
mainWin = (tk_stubs_init_p())? Tk_MainWindow(ptr->ip): (Tk_Window)NULL;
if (RTEST(val)) {
@@ -5368,8 +6190,10 @@ ip_is_deleted_p(self)
}
static VALUE
-ip_has_mainwindow_p(self)
+ip_has_mainwindow_p_core(self, argc, argv)
VALUE self;
+ int argc; /* dummy */
+ VALUE *argv; /* dummy */
{
struct tcltkip *ptr = get_ip(self);
@@ -5382,6 +6206,14 @@ ip_has_mainwindow_p(self)
}
}
+static VALUE
+ip_has_mainwindow_p(self)
+ VALUE self;
+{
+ return tk_funcall(ip_has_mainwindow_p_core, 0, (VALUE*)NULL, self);
+}
+
+
/*** ruby string <=> tcl object ***/
#if TCL_MAJOR_VERSION >= 8
static VALUE
@@ -5391,10 +6223,16 @@ get_str_from_obj(obj)
int len, binary = 0;
const char *s;
volatile VALUE str;
+#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 4)
+ int len2;
+ const char *s2;
+#endif
#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0
s = Tcl_GetStringFromObj(obj, &len);
-#else /* TCL_VERSION >= 8.1 */
+#else
+#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION <= 3
+ /* TCL_VERSION 8.1 -- 8.3 */
if (Tcl_GetCharLength(obj) != Tcl_UniCharLen(Tcl_GetUnicode(obj))) {
/* possibly binary string */
s = Tcl_GetByteArrayFromObj(obj, &len);
@@ -5403,9 +6241,30 @@ get_str_from_obj(obj)
/* possibly text string */
s = Tcl_GetStringFromObj(obj, &len);
}
+#else /* TCL_VERSION >= 8.4 */
+ if (IS_TCL_BYTEARRAY(obj)) {
+ s = Tcl_GetByteArrayFromObj(obj, &len);
+ binary = 1;
+ } else {
+ s = Tcl_GetStringFromObj(obj, &len);
+ }
+
+#endif
#endif
str = s ? rb_str_new(s, len) : rb_str_new2("");
- if (binary) rb_ivar_set(str, ID_at_enc, rb_str_new2("binary"));
+ if (binary) {
+#ifdef RUBY_VM
+ rb_enc_associate_index(str, ENCODING_INDEX_BINARY);
+#endif
+ rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY);
+#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1)
+ } else {
+#ifdef RUBY_VM
+ rb_enc_associate_index(str, ENCODING_INDEX_UTF8);
+#endif
+ rb_ivar_set(str, ID_at_enc, ENCODING_NAME_UTF8);
+#endif
+ }
return str;
}
@@ -5416,25 +6275,30 @@ get_obj_from_str(str)
const char *s = StringValuePtr(str);
#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0
- return Tcl_NewStringObj((char*)s, RSTRING(str)->len);
+ return Tcl_NewStringObj((char*)s, RSTRING_LEN(str));
#else /* TCL_VERSION >= 8.1 */
VALUE enc = rb_attr_get(str, ID_at_enc);
if (!NIL_P(enc)) {
StringValue(enc);
- if (strcmp(RSTRING(enc)->ptr, "binary") == 0) {
+ if (strcmp(RSTRING_PTR(enc), "binary") == 0) {
/* binary string */
- return Tcl_NewByteArrayObj(s, RSTRING(str)->len);
+ return Tcl_NewByteArrayObj(s, RSTRING_LEN(str));
} else {
/* text string */
- return Tcl_NewStringObj(s, RSTRING(str)->len);
+ return Tcl_NewStringObj(s, RSTRING_LEN(str));
}
- } else if (strlen(s) != RSTRING(str)->len) {
+#ifdef RUBY_VM
+ } else if (rb_enc_get_index(str) == ENCODING_INDEX_BINARY) {
+ /* binary string */
+ return Tcl_NewByteArrayObj(s, RSTRING_LEN(str));
+#endif
+ } else if (strlen(s) != RSTRING_LEN(str)) {
/* probably binary string */
- return Tcl_NewByteArrayObj(s, RSTRING(str)->len);
+ return Tcl_NewByteArrayObj(s, RSTRING_LEN(str));
} else {
/* probably text string */
- return Tcl_NewStringObj(s, RSTRING(str)->len);
+ return Tcl_NewStringObj(s, RSTRING_LEN(str));
}
#endif
}
@@ -5452,6 +6316,7 @@ ip_get_result_string_obj(interp)
Tcl_IncrRefCount(retObj);
strval = get_str_from_obj(retObj);
OBJ_TAINT(strval);
+ Tcl_ResetResult(interp);
Tcl_DecrRefCount(retObj);
return strval;
#else
@@ -5482,11 +6347,12 @@ call_queue_handler(evPtr, flags)
struct call_queue *q = (struct call_queue *)evPtr;
volatile VALUE ret;
volatile VALUE q_dat;
+ volatile VALUE thread = q->thread;
struct tcltkip *ptr;
DUMP2("do_call_queue_handler : evPtr = %p", evPtr);
- DUMP2("queue_handler thread : %lx", rb_thread_current());
- DUMP2("added by thread : %lx", q->thread);
+ DUMP2("call_queue_handler thread : %lx", rb_thread_current());
+ DUMP2("added by thread : %lx", thread);
if (*(q->done)) {
DUMP1("processed by another event-loop");
@@ -5495,6 +6361,12 @@ call_queue_handler(evPtr, flags)
DUMP1("process it on current event-loop");
}
+ if (RTEST(rb_thread_alive_p(thread))
+ && ! RTEST(rb_funcall(thread, ID_stop_p, 0))) {
+ DUMP1("caller is not yet ready to receive the result -> pending");
+ return 0;
+ }
+
/* process it */
*(q->done) = 1;
@@ -5505,33 +6377,56 @@ call_queue_handler(evPtr, flags)
return 1;
}
+ /* incr internal handler mark */
+ rbtk_internal_eventloop_handler++;
+
/* check safe-level */
if (rb_safe_level() != q->safe_level) {
- /* q_dat = Data_Wrap_Struct(rb_cData,0,0,q); */
- q_dat = Data_Wrap_Struct(rb_cData,call_queue_mark,0,q);
+ /* q_dat = Data_Wrap_Struct(rb_cData,0,-1,q); */
+ q_dat = Data_Wrap_Struct(rb_cData,call_queue_mark,-1,q);
ret = rb_funcall(rb_proc_new(callq_safelevel_handler, q_dat),
ID_call, 0);
rb_gc_force_recycle(q_dat);
+ q_dat = (VALUE)NULL;
} else {
- DUMP2("call function (for caller thread:%lx)", q->thread);
+ DUMP2("call function (for caller thread:%lx)", thread);
DUMP2("call function (current thread:%lx)", rb_thread_current());
ret = (q->func)(q->interp, q->argc, q->argv);
}
/* set result */
- RARRAY(q->result)->ptr[0] = ret;
+ RARRAY_PTR(q->result)[0] = ret;
+ ret = (VALUE)NULL;
+
+ /* decr internal handler mark */
+ rbtk_internal_eventloop_handler--;
/* complete */
*(q->done) = -1;
+ /* unlink ruby objects */
+ q->argv = (VALUE*)NULL;
+ q->interp = (VALUE)NULL;
+ q->result = (VALUE)NULL;
+ q->thread = (VALUE)NULL;
+
/* back to caller */
- if (RTEST(rb_funcall(q->thread, ID_alive_p, 0, 0))) {
- DUMP2("back to caller (caller thread:%lx)", q->thread);
+ /* if (RTEST(rb_funcall(thread, ID_alive_p, 0, 0))) { */
+ if (RTEST(rb_thread_alive_p(thread))) {
+ DUMP2("back to caller (caller thread:%lx)", thread);
DUMP2(" (current thread:%lx)", rb_thread_current());
- rb_thread_run(q->thread);
+#if CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE
+ have_rb_thread_waiting_for_value = 1;
+ rb_thread_wakeup(thread);
+#else
+ rb_thread_run(thread);
+#endif
DUMP1("finish back to caller");
+#if DO_THREAD_SCHEDULE_AT_CALLBACK_DONE
+ rb_thread_schedule();
+#endif
} else {
- DUMP2("caller is dead (caller thread:%lx)", q->thread);
+ DUMP2("caller is dead (caller thread:%lx)", thread);
DUMP2(" (current thread:%lx)", rb_thread_current());
}
@@ -5547,19 +6442,39 @@ tk_funcall(func, argc, argv, obj)
VALUE obj;
{
struct call_queue *callq;
+ struct tcltkip *ptr;
int *alloc_done;
int thr_crit_bup;
+ int is_tk_evloop_thread;
volatile VALUE current = rb_thread_current();
volatile VALUE ip_obj = obj;
volatile VALUE result;
volatile VALUE ret;
+ if (!NIL_P(ip_obj) && rb_obj_is_kind_of(ip_obj, tcltkip_class)) {
+ ptr = get_ip(ip_obj);
+ if (deleted_ip(ptr)) return Qnil;
+ } else {
+ ptr = (struct tcltkip *)NULL;
+ }
- if (!NIL_P(ip_obj) && deleted_ip(get_ip(ip_obj))) {
- return Qnil;
+#ifdef RUBY_VM
+ if (ptr) {
+ /* on Tcl interpreter */
+ is_tk_evloop_thread = (ptr->tk_thread_id == (Tcl_ThreadId) 0
+ || ptr->tk_thread_id == Tcl_GetCurrentThread());
+ } else {
+ /* on Tcl/Tk library */
+ is_tk_evloop_thread = (tk_eventloop_thread_id == (Tcl_ThreadId) 0
+ || tk_eventloop_thread_id == Tcl_GetCurrentThread());
}
+#else
+ is_tk_evloop_thread = 1;
+#endif
- if (NIL_P(eventloop_thread) || current == eventloop_thread) {
+ if (is_tk_evloop_thread
+ && (NIL_P(eventloop_thread) || current == eventloop_thread)
+ ) {
if (NIL_P(eventloop_thread)) {
DUMP2("tk_funcall from thread:%lx but no eventloop", current);
} else {
@@ -5579,23 +6494,32 @@ tk_funcall(func, argc, argv, obj)
/* allocate memory (argv cross over thread : must be in heap) */
if (argv) {
- VALUE *temp = ALLOC_N(VALUE, argc);
+ /* VALUE *temp = ALLOC_N(VALUE, argc); */
+ VALUE *temp = (VALUE*)ckalloc(sizeof(VALUE) * argc);
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)temp); /* XXXXXXXX */
+#endif
MEMCPY(temp, argv, VALUE, argc);
argv = temp;
}
/* allocate memory (keep result) */
- alloc_done = (int*)ALLOC(int);
+ /* alloc_done = (int*)ALLOC(int); */
+ alloc_done = (int*)ckalloc(sizeof(int));
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)alloc_done); /* XXXXXXXX */
+#endif
*alloc_done = 0;
/* allocate memory (freed by Tcl_ServiceEvent) */
- callq = (struct call_queue *)Tcl_Alloc(sizeof(struct call_queue));
+ /* callq = (struct call_queue *)Tcl_Alloc(sizeof(struct call_queue)); */
+ callq = (struct call_queue *)ckalloc(sizeof(struct call_queue));
+#if 0 /* use Tcl_Preserve/Release */
Tcl_Preserve(callq);
+#endif
/* allocate result obj */
- result = rb_ary_new2(1);
- RARRAY(result)->ptr[0] = Qnil;
- RARRAY(result)->len = 1;
+ result = rb_ary_new3(1, Qnil);
/* construct event data */
callq->done = alloc_done;
@@ -5610,28 +6534,83 @@ tk_funcall(func, argc, argv, obj)
/* add the handler to Tcl event queue */
DUMP1("add handler");
- Tcl_QueueEvent(&(callq->ev), TCL_QUEUE_HEAD);
+#ifdef RUBY_VM
+ if (ptr && ptr->tk_thread_id) {
+ /* Tcl_ThreadQueueEvent(ptr->tk_thread_id,
+ &(callq->ev), TCL_QUEUE_HEAD); */
+ Tcl_ThreadQueueEvent(ptr->tk_thread_id,
+ (Tcl_Event*)callq, TCL_QUEUE_HEAD);
+ Tcl_ThreadAlert(ptr->tk_thread_id);
+ } else if (tk_eventloop_thread_id) {
+ /* Tcl_ThreadQueueEvent(tk_eventloop_thread_id,
+ &(callq->ev), TCL_QUEUE_HEAD); */
+ Tcl_ThreadQueueEvent(tk_eventloop_thread_id,
+ (Tcl_Event*)callq, TCL_QUEUE_HEAD);
+ Tcl_ThreadAlert(tk_eventloop_thread_id);
+ } else {
+ /* Tcl_QueueEvent(&(callq->ev), TCL_QUEUE_HEAD); */
+ Tcl_QueueEvent((Tcl_Event*)callq, TCL_QUEUE_HEAD);
+ }
+#else
+ /* Tcl_QueueEvent(&(callq->ev), TCL_QUEUE_HEAD); */
+ Tcl_QueueEvent((Tcl_Event*)callq, TCL_QUEUE_HEAD);
+#endif
rb_thread_critical = thr_crit_bup;
/* wait for the handler to be processed */
DUMP2("wait for handler (current thread:%lx)", current);
while(*alloc_done >= 0) {
- rb_thread_stop();
+ DUMP2("*** wait for handler (current thread:%lx)", current);
+ /* rb_thread_stop(); */
+ rb_thread_sleep_forever();
+ DUMP2("*** wakeup (current thread:%lx)", current);
}
DUMP2("back from handler (current thread:%lx)", current);
/* get result & free allocated memory */
- ret = RARRAY(result)->ptr[0];
- free(alloc_done);
- if (argv) free(argv);
+ ret = RARRAY_PTR(result)[0];
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)alloc_done, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)alloc_done); /* XXXXXXXX */
+#else
+ /* free(alloc_done); */
+ ckfree((char*)alloc_done);
+#endif
+#endif
+ /* if (argv) free(argv); */
+ if (argv) {
+ /* if argv != NULL, alloc as 'temp' */
+ int i;
+ for(i = 0; i < argc; i++) { argv[i] = (VALUE)NULL; }
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)argv); /* XXXXXXXX */
+#else
+ ckfree((char*)argv);
+#endif
+#endif
+ }
+
+#if 0 /* callq is freed by Tcl_ServiceEvent */
+#if 0 /* use Tcl_Preserve/Release */
Tcl_Release(callq);
+#else
+ ckfree((char*)callq);
+#endif
+#endif
/* exception? */
if (rb_obj_is_kind_of(ret, rb_eException)) {
DUMP1("raise exception");
- rb_exc_raise(ret);
+ /* rb_exc_raise(ret); */
+ rb_exc_raise(rb_exc_new3(rb_obj_class(ret),
+ rb_funcall(ret, ID_to_s, 0, 0)));
}
DUMP1("exit tk_funcall");
@@ -5702,19 +6681,35 @@ ip_eval_real(self, cmd_str, cmd_len)
ret = rb_protect(call_tcl_eval, (VALUE)&inf, &status);
switch(status) {
case TAG_RAISE:
+#ifdef RUBY_VM
+ if (NIL_P(rb_errinfo())) {
+#else
if (NIL_P(ruby_errinfo)) {
+#endif
rbtk_pending_exception = rb_exc_new2(rb_eException,
"unknown exception");
} else {
+#ifdef RUBY_VM
+ rbtk_pending_exception = rb_errinfo();
+#else
rbtk_pending_exception = ruby_errinfo;
+#endif
}
break;
case TAG_FATAL:
+#ifdef RUBY_VM
+ if (NIL_P(rb_errinfo())) {
+#else
if (NIL_P(ruby_errinfo)) {
+#endif
rbtk_pending_exception = rb_exc_new2(rb_eFatal, "FATAL");
} else {
+#ifdef RUBY_VM
+ rbtk_pending_exception = rb_errinfo();
+#else
rbtk_pending_exception = ruby_errinfo;
+#endif
}
}
#endif
@@ -5814,6 +6809,12 @@ eval_queue_handler(evPtr, flags)
struct eval_queue *q = (struct eval_queue *)evPtr;
volatile VALUE ret;
volatile VALUE q_dat;
+ volatile VALUE thread = q->thread;
+ struct tcltkip *ptr;
+
+ DUMP2("do_eval_queue_handler : evPtr = %p", evPtr);
+ DUMP2("eval_queue_thread : %lx", rb_thread_current());
+ DUMP2("added by thread : %lx", thread);
if (*(q->done)) {
DUMP1("processed by another event-loop");
@@ -5822,39 +6823,82 @@ eval_queue_handler(evPtr, flags)
DUMP1("process it on current event-loop");
}
+ if (RTEST(rb_thread_alive_p(thread))
+ && ! RTEST(rb_funcall(thread, ID_stop_p, 0))) {
+ DUMP1("caller is not yet ready to receive the result -> pending");
+ return 0;
+ }
+
/* process it */
*(q->done) = 1;
+ /* deleted ipterp ? */
+ ptr = get_ip(q->interp);
+ if (deleted_ip(ptr)) {
+ /* deleted IP --> ignore */
+ return 1;
+ }
+
+ /* incr internal handler mark */
+ rbtk_internal_eventloop_handler++;
+
/* check safe-level */
if (rb_safe_level() != q->safe_level) {
#ifdef HAVE_NATIVETHREAD
- if (!is_ruby_native_thread()) {
- rb_bug("cross-thread violation on eval_queue_handler()");
- }
+#ifdef RUBY_VM
+#if 0
+ if (!ruby_native_thread_p()) {
+ rb_bug("cross-thread violation on eval_queue_handler()");
+ }
#endif
- /* q_dat = Data_Wrap_Struct(rb_cData,0,0,q); */
- q_dat = Data_Wrap_Struct(rb_cData,eval_queue_mark,0,q);
+#else
+ if (!is_ruby_native_thread()) {
+ rb_bug("cross-thread violation on eval_queue_handler()");
+ }
+#endif
+#endif
+ /* q_dat = Data_Wrap_Struct(rb_cData,0,-1,q); */
+ q_dat = Data_Wrap_Struct(rb_cData,eval_queue_mark,-1,q);
ret = rb_funcall(rb_proc_new(evq_safelevel_handler, q_dat),
ID_call, 0);
rb_gc_force_recycle(q_dat);
+ q_dat = (VALUE)NULL;
} else {
ret = ip_eval_real(q->interp, q->str, q->len);
}
/* set result */
- RARRAY(q->result)->ptr[0] = ret;
+ RARRAY_PTR(q->result)[0] = ret;
+ ret = (VALUE)NULL;
+
+ /* decr internal handler mark */
+ rbtk_internal_eventloop_handler--;
/* complete */
*(q->done) = -1;
+ /* unlink ruby objects */
+ q->interp = (VALUE)NULL;
+ q->result = (VALUE)NULL;
+ q->thread = (VALUE)NULL;
+
/* back to caller */
- if (RTEST(rb_funcall(q->thread, ID_alive_p, 0, 0))) {
- DUMP2("back to caller (caller thread:%lx)", q->thread);
+ /* if (RTEST(rb_funcall(thread, ID_alive_p, 0, 0))) { */
+ if (RTEST(rb_thread_alive_p(thread))) {
+ DUMP2("back to caller (caller thread:%lx)", thread);
DUMP2(" (current thread:%lx)", rb_thread_current());
- rb_thread_run(q->thread);
+#if CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE
+ have_rb_thread_waiting_for_value = 1;
+ rb_thread_wakeup(thread);
+#else
+ rb_thread_run(thread);
+#endif
DUMP1("finish back to caller");
+#if DO_THREAD_SCHEDULE_AT_CALLBACK_DONE
+ rb_thread_schedule();
+#endif
} else {
- DUMP2("caller is dead (caller thread:%lx)", q->thread);
+ DUMP2("caller is dead (caller thread:%lx)", thread);
DUMP2(" (current thread:%lx)", rb_thread_current());
}
@@ -5868,6 +6912,9 @@ ip_eval(self, str)
VALUE str;
{
struct eval_queue *evq;
+#ifdef RUBY_VM
+ struct tcltkip *ptr;
+#endif
char *eval_str;
int *alloc_done;
int thr_crit_bup;
@@ -5882,13 +6929,23 @@ ip_eval(self, str)
StringValue(str);
rb_thread_critical = thr_crit_bup;
- if (NIL_P(eventloop_thread) || current == eventloop_thread) {
+#ifdef RUBY_VM
+ ptr = get_ip(ip_obj);
+#endif
+
+ if (
+#ifdef RUBY_VM
+ (ptr->tk_thread_id == 0 || ptr->tk_thread_id == Tcl_GetCurrentThread())
+ &&
+#endif
+ (NIL_P(eventloop_thread) || current == eventloop_thread)
+ ) {
if (NIL_P(eventloop_thread)) {
DUMP2("eval from thread:%lx but no eventloop", current);
} else {
DUMP2("eval from current eventloop %lx", current);
}
- result = ip_eval_real(self, RSTRING(str)->ptr, RSTRING(str)->len);
+ result = ip_eval_real(self, RSTRING_PTR(str), RSTRING_LEN(str));
if (rb_obj_is_kind_of(result, rb_eException)) {
rb_exc_raise(result);
}
@@ -5900,27 +6957,36 @@ ip_eval(self, str)
thr_crit_bup = rb_thread_critical;
rb_thread_critical = Qtrue;
- /* allocate memory (protected from Tcl_ServiceEvent) */
- alloc_done = (int*)ALLOC(int);
+ /* allocate memory (keep result) */
+ /* alloc_done = (int*)ALLOC(int); */
+ alloc_done = (int*)ckalloc(sizeof(int));
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)alloc_done); /* XXXXXXXX */
+#endif
*alloc_done = 0;
- eval_str = ALLOC_N(char, RSTRING(str)->len + 1);
- memcpy(eval_str, RSTRING(str)->ptr, RSTRING(str)->len);
- eval_str[RSTRING(str)->len] = 0;
+ /* eval_str = ALLOC_N(char, RSTRING_LEN(str) + 1); */
+ eval_str = ckalloc(sizeof(char) * (RSTRING_LEN(str) + 1));
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)eval_str); /* XXXXXXXX */
+#endif
+ memcpy(eval_str, RSTRING_PTR(str), RSTRING_LEN(str));
+ eval_str[RSTRING_LEN(str)] = 0;
/* allocate memory (freed by Tcl_ServiceEvent) */
- evq = (struct eval_queue *)Tcl_Alloc(sizeof(struct eval_queue));
+ /* evq = (struct eval_queue *)Tcl_Alloc(sizeof(struct eval_queue)); */
+ evq = (struct eval_queue *)ckalloc(sizeof(struct eval_queue));
+#if 0 /* use Tcl_Preserve/Release */
Tcl_Preserve(evq);
+#endif
/* allocate result obj */
- result = rb_ary_new2(1);
- RARRAY(result)->ptr[0] = Qnil;
- RARRAY(result)->len = 1;
+ result = rb_ary_new3(1, Qnil);
/* construct event data */
evq->done = alloc_done;
evq->str = eval_str;
- evq->len = RSTRING(str)->len;
+ evq->len = RSTRING_LEN(str);
evq->interp = ip_obj;
evq->result = result;
evq->thread = current;
@@ -5931,26 +6997,73 @@ ip_eval(self, str)
/* add the handler to Tcl event queue */
DUMP1("add handler");
- Tcl_QueueEvent(&(evq->ev), position);
+#ifdef RUBY_VM
+ if (ptr->tk_thread_id) {
+ /* Tcl_ThreadQueueEvent(ptr->tk_thread_id, &(evq->ev), position); */
+ Tcl_ThreadQueueEvent(ptr->tk_thread_id, (Tcl_Event*)evq, position);
+ Tcl_ThreadAlert(ptr->tk_thread_id);
+ } else if (tk_eventloop_thread_id) {
+ Tcl_ThreadQueueEvent(tk_eventloop_thread_id, (Tcl_Event*)evq, position);
+ /* Tcl_ThreadQueueEvent(tk_eventloop_thread_id,
+ &(evq->ev), position); */
+ Tcl_ThreadAlert(tk_eventloop_thread_id);
+ } else {
+ /* Tcl_QueueEvent(&(evq->ev), position); */
+ Tcl_QueueEvent((Tcl_Event*)evq, position);
+ }
+#else
+ /* Tcl_QueueEvent(&(evq->ev), position); */
+ Tcl_QueueEvent((Tcl_Event*)evq, position);
+#endif
rb_thread_critical = thr_crit_bup;
/* wait for the handler to be processed */
DUMP2("wait for handler (current thread:%lx)", current);
while(*alloc_done >= 0) {
- rb_thread_stop();
+ DUMP2("*** wait for handler (current thread:%lx)", current);
+ /* rb_thread_stop(); */
+ rb_thread_sleep_forever();
+ DUMP2("*** wakeup (current thread:%lx)", current);
}
DUMP2("back from handler (current thread:%lx)", current);
/* get result & free allocated memory */
- ret = RARRAY(result)->ptr[0];
+ ret = RARRAY_PTR(result)[0];
- free(alloc_done);
- free(eval_str);
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)alloc_done, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)alloc_done); /* XXXXXXXX */
+#else
+ /* free(alloc_done); */
+ ckfree((char*)alloc_done);
+#endif
+#endif
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)eval_str, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)eval_str); /* XXXXXXXX */
+#else
+ /* free(eval_str); */
+ ckfree(eval_str);
+#endif
+#endif
+#if 0 /* evq is freed by Tcl_ServiceEvent */
+#if 0 /* use Tcl_Preserve/Release */
Tcl_Release(evq);
+#else
+ ckfree((char*)evq);
+#endif
+#endif
if (rb_obj_is_kind_of(ret, rb_eException)) {
- rb_exc_raise(ret);
+ DUMP1("raise exception");
+ /* rb_exc_raise(ret); */
+ rb_exc_raise(rb_exc_new3(rb_obj_class(ret),
+ rb_funcall(ret, ID_to_s, 0, 0)));
}
return ret;
@@ -6105,7 +7218,12 @@ lib_toUTF8_core(ip_obj, src, encodename)
if (NIL_P(encodename)) {
if (TYPE(str) == T_STRING) {
volatile VALUE enc;
+
+#ifdef RUBY_VM
+ enc = rb_funcall(rb_obj_encoding(str), ID_to_s, 0, 0);
+#else
enc = rb_attr_get(str, ID_at_enc);
+#endif
if (NIL_P(enc)) {
if (NIL_P(ip_obj)) {
encoding = (Tcl_Encoding)NULL;
@@ -6114,22 +7232,35 @@ lib_toUTF8_core(ip_obj, src, encodename)
if (NIL_P(enc)) {
encoding = (Tcl_Encoding)NULL;
} else {
- StringValue(enc);
- encoding = Tcl_GetEncoding(interp, RSTRING(enc)->ptr);
- if (encoding == (Tcl_Encoding)NULL) {
- rb_warning("Tk-interp has unknown encoding information (@encoding:'%s')", RSTRING(enc)->ptr);
- }
+ /* StringValue(enc); */
+ enc = rb_funcall(enc, ID_to_s, 0, 0);
+ /* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); */
+ if (!RSTRING_LEN(enc)) {
+ encoding = (Tcl_Encoding)NULL;
+ } else {
+ encoding = Tcl_GetEncoding((Tcl_Interp*)NULL,
+ RSTRING_PTR(enc));
+ if (encoding == (Tcl_Encoding)NULL) {
+ rb_warning("Tk-interp has unknown encoding information (@encoding:'%s')", RSTRING_PTR(enc));
+ }
+ }
}
}
} else {
StringValue(enc);
- if (strcmp(RSTRING(enc)->ptr, "binary") == 0) {
+ if (strcmp(RSTRING_PTR(enc), "binary") == 0) {
+#ifdef RUBY_VM
+ rb_enc_associate_index(str, ENCODING_INDEX_BINARY);
+#endif
+ rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY);
rb_thread_critical = thr_crit_bup;
return str;
}
- encoding = Tcl_GetEncoding(interp, RSTRING(enc)->ptr);
+ /* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); */
+ encoding = Tcl_GetEncoding((Tcl_Interp*)NULL,
+ RSTRING_PTR(enc));
if (encoding == (Tcl_Encoding)NULL) {
- rb_warning("string has unknown encoding information (@encoding:'%s')", RSTRING(enc)->ptr);
+ rb_warning("string has unknown encoding information (@encoding:'%s')", RSTRING_PTR(enc));
}
}
} else {
@@ -6137,43 +7268,59 @@ lib_toUTF8_core(ip_obj, src, encodename)
}
} else {
StringValue(encodename);
- encoding = Tcl_GetEncoding(interp, RSTRING(encodename)->ptr);
+ if (strcmp(RSTRING_PTR(encodename), "binary") == 0) {
+#ifdef RUBY_VM
+ rb_enc_associate_index(str, ENCODING_INDEX_BINARY);
+#endif
+ rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY);
+ rb_thread_critical = thr_crit_bup;
+ return str;
+ }
+ /* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(encodename)); */
+ encoding = Tcl_GetEncoding((Tcl_Interp*)NULL, RSTRING_PTR(encodename));
if (encoding == (Tcl_Encoding)NULL) {
/*
rb_warning("unknown encoding name '%s'",
- RSTRING(encodename)->ptr);
+ RSTRING_PTR(encodename));
*/
rb_raise(rb_eArgError, "unknown encoding name '%s'",
- RSTRING(encodename)->ptr);
+ RSTRING_PTR(encodename));
}
}
StringValue(str);
- if (!RSTRING(str)->len) {
+ if (!RSTRING_LEN(str)) {
rb_thread_critical = thr_crit_bup;
return str;
}
- buf = ALLOC_N(char,(RSTRING(str)->len)+1);
- memcpy(buf, RSTRING(str)->ptr, RSTRING(str)->len);
- buf[RSTRING(str)->len] = 0;
+ buf = ALLOC_N(char, RSTRING_LEN(str)+1);
+ /* buf = ckalloc(sizeof(char) * (RSTRING_LEN(str)+1)); */
+ memcpy(buf, RSTRING_PTR(str), RSTRING_LEN(str));
+ buf[RSTRING_LEN(str)] = 0;
Tcl_DStringInit(&dstr);
Tcl_DStringFree(&dstr);
/* Tcl_ExternalToUtfDString(encoding,buf,strlen(buf),&dstr); */
- Tcl_ExternalToUtfDString(encoding, buf, RSTRING(str)->len, &dstr);
+ Tcl_ExternalToUtfDString(encoding, buf, RSTRING_LEN(str), &dstr);
/* str = rb_tainted_str_new2(Tcl_DStringValue(&dstr)); */
/* str = rb_str_new2(Tcl_DStringValue(&dstr)); */
str = rb_str_new(Tcl_DStringValue(&dstr), Tcl_DStringLength(&dstr));
- rb_ivar_set(str, ID_at_enc, rb_tainted_str_new2("utf-8"));
+#ifdef RUBY_VM
+ rb_enc_associate_index(str, ENCODING_INDEX_UTF8);
+#endif
+ rb_ivar_set(str, ID_at_enc, ENCODING_NAME_UTF8);
if (taint_flag) OBJ_TAINT(str);
+ /*
if (encoding != (Tcl_Encoding)NULL) {
Tcl_FreeEncoding(encoding);
}
+ */
Tcl_DStringFree(&dstr);
free(buf);
+ /* ckfree(buf); */
rb_thread_critical = thr_crit_bup;
#endif
@@ -6251,10 +7398,21 @@ lib_fromUTF8_core(ip_obj, src, encodename)
enc = rb_attr_get(str, ID_at_enc);
if (!NIL_P(enc)) {
StringValue(enc);
- if (strcmp(RSTRING(enc)->ptr, "binary") == 0) {
+ if (strcmp(RSTRING_PTR(enc), "binary") == 0) {
+#ifdef RUBY_VM
+ rb_enc_associate_index(str, ENCODING_INDEX_BINARY);
+#endif
+ rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY);
rb_thread_critical = thr_crit_bup;
return str;
}
+#ifdef RUBY_VM
+ } else if (rb_enc_get_index(str) == ENCODING_INDEX_BINARY) {
+ rb_enc_associate_index(str, ENCODING_INDEX_BINARY);
+ rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY);
+ rb_thread_critical = thr_crit_bup;
+ return str;
+#endif
}
}
@@ -6265,75 +7423,106 @@ lib_fromUTF8_core(ip_obj, src, encodename)
if (NIL_P(enc)) {
encoding = (Tcl_Encoding)NULL;
} else {
- StringValue(enc);
- encoding = Tcl_GetEncoding(interp, RSTRING(enc)->ptr);
- if (encoding == (Tcl_Encoding)NULL) {
- rb_warning("Tk-interp has unknown encoding information (@encoding:'%s')", RSTRING(enc)->ptr);
- } else {
- encodename = rb_obj_dup(enc);
- }
+ /* StringValue(enc); */
+ enc = rb_funcall(enc, ID_to_s, 0, 0);
+ /* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); */
+ if (!RSTRING_LEN(enc)) {
+ encoding = (Tcl_Encoding)NULL;
+ } else {
+ encoding = Tcl_GetEncoding((Tcl_Interp*)NULL,
+ RSTRING_PTR(enc));
+ if (encoding == (Tcl_Encoding)NULL) {
+ rb_warning("Tk-interp has unknown encoding information (@encoding:'%s')", RSTRING_PTR(enc));
+ } else {
+ encodename = rb_obj_dup(enc);
+ }
+ }
}
}
} else {
StringValue(encodename);
- if (strcmp(RSTRING(encodename)->ptr, "binary") == 0) {
+ if (strcmp(RSTRING_PTR(encodename), "binary") == 0) {
+ Tcl_Obj *tclstr;
char *s;
int len;
StringValue(str);
- s = Tcl_GetByteArrayFromObj(Tcl_NewStringObj(RSTRING(str)->ptr,
- RSTRING(str)->len),
- &len);
+ tclstr = Tcl_NewStringObj(RSTRING_PTR(str), RSTRING_LEN(str));
+ Tcl_IncrRefCount(tclstr);
+ s = Tcl_GetByteArrayFromObj(tclstr, &len);
str = rb_tainted_str_new(s, len);
- rb_ivar_set(str, ID_at_enc, rb_tainted_str_new2("binary"));
+ s = (char*)NULL;
+ Tcl_DecrRefCount(tclstr);
+#ifdef RUBY_VM
+ rb_enc_associate_index(str, ENCODING_INDEX_BINARY);
+#endif
+ rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY);
rb_thread_critical = thr_crit_bup;
return str;
}
- encoding = Tcl_GetEncoding(interp, RSTRING(encodename)->ptr);
+ /* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(encodename)); */
+ encoding = Tcl_GetEncoding((Tcl_Interp*)NULL, RSTRING_PTR(encodename));
if (encoding == (Tcl_Encoding)NULL) {
/*
rb_warning("unknown encoding name '%s'",
- RSTRING(encodename)->ptr);
+ RSTRING_PTR(encodename));
encodename = Qnil;
*/
rb_raise(rb_eArgError, "unknown encoding name '%s'",
- RSTRING(encodename)->ptr);
+ RSTRING_PTR(encodename));
}
}
StringValue(str);
- if (RSTRING(str)->len == 0) {
+ if (RSTRING_LEN(str) == 0) {
rb_thread_critical = thr_crit_bup;
return rb_tainted_str_new2("");
}
- buf = ALLOC_N(char,strlen(RSTRING(str)->ptr)+1);
- memcpy(buf, RSTRING(str)->ptr, RSTRING(str)->len);
- buf[RSTRING(str)->len] = 0;
+ buf = ALLOC_N(char, RSTRING_LEN(str)+1);
+ /* buf = ckalloc(sizeof(char) * (RSTRING_LEN(str)+1)); */
+ memcpy(buf, RSTRING_PTR(str), RSTRING_LEN(str));
+ buf[RSTRING_LEN(str)] = 0;
Tcl_DStringInit(&dstr);
Tcl_DStringFree(&dstr);
/* Tcl_UtfToExternalDString(encoding,buf,strlen(buf),&dstr); */
- Tcl_UtfToExternalDString(encoding,buf,RSTRING(str)->len,&dstr);
+ Tcl_UtfToExternalDString(encoding,buf,RSTRING_LEN(str),&dstr);
/* str = rb_tainted_str_new2(Tcl_DStringValue(&dstr)); */
/* str = rb_str_new2(Tcl_DStringValue(&dstr)); */
str = rb_str_new(Tcl_DStringValue(&dstr), Tcl_DStringLength(&dstr));
+#ifdef RUBY_VM
+ if (interp) {
+ /* can access encoding_table of TclTkIp */
+ /* -> try to use encoding_table */
+ VALUE tbl = ip_get_encoding_table(ip_obj);
+ VALUE encobj = encoding_table_get_obj(tbl, encodename);
+ rb_enc_associate_index(str, rb_to_encoding_index(encobj));
+ } else {
+ /* cannot access encoding_table of TclTkIp */
+ /* -> try to find on Ruby Encoding */
+ rb_enc_associate_index(str, rb_enc_find_index(RSTRING_PTR(encodename)));
+ }
+#endif
rb_ivar_set(str, ID_at_enc, encodename);
if (taint_flag) OBJ_TAINT(str);
+ /*
if (encoding != (Tcl_Encoding)NULL) {
Tcl_FreeEncoding(encoding);
}
+ */
Tcl_DStringFree(&dstr);
free(buf);
+ /* ckfree(buf); */
rb_thread_critical = thr_crit_bup;
#endif
@@ -6384,21 +7573,29 @@ lib_UTF_backslash_core(self, str, all_bs)
tcl_stubs_check();
StringValue(str);
- if (!RSTRING(str)->len) {
+ if (!RSTRING_LEN(str)) {
return str;
}
thr_crit_bup = rb_thread_critical;
rb_thread_critical = Qtrue;
- src_buf = ALLOC_N(char,(RSTRING(str)->len)+1);
- memcpy(src_buf, RSTRING(str)->ptr, RSTRING(str)->len);
- src_buf[RSTRING(str)->len] = 0;
+ /* src_buf = ALLOC_N(char, RSTRING_LEN(str)+1); */
+ src_buf = ckalloc(sizeof(char) * (RSTRING_LEN(str)+1));
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)src_buf); /* XXXXXXXX */
+#endif
+ memcpy(src_buf, RSTRING_PTR(str), RSTRING_LEN(str));
+ src_buf[RSTRING_LEN(str)] = 0;
- dst_buf = ALLOC_N(char,(RSTRING(str)->len)+1);
+ /* dst_buf = ALLOC_N(char, RSTRING_LEN(str)+1); */
+ dst_buf = ckalloc(sizeof(char) * (RSTRING_LEN(str)+1));
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)dst_buf); /* XXXXXXXX */
+#endif
ptr = src_buf;
- while(RSTRING(str)->len > ptr - src_buf) {
+ while(RSTRING_LEN(str) > ptr - src_buf) {
if (*ptr == '\\' && (all_bs || *(ptr + 1) == 'u')) {
dst_len += Tcl_UtfBackslash(ptr, &read_len, (dst_buf + dst_len));
ptr += read_len;
@@ -6409,9 +7606,31 @@ lib_UTF_backslash_core(self, str, all_bs)
str = rb_str_new(dst_buf, dst_len);
if (taint_flag) OBJ_TAINT(str);
+#ifdef RUBY_VM
+ rb_enc_associate_index(str, ENCODING_INDEX_UTF8);
+#endif
+ rb_ivar_set(str, ID_at_enc, ENCODING_NAME_UTF8);
- free(src_buf);
- free(dst_buf);
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)src_buf, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)src_buf); /* XXXXXXXX */
+#else
+ /* free(src_buf); */
+ ckfree(src_buf);
+#endif
+#endif
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)dst_buf, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)dst_buf); /* XXXXXXXX */
+#else
+ /* free(dst_buf); */
+ ckfree(dst_buf);
+#endif
+#endif
rb_thread_critical = thr_crit_bup;
#endif
@@ -6464,7 +7683,7 @@ lib_set_system_encoding(self, enc_name)
if (Tcl_SetSystemEncoding((Tcl_Interp *)NULL,
StringValuePtr(enc_name)) != TCL_OK) {
rb_raise(rb_eArgError, "unknown encoding name '%s'",
- RSTRING(enc_name)->ptr);
+ RSTRING_PTR(enc_name));
}
return enc_name;
@@ -6502,7 +7721,11 @@ invoke_tcl_proc(arg)
#if TCL_MAJOR_VERSION >= 8
if (!inf->cmdinfo.isNativeObjectProc) {
/* string interface */
- argv = (char **)ALLOC_N(char *, argc+1);
+ /* argv = (char **)ALLOC_N(char *, argc+1);*/ /* XXXXXXXXXX */
+ argv = (char **)ckalloc(sizeof(char *)*(argc+1));
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)argv); /* XXXXXXXX */
+#endif
for (i = 0; i < argc; ++i) {
argv[i] = Tcl_GetStringFromObj(inf->objv[i], &len);
}
@@ -6527,7 +7750,16 @@ invoke_tcl_proc(arg)
= (*(inf->cmdinfo.proc))(inf->cmdinfo.clientData, inf->ptr->ip,
argc, (CONST84 char **)argv);
- free(argv);
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)argv); /* XXXXXXXX */
+#else
+ /* free(argv); */
+ ckfree((char*)argv);
+#endif
+#endif
#else /* TCL_MAJOR_VERSION < 8 */
inf->ptr->return_value
@@ -6573,6 +7805,9 @@ ip_invoke_core(interp, argc, argv)
#endif
#endif
+ /* get the data struct */
+ ptr = get_ip(interp);
+
/* get the command name string */
#if TCL_MAJOR_VERSION >= 8
cmd = Tcl_GetStringFromObj(objv[0], &len);
@@ -6632,14 +7867,22 @@ ip_invoke_core(interp, argc, argv)
unknown_flag = 1;
#if TCL_MAJOR_VERSION >= 8
- unknown_objv = (Tcl_Obj **)ALLOC_N(Tcl_Obj *, objc+2);
+ /* unknown_objv = (Tcl_Obj **)ALLOC_N(Tcl_Obj *, objc+2); */
+ unknown_objv = (Tcl_Obj **)ckalloc(sizeof(Tcl_Obj *) * (objc+2));
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)unknown_objv); /* XXXXXXXX */
+#endif
unknown_objv[0] = Tcl_NewStringObj("::unknown", 9);
Tcl_IncrRefCount(unknown_objv[0]);
memcpy(unknown_objv + 1, objv, sizeof(Tcl_Obj *)*objc);
unknown_objv[++objc] = (Tcl_Obj*)NULL;
objv = unknown_objv;
#else
- unknown_argv = (char **)ALLOC_N(char *, argc+2);
+ /* unknown_argv = (char **)ALLOC_N(char *, argc+2); */
+ unknown_argv = (char **)ckalloc(sizeof(char *) * (argc+2));
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)unknown_argv); /* XXXXXXXX */
+#endif
unknown_argv[0] = strdup("unknown");
memcpy(unknown_argv + 1, argv, sizeof(char *)*argc);
unknown_argv[++argc] = (char *)NULL;
@@ -6652,7 +7895,6 @@ ip_invoke_core(interp, argc, argv)
thr_crit_bup = rb_thread_critical;
rb_thread_critical = Qtrue;
-
#if 1 /* wrap tcl-proc call */
/* setup params */
inf.ptr = ptr;
@@ -6669,19 +7911,35 @@ ip_invoke_core(interp, argc, argv)
ret = rb_protect(invoke_tcl_proc, (VALUE)&inf, &status);
switch(status) {
case TAG_RAISE:
+#ifdef RUBY_VM
+ if (NIL_P(rb_errinfo())) {
+#else
if (NIL_P(ruby_errinfo)) {
+#endif
rbtk_pending_exception = rb_exc_new2(rb_eException,
"unknown exception");
} else {
+#ifdef RUBY_VM
+ rbtk_pending_exception = rb_errinfo();
+#else
rbtk_pending_exception = ruby_errinfo;
+#endif
}
break;
case TAG_FATAL:
+#ifdef RUBY_VM
+ if (NIL_P(rb_errinfo())) {
+#else
if (NIL_P(ruby_errinfo)) {
+#endif
rbtk_pending_exception = rb_exc_new2(rb_eFatal, "FATAL");
} else {
+#ifdef RUBY_VM
+ rbtk_pending_exception = rb_errinfo();
+#else
rbtk_pending_exception = ruby_errinfo;
+#endif
}
}
@@ -6693,7 +7951,11 @@ ip_invoke_core(interp, argc, argv)
int i;
/* string interface */
- argv = (char **)ALLOC_N(char *, argc+1);
+ /* argv = (char **)ALLOC_N(char *, argc+1); */
+ argv = (char **)ckalloc(sizeof(char *) * (argc+1));
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)argv); /* XXXXXXXX */
+#endif
for (i = 0; i < argc; ++i) {
argv[i] = Tcl_GetStringFromObj(objv[i], &len);
}
@@ -6722,7 +7984,16 @@ ip_invoke_core(interp, argc, argv)
ptr->return_value = (*info.proc)(info.clientData, ptr->ip,
argc, (CONST84 char **)argv);
- free(argv);
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)argv); /* XXXXXXXX */
+#else
+ /* free(argv); */
+ ckfree((char*)argv);
+#endif
+#endif
#else /* TCL_MAJOR_VERSION < 8 */
ptr->return_value = (*info.proc)(info.clientData, ptr->ip,
@@ -6735,10 +8006,29 @@ ip_invoke_core(interp, argc, argv)
if (unknown_flag) {
#if TCL_MAJOR_VERSION >= 8
Tcl_DecrRefCount(objv[0]);
- free(objv);
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)objv, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)objv); /* XXXXXXXX */
#else
+ /* free(objv); */
+ ckfree((char*)objv);
+#endif
+#endif
+#else /* TCL_MAJOR_VERSION < 8 */
free(argv[0]);
- free(argv);
+ /* ckfree(argv[0]); */
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)argv); /* XXXXXXXX */
+#else
+ /* free(argv); */
+ ckfree((char*)argv);
+#endif
+#endif
#endif
}
@@ -6793,7 +8083,11 @@ alloc_invoke_arguments(argc, argv)
/* memory allocation */
#if TCL_MAJOR_VERSION >= 8
- av = ALLOC_N(Tcl_Obj *, argc+1);
+ /* av = ALLOC_N(Tcl_Obj *, argc+1);*/ /* XXXXXXXXXX */
+ av = (Tcl_Obj**)ckalloc(sizeof(Tcl_Obj *)*(argc+1));
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)av); /* XXXXXXXX */
+#endif
for (i = 0; i < argc; ++i) {
av[i] = get_obj_from_str(argv[i]);
Tcl_IncrRefCount(av[i]);
@@ -6802,7 +8096,11 @@ alloc_invoke_arguments(argc, argv)
#else /* TCL_MAJOR_VERSION < 8 */
/* string interface */
- av = ALLOC_N(char *, argc+1);
+ /* av = ALLOC_N(char *, argc+1); */
+ av = (char**)ckalloc(sizeof(char *) * (argc+1));
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)av); /* XXXXXXXX */
+#endif
for (i = 0; i < argc; ++i) {
av[i] = strdup(StringValuePtr(argv[i]));
}
@@ -6828,11 +8126,34 @@ free_invoke_arguments(argc, av)
for (i = 0; i < argc; ++i) {
#if TCL_MAJOR_VERSION >= 8
Tcl_DecrRefCount(av[i]);
+ av[i] = (Tcl_Obj*)NULL;
#else /* TCL_MAJOR_VERSION < 8 */
free(av[i]);
+ av[i] = (char*)NULL;
#endif
}
- free(av);
+#if TCL_MAJOR_VERSION >= 8
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)av, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)av); /* XXXXXXXX */
+#else
+ ckfree((char*)av);
+#endif
+#endif
+#else /* TCL_MAJOR_VERSION < 8 */
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)av, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)av); /* XXXXXXXX */
+#else
+ /* free(av); */
+ ckfree((char*)av);
+#endif
+#endif
+#endif
}
static VALUE
@@ -6895,10 +8216,12 @@ invoke_queue_handler(evPtr, flags)
struct invoke_queue *q = (struct invoke_queue *)evPtr;
volatile VALUE ret;
volatile VALUE q_dat;
+ volatile VALUE thread = q->thread;
+ struct tcltkip *ptr;
DUMP2("do_invoke_queue_handler : evPtr = %p", evPtr);
DUMP2("invoke queue_thread : %lx", rb_thread_current());
- DUMP2("added by thread : %lx", q->thread);
+ DUMP2("added by thread : %lx", thread);
if (*(q->done)) {
DUMP1("processed by another event-loop");
@@ -6907,36 +8230,71 @@ invoke_queue_handler(evPtr, flags)
DUMP1("process it on current event-loop");
}
+ if (RTEST(rb_thread_alive_p(thread))
+ && ! RTEST(rb_funcall(thread, ID_stop_p, 0))) {
+ DUMP1("caller is not yet ready to receive the result -> pending");
+ return 0;
+ }
+
/* process it */
*(q->done) = 1;
+ /* deleted ipterp ? */
+ ptr = get_ip(q->interp);
+ if (deleted_ip(ptr)) {
+ /* deleted IP --> ignore */
+ return 1;
+ }
+
+ /* incr internal handler mark */
+ rbtk_internal_eventloop_handler++;
+
/* check safe-level */
if (rb_safe_level() != q->safe_level) {
/* q_dat = Data_Wrap_Struct(rb_cData,0,0,q); */
- q_dat = Data_Wrap_Struct(rb_cData,invoke_queue_mark,0,q);
+ q_dat = Data_Wrap_Struct(rb_cData,invoke_queue_mark,-1,q);
ret = rb_funcall(rb_proc_new(ivq_safelevel_handler, q_dat),
ID_call, 0);
rb_gc_force_recycle(q_dat);
+ q_dat = (VALUE)NULL;
} else {
- DUMP2("call invoke_real (for caller thread:%lx)", q->thread);
+ DUMP2("call invoke_real (for caller thread:%lx)", thread);
DUMP2("call invoke_real (current thread:%lx)", rb_thread_current());
ret = ip_invoke_core(q->interp, q->argc, q->argv);
}
/* set result */
- RARRAY(q->result)->ptr[0] = ret;
+ RARRAY_PTR(q->result)[0] = ret;
+ ret = (VALUE)NULL;
+
+ /* decr internal handler mark */
+ rbtk_internal_eventloop_handler--;
/* complete */
*(q->done) = -1;
+ /* unlink ruby objects */
+ q->interp = (VALUE)NULL;
+ q->result = (VALUE)NULL;
+ q->thread = (VALUE)NULL;
+
/* back to caller */
- if (RTEST(rb_funcall(q->thread, ID_alive_p, 0, 0))) {
- DUMP2("back to caller (caller thread:%lx)", q->thread);
+ /* if (RTEST(rb_funcall(thread, ID_alive_p, 0, 0))) { */
+ if (RTEST(rb_thread_alive_p(thread))) {
+ DUMP2("back to caller (caller thread:%lx)", thread);
DUMP2(" (current thread:%lx)", rb_thread_current());
- rb_thread_run(q->thread);
+#if CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE
+ have_rb_thread_waiting_for_value = 1;
+ rb_thread_wakeup(thread);
+#else
+ rb_thread_run(thread);
+#endif
DUMP1("finish back to caller");
+#if DO_THREAD_SCHEDULE_AT_CALLBACK_DONE
+ rb_thread_schedule();
+#endif
} else {
- DUMP2("caller is dead (caller thread:%lx)", q->thread);
+ DUMP2("caller is dead (caller thread:%lx)", thread);
DUMP2(" (current thread:%lx)", rb_thread_current());
}
@@ -6952,6 +8310,9 @@ ip_invoke_with_position(argc, argv, obj, position)
Tcl_QueuePosition position;
{
struct invoke_queue *ivq;
+#ifdef RUBY_VM
+ struct tcltkip *ptr;
+#endif
int *alloc_done;
int thr_crit_bup;
volatile VALUE current = rb_thread_current();
@@ -6968,7 +8329,21 @@ ip_invoke_with_position(argc, argv, obj, position)
if (argc < 1) {
rb_raise(rb_eArgError, "command name missing");
}
- if (NIL_P(eventloop_thread) || current == eventloop_thread) {
+
+#ifdef RUBY_VM
+ ptr = get_ip(ip_obj);
+ DUMP2("status: ptr->tk_thread_id %d", ptr->tk_thread_id);
+#endif
+ DUMP2("status: Tcl_GetCurrentThread %d", Tcl_GetCurrentThread());
+ DUMP2("status: eventloopt_thread %lx", eventloop_thread);
+
+ if (
+#ifdef RUBY_VM
+ (ptr->tk_thread_id == 0 || ptr->tk_thread_id == Tcl_GetCurrentThread())
+ &&
+#endif
+ (NIL_P(eventloop_thread) || current == eventloop_thread)
+ ) {
if (NIL_P(eventloop_thread)) {
DUMP2("invoke from thread:%lx but no eventloop", current);
} else {
@@ -6990,17 +8365,22 @@ ip_invoke_with_position(argc, argv, obj, position)
av = alloc_invoke_arguments(argc, argv);
/* allocate memory (keep result) */
- alloc_done = (int*)ALLOC(int);
+ /* alloc_done = (int*)ALLOC(int); */
+ alloc_done = (int*)ckalloc(sizeof(int));
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)alloc_done); /* XXXXXXXX */
+#endif
*alloc_done = 0;
/* allocate memory (freed by Tcl_ServiceEvent) */
- ivq = (struct invoke_queue *)Tcl_Alloc(sizeof(struct invoke_queue));
- Tcl_Preserve(ivq);
+ /* ivq = (struct invoke_queue *)Tcl_Alloc(sizeof(struct invoke_queue)); */
+ ivq = (struct invoke_queue *)ckalloc(sizeof(struct invoke_queue));
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)ivq); /* XXXXXXXX */
+#endif
/* allocate result obj */
- result = rb_ary_new2(1);
- RARRAY(result)->ptr[0] = Qnil;
- RARRAY(result)->len = 1;
+ result = rb_ary_new3(1, Qnil);
/* construct event data */
ivq->done = alloc_done;
@@ -7014,22 +8394,60 @@ ip_invoke_with_position(argc, argv, obj, position)
/* add the handler to Tcl event queue */
DUMP1("add handler");
- Tcl_QueueEvent(&(ivq->ev), position);
+#ifdef RUBY_VM
+ if (ptr->tk_thread_id) {
+ /* Tcl_ThreadQueueEvent(ptr->tk_thread_id, &(ivq->ev), position); */
+ Tcl_ThreadQueueEvent(ptr->tk_thread_id, (Tcl_Event*)ivq, position);
+ Tcl_ThreadAlert(ptr->tk_thread_id);
+ } else if (tk_eventloop_thread_id) {
+ /* Tcl_ThreadQueueEvent(tk_eventloop_thread_id,
+ &(ivq->ev), position); */
+ Tcl_ThreadQueueEvent(tk_eventloop_thread_id,
+ (Tcl_Event*)ivq, position);
+ Tcl_ThreadAlert(tk_eventloop_thread_id);
+ } else {
+ /* Tcl_QueueEvent(&(ivq->ev), position); */
+ Tcl_QueueEvent((Tcl_Event*)ivq, position);
+ }
+#else
+ /* Tcl_QueueEvent(&(ivq->ev), position); */
+ Tcl_QueueEvent((Tcl_Event*)ivq, position);
+#endif
rb_thread_critical = thr_crit_bup;
/* wait for the handler to be processed */
DUMP2("wait for handler (current thread:%lx)", current);
while(*alloc_done >= 0) {
- rb_thread_stop();
+ /* rb_thread_stop(); */
+ rb_thread_sleep_forever();
}
DUMP2("back from handler (current thread:%lx)", current);
/* get result & free allocated memory */
ret = RARRAY(result)->ptr[0];
- free(alloc_done);
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)alloc_done, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)alloc_done); /* XXXXXXXX */
+#else
+ /* free(alloc_done); */
+ ckfree((char*)alloc_done);
+#endif
+#endif
+#if 0 /* ivq is freed by Tcl_ServiceEvent */
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)ivq, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 0 /* use Tcl_Preserve/Release */
Tcl_Release(ivq);
+#else
+ ckfree((char*)ivq);
+#endif
+#endif
+#endif
/* free allocated memory */
free_invoke_arguments(argc, av);
@@ -7037,7 +8455,9 @@ ip_invoke_with_position(argc, argv, obj, position)
/* exception? */
if (rb_obj_is_kind_of(ret, rb_eException)) {
DUMP1("raise exception");
- rb_exc_raise(ret);
+ /* rb_exc_raise(ret); */
+ rb_exc_raise(rb_exc_new3(rb_obj_class(ret),
+ rb_funcall(ret, ID_to_s, 0, 0)));
}
DUMP1("exit ip_invoke");
@@ -7119,8 +8539,8 @@ ip_get_variable2_core(interp, argc, argv)
} else {
/* Tcl_Preserve(ptr->ip); */
rbtk_preserve_ip(ptr);
- ret = Tcl_GetVar2Ex(ptr->ip, RSTRING(varname)->ptr,
- NIL_P(index) ? NULL : RSTRING(index)->ptr,
+ ret = Tcl_GetVar2Ex(ptr->ip, RSTRING_PTR(varname),
+ NIL_P(index) ? NULL : RSTRING_PTR(index),
FIX2INT(flag));
}
@@ -7157,8 +8577,8 @@ ip_get_variable2_core(interp, argc, argv)
} else {
/* Tcl_Preserve(ptr->ip); */
rbtk_preserve_ip(ptr);
- ret = Tcl_GetVar2(ptr->ip, RSTRING(varname)->ptr,
- NIL_P(index) ? NULL : RSTRING(index)->ptr,
+ ret = Tcl_GetVar2(ptr->ip, RSTRING_PTR(varname),
+ NIL_P(index) ? NULL : RSTRING_PTR(index),
FIX2INT(flag));
}
@@ -7256,8 +8676,8 @@ ip_set_variable2_core(interp, argc, argv)
} else {
/* Tcl_Preserve(ptr->ip); */
rbtk_preserve_ip(ptr);
- ret = Tcl_SetVar2Ex(ptr->ip, RSTRING(varname)->ptr,
- NIL_P(index) ? NULL : RSTRING(index)->ptr,
+ ret = Tcl_SetVar2Ex(ptr->ip, RSTRING_PTR(varname),
+ NIL_P(index) ? NULL : RSTRING_PTR(index),
valobj, FIX2INT(flag));
}
@@ -7297,9 +8717,9 @@ ip_set_variable2_core(interp, argc, argv)
} else {
/* Tcl_Preserve(ptr->ip); */
rbtk_preserve_ip(ptr);
- ret = Tcl_SetVar2(ptr->ip, RSTRING(varname)->ptr,
- NIL_P(index) ? NULL : RSTRING(index)->ptr,
- RSTRING(value)->ptr, FIX2INT(flag));
+ ret = Tcl_SetVar2(ptr->ip, RSTRING_PTR(varname),
+ NIL_P(index) ? NULL : RSTRING_PTR(index),
+ RSTRING_PTR(value), FIX2INT(flag));
}
if (ret == (char*)NULL) {
@@ -7379,8 +8799,8 @@ ip_unset_variable2_core(interp, argc, argv)
return Qtrue;
}
- ptr->return_value = Tcl_UnsetVar2(ptr->ip, RSTRING(varname)->ptr,
- NIL_P(index) ? NULL : RSTRING(index)->ptr,
+ ptr->return_value = Tcl_UnsetVar2(ptr->ip, RSTRING_PTR(varname),
+ NIL_P(index) ? NULL : RSTRING_PTR(index),
FIX2INT(flag));
if (ptr->return_value == TCL_ERROR) {
@@ -7500,6 +8920,10 @@ lib_split_tklist_core(ip_obj, list_str)
volatile VALUE ary, elem;
int idx;
int taint_flag = OBJ_TAINTED(list_str);
+#ifdef RUBY_VM
+ int list_enc_idx;
+ volatile VALUE list_ivar_enc;
+#endif
int result;
VALUE old_gc;
@@ -7514,6 +8938,10 @@ lib_split_tklist_core(ip_obj, list_str)
}
StringValue(list_str);
+#ifdef RUBY_VM
+ list_enc_idx = rb_enc_get_index(list_str);
+ list_ivar_enc = rb_ivar_get(list_str, ID_at_enc);
+#endif
{
#if TCL_MAJOR_VERSION >= 8
@@ -7552,11 +8980,21 @@ lib_split_tklist_core(ip_obj, list_str)
for(idx = 0; idx < objc; idx++) {
elem = get_str_from_obj(objv[idx]);
+#ifdef RUBY_VM
+ if (rb_enc_get_index(elem) == ENCODING_INDEX_BINARY) {
+ rb_enc_associate_index(elem, ENCODING_INDEX_BINARY);
+ rb_ivar_set(elem, ID_at_enc, ENCODING_NAME_BINARY);
+ } else {
+ rb_enc_associate_index(elem, list_enc_idx);
+ rb_ivar_set(elem, ID_at_enc, list_ivar_enc);
+ }
+#endif
if (taint_flag) OBJ_TAINT(elem);
- RARRAY(ary)->ptr[idx] = elem;
+ /* RARRAY(ary)->ptr[idx] = elem; */
+ rb_ary_push(ary, elem);
}
- RARRAY(ary)->len = objc;
+ /* RARRAY(ary)->len = objc; */
if (old_gc == Qfalse) rb_gc_enable();
@@ -7573,7 +9011,7 @@ lib_split_tklist_core(ip_obj, list_str)
int argc;
char **argv;
- if (Tcl_SplitList(interp, RSTRING(list_str)->ptr,
+ if (Tcl_SplitList(interp, RSTRING_PTR(list_str),
&argc, &argv) == TCL_ERROR) {
if (interp == (Tcl_Interp*)NULL) {
rb_raise(rb_eRuntimeError, "can't get elements from list");
@@ -7594,9 +9032,10 @@ lib_split_tklist_core(ip_obj, list_str)
elem = rb_str_new2(argv[idx]);
}
/* rb_ivar_set(elem, ID_at_enc, rb_str_new2("binary")); */
- RARRAY(ary)->ptr[idx] = elem;
+ /* RARRAY(ary)->ptr[idx] = elem; */
+ rb_ary_push(ary, elem)
}
- RARRAY(ary)->len = argc;
+ /* RARRAY(ary)->len = argc; */
if (old_gc == Qfalse) rb_gc_enable();
#endif
@@ -7645,7 +9084,11 @@ lib_merge_tklist(argc, argv, obj)
old_gc = rb_gc_disable();
/* based on Tcl/Tk's Tcl_Merge() */
- flagPtr = ALLOC_N(int, argc);
+ /* flagPtr = ALLOC_N(int, argc); */
+ flagPtr = (int *)ckalloc(sizeof(int) * argc);
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)flagPtr); /* XXXXXXXXXX */
+#endif
/* pass 1 */
len = 1;
@@ -7653,7 +9096,7 @@ lib_merge_tklist(argc, argv, obj)
if (OBJ_TAINTED(argv[num])) taint_flag = 1;
dst = StringValuePtr(argv[num]);
#if TCL_MAJOR_VERSION >= 8
- len += Tcl_ScanCountedElement(dst, RSTRING(argv[num])->len,
+ len += Tcl_ScanCountedElement(dst, RSTRING_LEN(argv[num]),
&flagPtr[num]) + 1;
#else /* TCL_MAJOR_VERSION < 8 */
len += Tcl_ScanElement(dst, &flagPtr[num]) + 1;
@@ -7661,15 +9104,19 @@ lib_merge_tklist(argc, argv, obj)
}
/* pass 2 */
- result = (char *)Tcl_Alloc(len);
+ /* result = (char *)Tcl_Alloc(len); */
+ result = (char *)ckalloc(len);
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Preserve((ClientData)result);
+#endif
dst = result;
for(num = 0; num < argc; num++) {
#if TCL_MAJOR_VERSION >= 8
- len = Tcl_ConvertCountedElement(RSTRING(argv[num])->ptr,
- RSTRING(argv[num])->len,
+ len = Tcl_ConvertCountedElement(RSTRING_PTR(argv[num]),
+ RSTRING_LEN(argv[num]),
dst, flagPtr[num]);
#else /* TCL_MAJOR_VERSION < 8 */
- len = Tcl_ConvertElement(RSTRING(argv[num])->ptr, dst, flagPtr[num]);
+ len = Tcl_ConvertElement(RSTRING_PTR(argv[num]), dst, flagPtr[num]);
#endif
dst += len;
*dst = ' ';
@@ -7681,12 +9128,30 @@ lib_merge_tklist(argc, argv, obj)
dst[-1] = 0;
}
- free(flagPtr);
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)flagPtr, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)flagPtr);
+#else
+ /* free(flagPtr); */
+ ckfree((char*)flagPtr);
+#endif
+#endif
/* create object */
str = rb_str_new(result, dst - result - 1);
if (taint_flag) OBJ_TAINT(str);
- Tcl_Free(result);
+#if 0 /* use Tcl_EventuallyFree */
+ Tcl_EventuallyFree((ClientData)result, TCL_DYNAMIC); /* XXXXXXXX */
+#else
+#if 0 /* use Tcl_Preserve/Release */
+ Tcl_Release((ClientData)result); /* XXXXXXXXXXX */
+#else
+ /* Tcl_Free(result); */
+ ckfree(result);
+#endif
+#endif
if (old_gc == Qfalse) rb_gc_enable();
rb_thread_critical = thr_crit_bup;
@@ -7712,19 +9177,18 @@ lib_conv_listelement(self, src)
StringValue(src);
#if TCL_MAJOR_VERSION >= 8
- len = Tcl_ScanCountedElement(RSTRING(src)->ptr, RSTRING(src)->len,
+ len = Tcl_ScanCountedElement(RSTRING_PTR(src), RSTRING_LEN(src),
&scan_flag);
dst = rb_str_new(0, len + 1);
- len = Tcl_ConvertCountedElement(RSTRING(src)->ptr, RSTRING(src)->len,
- RSTRING(dst)->ptr, scan_flag);
+ len = Tcl_ConvertCountedElement(RSTRING_PTR(src), RSTRING_LEN(src),
+ RSTRING_PTR(dst), scan_flag);
#else /* TCL_MAJOR_VERSION < 8 */
- len = Tcl_ScanElement(RSTRING(src)->ptr, &scan_flag);
+ len = Tcl_ScanElement(RSTRING_PTR(src), &scan_flag);
dst = rb_str_new(0, len + 1);
- len = Tcl_ConvertElement(RSTRING(src)->ptr, RSTRING(dst)->ptr, scan_flag);
+ len = Tcl_ConvertElement(RSTRING_PTR(src), RSTRING_PTR(dst), scan_flag);
#endif
- RSTRING(dst)->len = len;
- RSTRING(dst)->ptr[len] = '\0';
+ rb_str_resize(dst, len);
if (taint_flag) OBJ_TAINT(dst);
rb_thread_critical = thr_crit_bup;
@@ -7732,6 +9196,34 @@ lib_conv_listelement(self, src)
return dst;
}
+static VALUE
+lib_getversion(self)
+ VALUE self;
+{
+ volatile VALUE type_name;
+
+ set_tcltk_version();
+
+ switch(tcltk_version.type) {
+ case TCL_ALPHA_RELEASE:
+ type_name = rb_str_new2("alpha");
+ break;
+ case TCL_BETA_RELEASE:
+ type_name = rb_str_new2("beta");
+ break;
+ case TCL_FINAL_RELEASE:
+ type_name = rb_str_new2("final");
+ break;
+ default:
+ type_name = rb_str_new2("unknown");
+ }
+
+ return rb_ary_new3(5, INT2NUM(tcltk_version.major),
+ INT2NUM(tcltk_version.minor),
+ INT2NUM(tcltk_version.type), type_name,
+ INT2NUM(tcltk_version.patchlevel));
+}
+
static VALUE
tcltklib_compile_info()
@@ -7754,6 +9246,7 @@ tcltklib_compile_info()
+ strlen("unknown tcl_threads");
info = ALLOC_N(char, size);
+ /* info = ckalloc(sizeof(char) * size); */ /* SEGV */
sprintf(info, form,
TCLTKLIB_RELEASE_DATE,
@@ -7789,15 +9282,532 @@ tcltklib_compile_info()
ret = rb_obj_freeze(rb_str_new2(info));
free(info);
+ /* ckfree(info); */
return ret;
}
+
+/*###############################################*/
+
+static VALUE
+create_dummy_encoding_for_tk_core(interp, name, error_mode)
+ VALUE interp;
+ VALUE name;
+ VALUE error_mode;
+{
+ struct tcltkip *ptr = get_ip(interp);
+
+ rb_secure(4);
+
+ StringValue(name);
+
+#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1)
+ if (Tcl_GetEncoding((Tcl_Interp*)NULL, RSTRING_PTR(name)) == (Tcl_Encoding)NULL) {
+ if (RTEST(error_mode)) {
+ rb_raise(rb_eArgError, "invalid Tk encoding name '%s'",
+ RSTRING_PTR(name));
+ } else {
+ return Qnil;
+ }
+ }
+#endif
+
+#ifdef RUBY_VM
+ if (RTEST(rb_define_dummy_encoding(RSTRING_PTR(name)))) {
+ int idx = rb_enc_find_index(StringValueCStr(name));
+ return rb_enc_from_encoding(rb_enc_from_index(idx));
+ } else {
+ if (RTEST(error_mode)) {
+ rb_raise(rb_eRuntimeError, "fail to create dummy encoding for '%s'",
+ RSTRING_PTR(name));
+ } else {
+ return Qnil;
+ }
+ }
+#else
+ return name;
+#endif
+}
+static VALUE
+create_dummy_encoding_for_tk(interp, name)
+ VALUE interp;
+ VALUE name;
+{
+ return create_dummy_encoding_for_tk_core(interp, name, Qtrue);
+}
+
+
+#ifdef RUBY_VM
+static int
+update_encoding_table(table, interp, error_mode)
+ VALUE table;
+ VALUE interp;
+ VALUE error_mode;
+{
+ struct tcltkip *ptr;
+ int retry = 0;
+ int i, idx, objc;
+ Tcl_Obj **objv;
+ Tcl_Obj *enc_list;
+ volatile VALUE encname = Qnil;
+ volatile VALUE encobj = Qnil;
+
+ /* interpreter check */
+ if (NIL_P(interp)) return 0;
+ ptr = get_ip(interp);
+ if (ptr == (struct tcltkip *) NULL) return 0;
+ if (deleted_ip(ptr)) return 0;
+
+ /* get Tcl's encoding list */
+ Tcl_GetEncodingNames(ptr->ip);
+ enc_list = Tcl_GetObjResult(ptr->ip);
+ Tcl_IncrRefCount(enc_list);
+
+ if (Tcl_ListObjGetElements(ptr->ip, enc_list,
+ &objc, &objv) != TCL_OK) {
+ Tcl_DecrRefCount(enc_list);
+ /* rb_raise(rb_eRuntimeError, "failt to get Tcl's encoding names");*/
+ return 0;
+ }
+
+ /* check each encoding name */
+ for(i = 0; i < objc; i++) {
+ encname = rb_str_new2(Tcl_GetString(objv[i]));
+ if (NIL_P(rb_hash_lookup(table, encname))) {
+ /* new Tk encoding -> add to table */
+ idx = rb_enc_find_index(StringValueCStr(encname));
+ if (idx < 0) {
+ encobj = create_dummy_encoding_for_tk_core(interp,encname,error_mode);
+ } else {
+ encobj = rb_enc_from_encoding(rb_enc_from_index(idx));
+ }
+ encname = rb_obj_freeze(encname);
+ rb_hash_aset(table, encname, encobj);
+ if (!NIL_P(encobj) && NIL_P(rb_hash_lookup(table, encobj))) {
+ rb_hash_aset(table, encobj, encname);
+ }
+ retry = 1;
+ }
+ }
+
+ Tcl_DecrRefCount(enc_list);
+
+ return retry;
+}
+
+static VALUE
+encoding_table_get_name_core(table, enc_arg, error_mode)
+ VALUE table;
+ VALUE enc_arg;
+ VALUE error_mode;
+{
+ volatile VALUE enc = enc_arg;
+ volatile VALUE name = Qnil;
+ volatile VALUE tmp = Qnil;
+ volatile VALUE interp = rb_ivar_get(table, ID_at_interp);
+ struct tcltkip *ptr = (struct tcltkip *) NULL;
+ int idx;
+
+ /* deleted interp ? */
+ if (!NIL_P(interp)) {
+ ptr = get_ip(interp);
+ if (deleted_ip(ptr)) {
+ ptr = (struct tcltkip *) NULL;
+ }
+ }
+
+ /* encoding argument check */
+ /* 1st: default encoding setting of interp */
+ if (ptr && NIL_P(enc)) {
+ if (rb_respond_to(interp, ID_encoding_name)) {
+ enc = rb_funcall(interp, ID_encoding_name, 0, 0);
+ }
+ }
+ /* 2nd: encoding system of Tcl/Tk */
+ if (NIL_P(enc)) {
+ enc = rb_str_new2(Tcl_GetEncodingName((Tcl_Encoding)NULL));
+ }
+ /* 3rd: Encoding.default_external */
+ if (NIL_P(enc)) {
+ enc = rb_enc_default_external();
+ }
+
+ if (RTEST(rb_obj_is_kind_of(enc, cRubyEncoding))) {
+ /* Ruby's Encoding object */
+ name = rb_hash_lookup(table, enc);
+ if (!NIL_P(name)) {
+ /* find */
+ return name;
+ }
+
+ /* is it new ? */
+ /* update check of Tk encoding names */
+ if (update_encoding_table(table, interp, error_mode)) {
+ /* add new relations to the table */
+ /* RETRY: registered Ruby encoding? */
+ name = rb_hash_lookup(table, enc);
+ if (!NIL_P(name)) {
+ /* find */
+ return name;
+ }
+ }
+ /* fail to find */
+
+ } else {
+ /* String or Symbol? */
+ name = rb_funcall(enc, ID_to_s, 0, 0);
+
+ if (!NIL_P(rb_hash_lookup(table, name))) {
+ /* find */
+ return name;
+ }
+
+ /* is it new ? */
+ idx = rb_enc_find_index(StringValueCStr(name));
+ if (idx >= 0) {
+ enc = rb_enc_from_encoding(rb_enc_from_index(idx));
+
+ /* registered Ruby encoding? */
+ tmp = rb_hash_lookup(table, enc);
+ if (!NIL_P(tmp)) {
+ /* find */
+ return tmp;
+ }
+
+ /* update check of Tk encoding names */
+ if (update_encoding_table(table, interp, error_mode)) {
+ /* add new relations to the table */
+ /* RETRY: registered Ruby encoding? */
+ tmp = rb_hash_lookup(table, enc);
+ if (!NIL_P(tmp)) {
+ /* find */
+ return tmp;
+ }
+ }
+ }
+ /* fail to find */
+ }
+
+ if (RTEST(error_mode)) {
+ enc = rb_funcall(enc_arg, ID_to_s, 0, 0);
+ rb_raise(rb_eArgError, "unsupported Tk encoding '%s'", RSTRING_PTR(enc));
+ }
+ return Qnil;
+}
+static VALUE
+encoding_table_get_obj_core(table, enc, error_mode)
+ VALUE table;
+ VALUE enc;
+ VALUE error_mode;
+{
+ volatile VALUE obj = Qnil;
+
+ obj = rb_hash_lookup(table,
+ encoding_table_get_name_core(table, enc, error_mode));
+ if (RTEST(rb_obj_is_kind_of(obj, cRubyEncoding))) {
+ return obj;
+ } else {
+ return Qnil;
+ }
+}
+
+#else /* ! RUBY_VM */
+#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1)
+static int
+update_encoding_table(table, interp, error_mode)
+ VALUE table;
+ VALUE interp;
+ VALUE error_mode;
+{
+ struct tcltkip *ptr;
+ int retry = 0;
+ int i, idx, objc;
+ Tcl_Obj **objv;
+ Tcl_Obj *enc_list;
+ volatile VALUE encname = Qnil;
+ volatile VALUE encobj = Qnil;
+
+ /* interpreter check */
+ if (NIL_P(interp)) return 0;
+ ptr = get_ip(interp);
+ if (ptr == (struct tcltkip *) NULL) return 0;
+ if (deleted_ip(ptr)) return 0;
+
+ /* get Tcl's encoding list */
+ Tcl_GetEncodingNames(ptr->ip);
+ enc_list = Tcl_GetObjResult(ptr->ip);
+ Tcl_IncrRefCount(enc_list);
+
+ if (Tcl_ListObjGetElements(ptr->ip, enc_list, &objc, &objv) != TCL_OK) {
+ Tcl_DecrRefCount(enc_list);
+ /* rb_raise(rb_eRuntimeError, "failt to get Tcl's encoding names"); */
+ return 0;
+ }
+
+ /* get encoding name and set it to table */
+ for(i = 0; i < objc; i++) {
+ encname = rb_str_new2(Tcl_GetString(objv[i]));
+ if (NIL_P(rb_hash_lookup(table, encname))) {
+ /* new Tk encoding -> add to table */
+ encname = rb_obj_freeze(encname);
+ rb_hash_aset(table, encname, encname);
+ retry = 1;
+ }
+ }
+
+ Tcl_DecrRefCount(enc_list);
+
+ return retry;
+}
+
+static VALUE
+encoding_table_get_name_core(table, enc, error_mode)
+ VALUE table;
+ VALUE enc;
+ VALUE error_mode;
+{
+ volatile VALUE name = Qnil;
+ int retry = 0;
+
+ enc = rb_funcall(enc, ID_to_s, 0, 0);
+ name = rb_hash_lookup(table, enc);
+
+ if (!NIL_P(name)) {
+ /* find */
+ return name;
+ }
+
+ /* update check */
+ if (update_encoding_table(table, rb_ivar_get(table, ID_at_interp),
+ error_mode)) {
+ /* add new relations to the table */
+ /* RETRY: registered Ruby encoding? */
+ name = rb_hash_lookup(table, enc);
+ if (!NIL_P(name)) {
+ /* find */
+ return name;
+ }
+ }
+
+ if (RTEST(error_mode)) {
+ rb_raise(rb_eArgError, "unsupported Tk encoding '%s'", RSTRING_PTR(enc));
+ }
+ return Qnil;
+}
+static VALUE
+encoding_table_get_obj_core(table, enc, error_mode)
+ VALUE table;
+ VALUE enc;
+ VALUE error_mode;
+{
+ return encoding_table_get_name_core(table, enc, error_mode);
+}
+
+#else /* Tcl/Tk 7.x or 8.0 */
+static VALUE
+encoding_table_get_name_core(table, enc, error_mode)
+ VALUE table;
+ VALUE enc;
+ VALUE error_mode;
+{
+ return Qnil;
+}
+static VALUE
+encoding_table_get_obj_core(table, enc, error_mode)
+ VALUE table;
+ VALUE enc;
+ VALUE error_mode;
+{
+ return Qnil;
+}
+#endif /* end of dependency for the version of Tcl/Tk */
+#endif
+
+static VALUE
+encoding_table_get_name(table, enc)
+ VALUE table;
+ VALUE enc;
+{
+ return encoding_table_get_name_core(table, enc, Qtrue);
+}
+static VALUE
+encoding_table_get_obj(table, enc)
+ VALUE table;
+ VALUE enc;
+{
+ return encoding_table_get_obj_core(table, enc, Qtrue);
+}
+
+#ifdef RUBY_VM
+static VALUE
+create_encoding_table(interp)
+ VALUE interp;
+{
+ struct tcltkip *ptr = get_ip(interp);
+ volatile VALUE table = rb_hash_new();
+ volatile VALUE encname = Qnil;
+ volatile VALUE encobj = Qnil;
+ int i, idx, objc;
+ Tcl_Obj **objv;
+ Tcl_Obj *enc_list;
+
+ rb_secure(4);
+
+ /* set 'binary' encoding */
+ encobj = rb_enc_from_encoding(rb_enc_from_index(ENCODING_INDEX_BINARY));
+ rb_hash_aset(table, ENCODING_NAME_BINARY, encobj);
+ rb_hash_aset(table, encobj, ENCODING_NAME_BINARY);
+
+
+ /* Tcl stub check */
+ tcl_stubs_check();
+
+ /* get Tcl's encoding list */
+ Tcl_GetEncodingNames(ptr->ip);
+ enc_list = Tcl_GetObjResult(ptr->ip);
+ Tcl_IncrRefCount(enc_list);
+
+ if (Tcl_ListObjGetElements(ptr->ip, enc_list, &objc, &objv) != TCL_OK) {
+ Tcl_DecrRefCount(enc_list);
+ rb_raise(rb_eRuntimeError, "failt to get Tcl's encoding names");
+ }
+
+ /* get encoding name and set it to table */
+ for(i = 0; i < objc; i++) {
+ int name2obj, obj2name;
+
+ name2obj = 1; obj2name = 1;
+ encname = rb_obj_freeze(rb_str_new2(Tcl_GetString(objv[i])));
+ idx = rb_enc_find_index(StringValueCStr(encname));
+ if (idx < 0) {
+ /* fail to find ruby encoding -> check known encoding */
+ if (strcmp(RSTRING_PTR(encname), "identity") == 0) {
+ name2obj = 1; obj2name = 0;
+ idx = ENCODING_INDEX_BINARY;
+
+ } else if (strcmp(RSTRING_PTR(encname), "shiftjis") == 0) {
+ name2obj = 1; obj2name = 0;
+ idx = rb_enc_find_index("Shift_JIS");
+
+ } else if (strcmp(RSTRING_PTR(encname), "unicode") == 0) {
+ name2obj = 1; obj2name = 0;
+ idx = ENCODING_INDEX_UTF8;
+
+ } else if (strcmp(RSTRING_PTR(encname), "symbol") == 0) {
+ name2obj = 1; obj2name = 0;
+ idx = rb_enc_find_index("ASCII-8BIT");
+
+ } else {
+ /* regist dummy encoding */
+ name2obj = 1; obj2name = 1;
+ }
+ }
+
+ if (idx < 0) {
+ /* unknown encoding -> create dummy */
+ encobj = create_dummy_encoding_for_tk(interp, encname);
+ } else {
+ encobj = rb_enc_from_encoding(rb_enc_from_index(idx));
+ }
+
+ if (name2obj) {
+ DUMP2("create_encoding_table: name2obj: %s", RSTRING_PTR(encname));
+ rb_hash_aset(table, encname, encobj);
+ }
+ if (obj2name) {
+ DUMP2("create_encoding_table: obj2name: %s", RSTRING_PTR(encname));
+ rb_hash_aset(table, encobj, encname);
+ }
+ }
+
+ Tcl_DecrRefCount(enc_list);
+
+ rb_ivar_set(table, ID_at_interp, interp);
+ rb_ivar_set(interp, ID_encoding_table, table);
+
+ return table;
+}
+
+#else /* ! RUBY_VM */
+#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1)
+static VALUE
+create_encoding_table(interp)
+ VALUE interp;
+{
+ struct tcltkip *ptr = get_ip(interp);
+ volatile VALUE table = rb_hash_new();
+ volatile VALUE encname = Qnil;
+ int i, objc;
+ Tcl_Obj **objv;
+ Tcl_Obj *enc_list;
+
+ rb_secure(4);
+
+ /* set 'binary' encoding */
+ rb_hash_aset(table, ENCODING_NAME_BINARY, ENCODING_NAME_BINARY);
+
+ /* get Tcl's encoding list */
+ Tcl_GetEncodingNames(ptr->ip);
+ enc_list = Tcl_GetObjResult(ptr->ip);
+ Tcl_IncrRefCount(enc_list);
+
+ if (Tcl_ListObjGetElements(ptr->ip, enc_list, &objc, &objv) != TCL_OK) {
+ Tcl_DecrRefCount(enc_list);
+ rb_raise(rb_eRuntimeError, "failt to get Tcl's encoding names");
+ }
+
+ /* get encoding name and set it to table */
+ for(i = 0; i < objc; i++) {
+ encname = rb_obj_freeze(rb_str_new2(Tcl_GetString(objv[i])));
+ rb_hash_aset(table, encname, encname);
+ }
+
+ Tcl_DecrRefCount(enc_list);
+
+ rb_ivar_set(table, ID_at_interp, interp);
+ rb_ivar_set(interp, ID_encoding_table, table);
+
+ return table;
+}
+
+#else /* Tcl/Tk 7.x or 8.0 */
+static VALUE
+create_encoding_table(interp)
+ VALUE interp;
+{
+ volatile VALUE table = rb_hash_new();
+ rb_secure(4);
+ rb_ivar_set(interp, ID_encoding_table, table);
+ return table;
+}
+#endif
+#endif
+
+static VALUE
+ip_get_encoding_table(interp)
+ VALUE interp;
+{
+ volatile VALUE table = Qnil;
+
+ table = rb_ivar_get(interp, ID_encoding_table);
+
+ if (NIL_P(table)) {
+ /* initialize encoding_table */
+ table = create_encoding_table(interp);
+ rb_define_singleton_method(table, "get_name", encoding_table_get_name, 1);
+ rb_define_singleton_method(table, "get_obj", encoding_table_get_obj, 1);
+ }
+
+ return table;
+}
+
+
/*###############################################*/
/*
* The following is based on tkMenu.[ch]
- * of Tcl/Tk (>=8.0) source code.
+ * of Tcl/Tk (Tk8.0 -- Tk8.5b1) source code.
*/
#if TCL_MAJOR_VERSION >= 8
@@ -7831,22 +9841,45 @@ struct dummy_TkMenuRef {
char *dummy3;
};
+#if 0 /* was available on Tk8.0 -- Tk8.4 */
EXTERN struct dummy_TkMenuRef *TkFindMenuReferences(Tcl_Interp*, char*);
+#else /* based on Tk8.0 -- Tk8.5.0 */
+#define MENU_HASH_KEY "tkMenus"
+#endif
#endif
static VALUE
-ip_make_menu_embeddable(interp, menu_path)
+ip_make_menu_embeddable_core(interp, argc, argv)
VALUE interp;
- VALUE menu_path;
+ int argc;
+ VALUE *argv;
{
#if TCL_MAJOR_VERSION >= 8
+ volatile VALUE menu_path;
struct tcltkip *ptr = get_ip(interp);
- struct dummy_TkMenuRef *menuRefPtr;
+ struct dummy_TkMenuRef *menuRefPtr = NULL;
+ XEvent event;
+ Tcl_HashTable *menuTablePtr;
+ Tcl_HashEntry *hashEntryPtr;
+ menu_path = argv[0];
StringValue(menu_path);
- menuRefPtr = TkFindMenuReferences(ptr->ip, RSTRING(menu_path)->ptr);
+#if 0 /* was available on Tk8.0 -- Tk8.4 */
+ menuRefPtr = TkFindMenuReferences(ptr->ip, RSTRING_PTR(menu_path));
+#else /* based on Tk8.0 -- Tk8.5b1 */
+ if ((menuTablePtr
+ = (Tcl_HashTable *) Tcl_GetAssocData(ptr->ip, MENU_HASH_KEY, NULL))
+ != NULL) {
+ if ((hashEntryPtr
+ = Tcl_FindHashEntry(menuTablePtr, RSTRING_PTR(menu_path)))
+ != NULL) {
+ menuRefPtr = (struct dummy_TkMenuRef *) Tcl_GetHashValue(hashEntryPtr);
+ }
+ }
+#endif
+
if (menuRefPtr == (struct dummy_TkMenuRef *) NULL) {
rb_raise(rb_eArgError, "not a menu widget, or invalid widget path");
}
@@ -7868,14 +9901,26 @@ ip_make_menu_embeddable(interp, menu_path)
char *s = "normal";
/* Tcl_SetStringObj((menuRefPtr->menuPtr)->menuTypePtr, s, strlen(s));*/
(menuRefPtr->menuPtr)->menuTypePtr = Tcl_NewStringObj(s, strlen(s));
+ /* Tcl_IncrRefCount((menuRefPtr->menuPtr)->menuTypePtr); */
/* (menuRefPtr->menuPtr)->menuType = TEAROFF_MENU; */
(menuRefPtr->menuPtr)->menuType = MASTER_MENU;
}
#endif
+#if 0 /* was available on Tk8.0 -- Tk8.4 */
TkEventuallyRecomputeMenu(menuRefPtr->menuPtr);
TkEventuallyRedrawMenu(menuRefPtr->menuPtr,
(struct dummy_TkMenuEntry *)NULL);
+#else /* based on Tk8.0 -- Tk8.5b1 */
+ memset((void *) &event, 0, sizeof(event));
+ event.xany.type = ConfigureNotify;
+ event.xany.serial = NextRequest(Tk_Display((menuRefPtr->menuPtr)->tkwin));
+ event.xany.send_event = 0; /* FALSE */
+ event.xany.window = Tk_WindowId((menuRefPtr->menuPtr)->tkwin);
+ event.xany.display = Tk_Display((menuRefPtr->menuPtr)->tkwin);
+ event.xconfigure.window = event.xany.window;
+ Tk_HandleEvent(&event);
+#endif
#else /* TCL_MAJOR_VERSION <= 7 */
rb_notimplement();
@@ -7884,6 +9929,18 @@ ip_make_menu_embeddable(interp, menu_path)
return interp;
}
+static VALUE
+ip_make_menu_embeddable(interp, menu_path)
+ VALUE interp;
+ VALUE menu_path;
+{
+ VALUE argv[1];
+
+ argv[0] = menu_path;
+ return tk_funcall(ip_make_menu_embeddable_core, 1, argv, interp);
+}
+
+
/*###############################################*/
/*---- initialization ----*/
@@ -7897,6 +9954,7 @@ Init_tcltklib()
VALUE ev_flag = rb_define_module_under(lib, "EventFlag");
VALUE var_flag = rb_define_module_under(lib, "VarAccessFlag");
+ VALUE release_type = rb_define_module_under(lib, "RELEASE_TYPE");
/* --------------------------------------------------------------- */
@@ -7904,6 +9962,22 @@ Init_tcltklib()
/* --------------------------------------------------------------- */
+#ifdef RUBY_VM
+ rb_global_variable(&cRubyEncoding);
+ cRubyEncoding = rb_const_get(rb_cObject, rb_intern("Encoding"));
+
+ ENCODING_INDEX_UTF8 = rb_enc_to_index(rb_utf8_encoding());
+ ENCODING_INDEX_BINARY = rb_enc_find_index("binary");
+#endif
+
+ rb_global_variable(&ENCODING_NAME_UTF8);
+ rb_global_variable(&ENCODING_NAME_BINARY);
+
+ ENCODING_NAME_UTF8 = rb_obj_freeze(rb_str_new2("utf-8"));
+ ENCODING_NAME_BINARY = rb_obj_freeze(rb_str_new2("binary"));
+
+ /* --------------------------------------------------------------- */
+
rb_global_variable(&eTkCallbackReturn);
rb_global_variable(&eTkCallbackBreak);
rb_global_variable(&eTkCallbackContinue);
@@ -7954,6 +10028,14 @@ Init_tcltklib()
/* --------------------------------------------------------------- */
+ rb_define_module_function(lib, "get_version", lib_getversion, -1);
+
+ rb_define_const(release_type, "ALPHA", INT2FIX(TCL_ALPHA_RELEASE));
+ rb_define_const(release_type, "BETA", INT2FIX(TCL_BETA_RELEASE));
+ rb_define_const(release_type, "FINAL", INT2FIX(TCL_FINAL_RELEASE));
+
+ /* --------------------------------------------------------------- */
+
eTkCallbackReturn = rb_define_class("TkCallbackReturn", rb_eStandardError);
eTkCallbackBreak = rb_define_class("TkCallbackBreak", rb_eStandardError);
eTkCallbackContinue = rb_define_class("TkCallbackContinue",
@@ -7973,6 +10055,8 @@ Init_tcltklib()
ID_at_enc = rb_intern("@encoding");
ID_at_interp = rb_intern("@interp");
+ ID_encoding_name = rb_intern("encoding_name");
+ ID_encoding_table = rb_intern("encoding_table");
ID_stop_p = rb_intern("stop?");
ID_alive_p = rb_intern("alive?");
@@ -8006,6 +10090,10 @@ Init_tcltklib()
lib_evloop_abort_on_exc, 0);
rb_define_module_function(lib, "mainloop_abort_on_exception=",
lib_evloop_abort_on_exc_set, 1);
+ rb_define_module_function(lib, "set_eventloop_window_mode",
+ set_eventloop_window_mode, 1);
+ rb_define_module_function(lib, "get_eventloop_window_mode",
+ get_eventloop_window_mode, 0);
rb_define_module_function(lib, "set_eventloop_tick",set_eventloop_tick,1);
rb_define_module_function(lib, "get_eventloop_tick",get_eventloop_tick,0);
rb_define_module_function(lib, "set_no_event_wait", set_no_event_wait, 1);
@@ -8067,6 +10155,12 @@ Init_tcltklib()
/* --------------------------------------------------------------- */
+ rb_define_method(ip, "create_dummy_encoding_for_tk",
+ create_dummy_encoding_for_tk, 1);
+ rb_define_method(ip, "encoding_table", ip_get_encoding_table, 0);
+
+ /* --------------------------------------------------------------- */
+
rb_define_method(ip, "_get_variable", ip_get_variable, 2);
rb_define_method(ip, "_get_variable2", ip_get_variable2, 3);
rb_define_method(ip, "_set_variable", ip_set_variable, 3);
@@ -8126,7 +10220,11 @@ Init_tcltklib()
/* if ruby->nativethread-supprt and tcltklib->doen't,
the following will cause link-error. */
+#ifdef RUBY_VM
+ ruby_native_thread_p();
+#else
is_ruby_native_thread();
+#endif
/* --------------------------------------------------------------- */
@@ -8134,7 +10232,7 @@ Init_tcltklib()
/* --------------------------------------------------------------- */
- ret = ruby_open_tcl_dll(rb_argv0 ? RSTRING(rb_argv0)->ptr : 0);
+ ret = ruby_open_tcl_dll(rb_argv0 ? RSTRING_PTR(rb_argv0) : 0);
switch(ret) {
case TCLTK_STUBS_OK:
break;
@@ -8147,6 +10245,14 @@ Init_tcltklib()
}
/* --------------------------------------------------------------- */
+
+ /* Tcl stub check */
+ tcl_stubs_check();
+
+ Tcl_ObjType_ByteArray = Tcl_GetObjType(Tcl_ObjTypeName_ByteArray);
+ Tcl_ObjType_String = Tcl_GetObjType(Tcl_ObjTypeName_String);
+
+ /* --------------------------------------------------------------- */
}
/* eof */
diff --git a/ext/tk/tkutil/extconf.rb b/ext/tk/tkutil/extconf.rb
index e3aa00a4b2..015bc3a45e 100644
--- a/ext/tk/tkutil/extconf.rb
+++ b/ext/tk/tkutil/extconf.rb
@@ -1,4 +1,13 @@
-if compiled?('tk')
+begin
+ has_tk = compiled?('tk')
+rescue NoMethodError
+ # Probably, called manually (NOT from 'extmk.rb'). Force to make Makefile.
+ has_tk = true
+end
+
+if has_tk
require 'mkmf'
+ have_func("rb_obj_instance_exec", "ruby.h")
+ have_func("strndup", "string.h")
create_makefile('tkutil')
end
diff --git a/ext/tk/tkutil/tkutil.c b/ext/tk/tkutil/tkutil.c
index be1b635a0f..00d719143b 100644
--- a/ext/tk/tkutil/tkutil.c
+++ b/ext/tk/tkutil/tkutil.c
@@ -2,18 +2,25 @@
tkutil.c -
- $Author: nagai $
- $Date: 2006/04/05 16:08:45 $
+ $Author$
created at: Fri Nov 3 00:47:54 JST 1995
************************************************/
-#define TKUTIL_RELEASE_DATE "2006-04-06"
+#define TKUTIL_RELEASE_DATE "2008-05-23"
#include "ruby.h"
+
+#ifdef RUBY_VM /* Ruby 1.9 */
+/* #include "ruby/ruby.h" */
+#include "ruby/signal.h"
+#include "ruby/st.h"
+#else
+/* #include "ruby.h" */
#include "rubysig.h"
#include "version.h"
#include "st.h"
+#endif
static VALUE cMethod;
@@ -27,6 +34,8 @@ static VALUE TK_None;
static VALUE cCB_SUBST;
static VALUE cSUBST_INFO;
+static VALUE ENCODING_NAME_UTF8; /* for saving GC cost */
+
static ID ID_split_tklist;
static ID ID_toUTF8;
static ID ID_fromUTF8;
@@ -59,7 +68,7 @@ tk_s_new(argc, argv, klass)
VALUE obj = rb_class_new_instance(argc, argv, klass);
if (rb_block_given_p()) {
-#if RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR <= 8 /* ruby 1.8.x */
+#ifndef HAVE_RB_OBJ_INSTANCE_EXEC
rb_obj_instance_eval(0, 0, obj);
#else
rb_obj_instance_exec(1, &obj, obj);
@@ -155,16 +164,16 @@ tk_uninstall_cmd(self, cmd_id)
int prefix_len = strlen(cmd_id_prefix);
StringValue(cmd_id);
- if (strncmp(cmd_id_head, RSTRING(cmd_id)->ptr, head_len) != 0) {
+ if (strncmp(cmd_id_head, RSTRING_PTR(cmd_id), head_len) != 0) {
return Qnil;
}
if (strncmp(cmd_id_prefix,
- RSTRING(cmd_id)->ptr + head_len, prefix_len) != 0) {
+ RSTRING_PTR(cmd_id) + head_len, prefix_len) != 0) {
return Qnil;
}
return rb_hash_delete(CALLBACK_TABLE,
- rb_str_new2(RSTRING(cmd_id)->ptr + head_len));
+ rb_str_new2(RSTRING_PTR(cmd_id) + head_len));
}
static VALUE
@@ -227,7 +236,7 @@ tk_symbolkey2str(self, keys)
if NIL_P(keys) return new_keys;
keys = rb_convert_type(keys, T_HASH, "Hash", "to_hash");
- st_foreach(RHASH(keys)->tbl, to_strkey, new_keys);
+ st_foreach(RHASH_TBL(keys), to_strkey, new_keys);
return new_keys;
}
@@ -267,25 +276,24 @@ ary2list(ary, enc_flag, self)
req_chk_flag = 0;
}
- /* size = RARRAY(ary)->len; */
+ /* size = RARRAY_LEN(ary); */
size = 0;
- for(idx = 0; idx < RARRAY(ary)->len; idx++) {
- if (TYPE(RARRAY(ary)->ptr[idx]) == T_HASH) {
- size += 2 * RHASH(RARRAY(ary)->ptr[idx])->tbl->num_entries;
+ for(idx = 0; idx < RARRAY_LEN(ary); idx++) {
+ if (TYPE(RARRAY_PTR(ary)[idx]) == T_HASH) {
+ size += 2 * RHASH_SIZE(RARRAY_PTR(ary)[idx]);
} else {
size++;
}
}
dst = rb_ary_new2(size);
- RARRAY(dst)->len = 0;
- for(idx = 0; idx < RARRAY(ary)->len; idx++) {
- val = RARRAY(ary)->ptr[idx];
+ for(idx = 0; idx < RARRAY_LEN(ary); idx++) {
+ val = RARRAY_PTR(ary)[idx];
str_val = Qnil;
switch(TYPE(val)) {
case T_ARRAY:
str_val = ary2list(val, enc_flag, self);
- RARRAY(dst)->ptr[RARRAY(dst)->len++] = str_val;
+ rb_ary_push(dst, str_val);
if (req_chk_flag) {
str_enc = rb_ivar_get(str_val, ID_at_enc);
@@ -303,19 +311,19 @@ ary2list(ary, enc_flag, self)
break;
case T_HASH:
- /* RARRAY(dst)->ptr[RARRAY(dst)->len++] = hash2list(val, self); */
+ /* rb_ary_push(dst, hash2list(val, self)); */
if (RTEST(enc_flag)) {
val = hash2kv_enc(val, Qnil, self);
} else {
val = hash2kv(val, Qnil, self);
}
- size2 = RARRAY(val)->len;
+ size2 = RARRAY_LEN(val);
for(idx2 = 0; idx2 < size2; idx2++) {
- val2 = RARRAY(val)->ptr[idx2];
+ val2 = RARRAY_PTR(val)[idx2];
switch(TYPE(val2)) {
case T_ARRAY:
str_val = ary2list(val2, enc_flag, self);
- RARRAY(dst)->ptr[RARRAY(dst)->len++] = str_val;
+ rb_ary_push(dst, str_val);
break;
case T_HASH:
@@ -324,13 +332,13 @@ ary2list(ary, enc_flag, self)
} else {
str_val = hash2list(val2, self);
}
- RARRAY(dst)->ptr[RARRAY(dst)->len++] = str_val;
+ rb_ary_push(dst, str_val);
break;
default:
if (val2 != TK_None) {
str_val = get_eval_string_core(val2, enc_flag, self);
- RARRAY(dst)->ptr[RARRAY(dst)->len++] = str_val;
+ rb_ary_push(dst, str_val);
}
}
@@ -352,7 +360,7 @@ ary2list(ary, enc_flag, self)
default:
if (val != TK_None) {
str_val = get_eval_string_core(val, enc_flag, self);
- RARRAY(dst)->ptr[RARRAY(dst)->len++] = str_val;
+ rb_ary_push(dst, str_val);
if (req_chk_flag) {
str_enc = rb_ivar_get(str_val, ID_at_enc);
@@ -371,21 +379,21 @@ ary2list(ary, enc_flag, self)
}
if (RTEST(dst_enc) && !NIL_P(sys_enc)) {
- for(idx = 0; idx < RARRAY(dst)->len; idx++) {
- str_val = RARRAY(dst)->ptr[idx];
+ for(idx = 0; idx < RARRAY_LEN(dst); idx++) {
+ str_val = RARRAY_PTR(dst)[idx];
if (rb_obj_respond_to(self, ID_toUTF8, Qtrue)) {
str_val = rb_funcall(self, ID_toUTF8, 1, str_val);
} else {
str_val = rb_funcall(cTclTkLib, ID_toUTF8, 1, str_val);
}
- RARRAY(dst)->ptr[idx] = str_val;
+ RARRAY_PTR(dst)[idx] = str_val;
}
val = rb_apply(cTclTkLib, ID_merge_tklist, dst);
if (TYPE(dst_enc) == T_STRING) {
val = rb_funcall(cTclTkLib, ID_fromUTF8, 2, val, dst_enc);
rb_ivar_set(val, ID_at_enc, dst_enc);
} else {
- rb_ivar_set(val, ID_at_enc, rb_str_new2("utf-8"));
+ rb_ivar_set(val, ID_at_enc, ENCODING_NAME_UTF8);
}
return val;
} else {
@@ -421,11 +429,10 @@ ary2list2(ary, enc_flag, self)
req_chk_flag = 0;
}
- size = RARRAY(ary)->len;
+ size = RARRAY_LEN(ary);
dst = rb_ary_new2(size);
- RARRAY(dst)->len = 0;
- for(idx = 0; idx < RARRAY(ary)->len; idx++) {
- val = RARRAY(ary)->ptr[idx];
+ for(idx = 0; idx < RARRAY_LEN(ary); idx++) {
+ val = RARRAY_PTR(ary)[idx];
str_val = Qnil;
switch(TYPE(val)) {
case T_ARRAY:
@@ -447,7 +454,7 @@ ary2list2(ary, enc_flag, self)
}
if (!NIL_P(str_val)) {
- RARRAY(dst)->ptr[RARRAY(dst)->len++] = str_val;
+ rb_ary_push(dst, str_val);
if (req_chk_flag) {
str_enc = rb_ivar_get(str_val, ID_at_enc);
@@ -465,21 +472,21 @@ ary2list2(ary, enc_flag, self)
}
if (RTEST(dst_enc) && !NIL_P(sys_enc)) {
- for(idx = 0; idx < RARRAY(dst)->len; idx++) {
- str_val = RARRAY(dst)->ptr[idx];
+ for(idx = 0; idx < RARRAY_LEN(dst); idx++) {
+ str_val = RARRAY_PTR(dst)[idx];
if (rb_obj_respond_to(self, ID_toUTF8, Qtrue)) {
str_val = rb_funcall(self, ID_toUTF8, 1, str_val);
} else {
str_val = rb_funcall(cTclTkLib, ID_toUTF8, 1, str_val);
}
- RARRAY(dst)->ptr[idx] = str_val;
+ RARRAY_PTR(dst)[idx] = str_val;
}
val = rb_apply(cTclTkLib, ID_merge_tklist, dst);
if (TYPE(dst_enc) == T_STRING) {
val = rb_funcall(cTclTkLib, ID_fromUTF8, 2, val, dst_enc);
rb_ivar_set(val, ID_at_enc, dst_enc);
} else {
- rb_ivar_set(val, ID_at_enc, rb_str_new2("utf-8"));
+ rb_ivar_set(val, ID_at_enc, ENCODING_NAME_UTF8);
}
return val;
} else {
@@ -503,38 +510,35 @@ assoc2kv(assoc, ary, self)
int i, j, len;
volatile VALUE pair;
volatile VALUE val;
- volatile VALUE dst = rb_ary_new2(2 * RARRAY(assoc)->len);
+ volatile VALUE dst = rb_ary_new2(2 * RARRAY_LEN(assoc));
- len = RARRAY(assoc)->len;
+ len = RARRAY_LEN(assoc);
for(i = 0; i < len; i++) {
- pair = RARRAY(assoc)->ptr[i];
+ pair = RARRAY_PTR(assoc)[i];
if (TYPE(pair) != T_ARRAY) {
- RARRAY(dst)->ptr[RARRAY(dst)->len++] = key2keyname(pair);
+ rb_ary_push(dst, key2keyname(pair));
continue;
}
- switch(RARRAY(assoc)->len) {
+ switch(RARRAY_LEN(assoc)) {
case 2:
- RARRAY(dst)->ptr[RARRAY(dst)->len++] = RARRAY(pair)->ptr[2];
+ rb_ary_push(dst, RARRAY_PTR(pair)[2]);
case 1:
- RARRAY(dst)->ptr[RARRAY(dst)->len++]
- = key2keyname(RARRAY(pair)->ptr[0]);
+ rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0]));
case 0:
continue;
default:
- RARRAY(dst)->ptr[RARRAY(dst)->len++]
- = key2keyname(RARRAY(pair)->ptr[0]);
+ rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0]));
- val = rb_ary_new2(RARRAY(pair)->len - 1);
- RARRAY(val)->len = 0;
- for(j = 1; j < RARRAY(pair)->len; j++) {
- RARRAY(val)->ptr[RARRAY(val)->len++] = RARRAY(pair)->ptr[j];
+ val = rb_ary_new2(RARRAY_LEN(pair) - 1);
+ for(j = 1; j < RARRAY_LEN(pair); j++) {
+ rb_ary_push(val, RARRAY_PTR(pair)[j]);
}
- RARRAY(dst)->ptr[RARRAY(dst)->len++] = val;
+ rb_ary_push(dst, val);
}
}
@@ -554,40 +558,35 @@ assoc2kv_enc(assoc, ary, self)
int i, j, len;
volatile VALUE pair;
volatile VALUE val;
- volatile VALUE dst = rb_ary_new2(2 * RARRAY(assoc)->len);
+ volatile VALUE dst = rb_ary_new2(2 * RARRAY_LEN(assoc));
- len = RARRAY(assoc)->len;
+ len = RARRAY_LEN(assoc);
for(i = 0; i < len; i++) {
- pair = RARRAY(assoc)->ptr[i];
+ pair = RARRAY_PTR(assoc)[i];
if (TYPE(pair) != T_ARRAY) {
- RARRAY(dst)->ptr[RARRAY(dst)->len++] = key2keyname(pair);
+ rb_ary_push(dst, key2keyname(pair));
continue;
}
- switch(RARRAY(assoc)->len) {
+ switch(RARRAY_LEN(assoc)) {
case 2:
- RARRAY(dst)->ptr[RARRAY(dst)->len++]
- = get_eval_string_core(RARRAY(pair)->ptr[2], Qtrue, self);
+ rb_ary_push(dst, get_eval_string_core(RARRAY_PTR(pair)[2], Qtrue, self));
case 1:
- RARRAY(dst)->ptr[RARRAY(dst)->len++]
- = key2keyname(RARRAY(pair)->ptr[0]);
+ rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0]));
case 0:
continue;
default:
- RARRAY(dst)->ptr[RARRAY(dst)->len++]
- = key2keyname(RARRAY(pair)->ptr[0]);
+ rb_ary_push(dst, key2keyname(RARRAY_PTR(pair)[0]));
- val = rb_ary_new2(RARRAY(pair)->len - 1);
- RARRAY(val)->len = 0;
- for(j = 1; j < RARRAY(pair)->len; j++) {
- RARRAY(val)->ptr[RARRAY(val)->len++] = RARRAY(pair)->ptr[j];
+ val = rb_ary_new2(RARRAY_LEN(pair) - 1);
+ for(j = 1; j < RARRAY_LEN(pair); j++) {
+ rb_ary_push(val, RARRAY_PTR(pair)[j]);
}
- RARRAY(dst)->ptr[RARRAY(dst)->len++]
- = get_eval_string_core(val, Qtrue, self);
+ rb_ary_push(dst, get_eval_string_core(val, Qtrue, self));
}
}
@@ -606,19 +605,18 @@ push_kv(key, val, args)
{
volatile VALUE ary;
- ary = RARRAY(args)->ptr[0];
+ ary = RARRAY_PTR(args)[0];
if (key == Qundef) return ST_CONTINUE;
#if 0
rb_ary_push(ary, key2keyname(key));
if (val != TK_None) rb_ary_push(ary, val);
#endif
- RARRAY(ary)->ptr[RARRAY(ary)->len++] = key2keyname(key);
+ rb_ary_push(ary, key2keyname(key));
if (val == TK_None) return ST_CHECK;
- RARRAY(ary)->ptr[RARRAY(ary)->len++]
- = get_eval_string_core(val, Qnil, RARRAY(args)->ptr[1]);
+ rb_ary_push(ary, get_eval_string_core(val, Qnil, RARRAY_PTR(args)[1]));
return ST_CHECK;
}
@@ -629,15 +627,10 @@ hash2kv(hash, ary, self)
VALUE ary;
VALUE self;
{
- volatile VALUE args = rb_ary_new2(2);
- volatile VALUE dst = rb_ary_new2(2 * RHASH(hash)->tbl->num_entries);
-
- RARRAY(dst)->len = 0;
+ volatile VALUE dst = rb_ary_new2(2 * RHASH_SIZE(hash));
+ volatile VALUE args = rb_ary_new3(2, dst, self);
- RARRAY(args)->ptr[0] = dst;
- RARRAY(args)->ptr[1] = self;
- RARRAY(args)->len = 2;
- st_foreach(RHASH(hash)->tbl, push_kv, args);
+ st_foreach(RHASH_TBL(hash), push_kv, args);
if (NIL_P(ary)) {
return dst;
@@ -654,22 +647,21 @@ push_kv_enc(key, val, args)
{
volatile VALUE ary;
- ary = RARRAY(args)->ptr[0];
+ ary = RARRAY_PTR(args)[0];
if (key == Qundef) return ST_CONTINUE;
#if 0
rb_ary_push(ary, key2keyname(key));
if (val != TK_None) {
rb_ary_push(ary, get_eval_string_core(val, Qtrue,
- RARRAY(args)->ptr[1]));
+ RARRAY_PTR(args)[1]));
}
#endif
- RARRAY(ary)->ptr[RARRAY(ary)->len++] = key2keyname(key);
+ rb_ary_push(ary, key2keyname(key));
if (val == TK_None) return ST_CHECK;
- RARRAY(ary)->ptr[RARRAY(ary)->len++]
- = get_eval_string_core(val, Qtrue, RARRAY(args)->ptr[1]);
+ rb_ary_push(ary, get_eval_string_core(val, Qtrue, RARRAY_PTR(args)[1]));
return ST_CHECK;
}
@@ -680,15 +672,10 @@ hash2kv_enc(hash, ary, self)
VALUE ary;
VALUE self;
{
- volatile VALUE args = rb_ary_new2(2);
- volatile VALUE dst = rb_ary_new2(2 * RHASH(hash)->tbl->num_entries);
-
- RARRAY(dst)->len = 0;
+ volatile VALUE dst = rb_ary_new2(2 * RHASH_SIZE(hash));
+ volatile VALUE args = rb_ary_new3(2, dst, self);
- RARRAY(args)->ptr[0] = dst;
- RARRAY(args)->ptr[1] = self;
- RARRAY(args)->len = 2;
- st_foreach(RHASH(hash)->tbl, push_kv_enc, args);
+ st_foreach(RHASH_TBL(hash), push_kv_enc, args);
if (NIL_P(ary)) {
return dst;
@@ -804,7 +791,11 @@ get_eval_string_core(obj, enc_flag, self)
return fromDefaultEnc_toUTF8(rb_str_new2(rb_id2name(SYM2ID(obj))), self);
}
} else {
+#ifdef RUBY_VM
+ return rb_sym_to_s(obj);
+#else
return rb_str_new2(rb_id2name(SYM2ID(obj)));
+#endif
}
case T_HASH:
@@ -862,7 +853,7 @@ get_eval_string_core(obj, enc_flag, self)
}
rb_warning("fail to convert '%s' to string for Tk",
- RSTRING(rb_funcall(obj, rb_intern("inspect"), 0, 0))->ptr);
+ RSTRING_PTR(rb_funcall(obj, rb_intern("inspect"), 0, 0)));
return obj;
}
@@ -915,14 +906,13 @@ tk_conv_args(argc, argv, self)
for(size = 0, idx = 2; idx < argc; idx++) {
if (TYPE(argv[idx]) == T_HASH) {
- size += 2 * RHASH(argv[idx])->tbl->num_entries;
+ size += 2 * RHASH_SIZE(argv[idx]);
} else {
size++;
}
}
/* dst = rb_ary_new2(argc - 2); */
dst = rb_ary_new2(size);
- RARRAY(dst)->len = 0;
for(idx = 2; idx < argc; idx++) {
if (TYPE(argv[idx]) == T_HASH) {
if (RTEST(argv[1])) {
@@ -931,8 +921,7 @@ tk_conv_args(argc, argv, self)
hash2kv(argv[idx], dst, self);
}
} else if (argv[idx] != TK_None) {
- RARRAY(dst)->ptr[RARRAY(dst)->len++]
- = get_eval_string_core(argv[idx], argv[1], self);
+ rb_ary_push(dst, get_eval_string_core(argv[idx], argv[1], self));
}
}
@@ -966,13 +955,13 @@ tcl2rb_bool(self, value)
value = rb_funcall(value, ID_downcase, 0);
- if (RSTRING(value)->ptr == (char*)NULL) return Qnil;
+ if (RSTRING_PTR(value) == (char*)NULL) return Qnil;
- if (RSTRING(value)->ptr[0] == '\0'
- || strcmp(RSTRING(value)->ptr, "0") == 0
- || strcmp(RSTRING(value)->ptr, "no") == 0
- || strcmp(RSTRING(value)->ptr, "off") == 0
- || strcmp(RSTRING(value)->ptr, "false") == 0) {
+ if (RSTRING_PTR(value)[0] == '\0'
+ || strcmp(RSTRING_PTR(value), "0") == 0
+ || strcmp(RSTRING_PTR(value), "no") == 0
+ || strcmp(RSTRING_PTR(value), "off") == 0
+ || strcmp(RSTRING_PTR(value), "false") == 0) {
return Qfalse;
} else {
return Qtrue;
@@ -983,21 +972,21 @@ static VALUE
tkstr_to_dec(value)
VALUE value;
{
- return rb_cstr_to_inum(RSTRING(value)->ptr, 10, 1);
+ return rb_cstr_to_inum(RSTRING_PTR(value), 10, 1);
}
static VALUE
tkstr_to_int(value)
VALUE value;
{
- return rb_cstr_to_inum(RSTRING(value)->ptr, 0, 1);
+ return rb_cstr_to_inum(RSTRING_PTR(value), 0, 1);
}
static VALUE
tkstr_to_float(value)
VALUE value;
{
- return rb_float_new(rb_cstr_to_dbl(RSTRING(value)->ptr, 1));
+ return rb_float_new(rb_cstr_to_dbl(RSTRING_PTR(value), 1));
}
static VALUE
@@ -1005,7 +994,7 @@ tkstr_invalid_numstr(value)
VALUE value;
{
rb_raise(rb_eArgError,
- "invalid value for Number: '%s'", RSTRING(value)->ptr);
+ "invalid value for Number: '%s'", RSTRING_PTR(value));
return Qnil; /*dummy*/
}
@@ -1024,7 +1013,7 @@ tkstr_to_number(value)
{
rb_check_type(value, T_STRING);
- if (RSTRING(value)->ptr == (char*)NULL) return INT2FIX(0);
+ if (RSTRING_PTR(value) == (char*)NULL) return INT2FIX(0);
return rb_rescue2(tkstr_to_int, value,
tkstr_rescue_float, value,
@@ -1046,8 +1035,8 @@ tkstr_to_str(value)
char * ptr;
int len;
- ptr = RSTRING(value)->ptr;
- len = RSTRING(value)->len;
+ ptr = RSTRING_PTR(value);
+ len = RSTRING_LEN(value);
if (len > 1 && *ptr == '{' && *(ptr + len - 1) == '}') {
return rb_str_new(ptr + 1, len - 2);
@@ -1062,7 +1051,7 @@ tcl2rb_string(self, value)
{
rb_check_type(value, T_STRING);
- if (RSTRING(value)->ptr == (char*)NULL) return rb_tainted_str_new2("");
+ if (RSTRING_PTR(value) == (char*)NULL) return rb_tainted_str_new2("");
return tkstr_to_str(value);
}
@@ -1074,7 +1063,7 @@ tcl2rb_num_or_str(self, value)
{
rb_check_type(value, T_STRING);
- if (RSTRING(value)->ptr == (char*)NULL) return rb_tainted_str_new2("");
+ if (RSTRING_PTR(value) == (char*)NULL) return rb_tainted_str_new2("");
return rb_rescue2(tkstr_to_number, value,
tkstr_to_str, value,
@@ -1084,11 +1073,13 @@ tcl2rb_num_or_str(self, value)
/*************************************/
+#define CBSUBST_TBL_MAX (256)
struct cbsubst_info {
- int size;
- char *key;
- char *type;
- ID *ivar;
+ int full_subst_length;
+ int keylen[CBSUBST_TBL_MAX];
+ unsigned char *key[CBSUBST_TBL_MAX];
+ unsigned char type[CBSUBST_TBL_MAX];
+ ID ivar[CBSUBST_TBL_MAX];
VALUE proc;
VALUE aliases;
};
@@ -1105,42 +1096,52 @@ static void
subst_free(ptr)
struct cbsubst_info *ptr;
{
+ int i;
+
if (ptr) {
- if (ptr->key != (char*)NULL) free(ptr->key);
- if (ptr->type != (char*)NULL) free(ptr->type);
- if (ptr->ivar != (ID*)NULL) free(ptr->ivar);
- free(ptr);
+ for(i = 0; i < CBSUBST_TBL_MAX; i++) {
+ if (ptr->key[i] != (unsigned char *)NULL) {
+ free(ptr->key[i]);
+ ptr->key[i] = (unsigned char *)NULL;
+ }
+ }
+ free(ptr);
}
}
-static void
-cbsubst_init()
+static struct cbsubst_info *
+allocate_cbsubst_info()
{
- struct cbsubst_info *inf;
- ID *ivar;
- volatile VALUE proc, aliases;
-
- inf = ALLOC(struct cbsubst_info);
+ struct cbsubst_info *inf;
+ volatile VALUE proc, aliases;
+ int idx;
- inf->size = 0;
+ inf = ALLOC(struct cbsubst_info);
- inf->key = ALLOC_N(char, 1);
- inf->key[0] = '\0';
+ inf->full_subst_length = 0;
- inf->type = ALLOC_N(char, 1);
- inf->type[0] = '\0';
+ for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) {
+ inf->keylen[idx] = 0;
+ inf->key[idx] = (unsigned char *) NULL;
+ inf->type[idx] = '\0';
+ inf->ivar[idx] = (ID) 0;
+ }
- ivar = ALLOC_N(ID, 1);
- inf->ivar = ivar;
+ proc = rb_hash_new();
+ inf->proc = proc;
- proc = rb_hash_new();
- inf->proc = proc;
+ aliases = rb_hash_new();
+ inf->aliases = aliases;
- aliases = rb_hash_new();
- inf->aliases = aliases;
+ return inf;
+}
+static void
+cbsubst_init()
+{
rb_const_set(cCB_SUBST, ID_SUBST_INFO,
- Data_Wrap_Struct(cSUBST_INFO, subst_mark, subst_free, inf));
+ Data_Wrap_Struct(cSUBST_INFO, subst_mark, subst_free,
+ allocate_cbsubst_info()));
}
static VALUE
@@ -1150,24 +1151,29 @@ cbsubst_initialize(argc, argv, self)
VALUE self;
{
struct cbsubst_info *inf;
- int idx;
+ int idx, iv_idx;
Data_Get_Struct(rb_const_get(rb_obj_class(self), ID_SUBST_INFO),
struct cbsubst_info, inf);
- for(idx = 0; idx < argc; idx++) {
- rb_ivar_set(self, inf->ivar[idx], argv[idx]);
+ idx = 0;
+ for(iv_idx = 0; iv_idx < CBSUBST_TBL_MAX; iv_idx++) {
+ if ( inf->ivar[iv_idx] == (ID) 0 ) continue;
+ rb_ivar_set(self, inf->ivar[iv_idx], argv[idx++]);
+ if (idx >= argc) break;
}
return self;
}
-
static VALUE
cbsubst_ret_val(self, val)
VALUE self;
VALUE val;
{
+ /* This method may be overwritten on some sub-classes. */
+ /* This method is used for converting from ruby's callback-return-value */
+ /* to tcl's value (e.g. validation procedure of entry widget). */
return val;
}
@@ -1181,7 +1187,7 @@ each_attr_def(key, value, klass)
switch(TYPE(key)) {
case T_STRING:
- key_id = rb_intern(RSTRING(key)->ptr);
+ key_id = rb_intern(RSTRING_PTR(key));
break;
case T_SYMBOL:
key_id = SYM2ID(key);
@@ -1193,7 +1199,7 @@ each_attr_def(key, value, klass)
switch(TYPE(value)) {
case T_STRING:
- value_id = rb_intern(RSTRING(value)->ptr);
+ value_id = rb_intern(RSTRING_PTR(value));
break;
case T_SYMBOL:
value_id = SYM2ID(value);
@@ -1228,28 +1234,80 @@ cbsubst_def_attr_aliases(self, tbl)
}
static VALUE
+cbsubst_sym_to_subst(self, sym)
+ VALUE self;
+ VALUE sym;
+{
+ struct cbsubst_info *inf;
+ const char *str;
+ unsigned char *buf, *ptr;
+ int idx, len;
+ ID id;
+ volatile VALUE ret;
+
+ if (TYPE(sym) != T_SYMBOL) return sym;
+
+ Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO),
+ struct cbsubst_info, inf);
+
+ if (!NIL_P(ret = rb_hash_aref(inf->aliases, sym))) {
+ str = rb_id2name(SYM2ID(ret));
+ } else {
+ str = rb_id2name(SYM2ID(sym));
+ }
+
+ id = rb_intern(RSTRING_PTR(rb_str_cat2(rb_str_new2("@"), str)));
+
+ for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) {
+ if (inf->ivar[idx] == id) break;
+ }
+ if (idx >= CBSUBST_TBL_MAX) return sym;
+
+ ptr = buf = ALLOC_N(char, inf->full_subst_length + 1);
+
+ *(ptr++) = '%';
+
+ if (len = inf->keylen[idx]) {
+ /* longname */
+ strncpy(ptr, inf->key[idx], len);
+ ptr += len;
+ } else {
+ /* single char */
+ *(ptr++) = idx;
+ }
+
+ *(ptr++) = ' ';
+ *(ptr++) = '\0';
+
+ ret = rb_str_new2(buf);
+
+ free(buf);
+
+ return ret;
+}
+
+static VALUE
cbsubst_get_subst_arg(argc, argv, self)
int argc;
VALUE *argv;
VALUE self;
{
struct cbsubst_info *inf;
- char *str, *buf, *ptr;
- int i, j, len;
+ const char *str;
+ unsigned char *buf, *ptr;
+ int i, idx, len;
ID id;
volatile VALUE arg_sym, ret;
Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO),
struct cbsubst_info, inf);
- buf = ALLOC_N(char, 3*argc + 1);
- ptr = buf;
- len = strlen(inf->key);
+ ptr = buf = ALLOC_N(char, inf->full_subst_length + 1);
for(i = 0; i < argc; i++) {
switch(TYPE(argv[i])) {
case T_STRING:
- str = RSTRING(argv[i])->ptr;
+ str = RSTRING_PTR(argv[i]);
arg_sym = ID2SYM(rb_intern(str));
break;
case T_SYMBOL:
@@ -1264,19 +1322,27 @@ cbsubst_get_subst_arg(argc, argv, self)
str = rb_id2name(SYM2ID(ret));
}
- id = rb_intern(RSTRING(rb_str_cat2(rb_str_new2("@"), str))->ptr);
-
- for(j = 0; j < len; j++) {
- if (inf->ivar[j] == id) break;
- }
+ id = rb_intern(RSTRING_PTR(rb_str_cat2(rb_str_new2("@"), str)));
- if (j >= len) {
+ for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) {
+ if (inf->ivar[idx] == id) break;
+ }
+ if (idx >= CBSUBST_TBL_MAX) {
rb_raise(rb_eArgError, "cannot find attribute :%s", str);
}
- *(ptr++) = '%';
- *(ptr++) = *(inf->key + j);
- *(ptr++) = ' ';
+ *(ptr++) = '%';
+
+ if (len = inf->keylen[idx]) {
+ /* longname */
+ strncpy(ptr, inf->key[idx], len);
+ ptr += len;
+ } else {
+ /* single char */
+ *(ptr++) = idx;
+ }
+
+ *(ptr++) = ' ';
}
*ptr = '\0';
@@ -1293,27 +1359,50 @@ cbsubst_get_subst_key(self, str)
VALUE self;
VALUE str;
{
+ struct cbsubst_info *inf;
volatile VALUE list;
volatile VALUE ret;
- int i, len;
- char *buf, *ptr;
+ VALUE keyval;
+ int i, len, keylen, idx;
+ unsigned char *buf, *ptr, *key;
list = rb_funcall(cTclTkLib, ID_split_tklist, 1, str);
+ len = RARRAY_LEN(list);
+
+ Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO),
+ struct cbsubst_info, inf);
- len = RARRAY(list)->len;
- buf = ALLOC_N(char, len + 1);
+ ptr = buf = ALLOC_N(unsigned char, inf->full_subst_length + len + 1);
for(i = 0; i < len; i++) {
- ptr = RSTRING(RARRAY(list)->ptr[i])->ptr;
- if (*ptr == '%' && *(ptr + 2) == '\0') {
- *(buf + i) = *(ptr + 1);
- } else {
- *(buf + i) = ' ';
- }
+ keyval = RARRAY_PTR(list)[i];
+ key = (unsigned char*)RSTRING_PTR(keyval);
+ if (*key == '%') {
+ if (*(key + 2) == '\0') {
+ /* single char */
+ *(ptr++) = *(key + 1);
+ } else {
+ /* search longname-key */
+ keylen = RSTRING_LEN(keyval) - 1;
+ for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) {
+ if (inf->keylen[idx] != keylen) continue;
+ if (inf->key[idx][0] != *(key + 1)) continue;
+ if (strncmp(inf->key[idx], key + 1, keylen)) continue;
+ break;
+ }
+ if (idx < CBSUBST_TBL_MAX) {
+ *(ptr++) = (unsigned char)idx;
+ } else {
+ *(ptr++) = ' ';
+ }
+ }
+ } else {
+ *(ptr++) = ' ';
+ }
}
- *(buf + len) = '\0';
+ *ptr = '\0';
- ret = rb_str_new2(buf);
+ ret = rb_str_new2((const char*)buf);
free(buf);
return ret;
}
@@ -1323,100 +1412,166 @@ cbsubst_get_all_subst_keys(self)
VALUE self;
{
struct cbsubst_info *inf;
- char *buf, *ptr;
- int i, len;
+ unsigned char *buf, *ptr;
+ unsigned char *keys_buf, *keys_ptr;
+ int idx, len;
volatile VALUE ret;
Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO),
struct cbsubst_info, inf);
- len = strlen(inf->key);
- buf = ALLOC_N(char, 3*len + 1);
- ptr = buf;
- for(i = 0; i < len; i++) {
- *(ptr++) = '%';
- *(ptr++) = *(inf->key + i);
- *(ptr++) = ' ';
+ ptr = buf = ALLOC_N(unsigned char, inf->full_subst_length + 1);
+ keys_ptr = keys_buf = ALLOC_N(unsigned char, CBSUBST_TBL_MAX + 1);
+
+ for(idx = 0; idx < CBSUBST_TBL_MAX; idx++) {
+ if (inf->ivar[idx] == (ID) 0) continue;
+
+ *(keys_ptr++) = (unsigned char)idx;
+
+ *(ptr++) = '%';
+
+ if (len = inf->keylen[idx]) {
+ /* longname */
+ strncpy(ptr, inf->key[idx], len);
+ ptr += len;
+ } else {
+ /* single char */
+ *(ptr++) = (unsigned char)idx;
+ }
+
+ *(ptr++) = ' ';
}
- *(buf + 3*len) = '\0';
- ret = rb_ary_new3(2, rb_str_new2(inf->key), rb_str_new2(buf));
+ *ptr = '\0';
+ *keys_ptr = '\0';
+
+ ret = rb_ary_new3(2, rb_str_new2(keys_buf), rb_str_new2((const char*)buf));
free(buf);
+ free(keys_buf);
return ret;
}
static VALUE
-cbsubst_table_setup(self, key_inf, proc_inf)
- VALUE self;
- VALUE key_inf;
- VALUE proc_inf;
+cbsubst_table_setup(argc, argv, self)
+ int argc;
+ VALUE *argv;
+ VALUE self;
{
- struct cbsubst_info *subst_inf;
- int idx;
- int len = RARRAY(key_inf)->len;
- int real_len = 0;
- char *key = ALLOC_N(char, len + 1);
- char *type = ALLOC_N(char, len + 1);
- ID *ivar = ALLOC_N(ID, len + 1);
- volatile VALUE proc = rb_hash_new();
- volatile VALUE aliases = rb_hash_new();
- volatile VALUE inf;
-
- /* init */
- subst_inf = ALLOC(struct cbsubst_info);
- /* subst_inf->size = len; */
- subst_inf->key = key;
- subst_inf->type = type;
- subst_inf->ivar = ivar;
- subst_inf->proc = proc;
- subst_inf->aliases = aliases;
-
- /*
- * keys : array of [subst, type, ivar]
- * subst ==> char code
- * type ==> char code
- * ivar ==> symbol
- */
- for(idx = 0; idx < len; idx++) {
- inf = RARRAY(key_inf)->ptr[idx];
- if (TYPE(inf) != T_ARRAY) continue;
- *(key + real_len) = (char)NUM2INT(RARRAY(inf)->ptr[0]);
- *(type + real_len) = (char)NUM2INT(RARRAY(inf)->ptr[1]);
-
- *(ivar + real_len)
- = rb_intern(
- RSTRING(
- rb_str_cat2(rb_str_new2("@"),
- rb_id2name(SYM2ID(RARRAY(inf)->ptr[2])))
- )->ptr
- );
-
- rb_attr(self, SYM2ID(RARRAY(inf)->ptr[2]), 1, 0, Qtrue);
- real_len++;
+ volatile VALUE key_inf;
+ volatile VALUE longkey_inf;
+ volatile VALUE proc_inf;
+ VALUE inf;
+ ID id;
+ struct cbsubst_info *subst_inf;
+ int idx, len;
+ unsigned char chr;
+
+ /* accept (key_inf, proc_inf) or (key_inf, longkey_inf, procinf) */
+ if (rb_scan_args(argc, argv, "21", &key_inf, &longkey_inf, &proc_inf) == 2) {
+ proc_inf = longkey_inf;
+ longkey_inf = rb_ary_new();
+ }
+
+ /* check the number of longkeys */
+ if (RARRAY_LEN(longkey_inf) > 125 /* from 0x80 to 0xFD */) {
+ rb_raise(rb_eArgError, "too many longname-key definitions");
+ }
+
+ /* init */
+ subst_inf = allocate_cbsubst_info();
+
+ /*
+ * keys : array of [subst, type, ivar]
+ * subst ==> char code or string
+ * type ==> char code or string
+ * ivar ==> symbol
+ */
+ len = RARRAY_LEN(key_inf);
+ for(idx = 0; idx < len; idx++) {
+ inf = RARRAY_PTR(key_inf)[idx];
+ if (TYPE(inf) != T_ARRAY) continue;
+
+ if (TYPE(RARRAY_PTR(inf)[0]) == T_STRING) {
+ chr = *(RSTRING_PTR(RARRAY_PTR(inf)[0]));
+ } else {
+ chr = NUM2CHR(RARRAY_PTR(inf)[0]);
}
- *(key + real_len) = '\0';
- *(type + real_len) = '\0';
- subst_inf->size = real_len;
-
- /*
- * procs : array of [type, proc]
- * type ==> char code
- * proc ==> proc/method/obj (must respond to 'call')
- */
- len = RARRAY(proc_inf)->len;
- for(idx = 0; idx < len; idx++) {
- inf = RARRAY(proc_inf)->ptr[idx];
- if (TYPE(inf) != T_ARRAY) continue;
- rb_hash_aset(proc, RARRAY(inf)->ptr[0], RARRAY(inf)->ptr[1]);
+ if (TYPE(RARRAY_PTR(inf)[1]) == T_STRING) {
+ subst_inf->type[chr] = *(RSTRING_PTR(RARRAY_PTR(inf)[1]));
+ } else {
+ subst_inf->type[chr] = NUM2CHR(RARRAY_PTR(inf)[1]);
}
- rb_const_set(self, ID_SUBST_INFO,
- Data_Wrap_Struct(cSUBST_INFO, subst_mark,
- subst_free, subst_inf));
+ subst_inf->full_subst_length += 3;
- return self;
+ id = SYM2ID(RARRAY_PTR(inf)[2]);
+ subst_inf->ivar[chr] = rb_intern(RSTRING_PTR(rb_str_cat2(rb_str_new2("@"), rb_id2name(id))));
+
+ rb_attr(self, id, 1, 0, Qtrue);
+ }
+
+
+ /*
+ * longkeys : array of [name, type, ivar]
+ * name ==> longname key string
+ * type ==> char code or string
+ * ivar ==> symbol
+ */
+ len = RARRAY_LEN(longkey_inf);
+ for(idx = 0; idx < len; idx++) {
+ inf = RARRAY_PTR(longkey_inf)[idx];
+ if (TYPE(inf) != T_ARRAY) continue;
+
+ chr = (unsigned char)(0x80 + idx);
+ subst_inf->keylen[chr] = RSTRING_LEN(RARRAY_PTR(inf)[0]);
+#if HAVE_STRNDUP
+ subst_inf->key[chr] = strndup(RSTRING_PTR(RARRAY_PTR(inf)[0]),
+ RSTRING_LEN(RARRAY_PTR(inf)[0]));
+#else
+ subst_inf->key[chr] = malloc(RSTRING_LEN(RARRAY_PTR(inf)[0]) + 1);
+ if (subst_inf->key[chr]) {
+ strncpy(subst_inf->key[chr], RSTRING_PTR(RARRAY_PTR(inf)[0]),
+ RSTRING_LEN(RARRAY_PTR(inf)[0]) + 1);
+ subst_inf->key[chr][RSTRING_LEN(RARRAY_PTR(inf)[0])] = '\0';
+ }
+#endif
+ if (TYPE(RARRAY_PTR(inf)[1]) == T_STRING) {
+ subst_inf->type[chr] = *(RSTRING_PTR(RARRAY_PTR(inf)[1]));
+ } else {
+ subst_inf->type[chr] = NUM2CHR(RARRAY_PTR(inf)[1]);
+ }
+
+ subst_inf->full_subst_length += (subst_inf->keylen[chr] + 2);
+
+ id = SYM2ID(RARRAY_PTR(inf)[2]);
+ subst_inf->ivar[chr] = rb_intern(RSTRING_PTR(rb_str_cat2(rb_str_new2("@"), rb_id2name(id))));
+
+ rb_attr(self, id, 1, 0, Qtrue);
+ }
+
+ /*
+ * procs : array of [type, proc]
+ * type ==> char code or string
+ * proc ==> proc/method/obj (must respond to 'call')
+ */
+ len = RARRAY_LEN(proc_inf);
+ for(idx = 0; idx < len; idx++) {
+ inf = RARRAY_PTR(proc_inf)[idx];
+ if (TYPE(inf) != T_ARRAY) continue;
+ rb_hash_aset(subst_inf->proc,
+ ((TYPE(RARRAY_PTR(inf)[0]) == T_STRING)?
+ INT2FIX(*(RSTRING_PTR(RARRAY_PTR(inf)[0]))) :
+ RARRAY_PTR(inf)[0]),
+ RARRAY_PTR(inf)[1]);
+ }
+
+ rb_const_set(self, ID_SUBST_INFO,
+ Data_Wrap_Struct(cSUBST_INFO, subst_mark,
+ subst_free, subst_inf));
+
+ return self;
}
static VALUE
@@ -1434,10 +1589,11 @@ cbsubst_scan_args(self, arg_key, val_ary)
{
struct cbsubst_info *inf;
int idx;
- int len = RARRAY(val_ary)->len;
- char c;
- char *ptr;
- volatile VALUE dst = rb_ary_new2(len);
+ unsigned char *keyptr = (unsigned char*)RSTRING_PTR(arg_key);
+ int keylen = RSTRING_LEN(arg_key);
+ int vallen = RARRAY_LEN(val_ary);
+ unsigned char type_chr;
+ volatile VALUE dst = rb_ary_new2(vallen);
volatile VALUE proc;
int thr_crit_bup;
VALUE old_gc;
@@ -1450,28 +1606,25 @@ cbsubst_scan_args(self, arg_key, val_ary)
Data_Get_Struct(rb_const_get(self, ID_SUBST_INFO),
struct cbsubst_info, inf);
- RARRAY(dst)->len = 0;
- for(idx = 0; idx < len; idx++) {
- if (idx >= RSTRING(arg_key)->len) {
- proc = Qnil;
- } else if (*(RSTRING(arg_key)->ptr + idx) == ' ') {
- proc = Qnil;
- } else {
- ptr = strchr(inf->key, *(RSTRING(arg_key)->ptr + idx));
- if (ptr == (char*)NULL) {
- proc = Qnil;
- } else {
- c = *(inf->type + (ptr - inf->key));
- proc = rb_hash_aref(inf->proc, INT2FIX(c));
- }
- }
-
- if (NIL_P(proc)) {
- RARRAY(dst)->ptr[RARRAY(dst)->len++] = RARRAY(val_ary)->ptr[idx];
- } else {
- RARRAY(dst)->ptr[RARRAY(dst)->len++]
- = rb_funcall(proc, ID_call, 1, RARRAY(val_ary)->ptr[idx]);
- }
+ for(idx = 0; idx < vallen; idx++) {
+ if (idx >= keylen) {
+ proc = Qnil;
+ } else if (*(keyptr + idx) == ' ') {
+ proc = Qnil;
+ } else {
+ if (type_chr = inf->type[*(keyptr + idx)]) {
+ proc = rb_hash_aref(inf->proc, INT2FIX((int)type_chr));
+ } else {
+ proc = Qnil;
+ }
+ }
+
+ if (NIL_P(proc)) {
+ rb_ary_push(dst, RARRAY_PTR(val_ary)[idx]);
+ } else {
+ rb_ary_push(dst, rb_funcall(proc, ID_call, 1,
+ RARRAY_PTR(val_ary)[idx]));
+ }
}
if (old_gc == Qfalse) rb_gc_enable();
@@ -1512,6 +1665,7 @@ tkobj_path(self)
return rb_ivar_get(self, ID_at_path);
}
+
/*************************************/
/* release date */
const char tkutil_release_date[] = TKUTIL_RELEASE_DATE;
@@ -1554,6 +1708,8 @@ Init_tkutil()
ID_SUBST_INFO = rb_intern("SUBST_INFO");
rb_define_singleton_method(cCB_SUBST, "ret_val", cbsubst_ret_val, 1);
rb_define_singleton_method(cCB_SUBST, "scan_args", cbsubst_scan_args, 2);
+ rb_define_singleton_method(cCB_SUBST, "_sym2subst",
+ cbsubst_sym_to_subst, 1);
rb_define_singleton_method(cCB_SUBST, "subst_arg",
cbsubst_get_subst_arg, -1);
rb_define_singleton_method(cCB_SUBST, "_get_subst_key",
@@ -1561,7 +1717,7 @@ Init_tkutil()
rb_define_singleton_method(cCB_SUBST, "_get_all_subst_keys",
cbsubst_get_all_subst_keys, 0);
rb_define_singleton_method(cCB_SUBST, "_setup_subst_table",
- cbsubst_table_setup, 2);
+ cbsubst_table_setup, -1);
rb_define_singleton_method(cCB_SUBST, "_get_extra_args_tbl",
cbsubst_get_extra_args_tbl, 0);
rb_define_singleton_method(cCB_SUBST, "_define_attribute_aliases",
@@ -1636,4 +1792,8 @@ Init_tkutil()
rb_define_method(mTK, "num_or_str", tcl2rb_num_or_str, 1);
/* --------------------- */
+ rb_global_variable(&ENCODING_NAME_UTF8);
+ ENCODING_NAME_UTF8 = rb_obj_freeze(rb_str_new2("utf-8"));
+
+ /* --------------------- */
}
diff --git a/ext/win32ole/extconf.rb b/ext/win32ole/extconf.rb
index 8cd9581fb0..565964cb81 100644
--- a/ext/win32ole/extconf.rb
+++ b/ext/win32ole/extconf.rb
@@ -1,7 +1,7 @@
#----------------------------------
# extconf.rb
-# $Revision: 1.5.2.2 $
-# $Date: 2005/10/09 02:15:03 $
+# $Revision$
+# $Date$
#----------------------------------
require 'mkmf'
@@ -35,7 +35,5 @@ end
case RUBY_PLATFORM
when /mswin32/
$CFLAGS += ' /W3'
-when /cygwin/, /mingw/
- $defs << '-DNONAMELESSUNION'
end
create_win32ole_makefile
diff --git a/ext/win32ole/sample/olegen.rb b/ext/win32ole/sample/olegen.rb
index ff450f235f..48d86893fe 100644
--- a/ext/win32ole/sample/olegen.rb
+++ b/ext/win32ole/sample/olegen.rb
@@ -1,7 +1,7 @@
#-----------------------------
# olegen.rb
-# $Date: 2002/06/01 12:34:29 $
-# $Revision: 1.1 $
+# $Date$
+# $Revision$
#-----------------------------
require 'win32ole'
diff --git a/ext/win32ole/tests/testOLEEVENT.rb b/ext/win32ole/tests/testOLEEVENT.rb
deleted file mode 100644
index 0901158642..0000000000
--- a/ext/win32ole/tests/testOLEEVENT.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-require 'rubyunit'
-require 'win32ole'
-
-class TestWIN32OLE_EVENT < RUNIT::TestCase
- def setup
- @excel = WIN32OLE.new("Excel.Application")
- @excel.visible = true
- @event = ""
- @event2 = ""
- end
- def test_on_event
- book = @excel.workbooks.Add
- value = ""
- begin
- ev = WIN32OLE_EVENT.new(book, 'WorkbookEvents')
- ev.on_event('SheetChange'){|arg1, arg2|
- begin
- value = arg1.value
- rescue
- value = $!.message
- end
- }
- book.Worksheets(1).Range("A1").value = "OK"
- ensure
- book.saved = true
- end
- assert_equal("OK", value)
- end
-
- def handler1
- @event += "handler1"
- end
- def handler2
- @event += "handler2"
- end
-
- def handler3
- @event += "handler3"
- end
-
- def test_on_event2
- book = @excel.workbooks.Add
- begin
- ev = WIN32OLE_EVENT.new(book, 'WorkbookEvents')
- ev.on_event('SheetChange'){|arg1, arg2|
- handler1
- }
- ev.on_event('SheetChange'){|arg1, arg2|
- handler2
- }
- book.Worksheets(1).Range("A1").value = "OK"
- ensure
- book.saved = true
- end
- assert_equal("handler2", @event)
- end
-
- def test_on_event3
- book = @excel.workbooks.Add
- begin
- ev = WIN32OLE_EVENT.new(book, 'WorkbookEvents')
- ev.on_event{ handler1 }
- ev.on_event{ handler2 }
- book.Worksheets(1).Range("A1").value = "OK"
- ensure
- book.saved = true
- end
- assert_equal("handler2", @event)
- end
-
- def test_on_event4
- book = @excel.workbooks.Add
- begin
- ev = WIN32OLE_EVENT.new(book, 'WorkbookEvents')
- ev.on_event{ handler1 }
- ev.on_event{ handler2 }
- ev.on_event('SheetChange'){|arg1, arg2| handler3 }
- book.Worksheets(1).Range("A1").value = "OK"
- ensure
- book.saved = true
- end
- assert_equal("handler3", @event)
- end
-
- def teardown
- @excel.quit
- @excel = nil
- GC.start
- end
-end
-
diff --git a/ext/win32ole/tests/testWIN32OLE.rb b/ext/win32ole/tests/testWIN32OLE.rb
index 5c01507377..d7f9dd2543 100644
--- a/ext/win32ole/tests/testWIN32OLE.rb
+++ b/ext/win32ole/tests/testWIN32OLE.rb
@@ -156,7 +156,8 @@ class TestWin32OLE < RUNIT::TestCase
sheet.range("A3").value = "=A1*10 + 9"
assert_equal(9999999999, sheet.range("A2").value)
assert_equal(9999999999, sheet.range("A3").value)
-
+ sheet.range("A4").value = "2008/03/04"
+ assert_equal("2008/03/04 00:00:00", sheet.range("A4").value)
ensure
book.saved = true
end
diff --git a/ext/win32ole/tests/test_win32ole_event.rb b/ext/win32ole/tests/test_win32ole_event.rb
new file mode 100644
index 0000000000..744021dfd2
--- /dev/null
+++ b/ext/win32ole/tests/test_win32ole_event.rb
@@ -0,0 +1,133 @@
+begin
+ require 'win32ole'
+rescue LoadError
+end
+require 'test/unit'
+
+if defined?(WIN32OLE_EVENT)
+ class TestWIN32OLE_EVENT < Test::Unit::TestCase
+ def create_temp_html
+ fso = WIN32OLE.new('Scripting.FileSystemObject')
+ dummy_file = fso.GetTempName + ".html"
+ cfolder = fso.getFolder(".")
+ f = cfolder.CreateTextFile(dummy_file)
+ f.writeLine("<html><body>This is test HTML file for Win32OLE.</body></html>")
+ f.close
+ dummy_path = cfolder.path + "\\" + dummy_file
+ dummy_path
+ end
+
+ def setup
+ @ie = WIN32OLE.new("InternetExplorer.Application")
+ @ie.visible = true
+ @event = ""
+ @event2 = ""
+ @event3 = ""
+ @f = create_temp_html
+ end
+
+ def default_handler(event, *args)
+ @event += event
+ end
+
+ def test_on_event
+ ev = WIN32OLE_EVENT.new(@ie, 'DWebBrowserEvents')
+ ev.on_event {|*args| default_handler(*args)}
+ @ie.navigate("file:///#{@f}")
+ while @ie.busy
+ WIN32OLE_EVENT.new(@ie, 'DWebBrowserEvents')
+ GC.start
+ sleep 0.1
+ end
+ assert_match(/BeforeNavigate/, @event)
+ assert_match(/NavigateComplete/, @event)
+ end
+
+ def test_on_event2
+ ev = WIN32OLE_EVENT.new(@ie, 'DWebBrowserEvents')
+ ev.on_event('BeforeNavigate') {|*args| handler1}
+ ev.on_event('BeforeNavigate') {|*args| handler2}
+ @ie.navigate("file:///#{@f}")
+ while @ie.busy
+ sleep 0.1
+ end
+ assert_equal("handler2", @event2)
+ end
+
+ def test_on_event3
+ ev = WIN32OLE_EVENT.new(@ie, 'DWebBrowserEvents')
+ ev.on_event {|*args| handler1}
+ ev.on_event {|*args| handler2}
+ @ie.navigate("file:///#{@f}")
+ while @ie.busy
+ sleep 0.1
+ end
+ assert_equal("handler2", @event2)
+ end
+
+ def test_on_event4
+ ev = WIN32OLE_EVENT.new(@ie, 'DWebBrowserEvents')
+ ev.on_event{|*args| handler1}
+ ev.on_event{|*args| handler2}
+ ev.on_event('NavigateComplete'){|*args| handler3(*args)}
+ @ie.navigate("file:///#{@f}")
+ while @ie.busy
+ sleep 0.1
+ end
+ assert(@event3!="")
+ assert("handler2", @event2)
+ end
+
+ def test_on_event5
+ ev = WIN32OLE_EVENT.new(@ie, 'DWebBrowserEvents')
+ ev.on_event {|*args| default_handler(*args)}
+ ev.on_event('NavigateComplete'){|*args| handler3(*args)}
+ @ie.navigate("file:///#{@f}")
+ while @ie.busy
+ sleep 0.1
+ end
+ assert_match(/BeforeNavigate/, @event)
+ assert(/NavigateComplete/ !~ @event)
+ assert(@event!="")
+ end
+
+ def test_unadvise
+ ev = WIN32OLE_EVENT.new(@ie, 'DWebBrowserEvents')
+ ev.on_event {|*args| default_handler(*args)}
+ @ie.navigate("file:///#{@f}")
+ while @ie.busy
+ sleep 0.1
+ end
+ assert_match(/BeforeNavigate/, @event)
+ ev.unadvise
+ @event = ""
+ @ie.navigate("file:///#{@f}")
+ while @ie.busy
+ sleep 0.1
+ end
+ assert_equal("", @event);
+ assert_raise(WIN32OLERuntimeError) {
+ ev.on_event {|*args| default_handler(*args)}
+ }
+ end
+
+ def handler1
+ @event2 = "handler1"
+ end
+
+ def handler2
+ @event2 = "handler2"
+ end
+
+ def handler3(url)
+ @event3 += url
+ end
+
+ def teardown
+ @ie.quit
+ @ie = nil
+ File.unlink(@f)
+ GC.start
+ end
+ end
+end
diff --git a/ext/win32ole/tests/testall.rb b/ext/win32ole/tests/testall.rb
index d45541f571..553ce88509 100644
--- a/ext/win32ole/tests/testall.rb
+++ b/ext/win32ole/tests/testall.rb
@@ -12,4 +12,5 @@ require "testNIL2VTEMPTY"
require "test_ole_methods.rb"
require "test_propertyputref.rb"
require "test_word.rb"
+require "test_win32ole_event.rb"
# require "testOLEEVENT"
diff --git a/ext/win32ole/win32ole.c b/ext/win32ole/win32ole.c
index b022a8c674..f5d75fedb9 100644
--- a/ext/win32ole/win32ole.c
+++ b/ext/win32ole/win32ole.c
@@ -12,12 +12,25 @@
*/
/*
- $Date: 2007/01/13 22:34:25 $
modified for win32ole (ruby) by Masaki.Suketa <masaki.suketa@nifty.ne.jp>
*/
#include "ruby.h"
#include "st.h"
+
+#define GNUC_OLDER_3_4_4 \
+ ((__GNUC__ < 3) || \
+ ((__GNUC__ <= 3) && (__GNUC_MINOR__ < 4)) || \
+ ((__GNUC__ <= 3) && (__GNUC_MINOR__ <= 4) && (__GNUC_PATCHLEVEL__ <= 4)))
+
+#if (defined(__GNUC__)) && (GNUC_OLDER_3_4_4)
+#ifndef NONAMELESSUNION
+#define NONAMELESSUNION 1
+#endif
+#endif
+
+#include <ctype.h>
+
#include <windows.h>
#include <ocidl.h>
#include <olectl.h>
@@ -29,6 +42,7 @@
#include <varargs.h>
#define va_init_list(a,b) va_start(a)
#endif
+#include <objidl.h>
#define DOUT fprintf(stderr,"[%d]\n",__LINE__)
#define DOUTS(x) fprintf(stderr,"[%d]:" #x "=%s\n",__LINE__,x)
@@ -36,13 +50,13 @@
#define DOUTI(x) fprintf(stderr, "[%ld]:" #x "=%d\n",__LINE__,x)
#define DOUTD(x) fprintf(stderr, "[%d]:" #x "=%f\n",__LINE__,x)
-#if defined NONAMELESSUNION && __GNUC__
+#if (defined(__GNUC__)) && (GNUC_OLDER_3_4_4)
#define V_UNION1(X, Y) ((X)->u.Y)
#else
#define V_UNION1(X, Y) ((X)->Y)
#endif
-#if defined NONAMELESSUNION && __GNUC__
+#if (defined(__GNUC__)) && (GNUC_OLDER_3_4_4)
#undef V_UNION
#define V_UNION(X,Y) ((X)->n1.n2.n3.Y)
@@ -78,7 +92,7 @@
#define WC2VSTR(x) ole_wc2vstr((x), TRUE)
-#define WIN32OLE_VERSION "0.7.2"
+#define WIN32OLE_VERSION "0.7.9"
typedef HRESULT (STDAPICALLTYPE FNCOCREATEINSTANCEEX)
(REFCLSID, IUnknown*, DWORD, COSERVERINFO*, DWORD, MULTI_QI*);
@@ -156,6 +170,9 @@ static VALUE com_hash;
static IDispatchVtbl com_vtbl;
static UINT cWIN32OLE_cp = CP_ACP;
static VARTYPE g_nil_to = VT_ERROR;
+static IMessageFilterVtbl message_filter;
+static IMessageFilter imessage_filter = { &message_filter };
+static IMessageFilter* previous_filter;
struct oledata {
IDispatch *pDispatch;
@@ -202,6 +219,101 @@ static char *ole_wc2mb(LPWSTR);
static VALUE ole_variant2val(VARIANT*);
static void ole_val2variant(VALUE, VARIANT*);
+static HRESULT (STDMETHODCALLTYPE mf_QueryInterface)(
+ IMessageFilter __RPC_FAR * This,
+ /* [in] */ REFIID riid,
+ /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
+{
+ if (MEMCMP(riid, &IID_IUnknown, GUID, 1) == 0
+ || MEMCMP(riid, &IID_IMessageFilter, GUID, 1) == 0)
+ {
+ *ppvObject = &message_filter;
+ return S_OK;
+ }
+ return E_NOINTERFACE;
+}
+
+static ULONG (STDMETHODCALLTYPE mf_AddRef)(
+ IMessageFilter __RPC_FAR * This)
+{
+ return 1;
+}
+
+static ULONG (STDMETHODCALLTYPE mf_Release)(
+ IMessageFilter __RPC_FAR * This)
+{
+ return 1;
+}
+
+static DWORD (STDMETHODCALLTYPE mf_HandleInComingCall)(
+ IMessageFilter __RPC_FAR * pThis,
+ DWORD dwCallType, //Type of incoming call
+ HTASK threadIDCaller, //Task handle calling this task
+ DWORD dwTickCount, //Elapsed tick count
+ LPINTERFACEINFO lpInterfaceInfo //Pointer to INTERFACEINFO structure
+ )
+{
+#ifdef DEBUG_MESSAGEFILTER
+ printf("incoming %08X, %08X, %d\n", dwCallType, threadIDCaller, dwTickCount);
+ fflush(stdout);
+#endif
+ switch (dwCallType)
+ {
+ case CALLTYPE_ASYNC:
+ case CALLTYPE_TOPLEVEL_CALLPENDING:
+ case CALLTYPE_ASYNC_CALLPENDING:
+ if (rb_during_gc()) {
+ return SERVERCALL_RETRYLATER;
+ }
+ break;
+ default:
+ break;
+ }
+ if (previous_filter) {
+ return previous_filter->lpVtbl->HandleInComingCall(previous_filter,
+ dwCallType,
+ threadIDCaller,
+ dwTickCount,
+ lpInterfaceInfo);
+ }
+ return SERVERCALL_ISHANDLED;
+}
+
+static DWORD (STDMETHODCALLTYPE mf_RetryRejectedCall)(
+ IMessageFilter* pThis,
+ HTASK threadIDCallee, //Server task handle
+ DWORD dwTickCount, //Elapsed tick count
+ DWORD dwRejectType //Returned rejection message
+ )
+{
+ if (previous_filter) {
+ return previous_filter->lpVtbl->RetryRejectedCall(previous_filter,
+ threadIDCallee,
+ dwTickCount,
+ dwRejectType);
+ }
+ return 1000;
+}
+
+static DWORD (STDMETHODCALLTYPE mf_MessagePending)(
+ IMessageFilter* pThis,
+ HTASK threadIDCallee, //Called applications task handle
+ DWORD dwTickCount, //Elapsed tick count
+ DWORD dwPendingType //Call type
+ )
+{
+ if (rb_during_gc()) {
+ return PENDINGMSG_WAITNOPROCESS;
+ }
+ if (previous_filter) {
+ return previous_filter->lpVtbl->MessagePending(previous_filter,
+ threadIDCallee,
+ dwTickCount,
+ dwPendingType);
+ }
+ return PENDINGMSG_WAITNOPROCESS;
+}
+
typedef struct _Win32OLEIDispatch
{
IDispatch dispatch;
@@ -458,7 +570,7 @@ date2time_str(date)
double date;
{
int y, m, d, hh, mm, ss;
- char szTime[20];
+ char szTime[40];
double2time(date, &y, &m, &d, &hh, &mm, &ss);
sprintf(szTime,
"%4.4d/%02.2d/%02.2d %02.2d:%02.2d:%02.2d",
@@ -521,6 +633,15 @@ ole_hresult2msg(hr)
return msg;
}
+static void
+ole_freeexceptinfo(pExInfo)
+ EXCEPINFO *pExInfo;
+{
+ SysFreeString(pExInfo->bstrDescription);
+ SysFreeString(pExInfo->bstrSource);
+ SysFreeString(pExInfo->bstrHelpFile);
+}
+
static VALUE
ole_excepinfo2msg(pExInfo)
EXCEPINFO *pExInfo;
@@ -560,9 +681,7 @@ ole_excepinfo2msg(pExInfo)
}
if(pSource) free(pSource);
if(pDescription) free(pDescription);
- SysFreeString(pExInfo->bstrDescription);
- SysFreeString(pExInfo->bstrSource);
- SysFreeString(pExInfo->bstrHelpFile);
+ ole_freeexceptinfo(pExInfo);
return error_msg;
}
@@ -617,6 +736,11 @@ ole_initialize()
/*
atexit((void (*)(void))ole_uninitialize);
*/
+ hr = CoRegisterMessageFilter(&imessage_filter, &previous_filter);
+ if(FAILED(hr)) {
+ previous_filter = NULL;
+ ole_raise(hr, rb_eRuntimeError, "fail: install OLE MessageFilter");
+ }
}
}
@@ -711,6 +835,71 @@ ole_ary_m_entry(val, pid)
return obj;
}
+static VALUE
+is_all_index_under(pid, pub, dim)
+ long *pid;
+ long *pub;
+ long dim;
+{
+ long i = 0;
+ for (i = 0; i < dim; i++) {
+ if (pid[i] > pub[i]) {
+ return Qfalse;
+ }
+ }
+ return Qtrue;
+}
+
+static long
+dimension(val)
+ VALUE val;
+{
+ long dim = 0;
+ long dim1 = 0;
+ long len = 0;
+ long i = 0;
+ if (TYPE(val) == T_ARRAY) {
+ len = RARRAY(val)->len;
+ for (i = 0; i < len; i++) {
+ dim1 = dimension(rb_ary_entry(val, i));
+ if (dim < dim1) {
+ dim = dim1;
+ }
+ }
+ dim += 1;
+ }
+ return dim;
+}
+
+static long
+ary_len_of_dim(ary, dim)
+ VALUE ary;
+ long dim;
+{
+ long ary_len = 0;
+ long ary_len1 = 0;
+ long len = 0;
+ long i = 0;
+ VALUE val;
+ if (dim == 0) {
+ if (TYPE(ary) == T_ARRAY) {
+ ary_len = RARRAY(ary)->len;
+ }
+ } else {
+ if (TYPE(ary) == T_ARRAY) {
+ len = RARRAY(ary)->len;
+ for (i = 0; i < len; i++) {
+ val = rb_ary_entry(ary, i);
+ ary_len1 = ary_len_of_dim(val, dim-1);
+ if (ary_len < ary_len1) {
+ ary_len = ary_len1;
+ }
+ }
+ }
+ }
+ return ary_len;
+}
+
static void
ole_set_safe_array(n, psa, pid, pub, val, dim)
long n;
@@ -721,22 +910,96 @@ ole_set_safe_array(n, psa, pid, pub, val, dim)
long dim;
{
VALUE val1;
+ HRESULT hr = S_OK;
VARIANT var;
- VariantInit(&var);
- if(n < 0) return;
- if(n == dim) {
+ VOID *p = NULL;
+ long i = n;
+ while(i >= 0) {
val1 = ole_ary_m_entry(val, pid);
+ VariantInit(&var);
ole_val2variant(val1, &var);
- SafeArrayPutElement(psa, pid, &var);
+ if (is_all_index_under(pid, pub, dim) == Qtrue) {
+ if ((V_VT(&var) == VT_DISPATCH && V_DISPATCH(&var) == NULL) ||
+ (V_VT(&var) == VT_UNKNOWN && V_UNKNOWN(&var) == NULL)) {
+ rb_raise(eWIN32OLE_RUNTIME_ERROR, "element of array does not have IDispatch or IUnknown Interface");
+ }
+ hr = SafeArrayPutElement(psa, pid, &var);
+ }
+ if (FAILED(hr)) {
+ ole_raise(hr, rb_eRuntimeError, "failed to SafeArrayPutElement");
+ }
+ pid[i] += 1;
+ if (pid[i] > pub[i]) {
+ pid[i] = 0;
+ i -= 1;
+ } else {
+ i = dim - 1;
+ }
+ }
+}
+
+static HRESULT
+ole_val_ary2variant_ary(val, var, vt)
+ VALUE val;
+ VARIANT *var;
+ VARTYPE vt;
+{
+ long dim = 0;
+ int i = 0;
+ HRESULT hr = S_OK;
+
+ SAFEARRAYBOUND *psab = NULL;
+ SAFEARRAY *psa = NULL;
+ long *pub, *pid;
+
+ Check_Type(val, T_ARRAY);
+
+ dim = dimension(val);
+
+ psab = ALLOC_N(SAFEARRAYBOUND, dim);
+ pub = ALLOC_N(long, dim);
+ pid = ALLOC_N(long, dim);
+
+ if(!psab || !pub || !pid) {
+ if(pub) free(pub);
+ if(psab) free(psab);
+ if(pid) free(pid);
+ rb_raise(rb_eRuntimeError, "memory allocation error");
+ }
+
+ for (i = 0; i < dim; i++) {
+ psab[i].cElements = ary_len_of_dim(val, i);
+ psab[i].lLbound = 0;
+ pub[i] = psab[i].cElements - 1;
+ pid[i] = 0;
}
- pid[n] += 1;
- if (pid[n] < pub[n]) {
- ole_set_safe_array(dim, psa, pid, pub, val, dim);
+ /* Create and fill VARIANT array */
+ if ((vt & ~VT_BYREF) == VT_ARRAY) {
+ vt = (vt | VT_VARIANT);
+ }
+ psa = SafeArrayCreate(VT_VARIANT, dim, psab);
+ if (psa == NULL)
+ hr = E_OUTOFMEMORY;
+ else
+ hr = SafeArrayLock(psa);
+ if (SUCCEEDED(hr)) {
+ ole_set_safe_array(dim-1, psa, pid, pub, val, dim);
+ hr = SafeArrayUnlock(psa);
+ }
+
+ if(pub) free(pub);
+ if(psab) free(psab);
+ if(pid) free(pid);
+
+ if (SUCCEEDED(hr)) {
+ V_VT(var) = vt;
+ V_ARRAY(var) = psa;
}
else {
- pid[n] = 0;
- ole_set_safe_array(n-1, psa, pid, pub, val, dim);
+ if (psa != NULL)
+ SafeArrayDestroy(psa);
}
+ return hr;
}
static void
@@ -759,63 +1022,8 @@ ole_val2variant(val, var)
}
switch (TYPE(val)) {
case T_ARRAY:
- {
- VALUE val1;
- long dim = 0;
- int i = 0;
-
- HRESULT hr;
- SAFEARRAYBOUND *psab;
- SAFEARRAY *psa;
- long *pub, *pid;
-
- val1 = val;
- while(TYPE(val1) == T_ARRAY) {
- val1 = rb_ary_entry(val1, 0);
- dim += 1;
- }
- psab = ALLOC_N(SAFEARRAYBOUND, dim);
- pub = ALLOC_N(long, dim);
- pid = ALLOC_N(long, dim);
-
- if(!psab || !pub || !pid) {
- if(pub) free(pub);
- if(psab) free(psab);
- if(pid) free(pid);
- rb_raise(rb_eRuntimeError, "memory allocation error");
- }
- val1 = val;
- i = 0;
- while(TYPE(val1) == T_ARRAY) {
- psab[i].cElements = RARRAY(val1)->len;
- psab[i].lLbound = 0;
- pub[i] = psab[i].cElements;
- pid[i] = 0;
- i ++;
- val1 = rb_ary_entry(val1, 0);
- }
- /* Create and fill VARIANT array */
- psa = SafeArrayCreate(VT_VARIANT, dim, psab);
- if (psa == NULL)
- hr = E_OUTOFMEMORY;
- else
- hr = SafeArrayLock(psa);
- if (SUCCEEDED(hr)) {
- ole_set_safe_array(dim-1, psa, pid, pub, val, dim-1);
- hr = SafeArrayUnlock(psa);
- }
- if(pub) free(pub);
- if(psab) free(psab);
- if(pid) free(pid);
-
- if (SUCCEEDED(hr)) {
- V_VT(var) = VT_VARIANT | VT_ARRAY;
- V_ARRAY(var) = psa;
- }
- else if (psa != NULL)
- SafeArrayDestroy(psa);
+ ole_val_ary2variant_ary(val, var, VT_VARIANT|VT_ARRAY);
break;
- }
case T_STRING:
V_VT(var) = VT_BSTR;
V_BSTR(var) = ole_mb2wc(StringValuePtr(val), -1);
@@ -926,8 +1134,8 @@ ole_variant2val(pvar)
if (!psa) {
return obj;
}
-
dim = SafeArrayGetDim(psa);
+
VariantInit(&variant);
V_VT(&variant) = (V_VT(pvar) & ~VT_ARRAY) | VT_BYREF;
@@ -2102,12 +2310,15 @@ ole_invoke(argc, argv, self, wFlags)
&result, &excepinfo, &argErr);
if (FAILED(hr)) {
/* retry to call args by value */
- if(op.dp.cArgs > cNamedArgs) {
+ if(op.dp.cArgs >= cNamedArgs) {
for(i = cNamedArgs; i < op.dp.cArgs; i++) {
n = op.dp.cArgs - i + cNamedArgs - 1;
param = rb_ary_entry(paramS, i-cNamedArgs);
ole_val2variant(param, &op.dp.rgvarg[n]);
}
+ if (hr == DISP_E_EXCEPTION) {
+ ole_freeexceptinfo(&excepinfo);
+ }
memset(&excepinfo, 0, sizeof(EXCEPINFO));
VariantInit(&result);
hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID,
@@ -2120,6 +2331,9 @@ ole_invoke(argc, argv, self, wFlags)
* hResult == DISP_E_EXCEPTION. this only happens on
* functions whose DISPID > 0x8000 */
if ((hr == DISP_E_EXCEPTION || hr == DISP_E_MEMBERNOTFOUND) && DispID > 0x8000) {
+ if (hr == DISP_E_EXCEPTION) {
+ ole_freeexceptinfo(&excepinfo);
+ }
memset(&excepinfo, 0, sizeof(EXCEPINFO));
hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID,
&IID_NULL, lcid, wFlags,
@@ -2139,6 +2353,9 @@ ole_invoke(argc, argv, self, wFlags)
param = rb_ary_entry(paramS, i-cNamedArgs);
ole_val2variant2(param, &op.dp.rgvarg[n]);
}
+ if (hr == DISP_E_EXCEPTION) {
+ ole_freeexceptinfo(&excepinfo);
+ }
memset(&excepinfo, 0, sizeof(EXCEPINFO));
VariantInit(&result);
hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID,
@@ -3261,6 +3478,54 @@ fole_method_help( self, cmdname )
}
/*
+ * call-seq:
+ * WIN32OLE#ole_activex_initialize() -> Qnil
+ *
+ * Initialize WIN32OLE object(ActiveX Control) by calling
+ * IPersistMemory::InitNew.
+ *
+ * Before calling OLE method, some kind of the ActiveX controls
+ * created with MFC should be initialized by calling
+ * IPersistXXX::InitNew.
+ *
+ * If and only if you recieved the exception "HRESULT error code:
+ * 0x8000ffff catastrophic failure", try this method before
+ * invoking any ole_method.
+ *
+ * obj = WIN32OLE.new("ProgID_or_GUID_of_ActiveX_Control")
+ * obj.ole_activex_initialize
+ * obj.method(...)
+ *
+ */
+static VALUE
+fole_activex_initialize(self)
+ VALUE self;
+{
+ struct oledata *pole;
+ IPersistMemory *pPersistMemory;
+
+ HRESULT hr = S_OK;
+
+ OLEData_Get_Struct(self, pole);
+
+ hr = pole->pDispatch->lpVtbl->QueryInterface(pole->pDispatch, &IID_IPersistMemory,
+ (void **)&pPersistMemory);
+ if (SUCCEEDED(hr)) {
+ hr = pPersistMemory->lpVtbl->InitNew(pPersistMemory);
+ OLE_RELEASE(pPersistMemory);
+ if (SUCCEEDED(hr)) {
+ return Qnil;
+ }
+ }
+
+ if (FAILED(hr)) {
+ ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, "fail to initialize ActiveX control");
+ }
+
+ return Qnil;
+}
+
+/*
* call-seq:
* WIN32OLE_TYPE.ole_classes(typelib)
*
@@ -5862,7 +6127,6 @@ find_default_source(ole, piid, ppTypeInfo)
OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
OLE_RELEASE(pTypeInfo);
-
/* Now that would be a bad surprise, if we didn't find it, wouldn't it? */
if (!*ppTypeInfo) {
if (SUCCEEDED(hr))
@@ -5958,6 +6222,7 @@ fev_initialize(argc, argv, self)
rb_raise(rb_eTypeError, "1st parameter must be WIN32OLE object");
}
+ pTypeInfo = NULL;
if(TYPE(itf) != T_NIL) {
if (ruby_safe_level > 0 && OBJ_TAINTED(itf)) {
rb_raise(rb_eSecurityError, "Insecure Event Creation - %s",
@@ -6118,6 +6383,14 @@ Init_win32ole()
com_vtbl.GetTypeInfo = GetTypeInfo;
com_vtbl.GetIDsOfNames = GetIDsOfNames;
com_vtbl.Invoke = Invoke;
+
+ message_filter.QueryInterface = mf_QueryInterface;
+ message_filter.AddRef = mf_AddRef;
+ message_filter.Release = mf_Release;
+ message_filter.HandleInComingCall = mf_HandleInComingCall;
+ message_filter.RetryRejectedCall = mf_RetryRejectedCall;
+ message_filter.MessagePending = mf_MessagePending;
+
com_hash = Data_Wrap_Struct(rb_cData, rb_mark_hash, st_free_table, st_init_numtable());
cWIN32OLE = rb_define_class("WIN32OLE", rb_cObject);
@@ -6161,6 +6434,7 @@ Init_win32ole()
rb_define_method(cWIN32OLE, "ole_method", fole_method_help, 1);
rb_define_alias(cWIN32OLE, "ole_method_help", "ole_method");
rb_define_method(cWIN32OLE, "ole_obj_help", fole_obj_help, 0);
+ rb_define_method(cWIN32OLE, "ole_activex_initialize", fole_activex_initialize, 0);
rb_define_const(cWIN32OLE, "VERSION", rb_str_new2(WIN32OLE_VERSION));
rb_define_const(cWIN32OLE, "ARGV", rb_ary_new());
diff --git a/ext/zlib/doc/zlib.rd b/ext/zlib/doc/zlib.rd
index f914d883fe..6a36dc7fed 100644
--- a/ext/zlib/doc/zlib.rd
+++ b/ext/zlib/doc/zlib.rd
@@ -4,7 +4,7 @@
#
# Copyright (C) UENO Katsuhiro 2000-2003
#
-# $Id: zlib.rd,v 1.1.2.1 2004/03/28 14:10:39 akr Exp $
+# $Id$
#
= Ruby/zlib version 0.6.0
diff --git a/ext/zlib/extconf.rb b/ext/zlib/extconf.rb
index 14c8376417..53b971b189 100644
--- a/ext/zlib/extconf.rb
+++ b/ext/zlib/extconf.rb
@@ -1,7 +1,7 @@
#
# extconf.rb
#
-# $Id: extconf.rb,v 1.2.2.2 2006/05/25 23:44:07 nobu Exp $
+# $Id$
#
require 'mkmf'
@@ -10,7 +10,7 @@ require 'rbconfig'
dir_config 'zlib'
-if %w'z libz zlib zdll'.find {|z| have_library(z, 'deflateReset')} and
+if %w'z libz zlib1 zlib zdll'.find {|z| have_library(z, 'deflateReset')} and
have_header('zlib.h') then
defines = []
@@ -22,7 +22,7 @@ if %w'z libz zlib zdll'.find {|z| have_library(z, 'deflateReset')} and
os_code = 'AMIGA'
when /\Aos2[\-_]emx\z/ then
os_code = 'OS2'
- when 'mswin32', 'mingw32', 'bccwin32' then
+ when /mswin|mingw|bccwin/ then
# NOTE: cygwin should be regarded as Unix.
os_code = 'WIN32'
else
diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c
index 4684865c65..98141b2f3f 100644
--- a/ext/zlib/zlib.c
+++ b/ext/zlib/zlib.c
@@ -3,7 +3,7 @@
*
* Copyright (C) UENO Katsuhiro 2000-2003
*
- * $Id: zlib.c,v 1.7.2.20 2006/02/14 11:21:54 ocean Exp $
+ * $Id$
*/
#include <ruby.h>
@@ -302,7 +302,7 @@ do_checksum(argc, argv, func)
/*
* call-seq: Zlib.adler32(string, adler)
*
- * Calculates Alder-32 checksum for +string+, and returns updated value of
+ * Calculates Adler-32 checksum for +string+, and returns updated value of
* +adler+. If +string+ is omitted, it returns the Adler-32 initial value. If
* +adler+ is omitted, it assumes that the initial value is given to +adler+.
*
@@ -610,7 +610,8 @@ zstream_append_input(z, src, len)
}
#define zstream_append_input2(z,v)\
- zstream_append_input((z), RSTRING(v)->ptr, RSTRING(v)->len)
+ RB_GC_GUARD(v),\
+ zstream_append_input((z), (Bytef*)RSTRING_PTR(v), RSTRING_LEN(v))
static void
zstream_discard_input(z, len)
@@ -733,6 +734,9 @@ zstream_run(z, src, len, flush)
}
for (;;) {
+ /* VC allocates err and guard to same address. accessing err and guard
+ in same scope prevents it. */
+ RB_GC_GUARD(guard);
n = z->stream.avail_out;
err = z->func->run(&z->stream, flush);
z->buf_filled += n - z->stream.avail_out;
@@ -1182,14 +1186,19 @@ static VALUE
rb_deflate_init_copy(self, orig)
VALUE self, orig;
{
- struct zstream *z1 = get_zstream(self);
- struct zstream *z2 = get_zstream(orig);
+ struct zstream *z1, *z2;
int err;
+ Data_Get_Struct(self, struct zstream, z1);
+ z2 = get_zstream(orig);
+
err = deflateCopy(&z1->stream, &z2->stream);
if (err != Z_OK) {
raise_zlib_error(err, 0);
}
+ z1->input = NIL_P(z2->input) ? Qnil : rb_str_dup(z2->input);
+ z1->buf = NIL_P(z2->buf) ? Qnil : rb_str_dup(z2->buf);
+ z1->buf_filled = z2->buf_filled;
z1->flags = z2->flags;
return self;
@@ -1369,6 +1378,7 @@ rb_deflate_params(obj, v_level, v_strategy)
level = ARG_LEVEL(v_level);
strategy = ARG_STRATEGY(v_strategy);
+ zstream_run(z, (Bytef*)"", 0, Z_SYNC_FLUSH);
err = deflateParams(&z->stream, level, strategy);
while (err == Z_BUF_ERROR) {
rb_warning("deflateParams() returned Z_BUF_ERROR");
@@ -2081,7 +2091,7 @@ gzfile_check_footer(gz)
if (gz->crc != crc) {
rb_raise(cCRCError, "invalid compressed data -- crc error");
}
- if (gz->z.stream.total_out != length) {
+ if ((gz->z.stream.total_out & 0xFFFFFFFFUL) != length) {
rb_raise(cLengthError, "invalid compressed data -- length error");
}
}
@@ -2486,7 +2496,7 @@ rb_gzfile_set_mtime(obj, mtime)
rb_raise(cGzError, "header is already written");
}
- if (FIXNUM_P(time)) {
+ if (FIXNUM_P(mtime)) {
gz->mtime = FIX2INT(mtime);
}
else {
@@ -3111,6 +3121,8 @@ gzreader_gets(argc, argv, obj)
if (NIL_P(rs)) {
dst = gzfile_read_all(gz);
if (RSTRING(dst)->len != 0) gz->lineno++;
+ else
+ return Qnil;
return dst;
}
@@ -3369,7 +3381,7 @@ void Init_zlib()
rb_define_singleton_method(cDeflate, "deflate", rb_deflate_s_deflate, -1);
rb_define_alloc_func(cDeflate, rb_deflate_s_allocate);
rb_define_method(cDeflate, "initialize", rb_deflate_initialize, -1);
- rb_define_method(cDeflate, "initialize_copy", rb_deflate_init_copy, 0);
+ rb_define_method(cDeflate, "initialize_copy", rb_deflate_init_copy, 1);
rb_define_method(cDeflate, "deflate", rb_deflate_deflate, -1);
rb_define_method(cDeflate, "<<", rb_deflate_addstr, 1);
rb_define_method(cDeflate, "flush", rb_deflate_flush, -1);
diff --git a/file.c b/file.c
index f5e9a9b9ed..b59e5608a1 100644
--- a/file.c
+++ b/file.c
@@ -2,8 +2,8 @@
file.c -
- $Author: nobu $
- $Date: 2006/08/19 02:29:18 $
+ $Author$
+ $Date$
created at: Mon Nov 15 12:24:34 JST 1993
Copyright (C) 1993-2003 Yukihiro Matsumoto
@@ -20,13 +20,11 @@
#include <sys/cygwin.h>
#endif
-#define OpenFile rb_io_t
#include "ruby.h"
#include "rubyio.h"
#include "rubysig.h"
#include "util.h"
#include "dln.h"
-#include <ctype.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
@@ -70,6 +68,10 @@ char *strrchr _((const char*,const char));
#include <sys/mkdev.h>
#endif
+#if defined(HAVE_FCNTL_H)
+#include <fcntl.h>
+#endif
+
#if !defined HAVE_LSTAT && !defined lstat
#define lstat stat
#endif
@@ -144,7 +146,7 @@ static VALUE
rb_file_path(obj)
VALUE obj;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
fptr = RFILE(rb_io_taint_check(obj))->fptr;
rb_io_check_initialized(fptr);
@@ -290,7 +292,6 @@ rb_stat_dev_minor(self)
#endif
}
-
/*
* call-seq:
* stat.ino => fixnum
@@ -355,7 +356,6 @@ rb_stat_nlink(self)
return UINT2NUM(get_stat(self)->st_nlink);
}
-
/*
* call-seq:
* stat.uid => fixnum
@@ -390,7 +390,6 @@ rb_stat_gid(self)
return UINT2NUM(get_stat(self)->st_gid);
}
-
/*
* call-seq:
* stat.rdev => fixnum or nil
@@ -520,7 +519,6 @@ rb_stat_blocks(self)
#endif
}
-
/*
* call-seq:
* stat.atime => time
@@ -658,7 +656,7 @@ rb_stat(file, st)
tmp = rb_check_convert_type(file, T_FILE, "IO", "to_io");
if (!NIL_P(tmp)) {
- OpenFile *fptr;
+ rb_io_t *fptr;
rb_secure(2);
GetOpenFile(tmp, fptr);
@@ -679,7 +677,7 @@ w32_io_info(file, st)
tmp = rb_check_convert_type(*file, T_FILE, "IO", "to_io");
if (!NIL_P(tmp)) {
- OpenFile *fptr;
+ rb_io_t *fptr;
GetOpenFile(tmp, fptr);
f = (HANDLE)rb_w32_get_osfhandle(fileno(fptr->f));
@@ -745,7 +743,7 @@ static VALUE
rb_io_stat(obj)
VALUE obj;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
struct stat st;
GetOpenFile(obj, fptr);
@@ -786,7 +784,6 @@ rb_file_s_lstat(klass, fname)
#endif
}
-
/*
* call-seq:
* file.lstat => stat
@@ -806,7 +803,7 @@ rb_file_lstat(obj)
VALUE obj;
{
#ifdef HAVE_LSTAT
- OpenFile *fptr;
+ rb_io_t *fptr;
struct stat st;
rb_secure(2);
@@ -827,7 +824,7 @@ group_member(gid)
GETGROUPS_T gid;
{
#ifndef _WIN32
- if (getgid() == gid)
+ if (getgid() == gid || getegid() == gid)
return Qtrue;
# ifdef HAVE_GETGROUPS
@@ -890,15 +887,15 @@ eaccess(path, mode)
if (st.st_uid == euid) /* owner */
mode <<= 6;
- else if (getegid() == st.st_gid || group_member(st.st_gid))
+ else if (group_member(st.st_gid))
mode <<= 3;
if ((st.st_mode & mode) == mode) return 0;
return -1;
#else
-# if _MSC_VER >= 1400
- mode &= 6;
+# if defined(_MSC_VER) || defined(__MINGW32__)
+ mode &= ~1;
# endif
return access(path, mode);
#endif
@@ -916,7 +913,6 @@ eaccess(path, mode)
*
*/
-
/*
* call-seq:
* File.directory?(file_name) => true or false
@@ -1105,7 +1101,6 @@ test_c(obj, fname)
return Qfalse;
}
-
/*
* call-seq:
* File.exist?(file_name) => true or false
@@ -1158,7 +1153,6 @@ test_R(obj, fname)
return Qtrue;
}
-
/*
* call-seq:
* File.writable?(file_name) => true or false
@@ -1271,10 +1265,10 @@ test_z(obj, fname)
/*
* call-seq:
- * File.file?(file_name) => integer or nil
+ * File.size?(file_name) => Integer or nil
*
- * Returns <code>nil</code> if <code>file_name</code> doesn't
- * exist or has zero size, the size of the file otherwise.
+ * Returns +nil+ if +file_name+ doesn't exist or has zero size, the size of the
+ * file otherwise.
*/
static VALUE
@@ -1336,7 +1330,7 @@ test_grpowned(obj, fname)
struct stat st;
if (rb_stat(fname, &st) < 0) return Qfalse;
- if (st.st_gid == getegid()) return Qtrue;
+ if (group_member(st.st_gid)) return Qtrue;
#endif
return Qfalse;
}
@@ -1497,7 +1491,7 @@ static VALUE
rb_file_ftype(st)
struct stat *st;
{
- char *t;
+ const char *t;
if (S_ISREG(st->st_mode)) {
t = "file";
@@ -1600,7 +1594,7 @@ static VALUE
rb_file_atime(obj)
VALUE obj;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
struct stat st;
GetOpenFile(obj, fptr);
@@ -1645,7 +1639,7 @@ static VALUE
rb_file_mtime(obj)
VALUE obj;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
struct stat st;
GetOpenFile(obj, fptr);
@@ -1693,7 +1687,7 @@ static VALUE
rb_file_ctime(obj)
VALUE obj;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
struct stat st;
GetOpenFile(obj, fptr);
@@ -1761,7 +1755,7 @@ static VALUE
rb_file_chmod(obj, vmode)
VALUE obj, vmode;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
int mode;
rb_secure(2);
@@ -1787,7 +1781,7 @@ lchmod_internal(path, mode)
const char *path;
void *mode;
{
- if (lchmod(path, (int)mode) < 0)
+ if (lchmod(path, (int)(VALUE)mode) < 0)
rb_sys_fail(path);
}
@@ -1905,7 +1899,7 @@ static VALUE
rb_file_chown(obj, owner, group)
VALUE obj, owner, group;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
int o, g;
rb_secure(2);
@@ -1936,7 +1930,6 @@ lchown_internal(path, argp)
rb_sys_fail(path);
}
-
/*
* call-seq:
* file.lchown(owner_int, group_int, file_name,..) => integer
@@ -2016,13 +2009,17 @@ rb_file_s_utime(argc, argv)
VALUE *argv;
{
VALUE atime, mtime, rest;
- struct timeval tvp[2];
+ struct timeval tvs[2], *tvp = NULL;
long n;
+ rb_secure(2);
rb_scan_args(argc, argv, "2*", &atime, &mtime, &rest);
- tvp[0] = rb_time_timeval(atime);
- tvp[1] = rb_time_timeval(mtime);
+ if (!NIL_P(atime) || !NIL_P(mtime)) {
+ tvp = tvs;
+ tvp[0] = rb_time_timeval(atime);
+ tvp[1] = rb_time_timeval(mtime);
+ }
n = apply2files(utime_internal, rest, tvp);
return LONG2FIX(n);
@@ -2055,16 +2052,19 @@ rb_file_s_utime(argc, argv)
VALUE atime, mtime, rest;
long n;
struct timeval tv;
- struct utimbuf utbuf;
+ struct utimbuf utbuf, *utp = NULL;
rb_scan_args(argc, argv, "2*", &atime, &mtime, &rest);
- tv = rb_time_timeval(atime);
- utbuf.actime = tv.tv_sec;
- tv = rb_time_timeval(mtime);
- utbuf.modtime = tv.tv_sec;
+ if (!NIL_P(atime) || !NIL_P(mtime)) {
+ utp = &utbuf;
+ tv = rb_time_timeval(atime);
+ utp->actime = tv.tv_sec;
+ tv = rb_time_timeval(mtime);
+ utp->modtime = tv.tv_sec;
+ }
- n = apply2files(utime_internal, rest, &utbuf);
+ n = apply2files(utime_internal, rest, utp);
return LONG2FIX(n);
}
@@ -2309,26 +2309,30 @@ rb_file_s_umask(argc, argv)
#define isdirsep(x) ((x) == '/')
#endif
-#ifndef CharNext /* defined as CharNext[AW] on Windows. */
-# if defined(DJGPP)
-# define CharNext(p) ((p) + mblen(p, MB_CUR_MAX))
-# else
-# define CharNext(p) ((p) + 1)
-# endif
-#endif
-
#if defined _WIN32 || defined __CYGWIN__
#define USE_NTFS 1
#else
#define USE_NTFS 0
#endif
+#ifdef DOSISH_DRIVE_LETTER
+#include <ctype.h>
+#endif
+
#if USE_NTFS
#define istrailinggabage(x) ((x) == '.' || (x) == ' ')
#else
#define istrailinggabage(x) 0
#endif
+#ifndef CharNext /* defined as CharNext[AW] on Windows. */
+# if defined(DJGPP)
+# define CharNext(p) ((p) + mblen(p, MB_CUR_MAX))
+# else
+# define CharNext(p) ((p) + 1)
+# endif
+#endif
+
#ifdef DOSISH_DRIVE_LETTER
static inline int
has_drive_letter(buf)
@@ -2440,9 +2444,8 @@ rb_path_last_separator(path)
return last;
}
-#define chompdirsep rb_path_end
-char *
-rb_path_end(path)
+static char *
+chompdirsep(path)
const char *path;
{
while (*path) {
@@ -2458,10 +2461,19 @@ rb_path_end(path)
return (char *)path;
}
+char *
+rb_path_end(path)
+ const char *path;
+{
+ if (isdirsep(*path)) path++;
+ return chompdirsep(path);
+}
+
#if USE_NTFS
static char *
ntfs_tail(const char *path)
{
+ while (*path == '.') path++;
while (*path && *path != ':') {
if (istrailinggabage(*path)) {
const char *last = path++;
@@ -2484,13 +2496,13 @@ ntfs_tail(const char *path)
#define BUFCHECK(cond) do {\
long bdiff = p - buf;\
- while (cond) {\
- buflen *= 2;\
+ if (cond) {\
+ do {buflen *= 2;} while (cond);\
+ rb_str_resize(result, buflen);\
+ buf = RSTRING_PTR(result);\
+ p = buf + bdiff;\
+ pend = buf + buflen;\
}\
- rb_str_resize(result, buflen);\
- buf = RSTRING(result)->ptr;\
- p = buf + bdiff;\
- pend = buf + buflen;\
} while (0)
#define BUFINIT() (\
@@ -2518,8 +2530,9 @@ file_expand_path(fname, dname, result)
tainted = OBJ_TAINTED(fname);
if (s[0] == '~') {
+ long userlen = 0;
if (isdirsep(s[1]) || s[1] == '\0') {
- char *dir = getenv("HOME");
+ const char *dir = getenv("HOME");
if (!dir) {
rb_raise(rb_eArgError, "couldn't find HOME environment -- expanding `%s'", s);
@@ -2545,9 +2558,10 @@ file_expand_path(fname, dname, result)
s++;
#endif
s = nextdirsep(b = s);
- BUFCHECK(bdiff + (s-b) >= buflen);
- memcpy(p, b, s-b);
- p += s-b;
+ userlen = s - b;
+ BUFCHECK(bdiff + userlen >= buflen);
+ memcpy(p, b, userlen);
+ p += userlen;
*p = '\0';
#ifdef HAVE_PWD_H
pwPtr = getpwnam(buf);
@@ -2560,8 +2574,18 @@ file_expand_path(fname, dname, result)
strcpy(buf, pwPtr->pw_dir);
p = buf + strlen(pwPtr->pw_dir);
endpwent();
+#else
+ rb_raise(rb_eArgError, "can't find user %s", buf);
#endif
}
+ if (!is_absolute_path(RSTRING_PTR(result))) {
+ if (userlen) {
+ rb_raise(rb_eArgError, "non-absolute home of %.*s", userlen, s);
+ }
+ else {
+ rb_raise(rb_eArgError, "non-absolute home");
+ }
+ }
}
#ifdef DOSISH_DRIVE_LETTER
/* skip drive letter */
@@ -2726,65 +2750,62 @@ file_expand_path(fname, dname, result)
p += s-b;
}
if (p == skiproot(buf) - 1) p++;
- buflen = p - buf;
- RSTRING(result)->len = buflen;
- *p = '\0';
#if USE_NTFS
- if (1 &&
-#ifdef __CYGWIN__
- !(buf[0] == '/' && !buf[1]) &&
-#endif
- !strpbrk(b = buf, "*?")) {
+ *p = '\0';
+ if ((s = strrdirsep(b = buf)) != 0 && !strpbrk(s, "*?")) {
size_t len;
WIN32_FIND_DATA wfd;
#ifdef __CYGWIN__
int lnk_added = 0, is_symlink = 0;
struct stat st;
- char w32buf[MAXPATHLEN], sep = 0;
- p = 0;
+ char w32buf[MAXPATHLEN];
+ p = (char *)s;
if (lstat(buf, &st) == 0 && S_ISLNK(st.st_mode)) {
is_symlink = 1;
- p = strrdirsep(buf);
- if (!p) p = skipprefix(buf);
- if (p) {
- sep = *p;
- *p = '\0';
- }
+ *p = '\0';
}
- if (cygwin_conv_to_win32_path(buf, w32buf) == 0) {
+ if (cygwin_conv_to_win32_path((*buf ? buf : "/"), w32buf) == 0) {
b = w32buf;
}
- if (p) *p = sep;
- else p = buf;
if (is_symlink && b == w32buf) {
+ *p = '\\';
+ strlcat(w32buf, p, sizeof(w32buf));
len = strlen(p);
if (len > 4 && strcasecmp(p + len - 4, ".lnk") != 0) {
lnk_added = 1;
strlcat(w32buf, ".lnk", sizeof(w32buf));
}
}
+ *p = '/';
#endif
HANDLE h = FindFirstFile(b, &wfd);
if (h != INVALID_HANDLE_VALUE) {
FindClose(h);
- p = strrdirsep(buf);
len = strlen(wfd.cFileName);
#ifdef __CYGWIN__
if (lnk_added && len > 4 &&
strcasecmp(wfd.cFileName + len - 4, ".lnk") == 0) {
- len -= 4;
+ wfd.cFileName[len -= 4] = '\0';
}
+#else
+ p = (char *)s;
#endif
- if (!p) p = buf;
- buflen = ++p - buf + len;
- rb_str_resize(result, buflen);
+ ++p;
+ BUFCHECK(bdiff + len >= buflen);
memcpy(p, wfd.cFileName, len + 1);
+ p += len;
}
+#ifdef __CYGWIN__
+ else {
+ p += strlen(p);
+ }
+#endif
}
#endif
if (tainted) OBJ_TAINT(result);
+ rb_str_set_len(result, p - buf);
return result;
}
@@ -2847,7 +2868,12 @@ rmext(p, l1, e)
}
if (l1 < l2) return l1;
- if (strncmp(p+l1-l2, e, l2) == 0) {
+#if CASEFOLD_FILESYSTEM
+#define fncomp strncasecmp
+#else
+#define fncomp strncmp
+#endif
+ if (fncomp(p+l1-l2, e, l2) == 0) {
return l1-l2;
}
return 0;
@@ -2867,24 +2893,17 @@ rmext(p, l1, e)
* File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby"
*/
-static VALUE
-rb_file_s_basename(argc, argv)
- int argc;
- VALUE *argv;
+const char *
+ruby_find_basename(name, baselen, alllen)
+ const char *name;
+ long *baselen, *alllen;
{
- VALUE fname, fext, basename;
- char *name, *p;
+ const char *p, *q, *e;
#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
- char *root;
+ const char *root;
#endif
- int f, n;
+ long f = 0, n = -1;
- if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) {
- StringValue(fext);
- }
- StringValue(fname);
- if (RSTRING(fname)->len == 0 || !*(name = RSTRING(fname)->ptr))
- return fname;
name = skipprefix(name);
#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
root = name;
@@ -2923,11 +2942,59 @@ rb_file_s_basename(argc, argv)
#else
n = chompdirsep(p) - p;
#endif
+ for (q = p; q - p < n && *q == '.'; q++);
+ for (e = 0; q - p < n; q = CharNext(q)) {
+ if (*q == '.') e = q;
+ }
+ if (e) f = e - p;
+ else f = n;
+ }
+
+ if (baselen)
+ *baselen = f;
+ if (alllen)
+ *alllen = n;
+ return p;
+}
+
+/*
+ * call-seq:
+ * File.basename(file_name [, suffix] ) -> base_name
+ *
+ * Returns the last component of the filename given in <i>file_name</i>,
+ * which must be formed using forward slashes (``<code>/</code>'')
+ * regardless of the separator used on the local file system. If
+ * <i>suffix</i> is given and present at the end of <i>file_name</i>,
+ * it is removed.
+ *
+ * File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb"
+ * File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby"
+ */
+
+static VALUE
+rb_file_s_basename(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ VALUE fname, fext, basename;
+ const char *name, *p;
+ long f, n;
+
+ if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) {
+ StringValue(fext);
+ }
+ StringValue(fname);
+ if (RSTRING_LEN(fname) == 0 || !*(name = RSTRING_PTR(fname)))
+ return fname;
+
+ p = ruby_find_basename(name, &f, &n);
+ if (n >= 0) {
if (NIL_P(fext) || !(f = rmext(p, n, StringValueCStr(fext)))) {
f = n;
}
- if (f == RSTRING(fname)->len) return fname;
+ if (f == RSTRING_LEN(fname)) return fname;
}
+
basename = rb_str_new(p, f);
OBJ_INFECT(basename, fname);
return basename;
@@ -2949,7 +3016,7 @@ static VALUE
rb_file_s_dirname(klass, fname)
VALUE klass, fname;
{
- char *name, *root, *p;
+ const char *name, *root, *p;
VALUE dirname;
name = StringValueCStr(fname);
@@ -2969,8 +3036,9 @@ rb_file_s_dirname(klass, fname)
return rb_str_new2(".");
#ifdef DOSISH_DRIVE_LETTER
if (has_drive_letter(name) && isdirsep(*(name + 2))) {
+ const char *top = skiproot(name + 2);
dirname = rb_str_new(name, 3);
- rb_str_cat(dirname, skiproot(name + 2), p - skiproot(name + 2));
+ rb_str_cat(dirname, top, p - top);
}
else
#endif
@@ -2984,32 +3052,29 @@ rb_file_s_dirname(klass, fname)
}
/*
- * call-seq:
- * File.extname(path) -> string
- *
- * Returns the extension (the portion of file name in <i>path</i>
- * after the period).
- *
- * File.extname("test.rb") #=> ".rb"
- * File.extname("a/b/d/test.rb") #=> ".rb"
- * File.extname("test") #=> ""
- * File.extname(".profile") #=> ""
- *
+ * accept a String, and return the pointer of the extension.
+ * if len is passed, set the length of extension to it.
+ * returned pointer is in ``name'' or NULL.
+ * returns *len
+ * no dot NULL 0
+ * dotfile top 0
+ * end with dot dot 1
+ * .ext dot len of .ext
+ * .ext:stream dot len of .ext without :stream (NT only)
+ *
*/
-
-static VALUE
-rb_file_s_extname(klass, fname)
- VALUE klass, fname;
+const char *
+ruby_find_extname(name, len)
+ const char *name;
+ long *len;
{
- const char *name, *p, *e;
- VALUE extname;
+ const char *p, *e;
- name = StringValueCStr(fname);
p = strrdirsep(name); /* get the last path component */
if (!p)
p = name;
else
- name = ++p;
+ do name = ++p; while (isdirsep(*p));
e = 0;
while (*p) {
@@ -3024,7 +3089,7 @@ rb_file_s_extname(klass, fname)
p = last;
break;
}
- e = dot;
+ if (*last == '.' || dot > last) e = dot;
continue;
#else
e = p; /* get the last dot of the last component */
@@ -3039,9 +3104,46 @@ rb_file_s_extname(klass, fname)
break;
p = CharNext(p);
}
- if (!e || e == name || e+1 == p) /* no dot, or the only dot is first or end? */
+
+ if (len) {
+ /* no dot, or the only dot is first or end? */
+ if (!e || e == name)
+ *len = 0;
+ else if (e+1 == p)
+ *len = 1;
+ else
+ *len = p - e;
+ }
+ return e;
+}
+
+/*
+ * call-seq:
+ * File.extname(path) -> string
+ *
+ * Returns the extension (the portion of file name in <i>path</i>
+ * after the period).
+ *
+ * File.extname("test.rb") #=> ".rb"
+ * File.extname("a/b/d/test.rb") #=> ".rb"
+ * File.extname("test") #=> ""
+ * File.extname(".profile") #=> ""
+ *
+ */
+
+static VALUE
+rb_file_s_extname(klass, fname)
+ VALUE klass, fname;
+{
+ const char *name, *e;
+ long len;
+ VALUE extname;
+
+ name = StringValueCStr(fname);
+ e = ruby_find_extname(name, &len);
+ if (len <= 1)
return rb_str_new(0, 0);
- extname = rb_str_new(e, p - e); /* keep the dot, too! */
+ extname = rb_str_new(e, len); /* keep the dot, too! */
OBJ_INFECT(extname, fname);
return extname;
}
@@ -3084,7 +3186,7 @@ rb_file_join(ary, sep)
long len, i;
int taint = 0;
VALUE result, tmp;
- char *name, *tail;
+ const char *name, *tail;
if (RARRAY(ary)->len == 0) return rb_str_new(0, 0);
if (OBJ_TAINTED(ary)) taint = 1;
@@ -3109,8 +3211,8 @@ rb_file_join(ary, sep)
case T_STRING:
break;
case T_ARRAY:
- if (rb_inspecting_p(tmp)) {
- tmp = rb_str_new2("[...]");
+ if (tmp == ary || rb_inspecting_p(tmp)) {
+ rb_raise(rb_eArgError, "recursive array");
}
else {
VALUE args[2];
@@ -3232,7 +3334,7 @@ static VALUE
rb_file_truncate(obj, len)
VALUE obj, len;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
FILE *f;
off_t pos;
@@ -3245,7 +3347,7 @@ rb_file_truncate(obj, len)
f = GetWriteFile(fptr);
fflush(f);
fseeko(f, (off_t)0, SEEK_CUR);
-#ifdef HAVE_TRUNCATE
+#ifdef HAVE_FTRUNCATE
if (ftruncate(fileno(f), pos) < 0)
rb_sys_fail(fptr->path);
#else
@@ -3293,7 +3395,7 @@ cygwin_flock(int fd, int op)
static int
rb_thread_flock(fd, op, fptr)
int fd, op;
- OpenFile *fptr;
+ rb_io_t *fptr;
{
if (rb_thread_alone() || (op & LOCK_NB)) {
int ret;
@@ -3359,7 +3461,7 @@ rb_file_flock(obj, operation)
VALUE operation;
{
#ifndef __CHECKER__
- OpenFile *fptr;
+ rb_io_t *fptr;
int op;
rb_secure(2);
@@ -3610,7 +3712,6 @@ rb_f_test(argc, argv)
}
-
/*
* Document-class: File::Stat
*
@@ -3889,7 +3990,7 @@ rb_stat_grpowned(obj)
VALUE obj;
{
#ifndef _WIN32
- if (get_stat(obj)->st_gid == getegid()) return Qtrue;
+ if (group_member(get_stat(obj)->st_gid)) return Qtrue;
#endif
return Qfalse;
}
@@ -3928,8 +4029,6 @@ rb_stat_r(obj)
return Qtrue;
}
-
-
/*
* call-seq:
* stat.readable_real? -> true or false
@@ -4078,7 +4177,6 @@ rb_stat_x(obj)
* the process.
*/
-
static VALUE
rb_stat_X(obj)
VALUE obj;
@@ -4142,7 +4240,6 @@ rb_stat_z(obj)
return Qfalse;
}
-
/*
* call-seq:
* state.size => integer
@@ -4254,14 +4351,22 @@ is_absolute_path(path)
return 0;
}
-#ifndef DOSISH
+#ifndef ENABLE_PATH_CHECK
+# if defined DOSISH || defined __CYGWIN__
+# define ENABLE_PATH_CHECK 0
+# else
+# define ENABLE_PATH_CHECK 1
+# endif
+#endif
+
+#if ENABLE_PATH_CHECK
static int
-path_check_0(fpath, loadpath)
+path_check_0(fpath, execpath)
VALUE fpath;
- int loadpath;
+ int execpath;
{
struct stat st;
- char *p0 = StringValueCStr(fpath);
+ const char *p0 = StringValueCStr(fpath);
char *p = 0, *s;
if (!is_absolute_path(p0)) {
@@ -4273,7 +4378,7 @@ path_check_0(fpath, loadpath)
rb_str_cat2(newpath, "/");
rb_str_cat2(newpath, p0);
- return path_check_0(newpath, loadpath);
+ p0 = RSTRING(fpath = newpath)->ptr;
}
for (;;) {
#ifndef S_IWOTH
@@ -4281,10 +4386,11 @@ path_check_0(fpath, loadpath)
#endif
if (stat(p0, &st) == 0 && S_ISDIR(st.st_mode) && (st.st_mode & S_IWOTH)
#ifdef S_ISVTX
- && (loadpath || !(st.st_mode & S_ISVTX))
+ && !(p && execpath && (st.st_mode & S_ISVTX))
#endif
) {
- rb_warn("Insecure world writable dir %s, mode 0%o", p0, st.st_mode);
+ rb_warn("Insecure world writable dir %s in %sPATH, mode 0%o",
+ p0, (execpath ? "" : "LOAD_"), st.st_mode);
if (p) *p = '/';
return 0;
}
@@ -4299,9 +4405,9 @@ path_check_0(fpath, loadpath)
static int
fpath_check(path)
- char *path;
+ const char *path;
{
-#ifndef DOSISH
+#if ENABLE_PATH_CHECK
return path_check_0(rb_str_new2(path), Qfalse);
#else
return 1;
@@ -4310,10 +4416,10 @@ fpath_check(path)
int
rb_path_check(path)
- char *path;
+ const char *path;
{
-#ifndef DOSISH
- char *p0, *p, *pend;
+#if ENABLE_PATH_CHECK
+ const char *p0, *p, *pend;
const char sep = PATH_SEP_CHAR;
if (!path) return 1;
@@ -4348,15 +4454,21 @@ is_macos_native_path(path)
static int
file_load_ok(file)
- char *file;
+ const char *file;
{
- FILE *f;
-
- if (!file) return 0;
- f = fopen(file, "r");
- if (f == NULL) return 0;
- fclose(f);
- return 1;
+ int ret = 1;
+ int fd = open(file, O_RDONLY);
+ if (fd == -1) return 0;
+#if !defined DOSISH
+ {
+ struct stat st;
+ if (fstat(fd, &st) || !S_ISREG(st.st_mode)) {
+ ret = 0;
+ }
+ }
+#endif
+ (void)close(fd);
+ return ret;
}
extern VALUE rb_load_path;
@@ -4366,8 +4478,8 @@ rb_find_file_ext(filep, ext)
VALUE *filep;
const char * const *ext;
{
- char *path, *found;
- char *f = RSTRING(*filep)->ptr;
+ const char *path, *found;
+ const char *f = RSTRING(*filep)->ptr;
VALUE fname;
long i, j;
@@ -4422,8 +4534,8 @@ rb_find_file(path)
VALUE path;
{
VALUE tmp;
- char *f = StringValueCStr(path);
- char *lpath;
+ const char *f = StringValueCStr(path);
+ const char *lpath;
if (f[0] == '~') {
path = rb_file_expand_path(path, Qnil);
@@ -4472,9 +4584,6 @@ rb_find_file(path)
}
else {
lpath = RSTRING(tmp)->ptr;
- if (rb_safe_level() >= 1 && !rb_path_check(lpath)) {
- rb_raise(rb_eSecurityError, "loading from unsafe path %s", lpath);
- }
}
}
else {
@@ -4484,7 +4593,9 @@ rb_find_file(path)
if (!lpath) {
return 0; /* no path, no load */
}
- f = dln_find_file(f, lpath);
+ if (!(f = dln_find_file(f, lpath))) {
+ return 0;
+ }
if (rb_safe_level() >= 1 && !fpath_check(f)) {
rb_raise(rb_eSecurityError, "loading from unsafe file %s", f);
}
diff --git a/gc.c b/gc.c
index 2e171bd9d7..fa45cd1e2d 100644
--- a/gc.c
+++ b/gc.c
@@ -2,8 +2,8 @@
gc.c -
- $Author: matz $
- $Date: 2006/08/25 08:12:46 $
+ $Author$
+ $Date$
created at: Tue Oct 5 09:44:46 JST 1993
Copyright (C) 1993-2003 Yukihiro Matsumoto
@@ -30,29 +30,17 @@
#include <sys/resource.h>
#endif
-#ifdef __ia64__
-#include <ucontext.h>
-#if defined(__FreeBSD__)
-/*
- * FreeBSD/ia64 currently does not have a way for a process to get the
- * base address for the RSE backing store, so hardcode it.
- */
-#define __libc_ia64_register_backing_store_base (4ULL<<61)
-#else
-#pragma weak __libc_ia64_register_backing_store_base
-extern unsigned long __libc_ia64_register_backing_store_base;
-#endif
-#endif
-
#if defined _WIN32 || defined __CYGWIN__
#include <windows.h>
#endif
void re_free_registers _((struct re_registers*));
-void rb_io_fptr_finalize _((struct OpenFile*));
+void rb_io_fptr_finalize _((struct rb_io_t*));
-#if !defined(setjmp) && defined(HAVE__SETJMP)
-#define setjmp(env) _setjmp(env)
+#define rb_setjmp(env) RUBY_SETJMP(env)
+#define rb_jmp_buf rb_jmpbuf_t
+#ifdef __CYGWIN__
+int _setjmp(), _longjmp();
#endif
/* Make alloca work the best possible way. */
@@ -88,19 +76,62 @@ static void run_final();
static VALUE nomem_error;
static void garbage_collect();
+int ruby_gc_stress = 0;
+
+NORETURN(void rb_exc_jump _((VALUE)));
+
void
rb_memerror()
{
- static int recurse = 0;
+ rb_thread_t th = rb_curr_thread;
- if (!nomem_error || (recurse > 0 && rb_safe_level() < 4)) {
+ if (!nomem_error ||
+ (rb_thread_raised_p(th, RAISED_NOMEMORY) && rb_safe_level() < 4)) {
fprintf(stderr, "[FATAL] failed to allocate memory\n");
exit(1);
}
- recurse++;
+ if (rb_thread_raised_p(th, RAISED_NOMEMORY)) {
+ rb_exc_jump(nomem_error);
+ }
+ rb_thread_raised_set(th, RAISED_NOMEMORY);
rb_exc_raise(nomem_error);
}
+/*
+ * call-seq:
+ * GC.stress => true or false
+ *
+ * returns current status of GC stress mode.
+ */
+
+static VALUE
+gc_stress_get(self)
+ VALUE self;
+{
+ return ruby_gc_stress ? Qtrue : Qfalse;
+}
+
+/*
+ * call-seq:
+ * GC.stress = bool => bool
+ *
+ * updates GC stress mode.
+ *
+ * When GC.stress = true, GC is invoked for all GC opportunity:
+ * all memory and object allocation.
+ *
+ * Since it makes Ruby very slow, it is only for debugging.
+ */
+
+static VALUE
+gc_stress_set(self, bool)
+ VALUE self, bool;
+{
+ rb_secure(2);
+ ruby_gc_stress = RTEST(bool);
+ return bool;
+}
+
void *
ruby_xmalloc(size)
long size;
@@ -111,9 +142,8 @@ ruby_xmalloc(size)
rb_raise(rb_eNoMemError, "negative allocation size (or too big)");
}
if (size == 0) size = 1;
- malloc_increase += size;
- if (malloc_increase > malloc_limit) {
+ if (ruby_gc_stress || (malloc_increase+size) > malloc_limit) {
garbage_collect();
}
RUBY_CRITICAL(mem = malloc(size));
@@ -124,6 +154,7 @@ ruby_xmalloc(size)
rb_memerror();
}
}
+ malloc_increase += size;
return mem;
}
@@ -152,7 +183,7 @@ ruby_xrealloc(ptr, size)
}
if (!ptr) return xmalloc(size);
if (size == 0) size = 1;
- malloc_increase += size;
+ if (ruby_gc_stress) garbage_collect();
RUBY_CRITICAL(mem = realloc(ptr, size));
if (!mem) {
garbage_collect();
@@ -161,6 +192,7 @@ ruby_xrealloc(ptr, size)
rb_memerror();
}
}
+ malloc_increase += size;
return mem;
}
@@ -387,12 +419,21 @@ add_heap()
}
#define RANY(o) ((RVALUE*)(o))
+int
+rb_during_gc()
+{
+ return during_gc;
+}
+
VALUE
rb_newobj()
{
VALUE obj;
- if (!freelist) garbage_collect();
+ if (during_gc)
+ rb_bug("object allocation during garbage collection phase");
+
+ if (ruby_gc_stress || !freelist) garbage_collect();
obj = (VALUE)freelist;
freelist = freelist->as.free.next;
@@ -423,6 +464,9 @@ rb_data_object_alloc(klass, datap, dmark, dfree)
extern st_table *rb_class_tbl;
VALUE *rb_gc_stack_start = 0;
+#ifdef __ia64
+VALUE *rb_gc_register_stack_start = 0;
+#endif
#ifdef DJGPP
/* set stack size (http://www.delorie.com/djgpp/v2faq/faq15_9.html) */
@@ -435,8 +479,8 @@ static unsigned int STACK_LEVEL_MAX = 65535;
unsigned int _stacksize = 262144;
# define STACK_LEVEL_MAX (_stacksize - 4096)
# undef HAVE_GETRLIMIT
-#elif defined(HAVE_GETRLIMIT)
-static unsigned int STACK_LEVEL_MAX = 655300;
+#elif defined(HAVE_GETRLIMIT) || defined(_WIN32)
+static size_t STACK_LEVEL_MAX = 655300;
#else
# define STACK_LEVEL_MAX 655300
#endif
@@ -445,24 +489,23 @@ static unsigned int STACK_LEVEL_MAX = 655300;
# define SET_STACK_END VALUE stack_end; alloca(0);
# define STACK_END (&stack_end)
#else
-# if defined(__GNUC__) && defined(USE_BUILTIN_FRAME_ADDRESS) && !defined(__ia64__)
+# if defined(__GNUC__) && defined(USE_BUILTIN_FRAME_ADDRESS) && !defined(__ia64)
# if ( __GNUC__ == 3 && __GNUC_MINOR__ > 0 ) || __GNUC__ > 3
__attribute__ ((noinline))
# endif
-static VALUE *
-stack_end_address(void)
+static void
+stack_end_address(VALUE **stack_end_p)
{
- return (VALUE *)__builtin_frame_address(0);
+ VALUE stack_end;
+ *stack_end_p = &stack_end;
}
-# define SET_STACK_END VALUE *stack_end = stack_end_address()
+# define SET_STACK_END VALUE *stack_end; stack_end_address(&stack_end)
# else
# define SET_STACK_END VALUE *stack_end = alloca(1)
# endif
# define STACK_END (stack_end)
#endif
-#if defined(sparc) || defined(__sparc__)
-# define STACK_LENGTH (rb_gc_stack_start - STACK_END + 0x80)
-#elif STACK_GROW_DIRECTION < 0
+#if STACK_GROW_DIRECTION < 0
# define STACK_LENGTH (rb_gc_stack_start - STACK_END)
#elif STACK_GROW_DIRECTION > 0
# define STACK_LENGTH (STACK_END - rb_gc_stack_start + 1)
@@ -496,7 +539,7 @@ stack_grow_direction(addr)
(ret) = (STACK_LENGTH > STACK_LEVEL_MAX + GC_WATER_MARK);\
} while (0)
-int
+size_t
ruby_stack_length(p)
VALUE **p;
{
@@ -527,24 +570,25 @@ init_mark_stack()
}
#define MARK_STACK_EMPTY (mark_stack_ptr == mark_stack)
-
+
static st_table *source_filenames;
char *
rb_source_filename(f)
const char *f;
{
- char *name;
+ st_data_t name;
- if (!st_lookup(source_filenames, (st_data_t)f, (st_data_t *)&name)) {
+ if (!st_lookup(source_filenames, (st_data_t)f, &name)) {
long len = strlen(f) + 1;
- char *ptr = name = ALLOC_N(char, len + 1);
+ char *ptr = ALLOC_N(char, len + 1);
+ name = (st_data_t)ptr;
*ptr++ = 0;
MEMCPY(ptr, f, char, len);
- st_add_direct(source_filenames, (st_data_t)ptr, (st_data_t)name);
+ st_add_direct(source_filenames, (st_data_t)ptr, name);
return ptr;
}
- return name + 1;
+ return (char *)name + 1;
}
static void
@@ -680,6 +724,31 @@ rb_mark_tbl(tbl)
}
static int
+mark_key(key, value, lev)
+ VALUE key, value;
+ int lev;
+{
+ gc_mark(key, lev);
+ return ST_CONTINUE;
+}
+
+static void
+mark_set(tbl, lev)
+ st_table *tbl;
+ int lev;
+{
+ if (!tbl) return;
+ st_foreach(tbl, mark_key, lev);
+}
+
+void
+rb_mark_set(tbl)
+ st_table *tbl;
+{
+ mark_set(tbl, 0);
+}
+
+static int
mark_keyvalue(key, value, lev)
VALUE key;
VALUE value;
@@ -734,7 +803,7 @@ gc_mark(ptr, lev)
if (!mark_stack_overflow) {
if (mark_stack_ptr - mark_stack < MARK_STACK_MAX) {
*mark_stack_ptr = ptr;
- mark_stack_ptr++;
+ mark_stack_ptr++;
}
else {
mark_stack_overflow = 1;
@@ -1008,7 +1077,16 @@ gc_mark_children(ptr, lev)
}
}
-static void obj_free _((VALUE));
+static int obj_free _((VALUE));
+
+static inline void
+add_freelist(p)
+ RVALUE *p;
+{
+ p->as.free.flags = 0;
+ p->as.free.next = freelist;
+ freelist = p;
+}
static void
finalize_list(p)
@@ -1018,9 +1096,7 @@ finalize_list(p)
RVALUE *tmp = p->as.free.next;
run_final((VALUE)p);
if (!FL_TEST(p, FL_SINGLETON)) { /* not freeing page */
- p->as.free.flags = 0;
- p->as.free.next = freelist;
- freelist = p;
+ add_freelist(p);
}
p = tmp;
}
@@ -1045,6 +1121,8 @@ free_unused_heaps()
}
}
+#define T_DEFERRED 0x3a
+
void rb_gc_abort_threads(void);
static void
@@ -1088,26 +1166,28 @@ gc_sweep()
int n = 0;
RVALUE *free = freelist;
RVALUE *final = final_list;
+ int deferred;
p = heaps[i].slot; pend = p + heaps[i].limit;
while (p < pend) {
if (!(p->as.basic.flags & FL_MARK)) {
- if (p->as.basic.flags) {
- obj_free((VALUE)p);
- }
- if (need_call_final && FL_TEST(p, FL_FINALIZE)) {
- p->as.free.flags = FL_MARK; /* remain marked */
+ if (p->as.basic.flags &&
+ ((deferred = obj_free((VALUE)p)) ||
+ ((FL_TEST(p, FL_FINALIZE)) && need_call_final))) {
+ if (!deferred) {
+ p->as.free.flags = T_DEFERRED;
+ RDATA(p)->dfree = 0;
+ }
+ p->as.free.flags |= FL_MARK;
p->as.free.next = final_list;
final_list = p;
}
else {
- p->as.free.flags = 0;
- p->as.free.next = freelist;
- freelist = p;
+ add_freelist(p);
}
n++;
}
- else if (RBASIC(p)->flags == FL_MARK) {
+ else if (BUILTIN_TYPE(p) == T_DEFERRED) {
/* objects to be finalized */
/* do nothing remain marked */
}
@@ -1143,6 +1223,15 @@ gc_sweep()
/* clear finalization list */
if (final_list) {
deferred_final_list = final_list;
+ if (!freelist && !rb_thread_critical) {
+ rb_gc_finalize_deferred();
+ }
+ else {
+ rb_thread_pending = 1;
+ }
+ if (!freelist) {
+ add_heap();
+ }
return;
}
free_unused_heaps();
@@ -1152,16 +1241,21 @@ void
rb_gc_force_recycle(p)
VALUE p;
{
- RANY(p)->as.free.flags = 0;
- RANY(p)->as.free.next = freelist;
- freelist = RANY(p);
+ add_freelist(RANY(p));
}
-static void
+static inline void
+make_deferred(p)
+ RVALUE *p;
+{
+ p->as.basic.flags = (p->as.basic.flags & ~T_MASK) | T_DEFERRED;
+}
+
+static int
obj_free(obj)
VALUE obj;
{
- switch (RANY(obj)->as.basic.flags & T_MASK) {
+ switch (BUILTIN_TYPE(obj)) {
case T_NIL:
case T_FIXNUM:
case T_TRUE:
@@ -1174,7 +1268,7 @@ obj_free(obj)
rb_free_generic_ivar((VALUE)obj);
}
- switch (RANY(obj)->as.basic.flags & T_MASK) {
+ switch (BUILTIN_TYPE(obj)) {
case T_OBJECT:
if (RANY(obj)->as.object.iv_tbl) {
st_free_table(RANY(obj)->as.object.iv_tbl);
@@ -1217,7 +1311,8 @@ obj_free(obj)
RUBY_CRITICAL(free(DATA_PTR(obj)));
}
else if (RANY(obj)->as.data.dfree) {
- (*RANY(obj)->as.data.dfree)(DATA_PTR(obj));
+ make_deferred(RANY(obj));
+ return 1;
}
}
break;
@@ -1229,8 +1324,11 @@ obj_free(obj)
break;
case T_FILE:
if (RANY(obj)->as.file.fptr) {
- rb_io_fptr_finalize(RANY(obj)->as.file.fptr);
- RUBY_CRITICAL(free(RANY(obj)->as.file.fptr));
+ struct rb_io_t *fptr = RANY(obj)->as.file.fptr;
+ make_deferred(RANY(obj));
+ RDATA(obj)->dfree = (void (*)(void*))rb_io_fptr_finalize;
+ RDATA(obj)->data = fptr;
+ return 1;
}
break;
case T_ICLASS:
@@ -1258,15 +1356,15 @@ obj_free(obj)
RUBY_CRITICAL(free(RANY(obj)->as.node.u1.node));
break;
}
- return; /* no need to free iv_tbl */
+ break; /* no need to free iv_tbl */
case T_SCOPE:
if (RANY(obj)->as.scope.local_vars &&
RANY(obj)->as.scope.flags != SCOPE_ALLOCA) {
VALUE *vars = RANY(obj)->as.scope.local_vars-1;
- if (!(RANY(obj)->as.scope.flags & SCOPE_CLONE) && vars[0] == 0)
+ if (!(RANY(obj)->as.scope.flags & SCOPE_CLONE) && vars[0] == 0)
RUBY_CRITICAL(free(RANY(obj)->as.scope.local_tbl));
- if (RANY(obj)->as.scope.flags & SCOPE_MALLOC)
+ if ((RANY(obj)->as.scope.flags & (SCOPE_MALLOC|SCOPE_CLONE)) == SCOPE_MALLOC)
RUBY_CRITICAL(free(vars));
}
break;
@@ -1281,6 +1379,8 @@ obj_free(obj)
rb_bug("gc_sweep(): unknown data type 0x%lx(0x%lx)",
RANY(obj)->as.basic.flags & T_MASK, obj);
}
+
+ return 0;
}
void
@@ -1292,6 +1392,8 @@ rb_gc_mark_frame(frame)
#ifdef __GNUC__
#if defined(__human68k__) || defined(DJGPP)
+#undef rb_setjmp
+#undef rb_jmp_buf
#if defined(__human68k__)
typedef unsigned long rb_jmp_buf[8];
__asm__ (".even\n\
@@ -1300,9 +1402,6 @@ _rb_setjmp:\n\
movem.l d3-d7/a3-a5,(a0)\n\
moveq.l #0,d0\n\
rts");
-#ifdef setjmp
-#undef setjmp
-#endif
#else
#if defined(DJGPP)
typedef unsigned long rb_jmp_buf[6];
@@ -1323,8 +1422,6 @@ _rb_setjmp:\n\
#endif
#endif
int rb_setjmp (rb_jmp_buf);
-#define jmp_buf rb_jmp_buf
-#define setjmp rb_setjmp
#endif /* __human68k__ or DJGPP */
#endif /* __GNUC__ */
@@ -1373,7 +1470,7 @@ garbage_collect()
FLUSH_REGISTER_WINDOWS;
/* This assumes that all registers are saved into the jmp_buf (and stack) */
- setjmp(save_regs_gc_mark);
+ rb_setjmp(save_regs_gc_mark);
mark_locations_array((VALUE*)save_regs_gc_mark, sizeof(save_regs_gc_mark) / sizeof(VALUE *));
#if STACK_GROW_DIRECTION < 0
rb_gc_mark_locations((VALUE*)STACK_END, rb_gc_stack_start);
@@ -1385,23 +1482,10 @@ garbage_collect()
else
rb_gc_mark_locations(rb_gc_stack_start, (VALUE*)STACK_END + 1);
#endif
-#ifdef __ia64__
+#ifdef __ia64
/* mark backing store (flushed register window on the stack) */
/* the basic idea from guile GC code */
- {
- ucontext_t ctx;
- VALUE *top, *bot;
- getcontext(&ctx);
- mark_locations_array((VALUE*)&ctx.uc_mcontext,
- ((size_t)(sizeof(VALUE)-1 + sizeof ctx.uc_mcontext)/sizeof(VALUE)));
- bot = (VALUE*)__libc_ia64_register_backing_store_base;
-#if defined(__FreeBSD__)
- top = (VALUE*)ctx.uc_mcontext.mc_special.bspstore;
-#else
- top = (VALUE*)ctx.uc_mcontext.sc_ar_bsp;
-#endif
- rb_gc_mark_locations(bot, top);
- }
+ rb_gc_mark_locations(rb_gc_register_stack_start, (VALUE*)rb_ia64_bsp());
#endif
#if defined(__human68k__) || defined(__mc68000__)
rb_gc_mark_locations((VALUE*)((char*)STACK_END + 2),
@@ -1477,6 +1561,28 @@ void
Init_stack(addr)
VALUE *addr;
{
+#ifdef __ia64
+ if (rb_gc_register_stack_start == 0) {
+# if defined(__FreeBSD__)
+ /*
+ * FreeBSD/ia64 currently does not have a way for a process to get the
+ * base address for the RSE backing store, so hardcode it.
+ */
+ rb_gc_register_stack_start = (4ULL<<61);
+# elif defined(HAVE___LIBC_IA64_REGISTER_BACKING_STORE_BASE)
+# pragma weak __libc_ia64_register_backing_store_base
+ extern unsigned long __libc_ia64_register_backing_store_base;
+ rb_gc_register_stack_start = (VALUE*)__libc_ia64_register_backing_store_base;
+# endif
+ }
+ {
+ VALUE *bsp = (VALUE*)rb_ia64_bsp();
+ if (rb_gc_register_stack_start == 0 ||
+ bsp < rb_gc_register_stack_start) {
+ rb_gc_register_stack_start = bsp;
+ }
+ }
+#endif
#if defined(_WIN32) || defined(__CYGWIN__)
MEMORY_BASIC_INFORMATION m;
memset(&m, 0, sizeof(m));
@@ -1485,10 +1591,12 @@ Init_stack(addr)
STACK_UPPER((VALUE *)&m, (VALUE *)m.BaseAddress,
(VALUE *)((char *)m.BaseAddress + m.RegionSize) - 1);
#elif defined(STACK_END_ADDRESS)
- extern void *STACK_END_ADDRESS;
- rb_gc_stack_start = STACK_END_ADDRESS;
+ {
+ extern void *STACK_END_ADDRESS;
+ rb_gc_stack_start = STACK_END_ADDRESS;
+ }
#else
- if (!addr) addr = (VALUE *)&addr;
+ if (!addr) addr = (void *)&addr;
STACK_UPPER(&addr, addr, ++addr);
if (rb_gc_stack_start) {
if (STACK_UPPER(&addr,
@@ -1513,6 +1621,50 @@ Init_stack(addr)
#endif
}
+void ruby_init_stack(VALUE *addr
+#ifdef __ia64
+ , void *bsp
+#endif
+ )
+{
+ if (!rb_gc_stack_start ||
+ STACK_UPPER(&addr,
+ rb_gc_stack_start > addr,
+ rb_gc_stack_start < addr)) {
+ rb_gc_stack_start = addr;
+ }
+#ifdef __ia64
+ if (!rb_gc_register_stack_start ||
+ (VALUE*)bsp < rb_gc_register_stack_start) {
+ rb_gc_register_stack_start = (VALUE*)bsp;
+ }
+#endif
+#ifdef HAVE_GETRLIMIT
+ {
+ struct rlimit rlim;
+
+ if (getrlimit(RLIMIT_STACK, &rlim) == 0) {
+ unsigned int space = rlim.rlim_cur/5;
+
+ if (space > 1024*1024) space = 1024*1024;
+ STACK_LEVEL_MAX = (rlim.rlim_cur - space) / sizeof(VALUE);
+ }
+ }
+#elif defined _WIN32
+ {
+ MEMORY_BASIC_INFORMATION mi;
+ DWORD size;
+ DWORD space;
+
+ if (VirtualQuery(&mi, &mi, sizeof(mi))) {
+ size = (char *)mi.BaseAddress - (char *)mi.AllocationBase;
+ space = size / 5;
+ if (space > 1024*1024) space = 1024*1024;
+ STACK_LEVEL_MAX = (size - space) / sizeof(VALUE);
+ }
+ }
+#endif
+}
/*
* Document-class: ObjectSpace
@@ -1560,6 +1712,7 @@ os_obj_of(of)
{
int i;
int n = 0;
+ volatile VALUE v;
for (i = 0; i < heaps_used; i++) {
RVALUE *p, *pend;
@@ -1567,19 +1720,21 @@ os_obj_of(of)
p = heaps[i].slot; pend = p + heaps[i].limit;
for (;p < pend; p++) {
if (p->as.basic.flags) {
- switch (TYPE(p)) {
+ switch (BUILTIN_TYPE(p)) {
case T_NONE:
case T_ICLASS:
case T_VARMAP:
case T_SCOPE:
case T_NODE:
+ case T_DEFERRED:
continue;
case T_CLASS:
if (FL_TEST(p, FL_SINGLETON)) continue;
default:
if (!p->as.basic.klass) continue;
- if (!of || rb_obj_is_kind_of((VALUE)p, of)) {
- rb_yield((VALUE)p);
+ v = (VALUE)p;
+ if (!of || rb_obj_is_kind_of(v, of)) {
+ rb_yield(v);
n++;
}
}
@@ -1624,16 +1779,21 @@ os_obj_of(of)
*/
static VALUE
-os_each_obj(argc, argv)
+os_each_obj(argc, argv, os)
int argc;
VALUE *argv;
+ VALUE os;
{
VALUE of;
rb_secure(4);
- if (rb_scan_args(argc, argv, "01", &of) == 0) {
+ if (argc == 0) {
of = 0;
}
+ else {
+ rb_scan_args(argc, argv, "01", &of);
+ }
+ RETURN_ENUMERATOR(os, 1, &of);
return os_obj_of(of);
}
@@ -1735,9 +1895,14 @@ define_final(argc, argv, os)
rb_obj_classname(block));
}
need_call_final = 1;
- FL_SET(obj, FL_FINALIZE);
+ if (!FL_ABLE(obj)) {
+ rb_raise(rb_eArgError, "cannot define finalizer for %s",
+ rb_obj_classname(obj));
+ }
+ RBASIC(obj)->flags |= FL_FINALIZE;
block = rb_ary_new3(2, INT2FIX(ruby_safe_level), block);
+ OBJ_FREEZE(block);
if (!finalizer_table) {
finalizer_table = st_init_numtable();
@@ -1746,7 +1911,9 @@ define_final(argc, argv, os)
rb_ary_push(table, block);
}
else {
- st_add_direct(finalizer_table, obj, rb_ary_new3(1, block));
+ table = rb_ary_new3(1, block);
+ RBASIC(table)->klass = 0;
+ st_add_direct(finalizer_table, obj, table);
}
return block;
}
@@ -1782,7 +1949,11 @@ run_final(obj)
VALUE args[3], table, objid;
objid = rb_obj_id(obj); /* make obj into id */
+ RBASIC(obj)->klass = 0;
rb_thread_critical = Qtrue;
+ if (BUILTIN_TYPE(obj) == T_DEFERRED && RDATA(obj)->dfree) {
+ (*RDATA(obj)->dfree)(DATA_PTR(obj));
+ }
args[1] = 0;
args[2] = (VALUE)ruby_safe_level;
for (i=0; i<RARRAY(finalizers)->len; i++) {
@@ -1821,7 +1992,7 @@ rb_gc_call_finalizer_at_exit()
int i;
/* run finalizers */
- if (need_call_final) {
+ if (need_call_final && finalizer_table) {
p = deferred_final_list;
deferred_final_list = 0;
finalize_list(p);
@@ -1830,19 +2001,23 @@ rb_gc_call_finalizer_at_exit()
while (p < pend) {
if (FL_TEST(p, FL_FINALIZE)) {
FL_UNSET(p, FL_FINALIZE);
- p->as.basic.klass = 0;
run_final((VALUE)p);
}
p++;
}
}
+ if (finalizer_table) {
+ st_free_table(finalizer_table);
+ finalizer_table = 0;
+ }
}
/* run data object's finalizers */
for (i = 0; i < heaps_used; i++) {
p = heaps[i].slot; pend = p + heaps[i].limit;
while (p < pend) {
if (BUILTIN_TYPE(p) == T_DATA &&
- DATA_PTR(p) && RANY(p)->as.data.dfree) {
+ DATA_PTR(p) && RANY(p)->as.data.dfree &&
+ RANY(p)->as.basic.klass != rb_cThread) {
p->as.free.flags = 0;
if ((long)RANY(p)->as.data.dfree == -1) {
RUBY_CRITICAL(free(DATA_PTR(p)));
@@ -1896,7 +2071,7 @@ id2ref(obj, objid)
}
if (!is_pointer_to_heap((void *)ptr)||
- (type = BUILTIN_TYPE(ptr)) >= T_BLKTAG || type == T_ICLASS) {
+ (type = BUILTIN_TYPE(ptr)) > T_SYMBOL || type == T_ICLASS) {
rb_raise(rb_eRangeError, "0x%lx is not id value", p0);
}
if (BUILTIN_TYPE(ptr) == 0 || RBASIC(ptr)->klass == 0) {
@@ -1912,7 +2087,7 @@ id2ref(obj, objid)
* call-seq:
* obj.__id__ => fixnum
* obj.object_id => fixnum
- *
+ *
* Returns an integer identifier for <i>obj</i>. The same number will
* be returned on all calls to <code>id</code> for a given object, and
* no two active objects will share an id.
@@ -1924,7 +2099,7 @@ id2ref(obj, objid)
/*
* call-seq:
* obj.hash => fixnum
- *
+ *
* Generates a <code>Fixnum</code> hash value for this object. This
* function must have the property that <code>a.eql?(b)</code> implies
* <code>a.hash == b.hash</code>. The hash value is used by class
@@ -1987,6 +2162,8 @@ Init_GC()
rb_define_singleton_method(rb_mGC, "start", rb_gc_start, 0);
rb_define_singleton_method(rb_mGC, "enable", rb_gc_enable, 0);
rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0);
+ rb_define_singleton_method(rb_mGC, "stress", gc_stress_get, 0);
+ rb_define_singleton_method(rb_mGC, "stress=", gc_stress_set, 1);
rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0);
rb_mObSpace = rb_define_module("ObjectSpace");
@@ -2010,7 +2187,10 @@ Init_GC()
source_filenames = st_init_strtable();
rb_global_variable(&nomem_error);
- nomem_error = rb_exc_new2(rb_eNoMemError, "failed to allocate memory");
+ nomem_error = rb_exc_new3(rb_eNoMemError,
+ rb_obj_freeze(rb_str_new2("failed to allocate memory")));
+ OBJ_TAINT(nomem_error);
+ OBJ_FREEZE(nomem_error);
rb_define_method(rb_mKernel, "hash", rb_obj_id, 0);
rb_define_method(rb_mKernel, "__id__", rb_obj_id, 0);
diff --git a/hash.c b/hash.c
index e3f6dc2050..8086e22ef7 100644
--- a/hash.c
+++ b/hash.c
@@ -2,8 +2,8 @@
hash.c -
- $Author: shyouhei $
- $Date: 2006/12/05 18:53:00 $
+ $Author$
+ $Date$
created at: Mon Nov 22 18:51:18 JST 1993
Copyright (C) 1993-2003 Yukihiro Matsumoto
@@ -81,7 +81,19 @@ VALUE
rb_hash(obj)
VALUE obj;
{
- return rb_funcall(obj, id_hash, 0);
+ VALUE hval = rb_funcall(obj, id_hash, 0);
+ retry:
+ switch (TYPE(hval)) {
+ case T_FIXNUM:
+ return hval;
+
+ case T_BIGNUM:
+ return LONG2FIX(((long*)(RBIGNUM_DIGITS(hval)))[0]);
+
+ default:
+ hval = rb_to_int(hval);
+ goto retry;
+ }
}
static int
@@ -89,24 +101,24 @@ rb_any_hash(a)
VALUE a;
{
VALUE hval;
+ int hnum;
switch (TYPE(a)) {
case T_FIXNUM:
case T_SYMBOL:
- return (int)a;
+ hnum = (int)a;
break;
case T_STRING:
- return rb_str_hash(a);
+ hnum = rb_str_hash(a);
break;
default:
- hval = rb_funcall(a, id_hash, 0);
- if (!FIXNUM_P(hval)) {
- hval = rb_funcall(hval, '%', 1, INT2FIX(536870923));
- }
- return (int)FIX2LONG(hval);
+ hval = rb_hash(a);
+ hnum = (int)FIX2LONG(hval);
}
+ hnum <<= 1;
+ return RSHIFT(hnum, 1);
}
static struct st_hash_type objhash = {
@@ -114,9 +126,11 @@ static struct st_hash_type objhash = {
rb_any_hash,
};
+typedef int st_foreach_func(st_data_t, st_data_t, st_data_t);
+
struct foreach_safe_arg {
st_table *tbl;
- int (*func)();
+ st_foreach_func *func;
st_data_t arg;
};
@@ -144,16 +158,18 @@ st_foreach_safe(table, func, a)
struct foreach_safe_arg arg;
arg.tbl = table;
- arg.func = func;
+ arg.func = (st_foreach_func *)func;
arg.arg = a;
if (st_foreach(table, foreach_safe_i, (st_data_t)&arg)) {
rb_raise(rb_eRuntimeError, "hash modified during iteration");
}
}
+typedef int rb_foreach_func(VALUE, VALUE, VALUE);
+
struct hash_foreach_arg {
VALUE hash;
- int (*func)();
+ rb_foreach_func *func;
VALUE arg;
};
@@ -165,7 +181,7 @@ hash_foreach_iter(key, value, arg)
int status;
st_table *tbl;
- tbl = RHASH(arg->hash)->tbl;
+ tbl = RHASH(arg->hash)->tbl;
if (key == Qundef) return ST_CONTINUE;
status = (*arg->func)(key, value, arg->arg);
if (RHASH(arg->hash)->tbl != tbl) {
@@ -218,7 +234,7 @@ rb_hash_foreach(hash, func, farg)
RHASH(hash)->iter_lev++;
arg.hash = hash;
- arg.func = func;
+ arg.func = (rb_foreach_func *)func;
arg.arg = farg;
rb_ensure(hash_foreach_call, (VALUE)&arg, hash_foreach_ensure, hash);
}
@@ -259,7 +275,7 @@ rb_hash_new()
* Hash.new => hash
* Hash.new(obj) => aHash
* Hash.new {|hash, key| block } => aHash
- *
+ *
* Returns a new, empty hash. If this hash is subsequently accessed by
* a key that doesn't correspond to a hash entry, the value returned
* depends on the style of <code>new</code> used to create the hash. In
@@ -269,7 +285,7 @@ rb_hash_new()
* called with the hash object and the key, and should return the
* default value. It is the block's responsibility to store the value
* in the hash if required.
- *
+ *
* h = Hash.new("Go Fish")
* h["a"] = 100
* h["b"] = 200
@@ -279,14 +295,14 @@ rb_hash_new()
* h["c"].upcase! #=> "GO FISH"
* h["d"] #=> "GO FISH"
* h.keys #=> ["a", "b"]
- *
+ *
* # While this creates a new default object each time
* h = Hash.new { |hash, key| hash[key] = "Go Fish: #{key}" }
* h["c"] #=> "Go Fish: c"
* h["c"].upcase! #=> "GO FISH: C"
* h["d"] #=> "Go Fish: d"
* h.keys #=> ["c", "d"]
- *
+ *
*/
static VALUE
@@ -316,11 +332,11 @@ rb_hash_initialize(argc, argv, hash)
/*
* call-seq:
* Hash[ [key =>|, value]* ] => hash
- *
+ *
* Creates a new hash populated with the given objects. Equivalent to
* the literal <code>{ <i>key</i>, <i>value</i>, ... }</code>. Keys and
* values occur in pairs, so there must be an even number of arguments.
- *
+ *
* Hash["a", 100, "b", 200] #=> {"a"=>100, "b"=>200}
* Hash["a" => 100, "b" => 200] #=> {"a"=>100, "b"=>200}
* { "a" => 100, "b" => 200 } #=> {"a"=>100, "b"=>200}
@@ -332,16 +348,38 @@ rb_hash_s_create(argc, argv, klass)
VALUE *argv;
VALUE klass;
{
- VALUE hash;
+ VALUE hash, tmp;
int i;
- if (argc == 1 && TYPE(argv[0]) == T_HASH) {
- hash = hash_alloc0(klass);
- RHASH(hash)->tbl = st_copy(RHASH(argv[0])->tbl);
+ if (argc == 1) {
+ tmp = rb_check_convert_type(argv[0], T_HASH, "Hash", "to_hash");
+ if (!NIL_P(tmp)) {
+ hash = hash_alloc0(klass);
+ RHASH(hash)->tbl = st_copy(RHASH(tmp)->tbl);
+ return hash;
+ }
- return hash;
+ tmp = rb_check_array_type(argv[0]);
+ if (!NIL_P(tmp)) {
+ long i;
+
+ hash = hash_alloc(klass);
+ for (i = 0; i < RARRAY_LEN(tmp); ++i) {
+ VALUE v = rb_check_array_type(RARRAY_PTR(tmp)[i]);
+ VALUE key, val = Qnil;
+
+ if (NIL_P(v)) continue;
+ switch (RARRAY_LEN(v)) {
+ case 2:
+ val = RARRAY_PTR(v)[1];
+ case 1:
+ key = RARRAY_PTR(v)[0];
+ rb_hash_aset(hash, key, val);
+ }
+ }
+ return hash;
+ }
}
-
if (argc % 2 != 0) {
rb_raise(rb_eArgError, "odd number of arguments for Hash");
}
@@ -373,13 +411,13 @@ rb_hash_rehash_i(key, value, tbl)
/*
* call-seq:
* hsh.rehash -> hsh
- *
+ *
* Rebuilds the hash based on the current hash values for each key. If
* values of key objects have changed since they were inserted, this
* method will reindex <i>hsh</i>. If <code>Hash#rehash</code> is
* called while an iterator is traversing the hash, an
* <code>IndexError</code> will be raised in the iterator.
- *
+ *
* a = [ "a", "b" ]
* c = [ "c", "d" ]
* h = { a => 100, c => 300 }
@@ -408,15 +446,15 @@ rb_hash_rehash(hash)
/*
* call-seq:
* hsh[key] => value
- *
+ *
* Element Reference---Retrieves the <i>value</i> object corresponding
* to the <i>key</i> object. If not found, returns the a default value (see
* <code>Hash::new</code> for details).
- *
+ *
* h = { "a" => 100, "b" => 200 }
* h["a"] #=> 100
* h["c"] #=> nil
- *
+ *
*/
VALUE
@@ -431,33 +469,45 @@ rb_hash_aref(hash, key)
return val;
}
+VALUE
+rb_hash_lookup(hash, key)
+ VALUE hash, key;
+{
+ VALUE val;
+
+ if (!st_lookup(RHASH(hash)->tbl, key, &val)) {
+ return Qnil; /* without Hash#default */
+ }
+ return val;
+}
+
/*
* call-seq:
* hsh.fetch(key [, default] ) => obj
* hsh.fetch(key) {| key | block } => obj
- *
+ *
* Returns a value from the hash for the given key. If the key can't be
* found, there are several options: With no other arguments, it will
* raise an <code>IndexError</code> exception; if <i>default</i> is
* given, then that will be returned; if the optional code block is
* specified, then that will be run and its result returned.
- *
+ *
* h = { "a" => 100, "b" => 200 }
* h.fetch("a") #=> 100
* h.fetch("z", "go fish") #=> "go fish"
* h.fetch("z") { |el| "go fish, #{el}"} #=> "go fish, z"
- *
+ *
* The following example shows that an exception is raised if the key
* is not found and a default value is not supplied.
- *
+ *
* h = { "a" => 100, "b" => 200 }
* h.fetch("z")
- *
+ *
* <em>produces:</em>
- *
+ *
* prog.rb:2:in `fetch': key not found (IndexError)
* from prog.rb:2
- *
+ *
*/
static VALUE
@@ -489,21 +539,21 @@ rb_hash_fetch(argc, argv, hash)
/*
* call-seq:
* hsh.default(key=nil) => obj
- *
+ *
* Returns the default value, the value that would be returned by
* <i>hsh</i>[<i>key</i>] if <i>key</i> did not exist in <i>hsh</i>.
* See also <code>Hash::new</code> and <code>Hash#default=</code>.
- *
+ *
* h = Hash.new #=> {}
* h.default #=> nil
* h.default(2) #=> nil
- *
+ *
* h = Hash.new("cat") #=> {}
* h.default #=> "cat"
* h.default(2) #=> "cat"
- *
+ *
* h = Hash.new {|h,k| h[k] = k.to_i*10} #=> {}
- * h.default #=> 0
+ * h.default #=> nil
* h.default(2) #=> 20
*/
@@ -526,11 +576,11 @@ rb_hash_default(argc, argv, hash)
/*
* call-seq:
* hsh.default = obj => hsh
- *
+ *
* Sets the default value, the value returned for a key that does not
* exist in the hash. It is not possible to set the a default to a
* <code>Proc</code> that will be executed on each key lookup.
- *
+ *
* h = { "a" => 100, "b" => 200 }
* h.default = "Go fish"
* h["a"] #=> 100
@@ -556,10 +606,10 @@ rb_hash_set_default(hash, ifnone)
/*
* call-seq:
* hsh.default_proc -> anObject
- *
+ *
* If <code>Hash::new</code> was invoked with a block, return that
* block, otherwise return <code>nil</code>.
- *
+ *
* h = Hash.new {|h,k| h[k] = k*k } #=> {}
* p = h.default_proc #=> #<Proc:0x401b3d08@-:1>
* a = [] #=> []
@@ -610,13 +660,13 @@ rb_hash_delete_key(hash, key)
/*
* call-seq:
* hsh.index(value) => key
- *
+ *
* Returns the key for a given value. If not found, returns <code>nil</code>.
- *
+ *
* h = { "a" => 100, "b" => 200 }
* h.index(200) #=> "b"
* h.index(999) #=> nil
- *
+ *
*/
static VALUE
@@ -637,9 +687,9 @@ rb_hash_index(hash, value)
* call-seq:
* hsh.indexes(key, ...) => array
* hsh.indices(key, ...) => array
- *
+ *
* Deprecated in favor of <code>Hash#select</code>.
- *
+ *
*/
static VALUE
@@ -665,18 +715,17 @@ rb_hash_indexes(argc, argv, hash)
* call-seq:
* hsh.delete(key) => value
* hsh.delete(key) {| key | block } => value
- *
+ *
* Deletes and returns a key-value pair from <i>hsh</i> whose key is
- * equal to <i>key</i>. If the key is not found, returns the
- * <em>default value</em>. If the optional code block is given and the
- * key is not found, pass in the key and return the result of
- * <i>block</i>.
- *
+ * equal to <i>key</i>. If the key is not found, returns <code>nil</code>.
+ * If the optional code block is given and the key is not found,
+ * pass in the key and return the result of <i>block</i>.
+ *
* h = { "a" => 100, "b" => 200 }
* h.delete("a") #=> 100
* h.delete("z") #=> nil
* h.delete("z") { |el| "#{el} not found" } #=> "z not found"
- *
+ *
*/
VALUE
@@ -725,11 +774,11 @@ shift_i_safe(key, value, var)
/*
* call-seq:
* hsh.shift -> anArray or obj
- *
+ *
* Removes a key-value pair from <i>hsh</i> and returns it as the
* two-item array <code>[</code> <i>key, value</i> <code>]</code>, or
* the hash's default value if the hash is empty.
- *
+ *
* h = { 1 => "a", 2 => "b", 3 => "c" }
* h.shift #=> [1, "a"]
* h #=> {2=>"b", 3=>"c"}
@@ -781,19 +830,20 @@ delete_if_i(key, value, hash)
/*
* call-seq:
* hsh.delete_if {| key, value | block } -> hsh
- *
+ *
* Deletes every key-value pair from <i>hsh</i> for which <i>block</i>
* evaluates to <code>true</code>.
- *
+ *
* h = { "a" => 100, "b" => 200, "c" => 300 }
* h.delete_if {|key, value| key >= "b" } #=> {"a"=>100}
- *
+ *
*/
VALUE
rb_hash_delete_if(hash)
VALUE hash;
{
+ RETURN_ENUMERATOR(hash, 0, 0);
rb_hash_modify(hash);
rb_hash_foreach(hash, delete_if_i, hash);
return hash;
@@ -802,7 +852,7 @@ rb_hash_delete_if(hash)
/*
* call-seq:
* hsh.reject! {| key, value | block } -> hsh or nil
- *
+ *
* Equivalent to <code>Hash#delete_if</code>, but returns
* <code>nil</code> if no changes were made.
*/
@@ -811,7 +861,10 @@ VALUE
rb_hash_reject_bang(hash)
VALUE hash;
{
- int n = RHASH(hash)->tbl->num_entries;
+ int n;
+
+ RETURN_ENUMERATOR(hash, 0, 0);
+ n = RHASH(hash)->tbl->num_entries;
rb_hash_delete_if(hash);
if (n == RHASH(hash)->tbl->num_entries) return Qnil;
return hash;
@@ -820,11 +873,11 @@ rb_hash_reject_bang(hash)
/*
* call-seq:
* hsh.reject {| key, value | block } -> a_hash
- *
+ *
* Same as <code>Hash#delete_if</code>, but works on (and returns) a
* copy of the <i>hsh</i>. Equivalent to
* <code><i>hsh</i>.dup.delete_if</code>.
- *
+ *
*/
static VALUE
@@ -853,7 +906,7 @@ select_i(key, value, result)
*
* h = { "cat" => "feline", "dog" => "canine", "cow" => "bovine" }
* h.values_at("cow", "cat") #=> ["bovine", "feline"]
-*/
+ */
VALUE
rb_hash_values_at(argc, argv, hash)
@@ -873,27 +926,23 @@ rb_hash_values_at(argc, argv, hash)
/*
* call-seq:
* hsh.select {|key, value| block} => array
- *
+ *
* Returns a new array consisting of <code>[key,value]</code>
* pairs for which the block returns true.
* Also see <code>Hash.values_at</code>.
- *
+ *
* h = { "a" => 100, "b" => 200, "c" => 300 }
* h.select {|k,v| k > "a"} #=> [["b", 200], ["c", 300]]
* h.select {|k,v| v < 200} #=> [["a", 100]]
*/
VALUE
-rb_hash_select(argc, argv, hash)
- int argc;
- VALUE *argv;
+rb_hash_select(hash)
VALUE hash;
{
VALUE result;
- if (argc > 0) {
- rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc);
- }
+ RETURN_ENUMERATOR(hash, 0, 0);
result = rb_ary_new();
rb_hash_foreach(hash, select_i, result);
return result;
@@ -909,12 +958,12 @@ clear_i(key, value, dummy)
/*
* call-seq:
* hsh.clear -> hsh
- *
+ *
* Removes all key-value pairs from <i>hsh</i>.
- *
+ *
* h = { "a" => 100, "b" => 200 } #=> {"a"=>100, "b"=>200}
* h.clear #=> {}
- *
+ *
*/
static VALUE
@@ -933,18 +982,18 @@ rb_hash_clear(hash)
* call-seq:
* hsh[key] = value => value
* hsh.store(key, value) => value
- *
+ *
* Element Assignment---Associates the value given by
* <i>value</i> with the key given by <i>key</i>.
* <i>key</i> should not have its value changed while it is in
* use as a key (a <code>String</code> passed as a key will be
* duplicated and frozen).
- *
+ *
* h = { "a" => 100, "b" => 200 }
* h["a"] = 9
* h["c"] = 4
* h #=> {"a"=>9, "b"=>200, "c"=>4}
- *
+ *
*/
VALUE
@@ -975,13 +1024,13 @@ replace_i(key, val, hash)
/*
* call-seq:
* hsh.replace(other_hash) -> hsh
- *
+ *
* Replaces the contents of <i>hsh</i> with the contents of
* <i>other_hash</i>.
- *
+ *
* h = { "a" => 100, "b" => 200 }
* h.replace({ "c" => 300, "d" => 400 }) #=> {"c"=>300, "d"=>400}
- *
+ *
*/
static VALUE
@@ -1007,9 +1056,9 @@ rb_hash_replace(hash, hash2)
* call-seq:
* hsh.length => fixnum
* hsh.size => fixnum
- *
+ *
* Returns the number of key-value pairs in the hash.
- *
+ *
* h = { "d" => 100, "a" => 200, "v" => 300, "e" => 400 }
* h.length #=> 4
* h.delete("a") #=> 200
@@ -1027,11 +1076,11 @@ rb_hash_size(hash)
/*
* call-seq:
* hsh.empty? => true or false
- *
+ *
* Returns <code>true</code> if <i>hsh</i> contains no key-value pairs.
- *
+ *
* {}.empty? #=> true
- *
+ *
*/
static VALUE
@@ -1055,15 +1104,15 @@ each_value_i(key, value)
/*
* call-seq:
* hsh.each_value {| value | block } -> hsh
- *
+ *
* Calls <i>block</i> once for each key in <i>hsh</i>, passing the
* value as a parameter.
- *
+ *
* h = { "a" => 100, "b" => 200 }
* h.each_value {|value| puts value }
- *
+ *
* <em>produces:</em>
- *
+ *
* 100
* 200
*/
@@ -1072,6 +1121,7 @@ static VALUE
rb_hash_each_value(hash)
VALUE hash;
{
+ RETURN_ENUMERATOR(hash, 0, 0);
rb_hash_foreach(hash, each_value_i, 0);
return hash;
}
@@ -1088,15 +1138,15 @@ each_key_i(key, value)
/*
* call-seq:
* hsh.each_key {| key | block } -> hsh
- *
+ *
* Calls <i>block</i> once for each key in <i>hsh</i>, passing the key
* as a parameter.
- *
+ *
* h = { "a" => 100, "b" => 200 }
* h.each_key {|key| puts key }
- *
+ *
* <em>produces:</em>
- *
+ *
* a
* b
*/
@@ -1104,6 +1154,7 @@ static VALUE
rb_hash_each_key(hash)
VALUE hash;
{
+ RETURN_ENUMERATOR(hash, 0, 0);
rb_hash_foreach(hash, each_key_i, 0);
return hash;
}
@@ -1120,24 +1171,25 @@ each_pair_i(key, value)
/*
* call-seq:
* hsh.each_pair {| key_value_array | block } -> hsh
- *
+ *
* Calls <i>block</i> once for each key in <i>hsh</i>, passing the key
* and value as parameters.
- *
+ *
* h = { "a" => 100, "b" => 200 }
* h.each_pair {|key, value| puts "#{key} is #{value}" }
- *
+ *
* <em>produces:</em>
- *
+ *
* a is 100
* b is 200
- *
+ *
*/
static VALUE
rb_hash_each_pair(hash)
VALUE hash;
{
+ RETURN_ENUMERATOR(hash, 0, 0);
rb_hash_foreach(hash, each_pair_i, 0);
return hash;
}
@@ -1154,27 +1206,28 @@ each_i(key, value)
/*
* call-seq:
* hsh.each {| key, value | block } -> hsh
- *
+ *
* Calls <i>block</i> once for each key in <i>hsh</i>, passing the key
* and value to the block as a two-element array. Because of the assignment
* semantics of block parameters, these elements will be split out if the
* block has two formal parameters. Also see <code>Hash.each_pair</code>, which
* will be marginally more efficient for blocks with two parameters.
- *
+ *
* h = { "a" => 100, "b" => 200 }
* h.each {|key, value| puts "#{key} is #{value}" }
- *
+ *
* <em>produces:</em>
- *
+ *
* a is 100
* b is 200
- *
+ *
*/
static VALUE
rb_hash_each(hash)
VALUE hash;
{
+ RETURN_ENUMERATOR(hash, 0, 0);
rb_hash_foreach(hash, each_i, 0);
return hash;
}
@@ -1191,10 +1244,10 @@ to_a_i(key, value, ary)
/*
* call-seq:
* hsh.to_a -> array
- *
+ *
* Converts <i>hsh</i> to a nested array of <code>[</code> <i>key,
* value</i> <code>]</code> arrays.
- *
+ *
* h = { "c" => 300, "a" => 100, "d" => 400, "c" => 300 }
* h.to_a #=> [["a", 100], ["c", 300], ["d", 400]]
*/
@@ -1214,17 +1267,17 @@ rb_hash_to_a(hash)
/*
* call-seq:
- * hsh.sort => array
- * hsh.sort {| a, b | block } => array
- *
+ * hsh.sort => array
+ * hsh.sort {| a, b | block } => array
+ *
* Converts <i>hsh</i> to a nested array of <code>[</code> <i>key,
* value</i> <code>]</code> arrays and sorts it, using
* <code>Array#sort</code>.
- *
+ *
* h = { "a" => 20, "b" => 30, "c" => 10 }
* h.sort #=> [["a", 20], ["b", 30], ["c", 10]]
* h.sort {|a,b| a[1]<=>b[1]} #=> [["c", 10], ["a", 20], ["b", 30]]
- *
+ *
*/
static VALUE
@@ -1298,12 +1351,12 @@ to_s_hash(hash)
/*
* call-seq:
* hsh.to_s => string
- *
+ *
* Converts <i>hsh</i> to a string by converting the hash to an array
* of <code>[</code> <i>key, value</i> <code>]</code> pairs and then
* converting that array to a string using <code>Array#join</code> with
* the default separator.
- *
+ *
* h = { "c" => 300, "a" => 100, "d" => 400, "c" => 300 }
* h.to_s #=> "a100c300d400"
*/
@@ -1342,13 +1395,13 @@ keys_i(key, value, ary)
/*
* call-seq:
* hsh.keys => array
- *
+ *
* Returns a new array populated with the keys from this hash. See also
* <code>Hash#values</code>.
- *
+ *
* h = { "a" => 100, "b" => 200, "c" => 300, "d" => 400 }
* h.keys #=> ["a", "b", "c", "d"]
- *
+ *
*/
static VALUE
@@ -1375,13 +1428,13 @@ values_i(key, value, ary)
/*
* call-seq:
* hsh.values => array
- *
+ *
* Returns a new array populated with the values from <i>hsh</i>. See
* also <code>Hash#keys</code>.
- *
+ *
* h = { "a" => 100, "b" => 200, "c" => 300 }
* h.values #=> [100, 200, 300]
- *
+ *
*/
static VALUE
@@ -1402,13 +1455,13 @@ rb_hash_values(hash)
* hsh.include?(key) => true or false
* hsh.key?(key) => true or false
* hsh.member?(key) => true or false
- *
+ *
* Returns <code>true</code> if the given key is present in <i>hsh</i>.
- *
+ *
* h = { "a" => 100, "b" => 200 }
* h.has_key?("a") #=> true
* h.has_key?("z") #=> false
- *
+ *
*/
static VALUE
@@ -1438,10 +1491,10 @@ rb_hash_search_value(key, value, data)
* call-seq:
* hsh.has_value?(value) => true or false
* hsh.value?(value) => true or false
- *
+ *
* Returns <code>true</code> if the given value is present for some key
* in <i>hsh</i>.
- *
+ *
* h = { "a" => 100, "b" => 200 }
* h.has_value?(100) #=> true
* h.has_value?(999) #=> false
@@ -1463,11 +1516,13 @@ rb_hash_has_value(hash, val)
struct equal_data {
int result;
st_table *tbl;
+ int eql;
};
static int
-equal_i(key, val1, data)
- VALUE key, val1;
+eql_i(key, val1, data)
+ VALUE key;
+ VALUE val1;
struct equal_data *data;
{
VALUE val2;
@@ -1477,13 +1532,30 @@ equal_i(key, val1, data)
data->result = Qfalse;
return ST_STOP;
}
- if (!rb_equal(val1, val2)) {
+ if (!(data->eql ? rb_eql(val1, val2) : rb_equal(val1, val2))) {
data->result = Qfalse;
return ST_STOP;
}
return ST_CONTINUE;
}
+static VALUE recursive_eql _((VALUE, VALUE, int));
+static VALUE
+recursive_eql(hash, dt, recur)
+ VALUE hash;
+ VALUE dt;
+ int recur;
+{
+ struct equal_data *data;
+
+ if (recur) return Qfalse;
+ data = (struct equal_data*)dt;
+ data->result = Qtrue;
+ rb_hash_foreach(hash, eql_i, (st_data_t)data);
+
+ return data->result;
+}
+
static VALUE
hash_equal(hash1, hash2, eql)
VALUE hash1, hash2;
@@ -1507,21 +1579,19 @@ hash_equal(hash1, hash2, eql)
}
data.tbl = RHASH(hash2)->tbl;
- data.result = Qtrue;
- rb_hash_foreach(hash1, equal_i, (st_data_t)&data);
-
- return data.result;
+ data.eql = eql;
+ return rb_exec_recursive(recursive_eql, hash1, (VALUE)&data);
}
/*
* call-seq:
* hsh == other_hash => true or false
- *
+ *
* Equality---Two hashes are equal if they each contain the same number
* of keys and if each key-value pair is equal to (according to
* <code>Object#==</code>) the corresponding elements in the other
* hash.
- *
+ *
* h1 = { "a" => 1, "c" => 2 }
* h2 = { 7 => 35, "c" => 2, "a" => 1 }
* h3 = { "a" => 1, "c" => 2, 7 => 35 }
@@ -1529,7 +1599,7 @@ hash_equal(hash1, hash2, eql)
* h1 == h2 #=> false
* h2 == h3 #=> true
* h3 == h4 #=> false
- *
+ *
*/
static VALUE
@@ -1540,6 +1610,66 @@ rb_hash_equal(hash1, hash2)
}
static int
+hash_i(key, val, hval)
+ VALUE key;
+ VALUE val;
+ int *hval;
+{
+ if (key == Qundef) return ST_CONTINUE;
+ *hval ^= rb_hash(key);
+ *hval ^= rb_hash(val);
+ return ST_CONTINUE;
+}
+
+static VALUE recursive_hash _((VALUE, VALUE, int));
+static VALUE
+recursive_hash(hash, dummy, recur)
+ VALUE hash;
+ VALUE dummy;
+ int recur;
+{
+ int hval;
+
+ if (recur) {
+ return LONG2FIX(0);
+ }
+ hval = RHASH(hash)->tbl->num_entries;
+ rb_hash_foreach(hash, hash_i, (st_data_t)&hval);
+ return INT2FIX(hval);
+}
+
+/*
+ * call-seq:
+ * array.hash -> fixnum
+ *
+ * Compute a hash-code for this array. Two arrays with the same content
+ * will have the same hash code (and will compare using <code>eql?</code>).
+ */
+
+static VALUE
+rb_hash_hash(hash)
+ VALUE hash;
+{
+ return rb_exec_recursive(recursive_hash, hash, 0);
+}
+
+
+/*
+ * call-seq:
+ * hash.eql?(other) -> true or false
+ *
+ * Returns <code>true</code> if <i>hash</i> and <i>other</i> are
+ * both hashes with the same content.
+ */
+
+static VALUE
+rb_hash_eql(hash1, hash2)
+ VALUE hash1, hash2;
+{
+ return hash_equal(hash1, hash2, Qtrue);
+}
+
+static int
rb_hash_invert_i(key, value, hash)
VALUE key, value;
VALUE hash;
@@ -1552,13 +1682,13 @@ rb_hash_invert_i(key, value, hash)
/*
* call-seq:
* hsh.invert -> aHash
- *
+ *
* Returns a new hash created by using <i>hsh</i>'s values as keys, and
* the keys as values.
- *
+ *
* h = { "n" => 100, "m" => 100, "y" => 300, "d" => 200, "a" => 0 }
* h.invert #=> {0=>"a", 100=>"n", 200=>"d", 300=>"y"}
- *
+ *
*/
static VALUE
@@ -1600,13 +1730,21 @@ rb_hash_update_block_i(key, value, hash)
* hsh.update(other_hash) => hsh
* hsh.merge!(other_hash){|key, oldval, newval| block} => hsh
* hsh.update(other_hash){|key, oldval, newval| block} => hsh
- *
- * Adds the contents of <i>other_hash</i> to <i>hsh</i>, overwriting
- * entries with duplicate keys with those from <i>other_hash</i>.
- *
+ *
+ * Adds the contents of <i>other_hash</i> to <i>hsh</i>. If no
+ * block is specified entries with duplicate keys are overwritten
+ * with the values from <i>other_hash</i>, otherwise the value
+ * of each duplicate key is determined by calling the block with
+ * the key, its value in <i>hsh</i> and its value in <i>other_hash</i>.
+ *
* h1 = { "a" => 100, "b" => 200 }
* h2 = { "b" => 254, "c" => 300 }
* h1.merge!(h2) #=> {"a"=>100, "b"=>254, "c"=>300}
+ *
+ * h1 = { "a" => 100, "b" => 200 }
+ * h2 = { "b" => 254, "c" => 300 }
+ * h1.merge!(h2) { |key, v1, v2| v1 }
+ * #=> {"a"=>100, "b"=>200, "c"=>300}
*/
static VALUE
@@ -1627,16 +1765,16 @@ rb_hash_update(hash1, hash2)
* call-seq:
* hsh.merge(other_hash) -> a_hash
* hsh.merge(other_hash){|key, oldval, newval| block} -> a_hash
- *
+ *
* Returns a new hash containing the contents of <i>other_hash</i> and
* the contents of <i>hsh</i>, overwriting entries in <i>hsh</i> with
* duplicate keys with those from <i>other_hash</i>.
- *
+ *
* h1 = { "a" => 100, "b" => 200 }
* h2 = { "b" => 254, "c" => 300 }
* h1.merge(h2) #=> {"a"=>100, "b"=>254, "c"=>300}
* h1 #=> {"a"=>100, "b"=>200}
- *
+ *
*/
static VALUE
@@ -1732,7 +1870,8 @@ rb_f_getenv(obj, name)
{
char *nam, *env;
- StringValue(name);
+ rb_secure(4);
+ SafeStringValue(name);
nam = RSTRING(name)->ptr;
if (strlen(nam) != RSTRING(name)->len) {
rb_raise(rb_eArgError, "bad environment variable name");
@@ -1764,12 +1903,13 @@ env_fetch(argc, argv)
long block_given;
char *nam, *env;
+ rb_secure(4);
rb_scan_args(argc, argv, "11", &key, &if_none);
block_given = rb_block_given_p();
if (block_given && argc == 2) {
rb_warn("block supersedes default value argument");
}
- StringValue(key);
+ SafeStringValue(key);
nam = RSTRING(key)->ptr;
if (strlen(nam) != RSTRING(key)->len) {
rb_raise(rb_eArgError, "bad environment variable name");
@@ -1807,6 +1947,19 @@ rb_env_path_tainted()
return path_tainted;
}
+#if defined(_WIN32) || (defined(HAVE_SETENV) && defined(HAVE_UNSETENV))
+#elif defined __sun__
+static int
+in_origenv(str)
+ const char *str;
+{
+ char **env;
+ for (env = origenviron; *env; ++env) {
+ if (*env == str) return 1;
+ }
+ return 0;
+}
+#else
static int
envix(nam)
const char *nam;
@@ -1828,6 +1981,7 @@ envix(nam)
FREE_ENVIRON(environ);
return i;
}
+#endif
void
ruby_setenv(name, value)
@@ -1860,6 +2014,21 @@ ruby_setenv(name, value)
setenv(name,value,1);
else
unsetenv(name);
+#elif defined __sun__
+ size_t len = strlen(name);
+ char **env_ptr, *str;
+ for (env_ptr = GET_ENVIRON(environ); (str = *env_ptr) != 0; ++env_ptr) {
+ if (!strncmp(str, name, len) && str[len] == '=') {
+ if (!in_origenv(str)) free(str);
+ while ((env_ptr[0] = env_ptr[1]) != 0) env_ptr++;
+ break;
+ }
+ }
+ if (value) {
+ str = malloc(len += strlen(value) + 2);
+ snprintf(str, len, "%s=%s", name, value);
+ putenv(str);
+ }
#else /* WIN32 */
size_t len;
int i=envix(name); /* where does it go? */
@@ -1964,8 +2133,10 @@ static VALUE
env_keys()
{
char **env;
- VALUE ary = rb_ary_new();
+ VALUE ary;
+ rb_secure(4);
+ ary = rb_ary_new();
env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
@@ -1982,9 +2153,11 @@ static VALUE
env_each_key(ehash)
VALUE ehash;
{
- VALUE keys = env_keys();
+ VALUE keys;
long i;
+ RETURN_ENUMERATOR(ehash, 0, 0);
+ keys = env_keys(); /* rb_secure(4); */
for (i=0; i<RARRAY(keys)->len; i++) {
rb_yield(RARRAY(keys)->ptr[i]);
}
@@ -1994,9 +2167,11 @@ env_each_key(ehash)
static VALUE
env_values()
{
+ VALUE ary;
char **env;
- VALUE ary = rb_ary_new();
+ rb_secure(4);
+ ary = rb_ary_new();
env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
@@ -2013,9 +2188,11 @@ static VALUE
env_each_value(ehash)
VALUE ehash;
{
- VALUE values = env_values();
+ VALUE values;
long i;
+ RETURN_ENUMERATOR(ehash, 0, 0);
+ values = env_values(); /* rb_secure(4); */
for (i=0; i<RARRAY(values)->len; i++) {
rb_yield(RARRAY(values)->ptr[i]);
}
@@ -2028,9 +2205,11 @@ env_each_i(ehash, values)
int values;
{
char **env;
- VALUE ary = rb_ary_new();
+ VALUE ary;
long i;
+ rb_secure(4);
+ ary = rb_ary_new();
env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
@@ -2057,6 +2236,7 @@ static VALUE
env_each(ehash)
VALUE ehash;
{
+ RETURN_ENUMERATOR(ehash, 0, 0);
return env_each_i(ehash, Qfalse);
}
@@ -2064,19 +2244,20 @@ static VALUE
env_each_pair(ehash)
VALUE ehash;
{
+ RETURN_ENUMERATOR(ehash, 0, 0);
return env_each_i(ehash, Qtrue);
}
static VALUE
-env_reject_bang()
+env_reject_bang(ehash)
+ VALUE ehash;
{
volatile VALUE keys;
long i;
int del = 0;
- rb_secure(4);
- keys = env_keys();
-
+ RETURN_ENUMERATOR(ehash, 0, 0);
+ keys = env_keys(); /* rb_secure(4); */
for (i=0; i<RARRAY(keys)->len; i++) {
VALUE val = rb_f_getenv(Qnil, RARRAY(keys)->ptr[i]);
if (!NIL_P(val)) {
@@ -2092,9 +2273,11 @@ env_reject_bang()
}
static VALUE
-env_delete_if()
+env_delete_if(ehash)
+ VALUE ehash;
{
- env_reject_bang();
+ RETURN_ENUMERATOR(ehash, 0, 0);
+ env_reject_bang(ehash);
return envtbl;
}
@@ -2103,9 +2286,11 @@ env_values_at(argc, argv)
int argc;
VALUE *argv;
{
- VALUE result = rb_ary_new();
+ VALUE result;
long i;
+ rb_secure(4);
+ result = rb_ary_new();
for (i=0; i<argc; i++) {
rb_ary_push(result, rb_f_getenv(Qnil, argv[i]));
}
@@ -2113,16 +2298,14 @@ env_values_at(argc, argv)
}
static VALUE
-env_select(argc, argv)
- int argc;
- VALUE *argv;
+env_select(ehash)
+ VALUE ehash;
{
VALUE result;
char **env;
- if (argc > 0) {
- rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc);
- }
+ RETURN_ENUMERATOR(ehash, 0, 0);
+ rb_secure(4);
result = rb_ary_new();
env = GET_ENVIRON(environ);
while (*env) {
@@ -2146,10 +2329,8 @@ env_clear()
{
volatile VALUE keys;
long i;
-
- rb_secure(4);
- keys = env_keys();
+ keys = env_keys(); /* rb_secure(4); */
for (i=0; i<RARRAY(keys)->len; i++) {
VALUE val = rb_f_getenv(Qnil, RARRAY(keys)->ptr[i]);
if (!NIL_P(val)) {
@@ -2169,9 +2350,10 @@ static VALUE
env_inspect()
{
char **env;
- VALUE str = rb_str_buf_new2("{");
- VALUE i;
+ VALUE str, i;
+ rb_secure(4);
+ str = rb_str_buf_new2("{");
env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
@@ -2199,8 +2381,10 @@ static VALUE
env_to_a()
{
char **env;
- VALUE ary = rb_ary_new();
+ VALUE ary;
+ rb_secure(4);
+ ary = rb_ary_new();
env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
@@ -2226,6 +2410,7 @@ env_size()
int i;
char **env;
+ rb_secure(4);
env = GET_ENVIRON(environ);
for(i=0; env[i]; i++)
;
@@ -2238,6 +2423,7 @@ env_empty_p()
{
char **env;
+ rb_secure(4);
env = GET_ENVIRON(environ);
if (env[0] == 0) {
FREE_ENVIRON(environ);
@@ -2253,6 +2439,7 @@ env_has_key(env, key)
{
char *s;
+ rb_secure(4);
s = StringValuePtr(key);
if (strlen(s) != RSTRING(key)->len)
rb_raise(rb_eArgError, "bad environment variable name");
@@ -2266,7 +2453,9 @@ env_has_value(dmy, value)
{
char **env;
- if (TYPE(value) != T_STRING) return Qfalse;
+ rb_secure(4);
+ value = rb_check_string_type(value);
+ if (NIL_P(value)) return Qfalse;
env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
@@ -2290,6 +2479,7 @@ env_index(dmy, value)
char **env;
VALUE str;
+ rb_secure(4);
StringValue(value);
env = GET_ENVIRON(environ);
while (*env) {
@@ -2318,6 +2508,7 @@ env_indexes(argc, argv)
rb_warn("ENV.%s is deprecated; use ENV.values_at",
rb_id2name(rb_frame_last_func()));
+ rb_secure(4);
for (i=0;i<argc;i++) {
VALUE tmp = rb_check_string_type(argv[i]);
if (NIL_P(tmp)) {
@@ -2336,8 +2527,10 @@ static VALUE
env_to_hash()
{
char **env;
- VALUE hash = rb_hash_new();
+ VALUE hash;
+ rb_secure(4);
+ hash = rb_hash_new();
env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
@@ -2362,6 +2555,7 @@ env_shift()
{
char **env;
+ rb_secure(4);
env = GET_ENVIRON(environ);
if (*env) {
char *s = strchr(*env, '=');
@@ -2399,9 +2593,10 @@ static VALUE
env_replace(env, hash)
VALUE env, hash;
{
- volatile VALUE keys = env_keys();
+ volatile VALUE keys;
long i;
+ keys = env_keys(); /* rb_secure(4); */
if (env == hash) return env;
hash = to_hash(hash);
rb_hash_foreach(hash, env_replace_i, keys);
@@ -2429,6 +2624,7 @@ static VALUE
env_update(env, hash)
VALUE env, hash;
{
+ rb_secure(4);
if (env == hash) return env;
hash = to_hash(hash);
rb_hash_foreach(hash, env_update_i, 0);
@@ -2441,11 +2637,43 @@ env_update(env, hash)
* arbitrary keys of any object type, not an integer index. The order
* in which you traverse a hash by either key or value may seem
* arbitrary, and will generally not be in the insertion order.
- *
+ *
* Hashes have a <em>default value</em> that is returned when accessing
* keys that do not exist in the hash. By default, that value is
* <code>nil</code>.
- *
+ *
+ * <code>Hash</code> uses <code>key.eql?</code> to test keys for equality.
+ * If you need to use instances of your own classes as keys in a <code>Hash</code>,
+ * it is recommended that you define both the <code>eql?</code> and <code>hash</code>
+ * methods. The <code>hash</code> method must have the property that
+ * <code>a.eql?(b)</code> implies <code>a.hash == b.hash</code>.
+ *
+ * class MyClass
+ * attr_reader :str
+ * def initialize(str)
+ * @str = str
+ * end
+ * def eql?(o)
+ * o.is_a?(MyClass) && str == o.str
+ * end
+ * def hash
+ * @str.hash
+ * end
+ * end
+ *
+ * a = MyClass.new("some string")
+ * b = MyClass.new("some string")
+ * a.eql? b #=> true
+ *
+ * h = {}
+ *
+ * h[a] = 1
+ * h[a] #=> 1
+ * h[b] #=> 1
+ *
+ * h[b] = 2
+ * h[a] #=> 2
+ * h[b] #=> 2
*/
void
@@ -2472,6 +2700,8 @@ Init_Hash()
rb_define_method(rb_cHash,"==", rb_hash_equal, 1);
rb_define_method(rb_cHash,"[]", rb_hash_aref, 1);
+ rb_define_method(rb_cHash,"hash", rb_hash_hash, 0);
+ rb_define_method(rb_cHash,"eql?", rb_hash_eql, 1);
rb_define_method(rb_cHash,"fetch", rb_hash_fetch, -1);
rb_define_method(rb_cHash,"[]=", rb_hash_aset, 2);
rb_define_method(rb_cHash,"store", rb_hash_aset, 2);
@@ -2498,7 +2728,7 @@ Init_Hash()
rb_define_method(rb_cHash,"shift", rb_hash_shift, 0);
rb_define_method(rb_cHash,"delete", rb_hash_delete, 1);
rb_define_method(rb_cHash,"delete_if", rb_hash_delete_if, 0);
- rb_define_method(rb_cHash,"select", rb_hash_select, -1);
+ rb_define_method(rb_cHash,"select", rb_hash_select, 0);
rb_define_method(rb_cHash,"reject", rb_hash_reject, 0);
rb_define_method(rb_cHash,"reject!", rb_hash_reject_bang, 0);
rb_define_method(rb_cHash,"clear", rb_hash_clear, 0);
@@ -2533,7 +2763,7 @@ Init_Hash()
rb_define_singleton_method(envtbl,"clear", env_clear, 0);
rb_define_singleton_method(envtbl,"reject", env_reject, 0);
rb_define_singleton_method(envtbl,"reject!", env_reject_bang, 0);
- rb_define_singleton_method(envtbl,"select", env_select, -1);
+ rb_define_singleton_method(envtbl,"select", env_select, 0);
rb_define_singleton_method(envtbl,"shift", env_shift, 0);
rb_define_singleton_method(envtbl,"invert", env_invert, 0);
rb_define_singleton_method(envtbl,"replace", env_replace, 1);
diff --git a/ia64.s b/ia64.s
new file mode 100644
index 0000000000..ba5241daf2
--- /dev/null
+++ b/ia64.s
@@ -0,0 +1,33 @@
+// rb_ia64_flushrs and rb_ia64_bsp is written in IA64 assembly language
+// because Intel Compiler for IA64 doesn't support inline assembly.
+//
+// This file is based on following C program compiled by gcc.
+//
+// void rb_ia64_flushrs(void) { __builtin_ia64_flushrs(); }
+// void *rb_ia64_bsp(void) { return __builtin_ia64_bsp(); }
+//
+ .file "ia64.c"
+ .text
+ .align 16
+ .global rb_ia64_flushrs#
+ .proc rb_ia64_flushrs#
+rb_ia64_flushrs:
+ .prologue
+ .body
+ flushrs
+ ;;
+ nop.i 0
+ br.ret.sptk.many b0
+ .endp rb_ia64_flushrs#
+ .align 16
+ .global rb_ia64_bsp#
+ .proc rb_ia64_bsp#
+rb_ia64_bsp:
+ .prologue
+ .body
+ nop.m 0
+ ;;
+ mov r8 = ar.bsp
+ br.ret.sptk.many b0
+ .endp rb_ia64_bsp#
+ .ident "GCC: (GNU) 3.3.5 (Debian 1:3.3.5-13)"
diff --git a/inits.c b/inits.c
index 4c6008e4b0..947bbbe242 100644
--- a/inits.c
+++ b/inits.c
@@ -2,8 +2,8 @@
inits.c -
- $Author: dave $
- $Date: 2003/12/19 03:58:57 $
+ $Author$
+ $Date$
created at: Tue Dec 28 16:01:58 JST 1993
Copyright (C) 1993-2003 Yukihiro Matsumoto
@@ -18,6 +18,7 @@ void Init_Binding _((void));
void Init_Comparable _((void));
void Init_Dir _((void));
void Init_Enumerable _((void));
+void Init_Enumerator _((void));
void Init_Exception _((void));
void Init_syserr _((void));
void Init_eval _((void));
@@ -79,6 +80,7 @@ rb_call_inits()
Init_Binding();
Init_Math();
Init_GC();
+ Init_Enumerator();
Init_marshal();
Init_version();
}
diff --git a/instruby.rb b/instruby.rb
index 1237b01abc..2903a7c739 100644..100755
--- a/instruby.rb
+++ b/instruby.rb
@@ -1,7 +1,7 @@
#!./miniruby
load "./rbconfig.rb"
-include Config
+include RbConfig
srcdir = File.dirname(__FILE__)
$:.unshift File.expand_path("lib", srcdir)
@@ -14,15 +14,26 @@ require 'tempfile'
STDOUT.sync = true
File.umask(0)
-def parse_args()
+def parse_args(argv = ARGV)
$mantype = 'doc'
$destdir = nil
+ $extout = nil
$make = 'make'
$mflags = []
$install = []
+ $installed_list = nil
+ $dryrun = false
+ $rdocdir = nil
+ $data_mode = 0644
+ $prog_mode = 0755
+ $dir_mode = nil
+ $script_mode = nil
+ $cmdtype = ('bat' if File::ALT_SEPARATOR == '\\')
+ mflags = []
opt = OptionParser.new
opt.on('-n') {$dryrun = true}
opt.on('--dest-dir=DIR') {|dir| $destdir = dir}
+ opt.on('--extout=DIR') {|dir| $extout = (dir unless dir.empty?)}
opt.on('--make=COMMAND') {|make| $make = make}
opt.on('--mantype=MAN') {|man| $mantype = man}
opt.on('--make-flags=FLAGS', '--mflags', Shellwords) do |v|
@@ -31,14 +42,49 @@ def parse_args()
end
$mflags.concat(v)
end
- opt.on('--install=TYPE', [:bin, :lib, :man]) {|ins| $install << ins}
- opt.parse! rescue abort [$!.message, opt].join("\n")
+ opt.on('-i', '--install=TYPE',
+ [:local, :bin, :"bin-arch", :"bin-comm", :lib, :man, :ext, :"ext-arch", :"ext-comm", :rdoc]) do |ins|
+ $install << ins
+ end
+ opt.on('--data-mode=OCTAL-MODE', OptionParser::OctalInteger) do |mode|
+ $data_mode = mode
+ end
+ opt.on('--prog-mode=OCTAL-MODE', OptionParser::OctalInteger) do |mode|
+ $prog_mode = mode
+ end
+ opt.on('--dir-mode=OCTAL-MODE', OptionParser::OctalInteger) do |mode|
+ $dir_mode = mode
+ end
+ opt.on('--script-mode=OCTAL-MODE', OptionParser::OctalInteger) do |mode|
+ $script_mode = mode
+ end
+ opt.on('--installed-list [FILENAME]') {|name| $installed_list = name}
+ opt.on('--rdoc-output [DIR]') {|dir| $rdocdir = dir}
+ opt.on('--cmd-type=TYPE', %w[bat cmd plain]) {|cmd| $cmdtype = (cmd unless cmd == 'plain')}
+
+ opt.order!(argv) do |v|
+ case v
+ when /\AINSTALL[-_]([-\w]+)=(.*)/
+ argv.unshift("--#{$1.tr('_', '-')}=#{$2}")
+ when /\A\w[-\w+]*=\z/
+ mflags << v
+ when /\A\w[-\w+]*\z/
+ $install << v.intern
+ else
+ raise OptionParser::InvalidArgument, v
+ end
+ end rescue abort [$!.message, opt].join("\n")
$make, *rest = Shellwords.shellwords($make)
$mflags.unshift(*rest) unless rest.empty?
+ $mflags.unshift(*mflags)
def $mflags.set?(flag)
- grep(/\A-(?!-).*#{'%c' % flag}/i) { return true }
+ grep(/\A-(?!-).*#{flag.chr}/i) { return true }
+ false
+ end
+ def $mflags.defined?(var)
+ grep(/\A#{var}=(.*)/) {return block_given? ? yield($1) : $1}
false
end
@@ -48,37 +94,105 @@ def parse_args()
$mflags << '-n' if $dryrun
end
- $mflags << "DESTDIR=#{$destdir}"
+ $destdir ||= $mflags.defined?("DESTDIR")
+ if $extout ||= $mflags.defined?("EXTOUT")
+ Config.expand($extout)
+ end
$continue = $mflags.set?(?k)
+
+ if $installed_list ||= $mflags.defined?('INSTALLED_LIST')
+ Config.expand($installed_list, Config::CONFIG)
+ $installed_list = open($installed_list, "ab")
+ $installed_list.sync = true
+ end
+
+ $rdocdir ||= $mflags.defined?('RDOCOUT')
+
+ $dir_mode ||= $prog_mode | 0700
+ $script_mode ||= $prog_mode
end
parse_args()
-include FileUtils::Verbose
+include FileUtils
include FileUtils::NoWrite if $dryrun
@fileutils_output = STDOUT
@fileutils_label = ''
-def install?(type)
- yield if $install.empty? or $install.include?(type)
+$install_procs = Hash.new {[]}
+def install?(*types, &block)
+ $install_procs[:all] <<= block
+ types.each do |type|
+ $install_procs[type] <<= block
+ end
end
def install(src, dest, options = {})
options[:preserve] = true
- super
+ super(src, with_destdir(dest), options)
+ if $installed_list
+ dest = File.join(dest, File.basename(src)) if $made_dirs[dest]
+ $installed_list.puts dest
+ end
+end
+
+def ln_sf(src, dest)
+ super(src, with_destdir(dest))
+ $installed_list.puts dest if $installed_list
end
$made_dirs = {}
def makedirs(dirs)
dirs = fu_list(dirs)
- dirs.reject! do |dir|
- $made_dirs.fetch(dir) do
+ dirs.collect! do |dir|
+ realdir = with_destdir(dir)
+ realdir unless $made_dirs.fetch(dir) do
$made_dirs[dir] = true
- File.directory?(dir)
+ $installed_list.puts(File.join(dir, "")) if $installed_list
+ File.directory?(realdir)
+ end
+ end.compact!
+ super(dirs, :mode => $dir_mode) unless dirs.empty?
+end
+
+def install_recursive(srcdir, dest, options = {})
+ opts = options.clone
+ noinst = opts.delete(:no_install)
+ glob = opts.delete(:glob) || "*"
+ subpath = srcdir.size..-1
+ Dir.glob("#{srcdir}/**/#{glob}") do |src|
+ case base = File.basename(src)
+ when /\A\#.*\#\z/, /~\z/
+ next
+ end
+ if noinst
+ if Array === noinst
+ next if noinst.any? {|n| File.fnmatch?(n, base)}
+ else
+ next if File.fnmatch?(noinst, base)
+ end
end
+ d = dest + src[subpath]
+ if File.directory?(src)
+ makedirs(d)
+ else
+ makedirs(File.dirname(d))
+ install src, d, opts
+ end
+ end
+end
+
+def open_for_install(path, mode)
+ data = open(realpath = with_destdir(path), "rb") {|f| f.read} rescue nil
+ newdata = yield
+ unless $dryrun
+ unless newdata == data
+ open(realpath, "wb", mode) {|f| f.write newdata}
+ end
+ File.chmod(mode, realpath)
end
- super(dirs, :mode => 0755, :verbose => true) unless dirs.empty?
+ $installed_list.puts path if $installed_list
end
def with_destdir(dir)
@@ -93,47 +207,40 @@ ruby_install_name = CONFIG["ruby_install_name"]
rubyw_install_name = CONFIG["rubyw_install_name"]
version = CONFIG["ruby_version"]
-bindir = with_destdir(CONFIG["bindir"])
-libdir = with_destdir(CONFIG["libdir"])
-rubylibdir = with_destdir(CONFIG["rubylibdir"])
-archlibdir = with_destdir(CONFIG["archdir"])
-sitelibdir = with_destdir(CONFIG["sitelibdir"])
-sitearchlibdir = with_destdir(CONFIG["sitearchdir"])
-mandir = with_destdir(File.join(CONFIG["mandir"], "man"))
+bindir = CONFIG["bindir"]
+libdir = CONFIG["libdir"]
+rubylibdir = CONFIG["rubylibdir"]
+archlibdir = CONFIG["archdir"]
+sitelibdir = CONFIG["sitelibdir"]
+sitearchlibdir = CONFIG["sitearchdir"]
+vendorlibdir = CONFIG["vendorlibdir"]
+vendorarchlibdir = CONFIG["vendorarchdir"]
+mandir = File.join(CONFIG["mandir"], "man")
configure_args = Shellwords.shellwords(CONFIG["configure_args"])
enable_shared = CONFIG["ENABLE_SHARED"] == 'yes'
dll = CONFIG["LIBRUBY_SO"]
lib = CONFIG["LIBRUBY"]
arc = CONFIG["LIBRUBY_A"]
-makedirs [bindir, libdir, rubylibdir, archlibdir, sitelibdir, sitearchlibdir]
+install?(:local, :arch, :bin, :'bin-arch') do
+ puts "installing binary commands"
-install?(:bin) do
- ruby_bin = File.join(bindir, ruby_install_name)
+ makedirs [bindir, libdir, archlibdir]
- install ruby_install_name+exeext, ruby_bin+exeext, :mode => 0755
- if File.exist?(ruby_install_name+exeext+".manifest")
- install ruby_install_name+exeext+".manifest", bindir, :mode => 0644
- end
+ install ruby_install_name+exeext, bindir, :mode => $prog_mode
if rubyw_install_name and !rubyw_install_name.empty?
- install rubyw_install_name+exeext, bindir, :mode => 0755
- if File.exist?(rubyw_install_name+exeext+".manifest")
- install rubyw_install_name+exeext+".manifest", bindir, :mode => 0644
- end
+ install rubyw_install_name+exeext, bindir, :mode => $prog_mode
end
if enable_shared and dll != lib
- install dll, bindir, :mode => 0755
- if File.exist?(dll+".manifest")
- install dll+".manifest", bindir, :mode => 0644
- end
+ install dll, bindir, :mode => $prog_mode
end
- install lib, libdir, :mode => 0755 unless lib == arc
- install arc, libdir, :mode => 0644
- install "config.h", archlibdir, :mode => 0644
- install "rbconfig.rb", archlibdir, :mode => 0644
+ install lib, libdir, :mode => $prog_mode unless lib == arc
+ install arc, libdir, :mode => $data_mode
+ install "config.h", archlibdir, :mode => $data_mode
+ install "rbconfig.rb", archlibdir, :mode => $data_mode
if CONFIG["ARCHFILE"]
for file in CONFIG["ARCHFILE"].split
- install file, archlibdir, :mode => 0644
+ install file, archlibdir, :mode => $data_mode
end
end
@@ -144,101 +251,161 @@ install?(:bin) do
end
end
-Dir.chdir srcdir
+if $extout
+ extout = "#$extout"
+ install?(:ext, :arch, :'ext-arch') do
+ puts "installing extension objects"
+ makedirs [archlibdir, sitearchlibdir, vendorarchlibdir]
+ if noinst = CONFIG["no_install_files"] and noinst.empty?
+ noinst = nil
+ end
+ install_recursive("#{extout}/#{CONFIG['arch']}", archlibdir, :no_install => noinst, :mode => $prog_mode)
+ end
+ install?(:ext, :comm, :'ext-comm') do
+ puts "installing extension scripts"
+ makedirs [rubylibdir, sitelibdir, vendorlibdir]
+ install_recursive("#{extout}/common", rubylibdir, :mode => $data_mode)
+ end
+end
+
+install?(:rdoc) do
+ if $rdocdir
+ puts "installing rdoc"
-install?(:lib) do
-ruby_shebang = File.join(CONFIG["bindir"], ruby_install_name)
-if File::ALT_SEPARATOR
- ruby_bin_dosish = ruby_shebang.tr(File::SEPARATOR, File::ALT_SEPARATOR)
+ ridatadir = File.join(CONFIG['datadir'], 'ri/$(MAJOR).$(MINOR)/system')
+ Config.expand(ridatadir)
+ makedirs [ridatadir]
+ install_recursive($rdocdir, ridatadir, :mode => $data_mode)
+ end
end
-for src in Dir["bin/*"]
- next unless File.file?(src)
- next if /\/[.#]|(\.(old|bak|orig|rej|diff|patch|core)|~|\/core)$/i =~ src
- name = ruby_install_name.sub(/ruby/, File.basename(src))
- dest = File.join(bindir, name)
+install?(:local, :comm, :bin, :'bin-comm') do
+ puts "installing command scripts"
- install src, dest, :mode => 0755
+ Dir.chdir srcdir
+ makedirs [bindir, rubylibdir]
- next if $dryrun
+ ruby_shebang = File.join(bindir, ruby_install_name)
+ if File::ALT_SEPARATOR
+ ruby_bin = ruby_shebang.tr(File::SEPARATOR, File::ALT_SEPARATOR)
+ end
+ for src in Dir["bin/*"]
+ next unless File.file?(src)
+ next if /\/[.#]|(\.(old|bak|orig|rej|diff|patch|core)|~|\/core)$/i =~ src
- shebang = ''
- body = ''
- open(dest, "r+") { |f|
- shebang = f.gets
- body = f.read
+ name = ruby_install_name.sub(/ruby/, File.basename(src))
- if shebang.sub!(/^\#!.*?ruby\b/) {"#!" + ruby_shebang}
- f.rewind
- f.print shebang, body
- f.truncate(f.pos)
+ shebang = ''
+ body = ''
+ open(src, "rb") do |f|
+ shebang = f.gets
+ body = f.read
end
- }
-
- if ruby_bin_dosish
- batfile = File.join(CONFIG["bindir"], name + ".bat")
- open(with_destdir(batfile), "w") { |b|
- b.print <<EOH, shebang, body, <<EOF
+ shebang.sub!(/^\#!.*?ruby\b/) {"#!" + ruby_shebang}
+ shebang.sub!(/\r$/, '')
+ body.gsub!(/\r$/, '')
+
+ cmd = File.join(bindir, name)
+ cmd << ".#{$cmdtype}" if $cmdtype
+ open_for_install(cmd, $script_mode) do
+ case $cmdtype
+ when "bat"
+ "#{<<EOH}#{shebang}#{body}#{<<EOF}".gsub(/$/, "\r")
@echo off
-if not "%~d0" == "~d0" goto WinNT
-#{ruby_bin_dosish} -x "#{batfile}" %1 %2 %3 %4 %5 %6 %7 %8 %9
-goto endofruby
+@if not "%~d0" == "~d0" goto WinNT
+#{ruby_bin} -x "#{cmd}" %1 %2 %3 %4 %5 %6 %7 %8 %9
+@goto endofruby
:WinNT
"%~dp0#{ruby_install_name}" -x "%~f0" %*
-goto endofruby
+@goto endofruby
EOH
__END__
:endofruby
EOF
- }
+ when "cmd"
+ "#{<<EOH}#{shebang}#{body}"
+@"%~dp0#{ruby_install_name}" -x "%~f0" %*
+@exit /b %ERRORLEVEL%
+EOH
+ else
+ shebang + body
+ end
+ end
end
end
-for f in Dir["lib/**/*{.rb,help-message}"]
- dir = File.dirname(f).sub!(/\Alib/, rubylibdir) || rubylibdir
- makedirs dir
- install f, dir, :mode => 0644
-end
-end
+install?(:local, :comm, :lib) do
+ puts "installing library scripts"
-install?(:bin) do
-for f in Dir["*.h"]
- install f, archlibdir, :mode => 0644
-end
+ Dir.chdir srcdir
+ makedirs [rubylibdir]
-if RUBY_PLATFORM =~ /mswin32|mingw|bccwin32/
- makedirs File.join(archlibdir, "win32")
- install "win32/win32.h", File.join(archlibdir, "win32"), :mode => 0644
+ for f in Dir["lib/**/*{.rb,help-message}"]
+ dir = File.dirname(f).sub!(/\Alib/, rubylibdir) || rubylibdir
+ makedirs dir
+ install f, dir, :mode => $data_mode
+ end
end
+
+install?(:local, :arch, :lib) do
+ puts "installing headers"
+
+ Dir.chdir(srcdir)
+ makedirs [archlibdir]
+ for f in Dir["*.h"]
+ install f, archlibdir, :mode => $data_mode
+ end
+
+ if RUBY_PLATFORM =~ /mswin32|mingw|bccwin32/
+ win32libdir = File.join(archlibdir, "win32")
+ makedirs win32libdir
+ install "win32/win32.h", win32libdir, :mode => $data_mode
+ end
end
-install?(:man) do
-for mdoc in Dir["*.[1-9]"]
- next unless File.file?(mdoc) and open(mdoc){|fh| fh.read(1) == '.'}
+install?(:local, :comm, :man) do
+ puts "installing manpages"
- section = mdoc[-1,1]
+ Dir.chdir(srcdir)
+ for mdoc in Dir["*.[1-9]"]
+ next unless File.file?(mdoc) and open(mdoc){|fh| fh.read(1) == '.'}
- destdir = mandir + section
- destfile = File.join(destdir, mdoc.sub(/ruby/, ruby_install_name))
+ destdir = mandir + mdoc[/(\d+)$/]
+ destfile = File.join(destdir, mdoc.sub(/ruby/, ruby_install_name))
- makedirs destdir
+ makedirs destdir
- if $mantype == "doc"
- install mdoc, destfile, :mode => 0644
- else
- require 'mdoc2man.rb'
+ if $mantype == "doc"
+ install mdoc, destfile, :mode => $data_mode
+ else
+ require 'mdoc2man.rb'
- w = Tempfile.open(mdoc)
+ w = Tempfile.open(mdoc)
- open(mdoc) { |r|
- Mdoc2Man.mdoc2man(r, w)
- }
+ open(mdoc) { |r|
+ Mdoc2Man.mdoc2man(r, w)
+ }
- w.close
+ w.close
- install w.path, destfile, :mode => 0644
+ install w.path, destfile, :mode => $data_mode
+ end
end
end
+
+$install << :local << :ext if $install.empty?
+$install.each do |inst|
+ if !(procs = $install_procs[inst]) || procs.empty?
+ next warn("unknown install target - #{inst}")
+ end
+ procs.each do |block|
+ dir = Dir.pwd
+ begin
+ block.call
+ ensure
+ Dir.chdir(dir)
+ end
+ end
end
# vi:set sw=2:
diff --git a/intern.h b/intern.h
index 072997503a..950ae9dad0 100644
--- a/intern.h
+++ b/intern.h
@@ -2,8 +2,8 @@
intern.h -
- $Author: matz $
- $Date: 2006/05/16 00:25:18 $
+ $Author$
+ $Date$
created at: Thu Jun 10 14:22:17 JST 1993
Copyright (C) 1993-2003 Yukihiro Matsumoto
@@ -70,6 +70,7 @@ VALUE rb_str_to_inum _((VALUE, int, int));
VALUE rb_cstr2inum _((const char*, int));
VALUE rb_str2inum _((VALUE, int));
VALUE rb_big2str _((VALUE, int));
+VALUE rb_big2str0 _((VALUE, int, int));
long rb_big2long _((VALUE));
#define rb_big2int(x) rb_big2long(x)
unsigned long rb_big2ulong _((VALUE));
@@ -82,6 +83,8 @@ unsigned LONG_LONG rb_big2ull _((VALUE));
#endif /* HAVE_LONG_LONG */
void rb_quad_pack _((char*,VALUE));
VALUE rb_quad_unpack _((const char*,int));
+void rb_big_pack(VALUE val, unsigned long *buf, long num_longs);
+VALUE rb_big_unpack(unsigned long *buf, long num_longs);
VALUE rb_dbl2big _((double));
double rb_big2dbl _((VALUE));
VALUE rb_big_plus _((VALUE, VALUE));
@@ -127,6 +130,14 @@ VALUE rb_singleton_class _((VALUE));
int rb_cmpint _((VALUE, VALUE, VALUE));
NORETURN(void rb_cmperr _((VALUE, VALUE)));
/* enum.c */
+VALUE rb_block_call _((VALUE, ID, int, VALUE*, VALUE (*)(ANYARGS), VALUE));
+/* enumerator.c */
+VALUE rb_enumeratorize _((VALUE, VALUE, int, VALUE *));
+#define RETURN_ENUMERATOR(obj, argc, argv) do { \
+ if (!rb_block_given_p()) \
+ return rb_enumeratorize(obj, ID2SYM(rb_frame_this_func()), \
+ argc, argv); \
+ } while (0)
/* error.c */
RUBY_EXTERN int ruby_nerrs;
VALUE rb_exc_new _((VALUE, const char*, long));
@@ -171,6 +182,7 @@ void rb_interrupt _((void));
VALUE rb_apply _((VALUE, ID, VALUE));
void rb_backtrace _((void));
ID rb_frame_last_func _((void));
+ID rb_frame_this_func _((void));
VALUE rb_obj_instance_eval _((int, VALUE*, VALUE));
VALUE rb_mod_module_eval _((int, VALUE*, VALUE));
void rb_load _((VALUE, int));
@@ -183,8 +195,11 @@ VALUE rb_require_safe _((VALUE, int));
void rb_obj_call_init _((VALUE, int, VALUE*));
VALUE rb_class_new_instance _((int, VALUE*, VALUE));
VALUE rb_block_proc _((void));
+VALUE rb_block_dup _((VALUE, VALUE, VALUE));
+VALUE rb_method_dup _((VALUE, VALUE, VALUE));
VALUE rb_f_lambda _((void));
-VALUE rb_proc_new _((VALUE (*)(ANYARGS/* VALUE yieldarg[, VALUE procarg] */), VALUE));
+VALUE rb_proc_call _((VALUE, VALUE));
+VALUE rb_obj_method _((VALUE, VALUE));
VALUE rb_protect _((VALUE (*)(VALUE), VALUE, int*));
void rb_set_end_proc _((void (*)(VALUE), VALUE));
void rb_mark_end_proc _((void));
@@ -206,12 +221,14 @@ void rb_thread_sleep _((int));
void rb_thread_sleep_forever _((void));
VALUE rb_thread_stop _((void));
VALUE rb_thread_wakeup _((VALUE));
+VALUE rb_thread_wakeup_alive _((VALUE));
VALUE rb_thread_run _((VALUE));
VALUE rb_thread_kill _((VALUE));
+VALUE rb_thread_alive_p _((VALUE));
VALUE rb_thread_create _((VALUE (*)(ANYARGS), void*));
void rb_thread_interrupt _((void));
void rb_thread_trap_eval _((VALUE, int, int));
-void rb_thread_signal_raise _((char*));
+void rb_thread_signal_raise _((int));
void rb_thread_signal_exit _((void));
int rb_thread_select _((int, fd_set *, fd_set *, fd_set *, struct timeval *));
void rb_thread_wait_for _((struct timeval));
@@ -220,6 +237,7 @@ VALUE rb_thread_main _((void));
VALUE rb_thread_local_aref _((VALUE, ID));
VALUE rb_thread_local_aset _((VALUE, ID, VALUE));
void rb_thread_atfork _((void));
+VALUE rb_exec_recursive _((VALUE(*)(VALUE, VALUE, int),VALUE,VALUE));
VALUE rb_funcall_rescue __((VALUE, ID, int, ...));
/* file.c */
VALUE rb_file_s_expand_path _((int, VALUE *));
@@ -231,13 +249,16 @@ char *rb_path_next _((const char *));
char *rb_path_skip_prefix _((const char *));
char *rb_path_last_separator _((const char *));
char *rb_path_end _((const char *));
+VALUE rb_file_directory_p _((VALUE,VALUE));
/* gc.c */
NORETURN(void rb_memerror __((void)));
int ruby_stack_check _((void));
-int ruby_stack_length _((VALUE**));
+size_t ruby_stack_length _((VALUE**));
+int rb_during_gc _((void));
char *rb_source_filename _((const char*));
void rb_gc_mark_locations _((VALUE*, VALUE*));
void rb_mark_tbl _((struct st_table*));
+void rb_mark_set _((struct st_table*));
void rb_mark_hash _((struct st_table*));
void rb_gc_mark_maybe _((VALUE));
void rb_gc_mark _((VALUE));
@@ -256,10 +277,11 @@ VALUE rb_hash _((VALUE));
VALUE rb_hash_new _((void));
VALUE rb_hash_freeze _((VALUE));
VALUE rb_hash_aref _((VALUE, VALUE));
+VALUE rb_hash_lookup _((VALUE, VALUE));
VALUE rb_hash_aset _((VALUE, VALUE, VALUE));
VALUE rb_hash_delete_if _((VALUE));
VALUE rb_hash_delete _((VALUE,VALUE));
-int rb_path_check _((char*));
+int rb_path_check _((const char*));
int rb_env_path_tainted _((void));
/* io.c */
#define rb_defout rb_stdout
@@ -315,6 +337,7 @@ VALUE rb_class_real _((VALUE));
VALUE rb_class_inherited_p _((VALUE, VALUE));
VALUE rb_convert_type _((VALUE,int,const char*,const char*));
VALUE rb_check_convert_type _((VALUE,int,const char*,const char*));
+VALUE rb_check_to_integer _((VALUE, const char *));
VALUE rb_to_int _((VALUE));
VALUE rb_Integer _((VALUE));
VALUE rb_Float _((VALUE));
@@ -337,6 +360,7 @@ int rb_is_class_id _((ID));
int rb_is_local_id _((ID));
int rb_is_junk_id _((ID));
int rb_symname_p _((const char*));
+int rb_sym_interned_p _((VALUE));
VALUE rb_backref_get _((void));
void rb_backref_set _((VALUE));
VALUE rb_lastline_get _((void));
@@ -353,6 +377,10 @@ VALUE rb_detach_process _((int));
VALUE rb_range_new _((VALUE, VALUE, int));
VALUE rb_range_beg_len _((VALUE, long*, long*, long, int));
VALUE rb_length_by_each _((VALUE));
+/* random.c */
+unsigned long rb_genrand_int32(void);
+double rb_genrand_real(void);
+void rb_reset_random_seed(void);
/* re.c */
int rb_memcmp _((const void*,const void*,long));
int rb_memcicmp _((const void*,const void*,long));
@@ -369,6 +397,8 @@ VALUE rb_reg_match2 _((VALUE));
int rb_reg_options _((VALUE));
void rb_set_kcode _((const char*));
const char* rb_get_kcode _((void));
+void rb_kcode_set_option _((VALUE));
+void rb_kcode_reset_option _((void));
/* ruby.c */
RUBY_EXTERN VALUE rb_argv;
RUBY_EXTERN VALUE rb_argv0;
@@ -390,8 +420,10 @@ void posix_signal _((int, RETSIGTYPE (*)(int)));
void rb_trap_exit _((void));
void rb_trap_exec _((void));
const char *ruby_signal_name _((int));
+void ruby_default_signal _((int));
/* sprintf.c */
VALUE rb_f_sprintf _((int, VALUE*));
+VALUE rb_str_format _((int, VALUE*, VALUE));
/* string.c */
VALUE rb_str_new _((const char*, long));
VALUE rb_str_new2 _((const char*));
@@ -402,6 +434,7 @@ VALUE rb_tainted_str_new _((const char*, long));
VALUE rb_tainted_str_new2 _((const char*));
VALUE rb_str_buf_new _((long));
VALUE rb_str_buf_new2 _((const char*));
+VALUE rb_str_tmp_new _((long));
VALUE rb_str_buf_append _((VALUE, VALUE));
VALUE rb_str_buf_cat _((VALUE, const char*, long));
VALUE rb_str_buf_cat2 _((VALUE, const char*));
@@ -416,6 +449,7 @@ VALUE rb_str_times _((VALUE, VALUE));
VALUE rb_str_substr _((VALUE, long, long));
void rb_str_modify _((VALUE));
VALUE rb_str_freeze _((VALUE));
+void rb_str_set_len _((VALUE, long));
VALUE rb_str_resize _((VALUE, long));
VALUE rb_str_cat _((VALUE, const char*, long));
VALUE rb_str_cat2 _((VALUE, const char*));
@@ -439,7 +473,7 @@ VALUE rb_struct_alloc _((VALUE, VALUE));
VALUE rb_struct_aref _((VALUE, VALUE));
VALUE rb_struct_aset _((VALUE, VALUE, VALUE));
VALUE rb_struct_getmember _((VALUE, ID));
-VALUE rb_struct_iv_get _((VALUE, char*));
+VALUE rb_struct_iv_get _((VALUE, const char*));
VALUE rb_struct_s_members _((VALUE));
VALUE rb_struct_members _((VALUE));
/* time.c */
diff --git a/io.c b/io.c
index 09fd3d0433..00a1820d88 100644
--- a/io.c
+++ b/io.c
@@ -2,8 +2,8 @@
io.c -
- $Author: matz $
- $Date: 2006/07/31 06:34:09 $
+ $Author$
+ $Date$
created at: Fri Oct 15 18:08:59 JST 1993
Copyright (C) 1993-2003 Yukihiro Matsumoto
@@ -21,6 +21,7 @@
#include "rubyio.h"
#include "rubysig.h"
#include "env.h"
+#include "re.h"
#include <ctype.h>
#include <errno.h>
@@ -36,6 +37,14 @@
# define USE_SETVBUF
#endif
+#ifndef BSD_STDIO
+# if defined(__MACH__) || defined(__DARWIN__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
+# define BSD_STDIO 1
+# else
+# define BSD_STDIO 0
+# endif
+#endif
+
#ifdef __QNXNTO__
#include "unix.h"
#endif
@@ -49,6 +58,9 @@
#elif defined(HAVE_SYS_FCNTL_H)
#include <sys/fcntl.h>
#endif
+#ifdef __CYGWIN__
+#include <io.h>
+#endif
#if !HAVE_OFF_T && !defined(off_t)
# define off_t long
@@ -108,6 +120,9 @@ extern void Init_File _((void));
# endif
#endif
+#define preserving_errno(stmts) \
+ do {int saved_errno = errno; stmts; errno = saved_errno;} while (0)
+
VALUE rb_cIO;
VALUE rb_eEOFError;
VALUE rb_eIOError;
@@ -219,7 +234,7 @@ rb_io_taint_check(io)
void
rb_io_check_initialized(fptr)
- OpenFile *fptr;
+ rb_io_t *fptr;
{
if (!fptr) {
rb_raise(rb_eIOError, "uninitialized stream");
@@ -228,7 +243,7 @@ rb_io_check_initialized(fptr)
void
rb_io_check_closed(fptr)
- OpenFile *fptr;
+ rb_io_t *fptr;
{
rb_io_check_initialized(fptr);
if (!fptr->f && !fptr->f2) {
@@ -236,15 +251,16 @@ rb_io_check_closed(fptr)
}
}
-static void io_fflush _((FILE *, OpenFile *));
+static void io_fflush _((FILE *, rb_io_t *));
-static OpenFile *
+static rb_io_t *
flush_before_seek(fptr)
- OpenFile *fptr;
+ rb_io_t *fptr;
{
if (fptr->mode & FMODE_WBUF) {
io_fflush(GetWriteFile(fptr), fptr);
}
+ errno = 0;
return fptr;
}
@@ -261,7 +277,7 @@ flush_before_seek(fptr)
void
rb_io_check_readable(fptr)
- OpenFile *fptr;
+ rb_io_t *fptr;
{
rb_io_check_closed(fptr);
if (!(fptr->mode & FMODE_READABLE)) {
@@ -280,7 +296,7 @@ rb_io_check_readable(fptr)
void
rb_io_check_writable(fptr)
- OpenFile *fptr;
+ rb_io_t *fptr;
{
rb_io_check_closed(fptr);
if (!(fptr->mode & FMODE_WRITABLE)) {
@@ -318,7 +334,7 @@ ruby_dup(orig)
fd = dup(orig);
if (fd < 0) {
- if (errno == EMFILE || errno == ENFILE) {
+ if (errno == EMFILE || errno == ENFILE || errno == ENOMEM) {
rb_gc();
fd = dup(orig);
}
@@ -345,7 +361,7 @@ io_alloc(klass)
static void
io_fflush(f, fptr)
FILE *f;
- OpenFile *fptr;
+ rb_io_t *fptr;
{
int n;
@@ -424,10 +440,13 @@ rb_io_wait_writable(f)
#endif
static int
-wsplit_p(OpenFile *fptr)
+wsplit_p(rb_io_t *fptr)
{
FILE *f = GetWriteFile(fptr);
+#if defined(HAVE_FCNTL) && defined(F_GETFL) && defined(O_NONBLOCK)
int r;
+#endif
+
if (!(fptr->mode & FMODE_WSPLIT_INITIALIZED)) {
struct stat buf;
if (fstat(fileno(f), &buf) == 0 &&
@@ -448,7 +467,7 @@ wsplit_p(OpenFile *fptr)
static long
io_fwrite(str, fptr)
VALUE str;
- OpenFile *fptr;
+ rb_io_t *fptr;
{
long len, n, r, l, offset = 0;
FILE *f = GetWriteFile(fptr);
@@ -471,6 +490,9 @@ io_fwrite(str, fptr)
TRAP_BEG;
r = write(fileno(f), RSTRING(str)->ptr+offset, l);
TRAP_END;
+#if BSD_STDIO
+ preserving_errno(fseeko(f, lseek(fileno(f), (off_t)0, SEEK_CUR), SEEK_SET));
+#endif
if (r == n) return len;
if (0 <= r) {
offset += r;
@@ -528,7 +550,7 @@ rb_io_fwrite(ptr, len, f)
long len;
FILE *f;
{
- OpenFile of;
+ rb_io_t of;
of.f = f;
of.f2 = NULL;
@@ -559,7 +581,7 @@ static VALUE
io_write(io, str)
VALUE io, str;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
long n;
rb_secure(4);
@@ -634,7 +656,7 @@ static VALUE
rb_io_flush(io)
VALUE io;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
FILE *f;
GetOpenFile(io, fptr);
@@ -642,6 +664,9 @@ rb_io_flush(io)
f = GetWriteFile(fptr);
io_fflush(f, fptr);
+#ifdef _WIN32
+ fsync(fileno(f));
+#endif
return io;
}
@@ -663,12 +688,12 @@ static VALUE
rb_io_tell(io)
VALUE io;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
off_t pos;
GetOpenFile(io, fptr);
pos = io_tell(fptr);
- if (pos < 0) rb_sys_fail(fptr->path);
+ if (pos < 0 && errno) rb_sys_fail(fptr->path);
return OFFT2NUM(pos);
}
@@ -677,13 +702,13 @@ rb_io_seek(io, offset, whence)
VALUE io, offset;
int whence;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
off_t pos;
pos = NUM2OFFT(offset);
GetOpenFile(io, fptr);
pos = io_seek(fptr, pos, whence);
- if (pos < 0) rb_sys_fail(fptr->path);
+ if (pos < 0 && errno) rb_sys_fail(fptr->path);
clearerr(fptr->f);
return INT2FIX(0);
@@ -741,7 +766,7 @@ static VALUE
rb_io_set_pos(io, offset)
VALUE io, offset;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
off_t pos;
pos = NUM2OFFT(offset);
@@ -771,7 +796,7 @@ static VALUE
rb_io_rewind(io)
VALUE io;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
GetOpenFile(io, fptr);
if (io_seek(fptr, 0L, 0) != 0) rb_sys_fail(fptr->path);
@@ -820,7 +845,7 @@ VALUE
rb_io_eof(io)
VALUE io;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
int ch;
GetOpenFile(io, fptr);
@@ -860,7 +885,7 @@ static VALUE
rb_io_sync(io)
VALUE io;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
GetOpenFile(io, fptr);
return (fptr->mode & FMODE_SYNC) ? Qtrue : Qfalse;
@@ -885,7 +910,7 @@ static VALUE
rb_io_set_sync(io, mode)
VALUE io, mode;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
GetOpenFile(io, fptr);
if (RTEST(mode)) {
@@ -914,7 +939,7 @@ rb_io_fsync(io)
VALUE io;
{
#ifdef HAVE_FSYNC
- OpenFile *fptr;
+ rb_io_t *fptr;
FILE *f;
GetOpenFile(io, fptr);
@@ -946,7 +971,7 @@ static VALUE
rb_io_fileno(io)
VALUE io;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
int fd;
GetOpenFile(io, fptr);
@@ -978,7 +1003,7 @@ static VALUE
rb_io_pid(io)
VALUE io;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
GetOpenFile(io, fptr);
if (!fptr->pid)
@@ -997,8 +1022,9 @@ static VALUE
rb_io_inspect(obj)
VALUE obj;
{
- OpenFile *fptr;
- char *buf, *cname, *st = "";
+ rb_io_t *fptr;
+ char *buf;
+ const char *cname, *st = "";
long len;
fptr = RFILE(rb_io_taint_check(obj))->fptr;
@@ -1052,11 +1078,11 @@ read_buffered_data(ptr, len, f)
#endif
}
-long
+static long
io_fread(ptr, len, fptr)
char *ptr;
long len;
- OpenFile *fptr;
+ rb_io_t *fptr;
{
long n = len;
int c;
@@ -1112,7 +1138,7 @@ rb_io_fread(ptr, len, f)
long len;
FILE *f;
{
- OpenFile of;
+ rb_io_t of;
of.f = f;
of.f2 = NULL;
@@ -1123,7 +1149,7 @@ rb_io_fread(ptr, len, f)
static long
remain_size(fptr)
- OpenFile *fptr;
+ rb_io_t *fptr;
{
struct stat st;
off_t siz = BUFSIZ;
@@ -1149,7 +1175,7 @@ remain_size(fptr)
static VALUE
read_all(fptr, siz, str)
- OpenFile *fptr;
+ rb_io_t *fptr;
long siz;
VALUE str;
{
@@ -1185,7 +1211,7 @@ read_all(fptr, siz, str)
return str;
}
-void rb_io_set_nonblock(OpenFile *fptr)
+void rb_io_set_nonblock(rb_io_t *fptr)
{
int flags;
#ifdef F_GETFL
@@ -1223,7 +1249,7 @@ void rb_io_set_nonblock(OpenFile *fptr)
static VALUE
io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock)
{
- OpenFile *fptr;
+ rb_io_t *fptr;
VALUE length, str;
long n, len;
@@ -1274,6 +1300,8 @@ io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock)
goto again;
rb_sys_fail(fptr->path);
}
+ if (fptr->f) /* update pos in FILE structure [ruby-core:21561] */
+ fflush(fptr->f);
}
rb_str_resize(str, n);
@@ -1406,7 +1434,7 @@ io_read_nonblock(int argc, VALUE *argv, VALUE io)
static VALUE
rb_io_write_nonblock(VALUE io, VALUE str)
{
- OpenFile *fptr;
+ rb_io_t *fptr;
FILE *f;
long n;
@@ -1453,7 +1481,7 @@ io_read(argc, argv, io)
VALUE *argv;
VALUE io;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
long n, len;
VALUE length, str;
@@ -1509,7 +1537,7 @@ io_read(argc, argv, io)
static int
appendline(fptr, delim, strp)
- OpenFile *fptr;
+ rb_io_t *fptr;
int delim;
VALUE *strp;
{
@@ -1614,7 +1642,7 @@ appendline(fptr, delim, strp)
static inline int
swallow(fptr, term)
- OpenFile *fptr;
+ rb_io_t *fptr;
int term;
{
FILE *f = fptr->f;
@@ -1653,7 +1681,7 @@ swallow(fptr, term)
static VALUE
rb_io_getline_fast(fptr, delim)
- OpenFile *fptr;
+ rb_io_t *fptr;
unsigned char delim;
{
VALUE str = Qnil;
@@ -1672,7 +1700,7 @@ rb_io_getline_fast(fptr, delim)
static int
rscheck(rsptr, rslen, rs)
- char *rsptr;
+ const char *rsptr;
long rslen;
VALUE rs;
{
@@ -1688,7 +1716,7 @@ rb_io_getline(rs, io)
VALUE rs, io;
{
VALUE str = Qnil;
- OpenFile *fptr;
+ rb_io_t *fptr;
GetOpenFile(io, fptr);
rb_io_check_readable(fptr);
@@ -1701,7 +1729,7 @@ rb_io_getline(rs, io)
}
else {
int c, newline;
- char *rsptr;
+ const char *rsptr;
long rslen;
int rspara = 0;
@@ -1722,7 +1750,7 @@ rb_io_getline(rs, io)
while ((c = appendline(fptr, newline, &str)) != EOF &&
(c != newline || RSTRING(str)->len < rslen ||
- (rspara || rscheck(rsptr,rslen,rs), 0) ||
+ ((rspara || rscheck(rsptr,rslen,rs)) && 0) ||
memcmp(RSTRING(str)->ptr+RSTRING(str)->len-rslen,rsptr,rslen)));
if (rspara) {
@@ -1745,7 +1773,7 @@ VALUE
rb_io_gets(io)
VALUE io;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
GetOpenFile(io, fptr);
rb_io_check_readable(fptr);
@@ -1813,7 +1841,7 @@ static VALUE
rb_io_lineno(io)
VALUE io;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
GetOpenFile(io, fptr);
rb_io_check_readable(fptr);
@@ -1841,7 +1869,7 @@ static VALUE
rb_io_set_lineno(io, lineno)
VALUE io, lineno;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
GetOpenFile(io, fptr);
rb_io_check_readable(fptr);
@@ -1963,6 +1991,7 @@ rb_io_each_line(argc, argv, io)
VALUE str;
VALUE rs;
+ RETURN_ENUMERATOR(io, argc, argv);
if (argc == 0) {
rs = rb_rs;
}
@@ -1978,7 +2007,7 @@ rb_io_each_line(argc, argv, io)
/*
* call-seq:
- * ios.each_byte {|byte| block } => nil
+ * ios.each_byte {|byte| block } => ios
*
* Calls the given block once for each byte (0..255) in <em>ios</em>,
* passing the byte as an argument. The stream must be opened for
@@ -1994,10 +2023,11 @@ static VALUE
rb_io_each_byte(io)
VALUE io;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
FILE *f;
int c;
+ RETURN_ENUMERATOR(io, 0, 0);
GetOpenFile(io, fptr);
for (;;) {
@@ -2023,6 +2053,97 @@ rb_io_each_byte(io)
return io;
}
+VALUE rb_io_getc _((VALUE));
+
+/*
+ * call-seq:
+ * ios.each_char {|c| block } => ios
+ *
+ * Calls the given block once for each character in <em>ios</em>,
+ * passing the character as an argument. The stream must be opened for
+ * reading or an <code>IOError</code> will be raised. Multibyte
+ * characters are dealt with according to $KCODE.
+ *
+ * f = File.new("testfile")
+ * f.each_char {|c| print c, ' ' } #=> #<File:testfile>
+ */
+
+static VALUE
+rb_io_each_char(io)
+ VALUE io;
+{
+ VALUE ch;
+
+ RETURN_ENUMERATOR(io, 0, 0);
+
+ while (!NIL_P(ch = rb_io_getc(io))) {
+ unsigned char c;
+ int n;
+ VALUE str;
+
+ c= FIX2INT(ch);
+ n = mbclen(c);
+ str = rb_tainted_str_new((const char *)&c, 1);
+
+ while (--n > 0) {
+ if (NIL_P(ch = rb_io_getc(io))) {
+ rb_yield(str);
+ return io;
+ }
+ c = FIX2INT(ch);
+ rb_str_cat(str, (const char *)&c, 1);
+ }
+ rb_yield(str);
+ }
+ return io;
+}
+
+/*
+ * call-seq:
+ * ios.lines(sep=$/) => anEnumerator
+ * ios.lines(limit) => anEnumerator
+ * ios.lines(sep, limit) => anEnumerator
+ *
+ * Returns an enumerator that gives each line in <em>ios</em>.
+ * The stream must be opened for reading or an <code>IOError</code>
+ * will be raised.
+ *
+ * f = File.new("testfile")
+ * f.lines.to_a #=> ["foo\n", "bar\n"]
+ * f.rewind
+ * f.lines.sort #=> ["bar\n", "foo\n"]
+ */
+
+static VALUE
+rb_io_lines(argc, argv, io)
+ int argc;
+ VALUE *argv;
+ VALUE io;
+{
+ return rb_enumeratorize(io, ID2SYM(rb_intern("each_line")), argc, argv);
+}
+
+/*
+ * call-seq:
+ * ios.bytes => anEnumerator
+ *
+ * Returns an enumerator that gives each byte (0..255) in <em>ios</em>.
+ * The stream must be opened for reading or an <code>IOError</code>
+ * will be raised.
+ *
+ * f = File.new("testfile")
+ * f.bytes.to_a #=> [104, 101, 108, 108, 111]
+ * f.rewind
+ * f.bytes.sort #=> [101, 104, 108, 108, 111]
+ */
+
+static VALUE
+rb_io_bytes(io)
+ VALUE io;
+{
+ return rb_enumeratorize(io, ID2SYM(rb_intern("each_byte")), 0, 0);
+}
+
/*
* call-seq:
* ios.getc => fixnum or nil
@@ -2039,7 +2160,7 @@ VALUE
rb_io_getc(io)
VALUE io;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
FILE *f;
int c;
@@ -2123,7 +2244,7 @@ VALUE
rb_io_ungetc(io, c)
VALUE io, c;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
int cc = NUM2INT(c);
GetOpenFile(io, fptr);
@@ -2153,7 +2274,7 @@ static VALUE
rb_io_isatty(io)
VALUE io;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
GetOpenFile(io, fptr);
if (isatty(fileno(fptr->f)) == 0)
@@ -2163,11 +2284,12 @@ rb_io_isatty(io)
static void
fptr_finalize(fptr, noraise)
- OpenFile *fptr;
+ rb_io_t *fptr;
int noraise;
{
int n1 = 0, n2 = 0, f1, f2 = -1;
+ errno = 0;
if (fptr->f2) {
f2 = fileno(fptr->f2);
while (n2 = 0, fflush(fptr->f2) < 0) {
@@ -2207,7 +2329,7 @@ fptr_finalize(fptr, noraise)
static void
rb_io_fptr_cleanup(fptr, noraise)
- OpenFile *fptr;
+ rb_io_t *fptr;
int noraise;
{
if (fptr->finalize) {
@@ -2220,23 +2342,23 @@ rb_io_fptr_cleanup(fptr, noraise)
void
rb_io_fptr_finalize(fptr)
- OpenFile *fptr;
+ rb_io_t *fptr;
{
if (!fptr) return;
if (fptr->path) {
free(fptr->path);
}
- if (!fptr->f && !fptr->f2) return;
- if (fileno(fptr->f) < 3) return;
-
- rb_io_fptr_cleanup(fptr, Qtrue);
+ if ((fptr->f && fileno(fptr->f) > 2) || fptr->f2) {
+ rb_io_fptr_cleanup(fptr, Qtrue);
+ }
+ xfree(fptr);
}
VALUE
rb_io_close(io)
VALUE io;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
int fd, fd2;
fptr = RFILE(io)->fptr;
@@ -2324,7 +2446,7 @@ static VALUE
rb_io_closed(io)
VALUE io;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
fptr = RFILE(io)->fptr;
rb_io_check_initialized(fptr);
@@ -2353,7 +2475,7 @@ static VALUE
rb_io_close_read(io)
VALUE io;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
int n;
if (rb_safe_level() >= 4 && !OBJ_TAINTED(io)) {
@@ -2398,7 +2520,7 @@ static VALUE
rb_io_close_write(io)
VALUE io;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
int n;
if (rb_safe_level() >= 4 && !OBJ_TAINTED(io)) {
@@ -2440,7 +2562,7 @@ rb_io_sysseek(argc, argv, io)
{
VALUE offset, ptrname;
int whence = SEEK_SET;
- OpenFile *fptr;
+ rb_io_t *fptr;
off_t pos;
if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
@@ -2478,7 +2600,7 @@ static VALUE
rb_io_syswrite(io, str)
VALUE io, str;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
FILE *f;
long n;
@@ -2526,7 +2648,7 @@ rb_io_sysread(argc, argv, io)
VALUE io;
{
VALUE len, str;
- OpenFile *fptr;
+ rb_io_t *fptr;
long n, ilen;
rb_scan_args(argc, argv, "11", &len, &str);
@@ -2588,11 +2710,11 @@ VALUE
rb_io_binmode(io)
VALUE io;
{
-#if defined(_WIN32) || defined(DJGPP) || defined(__CYGWIN__) || defined(__human68k__) || defined(__EMX__)
- OpenFile *fptr;
+ rb_io_t *fptr;
GetOpenFile(io, fptr);
-#ifdef __human68k__
+#if (defined(O_BINARY) && O_BINARY) || (defined(_IOBIN) && _IOBIN)
+#if (defined(_IOBIN) && _IOBIN) /* __human68k__ */
if (fptr->f)
fmode(fptr->f, _IOBIN);
if (fptr->f2)
@@ -2609,7 +2731,7 @@ rb_io_binmode(io)
return io;
}
-char*
+const char*
rb_io_flags_mode(flags)
int flags;
{
@@ -2669,11 +2791,16 @@ rb_io_mode_flags(mode)
case '+':
flags |= FMODE_READWRITE;
break;
+ case ':':
+ /* forward compatibility */
+ rb_warning("encoding options not supported in 1.8: %s", mode);
+ goto end;
default:
goto error;
}
}
+ end:
return flags;
}
@@ -2742,17 +2869,22 @@ rb_io_mode_modenum(mode)
case '+':
flags = (flags & ~O_ACCMODE) | O_RDWR;
break;
+ case ':':
+ /* forward compatibility */
+ rb_warning("encoding options not supported in 1.8: %s", mode);
+ goto end;
default:
goto error;
}
}
+ end:
return flags;
}
#define MODENUM_MAX 4
-static char*
+static const char*
rb_io_modenum_mode(flags)
int flags;
{
@@ -2761,13 +2893,16 @@ rb_io_modenum_mode(flags)
#else
# define MODE_BINARY(a,b) (a)
#endif
+ int accmode = flags & O_ACCMODE;
if (flags & O_APPEND) {
- if ((flags & O_RDWR) == O_RDWR) {
+ if (accmode == O_WRONLY) {
+ return MODE_BINARY("a", "ab");
+ }
+ if (accmode == O_RDWR) {
return MODE_BINARY("a+", "ab+");
}
- return MODE_BINARY("a", "ab");
}
- switch (flags & (O_RDONLY|O_WRONLY|O_RDWR)) {
+ switch (accmode) {
case O_RDONLY:
return MODE_BINARY("r", "rb");
case O_WRONLY:
@@ -2787,10 +2922,16 @@ rb_sysopen(fname, flags, mode)
{
int fd;
+#ifdef _WIN32
+ errno = EINVAL;
+#endif
fd = open(fname, flags, mode);
if (fd < 0) {
if (errno == EMFILE || errno == ENFILE) {
rb_gc();
+#ifdef _WIN32
+ errno = EINVAL;
+#endif
fd = open(fname, flags, mode);
}
if (fd < 0) {
@@ -2873,7 +3014,7 @@ rb_file_open_internal(io, fname, mode)
VALUE io;
const char *fname, *mode;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
MakeOpenFile(io, fptr);
@@ -2897,9 +3038,9 @@ rb_file_sysopen_internal(io, fname, flags, mode)
char *fname;
int flags, mode;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
int fd;
- char *m;
+ const char *m;
MakeOpenFile(io, fptr);
@@ -2922,13 +3063,13 @@ rb_file_sysopen(fname, flags, mode)
#if defined (_WIN32) || defined(DJGPP) || defined(__CYGWIN__) || defined(__human68k__) || defined(__VMS)
static struct pipe_list {
- OpenFile *fptr;
+ rb_io_t *fptr;
struct pipe_list *next;
} *pipe_list;
static void
pipe_add_fptr(fptr)
- OpenFile *fptr;
+ rb_io_t *fptr;
{
struct pipe_list *list;
@@ -2940,7 +3081,7 @@ pipe_add_fptr(fptr)
static void
pipe_del_fptr(fptr)
- OpenFile *fptr;
+ rb_io_t *fptr;
{
struct pipe_list *list = pipe_list;
struct pipe_list *tmp;
@@ -2975,11 +3116,11 @@ pipe_atexit _((void))
}
}
-static void pipe_finalize _((OpenFile *fptr,int));
+static void pipe_finalize _((rb_io_t *fptr,int));
static void
pipe_finalize(fptr, noraise)
- OpenFile *fptr;
+ rb_io_t *fptr;
int noraise;
{
#if !defined (__CYGWIN__) && !defined(_WIN32)
@@ -3005,27 +3146,27 @@ pipe_finalize(fptr, noraise)
void
rb_io_synchronized(fptr)
- OpenFile *fptr;
+ rb_io_t *fptr;
{
fptr->mode |= FMODE_SYNC;
}
void
rb_io_unbuffered(fptr)
- OpenFile *fptr;
+ rb_io_t *fptr;
{
rb_io_synchronized(fptr);
}
-static VALUE pipe_open(VALUE pstr, char *pname, char *mode);
+static VALUE pipe_open(VALUE pstr, const char *pname, const char *mode);
static VALUE
pipe_open(pstr, pname, mode)
VALUE pstr;
- char *pname, *mode;
+ const char *pname, *mode;
{
int modef = rb_io_mode_flags(mode);
- OpenFile *fptr;
+ rb_io_t *fptr;
#if defined(DJGPP) || defined(__human68k__) || defined(__VMS)
FILE *f;
#else
@@ -3038,7 +3179,7 @@ pipe_open(pstr, pname, mode)
#endif
volatile int doexec;
- if (!pname) pname = StringValuePtr(pstr);
+ if (!pname) pname = StringValueCStr(pstr);
doexec = (strcmp("-", pname) != 0);
#if defined(DJGPP) || defined(__human68k__) || defined(__VMS) || defined(_WIN32)
@@ -3110,8 +3251,10 @@ retry:
}
retry:
+ rb_thread_stop_timer();
switch ((pid = fork())) {
case 0: /* child */
+ rb_thread_atfork();
if (modef & FMODE_READABLE) {
close(pr[0]);
if (pr[1] != 1) {
@@ -3137,11 +3280,13 @@ retry:
ruby_sourcefile, ruby_sourceline, pname);
_exit(127);
}
+ rb_thread_start_timer();
rb_io_synchronized(RFILE(orig_stdout)->fptr);
rb_io_synchronized(RFILE(orig_stderr)->fptr);
return Qnil;
case -1: /* fork failed */
+ rb_thread_start_timer();
if (errno == EAGAIN) {
rb_thread_sleep(1);
goto retry;
@@ -3162,6 +3307,7 @@ retry:
break;
default: /* parent */
+ rb_thread_start_timer();
if (pid < 0) rb_sys_fail(pname);
else {
VALUE port = io_alloc(rb_cIO);
@@ -3244,7 +3390,7 @@ rb_io_s_popen(argc, argv, klass)
VALUE *argv;
VALUE klass;
{
- char *mode;
+ const char *mode;
VALUE pname, pmode, port;
if (rb_scan_args(argc, argv, "11", &pname, &pmode) == 1) {
@@ -3254,7 +3400,7 @@ rb_io_s_popen(argc, argv, klass)
mode = rb_io_modenum_mode(FIX2INT(pmode));
}
else {
- mode = rb_io_flags_mode(rb_io_mode_flags(StringValuePtr(pmode)));
+ mode = rb_io_flags_mode(rb_io_mode_flags(StringValueCStr(pmode)));
}
SafeStringValue(pname);
port = pipe_open(pname, 0, mode);
@@ -3282,12 +3428,14 @@ rb_open_file(argc, argv, io)
VALUE io;
{
VALUE fname, vmode, perm;
- char *mode;
- int flags, fmode;
+ const char *path, *mode;
+ int flags;
+ unsigned int fmode;
rb_scan_args(argc, argv, "12", &fname, &vmode, &perm);
SafeStringValue(fname);
+ path = StringValueCStr(fname);
if (FIXNUM_P(vmode) || !NIL_P(perm)) {
if (FIXNUM_P(vmode)) {
flags = FIX2INT(vmode);
@@ -3296,13 +3444,13 @@ rb_open_file(argc, argv, io)
SafeStringValue(vmode);
flags = rb_io_mode_modenum(RSTRING(vmode)->ptr);
}
- fmode = NIL_P(perm) ? 0666 : NUM2INT(perm);
+ fmode = NIL_P(perm) ? 0666 : NUM2UINT(perm);
- rb_file_sysopen_internal(io, RSTRING(fname)->ptr, flags, fmode);
+ rb_file_sysopen_internal(io, path, flags, fmode);
}
else {
- mode = NIL_P(vmode) ? "r" : StringValuePtr(vmode);
- rb_file_open_internal(io, RSTRING(fname)->ptr, mode);
+ mode = NIL_P(vmode) ? "r" : StringValueCStr(vmode);
+ rb_file_open_internal(io, path, mode);
}
return io;
}
@@ -3352,7 +3500,8 @@ rb_io_s_sysopen(argc, argv)
VALUE *argv;
{
VALUE fname, vmode, perm;
- int flags, fmode, fd;
+ int flags, fd;
+ unsigned int fmode;
char *path;
rb_scan_args(argc, argv, "12", &fname, &vmode, &perm);
@@ -3365,7 +3514,7 @@ rb_io_s_sysopen(argc, argv)
flags = rb_io_mode_modenum(RSTRING(vmode)->ptr);
}
if (NIL_P(perm)) fmode = 0666;
- else fmode = NUM2INT(perm);
+ else fmode = NUM2UINT(perm);
path = ALLOCA_N(char, strlen(RSTRING(fname)->ptr)+1);
strcpy(path, RSTRING(fname)->ptr);
@@ -3499,9 +3648,9 @@ rb_io_check_io(io)
return rb_check_convert_type(io, T_FILE, "IO", "to_io");
}
-static char*
+static const char*
rb_io_mode_string(fptr)
- OpenFile *fptr;
+ rb_io_t *fptr;
{
switch (fptr->mode & FMODE_READWRITE) {
case FMODE_READABLE:
@@ -3518,8 +3667,8 @@ static VALUE
io_reopen(io, nfile)
VALUE io, nfile;
{
- OpenFile *fptr, *orig;
- char *mode;
+ rb_io_t *fptr, *orig;
+ const char *mode;
int fd, fd2;
off_t pos = 0;
@@ -3544,7 +3693,7 @@ io_reopen(io, nfile)
io_fflush(GetWriteFile(fptr), fptr);
}
- /* copy OpenFile structure */
+ /* copy rb_io_t structure */
fptr->mode = orig->mode;
fptr->pid = orig->pid;
fptr->lineno = orig->lineno;
@@ -3635,8 +3784,8 @@ rb_io_reopen(argc, argv, file)
VALUE file;
{
VALUE fname, nmode;
- char *mode;
- OpenFile *fptr;
+ const char *mode;
+ rb_io_t *fptr;
rb_secure(4);
if (rb_scan_args(argc, argv, "11", &fname, &nmode) == 1) {
@@ -3650,12 +3799,12 @@ rb_io_reopen(argc, argv, file)
rb_io_taint_check(file);
fptr = RFILE(file)->fptr;
if (!fptr) {
- fptr = RFILE(file)->fptr = ALLOC(OpenFile);
- MEMZERO(fptr, OpenFile, 1);
+ fptr = RFILE(file)->fptr = ALLOC(rb_io_t);
+ MEMZERO(fptr, rb_io_t, 1);
}
if (!NIL_P(nmode)) {
- fptr->mode = rb_io_mode_flags(StringValuePtr(nmode));
+ fptr->mode = rb_io_mode_flags(StringValueCStr(nmode));
}
if (fptr->path) {
@@ -3663,7 +3812,7 @@ rb_io_reopen(argc, argv, file)
fptr->path = 0;
}
- fptr->path = strdup(RSTRING(fname)->ptr);
+ fptr->path = strdup(StringValueCStr(fname));
mode = rb_io_flags_mode(fptr->mode);
if (!fptr->f) {
fptr->f = rb_fopen(fptr->path, mode);
@@ -3674,16 +3823,16 @@ rb_io_reopen(argc, argv, file)
return file;
}
- if (freopen(RSTRING(fname)->ptr, mode, fptr->f) == 0) {
+ if (freopen(fptr->path, mode, fptr->f) == 0) {
rb_sys_fail(fptr->path);
}
#ifdef USE_SETVBUF
if (setvbuf(fptr->f, NULL, _IOFBF, 0) != 0)
- rb_warn("setvbuf() can't be honoured for %s", RSTRING(fname)->ptr);
+ rb_warn("setvbuf() can't be honoured for %s", fptr->path);
#endif
if (fptr->f2) {
- if (freopen(RSTRING(fname)->ptr, "w", fptr->f2) == 0) {
+ if (freopen(fptr->path, "w", fptr->f2) == 0) {
rb_sys_fail(fptr->path);
}
}
@@ -3696,9 +3845,9 @@ static VALUE
rb_io_init_copy(dest, io)
VALUE dest, io;
{
- OpenFile *fptr, *orig;
+ rb_io_t *fptr, *orig;
int fd;
- char *mode;
+ const char *mode;
io = rb_io_get_io(io);
if (dest == io) return dest;
@@ -3716,7 +3865,7 @@ rb_io_init_copy(dest, io)
fseeko(orig->f, 0L, SEEK_CUR);
}
- /* copy OpenFile structure */
+ /* copy rb_io_t structure */
fptr->mode = orig->mode;
fptr->pid = orig->pid;
fptr->lineno = orig->lineno;
@@ -4167,7 +4316,7 @@ prep_stdio(f, mode, klass)
int mode;
VALUE klass;
{
- OpenFile *fp;
+ rb_io_t *fp;
VALUE io = io_alloc(klass);
MakeOpenFile(io, fp);
@@ -4188,7 +4337,7 @@ prep_path(io, path)
VALUE io;
char *path;
{
- OpenFile *fptr;
+ rb_io_t *fptr;
GetOpenFile(io, fptr);
if (fptr->path) rb_bug("illegal prep_path() call");
@@ -4220,7 +4369,7 @@ rb_io_initialize(argc, argv, io)
VALUE io;
{
VALUE fnum, mode;
- OpenFile *fp;
+ rb_io_t *fp;
int fd, flags;
rb_secure(4);
@@ -4232,7 +4381,7 @@ rb_io_initialize(argc, argv, io)
}
else {
SafeStringValue(mode);
- flags = rb_io_mode_modenum(RSTRING(mode)->ptr);
+ flags = rb_io_mode_modenum(StringValueCStr(mode));
}
}
else {
@@ -4318,7 +4467,7 @@ rb_io_s_new(argc, argv, klass)
VALUE klass;
{
if (rb_block_given_p()) {
- char *cname = rb_class2name(klass);
+ const char *cname = rb_class2name(klass);
rb_warn("%s::new() does not take block; use %s::open() instead",
cname, cname);
@@ -4366,10 +4515,7 @@ static void
argf_close(file)
VALUE file;
{
- if (TYPE(file) == T_FILE)
- rb_io_close(file);
- else
- rb_funcall3(file, rb_intern("close"), 0, 0);
+ rb_funcall3(file, rb_intern("close"), 0, 0);
}
static int
@@ -4377,7 +4523,7 @@ next_argv()
{
extern VALUE rb_argv;
char *fn;
- OpenFile *fptr;
+ rb_io_t *fptr;
int stdout_binmode = 0;
if (TYPE(rb_stdout) == T_FILE) {
@@ -4402,7 +4548,7 @@ next_argv()
retry:
if (RARRAY(rb_argv)->len > 0) {
filename = rb_ary_shift(rb_argv);
- fn = StringValuePtr(filename);
+ fn = StringValueCStr(filename);
if (strlen(fn) == 1 && fn[0] == '-') {
current_file = rb_stdin;
if (ruby_inplace_mode) {
@@ -4414,7 +4560,10 @@ next_argv()
FILE *fr = rb_fopen(fn, "r");
if (ruby_inplace_mode) {
- struct stat st, st2;
+ struct stat st;
+#ifndef NO_SAFE_RENAME
+ struct stat st2;
+#endif
VALUE str;
FILE *fw;
@@ -4684,7 +4833,7 @@ rb_f_backquote(obj, str)
{
volatile VALUE port;
VALUE result;
- OpenFile *fptr;
+ rb_io_t *fptr;
SafeStringValue(str);
port = pipe_open(str, 0, "r");
@@ -4721,7 +4870,7 @@ rb_f_select(argc, argv, obj)
fd_set rset, wset, eset, pset;
fd_set *rp, *wp, *ep;
struct timeval *tp, timerec;
- OpenFile *fptr;
+ rb_io_t *fptr;
long i;
int max = 0, n;
int interrupt_flag = 0;
@@ -4883,7 +5032,7 @@ rb_io_ctl(io, req, arg, io_p)
{
#if !defined(MSDOS) && !defined(__human68k__)
int cmd = NUM2ULONG(req);
- OpenFile *fptr;
+ rb_io_t *fptr;
long len = 0;
long narg = 0;
int retval;
@@ -5063,7 +5212,7 @@ rb_f_syscall(argc, argv)
if (!NIL_P(v)) {
StringValue(v);
rb_str_modify(v);
- arg[i] = (unsigned long)RSTRING(v)->ptr;
+ arg[i] = (unsigned long)StringValueCStr(v);
}
else {
arg[i] = (unsigned long)NUM2LONG(*argv);
@@ -5255,14 +5404,16 @@ io_s_foreach(arg)
*/
static VALUE
-rb_io_s_foreach(argc, argv)
+rb_io_s_foreach(argc, argv, self)
int argc;
VALUE *argv;
+ VALUE self;
{
VALUE fname;
struct foreach_arg arg;
rb_scan_args(argc, argv, "11", &fname, &arg.sep);
+ RETURN_ENUMERATOR(self, argc, argv);
SafeStringValue(fname);
if (argc == 1) {
@@ -5271,7 +5422,7 @@ rb_io_s_foreach(argc, argv)
else if (!NIL_P(arg.sep)) {
StringValue(arg.sep);
}
- arg.io = rb_io_open(RSTRING(fname)->ptr, "r");
+ arg.io = rb_io_open(StringValueCStr(fname), "r");
if (NIL_P(arg.io)) return Qnil;
return rb_ensure(io_s_foreach, (VALUE)&arg, rb_io_close, arg.io);
@@ -5310,7 +5461,7 @@ rb_io_s_readlines(argc, argv, io)
SafeStringValue(fname);
arg.argc = argc - 1;
- arg.io = rb_io_open(RSTRING(fname)->ptr, "r");
+ arg.io = rb_io_open(StringValueCStr(fname), "r");
if (NIL_P(arg.io)) return Qnil;
return rb_ensure(io_s_readlines, (VALUE)&arg, rb_io_close, arg.io);
}
@@ -5322,6 +5473,18 @@ io_s_read(arg)
return io_read(arg->argc, &arg->sep, arg->io);
}
+struct seek_arg {
+ VALUE io;
+ VALUE offset;
+ int mode;
+};
+
+static VALUE
+seek_before_read(struct seek_arg *arg)
+{
+ return rb_io_seek(arg->io, arg->offset, arg->mode);
+}
+
/*
* call-seq:
* IO.read(name, [length [, offset]] ) => string
@@ -5348,10 +5511,19 @@ rb_io_s_read(argc, argv, io)
SafeStringValue(fname);
arg.argc = argc ? 1 : 0;
- arg.io = rb_io_open(RSTRING(fname)->ptr, "r");
+ arg.io = rb_io_open(StringValueCStr(fname), "r");
if (NIL_P(arg.io)) return Qnil;
if (!NIL_P(offset)) {
- rb_io_seek(arg.io, offset, SEEK_SET);
+ struct seek_arg sarg;
+ int state = 0;
+ sarg.io = arg.io;
+ sarg.offset = offset;
+ sarg.mode = SEEK_SET;
+ rb_protect((VALUE (*)(VALUE))seek_before_read, (VALUE)&sarg, &state);
+ if (state) {
+ rb_io_close(arg.io);
+ rb_jump_tag(state);
+ }
}
return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
}
@@ -5423,6 +5595,7 @@ argf_eof()
{
if (current_file) {
if (init_p == 0) return Qtrue;
+ next_argv();
ARGF_FORWARD(0, 0);
if (rb_io_eof(current_file)) {
return Qtrue;
@@ -5514,12 +5687,14 @@ argf_readchar()
}
static VALUE
-argf_each_line(argc, argv)
+argf_each_line(argc, argv, argf)
int argc;
VALUE *argv;
+ VALUE argf;
{
VALUE str;
+ RETURN_ENUMERATOR(argf, argc, argv);
if (!next_argv()) return Qnil;
if (TYPE(current_file) != T_FILE) {
for (;;) {
@@ -5535,10 +5710,12 @@ argf_each_line(argc, argv)
}
static VALUE
-argf_each_byte()
+argf_each_byte(argf)
+ VALUE argf;
{
VALUE byte;
+ RETURN_ENUMERATOR(argf, 0, 0);
while (!NIL_P(byte = argf_getc())) {
rb_yield(byte);
}
@@ -5546,6 +5723,42 @@ argf_each_byte()
}
static VALUE
+argf_each_char(argf)
+ VALUE argf;
+{
+ VALUE ch;
+
+ RETURN_ENUMERATOR(argf, 0, 0);
+
+ while (!NIL_P(ch = argf_getc())) {
+ unsigned char c;
+ int n;
+ VALUE str, file;
+
+ first_char:
+ c = FIX2INT(ch);
+ n = mbclen(c);
+ str = rb_tainted_str_new((const char *)&c, 1);
+ file = current_file;
+
+ while (--n > 0) {
+ if (NIL_P(ch = argf_getc())) {
+ rb_yield(str);
+ return argf;
+ }
+ if (current_file != file) {
+ rb_yield(str);
+ goto first_char;
+ }
+ c = FIX2INT(ch);
+ rb_str_cat(str, (const char *)&c, 1);
+ }
+ rb_yield(str);
+ }
+ return argf;
+}
+
+static VALUE
argf_filename()
{
next_argv();
@@ -5572,7 +5785,7 @@ argf_binmode()
static VALUE
argf_skip()
{
- if (next_p != -1) {
+ if (init_p && next_p == 0) {
argf_close(current_file);
next_p = 1;
}
@@ -5624,7 +5837,7 @@ opt_i_set(val)
StringValue(val);
if (ruby_inplace_mode) free(ruby_inplace_mode);
ruby_inplace_mode = 0;
- ruby_inplace_mode = strdup(RSTRING(val)->ptr);
+ ruby_inplace_mode = strdup(StringValueCStr(val));
}
/*
@@ -5787,6 +6000,10 @@ Init_IO()
rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
+ rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
+ rb_define_method(rb_cIO, "lines", rb_io_lines, -1);
+ rb_define_method(rb_cIO, "bytes", rb_io_bytes, 0);
+ rb_define_method(rb_cIO, "chars", rb_io_each_char, 0);
rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
@@ -5812,7 +6029,9 @@ Init_IO()
rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
rb_define_method(rb_cIO, "readline", rb_io_readline, -1);
rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
+ rb_define_method(rb_cIO, "getbyte", rb_io_getc, 0);
rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
+ rb_define_method(rb_cIO, "readbyte", rb_io_readchar, 0);
rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
rb_define_method(rb_cIO, "<<", rb_io_addstr, 1);
rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
@@ -5874,6 +6093,10 @@ Init_IO()
rb_define_singleton_method(argf, "each", argf_each_line, -1);
rb_define_singleton_method(argf, "each_line", argf_each_line, -1);
rb_define_singleton_method(argf, "each_byte", argf_each_byte, 0);
+ rb_define_singleton_method(argf, "each_char", argf_each_char, 0);
+ rb_define_singleton_method(argf, "lines", argf_each_line, -1);
+ rb_define_singleton_method(argf, "bytes", argf_each_byte, 0);
+ rb_define_singleton_method(argf, "chars", argf_each_char, 0);
rb_define_singleton_method(argf, "read", argf_read, -1);
rb_define_singleton_method(argf, "readlines", rb_f_readlines, -1);
@@ -5881,7 +6104,9 @@ Init_IO()
rb_define_singleton_method(argf, "gets", rb_f_gets, -1);
rb_define_singleton_method(argf, "readline", rb_f_readline, -1);
rb_define_singleton_method(argf, "getc", argf_getc, 0);
+ rb_define_singleton_method(argf, "getbyte", argf_getc, 0);
rb_define_singleton_method(argf, "readchar", argf_readchar, 0);
+ rb_define_singleton_method(argf, "readbyte", argf_readchar, 0);
rb_define_singleton_method(argf, "tell", argf_tell, 0);
rb_define_singleton_method(argf, "seek", argf_seek_m, -1);
rb_define_singleton_method(argf, "rewind", argf_rewind, 0);
diff --git a/keywords b/keywords
index 04be992857..6eed5e1f4d 100644
--- a/keywords
+++ b/keywords
@@ -1,4 +1,4 @@
-struct kwtable {char *name; int id[2]; enum lex_state state;};
+struct kwtable {const char *name; int id[2]; enum lex_state state;};
%%
__LINE__, {k__LINE__, k__LINE__}, EXPR_END
__FILE__, {k__FILE__, k__FILE__}, EXPR_END
diff --git a/lex.c b/lex.c
index 79d9448dae..a15309d502 100644
--- a/lex.c
+++ b/lex.c
@@ -1,6 +1,6 @@
/* C code produced by gperf version 2.7.2 */
/* Command-line: gperf -p -j1 -i 1 -g -o -t -N rb_reserved_word -k'1,3,$' ./keywords */
-struct kwtable {char *name; int id[2]; enum lex_state state;};
+struct kwtable {const char *name; int id[2]; enum lex_state state;};
#define TOTAL_KEYWORDS 40
#define MIN_WORD_LENGTH 2
diff --git a/lib/.document b/lib/.document
index 542ca3764c..2159be8360 100644
--- a/lib/.document
+++ b/lib/.document
@@ -8,6 +8,7 @@
English.rb
Env.rb
+README
abbrev.rb
base64.rb
benchmark.rb
@@ -23,6 +24,7 @@ debug.rb
delegate.rb
drb
drb.rb
+e2mmap.rb
erb.rb
eregex.rb
fileutils.rb
@@ -36,6 +38,7 @@ getopts.rb
gserver.rb
importenv.rb
ipaddr.rb
+irb
irb.rb
jcode.rb
logger.rb
diff --git a/lib/README b/lib/README
index d60c5cb1e9..fa2bbd9635 100644
--- a/lib/README
+++ b/lib/README
@@ -49,7 +49,7 @@ open3.rb opens subprocess connection stdin/stdout/stderr
optparse.rb command line option analysis
ostruct.rb python style object
parsearg.rb argument parser using getopts
-parsedate.rb parses date string
+parsedate.rb parses date string (obsolete)
pathname.rb Object-Oriented Pathname Class
ping.rb checks whether host is up, using TCP echo.
pp.rb pretty print objects
@@ -59,7 +59,7 @@ profiler.rb ruby profiler module
pstore.rb persistent object strage using marshal
racc/parser.rb racc (Ruby yACC) runtime
rational.rb rational number support
-rdoc source-code documentation tool
+rdoc source-code documentation tool
readbytes.rb define IO#readbytes
resolv-replace.rb replace Socket DNS by resolve.rb
resolv.rb DNS resolver in Ruby
diff --git a/lib/abbrev.rb b/lib/abbrev.rb
index bf489526cf..6530679681 100644
--- a/lib/abbrev.rb
+++ b/lib/abbrev.rb
@@ -8,7 +8,7 @@
#
# $Idaemons: /home/cvs/rb/abbrev.rb,v 1.2 2001/05/30 09:37:45 knu Exp $
# $RoughId: abbrev.rb,v 1.4 2003/10/14 19:45:42 knu Exp $
-# $Id: abbrev.rb,v 1.1.2.1 2004/01/20 05:27:12 dave Exp $
+# $Id$
=end
# Calculate the set of unique abbreviations for a given set of strings.
diff --git a/lib/base64.rb b/lib/base64.rb
index d80eb5a570..8628d611b2 100644
--- a/lib/base64.rb
+++ b/lib/base64.rb
@@ -102,7 +102,7 @@ module Base64
#
# require 'base64'
# data = "Now is the time for all good coders\nto learn Ruby"
- # puts Base64.b64encode(data)
+ # Base64.b64encode(data)
#
# <i>Generates:</i>
#
diff --git a/lib/benchmark.rb b/lib/benchmark.rb
index ea62dcd208..a54700a1c2 100644
--- a/lib/benchmark.rb
+++ b/lib/benchmark.rb
@@ -2,7 +2,7 @@
#
# benchmark.rb - a performance benchmarking library
#
-# $Id: benchmark.rb,v 1.8.2.2 2004/04/18 23:20:32 nobu Exp $
+# $Id$
#
# Created by Gotoken (gotoken@notwork.org).
#
@@ -304,7 +304,10 @@ module Benchmark
# Returns the elapsed real time used to execute the given block.
#
def realtime(&blk) # :yield:
- Benchmark::measure(&blk).real
+ r0 = Time.now
+ yield
+ r1 = Time.now
+ r1.to_f - r0.to_f
end
@@ -330,8 +333,8 @@ module Benchmark
# Registers the given label and block pair in the job list.
#
def item(label = "", &blk) # :yield:
- raise ArgmentError, "no block" unless block_given?
- label.concat ' '
+ raise ArgumentError, "no block" unless block_given?
+ label += ' '
w = label.length
@width = w if @width < w
@list.push [label, blk]
diff --git a/lib/cgi.rb b/lib/cgi.rb
index a5f79b14ac..7ee0edc9ac 100644
--- a/lib/cgi.rb
+++ b/lib/cgi.rb
@@ -284,7 +284,7 @@ class CGI
# Standard internet newline sequence
EOL = CR + LF
- REVISION = '$Id: cgi.rb,v 1.68.2.16.2.2 2006/12/03 08:06:27 shugo Exp $' #:nodoc:
+ REVISION = '$Id$' #:nodoc:
NEEDS_BINMODE = true if /WIN/ni.match(RUBY_PLATFORM)
@@ -306,7 +306,7 @@ class CGI
"METHOD_NOT_ALLOWED" => "405 Method Not Allowed",
"NOT_ACCEPTABLE" => "406 Not Acceptable",
"LENGTH_REQUIRED" => "411 Length Required",
- "PRECONDITION_FAILED" => "412 Rrecondition Failed",
+ "PRECONDITION_FAILED" => "412 Precondition Failed",
"SERVER_ERROR" => "500 Internal Server Error",
"NOT_IMPLEMENTED" => "501 Method Not Implemented",
"BAD_GATEWAY" => "502 Bad Gateway",
@@ -367,13 +367,13 @@ class CGI
# CGI::unescapeHTML("Usage: foo &quot;bar&quot; &lt;baz&gt;")
# # => "Usage: foo \"bar\" <baz>"
def CGI::unescapeHTML(string)
- string.gsub(/&(.*?);/n) do
+ string.gsub(/&(amp|quot|gt|lt|\#[0-9]+|\#x[0-9A-Fa-f]+);/n) do
match = $1.dup
case match
- when /\Aamp\z/ni then '&'
- when /\Aquot\z/ni then '"'
- when /\Agt\z/ni then '>'
- when /\Alt\z/ni then '<'
+ when 'amp' then '&'
+ when 'quot' then '"'
+ when 'gt' then '>'
+ when 'lt' then '<'
when /\A#0*(\d+)\z/n then
if Integer($1) < 256
Integer($1).chr
@@ -385,7 +385,7 @@ class CGI
end
end
when /\A#x([0-9a-f]+)\z/ni then
- if $1.hex < 256
+ if $1.hex < 128
$1.hex.chr
else
if $1.hex < 65536 and ($KCODE[0] == ?u or $KCODE[0] == ?U)
@@ -709,13 +709,13 @@ class CGI
require "nkf"
case options["charset"]
when /iso-2022-jp/ni
- content = NKF::nkf('-j', content)
+ content = NKF::nkf('-m0 -x -j', content)
options["language"] = "ja" unless options.has_key?("language")
when /euc-jp/ni
- content = NKF::nkf('-e', content)
+ content = NKF::nkf('-m0 -x -e', content)
options["language"] = "ja" unless options.has_key?("language")
when /shift_jis/ni
- content = NKF::nkf('-s', content)
+ content = NKF::nkf('-m0 -x -s', content)
options["language"] = "ja" unless options.has_key?("language")
end
end
@@ -792,11 +792,16 @@ class CGI
#
# These keywords correspond to attributes of the cookie object.
def initialize(name = "", *value)
- options = if name.kind_of?(String)
- { "name" => name, "value" => value }
- else
- name
- end
+ if name.kind_of?(String)
+ @name = name
+ @value = value
+ %r|^(.*/)|.match(ENV["SCRIPT_NAME"])
+ @path = ($1 or "")
+ @secure = false
+ return super(@value)
+ end
+
+ options = name
unless options.has_key?("name")
raise ArgumentError, "`name' required"
end
@@ -817,8 +822,8 @@ class CGI
super(@value)
end
- attr_accessor("name", "value", "path", "domain", "expires")
- attr_reader("secure")
+ attr_accessor("name", "path", "domain", "expires")
+ attr_reader("secure", "value")
# Set whether the Cookie is a secure cookie or not.
#
@@ -828,16 +833,16 @@ class CGI
@secure
end
+ def value=(val)
+ @value.replace(Array(val))
+ end
+
# Convert the Cookie to its string representation.
def to_s
buf = ""
buf += @name + '='
- if @value.kind_of?(String)
- buf += CGI::escape(@value)
- else
- buf += @value.collect{|v| CGI::escape(v) }.join("&")
- end
+ buf += @value.map { |v| CGI::escape(v) }.join("&")
if @domain
buf += '; domain=' + @domain
@@ -880,7 +885,7 @@ class CGI
if cookies.has_key?(name)
values = cookies[name].value + values
end
- cookies[name] = Cookie::new({ "name" => name, "value" => values })
+ cookies[name] = Cookie::new(name, *values)
end
cookies
@@ -1032,21 +1037,21 @@ class CGI
if "--" == $2
content_length = -1
end
- boundary_end = $2.dup
+ boundary_end = $2.dup
""
end
body.rewind
- /Content-Disposition:.* filename="?([^\";]*)"?/ni.match(head)
- filename = ($1 or "")
+ /Content-Disposition:.* filename=(?:"((?:\\.|[^\"])*)"|([^;\s]*))/ni.match(head)
+ filename = ($1 or $2 or "")
if /Mac/ni.match(env_table['HTTP_USER_AGENT']) and
/Mozilla/ni.match(env_table['HTTP_USER_AGENT']) and
(not /MSIE/ni.match(env_table['HTTP_USER_AGENT']))
filename = CGI::unescape(filename)
end
- /Content-Type: (.*)/ni.match(head)
+ /Content-Type: ([^\s]*)/ni.match(head)
content_type = ($1 or "")
(class << body; self; end).class_eval do
@@ -1055,7 +1060,7 @@ class CGI
define_method(:content_type) {content_type.dup.taint}
end
- /Content-Disposition:.* name="?([^\";]*)"?/ni.match(head)
+ /Content-Disposition:.* name="?([^\";\s]*)"?/ni.match(head)
name = $1.dup
if params.has_key?(name)
@@ -1064,7 +1069,7 @@ class CGI
params[name] = [body]
end
break if buf.size == 0
- break if content_length === -1
+ break if content_length == -1
end
raise EOFError, "bad boundary end of body part" unless boundary_end=~/--/
@@ -1084,7 +1089,12 @@ class CGI
%|(offline mode: enter name=value pairs on standard input)\n|
)
end
- readlines.join(' ').gsub(/\n/n, '')
+ array = readlines rescue nil
+ if not array.nil?
+ array.join(' ').gsub(/\n/n, '')
+ else
+ ""
+ end
end.gsub(/\\=/n, '%3D').gsub(/\\&/n, '%26')
words = Shellwords.shellwords(string)
diff --git a/lib/cgi/session.rb b/lib/cgi/session.rb
index 82eb7534d8..2dea08cf75 100644
--- a/lib/cgi/session.rb
+++ b/lib/cgi/session.rb
@@ -174,16 +174,21 @@ class CGI
# is used internally for automatically generated
# session ids.
def create_new_id
- require 'digest/md5'
- md5 = Digest::MD5::new
- now = Time::now
- md5.update(now.to_s)
- md5.update(String(now.usec))
- md5.update(String(rand(0)))
- md5.update(String($$))
- md5.update('foobar')
- @new_session = true
- md5.hexdigest
+ require 'securerandom'
+ begin
+ session_id = SecureRandom.hex(16)
+ rescue NotImplementedError
+ require 'digest/md5'
+ md5 = Digest::MD5::new
+ now = Time::now
+ md5.update(now.to_s)
+ md5.update(String(now.usec))
+ md5.update(String(rand(0)))
+ md5.update(String($$))
+ md5.update('foobar')
+ session_id = md5.hexdigest
+ end
+ session_id
end
private :create_new_id
@@ -224,7 +229,7 @@ class CGI
# session_path:: the path for which this session applies. Defaults
# to the directory of the CGI script.
#
- # +option+ is also passed on to the session storage class initialiser; see
+ # +option+ is also passed on to the session storage class initializer; see
# the documentation for each session storage class for the options
# they support.
#
@@ -250,6 +255,7 @@ class CGI
unless session_id
if option['new_session']
session_id = create_new_id
+ @new_session = true
end
end
unless session_id
@@ -265,6 +271,7 @@ class CGI
raise ArgumentError, "session_key `%s' should be supplied"%session_key
end
session_id = create_new_id
+ @new_session = true
end
end
@session_id = session_id
@@ -275,7 +282,8 @@ class CGI
unless option.fetch('new_session', true)
raise ArgumentError, "invalid session_id `%s'"%session_id
end
- session_id = @session_id = create_new_id
+ session_id = @session_id = create_new_id unless session_id
+ @new_session = true
retry
end
request.instance_eval do
@@ -351,7 +359,7 @@ class CGI
# characters; automatically generated session ids observe
# this requirement.
#
- # +option+ is a hash of options for the initialiser. The
+ # +option+ is a hash of options for the initializer. The
# following options are recognised:
#
# tmpdir:: the directory to use for storing the FileStore
@@ -391,8 +399,9 @@ class CGI
unless @hash
@hash = {}
begin
+ lockf = File.open(@path+".lock", "r")
+ lockf.flock File::LOCK_SH
f = File.open(@path, 'r')
- f.flock File::LOCK_SH
for line in f
line.chomp!
k, v = line.split('=',2)
@@ -400,6 +409,7 @@ class CGI
end
ensure
f.close unless f.nil?
+ lockf.close if lockf
end
end
@hash
@@ -409,13 +419,17 @@ class CGI
def update
return unless @hash
begin
- f = File.open(@path, File::CREAT|File::TRUNC|File::RDWR, 0600)
- f.flock File::LOCK_EX
+ lockf = File.open(@path+".lock", File::CREAT|File::RDWR, 0600)
+ lockf.flock File::LOCK_EX
+ f = File.open(@path+".new", File::CREAT|File::TRUNC|File::WRONLY, 0600)
for k,v in @hash
f.printf "%s=%s\n", CGI::escape(k), CGI::escape(String(v))
end
+ f.close
+ File.rename @path+".new", @path
ensure
- f.close unless f.nil?
+ f.close if f and !f.closed?
+ lockf.close if lockf
end
end
@@ -426,6 +440,8 @@ class CGI
# Close and delete the session's FileStore file.
def delete
+ File::unlink @path+".lock" rescue nil
+ File::unlink @path+".new" rescue nil
File::unlink @path
rescue Errno::ENOENT
end
diff --git a/lib/cgi/session/pstore.rb b/lib/cgi/session/pstore.rb
index bd93d0a6ff..3d204d5dc0 100644
--- a/lib/cgi/session/pstore.rb
+++ b/lib/cgi/session/pstore.rb
@@ -30,7 +30,7 @@ class CGI
# characters; automatically generated session ids observe
# this requirement.
#
- # +option+ is a hash of options for the initialiser. The
+ # +option+ is a hash of options for the initializer. The
# following options are recognised:
#
# tmpdir:: the directory to use for storing the PStore
diff --git a/lib/complex.rb b/lib/complex.rb
index 9300f391e8..808cecc95d 100644
--- a/lib/complex.rb
+++ b/lib/complex.rb
@@ -58,11 +58,7 @@ class Numeric
# See Complex#arg.
#
def arg
- if self >= 0
- return 0
- else
- return Math::PI
- end
+ Math.atan2!(0, self)
end
alias angle arg
@@ -102,6 +98,8 @@ class Complex < Numeric
@RCS_ID='-$Id: complex.rb,v 1.3 1998/07/08 10:05:28 keiju Exp keiju $-'
undef step
+ undef div, divmod
+ undef floor, truncate, ceil, round
def Complex.generic?(other) # :nodoc:
other.kind_of?(Integer) or
@@ -194,6 +192,10 @@ class Complex < Numeric
end
end
+ def quo(other)
+ Complex(@real.quo(1), @image.quo(1)) / other
+ end
+
#
# Raise this complex number to the given (real or complex) power.
#
@@ -409,8 +411,34 @@ class Complex < Numeric
end
+class Integer
+
+ unless defined?(1.numerator)
+ def numerator() self end
+ def denominator() 1 end
+
+ def gcd(other)
+ min = self.abs
+ max = other.abs
+ while min > 0
+ tmp = min
+ min = max % min
+ max = tmp
+ end
+ max
+ end
+
+ def lcm(other)
+ if self.zero? or other.zero?
+ 0
+ else
+ (self.div(self.gcd(other)) * other).abs
+ end
+ end
+ end
+end
module Math
alias sqrt! sqrt
diff --git a/lib/csv.rb b/lib/csv.rb
index 31b698f08c..f6c12fa285 100644
--- a/lib/csv.rb
+++ b/lib/csv.rb
@@ -1,7 +1,7 @@
# CSV -- module for generating/parsing CSV data.
# Copyright (C) 2000-2004 NAKAMURA, Hiroshi <nakahiro@sarion.co.jp>.
-# $Id: csv.rb,v 1.4.2.4 2004/05/27 14:39:10 nahi Exp $
+# $Id$
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
diff --git a/lib/date.rb b/lib/date.rb
index 8639b31575..37c7630895 100644
--- a/lib/date.rb
+++ b/lib/date.rb
@@ -1,12 +1,12 @@
#
# date.rb - date and time library
#
-# Author: Tadayoshi Funaba 1998-2006
+# Author: Tadayoshi Funaba 1998-2010
#
# Documentation: William Webber <william@williamwebber.com>
#
#--
-# $Id: date.rb,v 2.15 2005-02-06 11:09:53+09 tadf Exp $
+# $Id: date.rb,v 2.37 2008-01-17 20:16:31+09 tadf Exp $
#++
#
# == Overview
@@ -14,7 +14,7 @@
# This file provides two classes for working with
# dates and times.
#
-# The first class, Date, represents dates.
+# The first class, Date, represents dates.
# It works with years, months, weeks, and days.
# See the Date class documentation for more details.
#
@@ -80,7 +80,7 @@
# The standard civil year is 365 days long. However, the
# solar year is fractionally longer than this. To account
# for this, a *leap* *year* is occasionally inserted. This
-# is a year with 366 days, the extra day falling on February 29.
+# is a year with 366 days, the extra day falling on February 29.
# In the early days of the civil calendar, every fourth
# year without exception was a leap year. This way of
# reckoning leap years is the *Julian* *Calendar*.
@@ -148,7 +148,7 @@
# of time zones. Time zones are represented as an offset
# from UTC, as a fraction of a day. This offset is the
# how much local time is later (or earlier) than UTC.
-# UTC offset 0 is centred on England (also known as GMT).
+# UTC offset 0 is centred on England (also known as GMT).
# As you travel east, the offset increases until you
# reach the dateline in the middle of the Pacific Ocean;
# as you travel west, the offset decreases. This offset
@@ -249,6 +249,54 @@ class Date
# Abbreviated day names, in English.
ABBR_DAYNAMES = %w(Sun Mon Tue Wed Thu Fri Sat)
+ [MONTHNAMES, DAYNAMES, ABBR_MONTHNAMES, ABBR_DAYNAMES].each do |xs|
+ xs.each{|x| x.freeze unless x.nil?}.freeze
+ end
+
+ class Infinity < Numeric # :nodoc:
+
+ include Comparable
+
+ def initialize(d=1) @d = d <=> 0 end
+
+ def d() @d end
+
+ protected :d
+
+ def zero? () false end
+ def finite? () false end
+ def infinite? () d.nonzero? end
+ def nan? () d.zero? end
+
+ def abs() self.class.new end
+
+ def -@ () self.class.new(-d) end
+ def +@ () self.class.new(+d) end
+
+ def <=> (other)
+ case other
+ when Infinity; return d <=> other.d
+ when Numeric; return d
+ else
+ begin
+ l, r = other.coerce(self)
+ return l <=> r
+ rescue NoMethodError
+ end
+ end
+ nil
+ end
+
+ def coerce(other)
+ case other
+ when Numeric; return -d, d
+ else
+ super
+ end
+ end
+
+ end
+
# The Julian Day Number of the Day of Calendar Reform for Italy
# and the Catholic countries.
ITALY = 2299161 # 1582-10-15
@@ -259,11 +307,26 @@ class Date
# A constant used to indicate that a Date should always use the
# Julian calendar.
- JULIAN = false
+ JULIAN = Infinity.new
# A constant used to indicate that a Date should always use the
# Gregorian calendar.
- GREGORIAN = true
+ GREGORIAN = -Infinity.new
+
+ HALF_DAYS_IN_DAY = Rational(1, 2) # :nodoc:
+ HOURS_IN_DAY = Rational(1, 24) # :nodoc:
+ MINUTES_IN_DAY = Rational(1, 1440) # :nodoc:
+ SECONDS_IN_DAY = Rational(1, 86400) # :nodoc:
+ MILLISECONDS_IN_DAY = Rational(1, 86400*10**3) # :nodoc:
+ NANOSECONDS_IN_DAY = Rational(1, 86400*10**9) # :nodoc:
+ MILLISECONDS_IN_SECOND = Rational(1, 10**3) # :nodoc:
+ NANOSECONDS_IN_SECOND = Rational(1, 10**9) # :nodoc:
+
+ MJD_EPOCH_IN_AJD = Rational(4800001, 2) # 1858-11-17 # :nodoc:
+ UNIX_EPOCH_IN_AJD = Rational(4881175, 2) # 1970-01-01 # :nodoc:
+ MJD_EPOCH_IN_CJD = 2400001 # :nodoc:
+ UNIX_EPOCH_IN_CJD = 2440588 # :nodoc:
+ LD_EPOCH_IN_CJD = 2299160 # :nodoc:
# Does a given Julian Day Number fall inside the old-style (Julian)
# calendar?
@@ -273,10 +336,17 @@ class Date
# the answer is true; or it may a number representing the Day of
# Calendar Reform. Date::ENGLAND and Date::ITALY are two possible such
# days.
- def self.os? (jd, sg)
+
+ def self.julian? (jd, sg)
case sg
- when Numeric; jd < sg
- else; not sg
+ when Numeric
+ jd < sg
+ else
+ if $VERBOSE
+ warn("#{caller.shift.sub(/:in .*/, '')}: " \
+"warning: do not use non-numerical object as julian day number anymore")
+ end
+ not sg
end
end
@@ -285,7 +355,38 @@ class Date
#
# The reverse of self.os? See the documentation for that method for
# more details.
- def self.ns? (jd, sg) not os?(jd, sg) end
+ def self.gregorian? (jd, sg) !julian?(jd, sg) end
+
+ def self.fix_style(jd, sg) # :nodoc:
+ if julian?(jd, sg)
+ then JULIAN
+ else GREGORIAN end
+ end
+
+ private_class_method :fix_style
+
+ # Convert an Ordinal Date to a Julian Day Number.
+ #
+ # +y+ and +d+ are the year and day-of-year to convert.
+ # +sg+ specifies the Day of Calendar Reform.
+ #
+ # Returns the corresponding Julian Day Number.
+ def self.ordinal_to_jd(y, d, sg=GREGORIAN)
+ civil_to_jd(y, 1, d, sg)
+ end
+
+ # Convert a Julian Day Number to an Ordinal Date.
+ #
+ # +jd+ is the Julian Day Number to convert.
+ # +sg+ specifies the Day of Calendar Reform.
+ #
+ # Returns the corresponding Ordinal Date as
+ # [year, day_of_year]
+ def self.jd_to_ordinal(jd, sg=GREGORIAN)
+ y = jd_to_civil(jd, sg)[0]
+ doy = jd - civil_to_jd(y - 1, 12, 31, fix_style(jd, sg))
+ return y, doy
+ end
# Convert a Civil Date to a Julian Day Number.
# +y+, +m+, and +d+ are the year, month, and day of the
@@ -302,7 +403,7 @@ class Date
jd = (365.25 * (y + 4716)).floor +
(30.6001 * (m + 1)).floor +
d + b - 1524
- if os?(jd, sg)
+ if julian?(jd, sg)
jd -= b
end
jd
@@ -315,7 +416,7 @@ class Date
# Returns the corresponding [year, month, day_of_month]
# as a three-element array.
def self.jd_to_civil(jd, sg=GREGORIAN)
- if os?(jd, sg)
+ if julian?(jd, sg)
a = jd
else
x = ((jd - 1867216.25) / 36524.25).floor
@@ -336,27 +437,16 @@ class Date
return y, m, dom
end
- # Convert an Ordinal Date to a Julian Day Number.
- #
- # +y+ and +d+ are the year and day-of-year to convert.
- # +sg+ specifies the Day of Calendar Reform.
- #
- # Returns the corresponding Julian Day Number.
- def self.ordinal_to_jd(y, d, sg=GREGORIAN)
- civil_to_jd(y, 1, d, sg)
- end
-
- # Convert a Julian Day Number to an Ordinal Date.
+ # Convert a Commercial Date to a Julian Day Number.
#
- # +jd+ is the Julian Day Number to convert.
+ # +y+, +w+, and +d+ are the (commercial) year, week of the year,
+ # and day of the week of the Commercial Date to convert.
# +sg+ specifies the Day of Calendar Reform.
- #
- # Returns the corresponding Ordinal Date as
- # [year, day_of_year]
- def self.jd_to_ordinal(jd, sg=GREGORIAN)
- y = jd_to_civil(jd, sg)[0]
- doy = jd - civil_to_jd(y - 1, 12, 31, ns?(jd, sg))
- return y, doy
+ def self.commercial_to_jd(y, w, d, ns=GREGORIAN)
+ jd = civil_to_jd(y, 1, 4, ns)
+ (jd - (((jd - 1) + 1) % 7)) +
+ 7 * (w - 1) +
+ (d - 1)
end
# Convert a Julian Day Number to a Commercial Date
@@ -367,100 +457,101 @@ class Date
# Returns the corresponding Commercial Date as
# [commercial_year, week_of_year, day_of_week]
def self.jd_to_commercial(jd, sg=GREGORIAN)
- ns = ns?(jd, sg)
+ ns = fix_style(jd, sg)
a = jd_to_civil(jd - 3, ns)[0]
y = if jd >= commercial_to_jd(a + 1, 1, 1, ns) then a + 1 else a end
w = 1 + ((jd - commercial_to_jd(y, 1, 1, ns)) / 7).floor
d = (jd + 1) % 7
- if d.zero? then d = 7 end
+ d = 7 if d == 0
return y, w, d
end
- # Convert a Commercial Date to a Julian Day Number.
- #
- # +y+, +w+, and +d+ are the (commercial) year, week of the year,
- # and day of the week of the Commercial Date to convert.
- # +sg+ specifies the Day of Calendar Reform.
- def self.commercial_to_jd(y, w, d, ns=GREGORIAN)
- jd = civil_to_jd(y, 1, 4, ns)
- (jd - (((jd - 1) + 1) % 7)) +
- 7 * (w - 1) +
- (d - 1)
+ def self.weeknum_to_jd(y, w, d, f=0, ns=GREGORIAN) # :nodoc:
+ a = civil_to_jd(y, 1, 1, ns) + 6
+ (a - ((a - f) + 1) % 7 - 7) + 7 * w + d
end
- %w(self.clfloor clfloor).each do |name|
- module_eval <<-"end;"
- def #{name}(x, y=1)
- q, r = x.divmod(y)
- q = q.to_i
- return q, r
- end
- end;
+ def self.jd_to_weeknum(jd, f=0, sg=GREGORIAN) # :nodoc:
+ ns = fix_style(jd, sg)
+ y, m, d = jd_to_civil(jd, ns)
+ a = civil_to_jd(y, 1, 1, ns) + 6
+ w, d = (jd - (a - ((a - f) + 1) % 7) + 7).divmod(7)
+ return y, w, d
end
- private_class_method :clfloor
- private :clfloor
-
+ private_class_method :weeknum_to_jd, :jd_to_weeknum
# Convert an Astronomical Julian Day Number to a (civil) Julian
# Day Number.
#
- # +ajd+ is the Astronomical Julian Day Number to convert.
+ # +ajd+ is the Astronomical Julian Day Number to convert.
# +of+ is the offset from UTC as a fraction of a day (defaults to 0).
#
# Returns the (civil) Julian Day Number as [day_number,
# fraction] where +fraction+ is always 1/2.
- def self.ajd_to_jd(ajd, of=0) clfloor(ajd + of + 1.to_r/2) end
+ def self.ajd_to_jd(ajd, of=0) (ajd + of + HALF_DAYS_IN_DAY).divmod(1) end
# Convert a (civil) Julian Day Number to an Astronomical Julian
# Day Number.
#
# +jd+ is the Julian Day Number to convert, and +fr+ is a
- # fractional day.
+ # fractional day.
# +of+ is the offset from UTC as a fraction of a day (defaults to 0).
#
# Returns the Astronomical Julian Day Number as a single
# numeric value.
- def self.jd_to_ajd(jd, fr, of=0) jd + fr - of - 1.to_r/2 end
+ def self.jd_to_ajd(jd, fr, of=0) jd + fr - of - HALF_DAYS_IN_DAY end
# Convert a fractional day +fr+ to [hours, minutes, seconds,
# fraction_of_a_second]
def self.day_fraction_to_time(fr)
- h, fr = clfloor(fr, 1.to_r/24)
- min, fr = clfloor(fr, 1.to_r/1440)
- s, fr = clfloor(fr, 1.to_r/86400)
+ ss, fr = fr.divmod(SECONDS_IN_DAY) # 4p
+ h, ss = ss.divmod(3600)
+ min, s = ss.divmod(60)
return h, min, s, fr
end
# Convert an +h+ hour, +min+ minutes, +s+ seconds period
# to a fractional day.
- def self.time_to_day_fraction(h, min, s)
- h.to_r/24 + min.to_r/1440 + s.to_r/86400
+ begin
+ Rational(Rational(1, 2), 2) # a challenge
+
+ def self.time_to_day_fraction(h, min, s)
+ Rational(h * 3600 + min * 60 + s, 86400) # 4p
+ end
+ rescue
+ def self.time_to_day_fraction(h, min, s)
+ if Integer === h && Integer === min && Integer === s
+ Rational(h * 3600 + min * 60 + s, 86400) # 4p
+ else
+ (h * 3600 + min * 60 + s).to_r/86400 # 4p
+ end
+ end
end
# Convert an Astronomical Modified Julian Day Number to an
# Astronomical Julian Day Number.
- def self.amjd_to_ajd(amjd) amjd + 4800001.to_r/2 end
+ def self.amjd_to_ajd(amjd) amjd + MJD_EPOCH_IN_AJD end
# Convert an Astronomical Julian Day Number to an
# Astronomical Modified Julian Day Number.
- def self.ajd_to_amjd(ajd) ajd - 4800001.to_r/2 end
+ def self.ajd_to_amjd(ajd) ajd - MJD_EPOCH_IN_AJD end
# Convert a Modified Julian Day Number to a Julian
# Day Number.
- def self.mjd_to_jd(mjd) mjd + 2400001 end
+ def self.mjd_to_jd(mjd) mjd + MJD_EPOCH_IN_CJD end
# Convert a Julian Day Number to a Modified Julian Day
# Number.
- def self.jd_to_mjd(jd) jd - 2400001 end
+ def self.jd_to_mjd(jd) jd - MJD_EPOCH_IN_CJD end
# Convert a count of the number of days since the adoption
# of the Gregorian Calendar (in Italy) to a Julian Day Number.
- def self.ld_to_jd(ld) ld + 2299160 end
+ def self.ld_to_jd(ld) ld + LD_EPOCH_IN_CJD end
# Convert a Julian Day Number to the number of days since
# the adoption of the Gregorian Calendar (in Italy).
- def self.jd_to_ld(jd) jd - 2299160 end
+ def self.jd_to_ld(jd) jd - LD_EPOCH_IN_CJD end
# Convert a Julian Day Number to the day of the week.
#
@@ -476,10 +567,10 @@ class Date
#
# All years divisible by 4 are leap years in the Gregorian calendar,
# except for years divisible by 100 and not by 400.
- def self.gregorian_leap? (y) y % 4 == 0 and y % 100 != 0 or y % 400 == 0 end
+ def self.gregorian_leap? (y) y % 4 == 0 && y % 100 != 0 || y % 400 == 0 end
class << self; alias_method :leap?, :gregorian_leap? end
- class << self; alias_method :new0, :new end
+ class << self; alias_method :new!, :new end
# Is +jd+ a valid Julian Day Number?
#
@@ -487,16 +578,6 @@ class Date
# Julian Day Number.
def self.valid_jd? (jd, sg=ITALY) jd end
- # Create a new Date object from a Julian Day Number.
- #
- # +jd+ is the Julian Day Number; if not specified, it defaults to
- # 0.
- # +sg+ specifies the Day of Calendar Reform.
- def self.jd(jd=0, sg=ITALY)
- jd = valid_jd?(jd, sg)
- new0(jd_to_ajd(jd, 0, 0), 0, sg)
- end
-
# Do the year +y+ and day-of-year +d+ make a valid Ordinal Date?
# Returns the corresponding Julian Day Number if they do, or
# nil if they don't.
@@ -505,16 +586,16 @@ class Date
# from the end of the year (-1 being the last day of the year).
# No year wraparound is performed, however, so valid values of
# +d+ are -365 .. -1, 1 .. 365 on a non-leap-year,
- # -366 .. -1, 1 .. 366 on a leap year.
+ # -366 .. -1, 1 .. 366 on a leap year.
# A date falling in the period skipped in the Day of Calendar Reform
# adjustment is not valid.
#
# +sg+ specifies the Day of Calendar Reform.
def self.valid_ordinal? (y, d, sg=ITALY)
if d < 0
- ny, = clfloor(y + 1, 1)
+ ny, = (y + 1).divmod(1)
jd = ordinal_to_jd(ny, d + 1, sg)
- ns = ns?(jd, sg)
+ ns = fix_style(jd, sg)
return unless [y] == jd_to_ordinal(jd, sg)[0..0]
return unless [ny, 1] == jd_to_ordinal(jd - d, ns)
else
@@ -524,23 +605,6 @@ class Date
jd
end
- # Create a new Date object from an Ordinal Date, specified
- # by year +y+ and day-of-year +d+. +d+ can be negative,
- # in which it counts backwards from the end of the year.
- # No year wraparound is performed, however. An invalid
- # value for +d+ results in an ArgumentError being raised.
- #
- # +y+ defaults to -4712, and +d+ to 1; this is Julian Day
- # Number day 0.
- #
- # +sg+ specifies the Day of Calendar Reform.
- def self.ordinal(y=-4712, d=1, sg=ITALY)
- unless jd = valid_ordinal?(y, d, sg)
- raise ArgumentError, 'invalid date'
- end
- new0(jd_to_ajd(jd, 0, 0), 0, sg)
- end
-
# Do year +y+, month +m+, and day-of-month +d+ make a
# valid Civil Date? Returns the corresponding Julian
# Day Number if they do, nil if they don't.
@@ -558,10 +622,10 @@ class Date
m += 13
end
if d < 0
- ny, nm = clfloor(y * 12 + m, 12)
- nm, = clfloor(nm + 1, 1)
+ ny, nm = (y * 12 + m).divmod(12)
+ nm, = (nm + 1).divmod(1)
jd = civil_to_jd(ny, nm, d + 1, sg)
- ns = ns?(jd, sg)
+ ns = fix_style(jd, sg)
return unless [y, m] == jd_to_civil(jd, sg)[0..1]
return unless [ny, nm, 1] == jd_to_civil(jd - d, ns)
else
@@ -573,28 +637,6 @@ class Date
class << self; alias_method :valid_date?, :valid_civil? end
- # Create a new Date object for the Civil Date specified by
- # year +y+, month +m+, and day-of-month +d+.
- #
- # +m+ and +d+ can be negative, in which case they count
- # backwards from the end of the year and the end of the
- # month respectively. No wraparound is performed, however,
- # and invalid values cause an ArgumentError to be raised.
- # can be negative
- #
- # +y+ defaults to -4712, +m+ to 1, and +d+ to 1; this is
- # Julian Day Number day 0.
- #
- # +sg+ specifies the Day of Calendar Reform.
- def self.civil(y=-4712, m=1, d=1, sg=ITALY)
- unless jd = valid_civil?(y, m, d, sg)
- raise ArgumentError, 'invalid date'
- end
- new0(jd_to_ajd(jd, 0, 0), 0, sg)
- end
-
- class << self; alias_method :new, :civil end
-
# Do year +y+, week-of-year +w+, and day-of-week +d+ make a
# valid Commercial Date? Returns the corresponding Julian
# Day Number if they do, nil if they don't.
@@ -614,14 +656,106 @@ class Date
d += 8
end
if w < 0
- w = jd_to_commercial(commercial_to_jd(y + 1, 1, 1) + w * 7)[1]
+ ny, nw, nd =
+ jd_to_commercial(commercial_to_jd(y + 1, 1, 1) + w * 7)
+ return unless ny == y
+ w = nw
end
jd = commercial_to_jd(y, w, d)
- return unless ns?(jd, sg)
+ return unless gregorian?(jd, sg)
return unless [y, w, d] == jd_to_commercial(jd)
jd
end
+ def self.valid_weeknum? (y, w, d, f, sg=ITALY) # :nodoc:
+ if d < 0
+ d += 7
+ end
+ if w < 0
+ ny, nw, nd, nf =
+ jd_to_weeknum(weeknum_to_jd(y + 1, 1, f, f) + w * 7, f)
+ return unless ny == y
+ w = nw
+ end
+ jd = weeknum_to_jd(y, w, d, f)
+ return unless gregorian?(jd, sg)
+ return unless [y, w, d] == jd_to_weeknum(jd, f)
+ jd
+ end
+
+ private_class_method :valid_weeknum?
+
+ # Do hour +h+, minute +min+, and second +s+ constitute a valid time?
+ #
+ # If they do, returns their value as a fraction of a day. If not,
+ # returns nil.
+ #
+ # The 24-hour clock is used. Negative values of +h+, +min+, and
+ # +sec+ are treating as counting backwards from the end of the
+ # next larger unit (e.g. a +min+ of -2 is treated as 58). No
+ # wraparound is performed.
+ def self.valid_time? (h, min, s)
+ h += 24 if h < 0
+ min += 60 if min < 0
+ s += 60 if s < 0
+ return unless ((0...24) === h &&
+ (0...60) === min &&
+ (0...60) === s) ||
+ (24 == h &&
+ 0 == min &&
+ 0 == s)
+ time_to_day_fraction(h, min, s)
+ end
+
+ # Create a new Date object from a Julian Day Number.
+ #
+ # +jd+ is the Julian Day Number; if not specified, it defaults to
+ # 0.
+ # +sg+ specifies the Day of Calendar Reform.
+ def self.jd(jd=0, sg=ITALY)
+ jd = valid_jd?(jd, sg)
+ new!(jd_to_ajd(jd, 0, 0), 0, sg)
+ end
+
+ # Create a new Date object from an Ordinal Date, specified
+ # by year +y+ and day-of-year +d+. +d+ can be negative,
+ # in which it counts backwards from the end of the year.
+ # No year wraparound is performed, however. An invalid
+ # value for +d+ results in an ArgumentError being raised.
+ #
+ # +y+ defaults to -4712, and +d+ to 1; this is Julian Day
+ # Number day 0.
+ #
+ # +sg+ specifies the Day of Calendar Reform.
+ def self.ordinal(y=-4712, d=1, sg=ITALY)
+ unless jd = valid_ordinal?(y, d, sg)
+ raise ArgumentError, 'invalid date'
+ end
+ new!(jd_to_ajd(jd, 0, 0), 0, sg)
+ end
+
+ # Create a new Date object for the Civil Date specified by
+ # year +y+, month +m+, and day-of-month +d+.
+ #
+ # +m+ and +d+ can be negative, in which case they count
+ # backwards from the end of the year and the end of the
+ # month respectively. No wraparound is performed, however,
+ # and invalid values cause an ArgumentError to be raised.
+ # can be negative
+ #
+ # +y+ defaults to -4712, +m+ to 1, and +d+ to 1; this is
+ # Julian Day Number day 0.
+ #
+ # +sg+ specifies the Day of Calendar Reform.
+ def self.civil(y=-4712, m=1, d=1, sg=ITALY)
+ unless jd = valid_civil?(y, m, d, sg)
+ raise ArgumentError, 'invalid date'
+ end
+ new!(jd_to_ajd(jd, 0, 0), 0, sg)
+ end
+
+ class << self; alias_method :new, :civil end
+
# Create a new Date object for the Commercial Date specified by
# year +y+, week-of-year +w+, and day-of-week +d+.
#
@@ -640,20 +774,191 @@ class Date
unless jd = valid_commercial?(y, w, d, sg)
raise ArgumentError, 'invalid date'
end
- new0(jd_to_ajd(jd, 0, 0), 0, sg)
+ new!(jd_to_ajd(jd, 0, 0), 0, sg)
+ end
+
+ def self.weeknum(y=1582, w=41, d=5, f=0, sg=ITALY) # :nodoc:
+ unless jd = valid_weeknum?(y, w, d, f, sg)
+ raise ArgumentError, 'invalid date'
+ end
+ new!(jd_to_ajd(jd, 0, 0), 0, sg)
end
- def self.new_with_hash(elem, sg)
+ private_class_method :weeknum
+
+ def self.rewrite_frags(elem) # :nodoc:
elem ||= {}
- y, m, d = elem.values_at(:year, :mon, :mday)
- if [y, m, d].include? nil
- raise ArgumentError, '3 elements of civil date are necessary'
- else
- civil(y, m, d, sg)
+ if seconds = elem[:seconds]
+ d, fr = seconds.divmod(86400)
+ h, fr = fr.divmod(3600)
+ min, fr = fr.divmod(60)
+ s, fr = fr.divmod(1)
+ elem[:jd] = UNIX_EPOCH_IN_CJD + d
+ elem[:hour] = h
+ elem[:min] = min
+ elem[:sec] = s
+ elem[:sec_fraction] = fr
+ elem.delete(:seconds)
+ elem.delete(:offset)
end
+ elem
end
- private_class_method :new_with_hash
+ private_class_method :rewrite_frags
+
+ def self.complete_frags(elem) # :nodoc:
+ i = 0
+ g = [[:time, [:hour, :min, :sec]],
+ [nil, [:jd]],
+ [:ordinal, [:year, :yday, :hour, :min, :sec]],
+ [:civil, [:year, :mon, :mday, :hour, :min, :sec]],
+ [:commercial, [:cwyear, :cweek, :cwday, :hour, :min, :sec]],
+ [:wday, [:wday, :hour, :min, :sec]],
+ [:wnum0, [:year, :wnum0, :wday, :hour, :min, :sec]],
+ [:wnum1, [:year, :wnum1, :wday, :hour, :min, :sec]],
+ [nil, [:cwyear, :cweek, :wday, :hour, :min, :sec]],
+ [nil, [:year, :wnum0, :cwday, :hour, :min, :sec]],
+ [nil, [:year, :wnum1, :cwday, :hour, :min, :sec]]].
+ collect{|k, a| e = elem.values_at(*a).compact; [k, a, e]}.
+ select{|k, a, e| e.size > 0}.
+ sort_by{|k, a, e| [e.size, i -= 1]}.last
+
+ d = nil
+
+ if g && g[0] && (g[1].size - g[2].size) != 0
+ d ||= Date.today
+
+ case g[0]
+ when :ordinal
+ elem[:year] ||= d.year
+ elem[:yday] ||= 1
+ when :civil
+ g[1].each do |e|
+ break if elem[e]
+ elem[e] = d.__send__(e)
+ end
+ elem[:mon] ||= 1
+ elem[:mday] ||= 1
+ when :commercial
+ g[1].each do |e|
+ break if elem[e]
+ elem[e] = d.__send__(e)
+ end
+ elem[:cweek] ||= 1
+ elem[:cwday] ||= 1
+ when :wday
+ elem[:jd] ||= (d - d.wday + elem[:wday]).jd
+ when :wnum0
+ g[1].each do |e|
+ break if elem[e]
+ elem[e] = d.__send__(e)
+ end
+ elem[:wnum0] ||= 0
+ elem[:wday] ||= 0
+ when :wnum1
+ g[1].each do |e|
+ break if elem[e]
+ elem[e] = d.__send__(e)
+ end
+ elem[:wnum1] ||= 0
+ elem[:wday] ||= 0
+ end
+ end
+
+ if g && g[0] == :time
+ if self <= DateTime
+ d ||= Date.today
+ elem[:jd] ||= d.jd
+ end
+ end
+
+ elem[:hour] ||= 0
+ elem[:min] ||= 0
+ elem[:sec] ||= 0
+ elem[:sec] = [elem[:sec], 59].min
+
+ elem
+ end
+
+ private_class_method :complete_frags
+
+ def self.valid_date_frags?(elem, sg) # :nodoc:
+ catch :jd do
+ a = elem.values_at(:jd)
+ if a.all?
+ if jd = valid_jd?(*(a << sg))
+ throw :jd, jd
+ end
+ end
+
+ a = elem.values_at(:year, :yday)
+ if a.all?
+ if jd = valid_ordinal?(*(a << sg))
+ throw :jd, jd
+ end
+ end
+
+ a = elem.values_at(:year, :mon, :mday)
+ if a.all?
+ if jd = valid_civil?(*(a << sg))
+ throw :jd, jd
+ end
+ end
+
+ a = elem.values_at(:cwyear, :cweek, :cwday)
+ if a[2].nil? && elem[:wday]
+ a[2] = elem[:wday].nonzero? || 7
+ end
+ if a.all?
+ if jd = valid_commercial?(*(a << sg))
+ throw :jd, jd
+ end
+ end
+
+ a = elem.values_at(:year, :wnum0, :wday)
+ if a[2].nil? && elem[:cwday]
+ a[2] = elem[:cwday] % 7
+ end
+ if a.all?
+ if jd = valid_weeknum?(*(a << 0 << sg))
+ throw :jd, jd
+ end
+ end
+
+ a = elem.values_at(:year, :wnum1, :wday)
+ if a[2]
+ a[2] = (a[2] - 1) % 7
+ end
+ if a[2].nil? && elem[:cwday]
+ a[2] = (elem[:cwday] - 1) % 7
+ end
+ if a.all?
+ if jd = valid_weeknum?(*(a << 1 << sg))
+ throw :jd, jd
+ end
+ end
+ end
+ end
+
+ private_class_method :valid_date_frags?
+
+ def self.valid_time_frags? (elem) # :nodoc:
+ h, min, s = elem.values_at(:hour, :min, :sec)
+ valid_time?(h, min, s)
+ end
+
+ private_class_method :valid_time_frags?
+
+ def self.new_by_frags(elem, sg) # :nodoc:
+ elem = rewrite_frags(elem)
+ elem = complete_frags(elem)
+ unless jd = valid_date_frags?(elem, sg)
+ raise ArgumentError, 'invalid date'
+ end
+ new!(jd_to_ajd(jd, 0, 0), 0, sg)
+ end
+
+ private_class_method :new_by_frags
# Create a new Date object by parsing from a String
# according to a specified format.
@@ -672,13 +977,13 @@ class Date
# parsed.
def self.strptime(str='-4712-01-01', fmt='%F', sg=ITALY)
elem = _strptime(str, fmt)
- new_with_hash(elem, sg)
+ new_by_frags(elem, sg)
end
# Create a new Date object by parsing from a String,
# without specifying the format.
#
- # +str+ is a String holding a date representation.
+ # +str+ is a String holding a date representation.
# +comp+ specifies whether to interpret 2-digit years
# as 19XX (>= 69) or 20XX (< 69); the default is not to.
# The method will attempt to parse a date from the String
@@ -692,32 +997,18 @@ class Date
# +sg+ specifies the Day of Calendar Reform.
def self.parse(str='-4712-01-01', comp=false, sg=ITALY)
elem = _parse(str, comp)
- new_with_hash(elem, sg)
- end
-
- # Create a new Date object representing today.
- #
- # +sg+ specifies the Day of Calendar Reform.
- def self.today(sg=ITALY)
- jd = civil_to_jd(*(Time.now.to_a[3..5].reverse << sg))
- new0(jd_to_ajd(jd, 0, 0), 0, sg)
+ new_by_frags(elem, sg)
end
class << self
def once(*ids) # :nodoc:
for id in ids
- module_eval <<-"end;", __FILE__, __LINE__
+ module_eval <<-"end;"
alias_method :__#{id.to_i}__, :#{id.to_s}
private :__#{id.to_i}__
def #{id.to_s}(*args, &block)
- if defined? @__#{id.to_i}__
- @__#{id.to_i}__
- elsif ! self.frozen?
- @__#{id.to_i}__ ||= __#{id.to_i}__(*args, &block)
- else
- __#{id.to_i}__(*args, &block)
- end
+ (@__#{id.to_i}__ ||= [__#{id.to_i}__(*args, &block)])[0]
end
end;
end
@@ -727,7 +1018,7 @@ class Date
end
- # *NOTE* this is the documentation for the method new0(). If
+ # *NOTE* this is the documentation for the method new!(). If
# you are reading this as the documentation for new(), that is
# because rdoc doesn't fully support the aliasing of the
# initialize() method.
@@ -772,16 +1063,19 @@ class Date
once :jd, :day_fraction, :mjd, :ld
# Get the date as a Civil Date, [year, month, day_of_month]
- def civil() self.class.jd_to_civil(jd, @sg) end
+ def civil() self.class.jd_to_civil(jd, @sg) end # :nodoc:
# Get the date as an Ordinal Date, [year, day_of_year]
- def ordinal() self.class.jd_to_ordinal(jd, @sg) end
+ def ordinal() self.class.jd_to_ordinal(jd, @sg) end # :nodoc:
# Get the date as a Commercial Date, [year, week_of_year, day_of_week]
- def commercial() self.class.jd_to_commercial(jd, @sg) end
+ def commercial() self.class.jd_to_commercial(jd, @sg) end # :nodoc:
- once :civil, :ordinal, :commercial
- private :civil, :ordinal, :commercial
+ def weeknum0() self.class.__send__(:jd_to_weeknum, jd, 0, @sg) end # :nodoc:
+ def weeknum1() self.class.__send__(:jd_to_weeknum, jd, 1, @sg) end # :nodoc:
+
+ once :civil, :ordinal, :commercial, :weeknum0, :weeknum1
+ private :civil, :ordinal, :commercial, :weeknum0, :weeknum1
# Get the year of this date.
def year() civil[0] end
@@ -802,9 +1096,14 @@ class Date
alias_method :month, :mon
alias_method :day, :mday
+ def wnum0() weeknum0[1] end # :nodoc:
+ def wnum1() weeknum1[1] end # :nodoc:
+
+ private :wnum0, :wnum1
+
# Get the time of this date as [hours, minutes, seconds,
# fraction_of_a_second]
- def time() self.class.day_fraction_to_time(day_fraction) end
+ def time() self.class.day_fraction_to_time(day_fraction) end # :nodoc:
once :time
private :time
@@ -818,12 +1117,20 @@ class Date
# Get the second of this date.
def sec() time[2] end
- # Get the fraction-of-a-second of this date.
+ # Get the fraction-of-a-second of this date. The unit is in days.
+ # I do NOT recommend you to use this method.
def sec_fraction() time[3] end
+=begin
+ alias_method :minute, :min
+ alias_method :second, :sec
+ alias_method :second_fraction, :sec_fraction
+=end
+
private :hour, :min, :sec, :sec_fraction
+# :minute, :second, :second_fraction
- def zone() strftime('%Z') end
+ def zone() strftime('%:z') end
private :zone
@@ -844,18 +1151,38 @@ class Date
once :wday
+=begin
+ MONTHNAMES.each_with_index do |n, i|
+ if n
+ define_method(n.downcase + '?'){mon == i}
+ end
+ end
+
+ DAYNAMES.each_with_index do |n, i|
+ define_method(n.downcase + '?'){wday == i}
+ end
+=end
+
# Is the current date old-style (Julian Calendar)?
- def os? () self.class.os?(jd, @sg) end
+ def julian? () self.class.julian?(jd, @sg) end
# Is the current date new-style (Gregorian Calendar)?
- def ns? () self.class.ns?(jd, @sg) end
+ def gregorian? () self.class.gregorian?(jd, @sg) end
+
+ once :julian?, :gregorian?
+
+ def fix_style # :nodoc:
+ if julian?
+ then self.class::JULIAN
+ else self.class::GREGORIAN end
+ end
- once :os?, :ns?
+ private :fix_style
# Is this a leap year?
def leap?
- self.class.jd_to_civil(self.class.civil_to_jd(year, 3, 1, ns?) - 1,
- ns?)[-1] == 29
+ self.class.jd_to_civil(self.class.civil_to_jd(year, 3, 1, fix_style) - 1,
+ fix_style)[-1] == 29
end
once :leap?
@@ -864,7 +1191,7 @@ class Date
def start() @sg end
# Create a copy of this Date object using a new Day of Calendar Reform.
- def new_start(sg=self.class::ITALY) self.class.new0(@ajd, @of, sg) end
+ def new_start(sg=self.class::ITALY) self.class.new!(@ajd, @of, sg) end
# Create a copy of this Date object that uses the Italian/Catholic
# Day of Calendar Reform.
@@ -883,7 +1210,13 @@ class Date
def gregorian() new_start(self.class::GREGORIAN) end
def offset() @of end
- def new_offset(of=0) self.class.new0(@ajd, of, @sg) end
+
+ def new_offset(of=0)
+ if String === of
+ of = Rational(zone_to_diff(of) || 0, 86400)
+ end
+ self.class.new!(@ajd, of, @sg)
+ end
private :offset, :new_offset
@@ -898,7 +1231,7 @@ class Date
# particular, two Dates cannot be added to each other.
def + (n)
case n
- when Numeric; return self.class.new0(@ajd + n, @of, @sg)
+ when Numeric; return self.class.new!(@ajd + n, @of, @sg)
end
raise TypeError, 'expected numeric'
end
@@ -913,7 +1246,7 @@ class Date
# If +x+ is neither Numeric nor a Date, a TypeError is raised.
def - (x)
case x
- when Numeric; return self.class.new0(@ajd - x, @of, @sg)
+ when Numeric; return self.class.new!(@ajd - x, @of, @sg)
when Date; return @ajd - x.ajd
end
raise TypeError, 'expected numeric or date'
@@ -952,6 +1285,16 @@ class Date
false
end
+ def next_day(n=1) self + n end
+# def prev_day(n=1) self - n end
+
+ private :next_day
+
+ # Return a new Date one day after this one.
+ def next() next_day end
+
+ alias_method :succ, :next
+
# Return a new Date object that is +n+ months later than
# the current one.
#
@@ -959,10 +1302,13 @@ class Date
# than the last day of the target month, the day-of-the-month
# of the returned Date will be the last day of the target month.
def >> (n)
- y, m = clfloor(year * 12 + (mon - 1) + n, 12)
- m, = clfloor(m + 1, 1)
+ y, m = (year * 12 + (mon - 1) + n).divmod(12)
+ m, = (m + 1) .divmod(1)
d = mday
- d -= 1 until jd2 = self.class.valid_civil?(y, m, d, ns?)
+ until jd2 = self.class.valid_civil?(y, m, d, fix_style)
+ d -= 1
+ raise ArgumentError, 'invalid date' unless d > 0
+ end
self + (jd2 - jd)
end
@@ -974,13 +1320,33 @@ class Date
# of the returned Date will be the last day of the target month.
def << (n) self >> -n end
+=begin
+ def next_month(n=1) self >> n end
+ def prev_month(n=1) self << n end
+
+ def next_year(n=1) self >> n * 12 end
+ def prev_year(n=1) self << n * 12 end
+=end
+
+# require 'enumerator'
+
# Step the current date forward +step+ days at a
# time (or backward, if +step+ is negative) until
# we reach +limit+ (inclusive), yielding the resultant
# date at each step.
- def step(limit, step) # :yield: date
+ def step(limit, step=1) # :yield: date
+=begin
+ if step.zero?
+ raise ArgumentError, "step can't be 0"
+ end
+=end
+=begin
+ unless block_given?
+ return to_enum(:step, limit, step)
+ end
+=end
da = self
- op = [:-,:<=,:>=][step<=>0]
+ op = %w(- <= >=)[step <=> 0]
while da.__send__(op, limit)
yield da
da += step
@@ -990,25 +1356,20 @@ class Date
# Step forward one day at a time until we reach +max+
# (inclusive), yielding each date as we go.
- def upto(max, &block) # :yield: date
- step(max, +1, &block)
+ def upto(max, &block) # :yield: date
+ step(max, +1, &block)
end
# Step backward one day at a time until we reach +min+
# (inclusive), yielding each date as we go.
def downto(min, &block) # :yield: date
- step(min, -1, &block)
+ step(min, -1, &block)
end
- # Return a new Date one day after this one.
- def succ() self + 1 end
-
- alias_method :next, :succ
-
# Is this Date equal to +other+?
#
# +other+ must both be a Date object, and represent the same date.
- def eql? (other) Date === other and self == other end
+ def eql? (other) Date === other && self == other end
# Calculate a hash value for this date.
def hash() @ajd.hash end
@@ -1019,14 +1380,14 @@ class Date
# Return the date as a human-readable string.
#
# The format used is YYYY-MM-DD.
- def to_s() strftime end
+ def to_s() format('%.4d-%02d-%02d', year, mon, mday) end # 4p
# Dump to Marshal format.
def _dump(limit) Marshal.dump([@ajd, @of, @sg], -1) end
-# def self._load(str) new0(*Marshal.load(str)) end
+# def self._load(str) new!(*Marshal.load(str)) end
- # Load from Marshall format.
+ # Load from Marshal format.
def self._load(str)
a = Marshal.load(str)
if a.size == 2
@@ -1036,7 +1397,7 @@ class Date
else
ajd, of, sg = a
end
- new0(ajd, of, sg)
+ new!(ajd, of, sg)
end
end
@@ -1071,7 +1432,8 @@ end
# === sec_fraction()
#
# Get the fraction of a second of the time. This is returned as
-# a +Rational+.
+# a +Rational+. The unit is in days.
+# I do NOT recommend you to use this method.
#
# === zone()
#
@@ -1091,25 +1453,6 @@ end
#
class DateTime < Date
- # Do hour +h+, minute +min+, and second +s+ constitute a valid time?
- #
- # If they do, returns their value as a fraction of a day. If not,
- # returns nil.
- #
- # The 24-hour clock is used. Negative values of +h+, +min+, and
- # +sec+ are treating as counting backwards from the end of the
- # next larger unit (e.g. a +min+ of -2 is treated as 58). No
- # wraparound is performed.
- def self.valid_time? (h, min, s)
- h += 24 if h < 0
- min += 60 if min < 0
- s += 60 if s < 0
- return unless (0..24) === h and
- (0..59) === min and
- (0..59) === s
- time_to_day_fraction(h, min, s)
- end
-
# Create a new DateTime object corresponding to the specified
# Julian Day Number +jd+ and hour +h+, minute +min+, second +s+.
#
@@ -1124,11 +1467,14 @@ class DateTime < Date
#
# All day/time values default to 0.
def self.jd(jd=0, h=0, min=0, s=0, of=0, sg=ITALY)
- unless (jd = valid_jd?(jd, sg)) and
+ unless (jd = valid_jd?(jd, sg)) &&
(fr = valid_time?(h, min, s))
raise ArgumentError, 'invalid date'
end
- new0(jd_to_ajd(jd, fr, of), of, sg)
+ if String === of
+ of = Rational(zone_to_diff(of) || 0, 86400)
+ end
+ new!(jd_to_ajd(jd, fr, of), of, sg)
end
# Create a new DateTime object corresponding to the specified
@@ -1146,11 +1492,14 @@ class DateTime < Date
# +y+ defaults to -4712, and +d+ to 1; this is Julian Day Number
# day 0. The time values default to 0.
def self.ordinal(y=-4712, d=1, h=0, min=0, s=0, of=0, sg=ITALY)
- unless (jd = valid_ordinal?(y, d, sg)) and
+ unless (jd = valid_ordinal?(y, d, sg)) &&
(fr = valid_time?(h, min, s))
raise ArgumentError, 'invalid date'
end
- new0(jd_to_ajd(jd, fr, of), of, sg)
+ if String === of
+ of = Rational(zone_to_diff(of) || 0, 86400)
+ end
+ new!(jd_to_ajd(jd, fr, of), of, sg)
end
# Create a new DateTime object corresponding to the specified
@@ -1168,11 +1517,14 @@ class DateTime < Date
# +y+ defaults to -4712, +m+ to 1, and +d+ to 1; this is Julian Day
# Number day 0. The time values default to 0.
def self.civil(y=-4712, m=1, d=1, h=0, min=0, s=0, of=0, sg=ITALY)
- unless (jd = valid_civil?(y, m, d, sg)) and
+ unless (jd = valid_civil?(y, m, d, sg)) &&
(fr = valid_time?(h, min, s))
raise ArgumentError, 'invalid date'
end
- new0(jd_to_ajd(jd, fr, of), of, sg)
+ if String === of
+ of = Rational(zone_to_diff(of) || 0, 86400)
+ end
+ new!(jd_to_ajd(jd, fr, of), of, sg)
end
class << self; alias_method :new, :civil end
@@ -1193,31 +1545,42 @@ class DateTime < Date
# Calendar Reform for Italy and the Catholic countries.
# The time values default to 0.
def self.commercial(y=1582, w=41, d=5, h=0, min=0, s=0, of=0, sg=ITALY)
- unless (jd = valid_commercial?(y, w, d, sg)) and
+ unless (jd = valid_commercial?(y, w, d, sg)) &&
(fr = valid_time?(h, min, s))
raise ArgumentError, 'invalid date'
end
- new0(jd_to_ajd(jd, fr, of), of, sg)
+ if String === of
+ of = Rational(zone_to_diff(of) || 0, 86400)
+ end
+ new!(jd_to_ajd(jd, fr, of), of, sg)
end
- def self.new_with_hash(elem, sg)
- elem ||= {}
- y, m, d, h, min, s, fr, of =
- elem.values_at(:year, :mon, :mday,
- :hour, :min, :sec, :sec_fraction, :offset)
- h ||= 0
- min ||= 0
- s ||= 0
- fr ||= 0
- of ||= 0
- if [y, m, d].include? nil
- raise ArgumentError, '3 elements of civil date are necessary'
- else
- civil(y, m, d, h, min, s, of.to_r/86400, sg) + (fr/86400)
+ def self.weeknum(y=1582, w=41, d=5, f=0, h=0, min=0, s=0, of=0, sg=ITALY) # :nodoc:
+ unless (jd = valid_weeknum?(y, w, d, f, sg)) &&
+ (fr = valid_time?(h, min, s))
+ raise ArgumentError, 'invalid date'
end
+ if String === of
+ of = Rational(zone_to_diff(of) || 0, 86400)
+ end
+ new!(jd_to_ajd(jd, fr, of), of, sg)
+ end
+
+ private_class_method :weeknum
+
+ def self.new_by_frags(elem, sg) # :nodoc:
+ elem = rewrite_frags(elem)
+ elem = complete_frags(elem)
+ unless (jd = valid_date_frags?(elem, sg)) &&
+ (fr = valid_time_frags?(elem))
+ raise ArgumentError, 'invalid date'
+ end
+ fr += (elem[:sec_fraction] || 0) / 86400
+ of = Rational(elem[:offset] || 0, 86400)
+ new!(jd_to_ajd(jd, fr, of), of, sg)
end
- private_class_method :new_with_hash
+ private_class_method :new_by_frags
# Create a new DateTime object by parsing from a String
# according to a specified format.
@@ -1226,22 +1589,22 @@ class DateTime < Date
# +fmt+ is the format that the date-time is in. See
# date/format.rb for details on supported formats.
#
- # The default +str+ is '-4712-01-01T00:00:00Z', and the default
- # +fmt+ is '%FT%T%Z'. This gives midnight on Julian Day Number day 0.
+ # The default +str+ is '-4712-01-01T00:00:00+00:00', and the default
+ # +fmt+ is '%FT%T%z'. This gives midnight on Julian Day Number day 0.
#
# +sg+ specifies the Day of Calendar Reform.
#
# An ArgumentError will be raised if +str+ cannot be
# parsed.
- def self.strptime(str='-4712-01-01T00:00:00Z', fmt='%FT%T%Z', sg=ITALY)
+ def self.strptime(str='-4712-01-01T00:00:00+00:00', fmt='%FT%T%z', sg=ITALY)
elem = _strptime(str, fmt)
- new_with_hash(elem, sg)
+ new_by_frags(elem, sg)
end
# Create a new DateTime object by parsing from a String,
# without specifying the format.
#
- # +str+ is a String holding a date-time representation.
+ # +str+ is a String holding a date-time representation.
# +comp+ specifies whether to interpret 2-digit years
# as 19XX (>= 69) or 20XX (< 69); the default is not to.
# The method will attempt to parse a date-time from the String
@@ -1249,72 +1612,162 @@ class DateTime < Date
# for more details. If parsing fails, an ArgumentError
# will be raised.
#
- # The default +str+ is '-4712-01-01T00:00:00Z'; this is Julian
+ # The default +str+ is '-4712-01-01T00:00:00+00:00'; this is Julian
# Day Number day 0.
#
# +sg+ specifies the Day of Calendar Reform.
- def self.parse(str='-4712-01-01T00:00:00Z', comp=false, sg=ITALY)
+ def self.parse(str='-4712-01-01T00:00:00+00:00', comp=false, sg=ITALY)
elem = _parse(str, comp)
- new_with_hash(elem, sg)
+ new_by_frags(elem, sg)
end
- class << self; undef_method :today end rescue nil
+ public :hour, :min, :sec, :sec_fraction, :zone, :offset, :new_offset
+# :minute, :second, :second_fraction
+
+ def to_s # 4p
+ format('%.4d-%02d-%02dT%02d:%02d:%02d%s',
+ year, mon, mday, hour, min, sec, zone)
+ end
+
+end
+
+class Time
+
+# def to_time() getlocal end
+
+ def to_date
+ jd = Date.civil_to_jd(year, mon, mday, Date::ITALY)
+ Date.new!(Date.jd_to_ajd(jd, 0, 0), 0, Date::ITALY)
+ end
+
+ def to_datetime
+ jd = DateTime.civil_to_jd(year, mon, mday, DateTime::ITALY)
+ fr = DateTime.time_to_day_fraction(hour, min, [sec, 59].min) +
+ Rational(usec, 86400_000_000)
+ of = Rational(utc_offset, 86400)
+ DateTime.new!(DateTime.jd_to_ajd(jd, fr, of), of, DateTime::ITALY)
+ end
+
+ private :to_date, :to_datetime
+
+end
+
+class Date
+
+=begin
+ def to_time() Time.local(year, mon, mday) end
+ def to_date() self end
+ def to_datetime() DateTime.new!(self.class.jd_to_ajd(jd, 0, 0), @of, @sg) end
+=end
+
+ # Create a new Date object representing today.
+ #
+ # +sg+ specifies the Day of Calendar Reform.
+ def self.today(sg=ITALY)
+ t = Time.now
+ jd = civil_to_jd(t.year, t.mon, t.mday, sg)
+ new!(jd_to_ajd(jd, 0, 0), 0, sg)
+ end
# Create a new DateTime object representing the current time.
#
# +sg+ specifies the Day of Calendar Reform.
def self.now(sg=ITALY)
- i = Time.now
- a = i.to_a[0..5].reverse
- jd = civil_to_jd(*(a[0,3] << sg))
- fr = time_to_day_fraction(*(a[3,3])) + i.usec.to_r/86400000000
- of = i.utc_offset.to_r/86400
- new0(jd_to_ajd(jd, fr, of), of, sg)
+ t = Time.now
+ jd = civil_to_jd(t.year, t.mon, t.mday, sg)
+ fr = time_to_day_fraction(t.hour, t.min, [t.sec, 59].min) +
+ Rational(t.usec, 86400_000_000)
+ of = Rational(t.utc_offset, 86400)
+ new!(jd_to_ajd(jd, fr, of), of, sg)
end
- public :hour, :min, :sec, :sec_fraction, :zone, :offset, :new_offset
+ private_class_method :now
+
+end
+
+class DateTime < Date
+
+=begin
+ def to_time
+ d = new_offset(0)
+ d.instance_eval do
+ Time.utc(year, mon, mday, hour, min, sec,
+ (sec_fraction * 86400000000).to_i)
+ end.
+ getlocal
+ end
+
+ def to_date() Date.new!(self.class.jd_to_ajd(jd, 0, 0), 0, @sg) end
+ def to_datetime() self end
+=end
+
+ private_class_method :today
+ public_class_method :now
end
class Date
- [ %w(exist1? valid_jd?),
+ class << self
+
+ def deprecated_class_method_alias(old, new) # :nodoc:
+ module_eval <<-"end;"
+ class << self
+ def #{old}(*args, &block)
+ if $VERBOSE
+ warn("\#{caller.shift.sub(/:in .*/, '')}: " \
+ "warning: \#{self}::#{old} is deprecated; " \
+ "use \#{self}::#{new}")
+ end
+ #{new}(*args, &block)
+ end
+ end
+ end;
+ end
+
+ private :deprecated_class_method_alias
+
+ def deprecated_alias(old, new) # :nodoc:
+ module_eval <<-"end;"
+ def #{old}(*args, &block)
+ if $VERBOSE
+ warn("\#{caller.shift.sub(/:in .*/, '')}: " \
+ "warning: \#{self.class}\##{old} is deprecated; " \
+ "use \#{self.class}\##{new}")
+ end
+ #{new}(*args, &block)
+ end
+ end;
+ end
+
+ private :deprecated_alias
+
+ end
+
+ [ %w(os? julian?),
+ %w(ns? gregorian?),
+ %w(exist1? valid_jd?),
%w(exist2? valid_ordinal?),
%w(exist3? valid_date?),
%w(exist? valid_date?),
%w(existw? valid_commercial?),
+ %w(new0 new!),
%w(new1 jd),
%w(new2 ordinal),
%w(new3 new),
%w(neww commercial)
].each do |old, new|
- module_eval <<-"end;"
- def self.#{old}(*args, &block)
- if $VERBOSE
- warn("\#{caller.shift.sub(/:in .*/, '')}: " \
- "warning: \#{self}::#{old} is deprecated; " \
- "use \#{self}::#{new}")
- end
- #{new}(*args, &block)
- end
- end;
+ deprecated_class_method_alias(old, new)
end
- [ %w(sg start),
+ [ %w(os? julian?),
+ %w(ns? gregorian?),
+ %w(sg start),
%w(newsg new_start),
%w(of offset),
%w(newof new_offset)
].each do |old, new|
- module_eval <<-"end;"
- def #{old}(*args, &block)
- if $VERBOSE
- warn("\#{caller.shift.sub(/:in .*/, '')}: " \
- "warning: \#{self.class}\##{old} is deprecated; " \
- "use \#{self.class}\##{new}")
- end
- #{new}(*args, &block)
- end
- end;
+ deprecated_alias(old, new)
end
private :of, :newof
diff --git a/lib/date/format.rb b/lib/date/format.rb
index 4425635d33..f89c1344a9 100644
--- a/lib/date/format.rb
+++ b/lib/date/format.rb
@@ -1,603 +1,1190 @@
-# format.rb: Written by Tadayoshi Funaba 1999-2006
-# $Id: format.rb,v 2.15 2005-02-06 13:28:48+09 tadf Exp $
+# format.rb: Written by Tadayoshi Funaba 1999-2008
+# $Id: format.rb,v 2.43 2008-01-17 20:16:31+09 tadf Exp $
require 'rational'
class Date
- MONTHS = {
- 'january' => 1, 'february' => 2, 'march' => 3, 'april' => 4,
- 'may' => 5, 'june' => 6, 'july' => 7, 'august' => 8,
- 'september'=> 9, 'october' =>10, 'november' =>11, 'december' =>12
- }
-
- DAYS = {
- 'sunday' => 0, 'monday' => 1, 'tuesday' => 2, 'wednesday'=> 3,
- 'thursday' => 4, 'friday' => 5, 'saturday' => 6
- }
-
- ABBR_MONTHS = {
- 'jan' => 1, 'feb' => 2, 'mar' => 3, 'apr' => 4,
- 'may' => 5, 'jun' => 6, 'jul' => 7, 'aug' => 8,
- 'sep' => 9, 'oct' =>10, 'nov' =>11, 'dec' =>12
- }
-
- ABBR_DAYS = {
- 'sun' => 0, 'mon' => 1, 'tue' => 2, 'wed' => 3,
- 'thu' => 4, 'fri' => 5, 'sat' => 6
- }
-
- ZONES = {
- 'ut' => 0*3600, 'gmt' => 0*3600, 'est' => -5*3600, 'edt' => -4*3600,
- 'cst' => -6*3600, 'cdt' => -5*3600, 'mst' => -7*3600, 'mdt' => -6*3600,
- 'pst' => -8*3600, 'pdt' => -7*3600,
- 'a' => 1*3600, 'b' => 2*3600, 'c' => 3*3600, 'd' => 4*3600,
- 'e' => 5*3600, 'f' => 6*3600, 'g' => 7*3600, 'h' => 8*3600,
- 'i' => 9*3600, 'k' => 10*3600, 'l' => 11*3600, 'm' => 12*3600,
- 'n' => -1*3600, 'o' => -2*3600, 'p' => -3*3600, 'q' => -4*3600,
- 'r' => -5*3600, 's' => -6*3600, 't' => -7*3600, 'u' => -8*3600,
- 'v' => -9*3600, 'w' =>-10*3600, 'x' =>-11*3600, 'y' =>-12*3600,
- 'z' => 0*3600,
- 'utc' => 0*3600, 'wet' => 0*3600, 'bst' => 1*3600, 'wat' => -1*3600,
- 'at' => -2*3600, 'ast' => -4*3600, 'adt' => -3*3600, 'yst' => -9*3600,
- 'ydt' => -8*3600, 'hst' =>-10*3600, 'hdt' => -9*3600, 'cat' =>-10*3600,
- 'ahst'=>-10*3600, 'nt' =>-11*3600, 'idlw'=>-12*3600, 'cet' => 1*3600,
- 'met' => 1*3600, 'mewt'=> 1*3600, 'mest'=> 2*3600, 'mesz'=> 2*3600,
- 'swt' => 1*3600, 'sst' => 2*3600, 'fwt' => 1*3600, 'fst' => 2*3600,
- 'eet' => 2*3600, 'bt' => 3*3600, 'zp4' => 4*3600, 'zp5' => 5*3600,
- 'zp6' => 6*3600, 'wast'=> 7*3600, 'wadt'=> 8*3600, 'cct' => 8*3600,
- 'jst' => 9*3600, 'east'=> 10*3600, 'eadt'=> 11*3600, 'gst' => 10*3600,
- 'nzt' => 12*3600, 'nzst'=> 12*3600, 'nzdt'=> 13*3600, 'idle'=> 12*3600
- }
-
- def self.__strptime(str, fmt, elem)
- fmt.scan(/%[EO]?.|./mo) do |c|
- cc = c.sub(/\A%[EO]?(.)\z/mo, '%\\1')
- case cc
- when /\A\s/o
- str.sub!(/\A[\s\v]+/o, '')
- when '%A', '%a'
- return unless str.sub!(/\A([a-z]+)\b/io, '')
- val = DAYS[$1.downcase] || ABBR_DAYS[$1.downcase]
- return unless val
- elem[:wday] = val
- when '%B', '%b', '%h'
- return unless str.sub!(/\A([a-z]+)\b/io, '')
- val = MONTHS[$1.downcase] || ABBR_MONTHS[$1.downcase]
- return unless val
- elem[:mon] = val
- when '%C'
- return unless str.sub!(/\A(\d+)/o, '')
- val = $1.to_i
- elem[:cent] = val
- when '%c'
- return unless __strptime(str, '%a %b %e %H:%M:%S %Y', elem)
- when '%D'
- return unless __strptime(str, '%m/%d/%y', elem)
- when '%d', '%e'
- return unless str.sub!(/\A ?(\d+)/o, '')
- val = $1.to_i
- return unless (1..31) === val
- elem[:mday] = val
- when '%F'
- return unless __strptime(str, '%Y-%m-%d', elem)
- when '%G'
- return unless str.sub!(/\A([-+]?\d+)/o, '')
- val = $1.to_i
- elem[:cwyear] = val
- when '%g'
- return unless str.sub!(/\A(\d+)/o, '')
- val = $1.to_i
- return unless (0..99) === val
- elem[:cwyear] = val
- elem[:cent] ||= if val >= 69 then 19 else 20 end
- when '%H', '%k'
- return unless str.sub!(/\A ?(\d+)/o, '')
- val = $1.to_i
- return unless (0..24) === val
- elem[:hour] = val
- when '%I', '%l'
- return unless str.sub!(/\A ?(\d+)/o, '')
- val = $1.to_i
- return unless (1..12) === val
- elem[:hour] = val
- when '%j'
- return unless str.sub!(/\A(\d+)/o, '')
- val = $1.to_i
- return unless (1..366) === val
- elem[:yday] = val
- when '%M'
- return unless str.sub!(/\A(\d+)/o, '')
- val = $1.to_i
- return unless (0..59) === val
- elem[:min] = val
- when '%m'
- return unless str.sub!(/\A(\d+)/o, '')
- val = $1.to_i
- return unless (1..12) === val
- elem[:mon] = val
-=begin
- when '%N'
- return unless str.sub!(/\A(\d+)/o, '')
- val = $1.to_i.to_r / (10**9)
- elem[:sec_fraction] = val
-=end
- when '%n'
- return unless __strptime(str, ' ', elem)
- when '%p', '%P'
- return unless str.sub!(/\A([ap])(?:m\b|\.m\.)/io, '')
- elem[:merid] = if $1.downcase == 'a' then 0 else 12 end
- when '%R'
- return unless __strptime(str, '%H:%M', elem)
- when '%r'
- return unless __strptime(str, '%I:%M:%S %p', elem)
- when '%S'
- return unless str.sub!(/\A(\d+)/o, '')
- val = $1.to_i
- return unless (0..60) === val
- elem[:sec] = val
- when '%s'
- return unless str.sub!(/\A(\d+)/o, '')
- val = $1.to_i
- elem[:seconds] = val
- when '%T'
- return unless __strptime(str, '%H:%M:%S', elem)
- when '%t'
- return unless __strptime(str, ' ', elem)
- when '%U', '%W'
- return unless str.sub!(/\A(\d+)/o, '')
- val = $1.to_i
- return unless (0..53) === val
- elem[if c[-1,1] == 'U' then :wnum0 else :wnum1 end] = val
- when '%u'
- return unless str.sub!(/\A(\d+)/o, '')
- val = $1.to_i
- return unless (1..7) === val
- elem[:cwday] = val
- when '%V'
- return unless str.sub!(/\A(\d+)/o, '')
- val = $1.to_i
- return unless (1..53) === val
- elem[:cweek] = val
- when '%v'
- return unless __strptime(str, '%e-%b-%Y', elem)
- when '%w'
- return unless str.sub!(/\A(\d+)/o, '')
- val = $1.to_i
- return unless (0..6) === val
- elem[:wday] = val
- when '%X'
- return unless __strptime(str, '%H:%M:%S', elem)
- when '%x'
- return unless __strptime(str, '%m/%d/%y', elem)
- when '%Y'
- return unless str.sub!(/\A([-+]?\d+)/o, '')
- val = $1.to_i
- elem[:year] = val
- when '%y'
- return unless str.sub!(/\A(\d+)/o, '')
- val = $1.to_i
- return unless (0..99) === val
- elem[:year] = val
- elem[:cent] ||= if val >= 69 then 19 else 20 end
- when '%Z', '%z'
- return unless str.sub!(/\A([-+:a-z0-9]+(?:\s+dst\b)?)/io, '')
- val = $1
- elem[:zone] = val
- offset = zone_to_diff(val)
- elem[:offset] = offset
- when '%%'
- return unless str.sub!(/\A%/o, '')
- when '%+'
- return unless __strptime(str, '%a %b %e %H:%M:%S %Z %Y', elem)
-=begin
- when '%.'
- return unless str.sub!(/\A(\d+)/o, '')
- val = $1.to_i.to_r / (10**$1.size)
- elem[:sec_fraction] = val
-=end
- when '%1'
+ module Format # :nodoc:
+
+ MONTHS = {
+ 'january' => 1, 'february' => 2, 'march' => 3, 'april' => 4,
+ 'may' => 5, 'june' => 6, 'july' => 7, 'august' => 8,
+ 'september'=> 9, 'october' =>10, 'november' =>11, 'december' =>12
+ }
+
+ DAYS = {
+ 'sunday' => 0, 'monday' => 1, 'tuesday' => 2, 'wednesday'=> 3,
+ 'thursday' => 4, 'friday' => 5, 'saturday' => 6
+ }
+
+ ABBR_MONTHS = {
+ 'jan' => 1, 'feb' => 2, 'mar' => 3, 'apr' => 4,
+ 'may' => 5, 'jun' => 6, 'jul' => 7, 'aug' => 8,
+ 'sep' => 9, 'oct' =>10, 'nov' =>11, 'dec' =>12
+ }
+
+ ABBR_DAYS = {
+ 'sun' => 0, 'mon' => 1, 'tue' => 2, 'wed' => 3,
+ 'thu' => 4, 'fri' => 5, 'sat' => 6
+ }
+
+ ZONES = {
+ 'ut' => 0*3600, 'gmt' => 0*3600, 'est' => -5*3600, 'edt' => -4*3600,
+ 'cst' => -6*3600, 'cdt' => -5*3600, 'mst' => -7*3600, 'mdt' => -6*3600,
+ 'pst' => -8*3600, 'pdt' => -7*3600,
+ 'a' => 1*3600, 'b' => 2*3600, 'c' => 3*3600, 'd' => 4*3600,
+ 'e' => 5*3600, 'f' => 6*3600, 'g' => 7*3600, 'h' => 8*3600,
+ 'i' => 9*3600, 'k' => 10*3600, 'l' => 11*3600, 'm' => 12*3600,
+ 'n' => -1*3600, 'o' => -2*3600, 'p' => -3*3600, 'q' => -4*3600,
+ 'r' => -5*3600, 's' => -6*3600, 't' => -7*3600, 'u' => -8*3600,
+ 'v' => -9*3600, 'w' =>-10*3600, 'x' =>-11*3600, 'y' =>-12*3600,
+ 'z' => 0*3600,
+
+ 'utc' => 0*3600, 'wet' => 0*3600,
+ 'at' => -2*3600, 'brst'=> -2*3600, 'ndt' => -(2*3600+1800),
+ 'art' => -3*3600, 'adt' => -3*3600, 'brt' => -3*3600, 'clst'=> -3*3600,
+ 'nst' => -(3*3600+1800),
+ 'ast' => -4*3600, 'clt' => -4*3600,
+ 'akdt'=> -8*3600, 'ydt' => -8*3600,
+ 'akst'=> -9*3600, 'hadt'=> -9*3600, 'hdt' => -9*3600, 'yst' => -9*3600,
+ 'ahst'=>-10*3600, 'cat' =>-10*3600, 'hast'=>-10*3600, 'hst' =>-10*3600,
+ 'nt' =>-11*3600,
+ 'idlw'=>-12*3600,
+ 'bst' => 1*3600, 'cet' => 1*3600, 'fwt' => 1*3600, 'met' => 1*3600,
+ 'mewt'=> 1*3600, 'mez' => 1*3600, 'swt' => 1*3600, 'wat' => 1*3600,
+ 'west'=> 1*3600,
+ 'cest'=> 2*3600, 'eet' => 2*3600, 'fst' => 2*3600, 'mest'=> 2*3600,
+ 'mesz'=> 2*3600, 'sast'=> 2*3600, 'sst' => 2*3600,
+ 'bt' => 3*3600, 'eat' => 3*3600, 'eest'=> 3*3600, 'msk' => 3*3600,
+ 'msd' => 4*3600, 'zp4' => 4*3600,
+ 'zp5' => 5*3600, 'ist' => (5*3600+1800),
+ 'zp6' => 6*3600,
+ 'wast'=> 7*3600,
+ 'cct' => 8*3600, 'sgt' => 8*3600, 'wadt'=> 8*3600,
+ 'jst' => 9*3600, 'kst' => 9*3600,
+ 'east'=> 10*3600, 'gst' => 10*3600,
+ 'eadt'=> 11*3600,
+ 'idle'=> 12*3600, 'nzst'=> 12*3600, 'nzt' => 12*3600,
+ 'nzdt'=> 13*3600,
+
+ 'afghanistan' => 16200, 'alaskan' => -32400,
+ 'arab' => 10800, 'arabian' => 14400,
+ 'arabic' => 10800, 'atlantic' => -14400,
+ 'aus central' => 34200, 'aus eastern' => 36000,
+ 'azores' => -3600, 'canada central' => -21600,
+ 'cape verde' => -3600, 'caucasus' => 14400,
+ 'cen. australia' => 34200, 'central america' => -21600,
+ 'central asia' => 21600, 'central europe' => 3600,
+ 'central european' => 3600, 'central pacific' => 39600,
+ 'central' => -21600, 'china' => 28800,
+ 'dateline' => -43200, 'e. africa' => 10800,
+ 'e. australia' => 36000, 'e. europe' => 7200,
+ 'e. south america' => -10800, 'eastern' => -18000,
+ 'egypt' => 7200, 'ekaterinburg' => 18000,
+ 'fiji' => 43200, 'fle' => 7200,
+ 'greenland' => -10800, 'greenwich' => 0,
+ 'gtb' => 7200, 'hawaiian' => -36000,
+ 'india' => 19800, 'iran' => 12600,
+ 'jerusalem' => 7200, 'korea' => 32400,
+ 'mexico' => -21600, 'mid-atlantic' => -7200,
+ 'mountain' => -25200, 'myanmar' => 23400,
+ 'n. central asia' => 21600, 'nepal' => 20700,
+ 'new zealand' => 43200, 'newfoundland' => -12600,
+ 'north asia east' => 28800, 'north asia' => 25200,
+ 'pacific sa' => -14400, 'pacific' => -28800,
+ 'romance' => 3600, 'russian' => 10800,
+ 'sa eastern' => -10800, 'sa pacific' => -18000,
+ 'sa western' => -14400, 'samoa' => -39600,
+ 'se asia' => 25200, 'malay peninsula' => 28800,
+ 'south africa' => 7200, 'sri lanka' => 21600,
+ 'taipei' => 28800, 'tasmania' => 36000,
+ 'tokyo' => 32400, 'tonga' => 46800,
+ 'us eastern' => -18000, 'us mountain' => -25200,
+ 'vladivostok' => 36000, 'w. australia' => 28800,
+ 'w. central africa' => 3600, 'w. europe' => 3600,
+ 'west asia' => 18000, 'west pacific' => 36000,
+ 'yakutsk' => 32400
+ }
+
+ [MONTHS, DAYS, ABBR_MONTHS, ABBR_DAYS, ZONES].each do |x|
+ x.freeze
+ end
+
+ class Bag # :nodoc:
+
+ def initialize
+ @elem = {}
+ end
+
+ def method_missing(t, *args, &block)
+ t = t.to_s
+ set = t.chomp!('=')
+ t = t.intern
+ if set
+ @elem[t] = args[0]
+ else
+ @elem[t]
+ end
+ end
+
+ def to_hash
+ @elem.reject{|k, v| /\A_/ =~ k.to_s || v.nil?}
+ end
+
+ end
+
+ end
+
+ def emit(e, f) # :nodoc:
+ case e
+ when Numeric
+ sign = %w(+ + -)[e <=> 0]
+ e = e.abs
+ end
+
+ s = e.to_s
+
+ if f[:s] && f[:p] == '0'
+ f[:w] -= 1
+ end
+
+ if f[:s] && f[:p] == "\s"
+ s[0,0] = sign
+ end
+
+ if f[:p] != '-'
+ s = s.rjust(f[:w], f[:p])
+ end
+
+ if f[:s] && f[:p] != "\s"
+ s[0,0] = sign
+ end
+
+ s = s.upcase if f[:u]
+ s = s.downcase if f[:d]
+ s
+ end
+
+ def emit_w(e, w, f) # :nodoc:
+ f[:w] = [f[:w], w].compact.max
+ emit(e, f)
+ end
+
+ def emit_n(e, w, f) # :nodoc:
+ f[:p] ||= '0'
+ emit_w(e, w, f)
+ end
+
+ def emit_sn(e, w, f) # :nodoc:
+ if e < 0
+ w += 1
+ f[:s] = true
+ end
+ emit_n(e, w, f)
+ end
+
+ def emit_z(e, w, f) # :nodoc:
+ w += 1
+ f[:s] = true
+ emit_n(e, w, f)
+ end
+
+ def emit_a(e, w, f) # :nodoc:
+ f[:p] ||= "\s"
+ emit_w(e, w, f)
+ end
+
+ def emit_ad(e, w, f) # :nodoc:
+ if f[:x]
+ f[:u] = true
+ f[:d] = false
+ end
+ emit_a(e, w, f)
+ end
+
+ def emit_au(e, w, f) # :nodoc:
+ if f[:x]
+ f[:u] = false
+ f[:d] = true
+ end
+ emit_a(e, w, f)
+ end
+
+ private :emit, :emit_w, :emit_n, :emit_sn, :emit_z,
+ :emit_a, :emit_ad, :emit_au
+
+ def strftime(fmt='%F')
+ fmt.gsub(/%([-_0^#]+)?(\d+)?([EO]?(?::{1,3}z|.))/m) do |m|
+ f = {}
+ a = $&
+ s, w, c = $1, $2, $3
+ if s
+ s.scan(/./) do |k|
+ case k
+ when '-'; f[:p] = '-'
+ when '_'; f[:p] = "\s"
+ when '0'; f[:p] = '0'
+ when '^'; f[:u] = true
+ when '#'; f[:x] = true
+ end
+ end
+ end
+ if w
+ f[:w] = w.to_i
+ end
+ case c
+ when 'A'; emit_ad(DAYNAMES[wday], 0, f)
+ when 'a'; emit_ad(ABBR_DAYNAMES[wday], 0, f)
+ when 'B'; emit_ad(MONTHNAMES[mon], 0, f)
+ when 'b'; emit_ad(ABBR_MONTHNAMES[mon], 0, f)
+ when 'C', 'EC'; emit_sn((year / 100).floor, 2, f)
+ when 'c', 'Ec'; emit_a(strftime('%a %b %e %H:%M:%S %Y'), 0, f)
+ when 'D'; emit_a(strftime('%m/%d/%y'), 0, f)
+ when 'd', 'Od'; emit_n(mday, 2, f)
+ when 'e', 'Oe'; emit_a(mday, 2, f)
+ when 'F'
+ if m == '%F'
+ format('%.4d-%02d-%02d', year, mon, mday) # 4p
+ else
+ emit_a(strftime('%Y-%m-%d'), 0, f)
+ end
+ when 'G'; emit_sn(cwyear, 4, f)
+ when 'g'; emit_n(cwyear % 100, 2, f)
+ when 'H', 'OH'; emit_n(hour, 2, f)
+ when 'h'; emit_ad(strftime('%b'), 0, f)
+ when 'I', 'OI'; emit_n((hour % 12).nonzero? || 12, 2, f)
+ when 'j'; emit_n(yday, 3, f)
+ when 'k'; emit_a(hour, 2, f)
+ when 'L'
+ emit_n((sec_fraction / MILLISECONDS_IN_DAY).floor, 3, f)
+ when 'l'; emit_a((hour % 12).nonzero? || 12, 2, f)
+ when 'M', 'OM'; emit_n(min, 2, f)
+ when 'm', 'Om'; emit_n(mon, 2, f)
+ when 'N'
+ emit_n((sec_fraction / NANOSECONDS_IN_DAY).floor, 9, f)
+ when 'n'; "\n"
+ when 'P'; emit_ad(strftime('%p').downcase, 0, f)
+ when 'p'; emit_au(if hour < 12 then 'AM' else 'PM' end, 0, f)
+ when 'Q'
+ s = ((ajd - UNIX_EPOCH_IN_AJD) / MILLISECONDS_IN_DAY).round
+ emit_sn(s, 1, f)
+ when 'R'; emit_a(strftime('%H:%M'), 0, f)
+ when 'r'; emit_a(strftime('%I:%M:%S %p'), 0, f)
+ when 'S', 'OS'; emit_n(sec, 2, f)
+ when 's'
+ s = ((ajd - UNIX_EPOCH_IN_AJD) / SECONDS_IN_DAY).round
+ emit_sn(s, 1, f)
+ when 'T'
+ if m == '%T'
+ format('%02d:%02d:%02d', hour, min, sec) # 4p
+ else
+ emit_a(strftime('%H:%M:%S'), 0, f)
+ end
+ when 't'; "\t"
+ when 'U', 'W', 'OU', 'OW'
+ emit_n(if c[-1,1] == 'U' then wnum0 else wnum1 end, 2, f)
+ when 'u', 'Ou'; emit_n(cwday, 1, f)
+ when 'V', 'OV'; emit_n(cweek, 2, f)
+ when 'v'; emit_a(strftime('%e-%b-%Y'), 0, f)
+ when 'w', 'Ow'; emit_n(wday, 1, f)
+ when 'X', 'EX'; emit_a(strftime('%H:%M:%S'), 0, f)
+ when 'x', 'Ex'; emit_a(strftime('%m/%d/%y'), 0, f)
+ when 'Y', 'EY'; emit_sn(year, 4, f)
+ when 'y', 'Ey', 'Oy'; emit_n(year % 100, 2, f)
+ when 'Z'; emit_au(strftime('%:z'), 0, f)
+ when /\A(:{0,3})z/
+ t = $1.size
+ sign = if offset < 0 then -1 else +1 end
+ fr = offset.abs
+ ss = fr.div(SECONDS_IN_DAY) # 4p
+ hh, ss = ss.divmod(3600)
+ mm, ss = ss.divmod(60)
+ if t == 3
+ if ss.nonzero? then t = 2
+ elsif mm.nonzero? then t = 1
+ else t = -1
+ end
+ end
+ case t
+ when -1
+ tail = []
+ sep = ''
+ when 0
+ f[:w] -= 2 if f[:w]
+ tail = ['%02d' % mm]
+ sep = ''
+ when 1
+ f[:w] -= 3 if f[:w]
+ tail = ['%02d' % mm]
+ sep = ':'
+ when 2
+ f[:w] -= 6 if f[:w]
+ tail = ['%02d' % mm, '%02d' % ss]
+ sep = ':'
+ end
+ ([emit_z(sign * hh, 2, f)] + tail).join(sep)
+ when '%'; emit_a('%', 0, f)
+ when '+'; emit_a(strftime('%a %b %e %H:%M:%S %Z %Y'), 0, f)
+ when '1'
if $VERBOSE
- warn("warning: %1 is deprecated; forget this")
+ warn("warning: strftime: %1 is deprecated; forget this")
end
- return unless str.sub!(/\A(\d+)/o, '')
- val = $1.to_i
- elem[:jd] = val
- when '%2'
+ emit_n(jd, 1, f)
+ when '2'
if $VERBOSE
- warn("warning: %2 is deprecated; use '%Y-%j'")
+ warn("warning: strftime: %2 is deprecated; use '%Y-%j'")
end
- return unless __strptime(str, '%Y-%j', elem)
- when '%3'
+ emit_a(strftime('%Y-%j'), 0, f)
+ when '3'
if $VERBOSE
- warn("warning: %3 is deprecated; use '%F'")
+ warn("warning: strftime: %3 is deprecated; use '%F'")
end
- return unless __strptime(str, '%F', elem)
- when /\A%(.)/m
- return unless str.sub!(Regexp.new('\\A' + Regexp.quote($1)), '')
+ emit_a(strftime('%F'), 0, f)
else
- return unless str.sub!(Regexp.new('\\A' + Regexp.quote(c)), '')
+ a
end
end
+ end
- if cent = elem.delete(:cent)
- if elem[:cwyear]
- elem[:cwyear] += cent * 100
- end
- if elem[:year]
- elem[:year] += cent * 100
+# alias_method :format, :strftime
+
+ def asctime() strftime('%c') end
+
+ alias_method :ctime, :asctime
+
+=begin
+ def iso8601() strftime('%F') end
+
+ def rfc3339() iso8601 end
+
+ def rfc2822() strftime('%a, %-d %b %Y %T %z') end
+
+ alias_method :rfc822, :rfc2822
+
+ def jisx0301
+ if jd < 2405160
+ iso8601
+ else
+ case jd
+ when 2405160...2419614
+ g = 'M%02d' % (year - 1867)
+ when 2419614...2424875
+ g = 'T%02d' % (year - 1911)
+ when 2424875...2447535
+ g = 'S%02d' % (year - 1925)
+ else
+ g = 'H%02d' % (year - 1988)
end
+ g + strftime('.%m.%d')
end
+ end
- if merid = elem.delete(:merid)
- if elem[:hour]
- elem[:hour] %= 12
- elem[:hour] += merid
+ def beat(n=0)
+ i, f = (new_offset(HOURS_IN_DAY).day_fraction * 1000).divmod(1)
+ ('@%03d' % i) +
+ if n < 1
+ ''
+ else
+ '.%0*d' % [n, (f / Rational(1, 10**n)).round]
end
- end
+ end
+=end
- str
+ def self.num_pattern? (s) # :nodoc:
+ /\A%[EO]?[CDdeFGgHIjkLlMmNQRrSsTUuVvWwXxYy\d]/ =~ s || /\A\d/ =~ s
end
- private_class_method :__strptime
+ private_class_method :num_pattern?
- def self._strptime(str, fmt='%F')
- elem = {}
- elem if __strptime(str.dup, fmt, elem)
+ def self._strptime_i(str, fmt, e) # :nodoc:
+ fmt.scan(/%([EO]?(?::{1,3}z|.))|(.)/m) do |s, c|
+ a = $&
+ if s
+ case s
+ when 'A', 'a'
+ return unless str.sub!(/\A(#{Format::DAYS.keys.join('|')})/io, '') ||
+ str.sub!(/\A(#{Format::ABBR_DAYS.keys.join('|')})/io, '')
+ val = Format::DAYS[$1.downcase] || Format::ABBR_DAYS[$1.downcase]
+ return unless val
+ e.wday = val
+ when 'B', 'b', 'h'
+ return unless str.sub!(/\A(#{Format::MONTHS.keys.join('|')})/io, '') ||
+ str.sub!(/\A(#{Format::ABBR_MONTHS.keys.join('|')})/io, '')
+ val = Format::MONTHS[$1.downcase] || Format::ABBR_MONTHS[$1.downcase]
+ return unless val
+ e.mon = val
+ when 'C', 'EC'
+ return unless str.sub!(if num_pattern?($')
+ then /\A([-+]?\d{1,2})/
+ else /\A([-+]?\d{1,})/
+ end, '')
+ val = $1.to_i
+ e._cent = val
+ when 'c', 'Ec'
+ return unless _strptime_i(str, '%a %b %e %H:%M:%S %Y', e)
+ when 'D'
+ return unless _strptime_i(str, '%m/%d/%y', e)
+ when 'd', 'e', 'Od', 'Oe'
+ return unless str.sub!(/\A( \d|\d{1,2})/, '')
+ val = $1.to_i
+ return unless (1..31) === val
+ e.mday = val
+ when 'F'
+ return unless _strptime_i(str, '%Y-%m-%d', e)
+ when 'G'
+ return unless str.sub!(if num_pattern?($')
+ then /\A([-+]?\d{1,4})/
+ else /\A([-+]?\d{1,})/
+ end, '')
+ val = $1.to_i
+ e.cwyear = val
+ when 'g'
+ return unless str.sub!(/\A(\d{1,2})/, '')
+ val = $1.to_i
+ return unless (0..99) === val
+ e.cwyear = val
+ e._cent ||= if val >= 69 then 19 else 20 end
+ when 'H', 'k', 'OH'
+ return unless str.sub!(/\A( \d|\d{1,2})/, '')
+ val = $1.to_i
+ return unless (0..24) === val
+ e.hour = val
+ when 'I', 'l', 'OI'
+ return unless str.sub!(/\A( \d|\d{1,2})/, '')
+ val = $1.to_i
+ return unless (1..12) === val
+ e.hour = val
+ when 'j'
+ return unless str.sub!(/\A(\d{1,3})/, '')
+ val = $1.to_i
+ return unless (1..366) === val
+ e.yday = val
+ when 'L'
+ return unless str.sub!(if num_pattern?($')
+ then /\A([-+]?\d{1,3})/
+ else /\A([-+]?\d{1,})/
+ end, '')
+# val = Rational($1.to_i, 10**3)
+ val = Rational($1.to_i, 10**$1.size)
+ e.sec_fraction = val
+ when 'M', 'OM'
+ return unless str.sub!(/\A(\d{1,2})/, '')
+ val = $1.to_i
+ return unless (0..59) === val
+ e.min = val
+ when 'm', 'Om'
+ return unless str.sub!(/\A(\d{1,2})/, '')
+ val = $1.to_i
+ return unless (1..12) === val
+ e.mon = val
+ when 'N'
+ return unless str.sub!(if num_pattern?($')
+ then /\A([-+]?\d{1,9})/
+ else /\A([-+]?\d{1,})/
+ end, '')
+# val = Rational($1.to_i, 10**9)
+ val = Rational($1.to_i, 10**$1.size)
+ e.sec_fraction = val
+ when 'n', 't'
+ return unless _strptime_i(str, "\s", e)
+ when 'P', 'p'
+ return unless str.sub!(/\A([ap])(?:m\b|\.m\.)/i, '')
+ e._merid = if $1.downcase == 'a' then 0 else 12 end
+ when 'Q'
+ return unless str.sub!(/\A(-?\d{1,})/, '')
+ val = Rational($1.to_i, 10**3)
+ e.seconds = val
+ when 'R'
+ return unless _strptime_i(str, '%H:%M', e)
+ when 'r'
+ return unless _strptime_i(str, '%I:%M:%S %p', e)
+ when 'S', 'OS'
+ return unless str.sub!(/\A(\d{1,2})/, '')
+ val = $1.to_i
+ return unless (0..60) === val
+ e.sec = val
+ when 's'
+ return unless str.sub!(/\A(-?\d{1,})/, '')
+ val = $1.to_i
+ e.seconds = val
+ when 'T'
+ return unless _strptime_i(str, '%H:%M:%S', e)
+ when 'U', 'W', 'OU', 'OW'
+ return unless str.sub!(/\A(\d{1,2})/, '')
+ val = $1.to_i
+ return unless (0..53) === val
+ e.__send__(if s[-1,1] == 'U' then :wnum0= else :wnum1= end, val)
+ when 'u', 'Ou'
+ return unless str.sub!(/\A(\d{1})/, '')
+ val = $1.to_i
+ return unless (1..7) === val
+ e.cwday = val
+ when 'V', 'OV'
+ return unless str.sub!(/\A(\d{1,2})/, '')
+ val = $1.to_i
+ return unless (1..53) === val
+ e.cweek = val
+ when 'v'
+ return unless _strptime_i(str, '%e-%b-%Y', e)
+ when 'w'
+ return unless str.sub!(/\A(\d{1})/, '')
+ val = $1.to_i
+ return unless (0..6) === val
+ e.wday = val
+ when 'X', 'EX'
+ return unless _strptime_i(str, '%H:%M:%S', e)
+ when 'x', 'Ex'
+ return unless _strptime_i(str, '%m/%d/%y', e)
+ when 'Y', 'EY'
+ return unless str.sub!(if num_pattern?($')
+ then /\A([-+]?\d{1,4})/
+ else /\A([-+]?\d{1,})/
+ end, '')
+ val = $1.to_i
+ e.year = val
+ when 'y', 'Ey', 'Oy'
+ return unless str.sub!(/\A(\d{1,2})/, '')
+ val = $1.to_i
+ return unless (0..99) === val
+ e.year = val
+ e._cent ||= if val >= 69 then 19 else 20 end
+ when 'Z', /\A:{0,3}z/
+ return unless str.sub!(/\A((?:gmt|utc?)?[-+]\d+(?:[,.:]\d+(?::\d+)?)?
+ |[[:alpha:].\s]+(?:standard|daylight)\s+time\b
+ |[[:alpha:]]+(?:\s+dst)?\b
+ )/ix, '')
+ val = $1
+ e.zone = val
+ offset = zone_to_diff(val)
+ e.offset = offset
+ when '%'
+ return unless str.sub!(/\A%/, '')
+ when '+'
+ return unless _strptime_i(str, '%a %b %e %H:%M:%S %Z %Y', e)
+ when '1'
+ if $VERBOSE
+ warn("warning: strptime: %1 is deprecated; forget this")
+ end
+ return unless str.sub!(/\A(\d+)/, '')
+ val = $1.to_i
+ e.jd = val
+ when '2'
+ if $VERBOSE
+ warn("warning: strptime: %2 is deprecated; use '%Y-%j'")
+ end
+ return unless _strptime_i(str, '%Y-%j', e)
+ when '3'
+ if $VERBOSE
+ warn("warning: strptime: %3 is deprecated; use '%F'")
+ end
+ return unless _strptime_i(str, '%F', e)
+ else
+ return unless str.sub!(Regexp.new('\\A' + Regexp.quote(a)), '')
+ end
+ else
+ case c
+ when /\A[\s\v]/
+ str.sub!(/\A[\s\v]+/, '')
+ else
+ return unless str.sub!(Regexp.new('\\A' + Regexp.quote(a)), '')
+ end
+ end
+ end
end
- PARSE_MONTHPAT = ABBR_MONTHS.keys.join('|')
- PARSE_DAYPAT = ABBR_DAYS. keys.join('|')
+ private_class_method :_strptime_i
- def self._parse(str, comp=false)
+ def self._strptime(str, fmt='%F')
str = str.dup
+ e = Format::Bag.new
+ return unless _strptime_i(str, fmt, e)
+
+ if e._cent
+ if e.cwyear
+ e.cwyear += e._cent * 100
+ end
+ if e.year
+ e. year += e._cent * 100
+ end
+ end
+
+ if e._merid
+ if e.hour
+ e.hour %= 12
+ e.hour += e._merid
+ end
+ end
+
+ unless str.empty?
+ e.leftover = str
+ end
+
+ e.to_hash
+ end
+
+ def self.s3e(e, y, m, d, bc=false)
+ unless String === m
+ m = m.to_s
+ end
+
+ if y && m && !d
+ y, m, d = d, y, m
+ end
+
+ if y == nil
+ if d && d.size > 2
+ y = d
+ d = nil
+ end
+ if d && d[0,1] == "'"
+ y = d
+ d = nil
+ end
+ end
- str.gsub!(/[^-+,.\/:0-9a-z]+/ino, ' ')
+ if y
+ y.scan(/(\d+)(.+)?/)
+ if $2
+ y, d = d, $1
+ end
+ end
- # day
- if str.sub!(/(#{PARSE_DAYPAT})\S*/ino, ' ')
- wday = ABBR_DAYS[$1.downcase]
+ if m
+ if m[0,1] == "'" || m.size > 2
+ y, m, d = m, d, y # us -> be
+ end
end
- # time
+ if d
+ if d[0,1] == "'" || d.size > 2
+ y, d = d, y
+ end
+ end
+
+ if y
+ y =~ /([-+])?(\d+)/
+ if $1 || $2.size > 2
+ c = false
+ end
+ iy = $&.to_i
+ if bc
+ iy = -iy + 1
+ end
+ e.year = iy
+ end
+
+ if m
+ m =~ /\d+/
+ e.mon = $&.to_i
+ end
+
+ if d
+ d =~ /\d+/
+ e.mday = $&.to_i
+ end
+
+ if c != nil
+ e._comp = c
+ end
+
+ end
+
+ private_class_method :s3e
+
+ def self._parse_day(str, e) # :nodoc:
+ if str.sub!(/\b(#{Format::ABBR_DAYS.keys.join('|')})[^-\d\s]*/ino, ' ')
+ e.wday = Format::ABBR_DAYS[$1.downcase]
+ true
+=begin
+ elsif str.sub!(/\b(?!\dth)(su|mo|tu|we|th|fr|sa)\b/in, ' ')
+ e.wday = %w(su mo tu we th fr sa).index($1.downcase)
+ true
+=end
+ end
+ end
+
+ def self._parse_time(str, e) # :nodoc:
if str.sub!(
- /(\d+):(\d+)
- (?:
- :(\d+)(?:[,.](\d*))?
- )?
- (?:
- \s*
- ([ap])(?:m\b|\.m\.)
- )?
+ /(
+ (?:
+ \d+\s*:\s*\d+
+ (?:
+ \s*:\s*\d+(?:[,.]\d*)?
+ )?
+ |
+ \d+\s*h(?:\s*\d+m?(?:\s*\d+s?)?)?
+ )
+ (?:
+ \s*
+ [ap](?:m\b|\.m\.)
+ )?
+ |
+ \d+\s*[ap](?:m\b|\.m\.)
+ )
(?:
\s*
(
- [a-z]+(?:\s+dst)?\b
+ (?:gmt|utc?)?[-+]\d+(?:[,.:]\d+(?::\d+)?)?
|
- [-+]\d+(?::?\d+)
+ [[:alpha:].\s]+(?:standard|daylight)\stime\b
+ |
+ [[:alpha:]]+(?:\sdst)?\b
)
)?
- /inox,
+ /inx,
' ')
- hour = $1.to_i
- min = $2.to_i
- sec = $3.to_i if $3
- if $4
- sec_fraction = $4.to_i.to_r / (10**$4.size)
- end
+
+ t = $1
+ e.zone = $2 if $2
+
+ t =~ /\A(\d+)h?
+ (?:\s*:?\s*(\d+)m?
+ (?:
+ \s*:?\s*(\d+)(?:[,.](\d+))?s?
+ )?
+ )?
+ (?:\s*([ap])(?:m\b|\.m\.))?/inx
+
+ e.hour = $1.to_i
+ e.min = $2.to_i if $2
+ e.sec = $3.to_i if $3
+ e.sec_fraction = Rational($4.to_i, 10**$4.size) if $4
if $5
- hour %= 12
+ e.hour %= 12
if $5.downcase == 'p'
- hour += 12
+ e.hour += 12
end
end
+ true
+ end
+ end
- if $6
- zone = $6
- end
+=begin
+ def self._parse_beat(str, e) # :nodoc:
+ if str.sub!(/@\s*(\d+)(?:[,.](\d*))?/, ' ')
+ beat = Rational($1.to_i)
+ beat += Rational($2.to_i, 10**$2.size) if $2
+ secs = Rational(beat, 1000)
+ h, min, s, fr = self.day_fraction_to_time(secs)
+ e.hour = h
+ e.min = min
+ e.sec = s
+ e.sec_fraction = fr * 86400
+ e.zone = '+01:00'
+ true
end
+ end
+=end
- # eu
+ def self._parse_eu(str, e) # :nodoc:
if str.sub!(
- /(\d+)\S*
- \s+
- (#{PARSE_MONTHPAT})\S*
+ /'?(\d+)[^-\d\s]*
+ \s*
+ (#{Format::ABBR_MONTHS.keys.join('|')})[^-\d\s']*
(?:
- \s+
- (-?\d+)
+ \s*
+ (c(?:e|\.e\.)|b(?:ce|\.c\.e\.)|a(?:d|\.d\.)|b(?:c|\.c\.))?
+ \s*
+ ('?-?\d+(?:(?:st|nd|rd|th)\b)?)
)?
/inox,
- ' ')
- mday = $1.to_i
- mon = ABBR_MONTHS[$2.downcase]
-
- if $3
- year = $3.to_i
- if $3.size > 2
- comp = false
- end
- end
+ ' ') # '
+ s3e(e, $4, Format::ABBR_MONTHS[$2.downcase], $1,
+ $3 && $3[0,1].downcase == 'b')
+ true
+ end
+ end
- # us
- elsif str.sub!(
- /(#{PARSE_MONTHPAT})\S*
- \s+
- (\d+)\S*
- (?:
- \s+
- (-?\d+)
- )?
- /inox,
- ' ')
- mon = ABBR_MONTHS[$1.downcase]
- mday = $2.to_i
+ def self._parse_us(str, e) # :nodoc:
+ if str.sub!(
+ /\b(#{Format::ABBR_MONTHS.keys.join('|')})[^-\d\s']*
+ \s*
+ ('?\d+)[^-\d\s']*
+ (?:
+ \s*
+ (c(?:e|\.e\.)|b(?:ce|\.c\.e\.)|a(?:d|\.d\.)|b(?:c|\.c\.))?
+ \s*
+ ('?-?\d+)
+ )?
+ /inox,
+ ' ') # '
+ s3e(e, $4, Format::ABBR_MONTHS[$1.downcase], $2,
+ $3 && $3[0,1].downcase == 'b')
+ true
+ end
+ end
- if $3
- year = $3.to_i
- if $3.size > 2
- comp = false
- end
- end
+ def self._parse_iso(str, e) # :nodoc:
+ if str.sub!(/('?[-+]?\d+)-(\d+)-('?-?\d+)/n, ' ')
+ s3e(e, $1, $2, $3)
+ true
+ end
+ end
- # iso
- elsif str.sub!(/([-+]?\d+)-(\d+)-(-?\d+)/no, ' ')
- year = $1.to_i
- mon = $2.to_i
- mday = $3.to_i
-
- if $1.size > 2
- comp = false
- elsif $3.size > 2
- comp = false
- mday, mon, year = year, mon, mday
- end
+ def self._parse_iso2(str, e) # :nodoc:
+ if str.sub!(/\b(\d{2}|\d{4})?-?w(\d{2})(?:-?(\d))?\b/in, ' ')
+ e.cwyear = $1.to_i if $1
+ e.cweek = $2.to_i
+ e.cwday = $3.to_i if $3
+ true
+ elsif str.sub!(/-w-(\d)\b/in, ' ')
+ e.cwday = $1.to_i
+ true
+ elsif str.sub!(/--(\d{2})?-(\d{2})\b/n, ' ')
+ e.mon = $1.to_i if $1
+ e.mday = $2.to_i
+ true
+ elsif str.sub!(/--(\d{2})(\d{2})?\b/n, ' ')
+ e.mon = $1.to_i
+ e.mday = $2.to_i if $2
+ true
+ elsif /[,.](\d{2}|\d{4})-\d{3}\b/n !~ str &&
+ str.sub!(/\b(\d{2}|\d{4})-(\d{3})\b/n, ' ')
+ e.year = $1.to_i
+ e.yday = $2.to_i
+ true
+ elsif /\d-\d{3}\b/n !~ str &&
+ str.sub!(/\b-(\d{3})\b/n, ' ')
+ e.yday = $1.to_i
+ true
+ end
+ end
- # jis
- elsif str.sub!(/([MTSH])(\d+)\.(\d+)\.(\d+)/ino, ' ')
- e = { 'm'=>1867,
- 't'=>1911,
- 's'=>1925,
- 'h'=>1988
+ def self._parse_jis(str, e) # :nodoc:
+ if str.sub!(/\b([mtsh])(\d+)\.(\d+)\.(\d+)/in, ' ')
+ era = { 'm'=>1867,
+ 't'=>1911,
+ 's'=>1925,
+ 'h'=>1988
}[$1.downcase]
- year = $2.to_i + e
- mon = $3.to_i
- mday = $4.to_i
-
- # vms
- elsif str.sub!(/(-?\d+)-(#{PARSE_MONTHPAT})[^-]*-(-?\d+)/ino, ' ')
- mday = $1.to_i
- mon = ABBR_MONTHS[$2.downcase]
- year = $3.to_i
-
- if $1.size > 2
- comp = false
- year, mon, mday = mday, mon, year
- elsif $3.size > 2
- comp = false
- end
+ e.year = $2.to_i + era
+ e.mon = $3.to_i
+ e.mday = $4.to_i
+ true
+ end
+ end
- # sla
- elsif str.sub!(%r|(-?\d+)/(\d+)(?:/(-?\d+))?|no, ' ')
- mon = $1.to_i
- mday = $2.to_i
+ def self._parse_vms(str, e) # :nodoc:
+ if str.sub!(/('?-?\d+)-(#{Format::ABBR_MONTHS.keys.join('|')})[^-]*
+ -('?-?\d+)/inox, ' ')
+ s3e(e, $3, Format::ABBR_MONTHS[$2.downcase], $1)
+ true
+ elsif str.sub!(/\b(#{Format::ABBR_MONTHS.keys.join('|')})[^-]*
+ -('?-?\d+)(?:-('?-?\d+))?/inox, ' ')
+ s3e(e, $3, Format::ABBR_MONTHS[$1.downcase], $2)
+ true
+ end
+ end
- if $3
- year = $3.to_i
- if $3.size > 2
- comp = false
- end
- end
+ def self._parse_sla(str, e) # :nodoc:
+ if str.sub!(%r|('?-?\d+)/\s*('?\d+)(?:\D\s*('?-?\d+))?|n, ' ') # '
+ s3e(e, $3, $1, $2)
+ true
+ end
+ end
- if $3 && $1.size > 2
- comp = false
- year, mon, mday = mon, mday, year
- end
+ def self._parse_dot(str, e) # :nodoc:
+ if str.sub!(%r|('?-?\d+)\.\s*('?\d+)\.\s*('?-?\d+)|n, ' ') # '
+ s3e(e, $1, $2, $3)
+ true
+ end
+ end
- # ddd
- elsif str.sub!(
- /([-+]?)(\d{4,14})
- (?:
- \s*
- T?
- \s*
- (\d{2,6})(?:[,.](\d*))?
- )?
- (?:
- \s*
- (
- Z
- |
- [-+]\d{2,4}
- )
- \b
- )?
- /inox,
- ' ')
+ def self._parse_year(str, e) # :nodoc:
+ if str.sub!(/'(\d+)\b/n, ' ')
+ e.year = $1.to_i
+ true
+ end
+ end
+
+ def self._parse_mon(str, e) # :nodoc:
+ if str.sub!(/\b(#{Format::ABBR_MONTHS.keys.join('|')})\S*/ino, ' ')
+ e.mon = Format::ABBR_MONTHS[$1.downcase]
+ true
+ end
+ end
+
+ def self._parse_mday(str, e) # :nodoc:
+ if str.sub!(/(\d+)(st|nd|rd|th)\b/in, ' ')
+ e.mday = $1.to_i
+ true
+ end
+ end
+
+ def self._parse_ddd(str, e) # :nodoc:
+ if str.sub!(
+ /([-+]?)(\d{2,14})
+ (?:
+ \s*
+ t?
+ \s*
+ (\d{2,6})?(?:[,.](\d*))?
+ )?
+ (?:
+ \s*
+ (
+ z\b
+ |
+ [-+]\d{1,4}\b
+ |
+ \[[-+]?\d[^\]]*\]
+ )
+ )?
+ /inx,
+ ' ')
case $2.size
+ when 2
+ if $3.nil? && $4
+ e.sec = $2[-2, 2].to_i
+ else
+ e.mday = $2[ 0, 2].to_i
+ end
when 4
- mon = $2[ 0, 2].to_i
- mday = $2[ 2, 2].to_i
+ if $3.nil? && $4
+ e.sec = $2[-2, 2].to_i
+ e.min = $2[-4, 2].to_i
+ else
+ e.mon = $2[ 0, 2].to_i
+ e.mday = $2[ 2, 2].to_i
+ end
when 6
- year = ($1 + $2[ 0, 2]).to_i
- mon = $2[ 2, 2].to_i
- mday = $2[ 4, 2].to_i
+ if $3.nil? && $4
+ e.sec = $2[-2, 2].to_i
+ e.min = $2[-4, 2].to_i
+ e.hour = $2[-6, 2].to_i
+ else
+ e.year = ($1 + $2[ 0, 2]).to_i
+ e.mon = $2[ 2, 2].to_i
+ e.mday = $2[ 4, 2].to_i
+ end
when 8, 10, 12, 14
- year = ($1 + $2[ 0, 4]).to_i
- mon = $2[ 4, 2].to_i
- mday = $2[ 6, 2].to_i
- hour = $2[ 8, 2].to_i if $2.size >= 10
- min = $2[10, 2].to_i if $2.size >= 12
- sec = $2[12, 2].to_i if $2.size >= 14
- comp = false
+ if $3.nil? && $4
+ e.sec = $2[-2, 2].to_i
+ e.min = $2[-4, 2].to_i
+ e.hour = $2[-6, 2].to_i
+ e.mday = $2[-8, 2].to_i
+ if $2.size >= 10
+ e.mon = $2[-10, 2].to_i
+ end
+ if $2.size == 12
+ e.year = ($1 + $2[-12, 2]).to_i
+ end
+ if $2.size == 14
+ e.year = ($1 + $2[-14, 4]).to_i
+ e._comp = false
+ end
+ else
+ e.year = ($1 + $2[ 0, 4]).to_i
+ e.mon = $2[ 4, 2].to_i
+ e.mday = $2[ 6, 2].to_i
+ e.hour = $2[ 8, 2].to_i if $2.size >= 10
+ e.min = $2[10, 2].to_i if $2.size >= 12
+ e.sec = $2[12, 2].to_i if $2.size >= 14
+ e._comp = false
+ end
+ when 3
+ if $3.nil? && $4
+ e.sec = $2[-2, 2].to_i
+ e.min = $2[-3, 1].to_i
+ else
+ e.yday = $2[ 0, 3].to_i
+ end
+ when 5
+ if $3.nil? && $4
+ e.sec = $2[-2, 2].to_i
+ e.min = $2[-4, 2].to_i
+ e.hour = $2[-5, 1].to_i
+ else
+ e.year = ($1 + $2[ 0, 2]).to_i
+ e.yday = $2[ 2, 3].to_i
+ end
+ when 7
+ if $3.nil? && $4
+ e.sec = $2[-2, 2].to_i
+ e.min = $2[-4, 2].to_i
+ e.hour = $2[-6, 2].to_i
+ e.mday = $2[-7, 1].to_i
+ else
+ e.year = ($1 + $2[ 0, 4]).to_i
+ e.yday = $2[ 4, 3].to_i
+ end
end
if $3
- case $3.size
- when 2, 4, 6
- hour = $3[ 0, 2].to_i
- min = $3[ 2, 2].to_i if $3.size >= 4
- sec = $3[ 4, 2].to_i if $3.size >= 6
+ if $4
+ case $3.size
+ when 2, 4, 6
+ e.sec = $3[-2, 2].to_i
+ e.min = $3[-4, 2].to_i if $3.size >= 4
+ e.hour = $3[-6, 2].to_i if $3.size >= 6
+ end
+ else
+ case $3.size
+ when 2, 4, 6
+ e.hour = $3[ 0, 2].to_i
+ e.min = $3[ 2, 2].to_i if $3.size >= 4
+ e.sec = $3[ 4, 2].to_i if $3.size >= 6
+ end
end
end
if $4
- sec_fraction = $4.to_i.to_r / (10**$4.size)
+ e.sec_fraction = Rational($4.to_i, 10**$4.size)
end
if $5
- zone = $5
+ e.zone = $5
+ if e.zone[0,1] == '['
+ o, n, = e.zone[1..-2].split(':')
+ e.zone = n || o
+ if /\A\d/ =~ o
+ o = format('+%s', o)
+ end
+ e.offset = zone_to_diff(o)
+ end
end
+ true
end
+ end
- if str.sub!(/\b(bc\b|bce\b|b\.c\.|b\.c\.e\.)/ino, ' ')
- if year
- year = -year + 1
+ private_class_method :_parse_day, :_parse_time, # :_parse_beat,
+ :_parse_eu, :_parse_us, :_parse_iso, :_parse_iso2,
+ :_parse_jis, :_parse_vms, :_parse_sla, :_parse_dot,
+ :_parse_year, :_parse_mon, :_parse_mday, :_parse_ddd
+
+ def self._parse(str, comp=false)
+ str = str.dup
+
+ e = Format::Bag.new
+
+ e._comp = comp
+
+ str.gsub!(/[^-+',.\/:@[:alnum:]\[\]\x80-\xff]+/n, ' ')
+
+ _parse_time(str, e) # || _parse_beat(str, e)
+ _parse_day(str, e)
+
+ _parse_eu(str, e) ||
+ _parse_us(str, e) ||
+ _parse_iso(str, e) ||
+ _parse_jis(str, e) ||
+ _parse_vms(str, e) ||
+ _parse_sla(str, e) ||
+ _parse_dot(str, e) ||
+ _parse_iso2(str, e) ||
+ _parse_year(str, e) ||
+ _parse_mon(str, e) ||
+ _parse_mday(str, e) ||
+ _parse_ddd(str, e)
+
+ if str.sub!(/\b(bc\b|bce\b|b\.c\.|b\.c\.e\.)/in, ' ')
+ if e.year
+ e.year = -e.year + 1
end
end
- if comp and year
- if year >= 0 and year <= 99
- if year >= 69
- year += 1900
- else
- year += 2000
+ if str.sub!(/\A\s*(\d{1,2})\s*\z/n, ' ')
+ if e.hour && !e.mday
+ v = $1.to_i
+ if (1..31) === v
+ e.mday = v
+ end
+ end
+ if e.mday && !e.hour
+ v = $1.to_i
+ if (0..24) === v
+ e.hour = v
end
end
end
- elem = {}
- elem[:year] = year if year
- elem[:mon] = mon if mon
- elem[:mday] = mday if mday
- elem[:hour] = hour if hour
- elem[:min] = min if min
- elem[:sec] = sec if sec
- elem[:sec_fraction] = sec_fraction if sec_fraction
- elem[:zone] = zone if zone
- offset = zone_to_diff(zone) if zone
- elem[:offset] = offset if offset
- elem[:wday] = wday if wday
- elem
- end
-
- def self.zone_to_diff(str)
- abb, dst = str.downcase.split(/\s+/o, 2)
- if ZONES.include?(abb)
- offset = ZONES[abb]
- offset += 3600 if dst
- elsif /\A([-+])(\d{2}):?(\d{2})?\Z/no =~ str
- offset = $2.to_i * 3600 + $3.to_i * 60
- offset *= -1 if $1 == '-'
- end
- offset
- end
-
- def strftime(fmt='%F')
- o = ''
- fmt.scan(/%[EO]?.|./mo) do |c|
- cc = c.sub(/\A%[EO]?(.)\z/mo, '%\\1')
- case cc
- when '%A'; o << DAYNAMES[wday]
- when '%a'; o << ABBR_DAYNAMES[wday]
- when '%B'; o << MONTHNAMES[mon]
- when '%b'; o << ABBR_MONTHNAMES[mon]
- when '%C'; o << '%02d' % (year / 100.0).floor # P2,ID
- when '%c'; o << strftime('%a %b %e %H:%M:%S %Y')
- when '%D'; o << strftime('%m/%d/%y') # P2,ID
- when '%d'; o << '%02d' % mday
- when '%e'; o << '%2d' % mday
- when '%F'; o << strftime('%Y-%m-%d') # ID
- when '%G'; o << '%.4d' % cwyear # ID
- when '%g'; o << '%02d' % (cwyear % 100) # ID
- when '%H'; o << '%02d' % hour
- when '%h'; o << strftime('%b') # P2,ID
- when '%I'; o << '%02d' % ((hour % 12).nonzero? or 12)
- when '%j'; o << '%03d' % yday
- when '%k'; o << '%2d' % hour # AR,TZ,GL
- when '%l'; o << '%2d' % ((hour % 12).nonzero? or 12) # AR,TZ,GL
- when '%M'; o << '%02d' % min
- when '%m'; o << '%02d' % mon
-=begin
- when '%N' # GNU date
- o << '%09d' % (sec_fraction / (1.to_r/86400/(10**9)))
-=end
- when '%n'; o << "\n" # P2,ID
- when '%P'; o << if hour < 12 then 'am' else 'pm' end # GL
- when '%p'; o << if hour < 12 then 'AM' else 'PM' end
- when '%R'; o << strftime('%H:%M') # ID
- when '%r'; o << strftime('%I:%M:%S %p') # P2,ID
- when '%S'; o << '%02d' % sec
- when '%s' # TZ,GL
- d = ajd - self.class.jd_to_ajd(self.class.civil_to_jd(1970,1,1), 0)
- s = (d * 86400).to_i
- o << '%d' % s
- when '%T'; o << strftime('%H:%M:%S') # P2,ID
- when '%t'; o << "\t" # P2,ID
- when '%U', '%W'
- a = self.class.civil_to_jd(year, 1, 1, ns?) + 6
- k = if c[-1,1] == 'U' then 0 else 1 end
- w = (jd - (a - ((a - k) + 1) % 7) + 7) / 7
- o << '%02d' % w
- when '%u'; o << '%d' % cwday # P2,ID
- when '%V'; o << '%02d' % cweek # P2,ID
- when '%v'; o << strftime('%e-%b-%Y') # AR,TZ
- when '%w'; o << '%d' % wday
- when '%X'; o << strftime('%H:%M:%S')
- when '%x'; o << strftime('%m/%d/%y')
- when '%Y'; o << '%.4d' % year
- when '%y'; o << '%02d' % (year % 100)
- when '%Z'; o << (if offset.zero? then 'Z' else strftime('%z') end)
- when '%z' # ID
- o << if offset < 0 then '-' else '+' end
- of = offset.abs
- hh, fr = of.divmod(1.to_r/24)
- mm = fr / (1.to_r/1440)
- o << '%02d' % hh
- o << '%02d' % mm
- when '%%'; o << '%'
- when '%+'; o << strftime('%a %b %e %H:%M:%S %Z %Y') # TZ
-=begin
- when '%.'
- o << '%06d' % (sec_fraction / (1.to_r/86400/(10**6)))
-=end
- when '%1'
- if $VERBOSE
- warn("warning: %1 is deprecated; forget this")
+ if e._comp
+ if e.cwyear
+ if e.cwyear >= 0 && e.cwyear <= 99
+ e.cwyear += if e.cwyear >= 69
+ then 1900 else 2000 end
end
- o << '%d' % jd
- when '%2'
- if $VERBOSE
- warn("warning: %2 is deprecated; use '%Y-%j'")
- end
- o << strftime('%Y-%j')
- when '%3'
- if $VERBOSE
- warn("warning: %3 is deprecated; use '%F'")
+ end
+ if e.year
+ if e.year >= 0 && e.year <= 99
+ e.year += if e.year >= 69
+ then 1900 else 2000 end
end
- o << strftime('%F')
- when /\A%(.)/m
- o << $1
- else
- o << c
end
end
- o
- end
-# alias_method :format, :strftime
+ e.offset ||= zone_to_diff(e.zone) if e.zone
- def asctime() strftime('%c') end
+ e.to_hash
+ end
- alias_method :ctime, :asctime
+ def self.zone_to_diff(zone) # :nodoc:
+ zone = zone.downcase
+ if zone.sub!(/\s+(standard|daylight)\s+time\z/, '')
+ dst = $1 == 'daylight'
+ else
+ dst = zone.sub!(/\s+dst\z/, '')
+ end
+ if Format::ZONES.include?(zone)
+ offset = Format::ZONES[zone]
+ offset += 3600 if dst
+ elsif zone.sub!(/\A(?:gmt|utc?)?([-+])/, '')
+ sign = $1
+ if zone.include?(':')
+ hour, min, sec, = zone.split(':')
+ elsif zone.include?(',') || zone.include?('.')
+ hour, fr, = zone.split(/[,.]/)
+ min = Rational(fr.to_i, 10**fr.size) * 60
+ else
+ case zone.size
+ when 3
+ hour = zone[0,1]
+ min = zone[1,2]
+ else
+ hour = zone[0,2]
+ min = zone[2,2]
+ sec = zone[4,2]
+ end
+ end
+ offset = hour.to_i * 3600 + min.to_i * 60 + sec.to_i
+ offset *= -1 if sign == '-'
+ end
+ offset
+ end
end
class DateTime < Date
- def self._strptime(str, fmt='%FT%T%Z')
+ def strftime(fmt='%FT%T%:z')
+ super(fmt)
+ end
+
+ def self._strptime(str, fmt='%FT%T%z')
super(str, fmt)
end
- def strftime(fmt='%FT%T%Z')
- super(fmt)
+=begin
+ def iso8601_timediv(n) # :nodoc:
+ strftime('T%T' +
+ if n < 1
+ ''
+ else
+ '.%0*d' % [n, (sec_fraction / SECONDS_IN_DAY / (10**n)).round]
+ end +
+ '%:z')
+ end
+
+ private :iso8601_timediv
+
+ def iso8601(n=0)
+ super() + iso8601_timediv(n)
end
+ def rfc3339(n=0) iso8601(n) end
+
+ def jisx0301(n=0)
+ super() + iso8601_timediv(n)
+ end
+=end
+
end
diff --git a/lib/delegate.rb b/lib/delegate.rb
index 93c9803a18..43549946c9 100644
--- a/lib/delegate.rb
+++ b/lib/delegate.rb
@@ -115,6 +115,7 @@
# implementation, see SimpleDelegator.
#
class Delegator
+ IgnoreBacktracePat = %r"\A#{Regexp.quote(__FILE__)}:\d+:in `"
#
# Pass in the _obj_ to delegate method calls to. All methods supported by
@@ -133,14 +134,12 @@ class Delegator
for method in obj.methods
next if preserved.include? method
begin
- eval <<-EOS
+ eval <<-EOS, nil, __FILE__, __LINE__+1
def self.#{method}(*args, &block)
begin
__getobj__.__send__(:#{method}, *args, &block)
- rescue Exception
- $@.delete_if{|s| /:in `__getobj__'$/ =~ s} #`
- $@.delete_if{|s| /^\\(eval\\):/ =~ s}
- Kernel::raise
+ ensure
+ $@.delete_if{|s|IgnoreBacktracePat=~s} if $@
end
end
EOS
@@ -152,21 +151,21 @@ class Delegator
alias initialize_methods initialize
# Handles the magic of delegation through \_\_getobj\_\_.
- def method_missing(m, *args)
+ def method_missing(m, *args, &block)
target = self.__getobj__
unless target.respond_to?(m)
- super(m, *args)
+ super(m, *args, &block)
end
- target.__send__(m, *args)
+ target.__send__(m, *args, &block)
end
#
# Checks for a method provided by this the delegate object by fowarding the
# call through \_\_getobj\_\_.
#
- def respond_to?(m)
+ def respond_to?(m, include_private = false)
return true if super
- return self.__getobj__.respond_to?(m)
+ return self.__getobj__.respond_to?(m, include_private)
end
#
@@ -184,6 +183,7 @@ class Delegator
# Reinitializes delegation from a serialized object.
def marshal_load(obj)
initialize_methods(obj)
+ __setobj__(obj)
end
end
@@ -227,13 +227,15 @@ class SimpleDelegator<Delegator
# Clone support for the object returned by \_\_getobj\_\_.
def clone
- super
- __setobj__(__getobj__.clone)
+ new = super
+ new.__setobj__(__getobj__.clone)
+ new
end
# Duplication support for the object returned by \_\_getobj\_\_.
- def dup(obj)
- super
- __setobj__(__getobj__.dup)
+ def dup
+ new = super
+ new.__setobj__(__getobj__.clone)
+ new
end
end
@@ -248,7 +250,7 @@ SimpleDelegater = SimpleDelegator
# your class.
#
# class MyClass < DelegateClass( ClassToDelegateTo ) # Step 1
-# def initiaize
+# def initialize
# super(obj_of_ClassToDelegateTo) # Step 2
# end
# end
@@ -262,15 +264,15 @@ def DelegateClass(superclass)
def initialize(obj) # :nodoc:
@_dc_obj = obj
end
- def method_missing(m, *args) # :nodoc:
+ def method_missing(m, *args, &block) # :nodoc:
unless @_dc_obj.respond_to?(m)
- super(m, *args)
+ super(m, *args, &block)
end
- @_dc_obj.__send__(m, *args)
+ @_dc_obj.__send__(m, *args, &block)
end
- def respond_to?(m) # :nodoc:
+ def respond_to?(m, include_private = false) # :nodoc:
return true if super
- return @_dc_obj.respond_to?(m)
+ return @_dc_obj.respond_to?(m, include_private)
end
def __getobj__ # :nodoc:
@_dc_obj
@@ -280,23 +282,24 @@ def DelegateClass(superclass)
@_dc_obj = obj
end
def clone # :nodoc:
- super
- __setobj__(__getobj__.clone)
+ new = super
+ new.__setobj__(__getobj__.clone)
+ new
end
def dup # :nodoc:
- super
- __setobj__(__getobj__.dup)
+ new = super
+ new.__setobj__(__getobj__.clone)
+ new
end
}
for method in methods
begin
- klass.module_eval <<-EOS
+ klass.module_eval <<-EOS, __FILE__, __LINE__+1
def #{method}(*args, &block)
begin
@_dc_obj.__send__(:#{method}, *args, &block)
- rescue
- $@[0,2] = nil
- raise
+ ensure
+ $@.delete_if{|s| ::Delegator::IgnoreBacktracePat =~ s} if $@
end
end
EOS
diff --git a/lib/drb/acl.rb b/lib/drb/acl.rb
index aa86dbe70f..861c8a514d 100644
--- a/lib/drb/acl.rb
+++ b/lib/drb/acl.rb
@@ -13,6 +13,8 @@ class ACL
def initialize(str)
if str == '*' or str == 'all'
@pat = [:all]
+ elsif str.include?('*')
+ @pat = [:name, dot_pat(str)]
else
begin
@pat = [:ip, IPAddr.new(str)]
diff --git a/lib/drb/drb.rb b/lib/drb/drb.rb
index 25fbb3f788..795dc1ac4b 100644
--- a/lib/drb/drb.rb
+++ b/lib/drb/drb.rb
@@ -578,7 +578,7 @@ module DRb
end
raise(DRbConnError, 'connection closed') if str.nil?
raise(DRbConnError, 'premature marshal format(can\'t read)') if str.size < sz
- Thread.exclusive do
+ DRb.mutex.synchronize do
begin
save = Thread.current[:drb_untaint]
Thread.current[:drb_untaint] = []
@@ -842,15 +842,10 @@ module DRb
Socket::SOCK_STREAM,
0,
Socket::AI_PASSIVE)
- family = infos.collect { |af, *_| af }.uniq
- case family
- when ['AF_INET']
- return TCPServer.open('0.0.0.0', port)
- when ['AF_INET6']
- return TCPServer.open('::', port)
- else
- return TCPServer.open(port)
- end
+ families = Hash[*infos.collect { |af, *_| af }.uniq.zip([]).flatten]
+ return TCPServer.open('0.0.0.0', port) if families.has_key?('AF_INET')
+ return TCPServer.open('::', port) if families.has_key?('AF_INET6')
+ return TCPServer.open(port)
end
# Open a server listening for connections at +uri+ using
@@ -858,6 +853,7 @@ module DRb
def self.open_server(uri, config)
uri = 'druby://:0' unless uri
host, port, opt = parse_uri(uri)
+ config = {:tcp_original_host => host}.update(config)
if host.size == 0
host = getservername
soc = open_server_inaddr_any(host, port)
@@ -865,6 +861,7 @@ module DRb
soc = TCPServer.open(host, port)
end
port = soc.addr[1] if port == 0
+ config[:tcp_port] = port
uri = "druby://#{host}:#{port}"
self.new(uri, soc, config)
end
@@ -945,7 +942,12 @@ module DRb
break if (@acl ? @acl.allow_socket?(s) : true)
s.close
end
- self.class.new(nil, s, @config)
+ if @config[:tcp_original_host].to_s.size == 0
+ uri = "druby://#{s.addr[3]}:#{@config[:tcp_port]}"
+ else
+ uri = @uri
+ end
+ self.class.new(uri, s, @config)
end
# Check to see if this connection is alive.
@@ -1201,6 +1203,7 @@ module DRb
end
def alive? # :nodoc:
+ return false unless @protocol
@protocol.alive?
end
end
@@ -1666,6 +1669,12 @@ module DRb
#
# This is the URI of the current server. See #current_server.
def uri
+ drb = Thread.current['DRb']
+ client = (drb && drb['client'])
+ if client
+ uri = client.uri
+ return uri if uri
+ end
current_server.uri
end
module_function :uri
@@ -1738,10 +1747,16 @@ module DRb
end
module_function :install_acl
+ @mutex = Mutex.new
+ def mutex
+ @mutex
+ end
+ module_function :mutex
+
@server = {}
def regist_server(server)
@server[server.uri] = server
- Thread.exclusive do
+ mutex.synchronize do
@primary_server = server unless @primary_server
end
end
diff --git a/lib/drb/extservm.rb b/lib/drb/extservm.rb
index 7066f84c65..be40aea9f5 100644
--- a/lib/drb/extservm.rb
+++ b/lib/drb/extservm.rb
@@ -5,10 +5,12 @@
require 'drb/drb'
require 'thread'
+require 'monitor'
module DRb
class ExtServManager
include DRbUndumped
+ include MonitorMixin
@@command = {}
@@ -21,6 +23,8 @@ module DRb
end
def initialize
+ super()
+ @cond = new_cond
@servers = {}
@waiting = []
@queue = Queue.new
@@ -30,34 +34,26 @@ module DRb
attr_accessor :uri
def service(name)
- while true
- server = nil
- Thread.exclusive do
- server = @servers[name] if @servers[name]
- end
- return server if server && server.alive?
- invoke_service(name)
+ synchronize do
+ while true
+ server = @servers[name]
+ return server if server && server.alive?
+ invoke_service(name)
+ @cond.wait
+ end
end
end
def regist(name, ro)
- ary = nil
- Thread.exclusive do
- @servers[name] = ro
- ary = @waiting
- @waiting = []
- end
- ary.each do |th|
- begin
- th.run
- rescue ThreadError
- end
+ synchronize do
+ @servers[name] = ro
+ @cond.signal
end
self
end
def unregist(name)
- Thread.exclusive do
+ synchronize do
@servers.delete(name)
end
end
@@ -73,15 +69,12 @@ module DRb
end
def invoke_service(name)
- Thread.critical = true
- @waiting.push Thread.current
- @queue.push name
- Thread.stop
+ @queue.push(name)
end
def invoke_service_command(name, command)
raise "invalid command. name: #{name}" unless command
- Thread.exclusive do
+ synchronize do
return if @servers.include?(name)
@servers[name] = false
end
diff --git a/lib/drb/unix.rb b/lib/drb/unix.rb
index 989ec57eed..57feed8301 100644
--- a/lib/drb/unix.rb
+++ b/lib/drb/unix.rb
@@ -88,7 +88,7 @@ module DRb
public
def close
return unless @socket
- path = @socket.path
+ path = @socket.path if @server_mode
@socket.close
File.unlink(path) if @server_mode
@socket = nil
diff --git a/lib/erb.rb b/lib/erb.rb
index bf4b441028..1ed3c60060 100644
--- a/lib/erb.rb
+++ b/lib/erb.rb
@@ -236,11 +236,11 @@
# Rails, the web application framework, uses ERB to create views.
#
class ERB
- Revision = '$Date: 2006/02/12 15:09:25 $' #'
+ Revision = '$Date$' #'
# Returns revision information for the erb.rb module.
def self.version
- "erb.rb [2.0.4 #{ERB::Revision.split[1]}]"
+ "erb.rb [2.1.0 #{ERB::Revision.split[1]}]"
end
end
@@ -254,11 +254,13 @@ class ERB
end
attr_reader :value
alias :to_s :value
+
+ def empty?
+ @value.empty?
+ end
end
class Scanner # :nodoc:
- SplitRegexp = /(<%%)|(%%>)|(<%=)|(<%#)|(<%)|(%>)|(\n)/
-
@scanner_map = {}
def self.regist_scanner(klass, trim_mode, percent)
@scanner_map[[trim_mode, percent]] = klass
@@ -283,8 +285,6 @@ class ERB
end
class TrimScanner < Scanner # :nodoc:
- TrimSplitRegexp = /(<%%)|(%%>)|(<%=)|(<%#)|(<%)|(%>\n)|(%>)|(\n)/
-
def initialize(src, trim_mode, percent)
super
@trim_mode = trim_mode
@@ -308,9 +308,7 @@ class ERB
percent_line(line, &block)
end
else
- @src.each do |line|
- @scan_line.call(line, &block)
- end
+ @scan_line.call(@src, &block)
end
nil
end
@@ -329,57 +327,66 @@ class ERB
end
def scan_line(line)
- line.split(SplitRegexp).each do |token|
- next if token.empty?
- yield(token)
+ line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>|\n|\z)/m) do |tokens|
+ tokens.each do |token|
+ next if token.empty?
+ yield(token)
+ end
end
end
def trim_line1(line)
- line.split(TrimSplitRegexp).each do |token|
- next if token.empty?
- if token == "%>\n"
- yield('%>')
- yield(:cr)
- break
- end
- yield(token)
+ line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>\n|%>|\n|\z)/m) do |tokens|
+ tokens.each do |token|
+ next if token.empty?
+ if token == "%>\n"
+ yield('%>')
+ yield(:cr)
+ else
+ yield(token)
+ end
+ end
end
end
def trim_line2(line)
head = nil
- line.split(TrimSplitRegexp).each do |token|
- next if token.empty?
- head = token unless head
- if token == "%>\n"
- yield('%>')
- if is_erb_stag?(head)
- yield(:cr)
- else
- yield("\n")
- end
- break
- end
- yield(token)
+ line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>\n|%>|\n|\z)/m) do |tokens|
+ tokens.each do |token|
+ next if token.empty?
+ head = token unless head
+ if token == "%>\n"
+ yield('%>')
+ if is_erb_stag?(head)
+ yield(:cr)
+ else
+ yield("\n")
+ end
+ head = nil
+ else
+ yield(token)
+ head = nil if token == "\n"
+ end
+ end
end
end
- ExplicitTrimRegexp = /(^[ \t]*<%-)|(-%>\n?\z)|(<%-)|(-%>)|(<%%)|(%%>)|(<%=)|(<%#)|(<%)|(%>)|(\n)/
def explicit_trim_line(line)
- line.split(ExplicitTrimRegexp).each do |token|
- next if token.empty?
- if @stag.nil? && /[ \t]*<%-/ =~ token
- yield('<%')
- elsif @stag && /-%>\n/ =~ token
- yield('%>')
- yield(:cr)
- elsif @stag && token == '-%>'
- yield('%>')
- else
- yield(token)
- end
- end
+ line.scan(/(.*?)(^[ \t]*<%\-|<%\-|<%%|%%>|<%=|<%#|<%|-%>\n|-%>|%>|\z)/m) do |tokens|
+ tokens.each do |token|
+ next if token.empty?
+ if @stag.nil? && /[ \t]*<%-/ =~ token
+ yield('<%')
+ elsif @stag && token == "-%>\n"
+ yield('%>')
+ yield(:cr)
+ elsif @stag && token == '-%>'
+ yield('%>')
+ else
+ yield(token)
+ end
+ end
+ end
end
ERB_STAG = %w(<%= <%# <%)
@@ -392,11 +399,11 @@ class ERB
class SimpleScanner < Scanner # :nodoc:
def scan
- @src.each do |line|
- line.split(SplitRegexp).each do |token|
- next if token.empty?
- yield(token)
- end
+ @src.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>|\n|\z)/m) do |tokens|
+ tokens.each do |token|
+ next if token.empty?
+ yield(token)
+ end
end
end
end
@@ -407,75 +414,35 @@ class ERB
require 'strscan'
class SimpleScanner2 < Scanner # :nodoc:
def scan
- stag_reg = /(.*?)(<%%|<%=|<%#|<%|\n|\z)/
- etag_reg = /(.*?)(%%>|%>|\n|\z)/
+ stag_reg = /(.*?)(<%%|<%=|<%#|<%|\z)/m
+ etag_reg = /(.*?)(%%>|%>|\z)/m
scanner = StringScanner.new(@src)
while ! scanner.eos?
scanner.scan(@stag ? etag_reg : stag_reg)
- text = scanner[1]
- elem = scanner[2]
- yield(text) unless text.empty?
- yield(elem) unless elem.empty?
+ yield(scanner[1])
+ yield(scanner[2])
end
end
end
Scanner.regist_scanner(SimpleScanner2, nil, false)
- class PercentScanner < Scanner # :nodoc:
- def scan
- new_line = true
- stag_reg = /(.*?)(<%%|<%=|<%#|<%|\n|\z)/
- etag_reg = /(.*?)(%%>|%>|\n|\z)/
- scanner = StringScanner.new(@src)
- while ! scanner.eos?
- if new_line && @stag.nil?
- if scanner.scan(/%%/)
- yield('%')
- new_line = false
- next
- elsif scanner.scan(/%/)
- yield(PercentLine.new(scanner.scan(/.*?(\n|\z)/).chomp))
- next
- end
- end
- scanner.scan(@stag ? etag_reg : stag_reg)
- text = scanner[1]
- elem = scanner[2]
- yield(text) unless text.empty?
- yield(elem) unless elem.empty?
- new_line = (elem == "\n")
- end
- end
- end
- Scanner.regist_scanner(PercentScanner, nil, true)
-
class ExplicitScanner < Scanner # :nodoc:
def scan
- new_line = true
- stag_reg = /(.*?)(<%%|<%=|<%#|<%-|<%|\n|\z)/
- etag_reg = /(.*?)(%%>|-%>|%>|\n|\z)/
+ stag_reg = /(.*?)(^[ \t]*<%-|<%%|<%=|<%#|<%-|<%|\z)/m
+ etag_reg = /(.*?)(%%>|-%>|%>|\z)/m
scanner = StringScanner.new(@src)
while ! scanner.eos?
- if new_line && @stag.nil? && scanner.scan(/[ \t]*<%-/)
- yield('<%')
- new_line = false
- next
- end
scanner.scan(@stag ? etag_reg : stag_reg)
- text = scanner[1]
+ yield(scanner[1])
+
elem = scanner[2]
- new_line = (elem == "\n")
- yield(text) unless text.empty?
- if elem == '-%>'
+ if /[ \t]*<%-/ =~ elem
+ yield('<%')
+ elsif elem == '-%>'
yield('%>')
- if scanner.scan(/(\n|\z)/)
- yield(:cr)
- new_line = true
- end
- elsif elem == '<%-'
- yield('<%')
+ yield(:cr) if scanner.scan(/(\n|\z)/)
else
- yield(elem) unless elem.empty?
+ yield(elem)
end
end
end
@@ -516,16 +483,27 @@ class ERB
end
end
+ def content_dump(s)
+ n = s.count("\n")
+ if n > 0
+ s.dump + "\n" * n
+ else
+ s.dump
+ end
+ end
+
def compile(s)
out = Buffer.new(self)
content = ''
scanner = make_scanner(s)
scanner.scan do |token|
+ next if token.nil?
+ next if token == ''
if scanner.stag.nil?
case token
when PercentLine
- out.push("#{@put_cmd} #{content.dump}") if content.size > 0
+ out.push("#{@put_cmd} #{content_dump(content)}") if content.size > 0
content = ''
out.push(token.to_s)
out.cr
@@ -533,12 +511,11 @@ class ERB
out.cr
when '<%', '<%=', '<%#'
scanner.stag = token
- out.push("#{@put_cmd} #{content.dump}") if content.size > 0
+ out.push("#{@put_cmd} #{content_dump(content)}") if content.size > 0
content = ''
when "\n"
content << "\n"
- out.push("#{@put_cmd} #{content.dump}")
- out.cr
+ out.push("#{@put_cmd} #{content_dump(content)}")
content = ''
when '<%%'
content << '<%'
@@ -560,7 +537,7 @@ class ERB
when '<%='
out.push("#{@insert_cmd}((#{content}).to_s)")
when '<%#'
- # out.push("# #{content.dump}")
+ # out.push("# #{content_dump(content)}")
end
scanner.stag = nil
content = ''
@@ -571,7 +548,7 @@ class ERB
end
end
end
- out.push("#{@put_cmd} #{content.dump}") if content.size > 0
+ out.push("#{@put_cmd} #{content_dump(content)}") if content.size > 0
out.close
out.script
end
@@ -658,7 +635,7 @@ class ERB
#
# def build
# b = binding
- # # create and run templates, filling member data variebles
+ # # create and run templates, filling member data variables
# ERB.new(<<-'END_PRODUCT'.gsub(/^\s+/, ""), 0, "", "@product").result b
# <%= PRODUCT[:name] %>
# <%= PRODUCT[:desc] %>
@@ -734,29 +711,58 @@ class ERB
#
def result(b=TOPLEVEL_BINDING)
if @safe_level
- th = Thread.start {
+ proc {
$SAFE = @safe_level
eval(@src, b, (@filename || '(erb)'), 1)
- }
- return th.value
+ }.call
else
- return eval(@src, b, (@filename || '(erb)'), 1)
+ eval(@src, b, (@filename || '(erb)'), 1)
end
end
- def def_method(mod, methodname, fname='(ERB)') # :nodoc:
+ # Define _methodname_ as instance method of _mod_ from compiled ruby source.
+ #
+ # example:
+ # filename = 'example.rhtml' # 'arg1' and 'arg2' are used in example.rhtml
+ # erb = ERB.new(File.read(filename))
+ # erb.def_method(MyClass, 'render(arg1, arg2)', filename)
+ # print MyClass.new.render('foo', 123)
+ def def_method(mod, methodname, fname='(ERB)')
mod.module_eval("def #{methodname}\n" + self.src + "\nend\n", fname, 0)
end
- def def_module(methodname='erb') # :nodoc:
+ # Create unnamed module, define _methodname_ as instance method of it, and return it.
+ #
+ # example:
+ # filename = 'example.rhtml' # 'arg1' and 'arg2' are used in example.rhtml
+ # erb = ERB.new(File.read(filename))
+ # erb.filename = filename
+ # MyModule = erb.def_module('render(arg1, arg2)')
+ # class MyClass
+ # include MyModule
+ # end
+ def def_module(methodname='erb')
mod = Module.new
- def_method(mod, methodname)
+ def_method(mod, methodname, @filename || '(ERB)')
mod
end
- def def_class(superklass=Object, methodname='result') # :nodoc:
+ # Define unnamed class which has _methodname_ as instance method, and return it.
+ #
+ # example:
+ # class MyClass_
+ # def initialize(arg1, arg2)
+ # @arg1 = arg1; @arg2 = arg2
+ # end
+ # end
+ # filename = 'example.rhtml' # @arg1 and @arg2 are used in example.rhtml
+ # erb = ERB.new(File.read(filename))
+ # erb.filename = filename
+ # MyClass = erb.def_class(MyClass_, 'render()')
+ # print MyClass.new('foo', 123).render()
+ def def_class(superklass=Object, methodname='result')
cls = Class.new(superklass)
- def_method(cls, methodname)
+ def_method(cls, methodname, @filename || '(ERB)')
cls
end
end
@@ -810,15 +816,45 @@ end
#--
# ERB::DefMethod
class ERB
- module DefMethod # :nodoc:
+ # Utility module to define eRuby script as instance method.
+ #
+ # === Example
+ #
+ # example.rhtml:
+ # <% for item in @items %>
+ # <b><%= item %></b>
+ # <% end %>
+ #
+ # example.rb:
+ # require 'erb'
+ # class MyClass
+ # extend ERB::DefMethod
+ # def_erb_method('render()', 'example.rhtml')
+ # def initialize(items)
+ # @items = items
+ # end
+ # end
+ # print MyClass.new([10,20,30]).render()
+ #
+ # result:
+ #
+ # <b>10</b>
+ #
+ # <b>20</b>
+ #
+ # <b>30</b>
+ #
+ module DefMethod
public
- def def_erb_method(methodname, erb)
- if erb.kind_of? String
- fname = erb
- File.open(fname) {|f| erb = ERB.new(f.read) }
- erb.def_method(self, methodname, fname)
+ # define _methodname_ as instance method of current module, using ERB object or eRuby file
+ def def_erb_method(methodname, erb_or_fname)
+ if erb_or_fname.kind_of? String
+ fname = erb_or_fname
+ erb = ERB.new(File.read(fname))
+ erb.def_method(self, methodname, fname)
else
- erb.def_method(self, methodname)
+ erb = erb_or_fname
+ erb.def_method(self, methodname, erb.filename || '(ERB)')
end
end
module_function :def_erb_method
diff --git a/lib/fileutils.rb b/lib/fileutils.rb
index 043a24d2b5..81aa1e8207 100644
--- a/lib/fileutils.rb
+++ b/lib/fileutils.rb
@@ -1,7 +1,7 @@
#
# = fileutils.rb
#
-# Copyright (c) 2000-2005 Minero Aoki <aamine@loveruby.net>
+# Copyright (c) 2000-2006 Minero Aoki
#
# This program is free software.
# You can distribute/modify this program under the same terms of ruby.
@@ -116,7 +116,7 @@ module FileUtils
# FileUtils.cd('/', :verbose => true) # chdir and report it
#
def cd(dir, options = {}, &block) # :yield: dir
- fu_check_options options, :verbose
+ fu_check_options options, OPT_TABLE['cd']
fu_output_message "cd #{dir}" if options[:verbose]
Dir.chdir(dir, &block)
fu_output_message 'cd -' if options[:verbose] and block
@@ -127,7 +127,7 @@ module FileUtils
module_function :chdir
OPT_TABLE['cd'] =
- OPT_TABLE['chdir'] = %w( verbose )
+ OPT_TABLE['chdir'] = [:verbose]
#
# Options: (none)
@@ -163,7 +163,7 @@ module FileUtils
# FileUtils.mkdir 'tmp', :mode => 0700
#
def mkdir(list, options = {})
- fu_check_options options, :mode, :noop, :verbose
+ fu_check_options options, OPT_TABLE['mkdir']
list = fu_list(list)
fu_output_message "mkdir #{options[:mode] ? ('-m %03o ' % options[:mode]) : ''}#{list.join ' '}" if options[:verbose]
return if options[:noop]
@@ -174,7 +174,7 @@ module FileUtils
end
module_function :mkdir
- OPT_TABLE['mkdir'] = %w( noop verbose mode )
+ OPT_TABLE['mkdir'] = [:mode, :noop, :verbose]
#
# Options: mode noop verbose
@@ -193,7 +193,7 @@ module FileUtils
# You can pass several directories at a time in a list.
#
def mkdir_p(list, options = {})
- fu_check_options options, :mode, :noop, :verbose
+ fu_check_options options, OPT_TABLE['mkdir_p']
list = fu_list(list)
fu_output_message "mkdir -p #{options[:mode] ? ('-m %03o ' % options[:mode]) : ''}#{list.join ' '}" if options[:verbose]
return *list if options[:noop]
@@ -232,7 +232,7 @@ module FileUtils
OPT_TABLE['mkdir_p'] =
OPT_TABLE['mkpath'] =
- OPT_TABLE['makedirs'] = %w( noop verbose )
+ OPT_TABLE['makedirs'] = [:mode, :noop, :verbose]
def fu_mkdir(path, mode) #:nodoc:
path = path.sub(%r</\z>, '')
@@ -256,7 +256,7 @@ module FileUtils
# FileUtils.rmdir 'somedir', :verbose => true, :noop => true
#
def rmdir(list, options = {})
- fu_check_options options, :noop, :verbose
+ fu_check_options options, OPT_TABLE['rmdir']
list = fu_list(list)
fu_output_message "rmdir #{list.join ' '}" if options[:verbose]
return if options[:noop]
@@ -266,7 +266,7 @@ module FileUtils
end
module_function :rmdir
- OPT_TABLE['rmdir'] = %w( noop verbose )
+ OPT_TABLE['rmdir'] = [:noop, :verbose]
#
# Options: force noop verbose
@@ -291,7 +291,7 @@ module FileUtils
# FileUtils.ln %w(cp mv mkdir), '/bin' # Now /sbin/cp and /bin/cp are linked.
#
def ln(src, dest, options = {})
- fu_check_options options, :force, :noop, :verbose
+ fu_check_options options, OPT_TABLE['ln']
fu_output_message "ln#{options[:force] ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
return if options[:noop]
fu_each_src_dest0(src, dest) do |s,d|
@@ -305,7 +305,7 @@ module FileUtils
module_function :link
OPT_TABLE['ln'] =
- OPT_TABLE['link'] = %w( noop verbose force )
+ OPT_TABLE['link'] = [:force, :noop, :verbose]
#
# Options: force noop verbose
@@ -330,7 +330,7 @@ module FileUtils
# FileUtils.ln_s Dir.glob('bin/*.rb'), '/home/aamine/bin'
#
def ln_s(src, dest, options = {})
- fu_check_options options, :force, :noop, :verbose
+ fu_check_options options, OPT_TABLE['ln_s']
fu_output_message "ln -s#{options[:force] ? 'f' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
return if options[:noop]
fu_each_src_dest0(src, dest) do |s,d|
@@ -344,7 +344,7 @@ module FileUtils
module_function :symlink
OPT_TABLE['ln_s'] =
- OPT_TABLE['symlink'] = %w( noop verbose force )
+ OPT_TABLE['symlink'] = [:force, :noop, :verbose]
#
# Options: noop verbose
@@ -353,14 +353,14 @@ module FileUtils
# #ln_s(src, dest, :force)
#
def ln_sf(src, dest, options = {})
- fu_check_options options, :noop, :verbose
+ fu_check_options options, OPT_TABLE['ln_sf']
options = options.dup
options[:force] = true
ln_s src, dest, options
end
module_function :ln_sf
- OPT_TABLE['ln_sf'] = %w( noop verbose )
+ OPT_TABLE['ln_sf'] = [:noop, :verbose]
#
# Options: preserve noop verbose
@@ -376,7 +376,7 @@ module FileUtils
# FileUtils.cp 'symlink', 'dest' # copy content, "dest" is not a symlink
#
def cp(src, dest, options = {})
- fu_check_options options, :preserve, :noop, :verbose
+ fu_check_options options, OPT_TABLE['cp']
fu_output_message "cp#{options[:preserve] ? ' -p' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
return if options[:noop]
fu_each_src_dest(src, dest) do |s, d|
@@ -389,10 +389,10 @@ module FileUtils
module_function :copy
OPT_TABLE['cp'] =
- OPT_TABLE['copy'] = %w( noop verbose preserve )
+ OPT_TABLE['copy'] = [:preserve, :noop, :verbose]
#
- # Options: preserve noop verbose dereference_root
+ # Options: preserve noop verbose dereference_root remove_destination
#
# Copies +src+ to +dest+. If +src+ is a directory, this method copies
# all its contents recursively. If +dest+ is a directory, copies
@@ -415,17 +415,19 @@ module FileUtils
# # but this doesn't.
#
def cp_r(src, dest, options = {})
- fu_check_options options, :preserve, :noop, :verbose, :dereference_root
- fu_output_message "cp -r#{options[:preserve] ? 'p' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
+ fu_check_options options, OPT_TABLE['cp_r']
+ fu_output_message "cp -r#{options[:preserve] ? 'p' : ''}#{options[:remove_destination] ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
return if options[:noop]
+ options = options.dup
options[:dereference_root] = true unless options.key?(:dereference_root)
fu_each_src_dest(src, dest) do |s, d|
- copy_entry s, d, options[:preserve], options[:dereference_root]
+ copy_entry s, d, options[:preserve], options[:dereference_root], options[:remove_destination]
end
end
module_function :cp_r
- OPT_TABLE['cp_r'] = %w( noop verbose preserve dereference_root )
+ OPT_TABLE['cp_r'] = [:preserve, :noop, :verbose,
+ :dereference_root, :remove_destination]
#
# Copies a file system entry +src+ to +dest+.
@@ -441,9 +443,12 @@ module FileUtils
#
# If +dereference_root+ is true, this method dereference tree root.
#
- def copy_entry(src, dest, preserve = false, dereference_root = false)
+ # If +remove_destination+ is true, this method removes each destination file before copy.
+ #
+ def copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false)
Entry_.new(src, nil, dereference_root).traverse do |ent|
destent = Entry_.new(dest, ent.rel, false)
+ File.unlink destent.path if remove_destination && File.file?(destent.path)
ent.copy destent.path
ent.copy_metadata destent.path if preserve
end
@@ -484,7 +489,7 @@ module FileUtils
# FileUtils.mv Dir.glob('test*.rb'), 'test', :noop => true, :verbose => true
#
def mv(src, dest, options = {})
- fu_check_options options, :force, :noop, :verbose, :secure
+ fu_check_options options, OPT_TABLE['mv']
fu_output_message "mv#{options[:force] ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
return if options[:noop]
fu_each_src_dest(src, dest) do |s, d|
@@ -518,7 +523,7 @@ module FileUtils
module_function :move
OPT_TABLE['mv'] =
- OPT_TABLE['move'] = %w[force noop verbose secure]
+ OPT_TABLE['move'] = [:force, :noop, :verbose, :secure]
def rename_cannot_overwrite_file? #:nodoc:
/djgpp|cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM
@@ -536,7 +541,7 @@ module FileUtils
# FileUtils.rm 'NotExistFile', :force => true # never raises exception
#
def rm(list, options = {})
- fu_check_options options, :force, :noop, :verbose
+ fu_check_options options, OPT_TABLE['rm']
list = fu_list(list)
fu_output_message "rm#{options[:force] ? ' -f' : ''} #{list.join ' '}" if options[:verbose]
return if options[:noop]
@@ -551,7 +556,7 @@ module FileUtils
module_function :remove
OPT_TABLE['rm'] =
- OPT_TABLE['remove'] = %w( noop verbose force )
+ OPT_TABLE['remove'] = [:force, :noop, :verbose]
#
# Options: noop verbose
@@ -561,7 +566,7 @@ module FileUtils
# #rm(list, :force => true)
#
def rm_f(list, options = {})
- fu_check_options options, :noop, :verbose
+ fu_check_options options, OPT_TABLE['rm_f']
options = options.dup
options[:force] = true
rm list, options
@@ -572,7 +577,7 @@ module FileUtils
module_function :safe_unlink
OPT_TABLE['rm_f'] =
- OPT_TABLE['safe_unlink'] = %w( noop verbose )
+ OPT_TABLE['safe_unlink'] = [:noop, :verbose]
#
# Options: force noop verbose secure
@@ -596,7 +601,7 @@ module FileUtils
# See also #remove_entry_secure.
#
def rm_r(list, options = {})
- fu_check_options options, :force, :noop, :verbose, :secure
+ fu_check_options options, OPT_TABLE['rm_r']
# options[:secure] = true unless options.key?(:secure)
list = fu_list(list)
fu_output_message "rm -r#{options[:force] ? 'f' : ''} #{list.join ' '}" if options[:verbose]
@@ -611,7 +616,7 @@ module FileUtils
end
module_function :rm_r
- OPT_TABLE['rm_r'] = %w( noop verbose force secure )
+ OPT_TABLE['rm_r'] = [:force, :noop, :verbose, :secure]
#
# Options: noop verbose secure
@@ -624,7 +629,7 @@ module FileUtils
# Read the documentation of #rm_r first.
#
def rm_rf(list, options = {})
- fu_check_options options, :noop, :verbose, :secure
+ fu_check_options options, OPT_TABLE['rm_rf']
options = options.dup
options[:force] = true
rm_r list, options
@@ -635,7 +640,7 @@ module FileUtils
module_function :rmtree
OPT_TABLE['rm_rf'] =
- OPT_TABLE['rmtree'] = %w( noop verbose secure )
+ OPT_TABLE['rmtree'] = [:noop, :verbose, :secure]
#
# This method removes a file system entry +path+. +path+ shall be a
@@ -653,10 +658,10 @@ module FileUtils
# removing directories. This requires the current process is the
# owner of the removing whole directory tree, or is the super user (root).
#
- # WARNING: You must ensure that *ALL* parent directories are not
- # world writable. Otherwise this method does not work.
- # Only exception is temporary directory like /tmp and /var/tmp,
- # whose permission is 1777.
+ # WARNING: You must ensure that *ALL* parent directories cannot be
+ # moved by other untrusted users. For example, parent directories
+ # should not be owned by untrusted users, and should not be world
+ # writable except when the sticky bit set.
#
# WARNING: Only the owner of the removing directory tree, or Unix super
# user (root) should invoke this method. Otherwise this method does not
@@ -699,6 +704,11 @@ module FileUtils
end
f.chown euid, -1
f.chmod 0700
+ unless fu_stat_identical_entry?(st, File.lstat(fullpath))
+ # TOC-to-TOU attack?
+ File.unlink fullpath
+ return
+ end
}
# ---- tree root is frozen ----
root = Entry_.new(path)
@@ -820,16 +830,17 @@ module FileUtils
module_function :compare_stream
#
- # Options: mode noop verbose
+ # Options: mode preserve noop verbose
#
# If +src+ is not same as +dest+, copies it and changes the permission
# mode to +mode+. If +dest+ is a directory, destination is +dest+/+src+.
+ # This method removes destination before copy.
#
# FileUtils.install 'ruby', '/usr/local/bin/ruby', :mode => 0755, :verbose => true
# FileUtils.install 'lib.rb', '/usr/local/lib/ruby/site_ruby', :verbose => true
#
def install(src, dest, options = {})
- fu_check_options options, :mode, :preserve, :noop, :verbose
+ fu_check_options options, OPT_TABLE['install']
fu_output_message "install -c#{options[:preserve] && ' -p'}#{options[:mode] ? (' -m 0%o' % options[:mode]) : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
return if options[:noop]
fu_each_src_dest(src, dest) do |s, d|
@@ -844,7 +855,7 @@ module FileUtils
end
module_function :install
- OPT_TABLE['install'] = %w( noop verbose preserve mode )
+ OPT_TABLE['install'] = [:mode, :preserve, :noop, :verbose]
#
# Options: noop verbose
@@ -857,7 +868,7 @@ module FileUtils
# FileUtils.chmod 0755, '/usr/bin/ruby', :verbose => true
#
def chmod(mode, list, options = {})
- fu_check_options options, :noop, :verbose
+ fu_check_options options, OPT_TABLE['chmod']
list = fu_list(list)
fu_output_message sprintf('chmod %o %s', mode, list.join(' ')) if options[:verbose]
return if options[:noop]
@@ -867,7 +878,7 @@ module FileUtils
end
module_function :chmod
- OPT_TABLE['chmod'] = %w( noop verbose )
+ OPT_TABLE['chmod'] = [:noop, :verbose]
#
# Options: noop verbose force
@@ -878,7 +889,7 @@ module FileUtils
# FileUtils.chmod_R 0700, "/tmp/app.#{$$}"
#
def chmod_R(mode, list, options = {})
- fu_check_options options, :noop, :verbose, :force
+ fu_check_options options, OPT_TABLE['chmod_R']
list = fu_list(list)
fu_output_message sprintf('chmod -R%s %o %s',
(options[:force] ? 'f' : ''),
@@ -896,7 +907,7 @@ module FileUtils
end
module_function :chmod_R
- OPT_TABLE['chmod_R'] = %w( noop verbose )
+ OPT_TABLE['chmod_R'] = [:noop, :verbose, :force]
#
# Options: noop verbose
@@ -911,7 +922,7 @@ module FileUtils
# FileUtils.chown nil, 'bin', Dir.glob('/usr/bin/*'), :verbose => true
#
def chown(user, group, list, options = {})
- fu_check_options options, :noop, :verbose
+ fu_check_options options, OPT_TABLE['chown']
list = fu_list(list)
fu_output_message sprintf('chown %s%s',
[user,group].compact.join(':') + ' ',
@@ -925,7 +936,7 @@ module FileUtils
end
module_function :chown
- OPT_TABLE['chown'] = %w( noop verbose )
+ OPT_TABLE['chown'] = [:noop, :verbose]
#
# Options: noop verbose force
@@ -940,7 +951,7 @@ module FileUtils
# FileUtils.chown_R 'cvs', 'cvs', '/var/cvs', :verbose => true
#
def chown_R(user, group, list, options = {})
- fu_check_options options, :noop, :verbose, :force
+ fu_check_options options, OPT_TABLE['chown_R']
list = fu_list(list)
fu_output_message sprintf('chown -R%s %s%s',
(options[:force] ? 'f' : ''),
@@ -962,7 +973,7 @@ module FileUtils
end
module_function :chown_R
- OPT_TABLE['chown_R'] = %w( noop verbose )
+ OPT_TABLE['chown_R'] = [:noop, :verbose, :force]
begin
require 'etc'
@@ -979,6 +990,7 @@ module FileUtils
def fu_get_gid(group) #:nodoc:
return nil unless group
+ group = group.to_s
if /\A\d+\z/ =~ group
then group.to_i
else Etc.getgrnam(group).gid
@@ -1010,24 +1022,31 @@ module FileUtils
# FileUtils.touch Dir.glob('*.c'); system 'make'
#
def touch(list, options = {})
- fu_check_options options, :noop, :verbose
+ fu_check_options options, OPT_TABLE['touch']
list = fu_list(list)
- fu_output_message "touch #{list.join ' '}" if options[:verbose]
+ created = nocreate = options[:nocreate]
+ t = options[:mtime]
+ if options[:verbose]
+ fu_output_message "touch #{nocreate ? '-c ' : ''}#{t ? t.strftime('-t %Y%m%d%H%M.%S ') : ''}#{list.join ' '}"
+ end
return if options[:noop]
- t = Time.now
list.each do |path|
+ created = nocreate
begin
File.utime(t, t, path)
rescue Errno::ENOENT
+ raise if created
File.open(path, 'a') {
;
}
+ created = true
+ retry if t
end
end
end
module_function :touch
- OPT_TABLE['touch'] = %w( noop verbose )
+ OPT_TABLE['touch'] = [:noop, :verbose, :mtime, :nocreate]
private
@@ -1420,10 +1439,10 @@ module FileUtils
end
private_module_function :fu_have_st_ino?
- def fu_check_options(options, *optdecl) #:nodoc:
+ def fu_check_options(options, optdecl) #:nodoc:
h = options.dup
- optdecl.each do |name|
- h.delete name
+ optdecl.each do |opt|
+ h.delete opt
end
raise ArgumentError, "no such option: #{h.keys.join(' ')}" unless h.empty?
end
@@ -1449,8 +1468,6 @@ module FileUtils
end
private_module_function :fu_output_message
- METHODS = singleton_methods() - ['private_module_function']
-
#
# Returns an Array of method names which have any options.
#
@@ -1466,7 +1483,7 @@ module FileUtils
# p FileUtils.options #=> ["noop", "force", "verbose", "preserve", "mode"]
#
def FileUtils.options
- OPT_TABLE.values.flatten.uniq
+ OPT_TABLE.values.flatten.uniq.map {|sym| sym.to_s }
end
#
@@ -1478,7 +1495,7 @@ module FileUtils
#
def FileUtils.have_option?(mid, opt)
li = OPT_TABLE[mid.to_s] or raise ArgumentError, "no such method: #{mid}"
- li.include?(opt.to_s)
+ li.include?(opt)
end
#
@@ -1487,7 +1504,7 @@ module FileUtils
# p FileUtils.options(:rm) #=> ["noop", "verbose", "force"]
#
def FileUtils.options_of(mid)
- OPT_TABLE[mid.to_s]
+ OPT_TABLE[mid.to_s].map {|sym| sym.to_s }
end
#
@@ -1496,9 +1513,12 @@ module FileUtils
# p FileUtils.collect_method(:preserve) #=> ["cp", "cp_r", "copy", "install"]
#
def FileUtils.collect_method(opt)
- OPT_TABLE.keys.select {|m| OPT_TABLE[m].include?(opt.to_s) }
+ OPT_TABLE.keys.select {|m| OPT_TABLE[m].include?(opt) }
end
+ METHODS = singleton_methods() - %w( private_module_function
+ commands options have_option? options_of collect_method )
+
#
# This module has all methods of FileUtils module, but it outputs messages
# before acting. This equates to passing the <tt>:verbose</tt> flag to
@@ -1508,7 +1528,7 @@ module FileUtils
include FileUtils
@fileutils_output = $stderr
@fileutils_label = ''
- ::FileUtils.collect_method('verbose').each do |name|
+ ::FileUtils.collect_method(:verbose).each do |name|
module_eval(<<-EOS, __FILE__, __LINE__ + 1)
def #{name}(*args)
super(*fu_update_option(args, :verbose => true))
@@ -1533,7 +1553,7 @@ module FileUtils
include FileUtils
@fileutils_output = $stderr
@fileutils_label = ''
- ::FileUtils.collect_method('noop').each do |name|
+ ::FileUtils.collect_method(:noop).each do |name|
module_eval(<<-EOS, __FILE__, __LINE__ + 1)
def #{name}(*args)
super(*fu_update_option(args, :noop => true))
@@ -1559,7 +1579,7 @@ module FileUtils
include FileUtils
@fileutils_output = $stderr
@fileutils_label = ''
- ::FileUtils.collect_method('noop').each do |name|
+ ::FileUtils.collect_method(:noop).each do |name|
module_eval(<<-EOS, __FILE__, __LINE__ + 1)
def #{name}(*args)
super(*fu_update_option(args, :noop => true, :verbose => true))
diff --git a/lib/forwardable.rb b/lib/forwardable.rb
index 4383ce9bbb..cc6e4ee418 100644
--- a/lib/forwardable.rb
+++ b/lib/forwardable.rb
@@ -1,8 +1,8 @@
# = forwardable - Support for the Delegation Pattern
#
# $Release Version: 1.1$
-# $Revision: 1.2.2.2 $
-# $Date: 2006/06/02 13:23:01 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ishitsuka.com)
#
# Documentation by James Edward Gray II and Gavin Sinclair
@@ -38,7 +38,7 @@
# @q = [ ] # prepare delegate object
# end
#
-# # setup prefered interface, enq() and deq()...
+# # setup preferred interface, enq() and deq()...
# def_delegator :@q, :push, :enq
# def_delegator :@q, :shift, :deq
#
diff --git a/lib/generator.rb b/lib/generator.rb
index 21970981fc..dbdd0f40a9 100644
--- a/lib/generator.rb
+++ b/lib/generator.rb
@@ -2,7 +2,7 @@
#--
# $Idaemons: /home/cvs/rb/generator.rb,v 1.8 2001/10/03 08:54:32 knu Exp $
# $RoughId: generator.rb,v 1.10 2003/10/14 19:36:58 knu Exp $
-# $Id: generator.rb,v 1.2.2.2 2004/05/07 08:48:23 matz Exp $
+# $Id$
#++
#
# = generator.rb: convert an internal iterator to an external one
@@ -165,6 +165,44 @@ class Generator
end
end
+class Enumerable::Enumerator
+ def __generator
+ @generator ||= Generator.new(self)
+ end
+ private :__generator
+
+ # call-seq:
+ # e.next => object
+ #
+ # Returns the next object in the enumerator, and move the internal
+ # position forward. When the position reached at the end, internal
+ # position is rewinded then StopIteration is raised.
+ #
+ # Note that enumeration sequence by next method does not affect other
+ # non-external enumeration methods, unless underlying iteration
+ # methods itself has side-effect, e.g. IO#each_line.
+ #
+ # Caution: This feature internally uses Generator, which uses callcc
+ # to stop and resume enumeration to fetch each value. Use with care
+ # and be aware of the performance loss.
+ def next
+ g = __generator
+ return g.next unless g.end?
+
+ g.rewind
+ raise StopIteration, 'iteration reached at end'
+ end
+
+ # call-seq:
+ # e.rewind => e
+ #
+ # Rewinds the enumeration sequence by the next method.
+ def rewind
+ __generator.rewind
+ self
+ end
+end
+
#
# SyncEnumerator creates an Enumerable object from multiple Enumerable
# objects and enumerates them synchronously.
diff --git a/lib/getopts.rb b/lib/getopts.rb
index 0e21bf96c7..7124269351 100644
--- a/lib/getopts.rb
+++ b/lib/getopts.rb
@@ -1,8 +1,8 @@
#
# getopts.rb -
# $Release Version: $
-# $Revision: 1.8.2.4 $
-# $Date: 2006/08/04 22:00:21 $
+# $Revision$
+# $Date$
# by Yasuo OHBA(SHL Japan Inc. Technology Dept.)
#
# --
@@ -17,7 +17,7 @@
warn "Warning:#{caller[0].sub(/:in `.*'\z/, '')}: getopts is deprecated after Ruby 1.8.1; use optparse instead" if caller[0] and $VERBOSE
-$RCS_ID=%q$Header: /src/ruby/lib/getopts.rb,v 1.8.2.4 2006/08/04 22:00:21 drbrain Exp $
+$RCS_ID=%q$Header$
# getopts is obsolete. Use GetoptLong.
diff --git a/lib/ipaddr.rb b/lib/ipaddr.rb
index 67e2b65332..fe963e406c 100644
--- a/lib/ipaddr.rb
+++ b/lib/ipaddr.rb
@@ -2,14 +2,19 @@
# ipaddr.rb - A class to manipulate an IP address
#
# Copyright (c) 2002 Hajimu UMEMOTO <ume@mahoroba.org>.
+# Copyright (c) 2007 Akinori MUSHA <knu@iDaemons.org>.
# All rights reserved.
#
# You can redistribute and/or modify it under the same terms as Ruby.
#
-# $Id: ipaddr.rb,v 1.5.2.3 2006/08/04 22:00:21 drbrain Exp $
+# $Id$
+#
+# Contact:
+# - Akinori MUSHA <knu@iDaemons.org> (current maintainer)
#
# TODO:
# - scope_id support
+#
require 'socket'
unless Socket.const_defined? "AF_INET6"
@@ -107,12 +112,12 @@ class IPAddr
# Returns a new ipaddr built by bitwise AND.
def &(other)
- return self.clone.set(@addr & other.to_i)
+ return self.clone.set(@addr & coerce_other(other).to_i)
end
# Returns a new ipaddr built by bitwise OR.
def |(other)
- return self.clone.set(@addr | other.to_i)
+ return self.clone.set(@addr | coerce_other(other).to_i)
end
# Returns a new ipaddr built by bitwise right-shift.
@@ -130,12 +135,10 @@ class IPAddr
return self.clone.set(addr_mask(~@addr))
end
- # Returns true if two ipaddr are equal.
+ # Returns true if two ipaddrs are equal.
def ==(other)
- if other.kind_of?(IPAddr) && @family != other.family
- return false
- end
- return (@addr == other.to_i)
+ other = coerce_other(other)
+ return @family == other.family && @addr == other.to_i
end
# Returns a new ipaddr built by masking IP address with the given
@@ -149,10 +152,12 @@ class IPAddr
# e.g.:
# require 'ipaddr'
# net1 = IPAddr.new("192.168.2.0/24")
- # p net1.include?(IPAddr.new("192.168.2.0")) #=> true
- # p net1.include?(IPAddr.new("192.168.2.255")) #=> true
- # p net1.include?(IPAddr.new("192.168.3.0")) #=> false
+ # net2 = IPAddr.new("192.168.2.100")
+ # net3 = IPAddr.new("192.168.3.0")
+ # p net1.include?(net2) #=> true
+ # p net1.include?(net3) #=> false
def include?(other)
+ other = coerce_other(other)
if ipv4_mapped?
if (@mask_addr >> 32) != 0xffffffffffffffffffffffff
return false
@@ -165,17 +170,12 @@ class IPAddr
addr = @addr
family = @family
end
- if other.kind_of?(IPAddr)
- if other.ipv4_mapped?
- other_addr = (other.to_i & IN4MASK)
- other_family = Socket::AF_INET
- else
- other_addr = other.to_i
- other_family = other.family
- end
- else # Not IPAddr - assume integer in same family as us
- other_addr = other.to_i
- other_family = family
+ if other.ipv4_mapped?
+ other_addr = (other.to_i & IN4MASK)
+ other_family = Socket::AF_INET
+ else
+ other_addr = other.to_i
+ other_family = other.family
end
if family != other_family
@@ -316,6 +316,37 @@ class IPAddr
return _reverse + ".ip6.int"
end
+ # Returns the successor to the ipaddr.
+ def succ
+ return self.clone.set(@addr + 1, @family)
+ end
+
+ # Compares the ipaddr with another.
+ def <=>(other)
+ other = coerce_other(other)
+
+ return nil if other.family != @family
+
+ return @addr <=> other.to_i
+ end
+ include Comparable
+
+ # Creates a Range object for the network address.
+ def to_range
+ begin_addr = (@addr & @mask_addr)
+
+ case @family
+ when Socket::AF_INET
+ end_addr = (@addr | (IN4MASK ^ @mask_addr))
+ when Socket::AF_INET6
+ end_addr = (@addr | (IN6MASK ^ @mask_addr))
+ else
+ raise "unsupported address family"
+ end
+
+ return clone.set(begin_addr, @family)..clone.set(end_addr, @family)
+ end
+
# Returns a string containing a human-readable representation of the
# ipaddr. ("#<IPAddr: family:address/mask>")
def inspect
@@ -391,22 +422,36 @@ class IPAddr
private
- # Creates a new ipaddr containing the given human readable form of
- # an IP address. It also accepts `address/prefixlen' and
- # `address/mask'. When prefixlen or mask is specified, it returns a
- # masked ipaddr. IPv6 address may beenclosed with `[' and `]'.
+ # Creates a new ipaddr object either from a human readable IP
+ # address representation in string, or from a packed in_addr value
+ # followed by an address family.
+ #
+ # In the former case, the following are the valid formats that will
+ # be recognized: "address", "address/prefixlen" and "address/mask",
+ # where IPv6 address may be enclosed in square brackets (`[' and
+ # `]'). If a prefixlen or a mask is specified, it returns a masked
+ # IP address. Although the address family is determined
+ # automatically from a specified string, you can specify one
+ # explicitly by the optional second argument.
+ #
+ # Otherwise an IP addess is generated from a packed in_addr value
+ # and an address family.
#
- # Although an address family is determined automatically from a
- # specified address, you can specify an address family explicitly by
- # the optional second argument.
+ # The IPAddr class defines many methods and operators, and some of
+ # those, such as &, |, include? and ==, accept a string, or a packed
+ # in_addr value instead of an IPAddr object.
def initialize(addr = '::', family = Socket::AF_UNSPEC)
if !addr.kind_of?(String)
- if family != Socket::AF_INET6 && family != Socket::AF_INET
- raise ArgumentError, "unsupported address family"
+ case family
+ when Socket::AF_INET, Socket::AF_INET6
+ set(addr.to_i, family)
+ @mask_addr = (family == Socket::AF_INET) ? IN4MASK : IN6MASK
+ return
+ when Socket::AF_UNSPEC
+ raise ArgumentError, "address family must be specified"
+ else
+ raise ArgumentError, "unsupported address family: #{family}"
end
- set(addr, family)
- @mask_addr = (family == Socket::AF_INET) ? IN4MASK : IN6MASK
- return
end
prefix, prefixlen = addr.split('/')
if prefix =~ /^\[(.*)\]$/i
@@ -433,23 +478,31 @@ class IPAddr
@family = Socket::AF_INET6
end
if family != Socket::AF_UNSPEC && @family != family
- raise ArgumentError, "address family unmatch"
+ raise ArgumentError, "address family mismatch"
end
if prefixlen
mask!(prefixlen)
else
- @mask_addr = (family == Socket::AF_INET) ? IN4MASK : IN6MASK
+ @mask_addr = (@family == Socket::AF_INET) ? IN4MASK : IN6MASK
+ end
+ end
+
+ def coerce_other(other)
+ case other
+ when IPAddr
+ other
+ when String
+ self.class.new(other)
+ else
+ self.class.new(other, @family)
end
end
def in_addr(addr)
if addr =~ /^\d+\.\d+\.\d+\.\d+$/
- n = 0
- addr.split('.').each { |i|
- n <<= 8
- n += i.to_i
+ return addr.split('.').inject(0) { |i, s|
+ i << 8 | s.to_i
}
- return n
end
return nil
end
@@ -473,25 +526,20 @@ class IPAddr
if rest < 0
return nil
end
- a = [l, Array.new(rest, '0'), r].flatten!
- n = 0
- a.each { |i|
- n <<= 16
- n += i.hex
+ return (l + Array.new(rest, '0') + r).inject(0) { |i, s|
+ i << 16 | s.hex
}
- return n
end
def addr_mask(addr)
case @family
when Socket::AF_INET
- addr &= IN4MASK
+ return addr & IN4MASK
when Socket::AF_INET6
- addr &= IN6MASK
+ return addr & IN6MASK
else
raise "unsupported address family"
end
- return addr
end
def _reverse
diff --git a/lib/irb.rb b/lib/irb.rb
index 65b1512740..0b5d6ba57e 100644
--- a/lib/irb.rb
+++ b/lib/irb.rb
@@ -1,8 +1,8 @@
#
# irb.rb - irb main module
# $Release Version: 0.9.5 $
-# $Revision: 1.7.2.2 $
-# $Date: 2005/10/25 06:38:25 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
@@ -23,7 +23,7 @@ require "irb/locale"
STDOUT.sync = true
module IRB
- @RCS_ID='-$Id: irb.rb,v 1.7.2.2 2005/10/25 06:38:25 matz Exp $-'
+ @RCS_ID='-$Id$-'
class Abort < Exception;end
@@ -65,13 +65,21 @@ module IRB
trap("SIGINT") do
irb.signal_handle
end
-
- catch(:IRB_EXIT) do
- irb.eval_input
+
+ begin
+ catch(:IRB_EXIT) do
+ irb.eval_input
+ end
+ ensure
+ irb_at_exit
end
# print "\n"
end
+ def IRB.irb_at_exit
+ @CONF[:AT_EXIT].each{|hook| hook.call}
+ end
+
def IRB.irb_exit(irb, ret)
throw :IRB_EXIT, ret
end
@@ -149,10 +157,15 @@ module IRB
line.untaint
@context.evaluate(line, line_no)
output_value if @context.echo?
- rescue StandardError, ScriptError, Abort
- $! = RuntimeError.new("unknown exception raised") unless $!
- print $!.class, ": ", $!, "\n"
- if $@[0] =~ /irb(2)?(\/.*|-.*|\.rb)?:/ && $!.class.to_s !~ /^IRB/
+ exc = nil
+ rescue Interrupt => exc
+ rescue SystemExit, SignalException
+ raise
+ rescue Exception => exc
+ end
+ if exc
+ print exc.class, ": ", exc, "\n"
+ if exc.backtrace[0] =~ /irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/
irb_bug = true
else
irb_bug = false
@@ -161,7 +174,7 @@ module IRB
messages = []
lasts = []
levels = 0
- for m in $@
+ for m in exc.backtrace
m = @context.workspace.filter_backtrace(m) unless irb_bug
if m
if messages.size < @context.back_trace_limit
@@ -183,8 +196,7 @@ module IRB
print "Maybe IRB bug!!\n" if irb_bug
end
if $SAFE > 2
- warn "Error: irb does not work for $SAFE level higher than 2"
- exit 1
+ abort "Error: irb does not work for $SAFE level higher than 2"
end
end
end
diff --git a/lib/irb/cmd/chws.rb b/lib/irb/cmd/chws.rb
index 63be940f7a..88585b778b 100644
--- a/lib/irb/cmd/chws.rb
+++ b/lib/irb/cmd/chws.rb
@@ -1,8 +1,8 @@
#
# change-ws.rb -
# $Release Version: 0.9.5$
-# $Revision: 1.1.2.1 $
-# $Date: 2005/04/19 19:24:58 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
diff --git a/lib/irb/cmd/fork.rb b/lib/irb/cmd/fork.rb
index 67dee460f1..2866b1373b 100644
--- a/lib/irb/cmd/fork.rb
+++ b/lib/irb/cmd/fork.rb
@@ -1,8 +1,8 @@
#
# fork.rb -
# $Release Version: 0.9.5 $
-# $Revision: 1.2.2.1 $
-# $Date: 2005/04/19 19:24:58 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
@@ -10,7 +10,7 @@
#
#
-@RCS_ID='-$Id: fork.rb,v 1.2.2.1 2005/04/19 19:24:58 keiju Exp $-'
+@RCS_ID='-$Id$-'
module IRB
diff --git a/lib/irb/cmd/help.rb b/lib/irb/cmd/help.rb
index 578d9e63a6..3e8d1388e0 100644
--- a/lib/irb/cmd/help.rb
+++ b/lib/irb/cmd/help.rb
@@ -1,8 +1,8 @@
#
# help.rb - helper using ri
# $Release Version: 0.9.5$
-# $Revision: 1.2.4.1 $
-# $Date: 2005/04/19 19:24:58 $
+# $Revision$
+# $Date$
#
# --
#
diff --git a/lib/irb/cmd/load.rb b/lib/irb/cmd/load.rb
index aec5d8a391..cbc5d91d03 100644
--- a/lib/irb/cmd/load.rb
+++ b/lib/irb/cmd/load.rb
@@ -1,8 +1,8 @@
#
# load.rb -
# $Release Version: 0.9.5$
-# $Revision: 1.1.2.1 $
-# $Date: 2005/04/19 19:24:58 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
diff --git a/lib/irb/cmd/nop.rb b/lib/irb/cmd/nop.rb
index f0e786e8d4..aa553c959e 100644
--- a/lib/irb/cmd/nop.rb
+++ b/lib/irb/cmd/nop.rb
@@ -1,8 +1,8 @@
#
# nop.rb -
# $Release Version: 0.9.5$
-# $Revision: 1.1.2.1 $
-# $Date: 2005/04/19 19:24:58 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
@@ -13,7 +13,7 @@ module IRB
module ExtendCommand
class Nop
- @RCS_ID='-$Id: nop.rb,v 1.1.2.1 2005/04/19 19:24:58 keiju Exp $-'
+ @RCS_ID='-$Id$-'
def self.execute(conf, *opts)
command = new(conf)
diff --git a/lib/irb/cmd/pushws.rb b/lib/irb/cmd/pushws.rb
index 7acfee094f..eddaeae631 100644
--- a/lib/irb/cmd/pushws.rb
+++ b/lib/irb/cmd/pushws.rb
@@ -1,8 +1,8 @@
#
# change-ws.rb -
# $Release Version: 0.9.5$
-# $Revision: 1.1.2.1 $
-# $Date: 2005/04/19 19:24:58 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
diff --git a/lib/irb/cmd/subirb.rb b/lib/irb/cmd/subirb.rb
index 3ea9db33a0..79d654b172 100644
--- a/lib/irb/cmd/subirb.rb
+++ b/lib/irb/cmd/subirb.rb
@@ -2,8 +2,8 @@
#
# multi.rb -
# $Release Version: 0.9.5$
-# $Revision: 1.1.2.1 $
-# $Date: 2005/04/19 19:24:58 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
diff --git a/lib/irb/completion.rb b/lib/irb/completion.rb
index 49fb4556fa..000658e2a3 100644
--- a/lib/irb/completion.rb
+++ b/lib/irb/completion.rb
@@ -1,8 +1,8 @@
#
# irb/completor.rb -
# $Release Version: 0.9$
-# $Revision: 1.8.2.3 $
-# $Date: 2006/07/19 15:08:56 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ishitsuka.com)
# From Original Idea of shugo@ruby-lang.org
#
@@ -12,7 +12,7 @@ require "readline"
module IRB
module InputCompletor
- @RCS_ID='-$Id: completion.rb,v 1.8.2.3 2006/07/19 15:08:56 keiju Exp $-'
+ @RCS_ID='-$Id$-'
ReservedWords = [
"BEGIN", "END",
diff --git a/lib/irb/context.rb b/lib/irb/context.rb
index c82be24db1..d01bd4aefa 100644
--- a/lib/irb/context.rb
+++ b/lib/irb/context.rb
@@ -1,8 +1,8 @@
#
# irb/context.rb - irb context
# $Release Version: 0.9.5$
-# $Revision: 1.8.2.3 $
-# $Date: 2005/07/31 15:10:26 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
diff --git a/lib/irb/ext/change-ws.rb b/lib/irb/ext/change-ws.rb
index d75fe485c8..fff8f58fe5 100644
--- a/lib/irb/ext/change-ws.rb
+++ b/lib/irb/ext/change-ws.rb
@@ -1,8 +1,8 @@
#
# irb/ext/cb.rb -
# $Release Version: 0.9.5$
-# $Revision: 1.1.2.1 $
-# $Date: 2005/04/19 19:24:58 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
diff --git a/lib/irb/ext/history.rb b/lib/irb/ext/history.rb
index 2354ca96f7..40f8692e8b 100644
--- a/lib/irb/ext/history.rb
+++ b/lib/irb/ext/history.rb
@@ -1,8 +1,8 @@
#
# history.rb -
# $Release Version: 0.9.5$
-# $Revision: 1.1.2.2 $
-# $Date: 2005/04/19 19:24:58 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
@@ -49,7 +49,7 @@ module IRB
end
class History
- @RCS_ID='-$Id: history.rb,v 1.1.2.2 2005/04/19 19:24:58 keiju Exp $-'
+ @RCS_ID='-$Id$-'
def initialize(size = 16)
@size = size
diff --git a/lib/irb/ext/loader.rb b/lib/irb/ext/loader.rb
index 67fdc31c8e..837e2553ac 100644
--- a/lib/irb/ext/loader.rb
+++ b/lib/irb/ext/loader.rb
@@ -1,8 +1,8 @@
#
# loader.rb -
# $Release Version: 0.9.5$
-# $Revision: 1.1.2.1 $
-# $Date: 2005/04/19 19:24:58 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
@@ -15,7 +15,7 @@ module IRB
class LoadAbort < Exception;end
module IrbLoader
- @RCS_ID='-$Id: loader.rb,v 1.1.2.1 2005/04/19 19:24:58 keiju Exp $-'
+ @RCS_ID='-$Id$-'
alias ruby_load load
alias ruby_require require
diff --git a/lib/irb/ext/math-mode.rb b/lib/irb/ext/math-mode.rb
index dfb01f8202..bd443b96ed 100644
--- a/lib/irb/ext/math-mode.rb
+++ b/lib/irb/ext/math-mode.rb
@@ -1,8 +1,8 @@
#
# math-mode.rb -
# $Release Version: 0.9.5$
-# $Revision: 1.2.2.1 $
-# $Date: 2005/04/19 19:24:58 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
diff --git a/lib/irb/ext/multi-irb.rb b/lib/irb/ext/multi-irb.rb
index 946840fd40..634abbabf9 100644
--- a/lib/irb/ext/multi-irb.rb
+++ b/lib/irb/ext/multi-irb.rb
@@ -1,8 +1,8 @@
#
# irb/multi-irb.rb - multiple irb module
# $Release Version: 0.9.5$
-# $Revision: 1.2.2.1 $
-# $Date: 2005/04/19 19:24:58 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
@@ -15,7 +15,7 @@ require "thread"
module IRB
# job management class
class JobManager
- @RCS_ID='-$Id: multi-irb.rb,v 1.2.2.1 2005/04/19 19:24:58 keiju Exp $-'
+ @RCS_ID='-$Id$-'
def initialize
# @jobs = [[thread, irb],...]
@@ -70,7 +70,7 @@ module IRB
end
def search(key)
- case key
+ job = case key
when Integer
@jobs[key]
when Irb
@@ -78,10 +78,10 @@ module IRB
when Thread
@jobs.assoc(key)
else
- assoc = @jobs.find{|k, v| v.context.main.equal?(key)}
- IRB.fail NoSuchJob, key if assoc.nil?
- assoc
+ @jobs.find{|k, v| v.context.main.equal?(key)}
end
+ IRB.fail NoSuchJob, key if job.nil?
+ job
end
def delete(key)
diff --git a/lib/irb/ext/save-history.rb b/lib/irb/ext/save-history.rb
index 889d81d5be..5ecc5f5027 100644
--- a/lib/irb/ext/save-history.rb
+++ b/lib/irb/ext/save-history.rb
@@ -2,8 +2,8 @@
#
# save-history.rb -
# $Release Version: 0.9.5$
-# $Revision: 1.2.4.1 $
-# $Date: 2005/04/19 19:24:58 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKAkeiju@ruby-lang.org)
#
# --
@@ -15,7 +15,7 @@ require "readline"
module IRB
module HistorySavingAbility
- @RCS_ID='-$Id: save-history.rb,v 1.2.4.1 2005/04/19 19:24:58 keiju Exp $-'
+ @RCS_ID='-$Id$-'
end
class Context
@@ -50,23 +50,24 @@ module IRB
module HistorySavingAbility
include Readline
- def HistorySavingAbility.create_finalizer
- proc do
- if num = IRB.conf[:SAVE_HISTORY] and (num = num.to_i) > 0
- if hf = IRB.conf[:HISTORY_FILE]
- file = File.expand_path(hf)
- end
- file = IRB.rc_file("_history") unless file
- open(file, 'w' ) do |f|
- hist = HISTORY.to_a
- f.puts(hist[-num..-1] || hist)
- end
- end
- end
- end
+# def HistorySavingAbility.create_finalizer
+# proc do
+# if num = IRB.conf[:SAVE_HISTORY] and (num = num.to_i) > 0
+# if hf = IRB.conf[:HISTORY_FILE]
+# file = File.expand_path(hf)
+# end
+# file = IRB.rc_file("_history") unless file
+# open(file, 'w' ) do |f|
+# hist = HISTORY.to_a
+# f.puts(hist[-num..-1] || hist)
+# end
+# end
+# end
+# end
def HistorySavingAbility.extended(obj)
- ObjectSpace.define_finalizer(obj, HistorySavingAbility.create_finalizer)
+# ObjectSpace.define_finalizer(obj, HistorySavingAbility.create_finalizer)
+ IRB.conf[:AT_EXIT].push proc{obj.save_history}
obj.load_history
obj
end
@@ -80,6 +81,19 @@ module IRB
end
end
end
+
+ def save_history
+ if num = IRB.conf[:SAVE_HISTORY] and (num = num.to_i) > 0
+ if history_file = IRB.conf[:HISTORY_FILE]
+ history_file = File.expand_path(history_file)
+ end
+ history_file = IRB.rc_file("_history") unless history_file
+ open(history_file, 'w' ) do |f|
+ hist = HISTORY.to_a
+ f.puts(hist[-num..-1] || hist)
+ end
+ end
+ end
end
end
diff --git a/lib/irb/ext/tracer.rb b/lib/irb/ext/tracer.rb
index 8660bfed17..805f630a4d 100644
--- a/lib/irb/ext/tracer.rb
+++ b/lib/irb/ext/tracer.rb
@@ -1,8 +1,8 @@
#
# irb/lib/tracer.rb -
# $Release Version: 0.9.5$
-# $Revision: 1.1.2.1 $
-# $Date: 2005/04/19 19:24:58 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
diff --git a/lib/irb/ext/use-loader.rb b/lib/irb/ext/use-loader.rb
index 68bd1dd592..1b4d480fcd 100644
--- a/lib/irb/ext/use-loader.rb
+++ b/lib/irb/ext/use-loader.rb
@@ -1,8 +1,8 @@
#
# use-loader.rb -
# $Release Version: 0.9.5$
-# $Revision: 1.1.2.1 $
-# $Date: 2005/04/19 19:24:58 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
diff --git a/lib/irb/ext/workspaces.rb b/lib/irb/ext/workspaces.rb
index b09e52ca34..79098570dc 100644
--- a/lib/irb/ext/workspaces.rb
+++ b/lib/irb/ext/workspaces.rb
@@ -1,8 +1,8 @@
#
# push-ws.rb -
# $Release Version: 0.9.5$
-# $Revision: 1.1.2.1 $
-# $Date: 2005/04/19 19:24:58 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
diff --git a/lib/irb/extend-command.rb b/lib/irb/extend-command.rb
index 934f9f6fbb..de797ab78b 100644
--- a/lib/irb/extend-command.rb
+++ b/lib/irb/extend-command.rb
@@ -1,8 +1,8 @@
#
# irb/extend-command.rb - irb extend command
# $Release Version: 0.9.5$
-# $Revision: 1.4.2.3 $
-# $Date: 2006/08/08 15:16:21 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
@@ -112,7 +112,7 @@ module IRB
end
end
- # aliases = [commans_alias, flag], ...
+ # aliases = [commands_alias, flag], ...
def self.def_extend_command(cmd_name, cmd_class, load_file = nil, *aliases)
case cmd_class
when Symbol
@@ -126,9 +126,14 @@ module IRB
eval %[
def #{cmd_name}(*opts, &b)
require "#{load_file}"
+ arity = ExtendCommand::#{cmd_class}.instance_method(:execute).arity
+ args = (1..arity.abs).map {|i| "arg" + i.to_s }
+ args << "*opts" if arity < 0
+ args << "&block"
+ args = args.join(", ")
eval %[
- def #{cmd_name}(*opts, &b)
- ExtendCommand::#{cmd_class}.execute(irb_context, *opts, &b)
+ def #{cmd_name}(\#{args})
+ ExtendCommand::#{cmd_class}.execute(irb_context, \#{args})
end
]
send :#{cmd_name}, *opts, &b
diff --git a/lib/irb/frame.rb b/lib/irb/frame.rb
index a6f15d23e9..f0b0a9abf3 100644
--- a/lib/irb/frame.rb
+++ b/lib/irb/frame.rb
@@ -1,8 +1,8 @@
#
# frame.rb -
# $Release Version: 0.9$
-# $Revision: 1.4 $
-# $Date: 2002/07/09 11:17:16 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd)
#
# --
diff --git a/lib/irb/help.rb b/lib/irb/help.rb
index e239fdda4c..4921de6ec9 100644
--- a/lib/irb/help.rb
+++ b/lib/irb/help.rb
@@ -1,8 +1,8 @@
#
-# irb/help.rb - print usase module
+# irb/help.rb - print usage module
# $Release Version: 0.9.5$
-# $Revision: 1.2.2.1 $
-# $Date: 2005/04/19 19:24:57 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ishitsuka.com)
#
# --
diff --git a/lib/irb/init.rb b/lib/irb/init.rb
index 938e6e3d29..5bbcc9558b 100644
--- a/lib/irb/init.rb
+++ b/lib/irb/init.rb
@@ -1,8 +1,8 @@
#
# irb/init.rb - irb initialize module
# $Release Version: 0.9.5$
-# $Revision: 1.6.2.6 $
-# $Date: 2006/08/04 10:15:49 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
@@ -114,6 +114,8 @@ module IRB
# @CONF[:LC_MESSAGES] = "en"
@CONF[:LC_MESSAGES] = Locale.new
+ @CONF[:AT_EXIT] = []
+
@CONF[:DEBUG_LEVEL] = 1
end
diff --git a/lib/irb/input-method.rb b/lib/irb/input-method.rb
index d6abadba76..bfb90fa59a 100644
--- a/lib/irb/input-method.rb
+++ b/lib/irb/input-method.rb
@@ -1,8 +1,8 @@
#
# irb/input-method.rb - input methods used irb
# $Release Version: 0.9.5$
-# $Revision: 1.4.2.2 $
-# $Date: 2005/05/25 13:53:41 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
@@ -18,7 +18,7 @@ module IRB
#
STDIN_FILE_NAME = "(line)"
class InputMethod
- @RCS_ID='-$Id: input-method.rb,v 1.4.2.2 2005/05/25 13:53:41 shugo Exp $-'
+ @RCS_ID='-$Id$-'
def initialize(file = STDIN_FILE_NAME)
@file_name = file
diff --git a/lib/irb/lc/error.rb b/lib/irb/lc/error.rb
index 54420e3508..247596b7fe 100644
--- a/lib/irb/lc/error.rb
+++ b/lib/irb/lc/error.rb
@@ -1,8 +1,8 @@
#
# irb/lc/error.rb -
# $Release Version: 0.9.5$
-# $Revision: 1.5.2.1 $
-# $Date: 2005/04/19 19:24:59 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
diff --git a/lib/irb/lc/help-message b/lib/irb/lc/help-message
index f33d95e543..32087d113c 100644
--- a/lib/irb/lc/help-message
+++ b/lib/irb/lc/help-message
@@ -1,8 +1,8 @@
#
# irb/lc/help-message.rb -
# $Release Version: 0.9.5$
-# $Revision: 1.4.2.2 $
-# $Date: 2005/04/19 19:24:59 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
diff --git a/lib/irb/lc/ja/error.rb b/lib/irb/lc/ja/error.rb
index 25f8af68e0..4c2fb3b839 100644
--- a/lib/irb/lc/ja/error.rb
+++ b/lib/irb/lc/ja/error.rb
@@ -1,8 +1,8 @@
#
# irb/lc/ja/error.rb -
# $Release Version: 0.9.5$
-# $Revision: 1.5.2.1 $
-# $Date: 2005/04/19 19:24:59 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
diff --git a/lib/irb/lc/ja/help-message b/lib/irb/lc/ja/help-message
index 606f9e8984..debbfe9355 100644
--- a/lib/irb/lc/ja/help-message
+++ b/lib/irb/lc/ja/help-message
@@ -1,8 +1,8 @@
#
# irb/lc/ja/help-message.rb -
# $Release Version: 0.9.5$
-# $Revision: 1.3.2.2 $
-# $Date: 2005/04/19 19:24:59 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
diff --git a/lib/irb/locale.rb b/lib/irb/locale.rb
index 1f4f9f67d8..5ed9f54507 100644
--- a/lib/irb/locale.rb
+++ b/lib/irb/locale.rb
@@ -1,8 +1,8 @@
#
# irb/locale.rb - internationalization module
# $Release Version: 0.9.5$
-# $Revision: 1.6.2.3 $
-# $Date: 2005/09/01 18:30:46 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
@@ -14,7 +14,7 @@ autoload :Kconv, "kconv"
module IRB
class Locale
- @RCS_ID='-$Id: locale.rb,v 1.6.2.3 2005/09/01 18:30:46 keiju Exp $-'
+ @RCS_ID='-$Id$-'
JPDefaultLocale = "ja"
LOCALE_DIR = "/lc/"
@@ -71,7 +71,7 @@ module IRB
end
def puts(*opts)
- ary = opts.collect{|opt| String(opts)}
+ ary = opts.collect{|opt| String(opt)}
super(*ary)
end
@@ -153,8 +153,8 @@ module IRB
end
def search_file(path, file)
- if File.exists?(p1 = path + lc_path(file, "C"))
- if File.exists?(p2 = path + lc_path(file))
+ if File.exist?(p1 = path + lc_path(file, "C"))
+ if File.exist?(p2 = path + lc_path(file))
return p2
else
end
diff --git a/lib/irb/notifier.rb b/lib/irb/notifier.rb
index b03f445873..0f79bc5a8d 100644
--- a/lib/irb/notifier.rb
+++ b/lib/irb/notifier.rb
@@ -1,8 +1,8 @@
#
-# notifier.rb - optput methods used by irb
+# notifier.rb - output methods used by irb
# $Release Version: 0.9.5$
-# $Revision: 1.2.4.1 $
-# $Date: 2005/04/19 19:24:57 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
diff --git a/lib/irb/output-method.rb b/lib/irb/output-method.rb
index 01bfefb5af..b9a3a8851e 100644
--- a/lib/irb/output-method.rb
+++ b/lib/irb/output-method.rb
@@ -1,8 +1,8 @@
#
# output-method.rb - optput methods used by irb
# $Release Version: 0.9.5$
-# $Revision: 1.2.4.1 $
-# $Date: 2005/04/19 19:24:57 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
@@ -17,7 +17,7 @@ module IRB
# StdioOutputMethod
class OutputMethod
- @RCS_ID='-$Id: output-method.rb,v 1.2.4.1 2005/04/19 19:24:57 keiju Exp $-'
+ @RCS_ID='-$Id$-'
def print(*opts)
IRB.fail NotImplementError, "print"
diff --git a/lib/irb/ruby-lex.rb b/lib/irb/ruby-lex.rb
index 6310fb626b..313a809ccd 100644
--- a/lib/irb/ruby-lex.rb
+++ b/lib/irb/ruby-lex.rb
@@ -1,8 +1,8 @@
#
-# irb/ruby-lex.rb - ruby lexcal analizer
+# irb/ruby-lex.rb - ruby lexcal analyzer
# $Release Version: 0.9.5$
-# $Revision: 1.22.2.6 $
-# $Date: 2006/08/04 10:15:49 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
@@ -15,7 +15,7 @@ require "irb/slex"
require "irb/ruby-token"
class RubyLex
- @RCS_ID='-$Id: ruby-lex.rb,v 1.22.2.6 2006/08/04 10:15:49 keiju Exp $-'
+ @RCS_ID='-$Id$-'
extend Exception2MessageMapper
def_exception(:AlreadyDefinedToken, "Already defined token(%s)")
diff --git a/lib/irb/ruby-token.rb b/lib/irb/ruby-token.rb
index 4d56754d36..525d4df14c 100644
--- a/lib/irb/ruby-token.rb
+++ b/lib/irb/ruby-token.rb
@@ -1,8 +1,8 @@
#
# irb/ruby-token.rb - ruby tokens
# $Release Version: 0.9.5$
-# $Revision: 1.5.2.1 $
-# $Date: 2005/04/19 19:24:57 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
diff --git a/lib/irb/slex.rb b/lib/irb/slex.rb
index ed99e8fc86..f7e3a3b2b2 100644
--- a/lib/irb/slex.rb
+++ b/lib/irb/slex.rb
@@ -1,8 +1,8 @@
#
-# irb/slex.rb - symple lex analizer
+# irb/slex.rb - simple lex analyzer
# $Release Version: 0.9.5$
-# $Revision: 1.6.2.3 $
-# $Date: 2005/04/19 19:24:57 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
@@ -15,7 +15,7 @@ require "irb/notifier"
module IRB
class SLex
- @RCS_ID='-$Id: slex.rb,v 1.6.2.3 2005/04/19 19:24:57 keiju Exp $-'
+ @RCS_ID='-$Id$-'
extend Exception2MessageMapper
def_exception :ErrNodeNothing, "node nothing"
diff --git a/lib/irb/version.rb b/lib/irb/version.rb
index 95192669db..28b079740a 100644
--- a/lib/irb/version.rb
+++ b/lib/irb/version.rb
@@ -1,8 +1,8 @@
#
# irb/version.rb - irb version definition file
# $Release Version: 0.9.5$
-# $Revision: 1.4.2.1 $
-# $Date: 2005/04/19 19:24:57 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ishitsuka.com)
#
# --
diff --git a/lib/irb/workspace.rb b/lib/irb/workspace.rb
index 364820f997..7d1794cd7b 100644
--- a/lib/irb/workspace.rb
+++ b/lib/irb/workspace.rb
@@ -1,8 +1,8 @@
#
# irb/workspace-binding.rb -
# $Release Version: 0.9.5$
-# $Revision: 1.5.2.2 $
-# $Date: 2005/04/19 19:24:57 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
diff --git a/lib/irb/ws-for-case-2.rb b/lib/irb/ws-for-case-2.rb
index ca30eb34c0..afd49d23e1 100644
--- a/lib/irb/ws-for-case-2.rb
+++ b/lib/irb/ws-for-case-2.rb
@@ -1,8 +1,8 @@
#
# irb/ws-for-case-2.rb -
# $Release Version: 0.9.5$
-# $Revision: 1.2.2.1 $
-# $Date: 2005/04/19 19:24:57 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
diff --git a/lib/irb/xmp.rb b/lib/irb/xmp.rb
index 0a0883245b..4bcc2ca22f 100644
--- a/lib/irb/xmp.rb
+++ b/lib/irb/xmp.rb
@@ -1,8 +1,8 @@
#
# xmp.rb - irb version of gotoken xmp
# $Release Version: 0.9$
-# $Revision: 1.3 $
-# $Date: 2002/07/09 11:17:16 $
+# $Revision$
+# $Date$
# by Keiju ISHITSUKA(Nippon Rational Inc.)
#
# --
@@ -14,7 +14,7 @@ require "irb"
require "irb/frame"
class XMP
- @RCS_ID='-$Id: xmp.rb,v 1.3 2002/07/09 11:17:16 keiju Exp $-'
+ @RCS_ID='-$Id$-'
def initialize(bind = nil)
IRB.init_config(nil)
diff --git a/lib/jcode.rb b/lib/jcode.rb
index e5367e815b..78422f296f 100644
--- a/lib/jcode.rb
+++ b/lib/jcode.rb
@@ -77,7 +77,7 @@ class String
def succ!
reg = end_regexp
- if self =~ reg
+ if $KCODE != 'NONE' && self =~ reg
succ_table = SUCC[$KCODE[0,1].downcase]
begin
self[-1] += succ_table[self[-1]]
diff --git a/lib/logger.rb b/lib/logger.rb
index 3012ac2cc7..25553b2593 100644
--- a/lib/logger.rb
+++ b/lib/logger.rb
@@ -1,4 +1,4 @@
-# logger.rb - saimple logging utility
+# logger.rb - simple logging utility
# Copyright (C) 2000-2003, 2005 NAKAMURA, Hiroshi <nakahiro@sarion.co.jp>.
require 'monitor'
@@ -10,7 +10,7 @@ require 'monitor'
# License::
# You can redistribute it and/or modify it under the same terms of Ruby's
# license; either the dual license version in 2003, or any later version.
-# Revision:: $Id: logger.rb,v 1.5.2.9 2006/08/04 22:00:21 drbrain Exp $
+# Revision:: $Id$
#
# == Description
#
@@ -170,8 +170,7 @@ require 'monitor'
class Logger
VERSION = "1.2.6"
- /: (\S+),v (\S+)/ =~ %q$Id: logger.rb,v 1.5.2.9 2006/08/04 22:00:21 drbrain Exp $
- ProgName = "#{$1}/#{$2}"
+ ProgName = "#{File.basename(__FILE__)}/#{VERSION}"
class Error < RuntimeError; end
class ShiftingError < Error; end
diff --git a/lib/matrix.rb b/lib/matrix.rb
index c62acdf9aa..b1ee76f34b 100644
--- a/lib/matrix.rb
+++ b/lib/matrix.rb
@@ -590,15 +590,21 @@ class Matrix
a = src.to_a
for k in 0..size
- if (akk = a[k][k]) == 0
- i = k
- begin
- Matrix.Raise ErrNotRegular if (i += 1) > size
- end while a[i][k] == 0
+ i = k
+ akk = a[k][k].abs
+ for j in (k+1)..size
+ v = a[j][k].abs
+ if v > akk
+ i = j
+ akk = v
+ end
+ end
+ Matrix.Raise ErrNotRegular if akk == 0
+ if i != k
a[i], a[k] = a[k], a[i]
@rows[i], @rows[k] = @rows[k], @rows[i]
- akk = a[k][k]
end
+ akk = a[k][k]
for i in 0 .. size
next if i == k
@@ -1081,7 +1087,7 @@ class Vector
other.compare_by(@elements)
end
- alias eqn? ==
+ alias eql? ==
#
# For internal use.
diff --git a/lib/mkmf.rb b/lib/mkmf.rb
index b1b90829f0..c9e738a128 100644
--- a/lib/mkmf.rb
+++ b/lib/mkmf.rb
@@ -12,7 +12,7 @@ CXX_EXT = %w[cc cxx cpp]
if /mswin|bccwin|mingw|msdosdjgpp|human|os2/ !~ CONFIG['build_os']
CXX_EXT.concat(%w[C])
end
-SRC_EXT = %w[c m] << CXX_EXT
+SRC_EXT = %w[c m].concat(CXX_EXT)
$static = $config_h = nil
$default_static = $static
@@ -51,6 +51,9 @@ $archdir = CONFIG["archdir"]
$sitedir = CONFIG["sitedir"]
$sitelibdir = CONFIG["sitelibdir"]
$sitearchdir = CONFIG["sitearchdir"]
+$vendordir = CONFIG["vendordir"]
+$vendorlibdir = CONFIG["vendorlibdir"]
+$vendorarchdir = CONFIG["vendorarchdir"]
$mswin = /mswin/ =~ RUBY_PLATFORM
$bccwin = /bccwin/ =~ RUBY_PLATFORM
@@ -63,40 +66,56 @@ $beos = /beos/ =~ RUBY_PLATFORM
$solaris = /solaris/ =~ RUBY_PLATFORM
$dest_prefix_pattern = (File::PATH_SEPARATOR == ';' ? /\A([[:alpha:]]:)?/ : /\A/)
+# :stopdoc:
+
def config_string(key, config = CONFIG)
s = config[key] and !s.empty? and block_given? ? yield(s) : s
end
def dir_re(dir)
- Regexp.new('\$(?:\('+dir+'\)|\{'+dir+'\})(?:\$\(target_prefix\)|\{target_prefix\})?')
+ Regexp.new('\$(?:\('+dir+'\)|\{'+dir+'\})(?:\$(?:\(target_prefix\)|\{target_prefix\}))?')
end
INSTALL_DIRS = [
[dir_re('commondir'), "$(RUBYCOMMONDIR)"],
- [dir_re("sitedir"), "$(RUBYCOMMONDIR)"],
+ [dir_re('sitedir'), "$(RUBYCOMMONDIR)"],
+ [dir_re('vendordir'), "$(RUBYCOMMONDIR)"],
[dir_re('rubylibdir'), "$(RUBYLIBDIR)"],
[dir_re('archdir'), "$(RUBYARCHDIR)"],
[dir_re('sitelibdir'), "$(RUBYLIBDIR)"],
- [dir_re('sitearchdir'), "$(RUBYARCHDIR)"]
+ [dir_re('vendorlibdir'), "$(RUBYLIBDIR)"],
+ [dir_re('sitearchdir'), "$(RUBYARCHDIR)"],
+ [dir_re('bindir'), "$(BINDIR)"],
+ [dir_re('vendorarchdir'), "$(RUBYARCHDIR)"],
]
def install_dirs(target_prefix = nil)
if $extout
dirs = [
- ['RUBYCOMMONDIR', '$(extout)'],
- ['RUBYLIBDIR', '$(extout)$(target_prefix)'],
+ ['BINDIR', '$(extout)/bin'],
+ ['RUBYCOMMONDIR', '$(extout)/common'],
+ ['RUBYLIBDIR', '$(RUBYCOMMONDIR)$(target_prefix)'],
['RUBYARCHDIR', '$(extout)/$(arch)$(target_prefix)'],
['extout', "#$extout"],
['extout_prefix', "#$extout_prefix"],
]
elsif $extmk
dirs = [
+ ['BINDIR', '$(bindir)'],
['RUBYCOMMONDIR', '$(rubylibdir)'],
['RUBYLIBDIR', '$(rubylibdir)$(target_prefix)'],
['RUBYARCHDIR', '$(archdir)$(target_prefix)'],
]
+ elsif $configure_args.has_key?('--vendor')
+ dirs = [
+ ['BINDIR', '$(bindir)'],
+ ['RUBYCOMMONDIR', '$(vendordir)$(target_prefix)'],
+ ['RUBYLIBDIR', '$(vendorlibdir)$(target_prefix)'],
+ ['RUBYARCHDIR', '$(vendorarchdir)$(target_prefix)'],
+ ]
else
dirs = [
+ ['BINDIR', '$(bindir)'],
['RUBYCOMMONDIR', '$(sitedir)$(target_prefix)'],
['RUBYLIBDIR', '$(sitelibdir)$(target_prefix)'],
['RUBYARCHDIR', '$(sitearchdir)$(target_prefix)'],
@@ -114,13 +133,12 @@ end
topdir = File.dirname(libdir = File.dirname(__FILE__))
extdir = File.expand_path("ext", topdir)
$extmk = File.expand_path($0)[0, extdir.size+1] == extdir+"/"
-if not $extmk and File.exist?(Config::CONFIG["archdir"] + "/ruby.h")
- $hdrdir = $topdir = Config::CONFIG["archdir"]
-elsif File.exist?(($top_srcdir ||= topdir) + "/ruby.h") and
+if not $extmk and File.exist?(($hdrdir = Config::CONFIG["archdir"]) + "/ruby.h")
+ $topdir = $hdrdir
+elsif File.exist?(($hdrdir = ($top_srcdir ||= topdir)) + "/ruby.h") and
File.exist?(($topdir ||= Config::CONFIG["topdir"]) + "/config.h")
- $hdrdir = $top_srcdir
else
- abort "can't find header files for ruby."
+ abort "mkmf.rb can't find header files for ruby at #{$hdrdir}/ruby.h"
end
OUTFLAG = CONFIG['OUTFLAG']
@@ -129,11 +147,18 @@ CPPOUTFILE = CONFIG['CPPOUTFILE']
CONFTEST_C = "conftest.c"
class String
+ # Wraps a string in escaped quotes if it contains whitespace.
def quote
- /\s/ =~ self ? "\"#{self}\"" : self
+ /\s/ =~ self ? "\"#{self}\"" : "#{self}"
+ end
+
+ # Generates a string used as cpp macro name.
+ def tr_cpp
+ strip.upcase.tr_s("^A-Z0-9_", "_")
end
end
class Array
+ # Wraps all strings in escaped quotes if they contain whitespace.
def quote
map {|s| s.quote}
end
@@ -143,6 +168,8 @@ def rm_f(*files)
FileUtils.rm_f(Dir[files.join("\0")])
end
+# Returns time stamp of the +target+ file if it exists and is newer
+# than or equal to all of +times+.
def modified?(target, times)
(t = File.mtime(target)) rescue return nil
Array === times or times = [times]
@@ -165,12 +192,19 @@ def merge_libs(*libs)
end
end
+# This is a custom logging module. It generates an mkmf.log file when you
+# run your extconf.rb script. This can be useful for debugging unexpected
+# failures.
+#
+# This module and its associated methods are meant for internal use only.
+#
module Logging
@log = nil
@logfile = 'mkmf.log'
@orgerr = $stderr.dup
@orgout = $stdout.dup
@postpone = 0
+ @quiet = $extmk
def self::open
@log ||= File::open(@logfile, 'w')
@@ -214,9 +248,19 @@ module Logging
end
end
end
+
+ class << self
+ attr_accessor :quiet
+ end
end
def xsystem command
+ varpat = /\$\((\w+)\)|\$\{(\w+)\}/
+ if varpat =~ command
+ vars = Hash.new {|h, k| h[k] = ''; ENV[k]}
+ command = command.dup
+ nil while command.gsub!(varpat) {vars[$1||$2]}
+ end
Logging::open do
puts command.quote
system(command)
@@ -265,7 +309,7 @@ ensure
log_src(src)
end
-def link_command(ldflags, opt="", libpath=$LIBPATH)
+def link_command(ldflags, opt="", libpath=$DEFLIBPATH|$LIBPATH)
conf = Config::CONFIG.merge('hdrdir' => $hdrdir.quote,
'src' => CONFTEST_C,
'INCFLAGS' => $INCFLAGS,
@@ -291,9 +335,14 @@ def cpp_command(outfile, opt="")
conf)
end
-def libpathflag(libpath=$LIBPATH)
+def libpathflag(libpath=$DEFLIBPATH|$LIBPATH)
libpath.map{|x|
- (x == "$(topdir)" ? LIBPATHFLAG : LIBPATHFLAG+RPATHFLAG) % x.quote
+ case x
+ when "$(topdir)", /\A\./
+ LIBPATHFLAG
+ else
+ LIBPATHFLAG+RPATHFLAG
+ end % x.quote
}.join
end
@@ -413,16 +462,16 @@ end
def try_func(func, libs, headers = nil, &b)
headers = cpp_include(headers)
try_link(<<"SRC", libs, &b) or try_link(<<"SRC", libs, &b)
+#{COMMON_HEADERS}
#{headers}
/*top*/
int main() { return 0; }
-int t() { #{func}(); return 0; }
+int t() { void ((*volatile p)()); p = (void ((*)()))#{func}; return 0; }
SRC
-#{COMMON_HEADERS}
#{headers}
/*top*/
int main() { return 0; }
-int t() { void ((*volatile p)()); p = (void ((*)()))#{func}; return 0; }
+int t() { #{func}(); return 0; }
SRC
end
@@ -433,7 +482,7 @@ def try_var(var, headers = nil, &b)
#{headers}
/*top*/
int main() { return 0; }
-int t() { const volatile void *volatile p; p = (void *)&#{var}; return 0; }
+int t() { const volatile void *volatile p; p = &(&#{var})[0]; return 0; }
SRC
end
@@ -463,6 +512,7 @@ ensure
log_src(src)
end
+# This is used internally by the have_macro? method.
def macro_defined?(macro, src, opt = "", &b)
src = src.sub(/[^\n]\z/, "\\&\n")
try_compile(src + <<"SRC", opt, &b)
@@ -486,13 +536,14 @@ end
def install_files(mfile, ifiles, map = nil, srcprefix = nil)
ifiles or return
+ ifiles.empty? and return
srcprefix ||= '$(srcdir)'
Config::expand(srcdir = srcprefix.dup)
dirs = []
path = Hash.new {|h, i| h[i] = dirs.push([i])[-1]}
ifiles.each do |files, dir, prefix|
dir = map_dir(dir, map)
- prefix = %r|\A#{Regexp.quote(prefix)}/?| if prefix
+ prefix &&= %r|\A#{Regexp.quote(prefix)}/?|
if /\A\.\// =~ files
# install files which are in current working directory.
files = files[2..-1]
@@ -505,6 +556,10 @@ def install_files(mfile, ifiles, map = nil, srcprefix = nil)
f = nil
Dir.glob(files) do |f|
f[0..len] = "" if len
+ case File.basename(f)
+ when *$NONINSTALLFILES
+ next
+ end
d = File.dirname(f)
d.sub!(prefix, "") if prefix
d = (d.empty? || d == ".") ? dir : File.join(dir, d)
@@ -525,20 +580,25 @@ def install_rb(mfile, dest, srcdir = nil)
install_files(mfile, [["lib/**/*.rb", dest, "lib"]], nil, srcdir)
end
-def append_library(libs, lib)
+def append_library(libs, lib) # :no-doc:
format(LIBARG, lib) + " " + libs
end
def message(*s)
- unless $extmk and not $VERBOSE
+ unless Logging.quiet and not $VERBOSE
printf(*s)
$stdout.flush
end
end
+# This emits a string to stdout that allows users to see the results of the
+# various have* and find* methods as they are tested.
+#
+# Internal use only.
+#
def checking_for(m, fmt = nil)
f = caller[0][/in `(.*)'$/, 1] and f << ": " #` for vim
- m = "checking #{'for ' if /\Acheck/ !~ f}#{m}... "
+ m = "checking #{/\Acheck/ =~ f ? '' : 'for '}#{m}... "
message "%s", m
a = r = nil
Logging::postpone do
@@ -551,15 +611,29 @@ def checking_for(m, fmt = nil)
r
end
+def checking_message(target, place = nil, opt = nil)
+ [["in", place], ["with", opt]].inject("#{target}") do |msg, (pre, noun)|
+ if noun
+ [[:to_str], [:join, ","], [:to_s]].each do |meth, *args|
+ if noun.respond_to?(meth)
+ break noun = noun.send(meth, *args)
+ end
+ end
+ msg << " #{pre} #{noun}" unless noun.empty?
+ end
+ msg
+ end
+end
+
+# :startdoc:
+
# Returns whether or not +macro+ is defined either in the common header
# files or within any +headers+ you provide.
#
# Any options you pass to +opt+ are passed along to the compiler.
#
def have_macro(macro, headers = nil, opt = "", &b)
- m = "#{macro}"
- m << " in #{headers.inspect}" if headers
- checking_for m do
+ checking_for checking_message(macro, headers, opt) do
macro_defined?(macro, cpp_include(headers), opt, &b)
end
end
@@ -572,13 +646,13 @@ end
# If +headers+ are provided, it will include those header files as the
# header files it looks in when searching for +func+.
#
-# Real name of the library to be linked can be altered by
+# The real name of the library to be linked can be altered by
# '--with-FOOlib' configuration option.
#
def have_library(lib, func = nil, headers = nil, &b)
func = "main" if !func or func.empty?
lib = with_config(lib+'lib', lib)
- checking_for "#{func}() in #{LIBARG%lib}" do
+ checking_for checking_message("#{func}()", LIBARG%lib) do
if COMMON_LIBS.include?(lib)
true
else
@@ -631,9 +705,9 @@ end
# preprocessor macro would be passed to the compiler.
#
def have_func(func, headers = nil, &b)
- checking_for "#{func}()" do
+ checking_for checking_message("#{func}()", headers) do
if try_func(func, $libs, headers, &b)
- $defs.push(format("-DHAVE_%s", func.upcase))
+ $defs.push(format("-DHAVE_%s", func.tr_cpp))
true
else
false
@@ -650,9 +724,9 @@ end
# preprocessor macro would be passed to the compiler.
#
def have_var(var, headers = nil, &b)
- checking_for "#{var}" do
+ checking_for checking_message(var, headers) do
if try_var(var, headers, &b)
- $defs.push(format("-DHAVE_%s", var.upcase))
+ $defs.push(format("-DHAVE_%s", var.tr_cpp))
true
else
false
@@ -685,8 +759,9 @@ end
# of included directories that are sent to the compiler (via the -I switch).
#
def find_header(header, *paths)
+ message = checking_message(header, paths)
header = cpp_include(header)
- checking_for header do
+ checking_for message do
if try_cpp(header)
true
else
@@ -712,11 +787,11 @@ end
# If found, a macro is passed as a preprocessor constant to the compiler using
# the member name, in uppercase, prepended with 'HAVE_ST_'.
#
-# For example, if have_struct_member('foo', 'bar') returned true, then the
+# For example, if have_struct_member('struct foo', 'bar') returned true, then the
# HAVE_ST_BAR preprocessor macro would be passed to the compiler.
#
def have_struct_member(type, member, headers = nil, &b)
- checking_for "#{type}.#{member}" do
+ checking_for checking_message("#{type}.#{member}", headers) do
if try_compile(<<"SRC", &b)
#{COMMON_HEADERS}
#{cpp_include(headers)}
@@ -724,7 +799,7 @@ def have_struct_member(type, member, headers = nil, &b)
int main() { return 0; }
int s = (char *)&((#{type}*)0)->#{member} - (char *)0;
SRC
- $defs.push(format("-DHAVE_ST_%s", member.upcase))
+ $defs.push(format("-DHAVE_ST_%s", member.tr_cpp))
true
else
false
@@ -732,6 +807,21 @@ SRC
end
end
+def try_type(type, headers = nil, opt = "", &b)
+ if try_compile(<<"SRC", opt, &b)
+#{COMMON_HEADERS}
+#{cpp_include(headers)}
+/*top*/
+typedef #{type} conftest_type;
+int conftestval[sizeof(conftest_type)?1:-1];
+SRC
+ $defs.push(format("-DHAVE_TYPE_%s", type.tr_cpp))
+ true
+ else
+ false
+ end
+end
+
# Returns whether or not the static type +type+ is defined. You may
# optionally pass additional +headers+ to check against in addition to the
# common header files.
@@ -746,24 +836,66 @@ end
# preprocessor macro would be passed to the compiler.
#
def have_type(type, headers = nil, opt = "", &b)
- checking_for type do
- headers = cpp_include(headers)
- if try_compile(<<"SRC", opt, &b) or (/\A\w+\z/n =~ type && try_compile(<<"SRC", opt, &b))
-#{COMMON_HEADERS}
-#{headers}
-/*top*/
-static #{type} t;
-SRC
+ checking_for checking_message(type, headers, opt) do
+ try_type(type, headers, opt, &b)
+ end
+end
+
+# Returns where the static type +type+ is defined.
+#
+# You may also pass additional flags to +opt+ which are then passed along to
+# the compiler.
+#
+# See also +have_type+.
+#
+def find_type(type, opt, *headers, &b)
+ opt ||= ""
+ fmt = "not found"
+ def fmt.%(x)
+ x ? x.respond_to?(:join) ? x.join(",") : x : self
+ end
+ checking_for checking_message(type, nil, opt), fmt do
+ headers.find do |h|
+ try_type(type, h, opt, &b)
+ end
+ end
+end
+
+def try_const(const, headers = nil, opt = "", &b)
+ const, type = *const
+ if try_compile(<<"SRC", opt, &b)
#{COMMON_HEADERS}
-#{headers}
+#{cpp_include(headers)}
/*top*/
-static #{type} *t;
+typedef #{type || 'int'} conftest_type;
+conftest_type conftestval = #{type ? '' : '(int)'}#{const};
SRC
- $defs.push(format("-DHAVE_TYPE_%s", type.strip.upcase.tr_s("^A-Z0-9_", "_")))
- true
- else
- false
- end
+ $defs.push(format("-DHAVE_CONST_%s", const.tr_cpp))