summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/Setup1
-rw-r--r--ext/Win32API/MANIFEST7
-rw-r--r--ext/Win32API/Win32API.c223
-rw-r--r--ext/Win32API/extconf.rb7
-rw-r--r--ext/Win32API/getch.rb5
-rw-r--r--ext/Win32API/point.rb18
-rw-r--r--ext/aix_ld.rb2
-rw-r--r--ext/curses/curses.c107
-rw-r--r--ext/curses/extconf.rb5
-rw-r--r--ext/curses/hello.rb4
-rw-r--r--ext/curses/view.rb1
-rw-r--r--ext/cygwin32_ld.rb90
-rw-r--r--ext/dbm/dbm.c175
-rw-r--r--ext/dbm/extconf.rb6
-rw-r--r--ext/etc/etc.c91
-rw-r--r--ext/etc/extconf.rb24
-rw-r--r--ext/extmk.rb.in235
-rw-r--r--ext/extmk.rb.nt6
-rw-r--r--ext/fcntl/fcntl.c2
-rw-r--r--ext/kconv/kconv.c89
-rw-r--r--ext/md5/md5init.c14
-rw-r--r--ext/socket/depend2
-rw-r--r--ext/socket/extconf.rb12
-rw-r--r--ext/socket/socket.c829
-rw-r--r--ext/tcltklib/extconf.rb114
-rw-r--r--ext/tcltklib/lib/tcltk.rb287
-rw-r--r--ext/tcltklib/tcltklib.c293
-rw-r--r--ext/tk/MANIFEST25
-rw-r--r--ext/tk/depend1
-rw-r--r--ext/tk/extconf.rb2
-rw-r--r--ext/tk/lib/tk.rb2499
-rw-r--r--ext/tk/lib/tkafter.rb296
-rw-r--r--ext/tk/lib/tkbgerror.rb17
-rw-r--r--ext/tk/lib/tkcanvas.rb829
-rw-r--r--ext/tk/lib/tkclass.rb38
-rw-r--r--ext/tk/lib/tkdialog.rb141
-rw-r--r--ext/tk/lib/tkentry.rb73
-rw-r--r--ext/tk/lib/tkfont.rb944
-rw-r--r--ext/tk/lib/tkmenubar.rb137
-rw-r--r--ext/tk/lib/tkmngfocus.rb27
-rw-r--r--ext/tk/lib/tkpalette.rb48
-rw-r--r--ext/tk/lib/tkscrollbox.rb27
-rw-r--r--ext/tk/lib/tktext.rb797
-rw-r--r--ext/tk/lib/tkvirtevent.rb66
-rw-r--r--ext/tk/sample/tkbiff.rb149
-rw-r--r--ext/tk/sample/tkbrowse.rb79
-rw-r--r--ext/tk/sample/tkdialog.rb62
-rw-r--r--ext/tk/sample/tkfrom.rb132
-rw-r--r--ext/tk/sample/tkhello.rb10
-rw-r--r--ext/tk/sample/tkline.rb45
-rw-r--r--ext/tk/sample/tktimer.rb50
-rw-r--r--ext/tk/tkutil.c45
52 files changed, 8369 insertions, 819 deletions
diff --git a/ext/Setup b/ext/Setup
index c92ac53e00..9e3a2474c3 100644
--- a/ext/Setup
+++ b/ext/Setup
@@ -10,3 +10,4 @@
#socket
#tkutil
#tcltklib
+#gtk
diff --git a/ext/Win32API/MANIFEST b/ext/Win32API/MANIFEST
new file mode 100644
index 0000000000..7cc9ac445e
--- /dev/null
+++ b/ext/Win32API/MANIFEST
@@ -0,0 +1,7 @@
+MANIFEST
+depend
+MANIFEST
+Win32API.c
+extconf.rb
+getch.rb
+point.rb
diff --git a/ext/Win32API/Win32API.c b/ext/Win32API/Win32API.c
new file mode 100644
index 0000000000..f4cb5c726f
--- /dev/null
+++ b/ext/Win32API/Win32API.c
@@ -0,0 +1,223 @@
+/*
+ Win32API - Ruby Win32 API Import Facility
+*/
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <stdio.h>
+
+#define _T_VOID 0
+#define _T_NUMBER 1
+#define _T_POINTER 2
+#define _T_INTEGER 3
+
+typedef char *ApiPointer(void);
+typedef long ApiNumber(void);
+typedef void ApiVoid(void);
+typedef int ApiInteger(void);
+
+#include "ruby.h"
+
+typedef struct {
+ HANDLE dll;
+ HANDLE proc;
+ VALUE dllname;
+ VALUE import;
+ VALUE export;
+} Win32API;
+
+static void
+Win32API_FreeLibrary(hdll)
+ HINSTANCE hdll;
+{
+ FreeLibrary(hdll);
+}
+
+static VALUE
+Win32API_initialize(self, dllname, proc, import, export)
+ VALUE self;
+ VALUE dllname;
+ VALUE proc;
+ VALUE import;
+ VALUE export;
+{
+ HANDLE hproc;
+ HINSTANCE hdll;
+ VALUE str;
+ VALUE a_import;
+ VALUE *ptr;
+ int i;
+ int len;
+ int ex;
+
+ hdll = GetModuleHandle(RSTRING(dllname)->ptr);
+ if (!hdll) {
+ hdll = LoadLibrary(RSTRING(dllname)->ptr);
+ if (!hdll)
+ Fail("LoadLibrary: %s\n", RSTRING(dllname)->ptr);
+ Data_Wrap_Struct(self, 0, Win32API_FreeLibrary, hdll);
+ }
+ hproc = GetProcAddress(hdll, RSTRING(proc)->ptr);
+ if (!hproc) {
+ str = str_new3(proc);
+ str = str_cat(str, "A", 1);
+ hproc = GetProcAddress(hdll, RSTRING(str)->ptr);
+ if (!hproc)
+ Fail("GetProcAddress: %s or %s\n",
+ RSTRING(proc)->ptr, RSTRING(str)->ptr);
+ }
+ rb_iv_set(self, "__dll__", INT2NUM((int)hdll));
+ rb_iv_set(self, "__dllname__", dllname);
+ rb_iv_set(self, "__proc__", INT2NUM((int)hproc));
+
+ a_import = ary_new();
+ ptr = RARRAY(import)->ptr;
+ for (i = 0, len = RARRAY(import)->len; i < len; i++) {
+ int c = *(char *)RSTRING(ptr[i])->ptr;
+ switch (c) {
+ case 'N': case 'n': case 'L': case 'l':
+ ary_push(a_import, INT2FIX(_T_NUMBER));
+ break;
+ case 'P': case 'p':
+ ary_push(a_import, INT2FIX(_T_POINTER));
+ break;
+ case 'I': case 'i':
+ ary_push(a_import, INT2FIX(_T_INTEGER));
+ break;
+ }
+ }
+ rb_iv_set(self, "__import__", a_import);
+
+ switch (*RSTRING(export)->ptr) {
+ case 'V': case 'v':
+ ex = _T_VOID;
+ break;
+ case 'N': case 'n': case 'L': case 'l':
+ ex = _T_NUMBER;
+ break;
+ case 'P': case 'p':
+ ex = _T_POINTER;
+ break;
+ case 'I': case 'i':
+ ex = _T_INTEGER;
+ break;
+ }
+ rb_iv_set(self, "__export__", INT2FIX(ex));
+
+ return Qnil;
+}
+
+static VALUE
+Win32API_Call(argc, argv, obj)
+ VALUE argc;
+ VALUE argv;
+ VALUE obj;
+{
+ VALUE args;
+
+ FARPROC ApiFunction;
+
+ ApiPointer *ApiFunctionPointer;
+ ApiNumber *ApiFunctionNumber;
+ ApiVoid *ApiFunctionVoid;
+ ApiInteger *ApiFunctionInteger;
+
+ long lParam;
+ char *pParam;
+
+ VALUE Return;
+
+ VALUE obj_proc;
+ VALUE obj_import;
+ VALUE obj_export;
+ VALUE import_type;
+ int nimport, timport, texport, i;
+ int items;
+
+ items = rb_scan_args(argc, argv, "0*", &args);
+
+ obj_proc = rb_iv_get(obj, "__proc__");
+
+ ApiFunction = (FARPROC)NUM2INT(obj_proc);
+
+ obj_import = rb_iv_get(obj, "__import__");
+ obj_export = rb_iv_get(obj, "__export__");
+ nimport = RARRAY(obj_import)->len;
+ texport = FIX2INT(obj_export);
+
+ if (items != nimport)
+ Fail("Wrong number of parameters: expected %d, got %d.\n",
+ nimport, items);
+
+ if (0 < nimport) {
+ for (i = nimport - 1; 0 <= i; i--) {
+ VALUE str;
+ import_type = ary_entry(obj_import, i);
+ timport = FIX2INT(import_type);
+ switch (timport) {
+ case _T_NUMBER:
+ case _T_INTEGER:
+ lParam = NUM2INT(ary_entry(args, i));
+#if defined(_MSC_VER) || defined(__LCC__)
+ _asm {
+ mov eax, lParam
+ push eax
+ }
+#elif defined(__CYGWIN32__) || defined(__MINGW32__)
+ asm volatile ("pushl %0" :: "g" (lParam));
+#else
+#error
+#endif
+ break;
+ case _T_POINTER:
+ str = ary_entry(args, i);
+ Check_Type(str, T_STRING);
+ str_modify(str);
+ pParam = RSTRING(str)->ptr;
+#if defined(_MSC_VER) || defined(__LCC__)
+ _asm {
+ mov eax, dword ptr pParam
+ push eax
+ }
+#elif defined(__CYGWIN32__) || defined(__MINGW32__)
+ asm volatile ("pushl %0" :: "g" (pParam));
+#else
+#error
+#endif
+ break;
+ }
+ }
+
+ }
+
+ switch (texport) {
+ case _T_NUMBER:
+ ApiFunctionNumber = (ApiNumber *) ApiFunction;
+ Return = INT2NUM(ApiFunctionNumber());
+ break;
+ case _T_POINTER:
+ ApiFunctionPointer = (ApiPointer *) ApiFunction;
+ Return = str_new2((char *)ApiFunctionPointer());
+ break;
+ case _T_INTEGER:
+ ApiFunctionInteger = (ApiInteger *) ApiFunction;
+ Return = INT2NUM(ApiFunctionInteger());
+ break;
+ case _T_VOID:
+ default:
+ ApiFunctionVoid = (ApiVoid *) ApiFunction;
+ ApiFunctionVoid();
+ Return = INT2NUM(0);
+ break;
+ }
+ return Return;
+}
+
+void
+Init_Win32API()
+{
+ VALUE cWin32API = rb_define_class("Win32API", cObject);
+ rb_define_method(cWin32API, "initialize", Win32API_initialize, 4);
+ rb_define_method(cWin32API, "call", Win32API_Call, -1);
+ rb_define_alias(cWin32API, "Call", "call");
+}
diff --git a/ext/Win32API/extconf.rb b/ext/Win32API/extconf.rb
new file mode 100644
index 0000000000..5af3243d96
--- /dev/null
+++ b/ext/Win32API/extconf.rb
@@ -0,0 +1,7 @@
+case PLATFORM
+when /cygwin/,/mingw/
+ $CFLAGS = "-fno-defer-pop"
+ create_makefile("Win32API")
+when /win32/
+ create_makefile("Win32API")
+end
diff --git a/ext/Win32API/getch.rb b/ext/Win32API/getch.rb
new file mode 100644
index 0000000000..c015bbe9bc
--- /dev/null
+++ b/ext/Win32API/getch.rb
@@ -0,0 +1,5 @@
+require 'Win32API'
+
+getch = Win32API.new("crtdll", "_getch", [], 'L')
+
+puts getch.Call.chr
diff --git a/ext/Win32API/point.rb b/ext/Win32API/point.rb
new file mode 100644
index 0000000000..60e265f3ee
--- /dev/null
+++ b/ext/Win32API/point.rb
@@ -0,0 +1,18 @@
+require 'Win32API'
+
+getCursorPos = Win32API.new("user32", "GetCursorPos", ['P'], 'V')
+
+lpPoint = " " * 8 # store two LONGs
+getCursorPos.Call(lpPoint)
+x, y = lpPoint.unpack("LL") # get the actual values
+
+print "x: ", x, "\n"
+print "y: ", y, "\n"
+
+ods = Win32API.new("kernel32", "OutputDebugString", ['P'], 'V')
+ods.Call("Hello, World\n");
+
+GetDesktopWindow = Win32API.new("user32", "GetDesktopWindow", [], 'L')
+GetActiveWindow = Win32API.new("user32", "GetActiveWindow", [], 'L')
+SendMessage = Win32API.new("user32", "SendMessage", ['L'] * 4, 'L')
+SendMessage.Call GetDesktopWindow.Call, 274, 0xf140, 0
diff --git a/ext/aix_ld.rb b/ext/aix_ld.rb
index 1058977b88..42b2087a46 100644
--- a/ext/aix_ld.rb
+++ b/ext/aix_ld.rb
@@ -43,7 +43,7 @@ def extract(nm, out)
else
next
end
- }.sort!
+ }.compact!.sort!
uniq(data)
exp = open(out, "w")
for line in data
diff --git a/ext/curses/curses.c b/ext/curses/curses.c
index 3ae8db192d..f3d1bc0970 100644
--- a/ext/curses/curses.c
+++ b/ext/curses/curses.c
@@ -2,7 +2,7 @@
* ext/curses/curses.c
*
* by MAEDA Shugo (ender@pic-internet.or.jp)
- * modified by Yukihiro Matsumoto (matz@ruby.club.or.jp)
+ * modified by Yukihiro Matsumoto (matz@netlab.co.jp)
*/
#ifdef HAVE_NCURSES_H
@@ -12,12 +12,18 @@
# include <ncurses/curses.h>
# else
# include <curses.h>
-# if defined(__NetBSD__) && !defined(_maxx)
+# if (defined(__bsdi__) || defined(__NetBSD__)) && !defined(_maxx)
# define _maxx maxx
# endif
-# if defined(__NetBSD__) && !defined(_maxy)
+# if (defined(__bsdi__) || defined(__NetBSD__)) && !defined(_maxy)
# define _maxy maxy
# endif
+# if (defined(__bsdi__) || defined(__NetBSD__)) && !defined(_begx)
+# define _begx begx
+# endif
+# if (defined(__bsdi__) || defined(__NetBSD__)) && !defined(_begy)
+# define _begy begy
+# endif
# endif
#endif
@@ -32,14 +38,10 @@ struct windata {
WINDOW *window;
};
-#define NUM2CHAR(x) ((TYPE(x) == T_STRING)&&(RSTRING(x)->len>=1))?\
- RSTRING(x)->ptr[0]:(char)NUM2INT(x)
-#define CHAR2FIX(x) INT2FIX((int)x)
-
static void
no_window()
{
- Fail("already closed window");
+ rb_raise(rb_eRuntimeError, "already closed window");
}
#define GetWINDOW(obj, winp) {\
@@ -55,6 +57,7 @@ free_window(winp)
{
if (winp->window && winp->window != stdscr) delwin(winp->window);
winp->window = 0;
+ free(winp);
}
static VALUE
@@ -66,7 +69,7 @@ prep_window(class, window)
struct windata *winp;
if (window == NULL) {
- Fail("failed to create window");
+ rb_raise(rb_eRuntimeError, "failed to create window");
}
obj = Data_Make_Struct(class, struct windata, 0, free_window, winp);
@@ -83,7 +86,7 @@ curses_init_screen()
{
initscr();
if (stdscr == 0) {
- Fail("cannot initialize curses");
+ rb_raise(rb_eRuntimeError, "cannot initialize curses");
}
clear();
rb_stdscr = prep_window(cWindow, stdscr);
@@ -102,19 +105,33 @@ curses_stdscr()
static VALUE
curses_close_screen()
{
- endwin();
+#ifdef HAVE_ISENDWIN
+ if (!isendwin())
+#endif
+ endwin();
return Qnil;
}
+static void
+curses_finalize()
+{
+ if (stdscr
+#ifdef HAVE_ISENDWIN
+ && !isendwin()
+#endif
+ )
+ endwin();
+}
+
/* def closed? */
static VALUE
curses_closed()
{
-#ifdef HAVE_ENDWIN
+#ifdef HAVE_ISENDWIN
if (isendwin()) {
- return TRUE;
+ return Qtrue;
}
- return FALSE;
+ return Qfalse;
#else
rb_notimplement();
#endif
@@ -138,12 +155,16 @@ curses_refresh(obj)
return Qnil;
}
-/* def refresh */
+/* def doupdate */
static VALUE
curses_doupdate(obj)
VALUE obj;
{
+#ifdef HAVE_DOUPDATE
doupdate();
+#else
+ refresh();
+#endif
return Qnil;
}
@@ -235,7 +256,9 @@ static VALUE
curses_flash(obj)
VALUE obj;
{
+#ifdef HAVE_FLASH
flash();
+#endif
return Qnil;
}
@@ -287,7 +310,7 @@ static VALUE
curses_inch(obj)
VALUE obj;
{
- return CHAR2FIX(inch());
+ return CHR2FIX(inch());
}
/* def addch(ch) */
@@ -296,7 +319,7 @@ curses_addch(obj, ch)
VALUE obj;
VALUE ch;
{
- addch(NUM2CHAR(ch));
+ addch(NUM2CHR(ch));
return Qnil;
}
@@ -306,7 +329,7 @@ curses_insch(obj, ch)
VALUE obj;
VALUE ch;
{
- insch(NUM2CHAR(ch));
+ insch(NUM2CHR(ch));
return Qnil;
}
@@ -316,7 +339,9 @@ curses_addstr(obj, str)
VALUE obj;
VALUE str;
{
- addstr(RSTRING(str)->ptr);
+ if (!NIL_P(str)) {
+ addstr(STR2CSTR(str));
+ }
return Qnil;
}
@@ -325,7 +350,7 @@ static VALUE
curses_getch(obj)
VALUE obj;
{
- return CHAR2FIX(getch());
+ return CHR2FIX(getch());
}
/* def getstr */
@@ -335,7 +360,7 @@ curses_getstr(obj)
{
char rtn[1024]; /* This should be big enough.. I hope */
getstr(rtn);
- return str_taint(str_new2(rtn));
+ return rb_tainted_str_new2(rtn);
}
/* def delch */
@@ -352,7 +377,9 @@ static VALUE
curses_deleteln(obj)
VALUE obj;
{
+#ifdef HAVE_DELETELN
deleteln();
+#endif
return Qnil;
}
@@ -379,11 +406,15 @@ window_s_new(class, lines, cols, top, left)
VALUE top;
VALUE left;
{
+ VALUE w;
WINDOW *window;
window = newwin(NUM2INT(lines), NUM2INT(cols), NUM2INT(top), NUM2INT(left));
wclear(window);
- return prep_window(class, window);
+ w = prep_window(class, window);
+ rb_obj_call_init(w);
+
+ return w;
}
/* def subwin(lines, cols, top, left) */
@@ -412,7 +443,8 @@ window_close(obj)
struct windata *winp;
GetWINDOW(obj, winp);
- free_window(winp);
+ delwin(winp->window);
+ winp->window = 0;
return Qnil;
}
@@ -453,7 +485,7 @@ window_box(obj, vert, hor)
struct windata *winp;
GetWINDOW(obj, winp);
- box(winp->window, NUM2CHAR(vert), NUM2CHAR(hor));
+ box(winp->window, NUM2CHR(vert), NUM2CHR(hor));
return Qnil;
}
@@ -622,7 +654,7 @@ window_inch(obj)
struct windata *winp;
GetWINDOW(obj, winp);
- return CHAR2FIX(winch(winp->window));
+ return CHR2FIX(winch(winp->window));
}
/* def addch(ch) */
@@ -634,7 +666,7 @@ window_addch(obj, ch)
struct windata *winp;
GetWINDOW(obj, winp);
- waddch(winp->window, NUM2CHAR(ch));
+ waddch(winp->window, NUM2CHR(ch));
return Qnil;
}
@@ -648,7 +680,7 @@ window_insch(obj, ch)
struct windata *winp;
GetWINDOW(obj, winp);
- winsch(winp->window, NUM2CHAR(ch));
+ winsch(winp->window, NUM2CHR(ch));
return Qnil;
}
@@ -659,11 +691,12 @@ window_addstr(obj, str)
VALUE obj;
VALUE str;
{
- struct windata *winp;
-
- GetWINDOW(obj, winp);
- waddstr(winp->window, RSTRING(str)->ptr);
-
+ if (!NIL_P(str)) {
+ struct windata *winp;
+
+ GetWINDOW(obj, winp);
+ waddstr(winp->window, STR2CSTR(str));
+ }
return Qnil;
}
@@ -685,7 +718,7 @@ window_getch(obj)
struct windata *winp;
GetWINDOW(obj, winp);
- return CHAR2FIX(wgetch(winp->window));
+ return CHR2FIX(wgetch(winp->window));
}
/* def getstr */
@@ -698,7 +731,7 @@ window_getstr(obj)
GetWINDOW(obj, winp);
wgetstr(winp->window, rtn);
- return str_taint(str_new2(rtn));
+ return rb_tainted_str_new2(rtn);
}
/* def delch */
@@ -718,10 +751,12 @@ static VALUE
window_deleteln(obj)
VALUE obj;
{
+#ifdef HAVE_WDELETELN
struct windata *winp;
GetWINDOW(obj, winp);
wdeleteln(winp->window);
+#endif
return Qnil;
}
@@ -764,7 +799,7 @@ Init_curses()
rb_define_module_function(mCurses, "lines", curses_lines, 0);
rb_define_module_function(mCurses, "cols", curses_cols, 0);
- cWindow = rb_define_class_under(mCurses, "Window", cObject);
+ cWindow = rb_define_class_under(mCurses, "Window", rb_cObject);
rb_define_singleton_method(cWindow, "new", window_s_new, 4);
rb_define_method(cWindow, "subwin", window_subwin, 4);
rb_define_method(cWindow, "close", window_close, 0);
@@ -790,4 +825,6 @@ Init_curses()
rb_define_method(cWindow, "getstr", window_getstr, 0);
rb_define_method(cWindow, "delch", window_delch, 0);
rb_define_method(cWindow, "deleteln", window_deleteln, 0);
+
+ rb_set_end_proc(curses_finalize, 0);
}
diff --git a/ext/curses/extconf.rb b/ext/curses/extconf.rb
index 9b28437843..442a9424a2 100644
--- a/ext/curses/extconf.rb
+++ b/ext/curses/extconf.rb
@@ -1,6 +1,9 @@
+require 'mkmf'
$CFLAGS="-I/usr/include/ncurses -I/usr/local/include/ncurses"
$LDFLAGS="-L/usr/local/lib"
make=FALSE
+
+have_library("mytinfo", "tgetent") if /bow/ =~ PLATFORM
if have_header("ncurses.h") and have_library("ncurses", "initscr")
make=TRUE
elsif have_header("ncurses/curses.h") and have_library("ncurses", "initscr")
@@ -14,7 +17,7 @@ else
end
if make then
- for f in ["isendwin", "ungetch", "beep"]
+ for f in %w(isendwin ungetch beep doupdate flash deleteln wdeleteln)
have_func(f)
end
create_makefile("curses")
diff --git a/ext/curses/hello.rb b/ext/curses/hello.rb
index bed7779aac..a1915ce60d 100644
--- a/ext/curses/hello.rb
+++ b/ext/curses/hello.rb
@@ -10,6 +10,7 @@ def show_message(message)
win.box(?|, ?=)
win.setpos(2, 3)
win.addstr(message)
+ win.refresh
win.getch
win.close
end
@@ -18,8 +19,9 @@ init_screen
begin
crmode
# show_message("Hit any key")
- setpos (lines - 5) / 2, (cols - 10) / 2
+ setpos((lines - 5) / 2, (cols - 10) / 2)
addstr("Hit any key")
+ refresh
getch
show_message("Hello, World!")
refresh
diff --git a/ext/curses/view.rb b/ext/curses/view.rb
index e59a74ed44..5ba1a8413c 100644
--- a/ext/curses/view.rb
+++ b/ext/curses/view.rb
@@ -43,6 +43,7 @@ while TRUE
addstr(data_lines[lptr + i]) #if data_lines[lptr + i]
i += 1
end
+ refresh
explicit = FALSE
n = 0
diff --git a/ext/cygwin32_ld.rb b/ext/cygwin32_ld.rb
new file mode 100644
index 0000000000..a9c8e21cb0
--- /dev/null
+++ b/ext/cygwin32_ld.rb
@@ -0,0 +1,90 @@
+#!/usr/local/bin/ruby
+require '../../rbconfig'
+include Config
+
+args = ARGV.join(" ")
+
+objs = []
+flags = []
+libname = ''
+Init = "../init"
+
+path = ''
+
+def writeInit
+ out = open("#{Init}.c", "w")
+
+ out.print %q@
+#include <windows.h>
+#include <stdio.h>
+
+extern struct _reent *__imp_reent_data;
+WINAPI dll_entry(int a, int b, int c)
+{
+ _impure_ptr =__imp_reent_data;
+ return 1;
+}
+main(){}
+//void impure_setup(struct _reent *_impure_ptrMain)
+//{
+// _impure_ptr =__imp_reent_data;
+//}
+@
+ out.close
+end
+
+def xsystem cmd
+ print cmd, "\n"
+ system cmd
+end
+
+if args =~ /-o (\w+)\.dll/i
+ libname = $1
+ # Check for path:
+ if libname =~ /(\w+\/)(\w+)$/
+ path = $1
+ libname = $2
+ end
+ for arg in ARGV
+ case arg
+ when /\.[oa]$/i
+ objs.push(arg)
+ when /-o/, /\w+\.dll/i
+ ;
+ else
+ flags << arg
+ end
+ end
+
+ writeInit unless FileTest.exist?("#{Init}.c")
+ unless FileTest.exist?("#{Init}.o") and
+ File.mtime("#{Init}.c") < File.mtime("#{Init}.o")
+ xsystem "gcc -c #{Init}.c -o #{Init}.o"
+ end
+
+ command = "echo EXPORTS > #{libname}.def"
+ xsystem command
+# xsystem "echo impure_setup >> #{libname}.def"
+ xsystem "nm --extern-only " + objs.join(" ") +
+ " | sed -n '/^........ [CDT] _/s///p' >> #{libname}.def"
+
+ command = "gcc -nostdlib -o junk.o -Wl,--base-file,#{libname}.base,--dll " +
+ objs.join(" ") + " #{Init}.o "
+ command.concat(flags.join(" ") +
+ " -Wl,-e,_dll_entry@12 -lcygwin -lkernel32 #{CONFIG['srcdir']}/libruby.a")
+ xsystem command
+
+ command = "dlltool --as=as --dllname #{libname}.dll --def #{libname}.def --base-file #{libname}.base --output-exp #{libname}.exp"
+ xsystem command
+
+ command = "gcc -s -nostdlib -o #{libname}.dll -Wl,--dll #{libname}.exp " +
+ objs.join(" ") + " #{Init}.o "
+ command.concat(flags.join(" ") +
+ " -Wl,-e,_dll_entry@12 -lcygwin -lkernel32 #{CONFIG['srcdir']}/libruby.a")
+ xsystem command
+ File.unlink "junk.o" if FileTest.exist? "junk.o"
+
+else
+ # no special processing, just call ld
+ xsystem "ld #{args}"
+end
diff --git a/ext/dbm/dbm.c b/ext/dbm/dbm.c
index b416802241..2764a325e1 100644
--- a/ext/dbm/dbm.c
+++ b/ext/dbm/dbm.c
@@ -6,7 +6,7 @@
$Date$
created at: Mon Jan 24 15:59:52 JST 1994
- Copyright (C) 1995 Yukihiro Matsumoto
+ Copyright (C) 1995-1998 Yukihiro Matsumoto
************************************************/
@@ -15,11 +15,12 @@
#include <ndbm.h>
#include <fcntl.h>
#include <errno.h>
+#ifdef USE_CWGUSI
+# include <sys/errno.h>
+#endif
VALUE cDBM;
-extern VALUE mEnumerable;
-
struct dbmdata {
int di_size;
DBM *di_dbm;
@@ -28,7 +29,7 @@ struct dbmdata {
static void
closed_dbm()
{
- Fail("closed DBM file");
+ rb_raise(rb_eRuntimeError, "closed DBM file");
}
#define GetDBM(obj, dbmp) {\
@@ -41,13 +42,14 @@ free_dbm(dbmp)
struct dbmdata *dbmp;
{
if (dbmp->di_dbm) dbm_close(dbmp->di_dbm);
+ free(dbmp);
}
static VALUE
-fdbm_s_open(argc, argv, class)
+fdbm_s_open(argc, argv, klass)
int argc;
VALUE *argv;
- VALUE class;
+ VALUE klass;
{
VALUE file, vmode;
DBM *dbm;
@@ -79,9 +81,10 @@ fdbm_s_open(argc, argv, class)
rb_sys_fail(RSTRING(file)->ptr);
}
- obj = Data_Make_Struct(class,struct dbmdata,0,free_dbm,dbmp);
+ obj = Data_Make_Struct(klass,struct dbmdata,0,free_dbm,dbmp);
dbmp->di_dbm = dbm;
dbmp->di_size = -1;
+ rb_obj_call_init(obj);
return obj;
}
@@ -118,23 +121,23 @@ fdbm_fetch(obj, keystr)
if (value.dptr == 0) {
return Qnil;
}
- return str_taint(str_new(value.dptr, value.dsize));
+ return rb_tainted_str_new(value.dptr, value.dsize);
}
static VALUE
-fdbm_indexes(obj, ag)
- VALUE obj, ag;
+fdbm_indexes(argc, argv, obj)
+ int argc;
+ VALUE *argv;
+ VALUE obj;
{
- VALUE *p, *pend;
VALUE new;
- int i = 0;
- struct RArray *args = RARRAY(rb_Array(ag));
+ int i;
- new = ary_new2(args->len);
- p = args->ptr; pend = p + args->len;
- while (p < pend) {
- ary_push(new, fdbm_fetch(obj, *p++));
+ new = rb_ary_new2(argc);
+ for (i=0; i<argc; i++) {
+ rb_ary_push(new, fdbm_fetch(obj, argv[i]));
}
+
return new;
}
@@ -156,13 +159,13 @@ fdbm_delete(obj, keystr)
value = dbm_fetch(dbm, key);
if (value.dptr == 0) {
- if (iterator_p()) rb_yield(keystr);
+ if (rb_iterator_p()) rb_yield(keystr);
return Qnil;
}
if (dbm_delete(dbm, key)) {
dbmp->di_size = -1;
- Fail("dbm_delete failed");
+ rb_raise(rb_eRuntimeError, "dbm_delete failed");
}
else if (dbmp->di_size >= 0) {
dbmp->di_size--;
@@ -188,9 +191,9 @@ fdbm_shift(obj)
val = dbm_fetch(dbm, key);
dbm_delete(dbm, key);
- keystr = str_taint(str_new(key.dptr, key.dsize));
- valstr = str_taint(str_new(val.dptr, val.dsize));
- return assoc_new(keystr, valstr);
+ keystr = rb_tainted_str_new(key.dptr, key.dsize);
+ valstr = rb_tainted_str_new(val.dptr, val.dsize);
+ return rb_assoc_new(keystr, valstr);
}
static VALUE
@@ -207,11 +210,11 @@ fdbm_delete_if(obj)
dbm = dbmp->di_dbm;
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
val = dbm_fetch(dbm, key);
- keystr = str_taint(str_new(key.dptr, key.dsize));
- valstr = str_taint(str_new(val.dptr, val.dsize));
- if (RTEST(rb_yield(assoc_new(keystr, valstr)))) {
+ keystr = rb_tainted_str_new(key.dptr, key.dsize);
+ valstr = rb_tainted_str_new(val.dptr, val.dsize);
+ if (RTEST(rb_yield(rb_assoc_new(keystr, valstr)))) {
if (dbm_delete(dbm, key)) {
- Fail("dbm_delete failed");
+ rb_raise(rb_eRuntimeError, "dbm_delete failed");
}
}
}
@@ -232,13 +235,72 @@ fdbm_clear(obj)
dbmp->di_size = -1;
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
if (dbm_delete(dbm, key)) {
- Fail("dbm_delete failed");
+ rb_raise(rb_eRuntimeError, "dbm_delete failed");
}
}
return obj;
}
static VALUE
+fdbm_invert(obj)
+ VALUE obj;
+{
+ datum key, val;
+ struct dbmdata *dbmp;
+ DBM *dbm;
+ VALUE keystr, valstr;
+ VALUE hash = rb_hash_new();
+
+ GetDBM(obj, dbmp);
+ dbm = dbmp->di_dbm;
+ for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
+ val = dbm_fetch(dbm, key);
+ keystr = rb_tainted_str_new(key.dptr, key.dsize);
+ valstr = rb_tainted_str_new(val.dptr, val.dsize);
+ rb_hash_aset(hash, valstr, keystr);
+ }
+ return obj;
+}
+
+static VALUE
+each_pair(obj)
+ VALUE obj;
+{
+ return rb_funcall(obj, rb_intern("each_pair"), 0, 0);
+}
+
+static VALUE fdbm_store _((VALUE,VALUE,VALUE));
+
+static VALUE
+update_i(pair, dbm)
+ VALUE pair, dbm;
+{
+ Check_Type(pair, T_ARRAY);
+ if (RARRAY(pair)->len < 2) {
+ rb_raise(rb_eArgError, "pair must be [key, value]");
+ }
+ fdbm_store(dbm, RARRAY(pair)->ptr[0], RARRAY(pair)->ptr[1]);
+ return Qnil;
+}
+
+static VALUE
+fdbm_update(obj, other)
+ VALUE obj, other;
+{
+ rb_iterate(each_pair, other, update_i, obj);
+ return obj;
+}
+
+static VALUE
+fdbm_replace(obj, other)
+ VALUE obj, other;
+{
+ fdbm_clear(obj);
+ rb_iterate(each_pair, other, update_i, obj);
+ return obj;
+}
+
+static VALUE
fdbm_store(obj, keystr, valstr)
VALUE obj, keystr, valstr;
{
@@ -252,14 +314,14 @@ fdbm_store(obj, keystr, valstr)
}
rb_secure(4);
- keystr = obj_as_string(keystr);
+ keystr = rb_obj_as_string(keystr);
key.dptr = RSTRING(keystr)->ptr;
key.dsize = RSTRING(keystr)->len;
if (NIL_P(valstr)) return fdbm_delete(obj, keystr);
- valstr = obj_as_string(valstr);
+ valstr = rb_obj_as_string(valstr);
val.dptr = RSTRING(valstr)->ptr;
val.dsize = RSTRING(valstr)->len;
@@ -267,9 +329,11 @@ fdbm_store(obj, keystr, valstr)
dbmp->di_size = -1;
dbm = dbmp->di_dbm;
if (dbm_store(dbm, key, val, DBM_REPLACE)) {
+#ifdef HAVE_DBM_CLAERERR
dbm_clearerr(dbm);
- if (errno == EPERM) rb_sys_fail(Qnil);
- Fail("dbm_store failed");
+#endif
+ if (errno == EPERM) rb_sys_fail(0);
+ rb_raise(rb_eRuntimeError, "dbm_store failed");
}
return valstr;
@@ -316,8 +380,8 @@ fdbm_empty_p(obj)
else {
i = dbmp->di_size;
}
- if (i == 0) return TRUE;
- return FALSE;
+ if (i == 0) return Qtrue;
+ return Qfalse;
}
static VALUE
@@ -332,7 +396,7 @@ fdbm_each_value(obj)
dbm = dbmp->di_dbm;
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
val = dbm_fetch(dbm, key);
- rb_yield(str_taint(str_new(val.dptr, val.dsize)));
+ rb_yield(rb_tainted_str_new(val.dptr, val.dsize));
}
return obj;
}
@@ -348,7 +412,7 @@ fdbm_each_key(obj)
GetDBM(obj, dbmp);
dbm = dbmp->di_dbm;
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
- rb_yield(str_taint(str_new(key.dptr, key.dsize)));
+ rb_yield(rb_tainted_str_new(key.dptr, key.dsize));
}
return obj;
}
@@ -367,9 +431,9 @@ fdbm_each_pair(obj)
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
val = dbm_fetch(dbm, key);
- keystr = str_taint(str_new(key.dptr, key.dsize));
- valstr = str_taint(str_new(val.dptr, val.dsize));
- rb_yield(assoc_new(keystr, valstr));
+ keystr = rb_tainted_str_new(key.dptr, key.dsize);
+ valstr = rb_tainted_str_new(val.dptr, val.dsize);
+ rb_yield(rb_assoc_new(keystr, valstr));
}
return obj;
@@ -387,9 +451,9 @@ fdbm_keys(obj)
GetDBM(obj, dbmp);
dbm = dbmp->di_dbm;
- ary = ary_new();
+ ary = rb_ary_new();
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
- ary_push(ary, str_taint(str_new(key.dptr, key.dsize)));
+ rb_ary_push(ary, rb_tainted_str_new(key.dptr, key.dsize));
}
return ary;
@@ -407,10 +471,10 @@ fdbm_values(obj)
GetDBM(obj, dbmp);
dbm = dbmp->di_dbm;
- ary = ary_new();
+ ary = rb_ary_new();
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
val = dbm_fetch(dbm, key);
- ary_push(ary, str_taint(str_new(val.dptr, val.dsize)));
+ rb_ary_push(ary, rb_tainted_str_new(val.dptr, val.dsize));
}
return ary;
@@ -431,8 +495,8 @@ fdbm_has_key(obj, keystr)
GetDBM(obj, dbmp);
dbm = dbmp->di_dbm;
val = dbm_fetch(dbm, key);
- if (val.dptr) return TRUE;
- return FALSE;
+ if (val.dptr) return Qtrue;
+ return Qfalse;
}
static VALUE
@@ -453,9 +517,9 @@ fdbm_has_value(obj, valstr)
val = dbm_fetch(dbm, key);
if (val.dsize == RSTRING(valstr)->len &&
memcmp(val.dptr, RSTRING(valstr)->ptr, val.dsize) == 0)
- return TRUE;
+ return Qtrue;
}
- return FALSE;
+ return Qfalse;
}
static VALUE
@@ -470,26 +534,29 @@ fdbm_to_a(obj)
GetDBM(obj, dbmp);
dbm = dbmp->di_dbm;
- ary = ary_new();
+ ary = rb_ary_new();
for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
val = dbm_fetch(dbm, key);
- ary_push(ary, assoc_new(str_taint(str_new(key.dptr, key.dsize)),
- str_taint(str_new(val.dptr, val.dsize))));
+ rb_ary_push(ary, rb_assoc_new(rb_tainted_str_new(key.dptr, key.dsize),
+ rb_tainted_str_new(val.dptr, val.dsize)));
}
return ary;
}
+void
Init_dbm()
{
- cDBM = rb_define_class("DBM", cObject);
- rb_include_module(cDBM, mEnumerable);
+ cDBM = rb_define_class("DBM", rb_cObject);
+ rb_include_module(cDBM, rb_mEnumerable);
rb_define_singleton_method(cDBM, "open", fdbm_s_open, -1);
+ rb_define_singleton_method(cDBM, "new", fdbm_s_open, -1);
rb_define_method(cDBM, "close", fdbm_close, 0);
rb_define_method(cDBM, "[]", fdbm_fetch, 1);
rb_define_method(cDBM, "[]=", fdbm_store, 2);
- rb_define_method(cDBM, "indexes", fdbm_indexes, -2);
+ rb_define_method(cDBM, "indexes", fdbm_indexes, -1);
+ rb_define_method(cDBM, "indices", fdbm_indexes, -1);
rb_define_method(cDBM, "length", fdbm_length, 0);
rb_define_alias(cDBM, "size", "length");
rb_define_method(cDBM, "empty?", fdbm_empty_p, 0);
@@ -503,6 +570,10 @@ Init_dbm()
rb_define_method(cDBM, "delete", fdbm_delete, 1);
rb_define_method(cDBM, "delete_if", fdbm_delete_if, 0);
rb_define_method(cDBM, "clear", fdbm_clear, 0);
+ rb_define_method(cDBM,"invert", fdbm_invert, 0);
+ rb_define_method(cDBM,"update", fdbm_update, 1);
+ rb_define_method(cDBM,"replace", fdbm_replace, 1);
+
rb_define_method(cDBM, "include?", fdbm_has_key, 1);
rb_define_method(cDBM, "has_key?", fdbm_has_key, 1);
rb_define_method(cDBM, "has_value?", fdbm_has_value, 1);
diff --git a/ext/dbm/extconf.rb b/ext/dbm/extconf.rb
index 4a5d41f275..3a96cee12f 100644
--- a/ext/dbm/extconf.rb
+++ b/ext/dbm/extconf.rb
@@ -1,5 +1,9 @@
+require 'mkmf'
$LDFLAGS = "-L/usr/local/lib"
-have_library("gdbm", "dbm_open") or have_library("dbm", "dbm_open")
+have_library("gdbm", "dbm_open") or
+ have_library("db", "dbm_open") or
+ have_library("dbm", "dbm_open")
if have_func("dbm_open")
+ have_func("dbm_clearerr")
create_makefile("dbm")
end
diff --git a/ext/etc/etc.c b/ext/etc/etc.c
index 20cd9295ed..c10680c7d3 100644
--- a/ext/etc/etc.c
+++ b/ext/etc/etc.c
@@ -37,7 +37,7 @@ etc_getlogin(obj)
#endif
if (login)
- return str_new2(login);
+ return rb_tainted_str_new2(login);
return Qnil;
}
@@ -47,34 +47,36 @@ setup_passwd(pwd)
struct passwd *pwd;
{
if (pwd == 0) rb_sys_fail("/etc/passwd");
- return struct_new(sPasswd,
- str_new2(pwd->pw_name),
- str_new2(pwd->pw_passwd),
- INT2FIX(pwd->pw_uid),
- INT2FIX(pwd->pw_gid),
- str_new2(pwd->pw_gecos),
- str_new2(pwd->pw_dir),
- str_new2(pwd->pw_shell),
+ return rb_struct_new(sPasswd,
+ rb_tainted_str_new2(pwd->pw_name),
+ rb_tainted_str_new2(pwd->pw_passwd),
+ INT2FIX(pwd->pw_uid),
+ INT2FIX(pwd->pw_gid),
+#ifdef PW_GECOS
+ rb_tainted_str_new2(pwd->pw_gecos),
+#endif
+ rb_tainted_str_new2(pwd->pw_dir),
+ rb_tainted_str_new2(pwd->pw_shell),
#ifdef PW_CHANGE
- INT2FIX(pwd->pw_change),
+ INT2FIX(pwd->pw_change),
#endif
#ifdef PW_QUOTA
- INT2FIX(pwd->pw_quota),
+ INT2FIX(pwd->pw_quota),
#endif
#ifdef PW_AGE
- INT2FIX(pwd->pw_age),
+ INT2FIX(pwd->pw_age),
#endif
#ifdef PW_CLASS
- str_new2(pwd->pw_class),
+ rb_tainted_str_new2(pwd->pw_class),
#endif
#ifdef PW_COMMENT
- str_new2(pwd->pw_comment),
+ rb_tainted_str_new2(pwd->pw_comment),
#endif
#ifdef PW_EXPIRE
- INT2FIX(pwd->pw_expire),
+ INT2FIX(pwd->pw_expire),
#endif
- 0 /*dummy*/
- );
+ 0 /*dummy*/
+ );
}
#endif
@@ -96,7 +98,7 @@ etc_getpwuid(argc, argv, obj)
uid = getuid();
}
pwd = getpwuid(uid);
- if (pwd == 0) Fail("can't find user for %d", uid);
+ if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %d", uid);
return setup_passwd(pwd);
#else
return Qnil;
@@ -112,7 +114,7 @@ etc_getpwnam(obj, nam)
Check_Type(nam, T_STRING);
pwd = getpwnam(RSTRING(nam)->ptr);
- if (pwd == 0) Fail("can't find user for %s", RSTRING(nam)->ptr);
+ if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %s", RSTRING(nam)->ptr);
return setup_passwd(pwd);
#else
return Qnil;
@@ -123,10 +125,10 @@ static VALUE
etc_passwd(obj)
VALUE obj;
{
-#if defined(HAVE_GETPWENT) && !defined(__CYGWIN32__)
+#if defined(HAVE_GETPWENT)
struct passwd *pw;
- if (iterator_p()) {
+ if (rb_iterator_p()) {
setpwent();
while (pw = getpwent()) {
rb_yield(setup_passwd(pw));
@@ -135,7 +137,7 @@ etc_passwd(obj)
return obj;
}
pw = getpwent();
- if (pw == 0) Fail("can't fetch next -- /etc/passwd");
+ if (pw == 0) rb_raise(rb_eRuntimeError, "can't fetch next -- /etc/passwd");
return setup_passwd(pw);
#else
return Qnil;
@@ -150,17 +152,17 @@ setup_group(grp)
VALUE mem;
char **tbl;
- mem = ary_new();
+ mem = rb_ary_new();
tbl = grp->gr_mem;
while (*tbl) {
- ary_push(mem, str_new2(*tbl));
+ rb_ary_push(mem, rb_tainted_str_new2(*tbl));
tbl++;
}
- return struct_new(sGroup,
- str_new2(grp->gr_name),
- str_new2(grp->gr_passwd),
- INT2FIX(grp->gr_gid),
- mem);
+ return rb_struct_new(sGroup,
+ rb_tainted_str_new2(grp->gr_name),
+ rb_tainted_str_new2(grp->gr_passwd),
+ INT2FIX(grp->gr_gid),
+ mem);
}
#endif
@@ -174,7 +176,7 @@ etc_getgrgid(obj, id)
gid = NUM2INT(id);
grp = getgrgid(gid);
- if (grp == 0) Fail("can't find group for %d", gid);
+ if (grp == 0) rb_raise(rb_eArgError, "can't find group for %d", gid);
return setup_group(grp);
#else
return Qnil;
@@ -190,7 +192,7 @@ etc_getgrnam(obj, nam)
Check_Type(nam, T_STRING);
grp = getgrnam(RSTRING(nam)->ptr);
- if (grp == 0) Fail("can't find group for %s", RSTRING(nam)->ptr);
+ if (grp == 0) rb_raise(rb_eArgError, "can't find group for %s", RSTRING(nam)->ptr);
return setup_group(grp);
#else
return Qnil;
@@ -204,7 +206,7 @@ etc_group(obj)
#ifdef HAVE_GETGRENT
struct group *grp;
- if (iterator_p()) {
+ if (rb_iterator_p()) {
setgrent();
while (grp = getgrent()) {
rb_yield(setup_group(grp));
@@ -235,32 +237,35 @@ Init_etc()
rb_define_module_function(mEtc, "getgrnam", etc_getgrnam, 1);
rb_define_module_function(mEtc, "group", etc_group, 0);
- sPasswd = struct_define("Passwd",
- "name", "passwd", "uid", "gid",
- "gecos", "dir", "shell",
+ sPasswd = rb_struct_define("Passwd",
+ "name", "passwd", "uid", "gid",
+#ifdef PW_GECOS
+ "gecos",
+#endif
+ "dir", "shell",
#ifdef PW_CHANGE
- "change",
+ "change",
#endif
#ifdef PW_QUOTA
- "quota",
+ "quota",
#endif
#ifdef PW_AGE
- "age",
+ "age",
#endif
#ifdef PW_CLASS
- "class",
+ "class",
#endif
#ifdef PW_COMMENT
- "comment",
+ "comment",
#endif
#ifdef PW_EXPIRE
- "expire",
+ "expire",
#endif
- 0);
+ 0);
rb_global_variable(&sPasswd);
#ifdef HAVE_GETGRENT
- sGroup = struct_define("Group", "name", "passwd", "gid", "mem", 0);
+ sGroup = rb_struct_define("Group", "name", "passwd", "gid", "mem", 0);
rb_global_variable(&sGroup);
#endif
}
diff --git a/ext/etc/extconf.rb b/ext/etc/extconf.rb
index 884de93ec8..4cf04a3ec3 100644
--- a/ext/etc/extconf.rb
+++ b/ext/etc/extconf.rb
@@ -1,7 +1,31 @@
+require 'mkmf'
+
+def etc_grep_header(field)
+ f = open("conftest.c", "w")
+ f.print <<EOF
+#include <pwd.h>
+EOF
+ f.close
+ begin
+ if xsystem("#{CPP} | egrep #{field}")
+ $defs.push(format("-D%s", field.upcase))
+ end
+ ensure
+ system "rm -f conftest.c"
+ end
+end
+
have_library("sun", "getpwnam") # NIS (== YP) interface for IRIX 4
a = have_func("getlogin")
b = have_func("getpwent")
c = have_func("getgrent")
if a or b or c
+ etc_grep_header("pw_gecos")
+ etc_grep_header("pw_change")
+ etc_grep_header("pw_quota")
+ etc_grep_header("pw_age")
+ etc_grep_header("pw_class")
+ etc_grep_header("pw_comment")
+ etc_grep_header("pw_expire")
create_makefile("etc")
end
diff --git a/ext/extmk.rb.in b/ext/extmk.rb.in
index e1d318d19c..058c144f94 100644
--- a/ext/extmk.rb.in
+++ b/ext/extmk.rb.in
@@ -1,12 +1,14 @@
#! /usr/local/bin/ruby
-$".push 'mkmf.rb'
+$".push 'mkmf.rb' #"
+load '@top_srcdir@/lib/find.rb'
if ARGV[0] == 'static'
$force_static = TRUE
ARGV.shift
elsif ARGV[0] == 'install'
$install = TRUE
+ $destdir = ARGV[1] || ''
ARGV.shift
elsif ARGV[0] == 'clean'
$clean = TRUE
@@ -19,8 +21,16 @@ $cache_mod = FALSE;
$lib_cache = {}
$func_cache = {}
$hdr_cache = {}
-$topdir = "@top_srcdir@"
-if $topdir !~ "^/"
+$top_srcdir = "@top_srcdir@"
+if $top_srcdir !~ "^/"
+ # get absolute path
+ save = Dir.pwd
+ Dir.chdir $top_srcdir
+ $top_srcdir = Dir.pwd
+ Dir.chdir save
+end
+$topdir = ".."
+if $topdir !~ "^/"
# get absolute path
save = Dir.pwd
Dir.chdir $topdir
@@ -59,23 +69,59 @@ end
if PLATFORM == "m68k-human"
CFLAGS = "@CFLAGS@".gsub(/-c..-stack=[0-9]+ */, '')
-LINK = "@CC@ -o conftest -I#{$topdir} " + CFLAGS + " %s @LDFLAGS@ %s conftest.c @LIBS@ %s > nul 2>&1"
-CPP = "@CPP@ @CPPFLAGS@ -I#{$topdir} " + CFLAGS + " %s conftest.c > nul 2>&1"
else
CFLAGS = "@CFLAGS@"
-LINK = "@CC@ -o conftest -I#{$topdir} " + CFLAGS + " %s @LDFLAGS@ %s conftest.c %s > /dev/null 2>&1"
-CPP = "@CPP@ @CPPFLAGS@ -I#{$topdir} " + CFLAGS + " %s conftest.c > /dev/null 2>&1"
+end
+LINK = "@CC@ -o conftest -I#$topdir -I#$top_srcdir -I@includedir@ #{CFLAGS} %s @LDFLAGS@ %s conftest.c @LIBS@ %s"
+CPP = "@CPP@ @CPPFLAGS@ -I#$topdir -I#$top_srcdir -I@includedir@ #{CFLAGS} %s conftest.c"
+
+if /cygwin|mswin32|djgpp|mingw32|m68k-human/i =~ PLATFORM
+ $null = open("nul", "w")
+else
+ $null = open("/dev/null", "w")
+end
+
+$orgerr = $stderr.dup
+$orgout = $stdout.dup
+def xsystem command
+ if $DEBUG
+ return system(command)
+ end
+ $stderr.reopen($null)
+ $stdout.reopen($null)
+ r = system(command)
+ $stderr.reopen($orgerr)
+ $stdout.reopen($orgout)
+ return r
end
def try_link(libs)
- system(format(LINK, $CFLAGS, $LDFLAGS, libs))
+ xsystem(format(LINK, $CFLAGS, $LDFLAGS, libs))
end
def try_cpp
- system(format(CPP, $CFLAGS))
+ xsystem(format(CPP, $CFLAGS))
+end
+
+def install_rb(mfile)
+ path = []
+ dir = []
+ Find.find("lib") do |f|
+ next unless /\.rb$/ =~ f
+ f = f[4..-1]
+ path.push f
+ dir |= File.dirname(f)
+ end
+ for f in dir
+ next if f == "."
+ mfile.printf "\t@test -d $(DESTDIR)$(pkglibdir)/%s || mkdir $(DESTDIR)$(pkglibdir)/%s\n", f, f
+ end
+ for f in path
+ mfile.printf "\t$(INSTALL_DATA) lib/%s $(DESTDIR)$(pkglibdir)/%s\n", f, f
+ end
end
-def have_library(lib, func)
+def have_library(lib, func="main")
if $lib_cache[lib]
if $lib_cache[lib] == "yes"
if $libs
@@ -89,26 +135,34 @@ def have_library(lib, func)
end
end
- cfile = open("conftest.c", "w")
- cfile.printf "\
+ if func && func != ""
+ cfile = open("conftest.c", "w")
+ cfile.printf "\
int main() { return 0; }
int t() { %s(); return 0; }
", func
- cfile.close
+ cfile.close
- begin
+ begin
+ if $libs
+ libs = "-l" + lib + " " + $libs
+ else
+ libs = "-l" + lib
+ end
+ unless try_link(libs)
+ $lib_cache[lib] = 'no'
+ $cache_mod = TRUE
+ return FALSE
+ end
+ ensure
+ system "rm -f conftest*"
+ end
+ else
if $libs
libs = "-l" + lib + " " + $libs
else
libs = "-l" + lib
end
- unless try_link(libs)
- $lib_cache[lib] = 'no'
- $cache_mod = TRUE
- return FALSE
- end
- ensure
- system "rm -f conftest*"
end
$libs = libs
@@ -206,9 +260,19 @@ def create_makefile(target)
end
$defs.push(format("-DEXTLIB='%s'", libs.join(",")))
end
- $libs = "" unless $libs
- $srcdir = $topdir + "/ext/" + target
+ $DLDFLAGS = '@DLDFLAGS@'
+
+ if PLATFORM =~ /beos/
+ if $libs
+ $libs = $libs + " -lruby"
+ else
+ $libs = "-lruby"
+ end
+ $DLDFLAGS = $DLDFLAGS + " -L" + $topdir
+ end
+
+ $srcdir = $top_srcdir + "/ext/" + target
mfile = open("Makefile", "w")
mfile.printf "\
SHELL = /bin/sh
@@ -222,10 +286,11 @@ hdrdir = #{$topdir}
CC = @CC@
-CFLAGS = %s -I#{$topdir} %s #$CFLAGS %s
-DLDFLAGS = @DLDFLAGS@ #$LDFLAGS
+prefix = @prefix@
+CFLAGS = %s -I#{$topdir} -I#{$top_srcdir} -I@includedir@ #{CFLAGS} #$CFLAGS %s
+DLDFLAGS = #$DLDFLAGS @LDFLAGS@ #$LDFLAGS
LDSHARED = @LDSHARED@
-", if $static then "" else "@CCDLFLAGS@" end, CFLAGS, $defs.join(" ")
+", if $static then "" else "@CCDLFLAGS@" end, $defs.join(" ")
mfile.printf "\
@@ -234,18 +299,20 @@ RUBY_INSTALL_NAME = `t='$(program_transform_name)'; echo ruby | sed $$t`
prefix = @prefix@
exec_prefix = @exec_prefix@
-libdir = @libdir@/$(RUBY_INSTALL_NAME)/@arch@
+libdir = @libdir@
+pkglibdir = $(libdir)/$(RUBY_INSTALL_NAME)
+archdir = $(pkglibdir)/@arch@
@SET_MAKE@
#### End of system configuration section. ####
"
- mfile.printf "LOCAL_LIBS = %s\n", $local_libs if $local_libs
+ mfile.printf "LOCAL_LIBS = %s\n", $local_libs unless $local_libs == ""
mfile.printf "LIBS = %s\n", $libs
mfile.printf "OBJS = "
if !$objs then
$objs = []
- for f in Dir["#{$topdir}/ext/#{target}/*.{c,cc}"]
+ for f in Dir["#{$top_srcdir}/ext/#{$mdir}/*.{c,cc}"]
f = File.basename(f)
f.sub!(/\.(c|cc)$/, ".o")
$objs.push f
@@ -254,42 +321,48 @@ libdir = @libdir@/$(RUBY_INSTALL_NAME)/@arch@
mfile.printf $objs.join(" ")
mfile.printf "\n"
- mfile.printf "\
-TARGET = %s.%s
+ mfile.printf <<EOS
+TARGET = #{target}.#{$static ? "a" : "@DLEXT@"}
-INSTALL = %s@INSTALL@
+INSTALL = #{$dots}@INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
binsuffix = @binsuffix@
all: $(TARGET)
-clean:; @rm -f *.o *.so *.sl
+clean:; @rm -f *.o *.a *.so *.sl
@rm -f Makefile extconf.h conftest.*
@rm -f core ruby$(binsuffix) *~
realclean: clean
-", target,
- if $static then "o" else "@DLEXT@" end, $dots
+EOS
- mfile.printf "\
+ mfile.printf <<EOS
install:
-"
+ @test -d $(DESTDIR)$(libdir) || mkdir $(DESTDIR)$(libdir)
+ @test -d $(DESTDIR)$(pkglibdir) || mkdir $(DESTDIR)$(pkglibdir)
+ @test -d $(DESTDIR)$(archdir) || mkdir $(DESTDIR)$(archdir)
+EOS
if !$static
- mfile.printf "
- @test -d $(libdir) || mkdir $(libdir)
- $(INSTALL) $(TARGET) $(libdir)/$(TARGET)
+ mfile.printf "\
+ $(INSTALL) $(TARGET) $(DESTDIR)$(archdir)/$(TARGET)
"
end
- for rb in Dir["lib/*.rb"]
- mfile.printf "\t$(INSTALL) %s @libdir@/$(RUBY_INSTALL_NAME)\n", rb
- end
+ install_rb(mfile)
mfile.printf "\n"
- if !$static && "@DLEXT@" != "o"
+ if $static
+ mfile.printf "\
+$(TARGET): $(OBJS)
+ @AR@ cru $(TARGET) $(OBJS)
+ @-@RANLIB@ $(TARGET) 2> /dev/null || true
+"
+ elsif "@DLEXT@" != "o"
mfile.printf "\
$(TARGET): $(OBJS)
- $(LDSHARED) $(DLDFLAGS) -o $(TARGET) $(OBJS) $(LOCAL_LIBS) $(LIBS)
+ $(LDSHARED) $(DLDFLAGS) -o $(TARGET) $(OBJS) $(LIBS) $(LOCAL_LIBS)
"
elsif not File.exist?(target + ".c") and not File.exist?(target + ".cc")
if PLATFORM == "m68k-human"
@@ -297,16 +370,11 @@ $(TARGET): $(OBJS)
$(TARGET): $(OBJS)
ar cru $(TARGET) $(OBJS)
"
- elsif PLATFORM =~ "-nextstep"
+ elsif PLATFORM =~ "-nextstep" || PLATFORM =~ "-openstep" || PLATFORM =~ "-rhapsody"
mfile.printf "\
$(TARGET): $(OBJS)
cc -r $(CFLAGS) -o $(TARGET) $(OBJS)
"
- elsif $static
- mfile.printf "\
-$(TARGET): $(OBJS)
- ld -r -o $(TARGET) $(OBJS)
-"
else
mfile.printf "\
$(TARGET): $(OBJS)
@@ -324,6 +392,19 @@ $(TARGET): $(OBJS)
dfile.close
end
mfile.close
+
+ if PLATFORM =~ /beos/
+ if PLATFORM =~ /^powerpc/ then
+ deffilename = "ruby.exp"
+ else
+ deffilename = "ruby.def"
+ end
+ print "creating ruby.def\n"
+ open(deffilename, "w") do |file|
+ file.print("EXPORTS\n") if PLATFORM =~ /^i/
+ file.print("Init_#{target}\n")
+ end
+ end
end
def extmake(target)
@@ -335,24 +416,25 @@ def extmake(target)
return if $nodynamic and not $static
- $local_libs = nil
- $libs = nil
$objs = nil
- $CFLAGS = nil
- $LDFLAGS = nil
+ $libs = PLATFORM =~ /cygwin|beos|openstep|nextstep|rhapsody/ ? nil : "-lc"
+ $local_libs = "" # to be assigned in extconf.rb
+ $CFLAGS = ""
+ $LDFLAGS = ""
begin
- system "mkdir " + target unless File.directory?(target)
+ system "mkdir", target unless File.directory?(target)
Dir.chdir target
+ $mdir = target
if $static_ext.size > 0 ||
!File.exist?("./Makefile") ||
- older("./Makefile", "#{$topdir}/ext/@setup@") ||
+ older("./Makefile", "#{$top_srcdir}/ext/@setup@") ||
older("./Makefile", "../extmk.rb") ||
- older("./Makefile", "#{$topdir}/ext/#{target}/extconf.rb")
+ older("./Makefile", "#{$top_srcdir}/ext/#{target}/extconf.rb")
then
$defs = []
- if File.exist?("#{$topdir}/ext/#{target}/extconf.rb")
- load "#{$topdir}/ext/#{target}/extconf.rb"
+ if File.exist?("#{$top_srcdir}/ext/#{target}/extconf.rb")
+ load "#{$top_srcdir}/ext/#{target}/extconf.rb"
else
create_makefile(target);
end
@@ -362,7 +444,7 @@ def extmake(target)
$extlist.push [$static,target]
end
if $install
- system "make install"
+ system "make install DESTDIR=#{$destdir}"
elsif $clean
system "make clean"
else
@@ -370,9 +452,10 @@ def extmake(target)
end
end
if $static
- $extlibs += " " + $LDFLAGS if $LDFLAGS
- $extlibs += " " + $local_libs if $local_libs
+ $extlibs ||= ""
+ $extlibs += " " + $LDFLAGS unless $LDFLAGS == ""
$extlibs += " " + $libs if $libs
+ $extlibs += " " + $local_libs unless $local_libs == ""
end
ensure
Dir.chdir ".."
@@ -381,11 +464,11 @@ end
# get static-link modules
$static_ext = {}
-for setup in ["@setup@", "#{$topdir}/ext/@setup@"]
+for setup in ["@setup@", "#{$top_srcdir}/ext/@setup@"]
if File.file? setup
f = open(setup)
while f.gets()
- $_.chop!
+ $_.chomp!
sub!(/#.*$/, '')
next if /^\s*$/
if /^option +nodynamic/
@@ -399,7 +482,7 @@ for setup in ["@setup@", "#{$topdir}/ext/@setup@"]
end
end
-for d in Dir["#{$topdir}/ext/*"]
+for d in Dir["#{$top_srcdir}/ext/*"]
File.directory?(d) || next
File.file?(d + "/MANIFEST") || next
@@ -429,15 +512,16 @@ if $cache_mod
end
exit if $install or $clean
-$extinit += ""
+$extinit = "" unless $extinit
if $extlist.size > 0
for s,t in $extlist
- f = format("%s/%s.o", s, t)
+ f = format("%s/%s.a", s, t)
if File.exist?(f)
$extinit += format("\
\tInit_%s();\n\
\trb_provide(\"%s.o\");\n\
", t, t)
+ $extobjs = "" unless $extobjs
$extobjs += "ext/"
$extobjs += f
$extobjs += " "
@@ -446,7 +530,7 @@ if $extlist.size > 0
end
end
- if older("extinit.c", "#{$topdir}/ext/@setup@")
+ if older("extinit.c", "#{$top_srcdir}/ext/@setup@")
f = open("extinit.c", "w")
f.printf "void Init_ext() {\n"
f.printf $extinit
@@ -461,17 +545,24 @@ if $extlist.size > 0
Dir.chdir ".."
- if older("ruby@binsuffix@", "#{$topdir}/ext/@setup@") or older("ruby@binsuffix@", "miniruby@binsuffix@")
+ if older("ruby@binsuffix@", "#{$top_srcdir}/ext/@setup@") or older("ruby@binsuffix@", "miniruby@binsuffix@")
`rm -f ruby@binsuffix@`
end
- $extobjs = "ext/extinit.o " + $extobjs
+ if $extobjs
+ $extobjs = "ext/extinit.o " + $extobjs
+ else
+ $extobjs = "ext/extinit.o "
+ end
+ if PLATFORM =~ /m68k-human|beos/
+ $extlibs.gsub!("-L/usr/local/lib", "") if $extlibs
+ end
system format('make ruby@binsuffix@ EXTOBJS="%s" EXTLIBS="%s"', $extobjs, $extlibs)
else
Dir.chdir ".."
if older("ruby@binsuffix@", "miniruby@binsuffix@")
`rm -f ruby@binsuffix@`
- `cp miniruby@binsuffix@ ruby@binsuffix@`
+ system("make ruby@binsuffix@")
end
end
diff --git a/ext/extmk.rb.nt b/ext/extmk.rb.nt
index 6792f2717b..5836e5c681 100644
--- a/ext/extmk.rb.nt
+++ b/ext/extmk.rb.nt
@@ -1,5 +1,7 @@
#! /usr/local/bin/ruby
+$".push 'mkmf.rb' #"
+
if ARGV[0] == 'static'
$force_static = TRUE
ARGV.shift
@@ -379,7 +381,7 @@ def extmake(target)
end
end
if $static
- #$extlibs = " "
+ $extlibs = " "
$extlibs += " " + $LDFLAGS if $LDFLAGS
$extlibs += " " + $local_libs if $local_libs
$extlibs += " " + $libs if $libs
@@ -438,6 +440,8 @@ if $cache_mod
end
exit if $install or $clean
+$extinit = " " unless $extinit
+$extobjs = ""
if $extlist.size > 0
for s,t in $extlist
#for s,t in $static_ext
diff --git a/ext/fcntl/fcntl.c b/ext/fcntl/fcntl.c
index 17aacb13c3..186f9ac893 100644
--- a/ext/fcntl/fcntl.c
+++ b/ext/fcntl/fcntl.c
@@ -5,7 +5,7 @@
$Author$
created at: Mon Apr 7 18:53:05 JST 1997
- Copyright (C) 1997 Yukihiro Matsumoto
+ Copyright (C) 1997-1998 Yukihiro Matsumoto
************************************************/
diff --git a/ext/kconv/kconv.c b/ext/kconv/kconv.c
index 6778afcfe6..a3349826f1 100644
--- a/ext/kconv/kconv.c
+++ b/ext/kconv/kconv.c
@@ -1780,12 +1780,30 @@ kconv_kconv(argc, argv)
VALUE src, dst;
VALUE in, out;
int in_code, out_code;
+ char *codename = 0;
rb_scan_args(argc, argv, "12", &src, &out, &in);
Check_Type(src, T_STRING);
if (NIL_P(out)) {
- out_code = _JIS;
+ codename = rb_get_kcode();
+ goto codeselect;
+ }
+ else if (TYPE(out) == T_STRING) {
+ codename = RSTRING(out)->ptr;
+ codeselect:
+ switch (codename[0]) {
+ case 'E': case 'e':
+ out_code = _EUC;
+ break;
+ case 'S': case 's':
+ out_code = _SJIS;
+ break;
+ case 'J': case 'j':
+ default:
+ out_code = _JIS;
+ break;
+ }
}
else {
out_code = NUM2INT(out);
@@ -1794,12 +1812,28 @@ kconv_kconv(argc, argv)
if (NIL_P(in)) {
in_code = _AUTO;
}
+ else if (TYPE(in) == T_STRING) {
+ switch (RSTRING(in)->ptr[0]) {
+ case 'E': case 'e':
+ in_code = _EUC;
+ break;
+ case 'S': case 's':
+ in_code = _SJIS;
+ break;
+ case 'J': case 'j':
+ in_code = _JIS;
+ break;
+ default:
+ in_code = _AUTO;
+ break;
+ }
+ }
else {
in_code = NUM2INT(in);
if (in_code == _NOCONV) return (VALUE)src;
}
- dst = str_new(0, RSTRING(src)->len*3+10); /* large enough? */
+ dst = rb_str_new(0, RSTRING(src)->len*3+10); /* large enough? */
RSTRING(dst)->len = do_kconv(RSTRING(src)->ptr, RSTRING(dst)->ptr, RSTRING(dst)->len, out_code, in_code);
return dst;
@@ -1813,7 +1847,7 @@ kconv_tojis(obj, src)
Check_Type(src, T_STRING);
- dst = str_new(0, RSTRING(src)->len*3+10); /* large enough? */
+ dst = rb_str_new(0, RSTRING(src)->len*3+10); /* large enough? */
RSTRING(dst)->len = do_kconv(RSTRING(src)->ptr, RSTRING(dst)->ptr, RSTRING(dst)->len, _JIS, _AUTO);
return dst;
@@ -1827,7 +1861,7 @@ kconv_toeuc(obj, src)
Check_Type(src, T_STRING);
- dst = str_new(0, RSTRING(src)->len*3+10); /* large enough? */
+ dst = rb_str_new(0, RSTRING(src)->len*3+10); /* large enough? */
RSTRING(dst)->len = do_kconv(RSTRING(src)->ptr, RSTRING(dst)->ptr, RSTRING(dst)->len, _EUC, _AUTO);
return (VALUE)dst;
@@ -1841,7 +1875,7 @@ kconv_tosjis(obj, src)
Check_Type(src, T_STRING);
- dst = str_new(0, RSTRING(src)->len*3+10); /* large enough? */
+ dst = rb_str_new(0, RSTRING(src)->len*3+10); /* large enough? */
RSTRING(dst)->len = do_kconv(RSTRING(src)->ptr, RSTRING(dst)->ptr, RSTRING(dst)->len, _SJIS, _AUTO);
return dst;
@@ -1857,10 +1891,29 @@ static VALUE
kconv_guess(obj, src)
VALUE obj, src;
{
- unsigned char *p = RSTRING(src)->ptr;
- unsigned char *pend = p + RSTRING(src)->len;
+ unsigned char *p;
+ unsigned char *pend;
+ int sequence_counter = 0;
+
+ Check_Type(src, T_STRING);
+
+ p = RSTRING(src)->ptr;
+ pend = p + RSTRING(src)->len;
+
+#define INCR do {\
+ p++;\
+ if (p==pend) return INT2FIX(_UNKNOWN);\
+ sequence_counter++;\
+ if (sequence_counter % 2 == 1 && *p != 0xa4)\
+ sequence_counter = 0;\
+ if (6 <= sequence_counter) {\
+ sequence_counter = 0;\
+ return INT2FIX(_EUC);\
+ }\
+} while (0)
-#define INCR {p++;if (p==pend) return INT2FIX(_UNKNOWN);}
+ if (*p == 0xa4)
+ sequence_counter = 1;
while (p<pend) {
if (*p == '\033') {
@@ -1874,37 +1927,41 @@ kconv_guess(obj, src)
if (0x81 <= *p && *p <= 0x8d) {
return INT2FIX(_SJIS);
}
- if (*p == 0x8e) {
+ if (0x8f <= *p && *p <= 0x9f) {
+ return INT2FIX(_SJIS);
+ }
+ if (*p == 0x8e) { /* SS2 */
INCR;
if ((0x40 <= *p && *p <= 0x7e) ||
(0x80 <= *p && *p <= 0xa0) ||
(0xe0 <= *p && *p <= 0xfc))
return INT2FIX(_SJIS);
}
- if (0xa1 <= *p && *p <= 0xdf) {
+ else if (0xa1 <= *p && *p <= 0xdf) {
INCR;
if (0xf0 <= *p && *p <= 0xfe)
return INT2FIX(_EUC);
if (0xe0 <= *p && *p <= 0xef) {
- while (*p >= 0x40) {
+ while (p < pend && *p >= 0x40) {
if (*p >= 0x81) {
- if (0x8d <= *p || (0x8f <= *p && *p <= 0x9f)) {
+ if (*p <= 0x8d || (0x8f <= *p && *p <= 0x9f)) {
return INT2FIX(_SJIS);
}
else if (0xfd <= *p && *p <= 0xfe) {
return INT2FIX(_EUC);
}
}
+ INCR;
}
}
- if (*p <= 0x9f) {
+ else if (*p <= 0x9f) {
return INT2FIX(_SJIS);
}
}
- if (0xf0 <= *p && *p <= 0xfe) {
+ else if (0xf0 <= *p && *p <= 0xfe) {
return INT2FIX(_EUC);
}
- if (0xe0 <= *p && *p <= 0xef) {
+ else if (0xe0 <= *p && *p <= 0xef) {
INCR;
if ((0x40 <= *p && *p <= 0x7e) ||
(0x80 <= *p && *p <= 0xa0)) {
@@ -1914,7 +1971,7 @@ kconv_guess(obj, src)
return INT2FIX(_EUC);
}
}
- p++;
+ INCR;
}
return INT2FIX(_UNKNOWN);
}
diff --git a/ext/md5/md5init.c b/ext/md5/md5init.c
index 47f913792f..a825f96d47 100644
--- a/ext/md5/md5init.c
+++ b/ext/md5/md5init.c
@@ -5,7 +5,7 @@
$Author$
created at: Fri Aug 2 09:24:12 JST 1996
- Copyright (C) 1995 Yukihiro Matsumoto
+ Copyright (C) 1995-1998 Yukihiro Matsumoto
************************************************/
/* This module provides an interface to the RSA Data Security,
@@ -42,7 +42,7 @@ md5_digest(obj)
ctx = *md5;
MD5Final(digest, &ctx);
- return str_new(digest, 16);
+ return rb_str_new(digest, 16);
}
static VALUE
@@ -53,7 +53,7 @@ md5_clone(obj)
MD5_CTX *md5, *md5_new;
Data_Get_Struct(obj, MD5_CTX, md5);
- obj = Data_Make_Struct(CLASS_OF(obj), MD5_CTX, 0, 0, md5_new);
+ obj = Data_Make_Struct(CLASS_OF(obj), MD5_CTX, 0, free, md5_new);
*md5_new = *md5;
return obj;
@@ -61,6 +61,9 @@ md5_clone(obj)
static VALUE
md5_new(argc, argv, class)
+ int argc;
+ VALUE* argv;
+ VALUE class;
{
int i;
VALUE arg, obj;
@@ -69,18 +72,19 @@ md5_new(argc, argv, class)
rb_scan_args(argc, argv, "01", &arg);
if (!NIL_P(arg)) Check_Type(arg, T_STRING);
- obj = Data_Make_Struct(class, MD5_CTX, 0, 0, md5);
+ obj = Data_Make_Struct(class, MD5_CTX, 0, free, md5);
MD5Init(md5);
if (!NIL_P(arg)) {
md5_update(obj, arg);
}
+ rb_obj_call_init(obj);
return obj;
}
Init_md5()
{
- cMD5 = rb_define_class("MD5", cObject);
+ cMD5 = rb_define_class("MD5", rb_cObject);
rb_define_singleton_method(cMD5, "new", md5_new, -1);
diff --git a/ext/socket/depend b/ext/socket/depend
index 3d54fa073c..6e8c3b7d97 100644
--- a/ext/socket/depend
+++ b/ext/socket/depend
@@ -1 +1 @@
-socket.o : socket.c $(hdrdir)/ruby.h $(hdrdir)/config.h $(hdrdir)/defines.h $(hdrdir)/io.h $(hdrdir)/sig.h
+socket.o : socket.c $(hdrdir)/ruby.h $(hdrdir)/config.h $(hdrdir)/defines.h $(hdrdir)/rubyio.h $(hdrdir)/rubysig.h
diff --git a/ext/socket/extconf.rb b/ext/socket/extconf.rb
index f719723864..449d5a2785 100644
--- a/ext/socket/extconf.rb
+++ b/ext/socket/extconf.rb
@@ -1,18 +1,22 @@
-$LDFLAGS = "-L/usr/local/lib"
+require 'mkmf'
+$LDFLAGS = "-L/usr/local/lib" if File.directory?("/usr/local/lib")
case PLATFORM
when /mswin32/
test_func = "WSACleanup"
have_library("wsock32", "WSACleanup")
when /cygwin32/
- test_func = "cygwin32_socket"
+ test_func = "socket"
+when /beos/
+ test_func = "socket"
+ have_library("net", "socket")
else
test_func = "socket"
+ have_library("nsl", "t_open")
have_library("socket", "socket")
- have_library("inet", "gethostbyname")
- have_library("nsl", "gethostbyname")
end
have_header("sys/un.h")
if have_func(test_func)
+ have_func("inet_aton")
have_func("hsterror")
unless have_func("gethostname")
have_func("uname")
diff --git a/ext/socket/socket.c b/ext/socket/socket.c
index f5d191b056..e9bdbc9e8c 100644
--- a/ext/socket/socket.c
+++ b/ext/socket/socket.c
@@ -9,7 +9,8 @@
************************************************/
#include "ruby.h"
-#include "io.h"
+#include "rubyio.h"
+#include "rubysig.h"
#include <stdio.h>
#include <sys/types.h>
#ifndef NT
@@ -22,7 +23,14 @@
#include <sys/un.h>
#endif
-#if defined(THREAD) && defined(HAVE_FCNTL)
+#ifdef USE_CWGUSI
+extern int fileno(FILE *stream); /* <unix.mac.h> */
+extern int rb_thread_select(int, fd_set*, fd_set*, fd_set*, struct timeval*); /* thread.c */
+# include <sys/errno.h>
+# include <GUSI.h>
+#endif
+
+#if defined(USE_THREAD) && defined(HAVE_FCNTL)
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
@@ -34,30 +42,25 @@
#define EWOULDBLOCK EAGAIN
#endif
-extern VALUE cIO;
-extern VALUE cInteger;
-
-VALUE cBasicSocket;
-VALUE cIPsocket;
-VALUE cTCPsocket;
-VALUE cTCPserver;
-VALUE cUDPsocket;
+VALUE rb_cBasicSocket;
+VALUE rb_cIPsocket;
+VALUE rb_cTCPsocket;
+VALUE rb_cTCPserver;
+VALUE rb_cUDPsocket;
#ifdef AF_UNIX
-VALUE cUNIXsocket;
-VALUE cUNIXserver;
+VALUE rb_cUNIXsocket;
+VALUE rb_cUNIXserver;
#endif
-VALUE cSocket;
+VALUE rb_cSocket;
-extern VALUE eException;
-static VALUE eSocket;
+static VALUE rb_eSocket;
#ifdef SOCKS
-VALUE cSOCKSsocket;
+VALUE rb_cSOCKSsocket;
void SOCKSinit();
int Rconnect();
#endif
-FILE *rb_fdopen();
char *strdup();
#define INET_CLIENT 0
@@ -69,9 +72,12 @@ static void
sock_finalize(fptr)
OpenFile *fptr;
{
- SOCKET s = fileno(fptr->f);
+ SOCKET s;
+
+ if (!fptr->f) return;
+ s = fileno(fptr->f);
free(fptr->f);
- free(fptr->f2);
+ if (fptr->f2) free(fptr->f2);
closesocket(s);
}
#endif
@@ -85,6 +91,7 @@ sock_new(class, fd)
NEWOBJ(sock, struct RFile);
OBJSETUP(sock, class, T_FILE);
+ rb_secure(4);
MakeOpenFile(sock, fp);
fp->f = rb_fdopen(fd, "r");
#ifdef NT
@@ -92,7 +99,8 @@ sock_new(class, fd)
#endif
fp->f2 = rb_fdopen(fd, "w");
fp->mode = FMODE_READWRITE;
- io_unbuffered(fp);
+ rb_io_unbuffered(fp);
+ rb_obj_call_init((VALUE)sock);
return (VALUE)sock;
}
@@ -107,12 +115,15 @@ bsock_shutdown(argc, argv, sock)
int how;
OpenFile *fptr;
+ rb_secure(4);
rb_scan_args(argc, argv, "01", &howto);
if (howto == Qnil)
how = 2;
else {
how = NUM2INT(howto);
- if (how < 0 && how > 2) how = 2;
+ if (how < 0 || 2 < how) {
+ rb_raise(rb_eArgError, "`how' should be either 0, 1, 2");
+ }
}
GetOpenFile(sock, fptr);
if (shutdown(fileno(fptr->f), how) == -1)
@@ -122,9 +133,57 @@ bsock_shutdown(argc, argv, sock)
}
static VALUE
+bsock_close_read(sock)
+ VALUE sock;
+{
+ OpenFile *fptr;
+
+ rb_secure(4);
+ GetOpenFile(sock, fptr);
+ if (fptr->f2 == 0) {
+ return rb_io_close(sock);
+ }
+ if (shutdown(fileno(fptr->f), 0) == -1)
+ rb_sys_fail(0);
+ fptr->mode &= ~FMODE_READABLE;
+#ifdef NT
+ free(fptr->f);
+#else
+ fclose(fptr->f);
+#endif
+ fptr->f = fptr->f2;
+ fptr->f2 = 0;
+
+ return Qnil;
+}
+
+static VALUE
+bsock_close_write(sock)
+ VALUE sock;
+{
+ OpenFile *fptr;
+
+ rb_secure(4);
+ GetOpenFile(sock, fptr);
+ if (fptr->f2 == 0) {
+ return rb_io_close(sock);
+ }
+ if (shutdown(fileno(fptr->f), 1) == -1)
+ rb_sys_fail(0);
+ fptr->mode &= ~FMODE_WRITABLE;
+#ifdef NT
+ free(fptr->f2);
+#else
+ fclose(fptr->f2);
+#endif
+ fptr->f2 = 0;
+
+ return Qnil;
+}
+
+static VALUE
bsock_setsockopt(sock, lev, optname, val)
- VALUE sock, lev, optname;
- struct RString *val;
+ VALUE sock, lev, optname, val;
{
int level, option;
OpenFile *fptr;
@@ -148,8 +207,7 @@ bsock_setsockopt(sock, lev, optname, val)
v = (char*)&i; vlen = sizeof(i);
break;
default:
- Check_Type(val, T_STRING);
- v = val->ptr; vlen = val->len;
+ v = rb_str2cstr(val, &vlen);
}
GetOpenFile(sock, fptr);
@@ -163,6 +221,7 @@ static VALUE
bsock_getsockopt(sock, lev, optname)
VALUE sock, lev, optname;
{
+#if !defined(__BEOS__)
int level, option, len;
char *buf;
OpenFile *fptr;
@@ -176,7 +235,10 @@ bsock_getsockopt(sock, lev, optname)
if (getsockopt(fileno(fptr->f), level, option, buf, &len) < 0)
rb_sys_fail(fptr->path);
- return str_new(buf, len);
+ return rb_str_new(buf, len);
+#else
+ rb_notimplement();
+#endif
}
static VALUE
@@ -190,7 +252,7 @@ bsock_getsockname(sock)
GetOpenFile(sock, fptr);
if (getsockname(fileno(fptr->f), (struct sockaddr*)buf, &len) < 0)
rb_sys_fail("getsockname(2)");
- return str_new(buf, len);
+ return rb_str_new(buf, len);
}
static VALUE
@@ -204,7 +266,7 @@ bsock_getpeername(sock)
GetOpenFile(sock, fptr);
if (getpeername(fileno(fptr->f), (struct sockaddr*)buf, &len) < 0)
rb_sys_fail("getpeername(2)");
- return str_new(buf, len);
+ return rb_str_new(buf, len);
}
static VALUE
@@ -213,31 +275,32 @@ bsock_send(argc, argv, sock)
VALUE *argv;
VALUE sock;
{
- struct RString *msg, *to;
+ VALUE msg, to;
VALUE flags;
OpenFile *fptr;
FILE *f;
int fd, n;
+ char *m, *t;
+ int mlen, tlen;
rb_secure(4);
rb_scan_args(argc, argv, "21", &msg, &flags, &to);
- Check_Type(msg, T_STRING);
-
GetOpenFile(sock, fptr);
- f = fptr->f2?fptr->f2:fptr->f;
+ f = GetWriteFile(fptr);
fd = fileno(f);
retry:
-#ifdef THREAD
- thread_fd_writable(fd);
+#ifdef USE_THREAD
+ rb_thread_fd_writable(fd);
#endif
+ m = rb_str2cstr(msg, &mlen);
if (RTEST(to)) {
- Check_Type(to, T_STRING);
- n = sendto(fd, msg->ptr, msg->len, NUM2INT(flags),
- (struct sockaddr*)to->ptr, to->len);
+ t = rb_str2cstr(to, &tlen);
+ n = sendto(fd, m, mlen, NUM2INT(flags),
+ (struct sockaddr*)t, tlen);
}
else {
- n = send(fd, msg->ptr, msg->len, NUM2INT(flags));
+ n = send(fd, m, mlen, NUM2INT(flags));
}
if (n < 0) {
switch (errno) {
@@ -246,8 +309,8 @@ bsock_send(argc, argv, sock)
#if EAGAIN != EWOULDBLOCK
case EAGAIN:
#endif
-#ifdef THREAD
- thread_schedule();
+#ifdef USE_THREAD
+ rb_thread_schedule();
#endif
goto retry;
}
@@ -277,7 +340,6 @@ s_recv(sock, argc, argv, from)
enum sock_recv_type from;
{
OpenFile *fptr;
- FILE f;
VALUE str;
char buf[1024];
int fd, alen = sizeof buf;
@@ -289,12 +351,12 @@ s_recv(sock, argc, argv, from)
if (flg == Qnil) flags = 0;
else flags = NUM2INT(flg);
- str = str_new(0, NUM2INT(len));
+ str = rb_str_new(0, NUM2INT(len));
GetOpenFile(sock, fptr);
fd = fileno(fptr->f);
-#ifdef THREAD
- thread_wait_fd(fd);
+#ifdef USE_THREAD
+ rb_thread_wait_fd(fd);
#endif
TRAP_BEG;
retry:
@@ -309,38 +371,35 @@ s_recv(sock, argc, argv, from)
#if EAGAIN != EWOULDBLOCK
case EAGAIN:
#endif
-#ifdef THREAD
- thread_schedule();
+#ifdef USE_THREAD
+ rb_thread_schedule();
#endif
goto retry;
}
rb_sys_fail("recvfrom(2)");
}
- str_taint(str);
+ rb_obj_taint(str);
switch (from) {
case RECV_RECV:
return (VALUE)str;
case RECV_TCP:
if (alen != sizeof(struct sockaddr_in)) {
- TypeError("sockaddr size differs - should not happen");
+ rb_raise(rb_eTypeError, "sockaddr size differs - should not happen");
}
- return assoc_new(str, ipaddr((struct sockaddr_in *)buf));
+ return rb_assoc_new(str, ipaddr((struct sockaddr_in *)buf));
case RECV_UDP:
{
VALUE addr = ipaddr((struct sockaddr_in *)buf);
- return assoc_new(str, assoc_new(RARRAY(addr)->ptr[2],
- RARRAY(addr)->ptr[1]));
+ return rb_assoc_new(str, rb_assoc_new(RARRAY(addr)->ptr[2],
+ RARRAY(addr)->ptr[1]));
}
#ifdef HAVE_SYS_UN_H
case RECV_UNIX:
- if (alen != sizeof(struct sockaddr_un)) {
- TypeError("sockaddr size differs - should not happen");
- }
- return assoc_new(str, unixaddr((struct sockaddr_un *)buf));
+ return rb_assoc_new(str, unixaddr((struct sockaddr_un *)buf));
#endif
case RECV_SOCKET:
- return assoc_new(str, str_new(buf, alen));
+ return rb_assoc_new(str, rb_str_new(buf, alen));
}
}
@@ -353,7 +412,96 @@ bsock_recv(argc, argv, sock)
return s_recv(sock, argc, argv, RECV_RECV);
}
-#if defined(THREAD) && defined(HAVE_FCNTL)
+static VALUE
+mkipaddr(x)
+ unsigned long x;
+{
+ char buf[16];
+
+ x = ntohl(x);
+ sprintf(buf, "%d.%d.%d.%d",
+ (int) (x>>24) & 0xff, (int) (x>>16) & 0xff,
+ (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff);
+ return rb_str_new2(buf);
+}
+
+static VALUE
+ipaddr(sockaddr)
+ struct sockaddr_in *sockaddr;
+{
+ VALUE family, port, addr1, addr2;
+ VALUE ary;
+ struct hostent *hostent;
+
+ family = rb_str_new2("AF_INET");
+ hostent = gethostbyaddr((char*)&sockaddr->sin_addr.s_addr,
+ sizeof(sockaddr->sin_addr),
+ AF_INET);
+ addr1 = 0;
+ if (hostent) {
+ addr1 = rb_str_new2(hostent->h_name);
+ }
+ addr2 = mkipaddr(sockaddr->sin_addr.s_addr);
+ if (!addr1) addr1 = addr2;
+
+ port = INT2FIX(ntohs(sockaddr->sin_port));
+ ary = rb_ary_new3(4, family, port, addr1, addr2);
+
+ return ary;
+}
+
+#ifndef HAVE_INET_ATON
+static unsigned long
+inet_aton(host, inp)
+ char *host;
+ struct in_addr *inp;
+{
+ int d1, d2, d3, d4;
+ char ch;
+
+ if (sscanf(host, "%d.%d.%d.%d%c", &d1, &d2, &d3, &d4, &ch) == 4 &&
+ 0 <= d1 && d1 <= 255 && 0 <= d2 && d2 <= 255 &&
+ 0 <= d3 && d3 <= 255 && 0 <= d4 && d4 <= 255) {
+ inp->s_addr = htonl(
+ ((long) d1 << 24) | ((long) d2 << 16) |
+ ((long) d3 << 8) | ((long) d4 << 0));
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+static void
+setipaddr(name, addr)
+ char *name;
+ struct sockaddr_in *addr;
+{
+ struct hostent *hp;
+
+ if (name[0] == 0) {
+ addr->sin_addr.s_addr = INADDR_ANY;
+ }
+ else if (name[0] == '<' && strcmp(name, "<broadcast>") == 0) {
+ addr->sin_addr.s_addr = INADDR_BROADCAST;
+ }
+ else if (inet_aton(name, &addr->sin_addr) != 0) {
+ /* ok to set addr->sin_addr */
+ }
+ else {
+ hp = gethostbyname(name);
+ if (!hp) {
+#ifdef HAVE_HSTRERROR
+ extern int h_errno;
+ rb_raise(rb_eSocket, (char *)hstrerror(h_errno));
+#else
+ rb_raise(rb_eSocket, "host not found");
+#endif
+ }
+ memcpy((char *) &addr->sin_addr, hp->h_addr, hp->h_length);
+ }
+}
+
+#if defined(USE_THREAD) && defined(HAVE_FCNTL)
static int
thread_connect(fd, sockaddr, len, type)
int fd;
@@ -396,7 +544,7 @@ thread_connect(fd, sockaddr, len, type)
#endif
FD_ZERO(&fds);
FD_SET(fd, &fds);
- thread_select(fd+1, 0, &fds, 0, 0, 0);
+ rb_thread_select(fd+1, 0, &fds, 0, 0);
continue;
#endif
@@ -434,26 +582,25 @@ open_inet(class, h, serv, type)
int hostaddr, hostaddrPtr[2];
int servport;
char *syscall;
- VALUE sock;
if (h) {
Check_SafeStr(h);
host = RSTRING(h)->ptr;
hostent = gethostbyname(host);
if (hostent == NULL) {
- hostaddr = inet_addr(host);
- if (hostaddr == -1) {
+ if (!inet_aton(host, &sockaddr.sin_addr)) {
if (type == INET_SERVER && !strlen(host))
hostaddr = INADDR_ANY;
else {
#ifdef HAVE_HSTRERROR
extern int h_errno;
- Raise(eSocket, (char *)hstrerror(h_errno));
+ rb_raise(rb_eSocket, (char *)hstrerror(h_errno));
#else
- Raise(eSocket, "host not found");
+ rb_raise(rb_eSocket, "host not found");
#endif
}
}
+ hostaddr = sockaddr.sin_addr.s_addr;
_hostent.h_addr_list = (char **)hostaddrPtr;
_hostent.h_addr_list[0] = (char *)&hostaddr;
_hostent.h_addr_list[1] = NULL;
@@ -467,24 +614,30 @@ open_inet(class, h, serv, type)
servport = FIX2UINT(serv);
goto setup_servent;
}
- Check_Type(serv, T_STRING);
- servent = getservbyname(RSTRING(serv)->ptr, "tcp");
+ servent = getservbyname(STR2CSTR(serv), "tcp");
if (servent == NULL) {
- servport = strtoul(RSTRING(serv)->ptr, 0, 0);
- if (servport == -1) {
- Raise(eSocket, "no such servce %s", RSTRING(serv)->ptr);
+ char *s = STR2CSTR(serv);
+ char *end;
+
+ servport = strtoul(s, &end, 0);
+ if (*end != '\0') {
+ rb_raise(rb_eSocket, "no such servce %s", s);
}
setup_servent:
_servent.s_port = htons(servport);
_servent.s_proto = "tcp";
servent = &_servent;
}
+#ifdef __BEOS__
+ fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+#else
protoent = getprotobyname(servent->s_proto);
if (protoent == NULL) {
- Raise(eSocket, "no such proto %s", servent->s_proto);
+ rb_raise(rb_eSocket, "no such proto %s", servent->s_proto);
}
fd = socket(AF_INET, SOCK_STREAM, protoent->p_proto);
+#endif
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
@@ -505,9 +658,9 @@ open_inet(class, h, serv, type)
syscall = "bind(2)";
}
else {
-#if defined(THREAD) && defined(HAVE_FCNTL)
+#if defined(USE_THREAD) && defined(HAVE_FCNTL)
status = thread_connect(fd, (struct sockaddr*)&sockaddr,
- sizeof(sockaddr), type);
+ sizeof(sockaddr), type);
#else
#ifdef SOCKS
if (type == INET_SOCKS) {
@@ -523,7 +676,7 @@ open_inet(class, h, serv, type)
}
if (status < 0) {
- close (fd);
+ close(fd);
rb_sys_fail(syscall);
}
if (type == INET_SERVER) listen(fd, 5);
@@ -558,6 +711,49 @@ socks_s_open(class, host, serv)
#endif
static VALUE
+tcp_s_gethostbyname(obj, host)
+ VALUE obj, host;
+{
+ struct sockaddr_in addr;
+ struct hostent *h;
+ char **pch;
+ VALUE ary, names;
+
+ setipaddr(STR2CSTR(host), &addr);
+ h = gethostbyaddr((char *)&addr.sin_addr,
+ sizeof(addr.sin_addr),
+ AF_INET);
+
+ if (h == NULL) {
+#ifdef HAVE_HSTRERROR
+ extern int h_errno;
+ rb_raise(rb_eSocket, (char *)hstrerror(h_errno));
+#else
+ rb_raise(rb_eSocket, "host not found");
+#endif
+ }
+ ary = rb_ary_new();
+ rb_ary_push(ary, rb_str_new2(h->h_name));
+ names = rb_ary_new();
+ rb_ary_push(ary, names);
+ for (pch = h->h_aliases; *pch; pch++) {
+ rb_ary_push(names, rb_str_new2(*pch));
+ }
+ rb_ary_push(ary, NUM2INT(h->h_addrtype));
+#ifdef h_addr
+ for (pch = h->h_addr_list; *pch; pch++) {
+ memcpy((char *) &addr.sin_addr, *pch, h->h_length);
+ rb_ary_push(ary, mkipaddr(addr.sin_addr.s_addr));
+ }
+#else
+ memcpy((char *)&addr.sin_addr, h->h_addr, h->h_length);
+ rb_ary_push(ary, mkipaddr(addr.sin_addr.s_addr));
+#endif
+
+ return ary;
+}
+
+static VALUE
tcp_svr_s_open(argc, argv, class)
int argc;
VALUE *argv;
@@ -581,8 +777,8 @@ s_accept(class, fd, sockaddr, len)
int fd2;
retry:
-#ifdef THREAD
- thread_wait_fd(fd);
+#ifdef USE_THREAD
+ rb_thread_wait_fd(fd);
#endif
TRAP_BEG;
fd2 = accept(fd, sockaddr, len);
@@ -594,8 +790,8 @@ s_accept(class, fd, sockaddr, len)
#if EAGAIN != EWOULDBLOCK
case EAGAIN:
#endif
-#ifdef THREAD
- thread_schedule();
+#ifdef USE_THREAD
+ rb_thread_schedule();
#endif
goto retry;
}
@@ -614,7 +810,7 @@ tcp_accept(sock)
GetOpenFile(sock, fptr);
fromlen = sizeof(struct sockaddr_in);
- return s_accept(cTCPsocket, fileno(fptr->f),
+ return s_accept(rb_cTCPsocket, fileno(fptr->f),
(struct sockaddr*)&from, &fromlen);
}
@@ -670,81 +866,6 @@ open_unix(class, path, server)
}
#endif
-static void
-setipaddr(name, addr)
- char *name;
- struct sockaddr_in *addr;
-{
- int d1, d2, d3, d4;
- char ch;
- struct hostent *hp;
- long x;
-
- if (name[0] == 0) {
- addr->sin_addr.s_addr = INADDR_ANY;
- }
- else if (name[0] == '<' && strcmp(name, "<broadcast>") == 0) {
- addr->sin_addr.s_addr = INADDR_BROADCAST;
- }
- else if (sscanf(name, "%d.%d.%d.%d%c", &d1, &d2, &d3, &d4, &ch) == 4 &&
- 0 <= d1 && d1 <= 255 && 0 <= d2 && d2 <= 255 &&
- 0 <= d3 && d3 <= 255 && 0 <= d4 && d4 <= 255) {
- addr->sin_addr.s_addr = htonl(
- ((long) d1 << 24) | ((long) d2 << 16) |
- ((long) d3 << 8) | ((long) d4 << 0));
- }
- else {
- hp = gethostbyname(name);
- if (!hp) {
-#ifdef HAVE_HSTRERROR
- extern int h_errno;
- Raise(eSocket, (char *)hstrerror(h_errno));
-#else
- Raise(eSocket, "host not found");
-#endif
- }
- memcpy((char *) &addr->sin_addr, hp->h_addr, hp->h_length);
- }
-}
-
-static VALUE
-mkipaddr(x)
- unsigned long x;
-{
- char buf[16];
-
- x = ntohl(x);
- sprintf(buf, "%d.%d.%d.%d",
- (int) (x>>24) & 0xff, (int) (x>>16) & 0xff,
- (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff);
- return str_new2(buf);
-}
-
-static VALUE
-ipaddr(sockaddr)
- struct sockaddr_in *sockaddr;
-{
- VALUE family, port, addr1, addr2;
- VALUE ary;
- struct hostent *hostent;
-
- family = str_new2("AF_INET");
- hostent = gethostbyaddr((char*)&sockaddr->sin_addr.s_addr,
- sizeof(sockaddr->sin_addr),
- AF_INET);
- addr1 = 0;
- if (hostent) {
- addr1 = str_new2(hostent->h_name);
- }
- addr2 = mkipaddr(sockaddr->sin_addr.s_addr);
- if (!addr1) addr1 = addr2;
-
- port = INT2FIX(ntohs(sockaddr->sin_port));
- ary = ary_new3(4, family, port, addr1, addr2);
-
- return ary;
-}
-
static VALUE
ip_addr(sock)
VALUE sock;
@@ -781,13 +902,12 @@ ip_s_getaddress(obj, host)
{
struct sockaddr_in addr;
- if (obj_is_kind_of(host, cInteger)) {
+ if (rb_obj_is_kind_of(host, rb_cInteger)) {
int i = NUM2INT(host);
addr.sin_addr.s_addr = htonl(i);
}
else {
- Check_Type(host, T_STRING);
- setipaddr(RSTRING(host)->ptr, &addr);
+ setipaddr(STR2CSTR(host), &addr);
}
return mkipaddr(addr.sin_addr.s_addr);
@@ -805,37 +925,36 @@ udp_addrsetup(host, port, addr)
VALUE host, port;
struct sockaddr_in *addr;
{
- struct hostent *hostent;
-
memset(addr, 0, sizeof(struct sockaddr_in));
addr->sin_family = AF_INET;
if (NIL_P(host)) {
addr->sin_addr.s_addr = INADDR_ANY;
}
- else if (obj_is_kind_of(host, cInteger)) {
+ else if (rb_obj_is_kind_of(host, rb_cInteger)) {
int i = NUM2INT(host);
addr->sin_addr.s_addr = htonl(i);
}
else {
- Check_Type(host, T_STRING);
- setipaddr(RSTRING(host)->ptr, addr);
+ setipaddr(STR2CSTR(host), addr);
}
if (FIXNUM_P(port)) {
- addr->sin_port = FIX2INT(port);
+ addr->sin_port = htons(FIX2INT(port));
}
else {
struct servent *servent;
- Check_Type(port, T_STRING);
- servent = getservbyname(RSTRING(port)->ptr, "udp");
+ servent = getservbyname(STR2CSTR(port), "udp");
if (servent) {
addr->sin_port = servent->s_port;
}
else {
- int port = strtoul(RSTRING(port)->ptr, 0, 0);
+ char *s = STR2CSTR(port);
+ char *end;
+ int portno;
- if (port == -1) {
- Raise(eSocket, "no such servce %s", RSTRING(port)->ptr);
+ portno = strtoul(s, &end, 0);
+ if (*end != '\0') {
+ rb_raise(rb_eSocket, "no such servce %s", s);
}
addr->sin_port = htons(port);
}
@@ -859,8 +978,8 @@ udp_connect(sock, host, port)
#if EAGAIN != EWOULDBLOCK
case EAGAIN:
#endif
-#ifdef THREAD
- thread_schedule();
+#ifdef USE_THREAD
+ rb_thread_schedule();
#endif
goto retry;
}
@@ -896,19 +1015,21 @@ udp_send(argc, argv, sock)
OpenFile *fptr;
FILE *f;
int n;
+ char *m;
+ int mlen;
if (argc == 2) {
return bsock_send(argc, argv, sock);
}
rb_scan_args(argc, argv, "4", &mesg, &flags, &host, &port);
- Check_Type(mesg, T_STRING);
udp_addrsetup(host, port, &addr);
GetOpenFile(sock, fptr);
- f = fptr->f2?fptr->f2:fptr->f;
+ f = GetWriteFile(fptr);
+ m = rb_str2cstr(mesg, &mlen);
retry:
- n = sendto(fileno(f), RSTRING(mesg)->ptr, RSTRING(mesg)->len,
- NUM2INT(flags), (struct sockaddr*)&addr, sizeof(addr));
+ n = sendto(fileno(f), m, mlen, NUM2INT(flags),
+ (struct sockaddr*)&addr, sizeof(addr));
if (n < 0) {
switch (errno) {
case EINTR:
@@ -916,8 +1037,8 @@ udp_send(argc, argv, sock)
#if EAGAIN != EWOULDBLOCK
case EAGAIN:
#endif
-#ifdef THREAD
- thread_schedule();
+#ifdef USE_THREAD
+ rb_thread_schedule();
#endif
goto retry;
}
@@ -957,14 +1078,14 @@ unix_path(sock)
rb_sys_fail(0);
fptr->path = strdup(addr.sun_path);
}
- return str_new2(fptr->path);
+ return rb_str_new2(fptr->path);
}
static VALUE
-unix_svr_s_open(class, path)
- VALUE class, path;
+unix_svr_s_open(sock, path)
+ VALUE sock, path;
{
- return open_unix(class, path, 1);
+ return open_unix(sock, path, 1);
}
static VALUE
@@ -986,7 +1107,7 @@ unix_accept(sock)
GetOpenFile(sock, fptr);
fromlen = sizeof(struct sockaddr_un);
- return s_accept(cUNIXsocket, fileno(fptr->f),
+ return s_accept(rb_cUNIXsocket, fileno(fptr->f),
(struct sockaddr*)&from, &fromlen);
}
@@ -994,7 +1115,7 @@ static VALUE
unixaddr(sockaddr)
struct sockaddr_un *sockaddr;
{
- return assoc_new(str_new2("AF_UNIX"),str_new2(sockaddr->sun_path));
+ return rb_assoc_new(rb_str_new2("AF_UNIX"),rb_str_new2(sockaddr->sun_path));
}
static VALUE
@@ -1055,8 +1176,10 @@ setup_domain_and_type(domain, dv, type, tv)
else if (strcmp(ptr, "AF_IMPLINK") == 0)
*dv = AF_IMPLINK;
#endif
+#ifdef PF_INET
else if (strcmp(ptr, "PF_INET") == 0)
*dv = PF_INET;
+#endif
#ifdef PF_UNIX
else if (strcmp(ptr, "PF_UNIX") == 0)
*dv = PF_UNIX;
@@ -1076,7 +1199,7 @@ setup_domain_and_type(domain, dv, type, tv)
*dv = PF_IPX;
#endif
else
- Raise(eSocket, "Unknown socket domain %s", ptr);
+ rb_raise(rb_eSocket, "Unknown socket domain %s", ptr);
}
else {
*dv = NUM2INT(domain);
@@ -1104,7 +1227,7 @@ setup_domain_and_type(domain, dv, type, tv)
*tv = SOCK_PACKET;
#endif
else
- Raise(eSocket, "Unknown socket type %s", ptr);
+ rb_raise(rb_eSocket, "Unknown socket type %s", ptr);
}
else {
*tv = NUM2INT(type);
@@ -1121,6 +1244,7 @@ sock_s_open(class, domain, type, protocol)
setup_domain_and_type(domain, &d, type, &t);
fd = socket(d, t, NUM2INT(protocol));
if (fd < 0) rb_sys_fail("socket(2)");
+
return sock_new(class, fd);
}
@@ -1135,15 +1259,14 @@ static VALUE
sock_s_socketpair(class, domain, type, protocol)
VALUE class, domain, type, protocol;
{
-#if !defined(__CYGWIN32__) && !defined(NT)
- int fd;
+#if !defined(NT) && !defined(__BEOS__)
int d, t, sp[2];
setup_domain_and_type(domain, &d, type, &t);
if (socketpair(d, t, NUM2INT(protocol), sp) < 0)
rb_sys_fail("socketpair(2)");
- return assoc_new(sock_new(class, sp[0]), sock_new(class, sp[1]));
+ return rb_assoc_new(sock_new(class, sp[0]), sock_new(class, sp[1]));
#else
rb_notimplement();
#endif
@@ -1156,7 +1279,7 @@ sock_connect(sock, addr)
OpenFile *fptr;
Check_Type(addr, T_STRING);
- str_modify(addr);
+ rb_str_modify(addr);
GetOpenFile(sock, fptr);
retry:
@@ -1167,8 +1290,8 @@ sock_connect(sock, addr)
#if EAGAIN != EWOULDBLOCK
case EAGAIN:
#endif
-#ifdef THREAD
- thread_schedule();
+#ifdef USE_THREAD
+ rb_thread_schedule();
#endif
goto retry;
}
@@ -1185,7 +1308,7 @@ sock_bind(sock, addr)
OpenFile *fptr;
Check_Type(addr, T_STRING);
- str_modify(addr);
+ rb_str_modify(addr);
GetOpenFile(sock, fptr);
if (bind(fileno(fptr->f), (struct sockaddr*)RSTRING(addr)->ptr, RSTRING(addr)->len) < 0)
@@ -1226,9 +1349,9 @@ sock_accept(sock)
int len = sizeof buf;
GetOpenFile(sock, fptr);
- sock2 = s_accept(cSocket,fileno(fptr->f),(struct sockaddr*)buf,&len);
+ sock2 = s_accept(rb_cSocket,fileno(fptr->f),(struct sockaddr*)buf,&len);
- return assoc_new(sock2, str_new(buf, len));
+ return rb_assoc_new(sock2, rb_str_new(buf, len));
}
#ifdef HAVE_GETHOSTNAME
@@ -1242,7 +1365,7 @@ sock_gethostname(obj)
rb_sys_fail("gethostname");
buf[sizeof buf - 1] = '\0';
- return str_new2(buf);
+ return rb_str_new2(buf);
}
#else
#ifdef HAVE_UNAME
@@ -1256,7 +1379,7 @@ sock_gethostname(obj)
struct utsname un;
uname(&un);
- return str_new2(un.nodename);
+ return rb_str_new2(un.nodename);
}
#else
static VALUE
@@ -1272,32 +1395,31 @@ static VALUE
mkhostent(h)
struct hostent *h;
{
- struct sockaddr_in addr;
char **pch;
VALUE ary, names;
if (h == NULL) {
#ifdef HAVE_HSTRERROR
extern int h_errno;
- Raise(eSocket, (char *)hstrerror(h_errno));
+ rb_raise(rb_eSocket, (char *)hstrerror(h_errno));
#else
- Raise(eSocket, "host not found");
+ rb_raise(rb_eSocket, "host not found");
#endif
}
- ary = ary_new();
- ary_push(ary, str_new2(h->h_name));
- names = ary_new();
- ary_push(ary, names);
+ ary = rb_ary_new();
+ rb_ary_push(ary, rb_str_new2(h->h_name));
+ names = rb_ary_new();
+ rb_ary_push(ary, names);
for (pch = h->h_aliases; *pch; pch++) {
- ary_push(names, str_new2(*pch));
+ rb_ary_push(names, rb_str_new2(*pch));
}
- ary_push(ary, INT2FIX(h->h_length));
+ rb_ary_push(ary, NUM2INT(h->h_addrtype));
#ifdef h_addr
for (pch = h->h_addr_list; *pch; pch++) {
- ary_push(ary, str_new(*pch, h->h_length));
+ rb_ary_push(ary, rb_str_new(*pch, h->h_length));
}
#else
- ary_push(ary, str_new(h->h_addr, h->h_length));
+ rb_ary_push(ary, rb_str_new(h->h_addr, h->h_length));
#endif
return ary;
@@ -1310,13 +1432,12 @@ sock_s_gethostbyname(obj, host)
struct sockaddr_in addr;
struct hostent *h;
- if (obj_is_kind_of(host, cInteger)) {
+ if (rb_obj_is_kind_of(host, rb_cInteger)) {
int i = NUM2INT(host);
addr.sin_addr.s_addr = htonl(i);
}
else {
- Check_Type(host, T_STRING);
- setipaddr(RSTRING(host)->ptr, &addr);
+ setipaddr(STR2CSTR(host), &addr);
}
h = gethostbyaddr((char *)&addr.sin_addr,
sizeof(addr.sin_addr),
@@ -1332,20 +1453,20 @@ sock_s_gethostbyaddr(argc, argv)
{
VALUE vaddr, vtype;
int type;
-
- struct sockaddr_in *addr;
+ int alen;
+ char *addr;
struct hostent *h;
- rb_scan_args(argc, argv, "11", &addr, &type);
- Check_Type(addr, T_STRING);
- if (!NIL_P(type)) {
+ rb_scan_args(argc, argv, "11", &vaddr, &vtype);
+ addr = rb_str2cstr(vaddr, &alen);
+ if (!NIL_P(vtype)) {
type = NUM2INT(vtype);
}
else {
type = AF_INET;
}
- h = gethostbyaddr(RSTRING(addr)->ptr, RSTRING(addr)->len, type);
+ h = gethostbyaddr(addr, alen, type);
return mkhostent(h);
}
@@ -1361,15 +1482,22 @@ sock_s_getservbyaname(argc, argv)
int port;
rb_scan_args(argc, argv, "11", &service, &protocol);
- Check_Type(service, T_STRING);
if (NIL_P(protocol)) proto = "tcp";
- else proto = RSTRING(protocol)->ptr;
+ else proto = STR2CSTR(protocol);
- sp = getservbyname(RSTRING(service)->ptr, proto);
- if (!sp) {
- Raise(eSocket, "service/proto not found");
+ sp = getservbyname(STR2CSTR(service), proto);
+ if (sp) {
+ port = ntohs(sp->s_port);
+ }
+ else {
+ char *s = STR2CSTR(service);
+ char *end;
+
+ port = strtoul(s, &end, 0);
+ if (*end != '\0') {
+ rb_raise(rb_eSocket, "no such servce %s/%s", s, proto);
+ }
}
- port = ntohs(sp->s_port);
return INT2FIX(port);
}
@@ -1377,225 +1505,240 @@ sock_s_getservbyaname(argc, argv)
static VALUE mConst;
static void
-sock_define_const(name, value)
+sock_rb_define_const(name, value)
char *name;
- INT value;
+ int value;
{
- rb_define_const(cSocket, name, INT2FIX(value));
+ rb_define_const(rb_cSocket, name, INT2FIX(value));
rb_define_const(mConst, name, INT2FIX(value));
}
Init_socket()
{
- eSocket = rb_define_class("SocketError", eException);
-
- cBasicSocket = rb_define_class("BasicSocket", cIO);
- rb_undef_method(CLASS_OF(cBasicSocket), "new");
- rb_undef_method(CLASS_OF(cBasicSocket), "open");
- rb_define_method(cBasicSocket, "shutdown", bsock_shutdown, -1);
- rb_define_method(cBasicSocket, "setsockopt", bsock_setsockopt, 3);
- rb_define_method(cBasicSocket, "getsockopt", bsock_getsockopt, 2);
- rb_define_method(cBasicSocket, "getsockname", bsock_getsockname, 0);
- rb_define_method(cBasicSocket, "getpeername", bsock_getpeername, 0);
- rb_define_method(cBasicSocket, "send", bsock_send, -1);
- rb_define_method(cBasicSocket, "recv", bsock_recv, -1);
-
- cIPsocket = rb_define_class("IPsocket", cBasicSocket);
- rb_define_method(cIPsocket, "addr", ip_addr, 0);
- rb_define_method(cIPsocket, "peeraddr", ip_peeraddr, 0);
- rb_define_singleton_method(cIPsocket, "getaddress", ip_s_getaddress, 1);
-
- cTCPsocket = rb_define_class("TCPsocket", cIPsocket);
- rb_define_singleton_method(cTCPsocket, "open", tcp_s_open, 2);
- rb_define_singleton_method(cTCPsocket, "new", tcp_s_open, 2);
- rb_define_method(cTCPsocket, "recvfrom", tcp_recvfrom, -1);
+ rb_eSocket = rb_define_class("SocketError", rb_eStandardError);
+
+ rb_cBasicSocket = rb_define_class("BasicSocket", rb_cIO);
+ rb_undef_method(CLASS_OF(rb_cBasicSocket), "new");
+ rb_undef_method(CLASS_OF(rb_cBasicSocket), "open");
+ rb_define_method(rb_cBasicSocket, "close_read", bsock_close_read, 0);
+ rb_define_method(rb_cBasicSocket, "close_write", bsock_close_write, 0);
+ rb_define_method(rb_cBasicSocket, "shutdown", bsock_shutdown, -1);
+ rb_define_method(rb_cBasicSocket, "setsockopt", bsock_setsockopt, 3);
+ rb_define_method(rb_cBasicSocket, "getsockopt", bsock_getsockopt, 2);
+ rb_define_method(rb_cBasicSocket, "getsockname", bsock_getsockname, 0);
+ rb_define_method(rb_cBasicSocket, "getpeername", bsock_getpeername, 0);
+ rb_define_method(rb_cBasicSocket, "send", bsock_send, -1);
+ rb_define_method(rb_cBasicSocket, "recv", bsock_recv, -1);
+
+ rb_cIPsocket = rb_define_class("IPsocket", rb_cBasicSocket);
+ rb_define_method(rb_cIPsocket, "addr", ip_addr, 0);
+ rb_define_method(rb_cIPsocket, "peeraddr", ip_peeraddr, 0);
+ rb_define_singleton_method(rb_cIPsocket, "getaddress", ip_s_getaddress, 1);
+
+ rb_cTCPsocket = rb_define_class("TCPsocket", rb_cIPsocket);
+ rb_define_singleton_method(rb_cTCPsocket, "open", tcp_s_open, 2);
+ rb_define_singleton_method(rb_cTCPsocket, "new", tcp_s_open, 2);
+ rb_define_singleton_method(rb_cTCPsocket, "gethostbyname", tcp_s_gethostbyname, 1);
+ rb_define_method(rb_cTCPsocket, "recvfrom", tcp_recvfrom, -1);
#ifdef SOCKS
- cSOCKSsocket = rb_define_class("SOCKSsocket", cTCPsocket);
- rb_define_singleton_method(cSOCKSsocket, "open", socks_s_open, 2);
- rb_define_singleton_method(cSOCKSsocket, "new", socks_s_open, 2);
+ rb_cSOCKSsocket = rb_define_class("SOCKSsocket", rb_cTCPsocket);
+ rb_define_singleton_method(rb_cSOCKSsocket, "open", socks_s_open, 2);
+ rb_define_singleton_method(rb_cSOCKSsocket, "new", socks_s_open, 2);
#endif
- cTCPserver = rb_define_class("TCPserver", cTCPsocket);
- rb_define_singleton_method(cTCPserver, "open", tcp_svr_s_open, -1);
- rb_define_singleton_method(cTCPserver, "new", tcp_svr_s_open, -1);
- rb_define_method(cTCPserver, "accept", tcp_accept, 0);
+ rb_cTCPserver = rb_define_class("TCPserver", rb_cTCPsocket);
+ rb_define_singleton_method(rb_cTCPserver, "open", tcp_svr_s_open, -1);
+ rb_define_singleton_method(rb_cTCPserver, "new", tcp_svr_s_open, -1);
+ rb_define_method(rb_cTCPserver, "accept", tcp_accept, 0);
- cUDPsocket = rb_define_class("UDPsocket", cIPsocket);
- rb_define_singleton_method(cUDPsocket, "open", udp_s_open, 0);
- rb_define_singleton_method(cUDPsocket, "new", udp_s_open, 0);
- rb_define_method(cUDPsocket, "connect", udp_connect, 2);
- rb_define_method(cUDPsocket, "bind", udp_bind, 2);
- rb_define_method(cUDPsocket, "send", udp_send, -1);
- rb_define_method(cUDPsocket, "recvfrom", udp_recvfrom, -1);
+ rb_cUDPsocket = rb_define_class("UDPsocket", rb_cIPsocket);
+ rb_define_singleton_method(rb_cUDPsocket, "open", udp_s_open, 0);
+ rb_define_singleton_method(rb_cUDPsocket, "new", udp_s_open, 0);
+ rb_define_method(rb_cUDPsocket, "connect", udp_connect, 2);
+ rb_define_method(rb_cUDPsocket, "bind", udp_bind, 2);
+ rb_define_method(rb_cUDPsocket, "send", udp_send, -1);
+ rb_define_method(rb_cUDPsocket, "recvfrom", udp_recvfrom, -1);
#ifdef HAVE_SYS_UN_H
- cUNIXsocket = rb_define_class("UNIXsocket", cBasicSocket);
- rb_define_singleton_method(cUNIXsocket, "open", unix_s_sock_open, 1);
- rb_define_singleton_method(cUNIXsocket, "new", unix_s_sock_open, 1);
- rb_define_method(cUNIXsocket, "path", unix_path, 0);
- rb_define_method(cUNIXsocket, "addr", unix_addr, 0);
- rb_define_method(cUNIXsocket, "peeraddr", unix_peeraddr, 0);
- rb_define_method(cUNIXsocket, "recvfrom", unix_recvfrom, -1);
-
- cUNIXserver = rb_define_class("UNIXserver", cUNIXsocket);
- rb_define_singleton_method(cUNIXserver, "open", unix_svr_s_open, 1);
- rb_define_singleton_method(cUNIXserver, "new", unix_svr_s_open, 1);
- rb_define_method(cUNIXserver, "accept", unix_accept, 0);
-#endif
-
- cSocket = rb_define_class("Socket", cBasicSocket);
- rb_define_singleton_method(cSocket, "open", sock_s_open, 3);
- rb_define_singleton_method(cSocket, "new", sock_s_open, 3);
- rb_define_singleton_method(cSocket, "for_fd", sock_s_for_fd, 1);
-
- rb_define_method(cSocket, "connect", sock_connect, 1);
- rb_define_method(cSocket, "bind", sock_bind, 1);
- rb_define_method(cSocket, "listen", sock_listen, 1);
- rb_define_method(cSocket, "accept", sock_accept, 0);
-
- rb_define_method(cSocket, "recvfrom", sock_recvfrom, -1);
-
- rb_define_singleton_method(cSocket, "socketpair", sock_s_socketpair, 3);
- rb_define_singleton_method(cSocket, "pair", sock_s_socketpair, 3);
- rb_define_singleton_method(cSocket, "gethostname", sock_gethostname, 0);
- rb_define_singleton_method(cSocket, "gethostbyname", sock_s_gethostbyname, 1);
- rb_define_singleton_method(cSocket, "gethostbyaddr", sock_s_gethostbyaddr, -1);
- rb_define_singleton_method(cSocket, "getservbyname", sock_s_getservbyaname, -1);
+ rb_cUNIXsocket = rb_define_class("UNIXsocket", rb_cBasicSocket);
+ rb_define_singleton_method(rb_cUNIXsocket, "open", unix_s_sock_open, 1);
+ rb_define_singleton_method(rb_cUNIXsocket, "new", unix_s_sock_open, 1);
+ rb_define_method(rb_cUNIXsocket, "path", unix_path, 0);
+ rb_define_method(rb_cUNIXsocket, "addr", unix_addr, 0);
+ rb_define_method(rb_cUNIXsocket, "peeraddr", unix_peeraddr, 0);
+ rb_define_method(rb_cUNIXsocket, "recvfrom", unix_recvfrom, -1);
+
+ rb_cUNIXserver = rb_define_class("UNIXserver", rb_cUNIXsocket);
+ rb_define_singleton_method(rb_cUNIXserver, "open", unix_svr_s_open, 1);
+ rb_define_singleton_method(rb_cUNIXserver, "new", unix_svr_s_open, 1);
+ rb_define_method(rb_cUNIXserver, "accept", unix_accept, 0);
+#endif
+
+ rb_cSocket = rb_define_class("Socket", rb_cBasicSocket);
+ rb_define_singleton_method(rb_cSocket, "open", sock_s_open, 3);
+ rb_define_singleton_method(rb_cSocket, "new", sock_s_open, 3);
+ rb_define_singleton_method(rb_cSocket, "for_fd", sock_s_for_fd, 1);
+
+ rb_define_method(rb_cSocket, "connect", sock_connect, 1);
+ rb_define_method(rb_cSocket, "bind", sock_bind, 1);
+ rb_define_method(rb_cSocket, "listen", sock_listen, 1);
+ rb_define_method(rb_cSocket, "accept", sock_accept, 0);
+
+ rb_define_method(rb_cSocket, "recvfrom", sock_recvfrom, -1);
+
+ rb_define_singleton_method(rb_cSocket, "socketpair", sock_s_socketpair, 3);
+ rb_define_singleton_method(rb_cSocket, "pair", sock_s_socketpair, 3);
+ rb_define_singleton_method(rb_cSocket, "gethostname", sock_gethostname, 0);
+ rb_define_singleton_method(rb_cSocket, "gethostbyname", sock_s_gethostbyname, 1);
+ rb_define_singleton_method(rb_cSocket, "gethostbyaddr", sock_s_gethostbyaddr, -1);
+ rb_define_singleton_method(rb_cSocket, "getservbyname", sock_s_getservbyaname, -1);
/* constants */
- mConst = rb_define_module_under(cSocket, "Constants");
- sock_define_const("SOCK_STREAM", SOCK_STREAM);
- sock_define_const("SOCK_DGRAM", SOCK_DGRAM);
- sock_define_const("SOCK_RAW", SOCK_RAW);
+ mConst = rb_define_module_under(rb_cSocket, "Constants");
+ sock_rb_define_const("SOCK_STREAM", SOCK_STREAM);
+ sock_rb_define_const("SOCK_DGRAM", SOCK_DGRAM);
+#ifdef SOCK_RAW
+ sock_rb_define_const("SOCK_RAW", SOCK_RAW);
+#endif
#ifdef SOCK_RDM
- sock_define_const("SOCK_RDM", SOCK_RDM);
+ sock_rb_define_const("SOCK_RDM", SOCK_RDM);
#endif
#ifdef SOCK_SEQPACKET
- sock_define_const("SOCK_SEQPACKET", SOCK_SEQPACKET);
+ sock_rb_define_const("SOCK_SEQPACKET", SOCK_SEQPACKET);
#endif
#ifdef SOCK_PACKET
- sock_define_const("SOCK_PACKET", SOCK_PACKET);
+ sock_rb_define_const("SOCK_PACKET", SOCK_PACKET);
#endif
- sock_define_const("AF_INET", AF_INET);
- sock_define_const("PF_INET", PF_INET);
+ sock_rb_define_const("AF_INET", AF_INET);
+#ifdef PF_INET
+ sock_rb_define_const("PF_INET", PF_INET);
+#endif
#ifdef AF_UNIX
- sock_define_const("AF_UNIX", AF_UNIX);
- sock_define_const("PF_UNIX", PF_UNIX);
+ sock_rb_define_const("AF_UNIX", AF_UNIX);
+ sock_rb_define_const("PF_UNIX", PF_UNIX);
#endif
#ifdef AF_AX25
- sock_define_const("AF_AX25", AF_AX25);
- sock_define_const("PF_AX25", PF_AX25);
+ sock_rb_define_const("AF_AX25", AF_AX25);
+ sock_rb_define_const("PF_AX25", PF_AX25);
#endif
#ifdef AF_IPX
- sock_define_const("AF_IPX", AF_IPX);
- sock_define_const("PF_IPX", PF_IPX);
+ sock_rb_define_const("AF_IPX", AF_IPX);
+ sock_rb_define_const("PF_IPX", PF_IPX);
#endif
#ifdef AF_APPLETALK
- sock_define_const("AF_APPLETALK", AF_APPLETALK);
- sock_define_const("PF_APPLETALK", PF_APPLETALK);
+ sock_rb_define_const("AF_APPLETALK", AF_APPLETALK);
+ sock_rb_define_const("PF_APPLETALK", PF_APPLETALK);
#endif
- sock_define_const("MSG_OOB", MSG_OOB);
- sock_define_const("MSG_PEEK", MSG_PEEK);
- sock_define_const("MSG_DONTROUTE", MSG_DONTROUTE);
+ sock_rb_define_const("MSG_OOB", MSG_OOB);
+#ifdef MSG_PEEK
+ sock_rb_define_const("MSG_PEEK", MSG_PEEK);
+#endif
+#ifdef MSG_DONTROUTE
+ sock_rb_define_const("MSG_DONTROUTE", MSG_DONTROUTE);
+#endif
- sock_define_const("SOL_SOCKET", SOL_SOCKET);
+ sock_rb_define_const("SOL_SOCKET", SOL_SOCKET);
#ifdef SOL_IP
- sock_define_const("SOL_IP", SOL_IP);
+ sock_rb_define_const("SOL_IP", SOL_IP);
#endif
#ifdef SOL_IPX
- sock_define_const("SOL_IPX", SOL_IPX);
+ sock_rb_define_const("SOL_IPX", SOL_IPX);
#endif
#ifdef SOL_AX25
- sock_define_const("SOL_AX25", SOL_AX25);
+ sock_rb_define_const("SOL_AX25", SOL_AX25);
#endif
#ifdef SOL_ATALK
- sock_define_const("SOL_ATALK", SOL_ATALK);
+ sock_rb_define_const("SOL_ATALK", SOL_ATALK);
#endif
#ifdef SOL_TCP
- sock_define_const("SOL_TCP", SOL_TCP);
+ sock_rb_define_const("SOL_TCP", SOL_TCP);
#endif
#ifdef SOL_UDP
- sock_define_const("SOL_UDP", SOL_UDP);
+ sock_rb_define_const("SOL_UDP", SOL_UDP);
#endif
#ifdef SO_DEBUG
- sock_define_const("SO_DEBUG", SO_DEBUG);
+ sock_rb_define_const("SO_DEBUG", SO_DEBUG);
#endif
- sock_define_const("SO_REUSEADDR", SO_REUSEADDR);
+ sock_rb_define_const("SO_REUSEADDR", SO_REUSEADDR);
#ifdef SO_TYPE
- sock_define_const("SO_TYPE", SO_TYPE);
+ sock_rb_define_const("SO_TYPE", SO_TYPE);
#endif
#ifdef SO_ERROR
- sock_define_const("SO_ERROR", SO_ERROR);
+ sock_rb_define_const("SO_ERROR", SO_ERROR);
#endif
#ifdef SO_DONTROUTE
- sock_define_const("SO_DONTROUTE", SO_DONTROUTE);
+ sock_rb_define_const("SO_DONTROUTE", SO_DONTROUTE);
#endif
#ifdef SO_BROADCAST
- sock_define_const("SO_BROADCAST", SO_BROADCAST);
+ sock_rb_define_const("SO_BROADCAST", SO_BROADCAST);
#endif
#ifdef SO_SNDBUF
- sock_define_const("SO_SNDBUF", SO_SNDBUF);
+ sock_rb_define_const("SO_SNDBUF", SO_SNDBUF);
#endif
#ifdef SO_RCVBUF
- sock_define_const("SO_RCVBUF", SO_RCVBUF);
+ sock_rb_define_const("SO_RCVBUF", SO_RCVBUF);
+#endif
+#ifdef SO_KEEPALIVE
+ sock_rb_define_const("SO_KEEPALIVE", SO_KEEPALIVE);
#endif
- sock_define_const("SO_KEEPALIVE", SO_KEEPALIVE);
#ifdef SO_OOBINLINE
- sock_define_const("SO_OOBINLINE", SO_OOBINLINE);
+ sock_rb_define_const("SO_OOBINLINE", SO_OOBINLINE);
#endif
#ifdef SO_NO_CHECK
- sock_define_const("SO_NO_CHECK", SO_NO_CHECK);
+ sock_rb_define_const("SO_NO_CHECK", SO_NO_CHECK);
#endif
#ifdef SO_PRIORITY
- sock_define_const("SO_PRIORITY", SO_PRIORITY);
+ sock_rb_define_const("SO_PRIORITY", SO_PRIORITY);
+#endif
+#ifdef SO_LINGER
+ sock_rb_define_const("SO_LINGER", SO_LINGER);
#endif
- sock_define_const("SO_LINGER", SO_LINGER);
#ifdef SOPRI_INTERACTIVE
- sock_define_const("SOPRI_INTERACTIVE", SOPRI_INTERACTIVE);
+ sock_rb_define_const("SOPRI_INTERACTIVE", SOPRI_INTERACTIVE);
#endif
#ifdef SOPRI_NORMAL
- sock_define_const("SOPRI_NORMAL", SOPRI_NORMAL);
+ sock_rb_define_const("SOPRI_NORMAL", SOPRI_NORMAL);
#endif
#ifdef SOPRI_BACKGROUND
- sock_define_const("SOPRI_BACKGROUND", SOPRI_BACKGROUND);
+ sock_rb_define_const("SOPRI_BACKGROUND", SOPRI_BACKGROUND);
#endif
#ifdef IP_MULTICAST_IF
- sock_define_const("IP_MULTICAST_IF", IP_MULTICAST_IF);
+ sock_rb_define_const("IP_MULTICAST_IF", IP_MULTICAST_IF);
#endif
#ifdef IP_MULTICAST_TTL
- sock_define_const("IP_MULTICAST_TTL", IP_MULTICAST_TTL);
+ sock_rb_define_const("IP_MULTICAST_TTL", IP_MULTICAST_TTL);
#endif
#ifdef IP_MULTICAST_LOOP
- sock_define_const("IP_MULTICAST_LOOP", IP_MULTICAST_LOOP);
+ sock_rb_define_const("IP_MULTICAST_LOOP", IP_MULTICAST_LOOP);
#endif
#ifdef IP_ADD_MEMBERSHIP
- sock_define_const("IP_ADD_MEMBERSHIP", IP_ADD_MEMBERSHIP);
+ sock_rb_define_const("IP_ADD_MEMBERSHIP", IP_ADD_MEMBERSHIP);
#endif
#ifdef IP_DEFAULT_MULTICAST_TTL
- sock_define_const("IP_DEFAULT_MULTICAST_TTL", IP_DEFAULT_MULTICAST_TTL);
+ sock_rb_define_const("IP_DEFAULT_MULTICAST_TTL", IP_DEFAULT_MULTICAST_TTL);
#endif
#ifdef IP_DEFAULT_MULTICAST_LOOP
- sock_define_const("IP_DEFAULT_MULTICAST_LOOP", IP_DEFAULT_MULTICAST_LOOP);
+ sock_rb_define_const("IP_DEFAULT_MULTICAST_LOOP", IP_DEFAULT_MULTICAST_LOOP);
#endif
#ifdef IP_MAX_MEMBERSHIPS
- sock_define_const("IP_MAX_MEMBERSHIPS", IP_MAX_MEMBERSHIPS);
+ sock_rb_define_const("IP_MAX_MEMBERSHIPS", IP_MAX_MEMBERSHIPS);
#endif
#ifdef IPX_TYPE
- sock_define_const("IPX_TYPE", IPX_TYPE);
+ sock_rb_define_const("IPX_TYPE", IPX_TYPE);
#endif
#ifdef TCP_NODELAY
- sock_define_const("TCP_NODELAY", TCP_NODELAY);
+ sock_rb_define_const("TCP_NODELAY", TCP_NODELAY);
#endif
#ifdef TCP_MAXSEG
- sock_define_const("TCP_MAXSEG", TCP_MAXSEG);
+ sock_rb_define_const("TCP_MAXSEG", TCP_MAXSEG);
#endif
}
diff --git a/ext/tcltklib/extconf.rb b/ext/tcltklib/extconf.rb
index 26e7fe7b09..e34e549ca0 100644
--- a/ext/tcltklib/extconf.rb
+++ b/ext/tcltklib/extconf.rb
@@ -1,19 +1,27 @@
# extconf.rb for tcltklib
+require 'mkmf'
+
+have_library("nsl", "t_open")
have_library("socket", "socket")
-have_library("nsl", "gethostbyname")
+have_library("dl", "dlopen")
+have_library("m", "log")
-def search_file(var, include, *path)
+$includes = []
+def search_header(include, *path)
pwd = Dir.getwd
begin
- for i in path.reverse!
+ for i in path.sort!.reverse!
dir = Dir[i]
- for path in dir
+ for path in dir.sort!.reverse!
+ next unless File.directory? path
Dir.chdir path
files = Dir[include]
if files.size > 0
- var << path
- return files.pop
+ unless $includes.include? path
+ $includes << path
+ end
+ return
end
end
end
@@ -22,58 +30,56 @@ def search_file(var, include, *path)
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")
+search_header("tcl.h",
+ "/usr/include/tcl{,8*,7*}",
+ "/usr/include",
+ "/usr/local/include/tcl{,8*,7*}",
+ "/usr/local/include")
+search_header("tk.h",
+ "/usr/include/tk{,8*,4*}",
+ "/usr/include",
+ "/usr/local/include/tk{,8*,4*}",
+ "/usr/local/include")
+search_header("X11/Xlib.h",
+ "/usr/include/X11*",
+ "/usr/include",
+ "/usr/openwin/include",
+ "/usr/X11*/include")
-$CFLAGS = "-Wall " + $includes.collect{|path| "-I" + path}.join(" ")
+$CFLAGS = $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)$/, '')
+def search_lib(file, func, *path)
+ for i in path.reverse!
+ dir = Dir[i]
+ for path in dir.sort!.reverse!
+ $LDFLAGS = $libraries.collect{|p| "-L" + p}.join(" ") + " -L" + path
+ files = Dir[path+"/"+file]
+ if files.size > 0
+ for lib in files.sort!.reverse!
+ lib = File::basename(lib)
+ lib.sub!(/^lib/, '')
+ lib.sub!(/\.(a|so)$/, '')
+ if have_library(lib, func)
+ unless $libraries.include? path
+ $libraries << path
+ end
+ return true
+ end
+ end
+ end
+ end
+ end
+ return false;
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")
+if have_header("tcl.h") && have_header("tk.h") &&
+ search_lib("libX11.{so,a}", "XOpenDisplay",
+ "/usr/lib", "/usr/openwin/lib", "/usr/X11*/lib") &&
+ search_lib("libtcl{8*,7*,}.{so,a}", "Tcl_FindExecutable",
+ "/usr/lib", "/usr/local/lib") &&
+ search_lib("libtk{8*,4*,}.{so,a}", "Tk_Init",
+ "/usr/lib", "/usr/local/lib")
+ $LDFLAGS = $libraries.collect{|path| "-L" + path}.join(" ")
create_makefile("tcltklib")
end
diff --git a/ext/tcltklib/lib/tcltk.rb b/ext/tcltklib/lib/tcltk.rb
index 81d01f930d..54a00e8f3c 100644
--- a/ext/tcltklib/lib/tcltk.rb
+++ b/ext/tcltklib/lib/tcltk.rb
@@ -1,48 +1,44 @@
# tof
-#### tcltk ライブラリ
+#### tcltk library, more direct manipulation of tcl/tk
#### Sep. 5, 1997 Y. Shigehiro
require "tcltklib"
################
-# module TclTk: tcl/tk のライブラリ全体で必要になるものを集めたもの
-# (主に, 名前空間の点から module にする使う.)
+# module TclTk: collection of tcl/tk utilities (supplies namespace.)
module TclTk
- # 単にここに書けば最初に 1 度実行されるのか??
-
- # 生成した一意な名前を保持しておく連想配列を初期化する.
+ # initialize Hash to hold unique symbols and such
@namecnt = {}
- # コールバックを保持しておく連想配列を初期化する.
+ # initialize Hash to hold callbacks
@callback = {}
end
-# TclTk.mainloop(): TclTkLib.mainloop() を呼ぶ.
+# TclTk.mainloop(): call 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)
+# TclTk.deletecallbackkey(ca): remove callback from TclTk module
+# this does not remove callbacks from tcl/tk interpreter
+# without calling this method, TclTkInterpreter will not be GCed
+# ca: callback(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)
+# TclTk.dcb(ca, wid, W): call TclTk.deletecallbackkey() for each callbacks
+# in an array.
+# this is for callback for top-level <Destroy>
+# ca: array of callbacks(TclTkCallback)
+# wid: top-level widget(TclTkWidget)
+# w: information about window given by %W(String)
def TclTk.dcb(ca, wid, w)
if wid.to_s() == w
ca.each{|i|
@@ -51,33 +47,33 @@ def TclTk.dcb(ca, wid, w)
end
end
-# TclTk._addcallback(ca): コールバックを登録する.
-# ca: コールバック(TclTkCallback)
+# TclTk._addcallback(ca): register callback
+# ca: callback(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 インタプリタからのパラメータ
+# TclTk._callcallback(key, arg): invoke registered callback
+# key: key to select callback (to_s value of the TclTkCallback)
+# arg: parameter from tcl/tk interpreter
def TclTk._callcallback(key, arg)
print("_callcallback: ", @callback[key].inspect, "\n") if $DEBUG
@callback[key]._call(arg)
- # コールバックからの返り値はどうせ捨てられる.
- # String を返さないと, rb_eval_string() がエラーになる.
+ # throw out callback value
+ # should return String to satisfy rb_eval_string()
return ""
end
-# TclTk._newname(prefix): 一意な名前(String)を生成して返す.
-# prefix: 名前の接頭語
+# TclTk._newname(prefix): generate unique name(String)
+# prefix: prefix of the unique name
def TclTk._newname(prefix)
- # 生成した名前のカウンタは @namecnt に入っているので, 調べる.
+ # generated name counter is stored in @namecnt
if !@namecnt.key?(prefix)
- # 初めて使う接頭語なので初期化する.
+ # first appearing prefix, initialize
@namecnt[prefix] = 1
else
- # 使ったことのある接頭語なので, 次の名前にする.
+ # already appeared prefix, generate next name
@namecnt[prefix] += 1
end
return "#{prefix}#{@namecnt[prefix]}"
@@ -85,51 +81,48 @@ end
################
-# class TclTkInterpreter: tcl/tk のインタプリタ
+# class TclTkInterpreter: tcl/tk interpreter
class TclTkInterpreter
- # initialize(): 初期化.
+ # initialize():
def initialize()
- # インタプリタを生成する.
+ # generate interpreter object
@ip = TclTkIp.new()
- # インタプリタに ruby_fmt コマンドを追加する.
- # ruby_fmt コマンドとは, 後ろの引数を format コマンドで処理して
- # ruby コマンドに渡すものである.
- # (なお, ruby コマンドは, 引数を 1 つしかとれない.)
+ # add ruby_fmt command to tcl interpreter
+ # ruby_fmt command format arguments by `format' and call `ruby' command
+ # (notice ruby command receives only one argument)
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 で評価するスクリプト(に対応するオブジェクト列)
+ # @ip._get_eval_string(*args): generate string to evaluate in tcl interpreter
+ # *args: script which is going to be evaluated under tcl/tk
def @ip._get_eval_string(*args)
argstr = ""
args.each{|arg|
argstr += " " if argstr != ""
- # もし to_eval() メソッドが
+ # call to_eval if it is defined
if (arg.respond_to?(:to_eval))
- # 定義されていればそれを呼ぶ.
argstr += arg.to_eval()
else
- # 定義されていなければ to_s() を呼ぶ.
+ # call to_s unless defined
argstr += arg.to_s()
end
}
return argstr
end
- # @ip._eval_args(*args): tcl/tk インタプリタで評価し,
- # その結果(String)を返す.
- # *args: tcl/tk で評価するスクリプト(に対応するオブジェクト列)
+ # @ip._eval_args(*args): evaluate string under tcl/tk interpreter
+ # returns result string.
+ # *args: script which is going to be evaluated under tcl/tk
def @ip._eval_args(*args)
- # インタプリタで評価する文字列を求める.
+ # calculate the string to eval in the interpreter
argstr = _get_eval_string(*args)
- # インタプリタで評価する.
+ # evaluate under the interpreter
print("_eval: \"", argstr, "\"") if $DEBUG
res = _eval(argstr)
if $DEBUG
@@ -137,219 +130,205 @@ class TclTkInterpreter
elsif _return_value() != 0
print(res, "\n")
end
- fail(%Q/can't eval "#{argstr}"/) if _return_value() != 0
+ fail(%Q/can't eval "#{argstr}"/) if _return_value() != 0 #'
return res
end
- # tcl/tk のコマンドに対応するオブジェクトを生成し, 連想配列に入れておく.
+ # generate tcl/tk command object and register in the hash
@commands = {}
- # tcl/tk インタプリタに登録されているすべてのコマンドに対して,
+ # for all commands registered in tcl/tk interpreter:
@ip._eval("info command").split(/ /).each{|comname|
if comname =~ /^[.]/
- # コマンドがウィジェット(のパス名)の場合は
- # TclTkWidget のインスタンスを作って連想配列に入れる.
+ # if command is a widget (path), generate TclTkWidget,
+ # and register it in the hash
@commands[comname] = TclTkWidget.new(@ip, comname)
else
- # そうでない場合は
- # TclTkCommand のインスタンスを作って連想配列に入れる.
+ # otherwise, generate TclTkCommand
@commands[comname] = TclTkCommand.new(@ip, comname)
end
}
end
- # commands(): tcl/tk のコマンドに対応するオブジェクトを Hash に
- # 入れたものを返す.
+ # commands(): returns hash of the tcl/tk commands
def commands()
return @commands
end
- # rootwidget(): ルートウィジェット(TclTkWidget)を返す.
+ # rootwidget(): returns root widget(TclTkWidget)
def rootwidget()
return @commands["."]
end
- # _tcltkip(): @ip(TclTkIp) を返す.
+ # _tcltkip(): returns @ip(TclTkIp)
def _tcltkip()
return @ip
end
- # method_missing(id, *args): 未定義のメソッドは tcl/tk のコマンドとみなして
- # 実行し, その結果(String)を返す.
- # id: メソッドのシンボル
- # *args: コマンドの引数
+ # method_missing(id, *args): execute undefined method as tcl/tk command
+ # id: method symbol
+ # *args: method arguments
def method_missing(id, *args)
- # もし, メソッドの tcl/tk コマンドが
+ # if command named by id registered, then execute it
if @commands.key?(id.id2name)
- # あれば, 実行して結果を返す.
return @commands[id.id2name].e(*args)
else
- # 無ければもともとの処理.
+ # otherwise, exception
super
end
end
end
-# class TclTkObject: tcl/tk のオブジェクト
-# (基底クラスとして使う.
-# tcltk ライブラリを使う人が TclTkObject.new() することはないはず.)
+# class TclTkObject: base class of the tcl/tk objects
class TclTkObject
- # initialize(ip, exp): 初期化.
- # ip: インタプリタ(TclTkIp)
- # exp: tcl/tk での表現形
+ # initialize(ip, exp):
+ # ip: interpreter(TclTkIp)
+ # exp: tcl/tk representation
def initialize(ip, exp)
fail("type is not TclTkIp") if !ip.kind_of?(TclTkIp)
@ip = ip
@exp = exp
end
- # to_s(): tcl/tk での表現形(String)を返す.
+ # to_s(): returns tcl/tk representation
def to_s()
return @exp
end
end
-# class TclTkCommand: tcl/tk のコマンド
-# (tcltk ライブラリを使う人が TclTkCommand.new() することはないはず.
-# TclTkInterpreter:initialize() から new() される.)
+# class TclTkCommand: tcl/tk commands
+# you should not call TclTkCommand.new()
+# commands are created by TclTkInterpreter:initialize()
class TclTkCommand < TclTkObject
- # e(*args): コマンドを実行し, その結果(String)を返す.
- # (e は exec または eval の e.)
- # *args: コマンドの引数
+ # e(*args): execute command. returns String (e is for exec or eval)
+ # *args: command arguments
def e(*args)
return @ip._eval_args(to_s(), *args)
end
end
-# class TclTkLibCommand: tcl/tk のコマンド
-# (ライブラリにより実現されるコマンドで, tcl/tk インタプリタに最初から
-# 存在しないものは, インタプリタの commands() では生成できない.
-# そのようなものに対し, コマンドの名前から TclTkCommand オブジェクトを
-# 生成する.
+# class TclTkLibCommand: tcl/tk commands in the library
class TclTkLibCommand < TclTkCommand
- # initialize(ip, name): 初期化
- # ip: インタプリタ(TclTkInterpreter)
- # name: コマンド名 (String)
+ # initialize(ip, name):
+ # ip: interpreter(TclTkInterpreter)
+ # name: command name (String)
def initialize(ip, name)
super(ip._tcltkip, name)
end
end
-# class TclTkVariable: tcl/tk の変数
+# class TclTkVariable: tcl/tk variable
class TclTkVariable < TclTkObject
- # initialize(interp, dat): 初期化.
- # interp: インタプリタ(TclTkInterpreter)
- # dat: 設定する値(String)
- # nil なら, 設定しない.
+ # initialize(interp, dat):
+ # interp: interpreter(TclTkInterpreter)
+ # dat: the value to set(String)
+ # if nil, not initialize variable
def initialize(interp, dat)
- # tcl/tk での表現形(変数名)を自動生成する.
+ # auto-generate tcl/tk representation (variable name)
exp = TclTk._newname("v_")
- # TclTkObject を初期化する.
+ # initialize TclTkObject
super(interp._tcltkip(), exp)
- # set コマンドを使うのでとっておく.
+ # safe this for `set' command
@set = interp.commands()["set"]
- # 値を設定する.
+ # set value
set(dat) if dat
end
- # tcl/tk の set を使えば, 値の設定/参照はできるが,
- # それだけではなんなので, 一応, メソッドをかぶせたものも用意しておく.
+ # although you can set/refer variable by using set in tcl/tk,
+ # we provide the method for accessing variables
- # set(data): tcl/tk の変数に set を用いて値を設定する.
- # data: 設定する値
+ # set(data): set tcl/tk variable using `set'
+ # data: new value
def set(data)
@set.e(to_s(), data.to_s())
end
- # get(): tcl/tk の変数の値(String)を set を用いて読みだし返す.
+ # get(): read tcl/tk variable(String) using `set'
def get()
return @set.e(to_s())
end
end
-# class TclTkWidget: tcl/tk のウィジェット
+# class TclTkWidget: tcl/tk widget
class TclTkWidget < TclTkCommand
- # initialize(*args): 初期化.
- # *args: パラメータ
+ # initialize(*args):
+ # *args: parameters
def initialize(*args)
if args[0].kind_of?(TclTkIp)
- # 最初の引数が TclTkIp の場合:
+ # in case the 1st argument is TclTkIp:
- # 既に tcl/tk に定義されているウィジェットに TclTkWidget の構造を
- # かぶせる. (TclTkInterpreter:initialize() から使われる.)
+ # Wrap tcl/tk widget by TclTkWidget
+ # (used in TclTkInterpreter#initialize())
- # パラメータ数が 2 でなければエラー.
+ # need two arguments
fail("illegal # of parameter") if args.size != 2
- # ip: インタプリタ(TclTkIp)
- # exp: tcl/tk での表現形
+ # ip: interpreter(TclTkIp)
+ # exp: tcl/tk representation
ip, exp = args
- # TclTkObject を初期化する.
+ # initialize TclTkObject
super(ip, exp)
elsif args[0].kind_of?(TclTkInterpreter)
- # 最初の引数が TclTkInterpreter の場合:
+ # in case 1st parameter is TclTkInterpreter:
- # 親ウィジェットから新たなウィジェトを生成する.
+ # generate new widget from parent widget
- # interp: インタプリタ(TclTkInterpreter)
- # parent: 親ウィジェット
- # command: ウィジェットを生成するコマンド(label 等)
- # *args: command に渡す引数
+ # interp: interpreter(TclTkInterpreter)
+ # parent: parent widget
+ # command: widget generating tk command(label 等)
+ # *args: argument to the command
interp, parent, command, *args = args
- # ウィジェットの名前を作る.
+ # generate widget name
exp = parent.to_s()
exp += "." if exp !~ /[.]$/
exp += TclTk._newname("w_")
- # TclTkObject を初期化する.
+ # initialize TclTkObject
super(interp._tcltkip(), exp)
- # ウィジェットを生成する.
+ # generate widget
res = @ip._eval_args(command, exp, *args)
# fail("can't create Widget") if res != exp
- # tk_optionMenu では, ボタン名を exp で指定すると
- # res にメニュー名を返すので res != exp となる.
+ # for tk_optionMenu, it is legal res != exp
else
fail("first parameter is not TclTkInterpreter")
end
end
end
-# class TclTkCallback: tcl/tk のコールバック
+# class TclTkCallback: tcl/tk callbacks
class TclTkCallback < TclTkObject
- # initialize(interp, pr, arg): 初期化.
- # interp: インタプリタ(TclTkInterpreter)
- # pr: コールバック手続き(Proc)
- # arg: pr のイテレータ変数に渡す文字列
- # tcl/tk の bind コマンドではパラメータを受け取るために % 置換を
- # 用いるが, pr の内部で % を書いてもうまくいかない.
- # arg に文字列を書いておくと, その置換結果を, pr で
- # イテレータ変数を通して受け取ることができる.
- # scrollbar コマンドの -command オプションのように
- # 何も指定しなくてもパラメータが付くコマンドに対しては,
- # arg を指定してはならない.
+ # initialize(interp, pr, arg):
+ # interp: interpreter(TclTkInterpreter)
+ # pr: callback procedure(Proc)
+ # arg: string to pass as block parameters of pr
+ # bind command of tcl/tk uses % replacement for parameters
+ # pr can receive replaced data using block parameter
+ # its format is specified by arg string
+ # You should not specify arg for the command like
+ # scrollbar with -command option, which receives parameters
+ # without specifying any replacement
def initialize(interp, pr, arg = nil)
- # tcl/tk での表現形(変数名)を自動生成する.
+ # auto-generate tcl/tk representation (variable name)
exp = TclTk._newname("c_")
- # TclTkObject を初期化する.
+ # initialize TclTkObject
super(interp._tcltkip(), exp)
- # パラメータをとっておく.
+ # save parameters
@pr = pr
@arg = arg
- # モジュールに登録しておく.
+ # register in the module
TclTk._addcallback(self)
end
- # to_eval(): @ip._eval_args で評価するときの表現形(String)を返す.
+ # to_eval(): retuens string representation for @ip._eval_args
def to_eval()
if @arg
- # %s は ruby_fmt より前に bind により置換されてしまうので
- # %%s としてある. したがって, これは bind 専用.
+ # bind replaces %s before calling ruby_fmt, so %%s is used
s = %Q/{ruby_fmt {TclTk._callcallback("#{to_s()}", "%%s")} #{@arg}}/
else
s = %Q/{ruby_fmt {TclTk._callcallback("#{to_s()}", "%s")}}/
@@ -358,28 +337,28 @@ class TclTkCallback < TclTkObject
return s
end
- # _call(arg): コールバックを呼び出す.
- # arg: コールバックに渡されるパラメータ
+ # _call(arg): invoke callback
+ # arg: callback parameter
def _call(arg)
@pr.call(arg)
end
end
-# class TclTkImage: tcl/tk のイメージ
+# class TclTkImage: tcl/tk images
class TclTkImage < TclTkCommand
- # initialize(interp, t, *args): 初期化.
- # イメージの生成は TclTkImage.new() で行うが,
- # 破壊は image delete で行う. (いまいちだけど仕方が無い.)
- # interp: インタプリタ(TclTkInterpreter)
- # t: イメージのタイプ (photo, bitmap, etc.)
- # *args: コマンドの引数
+ # initialize(interp, t, *args):
+ # generating image is done by TclTkImage.new()
+ # destrying is done by image delete (inconsistent, sigh)
+ # interp: interpreter(TclTkInterpreter)
+ # t: image type (photo, bitmap, etc.)
+ # *args: command argument
def initialize(interp, t, *args)
- # tcl/tk での表現形(変数名)を自動生成する.
+ # auto-generate tcl/tk representation
exp = TclTk._newname("i_")
- # TclTkObject を初期化する.
+ # initialize TclTkObject
super(interp._tcltkip(), exp)
- # イメージを生成する.
+ # generate image
res = @ip._eval_args("image create", t, exp, *args)
fail("can't create Image") if res != exp
end
diff --git a/ext/tcltklib/tcltklib.c b/ext/tcltklib/tcltklib.c
index e7fe77d2b7..625fe61ccc 100644
--- a/ext/tcltklib/tcltklib.c
+++ b/ext/tcltklib/tcltklib.c
@@ -5,22 +5,31 @@
*/
#include "ruby.h"
-#include "sig.h"
+#include "rubysig.h"
#include <stdio.h>
#include <string.h>
#include <tcl.h>
#include <tk.h>
-/* for debug */
+#ifdef __MACOS__
+# include <tkMac.h>
+# include <Quickdraw.h>
+#endif
-#define DUMP1(ARG1) if (debug) { fprintf(stderr, "tcltklib: %s\n", ARG1);}
-#define DUMP2(ARG1, ARG2) if (debug) { fprintf(stderr, "tcltklib: ");\
+/* for rb_debug */
+
+#define DUMP1(ARG1) if (rb_debug) { fprintf(stderr, "tcltklib: %s\n", ARG1);}
+#define DUMP2(ARG1, ARG2) if (rb_debug) { fprintf(stderr, "tcltklib: ");\
fprintf(stderr, ARG1, ARG2); fprintf(stderr, "\n"); }
/*
#define DUMP1(ARG1)
#define DUMP2(ARG1, ARG2)
*/
+/* for callback break & continue */
+VALUE eTkCallbackBreak;
+VALUE eTkCallbackContinue;
+
/* from tkAppInit.c */
/*
@@ -33,26 +42,52 @@ int *tclDummyMathPtr = (int *) matherr;
/*---- module TclTkLib ----*/
-static VALUE thread_safe = Qnil;
+/* Tk_ThreadTimer */
+typedef struct {
+ Tcl_TimerToken token;
+ int flag;
+} Tk_TimerData;
+
+/* timer callback */
+void _timer_for_tcl (ClientData clientData)
+{
+ Tk_TimerData *timer = (Tk_TimerData*)clientData;
+
+ timer->flag = 0;
+ CHECK_INTS;
+#ifdef USE_THREAD
+ if (!rb_thread_critical) rb_thread_schedule();
+#endif
+
+ timer->token = Tk_CreateTimerHandler(200, _timer_for_tcl,
+ (ClientData)timer);
+ timer->flag = 1;
+}
/* execute Tk_MainLoop */
static VALUE
lib_mainloop(VALUE self)
{
- int old_trapflg;
- int flags = RTEST(thread_safe)?TCL_DONT_WAIT:0;
+ Tk_TimerData *timer;
+
+ timer = (Tk_TimerData *) ckalloc(sizeof(Tk_TimerData));
+ timer->flag = 0;
+ timer->token = Tk_CreateTimerHandler(200, _timer_for_tcl,
+ (ClientData)timer);
+ timer->flag = 1;
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;
+ Tcl_DoOneEvent(0);
}
DUMP1("stop Tk_Mainloop");
+#ifdef USE_THREAD
+ if (timer->flag) {
+ Tk_DeleteTimerHandler(timer->token);
+ }
+#endif
+
return Qnil;
}
@@ -71,27 +106,49 @@ ip_eval_rescue(VALUE *failed, VALUE einfo)
}
static int
+#if TCL_MAJOR_VERSION >= 8
+ip_ruby(ClientData clientData, Tcl_Interp *interp,
+ int argc, Tcl_Obj *CONST argv[])
+#else
ip_ruby(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
+#endif
{
VALUE res;
int old_trapflg;
VALUE failed = 0;
+ char *arg;
+ int dummy;
/* ruby command has 1 arg. */
if (argc != 2) {
- ArgError("wrong # of arguments (%d for 1)", argc);
+ rb_raise(rb_eArgError, "wrong # of arguments (%d for 1)", argc);
}
+ /* get C string from Tcl object */
+#if TCL_MAJOR_VERSION >= 8
+ arg = Tcl_GetStringFromObj(argv[1], &dummy);
+#else
+ arg = argv[1];
+#endif
+
/* 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;
+ DUMP2("rb_eval_string(%s)", arg);
+ old_trapflg = rb_trap_immediate;
+ rb_trap_immediate = 0;
+ res = rb_rescue(rb_eval_string, (VALUE)arg, ip_eval_rescue, (VALUE)&failed);
+ rb_trap_immediate = old_trapflg;
+ Tcl_ResetResult(interp);
if (failed) {
- Tcl_AppendResult(interp, RSTRING(failed)->ptr, (char*)NULL);
- return TCL_ERROR;
+ VALUE eclass = CLASS_OF(failed);
+ Tcl_AppendResult(interp, STR2CSTR(failed), (char*)NULL);
+ if (eclass == eTkCallbackBreak) {
+ return TCL_BREAK;
+ } else if (eclass == eTkCallbackContinue) {
+ return TCL_CONTINUE;
+ } else {
+ return TCL_ERROR;
+ }
}
/* result must be string or nil */
@@ -99,12 +156,11 @@ ip_ruby(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
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);
+ DUMP2("(rb_eval_string result) %s", STR2CSTR(res));
DUMP1("Tcl_AppendResult");
- Tcl_AppendResult(interp, RSTRING(res)->ptr, (char *)NULL);
+ Tcl_AppendResult(interp, STR2CSTR(res), (char *)NULL);
return TCL_OK;
}
@@ -115,6 +171,7 @@ ip_free(struct tcltkip *ptr)
{
DUMP1("Tcl_DeleteInterp");
Tcl_DeleteInterp(ptr->ip);
+ free(ptr);
}
/* create and initialize interpreter */
@@ -135,20 +192,26 @@ ip_new(VALUE self)
/* from Tcl_AppInit() */
DUMP1("Tcl_Init");
if (Tcl_Init(ptr->ip) == TCL_ERROR) {
- Fail("Tcl_Init");
+ rb_raise(rb_eRuntimeError, "Tcl_Init");
}
DUMP1("Tk_Init");
if (Tk_Init(ptr->ip) == TCL_ERROR) {
- Fail("Tk_Init");
+ rb_raise(rb_eRuntimeError, "Tk_Init");
}
DUMP1("Tcl_StaticPackage(\"Tk\")");
Tcl_StaticPackage(ptr->ip, "Tk", Tk_Init,
(Tcl_PackageInitProc *) NULL);
/* add ruby command to the interpreter */
+#if TCL_MAJOR_VERSION >= 8
+ DUMP1("Tcl_CreateObjCommand(\"ruby\")");
+ Tcl_CreateObjCommand(ptr->ip, "ruby", ip_ruby, (ClientData *)NULL,
+ (Tcl_CmdDeleteProc *)NULL);
+#else
DUMP1("Tcl_CreateCommand(\"ruby\")");
Tcl_CreateCommand(ptr->ip, "ruby", ip_ruby, (ClientData *)NULL,
(Tcl_CmdDeleteProc *)NULL);
+#endif
return obj;
}
@@ -157,6 +220,7 @@ ip_new(VALUE self)
static VALUE
ip_eval(VALUE self, VALUE str)
{
+ char *s;
char *buf; /* Tcl_Eval requires re-writable string region */
struct tcltkip *ptr; /* tcltkip data struct */
@@ -164,18 +228,162 @@ ip_eval(VALUE self, VALUE str)
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);
+ s = STR2CSTR(str);
+ buf = ALLOCA_N(char, strlen(s)+1);
+ strcpy(buf, s);
DUMP2("Tcl_Eval(%s)", buf);
ptr->return_value = Tcl_Eval(ptr->ip, buf);
if (ptr->return_value == TCL_ERROR) {
- Fail(ptr->ip->result);
+ rb_raise(rb_eRuntimeError, ptr->ip->result);
}
DUMP2("(TCL_Eval result) %d", ptr->return_value);
/* pass back the result (as string) */
- return(str_new2(ptr->ip->result));
+ return(rb_str_new2(ptr->ip->result));
+}
+
+
+static VALUE
+ip_toUTF8(VALUE self, VALUE str, VALUE encodename)
+{
+#ifndef TCL_UTF_MAX
+ return str;
+#else
+ Tcl_Interp *interp;
+ Tcl_Encoding encoding;
+ Tcl_DString dstr;
+ struct tcltkip *ptr;
+ char *buff1,*buff2;
+
+ Data_Get_Struct(self,struct tcltkip, ptr);
+ interp = ptr->ip;
+
+ encoding = Tcl_GetEncoding(interp,STR2CSTR(encodename));
+ buff1 = ALLOCA_N(char,strlen(STR2CSTR(str))+1);
+ strcpy(buff1,STR2CSTR(str));
+
+ Tcl_DStringInit(&dstr);
+ Tcl_DStringFree(&dstr);
+ Tcl_ExternalToUtfDString(encoding,buff1,strlen(buff1),&dstr);
+ buff2 = ALLOCA_N(char,Tcl_DStringLength(&dstr)+1);
+ strcpy(buff2,Tcl_DStringValue(&dstr));
+
+ Tcl_FreeEncoding(encoding);
+ Tcl_DStringFree(&dstr);
+
+ return rb_str_new2(buff2);
+#endif
+}
+
+static VALUE
+ip_fromUTF8(VALUE self, VALUE str, VALUE encodename)
+{
+#ifndef TCL_UTF_MAX
+ return str;
+#else
+ Tcl_Interp *interp;
+ Tcl_Encoding encoding;
+ Tcl_DString dstr;
+ struct tcltkip *ptr;
+ char *buff1,*buff2;
+
+ Data_Get_Struct(self,struct tcltkip, ptr);
+ interp = ptr->ip;
+
+ encoding = Tcl_GetEncoding(interp,STR2CSTR(encodename));
+ buff1 = ALLOCA_N(char,strlen(STR2CSTR(str))+1);
+ strcpy(buff1,STR2CSTR(str));
+
+ Tcl_DStringInit(&dstr);
+ Tcl_DStringFree(&dstr);
+ Tcl_UtfToExternalDString(encoding,buff1,strlen(buff1),&dstr);
+ buff2 = ALLOCA_N(char,Tcl_DStringLength(&dstr)+1);
+ strcpy(buff2,Tcl_DStringValue(&dstr));
+
+ Tcl_FreeEncoding(encoding);
+ Tcl_DStringFree(&dstr);
+
+ return rb_str_new2(buff2);
+#endif
+}
+
+
+static VALUE
+ip_invoke(int argc, VALUE *argv, VALUE obj)
+{
+ struct tcltkip *ptr; /* tcltkip data struct */
+ int i;
+ int object = 0;
+ Tcl_CmdInfo info;
+ char *cmd;
+ char **av = (char **)NULL;
+#if TCL_MAJOR_VERSION >= 8
+ Tcl_Obj **ov = (Tcl_Obj **)NULL;
+ Tcl_Obj *resultPtr;
+#endif
+
+ /* get the data struct */
+ Data_Get_Struct(obj, struct tcltkip, ptr);
+
+ /* get the command name string */
+ cmd = STR2CSTR(argv[0]);
+
+ /* map from the command name to a C procedure */
+ if (!Tcl_GetCommandInfo(ptr->ip, cmd, &info)) {
+ rb_raise(rb_eNameError, "invalid command name `%s'", cmd);
+ }
+#if TCL_MAJOR_VERSION >= 8
+ object = info.isNativeObjectProc;
+#endif
+
+ /* memory allocation for arguments of this command */
+ if (object) {
+#if TCL_MAJOR_VERSION >= 8
+ /* object interface */
+ ov = (Tcl_Obj **)ALLOCA_N(Tcl_Obj *, argc+1);
+ for (i = 0; i < argc; ++i) {
+ char *s = STR2CSTR(argv[i]);
+ ov[i] = Tcl_NewStringObj(s, strlen(s));
+ }
+ ov[argc] = (Tcl_Obj *)NULL;
+#endif
+ } else {
+ /* string interface */
+ av = (char **)ALLOCA_N(char *, argc+1);
+ for (i = 0; i < argc; ++i) {
+ char *s = STR2CSTR(argv[i]);
+
+ av[i] = ALLOCA_N(char, strlen(s)+1);
+ strcpy(av[i], s);
+ }
+ av[argc] = (char *)NULL;
+ }
+
+ Tcl_ResetResult(ptr->ip);
+
+ /* Invoke the C procedure */
+ if (object) {
+#if TCL_MAJOR_VERSION >= 8
+ int dummy;
+ ptr->return_value = (*info.objProc)(info.objClientData,
+ ptr->ip, argc, ov);
+
+ /* get the string value from the result object */
+ resultPtr = Tcl_GetObjResult(ptr->ip);
+ Tcl_SetResult(ptr->ip, Tcl_GetStringFromObj(resultPtr, &dummy),
+ TCL_VOLATILE);
+#endif
+ } else {
+ ptr->return_value = (*info.proc)(info.clientData,
+ ptr->ip, argc, av);
+ }
+
+ if (ptr->return_value == TCL_ERROR) {
+ rb_raise(rb_eRuntimeError, ptr->ip->result);
+ }
+
+ /* pass back the result (as string) */
+ return(rb_str_new2(ptr->ip->result));
}
/* get return code from Tcl_Eval() */
@@ -190,27 +398,44 @@ ip_retval(VALUE self)
return (INT2FIX(ptr->return_value));
}
+#ifdef __MACOS__
+static void
+_macinit()
+{
+ tcl_macQdPtr = &qd; /* setup QuickDraw globals */
+ Tcl_MacSetEventProc(TkMacConvertEvent); /* setup event handler */
+}
+#endif
+
/*---- initialization ----*/
void Init_tcltklib()
{
extern VALUE rb_argv0; /* the argv[0] */
VALUE lib = rb_define_module("TclTkLib");
- VALUE ip = rb_define_class("TclTkIp", cObject);
+ VALUE ip = rb_define_class("TclTkIp", rb_cObject);
+
+ eTkCallbackBreak = rb_define_class("TkCallbackBreak", rb_eStandardError);
+ eTkCallbackContinue = rb_define_class("TkCallbackContinue",rb_eStandardError);
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, "_toUTF8",ip_toUTF8,2);
+ rb_define_method(ip, "_fromUTF8",ip_fromUTF8,2);
+ rb_define_method(ip, "_invoke", ip_invoke, -1);
rb_define_method(ip, "_return_value", ip_retval, 0);
rb_define_method(ip, "mainloop", lib_mainloop, 0);
+#ifdef __MACOS__
+ _macinit();
+#endif
+
/*---- 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 */
diff --git a/ext/tk/MANIFEST b/ext/tk/MANIFEST
new file mode 100644
index 0000000000..9689186bf0
--- /dev/null
+++ b/ext/tk/MANIFEST
@@ -0,0 +1,25 @@
+MANIFEST
+extconf.rb
+depend
+tkutil.c
+lib/tk.rb
+lib/tkafter.rb
+lib/tkbgerror.rb
+lib/tkcanvas.rb
+lib/tkclass.rb
+lib/tkdialog.rb
+lib/tkentry.rb
+lib/tkfont.rb
+lib/tkmenubar.rb
+lib/tkmngfocus.rb
+lib/tkpalette.rb
+lib/tkscrollbox.rb
+lib/tktext.rb
+lib/tkvirtevent.rb
+sample/tkbiff.rb
+sample/tkbrowse.rb
+sample/tkdialog.rb
+sample/tkfrom.rb
+sample/tkhello.rb
+sample/tkline.rb
+sample/tktimer.rb
diff --git a/ext/tk/depend b/ext/tk/depend
new file mode 100644
index 0000000000..e325a82c0f
--- /dev/null
+++ b/ext/tk/depend
@@ -0,0 +1 @@
+tkutil.o: tkutil.c $(hdrdir)/ruby.h $(hdrdir)/config.h $(hdrdir)/defines.h
diff --git a/ext/tk/extconf.rb b/ext/tk/extconf.rb
new file mode 100644
index 0000000000..f769b06e30
--- /dev/null
+++ b/ext/tk/extconf.rb
@@ -0,0 +1,2 @@
+require 'mkmf'
+create_makefile("tkutil")
diff --git a/ext/tk/lib/tk.rb b/ext/tk/lib/tk.rb
new file mode 100644
index 0000000000..e32723be96
--- /dev/null
+++ b/ext/tk/lib/tk.rb
@@ -0,0 +1,2499 @@
+#
+# tk.rb - Tk interface modue using tcltklib
+# $Date$
+# by Yukihiro Matsumoto <matz@netlab.co.jp>
+
+# use Shigehiro's tcltklib
+require "tcltklib"
+require "tkutil"
+
+module TkComm
+ None = Object.new
+ def None.to_s
+ 'None'
+ end
+
+ Tk_CMDTBL = {}
+ Tk_WINDOWS = {}
+
+ def error_at
+ frames = caller()
+ frames.delete_if do |c|
+ c =~ %r!/tk(|core|thcore|canvas|text|entry|scrollbox)\.rb:\d+!
+ end
+ frames
+ end
+ private :error_at
+
+ def _genobj_for_tkwidget(path)
+ return TkRoot.new if path == '.'
+
+ begin
+ tk_class = TkCore::INTERP._invoke('winfo', 'class', path)
+ rescue
+ return path
+ end
+
+ ruby_class = TkClassBind::WidgetClassNameTBL[tk_class]
+ gen_class_name = ruby_class.name + 'GeneratedOnTk'
+ unless Object.const_defined? gen_class_name
+ eval "class #{gen_class_name}<#{ruby_class.name}
+ def initialize(path)
+ @path=path
+ Tk_WINDOWS[@path] = self
+ end
+ end"
+ end
+ eval "#{gen_class_name}.new('#{path}')"
+ end
+
+ def tk_tcl2ruby(val)
+ if val =~ /^rb_out (c\d+)/
+ return Tk_CMDTBL[$1]
+ end
+ if val.include? ?\s
+ return val.split.collect{|v| tk_tcl2ruby(v)}
+ end
+ case val
+ when /^@font/
+ TkFont.get_obj(val)
+ when /^-?\d+$/
+ val.to_i
+ when /^\./
+ Tk_WINDOWS[val] ? Tk_WINDOWS[val] : _genobj_for_tkwidget(val)
+ when / /
+ val.split.collect{|elt|
+ tk_tcl2ruby(elt)
+ }
+ when /^-?\d+\.\d*$/
+ val.to_f
+ else
+ val
+ end
+ end
+
+ def tk_split_list(str)
+ return [] if str == ""
+ idx = str.index('{')
+ return tk_tcl2ruby(str) unless idx
+
+ list = tk_tcl2ruby(str[0,idx])
+ list = [] if list == ""
+ str = str[idx+1..-1]
+ i = -1
+ brace = 1
+ str.each_byte {|c|
+ i += 1
+ brace += 1 if c == ?{
+ brace -= 1 if c == ?}
+ break if brace == 0
+ }
+ if str[0, i] == ' '
+ list.push ' '
+ else
+ list.push tk_split_list(str[0, i])
+ end
+ list += tk_split_list(str[i+1..-1])
+ list
+ end
+
+ def tk_split_simplelist(str)
+ return [] if str == ""
+ idx = str.index('{')
+ return str.split unless idx
+
+ list = str[0,idx].split
+ str = str[idx+1..-1]
+ i = -1
+ brace = 1
+ str.each_byte {|c|
+ i += 1
+ brace += 1 if c == ?{
+ brace -= 1 if c == ?}
+ break if brace == 0
+ }
+ if i == 0
+ list.push ''
+ elsif str[0, i] == ' '
+ list.push ' '
+ else
+ list.push str[0..i-1]
+ end
+ list += tk_split_simplelist(str[i+1..-1])
+ list
+ end
+ private :tk_tcl2ruby, :tk_split_list, :tk_split_simplelist
+
+ def hash_kv(keys)
+ conf = []
+ if keys and keys != None
+ for k, v in keys
+ conf.push("-#{k}")
+ conf.push(v)
+ end
+ end
+ conf
+ end
+ private :hash_kv
+
+ def array2tk_list(ary)
+ ary.collect{|e|
+ if e.kind_of? Array
+ "{#{array2tk_list(e)}}"
+ elsif e.kind_of? Hash
+ "{#{e.to_a.collect{|ee| array2tk_list(ee)}.join(' ')}}"
+ else
+ s = _get_eval_string(e)
+ (s.index(/\s/))? "{#{s}}": s
+ end
+ }.join(" ")
+ end
+ private :array2tk_list
+
+ def bool(val)
+ case val
+ when "1", 1, 'yes', 'true'
+ TRUE
+ else
+ FALSE
+ end
+ end
+ def number(val)
+ case val
+ when /^-?\d+$/
+ val.to_i
+ when /^-?\d+\.\d*$/
+ val.to_f
+ else
+ val
+ end
+ end
+ def string(val)
+ if val == "{}"
+ ''
+ elsif val[0] == ?{
+ val[1..-2]
+ else
+ val
+ end
+ end
+ def list(val)
+ tk_split_list(val).to_a
+ end
+ def window(val)
+ Tk_WINDOWS[val]
+ end
+ def procedure(val)
+ if val =~ /^rb_out (c\d+)/
+ Tk_CMDTBL[$1]
+ else
+ nil
+ end
+ end
+ private :bool, :number, :string, :list, :window, :procedure
+
+ def _get_eval_string(str)
+ return nil if str == None
+ if str.kind_of?(Hash)
+ str = hash_kv(str).join(" ")
+ elsif str.kind_of?(Array)
+ str = array2tk_list(str)
+ elsif str.kind_of?(Proc)
+ str = install_cmd(str)
+ elsif str == nil
+ str = ""
+ elsif str == false
+ str = "0"
+ elsif str == true
+ str = "1"
+ elsif (str.respond_to?(:to_eval))
+ str = str.to_eval()
+ else
+ str = str.to_s()
+ end
+ return str
+ end
+ private :_get_eval_string
+
+ Tk_IDs = [0, 0] # [0]-cmdid, [1]-winid
+ def _curr_cmd_id
+ id = format("c%.4d", Tk_IDs[0])
+ end
+ def _next_cmd_id
+ id = _curr_cmd_id
+ Tk_IDs[0] += 1
+ id
+ end
+ def install_cmd(cmd)
+ return '' if cmd == ''
+ id = _next_cmd_id
+ Tk_CMDTBL[id] = cmd
+ @cmdtbl = [] if not @cmdtbl
+ @cmdtbl.push id
+ return format("rb_out %s", id);
+ end
+ def uninstall_cmd(id)
+ Tk_CMDTBL[id] = nil
+ end
+ private :install_cmd, :uninstall_cmd
+
+ def install_win(ppath)
+ id = format("w%.4d", Tk_IDs[1])
+ Tk_IDs[1] += 1
+ if !ppath or ppath == "."
+ @path = format(".%s", id);
+ else
+ @path = format("%s.%s", ppath, id)
+ end
+ Tk_WINDOWS[@path] = self
+ end
+
+ def uninstall_win()
+ Tk_WINDOWS[@path] = nil
+ end
+
+ class Event
+ def initialize(seq,b,f,h,k,s,t,w,x,y,aa,ee,kk,nn,ww,tt,xx,yy)
+ @serial = seq
+ @num = b
+ @focus = (f == 1)
+ @height = h
+ @keycode = k
+ @state = s
+ @time = t
+ @width = w
+ @x = x
+ @y = y
+ @char = aa
+ @send_event = (ee == 1)
+ @keysym = kk
+ @keysym_num = nn
+ @type = tt
+ @widget = ww
+ @x_root = xx
+ @y_root = yy
+ end
+ attr :serial
+ attr :num
+ attr :focus
+ attr :height
+ attr :keycode
+ attr :state
+ attr :time
+ attr :width
+ attr :x
+ attr :y
+ attr :char
+ attr :send_event
+ attr :keysym
+ attr :keysym_num
+ attr :type
+ attr :widget
+ attr :x_root
+ attr :y_root
+ end
+
+ def install_bind(cmd, args=nil)
+ if args
+ id = install_cmd(proc{|arg|
+ TkUtil.eval_cmd cmd, *arg
+ })
+ id + " " + args
+ else
+ id = install_cmd(proc{|arg|
+ TkUtil.eval_cmd cmd, Event.new(*arg)
+ })
+ id + ' %# %b %f %h %k %s %t %w %x %y %A %E %K %N %W %T %X %Y'
+ end
+ end
+
+ def tk_event_sequence(context)
+ if context.kind_of? TkVirtualEvent
+ context = context.path
+ end
+ if context.kind_of? Array
+ context = context.collect{|ev|
+ if context.kind_of? TkVirtualEvent
+ ev.path
+ else
+ ev
+ end
+ }.join("><")
+ end
+ if /,/ =~ context
+ context = context.split(/\s*,\s*/).join("><")
+ else
+ context
+ end
+ end
+
+ def _bind_core(mode, path, context, cmd, args=nil)
+ id = install_bind(cmd, args)
+ begin
+ tk_call 'bind', path, "<#{tk_event_sequence(context)}>", mode + id
+ rescue
+ uninstall_cmd(id)
+ fail
+ end
+ end
+
+ def _bind(path, context, cmd, args=nil)
+ _bind_core('', path, context, cmd, args)
+ end
+
+ def _bind_append(path, context, cmd, args=nil)
+ _bind_core('+', path, context, cmd, args)
+ end
+ private :install_bind, :tk_event_sequence, :_bind_core, :_bind, :_bind_append
+
+ def bind_all(context, cmd=Proc.new, args=nil)
+ _bind 'all', context, cmd, args
+ end
+
+ def bind_append_all(context, cmd=Proc.new, args=nil)
+ _bind_append 'all', context, cmd, args
+ end
+
+ def bind(tagOrClass, context, cmd=Proc.new, args=nil)
+ _bind tagOrClass, context, cmd, args
+ end
+
+ def bind_append(tagOrClass, context, cmd=Proc.new, args=nil)
+ _bind_append tagOrClass, context, cmd, args
+ end
+
+ def _bindinfo(tagOrClass, context=nil)
+ if context
+ (tk_call('bind', tagOrClass,
+ "<#{tk_event_sequence(context)}>")).collect{|cmdline|
+ if cmdline =~ /^rb_out (c\d+)\s+(.*)$/
+ [Tk_CMDTBL[$1], $2]
+ else
+ cmdline
+ end
+ }
+ else
+ tk_split_list(tk_call 'bind', tagOrClass).collect{|seq|
+ seq[1..-2].gsub(/></,',')
+ }
+ end
+ end
+
+ def bindinfo(tagOrClass, context=nil)
+ _bindinfo tagOrClass, context
+ end
+
+ def pack(*args)
+ TkPack.configure *args
+ end
+
+ def grid(*args)
+ TkGrid.configure *args
+ end
+
+ def update(idle=nil)
+ if idle
+ tk_call 'update', 'idletasks'
+ else
+ tk_call 'update'
+ end
+ end
+
+end
+
+module TkCore
+ include TkComm
+ extend TkComm
+
+ INTERP = TclTkIp.new
+
+ INTERP._invoke("proc", "rb_out", "args", "if {[set st [catch {ruby [format \"TkCore.callback %%Q!%s!\" $args]} ret]] != 0} {return -code $st $ret} {return $ret}")
+
+ def callback_break
+ raise TkCallbackBreak, "Tk callback returns 'break' status"
+ end
+
+ def callback_continue
+ raise TkCallbackContinue, "Tk callback returns 'continue' status"
+ end
+
+ def after(ms, cmd=Proc.new)
+ myid = _curr_cmd_id
+ cmdid = install_cmd(cmd)
+ tk_call("after",ms,cmdid)
+ return
+ if false #defined? Thread
+ Thread.start do
+ ms = Float(ms)/1000
+ ms = 10 if ms == 0
+ sleep ms/1000
+ cmd.call
+ end
+ else
+ cmdid = install_cmd(cmd)
+ tk_call("after",ms,cmdid)
+ end
+ end
+
+ def TkCore.callback(arg)
+ arg = Array(tk_split_list(arg))
+ _get_eval_string(TkUtil.eval_cmd(Tk_CMDTBL[arg.shift], *arg))
+ end
+
+ def appname(name=None)
+ tk_call('tk', 'appname', name)
+ end
+
+ def appsend(interp, async, *args)
+ if async
+ tk_call('send', '-async', '--', interp, *args)
+ else
+ tk_call('send', '--', interp, *args)
+ end
+ end
+
+ def rb_appsend(interp, async, *args)
+ args = args.filter{|c| _get_eval_string(c).gsub(/[][$"]/, '\\\\\&')}
+ args.push(').to_s"')
+ appsend(interp, async, 'ruby "(', *args)
+ end
+
+ def appsend_displayof(interp, win, async, *args)
+ win = '.' if win == nil
+ if async
+ tk_call('send', '-async', '-displayof', win, '--', interp, *args)
+ else
+ tk_call('send', '-displayor', win, '--', interp, *args)
+ end
+ end
+
+ def rb_appsend_displayof(interp, win, async, *args)
+ args = args.filter{|c| _get_eval_string(c).gsub(/[][$"]/, '\\\\\&')}
+ args.push(').to_s"')
+ appsend_displayof(interp, win, async, 'ruby "(', *args)
+ end
+
+ def info(*args)
+ tk_call('info', *args)
+ end
+
+ def mainloop
+ TclTkLib.mainloop
+ end
+
+ def event_generate(window, context, keys=nil)
+ window = window.path if window.kind_of? TkObject
+ if keys
+ tk_call('event', 'generate', window,
+ "<#{tk_event_sequence(context)}>", *hash_kv(keys))
+ else
+ tk_call('event', 'generate', window, "<#{tk_event_sequence(context)}>")
+ end
+ end
+
+ def messageBox(keys)
+ tk_call 'tk_messageBox', *hash_kv(keys)
+ end
+
+ def getOpenFile(keys)
+ tk_call 'tk_getOpenFile', *hash_kv(keys)
+ end
+
+ def getSaveFile(keys)
+ tk_call 'tk_getSaveFile', *hash_kv(keys)
+ end
+
+ def chooseColor(keys)
+ tk_call 'tk_chooseColor', *hash_kv(keys)
+ end
+
+ def tk_call(*args)
+ print args.join(" "), "\n" if $DEBUG
+ args.filter {|x|_get_eval_string(x)}
+ args.compact!
+ args.flatten!
+ begin
+ res = INTERP._invoke(*args)
+ rescue NameError
+ err = $!
+ begin
+ args.unshift "unknown"
+ res = INTERP._invoke(*args)
+ rescue
+ raise unless /^invalid command/ =~ $!
+ raise err
+ end
+ end
+ if INTERP._return_value() != 0
+ fail RuntimeError, res, error_at
+ end
+ print "==> ", res, "\n" if $DEBUG
+ return res
+ end
+end
+
+module Tk
+ include TkCore
+ extend Tk
+
+ TCL_VERSION = INTERP._invoke("info", "tclversion")
+ TK_VERSION = INTERP._invoke("set", "tk_version")
+ JAPANIZED_TK = (INTERP._invoke("info", "commands", "kanji") != "")
+
+ def root
+ TkRoot.new
+ end
+
+ def bell
+ tk_call 'bell'
+ end
+
+ def Tk.focus(display=nil)
+ if display == nil
+ r = tk_call('focus')
+ else
+ r = tk_call('focus', '-displayof', display)
+ end
+ tk_tcl2ruby(r)
+ end
+
+ def Tk.focus_lastfor(win)
+ tk_tcl2ruby(tk_call('focus', '-lastfor', win))
+ end
+
+ def toUTF8(str,encoding)
+ INTERP._toUTF8(str,encoding)
+ end
+
+ def fromUTF8(str,encoding)
+ INTERP._fromUTF8(str,encoding)
+ end
+
+ module Scrollable
+ def xscrollcommand(cmd=Proc.new)
+ configure_cmd 'xscrollcommand', cmd
+ end
+ def yscrollcommand(cmd=Proc.new)
+ configure_cmd 'yscrollcommand', cmd
+ end
+ end
+
+ module Wm
+ def aspect(*args)
+ w = window(tk_call('wm', 'grid', path, *args))
+ w.split.collect{|s|s.to_i} if args.length == 0
+ end
+ def client(name=None)
+ tk_call 'wm', 'client', path, name
+ end
+ def colormapwindows(*args)
+ list(tk_call('wm', 'colormapwindows', path, *args))
+ end
+ def wm_command(value=None)
+ string(tk_call('wm', 'command', path, value))
+ end
+ def deiconify
+ tk_call 'wm', 'deiconify', path
+ end
+ def focusmodel(*args)
+ tk_call 'wm', 'focusmodel', path, *args
+ end
+ def frame
+ tk_call 'wm', 'frame', path
+ end
+ def geometry(*args)
+ list(tk_call('wm', 'geometry', path, *args))
+ end
+ def grid(*args)
+ w = tk_call('wm', 'grid', path, *args)
+ list(w) if args.size == 0
+ end
+ def group(*args)
+ tk_call 'wm', 'group', path, *args
+ end
+ def iconbitmap(*args)
+ tk_call 'wm', 'iconbitmap', path, *args
+ end
+ def iconify
+ tk_call 'wm', 'iconify', path
+ end
+ def iconmask(*args)
+ tk_call 'wm', 'iconmask', path, *args
+ end
+ def iconname(*args)
+ tk_call 'wm', 'iconname', path, *args
+ end
+ def iconposition(*args)
+ w = tk_call('wm', 'iconposition', path, *args)
+ list(w) if args.size == 0
+ end
+ def iconwindow(*args)
+ w = tk_call('wm', 'iconwindow', path, *args)
+ window(w) if args.size == 0
+ end
+ def maxsize(*args)
+ w = tk_call('wm', 'maxsize', path, *args)
+ list(w) if not args.size == 0
+ end
+ def minsize(*args)
+ w = tk_call('wm', 'minsize', path, *args)
+ list(w) if args.size == 0
+ end
+ def overrideredirect(bool=None)
+ if bool == None
+ bool(tk_call('wm', 'overrideredirect', path))
+ else
+ tk_call 'wm', 'overrideredirect', path, bool
+ end
+ end
+ def positionfrom(*args)
+ tk_call 'wm', 'positionfrom', path, *args
+ end
+ def protocol(name=nil, cmd=nil)
+ if cmd
+ tk_call('wm', 'protocol', path, name, cmd)
+ elsif name
+ result = tk_call('wm', 'protocol', path, name)
+ (result == "")? nil : tk_tcl2ruby(result)
+ else
+ tk_split_simplelist(tk_call('wm', 'protocol', path))
+ end
+ end
+ def resizable(*args)
+ w = tk_call('wm', 'resizable', path, *args)
+ if args.length == 0
+ list(w).collect{|e| bool(e)}
+ end
+ end
+ def sizefrom(*args)
+ list(tk_call('wm', 'sizefrom', path, *args))
+ end
+ def state
+ tk_call 'wm', 'state', path
+ end
+ def title(*args)
+ tk_call 'wm', 'title', path, *args
+ end
+ def transient(*args)
+ tk_call 'wm', 'transient', path, *args
+ end
+ def withdraw
+ tk_call 'wm', 'withdraw', path
+ end
+ end
+end
+
+class TkVariable
+ include Tk
+ extend TkCore
+
+ TkVar_CB_TBL = {}
+ Tk_VARIABLE_ID = ["v00000"]
+
+ INTERP._invoke("proc", "rb_var", "args", "ruby [format \"TkVariable.callback %%Q!%s!\" $args]")
+
+ def TkVariable.callback(args)
+ name1,name2,op = tk_split_list(args)
+ if TkVar_CB_TBL[name1]
+ _get_eval_string(TkVar_CB_TBL[name1].trace_callback(name2,op))
+ else
+ ''
+ end
+ end
+
+ def initialize(val="")
+ @id = Tk_VARIABLE_ID[0]
+ Tk_VARIABLE_ID[0] = Tk_VARIABLE_ID[0].succ
+ if val == []
+ INTERP._eval(format('global %s; set %s(0) 0; unset %s(0)',
+ @id, @id, @id))
+ elsif val.kind_of?(Array)
+ a = []
+ val.each_with_index{|e,i| a.push(i); a.push(array2tk_list(e))}
+ s = '"' + a.join(" ").gsub(/[][$"]/, '\\\\\&') + '"' #'
+ INTERP._eval(format('global %s; array set %s %s', @id, @id, s))
+ elsif val.kind_of?(Hash)
+ s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\
+ .gsub(/[][$"]/, '\\\\\&') + '"' #'
+ INTERP._eval(format('global %s; array set %s %s', @id, @id, s))
+ else
+ s = '"' + _get_eval_string(val).gsub(/[][$"]/, '\\\\\&') + '"' #'
+ INTERP._eval(format('global %s; set %s %s', @id, @id, s))
+ end
+ end
+
+ def wait
+ INTERP._eval("tkwait variable #{@id}")
+ end
+
+ def id
+ @id
+ end
+
+ def value
+ begin
+ INTERP._eval(format('global %s; set %s', @id, @id))
+ rescue
+ if INTERP._eval(format('global %s; array exists %s', @id, @id)) != "1"
+ raise
+ else
+ Hash[*tk_split_simplelist(INTERP\
+ ._eval(format('global %s; array get %s',
+ @id, @id)))]
+ end
+ end
+ end
+
+ def value=(val)
+ begin
+ s = '"' + _get_eval_string(val).gsub(/[][$"]/, '\\\\\&') + '"' #'
+ INTERP._eval(format('global %s; set %s %s', @id, @id, s))
+ rescue
+ if INTERP._eval(format('global %s; array exists %s', @id, @id)) != "1"
+ raise
+ else
+ INTERP._eval(format('global %s; unset %s'), @id, @id)
+ if val == []
+ INTERP._eval(format('global %s; set %s(0) 0; unset %s(0)',
+ @id, @id, @id))
+ elsif val.kind_of?(Array)
+ a = []
+ val.each_with_index{|e,i| a.push(i); a.push(array2tk_list(e))}
+ s = '"' + a.join(" ").gsub(/[][$"]/, '\\\\\&') + '"' #'
+ INTERP._eval(format('global %s; unset %s; array set %s %s',
+ @id, @id, @id, s))
+ elsif val.kind_of?(Hash)
+ s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\
+ .gsub(/[][$"]/, '\\\\\&') + '"' #'
+ INTERP._eval(format('global %s; unset %s; array set %s %s',
+ @id, @id, @id, s))
+ else
+ raise
+ end
+ end
+ end
+ end
+
+ def [](index)
+ INTERP._eval(format('global %s; set %s(%s)',
+ @id, @id, _get_eval_string(index)))
+ end
+
+ def []=(index,val)
+ INTERP._eval(format('global %s; set %s(%s) %s', @id, @id,
+ _get_eval_string(index), _get_eval_string(val)))
+ end
+
+ def to_i
+ Integer(number(value))
+ end
+
+ def to_f
+ Float(number(value))
+ end
+
+ def to_s
+ String(string(value))
+ end
+
+ def inspect
+ format "<TkVariable: %s>", @id
+ end
+
+ def ==(other)
+ case other
+ when TkVariable
+ self.equal(self)
+ when String
+ self.to_s == other
+ when Integer
+ self.to_i == other
+ when Float
+ self.to_f == other
+ when Array
+ self.to_a == other
+ else
+ false
+ end
+ end
+
+ def to_a
+ list(value)
+ end
+
+ def to_eval
+ @id
+ end
+
+ def unset(elem=nil)
+ if elem
+ INTERP._eval(format('global %s; unset %s(%s)',
+ @id, @id, tk_tcl2ruby(elem)))
+ else
+ INTERP._eval(format('global %s; unset %s', @id, @id))
+ end
+ end
+ alias remove unset
+
+ def trace_callback(elem, op)
+ if @trace_var.kind_of? Array
+ @trace_var.each{|m,e| e.call(self,elem,op) if m.index(op)}
+ end
+ if elem.kind_of? String
+ if @trace_elem[elem].kind_of? Array
+ @trace_elem[elem].each{|m,e| e.call(self,elem,op) if m.index(op)}
+ end
+ end
+ end
+
+ def trace(opts, cmd)
+ @trace_var = [] if @trace_var == nil
+ opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('')
+ @trace_var.unshift([opts,cmd])
+ if @trace_opts == nil
+ TkVar_CB_TBL[@id] = self
+ @trace_opts = opts
+ Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var')
+ else
+ newopts = @trace_opts.dup
+ opts.each_byte{|c| newopts += c.chr unless @newopts.index(c)}
+ if newopts != @trace_opts
+ Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var')
+ @trace_opts.replace(newopts)
+ Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var')
+ end
+ end
+ end
+
+ def trace_element(elem, opts, cmd)
+ @trace_elem = {} if @trace_elem == nil
+ @trace_elem[elem] = [] if @trace_elem[elem] == nil
+ opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('')
+ @trace_elem[elem].unshift([opts,cmd])
+ if @trace_opts == nil
+ TkVar_CB_TBL[@id] = self
+ @trace_opts = opts
+ Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var')
+ else
+ newopts = @trace_opts.dup
+ opts.each_byte{|c| newopts += c.chr unless @newopts.index(c)}
+ if newopts != @trace_opts
+ Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var')
+ @trace_opts.replace(newopts)
+ Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var')
+ end
+ end
+ end
+
+ def trace_vinfo
+ return [] unless @trace_var
+ @trace_var.dup
+ end
+ def trace_vinfo_for_element(elem)
+ return [] unless @trace_elem
+ return [] unless @trace_elem[elem]
+ @trace_elem[elem].dup
+ end
+
+ def trace_vdelete(opts,cmd)
+ return unless @trace_var.kind_of? Array
+ opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('')
+ idx = -1
+ newopts = ''
+ @trace_var.each_with_index{|i,e|
+ if idx < 0 && e[0] == opts && e[1] == cmd
+ idx = i
+ next
+ end
+ e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
+ }
+ if idx >= 0
+ @trace_var.delete_at(idx)
+ else
+ return
+ end
+
+ @trace_elem.each{|elem|
+ @trace_elem[elem].each{|e|
+ e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
+ }
+ }
+
+ newopts = ['r','w','u'].find_all{|c| newopts.index(c)}.join('')
+ if newopts != @trace_opts
+ Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var')
+ @trace_opts.replace(newopts)
+ if @trace_opts != ''
+ Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var')
+ end
+ end
+ end
+
+ def trace_vdelete_for_element(elem,opts,cmd)
+ return unless @trace_elem.kind_of? Hash
+ return unless @trace_elem[elem].kind_of? Array
+ opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('')
+ idx = -1
+ @trace_elem[elem].each_with_index{|i,e|
+ if idx < 0 && e[0] == opts && e[1] == cmd
+ idx = i
+ next
+ end
+ }
+ if idx >= 0
+ @trace_elem[elem].delete_at(idx)
+ else
+ return
+ end
+
+ newopts = ''
+ @trace_var.each{|e|
+ e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
+ }
+ @trace_elem.each{|elem|
+ @trace_elem[elem].each{|e|
+ e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
+ }
+ }
+
+ newopts = ['r','w','u'].find_all{|c| newopts.index(c)}.join('')
+ if newopts != @trace_opts
+ Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var')
+ @trace_opts.replace(newopts)
+ if @trace_opts != ''
+ Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var')
+ end
+ end
+ end
+end
+
+class TkVarAccess<TkVariable
+ def initialize(varname, val=nil)
+ @id = varname
+ if val
+ s = '"' + _get_eval_string(val).gsub(/[][$"]/, '\\\\\&') + '"' #'
+ INTERP._eval(format('global %s; set %s %s', @id, @id, s))
+ end
+ end
+end
+
+module TkSelection
+ include Tk
+ extend Tk
+ def clear(win=Tk.root)
+ tk_call 'selection', 'clear', win.path
+ end
+ def get(type=None)
+ tk_call 'selection', 'get', type
+ end
+ def TkSelection.handle(win, func, type=None, format=None)
+ id = install_cmd(func)
+ tk_call 'selection', 'handle', win.path, id, type, format
+ end
+ def handle(func, type=None, format=None)
+ TkSelection.handle self, func, type, format
+ end
+ def TkSelection.own(win, func=None)
+ id = install_cmd(func)
+ tk_call 'selection', 'own', win.path, id
+ end
+ def own(func=None)
+ TkSelection.own self, func
+ end
+
+ module_function :clear, :get
+end
+
+module TkKinput
+ include Tk
+ extend Tk
+
+ def TkKinput.start(window, style=None)
+ tk_call 'kinput_start', window.path, style
+ end
+ def kinput_start(style=None)
+ TkKinput.start(self, style)
+ end
+
+ def TkKinput.send_spot(window)
+ tk_call 'kinput_send_spot', window.path
+ end
+ def kinput_send_spot
+ TkKinput.send_spot(self)
+ end
+
+ def TkKinput.input_start(window, keys=nil)
+ tk_call 'kanjiInput', 'start', window.path, *hash_kv(keys)
+ end
+ def kanji_input_start(keys=nil)
+ TkKinput.input_start(self, keys)
+ end
+
+ def TkKinput.attribute_config(window, slot, value=None)
+ if slot.kind_of? Hash
+ tk_call 'kanjiInput', 'attribute', window.path, *hash_kv(slot)
+ else
+ tk_call 'kanjiInput', 'attribute', window.path, "-#{slot}", value
+ end
+ end
+ def kinput_attribute_config(slot, value=None)
+ TkKinput.attribute_config(self, slot, value)
+ end
+
+ def TkKinput.attribute_info(window, slot=nil)
+ if slot
+ conf = tk_split_list(tk_call('kanjiInput', 'attribute',
+ window.path, "-#{slot}"))
+ conf[0] = conf[0][1..-1]
+ conf
+ else
+ tk_split_list(tk_call('kanjiInput', 'attribute',
+ window.path)).collect{|conf|
+ conf[0] = conf[0][1..-1]
+ conf
+ }
+ end
+ end
+ def kinput_attribute_info(slot=nil)
+ TkKinput.attribute_info(self, slot)
+ end
+
+ def TkKinput.input_end(window)
+ tk_call 'kanjiInput', 'end', window.path
+ end
+ def kanji_input_end
+ TkKinput.input_end(self)
+ end
+end
+
+module TkWinfo
+ include Tk
+ extend Tk
+ def TkWinfo.atom(name)
+ tk_call 'winfo', name
+ end
+ def winfo_atom(name)
+ TkWinfo.atom name
+ end
+ def TkWinfo.atomname(id)
+ tk_call 'winfo', id
+ end
+ def winfo_atomname(id)
+ TkWinfo.atomname id
+ end
+ def TkWinfo.cells(window)
+ number(tk_call('winfo', window.path))
+ end
+ def winfo_cells
+ TkWinfo.cells self
+ end
+ def TkWinfo.children(window)
+ c = tk_call('winfo', 'children', window.path)
+ list(c)
+ end
+ def winfo_children
+ TkWinfo.children self
+ end
+ def TkWinfo.classname(window)
+ tk_call 'winfo', 'class', window.path
+ end
+ def winfo_classname
+ TkWinfo.classname self
+ end
+ def TkWinfo.containing(rootX, rootY)
+ path = tk_call('winfo', 'containing', rootX, rootY)
+ window(path)
+ end
+ def winfo_containing(x, y)
+ TkWinfo.containing x, y
+ end
+ def TkWinfo.depth(window)
+ number(tk_call('winfo', 'depth', window.path))
+ end
+ def winfo_depth
+ TkWinfo.depth self
+ end
+ def TkWinfo.exist?(window)
+ bool(tk_call('winfo', 'exists', window.path))
+ end
+ def winfo_exist?
+ TkWinfo.exist? self
+ end
+ def TkWinfo.fpixels(window, number)
+ number(tk_call('winfo', 'fpixels', window.path, number))
+ end
+ def winfo_fpixels(number)
+ TkWinfo.fpixels self, number
+ end
+ def TkWinfo.geometry(window)
+ list(tk_call('winfo', 'geometry', window.path))
+ end
+ def winfo_geometry
+ TkWinfo.geometry self
+ end
+ def TkWinfo.height(window)
+ number(tk_call('winfo', 'height', window.path))
+ end
+ def winfo_height
+ TkWinfo.height self
+ end
+ def TkWinfo.id(window)
+ number(tk_call('winfo', 'id', window.path))
+ end
+ def winfo_id
+ TkWinfo.id self
+ end
+ def TkWinfo.interps(window=nil)
+ if window
+ tk_split_simplelist(tk_call('winfo', '-displayof', window.path,
+ 'interps'))
+ else
+ tk_split_simplelist(tk_call('winfo', 'interps'))
+ end
+ end
+ def winfo_interps
+ TkWinfo.interps self
+ end
+ def TkWinfo.mapped?(window)
+ bool(tk_call('winfo', 'ismapped', window.path))
+ end
+ def winfo_mapped?
+ TkWinfo.mapped? self
+ end
+ def TkWinfo.appname(window)
+ bool(tk_call('winfo', 'name', window.path))
+ end
+ def winfo_appname
+ TkWinfo.appname self
+ end
+ def TkWinfo.parent(window)
+ window(tk_call('winfo', 'parent', window.path))
+ end
+ def winfo_parent
+ TkWinfo.parent self
+ end
+ def TkWinfo.widget(id)
+ window(tk_call('winfo', 'pathname', id))
+ end
+ def winfo_widget(id)
+ TkWinfo.widget id
+ end
+ def TkWinfo.pixels(window, number)
+ number(tk_call('winfo', 'pixels', window.path, number))
+ end
+ def winfo_pixels(number)
+ TkWinfo.pixels self, number
+ end
+ def TkWinfo.reqheight(window)
+ number(tk_call('winfo', 'reqheight', window.path))
+ end
+ def winfo_reqheight
+ TkWinfo.reqheight self
+ end
+ def TkWinfo.reqwidth(window)
+ number(tk_call('winfo', 'reqwidth', window.path))
+ end
+ def winfo_reqwidth
+ TkWinfo.reqwidth self
+ end
+ def TkWinfo.rgb(window, color)
+ list(tk_call('winfo', 'rgb', window.path, color))
+ end
+ def winfo_rgb(color)
+ TkWinfo.rgb self, color
+ end
+ def TkWinfo.rootx(window)
+ number(tk_call('winfo', 'rootx', window.path))
+ end
+ def winfo_rootx
+ TkWinfo.rootx self
+ end
+ def TkWinfo.rooty(window)
+ number(tk_call('winfo', 'rooty', window.path))
+ end
+ def winfo_rooty
+ TkWinfo.rooty self
+ end
+ def TkWinfo.screen(window)
+ tk_call 'winfo', 'screen', window.path
+ end
+ def winfo_screen
+ TkWinfo.screen self
+ end
+ def TkWinfo.screencells(window)
+ number(tk_call('winfo', 'screencells', window.path))
+ end
+ def winfo_screencells
+ TkWinfo.screencells self
+ end
+ def TkWinfo.screendepth(window)
+ number(tk_call('winfo', 'screendepth', window.path))
+ end
+ def winfo_screendepth
+ TkWinfo.screendepth self
+ end
+ def TkWinfo.screenheight (window)
+ number(tk_call('winfo', 'screenheight', window.path))
+ end
+ def winfo_screenheight
+ TkWinfo.screenheight self
+ end
+ def TkWinfo.screenmmheight(window)
+ number(tk_call('winfo', 'screenmmheight', window.path))
+ end
+ def winfo_screenmmheight
+ TkWinfo.screenmmheight self
+ end
+ def TkWinfo.screenmmwidth(window)
+ number(tk_call('winfo', 'screenmmwidth', window.path))
+ end
+ def winfo_screenmmwidth
+ TkWinfo.screenmmwidth self
+ end
+ def TkWinfo.screenvisual(window)
+ tk_call 'winfo', 'screenvisual', window.path
+ end
+ def winfo_screenvisual
+ TkWinfo.screenvisual self
+ end
+ def TkWinfo.screenwidth(window)
+ number(tk_call('winfo', 'screenwidth', window.path))
+ end
+ def winfo_screenwidth
+ TkWinfo.screenwidth self
+ end
+ def TkWinfo.toplevel(window)
+ window(tk_call('winfo', 'toplevel', window.path))
+ end
+ def winfo_toplevel
+ TkWinfo.toplevel self
+ end
+ def TkWinfo.visual(window)
+ tk_call 'winfo', 'visual', window.path
+ end
+ def winfo_visual
+ TkWinfo.visual self
+ end
+ def TkWinfo.vrootheigh(window)
+ number(tk_call('winfo', 'vrootheight', window.path))
+ end
+ def winfo_vrootheight
+ TkWinfo.vrootheight self
+ end
+ def TkWinfo.vrootwidth(window)
+ number(tk_call('winfo', 'vrootwidth', window.path))
+ end
+ def winfo_vrootwidth
+ TkWinfo.vrootwidth self
+ end
+ def TkWinfo.vrootx(window)
+ number(tk_call('winfo', 'vrootx', window.path))
+ end
+ def winfo_vrootx
+ TkWinfo.vrootx self
+ end
+ def TkWinfo.vrooty(window)
+ number(tk_call('winfo', 'vrooty', window.path))
+ end
+ def winfo_vrooty
+ TkWinfo.vrooty self
+ end
+ def TkWinfo.width(window)
+ number(tk_call('winfo', 'width', window.path))
+ end
+ def winfo_width
+ TkWinfo.width self
+ end
+ def TkWinfo.x(window)
+ number(tk_call('winfo', 'x', window.path))
+ end
+ def winfo_x
+ TkWinfo.x self
+ end
+ def TkWinfo.y(window)
+ number(tk_call('winfo', 'y', window.path))
+ end
+ def winfo_y
+ TkWinfo.y self
+ end
+ def TkWinfo.viewable(window)
+ bool(tk_call 'winfo', 'viewable', window.path)
+ end
+ def winfo_viewable
+ TkWinfo.viewable self
+ end
+ def TkWinfo.pointerx(window)
+ number(tk_call('winfo', 'pointerx', window.path))
+ end
+ def winfo_pointerx
+ TkWinfo.pointerx self
+ end
+ def TkWinfo.pointery(window)
+ number(tk_call('winfo', 'pointery', window.path))
+ end
+ def winfo_pointery
+ TkWinfo.pointery self
+ end
+ def TkWinfo.pointerxy(window)
+ list(tk_call('winfo', 'pointerxy', window.path))
+ end
+ def winfo_pointerxy
+ TkWinfo.pointerxy self
+ end
+end
+
+module TkPack
+ include Tk
+ extend Tk
+ def configure(win, *args)
+ if args[-1].kind_of?(Hash)
+ keys = args.pop
+ end
+ wins = [win.epath]
+ for i in args
+ wins.push i.epath
+ end
+ tk_call "pack", 'configure', *(wins+hash_kv(keys))
+ end
+
+ def forget(*args)
+ tk_call 'pack', 'forget' *args
+ end
+
+ def propagate(master, bool=None)
+ bool(tk_call('pack', 'propagate', master.epath, bool))
+ end
+ module_function :configure, :forget, :propagate
+end
+
+module TkGrid
+ include Tk
+ extend Tk
+
+ def bbox(*args)
+ list(tk_call('grid', 'bbox', *args))
+ end
+
+ def configure(widget, *args)
+ if args[-1].kind_of?(Hash)
+ keys = args.pop
+ end
+ wins = [widget.epath]
+ for i in args
+ wins.push i.epath
+ end
+ tk_call "grid", 'configure', *(wins+hash_kv(keys))
+ end
+
+ def columnconfigure(master, index, args)
+ tk_call "grid", 'columnconfigure', master, index, *hash_kv(args)
+ end
+
+ def rowconfigure(master, index, args)
+ tk_call "grid", 'rowconfigure', master, index, *hash_kv(args)
+ end
+
+ def add(widget, *args)
+ configure(widget, *args)
+ end
+
+ def forget(*args)
+ tk_call 'grid', 'forget', *args
+ end
+
+ def info(slave)
+ list(tk_call('grid', 'info', slave))
+ end
+
+ def location(master, x, y)
+ list(tk_call('grid', 'location', master, x, y))
+ end
+
+ def propagate(master, bool=None)
+ bool(tk_call('grid', 'propagate', master.epath, bool))
+ end
+
+ def remove(*args)
+ tk_call 'grid', 'remove', *args
+ end
+
+ def size(master)
+ tk_call 'grid', 'size', master
+ end
+
+ def slaves(args)
+ list(tk_call('grid', 'slaves', *hash_kv(args)))
+ end
+
+ module_function :bbox, :forget, :propagate, :info
+ module_function :remove, :size, :slaves, :location
+ module_function :configure, :columnconfigure, :rowconfigure
+end
+
+module TkOption
+ include Tk
+ extend Tk
+ def add pat, value, pri=None
+ tk_call 'option', 'add', pat, value, pri
+ end
+ def clear
+ tk_call 'option', 'clear'
+ end
+ def get win, name, klass
+ tk_call 'option', 'get', win ,name, klass
+ end
+ def readfile file, pri=None
+ tk_call 'option', 'readfile', file, pri
+ end
+ module_function :add, :clear, :get, :readfile
+end
+
+module TkTreatFont
+ def font_configinfo
+ ret = TkFont.used_on(self.path)
+ if ret == nil
+ ret = TkFont.init_widget_font(self.path, self.path, 'configure')
+ end
+ ret
+ end
+ alias fontobj font_configinfo
+
+ def font_configure(slot)
+ if (fnt = slot['font'])
+ slot['font'] = nil
+ if fnt.kind_of? TkFont
+ return fnt.call_font_configure(self.path, self.path,'configure',slot)
+ else
+ latinfont_configure(fnt) if fnt
+ end
+ end
+ if (ltn = slot['latinfont'])
+ slot['latinfont'] = nil
+ latinfont_configure(ltn) if ltn
+ end
+ if (ltn = slot['asciifont'])
+ slot['asciifont'] = nil
+ latinfont_configure(ltn) if ltn
+ end
+ if (knj = slot['kanjifont'])
+ slot['kanjifont'] = nil
+ kanjifont_configure(knj) if knj
+ end
+
+ tk_call(self.path, 'configure', *hash_kv(slot)) if slot != {}
+ self
+ end
+
+ def latinfont_configure(ltn, keys=nil)
+ fobj = fontobj
+ if ltn.kind_of? TkFont
+ conf = {}
+ ltn.latin_configinfo.each{|key,val| conf[key] = val}
+ if keys
+ fobj.latin_configure(conf.update(keys))
+ else
+ fobj.latin_configure(conf)
+ end
+ else
+ fobj.latin_replace(ltn)
+ end
+ end
+ alias asciifont_configure latinfont_configure
+
+ def kanjifont_configure(knj, keys=nil)
+ fobj = fontobj
+ if knj.kind_of? TkFont
+ conf = {}
+ knj.kanji_configinfo.each{|key,val| conf[key] = val}
+ if keys
+ fobj.kanji_configure(conf.update(keys))
+ else
+ fobj.kanji_configure(cond)
+ end
+ else
+ fobj.kanji_replace(knj)
+ end
+ end
+
+ def font_copy(window, tag=nil)
+ if tag
+ window.tagfontobj(tag).configinfo.each{|key,value|
+ fontobj.configure(key,value)
+ }
+ fontobj.replace(window.tagfontobj(tag).latin_font,
+ window.tagfontobj(tag).kanji_font)
+ else
+ window.fontobj.configinfo.each{|key,value|
+ fontobj.configure(key,value)
+ }
+ fontobj.replace(window.fontobj.latin_font, window.fontobj.kanji_font)
+ end
+ end
+
+ def latinfont_copy(window, tag=nil)
+ if tag
+ fontobj.latin_replace(window.tagfontobj(tag).latin_font)
+ else
+ fontobj.latin_replace(window.fontobj.latin_font)
+ end
+ end
+ alias asciifont_copy latinfont_copy
+
+ def kanjifont_copy(window, tag=nil)
+ if tag
+ fontobj.kanji_replace(window.tagfontobj(tag).kanji_font)
+ else
+ fontobj.kanji_replace(window.fontobj.kanji_font)
+ end
+ end
+end
+
+class TkObject<TkKernel
+ include Tk
+ include TkTreatFont
+
+ def path
+ return @path
+ end
+
+ def epath
+ return @path
+ end
+
+ def to_eval
+ @path
+ end
+
+ def tk_send(cmd, *rest)
+ tk_call path, cmd, *rest
+ end
+ private :tk_send
+
+ def method_missing(id, *args)
+ name = id.id2name
+ case args.length
+ when 1
+ configure name, args[0]
+ when 0
+ begin
+ cget name
+ rescue
+ fail NameError, "undefined local variable or method `#{name}' for #{self.to_s}", error_at
+ end
+ else
+ fail NameError, "undefined method `#{name}' for #{self.to_s}", error_at
+ end
+ end
+
+ def [](id)
+ cget id
+ end
+
+ def []=(id, val)
+ configure id, val
+ end
+
+ def cget(slot)
+ tk_tcl2ruby tk_call path, 'cget', "-#{slot}"
+ end
+
+ def configure(slot, value=None)
+ if slot.kind_of? Hash
+ if ( slot['font'] || slot['kanjifont'] \
+ || slot['latinfont'] || slot['asciifont'] )
+ font_configure(slot.dup)
+ else
+ tk_call path, 'configure', *hash_kv(slot)
+ end
+
+ else
+ if ( slot == 'font' || slot == 'kanjifont' \
+ || slot == 'latinfont' || slot == 'asciifont' )
+ font_configure({slot=>value})
+ else
+ tk_call path, 'configure', "-#{slot}", value
+ end
+ end
+ end
+
+ def configure_cmd(slot, value)
+ configure slot, install_cmd(value)
+ end
+
+ def configinfo(slot = nil)
+ if slot == 'font' || slot == 'kanjifont'
+ fontobj
+
+ else
+ if slot
+ conf = tk_split_list(tk_send('configure', "-#{slot}") )
+ conf[0] = conf[0][1..-1]
+ conf
+
+ else
+ ret = tk_split_list(tk_send('configure') ).collect{|conf|
+ conf[0] = conf[0][1..-1]
+ conf
+ }
+ if ret.assoc('font')
+ ret.delete_if{|item| item[0] == 'font' || item[0] == 'kanjifont'}
+ ret.push(['font', fontobj])
+ else
+ ret
+ end
+ end
+ end
+ end
+
+ def bind(context, cmd=Proc.new, args=nil)
+ _bind path, context, cmd, args
+ end
+
+ def bind_append(context, cmd=Proc.new, args=nil)
+ _bind_append path, context, cmd, args
+ end
+
+ def bindinfo(context=nil)
+ _bindinfo path, context
+ end
+
+ def event_generate(context, keys=nil)
+ if keys
+ tk_call('event', 'generate', path,
+ "<#{tk_event_sequence(context)}>", *hash_kv(keys))
+ else
+ tk_call('event', 'generate', path, "<#{tk_event_sequence(context)}>")
+ end
+ end
+
+ def tk_trace_variable(v)
+ unless v.kind_of?(TkVariable)
+ fail ArgumentError, format("requires TkVariable given %s", v.type)
+ end
+ v
+ end
+ private :tk_trace_variable
+
+ def destroy
+ tk_call 'trace', 'vdelete', @tk_vn, 'w', @var_id if @var_id
+ end
+end
+
+module TkClassBind
+ WidgetClassNameTBL = {}
+
+ def TkClassBind.name2class(name)
+ WidgetClassNameTBL[name]
+ end
+
+ def bind(context, cmd=Proc.new, args=nil)
+ Tk.bind to_eval, context, cmd, args
+ end
+
+ def bind_append(context, cmd=Proc.new, args=nil)
+ Tk.bind_append to_eval, context, cmd, args
+ end
+
+ def bindinfo(context=nil)
+ Tk.bindinfo to_eval, context
+ end
+end
+
+class TkWindow<TkObject
+ extend TkClassBind
+
+ def initialize(parent=nil, keys=nil)
+ install_win(if parent then parent.path end)
+ create_self
+ if keys
+ # tk_call @path, 'configure', *hash_kv(keys)
+ configure(keys)
+ end
+ end
+
+ def create_self
+ end
+ private :create_self
+
+ def pack(keys = nil)
+ tk_call 'pack', epath, *hash_kv(keys)
+ self
+ end
+
+ def unpack(keys = nil)
+ tk_call 'pack', 'forget', epath
+ self
+ end
+
+ def grid(keys = nil)
+ tk_call 'grid', epath, *hash_kv(keys)
+ self
+ end
+
+ def ungrid(keys = nil)
+ tk_call 'grid', 'forget', epath
+ self
+ end
+
+ def place(keys = nil)
+ tk_call 'place', epath, *hash_kv(keys)
+ self
+ end
+
+ def unplace(keys = nil)
+ tk_call 'place', 'forget', epath, *hash_kv(keys)
+ self
+ end
+ alias place_forget unplace
+
+ def place_config(keys)
+ tk_call "place", 'configure', epath, *hash_kv(keys)
+ end
+
+ def place_info()
+ ilist = list(tk_call('place', 'info', epath))
+ info = {}
+ while key = ilist.shift
+ info[key[1..-1]] = ilist.shift
+ end
+ return info
+ end
+
+ def pack_slaves()
+ list(tk_call('pack', 'slaves', epath))
+ end
+
+ def pack_info()
+ ilist = list(tk_call('pack', 'info', epath))
+ info = {}
+ while key = ilist.shift
+ info[key[1..-1]] = ilist.shift
+ end
+ return info
+ end
+
+ def place_slaves()
+ list(tk_call('place', 'slaves', epath))
+ end
+
+ def focus(force=false)
+ if force
+ tk_call 'focus', '-force', path
+ else
+ tk_call 'focus', path
+ end
+ self
+ end
+
+ def grab(*args)
+ if !args or args.length == 0
+ tk_call 'grab', 'set', path
+ elsif args.length == 1
+ case args[0]
+ when 'global'
+ tk_call 'grab', 'set', '-global', path
+ else
+ val = tk_call('grab', args[0], path)
+ end
+ case args[0]
+ when 'current'
+ return window(val)
+ when 'status'
+ return val
+ end
+ else
+ fail ArgumentError, 'wrong # of args'
+ end
+ end
+
+ def lower(below=None)
+ tk_call 'lower', path, below
+ self
+ end
+ def raise(above=None)
+ tk_call 'raise', path, above
+ self
+ end
+
+ def command(cmd=Proc.new)
+ configure_cmd 'command', cmd
+ end
+
+ def colormodel model=None
+ tk_call 'tk', 'colormodel', path, model
+ self
+ end
+
+ def destroy
+ tk_call 'destroy', path
+ if @cmdtbl
+ for id in @cmdtbl
+ uninstall_cmd id
+ end
+ end
+ uninstall_win
+ end
+
+ def wait_visibility
+ tk_call 'tkwait', 'visibility', path
+ end
+ alias wait wait_visibility
+
+ def wait_destroy
+ tk_call 'tkwait', 'window', path
+ end
+
+ def bindtags(taglist=nil)
+ if taglist
+ fail unless taglist.kind_of? Array
+ tk_call('bindtags', path, taglist)
+ else
+ tk_split_list(tk_call('bindtags', path)).collect{|tag|
+ if tag == nil
+ '.'
+ elsif tag.kind_of?(String) && (cls = TkClassBind.name2class(tag))
+ cls
+ else
+ tag
+ end
+ }
+ end
+ end
+end
+
+class TkRoot<TkWindow
+ include Wm
+ ROOT = []
+ def TkRoot.new
+ return ROOT[0] if ROOT[0]
+ new = super
+ ROOT[0] = new
+ Tk_WINDOWS["."] = new
+ end
+
+ WidgetClassName = 'Tk'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+ def self.to_eval
+ WidgetClassName
+ end
+
+ def create_self
+ @path = '.'
+ end
+ def path
+ "."
+ end
+end
+
+class TkToplevel<TkWindow
+ include Wm
+
+ WidgetClassName = 'Toplevel'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+ def self.to_eval
+ WidgetClassName
+ end
+
+ def initialize(parent=nil, screen=nil, classname=nil, keys=nil)
+ if screen.kind_of? Hash
+ keys = screen.dup
+ else
+ @screen = screen
+ end
+ @classname = classname
+ if keys.kind_of? Hash
+ keys = keys.dup
+ if keys['classname']
+ @classname = keys['classname']
+ keys['classname'] = nil
+ end
+ if keys['colormap']
+ @colormap = keys['colormap']
+ keys['colormap'] = nil
+ end
+ if keys['container']
+ @classname = keys['container']
+ keys['classname'] = nil
+ end
+ if keys['screen']
+ @screen = keys['screen']
+ keys['screen'] = nil
+ end
+ if keys['use']
+ @use = keys['use']
+ keys['use'] = nil
+ end
+ if keys['visual']
+ @screen = keys['visual']
+ keys['visual'] = nil
+ end
+ end
+ super(parent, keys)
+ end
+
+ def create_self
+ s = []
+ s.push << "-class" << @classname if @classname
+ s.push << "-colormap" << @colormap if @colormap
+ s.push << "-container" << @container if @container
+ s.push << "-screen" << @screen if @screen
+ s.push << "-use" << @use if @use
+ s.push << "-visual" << @visual if @visual
+ tk_call 'toplevel', @path, *s
+ end
+
+ def specific_class
+ @classname
+ end
+end
+
+class TkFrame<TkWindow
+ WidgetClassName = 'Frame'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+ def self.to_eval
+ WidgetClassName
+ end
+
+ def initialize(parent=nil, keys=nil)
+ if keys.kind_of? Hash
+ keys = keys.dup
+ if keys['classname']
+ @classname = keys['classname']
+ keys['classname'] = nil
+ end
+ if keys['colormap']
+ @colormap = keys['colormap']
+ keys['colormap'] = nil
+ end
+ if keys['container']
+ @classname = keys['container']
+ keys['classname'] = nil
+ end
+ if keys['visual']
+ @screen = keys['visual']
+ keys['visual'] = nil
+ end
+ end
+ super(parent, keys)
+ end
+
+ def create_self
+ s = []
+ s.push << "-class" << @classname if @classname
+ s.push << "-colormap" << @colormap if @colormap
+ s.push << "-container" << @container if @container
+ s.push << "-visual" << @visual if @visual
+ tk_call 'frame', @path, *s
+ end
+end
+
+class TkLabel<TkWindow
+ WidgetClassName = 'Label'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+ def self.to_eval
+ WidgetClassName
+ end
+ def create_self
+ tk_call 'label', @path
+ end
+ def textvariable(v)
+ configure 'textvariable', tk_trace_variable(v)
+ end
+end
+
+class TkButton<TkLabel
+ WidgetClassName = 'Button'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+# def TkButton.to_eval
+ def self.to_eval
+ WidgetClassName
+ end
+ def create_self
+ tk_call 'button', @path
+ end
+ def invoke
+ tk_send 'invoke'
+ end
+ def flash
+ tk_send 'flash'
+ end
+end
+
+class TkRadioButton<TkButton
+ WidgetClassName = 'Radiobutton'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+ def TkRadioButton.to_eval
+ WidgetClassName
+ end
+ def create_self
+ tk_call 'radiobutton', @path
+ end
+ def deselect
+ tk_send 'deselect'
+ end
+ def select
+ tk_send 'select'
+ end
+ def variable(v)
+ configure 'variable', tk_trace_variable(v)
+ end
+end
+
+class TkCheckButton<TkRadioButton
+ TkClassBind::WidgetClassNameTBL['Checkbutton'] = self
+ def TkCheckButton.to_eval
+ 'Checkbutton'
+ end
+ def create_self
+ tk_call 'checkbutton', @path
+ end
+ def toggle
+ tk_send 'toggle'
+ end
+end
+
+class TkMessage<TkLabel
+ TkClassBind::WidgetClassNameTBL['Message'] = self
+ def TkMessage.to_eval
+ 'Message'
+ end
+ def create_self
+ tk_call 'message', @path
+ end
+end
+
+class TkScale<TkWindow
+ WidgetClassName = 'Scale'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+ def self.to_eval
+ WidgetClassName
+ end
+
+ def create_self
+ tk_call 'scale', path
+ end
+
+ def get
+ number(tk_send('get'))
+ end
+
+ def set(val)
+ tk_send "set", val
+ end
+
+ def value
+ get
+ end
+
+ def value= (val)
+ set val
+ end
+end
+
+class TkScrollbar<TkWindow
+ WidgetClassName = 'Scrollbar'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+ def self.to_eval
+ WidgetClassName
+ end
+
+ def create_self
+ tk_call 'scrollbar', path
+ end
+
+ def delta(deltax=None, deltay=None)
+ number(tk_send('delta', deltax, deltay))
+ end
+
+ def fraction(x=None, y=None)
+ number(tk_send('fraction', x, y))
+ end
+
+ def identify(x=None, y=None)
+ tk_send('fraction', x, y)
+ end
+
+ def get
+ ary1 = tk_send('get', path).split
+ ary2 = []
+ for i in ary1
+ ary2.push number(i)
+ end
+ ary2
+ end
+
+ def set(first, last)
+ tk_send "set", first, last
+ end
+end
+
+class TkTextWin<TkWindow
+ def create_self
+ raise TypeError, "TkTextWin is abstract class"
+ end
+
+ def bbox(index)
+ tk_send 'bbox', index
+ end
+ def delete(first, last=None)
+ tk_send 'delete', first, last
+ end
+ def get(*index)
+ tk_send 'get', *index
+ end
+ def index(index)
+ tk_send 'index', index
+ end
+ def insert(index, chars, *args)
+ tk_send 'insert', index, chars, *args
+ end
+ def scan_mark(x, y)
+ tk_send 'scan', 'mark', x, y
+ end
+ def scan_dragto(x, y)
+ tk_send 'scan', 'dragto', x, y
+ end
+ def see(index)
+ tk_send 'see', index
+ end
+end
+
+class TkListbox<TkTextWin
+ TkClassBind::WidgetClassNameTBL['Listbox'] = self
+ def TkListbox.to_eval
+ 'Listbox'
+ end
+ def create_self
+ tk_call 'listbox', path
+ end
+
+ def activate(y)
+ tk_send 'activate', y
+ end
+ def curselection
+ list(tk_send('curselection'))
+ end
+ def nearest(y)
+ tk_send('nearest', y).to_i
+ end
+ def size(y)
+ tk_send('size').to_i
+ end
+ def selection_anchor(index)
+ tk_send 'selection', 'anchor', index
+ end
+ def selection_clear(first, last=None)
+ tk_send 'selection', 'clear', first, last
+ end
+ def selection_includes
+ bool(tk_send('selection', 'includes'))
+ end
+ def selection_set(first, last=None)
+ tk_send 'selection', 'set', first, last
+ end
+ def xview(cmd, index, *more)
+ v = tk_send('xview', cmd, index, *more)
+ v.to_i if more.size == 0
+ end
+ def yview(cmd, index, *more)
+ v = tk_send('yview', cmd, index, *more)
+ v.to_i if more.size == 0
+ end
+end
+
+module TkTreatMenuEntryFont
+ def tagfont_configinfo(index)
+ pathname = self.path + ';' + index
+ ret = TkFont.used_on(pathname)
+ if ret == nil
+ ret = TkFont.init_widget_font(pathname,
+ self.path, 'entryconfigure', index)
+ end
+ ret
+ end
+ alias tagfontobj tagfont_configinfo
+
+ def tagfont_configure(index, slot)
+ pathname = self.path + ';' + index
+ if (fnt = slot['font'])
+ slot['font'] = nil
+ if fnt.kind_of? TkFont
+ return fnt.call_font_configure(pathname,
+ self.path,'entryconfigure',index,slot)
+ else
+ latintagfont_configure(index, fnt) if fnt
+ end
+ end
+ if (ltn = slot['latinfont'])
+ slot['latinfont'] = nil
+ latintagfont_configure(index, ltn) if ltn
+ end
+ if (ltn = slot['asciifont'])
+ slot['asciifont'] = nil
+ latintagfont_configure(index, ltn) if ltn
+ end
+ if (knj = slot['kanjifont'])
+ slot['kanjifont'] = nil
+ kanjitagfont_configure(index, knj) if knj
+ end
+
+ tk_call(self.path, 'entryconfigure', index, *hash_kv(slot)) if slot != {}
+ self
+ end
+
+ def latintagfont_configure(index, ltn, keys=nil)
+ fobj = tagfontobj(index)
+ if ltn.kind_of? TkFont
+ conf = {}
+ ltn.latin_configinfo.each{|key,val| conf[key] = val if val != []}
+ if conf == {}
+ fobj.latin_replace(ltn)
+ fobj.latin_configure(keys) if keys
+ elsif keys
+ fobj.latin_configure(conf.update(keys))
+ else
+ fobj.latin_configure(conf)
+ end
+ else
+ fobj.latin_replace(ltn)
+ end
+ end
+ alias asciitagfont_configure latintagfont_configure
+
+ def kanjitagfont_configure(index, knj, keys=nil)
+ fobj = tagfontobj(index)
+ if knj.kind_of? TkFont
+ conf = {}
+ knj.kanji_configinfo.each{|key,val| conf[key] = val if val != []}
+ if conf == {}
+ fobj.kanji_replace(knj)
+ fobj.kanji_configure(keys) if keys
+ elsif keys
+ fobj.kanji_configure(conf.update(keys))
+ else
+ fobj.kanji_configure(conf)
+ end
+ else
+ fobj.kanji_replace(knj)
+ end
+ end
+
+ def tagfont_copy(index, window, wintag=nil)
+ if wintag
+ window.tagfontobj(wintag).configinfo.each{|key,value|
+ tagfontobj(index).configure(key,value)
+ }
+ tagfontobj(index).replace(window.tagfontobj(wintag).latin_font,
+ window.tagfontobj(wintag).kanji_font)
+ else
+ window.tagfont(wintag).configinfo.each{|key,value|
+ tagfontobj(index).configure(key,value)
+ }
+ tagfontobj(index).replace(window.fontobj.latin_font,
+ window.fontobj.kanji_font)
+ end
+ end
+
+ def latintagfont_copy(index, window, wintag=nil)
+ if wintag
+ tagfontobj(index).latin_replace(window.tagfontobj(wintag).latin_font)
+ else
+ tagfontobj(index).latin_replace(window.fontobj.latin_font)
+ end
+ end
+ alias asciitagfont_copy latintagfont_copy
+
+ def kanjitagfont_copy(index, window, wintag=nil)
+ if wintag
+ tagfontobj(index).kanji_replace(window.tagfontobj(wintag).kanji_font)
+ else
+ tagfontobj(index).kanji_replace(window.fontobj.kanji_font)
+ end
+ end
+end
+
+class TkMenu<TkWindow
+ include TkTreatMenuEntryFont
+
+ WidgetClassName = 'Menu'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+ def self.to_eval
+ WidgetClassName
+ end
+ def create_self
+ tk_call 'menu', path
+ end
+ def activate(index)
+ tk_send 'activate', index
+ end
+ def add(type, keys=nil)
+ tk_send 'add', type, *hash_kv(keys)
+ end
+ def index(index)
+ tk_send 'index', index
+ end
+ def invoke(index)
+ tk_send 'invoke', index
+ end
+ def insert(index, type, keys=nil)
+ tk_send 'add', index, type, *hash_kv(keys)
+ end
+ def delete(index, last=None)
+ tk_send 'delete', index, last
+ end
+ def post(x, y)
+ tk_send 'post', x, y
+ end
+ def postcascade(index)
+ tk_send 'postcascade', index
+ end
+ def postcommand(cmd=Proc.new)
+ configure_cmd 'postcommand', cmd
+ end
+ def menutype(index)
+ tk_send 'type', index
+ end
+ def unpost
+ tk_send 'unpost'
+ end
+ def yposition(index)
+ number(tk_send('yposition', index))
+ end
+ def entryconfigure(index, keys=nil)
+ tk_send 'entryconfigure', index, *hash_kv(keys)
+ end
+# def entryconfigure(index, keys=nil)
+# tk_send 'entryconfigure', index, *hash_kv(keys)
+# end
+ def entrycget(index, key)
+ tk_tcl2ruby tk_send 'entrycget', index, "-#{key}"
+ end
+ def entryconfigure(index, key, val=None)
+ if key.kind_of? Hash
+ if ( key['font'] || key['kanjifont'] \
+ || key['latinfont'] || key['asciifont'] )
+ tagfont_configure(index, key.dup)
+ else
+ tk_send 'entryconfigure', index, *hash_kv(key)
+ end
+
+ else
+ if ( key == 'font' || key == 'kanjifont' \
+ || key == 'latinfont' || key == 'asciifont' )
+ tagfont_configure({key=>val})
+ else
+ tk_call 'entryconfigure', index, "-#{key}", val
+ end
+ end
+ end
+
+ def entryconfiginfo(index, key=nil)
+ if key
+ conf = tk_split_list(tk_send('entryconfigure',index,"-#{key}"))
+ conf[0] = conf[0][1..-1]
+ conf
+ else
+ tk_split_list(tk_send('entryconfigure', index)).collect{|conf|
+ conf[0] = conf[0][1..-1]
+ conf
+ }
+ end
+ end
+end
+
+class TkMenubutton<TkLabel
+ TkClassBind::WidgetClassNameTBL['Menubutton'] = self
+ def TkMenubutton.to_eval
+ 'Menubutton'
+ end
+ def create_self
+ tk_call 'menubutton', path
+ end
+end
+
+module TkComposite
+ def initialize(parent=nil, *args)
+ @frame = TkFrame.new(parent)
+ @path = @epath = @frame.path
+ initialize_composite(*args)
+ end
+
+ def epath
+ @epath
+ end
+
+ def initialize_composite(*args) end
+ private :initialize_composite
+
+ def delegate(option, *wins)
+ unless @delegates
+ @delegates = {}
+ @delegates['DEFAULT'] = @frame
+ end
+ if @delegates[option].kind_of?(Array)
+ for i in wins
+ @delegates[option].push(i)
+ end
+ else
+ @delegates[option] = wins
+ end
+ end
+
+ def configure(slot, value=None)
+ if slot.kind_of? Hash
+ slot.each{|slot,value| configure slot, value}
+ else
+ if @delegates and @delegates[slot]
+ for i in @delegates[slot]
+ if not i
+ i = @delegates['DEFALUT']
+ redo
+ else
+ last = i.configure(slot, value)
+ end
+ end
+ last
+ else
+ super
+ end
+ end
+ end
+end
+
+module TkClipboard
+ include Tk
+ extend Tk
+
+ def clear
+ tk_call 'clipboard', 'clear'
+ end
+ def get
+ begin
+ tk_call 'selection', 'get', '-selection', 'CLIPBOARD'
+ rescue
+ ''
+ end
+ end
+ def set(data)
+ clear
+ append(data)
+ end
+ def append(data)
+ tk_call 'clipboard', 'append', data
+ end
+
+ module_function :clear, :set, :get, :append
+end
+
+autoload :TkCanvas, 'tkcanvas'
+autoload :TkImage, 'tkcanvas'
+autoload :TkBitmapImage, 'tkcanvas'
+autoload :TkPhotoImage, 'tkcanvas'
+autoload :TkEntry, 'tkentry'
+autoload :TkText, 'tktext'
+autoload :TkDialog, 'tkdialog'
+autoload :TkMenubar, 'tkmenubar'
+autoload :TkAfter, 'tkafter'
+autoload :TkPalette, 'tkpalette'
+autoload :TkFont, 'tkfont'
+autoload :TkVirtualEvent, 'tkvirtevent'
diff --git a/ext/tk/lib/tkafter.rb b/ext/tk/lib/tkafter.rb
new file mode 100644
index 0000000000..be2e50ff3a
--- /dev/null
+++ b/ext/tk/lib/tkafter.rb
@@ -0,0 +1,296 @@
+#
+# tkafter.rb : methods for Tcl/Tk after command
+# 1998/07/02 by Hidetoshi Nagai <nagai@ai.kyutech.ac.jp>
+#
+require 'tk'
+
+class TkAfter
+ include TkCore
+ extend TkCore
+
+ Tk_CBID = [0]
+ Tk_CBTBL = {}
+
+ INTERP._invoke("proc", "rb_after", "args", "ruby [format \"TkAfter.callback %%Q!%s!\" $args]")
+
+ ###############################
+ # class methods
+ ###############################
+ def TkAfter.callback(arg)
+ @after_id = nil
+ arg = Array(tk_split_list(arg))
+ obj_id = arg.shift
+ ex_obj = Tk_CBTBL[obj_id]
+ return nil if ex_obj == nil; # canceled
+ _get_eval_string(ex_obj.do_callback(*arg))
+ end
+
+ def TkAfter.info
+ tk_call('after', 'info').split(' ').filter{|id|
+ ret = Tk_CBTBL.find{|key,val| val.after_id == id}
+ (ret == nil)? id: ret[1]
+ }
+ end
+
+ ###############################
+ # instance methods
+ ###############################
+ def do_callback(*args)
+ @in_callback = true
+ ret = @current_proc.call(*args)
+ if @set_next
+ set_next_callback(*args)
+ else
+ @set_next = true
+ end
+ @in_callback = false
+ ret
+ end
+
+ def set_callback(sleep, args=nil)
+ @after_script = "rb_after #{@id} #{_get_eval_string(args)}"
+ @after_id = tk_call('after', sleep, @after_script)
+ @current_script = [sleep, @after_script]
+ end
+
+ def set_next_callback(*args)
+ if @running == false || @proc_max == 0 || @do_loop == 0
+ Tk_CBTBL[@id] = nil ;# for GC
+ @running = false
+ return
+ end
+ if @current_pos >= @proc_max
+ if @do_loop < 0 || (@do_loop -= 1) > 0
+ @current_pos = 0
+ else
+ Tk_CBTBL[@id] = nil ;# for GC
+ @running = false
+ return
+ end
+ end
+
+ @current_args = args
+
+ if @sleep_time.kind_of? Proc
+ sleep = @sleep_time.call(*args)
+ else
+ sleep = @sleep_time
+ end
+ @current_sleep = sleep
+
+ cmd, *cmd_args = @loop_proc[@current_pos]
+ @current_pos += 1
+ @current_proc = cmd
+
+ if cmd_args[0].kind_of? Proc
+ #c = cmd_args.shift
+ #cb_args = c.call(*(cmd_args + args))
+ cb_args = cmd_args[0].call(*args)
+ else
+ cb_args = cmd_args
+ end
+
+ set_callback(sleep, cb_args)
+ end
+
+ def initialize(*args)
+ @id = format("a%.4d", Tk_CBID[0])
+ Tk_CBID[0] += 1
+
+ @set_next = true
+
+ @init_sleep = 0
+ @init_proc = nil
+ @init_args = []
+
+ @current_script = []
+ @current_proc = nil
+ @current_args = nil
+
+ @sleep_time = 0
+ @current_sleep = 0
+ @loop_exec = 0
+ @do_loop = 0
+ @loop_proc = []
+ @proc_max = 0
+ @current_pos = 0
+
+ @after_id = nil
+ @after_script = nil
+
+ set_procs(*args) if args != []
+
+ @running = false
+ end
+
+ attr :after_id
+ attr :after_script
+ attr :current_proc
+ attr :current_sleep
+
+ attr_accessor :loop_exec
+
+ def get_procs
+ [@init_sleep, @init_proc, @init_args, @sleep_time, @loop_exec, @loop_proc]
+ end
+
+ def current_status
+ [@running, @current_sleep, @current_proc, @current_args, @do_loop]
+ end
+
+ def running?
+ @running
+ end
+
+ def loop_rest
+ @do_loop
+ end
+
+ def loop_rest=(rest)
+ @do_loop = rest
+ end
+
+ def set_procs(interval, loop_exec, *procs)
+ if !interval == 'idle' \
+ && !interval.kind_of?(Integer) && !interval.kind_of?(Proc)
+ fail format("%s need to be Integer or Proc", interval.inspect)
+ end
+ @sleep_time = interval
+
+ @loop_proc = []
+ procs.each{|e|
+ if e.kind_of? Proc
+ @loop_proc.push([e])
+ else
+ @loop_proc.push(e)
+ end
+ }
+ @proc_max = @loop_proc.size
+ @current_pos = 0
+
+ @do_loop = 0
+ if loop_exec
+ if loop_exec.kind_of?(Integer) && loop_exec < 0
+ @loop_exec = -1
+ elsif loop_exec == nil || loop_exec == false || loop_exec == 0
+ @loop_exec = 1
+ else
+ if not loop_exec.kind_of?(Integer)
+ fail format("%s need to be Integer", loop_exec.inspect)
+ end
+ @loop_exec = loop_exec
+ end
+ @do_loop = @loop_exec
+ end
+
+ self
+ end
+
+ def add_procs(*procs)
+ procs.each{|e|
+ if e.kind_of? Proc
+ @loop_proc.push([e])
+ else
+ @loop_proc.push(e)
+ end
+ }
+ @proc_max = @loop_proc.size
+
+ self
+ end
+
+ def set_start_proc(sleep, init_proc, *init_args)
+ if !sleep == 'idle' && !sleep.kind_of?(Integer)
+ fail format("%s need to be Integer", sleep.inspect)
+ end
+ @init_sleep = sleep
+ @init_proc = init_proc
+ @init_args = init_args
+ self
+ end
+
+ def start(*init_args)
+ return nil if @running
+
+ Tk_CBTBL[@id] = self
+ @do_loop = @loop_exec
+ @current_pos = 0
+
+ argc = init_args.size
+ if argc > 0
+ sleep = init_args.shift
+ if !sleep == 'idle' && !sleep.kind_of?(Integer)
+ fail format("%s need to be Integer", sleep.inspect)
+ end
+ @init_sleep = sleep
+ end
+ @init_proc = init_args.shift if argc > 1
+ @init_args = init_args if argc > 0
+
+ @current_sleep = @init_sleep
+ @running = true
+ if @init_proc
+ if not @init_proc.kind_of? Proc
+ fail format("%s need to be Proc", @init_proc.inspect)
+ end
+ @current_proc = @init_proc
+ set_callback(sleep, @init_args)
+ @set_next = false if @in_callback
+ else
+ set_next_callback(*@init_args)
+ end
+
+ self
+ end
+
+ def restart(*restart_args)
+ cancel if @running
+ if restart_args == []
+ start(@init_sleep, @init_proc, *@init_args)
+ else
+ start(*restart_args)
+ end
+ end
+
+ def cancel
+ @running = false
+ tk_call 'after', 'cancel', @after_id if @after_id
+ @after_id = nil
+ Tk_CBTBL[@id] = nil ;# for GC
+ self
+ end
+ alias stop cancel
+
+ def continue(wait=nil)
+ sleep, cmd = @current_script
+ return nil if cmd == nil || @running == true
+ if wait
+ if not wait.kind_of? Integer
+ fail format("%s need to be Integer", wait.inspect)
+ end
+ sleep = wait
+ end
+ Tk_CBTBL[@id] = self
+ @running = true
+ @after_id = tk_call('after', sleep, cmd)
+ self
+ end
+
+ def skip
+ return nil if @running == false
+ cancel
+ Tk_CBTBL[@id] = self
+ @running = true
+ set_next_callback(@current_args)
+ self
+ end
+
+ def info
+ if @after_id
+ inf = tk_split_list(tk_call('after', 'info', @after_id))
+ [Tk_CBTBL[inf[0][1]], inf[1]]
+ else
+ nil
+ end
+ end
+end
diff --git a/ext/tk/lib/tkbgerror.rb b/ext/tk/lib/tkbgerror.rb
new file mode 100644
index 0000000000..8022077a3f
--- /dev/null
+++ b/ext/tk/lib/tkbgerror.rb
@@ -0,0 +1,17 @@
+#
+# tkbgerror -- bgerror ( tkerror ) module
+# 1998/07/16 by Hidetoshi Nagai <nagai@ai.kyutech.ac.jp>
+#
+require 'tk'
+
+module TkBgError
+ extend Tk
+
+ def bgerror(message)
+ tk_call 'bgerror', message
+ end
+ alias tkerror bgerror
+ alias show bgerror
+
+ module_function :bgerror, :tkerror, :show
+end
diff --git a/ext/tk/lib/tkcanvas.rb b/ext/tk/lib/tkcanvas.rb
new file mode 100644
index 0000000000..1cf24eeb7b
--- /dev/null
+++ b/ext/tk/lib/tkcanvas.rb
@@ -0,0 +1,829 @@
+#
+# tkcanvas.rb - Tk canvas classes
+# $Date$
+# by Yukihiro Matsumoto <matz@caelum.co.jp>
+# $Date$
+# by Hidetoshi Nagai <nagai@ai.kyutech.ac.jp>
+
+require "tk"
+require 'tkfont'
+
+module TkTreatCItemFont
+ def tagfont_configinfo(tagOrId)
+ if tagOrId.kind_of?(TkcItem) || tagOrId.kind_of?(TkcTag)
+ pathname = self.path + ';' + tagOrId.id.to_s
+ else
+ pathname = self.path + ';' + tagOrId.to_s
+ end
+ ret = TkFont.used_on(pathname)
+ if ret == nil
+ ret = TkFont.init_widget_font(pathname,
+ self.path, 'itemconfigure', tagOrId)
+ end
+ ret
+ end
+ alias tagfontobj tagfont_configinfo
+
+ def tagfont_configure(tagOrId, slot)
+ if tagOrId.kind_of?(TkcItem) || tagOrId.kind_of?(TkcTag)
+ pathname = self.path + ';' + tagOrId.id.to_s
+ else
+ pathname = self.path + ';' + tagOrId.to_s
+ end
+ if (fnt = slot['font'])
+ slot['font'] = nil
+ if fnt.kind_of? TkFont
+ return fnt.call_font_configure(pathname,
+ self.path,'itemconfigure',tagOrId,slot)
+ else
+ latintagfont_configure(tagOrId, fnt) if fnt
+ end
+ end
+ if (ltn = slot['latinfont'])
+ slot['latinfont'] = nil
+ latintagfont_configure(tagOrId, ltn) if ltn
+ end
+ if (ltn = slot['asciifont'])
+ slot['asciifont'] = nil
+ latintagfont_configure(tagOrId, ltn) if ltn
+ end
+ if (knj = slot['kanjifont'])
+ slot['kanjifont'] = nil
+ kanjitagfont_configure(tagOrId, knj) if knj
+ end
+
+ tk_call(self.path, 'itemconfigure', tagOrId, *hash_kv(slot)) if slot != {}
+ self
+ end
+
+ def latintagfont_configure(tagOrId, ltn, keys=nil)
+ fobj = tagfontobj(tagOrId)
+ if ltn.kind_of? TkFont
+ conf = {}
+ ltn.latin_configinfo.each{|key,val| conf[key] = val if val != []}
+ if conf == {}
+ fobj.latin_replace(ltn)
+ fobj.latin_configure(keys) if keys
+ elsif keys
+ fobj.latin_configure(conf.update(keys))
+ else
+ fobj.latin_configure(conf)
+ end
+ else
+ fobj.latin_replace(ltn)
+ end
+ end
+ alias asciitagfont_configure latintagfont_configure
+
+ def kanjitagfont_configure(tagOrId, knj, keys=nil)
+ fobj = tagfontobj(tagOrId)
+ if knj.kind_of? TkFont
+ conf = {}
+ knj.kanji_configinfo.each{|key,val| conf[key] = val if val != []}
+ if conf == {}
+ fobj.kanji_replace(knj)
+ fobj.kanji_configure(keys) if keys
+ elsif keys
+ fobj.kanji_configure(conf.update(keys))
+ else
+ fobj.kanji_configure(conf)
+ end
+ else
+ fobj.kanji_replace(knj)
+ end
+ end
+
+ def tagfont_copy(tagOrId, window, wintag=nil)
+ if wintag
+ window.tagfontobj(wintag).configinfo.each{|key,value|
+ tagfontobj(tagOrId).configure(key,value)
+ }
+ tagfontobj(tagOrId).replace(window.tagfontobj(wintag).latin_font,
+ window.tagfontobj(wintag).kanji_font)
+ else
+ window.tagfont(tagOrId).configinfo.each{|key,value|
+ tagfontobj(tagOrId).configure(key,value)
+ }
+ tagfontobj(tagOrId).replace(window.fontobj.latin_font,
+ window.fontobj.kanji_font)
+ end
+ end
+
+ def latintagfont_copy(tagOrId, window, wintag=nil)
+ if wintag
+ tagfontobj(tagOrId).latin_replace(window.tagfontobj(wintag).latin_font)
+ else
+ tagfontobj(tagOrId).latin_replace(window.fontobj.latin_font)
+ end
+ end
+ alias asciitagfont_copy latintagfont_copy
+
+ def kanjitagfont_copy(tagOrId, window, wintag=nil)
+ if wintag
+ tagfontobj(tagOrId).kanji_replace(window.tagfontobj(wintag).kanji_font)
+ else
+ tagfontobj(tagOrId).kanji_replace(window.fontobj.kanji_font)
+ end
+ end
+end
+
+class TkCanvas<TkWindow
+ include TkTreatCItemFont
+
+ WidgetClassName = 'Canvas'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+ def self.to_eval
+ WidgetClassName
+ end
+
+ def create_self
+ tk_call 'canvas', path
+ end
+
+ def tagid(tag)
+ if tag.kind_of?(TkcItem) || tag.kind_of?(TkcTag)
+ tag.id
+ else
+ tag
+ end
+ end
+ private :tagid
+
+ def addtag(tag, mode, *args)
+ tk_send 'addtag', tagid(tag), mode, *args
+ end
+ def addtag_above(tagOrId, target)
+ addtag(tagOrId, 'above', tagid(target))
+ end
+ def addtag_all(tagOrId)
+ addtag(tagOrId, 'all')
+ end
+ def addtag_below(tagOrId, target)
+ addtag(tagOrId, 'below', tagid(target))
+ end
+ def addtag_closest(tagOrId, x, y, halo=None, start=None)
+ addtag(tagOrId, 'closest', x, y, halo, start)
+ end
+ def addtag_enclosed(tagOrId, x1, y1, x2, y2)
+ addtag(tagOrId, 'enclosed', x1, y1, x2, y2)
+ end
+ def addtag_overlapping(tagOrId, x1, y1, x2, y2)
+ addtag(tagOrId, 'overlapping', x1, y1, x2, y2)
+ end
+ def addtag_withtag(tagOrId, tag)
+ addtag(tagOrId, 'withtag', tagid(tag))
+ end
+
+ def bbox(tagOrId, *tags)
+ list(tk_send('bbox', tagid(tagOrId), *tags))
+ end
+
+ def itembind(tag, context, cmd=Proc.new, args=nil)
+ id = install_bind(cmd, args)
+ begin
+ tk_send 'bind', tagid(tag), "<#{tk_event_sequence(context)}>", id
+ rescue
+ uninstall_cmd(cmd)
+ fail
+ end
+ # @cmdtbl.push id
+ end
+
+ def itembindinfo(tag, context=nil)
+ if context
+ (tk_send('bind', tagid(tag),
+ "<#{tk_event_sequence(context)}>")).collect{|cmdline|
+ if cmdline =~ /^rb_out (c\d+)\s+(.*)$/
+ [Tk_CMDTBL[$1], $2]
+ else
+ cmdline
+ end
+ }
+ else
+ tk_split_list(tk_send 'bind', tagid(tag)).filter{|seq|
+ seq[1..-2].gsub(/></,',')
+ }
+ end
+ end
+
+ def canvasx(x, *args)
+ tk_tcl2ruby(tk_send 'canvasx', x, *args)
+ end
+ def canvasy(y, *args)
+ tk_tcl2ruby(tk_send 'canvasy', y, *args)
+ end
+
+ def coords(tag, *args)
+ if args == []
+ tk_split_list(tk_send('coords', tagid(tag)))
+ else
+ tk_send('coords', tagid(tag), *args)
+ end
+ end
+
+ def dchars(tag, first, last=None)
+ tk_send 'dchars', tagid(tag), first, last
+ end
+
+ def delete(*args)
+ tk_send 'delete', *args
+ end
+ alias remove delete
+
+ def dtag(tag, tag_to_del=None)
+ tk_send 'dtag', tagid(tag), tag_to_del
+ end
+
+ def find(mode, *args)
+ list(tk_send 'find', mode, *args).filter{|id|
+ TkcItem.id2obj(id)
+ }
+ end
+ def find_above(target)
+ find('above', tagid(target))
+ end
+ def find_all
+ find('all')
+ end
+ def find_below(target)
+ find('below', tagid(target))
+ end
+ def find_closest(x, y, halo=None, start=None)
+ find('closest', x, y, halo, start)
+ end
+ def find_enclosed(x1, y1, x2, y2)
+ find('enclosed', x1, y1, x2, y2)
+ end
+ def find_overlapping(x1, y1, x2, y2)
+ find('overlapping', x1, y1, x2, y2)
+ end
+ def find_withtag(tag)
+ find('withtag', tag)
+ end
+
+ def itemfocus(tagOrId=nil)
+ if tagOrId
+ tk_send 'focus', tagid(tagOrId)
+ else
+ ret = tk_send('focus')
+ if ret == ""
+ nil
+ else
+ TkcItem.id2obj(ret)
+ end
+ end
+ end
+
+ def gettags(tagOrId)
+ list(tk_send('gettags', tagid(tagOrId))).collect{|tag|
+ TkcTag.id2obj(tag)
+ }
+ end
+
+ def icursor(tagOrId, index)
+ tk_send 'icursor', tagid(tagOrId), index
+ end
+
+ def index(tagOrId, index)
+ tk_send 'index', tagid(tagOrId), index
+ end
+
+ def insert(tagOrId, index, string)
+ tk_send 'insert', tagid(tagOrId), index, string
+ end
+
+ def itemcget(tagOrId, option)
+ tk_tcl2ruby tk_send 'itemcget', tagid(tagOrId), "-#{option}"
+ end
+
+ def itemconfigure(tagOrId, key, value=None)
+ if key.kind_of? Hash
+ if ( key['font'] || key['kanjifont'] \
+ || key['latinfont'] || key['asciifont'] )
+ tagfont_configure(tagOrId, key.dup)
+ else
+ tk_send 'itemconfigure', tagid(tagOrId), *hash_kv(key)
+ end
+
+ else
+ if ( key == 'font' || key == 'kanjifont' \
+ || key == 'latinfont' || key == 'asciifont' )
+ tagfont_configure(tagid(tagOrId), {key=>value})
+ else
+ tk_send 'itemconfigure', tagid(tagOrId), "-#{key}", value
+ end
+ end
+ end
+# def itemconfigure(tagOrId, key, value=None)
+# if key.kind_of? Hash
+# tk_send 'itemconfigure', tagid(tagOrId), *hash_kv(key)
+# else
+# tk_send 'itemconfigure', tagid(tagOrId), "-#{key}", value
+# end
+# end
+# def itemconfigure(tagOrId, keys)
+# tk_send 'itemconfigure', tagid(tagOrId), *hash_kv(keys)
+# end
+
+ def itemconfiginfo(tagOrId, key=nil)
+ if key
+ conf = tk_split_list(tk_send 'itemconfigure', tagid(tagOrId), "-#{key}")
+ conf[0] = conf[0][1..-1]
+ conf
+ else
+ tk_split_list(tk_send 'itemconfigure', tagid(tagOrId)).collect{|conf|
+ conf[0] = conf[0][1..-1]
+ conf
+ }
+ end
+ end
+
+ def lower(tag, below=None)
+ tk_send 'lower', tagid(tag), below
+ end
+
+ def move(tag, x, y)
+ tk_send 'move', tagid(tag), x, y
+ end
+
+ def postscript(keys)
+ tk_send "postscript", *hash_kv(keys)
+ end
+
+ def raise(tag, above=None)
+ tk_send 'raise', tagid(tag), above
+ end
+
+ def scale(tag, x, y, xs, ys)
+ tk_send 'scale', tagid(tag), x, y, xs, ys
+ end
+
+ def scan_mark(x, y)
+ tk_send 'scan', 'mark', x, y
+ end
+ def scan_dragto(x, y)
+ tk_send 'scan', 'dragto', x, y
+ end
+
+ def select(mode, *args)
+ tk_send 'select', mode, *args
+ end
+ def select_adjust(tagOrId, index)
+ select('adjust', tagid(tagOrId), index)
+ end
+ def select_clear
+ select('clear')
+ end
+ def select_from(tagOrId, index)
+ select('from', tagid(tagOrId), index)
+ end
+ def select_item
+ select('item')
+ end
+ def select_to(tagOrId, index)
+ select('to', tagid(tagOrId), index)
+ end
+
+ def itemtype(tag)
+ TkcItem.type2class(tk_send 'type', tagid(tag))
+ end
+
+ def xview(*index)
+ tk_send 'xview', *index
+ end
+ def yview(*index)
+ tk_send 'yview', *index
+ end
+end
+
+module TkcTagAccess
+ include TkComm
+ include TkTreatTagFont
+
+ def addtag(tag)
+ @c.addtag(tag, 'with', @id)
+ end
+
+ def bbox
+ @c.bbox(@id)
+ end
+
+ def bind(seq, cmd=Proc.new, args=nil)
+ @c.itembind @id, seq, cmd, args
+ end
+
+ def bindinfo(seq=nil)
+ @c.itembindinfo @id, seq
+ end
+
+ def cget(option)
+ @c.itemcget @id, option
+ end
+
+ def configure(key, value=None)
+ @c.itemconfigure @id, key, value
+ end
+# def configure(keys)
+# @c.itemconfigure @id, keys
+# end
+
+ def configinfo(key=nil)
+ @c.itemconfiginfo @id, key
+ end
+
+ def coords(*args)
+ @c.coords @id, *args
+ end
+
+ def dchars(first, last=None)
+ @c.dchars @id, first, last
+ end
+
+ def dtag(tag_to_del=None)
+ @c.dtag @id, tag_to_del
+ end
+
+ def find
+ @c.find 'withtag', @id
+ end
+ alias list find
+
+ def focus
+ @c.itemfocus @id
+ end
+
+ def gettags
+ @c.gettags @id
+ end
+
+ def icursor(index)
+ @c.icursor @id, index
+ end
+
+ def index(index)
+ @c.index @id, index
+ end
+
+ def insert(beforethis, string)
+ @c.insert @id, beforethis, string
+ end
+
+ def lower(belowthis=None)
+ @c.lower @id, belowthis
+ end
+
+ def move(xamount, yamount)
+ @c.move @id, xamount, yamount
+ end
+
+ def raise(abovethis=None)
+ @c.raise @id, abovethis
+ end
+
+ def scale(xorigin, yorigin, xscale, yscale)
+ @c.scale @id, xorigin, yorigin, xscale, yscale
+ end
+
+ def select_adjust(index)
+ @c.select('adjust', @id, index)
+ end
+ def select_from(index)
+ @c.select('from', @id, index)
+ end
+ def select_to(index)
+ @c.select('to', @id, index)
+ end
+
+ def itemtype
+ @c.itemtype @id
+ end
+end
+
+class TkcTag<TkObject
+ include TkcTagAccess
+
+ CTagID_TBL = {}
+
+ def TkcTag.id2obj(id)
+ CTagID_TBL[id]? CTagID_TBL[id]: id
+ end
+
+ $tk_canvas_tag = 'ctag0000'
+ def initialize(parent, mode=nil, *args)
+ if not parent.kind_of?(TkCanvas)
+ fail format("%s need to be TkCanvas", parent.inspect)
+ end
+ @c = parent
+ @path = @id = $tk_canvas_tag
+ CTagID_TBL[@id] = self
+ $tk_canvas_tag = $tk_canvas_tag.succ
+ if mode
+ tk_call @c.path, "addtag", @id, mode, *args
+ end
+ end
+ def id
+ return @id
+ end
+
+ def delete
+ @c.delete @id
+ CTagID_TBL[@id] = nil
+ end
+ alias remove delete
+ alias destroy delete
+
+ def set_to_above(target)
+ @c.addtag_above(@id, target)
+ end
+ alias above set_to_above
+
+ def set_to_all
+ @c.addtag_all(@id)
+ end
+ alias all set_to_all
+
+ def set_to_below(target)
+ @c.addtag_below(@id, target)
+ end
+ alias below set_to_below
+
+ def set_to_closest(x, y, halo=None, start=None)
+ @c.addtag_closest(@id, x, y, halo, start)
+ end
+ alias closest set_to_closest
+
+ def set_to_enclosed(x1, y1, x2, y2)
+ @c.addtag_enclosest(@id, x1, y1, x2, y2)
+ end
+ alias enclosed set_to_enclosed
+
+ def set_to_overlapping(x1, y1, x2, y2)
+ @c.addtag_overlapping(@id, x1, y1, x2, y2)
+ end
+ alias overlapping set_to_overlapping
+
+ def set_to_withtag(target)
+ @c.addtag_withtag(@id, target)
+ end
+ alias withtag set_to_withtag
+end
+
+class TkcTagAll<TkcTag
+ def initialize(parent)
+ if not parent.kind_of?(TkCanvas)
+ fail format("%s need to be TkCanvas", parent.inspect)
+ end
+ @c = parent
+ @path = @id = 'all'
+ CTagID_TBL[@id] = self
+ end
+end
+
+class TkcTagCurrent<TkcTag
+ def initialize(parent)
+ if not parent.kind_of?(TkCanvas)
+ fail format("%s need to be TkCanvas", parent.inspect)
+ end
+ @c = parent
+ @path = @id = 'current'
+ CTagID_TBL[@id] = self
+ end
+end
+
+class TkcGroup<TkcTag
+ $tk_group_id = 'tkg00000'
+ def create_self(parent, *args)
+ if not parent.kind_of?(TkCanvas)
+ fail format("%s need to be TkCanvas", parent.inspect)
+ end
+ @c = parent
+ @path = @id = $tk_group_id
+ CTagID_TBL[@id] = self
+ $tk_group_id = $tk_group_id.succ
+ add(*args) if args != []
+ end
+
+ def include(*tags)
+ for i in tags
+ i.addtag @id
+ end
+ end
+
+ def exclude(*tags)
+ for i in tags
+ i.delete @id
+ end
+ end
+end
+
+
+class TkcItem<TkObject
+ include TkcTagAccess
+
+ CItemTypeToClass = {}
+ CItemID_TBL = {}
+
+ def TkcItem.type2class(type)
+ CItemTypeToClass[type]
+ end
+
+ def TkcItem.id2obj(id)
+ CItemID_TBL[id]? CItemID_TBL[id]: id
+ end
+
+ def initialize(parent, *args)
+ if not parent.kind_of?(TkCanvas)
+ fail format("%s need to be TkCanvas", parent.inspect)
+ end
+ @parent = @c = parent
+ @path = parent.path
+ if args[-1].kind_of? Hash
+ keys = args.pop
+ end
+ @id = create_self(*args).to_i ;# 'canvas item id' is integer number
+ CItemID_TBL[@id] = self
+ if keys
+ # tk_call @path, 'itemconfigure', @id, *hash_kv(keys)
+ configure(keys) if keys
+ end
+ end
+ def create_self(*args); end
+ private :create_self
+ def id
+ return @id
+ end
+
+ def delete
+ @c.delete @id
+ CItemID_TBL[@id] = nil
+ end
+ alias remove delete
+ alias destroy delete
+end
+
+class TkcArc<TkcItem
+ CItemTypeToClass['arc'] = self
+ def create_self(*args)
+ tk_call(@path, 'create', 'arc', *args)
+ end
+end
+class TkcBitmap<TkcItem
+ CItemTypeToClass['bitmap'] = self
+ def create_self(*args)
+ tk_call(@path, 'create', 'bitmap', *args)
+ end
+end
+class TkcImage<TkcItem
+ CItemTypeToClass['image'] = self
+ def create_self(*args)
+ tk_call(@path, 'create', 'image', *args)
+ end
+end
+class TkcLine<TkcItem
+ CItemTypeToClass['line'] = self
+ def create_self(*args)
+ tk_call(@path, 'create', 'line', *args)
+ end
+end
+class TkcOval<TkcItem
+ CItemTypeToClass['oval'] = self
+ def create_self(*args)
+ tk_call(@path, 'create', 'oval', *args)
+ end
+end
+class TkcPolygon<TkcItem
+ CItemTypeToClass['polygon'] = self
+ def create_self(*args)
+ tk_call(@path, 'create', 'polygon', *args)
+ end
+end
+class TkcRectangle<TkcItem
+ CItemTypeToClass['rectangle'] = self
+ def create_self(*args)
+ tk_call(@path, 'create', 'rectangle', *args)
+ end
+end
+class TkcText<TkcItem
+ CItemTypeToClass['text'] = self
+ def create_self(*args)
+ tk_call(@path, 'create', 'text', *args)
+ end
+end
+class TkcWindow<TkcItem
+ CItemTypeToClass['window'] = self
+ def create_self(*args)
+ tk_call(@path, 'create', 'window', *args)
+ end
+end
+
+class TkImage<TkObject
+ include Tk
+
+ Tk_IMGTBL = {}
+
+ $tk_image_id = 'i00000'
+ def initialize(keys=nil)
+ @path = $tk_image_id
+ $tk_image_id = $tk_image_id.succ
+ tk_call 'image', 'create', @type, @path, *hash_kv(keys)
+ Tk_IMGTBL[@path] = self
+ end
+
+ def delete
+ Tk_IMGTBL[@id] = nil if @id
+ tk_call('image', 'delete', @path)
+ end
+ def height
+ number(tk_call('image', 'height', @path))
+ end
+ def itemtype
+ tk_call('image', 'type', @path)
+ end
+ def width
+ number(tk_call('image', 'width', @path))
+ end
+
+ def TkImage.names
+ Tk.tk_call('image', 'names').split.filter{|id|
+ (Tk_IMGTBL[id])? Tk_IMGTBL[id] : id
+ }
+ end
+
+ def TkImage.types
+ Tk.tk_call('image', 'types').split
+ end
+end
+
+class TkBitmapImage<TkImage
+ def initialize(*args)
+ @type = 'bitmap'
+ super
+ end
+end
+
+class TkPhotoImage<TkImage
+ def initialize(*args)
+ @type = 'photo'
+ super
+ end
+
+ def blank
+ tk_send 'blank'
+ end
+
+ def cget(option)
+ tk_tcl2ruby tk_send 'cget', option
+ end
+
+ def copy(source, *opts)
+ args = opts.collect{|term|
+ if term.kind_of?(String) && term.include?(?\s)
+ term.split
+ else
+ term
+ end
+ }.flatten
+
+ tk_send 'copy', source, *args
+ end
+
+ def get(x, y)
+ tk_send 'get', x, y
+ end
+
+ def put(data, *to)
+ if to == []
+ tk_send 'put', data
+ else
+ tk_send 'put', data, '-to', *to
+ end
+ end
+
+ def read(file, *opts)
+ args = opts.collect{|term|
+ if term.kind_of?(String) && term.include?(?\s)
+ term.split
+ else
+ term
+ end
+ }.flatten
+
+ tk_send 'read', file, *args
+ end
+
+ def redither
+ tk_send 'redither'
+ end
+
+ def write(file, *opts)
+ args = opts.collect{|term|
+ if term.kind_of?(String) && term.include?(?\s)
+ term.split
+ else
+ term
+ end
+ }.flatten
+
+ tk_send 'write', file, *args
+ end
+end
diff --git a/ext/tk/lib/tkclass.rb b/ext/tk/lib/tkclass.rb
new file mode 100644
index 0000000000..0b33d4ec8b
--- /dev/null
+++ b/ext/tk/lib/tkclass.rb
@@ -0,0 +1,38 @@
+#
+# tkclass.rb - Tk classes
+# $Date$
+# by Yukihiro Matsumoto <matz@caelum.co.jp>
+
+require "tk"
+
+TopLevel = TkToplevel
+Frame = TkFrame
+Label = TkLabel
+Button = TkButton
+Radiobutton = TkRadioButton
+Checkbutton = TkCheckButton
+Message = TkMessage
+Entry = TkEntry
+Text = TkText
+Scale = TkScale
+Scrollbar = TkScrollbar
+Listbox = TkListbox
+Menu = TkMenu
+Menubutton = TkMenubutton
+Canvas = TkCanvas
+Arc = TkcArc
+Bitmap = TkcBitmap
+Line = TkcLine
+Oval = TkcOval
+Polygon = TkcPolygon
+Rectangle = TkcRectangle
+TextItem = TkcText
+WindowItem = TkcWindow
+Selection = TkSelection
+Winfo = TkWinfo
+Pack = TkPack
+Variable = TkVariable
+
+def Mainloop
+ Tk.mainloop
+end
diff --git a/ext/tk/lib/tkdialog.rb b/ext/tk/lib/tkdialog.rb
new file mode 100644
index 0000000000..1133db6ae9
--- /dev/null
+++ b/ext/tk/lib/tkdialog.rb
@@ -0,0 +1,141 @@
+require "tk"
+
+class TkDialog < TkWindow
+ extend Tk
+
+ # initialize tk_dialog
+ def initialize(keys = nil)
+ super()
+ @var = TkVariable.new
+ id = @var.id
+
+ @title = title
+
+ @message = message
+ @message_config = message_config
+
+ @bitmap = bitmap
+ @bitmap_config = message_config
+
+ @default_button = default_button
+
+ @buttons = buttons
+ @button_configs = proc{|num| button_configs num}
+
+ if keys.kind_of? Hash
+ @title = keys['title'] if keys['title']
+ @message = keys['message'] if keys['message']
+ @bitmap = keys['bitmap'] if keys['bitmap']
+ @default_button = keys['default'] if keys['default']
+ @buttons = keys['buttons'] if keys['buttons']
+
+ @command = keys['prev_command']
+
+ @message_config = keys['message_config'] if keys['message_config']
+ @bitmap_config = keys['bitmap_config'] if keys['bitmap_config']
+ @button_configs = keys['button_configs'] if keys['button_configs']
+ end
+
+ if @title.include? ?\s
+ @title = '{' + @title + '}'
+ end
+
+ @buttons = tk_split_list(@buttons) if @buttons.kind_of? String
+ @buttons = @buttons.collect{|s|
+ if s.kind_of? Array
+ s = s.join(' ')
+ end
+ if s.include? ?\s
+ '{' + s + '}'
+ else
+ s
+ end
+ }
+
+ config = ""
+ if @message_config.kind_of? Hash
+ config << format("%s.msg configure %s\n",
+ @path, hash_kv(@message_config).join(' '))
+ end
+ if @bitmap_config.kind_of? Hash
+ config << format("%s.msg configure %s\n",
+ @path, hash_kv(@bitmap_config).join(' '))
+ end
+ if @button_configs.kind_of? Proc
+ @buttons.each_index{|i|
+ if (c = @button_configs.call(i)).kind_of? Hash
+ config << format("%s.button%s configure %s\n",
+ @path, i, hash_kv(c).join(' '))
+ end
+ }
+ end
+ config = 'after idle {' + config + '};' if config != ""
+
+ if @command.kind_of? Proc
+ @command.call(self)
+ end
+
+ INTERP._eval('eval {global '+id+';'+config+
+ 'set '+id+' [tk_dialog '+
+ @path+" "+@title+" {#{@message}} "+@bitmap+" "+
+ String(@default_button)+" "+@buttons.join(' ')+']}')
+ 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 message_config
+ return nil
+ end
+ def bitmap
+ return "info"
+ end
+ def bitmap_config
+ return nil
+ end
+ def default_button
+ return 0
+ end
+ def buttons
+ #return "BUTTON1 BUTTON2"
+ return ["BUTTON1", "BUTTON2"]
+ end
+ def button_configs(num)
+ return nil
+ 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
diff --git a/ext/tk/lib/tkentry.rb b/ext/tk/lib/tkentry.rb
new file mode 100644
index 0000000000..b834c455c6
--- /dev/null
+++ b/ext/tk/lib/tkentry.rb
@@ -0,0 +1,73 @@
+#
+# tkentry.rb - Tk entry classes
+# $Date$
+# by Yukihiro Matsumoto <matz@caelum.co.jp>
+
+require 'tk.rb'
+
+class TkEntry<TkLabel
+ WidgetClassName = 'Entry'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+ def self.to_eval
+ WidgetClassName
+ end
+
+ def create_self
+ tk_call 'entry', @path
+ end
+ def scrollcommand(cmd)
+ configure 'scrollcommand', cmd
+ end
+
+ def delete(s, e=None)
+ tk_send 'delete', s, e
+ end
+
+ def cursor
+ tk_send 'index', 'insert'
+ end
+ def cursor=(index)
+ tk_send 'icursor', index
+ end
+ def index(index)
+ number(tk_send('index', index))
+ end
+ def insert(pos,text)
+ tk_send 'insert', pos, text
+ end
+ def mark(pos)
+ tk_send 'scan', 'mark', pos
+ end
+ def dragto(pos)
+ tk_send 'scan', 'dragto', pos
+ end
+ def selection_adjust(index)
+ tk_send 'selection', 'adjust', index
+ end
+ def selection_clear
+ tk_send 'selection', 'clear', 'end'
+ end
+ def selection_from(index)
+ tk_send 'selection', 'from', index
+ end
+ def selection_present()
+ tk_send('selection', 'present') == 1
+ end
+ def selection_range(s, e)
+ tk_send 'selection', 'range', s, e
+ end
+ def selection_to(index)
+ tk_send 'selection', 'to', index
+ end
+ def xview(*index)
+ tk_send 'xview', *index
+ end
+
+ def value
+ tk_send 'get'
+ end
+ def value= (val)
+ tk_send 'delete', 0, 'end'
+ tk_send 'insert', 0, val
+ end
+end
diff --git a/ext/tk/lib/tkfont.rb b/ext/tk/lib/tkfont.rb
new file mode 100644
index 0000000000..421988aeca
--- /dev/null
+++ b/ext/tk/lib/tkfont.rb
@@ -0,0 +1,944 @@
+#
+# tkfont.rb - the class to treat fonts on Ruby/Tk
+#
+# by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)
+#
+require 'tk'
+
+class TkFont
+ include Tk
+ extend TkCore
+
+ Tk_FontID = [0]
+ Tk_FontNameTBL = {}
+ Tk_FontUseTBL = {}
+
+ DEFAULT_LATIN_FONT_NAME = 'a14'.freeze
+ DEFAULT_KANJI_FONT_NAME = 'k14'.freeze
+
+ ###################################
+ # class methods
+ ###################################
+ def TkFont.families(window=nil)
+ case (Tk::TK_VERSION)
+ when /^4\.*/
+ ['fixed']
+
+ when /^8\.*/
+ if window
+ tk_split_simplelist(tk_call('font', 'families', '-displayof', window))
+ else
+ tk_split_simplelist(tk_call('font', 'families'))
+ end
+ end
+ end
+
+ def TkFont.names
+ case (Tk::TK_VERSION)
+ when /^4\.*/
+ r = ['fixed']
+ r += ['a14', 'k14'] if JAPANIZED_TK
+ Tk_FontNameTBL.each_value{|obj| r.push(obj)}
+ r | []
+
+ when /^8\.*/
+ tk_split_simplelist(tk_call('font', 'names'))
+
+ end
+ end
+
+ def TkFont.create_copy(font)
+ keys = {}
+ font.configure.each{|key,value| keys[key] = value }
+ new_font = TkFont.new(font.latin_font, font.kanji_font, keys)
+ end
+
+ def TkFont.get_obj(name)
+ if name =~ /^(@font[0-9]+)(|c|l|k)$/
+ Tk_FontNameTBL[$1]
+ else
+ nil
+ end
+ end
+
+ def TkFont.init_widget_font(path, *args)
+ case (Tk::TK_VERSION)
+ when /^4\.*/
+ conf = tk_split_simplelist(tk_call(*args)).
+ find_all{|prop| prop[0..5]=='-font ' || prop[0..10]=='-kanjifont '}.
+ collect{|prop| tk_split_simplelist(prop)}
+ if font_inf = conf.assoc('-font')
+ ltn = font_inf[4]
+ ltn = nil if ltn == []
+ else
+ #ltn = nil
+ raise RuntimeError, "unknown option '-font'"
+ end
+ if font_inf = conf.assoc('-kanjifont')
+ knj = font_inf[4]
+ knj = nil if knj == []
+ else
+ knj = nil
+ end
+ TkFont.new(ltn, knj).call_font_configure(path, *(args + [{}]))
+
+ when /^8\.*/
+ font_prop = tk_split_simplelist(tk_call(*args)).find{|prop|
+ prop[0..5] == '-font '
+ }
+ unless font_prop
+ raise RuntimeError, "unknown option '-font'"
+ end
+ fnt = tk_split_simplelist(font_prop)[4]
+ if fnt == ""
+ TkFont.new(nil, nil).call_font_configure(path, *(args + [{}]))
+ else
+ begin
+ compound = Hash[*list(tk_call('font', 'configure',
+ fnt))].collect{|key,value|
+ [key[1..-1], value]
+ }.assoc('compound')[1]
+ rescue
+ compound = []
+ end
+ if compound == []
+ TkFont.new(fnt, DEFAULT_KANJI_FONT_NAME) \
+ .call_font_configure(path, *(args + [{}]))
+ else
+ TkFont.new(compound[0], compound[1]) \
+ .call_font_configure(path, *(args + [{}]))
+ end
+ end
+ end
+ end
+
+ def TkFont.used_on(path=nil)
+ if path
+ Tk_FontUseTBL[path]
+ else
+ Tk_FontUseTBL.values | []
+ end
+ end
+
+ ###################################
+ private
+ ###################################
+ def initialize(ltn=nil, knj=nil, keys=nil)
+ @id = format("@font%.4d", Tk_FontID[0])
+ Tk_FontID[0] += 1
+ Tk_FontNameTBL[@id] = self
+
+ ltn = DEFAULT_LATIN_FONT_NAME unless ltn
+ create_latinfont(ltn)
+
+ knj = DEFAULT_KANJI_FONT_NAME unless knj
+ create_kanjifont(knj)
+
+ create_compoundfont(keys)
+ end
+
+ def _get_font_info_from_hash(font)
+ foundry = (info = font['foundry'] .to_s)? info: '*'
+ family = (info = font['family'] .to_s)? info: '*'
+ weight = (info = font['weight'] .to_s)? info: '*'
+ slant = (info = font['slant'] .to_s)? info: '*'
+ swidth = (info = font['swidth'] .to_s)? info: '*'
+ adstyle = (info = font['adstyle'] .to_s)? info: '*'
+ pixels = (info = font['pixels'] .to_s)? info: '*'
+ points = (info = font['points'] .to_s)? info: '*'
+ resx = (info = font['resx'] .to_s)? info: '*'
+ resy = (info = font['resy'] .to_s)? info: '*'
+ space = (info = font['space'] .to_s)? info: '*'
+ avgWidth = (info = font['avgWidth'].to_s)? info: '*'
+ charset = (info = font['charset'] .to_s)? info: '*'
+ encoding = (info = font['encoding'].to_s)? info: '*'
+
+ Array([foundry, family, weight, slant, swidth, adstyle,
+ pixels, points, resx, resy, space, avgWidth, charset, encoding])
+ end
+
+ def create_latinfont_tk4x(font)
+ if font.kind_of? Hash
+ @latinfont = '-' + _get_font_info_from_hash(font).join('-') + '-'
+
+ elsif font.kind_of? Array
+ finfo = {}
+ finfo['family'] = font[0].to_s
+ if font[1]
+ fsize = font[1].to_s
+ if fsize != '0' && fsize =~ /^(|\+|-)([0-9]+)$/
+ if $1 == '-'
+ finfo['pixels'] = $2
+ else
+ finfo['points'] = $2
+ end
+ else
+ finfo['points'] = '13'
+ end
+ end
+ font[2..-1].each{|style|
+ case (style)
+ when 'normal'
+ finfo['weight'] = style
+ when 'bold'
+ finfo['weight'] = style
+ when 'roman'
+ finfo['slant'] = 'r'
+ when 'italic'
+ finfo['slant'] = 'i'
+ end
+ }
+
+ @latinfont = '-' + _get_font_info_from_hash(finfo).join('-') + '-'
+
+ elsif font.kind_of? TkFont
+ @latinfont = font.latin_font
+
+ else
+ @latinfont = font
+
+ end
+ end
+
+ def create_kanjifont_tk4x(font)
+ unless JAPANIZED_TK
+ @kanjifont = ""
+ return
+ end
+
+ if font.kind_of? Hash
+ @kanjifont = '-' + _get_font_info_from_hash(font).join('-') + '-'
+
+ elsif font.kind_of? Array
+ finfo = {}
+ finfo['family'] = font[0].to_s
+ if font[1]
+ fsize = font[1].to_s
+ if fsize != '0' && fsize =~ /^(|\+|-)([0-9]+)$/
+ if $1 == '-'
+ finfo['pixels'] = $2
+ else
+ finfo['points'] = $2
+ end
+ else
+ finfo['points'] = '13'
+ end
+ end
+ font[2..-1].each{|style|
+ case (style)
+ when 'normal'
+ finfo['weight'] = style
+ when 'bold'
+ finfo['weight'] = style
+ when 'roman'
+ finfo['slant'] = 'r'
+ when 'italic'
+ finfo['slant'] = 'i'
+ end
+ }
+
+ @kanjifont = '-' + _get_font_info_from_hash(finfo).join('-') + '-'
+
+ elsif font.kind_of? TkFont
+ @kanjifont = font.kanji_font
+
+ else
+ @kanjifont = font
+
+ end
+ end
+
+ def create_compoundfont_tk4x(keys)
+ if JAPANIZED_TK
+ @compoundfont = [[@latinfont], [@kanjifont]]
+ @fontslot = {'font'=>@latinfont, 'kanjifont'=>@kanjifont}
+ else
+ @compoundfont = @latinfont
+ @fontslot = {'font'=>@latinfont}
+ end
+ end
+
+ def create_latinfont_tk8x(font)
+ @latinfont = @id + 'l'
+
+ if JAPANIZED_TK
+ if font.kind_of? Hash
+ tk_call('font', 'create', @latinfont, *hash_kv(font))
+ elsif font.kind_of? Array
+ tk_call('font', 'create', @latinfont, '-copy', array2tk_list(font))
+ elsif font.kind_of? TkFont
+ tk_call('font', 'create', @latinfont, '-copy', font.latin_font)
+ else
+ tk_call('font', 'create', @latinfont, '-copy', font)
+ end
+ else
+ if font.kind_of? Hash
+ tk_call('font', 'create', @latinfont, *hash_kv(font))
+ else
+ keys = {}
+ if font.kind_of? Array
+ actual_core(array2tk_list(font)).each{|key,val| keys[key] = val}
+ elsif font.kind_of? TkFont
+ actual_core(font.latin_font).each{|key,val| keys[key] = val}
+ else
+ actual_core(font).each{|key,val| keys[key] = val}
+ end
+ tk_call('font', 'create', @latinfont, *hash_kv(keys))
+ end
+ end
+ end
+
+ def create_kanjifont_tk80(font)
+ unless JAPANIZED_TK
+ @kanjifont = ""
+ return
+ end
+
+ @kanjifont = @id + 'k'
+
+ if font.kind_of? Hash
+ if font['charset']
+ tk_call('font', 'create', @kanjifont, *hash_kv(font))
+ else
+ tk_call('font', 'create', @kanjifont,
+ '-charset', 'jisx0208.1983', *hash_kv(font))
+ end
+ elsif font.kind_of? Array
+ tk_call('font', 'create', @kanjifont, '-copy', array2tk_list(font))
+ tk_call('font', 'configure', @kanjifont, '-charset', 'jisx0208.1983')
+
+ elsif font.kind_of? TkFont
+ tk_call('font', 'create', @kanjifont, '-copy', font.kanji_font)
+
+ else
+ tk_call('font', 'create', @kanjifont, '-copy', font,
+ '-charset', 'jisx0208.1983')
+
+ end
+ end
+
+ def create_kanjifont_tk81(font)
+ @kanjifont = @id + 'k'
+
+ if font.kind_of? Hash
+ tk_call('font', 'create', @kanjifont, *hash_kv(font))
+ else
+ keys = {}
+ if font.kind_of? Array
+ actual_core(array2tk_list(font)).each{|key,val| keys[key] = val}
+ elsif font.kind_of? TkFont
+ actual_core(font.kanji_font).each{|key,val| keys[key] = val}
+ else
+ actual_core(font).each{|key,val| keys[key] = val}
+ end
+ tk_call('font', 'create', @kanjifont, *hash_kv(keys))
+ end
+
+ keys = {}
+ actual_core(@kanjifont).each{|key,val| keys[key] = val}
+ begin
+ tk_call('font', 'configure', @compoundfont, *hash_kv(keys))
+ rescue
+ end
+ end
+
+ def create_compoundfont_tk80(keys)
+ @compoundfont = @id + 'c'
+ if JAPANIZED_TK
+ @fontslot = {'font'=>@compoundfont}
+ tk_call('font', 'create', @compoundfont,
+ '-compound', [@latinfont, @kanjifont], *hash_kv(keys))
+ else
+ tk_call('font', 'create', @compoundfont)
+ latinkeys = {}
+ begin
+ actual_core(@latinfont).each{|key,val| latinkeys[key] = val}
+ rescue
+ latinkeys {}
+ end
+ if latinkeys != {}
+ tk_call('font', 'configure', @compoundfont, *hash_kv(latinkeys))
+ end
+ @fontslot = {'font'=>@compoundfont}
+ tk_call('font', 'configure', @compoundfont, *hash_kv(keys))
+ end
+ end
+
+ def create_compoundfont_tk81(keys)
+ @compoundfont = @id + 'c'
+ tk_call('font', 'create', @compoundfont)
+
+ latinkeys = {}
+ begin
+ actual_core(@latinfont).each{|key,val| latinkeys[key] = val}
+ rescue
+ latinkeys {}
+ end
+ if latinkeys != {}
+ tk_call('font', 'configure', @compoundfont, *hash_kv(latinkeys))
+ end
+
+ kanjikeys = {}
+ begin
+ actual_core(@kanjifont).each{|key,val| kanjikeys[key] = val}
+ rescue
+ kanjikeys {}
+ end
+ if kanjikeys != {}
+ tk_call('font', 'configure', @compoundfont, *hash_kv(kanjikeys))
+ end
+
+ @fontslot = {'font'=>@compoundfont}
+ tk_call('font', 'configure', @compoundfont, *hash_kv(keys))
+ end
+
+ def actual_core_tk4x(font, window=nil, option=nil)
+ # dummy
+ if option
+ ""
+ else
+ Array([ ['family',[]], ['size',[]], ['weight',[]], ['slant',[]],
+ ['underline',[]], ['overstrike',[]], ['charset',[]],
+ ['pointadjust',[]] ])
+ end
+ end
+
+ def actual_core_tk8x(font, window=nil, option=nil)
+ if option == 'compound'
+ ""
+ elsif option
+ if window
+ tk_call('font', 'actual', font, "-#{option}")
+ else
+ tk_call('font', 'actual', font, "-displayof", window, "-#{option}")
+ end
+ else
+ l = tk_split_simplelist(if window
+ tk_call('font', 'actual', font,
+ "-displayof", window)
+ else
+ tk_call('font', 'actual', font)
+ end)
+ r = []
+ while key=l.shift
+ if key == '-compound'
+ l.shift
+ else
+ r.push [key[1..-1], l.shift]
+ end
+ end
+ r
+ end
+ end
+
+ def configure_core_tk4x(font, slot, value=None)
+ ""
+ end
+
+ def configinfo_core_tk4x(font, option=nil)
+ # dummy
+ if option
+ ""
+ else
+ Array([ ['family',[]], ['size',[]], ['weight',[]], ['slant',[]],
+ ['underline',[]], ['overstrike',[]], ['charset',[]],
+ ['pointadjust',[]] ])
+ end
+ end
+
+ def configure_core_tk8x(font, slot, value=None)
+ if slot.kind_of? Hash
+ tk_call 'font', 'configure', font, *hash_kv(slot)
+ else
+ tk_call 'font', 'configure', font, "-#{slot}", value
+ end
+ end
+
+ def configinfo_core_tk8x(font, option=nil)
+ if option == 'compound'
+ ""
+ elsif option
+ tk_call('font', 'configure', font, "-#{option}")
+ else
+ l = tk_split_simplelist(tk_call('font', 'configure', font))
+ r = []
+ while key=l.shift
+ if key == '-compound'
+ l.shift
+ else
+ r.push [key[1..-1], l.shift]
+ end
+ end
+ r
+ end
+ end
+
+ def delete_core_tk4x
+ Tk_FontNameTBL[@id] = nil
+ Tk_FontUseTBL.delete_if{|key,value| value == self}
+ end
+
+ def delete_core_tk8x
+ begin
+ tk_call('font', 'delete', @latinfont)
+ rescue
+ end
+ begin
+ tk_call('font', 'delete', @kanjifont)
+ rescue
+ end
+ begin
+ tk_call('font', 'delete', @compoundfont)
+ rescue
+ end
+ Tk_FontNameTBL[@id] = nil
+ Tk_FontUseTBL.delete_if{|key,value| value == self}
+ end
+
+ def latin_replace_core_tk4x(ltn)
+ create_latinfont_tk4x(ltn)
+ @compoundfont[0] = [@latinfont] if JAPANIZED_TK
+ @fontslot['font'] = @latinfont
+ Tk_FontUseTBL.dup.each{|w, fobj|
+ if self == fobj
+ begin
+ if w.include?(';')
+ win, tag = w.split(';')
+ winobj = tk_tcl2ruby(win)
+# winobj.tagfont_configure(tag, {'font'=>@latinfont})
+ if winobj.kind_of? TkText
+ tk_call(win, 'tag', 'configure', tag, '-font', @latinfont)
+ elsif winobj.kind_of? TkCanvas
+ tk_call(win, 'itemconfigure', tag, '-font', @latinfont)
+ elsif winobj.kind_of? TkMenu
+ tk_call(win, 'entryconfigure', tag, '-font', @latinfont)
+ else
+ raise RuntimeError, "unknown widget type"
+ end
+ else
+# tk_tcl2ruby(w).font_configure('font'=>@latinfont)
+ tk_call(w, 'configure', '-font', @latinfont)
+ end
+ rescue
+ Tk_FontUseTBL[w] = nil
+ end
+ end
+ }
+ self
+ end
+
+ def kanji_replace_core_tk4x(knj)
+ return self unless JAPANIZED_TK
+
+ create_kanjifont_tk4x(knj)
+ @compoundfont[1] = [@kanjifont]
+ @fontslot['kanjifont'] = @kanjifont
+ Tk_FontUseTBL.dup.each{|w, fobj|
+ if self == fobj
+ begin
+ if w.include?(';')
+ win, tag = w.split(';')
+ winobj = tk_tcl2ruby(win)
+# winobj.tagfont_configure(tag, {'kanjifont'=>@kanjifont})
+ if winobj.kind_of? TkText
+ tk_call(win, 'tag', 'configure', tag, '-kanjifont', @kanjifont)
+ elsif winobj.kind_of? TkCanvas
+ tk_call(win, 'itemconfigure', tag, '-kanjifont', @kanjifont)
+ elsif winobj.kind_of? TkMenu
+ tk_call(win, 'entryconfigure', tag, '-kanjifont', @latinfont)
+ else
+ raise RuntimeError, "unknown widget type"
+ end
+ else
+# tk_tcl2ruby(w).font_configure('kanjifont'=>@kanjifont)
+ tk_call(w, 'configure', '-kanjifont', @kanjifont)
+ end
+ rescue
+ Tk_FontUseTBL[w] = nil
+ end
+ end
+ }
+ self
+ end
+
+ def latin_replace_core_tk8x(ltn)
+ begin
+ tk_call('font', 'delete', @latinfont)
+ rescue
+ end
+ create_latinfont(ltn)
+ self
+ end
+
+ def kanji_replace_core_tk80(knj)
+ return self unless JAPANIZED_TK
+
+ begin
+ tk_call('font', 'delete', @kanjifont)
+ rescue
+ end
+ create_kanjifont(knj)
+ self
+ end
+
+ def kanji_replace_core_tk81(knj)
+ if font.kind_of? Hash
+ tk_call('font', 'configure', @compoundfont, *hash_kv(font))
+ else
+ keys = {}
+ if font.kind_of? Array
+ actual_core(array2tk_list(font)).each{|key,val| keys[key] = val}
+ elsif font.kind_of? TkFont
+ actual_core(font.latin_font).each{|key,val| keys[key] = val}
+ else
+ actual_core(font).each{|key,val| keys[key] = val}
+ end
+ tk_call('font', 'configure', @compoundfont, *hash_kv(keys))
+ end
+ self
+ end
+
+ def measure_core_tk4x(window, text)
+ 0
+ end
+
+ def measure_core_tk8x(window, text)
+ if window
+ number(tk_call('font', 'measure', @compoundfont,
+ '-displayof', window, text))
+ else
+ number(tk_call('font', 'measure', @compoundfont, text))
+ end
+ end
+
+ def metrics_core_tk4x(font, window, option=nil)
+ # dummy
+ if option
+ ""
+ else
+ Array([ ['ascent',[]], ['descent',[]], ['linespace',[]], ['fixed',[]] ])
+ end
+ end
+
+ def metrics_core_tk8x(font, window, option=nil)
+ if option
+ if window
+ number(tk_call('font', 'metrics', font, "-#{option}"))
+ else
+ number(tk_call('font', 'metrics', font,
+ "-displayof", window, "-#{option}"))
+ end
+ else
+ l = tk_split_list(if window
+ tk_call('font','metrics',font,"-displayof",window)
+ else
+ tk_call('font','metrics',font)
+ end)
+ r = []
+ while key=l.shift
+ r.push [key[1..-1], l.shift.to_i]
+ end
+ r
+ end
+ end
+
+ ###################################
+ # private alias
+ ###################################
+ case (Tk::TK_VERSION)
+ when /^4\.*/
+ alias create_latinfont create_latinfont_tk4x
+ alias create_kanjifont create_kanjifont_tk4x
+ alias create_compoundfont create_compoundfont_tk4x
+ alias actual_core actual_core_tk4x
+ alias configure_core configure_core_tk4x
+ alias configinfo_core configinfo_core_tk4x
+ alias delete_core delete_core_tk4x
+ alias latin_replace_core latin_replace_core_tk4x
+ alias kanji_replace_core kanji_replace_core_tk4x
+ alias measure_core measure_core_tk4x
+ alias metrics_core metrics_core_tk4x
+
+ when /^8\.0/
+ alias create_latinfont create_latinfont_tk8x
+ alias create_kanjifont create_kanjifont_tk80
+ alias create_compoundfont create_compoundfont_tk80
+ alias actual_core actual_core_tk8x
+ alias configure_core configure_core_tk8x
+ alias configinfo_core configinfo_core_tk8x
+ alias delete_core delete_core_tk8x
+ alias latin_replace_core latin_replace_core_tk8x
+ alias kanji_replace_core kanji_replace_core_tk80
+ alias measure_core measure_core_tk8x
+ alias metrics_core metrics_core_tk8x
+
+ when /^8\.1/
+ alias create_latinfont create_latinfont_tk8x
+ alias create_kanjifont create_kanjifont_tk81
+ alias create_compoundfont create_compoundfont_tk81
+ alias actual_core actual_core_tk8x
+ alias configure_core configure_core_tk8x
+ alias configinfo_core configinfo_core_tk8x
+ alias delete_core delete_core_tk8x
+ alias latin_replace_core latin_replace_core_tk8x
+ alias kanji_replace_core kanji_replace_core_tk81
+ alias measure_core measure_core_tk8x
+ alias metrics_core metrics_core_tk8x
+
+ end
+
+ ###################################
+ public
+ ###################################
+ def call_font_configure(path, *args)
+ args += hash_kv(args.pop.update(@fontslot))
+ tk_call *args
+ Tk_FontUseTBL[path] = self
+ self
+ end
+
+ def used
+ ret = []
+ Tk_FontUseTBL.each{|key,value|
+ if key.include?(';')
+ win, tag = key.split(';')
+ winobj = tk_tcl2ruby(win)
+ if winobj.kind_of? TkText
+ ret.push([winobj, winobj.tagid2obj(tag)])
+ elsif winobj.kind_of? TkCanvas
+ if (tagobj = TkcTag.id2obj(tag)).kind_of? TkcTag
+ ret.push([winobj, tagobj])
+ elsif (tagobj = TkcItem.id2obj(tag)).kind_of? TkcItem
+ ret.push([winobj, tagobj])
+ else
+ ret.push([winobj, tag])
+ end
+ elsif winobj.kind_of? TkMenu
+ ret.push([winobj, tag])
+ else
+ ret.push([win, tag])
+ end
+ else
+ ret.push(tk_tcl2ruby(key)) if value == self
+ end
+ }
+ ret
+ end
+
+ def id
+ @id
+ end
+
+ def to_eval
+ font
+ end
+
+ def font
+ @compoundfont
+ end
+
+ def latin_font
+ @latinfont
+ end
+
+ def kanji_font
+ @kanjifont
+ end
+
+ def actual(option=nil)
+ actual_core(@compoundfont, nil, option)
+ end
+
+ def actual_displayof(window, option=nil)
+ window = '.' unless window
+ actual_core(@compoundfont, window, option)
+ end
+
+ def latin_actual(option=nil)
+ actual_core(@latinfont, nil, option)
+ end
+
+ def latin_actual_displayof(window, option=nil)
+ window = '.' unless window
+ actual_core(@latinfont, window, option)
+ end
+
+ def kanji_actual(option=nil)
+ #if JAPANIZED_TK
+ if @kanjifont != ""
+ actual_core(@kanjifont, nil, option)
+ else
+ actual_core_tk4x(nil, nil, option)
+ end
+ end
+
+ def kanji_actual_displayof(window, option=nil)
+ #if JAPANIZED_TK
+ if @kanjifont != ""
+ window = '.' unless window
+ actual_core(@kanjifont, window, option)
+ else
+ actual_core_tk4x(nil, window, option)
+ end
+ end
+
+ def [](slot)
+ configinfo slot
+ end
+
+ def []=(slot, val)
+ configure slot, val
+ end
+
+ def configure(slot, value=None)
+ configure_core(@compoundfont, slot, value)
+ end
+
+ def configinfo(slot=nil)
+ configinfo_core(@compoundfont, slot)
+ end
+
+ def delete
+ delete_core
+ end
+
+ def latin_configure(slot, value=None)
+ if JAPANIZED_TK
+ configure_core(@latinfont, slot, value)
+ else
+ configure(slot, value)
+ end
+ end
+
+ def latin_configinfo(slot=nil)
+ if JAPANIZED_TK
+ configinfo_core(@latinfont, slot)
+ else
+ configure(slot, value)
+ end
+ end
+
+ def kanji_configure(slot, value=None)
+ #if JAPANIZED_TK
+ if @kanjifont != ""
+ configure_core(@kanjifont, slot, value)
+ else
+ #""
+ configure(slot, value)
+ end
+ end
+
+ def kanji_configinfo(slot=nil)
+ #if JAPANIZED_TK
+ if @kanjifont != ""
+ configinfo_core(@kanjifont, slot)
+ else
+ #[]
+ configinfo(slot)
+ end
+ end
+
+ def replace(ltn, knj)
+ latin_replace(ltn)
+ kanji_replace(knj)
+ self
+ end
+
+ def latin_replace(ltn)
+ latin_replace_core(ltn)
+ end
+
+ def kanji_replace(knj)
+ kanji_replace_core(knj)
+ end
+
+ def measure(text)
+ measure_core(nil, text)
+ end
+
+ def measure_displayof(window, text)
+ window = '.' unless window
+ measure_core(window, text)
+ end
+
+ def metrics(option=nil)
+ metrics_core(@compoundfont, nil, option)
+ end
+
+ def metrics_displayof(window, option=nil)
+ window = '.' unless window
+ metrics_core(@compoundfont, window, option)
+ end
+
+ def latin_metrics(option=nil)
+ metrics_core(@latinfont, nil, option)
+ end
+
+ def latin_metrics_displayof(window, option=nil)
+ window = '.' unless window
+ metrics_core(@latinfont, window, option)
+ end
+
+ def kanji_metrics(option=nil)
+ if JAPANIZED_TK
+ metrics_core(@kanjifont, nil, option)
+ else
+ metrics_core_tk4x(nil, nil, option)
+ end
+ end
+
+ def kanji_metrics_displayof(window, option=nil)
+ if JAPANIZED_TK
+ window = '.' unless window
+ metrics_core(@kanjifont, window, option)
+ else
+ metrics_core_tk4x(nil, window, option)
+ end
+ end
+
+ ###################################
+ # public alias
+ ###################################
+ alias ascii_font latin_font
+ alias create_asciifont create_latinfont
+ alias ascii_actual latin_actual
+ alias ascii_actual_displayof latin_actual_displayof
+ alias ascii_configure latin_configure
+ alias ascii_configinfo latin_configinfo
+ alias ascii_replace latin_replace
+ alias ascii_metrics latin_metrics
+
+end
+
+module TkTreatTagFont
+ def font_configinfo
+ @parent.tagfont_configinfo(@id)
+ end
+ alias font font_configinfo
+
+ def font_configure(slot)
+ @parent.tagfont_configure(@id, slot)
+ end
+
+ def latinfont_configure(ltn, keys=nil)
+ @parent.latintagfont_configure(@id, ltn, keys)
+ end
+ alias asciifont_configure latinfont_configure
+
+ def kanjifont_configure(knj, keys=nil)
+ @parent.kanjitagfont_configure(@id, ltn, keys)
+ end
+
+ def font_copy(window, wintag=nil)
+ @parent.tagfont_copy(@id, window, wintag)
+ end
+
+ def latinfont_copy(window, wintag=nil)
+ @parent.latintagfont_copy(@id, window, wintag)
+ end
+ alias asciifont_copy latinfont_copy
+
+ def kanjifont_copy(window, wintag=nil)
+ @parent.kanjitagfont_copy(@id, window, wintag)
+ end
+end
diff --git a/ext/tk/lib/tkmenubar.rb b/ext/tk/lib/tkmenubar.rb
new file mode 100644
index 0000000000..441f3f5c03
--- /dev/null
+++ b/ext/tk/lib/tkmenubar.rb
@@ -0,0 +1,137 @@
+#
+# tkmenubar.rb
+#
+# Copyright (C) 1998 maeda shugo. All rights reserved.
+# This file can be distributed under the terms of the Ruby.
+
+# Usage:
+#
+# menu_spec = [
+# [['File', 0],
+# ['Open', proc{puts('Open clicked')}, 0],
+# '---',
+# ['Quit', proc{exit}, 0]],
+# [['Edit', 0],
+# ['Cut', proc{puts('Cut clicked')}, 2],
+# ['Copy', proc{puts('Copy clicked')}, 0],
+# ['Paste', proc{puts('Paste clicked')}, 0]]
+# ]
+# menubar = TkMenubar.new(nil, menu_spec,
+# 'tearoff'=>false,
+# 'foreground'=>'grey40',
+# 'activeforeground'=>'red',
+# 'font'=>'-adobe-helvetica-bold-r-*--12-*-iso8859-1')
+# menubar.pack('side'=>'top', 'fill'=>'x')
+#
+#
+# OR
+#
+#
+# menubar = TkMenubar.new
+# menubar.add_menu([['File', 0],
+# ['Open', proc{puts('Open clicked')}, 0],
+# '---',
+# ['Quit', proc{exit}, 0]])
+# menubar.add_menu([['Edit', 0],
+# ['Cut', proc{puts('Cut clicked')}, 2],
+# ['Copy', proc{puts('Copy clicked')}, 0],
+# ['Paste', proc{puts('Paste clicked')}, 0]])
+# menubar.configure('tearoff', false)
+# menubar.configure('foreground', 'grey40')
+# menubar.configure('activeforeground', 'red')
+# menubar.configure('font', '-adobe-helvetica-bold-r-*--12-*-iso8859-1')
+# menubar.pack('side'=>'top', 'fill'=>'x')
+
+# The format of the menu_spec is:
+# [
+# [
+# [button text, underline, accelerator],
+# [menu label, command, underline, accelerator],
+# '---', # separator
+# ...
+# ],
+# ...
+# ]
+
+# underline and accelerator are optional parameters.
+# Hashes are OK instead of Arrays.
+
+# To use add_menu, configuration must be done by calling configure after
+# adding all menus by add_menu, not by the constructor arguments.
+
+require "tk"
+
+class TkMenubar<TkFrame
+
+ include TkComposite
+
+ def initialize(parent = nil, spec = nil, options = nil)
+ super(parent, options)
+
+ @menus = []
+
+ if spec
+ for menu_info in spec
+ add_menu(menu_info)
+ end
+ end
+
+ if options
+ for key, value in options
+ configure(key, value)
+ end
+ end
+ end
+
+ def add_menu(menu_info)
+ btn_info = menu_info.shift
+ mbtn = TkMenubutton.new(@frame)
+
+ if btn_info.kind_of?(Hash)
+ for key, value in btn_info
+ mbtn.configure(key, value)
+ end
+ elsif btn_info.kind_of?(Array)
+ mbtn.configure('text', btn_info[0]) if btn_info[0]
+ mbtn.configure('underline', btn_info[1]) if btn_info[1]
+ mbtn.configure('accelerator', btn_info[2]) if btn_info[2]
+ else
+ mbtn.configure('text', btn_info)
+ end
+
+ menu = TkMenu.new(mbtn)
+
+ for item_info in menu_info
+ if item_info.kind_of?(Hash)
+ menu.add('command', item_info)
+ elsif item_info.kind_of?(Array)
+ options = {}
+ options['label'] = item_info[0] if item_info[0]
+ options['command'] = item_info[1] if item_info[1]
+ options['underline'] = item_info[2] if item_info[2]
+ options['accelerator'] = item_info[3] if item_info[3]
+ menu.add('command', options)
+ elsif /^-+$/ =~ item_info
+ menu.add('sep')
+ else
+ menu.add('command', 'label' => item_info)
+ end
+ end
+
+ mbtn.menu(menu)
+ @menus.push([mbtn, menu])
+ delegate('tearoff', menu)
+ delegate('foreground', mbtn, menu)
+ delegate('background', mbtn, menu)
+ delegate('disabledforeground', mbtn, menu)
+ delegate('activeforeground', mbtn, menu)
+ delegate('activebackground', mbtn, menu)
+ delegate('font', mbtn, menu)
+ delegate('kanjifont', mbtn, menu)
+ mbtn.pack('side' => 'left')
+ end
+
+ def [](index)
+ return @menus[index]
+ end
+end
diff --git a/ext/tk/lib/tkmngfocus.rb b/ext/tk/lib/tkmngfocus.rb
new file mode 100644
index 0000000000..921fb646e7
--- /dev/null
+++ b/ext/tk/lib/tkmngfocus.rb
@@ -0,0 +1,27 @@
+#
+# tkmngfocus.rb : methods for Tcl/Tk standard library 'focus.tcl'
+# 1998/07/16 by Hidetoshi Nagai <nagai@ai.kyutech.ac.jp>
+#
+require 'tk'
+
+module TkManageFocus
+ extend Tk
+
+ def TkManageFocus.followsMouse
+ tk_call 'tk_focusFollowsMouse'
+ end
+
+ def TkManageFocus.next(window)
+ tk_call 'tk_focusNext', window
+ end
+ def focusNext
+ TkManageFocus.next(self)
+ end
+
+ def TkManageFocus.prev(window)
+ tk_call 'tk_focusPrev', window
+ end
+ def focusPrev
+ TkManageFocus.prev(self)
+ end
+end
diff --git a/ext/tk/lib/tkpalette.rb b/ext/tk/lib/tkpalette.rb
new file mode 100644
index 0000000000..a2dc7c87cb
--- /dev/null
+++ b/ext/tk/lib/tkpalette.rb
@@ -0,0 +1,48 @@
+#
+# tkpalette.rb : methods for Tcl/Tk standard library 'palette.tcl'
+# 1998/06/21 by Hidetoshi Nagai <nagai@ai.kyutech.ac.jp>
+#
+require 'tk'
+
+module TkPalette
+ include Tk
+ extend Tk
+
+ def TkPalette.set(*args)
+ args = args.to_a.flatten if args.kind_of? Hash
+ tk_call 'tk_setPalette', *args
+ end
+ def TkPalette.setPalette(*args)
+ TkPalette.set(*args)
+ end
+
+ def TkPalette.bisque
+ tk_call 'tk_bisque'
+ end
+
+ def TkPalette.darken(color, percent)
+ tk_call 'tkDarken', color, percent
+ end
+
+ def TkPalette.recolorTree(window, colors)
+ if not colors.kind_of?(Hash)
+ fail "2nd arg need to be Hash"
+ end
+
+ colors.each{|key, value|
+ begin
+ if window.cget(key) == tk_call('set', "tkPalette(#{key})")
+ window[key] = colors[key]
+ end
+ rescue
+ # ignore
+ end
+ }
+
+ TkWinfo.children(window).each{|w| TkPalette.recolorTree(w, colors)}
+ end
+
+ def recolorTree(colors)
+ TkPalette.recolorTree(self, colors)
+ end
+end
diff --git a/ext/tk/lib/tkscrollbox.rb b/ext/tk/lib/tkscrollbox.rb
new file mode 100644
index 0000000000..8d129b2f4b
--- /dev/null
+++ b/ext/tk/lib/tkscrollbox.rb
@@ -0,0 +1,27 @@
+#
+# tkscrollbox.rb - Tk Listbox with Scrollbar
+# as an example of Composite Widget
+# $Date$
+# by Yukihiro Matsumoto <matz@caelum.co.jp>
+
+require 'tk.rb'
+
+class TkScrollbox<TkListbox
+ include TkComposite
+ def initialize_composite
+ list = TkListbox.new(@frame)
+ scroll = TkScrollbar.new(@frame)
+ @path = list.path
+
+ list.configure 'yscroll', scroll.path+" set"
+ list.pack 'side'=>'left','fill'=>'both','expand'=>'yes'
+ scroll.configure 'command', list.path+" yview"
+ scroll.pack 'side'=>'right','fill'=>'y'
+
+ delegate('DEFAULT', list)
+ delegate('foreground', list)
+ delegate('background', list, scroll)
+ delegate('borderwidth', @frame)
+ delegate('relief', @frame)
+ end
+end
diff --git a/ext/tk/lib/tktext.rb b/ext/tk/lib/tktext.rb
new file mode 100644
index 0000000000..02d5a7f3e0
--- /dev/null
+++ b/ext/tk/lib/tktext.rb
@@ -0,0 +1,797 @@
+#
+# tktext.rb - Tk text classes
+# $Date$
+# by Yukihiro Matsumoto <matz@caelum.co.jp>
+
+require 'tk.rb'
+require 'tkfont'
+
+module TkTreatTextTagFont
+ def tagfont_configinfo(tag)
+ if tag.kind_of? TkTextTag
+ pathname = self.path + ';' + tag.id
+ else
+ pathname = self.path + ';' + tag
+ end
+ ret = TkFont.used_on(pathname)
+ if ret == nil
+ ret = TkFont.init_widget_font(pathname,
+ self.path, 'tag', 'configure', tag)
+ end
+ ret
+ end
+ alias tagfontobj tagfont_configinfo
+
+ def tagfont_configure(tag, slot)
+ if tag.kind_of? TkTextTag
+ pathname = self.path + ';' + tag.id
+ else
+ pathname = self.path + ';' + tag
+ end
+ if (fnt = slot['font'])
+ slot['font'] = nil
+ if fnt.kind_of? TkFont
+ return fnt.call_font_configure(pathname,
+ self.path,'tag','configure',tag,slot)
+ else
+ latintagfont_configure(tag, fnt) if fnt
+ end
+ end
+ if (ltn = slot['latinfont'])
+ slot['latinfont'] = nil
+ latintagfont_configure(tag, ltn) if ltn
+ end
+ if (ltn = slot['asciifont'])
+ slot['asciifont'] = nil
+ latintagfont_configure(tag, ltn) if ltn
+ end
+ if (knj = slot['kanjifont'])
+ slot['kanjifont'] = nil
+ kanjitagfont_configure(tag, knj) if knj
+ end
+
+ tk_call(self.path, 'tag', 'configure', tag, *hash_kv(slot)) if slot != {}
+ self
+ end
+
+ def latintagfont_configure(tag, ltn, keys=nil)
+ fobj = tagfontobj(tag)
+ if ltn.kind_of? TkFont
+ conf = {}
+ ltn.latin_configinfo.each{|key,val| conf[key] = val if val != []}
+ if conf == {}
+ fobj.latin_replace(ltn)
+ fobj.latin_configure(keys) if keys
+ elsif keys
+ fobj.latin_configure(conf.update(keys))
+ else
+ fobj.latin_configure(conf)
+ end
+ else
+ fobj.latin_replace(ltn)
+ end
+ end
+ alias asciitagfont_configure latintagfont_configure
+
+ def kanjitagfont_configure(tag, knj, keys=nil)
+ fobj = tagfontobj(tag)
+ if knj.kind_of? TkFont
+ conf = {}
+ knj.kanji_configinfo.each{|key,val| conf[key] = val if val != []}
+ if conf == {}
+ fobj.kanji_replace(knj)
+ fobj.kanji_configure(keys) if keys
+ elsif keys
+ fobj.kanji_configure(conf.update(keys))
+ else
+ fobj.kanji_configure(conf)
+ end
+ else
+ fobj.kanji_replace(knj)
+ end
+ end
+
+ def tagfont_copy(tag, window, wintag=nil)
+ if wintag
+ window.tagfontobj(wintag).configinfo.each{|key,value|
+ tagfontobj(tag).configure(key,value)
+ }
+ tagfontobj(tag).replace(window.tagfontobj(wintag).latin_font,
+ window.tagfontobj(wintag).kanji_font)
+ else
+ window.tagfont(wintag).configinfo.each{|key,value|
+ tagfontobj(tag).configure(key,value)
+ }
+ tagfontobj(tag).replace(window.fontobj.latin_font,
+ window.fontobj.kanji_font)
+ end
+ end
+
+ def latintagfont_copy(tag, window, wintag=nil)
+ if wintag
+ tagfontobj(tag).latin_replace(window.tagfontobj(wintag).latin_font)
+ else
+ tagfontobj(tag).latin_replace(window.fontobj.latin_font)
+ end
+ end
+ alias asciitagfont_copy latintagfont_copy
+
+ def kanjitagfont_copy(tag, window, wintag=nil)
+ if wintag
+ tagfontobj(tag).kanji_replace(window.tagfontobj(wintag).kanji_font)
+ else
+ tagfontobj(tag).kanji_replace(window.fontobj.kanji_font)
+ end
+ end
+end
+
+class TkText<TkTextWin
+ include TkTreatTextTagFont
+
+ WidgetClassName = 'Text'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+ def self.to_eval
+ WidgetClassName
+ end
+ include Scrollable
+ def create_self
+ tk_call 'text', @path
+ @tags = {}
+ end
+ def index(index)
+ tk_send 'index', index
+ end
+ def value
+ tk_send 'get', "1.0", "end - 1 char"
+ end
+ def value= (val)
+ tk_send 'delete', "1.0", 'end'
+ tk_send 'insert', "1.0", val
+ end
+ def _addcmd(cmd)
+ @cmdtbl.push cmd
+ end
+ def _addtag(name, obj)
+ @tags[name] = obj
+ end
+
+ def tagid2obj(tagid)
+ if not @tags[tagid]
+ tagid
+ else
+ @tags[tagid]
+ end
+ end
+
+ def tag_names(index=None)
+ tk_split_list(tk_send('tag', 'names', index)).collect{|elt|
+ tagid2obj(elt)
+ }
+ end
+ def window_names
+ tk_send('window', 'names').collect{|elt|
+ tagid2obj(elt)
+ }
+ end
+ def image_names
+ tk_send('image', 'names').collect{|elt|
+ tagid2obj(elt)
+ }
+ end
+
+ def set_insert(index)
+ tk_send 'mark', 'set', 'insert', index
+ end
+ def set_current(index)
+ tk_send 'mark', 'set', 'current', index
+ end
+
+ def insert(index, chars, *tags)
+ super index, chars, tags.collect{|x|_get_eval_string(x)}.join(' ')
+ end
+
+ def destroy
+ @tags.each_value do |t|
+ t.destroy
+ end
+ super
+ end
+
+ def backspace
+ self.delete 'insert'
+ end
+
+ def compare(idx1, op, idx2)
+ bool(tk_send('compare', idx1, op, idx2))
+ end
+
+ def debug
+ bool(tk_send('debug'))
+ end
+ def debug=(boolean)
+ tk_send 'debug', boolean
+ end
+
+ def bbox(index)
+ inf = tk_send('bbox', index)
+ (inf == "")? [0,0,0,0]: inf
+ end
+ def dlineinfo(index)
+ inf = tk_send('dlineinfo', index)
+ (inf == "")? [0,0,0,0,0]: inf
+ end
+
+ def yview(*what)
+ tk_send 'yview', *what
+ end
+ def yview_pickplace(*what)
+ tk_send 'yview', '-pickplace', *what
+ end
+
+ def xview(*what)
+ tk_send 'xview', *what
+ end
+ def xview_pickplace(*what)
+ tk_send 'xview', '-pickplace', *what
+ end
+
+ def tag_add(tag,index1,index2=None)
+ tk_send 'tag', 'add', tag, index1, index2
+ end
+
+ def _tag_bind_core(mode, tag, seq, cmd=Proc.new, args=nil)
+ id = install_bind(cmd, args)
+ tk_send 'tag', 'bind', tag, "<#{tk_event_sequence(seq)}>", mode + id
+ # _addcmd cmd
+ end
+ private :_tag_bind_core
+
+ def tag_bind(tag, seq, cmd=Proc.new, args=nil)
+ _tag_bind_core('', tag, seq, cmd=Proc.new, args=nil)
+ end
+
+ def tag_bind_append(tag, seq, cmd=Proc.new, args=nil)
+ _tag_bind_core('+', tag, seq, cmd=Proc.new, args=nil)
+ end
+
+ def tag_bindinfo(tag, context=nil)
+ if context
+ (tk_send('tag', 'bind', tag,
+ "<#{tk_event_sequence(context)}>")).collect{|cmdline|
+ if cmdline =~ /^rb_out (c\d+)\s+(.*)$/
+ [Tk_CMDTBL[$1], $2]
+ else
+ cmdline
+ end
+ }
+ else
+ tk_split_list(tk_send('tag', 'bind', tag)).filter{|seq|
+ seq[1..-2].gsub(/></,',')
+ }
+ end
+ end
+
+ def tag_cget(tag, key)
+ tk_tcl2ruby tk_call @t.path, 'tag', 'cget', tag, "-#{key}"
+ end
+
+ def tag_configure(tag, key, val=None)
+ if key.kind_of? Hash
+ if ( key['font'] || key['kanjifont'] \
+ || key['latinfont'] || key['asciifont'] )
+ tagfont_configure(tag, key.dup)
+ else
+ tk_send 'tag', 'configure', tag, *hash_kv(key)
+ end
+
+ else
+ if ( key == 'font' || key == 'kanjifont' \
+ || key == 'latinfont' || key == 'asciifont' )
+ tagfont_configure({key=>val})
+ else
+ tk_call 'tag', 'configure', tag, "-#{key}", val
+ end
+ end
+ end
+
+ def tag_configinfo(tag, key=nil)
+ if key
+ conf = tk_split_list(tk_send('tag','configure',tag,"-#{key}"))
+ conf[0] = conf[0][1..-1]
+ conf
+ else
+ tk_split_list(tk_send('tag', 'configure', tag)).collect{|conf|
+ conf[0] = conf[0][1..-1]
+ conf
+ }
+ end
+ end
+
+ def tag_raise(tag, above=None)
+ tk_send 'tag', 'raise', tag, above
+ end
+
+ def tag_lower(tag, below=None)
+ tk_send 'tag', 'lower', tag, below
+ end
+
+ def tag_remove(tag, *index)
+ tk_send 'tag', 'remove', tag, *index
+ end
+
+ def tag_ranges(tag)
+ l = tk_split_list(tk_send('tag', 'ranges', tag))
+ r = []
+ while key=l.shift
+ r.push [key, l.shift]
+ end
+ r
+ end
+
+ def tag_nextrange(tag, first, last=None)
+ tk_split_list(tk_send('tag', 'nextrange', tag, first, last))
+ end
+
+ def tag_prevrange(tag, first, last=None)
+ tk_split_list(tk_send('tag', 'prevrange', tag, first, last))
+ end
+
+ def search_with_length(pat,start,stop=None)
+ pat = pat.char if pat.kind_of? Integer
+ if stop != None
+ return ["", 0] if compare(start,'>=',stop)
+ txt = get(start,stop)
+ if (pos = txt.index(pat))
+ pos = txt[0..(pos-1)].split('').length if pos > 0
+ if pat.kind_of? String
+ return [index(start + " + #{pos} chars"), pat.split('').length]
+ else
+ return [index(start + " + #{pos} chars"), $&.split('').length]
+ end
+ else
+ return ["", 0]
+ end
+ else
+ txt = get(start,'end - 1 char')
+ if (pos = txt.index(pat))
+ pos = txt[0..(pos-1)].split('').length if pos > 0
+ if pat.kind_of? String
+ return [index(start + " + #{pos} chars"), pat.split('').length]
+ else
+ return [index(start + " + #{pos} chars"), $&.split('').length]
+ end
+ else
+ txt = get('1.0','end - 1 char')
+ if (pos = txt.index(pat))
+ pos = txt[0..(pos-1)].split('').length if pos > 0
+ if pat.kind_of? String
+ return [index("1.0 + #{pos} chars"), pat.split('').length]
+ else
+ return [index("1.0 + #{pos} chars"), $&.split('').length]
+ end
+ else
+ return ["", 0]
+ end
+ end
+ end
+ end
+
+ def search(pat,start,stop=None)
+ search_with_length(pat,start,stop)[0]
+ end
+
+ def rsearch_with_length(pat,start,stop=None)
+ pat = pat.char if pat.kind_of? Integer
+ if stop != None
+ return ["", 0] if compare(start,'<=',stop)
+ txt = get(stop,start)
+ if (pos = txt.rindex(pat))
+ pos = txt[0..(pos-1)].split('').length if pos > 0
+ if pat.kind_of? String
+ return [index(stop + " + #{pos} chars"), pat.split('').length]
+ else
+ return [index(stop + " + #{pos} chars"), $&.split('').length]
+ end
+ else
+ return ["", 0]
+ end
+ else
+ txt = get('1.0',start)
+ if (pos = txt.rindex(pat))
+ pos = txt[0..(pos-1)].split('').length if pos > 0
+ if pat.kind_of? String
+ return [index("1.0 + #{pos} chars"), pat.split('').length]
+ else
+ return [index("1.0 + #{pos} chars"), $&.split('').length]
+ end
+ else
+ txt = get('1.0','end - 1 char')
+ if (pos = txt.rindex(pat))
+ pos = txt[0..(pos-1)].split('').length if pos > 0
+ if pat.kind_of? String
+ return [index("1.0 + #{pos} chars"), pat.split('').length]
+ else
+ return [index("1.0 + #{pos} chars"), $&.split('').length]
+ end
+ else
+ return ["", 0]
+ end
+ end
+ end
+ end
+
+ def rsearch(pat,start,stop=None)
+ rsearch_with_length(pat,start,stop)[0]
+ end
+end
+
+class TkTextTag<TkObject
+ include TkTreatTagFont
+
+ $tk_text_tag = 'tag0000'
+ def initialize(parent, keys=nil)
+ if not parent.kind_of?(TkText)
+ fail format("%s need to be TkText", parent.inspect)
+ end
+ @parent = @t = parent
+ @path = @id = $tk_text_tag
+ $tk_text_tag = $tk_text_tag.succ
+ #tk_call @t.path, "tag", "configure", @id, *hash_kv(keys)
+ configure(keys) if keys
+ @t._addtag id, self
+ end
+ def id
+ return @id
+ end
+
+ def first
+ @id + '.first'
+ end
+
+ def last
+ @id + '.last'
+ end
+
+ def add(*index)
+ tk_call @t.path, 'tag', 'add', @id, *index
+ end
+
+ def remove(*index)
+ tk_call @t.path, 'tag', 'remove', @id, *index
+ end
+
+ def ranges
+ l = tk_split_list(tk_call(@t.path, 'tag', 'ranges', @id))
+ r = []
+ while key=l.shift
+ r.push [key, l.shift]
+ end
+ r
+ end
+
+ def nextrange(first, last=None)
+ tk_split_list(tk_call(@t.path, 'tag', 'nextrange', @id, first, last))
+ end
+
+ def prevrange(first, last=None)
+ tk_split_list(tk_call(@t.path, 'tag', 'prevrange', @id, first, last))
+ end
+
+ def [](key)
+ cget key
+ end
+
+ def []=(key,val)
+ configure key, val
+ end
+
+ def cget(key)
+ tk_tcl2ruby tk_call @t.path, 'tag', 'cget', @id, "-#{key}"
+ end
+
+ def configure(key, val=None)
+ @t.tag_configure @id, key, val
+ end
+# def configure(key, val=None)
+# if key.kind_of? Hash
+# tk_call @t.path, 'tag', 'configure', @id, *hash_kv(key)
+# else
+# tk_call @t.path, 'tag', 'configure', @id, "-#{key}", val
+# end
+# end
+# def configure(key, value)
+# if value == FALSE
+# value = "0"
+# elsif value.kind_of? Proc
+# value = install_cmd(value)
+# end
+# tk_call @t.path, 'tag', 'configure', @id, "-#{key}", value
+# end
+
+ def configinfo(key=nil)
+ @t.tag_configinfo @id, key
+ end
+# def configinfo(key=nil)
+# if key
+# conf = tk_split_list(tk_call(@t.path, 'tag','configure',@id,"-#{key}"))
+# conf[0] = conf[0][1..-1]
+# conf
+# else
+# tk_split_list(tk_call(@t.path, 'tag', 'configure', @id)).collect{|conf|
+# conf[0] = conf[0][1..-1]
+# conf
+# }
+# end
+# end
+
+ def bind(seq, cmd=Proc.new, args=nil)
+ id = install_bind(cmd, args)
+ tk_call @t.path, 'tag', 'bind', @id, "<#{tk_event_sequence(seq)}>", id
+ # @t._addcmd cmd
+ end
+
+ def bindinfo(context=nil)
+ if context
+ (tk_call(@t.path, 'tag', 'bind', @id,
+ "<#{tk_event_sequence(context)}>")).collect{|cmdline|
+ if cmdline =~ /^rb_out (c\d+)\s+(.*)$/
+ [Tk_CMDTBL[$1], $2]
+ else
+ cmdline
+ end
+ }
+ else
+ tk_split_list(tk_call(@t.path, 'tag', 'bind', @id)).filter{|seq|
+ seq[1..-2].gsub(/></,',')
+ }
+ end
+ end
+
+ def raise(above=None)
+ tk_call @t.path, 'tag', 'raise', @id, above
+ end
+
+ def lower(below=None)
+ tk_call @t.path, 'tag', 'lower', @id, below
+ end
+
+ def destroy
+ tk_call @t.path, 'tag', 'delete', @id
+ end
+end
+
+class TkTextTagSel<TkTextTag
+ def initialize(parent, keys=nil)
+ if not parent.kind_of?(TkText)
+ fail format("%s need to be TkText", parent.inspect)
+ end
+ @t = parent
+ @path = @id = 'sel'
+ #tk_call @t.path, "tag", "configure", @id, *hash_kv(keys)
+ configure(keys) if keys
+ @t._addtag id, self
+ end
+end
+
+class TkTextMark<TkObject
+ $tk_text_mark = 'mark0000'
+ def initialize(parent, index)
+ if not parent.kind_of?(TkText)
+ fail format("%s need to be TkText", parent.inspect)
+ end
+ @t = parent
+ @path = @id = $tk_text_mark
+ $tk_text_mark = $tk_text_mark.succ
+ tk_call @t.path, 'mark', 'set', @id, index
+ @t._addtag id, self
+ end
+ def id
+ return @id
+ end
+
+ def set(where)
+ tk_call @t.path, 'mark', 'set', @id, where
+ end
+
+ def unset
+ tk_call @t.path, 'mark', 'unset', @id
+ end
+ alias destroy unset
+
+ def gravity
+ tk_call @t.path, 'mark', 'gravity', @id
+ end
+
+ def gravity=(direction)
+ tk_call @t.path, 'mark', 'gravity', @id, direction
+ end
+end
+
+class TkTextMarkInsert<TkTextMark
+ def initialize(parent, index=nil)
+ if not parent.kind_of?(TkText)
+ fail format("%s need to be TkText", parent.inspect)
+ end
+ @t = parent
+ @path = @id = 'insert'
+ tk_call @t.path, 'mark', 'set', @id, index if index
+ @t._addtag id, self
+ end
+end
+
+class TkTextMarkCurrent<TkTextMark
+ def initialize(parent,index=nil)
+ if not parent.kind_of?(TkText)
+ fail format("%s need to be TkText", parent.inspect)
+ end
+ @t = parent
+ @path = @id = 'current'
+ tk_call @t.path, 'mark', 'set', @id, index if index
+ @t._addtag id, self
+ end
+end
+
+class TkTextWindow<TkObject
+ def initialize(parent, index, keys)
+ if not parent.kind_of?(TkText)
+ fail format("%s need to be TkText", parent.inspect)
+ end
+ @t = parent
+ if index == 'end'
+ @path = TkTextMark.new(@t, tk_call(@t.path, 'index', 'end - 1 chars'))
+ elsif index.kind_of? TkTextMark
+ if tk_call(@t.path,'index',index.path) == tk_call(@t.path,'index','end')
+ @path = TkTextMark.new(@t, tk_call(@t.path, 'index', 'end - 1 chars'))
+ else
+ @path = TkTextMark.new(@t, tk_call(@t.path, 'index', index.path))
+ end
+ else
+ @path = TkTextMark.new(@t, tk_call(@t.path, 'index', index))
+ end
+ @path.gravity = 'left'
+ @index = @path.path
+ @id = keys['window']
+ if keys['create']
+ @p_create = keys['create']
+ if @p_create.kind_of? Proc
+ keys['create'] = install_cmd(proc{@id = @p_create.call; @id.path})
+ end
+ end
+ tk_call @t.path, 'window', 'create', @index, *hash_kv(keys)
+ end
+
+ def [](slot)
+ cget(slot)
+ end
+ def []=(slot, value)
+ configure(slot, value)
+ end
+
+ def cget(slot)
+ tk_tcl2ruby tk_call @t.path, 'window', 'cget', @index, "-#{slot}"
+ end
+
+ def configure(slot, value=None)
+ if slot.kind_of? Hash
+ @id = slot['window'] if slot['window']
+ if slot['create']
+ self.create=value
+ slot['create']=nil
+ end
+ if slot.size > 0
+ tk_call @t.path, 'window', 'configure', @index, *hash_kv(slot)
+ end
+ else
+ @id = value if slot == 'window'
+ if slot == 'create'
+ self.create=value
+ else
+ tk_call @t.path, 'window', 'configure', @index, "-#{slot}", value
+ end
+ end
+ end
+
+ def window
+ @id
+ end
+
+ def window=(value)
+ tk_call @t.path, 'window', 'configure', @index, '-window', value
+ @id = value
+ end
+
+ def create
+ @p_create
+ end
+
+ def create=(value)
+ @p_create = value
+ if @p_create.kind_of? Proc
+ value = install_cmd(proc{@id = @p_create.call})
+ end
+ tk_call @t.path, 'window', 'configure', @index, '-create', value
+ end
+
+ def configinfo(slot = nil)
+ if slot
+ conf = tk_split_list(tk_call @t.path, 'window', 'configure',
+ @index, "-#{slot}")
+ conf[0] = conf[0][1..-1]
+ conf
+ else
+ tk_split_list(tk_call @t.path, 'window', 'configure',
+ @index).collect{|conf|
+ conf[0] = conf[0][1..-1]
+ conf
+ }
+ end
+ end
+end
+
+class TkTextImage<TkObject
+ def initialize(parent, index, keys)
+ if not parent.kind_of?(TkText)
+ fail format("%s need to be TkText", parent.inspect)
+ end
+ @t = parent
+ if index == 'end'
+ @path = TkTextMark.new(@t, tk_call(@t.path, 'index', 'end - 1 chars'))
+ elsif index.kind_of? TkTextMark
+ if tk_call(@t.path,'index',index.path) == tk_call(@t.path,'index','end')
+ @path = TkTextMark.new(@t, tk_call(@t.path, 'index', 'end - 1 chars'))
+ else
+ @path = TkTextMark.new(@t, tk_call(@t.path, 'index', index.path))
+ end
+ else
+ @path = TkTextMark.new(@t, tk_call(@t.path, 'index', index))
+ end
+ @path.gravity = 'left'
+ @index = @path.path
+ @id = tk_call(@t.path, 'image', 'create', @index, *hash_kv(keys))
+ end
+
+ def [](slot)
+ cget(slot)
+ end
+ def []=(slot, value)
+ configure(slot, value)
+ end
+
+ def cget(slot)
+ tk_tcl2ruby tk_call @t.path, 'image', 'cget', @index, "-#{slot}"
+ end
+
+ def configure(slot, value=None)
+ if slot.kind_of? Hash
+ tk_call @t.path, 'image', 'configure', @index, *hash_kv(slot)
+ else
+ tk_call @t.path, 'image', 'configure', @index, "-#{slot}", value
+ end
+ end
+# def configure(slot, value)
+# tk_call @t.path, 'image', 'configure', @index, "-#{slot}", value
+# end
+
+ def image
+ tk_call @t.path, 'image', 'configure', @index, '-image'
+ end
+
+ def image=(value)
+ tk_call @t.path, 'image', 'configure', @index, '-image', value
+ end
+
+ def configinfo(slot = nil)
+ if slot
+ conf = tk_split_list(tk_call @t.path, 'image', 'configure',
+ @index, "-#{slot}")
+ conf[0] = conf[0][1..-1]
+ conf
+ else
+ tk_split_list(tk_call @t.path, 'image', 'configure',
+ @index).collect{|conf|
+ conf[0] = conf[0][1..-1]
+ conf
+ }
+ end
+ end
+end
diff --git a/ext/tk/lib/tkvirtevent.rb b/ext/tk/lib/tkvirtevent.rb
new file mode 100644
index 0000000000..0d100c2186
--- /dev/null
+++ b/ext/tk/lib/tkvirtevent.rb
@@ -0,0 +1,66 @@
+#
+# tkvirtevent.rb : treats virtual events
+# 1998/07/16 by Hidetoshi Nagai <nagai@ai.kyutech.ac.jp>
+#
+require 'tk'
+
+class TkVirtualEvent<TkObject
+ extend Tk
+
+ TkVirturlEventID = [0]
+ TkVirturlEventTBL = {}
+
+ def TkVirtualEvent.getobj(event)
+ obj = TkVirturlEventTBL[event]
+ obj ? obj : event
+ end
+
+ def TkVirtualEvent.info
+ tk_call('event', 'info').split(/\s+/).filter{|seq|
+ TkVirtualEvent.getobj(seq[1..-2])
+ }
+ end
+
+ def initialize(*sequences)
+ @path = @id = format("<VirtEvent%.4d>", TkVirturlEventID[0])
+ TkVirturlEventID[0] += 1
+ add(*sequences)
+ end
+
+ def add(*sequences)
+ if sequences != []
+ tk_call('event', 'add', "<#{@id}>",
+ *(sequences.collect{|seq| "<#{tk_event_sequence(seq)}>"}) )
+ TkVirturlEventTBL[@id] = self
+ end
+ self
+ end
+
+ def delete(*sequences)
+ if sequences == []
+ tk_call('event', 'delete', "<#{@id}>")
+ TkVirturlEventTBL[@id] = nil
+ else
+ tk_call('event', 'delete', "<#{@id}>",
+ *(sequences.collect{|seq| "<#{tk_event_sequence(seq)}>"}) )
+ TkVirturlEventTBL[@id] = nil if info == []
+ end
+ self
+ end
+
+ def info
+ tk_call('event', 'info', "<#{@id}>").split(/\s+/).filter{|seq|
+ l = seq.scan(/<*[^<>]+>*/).filter{|subseq|
+ case (subseq)
+ when /^<<[^<>]+>>$/
+ TkVirtualEvent.getobj(subseq[1..-2])
+ when /^<[^<>]+>$/
+ subseq[1..-2]
+ else
+ subseq.split('')
+ end
+ }.flatten
+ (l.size == 1) ? l[0] : l
+ }
+ end
+end
diff --git a/ext/tk/sample/tkbiff.rb b/ext/tk/sample/tkbiff.rb
new file mode 100644
index 0000000000..d2d7bf7beb
--- /dev/null
+++ b/ext/tk/sample/tkbiff.rb
@@ -0,0 +1,149 @@
+#! /usr/local/bin/ruby
+
+if ARGV[0] != '-d'
+ unless $DEBUG
+ exit if fork
+ end
+else
+ ARGV.shift
+end
+
+if ARGV.length == 0
+ if ENV['MAIL']
+ $spool = ENV['MAIL']
+ else
+ $spool = '/usr/spool/mail/' + ENV['USER']
+ end
+else
+ $spool = ARGV[0]
+end
+
+require "parsedate"
+require "base64"
+
+include ParseDate
+
+class Mail
+ def Mail.new(f)
+ if !f.kind_of?(IO)
+ f = open(f, "r")
+ me = super
+ f.close
+ else
+ me = super
+ end
+ return me
+ end
+
+ def initialize(f)
+ @header = {}
+ @body = []
+ while f.gets()
+ $_.chop!
+ next if /^From / # skip From-line
+ break if /^$/ # end of header
+ if /^(\S+):\s*(.*)/
+ @header[attr = $1.capitalize] = $2
+ elsif attr
+ sub(/^\s*/, '')
+ @header[attr] += "\n" + $_
+ end
+ end
+
+ return if ! $_
+
+ while f.gets()
+ break if /^From /
+ @body.push($_)
+ end
+ end
+
+ def header
+ return @header
+ end
+
+ def body
+ return @body
+ end
+
+end
+
+require "tkscrollbox"
+
+$top = TkRoot.new
+$top.withdraw
+$list = TkScrollbox.new($top) {
+ relief 'raised'
+ width 80
+ height 8
+ setgrid 'yes'
+ pack
+}
+TkButton.new($top) {
+ text 'Dismiss'
+ command proc {$top.withdraw}
+ pack('fill'=>'both','expand'=>'yes')
+}
+$top.bind "Control-c", proc{exit}
+$top.bind "Control-q", proc{exit}
+$top.bind "space", proc{exit}
+
+$spool_size = 0
+$check_time = Time.now
+
+def check
+ $check_time = Time.now
+ size = File.size($spool)
+ if size and size != $spool_size
+ $spool_size = size
+ pop_up if size > 0
+ end
+ Tk.after 5000, proc{check}
+end
+
+if defined? Thread
+ Thread.start do
+ loop do
+ sleep 600
+ if Time.now - $check_time > 200
+ Tk.after 5000, proc{check}
+ end
+ end
+ end
+end
+
+def pop_up
+ outcount = 0;
+ $list.delete 0, 'end'
+ f = open($spool, "r")
+ while !f.eof?
+ mail = Mail.new(f)
+ date, from, subj = mail.header['Date'], mail.header['From'], mail.header['Subject']
+ next if !date
+ y = m = d = 0
+ y, m, d = parsedate(date) if date
+ from = "sombody@somewhere" if ! from
+ subj = "(nil)" if ! subj
+ from = decode_b(from)
+ subj = decode_b(subj)
+ $list.insert 'end', format('%-02d/%02d/%02d [%-28.28s] %s',y,m,d,from,subj)
+ outcount += 1
+ end
+ f.close
+ if outcount == 0
+ $list.insert 'end', "You have no mail."
+ else
+ $list.see 'end'
+ end
+ $top.deiconify
+ Tk.after 2000, proc{$top.withdraw}
+end
+
+$list.insert 'end', "You have no mail."
+check
+Tk.after 2000, proc{$top.withdraw}
+begin
+ Tk.mainloop
+rescue
+ `echo #$! > /tmp/tkbiff`
+end
diff --git a/ext/tk/sample/tkbrowse.rb b/ext/tk/sample/tkbrowse.rb
new file mode 100644
index 0000000000..882f0a489b
--- /dev/null
+++ b/ext/tk/sample/tkbrowse.rb
@@ -0,0 +1,79 @@
+#!/usr/local/bin/ruby
+#
+# This script generates a directory browser, which lists the working
+# directory and allows you to open files or subdirectories by
+# double-clicking.
+
+# Create a scrollbar on the right side of the main window and a listbox
+# on the left side.
+
+require "tkscrollbox"
+
+# The procedure below is invoked to open a browser on a given file; if the
+# file is a directory then another instance of this program is invoked; if
+# the file is a regular file then the Mx editor is invoked to display
+# the file.
+
+$dirlist = {}
+
+def browsedir (dir)
+ if $dirlist.key? dir
+ $dirlist[dir]
+ else
+ top = if $dirlist.size > 0 then TkToplevel.new else nil end
+ list = TkScrollbox.new(top) {
+ relief 'raised'
+ width 20
+ height 20
+ setgrid 'yes'
+ pack
+ }
+ list.insert 'end', *`ls #{dir}`.split
+
+ # Set up bindings for the browser.
+
+ list.focus
+ list.bind "Control-q", proc{exit}
+ list.bind "Control-c", proc{exit}
+ list.bind "Control-p", proc{
+ print "selection <", TkSelection.get, ">\n"
+ }
+
+ list.bind "Double-Button-1", proc{
+ for i in TkSelection.get.split
+ print "clicked ", i, "\n"
+ browse dir, i
+ end
+ }
+ $dirlist[dir] = list
+ end
+end
+
+def browse (dir, file)
+ file="#{dir}/#{file}"
+ if File.directory? file
+ browsedir(file)
+ else
+ if File.file? file
+ if ENV['EDITOR']
+ system format("%s %s&", ENV['EDITOR'], file)
+ else
+ system "xedit #{file}&"
+ end
+ else
+ STDERR.print "\"#{file}\" isn't a directory or regular file"
+ end
+ end
+end
+
+# Fill the listbox with a list of all the files in the directory (run
+# the "ls" command to get that information).
+
+if ARGV.length>0
+ dir = ARGV[0]
+else
+ dir="."
+end
+
+browsedir(dir)
+Tk.mainloop
diff --git a/ext/tk/sample/tkdialog.rb b/ext/tk/sample/tkdialog.rb
new file mode 100644
index 0000000000..e83e16d0a8
--- /dev/null
+++ b/ext/tk/sample/tkdialog.rb
@@ -0,0 +1,62 @@
+#! /usr/local/bin/ruby
+require "tk"
+
+root = TkFrame.new
+top = TkFrame.new(root) {
+ relief 'raised'
+ border 1
+}
+msg = TkMessage.new(top) {
+ text "File main.c hasn't been saved to disk since \
+it was last modified. What should I do?"
+ justify 'center'
+ aspect 200
+ font '-Adobe-helvetica-medium-r-normal--*-240*'
+ pack('padx'=>5, 'pady'=>5, 'expand'=>'yes')
+}
+top.pack('fill'=>'both')
+root.pack
+
+bot = TkFrame.new(root) {
+ relief 'raised'
+ border 1
+}
+
+TkFrame.new(bot) { |left|
+ relief 'sunken'
+ border 1
+ pack('side'=>'left', 'expand'=>'yes', 'padx'=>10, 'pady'=> 10)
+ TkButton.new(left) {
+ text "Save File"
+ command "quit 'save'"
+ pack('expand'=>'yes','padx'=>6,'pady'=> 6)
+ top.bind "Enter", proc{state 'active'}
+ msg.bind "Enter", proc{state 'active'}
+ bot.bind "Enter", proc{state 'active'}
+ top.bind "Leave", proc{state 'normal'}
+ msg.bind "Leave", proc{state 'normal'}
+ bot.bind "Leave", proc{state 'normal'}
+ Tk.root.bind "ButtonRelease-1", proc{quit 'save'}
+ Tk.root.bind "Return", proc{quit 'save'}
+ }
+}
+TkButton.new(bot) {
+ text "Quit Anyway"
+ command "quit 'quit'"
+ pack('side'=>'left', 'expand'=>'yes', 'padx'=>10)
+}
+TkButton.new(bot) {
+ text "Return To Editor"
+ command "quit 'return'"
+ pack('side'=>'left', 'expand'=>'yes', 'padx'=>10)
+}
+bot.pack
+root.pack('side'=>'top', 'fill'=>'both', 'expand'=>'yes')
+
+def quit(button)
+ print "aaa\n"
+ print "You pressed the \"#{button}\" button; bye-bye!\n"
+ exit
+end
+
+Tk.mainloop
diff --git a/ext/tk/sample/tkfrom.rb b/ext/tk/sample/tkfrom.rb
new file mode 100644
index 0000000000..ba0e547799
--- /dev/null
+++ b/ext/tk/sample/tkfrom.rb
@@ -0,0 +1,132 @@
+#! /usr/local/bin/ruby
+
+require "parsedate"
+require "base64"
+
+include ParseDate
+
+class Mail
+ def Mail.new(f)
+ if !f.kind_of?(IO)
+ f = open(f, "r")
+ me = super(f)
+ f.close
+ else
+ me = super
+ end
+ return me
+ end
+
+ def initialize(f)
+ @header = {}
+ @body = []
+ while f.gets()
+ $_.chop!
+ next if /^From / # skip From-line
+ break if /^$/ # end of header
+ if /^(\S+):\s*(.*)/
+ @header[attr = $1.capitalize] = $2
+ elsif attr
+ sub(/^\s*/, '')
+ @header[attr] += "\n" + $_
+ end
+ end
+
+ return if ! $_
+
+ while f.gets()
+ break if /^From /
+ @body.push($_)
+ end
+ end
+
+ def header
+ return @header
+ end
+
+ def body
+ return @body
+ end
+
+end
+
+if ARGV.length == 0
+ if ENV['MAIL']
+ ARGV[0] = ENV['MAIL']
+ elsif ENV['USER']
+ ARGV[0] = '/usr/spool/mail/' + ENV['USER']
+ elsif ENV['LOGNAME']
+ ARGV[0] = '/usr/spool/mail/' + ENV['LOGNAME']
+ end
+end
+
+require "tk"
+list = scroll = nil
+TkFrame.new{|f|
+ list = TkListbox.new(f) {
+ yscroll proc{|idx|
+ scroll.set *idx
+ }
+ relief 'raised'
+# geometry "80x5"
+ width 80
+ height 5
+ setgrid 'yes'
+ pack('side'=>'left','fill'=>'both','expand'=>'yes')
+ }
+ scroll = TkScrollbar.new(f) {
+ command proc{|idx|
+ list.yview *idx
+ }
+ pack('side'=>'right','fill'=>'y')
+ }
+ pack
+}
+root = Tk.root
+TkButton.new(root) {
+ text 'Dismiss'
+ command proc {exit}
+ pack('fill'=>'both','expand'=>'yes')
+}
+root.bind "Control-c", proc{exit}
+root.bind "Control-q", proc{exit}
+root.bind "space", proc{exit}
+
+$outcount = 0;
+for file in ARGV
+ next if File.exist?(file)
+ atime = File.atime(file)
+ mtime = File.mtime(file)
+ f = open(file, "r")
+ begin
+ until f.eof
+ mail = Mail.new(f)
+ date = mail.header['Date']
+ next unless date
+ from = mail.header['From']
+ subj = mail.header['Subject']
+ y = m = d = 0
+ y, m, d = parsedate(date) if date
+ from = "sombody@somewhere" unless from
+ subj = "(nil)" unless subj
+ from = decode_b(from)
+ subj = decode_b(subj)
+ list.insert 'end', format('%-02d/%02d/%02d [%-28.28s] %s',y,m,d,from,subj)
+ $outcount += 1
+ end
+ ensure
+ f.close
+ File.utime(atime, mtime, file)
+ list.see 'end'
+ end
+end
+
+limit = 10000
+if $outcount == 0
+ list.insert 'end', "You have no mail."
+ limit = 2000
+end
+Tk.after limit, proc{
+ exit
+}
+Tk.mainloop
diff --git a/ext/tk/sample/tkhello.rb b/ext/tk/sample/tkhello.rb
new file mode 100644
index 0000000000..5188fe1c8c
--- /dev/null
+++ b/ext/tk/sample/tkhello.rb
@@ -0,0 +1,10 @@
+require "tk"
+
+TkButton.new(nil,
+ 'text' => 'hello',
+ 'command' => proc{print "hello\n"}).pack('fill'=>'x')
+TkButton.new(nil,
+ 'text' => 'quit',
+ 'command' => 'exit').pack('fill'=>'x')
+
+Tk.mainloop
diff --git a/ext/tk/sample/tkline.rb b/ext/tk/sample/tkline.rb
new file mode 100644
index 0000000000..2406b0749f
--- /dev/null
+++ b/ext/tk/sample/tkline.rb
@@ -0,0 +1,45 @@
+
+require "tkclass"
+
+$tkline_init = FALSE
+def start_random
+ return if $tkline_init
+ $tkline_init = TRUE
+ if defined? Thread
+ Thread.start do
+ loop do
+ sleep 2
+ Line.new($c, rand(400), rand(200), rand(400), rand(200))
+ end
+ end
+ end
+end
+
+$c = Canvas.new
+$c.pack
+$start_x = start_y = 0
+
+def do_press(x, y)
+ $start_x = x
+ $start_y = y
+ $current_line = Line.new($c, x, y, x, y)
+ start_random
+end
+def do_motion(x, y)
+ if $current_line
+ $current_line.coords $start_x, $start_y, x, y
+ end
+end
+
+def do_release(x, y)
+ if $current_line
+ $current_line.coords $start_x, $start_y, x, y
+ $current_line.fill 'black'
+ $current_line = nil
+ end
+end
+
+$c.bind("1", proc{|e| do_press e.x, e.y})
+$c.bind("B1-Motion", proc{|x, y| do_motion x, y}, "%x %y")
+$c.bind("ButtonRelease-1", proc{|x, y| do_release x, y}, "%x %y")
+Tk.mainloop
diff --git a/ext/tk/sample/tktimer.rb b/ext/tk/sample/tktimer.rb
new file mode 100644
index 0000000000..34377e2f39
--- /dev/null
+++ b/ext/tk/sample/tktimer.rb
@@ -0,0 +1,50 @@
+#!/usr/local/bin/ruby
+# This script generates a counter with start and stop buttons.
+
+require "tk"
+$label = TkLabel.new {
+ text '0.00'
+ relief 'raised'
+ width 10
+ pack('side'=>'bottom', 'fill'=>'both')
+}
+
+TkButton.new {
+ text 'Start'
+ command proc {
+ if $stopped
+ $stopped = FALSE
+ tick
+ end
+ }
+ pack('side'=>'left','fill'=>'both','expand'=>'yes')
+}
+TkButton.new {
+ text 'Stop'
+ command proc{
+ exit if $stopped
+ $stopped = TRUE
+ }
+ pack('side'=>'right','fill'=>'both','expand'=>'yes')
+}
+
+$seconds=0
+$hundredths=0
+$stopped=TRUE
+
+def tick
+ if $stopped then return end
+ Tk.after 50, proc{tick}
+ $hundredths+=5
+ if $hundredths >= 100
+ $hundredths=0
+ $seconds+=1
+ end
+ $label.text format("%d.%02d", $seconds, $hundredths)
+end
+
+root = Tk.root
+root.bind "Control-c", proc{root.destroy}
+root.bind "Control-q", proc{root.destroy}
+Tk.root.focus
+Tk.mainloop
diff --git a/ext/tk/tkutil.c b/ext/tk/tkutil.c
new file mode 100644
index 0000000000..e93733bb67
--- /dev/null
+++ b/ext/tk/tkutil.c
@@ -0,0 +1,45 @@
+/************************************************
+
+ tk.c -
+
+ $Author$
+ $Date$
+ created at: Fri Nov 3 00:47:54 JST 1995
+
+************************************************/
+
+#include "ruby.h"
+
+static VALUE
+tk_eval_cmd(argc, argv)
+ int argc;
+ VALUE argv[];
+{
+ VALUE cmd, rest;
+
+ rb_scan_args(argc, argv, "1*", &cmd, &rest);
+ return rb_eval_cmd(cmd, rest);
+}
+
+static VALUE
+tk_s_new(argc, argv, class)
+ int argc;
+ VALUE *argv;
+ VALUE class;
+{
+ VALUE obj = rb_obj_alloc(class);
+
+ rb_funcall2(obj, rb_intern("initialize"), argc, argv);
+ if (rb_iterator_p()) rb_obj_instance_eval(0, 0, obj);
+ return obj;
+}
+
+Init_tkutil()
+{
+ VALUE mTK = rb_define_module("TkUtil");
+ VALUE cTK = rb_define_class("TkKernel", rb_cObject);
+
+ rb_define_singleton_method(mTK, "eval_cmd", tk_eval_cmd, -1);
+
+ rb_define_singleton_method(cTK, "new", tk_s_new, -1);
+}