Initial revision

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@8 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
matz 1998-01-16 12:19:09 +00:00
parent 3db12e8b23
commit 62e41d3f2e
56 changed files with 13850 additions and 0 deletions

17
.cvsignore Normal file
View File

@ -0,0 +1,17 @@
parse.c
newver.rb
ruby
miniruby
README.fat-patch
config.cache
config.h
config.log
config.status
Makefile
ppack
archive
*.orig
*.rej
*.bak
*.sav
*~

248
COPYING Normal file
View File

@ -0,0 +1,248 @@
GNU GENERAL PUBLIC LICENSE
Version 1, February 1989
Copyright (C) 1989 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The license agreements of most software companies try to keep users
at the mercy of those companies. By contrast, our General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. The
General Public License applies to the Free Software Foundation's
software and to any other program whose authors commit to using it.
You can use it for your programs, too.
When we speak of free software, we are referring to freedom, not
price. Specifically, the General Public License is designed to make
sure that you have the freedom to give away or sell copies of free
software, that you receive source code or can get it if you want it,
that you can change the software or use pieces of it in new free
programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of a such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must tell them their rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any program or other work which
contains a notice placed by the copyright holder saying it may be
distributed under the terms of this General Public License. The
"Program", below, refers to any such program or work, and a "work based
on the Program" means either the Program or any work containing the
Program or a portion of it, either verbatim or with modifications. Each
licensee is addressed as "you".
1. You may copy and distribute verbatim copies of the Program's source
code as you receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice and
disclaimer of warranty; keep intact all the notices that refer to this
General Public License and to the absence of any warranty; and give any
other recipients of the Program a copy of this General Public License
along with the Program. You may charge a fee for the physical act of
transferring a copy.
2. You may modify your copy or copies of the Program or any portion of
it, and copy and distribute such modifications under the terms of Paragraph
1 above, provided that you also do the following:
a) cause the modified files to carry prominent notices stating that
you changed the files and the date of any change; and
b) cause the whole of any work that you distribute or publish, that
in whole or in part contains the Program or any part thereof, either
with or without modifications, to be licensed at no charge to all
third parties under the terms of this General Public License (except
that you may choose to grant warranty protection to some or all
third parties, at your option).
c) If the modified program normally reads commands interactively when
run, you must cause it, when started running for such interactive use
in the simplest and most usual way, to print or display an
announcement including an appropriate copyright notice and a notice
that there is no warranty (or else, saying that you provide a
warranty) and that users may redistribute the program under these
conditions, and telling the user how to view a copy of this General
Public License.
d) You may charge a fee for the physical act of transferring a
copy, and you may at your option offer warranty protection in
exchange for a fee.
Mere aggregation of another independent work with the Program (or its
derivative) on a volume of a storage or distribution medium does not bring
the other work under the scope of these terms.
3. You may copy and distribute the Program (or a portion or derivative of
it, under Paragraph 2) in object code or executable form under the terms of
Paragraphs 1 and 2 above provided that you also do one of the following:
a) accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of
Paragraphs 1 and 2 above; or,
b) accompany it with a written offer, valid for at least three
years, to give any third party free (except for a nominal charge
for the cost of distribution) a complete machine-readable copy of the
corresponding source code, to be distributed under the terms of
Paragraphs 1 and 2 above; or,
c) accompany it with the information you received as to where the
corresponding source code may be obtained. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form alone.)
Source code for a work means the preferred form of the work for making
modifications to it. For an executable file, complete source code means
all the source code for all modules it contains; but, as a special
exception, it need not include source code for modules which are standard
libraries that accompany the operating system on which the executable
file runs, or for standard header files or definitions files that
accompany that operating system.
4. You may not copy, modify, sublicense, distribute or transfer the
Program except as expressly provided under this General Public License.
Any attempt otherwise to copy, modify, sublicense, distribute or transfer
the Program is void, and will automatically terminate your rights to use
the Program under this License. However, parties who have received
copies, or rights to use copies, from you under this General Public
License will not have their licenses terminated so long as such parties
remain in full compliance.
5. By copying, distributing or modifying the Program (or any work based
on the Program) you indicate your acceptance of this license to do so,
and all its terms and conditions.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the original
licensor to copy, distribute or modify the Program subject to these
terms and conditions. You may not impose any further restrictions on the
recipients' exercise of the rights granted herein.
7. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of the license which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
the license, you may choose any version ever published by the Free Software
Foundation.
8. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to humanity, the best way to achieve this is to make it
free software which everyone can redistribute and change under these
terms.
To do so, attach the following notices to the program. It is safest to
attach them to the start of each source file to most effectively convey
the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19xx name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the
appropriate parts of the General Public License. Of course, the
commands you use may be called something other than `show w' and `show
c'; they could even be mouse-clicks or menu items--whatever suits your
program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
program `Gnomovision' (a program to direct compilers to make passes
at assemblers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
That's all there is to it!

18
ext/gtk/MANIFEST Normal file
View File

@ -0,0 +1,18 @@
MANIFEST
extconf.rb
gtk.c
test.rb
test.xpm
test0.rb
test1.rb
test2.rb
test3.rb
test4.rb
test5.rb
test6.rb
test7.rb
test8.rb
test9.rb
testa.rb
testb.rb
testc.rb

6
ext/gtk/extconf.rb Normal file
View File

@ -0,0 +1,6 @@
require "mkmf"
if have_library("glib", "g_print") and
have_library("gdk", "gdk_init") and
have_library("gtk", "gtk_init")
create_makefile("gtk")
end

5904
ext/gtk/gtk.c Normal file

File diff suppressed because it is too large Load Diff

96
ext/gtk/test.rb Normal file
View File

@ -0,0 +1,96 @@
require 'gtk'
def create_menu(depth)
return nil if depth < 1
menu = Gtk::Menu::new()
group = nil
submenu = nil
for i in 0..4
buf = sprintf("item %2d - %d", depth, i+1)
# menuitem = Gtk::MenuItem::new(buf)
menuitem = Gtk::RadioMenuItem.new(group, buf)
group = menuitem.group
if depth % 2
menuitem.set_show_toggle TRUE
end
menu.append menuitem
menuitem.show
if depth > 0
unless submenu
submenu = create_menu(depth - 1)
end
menuitem.set_submenu submenu
end
end
return menu
end
window = Gtk::Window::new(Gtk::WINDOW_TOPLEVEL)
window.signal_connect("destroy") do
exit
end
window.signal_connect("delete_event") do
exit
end
window.set_title("menus")
window.border_width(0)
box1 = Gtk::VBox::new(FALSE, 0)
window.add box1
box1.show
menubar = Gtk::MenuBar::new()
box1.pack_start menubar, FALSE, TRUE, 0
menubar.show
menu = create_menu(2)
menuitem = Gtk::MenuItem::new("test\nline2")
menuitem.set_submenu menu
menubar.append menuitem
menuitem.show
menuitem = Gtk::MenuItem::new("foo")
menuitem.set_submenu menu
menubar.append menuitem
menuitem.show
menuitem = Gtk::MenuItem::new("bar")
menuitem.set_submenu menu
menubar.append menuitem
menuitem.show
box2 = Gtk::VBox::new(FALSE, 10)
box2.border_width 10
box1.pack_start box2, TRUE, TRUE, 0
box2.show
optionmenu = Gtk::OptionMenu::new()
optionmenu.set_menu create_menu(1)
optionmenu.set_history 4
box2.pack_start optionmenu, TRUE, TRUE, 0
optionmenu.show
separator = Gtk::HSeparator::new()
box1.pack_start(separator, FALSE, TRUE, 0)
separator.show
box2 = Gtk::HBox::new(FALSE, 10)
box2.border_width(10)
box1.pack_start(box2, FALSE, TRUE, 0)
box2.show
button = Gtk::Button::new("close")
button.signal_connect("clicked") do
window.destroy
exit
end
box2.pack_start(button, TRUE, TRUE, 0)
button.set_flags(Gtk::CAN_DEFAULT);
button.grab_default
button.show
window.show
Gtk::main()

92
ext/gtk/test.xpm Normal file
View File

@ -0,0 +1,92 @@
/* XPM */
static char *openfile[] = {
/* width height num_colors chars_per_pixel */
" 20 19 66 2",
/* colors */
".. c None",
".# c #000000",
".a c #dfdfdf",
".b c #7f7f7f",
".c c #006f6f",
".d c #00efef",
".e c #009f9f",
".f c #004040",
".g c #00bfbf",
".h c #ff0000",
".i c #ffffff",
".j c #7f0000",
".k c #007070",
".l c #00ffff",
".m c #00a0a0",
".n c #004f4f",
".o c #00cfcf",
".p c #8f8f8f",
".q c #6f6f6f",
".r c #a0a0a0",
".s c #7f7f00",
".t c #007f7f",
".u c #5f5f5f",
".v c #707070",
".w c #00f0f0",
".x c #009090",
".y c #ffff00",
".z c #0000ff",
".A c #00afaf",
".B c #00d0d0",
".C c #00dfdf",
".D c #005f5f",
".E c #00b0b0",
".F c #001010",
".G c #00c0c0",
".H c #000f0f",
".I c #00007f",
".J c #005050",
".K c #002f2f",
".L c #dfcfcf",
".M c #dfd0d0",
".N c #006060",
".O c #00e0e0",
".P c #00ff00",
".Q c #002020",
".R c #dfc0c0",
".S c #008080",
".T c #001f1f",
".U c #003f3f",
".V c #007f00",
".W c #00000f",
".X c #000010",
".Y c #00001f",
".Z c #000020",
".0 c #00002f",
".1 c #000030",
".2 c #00003f",
".3 c #000040",
".4 c #00004f",
".5 c #000050",
".6 c #00005f",
".7 c #000060",
".8 c #00006f",
".9 c #000070",
"#. c #7f7f80",
"## c #9f9f9f",
/* pixels */
"........................................",
"........................................",
"........................................",
".......................#.#.#............",
".....................#.......#...#......",
"...............................#.#......",
".......#.#.#.................#.#.#......",
".....#.y.i.y.#.#.#.#.#.#.#..............",
".....#.i.y.i.y.i.y.i.y.i.#..............",
".....#.y.i.y.i.y.i.y.i.y.#..............",
".....#.i.y.i.y.#.#.#.#.#.#.#.#.#.#.#....",
".....#.y.i.y.#.s.s.s.s.s.s.s.s.s.#......",
".....#.i.y.#.s.s.s.s.s.s.s.s.s.#........",
".....#.y.#.s.s.s.s.s.s.s.s.s.#..........",
".....#.#.s.s.s.s.s.s.s.s.s.#............",
".....#.#.#.#.#.#.#.#.#.#.#..............",
"........................................",
"........................................",
"........................................"
};

13
ext/gtk/test0.rb Normal file
View File

@ -0,0 +1,13 @@
require 'gtk'
window = Gtk::Window::new(Gtk::WINDOW_TOPLEVEL)
window.border_width(10)
button = Gtk::Button::new("Hello World")
button.signal_connect("clicked") do
print "hello world\n"
exit
end
window.add(button)
button.show
window.show
Gtk::main()

41
ext/gtk/test1.rb Normal file
View File

@ -0,0 +1,41 @@
require 'gtk'
window = Gtk::Window::new(Gtk::WINDOW_TOPLEVEL)
window.set_title("entry")
window.border_width(0)
box1 = Gtk::VBox::new(FALSE, 0)
window.add(box1)
box1.show
box2 = Gtk::VBox::new(FALSE, 10)
box2.border_width(10)
box1.pack_start(box2, TRUE, TRUE, 0)
box2.show
entry = Gtk::Entry::new()
entry.set_text("hello world")
box2.pack_start(entry, TRUE, TRUE, 0)
entry.show
separator = Gtk::HSeparator::new()
box1.pack_start(separator, FALSE, TRUE, 0)
separator.show
box2 = Gtk::VBox::new(FALSE, 10)
box2.border_width(10)
box1.pack_start(box2, FALSE, TRUE, 0)
box2.show
button = Gtk::Button::new("close")
button.signal_connect("clicked") do
window.destroy
exit
end
box2.pack_start(button, TRUE, TRUE, 0)
button.set_flags(Gtk::CAN_DEFAULT);
button.grab_default
button.show
window.show
Gtk::main()

89
ext/gtk/test2.rb Normal file
View File

@ -0,0 +1,89 @@
require 'gtk'
window = Gtk::Window::new(Gtk::WINDOW_TOPLEVEL)
window.set_title("list")
window.border_width(0)
box1 = Gtk::VBox::new(FALSE, 0)
window.add(box1)
box1.show
box2 = Gtk::VBox::new(FALSE, 10)
box2.border_width(10)
box1.pack_start(box2, TRUE, TRUE, 0)
box2.show
scrolled_win = Gtk::ScrolledWindow::new()
scrolled_win.set_policy(Gtk::POLICY_AUTOMATIC,Gtk::POLICY_AUTOMATIC)
box2.pack_start(scrolled_win, TRUE, TRUE, 0)
scrolled_win.show
list = Gtk::List::new()
list.set_selection_mode(Gtk::SELECTION_MULTIPLE)
list.set_selection_mode(Gtk::SELECTION_BROWSE)
scrolled_win.add(list)
list.show
for i in [
"hello",
"world",
"blah",
"foo",
"bar",
"argh",
"spencer",
"is a",
"wussy",
"programmer",
]
list_item = Gtk::ListItem::new(i)
list.add(list_item)
list_item.show
end
button = Gtk::Button::new("add")
button.set_flags(Gtk::CAN_FOCUS);
i = 1
button.signal_connect("clicked") do
list_item = Gtk::ListItem::new(format("added item %d", i))
list.add(list_item)
list_item.show
i += 1
end
box2.pack_start(button, FALSE, TRUE, 0)
button.show
button = Gtk::Button::new("remove")
button.set_flags(Gtk::CAN_FOCUS);
button.signal_connect("clicked") do
tmp_list = list.selection
list.remove_items(tmp_list)
for i in tmp_list
i.destroy
end
end
box2.pack_start(button, FALSE, TRUE, 0)
button.show
separator = Gtk::HSeparator::new()
box1.pack_start(separator, FALSE, TRUE, 0)
separator.show
box2 = Gtk::VBox::new(FALSE, 10)
box2.border_width(10)
box1.pack_start(box2, FALSE, TRUE, 0)
box2.show
button = Gtk::Button::new("close")
button.signal_connect("clicked") do
window.destroy
exit
end
box2.pack_start(button, TRUE, TRUE, 0)
button.set_flags(Gtk::CAN_DEFAULT);
button.grab_default
button.show
window.show
Gtk::main()

16
ext/gtk/test3.rb Normal file
View File

@ -0,0 +1,16 @@
require 'gtk'
window = Gtk::FileSelection::new("file selection dialog")
window.position(Gtk::WIN_POS_MOUSE)
window.border_width(0)
window.ok_button.signal_connect("clicked") do
print window.get_filename, "\n"
end
window.cancel_button.signal_connect("clicked") do
window.destroy
exit
end
window.show
Gtk::main()

77
ext/gtk/test4.rb Normal file
View File

@ -0,0 +1,77 @@
require 'gtk'
window = Gtk::Window::new(Gtk::WINDOW_TOPLEVEL)
window.set_title("notebook")
window.border_width(0)
box1 = Gtk::VBox::new(FALSE, 0)
window.add(box1)
box1.show
box2 = Gtk::VBox::new(FALSE, 10)
box2.border_width(10)
box1.pack_start(box2, TRUE, TRUE, 0)
box2.show
notebook = Gtk::Notebook::new()
notebook.set_tab_pos(Gtk::POS_TOP)
box2.pack_start(notebook, TRUE, TRUE, 0)
notebook.show
for i in 1..5
frame = Gtk::Frame::new(format("Page %d", i))
frame.border_width(10)
frame.set_usize(200, 150)
frame.show
label = Gtk::Label::new(format("Box %d", i))
frame.add label
label.show
label = Gtk::Label::new(format("Tab %d", i))
notebook.append_page frame, label
end
separator = Gtk::HSeparator::new()
box1.pack_start(separator, FALSE, TRUE, 0)
separator.show
box2 = Gtk::HBox::new(FALSE, 10)
box2.border_width(10)
box1.pack_start(box2, FALSE, TRUE, 0)
box2.show
button = Gtk::Button::new("close")
button.signal_connect("clicked") do
window.destroy
exit
end
box2.pack_start(button, TRUE, TRUE, 0)
button.set_flags(Gtk::CAN_DEFAULT);
button.grab_default
button.show
button = Gtk::Button::new("next")
button.signal_connect("clicked") do
notebook.next_page
end
box2.pack_start(button, TRUE, TRUE, 0)
button.show
button = Gtk::Button::new("prev")
button.signal_connect("clicked") do
notebook.prev_page
end
box2.pack_start(button, TRUE, TRUE, 0)
button.show
button = Gtk::Button::new("rotate")
button.signal_connect("clicked") do
notebook.set_tab_pos((notebook.tab_pos+1)%4)
end
box2.pack_start(button, TRUE, TRUE, 0)
button.show
window.show
Gtk::main()

63
ext/gtk/test5.rb Normal file
View File

@ -0,0 +1,63 @@
require 'gtk'
window = Gtk::Window::new(Gtk::WINDOW_TOPLEVEL)
window.set_title("buttons")
window.border_width(0)
box1 = Gtk::VBox::new(FALSE, 0)
window.add(box1)
box1.show
table = Gtk::Table::new(3, 3, FALSE)
table.set_row_spacings(5)
table.set_col_spacings(5)
table.border_width(10)
box1.pack_start(table, TRUE, TRUE, 0)
table.show
button = []
0.upto(8) do |i|
button.push Gtk::Button::new("button"+(i+1))
end
0.upto(8) do |i|
button[i].signal_connect("clicked") do |w|
if button[i+1].visible?
button[i+1].hide
else
button[i+1].show
end
end
button[i].show
end
table.attach(button[0], 0, 1, 0, 1, nil, nil, 0, 0)
table.attach(button[1], 1, 2, 1, 2, nil, nil, 0, 0)
table.attach(button[2], 2, 3, 2, 3, nil, nil, 0, 0)
table.attach(button[3], 0, 1, 2, 3, nil, nil, 0, 0)
table.attach(button[4], 2, 3, 0, 1, nil, nil, 0, 0)
table.attach(button[5], 1, 2, 2, 3, nil, nil, 0, 0)
table.attach(button[6], 1, 2, 0, 1, nil, nil, 0, 0)
table.attach(button[7], 2, 3, 1, 2, nil, nil, 0, 0)
table.attach(button[8], 0, 1, 1, 2, nil, nil, 0, 0)
separator = Gtk::HSeparator::new()
box1.pack_start(separator, FALSE, TRUE, 0)
separator.show
box2 = Gtk::VBox::new(FALSE, 10)
box2.border_width(10)
box1.pack_start(box2, FALSE, TRUE, 0)
box2.show
close = Gtk::Button::new("close")
close.signal_connect("clicked") do
window.destroy
exit
end
box2.pack_start(close, TRUE, TRUE, 0)
close.set_flags(Gtk::CAN_DEFAULT);
close.grab_default
close.show
window.show
Gtk::main()

49
ext/gtk/test6.rb Normal file
View File

@ -0,0 +1,49 @@
require 'gtk'
window = Gtk::Window::new(Gtk::WINDOW_TOPLEVEL)
window.set_title("toggle buttons")
window.border_width(0)
box1 = Gtk::VBox::new(FALSE, 0)
window.add(box1)
box1.show
box2 = Gtk::VBox::new(FALSE, 10)
box2.border_width(10)
box1.pack_start(box2, TRUE, TRUE, 0)
box2.show
button = Gtk::ToggleButton::new("button1")
box2.pack_start(button, TRUE, TRUE, 0)
button.show
button = Gtk::ToggleButton::new("button2")
box2.pack_start(button, TRUE, TRUE, 0)
button.show
button = Gtk::ToggleButton::new("button3")
box2.pack_start(button, TRUE, TRUE, 0)
button.show
separator = Gtk::HSeparator::new()
box1.pack_start(separator, FALSE, TRUE, 0)
separator.show
box2 = Gtk::VBox::new(FALSE, 10)
box2.border_width(10)
box1.pack_start(box2, FALSE, TRUE, 0)
box2.show
close = Gtk::Button::new("close")
close.signal_connect("clicked") do
window.destroy
exit
end
box2.pack_start(close, TRUE, TRUE, 0)
close.set_flags(Gtk::CAN_DEFAULT);
close.grab_default
close.show
window.show
Gtk::main()

49
ext/gtk/test7.rb Normal file
View File

@ -0,0 +1,49 @@
require 'gtk'
window = Gtk::Window::new(Gtk::WINDOW_TOPLEVEL)
window.set_title("check buttons")
window.border_width(0)
box1 = Gtk::VBox::new(FALSE, 0)
window.add(box1)
box1.show
box2 = Gtk::VBox::new(FALSE, 10)
box2.border_width(10)
box1.pack_start(box2, TRUE, TRUE, 0)
box2.show
button = Gtk::CheckButton::new("button1")
box2.pack_start(button, TRUE, TRUE, 0)
button.show
button = Gtk::CheckButton::new("button2")
box2.pack_start(button, TRUE, TRUE, 0)
button.show
button = Gtk::CheckButton::new("button3")
box2.pack_start(button, TRUE, TRUE, 0)
button.show
separator = Gtk::HSeparator::new()
box1.pack_start(separator, FALSE, TRUE, 0)
separator.show
box2 = Gtk::VBox::new(FALSE, 10)
box2.border_width(10)
box1.pack_start(box2, FALSE, TRUE, 0)
box2.show
close = Gtk::Button::new("close")
close.signal_connect("clicked") do
window.destroy
exit
end
box2.pack_start(close, TRUE, TRUE, 0)
close.set_flags(Gtk::CAN_DEFAULT);
close.grab_default
close.show
window.show
Gtk::main()

49
ext/gtk/test8.rb Normal file
View File

@ -0,0 +1,49 @@
require 'gtk'
window = Gtk::Window::new(Gtk::WINDOW_TOPLEVEL)
window.set_title("radio buttons")
window.border_width(0)
box1 = Gtk::VBox::new(FALSE, 0)
window.add(box1)
box1.show
box2 = Gtk::VBox::new(FALSE, 10)
box2.border_width 10
box1.pack_start(box2, TRUE, TRUE, 0)
box2.show
button = Gtk::RadioButton::new("button1")
box2.pack_start(button, TRUE, TRUE, 0)
button.show
button = Gtk::RadioButton::new(button, "button2")
box2.pack_start(button, TRUE, TRUE, 0)
button.show
button = Gtk::RadioButton::new(button, "button3")
box2.pack_start(button, TRUE, TRUE, 0)
button.show
separator = Gtk::HSeparator::new()
box1.pack_start(separator, FALSE, TRUE, 0)
separator.show
box2 = Gtk::VBox::new(FALSE, 10)
box2.border_width(10)
box1.pack_start(box2, FALSE, TRUE, 0)
box2.show
close = Gtk::Button::new("close")
close.signal_connect("clicked") do
window.destroy
exit
end
box2.pack_start(close, TRUE, TRUE, 0)
close.set_flags(Gtk::CAN_DEFAULT);
close.grab_default
close.show
window.show
Gtk::main()

98
ext/gtk/test9.rb Normal file
View File

@ -0,0 +1,98 @@
require 'gtk'
def create_bbox_window(horizontal, title, pos, spacing, cw, ch, layout)
window = Gtk::Window::new(Gtk::WINDOW_TOPLEVEL)
window.set_title(title)
window.signal_connect("destroy") do
window.destroy
end
window.signal_connect("delete_event") do
window.hide
window.destroy
end
if horizontal
window.set_usize(550, 60)
window.set_uposition(150, pos)
else
window.set_usize(150, 400)
window.set_uposition(pos, 200)
end
box1 = Gtk::VBox::new(FALSE, 0)
window.add box1
box1.show
if horizontal
bbox = Gtk::HButtonBox::new()
else
bbox = Gtk::VButtonBox::new()
end
bbox.set_layout layout
bbox.set_spacing spacing
bbox.set_child_size cw, ch
bbox.show
box1.border_width 25
box1.pack_start(bbox, TRUE, TRUE, 0)
button = Gtk::Button::new("OK")
bbox.add button
button.signal_connect("clicked") do
window.hide
window.destroy
end
button.show
button = Gtk::Button::new("Cancel")
bbox.add button
button.signal_connect("clicked") do
window.hide
window.destroy
end
button.show
button = Gtk::Button::new("Help")
bbox.add button
button.show
window.show
end
def test_hbbox
create_bbox_window(TRUE, "Spread", 50, 40, 85, 25, Gtk::BUTTONBOX_SPREAD);
create_bbox_window(TRUE, "Edge", 250, 40, 85, 28, Gtk::BUTTONBOX_EDGE);
create_bbox_window(TRUE, "Start", 450, 40, 85, 25, Gtk::BUTTONBOX_START);
create_bbox_window(TRUE, "End", 650, 15, 30, 25, Gtk::BUTTONBOX_END);
end
def test_vbbox
create_bbox_window(FALSE, "Spread", 50, 40, 85, 25, Gtk::BUTTONBOX_SPREAD);
create_bbox_window(FALSE, "Edge", 250, 40, 85, 28, Gtk::BUTTONBOX_EDGE);
create_bbox_window(FALSE, "Start", 450, 40, 85, 25, Gtk::BUTTONBOX_START);
create_bbox_window(FALSE, "End", 650, 15, 30, 25, Gtk::BUTTONBOX_END);
end
window = Gtk::Window::new(Gtk::WINDOW_TOPLEVEL)
window.signal_connect("delete_event") do
window.destroy
exit
end
window.set_title("button box")
window.border_width(20)
bbox = Gtk::HButtonBox::new()
window.add(bbox)
bbox.show
button = Gtk::Button::new("Horizontal")
def button.clicked(*args)
test_hbbox
end
bbox.add button
button.show
button = Gtk::Button::new("Vertical")
def button.clicked(*args)
test_vbbox
end
bbox.add button
button.show
window.show
Gtk::main()

78
ext/gtk/testa.rb Normal file
View File

@ -0,0 +1,78 @@
require 'gtk'
window = Gtk::Window::new(Gtk::WINDOW_TOPLEVEL)
window.set_title("toolbar test")
window.set_policy(TRUE, TRUE, TRUE)
window.signal_connect("destroy") do
exit
end
window.signal_connect("delete_event") do
exit
end
window.border_width(0)
window.realize
toolbar = Gtk::Toolbar::new(Gtk::ORIENTATION_HORIZONTAL, Gtk::TOOLBAR_BOTH)
toolbar.append_item "Horizontal", "Horizontal toolbar layout",
Gtk::Pixmap::new(*Gdk::Pixmap::create_from_xpm(window.window,
nil,
#window.style.bg[Gtk::STATE_NORMAL],
"test.xpm")), nil do
toolbar.set_orientation Gtk::ORIENTATION_HORIZONTAL
end
toolbar.append_item "Vertival", "Vertical toolbar layout",
Gtk::Pixmap::new(*Gdk::Pixmap::create_from_xpm(window.window,
nil, #window.style.bg[Gtk::STATE_NORMAL],
"test.xpm")), nil do
toolbar.set_orientation Gtk::ORIENTATION_VERTICAL
end
toolbar.append_space
toolbar.append_item "Icons", "Only show toolbar icons",
Gtk::Pixmap::new(*Gdk::Pixmap::create_from_xpm(window.window,
nil, #window.style.bg[Gtk::STATE_NORMAL],
"test.xpm")), nil do
toolbar.set_style Gtk::TOOLBAR_ICONS
end
toolbar.append_item "Text", "Only show toolbar text",
Gtk::Pixmap::new(*Gdk::Pixmap::create_from_xpm(window.window,
nil,#window.style.bg[Gtk::STATE_NORMAL],
"test.xpm")), nil do
toolbar.set_style Gtk::TOOLBAR_TEXT
end
toolbar.append_item "Both", "Show toolbar icons and text",
Gtk::Pixmap::new(*Gdk::Pixmap::create_from_xpm(window.window,
nil, #window.style.bg[Gtk::STATE_NORMAL],
"test.xpm")), nil do
toolbar.set_style Gtk::TOOLBAR_BOTH
end
toolbar.append_space
toolbar.append_item "Small", "User small spaces",
Gtk::Pixmap::new(*Gdk::Pixmap::create_from_xpm(window.window,
nil,#window.style.bg[Gtk::STATE_NORMAL],
"test.xpm")), nil do
toolbar.set_space_size 5
end
toolbar.append_item "Big", "User big spaces",
Gtk::Pixmap::new(*Gdk::Pixmap::create_from_xpm(window.window,
nil,#window.style.bg[Gtk::STATE_NORMAL],
"test.xpm")), nil do
toolbar.set_space_size 10
end
toolbar.append_space
toolbar.append_item "Enable", "Enable tooltips",
Gtk::Pixmap::new(*Gdk::Pixmap::create_from_xpm(window.window,
nil,#window.style.bg[Gtk::STATE_NORMAL],
"test.xpm")), nil do
toolbar.set_tooltips TRUE
end
toolbar.append_item "Disable", "Disable tooltips",
Gtk::Pixmap::new(*Gdk::Pixmap::create_from_xpm(window.window,
nil,#window.style.bg[Gtk::STATE_NORMAL],
"test.xpm")), nil do
toolbar.set_tooltips FALSE
end
window.add toolbar
toolbar.show
window.show
Gtk::main()

78
ext/gtk/testb.rb Normal file
View File

@ -0,0 +1,78 @@
require 'gtk'
window = Gtk::Window::new(Gtk::WINDOW_TOPLEVEL)
window.signal_connect("destroy") do
exit
end
window.signal_connect("delete_event") do
exit
end
window.set_title("buttons")
window.border_width(0)
box1 = Gtk::VBox::new(FALSE, 0)
window.add box1
box1.show
box2 = Gtk::HBox::new(FALSE, 5)
box2.border_width 10
box1.pack_start box2, TRUE, TRUE, 0
box2.show
label = Gtk::Label::new("Hello World")
frame = Gtk::Frame::new("Frame 1")
box2.pack_start frame, TRUE, TRUE, 0
frame.show
box3 = Gtk::VBox::new(FALSE, 5)
box3.border_width 5
frame.add box3
box3.show
button = Gtk::Button::new("switch")
button.signal_connect("clicked") do
label.reparent box3
end
box3.pack_start button, FALSE, TRUE, 0
button.show
box3.pack_start label, FALSE, TRUE, 0
label.show
frame = Gtk::Frame::new("Frame 2")
box2.pack_start frame, TRUE, TRUE, 0
frame.show
box4 = Gtk::VBox::new(FALSE, 5)
box4.border_width 5
frame.add box4
box4.show
button = Gtk::Button::new("switch")
button.signal_connect("clicked") do
label.reparent box4
end
box4.pack_start button, FALSE, TRUE, 0
button.show
separator = Gtk::HSeparator::new()
box1.pack_start(separator, FALSE, TRUE, 0)
separator.show
box2 = Gtk::HBox::new(FALSE, 10)
box2.border_width(10)
box1.pack_start(box2, FALSE, TRUE, 0)
box2.show
button = Gtk::Button::new("close")
button.signal_connect("clicked") do
window.destroy
exit
end
box2.pack_start(button, TRUE, TRUE, 0)
button.set_flags(Gtk::CAN_DEFAULT);
button.grab_default
button.show
window.show
Gtk::main()

64
ext/gtk/testc.rb Normal file
View File

@ -0,0 +1,64 @@
require 'gtk'
window = Gtk::Window::new(Gtk::WINDOW_TOPLEVEL)
window.signal_connect("destroy") do
exit
end
window.signal_connect("delete_event") do
exit
end
window.set_title("pixmap")
window.border_width(0)
window.realize
box1 = Gtk::VBox::new(FALSE, 0)
window.add box1
box1.show
box2 = Gtk::HBox::new(FALSE, 10)
box2.border_width 10
box1.pack_start box2, TRUE, TRUE, 0
box2.show
button = Gtk::Button::new()
box2.pack_start button, FALSE, FALSE, 0
button.show
style = button.style
pixmap, mask = Gdk::Pixmap::create_from_xpm(window.window,
nil,
#style.bg[Gtk::STATE_NORMAL],
"test.xpm")
pixmapwid = Gtk::Pixmap::new(pixmap, mask)
label = Gtk::Label::new("Pixmap\ntest")
box3 = Gtk::HBox::new(FALSE, 0)
box3.border_width 2
box3.add pixmapwid
box3.add label
button.add box3
pixmapwid.show
label.show
box3.show
separator = Gtk::HSeparator::new()
box1.pack_start(separator, FALSE, TRUE, 0)
separator.show
box2 = Gtk::HBox::new(FALSE, 10)
box2.border_width(10)
box1.pack_start(box2, FALSE, TRUE, 0)
box2.show
button = Gtk::Button::new("close")
button.signal_connect("clicked") do
window.destroy
exit
end
box2.pack_start(button, TRUE, TRUE, 0)
button.set_flags(Gtk::CAN_DEFAULT);
button.grab_default
button.show
window.show
Gtk::main()

15
ext/tcltklib/MANIFEST Normal file
View File

@ -0,0 +1,15 @@
MANIFEST
README.euc
MANUAL.euc
tcltklib.c
depend
extconf.rb
lib/tcltk.rb
demo/lines1.rb
demo/lines0.tcl
demo/lines2.rb
sample/sample1.rb
sample/sample2.rb
sample/maru.gif
sample/batsu.gif
sample/sample0.rb

124
ext/tcltklib/MANUAL.euc Normal file
View File

@ -0,0 +1,124 @@
(tof)
MANUAL.euc
Sep. 19, 1997 Y. Shigehiro
以下, 「tcl/tk」という表記は, tclsh や wish を実現している, 一般でいう
ところの tcl/tk を指します. 「tcltk ライブラリ」, 「tcltklib ライブラ
リ」という表記は, 本パッケージに含まれる ruby 用のライブラリを指します.
<< tcltk ライブラリ >>
tcl/tk の C ライブラリを利用するための高(中?)水準インターフェースを提
供します.
このライブラリは ruby から tcl/tk ライブラリを利用するためのもので, 内
部で tcltklib ライブラリを利用しています.
[説明]
tcl/tk インタプリタでは, ウィジェットに何か指示を送るには, ウィジェッ
ト名に続いてパラメータを書きます. したがって, ウィジェットがオブジェク
トであり, それに対してメソッドを送っている, とみなすことができます. さ
て, tcl/tk インタプリタでは, 組み込みコマンドも, 前述のウィジェットと
同じような書式の命令で実行されます. すなわち, コマンドもオブジェクトで
あると考えることができます.
このような考えに基づき, tcltk ライブラリでは, tcl/tk のコマンドやウィ
ジェットに対応するオブジェクトを生成します. オブジェクトに対するメソッ
ド呼び出しは, e() メソッドにより実行されます. 例えば, tcl/tk の info
コマンドに対応する ruby のオブジェクトが info という名前であるとすると,
tcl/tk の
info commands
という命令は tcltk ライブラリでは
info.e("commands")
と記述されます. また, 「.」というウィジェット (wish 実行時に自動的に生
成されるルートウィジェット) に対応する ruby のオブジェクトが root とい
う名前であるとすると,
. configure -height 300 -width 300
という tcl/tk の命令は
root.e("configure -height 300 -width 300")
と記述されます. このような記述は, 見ためには美しくありませんが, そして,
スクリプトを読む人には見づらいかも知れませんが, 実際にスクリプトを書い
てみると予想外に手軽です.
[使用法]
1. ライブラリを読み込む.
require "tcltk"
2. tcl/tk インタプリタを生成する.
ip = TclTkInterpreter.new()
3. tcl/tk のコマンドに対応するオブジェクトを変数に代入しておく.
# コマンドに対応するオブジェクトが入った Hash を取り出す.
c = ip.commands()
# 使いたいコマンドに対応するオブジェクトを個別の変数に代入する.
bind, button, info, wm = c.indexes("bind", "button", "info", "wm")
4. 必要な処理を行う.
詳しくは, サンプルを参照のこと.
5. 準備ができたら, イベントループに入る.
TclTk.mainloop()
(( 以下, モジュール, クラス等の説明を書く予定.))
<< tcltklib ライブラリ >>
tcl/tk の C ライブラリを利用するための低水準インターフェースを提供しま
す.
コンパイル/実行には, tcl/tk の C ライブラリが必要です.
[説明]
このライブラリを用いると, ruby から tcl/tk の C ライブラリを利用できま
す. 具体的には, ruby インタプリタから tcl/tk インタプリタを呼び出すこ
とができます. さらに, その(ruby インタプリタから呼び出した) tcl/tk イ
ンタプリタから, 逆に ruby インタプリタを呼び出すこともできます.
[使用法]
require "tcltklib" すると, 以下のモジュール, クラスが利用可能です.
モジュール TclTkLib
tcl/tk ライブラリを呼び出すメソッドを集めたモジュールです. ただし,
tcl/tk インタプリタ関係のメソッドはクラス TclTkIp にあります.
モジュールメソッド mainloop()
Tk_MainLoop を実行します. 全ての tk のウインドウが無くなると終了
します(例えば, tcl/tk で書くところの "destroy ." をした場合等).
引数: 無し
戻り値: nil
クラス TclTkIp
インスタンスが tcl/tk のインタプリタに対応します. tcl/tk のライブ
ラリの仕様通り, インスタンスを複数個生成しても正しく動作します(そ
んなことをする必要はあまり無いはずですが). インタプリタは wish の
tcl/tk コマンドを実行できます. さらに, 以下のコマンドを実行できま
す.
コマンド ruby
引数を ruby で実行します(ruby_eval_string を実行します). 引数
は 1 つでなければなりません. 戻り値は ruby の実行結果です.
ruby の実行結果は nil か String でなければなりません.
クラスメソッド new()
TclTkIp クラスのインスタンスを生成します
引数: 無し
戻り値 (TclTkIp): 生成されたインスタンス
メソッド _eval(script)
インタプリタで script を評価します(Tcl_Eval を実行します). 前述
のように, ruby コマンドにより script 内から ruby スクリプトを実
行できます.
引数: script (String) - インタプリタで評価するスクリプト文字列
戻り値 (String): 評価結果 ((Tcl_Interp *)->result)
メソッド _return_value()
直前の Tcl_Eval の戻り値を返します. 0(TCL_OK) で正常終了です.
引数: 無し
戻り値 (Fixnum): 直前の Tcl_Eval() が返した値.
(eof)

133
ext/tcltklib/README.euc Normal file
View File

@ -0,0 +1,133 @@
(tof)
tcltk ライブラリ
tcltklib ライブラリ
Sep. 19, 1997 Y. Shigehiro
以下, 「tcl/tk」という表記は, tclsh や wish を実現している, 一般でいう
ところの tcl/tk を指します. 「tcltk ライブラリ」, 「tcltklib ライブラ
リ」という表記は, 本パッケージに含まれる ruby 用のライブラリを指します.
[ファイルについて]
README.euc : このファイル(注意, 特徴, インストールの方法).
MANUAL.euc : マニュアル.
lib/, ext/ : ライブラリの実体.
sample/ : マニュアル代わりのサンプルプログラム.
sample/sample0.rb : tcltklib ライブラリのテスト.
sample/sample1.rb : tcltk ライブラリのテスト.
tcl/tk (wish) でできそうなことを一通り書いてみました.
sample/sample2.rb : tcltk ライブラリのサンプル.
maeda shugo (shugo@po.aianet.ne.jp) 氏による
(`rb.tk' で書かれていた) ruby のサンプルプログラム
http://www.aianet.or.jp/~shugo/ruby/othello.rb.gz
を tcltk ライブラリを使うように, 機械的に変更してみました.
demo/ : 100 本の線を 100 回描くデモプログラム.
最初に空ループの時間を測定し, 続いて実際に線を引く時間を測定します.
tcl/tk は(再)描画のときに backing store を使わずに律義に 10000 本(?)
線を引くので, (再)描画を始めると, マシンがかなり重くなります.
demo/lines0.tcl : wish 用のスクリプト.
demo/lines1.rb : `tk.rb' 用のスクリプト.
demo/lines2.rb : tcltk ライブラリ用のスクリプト.
[注意]
コンパイル/実行には, tcl/tk の C ライブラリが必要です.
このライブラリは,
ruby-1.0-970701, ruby-1.0-970911, ruby-1.0-970919
FreeBSD 2.2.2-RELEASE
およびそのパッケージ jp-tcl-7.6.tgz, jp-tk-4.2.tgz
で作成/動作確認しました. 他の環境では動作するかどうかわかりません.
TclTkLib.mainloop を実行中に Control-C が効かないのは不便なので, ruby
のソースを参考に, #include "sig.h" して trap_immediate を操作していま
すが, ruby の README.EXT にも書いてないのに, こんなことをして良いのか
どうかわかりません.
-d オプションでデバッグ情報を表示させるために, ruby のソースを参考に,
debug という大域変数を参照していますが, ruby の README.EXT にも書いて
ないのに, こんなことをして良いのかどうかわかりません.
extconf.rb は書きましたが, (いろいろな意味で)これで良いのか良く分かり
ません.
[特徴]
ruby から tcl/tk ライブラリを利用できます.
tcl/tk インタプリタのスクリプトは, 機械的に tcltk ライブラリ用の ruby
スクリプトに変換できます.
(`tk.rb' との違い)
1. tcl/tk インタプリタのスクリプトが, どのように, tcltk ライブラリ用の
ruby スクリプトに変換されるかが理解できれば, マニュアル類が無いに等
しい `tk.rb' とは異なり
tcl/tk のマニュアルやオンラインドキュメントを用いて
効率良くプログラミングを行うことができます.
記述方法がわからない, コマンドに与えるパラメータがわからない...
- Canvas.new { ... } と, なぜイテレータブロックを書けるの??
- Canvas の bbox は数値のリストを返すのに, xview は文字列を返すの??
と, いちいち, ライブラリのソースを追いかける必要はありません.
2. 個々の機能(オプション)を個別処理によりサポートしており, そのためサ
ポートしていない機能は使うことができない(本当は使えないこともないの
ですが) `tk.rb' とは異なり, tcl/tk インタプリタで可能なことは
ほとんど
ruby からも実行できます. 現在, ruby から実行できないことが確認され
ているのは,
bind コマンドでスクリプトを追加する構文
「bind tag sequence +script」
^
のみです.
- `. configure -width' をしようとして, `Tk.root.height()' と書い
たのに, `undefined method `height'' と怒られてしまった. tk.rb を
読んでみて, ガーン. できないのか...
ということはありません.
3. wish プロセスを起動しプロセス間通信で wish を利用する `tk.rb' とは
異なり, tcl/tk の C ライブラリをリンクし
より高速に (といっても, 思った程は速くないですが)
処理を行います.
4. `tk.rb' ほど, 高水準なインターフェースを備えていないため, tcl/tk イ
ンタプリタの生成等
何から何まで自分で記述
しなければなりません(その代わり, tcl/tk ライブラリの仕様通り,
tcl/tk インタプリタを複数生成することもできますが).
インターフェースは(おそらく) ruby の思想に沿ったものではありません.
また, スクリプトの記述は
ダサダサ
です. スクリプトは, 一見, 読みづらいものとなります. が, 書く人にとっ
ては, それほど煩わしいものではないと思います.
[インストールの方法]
0. ruby のソースファイル(ruby-1.0-なんたら.tgz)を展開しておきます.
1. ruby-1.0-なんたら/ext に ext/tcltklib をコピーします.
cp -r ext/tcltklib ???/ruby-1.0-なんたら/ext/
2. ruby のインストール法に従い make 等をします.
3. ruby のライブラリ置場に lib/* をコピーします.
cp lib/* /usr/local/lib/ruby/
(eof)

View File

@ -0,0 +1,42 @@
#! /usr/local/bin/wish
proc drawlines {} {
puts [clock format [clock seconds]]
for {set j 0} {$j < 100} {incr j} {
puts -nonewline "*"
flush stdout
if {$j & 1} {
set c "blue"
} {
set c "red"
}
for {set i 0} {$i < 100} {incr i} {
# .a create line $i 0 0 [expr 500 - $i] -fill $c
}
}
puts [clock format [clock seconds]]
for {set j 0} {$j < 100} {incr j} {
puts -nonewline "*"
flush stdout
if {$j & 1} {
set c "blue"
} {
set c "red"
}
for {set i 0} {$i < 100} {incr i} {
.a create line $i 0 0 [expr 500 - $i] -fill $c
}
}
puts [clock format [clock seconds]]
# destroy .
}
canvas .a -height 500 -width 500
button .b -text draw -command drawlines
pack .a .b -side left
# eof

View File

@ -0,0 +1,54 @@
#! /usr/local/bin/ruby
require "tk"
def drawlines()
print Time.now, "\n"
for j in 0 .. 99
print "*"
$stdout.flush
if (j & 1) != 0
col = "blue"
else
col = "red"
end
for i in 0 .. 99
# TkcLine.new($a, i, 0, 0, 500 - i, "-fill", col)
end
end
print Time.now, "\n"
for j in 0 .. 99
print "*"
$stdout.flush
if (j & 1) != 0
col = "blue"
else
col = "red"
end
for i in 0 .. 99
TkcLine.new($a, i, 0, 0, 500 - i, "-fill", col)
end
end
print Time.now, "\n"
# Tk.root.destroy
end
$a = TkCanvas.new{
height(500)
width(500)
}
$b = TkButton.new{
text("draw")
command(proc{drawlines()})
}
TkPack.configure($a, $b, {"side"=>"left"})
Tk.mainloop
# eof

View File

@ -0,0 +1,50 @@
#! /usr/local/bin/ruby
require "tcltk"
def drawlines()
print Time.now, "\n"
for j in 0 .. 99
print "*"
$stdout.flush
if (j & 1) != 0
col = "blue"
else
col = "red"
end
for i in 0 .. 99
# $a.e("create line", i, 0, 0, 500 - i, "-fill", col)
end
end
print Time.now, "\n"
for j in 0 .. 99
print "*"
$stdout.flush
if (j & 1) != 0
col = "blue"
else
col = "red"
end
for i in 0 .. 99
$a.e("create line", i, 0, 0, 500 - i, "-fill", col)
end
end
print Time.now, "\n"
# $ip.commands()["destroy"].e($root)
end
$ip = TclTkInterpreter.new()
$root = $ip.rootwidget()
$a = TclTkWidget.new($ip, $root, "canvas", "-height 500 -width 500")
$c = TclTkCallback.new($ip, proc{drawlines()})
$b = TclTkWidget.new($ip, $root, "button", "-text draw -command", $c)
$ip.commands()["pack"].e($a, $b, "-side left")
TclTk.mainloop
# eof

1
ext/tcltklib/depend Normal file
View File

@ -0,0 +1 @@
tcltklib.o: tcltklib.c $(hdrdir)/ruby.h $(hdrdir)/config.h $(hdrdir)/defines.h

79
ext/tcltklib/extconf.rb Normal file
View File

@ -0,0 +1,79 @@
# extconf.rb for tcltklib
have_library("socket", "socket")
have_library("nsl", "gethostbyname")
def search_file(var, include, *path)
pwd = Dir.getwd
begin
for i in path.reverse!
dir = Dir[i]
for path in dir
Dir.chdir path
files = Dir[include]
if files.size > 0
var << path
return files.pop
end
end
end
ensure
Dir.chdir pwd
end
end
$includes = []
search_file($includes,
"tcl.h",
"/usr/include/tcl*",
"/usr/include",
"/usr/local/include/tcl*",
"/usr/local/include")
search_file($includes,
"tk.h",
"/usr/include/tk*",
"/usr/include",
"/usr/local/include/tk*",
"/usr/local/include")
search_file($includes,
"X11/Xlib.h",
"/usr/include",
"/usr/X11*/include",
"/usr/include",
"/usr/X11*/include")
$CFLAGS = "-Wall " + $includes.collect{|path| "-I" + path}.join(" ")
$libraries = []
tcllibfile = search_file($libraries,
"libtcl{,7*,8*}.{a,so}",
"/usr/lib",
"/usr/local/lib")
if tcllibfile
tcllibfile.sub!(/^lib/, '')
tcllibfile.sub!(/\.(a|so)$/, '')
end
tklibfile = search_file($libraries,
"libtk{,4*,8*}.{a,so}",
"/usr/lib",
"/usr/local/lib")
if tklibfile
tklibfile.sub!(/^lib/, '')
tklibfile.sub!(/\.(a|so)$/, '')
end
search_file($libraries,
"libX11.{a,so}",
"/usr/lib",
"/usr/X11*/lib")
$LDFLAGS = $libraries.collect{|path| "-L" + path}.join(" ")
have_library("dl", "dlopen")
if have_header("tcl.h") &&
have_header("tk.h") &&
have_library("X11", "XOpenDisplay") &&
have_library("m", "log") &&
have_library(tcllibfile, "Tcl_FindExecutable") &&
have_library(tklibfile, "Tk_Init")
create_makefile("tcltklib")
end

388
ext/tcltklib/lib/tcltk.rb Normal file
View File

@ -0,0 +1,388 @@
# tof
#### tcltk ライブラリ
#### Sep. 5, 1997 Y. Shigehiro
require "tcltklib"
################
# module TclTk: tcl/tk のライブラリ全体で必要になるものを集めたもの
# (主に, 名前空間の点から module にする使う.)
module TclTk
# 単にここに書けば最初に 1 度実行されるのか??
# 生成した一意な名前を保持しておく連想配列を初期化する.
@namecnt = {}
# コールバックを保持しておく連想配列を初期化する.
@callback = {}
end
# TclTk.mainloop(): TclTkLib.mainloop() を呼ぶ.
def TclTk.mainloop()
print("mainloop: start\n") if $DEBUG
TclTkLib.mainloop()
print("mainloop: end\n") if $DEBUG
end
# TclTk.deletecallbackkey(ca): コールバックを TclTk module から取り除く.
# tcl/tk インタプリタにおいてコールバックが取り消されるわけではない.
# これをしないと, 最後に TclTkInterpreter が GC できない.
# (GC したくなければ, 別に, これをしなくても良い.)
# ca: コールバック(TclTkCallback)
def TclTk.deletecallbackkey(ca)
print("deletecallbackkey: ", ca.to_s(), "\n") if $DEBUG
@callback.delete(ca.to_s)
end
# TclTk.dcb(ca, wid, W): 配列に入っている複数のコールバックに対して
# TclTk.deletecallbackkey() を呼ぶ.
# トップレベルの <Destroy> イベントのコールバックとして呼ぶためのもの.
# ca: コールバック(TclTkCallback) の Array
# wid: トップレベルのウィジェット(TclTkWidget)
# w: コールバックに %W で与えられる, ウインドウに関するパラメータ(String)
def TclTk.dcb(ca, wid, w)
if wid.to_s() == w
ca.each{|i|
TclTk.deletecallbackkey(i)
}
end
end
# TclTk._addcallback(ca): コールバックを登録する.
# ca: コールバック(TclTkCallback)
def TclTk._addcallback(ca)
print("_addcallback: ", ca.to_s(), "\n") if $DEBUG
@callback[ca.to_s()] = ca
end
# TclTk._callcallback(key, arg): 登録したコールバックを呼び出す.
# key: コールバックを選択するキー (TclTkCallback が to_s() で返す値)
# arg: tcl/tk インタプリタからのパラメータ
def TclTk._callcallback(key, arg)
print("_callcallback: ", @callback[key].inspect, "\n") if $DEBUG
@callback[key]._call(arg)
# コールバックからの返り値はどうせ捨てられる.
# String を返さないと, rb_eval_string() がエラーになる.
return ""
end
# TclTk._newname(prefix): 一意な名前(String)を生成して返す.
# prefix: 名前の接頭語
def TclTk._newname(prefix)
# 生成した名前のカウンタは @namecnt に入っているので, 調べる.
if !@namecnt.key?(prefix)
# 初めて使う接頭語なので初期化する.
@namecnt[prefix] = 1
else
# 使ったことのある接頭語なので, 次の名前にする.
@namecnt[prefix] += 1
end
return "#{prefix}#{@namecnt[prefix]}"
end
################
# class TclTkInterpreter: tcl/tk のインタプリタ
class TclTkInterpreter
# initialize(): 初期化.
def initialize()
# インタプリタを生成する.
@ip = TclTkIp.new()
# インタプリタに ruby_fmt コマンドを追加する.
# ruby_fmt コマンドとは, 後ろの引数を format コマンドで処理して
# ruby コマンドに渡すものである.
# (なお, ruby コマンドは, 引数を 1 つしかとれない.)
if $DEBUG
@ip._eval("proc ruby_fmt {fmt args} { puts \"ruby_fmt: $fmt $args\" ; ruby [format $fmt $args] }")
else
@ip._eval("proc ruby_fmt {fmt args} { ruby [format $fmt $args] }")
end
# @ip._get_eval_string(*args): tcl/tk インタプリタで評価する
# 文字列(String)を生成して返す.
# *args: tcl/tk で評価するスクリプト(に対応するオブジェクト列)
def @ip._get_eval_string(*args)
argstr = ""
args.each{|arg|
argstr += " " if argstr != ""
# もし to_eval() メソッドが
if (arg.respond_to?(:to_eval))
# 定義されていればそれを呼ぶ.
argstr += arg.to_eval()
else
# 定義されていなければ to_s() を呼ぶ.
argstr += arg.to_s()
end
}
return argstr
end
# @ip._eval_args(*args): tcl/tk インタプリタで評価し,
# その結果(String)を返す.
# *args: tcl/tk で評価するスクリプト(に対応するオブジェクト列)
def @ip._eval_args(*args)
# インタプリタで評価する文字列を求める.
argstr = _get_eval_string(*args)
# インタプリタで評価する.
print("_eval: \"", argstr, "\"") if $DEBUG
res = _eval(argstr)
if $DEBUG
print(" -> \"", res, "\"\n")
elsif _return_value() != 0
print(res, "\n")
end
fail(%Q/can't eval "#{argstr}"/) if _return_value() != 0
return res
end
# tcl/tk のコマンドに対応するオブジェクトを生成し, 連想配列に入れておく.
@commands = {}
# tcl/tk インタプリタに登録されているすべてのコマンドに対して,
@ip._eval("info command").split(/ /).each{|comname|
if comname =~ /^[.]/
# コマンドがウィジェット(のパス名)の場合は
# TclTkWidget のインスタンスを作って連想配列に入れる.
@commands[comname] = TclTkWidget.new(@ip, comname)
else
# そうでない場合は
# TclTkCommand のインスタンスを作って連想配列に入れる.
@commands[comname] = TclTkCommand.new(@ip, comname)
end
}
end
# commands(): tcl/tk のコマンドに対応するオブジェクトを Hash に
# 入れたものを返す.
def commands()
return @commands
end
# rootwidget(): ルートウィジェット(TclTkWidget)を返す.
def rootwidget()
return @commands["."]
end
# _tcltkip(): @ip(TclTkIp) を返す.
def _tcltkip()
return @ip
end
# method_missing(id, *args): 未定義のメソッドは tcl/tk のコマンドとみなして
# 実行し, その結果(String)を返す.
# id: メソッドのシンボル
# *args: コマンドの引数
def method_missing(id, *args)
# もし, メソッドの tcl/tk コマンドが
if @commands.key?(id.id2name)
# あれば, 実行して結果を返す.
return @commands[id.id2name].e(*args)
else
# 無ければもともとの処理.
super
end
end
end
# class TclTkObject: tcl/tk のオブジェクト
# (基底クラスとして使う.
# tcltk ライブラリを使う人が TclTkObject.new() することはないはず.)
class TclTkObject
# initialize(ip, exp): 初期化.
# ip: インタプリタ(TclTkIp)
# exp: tcl/tk での表現形
def initialize(ip, exp)
fail("type is not TclTkIp") if !ip.kind_of?(TclTkIp)
@ip = ip
@exp = exp
end
# to_s(): tcl/tk での表現形(String)を返す.
def to_s()
return @exp
end
end
# class TclTkCommand: tcl/tk のコマンド
# (tcltk ライブラリを使う人が TclTkCommand.new() することはないはず.
# TclTkInterpreter:initialize() から new() される.)
class TclTkCommand < TclTkObject
# e(*args): コマンドを実行し, その結果(String)を返す.
# (e は exec または eval の e.)
# *args: コマンドの引数
def e(*args)
return @ip._eval_args(to_s(), *args)
end
end
# class TclTkLibCommand: tcl/tk のコマンド
# (ライブラリにより実現されるコマンドで, tcl/tk インタプリタに最初から
# 存在しないものは, インタプリタの commands() では生成できない.
# そのようなものに対し, コマンドの名前から TclTkCommand オブジェクトを
# 生成する.
class TclTkLibCommand < TclTkCommand
# initialize(ip, name): 初期化
# ip: インタプリタ(TclTkInterpreter)
# name: コマンド名 (String)
def initialize(ip, name)
super(ip._tcltkip, name)
end
end
# class TclTkVariable: tcl/tk の変数
class TclTkVariable < TclTkObject
# initialize(interp, dat): 初期化.
# interp: インタプリタ(TclTkInterpreter)
# dat: 設定する値(String)
# nil なら, 設定しない.
def initialize(interp, dat)
# tcl/tk での表現形(変数名)を自動生成する.
exp = TclTk._newname("v_")
# TclTkObject を初期化する.
super(interp._tcltkip(), exp)
# set コマンドを使うのでとっておく.
@set = interp.commands()["set"]
# 値を設定する.
set(dat) if dat
end
# tcl/tk の set を使えば, 値の設定/参照はできるが,
# それだけではなんなので, 一応, メソッドをかぶせたものも用意しておく.
# set(data): tcl/tk の変数に set を用いて値を設定する.
# data: 設定する値
def set(data)
@set.e(to_s(), data.to_s())
end
# get(): tcl/tk の変数の値(String)を set を用いて読みだし返す.
def get()
return @set.e(to_s())
end
end
# class TclTkWidget: tcl/tk のウィジェット
class TclTkWidget < TclTkCommand
# initialize(*args): 初期化.
# *args: パラメータ
def initialize(*args)
if args[0].kind_of?(TclTkIp)
# 最初の引数が TclTkIp の場合:
# 既に tcl/tk に定義されているウィジェットに TclTkWidget の構造を
# かぶせる. (TclTkInterpreter:initialize() から使われる.)
# パラメータ数が 2 でなければエラー.
fail("illegal # of parameter") if args.size != 2
# ip: インタプリタ(TclTkIp)
# exp: tcl/tk での表現形
ip, exp = args
# TclTkObject を初期化する.
super(ip, exp)
elsif args[0].kind_of?(TclTkInterpreter)
# 最初の引数が TclTkInterpreter の場合:
# 親ウィジェットから新たなウィジェトを生成する.
# interp: インタプリタ(TclTkInterpreter)
# parent: 親ウィジェット
# command: ウィジェットを生成するコマンド(label 等)
# *args: command に渡す引数
interp, parent, command, *args = args
# ウィジェットの名前を作る.
exp = parent.to_s()
exp += "." if exp !~ /[.]$/
exp += TclTk._newname("w_")
# TclTkObject を初期化する.
super(interp._tcltkip(), exp)
# ウィジェットを生成する.
res = @ip._eval_args(command, exp, *args)
# fail("can't create Widget") if res != exp
# tk_optionMenu では, ボタン名を exp で指定すると
# res にメニュー名を返すので res != exp となる.
else
fail("first parameter is not TclTkInterpreter")
end
end
end
# class TclTkCallback: tcl/tk のコールバック
class TclTkCallback < TclTkObject
# initialize(interp, pr, arg): 初期化.
# interp: インタプリタ(TclTkInterpreter)
# pr: コールバック手続き(Proc)
# arg: pr のイテレータ変数に渡す文字列
# tcl/tk の bind コマンドではパラメータを受け取るために % 置換を
# 用いるが, pr の内部で % を書いてもうまくいかない.
# arg に文字列を書いておくと, その置換結果を, pr で
# イテレータ変数を通して受け取ることができる.
# scrollbar コマンドの -command オプションのように
# 何も指定しなくてもパラメータが付くコマンドに対しては,
# arg を指定してはならない.
def initialize(interp, pr, arg = nil)
# tcl/tk での表現形(変数名)を自動生成する.
exp = TclTk._newname("c_")
# TclTkObject を初期化する.
super(interp._tcltkip(), exp)
# パラメータをとっておく.
@pr = pr
@arg = arg
# モジュールに登録しておく.
TclTk._addcallback(self)
end
# to_eval(): @ip._eval_args で評価するときの表現形(String)を返す.
def to_eval()
if @arg
# %s は ruby_fmt より前に bind により置換されてしまうので
# %%s としてある. したがって, これは bind 専用.
s = %Q/{ruby_fmt {TclTk._callcallback("#{to_s()}", "%%s")} #{@arg}}/
else
s = %Q/{ruby_fmt {TclTk._callcallback("#{to_s()}", "%s")}}/
end
return s
end
# _call(arg): コールバックを呼び出す.
# arg: コールバックに渡されるパラメータ
def _call(arg)
@pr.call(arg)
end
end
# class TclTkImage: tcl/tk のイメージ
class TclTkImage < TclTkCommand
# initialize(interp, t, *args): 初期化.
# イメージの生成は TclTkImage.new() で行うが,
# 破壊は image delete で行う. (いまいちだけど仕方が無い.)
# interp: インタプリタ(TclTkInterpreter)
# t: イメージのタイプ (photo, bitmap, etc.)
# *args: コマンドの引数
def initialize(interp, t, *args)
# tcl/tk での表現形(変数名)を自動生成する.
exp = TclTk._newname("i_")
# TclTkObject を初期化する.
super(interp._tcltkip(), exp)
# イメージを生成する.
res = @ip._eval_args("image create", t, exp, *args)
fail("can't create Image") if res != exp
end
end
# eof

Binary file not shown.

After

Width:  |  Height:  |  Size: 538 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 481 B

View File

@ -0,0 +1,39 @@
#! /usr/local/bin/ruby -vd
# tcltklib ライブラリのテスト
require "tcltklib"
def test
# インタプリタを生成する
ip1 = TclTkIp.new()
# 評価してみる
print ip1._return_value().inspect, "\n"
print ip1._eval("puts {abc}").inspect, "\n"
# ボタンを作ってみる
print ip1._return_value().inspect, "\n"
print ip1._eval("button .lab -text exit -command \"destroy .\"").inspect,
"\n"
print ip1._return_value().inspect, "\n"
print ip1._eval("pack .lab").inspect, "\n"
print ip1._return_value().inspect, "\n"
# インタプリタから ruby コマンドを評価してみる
# print ip1._eval(%q/ruby {print "print by ruby\n"}/).inspect, "\n"
print ip1._eval(%q+puts [ruby {print "print by ruby\n"; "puts by tcl/tk"}]+).inspect, "\n"
print ip1._return_value().inspect, "\n"
# もう一つインタプリタを生成してみる
ip2 = TclTkIp.new()
ip2._eval("button .lab -text test -command \"puts test ; destroy .\"")
ip2._eval("pack .lab")
TclTkLib.mainloop
end
test
GC.start
print "exit\n"

View File

@ -0,0 +1,634 @@
#! /usr/local/bin/ruby -d
#! /usr/local/bin/ruby
# -d オプションを付けると, デバッグ情報を表示する.
# tcltk ライブラリのサンプル
# まず, ライブラリを require する.
require "tcltk"
# 以下は, Test1 のインスタンスの initialize() で,
# tcl/tk に関する処理を行う例である.
# 必ずしもそのようにする必要は無く,
# (もし, そうしたければ) class の外で tcl/tk に関する処理を行っても良い.
class Test1
# 初期化(インタプリタを生成してウィジェットを生成する).
def initialize()
#### 使う前のおまじない
# インタプリタの生成.
ip = TclTkInterpreter.new()
# コマンドに対応するオブジェクトを c に設定しておく.
c = ip.commands()
# 使用するコマンドに対応するオブジェクトは変数に入れておく.
append, bind, button, destroy, incr, info, label, place, set, wm =
c.indexes(
"append", "bind", "button", "destroy", "incr", "info", "label", "place",
"set", "wm")
#### tcl/tk のコマンドに対応するオブジェクト(TclTkCommand)の操作
# 実行する時は, e() メソッドを使う.
# (以下は, tcl/tk における info command r* を実行.)
print info.e("command", "r*"), "\n"
# 引数は, まとめた文字列にしても同じ.
print info.e("command r*"), "\n"
# 変数を用いなくとも実行できるが, 見ためが悪い.
print c["info"].e("command", "r*"), "\n"
# インタプリタのメソッドとしても実行できるが, 効率が悪い.
print ip.info("command", "r*"), "\n"
####
# 以下, 生成したオブジェクトは変数に代入しておかないと
# GC の対象になってしまう.
#### tcl/tk の変数に対応するオブジェクト(TclTkVariable)の操作
# 生成と同時に値を設定する.
v1 = TclTkVariable.new(ip, "20")
# 読み出しは get メソッドを使う.
print v1.get(), "\n"
# 設定は set メソッドを使う.
v1.set(40)
print v1.get(), "\n"
# set コマンドを使って読み出し, 設定は可能だが見ためが悪い.
# e() メソッド等の引数に直接 TclTkObject や数値を書いても良い.
set.e(v1, 30)
print set.e(v1), "\n"
# tcl/tk のコマンドで変数を操作できる.
incr.e(v1)
print v1.get(), "\n"
append.e(v1, 10)
print v1.get(), "\n"
#### tcl/tk のウィジェットに対応するオブジェクト(TclTkWidget)の操作
# ルートウィジェットを取り出す.
root = ip.rootwidget()
# ウィジェットの操作.
root.e("configure -height 300 -width 300")
# タイトルを付けるときは wm を使う.
wm.e("title", root, $0)
# 親ウィジェットとコマンドを指定して, ウィジェットを作る.
l1 = TclTkWidget.new(ip, root, label, "-text {type `x' to print}")
# place すると表示される.
place.e(l1, "-x 0 -rely 0.0 -relwidth 1 -relheight 0.1")
# コマンド名は文字列で指定しても良いが, 見ためが悪い.
# (コマンド名は独立した引数でなければならない.)
l2 = TclTkWidget.new(ip, root, "label")
# ウィジェットの操作.
l2.e("configure -text {type `q' to exit}")
place.e(l2, "-x 0 -rely 0.1 -relwidth 1 -relheight 0.1")
#### tcl/tk のコールバックに対応するオブジェクト(TclTkCallback)の操作
# コールバックを生成する.
c1 = TclTkCallback.new(ip, proc{sample(ip, root)})
# コールバックを持つウィジェットを生成する.
b1 = TclTkWidget.new(ip, root, button, "-text sample -command", c1)
place.e(b1, "-x 0 -rely 0.2 -relwidth 1 -relheight 0.1")
# イベントループを抜けるには destroy.e(root) する.
c2 = TclTkCallback.new(ip, proc{destroy.e(root)})
b2 = TclTkWidget.new(ip, root, button, "-text exit -command", c2)
place.e(b2, "-x 0 -rely 0.3 -relwidth 1 -relheight 0.1")
#### イベントのバインド
# script の追加 (bind tag sequence +script) は今のところできない.
# (イテレータ変数の設定がうまくいかない.)
# 基本的にはウィジェットに対するコールバックと同じ.
c3 = TclTkCallback.new(ip, proc{print("q pressed\n"); destroy.e(root)})
bind.e(root, "q", c3)
# bind コマンドで % 置換によりパラメータを受け取りたいときは,
# proc{} の後ろに文字列で指定すると,
# 置換結果をイテレータ変数を通して受け取ることができる.
# ただし proc{} の後ろの文字列は,
# bind コマンドに与えるコールバック以外で指定してはいけない.
c4 = TclTkCallback.new(ip, proc{|i| print("#{i} pressed\n")}, "%A")
bind.e(root, "x", c4)
# TclTkCallback を GC の対象にしたければ,
# dcb() (または deletecallbackkeys()) する必要がある.
cb = [c1, c2, c3, c4]
c5 = TclTkCallback.new(ip, proc{|w| TclTk.dcb(cb, root, w)}, "%W")
bind.e(root, "<Destroy>", c5)
cb.push(c5)
#### tcl/tk のイメージに対応するオブジェクト(TclTkImage)の操作
# データを指定して生成する.
i1 = TclTkImage.new(ip, "photo", "-file maru.gif")
# ラベルに張り付けてみる.
l3 = TclTkWidget.new(ip, root, label, "-relief raised -image", i1)
place.e(l3, "-x 0 -rely 0.4 -relwidth 0.2 -relheight 0.2")
# 空のイメージを生成して後で操作する.
i2 = TclTkImage.new(ip, "photo")
# イメージを操作する.
i2.e("copy", i1)
i2.e("configure -gamma 0.5")
l4 = TclTkWidget.new(ip, root, label, "-relief raised -image", i2)
place.e(l4, "-relx 0.2 -rely 0.4 -relwidth 0.2 -relheight 0.2")
####
end
# サンプルのためのウィジェットを生成する.
def sample(ip, parent)
bind, button, destroy, grid, toplevel, wm = ip.commands().indexes(
"bind", "button", "destroy", "grid", "toplevel", "wm")
## toplevel
# 新しいウインドウを開くには, toplevel を使う.
t1 = TclTkWidget.new(ip, parent, toplevel)
# タイトルを付けておく
wm.e("title", t1, "sample")
# ウィジェットが破壊されたとき, コールバックが GC の対象になるようにする.
cb = []
cb.push(c = TclTkCallback.new(ip, proc{|w| TclTk.dcb(cb, t1, w)}, "%W"))
bind.e(t1, "<Destroy>", c)
# ボタンの生成.
wid = []
# toplevel ウィジェットを破壊するには destroy する.
cb.push(c = TclTkCallback.new(ip, proc{destroy.e(t1)}))
wid.push(TclTkWidget.new(ip, t1, button, "-text close -command", c))
cb.push(c = TclTkCallback.new(ip, proc{test_label(ip, t1)}))
wid.push(TclTkWidget.new(ip, t1, button, "-text label -command", c))
cb.push(c = TclTkCallback.new(ip, proc{test_button(ip, t1)}))
wid.push(TclTkWidget.new(ip, t1, button, "-text button -command", c))
cb.push(c = TclTkCallback.new(ip, proc{test_checkbutton(ip, t1)}))
wid.push(TclTkWidget.new(ip, t1, button, "-text checkbutton -command", c))
cb.push(c = TclTkCallback.new(ip, proc{test_radiobutton(ip, t1)}))
wid.push(TclTkWidget.new(ip, t1, button, "-text radiobutton -command", c))
cb.push(c = TclTkCallback.new(ip, proc{test_scale(ip, t1)}))
wid.push(TclTkWidget.new(ip, t1, button, "-text scale -command", c))
cb.push(c = TclTkCallback.new(ip, proc{test_entry(ip, t1)}))
wid.push(TclTkWidget.new(ip, t1, button, "-text entry -command", c))
cb.push(c = TclTkCallback.new(ip, proc{test_text(ip, t1)}))
wid.push(TclTkWidget.new(ip, t1, button, "-text text -command", c))
cb.push(c = TclTkCallback.new(ip, proc{test_raise(ip, t1)}))
wid.push(TclTkWidget.new(ip, t1, button, "-text raise/lower -command", c))
cb.push(c = TclTkCallback.new(ip, proc{test_modal(ip, t1)}))
wid.push(TclTkWidget.new(ip, t1, button, "-text message/modal -command",
c))
cb.push(c = TclTkCallback.new(ip, proc{test_menu(ip, t1)}))
wid.push(TclTkWidget.new(ip, t1, button, "-text menu -command", c))
cb.push(c = TclTkCallback.new(ip, proc{test_listbox(ip, t1)}))
wid.push(TclTkWidget.new(ip, t1, button, "-text listbox/scrollbar",
"-command", c))
cb.push(c = TclTkCallback.new(ip, proc{test_canvas(ip, t1)}))
wid.push(TclTkWidget.new(ip, t1, button, "-text canvas -command", c))
# grid で表示する.
ro = co = 0
wid.each{|w|
grid.e(w, "-row", ro, "-column", co, "-sticky news")
ro += 1
if ro == 7
ro = 0
co += 1
end
}
end
# inittoplevel(ip, parent, title)
# 以下の処理をまとめて行う.
# 1. toplevel ウィジェットを作成する.
# 2. コールバックを登録する配列を用意し, toplevel ウィジェットの
# <Destroy> イベントにコールバックを削除する手続きを登録する.
# 3. クローズボタンを作る.
# 作成した toplevel ウィジェット, クローズボタン, コールバック登録用変数
# を返す.
# ip: インタプリタ
# parent: 親ウィジェット
# title: toplevel ウィジェットのウインドウのタイトル
def inittoplevel(ip, parent, title)
bind, button, destroy, toplevel, wm = ip.commands().indexes(
"bind", "button", "destroy", "toplevel", "wm")
# 新しいウインドウを開くには, toplevel を使う.
t1 = TclTkWidget.new(ip, parent, toplevel)
# タイトルを付けておく
wm.e("title", t1, title)
# ウィジェットが破壊されたとき, コールバックが GC の対象になるようにする.
cb = []
cb.push(c = TclTkCallback.new(ip, proc{|w| TclTk.dcb(cb, t1, w)}, "%W"))
bind.e(t1, "<Destroy>", c)
# close ボタンを作っておく.
# toplevel ウィジェットを破壊するには destroy する.
cb.push(c = TclTkCallback.new(ip, proc{destroy.e(t1)}))
b1 = TclTkWidget.new(ip, t1, button, "-text close -command", c)
return t1, b1, cb
end
# label のサンプル.
def test_label(ip, parent)
button, global, label, pack = ip.commands().indexes(
"button", "global", "label", "pack")
t1, b1, cb = inittoplevel(ip, parent, "label")
## label
# いろいろな形のラベル.
l1 = TclTkWidget.new(ip, t1, label, "-text {default(flat)}")
l2 = TclTkWidget.new(ip, t1, label, "-text raised -relief raised")
l3 = TclTkWidget.new(ip, t1, label, "-text sunken -relief sunken")
l4 = TclTkWidget.new(ip, t1, label, "-text groove -relief groove")
l5 = TclTkWidget.new(ip, t1, label, "-text ridge -relief ridge")
l6 = TclTkWidget.new(ip, t1, label, "-bitmap error")
l7 = TclTkWidget.new(ip, t1, label, "-bitmap questhead")
# pack しても表示される.
pack.e(b1, l1, l2, l3, l4, l5, l6, l7, "-pady 3")
## -textvariable
# tcltk ライブラリの実装では, コールバックは tcl/tk の``手続き''を通して
# 呼ばれる. したがって, コールバックの中で(大域)変数にアクセスするときは,
# global する必要がある.
# global する前に変数に値を設定してしまうとエラーになるので,
# tcl/tk における表現形だけ生成して, 実際に値を設定しないように,
# 2 番目の引数には nil を与える.
v1 = TclTkVariable.new(ip, nil)
global.e(v1)
v1.set(100)
# -textvariable で変数を設定する.
l6 = TclTkWidget.new(ip, t1, label, "-textvariable", v1)
# コールバックの中から変数を操作する.
cb.push(c = TclTkCallback.new(ip, proc{
global.e(v1); v1.set(v1.get().to_i + 10)}))
b2 = TclTkWidget.new(ip, t1, button, "-text +10 -command", c)
cb.push(c = TclTkCallback.new(ip, proc{
global.e(v1); v1.set(v1.get().to_i - 10)}))
b3 = TclTkWidget.new(ip, t1, button, "-text -10 -command", c)
pack.e(l6, b2, b3)
end
# button のサンプル.
def test_button(ip, parent)
button, pack = ip.commands().indexes("button", "pack")
t1, b1, cb = inittoplevel(ip, parent, "button")
## button
# コールバック内で参照する変数は先に宣言しておかなければならない.
b3 = b4 = nil
cb.push(c = TclTkCallback.new(ip, proc{b3.e("flash"); b4.e("flash")}))
b2 = TclTkWidget.new(ip, t1, button, "-text flash -command", c)
cb.push(c = TclTkCallback.new(ip, proc{b2.e("configure -state normal")}))
b3 = TclTkWidget.new(ip, t1, button, "-text normal -command", c)
cb.push(c = TclTkCallback.new(ip, proc{b2.e("configure -state disabled")}))
b4 = TclTkWidget.new(ip, t1, button, "-text disable -command", c)
pack.e(b1, b2, b3, b4)
end
# checkbutton のサンプル.
def test_checkbutton(ip, parent)
checkbutton, global, pack = ip.commands().indexes(
"checkbutton", "global", "pack")
t1, b1, cb = inittoplevel(ip, parent, "checkbutton")
## checkbutton
v1 = TclTkVariable.new(ip, nil)
global.e(v1)
# -variable で変数を設定する.
ch1 = TclTkWidget.new(ip, t1, checkbutton, "-onvalue on -offvalue off",
"-textvariable", v1, "-variable", v1)
pack.e(b1, ch1)
end
# radiobutton のサンプル.
def test_radiobutton(ip, parent)
global, label, pack, radiobutton = ip.commands().indexes(
"global", "label", "pack", "radiobutton")
t1, b1, cb = inittoplevel(ip, parent, "radiobutton")
## radiobutton
v1 = TclTkVariable.new(ip, nil)
global.e(v1)
# ヌルストリングは "{}" で指定する.
v1.set("{}")
l1 = TclTkWidget.new(ip, t1, label, "-textvariable", v1)
# -variable で同じ変数を指定すると同じグループになる.
ra1 = TclTkWidget.new(ip, t1, radiobutton,
"-text radio1 -value r1 -variable", v1)
ra2 = TclTkWidget.new(ip, t1, radiobutton,
"-text radio2 -value r2 -variable", v1)
cb.push(c = TclTkCallback.new(ip, proc{global.e(v1); v1.set("{}")}))
ra3 = TclTkWidget.new(ip, t1, radiobutton,
"-text clear -value r3 -variable", v1, "-command", c)
pack.e(b1, l1, ra1, ra2, ra3)
end
# scale のサンプル.
def test_scale(ip, parent)
global, pack, scale = ip.commands().indexes(
"global", "pack", "scale")
t1, b1, cb = inittoplevel(ip, parent, "scale")
## scale
v1 = TclTkVariable.new(ip, nil)
global.e(v1)
v1.set(219)
# コールバック内で参照する変数は先に宣言しておかなければならない.
sca1 = nil
cb.push(c = TclTkCallback.new(ip, proc{global.e(v1); v = v1.get();
sca1.e("configure -background", format("#%02x%02x%02x", v, v, v))}))
sca1 = TclTkWidget.new(ip, t1, scale,
"-label scale -orient h -from 0 -to 255 -variable", v1, "-command", c)
pack.e(b1, sca1)
end
# entry のサンプル.
def test_entry(ip, parent)
button, entry, global, pack = ip.commands().indexes(
"button", "entry", "global", "pack")
t1, b1, cb = inittoplevel(ip, parent, "entry")
## entry
v1 = TclTkVariable.new(ip, nil)
global.e(v1)
# ヌルストリングは "{}" で指定する.
v1.set("{}")
en1 = TclTkWidget.new(ip, t1, entry, "-textvariable", v1)
cb.push(c = TclTkCallback.new(ip, proc{
global.e(v1); print(v1.get(), "\n"); v1.set("{}")}))
b2 = TclTkWidget.new(ip, t1, button, "-text print -command", c)
pack.e(b1, en1, b2)
end
# text のサンプル.
def test_text(ip, parent)
button, pack, text = ip.commands().indexes(
"button", "pack", "text")
t1, b1, cb = inittoplevel(ip, parent, "text")
## text
te1 = TclTkWidget.new(ip, t1, text)
cb.push(c = TclTkCallback.new(ip, proc{
# 1 行目の 0 文字目から最後までを表示し, 削除する.
print(te1.e("get 1.0 end")); te1.e("delete 1.0 end")}))
b2 = TclTkWidget.new(ip, t1, button, "-text print -command", c)
pack.e(b1, te1, b2)
end
# raise/lower のサンプル.
def test_raise(ip, parent)
button, frame, lower, pack, raise = ip.commands().indexes(
"button", "frame", "lower", "pack", "raise")
t1, b1, cb = inittoplevel(ip, parent, "raise/lower")
## raise/lower
# button を隠すテストのために, frame を使う.
f1 = TclTkWidget.new(ip, t1, frame)
# コールバック内で参照する変数は先に宣言しておかなければならない.
b2 = nil
cb.push(c = TclTkCallback.new(ip, proc{raise.e(f1, b2)}))
b2 = TclTkWidget.new(ip, t1, button, "-text raise -command", c)
cb.push(c = TclTkCallback.new(ip, proc{lower.e(f1, b2)}))
b3 = TclTkWidget.new(ip, t1, button, "-text lower -command", c)
lower.e(f1, b3)
pack.e(b2, b3, "-in", f1)
pack.e(b1, f1)
end
# modal なウィジェットのサンプル.
def test_modal(ip, parent)
button, frame, message, pack, tk_chooseColor, tk_getOpenFile,
tk_messageBox = ip.commands().indexes(
"button", "frame", "message", "pack", "tk_chooseColor",
"tk_getOpenFile", "tk_messageBox")
# 最初に load されていないライブラリは ip.commands() に存在しないので,
# TclTkLibCommand を生成する必要がある.
tk_dialog = TclTkLibCommand.new(ip, "tk_dialog")
t1, b1, cb = inittoplevel(ip, parent, "message/modal")
## message
mes = "これは message ウィジェットのテストです."
mes += "以下は modal なウィジェットのテストです."
me1 = TclTkWidget.new(ip, t1, message, "-text {#{mes}}")
## modal
# tk_messageBox
cb.push(c = TclTkCallback.new(ip, proc{
print tk_messageBox.e("-type yesnocancel -message messageBox",
"-icon error -default cancel -title messageBox"), "\n"}))
b2 = TclTkWidget.new(ip, t1, button, "-text messageBox -command", c)
# tk_dialog
cb.push(c = TclTkCallback.new(ip, proc{
# ウィジェット名を生成するためにダミーの frame を生成.
print tk_dialog.e(TclTkWidget.new(ip, t1, frame),
"dialog dialog error 2 yes no cancel"), "\n"}))
b3 = TclTkWidget.new(ip, t1, button, "-text dialog -command", c)
# tk_chooseColor
cb.push(c = TclTkCallback.new(ip, proc{
print tk_chooseColor.e("-title chooseColor"), "\n"}))
b4 = TclTkWidget.new(ip, t1, button, "-text chooseColor -command", c)
# tk_getOpenFile
cb.push(c = TclTkCallback.new(ip, proc{
print tk_getOpenFile.e("-defaultextension .rb",
"-filetypes {{{Ruby Script} {.rb}} {{All Files} {*}}}",
"-title getOpenFile"), "\n"}))
b5 = TclTkWidget.new(ip, t1, button, "-text getOpenFile -command", c)
pack.e(b1, me1, b2, b3, b4, b5)
end
# menu のサンプル.
def test_menu(ip, parent)
global, menu, menubutton, pack = ip.commands().indexes(
"global", "menu", "menubutton", "pack")
tk_optionMenu = TclTkLibCommand.new(ip, "tk_optionMenu")
t1, b1, cb = inittoplevel(ip, parent, "menu")
## menu
# menubutton を生成する.
mb1 = TclTkWidget.new(ip, t1, menubutton, "-text menu")
# menu を生成する.
me1 = TclTkWidget.new(ip, mb1, menu)
# mb1 から me1 が起動されるようにする.
mb1.e("configure -menu", me1)
# cascade で起動される menu を生成する.
me11 = TclTkWidget.new(ip, me1, menu)
# radiobutton のサンプル.
v1 = TclTkVariable.new(ip, nil); global.e(v1); v1.set("r1")
me11.e("add radiobutton -label radio1 -value r1 -variable", v1)
me11.e("add radiobutton -label radio2 -value r2 -variable", v1)
me11.e("add radiobutton -label radio3 -value r3 -variable", v1)
# cascade により mb11 が起動されるようにする.
me1.e("add cascade -label cascade -menu", me11)
# checkbutton のサンプル.
v2 = TclTkVariable.new(ip, nil); global.e(v2); v2.set("none")
me1.e("add checkbutton -label check -variable", v2)
# separator のサンプル.
me1.e("add separator")
# command のサンプル.
v3 = nil
cb.push(c = TclTkCallback.new(ip, proc{
global.e(v1, v2, v3); print "v1: ", v1.get(), ", v2: ", v2.get(),
", v3: ", v3.get(), "\n"}))
me1.e("add command -label print -command", c)
## tk_optionMenu
v3 = TclTkVariable.new(ip, nil); global.e(v3); v3.set("opt2")
om1 = TclTkWidget.new(ip, t1, tk_optionMenu, v3, "opt1 opt2 opt3 opt4")
pack.e(b1, mb1, om1, "-side left")
end
# listbox のサンプル.
def test_listbox(ip, parent)
clipboard, frame, grid, listbox, lower, menu, menubutton, pack, scrollbar,
selection = ip.commands().indexes(
"clipboard", "frame", "grid", "listbox", "lower", "menu", "menubutton",
"pack", "scrollbar", "selection")
t1, b1, cb = inittoplevel(ip, parent, "listbox")
## listbox/scrollbar
f1 = TclTkWidget.new(ip, t1, frame)
# コールバック内で参照する変数は先に宣言しておかなければならない.
li1 = sc1 = sc2 = nil
# 実行時に, 後ろにパラメータがつくコールバックは,
# イテレータ変数でそのパラメータを受け取ることができる.
# (複数のパラメータはひとつの文字列にまとめられる.)
cb.push(c1 = TclTkCallback.new(ip, proc{|i| li1.e("xview", i)}))
cb.push(c2 = TclTkCallback.new(ip, proc{|i| li1.e("yview", i)}))
cb.push(c3 = TclTkCallback.new(ip, proc{|i| sc1.e("set", i)}))
cb.push(c4 = TclTkCallback.new(ip, proc{|i| sc2.e("set", i)}))
# listbox
li1 = TclTkWidget.new(ip, f1, listbox,
"-xscrollcommand", c3, "-yscrollcommand", c4,
"-selectmode extended -exportselection true")
for i in 1..20
li1.e("insert end {line #{i} line #{i} line #{i} line #{i} line #{i}}")
end
# scrollbar
sc1 = TclTkWidget.new(ip, f1, scrollbar, "-orient horizontal -command", c1)
sc2 = TclTkWidget.new(ip, f1, scrollbar, "-orient vertical -command", c2)
## selection/clipboard
mb1 = TclTkWidget.new(ip, t1, menubutton, "-text edit")
me1 = TclTkWidget.new(ip, mb1, menu)
mb1.e("configure -menu", me1)
cb.push(c = TclTkCallback.new(ip, proc{
# clipboard をクリア.
clipboard.e("clear")
# selection から文字列を読み込み clipboard に追加する.
clipboard.e("append {#{selection.e(\"get\")}}")}))
me1.e("add command -label {selection -> clipboard} -command",c)
cb.push(c = TclTkCallback.new(ip, proc{
# li1 をクリア.
li1.e("delete 0 end")
# clipboard から文字列を取り出し, 1 行ずつ
selection.e("get -selection CLIPBOARD").split(/\n/).each{|line|
# li1 に挿入する.
li1.e("insert end {#{line}}")}}))
me1.e("add command -label {clipboard -> listbox} -command",c)
grid.e(li1, "-row 0 -column 0 -sticky news")
grid.e(sc1, "-row 1 -column 0 -sticky ew")
grid.e(sc2, "-row 0 -column 1 -sticky ns")
grid.e("rowconfigure", f1, "0 -weight 100")
grid.e("columnconfigure", f1, "0 -weight 100")
f2 = TclTkWidget.new(ip, t1, frame)
lower.e(f2, b1)
pack.e(b1, mb1, "-in", f2, "-side left")
pack.e(f2, f1)
end
# canvas のサンプル.
def test_canvas(ip, parent)
canvas, lower, pack = ip.commands().indexes("canvas", "lower", "pack")
t1, b1, cb = inittoplevel(ip, parent, "canvas")
## canvas
ca1 = TclTkWidget.new(ip, t1, canvas, "-width 400 -height 300")
lower.e(ca1, b1)
# rectangle を作る.
idr = ca1.e("create rectangle 10 10 20 20")
# oval を作る.
ca1.e("create oval 60 10 100 50")
# polygon を作る.
ca1.e("create polygon 110 10 110 30 140 10")
# line を作る.
ca1.e("create line 150 10 150 30 190 10")
# arc を作る.
ca1.e("create arc 200 10 250 50 -start 0 -extent 90 -style pieslice")
# i1 は本当は, どこかで破壊しなければならないが, 面倒なので放ってある.
i1 = TclTkImage.new(ip, "photo", "-file maru.gif")
# image を作る.
ca1.e("create image 100 100 -image", i1)
# bitmap を作る.
ca1.e("create bitmap 260 50 -bitmap questhead")
# text を作る.
ca1.e("create text 320 50 -text {drag rectangle}")
# window を作る(クローズボタン).
ca1.e("create window 200 200 -window", b1)
# bind により rectangle を drag できるようにする.
cb.push(c = TclTkCallback.new(ip, proc{|i|
# i に x と y を受け取るので, 取り出す.
x, y = i.split(/ /); x = x.to_f; y = y.to_f
# 座標を変更する.
ca1.e("coords current #{x - 5} #{y - 5} #{x + 5} #{y + 5}")},
# x, y 座標を空白で区切ったものをイテレータ変数へ渡すように指定.
"%x %y"))
# rectangle に bind する.
ca1.e("bind", idr, "<B1-Motion>", c)
pack.e(ca1)
end
end
# test driver
if ARGV.size == 0
print "#{$0} n で, n 個のインタプリタを起動します.\n"
n = 1
else
n = ARGV[0].to_i
end
print "start\n"
ip = []
# インタプリタ, ウィジェット等の生成.
for i in 1 .. n
ip.push(Test1.new())
end
# 用意ができたらイベントループに入る.
TclTk.mainloop()
print "exit from mainloop\n"
# インタプリタが GC されるかのテスト.
ip = []
print "GC.start\n" if $DEBUG
GC.start() if $DEBUG
print "end\n"
exit
# end

View File

@ -0,0 +1,449 @@
#!/usr/local/bin/ruby
#----------------------> pretty simple othello game <-----------------------
# othello.rb
#
# version 0.3
# maeda shugo (shuto@po.aianet.ne.jp)
#---------------------------------------------------------------------------
# Sep. 17, 1997 modified by Y. Shigehiro for tcltk library
# maeda shugo (shugo@po.aianet.ne.jp) 氏による
# (ruby/tk で書かれていた) ruby のサンプルプログラム
# http://www.aianet.or.jp/~shugo/ruby/othello.rb.gz
# を tcltk ライブラリを使うように, 機械的に変更してみました.
#
# なるべくオリジナルと同じになるようにしてあります.
require "observer"
require "tcltk"
$ip = TclTkInterpreter.new()
$root = $ip.rootwidget()
$button, $canvas, $checkbutton, $frame, $label, $pack, $update, $wm =
$ip.commands().indexes(
"button", "canvas", "checkbutton", "frame", "label", "pack", "update", "wm")
class Othello
EMPTY = 0
BLACK = 1
WHITE = - BLACK
attr :in_com_turn
attr :game_over
class Board
include Observable
DIRECTIONS = [
[-1, -1], [-1, 0], [-1, 1],
[ 0, -1], [ 0, 1],
[ 1, -1], [ 1, 0], [ 1, 1]
]
attr :com_disk, TRUE
def initialize(othello)
@othello = othello
reset
end
def notify_observers(*arg)
if @observer_peers != nil
super(*arg)
end
end
def reset
@data = [
[EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY],
[EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY],
[EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY],
[EMPTY, EMPTY, EMPTY, WHITE, BLACK, EMPTY, EMPTY, EMPTY],
[EMPTY, EMPTY, EMPTY, BLACK, WHITE, EMPTY, EMPTY, EMPTY],
[EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY],
[EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY],
[EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY]
]
changed
notify_observers
end
def man_disk
return - @com_disk
end
def other_disk(disk)
return - disk
end
def get_disk(row, col)
return @data[row][col]
end
def reverse_to(row, col, my_disk, dir_y, dir_x)
y = row
x = col
begin
y += dir_y
x += dir_x
if y < 0 || x < 0 || y > 7 || x > 7 ||
@data[y][x] == EMPTY
return
end
end until @data[y][x] == my_disk
begin
@data[y][x] = my_disk
changed
notify_observers(y, x)
y -= dir_y
x -= dir_x
end until y == row && x == col
end
def put_disk(row, col, disk)
@data[row][col] = disk
changed
notify_observers(row, col)
DIRECTIONS.each do |dir|
reverse_to(row, col, disk, *dir)
end
end
def count_disk(disk)
num = 0
@data.each do |rows|
rows.each do |d|
if d == disk
num += 1
end
end
end
return num
end
def count_point_to(row, col, my_disk, dir_y, dir_x)
return 0 if @data[row][col] != EMPTY
count = 0
loop do
row += dir_y
col += dir_x
break if row < 0 || col < 0 || row > 7 || col > 7
case @data[row][col]
when my_disk
return count
when other_disk(my_disk)
count += 1
when EMPTY
break
end
end
return 0
end
def count_point(row, col, my_disk)
count = 0
DIRECTIONS.each do |dir|
count += count_point_to(row, col, my_disk, *dir)
end
return count
end
def corner?(row, col)
return (row == 0 && col == 0) ||
(row == 0 && col == 7) ||
(row == 7 && col == 0) ||
(row == 7 && col == 7)
end
def search(my_disk)
max = 0
max_row = nil
max_col = nil
for row in 0 .. 7
for col in 0 .. 7
buf = count_point(row, col, my_disk)
if (corner?(row, col) && buf > 0) || max < buf
max = buf
max_row = row
max_col = col
end
end
end
return max_row, max_col
end
end #--------------------------> class Board ends here
class BoardView < TclTkWidget
BACK_GROUND_COLOR = "DarkGreen"
HILIT_BG_COLOR = "green"
BORDER_COLOR = "black"
BLACK_COLOR = "black"
WHITE_COLOR = "white"
STOP_COLOR = "red"
attr :left
attr :top
attr :right
attr :bottom
class Square
attr :oval, TRUE
attr :row
attr :col
def initialize(view, row, col)
@view = view
@id = @view.e("create rectangle", *view.tk_rect(view.left + col,
view.top + row,
view.left + col + 1,
view.top + row + 1))
@row = row
@col = col
@view.e("itemconfigure", @id,
"-width 0.5m -outline #{BORDER_COLOR}")
@view.e("bind", @id, "<Any-Enter>", TclTkCallback.new($ip, proc{
if @oval == nil
view.e("itemconfigure", @id, "-fill #{HILIT_BG_COLOR}")
end
}))
@view.e("bind", @id, "<Any-Leave>", TclTkCallback.new($ip, proc{
view.e("itemconfigure", @id, "-fill #{BACK_GROUND_COLOR}")
}))
@view.e("bind", @id, "<ButtonRelease-1>", TclTkCallback.new($ip,
proc{
view.click_square(self)
}))
end
def blink(color)
@view.e("itemconfigure", @id, "-fill #{color}")
$update.e()
sleep(0.1)
@view.e("itemconfigure", @id, "-fill #{BACK_GROUND_COLOR}")
end
end #-----------------------> class Square ends here
def initialize(othello, board)
super($ip, $root, $canvas)
@othello = othello
@board = board
@board.add_observer(self)
@squares = Array.new(8)
for i in 0 .. 7
@squares[i] = Array.new(8)
end
@left = 1
@top = 0.5
@right = @left + 8
@bottom = @top + 8
i = self.e("create rectangle", *tk_rect(@left, @top, @right, @bottom))
self.e("itemconfigure", i,
"-width 1m -outline #{BORDER_COLOR} -fill #{BACK_GROUND_COLOR}")
for row in 0 .. 7
for col in 0 .. 7
@squares[row][col] = Square.new(self, row, col)
end
end
update
end
def tk_rect(left, top, right, bottom)
return left.to_s + "c", top.to_s + "c",
right.to_s + "c", bottom.to_s + "c"
end
def clear
each_square do |square|
if square.oval != nil
self.e("delete", square.oval)
square.oval = nil
end
end
end
def draw_disk(row, col, disk)
if disk == EMPTY
if @squares[row][col].oval != nil
self.e("delete", @squares[row][col].oval)
@squares[row][col].oval = nil
end
return
end
$update.e()
sleep(0.05)
oval = @squares[row][col].oval
if oval == nil
oval = self.e("create oval", *tk_rect(@left + col + 0.2,
@top + row + 0.2,
@left + col + 0.8,
@top + row + 0.8))
@squares[row][col].oval = oval
end
case disk
when BLACK
color = BLACK_COLOR
when WHITE
color = WHITE_COLOR
else
fail format("Unknown disk type: %d", disk)
end
self.e("itemconfigure", oval, "-outline #{color} -fill #{color}")
end
def update(row = nil, col = nil)
if row && col
draw_disk(row, col, @board.get_disk(row, col))
else
each_square do |square|
draw_disk(square.row, square.col,
@board.get_disk(square.row, square.col))
end
end
@othello.show_point
end
def each_square
@squares.each do |rows|
rows.each do |square|
yield(square)
end
end
end
def click_square(square)
if @othello.in_com_turn || @othello.game_over ||
@board.count_point(square.row,
square.col,
@board.man_disk) == 0
square.blink(STOP_COLOR)
return
end
@board.put_disk(square.row, square.col, @board.man_disk)
@othello.com_turn
end
private :draw_disk
public :update
end #----------------------> class BoardView ends here
def initialize
@msg_label = TclTkWidget.new($ip, $root, $label)
$pack.e(@msg_label)
@board = Board.new(self)
@board_view = BoardView.new(self, @board)
#### added by Y. Shigehiro
## board_view の大きさを設定する.
x1, y1, x2, y2 = @board_view.e("bbox all").split(/ /).collect{|i| i.to_f}
@board_view.e("configure -width", x2 - x1)
@board_view.e("configure -height", y2 - y1)
## scrollregion を設定する.
@board_view.e("configure -scrollregion {", @board_view.e("bbox all"),
"}")
#### ここまで
$pack.e(@board_view, "-fill both -expand true")
panel = TclTkWidget.new($ip, $root, $frame)
@play_black = TclTkWidget.new($ip, panel, $checkbutton,
"-text {com is black} -command", TclTkCallback.new($ip, proc{
switch_side
}))
$pack.e(@play_black, "-side left")
quit = TclTkWidget.new($ip, panel, $button, "-text Quit -command",
TclTkCallback.new($ip, proc{
exit
}))
$pack.e(quit, "-side right -fill x")
reset = TclTkWidget.new($ip, panel, $button, "-text Reset -command",
TclTkCallback.new($ip, proc{
reset_game
}))
$pack.e(reset, "-side right -fill x")
$pack.e(panel, "-side bottom -fill x")
# root = Tk.root
$wm.e("title", $root, "Othello")
$wm.e("iconname", $root, "Othello")
@board.com_disk = WHITE
@game_over = FALSE
TclTk.mainloop
end
def switch_side
if @in_com_turn
@play_black.e("toggle")
else
@board.com_disk = @board.man_disk
com_turn unless @game_over
end
end
def reset_game
if @board.com_disk == BLACK
@board.com_disk = WHITE
@play_black.e("toggle")
end
@board_view.clear
@board.reset
$wm.e("title", $root, "Othello")
@game_over = FALSE
end
def com_turn
@in_com_turn = TRUE
$update.e()
sleep(0.5)
begin
com_disk = @board.count_disk(@board.com_disk)
man_disk = @board.count_disk(@board.man_disk)
if @board.count_disk(EMPTY) == 0
if man_disk == com_disk
$wm.e("title", $root, "{Othello - Draw!}")
elsif man_disk > com_disk
$wm.e("title", $root, "{Othello - You Win!}")
else
$wm.e("title", $root, "{Othello - You Loose!}")
end
@game_over = TRUE
break
elsif com_disk == 0
$wm.e("title", $root, "{Othello - You Win!}")
@game_over = TRUE
break
elsif man_disk == 0
$wm.e("title", $root, "{Othello - You Loose!}")
@game_over = TRUE
break
end
row, col = @board.search(@board.com_disk)
break if row == nil || col == nil
@board.put_disk(row, col, @board.com_disk)
end while @board.search(@board.man_disk) == [nil, nil]
@in_com_turn = FALSE
end
def show_point
black = @board.count_disk(BLACK)
white = @board.count_disk(WHITE)
@msg_label.e("configure -text",
%Q/{#{format("BLACK: %.2d WHITE: %.2d", black, white)}}/)
end
end #----------------------> class Othello ends here
Othello.new
#----------------------------------------------> othello.rb ends here

216
ext/tcltklib/tcltklib.c Normal file
View File

@ -0,0 +1,216 @@
/*
* tcltklib.c
* Aug. 27, 1997 Y. Shigehiro
* Oct. 24, 1997 Y. Matsumoto
*/
#include "ruby.h"
#include "sig.h"
#include <stdio.h>
#include <string.h>
#include <tcl.h>
#include <tk.h>
/* for debug */
#define DUMP1(ARG1) if (debug) { fprintf(stderr, "tcltklib: %s\n", ARG1);}
#define DUMP2(ARG1, ARG2) if (debug) { fprintf(stderr, "tcltklib: ");\
fprintf(stderr, ARG1, ARG2); fprintf(stderr, "\n"); }
/*
#define DUMP1(ARG1)
#define DUMP2(ARG1, ARG2)
*/
/* from tkAppInit.c */
/*
* The following variable is a special hack that is needed in order for
* Sun shared libraries to be used for Tcl.
*/
extern int matherr();
int *tclDummyMathPtr = (int *) matherr;
/*---- module TclTkLib ----*/
static VALUE thread_safe = Qnil;
/* execute Tk_MainLoop */
static VALUE
lib_mainloop(VALUE self)
{
int old_trapflg;
int flags = RTEST(thread_safe)?TCL_DONT_WAIT:0;
DUMP1("start Tk_Mainloop");
while (Tk_GetNumMainWindows() > 0) {
old_trapflg = trap_immediate;
trap_immediate = 1;
Tcl_DoOneEvent(flags);
trap_immediate = old_trapflg;
CHECK_INTS;
flags = (thread_safe == 0 || thread_safe == Qnil)?0:TCL_DONT_WAIT;
}
DUMP1("stop Tk_Mainloop");
return Qnil;
}
/*---- class TclTkIp ----*/
struct tcltkip {
Tcl_Interp *ip; /* the interpreter */
int return_value; /* return value */
};
/* Tcl command `ruby' */
static VALUE
ip_eval_rescue(VALUE *failed, VALUE einfo)
{
*failed = einfo;
return Qnil;
}
static int
ip_ruby(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
{
VALUE res;
int old_trapflg;
VALUE failed = 0;
/* ruby command has 1 arg. */
if (argc != 2) {
ArgError("wrong # of arguments (%d for 1)", argc);
}
/* evaluate the argument string by ruby */
DUMP2("rb_eval_string(%s)", argv[1]);
old_trapflg = trap_immediate;
trap_immediate = 0;
res = rb_rescue(rb_eval_string, argv[1], ip_eval_rescue, &failed);
trap_immediate = old_trapflg;
if (failed) {
Tcl_AppendResult(interp, RSTRING(failed)->ptr, (char*)NULL);
return TCL_ERROR;
}
/* result must be string or nil */
if (NIL_P(res)) {
DUMP1("(rb_eval_string result) nil");
return TCL_OK;
}
Check_Type(res, T_STRING);
/* copy result to the tcl interpreter */
DUMP2("(rb_eval_string result) %s", RSTRING(res)->ptr);
DUMP1("Tcl_AppendResult");
Tcl_AppendResult(interp, RSTRING(res)->ptr, (char *)NULL);
return TCL_OK;
}
/* destroy interpreter */
static void
ip_free(struct tcltkip *ptr)
{
DUMP1("Tcl_DeleteInterp");
Tcl_DeleteInterp(ptr->ip);
}
/* create and initialize interpreter */
static VALUE
ip_new(VALUE self)
{
struct tcltkip *ptr; /* tcltkip data struct */
VALUE obj; /* newly created object */
/* create object */
obj = Data_Make_Struct(self, struct tcltkip, 0, ip_free, ptr);
ptr->return_value = 0;
/* from Tk_Main() */
DUMP1("Tcl_CreateInterp");
ptr->ip = Tcl_CreateInterp();
/* from Tcl_AppInit() */
DUMP1("Tcl_Init");
if (Tcl_Init(ptr->ip) == TCL_ERROR) {
Fail("Tcl_Init");
}
DUMP1("Tk_Init");
if (Tk_Init(ptr->ip) == TCL_ERROR) {
Fail("Tk_Init");
}
DUMP1("Tcl_StaticPackage(\"Tk\")");
Tcl_StaticPackage(ptr->ip, "Tk", Tk_Init,
(Tcl_PackageInitProc *) NULL);
/* add ruby command to the interpreter */
DUMP1("Tcl_CreateCommand(\"ruby\")");
Tcl_CreateCommand(ptr->ip, "ruby", ip_ruby, (ClientData *)NULL,
(Tcl_CmdDeleteProc *)NULL);
return obj;
}
/* eval string in tcl by Tcl_Eval() */
static VALUE
ip_eval(VALUE self, VALUE str)
{
char *buf; /* Tcl_Eval requires re-writable string region */
struct tcltkip *ptr; /* tcltkip data struct */
/* get the data struct */
Data_Get_Struct(self, struct tcltkip, ptr);
/* call Tcl_Eval() */
Check_Type(str, T_STRING);
buf = ALLOCA_N(char,RSTRING(str)->len+1);
strcpy(buf, RSTRING(str)->ptr);
DUMP2("Tcl_Eval(%s)", buf);
ptr->return_value = Tcl_Eval(ptr->ip, buf);
if (ptr->return_value == TCL_ERROR) {
Fail(ptr->ip->result);
}
DUMP2("(TCL_Eval result) %d", ptr->return_value);
/* pass back the result (as string) */
return(str_new2(ptr->ip->result));
}
/* get return code from Tcl_Eval() */
static VALUE
ip_retval(VALUE self)
{
struct tcltkip *ptr; /* tcltkip data struct */
/* get the data strcut */
Data_Get_Struct(self, struct tcltkip, ptr);
return (INT2FIX(ptr->return_value));
}
/*---- initialization ----*/
void Init_tcltklib()
{
extern VALUE rb_argv0; /* the argv[0] */
VALUE lib = rb_define_module("TclTkLib");
VALUE ip = rb_define_class("TclTkIp", cObject);
rb_define_module_function(lib, "mainloop", lib_mainloop, 0);
rb_define_singleton_method(ip, "new", ip_new, 0);
rb_define_method(ip, "_eval", ip_eval, 1);
rb_define_method(ip, "_return_value", ip_retval, 0);
rb_define_method(ip, "mainloop", lib_mainloop, 0);
/*---- initialize tcl/tk libraries ----*/
/* from Tk_Main() */
DUMP1("Tcl_FindExecutable");
Tcl_FindExecutable(RSTRING(rb_argv0)->ptr);
rb_define_variable("$tk_thread_safe", &thread_safe);
}
/* eof */

37
instruby.rb Normal file
View File

@ -0,0 +1,37 @@
#!./miniruby
require "rbconfig.rb"
include Config
$:.unshift CONFIG["srcdir"]+"/lib"
require "ftools"
binsuffix = CONFIG["binsuffix"]
if ENV["prefix"]
prefix = ENV["prefix"]
else
prefix = CONFIG["prefix"]
end
ruby_install_name = CONFIG["ruby_install_name"]
bindir = prefix + "/bin"
libdir = prefix + "/lib/" + ruby_install_name
archdir = libdir+"/"+CONFIG["arch"]
mandir = CONFIG["mandir"] + "/man1"
File.install "ruby#{binsuffix}",
"#{bindir}/#{ruby_install_name}#{binsuffix}", 0755, TRUE
File.makedirs libdir, TRUE
Dir.chdir "ext"
system "../miniruby#{binsuffix} extmk.rb install"
Dir.chdir CONFIG["srcdir"]
IO.foreach 'MANIFEST' do |$_|
$_.chop!
if /^lib/
File.install $_, libdir, 0644, TRUE
elsif /^[a-z]+\.h$/
File.install $_, archdir, 0644, TRUE
end
File.install "config.h", archdir, 0644, TRUE
end
File.install "rbconfig.rb", archdir, 0644, TRUE
File.install "ruby.1", mandir, 0644, TRUE
# vi:set sw=2:

291
intern.h Normal file
View File

@ -0,0 +1,291 @@
/* Functions and variables that are used by more than one source file of
* the kernel. Not available to extensions and applications.
*/
/* array.c */
void memclear _((register VALUE *, register int));
VALUE assoc_new _((VALUE, VALUE));
VALUE ary_new _((void));
VALUE ary_new2 _((int));
VALUE ary_new3();
VALUE ary_new4 _((int, VALUE *));
VALUE ary_freeze _((VALUE));
void ary_store _((VALUE, int, VALUE));
VALUE ary_push _((VALUE, VALUE));
VALUE ary_pop _((VALUE));
VALUE ary_shift _((VALUE));
VALUE ary_unshift _((VALUE, VALUE));
VALUE ary_entry _((VALUE, int));
VALUE ary_each _((VALUE));
VALUE ary_join _((VALUE, VALUE));
VALUE ary_to_s _((VALUE));
VALUE ary_print_on _((VALUE, VALUE));
VALUE ary_reverse _((VALUE));
VALUE ary_sort_bang _((VALUE));
VALUE ary_sort _((VALUE));
VALUE ary_delete _((VALUE, VALUE));
VALUE ary_delete_at _((VALUE, VALUE));
VALUE ary_plus _((VALUE, VALUE));
VALUE ary_concat _((VALUE, VALUE));
VALUE ary_assoc _((VALUE, VALUE));
VALUE ary_rassoc _((VALUE, VALUE));
VALUE ary_includes _((VALUE, VALUE));
/* bignum.c */
VALUE big_clone _((VALUE));
void big_2comp _((VALUE));
VALUE big_norm _((VALUE));
VALUE uint2big _((UINT));
VALUE int2big _((INT));
VALUE uint2inum _((UINT));
VALUE int2inum _((INT));
VALUE str2inum _((UCHAR *, int));
VALUE big2str _((VALUE, int));
INT big2int _((VALUE));
VALUE big_to_i _((VALUE));
VALUE dbl2big _((double));
double big2dbl _((VALUE));
VALUE big_to_f _((VALUE));
VALUE big_plus _((VALUE, VALUE));
VALUE big_minus _((VALUE, VALUE));
VALUE big_mul _((VALUE, VALUE));
VALUE big_pow _((VALUE, VALUE));
VALUE big_and _((VALUE, VALUE));
VALUE big_or _((VALUE, VALUE));
VALUE big_xor _((VALUE, VALUE));
VALUE big_lshift _((VALUE, VALUE));
VALUE big_rand _((VALUE));
/* class.c */
VALUE class_new _((VALUE));
VALUE singleton_class_new _((VALUE));
VALUE singleton_class_clone _((VALUE));
void singleton_class_attached _((VALUE,VALUE));
VALUE rb_define_class_id _((ID, VALUE));
VALUE module_new _((void));
VALUE rb_define_module_id _((ID));
VALUE mod_included_modules _((VALUE));
VALUE mod_ancestors _((VALUE));
VALUE class_instance_methods _((int, VALUE *, VALUE));
VALUE class_private_instance_methods _((int, VALUE *, VALUE));
VALUE obj_singleton_methods _((VALUE));
void rb_define_method_id _((VALUE, ID, VALUE (*)(), int));
void rb_undef_method _((VALUE, char *));
void rb_define_private_method _((VALUE, char *, VALUE (*)(), int));
void rb_define_singleton_method _((VALUE,char*,VALUE(*)(),int));
void rb_define_private_method _((VALUE,char*,VALUE(*)(),int));
VALUE rb_singleton_class _((VALUE));
/* enum.c */
VALUE enum_length _((VALUE));
/* error.c */
VALUE exc_new _((VALUE, char *, UINT));
VALUE exc_new2 _((VALUE, char *));
VALUE exc_new3 _((VALUE, VALUE));
#ifdef __GNUC__
volatile voidfn TypeError;
volatile voidfn ArgError;
volatile voidfn NameError;
volatile voidfn IndexError;
volatile voidfn LoadError;
#else
void TypeError();
void ArgError();
void NameError();
void IndexError();
void LoadError();
#endif
/* eval.c */
void rb_clear_cache _((void));
void rb_alias _((VALUE, ID, ID));
int rb_method_boundp _((VALUE, ID, int));
VALUE dyna_var_defined _((ID));
VALUE dyna_var_ref _((ID));
VALUE dyna_var_asgn _((ID, VALUE));
void ruby_init _((void));
void ruby_options _((int, char **));
void ruby_run _((void));
void rb_eval_cmd _((VALUE, VALUE));
void rb_trap_eval _((VALUE, int));
int rb_respond_to _((VALUE, ID));
void rb_raise _((VALUE));
void rb_fatal _((VALUE));
void rb_interrupt _((void));
int iterator_p _((void));
VALUE rb_yield_0 _((VALUE, volatile VALUE));
VALUE rb_apply _((VALUE, ID, VALUE));
VALUE rb_funcall2 _((VALUE, ID, int, VALUE *));
void rb_backtrace _((void));
ID rb_frame_last_func _((void));
VALUE f_load _((VALUE, VALUE));
void rb_provide _((char *));
VALUE f_require _((VALUE, VALUE));
VALUE class_new_instance _((int, VALUE *, VALUE));
VALUE f_lambda _((void));
void rb_set_end_proc _((void (*)(),VALUE));
void gc_mark_threads _((void));
void thread_schedule _((void));
void thread_wait_fd _((int));
void thread_fd_writable _((int));
int thread_alone _((void));
void thread_sleep _((int));
void thread_sleep_forever _((void));
VALUE thread_create _((VALUE (*)(), void *));
void thread_interrupt _((void));
/* file.c */
VALUE file_open _((char *, char *));
int eaccess _((char *, int));
VALUE file_s_expand_path _((VALUE, VALUE));
/* gc.c */
void rb_global_variable _((VALUE *));
void gc_mark_locations _((VALUE *, VALUE *));
void gc_mark_maybe();
void gc_mark();
void gc_force_recycle();
void gc_gc _((void));
void init_stack _((void));
void init_heap _((void));
/* hash.c */
VALUE hash_freeze _((VALUE));
VALUE rb_hash _((VALUE));
VALUE hash_new _((void));
VALUE hash_aref _((VALUE, VALUE));
VALUE hash_aset _((VALUE, VALUE, VALUE));
/* io.c */
void eof_error _((void));
VALUE io_write _((VALUE, VALUE));
VALUE io_gets_method _((int, VALUE*, VALUE));
VALUE io_gets _((VALUE));
VALUE io_getc _((VALUE));
VALUE io_ungetc _((VALUE, VALUE));
VALUE io_close _((VALUE));
VALUE io_binmode _((VALUE));
int io_mode_flags _((char *));
VALUE io_reopen _((VALUE, VALUE));
VALUE f_gets _((void));
void rb_str_setter _((VALUE, ID, VALUE *));
/* numeric.c */
void num_zerodiv _((void));
VALUE num_coerce_bin _((VALUE, VALUE));
VALUE float_new _((double));
VALUE flo_pow _((VALUE, VALUE));
VALUE num2fix _((VALUE));
VALUE fix2str _((VALUE, int));
VALUE fix_to_s _((VALUE));
VALUE num_upto _((VALUE, VALUE));
VALUE fix_upto _((VALUE, VALUE));
/* object.c */
VALUE rb_equal _((VALUE, VALUE));
int rb_eql _((VALUE, VALUE));
VALUE obj_equal _((VALUE, VALUE));
VALUE any_to_s _((VALUE));
VALUE rb_inspect _((VALUE));
VALUE obj_is_instance_of _((VALUE, VALUE));
VALUE obj_is_kind_of _((VALUE, VALUE));
VALUE obj_alloc _((VALUE));
VALUE rb_Integer _((VALUE));
VALUE rb_Float _((VALUE));
VALUE rb_String _((VALUE));
VALUE rb_Array _((VALUE));
double num2dbl _((VALUE));
/* parse.y */
int yyparse _((void));
void pushback _((int));
ID id_attrset _((ID));
void yyappend_print _((void));
void yywhile_loop _((int, int));
int rb_is_const_id _((ID));
int rb_is_instance_id _((ID));
void local_var_append _((ID));
VALUE backref_get _((void));
void backref_set _((VALUE));
VALUE lastline_get _((void));
void lastline_set _((VALUE));
/* process.c */
int rb_proc_exec _((char *));
void rb_syswait _((int));
/* range.c */
VALUE range_new _((VALUE, VALUE));
VALUE range_beg_end _((VALUE, int *, int *));
/* re.c */
VALUE reg_nth_defined _((int, VALUE));
VALUE reg_nth_match _((int, VALUE));
VALUE reg_last_match _((VALUE));
VALUE reg_match_pre _((VALUE));
VALUE reg_match_post _((VALUE));
VALUE reg_match_last _((VALUE));
VALUE reg_new _((char *, int, int));
VALUE reg_match _((VALUE, VALUE));
VALUE reg_match2 _((VALUE));
void rb_set_kcode _((char *));
/* ruby.c */
void rb_require_modules _((void));
void rb_load_file _((char *));
void ruby_script _((char *));
void ruby_prog_init _((void));
void ruby_set_argv _((int, char **));
void ruby_process_options _((int, char **));
/* signal.c */
VALUE f_kill _((int, VALUE *));
void gc_mark_trap_list _((void));
void posix_signal _((int, void (*)()));
void rb_trap_exit _((void));
void rb_trap_exec _((void));
/* sprintf.c */
VALUE f_sprintf _((int, VALUE *));
/* string.c */
VALUE str_new _((UCHAR *, UINT));
VALUE str_new2 _((UCHAR *));
VALUE str_new3 _((VALUE));
VALUE str_new4 _((VALUE));
VALUE obj_as_string _((VALUE));
VALUE str_dup _((VALUE));
VALUE str_plus _((VALUE, VALUE));
VALUE str_times _((VALUE, VALUE));
VALUE str_substr _((VALUE, int, int));
void str_modify _((VALUE));
VALUE str_freeze _((VALUE));
VALUE str_dup_freezed _((VALUE));
VALUE str_taint _((VALUE));
VALUE str_tainted _((VALUE));
VALUE str_resize _((VALUE, int));
VALUE str_cat _((VALUE, UCHAR *, UINT));
int str_hash _((VALUE));
int str_cmp _((VALUE, VALUE));
VALUE str_upto _((VALUE, VALUE));
VALUE str_inspect _((VALUE));
VALUE str_split _((VALUE, char *));
/* struct.c */
VALUE struct_new();
VALUE struct_define();
VALUE struct_alloc _((VALUE, VALUE));
VALUE struct_aref _((VALUE, VALUE));
VALUE struct_aset _((VALUE, VALUE, VALUE));
VALUE struct_getmember _((VALUE, ID));
/* time.c */
VALUE time_new _((int, int));
/* util.c */
void add_suffix _((VALUE, char *));
unsigned long scan_oct _((char *, int, int *));
unsigned long scan_hex _((char *, int, int *));
/* variable.c */
VALUE mod_name _((VALUE));
VALUE rb_class_path _((VALUE));
void rb_set_class_path _((VALUE, VALUE, char *));
VALUE rb_path2class _((char *));
void rb_name_class _((VALUE, ID));
void rb_autoload _((char *, char *));
VALUE f_autoload _((VALUE, VALUE, VALUE));
void gc_mark_global_tbl _((void));
VALUE f_trace_var _((int, VALUE *));
VALUE f_untrace_var _((int, VALUE *));
VALUE rb_gvar_set2 _((char *, VALUE));
VALUE f_global_variables _((void));
void rb_alias_variable _((ID, ID));
VALUE rb_ivar_get _((VALUE, ID));
VALUE rb_ivar_set _((VALUE, ID, VALUE));
VALUE rb_ivar_defined _((VALUE, ID));
VALUE obj_instance_variables _((VALUE));
VALUE mod_const_at _((VALUE, VALUE));
VALUE mod_constants _((VALUE));
VALUE mod_const_of _((VALUE, VALUE));
int rb_const_defined_at _((VALUE, ID));
int rb_autoload_defined _((ID));
int rb_const_defined _((VALUE, ID));

40
keywords Normal file
View File

@ -0,0 +1,40 @@
struct kwtable {char *name; int id[2]; enum lex_state state;};
%%
BEGIN, klBEGIN, klBEGIN, EXPR_END
END, klEND, klEND, EXPR_END
alias, kALIAS, kALIAS, EXPR_FNAME
and, kAND, kAND, EXPR_BEG
begin, kBEGIN, kBEGIN, EXPR_BEG
break, kBREAK, kBREAK, EXPR_END
case, kCASE, kCASE, EXPR_BEG
class, kCLASS, kCLASS, EXPR_CLASS
def, kDEF, kDEF, EXPR_FNAME
defined?, kDEFINED, kDEFINED, EXPR_END
do, kDO, kDO, EXPR_BEG
else, kELSE, kELSE, EXPR_BEG
elsif, kELSIF, kELSIF, EXPR_BEG
end, kEND, kEND, EXPR_END
ensure, kENSURE, kENSURE, EXPR_BEG
false, kFALSE, kFALSE, EXPR_END
for, kFOR, kFOR, EXPR_BEG
if, kIF, kIF_MOD, EXPR_BEG
in, kIN, kIN, EXPR_BEG
module, kMODULE, kMODULE, EXPR_BEG
next, kNEXT, kNEXT, EXPR_END
nil, kNIL, kNIL, EXPR_END
not, kNOT, kNOT, EXPR_BEG
or, kOR, kOR, EXPR_BEG
redo, kREDO, kREDO, EXPR_END
rescue, kRESCUE, kRESCUE, EXPR_MID
retry, kRETRY, kRETRY, EXPR_END
return, kRETURN, kRETURN, EXPR_MID
self, kSELF, kSELF, EXPR_END
super, kSUPER, kSUPER, EXPR_END
then, kTHEN, kTHEN, EXPR_BEG
true, kTRUE, kTRUE, EXPR_END
undef, kUNDEF, kUNDEF, EXPR_FNAME
unless, kUNLESS, kUNLESS_MOD, EXPR_BEG
until, kUNTIL, kUNTIL_MOD, EXPR_BEG
when, kWHEN, kWHEN, EXPR_BEG
while, kWHILE, kWHILE_MOD, EXPR_BEG
yield, kYIELD, kYIELD, EXPR_END

117
lex.c Normal file
View File

@ -0,0 +1,117 @@
/* C code produced by gperf version 2.5 (GNU C++ version) */
/* Command-line: gperf -p -j1 -i 1 -g -o -t -N rb_reserved_word -k1,3,$ keywords */
struct kwtable {char *name; int id[2]; enum lex_state state;};
#define TOTAL_KEYWORDS 38
#define MIN_WORD_LENGTH 2
#define MAX_WORD_LENGTH 8
#define MIN_HASH_VALUE 6
#define MAX_HASH_VALUE 52
/* maximum key range = 47, duplicates = 0 */
#ifdef __GNUC__
inline
#endif
static unsigned int
hash (str, len)
register char *str;
register int unsigned len;
{
static unsigned char asso_values[] =
{
53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
53, 53, 53, 11, 53, 53, 34, 53, 1, 35,
53, 1, 53, 53, 53, 53, 53, 53, 1, 53,
53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
53, 53, 53, 53, 53, 53, 53, 29, 1, 2,
1, 1, 4, 24, 53, 17, 53, 20, 9, 2,
9, 26, 14, 53, 5, 1, 1, 16, 53, 21,
24, 9, 53, 53, 53, 53, 53, 53,
};
register int hval = len;
switch (hval)
{
default:
case 3:
hval += asso_values[str[2]];
case 2:
case 1:
hval += asso_values[str[0]];
break;
}
return hval + asso_values[str[len - 1]];
}
#ifdef __GNUC__
inline
#endif
struct kwtable *
rb_reserved_word (str, len)
register char *str;
register unsigned int len;
{
static struct kwtable wordlist[] =
{
{"",}, {"",}, {"",}, {"",}, {"",}, {"",},
{"end", kEND, kEND, EXPR_END},
{"else", kELSE, kELSE, EXPR_BEG},
{"case", kCASE, kCASE, EXPR_BEG},
{"ensure", kENSURE, kENSURE, EXPR_BEG},
{"module", kMODULE, kMODULE, EXPR_BEG},
{"elsif", kELSIF, kELSIF, EXPR_BEG},
{"def", kDEF, kDEF, EXPR_FNAME},
{"rescue", kRESCUE, kRESCUE, EXPR_MID},
{"not", kNOT, kNOT, EXPR_BEG},
{"then", kTHEN, kTHEN, EXPR_BEG},
{"yield", kYIELD, kYIELD, EXPR_END},
{"for", kFOR, kFOR, EXPR_BEG},
{"self", kSELF, kSELF, EXPR_END},
{"false", kFALSE, kFALSE, EXPR_END},
{"retry", kRETRY, kRETRY, EXPR_END},
{"return", kRETURN, kRETURN, EXPR_MID},
{"true", kTRUE, kTRUE, EXPR_END},
{"if", kIF, kIF_MOD, EXPR_BEG},
{"defined?", kDEFINED, kDEFINED, EXPR_END},
{"super", kSUPER, kSUPER, EXPR_END},
{"undef", kUNDEF, kUNDEF, EXPR_FNAME},
{"break", kBREAK, kBREAK, EXPR_END},
{"in", kIN, kIN, EXPR_BEG},
{"do", kDO, kDO, EXPR_BEG},
{"nil", kNIL, kNIL, EXPR_END},
{"until", kUNTIL, kUNTIL_MOD, EXPR_BEG},
{"unless", kUNLESS, kUNLESS_MOD, EXPR_BEG},
{"or", kOR, kOR, EXPR_BEG},
{"and", kAND, kAND, EXPR_BEG},
{"when", kWHEN, kWHEN, EXPR_BEG},
{"redo", kREDO, kREDO, EXPR_END},
{"class", kCLASS, kCLASS, EXPR_CLASS},
{"next", kNEXT, kNEXT, EXPR_END},
{"begin", kBEGIN, kBEGIN, EXPR_BEG},
{"END", klEND, klEND, EXPR_END},
{"BEGIN", klBEGIN, klBEGIN, EXPR_END},
{"",}, {"",},
{"while", kWHILE, kWHILE_MOD, EXPR_BEG},
{"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
{"alias", kALIAS, kALIAS, EXPR_FNAME},
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
{
register int key = hash (str, len);
if (key <= MAX_HASH_VALUE && key >= 0)
{
register char *s = wordlist[key].name;
if (*s == *str && !strcmp (str + 1, s + 1))
return &wordlist[key];
}
}
return 0;
}

44
lib/delegate.rb Normal file
View File

@ -0,0 +1,44 @@
# Delegation class that delegates even methods defined in super class,
# which can not be covered with normal method_missing hack.
#
# Delegater is the abstract delegation class. Need to redefine
# `__getobj__' method in the subclass. SimpleDelegater is the
# concrete subclass for simple delegation.
#
# Usage:
# foo = Object.new
# foo = SimpleDelegater.new(foo)
# foo.type # => Object
class Delegater
def initialize(obj)
preserved = ["id", "equal?", "__getobj__"]
for t in self.type.ancestors
preserved |= t.instance_methods
break if t == Delegater
end
for method in obj.methods
next if preserved.include? method
eval "def self.#{method}(*args); __getobj__.send :#{method}, *args; end"
end
end
def __getobj__
raise NotImplementError, "need to define `__getobj__'"
end
end
class SimpleDelegater<Delegater
def initialize(obj)
super
@obj = obj
end
def __getobj__
@obj
end
end

39
lib/eregex.rb Normal file
View File

@ -0,0 +1,39 @@
class RegOr
def initialize(re1, re2)
@re1 = re1
@re2 = re2
end
def =~ (str)
@re1 =~ str or @re2 =~ str
end
end
class RegAnd
def initialize(re1, re2)
@re1 = re1
@re2 = re2
end
def =~ (str)
@re1 =~ str and @re2 =~ str
end
end
class Regexp
def |(other)
RegOr.new(self, other)
end
def &(other)
RegAnd.new(self, other)
end
end
p "abc" =~ /b/|/c/
p "abc" =~ /b/&/c/

163
lib/ftools.rb Normal file
View File

@ -0,0 +1,163 @@
class << File
TOO_BIG = 1024 * 1024 * 2 # 2MB
def catname from, to
if FileTest.directory? to
to +
if to =~ /\\/
if to[-1,1] != '\\' then '\\' end + basename(from)
else
if to[-1,1] != '/' then '/' end + basename(from)
end
else
to
end
end
# copy file
def syscopy from, to
to = catname(from, to)
fsize = size(from)
fsize = 1024 if fsize < 512
fsize = TOO_BIG if fsize > TOO_BIG
from = open(from, "r")
from.binmode
to = open(to, "w")
to.binmode
begin
while TRUE
r = from.sysread(fsize)
rsize = r.size
w = 0
while w < rsize
t = to.syswrite(r[w, rsize - w])
w += t
end
end
rescue EOFError
ret = TRUE
rescue
ret = FALSE
ensure
to.close
from.close
end
ret
end
def copy from, to, verbose = FALSE
$stderr.print from, " -> ", catname(from, to), "\n" if verbose
syscopy from, to
end
alias cp copy
# move file
def move from, to, verbose = FALSE
to = catname(from, to)
$stderr.print from, " -> ", to, "\n" if verbose
if PLATFORM =~ /djgpp|cygwin32|mswin32/ and FileTest.file? to
unlink to
end
begin
rename from, to
rescue
syscopy from, to and unlink from
end
end
alias mv move
# compare two files
# TRUE: identical
# FALSE: not identical
def compare from, to, verbose = FALSE
$stderr.print from, " <=> ", to, "\n" if verbose
fsize = size(from)
fsize = 1024 if fsize < 512
fsize = TOO_BIG if fsize > TOO_BIG
from = open(from, "r")
from.binmode
to = open(to, "r")
to.binmode
ret = FALSE
fr = tr = ''
begin
while fr == tr
if fr = from.read(fsize)
tr = to.read(fr.size)
else
ret = !to.read(fsize)
break
end
end
rescue
ret = FALSE
ensure
to.close
from.close
end
ret
end
alias cmp compare
# unlink files safely
def safe_unlink(*files)
verbose = if files[-1].is_a? String then FALSE else files.pop end
begin
$stderr.print files.join(" "), "\n" if verbose
chmod 0777, *files
unlink *files
rescue
# STDERR.print "warning: Couldn't unlink #{files.join ' '}\n"
end
end
alias rm_f safe_unlink
def makedirs(*dirs)
verbose = if dirs[-1].is_a? String then FALSE else dirs.pop end
# mode = if dirs[-1].is_a? Fixnum then dirs.pop else 0755 end
mode = 0755
for dir in dirs
next if FileTest.directory? dir
parent = dirname(dir)
makedirs parent unless FileTest.directory? parent
$stderr.print "mkdir ", dir, "\n" if verbose
Dir.mkdir dir, mode
end
end
alias mkpath makedirs
alias o_chmod chmod
def chmod(mode, *files)
verbose = if files[-1].is_a? String then FALSE else files.pop end
$stderr.printf "chmod %04o %s\n", mode, files.join(" ") if verbose
o_chmod mode, *files
end
def install(from, to, mode, verbose)
to = catname(from, to)
unless FileTest.exist? to and cmp from, to
cp from, to, verbose
chmod mode, to, verbose if mode
end
end
end
# vi:set sw=2:

29
lib/importenv.rb Normal file
View File

@ -0,0 +1,29 @@
# importenv.rb -- imports environment variables as global variables
#
# Usage:
#
# require 'importenv'
# p $USER
# $USER = "matz"
# p ENV["USER"]
for k,v in ENV
next unless /^[a-zA-Z][_a-zA-Z0-9]*/ =~ k
eval <<EOS
$#{k} = %q!#{v}!
trace_var "$#{k}", proc{|v|
ENV[%q!#{k}!] = v;
$#{k} = %q!#{v}!
if v == nil
untrace_var "$#{k}"
end
}
EOS
end
p $TERM
$TERM = nil
p $TERM
p ENV["TERM"]
$TERM = "foo"
p ENV["TERM"]

343
lib/mkmf.rb Normal file
View File

@ -0,0 +1,343 @@
# module to create Makefile for extention modules
# invoke like: ruby -r mkmf extconf.rb
require 'rbconfig'
include Config
$found = false;
$lib_cache = {}
$lib_found = {}
$func_cache = {}
$func_found = {}
$hdr_cache = {}
$hdr_found = {}
$config_cache = CONFIG["compile_dir"]+"/ext/config.cache"
if File.exist?($config_cache) then
f = open($config_cache, "r")
while f.gets
case $_
when /^lib: (.+) (yes|no)/
$lib_cache[$1] = $2
when /^func: ([\w_]+) (yes|no)/
$func_cache[$1] = $2
when /^hdr: (.+) (yes|no)/
$hdr_cache[$1] = $2
end
end
f.close
end
$srcdir = CONFIG["srcdir"]
$libdir = CONFIG["libdir"]+"/"+CONFIG["ruby_install_name"]
$archdir = $libdir+"/"+CONFIG["arch"]
$install = CONFIG["INSTALL_PROGRAM"]
$install_data = CONFIG["INSTALL_DATA"]
if $install !~ /^\// then
$install = CONFIG["srcdir"]+"/"+$install
end
if File.exist? $archdir + "/ruby.h"
$hdrdir = $archdir
elsif File.exist? $srcdir + "/ruby.h"
$hdrdir = $srcdir
else
STDERR.print "can't find header files for ruby.\n"
exit 1
end
nul = "> /dev/null"
CFLAGS = CONFIG["CFLAGS"]
if PLATFORM == "m68k-human"
nul = "> nul"
CFLAGS.gsub!(/-c..-stack=[0-9]+ */, '')
end
if $DEBUG
nul = ""
end
LINK = CONFIG["CC"]+" -o conftest -I#{$srcdir} " + CFLAGS + " %s " + CONFIG["LDFLAGS"] + " %s conftest.c " + CONFIG["LIBS"] + "%s " + nul + " 2>&1"
CPP = CONFIG["CPP"] + " -E -I#{$srcdir} " + CFLAGS + " %s conftest.c " + nul + " 2>&1"
def try_link(libs)
system(format(LINK, $CFLAGS, $LDFLAGS, libs))
end
def try_cpp
system(format(CPP, $CFLAGS))
end
def have_library(lib, func)
printf "checking for %s() in -l%s... ", func, lib
STDOUT.flush
if $lib_cache[lib]
if $lib_cache[lib] == "yes"
if $libs
$libs = "-l" + lib + " " + $libs
else
$libs = "-l" + lib
end
print "(cached) yes\n"
return TRUE
else
print "(cached) no\n"
return FALSE
end
end
cfile = open("conftest.c", "w")
cfile.printf "\
int main() { return 0; }
int t() { %s(); return 0; }
", func
cfile.close
begin
if $libs
libs = "-l" + lib + " " + $libs
else
libs = "-l" + lib
end
unless try_link(libs)
$lib_found[lib] = 'no'
$found = TRUE
print "no\n"
return FALSE
end
ensure
system "rm -f conftest*"
end
$libs = libs
$lib_found[lib] = 'yes'
$found = TRUE
print "yes\n"
return TRUE
end
def have_func(func)
printf "checking for %s()... ", func
STDOUT.flush
if $func_cache[func]
if $func_cache[func] == "yes"
$defs.push(format("-DHAVE_%s", func.upcase))
print "(cached) yes\n"
return TRUE
else
print "(cached) no\n"
return FALSE
end
end
cfile = open("conftest.c", "w")
cfile.printf "\
char %s();
int main() { return 0; }
int t() { %s(); return 0; }
", func, func
cfile.close
libs = $libs
libs = "" if libs == nil
begin
unless try_link(libs)
$func_found[func] = 'no'
$found = TRUE
print "no\n"
return FALSE
end
ensure
system "rm -f conftest*"
end
$defs.push(format("-DHAVE_%s", func.upcase))
$func_found[func] = 'yes'
$found = TRUE
print "yes\n"
return TRUE
end
def have_header(header)
printf "checking for %s... ", header
STDOUT.flush
if $hdr_cache[header]
if $hdr_cache[header] == "yes"
header.tr!("a-z./\055", "A-Z___")
$defs.push(format("-DHAVE_%s", header))
print "(cached) yes\n"
return TRUE
else
print "(cached) no\n"
return FALSE
end
end
cfile = open("conftest.c", "w")
cfile.printf "\
#include <%s>
", header
cfile.close
begin
unless try_cpp
$hdr_found[header] = 'no'
$found = TRUE
print "no\n"
return FALSE
end
ensure
system "rm -f conftest*"
end
$hdr_found[header] = 'yes'
header.tr!("a-z./\055", "A-Z___")
$defs.push(format("-DHAVE_%s", header))
$found = TRUE
print "yes\n"
return TRUE
end
def create_header()
print "creating extconf.h\n"
STDOUT.flush
if $defs.length > 0
hfile = open("extconf.h", "w")
for line in $defs
line =~ /^-D(.*)/
hfile.printf "#define %s 1\n", $1
end
hfile.close
end
end
def create_makefile(target)
print "creating Makefile\n"
STDOUT.flush
if $libs and CONFIG["DLEXT"] == "o"
libs = $libs.split
for lib in libs
lib.sub!(/-l(.*)/, '"lib\1.a"')
end
$defs.push(format("-DEXTLIB='%s'", libs.join(",")))
end
$libs = "" unless $libs
if !$objs then
$objs = Dir["*.c"]
for f in $objs
f.sub!(/\.(c|cc)$/, ".o")
end
end
$objs = $objs.join(" ")
mfile = open("Makefile", "w")
mfile.print <<EOMF
SHELL = /bin/sh
#### Start of system configuration section. ####
srcdir = #{$srcdir}
hdrdir = #{$hdrdir}
CC = gcc
CFLAGS = #{CONFIG["CCDLFLAGS"]} -I#{$hdrdir} #{CFLAGS} #{$CFLAGS} #{$defs.join(" ")}
DLDFLAGS = #{CONFIG["DLDFLAGS"]} #{$LDFLAGS}
LDSHARED = #{CONFIG["LDSHARED"]}
prefix = #{CONFIG["prefix"]}
exec_prefix = #{CONFIG["exec_prefix"]}
libdir = #{$archdir}
#### End of system configuration section. ####
LOCAL_LIBS = #{$local_libs}
LIBS = #{$libs}
OBJS = #{$objs}
TARGET = #{target}.#{CONFIG["DLEXT"]}
INSTALL = #{$install}
binsuffix = #{CONFIG["binsuffix"]}
all: $(TARGET)
clean:; @rm -f *.o *.so *.sl
@rm -f Makefile extconf.h conftest.*
@rm -f core ruby$(binsuffix) *~
realclean: clean
install: $(libdir)/$(TARGET)
$(libdir)/$(TARGET): $(TARGET)
@test -d $(libdir) || mkdir $(libdir)
$(INSTALL) $(TARGET) $(libdir)/$(TARGET)
EOMF
for rb in Dir["lib/*.rb"]
mfile.printf "\t$(INSTALL) %s %s\n", rb, $libdir
end
mfile.printf "\n"
if CONFIG["DLEXT"] != "o"
mfile.printf <<EOMF
$(TARGET): $(OBJS)
$(LDSHARED) $(DLDFLAGS) -o $(TARGET) $(OBJS) $(LOCAL_LIBS) $(LIBS)
EOMF
elsif not File.exist?(target + ".c") and not File.exist?(target + ".cc") or
mfile.print "$(TARGET): $(OBJS)\n"
case PLATFORM
when "m68k-human"
mfile.printf "ar cru $(TARGET) $(OBJS)\n"
when /-nextstep/
mfile.printf "cc -r $(CFLAGS) -o $(TARGET) $(OBJS)\n"
else
mfile.printf "ld $(DLDFLAGS) -r -o $(TARGET) $(OBJS)\n"
end
end
if File.exist?("depend")
dfile = open("depend", "r")
mfile.printf "###\n"
while line = dfile.gets()
mfile.print line
end
dfile.close
end
mfile.close
if $found
begin
f = open($config_cache, "w")
for k,v in $lib_cache
f.printf "lib: %s %s\n", k, v.downcase
end
for k,v in $lib_found
f.printf "lib: %s %s\n", k, v.downcase
end
for k,v in $func_cache
f.printf "func: %s %s\n", k, v.downcase
end
for k,v in $func_found
f.printf "func: %s %s\n", k, v.downcase
end
for k,v in $hdr_cache
f.printf "hdr: %s %s\n", k, v.downcase
end
for k,v in $hdr_found
f.printf "hdr: %s %s\n", k, v.downcase
end
f.close
rescue
end
end
end
$local_libs = nil
$libs = nil
$objs = nil
$CFLAGS = nil
$LDFLAGS = nil
$defs = []

55
lib/ostruct.rb Normal file
View File

@ -0,0 +1,55 @@
# ostruct.rb - Python Style Object
# just assign to create field
#
# s = OpenStruct.new
# s.foo = 25
# p s.foo
# s.bar = 2
# p s.bar
# p s
class OpenStruct
def initialize(hash=nil)
@table = {}
if hash
for k,v in hash
@table[k] = v
end
end
end
def method_missing(mid, *args)
mname = mid.id2name
len = args.length
if mname =~ /=$/
if len != 1
raise ArgumentError, "wrong # of arguments (#{len} for 1)", caller(1)
end
mname.chop!
@table[mname] = args[0]
elsif args.length == 0
@table[mname]
else
raise NameError, "undefined method `#{mname}'", caller(1)
end
end
def delete_field(name)
if name.type == Fixnum
name = name.id2name
end
@table.delete name
end
def inspect
str = "<#{self.type}"
for k,v in @table
str += " "
str += k
str += "="
str += v.inspect
end
str += ">"
str
end
end

121
lib/pstore.rb Normal file
View File

@ -0,0 +1,121 @@
#!/usr/local/bin/ruby
# How to use:
#
# db = PStore.new("/tmp/foo")
# db.transaction do
# p db.roots
# ary = db["root"] = [1,2,3,4]
# ary[0] = [1,1.5]
# end
# db.transaction do
# p db["root"]
# end
require "marshal"
class PStore
Exception(:Error)
def initialize(file)
dir = File::dirname(file)
unless File::directory? dir
raise PStore::Error, format("directory %s does not exist", dir)
end
unless File::writable? dir
raise PStore::Error, format("directory %s not writable", dir)
end
if File::exist? file and not File::readable? file
raise PStore::Error, format("file %s not readable", file)
end
@transaction = false
@filename = file
@abort = false
end
def in_transaction
raise PStore::Error, "not in transaction" unless @transaction
end
private :in_transaction
def [](name)
in_transaction
value = @table[name]
if value == nil
raise PStore::Error, format("undefined root name `%s'", name)
end
value
end
def []=(name, value)
in_transaction
@table[name] = value
end
def roots
in_transaction
@table.keys
end
def root?(name)
in_transaction
@table.key? name
end
def path
@filename
end
def commit
@abort = false
throw :pstore_abort_transaction
end
def abort
@abort = true
throw :pstore_abort_transaction
end
def transaction
raise PStore::Error, "nested transaction" if @transaction
begin
@transaction = true
value = file = nil
begin
File::open(@filename, "r") do |file|
@table = Marshal.load(file)
end
rescue Errno::ENOENT
@table = {}
end
begin
catch(:pstore_abort_transaction) do
value = yield(self)
end
ensure
unless @abort
File::rename @filename, @filename+"~"
begin
File::open(@filename, "w") do |file|
Marshal::dump(@table, file)
end
rescue
File::rename @filename+"~", @filename
end
end
@abort = false
end
ensure
@transaction = false
end
value
end
end
db = PStore.new("/tmp/foo")
db.transaction do
p db.roots
ary = db["root"] = [1,2,3,4]
ary[0] = [1,1.5]
end
db.transaction do
p db["root"]
end

48
lib/shellwords.rb Normal file
View File

@ -0,0 +1,48 @@
# shellwords.rb
# original is shellwords.pl
#
# Usage:
# require 'shellwords.rb'
# words = Shellwords.shellwords(line)
#
# or
#
# include Shellwords
# words = shellwords(line)
module Shellwords
def shellwords(line)
return '' unless line
line.sub! /^\s+/, ''
words = []
while line != ''
field = ''
while TRUE
if line.sub! /^"(([^"\\]|\\.)*)"/, '' then
snippet = $1
snippet.gsub! /\\(.)/, '\1'
elsif line =~ /^"/ then
STDOUT.print "Unmatched double quote: $_\n"
exit
elsif line.sub! /^'(([^'\\]|\\.)*)'/, '' then
snippet = $1
snippet.gsub! /\\(.)/, '\1'
elsif line =~ /^'/ then
STDOUT.print "Unmatched single quote: $_\n"
exit
elsif line.sub! /^\\(.)/, '' then
snippet = $1
elsif line.sub! /^([^\s\\'"]+)/, '' then
snippet = $1
else
line.sub! /^\s+/, ''
break
end
field += snippet
end
words += field
end
words
end
module_function :shellwords
end

62
lib/tkdialog.rb Normal file
View File

@ -0,0 +1,62 @@
require "tk"
class TkDialog < TkWindow
# initialize tk_dialog
def initialize
super
@var = TkVariable.new
id = @var.id
INTERP._eval('eval {global '+id+';'+
'set '+id+' [tk_dialog '+
@path+" "+title+" \"#{message}\" "+bitmap+" "+
default_button+" "+buttons+']}')
end
def value
return @var.value.to_i
end
######################################################
# #
# these methods must be overridden for each dialog #
# #
######################################################
def title
return "DIALOG"
end
def message
return "MESSAGE"
end
def bitmap
return "info"
end
def default_button
return 0
end
def buttons
return "BUTTON1 BUTTON2"
end
end
#
# dialog for warning
#
class TkWarning < TkDialog
def initialize(mes)
@mes = mes
super()
end
def message
return @mes
end
def title
return "WARNING";
end
def bitmap
return "warning";
end
def default_button
return 0;
end
def buttons
return "OK";
end
end

70
lib/weakref.rb Normal file
View File

@ -0,0 +1,70 @@
# Weak Reference class that does not bother GCing.
#
# Usage:
# foo = Object.new
# foo.hash
# foo = WeakRef.new(foo)
# foo.hash
# ObjectSpace.garbage_collect
# foo.hash # => Raises WeakRef::RefError (because original GC'ed)
require "delegate"
class WeakRef<Delegater
Exception :RefError
ID_MAP = {}
ID_REV_MAP = {}
ObjectSpace.add_finalizer(lambda{|id|
rid = ID_MAP[id]
if rid
ID_REV_MAP[rid] = nil
ID_MAP[id] = nil
end
rid = ID_REV_MAP[id]
if rid
ID_REV_MAP[id] = nil
ID_MAP[rid] = nil
end
})
def initialize(orig)
super
@id = orig.id
ObjectSpace.call_finalizer orig
ID_MAP[@id] = self.id
ID_REV_MAP[self.id] = @id
end
def __getobj__
unless ID_MAP[@id]
$@ = caller(1)
$! = RefError.new("Illegal Reference - probably recycled")
raise
end
ObjectSpace.id2ref(@id)
# ObjectSpace.each_object do |obj|
# return obj if obj.id == @id
# end
end
def weakref_alive?
if ID_MAP[@id]
true
else
false
end
end
def []
__getobj__
end
end
foo = Object.new
p foo.hash
foo = WeakRef.new(foo)
p foo.hash
ObjectSpace.garbage_collect
p foo.hash

868
marshal.c Normal file
View File

@ -0,0 +1,868 @@
/************************************************
marshal.c -
$Author$
$Revision$
$Date$
created at: Thu Apr 27 16:30:01 JST 1995
************************************************/
#include "ruby.h"
#include "io.h"
#include "st.h"
#define MARSHAL_MAJOR 4
#define MARSHAL_MINOR 0
#define TYPE_NIL '0'
#define TYPE_TRUE 'T'
#define TYPE_FALSE 'F'
#define TYPE_FIXNUM 'i'
#define TYPE_UCLASS 'C'
#define TYPE_OBJECT 'o'
#define TYPE_USERDEF 'u'
#define TYPE_FLOAT 'f'
#define TYPE_BIGNUM 'l'
#define TYPE_STRING '"'
#define TYPE_REGEXP '/'
#define TYPE_ARRAY '['
#define TYPE_HASH '{'
#define TYPE_STRUCT 'S'
#define TYPE_MODULE 'M'
#define TYPE_SYMBOL ':'
#define TYPE_SYMLINK ';'
#define TYPE_LINK '@'
extern VALUE cString;
extern VALUE cRegexp;
extern VALUE cArray;
extern VALUE cHash;
VALUE rb_path2class();
static ID s_dump, s_load;
struct dump_arg {
VALUE obj;
FILE *fp;
VALUE str;
st_table *symbol;
st_table *data;
};
struct dump_call_arg {
VALUE obj;
struct dump_arg *arg;
int limit;
};
static void w_long _((long, struct dump_arg*));
static void
w_byte(c, arg)
char c;
struct dump_arg *arg;
{
if (arg->fp) putc(c, arg->fp);
else str_cat(arg->str, (UCHAR*)&c, 1);
}
static void
w_bytes(s, n, arg)
char *s;
int n;
struct dump_arg *arg;
{
w_long(n, arg);
if (arg->fp) {
fwrite(s, 1, n, arg->fp);
}
else {
str_cat(arg->str, s, n);
}
}
static void
w_short(x, arg)
int x;
struct dump_arg *arg;
{
int i;
for (i=0; i<sizeof(USHORT); i++) {
w_byte((x >> (i*8)) & 0xff, arg);
}
}
static void
w_long(x, arg)
long x;
struct dump_arg *arg;
{
char buf[sizeof(long)+1];
int i, len = 0;
if (x == 0) {
w_byte(0, arg);
return;
}
for (i=1;i<sizeof(long)+1;i++) {
buf[i] = x & 0xff;
x = RSHIFT(x,8);
if (x == 0) {
buf[0] = i;
break;
}
if (x == -1) {
buf[0] = -i;
break;
}
}
len = i;
for (i=0;i<=len;i++) {
w_byte(buf[i], arg);
}
}
static void
w_float(d, arg)
double d;
struct dump_arg *arg;
{
char buf[100];
sprintf(buf, "%.12g", d);
w_bytes(buf, strlen(buf), arg);
}
static void
w_symbol(id, arg)
ID id;
struct dump_arg *arg;
{
char *sym = rb_id2name(id);
int num;
if (st_lookup(arg->symbol, id, &num)) {
w_byte(TYPE_SYMLINK, arg);
w_long(num, arg);
}
else {
w_byte(TYPE_SYMBOL, arg);
w_bytes(sym, strlen(sym), arg);
st_insert(arg->symbol, id, arg->symbol->num_entries);
}
}
static void
w_unique(s, arg)
char *s;
struct dump_arg *arg;
{
w_symbol(rb_intern(s), arg);
}
static void w_object _((VALUE,struct dump_arg*,int));
extern VALUE cIO, cBignum, cStruct;
static int
hash_each(key, value, arg)
VALUE key, value;
struct dump_call_arg *arg;
{
w_object(key, arg->arg, arg->limit);
w_object(value, arg->arg, arg->limit);
return ST_CONTINUE;
}
static int
obj_each(id, value, arg)
ID id;
VALUE value;
struct dump_call_arg *arg;
{
w_symbol(id, arg->arg);
w_object(value, arg->arg, arg->limit);
return ST_CONTINUE;
}
static void
w_uclass(obj, class, arg)
VALUE obj, class;
struct dump_arg *arg;
{
if (CLASS_OF(obj) != class) {
w_byte(TYPE_UCLASS, arg);
w_unique(rb_class2name(CLASS_OF(obj)), arg);
}
}
static void
w_object(obj, arg, limit)
VALUE obj;
struct dump_arg *arg;
int limit;
{
int n;
struct dump_call_arg c_arg;
if (limit == 0) {
Fail("exceed depth limit");
}
limit--;
c_arg.limit = limit;
c_arg.arg = arg;
if (obj == Qnil) {
w_byte(TYPE_NIL, arg);
}
else if (obj == TRUE) {
w_byte(TYPE_TRUE, arg);
}
else if (obj == FALSE) {
w_byte(TYPE_FALSE, arg);
}
else if (FIXNUM_P(obj)) {
#if SIZEOF_LONG <= 4
w_byte(TYPE_FIXNUM, arg);
w_long(FIX2INT(obj), arg);
#else
if (RSHIFT(obj, 32) == 0 || RSHIFT(obj, 32) == -1) {
w_byte(TYPE_FIXNUM, arg);
w_long(FIX2INT(obj), arg);
}
else {
obj = int2big(FIX2INT(obj));
goto write_bignum;
}
#endif
}
else {
int num;
if (st_lookup(arg->data, obj, &num)) {
w_byte(TYPE_LINK, arg);
w_long(num, arg);
return;
}
st_insert(arg->data, obj, arg->data->num_entries);
if (rb_respond_to(obj, s_dump)) {
VALUE v;
w_byte(TYPE_USERDEF, arg);
w_unique(rb_class2name(CLASS_OF(obj)), arg);
v = rb_funcall(obj, s_dump, 1, limit);
if (TYPE(v) != T_STRING) {
TypeError("_dump_to must return String");
}
w_bytes(RSTRING(v)->ptr, RSTRING(v)->len, arg);
return;
}
switch (BUILTIN_TYPE(obj)) {
case T_MODULE:
case T_CLASS:
w_byte(TYPE_MODULE, arg);
{
VALUE path = rb_class_path(obj);
w_bytes(RSTRING(path)->ptr, RSTRING(path)->len, arg);
}
return;
case T_FLOAT:
w_byte(TYPE_FLOAT, arg);
w_float(RFLOAT(obj)->value, arg);
return;
case T_BIGNUM:
write_bignum:
w_byte(TYPE_BIGNUM, arg);
{
char sign = RBIGNUM(obj)->sign?'+':'-';
int len = RBIGNUM(obj)->len;
USHORT *d = RBIGNUM(obj)->digits;
w_byte(sign, arg);
w_long(len, arg);
while (len--) {
w_short(*d, arg);
d++;
}
}
return;
case T_STRING:
w_uclass(obj, cString, arg);
w_byte(TYPE_STRING, arg);
w_bytes(RSTRING(obj)->ptr, RSTRING(obj)->len, arg);
return;
case T_REGEXP:
w_uclass(obj, cRegexp, arg);
w_byte(TYPE_REGEXP, arg);
w_bytes(RREGEXP(obj)->str, RREGEXP(obj)->len, arg);
w_byte(FL_TEST(obj, FL_USER1), arg);
return;
case T_ARRAY:
w_uclass(obj, cArray, arg);
w_byte(TYPE_ARRAY, arg);
{
int len = RARRAY(obj)->len;
VALUE *ptr = RARRAY(obj)->ptr;
w_long(len, arg);
while (len--) {
w_object(*ptr, arg, limit);
ptr++;
}
}
break;
case T_HASH:
w_uclass(obj, cHash, arg);
w_byte(TYPE_HASH, arg);
w_long(RHASH(obj)->tbl->num_entries, arg);
st_foreach(RHASH(obj)->tbl, hash_each, &c_arg);
break;
case T_STRUCT:
w_byte(TYPE_STRUCT, arg);
{
int len = RSTRUCT(obj)->len;
char *path = rb_class2name(CLASS_OF(obj));
VALUE mem;
int i;
w_unique(path, arg);
w_long(len, arg);
mem = rb_ivar_get(CLASS_OF(obj), rb_intern("__member__"));
if (mem == Qnil) {
Fatal("non-initialized struct");
}
for (i=0; i<len; i++) {
w_symbol(FIX2INT(RARRAY(mem)->ptr[i]), arg);
w_object(RSTRUCT(obj)->ptr[i], arg, limit);
}
}
break;
case T_OBJECT:
w_byte(TYPE_OBJECT, arg);
{
VALUE class = CLASS_OF(obj);
char *path;
if (FL_TEST(class, FL_SINGLETON)) {
TypeError("singleton can't be dumped");
}
path = rb_class2name(class);
w_unique(path, arg);
if (ROBJECT(obj)->iv_tbl) {
w_long(ROBJECT(obj)->iv_tbl->num_entries, arg);
st_foreach(ROBJECT(obj)->iv_tbl, obj_each, &c_arg);
}
else {
w_long(0, arg);
}
}
break;
default:
TypeError("can't dump %s", rb_class2name(CLASS_OF(obj)));
break;
}
}
}
static VALUE
dump(arg)
struct dump_call_arg *arg;
{
w_object(arg->obj, arg->arg, arg->limit);
}
static VALUE
dump_ensure(arg)
struct dump_arg *arg;
{
st_free_table(arg->symbol);
st_free_table(arg->data);
}
static VALUE
marshal_dump(argc, argv)
int argc;
VALUE* argv;
{
VALUE obj, port, a1, a2;
int limit = -1;
extern VALUE cIO;
struct dump_arg arg;
struct dump_call_arg c_arg;
port = 0;
rb_scan_args(argc, argv, "12", &obj, &a1, &a2);
if (argc == 3) {
limit = NUM2INT(a2);
port = a1;
}
else if (argc == 2) {
if (FIXNUM_P(a1)) limit = FIX2INT(a1);
else port = a1;
}
if (port) {
if (obj_is_kind_of(port, cIO)) {
OpenFile *fptr;
io_binmode(port);
GetOpenFile(port, fptr);
io_writable(fptr);
arg.fp = (fptr->f2) ? fptr->f2 : fptr->f;
}
else {
TypeError("instance of IO needed");
}
}
else {
arg.fp = 0;
port = str_new(0, 0);
arg.str = port;
}
arg.symbol = st_init_numtable();
arg.data = st_init_numtable();
c_arg.obj = obj;
c_arg.arg = &arg;
c_arg.limit = limit;
w_byte(MARSHAL_MAJOR, &arg);
w_byte(MARSHAL_MINOR, &arg);
rb_ensure(dump, &c_arg, dump_ensure, &arg);
return port;
}
struct load_arg {
FILE *fp;
UCHAR *ptr, *end;
st_table *symbol;
st_table *data;
VALUE proc;
};
static int
r_byte(arg)
struct load_arg *arg;
{
if (arg->fp) return getc(arg->fp);
if (arg->ptr < arg->end) return *arg->ptr++;
return EOF;
}
static USHORT
r_short(arg)
struct load_arg *arg;
{
USHORT x;
int i;
x = 0;
for (i=0; i<sizeof(USHORT); i++) {
x |= r_byte(arg)<<(i*8);
}
return x;
}
static void
long_toobig(size)
int size;
{
TypeError("long too big for this architecture (size %d, given %d)",
sizeof(long), size);
}
static long
r_long(arg)
struct load_arg *arg;
{
int c = r_byte(arg), i;
register long x;
if (c == 0) return 0;
if (c > 0) {
if (c > sizeof(long)) long_toobig((int)c);
x = 0;
for (i=0;i<c;i++) {
x |= (long)r_byte(arg) << (8*i);
}
}
else if (c < 0) {
c = -c;
if (c > sizeof(long)) long_toobig((int)c);
x = -1;
for (i=0;i<c;i++) {
x &= ~(0xff << (8*i));
x |= (long)r_byte(arg) << (8*i);
}
}
return x;
}
#define r_bytes(s, arg) \
(s = (char*)r_long(arg), r_bytes0(&s,ALLOCA_N(char,(long)s),(long)s,arg))
static int
r_bytes0(sp, s, len, arg)
char **sp, *s;
int len;
struct load_arg *arg;
{
if (arg->fp) {
len = fread(s, 1, len, arg->fp);
}
else {
if (arg->ptr + len > arg->end) {
len = arg->end - arg->ptr;
}
memcpy(s, arg->ptr, len);
arg->ptr += len;
}
(s)[len] = '\0';
*sp = s;
return len;
}
static ID
r_symbol(arg)
struct load_arg *arg;
{
char *buf;
ID id;
char type;
if (r_byte(arg) == TYPE_SYMLINK) {
int num = r_long(arg);
if (st_lookup(arg->symbol, num, &id)) {
return id;
}
TypeError("bad symbol");
}
r_bytes(buf, arg);
id = rb_intern(buf);
st_insert(arg->symbol, arg->symbol->num_entries, id);
return id;
}
static char*
r_unique(arg)
struct load_arg *arg;
{
return rb_id2name(r_symbol(arg));
}
static VALUE
r_string(arg)
struct load_arg *arg;
{
char *buf;
int len = r_bytes(buf, arg);
return str_taint(str_new(buf, len));
}
static VALUE
r_regist(v, arg)
VALUE v;
struct load_arg *arg;
{
if (arg->proc) {
rb_funcall(arg->proc, rb_intern("call"), 1, v);
}
st_insert(arg->data, arg->data->num_entries, v);
return v;
}
static VALUE
r_object(arg)
struct load_arg *arg;
{
VALUE v;
int type = r_byte(arg);
switch (type) {
case EOF:
eof_error();
return Qnil;
case TYPE_LINK:
if (st_lookup(arg->data, r_long(arg), &v)) {
return v;
}
ArgError("dump format error (unlinked)");
break;
case TYPE_UCLASS:
{
VALUE c = rb_path2class(r_unique(arg));
v = r_object(arg);
if (rb_special_const_p(v)) {
ArgError("dump format error (user class)");
}
RBASIC(v)->class = c;
return v;
}
case TYPE_NIL:
return Qnil;
case TYPE_TRUE:
return TRUE;
case TYPE_FALSE:
return FALSE;
case TYPE_FIXNUM:
{
int i = r_long(arg);
return INT2FIX(i);
}
case TYPE_FLOAT:
{
#ifndef atof
double atof();
#endif
char *buf;
r_bytes(buf, arg);
v = float_new(atof(buf));
return r_regist(v, arg);
}
case TYPE_BIGNUM:
{
int len;
USHORT *digits;
NEWOBJ(big, struct RBignum);
OBJSETUP(big, cBignum, T_BIGNUM);
big->sign = (r_byte(arg) == '+');
big->len = len = r_long(arg);
big->digits = digits = ALLOC_N(USHORT, len);
while (len--) {
*digits++ = r_short(arg);
}
big = RBIGNUM(big_norm((VALUE)big));
if (TYPE(big) == T_BIGNUM) {
r_regist(big, arg);
}
return (VALUE)big;
}
case TYPE_STRING:
return r_regist(r_string(arg), arg);
case TYPE_REGEXP:
{
char *buf;
int len = r_bytes(buf, arg);
int ci = r_byte(arg);
return r_regist(reg_new(buf, len, ci), arg);
}
case TYPE_ARRAY:
{
volatile int len = r_long(arg);
v = ary_new2(len);
r_regist(v, arg);
while (len--) {
ary_push(v, r_object(arg));
}
return v;
}
case TYPE_HASH:
{
int len = r_long(arg);
v = hash_new();
r_regist(v, arg);
while (len--) {
VALUE key = r_object(arg);
VALUE value = r_object(arg);
hash_aset(v, key, value);
}
return v;
}
case TYPE_STRUCT:
{
VALUE class, mem, values;
volatile int i; /* gcc 2.7.2.3 -O2 bug?? */
int len;
ID slot;
class = rb_path2class(r_unique(arg));
mem = rb_ivar_get(class, rb_intern("__member__"));
if (mem == Qnil) {
Fatal("non-initialized struct");
}
len = r_long(arg);
values = ary_new2(len);
for (i=0; i<len; i++) {
ary_push(values, Qnil);
}
v = struct_alloc(class, values);
r_regist(v, arg);
for (i=0; i<len; i++) {
slot = r_symbol(arg);
if (RARRAY(mem)->ptr[i] != INT2FIX(slot)) {
TypeError("struct %s not compatible (:%s for :%s)",
rb_class2name(class),
rb_id2name(slot),
rb_id2name(FIX2INT(RARRAY(mem)->ptr[i])));
}
struct_aset(v, INT2FIX(i), r_object(arg));
}
return v;
}
break;
case TYPE_USERDEF:
{
VALUE class;
int len;
class = rb_path2class(r_unique(arg));
if (rb_respond_to(class, s_load)) {
v = rb_funcall(class, s_load, 1, r_string(arg));
return r_regist(v, arg);
}
TypeError("class %s needs to have method `_load_from'",
rb_class2name(class));
}
break;
case TYPE_OBJECT:
{
VALUE class;
int len;
class = rb_path2class(r_unique(arg));
len = r_long(arg);
v = obj_alloc(class);
r_regist(v, arg);
if (len > 0) {
while (len--) {
ID id = r_symbol(arg);
VALUE val = r_object(arg);
rb_ivar_set(v, id, val);
}
}
return v;
}
break;
case TYPE_MODULE:
{
char *buf;
r_bytes(buf, arg);
return rb_path2class(buf);
}
default:
ArgError("dump format error(0x%x)", type);
break;
}
}
static VALUE
load(arg)
struct load_arg *arg;
{
return r_object(arg);
}
static VALUE
load_ensure(arg)
struct load_arg *arg;
{
st_free_table(arg->symbol);
st_free_table(arg->data);
}
static VALUE
marshal_load(argc, argv)
int argc;
VALUE *argv;
{
VALUE port, proc;
FILE *fp;
int major;
VALUE v;
OpenFile *fptr;
struct load_arg arg;
rb_scan_args(argc, argv, "11", &port, &proc);
if (TYPE(port) == T_STRING) {
arg.fp = 0;
arg.ptr = RSTRING(port)->ptr;
arg.end = arg.ptr + RSTRING(port)->len;
}
else {
if (obj_is_kind_of(port, cIO)) {
io_binmode(port);
GetOpenFile(port, fptr);
io_readable(fptr);
arg.fp = fptr->f;
}
else {
TypeError("instance of IO needed");
}
}
major = r_byte(&arg);
if (major == MARSHAL_MAJOR) {
if (r_byte(&arg) != MARSHAL_MINOR) {
Warning("Old marshal file format (can be read)");
}
arg.symbol = st_init_numtable();
arg.data = st_init_numtable();
if (NIL_P(proc)) arg.proc = 0;
else arg.proc = proc;
v = rb_ensure(load, &arg, load_ensure, &arg);
}
else {
TypeError("Old marshal file format (can't read)");
}
return v;
}
Init_marshal()
{
VALUE mMarshal = rb_define_module("Marshal");
s_dump = rb_intern("_dump_to");
s_load = rb_intern("_load_from");
rb_define_module_function(mMarshal, "dump", marshal_dump, -1);
rb_define_module_function(mMarshal, "load", marshal_load, -1);
rb_define_module_function(mMarshal, "restore", marshal_load, 1);
rb_provide("marshal.o"); /* for backward compatibility */
}

77
mkconfig.rb Normal file
View File

@ -0,0 +1,77 @@
#!./miniruby
require File.dirname($0)+"/lib/ftools"
rbconfig_rb = ARGV[0] || 'rbconfig.rb'
File.makedirs(File.dirname(rbconfig_rb), true)
version = VERSION
config = open(rbconfig_rb, "w")
$stdout.reopen(config)
fast = {'prefix'=>TRUE, 'INSTALL'=>TRUE, 'binsuffix'=>TRUE}
print %[
module Config
VERSION == "#{version}" or
raise "ruby lib version (#{version}) doesn't match executable version (\#{VERSION})"
# This file was created by configrb when ruby was built. Any changes
# made to this file will be lost the next time ruby is built.
]
print " CONFIG = {}\n"
v_fast = []
v_others = []
File.foreach "config.status" do |$_|
next if /^#/
if /^s%@program_transform_name@%s,(.*)%g$/
ptn = $1.sub(/\$\$/, '$').split(/,/)
v_fast << " CONFIG[\"ruby_install_name\"] = \"" + "ruby".sub(ptn[0],ptn[1]) + "\"\n"
elsif /^s%@(\w+)@%(.*)%g/
name = $1
val = $2 || ""
next if name =~ /^(INSTALL|DEFS|configure_input|srcdir|top_srcdir)$/
v = " CONFIG[\"" + name + "\"] = " +
val.sub(/^\s*(.*)\s*$/, '"\1"').gsub(/\$\{?([^}]*)\}?/) {
"\#{CONFIG[\\\"#{$1}\\\"]}"
} + "\n"
if fast[name]
v_fast << v
else
v_others << v
end
if /DEFS/
val.split(/\s*-D/).each do |i|
if i =~ /(.*)=(\\")?([^\\]*)(\\")?/
key, val = $1, $3
if val == '1'
val = "TRUE"
else
val.sub! /^\s*(.*)\s*$/, '"\1"'
end
print " CONFIG[\"#{key}\"] = #{val}\n"
end
end
end
elsif /^ac_given_srcdir=(.*)/
path = $1
cwd = Dir.pwd
begin
Dir.chdir path
v_fast << " CONFIG[\"srcdir\"] = \"" + Dir.pwd + "\"\n"
ensure
Dir.chdir cwd
end
elsif /^ac_given_INSTALL=(.*)/
v_fast << " CONFIG[\"INSTALL\"] = " + $1 + "\n"
end
# break if /^CEOF/
end
print v_fast, v_others
Dir.chdir File.dirname($0)
print " CONFIG[\"compile_dir\"] = \"#{Dir.pwd}\"\n"
print "end\n"
config.close
# vi:set sw=2:

14
rubytest.rb Normal file
View File

@ -0,0 +1,14 @@
require 'rbconfig'
include Config
$stderr.reopen($stdout)
error = ''
`./ruby #{CONFIG["srcdir"]}/sample/test.rb`.each do |line|
if line =~ /^end of test/
print "test succeeded\n"
exit 0
end
error << line if line =~ %r:^(sample/test.rb|not):
end
print error
print "test failed\n"

36
sample/cbreak.rb Normal file
View File

@ -0,0 +1,36 @@
# ioctl example works on Sun
CBREAK = 0x00000002
ECHO = 0x00000008
TIOCGETP = 0x40067408
TIOCSETP = 0x80067409
def cbreak ()
set_cbreak(TRUE)
end
def cooked ()
set_cbreak(FALSE)
end
def set_cbreak (on)
tty = "\0" * 256
STDIN.ioctl(TIOCGETP, tty)
ttys = tty.unpack("C4 S")
if on
ttys[4] |= CBREAK
ttys[4] &= ~ECHO
else
ttys[4] &= ~CBREAK
ttys[4] |= ECHO
end
tty = ttys.pack("C4 S")
STDIN.ioctl(TIOCSETP, tty)
end
cbreak();
print("this is no-echo line: ");
readline().print
cooked();
print("this is echo line: ");
readline()

962
sample/rbc.rb Normal file
View File

@ -0,0 +1,962 @@
#!/usr/local/bin/ruby
#
# rbc.rb -
# $Release Version: 0.6 $
# $Revision: 1.2 $
# $Date: 1997/11/27 13:46:06 $
# by Keiju ISHITSUKA(Nippon Rational Inc.)
#
# --
# Usage:
#
# rbc.rb [options] file_name opts
# options:
# -d デバッグモード(利用しない方が良いでしょう)
# -m bcモード(分数, 行列の計算ができます)
# -r load-module ruby -r と同じ
# --inspect 結果出力にinspectを用いる(bcモード以外はデ
# フォルト).
# --noinspect 結果出力にinspectを用いない.
# --noreadline readlineライブラリを利用しない(デフォルト
# ではreadlineライブラリを利用しようとする).
#
# 追加 private method:
# exit, quit 終了する.
# inspect(sw = nil) インスペクトモードのトグル
# trace_load(sw = nil) load/require時にrbcのfile読み込み機能を用
# いるモードのスイッチ(デフォルトはトレース
# モード)
#
require "e2mmap.rb"
$stdout.sync = TRUE
module BC_APPLICATION__
RCS_ID='-$Header: /home/keiju/var/src/var.lib/ruby/ruby/RCS/rbc.rb,v 1.2 1997/11/27 13:46:06 keiju Exp keiju $-'
extend Exception2MessageMapper
def_exception :UnrecognizedSwitch, "Unrecognized switch: %s"
$DEBUG = FALSE
$INSPECT = nil
CONFIG = {}
CONFIG[0] = $0
CONFIG[:USE_READLINE] = TRUE
CONFIG[:LOAD_MODULES] = []
CONFIG[:INSPECT] = nil
CONFIG[:TRACE_LOAD] = TRUE
while opt = ARGV.shift
case opt
when "-d"
$DEBUG = TRUE
when "-m"
CONFIG[:INSPECT] = FALSE if CONFIG[:INSPECT].nil?
require "mathn.rb"
include Math
when "-r"
opt = ARGV.shift
CONFIG[:LOAD_MODULES].push opt if opt
when "--inspect"
CONFIG[:INSPECT] = TRUE
when "--noinspect"
CONFIG[:INSPECT] = FALSE
when "--noreadline"
CONFIG[:USE_READLINE] = FALSE
when /^-/
# print UnrecognizedSwitch.inspect, "\n"
BC.fail UnrecognizedSwitch, opt
else
CONFIG[:USE_READLINE] = FALSE
$0 = opt
break
end
end
CONFIG[:INSPECT] = TRUE if CONFIG[:INSPECT].nil?
PROMPTi = "rbc%d> "
PROMPTs = "rbc%d%s "
PROMPTe = "rbc%d* "
class BC
def initialize
lex_init
end
def eval_input(io, cont, bind)
line = ''
@io = io
@ltype = nil
@quoted = nil
@indent = 0
@lex_state = EXPR_BEG
@io.prompt = format(PROMPTi, @indent)
loop do
@continue = FALSE
l = @io.gets
unless l
break if line == ''
else
line = line + l
lex(l) if l != "\n"
print @quoted.inspect, "\n" if $DEBUG
if @ltype
@io.prompt = format(PROMPTs, @indent, @ltype)
next
elsif @continue
@io.prompt = format(PROMPTe, @indent)
next
elsif @indent > 0
@io.prompt = format(PROMPTi, @indent)
next
end
end
if line != "\n"
begin
if CONFIG[:INSPECT]
print (cont._=eval(line, bind)).inspect, "\n"
else
print (cont._=eval(line, bind)), "\n"
end
rescue
# $! = 'exception raised' unless $!
# print "ERR: ", $!, "\n"
$! = RuntimeError.new("exception raised") unless $!
print $!.type, ": ", $!, "\n"
end
end
break if not l
line = ''
indent = 0
@io.prompt = format(PROMPTi, indent)
end
print "\n"
end
EXPR_BEG = :EXPR_BEG
EXPR_MID = :EXPR_MID
EXPR_END = :EXPR_END
EXPR_ARG = :EXPR_ARG
EXPR_FNAME = :EXPR_FNAME
CLAUSE_STATE_TRANS = {
"alias" => EXPR_FNAME,
"and" => EXPR_BEG,
"begin" => EXPR_BEG,
"case" => EXPR_BEG,
"class" => EXPR_BEG,
"def" => EXPR_FNAME,
"defined?" => EXPR_END,
"do" => EXPR_BEG,
"else" => EXPR_BEG,
"elsif" => EXPR_BEG,
"end" => EXPR_END,
"ensure" => EXPR_BEG,
"for" => EXPR_BEG,
"if" => EXPR_BEG,
"in" => EXPR_BEG,
"module" => EXPR_BEG,
"nil" => EXPR_END,
"not" => EXPR_BEG,
"or" => EXPR_BEG,
"rescue" => EXPR_MID,
"return" => EXPR_MID,
"self" => EXPR_END,
"super" => EXPR_END,
"then" => EXPR_BEG,
"undef" => EXPR_FNAME,
"unless" => EXPR_BEG,
"until" => EXPR_BEG,
"when" => EXPR_BEG,
"while" => EXPR_BEG,
"yield" => EXPR_END
}
ENINDENT_CLAUSE = [
"case", "class", "def", "do", "for", "if",
"module", "unless", "until", "while", "begin" #, "when"
]
DEINDENT_CLAUSE = ["end"]
PARCENT_LTYPE = {
"q" => "\'",
"Q" => "\"",
"x" => "\`",
"r" => "\/"
}
PARCENT_PAREN = {
"{" => "}",
"[" => "]",
"<" => ">",
"(" => ")"
}
def lex_init()
@OP = Trie.new
@OP.def_rules("\0", "\004", "\032"){}
@OP.def_rules(" ", "\t", "\f", "\r", "\13") do
@space_seen = TRUE
next
end
@OP.def_rule("#") do
|op, rests|
@ltype = "#"
identify_comment(rests)
end
@OP.def_rule("\n") do
print "\\n\n" if $DEBUG
if @lex_state == EXPR_BEG || @lex_state == EXPR_FNAME
@continue = TRUE
else
@lex_state = EXPR_BEG
end
end
@OP.def_rules("*", "*=", "**=", "**") {@lex_state = EXPR_BEG}
@OP.def_rules("!", "!=", "!~") {@lex_state = EXPR_BEG}
@OP.def_rules("=", "==", "===", "=~", "=>") {@lex_state = EXPR_BEG}
@OP.def_rules("<", "<=", "<=>", "<<", "<=") {@lex_state = EXPR_BEG}
@OP.def_rules(">", ">=", ">>", ">=") {@lex_state = EXPR_BEG}
@OP.def_rules("'", '"') do
|op, rests|
@ltype = op
@quoted = op
identify_string(rests)
end
@OP.def_rules("`") do
|op, rests|
if @lex_state != EXPR_FNAME
@ltype = op
@quoted = op
identify_string(rests)
end
end
@OP.def_rules('?') do
|op, rests|
@lex_state = EXPR_END
identify_question(rests)
end
@OP.def_rules("&", "&&", "&=", "|", "||", "|=") do
@lex_state = EXPR_BEG
end
@OP.def_rule("+@", proc{@lex_state == EXPR_FNAME}) {}
@OP.def_rule("-@", proc{@lex_state == EXPR_FNAME}) {}
@OP.def_rules("+=", "-=") {@lex_state = EXPR_BEG}
@OP.def_rules("+", "-") do
|op, rests|
if @lex_state == EXPR_ARG
if @space_seen and rests[0] =~ /[0-9]/
identify_number(rests)
else
@lex_state = EXPR_BEG
end
elsif @lex_state != EXPR_END and rests[0] =~ /[0-9]/
identify_number(rests)
else
@lex_state = EXPR_BEG
end
end
@OP.def_rule(".") do
|op, rests|
@lex_state = EXPR_BEG
if rests[0] =~ /[0-9]/
rests.unshift op
identify_number(rests)
end
end
@OP.def_rules("..", "...") {@lex_state = EXPR_BEG}
lex_int2
end
def lex_int2
@OP.def_rules("]", "}", ")") do
@lex_state = EXPR_END
@indent -= 1
end
@OP.def_rule(":") {}
@OP.def_rule("::") {@lex_state = EXPR_BEG}
@OP.def_rule("/") do
|op, rests|
if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
@ltype = op
@quoted = op
identify_string(rests)
elsif rests[0] == '='
rests.shift
@lex_state = EXPR_BEG
elsif @lex_state == EXPR_ARG and @space_seen and rests[0] =~ /\s/
@ltype = op
@quoted = op
identify_string(rests)
else
@lex_state = EXPR_BEG
end
end
@OP.def_rules("^", "^=") {@lex_state = EXPR_BEG}
@OP.def_rules(",", ";") {@lex_state = EXPR_BEG}
@OP.def_rule("~") {@lex_state = EXPR_BEG}
@OP.def_rule("~@", proc{@lex_state = EXPR_FNAME}) {}
@OP.def_rule("(") do
@lex_state = EXPR_BEG
@indent += 1
end
@OP.def_rule("[]", proc{@lex_state == EXPR_FNAME}) {}
@OP.def_rule("[]=", proc{@lex_state == EXPR_FNAME}) {}
@OP.def_rule("[") do
@indent += 1
if @lex_state != EXPR_FNAME
@lex_state = EXPR_BEG
end
end
@OP.def_rule("{") do
@lex_state = EXPR_BEG
@indent += 1
end
@OP.def_rule('\\') {|op, rests| identify_escape(rests)} #')
@OP.def_rule('%') do
|op, rests|
if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
identify_quotation(rests)
elsif rests[0] == '='
rests.shift
elsif @lex_state == EXPR_ARG and @space_seen and rests[0] =~ /\s/
identify_quotation(rests)
else
@lex_state = EXPR_BEG
end
end
@OP.def_rule('$') do
|op, rests|
identify_gvar(rests)
end
@OP.def_rule('@') do
|op, rests|
if rests[0] =~ /[\w_]/
rests.unshift op
identify_identifier(rests)
end
end
@OP.def_rule("") do
|op, rests|
printf "match: start %s: %s", op, rests.inspect if $DEBUG
if rests[0] =~ /[0-9]/
identify_number(rests)
elsif rests[0] =~ /[\w_]/
identify_identifier(rests)
end
printf "match: end %s: %s", op, rests.inspect if $DEBUG
end
end
def lex(l)
chrs = l.split(//)
tokens = []
case @ltype
when "'", '"', '`', '/'
identify_string(chrs)
return if chrs.empty?
when "#"
identify_comment(chrs)
return
when "="
if l =~ /^=end/
$ltype = nil
return
end
else
if l =~ /^=begin/
$ltype = "="
return
end
end
until chrs.empty?
@space_seen = FALSE
printf "perse: %s\n", chrs.join("") if $DEBUG
@OP.match(chrs)
printf "lex_state: %s continue: %s\n", @lex_state.id2name, @continue if $DEBUG
end
end
def identify_gvar(chrs)
@lex_state = EXPR_END
ch = chrs.shift
case ch
when /[_~*$?!@/\\;,.=:<>"]/ #"
return
when "-"
ch = chrs.shift
return
when "&", "`", "'", "+"
return
when /[1-9]/
chrs.unshift ch
v = "$"
while (ch = chrs.shift) =~ /[0-9]/
end
chrs.unshift ch
return
when /\w/
chrs.unshift ch
chrs.unshift "$"
identify_identifier(chrs)
return
else
chrs.unshift ch
return
end
end
def identify_identifier(chrs)
token = ""
token.concat chrs.shift if chrs[0] =~ /[$@]/
while (ch = chrs.shift) =~ /\w|_/
print ":", ch, ":" if $DEBUG
token.concat ch
end
chrs.unshift ch
if ch == "!" or ch == "?"
chrs.shift
token.concat ch
end
# fix token
if token =~ /^[$@]/
@lex_state = EXPR_END
return
end
print token, "\n" if $DEBUG
if state = CLAUSE_STATE_TRANS[token]
if @lex_state != EXPR_BEG and token =~ /^(if|unless|while|until)/
# 修飾子
else
if ENINDENT_CLAUSE.include?(token)
@indent += 1
elsif DEINDENT_CLAUSE.include?(token)
@indent -= 1
end
end
@lex_state = state
return
end
if @lex_state == EXPR_FNAME
@lex_state = EXPR_END
if chrs[0] == '='
chrs.shift
end
elsif @lex_state == EXPR_BEG
@lex_state = EXPR_ARG
else
@lex_state = EXPR_END
end
end
def identify_quotation(chrs)
ch = chrs.shift
if lt = PARCENT_LTYPE[ch]
ch = chrs.shift
else
lt = "\""
end
if ch !~ /\W/
chrs.unshift ch
next
end
@ltype = lt
unless @quoted = PARCENT_PAREN[ch]
@quoted = ch
end
identify_string(chrs)
end
def identify_number(chrs)
@lex_state = EXPR_END
ch = chrs.shift
case ch
when /0/
if (ch = chrs[0]) == "x"
chrs.shift
match = /[0-9a-f_]/
else
match = /[0-7_]/
end
while ch = chrs.shift
if ch !~ match
chrs.unshift ch
break
end
end
return
end
while ch = chrs.shift
case ch
when /[0-9]/
when "e", "E"
# type = FLOAT
unless (ch = chrs.shift) == "+" or ch == "-"
chrs.unshift ch
end
when "."
# type = FLOAT
when "_"
else
chrs.unshift ch
return
end
end
end
def identify_question(chrs)
@lex_state = EXPR_END
if chrs.shift == "\\" #"
identify_escape(chrs)
end
end
def identify_string(chrs)
while ch = chrs.shift
if @quoted == ch
if @ltype == "/"
if chrs[0] =~ /i|o|n|e|s/
chrs.shift
end
end
@ltype = nil
@quoted = nil
@lex_state = EXPR_END
break
elsif ch == '\\' #'
identify_escape(chrs)
end
end
end
def identify_comment(chrs)
while ch = chrs.shift
if ch == "\\" #"
identify_escape(chrs)
end
if ch == "\n"
@ltype = nil
chrs.unshift ch
break
end
end
end
def identify_escape(chrs)
ch = chrs.shift
case ch
when "\n", "\r", "\f"
@continue = TRUE
when "\\", "n", "t", "r", "f", "v", "a", "e", "b" #"
when /[0-7]/
chrs.unshift ch
3.times do
ch = chrs.shift
case ch
when /[0-7]/
when nil
break
else
chrs.unshift ch
break
end
end
when "x"
2.times do
ch = chrs.shift
case ch
when /[0-9a-fA-F]/
when nil
break
else
chrs.unshift ch
break
end
end
when "M"
if (ch = chrs.shift) != '-'
chrs.unshift ch
elsif (ch = chrs.shift) == "\\" #"
identify_escape(chrs)
end
return
when "C", "c", "^"
if ch == "C" and (ch = chrs.shift) != "-"
chrs.unshift ch
elsif (ch = chrs.shift) == "\\" #"
identify_escape(chrs)
end
return
end
end
end
class Trie
extend Exception2MessageMapper
def_exception :ErrNodeNothing, "node nothing"
def_exception :ErrNodeAlreadyExists, "node already exists"
class Node
# postprocがなければ抽象ード, nilじゃなければ具象ード
def initialize(preproc = nil, postproc = nil)
@Tree = {}
@preproc = preproc
@postproc = postproc
end
def preproc(p)
@preproc = p
end
def postproc(p)
@postproc = p
end
def search(chrs, opt = nil)
return self if chrs.empty?
ch = chrs.shift
if node = @Tree[ch]
node.search(chrs, opt)
else
if opt
chrs.unshift ch
self.create_subnode(chrs)
else
Trie.fail ErrNodeNothing
end
end
end
def create_subnode(chrs, preproc = nil, postproc = nil)
ch = chrs.shift
if node = @Tree[ch]
if chrs.empty?
Trie.fail ErrNodeAlreadyExists
else
node.create_subnode(chrs, preproc, postproc)
end
else
if chrs.empty?
node = Node.new(preproc, postproc)
else
node = Node.new
node.create_subnode(chrs, preproc, postproc)
end
@Tree[ch] = node
end
node
end
def match(chrs, op = "")
print "match: ", chrs, ":", op, "\n" if $DEBUG
if chrs.empty?
if @preproc.nil? || @preproc.call(op, chrs)
printf "op1: %s\n", op if $DEBUG
@postproc.call(op, chrs)
""
else
nil
end
else
ch = chrs.shift
if node = @Tree[ch]
if ret = node.match(chrs, op+ch)
return ch+ret
elsif @postproc and @preproc.nil? || @preproc.call(op, chrs)
chrs.unshift ch
printf "op2: %s\n", op if $DEBUG
@postproc.call(op, chrs)
return ""
else
chrs.unshift ch
return nil
end
else
if @postproc and @preproc.nil? || @preproc.call(op, chrs)
printf "op3: %s\n", op if $DEBUG
chrs.unshift ch
@postproc.call(op, chrs)
return ""
else
chrs.unshift ch
return nil
end
end
end
end
end
def initialize
@head = Node.new("")
end
def def_rule(token, preproc = nil, postproc = nil)
node = search(token, :CREATE)
# print node.inspect, "\n" if $DEBUG
node.preproc(preproc)
if iterator?
node.postproc(proc)
elsif postproc
node.postproc(postproc)
end
end
def def_rules(*tokens)
if iterator?
p = proc
end
for token in tokens
def_rule(token, nil, p)
end
end
def preporc(token)
node = search(token)
node.preproc proc
end
def postproc(token)
node = search(token)
node.postproc proc
end
def search(token, opt = nil)
@head.search(token.split(//), opt)
end
def match(token)
token = token.split(//) if token.kind_of?(String)
ret = @head.match(token)
printf "match end: %s:%s", ret, token.inspect if $DEBUG
ret
end
def inspect
format("<Trie: @head = %s>", @head.inspect)
end
end
if /^-tt(.*)$/ =~ ARGV[0]
# Tracer.on
case $1
when "1"
tr = Trie.new
print "0: ", tr.inspect, "\n"
tr.def_rule("=") {print "=\n"}
print "1: ", tr.inspect, "\n"
tr.def_rule("==") {print "==\n"}
print "2: ", tr.inspect, "\n"
print "case 1:\n"
print tr.match("="), "\n"
print "case 2:\n"
print tr.match("=="), "\n"
print "case 3:\n"
print tr.match("=>"), "\n"
when "2"
tr = Trie.new
print "0: ", tr.inspect, "\n"
tr.def_rule("=") {print "=\n"}
print "1: ", tr.inspect, "\n"
tr.def_rule("==", proc{FALSE}) {print "==\n"}
print "2: ", tr.inspect, "\n"
print "case 1:\n"
print tr.match("="), "\n"
print "case 2:\n"
print tr.match("=="), "\n"
print "case 3:\n"
print tr.match("=>"), "\n"
end
exit
end
module CONTEXT
def _=(value)
@_ = value
end
def _
@_
end
def quit
exit
end
def trace_load(opt = nil)
if opt
@Trace_require = opt
else
@Trace_require = !@Trace_require
end
print "Switch to load/require #{unless @Trace_require; ' non';end} trace mode.\n"
if @Trace_require
eval %{
class << self
alias load rbc_load
alias require rbc_require
end
}
else
eval %{
class << self
alias load rbc_load_org
alias require rbc_require_org
end
}
end
@Trace_require
end
alias rbc_load_org load
def rbc_load(file_name)
return true if load_sub(file_name)
raise LoadError, "No such file to load -- #{file_name}"
end
alias rbc_require_org require
def rbc_require(file_name)
rex = Regexp.new("#{Regexp.quote(file_name)}(\.o|\.rb)?")
return false if $".find{|f| f =~ rex}
case file_name
when /\.rb$/
if load_sub(file_name)
$:.push file_name
return true
end
when /\.(so|o|sl)$/
require_org(file_name)
end
if load_sub(f = file_name + ".rb")
$:.push f
end
require(file_name)
end
def load_sub(fn)
if fn =~ /^#{Regexp.quote(File::Separator)}/
return false unless File.exist?(fn)
BC.new.eval_input FileInputMethod.new(fn), self, CONFIG[:BIND]
return true
end
for path in $:
if File.exist?(f = File.join(path, fn))
BC.new.eval_input FileInputMethod.new(f), self, CONFIG[:BIND]
return true
end
end
return false
end
def inspect(opt = nil)
if opt
CONFIG[:INSPECT] = opt
else
CONFIG[:INSPECT] = !$INSPECT
end
print "Switch to#{unless $INSPECT; ' non';end} inspect mode.\n"
$INSPECT
end
def run
CONFIG[:BIND] = proc
if CONFIG[:TRACE_LOAD]
trace_load true
end
for m in CONFIG[:LOAD_MODULES]
begin
require m
rescue
print $@[0], ":", $!.type, ": ", $!, "\n"
end
end
if !$0.equal?(CONFIG[0])
io = FileInputMethod.new($0)
elsif defined? Readline
io = ReadlineInputMethod.new
else
io = StdioInputMethod.new
end
BC.new.eval_input io, self, CONFIG[:BIND]
end
end
class InputMethod
attr :prompt, TRUE
def gets
end
public :gets
end
class StdioInputMethod < InputMethod
def gets
print @prompt
$stdin.gets
end
end
class FileInputMethod < InputMethod
def initialize(file)
@io = open(file)
end
def gets
l = @io.gets
print @prompt, l
l
end
end
if CONFIG[:USE_READLINE]
begin
require "readline"
print "use readline module\n"
class ReadlineInputMethod < InputMethod
include Readline
def gets
if l = readline(@prompt, TRUE)
l + "\n"
else
l
end
end
end
rescue
CONFIG[:USE_READLINE] = FALSE
end
end
end
extend BC_APPLICATION__::CONTEXT
run{}

981
win32/sdbm.c Normal file
View File

@ -0,0 +1,981 @@
/*
* sdbm - ndbm work-alike hashed database library
* based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
* author: oz@nexus.yorku.ca
* status: public domain.
*
* core routines
*/
#ifndef lint
/*char sdbm_rcsid[] = "$Id: sdbm.c,v 1.16 90/12/13 13:01:31 oz Exp $";*/
#endif
#include "sdbm.h"
/*#include "tune.h"*/
/*
* sdbm - ndbm work-alike hashed database library
* tuning and portability constructs [not nearly enough]
* author: oz@nexus.yorku.ca
*/
#define BYTESIZ 8
#ifdef SVID
#include <unistd.h>
#endif
#ifdef __GO32__
#include <unistd.h>
#endif
#ifdef BSD42
#define SEEK_SET L_SET
#define memset(s,c,n) bzero(s, n) /* only when c is zero */
#define memcpy(s1,s2,n) bcopy(s2, s1, n)
#define memcmp(s1,s2,n) bcmp(s1,s2,n)
#endif
/*
* important tuning parms (hah)
*/
#define SEEDUPS /* always detect duplicates */
#define BADMESS /* generate a message for worst case:
cannot make room after SPLTMAX splits */
/*
* misc
*/
#ifdef DEBUG
#define debug(x) printf x
#else
#define debug(x)
#endif
#ifdef BIG_E
#define GET_SHORT(p, i) (((unsigned)((unsigned char *)(p))[(i)*2] << 8) + (((unsigned char *)(p))[(i)*2 + 1]))
#define PUT_SHORT(p, i, s) (((unsigned char *)(p))[(i)*2] = (unsigned char)((s) >> 8), ((unsigned char *)(p))[(i)*2 + 1] = (unsigned char)(s))
#else
#define GET_SHORT(p, i) ((p)[i])
#define PUT_SHORT(p, i, s) ((p)[i] = (s))
#endif
/*#include "pair.h"*/
static int fitpair proto((char *, int));
static void putpair proto((char *, datum, datum));
static datum getpair proto((char *, datum));
static int delpair proto((char *, datum));
static int chkpage proto((char *));
static datum getnkey proto((char *, int));
static void splpage proto((char *, char *, long));
#ifdef SEEDUPS
static int duppair proto((char *, datum));
#endif
#ifdef MSDOS
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifdef BSD42
#include <sys/file.h>
#else
#include <fcntl.h>
/*#include <memory.h>*/
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
#include <errno.h>
#ifndef EPERM
#define EPERM EACCES
#endif
#include <string.h>
#ifdef __STDC__
#include <stddef.h>
#endif
#ifndef NULL
#define NULL 0
#endif
/*
* externals
*/
#ifndef sun
#ifndef MSDOS
extern int errno;
#endif
#endif
/*
* forward
*/
static int getdbit proto((DBM *, long));
static int setdbit proto((DBM *, long));
static int getpage proto((DBM *, long));
static datum getnext proto((DBM *));
static int makroom proto((DBM *, long, int));
/*
* useful macros
*/
#define bad(x) ((x).dptr == NULL || (x).dsize < 0)
#define exhash(item) dbm_hash((item).dptr, (item).dsize)
#define ioerr(db) ((db)->flags |= DBM_IOERR)
#define OFF_PAG(off) (long) (off) * PBLKSIZ
#define OFF_DIR(off) (long) (off) * DBLKSIZ
static long masks[] = {
000000000000L, 000000000001L, 000000000003L,
000000000007L, 000000000017L, 000000000037L,
000000000077L, 000000000177L, 000000000377L,
000000000777L, 000000001777L, 000000003777L,
000000007777L, 000000017777L, 000000037777L,
000000077777L, 000000177777L, 000000377777L,
000000777777L, 000001777777L, 000003777777L,
000007777777L, 000017777777L, 000037777777L,
000077777777L, 000177777777L, 000377777777L,
000777777777L, 001777777777L, 003777777777L,
007777777777L, 017777777777L
};
datum nullitem = {NULL, 0};
DBM *
dbm_open(file, flags, mode)
register char *file;
register int flags;
register int mode;
{
register DBM *db;
register char *dirname;
register char *pagname;
register int n;
if (file == NULL || !*file)
return errno = EINVAL, (DBM *) NULL;
/*
* need space for two seperate filenames
*/
n = strlen(file) * 2 + strlen(DIRFEXT) + strlen(PAGFEXT) + 2;
if ((dirname = malloc((unsigned) n)) == NULL)
return errno = ENOMEM, (DBM *) NULL;
/*
* build the file names
*/
dirname = strcat(strcpy(dirname, file), DIRFEXT);
pagname = strcpy(dirname + strlen(dirname) + 1, file);
pagname = strcat(pagname, PAGFEXT);
db = dbm_prep(dirname, pagname, flags, mode);
free((char *) dirname);
return db;
}
DBM *
dbm_prep(dirname, pagname, flags, mode)
char *dirname;
char *pagname;
int flags;
int mode;
{
register DBM *db;
struct stat dstat;
if ((db = (DBM *) malloc(sizeof(DBM))) == NULL)
return errno = ENOMEM, (DBM *) NULL;
db->flags = 0;
db->hmask = 0;
db->blkptr = 0;
db->keyptr = 0;
/*
* adjust user flags so that WRONLY becomes RDWR,
* as required by this package. Also set our internal
* flag for RDONLY.
*/
if (flags & O_WRONLY)
flags = (flags & ~O_WRONLY) | O_RDWR;
if (flags & O_RDONLY)
db->flags = DBM_RDONLY;
/*
* open the files in sequence, and stat the dirfile.
* If we fail anywhere, undo everything, return NULL.
*/
#ifdef MSDOS
flags |= O_BINARY;
#endif
if ((db->pagf = open(pagname, flags, mode)) > -1) {
if ((db->dirf = open(dirname, flags, mode)) > -1) {
/*
* need the dirfile size to establish max bit number.
*/
if (fstat(db->dirf, &dstat) == 0) {
/*
* zero size: either a fresh database, or one with a single,
* unsplit data page: dirpage is all zeros.
*/
db->dirbno = (!dstat.st_size) ? 0 : -1;
db->pagbno = -1;
db->maxbno = dstat.st_size * (long) BYTESIZ;
(void) memset(db->pagbuf, 0, PBLKSIZ);
(void) memset(db->dirbuf, 0, DBLKSIZ);
/*
* success
*/
return db;
}
(void) close(db->dirf);
}
(void) close(db->pagf);
}
free((char *) db);
return (DBM *) NULL;
}
void
dbm_close(db)
register DBM *db;
{
if (db == NULL)
errno = EINVAL;
else {
(void) close(db->dirf);
(void) close(db->pagf);
free((char *) db);
}
}
datum
dbm_fetch(db, key)
register DBM *db;
datum key;
{
if (db == NULL || bad(key))
return errno = EINVAL, nullitem;
if (getpage(db, exhash(key)))
return getpair(db->pagbuf, key);
return ioerr(db), nullitem;
}
int
dbm_delete(db, key)
register DBM *db;
datum key;
{
if (db == NULL || bad(key))
return errno = EINVAL, -1;
if (dbm_rdonly(db))
return errno = EPERM, -1;
if (getpage(db, exhash(key))) {
if (!delpair(db->pagbuf, key))
return -1;
/*
* update the page file
*/
if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0
|| write(db->pagf, db->pagbuf, PBLKSIZ) < 0)
return ioerr(db), -1;
return 0;
}
return ioerr(db), -1;
}
int
dbm_store(db, key, val, flags)
register DBM *db;
datum key;
datum val;
int flags;
{
int need;
register long hash;
if (db == NULL || bad(key))
return errno = EINVAL, -1;
if (dbm_rdonly(db))
return errno = EPERM, -1;
need = key.dsize + val.dsize;
/*
* is the pair too big (or too small) for this database ??
*/
if (need < 0 || need > PAIRMAX)
return errno = EINVAL, -1;
if (getpage(db, (hash = exhash(key)))) {
/*
* if we need to replace, delete the key/data pair
* first. If it is not there, ignore.
*/
if (flags == DBM_REPLACE)
(void) delpair(db->pagbuf, key);
#ifdef SEEDUPS
else if (duppair(db->pagbuf, key))
return 1;
#endif
/*
* if we do not have enough room, we have to split.
*/
if (!fitpair(db->pagbuf, need))
if (!makroom(db, hash, need))
return ioerr(db), -1;
/*
* we have enough room or split is successful. insert the key,
* and update the page file.
*/
(void) putpair(db->pagbuf, key, val);
if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0
|| write(db->pagf, db->pagbuf, PBLKSIZ) < 0)
return ioerr(db), -1;
/*
* success
*/
return 0;
}
return ioerr(db), -1;
}
/*
* makroom - make room by splitting the overfull page
* this routine will attempt to make room for SPLTMAX times before
* giving up.
*/
static int
makroom(db, hash, need)
register DBM *db;
long hash;
int need;
{
long newp;
char twin[PBLKSIZ];
#ifdef MSDOS
char zer[PBLKSIZ];
#endif
char *pag = db->pagbuf;
char *new = twin;
register int smax = SPLTMAX;
long oldtail;
do {
/*
* split the current page
*/
(void) splpage(pag, new, db->hmask + 1);
/*
* address of the new page
*/
newp = (hash & db->hmask) | (db->hmask + 1);
debug(("newp: %ld\n", newp));
/*
* write delay, read avoidence/cache shuffle:
* select the page for incoming pair: if key is to go to the new page,
* write out the previous one, and copy the new one over, thus making
* it the current page. If not, simply write the new page, and we are
* still looking at the page of interest. current page is not updated
* here, as dbm_store will do so, after it inserts the incoming pair.
*/
#ifdef MSDOS
/*
* Fill hole with 0 if made it.
* (hole is NOT read as 0)
*/
oldtail = lseek(db->pagf, 0L, SEEK_END);
memset(zer, 0, PBLKSIZ);
while (OFF_PAG(newp) > oldtail) {
if (lseek(db->pagf, 0L, SEEK_END) < 0 ||
write(db->pagf, zer, PBLKSIZ) < 0) {
return 0;
}
oldtail += PBLKSIZ;
}
#endif
if (hash & (db->hmask + 1)) {
if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0
|| write(db->pagf, db->pagbuf, PBLKSIZ) < 0)
return 0;
db->pagbno = newp;
(void) memcpy(pag, new, PBLKSIZ);
}
else if (lseek(db->pagf, OFF_PAG(newp), SEEK_SET) < 0
|| write(db->pagf, new, PBLKSIZ) < 0)
return 0;
if (!setdbit(db, db->curbit))
return 0;
/*
* see if we have enough room now
*/
if (fitpair(pag, need))
return 1;
/*
* try again... update curbit and hmask as getpage would have
* done. because of our update of the current page, we do not
* need to read in anything. BUT we have to write the current
* [deferred] page out, as the window of failure is too great.
*/
db->curbit = 2 * db->curbit +
((hash & (db->hmask + 1)) ? 2 : 1);
db->hmask |= (db->hmask + 1);
if (lseek(db->pagf, OFF_PAG(db->pagbno), SEEK_SET) < 0
|| write(db->pagf, db->pagbuf, PBLKSIZ) < 0)
return 0;
} while (--smax);
/*
* if we are here, this is real bad news. After SPLTMAX splits,
* we still cannot fit the key. say goodnight.
*/
#ifdef BADMESS
(void) write(2, "sdbm: cannot insert after SPLTMAX attempts.\n", 44);
#endif
return 0;
}
/*
* the following two routines will break if
* deletions aren't taken into account. (ndbm bug)
*/
datum
dbm_firstkey(db)
register DBM *db;
{
if (db == NULL)
return errno = EINVAL, nullitem;
/*
* start at page 0
*/
(void) memset(db->pagbuf, 0, PBLKSIZ);
if (lseek(db->pagf, OFF_PAG(0), SEEK_SET) < 0
|| read(db->pagf, db->pagbuf, PBLKSIZ) < 0)
return ioerr(db), nullitem;
db->pagbno = 0;
db->blkptr = 0;
db->keyptr = 0;
return getnext(db);
}
datum
dbm_nextkey(db)
register DBM *db;
{
if (db == NULL)
return errno = EINVAL, nullitem;
return getnext(db);
}
/*
* all important binary trie traversal
*/
static int
getpage(db, hash)
register DBM *db;
register long hash;
{
register int hbit;
register long dbit;
register long pagb;
dbit = 0;
hbit = 0;
while (dbit < db->maxbno && getdbit(db, dbit))
dbit = 2 * dbit + ((hash & ((long) 1 << hbit++)) ? 2 : 1);
debug(("dbit: %d...", dbit));
db->curbit = dbit;
db->hmask = masks[hbit];
pagb = hash & db->hmask;
/*
* see if the block we need is already in memory.
* note: this lookaside cache has about 10% hit rate.
*/
if (pagb != db->pagbno) {
/*
* note: here, we assume a "hole" is read as 0s.
* if not, must zero pagbuf first.
*/
(void) memset(db->pagbuf, 0, PBLKSIZ);
if (lseek(db->pagf, OFF_PAG(pagb), SEEK_SET) < 0
|| read(db->pagf, db->pagbuf, PBLKSIZ) < 0)
return 0;
if (!chkpage(db->pagbuf)) {
return 0;
}
db->pagbno = pagb;
debug(("pag read: %d\n", pagb));
}
return 1;
}
static int
getdbit(db, dbit)
register DBM *db;
register long dbit;
{
register long c;
register long dirb;
c = dbit / BYTESIZ;
dirb = c / DBLKSIZ;
if (dirb != db->dirbno) {
if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0
|| read(db->dirf, db->dirbuf, DBLKSIZ) < 0)
return 0;
db->dirbno = dirb;
debug(("dir read: %d\n", dirb));
}
return db->dirbuf[c % DBLKSIZ] & (1 << (dbit % BYTESIZ));
}
static int
setdbit(db, dbit)
register DBM *db;
register long dbit;
{
register long c;
register long dirb;
c = dbit / BYTESIZ;
dirb = c / DBLKSIZ;
if (dirb != db->dirbno) {
if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0
|| read(db->dirf, db->dirbuf, DBLKSIZ) < 0)
return 0;
db->dirbno = dirb;
debug(("dir read: %d\n", dirb));
}
db->dirbuf[c % DBLKSIZ] |= (1 << (dbit % BYTESIZ));
if (dbit >= db->maxbno)
db->maxbno += (long) DBLKSIZ * BYTESIZ;
if (lseek(db->dirf, OFF_DIR(dirb), SEEK_SET) < 0
|| write(db->dirf, db->dirbuf, DBLKSIZ) < 0)
return 0;
return 1;
}
/*
* getnext - get the next key in the page, and if done with
* the page, try the next page in sequence
*/
static datum
getnext(db)
register DBM *db;
{
datum key;
for (;;) {
db->keyptr++;
key = getnkey(db->pagbuf, db->keyptr);
if (key.dptr != NULL)
return key;
/*
* we either run out, or there is nothing on this page..
* try the next one... If we lost our position on the
* file, we will have to seek.
*/
db->keyptr = 0;
if (db->pagbno != db->blkptr++)
if (lseek(db->pagf, OFF_PAG(db->blkptr), SEEK_SET) < 0)
break;
db->pagbno = db->blkptr;
if (read(db->pagf, db->pagbuf, PBLKSIZ) <= 0)
break;
if (!chkpage(db->pagbuf)) {
break;
}
}
return ioerr(db), nullitem;
}
/* pair.c */
/*
* sdbm - ndbm work-alike hashed database library
* based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
* author: oz@nexus.yorku.ca
* status: public domain.
*
* page-level routines
*/
#ifndef lint
/*char pair_rcsid[] = "$Id: pair.c,v 1.10 90/12/13 13:00:35 oz Exp $";*/
#endif
#ifndef BSD42
/*#include <memory.h>*/
#endif
#define exhash(item) dbm_hash((item).dptr, (item).dsize)
/*
* forward
*/
static int seepair proto((char *, int, char *, int));
/*
* page format:
* +------------------------------+
* ino | n | keyoff | datoff | keyoff |
* +------------+--------+--------+
* | datoff | - - - ----> |
* +--------+---------------------+
* | F R E E A R E A |
* +--------------+---------------+
* | <---- - - - | data |
* +--------+-----+----+----------+
* | key | data | key |
* +--------+----------+----------+
*
* calculating the offsets for free area: if the number
* of entries (ino[0]) is zero, the offset to the END of
* the free area is the block size. Otherwise, it is the
* nth (ino[ino[0]]) entry's offset.
*/
static int
fitpair(pag, need)
char *pag;
int need;
{
register int n;
register int off;
register int free;
register short *ino = (short *) pag;
off = ((n = GET_SHORT(ino,0)) > 0) ? GET_SHORT(ino,n) : PBLKSIZ;
free = off - (n + 1) * sizeof(short);
need += 2 * sizeof(short);
debug(("free %d need %d\n", free, need));
return need <= free;
}
static void
putpair(pag, key, val)
char *pag;
datum key;
datum val;
{
register int n;
register int off;
register short *ino = (short *) pag;
off = ((n = GET_SHORT(ino,0)) > 0) ? GET_SHORT(ino,n) : PBLKSIZ;
/*
* enter the key first
*/
off -= key.dsize;
if (key.dsize)
(void) memcpy(pag + off, key.dptr, key.dsize);
PUT_SHORT(ino,n + 1,off);
/*
* now the data
*/
off -= val.dsize;
if (val.dsize)
(void) memcpy(pag + off, val.dptr, val.dsize);
PUT_SHORT(ino,n + 2,off);
/*
* adjust item count
*/
PUT_SHORT(ino,0,GET_SHORT(ino,0) + 2);
}
static datum
getpair(pag, key)
char *pag;
datum key;
{
register int i;
register int n;
datum val;
register short *ino = (short *) pag;
if ((n = GET_SHORT(ino,0)) == 0)
return nullitem;
if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0)
return nullitem;
val.dptr = pag + GET_SHORT(ino,i + 1);
val.dsize = GET_SHORT(ino,i) - GET_SHORT(ino,i + 1);
return val;
}
#ifdef SEEDUPS
static int
duppair(pag, key)
char *pag;
datum key;
{
register short *ino = (short *) pag;
return GET_SHORT(ino,0) > 0 &&
seepair(pag, GET_SHORT(ino,0), key.dptr, key.dsize) > 0;
}
#endif
static datum
getnkey(pag, num)
char *pag;
int num;
{
datum key;
register int off;
register short *ino = (short *) pag;
num = num * 2 - 1;
if (GET_SHORT(ino,0) == 0 || num > GET_SHORT(ino,0))
return nullitem;
off = (num > 1) ? GET_SHORT(ino,num - 1) : PBLKSIZ;
key.dptr = pag + GET_SHORT(ino,num);
key.dsize = off - GET_SHORT(ino,num);
return key;
}
static int
delpair(pag, key)
char *pag;
datum key;
{
register int n;
register int i;
register short *ino = (short *) pag;
if ((n = GET_SHORT(ino,0)) == 0)
return 0;
if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0)
return 0;
/*
* found the key. if it is the last entry
* [i.e. i == n - 1] we just adjust the entry count.
* hard case: move all data down onto the deleted pair,
* shift offsets onto deleted offsets, and adjust them.
* [note: 0 < i < n]
*/
if (i < n - 1) {
register int m;
register char *dst = pag + (i == 1 ? PBLKSIZ : GET_SHORT(ino,i - 1));
register char *src = pag + GET_SHORT(ino,i + 1);
register int zoo = dst - src;
debug(("free-up %d ", zoo));
/*
* shift data/keys down
*/
m = GET_SHORT(ino,i + 1) - GET_SHORT(ino,n);
#ifdef DUFF
#define MOVB *--dst = *--src
if (m > 0) {
register int loop = (m + 8 - 1) >> 3;
switch (m & (8 - 1)) {
case 0: do {
MOVB; case 7: MOVB;
case 6: MOVB; case 5: MOVB;
case 4: MOVB; case 3: MOVB;
case 2: MOVB; case 1: MOVB;
} while (--loop);
}
}
#else
#ifdef MEMMOVE
memmove(dst, src, m);
#else
while (m--)
*--dst = *--src;
#endif
#endif
/*
* adjust offset index up
*/
while (i < n - 1) {
PUT_SHORT(ino,i, GET_SHORT(ino,i + 2) + zoo);
i++;
}
}
PUT_SHORT(ino, 0, GET_SHORT(ino, 0) - 2);
return 1;
}
/*
* search for the key in the page.
* return offset index in the range 0 < i < n.
* return 0 if not found.
*/
static int
seepair(pag, n, key, siz)
char *pag;
register int n;
register char *key;
register int siz;
{
register int i;
register int off = PBLKSIZ;
register short *ino = (short *) pag;
for (i = 1; i < n; i += 2) {
if (siz == off - GET_SHORT(ino,i) &&
memcmp(key, pag + GET_SHORT(ino,i), siz) == 0)
return i;
off = GET_SHORT(ino,i + 1);
}
return 0;
}
static void
splpage(pag, new, sbit)
char *pag;
char *new;
long sbit;
{
datum key;
datum val;
register int n;
register int off = PBLKSIZ;
char cur[PBLKSIZ];
register short *ino = (short *) cur;
(void) memcpy(cur, pag, PBLKSIZ);
(void) memset(pag, 0, PBLKSIZ);
(void) memset(new, 0, PBLKSIZ);
n = GET_SHORT(ino,0);
for (ino++; n > 0; ino += 2) {
key.dptr = cur + GET_SHORT(ino,0);
key.dsize = off - GET_SHORT(ino,0);
val.dptr = cur + GET_SHORT(ino,1);
val.dsize = GET_SHORT(ino,0) - GET_SHORT(ino,1);
/*
* select the page pointer (by looking at sbit) and insert
*/
(void) putpair((exhash(key) & sbit) ? new : pag, key, val);
off = GET_SHORT(ino,1);
n -= 2;
}
debug(("%d split %d/%d\n", ((short *) cur)[0] / 2,
((short *) new)[0] / 2,
((short *) pag)[0] / 2));
}
/*
* check page sanity:
* number of entries should be something
* reasonable, and all offsets in the index should be in order.
* this could be made more rigorous.
*/
static int
chkpage(pag)
char *pag;
{
register int n;
register int off;
register short *ino = (short *) pag;
if ((n = GET_SHORT(ino,0)) < 0 || n > PBLKSIZ / sizeof(short))
return 0;
if (n > 0) {
off = PBLKSIZ;
for (ino++; n > 0; ino += 2) {
if (GET_SHORT(ino,0) > off || GET_SHORT(ino,1) > off ||
GET_SHORT(ino,1) > GET_SHORT(ino,0))
return 0;
off = GET_SHORT(ino,1);
n -= 2;
}
}
return 1;
}
/* hash.c */
/*
* sdbm - ndbm work-alike hashed database library
* based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
* author: oz@nexus.yorku.ca
* status: public domain. keep it that way.
*
* hashing routine
*/
/*
* polynomial conversion ignoring overflows
* [this seems to work remarkably well, in fact better
* then the ndbm hash function. Replace at your own risk]
* use: 65599 nice.
* 65587 even better.
*/
long
dbm_hash(str, len)
register char *str;
register int len;
{
register unsigned long n = 0;
#ifdef DUFF
#define HASHC n = *str++ + 65599 * n
if (len > 0) {
register int loop = (len + 8 - 1) >> 3;
switch(len & (8 - 1)) {
case 0: do {
HASHC; case 7: HASHC;
case 6: HASHC; case 5: HASHC;
case 4: HASHC; case 3: HASHC;
case 2: HASHC; case 1: HASHC;
} while (--loop);
}
}
#else
while (len--)
n = ((*str++) & 255) + 65587L * n;
#endif
return n;
}

84
win32/sdbm.h Normal file
View File

@ -0,0 +1,84 @@
/*
* sdbm - ndbm work-alike hashed database library
* based on Per-Ake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
* author: oz@nexus.yorku.ca
* status: public domain.
*/
#ifndef _NDBM_H_
#define _NDBM_H_
#define DBLKSIZ 4096
#define PBLKSIZ 1024
#define PAIRMAX 1008 /* arbitrary on PBLKSIZ-N */
#define SPLTMAX 10 /* maximum allowed splits */
/* for a single insertion */
#define DIRFEXT ".dir"
#define PAGFEXT ".pag"
typedef struct {
int dirf; /* directory file descriptor */
int pagf; /* page file descriptor */
int flags; /* status/error flags, see below */
long maxbno; /* size of dirfile in bits */
long curbit; /* current bit number */
long hmask; /* current hash mask */
long blkptr; /* current block for nextkey */
int keyptr; /* current key for nextkey */
long blkno; /* current page to read/write */
long pagbno; /* current page in pagbuf */
char pagbuf[PBLKSIZ]; /* page file block buffer */
long dirbno; /* current block in dirbuf */
char dirbuf[DBLKSIZ]; /* directory file block buffer */
} DBM;
#define DBM_RDONLY 0x1 /* data base open read-only */
#define DBM_IOERR 0x2 /* data base I/O error */
/*
* utility macros
*/
#define dbm_rdonly(db) ((db)->flags & DBM_RDONLY)
#define dbm_error(db) ((db)->flags & DBM_IOERR)
#define dbm_clearerr(db) ((db)->flags &= ~DBM_IOERR) /* ouch */
#define dbm_dirfno(db) ((db)->dirf)
#define dbm_pagfno(db) ((db)->pagf)
typedef struct {
char *dptr;
int dsize;
} datum;
extern datum nullitem;
#if defined(__STDC__) || defined(MSDOS)
#define proto(p) p
#else
#define proto(p) ()
#endif
/*
* flags to dbm_store
*/
#define DBM_INSERT 0
#define DBM_REPLACE 1
/*
* ndbm interface
*/
extern DBM *dbm_open proto((char *, int, int));
extern void dbm_close proto((DBM *));
extern datum dbm_fetch proto((DBM *, datum));
extern int dbm_delete proto((DBM *, datum));
extern int dbm_store proto((DBM *, datum, datum, int));
extern datum dbm_firstkey proto((DBM *));
extern datum dbm_nextkey proto((DBM *));
/*
* other
*/
extern DBM *dbm_prep proto((char *, char *, int, int));
extern long dbm_hash proto((char *, int));
#endif /* _NDBM_H_ */