diff options
Diffstat (limited to 'trunk/ext/tk/tcltklib.c')
-rw-r--r-- | trunk/ext/tk/tcltklib.c | 10154 |
1 files changed, 0 insertions, 10154 deletions
diff --git a/trunk/ext/tk/tcltklib.c b/trunk/ext/tk/tcltklib.c deleted file mode 100644 index 70894269ec..0000000000 --- a/trunk/ext/tk/tcltklib.c +++ /dev/null @@ -1,10154 +0,0 @@ -/* - * tcltklib.c - * Aug. 27, 1997 Y. Shigehiro - * Oct. 24, 1997 Y. Matsumoto - */ - -#define TCLTKLIB_RELEASE_DATE "2008-06-17" - -#include "ruby.h" - -#ifdef HAVE_RUBY_SIGNAL_H -#include "ruby/signal.h" -#else -#include "rubysig.h" -#endif -#ifdef HAVE_RUBY_ENCODING_H -#include "ruby/encoding.h" -#endif -#ifndef HAVE_RUBY_RUBY_H -#include "version.h" -#endif - -#undef EXTERN /* avoid conflict with tcl.h of tcl8.2 or before */ -#include <stdio.h> -#ifdef HAVE_STDARG_PROTOTYPES -#include <stdarg.h> -#define va_init_list(a,b) va_start(a,b) -#else -#include <varargs.h> -#define va_init_list(a,b) va_start(a) -#endif -#include <string.h> -#include <tcl.h> -#include <tk.h> - -#ifndef HAVE_RUBY_NATIVE_THREAD_P -#define ruby_native_thread_p() is_ruby_native_thread() -#undef RUBY_USE_NATIVE_THREAD -#else -#define RUBY_USE_NATIVE_THREAD 1 -#endif -#ifndef HAVE_RB_ERRINFO -#define rb_errinfo() (ruby_errinfo+0) /* cannot be l-value */ -#endif -#ifndef HAVE_RB_SAFE_LEVEL -#define rb_safe_level() (ruby_safe_level+0) /* cannot be l-value */ -#endif - -#include "stubs.h" - -#ifndef TCL_ALPHA_RELEASE -#define TCL_ALPHA_RELEASE 0 -#define TCL_BETA_RELEASE 1 -#define TCL_FINAL_RELEASE 2 -#endif - -static struct { - int major; - int minor; - int patchlevel; - int type; -} tcltk_version = {0, 0, 0, 0}; - -static void -set_tcltk_version() -{ - if (tcltk_version.major) return; - - Tcl_GetVersion(&(tcltk_version.major), - &(tcltk_version.minor), - &(tcltk_version.patchlevel), - &(tcltk_version.type)); -} - -#if TCL_MAJOR_VERSION >= 8 -# ifndef CONST84 -# if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION <= 4 /* Tcl8.0.x -- 8.4b1 */ -# define CONST84 -# else /* unknown (maybe TCL_VERSION >= 8.5) */ -# ifdef CONST -# define CONST84 CONST -# else -# define CONST84 -# endif -# endif -# endif -#else /* TCL_MAJOR_VERSION < 8 */ -# ifdef CONST -# define CONST84 CONST -# else -# define CONST -# define CONST84 -# endif -#endif - -/* copied from eval.c */ -#define TAG_RETURN 0x1 -#define TAG_BREAK 0x2 -#define TAG_NEXT 0x3 -#define TAG_RETRY 0x4 -#define TAG_REDO 0x5 -#define TAG_RAISE 0x6 -#define TAG_THROW 0x7 -#define TAG_FATAL 0x8 - -/* for ruby_debug */ -#define DUMP1(ARG1) if (ruby_debug) { fprintf(stderr, "tcltklib: %s\n", ARG1); fflush(stderr); } -#define DUMP2(ARG1, ARG2) if (ruby_debug) { fprintf(stderr, "tcltklib: ");\ -fprintf(stderr, ARG1, ARG2); fprintf(stderr, "\n"); fflush(stderr); } -#define DUMP3(ARG1, ARG2, ARG3) if (ruby_debug) { fprintf(stderr, "tcltklib: ");\ -fprintf(stderr, ARG1, ARG2, ARG3); fprintf(stderr, "\n"); fflush(stderr); } -/* -#define DUMP1(ARG1) -#define DUMP2(ARG1, ARG2) -#define DUMP3(ARG1, ARG2, ARG3) -*/ - -/* release date */ -static const char tcltklib_release_date[] = TCLTKLIB_RELEASE_DATE; - -/* finalize_proc_name */ -static const char finalize_hook_name[] = "INTERP_FINALIZE_HOOK"; - -static void ip_finalize _((Tcl_Interp*)); - -static int at_exit = 0; - -#ifdef HAVE_RUBY_ENCODING_H -static VALUE cRubyEncoding; - -/* encoding */ -static int ENCODING_INDEX_UTF8; -static int ENCODING_INDEX_BINARY; -#endif -static VALUE ENCODING_NAME_UTF8; -static VALUE ENCODING_NAME_BINARY; - -static VALUE create_dummy_encoding_for_tk_core _((VALUE, VALUE, VALUE)); -static VALUE create_dummy_encoding_for_tk _((VALUE, VALUE)); -static int update_encoding_table _((VALUE, VALUE, VALUE)); -static VALUE encoding_table_get_name_core _((VALUE, VALUE, VALUE)); -static VALUE encoding_table_get_obj_core _((VALUE, VALUE, VALUE)); -static VALUE encoding_table_get_name _((VALUE, VALUE)); -static VALUE encoding_table_get_obj _((VALUE, VALUE)); -static VALUE create_encoding_table _((VALUE)); -static VALUE ip_get_encoding_table _((VALUE)); - - -/* for callback break & continue */ -static VALUE eTkCallbackReturn; -static VALUE eTkCallbackBreak; -static VALUE eTkCallbackContinue; - -static VALUE eLocalJumpError; - -static VALUE eTkLocalJumpError; -static VALUE eTkCallbackRetry; -static VALUE eTkCallbackRedo; -static VALUE eTkCallbackThrow; - -static VALUE tcltkip_class; - -static ID ID_at_enc; -static ID ID_at_interp; - -static ID ID_encoding_name; -static ID ID_encoding_table; - -static ID ID_stop_p; -static ID ID_alive_p; -static ID ID_kill; -static ID ID_join; -static ID ID_value; - -static ID ID_call; -static ID ID_backtrace; -static ID ID_message; - -static ID ID_at_reason; -static ID ID_return; -static ID ID_break; -static ID ID_next; - -static ID ID_to_s; -static ID ID_inspect; - -static VALUE ip_invoke_real _((int, VALUE*, VALUE)); -static VALUE ip_invoke _((int, VALUE*, VALUE)); -static VALUE ip_invoke_with_position _((int, VALUE*, VALUE, Tcl_QueuePosition)); -static VALUE tk_funcall _((VALUE(), int, VALUE*, VALUE)); -static VALUE callq_safelevel_handler _((VALUE, VALUE)); - -/* Tcl's object type */ -#if TCL_MAJOR_VERSION >= 8 -static const char Tcl_ObjTypeName_ByteArray[] = "bytearray"; -static Tcl_ObjType *Tcl_ObjType_ByteArray; - -static const char Tcl_ObjTypeName_String[] = "string"; -static Tcl_ObjType *Tcl_ObjType_String; - -#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1) -#define IS_TCL_BYTEARRAY(obj) ((obj)->typePtr == Tcl_ObjType_ByteArray) -#define IS_TCL_STRING(obj) ((obj)->typePtr == Tcl_ObjType_String) -#define IS_TCL_VALID_STRING(obj) ((obj)->bytes != (char*)NULL) -#endif -#endif - -#ifndef HAVE_RB_HASH_LOOKUP -#define rb_hash_lookup rb_hash_aref -#endif - -/* safe Tcl_Eval and Tcl_GlobalEval */ -static int -#ifdef HAVE_PROTOTYPES -tcl_eval(Tcl_Interp *interp, const char *cmd) -#else -tcl_eval(interp, cmd) - Tcl_Interp *interp; - const char *cmd; /* don't have to be writable */ -#endif -{ - char *buf = strdup(cmd); - int ret; - - Tcl_AllowExceptions(interp); - ret = Tcl_Eval(interp, buf); - free(buf); - return ret; -} - -#undef Tcl_Eval -#define Tcl_Eval tcl_eval - -static int -#ifdef HAVE_PROTOTYPES -tcl_global_eval(Tcl_Interp *interp, const char *cmd) -#else -tcl_global_eval(interp, cmd) - Tcl_Interp *interp; - const char *cmd; /* don't have to be writable */ -#endif -{ - char *buf = strdup(cmd); - int ret; - - Tcl_AllowExceptions(interp); - ret = Tcl_GlobalEval(interp, buf); - free(buf); - return ret; -} - -#undef Tcl_GlobalEval -#define Tcl_GlobalEval tcl_global_eval - -/* Tcl_{Incr|Decr}RefCount for tcl7.x or earlier */ -#if TCL_MAJOR_VERSION < 8 -#define Tcl_IncrRefCount(obj) (1) -#define Tcl_DecrRefCount(obj) (1) -#endif - -/* Tcl_GetStringResult for tcl7.x or earlier */ -#if TCL_MAJOR_VERSION < 8 -#define Tcl_GetStringResult(interp) ((interp)->result) -#endif - -/* Tcl_[GS]etVar2Ex for tcl8.0 */ -#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0 -static Tcl_Obj * -Tcl_GetVar2Ex(interp, name1, name2, flags) - Tcl_Interp *interp; - CONST char *name1; - CONST char *name2; - int flags; -{ - Tcl_Obj *nameObj1, *nameObj2 = NULL, *retObj; - - nameObj1 = Tcl_NewStringObj((char*)name1, -1); - Tcl_IncrRefCount(nameObj1); - - if (name2) { - nameObj2 = Tcl_NewStringObj((char*)name2, -1); - Tcl_IncrRefCount(nameObj2); - } - - retObj = Tcl_ObjGetVar2(interp, nameObj1, nameObj2, flags); - - if (name2) { - Tcl_DecrRefCount(nameObj2); - } - - Tcl_DecrRefCount(nameObj1); - - return retObj; -} - -static Tcl_Obj * -Tcl_SetVar2Ex(interp, name1, name2, newValObj, flags) - Tcl_Interp *interp; - CONST char *name1; - CONST char *name2; - Tcl_Obj *newValObj; - int flags; -{ - Tcl_Obj *nameObj1, *nameObj2 = NULL, *retObj; - - nameObj1 = Tcl_NewStringObj((char*)name1, -1); - Tcl_IncrRefCount(nameObj1); - - if (name2) { - nameObj2 = Tcl_NewStringObj((char*)name2, -1); - Tcl_IncrRefCount(nameObj2); - } - - retObj = Tcl_ObjSetVar2(interp, nameObj1, nameObj2, newValObj, flags); - - if (name2) { - Tcl_DecrRefCount(nameObj2); - } - - Tcl_DecrRefCount(nameObj1); - - return retObj; -} -#endif - -/* from tkAppInit.c */ - -#if TCL_MAJOR_VERSION < 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION < 4) -# if !defined __MINGW32__ && !defined __BORLANDC__ -/* - * The following variable is a special hack that is needed in order for - * Sun shared libraries to be used for Tcl. - */ - -extern int matherr(); -int *tclDummyMathPtr = (int *) matherr; -# endif -#endif - -/*---- module TclTkLib ----*/ - -struct invoke_queue { - Tcl_Event ev; - int argc; -#if TCL_MAJOR_VERSION >= 8 - Tcl_Obj **argv; -#else /* TCL_MAJOR_VERSION < 8 */ - char **argv; -#endif - VALUE interp; - int *done; - int safe_level; - VALUE result; - VALUE thread; -}; - -struct eval_queue { - Tcl_Event ev; - char *str; - int len; - VALUE interp; - int *done; - int safe_level; - VALUE result; - VALUE thread; -}; - -struct call_queue { - Tcl_Event ev; - VALUE (*func)(); - int argc; - VALUE *argv; - VALUE interp; - int *done; - int safe_level; - VALUE result; - VALUE thread; -}; - -void -invoke_queue_mark(struct invoke_queue *q) -{ - rb_gc_mark(q->interp); - rb_gc_mark(q->result); - rb_gc_mark(q->thread); -} - -void -eval_queue_mark(struct eval_queue *q) -{ - rb_gc_mark(q->interp); - rb_gc_mark(q->result); - rb_gc_mark(q->thread); -} - -void -call_queue_mark(struct call_queue *q) -{ - int i; - - for(i = 0; i < q->argc; i++) { - rb_gc_mark(q->argv[i]); - } - - rb_gc_mark(q->interp); - rb_gc_mark(q->result); - rb_gc_mark(q->thread); -} - - -static VALUE eventloop_thread; -#ifdef RUBY_USE_NATIVE_THREAD -Tcl_ThreadId tk_eventloop_thread_id; /* native thread ID of Tcl interpreter */ -#endif -static VALUE eventloop_stack; -static int window_event_mode = ( ~ TCL_IDLE_EVENTS | TCL_WINDOW_EVENTS ); - -static VALUE watchdog_thread; - -Tcl_Interp *current_interp; - -/* thread control strategy */ -/* multi-tk works with the following settings only ??? - : CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE 1 - : USE_TOGGLE_WINDOW_MODE_FOR_IDLE 0 - : DO_THREAD_SCHEDULE_AT_CALLBACK_DONE 0 -*/ -#ifdef RUBY_USE_NATIVE_THREAD -#define CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE 1 -#define USE_TOGGLE_WINDOW_MODE_FOR_IDLE 0 -#define DO_THREAD_SCHEDULE_AT_CALLBACK_DONE 1 -#else /* ! RUBY_USE_NATIVE_THREAD */ -#define CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE 1 -#define USE_TOGGLE_WINDOW_MODE_FOR_IDLE 0 -#define DO_THREAD_SCHEDULE_AT_CALLBACK_DONE 0 -#endif - -#if CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE -static int have_rb_thread_waiting_for_value = 0; -#endif - -/* - * 'event_loop_max' is a maximum events which the eventloop processes in one - * term of thread scheduling. 'no_event_tick' is the count-up value when - * there are no event for processing. - * 'timer_tick' is a limit of one term of thread scheduling. - * If 'timer_tick' == 0, then not use the timer for thread scheduling. - */ -#ifdef RUBY_USE_NATIVE_THREAD -#define DEFAULT_EVENT_LOOP_MAX 800/*counts*/ -#define DEFAULT_NO_EVENT_TICK 10/*counts*/ -#define DEFAULT_NO_EVENT_WAIT 1/*milliseconds ( 1 -- 999 ) */ -#define WATCHDOG_INTERVAL 10/*milliseconds ( 1 -- 999 ) */ -#define DEFAULT_TIMER_TICK 0/*milliseconds ( 0 -- 999 ) */ -#define NO_THREAD_INTERRUPT_TIME 100/*milliseconds ( 1 -- 999 ) */ -#else /* ! RUBY_USE_NATIVE_THREAD */ -#define DEFAULT_EVENT_LOOP_MAX 800/*counts*/ -#define DEFAULT_NO_EVENT_TICK 10/*counts*/ -#define DEFAULT_NO_EVENT_WAIT 20/*milliseconds ( 1 -- 999 ) */ -#define WATCHDOG_INTERVAL 10/*milliseconds ( 1 -- 999 ) */ -#define DEFAULT_TIMER_TICK 0/*milliseconds ( 0 -- 999 ) */ -#define NO_THREAD_INTERRUPT_TIME 100/*milliseconds ( 1 -- 999 ) */ -#endif - -static int event_loop_max = DEFAULT_EVENT_LOOP_MAX; -static int no_event_tick = DEFAULT_NO_EVENT_TICK; -static int no_event_wait = DEFAULT_NO_EVENT_WAIT; -static int timer_tick = DEFAULT_TIMER_TICK; -static int req_timer_tick = DEFAULT_TIMER_TICK; -static int run_timer_flag = 0; - -static int event_loop_wait_event = 0; -static int event_loop_abort_on_exc = 1; -static int loop_counter = 0; - -static int check_rootwidget_flag = 0; - - -/* call ruby interpreter */ -#if TCL_MAJOR_VERSION >= 8 -static int ip_ruby_eval _((ClientData, Tcl_Interp *, int, Tcl_Obj *CONST*)); -static int ip_ruby_cmd _((ClientData, Tcl_Interp *, int, Tcl_Obj *CONST*)); -#else /* TCL_MAJOR_VERSION < 8 */ -static int ip_ruby_eval _((ClientData, Tcl_Interp *, int, char **)); -static int ip_ruby_cmd _((ClientData, Tcl_Interp *, int, char **)); -#endif - -struct cmd_body_arg { - VALUE receiver; - ID method; - VALUE args; -}; - - -/*----------------------------*/ -/* use Tcl internal functions */ -/*----------------------------*/ -#ifndef TCL_NAMESPACE_DEBUG -#define TCL_NAMESPACE_DEBUG 0 -#endif - -#if TCL_NAMESPACE_DEBUG - -#if TCL_MAJOR_VERSION >= 8 -EXTERN struct TclIntStubs *tclIntStubsPtr; -#endif - -/*-- Tcl_GetCurrentNamespace --*/ -#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION < 5 -/* Tcl7.x doesn't have namespace support. */ -/* Tcl8.5+ has definition of Tcl_GetCurrentNamespace() in tclDecls.h */ -# ifndef Tcl_GetCurrentNamespace -EXTERN Tcl_Namespace * Tcl_GetCurrentNamespace _((Tcl_Interp *)); -# endif -# if defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) -# ifndef Tcl_GetCurrentNamespace -# ifndef FunctionNum_of_GetCurrentNamespace -#define FunctionNum_of_GetCurrentNamespace 124 -# endif -struct DummyTclIntStubs_for_GetCurrentNamespace { - int magic; - struct TclIntStubHooks *hooks; - void (*func[FunctionNum_of_GetCurrentNamespace])(); - Tcl_Namespace * (*tcl_GetCurrentNamespace) _((Tcl_Interp *)); -}; - -#define Tcl_GetCurrentNamespace \ - (((struct DummyTclIntStubs_for_GetCurrentNamespace *)tclIntStubsPtr)->tcl_GetCurrentNamespace) -# endif -# endif -#endif - -/* namespace check */ -/* ip_null_namespace(Tcl_Interp *interp) */ -#if TCL_MAJOR_VERSION < 8 -#define ip_null_namespace(interp) (0) -#else /* support namespace */ -#define ip_null_namespace(interp) \ - (Tcl_GetCurrentNamespace(interp) == (Tcl_Namespace *)NULL) -#endif - -/* rbtk_invalid_namespace(tcltkip *ptr) */ -#if TCL_MAJOR_VERSION < 8 -#define rbtk_invalid_namespace(ptr) (0) -#else /* support namespace */ -#define rbtk_invalid_namespace(ptr) \ - ((ptr)->default_ns == (Tcl_Namespace*)NULL || Tcl_GetCurrentNamespace((ptr)->ip) != (ptr)->default_ns) -#endif - -/*-- Tcl_PopCallFrame & Tcl_PushCallFrame --*/ -#if TCL_MAJOR_VERSION >= 8 -# ifndef CallFrame -typedef struct CallFrame { - Tcl_Namespace *nsPtr; - int dummy1; - int dummy2; - char *dummy3; - struct CallFrame *callerPtr; - struct CallFrame *callerVarPtr; - int level; - char *dummy7; - char *dummy8; - int dummy9; - char* dummy10; -} CallFrame; -# endif - -# if !defined(TclGetFrame) && !defined(TclGetFrame_TCL_DECLARED) -EXTERN int TclGetFrame _((Tcl_Interp *, CONST char *, CallFrame **)); -# endif -# if defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) -# ifndef TclGetFrame -# ifndef FunctionNum_of_GetFrame -#define FunctionNum_of_GetFrame 32 -# endif -struct DummyTclIntStubs_for_GetFrame { - int magic; - struct TclIntStubHooks *hooks; - void (*func[FunctionNum_of_GetFrame])(); - int (*tclGetFrame) _((Tcl_Interp *, CONST char *, CallFrame **)); -}; -#define TclGetFrame \ - (((struct DummyTclIntStubs_for_GetFrame *)tclIntStubsPtr)->tclGetFrame) -# endif -# endif - -# if !defined(Tcl_PopCallFrame) && !defined(Tcl_PopCallFrame_TCL_DECLARED) -EXTERN void Tcl_PopCallFrame _((Tcl_Interp *)); -EXTERN int Tcl_PushCallFrame _((Tcl_Interp *, Tcl_CallFrame *, Tcl_Namespace *, int)); -# endif -# if defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) -# ifndef Tcl_PopCallFrame -# ifndef FunctionNum_of_PopCallFrame -#define FunctionNum_of_PopCallFrame 128 -# endif -struct DummyTclIntStubs_for_PopCallFrame { - int magic; - struct TclIntStubHooks *hooks; - void (*func[FunctionNum_of_PopCallFrame])(); - void (*tcl_PopCallFrame) _((Tcl_Interp *)); - int (*tcl_PushCallFrame) _((Tcl_Interp *, Tcl_CallFrame *, Tcl_Namespace *, int)); -}; - -#define Tcl_PopCallFrame \ - (((struct DummyTclIntStubs_for_PopCallFrame *)tclIntStubsPtr)->tcl_PopCallFrame) -#define Tcl_PushCallFrame \ - (((struct DummyTclIntStubs_for_PopCallFrame *)tclIntStubsPtr)->tcl_PushCallFrame) -# endif -# endif - -#else /* Tcl7.x */ -# ifndef CallFrame -typedef struct CallFrame { - Tcl_HashTable varTable; - int level; - int argc; - char **argv; - struct CallFrame *callerPtr; - struct CallFrame *callerVarPtr; -} CallFrame; -# endif -# ifndef Tcl_CallFrame -#define Tcl_CallFrame CallFrame -# endif - -# if !defined(TclGetFrame) && !defined(TclGetFrame_TCL_DECLARED) -EXTERN int TclGetFrame _((Tcl_Interp *, CONST char *, CallFrame **)); -# endif - -# if !defined(Tcl_PopCallFrame) && !defined(Tcl_PopCallFrame_TCL_DECLARED) -typedef struct DummyInterp { - char *dummy1; - char *dummy2; - int dummy3; - Tcl_HashTable dummy4; - Tcl_HashTable dummy5; - Tcl_HashTable dummy6; - int numLevels; - int maxNestingDepth; - CallFrame *framePtr; - CallFrame *varFramePtr; -} DummyInterp; - -static void -Tcl_PopCallFrame(interp) - Tcl_Interp *interp; -{ - DummyInterp *iPtr = (DummyInterp*)interp; - CallFrame *frame = iPtr->varFramePtr; - - /* **** DUMMY **** */ - iPtr->framePtr = frame.callerPtr; - iPtr->varFramePtr = frame.callerVarPtr; - - return TCL_OK; -} - -/* dummy */ -#define Tcl_Namespace char - -static int -Tcl_PushCallFrame(interp, framePtr, nsPtr, isProcCallFrame) - Tcl_Interp *interp; - Tcl_CallFrame *framePtr; - Tcl_Namespace *nsPtr; - int isProcCallFrame; -{ - DummyInterp *iPtr = (DummyInterp*)interp; - CallFrame *frame = (CallFrame *)framePtr; - - /* **** DUMMY **** */ - Tcl_InitHashTable(&frame.varTable, TCL_STRING_KEYS); - if (iPtr->varFramePtr != NULL) { - frame.level = iPtr->varFramePtr->level + 1; - } else { - frame.level = 1; - } - frame.callerPtr = iPtr->framePtr; - frame.callerVarPtr = iPtr->varFramePtr; - iPtr->framePtr = &frame; - iPtr->varFramePtr = &frame; - - return TCL_OK; -} -# endif - -#endif - -#endif /* TCL_NAMESPACE_DEBUG */ - - -/*---- class TclTkIp ----*/ -struct tcltkip { - Tcl_Interp *ip; /* the interpreter */ -#if TCL_NAMESPACE_DEBUG - Tcl_Namespace *default_ns; /* default namespace */ -#endif -#ifdef RUBY_USE_NATIVE_THREAD - Tcl_ThreadId tk_thread_id; /* native thread ID of Tcl interpreter */ -#endif - int has_orig_exit; /* has original 'exit' command ? */ - Tcl_CmdInfo orig_exit_info; /* command info of original 'exit' command */ - int ref_count; /* reference count of rbtk_preserve_ip call */ - int allow_ruby_exit; /* allow exiting ruby by 'exit' function */ - int return_value; /* return value */ -}; - -static struct tcltkip * -get_ip(self) - VALUE self; -{ - struct tcltkip *ptr; - - Data_Get_Struct(self, struct tcltkip, ptr); - if (ptr == 0) { - /* rb_raise(rb_eTypeError, "uninitialized TclTkIp"); */ - return((struct tcltkip *)NULL); - } - if (ptr->ip == (Tcl_Interp*)NULL) { - /* rb_raise(rb_eRuntimeError, "deleted IP"); */ - return((struct tcltkip *)NULL); - } - return ptr; -} - -static int -deleted_ip(ptr) - struct tcltkip *ptr; -{ - if (!ptr || !ptr->ip || Tcl_InterpDeleted(ptr->ip) -#if TCL_NAMESPACE_DEBUG - || rbtk_invalid_namespace(ptr) -#endif - ) { - DUMP1("ip is deleted"); - return 1; - } - return 0; -} - -/* increment/decrement reference count of tcltkip */ -static int -rbtk_preserve_ip(ptr) - struct tcltkip *ptr; -{ - ptr->ref_count++; - if (ptr->ip == (Tcl_Interp*)NULL) { - /* deleted IP */ - ptr->ref_count = 0; - } else { - Tcl_Preserve((ClientData)ptr->ip); - } - return(ptr->ref_count); -} - -static int -rbtk_release_ip(ptr) - struct tcltkip *ptr; -{ - ptr->ref_count--; - if (ptr->ref_count < 0) { - ptr->ref_count = 0; - } else if (ptr->ip == (Tcl_Interp*)NULL) { - /* deleted IP */ - ptr->ref_count = 0; - } else { - Tcl_Release((ClientData)ptr->ip); - } - return(ptr->ref_count); -} - - -static VALUE -#ifdef HAVE_STDARG_PROTOTYPES -create_ip_exc(VALUE interp, VALUE exc, const char *fmt, ...) -#else -create_ip_exc(interp, exc, fmt, va_alist) - VALUE interp: - VALUE exc; - const char *fmt; - va_dcl -#endif -{ - va_list args; - char buf[BUFSIZ]; - VALUE einfo; - struct tcltkip *ptr = get_ip(interp); - - va_init_list(args,fmt); - vsnprintf(buf, BUFSIZ, fmt, args); - buf[BUFSIZ - 1] = '\0'; - va_end(args); - einfo = rb_exc_new2(exc, buf); - rb_ivar_set(einfo, ID_at_interp, interp); - if (ptr) { - Tcl_ResetResult(ptr->ip); - } - - return einfo; -} - - -/* stub status */ -static void -tcl_stubs_check() -{ - if (!tcl_stubs_init_p()) { - int st = ruby_tcl_stubs_init(); - switch(st) { - case TCLTK_STUBS_OK: - break; - case NO_TCL_DLL: - rb_raise(rb_eLoadError, "tcltklib: fail to open tcl_dll"); - case NO_FindExecutable: - rb_raise(rb_eLoadError, "tcltklib: can't find Tcl_FindExecutable"); - case NO_CreateInterp: - rb_raise(rb_eLoadError, "tcltklib: can't find Tcl_CreateInterp()"); - case NO_DeleteInterp: - rb_raise(rb_eLoadError, "tcltklib: can't find Tcl_DeleteInterp()"); - case FAIL_CreateInterp: - rb_raise(rb_eRuntimeError, "tcltklib: fail to create a new IP to call Tcl_InitStubs()"); - case FAIL_Tcl_InitStubs: - rb_raise(rb_eRuntimeError, "tcltklib: fail to Tcl_InitStubs()"); - default: - rb_raise(rb_eRuntimeError, "tcltklib: unknown error(%d) on ruby_tcl_stubs_init()", st); - } - } -} - - -static VALUE -tcltkip_init_tk(interp) - VALUE interp; -{ - struct tcltkip *ptr = get_ip(interp); - -#if TCL_MAJOR_VERSION >= 8 - int st; - - if (Tcl_IsSafe(ptr->ip)) { - DUMP1("Tk_SafeInit"); - st = ruby_tk_stubs_safeinit(ptr->ip); - switch(st) { - case TCLTK_STUBS_OK: - break; - case NO_Tk_Init: - return rb_exc_new2(rb_eLoadError, - "tcltklib: can't find Tk_SafeInit()"); - case FAIL_Tk_Init: - return create_ip_exc(interp, rb_eRuntimeError, - "tcltklib: fail to Tk_SafeInit(). %s", - Tcl_GetStringResult(ptr->ip)); - case FAIL_Tk_InitStubs: - return create_ip_exc(interp, rb_eRuntimeError, - "tcltklib: fail to Tk_InitStubs(). %s", - Tcl_GetStringResult(ptr->ip)); - default: - return create_ip_exc(interp, rb_eRuntimeError, - "tcltklib: unknown error(%d) on ruby_tk_stubs_safeinit", st); - } - } else { - DUMP1("Tk_Init"); - st = ruby_tk_stubs_init(ptr->ip); - switch(st) { - case TCLTK_STUBS_OK: - break; - case NO_Tk_Init: - return rb_exc_new2(rb_eLoadError, - "tcltklib: can't find Tk_Init()"); - case FAIL_Tk_Init: - return create_ip_exc(interp, rb_eRuntimeError, - "tcltklib: fail to Tk_Init(). %s", - Tcl_GetStringResult(ptr->ip)); - case FAIL_Tk_InitStubs: - return create_ip_exc(interp, rb_eRuntimeError, - "tcltklib: fail to Tk_InitStubs(). %s", - Tcl_GetStringResult(ptr->ip)); - default: - return create_ip_exc(interp, rb_eRuntimeError, - "tcltklib: unknown error(%d) on ruby_tk_stubs_init", st); - } - } - -#else /* TCL_MAJOR_VERSION < 8 */ - DUMP1("Tk_Init"); - if (ruby_tk_stubs_init(ptr->ip) != TCLTK_STUBS_OK) { - return rb_exc_new2(rb_eRuntimeError, ptr->ip->result); - } -#endif - -#ifdef RUBY_USE_NATIVE_THREAD - ptr->tk_thread_id = Tcl_GetCurrentThread(); -#endif - - return Qnil; -} - - -/* treat excetiopn on Tcl side */ -static VALUE rbtk_pending_exception; -static int rbtk_eventloop_depth = 0; -static int rbtk_internal_eventloop_handler = 0; - - -static int -pending_exception_check0() -{ - volatile VALUE exc = rbtk_pending_exception; - - if (!NIL_P(exc) && rb_obj_is_kind_of(exc, rb_eException)) { - DUMP1("find a pending exception"); - if (rbtk_eventloop_depth > 0 - || rbtk_internal_eventloop_handler > 0 - ) { - return 1; /* pending */ - } else { - rbtk_pending_exception = Qnil; - - if (rb_obj_is_kind_of(exc, eTkCallbackRetry)) { - DUMP1("pending_exception_check0: call rb_jump_tag(retry)"); - rb_jump_tag(TAG_RETRY); - } else if (rb_obj_is_kind_of(exc, eTkCallbackRedo)) { - DUMP1("pending_exception_check0: call rb_jump_tag(redo)"); - rb_jump_tag(TAG_REDO); - } else if (rb_obj_is_kind_of(exc, eTkCallbackThrow)) { - DUMP1("pending_exception_check0: call rb_jump_tag(throw)"); - rb_jump_tag(TAG_THROW); - } - - rb_exc_raise(exc); - } - } else { - return 0; - } -} - -static int -pending_exception_check1(thr_crit_bup, ptr) - int thr_crit_bup; - struct tcltkip *ptr; -{ - volatile VALUE exc = rbtk_pending_exception; - - if (!NIL_P(exc) && rb_obj_is_kind_of(exc, rb_eException)) { - DUMP1("find a pending exception"); - - if (rbtk_eventloop_depth > 0 - || rbtk_internal_eventloop_handler > 0 - ) { - return 1; /* pending */ - } else { - rbtk_pending_exception = Qnil; - - if (ptr != (struct tcltkip *)NULL) { - /* Tcl_Release(ptr->ip); */ - rbtk_release_ip(ptr); - } - - rb_thread_critical = thr_crit_bup; - - if (rb_obj_is_kind_of(exc, eTkCallbackRetry)) { - DUMP1("pending_exception_check1: call rb_jump_tag(retry)"); - rb_jump_tag(TAG_RETRY); - } else if (rb_obj_is_kind_of(exc, eTkCallbackRedo)) { - DUMP1("pending_exception_check1: call rb_jump_tag(redo)"); - rb_jump_tag(TAG_REDO); - } else if (rb_obj_is_kind_of(exc, eTkCallbackThrow)) { - DUMP1("pending_exception_check1: call rb_jump_tag(throw)"); - rb_jump_tag(TAG_THROW); - } - rb_exc_raise(exc); - } - } else { - return 0; - } -} - - -/* call original 'exit' command */ -static void -call_original_exit(ptr, state) - struct tcltkip *ptr; - int state; -{ - int thr_crit_bup; - Tcl_CmdInfo *info; -#if TCL_MAJOR_VERSION >= 8 - Tcl_Obj *cmd_obj; - Tcl_Obj *state_obj; -#endif - DUMP1("original_exit is called"); - - if (!(ptr->has_orig_exit)) return; - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - Tcl_ResetResult(ptr->ip); - - info = &(ptr->orig_exit_info); - - /* memory allocation for arguments of this command */ -#if TCL_MAJOR_VERSION >= 8 - state_obj = Tcl_NewIntObj(state); - Tcl_IncrRefCount(state_obj); - - if (info->isNativeObjectProc) { - Tcl_Obj **argv; -#define USE_RUBY_ALLOC 0 -#if USE_RUBY_ALLOC - argv = (Tcl_Obj **)ALLOC_N(Tcl_Obj *, 3); -#else /* not USE_RUBY_ALLOC */ - argv = (Tcl_Obj **)ckalloc(sizeof(Tcl_Obj *) * 3); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ -#endif -#endif - cmd_obj = Tcl_NewStringObj("exit", 4); - Tcl_IncrRefCount(cmd_obj); - - argv[0] = cmd_obj; - argv[1] = state_obj; - argv[2] = (Tcl_Obj *)NULL; - - ptr->return_value - = (*(info->objProc))(info->objClientData, ptr->ip, 2, argv); - - Tcl_DecrRefCount(cmd_obj); - -#if USE_RUBY_ALLOC - free(argv); -#else /* not USE_RUBY_ALLOC */ -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)argv); /* XXXXXXXX */ -#else - /* free(argv); */ - ckfree((char*)argv); -#endif -#endif -#endif -#undef USE_RUBY_ALLOC - - } else { - /* string interface */ - CONST84 char **argv; -#define USE_RUBY_ALLOC 0 -#if USE_RUBY_ALLOC - argv = ALLOC_N(char *, 3); /* XXXXXXXXXX */ -#else /* not USE_RUBY_ALLOC */ - argv = (CONST84 char **)ckalloc(sizeof(char *) * 3); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ -#endif -#endif - argv[0] = "exit"; - /* argv[1] = Tcl_GetString(state_obj); */ - argv[1] = Tcl_GetStringFromObj(state_obj, (int*)NULL); - argv[2] = (char *)NULL; - - ptr->return_value = (*(info->proc))(info->clientData, ptr->ip, 2, argv); - -#if USE_RUBY_ALLOC - free(argv); -#else /* not USE_RUBY_ALLOC */ -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)argv); /* XXXXXXXX */ -#else - /* free(argv); */ - ckfree((char*)argv); -#endif -#endif -#endif -#undef USE_RUBY_ALLOC - } - - Tcl_DecrRefCount(state_obj); - -#else /* TCL_MAJOR_VERSION < 8 */ - { - /* string interface */ - char **argv; -#define USE_RUBY_ALLOC 0 -#if USE_RUBY_ALLOC - argv = (char **)ALLOC_N(char *, 3); -#else /* not USE_RUBY_ALLOC */ - argv = (char **)ckalloc(sizeof(char *) * 3); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ -#endif -#endif - argv[0] = "exit"; - argv[1] = RSTRING_PTR(rb_fix2str(INT2NUM(state), 10)); - argv[2] = (char *)NULL; - - ptr->return_value = (*(info->proc))(info->clientData, ptr->ip, - 2, argv); - -#if USE_RUBY_ALLOC - free(argv); -#else /* not USE_RUBY_ALLOC */ -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)argv); /* XXXXXXXX */ -#else - /* free(argv); */ - ckfree(argv); -#endif -#endif -#endif -#undef USE_RUBY_ALLOC - } -#endif - DUMP1("complete original_exit"); - - rb_thread_critical = thr_crit_bup; -} - -/* Tk_ThreadTimer */ -static Tcl_TimerToken timer_token = (Tcl_TimerToken)NULL; - -/* timer callback */ -static void _timer_for_tcl _((ClientData)); -static void -_timer_for_tcl(clientData) - ClientData clientData; -{ - int thr_crit_bup; - - /* struct invoke_queue *q, *tmp; */ - /* VALUE thread; */ - - DUMP1("call _timer_for_tcl"); - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - Tcl_DeleteTimerHandler(timer_token); - - run_timer_flag = 1; - - if (timer_tick > 0) { - timer_token = Tcl_CreateTimerHandler(timer_tick, _timer_for_tcl, - (ClientData)0); - } else { - timer_token = (Tcl_TimerToken)NULL; - } - - rb_thread_critical = thr_crit_bup; - - /* rb_thread_schedule(); */ - /* tick_counter += event_loop_max; */ -} - -#ifdef RUBY_USE_NATIVE_THREAD -#if USE_TOGGLE_WINDOW_MODE_FOR_IDLE -static int -toggle_eventloop_window_mode_for_idle() -{ - if (window_event_mode & TCL_IDLE_EVENTS) { - /* idle -> event */ - window_event_mode |= TCL_WINDOW_EVENTS; - window_event_mode &= ~TCL_IDLE_EVENTS; - return 1; - } else { - /* event -> idle */ - window_event_mode |= TCL_IDLE_EVENTS; - window_event_mode &= ~TCL_WINDOW_EVENTS; - return 0; - } -} -#endif -#endif - -static VALUE -set_eventloop_window_mode(self, mode) - VALUE self; - VALUE mode; -{ - rb_secure(4); - - if (RTEST(mode)) { - window_event_mode = ~0; - } else { - window_event_mode = ~(TCL_WINDOW_EVENTS | TCL_IDLE_EVENTS); - } - - return mode; -} - -static VALUE -get_eventloop_window_mode(self) - VALUE self; -{ - if ( ~window_event_mode ) { - return Qfalse; - } else { - return Qtrue; - } -} - -static VALUE -set_eventloop_tick(self, tick) - VALUE self; - VALUE tick; -{ - int ttick = NUM2INT(tick); - int thr_crit_bup; - - rb_secure(4); - - if (ttick < 0) { - rb_raise(rb_eArgError, - "timer-tick parameter must be 0 or positive number"); - } - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - /* delete old timer callback */ - Tcl_DeleteTimerHandler(timer_token); - - timer_tick = req_timer_tick = ttick; - if (timer_tick > 0) { - /* start timer callback */ - timer_token = Tcl_CreateTimerHandler(timer_tick, _timer_for_tcl, - (ClientData)0); - } else { - timer_token = (Tcl_TimerToken)NULL; - } - - rb_thread_critical = thr_crit_bup; - - return tick; -} - -static VALUE -get_eventloop_tick(self) - VALUE self; -{ - return INT2NUM(timer_tick); -} - -static VALUE -ip_set_eventloop_tick(self, tick) - VALUE self; - VALUE tick; -{ - struct tcltkip *ptr = get_ip(self); - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - return get_eventloop_tick(self); - } - - if (Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL) { - /* slave IP */ - return get_eventloop_tick(self); - } - return set_eventloop_tick(self, tick); -} - -static VALUE -ip_get_eventloop_tick(self) - VALUE self; -{ - return get_eventloop_tick(self); -} - -static VALUE -set_no_event_wait(self, wait) - VALUE self; - VALUE wait; -{ - int t_wait = NUM2INT(wait); - - rb_secure(4); - - if (t_wait <= 0) { - rb_raise(rb_eArgError, - "no_event_wait parameter must be positive number"); - } - - no_event_wait = t_wait; - - return wait; -} - -static VALUE -get_no_event_wait(self) - VALUE self; -{ - return INT2NUM(no_event_wait); -} - -static VALUE -ip_set_no_event_wait(self, wait) - VALUE self; - VALUE wait; -{ - struct tcltkip *ptr = get_ip(self); - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - return get_no_event_wait(self); - } - - if (Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL) { - /* slave IP */ - return get_no_event_wait(self); - } - return set_no_event_wait(self, wait); -} - -static VALUE -ip_get_no_event_wait(self) - VALUE self; -{ - return get_no_event_wait(self); -} - -static VALUE -set_eventloop_weight(self, loop_max, no_event) - VALUE self; - VALUE loop_max; - VALUE no_event; -{ - int lpmax = NUM2INT(loop_max); - int no_ev = NUM2INT(no_event); - - rb_secure(4); - - if (lpmax <= 0 || no_ev <= 0) { - rb_raise(rb_eArgError, "weight parameters must be positive numbers"); - } - - event_loop_max = lpmax; - no_event_tick = no_ev; - - return rb_ary_new3(2, loop_max, no_event); -} - -static VALUE -get_eventloop_weight(self) - VALUE self; -{ - return rb_ary_new3(2, INT2NUM(event_loop_max), INT2NUM(no_event_tick)); -} - -static VALUE -ip_set_eventloop_weight(self, loop_max, no_event) - VALUE self; - VALUE loop_max; - VALUE no_event; -{ - struct tcltkip *ptr = get_ip(self); - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - return get_eventloop_weight(self); - } - - if (Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL) { - /* slave IP */ - return get_eventloop_weight(self); - } - return set_eventloop_weight(self, loop_max, no_event); -} - -static VALUE -ip_get_eventloop_weight(self) - VALUE self; -{ - return get_eventloop_weight(self); -} - -static VALUE -set_max_block_time(self, time) - VALUE self; - VALUE time; -{ - struct Tcl_Time tcl_time; - VALUE divmod; - - switch(TYPE(time)) { - case T_FIXNUM: - case T_BIGNUM: - /* time is micro-second value */ - divmod = rb_funcall(time, rb_intern("divmod"), 1, LONG2NUM(1000000)); - tcl_time.sec = NUM2LONG(RARRAY_PTR(divmod)[0]); - tcl_time.usec = NUM2LONG(RARRAY_PTR(divmod)[1]); - break; - - case T_FLOAT: - /* time is second value */ - divmod = rb_funcall(time, rb_intern("divmod"), 1, INT2FIX(1)); - tcl_time.sec = NUM2LONG(RARRAY_PTR(divmod)[0]); - tcl_time.usec = (long)(NUM2DBL(RARRAY_PTR(divmod)[1]) * 1000000); - - default: - { - VALUE tmp = rb_funcall(time, ID_inspect, 0, 0); - rb_raise(rb_eArgError, "invalid value for time: '%s'", - StringValuePtr(tmp)); - } - } - - Tcl_SetMaxBlockTime(&tcl_time); - - return Qnil; -} - -static VALUE -lib_evloop_thread_p(self) - VALUE self; -{ - if (NIL_P(eventloop_thread)) { - return Qnil; /* no eventloop */ - } else if (rb_thread_current() == eventloop_thread) { - return Qtrue; /* is eventloop */ - } else { - return Qfalse; /* not eventloop */ - } -} - -static VALUE -lib_evloop_abort_on_exc(self) - VALUE self; -{ - if (event_loop_abort_on_exc > 0) { - return Qtrue; - } else if (event_loop_abort_on_exc == 0) { - return Qfalse; - } else { - return Qnil; - } -} - -static VALUE -ip_evloop_abort_on_exc(self) - VALUE self; -{ - return lib_evloop_abort_on_exc(self); -} - -static VALUE -lib_evloop_abort_on_exc_set(self, val) - VALUE self, val; -{ - rb_secure(4); - if (RTEST(val)) { - event_loop_abort_on_exc = 1; - } else if (NIL_P(val)) { - event_loop_abort_on_exc = -1; - } else { - event_loop_abort_on_exc = 0; - } - return lib_evloop_abort_on_exc(self); -} - -static VALUE -ip_evloop_abort_on_exc_set(self, val) - VALUE self, val; -{ - struct tcltkip *ptr = get_ip(self); - - rb_secure(4); - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - return lib_evloop_abort_on_exc(self); - } - - if (Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL) { - /* slave IP */ - return lib_evloop_abort_on_exc(self); - } - return lib_evloop_abort_on_exc_set(self, val); -} - -static VALUE -lib_num_of_mainwindows_core(self, argc, argv) - VALUE self; - int argc; /* dummy */ - VALUE *argv; /* dummy */ -{ - if (tk_stubs_init_p()) { - return INT2FIX(Tk_GetNumMainWindows()); - } else { - return INT2FIX(0); - } -} - -static VALUE -lib_num_of_mainwindows(self) - VALUE self; -{ -#ifdef RUBY_USE_NATIVE_THREAD /* Ruby 1.9+ !!! */ - return tk_funcall(lib_num_of_mainwindows_core, 0, (VALUE*)NULL, self); -#else - return lib_num_of_mainwindows_core(self, 0, (VALUE*)NULL); -#endif -} - - -#ifdef RUBY_USE_NATIVE_THREAD /* Ruby 1.9+ !!! */ -static VALUE -call_DoOneEvent_core(flag_val) - VALUE flag_val; -{ - int flag; - - flag = FIX2INT(flag_val); - if (Tcl_DoOneEvent(flag)) { - return Qtrue; - } else { - return Qfalse; - } -} - -static VALUE -call_DoOneEvent(flag_val) - VALUE flag_val; -{ - return tk_funcall(call_DoOneEvent_core, 0, (VALUE*)NULL, flag_val); -} - -#else /* Ruby 1.8- */ -static VALUE -call_DoOneEvent(flag_val) - VALUE flag_val; -{ - int flag; - - flag = FIX2INT(flag_val); - if (Tcl_DoOneEvent(flag)) { - return Qtrue; - } else { - return Qfalse; - } -} -#endif - - -static VALUE -eventloop_sleep(dummy) - VALUE dummy; -{ - struct timeval t; - - if (no_event_wait <= 0) { - return Qnil; - } - - t.tv_sec = (time_t)0; - t.tv_usec = (time_t)(no_event_wait*1000.0); - -#ifdef HAVE_NATIVETHREAD -#ifndef RUBY_USE_NATIVE_THREAD - if (!ruby_native_thread_p()) { - rb_bug("cross-thread violation on eventloop_sleep()"); - } -#endif -#endif - - DUMP2("eventloop_sleep: rb_thread_wait_for() at thread : %lx", rb_thread_current()); - rb_thread_wait_for(t); - DUMP2("eventloop_sleep: finish at thread : %lx", rb_thread_current()); - -#ifdef HAVE_NATIVETHREAD -#ifndef RUBY_USE_NATIVE_THREAD - if (!ruby_native_thread_p()) { - rb_bug("cross-thread violation on eventloop_sleep()"); - } -#endif -#endif - - return Qnil; -} - -#define USE_EVLOOP_THREAD_ALONE_CHECK_FLAG 0 - -#if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG -static int -get_thread_alone_check_flag() -{ -#ifdef RUBY_USE_NATIVE_THREAD - return 0; -#else - set_tcltk_version(); - - if (tcltk_version.major < 8) { - /* Tcl/Tk 7.x */ - return 1; - } else if (tcltk_version.major == 8) { - if (tcltk_version.minor < 5) { - /* Tcl/Tk 8.0 - 8.4 */ - return 1; - } else if (tcltk_version.minor == 5) { - if (tcltk_version.type < TCL_FINAL_RELEASE) { - /* Tcl/Tk 8.5a? - 8.5b? */ - return 1; - } else { - /* Tcl/Tk 8.5.x */ - return 0; - } - } else { - /* Tcl/Tk 8.6 - 8.9 ?? */ - return 0; - } - } else { - /* Tcl/Tk 9+ ?? */ - return 0; - } -#endif -} -#endif - -static int -lib_eventloop_core(check_root, update_flag, check_var, interp) - int check_root; - int update_flag; - int *check_var; - Tcl_Interp *interp; -{ - volatile VALUE current = eventloop_thread; - int found_event = 1; - int event_flag; - struct timeval t; - int thr_crit_bup; - int status; - int depth = rbtk_eventloop_depth; -#if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG - int thread_alone_check_flag = 1; -#endif - - if (update_flag) DUMP1("update loop start!!"); - - t.tv_sec = (time_t)0; - t.tv_usec = (time_t)(no_event_wait*1000.0); - - Tcl_DeleteTimerHandler(timer_token); - run_timer_flag = 0; - if (timer_tick > 0) { - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - timer_token = Tcl_CreateTimerHandler(timer_tick, _timer_for_tcl, - (ClientData)0); - rb_thread_critical = thr_crit_bup; - } else { - timer_token = (Tcl_TimerToken)NULL; - } - -#if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG - /* version check */ - thread_alone_check_flag = get_thread_alone_check_flag(); -#endif - - for(;;) { -#if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG - if (thread_alone_check_flag && rb_thread_alone()) { -#else - if (rb_thread_alone()) { -#endif - DUMP1("no other thread"); - event_loop_wait_event = 0; - - if (update_flag) { - event_flag = update_flag | TCL_DONT_WAIT; /* for safety */ - } else { - event_flag = TCL_ALL_EVENTS; - /* event_flag = TCL_ALL_EVENTS | TCL_DONT_WAIT; */ - } - - if (timer_tick == 0 && update_flag == 0) { - timer_tick = NO_THREAD_INTERRUPT_TIME; - timer_token = Tcl_CreateTimerHandler(timer_tick, - _timer_for_tcl, - (ClientData)0); - } - - if (check_var != (int *)NULL) { - if (*check_var || !found_event) { - return found_event; - } - if (interp != (Tcl_Interp*)NULL - && Tcl_InterpDeleted(interp)) { - /* IP for check_var is deleted */ - return 0; - } - } - - /* found_event = Tcl_DoOneEvent(event_flag); */ - found_event = RTEST(rb_protect(call_DoOneEvent, - INT2FIX(event_flag), &status)); - if (status) { - switch (status) { - case TAG_RAISE: - if (NIL_P(rb_errinfo())) { - rbtk_pending_exception - = rb_exc_new2(rb_eException, "unknown exception"); - } else { - rbtk_pending_exception = rb_errinfo(); - - if (!NIL_P(rbtk_pending_exception)) { - if (rbtk_eventloop_depth == 0) { - VALUE exc = rbtk_pending_exception; - rbtk_pending_exception = Qnil; - rb_exc_raise(exc); - } else { - return 0; - } - } - } - break; - - case TAG_FATAL: - if (NIL_P(rb_errinfo())) { - rb_exc_raise(rb_exc_new2(rb_eFatal, "FATAL")); - } else { - rb_exc_raise(rb_errinfo()); - } - } - } - - if (depth != rbtk_eventloop_depth) { - DUMP2("DoOneEvent(1) abnormal exit!! %d", - rbtk_eventloop_depth); - } - - if (check_var != (int*)NULL && !NIL_P(rbtk_pending_exception)) { - DUMP1("exception on wait"); - return 0; - } - - if (pending_exception_check0()) { - /* pending -> upper level */ - return 0; - } - - if (update_flag != 0) { - if (found_event) { - DUMP1("next update loop"); - continue; - } else { - DUMP1("update complete"); - return 0; - } - } - - DUMP1("trap check"); - if (rb_trap_pending) { - run_timer_flag = 0; - if (rb_prohibit_interrupt || check_var != (int*)NULL) { - /* pending or on wait command */ - return 0; - } else { - rb_trap_exec(); - } - } - - DUMP1("check Root Widget"); - if (check_root && tk_stubs_init_p() && Tk_GetNumMainWindows() == 0) { - run_timer_flag = 0; - if (rb_trap_pending) { - if (rb_prohibit_interrupt || check_var != (int*)NULL) { - /* pending or on wait command */ - return 0; - } else { - rb_trap_exec(); - } - } - return 1; - } - - if (loop_counter++ > 30000) { - /* fprintf(stderr, "loop_counter > 30000\n"); */ - loop_counter = 0; - } - - } else { - int tick_counter; - - DUMP1("there are other threads"); - event_loop_wait_event = 1; - - found_event = 1; - - if (update_flag) { - event_flag = update_flag | TCL_DONT_WAIT; /* for safety */ - } else { - event_flag = TCL_ALL_EVENTS | TCL_DONT_WAIT; - } - - timer_tick = req_timer_tick; - tick_counter = 0; - while(tick_counter < event_loop_max) { - if (check_var != (int *)NULL) { - if (*check_var || !found_event) { - return found_event; - } - if (interp != (Tcl_Interp*)NULL - && Tcl_InterpDeleted(interp)) { - /* IP for check_var is deleted */ - return 0; - } - } - - if (NIL_P(eventloop_thread) || current == eventloop_thread) { - int st; - int status; -#ifdef RUBY_USE_NATIVE_THREAD - if (update_flag) { - st = RTEST(rb_protect(call_DoOneEvent, - INT2FIX(event_flag), &status)); - } else { - st = RTEST(rb_protect(call_DoOneEvent, - INT2FIX(event_flag & window_event_mode), - &status)); -#if USE_TOGGLE_WINDOW_MODE_FOR_IDLE - if (!st) { - if (toggle_eventloop_window_mode_for_idle()) { - /* idle-mode -> event-mode*/ - tick_counter = event_loop_max; - } else { - /* event-mode -> idle-mode */ - tick_counter = 0; - } - } -#endif - } -#else - /* st = Tcl_DoOneEvent(event_flag); */ - st = RTEST(rb_protect(call_DoOneEvent, - INT2FIX(event_flag), &status)); -#endif - -#if CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE - if (have_rb_thread_waiting_for_value) { - have_rb_thread_waiting_for_value = 0; - rb_thread_schedule(); - } -#endif - - if (status) { - switch (status) { - case TAG_RAISE: - if (NIL_P(rb_errinfo())) { - rbtk_pending_exception - = rb_exc_new2(rb_eException, - "unknown exception"); - } else { - rbtk_pending_exception = rb_errinfo(); - - if (!NIL_P(rbtk_pending_exception)) { - if (rbtk_eventloop_depth == 0) { - VALUE exc = rbtk_pending_exception; - rbtk_pending_exception = Qnil; - rb_exc_raise(exc); - } else { - return 0; - } - } - } - break; - - case TAG_FATAL: - if (NIL_P(rb_errinfo())) { - rb_exc_raise(rb_exc_new2(rb_eFatal, "FATAL")); - } else { - rb_exc_raise(rb_errinfo()); - } - } - } - - if (depth != rbtk_eventloop_depth) { - DUMP2("DoOneEvent(2) abnormal exit!! %d", - rbtk_eventloop_depth); - return 0; - } - - DUMP1("trap check"); - if (rb_trap_pending) { - run_timer_flag = 0; - if (rb_prohibit_interrupt || check_var != (int*)NULL) { - /* pending or on wait command */ - return 0; - } else { - rb_trap_exec(); - } - } - - if (check_var != (int*)NULL - && !NIL_P(rbtk_pending_exception)) { - DUMP1("exception on wait"); - return 0; - } - - if (pending_exception_check0()) { - /* pending -> upper level */ - return 0; - } - - if (st) { - tick_counter++; - } else { - if (update_flag != 0) { - DUMP1("update complete"); - return 0; - } - - tick_counter += no_event_tick; - - /* rb_thread_wait_for(t); */ - - rb_protect(eventloop_sleep, Qnil, &status); - - if (status) { - switch (status) { - case TAG_RAISE: - if (NIL_P(rb_errinfo())) { - rbtk_pending_exception - = rb_exc_new2(rb_eException, - "unknown exception"); - } else { - rbtk_pending_exception = rb_errinfo(); - - if (!NIL_P(rbtk_pending_exception)) { - if (rbtk_eventloop_depth == 0) { - VALUE exc = rbtk_pending_exception; - rbtk_pending_exception = Qnil; - rb_exc_raise(exc); - } else { - return 0; - } - } - } - break; - - case TAG_FATAL: - if (NIL_P(rb_errinfo())) { - rb_exc_raise(rb_exc_new2(rb_eFatal, - "FATAL")); - } else { - rb_exc_raise(rb_errinfo()); - } - } - } - } - - } else { - DUMP2("sleep eventloop %lx", current); - DUMP2("eventloop thread is %lx", eventloop_thread); - /* rb_thread_stop(); */ - rb_thread_sleep_forever(); - } - - if (!NIL_P(watchdog_thread) && eventloop_thread != current) { - return 1; - } - - DUMP1("trap check"); - if (rb_trap_pending) { - run_timer_flag = 0; - if (rb_prohibit_interrupt || check_var != (int*)NULL) { - /* pending or on wait command */ - return 0; - } else { - rb_trap_exec(); - } - } - - DUMP1("check Root Widget"); - if (check_root && tk_stubs_init_p() && Tk_GetNumMainWindows() == 0) { - run_timer_flag = 0; - if (rb_trap_pending) { - if (rb_prohibit_interrupt || check_var != (int*)NULL) { - /* pending or on wait command */ - return 0; - } else { - rb_trap_exec(); - } - } - return 1; - } - - if (loop_counter++ > 30000) { - /* fprintf(stderr, "loop_counter > 30000\n"); */ - loop_counter = 0; - } - - if (run_timer_flag) { - /* - DUMP1("timer interrupt"); - run_timer_flag = 0; - */ - break; /* switch to other thread */ - } - } - - DUMP1("thread scheduling"); - rb_thread_schedule(); - } - - DUMP1("trap check & thread scheduling"); -#ifdef RUBY_USE_NATIVE_THREAD - /* if (update_flag == 0) CHECK_INTS; */ /*XXXXXXXXXXXXX TODO !!!! */ -#else - if (update_flag == 0) CHECK_INTS; -#endif - - } - return 1; -} - - -struct evloop_params { - int check_root; - int update_flag; - int *check_var; - Tcl_Interp *interp; - int thr_crit_bup; -}; - -VALUE -lib_eventloop_main_core(args) - VALUE args; -{ - struct evloop_params *params = (struct evloop_params *)args; - - check_rootwidget_flag = params->check_root; - - if (lib_eventloop_core(params->check_root, - params->update_flag, - params->check_var, - params->interp)) { - return Qtrue; - } else { - return Qfalse; - } -} - -VALUE -lib_eventloop_main(args) - VALUE args; -{ - return lib_eventloop_main_core(args); - -#if 0 - volatile VALUE ret; - int status = 0; - - ret = rb_protect(lib_eventloop_main_core, args, &status); - - switch (status) { - case TAG_RAISE: - if (NIL_P(rb_errinfo())) { - rbtk_pending_exception - = rb_exc_new2(rb_eException, "unknown exception"); - } else { - rbtk_pending_exception = rb_errinfo(); - } - return Qnil; - - case TAG_FATAL: - if (NIL_P(rb_errinfo())) { - rbtk_pending_exception = rb_exc_new2(rb_eFatal, "FATAL"); - } else { - rbtk_pending_exception = rb_errinfo(); - } - return Qnil; - } - - return ret; -#endif -} - -VALUE -lib_eventloop_ensure(args) - VALUE args; -{ - struct evloop_params *ptr = (struct evloop_params *)args; - volatile VALUE current_evloop = rb_thread_current(); - - DUMP2("eventloop_ensure: current-thread : %lx", current_evloop); - DUMP2("eventloop_ensure: eventloop-thread : %lx", eventloop_thread); - if (eventloop_thread != current_evloop) { - DUMP2("finish eventloop %lx (NOT current eventloop)", current_evloop); - - rb_thread_critical = ptr->thr_crit_bup; - - free(ptr); - /* ckfree((char*)ptr); */ - - return Qnil; - } - - while((eventloop_thread = rb_ary_pop(eventloop_stack))) { - DUMP2("eventloop-ensure: new eventloop-thread -> %lx", - eventloop_thread); - - if (eventloop_thread == current_evloop) { - rbtk_eventloop_depth--; - DUMP2("eventloop %lx : back from recursive call", current_evloop); - break; - } - - if (NIL_P(eventloop_thread)) { - Tcl_DeleteTimerHandler(timer_token); - timer_token = (Tcl_TimerToken)NULL; - - break; - } - -#ifdef RUBY_VM - if (RTEST(rb_funcall(eventloop_thread, ID_alive_p, 0, 0))) { -#else - if (RTEST(rb_thread_alive_p(eventloop_thread))) { -#endif - DUMP2("eventloop-enshure: wake up parent %lx", eventloop_thread); - rb_thread_wakeup(eventloop_thread); - - break; - } - } - -#ifdef RUBY_USE_NATIVE_THREAD - if (NIL_P(eventloop_thread)) { - tk_eventloop_thread_id = (Tcl_ThreadId) 0; - } -#endif - - rb_thread_critical = ptr->thr_crit_bup; - - free(ptr); - /* ckfree((char*)ptr);*/ - - DUMP2("finish current eventloop %lx", current_evloop); - return Qnil; -} - -static VALUE -lib_eventloop_launcher(check_root, update_flag, check_var, interp) - int check_root; - int update_flag; - int *check_var; - Tcl_Interp *interp; -{ - volatile VALUE parent_evloop = eventloop_thread; - struct evloop_params *args = ALLOC(struct evloop_params); - /* struct evloop_params *args = (struct evloop_params *)ckalloc(sizeof(struct evloop_params)); */ - - tcl_stubs_check(); - - eventloop_thread = rb_thread_current(); -#ifdef RUBY_USE_NATIVE_THREAD - tk_eventloop_thread_id = Tcl_GetCurrentThread(); -#endif - - if (parent_evloop == eventloop_thread) { - DUMP2("eventloop: recursive call on %lx", parent_evloop); - rbtk_eventloop_depth++; - } - - if (!NIL_P(parent_evloop) && parent_evloop != eventloop_thread) { - DUMP2("wait for stop of parent_evloop %lx", parent_evloop); - while(!RTEST(rb_funcall(parent_evloop, ID_stop_p, 0))) { - DUMP2("parent_evloop %lx doesn't stop", parent_evloop); - rb_thread_run(parent_evloop); - } - DUMP1("succeed to stop parent"); - } - - rb_ary_push(eventloop_stack, parent_evloop); - - DUMP3("tcltklib: eventloop-thread : %lx -> %lx\n", - parent_evloop, eventloop_thread); - - args->check_root = check_root; - args->update_flag = update_flag; - args->check_var = check_var; - args->interp = interp; - args->thr_crit_bup = rb_thread_critical; - - rb_thread_critical = Qfalse; - -#if 0 - return rb_ensure(lib_eventloop_main, (VALUE)args, - lib_eventloop_ensure, (VALUE)args); -#endif - return rb_ensure(lib_eventloop_main_core, (VALUE)args, - lib_eventloop_ensure, (VALUE)args); -} - -/* execute Tk_MainLoop */ -static VALUE -lib_mainloop(argc, argv, self) - int argc; - VALUE *argv; - VALUE self; -{ - VALUE check_rootwidget; - - if (rb_scan_args(argc, argv, "01", &check_rootwidget) == 0) { - check_rootwidget = Qtrue; - } else if (RTEST(check_rootwidget)) { - check_rootwidget = Qtrue; - } else { - check_rootwidget = Qfalse; - } - - return lib_eventloop_launcher(RTEST(check_rootwidget), 0, - (int*)NULL, (Tcl_Interp*)NULL); -} - -static VALUE -ip_mainloop(argc, argv, self) - int argc; - VALUE *argv; - VALUE self; -{ - struct tcltkip *ptr = get_ip(self); - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - return Qnil; - } - - if (Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL) { - /* slave IP */ - return Qnil; - } - return lib_mainloop(argc, argv, self); -} - - -static VALUE -watchdog_evloop_launcher(check_rootwidget) - VALUE check_rootwidget; -{ - return lib_eventloop_launcher(RTEST(check_rootwidget), 0, - (int*)NULL, (Tcl_Interp*)NULL); -} - -#define EVLOOP_WAKEUP_CHANCE 3 - -static VALUE -lib_watchdog_core(check_rootwidget) - VALUE check_rootwidget; -{ - VALUE evloop; - int prev_val = -1; - int chance = 0; - int check = RTEST(check_rootwidget); - struct timeval t0, t1; - - t0.tv_sec = (time_t)0; - t0.tv_usec = (time_t)((NO_THREAD_INTERRUPT_TIME)*1000.0); - t1.tv_sec = (time_t)0; - t1.tv_usec = (time_t)((WATCHDOG_INTERVAL)*1000.0); - - /* check other watchdog thread */ - if (!NIL_P(watchdog_thread)) { - if (RTEST(rb_funcall(watchdog_thread, ID_stop_p, 0))) { - rb_funcall(watchdog_thread, ID_kill, 0); - } else { - return Qnil; - } - } - watchdog_thread = rb_thread_current(); - - /* watchdog start */ - do { - if (NIL_P(eventloop_thread) - || (loop_counter == prev_val && chance >= EVLOOP_WAKEUP_CHANCE)) { - /* start new eventloop thread */ - DUMP2("eventloop thread %lx is sleeping or dead", - eventloop_thread); - evloop = rb_thread_create(watchdog_evloop_launcher, - (void*)&check_rootwidget); - DUMP2("create new eventloop thread %lx", evloop); - loop_counter = -1; - chance = 0; - rb_thread_run(evloop); - } else { - prev_val = loop_counter; - if (RTEST(rb_funcall(eventloop_thread, ID_stop_p, 0))) { - ++chance; - } else { - chance = 0; - } - if (event_loop_wait_event) { - rb_thread_wait_for(t0); - } else { - rb_thread_wait_for(t1); - } - /* rb_thread_schedule(); */ - } - } while(!check || !tk_stubs_init_p() || Tk_GetNumMainWindows() != 0); - - return Qnil; -} - -VALUE -lib_watchdog_ensure(arg) - VALUE arg; -{ - eventloop_thread = Qnil; /* stop eventloops */ -#ifdef RUBY_USE_NATIVE_THREAD - tk_eventloop_thread_id = (Tcl_ThreadId) 0; -#endif - return Qnil; -} - -static VALUE -lib_mainloop_watchdog(argc, argv, self) - int argc; - VALUE *argv; - VALUE self; -{ - VALUE check_rootwidget; - -#ifdef RUBY_USE_NATIVE_THREAD - rb_raise(rb_eNotImpError, - "eventloop_watchdog is not implemented on Ruby VM."); -#endif - - if (rb_scan_args(argc, argv, "01", &check_rootwidget) == 0) { - check_rootwidget = Qtrue; - } else if (RTEST(check_rootwidget)) { - check_rootwidget = Qtrue; - } else { - check_rootwidget = Qfalse; - } - - return rb_ensure(lib_watchdog_core, check_rootwidget, - lib_watchdog_ensure, Qnil); -} - -static VALUE -ip_mainloop_watchdog(argc, argv, self) - int argc; - VALUE *argv; - VALUE self; -{ - struct tcltkip *ptr = get_ip(self); - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - return Qnil; - } - - if (Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL) { - /* slave IP */ - return Qnil; - } - return lib_mainloop_watchdog(argc, argv, self); -} - - -/* thread-safe(?) interaction between Ruby and Tk */ -struct thread_call_proc_arg { - VALUE proc; - int *done; -}; - -void -_thread_call_proc_arg_mark(struct thread_call_proc_arg *q) -{ - rb_gc_mark(q->proc); -} - -static VALUE -_thread_call_proc_core(arg) - VALUE arg; -{ - struct thread_call_proc_arg *q = (struct thread_call_proc_arg*)arg; - return rb_funcall(q->proc, ID_call, 0); -} - -static VALUE -_thread_call_proc_ensure(arg) - VALUE arg; -{ - struct thread_call_proc_arg *q = (struct thread_call_proc_arg*)arg; - *(q->done) = 1; - return Qnil; -} - -static VALUE -_thread_call_proc(arg) - VALUE arg; -{ - struct thread_call_proc_arg *q = (struct thread_call_proc_arg*)arg; - - return rb_ensure(_thread_call_proc_core, (VALUE)q, - _thread_call_proc_ensure, (VALUE)q); -} - -static VALUE -_thread_call_proc_value(th) - VALUE th; -{ - return rb_funcall(th, ID_value, 0); -} - -static VALUE -lib_thread_callback(argc, argv, self) - int argc; - VALUE *argv; - VALUE self; -{ - struct thread_call_proc_arg *q; - VALUE proc, th, ret; - int status, foundEvent; - - if (rb_scan_args(argc, argv, "01", &proc) == 0) { - proc = rb_block_proc(); - } - - q = (struct thread_call_proc_arg *)ALLOC(struct thread_call_proc_arg); - /* q = (struct thread_call_proc_arg *)ckalloc(sizeof(struct thread_call_proc_arg)); */ - q->proc = proc; - q->done = (int*)ALLOC(int); - /* q->done = (int*)ckalloc(sizeof(int)); */ - *(q->done) = 0; - - /* create call-proc thread */ - th = rb_thread_create(_thread_call_proc, (void*)q); - - rb_thread_schedule(); - - /* start sub-eventloop */ - foundEvent = RTEST(lib_eventloop_launcher(/* not check root-widget */0, 0, - q->done, (Tcl_Interp*)NULL)); - -#ifdef RUBY_VM - if (RTEST(rb_funcall(th, ID_alive_p, 0))) { -#else - if (RTEST(rb_thread_alive_p(th))) { -#endif - rb_funcall(th, ID_kill, 0); - ret = Qnil; - } else { - ret = rb_protect(_thread_call_proc_value, th, &status); - } - - free(q->done); - free(q); - /* ckfree((char*)q->done); */ - /* ckfree((char*)q); */ - - if (NIL_P(rbtk_pending_exception)) { - /* return rb_errinfo(); */ - if (status) { - rb_exc_raise(rb_errinfo()); - } - } else { - VALUE exc = rbtk_pending_exception; - rbtk_pending_exception = Qnil; - /* return exc; */ - rb_exc_raise(exc); - } - - return ret; -} - - -/* do_one_event */ -static VALUE -lib_do_one_event_core(argc, argv, self, is_ip) - int argc; - VALUE *argv; - VALUE self; - int is_ip; -{ - volatile VALUE vflags; - int flags; - int found_event; - - if (!NIL_P(eventloop_thread)) { - rb_raise(rb_eRuntimeError, "eventloop is already running"); - } - - tcl_stubs_check(); - - if (rb_scan_args(argc, argv, "01", &vflags) == 0) { - flags = TCL_ALL_EVENTS | TCL_DONT_WAIT; - } else { - Check_Type(vflags, T_FIXNUM); - flags = FIX2INT(vflags); - } - - if (rb_safe_level() >= 4 || (rb_safe_level() >=1 && OBJ_TAINTED(vflags))) { - flags |= TCL_DONT_WAIT; - } - - if (is_ip) { - /* check IP */ - struct tcltkip *ptr = get_ip(self); - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - return Qfalse; - } - - if (Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL) { - /* slave IP */ - flags |= TCL_DONT_WAIT; - } - } - - /* found_event = Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT); */ - found_event = Tcl_DoOneEvent(flags); - - if (pending_exception_check0()) { - return Qfalse; - } - - if (found_event) { - return Qtrue; - } else { - return Qfalse; - } -} - -static VALUE -lib_do_one_event(argc, argv, self) - int argc; - VALUE *argv; - VALUE self; -{ - return lib_do_one_event_core(argc, argv, self, 0); -} - -static VALUE -ip_do_one_event(argc, argv, self) - int argc; - VALUE *argv; - VALUE self; -{ - return lib_do_one_event_core(argc, argv, self, 0); -} - - -static void -ip_set_exc_message(interp, exc) - Tcl_Interp *interp; - VALUE exc; -{ - char *buf; - Tcl_DString dstr; - volatile VALUE msg; - int thr_crit_bup; - -#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION > 0) - volatile VALUE enc; - Tcl_Encoding encoding; -#endif - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - msg = rb_funcall(exc, ID_message, 0, 0); - StringValue(msg); - -#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION > 0) - enc = rb_attr_get(exc, ID_at_enc); - if (NIL_P(enc)) { - enc = rb_attr_get(msg, ID_at_enc); - } - if (NIL_P(enc)) { - encoding = (Tcl_Encoding)NULL; - } else if (TYPE(enc) == T_STRING) { - /* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); */ - encoding = Tcl_GetEncoding((Tcl_Interp*)NULL, RSTRING_PTR(enc)); - } else { - enc = rb_funcall(enc, ID_to_s, 0, 0); - /* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); */ - encoding = Tcl_GetEncoding((Tcl_Interp*)NULL, RSTRING_PTR(enc)); - } - - /* to avoid a garbled error message dialog */ - /* buf = ALLOC_N(char, (RSTRING(msg)->len)+1);*/ - /* memcpy(buf, RSTRING(msg)->ptr, RSTRING(msg)->len);*/ - /* buf[RSTRING(msg)->len] = 0; */ - buf = ALLOC_N(char, RSTRING_LEN(msg)+1); - /* buf = ckalloc(sizeof(char)*((RSTRING_LEN(msg))+1)); */ - memcpy(buf, RSTRING_PTR(msg), RSTRING_LEN(msg)); - buf[RSTRING_LEN(msg)] = 0; - - Tcl_DStringInit(&dstr); - Tcl_DStringFree(&dstr); - Tcl_ExternalToUtfDString(encoding, buf, RSTRING_LEN(msg), &dstr); - - Tcl_AppendResult(interp, Tcl_DStringValue(&dstr), (char*)NULL); - DUMP2("error message:%s", Tcl_DStringValue(&dstr)); - Tcl_DStringFree(&dstr); - free(buf); - /* ckfree(buf); */ - -#else /* TCL_VERSION <= 8.0 */ - Tcl_AppendResult(interp, RSTRING_PTR(msg), (char*)NULL); -#endif - - rb_thread_critical = thr_crit_bup; -} - -static VALUE -TkStringValue(obj) - VALUE obj; -{ - switch(TYPE(obj)) { - case T_STRING: - return obj; - - case T_NIL: - return rb_str_new2(""); - - case T_TRUE: - return rb_str_new2("1"); - - case T_FALSE: - return rb_str_new2("0"); - - case T_ARRAY: - return rb_funcall(obj, ID_join, 1, rb_str_new2(" ")); - - default: - if (rb_respond_to(obj, ID_to_s)) { - return rb_funcall(obj, ID_to_s, 0, 0); - } - } - - return rb_funcall(obj, ID_inspect, 0, 0); -} - -static int -tcl_protect_core(interp, proc, data) /* should not raise exception */ - Tcl_Interp *interp; - VALUE (*proc)(); - VALUE data; -{ - volatile VALUE ret, exc = Qnil; - int status = 0; - int thr_crit_bup = rb_thread_critical; - - Tcl_ResetResult(interp); - - rb_thread_critical = Qfalse; - ret = rb_protect(proc, data, &status); - rb_thread_critical = Qtrue; - if (status) { - char *buf; - VALUE old_gc; - volatile VALUE type, str; - - old_gc = rb_gc_disable(); - - switch(status) { - case TAG_RETURN: - type = eTkCallbackReturn; - goto error; - case TAG_BREAK: - type = eTkCallbackBreak; - goto error; - case TAG_NEXT: - type = eTkCallbackContinue; - goto error; - error: - str = rb_str_new2("LocalJumpError: "); - rb_str_append(str, rb_obj_as_string(rb_errinfo())); - exc = rb_exc_new3(type, str); - break; - - case TAG_RETRY: - if (NIL_P(rb_errinfo())) { - DUMP1("rb_protect: retry"); - exc = rb_exc_new2(eTkCallbackRetry, "retry jump error"); - } else { - exc = rb_errinfo(); - } - break; - - case TAG_REDO: - if (NIL_P(rb_errinfo())) { - DUMP1("rb_protect: redo"); - exc = rb_exc_new2(eTkCallbackRedo, "redo jump error"); - } else { - exc = rb_errinfo(); - } - break; - - case TAG_RAISE: - if (NIL_P(rb_errinfo())) { - exc = rb_exc_new2(rb_eException, "unknown exception"); - } else { - exc = rb_errinfo(); - } - break; - - case TAG_FATAL: - if (NIL_P(rb_errinfo())) { - exc = rb_exc_new2(rb_eFatal, "FATAL"); - } else { - exc = rb_errinfo(); - } - break; - - case TAG_THROW: - if (NIL_P(rb_errinfo())) { - DUMP1("rb_protect: throw"); - exc = rb_exc_new2(eTkCallbackThrow, "throw jump error"); - } else { - exc = rb_errinfo(); - } - break; - - default: - buf = ALLOC_N(char, 256); - /* buf = ckalloc(sizeof(char) * 256); */ - sprintf(buf, "unknown loncaljmp status %d", status); - exc = rb_exc_new2(rb_eException, buf); - free(buf); - /* ckfree(buf); */ - break; - } - - if (old_gc == Qfalse) rb_gc_enable(); - - ret = Qnil; - } - - rb_thread_critical = thr_crit_bup; - - Tcl_ResetResult(interp); - - /* status check */ - if (!NIL_P(exc)) { - volatile VALUE eclass = rb_obj_class(exc); - volatile VALUE backtrace; - - DUMP1("(failed)"); - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - DUMP1("set backtrace"); - if (!NIL_P(backtrace = rb_funcall(exc, ID_backtrace, 0, 0))) { - backtrace = rb_ary_join(backtrace, rb_str_new2("\n")); - Tcl_AddErrorInfo(interp, StringValuePtr(backtrace)); - } - - rb_thread_critical = thr_crit_bup; - - ip_set_exc_message(interp, exc); - - if (eclass == eTkCallbackReturn) - return TCL_RETURN; - - if (eclass == eTkCallbackBreak) - return TCL_BREAK; - - if (eclass == eTkCallbackContinue) - return TCL_CONTINUE; - - if (eclass == rb_eSystemExit || eclass == rb_eInterrupt) { - rbtk_pending_exception = exc; - return TCL_RETURN; - } - - if (rb_obj_is_kind_of(exc, eTkLocalJumpError)) { - rbtk_pending_exception = exc; - return TCL_ERROR; - } - - if (rb_obj_is_kind_of(exc, eLocalJumpError)) { - VALUE reason = rb_ivar_get(exc, ID_at_reason); - - if (TYPE(reason) == T_SYMBOL) { - if (SYM2ID(reason) == ID_return) - return TCL_RETURN; - - if (SYM2ID(reason) == ID_break) - return TCL_BREAK; - - if (SYM2ID(reason) == ID_next) - return TCL_CONTINUE; - } - } - - return TCL_ERROR; - } - - /* result must be string or nil */ - if (!NIL_P(ret)) { - /* copy result to the tcl interpreter */ - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - ret = TkStringValue(ret); - DUMP1("Tcl_AppendResult"); - Tcl_AppendResult(interp, RSTRING_PTR(ret), (char *)NULL); - - rb_thread_critical = thr_crit_bup; - } - - DUMP2("(result) %s", NIL_P(ret) ? "nil" : RSTRING_PTR(ret)); - - return TCL_OK; -} - -static int -tcl_protect(interp, proc, data) - Tcl_Interp *interp; - VALUE (*proc)(); - VALUE data; -{ - int old_trapflag = rb_trap_immediate; - int code; - -#ifdef HAVE_NATIVETHREAD -#ifndef RUBY_USE_NATIVE_THREAD - if (!ruby_native_thread_p()) { - rb_bug("cross-thread violation on tcl_protect()"); - } -#endif -#endif - - rb_trap_immediate = 0; - code = tcl_protect_core(interp, proc, data); - rb_trap_immediate = old_trapflag; - - return code; -} - -static int -#if TCL_MAJOR_VERSION >= 8 -ip_ruby_eval(clientData, interp, argc, argv) - ClientData clientData; - Tcl_Interp *interp; - int argc; - Tcl_Obj *CONST argv[]; -#else /* TCL_MAJOR_VERSION < 8 */ -ip_ruby_eval(clientData, interp, argc, argv) - ClientData clientData; - Tcl_Interp *interp; - int argc; - char *argv[]; -#endif -{ - char *arg; - int thr_crit_bup; - int code; - - if (interp == (Tcl_Interp*)NULL) { - rbtk_pending_exception = rb_exc_new2(rb_eRuntimeError, - "IP is deleted"); - return TCL_ERROR; - } - - /* ruby command has 1 arg. */ - if (argc != 2) { -#if 0 - rb_raise(rb_eArgError, - "wrong number of arguments (%d for 1)", argc - 1); -#else - char buf[sizeof(int)*8 + 1]; - Tcl_ResetResult(interp); - sprintf(buf, "%d", argc-1); - Tcl_AppendResult(interp, "wrong number of arguments (", - buf, " for 1)", (char *)NULL); - rbtk_pending_exception = rb_exc_new2(rb_eArgError, - Tcl_GetStringResult(interp)); - return TCL_ERROR; -#endif - } - - /* get C string from Tcl object */ -#if TCL_MAJOR_VERSION >= 8 - { - char *str; - int len; - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - str = Tcl_GetStringFromObj(argv[1], &len); - arg = ALLOC_N(char, len + 1); - /* arg = ckalloc(sizeof(char) * (len + 1)); */ - memcpy(arg, str, len); - arg[len] = 0; - - rb_thread_critical = thr_crit_bup; - - } -#else /* TCL_MAJOR_VERSION < 8 */ - arg = argv[1]; -#endif - - /* evaluate the argument string by ruby */ - DUMP2("rb_eval_string(%s)", arg); - - code = tcl_protect(interp, rb_eval_string, (VALUE)arg); - -#if TCL_MAJOR_VERSION >= 8 - free(arg); - /* ckfree(arg); */ -#endif - - return code; -} - - -/* Tcl command `ruby_cmd' */ -static VALUE -ip_ruby_cmd_core(arg) - struct cmd_body_arg *arg; -{ - volatile VALUE ret; - int thr_crit_bup; - - DUMP1("call ip_ruby_cmd_core"); - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qfalse; - ret = rb_apply(arg->receiver, arg->method, arg->args); - rb_thread_critical = thr_crit_bup; - DUMP1("finish ip_ruby_cmd_core"); - - return ret; -} - -#define SUPPORT_NESTED_CONST_AS_IP_RUBY_CMD_RECEIVER 1 - -static VALUE -ip_ruby_cmd_receiver_const_get(name) - char *name; -{ - volatile VALUE klass = rb_cObject; -#if 0 - char *head, *tail; -#endif - int state; - -#if SUPPORT_NESTED_CONST_AS_IP_RUBY_CMD_RECEIVER - klass = rb_eval_string_protect(name, &state); - if (state) { - return Qnil; - } else { - return klass; - } -#else - return rb_const_get(klass, rb_intern(name)); -#endif - - /* TODO!!!!!! */ - /* support nest of classes/modules */ - - /* return rb_eval_string(name); */ - /* return rb_eval_string_protect(name, &state); */ - -#if 0 /* doesn't work!! (fail to autoload?) */ - /* duplicate */ - head = name = strdup(name); - - /* has '::' at head ? */ - if (*head == ':') head += 2; - tail = head; - - /* search */ - while(*tail) { - if (*tail == ':') { - *tail = '\0'; - klass = rb_const_get(klass, rb_intern(head)); - tail += 2; - head = tail; - } else { - tail++; - } - } - - free(name); - return rb_const_get(klass, rb_intern(head)); -#endif -} - -static VALUE -ip_ruby_cmd_receiver_get(str) - char *str; -{ - volatile VALUE receiver; -#if !SUPPORT_NESTED_CONST_AS_IP_RUBY_CMD_RECEIVER - int state; -#endif - - if (str[0] == ':' || ('A' <= str[0] && str[0] <= 'Z')) { - /* class | module | constant */ -#if SUPPORT_NESTED_CONST_AS_IP_RUBY_CMD_RECEIVER - receiver = ip_ruby_cmd_receiver_const_get(str); -#else - receiver = rb_protect(ip_ruby_cmd_receiver_const_get, (VALUE)str, &state); - if (state) return Qnil; -#endif - } else if (str[0] == '$') { - /* global variable */ - receiver = rb_gv_get(str); - } else { - /* global variable omitted '$' */ - char *buf; - int len; - - len = strlen(str); - buf = ALLOC_N(char, len + 2); - /* buf = ckalloc(sizeof(char) * (len + 2)); */ - buf[0] = '$'; - memcpy(buf + 1, str, len); - buf[len + 1] = 0; - receiver = rb_gv_get(buf); - free(buf); - /* ckfree(buf); */ - } - - return receiver; -} - -/* ruby_cmd receiver method arg ... */ -static int -#if TCL_MAJOR_VERSION >= 8 -ip_ruby_cmd(clientData, interp, argc, argv) - ClientData clientData; - Tcl_Interp *interp; - int argc; - Tcl_Obj *CONST argv[]; -#else /* TCL_MAJOR_VERSION < 8 */ -ip_ruby_cmd(clientData, interp, argc, argv) - ClientData clientData; - Tcl_Interp *interp; - int argc; - char *argv[]; -#endif -{ - volatile VALUE receiver; - volatile ID method; - volatile VALUE args; - char *str; - int i; - int len; - struct cmd_body_arg *arg; - int thr_crit_bup; - VALUE old_gc; - int code; - - if (interp == (Tcl_Interp*)NULL) { - rbtk_pending_exception = rb_exc_new2(rb_eRuntimeError, - "IP is deleted"); - return TCL_ERROR; - } - - if (argc < 3) { -#if 0 - rb_raise(rb_eArgError, "too few arguments"); -#else - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "too few arguments", (char *)NULL); - rbtk_pending_exception = rb_exc_new2(rb_eArgError, - Tcl_GetStringResult(interp)); - return TCL_ERROR; -#endif - } - - /* get arguments from Tcl objects */ - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - old_gc = rb_gc_disable(); - - /* get receiver */ -#if TCL_MAJOR_VERSION >= 8 - str = Tcl_GetStringFromObj(argv[1], &len); -#else /* TCL_MAJOR_VERSION < 8 */ - str = argv[1]; -#endif - DUMP2("receiver:%s",str); - /* receiver = rb_protect(ip_ruby_cmd_receiver_get, (VALUE)str, &code); */ - receiver = ip_ruby_cmd_receiver_get(str); - if (NIL_P(receiver)) { -#if 0 - rb_raise(rb_eArgError, - "unknown class/module/global-variable '%s'", str); -#else - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "unknown class/module/global-variable '", - str, "'", (char *)NULL); - rbtk_pending_exception = rb_exc_new2(rb_eArgError, - Tcl_GetStringResult(interp)); - if (old_gc == Qfalse) rb_gc_enable(); - return TCL_ERROR; -#endif - } - - /* get metrhod */ -#if TCL_MAJOR_VERSION >= 8 - str = Tcl_GetStringFromObj(argv[2], &len); -#else /* TCL_MAJOR_VERSION < 8 */ - str = argv[2]; -#endif - method = rb_intern(str); - - /* get args */ - args = rb_ary_new2(argc - 2); -#ifdef HAVE_STRUCT_RARRAY_LEN - RARRAY(args)->len = 0; -#endif - for(i = 3; i < argc; i++) { -#if TCL_MAJOR_VERSION >= 8 - str = Tcl_GetStringFromObj(argv[i], &len); - DUMP2("arg:%s",str); -#ifndef HAVE_STRUCT_RARRAY_LEN - rb_ary_push(args, rb_tainted_str_new(str, len)); -#else - RARRAY(args)->ptr[RARRAY(args)->len++] = rb_tainted_str_new(str, len); -#endif -#else /* TCL_MAJOR_VERSION < 8 */ - DUMP2("arg:%s",argv[i]); -#ifndef HAVE_STRUCT_RARRAY_LEN - rb_ary_push(args, rb_tainted_str_new2(argv[i])); -#else - RARRAY(args)->ptr[RARRAY(args)->len++] = rb_tainted_str_new2(argv[i]); -#endif -#endif - } - - if (old_gc == Qfalse) rb_gc_enable(); - rb_thread_critical = thr_crit_bup; - - /* allocate */ - arg = ALLOC(struct cmd_body_arg); - /* arg = (struct cmd_body_arg *)ckalloc(sizeof(struct cmd_body_arg)); */ - - arg->receiver = receiver; - arg->method = method; - arg->args = args; - - /* evaluate the argument string by ruby */ - code = tcl_protect(interp, ip_ruby_cmd_core, (VALUE)arg); - - free(arg); - /* ckfree((char*)arg); */ - - return code; -} - - -/*****************************/ -/* relpace of 'exit' command */ -/*****************************/ -static int -#if TCL_MAJOR_VERSION >= 8 -ip_InterpExitObjCmd(clientData, interp, argc, argv) - ClientData clientData; - Tcl_Interp *interp; - int argc; - Tcl_Obj *CONST argv[]; -#else /* TCL_MAJOR_VERSION < 8 */ -ip_InterpExitCommand(clientData, interp, argc, argv) - ClientData clientData; - Tcl_Interp *interp; - int argc; - char *argv[]; -#endif -{ - DUMP1("start ip_InterpExitCommand"); - if (interp != (Tcl_Interp*)NULL - && !Tcl_InterpDeleted(interp) -#if TCL_NAMESPACE_DEBUG - && !ip_null_namespace(interp) -#endif - ) { - Tcl_ResetResult(interp); - /* Tcl_Preserve(interp); */ - /* Tcl_Eval(interp, "interp eval {} {destroy .}; interp delete {}"); */ - ip_finalize(interp); - Tcl_DeleteInterp(interp); - Tcl_Release(interp); - } - return TCL_OK; -} - -static int -#if TCL_MAJOR_VERSION >= 8 -ip_RubyExitObjCmd(clientData, interp, argc, argv) - ClientData clientData; - Tcl_Interp *interp; - int argc; - Tcl_Obj *CONST argv[]; -#else /* TCL_MAJOR_VERSION < 8 */ -ip_RubyExitCommand(clientData, interp, argc, argv) - ClientData clientData; - Tcl_Interp *interp; - int argc; - char *argv[]; -#endif -{ - int state; - char *cmd, *param; -#if TCL_MAJOR_VERSION < 8 - char *endptr; - cmd = argv[0]; -#endif - - DUMP1("start ip_RubyExitCommand"); - -#if TCL_MAJOR_VERSION >= 8 - /* cmd = Tcl_GetString(argv[0]); */ - cmd = Tcl_GetStringFromObj(argv[0], (int*)NULL); -#endif - - if (argc < 1 || argc > 2) { - /* arguemnt error */ - Tcl_AppendResult(interp, - "wrong number of arguments: should be \"", - cmd, " ?returnCode?\"", (char *)NULL); - return TCL_ERROR; - } - - if (interp == (Tcl_Interp*)NULL) return TCL_OK; - - Tcl_ResetResult(interp); - - if (rb_safe_level() >= 4 || Tcl_IsSafe(interp)) { - ip_finalize(interp); - Tcl_DeleteInterp(interp); - Tcl_Release(interp); - return TCL_OK; - } - - switch(argc) { - case 1: - /* rb_exit(0); */ /* not return if succeed */ - Tcl_AppendResult(interp, - "fail to call \"", cmd, "\"", (char *)NULL); - - rbtk_pending_exception = rb_exc_new2(rb_eSystemExit, - Tcl_GetStringResult(interp)); - rb_iv_set(rbtk_pending_exception, "status", INT2FIX(0)); - - return TCL_RETURN; - - case 2: -#if TCL_MAJOR_VERSION >= 8 - if (Tcl_GetIntFromObj(interp, argv[1], &state) == TCL_ERROR) { - return TCL_ERROR; - } - /* param = Tcl_GetString(argv[1]); */ - param = Tcl_GetStringFromObj(argv[1], (int*)NULL); -#else /* TCL_MAJOR_VERSION < 8 */ - state = (int)strtol(argv[1], &endptr, 0); - if (*endptr) { - Tcl_AppendResult(interp, - "expected integer but got \"", - argv[1], "\"", (char *)NULL); - return TCL_ERROR; - } - param = argv[1]; -#endif - /* rb_exit(state); */ /* not return if succeed */ - - Tcl_AppendResult(interp, "fail to call \"", cmd, " ", - param, "\"", (char *)NULL); - - rbtk_pending_exception = rb_exc_new2(rb_eSystemExit, - Tcl_GetStringResult(interp)); - rb_iv_set(rbtk_pending_exception, "status", INT2FIX(state)); - - return TCL_RETURN; - - default: - /* arguemnt error */ - Tcl_AppendResult(interp, - "wrong number of arguments: should be \"", - cmd, " ?returnCode?\"", (char *)NULL); - return TCL_ERROR; - } -} - - -/**************************/ -/* based on tclEvent.c */ -/**************************/ - -/*********************/ -/* replace of update */ -/*********************/ -#if TCL_MAJOR_VERSION >= 8 -static int ip_rbUpdateObjCmd _((ClientData, Tcl_Interp *, int, - Tcl_Obj *CONST [])); -static int -ip_rbUpdateObjCmd(clientData, interp, objc, objv) - ClientData clientData; - Tcl_Interp *interp; - int objc; - Tcl_Obj *CONST objv[]; -#else /* TCL_MAJOR_VERSION < 8 */ -static int ip_rbUpdateCommand _((ClientData, Tcl_Interp *, int, char *[])); -static int -ip_rbUpdateCommand(clientData, interp, objc, objv) - ClientData clientData; - Tcl_Interp *interp; - int objc; - char *objv[]; -#endif -{ - int optionIndex; - int ret; - int flags = 0; - static CONST char *updateOptions[] = {"idletasks", (char *) NULL}; - enum updateOptions {REGEXP_IDLETASKS}; - - DUMP1("Ruby's 'update' is called"); - if (interp == (Tcl_Interp*)NULL) { - rbtk_pending_exception = rb_exc_new2(rb_eRuntimeError, - "IP is deleted"); - return TCL_ERROR; - } -#ifdef HAVE_NATIVETHREAD -#ifndef RUBY_USE_NATIVE_THREAD - if (!ruby_native_thread_p()) { - rb_bug("cross-thread violation on ip_ruby_eval()"); - } -#endif -#endif - - Tcl_ResetResult(interp); - - if (objc == 1) { - flags = TCL_DONT_WAIT; - - } else if (objc == 2) { -#if TCL_MAJOR_VERSION >= 8 - if (Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)updateOptions, - "option", 0, &optionIndex) != TCL_OK) { - return TCL_ERROR; - } - switch ((enum updateOptions) optionIndex) { - case REGEXP_IDLETASKS: { - flags = TCL_IDLE_EVENTS; - break; - } - default: { - rb_bug("ip_rbUpdateObjCmd: bad option index to UpdateOptions"); - } - } -#else - if (strncmp(objv[1], "idletasks", strlen(objv[1])) != 0) { - Tcl_AppendResult(interp, "bad option \"", objv[1], - "\": must be idletasks", (char *) NULL); - return TCL_ERROR; - } - flags = TCL_IDLE_EVENTS; -#endif - } else { -#ifdef Tcl_WrongNumArgs - Tcl_WrongNumArgs(interp, 1, objv, "[ idletasks ]"); -#else -# if TCL_MAJOR_VERSION >= 8 - int dummy; - Tcl_AppendResult(interp, "wrong number of arguments: should be \"", - Tcl_GetStringFromObj(objv[0], &dummy), - " [ idletasks ]\"", - (char *) NULL); -# else /* TCL_MAJOR_VERSION < 8 */ - Tcl_AppendResult(interp, "wrong number of arguments: should be \"", - objv[0], " [ idletasks ]\"", (char *) NULL); -# endif -#endif - return TCL_ERROR; - } - - Tcl_Preserve(interp); - - /* call eventloop */ - /* ret = lib_eventloop_core(0, flags, (int *)NULL);*/ /* ignore result */ - ret = RTEST(lib_eventloop_launcher(0, flags, (int *)NULL, interp)); /* ignore result */ - - /* exception check */ - if (!NIL_P(rbtk_pending_exception)) { - Tcl_Release(interp); - - /* - if (rb_obj_is_kind_of(rbtk_pending_exception, rb_eSystemExit)) { - */ - if (rb_obj_is_kind_of(rbtk_pending_exception, rb_eSystemExit) - || rb_obj_is_kind_of(rbtk_pending_exception, rb_eInterrupt)) { - return TCL_RETURN; - } else{ - return TCL_ERROR; - } - } - - /* trap check */ - if (rb_trap_pending) { - Tcl_Release(interp); - - return TCL_RETURN; - } - - /* - * Must clear the interpreter's result because event handlers could - * have executed commands. - */ - - DUMP2("last result '%s'", Tcl_GetStringResult(interp)); - Tcl_ResetResult(interp); - Tcl_Release(interp); - - DUMP1("finish Ruby's 'update'"); - return TCL_OK; -} - - -/**********************/ -/* update with thread */ -/**********************/ -struct th_update_param { - VALUE thread; - int done; -}; - -static void rb_threadUpdateProc _((ClientData)); -static void -rb_threadUpdateProc(clientData) - ClientData clientData; /* Pointer to integer to set to 1. */ -{ - struct th_update_param *param = (struct th_update_param *) clientData; - - DUMP1("threadUpdateProc is called"); - param->done = 1; - rb_thread_wakeup(param->thread); - - return; -} - -#if TCL_MAJOR_VERSION >= 8 -static int ip_rb_threadUpdateObjCmd _((ClientData, Tcl_Interp *, int, - Tcl_Obj *CONST [])); -static int -ip_rb_threadUpdateObjCmd(clientData, interp, objc, objv) - ClientData clientData; - Tcl_Interp *interp; - int objc; - Tcl_Obj *CONST objv[]; -#else /* TCL_MAJOR_VERSION < 8 */ -static int ip_rb_threadUpdateCommand _((ClientData, Tcl_Interp *, int, - char *[])); -static int -ip_rb_threadUpdateCommand(clientData, interp, objc, objv) - ClientData clientData; - Tcl_Interp *interp; - int objc; - char *objv[]; -#endif -{ - int optionIndex; - int flags = 0; - struct th_update_param *param; - static CONST char *updateOptions[] = {"idletasks", (char *) NULL}; - enum updateOptions {REGEXP_IDLETASKS}; - volatile VALUE current_thread = rb_thread_current(); - - DUMP1("Ruby's 'thread_update' is called"); - if (interp == (Tcl_Interp*)NULL) { - rbtk_pending_exception = rb_exc_new2(rb_eRuntimeError, - "IP is deleted"); - return TCL_ERROR; - } -#ifdef HAVE_NATIVETHREAD -#ifndef RUBY_USE_NATIVE_THREAD - if (!ruby_native_thread_p()) { - rb_bug("cross-thread violation on ip_rb_threadUpdateCommand()"); - } -#endif -#endif - - if (rb_thread_alone() - || NIL_P(eventloop_thread) || eventloop_thread == current_thread) { -#if TCL_MAJOR_VERSION >= 8 - DUMP1("call ip_rbUpdateObjCmd"); - return ip_rbUpdateObjCmd(clientData, interp, objc, objv); -#else /* TCL_MAJOR_VERSION < 8 */ - DUMP1("call ip_rbUpdateCommand"); - return ip_rbUpdateCommand(clientData, interp, objc, objv); -#endif - } - - DUMP1("start Ruby's 'thread_update' body"); - - Tcl_ResetResult(interp); - - if (objc == 1) { - flags = TCL_DONT_WAIT; - - } else if (objc == 2) { -#if TCL_MAJOR_VERSION >= 8 - if (Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)updateOptions, - "option", 0, &optionIndex) != TCL_OK) { - return TCL_ERROR; - } - switch ((enum updateOptions) optionIndex) { - case REGEXP_IDLETASKS: { - flags = TCL_IDLE_EVENTS; - break; - } - default: { - rb_bug("ip_rb_threadUpdateObjCmd: bad option index to UpdateOptions"); - } - } -#else - if (strncmp(objv[1], "idletasks", strlen(objv[1])) != 0) { - Tcl_AppendResult(interp, "bad option \"", objv[1], - "\": must be idletasks", (char *) NULL); - return TCL_ERROR; - } - flags = TCL_IDLE_EVENTS; -#endif - } else { -#ifdef Tcl_WrongNumArgs - Tcl_WrongNumArgs(interp, 1, objv, "[ idletasks ]"); -#else -# if TCL_MAJOR_VERSION >= 8 - int dummy; - Tcl_AppendResult(interp, "wrong number of arguments: should be \"", - Tcl_GetStringFromObj(objv[0], &dummy), - " [ idletasks ]\"", - (char *) NULL); -# else /* TCL_MAJOR_VERSION < 8 */ - Tcl_AppendResult(interp, "wrong number of arguments: should be \"", - objv[0], " [ idletasks ]\"", (char *) NULL); -# endif -#endif - return TCL_ERROR; - } - - DUMP1("pass argument check"); - - /* param = (struct th_update_param *)Tcl_Alloc(sizeof(struct th_update_param)); */ - param = (struct th_update_param *)ckalloc(sizeof(struct th_update_param)); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)param); -#endif - param->thread = current_thread; - param->done = 0; - - DUMP1("set idle proc"); - Tcl_DoWhenIdle(rb_threadUpdateProc, (ClientData) param); - - while(!param->done) { - DUMP1("wait for complete idle proc"); - /* rb_thread_stop(); */ - rb_thread_sleep_forever(); - } - -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)param); -#else - /* Tcl_Free((char *)param); */ - ckfree((char *)param); -#endif -#endif - - DUMP1("finish Ruby's 'thread_update'"); - return TCL_OK; -} - - -/***************************/ -/* replace of vwait/tkwait */ -/***************************/ -#if TCL_MAJOR_VERSION >= 8 -static int ip_rbVwaitObjCmd _((ClientData, Tcl_Interp *, int, - Tcl_Obj *CONST [])); -static int ip_rb_threadVwaitObjCmd _((ClientData, Tcl_Interp *, int, - Tcl_Obj *CONST [])); -static int ip_rbTkWaitObjCmd _((ClientData, Tcl_Interp *, int, - Tcl_Obj *CONST [])); -static int ip_rb_threadTkWaitObjCmd _((ClientData, Tcl_Interp *, int, - Tcl_Obj *CONST [])); -#else -static int ip_rbVwaitCommand _((ClientData, Tcl_Interp *, int, char *[])); -static int ip_rb_threadVwaitCommand _((ClientData, Tcl_Interp *, int, - char *[])); -static int ip_rbTkWaitCommand _((ClientData, Tcl_Interp *, int, char *[])); -static int ip_rb_threadTkWaitCommand _((ClientData, Tcl_Interp *, int, - char *[])); -#endif - -#if TCL_MAJOR_VERSION >= 8 -static char *VwaitVarProc _((ClientData, Tcl_Interp *, - CONST84 char *,CONST84 char *, int)); -static char * -VwaitVarProc(clientData, interp, name1, name2, flags) - ClientData clientData; /* Pointer to integer to set to 1. */ - Tcl_Interp *interp; /* Interpreter containing variable. */ - CONST84 char *name1; /* Name of variable. */ - CONST84 char *name2; /* Second part of variable name. */ - int flags; /* Information about what happened. */ -#else /* TCL_MAJOR_VERSION < 8 */ -static char *VwaitVarProc _((ClientData, Tcl_Interp *, char *, char *, int)); -static char * -VwaitVarProc(clientData, interp, name1, name2, flags) - ClientData clientData; /* Pointer to integer to set to 1. */ - Tcl_Interp *interp; /* Interpreter containing variable. */ - char *name1; /* Name of variable. */ - char *name2; /* Second part of variable name. */ - int flags; /* Information about what happened. */ -#endif -{ - int *donePtr = (int *) clientData; - - *donePtr = 1; - return (char *) NULL; -} - -#if TCL_MAJOR_VERSION >= 8 -static int -ip_rbVwaitObjCmd(clientData, interp, objc, objv) - ClientData clientData; - Tcl_Interp *interp; - int objc; - Tcl_Obj *CONST objv[]; -#else /* TCL_MAJOR_VERSION < 8 */ -static int -ip_rbVwaitCommand(clientData, interp, objc, objv) - ClientData clientData; - Tcl_Interp *interp; - int objc; - char *objv[]; -#endif -{ - int ret, done, foundEvent; - char *nameString; - int dummy; - int thr_crit_bup; - - DUMP1("Ruby's 'vwait' is called"); - if (interp == (Tcl_Interp*)NULL) { - rbtk_pending_exception = rb_exc_new2(rb_eRuntimeError, - "IP is deleted"); - return TCL_ERROR; - } - -#if 0 - if (!rb_thread_alone() - && eventloop_thread != Qnil - && eventloop_thread != rb_thread_current()) { -#if TCL_MAJOR_VERSION >= 8 - DUMP1("call ip_rb_threadVwaitObjCmd"); - return ip_rb_threadVwaitObjCmd(clientData, interp, objc, objv); -#else /* TCL_MAJOR_VERSION < 8 */ - DUMP1("call ip_rb_threadVwaitCommand"); - return ip_rb_threadVwaitCommand(clientData, interp, objc, objv); -#endif - } -#endif - - Tcl_Preserve(interp); -#ifdef HAVE_NATIVETHREAD -#ifndef RUBY_USE_NATIVE_THREAD - if (!ruby_native_thread_p()) { - rb_bug("cross-thread violation on ip_rbVwaitCommand()"); - } -#endif -#endif - - Tcl_ResetResult(interp); - - if (objc != 2) { -#ifdef Tcl_WrongNumArgs - Tcl_WrongNumArgs(interp, 1, objv, "name"); -#else - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - -#if TCL_MAJOR_VERSION >= 8 - /* nameString = Tcl_GetString(objv[0]); */ - nameString = Tcl_GetStringFromObj(objv[0], &dummy); -#else /* TCL_MAJOR_VERSION < 8 */ - nameString = objv[0]; -#endif - Tcl_AppendResult(interp, "wrong number of arguments: should be \"", - nameString, " name\"", (char *) NULL); - - rb_thread_critical = thr_crit_bup; -#endif - - Tcl_Release(interp); - return TCL_ERROR; - } - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - -#if TCL_MAJOR_VERSION >= 8 - Tcl_IncrRefCount(objv[1]); - /* nameString = Tcl_GetString(objv[1]); */ - nameString = Tcl_GetStringFromObj(objv[1], &dummy); -#else /* TCL_MAJOR_VERSION < 8 */ - nameString = objv[1]; -#endif - - /* - if (Tcl_TraceVar(interp, nameString, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - VwaitVarProc, (ClientData) &done) != TCL_OK) { - return TCL_ERROR; - } - */ - ret = Tcl_TraceVar(interp, nameString, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - VwaitVarProc, (ClientData) &done); - - rb_thread_critical = thr_crit_bup; - - if (ret != TCL_OK) { -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(objv[1]); -#endif - Tcl_Release(interp); - return TCL_ERROR; - } - - done = 0; - - foundEvent = RTEST(lib_eventloop_launcher(/* not check root-widget */0, - 0, &done, interp)); - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - Tcl_UntraceVar(interp, nameString, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - VwaitVarProc, (ClientData) &done); - - rb_thread_critical = thr_crit_bup; - - /* exception check */ - if (!NIL_P(rbtk_pending_exception)) { -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(objv[1]); -#endif - Tcl_Release(interp); - -/* - if (rb_obj_is_kind_of(rbtk_pending_exception, rb_eSystemExit)) { -*/ - if (rb_obj_is_kind_of(rbtk_pending_exception, rb_eSystemExit) - || rb_obj_is_kind_of(rbtk_pending_exception, rb_eInterrupt)) { - return TCL_RETURN; - } else{ - return TCL_ERROR; - } - } - - /* trap check */ - if (rb_trap_pending) { -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(objv[1]); -#endif - Tcl_Release(interp); - - return TCL_RETURN; - } - - /* - * Clear out the interpreter's result, since it may have been set - * by event handlers. - */ - - Tcl_ResetResult(interp); - if (!foundEvent) { - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - Tcl_AppendResult(interp, "can't wait for variable \"", nameString, - "\": would wait forever", (char *) NULL); - - rb_thread_critical = thr_crit_bup; - -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(objv[1]); -#endif - Tcl_Release(interp); - return TCL_ERROR; - } - -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(objv[1]); -#endif - Tcl_Release(interp); - return TCL_OK; -} - - -/**************************/ -/* based on tkCmd.c */ -/**************************/ -#if TCL_MAJOR_VERSION >= 8 -static char *WaitVariableProc _((ClientData, Tcl_Interp *, - CONST84 char *,CONST84 char *, int)); -static char * -WaitVariableProc(clientData, interp, name1, name2, flags) - ClientData clientData; /* Pointer to integer to set to 1. */ - Tcl_Interp *interp; /* Interpreter containing variable. */ - CONST84 char *name1; /* Name of variable. */ - CONST84 char *name2; /* Second part of variable name. */ - int flags; /* Information about what happened. */ -#else /* TCL_MAJOR_VERSION < 8 */ -static char *WaitVariableProc _((ClientData, Tcl_Interp *, - char *, char *, int)); -static char * -WaitVariableProc(clientData, interp, name1, name2, flags) - ClientData clientData; /* Pointer to integer to set to 1. */ - Tcl_Interp *interp; /* Interpreter containing variable. */ - char *name1; /* Name of variable. */ - char *name2; /* Second part of variable name. */ - int flags; /* Information about what happened. */ -#endif -{ - int *donePtr = (int *) clientData; - - *donePtr = 1; - return (char *) NULL; -} - -static void WaitVisibilityProc _((ClientData, XEvent *)); -static void -WaitVisibilityProc(clientData, eventPtr) - ClientData clientData; /* Pointer to integer to set to 1. */ - XEvent *eventPtr; /* Information about event (not used). */ -{ - int *donePtr = (int *) clientData; - - if (eventPtr->type == VisibilityNotify) { - *donePtr = 1; - } - if (eventPtr->type == DestroyNotify) { - *donePtr = 2; - } -} - -static void WaitWindowProc _((ClientData, XEvent *)); -static void -WaitWindowProc(clientData, eventPtr) - ClientData clientData; /* Pointer to integer to set to 1. */ - XEvent *eventPtr; /* Information about event. */ -{ - int *donePtr = (int *) clientData; - - if (eventPtr->type == DestroyNotify) { - *donePtr = 1; - } -} - -#if TCL_MAJOR_VERSION >= 8 -static int -ip_rbTkWaitObjCmd(clientData, interp, objc, objv) - ClientData clientData; - Tcl_Interp *interp; - int objc; - Tcl_Obj *CONST objv[]; -#else /* TCL_MAJOR_VERSION < 8 */ -static int -ip_rbTkWaitCommand(clientData, interp, objc, objv) - ClientData clientData; - Tcl_Interp *interp; - int objc; - char *objv[]; -#endif -{ - Tk_Window tkwin = (Tk_Window) clientData; - Tk_Window window; - int done, index; - static CONST char *optionStrings[] = { "variable", "visibility", "window", - (char *) NULL }; - enum options { TKWAIT_VARIABLE, TKWAIT_VISIBILITY, TKWAIT_WINDOW }; - char *nameString; - int ret, dummy; - int thr_crit_bup; - - DUMP1("Ruby's 'tkwait' is called"); - if (interp == (Tcl_Interp*)NULL) { - rbtk_pending_exception = rb_exc_new2(rb_eRuntimeError, - "IP is deleted"); - return TCL_ERROR; - } - -#if 0 - if (!rb_thread_alone() - && eventloop_thread != Qnil - && eventloop_thread != rb_thread_current()) { -#if TCL_MAJOR_VERSION >= 8 - DUMP1("call ip_rb_threadTkWaitObjCmd"); - return ip_rb_threadTkWaitObjCmd(clientData, interp, objc, objv); -#else /* TCL_MAJOR_VERSION < 8 */ - DUMP1("call ip_rb_threadTkWaitCommand"); - return ip_rb_threadTkWwaitCommand(clientData, interp, objc, objv); -#endif - } -#endif - - Tcl_Preserve(interp); - Tcl_ResetResult(interp); - - if (objc != 3) { -#ifdef Tcl_WrongNumArgs - Tcl_WrongNumArgs(interp, 1, objv, "variable|visibility|window name"); -#else - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - -#if TCL_MAJOR_VERSION >= 8 - Tcl_AppendResult(interp, "wrong number of arguments: should be \"", - Tcl_GetStringFromObj(objv[0], &dummy), - " variable|visibility|window name\"", - (char *) NULL); -#else /* TCL_MAJOR_VERSION < 8 */ - Tcl_AppendResult(interp, "wrong number of arguments: should be \"", - objv[0], " variable|visibility|window name\"", - (char *) NULL); -#endif - - rb_thread_critical = thr_crit_bup; -#endif - - Tcl_Release(interp); - return TCL_ERROR; - } - -#if TCL_MAJOR_VERSION >= 8 - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - /* - if (Tcl_GetIndexFromObj(interp, objv[1], - (CONST84 char **)optionStrings, - "option", 0, &index) != TCL_OK) { - return TCL_ERROR; - } - */ - ret = Tcl_GetIndexFromObj(interp, objv[1], - (CONST84 char **)optionStrings, - "option", 0, &index); - - rb_thread_critical = thr_crit_bup; - - if (ret != TCL_OK) { - Tcl_Release(interp); - return TCL_ERROR; - } -#else /* TCL_MAJOR_VERSION < 8 */ - { - int c = objv[1][0]; - size_t length = strlen(objv[1]); - - if ((c == 'v') && (strncmp(objv[1], "variable", length) == 0) - && (length >= 2)) { - index = TKWAIT_VARIABLE; - } else if ((c == 'v') && (strncmp(objv[1], "visibility", length) == 0) - && (length >= 2)) { - index = TKWAIT_VISIBILITY; - } else if ((c == 'w') && (strncmp(objv[1], "window", length) == 0)) { - index = TKWAIT_WINDOW; - } else { - Tcl_AppendResult(interp, "bad option \"", objv[1], - "\": must be variable, visibility, or window", - (char *) NULL); - Tcl_Release(interp); - return TCL_ERROR; - } - } -#endif - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - -#if TCL_MAJOR_VERSION >= 8 - Tcl_IncrRefCount(objv[2]); - /* nameString = Tcl_GetString(objv[2]); */ - nameString = Tcl_GetStringFromObj(objv[2], &dummy); -#else /* TCL_MAJOR_VERSION < 8 */ - nameString = objv[2]; -#endif - - rb_thread_critical = thr_crit_bup; - - switch ((enum options) index) { - case TKWAIT_VARIABLE: - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - /* - if (Tcl_TraceVar(interp, nameString, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - WaitVariableProc, (ClientData) &done) != TCL_OK) { - return TCL_ERROR; - } - */ - ret = Tcl_TraceVar(interp, nameString, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - WaitVariableProc, (ClientData) &done); - - rb_thread_critical = thr_crit_bup; - - if (ret != TCL_OK) { -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(objv[2]); -#endif - Tcl_Release(interp); - return TCL_ERROR; - } - - done = 0; - /* lib_eventloop_core(check_rootwidget_flag, 0, &done); */ - lib_eventloop_launcher(check_rootwidget_flag, 0, &done, interp); - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - Tcl_UntraceVar(interp, nameString, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - WaitVariableProc, (ClientData) &done); - -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(objv[2]); -#endif - - rb_thread_critical = thr_crit_bup; - - /* exception check */ - if (!NIL_P(rbtk_pending_exception)) { - Tcl_Release(interp); - - /* - if (rb_obj_is_kind_of(rbtk_pending_exception, rb_eSystemExit)) { - */ - if (rb_obj_is_kind_of(rbtk_pending_exception, rb_eSystemExit) - || rb_obj_is_kind_of(rbtk_pending_exception, rb_eInterrupt)) { - return TCL_RETURN; - } else{ - return TCL_ERROR; - } - } - - /* trap check */ - if (rb_trap_pending) { - Tcl_Release(interp); - - return TCL_RETURN; - } - - break; - - case TKWAIT_VISIBILITY: - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - /* This function works on the Tk eventloop thread only. */ - if (!tk_stubs_init_p() || Tk_MainWindow(interp) == (Tk_Window)NULL) { - window = NULL; - } else { - window = Tk_NameToWindow(interp, nameString, tkwin); - } - - if (window == NULL) { - Tcl_AppendResult(interp, ": tkwait: ", - "no main-window (not Tk application?)", - (char*)NULL); - rb_thread_critical = thr_crit_bup; -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(objv[2]); -#endif - Tcl_Release(interp); - return TCL_ERROR; - } - - Tk_CreateEventHandler(window, - VisibilityChangeMask|StructureNotifyMask, - WaitVisibilityProc, (ClientData) &done); - - rb_thread_critical = thr_crit_bup; - - done = 0; - /* lib_eventloop_core(check_rootwidget_flag, 0, &done); */ - lib_eventloop_launcher(check_rootwidget_flag, 0, &done, interp); - - /* exception check */ - if (!NIL_P(rbtk_pending_exception)) { -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(objv[2]); -#endif - Tcl_Release(interp); - - /* - if (rb_obj_is_kind_of(rbtk_pending_exception, rb_eSystemExit)) { - */ - if (rb_obj_is_kind_of(rbtk_pending_exception, rb_eSystemExit) - || rb_obj_is_kind_of(rbtk_pending_exception, rb_eInterrupt)) { - return TCL_RETURN; - } else{ - return TCL_ERROR; - } - } - - /* trap check */ - if (rb_trap_pending) { -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(objv[2]); -#endif - Tcl_Release(interp); - - return TCL_RETURN; - } - - if (done != 1) { - /* - * Note that we do not delete the event handler because it - * was deleted automatically when the window was destroyed. - */ - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "window \"", nameString, - "\" was deleted before its visibility changed", - (char *) NULL); - - rb_thread_critical = thr_crit_bup; - -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(objv[2]); -#endif - Tcl_Release(interp); - return TCL_ERROR; - } - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(objv[2]); -#endif - - Tk_DeleteEventHandler(window, - VisibilityChangeMask|StructureNotifyMask, - WaitVisibilityProc, (ClientData) &done); - - rb_thread_critical = thr_crit_bup; - - break; - - case TKWAIT_WINDOW: - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - /* This function works on the Tk eventloop thread only. */ - if (!tk_stubs_init_p() || Tk_MainWindow(interp) == (Tk_Window)NULL) { - window = NULL; - } else { - window = Tk_NameToWindow(interp, nameString, tkwin); - } - -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(objv[2]); -#endif - - if (window == NULL) { - Tcl_AppendResult(interp, ": tkwait: ", - "no main-window (not Tk application?)", - (char*)NULL); - rb_thread_critical = thr_crit_bup; - Tcl_Release(interp); - return TCL_ERROR; - } - - Tk_CreateEventHandler(window, StructureNotifyMask, - WaitWindowProc, (ClientData) &done); - - rb_thread_critical = thr_crit_bup; - - done = 0; - /* lib_eventloop_core(check_rootwidget_flag, 0, &done); */ - lib_eventloop_launcher(check_rootwidget_flag, 0, &done, interp); - - /* exception check */ - if (!NIL_P(rbtk_pending_exception)) { - Tcl_Release(interp); - - /* - if (rb_obj_is_kind_of(rbtk_pending_exception, rb_eSystemExit)) { - */ - if (rb_obj_is_kind_of(rbtk_pending_exception, rb_eSystemExit) - || rb_obj_is_kind_of(rbtk_pending_exception, rb_eInterrupt)) { - return TCL_RETURN; - } else{ - return TCL_ERROR; - } - } - - /* trap check */ - if (rb_trap_pending) { - Tcl_Release(interp); - - return TCL_RETURN; - } - - /* - * Note: there's no need to delete the event handler. It was - * deleted automatically when the window was destroyed. - */ - break; - } - - /* - * Clear out the interpreter's result, since it may have been set - * by event handlers. - */ - - Tcl_ResetResult(interp); - Tcl_Release(interp); - return TCL_OK; -} - -/****************************/ -/* vwait/tkwait with thread */ -/****************************/ -struct th_vwait_param { - VALUE thread; - int done; -}; - -#if TCL_MAJOR_VERSION >= 8 -static char *rb_threadVwaitProc _((ClientData, Tcl_Interp *, - CONST84 char *,CONST84 char *, int)); -static char * -rb_threadVwaitProc(clientData, interp, name1, name2, flags) - ClientData clientData; /* Pointer to integer to set to 1. */ - Tcl_Interp *interp; /* Interpreter containing variable. */ - CONST84 char *name1; /* Name of variable. */ - CONST84 char *name2; /* Second part of variable name. */ - int flags; /* Information about what happened. */ -#else /* TCL_MAJOR_VERSION < 8 */ -static char *rb_threadVwaitProc _((ClientData, Tcl_Interp *, - char *, char *, int)); -static char * -rb_threadVwaitProc(clientData, interp, name1, name2, flags) - ClientData clientData; /* Pointer to integer to set to 1. */ - Tcl_Interp *interp; /* Interpreter containing variable. */ - char *name1; /* Name of variable. */ - char *name2; /* Second part of variable name. */ - int flags; /* Information about what happened. */ -#endif -{ - struct th_vwait_param *param = (struct th_vwait_param *) clientData; - - if (flags & (TCL_INTERP_DESTROYED | TCL_TRACE_DESTROYED)) { - param->done = -1; - } else { - param->done = 1; - } - if (param->done != 0) rb_thread_wakeup(param->thread); - - return (char *)NULL; -} - -#define TKWAIT_MODE_VISIBILITY 1 -#define TKWAIT_MODE_DESTROY 2 - -static void rb_threadWaitVisibilityProc _((ClientData, XEvent *)); -static void -rb_threadWaitVisibilityProc(clientData, eventPtr) - ClientData clientData; /* Pointer to integer to set to 1. */ - XEvent *eventPtr; /* Information about event (not used). */ -{ - struct th_vwait_param *param = (struct th_vwait_param *) clientData; - - if (eventPtr->type == VisibilityNotify) { - param->done = TKWAIT_MODE_VISIBILITY; - } - if (eventPtr->type == DestroyNotify) { - param->done = TKWAIT_MODE_DESTROY; - } - if (param->done != 0) rb_thread_wakeup(param->thread); -} - -static void rb_threadWaitWindowProc _((ClientData, XEvent *)); -static void -rb_threadWaitWindowProc(clientData, eventPtr) - ClientData clientData; /* Pointer to integer to set to 1. */ - XEvent *eventPtr; /* Information about event. */ -{ - struct th_vwait_param *param = (struct th_vwait_param *) clientData; - - if (eventPtr->type == DestroyNotify) { - param->done = TKWAIT_MODE_DESTROY; - } - if (param->done != 0) rb_thread_wakeup(param->thread); -} - -#if TCL_MAJOR_VERSION >= 8 -static int -ip_rb_threadVwaitObjCmd(clientData, interp, objc, objv) - ClientData clientData; - Tcl_Interp *interp; - int objc; - Tcl_Obj *CONST objv[]; -#else /* TCL_MAJOR_VERSION < 8 */ -static int -ip_rb_threadVwaitCommand(clientData, interp, objc, objv) - ClientData clientData; - Tcl_Interp *interp; - int objc; - char *objv[]; -#endif -{ - struct th_vwait_param *param; - char *nameString; - int ret, dummy; - int thr_crit_bup; - volatile VALUE current_thread = rb_thread_current(); - - DUMP1("Ruby's 'thread_vwait' is called"); - if (interp == (Tcl_Interp*)NULL) { - rbtk_pending_exception = rb_exc_new2(rb_eRuntimeError, - "IP is deleted"); - return TCL_ERROR; - } - - if (rb_thread_alone() || eventloop_thread == current_thread) { -#if TCL_MAJOR_VERSION >= 8 - DUMP1("call ip_rbVwaitObjCmd"); - return ip_rbVwaitObjCmd(clientData, interp, objc, objv); -#else /* TCL_MAJOR_VERSION < 8 */ - DUMP1("call ip_rbVwaitCommand"); - return ip_rbVwaitCommand(clientData, interp, objc, objv); -#endif - } - - Tcl_Preserve(interp); - Tcl_ResetResult(interp); - - if (objc != 2) { -#ifdef Tcl_WrongNumArgs - Tcl_WrongNumArgs(interp, 1, objv, "name"); -#else - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - -#if TCL_MAJOR_VERSION >= 8 - /* nameString = Tcl_GetString(objv[0]); */ - nameString = Tcl_GetStringFromObj(objv[0], &dummy); -#else /* TCL_MAJOR_VERSION < 8 */ - nameString = objv[0]; -#endif - Tcl_AppendResult(interp, "wrong number of arguments: should be \"", - nameString, " name\"", (char *) NULL); - - rb_thread_critical = thr_crit_bup; -#endif - - Tcl_Release(interp); - return TCL_ERROR; - } - -#if TCL_MAJOR_VERSION >= 8 - Tcl_IncrRefCount(objv[1]); - /* nameString = Tcl_GetString(objv[1]); */ - nameString = Tcl_GetStringFromObj(objv[1], &dummy); -#else /* TCL_MAJOR_VERSION < 8 */ - nameString = objv[1]; -#endif - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - /* param = (struct th_vwait_param *)Tcl_Alloc(sizeof(struct th_vwait_param)); */ - param = (struct th_vwait_param *)ckalloc(sizeof(struct th_vwait_param)); -#if 1 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)param); -#endif - param->thread = current_thread; - param->done = 0; - - /* - if (Tcl_TraceVar(interp, nameString, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - rb_threadVwaitProc, (ClientData) param) != TCL_OK) { - return TCL_ERROR; - } - */ - ret = Tcl_TraceVar(interp, nameString, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - rb_threadVwaitProc, (ClientData) param); - - rb_thread_critical = thr_crit_bup; - - if (ret != TCL_OK) { -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 1 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)param); -#else - /* Tcl_Free((char *)param); */ - ckfree((char *)param); -#endif -#endif - -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(objv[1]); -#endif - Tcl_Release(interp); - return TCL_ERROR; - } - - while(!param->done) { - /* rb_thread_stop(); */ - rb_thread_sleep_forever(); - } - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - if (param->done > 0) { - Tcl_UntraceVar(interp, nameString, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - rb_threadVwaitProc, (ClientData) param); - } - -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 1 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)param); -#else - /* Tcl_Free((char *)param); */ - ckfree((char *)param); -#endif -#endif - - rb_thread_critical = thr_crit_bup; - -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(objv[1]); -#endif - Tcl_Release(interp); - return TCL_OK; -} - -#if TCL_MAJOR_VERSION >= 8 -static int -ip_rb_threadTkWaitObjCmd(clientData, interp, objc, objv) - ClientData clientData; - Tcl_Interp *interp; - int objc; - Tcl_Obj *CONST objv[]; -#else /* TCL_MAJOR_VERSION < 8 */ -static int -ip_rb_threadTkWaitCommand(clientData, interp, objc, objv) - ClientData clientData; - Tcl_Interp *interp; - int objc; - char *objv[]; -#endif -{ - struct th_vwait_param *param; - Tk_Window tkwin = (Tk_Window) clientData; - Tk_Window window; - int index; - static CONST char *optionStrings[] = { "variable", "visibility", "window", - (char *) NULL }; - enum options { TKWAIT_VARIABLE, TKWAIT_VISIBILITY, TKWAIT_WINDOW }; - char *nameString; - int ret, dummy; - int thr_crit_bup; - volatile VALUE current_thread = rb_thread_current(); - - DUMP1("Ruby's 'thread_tkwait' is called"); - if (interp == (Tcl_Interp*)NULL) { - rbtk_pending_exception = rb_exc_new2(rb_eRuntimeError, - "IP is deleted"); - return TCL_ERROR; - } - - if (rb_thread_alone() || eventloop_thread == current_thread) { -#if TCL_MAJOR_VERSION >= 8 - DUMP1("call ip_rbTkWaitObjCmd"); - return ip_rbTkWaitObjCmd(clientData, interp, objc, objv); -#else /* TCL_MAJOR_VERSION < 8 */ - DUMP1("call rb_VwaitCommand"); - return ip_rbTkWaitCommand(clientData, interp, objc, objv); -#endif - } - - Tcl_Preserve(interp); - Tcl_Preserve(tkwin); - - Tcl_ResetResult(interp); - - if (objc != 3) { -#ifdef Tcl_WrongNumArgs - Tcl_WrongNumArgs(interp, 1, objv, "variable|visibility|window name"); -#else - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - -#if TCL_MAJOR_VERSION >= 8 - Tcl_AppendResult(interp, "wrong number of arguments: should be \"", - Tcl_GetStringFromObj(objv[0], &dummy), - " variable|visibility|window name\"", - (char *) NULL); -#else /* TCL_MAJOR_VERSION < 8 */ - Tcl_AppendResult(interp, "wrong number of arguments: should be \"", - objv[0], " variable|visibility|window name\"", - (char *) NULL); -#endif - - rb_thread_critical = thr_crit_bup; -#endif - - Tcl_Release(tkwin); - Tcl_Release(interp); - return TCL_ERROR; - } - -#if TCL_MAJOR_VERSION >= 8 - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - /* - if (Tcl_GetIndexFromObj(interp, objv[1], - (CONST84 char **)optionStrings, - "option", 0, &index) != TCL_OK) { - return TCL_ERROR; - } - */ - ret = Tcl_GetIndexFromObj(interp, objv[1], - (CONST84 char **)optionStrings, - "option", 0, &index); - - rb_thread_critical = thr_crit_bup; - - if (ret != TCL_OK) { - Tcl_Release(tkwin); - Tcl_Release(interp); - return TCL_ERROR; - } -#else /* TCL_MAJOR_VERSION < 8 */ - { - int c = objv[1][0]; - size_t length = strlen(objv[1]); - - if ((c == 'v') && (strncmp(objv[1], "variable", length) == 0) - && (length >= 2)) { - index = TKWAIT_VARIABLE; - } else if ((c == 'v') && (strncmp(objv[1], "visibility", length) == 0) - && (length >= 2)) { - index = TKWAIT_VISIBILITY; - } else if ((c == 'w') && (strncmp(objv[1], "window", length) == 0)) { - index = TKWAIT_WINDOW; - } else { - Tcl_AppendResult(interp, "bad option \"", objv[1], - "\": must be variable, visibility, or window", - (char *) NULL); - Tcl_Release(tkwin); - Tcl_Release(interp); - return TCL_ERROR; - } - } -#endif - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - -#if TCL_MAJOR_VERSION >= 8 - Tcl_IncrRefCount(objv[2]); - /* nameString = Tcl_GetString(objv[2]); */ - nameString = Tcl_GetStringFromObj(objv[2], &dummy); -#else /* TCL_MAJOR_VERSION < 8 */ - nameString = objv[2]; -#endif - - /* param = (struct th_vwait_param *)Tcl_Alloc(sizeof(struct th_vwait_param)); */ - param = (struct th_vwait_param *)ckalloc(sizeof(struct th_vwait_param)); -#if 1 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)param); -#endif - param->thread = current_thread; - param->done = 0; - - rb_thread_critical = thr_crit_bup; - - switch ((enum options) index) { - case TKWAIT_VARIABLE: - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - /* - if (Tcl_TraceVar(interp, nameString, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - rb_threadVwaitProc, (ClientData) param) != TCL_OK) { - return TCL_ERROR; - } - */ - ret = Tcl_TraceVar(interp, nameString, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - rb_threadVwaitProc, (ClientData) param); - - rb_thread_critical = thr_crit_bup; - - if (ret != TCL_OK) { -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 1 /* use Tcl_Preserve/Release */ - Tcl_Release(param); -#else - /* Tcl_Free((char *)param); */ - ckfree((char *)param); -#endif -#endif - -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(objv[2]); -#endif - - Tcl_Release(tkwin); - Tcl_Release(interp); - return TCL_ERROR; - } - - while(!param->done) { - /* rb_thread_stop(); */ - rb_thread_sleep_forever(); - } - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - if (param->done > 0) { - Tcl_UntraceVar(interp, nameString, - TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, - rb_threadVwaitProc, (ClientData) param); - } - -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(objv[2]); -#endif - - rb_thread_critical = thr_crit_bup; - - break; - - case TKWAIT_VISIBILITY: - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - -#if 0 /* variable 'tkwin' must keep the token of MainWindow */ - if (!tk_stubs_init_p() || Tk_MainWindow(interp) == (Tk_Window)NULL) { - window = NULL; - } else { - window = Tk_NameToWindow(interp, nameString, tkwin); - } -#else - if (!tk_stubs_init_p() || tkwin == (Tk_Window)NULL) { - window = NULL; - } else { - /* Tk_NameToWindow() returns right token on non-eventloop thread */ - Tcl_CmdInfo info; - if (Tcl_GetCommandInfo(interp, ".", &info)) { /* check root */ - window = Tk_NameToWindow(interp, nameString, tkwin); - } else { - window = NULL; - } - } -#endif - - if (window == NULL) { - Tcl_AppendResult(interp, ": thread_tkwait: ", - "no main-window (not Tk application?)", - (char*)NULL); - - rb_thread_critical = thr_crit_bup; - -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 1 /* use Tcl_Preserve/Release */ - Tcl_Release(param); -#else - /* Tcl_Free((char *)param); */ - ckfree((char *)param); -#endif -#endif - -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(objv[2]); -#endif - Tcl_Release(tkwin); - Tcl_Release(interp); - return TCL_ERROR; - } - Tcl_Preserve(window); - - Tk_CreateEventHandler(window, - VisibilityChangeMask|StructureNotifyMask, - rb_threadWaitVisibilityProc, (ClientData) param); - - rb_thread_critical = thr_crit_bup; - - while(param->done != TKWAIT_MODE_VISIBILITY) { - if (param->done == TKWAIT_MODE_DESTROY) break; - /* rb_thread_stop(); */ - rb_thread_sleep_forever(); - } - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - /* when a window is destroyed, no need to call Tk_DeleteEventHandler */ - if (param->done != TKWAIT_MODE_DESTROY) { - Tk_DeleteEventHandler(window, - VisibilityChangeMask|StructureNotifyMask, - rb_threadWaitVisibilityProc, - (ClientData) param); - } - - if (param->done != 1) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "window \"", nameString, - "\" was deleted before its visibility changed", - (char *) NULL); - - rb_thread_critical = thr_crit_bup; - - Tcl_Release(window); - -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 1 /* use Tcl_Preserve/Release */ - Tcl_Release(param); -#else - /* Tcl_Free((char *)param); */ - ckfree((char *)param); -#endif -#endif - -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(objv[2]); -#endif - - Tcl_Release(tkwin); - Tcl_Release(interp); - return TCL_ERROR; - } - - Tcl_Release(window); - -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(objv[2]); -#endif - - rb_thread_critical = thr_crit_bup; - - break; - - case TKWAIT_WINDOW: - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - -#if 0 /* variable 'tkwin' must keep the token of MainWindow */ - if (!tk_stubs_init_p() || Tk_MainWindow(interp) == (Tk_Window)NULL) { - window = NULL; - } else { - window = Tk_NameToWindow(interp, nameString, tkwin); - } -#else - if (!tk_stubs_init_p() || tkwin == (Tk_Window)NULL) { - window = NULL; - } else { - /* Tk_NameToWindow() returns right token on non-eventloop thread */ - Tcl_CmdInfo info; - if (Tcl_GetCommandInfo(interp, ".", &info)) { /* check root */ - window = Tk_NameToWindow(interp, nameString, tkwin); - } else { - window = NULL; - } - } -#endif - -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(objv[2]); -#endif - - if (window == NULL) { - Tcl_AppendResult(interp, ": thread_tkwait: ", - "no main-window (not Tk application?)", - (char*)NULL); - - rb_thread_critical = thr_crit_bup; - -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 1 /* use Tcl_Preserve/Release */ - Tcl_Release(param); -#else - /* Tcl_Free((char *)param); */ - ckfree((char *)param); -#endif -#endif - - Tcl_Release(tkwin); - Tcl_Release(interp); - return TCL_ERROR; - } - - Tcl_Preserve(window); - - Tk_CreateEventHandler(window, StructureNotifyMask, - rb_threadWaitWindowProc, (ClientData) param); - - rb_thread_critical = thr_crit_bup; - - while(param->done != TKWAIT_MODE_DESTROY) { - /* rb_thread_stop(); */ - rb_thread_sleep_forever(); - } - - Tcl_Release(window); - - /* when a window is destroyed, no need to call Tk_DeleteEventHandler - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - Tk_DeleteEventHandler(window, StructureNotifyMask, - rb_threadWaitWindowProc, (ClientData) param); - - rb_thread_critical = thr_crit_bup; - */ - - break; - } /* end of 'switch' statement */ - -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 1 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)param); -#else - /* Tcl_Free((char *)param); */ - ckfree((char *)param); -#endif -#endif - - /* - * Clear out the interpreter's result, since it may have been set - * by event handlers. - */ - - Tcl_ResetResult(interp); - - Tcl_Release(tkwin); - Tcl_Release(interp); - return TCL_OK; -} - -static VALUE -ip_thread_vwait(self, var) - VALUE self; - VALUE var; -{ - VALUE argv[2]; - volatile VALUE cmd_str = rb_str_new2("thread_vwait"); - - argv[0] = cmd_str; - argv[1] = var; - - return ip_invoke_with_position(2, argv, self, TCL_QUEUE_TAIL); -} - -static VALUE -ip_thread_tkwait(self, mode, target) - VALUE self; - VALUE mode; - VALUE target; -{ - VALUE argv[3]; - volatile VALUE cmd_str = rb_str_new2("thread_tkwait"); - - argv[0] = cmd_str; - argv[1] = mode; - argv[2] = target; - - return ip_invoke_with_position(3, argv, self, TCL_QUEUE_TAIL); -} - - -/* delete slave interpreters */ -#if TCL_MAJOR_VERSION >= 8 -static void -delete_slaves(ip) - Tcl_Interp *ip; -{ - int thr_crit_bup; - Tcl_Interp *slave; - Tcl_Obj *slave_list, *elem; - char *slave_name; - int i, len; - - DUMP1("delete slaves"); - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - if (!Tcl_InterpDeleted(ip) && Tcl_Eval(ip, "interp slaves") == TCL_OK) { - slave_list = Tcl_GetObjResult(ip); - Tcl_IncrRefCount(slave_list); - - if (Tcl_ListObjLength((Tcl_Interp*)NULL, slave_list, &len) == TCL_OK) { - for(i = 0; i < len; i++) { - Tcl_ListObjIndex((Tcl_Interp*)NULL, slave_list, i, &elem); - - if (elem == (Tcl_Obj*)NULL) continue; - - Tcl_IncrRefCount(elem); - - /* get slave */ - /* slave_name = Tcl_GetString(elem); */ - slave_name = Tcl_GetStringFromObj(elem, (int*)NULL); - DUMP2("delete slave:'%s'", slave_name); - - Tcl_DecrRefCount(elem); - - slave = Tcl_GetSlave(ip, slave_name); - if (slave == (Tcl_Interp*)NULL) continue; - - /* call ip_finalize */ - ip_finalize(slave); - - Tcl_DeleteInterp(slave); - /* Tcl_Release(slave); */ - } - } - - Tcl_DecrRefCount(slave_list); - } - - rb_thread_critical = thr_crit_bup; -} -#else /* TCL_MAJOR_VERSION < 8 */ -static void -delete_slaves(ip) - Tcl_Interp *ip; -{ - int thr_crit_bup; - Tcl_Interp *slave; - int argc; - char **argv; - char *slave_list; - char *slave_name; - int i, len; - - DUMP1("delete slaves"); - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - if (!Tcl_InterpDeleted(ip) && Tcl_Eval(ip, "interp slaves") == TCL_OK) { - slave_list = ip->result; - if (Tcl_SplitList((Tcl_Interp*)NULL, - slave_list, &argc, &argv) == TCL_OK) { - for(i = 0; i < argc; i++) { - slave_name = argv[i]; - - DUMP2("delete slave:'%s'", slave_name); - - slave = Tcl_GetSlave(ip, slave_name); - if (slave == (Tcl_Interp*)NULL) continue; - - /* call ip_finalize */ - ip_finalize(slave); - - Tcl_DeleteInterp(slave); - } - } - } - - rb_thread_critical = thr_crit_bup; -} -#endif - - -/* finalize operation */ -static void -lib_mark_at_exit(self) - VALUE self; -{ - at_exit = 1; -} - -static int -#if TCL_MAJOR_VERSION >= 8 -ip_null_proc(clientData, interp, argc, argv) - ClientData clientData; - Tcl_Interp *interp; - int argc; - Tcl_Obj *CONST argv[]; -#else /* TCL_MAJOR_VERSION < 8 */ -ip_null_proc(clientData, interp, argc, argv) - ClientData clientData; - Tcl_Interp *interp; - int argc; - char *argv[]; -#endif -{ - Tcl_ResetResult(interp); - return TCL_OK; -} - -static void -ip_finalize(ip) - Tcl_Interp *ip; -{ - Tcl_CmdInfo info; - int thr_crit_bup; - - VALUE rb_debug_bup, rb_verbose_bup; - /* When ruby is exiting, printing debug messages in some callback - operations from Tcl-IP sometimes cause SEGV. I don't know the - reason. But I got SEGV when calling "rb_io_write(rb_stdout, ...)". - So, in some part of this function, debug mode and verbose mode - are disabled. If you know the reason, please fix it. - -- Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) */ - - DUMP1("start ip_finalize"); - - if (ip == (Tcl_Interp*)NULL) { - DUMP1("ip is NULL"); - return; - } - - if (Tcl_InterpDeleted(ip)) { - DUMP2("ip(%p) is already deleted", ip); - return; - } - -#if TCL_NAMESPACE_DEBUG - if (ip_null_namespace(ip)) { - DUMP2("ip(%p) has null namespace", ip); - return; - } -#endif - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - rb_debug_bup = ruby_debug; - rb_verbose_bup = ruby_verbose; - - Tcl_Preserve(ip); - - /* delete slaves */ - delete_slaves(ip); - - /* shut off some connections from Tcl-proc to Ruby */ - if (at_exit) { - /* NOTE: Only when at exit. - Because, ruby removes objects, which depends on the deleted - interpreter, on some callback operations. - It is important for GC. */ -#if TCL_MAJOR_VERSION >= 8 - Tcl_CreateObjCommand(ip, "ruby", ip_null_proc, - (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); - Tcl_CreateObjCommand(ip, "ruby_eval", ip_null_proc, - (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); - Tcl_CreateObjCommand(ip, "ruby_cmd", ip_null_proc, - (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); -#else /* TCL_MAJOR_VERSION < 8 */ - Tcl_CreateCommand(ip, "ruby", ip_null_proc, - (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); - Tcl_CreateCommand(ip, "ruby_eval", ip_null_proc, - (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); - Tcl_CreateCommand(ip, "ruby_cmd", ip_null_proc, - (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); -#endif - /* - rb_thread_critical = thr_crit_bup; - return; - */ - } - - /* delete root widget */ -#if 0 /* cause SEGV on Ruby 1.9 */ - DUMP1("check `destroy'"); - if (Tcl_GetCommandInfo(ip, "destroy", &info)) { - DUMP1("call `destroy .'"); - Tcl_GlobalEval(ip, "catch {destroy .}"); - } -#endif -#if 1 - DUMP1("destroy root widget"); - if (tk_stubs_init_p() && Tk_MainWindow(ip) != (Tk_Window)NULL) { - /* - * On Ruby VM, this code piece may be not called, because - * Tk_MainWindow() returns NULL on a native thread except - * the thread which initialize Tk environment. - * Of course, that is a problem. But maybe not so serious. - * All widgets are destroyed when the Tcl interp is deleted. - * At then, Ruby may raise exceptions on the delete hook - * callbacks which registered for the deleted widgets, and - * may fail to clear objects which depends on the widgets. - * Although it is the problem, it is possibly avoidable by - * rescuing exceptions and the finalize hook of the interp. - */ - Tk_Window win = Tk_MainWindow(ip); - - DUMP1("call Tk_DestroyWindow"); - ruby_debug = Qfalse; - ruby_verbose = Qnil; - if (! (((Tk_FakeWin*)win)->flags & TK_ALREADY_DEAD)) { - Tk_DestroyWindow(win); - } - ruby_debug = rb_debug_bup; - ruby_verbose = rb_verbose_bup; - } -#endif - - /* call finalize-hook-proc */ - DUMP1("check `finalize-hook-proc'"); - if ( Tcl_GetCommandInfo(ip, finalize_hook_name, &info)) { - DUMP2("call finalize hook proc '%s'", finalize_hook_name); - ruby_debug = Qfalse; - ruby_verbose = Qnil; - Tcl_GlobalEval(ip, finalize_hook_name); - ruby_debug = rb_debug_bup; - ruby_verbose = rb_verbose_bup; - } - - DUMP1("check `foreach' & `after'"); - if ( Tcl_GetCommandInfo(ip, "foreach", &info) - && Tcl_GetCommandInfo(ip, "after", &info) ) { - DUMP1("cancel after callbacks"); - ruby_debug = Qfalse; - ruby_verbose = Qnil; - Tcl_GlobalEval(ip, "catch {foreach id [after info] {after cancel $id}}"); - ruby_debug = rb_debug_bup; - ruby_verbose = rb_verbose_bup; - } - - Tcl_Release(ip); - - DUMP1("finish ip_finalize"); - ruby_debug = rb_debug_bup; - ruby_verbose = rb_verbose_bup; - rb_thread_critical = thr_crit_bup; -} - - -/* destroy interpreter */ -static void -ip_free(ptr) - struct tcltkip *ptr; -{ - int thr_crit_bup; - - DUMP2("free Tcl Interp %lx", (unsigned long)ptr->ip); - if (ptr) { - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - if ( ptr->ip != (Tcl_Interp*)NULL - && !Tcl_InterpDeleted(ptr->ip) - && Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL - && !Tcl_InterpDeleted(Tcl_GetMaster(ptr->ip)) ) { - DUMP2("parent IP(%lx) is not deleted", - (unsigned long)Tcl_GetMaster(ptr->ip)); - DUMP2("slave IP(%lx) should not be deleted", - (unsigned long)ptr->ip); - free(ptr); - /* ckfree((char*)ptr); */ - rb_thread_critical = thr_crit_bup; - return; - } - - if (ptr->ip == (Tcl_Interp*)NULL) { - DUMP1("ip_free is called for deleted IP"); - free(ptr); - /* ckfree((char*)ptr); */ - rb_thread_critical = thr_crit_bup; - return; - } - - ip_finalize(ptr->ip); - Tcl_DeleteInterp(ptr->ip); - Tcl_Release(ptr->ip); - - ptr->ip = (Tcl_Interp*)NULL; - free(ptr); - /* ckfree((char*)ptr); */ - - rb_thread_critical = thr_crit_bup; - } - - DUMP1("complete freeing Tcl Interp"); -} - - -/* create and initialize interpreter */ -static VALUE ip_alloc _((VALUE)); -static VALUE -ip_alloc(self) - VALUE self; -{ - return Data_Wrap_Struct(self, 0, ip_free, 0); -} - -static void -ip_replace_wait_commands(interp, mainWin) - Tcl_Interp *interp; - Tk_Window mainWin; -{ - /* replace 'vwait' command */ -#if TCL_MAJOR_VERSION >= 8 - DUMP1("Tcl_CreateObjCommand(\"vwait\")"); - Tcl_CreateObjCommand(interp, "vwait", ip_rbVwaitObjCmd, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); -#else /* TCL_MAJOR_VERSION < 8 */ - DUMP1("Tcl_CreateCommand(\"vwait\")"); - Tcl_CreateCommand(interp, "vwait", ip_rbVwaitCommand, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); -#endif - - /* replace 'tkwait' command */ -#if TCL_MAJOR_VERSION >= 8 - DUMP1("Tcl_CreateObjCommand(\"tkwait\")"); - Tcl_CreateObjCommand(interp, "tkwait", ip_rbTkWaitObjCmd, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); -#else /* TCL_MAJOR_VERSION < 8 */ - DUMP1("Tcl_CreateCommand(\"tkwait\")"); - Tcl_CreateCommand(interp, "tkwait", ip_rbTkWaitCommand, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); -#endif - - /* add 'thread_vwait' command */ -#if TCL_MAJOR_VERSION >= 8 - DUMP1("Tcl_CreateObjCommand(\"thread_vwait\")"); - Tcl_CreateObjCommand(interp, "thread_vwait", ip_rb_threadVwaitObjCmd, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); -#else /* TCL_MAJOR_VERSION < 8 */ - DUMP1("Tcl_CreateCommand(\"thread_vwait\")"); - Tcl_CreateCommand(interp, "thread_vwait", ip_rb_threadVwaitCommand, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); -#endif - - /* add 'thread_tkwait' command */ -#if TCL_MAJOR_VERSION >= 8 - DUMP1("Tcl_CreateObjCommand(\"thread_tkwait\")"); - Tcl_CreateObjCommand(interp, "thread_tkwait", ip_rb_threadTkWaitObjCmd, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); -#else /* TCL_MAJOR_VERSION < 8 */ - DUMP1("Tcl_CreateCommand(\"thread_tkwait\")"); - Tcl_CreateCommand(interp, "thread_tkwait", ip_rb_threadTkWaitCommand, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); -#endif - - /* replace 'update' command */ -#if TCL_MAJOR_VERSION >= 8 - DUMP1("Tcl_CreateObjCommand(\"update\")"); - Tcl_CreateObjCommand(interp, "update", ip_rbUpdateObjCmd, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); -#else /* TCL_MAJOR_VERSION < 8 */ - DUMP1("Tcl_CreateCommand(\"update\")"); - Tcl_CreateCommand(interp, "update", ip_rbUpdateCommand, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); -#endif - - /* add 'thread_update' command */ -#if TCL_MAJOR_VERSION >= 8 - DUMP1("Tcl_CreateObjCommand(\"thread_update\")"); - Tcl_CreateObjCommand(interp, "thread_update", ip_rb_threadUpdateObjCmd, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); -#else /* TCL_MAJOR_VERSION < 8 */ - DUMP1("Tcl_CreateCommand(\"thread_update\")"); - Tcl_CreateCommand(interp, "thread_update", ip_rb_threadUpdateCommand, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); -#endif -} - - - -#if TCL_MAJOR_VERSION >= 8 -static int ip_rbNamespaceObjCmd _((ClientData, Tcl_Interp *, int, - Tcl_Obj *CONST [])); -static int -ip_rbNamespaceObjCmd(clientData, interp, objc, objv) - ClientData clientData; - Tcl_Interp *interp; - int objc; - Tcl_Obj *CONST objv[]; -{ - Tcl_CmdInfo info; - int ret; - - if (!Tcl_GetCommandInfo(interp, "__orig_namespace_command__", &(info))) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, - "invalid command name \"namespace\"", (char*)NULL); - return TCL_ERROR; - } - - rbtk_eventloop_depth++; - DUMP2("namespace wrapper enter depth == %d", rbtk_eventloop_depth); - - if (info.isNativeObjectProc) { - ret = (*(info.objProc))(info.objClientData, interp, objc, objv); - } else { - /* string interface */ - int i; - char **argv; - - /* argv = (char **)Tcl_Alloc(sizeof(char *) * (objc + 1)); */ - argv = (char **)ckalloc(sizeof(char *) * (objc + 1)); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ -#endif - - for(i = 0; i < objc; i++) { - /* argv[i] = Tcl_GetString(objv[i]); */ - argv[i] = Tcl_GetStringFromObj(objv[i], (int*)NULL); - } - argv[objc] = (char *)NULL; - - ret = (*(info.proc))(info.clientData, interp, - objc, (CONST84 char **)argv); - -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)argv); /* XXXXXXXX */ -#else - /* Tcl_Free((char*)argv); */ - ckfree((char*)argv); -#endif -#endif - } - - DUMP2("namespace wrapper exit depth == %d", rbtk_eventloop_depth); - rbtk_eventloop_depth--; - - return ret; -} -#endif - -static void -ip_wrap_namespace_command(interp) - Tcl_Interp *interp; -{ -#if TCL_MAJOR_VERSION >= 8 - Tcl_CmdInfo orig_info; - - if (!Tcl_GetCommandInfo(interp, "namespace", &(orig_info))) { - return; - } - - if (orig_info.isNativeObjectProc) { - Tcl_CreateObjCommand(interp, "__orig_namespace_command__", - orig_info.objProc, orig_info.objClientData, - orig_info.deleteProc); - } else { - Tcl_CreateCommand(interp, "__orig_namespace_command__", - orig_info.proc, orig_info.clientData, - orig_info.deleteProc); - } - - Tcl_CreateObjCommand(interp, "namespace", ip_rbNamespaceObjCmd, - (ClientData) 0, (Tcl_CmdDeleteProc *)NULL); -#endif -} - - -/* call when interpreter is deleted */ -static void -ip_CallWhenDeleted(clientData, ip) - ClientData clientData; - Tcl_Interp *ip; -{ - int thr_crit_bup; - /* Tk_Window main_win = (Tk_Window) clientData; */ - - DUMP1("start ip_CallWhenDeleted"); - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - ip_finalize(ip); - - DUMP1("finish ip_CallWhenDeleted"); - rb_thread_critical = thr_crit_bup; -} - -/* initialize interpreter */ -static VALUE -ip_init(argc, argv, self) - int argc; - VALUE *argv; - VALUE self; -{ - struct tcltkip *ptr; /* tcltkip data struct */ - VALUE argv0, opts; - int cnt; - int st; - int with_tk = 1; - Tk_Window mainWin = (Tk_Window)NULL; - - /* security check */ - if (rb_safe_level() >= 4) { - rb_raise(rb_eSecurityError, - "Cannot create a TclTkIp object at level %d", - rb_safe_level()); - } - - /* create object */ - Data_Get_Struct(self, struct tcltkip, ptr); - ptr = ALLOC(struct tcltkip); - /* ptr = (struct tcltkip *)ckalloc(sizeof(struct tcltkip)); */ - DATA_PTR(self) = ptr; -#ifdef RUBY_USE_NATIVE_THREAD - ptr->tk_thread_id = 0; -#endif - ptr->ref_count = 0; - ptr->allow_ruby_exit = 1; - ptr->return_value = 0; - - /* from Tk_Main() */ - DUMP1("Tcl_CreateInterp"); - ptr->ip = ruby_tcl_create_ip_and_stubs_init(&st); - if (ptr->ip == NULL) { - switch(st) { - case TCLTK_STUBS_OK: - break; - case NO_TCL_DLL: - rb_raise(rb_eLoadError, "tcltklib: fail to open tcl_dll"); - case NO_FindExecutable: - rb_raise(rb_eLoadError, "tcltklib: can't find Tcl_FindExecutable"); - case NO_CreateInterp: - rb_raise(rb_eLoadError, "tcltklib: can't find Tcl_CreateInterp()"); - case NO_DeleteInterp: - rb_raise(rb_eLoadError, "tcltklib: can't find Tcl_DeleteInterp()"); - case FAIL_CreateInterp: - rb_raise(rb_eRuntimeError, "tcltklib: fail to create a new IP"); - case FAIL_Tcl_InitStubs: - rb_raise(rb_eRuntimeError, "tcltklib: fail to Tcl_InitStubs()"); - default: - rb_raise(rb_eRuntimeError, "tcltklib: unknown error(%d) on ruby_tcl_create_ip_and_stubs_init", st); - } - } - -#if TCL_MAJOR_VERSION >= 8 -#if TCL_NAMESPACE_DEBUG - DUMP1("get current namespace"); - if ((ptr->default_ns = Tcl_GetCurrentNamespace(ptr->ip)) - == (Tcl_Namespace*)NULL) { - rb_raise(rb_eRuntimeError, "a new Tk interpreter has a NULL namespace"); - } -#endif -#endif - - rbtk_preserve_ip(ptr); - DUMP2("IP ref_count = %d", ptr->ref_count); - current_interp = ptr->ip; - - ptr->has_orig_exit - = Tcl_GetCommandInfo(ptr->ip, "exit", &(ptr->orig_exit_info)); - - /* from Tcl_AppInit() */ - DUMP1("Tcl_Init"); - if (Tcl_Init(ptr->ip) == TCL_ERROR) { - rb_raise(rb_eRuntimeError, "%s", Tcl_GetStringResult(ptr->ip)); - } - - /* set variables */ - cnt = rb_scan_args(argc, argv, "02", &argv0, &opts); - switch(cnt) { - case 2: - /* options */ - if (NIL_P(opts) || opts == Qfalse) { - /* without Tk */ - with_tk = 0; - } else { - /* Tcl_SetVar(ptr->ip, "argv", StringValuePtr(opts), 0); */ - Tcl_SetVar(ptr->ip, "argv", StringValuePtr(opts), TCL_GLOBAL_ONLY); - } - case 1: - /* argv0 */ - if (!NIL_P(argv0)) { - if (strncmp(StringValuePtr(argv0), "-e", 3) == 0 - || strncmp(StringValuePtr(argv0), "-", 2) == 0) { - Tcl_SetVar(ptr->ip, "argv0", "ruby", TCL_GLOBAL_ONLY); - } else { - /* Tcl_SetVar(ptr->ip, "argv0", StringValuePtr(argv0), 0); */ - Tcl_SetVar(ptr->ip, "argv0", StringValuePtr(argv0), - TCL_GLOBAL_ONLY); - } - } - case 0: - /* no args */ - ; - } - - /* from Tcl_AppInit() */ - if (with_tk) { - DUMP1("Tk_Init"); - st = ruby_tk_stubs_init(ptr->ip); - switch(st) { - case TCLTK_STUBS_OK: - break; - case NO_Tk_Init: - rb_raise(rb_eLoadError, "tcltklib: can't find Tk_Init()"); - case FAIL_Tk_Init: - rb_raise(rb_eRuntimeError, "tcltklib: fail to Tk_Init(). %s", - Tcl_GetStringResult(ptr->ip)); - case FAIL_Tk_InitStubs: - rb_raise(rb_eRuntimeError, "tcltklib: fail to Tk_InitStubs(). %s", - Tcl_GetStringResult(ptr->ip)); - default: - rb_raise(rb_eRuntimeError, "tcltklib: unknown error(%d) on ruby_tk_stubs_init", st); - } - - DUMP1("Tcl_StaticPackage(\"Tk\")"); -#if TCL_MAJOR_VERSION >= 8 - Tcl_StaticPackage(ptr->ip, "Tk", Tk_Init, Tk_SafeInit); -#else /* TCL_MAJOR_VERSION < 8 */ - Tcl_StaticPackage(ptr->ip, "Tk", Tk_Init, - (Tcl_PackageInitProc *) NULL); -#endif - -#ifdef RUBY_USE_NATIVE_THREAD - /* set Tk thread ID */ - ptr->tk_thread_id = Tcl_GetCurrentThread(); -#endif - /* get main window */ - mainWin = Tk_MainWindow(ptr->ip); - Tk_Preserve((ClientData)mainWin); - } - - /* add ruby command to the interpreter */ -#if TCL_MAJOR_VERSION >= 8 - DUMP1("Tcl_CreateObjCommand(\"ruby\")"); - Tcl_CreateObjCommand(ptr->ip, "ruby", ip_ruby_eval, (ClientData)NULL, - (Tcl_CmdDeleteProc *)NULL); - DUMP1("Tcl_CreateObjCommand(\"ruby_eval\")"); - Tcl_CreateObjCommand(ptr->ip, "ruby_eval", ip_ruby_eval, (ClientData)NULL, - (Tcl_CmdDeleteProc *)NULL); - DUMP1("Tcl_CreateObjCommand(\"ruby_cmd\")"); - Tcl_CreateObjCommand(ptr->ip, "ruby_cmd", ip_ruby_cmd, (ClientData)NULL, - (Tcl_CmdDeleteProc *)NULL); -#else /* TCL_MAJOR_VERSION < 8 */ - DUMP1("Tcl_CreateCommand(\"ruby\")"); - Tcl_CreateCommand(ptr->ip, "ruby", ip_ruby_eval, (ClientData)NULL, - (Tcl_CmdDeleteProc *)NULL); - DUMP1("Tcl_CreateCommand(\"ruby_eval\")"); - Tcl_CreateCommand(ptr->ip, "ruby_eval", ip_ruby_eval, (ClientData)NULL, - (Tcl_CmdDeleteProc *)NULL); - DUMP1("Tcl_CreateCommand(\"ruby_cmd\")"); - Tcl_CreateCommand(ptr->ip, "ruby_cmd", ip_ruby_cmd, (ClientData)NULL, - (Tcl_CmdDeleteProc *)NULL); -#endif - - /* add 'interp_exit', 'ruby_exit' and replace 'exit' command */ -#if TCL_MAJOR_VERSION >= 8 - DUMP1("Tcl_CreateObjCommand(\"interp_exit\")"); - Tcl_CreateObjCommand(ptr->ip, "interp_exit", ip_InterpExitObjCmd, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); - DUMP1("Tcl_CreateObjCommand(\"ruby_exit\")"); - Tcl_CreateObjCommand(ptr->ip, "ruby_exit", ip_RubyExitObjCmd, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); - DUMP1("Tcl_CreateObjCommand(\"exit\") --> \"ruby_exit\""); - Tcl_CreateObjCommand(ptr->ip, "exit", ip_RubyExitObjCmd, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); -#else /* TCL_MAJOR_VERSION < 8 */ - DUMP1("Tcl_CreateCommand(\"interp_exit\")"); - Tcl_CreateCommand(ptr->ip, "interp_exit", ip_InterpExitCommand, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); - DUMP1("Tcl_CreateCommand(\"ruby_exit\")"); - Tcl_CreateCommand(ptr->ip, "ruby_exit", ip_RubyExitCommand, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); - DUMP1("Tcl_CreateCommand(\"exit\") --> \"ruby_exit\""); - Tcl_CreateCommand(ptr->ip, "exit", ip_RubyExitCommand, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); -#endif - - /* replace vwait and tkwait */ - ip_replace_wait_commands(ptr->ip, mainWin); - - /* wrap namespace command */ - ip_wrap_namespace_command(ptr->ip); - - /* set finalizer */ - Tcl_CallWhenDeleted(ptr->ip, ip_CallWhenDeleted, (ClientData)mainWin); - - if (mainWin != (Tk_Window)NULL) { - Tk_Release((ClientData)mainWin); - } - - return self; -} - -static VALUE -ip_create_slave_core(interp, argc, argv) - VALUE interp; - int argc; - VALUE *argv; -{ - struct tcltkip *master = get_ip(interp); - struct tcltkip *slave = ALLOC(struct tcltkip); - /* struct tcltkip *slave = (struct tcltkip *)ckalloc(sizeof(struct tcltkip)); */ - VALUE safemode; - VALUE name; - int safe; - int thr_crit_bup; - Tk_Window mainWin; - - /* ip is deleted? */ - if (deleted_ip(master)) { - return rb_exc_new2(rb_eRuntimeError, - "deleted master cannot create a new slave"); - } - - name = argv[0]; - safemode = argv[1]; - - if (Tcl_IsSafe(master->ip) == 1) { - safe = 1; - } else if (safemode == Qfalse || NIL_P(safemode)) { - safe = 0; - /* rb_secure(4); */ /* already checked */ - } else { - safe = 1; - } - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - -#if 0 - /* init Tk */ - if (RTEST(with_tk)) { - volatile VALUE exc; - if (!tk_stubs_init_p()) { - exc = tcltkip_init_tk(interp); - if (!NIL_P(exc)) { - rb_thread_critical = thr_crit_bup; - return exc; - } - } - } -#endif - - /* create slave-ip */ -#ifdef RUBY_USE_NATIVE_THREAD - /* slave->tk_thread_id = 0; */ - slave->tk_thread_id = master->tk_thread_id; /* == current thread */ -#endif - slave->ref_count = 0; - slave->allow_ruby_exit = 0; - slave->return_value = 0; - - slave->ip = Tcl_CreateSlave(master->ip, StringValuePtr(name), safe); - if (slave->ip == NULL) { - rb_thread_critical = thr_crit_bup; - return rb_exc_new2(rb_eRuntimeError, - "fail to create the new slave interpreter"); - } -#if TCL_MAJOR_VERSION >= 8 -#if TCL_NAMESPACE_DEBUG - slave->default_ns = Tcl_GetCurrentNamespace(slave->ip); -#endif -#endif - rbtk_preserve_ip(slave); - - slave->has_orig_exit - = Tcl_GetCommandInfo(slave->ip, "exit", &(slave->orig_exit_info)); - - /* replace 'exit' command --> 'interp_exit' command */ - mainWin = (tk_stubs_init_p())? Tk_MainWindow(slave->ip): (Tk_Window)NULL; -#if TCL_MAJOR_VERSION >= 8 - DUMP1("Tcl_CreateObjCommand(\"exit\") --> \"interp_exit\""); - Tcl_CreateObjCommand(slave->ip, "exit", ip_InterpExitObjCmd, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); -#else /* TCL_MAJOR_VERSION < 8 */ - DUMP1("Tcl_CreateCommand(\"exit\") --> \"interp_exit\""); - Tcl_CreateCommand(slave->ip, "exit", ip_InterpExitCommand, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); -#endif - - /* replace vwait and tkwait */ - ip_replace_wait_commands(slave->ip, mainWin); - - /* wrap namespace command */ - ip_wrap_namespace_command(slave->ip); - - /* set finalizer */ - Tcl_CallWhenDeleted(slave->ip, ip_CallWhenDeleted, (ClientData)mainWin); - - rb_thread_critical = thr_crit_bup; - - return Data_Wrap_Struct(CLASS_OF(interp), 0, ip_free, slave); -} - -static VALUE -ip_create_slave(argc, argv, self) - int argc; - VALUE *argv; - VALUE self; -{ - struct tcltkip *master = get_ip(self); - VALUE safemode; - VALUE name; - VALUE callargv[2]; - - /* ip is deleted? */ - if (deleted_ip(master)) { - rb_raise(rb_eRuntimeError, - "deleted master cannot create a new slave interpreter"); - } - - /* argument check */ - if (rb_scan_args(argc, argv, "11", &name, &safemode) == 1) { - safemode = Qfalse; - } - if (Tcl_IsSafe(master->ip) != 1 - && (safemode == Qfalse || NIL_P(safemode))) { - rb_secure(4); - } - - StringValue(name); - callargv[0] = name; - callargv[1] = safemode; - - return tk_funcall(ip_create_slave_core, 2, callargv, self); -} - - -/* self is slave of master? */ -static VALUE -ip_is_slave_of_p(self, master) - VALUE self, master; -{ - if (!rb_obj_is_kind_of(master, tcltkip_class)) { - rb_raise(rb_eArgError, "expected TclTkIp object"); - } - - if (Tcl_GetMaster(get_ip(self)->ip) == get_ip(master)->ip) { - return Qtrue; - } else { - return Qfalse; - } -} - - -/* create console (if supported) */ -#if defined(MAC_TCL) || defined(__WIN32__) -#if TCL_MAJOR_VERSION < 8 \ - || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0) \ - || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 1 \ - && (TCL_RELEASE_LEVEL == TCL_ALPHA_RELEASE \ - || (TCL_RELEASE_LEVEL == TCL_BETA_RELEASE \ - && TCL_RELEASE_SERIAL < 2) ) ) -EXTERN void TkConsoleCreate _((void)); -#endif -#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 1 \ - && ( (TCL_RELEASE_LEVEL == TCL_FINAL_RELEASE \ - && TCL_RELEASE_SERIAL == 0) \ - || (TCL_RELEASE_LEVEL == TCL_BETA_RELEASE \ - && TCL_RELEASE_SERIAL >= 2) ) -EXTERN void TkConsoleCreate_ _((void)); -#endif -#endif -static VALUE -ip_create_console_core(interp, argc, argv) - VALUE interp; - int argc; /* dummy */ - VALUE *argv; /* dummy */ -{ - struct tcltkip *ptr = get_ip(interp); - - if (!tk_stubs_init_p()) { - tcltkip_init_tk(interp); - } - - if (Tcl_GetVar(ptr->ip,"tcl_interactive",TCL_GLOBAL_ONLY) == (char*)NULL) { - Tcl_SetVar(ptr->ip, "tcl_interactive", "0", TCL_GLOBAL_ONLY); - } - -#if TCL_MAJOR_VERSION > 8 \ - || (TCL_MAJOR_VERSION == 8 \ - && (TCL_MINOR_VERSION > 1 \ - || (TCL_MINOR_VERSION == 1 \ - && TCL_RELEASE_LEVEL == TCL_FINAL_RELEASE \ - && TCL_RELEASE_SERIAL >= 1) ) ) - Tk_InitConsoleChannels(ptr->ip); - - if (Tk_CreateConsoleWindow(ptr->ip) != TCL_OK) { - rb_raise(rb_eRuntimeError, "fail to create console-window"); - } -#else -#if defined(MAC_TCL) || defined(__WIN32__) -#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 1 \ - && ( (TCL_RELEASE_LEVEL == TCL_FINAL_RELEASE && TCL_RELEASE_SERIAL == 0) \ - || (TCL_RELEASE_LEVEL == TCL_BETA_RELEASE && TCL_RELEASE_SERIAL >= 2) ) - TkConsoleCreate_(); -#else - TkConsoleCreate(); -#endif - - if (TkConsoleInit(ptr->ip) != TCL_OK) { - rb_raise(rb_eRuntimeError, "fail to create console-window"); - } -#else - rb_notimplement(); -#endif -#endif - - return interp; -} - -static VALUE -ip_create_console(self) - VALUE self; -{ - struct tcltkip *ptr = get_ip(self); - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - rb_raise(rb_eRuntimeError, "interpreter is deleted"); - } - - return tk_funcall(ip_create_console_core, 0, (VALUE*)NULL, self); -} - -/* make ip "safe" */ -static VALUE -ip_make_safe_core(interp, argc, argv) - VALUE interp; - int argc; /* dummy */ - VALUE *argv; /* dummy */ -{ - struct tcltkip *ptr = get_ip(interp); - Tk_Window mainWin; - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - return rb_exc_new2(rb_eRuntimeError, "interpreter is deleted"); - } - - if (Tcl_MakeSafe(ptr->ip) == TCL_ERROR) { - /* return rb_exc_new2(rb_eRuntimeError, - Tcl_GetStringResult(ptr->ip)); */ - return create_ip_exc(interp, rb_eRuntimeError, - Tcl_GetStringResult(ptr->ip)); - } - - ptr->allow_ruby_exit = 0; - - /* replace 'exit' command --> 'interp_exit' command */ - mainWin = (tk_stubs_init_p())? Tk_MainWindow(ptr->ip): (Tk_Window)NULL; -#if TCL_MAJOR_VERSION >= 8 - DUMP1("Tcl_CreateObjCommand(\"exit\") --> \"interp_exit\""); - Tcl_CreateObjCommand(ptr->ip, "exit", ip_InterpExitObjCmd, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); -#else /* TCL_MAJOR_VERSION < 8 */ - DUMP1("Tcl_CreateCommand(\"exit\") --> \"interp_exit\""); - Tcl_CreateCommand(ptr->ip, "exit", ip_InterpExitCommand, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); -#endif - - return interp; -} - -static VALUE -ip_make_safe(self) - VALUE self; -{ - struct tcltkip *ptr = get_ip(self); - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - rb_raise(rb_eRuntimeError, "interpreter is deleted"); - } - - return tk_funcall(ip_make_safe_core, 0, (VALUE*)NULL, self); -} - -/* is safe? */ -static VALUE -ip_is_safe_p(self) - VALUE self; -{ - struct tcltkip *ptr = get_ip(self); - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - rb_raise(rb_eRuntimeError, "interpreter is deleted"); - } - - if (Tcl_IsSafe(ptr->ip)) { - return Qtrue; - } else { - return Qfalse; - } -} - -/* allow_ruby_exit? */ -static VALUE -ip_allow_ruby_exit_p(self) - VALUE self; -{ - struct tcltkip *ptr = get_ip(self); - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - rb_raise(rb_eRuntimeError, "interpreter is deleted"); - } - - if (ptr->allow_ruby_exit) { - return Qtrue; - } else { - return Qfalse; - } -} - -/* allow_ruby_exit = mode */ -static VALUE -ip_allow_ruby_exit_set(self, val) - VALUE self, val; -{ - struct tcltkip *ptr = get_ip(self); - Tk_Window mainWin; - - rb_secure(4); - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - rb_raise(rb_eRuntimeError, "interpreter is deleted"); - } - - if (Tcl_IsSafe(ptr->ip)) { - rb_raise(rb_eSecurityError, - "insecure operation on a safe interpreter"); - } - - /* - * Because of cross-threading, the following line may fail to find - * the MainWindow, even if the Tcl/Tk interpreter has one or more. - * But it has no problem. Current implementation of both type of - * the "exit" command don't need maiinWin token. - */ - mainWin = (tk_stubs_init_p())? Tk_MainWindow(ptr->ip): (Tk_Window)NULL; - - if (RTEST(val)) { - ptr->allow_ruby_exit = 1; -#if TCL_MAJOR_VERSION >= 8 - DUMP1("Tcl_CreateObjCommand(\"exit\") --> \"ruby_exit\""); - Tcl_CreateObjCommand(ptr->ip, "exit", ip_RubyExitObjCmd, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); -#else /* TCL_MAJOR_VERSION < 8 */ - DUMP1("Tcl_CreateCommand(\"exit\") --> \"ruby_exit\""); - Tcl_CreateCommand(ptr->ip, "exit", ip_RubyExitCommand, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); -#endif - return Qtrue; - - } else { - ptr->allow_ruby_exit = 0; -#if TCL_MAJOR_VERSION >= 8 - DUMP1("Tcl_CreateObjCommand(\"exit\") --> \"interp_exit\""); - Tcl_CreateObjCommand(ptr->ip, "exit", ip_InterpExitObjCmd, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); -#else /* TCL_MAJOR_VERSION < 8 */ - DUMP1("Tcl_CreateCommand(\"exit\") --> \"interp_exit\""); - Tcl_CreateCommand(ptr->ip, "exit", ip_InterpExitCommand, - (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); -#endif - return Qfalse; - } -} - -/* delete interpreter */ -static VALUE -ip_delete(self) - VALUE self; -{ - int thr_crit_bup; - struct tcltkip *ptr = get_ip(self); - - if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL) { - DUMP1("delete deleted IP"); - return Qnil; - } - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - DUMP1("call ip_finalize"); - ip_finalize(ptr->ip); - - DUMP1("delete interp"); - Tcl_DeleteInterp(ptr->ip); - Tcl_Release(ptr->ip); - - rb_thread_critical = thr_crit_bup; - - return Qnil; -} - - -/* is deleted? */ -static VALUE -ip_has_invalid_namespace_p(self) - VALUE self; -{ - struct tcltkip *ptr = get_ip(self); - - if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp *)NULL) { - /* deleted IP */ - return Qtrue; - } - -#if TCL_NAMESPACE_DEBUG - if (rbtk_invalid_namespace(ptr)) { - return Qtrue; - } else { - return Qfalse; - } -#else - return Qfalse; -#endif -} - -static VALUE -ip_is_deleted_p(self) - VALUE self; -{ - struct tcltkip *ptr = get_ip(self); - - if (deleted_ip(ptr)) { - return Qtrue; - } else { - return Qfalse; - } -} - -static VALUE -ip_has_mainwindow_p_core(self, argc, argv) - VALUE self; - int argc; /* dummy */ - VALUE *argv; /* dummy */ -{ - struct tcltkip *ptr = get_ip(self); - - if (deleted_ip(ptr) || !tk_stubs_init_p()) { - return Qnil; - } else if (Tk_MainWindow(ptr->ip) == (Tk_Window)NULL) { - return Qfalse; - } else { - return Qtrue; - } -} - -static VALUE -ip_has_mainwindow_p(self) - VALUE self; -{ - return tk_funcall(ip_has_mainwindow_p_core, 0, (VALUE*)NULL, self); -} - - -/*** ruby string <=> tcl object ***/ -#if TCL_MAJOR_VERSION >= 8 -static VALUE -get_str_from_obj(obj) - Tcl_Obj *obj; -{ - int len, binary = 0; - const char *s; - volatile VALUE str; - -#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0 - s = Tcl_GetStringFromObj(obj, &len); -#else -#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION <= 3 - /* TCL_VERSION 8.1 -- 8.3 */ - if (Tcl_GetCharLength(obj) != Tcl_UniCharLen(Tcl_GetUnicode(obj))) { - /* possibly binary string */ - s = (char *)Tcl_GetByteArrayFromObj(obj, &len); - binary = 1; - } else { - /* possibly text string */ - s = Tcl_GetStringFromObj(obj, &len); - } -#else /* TCL_VERSION >= 8.4 */ - if (IS_TCL_BYTEARRAY(obj)) { - s = (char *)Tcl_GetByteArrayFromObj(obj, &len); - binary = 1; - } else { - s = Tcl_GetStringFromObj(obj, &len); - } - -#endif -#endif - str = s ? rb_str_new(s, len) : rb_str_new2(""); - if (binary) { -#ifdef HAVE_RUBY_ENCODING_H - rb_enc_associate_index(str, ENCODING_INDEX_BINARY); -#endif - rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); -#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1) - } else { -#ifdef HAVE_RUBY_ENCODING_H - rb_enc_associate_index(str, ENCODING_INDEX_UTF8); -#endif - rb_ivar_set(str, ID_at_enc, ENCODING_NAME_UTF8); -#endif - } - return str; -} - -static Tcl_Obj * -get_obj_from_str(str) - VALUE str; -{ - const char *s = StringValuePtr(str); - -#if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0 - return Tcl_NewStringObj((char*)s, RSTRING_LEN(str)); -#else /* TCL_VERSION >= 8.1 */ - VALUE enc = rb_attr_get(str, ID_at_enc); - - if (!NIL_P(enc)) { - StringValue(enc); - if (strcmp(RSTRING_PTR(enc), "binary") == 0) { - /* binary string */ - return Tcl_NewByteArrayObj((const unsigned char *)s, RSTRING_LEN(str)); - } else { - /* text string */ - return Tcl_NewStringObj(s, RSTRING_LEN(str)); - } -#ifdef HAVE_RUBY_ENCODING_H - } else if (rb_enc_get_index(str) == ENCODING_INDEX_BINARY) { - /* binary string */ - return Tcl_NewByteArrayObj((const unsigned char *)s, RSTRING_LEN(str)); -#endif - } else if (strlen(s) != RSTRING_LEN(str)) { - /* probably binary string */ - return Tcl_NewByteArrayObj((const unsigned char *)s, RSTRING_LEN(str)); - } else { - /* probably text string */ - return Tcl_NewStringObj(s, RSTRING_LEN(str)); - } -#endif -} -#endif /* ruby string <=> tcl object */ - -static VALUE -ip_get_result_string_obj(interp) - Tcl_Interp *interp; -{ -#if TCL_MAJOR_VERSION >= 8 - Tcl_Obj *retObj; - volatile VALUE strval; - - retObj = Tcl_GetObjResult(interp); - Tcl_IncrRefCount(retObj); - strval = get_str_from_obj(retObj); - OBJ_TAINT(strval); - Tcl_ResetResult(interp); - Tcl_DecrRefCount(retObj); - return strval; -#else - return rb_tainted_str_new2(interp->result); -#endif -} - -/* call Tcl/Tk functions on the eventloop thread */ -static VALUE -callq_safelevel_handler(arg, callq) - VALUE arg; - VALUE callq; -{ - struct call_queue *q; - - Data_Get_Struct(callq, struct call_queue, q); - DUMP2("(safe-level handler) $SAFE = %d", q->safe_level); - rb_set_safe_level(q->safe_level); - return((q->func)(q->interp, q->argc, q->argv)); -} - -static int call_queue_handler _((Tcl_Event *, int)); -static int -call_queue_handler(evPtr, flags) - Tcl_Event *evPtr; - int flags; -{ - struct call_queue *q = (struct call_queue *)evPtr; - volatile VALUE ret; - volatile VALUE q_dat; - volatile VALUE thread = q->thread; - struct tcltkip *ptr; - - DUMP2("do_call_queue_handler : evPtr = %p", evPtr); - DUMP2("call_queue_handler thread : %lx", rb_thread_current()); - DUMP2("added by thread : %lx", thread); - - if (*(q->done)) { - DUMP1("processed by another event-loop"); - return 0; - } else { - DUMP1("process it on current event-loop"); - } - -#ifdef RUBY_VM - if (RTEST(rb_funcall(thread, ID_alive_p, 0)) - && ! RTEST(rb_funcall(thread, ID_stop_p, 0))) { -#else - if (RTEST(rb_thread_alive_p(thread)) - && ! RTEST(rb_funcall(thread, ID_stop_p, 0))) { -#endif - DUMP1("caller is not yet ready to receive the result -> pending"); - return 0; - } - - /* process it */ - *(q->done) = 1; - - /* deleted ipterp ? */ - ptr = get_ip(q->interp); - if (deleted_ip(ptr)) { - /* deleted IP --> ignore */ - return 1; - } - - /* incr internal handler mark */ - rbtk_internal_eventloop_handler++; - - /* check safe-level */ - if (rb_safe_level() != q->safe_level) { - /* q_dat = Data_Wrap_Struct(rb_cData,0,-1,q); */ - q_dat = Data_Wrap_Struct(rb_cData,call_queue_mark,-1,q); - ret = rb_funcall(rb_proc_new(callq_safelevel_handler, q_dat), - ID_call, 0); - rb_gc_force_recycle(q_dat); - q_dat = (VALUE)NULL; - } else { - DUMP2("call function (for caller thread:%lx)", thread); - DUMP2("call function (current thread:%lx)", rb_thread_current()); - ret = (q->func)(q->interp, q->argc, q->argv); - } - - /* set result */ - RARRAY_PTR(q->result)[0] = ret; - ret = (VALUE)NULL; - - /* decr internal handler mark */ - rbtk_internal_eventloop_handler--; - - /* complete */ - *(q->done) = -1; - - /* unlink ruby objects */ - q->argv = (VALUE*)NULL; - q->interp = (VALUE)NULL; - q->result = (VALUE)NULL; - q->thread = (VALUE)NULL; - - /* back to caller */ -#ifdef RUBY_VM - if (RTEST(rb_funcall(thread, ID_alive_p, 0, 0))) { -#else - if (RTEST(rb_thread_alive_p(thread))) { -#endif - DUMP2("back to caller (caller thread:%lx)", thread); - DUMP2(" (current thread:%lx)", rb_thread_current()); -#if CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE - have_rb_thread_waiting_for_value = 1; - rb_thread_wakeup(thread); -#else - rb_thread_run(thread); -#endif - DUMP1("finish back to caller"); -#if DO_THREAD_SCHEDULE_AT_CALLBACK_DONE - rb_thread_schedule(); -#endif - } else { - DUMP2("caller is dead (caller thread:%lx)", thread); - DUMP2(" (current thread:%lx)", rb_thread_current()); - } - - /* end of handler : remove it */ - return 1; -} - -static VALUE -tk_funcall(func, argc, argv, obj) - VALUE (*func)(); - int argc; - VALUE *argv; - VALUE obj; -{ - struct call_queue *callq; - struct tcltkip *ptr; - int *alloc_done; - int thr_crit_bup; - int is_tk_evloop_thread; - volatile VALUE current = rb_thread_current(); - volatile VALUE ip_obj = obj; - volatile VALUE result; - volatile VALUE ret; - - if (!NIL_P(ip_obj) && rb_obj_is_kind_of(ip_obj, tcltkip_class)) { - ptr = get_ip(ip_obj); - if (deleted_ip(ptr)) return Qnil; - } else { - ptr = (struct tcltkip *)NULL; - } - -#ifdef RUBY_USE_NATIVE_THREAD - if (ptr) { - /* on Tcl interpreter */ - is_tk_evloop_thread = (ptr->tk_thread_id == (Tcl_ThreadId) 0 - || ptr->tk_thread_id == Tcl_GetCurrentThread()); - } else { - /* on Tcl/Tk library */ - is_tk_evloop_thread = (tk_eventloop_thread_id == (Tcl_ThreadId) 0 - || tk_eventloop_thread_id == Tcl_GetCurrentThread()); - } -#else - is_tk_evloop_thread = 1; -#endif - - if (is_tk_evloop_thread - && (NIL_P(eventloop_thread) || current == eventloop_thread) - ) { - if (NIL_P(eventloop_thread)) { - DUMP2("tk_funcall from thread:%lx but no eventloop", current); - } else { - DUMP2("tk_funcall from current eventloop %lx", current); - } - result = (func)(ip_obj, argc, argv); - if (rb_obj_is_kind_of(result, rb_eException)) { - rb_exc_raise(result); - } - return result; - } - - DUMP2("tk_funcall from thread %lx (NOT current eventloop)", current); - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - /* allocate memory (argv cross over thread : must be in heap) */ - if (argv) { - /* VALUE *temp = ALLOC_N(VALUE, argc); */ - VALUE *temp = (VALUE*)ckalloc(sizeof(VALUE) * argc); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)temp); /* XXXXXXXX */ -#endif - MEMCPY(temp, argv, VALUE, argc); - argv = temp; - } - - /* allocate memory (keep result) */ - /* alloc_done = (int*)ALLOC(int); */ - alloc_done = (int*)ckalloc(sizeof(int)); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)alloc_done); /* XXXXXXXX */ -#endif - *alloc_done = 0; - - /* allocate memory (freed by Tcl_ServiceEvent) */ - /* callq = (struct call_queue *)Tcl_Alloc(sizeof(struct call_queue)); */ - callq = (struct call_queue *)ckalloc(sizeof(struct call_queue)); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve(callq); -#endif - - /* allocate result obj */ - result = rb_ary_new3(1, Qnil); - - /* construct event data */ - callq->done = alloc_done; - callq->func = func; - callq->argc = argc; - callq->argv = argv; - callq->interp = ip_obj; - callq->result = result; - callq->thread = current; - callq->safe_level = rb_safe_level(); - callq->ev.proc = call_queue_handler; - - /* add the handler to Tcl event queue */ - DUMP1("add handler"); -#ifdef RUBY_USE_NATIVE_THREAD - if (ptr && ptr->tk_thread_id) { - /* Tcl_ThreadQueueEvent(ptr->tk_thread_id, - &(callq->ev), TCL_QUEUE_HEAD); */ - Tcl_ThreadQueueEvent(ptr->tk_thread_id, - (Tcl_Event*)callq, TCL_QUEUE_HEAD); - Tcl_ThreadAlert(ptr->tk_thread_id); - } else if (tk_eventloop_thread_id) { - /* Tcl_ThreadQueueEvent(tk_eventloop_thread_id, - &(callq->ev), TCL_QUEUE_HEAD); */ - Tcl_ThreadQueueEvent(tk_eventloop_thread_id, - (Tcl_Event*)callq, TCL_QUEUE_HEAD); - Tcl_ThreadAlert(tk_eventloop_thread_id); - } else { - /* Tcl_QueueEvent(&(callq->ev), TCL_QUEUE_HEAD); */ - Tcl_QueueEvent((Tcl_Event*)callq, TCL_QUEUE_HEAD); - } -#else - /* Tcl_QueueEvent(&(callq->ev), TCL_QUEUE_HEAD); */ - Tcl_QueueEvent((Tcl_Event*)callq, TCL_QUEUE_HEAD); -#endif - - rb_thread_critical = thr_crit_bup; - - /* wait for the handler to be processed */ - DUMP2("wait for handler (current thread:%lx)", current); - while(*alloc_done >= 0) { - DUMP2("*** wait for handler (current thread:%lx)", current); - /* rb_thread_stop(); */ - rb_thread_sleep_forever(); - DUMP2("*** wakeup (current thread:%lx)", current); - } - DUMP2("back from handler (current thread:%lx)", current); - - /* get result & free allocated memory */ - ret = RARRAY_PTR(result)[0]; -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)alloc_done, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)alloc_done); /* XXXXXXXX */ -#else - /* free(alloc_done); */ - ckfree((char*)alloc_done); -#endif -#endif - /* if (argv) free(argv); */ - if (argv) { - /* if argv != NULL, alloc as 'temp' */ - int i; - for(i = 0; i < argc; i++) { argv[i] = (VALUE)NULL; } - -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)argv); /* XXXXXXXX */ -#else - ckfree((char*)argv); -#endif -#endif - } - -#if 0 /* callq is freed by Tcl_ServiceEvent */ -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release(callq); -#else - ckfree((char*)callq); -#endif -#endif - - /* exception? */ - if (rb_obj_is_kind_of(ret, rb_eException)) { - DUMP1("raise exception"); - /* rb_exc_raise(ret); */ - rb_exc_raise(rb_exc_new3(rb_obj_class(ret), - rb_funcall(ret, ID_to_s, 0, 0))); - } - - DUMP1("exit tk_funcall"); - return ret; -} - - -/* eval string in tcl by Tcl_Eval() */ -#if TCL_MAJOR_VERSION >= 8 -struct call_eval_info { - struct tcltkip *ptr; - Tcl_Obj *cmd; -}; - -static VALUE -call_tcl_eval(arg) - VALUE arg; -{ - struct call_eval_info *inf = (struct call_eval_info *)arg; - - Tcl_AllowExceptions(inf->ptr->ip); - inf->ptr->return_value = Tcl_EvalObj(inf->ptr->ip, inf->cmd); - - return Qnil; -} -#endif - -static VALUE -ip_eval_real(self, cmd_str, cmd_len) - VALUE self; - char *cmd_str; - int cmd_len; -{ - volatile VALUE ret; - struct tcltkip *ptr = get_ip(self); - int thr_crit_bup; - -#if TCL_MAJOR_VERSION >= 8 - /* call Tcl_EvalObj() */ - { - Tcl_Obj *cmd; - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - cmd = Tcl_NewStringObj(cmd_str, cmd_len); - Tcl_IncrRefCount(cmd); - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - Tcl_DecrRefCount(cmd); - rb_thread_critical = thr_crit_bup; - ptr->return_value = TCL_OK; - return rb_tainted_str_new2(""); - } else { - int status; - struct call_eval_info inf; - - /* Tcl_Preserve(ptr->ip); */ - rbtk_preserve_ip(ptr); - -#if 0 - ptr->return_value = Tcl_EvalObj(ptr->ip, cmd); - /* ptr->return_value = Tcl_GlobalEvalObj(ptr->ip, cmd); */ -#else - inf.ptr = ptr; - inf.cmd = cmd; - ret = rb_protect(call_tcl_eval, (VALUE)&inf, &status); - switch(status) { - case TAG_RAISE: - if (NIL_P(rb_errinfo())) { - rbtk_pending_exception = rb_exc_new2(rb_eException, - "unknown exception"); - } else { - rbtk_pending_exception = rb_errinfo(); - } - break; - - case TAG_FATAL: - if (NIL_P(rb_errinfo())) { - rbtk_pending_exception = rb_exc_new2(rb_eFatal, "FATAL"); - } else { - rbtk_pending_exception = rb_errinfo(); - } - } -#endif - } - - Tcl_DecrRefCount(cmd); - - } - - if (pending_exception_check1(thr_crit_bup, ptr)) { - rbtk_release_ip(ptr); - return rbtk_pending_exception; - } - - /* if (ptr->return_value == TCL_ERROR) { */ - if (ptr->return_value != TCL_OK) { - if (event_loop_abort_on_exc > 0 && !Tcl_InterpDeleted(ptr->ip)) { - volatile VALUE exc; - - switch (ptr->return_value) { - case TCL_RETURN: - exc = create_ip_exc(self, eTkCallbackReturn, - "ip_eval_real receives TCL_RETURN"); - case TCL_BREAK: - exc = create_ip_exc(self, eTkCallbackBreak, - "ip_eval_real receives TCL_BREAK"); - case TCL_CONTINUE: - exc = create_ip_exc(self, eTkCallbackContinue, - "ip_eval_real receives TCL_CONTINUE"); - default: - exc = create_ip_exc(self, rb_eRuntimeError, "%s", - Tcl_GetStringResult(ptr->ip)); - } - - rbtk_release_ip(ptr); - rb_thread_critical = thr_crit_bup; - return exc; - } else { - if (event_loop_abort_on_exc < 0) { - rb_warning("%s (ignore)", Tcl_GetStringResult(ptr->ip)); - } else { - rb_warn("%s (ignore)", Tcl_GetStringResult(ptr->ip)); - } - Tcl_ResetResult(ptr->ip); - rbtk_release_ip(ptr); - rb_thread_critical = thr_crit_bup; - return rb_tainted_str_new2(""); - } - } - - /* pass back the result (as string) */ - ret = ip_get_result_string_obj(ptr->ip); - rbtk_release_ip(ptr); - rb_thread_critical = thr_crit_bup; - return ret; - -#else /* TCL_MAJOR_VERSION < 8 */ - DUMP2("Tcl_Eval(%s)", cmd_str); - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - ptr->return_value = TCL_OK; - return rb_tainted_str_new2(""); - } else { - /* Tcl_Preserve(ptr->ip); */ - rbtk_preserve_ip(ptr); - ptr->return_value = Tcl_Eval(ptr->ip, cmd_str); - /* ptr->return_value = Tcl_GlobalEval(ptr->ip, cmd_str); */ - } - - if (pending_exception_check1(thr_crit_bup, ptr)) { - rbtk_release_ip(ptr); - return rbtk_pending_exception; - } - - /* if (ptr->return_value == TCL_ERROR) { */ - if (ptr->return_value != TCL_OK) { - volatile VALUE exc; - - switch (ptr->return_value) { - case TCL_RETURN: - exc = create_ip_exc(self, eTkCallbackReturn, - "ip_eval_real receives TCL_RETURN"); - case TCL_BREAK: - exc = create_ip_exc(self, eTkCallbackBreak, - "ip_eval_real receives TCL_BREAK"); - case TCL_CONTINUE: - exc = create_ip_exc(self, eTkCallbackContinue, - "ip_eval_real receives TCL_CONTINUE"); - default: - exc = create_ip_exc(self, rb_eRuntimeError, "%s", ptr->ip->result); - } - - rbtk_release_ip(ptr); - return exc; - } - DUMP2("(TCL_Eval result) %d", ptr->return_value); - - /* pass back the result (as string) */ - ret = ip_get_result_string_obj(ptr->ip); - rbtk_release_ip(ptr); - return ret; -#endif -} - -static VALUE -evq_safelevel_handler(arg, evq) - VALUE arg; - VALUE evq; -{ - struct eval_queue *q; - - Data_Get_Struct(evq, struct eval_queue, q); - DUMP2("(safe-level handler) $SAFE = %d", q->safe_level); - rb_set_safe_level(q->safe_level); - return ip_eval_real(q->interp, q->str, q->len); -} - -int eval_queue_handler _((Tcl_Event *, int)); -int -eval_queue_handler(evPtr, flags) - Tcl_Event *evPtr; - int flags; -{ - struct eval_queue *q = (struct eval_queue *)evPtr; - volatile VALUE ret; - volatile VALUE q_dat; - volatile VALUE thread = q->thread; - struct tcltkip *ptr; - - DUMP2("do_eval_queue_handler : evPtr = %p", evPtr); - DUMP2("eval_queue_thread : %lx", rb_thread_current()); - DUMP2("added by thread : %lx", thread); - - if (*(q->done)) { - DUMP1("processed by another event-loop"); - return 0; - } else { - DUMP1("process it on current event-loop"); - } - -#ifdef RUBY_VM - if (RTEST(rb_funcall(thread, ID_alive_p, 0)) - && ! RTEST(rb_funcall(thread, ID_stop_p, 0))) { -#else - if (RTEST(rb_thread_alive_p(thread)) - && ! RTEST(rb_funcall(thread, ID_stop_p, 0))) { -#endif - DUMP1("caller is not yet ready to receive the result -> pending"); - return 0; - } - - /* process it */ - *(q->done) = 1; - - /* deleted ipterp ? */ - ptr = get_ip(q->interp); - if (deleted_ip(ptr)) { - /* deleted IP --> ignore */ - return 1; - } - - /* incr internal handler mark */ - rbtk_internal_eventloop_handler++; - - /* check safe-level */ - if (rb_safe_level() != q->safe_level) { -#ifdef HAVE_NATIVETHREAD -#ifndef RUBY_USE_NATIVE_THREAD - if (!ruby_native_thread_p()) { - rb_bug("cross-thread violation on eval_queue_handler()"); - } -#endif -#endif - /* q_dat = Data_Wrap_Struct(rb_cData,0,-1,q); */ - q_dat = Data_Wrap_Struct(rb_cData,eval_queue_mark,-1,q); - ret = rb_funcall(rb_proc_new(evq_safelevel_handler, q_dat), - ID_call, 0); - rb_gc_force_recycle(q_dat); - q_dat = (VALUE)NULL; - } else { - ret = ip_eval_real(q->interp, q->str, q->len); - } - - /* set result */ - RARRAY_PTR(q->result)[0] = ret; - ret = (VALUE)NULL; - - /* decr internal handler mark */ - rbtk_internal_eventloop_handler--; - - /* complete */ - *(q->done) = -1; - - /* unlink ruby objects */ - q->interp = (VALUE)NULL; - q->result = (VALUE)NULL; - q->thread = (VALUE)NULL; - - /* back to caller */ -#ifdef RUBY_VM - if (RTEST(rb_funcall(thread, ID_alive_p, 0, 0))) { -#else - if (RTEST(rb_thread_alive_p(thread))) { -#endif - DUMP2("back to caller (caller thread:%lx)", thread); - DUMP2(" (current thread:%lx)", rb_thread_current()); -#if CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE - have_rb_thread_waiting_for_value = 1; - rb_thread_wakeup(thread); -#else - rb_thread_run(thread); -#endif - DUMP1("finish back to caller"); -#if DO_THREAD_SCHEDULE_AT_CALLBACK_DONE - rb_thread_schedule(); -#endif - } else { - DUMP2("caller is dead (caller thread:%lx)", thread); - DUMP2(" (current thread:%lx)", rb_thread_current()); - } - - /* end of handler : remove it */ - return 1; -} - -static VALUE -ip_eval(self, str) - VALUE self; - VALUE str; -{ - struct eval_queue *evq; -#ifdef RUBY_USE_NATIVE_THREAD - struct tcltkip *ptr; -#endif - char *eval_str; - int *alloc_done; - int thr_crit_bup; - volatile VALUE current = rb_thread_current(); - volatile VALUE ip_obj = self; - volatile VALUE result; - volatile VALUE ret; - Tcl_QueuePosition position; - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - StringValue(str); - rb_thread_critical = thr_crit_bup; - -#ifdef RUBY_USE_NATIVE_THREAD - ptr = get_ip(ip_obj); -#endif - - if ( -#ifdef RUBY_USE_NATIVE_THREAD - (ptr->tk_thread_id == 0 || ptr->tk_thread_id == Tcl_GetCurrentThread()) - && -#endif - (NIL_P(eventloop_thread) || current == eventloop_thread) - ) { - if (NIL_P(eventloop_thread)) { - DUMP2("eval from thread:%lx but no eventloop", current); - } else { - DUMP2("eval from current eventloop %lx", current); - } - result = ip_eval_real(self, RSTRING_PTR(str), RSTRING_LEN(str)); - if (rb_obj_is_kind_of(result, rb_eException)) { - rb_exc_raise(result); - } - return result; - } - - DUMP2("eval from thread %lx (NOT current eventloop)", current); - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - /* allocate memory (keep result) */ - /* alloc_done = (int*)ALLOC(int); */ - alloc_done = (int*)ckalloc(sizeof(int)); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)alloc_done); /* XXXXXXXX */ -#endif - *alloc_done = 0; - - /* eval_str = ALLOC_N(char, RSTRING_LEN(str) + 1); */ - eval_str = ckalloc(sizeof(char) * (RSTRING_LEN(str) + 1)); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)eval_str); /* XXXXXXXX */ -#endif - memcpy(eval_str, RSTRING_PTR(str), RSTRING_LEN(str)); - eval_str[RSTRING_LEN(str)] = 0; - - /* allocate memory (freed by Tcl_ServiceEvent) */ - /* evq = (struct eval_queue *)Tcl_Alloc(sizeof(struct eval_queue)); */ - evq = (struct eval_queue *)ckalloc(sizeof(struct eval_queue)); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve(evq); -#endif - - /* allocate result obj */ - result = rb_ary_new3(1, Qnil); - - /* construct event data */ - evq->done = alloc_done; - evq->str = eval_str; - evq->len = RSTRING_LEN(str); - evq->interp = ip_obj; - evq->result = result; - evq->thread = current; - evq->safe_level = rb_safe_level(); - evq->ev.proc = eval_queue_handler; - - position = TCL_QUEUE_TAIL; - - /* add the handler to Tcl event queue */ - DUMP1("add handler"); -#ifdef RUBY_USE_NATIVE_THREAD - if (ptr->tk_thread_id) { - /* Tcl_ThreadQueueEvent(ptr->tk_thread_id, &(evq->ev), position); */ - Tcl_ThreadQueueEvent(ptr->tk_thread_id, (Tcl_Event*)evq, position); - Tcl_ThreadAlert(ptr->tk_thread_id); - } else if (tk_eventloop_thread_id) { - Tcl_ThreadQueueEvent(tk_eventloop_thread_id, (Tcl_Event*)evq, position); - /* Tcl_ThreadQueueEvent(tk_eventloop_thread_id, - &(evq->ev), position); */ - Tcl_ThreadAlert(tk_eventloop_thread_id); - } else { - /* Tcl_QueueEvent(&(evq->ev), position); */ - Tcl_QueueEvent((Tcl_Event*)evq, position); - } -#else - /* Tcl_QueueEvent(&(evq->ev), position); */ - Tcl_QueueEvent((Tcl_Event*)evq, position); -#endif - - rb_thread_critical = thr_crit_bup; - - /* wait for the handler to be processed */ - DUMP2("wait for handler (current thread:%lx)", current); - while(*alloc_done >= 0) { - DUMP2("*** wait for handler (current thread:%lx)", current); - /* rb_thread_stop(); */ - rb_thread_sleep_forever(); - DUMP2("*** wakeup (current thread:%lx)", current); - } - DUMP2("back from handler (current thread:%lx)", current); - - /* get result & free allocated memory */ - ret = RARRAY_PTR(result)[0]; - -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)alloc_done, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)alloc_done); /* XXXXXXXX */ -#else - /* free(alloc_done); */ - ckfree((char*)alloc_done); -#endif -#endif -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)eval_str, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)eval_str); /* XXXXXXXX */ -#else - /* free(eval_str); */ - ckfree(eval_str); -#endif -#endif -#if 0 /* evq is freed by Tcl_ServiceEvent */ -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release(evq); -#else - ckfree((char*)evq); -#endif -#endif - - if (rb_obj_is_kind_of(ret, rb_eException)) { - DUMP1("raise exception"); - /* rb_exc_raise(ret); */ - rb_exc_raise(rb_exc_new3(rb_obj_class(ret), - rb_funcall(ret, ID_to_s, 0, 0))); - } - - return ret; -} - - -/* restart Tk */ -static VALUE -lib_restart_core(interp, argc, argv) - VALUE interp; - int argc; /* dummy */ - VALUE *argv; /* dummy */ -{ - volatile VALUE exc; - struct tcltkip *ptr = get_ip(interp); - int thr_crit_bup; - - /* rb_secure(4); */ /* already checked */ - - /* tcl_stubs_check(); */ /* already checked */ - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - return rb_exc_new2(rb_eRuntimeError, "interpreter is deleted"); - } - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - /* Tcl_Preserve(ptr->ip); */ - rbtk_preserve_ip(ptr); - - /* destroy the root wdiget */ - ptr->return_value = Tcl_Eval(ptr->ip, "destroy ."); - /* ignore ERROR */ - DUMP2("(TCL_Eval result) %d", ptr->return_value); - Tcl_ResetResult(ptr->ip); - -#if TCL_MAJOR_VERSION >= 8 - /* delete namespace ( tested on tk8.4.5 ) */ - ptr->return_value = Tcl_Eval(ptr->ip, "namespace delete ::tk::msgcat"); - /* ignore ERROR */ - DUMP2("(TCL_Eval result) %d", ptr->return_value); - Tcl_ResetResult(ptr->ip); -#endif - - /* delete trace proc ( tested on tk8.4.5 ) */ - ptr->return_value = Tcl_Eval(ptr->ip, "trace vdelete ::tk_strictMotif w ::tk::EventMotifBindings"); - /* ignore ERROR */ - DUMP2("(TCL_Eval result) %d", ptr->return_value); - Tcl_ResetResult(ptr->ip); - - /* execute Tk_Init or Tk_SafeInit */ - exc = tcltkip_init_tk(interp); - if (!NIL_P(exc)) { - rb_thread_critical = thr_crit_bup; - rbtk_release_ip(ptr); - return exc; - } - - /* Tcl_Release(ptr->ip); */ - rbtk_release_ip(ptr); - - rb_thread_critical = thr_crit_bup; - - /* return Qnil; */ - return interp; -} - -static VALUE -lib_restart(self) - VALUE self; -{ - struct tcltkip *ptr = get_ip(self); - - rb_secure(4); - - tcl_stubs_check(); - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - rb_raise(rb_eRuntimeError, "interpreter is deleted"); - } - - return tk_funcall(lib_restart_core, 0, (VALUE*)NULL, self); -} - - -static VALUE -ip_restart(self) - VALUE self; -{ - struct tcltkip *ptr = get_ip(self); - - rb_secure(4); - - tcl_stubs_check(); - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - rb_raise(rb_eRuntimeError, "interpreter is deleted"); - } - - if (Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL) { - /* slave IP */ - return Qnil; - } - return lib_restart(self); -} - -static VALUE -lib_toUTF8_core(ip_obj, src, encodename) - VALUE ip_obj; - VALUE src; - VALUE encodename; -{ - volatile VALUE str = src; - -#ifdef TCL_UTF_MAX - Tcl_Interp *interp; - Tcl_Encoding encoding; - Tcl_DString dstr; - int taint_flag = OBJ_TAINTED(str); - struct tcltkip *ptr; - char *buf; - int thr_crit_bup; -#endif - - tcl_stubs_check(); - - if (NIL_P(src)) { - return rb_str_new2(""); - } - -#ifdef TCL_UTF_MAX - if (NIL_P(ip_obj)) { - interp = (Tcl_Interp *)NULL; - } else { - ptr = get_ip(ip_obj); - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - interp = (Tcl_Interp *)NULL; - } else { - interp = ptr->ip; - } - } - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - if (NIL_P(encodename)) { - if (TYPE(str) == T_STRING) { - volatile VALUE enc; - -#ifdef HAVE_RUBY_ENCODING_H - enc = rb_funcall(rb_obj_encoding(str), ID_to_s, 0, 0); -#else - enc = rb_attr_get(str, ID_at_enc); -#endif - if (NIL_P(enc)) { - if (NIL_P(ip_obj)) { - encoding = (Tcl_Encoding)NULL; - } else { - enc = rb_attr_get(ip_obj, ID_at_enc); - if (NIL_P(enc)) { - encoding = (Tcl_Encoding)NULL; - } else { - /* StringValue(enc); */ - enc = rb_funcall(enc, ID_to_s, 0, 0); - /* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); */ - if (!RSTRING_LEN(enc)) { - encoding = (Tcl_Encoding)NULL; - } else { - encoding = Tcl_GetEncoding((Tcl_Interp*)NULL, - RSTRING_PTR(enc)); - if (encoding == (Tcl_Encoding)NULL) { - rb_warning("Tk-interp has unknown encoding information (@encoding:'%s')", RSTRING_PTR(enc)); - } - } - } - } - } else { - StringValue(enc); - if (strcmp(RSTRING_PTR(enc), "binary") == 0) { -#ifdef HAVE_RUBY_ENCODING_H - rb_enc_associate_index(str, ENCODING_INDEX_BINARY); -#endif - rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); - rb_thread_critical = thr_crit_bup; - return str; - } - /* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); */ - encoding = Tcl_GetEncoding((Tcl_Interp*)NULL, - RSTRING_PTR(enc)); - if (encoding == (Tcl_Encoding)NULL) { - rb_warning("string has unknown encoding information (@encoding:'%s')", RSTRING_PTR(enc)); - } - } - } else { - encoding = (Tcl_Encoding)NULL; - } - } else { - StringValue(encodename); - if (strcmp(RSTRING_PTR(encodename), "binary") == 0) { -#ifdef HAVE_RUBY_ENCODING_H - rb_enc_associate_index(str, ENCODING_INDEX_BINARY); -#endif - rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); - rb_thread_critical = thr_crit_bup; - return str; - } - /* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(encodename)); */ - encoding = Tcl_GetEncoding((Tcl_Interp*)NULL, RSTRING_PTR(encodename)); - if (encoding == (Tcl_Encoding)NULL) { - /* - rb_warning("unknown encoding name '%s'", - RSTRING_PTR(encodename)); - */ - rb_raise(rb_eArgError, "unknown encoding name '%s'", - RSTRING_PTR(encodename)); - } - } - - StringValue(str); - if (!RSTRING_LEN(str)) { - rb_thread_critical = thr_crit_bup; - return str; - } - buf = ALLOC_N(char, RSTRING_LEN(str)+1); - /* buf = ckalloc(sizeof(char) * (RSTRING_LEN(str)+1)); */ - memcpy(buf, RSTRING_PTR(str), RSTRING_LEN(str)); - buf[RSTRING_LEN(str)] = 0; - - Tcl_DStringInit(&dstr); - Tcl_DStringFree(&dstr); - /* Tcl_ExternalToUtfDString(encoding,buf,strlen(buf),&dstr); */ - Tcl_ExternalToUtfDString(encoding, buf, RSTRING_LEN(str), &dstr); - - /* str = rb_tainted_str_new2(Tcl_DStringValue(&dstr)); */ - /* str = rb_str_new2(Tcl_DStringValue(&dstr)); */ - str = rb_str_new(Tcl_DStringValue(&dstr), Tcl_DStringLength(&dstr)); -#ifdef HAVE_RUBY_ENCODING_H - rb_enc_associate_index(str, ENCODING_INDEX_UTF8); -#endif - rb_ivar_set(str, ID_at_enc, ENCODING_NAME_UTF8); - if (taint_flag) OBJ_TAINT(str); - - /* - if (encoding != (Tcl_Encoding)NULL) { - Tcl_FreeEncoding(encoding); - } - */ - Tcl_DStringFree(&dstr); - - free(buf); - /* ckfree(buf); */ - - rb_thread_critical = thr_crit_bup; -#endif - - return str; -} - -static VALUE -lib_toUTF8(argc, argv, self) - int argc; - VALUE *argv; - VALUE self; -{ - VALUE str, encodename; - - if (rb_scan_args(argc, argv, "11", &str, &encodename) == 1) { - encodename = Qnil; - } - return lib_toUTF8_core(Qnil, str, encodename); -} - -static VALUE -ip_toUTF8(argc, argv, self) - int argc; - VALUE *argv; - VALUE self; -{ - VALUE str, encodename; - - if (rb_scan_args(argc, argv, "11", &str, &encodename) == 1) { - encodename = Qnil; - } - return lib_toUTF8_core(self, str, encodename); -} - -static VALUE -lib_fromUTF8_core(ip_obj, src, encodename) - VALUE ip_obj; - VALUE src; - VALUE encodename; -{ - volatile VALUE str = src; - -#ifdef TCL_UTF_MAX - Tcl_Interp *interp; - Tcl_Encoding encoding; - Tcl_DString dstr; - int taint_flag = OBJ_TAINTED(str); - char *buf; - int thr_crit_bup; -#endif - - tcl_stubs_check(); - - if (NIL_P(src)) { - return rb_str_new2(""); - } - -#ifdef TCL_UTF_MAX - if (NIL_P(ip_obj)) { - interp = (Tcl_Interp *)NULL; - } else if (get_ip(ip_obj) == (struct tcltkip *)NULL) { - interp = (Tcl_Interp *)NULL; - } else { - interp = get_ip(ip_obj)->ip; - } - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - if (NIL_P(encodename)) { - volatile VALUE enc; - - if (TYPE(str) == T_STRING) { - enc = rb_attr_get(str, ID_at_enc); - if (!NIL_P(enc)) { - StringValue(enc); - if (strcmp(RSTRING_PTR(enc), "binary") == 0) { -#ifdef HAVE_RUBY_ENCODING_H - rb_enc_associate_index(str, ENCODING_INDEX_BINARY); -#endif - rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); - rb_thread_critical = thr_crit_bup; - return str; - } -#ifdef HAVE_RUBY_ENCODING_H - } else if (rb_enc_get_index(str) == ENCODING_INDEX_BINARY) { - rb_enc_associate_index(str, ENCODING_INDEX_BINARY); - rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); - rb_thread_critical = thr_crit_bup; - return str; -#endif - } - } - - if (NIL_P(ip_obj)) { - encoding = (Tcl_Encoding)NULL; - } else { - enc = rb_attr_get(ip_obj, ID_at_enc); - if (NIL_P(enc)) { - encoding = (Tcl_Encoding)NULL; - } else { - /* StringValue(enc); */ - enc = rb_funcall(enc, ID_to_s, 0, 0); - /* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); */ - if (!RSTRING_LEN(enc)) { - encoding = (Tcl_Encoding)NULL; - } else { - encoding = Tcl_GetEncoding((Tcl_Interp*)NULL, - RSTRING_PTR(enc)); - if (encoding == (Tcl_Encoding)NULL) { - rb_warning("Tk-interp has unknown encoding information (@encoding:'%s')", RSTRING_PTR(enc)); - } else { - encodename = rb_obj_dup(enc); - } - } - } - } - - } else { - StringValue(encodename); - - if (strcmp(RSTRING_PTR(encodename), "binary") == 0) { - Tcl_Obj *tclstr; - char *s; - int len; - - StringValue(str); - tclstr = Tcl_NewStringObj(RSTRING_PTR(str), RSTRING_LEN(str)); - Tcl_IncrRefCount(tclstr); - s = (char*)Tcl_GetByteArrayFromObj(tclstr, &len); - str = rb_tainted_str_new(s, len); - s = (char*)NULL; - Tcl_DecrRefCount(tclstr); -#ifdef HAVE_RUBY_ENCODING_H - rb_enc_associate_index(str, ENCODING_INDEX_BINARY); -#endif - rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); - - rb_thread_critical = thr_crit_bup; - return str; - } - - /* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(encodename)); */ - encoding = Tcl_GetEncoding((Tcl_Interp*)NULL, RSTRING_PTR(encodename)); - if (encoding == (Tcl_Encoding)NULL) { - /* - rb_warning("unknown encoding name '%s'", - RSTRING_PTR(encodename)); - encodename = Qnil; - */ - rb_raise(rb_eArgError, "unknown encoding name '%s'", - RSTRING_PTR(encodename)); - } - } - - StringValue(str); - - if (RSTRING_LEN(str) == 0) { - rb_thread_critical = thr_crit_bup; - return rb_tainted_str_new2(""); - } - - buf = ALLOC_N(char, RSTRING_LEN(str)+1); - /* buf = ckalloc(sizeof(char) * (RSTRING_LEN(str)+1)); */ - memcpy(buf, RSTRING_PTR(str), RSTRING_LEN(str)); - buf[RSTRING_LEN(str)] = 0; - - Tcl_DStringInit(&dstr); - Tcl_DStringFree(&dstr); - /* Tcl_UtfToExternalDString(encoding,buf,strlen(buf),&dstr); */ - Tcl_UtfToExternalDString(encoding,buf,RSTRING_LEN(str),&dstr); - - /* str = rb_tainted_str_new2(Tcl_DStringValue(&dstr)); */ - /* str = rb_str_new2(Tcl_DStringValue(&dstr)); */ - str = rb_str_new(Tcl_DStringValue(&dstr), Tcl_DStringLength(&dstr)); -#ifdef HAVE_RUBY_ENCODING_H - if (interp) { - /* can access encoding_table of TclTkIp */ - /* -> try to use encoding_table */ - VALUE tbl = ip_get_encoding_table(ip_obj); - VALUE encobj = encoding_table_get_obj(tbl, encodename); - rb_enc_associate_index(str, rb_to_encoding_index(encobj)); - } else { - /* cannot access encoding_table of TclTkIp */ - /* -> try to find on Ruby Encoding */ - rb_enc_associate_index(str, rb_enc_find_index(RSTRING_PTR(encodename))); - } -#endif - rb_ivar_set(str, ID_at_enc, encodename); - - if (taint_flag) OBJ_TAINT(str); - - /* - if (encoding != (Tcl_Encoding)NULL) { - Tcl_FreeEncoding(encoding); - } - */ - Tcl_DStringFree(&dstr); - - free(buf); - /* ckfree(buf); */ - - rb_thread_critical = thr_crit_bup; -#endif - - return str; -} - -static VALUE -lib_fromUTF8(argc, argv, self) - int argc; - VALUE *argv; - VALUE self; -{ - VALUE str, encodename; - - if (rb_scan_args(argc, argv, "11", &str, &encodename) == 1) { - encodename = Qnil; - } - return lib_fromUTF8_core(Qnil, str, encodename); -} - -static VALUE -ip_fromUTF8(argc, argv, self) - int argc; - VALUE *argv; - VALUE self; -{ - VALUE str, encodename; - - if (rb_scan_args(argc, argv, "11", &str, &encodename) == 1) { - encodename = Qnil; - } - return lib_fromUTF8_core(self, str, encodename); -} - -static VALUE -lib_UTF_backslash_core(self, str, all_bs) - VALUE self; - VALUE str; - int all_bs; -{ -#ifdef TCL_UTF_MAX - char *src_buf, *dst_buf, *ptr; - int read_len = 0, dst_len = 0; - int taint_flag = OBJ_TAINTED(str); - int thr_crit_bup; - - tcl_stubs_check(); - - StringValue(str); - if (!RSTRING_LEN(str)) { - return str; - } - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - /* src_buf = ALLOC_N(char, RSTRING_LEN(str)+1); */ - src_buf = ckalloc(sizeof(char) * (RSTRING_LEN(str)+1)); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)src_buf); /* XXXXXXXX */ -#endif - memcpy(src_buf, RSTRING_PTR(str), RSTRING_LEN(str)); - src_buf[RSTRING_LEN(str)] = 0; - - /* dst_buf = ALLOC_N(char, RSTRING_LEN(str)+1); */ - dst_buf = ckalloc(sizeof(char) * (RSTRING_LEN(str)+1)); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)dst_buf); /* XXXXXXXX */ -#endif - - ptr = src_buf; - while(RSTRING_LEN(str) > ptr - src_buf) { - if (*ptr == '\\' && (all_bs || *(ptr + 1) == 'u')) { - dst_len += Tcl_UtfBackslash(ptr, &read_len, (dst_buf + dst_len)); - ptr += read_len; - } else { - *(dst_buf + (dst_len++)) = *(ptr++); - } - } - - str = rb_str_new(dst_buf, dst_len); - if (taint_flag) OBJ_TAINT(str); -#ifdef HAVE_RUBY_ENCODING_H - rb_enc_associate_index(str, ENCODING_INDEX_UTF8); -#endif - rb_ivar_set(str, ID_at_enc, ENCODING_NAME_UTF8); - -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)src_buf, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)src_buf); /* XXXXXXXX */ -#else - /* free(src_buf); */ - ckfree(src_buf); -#endif -#endif -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)dst_buf, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)dst_buf); /* XXXXXXXX */ -#else - /* free(dst_buf); */ - ckfree(dst_buf); -#endif -#endif - - rb_thread_critical = thr_crit_bup; -#endif - - return str; -} - -static VALUE -lib_UTF_backslash(self, str) - VALUE self; - VALUE str; -{ - return lib_UTF_backslash_core(self, str, 0); -} - -static VALUE -lib_Tcl_backslash(self, str) - VALUE self; - VALUE str; -{ - return lib_UTF_backslash_core(self, str, 1); -} - -static VALUE -lib_get_system_encoding(self) - VALUE self; -{ -#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION > 0) - tcl_stubs_check(); - return rb_str_new2(Tcl_GetEncodingName((Tcl_Encoding)NULL)); -#else - return Qnil; -#endif -} - -static VALUE -lib_set_system_encoding(self, enc_name) - VALUE self; - VALUE enc_name; -{ -#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION > 0) - tcl_stubs_check(); - - if (NIL_P(enc_name)) { - Tcl_SetSystemEncoding((Tcl_Interp *)NULL, (CONST char *)NULL); - return lib_get_system_encoding(self); - } - - enc_name = rb_funcall(enc_name, ID_to_s, 0, 0); - if (Tcl_SetSystemEncoding((Tcl_Interp *)NULL, - StringValuePtr(enc_name)) != TCL_OK) { - rb_raise(rb_eArgError, "unknown encoding name '%s'", - RSTRING_PTR(enc_name)); - } - - return enc_name; -#else - return Qnil; -#endif -} - - -/* invoke Tcl proc */ -struct invoke_info { - struct tcltkip *ptr; - Tcl_CmdInfo cmdinfo; -#if TCL_MAJOR_VERSION >= 8 - int objc; - Tcl_Obj **objv; -#else - int argc; - char **argv; -#endif -}; - -static VALUE -invoke_tcl_proc(arg) - VALUE arg; -{ - struct invoke_info *inf = (struct invoke_info *)arg; - int i, len; -#if TCL_MAJOR_VERSION >= 8 - int argc = inf->objc; - char **argv = (char **)NULL; -#endif - - /* memory allocation for arguments of this command */ -#if TCL_MAJOR_VERSION >= 8 - if (!inf->cmdinfo.isNativeObjectProc) { - /* string interface */ - /* argv = (char **)ALLOC_N(char *, argc+1);*/ /* XXXXXXXXXX */ - argv = (char **)ckalloc(sizeof(char *)*(argc+1)); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ -#endif - for (i = 0; i < argc; ++i) { - argv[i] = Tcl_GetStringFromObj(inf->objv[i], &len); - } - argv[argc] = (char *)NULL; - } -#endif - - Tcl_ResetResult(inf->ptr->ip); - - /* Invoke the C procedure */ -#if TCL_MAJOR_VERSION >= 8 - if (inf->cmdinfo.isNativeObjectProc) { - inf->ptr->return_value - = (*(inf->cmdinfo.objProc))(inf->cmdinfo.objClientData, - inf->ptr->ip, inf->objc, inf->objv); - } - else -#endif - { -#if TCL_MAJOR_VERSION >= 8 - inf->ptr->return_value - = (*(inf->cmdinfo.proc))(inf->cmdinfo.clientData, inf->ptr->ip, - argc, (CONST84 char **)argv); - -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)argv); /* XXXXXXXX */ -#else - /* free(argv); */ - ckfree((char*)argv); -#endif -#endif - -#else /* TCL_MAJOR_VERSION < 8 */ - inf->ptr->return_value - = (*(inf->cmdinfo.proc))(inf->cmdinfo.clientData, inf->ptr->ip, - inf->argc, inf->argv); -#endif - } - - return Qnil; -} - - -#if TCL_MAJOR_VERSION >= 8 -static VALUE -ip_invoke_core(interp, objc, objv) - VALUE interp; - int objc; - Tcl_Obj **objv; -#else -static VALUE -ip_invoke_core(interp, argc, argv) - VALUE interp; - int argc; - char **argv; -#endif -{ - struct tcltkip *ptr; - Tcl_CmdInfo info; - char *cmd; - int len; - int thr_crit_bup; - int unknown_flag = 0; - -#if 1 /* wrap tcl-proc call */ - struct invoke_info inf; - int status; - VALUE ret; -#else -#if TCL_MAJOR_VERSION >= 8 - int argc = objc; - char **argv = (char **)NULL; - /* Tcl_Obj *resultPtr; */ -#endif -#endif - - /* get the data struct */ - ptr = get_ip(interp); - - /* get the command name string */ -#if TCL_MAJOR_VERSION >= 8 - cmd = Tcl_GetStringFromObj(objv[0], &len); -#else /* TCL_MAJOR_VERSION < 8 */ - cmd = argv[0]; -#endif - - /* get the data struct */ - ptr = get_ip(interp); - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - return rb_tainted_str_new2(""); - } - - /* Tcl_Preserve(ptr->ip); */ - rbtk_preserve_ip(ptr); - - /* map from the command name to a C procedure */ - DUMP2("call Tcl_GetCommandInfo, %s", cmd); - if (!Tcl_GetCommandInfo(ptr->ip, cmd, &info)) { - DUMP1("error Tcl_GetCommandInfo"); - DUMP1("try auto_load (call 'unknown' command)"); - if (!Tcl_GetCommandInfo(ptr->ip, -#if TCL_MAJOR_VERSION >= 8 - "::unknown", -#else - "unknown", -#endif - &info)) { - DUMP1("fail to get 'unknown' command"); - /* if (event_loop_abort_on_exc || cmd[0] != '.') { */ - if (event_loop_abort_on_exc > 0) { - /* Tcl_Release(ptr->ip); */ - rbtk_release_ip(ptr); - /*rb_ip_raise(obj,rb_eNameError,"invalid command name `%s'",cmd);*/ - return create_ip_exc(interp, rb_eNameError, - "invalid command name `%s'", cmd); - } else { - if (event_loop_abort_on_exc < 0) { - rb_warning("invalid command name `%s' (ignore)", cmd); - } else { - rb_warn("invalid command name `%s' (ignore)", cmd); - } - Tcl_ResetResult(ptr->ip); - /* Tcl_Release(ptr->ip); */ - rbtk_release_ip(ptr); - return rb_tainted_str_new2(""); - } - } else { -#if TCL_MAJOR_VERSION >= 8 - Tcl_Obj **unknown_objv; -#else - char **unknown_argv; -#endif - DUMP1("find 'unknown' command -> set arguemnts"); - unknown_flag = 1; - -#if TCL_MAJOR_VERSION >= 8 - /* unknown_objv = (Tcl_Obj **)ALLOC_N(Tcl_Obj *, objc+2); */ - unknown_objv = (Tcl_Obj **)ckalloc(sizeof(Tcl_Obj *) * (objc+2)); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)unknown_objv); /* XXXXXXXX */ -#endif - unknown_objv[0] = Tcl_NewStringObj("::unknown", 9); - Tcl_IncrRefCount(unknown_objv[0]); - memcpy(unknown_objv + 1, objv, sizeof(Tcl_Obj *)*objc); - unknown_objv[++objc] = (Tcl_Obj*)NULL; - objv = unknown_objv; -#else - /* unknown_argv = (char **)ALLOC_N(char *, argc+2); */ - unknown_argv = (char **)ckalloc(sizeof(char *) * (argc+2)); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)unknown_argv); /* XXXXXXXX */ -#endif - unknown_argv[0] = strdup("unknown"); - memcpy(unknown_argv + 1, argv, sizeof(char *)*argc); - unknown_argv[++argc] = (char *)NULL; - argv = unknown_argv; -#endif - } - } - DUMP1("end Tcl_GetCommandInfo"); - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - -#if 1 /* wrap tcl-proc call */ - /* setup params */ - inf.ptr = ptr; - inf.cmdinfo = info; -#if TCL_MAJOR_VERSION >= 8 - inf.objc = objc; - inf.objv = objv; -#else - inf.argc = argc; - inf.argv = argv; -#endif - - /* invoke tcl-proc */ - ret = rb_protect(invoke_tcl_proc, (VALUE)&inf, &status); - switch(status) { - case TAG_RAISE: - if (NIL_P(rb_errinfo())) { - rbtk_pending_exception = rb_exc_new2(rb_eException, - "unknown exception"); - } else { - rbtk_pending_exception = rb_errinfo(); - } - break; - - case TAG_FATAL: - if (NIL_P(rb_errinfo())) { - rbtk_pending_exception = rb_exc_new2(rb_eFatal, "FATAL"); - } else { - rbtk_pending_exception = rb_errinfo(); - } - } - -#else /* !wrap tcl-proc call */ - - /* memory allocation for arguments of this command */ -#if TCL_MAJOR_VERSION >= 8 - if (!info.isNativeObjectProc) { - int i; - - /* string interface */ - /* argv = (char **)ALLOC_N(char *, argc+1); */ - argv = (char **)ckalloc(sizeof(char *) * (argc+1)); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ -#endif - for (i = 0; i < argc; ++i) { - argv[i] = Tcl_GetStringFromObj(objv[i], &len); - } - argv[argc] = (char *)NULL; - } -#endif - - Tcl_ResetResult(ptr->ip); - - /* Invoke the C procedure */ -#if TCL_MAJOR_VERSION >= 8 - if (info.isNativeObjectProc) { - ptr->return_value = (*info.objProc)(info.objClientData, ptr->ip, - objc, objv); -#if 0 - /* get the string value from the result object */ - resultPtr = Tcl_GetObjResult(ptr->ip); - Tcl_SetResult(ptr->ip, Tcl_GetStringFromObj(resultPtr, &len), - TCL_VOLATILE); -#endif - } - else -#endif - { -#if TCL_MAJOR_VERSION >= 8 - ptr->return_value = (*info.proc)(info.clientData, ptr->ip, - argc, (CONST84 char **)argv); - -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)argv); /* XXXXXXXX */ -#else - /* free(argv); */ - ckfree((char*)argv); -#endif -#endif - -#else /* TCL_MAJOR_VERSION < 8 */ - ptr->return_value = (*info.proc)(info.clientData, ptr->ip, - argc, argv); -#endif - } -#endif /* ! wrap tcl-proc call */ - - /* free allocated memory for calling 'unknown' command */ - if (unknown_flag) { -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(objv[0]); -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)objv, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)objv); /* XXXXXXXX */ -#else - /* free(objv); */ - ckfree((char*)objv); -#endif -#endif -#else /* TCL_MAJOR_VERSION < 8 */ - free(argv[0]); - /* ckfree(argv[0]); */ -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)argv); /* XXXXXXXX */ -#else - /* free(argv); */ - ckfree((char*)argv); -#endif -#endif -#endif - } - - /* exception on mainloop */ - if (pending_exception_check1(thr_crit_bup, ptr)) { - return rbtk_pending_exception; - } - - rb_thread_critical = thr_crit_bup; - - /* if (ptr->return_value == TCL_ERROR) { */ - if (ptr->return_value != TCL_OK) { - if (event_loop_abort_on_exc > 0 && !Tcl_InterpDeleted(ptr->ip)) { - switch (ptr->return_value) { - case TCL_RETURN: - return create_ip_exc(interp, eTkCallbackReturn, - "ip_invoke_core receives TCL_RETURN"); - case TCL_BREAK: - return create_ip_exc(interp, eTkCallbackBreak, - "ip_invoke_core receives TCL_BREAK"); - case TCL_CONTINUE: - return create_ip_exc(interp, eTkCallbackContinue, - "ip_invoke_core receives TCL_CONTINUE"); - default: - return create_ip_exc(interp, rb_eRuntimeError, "%s", - Tcl_GetStringResult(ptr->ip)); - } - - } else { - if (event_loop_abort_on_exc < 0) { - rb_warning("%s (ignore)", Tcl_GetStringResult(ptr->ip)); - } else { - rb_warn("%s (ignore)", Tcl_GetStringResult(ptr->ip)); - } - Tcl_ResetResult(ptr->ip); - return rb_tainted_str_new2(""); - } - } - - /* pass back the result (as string) */ - return ip_get_result_string_obj(ptr->ip); -} - - -#if TCL_MAJOR_VERSION >= 8 -static Tcl_Obj ** -#else /* TCL_MAJOR_VERSION < 8 */ -static char ** -#endif -alloc_invoke_arguments(argc, argv) - int argc; - VALUE *argv; -{ - int i; - int thr_crit_bup; - -#if TCL_MAJOR_VERSION >= 8 - Tcl_Obj **av; -#else /* TCL_MAJOR_VERSION < 8 */ - char **av; -#endif - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - /* memory allocation */ -#if TCL_MAJOR_VERSION >= 8 - /* av = ALLOC_N(Tcl_Obj *, argc+1);*/ /* XXXXXXXXXX */ - av = (Tcl_Obj**)ckalloc(sizeof(Tcl_Obj *)*(argc+1)); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)av); /* XXXXXXXX */ -#endif - for (i = 0; i < argc; ++i) { - av[i] = get_obj_from_str(argv[i]); - Tcl_IncrRefCount(av[i]); - } - av[argc] = NULL; - -#else /* TCL_MAJOR_VERSION < 8 */ - /* string interface */ - /* av = ALLOC_N(char *, argc+1); */ - av = (char**)ckalloc(sizeof(char *) * (argc+1)); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)av); /* XXXXXXXX */ -#endif - for (i = 0; i < argc; ++i) { - av[i] = strdup(StringValuePtr(argv[i])); - } - av[argc] = NULL; -#endif - - rb_thread_critical = thr_crit_bup; - - return av; -} - -static void -free_invoke_arguments(argc, av) - int argc; -#if TCL_MAJOR_VERSION >= 8 - Tcl_Obj **av; -#else /* TCL_MAJOR_VERSION < 8 */ - char **av; -#endif -{ - int i; - - for (i = 0; i < argc; ++i) { -#if TCL_MAJOR_VERSION >= 8 - Tcl_DecrRefCount(av[i]); - av[i] = (Tcl_Obj*)NULL; -#else /* TCL_MAJOR_VERSION < 8 */ - free(av[i]); - av[i] = (char*)NULL; -#endif - } -#if TCL_MAJOR_VERSION >= 8 -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)av, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)av); /* XXXXXXXX */ -#else - ckfree((char*)av); -#endif -#endif -#else /* TCL_MAJOR_VERSION < 8 */ -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)av, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)av); /* XXXXXXXX */ -#else - /* free(av); */ - ckfree((char*)av); -#endif -#endif -#endif -} - -static VALUE -ip_invoke_real(argc, argv, interp) - int argc; - VALUE *argv; - VALUE interp; -{ - VALUE v; - struct tcltkip *ptr; /* tcltkip data struct */ - -#if TCL_MAJOR_VERSION >= 8 - Tcl_Obj **av = (Tcl_Obj **)NULL; -#else /* TCL_MAJOR_VERSION < 8 */ - char **av = (char **)NULL; -#endif - - DUMP2("invoke_real called by thread:%lx", rb_thread_current()); - - /* get the data struct */ - ptr = get_ip(interp); - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - return rb_tainted_str_new2(""); - } - - /* allocate memory for arguments */ - av = alloc_invoke_arguments(argc, argv); - - /* Invoke the C procedure */ - Tcl_ResetResult(ptr->ip); - v = ip_invoke_core(interp, argc, av); - - /* free allocated memory */ - free_invoke_arguments(argc, av); - - return v; -} - -VALUE -ivq_safelevel_handler(arg, ivq) - VALUE arg; - VALUE ivq; -{ - struct invoke_queue *q; - - Data_Get_Struct(ivq, struct invoke_queue, q); - DUMP2("(safe-level handler) $SAFE = %d", q->safe_level); - rb_set_safe_level(q->safe_level); - return ip_invoke_core(q->interp, q->argc, q->argv); -} - -int invoke_queue_handler _((Tcl_Event *, int)); -int -invoke_queue_handler(evPtr, flags) - Tcl_Event *evPtr; - int flags; -{ - struct invoke_queue *q = (struct invoke_queue *)evPtr; - volatile VALUE ret; - volatile VALUE q_dat; - volatile VALUE thread = q->thread; - struct tcltkip *ptr; - - DUMP2("do_invoke_queue_handler : evPtr = %p", evPtr); - DUMP2("invoke queue_thread : %lx", rb_thread_current()); - DUMP2("added by thread : %lx", thread); - - if (*(q->done)) { - DUMP1("processed by another event-loop"); - return 0; - } else { - DUMP1("process it on current event-loop"); - } - -#ifdef RUBY_VM - if (RTEST(rb_funcall(thread, ID_alive_p, 0)) - && ! RTEST(rb_funcall(thread, ID_stop_p, 0))) { -#else - if (RTEST(rb_thread_alive_p(thread)) - && ! RTEST(rb_funcall(thread, ID_stop_p, 0))) { -#endif - DUMP1("caller is not yet ready to receive the result -> pending"); - return 0; - } - - /* process it */ - *(q->done) = 1; - - /* deleted ipterp ? */ - ptr = get_ip(q->interp); - if (deleted_ip(ptr)) { - /* deleted IP --> ignore */ - return 1; - } - - /* incr internal handler mark */ - rbtk_internal_eventloop_handler++; - - /* check safe-level */ - if (rb_safe_level() != q->safe_level) { - /* q_dat = Data_Wrap_Struct(rb_cData,0,0,q); */ - q_dat = Data_Wrap_Struct(rb_cData,invoke_queue_mark,-1,q); - ret = rb_funcall(rb_proc_new(ivq_safelevel_handler, q_dat), - ID_call, 0); - rb_gc_force_recycle(q_dat); - q_dat = (VALUE)NULL; - } else { - DUMP2("call invoke_real (for caller thread:%lx)", thread); - DUMP2("call invoke_real (current thread:%lx)", rb_thread_current()); - ret = ip_invoke_core(q->interp, q->argc, q->argv); - } - - /* set result */ - RARRAY_PTR(q->result)[0] = ret; - ret = (VALUE)NULL; - - /* decr internal handler mark */ - rbtk_internal_eventloop_handler--; - - /* complete */ - *(q->done) = -1; - - /* unlink ruby objects */ - q->interp = (VALUE)NULL; - q->result = (VALUE)NULL; - q->thread = (VALUE)NULL; - - /* back to caller */ -#ifdef RUBY_VM - if (RTEST(rb_funcall(thread, ID_alive_p, 0, 0))) { -#else - if (RTEST(rb_thread_alive_p(thread))) { -#endif - DUMP2("back to caller (caller thread:%lx)", thread); - DUMP2(" (current thread:%lx)", rb_thread_current()); -#if CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE - have_rb_thread_waiting_for_value = 1; - rb_thread_wakeup(thread); -#else - rb_thread_run(thread); -#endif - DUMP1("finish back to caller"); -#if DO_THREAD_SCHEDULE_AT_CALLBACK_DONE - rb_thread_schedule(); -#endif - } else { - DUMP2("caller is dead (caller thread:%lx)", thread); - DUMP2(" (current thread:%lx)", rb_thread_current()); - } - - /* end of handler : remove it */ - return 1; -} - -static VALUE -ip_invoke_with_position(argc, argv, obj, position) - int argc; - VALUE *argv; - VALUE obj; - Tcl_QueuePosition position; -{ - struct invoke_queue *ivq; -#ifdef RUBY_USE_NATIVE_THREAD - struct tcltkip *ptr; -#endif - int *alloc_done; - int thr_crit_bup; - volatile VALUE current = rb_thread_current(); - volatile VALUE ip_obj = obj; - volatile VALUE result; - volatile VALUE ret; - -#if TCL_MAJOR_VERSION >= 8 - Tcl_Obj **av = (Tcl_Obj **)NULL; -#else /* TCL_MAJOR_VERSION < 8 */ - char **av = (char **)NULL; -#endif - - if (argc < 1) { - rb_raise(rb_eArgError, "command name missing"); - } - -#ifdef RUBY_USE_NATIVE_THREAD - ptr = get_ip(ip_obj); - DUMP2("status: ptr->tk_thread_id %p", ptr->tk_thread_id); - DUMP2("status: Tcl_GetCurrentThread %p", Tcl_GetCurrentThread()); -#else - DUMP2("status: Tcl_GetCurrentThread %lx", Tcl_GetCurrentThread()); -#endif - DUMP2("status: eventloopt_thread %lx", eventloop_thread); - - if ( -#ifdef RUBY_USE_NATIVE_THREAD - (ptr->tk_thread_id == 0 || ptr->tk_thread_id == Tcl_GetCurrentThread()) - && -#endif - (NIL_P(eventloop_thread) || current == eventloop_thread) - ) { - if (NIL_P(eventloop_thread)) { - DUMP2("invoke from thread:%lx but no eventloop", current); - } else { - DUMP2("invoke from current eventloop %lx", current); - } - result = ip_invoke_real(argc, argv, ip_obj); - if (rb_obj_is_kind_of(result, rb_eException)) { - rb_exc_raise(result); - } - return result; - } - - DUMP2("invoke from thread %lx (NOT current eventloop)", current); - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - /* allocate memory (for arguments) */ - av = alloc_invoke_arguments(argc, argv); - - /* allocate memory (keep result) */ - /* alloc_done = (int*)ALLOC(int); */ - alloc_done = (int*)ckalloc(sizeof(int)); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)alloc_done); /* XXXXXXXX */ -#endif - *alloc_done = 0; - - /* allocate memory (freed by Tcl_ServiceEvent) */ - /* ivq = (struct invoke_queue *)Tcl_Alloc(sizeof(struct invoke_queue)); */ - ivq = (struct invoke_queue *)ckalloc(sizeof(struct invoke_queue)); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)ivq); /* XXXXXXXX */ -#endif - - /* allocate result obj */ - result = rb_ary_new3(1, Qnil); - - /* construct event data */ - ivq->done = alloc_done; - ivq->argc = argc; - ivq->argv = av; - ivq->interp = ip_obj; - ivq->result = result; - ivq->thread = current; - ivq->safe_level = rb_safe_level(); - ivq->ev.proc = invoke_queue_handler; - - /* add the handler to Tcl event queue */ - DUMP1("add handler"); -#ifdef RUBY_USE_NATIVE_THREAD - if (ptr->tk_thread_id) { - /* Tcl_ThreadQueueEvent(ptr->tk_thread_id, &(ivq->ev), position); */ - Tcl_ThreadQueueEvent(ptr->tk_thread_id, (Tcl_Event*)ivq, position); - Tcl_ThreadAlert(ptr->tk_thread_id); - } else if (tk_eventloop_thread_id) { - /* Tcl_ThreadQueueEvent(tk_eventloop_thread_id, - &(ivq->ev), position); */ - Tcl_ThreadQueueEvent(tk_eventloop_thread_id, - (Tcl_Event*)ivq, position); - Tcl_ThreadAlert(tk_eventloop_thread_id); - } else { - /* Tcl_QueueEvent(&(ivq->ev), position); */ - Tcl_QueueEvent((Tcl_Event*)ivq, position); - } -#else - /* Tcl_QueueEvent(&(ivq->ev), position); */ - Tcl_QueueEvent((Tcl_Event*)ivq, position); -#endif - - rb_thread_critical = thr_crit_bup; - - /* wait for the handler to be processed */ - DUMP2("wait for handler (current thread:%lx)", current); - while(*alloc_done >= 0) { - /* rb_thread_stop(); */ - rb_thread_sleep_forever(); - } - DUMP2("back from handler (current thread:%lx)", current); - - /* get result & free allocated memory */ - ret = RARRAY(result)->ptr[0]; -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)alloc_done, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)alloc_done); /* XXXXXXXX */ -#else - /* free(alloc_done); */ - ckfree((char*)alloc_done); -#endif -#endif - -#if 0 /* ivq is freed by Tcl_ServiceEvent */ -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)ivq, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release(ivq); -#else - ckfree((char*)ivq); -#endif -#endif -#endif - - /* free allocated memory */ - free_invoke_arguments(argc, av); - - /* exception? */ - if (rb_obj_is_kind_of(ret, rb_eException)) { - DUMP1("raise exception"); - /* rb_exc_raise(ret); */ - rb_exc_raise(rb_exc_new3(rb_obj_class(ret), - rb_funcall(ret, ID_to_s, 0, 0))); - } - - DUMP1("exit ip_invoke"); - return ret; -} - - -/* get return code from Tcl_Eval() */ -static VALUE -ip_retval(self) - VALUE self; -{ - struct tcltkip *ptr; /* tcltkip data struct */ - - /* get the data strcut */ - ptr = get_ip(self); - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - return rb_tainted_str_new2(""); - } - - return (INT2FIX(ptr->return_value)); -} - -static VALUE -ip_invoke(argc, argv, obj) - int argc; - VALUE *argv; - VALUE obj; -{ - return ip_invoke_with_position(argc, argv, obj, TCL_QUEUE_TAIL); -} - -static VALUE -ip_invoke_immediate(argc, argv, obj) - int argc; - VALUE *argv; - VALUE obj; -{ - /* POTENTIALY INSECURE : can create infinite loop */ - rb_secure(4); - return ip_invoke_with_position(argc, argv, obj, TCL_QUEUE_HEAD); -} - - -/* access Tcl variables */ -static VALUE -ip_get_variable2_core(interp, argc, argv) - VALUE interp; - int argc; - VALUE *argv; -{ - struct tcltkip *ptr = get_ip(interp); - int thr_crit_bup; - volatile VALUE varname, index, flag; - - varname = argv[0]; - index = argv[1]; - flag = argv[2]; - - /* - StringValue(varname); - if (!NIL_P(index)) StringValue(index); - */ - -#if TCL_MAJOR_VERSION >= 8 - { - Tcl_Obj *ret; - volatile VALUE strval; - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - rb_thread_critical = thr_crit_bup; - return rb_tainted_str_new2(""); - } else { - /* Tcl_Preserve(ptr->ip); */ - rbtk_preserve_ip(ptr); - ret = Tcl_GetVar2Ex(ptr->ip, RSTRING_PTR(varname), - NIL_P(index) ? NULL : RSTRING_PTR(index), - FIX2INT(flag)); - } - - if (ret == (Tcl_Obj*)NULL) { - volatile VALUE exc; - /* exc = rb_exc_new2(rb_eRuntimeError, - Tcl_GetStringResult(ptr->ip)); */ - exc = create_ip_exc(interp, rb_eRuntimeError, - Tcl_GetStringResult(ptr->ip)); - /* Tcl_Release(ptr->ip); */ - rbtk_release_ip(ptr); - rb_thread_critical = thr_crit_bup; - return exc; - } - - Tcl_IncrRefCount(ret); - strval = get_str_from_obj(ret); - OBJ_TAINT(strval); - Tcl_DecrRefCount(ret); - - /* Tcl_Release(ptr->ip); */ - rbtk_release_ip(ptr); - rb_thread_critical = thr_crit_bup; - return(strval); - } -#else /* TCL_MAJOR_VERSION < 8 */ - { - char *ret; - volatile VALUE strval; - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - return rb_tainted_str_new2(""); - } else { - /* Tcl_Preserve(ptr->ip); */ - rbtk_preserve_ip(ptr); - ret = Tcl_GetVar2(ptr->ip, RSTRING_PTR(varname), - NIL_P(index) ? NULL : RSTRING_PTR(index), - FIX2INT(flag)); - } - - if (ret == (char*)NULL) { - volatile VALUE exc; - exc = rb_exc_new2(rb_eRuntimeError, Tcl_GetStringResult(ptr->ip)); - /* Tcl_Release(ptr->ip); */ - rbtk_release_ip(ptr); - rb_thread_critical = thr_crit_bup; - return exc; - } - - strval = rb_tainted_str_new2(ret); - /* Tcl_Release(ptr->ip); */ - rbtk_release_ip(ptr); - rb_thread_critical = thr_crit_bup; - - return(strval); - } -#endif -} - -static VALUE -ip_get_variable2(self, varname, index, flag) - VALUE self; - VALUE varname; - VALUE index; - VALUE flag; -{ - VALUE argv[3]; - VALUE retval; - - StringValue(varname); - if (!NIL_P(index)) StringValue(index); - - argv[0] = varname; - argv[1] = index; - argv[2] = flag; - - retval = tk_funcall(ip_get_variable2_core, 3, argv, self); - - if (NIL_P(retval)) { - return rb_tainted_str_new2(""); - } else { - return retval; - } -} - -static VALUE -ip_get_variable(self, varname, flag) - VALUE self; - VALUE varname; - VALUE flag; -{ - return ip_get_variable2(self, varname, Qnil, flag); -} - -static VALUE -ip_set_variable2_core(interp, argc, argv) - VALUE interp; - int argc; - VALUE *argv; -{ - struct tcltkip *ptr = get_ip(interp); - int thr_crit_bup; - volatile VALUE varname, index, value, flag; - - varname = argv[0]; - index = argv[1]; - value = argv[2]; - flag = argv[3]; - - /* - StringValue(varname); - if (!NIL_P(index)) StringValue(index); - StringValue(value); - */ - -#if TCL_MAJOR_VERSION >= 8 - { - Tcl_Obj *valobj, *ret; - volatile VALUE strval; - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - valobj = get_obj_from_str(value); - Tcl_IncrRefCount(valobj); - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - Tcl_DecrRefCount(valobj); - rb_thread_critical = thr_crit_bup; - return rb_tainted_str_new2(""); - } else { - /* Tcl_Preserve(ptr->ip); */ - rbtk_preserve_ip(ptr); - ret = Tcl_SetVar2Ex(ptr->ip, RSTRING_PTR(varname), - NIL_P(index) ? NULL : RSTRING_PTR(index), - valobj, FIX2INT(flag)); - } - - Tcl_DecrRefCount(valobj); - - if (ret == (Tcl_Obj*)NULL) { - volatile VALUE exc; - /* exc = rb_exc_new2(rb_eRuntimeError, - Tcl_GetStringResult(ptr->ip)); */ - exc = create_ip_exc(interp, rb_eRuntimeError, - Tcl_GetStringResult(ptr->ip)); - /* Tcl_Release(ptr->ip); */ - rbtk_release_ip(ptr); - rb_thread_critical = thr_crit_bup; - return exc; - } - - Tcl_IncrRefCount(ret); - strval = get_str_from_obj(ret); - OBJ_TAINT(strval); - Tcl_DecrRefCount(ret); - - /* Tcl_Release(ptr->ip); */ - rbtk_release_ip(ptr); - rb_thread_critical = thr_crit_bup; - - return(strval); - } -#else /* TCL_MAJOR_VERSION < 8 */ - { - CONST char *ret; - volatile VALUE strval; - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - return rb_tainted_str_new2(""); - } else { - /* Tcl_Preserve(ptr->ip); */ - rbtk_preserve_ip(ptr); - ret = Tcl_SetVar2(ptr->ip, RSTRING_PTR(varname), - NIL_P(index) ? NULL : RSTRING_PTR(index), - RSTRING_PTR(value), FIX2INT(flag)); - } - - if (ret == (char*)NULL) { - return rb_exc_new2(rb_eRuntimeError, ptr->ip->result); - } - - strval = rb_tainted_str_new2(ret); - - /* Tcl_Release(ptr->ip); */ - rbtk_release_ip(ptr); - rb_thread_critical = thr_crit_bup; - - return(strval); - } -#endif -} - -static VALUE -ip_set_variable2(self, varname, index, value, flag) - VALUE self; - VALUE varname; - VALUE index; - VALUE value; - VALUE flag; -{ - VALUE argv[4]; - VALUE retval; - - StringValue(varname); - if (!NIL_P(index)) StringValue(index); - StringValue(value); - - argv[0] = varname; - argv[1] = index; - argv[2] = value; - argv[3] = flag; - - retval = tk_funcall(ip_set_variable2_core, 4, argv, self); - - if (NIL_P(retval)) { - return rb_tainted_str_new2(""); - } else { - return retval; - } -} - -static VALUE -ip_set_variable(self, varname, value, flag) - VALUE self; - VALUE varname; - VALUE value; - VALUE flag; -{ - return ip_set_variable2(self, varname, Qnil, value, flag); -} - -static VALUE -ip_unset_variable2_core(interp, argc, argv) - VALUE interp; - int argc; - VALUE *argv; -{ - struct tcltkip *ptr = get_ip(interp); - volatile VALUE varname, index, flag; - - varname = argv[0]; - index = argv[1]; - flag = argv[2]; - - /* - StringValue(varname); - if (!NIL_P(index)) StringValue(index); - */ - - /* ip is deleted? */ - if (deleted_ip(ptr)) { - return Qtrue; - } - - ptr->return_value = Tcl_UnsetVar2(ptr->ip, RSTRING_PTR(varname), - NIL_P(index) ? NULL : RSTRING_PTR(index), - FIX2INT(flag)); - - if (ptr->return_value == TCL_ERROR) { - if (FIX2INT(flag) & TCL_LEAVE_ERR_MSG) { - /* return rb_exc_new2(rb_eRuntimeError, - Tcl_GetStringResult(ptr->ip)); */ - return create_ip_exc(interp, rb_eRuntimeError, - Tcl_GetStringResult(ptr->ip)); - } - return Qfalse; - } - return Qtrue; -} - -static VALUE -ip_unset_variable2(self, varname, index, flag) - VALUE self; - VALUE varname; - VALUE index; - VALUE flag; -{ - VALUE argv[3]; - VALUE retval; - - StringValue(varname); - if (!NIL_P(index)) StringValue(index); - - argv[0] = varname; - argv[1] = index; - argv[2] = flag; - - retval = tk_funcall(ip_unset_variable2_core, 3, argv, self); - - if (NIL_P(retval)) { - return rb_tainted_str_new2(""); - } else { - return retval; - } -} - -static VALUE -ip_unset_variable(self, varname, flag) - VALUE self; - VALUE varname; - VALUE flag; -{ - return ip_unset_variable2(self, varname, Qnil, flag); -} - -static VALUE -ip_get_global_var(self, varname) - VALUE self; - VALUE varname; -{ - return ip_get_variable(self, varname, - INT2FIX(TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG)); -} - -static VALUE -ip_get_global_var2(self, varname, index) - VALUE self; - VALUE varname; - VALUE index; -{ - return ip_get_variable2(self, varname, index, - INT2FIX(TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG)); -} - -static VALUE -ip_set_global_var(self, varname, value) - VALUE self; - VALUE varname; - VALUE value; -{ - return ip_set_variable(self, varname, value, - INT2FIX(TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG)); -} - -static VALUE -ip_set_global_var2(self, varname, index, value) - VALUE self; - VALUE varname; - VALUE index; - VALUE value; -{ - return ip_set_variable2(self, varname, index, value, - INT2FIX(TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG)); -} - -static VALUE -ip_unset_global_var(self, varname) - VALUE self; - VALUE varname; -{ - return ip_unset_variable(self, varname, - INT2FIX(TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG)); -} - -static VALUE -ip_unset_global_var2(self, varname, index) - VALUE self; - VALUE varname; - VALUE index; -{ - return ip_unset_variable2(self, varname, index, - INT2FIX(TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG)); -} - - -/* treat Tcl_List */ -static VALUE -lib_split_tklist_core(ip_obj, list_str) - VALUE ip_obj; - VALUE list_str; -{ - Tcl_Interp *interp; - volatile VALUE ary, elem; - int idx; - int taint_flag = OBJ_TAINTED(list_str); -#ifdef HAVE_RUBY_ENCODING_H - int list_enc_idx; - volatile VALUE list_ivar_enc; -#endif - int result; - VALUE old_gc; - - tcl_stubs_check(); - - if (NIL_P(ip_obj)) { - interp = (Tcl_Interp *)NULL; - } else if (get_ip(ip_obj) == (struct tcltkip *)NULL) { - interp = (Tcl_Interp *)NULL; - } else { - interp = get_ip(ip_obj)->ip; - } - - StringValue(list_str); -#ifdef HAVE_RUBY_ENCODING_H - list_enc_idx = rb_enc_get_index(list_str); - list_ivar_enc = rb_ivar_get(list_str, ID_at_enc); -#endif - - { -#if TCL_MAJOR_VERSION >= 8 - /* object style interface */ - Tcl_Obj *listobj; - int objc; - Tcl_Obj **objv; - int thr_crit_bup; - - listobj = get_obj_from_str(list_str); - - Tcl_IncrRefCount(listobj); - - result = Tcl_ListObjGetElements(interp, listobj, &objc, &objv); - - if (result == TCL_ERROR) { - Tcl_DecrRefCount(listobj); - if (interp == (Tcl_Interp*)NULL) { - rb_raise(rb_eRuntimeError, "can't get elements from list"); - } else { - rb_raise(rb_eRuntimeError, "%s", Tcl_GetStringResult(interp)); - } - } - - for(idx = 0; idx < objc; idx++) { - Tcl_IncrRefCount(objv[idx]); - } - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - ary = rb_ary_new2(objc); - if (taint_flag) OBJ_TAINT(ary); - - old_gc = rb_gc_disable(); - - for(idx = 0; idx < objc; idx++) { - elem = get_str_from_obj(objv[idx]); -#ifdef HAVE_RUBY_ENCODING_H - if (rb_enc_get_index(elem) == ENCODING_INDEX_BINARY) { - rb_enc_associate_index(elem, ENCODING_INDEX_BINARY); - rb_ivar_set(elem, ID_at_enc, ENCODING_NAME_BINARY); - } else { - rb_enc_associate_index(elem, list_enc_idx); - rb_ivar_set(elem, ID_at_enc, list_ivar_enc); - } -#endif - if (taint_flag) OBJ_TAINT(elem); - /* RARRAY(ary)->ptr[idx] = elem; */ - rb_ary_push(ary, elem); - } - - /* RARRAY(ary)->len = objc; */ - - if (old_gc == Qfalse) rb_gc_enable(); - - rb_thread_critical = thr_crit_bup; - - for(idx = 0; idx < objc; idx++) { - Tcl_DecrRefCount(objv[idx]); - } - - Tcl_DecrRefCount(listobj); - -#else /* TCL_MAJOR_VERSION < 8 */ - /* string style interface */ - int argc; - char **argv; - - if (Tcl_SplitList(interp, RSTRING_PTR(list_str), - &argc, &argv) == TCL_ERROR) { - if (interp == (Tcl_Interp*)NULL) { - rb_raise(rb_eRuntimeError, "can't get elements from list"); - } else { - rb_raise(rb_eRuntimeError, "%s", interp->result); - } - } - - ary = rb_ary_new2(argc); - if (taint_flag) OBJ_TAINT(ary); - - old_gc = rb_gc_disable(); - - for(idx = 0; idx < argc; idx++) { - if (taint_flag) { - elem = rb_tainted_str_new2(argv[idx]); - } else { - elem = rb_str_new2(argv[idx]); - } - /* rb_ivar_set(elem, ID_at_enc, rb_str_new2("binary")); */ - /* RARRAY(ary)->ptr[idx] = elem; */ - rb_ary_push(ary, elem) - } - /* RARRAY(ary)->len = argc; */ - - if (old_gc == Qfalse) rb_gc_enable(); -#endif - } - - return ary; -} - -static VALUE -lib_split_tklist(self, list_str) - VALUE self; - VALUE list_str; -{ - return lib_split_tklist_core(Qnil, list_str); -} - - -static VALUE -ip_split_tklist(self, list_str) - VALUE self; - VALUE list_str; -{ - return lib_split_tklist_core(self, list_str); -} - -static VALUE -lib_merge_tklist(argc, argv, obj) - int argc; - VALUE *argv; - VALUE obj; -{ - int num, len; - int *flagPtr; - char *dst, *result; - volatile VALUE str; - int taint_flag = 0; - int thr_crit_bup; - VALUE old_gc; - - if (argc == 0) return rb_str_new2(""); - - tcl_stubs_check(); - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - old_gc = rb_gc_disable(); - - /* based on Tcl/Tk's Tcl_Merge() */ - /* flagPtr = ALLOC_N(int, argc); */ - flagPtr = (int *)ckalloc(sizeof(int) * argc); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)flagPtr); /* XXXXXXXXXX */ -#endif - - /* pass 1 */ - len = 1; - for(num = 0; num < argc; num++) { - if (OBJ_TAINTED(argv[num])) taint_flag = 1; - dst = StringValuePtr(argv[num]); -#if TCL_MAJOR_VERSION >= 8 - len += Tcl_ScanCountedElement(dst, RSTRING_LEN(argv[num]), - &flagPtr[num]) + 1; -#else /* TCL_MAJOR_VERSION < 8 */ - len += Tcl_ScanElement(dst, &flagPtr[num]) + 1; -#endif - } - - /* pass 2 */ - /* result = (char *)Tcl_Alloc(len); */ - result = (char *)ckalloc(len); -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Preserve((ClientData)result); -#endif - dst = result; - for(num = 0; num < argc; num++) { -#if TCL_MAJOR_VERSION >= 8 - len = Tcl_ConvertCountedElement(RSTRING_PTR(argv[num]), - RSTRING_LEN(argv[num]), - dst, flagPtr[num]); -#else /* TCL_MAJOR_VERSION < 8 */ - len = Tcl_ConvertElement(RSTRING_PTR(argv[num]), dst, flagPtr[num]); -#endif - dst += len; - *dst = ' '; - dst++; - } - if (dst == result) { - *dst = 0; - } else { - dst[-1] = 0; - } - -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)flagPtr, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)flagPtr); -#else - /* free(flagPtr); */ - ckfree((char*)flagPtr); -#endif -#endif - - /* create object */ - str = rb_str_new(result, dst - result - 1); - if (taint_flag) OBJ_TAINT(str); -#if 0 /* use Tcl_EventuallyFree */ - Tcl_EventuallyFree((ClientData)result, TCL_DYNAMIC); /* XXXXXXXX */ -#else -#if 0 /* use Tcl_Preserve/Release */ - Tcl_Release((ClientData)result); /* XXXXXXXXXXX */ -#else - /* Tcl_Free(result); */ - ckfree(result); -#endif -#endif - - if (old_gc == Qfalse) rb_gc_enable(); - rb_thread_critical = thr_crit_bup; - - return str; -} - -static VALUE -lib_conv_listelement(self, src) - VALUE self; - VALUE src; -{ - int len, scan_flag; - volatile VALUE dst; - int taint_flag = OBJ_TAINTED(src); - int thr_crit_bup; - - tcl_stubs_check(); - - thr_crit_bup = rb_thread_critical; - rb_thread_critical = Qtrue; - - StringValue(src); - -#if TCL_MAJOR_VERSION >= 8 - len = Tcl_ScanCountedElement(RSTRING_PTR(src), RSTRING_LEN(src), - &scan_flag); - dst = rb_str_new(0, len + 1); - len = Tcl_ConvertCountedElement(RSTRING_PTR(src), RSTRING_LEN(src), - RSTRING_PTR(dst), scan_flag); -#else /* TCL_MAJOR_VERSION < 8 */ - len = Tcl_ScanElement(RSTRING_PTR(src), &scan_flag); - dst = rb_str_new(0, len + 1); - len = Tcl_ConvertElement(RSTRING_PTR(src), RSTRING_PTR(dst), scan_flag); -#endif - - rb_str_resize(dst, len); - if (taint_flag) OBJ_TAINT(dst); - - rb_thread_critical = thr_crit_bup; - - return dst; -} - -static VALUE -lib_getversion(self) - VALUE self; -{ - volatile VALUE type_name; - - set_tcltk_version(); - - switch(tcltk_version.type) { - case TCL_ALPHA_RELEASE: - type_name = rb_str_new2("alpha"); - break; - case TCL_BETA_RELEASE: - type_name = rb_str_new2("beta"); - break; - case TCL_FINAL_RELEASE: - type_name = rb_str_new2("final"); - break; - default: - type_name = rb_str_new2("unknown"); - } - - return rb_ary_new3(5, INT2NUM(tcltk_version.major), - INT2NUM(tcltk_version.minor), - INT2NUM(tcltk_version.type), type_name, - INT2NUM(tcltk_version.patchlevel)); -} - - -static VALUE -tcltklib_compile_info() -{ - volatile VALUE ret; - int size; - char form[] - = "tcltklib %s :: Ruby%s (%s) %s pthread :: Tcl%s(%s)/Tk%s(%s) %s"; - char *info; - - size = strlen(form) - + strlen(TCLTKLIB_RELEASE_DATE) - + strlen(RUBY_VERSION) - + strlen(RUBY_RELEASE_DATE) - + strlen("without") - + strlen(TCL_PATCH_LEVEL) - + strlen("without stub") - + strlen(TK_PATCH_LEVEL) - + strlen("without stub") - + strlen("unknown tcl_threads"); - - info = ALLOC_N(char, size); - /* info = ckalloc(sizeof(char) * size); */ /* SEGV */ - - sprintf(info, form, - TCLTKLIB_RELEASE_DATE, - RUBY_VERSION, RUBY_RELEASE_DATE, -#ifdef HAVE_NATIVETHREAD - "with", -#else - "without", -#endif - TCL_PATCH_LEVEL, -#ifdef USE_TCL_STUBS - "with stub", -#else - "without stub", -#endif - TK_PATCH_LEVEL, -#ifdef USE_TK_STUBS - "with stub", -#else - "without stub", -#endif -#ifdef WITH_TCL_ENABLE_THREAD -# if WITH_TCL_ENABLE_THREAD - "with tcl_threads" -# else - "without tcl_threads" -# endif -#else - "unknown tcl_threads" -#endif - ); - - ret = rb_obj_freeze(rb_str_new2(info)); - - free(info); - /* ckfree(info); */ - - return ret; -} - - -/*###############################################*/ - -static VALUE -create_dummy_encoding_for_tk_core(interp, name, error_mode) - VALUE interp; - VALUE name; - VALUE error_mode; -{ - get_ip(interp); - - rb_secure(4); - - StringValue(name); - -#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1) - if (Tcl_GetEncoding((Tcl_Interp*)NULL, RSTRING_PTR(name)) == (Tcl_Encoding)NULL) { - if (RTEST(error_mode)) { - rb_raise(rb_eArgError, "invalid Tk encoding name '%s'", - RSTRING_PTR(name)); - } else { - return Qnil; - } - } -#endif - -#ifdef HAVE_RUBY_ENCODING_H - if (RTEST(rb_define_dummy_encoding(RSTRING_PTR(name)))) { - int idx = rb_enc_find_index(StringValueCStr(name)); - return rb_enc_from_encoding(rb_enc_from_index(idx)); - } else { - if (RTEST(error_mode)) { - rb_raise(rb_eRuntimeError, "fail to create dummy encoding for '%s'", - RSTRING_PTR(name)); - } else { - return Qnil; - } - } -#else - return name; -#endif -} -static VALUE -create_dummy_encoding_for_tk(interp, name) - VALUE interp; - VALUE name; -{ - return create_dummy_encoding_for_tk_core(interp, name, Qtrue); -} - - -#ifdef HAVE_RUBY_ENCODING_H -static int -update_encoding_table(table, interp, error_mode) - VALUE table; - VALUE interp; - VALUE error_mode; -{ - struct tcltkip *ptr; - int retry = 0; - int i, idx, objc; - Tcl_Obj **objv; - Tcl_Obj *enc_list; - volatile VALUE encname = Qnil; - volatile VALUE encobj = Qnil; - - /* interpreter check */ - if (NIL_P(interp)) return 0; - ptr = get_ip(interp); - if (ptr == (struct tcltkip *) NULL) return 0; - if (deleted_ip(ptr)) return 0; - - /* get Tcl's encoding list */ - Tcl_GetEncodingNames(ptr->ip); - enc_list = Tcl_GetObjResult(ptr->ip); - Tcl_IncrRefCount(enc_list); - - if (Tcl_ListObjGetElements(ptr->ip, enc_list, - &objc, &objv) != TCL_OK) { - Tcl_DecrRefCount(enc_list); - /* rb_raise(rb_eRuntimeError, "failt to get Tcl's encoding names");*/ - return 0; - } - - /* check each encoding name */ - for(i = 0; i < objc; i++) { - encname = rb_str_new2(Tcl_GetString(objv[i])); - if (NIL_P(rb_hash_lookup(table, encname))) { - /* new Tk encoding -> add to table */ - idx = rb_enc_find_index(StringValueCStr(encname)); - if (idx < 0) { - encobj = create_dummy_encoding_for_tk_core(interp,encname,error_mode); - } else { - encobj = rb_enc_from_encoding(rb_enc_from_index(idx)); - } - encname = rb_obj_freeze(encname); - rb_hash_aset(table, encname, encobj); - if (!NIL_P(encobj) && NIL_P(rb_hash_lookup(table, encobj))) { - rb_hash_aset(table, encobj, encname); - } - retry = 1; - } - } - - Tcl_DecrRefCount(enc_list); - - return retry; -} - -static VALUE -encoding_table_get_name_core(table, enc_arg, error_mode) - VALUE table; - VALUE enc_arg; - VALUE error_mode; -{ - volatile VALUE enc = enc_arg; - volatile VALUE name = Qnil; - volatile VALUE tmp = Qnil; - volatile VALUE interp = rb_ivar_get(table, ID_at_interp); - struct tcltkip *ptr = (struct tcltkip *) NULL; - int idx; - - /* deleted interp ? */ - if (!NIL_P(interp)) { - ptr = get_ip(interp); - if (deleted_ip(ptr)) { - ptr = (struct tcltkip *) NULL; - } - } - - /* encoding argument check */ - /* 1st: default encoding setting of interp */ - if (ptr && NIL_P(enc)) { - if (rb_respond_to(interp, ID_encoding_name)) { - enc = rb_funcall(interp, ID_encoding_name, 0, 0); - } - } - /* 2nd: encoding system of Tcl/Tk */ - if (NIL_P(enc)) { - enc = rb_str_new2(Tcl_GetEncodingName((Tcl_Encoding)NULL)); - } - /* 3rd: Encoding.default_external */ - if (NIL_P(enc)) { - enc = rb_enc_default_external(); - } - - if (RTEST(rb_obj_is_kind_of(enc, cRubyEncoding))) { - /* Ruby's Encoding object */ - name = rb_hash_lookup(table, enc); - if (!NIL_P(name)) { - /* find */ - return name; - } - - /* is it new ? */ - /* update check of Tk encoding names */ - if (update_encoding_table(table, interp, error_mode)) { - /* add new relations to the table */ - /* RETRY: registered Ruby encoding? */ - name = rb_hash_lookup(table, enc); - if (!NIL_P(name)) { - /* find */ - return name; - } - } - /* fail to find */ - - } else { - /* String or Symbol? */ - name = rb_funcall(enc, ID_to_s, 0, 0); - - if (!NIL_P(rb_hash_lookup(table, name))) { - /* find */ - return name; - } - - /* is it new ? */ - idx = rb_enc_find_index(StringValueCStr(name)); - if (idx >= 0) { - enc = rb_enc_from_encoding(rb_enc_from_index(idx)); - - /* registered Ruby encoding? */ - tmp = rb_hash_lookup(table, enc); - if (!NIL_P(tmp)) { - /* find */ - return tmp; - } - - /* update check of Tk encoding names */ - if (update_encoding_table(table, interp, error_mode)) { - /* add new relations to the table */ - /* RETRY: registered Ruby encoding? */ - tmp = rb_hash_lookup(table, enc); - if (!NIL_P(tmp)) { - /* find */ - return tmp; - } - } - } - /* fail to find */ - } - - if (RTEST(error_mode)) { - enc = rb_funcall(enc_arg, ID_to_s, 0, 0); - rb_raise(rb_eArgError, "unsupported Tk encoding '%s'", RSTRING_PTR(enc)); - } - return Qnil; -} -static VALUE -encoding_table_get_obj_core(table, enc, error_mode) - VALUE table; - VALUE enc; - VALUE error_mode; -{ - volatile VALUE obj = Qnil; - - obj = rb_hash_lookup(table, - encoding_table_get_name_core(table, enc, error_mode)); - if (RTEST(rb_obj_is_kind_of(obj, cRubyEncoding))) { - return obj; - } else { - return Qnil; - } -} - -#else /* ! HAVE_RUBY_ENCODING_H */ -#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1) -static int -update_encoding_table(table, interp, error_mode) - VALUE table; - VALUE interp; - VALUE error_mode; -{ - struct tcltkip *ptr; - int retry = 0; - int i, idx, objc; - Tcl_Obj **objv; - Tcl_Obj *enc_list; - volatile VALUE encname = Qnil; - volatile VALUE encobj = Qnil; - - /* interpreter check */ - if (NIL_P(interp)) return 0; - ptr = get_ip(interp); - if (ptr == (struct tcltkip *) NULL) return 0; - if (deleted_ip(ptr)) return 0; - - /* get Tcl's encoding list */ - Tcl_GetEncodingNames(ptr->ip); - enc_list = Tcl_GetObjResult(ptr->ip); - Tcl_IncrRefCount(enc_list); - - if (Tcl_ListObjGetElements(ptr->ip, enc_list, &objc, &objv) != TCL_OK) { - Tcl_DecrRefCount(enc_list); - /* rb_raise(rb_eRuntimeError, "failt to get Tcl's encoding names"); */ - return 0; - } - - /* get encoding name and set it to table */ - for(i = 0; i < objc; i++) { - encname = rb_str_new2(Tcl_GetString(objv[i])); - if (NIL_P(rb_hash_lookup(table, encname))) { - /* new Tk encoding -> add to table */ - encname = rb_obj_freeze(encname); - rb_hash_aset(table, encname, encname); - retry = 1; - } - } - - Tcl_DecrRefCount(enc_list); - - return retry; -} - -static VALUE -encoding_table_get_name_core(table, enc, error_mode) - VALUE table; - VALUE enc; - VALUE error_mode; -{ - volatile VALUE name = Qnil; - int retry = 0; - - enc = rb_funcall(enc, ID_to_s, 0, 0); - name = rb_hash_lookup(table, enc); - - if (!NIL_P(name)) { - /* find */ - return name; - } - - /* update check */ - if (update_encoding_table(table, rb_ivar_get(table, ID_at_interp), - error_mode)) { - /* add new relations to the table */ - /* RETRY: registered Ruby encoding? */ - name = rb_hash_lookup(table, enc); - if (!NIL_P(name)) { - /* find */ - return name; - } - } - - if (RTEST(error_mode)) { - rb_raise(rb_eArgError, "unsupported Tk encoding '%s'", RSTRING_PTR(enc)); - } - return Qnil; -} -static VALUE -encoding_table_get_obj_core(table, enc, error_mode) - VALUE table; - VALUE enc; - VALUE error_mode; -{ - return encoding_table_get_name_core(table, enc, error_mode); -} - -#else /* Tcl/Tk 7.x or 8.0 */ -static VALUE -encoding_table_get_name_core(table, enc, error_mode) - VALUE table; - VALUE enc; - VALUE error_mode; -{ - return Qnil; -} -static VALUE -encoding_table_get_obj_core(table, enc, error_mode) - VALUE table; - VALUE enc; - VALUE error_mode; -{ - return Qnil; -} -#endif /* end of dependency for the version of Tcl/Tk */ -#endif - -static VALUE -encoding_table_get_name(table, enc) - VALUE table; - VALUE enc; -{ - return encoding_table_get_name_core(table, enc, Qtrue); -} -static VALUE -encoding_table_get_obj(table, enc) - VALUE table; - VALUE enc; -{ - return encoding_table_get_obj_core(table, enc, Qtrue); -} - -#ifdef HAVE_RUBY_ENCODING_H -static VALUE -create_encoding_table(interp) - VALUE interp; -{ - struct tcltkip *ptr = get_ip(interp); - volatile VALUE table = rb_hash_new(); - volatile VALUE encname = Qnil; - volatile VALUE encobj = Qnil; - int i, idx, objc; - Tcl_Obj **objv; - Tcl_Obj *enc_list; - - rb_secure(4); - - /* set 'binary' encoding */ - encobj = rb_enc_from_encoding(rb_enc_from_index(ENCODING_INDEX_BINARY)); - rb_hash_aset(table, ENCODING_NAME_BINARY, encobj); - rb_hash_aset(table, encobj, ENCODING_NAME_BINARY); - - - /* Tcl stub check */ - tcl_stubs_check(); - - /* get Tcl's encoding list */ - Tcl_GetEncodingNames(ptr->ip); - enc_list = Tcl_GetObjResult(ptr->ip); - Tcl_IncrRefCount(enc_list); - - if (Tcl_ListObjGetElements(ptr->ip, enc_list, &objc, &objv) != TCL_OK) { - Tcl_DecrRefCount(enc_list); - rb_raise(rb_eRuntimeError, "failt to get Tcl's encoding names"); - } - - /* get encoding name and set it to table */ - for(i = 0; i < objc; i++) { - int name2obj, obj2name; - - name2obj = 1; obj2name = 1; - encname = rb_obj_freeze(rb_str_new2(Tcl_GetString(objv[i]))); - idx = rb_enc_find_index(StringValueCStr(encname)); - if (idx < 0) { - /* fail to find ruby encoding -> check known encoding */ - if (strcmp(RSTRING_PTR(encname), "identity") == 0) { - name2obj = 1; obj2name = 0; - idx = ENCODING_INDEX_BINARY; - - } else if (strcmp(RSTRING_PTR(encname), "shiftjis") == 0) { - name2obj = 1; obj2name = 0; - idx = rb_enc_find_index("Shift_JIS"); - - } else if (strcmp(RSTRING_PTR(encname), "unicode") == 0) { - name2obj = 1; obj2name = 0; - idx = ENCODING_INDEX_UTF8; - - } else if (strcmp(RSTRING_PTR(encname), "symbol") == 0) { - name2obj = 1; obj2name = 0; - idx = rb_enc_find_index("ASCII-8BIT"); - - } else { - /* regist dummy encoding */ - name2obj = 1; obj2name = 1; - } - } - - if (idx < 0) { - /* unknown encoding -> create dummy */ - encobj = create_dummy_encoding_for_tk(interp, encname); - } else { - encobj = rb_enc_from_encoding(rb_enc_from_index(idx)); - } - - if (name2obj) { - DUMP2("create_encoding_table: name2obj: %s", RSTRING_PTR(encname)); - rb_hash_aset(table, encname, encobj); - } - if (obj2name) { - DUMP2("create_encoding_table: obj2name: %s", RSTRING_PTR(encname)); - rb_hash_aset(table, encobj, encname); - } - } - - Tcl_DecrRefCount(enc_list); - - rb_ivar_set(table, ID_at_interp, interp); - rb_ivar_set(interp, ID_encoding_table, table); - - return table; -} - -#else /* ! HAVE_RUBY_ENCODING_H */ -#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1) -static VALUE -create_encoding_table(interp) - VALUE interp; -{ - struct tcltkip *ptr = get_ip(interp); - volatile VALUE table = rb_hash_new(); - volatile VALUE encname = Qnil; - int i, objc; - Tcl_Obj **objv; - Tcl_Obj *enc_list; - - rb_secure(4); - - /* set 'binary' encoding */ - rb_hash_aset(table, ENCODING_NAME_BINARY, ENCODING_NAME_BINARY); - - /* get Tcl's encoding list */ - Tcl_GetEncodingNames(ptr->ip); - enc_list = Tcl_GetObjResult(ptr->ip); - Tcl_IncrRefCount(enc_list); - - if (Tcl_ListObjGetElements(ptr->ip, enc_list, &objc, &objv) != TCL_OK) { - Tcl_DecrRefCount(enc_list); - rb_raise(rb_eRuntimeError, "failt to get Tcl's encoding names"); - } - - /* get encoding name and set it to table */ - for(i = 0; i < objc; i++) { - encname = rb_obj_freeze(rb_str_new2(Tcl_GetString(objv[i]))); - rb_hash_aset(table, encname, encname); - } - - Tcl_DecrRefCount(enc_list); - - rb_ivar_set(table, ID_at_interp, interp); - rb_ivar_set(interp, ID_encoding_table, table); - - return table; -} - -#else /* Tcl/Tk 7.x or 8.0 */ -static VALUE -create_encoding_table(interp) - VALUE interp; -{ - volatile VALUE table = rb_hash_new(); - rb_secure(4); - rb_ivar_set(interp, ID_encoding_table, table); - return table; -} -#endif -#endif - -static VALUE -ip_get_encoding_table(interp) - VALUE interp; -{ - volatile VALUE table = Qnil; - - table = rb_ivar_get(interp, ID_encoding_table); - - if (NIL_P(table)) { - /* initialize encoding_table */ - table = create_encoding_table(interp); - rb_define_singleton_method(table, "get_name", encoding_table_get_name, 1); - rb_define_singleton_method(table, "get_obj", encoding_table_get_obj, 1); - } - - return table; -} - - -/*###############################################*/ - -/* - * The following is based on tkMenu.[ch] - * of Tcl/Tk (Tk8.0 -- Tk8.5b1) source code. - */ -#if TCL_MAJOR_VERSION >= 8 - -#define MASTER_MENU 0 -#define TEAROFF_MENU 1 -#define MENUBAR 2 - -struct dummy_TkMenuEntry { - int type; - struct dummy_TkMenu *menuPtr; - /* , and etc. */ -}; - -struct dummy_TkMenu { - Tk_Window tkwin; - Display *display; - Tcl_Interp *interp; - Tcl_Command widgetCmd; - struct dummy_TkMenuEntry **entries; - int numEntries; - int active; - int menuType; /* MASTER_MENU, TEAROFF_MENU, or MENUBAR */ - Tcl_Obj *menuTypePtr; - /* , and etc. */ -}; - -struct dummy_TkMenuRef { - struct dummy_TkMenu *menuPtr; - char *dummy1; - char *dummy2; - char *dummy3; -}; - -#if 0 /* was available on Tk8.0 -- Tk8.4 */ -EXTERN struct dummy_TkMenuRef *TkFindMenuReferences(Tcl_Interp*, char*); -#else /* based on Tk8.0 -- Tk8.5.0 */ -#define MENU_HASH_KEY "tkMenus" -#endif - -#endif - -static VALUE -ip_make_menu_embeddable_core(interp, argc, argv) - VALUE interp; - int argc; - VALUE *argv; -{ -#if TCL_MAJOR_VERSION >= 8 - volatile VALUE menu_path; - struct tcltkip *ptr = get_ip(interp); - struct dummy_TkMenuRef *menuRefPtr = NULL; - XEvent event; - Tcl_HashTable *menuTablePtr; - Tcl_HashEntry *hashEntryPtr; - - menu_path = argv[0]; - StringValue(menu_path); - -#if 0 /* was available on Tk8.0 -- Tk8.4 */ - menuRefPtr = TkFindMenuReferences(ptr->ip, RSTRING_PTR(menu_path)); -#else /* based on Tk8.0 -- Tk8.5b1 */ - if ((menuTablePtr - = (Tcl_HashTable *) Tcl_GetAssocData(ptr->ip, MENU_HASH_KEY, NULL)) - != NULL) { - if ((hashEntryPtr - = Tcl_FindHashEntry(menuTablePtr, RSTRING_PTR(menu_path))) - != NULL) { - menuRefPtr = (struct dummy_TkMenuRef *) Tcl_GetHashValue(hashEntryPtr); - } - } -#endif - - if (menuRefPtr == (struct dummy_TkMenuRef *) NULL) { - rb_raise(rb_eArgError, "not a menu widget, or invalid widget path"); - } - - if (menuRefPtr->menuPtr == (struct dummy_TkMenu *) NULL) { - rb_raise(rb_eRuntimeError, - "invalid menu widget (maybe already destroyed)"); - } - - if ((menuRefPtr->menuPtr)->menuType != MENUBAR) { - rb_raise(rb_eRuntimeError, - "target menu widget must be a MENUBAR type"); - } - - (menuRefPtr->menuPtr)->menuType = TEAROFF_MENU; -#if 0 /* cause SEGV */ - { - /* char *s = "tearoff"; */ - char *s = "normal"; - /* Tcl_SetStringObj((menuRefPtr->menuPtr)->menuTypePtr, s, strlen(s));*/ - (menuRefPtr->menuPtr)->menuTypePtr = Tcl_NewStringObj(s, strlen(s)); - /* Tcl_IncrRefCount((menuRefPtr->menuPtr)->menuTypePtr); */ - /* (menuRefPtr->menuPtr)->menuType = TEAROFF_MENU; */ - (menuRefPtr->menuPtr)->menuType = MASTER_MENU; - } -#endif - -#if 0 /* was available on Tk8.0 -- Tk8.4 */ - TkEventuallyRecomputeMenu(menuRefPtr->menuPtr); - TkEventuallyRedrawMenu(menuRefPtr->menuPtr, - (struct dummy_TkMenuEntry *)NULL); -#else /* based on Tk8.0 -- Tk8.5b1 */ - memset((void *) &event, 0, sizeof(event)); - event.xany.type = ConfigureNotify; - event.xany.serial = NextRequest(Tk_Display((menuRefPtr->menuPtr)->tkwin)); - event.xany.send_event = 0; /* FALSE */ - event.xany.window = Tk_WindowId((menuRefPtr->menuPtr)->tkwin); - event.xany.display = Tk_Display((menuRefPtr->menuPtr)->tkwin); - event.xconfigure.window = event.xany.window; - Tk_HandleEvent(&event); -#endif - -#else /* TCL_MAJOR_VERSION <= 7 */ - rb_notimplement(); -#endif - - return interp; -} - -static VALUE -ip_make_menu_embeddable(interp, menu_path) - VALUE interp; - VALUE menu_path; -{ - VALUE argv[1]; - - argv[0] = menu_path; - return tk_funcall(ip_make_menu_embeddable_core, 1, argv, interp); -} - - -/*###############################################*/ - -/*---- initialization ----*/ -void -Init_tcltklib() -{ - int ret; - - VALUE lib = rb_define_module("TclTkLib"); - VALUE ip = rb_define_class("TclTkIp", rb_cObject); - - VALUE ev_flag = rb_define_module_under(lib, "EventFlag"); - VALUE var_flag = rb_define_module_under(lib, "VarAccessFlag"); - VALUE release_type = rb_define_module_under(lib, "RELEASE_TYPE"); - - /* --------------------------------------------------------------- */ - - tcltkip_class = ip; - - /* --------------------------------------------------------------- */ - -#ifdef HAVE_RUBY_ENCODING_H - rb_global_variable(&cRubyEncoding); - cRubyEncoding = rb_path2class("Encoding"); - - ENCODING_INDEX_UTF8 = rb_enc_to_index(rb_utf8_encoding()); - ENCODING_INDEX_BINARY = rb_enc_find_index("binary"); -#endif - - rb_global_variable(&ENCODING_NAME_UTF8); - rb_global_variable(&ENCODING_NAME_BINARY); - - ENCODING_NAME_UTF8 = rb_obj_freeze(rb_str_new2("utf-8")); - ENCODING_NAME_BINARY = rb_obj_freeze(rb_str_new2("binary")); - - /* --------------------------------------------------------------- */ - - rb_global_variable(&eTkCallbackReturn); - rb_global_variable(&eTkCallbackBreak); - rb_global_variable(&eTkCallbackContinue); - - rb_global_variable(&eventloop_thread); - rb_global_variable(&eventloop_stack); - rb_global_variable(&watchdog_thread); - - rb_global_variable(&rbtk_pending_exception); - - /* --------------------------------------------------------------- */ - - rb_define_const(lib, "COMPILE_INFO", tcltklib_compile_info()); - - rb_define_const(lib, "RELEASE_DATE", - rb_obj_freeze(rb_str_new2(tcltklib_release_date))); - - rb_define_const(lib, "FINALIZE_PROC_NAME", - rb_str_new2(finalize_hook_name)); - - /* --------------------------------------------------------------- */ - - rb_define_const(ev_flag, "NONE", INT2FIX(0)); - rb_define_const(ev_flag, "WINDOW", INT2FIX(TCL_WINDOW_EVENTS)); - rb_define_const(ev_flag, "FILE", INT2FIX(TCL_FILE_EVENTS)); - rb_define_const(ev_flag, "TIMER", INT2FIX(TCL_TIMER_EVENTS)); - rb_define_const(ev_flag, "IDLE", INT2FIX(TCL_IDLE_EVENTS)); - rb_define_const(ev_flag, "ALL", INT2FIX(TCL_ALL_EVENTS)); - rb_define_const(ev_flag, "DONT_WAIT", INT2FIX(TCL_DONT_WAIT)); - - /* --------------------------------------------------------------- */ - - rb_define_const(var_flag, "NONE", INT2FIX(0)); - rb_define_const(var_flag, "GLOBAL_ONLY", INT2FIX(TCL_GLOBAL_ONLY)); -#ifdef TCL_NAMESPACE_ONLY - rb_define_const(var_flag, "NAMESPACE_ONLY", INT2FIX(TCL_NAMESPACE_ONLY)); -#else /* probably Tcl7.6 */ - rb_define_const(var_flag, "NAMESPACE_ONLY", INT2FIX(0)); -#endif - rb_define_const(var_flag, "LEAVE_ERR_MSG", INT2FIX(TCL_LEAVE_ERR_MSG)); - rb_define_const(var_flag, "APPEND_VALUE", INT2FIX(TCL_APPEND_VALUE)); - rb_define_const(var_flag, "LIST_ELEMENT", INT2FIX(TCL_LIST_ELEMENT)); -#ifdef TCL_PARSE_PART1 - rb_define_const(var_flag, "PARSE_VARNAME", INT2FIX(TCL_PARSE_PART1)); -#else /* probably Tcl7.6 */ - rb_define_const(var_flag, "PARSE_VARNAME", INT2FIX(0)); -#endif - - /* --------------------------------------------------------------- */ - - rb_define_module_function(lib, "get_version", lib_getversion, -1); - - rb_define_const(release_type, "ALPHA", INT2FIX(TCL_ALPHA_RELEASE)); - rb_define_const(release_type, "BETA", INT2FIX(TCL_BETA_RELEASE)); - rb_define_const(release_type, "FINAL", INT2FIX(TCL_FINAL_RELEASE)); - - /* --------------------------------------------------------------- */ - - eTkCallbackReturn = rb_define_class("TkCallbackReturn", rb_eStandardError); - eTkCallbackBreak = rb_define_class("TkCallbackBreak", rb_eStandardError); - eTkCallbackContinue = rb_define_class("TkCallbackContinue", - rb_eStandardError); - - /* --------------------------------------------------------------- */ - - eLocalJumpError = rb_const_get(rb_cObject, rb_intern("LocalJumpError")); - - eTkLocalJumpError = rb_define_class("TkLocalJumpError", eLocalJumpError); - - eTkCallbackRetry = rb_define_class("TkCallbackRetry", eTkLocalJumpError); - eTkCallbackRedo = rb_define_class("TkCallbackRedo", eTkLocalJumpError); - eTkCallbackThrow = rb_define_class("TkCallbackThrow", eTkLocalJumpError); - - /* --------------------------------------------------------------- */ - - ID_at_enc = rb_intern("@encoding"); - ID_at_interp = rb_intern("@interp"); - ID_encoding_name = rb_intern("encoding_name"); - ID_encoding_table = rb_intern("encoding_table"); - - ID_stop_p = rb_intern("stop?"); - ID_alive_p = rb_intern("alive?"); - ID_kill = rb_intern("kill"); - ID_join = rb_intern("join"); - ID_value = rb_intern("value"); - - ID_call = rb_intern("call"); - ID_backtrace = rb_intern("backtrace"); - ID_message = rb_intern("message"); - - ID_at_reason = rb_intern("@reason"); - ID_return = rb_intern("return"); - ID_break = rb_intern("break"); - ID_next = rb_intern("next"); - - ID_to_s = rb_intern("to_s"); - ID_inspect = rb_intern("inspect"); - - /* --------------------------------------------------------------- */ - - rb_define_module_function(lib, "mainloop", lib_mainloop, -1); - rb_define_module_function(lib, "mainloop_thread?", - lib_evloop_thread_p, 0); - rb_define_module_function(lib, "mainloop_watchdog", - lib_mainloop_watchdog, -1); - rb_define_module_function(lib, "do_thread_callback", - lib_thread_callback, -1); - rb_define_module_function(lib, "do_one_event", lib_do_one_event, -1); - rb_define_module_function(lib, "mainloop_abort_on_exception", - lib_evloop_abort_on_exc, 0); - rb_define_module_function(lib, "mainloop_abort_on_exception=", - lib_evloop_abort_on_exc_set, 1); - rb_define_module_function(lib, "set_eventloop_window_mode", - set_eventloop_window_mode, 1); - rb_define_module_function(lib, "get_eventloop_window_mode", - get_eventloop_window_mode, 0); - rb_define_module_function(lib, "set_eventloop_tick",set_eventloop_tick,1); - rb_define_module_function(lib, "get_eventloop_tick",get_eventloop_tick,0); - rb_define_module_function(lib, "set_no_event_wait", set_no_event_wait, 1); - rb_define_module_function(lib, "get_no_event_wait", get_no_event_wait, 0); - rb_define_module_function(lib, "set_eventloop_weight", - set_eventloop_weight, 2); - rb_define_module_function(lib, "set_max_block_time", set_max_block_time,1); - rb_define_module_function(lib, "get_eventloop_weight", - get_eventloop_weight, 0); - rb_define_module_function(lib, "num_of_mainwindows", - lib_num_of_mainwindows, 0); - - /* --------------------------------------------------------------- */ - - rb_define_module_function(lib, "_split_tklist", lib_split_tklist, 1); - rb_define_module_function(lib, "_merge_tklist", lib_merge_tklist, -1); - rb_define_module_function(lib, "_conv_listelement", - lib_conv_listelement, 1); - rb_define_module_function(lib, "_toUTF8", lib_toUTF8, -1); - rb_define_module_function(lib, "_fromUTF8", lib_fromUTF8, -1); - rb_define_module_function(lib, "_subst_UTF_backslash", - lib_UTF_backslash, 1); - rb_define_module_function(lib, "_subst_Tcl_backslash", - lib_Tcl_backslash, 1); - - rb_define_module_function(lib, "encoding_system", - lib_get_system_encoding, 0); - rb_define_module_function(lib, "encoding_system=", - lib_set_system_encoding, 1); - rb_define_module_function(lib, "encoding", - lib_get_system_encoding, 0); - rb_define_module_function(lib, "encoding=", - lib_set_system_encoding, 1); - - /* --------------------------------------------------------------- */ - - rb_define_alloc_func(ip, ip_alloc); - rb_define_method(ip, "initialize", ip_init, -1); - rb_define_method(ip, "create_slave", ip_create_slave, -1); - rb_define_method(ip, "slave_of?", ip_is_slave_of_p, 1); - rb_define_method(ip, "make_safe", ip_make_safe, 0); - rb_define_method(ip, "safe?", ip_is_safe_p, 0); - rb_define_method(ip, "allow_ruby_exit?", ip_allow_ruby_exit_p, 0); - rb_define_method(ip, "allow_ruby_exit=", ip_allow_ruby_exit_set, 1); - rb_define_method(ip, "delete", ip_delete, 0); - rb_define_method(ip, "deleted?", ip_is_deleted_p, 0); - rb_define_method(ip, "has_mainwindow?", ip_has_mainwindow_p, 0); - rb_define_method(ip, "invalid_namespace?", ip_has_invalid_namespace_p, 0); - rb_define_method(ip, "_eval", ip_eval, 1); - rb_define_method(ip, "_toUTF8", ip_toUTF8, -1); - rb_define_method(ip, "_fromUTF8", ip_fromUTF8, -1); - rb_define_method(ip, "_thread_vwait", ip_thread_vwait, 1); - rb_define_method(ip, "_thread_tkwait", ip_thread_tkwait, 2); - rb_define_method(ip, "_invoke", ip_invoke, -1); - rb_define_method(ip, "_immediate_invoke", ip_invoke_immediate, -1); - rb_define_method(ip, "_return_value", ip_retval, 0); - - rb_define_method(ip, "_create_console", ip_create_console, 0); - - /* --------------------------------------------------------------- */ - - rb_define_method(ip, "create_dummy_encoding_for_tk", - create_dummy_encoding_for_tk, 1); - rb_define_method(ip, "encoding_table", ip_get_encoding_table, 0); - - /* --------------------------------------------------------------- */ - - rb_define_method(ip, "_get_variable", ip_get_variable, 2); - rb_define_method(ip, "_get_variable2", ip_get_variable2, 3); - rb_define_method(ip, "_set_variable", ip_set_variable, 3); - rb_define_method(ip, "_set_variable2", ip_set_variable2, 4); - rb_define_method(ip, "_unset_variable", ip_unset_variable, 2); - rb_define_method(ip, "_unset_variable2", ip_unset_variable2, 3); - rb_define_method(ip, "_get_global_var", ip_get_global_var, 1); - rb_define_method(ip, "_get_global_var2", ip_get_global_var2, 2); - rb_define_method(ip, "_set_global_var", ip_set_global_var, 2); - rb_define_method(ip, "_set_global_var2", ip_set_global_var2, 3); - rb_define_method(ip, "_unset_global_var", ip_unset_global_var, 1); - rb_define_method(ip, "_unset_global_var2", ip_unset_global_var2, 2); - - /* --------------------------------------------------------------- */ - - rb_define_method(ip, "_make_menu_embeddable", ip_make_menu_embeddable, 1); - - /* --------------------------------------------------------------- */ - - rb_define_method(ip, "_split_tklist", ip_split_tklist, 1); - rb_define_method(ip, "_merge_tklist", lib_merge_tklist, -1); - rb_define_method(ip, "_conv_listelement", lib_conv_listelement, 1); - - /* --------------------------------------------------------------- */ - - rb_define_method(ip, "mainloop", ip_mainloop, -1); - rb_define_method(ip, "mainloop_watchdog", ip_mainloop_watchdog, -1); - rb_define_method(ip, "do_one_event", ip_do_one_event, -1); - rb_define_method(ip, "mainloop_abort_on_exception", - ip_evloop_abort_on_exc, 0); - rb_define_method(ip, "mainloop_abort_on_exception=", - ip_evloop_abort_on_exc_set, 1); - rb_define_method(ip, "set_eventloop_tick", ip_set_eventloop_tick, 1); - rb_define_method(ip, "get_eventloop_tick", ip_get_eventloop_tick, 0); - rb_define_method(ip, "set_no_event_wait", ip_set_no_event_wait, 1); - rb_define_method(ip, "get_no_event_wait", ip_get_no_event_wait, 0); - rb_define_method(ip, "set_eventloop_weight", ip_set_eventloop_weight, 2); - rb_define_method(ip, "get_eventloop_weight", ip_get_eventloop_weight, 0); - rb_define_method(ip, "set_max_block_time", set_max_block_time, 1); - rb_define_method(ip, "restart", ip_restart, 0); - - /* --------------------------------------------------------------- */ - - eventloop_thread = Qnil; - -#ifndef DEFAULT_EVENTLOOP_DEPTH -#define DEFAULT_EVENTLOOP_DEPTH 7 -#endif - eventloop_stack = rb_ary_new2(DEFAULT_EVENTLOOP_DEPTH); - OBJ_TAINT(eventloop_stack); - - watchdog_thread = Qnil; - - rbtk_pending_exception = Qnil; - - /* --------------------------------------------------------------- */ - - /* if ruby->nativethread-supprt and tcltklib->doen't, - the following will cause link-error. */ - ruby_native_thread_p(); - - /* --------------------------------------------------------------- */ - - rb_set_end_proc(lib_mark_at_exit, 0); - - /* --------------------------------------------------------------- */ - - ret = ruby_open_tcl_dll(rb_argv0 ? RSTRING_PTR(rb_argv0) : 0); - switch(ret) { - case TCLTK_STUBS_OK: - break; - case NO_TCL_DLL: - rb_raise(rb_eLoadError, "tcltklib: fail to open tcl_dll"); - case NO_FindExecutable: - rb_raise(rb_eLoadError, "tcltklib: can't find Tcl_FindExecutable"); - default: - rb_raise(rb_eLoadError, "tcltklib: unknown error(%d) on ruby_open_tcl_dll", ret); - } - - /* --------------------------------------------------------------- */ - - /* Tcl stub check */ - tcl_stubs_check(); - - Tcl_ObjType_ByteArray = Tcl_GetObjType(Tcl_ObjTypeName_ByteArray); - Tcl_ObjType_String = Tcl_GetObjType(Tcl_ObjTypeName_String); - - /* --------------------------------------------------------------- */ - - (void)call_original_exit; -} - -/* eof */ |