|
Ruby
1.9.3p537(2014-02-19revision0)
|
00001 /* 00002 * tcltklib.c 00003 * Aug. 27, 1997 Y. Shigehiro 00004 * Oct. 24, 1997 Y. Matsumoto 00005 */ 00006 00007 #define TCLTKLIB_RELEASE_DATE "2010-08-25" 00008 /* #define CREATE_RUBYTK_KIT */ 00009 00010 #include "ruby.h" 00011 00012 #ifdef HAVE_RUBY_ENCODING_H 00013 #include "ruby/encoding.h" 00014 #endif 00015 #ifndef RUBY_VERSION 00016 #define RUBY_VERSION "(unknown version)" 00017 #endif 00018 #ifndef RUBY_RELEASE_DATE 00019 #define RUBY_RELEASE_DATE "unknown release-date" 00020 #endif 00021 00022 #ifdef RUBY_VM 00023 static VALUE rb_thread_critical; /* dummy */ 00024 int rb_thread_check_trap_pending(); 00025 #else 00026 /* use rb_thread_critical on Ruby 1.8.x */ 00027 #include "rubysig.h" 00028 #endif 00029 00030 #if !defined(RSTRING_PTR) 00031 #define RSTRING_PTR(s) (RSTRING(s)->ptr) 00032 #define RSTRING_LEN(s) (RSTRING(s)->len) 00033 #endif 00034 #if !defined(RARRAY_PTR) 00035 #define RARRAY_PTR(s) (RARRAY(s)->ptr) 00036 #define RARRAY_LEN(s) (RARRAY(s)->len) 00037 #endif 00038 00039 #ifdef OBJ_UNTRUST 00040 #define RbTk_OBJ_UNTRUST(x) do {OBJ_TAINT(x); OBJ_UNTRUST(x);} while (0) 00041 #else 00042 #define RbTk_OBJ_UNTRUST(x) OBJ_TAINT(x) 00043 #endif 00044 00045 #if defined(HAVE_RB_PROC_NEW) && !defined(RUBY_VM) 00046 /* Ruby 1.8 :: rb_proc_new() was hidden from intern.h at 2008/04/22 */ 00047 extern VALUE rb_proc_new _((VALUE (*)(ANYARGS/* VALUE yieldarg[, VALUE procarg] */), VALUE)); 00048 #endif 00049 00050 #undef EXTERN /* avoid conflict with tcl.h of tcl8.2 or before */ 00051 #include <stdio.h> 00052 #ifdef HAVE_STDARG_PROTOTYPES 00053 #include <stdarg.h> 00054 #define va_init_list(a,b) va_start(a,b) 00055 #else 00056 #include <varargs.h> 00057 #define va_init_list(a,b) va_start(a) 00058 #endif 00059 #include <string.h> 00060 00061 #if !defined HAVE_VSNPRINTF && !defined vsnprintf 00062 # ifdef WIN32 00063 /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ 00064 # define vsnprintf _vsnprintf 00065 # else 00066 # ifdef HAVE_RUBY_RUBY_H 00067 # include "ruby/missing.h" 00068 # else 00069 # include "missing.h" 00070 # endif 00071 # endif 00072 #endif 00073 00074 #include <tcl.h> 00075 #include <tk.h> 00076 00077 #ifndef HAVE_RUBY_NATIVE_THREAD_P 00078 #define ruby_native_thread_p() is_ruby_native_thread() 00079 #undef RUBY_USE_NATIVE_THREAD 00080 #else 00081 #define RUBY_USE_NATIVE_THREAD 1 00082 #endif 00083 00084 #ifndef HAVE_RB_ERRINFO 00085 #define rb_errinfo() (ruby_errinfo+0) /* cannot be l-value */ 00086 #else 00087 VALUE rb_errinfo(void); 00088 #endif 00089 #ifndef HAVE_RB_SAFE_LEVEL 00090 #define rb_safe_level() (ruby_safe_level+0) 00091 #endif 00092 #ifndef HAVE_RB_SOURCEFILE 00093 #define rb_sourcefile() (ruby_sourcefile+0) 00094 #endif 00095 00096 #include "stubs.h" 00097 00098 #ifndef TCL_ALPHA_RELEASE 00099 #define TCL_ALPHA_RELEASE 0 /* "alpha" */ 00100 #define TCL_BETA_RELEASE 1 /* "beta" */ 00101 #define TCL_FINAL_RELEASE 2 /* "final" */ 00102 #endif 00103 00104 static struct { 00105 int major; 00106 int minor; 00107 int type; /* ALPHA==0, BETA==1, FINAL==2 */ 00108 int patchlevel; 00109 } tcltk_version = {0, 0, 0, 0}; 00110 00111 static void 00112 set_tcltk_version() 00113 { 00114 if (tcltk_version.major) return; 00115 00116 Tcl_GetVersion(&(tcltk_version.major), 00117 &(tcltk_version.minor), 00118 &(tcltk_version.patchlevel), 00119 &(tcltk_version.type)); 00120 } 00121 00122 #if TCL_MAJOR_VERSION >= 8 00123 # ifndef CONST84 00124 # if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION <= 4 /* Tcl8.0.x -- 8.4b1 */ 00125 # define CONST84 00126 # else /* unknown (maybe TCL_VERSION >= 8.5) */ 00127 # ifdef CONST 00128 # define CONST84 CONST 00129 # else 00130 # define CONST84 00131 # endif 00132 # endif 00133 # endif 00134 #else /* TCL_MAJOR_VERSION < 8 */ 00135 # ifdef CONST 00136 # define CONST84 CONST 00137 # else 00138 # define CONST 00139 # define CONST84 00140 # endif 00141 #endif 00142 00143 #ifndef CONST86 00144 # if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION <= 5 /* Tcl8.0.x -- 8.5.x */ 00145 # define CONST86 00146 # else 00147 # define CONST86 CONST84 00148 # endif 00149 #endif 00150 00151 /* copied from eval.c */ 00152 #define TAG_RETURN 0x1 00153 #define TAG_BREAK 0x2 00154 #define TAG_NEXT 0x3 00155 #define TAG_RETRY 0x4 00156 #define TAG_REDO 0x5 00157 #define TAG_RAISE 0x6 00158 #define TAG_THROW 0x7 00159 #define TAG_FATAL 0x8 00160 00161 /* for ruby_debug */ 00162 #define DUMP1(ARG1) if (ruby_debug) { fprintf(stderr, "tcltklib: %s\n", ARG1); fflush(stderr); } 00163 #define DUMP2(ARG1, ARG2) if (ruby_debug) { fprintf(stderr, "tcltklib: ");\ 00164 fprintf(stderr, ARG1, ARG2); fprintf(stderr, "\n"); fflush(stderr); } 00165 #define DUMP3(ARG1, ARG2, ARG3) if (ruby_debug) { fprintf(stderr, "tcltklib: ");\ 00166 fprintf(stderr, ARG1, ARG2, ARG3); fprintf(stderr, "\n"); fflush(stderr); } 00167 /* 00168 #define DUMP1(ARG1) 00169 #define DUMP2(ARG1, ARG2) 00170 #define DUMP3(ARG1, ARG2, ARG3) 00171 */ 00172 00173 /* release date */ 00174 static const char tcltklib_release_date[] = TCLTKLIB_RELEASE_DATE; 00175 00176 /* finalize_proc_name */ 00177 static const char finalize_hook_name[] = "INTERP_FINALIZE_HOOK"; 00178 00179 static void ip_finalize _((Tcl_Interp*)); 00180 00181 static int at_exit = 0; 00182 00183 #ifdef HAVE_RUBY_ENCODING_H 00184 static VALUE cRubyEncoding; 00185 00186 /* encoding */ 00187 static int ENCODING_INDEX_UTF8; 00188 static int ENCODING_INDEX_BINARY; 00189 #endif 00190 static VALUE ENCODING_NAME_UTF8; 00191 static VALUE ENCODING_NAME_BINARY; 00192 00193 static VALUE create_dummy_encoding_for_tk_core _((VALUE, VALUE, VALUE)); 00194 static VALUE create_dummy_encoding_for_tk _((VALUE, VALUE)); 00195 static int update_encoding_table _((VALUE, VALUE, VALUE)); 00196 static VALUE encoding_table_get_name_core _((VALUE, VALUE, VALUE)); 00197 static VALUE encoding_table_get_obj_core _((VALUE, VALUE, VALUE)); 00198 static VALUE encoding_table_get_name _((VALUE, VALUE)); 00199 static VALUE encoding_table_get_obj _((VALUE, VALUE)); 00200 static VALUE create_encoding_table _((VALUE)); 00201 static VALUE ip_get_encoding_table _((VALUE)); 00202 00203 00204 /* for callback break & continue */ 00205 static VALUE eTkCallbackReturn; 00206 static VALUE eTkCallbackBreak; 00207 static VALUE eTkCallbackContinue; 00208 00209 static VALUE eLocalJumpError; 00210 00211 static VALUE eTkLocalJumpError; 00212 static VALUE eTkCallbackRetry; 00213 static VALUE eTkCallbackRedo; 00214 static VALUE eTkCallbackThrow; 00215 00216 static VALUE tcltkip_class; 00217 00218 static ID ID_at_enc; 00219 static ID ID_at_interp; 00220 00221 static ID ID_encoding_name; 00222 static ID ID_encoding_table; 00223 00224 static ID ID_stop_p; 00225 static ID ID_alive_p; 00226 static ID ID_kill; 00227 static ID ID_join; 00228 static ID ID_value; 00229 00230 static ID ID_call; 00231 static ID ID_backtrace; 00232 static ID ID_message; 00233 00234 static ID ID_at_reason; 00235 static ID ID_return; 00236 static ID ID_break; 00237 static ID ID_next; 00238 00239 static ID ID_to_s; 00240 static ID ID_inspect; 00241 00242 static VALUE ip_invoke_real _((int, VALUE*, VALUE)); 00243 static VALUE ip_invoke _((int, VALUE*, VALUE)); 00244 static VALUE ip_invoke_with_position _((int, VALUE*, VALUE, Tcl_QueuePosition)); 00245 static VALUE tk_funcall _((VALUE(), int, VALUE*, VALUE)); 00246 static VALUE callq_safelevel_handler _((VALUE, VALUE)); 00247 00248 /* Tcl's object type */ 00249 #if TCL_MAJOR_VERSION >= 8 00250 static const char Tcl_ObjTypeName_ByteArray[] = "bytearray"; 00251 static CONST86 Tcl_ObjType *Tcl_ObjType_ByteArray; 00252 00253 static const char Tcl_ObjTypeName_String[] = "string"; 00254 static CONST86 Tcl_ObjType *Tcl_ObjType_String; 00255 00256 #if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1) 00257 #define IS_TCL_BYTEARRAY(obj) ((obj)->typePtr == Tcl_ObjType_ByteArray) 00258 #define IS_TCL_STRING(obj) ((obj)->typePtr == Tcl_ObjType_String) 00259 #define IS_TCL_VALID_STRING(obj) ((obj)->bytes != (char*)NULL) 00260 #endif 00261 #endif 00262 00263 #ifndef HAVE_RB_HASH_LOOKUP 00264 #define rb_hash_lookup rb_hash_aref 00265 #endif 00266 00267 /* safe Tcl_Eval and Tcl_GlobalEval */ 00268 static int 00269 #ifdef HAVE_PROTOTYPES 00270 tcl_eval(Tcl_Interp *interp, const char *cmd) 00271 #else 00272 tcl_eval(interp, cmd) 00273 Tcl_Interp *interp; 00274 const char *cmd; /* don't have to be writable */ 00275 #endif 00276 { 00277 char *buf = strdup(cmd); 00278 int ret; 00279 00280 Tcl_AllowExceptions(interp); 00281 ret = Tcl_Eval(interp, buf); 00282 free(buf); 00283 return ret; 00284 } 00285 00286 #undef Tcl_Eval 00287 #define Tcl_Eval tcl_eval 00288 00289 static int 00290 #ifdef HAVE_PROTOTYPES 00291 tcl_global_eval(Tcl_Interp *interp, const char *cmd) 00292 #else 00293 tcl_global_eval(interp, cmd) 00294 Tcl_Interp *interp; 00295 const char *cmd; /* don't have to be writable */ 00296 #endif 00297 { 00298 char *buf = strdup(cmd); 00299 int ret; 00300 00301 Tcl_AllowExceptions(interp); 00302 ret = Tcl_GlobalEval(interp, buf); 00303 free(buf); 00304 return ret; 00305 } 00306 00307 #undef Tcl_GlobalEval 00308 #define Tcl_GlobalEval tcl_global_eval 00309 00310 /* Tcl_{Incr|Decr}RefCount for tcl7.x or earlier */ 00311 #if TCL_MAJOR_VERSION < 8 00312 #define Tcl_IncrRefCount(obj) (1) 00313 #define Tcl_DecrRefCount(obj) (1) 00314 #endif 00315 00316 /* Tcl_GetStringResult for tcl7.x or earlier */ 00317 #if TCL_MAJOR_VERSION < 8 00318 #define Tcl_GetStringResult(interp) ((interp)->result) 00319 #endif 00320 00321 /* Tcl_[GS]etVar2Ex for tcl8.0 */ 00322 #if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0 00323 static Tcl_Obj * 00324 Tcl_GetVar2Ex(interp, name1, name2, flags) 00325 Tcl_Interp *interp; 00326 CONST char *name1; 00327 CONST char *name2; 00328 int flags; 00329 { 00330 Tcl_Obj *nameObj1, *nameObj2 = NULL, *retObj; 00331 00332 nameObj1 = Tcl_NewStringObj((char*)name1, -1); 00333 Tcl_IncrRefCount(nameObj1); 00334 00335 if (name2) { 00336 nameObj2 = Tcl_NewStringObj((char*)name2, -1); 00337 Tcl_IncrRefCount(nameObj2); 00338 } 00339 00340 retObj = Tcl_ObjGetVar2(interp, nameObj1, nameObj2, flags); 00341 00342 if (name2) { 00343 Tcl_DecrRefCount(nameObj2); 00344 } 00345 00346 Tcl_DecrRefCount(nameObj1); 00347 00348 return retObj; 00349 } 00350 00351 static Tcl_Obj * 00352 Tcl_SetVar2Ex(interp, name1, name2, newValObj, flags) 00353 Tcl_Interp *interp; 00354 CONST char *name1; 00355 CONST char *name2; 00356 Tcl_Obj *newValObj; 00357 int flags; 00358 { 00359 Tcl_Obj *nameObj1, *nameObj2 = NULL, *retObj; 00360 00361 nameObj1 = Tcl_NewStringObj((char*)name1, -1); 00362 Tcl_IncrRefCount(nameObj1); 00363 00364 if (name2) { 00365 nameObj2 = Tcl_NewStringObj((char*)name2, -1); 00366 Tcl_IncrRefCount(nameObj2); 00367 } 00368 00369 retObj = Tcl_ObjSetVar2(interp, nameObj1, nameObj2, newValObj, flags); 00370 00371 if (name2) { 00372 Tcl_DecrRefCount(nameObj2); 00373 } 00374 00375 Tcl_DecrRefCount(nameObj1); 00376 00377 return retObj; 00378 } 00379 #endif 00380 00381 /* from tkAppInit.c */ 00382 00383 #if TCL_MAJOR_VERSION < 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION < 4) 00384 # if !defined __MINGW32__ && !defined __BORLANDC__ 00385 /* 00386 * The following variable is a special hack that is needed in order for 00387 * Sun shared libraries to be used for Tcl. 00388 */ 00389 00390 extern int matherr(); 00391 int *tclDummyMathPtr = (int *) matherr; 00392 # endif 00393 #endif 00394 00395 /*---- module TclTkLib ----*/ 00396 00397 struct invoke_queue { 00398 Tcl_Event ev; 00399 int argc; 00400 #if TCL_MAJOR_VERSION >= 8 00401 Tcl_Obj **argv; 00402 #else /* TCL_MAJOR_VERSION < 8 */ 00403 char **argv; 00404 #endif 00405 VALUE interp; 00406 int *done; 00407 int safe_level; 00408 VALUE result; 00409 VALUE thread; 00410 }; 00411 00412 struct eval_queue { 00413 Tcl_Event ev; 00414 char *str; 00415 int len; 00416 VALUE interp; 00417 int *done; 00418 int safe_level; 00419 VALUE result; 00420 VALUE thread; 00421 }; 00422 00423 struct call_queue { 00424 Tcl_Event ev; 00425 VALUE (*func)(); 00426 int argc; 00427 VALUE *argv; 00428 VALUE interp; 00429 int *done; 00430 int safe_level; 00431 VALUE result; 00432 VALUE thread; 00433 }; 00434 00435 void 00436 invoke_queue_mark(struct invoke_queue *q) 00437 { 00438 rb_gc_mark(q->interp); 00439 rb_gc_mark(q->result); 00440 rb_gc_mark(q->thread); 00441 } 00442 00443 void 00444 eval_queue_mark(struct eval_queue *q) 00445 { 00446 rb_gc_mark(q->interp); 00447 rb_gc_mark(q->result); 00448 rb_gc_mark(q->thread); 00449 } 00450 00451 void 00452 call_queue_mark(struct call_queue *q) 00453 { 00454 int i; 00455 00456 for(i = 0; i < q->argc; i++) { 00457 rb_gc_mark(q->argv[i]); 00458 } 00459 00460 rb_gc_mark(q->interp); 00461 rb_gc_mark(q->result); 00462 rb_gc_mark(q->thread); 00463 } 00464 00465 00466 static VALUE eventloop_thread; 00467 static Tcl_Interp *eventloop_interp; 00468 #ifdef RUBY_USE_NATIVE_THREAD 00469 Tcl_ThreadId tk_eventloop_thread_id; /* native thread ID of Tcl interpreter */ 00470 #endif 00471 static VALUE eventloop_stack; 00472 static int window_event_mode = ~0; 00473 00474 static VALUE watchdog_thread; 00475 00476 Tcl_Interp *current_interp; 00477 00478 /* thread control strategy */ 00479 /* multi-tk works with the following settings only ??? 00480 : CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE 1 00481 : USE_TOGGLE_WINDOW_MODE_FOR_IDLE 0 00482 : DO_THREAD_SCHEDULE_AT_CALLBACK_DONE 0 00483 */ 00484 #ifdef RUBY_USE_NATIVE_THREAD 00485 #define CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE 1 00486 #define USE_TOGGLE_WINDOW_MODE_FOR_IDLE 0 00487 #define DO_THREAD_SCHEDULE_AT_CALLBACK_DONE 1 00488 #else /* ! RUBY_USE_NATIVE_THREAD */ 00489 #define CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE 1 00490 #define USE_TOGGLE_WINDOW_MODE_FOR_IDLE 0 00491 #define DO_THREAD_SCHEDULE_AT_CALLBACK_DONE 0 00492 #endif 00493 00494 #if CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE 00495 static int have_rb_thread_waiting_for_value = 0; 00496 #endif 00497 00498 /* 00499 * 'event_loop_max' is a maximum events which the eventloop processes in one 00500 * term of thread scheduling. 'no_event_tick' is the count-up value when 00501 * there are no event for processing. 00502 * 'timer_tick' is a limit of one term of thread scheduling. 00503 * If 'timer_tick' == 0, then not use the timer for thread scheduling. 00504 */ 00505 #ifdef RUBY_USE_NATIVE_THREAD 00506 #define DEFAULT_EVENT_LOOP_MAX 800/*counts*/ 00507 #define DEFAULT_NO_EVENT_TICK 10/*counts*/ 00508 #define DEFAULT_NO_EVENT_WAIT 5/*milliseconds ( 1 -- 999 ) */ 00509 #define WATCHDOG_INTERVAL 10/*milliseconds ( 1 -- 999 ) */ 00510 #define DEFAULT_TIMER_TICK 0/*milliseconds ( 0 -- 999 ) */ 00511 #define NO_THREAD_INTERRUPT_TIME 100/*milliseconds ( 1 -- 999 ) */ 00512 #else /* ! RUBY_USE_NATIVE_THREAD */ 00513 #define DEFAULT_EVENT_LOOP_MAX 800/*counts*/ 00514 #define DEFAULT_NO_EVENT_TICK 10/*counts*/ 00515 #define DEFAULT_NO_EVENT_WAIT 20/*milliseconds ( 1 -- 999 ) */ 00516 #define WATCHDOG_INTERVAL 10/*milliseconds ( 1 -- 999 ) */ 00517 #define DEFAULT_TIMER_TICK 0/*milliseconds ( 0 -- 999 ) */ 00518 #define NO_THREAD_INTERRUPT_TIME 100/*milliseconds ( 1 -- 999 ) */ 00519 #endif 00520 00521 #define EVENT_HANDLER_TIMEOUT 100/*milliseconds*/ 00522 00523 static int event_loop_max = DEFAULT_EVENT_LOOP_MAX; 00524 static int no_event_tick = DEFAULT_NO_EVENT_TICK; 00525 static int no_event_wait = DEFAULT_NO_EVENT_WAIT; 00526 static int timer_tick = DEFAULT_TIMER_TICK; 00527 static int req_timer_tick = DEFAULT_TIMER_TICK; 00528 static int run_timer_flag = 0; 00529 00530 static int event_loop_wait_event = 0; 00531 static int event_loop_abort_on_exc = 1; 00532 static int loop_counter = 0; 00533 00534 static int check_rootwidget_flag = 0; 00535 00536 00537 /* call ruby interpreter */ 00538 #if TCL_MAJOR_VERSION >= 8 00539 static int ip_ruby_eval _((ClientData, Tcl_Interp *, int, Tcl_Obj *CONST*)); 00540 static int ip_ruby_cmd _((ClientData, Tcl_Interp *, int, Tcl_Obj *CONST*)); 00541 #else /* TCL_MAJOR_VERSION < 8 */ 00542 static int ip_ruby_eval _((ClientData, Tcl_Interp *, int, char **)); 00543 static int ip_ruby_cmd _((ClientData, Tcl_Interp *, int, char **)); 00544 #endif 00545 00546 struct cmd_body_arg { 00547 VALUE receiver; 00548 ID method; 00549 VALUE args; 00550 }; 00551 00552 /*----------------------------*/ 00553 /* use Tcl internal functions */ 00554 /*----------------------------*/ 00555 #ifndef TCL_NAMESPACE_DEBUG 00556 #define TCL_NAMESPACE_DEBUG 0 00557 #endif 00558 00559 #if TCL_NAMESPACE_DEBUG 00560 00561 #if TCL_MAJOR_VERSION >= 8 00562 EXTERN struct TclIntStubs *tclIntStubsPtr; 00563 #endif 00564 00565 /*-- Tcl_GetCurrentNamespace --*/ 00566 #if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION < 5 00567 /* Tcl7.x doesn't have namespace support. */ 00568 /* Tcl8.5+ has definition of Tcl_GetCurrentNamespace() in tclDecls.h */ 00569 # ifndef Tcl_GetCurrentNamespace 00570 EXTERN Tcl_Namespace * Tcl_GetCurrentNamespace _((Tcl_Interp *)); 00571 # endif 00572 # if defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) 00573 # ifndef Tcl_GetCurrentNamespace 00574 # ifndef FunctionNum_of_GetCurrentNamespace 00575 #define FunctionNum_of_GetCurrentNamespace 124 00576 # endif 00577 struct DummyTclIntStubs_for_GetCurrentNamespace { 00578 int magic; 00579 struct TclIntStubHooks *hooks; 00580 void (*func[FunctionNum_of_GetCurrentNamespace])(); 00581 Tcl_Namespace * (*tcl_GetCurrentNamespace) _((Tcl_Interp *)); 00582 }; 00583 00584 #define Tcl_GetCurrentNamespace \ 00585 (((struct DummyTclIntStubs_for_GetCurrentNamespace *)tclIntStubsPtr)->tcl_GetCurrentNamespace) 00586 # endif 00587 # endif 00588 #endif 00589 00590 /* namespace check */ 00591 /* ip_null_namespace(Tcl_Interp *interp) */ 00592 #if TCL_MAJOR_VERSION < 8 00593 #define ip_null_namespace(interp) (0) 00594 #else /* support namespace */ 00595 #define ip_null_namespace(interp) \ 00596 (Tcl_GetCurrentNamespace(interp) == (Tcl_Namespace *)NULL) 00597 #endif 00598 00599 /* rbtk_invalid_namespace(tcltkip *ptr) */ 00600 #if TCL_MAJOR_VERSION < 8 00601 #define rbtk_invalid_namespace(ptr) (0) 00602 #else /* support namespace */ 00603 #define rbtk_invalid_namespace(ptr) \ 00604 ((ptr)->default_ns == (Tcl_Namespace*)NULL || Tcl_GetCurrentNamespace((ptr)->ip) != (ptr)->default_ns) 00605 #endif 00606 00607 /*-- Tcl_PopCallFrame & Tcl_PushCallFrame --*/ 00608 #if TCL_MAJOR_VERSION >= 8 00609 # ifndef CallFrame 00610 typedef struct CallFrame { 00611 Tcl_Namespace *nsPtr; 00612 int dummy1; 00613 int dummy2; 00614 char *dummy3; 00615 struct CallFrame *callerPtr; 00616 struct CallFrame *callerVarPtr; 00617 int level; 00618 char *dummy7; 00619 char *dummy8; 00620 int dummy9; 00621 char* dummy10; 00622 } CallFrame; 00623 # endif 00624 00625 # if !defined(TclGetFrame) && !defined(TclGetFrame_TCL_DECLARED) 00626 EXTERN int TclGetFrame _((Tcl_Interp *, CONST char *, CallFrame **)); 00627 # endif 00628 # if defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) 00629 # ifndef TclGetFrame 00630 # ifndef FunctionNum_of_GetFrame 00631 #define FunctionNum_of_GetFrame 32 00632 # endif 00633 struct DummyTclIntStubs_for_GetFrame { 00634 int magic; 00635 struct TclIntStubHooks *hooks; 00636 void (*func[FunctionNum_of_GetFrame])(); 00637 int (*tclGetFrame) _((Tcl_Interp *, CONST char *, CallFrame **)); 00638 }; 00639 #define TclGetFrame \ 00640 (((struct DummyTclIntStubs_for_GetFrame *)tclIntStubsPtr)->tclGetFrame) 00641 # endif 00642 # endif 00643 00644 # if !defined(Tcl_PopCallFrame) && !defined(Tcl_PopCallFrame_TCL_DECLARED) 00645 EXTERN void Tcl_PopCallFrame _((Tcl_Interp *)); 00646 EXTERN int Tcl_PushCallFrame _((Tcl_Interp *, Tcl_CallFrame *, Tcl_Namespace *, int)); 00647 # endif 00648 # if defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) 00649 # ifndef Tcl_PopCallFrame 00650 # ifndef FunctionNum_of_PopCallFrame 00651 #define FunctionNum_of_PopCallFrame 128 00652 # endif 00653 struct DummyTclIntStubs_for_PopCallFrame { 00654 int magic; 00655 struct TclIntStubHooks *hooks; 00656 void (*func[FunctionNum_of_PopCallFrame])(); 00657 void (*tcl_PopCallFrame) _((Tcl_Interp *)); 00658 int (*tcl_PushCallFrame) _((Tcl_Interp *, Tcl_CallFrame *, Tcl_Namespace *, int)); 00659 }; 00660 00661 #define Tcl_PopCallFrame \ 00662 (((struct DummyTclIntStubs_for_PopCallFrame *)tclIntStubsPtr)->tcl_PopCallFrame) 00663 #define Tcl_PushCallFrame \ 00664 (((struct DummyTclIntStubs_for_PopCallFrame *)tclIntStubsPtr)->tcl_PushCallFrame) 00665 # endif 00666 # endif 00667 00668 #else /* Tcl7.x */ 00669 # ifndef CallFrame 00670 typedef struct CallFrame { 00671 Tcl_HashTable varTable; 00672 int level; 00673 int argc; 00674 char **argv; 00675 struct CallFrame *callerPtr; 00676 struct CallFrame *callerVarPtr; 00677 } CallFrame; 00678 # endif 00679 # ifndef Tcl_CallFrame 00680 #define Tcl_CallFrame CallFrame 00681 # endif 00682 00683 # if !defined(TclGetFrame) && !defined(TclGetFrame_TCL_DECLARED) 00684 EXTERN int TclGetFrame _((Tcl_Interp *, CONST char *, CallFrame **)); 00685 # endif 00686 00687 # if !defined(Tcl_PopCallFrame) && !defined(Tcl_PopCallFrame_TCL_DECLARED) 00688 typedef struct DummyInterp { 00689 char *dummy1; 00690 char *dummy2; 00691 int dummy3; 00692 Tcl_HashTable dummy4; 00693 Tcl_HashTable dummy5; 00694 Tcl_HashTable dummy6; 00695 int numLevels; 00696 int maxNestingDepth; 00697 CallFrame *framePtr; 00698 CallFrame *varFramePtr; 00699 } DummyInterp; 00700 00701 static void 00702 Tcl_PopCallFrame(interp) 00703 Tcl_Interp *interp; 00704 { 00705 DummyInterp *iPtr = (DummyInterp*)interp; 00706 CallFrame *frame = iPtr->varFramePtr; 00707 00708 /* **** DUMMY **** */ 00709 iPtr->framePtr = frame.callerPtr; 00710 iPtr->varFramePtr = frame.callerVarPtr; 00711 00712 return TCL_OK; 00713 } 00714 00715 /* dummy */ 00716 #define Tcl_Namespace char 00717 00718 static int 00719 Tcl_PushCallFrame(interp, framePtr, nsPtr, isProcCallFrame) 00720 Tcl_Interp *interp; 00721 Tcl_CallFrame *framePtr; 00722 Tcl_Namespace *nsPtr; 00723 int isProcCallFrame; 00724 { 00725 DummyInterp *iPtr = (DummyInterp*)interp; 00726 CallFrame *frame = (CallFrame *)framePtr; 00727 00728 /* **** DUMMY **** */ 00729 Tcl_InitHashTable(&frame.varTable, TCL_STRING_KEYS); 00730 if (iPtr->varFramePtr != NULL) { 00731 frame.level = iPtr->varFramePtr->level + 1; 00732 } else { 00733 frame.level = 1; 00734 } 00735 frame.callerPtr = iPtr->framePtr; 00736 frame.callerVarPtr = iPtr->varFramePtr; 00737 iPtr->framePtr = &frame; 00738 iPtr->varFramePtr = &frame; 00739 00740 return TCL_OK; 00741 } 00742 # endif 00743 00744 #endif 00745 00746 #endif /* TCL_NAMESPACE_DEBUG */ 00747 00748 00749 /*---- class TclTkIp ----*/ 00750 struct tcltkip { 00751 Tcl_Interp *ip; /* the interpreter */ 00752 #if TCL_NAMESPACE_DEBUG 00753 Tcl_Namespace *default_ns; /* default namespace */ 00754 #endif 00755 #ifdef RUBY_USE_NATIVE_THREAD 00756 Tcl_ThreadId tk_thread_id; /* native thread ID of Tcl interpreter */ 00757 #endif 00758 int has_orig_exit; /* has original 'exit' command ? */ 00759 Tcl_CmdInfo orig_exit_info; /* command info of original 'exit' command */ 00760 int ref_count; /* reference count of rbtk_preserve_ip call */ 00761 int allow_ruby_exit; /* allow exiting ruby by 'exit' function */ 00762 int return_value; /* return value */ 00763 }; 00764 00765 static struct tcltkip * 00766 get_ip(self) 00767 VALUE self; 00768 { 00769 struct tcltkip *ptr; 00770 00771 Data_Get_Struct(self, struct tcltkip, ptr); 00772 if (ptr == 0) { 00773 /* rb_raise(rb_eTypeError, "uninitialized TclTkIp"); */ 00774 return((struct tcltkip *)NULL); 00775 } 00776 if (ptr->ip == (Tcl_Interp*)NULL) { 00777 /* rb_raise(rb_eRuntimeError, "deleted IP"); */ 00778 return((struct tcltkip *)NULL); 00779 } 00780 return ptr; 00781 } 00782 00783 static int 00784 deleted_ip(ptr) 00785 struct tcltkip *ptr; 00786 { 00787 if (!ptr || !ptr->ip || Tcl_InterpDeleted(ptr->ip) 00788 #if TCL_NAMESPACE_DEBUG 00789 || rbtk_invalid_namespace(ptr) 00790 #endif 00791 ) { 00792 DUMP1("ip is deleted"); 00793 return 1; 00794 } 00795 return 0; 00796 } 00797 00798 /* increment/decrement reference count of tcltkip */ 00799 static int 00800 rbtk_preserve_ip(ptr) 00801 struct tcltkip *ptr; 00802 { 00803 ptr->ref_count++; 00804 if (ptr->ip == (Tcl_Interp*)NULL) { 00805 /* deleted IP */ 00806 ptr->ref_count = 0; 00807 } else { 00808 Tcl_Preserve((ClientData)ptr->ip); 00809 } 00810 return(ptr->ref_count); 00811 } 00812 00813 static int 00814 rbtk_release_ip(ptr) 00815 struct tcltkip *ptr; 00816 { 00817 ptr->ref_count--; 00818 if (ptr->ref_count < 0) { 00819 ptr->ref_count = 0; 00820 } else if (ptr->ip == (Tcl_Interp*)NULL) { 00821 /* deleted IP */ 00822 ptr->ref_count = 0; 00823 } else { 00824 Tcl_Release((ClientData)ptr->ip); 00825 } 00826 return(ptr->ref_count); 00827 } 00828 00829 00830 static VALUE 00831 #ifdef HAVE_STDARG_PROTOTYPES 00832 create_ip_exc(VALUE interp, VALUE exc, const char *fmt, ...) 00833 #else 00834 create_ip_exc(interp, exc, fmt, va_alist) 00835 VALUE interp: 00836 VALUE exc; 00837 const char *fmt; 00838 va_dcl 00839 #endif 00840 { 00841 va_list args; 00842 VALUE msg; 00843 VALUE einfo; 00844 struct tcltkip *ptr = get_ip(interp); 00845 00846 va_init_list(args,fmt); 00847 msg = rb_vsprintf(fmt, args); 00848 va_end(args); 00849 einfo = rb_exc_new3(exc, msg); 00850 rb_ivar_set(einfo, ID_at_interp, interp); 00851 if (ptr) { 00852 Tcl_ResetResult(ptr->ip); 00853 } 00854 00855 return einfo; 00856 } 00857 00858 00859 /*####################################################################*/ 00860 #if defined CREATE_RUBYTK_KIT || defined CREATE_RUBYKIT 00861 00862 /*--------------------------------------------------------*/ 00863 00864 #if 10 * TCL_MAJOR_VERSION + TCL_MINOR_VERSION < 84 00865 #error Ruby/Tk-Kit requires Tcl/Tk8.4 or later. 00866 #endif 00867 00868 /*--------------------------------------------------------*/ 00869 00870 /* Many part of code to support Ruby/Tk-Kit is quoted from Tclkit. */ 00871 /* But, never ask Tclkit community about Ruby/Tk-Kit. */ 00872 /* Please ask Ruby (Ruby/Tk) community (e.g. "ruby-dev" mailing list). */ 00873 /* 00874 ----<< license terms of TclKit (from kitgen's "README" file) >>--------------- 00875 The Tclkit-specific sources are license free, they just have a copyright. Hold 00876 the author(s) harmless and any lawful use is permitted. 00877 00878 This does *not* apply to any of the sources of the other major Open Source 00879 Software used in Tclkit, which each have very liberal BSD/MIT-like licenses: 00880 00881 * Tcl/Tk, TclVFS, Thread, Vlerq, Zlib 00882 ------------------------------------------------------------------------------ 00883 */ 00884 /* Tcl/Tk stubs may work, but probably it is meaningless. */ 00885 #if defined USE_TCL_STUBS || defined USE_TK_STUBS 00886 # error Not support Tcl/Tk stubs with Ruby/Tk-Kit or Rubykit. 00887 #endif 00888 00889 #ifndef KIT_INCLUDES_ZLIB 00890 #if 10 * TCL_MAJOR_VERSION + TCL_MINOR_VERSION < 86 00891 #define KIT_INCLUDES_ZLIB 1 00892 #else 00893 #define KIT_INCLUDES_ZLIB 0 00894 #endif 00895 #endif 00896 00897 #ifdef _WIN32 00898 #define WIN32_LEAN_AND_MEAN 00899 #include <windows.h> 00900 #undef WIN32_LEAN_AND_MEAN 00901 #endif 00902 00903 #if 10 * TCL_MAJOR_VERSION + TCL_MINOR_VERSION < 86 00904 EXTERN Tcl_Obj* TclGetStartupScriptPath(); 00905 EXTERN void TclSetStartupScriptPath _((Tcl_Obj*)); 00906 #define Tcl_GetStartupScript(encPtr) TclGetStartupScriptPath() 00907 #define Tcl_SetStartupScript(path,enc) TclSetStartupScriptPath(path) 00908 #endif 00909 #if !defined(TclSetPreInitScript) && !defined(TclSetPreInitScript_TCL_DECLARED) 00910 EXTERN char* TclSetPreInitScript _((char *)); 00911 #endif 00912 00913 #ifndef KIT_INCLUDES_TK 00914 # define KIT_INCLUDES_TK 1 00915 #endif 00916 /* #define KIT_INCLUDES_ITCL 1 */ 00917 /* #define KIT_INCLUDES_THREAD 1 */ 00918 00919 Tcl_AppInitProc Vfs_Init, Rechan_Init; 00920 #if 10 * TCL_MAJOR_VERSION + TCL_MINOR_VERSION < 85 00921 Tcl_AppInitProc Pwb_Init; 00922 #endif 00923 00924 #ifdef KIT_LITE 00925 Tcl_AppInitProc Vlerq_Init, Vlerq_SafeInit; 00926 #else 00927 Tcl_AppInitProc Mk4tcl_Init; 00928 #endif 00929 00930 #if defined TCL_THREADS && defined KIT_INCLUDES_THREAD 00931 Tcl_AppInitProc Thread_Init; 00932 #endif 00933 00934 #if KIT_INCLUDES_ZLIB 00935 Tcl_AppInitProc Zlib_Init; 00936 #endif 00937 00938 #ifdef KIT_INCLUDES_ITCL 00939 Tcl_AppInitProc Itcl_Init; 00940 #endif 00941 00942 #ifdef _WIN32 00943 Tcl_AppInitProc Dde_Init, Dde_SafeInit, Registry_Init; 00944 #endif 00945 00946 /*--------------------------------------------------------*/ 00947 00948 #define RUBYTK_KITPATH_CONST_NAME "RUBYTK_KITPATH" 00949 00950 static char *rubytk_kitpath = NULL; 00951 00952 static char rubytkkit_preInitCmd[] = 00953 "proc tclKitPreInit {} {\n" 00954 "rename tclKitPreInit {}\n" 00955 "load {} rubytk_kitpath\n" 00956 #if KIT_INCLUDES_ZLIB 00957 "catch {load {} zlib}\n" 00958 #endif 00959 #ifdef KIT_LITE 00960 "load {} vlerq\n" 00961 "namespace eval ::vlerq {}\n" 00962 "if {[catch { vlerq open $::tcl::kitpath } ::vlerq::starkit_root]} {\n" 00963 "set n -1\n" 00964 "} else {\n" 00965 "set files [vlerq get $::vlerq::starkit_root 0 dirs 0 files]\n" 00966 "set n [lsearch [vlerq get $files * name] boot.tcl]\n" 00967 "}\n" 00968 "if {$n >= 0} {\n" 00969 "array set a [vlerq get $files $n]\n" 00970 #else 00971 "load {} Mk4tcl\n" 00972 #if defined KIT_VFS_WRITABLE && !defined CREATE_RUBYKIT 00973 /* running command cannot open itself for writing */ 00974 "mk::file open exe $::tcl::kitpath\n" 00975 #else 00976 "mk::file open exe $::tcl::kitpath -readonly\n" 00977 #endif 00978 "set n [mk::select exe.dirs!0.files name boot.tcl]\n" 00979 "if {[llength $n] == 1} {\n" 00980 "array set a [mk::get exe.dirs!0.files!$n]\n" 00981 #endif 00982 "if {![info exists a(contents)]} { error {no boot.tcl file} }\n" 00983 "if {$a(size) != [string length $a(contents)]} {\n" 00984 "set a(contents) [zlib decompress $a(contents)]\n" 00985 "}\n" 00986 "if {$a(contents) eq \"\"} { error {empty boot.tcl} }\n" 00987 "uplevel #0 $a(contents)\n" 00988 #if 0 00989 "} elseif {[lindex $::argv 0] eq \"-init-\"} {\n" 00990 "uplevel #0 { source [lindex $::argv 1] }\n" 00991 "exit\n" 00992 #endif 00993 "} else {\n" 00994 /* When cannot find VFS data, try to use a real directory */ 00995 "set vfsdir \"[file rootname $::tcl::kitpath].vfs\"\n" 00996 "if {[file isdirectory $vfsdir]} {\n" 00997 "set ::tcl_library [file join $vfsdir lib tcl$::tcl_version]\n" 00998 "set ::tcl_libPath [list $::tcl_library [file join $vfsdir lib]]\n" 00999 "catch {uplevel #0 [list source [file join $vfsdir config.tcl]]}\n" 01000 "uplevel #0 [list source [file join $::tcl_library init.tcl]]\n" 01001 "set ::auto_path $::tcl_libPath\n" 01002 "} else {\n" 01003 "error \"\n $::tcl::kitpath has no VFS data to start up\"\n" 01004 "}\n" 01005 "}\n" 01006 "}\n" 01007 "tclKitPreInit" 01008 ; 01009 01010 #if 0 01011 /* Not use this script. 01012 It's a memo to support an initScript for Tcl interpreters in the future. */ 01013 static const char initScript[] = 01014 "if {[file isfile [file join $::tcl::kitpath main.tcl]]} {\n" 01015 "if {[info commands console] != {}} { console hide }\n" 01016 "set tcl_interactive 0\n" 01017 "incr argc\n" 01018 "set argv [linsert $argv 0 $argv0]\n" 01019 "set argv0 [file join $::tcl::kitpath main.tcl]\n" 01020 "} else continue\n" 01021 ; 01022 #endif 01023 01024 /*--------------------------------------------------------*/ 01025 01026 static char* 01027 set_rubytk_kitpath(const char *kitpath) 01028 { 01029 if (kitpath) { 01030 int len = (int)strlen(kitpath); 01031 if (rubytk_kitpath) { 01032 ckfree(rubytk_kitpath); 01033 } 01034 01035 rubytk_kitpath = (char *)ckalloc(len + 1); 01036 memcpy(rubytk_kitpath, kitpath, len); 01037 rubytk_kitpath[len] = '\0'; 01038 } 01039 return rubytk_kitpath; 01040 } 01041 01042 /*--------------------------------------------------------*/ 01043 01044 #ifdef WIN32 01045 #define DEV_NULL "NUL" 01046 #else 01047 #define DEV_NULL "/dev/null" 01048 #endif 01049 01050 static void 01051 check_tclkit_std_channels() 01052 { 01053 Tcl_Channel chan; 01054 01055 /* 01056 * We need to verify if we have the standard channels and create them if 01057 * not. Otherwise internals channels may get used as standard channels 01058 * (like for encodings) and panic. 01059 */ 01060 chan = Tcl_GetStdChannel(TCL_STDIN); 01061 if (chan == NULL) { 01062 chan = Tcl_OpenFileChannel(NULL, DEV_NULL, "r", 0); 01063 if (chan != NULL) { 01064 Tcl_SetChannelOption(NULL, chan, "-encoding", "utf-8"); 01065 } 01066 Tcl_SetStdChannel(chan, TCL_STDIN); 01067 } 01068 chan = Tcl_GetStdChannel(TCL_STDOUT); 01069 if (chan == NULL) { 01070 chan = Tcl_OpenFileChannel(NULL, DEV_NULL, "w", 0); 01071 if (chan != NULL) { 01072 Tcl_SetChannelOption(NULL, chan, "-encoding", "utf-8"); 01073 } 01074 Tcl_SetStdChannel(chan, TCL_STDOUT); 01075 } 01076 chan = Tcl_GetStdChannel(TCL_STDERR); 01077 if (chan == NULL) { 01078 chan = Tcl_OpenFileChannel(NULL, DEV_NULL, "w", 0); 01079 if (chan != NULL) { 01080 Tcl_SetChannelOption(NULL, chan, "-encoding", "utf-8"); 01081 } 01082 Tcl_SetStdChannel(chan, TCL_STDERR); 01083 } 01084 } 01085 01086 /*--------------------------------------------------------*/ 01087 01088 static int 01089 rubytk_kitpathObjCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) 01090 { 01091 const char* str; 01092 if (objc == 2) { 01093 set_rubytk_kitpath(Tcl_GetString(objv[1])); 01094 } else if (objc > 2) { 01095 Tcl_WrongNumArgs(interp, 1, objv, "?path?"); 01096 } 01097 str = rubytk_kitpath ? rubytk_kitpath : Tcl_GetNameOfExecutable(); 01098 Tcl_SetObjResult(interp, Tcl_NewStringObj(str, -1)); 01099 return TCL_OK; 01100 } 01101 01102 /* 01103 * Public entry point for ::tcl::kitpath. 01104 * Creates both link variable name and Tcl command ::tcl::kitpath. 01105 */ 01106 static int 01107 rubytk_kitpath_init(Tcl_Interp *interp) 01108 { 01109 Tcl_CreateObjCommand(interp, "::tcl::kitpath", rubytk_kitpathObjCmd, 0, 0); 01110 if (Tcl_LinkVar(interp, "::tcl::kitpath", (char *) &rubytk_kitpath, 01111 TCL_LINK_STRING | TCL_LINK_READ_ONLY) != TCL_OK) { 01112 Tcl_ResetResult(interp); 01113 } 01114 01115 Tcl_CreateObjCommand(interp, "::tcl::rubytk_kitpath", rubytk_kitpathObjCmd, 0, 0); 01116 if (Tcl_LinkVar(interp, "::tcl::rubytk_kitpath", (char *) &rubytk_kitpath, 01117 TCL_LINK_STRING | TCL_LINK_READ_ONLY) != TCL_OK) { 01118 Tcl_ResetResult(interp); 01119 } 01120 01121 if (rubytk_kitpath == NULL) { 01122 /* 01123 * XXX: We may want to avoid doing this to allow tcl::kitpath calls 01124 * XXX: to obtain changes in nameofexe, if they occur. 01125 */ 01126 set_rubytk_kitpath(Tcl_GetNameOfExecutable()); 01127 } 01128 01129 return Tcl_PkgProvide(interp, "rubytk_kitpath", "1.0"); 01130 } 01131 01132 /*--------------------------------------------------------*/ 01133 01134 static void 01135 init_static_tcltk_packages() 01136 { 01137 /* 01138 * Ensure that std channels exist (creating them if necessary) 01139 */ 01140 check_tclkit_std_channels(); 01141 01142 #ifdef KIT_INCLUDES_ITCL 01143 Tcl_StaticPackage(0, "Itcl", Itcl_Init, NULL); 01144 #endif 01145 #ifdef KIT_LITE 01146 Tcl_StaticPackage(0, "Vlerq", Vlerq_Init, Vlerq_SafeInit); 01147 #else 01148 Tcl_StaticPackage(0, "Mk4tcl", Mk4tcl_Init, NULL); 01149 #endif 01150 #if 10 * TCL_MAJOR_VERSION + TCL_MINOR_VERSION < 85 01151 Tcl_StaticPackage(0, "pwb", Pwb_Init, NULL); 01152 #endif 01153 Tcl_StaticPackage(0, "rubytk_kitpath", rubytk_kitpath_init, NULL); 01154 Tcl_StaticPackage(0, "rechan", Rechan_Init, NULL); 01155 Tcl_StaticPackage(0, "vfs", Vfs_Init, NULL); 01156 #if KIT_INCLUDES_ZLIB 01157 Tcl_StaticPackage(0, "zlib", Zlib_Init, NULL); 01158 #endif 01159 #if defined TCL_THREADS && defined KIT_INCLUDES_THREAD 01160 Tcl_StaticPackage(0, "Thread", Thread_Init, Thread_SafeInit); 01161 #endif 01162 #ifdef _WIN32 01163 #if 10 * TCL_MAJOR_VERSION + TCL_MINOR_VERSION > 84 01164 Tcl_StaticPackage(0, "dde", Dde_Init, Dde_SafeInit); 01165 #else 01166 Tcl_StaticPackage(0, "dde", Dde_Init, NULL); 01167 #endif 01168 Tcl_StaticPackage(0, "registry", Registry_Init, NULL); 01169 #endif 01170 #ifdef KIT_INCLUDES_TK 01171 Tcl_StaticPackage(0, "Tk", Tk_Init, Tk_SafeInit); 01172 #endif 01173 } 01174 01175 /*--------------------------------------------------------*/ 01176 01177 static int 01178 call_tclkit_init_script(Tcl_Interp *interp) 01179 { 01180 #if 0 01181 /* Currently, do nothing in this function. 01182 It's a memo (quoted from kitInit.c of Tclkit) 01183 to support an initScript for Tcl interpreters in the future. */ 01184 if (Tcl_EvalEx(interp, initScript, -1, TCL_EVAL_GLOBAL) == TCL_OK) { 01185 const char *encoding = NULL; 01186 Tcl_Obj* path = Tcl_GetStartupScript(&encoding); 01187 Tcl_SetStartupScript(Tcl_GetObjResult(interp), encoding); 01188 if (path == NULL) { 01189 Tcl_Eval(interp, "incr argc -1; set argv [lrange $argv 1 end]"); 01190 } 01191 } 01192 #endif 01193 01194 return 1; 01195 } 01196 01197 /*--------------------------------------------------------*/ 01198 01199 #ifdef __WIN32__ 01200 /* #include <tkWinInt.h> *//* conflict definition of struct timezone */ 01201 /* #include <tkIntPlatDecls.h> */ 01202 /* #include <windows.h> */ 01203 EXTERN void TkWinSetHINSTANCE(HINSTANCE hInstance); 01204 void rbtk_win32_SetHINSTANCE(const char *module_name) 01205 { 01206 /* TCHAR szBuf[256]; */ 01207 HINSTANCE hInst; 01208 01209 /* hInst = GetModuleHandle(NULL); */ 01210 /* hInst = GetModuleHandle("tcltklib.so"); */ 01211 hInst = GetModuleHandle(module_name); 01212 TkWinSetHINSTANCE(hInst); 01213 01214 /* GetModuleFileName(hInst, szBuf, sizeof(szBuf) / sizeof(TCHAR)); */ 01215 /* MessageBox(NULL, szBuf, TEXT("OK"), MB_OK); */ 01216 } 01217 #endif 01218 01219 /*--------------------------------------------------------*/ 01220 01221 static void 01222 setup_rubytkkit() 01223 { 01224 init_static_tcltk_packages(); 01225 01226 { 01227 ID const_id; 01228 const_id = rb_intern(RUBYTK_KITPATH_CONST_NAME); 01229 01230 if (rb_const_defined(rb_cObject, const_id)) { 01231 volatile VALUE pathobj; 01232 pathobj = rb_const_get(rb_cObject, const_id); 01233 01234 if (rb_obj_is_kind_of(pathobj, rb_cString)) { 01235 #ifdef HAVE_RUBY_ENCODING_H 01236 pathobj = rb_str_export_to_enc(pathobj, rb_utf8_encoding()); 01237 #endif 01238 set_rubytk_kitpath(RSTRING_PTR(pathobj)); 01239 } 01240 } 01241 } 01242 01243 #ifdef CREATE_RUBYTK_KIT 01244 if (rubytk_kitpath == NULL) { 01245 #ifdef __WIN32__ 01246 /* rbtk_win32_SetHINSTANCE("tcltklib.so"); */ 01247 { 01248 volatile VALUE basename; 01249 basename = rb_funcall(rb_cFile, rb_intern("basename"), 1, 01250 rb_str_new2(rb_sourcefile())); 01251 rbtk_win32_SetHINSTANCE(RSTRING_PTR(basename)); 01252 } 01253 #endif 01254 set_rubytk_kitpath(rb_sourcefile()); 01255 } 01256 #endif 01257 01258 if (rubytk_kitpath == NULL) { 01259 set_rubytk_kitpath(Tcl_GetNameOfExecutable()); 01260 } 01261 01262 TclSetPreInitScript(rubytkkit_preInitCmd); 01263 } 01264 01265 /*--------------------------------------------------------*/ 01266 01267 #endif /* defined CREATE_RUBYTK_KIT || defined CREATE_RUBYKIT */ 01268 /*####################################################################*/ 01269 01270 01271 /**********************************************************************/ 01272 01273 /* stub status */ 01274 static void 01275 tcl_stubs_check() 01276 { 01277 if (!tcl_stubs_init_p()) { 01278 int st = ruby_tcl_stubs_init(); 01279 switch(st) { 01280 case TCLTK_STUBS_OK: 01281 break; 01282 case NO_TCL_DLL: 01283 rb_raise(rb_eLoadError, "tcltklib: fail to open tcl_dll"); 01284 case NO_FindExecutable: 01285 rb_raise(rb_eLoadError, "tcltklib: can't find Tcl_FindExecutable"); 01286 case NO_CreateInterp: 01287 rb_raise(rb_eLoadError, "tcltklib: can't find Tcl_CreateInterp()"); 01288 case NO_DeleteInterp: 01289 rb_raise(rb_eLoadError, "tcltklib: can't find Tcl_DeleteInterp()"); 01290 case FAIL_CreateInterp: 01291 rb_raise(rb_eRuntimeError, "tcltklib: fail to create a new IP to call Tcl_InitStubs()"); 01292 case FAIL_Tcl_InitStubs: 01293 rb_raise(rb_eRuntimeError, "tcltklib: fail to Tcl_InitStubs()"); 01294 default: 01295 rb_raise(rb_eRuntimeError, "tcltklib: unknown error(%d) on ruby_tcl_stubs_init()", st); 01296 } 01297 } 01298 } 01299 01300 01301 static VALUE 01302 tcltkip_init_tk(interp) 01303 VALUE interp; 01304 { 01305 struct tcltkip *ptr = get_ip(interp); 01306 01307 #if TCL_MAJOR_VERSION >= 8 01308 int st; 01309 01310 if (Tcl_IsSafe(ptr->ip)) { 01311 DUMP1("Tk_SafeInit"); 01312 st = ruby_tk_stubs_safeinit(ptr->ip); 01313 switch(st) { 01314 case TCLTK_STUBS_OK: 01315 break; 01316 case NO_Tk_Init: 01317 return rb_exc_new2(rb_eLoadError, 01318 "tcltklib: can't find Tk_SafeInit()"); 01319 case FAIL_Tk_Init: 01320 return create_ip_exc(interp, rb_eRuntimeError, 01321 "tcltklib: fail to Tk_SafeInit(). %s", 01322 Tcl_GetStringResult(ptr->ip)); 01323 case FAIL_Tk_InitStubs: 01324 return create_ip_exc(interp, rb_eRuntimeError, 01325 "tcltklib: fail to Tk_InitStubs(). %s", 01326 Tcl_GetStringResult(ptr->ip)); 01327 default: 01328 return create_ip_exc(interp, rb_eRuntimeError, 01329 "tcltklib: unknown error(%d) on ruby_tk_stubs_safeinit", st); 01330 } 01331 } else { 01332 DUMP1("Tk_Init"); 01333 st = ruby_tk_stubs_init(ptr->ip); 01334 switch(st) { 01335 case TCLTK_STUBS_OK: 01336 break; 01337 case NO_Tk_Init: 01338 return rb_exc_new2(rb_eLoadError, 01339 "tcltklib: can't find Tk_Init()"); 01340 case FAIL_Tk_Init: 01341 return create_ip_exc(interp, rb_eRuntimeError, 01342 "tcltklib: fail to Tk_Init(). %s", 01343 Tcl_GetStringResult(ptr->ip)); 01344 case FAIL_Tk_InitStubs: 01345 return create_ip_exc(interp, rb_eRuntimeError, 01346 "tcltklib: fail to Tk_InitStubs(). %s", 01347 Tcl_GetStringResult(ptr->ip)); 01348 default: 01349 return create_ip_exc(interp, rb_eRuntimeError, 01350 "tcltklib: unknown error(%d) on ruby_tk_stubs_init", st); 01351 } 01352 } 01353 01354 #else /* TCL_MAJOR_VERSION < 8 */ 01355 DUMP1("Tk_Init"); 01356 if (ruby_tk_stubs_init(ptr->ip) != TCLTK_STUBS_OK) { 01357 return rb_exc_new2(rb_eRuntimeError, ptr->ip->result); 01358 } 01359 #endif 01360 01361 #ifdef RUBY_USE_NATIVE_THREAD 01362 ptr->tk_thread_id = Tcl_GetCurrentThread(); 01363 #endif 01364 01365 return Qnil; 01366 } 01367 01368 01369 /* treat excetiopn on Tcl side */ 01370 static VALUE rbtk_pending_exception; 01371 static int rbtk_eventloop_depth = 0; 01372 static int rbtk_internal_eventloop_handler = 0; 01373 01374 01375 static int 01376 pending_exception_check0() 01377 { 01378 volatile VALUE exc = rbtk_pending_exception; 01379 01380 if (!NIL_P(exc) && rb_obj_is_kind_of(exc, rb_eException)) { 01381 DUMP1("find a pending exception"); 01382 if (rbtk_eventloop_depth > 0 01383 || rbtk_internal_eventloop_handler > 0 01384 ) { 01385 return 1; /* pending */ 01386 } else { 01387 rbtk_pending_exception = Qnil; 01388 01389 if (rb_obj_is_kind_of(exc, eTkCallbackRetry)) { 01390 DUMP1("pending_exception_check0: call rb_jump_tag(retry)"); 01391 rb_jump_tag(TAG_RETRY); 01392 } else if (rb_obj_is_kind_of(exc, eTkCallbackRedo)) { 01393 DUMP1("pending_exception_check0: call rb_jump_tag(redo)"); 01394 rb_jump_tag(TAG_REDO); 01395 } else if (rb_obj_is_kind_of(exc, eTkCallbackThrow)) { 01396 DUMP1("pending_exception_check0: call rb_jump_tag(throw)"); 01397 rb_jump_tag(TAG_THROW); 01398 } 01399 01400 rb_exc_raise(exc); 01401 } 01402 } else { 01403 return 0; 01404 } 01405 } 01406 01407 static int 01408 pending_exception_check1(thr_crit_bup, ptr) 01409 int thr_crit_bup; 01410 struct tcltkip *ptr; 01411 { 01412 volatile VALUE exc = rbtk_pending_exception; 01413 01414 if (!NIL_P(exc) && rb_obj_is_kind_of(exc, rb_eException)) { 01415 DUMP1("find a pending exception"); 01416 01417 if (rbtk_eventloop_depth > 0 01418 || rbtk_internal_eventloop_handler > 0 01419 ) { 01420 return 1; /* pending */ 01421 } else { 01422 rbtk_pending_exception = Qnil; 01423 01424 if (ptr != (struct tcltkip *)NULL) { 01425 /* Tcl_Release(ptr->ip); */ 01426 rbtk_release_ip(ptr); 01427 } 01428 01429 rb_thread_critical = thr_crit_bup; 01430 01431 if (rb_obj_is_kind_of(exc, eTkCallbackRetry)) { 01432 DUMP1("pending_exception_check1: call rb_jump_tag(retry)"); 01433 rb_jump_tag(TAG_RETRY); 01434 } else if (rb_obj_is_kind_of(exc, eTkCallbackRedo)) { 01435 DUMP1("pending_exception_check1: call rb_jump_tag(redo)"); 01436 rb_jump_tag(TAG_REDO); 01437 } else if (rb_obj_is_kind_of(exc, eTkCallbackThrow)) { 01438 DUMP1("pending_exception_check1: call rb_jump_tag(throw)"); 01439 rb_jump_tag(TAG_THROW); 01440 } 01441 rb_exc_raise(exc); 01442 } 01443 } else { 01444 return 0; 01445 } 01446 } 01447 01448 01449 /* call original 'exit' command */ 01450 static void 01451 call_original_exit(ptr, state) 01452 struct tcltkip *ptr; 01453 int state; 01454 { 01455 int thr_crit_bup; 01456 Tcl_CmdInfo *info; 01457 #if TCL_MAJOR_VERSION >= 8 01458 Tcl_Obj *cmd_obj; 01459 Tcl_Obj *state_obj; 01460 #endif 01461 DUMP1("original_exit is called"); 01462 01463 if (!(ptr->has_orig_exit)) return; 01464 01465 thr_crit_bup = rb_thread_critical; 01466 rb_thread_critical = Qtrue; 01467 01468 Tcl_ResetResult(ptr->ip); 01469 01470 info = &(ptr->orig_exit_info); 01471 01472 /* memory allocation for arguments of this command */ 01473 #if TCL_MAJOR_VERSION >= 8 01474 state_obj = Tcl_NewIntObj(state); 01475 Tcl_IncrRefCount(state_obj); 01476 01477 if (info->isNativeObjectProc) { 01478 Tcl_Obj **argv; 01479 #define USE_RUBY_ALLOC 0 01480 #if USE_RUBY_ALLOC 01481 argv = (Tcl_Obj **)ALLOC_N(Tcl_Obj *, 3); 01482 #else /* not USE_RUBY_ALLOC */ 01483 argv = (Tcl_Obj **)ckalloc(sizeof(Tcl_Obj *) * 3); 01484 #if 0 /* use Tcl_Preserve/Release */ 01485 Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ 01486 #endif 01487 #endif 01488 cmd_obj = Tcl_NewStringObj("exit", 4); 01489 Tcl_IncrRefCount(cmd_obj); 01490 01491 argv[0] = cmd_obj; 01492 argv[1] = state_obj; 01493 argv[2] = (Tcl_Obj *)NULL; 01494 01495 ptr->return_value 01496 = (*(info->objProc))(info->objClientData, ptr->ip, 2, argv); 01497 01498 Tcl_DecrRefCount(cmd_obj); 01499 01500 #if USE_RUBY_ALLOC 01501 xfree(argv); 01502 #else /* not USE_RUBY_ALLOC */ 01503 #if 0 /* use Tcl_EventuallyFree */ 01504 Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ 01505 #else 01506 #if 0 /* use Tcl_Preserve/Release */ 01507 Tcl_Release((ClientData)argv); /* XXXXXXXX */ 01508 #else 01509 /* free(argv); */ 01510 ckfree((char*)argv); 01511 #endif 01512 #endif 01513 #endif 01514 #undef USE_RUBY_ALLOC 01515 01516 } else { 01517 /* string interface */ 01518 CONST84 char **argv; 01519 #define USE_RUBY_ALLOC 0 01520 #if USE_RUBY_ALLOC 01521 argv = ALLOC_N(char *, 3); /* XXXXXXXXXX */ 01522 #else /* not USE_RUBY_ALLOC */ 01523 argv = (CONST84 char **)ckalloc(sizeof(char *) * 3); 01524 #if 0 /* use Tcl_Preserve/Release */ 01525 Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ 01526 #endif 01527 #endif 01528 argv[0] = (char *)"exit"; 01529 /* argv[1] = Tcl_GetString(state_obj); */ 01530 argv[1] = Tcl_GetStringFromObj(state_obj, (int*)NULL); 01531 argv[2] = (char *)NULL; 01532 01533 ptr->return_value = (*(info->proc))(info->clientData, ptr->ip, 2, argv); 01534 01535 #if USE_RUBY_ALLOC 01536 xfree(argv); 01537 #else /* not USE_RUBY_ALLOC */ 01538 #if 0 /* use Tcl_EventuallyFree */ 01539 Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ 01540 #else 01541 #if 0 /* use Tcl_Preserve/Release */ 01542 Tcl_Release((ClientData)argv); /* XXXXXXXX */ 01543 #else 01544 /* free(argv); */ 01545 ckfree((char*)argv); 01546 #endif 01547 #endif 01548 #endif 01549 #undef USE_RUBY_ALLOC 01550 } 01551 01552 Tcl_DecrRefCount(state_obj); 01553 01554 #else /* TCL_MAJOR_VERSION < 8 */ 01555 { 01556 /* string interface */ 01557 char **argv; 01558 #define USE_RUBY_ALLOC 0 01559 #if USE_RUBY_ALLOC 01560 argv = (char **)ALLOC_N(char *, 3); 01561 #else /* not USE_RUBY_ALLOC */ 01562 argv = (char **)ckalloc(sizeof(char *) * 3); 01563 #if 0 /* use Tcl_Preserve/Release */ 01564 Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ 01565 #endif 01566 #endif 01567 argv[0] = "exit"; 01568 argv[1] = RSTRING_PTR(rb_fix2str(INT2NUM(state), 10)); 01569 argv[2] = (char *)NULL; 01570 01571 ptr->return_value = (*(info->proc))(info->clientData, ptr->ip, 01572 2, argv); 01573 01574 #if USE_RUBY_ALLOC 01575 xfree(argv); 01576 #else /* not USE_RUBY_ALLOC */ 01577 #if 0 /* use Tcl_EventuallyFree */ 01578 Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ 01579 #else 01580 #if 0 /* use Tcl_Preserve/Release */ 01581 Tcl_Release((ClientData)argv); /* XXXXXXXX */ 01582 #else 01583 /* free(argv); */ 01584 ckfree(argv); 01585 #endif 01586 #endif 01587 #endif 01588 #undef USE_RUBY_ALLOC 01589 } 01590 #endif 01591 DUMP1("complete original_exit"); 01592 01593 rb_thread_critical = thr_crit_bup; 01594 } 01595 01596 /* Tk_ThreadTimer */ 01597 static Tcl_TimerToken timer_token = (Tcl_TimerToken)NULL; 01598 01599 /* timer callback */ 01600 static void _timer_for_tcl _((ClientData)); 01601 static void 01602 _timer_for_tcl(clientData) 01603 ClientData clientData; 01604 { 01605 int thr_crit_bup; 01606 01607 /* struct invoke_queue *q, *tmp; */ 01608 /* VALUE thread; */ 01609 01610 DUMP1("call _timer_for_tcl"); 01611 01612 thr_crit_bup = rb_thread_critical; 01613 rb_thread_critical = Qtrue; 01614 01615 Tcl_DeleteTimerHandler(timer_token); 01616 01617 run_timer_flag = 1; 01618 01619 if (timer_tick > 0) { 01620 timer_token = Tcl_CreateTimerHandler(timer_tick, _timer_for_tcl, 01621 (ClientData)0); 01622 } else { 01623 timer_token = (Tcl_TimerToken)NULL; 01624 } 01625 01626 rb_thread_critical = thr_crit_bup; 01627 01628 /* rb_thread_schedule(); */ 01629 /* tick_counter += event_loop_max; */ 01630 } 01631 01632 #ifdef RUBY_USE_NATIVE_THREAD 01633 #if USE_TOGGLE_WINDOW_MODE_FOR_IDLE 01634 static int 01635 toggle_eventloop_window_mode_for_idle() 01636 { 01637 if (window_event_mode & TCL_IDLE_EVENTS) { 01638 /* idle -> event */ 01639 window_event_mode |= TCL_WINDOW_EVENTS; 01640 window_event_mode &= ~TCL_IDLE_EVENTS; 01641 return 1; 01642 } else { 01643 /* event -> idle */ 01644 window_event_mode |= TCL_IDLE_EVENTS; 01645 window_event_mode &= ~TCL_WINDOW_EVENTS; 01646 return 0; 01647 } 01648 } 01649 #endif 01650 #endif 01651 01652 static VALUE 01653 set_eventloop_window_mode(self, mode) 01654 VALUE self; 01655 VALUE mode; 01656 { 01657 rb_secure(4); 01658 01659 if (RTEST(mode)) { 01660 window_event_mode = ~0; 01661 } else { 01662 window_event_mode = ~TCL_WINDOW_EVENTS; 01663 } 01664 01665 return mode; 01666 } 01667 01668 static VALUE 01669 get_eventloop_window_mode(self) 01670 VALUE self; 01671 { 01672 if ( ~window_event_mode ) { 01673 return Qfalse; 01674 } else { 01675 return Qtrue; 01676 } 01677 } 01678 01679 static VALUE 01680 set_eventloop_tick(self, tick) 01681 VALUE self; 01682 VALUE tick; 01683 { 01684 int ttick = NUM2INT(tick); 01685 int thr_crit_bup; 01686 01687 rb_secure(4); 01688 01689 if (ttick < 0) { 01690 rb_raise(rb_eArgError, 01691 "timer-tick parameter must be 0 or positive number"); 01692 } 01693 01694 thr_crit_bup = rb_thread_critical; 01695 rb_thread_critical = Qtrue; 01696 01697 /* delete old timer callback */ 01698 Tcl_DeleteTimerHandler(timer_token); 01699 01700 timer_tick = req_timer_tick = ttick; 01701 if (timer_tick > 0) { 01702 /* start timer callback */ 01703 timer_token = Tcl_CreateTimerHandler(timer_tick, _timer_for_tcl, 01704 (ClientData)0); 01705 } else { 01706 timer_token = (Tcl_TimerToken)NULL; 01707 } 01708 01709 rb_thread_critical = thr_crit_bup; 01710 01711 return tick; 01712 } 01713 01714 static VALUE 01715 get_eventloop_tick(self) 01716 VALUE self; 01717 { 01718 return INT2NUM(timer_tick); 01719 } 01720 01721 static VALUE 01722 ip_set_eventloop_tick(self, tick) 01723 VALUE self; 01724 VALUE tick; 01725 { 01726 struct tcltkip *ptr = get_ip(self); 01727 01728 /* ip is deleted? */ 01729 if (deleted_ip(ptr)) { 01730 return get_eventloop_tick(self); 01731 } 01732 01733 if (Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL) { 01734 /* slave IP */ 01735 return get_eventloop_tick(self); 01736 } 01737 return set_eventloop_tick(self, tick); 01738 } 01739 01740 static VALUE 01741 ip_get_eventloop_tick(self) 01742 VALUE self; 01743 { 01744 return get_eventloop_tick(self); 01745 } 01746 01747 static VALUE 01748 set_no_event_wait(self, wait) 01749 VALUE self; 01750 VALUE wait; 01751 { 01752 int t_wait = NUM2INT(wait); 01753 01754 rb_secure(4); 01755 01756 if (t_wait <= 0) { 01757 rb_raise(rb_eArgError, 01758 "no_event_wait parameter must be positive number"); 01759 } 01760 01761 no_event_wait = t_wait; 01762 01763 return wait; 01764 } 01765 01766 static VALUE 01767 get_no_event_wait(self) 01768 VALUE self; 01769 { 01770 return INT2NUM(no_event_wait); 01771 } 01772 01773 static VALUE 01774 ip_set_no_event_wait(self, wait) 01775 VALUE self; 01776 VALUE wait; 01777 { 01778 struct tcltkip *ptr = get_ip(self); 01779 01780 /* ip is deleted? */ 01781 if (deleted_ip(ptr)) { 01782 return get_no_event_wait(self); 01783 } 01784 01785 if (Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL) { 01786 /* slave IP */ 01787 return get_no_event_wait(self); 01788 } 01789 return set_no_event_wait(self, wait); 01790 } 01791 01792 static VALUE 01793 ip_get_no_event_wait(self) 01794 VALUE self; 01795 { 01796 return get_no_event_wait(self); 01797 } 01798 01799 static VALUE 01800 set_eventloop_weight(self, loop_max, no_event) 01801 VALUE self; 01802 VALUE loop_max; 01803 VALUE no_event; 01804 { 01805 int lpmax = NUM2INT(loop_max); 01806 int no_ev = NUM2INT(no_event); 01807 01808 rb_secure(4); 01809 01810 if (lpmax <= 0 || no_ev <= 0) { 01811 rb_raise(rb_eArgError, "weight parameters must be positive numbers"); 01812 } 01813 01814 event_loop_max = lpmax; 01815 no_event_tick = no_ev; 01816 01817 return rb_ary_new3(2, loop_max, no_event); 01818 } 01819 01820 static VALUE 01821 get_eventloop_weight(self) 01822 VALUE self; 01823 { 01824 return rb_ary_new3(2, INT2NUM(event_loop_max), INT2NUM(no_event_tick)); 01825 } 01826 01827 static VALUE 01828 ip_set_eventloop_weight(self, loop_max, no_event) 01829 VALUE self; 01830 VALUE loop_max; 01831 VALUE no_event; 01832 { 01833 struct tcltkip *ptr = get_ip(self); 01834 01835 /* ip is deleted? */ 01836 if (deleted_ip(ptr)) { 01837 return get_eventloop_weight(self); 01838 } 01839 01840 if (Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL) { 01841 /* slave IP */ 01842 return get_eventloop_weight(self); 01843 } 01844 return set_eventloop_weight(self, loop_max, no_event); 01845 } 01846 01847 static VALUE 01848 ip_get_eventloop_weight(self) 01849 VALUE self; 01850 { 01851 return get_eventloop_weight(self); 01852 } 01853 01854 static VALUE 01855 set_max_block_time(self, time) 01856 VALUE self; 01857 VALUE time; 01858 { 01859 struct Tcl_Time tcl_time; 01860 VALUE divmod; 01861 01862 switch(TYPE(time)) { 01863 case T_FIXNUM: 01864 case T_BIGNUM: 01865 /* time is micro-second value */ 01866 divmod = rb_funcall(time, rb_intern("divmod"), 1, LONG2NUM(1000000)); 01867 tcl_time.sec = NUM2LONG(RARRAY_PTR(divmod)[0]); 01868 tcl_time.usec = NUM2LONG(RARRAY_PTR(divmod)[1]); 01869 break; 01870 01871 case T_FLOAT: 01872 /* time is second value */ 01873 divmod = rb_funcall(time, rb_intern("divmod"), 1, INT2FIX(1)); 01874 tcl_time.sec = NUM2LONG(RARRAY_PTR(divmod)[0]); 01875 tcl_time.usec = (long)(NUM2DBL(RARRAY_PTR(divmod)[1]) * 1000000); 01876 01877 default: 01878 { 01879 VALUE tmp = rb_funcall(time, ID_inspect, 0, 0); 01880 rb_raise(rb_eArgError, "invalid value for time: '%s'", 01881 StringValuePtr(tmp)); 01882 } 01883 } 01884 01885 Tcl_SetMaxBlockTime(&tcl_time); 01886 01887 return Qnil; 01888 } 01889 01890 static VALUE 01891 lib_evloop_thread_p(self) 01892 VALUE self; 01893 { 01894 if (NIL_P(eventloop_thread)) { 01895 return Qnil; /* no eventloop */ 01896 } else if (rb_thread_current() == eventloop_thread) { 01897 return Qtrue; /* is eventloop */ 01898 } else { 01899 return Qfalse; /* not eventloop */ 01900 } 01901 } 01902 01903 static VALUE 01904 lib_evloop_abort_on_exc(self) 01905 VALUE self; 01906 { 01907 if (event_loop_abort_on_exc > 0) { 01908 return Qtrue; 01909 } else if (event_loop_abort_on_exc == 0) { 01910 return Qfalse; 01911 } else { 01912 return Qnil; 01913 } 01914 } 01915 01916 static VALUE 01917 ip_evloop_abort_on_exc(self) 01918 VALUE self; 01919 { 01920 return lib_evloop_abort_on_exc(self); 01921 } 01922 01923 static VALUE 01924 lib_evloop_abort_on_exc_set(self, val) 01925 VALUE self, val; 01926 { 01927 rb_secure(4); 01928 if (RTEST(val)) { 01929 event_loop_abort_on_exc = 1; 01930 } else if (NIL_P(val)) { 01931 event_loop_abort_on_exc = -1; 01932 } else { 01933 event_loop_abort_on_exc = 0; 01934 } 01935 return lib_evloop_abort_on_exc(self); 01936 } 01937 01938 static VALUE 01939 ip_evloop_abort_on_exc_set(self, val) 01940 VALUE self, val; 01941 { 01942 struct tcltkip *ptr = get_ip(self); 01943 01944 rb_secure(4); 01945 01946 /* ip is deleted? */ 01947 if (deleted_ip(ptr)) { 01948 return lib_evloop_abort_on_exc(self); 01949 } 01950 01951 if (Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL) { 01952 /* slave IP */ 01953 return lib_evloop_abort_on_exc(self); 01954 } 01955 return lib_evloop_abort_on_exc_set(self, val); 01956 } 01957 01958 static VALUE 01959 lib_num_of_mainwindows_core(self, argc, argv) 01960 VALUE self; 01961 int argc; /* dummy */ 01962 VALUE *argv; /* dummy */ 01963 { 01964 if (tk_stubs_init_p()) { 01965 return INT2FIX(Tk_GetNumMainWindows()); 01966 } else { 01967 return INT2FIX(0); 01968 } 01969 } 01970 01971 static VALUE 01972 lib_num_of_mainwindows(self) 01973 VALUE self; 01974 { 01975 #ifdef RUBY_USE_NATIVE_THREAD /* Ruby 1.9+ !!! */ 01976 return tk_funcall(lib_num_of_mainwindows_core, 0, (VALUE*)NULL, self); 01977 #else 01978 return lib_num_of_mainwindows_core(self, 0, (VALUE*)NULL); 01979 #endif 01980 } 01981 01982 void 01983 rbtk_EventSetupProc(ClientData clientData, int flag) 01984 { 01985 Tcl_Time tcl_time; 01986 tcl_time.sec = 0; 01987 tcl_time.usec = 1000L * (long)no_event_tick; 01988 Tcl_SetMaxBlockTime(&tcl_time); 01989 } 01990 01991 void 01992 rbtk_EventCheckProc(ClientData clientData, int flag) 01993 { 01994 rb_thread_schedule(); 01995 } 01996 01997 01998 #ifdef RUBY_USE_NATIVE_THREAD /* Ruby 1.9+ !!! */ 01999 static VALUE 02000 #ifdef HAVE_PROTOTYPES 02001 call_DoOneEvent_core(VALUE flag_val) 02002 #else 02003 call_DoOneEvent_core(flag_val) 02004 VALUE flag_val; 02005 #endif 02006 { 02007 int flag; 02008 02009 flag = FIX2INT(flag_val); 02010 if (Tcl_DoOneEvent(flag)) { 02011 return Qtrue; 02012 } else { 02013 return Qfalse; 02014 } 02015 } 02016 02017 static VALUE 02018 #ifdef HAVE_PROTOTYPES 02019 call_DoOneEvent(VALUE flag_val) 02020 #else 02021 call_DoOneEvent(flag_val) 02022 VALUE flag_val; 02023 #endif 02024 { 02025 return tk_funcall(call_DoOneEvent_core, 0, (VALUE*)NULL, flag_val); 02026 } 02027 02028 #else /* Ruby 1.8- */ 02029 static VALUE 02030 #ifdef HAVE_PROTOTYPES 02031 call_DoOneEvent(VALUE flag_val) 02032 #else 02033 call_DoOneEvent(flag_val) 02034 VALUE flag_val; 02035 #endif 02036 { 02037 int flag; 02038 02039 flag = FIX2INT(flag_val); 02040 if (Tcl_DoOneEvent(flag)) { 02041 return Qtrue; 02042 } else { 02043 return Qfalse; 02044 } 02045 } 02046 #endif 02047 02048 02049 static VALUE 02050 #ifdef HAVE_PROTOTYPES 02051 eventloop_sleep(VALUE dummy) 02052 #else 02053 eventloop_sleep(dummy) 02054 VALUE dummy; 02055 #endif 02056 { 02057 struct timeval t; 02058 02059 if (no_event_wait <= 0) { 02060 return Qnil; 02061 } 02062 02063 t.tv_sec = 0; 02064 t.tv_usec = (long)(no_event_wait*1000.0); 02065 02066 #ifdef HAVE_NATIVETHREAD 02067 #ifndef RUBY_USE_NATIVE_THREAD 02068 if (!ruby_native_thread_p()) { 02069 rb_bug("cross-thread violation on eventloop_sleep()"); 02070 } 02071 #endif 02072 #endif 02073 02074 DUMP2("eventloop_sleep: rb_thread_wait_for() at thread : %lx", rb_thread_current()); 02075 rb_thread_wait_for(t); 02076 DUMP2("eventloop_sleep: finish at thread : %lx", rb_thread_current()); 02077 02078 #ifdef HAVE_NATIVETHREAD 02079 #ifndef RUBY_USE_NATIVE_THREAD 02080 if (!ruby_native_thread_p()) { 02081 rb_bug("cross-thread violation on eventloop_sleep()"); 02082 } 02083 #endif 02084 #endif 02085 02086 return Qnil; 02087 } 02088 02089 #define USE_EVLOOP_THREAD_ALONE_CHECK_FLAG 0 02090 02091 #if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG 02092 static int 02093 get_thread_alone_check_flag() 02094 { 02095 #ifdef RUBY_USE_NATIVE_THREAD 02096 return 0; 02097 #else 02098 set_tcltk_version(); 02099 02100 if (tcltk_version.major < 8) { 02101 /* Tcl/Tk 7.x */ 02102 return 1; 02103 } else if (tcltk_version.major == 8) { 02104 if (tcltk_version.minor < 5) { 02105 /* Tcl/Tk 8.0 - 8.4 */ 02106 return 1; 02107 } else if (tcltk_version.minor == 5) { 02108 if (tcltk_version.type < TCL_FINAL_RELEASE) { 02109 /* Tcl/Tk 8.5a? - 8.5b? */ 02110 return 1; 02111 } else { 02112 /* Tcl/Tk 8.5.x */ 02113 return 0; 02114 } 02115 } else { 02116 /* Tcl/Tk 8.6 - 8.9 ?? */ 02117 return 0; 02118 } 02119 } else { 02120 /* Tcl/Tk 9+ ?? */ 02121 return 0; 02122 } 02123 #endif 02124 } 02125 #endif 02126 02127 #define TRAP_CHECK() do { \ 02128 if (trap_check(check_var) == 0) return 0; \ 02129 } while (0) 02130 02131 static int 02132 trap_check(int *check_var) 02133 { 02134 DUMP1("trap check"); 02135 02136 #ifdef RUBY_VM 02137 if (rb_thread_check_trap_pending()) { 02138 if (check_var != (int*)NULL) { 02139 /* wait command */ 02140 return 0; 02141 } 02142 else { 02143 rb_thread_check_ints(); 02144 } 02145 } 02146 #else 02147 if (rb_trap_pending) { 02148 run_timer_flag = 0; 02149 if (rb_prohibit_interrupt || check_var != (int*)NULL) { 02150 /* pending or on wait command */ 02151 return 0; 02152 } else { 02153 rb_trap_exec(); 02154 } 02155 } 02156 #endif 02157 02158 return 1; 02159 } 02160 02161 static int 02162 check_eventloop_interp() 02163 { 02164 DUMP1("check eventloop_interp"); 02165 if (eventloop_interp != (Tcl_Interp*)NULL 02166 && Tcl_InterpDeleted(eventloop_interp)) { 02167 DUMP2("eventloop_interp(%p) was deleted", eventloop_interp); 02168 return 1; 02169 } 02170 02171 return 0; 02172 } 02173 02174 static int 02175 lib_eventloop_core(check_root, update_flag, check_var, interp) 02176 int check_root; 02177 int update_flag; 02178 int *check_var; 02179 Tcl_Interp *interp; 02180 { 02181 volatile VALUE current = eventloop_thread; 02182 int found_event = 1; 02183 int event_flag; 02184 struct timeval t; 02185 int thr_crit_bup; 02186 int status; 02187 int depth = rbtk_eventloop_depth; 02188 #if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG 02189 int thread_alone_check_flag = 1; 02190 #endif 02191 02192 if (update_flag) DUMP1("update loop start!!"); 02193 02194 t.tv_sec = 0; 02195 t.tv_usec = 1000 * (long)no_event_wait; 02196 02197 Tcl_DeleteTimerHandler(timer_token); 02198 run_timer_flag = 0; 02199 if (timer_tick > 0) { 02200 thr_crit_bup = rb_thread_critical; 02201 rb_thread_critical = Qtrue; 02202 timer_token = Tcl_CreateTimerHandler(timer_tick, _timer_for_tcl, 02203 (ClientData)0); 02204 rb_thread_critical = thr_crit_bup; 02205 } else { 02206 timer_token = (Tcl_TimerToken)NULL; 02207 } 02208 02209 #if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG 02210 /* version check */ 02211 thread_alone_check_flag = get_thread_alone_check_flag(); 02212 #endif 02213 02214 for(;;) { 02215 if (check_eventloop_interp()) return 0; 02216 02217 #if USE_EVLOOP_THREAD_ALONE_CHECK_FLAG 02218 if (thread_alone_check_flag && rb_thread_alone()) { 02219 #else 02220 if (rb_thread_alone()) { 02221 #endif 02222 DUMP1("no other thread"); 02223 event_loop_wait_event = 0; 02224 02225 if (update_flag) { 02226 event_flag = update_flag; 02227 /* event_flag = update_flag | TCL_DONT_WAIT; */ /* for safety */ 02228 } else { 02229 event_flag = TCL_ALL_EVENTS; 02230 /* event_flag = TCL_ALL_EVENTS | TCL_DONT_WAIT; */ 02231 } 02232 02233 if (timer_tick == 0 && update_flag == 0) { 02234 timer_tick = NO_THREAD_INTERRUPT_TIME; 02235 timer_token = Tcl_CreateTimerHandler(timer_tick, 02236 _timer_for_tcl, 02237 (ClientData)0); 02238 } 02239 02240 if (check_var != (int *)NULL) { 02241 if (*check_var || !found_event) { 02242 return found_event; 02243 } 02244 if (interp != (Tcl_Interp*)NULL 02245 && Tcl_InterpDeleted(interp)) { 02246 /* IP for check_var is deleted */ 02247 return 0; 02248 } 02249 } 02250 02251 /* found_event = Tcl_DoOneEvent(event_flag); */ 02252 found_event = RTEST(rb_protect(call_DoOneEvent, 02253 INT2FIX(event_flag), &status)); 02254 if (status) { 02255 switch (status) { 02256 case TAG_RAISE: 02257 if (NIL_P(rb_errinfo())) { 02258 rbtk_pending_exception 02259 = rb_exc_new2(rb_eException, "unknown exception"); 02260 } else { 02261 rbtk_pending_exception = rb_errinfo(); 02262 02263 if (!NIL_P(rbtk_pending_exception)) { 02264 if (rbtk_eventloop_depth == 0) { 02265 VALUE exc = rbtk_pending_exception; 02266 rbtk_pending_exception = Qnil; 02267 rb_exc_raise(exc); 02268 } else { 02269 return 0; 02270 } 02271 } 02272 } 02273 break; 02274 02275 case TAG_FATAL: 02276 if (NIL_P(rb_errinfo())) { 02277 rb_exc_raise(rb_exc_new2(rb_eFatal, "FATAL")); 02278 } else { 02279 rb_exc_raise(rb_errinfo()); 02280 } 02281 } 02282 } 02283 02284 if (depth != rbtk_eventloop_depth) { 02285 DUMP2("DoOneEvent(1) abnormal exit!! %d", 02286 rbtk_eventloop_depth); 02287 } 02288 02289 if (check_var != (int*)NULL && !NIL_P(rbtk_pending_exception)) { 02290 DUMP1("exception on wait"); 02291 return 0; 02292 } 02293 02294 if (pending_exception_check0()) { 02295 /* pending -> upper level */ 02296 return 0; 02297 } 02298 02299 if (update_flag != 0) { 02300 if (found_event) { 02301 DUMP1("next update loop"); 02302 continue; 02303 } else { 02304 DUMP1("update complete"); 02305 return 0; 02306 } 02307 } 02308 02309 TRAP_CHECK(); 02310 if (check_eventloop_interp()) return 0; 02311 02312 DUMP1("check Root Widget"); 02313 if (check_root && tk_stubs_init_p() && Tk_GetNumMainWindows() == 0) { 02314 run_timer_flag = 0; 02315 TRAP_CHECK(); 02316 return 1; 02317 } 02318 02319 if (loop_counter++ > 30000) { 02320 /* fprintf(stderr, "loop_counter > 30000\n"); */ 02321 loop_counter = 0; 02322 } 02323 02324 } else { 02325 int tick_counter; 02326 02327 DUMP1("there are other threads"); 02328 event_loop_wait_event = 1; 02329 02330 found_event = 1; 02331 02332 if (update_flag) { 02333 event_flag = update_flag; /* for safety */ 02334 /* event_flag = update_flag | TCL_DONT_WAIT; */ /* for safety */ 02335 } else { 02336 event_flag = TCL_ALL_EVENTS; 02337 /* event_flag = TCL_ALL_EVENTS | TCL_DONT_WAIT; */ 02338 } 02339 02340 timer_tick = req_timer_tick; 02341 tick_counter = 0; 02342 while(tick_counter < event_loop_max) { 02343 if (check_var != (int *)NULL) { 02344 if (*check_var || !found_event) { 02345 return found_event; 02346 } 02347 if (interp != (Tcl_Interp*)NULL 02348 && Tcl_InterpDeleted(interp)) { 02349 /* IP for check_var is deleted */ 02350 return 0; 02351 } 02352 } 02353 02354 if (NIL_P(eventloop_thread) || current == eventloop_thread) { 02355 int st; 02356 int status; 02357 02358 #ifdef RUBY_USE_NATIVE_THREAD 02359 if (update_flag) { 02360 st = RTEST(rb_protect(call_DoOneEvent, 02361 INT2FIX(event_flag), &status)); 02362 } else { 02363 st = RTEST(rb_protect(call_DoOneEvent, 02364 INT2FIX(event_flag & window_event_mode), 02365 &status)); 02366 #if USE_TOGGLE_WINDOW_MODE_FOR_IDLE 02367 if (!st) { 02368 if (toggle_eventloop_window_mode_for_idle()) { 02369 /* idle-mode -> event-mode*/ 02370 tick_counter = event_loop_max; 02371 } else { 02372 /* event-mode -> idle-mode */ 02373 tick_counter = 0; 02374 } 02375 } 02376 #endif 02377 } 02378 #else 02379 /* st = Tcl_DoOneEvent(event_flag); */ 02380 st = RTEST(rb_protect(call_DoOneEvent, 02381 INT2FIX(event_flag), &status)); 02382 #endif 02383 02384 #if CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE 02385 if (have_rb_thread_waiting_for_value) { 02386 have_rb_thread_waiting_for_value = 0; 02387 rb_thread_schedule(); 02388 } 02389 #endif 02390 02391 if (status) { 02392 switch (status) { 02393 case TAG_RAISE: 02394 if (NIL_P(rb_errinfo())) { 02395 rbtk_pending_exception 02396 = rb_exc_new2(rb_eException, 02397 "unknown exception"); 02398 } else { 02399 rbtk_pending_exception = rb_errinfo(); 02400 02401 if (!NIL_P(rbtk_pending_exception)) { 02402 if (rbtk_eventloop_depth == 0) { 02403 VALUE exc = rbtk_pending_exception; 02404 rbtk_pending_exception = Qnil; 02405 rb_exc_raise(exc); 02406 } else { 02407 return 0; 02408 } 02409 } 02410 } 02411 break; 02412 02413 case TAG_FATAL: 02414 if (NIL_P(rb_errinfo())) { 02415 rb_exc_raise(rb_exc_new2(rb_eFatal, "FATAL")); 02416 } else { 02417 rb_exc_raise(rb_errinfo()); 02418 } 02419 } 02420 } 02421 02422 if (depth != rbtk_eventloop_depth) { 02423 DUMP2("DoOneEvent(2) abnormal exit!! %d", 02424 rbtk_eventloop_depth); 02425 return 0; 02426 } 02427 02428 TRAP_CHECK(); 02429 02430 if (check_var != (int*)NULL 02431 && !NIL_P(rbtk_pending_exception)) { 02432 DUMP1("exception on wait"); 02433 return 0; 02434 } 02435 02436 if (pending_exception_check0()) { 02437 /* pending -> upper level */ 02438 return 0; 02439 } 02440 02441 if (st) { 02442 tick_counter++; 02443 } else { 02444 if (update_flag != 0) { 02445 DUMP1("update complete"); 02446 return 0; 02447 } 02448 02449 tick_counter += no_event_tick; 02450 02451 #if 0 02452 /* rb_thread_wait_for(t); */ 02453 rb_protect(eventloop_sleep, Qnil, &status); 02454 02455 if (status) { 02456 switch (status) { 02457 case TAG_RAISE: 02458 if (NIL_P(rb_errinfo())) { 02459 rbtk_pending_exception 02460 = rb_exc_new2(rb_eException, 02461 "unknown exception"); 02462 } else { 02463 rbtk_pending_exception = rb_errinfo(); 02464 02465 if (!NIL_P(rbtk_pending_exception)) { 02466 if (rbtk_eventloop_depth == 0) { 02467 VALUE exc = rbtk_pending_exception; 02468 rbtk_pending_exception = Qnil; 02469 rb_exc_raise(exc); 02470 } else { 02471 return 0; 02472 } 02473 } 02474 } 02475 break; 02476 02477 case TAG_FATAL: 02478 if (NIL_P(rb_errinfo())) { 02479 rb_exc_raise(rb_exc_new2(rb_eFatal, 02480 "FATAL")); 02481 } else { 02482 rb_exc_raise(rb_errinfo()); 02483 } 02484 } 02485 } 02486 #endif 02487 } 02488 02489 } else { 02490 DUMP2("sleep eventloop %lx", current); 02491 DUMP2("eventloop thread is %lx", eventloop_thread); 02492 /* rb_thread_stop(); */ 02493 rb_thread_sleep_forever(); 02494 } 02495 02496 if (!NIL_P(watchdog_thread) && eventloop_thread != current) { 02497 return 1; 02498 } 02499 02500 TRAP_CHECK(); 02501 if (check_eventloop_interp()) return 0; 02502 02503 DUMP1("check Root Widget"); 02504 if (check_root && tk_stubs_init_p() && Tk_GetNumMainWindows() == 0) { 02505 run_timer_flag = 0; 02506 TRAP_CHECK(); 02507 return 1; 02508 } 02509 02510 if (loop_counter++ > 30000) { 02511 /* fprintf(stderr, "loop_counter > 30000\n"); */ 02512 loop_counter = 0; 02513 } 02514 02515 if (run_timer_flag) { 02516 /* 02517 DUMP1("timer interrupt"); 02518 run_timer_flag = 0; 02519 */ 02520 break; /* switch to other thread */ 02521 } 02522 } 02523 02524 DUMP1("thread scheduling"); 02525 rb_thread_schedule(); 02526 } 02527 02528 DUMP1("check interrupts"); 02529 #if defined(RUBY_USE_NATIVE_THREAD) || defined(RUBY_VM) 02530 if (update_flag == 0) rb_thread_check_ints(); 02531 #else 02532 if (update_flag == 0) CHECK_INTS; 02533 #endif 02534 02535 } 02536 return 1; 02537 } 02538 02539 02540 struct evloop_params { 02541 int check_root; 02542 int update_flag; 02543 int *check_var; 02544 Tcl_Interp *interp; 02545 int thr_crit_bup; 02546 }; 02547 02548 VALUE 02549 lib_eventloop_main_core(args) 02550 VALUE args; 02551 { 02552 struct evloop_params *params = (struct evloop_params *)args; 02553 02554 check_rootwidget_flag = params->check_root; 02555 02556 Tcl_CreateEventSource(rbtk_EventSetupProc, rbtk_EventCheckProc, (ClientData)args); 02557 02558 if (lib_eventloop_core(params->check_root, 02559 params->update_flag, 02560 params->check_var, 02561 params->interp)) { 02562 return Qtrue; 02563 } else { 02564 return Qfalse; 02565 } 02566 } 02567 02568 VALUE 02569 lib_eventloop_main(args) 02570 VALUE args; 02571 { 02572 return lib_eventloop_main_core(args); 02573 02574 #if 0 02575 volatile VALUE ret; 02576 int status = 0; 02577 02578 ret = rb_protect(lib_eventloop_main_core, args, &status); 02579 02580 switch (status) { 02581 case TAG_RAISE: 02582 if (NIL_P(rb_errinfo())) { 02583 rbtk_pending_exception 02584 = rb_exc_new2(rb_eException, "unknown exception"); 02585 } else { 02586 rbtk_pending_exception = rb_errinfo(); 02587 } 02588 return Qnil; 02589 02590 case TAG_FATAL: 02591 if (NIL_P(rb_errinfo())) { 02592 rbtk_pending_exception = rb_exc_new2(rb_eFatal, "FATAL"); 02593 } else { 02594 rbtk_pending_exception = rb_errinfo(); 02595 } 02596 return Qnil; 02597 } 02598 02599 return ret; 02600 #endif 02601 } 02602 02603 VALUE 02604 lib_eventloop_ensure(args) 02605 VALUE args; 02606 { 02607 struct evloop_params *ptr = (struct evloop_params *)args; 02608 volatile VALUE current_evloop = rb_thread_current(); 02609 02610 Tcl_DeleteEventSource(rbtk_EventSetupProc, rbtk_EventCheckProc, (ClientData)args); 02611 02612 DUMP2("eventloop_ensure: current-thread : %lx", current_evloop); 02613 DUMP2("eventloop_ensure: eventloop-thread : %lx", eventloop_thread); 02614 if (eventloop_thread != current_evloop) { 02615 DUMP2("finish eventloop %lx (NOT current eventloop)", current_evloop); 02616 02617 rb_thread_critical = ptr->thr_crit_bup; 02618 02619 xfree(ptr); 02620 /* ckfree((char*)ptr); */ 02621 02622 return Qnil; 02623 } 02624 02625 while((eventloop_thread = rb_ary_pop(eventloop_stack))) { 02626 DUMP2("eventloop-ensure: new eventloop-thread -> %lx", 02627 eventloop_thread); 02628 02629 if (eventloop_thread == current_evloop) { 02630 rbtk_eventloop_depth--; 02631 DUMP2("eventloop %lx : back from recursive call", current_evloop); 02632 break; 02633 } 02634 02635 if (NIL_P(eventloop_thread)) { 02636 Tcl_DeleteTimerHandler(timer_token); 02637 timer_token = (Tcl_TimerToken)NULL; 02638 02639 break; 02640 } 02641 02642 #ifdef RUBY_VM 02643 if (RTEST(rb_funcall(eventloop_thread, ID_alive_p, 0, 0))) { 02644 #else 02645 if (RTEST(rb_thread_alive_p(eventloop_thread))) { 02646 #endif 02647 DUMP2("eventloop-enshure: wake up parent %lx", eventloop_thread); 02648 rb_thread_wakeup(eventloop_thread); 02649 02650 break; 02651 } 02652 } 02653 02654 #ifdef RUBY_USE_NATIVE_THREAD 02655 if (NIL_P(eventloop_thread)) { 02656 tk_eventloop_thread_id = (Tcl_ThreadId) 0; 02657 } 02658 #endif 02659 02660 rb_thread_critical = ptr->thr_crit_bup; 02661 02662 xfree(ptr); 02663 /* ckfree((char*)ptr);*/ 02664 02665 DUMP2("finish current eventloop %lx", current_evloop); 02666 return Qnil; 02667 } 02668 02669 static VALUE 02670 lib_eventloop_launcher(check_root, update_flag, check_var, interp) 02671 int check_root; 02672 int update_flag; 02673 int *check_var; 02674 Tcl_Interp *interp; 02675 { 02676 volatile VALUE parent_evloop = eventloop_thread; 02677 struct evloop_params *args = ALLOC(struct evloop_params); 02678 /* struct evloop_params *args = (struct evloop_params *)ckalloc(sizeof(struct evloop_params)); */ 02679 02680 tcl_stubs_check(); 02681 02682 eventloop_thread = rb_thread_current(); 02683 #ifdef RUBY_USE_NATIVE_THREAD 02684 tk_eventloop_thread_id = Tcl_GetCurrentThread(); 02685 #endif 02686 02687 if (parent_evloop == eventloop_thread) { 02688 DUMP2("eventloop: recursive call on %lx", parent_evloop); 02689 rbtk_eventloop_depth++; 02690 } 02691 02692 if (!NIL_P(parent_evloop) && parent_evloop != eventloop_thread) { 02693 DUMP2("wait for stop of parent_evloop %lx", parent_evloop); 02694 while(!RTEST(rb_funcall(parent_evloop, ID_stop_p, 0))) { 02695 DUMP2("parent_evloop %lx doesn't stop", parent_evloop); 02696 rb_thread_run(parent_evloop); 02697 } 02698 DUMP1("succeed to stop parent"); 02699 } 02700 02701 rb_ary_push(eventloop_stack, parent_evloop); 02702 02703 DUMP3("tcltklib: eventloop-thread : %lx -> %lx\n", 02704 parent_evloop, eventloop_thread); 02705 02706 args->check_root = check_root; 02707 args->update_flag = update_flag; 02708 args->check_var = check_var; 02709 args->interp = interp; 02710 args->thr_crit_bup = rb_thread_critical; 02711 02712 rb_thread_critical = Qfalse; 02713 02714 #if 0 02715 return rb_ensure(lib_eventloop_main, (VALUE)args, 02716 lib_eventloop_ensure, (VALUE)args); 02717 #endif 02718 return rb_ensure(lib_eventloop_main_core, (VALUE)args, 02719 lib_eventloop_ensure, (VALUE)args); 02720 } 02721 02722 /* execute Tk_MainLoop */ 02723 static VALUE 02724 lib_mainloop(argc, argv, self) 02725 int argc; 02726 VALUE *argv; 02727 VALUE self; 02728 { 02729 VALUE check_rootwidget; 02730 02731 if (rb_scan_args(argc, argv, "01", &check_rootwidget) == 0) { 02732 check_rootwidget = Qtrue; 02733 } else if (RTEST(check_rootwidget)) { 02734 check_rootwidget = Qtrue; 02735 } else { 02736 check_rootwidget = Qfalse; 02737 } 02738 02739 return lib_eventloop_launcher(RTEST(check_rootwidget), 0, 02740 (int*)NULL, (Tcl_Interp*)NULL); 02741 } 02742 02743 static VALUE 02744 ip_mainloop(argc, argv, self) 02745 int argc; 02746 VALUE *argv; 02747 VALUE self; 02748 { 02749 volatile VALUE ret; 02750 struct tcltkip *ptr = get_ip(self); 02751 02752 /* ip is deleted? */ 02753 if (deleted_ip(ptr)) { 02754 return Qnil; 02755 } 02756 02757 if (Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL) { 02758 /* slave IP */ 02759 return Qnil; 02760 } 02761 02762 eventloop_interp = ptr->ip; 02763 ret = lib_mainloop(argc, argv, self); 02764 eventloop_interp = (Tcl_Interp*)NULL; 02765 return ret; 02766 } 02767 02768 02769 static VALUE 02770 watchdog_evloop_launcher(check_rootwidget) 02771 VALUE check_rootwidget; 02772 { 02773 return lib_eventloop_launcher(RTEST(check_rootwidget), 0, 02774 (int*)NULL, (Tcl_Interp*)NULL); 02775 } 02776 02777 #define EVLOOP_WAKEUP_CHANCE 3 02778 02779 static VALUE 02780 lib_watchdog_core(check_rootwidget) 02781 VALUE check_rootwidget; 02782 { 02783 VALUE evloop; 02784 int prev_val = -1; 02785 int chance = 0; 02786 int check = RTEST(check_rootwidget); 02787 struct timeval t0, t1; 02788 02789 t0.tv_sec = 0; 02790 t0.tv_usec = (long)((NO_THREAD_INTERRUPT_TIME)*1000.0); 02791 t1.tv_sec = 0; 02792 t1.tv_usec = (long)((WATCHDOG_INTERVAL)*1000.0); 02793 02794 /* check other watchdog thread */ 02795 if (!NIL_P(watchdog_thread)) { 02796 if (RTEST(rb_funcall(watchdog_thread, ID_stop_p, 0))) { 02797 rb_funcall(watchdog_thread, ID_kill, 0); 02798 } else { 02799 return Qnil; 02800 } 02801 } 02802 watchdog_thread = rb_thread_current(); 02803 02804 /* watchdog start */ 02805 do { 02806 if (NIL_P(eventloop_thread) 02807 || (loop_counter == prev_val && chance >= EVLOOP_WAKEUP_CHANCE)) { 02808 /* start new eventloop thread */ 02809 DUMP2("eventloop thread %lx is sleeping or dead", 02810 eventloop_thread); 02811 evloop = rb_thread_create(watchdog_evloop_launcher, 02812 (void*)&check_rootwidget); 02813 DUMP2("create new eventloop thread %lx", evloop); 02814 loop_counter = -1; 02815 chance = 0; 02816 rb_thread_run(evloop); 02817 } else { 02818 prev_val = loop_counter; 02819 if (RTEST(rb_funcall(eventloop_thread, ID_stop_p, 0))) { 02820 ++chance; 02821 } else { 02822 chance = 0; 02823 } 02824 if (event_loop_wait_event) { 02825 rb_thread_wait_for(t0); 02826 } else { 02827 rb_thread_wait_for(t1); 02828 } 02829 /* rb_thread_schedule(); */ 02830 } 02831 } while(!check || !tk_stubs_init_p() || Tk_GetNumMainWindows() != 0); 02832 02833 return Qnil; 02834 } 02835 02836 VALUE 02837 lib_watchdog_ensure(arg) 02838 VALUE arg; 02839 { 02840 eventloop_thread = Qnil; /* stop eventloops */ 02841 #ifdef RUBY_USE_NATIVE_THREAD 02842 tk_eventloop_thread_id = (Tcl_ThreadId) 0; 02843 #endif 02844 return Qnil; 02845 } 02846 02847 static VALUE 02848 lib_mainloop_watchdog(argc, argv, self) 02849 int argc; 02850 VALUE *argv; 02851 VALUE self; 02852 { 02853 VALUE check_rootwidget; 02854 02855 #ifdef RUBY_VM 02856 rb_raise(rb_eNotImpError, 02857 "eventloop_watchdog is not implemented on Ruby VM."); 02858 #endif 02859 02860 if (rb_scan_args(argc, argv, "01", &check_rootwidget) == 0) { 02861 check_rootwidget = Qtrue; 02862 } else if (RTEST(check_rootwidget)) { 02863 check_rootwidget = Qtrue; 02864 } else { 02865 check_rootwidget = Qfalse; 02866 } 02867 02868 return rb_ensure(lib_watchdog_core, check_rootwidget, 02869 lib_watchdog_ensure, Qnil); 02870 } 02871 02872 static VALUE 02873 ip_mainloop_watchdog(argc, argv, self) 02874 int argc; 02875 VALUE *argv; 02876 VALUE self; 02877 { 02878 struct tcltkip *ptr = get_ip(self); 02879 02880 /* ip is deleted? */ 02881 if (deleted_ip(ptr)) { 02882 return Qnil; 02883 } 02884 02885 if (Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL) { 02886 /* slave IP */ 02887 return Qnil; 02888 } 02889 return lib_mainloop_watchdog(argc, argv, self); 02890 } 02891 02892 02893 /* thread-safe(?) interaction between Ruby and Tk */ 02894 struct thread_call_proc_arg { 02895 VALUE proc; 02896 int *done; 02897 }; 02898 02899 void 02900 _thread_call_proc_arg_mark(struct thread_call_proc_arg *q) 02901 { 02902 rb_gc_mark(q->proc); 02903 } 02904 02905 static VALUE 02906 _thread_call_proc_core(arg) 02907 VALUE arg; 02908 { 02909 struct thread_call_proc_arg *q = (struct thread_call_proc_arg*)arg; 02910 return rb_funcall(q->proc, ID_call, 0); 02911 } 02912 02913 static VALUE 02914 _thread_call_proc_ensure(arg) 02915 VALUE arg; 02916 { 02917 struct thread_call_proc_arg *q = (struct thread_call_proc_arg*)arg; 02918 *(q->done) = 1; 02919 return Qnil; 02920 } 02921 02922 static VALUE 02923 _thread_call_proc(arg) 02924 VALUE arg; 02925 { 02926 struct thread_call_proc_arg *q = (struct thread_call_proc_arg*)arg; 02927 02928 return rb_ensure(_thread_call_proc_core, (VALUE)q, 02929 _thread_call_proc_ensure, (VALUE)q); 02930 } 02931 02932 static VALUE 02933 #ifdef HAVE_PROTOTYPES 02934 _thread_call_proc_value(VALUE th) 02935 #else 02936 _thread_call_proc_value(th) 02937 VALUE th; 02938 #endif 02939 { 02940 return rb_funcall(th, ID_value, 0); 02941 } 02942 02943 static VALUE 02944 lib_thread_callback(argc, argv, self) 02945 int argc; 02946 VALUE *argv; 02947 VALUE self; 02948 { 02949 struct thread_call_proc_arg *q; 02950 VALUE proc, th, ret; 02951 int status, foundEvent; 02952 02953 if (rb_scan_args(argc, argv, "01", &proc) == 0) { 02954 proc = rb_block_proc(); 02955 } 02956 02957 q = (struct thread_call_proc_arg *)ALLOC(struct thread_call_proc_arg); 02958 /* q = (struct thread_call_proc_arg *)ckalloc(sizeof(struct thread_call_proc_arg)); */ 02959 q->proc = proc; 02960 q->done = (int*)ALLOC(int); 02961 /* q->done = (int*)ckalloc(sizeof(int)); */ 02962 *(q->done) = 0; 02963 02964 /* create call-proc thread */ 02965 th = rb_thread_create(_thread_call_proc, (void*)q); 02966 02967 rb_thread_schedule(); 02968 02969 /* start sub-eventloop */ 02970 foundEvent = RTEST(lib_eventloop_launcher(/* not check root-widget */0, 0, 02971 q->done, (Tcl_Interp*)NULL)); 02972 02973 #ifdef RUBY_VM 02974 if (RTEST(rb_funcall(th, ID_alive_p, 0))) { 02975 #else 02976 if (RTEST(rb_thread_alive_p(th))) { 02977 #endif 02978 rb_funcall(th, ID_kill, 0); 02979 ret = Qnil; 02980 } else { 02981 ret = rb_protect(_thread_call_proc_value, th, &status); 02982 } 02983 02984 xfree(q->done); 02985 xfree(q); 02986 /* ckfree((char*)q->done); */ 02987 /* ckfree((char*)q); */ 02988 02989 if (NIL_P(rbtk_pending_exception)) { 02990 /* return rb_errinfo(); */ 02991 if (status) { 02992 rb_exc_raise(rb_errinfo()); 02993 } 02994 } else { 02995 VALUE exc = rbtk_pending_exception; 02996 rbtk_pending_exception = Qnil; 02997 /* return exc; */ 02998 rb_exc_raise(exc); 02999 } 03000 03001 return ret; 03002 } 03003 03004 03005 /* do_one_event */ 03006 static VALUE 03007 lib_do_one_event_core(argc, argv, self, is_ip) 03008 int argc; 03009 VALUE *argv; 03010 VALUE self; 03011 int is_ip; 03012 { 03013 volatile VALUE vflags; 03014 int flags; 03015 int found_event; 03016 03017 if (!NIL_P(eventloop_thread)) { 03018 rb_raise(rb_eRuntimeError, "eventloop is already running"); 03019 } 03020 03021 tcl_stubs_check(); 03022 03023 if (rb_scan_args(argc, argv, "01", &vflags) == 0) { 03024 flags = TCL_ALL_EVENTS | TCL_DONT_WAIT; 03025 } else { 03026 Check_Type(vflags, T_FIXNUM); 03027 flags = FIX2INT(vflags); 03028 } 03029 03030 if (rb_safe_level() >= 4 || (rb_safe_level() >=1 && OBJ_TAINTED(vflags))) { 03031 flags |= TCL_DONT_WAIT; 03032 } 03033 03034 if (is_ip) { 03035 /* check IP */ 03036 struct tcltkip *ptr = get_ip(self); 03037 03038 /* ip is deleted? */ 03039 if (deleted_ip(ptr)) { 03040 return Qfalse; 03041 } 03042 03043 if (Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL) { 03044 /* slave IP */ 03045 flags |= TCL_DONT_WAIT; 03046 } 03047 } 03048 03049 /* found_event = Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT); */ 03050 found_event = Tcl_DoOneEvent(flags); 03051 03052 if (pending_exception_check0()) { 03053 return Qfalse; 03054 } 03055 03056 if (found_event) { 03057 return Qtrue; 03058 } else { 03059 return Qfalse; 03060 } 03061 } 03062 03063 static VALUE 03064 lib_do_one_event(argc, argv, self) 03065 int argc; 03066 VALUE *argv; 03067 VALUE self; 03068 { 03069 return lib_do_one_event_core(argc, argv, self, 0); 03070 } 03071 03072 static VALUE 03073 ip_do_one_event(argc, argv, self) 03074 int argc; 03075 VALUE *argv; 03076 VALUE self; 03077 { 03078 return lib_do_one_event_core(argc, argv, self, 0); 03079 } 03080 03081 03082 static void 03083 ip_set_exc_message(interp, exc) 03084 Tcl_Interp *interp; 03085 VALUE exc; 03086 { 03087 char *buf; 03088 Tcl_DString dstr; 03089 volatile VALUE msg; 03090 int thr_crit_bup; 03091 03092 #if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION > 0) 03093 volatile VALUE enc; 03094 Tcl_Encoding encoding; 03095 #endif 03096 03097 thr_crit_bup = rb_thread_critical; 03098 rb_thread_critical = Qtrue; 03099 03100 msg = rb_funcall(exc, ID_message, 0, 0); 03101 StringValue(msg); 03102 03103 #if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION > 0) 03104 enc = rb_attr_get(exc, ID_at_enc); 03105 if (NIL_P(enc)) { 03106 enc = rb_attr_get(msg, ID_at_enc); 03107 } 03108 if (NIL_P(enc)) { 03109 encoding = (Tcl_Encoding)NULL; 03110 } else if (TYPE(enc) == T_STRING) { 03111 /* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); */ 03112 encoding = Tcl_GetEncoding((Tcl_Interp*)NULL, RSTRING_PTR(enc)); 03113 } else { 03114 enc = rb_funcall(enc, ID_to_s, 0, 0); 03115 /* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); */ 03116 encoding = Tcl_GetEncoding((Tcl_Interp*)NULL, RSTRING_PTR(enc)); 03117 } 03118 03119 /* to avoid a garbled error message dialog */ 03120 /* buf = ALLOC_N(char, (RSTRING(msg)->len)+1);*/ 03121 /* memcpy(buf, RSTRING(msg)->ptr, RSTRING(msg)->len);*/ 03122 /* buf[RSTRING(msg)->len] = 0; */ 03123 buf = ALLOC_N(char, RSTRING_LEN(msg)+1); 03124 /* buf = ckalloc(sizeof(char)*((RSTRING_LEN(msg))+1)); */ 03125 memcpy(buf, RSTRING_PTR(msg), RSTRING_LEN(msg)); 03126 buf[RSTRING_LEN(msg)] = 0; 03127 03128 Tcl_DStringInit(&dstr); 03129 Tcl_DStringFree(&dstr); 03130 Tcl_ExternalToUtfDString(encoding, buf, RSTRING_LEN(msg), &dstr); 03131 03132 Tcl_AppendResult(interp, Tcl_DStringValue(&dstr), (char*)NULL); 03133 DUMP2("error message:%s", Tcl_DStringValue(&dstr)); 03134 Tcl_DStringFree(&dstr); 03135 xfree(buf); 03136 /* ckfree(buf); */ 03137 03138 #else /* TCL_VERSION <= 8.0 */ 03139 Tcl_AppendResult(interp, RSTRING_PTR(msg), (char*)NULL); 03140 #endif 03141 03142 rb_thread_critical = thr_crit_bup; 03143 } 03144 03145 static VALUE 03146 TkStringValue(obj) 03147 VALUE obj; 03148 { 03149 switch(TYPE(obj)) { 03150 case T_STRING: 03151 return obj; 03152 03153 case T_NIL: 03154 return rb_str_new2(""); 03155 03156 case T_TRUE: 03157 return rb_str_new2("1"); 03158 03159 case T_FALSE: 03160 return rb_str_new2("0"); 03161 03162 case T_ARRAY: 03163 return rb_funcall(obj, ID_join, 1, rb_str_new2(" ")); 03164 03165 default: 03166 if (rb_respond_to(obj, ID_to_s)) { 03167 return rb_funcall(obj, ID_to_s, 0, 0); 03168 } 03169 } 03170 03171 return rb_funcall(obj, ID_inspect, 0, 0); 03172 } 03173 03174 static int 03175 #ifdef HAVE_PROTOTYPES 03176 tcl_protect_core(Tcl_Interp *interp, VALUE (*proc)(VALUE), VALUE data) 03177 #else 03178 tcl_protect_core(interp, proc, data) /* should not raise exception */ 03179 Tcl_Interp *interp; 03180 VALUE (*proc)(); 03181 VALUE data; 03182 #endif 03183 { 03184 volatile VALUE ret, exc = Qnil; 03185 int status = 0; 03186 int thr_crit_bup = rb_thread_critical; 03187 03188 Tcl_ResetResult(interp); 03189 03190 rb_thread_critical = Qfalse; 03191 ret = rb_protect(proc, data, &status); 03192 rb_thread_critical = Qtrue; 03193 if (status) { 03194 char *buf; 03195 VALUE old_gc; 03196 volatile VALUE type, str; 03197 03198 old_gc = rb_gc_disable(); 03199 03200 switch(status) { 03201 case TAG_RETURN: 03202 type = eTkCallbackReturn; 03203 goto error; 03204 case TAG_BREAK: 03205 type = eTkCallbackBreak; 03206 goto error; 03207 case TAG_NEXT: 03208 type = eTkCallbackContinue; 03209 goto error; 03210 error: 03211 str = rb_str_new2("LocalJumpError: "); 03212 rb_str_append(str, rb_obj_as_string(rb_errinfo())); 03213 exc = rb_exc_new3(type, str); 03214 break; 03215 03216 case TAG_RETRY: 03217 if (NIL_P(rb_errinfo())) { 03218 DUMP1("rb_protect: retry"); 03219 exc = rb_exc_new2(eTkCallbackRetry, "retry jump error"); 03220 } else { 03221 exc = rb_errinfo(); 03222 } 03223 break; 03224 03225 case TAG_REDO: 03226 if (NIL_P(rb_errinfo())) { 03227 DUMP1("rb_protect: redo"); 03228 exc = rb_exc_new2(eTkCallbackRedo, "redo jump error"); 03229 } else { 03230 exc = rb_errinfo(); 03231 } 03232 break; 03233 03234 case TAG_RAISE: 03235 if (NIL_P(rb_errinfo())) { 03236 exc = rb_exc_new2(rb_eException, "unknown exception"); 03237 } else { 03238 exc = rb_errinfo(); 03239 } 03240 break; 03241 03242 case TAG_FATAL: 03243 if (NIL_P(rb_errinfo())) { 03244 exc = rb_exc_new2(rb_eFatal, "FATAL"); 03245 } else { 03246 exc = rb_errinfo(); 03247 } 03248 break; 03249 03250 case TAG_THROW: 03251 if (NIL_P(rb_errinfo())) { 03252 DUMP1("rb_protect: throw"); 03253 exc = rb_exc_new2(eTkCallbackThrow, "throw jump error"); 03254 } else { 03255 exc = rb_errinfo(); 03256 } 03257 break; 03258 03259 default: 03260 buf = ALLOC_N(char, 256); 03261 /* buf = ckalloc(sizeof(char) * 256); */ 03262 sprintf(buf, "unknown loncaljmp status %d", status); 03263 exc = rb_exc_new2(rb_eException, buf); 03264 xfree(buf); 03265 /* ckfree(buf); */ 03266 break; 03267 } 03268 03269 if (old_gc == Qfalse) rb_gc_enable(); 03270 03271 ret = Qnil; 03272 } 03273 03274 rb_thread_critical = thr_crit_bup; 03275 03276 Tcl_ResetResult(interp); 03277 03278 /* status check */ 03279 if (!NIL_P(exc)) { 03280 volatile VALUE eclass = rb_obj_class(exc); 03281 volatile VALUE backtrace; 03282 03283 DUMP1("(failed)"); 03284 03285 thr_crit_bup = rb_thread_critical; 03286 rb_thread_critical = Qtrue; 03287 03288 DUMP1("set backtrace"); 03289 if (!NIL_P(backtrace = rb_funcall(exc, ID_backtrace, 0, 0))) { 03290 backtrace = rb_ary_join(backtrace, rb_str_new2("\n")); 03291 Tcl_AddErrorInfo(interp, StringValuePtr(backtrace)); 03292 } 03293 03294 rb_thread_critical = thr_crit_bup; 03295 03296 ip_set_exc_message(interp, exc); 03297 03298 if (eclass == eTkCallbackReturn) 03299 return TCL_RETURN; 03300 03301 if (eclass == eTkCallbackBreak) 03302 return TCL_BREAK; 03303 03304 if (eclass == eTkCallbackContinue) 03305 return TCL_CONTINUE; 03306 03307 if (eclass == rb_eSystemExit || eclass == rb_eInterrupt) { 03308 rbtk_pending_exception = exc; 03309 return TCL_RETURN; 03310 } 03311 03312 if (rb_obj_is_kind_of(exc, eTkLocalJumpError)) { 03313 rbtk_pending_exception = exc; 03314 return TCL_ERROR; 03315 } 03316 03317 if (rb_obj_is_kind_of(exc, eLocalJumpError)) { 03318 VALUE reason = rb_ivar_get(exc, ID_at_reason); 03319 03320 if (TYPE(reason) == T_SYMBOL) { 03321 if (SYM2ID(reason) == ID_return) 03322 return TCL_RETURN; 03323 03324 if (SYM2ID(reason) == ID_break) 03325 return TCL_BREAK; 03326 03327 if (SYM2ID(reason) == ID_next) 03328 return TCL_CONTINUE; 03329 } 03330 } 03331 03332 return TCL_ERROR; 03333 } 03334 03335 /* result must be string or nil */ 03336 if (!NIL_P(ret)) { 03337 /* copy result to the tcl interpreter */ 03338 thr_crit_bup = rb_thread_critical; 03339 rb_thread_critical = Qtrue; 03340 03341 ret = TkStringValue(ret); 03342 DUMP1("Tcl_AppendResult"); 03343 Tcl_AppendResult(interp, RSTRING_PTR(ret), (char *)NULL); 03344 03345 rb_thread_critical = thr_crit_bup; 03346 } 03347 03348 DUMP2("(result) %s", NIL_P(ret) ? "nil" : RSTRING_PTR(ret)); 03349 03350 return TCL_OK; 03351 } 03352 03353 static int 03354 tcl_protect(interp, proc, data) 03355 Tcl_Interp *interp; 03356 VALUE (*proc)(); 03357 VALUE data; 03358 { 03359 int code; 03360 03361 #ifdef HAVE_NATIVETHREAD 03362 #ifndef RUBY_USE_NATIVE_THREAD 03363 if (!ruby_native_thread_p()) { 03364 rb_bug("cross-thread violation on tcl_protect()"); 03365 } 03366 #endif 03367 #endif 03368 03369 #ifdef RUBY_VM 03370 code = tcl_protect_core(interp, proc, data); 03371 #else 03372 do { 03373 int old_trapflag = rb_trap_immediate; 03374 rb_trap_immediate = 0; 03375 code = tcl_protect_core(interp, proc, data); 03376 rb_trap_immediate = old_trapflag; 03377 } while (0); 03378 #endif 03379 03380 return code; 03381 } 03382 03383 static int 03384 #if TCL_MAJOR_VERSION >= 8 03385 ip_ruby_eval(clientData, interp, argc, argv) 03386 ClientData clientData; 03387 Tcl_Interp *interp; 03388 int argc; 03389 Tcl_Obj *CONST argv[]; 03390 #else /* TCL_MAJOR_VERSION < 8 */ 03391 ip_ruby_eval(clientData, interp, argc, argv) 03392 ClientData clientData; 03393 Tcl_Interp *interp; 03394 int argc; 03395 char *argv[]; 03396 #endif 03397 { 03398 char *arg; 03399 int thr_crit_bup; 03400 int code; 03401 03402 if (interp == (Tcl_Interp*)NULL) { 03403 rbtk_pending_exception = rb_exc_new2(rb_eRuntimeError, 03404 "IP is deleted"); 03405 return TCL_ERROR; 03406 } 03407 03408 /* ruby command has 1 arg. */ 03409 if (argc != 2) { 03410 #if 0 03411 rb_raise(rb_eArgError, 03412 "wrong number of arguments (%d for 1)", argc - 1); 03413 #else 03414 char buf[sizeof(int)*8 + 1]; 03415 Tcl_ResetResult(interp); 03416 sprintf(buf, "%d", argc-1); 03417 Tcl_AppendResult(interp, "wrong number of arguments (", 03418 buf, " for 1)", (char *)NULL); 03419 rbtk_pending_exception = rb_exc_new2(rb_eArgError, 03420 Tcl_GetStringResult(interp)); 03421 return TCL_ERROR; 03422 #endif 03423 } 03424 03425 /* get C string from Tcl object */ 03426 #if TCL_MAJOR_VERSION >= 8 03427 { 03428 char *str; 03429 int len; 03430 03431 thr_crit_bup = rb_thread_critical; 03432 rb_thread_critical = Qtrue; 03433 03434 str = Tcl_GetStringFromObj(argv[1], &len); 03435 arg = ALLOC_N(char, len + 1); 03436 /* arg = ckalloc(sizeof(char) * (len + 1)); */ 03437 memcpy(arg, str, len); 03438 arg[len] = 0; 03439 03440 rb_thread_critical = thr_crit_bup; 03441 03442 } 03443 #else /* TCL_MAJOR_VERSION < 8 */ 03444 arg = argv[1]; 03445 #endif 03446 03447 /* evaluate the argument string by ruby */ 03448 DUMP2("rb_eval_string(%s)", arg); 03449 03450 code = tcl_protect(interp, rb_eval_string, (VALUE)arg); 03451 03452 #if TCL_MAJOR_VERSION >= 8 03453 xfree(arg); 03454 /* ckfree(arg); */ 03455 #endif 03456 03457 return code; 03458 } 03459 03460 03461 /* Tcl command `ruby_cmd' */ 03462 static VALUE 03463 ip_ruby_cmd_core(arg) 03464 struct cmd_body_arg *arg; 03465 { 03466 volatile VALUE ret; 03467 int thr_crit_bup; 03468 03469 DUMP1("call ip_ruby_cmd_core"); 03470 thr_crit_bup = rb_thread_critical; 03471 rb_thread_critical = Qfalse; 03472 ret = rb_apply(arg->receiver, arg->method, arg->args); 03473 DUMP2("rb_apply return:%lx", ret); 03474 rb_thread_critical = thr_crit_bup; 03475 DUMP1("finish ip_ruby_cmd_core"); 03476 03477 return ret; 03478 } 03479 03480 #define SUPPORT_NESTED_CONST_AS_IP_RUBY_CMD_RECEIVER 1 03481 03482 static VALUE 03483 ip_ruby_cmd_receiver_const_get(name) 03484 char *name; 03485 { 03486 volatile VALUE klass = rb_cObject; 03487 #if 0 03488 char *head, *tail; 03489 #endif 03490 int state; 03491 03492 #if SUPPORT_NESTED_CONST_AS_IP_RUBY_CMD_RECEIVER 03493 klass = rb_eval_string_protect(name, &state); 03494 if (state) { 03495 return Qnil; 03496 } else { 03497 return klass; 03498 } 03499 #else 03500 return rb_const_get(klass, rb_intern(name)); 03501 #endif 03502 03503 /* TODO!!!!!! */ 03504 /* support nest of classes/modules */ 03505 03506 /* return rb_eval_string(name); */ 03507 /* return rb_eval_string_protect(name, &state); */ 03508 03509 #if 0 /* doesn't work!! (fail to autoload?) */ 03510 /* duplicate */ 03511 head = name = strdup(name); 03512 03513 /* has '::' at head ? */ 03514 if (*head == ':') head += 2; 03515 tail = head; 03516 03517 /* search */ 03518 while(*tail) { 03519 if (*tail == ':') { 03520 *tail = '\0'; 03521 klass = rb_const_get(klass, rb_intern(head)); 03522 tail += 2; 03523 head = tail; 03524 } else { 03525 tail++; 03526 } 03527 } 03528 03529 free(name); 03530 return rb_const_get(klass, rb_intern(head)); 03531 #endif 03532 } 03533 03534 static VALUE 03535 ip_ruby_cmd_receiver_get(str) 03536 char *str; 03537 { 03538 volatile VALUE receiver; 03539 #if !SUPPORT_NESTED_CONST_AS_IP_RUBY_CMD_RECEIVER 03540 int state; 03541 #endif 03542 03543 if (str[0] == ':' || ('A' <= str[0] && str[0] <= 'Z')) { 03544 /* class | module | constant */ 03545 #if SUPPORT_NESTED_CONST_AS_IP_RUBY_CMD_RECEIVER 03546 receiver = ip_ruby_cmd_receiver_const_get(str); 03547 #else 03548 receiver = rb_protect(ip_ruby_cmd_receiver_const_get, (VALUE)str, &state); 03549 if (state) return Qnil; 03550 #endif 03551 } else if (str[0] == '$') { 03552 /* global variable */ 03553 receiver = rb_gv_get(str); 03554 } else { 03555 /* global variable omitted '$' */ 03556 char *buf; 03557 int len; 03558 03559 len = strlen(str); 03560 buf = ALLOC_N(char, len + 2); 03561 /* buf = ckalloc(sizeof(char) * (len + 2)); */ 03562 buf[0] = '$'; 03563 memcpy(buf + 1, str, len); 03564 buf[len + 1] = 0; 03565 receiver = rb_gv_get(buf); 03566 xfree(buf); 03567 /* ckfree(buf); */ 03568 } 03569 03570 return receiver; 03571 } 03572 03573 /* ruby_cmd receiver method arg ... */ 03574 static int 03575 #if TCL_MAJOR_VERSION >= 8 03576 ip_ruby_cmd(clientData, interp, argc, argv) 03577 ClientData clientData; 03578 Tcl_Interp *interp; 03579 int argc; 03580 Tcl_Obj *CONST argv[]; 03581 #else /* TCL_MAJOR_VERSION < 8 */ 03582 ip_ruby_cmd(clientData, interp, argc, argv) 03583 ClientData clientData; 03584 Tcl_Interp *interp; 03585 int argc; 03586 char *argv[]; 03587 #endif 03588 { 03589 volatile VALUE receiver; 03590 volatile ID method; 03591 volatile VALUE args; 03592 char *str; 03593 int i; 03594 int len; 03595 struct cmd_body_arg *arg; 03596 int thr_crit_bup; 03597 VALUE old_gc; 03598 int code; 03599 03600 if (interp == (Tcl_Interp*)NULL) { 03601 rbtk_pending_exception = rb_exc_new2(rb_eRuntimeError, 03602 "IP is deleted"); 03603 return TCL_ERROR; 03604 } 03605 03606 if (argc < 3) { 03607 #if 0 03608 rb_raise(rb_eArgError, "too few arguments"); 03609 #else 03610 Tcl_ResetResult(interp); 03611 Tcl_AppendResult(interp, "too few arguments", (char *)NULL); 03612 rbtk_pending_exception = rb_exc_new2(rb_eArgError, 03613 Tcl_GetStringResult(interp)); 03614 return TCL_ERROR; 03615 #endif 03616 } 03617 03618 /* get arguments from Tcl objects */ 03619 thr_crit_bup = rb_thread_critical; 03620 rb_thread_critical = Qtrue; 03621 old_gc = rb_gc_disable(); 03622 03623 /* get receiver */ 03624 #if TCL_MAJOR_VERSION >= 8 03625 str = Tcl_GetStringFromObj(argv[1], &len); 03626 #else /* TCL_MAJOR_VERSION < 8 */ 03627 str = argv[1]; 03628 #endif 03629 DUMP2("receiver:%s",str); 03630 /* receiver = rb_protect(ip_ruby_cmd_receiver_get, (VALUE)str, &code); */ 03631 receiver = ip_ruby_cmd_receiver_get(str); 03632 if (NIL_P(receiver)) { 03633 #if 0 03634 rb_raise(rb_eArgError, 03635 "unknown class/module/global-variable '%s'", str); 03636 #else 03637 Tcl_ResetResult(interp); 03638 Tcl_AppendResult(interp, "unknown class/module/global-variable '", 03639 str, "'", (char *)NULL); 03640 rbtk_pending_exception = rb_exc_new2(rb_eArgError, 03641 Tcl_GetStringResult(interp)); 03642 if (old_gc == Qfalse) rb_gc_enable(); 03643 return TCL_ERROR; 03644 #endif 03645 } 03646 03647 /* get metrhod */ 03648 #if TCL_MAJOR_VERSION >= 8 03649 str = Tcl_GetStringFromObj(argv[2], &len); 03650 #else /* TCL_MAJOR_VERSION < 8 */ 03651 str = argv[2]; 03652 #endif 03653 method = rb_intern(str); 03654 03655 /* get args */ 03656 args = rb_ary_new2(argc - 2); 03657 for(i = 3; i < argc; i++) { 03658 VALUE s; 03659 #if TCL_MAJOR_VERSION >= 8 03660 str = Tcl_GetStringFromObj(argv[i], &len); 03661 s = rb_tainted_str_new(str, len); 03662 #else /* TCL_MAJOR_VERSION < 8 */ 03663 str = argv[i]; 03664 s = rb_tainted_str_new2(str); 03665 #endif 03666 DUMP2("arg:%s",str); 03667 #ifndef HAVE_STRUCT_RARRAY_LEN 03668 rb_ary_push(args, s); 03669 #else 03670 RARRAY(args)->ptr[RARRAY(args)->len++] = s; 03671 #endif 03672 } 03673 03674 if (old_gc == Qfalse) rb_gc_enable(); 03675 rb_thread_critical = thr_crit_bup; 03676 03677 /* allocate */ 03678 arg = ALLOC(struct cmd_body_arg); 03679 /* arg = (struct cmd_body_arg *)ckalloc(sizeof(struct cmd_body_arg)); */ 03680 03681 arg->receiver = receiver; 03682 arg->method = method; 03683 arg->args = args; 03684 03685 /* evaluate the argument string by ruby */ 03686 code = tcl_protect(interp, ip_ruby_cmd_core, (VALUE)arg); 03687 03688 xfree(arg); 03689 /* ckfree((char*)arg); */ 03690 03691 return code; 03692 } 03693 03694 03695 /*****************************/ 03696 /* relpace of 'exit' command */ 03697 /*****************************/ 03698 static int 03699 #if TCL_MAJOR_VERSION >= 8 03700 #ifdef HAVE_PROTOTYPES 03701 ip_InterpExitObjCmd(ClientData clientData, Tcl_Interp *interp, 03702 int argc, Tcl_Obj *CONST argv[]) 03703 #else 03704 ip_InterpExitObjCmd(clientData, interp, argc, argv) 03705 ClientData clientData; 03706 Tcl_Interp *interp; 03707 int argc; 03708 Tcl_Obj *CONST argv[]; 03709 #endif 03710 #else /* TCL_MAJOR_VERSION < 8 */ 03711 #ifdef HAVE_PROTOTYPES 03712 ip_InterpExitCommand(ClientData clientData, Tcl_Interp *interp, 03713 int argc, char *argv[]) 03714 #else 03715 ip_InterpExitCommand(clientData, interp, argc, argv) 03716 ClientData clientData; 03717 Tcl_Interp *interp; 03718 int argc; 03719 char *argv[]; 03720 #endif 03721 #endif 03722 { 03723 DUMP1("start ip_InterpExitCommand"); 03724 if (interp != (Tcl_Interp*)NULL 03725 && !Tcl_InterpDeleted(interp) 03726 #if TCL_NAMESPACE_DEBUG 03727 && !ip_null_namespace(interp) 03728 #endif 03729 ) { 03730 Tcl_ResetResult(interp); 03731 /* Tcl_Preserve(interp); */ 03732 /* Tcl_Eval(interp, "interp eval {} {destroy .}; interp delete {}"); */ 03733 if (!Tcl_InterpDeleted(interp)) { 03734 ip_finalize(interp); 03735 03736 Tcl_DeleteInterp(interp); 03737 Tcl_Release(interp); 03738 } 03739 } 03740 return TCL_OK; 03741 } 03742 03743 static int 03744 #if TCL_MAJOR_VERSION >= 8 03745 #ifdef HAVE_PROTOTYPES 03746 ip_RubyExitObjCmd(ClientData clientData, Tcl_Interp *interp, 03747 int argc, Tcl_Obj *CONST argv[]) 03748 #else 03749 ip_RubyExitObjCmd(clientData, interp, argc, argv) 03750 ClientData clientData; 03751 Tcl_Interp *interp; 03752 int argc; 03753 Tcl_Obj *CONST argv[]; 03754 #endif 03755 #else /* TCL_MAJOR_VERSION < 8 */ 03756 #ifdef HAVE_PROTOTYPES 03757 ip_RubyExitCommand(ClientData clientData, Tcl_Interp *interp, 03758 int argc, char *argv[]) 03759 #else 03760 ip_RubyExitCommand(clientData, interp, argc, argv) 03761 ClientData clientData; 03762 Tcl_Interp *interp; 03763 int argc; 03764 char *argv[]; 03765 #endif 03766 #endif 03767 { 03768 int state; 03769 char *cmd, *param; 03770 #if TCL_MAJOR_VERSION < 8 03771 char *endptr; 03772 cmd = argv[0]; 03773 #endif 03774 03775 DUMP1("start ip_RubyExitCommand"); 03776 03777 #if TCL_MAJOR_VERSION >= 8 03778 /* cmd = Tcl_GetString(argv[0]); */ 03779 cmd = Tcl_GetStringFromObj(argv[0], (int*)NULL); 03780 #endif 03781 03782 if (argc < 1 || argc > 2) { 03783 /* arguemnt error */ 03784 Tcl_AppendResult(interp, 03785 "wrong number of arguments: should be \"", 03786 cmd, " ?returnCode?\"", (char *)NULL); 03787 return TCL_ERROR; 03788 } 03789 03790 if (interp == (Tcl_Interp*)NULL) return TCL_OK; 03791 03792 Tcl_ResetResult(interp); 03793 03794 if (rb_safe_level() >= 4 || Tcl_IsSafe(interp)) { 03795 if (!Tcl_InterpDeleted(interp)) { 03796 ip_finalize(interp); 03797 03798 Tcl_DeleteInterp(interp); 03799 Tcl_Release(interp); 03800 } 03801 return TCL_OK; 03802 } 03803 03804 switch(argc) { 03805 case 1: 03806 /* rb_exit(0); */ /* not return if succeed */ 03807 Tcl_AppendResult(interp, 03808 "fail to call \"", cmd, "\"", (char *)NULL); 03809 03810 rbtk_pending_exception = rb_exc_new2(rb_eSystemExit, 03811 Tcl_GetStringResult(interp)); 03812 rb_iv_set(rbtk_pending_exception, "status", INT2FIX(0)); 03813 03814 return TCL_RETURN; 03815 03816 case 2: 03817 #if TCL_MAJOR_VERSION >= 8 03818 if (Tcl_GetIntFromObj(interp, argv[1], &state) == TCL_ERROR) { 03819 return TCL_ERROR; 03820 } 03821 /* param = Tcl_GetString(argv[1]); */ 03822 param = Tcl_GetStringFromObj(argv[1], (int*)NULL); 03823 #else /* TCL_MAJOR_VERSION < 8 */ 03824 state = (int)strtol(argv[1], &endptr, 0); 03825 if (*endptr) { 03826 Tcl_AppendResult(interp, 03827 "expected integer but got \"", 03828 argv[1], "\"", (char *)NULL); 03829 return TCL_ERROR; 03830 } 03831 param = argv[1]; 03832 #endif 03833 /* rb_exit(state); */ /* not return if succeed */ 03834 03835 Tcl_AppendResult(interp, "fail to call \"", cmd, " ", 03836 param, "\"", (char *)NULL); 03837 03838 rbtk_pending_exception = rb_exc_new2(rb_eSystemExit, 03839 Tcl_GetStringResult(interp)); 03840 rb_iv_set(rbtk_pending_exception, "status", INT2FIX(state)); 03841 03842 return TCL_RETURN; 03843 03844 default: 03845 /* arguemnt error */ 03846 Tcl_AppendResult(interp, 03847 "wrong number of arguments: should be \"", 03848 cmd, " ?returnCode?\"", (char *)NULL); 03849 return TCL_ERROR; 03850 } 03851 } 03852 03853 03854 /**************************/ 03855 /* based on tclEvent.c */ 03856 /**************************/ 03857 03858 /*********************/ 03859 /* replace of update */ 03860 /*********************/ 03861 #if TCL_MAJOR_VERSION >= 8 03862 static int ip_rbUpdateObjCmd _((ClientData, Tcl_Interp *, int, 03863 Tcl_Obj *CONST [])); 03864 static int 03865 ip_rbUpdateObjCmd(clientData, interp, objc, objv) 03866 ClientData clientData; 03867 Tcl_Interp *interp; 03868 int objc; 03869 Tcl_Obj *CONST objv[]; 03870 #else /* TCL_MAJOR_VERSION < 8 */ 03871 static int ip_rbUpdateCommand _((ClientData, Tcl_Interp *, int, char *[])); 03872 static int 03873 ip_rbUpdateCommand(clientData, interp, objc, objv) 03874 ClientData clientData; 03875 Tcl_Interp *interp; 03876 int objc; 03877 char *objv[]; 03878 #endif 03879 { 03880 int optionIndex; 03881 int ret; 03882 int flags = 0; 03883 static CONST char *updateOptions[] = {"idletasks", (char *) NULL}; 03884 enum updateOptions {REGEXP_IDLETASKS}; 03885 03886 DUMP1("Ruby's 'update' is called"); 03887 if (interp == (Tcl_Interp*)NULL) { 03888 rbtk_pending_exception = rb_exc_new2(rb_eRuntimeError, 03889 "IP is deleted"); 03890 return TCL_ERROR; 03891 } 03892 #ifdef HAVE_NATIVETHREAD 03893 #ifndef RUBY_USE_NATIVE_THREAD 03894 if (!ruby_native_thread_p()) { 03895 rb_bug("cross-thread violation on ip_ruby_eval()"); 03896 } 03897 #endif 03898 #endif 03899 03900 Tcl_ResetResult(interp); 03901 03902 if (objc == 1) { 03903 flags = TCL_DONT_WAIT; 03904 03905 } else if (objc == 2) { 03906 #if TCL_MAJOR_VERSION >= 8 03907 if (Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)updateOptions, 03908 "option", 0, &optionIndex) != TCL_OK) { 03909 return TCL_ERROR; 03910 } 03911 switch ((enum updateOptions) optionIndex) { 03912 case REGEXP_IDLETASKS: { 03913 flags = TCL_IDLE_EVENTS; 03914 break; 03915 } 03916 default: { 03917 rb_bug("ip_rbUpdateObjCmd: bad option index to UpdateOptions"); 03918 } 03919 } 03920 #else 03921 if (strncmp(objv[1], "idletasks", strlen(objv[1])) != 0) { 03922 Tcl_AppendResult(interp, "bad option \"", objv[1], 03923 "\": must be idletasks", (char *) NULL); 03924 return TCL_ERROR; 03925 } 03926 flags = TCL_IDLE_EVENTS; 03927 #endif 03928 } else { 03929 #ifdef Tcl_WrongNumArgs 03930 Tcl_WrongNumArgs(interp, 1, objv, "[ idletasks ]"); 03931 #else 03932 # if TCL_MAJOR_VERSION >= 8 03933 int dummy; 03934 Tcl_AppendResult(interp, "wrong number of arguments: should be \"", 03935 Tcl_GetStringFromObj(objv[0], &dummy), 03936 " [ idletasks ]\"", 03937 (char *) NULL); 03938 # else /* TCL_MAJOR_VERSION < 8 */ 03939 Tcl_AppendResult(interp, "wrong number of arguments: should be \"", 03940 objv[0], " [ idletasks ]\"", (char *) NULL); 03941 # endif 03942 #endif 03943 return TCL_ERROR; 03944 } 03945 03946 Tcl_Preserve(interp); 03947 03948 /* call eventloop */ 03949 /* ret = lib_eventloop_core(0, flags, (int *)NULL);*/ /* ignore result */ 03950 ret = RTEST(lib_eventloop_launcher(0, flags, (int *)NULL, interp)); /* ignore result */ 03951 03952 /* exception check */ 03953 if (!NIL_P(rbtk_pending_exception)) { 03954 Tcl_Release(interp); 03955 03956 /* 03957 if (rb_obj_is_kind_of(rbtk_pending_exception, rb_eSystemExit)) { 03958 */ 03959 if (rb_obj_is_kind_of(rbtk_pending_exception, rb_eSystemExit) 03960 || rb_obj_is_kind_of(rbtk_pending_exception, rb_eInterrupt)) { 03961 return TCL_RETURN; 03962 } else{ 03963 return TCL_ERROR; 03964 } 03965 } 03966 03967 /* trap check */ 03968 #ifdef RUBY_VM 03969 if (rb_thread_check_trap_pending()) { 03970 #else 03971 if (rb_trap_pending) { 03972 #endif 03973 Tcl_Release(interp); 03974 03975 return TCL_RETURN; 03976 } 03977 03978 /* 03979 * Must clear the interpreter's result because event handlers could 03980 * have executed commands. 03981 */ 03982 03983 DUMP2("last result '%s'", Tcl_GetStringResult(interp)); 03984 Tcl_ResetResult(interp); 03985 Tcl_Release(interp); 03986 03987 DUMP1("finish Ruby's 'update'"); 03988 return TCL_OK; 03989 } 03990 03991 03992 /**********************/ 03993 /* update with thread */ 03994 /**********************/ 03995 struct th_update_param { 03996 VALUE thread; 03997 int done; 03998 }; 03999 04000 static void rb_threadUpdateProc _((ClientData)); 04001 static void 04002 rb_threadUpdateProc(clientData) 04003 ClientData clientData; /* Pointer to integer to set to 1. */ 04004 { 04005 struct th_update_param *param = (struct th_update_param *) clientData; 04006 04007 DUMP1("threadUpdateProc is called"); 04008 param->done = 1; 04009 rb_thread_wakeup(param->thread); 04010 04011 return; 04012 } 04013 04014 #if TCL_MAJOR_VERSION >= 8 04015 static int ip_rb_threadUpdateObjCmd _((ClientData, Tcl_Interp *, int, 04016 Tcl_Obj *CONST [])); 04017 static int 04018 ip_rb_threadUpdateObjCmd(clientData, interp, objc, objv) 04019 ClientData clientData; 04020 Tcl_Interp *interp; 04021 int objc; 04022 Tcl_Obj *CONST objv[]; 04023 #else /* TCL_MAJOR_VERSION < 8 */ 04024 static int ip_rb_threadUpdateCommand _((ClientData, Tcl_Interp *, int, 04025 char *[])); 04026 static int 04027 ip_rb_threadUpdateCommand(clientData, interp, objc, objv) 04028 ClientData clientData; 04029 Tcl_Interp *interp; 04030 int objc; 04031 char *objv[]; 04032 #endif 04033 { 04034 int optionIndex; 04035 int flags = 0; 04036 struct th_update_param *param; 04037 static CONST char *updateOptions[] = {"idletasks", (char *) NULL}; 04038 enum updateOptions {REGEXP_IDLETASKS}; 04039 volatile VALUE current_thread = rb_thread_current(); 04040 struct timeval t; 04041 04042 DUMP1("Ruby's 'thread_update' is called"); 04043 if (interp == (Tcl_Interp*)NULL) { 04044 rbtk_pending_exception = rb_exc_new2(rb_eRuntimeError, 04045 "IP is deleted"); 04046 return TCL_ERROR; 04047 } 04048 #ifdef HAVE_NATIVETHREAD 04049 #ifndef RUBY_USE_NATIVE_THREAD 04050 if (!ruby_native_thread_p()) { 04051 rb_bug("cross-thread violation on ip_rb_threadUpdateCommand()"); 04052 } 04053 #endif 04054 #endif 04055 04056 if (rb_thread_alone() 04057 || NIL_P(eventloop_thread) || eventloop_thread == current_thread) { 04058 #if TCL_MAJOR_VERSION >= 8 04059 DUMP1("call ip_rbUpdateObjCmd"); 04060 return ip_rbUpdateObjCmd(clientData, interp, objc, objv); 04061 #else /* TCL_MAJOR_VERSION < 8 */ 04062 DUMP1("call ip_rbUpdateCommand"); 04063 return ip_rbUpdateCommand(clientData, interp, objc, objv); 04064 #endif 04065 } 04066 04067 DUMP1("start Ruby's 'thread_update' body"); 04068 04069 Tcl_ResetResult(interp); 04070 04071 if (objc == 1) { 04072 flags = TCL_DONT_WAIT; 04073 04074 } else if (objc == 2) { 04075 #if TCL_MAJOR_VERSION >= 8 04076 if (Tcl_GetIndexFromObj(interp, objv[1], (CONST84 char **)updateOptions, 04077 "option", 0, &optionIndex) != TCL_OK) { 04078 return TCL_ERROR; 04079 } 04080 switch ((enum updateOptions) optionIndex) { 04081 case REGEXP_IDLETASKS: { 04082 flags = TCL_IDLE_EVENTS; 04083 break; 04084 } 04085 default: { 04086 rb_bug("ip_rb_threadUpdateObjCmd: bad option index to UpdateOptions"); 04087 } 04088 } 04089 #else 04090 if (strncmp(objv[1], "idletasks", strlen(objv[1])) != 0) { 04091 Tcl_AppendResult(interp, "bad option \"", objv[1], 04092 "\": must be idletasks", (char *) NULL); 04093 return TCL_ERROR; 04094 } 04095 flags = TCL_IDLE_EVENTS; 04096 #endif 04097 } else { 04098 #ifdef Tcl_WrongNumArgs 04099 Tcl_WrongNumArgs(interp, 1, objv, "[ idletasks ]"); 04100 #else 04101 # if TCL_MAJOR_VERSION >= 8 04102 int dummy; 04103 Tcl_AppendResult(interp, "wrong number of arguments: should be \"", 04104 Tcl_GetStringFromObj(objv[0], &dummy), 04105 " [ idletasks ]\"", 04106 (char *) NULL); 04107 # else /* TCL_MAJOR_VERSION < 8 */ 04108 Tcl_AppendResult(interp, "wrong number of arguments: should be \"", 04109 objv[0], " [ idletasks ]\"", (char *) NULL); 04110 # endif 04111 #endif 04112 return TCL_ERROR; 04113 } 04114 04115 DUMP1("pass argument check"); 04116 04117 /* param = (struct th_update_param *)Tcl_Alloc(sizeof(struct th_update_param)); */ 04118 param = (struct th_update_param *)ckalloc(sizeof(struct th_update_param)); 04119 #if 0 /* use Tcl_Preserve/Release */ 04120 Tcl_Preserve((ClientData)param); 04121 #endif 04122 param->thread = current_thread; 04123 param->done = 0; 04124 04125 DUMP1("set idle proc"); 04126 Tcl_DoWhenIdle(rb_threadUpdateProc, (ClientData) param); 04127 04128 t.tv_sec = 0; 04129 t.tv_usec = (long)((EVENT_HANDLER_TIMEOUT)*1000.0); 04130 04131 while(!param->done) { 04132 DUMP1("wait for complete idle proc"); 04133 /* rb_thread_stop(); */ 04134 /* rb_thread_sleep_forever(); */ 04135 rb_thread_wait_for(t); 04136 if (NIL_P(eventloop_thread)) { 04137 break; 04138 } 04139 } 04140 04141 #if 0 /* use Tcl_EventuallyFree */ 04142 Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ 04143 #else 04144 #if 0 /* use Tcl_Preserve/Release */ 04145 Tcl_Release((ClientData)param); 04146 #else 04147 /* Tcl_Free((char *)param); */ 04148 ckfree((char *)param); 04149 #endif 04150 #endif 04151 04152 DUMP1("finish Ruby's 'thread_update'"); 04153 return TCL_OK; 04154 } 04155 04156 04157 /***************************/ 04158 /* replace of vwait/tkwait */ 04159 /***************************/ 04160 #if TCL_MAJOR_VERSION >= 8 04161 static int ip_rbVwaitObjCmd _((ClientData, Tcl_Interp *, int, 04162 Tcl_Obj *CONST [])); 04163 static int ip_rb_threadVwaitObjCmd _((ClientData, Tcl_Interp *, int, 04164 Tcl_Obj *CONST [])); 04165 static int ip_rbTkWaitObjCmd _((ClientData, Tcl_Interp *, int, 04166 Tcl_Obj *CONST [])); 04167 static int ip_rb_threadTkWaitObjCmd _((ClientData, Tcl_Interp *, int, 04168 Tcl_Obj *CONST [])); 04169 #else 04170 static int ip_rbVwaitCommand _((ClientData, Tcl_Interp *, int, char *[])); 04171 static int ip_rb_threadVwaitCommand _((ClientData, Tcl_Interp *, int, 04172 char *[])); 04173 static int ip_rbTkWaitCommand _((ClientData, Tcl_Interp *, int, char *[])); 04174 static int ip_rb_threadTkWaitCommand _((ClientData, Tcl_Interp *, int, 04175 char *[])); 04176 #endif 04177 04178 #if TCL_MAJOR_VERSION >= 8 04179 static char *VwaitVarProc _((ClientData, Tcl_Interp *, 04180 CONST84 char *,CONST84 char *, int)); 04181 static char * 04182 VwaitVarProc(clientData, interp, name1, name2, flags) 04183 ClientData clientData; /* Pointer to integer to set to 1. */ 04184 Tcl_Interp *interp; /* Interpreter containing variable. */ 04185 CONST84 char *name1; /* Name of variable. */ 04186 CONST84 char *name2; /* Second part of variable name. */ 04187 int flags; /* Information about what happened. */ 04188 #else /* TCL_MAJOR_VERSION < 8 */ 04189 static char *VwaitVarProc _((ClientData, Tcl_Interp *, char *, char *, int)); 04190 static char * 04191 VwaitVarProc(clientData, interp, name1, name2, flags) 04192 ClientData clientData; /* Pointer to integer to set to 1. */ 04193 Tcl_Interp *interp; /* Interpreter containing variable. */ 04194 char *name1; /* Name of variable. */ 04195 char *name2; /* Second part of variable name. */ 04196 int flags; /* Information about what happened. */ 04197 #endif 04198 { 04199 int *donePtr = (int *) clientData; 04200 04201 *donePtr = 1; 04202 return (char *) NULL; 04203 } 04204 04205 #if TCL_MAJOR_VERSION >= 8 04206 static int 04207 ip_rbVwaitObjCmd(clientData, interp, objc, objv) 04208 ClientData clientData; /* Not used */ 04209 Tcl_Interp *interp; 04210 int objc; 04211 Tcl_Obj *CONST objv[]; 04212 #else /* TCL_MAJOR_VERSION < 8 */ 04213 static int 04214 ip_rbVwaitCommand(clientData, interp, objc, objv) 04215 ClientData clientData; /* Not used */ 04216 Tcl_Interp *interp; 04217 int objc; 04218 char *objv[]; 04219 #endif 04220 { 04221 int ret, done, foundEvent; 04222 char *nameString; 04223 int dummy; 04224 int thr_crit_bup; 04225 04226 DUMP1("Ruby's 'vwait' is called"); 04227 if (interp == (Tcl_Interp*)NULL) { 04228 rbtk_pending_exception = rb_exc_new2(rb_eRuntimeError, 04229 "IP is deleted"); 04230 return TCL_ERROR; 04231 } 04232 04233 #if 0 04234 if (!rb_thread_alone() 04235 && eventloop_thread != Qnil 04236 && eventloop_thread != rb_thread_current()) { 04237 #if TCL_MAJOR_VERSION >= 8 04238 DUMP1("call ip_rb_threadVwaitObjCmd"); 04239 return ip_rb_threadVwaitObjCmd(clientData, interp, objc, objv); 04240 #else /* TCL_MAJOR_VERSION < 8 */ 04241 DUMP1("call ip_rb_threadVwaitCommand"); 04242 return ip_rb_threadVwaitCommand(clientData, interp, objc, objv); 04243 #endif 04244 } 04245 #endif 04246 04247 Tcl_Preserve(interp); 04248 #ifdef HAVE_NATIVETHREAD 04249 #ifndef RUBY_USE_NATIVE_THREAD 04250 if (!ruby_native_thread_p()) { 04251 rb_bug("cross-thread violation on ip_rbVwaitCommand()"); 04252 } 04253 #endif 04254 #endif 04255 04256 Tcl_ResetResult(interp); 04257 04258 if (objc != 2) { 04259 #ifdef Tcl_WrongNumArgs 04260 Tcl_WrongNumArgs(interp, 1, objv, "name"); 04261 #else 04262 thr_crit_bup = rb_thread_critical; 04263 rb_thread_critical = Qtrue; 04264 04265 #if TCL_MAJOR_VERSION >= 8 04266 /* nameString = Tcl_GetString(objv[0]); */ 04267 nameString = Tcl_GetStringFromObj(objv[0], &dummy); 04268 #else /* TCL_MAJOR_VERSION < 8 */ 04269 nameString = objv[0]; 04270 #endif 04271 Tcl_AppendResult(interp, "wrong number of arguments: should be \"", 04272 nameString, " name\"", (char *) NULL); 04273 04274 rb_thread_critical = thr_crit_bup; 04275 #endif 04276 04277 Tcl_Release(interp); 04278 return TCL_ERROR; 04279 } 04280 04281 thr_crit_bup = rb_thread_critical; 04282 rb_thread_critical = Qtrue; 04283 04284 #if TCL_MAJOR_VERSION >= 8 04285 Tcl_IncrRefCount(objv[1]); 04286 /* nameString = Tcl_GetString(objv[1]); */ 04287 nameString = Tcl_GetStringFromObj(objv[1], &dummy); 04288 #else /* TCL_MAJOR_VERSION < 8 */ 04289 nameString = objv[1]; 04290 #endif 04291 04292 /* 04293 if (Tcl_TraceVar(interp, nameString, 04294 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, 04295 VwaitVarProc, (ClientData) &done) != TCL_OK) { 04296 return TCL_ERROR; 04297 } 04298 */ 04299 ret = Tcl_TraceVar(interp, nameString, 04300 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, 04301 VwaitVarProc, (ClientData) &done); 04302 04303 rb_thread_critical = thr_crit_bup; 04304 04305 if (ret != TCL_OK) { 04306 #if TCL_MAJOR_VERSION >= 8 04307 Tcl_DecrRefCount(objv[1]); 04308 #endif 04309 Tcl_Release(interp); 04310 return TCL_ERROR; 04311 } 04312 04313 done = 0; 04314 04315 foundEvent = RTEST(lib_eventloop_launcher(/* not check root-widget */0, 04316 0, &done, interp)); 04317 04318 thr_crit_bup = rb_thread_critical; 04319 rb_thread_critical = Qtrue; 04320 04321 Tcl_UntraceVar(interp, nameString, 04322 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, 04323 VwaitVarProc, (ClientData) &done); 04324 04325 rb_thread_critical = thr_crit_bup; 04326 04327 /* exception check */ 04328 if (!NIL_P(rbtk_pending_exception)) { 04329 #if TCL_MAJOR_VERSION >= 8 04330 Tcl_DecrRefCount(objv[1]); 04331 #endif 04332 Tcl_Release(interp); 04333 04334 /* 04335 if (rb_obj_is_kind_of(rbtk_pending_exception, rb_eSystemExit)) { 04336 */ 04337 if (rb_obj_is_kind_of(rbtk_pending_exception, rb_eSystemExit) 04338 || rb_obj_is_kind_of(rbtk_pending_exception, rb_eInterrupt)) { 04339 return TCL_RETURN; 04340 } else{ 04341 return TCL_ERROR; 04342 } 04343 } 04344 04345 /* trap check */ 04346 #ifdef RUBY_VM 04347 if (rb_thread_check_trap_pending()) { 04348 #else 04349 if (rb_trap_pending) { 04350 #endif 04351 #if TCL_MAJOR_VERSION >= 8 04352 Tcl_DecrRefCount(objv[1]); 04353 #endif 04354 Tcl_Release(interp); 04355 04356 return TCL_RETURN; 04357 } 04358 04359 /* 04360 * Clear out the interpreter's result, since it may have been set 04361 * by event handlers. 04362 */ 04363 04364 Tcl_ResetResult(interp); 04365 if (!foundEvent) { 04366 thr_crit_bup = rb_thread_critical; 04367 rb_thread_critical = Qtrue; 04368 04369 Tcl_AppendResult(interp, "can't wait for variable \"", nameString, 04370 "\": would wait forever", (char *) NULL); 04371 04372 rb_thread_critical = thr_crit_bup; 04373 04374 #if TCL_MAJOR_VERSION >= 8 04375 Tcl_DecrRefCount(objv[1]); 04376 #endif 04377 Tcl_Release(interp); 04378 return TCL_ERROR; 04379 } 04380 04381 #if TCL_MAJOR_VERSION >= 8 04382 Tcl_DecrRefCount(objv[1]); 04383 #endif 04384 Tcl_Release(interp); 04385 return TCL_OK; 04386 } 04387 04388 04389 /**************************/ 04390 /* based on tkCmd.c */ 04391 /**************************/ 04392 #if TCL_MAJOR_VERSION >= 8 04393 static char *WaitVariableProc _((ClientData, Tcl_Interp *, 04394 CONST84 char *,CONST84 char *, int)); 04395 static char * 04396 WaitVariableProc(clientData, interp, name1, name2, flags) 04397 ClientData clientData; /* Pointer to integer to set to 1. */ 04398 Tcl_Interp *interp; /* Interpreter containing variable. */ 04399 CONST84 char *name1; /* Name of variable. */ 04400 CONST84 char *name2; /* Second part of variable name. */ 04401 int flags; /* Information about what happened. */ 04402 #else /* TCL_MAJOR_VERSION < 8 */ 04403 static char *WaitVariableProc _((ClientData, Tcl_Interp *, 04404 char *, char *, int)); 04405 static char * 04406 WaitVariableProc(clientData, interp, name1, name2, flags) 04407 ClientData clientData; /* Pointer to integer to set to 1. */ 04408 Tcl_Interp *interp; /* Interpreter containing variable. */ 04409 char *name1; /* Name of variable. */ 04410 char *name2; /* Second part of variable name. */ 04411 int flags; /* Information about what happened. */ 04412 #endif 04413 { 04414 int *donePtr = (int *) clientData; 04415 04416 *donePtr = 1; 04417 return (char *) NULL; 04418 } 04419 04420 static void WaitVisibilityProc _((ClientData, XEvent *)); 04421 static void 04422 WaitVisibilityProc(clientData, eventPtr) 04423 ClientData clientData; /* Pointer to integer to set to 1. */ 04424 XEvent *eventPtr; /* Information about event (not used). */ 04425 { 04426 int *donePtr = (int *) clientData; 04427 04428 if (eventPtr->type == VisibilityNotify) { 04429 *donePtr = 1; 04430 } 04431 if (eventPtr->type == DestroyNotify) { 04432 *donePtr = 2; 04433 } 04434 } 04435 04436 static void WaitWindowProc _((ClientData, XEvent *)); 04437 static void 04438 WaitWindowProc(clientData, eventPtr) 04439 ClientData clientData; /* Pointer to integer to set to 1. */ 04440 XEvent *eventPtr; /* Information about event. */ 04441 { 04442 int *donePtr = (int *) clientData; 04443 04444 if (eventPtr->type == DestroyNotify) { 04445 *donePtr = 1; 04446 } 04447 } 04448 04449 #if TCL_MAJOR_VERSION >= 8 04450 static int 04451 ip_rbTkWaitObjCmd(clientData, interp, objc, objv) 04452 ClientData clientData; 04453 Tcl_Interp *interp; 04454 int objc; 04455 Tcl_Obj *CONST objv[]; 04456 #else /* TCL_MAJOR_VERSION < 8 */ 04457 static int 04458 ip_rbTkWaitCommand(clientData, interp, objc, objv) 04459 ClientData clientData; 04460 Tcl_Interp *interp; 04461 int objc; 04462 char *objv[]; 04463 #endif 04464 { 04465 Tk_Window tkwin = (Tk_Window) clientData; 04466 Tk_Window window; 04467 int done, index; 04468 static CONST char *optionStrings[] = { "variable", "visibility", "window", 04469 (char *) NULL }; 04470 enum options { TKWAIT_VARIABLE, TKWAIT_VISIBILITY, TKWAIT_WINDOW }; 04471 char *nameString; 04472 int ret, dummy; 04473 int thr_crit_bup; 04474 04475 DUMP1("Ruby's 'tkwait' is called"); 04476 if (interp == (Tcl_Interp*)NULL) { 04477 rbtk_pending_exception = rb_exc_new2(rb_eRuntimeError, 04478 "IP is deleted"); 04479 return TCL_ERROR; 04480 } 04481 04482 #if 0 04483 if (!rb_thread_alone() 04484 && eventloop_thread != Qnil 04485 && eventloop_thread != rb_thread_current()) { 04486 #if TCL_MAJOR_VERSION >= 8 04487 DUMP1("call ip_rb_threadTkWaitObjCmd"); 04488 return ip_rb_threadTkWaitObjCmd((ClientData)tkwin, interp, objc, objv); 04489 #else /* TCL_MAJOR_VERSION < 8 */ 04490 DUMP1("call ip_rb_threadTkWaitCommand"); 04491 return ip_rb_threadTkWwaitCommand((ClientData)tkwin, interp, objc, objv); 04492 #endif 04493 } 04494 #endif 04495 04496 Tcl_Preserve(interp); 04497 Tcl_ResetResult(interp); 04498 04499 if (objc != 3) { 04500 #ifdef Tcl_WrongNumArgs 04501 Tcl_WrongNumArgs(interp, 1, objv, "variable|visibility|window name"); 04502 #else 04503 thr_crit_bup = rb_thread_critical; 04504 rb_thread_critical = Qtrue; 04505 04506 #if TCL_MAJOR_VERSION >= 8 04507 Tcl_AppendResult(interp, "wrong number of arguments: should be \"", 04508 Tcl_GetStringFromObj(objv[0], &dummy), 04509 " variable|visibility|window name\"", 04510 (char *) NULL); 04511 #else /* TCL_MAJOR_VERSION < 8 */ 04512 Tcl_AppendResult(interp, "wrong number of arguments: should be \"", 04513 objv[0], " variable|visibility|window name\"", 04514 (char *) NULL); 04515 #endif 04516 04517 rb_thread_critical = thr_crit_bup; 04518 #endif 04519 04520 Tcl_Release(interp); 04521 return TCL_ERROR; 04522 } 04523 04524 #if TCL_MAJOR_VERSION >= 8 04525 thr_crit_bup = rb_thread_critical; 04526 rb_thread_critical = Qtrue; 04527 04528 /* 04529 if (Tcl_GetIndexFromObj(interp, objv[1], 04530 (CONST84 char **)optionStrings, 04531 "option", 0, &index) != TCL_OK) { 04532 return TCL_ERROR; 04533 } 04534 */ 04535 ret = Tcl_GetIndexFromObj(interp, objv[1], 04536 (CONST84 char **)optionStrings, 04537 "option", 0, &index); 04538 04539 rb_thread_critical = thr_crit_bup; 04540 04541 if (ret != TCL_OK) { 04542 Tcl_Release(interp); 04543 return TCL_ERROR; 04544 } 04545 #else /* TCL_MAJOR_VERSION < 8 */ 04546 { 04547 int c = objv[1][0]; 04548 size_t length = strlen(objv[1]); 04549 04550 if ((c == 'v') && (strncmp(objv[1], "variable", length) == 0) 04551 && (length >= 2)) { 04552 index = TKWAIT_VARIABLE; 04553 } else if ((c == 'v') && (strncmp(objv[1], "visibility", length) == 0) 04554 && (length >= 2)) { 04555 index = TKWAIT_VISIBILITY; 04556 } else if ((c == 'w') && (strncmp(objv[1], "window", length) == 0)) { 04557 index = TKWAIT_WINDOW; 04558 } else { 04559 Tcl_AppendResult(interp, "bad option \"", objv[1], 04560 "\": must be variable, visibility, or window", 04561 (char *) NULL); 04562 Tcl_Release(interp); 04563 return TCL_ERROR; 04564 } 04565 } 04566 #endif 04567 04568 thr_crit_bup = rb_thread_critical; 04569 rb_thread_critical = Qtrue; 04570 04571 #if TCL_MAJOR_VERSION >= 8 04572 Tcl_IncrRefCount(objv[2]); 04573 /* nameString = Tcl_GetString(objv[2]); */ 04574 nameString = Tcl_GetStringFromObj(objv[2], &dummy); 04575 #else /* TCL_MAJOR_VERSION < 8 */ 04576 nameString = objv[2]; 04577 #endif 04578 04579 rb_thread_critical = thr_crit_bup; 04580 04581 switch ((enum options) index) { 04582 case TKWAIT_VARIABLE: 04583 thr_crit_bup = rb_thread_critical; 04584 rb_thread_critical = Qtrue; 04585 /* 04586 if (Tcl_TraceVar(interp, nameString, 04587 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, 04588 WaitVariableProc, (ClientData) &done) != TCL_OK) { 04589 return TCL_ERROR; 04590 } 04591 */ 04592 ret = Tcl_TraceVar(interp, nameString, 04593 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, 04594 WaitVariableProc, (ClientData) &done); 04595 04596 rb_thread_critical = thr_crit_bup; 04597 04598 if (ret != TCL_OK) { 04599 #if TCL_MAJOR_VERSION >= 8 04600 Tcl_DecrRefCount(objv[2]); 04601 #endif 04602 Tcl_Release(interp); 04603 return TCL_ERROR; 04604 } 04605 04606 done = 0; 04607 /* lib_eventloop_core(check_rootwidget_flag, 0, &done); */ 04608 lib_eventloop_launcher(check_rootwidget_flag, 0, &done, interp); 04609 04610 thr_crit_bup = rb_thread_critical; 04611 rb_thread_critical = Qtrue; 04612 04613 Tcl_UntraceVar(interp, nameString, 04614 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, 04615 WaitVariableProc, (ClientData) &done); 04616 04617 #if TCL_MAJOR_VERSION >= 8 04618 Tcl_DecrRefCount(objv[2]); 04619 #endif 04620 04621 rb_thread_critical = thr_crit_bup; 04622 04623 /* exception check */ 04624 if (!NIL_P(rbtk_pending_exception)) { 04625 Tcl_Release(interp); 04626 04627 /* 04628 if (rb_obj_is_kind_of(rbtk_pending_exception, rb_eSystemExit)) { 04629 */ 04630 if (rb_obj_is_kind_of(rbtk_pending_exception, rb_eSystemExit) 04631 || rb_obj_is_kind_of(rbtk_pending_exception, rb_eInterrupt)) { 04632 return TCL_RETURN; 04633 } else{ 04634 return TCL_ERROR; 04635 } 04636 } 04637 04638 /* trap check */ 04639 #ifdef RUBY_VM 04640 if (rb_thread_check_trap_pending()) { 04641 #else 04642 if (rb_trap_pending) { 04643 #endif 04644 Tcl_Release(interp); 04645 04646 return TCL_RETURN; 04647 } 04648 04649 break; 04650 04651 case TKWAIT_VISIBILITY: 04652 thr_crit_bup = rb_thread_critical; 04653 rb_thread_critical = Qtrue; 04654 04655 /* This function works on the Tk eventloop thread only. */ 04656 if (!tk_stubs_init_p() || Tk_MainWindow(interp) == (Tk_Window)NULL) { 04657 window = NULL; 04658 } else { 04659 window = Tk_NameToWindow(interp, nameString, tkwin); 04660 } 04661 04662 if (window == NULL) { 04663 Tcl_AppendResult(interp, ": tkwait: ", 04664 "no main-window (not Tk application?)", 04665 (char*)NULL); 04666 rb_thread_critical = thr_crit_bup; 04667 #if TCL_MAJOR_VERSION >= 8 04668 Tcl_DecrRefCount(objv[2]); 04669 #endif 04670 Tcl_Release(interp); 04671 return TCL_ERROR; 04672 } 04673 04674 Tk_CreateEventHandler(window, 04675 VisibilityChangeMask|StructureNotifyMask, 04676 WaitVisibilityProc, (ClientData) &done); 04677 04678 rb_thread_critical = thr_crit_bup; 04679 04680 done = 0; 04681 /* lib_eventloop_core(check_rootwidget_flag, 0, &done); */ 04682 lib_eventloop_launcher(check_rootwidget_flag, 0, &done, interp); 04683 04684 /* exception check */ 04685 if (!NIL_P(rbtk_pending_exception)) { 04686 #if TCL_MAJOR_VERSION >= 8 04687 Tcl_DecrRefCount(objv[2]); 04688 #endif 04689 Tcl_Release(interp); 04690 04691 /* 04692 if (rb_obj_is_kind_of(rbtk_pending_exception, rb_eSystemExit)) { 04693 */ 04694 if (rb_obj_is_kind_of(rbtk_pending_exception, rb_eSystemExit) 04695 || rb_obj_is_kind_of(rbtk_pending_exception, rb_eInterrupt)) { 04696 return TCL_RETURN; 04697 } else{ 04698 return TCL_ERROR; 04699 } 04700 } 04701 04702 /* trap check */ 04703 #ifdef RUBY_VM 04704 if (rb_thread_check_trap_pending()) { 04705 #else 04706 if (rb_trap_pending) { 04707 #endif 04708 #if TCL_MAJOR_VERSION >= 8 04709 Tcl_DecrRefCount(objv[2]); 04710 #endif 04711 Tcl_Release(interp); 04712 04713 return TCL_RETURN; 04714 } 04715 04716 if (done != 1) { 04717 /* 04718 * Note that we do not delete the event handler because it 04719 * was deleted automatically when the window was destroyed. 04720 */ 04721 thr_crit_bup = rb_thread_critical; 04722 rb_thread_critical = Qtrue; 04723 04724 Tcl_ResetResult(interp); 04725 Tcl_AppendResult(interp, "window \"", nameString, 04726 "\" was deleted before its visibility changed", 04727 (char *) NULL); 04728 04729 rb_thread_critical = thr_crit_bup; 04730 04731 #if TCL_MAJOR_VERSION >= 8 04732 Tcl_DecrRefCount(objv[2]); 04733 #endif 04734 Tcl_Release(interp); 04735 return TCL_ERROR; 04736 } 04737 04738 thr_crit_bup = rb_thread_critical; 04739 rb_thread_critical = Qtrue; 04740 04741 #if TCL_MAJOR_VERSION >= 8 04742 Tcl_DecrRefCount(objv[2]); 04743 #endif 04744 04745 Tk_DeleteEventHandler(window, 04746 VisibilityChangeMask|StructureNotifyMask, 04747 WaitVisibilityProc, (ClientData) &done); 04748 04749 rb_thread_critical = thr_crit_bup; 04750 04751 break; 04752 04753 case TKWAIT_WINDOW: 04754 thr_crit_bup = rb_thread_critical; 04755 rb_thread_critical = Qtrue; 04756 04757 /* This function works on the Tk eventloop thread only. */ 04758 if (!tk_stubs_init_p() || Tk_MainWindow(interp) == (Tk_Window)NULL) { 04759 window = NULL; 04760 } else { 04761 window = Tk_NameToWindow(interp, nameString, tkwin); 04762 } 04763 04764 #if TCL_MAJOR_VERSION >= 8 04765 Tcl_DecrRefCount(objv[2]); 04766 #endif 04767 04768 if (window == NULL) { 04769 Tcl_AppendResult(interp, ": tkwait: ", 04770 "no main-window (not Tk application?)", 04771 (char*)NULL); 04772 rb_thread_critical = thr_crit_bup; 04773 Tcl_Release(interp); 04774 return TCL_ERROR; 04775 } 04776 04777 Tk_CreateEventHandler(window, StructureNotifyMask, 04778 WaitWindowProc, (ClientData) &done); 04779 04780 rb_thread_critical = thr_crit_bup; 04781 04782 done = 0; 04783 /* lib_eventloop_core(check_rootwidget_flag, 0, &done); */ 04784 lib_eventloop_launcher(check_rootwidget_flag, 0, &done, interp); 04785 04786 /* exception check */ 04787 if (!NIL_P(rbtk_pending_exception)) { 04788 Tcl_Release(interp); 04789 04790 /* 04791 if (rb_obj_is_kind_of(rbtk_pending_exception, rb_eSystemExit)) { 04792 */ 04793 if (rb_obj_is_kind_of(rbtk_pending_exception, rb_eSystemExit) 04794 || rb_obj_is_kind_of(rbtk_pending_exception, rb_eInterrupt)) { 04795 return TCL_RETURN; 04796 } else{ 04797 return TCL_ERROR; 04798 } 04799 } 04800 04801 /* trap check */ 04802 #ifdef RUBY_VM 04803 if (rb_thread_check_trap_pending()) { 04804 #else 04805 if (rb_trap_pending) { 04806 #endif 04807 Tcl_Release(interp); 04808 04809 return TCL_RETURN; 04810 } 04811 04812 /* 04813 * Note: there's no need to delete the event handler. It was 04814 * deleted automatically when the window was destroyed. 04815 */ 04816 break; 04817 } 04818 04819 /* 04820 * Clear out the interpreter's result, since it may have been set 04821 * by event handlers. 04822 */ 04823 04824 Tcl_ResetResult(interp); 04825 Tcl_Release(interp); 04826 return TCL_OK; 04827 } 04828 04829 /****************************/ 04830 /* vwait/tkwait with thread */ 04831 /****************************/ 04832 struct th_vwait_param { 04833 VALUE thread; 04834 int done; 04835 }; 04836 04837 #if TCL_MAJOR_VERSION >= 8 04838 static char *rb_threadVwaitProc _((ClientData, Tcl_Interp *, 04839 CONST84 char *,CONST84 char *, int)); 04840 static char * 04841 rb_threadVwaitProc(clientData, interp, name1, name2, flags) 04842 ClientData clientData; /* Pointer to integer to set to 1. */ 04843 Tcl_Interp *interp; /* Interpreter containing variable. */ 04844 CONST84 char *name1; /* Name of variable. */ 04845 CONST84 char *name2; /* Second part of variable name. */ 04846 int flags; /* Information about what happened. */ 04847 #else /* TCL_MAJOR_VERSION < 8 */ 04848 static char *rb_threadVwaitProc _((ClientData, Tcl_Interp *, 04849 char *, char *, int)); 04850 static char * 04851 rb_threadVwaitProc(clientData, interp, name1, name2, flags) 04852 ClientData clientData; /* Pointer to integer to set to 1. */ 04853 Tcl_Interp *interp; /* Interpreter containing variable. */ 04854 char *name1; /* Name of variable. */ 04855 char *name2; /* Second part of variable name. */ 04856 int flags; /* Information about what happened. */ 04857 #endif 04858 { 04859 struct th_vwait_param *param = (struct th_vwait_param *) clientData; 04860 04861 if (flags & (TCL_INTERP_DESTROYED | TCL_TRACE_DESTROYED)) { 04862 param->done = -1; 04863 } else { 04864 param->done = 1; 04865 } 04866 if (param->done != 0) rb_thread_wakeup(param->thread); 04867 04868 return (char *)NULL; 04869 } 04870 04871 #define TKWAIT_MODE_VISIBILITY 1 04872 #define TKWAIT_MODE_DESTROY 2 04873 04874 static void rb_threadWaitVisibilityProc _((ClientData, XEvent *)); 04875 static void 04876 rb_threadWaitVisibilityProc(clientData, eventPtr) 04877 ClientData clientData; /* Pointer to integer to set to 1. */ 04878 XEvent *eventPtr; /* Information about event (not used). */ 04879 { 04880 struct th_vwait_param *param = (struct th_vwait_param *) clientData; 04881 04882 if (eventPtr->type == VisibilityNotify) { 04883 param->done = TKWAIT_MODE_VISIBILITY; 04884 } 04885 if (eventPtr->type == DestroyNotify) { 04886 param->done = TKWAIT_MODE_DESTROY; 04887 } 04888 if (param->done != 0) rb_thread_wakeup(param->thread); 04889 } 04890 04891 static void rb_threadWaitWindowProc _((ClientData, XEvent *)); 04892 static void 04893 rb_threadWaitWindowProc(clientData, eventPtr) 04894 ClientData clientData; /* Pointer to integer to set to 1. */ 04895 XEvent *eventPtr; /* Information about event. */ 04896 { 04897 struct th_vwait_param *param = (struct th_vwait_param *) clientData; 04898 04899 if (eventPtr->type == DestroyNotify) { 04900 param->done = TKWAIT_MODE_DESTROY; 04901 } 04902 if (param->done != 0) rb_thread_wakeup(param->thread); 04903 } 04904 04905 #if TCL_MAJOR_VERSION >= 8 04906 static int 04907 ip_rb_threadVwaitObjCmd(clientData, interp, objc, objv) 04908 ClientData clientData; 04909 Tcl_Interp *interp; 04910 int objc; 04911 Tcl_Obj *CONST objv[]; 04912 #else /* TCL_MAJOR_VERSION < 8 */ 04913 static int 04914 ip_rb_threadVwaitCommand(clientData, interp, objc, objv) 04915 ClientData clientData; /* Not used */ 04916 Tcl_Interp *interp; 04917 int objc; 04918 char *objv[]; 04919 #endif 04920 { 04921 struct th_vwait_param *param; 04922 char *nameString; 04923 int ret, dummy; 04924 int thr_crit_bup; 04925 volatile VALUE current_thread = rb_thread_current(); 04926 struct timeval t; 04927 04928 DUMP1("Ruby's 'thread_vwait' is called"); 04929 if (interp == (Tcl_Interp*)NULL) { 04930 rbtk_pending_exception = rb_exc_new2(rb_eRuntimeError, 04931 "IP is deleted"); 04932 return TCL_ERROR; 04933 } 04934 04935 if (rb_thread_alone() || eventloop_thread == current_thread) { 04936 #if TCL_MAJOR_VERSION >= 8 04937 DUMP1("call ip_rbVwaitObjCmd"); 04938 return ip_rbVwaitObjCmd(clientData, interp, objc, objv); 04939 #else /* TCL_MAJOR_VERSION < 8 */ 04940 DUMP1("call ip_rbVwaitCommand"); 04941 return ip_rbVwaitCommand(clientData, interp, objc, objv); 04942 #endif 04943 } 04944 04945 Tcl_Preserve(interp); 04946 Tcl_ResetResult(interp); 04947 04948 if (objc != 2) { 04949 #ifdef Tcl_WrongNumArgs 04950 Tcl_WrongNumArgs(interp, 1, objv, "name"); 04951 #else 04952 thr_crit_bup = rb_thread_critical; 04953 rb_thread_critical = Qtrue; 04954 04955 #if TCL_MAJOR_VERSION >= 8 04956 /* nameString = Tcl_GetString(objv[0]); */ 04957 nameString = Tcl_GetStringFromObj(objv[0], &dummy); 04958 #else /* TCL_MAJOR_VERSION < 8 */ 04959 nameString = objv[0]; 04960 #endif 04961 Tcl_AppendResult(interp, "wrong number of arguments: should be \"", 04962 nameString, " name\"", (char *) NULL); 04963 04964 rb_thread_critical = thr_crit_bup; 04965 #endif 04966 04967 Tcl_Release(interp); 04968 return TCL_ERROR; 04969 } 04970 04971 #if TCL_MAJOR_VERSION >= 8 04972 Tcl_IncrRefCount(objv[1]); 04973 /* nameString = Tcl_GetString(objv[1]); */ 04974 nameString = Tcl_GetStringFromObj(objv[1], &dummy); 04975 #else /* TCL_MAJOR_VERSION < 8 */ 04976 nameString = objv[1]; 04977 #endif 04978 thr_crit_bup = rb_thread_critical; 04979 rb_thread_critical = Qtrue; 04980 04981 /* param = (struct th_vwait_param *)Tcl_Alloc(sizeof(struct th_vwait_param)); */ 04982 param = (struct th_vwait_param *)ckalloc(sizeof(struct th_vwait_param)); 04983 #if 1 /* use Tcl_Preserve/Release */ 04984 Tcl_Preserve((ClientData)param); 04985 #endif 04986 param->thread = current_thread; 04987 param->done = 0; 04988 04989 /* 04990 if (Tcl_TraceVar(interp, nameString, 04991 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, 04992 rb_threadVwaitProc, (ClientData) param) != TCL_OK) { 04993 return TCL_ERROR; 04994 } 04995 */ 04996 ret = Tcl_TraceVar(interp, nameString, 04997 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, 04998 rb_threadVwaitProc, (ClientData) param); 04999 05000 rb_thread_critical = thr_crit_bup; 05001 05002 if (ret != TCL_OK) { 05003 #if 0 /* use Tcl_EventuallyFree */ 05004 Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ 05005 #else 05006 #if 1 /* use Tcl_Preserve/Release */ 05007 Tcl_Release((ClientData)param); 05008 #else 05009 /* Tcl_Free((char *)param); */ 05010 ckfree((char *)param); 05011 #endif 05012 #endif 05013 05014 #if TCL_MAJOR_VERSION >= 8 05015 Tcl_DecrRefCount(objv[1]); 05016 #endif 05017 Tcl_Release(interp); 05018 return TCL_ERROR; 05019 } 05020 05021 t.tv_sec = 0; 05022 t.tv_usec = (long)((EVENT_HANDLER_TIMEOUT)*1000.0); 05023 05024 while(!param->done) { 05025 /* rb_thread_stop(); */ 05026 /* rb_thread_sleep_forever(); */ 05027 rb_thread_wait_for(t); 05028 if (NIL_P(eventloop_thread)) { 05029 break; 05030 } 05031 } 05032 05033 thr_crit_bup = rb_thread_critical; 05034 rb_thread_critical = Qtrue; 05035 05036 if (param->done > 0) { 05037 Tcl_UntraceVar(interp, nameString, 05038 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, 05039 rb_threadVwaitProc, (ClientData) param); 05040 } 05041 05042 #if 0 /* use Tcl_EventuallyFree */ 05043 Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ 05044 #else 05045 #if 1 /* use Tcl_Preserve/Release */ 05046 Tcl_Release((ClientData)param); 05047 #else 05048 /* Tcl_Free((char *)param); */ 05049 ckfree((char *)param); 05050 #endif 05051 #endif 05052 05053 rb_thread_critical = thr_crit_bup; 05054 05055 #if TCL_MAJOR_VERSION >= 8 05056 Tcl_DecrRefCount(objv[1]); 05057 #endif 05058 Tcl_Release(interp); 05059 return TCL_OK; 05060 } 05061 05062 #if TCL_MAJOR_VERSION >= 8 05063 static int 05064 ip_rb_threadTkWaitObjCmd(clientData, interp, objc, objv) 05065 ClientData clientData; 05066 Tcl_Interp *interp; 05067 int objc; 05068 Tcl_Obj *CONST objv[]; 05069 #else /* TCL_MAJOR_VERSION < 8 */ 05070 static int 05071 ip_rb_threadTkWaitCommand(clientData, interp, objc, objv) 05072 ClientData clientData; 05073 Tcl_Interp *interp; 05074 int objc; 05075 char *objv[]; 05076 #endif 05077 { 05078 struct th_vwait_param *param; 05079 Tk_Window tkwin = (Tk_Window) clientData; 05080 Tk_Window window; 05081 int index; 05082 static CONST char *optionStrings[] = { "variable", "visibility", "window", 05083 (char *) NULL }; 05084 enum options { TKWAIT_VARIABLE, TKWAIT_VISIBILITY, TKWAIT_WINDOW }; 05085 char *nameString; 05086 int ret, dummy; 05087 int thr_crit_bup; 05088 volatile VALUE current_thread = rb_thread_current(); 05089 struct timeval t; 05090 05091 DUMP1("Ruby's 'thread_tkwait' is called"); 05092 if (interp == (Tcl_Interp*)NULL) { 05093 rbtk_pending_exception = rb_exc_new2(rb_eRuntimeError, 05094 "IP is deleted"); 05095 return TCL_ERROR; 05096 } 05097 05098 if (rb_thread_alone() || eventloop_thread == current_thread) { 05099 #if TCL_MAJOR_VERSION >= 8 05100 DUMP1("call ip_rbTkWaitObjCmd"); 05101 DUMP2("eventloop_thread %lx", eventloop_thread); 05102 DUMP2("current_thread %lx", current_thread); 05103 return ip_rbTkWaitObjCmd(clientData, interp, objc, objv); 05104 #else /* TCL_MAJOR_VERSION < 8 */ 05105 DUMP1("call rb_VwaitCommand"); 05106 return ip_rbTkWaitCommand(clientData, interp, objc, objv); 05107 #endif 05108 } 05109 05110 Tcl_Preserve(interp); 05111 Tcl_Preserve(tkwin); 05112 05113 Tcl_ResetResult(interp); 05114 05115 if (objc != 3) { 05116 #ifdef Tcl_WrongNumArgs 05117 Tcl_WrongNumArgs(interp, 1, objv, "variable|visibility|window name"); 05118 #else 05119 thr_crit_bup = rb_thread_critical; 05120 rb_thread_critical = Qtrue; 05121 05122 #if TCL_MAJOR_VERSION >= 8 05123 Tcl_AppendResult(interp, "wrong number of arguments: should be \"", 05124 Tcl_GetStringFromObj(objv[0], &dummy), 05125 " variable|visibility|window name\"", 05126 (char *) NULL); 05127 #else /* TCL_MAJOR_VERSION < 8 */ 05128 Tcl_AppendResult(interp, "wrong number of arguments: should be \"", 05129 objv[0], " variable|visibility|window name\"", 05130 (char *) NULL); 05131 #endif 05132 05133 rb_thread_critical = thr_crit_bup; 05134 #endif 05135 05136 Tcl_Release(tkwin); 05137 Tcl_Release(interp); 05138 return TCL_ERROR; 05139 } 05140 05141 #if TCL_MAJOR_VERSION >= 8 05142 thr_crit_bup = rb_thread_critical; 05143 rb_thread_critical = Qtrue; 05144 /* 05145 if (Tcl_GetIndexFromObj(interp, objv[1], 05146 (CONST84 char **)optionStrings, 05147 "option", 0, &index) != TCL_OK) { 05148 return TCL_ERROR; 05149 } 05150 */ 05151 ret = Tcl_GetIndexFromObj(interp, objv[1], 05152 (CONST84 char **)optionStrings, 05153 "option", 0, &index); 05154 05155 rb_thread_critical = thr_crit_bup; 05156 05157 if (ret != TCL_OK) { 05158 Tcl_Release(tkwin); 05159 Tcl_Release(interp); 05160 return TCL_ERROR; 05161 } 05162 #else /* TCL_MAJOR_VERSION < 8 */ 05163 { 05164 int c = objv[1][0]; 05165 size_t length = strlen(objv[1]); 05166 05167 if ((c == 'v') && (strncmp(objv[1], "variable", length) == 0) 05168 && (length >= 2)) { 05169 index = TKWAIT_VARIABLE; 05170 } else if ((c == 'v') && (strncmp(objv[1], "visibility", length) == 0) 05171 && (length >= 2)) { 05172 index = TKWAIT_VISIBILITY; 05173 } else if ((c == 'w') && (strncmp(objv[1], "window", length) == 0)) { 05174 index = TKWAIT_WINDOW; 05175 } else { 05176 Tcl_AppendResult(interp, "bad option \"", objv[1], 05177 "\": must be variable, visibility, or window", 05178 (char *) NULL); 05179 Tcl_Release(tkwin); 05180 Tcl_Release(interp); 05181 return TCL_ERROR; 05182 } 05183 } 05184 #endif 05185 05186 thr_crit_bup = rb_thread_critical; 05187 rb_thread_critical = Qtrue; 05188 05189 #if TCL_MAJOR_VERSION >= 8 05190 Tcl_IncrRefCount(objv[2]); 05191 /* nameString = Tcl_GetString(objv[2]); */ 05192 nameString = Tcl_GetStringFromObj(objv[2], &dummy); 05193 #else /* TCL_MAJOR_VERSION < 8 */ 05194 nameString = objv[2]; 05195 #endif 05196 05197 /* param = (struct th_vwait_param *)Tcl_Alloc(sizeof(struct th_vwait_param)); */ 05198 param = (struct th_vwait_param *)ckalloc(sizeof(struct th_vwait_param)); 05199 #if 1 /* use Tcl_Preserve/Release */ 05200 Tcl_Preserve((ClientData)param); 05201 #endif 05202 param->thread = current_thread; 05203 param->done = 0; 05204 05205 rb_thread_critical = thr_crit_bup; 05206 05207 switch ((enum options) index) { 05208 case TKWAIT_VARIABLE: 05209 thr_crit_bup = rb_thread_critical; 05210 rb_thread_critical = Qtrue; 05211 /* 05212 if (Tcl_TraceVar(interp, nameString, 05213 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, 05214 rb_threadVwaitProc, (ClientData) param) != TCL_OK) { 05215 return TCL_ERROR; 05216 } 05217 */ 05218 ret = Tcl_TraceVar(interp, nameString, 05219 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, 05220 rb_threadVwaitProc, (ClientData) param); 05221 05222 rb_thread_critical = thr_crit_bup; 05223 05224 if (ret != TCL_OK) { 05225 #if 0 /* use Tcl_EventuallyFree */ 05226 Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ 05227 #else 05228 #if 1 /* use Tcl_Preserve/Release */ 05229 Tcl_Release(param); 05230 #else 05231 /* Tcl_Free((char *)param); */ 05232 ckfree((char *)param); 05233 #endif 05234 #endif 05235 05236 #if TCL_MAJOR_VERSION >= 8 05237 Tcl_DecrRefCount(objv[2]); 05238 #endif 05239 05240 Tcl_Release(tkwin); 05241 Tcl_Release(interp); 05242 return TCL_ERROR; 05243 } 05244 05245 t.tv_sec = 0; 05246 t.tv_usec = (long)((EVENT_HANDLER_TIMEOUT)*1000.0); 05247 05248 while(!param->done) { 05249 /* rb_thread_stop(); */ 05250 /* rb_thread_sleep_forever(); */ 05251 rb_thread_wait_for(t); 05252 if (NIL_P(eventloop_thread)) { 05253 break; 05254 } 05255 } 05256 05257 thr_crit_bup = rb_thread_critical; 05258 rb_thread_critical = Qtrue; 05259 05260 if (param->done > 0) { 05261 Tcl_UntraceVar(interp, nameString, 05262 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, 05263 rb_threadVwaitProc, (ClientData) param); 05264 } 05265 05266 #if TCL_MAJOR_VERSION >= 8 05267 Tcl_DecrRefCount(objv[2]); 05268 #endif 05269 05270 rb_thread_critical = thr_crit_bup; 05271 05272 break; 05273 05274 case TKWAIT_VISIBILITY: 05275 thr_crit_bup = rb_thread_critical; 05276 rb_thread_critical = Qtrue; 05277 05278 #if 0 /* variable 'tkwin' must keep the token of MainWindow */ 05279 if (!tk_stubs_init_p() || Tk_MainWindow(interp) == (Tk_Window)NULL) { 05280 window = NULL; 05281 } else { 05282 window = Tk_NameToWindow(interp, nameString, tkwin); 05283 } 05284 #else 05285 if (!tk_stubs_init_p() || tkwin == (Tk_Window)NULL) { 05286 window = NULL; 05287 } else { 05288 /* Tk_NameToWindow() returns right token on non-eventloop thread */ 05289 Tcl_CmdInfo info; 05290 if (Tcl_GetCommandInfo(interp, ".", &info)) { /* check root */ 05291 window = Tk_NameToWindow(interp, nameString, tkwin); 05292 } else { 05293 window = NULL; 05294 } 05295 } 05296 #endif 05297 05298 if (window == NULL) { 05299 Tcl_AppendResult(interp, ": thread_tkwait: ", 05300 "no main-window (not Tk application?)", 05301 (char*)NULL); 05302 05303 rb_thread_critical = thr_crit_bup; 05304 05305 #if 0 /* use Tcl_EventuallyFree */ 05306 Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ 05307 #else 05308 #if 1 /* use Tcl_Preserve/Release */ 05309 Tcl_Release(param); 05310 #else 05311 /* Tcl_Free((char *)param); */ 05312 ckfree((char *)param); 05313 #endif 05314 #endif 05315 05316 #if TCL_MAJOR_VERSION >= 8 05317 Tcl_DecrRefCount(objv[2]); 05318 #endif 05319 Tcl_Release(tkwin); 05320 Tcl_Release(interp); 05321 return TCL_ERROR; 05322 } 05323 Tcl_Preserve(window); 05324 05325 Tk_CreateEventHandler(window, 05326 VisibilityChangeMask|StructureNotifyMask, 05327 rb_threadWaitVisibilityProc, (ClientData) param); 05328 05329 rb_thread_critical = thr_crit_bup; 05330 05331 t.tv_sec = 0; 05332 t.tv_usec = (long)((EVENT_HANDLER_TIMEOUT)*1000.0); 05333 05334 while(param->done != TKWAIT_MODE_VISIBILITY) { 05335 if (param->done == TKWAIT_MODE_DESTROY) break; 05336 /* rb_thread_stop(); */ 05337 /* rb_thread_sleep_forever(); */ 05338 rb_thread_wait_for(t); 05339 if (NIL_P(eventloop_thread)) { 05340 break; 05341 } 05342 } 05343 05344 thr_crit_bup = rb_thread_critical; 05345 rb_thread_critical = Qtrue; 05346 05347 /* when a window is destroyed, no need to call Tk_DeleteEventHandler */ 05348 if (param->done != TKWAIT_MODE_DESTROY) { 05349 Tk_DeleteEventHandler(window, 05350 VisibilityChangeMask|StructureNotifyMask, 05351 rb_threadWaitVisibilityProc, 05352 (ClientData) param); 05353 } 05354 05355 if (param->done != 1) { 05356 Tcl_ResetResult(interp); 05357 Tcl_AppendResult(interp, "window \"", nameString, 05358 "\" was deleted before its visibility changed", 05359 (char *) NULL); 05360 05361 rb_thread_critical = thr_crit_bup; 05362 05363 Tcl_Release(window); 05364 05365 #if 0 /* use Tcl_EventuallyFree */ 05366 Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ 05367 #else 05368 #if 1 /* use Tcl_Preserve/Release */ 05369 Tcl_Release(param); 05370 #else 05371 /* Tcl_Free((char *)param); */ 05372 ckfree((char *)param); 05373 #endif 05374 #endif 05375 05376 #if TCL_MAJOR_VERSION >= 8 05377 Tcl_DecrRefCount(objv[2]); 05378 #endif 05379 05380 Tcl_Release(tkwin); 05381 Tcl_Release(interp); 05382 return TCL_ERROR; 05383 } 05384 05385 Tcl_Release(window); 05386 05387 #if TCL_MAJOR_VERSION >= 8 05388 Tcl_DecrRefCount(objv[2]); 05389 #endif 05390 05391 rb_thread_critical = thr_crit_bup; 05392 05393 break; 05394 05395 case TKWAIT_WINDOW: 05396 thr_crit_bup = rb_thread_critical; 05397 rb_thread_critical = Qtrue; 05398 05399 #if 0 /* variable 'tkwin' must keep the token of MainWindow */ 05400 if (!tk_stubs_init_p() || Tk_MainWindow(interp) == (Tk_Window)NULL) { 05401 window = NULL; 05402 } else { 05403 window = Tk_NameToWindow(interp, nameString, tkwin); 05404 } 05405 #else 05406 if (!tk_stubs_init_p() || tkwin == (Tk_Window)NULL) { 05407 window = NULL; 05408 } else { 05409 /* Tk_NameToWindow() returns right token on non-eventloop thread */ 05410 Tcl_CmdInfo info; 05411 if (Tcl_GetCommandInfo(interp, ".", &info)) { /* check root */ 05412 window = Tk_NameToWindow(interp, nameString, tkwin); 05413 } else { 05414 window = NULL; 05415 } 05416 } 05417 #endif 05418 05419 #if TCL_MAJOR_VERSION >= 8 05420 Tcl_DecrRefCount(objv[2]); 05421 #endif 05422 05423 if (window == NULL) { 05424 Tcl_AppendResult(interp, ": thread_tkwait: ", 05425 "no main-window (not Tk application?)", 05426 (char*)NULL); 05427 05428 rb_thread_critical = thr_crit_bup; 05429 05430 #if 0 /* use Tcl_EventuallyFree */ 05431 Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ 05432 #else 05433 #if 1 /* use Tcl_Preserve/Release */ 05434 Tcl_Release(param); 05435 #else 05436 /* Tcl_Free((char *)param); */ 05437 ckfree((char *)param); 05438 #endif 05439 #endif 05440 05441 Tcl_Release(tkwin); 05442 Tcl_Release(interp); 05443 return TCL_ERROR; 05444 } 05445 05446 Tcl_Preserve(window); 05447 05448 Tk_CreateEventHandler(window, StructureNotifyMask, 05449 rb_threadWaitWindowProc, (ClientData) param); 05450 05451 rb_thread_critical = thr_crit_bup; 05452 05453 t.tv_sec = 0; 05454 t.tv_usec = (long)((EVENT_HANDLER_TIMEOUT)*1000.0); 05455 05456 while(param->done != TKWAIT_MODE_DESTROY) { 05457 /* rb_thread_stop(); */ 05458 /* rb_thread_sleep_forever(); */ 05459 rb_thread_wait_for(t); 05460 if (NIL_P(eventloop_thread)) { 05461 break; 05462 } 05463 } 05464 05465 Tcl_Release(window); 05466 05467 /* when a window is destroyed, no need to call Tk_DeleteEventHandler 05468 thr_crit_bup = rb_thread_critical; 05469 rb_thread_critical = Qtrue; 05470 05471 Tk_DeleteEventHandler(window, StructureNotifyMask, 05472 rb_threadWaitWindowProc, (ClientData) param); 05473 05474 rb_thread_critical = thr_crit_bup; 05475 */ 05476 05477 break; 05478 } /* end of 'switch' statement */ 05479 05480 #if 0 /* use Tcl_EventuallyFree */ 05481 Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */ 05482 #else 05483 #if 1 /* use Tcl_Preserve/Release */ 05484 Tcl_Release((ClientData)param); 05485 #else 05486 /* Tcl_Free((char *)param); */ 05487 ckfree((char *)param); 05488 #endif 05489 #endif 05490 05491 /* 05492 * Clear out the interpreter's result, since it may have been set 05493 * by event handlers. 05494 */ 05495 05496 Tcl_ResetResult(interp); 05497 05498 Tcl_Release(tkwin); 05499 Tcl_Release(interp); 05500 return TCL_OK; 05501 } 05502 05503 static VALUE 05504 ip_thread_vwait(self, var) 05505 VALUE self; 05506 VALUE var; 05507 { 05508 VALUE argv[2]; 05509 volatile VALUE cmd_str = rb_str_new2("thread_vwait"); 05510 05511 argv[0] = cmd_str; 05512 argv[1] = var; 05513 05514 return ip_invoke_with_position(2, argv, self, TCL_QUEUE_TAIL); 05515 } 05516 05517 static VALUE 05518 ip_thread_tkwait(self, mode, target) 05519 VALUE self; 05520 VALUE mode; 05521 VALUE target; 05522 { 05523 VALUE argv[3]; 05524 volatile VALUE cmd_str = rb_str_new2("thread_tkwait"); 05525 05526 argv[0] = cmd_str; 05527 argv[1] = mode; 05528 argv[2] = target; 05529 05530 return ip_invoke_with_position(3, argv, self, TCL_QUEUE_TAIL); 05531 } 05532 05533 05534 /* delete slave interpreters */ 05535 #if TCL_MAJOR_VERSION >= 8 05536 static void 05537 delete_slaves(ip) 05538 Tcl_Interp *ip; 05539 { 05540 int thr_crit_bup; 05541 Tcl_Interp *slave; 05542 Tcl_Obj *slave_list, *elem; 05543 char *slave_name; 05544 int i, len; 05545 05546 DUMP1("delete slaves"); 05547 thr_crit_bup = rb_thread_critical; 05548 rb_thread_critical = Qtrue; 05549 05550 if (!Tcl_InterpDeleted(ip) && Tcl_Eval(ip, "interp slaves") == TCL_OK) { 05551 slave_list = Tcl_GetObjResult(ip); 05552 Tcl_IncrRefCount(slave_list); 05553 05554 if (Tcl_ListObjLength((Tcl_Interp*)NULL, slave_list, &len) == TCL_OK) { 05555 for(i = 0; i < len; i++) { 05556 Tcl_ListObjIndex((Tcl_Interp*)NULL, slave_list, i, &elem); 05557 05558 if (elem == (Tcl_Obj*)NULL) continue; 05559 05560 Tcl_IncrRefCount(elem); 05561 05562 /* get slave */ 05563 /* slave_name = Tcl_GetString(elem); */ 05564 slave_name = Tcl_GetStringFromObj(elem, (int*)NULL); 05565 DUMP2("delete slave:'%s'", slave_name); 05566 05567 Tcl_DecrRefCount(elem); 05568 05569 slave = Tcl_GetSlave(ip, slave_name); 05570 if (slave == (Tcl_Interp*)NULL) continue; 05571 05572 if (!Tcl_InterpDeleted(slave)) { 05573 /* call ip_finalize */ 05574 ip_finalize(slave); 05575 05576 Tcl_DeleteInterp(slave); 05577 /* Tcl_Release(slave); */ 05578 } 05579 } 05580 } 05581 05582 Tcl_DecrRefCount(slave_list); 05583 } 05584 05585 rb_thread_critical = thr_crit_bup; 05586 } 05587 #else /* TCL_MAJOR_VERSION < 8 */ 05588 static void 05589 delete_slaves(ip) 05590 Tcl_Interp *ip; 05591 { 05592 int thr_crit_bup; 05593 Tcl_Interp *slave; 05594 int argc; 05595 char **argv; 05596 char *slave_list; 05597 char *slave_name; 05598 int i, len; 05599 05600 DUMP1("delete slaves"); 05601 thr_crit_bup = rb_thread_critical; 05602 rb_thread_critical = Qtrue; 05603 05604 if (!Tcl_InterpDeleted(ip) && Tcl_Eval(ip, "interp slaves") == TCL_OK) { 05605 slave_list = ip->result; 05606 if (Tcl_SplitList((Tcl_Interp*)NULL, 05607 slave_list, &argc, &argv) == TCL_OK) { 05608 for(i = 0; i < argc; i++) { 05609 slave_name = argv[i]; 05610 05611 DUMP2("delete slave:'%s'", slave_name); 05612 05613 slave = Tcl_GetSlave(ip, slave_name); 05614 if (slave == (Tcl_Interp*)NULL) continue; 05615 05616 if (!Tcl_InterpDeleted(slave)) { 05617 /* call ip_finalize */ 05618 ip_finalize(slave); 05619 05620 Tcl_DeleteInterp(slave); 05621 } 05622 } 05623 } 05624 } 05625 05626 rb_thread_critical = thr_crit_bup; 05627 } 05628 #endif 05629 05630 05631 /* finalize operation */ 05632 static void 05633 #ifdef HAVE_PROTOTYPES 05634 lib_mark_at_exit(VALUE self) 05635 #else 05636 lib_mark_at_exit(self) 05637 VALUE self; 05638 #endif 05639 { 05640 at_exit = 1; 05641 } 05642 05643 static int 05644 #if TCL_MAJOR_VERSION >= 8 05645 #ifdef HAVE_PROTOTYPES 05646 ip_null_proc(ClientData clientData, Tcl_Interp *interp, 05647 int argc, Tcl_Obj *CONST argv[]) 05648 #else 05649 ip_null_proc(clientData, interp, argc, argv) 05650 ClientData clientData; 05651 Tcl_Interp *interp; 05652 int argc; 05653 Tcl_Obj *CONST argv[]; 05654 #endif 05655 #else /* TCL_MAJOR_VERSION < 8 */ 05656 #ifdef HAVE_PROTOTYPES 05657 ip_null_proc(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) 05658 #else 05659 ip_null_proc(clientData, interp, argc, argv) 05660 ClientData clientData; 05661 Tcl_Interp *interp; 05662 int argc; 05663 char *argv[]; 05664 #endif 05665 #endif 05666 { 05667 Tcl_ResetResult(interp); 05668 return TCL_OK; 05669 } 05670 05671 static void 05672 ip_finalize(ip) 05673 Tcl_Interp *ip; 05674 { 05675 Tcl_CmdInfo info; 05676 int thr_crit_bup; 05677 05678 VALUE rb_debug_bup, rb_verbose_bup; 05679 /* When ruby is exiting, printing debug messages in some callback 05680 operations from Tcl-IP sometimes cause SEGV. I don't know the 05681 reason. But I got SEGV when calling "rb_io_write(rb_stdout, ...)". 05682 So, in some part of this function, debug mode and verbose mode 05683 are disabled. If you know the reason, please fix it. 05684 -- Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) */ 05685 05686 DUMP1("start ip_finalize"); 05687 05688 if (ip == (Tcl_Interp*)NULL) { 05689 DUMP1("ip is NULL"); 05690 return; 05691 } 05692 05693 if (Tcl_InterpDeleted(ip)) { 05694 DUMP2("ip(%p) is already deleted", ip); 05695 return; 05696 } 05697 05698 #if TCL_NAMESPACE_DEBUG 05699 if (ip_null_namespace(ip)) { 05700 DUMP2("ip(%p) has null namespace", ip); 05701 return; 05702 } 05703 #endif 05704 05705 thr_crit_bup = rb_thread_critical; 05706 rb_thread_critical = Qtrue; 05707 05708 rb_debug_bup = ruby_debug; 05709 rb_verbose_bup = ruby_verbose; 05710 05711 Tcl_Preserve(ip); 05712 05713 /* delete slaves */ 05714 delete_slaves(ip); 05715 05716 /* shut off some connections from Tcl-proc to Ruby */ 05717 if (at_exit) { 05718 /* NOTE: Only when at exit. 05719 Because, ruby removes objects, which depends on the deleted 05720 interpreter, on some callback operations. 05721 It is important for GC. */ 05722 #if TCL_MAJOR_VERSION >= 8 05723 Tcl_CreateObjCommand(ip, "ruby", ip_null_proc, 05724 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); 05725 Tcl_CreateObjCommand(ip, "ruby_eval", ip_null_proc, 05726 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); 05727 Tcl_CreateObjCommand(ip, "ruby_cmd", ip_null_proc, 05728 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); 05729 #else /* TCL_MAJOR_VERSION < 8 */ 05730 Tcl_CreateCommand(ip, "ruby", ip_null_proc, 05731 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); 05732 Tcl_CreateCommand(ip, "ruby_eval", ip_null_proc, 05733 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); 05734 Tcl_CreateCommand(ip, "ruby_cmd", ip_null_proc, 05735 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); 05736 #endif 05737 /* 05738 rb_thread_critical = thr_crit_bup; 05739 return; 05740 */ 05741 } 05742 05743 /* delete root widget */ 05744 #ifdef RUBY_VM 05745 /* cause SEGV on Ruby 1.9 */ 05746 #else 05747 DUMP1("check `destroy'"); 05748 if (Tcl_GetCommandInfo(ip, "destroy", &info)) { 05749 DUMP1("call `destroy .'"); 05750 Tcl_GlobalEval(ip, "catch {destroy .}"); 05751 } 05752 #endif 05753 #if 1 05754 DUMP1("destroy root widget"); 05755 if (tk_stubs_init_p() && Tk_MainWindow(ip) != (Tk_Window)NULL) { 05756 /* 05757 * On Ruby VM, this code piece may be not called, because 05758 * Tk_MainWindow() returns NULL on a native thread except 05759 * the thread which initialize Tk environment. 05760 * Of course, that is a problem. But maybe not so serious. 05761 * All widgets are destroyed when the Tcl interp is deleted. 05762 * At then, Ruby may raise exceptions on the delete hook 05763 * callbacks which registered for the deleted widgets, and 05764 * may fail to clear objects which depends on the widgets. 05765 * Although it is the problem, it is possibly avoidable by 05766 * rescuing exceptions and the finalize hook of the interp. 05767 */ 05768 Tk_Window win = Tk_MainWindow(ip); 05769 05770 DUMP1("call Tk_DestroyWindow"); 05771 ruby_debug = Qfalse; 05772 ruby_verbose = Qnil; 05773 if (! (((Tk_FakeWin*)win)->flags & TK_ALREADY_DEAD)) { 05774 Tk_DestroyWindow(win); 05775 } 05776 ruby_debug = rb_debug_bup; 05777 ruby_verbose = rb_verbose_bup; 05778 } 05779 #endif 05780 05781 /* call finalize-hook-proc */ 05782 DUMP1("check `finalize-hook-proc'"); 05783 if ( Tcl_GetCommandInfo(ip, finalize_hook_name, &info)) { 05784 DUMP2("call finalize hook proc '%s'", finalize_hook_name); 05785 ruby_debug = Qfalse; 05786 ruby_verbose = Qnil; 05787 Tcl_GlobalEval(ip, finalize_hook_name); 05788 ruby_debug = rb_debug_bup; 05789 ruby_verbose = rb_verbose_bup; 05790 } 05791 05792 DUMP1("check `foreach' & `after'"); 05793 if ( Tcl_GetCommandInfo(ip, "foreach", &info) 05794 && Tcl_GetCommandInfo(ip, "after", &info) ) { 05795 DUMP1("cancel after callbacks"); 05796 ruby_debug = Qfalse; 05797 ruby_verbose = Qnil; 05798 Tcl_GlobalEval(ip, "catch {foreach id [after info] {after cancel $id}}"); 05799 ruby_debug = rb_debug_bup; 05800 ruby_verbose = rb_verbose_bup; 05801 } 05802 05803 Tcl_Release(ip); 05804 05805 DUMP1("finish ip_finalize"); 05806 ruby_debug = rb_debug_bup; 05807 ruby_verbose = rb_verbose_bup; 05808 rb_thread_critical = thr_crit_bup; 05809 } 05810 05811 05812 /* destroy interpreter */ 05813 static void 05814 ip_free(ptr) 05815 struct tcltkip *ptr; 05816 { 05817 int thr_crit_bup; 05818 05819 DUMP2("free Tcl Interp %lx", (unsigned long)ptr->ip); 05820 if (ptr) { 05821 thr_crit_bup = rb_thread_critical; 05822 rb_thread_critical = Qtrue; 05823 05824 if ( ptr->ip != (Tcl_Interp*)NULL 05825 && !Tcl_InterpDeleted(ptr->ip) 05826 && Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL 05827 && !Tcl_InterpDeleted(Tcl_GetMaster(ptr->ip)) ) { 05828 DUMP2("parent IP(%lx) is not deleted", 05829 (unsigned long)Tcl_GetMaster(ptr->ip)); 05830 DUMP2("slave IP(%lx) should not be deleted", 05831 (unsigned long)ptr->ip); 05832 xfree(ptr); 05833 /* ckfree((char*)ptr); */ 05834 rb_thread_critical = thr_crit_bup; 05835 return; 05836 } 05837 05838 if (ptr->ip == (Tcl_Interp*)NULL) { 05839 DUMP1("ip_free is called for deleted IP"); 05840 xfree(ptr); 05841 /* ckfree((char*)ptr); */ 05842 rb_thread_critical = thr_crit_bup; 05843 return; 05844 } 05845 05846 if (!Tcl_InterpDeleted(ptr->ip)) { 05847 ip_finalize(ptr->ip); 05848 05849 Tcl_DeleteInterp(ptr->ip); 05850 Tcl_Release(ptr->ip); 05851 } 05852 05853 ptr->ip = (Tcl_Interp*)NULL; 05854 xfree(ptr); 05855 /* ckfree((char*)ptr); */ 05856 05857 rb_thread_critical = thr_crit_bup; 05858 } 05859 05860 DUMP1("complete freeing Tcl Interp"); 05861 } 05862 05863 05864 /* create and initialize interpreter */ 05865 static VALUE ip_alloc _((VALUE)); 05866 static VALUE 05867 ip_alloc(self) 05868 VALUE self; 05869 { 05870 return Data_Wrap_Struct(self, 0, ip_free, 0); 05871 } 05872 05873 static void 05874 ip_replace_wait_commands(interp, mainWin) 05875 Tcl_Interp *interp; 05876 Tk_Window mainWin; 05877 { 05878 /* replace 'vwait' command */ 05879 #if TCL_MAJOR_VERSION >= 8 05880 DUMP1("Tcl_CreateObjCommand(\"vwait\")"); 05881 Tcl_CreateObjCommand(interp, "vwait", ip_rbVwaitObjCmd, 05882 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); 05883 #else /* TCL_MAJOR_VERSION < 8 */ 05884 DUMP1("Tcl_CreateCommand(\"vwait\")"); 05885 Tcl_CreateCommand(interp, "vwait", ip_rbVwaitCommand, 05886 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); 05887 #endif 05888 05889 /* replace 'tkwait' command */ 05890 #if TCL_MAJOR_VERSION >= 8 05891 DUMP1("Tcl_CreateObjCommand(\"tkwait\")"); 05892 Tcl_CreateObjCommand(interp, "tkwait", ip_rbTkWaitObjCmd, 05893 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 05894 #else /* TCL_MAJOR_VERSION < 8 */ 05895 DUMP1("Tcl_CreateCommand(\"tkwait\")"); 05896 Tcl_CreateCommand(interp, "tkwait", ip_rbTkWaitCommand, 05897 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 05898 #endif 05899 05900 /* add 'thread_vwait' command */ 05901 #if TCL_MAJOR_VERSION >= 8 05902 DUMP1("Tcl_CreateObjCommand(\"thread_vwait\")"); 05903 Tcl_CreateObjCommand(interp, "thread_vwait", ip_rb_threadVwaitObjCmd, 05904 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); 05905 #else /* TCL_MAJOR_VERSION < 8 */ 05906 DUMP1("Tcl_CreateCommand(\"thread_vwait\")"); 05907 Tcl_CreateCommand(interp, "thread_vwait", ip_rb_threadVwaitCommand, 05908 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); 05909 #endif 05910 05911 /* add 'thread_tkwait' command */ 05912 #if TCL_MAJOR_VERSION >= 8 05913 DUMP1("Tcl_CreateObjCommand(\"thread_tkwait\")"); 05914 Tcl_CreateObjCommand(interp, "thread_tkwait", ip_rb_threadTkWaitObjCmd, 05915 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 05916 #else /* TCL_MAJOR_VERSION < 8 */ 05917 DUMP1("Tcl_CreateCommand(\"thread_tkwait\")"); 05918 Tcl_CreateCommand(interp, "thread_tkwait", ip_rb_threadTkWaitCommand, 05919 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 05920 #endif 05921 05922 /* replace 'update' command */ 05923 #if TCL_MAJOR_VERSION >= 8 05924 DUMP1("Tcl_CreateObjCommand(\"update\")"); 05925 Tcl_CreateObjCommand(interp, "update", ip_rbUpdateObjCmd, 05926 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 05927 #else /* TCL_MAJOR_VERSION < 8 */ 05928 DUMP1("Tcl_CreateCommand(\"update\")"); 05929 Tcl_CreateCommand(interp, "update", ip_rbUpdateCommand, 05930 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 05931 #endif 05932 05933 /* add 'thread_update' command */ 05934 #if TCL_MAJOR_VERSION >= 8 05935 DUMP1("Tcl_CreateObjCommand(\"thread_update\")"); 05936 Tcl_CreateObjCommand(interp, "thread_update", ip_rb_threadUpdateObjCmd, 05937 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 05938 #else /* TCL_MAJOR_VERSION < 8 */ 05939 DUMP1("Tcl_CreateCommand(\"thread_update\")"); 05940 Tcl_CreateCommand(interp, "thread_update", ip_rb_threadUpdateCommand, 05941 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 05942 #endif 05943 } 05944 05945 05946 #if TCL_MAJOR_VERSION >= 8 05947 static int 05948 ip_rb_replaceSlaveTkCmdsObjCmd(clientData, interp, objc, objv) 05949 ClientData clientData; 05950 Tcl_Interp *interp; 05951 int objc; 05952 Tcl_Obj *CONST objv[]; 05953 #else /* TCL_MAJOR_VERSION < 8 */ 05954 static int 05955 ip_rb_replaceSlaveTkCmdsCommand(clientData, interp, objc, objv) 05956 ClientData clientData; 05957 Tcl_Interp *interp; 05958 int objc; 05959 char *objv[]; 05960 #endif 05961 { 05962 char *slave_name; 05963 Tcl_Interp *slave; 05964 Tk_Window mainWin; 05965 05966 if (objc != 2) { 05967 #ifdef Tcl_WrongNumArgs 05968 Tcl_WrongNumArgs(interp, 1, objv, "slave_name"); 05969 #else 05970 char *nameString; 05971 #if TCL_MAJOR_VERSION >= 8 05972 nameString = Tcl_GetStringFromObj(objv[0], (int*)NULL); 05973 #else /* TCL_MAJOR_VERSION < 8 */ 05974 nameString = objv[0]; 05975 #endif 05976 Tcl_AppendResult(interp, "wrong number of arguments: should be \"", 05977 nameString, " slave_name\"", (char *) NULL); 05978 #endif 05979 } 05980 05981 #if TCL_MAJOR_VERSION >= 8 05982 slave_name = Tcl_GetStringFromObj(objv[1], (int*)NULL); 05983 #else 05984 slave_name = objv[1]; 05985 #endif 05986 05987 slave = Tcl_GetSlave(interp, slave_name); 05988 if (slave == NULL) { 05989 Tcl_AppendResult(interp, "cannot find slave \"", 05990 slave_name, "\"", (char *)NULL); 05991 return TCL_ERROR; 05992 } 05993 mainWin = Tk_MainWindow(slave); 05994 05995 /* replace 'exit' command --> 'interp_exit' command */ 05996 #if TCL_MAJOR_VERSION >= 8 05997 DUMP1("Tcl_CreateObjCommand(\"exit\") --> \"interp_exit\""); 05998 Tcl_CreateObjCommand(slave, "exit", ip_InterpExitObjCmd, 05999 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 06000 #else /* TCL_MAJOR_VERSION < 8 */ 06001 DUMP1("Tcl_CreateCommand(\"exit\") --> \"interp_exit\""); 06002 Tcl_CreateCommand(slave, "exit", ip_InterpExitCommand, 06003 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 06004 #endif 06005 06006 /* replace vwait and tkwait */ 06007 ip_replace_wait_commands(slave, mainWin); 06008 06009 return TCL_OK; 06010 } 06011 06012 06013 #if TCL_MAJOR_VERSION >= 8 06014 static int ip_rbNamespaceObjCmd _((ClientData, Tcl_Interp *, int, 06015 Tcl_Obj *CONST [])); 06016 static int 06017 ip_rbNamespaceObjCmd(clientData, interp, objc, objv) 06018 ClientData clientData; 06019 Tcl_Interp *interp; 06020 int objc; 06021 Tcl_Obj *CONST objv[]; 06022 { 06023 Tcl_CmdInfo info; 06024 int ret; 06025 06026 if (!Tcl_GetCommandInfo(interp, "__orig_namespace_command__", &(info))) { 06027 Tcl_ResetResult(interp); 06028 Tcl_AppendResult(interp, 06029 "invalid command name \"namespace\"", (char*)NULL); 06030 return TCL_ERROR; 06031 } 06032 06033 rbtk_eventloop_depth++; 06034 /* DUMP2("namespace wrapper enter depth == %d", rbtk_eventloop_depth); */ 06035 06036 if (info.isNativeObjectProc) { 06037 ret = (*(info.objProc))(info.objClientData, interp, objc, objv); 06038 } else { 06039 /* string interface */ 06040 int i; 06041 char **argv; 06042 06043 /* argv = (char **)Tcl_Alloc(sizeof(char *) * (objc + 1)); */ 06044 argv = (char **)ckalloc(sizeof(char *) * (objc + 1)); 06045 #if 0 /* use Tcl_Preserve/Release */ 06046 Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ 06047 #endif 06048 06049 for(i = 0; i < objc; i++) { 06050 /* argv[i] = Tcl_GetString(objv[i]); */ 06051 argv[i] = Tcl_GetStringFromObj(objv[i], (int*)NULL); 06052 } 06053 argv[objc] = (char *)NULL; 06054 06055 ret = (*(info.proc))(info.clientData, interp, 06056 objc, (CONST84 char **)argv); 06057 06058 #if 0 /* use Tcl_EventuallyFree */ 06059 Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ 06060 #else 06061 #if 0 /* use Tcl_Preserve/Release */ 06062 Tcl_Release((ClientData)argv); /* XXXXXXXX */ 06063 #else 06064 /* Tcl_Free((char*)argv); */ 06065 ckfree((char*)argv); 06066 #endif 06067 #endif 06068 } 06069 06070 /* DUMP2("namespace wrapper exit depth == %d", rbtk_eventloop_depth); */ 06071 rbtk_eventloop_depth--; 06072 06073 return ret; 06074 } 06075 #endif 06076 06077 static void 06078 ip_wrap_namespace_command(interp) 06079 Tcl_Interp *interp; 06080 { 06081 #if TCL_MAJOR_VERSION >= 8 06082 Tcl_CmdInfo orig_info; 06083 06084 if (!Tcl_GetCommandInfo(interp, "namespace", &(orig_info))) { 06085 return; 06086 } 06087 06088 if (orig_info.isNativeObjectProc) { 06089 Tcl_CreateObjCommand(interp, "__orig_namespace_command__", 06090 orig_info.objProc, orig_info.objClientData, 06091 orig_info.deleteProc); 06092 } else { 06093 Tcl_CreateCommand(interp, "__orig_namespace_command__", 06094 orig_info.proc, orig_info.clientData, 06095 orig_info.deleteProc); 06096 } 06097 06098 Tcl_CreateObjCommand(interp, "namespace", ip_rbNamespaceObjCmd, 06099 (ClientData) 0, (Tcl_CmdDeleteProc *)NULL); 06100 #endif 06101 } 06102 06103 06104 /* call when interpreter is deleted */ 06105 static void 06106 #ifdef HAVE_PROTOTYPES 06107 ip_CallWhenDeleted(ClientData clientData, Tcl_Interp *ip) 06108 #else 06109 ip_CallWhenDeleted(clientData, ip) 06110 ClientData clientData; 06111 Tcl_Interp *ip; 06112 #endif 06113 { 06114 int thr_crit_bup; 06115 /* Tk_Window main_win = (Tk_Window) clientData; */ 06116 06117 DUMP1("start ip_CallWhenDeleted"); 06118 thr_crit_bup = rb_thread_critical; 06119 rb_thread_critical = Qtrue; 06120 06121 ip_finalize(ip); 06122 06123 DUMP1("finish ip_CallWhenDeleted"); 06124 rb_thread_critical = thr_crit_bup; 06125 } 06126 06127 /*--------------------------------------------------------*/ 06128 06129 /* initialize interpreter */ 06130 static VALUE 06131 ip_init(argc, argv, self) 06132 int argc; 06133 VALUE *argv; 06134 VALUE self; 06135 { 06136 struct tcltkip *ptr; /* tcltkip data struct */ 06137 VALUE argv0, opts; 06138 int cnt; 06139 int st; 06140 int with_tk = 1; 06141 Tk_Window mainWin = (Tk_Window)NULL; 06142 06143 /* security check */ 06144 if (rb_safe_level() >= 4) { 06145 rb_raise(rb_eSecurityError, 06146 "Cannot create a TclTkIp object at level %d", 06147 rb_safe_level()); 06148 } 06149 06150 /* create object */ 06151 Data_Get_Struct(self, struct tcltkip, ptr); 06152 ptr = ALLOC(struct tcltkip); 06153 /* ptr = (struct tcltkip *)ckalloc(sizeof(struct tcltkip)); */ 06154 DATA_PTR(self) = ptr; 06155 #ifdef RUBY_USE_NATIVE_THREAD 06156 ptr->tk_thread_id = 0; 06157 #endif 06158 ptr->ref_count = 0; 06159 ptr->allow_ruby_exit = 1; 06160 ptr->return_value = 0; 06161 06162 /* from Tk_Main() */ 06163 DUMP1("Tcl_CreateInterp"); 06164 ptr->ip = ruby_tcl_create_ip_and_stubs_init(&st); 06165 if (ptr->ip == NULL) { 06166 switch(st) { 06167 case TCLTK_STUBS_OK: 06168 break; 06169 case NO_TCL_DLL: 06170 rb_raise(rb_eLoadError, "tcltklib: fail to open tcl_dll"); 06171 case NO_FindExecutable: 06172 rb_raise(rb_eLoadError, "tcltklib: can't find Tcl_FindExecutable"); 06173 case NO_CreateInterp: 06174 rb_raise(rb_eLoadError, "tcltklib: can't find Tcl_CreateInterp()"); 06175 case NO_DeleteInterp: 06176 rb_raise(rb_eLoadError, "tcltklib: can't find Tcl_DeleteInterp()"); 06177 case FAIL_CreateInterp: 06178 rb_raise(rb_eRuntimeError, "tcltklib: fail to create a new IP"); 06179 case FAIL_Tcl_InitStubs: 06180 rb_raise(rb_eRuntimeError, "tcltklib: fail to Tcl_InitStubs()"); 06181 default: 06182 rb_raise(rb_eRuntimeError, "tcltklib: unknown error(%d) on ruby_tcl_create_ip_and_stubs_init", st); 06183 } 06184 } 06185 06186 #if TCL_MAJOR_VERSION >= 8 06187 #if TCL_NAMESPACE_DEBUG 06188 DUMP1("get current namespace"); 06189 if ((ptr->default_ns = Tcl_GetCurrentNamespace(ptr->ip)) 06190 == (Tcl_Namespace*)NULL) { 06191 rb_raise(rb_eRuntimeError, "a new Tk interpreter has a NULL namespace"); 06192 } 06193 #endif 06194 #endif 06195 06196 rbtk_preserve_ip(ptr); 06197 DUMP2("IP ref_count = %d", ptr->ref_count); 06198 current_interp = ptr->ip; 06199 06200 ptr->has_orig_exit 06201 = Tcl_GetCommandInfo(ptr->ip, "exit", &(ptr->orig_exit_info)); 06202 06203 #if defined CREATE_RUBYTK_KIT || defined CREATE_RUBYKIT 06204 call_tclkit_init_script(current_interp); 06205 06206 # if 10 * TCL_MAJOR_VERSION + TCL_MINOR_VERSION > 84 06207 { 06208 Tcl_DString encodingName; 06209 Tcl_GetEncodingNameFromEnvironment(&encodingName); 06210 if (strcmp(Tcl_DStringValue(&encodingName), Tcl_GetEncodingName(NULL))) { 06211 /* fails, so we set a variable and do it in the boot.tcl script */ 06212 Tcl_SetSystemEncoding(NULL, Tcl_DStringValue(&encodingName)); 06213 } 06214 Tcl_SetVar(current_interp, "tclkit_system_encoding", Tcl_DStringValue(&encodingName), 0); 06215 Tcl_DStringFree(&encodingName); 06216 } 06217 # endif 06218 #endif 06219 06220 /* set variables */ 06221 Tcl_Eval(ptr->ip, "set argc 0; set argv {}; set argv0 tcltklib.so"); 06222 06223 cnt = rb_scan_args(argc, argv, "02", &argv0, &opts); 06224 switch(cnt) { 06225 case 2: 06226 /* options */ 06227 if (NIL_P(opts) || opts == Qfalse) { 06228 /* without Tk */ 06229 with_tk = 0; 06230 } else { 06231 /* Tcl_SetVar(ptr->ip, "argv", StringValuePtr(opts), 0); */ 06232 Tcl_SetVar(ptr->ip, "argv", StringValuePtr(opts), TCL_GLOBAL_ONLY); 06233 Tcl_Eval(ptr->ip, "set argc [llength $argv]"); 06234 } 06235 case 1: 06236 /* argv0 */ 06237 if (!NIL_P(argv0)) { 06238 if (strncmp(StringValuePtr(argv0), "-e", 3) == 0 06239 || strncmp(StringValuePtr(argv0), "-", 2) == 0) { 06240 Tcl_SetVar(ptr->ip, "argv0", "ruby", TCL_GLOBAL_ONLY); 06241 } else { 06242 /* Tcl_SetVar(ptr->ip, "argv0", StringValuePtr(argv0), 0); */ 06243 Tcl_SetVar(ptr->ip, "argv0", StringValuePtr(argv0), 06244 TCL_GLOBAL_ONLY); 06245 } 06246 } 06247 case 0: 06248 /* no args */ 06249 ; 06250 } 06251 06252 /* from Tcl_AppInit() */ 06253 DUMP1("Tcl_Init"); 06254 #if (defined CREATE_RUBYTK_KIT || defined CREATE_RUBYKIT) && (!defined KIT_LITE) && (10 * TCL_MAJOR_VERSION + TCL_MINOR_VERSION == 85) 06255 /*************************************************************************/ 06256 /* FIX ME (2010/06/28) */ 06257 /* Don't use ::chan command for Mk4tcl + tclvfs-1.4 on Tcl8.5. */ 06258 /* It fails to access VFS files because of vfs::zstream. */ 06259 /* So, force to use ::rechan by temporaly hiding ::chan. */ 06260 /*************************************************************************/ 06261 Tcl_Eval(ptr->ip, "catch {rename ::chan ::_tmp_chan}"); 06262 if (Tcl_Init(ptr->ip) == TCL_ERROR) { 06263 rb_raise(rb_eRuntimeError, "%s", Tcl_GetStringResult(ptr->ip)); 06264 } 06265 Tcl_Eval(ptr->ip, "catch {rename ::_tmp_chan ::chan}"); 06266 #else 06267 if (Tcl_Init(ptr->ip) == TCL_ERROR) { 06268 rb_raise(rb_eRuntimeError, "%s", Tcl_GetStringResult(ptr->ip)); 06269 } 06270 #endif 06271 06272 st = ruby_tcl_stubs_init(); 06273 /* from Tcl_AppInit() */ 06274 if (with_tk) { 06275 DUMP1("Tk_Init"); 06276 st = ruby_tk_stubs_init(ptr->ip); 06277 switch(st) { 06278 case TCLTK_STUBS_OK: 06279 break; 06280 case NO_Tk_Init: 06281 rb_raise(rb_eLoadError, "tcltklib: can't find Tk_Init()"); 06282 case FAIL_Tk_Init: 06283 rb_raise(rb_eRuntimeError, "tcltklib: fail to Tk_Init(). %s", 06284 Tcl_GetStringResult(ptr->ip)); 06285 case FAIL_Tk_InitStubs: 06286 rb_raise(rb_eRuntimeError, "tcltklib: fail to Tk_InitStubs(). %s", 06287 Tcl_GetStringResult(ptr->ip)); 06288 default: 06289 rb_raise(rb_eRuntimeError, "tcltklib: unknown error(%d) on ruby_tk_stubs_init", st); 06290 } 06291 06292 DUMP1("Tcl_StaticPackage(\"Tk\")"); 06293 #if TCL_MAJOR_VERSION >= 8 06294 Tcl_StaticPackage(ptr->ip, "Tk", Tk_Init, Tk_SafeInit); 06295 #else /* TCL_MAJOR_VERSION < 8 */ 06296 Tcl_StaticPackage(ptr->ip, "Tk", Tk_Init, 06297 (Tcl_PackageInitProc *) NULL); 06298 #endif 06299 06300 #ifdef RUBY_USE_NATIVE_THREAD 06301 /* set Tk thread ID */ 06302 ptr->tk_thread_id = Tcl_GetCurrentThread(); 06303 #endif 06304 /* get main window */ 06305 mainWin = Tk_MainWindow(ptr->ip); 06306 Tk_Preserve((ClientData)mainWin); 06307 } 06308 06309 /* add ruby command to the interpreter */ 06310 #if TCL_MAJOR_VERSION >= 8 06311 DUMP1("Tcl_CreateObjCommand(\"ruby\")"); 06312 Tcl_CreateObjCommand(ptr->ip, "ruby", ip_ruby_eval, (ClientData)NULL, 06313 (Tcl_CmdDeleteProc *)NULL); 06314 DUMP1("Tcl_CreateObjCommand(\"ruby_eval\")"); 06315 Tcl_CreateObjCommand(ptr->ip, "ruby_eval", ip_ruby_eval, (ClientData)NULL, 06316 (Tcl_CmdDeleteProc *)NULL); 06317 DUMP1("Tcl_CreateObjCommand(\"ruby_cmd\")"); 06318 Tcl_CreateObjCommand(ptr->ip, "ruby_cmd", ip_ruby_cmd, (ClientData)NULL, 06319 (Tcl_CmdDeleteProc *)NULL); 06320 #else /* TCL_MAJOR_VERSION < 8 */ 06321 DUMP1("Tcl_CreateCommand(\"ruby\")"); 06322 Tcl_CreateCommand(ptr->ip, "ruby", ip_ruby_eval, (ClientData)NULL, 06323 (Tcl_CmdDeleteProc *)NULL); 06324 DUMP1("Tcl_CreateCommand(\"ruby_eval\")"); 06325 Tcl_CreateCommand(ptr->ip, "ruby_eval", ip_ruby_eval, (ClientData)NULL, 06326 (Tcl_CmdDeleteProc *)NULL); 06327 DUMP1("Tcl_CreateCommand(\"ruby_cmd\")"); 06328 Tcl_CreateCommand(ptr->ip, "ruby_cmd", ip_ruby_cmd, (ClientData)NULL, 06329 (Tcl_CmdDeleteProc *)NULL); 06330 #endif 06331 06332 /* add 'interp_exit', 'ruby_exit' and replace 'exit' command */ 06333 #if TCL_MAJOR_VERSION >= 8 06334 DUMP1("Tcl_CreateObjCommand(\"interp_exit\")"); 06335 Tcl_CreateObjCommand(ptr->ip, "interp_exit", ip_InterpExitObjCmd, 06336 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 06337 DUMP1("Tcl_CreateObjCommand(\"ruby_exit\")"); 06338 Tcl_CreateObjCommand(ptr->ip, "ruby_exit", ip_RubyExitObjCmd, 06339 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 06340 DUMP1("Tcl_CreateObjCommand(\"exit\") --> \"ruby_exit\""); 06341 Tcl_CreateObjCommand(ptr->ip, "exit", ip_RubyExitObjCmd, 06342 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 06343 #else /* TCL_MAJOR_VERSION < 8 */ 06344 DUMP1("Tcl_CreateCommand(\"interp_exit\")"); 06345 Tcl_CreateCommand(ptr->ip, "interp_exit", ip_InterpExitCommand, 06346 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 06347 DUMP1("Tcl_CreateCommand(\"ruby_exit\")"); 06348 Tcl_CreateCommand(ptr->ip, "ruby_exit", ip_RubyExitCommand, 06349 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 06350 DUMP1("Tcl_CreateCommand(\"exit\") --> \"ruby_exit\""); 06351 Tcl_CreateCommand(ptr->ip, "exit", ip_RubyExitCommand, 06352 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 06353 #endif 06354 06355 /* replace vwait and tkwait */ 06356 ip_replace_wait_commands(ptr->ip, mainWin); 06357 06358 /* wrap namespace command */ 06359 ip_wrap_namespace_command(ptr->ip); 06360 06361 /* define command to replace commands which depend on slave's MainWindow */ 06362 #if TCL_MAJOR_VERSION >= 8 06363 Tcl_CreateObjCommand(ptr->ip, "__replace_slave_tk_commands__", 06364 ip_rb_replaceSlaveTkCmdsObjCmd, 06365 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); 06366 #else /* TCL_MAJOR_VERSION < 8 */ 06367 Tcl_CreateCommand(ptr->ip, "__replace_slave_tk_commands__", 06368 ip_rb_replaceSlaveTkCmdsCommand, 06369 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); 06370 #endif 06371 06372 /* set finalizer */ 06373 Tcl_CallWhenDeleted(ptr->ip, ip_CallWhenDeleted, (ClientData)mainWin); 06374 06375 if (mainWin != (Tk_Window)NULL) { 06376 Tk_Release((ClientData)mainWin); 06377 } 06378 06379 return self; 06380 } 06381 06382 static VALUE 06383 ip_create_slave_core(interp, argc, argv) 06384 VALUE interp; 06385 int argc; 06386 VALUE *argv; 06387 { 06388 struct tcltkip *master = get_ip(interp); 06389 struct tcltkip *slave = ALLOC(struct tcltkip); 06390 /* struct tcltkip *slave = (struct tcltkip *)ckalloc(sizeof(struct tcltkip)); */ 06391 VALUE safemode; 06392 VALUE name; 06393 int safe; 06394 int thr_crit_bup; 06395 Tk_Window mainWin; 06396 06397 /* ip is deleted? */ 06398 if (deleted_ip(master)) { 06399 return rb_exc_new2(rb_eRuntimeError, 06400 "deleted master cannot create a new slave"); 06401 } 06402 06403 name = argv[0]; 06404 safemode = argv[1]; 06405 06406 if (Tcl_IsSafe(master->ip) == 1) { 06407 safe = 1; 06408 } else if (safemode == Qfalse || NIL_P(safemode)) { 06409 safe = 0; 06410 /* rb_secure(4); */ /* already checked */ 06411 } else { 06412 safe = 1; 06413 } 06414 06415 thr_crit_bup = rb_thread_critical; 06416 rb_thread_critical = Qtrue; 06417 06418 #if 0 06419 /* init Tk */ 06420 if (RTEST(with_tk)) { 06421 volatile VALUE exc; 06422 if (!tk_stubs_init_p()) { 06423 exc = tcltkip_init_tk(interp); 06424 if (!NIL_P(exc)) { 06425 rb_thread_critical = thr_crit_bup; 06426 return exc; 06427 } 06428 } 06429 } 06430 #endif 06431 06432 /* create slave-ip */ 06433 #ifdef RUBY_USE_NATIVE_THREAD 06434 /* slave->tk_thread_id = 0; */ 06435 slave->tk_thread_id = master->tk_thread_id; /* == current thread */ 06436 #endif 06437 slave->ref_count = 0; 06438 slave->allow_ruby_exit = 0; 06439 slave->return_value = 0; 06440 06441 slave->ip = Tcl_CreateSlave(master->ip, StringValuePtr(name), safe); 06442 if (slave->ip == NULL) { 06443 rb_thread_critical = thr_crit_bup; 06444 return rb_exc_new2(rb_eRuntimeError, 06445 "fail to create the new slave interpreter"); 06446 } 06447 #if TCL_MAJOR_VERSION >= 8 06448 #if TCL_NAMESPACE_DEBUG 06449 slave->default_ns = Tcl_GetCurrentNamespace(slave->ip); 06450 #endif 06451 #endif 06452 rbtk_preserve_ip(slave); 06453 06454 slave->has_orig_exit 06455 = Tcl_GetCommandInfo(slave->ip, "exit", &(slave->orig_exit_info)); 06456 06457 /* replace 'exit' command --> 'interp_exit' command */ 06458 mainWin = (tk_stubs_init_p())? Tk_MainWindow(slave->ip): (Tk_Window)NULL; 06459 #if TCL_MAJOR_VERSION >= 8 06460 DUMP1("Tcl_CreateObjCommand(\"exit\") --> \"interp_exit\""); 06461 Tcl_CreateObjCommand(slave->ip, "exit", ip_InterpExitObjCmd, 06462 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 06463 #else /* TCL_MAJOR_VERSION < 8 */ 06464 DUMP1("Tcl_CreateCommand(\"exit\") --> \"interp_exit\""); 06465 Tcl_CreateCommand(slave->ip, "exit", ip_InterpExitCommand, 06466 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 06467 #endif 06468 06469 /* replace vwait and tkwait */ 06470 ip_replace_wait_commands(slave->ip, mainWin); 06471 06472 /* wrap namespace command */ 06473 ip_wrap_namespace_command(slave->ip); 06474 06475 /* define command to replace cmds which depend on slave-slave's MainWin */ 06476 #if TCL_MAJOR_VERSION >= 8 06477 Tcl_CreateObjCommand(slave->ip, "__replace_slave_tk_commands__", 06478 ip_rb_replaceSlaveTkCmdsObjCmd, 06479 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); 06480 #else /* TCL_MAJOR_VERSION < 8 */ 06481 Tcl_CreateCommand(slave->ip, "__replace_slave_tk_commands__", 06482 ip_rb_replaceSlaveTkCmdsCommand, 06483 (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); 06484 #endif 06485 06486 /* set finalizer */ 06487 Tcl_CallWhenDeleted(slave->ip, ip_CallWhenDeleted, (ClientData)mainWin); 06488 06489 rb_thread_critical = thr_crit_bup; 06490 06491 return Data_Wrap_Struct(CLASS_OF(interp), 0, ip_free, slave); 06492 } 06493 06494 static VALUE 06495 ip_create_slave(argc, argv, self) 06496 int argc; 06497 VALUE *argv; 06498 VALUE self; 06499 { 06500 struct tcltkip *master = get_ip(self); 06501 VALUE safemode; 06502 VALUE name; 06503 VALUE callargv[2]; 06504 06505 /* ip is deleted? */ 06506 if (deleted_ip(master)) { 06507 rb_raise(rb_eRuntimeError, 06508 "deleted master cannot create a new slave interpreter"); 06509 } 06510 06511 /* argument check */ 06512 if (rb_scan_args(argc, argv, "11", &name, &safemode) == 1) { 06513 safemode = Qfalse; 06514 } 06515 if (Tcl_IsSafe(master->ip) != 1 06516 && (safemode == Qfalse || NIL_P(safemode))) { 06517 rb_secure(4); 06518 } 06519 06520 StringValue(name); 06521 callargv[0] = name; 06522 callargv[1] = safemode; 06523 06524 return tk_funcall(ip_create_slave_core, 2, callargv, self); 06525 } 06526 06527 06528 /* self is slave of master? */ 06529 static VALUE 06530 ip_is_slave_of_p(self, master) 06531 VALUE self, master; 06532 { 06533 if (!rb_obj_is_kind_of(master, tcltkip_class)) { 06534 rb_raise(rb_eArgError, "expected TclTkIp object"); 06535 } 06536 06537 if (Tcl_GetMaster(get_ip(self)->ip) == get_ip(master)->ip) { 06538 return Qtrue; 06539 } else { 06540 return Qfalse; 06541 } 06542 } 06543 06544 06545 /* create console (if supported) */ 06546 #if defined(MAC_TCL) || defined(__WIN32__) 06547 #if TCL_MAJOR_VERSION < 8 \ 06548 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0) \ 06549 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 1 \ 06550 && (TCL_RELEASE_LEVEL == TCL_ALPHA_RELEASE \ 06551 || (TCL_RELEASE_LEVEL == TCL_BETA_RELEASE \ 06552 && TCL_RELEASE_SERIAL < 2) ) ) 06553 EXTERN void TkConsoleCreate _((void)); 06554 #endif 06555 #if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 1 \ 06556 && ( (TCL_RELEASE_LEVEL == TCL_FINAL_RELEASE \ 06557 && TCL_RELEASE_SERIAL == 0) \ 06558 || (TCL_RELEASE_LEVEL == TCL_BETA_RELEASE \ 06559 && TCL_RELEASE_SERIAL >= 2) ) 06560 EXTERN void TkConsoleCreate_ _((void)); 06561 #endif 06562 #endif 06563 static VALUE 06564 ip_create_console_core(interp, argc, argv) 06565 VALUE interp; 06566 int argc; /* dummy */ 06567 VALUE *argv; /* dummy */ 06568 { 06569 struct tcltkip *ptr = get_ip(interp); 06570 06571 if (!tk_stubs_init_p()) { 06572 tcltkip_init_tk(interp); 06573 } 06574 06575 if (Tcl_GetVar(ptr->ip,"tcl_interactive",TCL_GLOBAL_ONLY) == (char*)NULL) { 06576 Tcl_SetVar(ptr->ip, "tcl_interactive", "0", TCL_GLOBAL_ONLY); 06577 } 06578 06579 #if TCL_MAJOR_VERSION > 8 \ 06580 || (TCL_MAJOR_VERSION == 8 \ 06581 && (TCL_MINOR_VERSION > 1 \ 06582 || (TCL_MINOR_VERSION == 1 \ 06583 && TCL_RELEASE_LEVEL == TCL_FINAL_RELEASE \ 06584 && TCL_RELEASE_SERIAL >= 1) ) ) 06585 Tk_InitConsoleChannels(ptr->ip); 06586 06587 if (Tk_CreateConsoleWindow(ptr->ip) != TCL_OK) { 06588 rb_raise(rb_eRuntimeError, "fail to create console-window"); 06589 } 06590 #else 06591 #if defined(MAC_TCL) || defined(__WIN32__) 06592 #if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 1 \ 06593 && ( (TCL_RELEASE_LEVEL == TCL_FINAL_RELEASE && TCL_RELEASE_SERIAL == 0) \ 06594 || (TCL_RELEASE_LEVEL == TCL_BETA_RELEASE && TCL_RELEASE_SERIAL >= 2) ) 06595 TkConsoleCreate_(); 06596 #else 06597 TkConsoleCreate(); 06598 #endif 06599 06600 if (TkConsoleInit(ptr->ip) != TCL_OK) { 06601 rb_raise(rb_eRuntimeError, "fail to create console-window"); 06602 } 06603 #else 06604 rb_notimplement(); 06605 #endif 06606 #endif 06607 06608 return interp; 06609 } 06610 06611 static VALUE 06612 ip_create_console(self) 06613 VALUE self; 06614 { 06615 struct tcltkip *ptr = get_ip(self); 06616 06617 /* ip is deleted? */ 06618 if (deleted_ip(ptr)) { 06619 rb_raise(rb_eRuntimeError, "interpreter is deleted"); 06620 } 06621 06622 return tk_funcall(ip_create_console_core, 0, (VALUE*)NULL, self); 06623 } 06624 06625 /* make ip "safe" */ 06626 static VALUE 06627 ip_make_safe_core(interp, argc, argv) 06628 VALUE interp; 06629 int argc; /* dummy */ 06630 VALUE *argv; /* dummy */ 06631 { 06632 struct tcltkip *ptr = get_ip(interp); 06633 Tk_Window mainWin; 06634 06635 /* ip is deleted? */ 06636 if (deleted_ip(ptr)) { 06637 return rb_exc_new2(rb_eRuntimeError, "interpreter is deleted"); 06638 } 06639 06640 if (Tcl_MakeSafe(ptr->ip) == TCL_ERROR) { 06641 /* return rb_exc_new2(rb_eRuntimeError, 06642 Tcl_GetStringResult(ptr->ip)); */ 06643 return create_ip_exc(interp, rb_eRuntimeError, "%s", 06644 Tcl_GetStringResult(ptr->ip)); 06645 } 06646 06647 ptr->allow_ruby_exit = 0; 06648 06649 /* replace 'exit' command --> 'interp_exit' command */ 06650 mainWin = (tk_stubs_init_p())? Tk_MainWindow(ptr->ip): (Tk_Window)NULL; 06651 #if TCL_MAJOR_VERSION >= 8 06652 DUMP1("Tcl_CreateObjCommand(\"exit\") --> \"interp_exit\""); 06653 Tcl_CreateObjCommand(ptr->ip, "exit", ip_InterpExitObjCmd, 06654 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 06655 #else /* TCL_MAJOR_VERSION < 8 */ 06656 DUMP1("Tcl_CreateCommand(\"exit\") --> \"interp_exit\""); 06657 Tcl_CreateCommand(ptr->ip, "exit", ip_InterpExitCommand, 06658 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 06659 #endif 06660 06661 return interp; 06662 } 06663 06664 static VALUE 06665 ip_make_safe(self) 06666 VALUE self; 06667 { 06668 struct tcltkip *ptr = get_ip(self); 06669 06670 /* ip is deleted? */ 06671 if (deleted_ip(ptr)) { 06672 rb_raise(rb_eRuntimeError, "interpreter is deleted"); 06673 } 06674 06675 return tk_funcall(ip_make_safe_core, 0, (VALUE*)NULL, self); 06676 } 06677 06678 /* is safe? */ 06679 static VALUE 06680 ip_is_safe_p(self) 06681 VALUE self; 06682 { 06683 struct tcltkip *ptr = get_ip(self); 06684 06685 /* ip is deleted? */ 06686 if (deleted_ip(ptr)) { 06687 rb_raise(rb_eRuntimeError, "interpreter is deleted"); 06688 } 06689 06690 if (Tcl_IsSafe(ptr->ip)) { 06691 return Qtrue; 06692 } else { 06693 return Qfalse; 06694 } 06695 } 06696 06697 /* allow_ruby_exit? */ 06698 static VALUE 06699 ip_allow_ruby_exit_p(self) 06700 VALUE self; 06701 { 06702 struct tcltkip *ptr = get_ip(self); 06703 06704 /* ip is deleted? */ 06705 if (deleted_ip(ptr)) { 06706 rb_raise(rb_eRuntimeError, "interpreter is deleted"); 06707 } 06708 06709 if (ptr->allow_ruby_exit) { 06710 return Qtrue; 06711 } else { 06712 return Qfalse; 06713 } 06714 } 06715 06716 /* allow_ruby_exit = mode */ 06717 static VALUE 06718 ip_allow_ruby_exit_set(self, val) 06719 VALUE self, val; 06720 { 06721 struct tcltkip *ptr = get_ip(self); 06722 Tk_Window mainWin; 06723 06724 rb_secure(4); 06725 06726 /* ip is deleted? */ 06727 if (deleted_ip(ptr)) { 06728 rb_raise(rb_eRuntimeError, "interpreter is deleted"); 06729 } 06730 06731 if (Tcl_IsSafe(ptr->ip)) { 06732 rb_raise(rb_eSecurityError, 06733 "insecure operation on a safe interpreter"); 06734 } 06735 06736 /* 06737 * Because of cross-threading, the following line may fail to find 06738 * the MainWindow, even if the Tcl/Tk interpreter has one or more. 06739 * But it has no problem. Current implementation of both type of 06740 * the "exit" command don't need maiinWin token. 06741 */ 06742 mainWin = (tk_stubs_init_p())? Tk_MainWindow(ptr->ip): (Tk_Window)NULL; 06743 06744 if (RTEST(val)) { 06745 ptr->allow_ruby_exit = 1; 06746 #if TCL_MAJOR_VERSION >= 8 06747 DUMP1("Tcl_CreateObjCommand(\"exit\") --> \"ruby_exit\""); 06748 Tcl_CreateObjCommand(ptr->ip, "exit", ip_RubyExitObjCmd, 06749 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 06750 #else /* TCL_MAJOR_VERSION < 8 */ 06751 DUMP1("Tcl_CreateCommand(\"exit\") --> \"ruby_exit\""); 06752 Tcl_CreateCommand(ptr->ip, "exit", ip_RubyExitCommand, 06753 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 06754 #endif 06755 return Qtrue; 06756 06757 } else { 06758 ptr->allow_ruby_exit = 0; 06759 #if TCL_MAJOR_VERSION >= 8 06760 DUMP1("Tcl_CreateObjCommand(\"exit\") --> \"interp_exit\""); 06761 Tcl_CreateObjCommand(ptr->ip, "exit", ip_InterpExitObjCmd, 06762 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 06763 #else /* TCL_MAJOR_VERSION < 8 */ 06764 DUMP1("Tcl_CreateCommand(\"exit\") --> \"interp_exit\""); 06765 Tcl_CreateCommand(ptr->ip, "exit", ip_InterpExitCommand, 06766 (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL); 06767 #endif 06768 return Qfalse; 06769 } 06770 } 06771 06772 /* delete interpreter */ 06773 static VALUE 06774 ip_delete(self) 06775 VALUE self; 06776 { 06777 int thr_crit_bup; 06778 struct tcltkip *ptr = get_ip(self); 06779 06780 /* if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL) { */ 06781 if (deleted_ip(ptr)) { 06782 DUMP1("delete deleted IP"); 06783 return Qnil; 06784 } 06785 06786 thr_crit_bup = rb_thread_critical; 06787 rb_thread_critical = Qtrue; 06788 06789 DUMP1("delete interp"); 06790 if (!Tcl_InterpDeleted(ptr->ip)) { 06791 DUMP1("call ip_finalize"); 06792 ip_finalize(ptr->ip); 06793 06794 Tcl_DeleteInterp(ptr->ip); 06795 Tcl_Release(ptr->ip); 06796 } 06797 06798 rb_thread_critical = thr_crit_bup; 06799 06800 return Qnil; 06801 } 06802 06803 06804 /* is deleted? */ 06805 static VALUE 06806 ip_has_invalid_namespace_p(self) 06807 VALUE self; 06808 { 06809 struct tcltkip *ptr = get_ip(self); 06810 06811 if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp *)NULL) { 06812 /* deleted IP */ 06813 return Qtrue; 06814 } 06815 06816 #if TCL_NAMESPACE_DEBUG 06817 if (rbtk_invalid_namespace(ptr)) { 06818 return Qtrue; 06819 } else { 06820 return Qfalse; 06821 } 06822 #else 06823 return Qfalse; 06824 #endif 06825 } 06826 06827 static VALUE 06828 ip_is_deleted_p(self) 06829 VALUE self; 06830 { 06831 struct tcltkip *ptr = get_ip(self); 06832 06833 if (deleted_ip(ptr)) { 06834 return Qtrue; 06835 } else { 06836 return Qfalse; 06837 } 06838 } 06839 06840 static VALUE 06841 ip_has_mainwindow_p_core(self, argc, argv) 06842 VALUE self; 06843 int argc; /* dummy */ 06844 VALUE *argv; /* dummy */ 06845 { 06846 struct tcltkip *ptr = get_ip(self); 06847 06848 if (deleted_ip(ptr) || !tk_stubs_init_p()) { 06849 return Qnil; 06850 } else if (Tk_MainWindow(ptr->ip) == (Tk_Window)NULL) { 06851 return Qfalse; 06852 } else { 06853 return Qtrue; 06854 } 06855 } 06856 06857 static VALUE 06858 ip_has_mainwindow_p(self) 06859 VALUE self; 06860 { 06861 return tk_funcall(ip_has_mainwindow_p_core, 0, (VALUE*)NULL, self); 06862 } 06863 06864 06865 /*** ruby string <=> tcl object ***/ 06866 #if TCL_MAJOR_VERSION >= 8 06867 static VALUE 06868 get_str_from_obj(obj) 06869 Tcl_Obj *obj; 06870 { 06871 int len, binary = 0; 06872 const char *s; 06873 volatile VALUE str; 06874 06875 #if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0 06876 s = Tcl_GetStringFromObj(obj, &len); 06877 #else 06878 #if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION <= 3 06879 /* TCL_VERSION 8.1 -- 8.3 */ 06880 if (Tcl_GetCharLength(obj) != Tcl_UniCharLen(Tcl_GetUnicode(obj))) { 06881 /* possibly binary string */ 06882 s = (char *)Tcl_GetByteArrayFromObj(obj, &len); 06883 binary = 1; 06884 } else { 06885 /* possibly text string */ 06886 s = Tcl_GetStringFromObj(obj, &len); 06887 } 06888 #else /* TCL_VERSION >= 8.4 */ 06889 if (IS_TCL_BYTEARRAY(obj)) { 06890 s = (char *)Tcl_GetByteArrayFromObj(obj, &len); 06891 binary = 1; 06892 } else { 06893 s = Tcl_GetStringFromObj(obj, &len); 06894 } 06895 06896 #endif 06897 #endif 06898 str = s ? rb_str_new(s, len) : rb_str_new2(""); 06899 if (binary) { 06900 #ifdef HAVE_RUBY_ENCODING_H 06901 rb_enc_associate_index(str, ENCODING_INDEX_BINARY); 06902 #endif 06903 rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); 06904 #if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1) 06905 } else { 06906 #ifdef HAVE_RUBY_ENCODING_H 06907 rb_enc_associate_index(str, ENCODING_INDEX_UTF8); 06908 #endif 06909 rb_ivar_set(str, ID_at_enc, ENCODING_NAME_UTF8); 06910 #endif 06911 } 06912 return str; 06913 } 06914 06915 static Tcl_Obj * 06916 get_obj_from_str(str) 06917 VALUE str; 06918 { 06919 const char *s = StringValuePtr(str); 06920 06921 #if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0 06922 return Tcl_NewStringObj((char*)s, RSTRING_LEN(str)); 06923 #else /* TCL_VERSION >= 8.1 */ 06924 VALUE enc = rb_attr_get(str, ID_at_enc); 06925 06926 if (!NIL_P(enc)) { 06927 StringValue(enc); 06928 if (strcmp(RSTRING_PTR(enc), "binary") == 0) { 06929 /* binary string */ 06930 return Tcl_NewByteArrayObj((const unsigned char *)s, RSTRING_LEN(str)); 06931 } else { 06932 /* text string */ 06933 return Tcl_NewStringObj(s, RSTRING_LEN(str)); 06934 } 06935 #ifdef HAVE_RUBY_ENCODING_H 06936 } else if (rb_enc_get_index(str) == ENCODING_INDEX_BINARY) { 06937 /* binary string */ 06938 return Tcl_NewByteArrayObj((const unsigned char *)s, RSTRING_LEN(str)); 06939 #endif 06940 } else if (memchr(s, 0, RSTRING_LEN(str))) { 06941 /* probably binary string */ 06942 return Tcl_NewByteArrayObj((const unsigned char *)s, RSTRING_LEN(str)); 06943 } else { 06944 /* probably text string */ 06945 return Tcl_NewStringObj(s, RSTRING_LEN(str)); 06946 } 06947 #endif 06948 } 06949 #endif /* ruby string <=> tcl object */ 06950 06951 static VALUE 06952 ip_get_result_string_obj(interp) 06953 Tcl_Interp *interp; 06954 { 06955 #if TCL_MAJOR_VERSION >= 8 06956 Tcl_Obj *retObj; 06957 volatile VALUE strval; 06958 06959 retObj = Tcl_GetObjResult(interp); 06960 Tcl_IncrRefCount(retObj); 06961 strval = get_str_from_obj(retObj); 06962 RbTk_OBJ_UNTRUST(strval); 06963 Tcl_ResetResult(interp); 06964 Tcl_DecrRefCount(retObj); 06965 return strval; 06966 #else 06967 return rb_tainted_str_new2(interp->result); 06968 #endif 06969 } 06970 06971 /* call Tcl/Tk functions on the eventloop thread */ 06972 static VALUE 06973 callq_safelevel_handler(arg, callq) 06974 VALUE arg; 06975 VALUE callq; 06976 { 06977 struct call_queue *q; 06978 06979 Data_Get_Struct(callq, struct call_queue, q); 06980 DUMP2("(safe-level handler) $SAFE = %d", q->safe_level); 06981 rb_set_safe_level(q->safe_level); 06982 return((q->func)(q->interp, q->argc, q->argv)); 06983 } 06984 06985 static int call_queue_handler _((Tcl_Event *, int)); 06986 static int 06987 call_queue_handler(evPtr, flags) 06988 Tcl_Event *evPtr; 06989 int flags; 06990 { 06991 struct call_queue *q = (struct call_queue *)evPtr; 06992 volatile VALUE ret; 06993 volatile VALUE q_dat; 06994 volatile VALUE thread = q->thread; 06995 struct tcltkip *ptr; 06996 06997 DUMP2("do_call_queue_handler : evPtr = %p", evPtr); 06998 DUMP2("call_queue_handler thread : %lx", rb_thread_current()); 06999 DUMP2("added by thread : %lx", thread); 07000 07001 if (*(q->done)) { 07002 DUMP1("processed by another event-loop"); 07003 return 0; 07004 } else { 07005 DUMP1("process it on current event-loop"); 07006 } 07007 07008 #ifdef RUBY_VM 07009 if (RTEST(rb_funcall(thread, ID_alive_p, 0)) 07010 && ! RTEST(rb_funcall(thread, ID_stop_p, 0))) { 07011 #else 07012 if (RTEST(rb_thread_alive_p(thread)) 07013 && ! RTEST(rb_funcall(thread, ID_stop_p, 0))) { 07014 #endif 07015 DUMP1("caller is not yet ready to receive the result -> pending"); 07016 return 0; 07017 } 07018 07019 /* process it */ 07020 *(q->done) = 1; 07021 07022 /* deleted ipterp ? */ 07023 ptr = get_ip(q->interp); 07024 if (deleted_ip(ptr)) { 07025 /* deleted IP --> ignore */ 07026 return 1; 07027 } 07028 07029 /* incr internal handler mark */ 07030 rbtk_internal_eventloop_handler++; 07031 07032 /* check safe-level */ 07033 if (rb_safe_level() != q->safe_level) { 07034 /* q_dat = Data_Wrap_Struct(rb_cData,0,-1,q); */ 07035 q_dat = Data_Wrap_Struct(rb_cData,call_queue_mark,-1,q); 07036 ret = rb_funcall(rb_proc_new(callq_safelevel_handler, q_dat), 07037 ID_call, 0); 07038 rb_gc_force_recycle(q_dat); 07039 q_dat = (VALUE)NULL; 07040 } else { 07041 DUMP2("call function (for caller thread:%lx)", thread); 07042 DUMP2("call function (current thread:%lx)", rb_thread_current()); 07043 ret = (q->func)(q->interp, q->argc, q->argv); 07044 } 07045 07046 /* set result */ 07047 RARRAY_PTR(q->result)[0] = ret; 07048 ret = (VALUE)NULL; 07049 07050 /* decr internal handler mark */ 07051 rbtk_internal_eventloop_handler--; 07052 07053 /* complete */ 07054 *(q->done) = -1; 07055 07056 /* unlink ruby objects */ 07057 q->argv = (VALUE*)NULL; 07058 q->interp = (VALUE)NULL; 07059 q->result = (VALUE)NULL; 07060 q->thread = (VALUE)NULL; 07061 07062 /* back to caller */ 07063 #ifdef RUBY_VM 07064 if (RTEST(rb_funcall(thread, ID_alive_p, 0, 0))) { 07065 #else 07066 if (RTEST(rb_thread_alive_p(thread))) { 07067 #endif 07068 DUMP2("back to caller (caller thread:%lx)", thread); 07069 DUMP2(" (current thread:%lx)", rb_thread_current()); 07070 #if CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE 07071 have_rb_thread_waiting_for_value = 1; 07072 rb_thread_wakeup(thread); 07073 #else 07074 rb_thread_run(thread); 07075 #endif 07076 DUMP1("finish back to caller"); 07077 #if DO_THREAD_SCHEDULE_AT_CALLBACK_DONE 07078 rb_thread_schedule(); 07079 #endif 07080 } else { 07081 DUMP2("caller is dead (caller thread:%lx)", thread); 07082 DUMP2(" (current thread:%lx)", rb_thread_current()); 07083 } 07084 07085 /* end of handler : remove it */ 07086 return 1; 07087 } 07088 07089 static VALUE 07090 tk_funcall(func, argc, argv, obj) 07091 VALUE (*func)(); 07092 int argc; 07093 VALUE *argv; 07094 VALUE obj; 07095 { 07096 struct call_queue *callq; 07097 struct tcltkip *ptr; 07098 int *alloc_done; 07099 int thr_crit_bup; 07100 int is_tk_evloop_thread; 07101 volatile VALUE current = rb_thread_current(); 07102 volatile VALUE ip_obj = obj; 07103 volatile VALUE result; 07104 volatile VALUE ret; 07105 struct timeval t; 07106 07107 if (!NIL_P(ip_obj) && rb_obj_is_kind_of(ip_obj, tcltkip_class)) { 07108 ptr = get_ip(ip_obj); 07109 if (deleted_ip(ptr)) return Qnil; 07110 } else { 07111 ptr = (struct tcltkip *)NULL; 07112 } 07113 07114 #ifdef RUBY_USE_NATIVE_THREAD 07115 if (ptr) { 07116 /* on Tcl interpreter */ 07117 is_tk_evloop_thread = (ptr->tk_thread_id == (Tcl_ThreadId) 0 07118 || ptr->tk_thread_id == Tcl_GetCurrentThread()); 07119 } else { 07120 /* on Tcl/Tk library */ 07121 is_tk_evloop_thread = (tk_eventloop_thread_id == (Tcl_ThreadId) 0 07122 || tk_eventloop_thread_id == Tcl_GetCurrentThread()); 07123 } 07124 #else 07125 is_tk_evloop_thread = 1; 07126 #endif 07127 07128 if (is_tk_evloop_thread 07129 && (NIL_P(eventloop_thread) || current == eventloop_thread) 07130 ) { 07131 if (NIL_P(eventloop_thread)) { 07132 DUMP2("tk_funcall from thread:%lx but no eventloop", current); 07133 } else { 07134 DUMP2("tk_funcall from current eventloop %lx", current); 07135 } 07136 result = (func)(ip_obj, argc, argv); 07137 if (rb_obj_is_kind_of(result, rb_eException)) { 07138 rb_exc_raise(result); 07139 } 07140 return result; 07141 } 07142 07143 DUMP2("tk_funcall from thread %lx (NOT current eventloop)", current); 07144 07145 thr_crit_bup = rb_thread_critical; 07146 rb_thread_critical = Qtrue; 07147 07148 /* allocate memory (argv cross over thread : must be in heap) */ 07149 if (argv) { 07150 /* VALUE *temp = ALLOC_N(VALUE, argc); */ 07151 VALUE *temp = (VALUE*)ckalloc(sizeof(VALUE) * argc); 07152 #if 0 /* use Tcl_Preserve/Release */ 07153 Tcl_Preserve((ClientData)temp); /* XXXXXXXX */ 07154 #endif 07155 MEMCPY(temp, argv, VALUE, argc); 07156 argv = temp; 07157 } 07158 07159 /* allocate memory (keep result) */ 07160 /* alloc_done = (int*)ALLOC(int); */ 07161 alloc_done = (int*)ckalloc(sizeof(int)); 07162 #if 0 /* use Tcl_Preserve/Release */ 07163 Tcl_Preserve((ClientData)alloc_done); /* XXXXXXXX */ 07164 #endif 07165 *alloc_done = 0; 07166 07167 /* allocate memory (freed by Tcl_ServiceEvent) */ 07168 /* callq = (struct call_queue *)Tcl_Alloc(sizeof(struct call_queue)); */ 07169 callq = (struct call_queue *)ckalloc(sizeof(struct call_queue)); 07170 #if 0 /* use Tcl_Preserve/Release */ 07171 Tcl_Preserve(callq); 07172 #endif 07173 07174 /* allocate result obj */ 07175 result = rb_ary_new3(1, Qnil); 07176 07177 /* construct event data */ 07178 callq->done = alloc_done; 07179 callq->func = func; 07180 callq->argc = argc; 07181 callq->argv = argv; 07182 callq->interp = ip_obj; 07183 callq->result = result; 07184 callq->thread = current; 07185 callq->safe_level = rb_safe_level(); 07186 callq->ev.proc = call_queue_handler; 07187 07188 /* add the handler to Tcl event queue */ 07189 DUMP1("add handler"); 07190 #ifdef RUBY_USE_NATIVE_THREAD 07191 if (ptr && ptr->tk_thread_id) { 07192 /* Tcl_ThreadQueueEvent(ptr->tk_thread_id, 07193 &(callq->ev), TCL_QUEUE_HEAD); */ 07194 Tcl_ThreadQueueEvent(ptr->tk_thread_id, 07195 (Tcl_Event*)callq, TCL_QUEUE_HEAD); 07196 Tcl_ThreadAlert(ptr->tk_thread_id); 07197 } else if (tk_eventloop_thread_id) { 07198 /* Tcl_ThreadQueueEvent(tk_eventloop_thread_id, 07199 &(callq->ev), TCL_QUEUE_HEAD); */ 07200 Tcl_ThreadQueueEvent(tk_eventloop_thread_id, 07201 (Tcl_Event*)callq, TCL_QUEUE_HEAD); 07202 Tcl_ThreadAlert(tk_eventloop_thread_id); 07203 } else { 07204 /* Tcl_QueueEvent(&(callq->ev), TCL_QUEUE_HEAD); */ 07205 Tcl_QueueEvent((Tcl_Event*)callq, TCL_QUEUE_HEAD); 07206 } 07207 #else 07208 /* Tcl_QueueEvent(&(callq->ev), TCL_QUEUE_HEAD); */ 07209 Tcl_QueueEvent((Tcl_Event*)callq, TCL_QUEUE_HEAD); 07210 #endif 07211 07212 rb_thread_critical = thr_crit_bup; 07213 07214 /* wait for the handler to be processed */ 07215 t.tv_sec = 0; 07216 t.tv_usec = (long)((EVENT_HANDLER_TIMEOUT)*1000.0); 07217 07218 DUMP2("callq wait for handler (current thread:%lx)", current); 07219 while(*alloc_done >= 0) { 07220 DUMP2("*** callq wait for handler (current thread:%lx)", current); 07221 /* rb_thread_stop(); */ 07222 /* rb_thread_sleep_forever(); */ 07223 rb_thread_wait_for(t); 07224 DUMP2("*** callq wakeup (current thread:%lx)", current); 07225 DUMP2("*** (eventloop thread:%lx)", eventloop_thread); 07226 if (NIL_P(eventloop_thread)) { 07227 DUMP1("*** callq lost eventloop thread"); 07228 break; 07229 } 07230 } 07231 DUMP2("back from handler (current thread:%lx)", current); 07232 07233 /* get result & free allocated memory */ 07234 ret = RARRAY_PTR(result)[0]; 07235 #if 0 /* use Tcl_EventuallyFree */ 07236 Tcl_EventuallyFree((ClientData)alloc_done, TCL_DYNAMIC); /* XXXXXXXX */ 07237 #else 07238 #if 0 /* use Tcl_Preserve/Release */ 07239 Tcl_Release((ClientData)alloc_done); /* XXXXXXXX */ 07240 #else 07241 /* free(alloc_done); */ 07242 ckfree((char*)alloc_done); 07243 #endif 07244 #endif 07245 /* if (argv) free(argv); */ 07246 if (argv) { 07247 /* if argv != NULL, alloc as 'temp' */ 07248 int i; 07249 for(i = 0; i < argc; i++) { argv[i] = (VALUE)NULL; } 07250 07251 #if 0 /* use Tcl_EventuallyFree */ 07252 Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ 07253 #else 07254 #if 0 /* use Tcl_Preserve/Release */ 07255 Tcl_Release((ClientData)argv); /* XXXXXXXX */ 07256 #else 07257 ckfree((char*)argv); 07258 #endif 07259 #endif 07260 } 07261 07262 #if 0 /* callq is freed by Tcl_ServiceEvent */ 07263 #if 0 /* use Tcl_Preserve/Release */ 07264 Tcl_Release(callq); 07265 #else 07266 ckfree((char*)callq); 07267 #endif 07268 #endif 07269 07270 /* exception? */ 07271 if (rb_obj_is_kind_of(ret, rb_eException)) { 07272 DUMP1("raise exception"); 07273 /* rb_exc_raise(ret); */ 07274 rb_exc_raise(rb_exc_new3(rb_obj_class(ret), 07275 rb_funcall(ret, ID_to_s, 0, 0))); 07276 } 07277 07278 DUMP1("exit tk_funcall"); 07279 return ret; 07280 } 07281 07282 07283 /* eval string in tcl by Tcl_Eval() */ 07284 #if TCL_MAJOR_VERSION >= 8 07285 struct call_eval_info { 07286 struct tcltkip *ptr; 07287 Tcl_Obj *cmd; 07288 }; 07289 07290 static VALUE 07291 #ifdef HAVE_PROTOTYPES 07292 call_tcl_eval(VALUE arg) 07293 #else 07294 call_tcl_eval(arg) 07295 VALUE arg; 07296 #endif 07297 { 07298 struct call_eval_info *inf = (struct call_eval_info *)arg; 07299 07300 Tcl_AllowExceptions(inf->ptr->ip); 07301 inf->ptr->return_value = Tcl_EvalObj(inf->ptr->ip, inf->cmd); 07302 07303 return Qnil; 07304 } 07305 #endif 07306 07307 static VALUE 07308 ip_eval_real(self, cmd_str, cmd_len) 07309 VALUE self; 07310 char *cmd_str; 07311 int cmd_len; 07312 { 07313 volatile VALUE ret; 07314 struct tcltkip *ptr = get_ip(self); 07315 int thr_crit_bup; 07316 07317 #if TCL_MAJOR_VERSION >= 8 07318 /* call Tcl_EvalObj() */ 07319 { 07320 Tcl_Obj *cmd; 07321 07322 thr_crit_bup = rb_thread_critical; 07323 rb_thread_critical = Qtrue; 07324 07325 cmd = Tcl_NewStringObj(cmd_str, cmd_len); 07326 Tcl_IncrRefCount(cmd); 07327 07328 /* ip is deleted? */ 07329 if (deleted_ip(ptr)) { 07330 Tcl_DecrRefCount(cmd); 07331 rb_thread_critical = thr_crit_bup; 07332 ptr->return_value = TCL_OK; 07333 return rb_tainted_str_new2(""); 07334 } else { 07335 int status; 07336 struct call_eval_info inf; 07337 07338 /* Tcl_Preserve(ptr->ip); */ 07339 rbtk_preserve_ip(ptr); 07340 07341 #if 0 07342 ptr->return_value = Tcl_EvalObj(ptr->ip, cmd); 07343 /* ptr->return_value = Tcl_GlobalEvalObj(ptr->ip, cmd); */ 07344 #else 07345 inf.ptr = ptr; 07346 inf.cmd = cmd; 07347 ret = rb_protect(call_tcl_eval, (VALUE)&inf, &status); 07348 switch(status) { 07349 case TAG_RAISE: 07350 if (NIL_P(rb_errinfo())) { 07351 rbtk_pending_exception = rb_exc_new2(rb_eException, 07352 "unknown exception"); 07353 } else { 07354 rbtk_pending_exception = rb_errinfo(); 07355 } 07356 break; 07357 07358 case TAG_FATAL: 07359 if (NIL_P(rb_errinfo())) { 07360 rbtk_pending_exception = rb_exc_new2(rb_eFatal, "FATAL"); 07361 } else { 07362 rbtk_pending_exception = rb_errinfo(); 07363 } 07364 } 07365 #endif 07366 } 07367 07368 Tcl_DecrRefCount(cmd); 07369 07370 } 07371 07372 if (pending_exception_check1(thr_crit_bup, ptr)) { 07373 rbtk_release_ip(ptr); 07374 return rbtk_pending_exception; 07375 } 07376 07377 /* if (ptr->return_value == TCL_ERROR) { */ 07378 if (ptr->return_value != TCL_OK) { 07379 if (event_loop_abort_on_exc > 0 && !Tcl_InterpDeleted(ptr->ip)) { 07380 volatile VALUE exc; 07381 07382 switch (ptr->return_value) { 07383 case TCL_RETURN: 07384 exc = create_ip_exc(self, eTkCallbackReturn, 07385 "ip_eval_real receives TCL_RETURN"); 07386 case TCL_BREAK: 07387 exc = create_ip_exc(self, eTkCallbackBreak, 07388 "ip_eval_real receives TCL_BREAK"); 07389 case TCL_CONTINUE: 07390 exc = create_ip_exc(self, eTkCallbackContinue, 07391 "ip_eval_real receives TCL_CONTINUE"); 07392 default: 07393 exc = create_ip_exc(self, rb_eRuntimeError, "%s", 07394 Tcl_GetStringResult(ptr->ip)); 07395 } 07396 07397 rbtk_release_ip(ptr); 07398 rb_thread_critical = thr_crit_bup; 07399 return exc; 07400 } else { 07401 if (event_loop_abort_on_exc < 0) { 07402 rb_warning("%s (ignore)", Tcl_GetStringResult(ptr->ip)); 07403 } else { 07404 rb_warn("%s (ignore)", Tcl_GetStringResult(ptr->ip)); 07405 } 07406 Tcl_ResetResult(ptr->ip); 07407 rbtk_release_ip(ptr); 07408 rb_thread_critical = thr_crit_bup; 07409 return rb_tainted_str_new2(""); 07410 } 07411 } 07412 07413 /* pass back the result (as string) */ 07414 ret = ip_get_result_string_obj(ptr->ip); 07415 rbtk_release_ip(ptr); 07416 rb_thread_critical = thr_crit_bup; 07417 return ret; 07418 07419 #else /* TCL_MAJOR_VERSION < 8 */ 07420 DUMP2("Tcl_Eval(%s)", cmd_str); 07421 07422 /* ip is deleted? */ 07423 if (deleted_ip(ptr)) { 07424 ptr->return_value = TCL_OK; 07425 return rb_tainted_str_new2(""); 07426 } else { 07427 /* Tcl_Preserve(ptr->ip); */ 07428 rbtk_preserve_ip(ptr); 07429 ptr->return_value = Tcl_Eval(ptr->ip, cmd_str); 07430 /* ptr->return_value = Tcl_GlobalEval(ptr->ip, cmd_str); */ 07431 } 07432 07433 if (pending_exception_check1(thr_crit_bup, ptr)) { 07434 rbtk_release_ip(ptr); 07435 return rbtk_pending_exception; 07436 } 07437 07438 /* if (ptr->return_value == TCL_ERROR) { */ 07439 if (ptr->return_value != TCL_OK) { 07440 volatile VALUE exc; 07441 07442 switch (ptr->return_value) { 07443 case TCL_RETURN: 07444 exc = create_ip_exc(self, eTkCallbackReturn, 07445 "ip_eval_real receives TCL_RETURN"); 07446 case TCL_BREAK: 07447 exc = create_ip_exc(self, eTkCallbackBreak, 07448 "ip_eval_real receives TCL_BREAK"); 07449 case TCL_CONTINUE: 07450 exc = create_ip_exc(self, eTkCallbackContinue, 07451 "ip_eval_real receives TCL_CONTINUE"); 07452 default: 07453 exc = create_ip_exc(self, rb_eRuntimeError, "%s", ptr->ip->result); 07454 } 07455 07456 rbtk_release_ip(ptr); 07457 return exc; 07458 } 07459 DUMP2("(TCL_Eval result) %d", ptr->return_value); 07460 07461 /* pass back the result (as string) */ 07462 ret = ip_get_result_string_obj(ptr->ip); 07463 rbtk_release_ip(ptr); 07464 return ret; 07465 #endif 07466 } 07467 07468 static VALUE 07469 evq_safelevel_handler(arg, evq) 07470 VALUE arg; 07471 VALUE evq; 07472 { 07473 struct eval_queue *q; 07474 07475 Data_Get_Struct(evq, struct eval_queue, q); 07476 DUMP2("(safe-level handler) $SAFE = %d", q->safe_level); 07477 rb_set_safe_level(q->safe_level); 07478 return ip_eval_real(q->interp, q->str, q->len); 07479 } 07480 07481 int eval_queue_handler _((Tcl_Event *, int)); 07482 int 07483 eval_queue_handler(evPtr, flags) 07484 Tcl_Event *evPtr; 07485 int flags; 07486 { 07487 struct eval_queue *q = (struct eval_queue *)evPtr; 07488 volatile VALUE ret; 07489 volatile VALUE q_dat; 07490 volatile VALUE thread = q->thread; 07491 struct tcltkip *ptr; 07492 07493 DUMP2("do_eval_queue_handler : evPtr = %p", evPtr); 07494 DUMP2("eval_queue_thread : %lx", rb_thread_current()); 07495 DUMP2("added by thread : %lx", thread); 07496 07497 if (*(q->done)) { 07498 DUMP1("processed by another event-loop"); 07499 return 0; 07500 } else { 07501 DUMP1("process it on current event-loop"); 07502 } 07503 07504 #ifdef RUBY_VM 07505 if (RTEST(rb_funcall(thread, ID_alive_p, 0)) 07506 && ! RTEST(rb_funcall(thread, ID_stop_p, 0))) { 07507 #else 07508 if (RTEST(rb_thread_alive_p(thread)) 07509 && ! RTEST(rb_funcall(thread, ID_stop_p, 0))) { 07510 #endif 07511 DUMP1("caller is not yet ready to receive the result -> pending"); 07512 return 0; 07513 } 07514 07515 /* process it */ 07516 *(q->done) = 1; 07517 07518 /* deleted ipterp ? */ 07519 ptr = get_ip(q->interp); 07520 if (deleted_ip(ptr)) { 07521 /* deleted IP --> ignore */ 07522 return 1; 07523 } 07524 07525 /* incr internal handler mark */ 07526 rbtk_internal_eventloop_handler++; 07527 07528 /* check safe-level */ 07529 if (rb_safe_level() != q->safe_level) { 07530 #ifdef HAVE_NATIVETHREAD 07531 #ifndef RUBY_USE_NATIVE_THREAD 07532 if (!ruby_native_thread_p()) { 07533 rb_bug("cross-thread violation on eval_queue_handler()"); 07534 } 07535 #endif 07536 #endif 07537 /* q_dat = Data_Wrap_Struct(rb_cData,0,-1,q); */ 07538 q_dat = Data_Wrap_Struct(rb_cData,eval_queue_mark,-1,q); 07539 ret = rb_funcall(rb_proc_new(evq_safelevel_handler, q_dat), 07540 ID_call, 0); 07541 rb_gc_force_recycle(q_dat); 07542 q_dat = (VALUE)NULL; 07543 } else { 07544 ret = ip_eval_real(q->interp, q->str, q->len); 07545 } 07546 07547 /* set result */ 07548 RARRAY_PTR(q->result)[0] = ret; 07549 ret = (VALUE)NULL; 07550 07551 /* decr internal handler mark */ 07552 rbtk_internal_eventloop_handler--; 07553 07554 /* complete */ 07555 *(q->done) = -1; 07556 07557 /* unlink ruby objects */ 07558 q->interp = (VALUE)NULL; 07559 q->result = (VALUE)NULL; 07560 q->thread = (VALUE)NULL; 07561 07562 /* back to caller */ 07563 #ifdef RUBY_VM 07564 if (RTEST(rb_funcall(thread, ID_alive_p, 0, 0))) { 07565 #else 07566 if (RTEST(rb_thread_alive_p(thread))) { 07567 #endif 07568 DUMP2("back to caller (caller thread:%lx)", thread); 07569 DUMP2(" (current thread:%lx)", rb_thread_current()); 07570 #if CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE 07571 have_rb_thread_waiting_for_value = 1; 07572 rb_thread_wakeup(thread); 07573 #else 07574 rb_thread_run(thread); 07575 #endif 07576 DUMP1("finish back to caller"); 07577 #if DO_THREAD_SCHEDULE_AT_CALLBACK_DONE 07578 rb_thread_schedule(); 07579 #endif 07580 } else { 07581 DUMP2("caller is dead (caller thread:%lx)", thread); 07582 DUMP2(" (current thread:%lx)", rb_thread_current()); 07583 } 07584 07585 /* end of handler : remove it */ 07586 return 1; 07587 } 07588 07589 static VALUE 07590 ip_eval(self, str) 07591 VALUE self; 07592 VALUE str; 07593 { 07594 struct eval_queue *evq; 07595 #ifdef RUBY_USE_NATIVE_THREAD 07596 struct tcltkip *ptr; 07597 #endif 07598 char *eval_str; 07599 int *alloc_done; 07600 int thr_crit_bup; 07601 volatile VALUE current = rb_thread_current(); 07602 volatile VALUE ip_obj = self; 07603 volatile VALUE result; 07604 volatile VALUE ret; 07605 Tcl_QueuePosition position; 07606 struct timeval t; 07607 07608 thr_crit_bup = rb_thread_critical; 07609 rb_thread_critical = Qtrue; 07610 StringValue(str); 07611 rb_thread_critical = thr_crit_bup; 07612 07613 #ifdef RUBY_USE_NATIVE_THREAD 07614 ptr = get_ip(ip_obj); 07615 DUMP2("eval status: ptr->tk_thread_id %p", ptr->tk_thread_id); 07616 DUMP2("eval status: Tcl_GetCurrentThread %p", Tcl_GetCurrentThread()); 07617 #else 07618 DUMP2("status: Tcl_GetCurrentThread %p", Tcl_GetCurrentThread()); 07619 #endif 07620 DUMP2("status: eventloopt_thread %lx", eventloop_thread); 07621 07622 if ( 07623 #ifdef RUBY_USE_NATIVE_THREAD 07624 (ptr->tk_thread_id == 0 || ptr->tk_thread_id == Tcl_GetCurrentThread()) 07625 && 07626 #endif 07627 (NIL_P(eventloop_thread) || current == eventloop_thread) 07628 ) { 07629 if (NIL_P(eventloop_thread)) { 07630 DUMP2("eval from thread:%lx but no eventloop", current); 07631 } else { 07632 DUMP2("eval from current eventloop %lx", current); 07633 } 07634 result = ip_eval_real(self, RSTRING_PTR(str), RSTRING_LEN(str)); 07635 if (rb_obj_is_kind_of(result, rb_eException)) { 07636 rb_exc_raise(result); 07637 } 07638 return result; 07639 } 07640 07641 DUMP2("eval from thread %lx (NOT current eventloop)", current); 07642 07643 thr_crit_bup = rb_thread_critical; 07644 rb_thread_critical = Qtrue; 07645 07646 /* allocate memory (keep result) */ 07647 /* alloc_done = (int*)ALLOC(int); */ 07648 alloc_done = (int*)ckalloc(sizeof(int)); 07649 #if 0 /* use Tcl_Preserve/Release */ 07650 Tcl_Preserve((ClientData)alloc_done); /* XXXXXXXX */ 07651 #endif 07652 *alloc_done = 0; 07653 07654 /* eval_str = ALLOC_N(char, RSTRING_LEN(str) + 1); */ 07655 eval_str = ckalloc(sizeof(char) * (RSTRING_LEN(str) + 1)); 07656 #if 0 /* use Tcl_Preserve/Release */ 07657 Tcl_Preserve((ClientData)eval_str); /* XXXXXXXX */ 07658 #endif 07659 memcpy(eval_str, RSTRING_PTR(str), RSTRING_LEN(str)); 07660 eval_str[RSTRING_LEN(str)] = 0; 07661 07662 /* allocate memory (freed by Tcl_ServiceEvent) */ 07663 /* evq = (struct eval_queue *)Tcl_Alloc(sizeof(struct eval_queue)); */ 07664 evq = (struct eval_queue *)ckalloc(sizeof(struct eval_queue)); 07665 #if 0 /* use Tcl_Preserve/Release */ 07666 Tcl_Preserve(evq); 07667 #endif 07668 07669 /* allocate result obj */ 07670 result = rb_ary_new3(1, Qnil); 07671 07672 /* construct event data */ 07673 evq->done = alloc_done; 07674 evq->str = eval_str; 07675 evq->len = RSTRING_LEN(str); 07676 evq->interp = ip_obj; 07677 evq->result = result; 07678 evq->thread = current; 07679 evq->safe_level = rb_safe_level(); 07680 evq->ev.proc = eval_queue_handler; 07681 07682 position = TCL_QUEUE_TAIL; 07683 07684 /* add the handler to Tcl event queue */ 07685 DUMP1("add handler"); 07686 #ifdef RUBY_USE_NATIVE_THREAD 07687 if (ptr->tk_thread_id) { 07688 /* Tcl_ThreadQueueEvent(ptr->tk_thread_id, &(evq->ev), position); */ 07689 Tcl_ThreadQueueEvent(ptr->tk_thread_id, (Tcl_Event*)evq, position); 07690 Tcl_ThreadAlert(ptr->tk_thread_id); 07691 } else if (tk_eventloop_thread_id) { 07692 Tcl_ThreadQueueEvent(tk_eventloop_thread_id, (Tcl_Event*)evq, position); 07693 /* Tcl_ThreadQueueEvent(tk_eventloop_thread_id, 07694 &(evq->ev), position); */ 07695 Tcl_ThreadAlert(tk_eventloop_thread_id); 07696 } else { 07697 /* Tcl_QueueEvent(&(evq->ev), position); */ 07698 Tcl_QueueEvent((Tcl_Event*)evq, position); 07699 } 07700 #else 07701 /* Tcl_QueueEvent(&(evq->ev), position); */ 07702 Tcl_QueueEvent((Tcl_Event*)evq, position); 07703 #endif 07704 07705 rb_thread_critical = thr_crit_bup; 07706 07707 /* wait for the handler to be processed */ 07708 t.tv_sec = 0; 07709 t.tv_usec = (long)((EVENT_HANDLER_TIMEOUT)*1000.0); 07710 07711 DUMP2("evq wait for handler (current thread:%lx)", current); 07712 while(*alloc_done >= 0) { 07713 DUMP2("*** evq wait for handler (current thread:%lx)", current); 07714 /* rb_thread_stop(); */ 07715 /* rb_thread_sleep_forever(); */ 07716 rb_thread_wait_for(t); 07717 DUMP2("*** evq wakeup (current thread:%lx)", current); 07718 DUMP2("*** (eventloop thread:%lx)", eventloop_thread); 07719 if (NIL_P(eventloop_thread)) { 07720 DUMP1("*** evq lost eventloop thread"); 07721 break; 07722 } 07723 } 07724 DUMP2("back from handler (current thread:%lx)", current); 07725 07726 /* get result & free allocated memory */ 07727 ret = RARRAY_PTR(result)[0]; 07728 07729 #if 0 /* use Tcl_EventuallyFree */ 07730 Tcl_EventuallyFree((ClientData)alloc_done, TCL_DYNAMIC); /* XXXXXXXX */ 07731 #else 07732 #if 0 /* use Tcl_Preserve/Release */ 07733 Tcl_Release((ClientData)alloc_done); /* XXXXXXXX */ 07734 #else 07735 /* free(alloc_done); */ 07736 ckfree((char*)alloc_done); 07737 #endif 07738 #endif 07739 #if 0 /* use Tcl_EventuallyFree */ 07740 Tcl_EventuallyFree((ClientData)eval_str, TCL_DYNAMIC); /* XXXXXXXX */ 07741 #else 07742 #if 0 /* use Tcl_Preserve/Release */ 07743 Tcl_Release((ClientData)eval_str); /* XXXXXXXX */ 07744 #else 07745 /* free(eval_str); */ 07746 ckfree(eval_str); 07747 #endif 07748 #endif 07749 #if 0 /* evq is freed by Tcl_ServiceEvent */ 07750 #if 0 /* use Tcl_Preserve/Release */ 07751 Tcl_Release(evq); 07752 #else 07753 ckfree((char*)evq); 07754 #endif 07755 #endif 07756 07757 if (rb_obj_is_kind_of(ret, rb_eException)) { 07758 DUMP1("raise exception"); 07759 /* rb_exc_raise(ret); */ 07760 rb_exc_raise(rb_exc_new3(rb_obj_class(ret), 07761 rb_funcall(ret, ID_to_s, 0, 0))); 07762 } 07763 07764 return ret; 07765 } 07766 07767 07768 static int 07769 ip_cancel_eval_core(interp, msg, flag) 07770 Tcl_Interp *interp; 07771 VALUE msg; 07772 int flag; 07773 { 07774 #if TCL_MAJOR_VERSION < 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION < 6) 07775 rb_raise(rb_eNotImpError, 07776 "cancel_eval is supported Tcl/Tk8.6 or later."); 07777 #else 07778 Tcl_Obj *msg_obj; 07779 07780 if (NIL_P(msg)) { 07781 msg_obj = NULL; 07782 } else { 07783 msg_obj = Tcl_NewStringObj(RSTRING_PTR(msg), RSTRING_LEN(msg)); 07784 Tcl_IncrRefCount(msg_obj); 07785 } 07786 07787 return Tcl_CancelEval(interp, msg_obj, 0, flag); 07788 #endif 07789 } 07790 07791 static VALUE 07792 ip_cancel_eval(argc, argv, self) 07793 int argc; 07794 VALUE *argv; 07795 VALUE self; 07796 { 07797 VALUE retval; 07798 07799 if (rb_scan_args(argc, argv, "01", &retval) == 0) { 07800 retval = Qnil; 07801 } 07802 if (ip_cancel_eval_core(get_ip(self)->ip, retval, 0) == TCL_OK) { 07803 return Qtrue; 07804 } else { 07805 return Qfalse; 07806 } 07807 } 07808 07809 #ifndef TCL_CANCEL_UNWIND 07810 #define TCL_CANCEL_UNWIND 0x100000 07811 #endif 07812 static VALUE 07813 ip_cancel_eval_unwind(argc, argv, self) 07814 int argc; 07815 VALUE *argv; 07816 VALUE self; 07817 { 07818 int flag = 0; 07819 VALUE retval; 07820 07821 if (rb_scan_args(argc, argv, "01", &retval) == 0) { 07822 retval = Qnil; 07823 } 07824 07825 flag |= TCL_CANCEL_UNWIND; 07826 if (ip_cancel_eval_core(get_ip(self)->ip, retval, flag) == TCL_OK) { 07827 return Qtrue; 07828 } else { 07829 return Qfalse; 07830 } 07831 } 07832 07833 /* restart Tk */ 07834 static VALUE 07835 lib_restart_core(interp, argc, argv) 07836 VALUE interp; 07837 int argc; /* dummy */ 07838 VALUE *argv; /* dummy */ 07839 { 07840 volatile VALUE exc; 07841 struct tcltkip *ptr = get_ip(interp); 07842 int thr_crit_bup; 07843 07844 /* rb_secure(4); */ /* already checked */ 07845 07846 /* tcl_stubs_check(); */ /* already checked */ 07847 07848 /* ip is deleted? */ 07849 if (deleted_ip(ptr)) { 07850 return rb_exc_new2(rb_eRuntimeError, "interpreter is deleted"); 07851 } 07852 07853 thr_crit_bup = rb_thread_critical; 07854 rb_thread_critical = Qtrue; 07855 07856 /* Tcl_Preserve(ptr->ip); */ 07857 rbtk_preserve_ip(ptr); 07858 07859 /* destroy the root wdiget */ 07860 ptr->return_value = Tcl_Eval(ptr->ip, "destroy ."); 07861 /* ignore ERROR */ 07862 DUMP2("(TCL_Eval result) %d", ptr->return_value); 07863 Tcl_ResetResult(ptr->ip); 07864 07865 #if TCL_MAJOR_VERSION >= 8 07866 /* delete namespace ( tested on tk8.4.5 ) */ 07867 ptr->return_value = Tcl_Eval(ptr->ip, "namespace delete ::tk::msgcat"); 07868 /* ignore ERROR */ 07869 DUMP2("(TCL_Eval result) %d", ptr->return_value); 07870 Tcl_ResetResult(ptr->ip); 07871 #endif 07872 07873 /* delete trace proc ( tested on tk8.4.5 ) */ 07874 ptr->return_value = Tcl_Eval(ptr->ip, "trace vdelete ::tk_strictMotif w ::tk::EventMotifBindings"); 07875 /* ignore ERROR */ 07876 DUMP2("(TCL_Eval result) %d", ptr->return_value); 07877 Tcl_ResetResult(ptr->ip); 07878 07879 /* execute Tk_Init or Tk_SafeInit */ 07880 exc = tcltkip_init_tk(interp); 07881 if (!NIL_P(exc)) { 07882 rb_thread_critical = thr_crit_bup; 07883 rbtk_release_ip(ptr); 07884 return exc; 07885 } 07886 07887 /* Tcl_Release(ptr->ip); */ 07888 rbtk_release_ip(ptr); 07889 07890 rb_thread_critical = thr_crit_bup; 07891 07892 /* return Qnil; */ 07893 return interp; 07894 } 07895 07896 static VALUE 07897 lib_restart(self) 07898 VALUE self; 07899 { 07900 struct tcltkip *ptr = get_ip(self); 07901 07902 rb_secure(4); 07903 07904 tcl_stubs_check(); 07905 07906 /* ip is deleted? */ 07907 if (deleted_ip(ptr)) { 07908 rb_raise(rb_eRuntimeError, "interpreter is deleted"); 07909 } 07910 07911 return tk_funcall(lib_restart_core, 0, (VALUE*)NULL, self); 07912 } 07913 07914 07915 static VALUE 07916 ip_restart(self) 07917 VALUE self; 07918 { 07919 struct tcltkip *ptr = get_ip(self); 07920 07921 rb_secure(4); 07922 07923 tcl_stubs_check(); 07924 07925 /* ip is deleted? */ 07926 if (deleted_ip(ptr)) { 07927 rb_raise(rb_eRuntimeError, "interpreter is deleted"); 07928 } 07929 07930 if (Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL) { 07931 /* slave IP */ 07932 return Qnil; 07933 } 07934 return lib_restart(self); 07935 } 07936 07937 static VALUE 07938 lib_toUTF8_core(ip_obj, src, encodename) 07939 VALUE ip_obj; 07940 VALUE src; 07941 VALUE encodename; 07942 { 07943 volatile VALUE str = src; 07944 07945 #ifdef TCL_UTF_MAX 07946 Tcl_Interp *interp; 07947 Tcl_Encoding encoding; 07948 Tcl_DString dstr; 07949 int taint_flag = OBJ_TAINTED(str); 07950 struct tcltkip *ptr; 07951 char *buf; 07952 int thr_crit_bup; 07953 #endif 07954 07955 tcl_stubs_check(); 07956 07957 if (NIL_P(src)) { 07958 return rb_str_new2(""); 07959 } 07960 07961 #ifdef TCL_UTF_MAX 07962 if (NIL_P(ip_obj)) { 07963 interp = (Tcl_Interp *)NULL; 07964 } else { 07965 ptr = get_ip(ip_obj); 07966 07967 /* ip is deleted? */ 07968 if (deleted_ip(ptr)) { 07969 interp = (Tcl_Interp *)NULL; 07970 } else { 07971 interp = ptr->ip; 07972 } 07973 } 07974 07975 thr_crit_bup = rb_thread_critical; 07976 rb_thread_critical = Qtrue; 07977 07978 if (NIL_P(encodename)) { 07979 if (TYPE(str) == T_STRING) { 07980 volatile VALUE enc; 07981 07982 #ifdef HAVE_RUBY_ENCODING_H 07983 enc = rb_funcall(rb_obj_encoding(str), ID_to_s, 0, 0); 07984 #else 07985 enc = rb_attr_get(str, ID_at_enc); 07986 #endif 07987 if (NIL_P(enc)) { 07988 if (NIL_P(ip_obj)) { 07989 encoding = (Tcl_Encoding)NULL; 07990 } else { 07991 enc = rb_attr_get(ip_obj, ID_at_enc); 07992 if (NIL_P(enc)) { 07993 encoding = (Tcl_Encoding)NULL; 07994 } else { 07995 /* StringValue(enc); */ 07996 enc = rb_funcall(enc, ID_to_s, 0, 0); 07997 /* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); */ 07998 if (!RSTRING_LEN(enc)) { 07999 encoding = (Tcl_Encoding)NULL; 08000 } else { 08001 encoding = Tcl_GetEncoding((Tcl_Interp*)NULL, 08002 RSTRING_PTR(enc)); 08003 if (encoding == (Tcl_Encoding)NULL) { 08004 rb_warning("Tk-interp has unknown encoding information (@encoding:'%s')", RSTRING_PTR(enc)); 08005 } 08006 } 08007 } 08008 } 08009 } else { 08010 StringValue(enc); 08011 if (strcmp(RSTRING_PTR(enc), "binary") == 0) { 08012 #ifdef HAVE_RUBY_ENCODING_H 08013 rb_enc_associate_index(str, ENCODING_INDEX_BINARY); 08014 #endif 08015 rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); 08016 rb_thread_critical = thr_crit_bup; 08017 return str; 08018 } 08019 /* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); */ 08020 encoding = Tcl_GetEncoding((Tcl_Interp*)NULL, 08021 RSTRING_PTR(enc)); 08022 if (encoding == (Tcl_Encoding)NULL) { 08023 rb_warning("string has unknown encoding information (@encoding:'%s')", RSTRING_PTR(enc)); 08024 } 08025 } 08026 } else { 08027 encoding = (Tcl_Encoding)NULL; 08028 } 08029 } else { 08030 StringValue(encodename); 08031 if (strcmp(RSTRING_PTR(encodename), "binary") == 0) { 08032 #ifdef HAVE_RUBY_ENCODING_H 08033 rb_enc_associate_index(str, ENCODING_INDEX_BINARY); 08034 #endif 08035 rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); 08036 rb_thread_critical = thr_crit_bup; 08037 return str; 08038 } 08039 /* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(encodename)); */ 08040 encoding = Tcl_GetEncoding((Tcl_Interp*)NULL, RSTRING_PTR(encodename)); 08041 if (encoding == (Tcl_Encoding)NULL) { 08042 /* 08043 rb_warning("unknown encoding name '%s'", 08044 RSTRING_PTR(encodename)); 08045 */ 08046 rb_raise(rb_eArgError, "unknown encoding name '%s'", 08047 RSTRING_PTR(encodename)); 08048 } 08049 } 08050 08051 StringValue(str); 08052 if (!RSTRING_LEN(str)) { 08053 rb_thread_critical = thr_crit_bup; 08054 return str; 08055 } 08056 buf = ALLOC_N(char, RSTRING_LEN(str)+1); 08057 /* buf = ckalloc(sizeof(char) * (RSTRING_LEN(str)+1)); */ 08058 memcpy(buf, RSTRING_PTR(str), RSTRING_LEN(str)); 08059 buf[RSTRING_LEN(str)] = 0; 08060 08061 Tcl_DStringInit(&dstr); 08062 Tcl_DStringFree(&dstr); 08063 /* Tcl_ExternalToUtfDString(encoding,buf,strlen(buf),&dstr); */ 08064 Tcl_ExternalToUtfDString(encoding, buf, RSTRING_LEN(str), &dstr); 08065 08066 /* str = rb_tainted_str_new2(Tcl_DStringValue(&dstr)); */ 08067 /* str = rb_str_new2(Tcl_DStringValue(&dstr)); */ 08068 str = rb_str_new(Tcl_DStringValue(&dstr), Tcl_DStringLength(&dstr)); 08069 #ifdef HAVE_RUBY_ENCODING_H 08070 rb_enc_associate_index(str, ENCODING_INDEX_UTF8); 08071 #endif 08072 if (taint_flag) RbTk_OBJ_UNTRUST(str); 08073 rb_ivar_set(str, ID_at_enc, ENCODING_NAME_UTF8); 08074 08075 /* 08076 if (encoding != (Tcl_Encoding)NULL) { 08077 Tcl_FreeEncoding(encoding); 08078 } 08079 */ 08080 Tcl_DStringFree(&dstr); 08081 08082 xfree(buf); 08083 /* ckfree(buf); */ 08084 08085 rb_thread_critical = thr_crit_bup; 08086 #endif 08087 08088 return str; 08089 } 08090 08091 static VALUE 08092 lib_toUTF8(argc, argv, self) 08093 int argc; 08094 VALUE *argv; 08095 VALUE self; 08096 { 08097 VALUE str, encodename; 08098 08099 if (rb_scan_args(argc, argv, "11", &str, &encodename) == 1) { 08100 encodename = Qnil; 08101 } 08102 return lib_toUTF8_core(Qnil, str, encodename); 08103 } 08104 08105 static VALUE 08106 ip_toUTF8(argc, argv, self) 08107 int argc; 08108 VALUE *argv; 08109 VALUE self; 08110 { 08111 VALUE str, encodename; 08112 08113 if (rb_scan_args(argc, argv, "11", &str, &encodename) == 1) { 08114 encodename = Qnil; 08115 } 08116 return lib_toUTF8_core(self, str, encodename); 08117 } 08118 08119 static VALUE 08120 lib_fromUTF8_core(ip_obj, src, encodename) 08121 VALUE ip_obj; 08122 VALUE src; 08123 VALUE encodename; 08124 { 08125 volatile VALUE str = src; 08126 08127 #ifdef TCL_UTF_MAX 08128 Tcl_Interp *interp; 08129 Tcl_Encoding encoding; 08130 Tcl_DString dstr; 08131 int taint_flag = OBJ_TAINTED(str); 08132 char *buf; 08133 int thr_crit_bup; 08134 #endif 08135 08136 tcl_stubs_check(); 08137 08138 if (NIL_P(src)) { 08139 return rb_str_new2(""); 08140 } 08141 08142 #ifdef TCL_UTF_MAX 08143 if (NIL_P(ip_obj)) { 08144 interp = (Tcl_Interp *)NULL; 08145 } else if (get_ip(ip_obj) == (struct tcltkip *)NULL) { 08146 interp = (Tcl_Interp *)NULL; 08147 } else { 08148 interp = get_ip(ip_obj)->ip; 08149 } 08150 08151 thr_crit_bup = rb_thread_critical; 08152 rb_thread_critical = Qtrue; 08153 08154 if (NIL_P(encodename)) { 08155 volatile VALUE enc; 08156 08157 if (TYPE(str) == T_STRING) { 08158 enc = rb_attr_get(str, ID_at_enc); 08159 if (!NIL_P(enc)) { 08160 StringValue(enc); 08161 if (strcmp(RSTRING_PTR(enc), "binary") == 0) { 08162 #ifdef HAVE_RUBY_ENCODING_H 08163 rb_enc_associate_index(str, ENCODING_INDEX_BINARY); 08164 #endif 08165 rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); 08166 rb_thread_critical = thr_crit_bup; 08167 return str; 08168 } 08169 #ifdef HAVE_RUBY_ENCODING_H 08170 } else if (rb_enc_get_index(str) == ENCODING_INDEX_BINARY) { 08171 rb_enc_associate_index(str, ENCODING_INDEX_BINARY); 08172 rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); 08173 rb_thread_critical = thr_crit_bup; 08174 return str; 08175 #endif 08176 } 08177 } 08178 08179 if (NIL_P(ip_obj)) { 08180 encoding = (Tcl_Encoding)NULL; 08181 } else { 08182 enc = rb_attr_get(ip_obj, ID_at_enc); 08183 if (NIL_P(enc)) { 08184 encoding = (Tcl_Encoding)NULL; 08185 } else { 08186 /* StringValue(enc); */ 08187 enc = rb_funcall(enc, ID_to_s, 0, 0); 08188 /* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); */ 08189 if (!RSTRING_LEN(enc)) { 08190 encoding = (Tcl_Encoding)NULL; 08191 } else { 08192 encoding = Tcl_GetEncoding((Tcl_Interp*)NULL, 08193 RSTRING_PTR(enc)); 08194 if (encoding == (Tcl_Encoding)NULL) { 08195 rb_warning("Tk-interp has unknown encoding information (@encoding:'%s')", RSTRING_PTR(enc)); 08196 } else { 08197 encodename = rb_obj_dup(enc); 08198 } 08199 } 08200 } 08201 } 08202 08203 } else { 08204 StringValue(encodename); 08205 08206 if (strcmp(RSTRING_PTR(encodename), "binary") == 0) { 08207 Tcl_Obj *tclstr; 08208 char *s; 08209 int len; 08210 08211 StringValue(str); 08212 tclstr = Tcl_NewStringObj(RSTRING_PTR(str), RSTRING_LEN(str)); 08213 Tcl_IncrRefCount(tclstr); 08214 s = (char*)Tcl_GetByteArrayFromObj(tclstr, &len); 08215 str = rb_tainted_str_new(s, len); 08216 s = (char*)NULL; 08217 Tcl_DecrRefCount(tclstr); 08218 #ifdef HAVE_RUBY_ENCODING_H 08219 rb_enc_associate_index(str, ENCODING_INDEX_BINARY); 08220 #endif 08221 rb_ivar_set(str, ID_at_enc, ENCODING_NAME_BINARY); 08222 08223 rb_thread_critical = thr_crit_bup; 08224 return str; 08225 } 08226 08227 /* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(encodename)); */ 08228 encoding = Tcl_GetEncoding((Tcl_Interp*)NULL, RSTRING_PTR(encodename)); 08229 if (encoding == (Tcl_Encoding)NULL) { 08230 /* 08231 rb_warning("unknown encoding name '%s'", 08232 RSTRING_PTR(encodename)); 08233 encodename = Qnil; 08234 */ 08235 rb_raise(rb_eArgError, "unknown encoding name '%s'", 08236 RSTRING_PTR(encodename)); 08237 } 08238 } 08239 08240 StringValue(str); 08241 08242 if (RSTRING_LEN(str) == 0) { 08243 rb_thread_critical = thr_crit_bup; 08244 return rb_tainted_str_new2(""); 08245 } 08246 08247 buf = ALLOC_N(char, RSTRING_LEN(str)+1); 08248 /* buf = ckalloc(sizeof(char) * (RSTRING_LEN(str)+1)); */ 08249 memcpy(buf, RSTRING_PTR(str), RSTRING_LEN(str)); 08250 buf[RSTRING_LEN(str)] = 0; 08251 08252 Tcl_DStringInit(&dstr); 08253 Tcl_DStringFree(&dstr); 08254 /* Tcl_UtfToExternalDString(encoding,buf,strlen(buf),&dstr); */ 08255 Tcl_UtfToExternalDString(encoding,buf,RSTRING_LEN(str),&dstr); 08256 08257 /* str = rb_tainted_str_new2(Tcl_DStringValue(&dstr)); */ 08258 /* str = rb_str_new2(Tcl_DStringValue(&dstr)); */ 08259 str = rb_str_new(Tcl_DStringValue(&dstr), Tcl_DStringLength(&dstr)); 08260 #ifdef HAVE_RUBY_ENCODING_H 08261 if (interp) { 08262 /* can access encoding_table of TclTkIp */ 08263 /* -> try to use encoding_table */ 08264 VALUE tbl = ip_get_encoding_table(ip_obj); 08265 VALUE encobj = encoding_table_get_obj(tbl, encodename); 08266 rb_enc_associate_index(str, rb_to_encoding_index(encobj)); 08267 } else { 08268 /* cannot access encoding_table of TclTkIp */ 08269 /* -> try to find on Ruby Encoding */ 08270 rb_enc_associate_index(str, rb_enc_find_index(RSTRING_PTR(encodename))); 08271 } 08272 #endif 08273 08274 if (taint_flag) RbTk_OBJ_UNTRUST(str); 08275 rb_ivar_set(str, ID_at_enc, encodename); 08276 08277 /* 08278 if (encoding != (Tcl_Encoding)NULL) { 08279 Tcl_FreeEncoding(encoding); 08280 } 08281 */ 08282 Tcl_DStringFree(&dstr); 08283 08284 xfree(buf); 08285 /* ckfree(buf); */ 08286 08287 rb_thread_critical = thr_crit_bup; 08288 #endif 08289 08290 return str; 08291 } 08292 08293 static VALUE 08294 lib_fromUTF8(argc, argv, self) 08295 int argc; 08296 VALUE *argv; 08297 VALUE self; 08298 { 08299 VALUE str, encodename; 08300 08301 if (rb_scan_args(argc, argv, "11", &str, &encodename) == 1) { 08302 encodename = Qnil; 08303 } 08304 return lib_fromUTF8_core(Qnil, str, encodename); 08305 } 08306 08307 static VALUE 08308 ip_fromUTF8(argc, argv, self) 08309 int argc; 08310 VALUE *argv; 08311 VALUE self; 08312 { 08313 VALUE str, encodename; 08314 08315 if (rb_scan_args(argc, argv, "11", &str, &encodename) == 1) { 08316 encodename = Qnil; 08317 } 08318 return lib_fromUTF8_core(self, str, encodename); 08319 } 08320 08321 static VALUE 08322 lib_UTF_backslash_core(self, str, all_bs) 08323 VALUE self; 08324 VALUE str; 08325 int all_bs; 08326 { 08327 #ifdef TCL_UTF_MAX 08328 char *src_buf, *dst_buf, *ptr; 08329 int read_len = 0, dst_len = 0; 08330 int taint_flag = OBJ_TAINTED(str); 08331 int thr_crit_bup; 08332 08333 tcl_stubs_check(); 08334 08335 StringValue(str); 08336 if (!RSTRING_LEN(str)) { 08337 return str; 08338 } 08339 08340 thr_crit_bup = rb_thread_critical; 08341 rb_thread_critical = Qtrue; 08342 08343 /* src_buf = ALLOC_N(char, RSTRING_LEN(str)+1); */ 08344 src_buf = ckalloc(sizeof(char) * (RSTRING_LEN(str)+1)); 08345 #if 0 /* use Tcl_Preserve/Release */ 08346 Tcl_Preserve((ClientData)src_buf); /* XXXXXXXX */ 08347 #endif 08348 memcpy(src_buf, RSTRING_PTR(str), RSTRING_LEN(str)); 08349 src_buf[RSTRING_LEN(str)] = 0; 08350 08351 /* dst_buf = ALLOC_N(char, RSTRING_LEN(str)+1); */ 08352 dst_buf = ckalloc(sizeof(char) * (RSTRING_LEN(str)+1)); 08353 #if 0 /* use Tcl_Preserve/Release */ 08354 Tcl_Preserve((ClientData)dst_buf); /* XXXXXXXX */ 08355 #endif 08356 08357 ptr = src_buf; 08358 while(RSTRING_LEN(str) > ptr - src_buf) { 08359 if (*ptr == '\\' && (all_bs || *(ptr + 1) == 'u')) { 08360 dst_len += Tcl_UtfBackslash(ptr, &read_len, (dst_buf + dst_len)); 08361 ptr += read_len; 08362 } else { 08363 *(dst_buf + (dst_len++)) = *(ptr++); 08364 } 08365 } 08366 08367 str = rb_str_new(dst_buf, dst_len); 08368 if (taint_flag) RbTk_OBJ_UNTRUST(str); 08369 #ifdef HAVE_RUBY_ENCODING_H 08370 rb_enc_associate_index(str, ENCODING_INDEX_UTF8); 08371 #endif 08372 rb_ivar_set(str, ID_at_enc, ENCODING_NAME_UTF8); 08373 08374 #if 0 /* use Tcl_EventuallyFree */ 08375 Tcl_EventuallyFree((ClientData)src_buf, TCL_DYNAMIC); /* XXXXXXXX */ 08376 #else 08377 #if 0 /* use Tcl_Preserve/Release */ 08378 Tcl_Release((ClientData)src_buf); /* XXXXXXXX */ 08379 #else 08380 /* free(src_buf); */ 08381 ckfree(src_buf); 08382 #endif 08383 #endif 08384 #if 0 /* use Tcl_EventuallyFree */ 08385 Tcl_EventuallyFree((ClientData)dst_buf, TCL_DYNAMIC); /* XXXXXXXX */ 08386 #else 08387 #if 0 /* use Tcl_Preserve/Release */ 08388 Tcl_Release((ClientData)dst_buf); /* XXXXXXXX */ 08389 #else 08390 /* free(dst_buf); */ 08391 ckfree(dst_buf); 08392 #endif 08393 #endif 08394 08395 rb_thread_critical = thr_crit_bup; 08396 #endif 08397 08398 return str; 08399 } 08400 08401 static VALUE 08402 lib_UTF_backslash(self, str) 08403 VALUE self; 08404 VALUE str; 08405 { 08406 return lib_UTF_backslash_core(self, str, 0); 08407 } 08408 08409 static VALUE 08410 lib_Tcl_backslash(self, str) 08411 VALUE self; 08412 VALUE str; 08413 { 08414 return lib_UTF_backslash_core(self, str, 1); 08415 } 08416 08417 static VALUE 08418 lib_get_system_encoding(self) 08419 VALUE self; 08420 { 08421 #if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION > 0) 08422 tcl_stubs_check(); 08423 return rb_str_new2(Tcl_GetEncodingName((Tcl_Encoding)NULL)); 08424 #else 08425 return Qnil; 08426 #endif 08427 } 08428 08429 static VALUE 08430 lib_set_system_encoding(self, enc_name) 08431 VALUE self; 08432 VALUE enc_name; 08433 { 08434 #if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION > 0) 08435 tcl_stubs_check(); 08436 08437 if (NIL_P(enc_name)) { 08438 Tcl_SetSystemEncoding((Tcl_Interp *)NULL, (CONST char *)NULL); 08439 return lib_get_system_encoding(self); 08440 } 08441 08442 enc_name = rb_funcall(enc_name, ID_to_s, 0, 0); 08443 if (Tcl_SetSystemEncoding((Tcl_Interp *)NULL, 08444 StringValuePtr(enc_name)) != TCL_OK) { 08445 rb_raise(rb_eArgError, "unknown encoding name '%s'", 08446 RSTRING_PTR(enc_name)); 08447 } 08448 08449 return enc_name; 08450 #else 08451 return Qnil; 08452 #endif 08453 } 08454 08455 08456 /* invoke Tcl proc */ 08457 struct invoke_info { 08458 struct tcltkip *ptr; 08459 Tcl_CmdInfo cmdinfo; 08460 #if TCL_MAJOR_VERSION >= 8 08461 int objc; 08462 Tcl_Obj **objv; 08463 #else 08464 int argc; 08465 char **argv; 08466 #endif 08467 }; 08468 08469 static VALUE 08470 #ifdef HAVE_PROTOTYPES 08471 invoke_tcl_proc(VALUE arg) 08472 #else 08473 invoke_tcl_proc(arg) 08474 VALUE arg; 08475 #endif 08476 { 08477 struct invoke_info *inf = (struct invoke_info *)arg; 08478 int i, len; 08479 #if TCL_MAJOR_VERSION >= 8 08480 int argc = inf->objc; 08481 char **argv = (char **)NULL; 08482 #endif 08483 08484 /* memory allocation for arguments of this command */ 08485 #if TCL_MAJOR_VERSION >= 8 08486 if (!inf->cmdinfo.isNativeObjectProc) { 08487 /* string interface */ 08488 /* argv = (char **)ALLOC_N(char *, argc+1);*/ /* XXXXXXXXXX */ 08489 argv = (char **)ckalloc(sizeof(char *)*(argc+1)); 08490 #if 0 /* use Tcl_Preserve/Release */ 08491 Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ 08492 #endif 08493 for (i = 0; i < argc; ++i) { 08494 argv[i] = Tcl_GetStringFromObj(inf->objv[i], &len); 08495 } 08496 argv[argc] = (char *)NULL; 08497 } 08498 #endif 08499 08500 Tcl_ResetResult(inf->ptr->ip); 08501 08502 /* Invoke the C procedure */ 08503 #if TCL_MAJOR_VERSION >= 8 08504 if (inf->cmdinfo.isNativeObjectProc) { 08505 inf->ptr->return_value 08506 = (*(inf->cmdinfo.objProc))(inf->cmdinfo.objClientData, 08507 inf->ptr->ip, inf->objc, inf->objv); 08508 } 08509 else 08510 #endif 08511 { 08512 #if TCL_MAJOR_VERSION >= 8 08513 inf->ptr->return_value 08514 = (*(inf->cmdinfo.proc))(inf->cmdinfo.clientData, inf->ptr->ip, 08515 argc, (CONST84 char **)argv); 08516 08517 #if 0 /* use Tcl_EventuallyFree */ 08518 Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ 08519 #else 08520 #if 0 /* use Tcl_Preserve/Release */ 08521 Tcl_Release((ClientData)argv); /* XXXXXXXX */ 08522 #else 08523 /* free(argv); */ 08524 ckfree((char*)argv); 08525 #endif 08526 #endif 08527 08528 #else /* TCL_MAJOR_VERSION < 8 */ 08529 inf->ptr->return_value 08530 = (*(inf->cmdinfo.proc))(inf->cmdinfo.clientData, inf->ptr->ip, 08531 inf->argc, inf->argv); 08532 #endif 08533 } 08534 08535 return Qnil; 08536 } 08537 08538 08539 #if TCL_MAJOR_VERSION >= 8 08540 static VALUE 08541 ip_invoke_core(interp, objc, objv) 08542 VALUE interp; 08543 int objc; 08544 Tcl_Obj **objv; 08545 #else 08546 static VALUE 08547 ip_invoke_core(interp, argc, argv) 08548 VALUE interp; 08549 int argc; 08550 char **argv; 08551 #endif 08552 { 08553 struct tcltkip *ptr; 08554 Tcl_CmdInfo info; 08555 char *cmd; 08556 int len; 08557 int thr_crit_bup; 08558 int unknown_flag = 0; 08559 08560 #if 1 /* wrap tcl-proc call */ 08561 struct invoke_info inf; 08562 int status; 08563 VALUE ret; 08564 #else 08565 #if TCL_MAJOR_VERSION >= 8 08566 int argc = objc; 08567 char **argv = (char **)NULL; 08568 /* Tcl_Obj *resultPtr; */ 08569 #endif 08570 #endif 08571 08572 /* get the data struct */ 08573 ptr = get_ip(interp); 08574 08575 /* get the command name string */ 08576 #if TCL_MAJOR_VERSION >= 8 08577 cmd = Tcl_GetStringFromObj(objv[0], &len); 08578 #else /* TCL_MAJOR_VERSION < 8 */ 08579 cmd = argv[0]; 08580 #endif 08581 08582 /* get the data struct */ 08583 ptr = get_ip(interp); 08584 08585 /* ip is deleted? */ 08586 if (deleted_ip(ptr)) { 08587 return rb_tainted_str_new2(""); 08588 } 08589 08590 /* Tcl_Preserve(ptr->ip); */ 08591 rbtk_preserve_ip(ptr); 08592 08593 /* map from the command name to a C procedure */ 08594 DUMP2("call Tcl_GetCommandInfo, %s", cmd); 08595 if (!Tcl_GetCommandInfo(ptr->ip, cmd, &info)) { 08596 DUMP1("error Tcl_GetCommandInfo"); 08597 DUMP1("try auto_load (call 'unknown' command)"); 08598 if (!Tcl_GetCommandInfo(ptr->ip, 08599 #if TCL_MAJOR_VERSION >= 8 08600 "::unknown", 08601 #else 08602 "unknown", 08603 #endif 08604 &info)) { 08605 DUMP1("fail to get 'unknown' command"); 08606 /* if (event_loop_abort_on_exc || cmd[0] != '.') { */ 08607 if (event_loop_abort_on_exc > 0) { 08608 /* Tcl_Release(ptr->ip); */ 08609 rbtk_release_ip(ptr); 08610 /*rb_ip_raise(obj,rb_eNameError,"invalid command name `%s'",cmd);*/ 08611 return create_ip_exc(interp, rb_eNameError, 08612 "invalid command name `%s'", cmd); 08613 } else { 08614 if (event_loop_abort_on_exc < 0) { 08615 rb_warning("invalid command name `%s' (ignore)", cmd); 08616 } else { 08617 rb_warn("invalid command name `%s' (ignore)", cmd); 08618 } 08619 Tcl_ResetResult(ptr->ip); 08620 /* Tcl_Release(ptr->ip); */ 08621 rbtk_release_ip(ptr); 08622 return rb_tainted_str_new2(""); 08623 } 08624 } else { 08625 #if TCL_MAJOR_VERSION >= 8 08626 Tcl_Obj **unknown_objv; 08627 #else 08628 char **unknown_argv; 08629 #endif 08630 DUMP1("find 'unknown' command -> set arguemnts"); 08631 unknown_flag = 1; 08632 08633 #if TCL_MAJOR_VERSION >= 8 08634 /* unknown_objv = (Tcl_Obj **)ALLOC_N(Tcl_Obj *, objc+2); */ 08635 unknown_objv = (Tcl_Obj **)ckalloc(sizeof(Tcl_Obj *) * (objc+2)); 08636 #if 0 /* use Tcl_Preserve/Release */ 08637 Tcl_Preserve((ClientData)unknown_objv); /* XXXXXXXX */ 08638 #endif 08639 unknown_objv[0] = Tcl_NewStringObj("::unknown", 9); 08640 Tcl_IncrRefCount(unknown_objv[0]); 08641 memcpy(unknown_objv + 1, objv, sizeof(Tcl_Obj *)*objc); 08642 unknown_objv[++objc] = (Tcl_Obj*)NULL; 08643 objv = unknown_objv; 08644 #else 08645 /* unknown_argv = (char **)ALLOC_N(char *, argc+2); */ 08646 unknown_argv = (char **)ckalloc(sizeof(char *) * (argc+2)); 08647 #if 0 /* use Tcl_Preserve/Release */ 08648 Tcl_Preserve((ClientData)unknown_argv); /* XXXXXXXX */ 08649 #endif 08650 unknown_argv[0] = strdup("unknown"); 08651 memcpy(unknown_argv + 1, argv, sizeof(char *)*argc); 08652 unknown_argv[++argc] = (char *)NULL; 08653 argv = unknown_argv; 08654 #endif 08655 } 08656 } 08657 DUMP1("end Tcl_GetCommandInfo"); 08658 08659 thr_crit_bup = rb_thread_critical; 08660 rb_thread_critical = Qtrue; 08661 08662 #if 1 /* wrap tcl-proc call */ 08663 /* setup params */ 08664 inf.ptr = ptr; 08665 inf.cmdinfo = info; 08666 #if TCL_MAJOR_VERSION >= 8 08667 inf.objc = objc; 08668 inf.objv = objv; 08669 #else 08670 inf.argc = argc; 08671 inf.argv = argv; 08672 #endif 08673 08674 /* invoke tcl-proc */ 08675 ret = rb_protect(invoke_tcl_proc, (VALUE)&inf, &status); 08676 switch(status) { 08677 case TAG_RAISE: 08678 if (NIL_P(rb_errinfo())) { 08679 rbtk_pending_exception = rb_exc_new2(rb_eException, 08680 "unknown exception"); 08681 } else { 08682 rbtk_pending_exception = rb_errinfo(); 08683 } 08684 break; 08685 08686 case TAG_FATAL: 08687 if (NIL_P(rb_errinfo())) { 08688 rbtk_pending_exception = rb_exc_new2(rb_eFatal, "FATAL"); 08689 } else { 08690 rbtk_pending_exception = rb_errinfo(); 08691 } 08692 } 08693 08694 #else /* !wrap tcl-proc call */ 08695 08696 /* memory allocation for arguments of this command */ 08697 #if TCL_MAJOR_VERSION >= 8 08698 if (!info.isNativeObjectProc) { 08699 int i; 08700 08701 /* string interface */ 08702 /* argv = (char **)ALLOC_N(char *, argc+1); */ 08703 argv = (char **)ckalloc(sizeof(char *) * (argc+1)); 08704 #if 0 /* use Tcl_Preserve/Release */ 08705 Tcl_Preserve((ClientData)argv); /* XXXXXXXX */ 08706 #endif 08707 for (i = 0; i < argc; ++i) { 08708 argv[i] = Tcl_GetStringFromObj(objv[i], &len); 08709 } 08710 argv[argc] = (char *)NULL; 08711 } 08712 #endif 08713 08714 Tcl_ResetResult(ptr->ip); 08715 08716 /* Invoke the C procedure */ 08717 #if TCL_MAJOR_VERSION >= 8 08718 if (info.isNativeObjectProc) { 08719 ptr->return_value = (*info.objProc)(info.objClientData, ptr->ip, 08720 objc, objv); 08721 #if 0 08722 /* get the string value from the result object */ 08723 resultPtr = Tcl_GetObjResult(ptr->ip); 08724 Tcl_SetResult(ptr->ip, Tcl_GetStringFromObj(resultPtr, &len), 08725 TCL_VOLATILE); 08726 #endif 08727 } 08728 else 08729 #endif 08730 { 08731 #if TCL_MAJOR_VERSION >= 8 08732 ptr->return_value = (*info.proc)(info.clientData, ptr->ip, 08733 argc, (CONST84 char **)argv); 08734 08735 #if 0 /* use Tcl_EventuallyFree */ 08736 Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ 08737 #else 08738 #if 0 /* use Tcl_Preserve/Release */ 08739 Tcl_Release((ClientData)argv); /* XXXXXXXX */ 08740 #else 08741 /* free(argv); */ 08742 ckfree((char*)argv); 08743 #endif 08744 #endif 08745 08746 #else /* TCL_MAJOR_VERSION < 8 */ 08747 ptr->return_value = (*info.proc)(info.clientData, ptr->ip, 08748 argc, argv); 08749 #endif 08750 } 08751 #endif /* ! wrap tcl-proc call */ 08752 08753 /* free allocated memory for calling 'unknown' command */ 08754 if (unknown_flag) { 08755 #if TCL_MAJOR_VERSION >= 8 08756 Tcl_DecrRefCount(objv[0]); 08757 #if 0 /* use Tcl_EventuallyFree */ 08758 Tcl_EventuallyFree((ClientData)objv, TCL_DYNAMIC); /* XXXXXXXX */ 08759 #else 08760 #if 0 /* use Tcl_Preserve/Release */ 08761 Tcl_Release((ClientData)objv); /* XXXXXXXX */ 08762 #else 08763 /* free(objv); */ 08764 ckfree((char*)objv); 08765 #endif 08766 #endif 08767 #else /* TCL_MAJOR_VERSION < 8 */ 08768 free(argv[0]); 08769 /* ckfree(argv[0]); */ 08770 #if 0 /* use Tcl_EventuallyFree */ 08771 Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */ 08772 #else 08773 #if 0 /* use Tcl_Preserve/Release */ 08774 Tcl_Release((ClientData)argv); /* XXXXXXXX */ 08775 #else 08776 /* free(argv); */ 08777 ckfree((char*)argv); 08778 #endif 08779 #endif 08780 #endif 08781 } 08782 08783 /* exception on mainloop */ 08784 if (pending_exception_check1(thr_crit_bup, ptr)) { 08785 return rbtk_pending_exception; 08786 } 08787 08788 rb_thread_critical = thr_crit_bup; 08789 08790 /* if (ptr->return_value == TCL_ERROR) { */ 08791 if (ptr->return_value != TCL_OK) { 08792 if (event_loop_abort_on_exc > 0 && !Tcl_InterpDeleted(ptr->ip)) { 08793 switch (ptr->return_value) { 08794 case TCL_RETURN: 08795 return create_ip_exc(interp, eTkCallbackReturn, 08796 "ip_invoke_core receives TCL_RETURN"); 08797 case TCL_BREAK: 08798 return create_ip_exc(interp, eTkCallbackBreak, 08799 "ip_invoke_core receives TCL_BREAK"); 08800 case TCL_CONTINUE: 08801 return create_ip_exc(interp, eTkCallbackContinue, 08802 "ip_invoke_core receives TCL_CONTINUE"); 08803 default: 08804 return create_ip_exc(interp, rb_eRuntimeError, "%s", 08805 Tcl_GetStringResult(ptr->ip)); 08806 } 08807 08808 } else { 08809 if (event_loop_abort_on_exc < 0) { 08810 rb_warning("%s (ignore)", Tcl_GetStringResult(ptr->ip)); 08811 } else { 08812 rb_warn("%s (ignore)", Tcl_GetStringResult(ptr->ip)); 08813 } 08814 Tcl_ResetResult(ptr->ip); 08815 return rb_tainted_str_new2(""); 08816 } 08817 } 08818 08819 /* pass back the result (as string) */ 08820 return ip_get_result_string_obj(ptr->ip); 08821 } 08822 08823 08824 #if TCL_MAJOR_VERSION >= 8 08825 static Tcl_Obj ** 08826 #else /* TCL_MAJOR_VERSION < 8 */ 08827 static char ** 08828 #endif 08829 alloc_invoke_arguments(argc, argv) 08830 int argc; 08831 VALUE *argv; 08832 { 08833 int i; 08834 int thr_crit_bup; 08835 08836 #if TCL_MAJOR_VERSION >= 8 08837 Tcl_Obj **av; 08838 #else /* TCL_MAJOR_VERSION < 8 */ 08839 char **av; 08840 #endif 08841 08842 thr_crit_bup = rb_thread_critical; 08843 rb_thread_critical = Qtrue; 08844 08845 /* memory allocation */ 08846 #if TCL_MAJOR_VERSION >= 8 08847 /* av = ALLOC_N(Tcl_Obj *, argc+1);*/ /* XXXXXXXXXX */ 08848 av = (Tcl_Obj**)ckalloc(sizeof(Tcl_Obj *)*(argc+1)); 08849 #if 0 /* use Tcl_Preserve/Release */ 08850 Tcl_Preserve((ClientData)av); /* XXXXXXXX */ 08851 #endif 08852 for (i = 0; i < argc; ++i) { 08853 av[i] = get_obj_from_str(argv[i]); 08854 Tcl_IncrRefCount(av[i]); 08855 } 08856 av[argc] = NULL; 08857 08858 #else /* TCL_MAJOR_VERSION < 8 */ 08859 /* string interface */ 08860 /* av = ALLOC_N(char *, argc+1); */ 08861 av = (char**)ckalloc(sizeof(char *) * (argc+1)); 08862 #if 0 /* use Tcl_Preserve/Release */ 08863 Tcl_Preserve((ClientData)av); /* XXXXXXXX */ 08864 #endif 08865 for (i = 0; i < argc; ++i) { 08866 av[i] = strdup(StringValuePtr(argv[i])); 08867 } 08868 av[argc] = NULL; 08869 #endif 08870 08871 rb_thread_critical = thr_crit_bup; 08872 08873 return av; 08874 } 08875 08876 static void 08877 free_invoke_arguments(argc, av) 08878 int argc; 08879 #if TCL_MAJOR_VERSION >= 8 08880 Tcl_Obj **av; 08881 #else /* TCL_MAJOR_VERSION < 8 */ 08882 char **av; 08883 #endif 08884 { 08885 int i; 08886 08887 for (i = 0; i < argc; ++i) { 08888 #if TCL_MAJOR_VERSION >= 8 08889 Tcl_DecrRefCount(av[i]); 08890 av[i] = (Tcl_Obj*)NULL; 08891 #else /* TCL_MAJOR_VERSION < 8 */ 08892 free(av[i]); 08893 av[i] = (char*)NULL; 08894 #endif 08895 } 08896 #if TCL_MAJOR_VERSION >= 8 08897 #if 0 /* use Tcl_EventuallyFree */ 08898 Tcl_EventuallyFree((ClientData)av, TCL_DYNAMIC); /* XXXXXXXX */ 08899 #else 08900 #if 0 /* use Tcl_Preserve/Release */ 08901 Tcl_Release((ClientData)av); /* XXXXXXXX */ 08902 #else 08903 ckfree((char*)av); 08904 #endif 08905 #endif 08906 #else /* TCL_MAJOR_VERSION < 8 */ 08907 #if 0 /* use Tcl_EventuallyFree */ 08908 Tcl_EventuallyFree((ClientData)av, TCL_DYNAMIC); /* XXXXXXXX */ 08909 #else 08910 #if 0 /* use Tcl_Preserve/Release */ 08911 Tcl_Release((ClientData)av); /* XXXXXXXX */ 08912 #else 08913 /* free(av); */ 08914 ckfree((char*)av); 08915 #endif 08916 #endif 08917 #endif 08918 } 08919 08920 static VALUE 08921 ip_invoke_real(argc, argv, interp) 08922 int argc; 08923 VALUE *argv; 08924 VALUE interp; 08925 { 08926 VALUE v; 08927 struct tcltkip *ptr; /* tcltkip data struct */ 08928 08929 #if TCL_MAJOR_VERSION >= 8 08930 Tcl_Obj **av = (Tcl_Obj **)NULL; 08931 #else /* TCL_MAJOR_VERSION < 8 */ 08932 char **av = (char **)NULL; 08933 #endif 08934 08935 DUMP2("invoke_real called by thread:%lx", rb_thread_current()); 08936 08937 /* get the data struct */ 08938 ptr = get_ip(interp); 08939 08940 /* ip is deleted? */ 08941 if (deleted_ip(ptr)) { 08942 return rb_tainted_str_new2(""); 08943 } 08944 08945 /* allocate memory for arguments */ 08946 av = alloc_invoke_arguments(argc, argv); 08947 08948 /* Invoke the C procedure */ 08949 Tcl_ResetResult(ptr->ip); 08950 v = ip_invoke_core(interp, argc, av); 08951 08952 /* free allocated memory */ 08953 free_invoke_arguments(argc, av); 08954 08955 return v; 08956 } 08957 08958 VALUE 08959 ivq_safelevel_handler(arg, ivq) 08960 VALUE arg; 08961 VALUE ivq; 08962 { 08963 struct invoke_queue *q; 08964 08965 Data_Get_Struct(ivq, struct invoke_queue, q); 08966 DUMP2("(safe-level handler) $SAFE = %d", q->safe_level); 08967 rb_set_safe_level(q->safe_level); 08968 return ip_invoke_core(q->interp, q->argc, q->argv); 08969 } 08970 08971 int invoke_queue_handler _((Tcl_Event *, int)); 08972 int 08973 invoke_queue_handler(evPtr, flags) 08974 Tcl_Event *evPtr; 08975 int flags; 08976 { 08977 struct invoke_queue *q = (struct invoke_queue *)evPtr; 08978 volatile VALUE ret; 08979 volatile VALUE q_dat; 08980 volatile VALUE thread = q->thread; 08981 struct tcltkip *ptr; 08982 08983 DUMP2("do_invoke_queue_handler : evPtr = %p", evPtr); 08984 DUMP2("invoke queue_thread : %lx", rb_thread_current()); 08985 DUMP2("added by thread : %lx", thread); 08986 08987 if (*(q->done)) { 08988 DUMP1("processed by another event-loop"); 08989 return 0; 08990 } else { 08991 DUMP1("process it on current event-loop"); 08992 } 08993 08994 #ifdef RUBY_VM 08995 if (RTEST(rb_funcall(thread, ID_alive_p, 0)) 08996 && ! RTEST(rb_funcall(thread, ID_stop_p, 0))) { 08997 #else 08998 if (RTEST(rb_thread_alive_p(thread)) 08999 && ! RTEST(rb_funcall(thread, ID_stop_p, 0))) { 09000 #endif 09001 DUMP1("caller is not yet ready to receive the result -> pending"); 09002 return 0; 09003 } 09004 09005 /* process it */ 09006 *(q->done) = 1; 09007 09008 /* deleted ipterp ? */ 09009 ptr = get_ip(q->interp); 09010 if (deleted_ip(ptr)) { 09011 /* deleted IP --> ignore */ 09012 return 1; 09013 } 09014 09015 /* incr internal handler mark */ 09016 rbtk_internal_eventloop_handler++; 09017 09018 /* check safe-level */ 09019 if (rb_safe_level() != q->safe_level) { 09020 /* q_dat = Data_Wrap_Struct(rb_cData,0,0,q); */ 09021 q_dat = Data_Wrap_Struct(rb_cData,invoke_queue_mark,-1,q); 09022 ret = rb_funcall(rb_proc_new(ivq_safelevel_handler, q_dat), 09023 ID_call, 0); 09024 rb_gc_force_recycle(q_dat); 09025 q_dat = (VALUE)NULL; 09026 } else { 09027 DUMP2("call invoke_real (for caller thread:%lx)", thread); 09028 DUMP2("call invoke_real (current thread:%lx)", rb_thread_current()); 09029 ret = ip_invoke_core(q->interp, q->argc, q->argv); 09030 } 09031 09032 /* set result */ 09033 RARRAY_PTR(q->result)[0] = ret; 09034 ret = (VALUE)NULL; 09035 09036 /* decr internal handler mark */ 09037 rbtk_internal_eventloop_handler--; 09038 09039 /* complete */ 09040 *(q->done) = -1; 09041 09042 /* unlink ruby objects */ 09043 q->interp = (VALUE)NULL; 09044 q->result = (VALUE)NULL; 09045 q->thread = (VALUE)NULL; 09046 09047 /* back to caller */ 09048 #ifdef RUBY_VM 09049 if (RTEST(rb_funcall(thread, ID_alive_p, 0, 0))) { 09050 #else 09051 if (RTEST(rb_thread_alive_p(thread))) { 09052 #endif 09053 DUMP2("back to caller (caller thread:%lx)", thread); 09054 DUMP2(" (current thread:%lx)", rb_thread_current()); 09055 #if CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE 09056 have_rb_thread_waiting_for_value = 1; 09057 rb_thread_wakeup(thread); 09058 #else 09059 rb_thread_run(thread); 09060 #endif 09061 DUMP1("finish back to caller"); 09062 #if DO_THREAD_SCHEDULE_AT_CALLBACK_DONE 09063 rb_thread_schedule(); 09064 #endif 09065 } else { 09066 DUMP2("caller is dead (caller thread:%lx)", thread); 09067 DUMP2(" (current thread:%lx)", rb_thread_current()); 09068 } 09069 09070 /* end of handler : remove it */ 09071 return 1; 09072 } 09073 09074 static VALUE 09075 ip_invoke_with_position(argc, argv, obj, position) 09076 int argc; 09077 VALUE *argv; 09078 VALUE obj; 09079 Tcl_QueuePosition position; 09080 { 09081 struct invoke_queue *ivq; 09082 #ifdef RUBY_USE_NATIVE_THREAD 09083 struct tcltkip *ptr; 09084 #endif 09085 int *alloc_done; 09086 int thr_crit_bup; 09087 volatile VALUE current = rb_thread_current(); 09088 volatile VALUE ip_obj = obj; 09089 volatile VALUE result; 09090 volatile VALUE ret; 09091 struct timeval t; 09092 09093 #if TCL_MAJOR_VERSION >= 8 09094 Tcl_Obj **av = (Tcl_Obj **)NULL; 09095 #else /* TCL_MAJOR_VERSION < 8 */ 09096 char **av = (char **)NULL; 09097 #endif 09098 09099 if (argc < 1) { 09100 rb_raise(rb_eArgError, "command name missing"); 09101 } 09102 09103 #ifdef RUBY_USE_NATIVE_THREAD 09104 ptr = get_ip(ip_obj); 09105 DUMP2("invoke status: ptr->tk_thread_id %p", ptr->tk_thread_id); 09106 DUMP2("invoke status: Tcl_GetCurrentThread %p", Tcl_GetCurrentThread()); 09107 #else 09108 DUMP2("status: Tcl_GetCurrentThread %p", Tcl_GetCurrentThread()); 09109 #endif 09110 DUMP2("status: eventloopt_thread %lx", eventloop_thread); 09111 09112 if ( 09113 #ifdef RUBY_USE_NATIVE_THREAD 09114 (ptr->tk_thread_id == 0 || ptr->tk_thread_id == Tcl_GetCurrentThread()) 09115 && 09116 #endif 09117 (NIL_P(eventloop_thread) || current == eventloop_thread) 09118 ) { 09119 if (NIL_P(eventloop_thread)) { 09120 DUMP2("invoke from thread:%lx but no eventloop", current); 09121 } else { 09122 DUMP2("invoke from current eventloop %lx", current); 09123 } 09124 result = ip_invoke_real(argc, argv, ip_obj); 09125 if (rb_obj_is_kind_of(result, rb_eException)) { 09126 rb_exc_raise(result); 09127 } 09128 return result; 09129 } 09130 09131 DUMP2("invoke from thread %lx (NOT current eventloop)", current); 09132 09133 thr_crit_bup = rb_thread_critical; 09134 rb_thread_critical = Qtrue; 09135 09136 /* allocate memory (for arguments) */ 09137 av = alloc_invoke_arguments(argc, argv); 09138 09139 /* allocate memory (keep result) */ 09140 /* alloc_done = (int*)ALLOC(int); */ 09141 alloc_done = (int*)ckalloc(sizeof(int)); 09142 #if 0 /* use Tcl_Preserve/Release */ 09143 Tcl_Preserve((ClientData)alloc_done); /* XXXXXXXX */ 09144 #endif 09145 *alloc_done = 0; 09146 09147 /* allocate memory (freed by Tcl_ServiceEvent) */ 09148 /* ivq = (struct invoke_queue *)Tcl_Alloc(sizeof(struct invoke_queue)); */ 09149 ivq = (struct invoke_queue *)ckalloc(sizeof(struct invoke_queue)); 09150 #if 0 /* use Tcl_Preserve/Release */ 09151 Tcl_Preserve((ClientData)ivq); /* XXXXXXXX */ 09152 #endif 09153 09154 /* allocate result obj */ 09155 result = rb_ary_new3(1, Qnil); 09156 09157 /* construct event data */ 09158 ivq->done = alloc_done; 09159 ivq->argc = argc; 09160 ivq->argv = av; 09161 ivq->interp = ip_obj; 09162 ivq->result = result; 09163 ivq->thread = current; 09164 ivq->safe_level = rb_safe_level(); 09165 ivq->ev.proc = invoke_queue_handler; 09166 09167 /* add the handler to Tcl event queue */ 09168 DUMP1("add handler"); 09169 #ifdef RUBY_USE_NATIVE_THREAD 09170 if (ptr->tk_thread_id) { 09171 /* Tcl_ThreadQueueEvent(ptr->tk_thread_id, &(ivq->ev), position); */ 09172 Tcl_ThreadQueueEvent(ptr->tk_thread_id, (Tcl_Event*)ivq, position); 09173 Tcl_ThreadAlert(ptr->tk_thread_id); 09174 } else if (tk_eventloop_thread_id) { 09175 /* Tcl_ThreadQueueEvent(tk_eventloop_thread_id, 09176 &(ivq->ev), position); */ 09177 Tcl_ThreadQueueEvent(tk_eventloop_thread_id, 09178 (Tcl_Event*)ivq, position); 09179 Tcl_ThreadAlert(tk_eventloop_thread_id); 09180 } else { 09181 /* Tcl_QueueEvent(&(ivq->ev), position); */ 09182 Tcl_QueueEvent((Tcl_Event*)ivq, position); 09183 } 09184 #else 09185 /* Tcl_QueueEvent(&(ivq->ev), position); */ 09186 Tcl_QueueEvent((Tcl_Event*)ivq, position); 09187 #endif 09188 09189 rb_thread_critical = thr_crit_bup; 09190 09191 /* wait for the handler to be processed */ 09192 t.tv_sec = 0; 09193 t.tv_usec = (long)((EVENT_HANDLER_TIMEOUT)*1000.0); 09194 09195 DUMP2("ivq wait for handler (current thread:%lx)", current); 09196 while(*alloc_done >= 0) { 09197 /* rb_thread_stop(); */ 09198 /* rb_thread_sleep_forever(); */ 09199 rb_thread_wait_for(t); 09200 DUMP2("*** ivq wakeup (current thread:%lx)", current); 09201 DUMP2("*** (eventloop thread:%lx)", eventloop_thread); 09202 if (NIL_P(eventloop_thread)) { 09203 DUMP1("*** ivq lost eventloop thread"); 09204 break; 09205 } 09206 } 09207 DUMP2("back from handler (current thread:%lx)", current); 09208 09209 /* get result & free allocated memory */ 09210 ret = RARRAY_PTR(result)[0]; 09211 #if 0 /* use Tcl_EventuallyFree */ 09212 Tcl_EventuallyFree((ClientData)alloc_done, TCL_DYNAMIC); /* XXXXXXXX */ 09213 #else 09214 #if 0 /* use Tcl_Preserve/Release */ 09215 Tcl_Release((ClientData)alloc_done); /* XXXXXXXX */ 09216 #else 09217 /* free(alloc_done); */ 09218 ckfree((char*)alloc_done); 09219 #endif 09220 #endif 09221 09222 #if 0 /* ivq is freed by Tcl_ServiceEvent */ 09223 #if 0 /* use Tcl_EventuallyFree */ 09224 Tcl_EventuallyFree((ClientData)ivq, TCL_DYNAMIC); /* XXXXXXXX */ 09225 #else 09226 #if 0 /* use Tcl_Preserve/Release */ 09227 Tcl_Release(ivq); 09228 #else 09229 ckfree((char*)ivq); 09230 #endif 09231 #endif 09232 #endif 09233 09234 /* free allocated memory */ 09235 free_invoke_arguments(argc, av); 09236 09237 /* exception? */ 09238 if (rb_obj_is_kind_of(ret, rb_eException)) { 09239 DUMP1("raise exception"); 09240 /* rb_exc_raise(ret); */ 09241 rb_exc_raise(rb_exc_new3(rb_obj_class(ret), 09242 rb_funcall(ret, ID_to_s, 0, 0))); 09243 } 09244 09245 DUMP1("exit ip_invoke"); 09246 return ret; 09247 } 09248 09249 09250 /* get return code from Tcl_Eval() */ 09251 static VALUE 09252 ip_retval(self) 09253 VALUE self; 09254 { 09255 struct tcltkip *ptr; /* tcltkip data struct */ 09256 09257 /* get the data strcut */ 09258 ptr = get_ip(self); 09259 09260 /* ip is deleted? */ 09261 if (deleted_ip(ptr)) { 09262 return rb_tainted_str_new2(""); 09263 } 09264 09265 return (INT2FIX(ptr->return_value)); 09266 } 09267 09268 static VALUE 09269 ip_invoke(argc, argv, obj) 09270 int argc; 09271 VALUE *argv; 09272 VALUE obj; 09273 { 09274 return ip_invoke_with_position(argc, argv, obj, TCL_QUEUE_TAIL); 09275 } 09276 09277 static VALUE 09278 ip_invoke_immediate(argc, argv, obj) 09279 int argc; 09280 VALUE *argv; 09281 VALUE obj; 09282 { 09283 /* POTENTIALY INSECURE : can create infinite loop */ 09284 rb_secure(4); 09285 return ip_invoke_with_position(argc, argv, obj, TCL_QUEUE_HEAD); 09286 } 09287 09288 09289 /* access Tcl variables */ 09290 static VALUE 09291 ip_get_variable2_core(interp, argc, argv) 09292 VALUE interp; 09293 int argc; 09294 VALUE *argv; 09295 { 09296 struct tcltkip *ptr = get_ip(interp); 09297 int thr_crit_bup; 09298 volatile VALUE varname, index, flag; 09299 09300 varname = argv[0]; 09301 index = argv[1]; 09302 flag = argv[2]; 09303 09304 /* 09305 StringValue(varname); 09306 if (!NIL_P(index)) StringValue(index); 09307 */ 09308 09309 #if TCL_MAJOR_VERSION >= 8 09310 { 09311 Tcl_Obj *ret; 09312 volatile VALUE strval; 09313 09314 thr_crit_bup = rb_thread_critical; 09315 rb_thread_critical = Qtrue; 09316 09317 /* ip is deleted? */ 09318 if (deleted_ip(ptr)) { 09319 rb_thread_critical = thr_crit_bup; 09320 return rb_tainted_str_new2(""); 09321 } else { 09322 /* Tcl_Preserve(ptr->ip); */ 09323 rbtk_preserve_ip(ptr); 09324 ret = Tcl_GetVar2Ex(ptr->ip, RSTRING_PTR(varname), 09325 NIL_P(index) ? NULL : RSTRING_PTR(index), 09326 FIX2INT(flag)); 09327 } 09328 09329 if (ret == (Tcl_Obj*)NULL) { 09330 volatile VALUE exc; 09331 /* exc = rb_exc_new2(rb_eRuntimeError, 09332 Tcl_GetStringResult(ptr->ip)); */ 09333 exc = create_ip_exc(interp, rb_eRuntimeError, "%s", 09334 Tcl_GetStringResult(ptr->ip)); 09335 /* Tcl_Release(ptr->ip); */ 09336 rbtk_release_ip(ptr); 09337 rb_thread_critical = thr_crit_bup; 09338 return exc; 09339 } 09340 09341 Tcl_IncrRefCount(ret); 09342 strval = get_str_from_obj(ret); 09343 RbTk_OBJ_UNTRUST(strval); 09344 Tcl_DecrRefCount(ret); 09345 09346 /* Tcl_Release(ptr->ip); */ 09347 rbtk_release_ip(ptr); 09348 rb_thread_critical = thr_crit_bup; 09349 return(strval); 09350 } 09351 #else /* TCL_MAJOR_VERSION < 8 */ 09352 { 09353 char *ret; 09354 volatile VALUE strval; 09355 09356 /* ip is deleted? */ 09357 if (deleted_ip(ptr)) { 09358 return rb_tainted_str_new2(""); 09359 } else { 09360 /* Tcl_Preserve(ptr->ip); */ 09361 rbtk_preserve_ip(ptr); 09362 ret = Tcl_GetVar2(ptr->ip, RSTRING_PTR(varname), 09363 NIL_P(index) ? NULL : RSTRING_PTR(index), 09364 FIX2INT(flag)); 09365 } 09366 09367 if (ret == (char*)NULL) { 09368 volatile VALUE exc; 09369 exc = rb_exc_new2(rb_eRuntimeError, Tcl_GetStringResult(ptr->ip)); 09370 /* Tcl_Release(ptr->ip); */ 09371 rbtk_release_ip(ptr); 09372 rb_thread_critical = thr_crit_bup; 09373 return exc; 09374 } 09375 09376 strval = rb_tainted_str_new2(ret); 09377 /* Tcl_Release(ptr->ip); */ 09378 rbtk_release_ip(ptr); 09379 rb_thread_critical = thr_crit_bup; 09380 09381 return(strval); 09382 } 09383 #endif 09384 } 09385 09386 static VALUE 09387 ip_get_variable2(self, varname, index, flag) 09388 VALUE self; 09389 VALUE varname; 09390 VALUE index; 09391 VALUE flag; 09392 { 09393 VALUE argv[3]; 09394 VALUE retval; 09395 09396 StringValue(varname); 09397 if (!NIL_P(index)) StringValue(index); 09398 09399 argv[0] = varname; 09400 argv[1] = index; 09401 argv[2] = flag; 09402 09403 retval = tk_funcall(ip_get_variable2_core, 3, argv, self); 09404 09405 if (NIL_P(retval)) { 09406 return rb_tainted_str_new2(""); 09407 } else { 09408 return retval; 09409 } 09410 } 09411 09412 static VALUE 09413 ip_get_variable(self, varname, flag) 09414 VALUE self; 09415 VALUE varname; 09416 VALUE flag; 09417 { 09418 return ip_get_variable2(self, varname, Qnil, flag); 09419 } 09420 09421 static VALUE 09422 ip_set_variable2_core(interp, argc, argv) 09423 VALUE interp; 09424 int argc; 09425 VALUE *argv; 09426 { 09427 struct tcltkip *ptr = get_ip(interp); 09428 int thr_crit_bup; 09429 volatile VALUE varname, index, value, flag; 09430 09431 varname = argv[0]; 09432 index = argv[1]; 09433 value = argv[2]; 09434 flag = argv[3]; 09435 09436 /* 09437 StringValue(varname); 09438 if (!NIL_P(index)) StringValue(index); 09439 StringValue(value); 09440 */ 09441 09442 #if TCL_MAJOR_VERSION >= 8 09443 { 09444 Tcl_Obj *valobj, *ret; 09445 volatile VALUE strval; 09446 09447 thr_crit_bup = rb_thread_critical; 09448 rb_thread_critical = Qtrue; 09449 09450 valobj = get_obj_from_str(value); 09451 Tcl_IncrRefCount(valobj); 09452 09453 /* ip is deleted? */ 09454 if (deleted_ip(ptr)) { 09455 Tcl_DecrRefCount(valobj); 09456 rb_thread_critical = thr_crit_bup; 09457 return rb_tainted_str_new2(""); 09458 } else { 09459 /* Tcl_Preserve(ptr->ip); */ 09460 rbtk_preserve_ip(ptr); 09461 ret = Tcl_SetVar2Ex(ptr->ip, RSTRING_PTR(varname), 09462 NIL_P(index) ? NULL : RSTRING_PTR(index), 09463 valobj, FIX2INT(flag)); 09464 } 09465 09466 Tcl_DecrRefCount(valobj); 09467 09468 if (ret == (Tcl_Obj*)NULL) { 09469 volatile VALUE exc; 09470 /* exc = rb_exc_new2(rb_eRuntimeError, 09471 Tcl_GetStringResult(ptr->ip)); */ 09472 exc = create_ip_exc(interp, rb_eRuntimeError, "%s", 09473 Tcl_GetStringResult(ptr->ip)); 09474 /* Tcl_Release(ptr->ip); */ 09475 rbtk_release_ip(ptr); 09476 rb_thread_critical = thr_crit_bup; 09477 return exc; 09478 } 09479 09480 Tcl_IncrRefCount(ret); 09481 strval = get_str_from_obj(ret); 09482 RbTk_OBJ_UNTRUST(strval); 09483 Tcl_DecrRefCount(ret); 09484 09485 /* Tcl_Release(ptr->ip); */ 09486 rbtk_release_ip(ptr); 09487 rb_thread_critical = thr_crit_bup; 09488 09489 return(strval); 09490 } 09491 #else /* TCL_MAJOR_VERSION < 8 */ 09492 { 09493 CONST char *ret; 09494 volatile VALUE strval; 09495 09496 /* ip is deleted? */ 09497 if (deleted_ip(ptr)) { 09498 return rb_tainted_str_new2(""); 09499 } else { 09500 /* Tcl_Preserve(ptr->ip); */ 09501 rbtk_preserve_ip(ptr); 09502 ret = Tcl_SetVar2(ptr->ip, RSTRING_PTR(varname), 09503 NIL_P(index) ? NULL : RSTRING_PTR(index), 09504 RSTRING_PTR(value), FIX2INT(flag)); 09505 } 09506 09507 if (ret == (char*)NULL) { 09508 return rb_exc_new2(rb_eRuntimeError, ptr->ip->result); 09509 } 09510 09511 strval = rb_tainted_str_new2(ret); 09512 09513 /* Tcl_Release(ptr->ip); */ 09514 rbtk_release_ip(ptr); 09515 rb_thread_critical = thr_crit_bup; 09516 09517 return(strval); 09518 } 09519 #endif 09520 } 09521 09522 static VALUE 09523 ip_set_variable2(self, varname, index, value, flag) 09524 VALUE self; 09525 VALUE varname; 09526 VALUE index; 09527 VALUE value; 09528 VALUE flag; 09529 { 09530 VALUE argv[4]; 09531 VALUE retval; 09532 09533 StringValue(varname); 09534 if (!NIL_P(index)) StringValue(index); 09535 StringValue(value); 09536 09537 argv[0] = varname; 09538 argv[1] = index; 09539 argv[2] = value; 09540 argv[3] = flag; 09541 09542 retval = tk_funcall(ip_set_variable2_core, 4, argv, self); 09543 09544 if (NIL_P(retval)) { 09545 return rb_tainted_str_new2(""); 09546 } else { 09547 return retval; 09548 } 09549 } 09550 09551 static VALUE 09552 ip_set_variable(self, varname, value, flag) 09553 VALUE self; 09554 VALUE varname; 09555 VALUE value; 09556 VALUE flag; 09557 { 09558 return ip_set_variable2(self, varname, Qnil, value, flag); 09559 } 09560 09561 static VALUE 09562 ip_unset_variable2_core(interp, argc, argv) 09563 VALUE interp; 09564 int argc; 09565 VALUE *argv; 09566 { 09567 struct tcltkip *ptr = get_ip(interp); 09568 volatile VALUE varname, index, flag; 09569 09570 varname = argv[0]; 09571 index = argv[1]; 09572 flag = argv[2]; 09573 09574 /* 09575 StringValue(varname); 09576 if (!NIL_P(index)) StringValue(index); 09577 */ 09578 09579 /* ip is deleted? */ 09580 if (deleted_ip(ptr)) { 09581 return Qtrue; 09582 } 09583 09584 ptr->return_value = Tcl_UnsetVar2(ptr->ip, RSTRING_PTR(varname), 09585 NIL_P(index) ? NULL : RSTRING_PTR(index), 09586 FIX2INT(flag)); 09587 09588 if (ptr->return_value == TCL_ERROR) { 09589 if (FIX2INT(flag) & TCL_LEAVE_ERR_MSG) { 09590 /* return rb_exc_new2(rb_eRuntimeError, 09591 Tcl_GetStringResult(ptr->ip)); */ 09592 return create_ip_exc(interp, rb_eRuntimeError, "%s", 09593 Tcl_GetStringResult(ptr->ip)); 09594 } 09595 return Qfalse; 09596 } 09597 return Qtrue; 09598 } 09599 09600 static VALUE 09601 ip_unset_variable2(self, varname, index, flag) 09602 VALUE self; 09603 VALUE varname; 09604 VALUE index; 09605 VALUE flag; 09606 { 09607 VALUE argv[3]; 09608 VALUE retval; 09609 09610 StringValue(varname); 09611 if (!NIL_P(index)) StringValue(index); 09612 09613 argv[0] = varname; 09614 argv[1] = index; 09615 argv[2] = flag; 09616 09617 retval = tk_funcall(ip_unset_variable2_core, 3, argv, self); 09618 09619 if (NIL_P(retval)) { 09620 return rb_tainted_str_new2(""); 09621 } else { 09622 return retval; 09623 } 09624 } 09625 09626 static VALUE 09627 ip_unset_variable(self, varname, flag) 09628 VALUE self; 09629 VALUE varname; 09630 VALUE flag; 09631 { 09632 return ip_unset_variable2(self, varname, Qnil, flag); 09633 } 09634 09635 static VALUE 09636 ip_get_global_var(self, varname) 09637 VALUE self; 09638 VALUE varname; 09639 { 09640 return ip_get_variable(self, varname, 09641 INT2FIX(TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG)); 09642 } 09643 09644 static VALUE 09645 ip_get_global_var2(self, varname, index) 09646 VALUE self; 09647 VALUE varname; 09648 VALUE index; 09649 { 09650 return ip_get_variable2(self, varname, index, 09651 INT2FIX(TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG)); 09652 } 09653 09654 static VALUE 09655 ip_set_global_var(self, varname, value) 09656 VALUE self; 09657 VALUE varname; 09658 VALUE value; 09659 { 09660 return ip_set_variable(self, varname, value, 09661 INT2FIX(TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG)); 09662 } 09663 09664 static VALUE 09665 ip_set_global_var2(self, varname, index, value) 09666 VALUE self; 09667 VALUE varname; 09668 VALUE index; 09669 VALUE value; 09670 { 09671 return ip_set_variable2(self, varname, index, value, 09672 INT2FIX(TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG)); 09673 } 09674 09675 static VALUE 09676 ip_unset_global_var(self, varname) 09677 VALUE self; 09678 VALUE varname; 09679 { 09680 return ip_unset_variable(self, varname, 09681 INT2FIX(TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG)); 09682 } 09683 09684 static VALUE 09685 ip_unset_global_var2(self, varname, index) 09686 VALUE self; 09687 VALUE varname; 09688 VALUE index; 09689 { 09690 return ip_unset_variable2(self, varname, index, 09691 INT2FIX(TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG)); 09692 } 09693 09694 09695 /* treat Tcl_List */ 09696 static VALUE 09697 lib_split_tklist_core(ip_obj, list_str) 09698 VALUE ip_obj; 09699 VALUE list_str; 09700 { 09701 Tcl_Interp *interp; 09702 volatile VALUE ary, elem; 09703 int idx; 09704 int taint_flag = OBJ_TAINTED(list_str); 09705 #ifdef HAVE_RUBY_ENCODING_H 09706 int list_enc_idx; 09707 volatile VALUE list_ivar_enc; 09708 #endif 09709 int result; 09710 VALUE old_gc; 09711 09712 tcl_stubs_check(); 09713 09714 if (NIL_P(ip_obj)) { 09715 interp = (Tcl_Interp *)NULL; 09716 } else if (get_ip(ip_obj) == (struct tcltkip *)NULL) { 09717 interp = (Tcl_Interp *)NULL; 09718 } else { 09719 interp = get_ip(ip_obj)->ip; 09720 } 09721 09722 StringValue(list_str); 09723 #ifdef HAVE_RUBY_ENCODING_H 09724 list_enc_idx = rb_enc_get_index(list_str); 09725 list_ivar_enc = rb_ivar_get(list_str, ID_at_enc); 09726 #endif 09727 09728 { 09729 #if TCL_MAJOR_VERSION >= 8 09730 /* object style interface */ 09731 Tcl_Obj *listobj; 09732 int objc; 09733 Tcl_Obj **objv; 09734 int thr_crit_bup; 09735 09736 listobj = get_obj_from_str(list_str); 09737 09738 Tcl_IncrRefCount(listobj); 09739 09740 result = Tcl_ListObjGetElements(interp, listobj, &objc, &objv); 09741 09742 if (result == TCL_ERROR) { 09743 Tcl_DecrRefCount(listobj); 09744 if (interp == (Tcl_Interp*)NULL) { 09745 rb_raise(rb_eRuntimeError, "can't get elements from list"); 09746 } else { 09747 rb_raise(rb_eRuntimeError, "%s", Tcl_GetStringResult(interp)); 09748 } 09749 } 09750 09751 for(idx = 0; idx < objc; idx++) { 09752 Tcl_IncrRefCount(objv[idx]); 09753 } 09754 09755 thr_crit_bup = rb_thread_critical; 09756 rb_thread_critical = Qtrue; 09757 09758 ary = rb_ary_new2(objc); 09759 if (taint_flag) RbTk_OBJ_UNTRUST(ary); 09760 09761 old_gc = rb_gc_disable(); 09762 09763 for(idx = 0; idx < objc; idx++) { 09764 elem = get_str_from_obj(objv[idx]); 09765 if (taint_flag) RbTk_OBJ_UNTRUST(elem); 09766 09767 #ifdef HAVE_RUBY_ENCODING_H 09768 if (rb_enc_get_index(elem) == ENCODING_INDEX_BINARY) { 09769 rb_enc_associate_index(elem, ENCODING_INDEX_BINARY); 09770 rb_ivar_set(elem, ID_at_enc, ENCODING_NAME_BINARY); 09771 } else { 09772 rb_enc_associate_index(elem, list_enc_idx); 09773 rb_ivar_set(elem, ID_at_enc, list_ivar_enc); 09774 } 09775 #endif 09776 /* RARRAY(ary)->ptr[idx] = elem; */ 09777 rb_ary_push(ary, elem); 09778 } 09779 09780 /* RARRAY(ary)->len = objc; */ 09781 09782 if (old_gc == Qfalse) rb_gc_enable(); 09783 09784 rb_thread_critical = thr_crit_bup; 09785 09786 for(idx = 0; idx < objc; idx++) { 09787 Tcl_DecrRefCount(objv[idx]); 09788 } 09789 09790 Tcl_DecrRefCount(listobj); 09791 09792 #else /* TCL_MAJOR_VERSION < 8 */ 09793 /* string style interface */ 09794 int argc; 09795 char **argv; 09796 09797 if (Tcl_SplitList(interp, RSTRING_PTR(list_str), 09798 &argc, &argv) == TCL_ERROR) { 09799 if (interp == (Tcl_Interp*)NULL) { 09800 rb_raise(rb_eRuntimeError, "can't get elements from list"); 09801 } else { 09802 rb_raise(rb_eRuntimeError, "%s", interp->result); 09803 } 09804 } 09805 09806 ary = rb_ary_new2(argc); 09807 if (taint_flag) RbTk_OBJ_UNTRUST(ary); 09808 09809 old_gc = rb_gc_disable(); 09810 09811 for(idx = 0; idx < argc; idx++) { 09812 if (taint_flag) { 09813 elem = rb_tainted_str_new2(argv[idx]); 09814 } else { 09815 elem = rb_str_new2(argv[idx]); 09816 } 09817 /* rb_ivar_set(elem, ID_at_enc, rb_str_new2("binary")); */ 09818 /* RARRAY(ary)->ptr[idx] = elem; */ 09819 rb_ary_push(ary, elem) 09820 } 09821 /* RARRAY(ary)->len = argc; */ 09822 09823 if (old_gc == Qfalse) rb_gc_enable(); 09824 #endif 09825 } 09826 09827 return ary; 09828 } 09829 09830 static VALUE 09831 lib_split_tklist(self, list_str) 09832 VALUE self; 09833 VALUE list_str; 09834 { 09835 return lib_split_tklist_core(Qnil, list_str); 09836 } 09837 09838 09839 static VALUE 09840 ip_split_tklist(self, list_str) 09841 VALUE self; 09842 VALUE list_str; 09843 { 09844 return lib_split_tklist_core(self, list_str); 09845 } 09846 09847 static VALUE 09848 lib_merge_tklist(argc, argv, obj) 09849 int argc; 09850 VALUE *argv; 09851 VALUE obj; 09852 { 09853 int num, len; 09854 int *flagPtr; 09855 char *dst, *result; 09856 volatile VALUE str; 09857 int taint_flag = 0; 09858 int thr_crit_bup; 09859 VALUE old_gc; 09860 09861 if (argc == 0) return rb_str_new2(""); 09862 09863 tcl_stubs_check(); 09864 09865 thr_crit_bup = rb_thread_critical; 09866 rb_thread_critical = Qtrue; 09867 old_gc = rb_gc_disable(); 09868 09869 /* based on Tcl/Tk's Tcl_Merge() */ 09870 /* flagPtr = ALLOC_N(int, argc); */ 09871 flagPtr = (int *)ckalloc(sizeof(int) * argc); 09872 #if 0 /* use Tcl_Preserve/Release */ 09873 Tcl_Preserve((ClientData)flagPtr); /* XXXXXXXXXX */ 09874 #endif 09875 09876 /* pass 1 */ 09877 len = 1; 09878 for(num = 0; num < argc; num++) { 09879 if (OBJ_TAINTED(argv[num])) taint_flag = 1; 09880 dst = StringValuePtr(argv[num]); 09881 #if TCL_MAJOR_VERSION >= 8 09882 len += Tcl_ScanCountedElement(dst, RSTRING_LEN(argv[num]), 09883 &flagPtr[num]) + 1; 09884 #else /* TCL_MAJOR_VERSION < 8 */ 09885 len += Tcl_ScanElement(dst, &flagPtr[num]) + 1; 09886 #endif 09887 } 09888 09889 /* pass 2 */ 09890 /* result = (char *)Tcl_Alloc(len); */ 09891 result = (char *)ckalloc(len); 09892 #if 0 /* use Tcl_Preserve/Release */ 09893 Tcl_Preserve((ClientData)result); 09894 #endif 09895 dst = result; 09896 for(num = 0; num < argc; num++) { 09897 #if TCL_MAJOR_VERSION >= 8 09898 len = Tcl_ConvertCountedElement(RSTRING_PTR(argv[num]), 09899 RSTRING_LEN(argv[num]), 09900 dst, flagPtr[num]); 09901 #else /* TCL_MAJOR_VERSION < 8 */ 09902 len = Tcl_ConvertElement(RSTRING_PTR(argv[num]), dst, flagPtr[num]); 09903 #endif 09904 dst += len; 09905 *dst = ' '; 09906 dst++; 09907 } 09908 if (dst == result) { 09909 *dst = 0; 09910 } else { 09911 dst[-1] = 0; 09912 } 09913 09914 #if 0 /* use Tcl_EventuallyFree */ 09915 Tcl_EventuallyFree((ClientData)flagPtr, TCL_DYNAMIC); /* XXXXXXXX */ 09916 #else 09917 #if 0 /* use Tcl_Preserve/Release */ 09918 Tcl_Release((ClientData)flagPtr); 09919 #else 09920 /* free(flagPtr); */ 09921 ckfree((char*)flagPtr); 09922 #endif 09923 #endif 09924 09925 /* create object */ 09926 str = rb_str_new(result, dst - result - 1); 09927 if (taint_flag) RbTk_OBJ_UNTRUST(str); 09928 #if 0 /* use Tcl_EventuallyFree */ 09929 Tcl_EventuallyFree((ClientData)result, TCL_DYNAMIC); /* XXXXXXXX */ 09930 #else 09931 #if 0 /* use Tcl_Preserve/Release */ 09932 Tcl_Release((ClientData)result); /* XXXXXXXXXXX */ 09933 #else 09934 /* Tcl_Free(result); */ 09935 ckfree(result); 09936 #endif 09937 #endif 09938 09939 if (old_gc == Qfalse) rb_gc_enable(); 09940 rb_thread_critical = thr_crit_bup; 09941 09942 return str; 09943 } 09944 09945 static VALUE 09946 lib_conv_listelement(self, src) 09947 VALUE self; 09948 VALUE src; 09949 { 09950 int len, scan_flag; 09951 volatile VALUE dst; 09952 int taint_flag = OBJ_TAINTED(src); 09953 int thr_crit_bup; 09954 09955 tcl_stubs_check(); 09956 09957 thr_crit_bup = rb_thread_critical; 09958 rb_thread_critical = Qtrue; 09959 09960 StringValue(src); 09961 09962 #if TCL_MAJOR_VERSION >= 8 09963 len = Tcl_ScanCountedElement(RSTRING_PTR(src), RSTRING_LEN(src), 09964 &scan_flag); 09965 dst = rb_str_new(0, len + 1); 09966 len = Tcl_ConvertCountedElement(RSTRING_PTR(src), RSTRING_LEN(src), 09967 RSTRING_PTR(dst), scan_flag); 09968 #else /* TCL_MAJOR_VERSION < 8 */ 09969 len = Tcl_ScanElement(RSTRING_PTR(src), &scan_flag); 09970 dst = rb_str_new(0, len + 1); 09971 len = Tcl_ConvertElement(RSTRING_PTR(src), RSTRING_PTR(dst), scan_flag); 09972 #endif 09973 09974 rb_str_resize(dst, len); 09975 if (taint_flag) RbTk_OBJ_UNTRUST(dst); 09976 09977 rb_thread_critical = thr_crit_bup; 09978 09979 return dst; 09980 } 09981 09982 static VALUE 09983 lib_getversion(self) 09984 VALUE self; 09985 { 09986 set_tcltk_version(); 09987 09988 return rb_ary_new3(4, INT2NUM(tcltk_version.major), 09989 INT2NUM(tcltk_version.minor), 09990 INT2NUM(tcltk_version.type), 09991 INT2NUM(tcltk_version.patchlevel)); 09992 } 09993 09994 static VALUE 09995 lib_get_reltype_name(self) 09996 VALUE self; 09997 { 09998 set_tcltk_version(); 09999 10000 switch(tcltk_version.type) { 10001 case TCL_ALPHA_RELEASE: 10002 return rb_str_new2("alpha"); 10003 case TCL_BETA_RELEASE: 10004 return rb_str_new2("beta"); 10005 case TCL_FINAL_RELEASE: 10006 return rb_str_new2("final"); 10007 default: 10008 rb_raise(rb_eRuntimeError, "tcltklib has invalid release type number"); 10009 } 10010 } 10011 10012 10013 static VALUE 10014 tcltklib_compile_info() 10015 { 10016 volatile VALUE ret; 10017 int size; 10018 char form[] 10019 = "tcltklib %s :: Ruby%s (%s) %s pthread :: Tcl%s(%s)/Tk%s(%s) %s"; 10020 char *info; 10021 10022 size = strlen(form) 10023 + strlen(TCLTKLIB_RELEASE_DATE) 10024 + strlen(RUBY_VERSION) 10025 + strlen(RUBY_RELEASE_DATE) 10026 + strlen("without") 10027 + strlen(TCL_PATCH_LEVEL) 10028 + strlen("without stub") 10029 + strlen(TK_PATCH_LEVEL) 10030 + strlen("without stub") 10031 + strlen("unknown tcl_threads"); 10032 10033 info = ALLOC_N(char, size); 10034 /* info = ckalloc(sizeof(char) * size); */ /* SEGV */ 10035 10036 sprintf(info, form, 10037 TCLTKLIB_RELEASE_DATE, 10038 RUBY_VERSION, RUBY_RELEASE_DATE, 10039 #ifdef HAVE_NATIVETHREAD 10040 "with", 10041 #else 10042 "without", 10043 #endif 10044 TCL_PATCH_LEVEL, 10045 #ifdef USE_TCL_STUBS 10046 "with stub", 10047 #else 10048 "without stub", 10049 #endif 10050 TK_PATCH_LEVEL, 10051 #ifdef USE_TK_STUBS 10052 "with stub", 10053 #else 10054 "without stub", 10055 #endif 10056 #ifdef WITH_TCL_ENABLE_THREAD 10057 # if WITH_TCL_ENABLE_THREAD 10058 "with tcl_threads" 10059 # else 10060 "without tcl_threads" 10061 # endif 10062 #else 10063 "unknown tcl_threads" 10064 #endif 10065 ); 10066 10067 ret = rb_obj_freeze(rb_str_new2(info)); 10068 10069 xfree(info); 10070 /* ckfree(info); */ 10071 10072 return ret; 10073 } 10074 10075 10076 /*###############################################*/ 10077 10078 static VALUE 10079 create_dummy_encoding_for_tk_core(interp, name, error_mode) 10080 VALUE interp; 10081 VALUE name; 10082 VALUE error_mode; 10083 { 10084 get_ip(interp); 10085 10086 rb_secure(4); 10087 10088 StringValue(name); 10089 10090 #if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1) 10091 if (Tcl_GetEncoding((Tcl_Interp*)NULL, RSTRING_PTR(name)) == (Tcl_Encoding)NULL) { 10092 if (RTEST(error_mode)) { 10093 rb_raise(rb_eArgError, "invalid Tk encoding name '%s'", 10094 RSTRING_PTR(name)); 10095 } else { 10096 return Qnil; 10097 } 10098 } 10099 #endif 10100 10101 #ifdef HAVE_RUBY_ENCODING_H 10102 if (RTEST(rb_define_dummy_encoding(RSTRING_PTR(name)))) { 10103 int idx = rb_enc_find_index(StringValueCStr(name)); 10104 return rb_enc_from_encoding(rb_enc_from_index(idx)); 10105 } else { 10106 if (RTEST(error_mode)) { 10107 rb_raise(rb_eRuntimeError, "fail to create dummy encoding for '%s'", 10108 RSTRING_PTR(name)); 10109 } else { 10110 return Qnil; 10111 } 10112 } 10113 #else 10114 return name; 10115 #endif 10116 } 10117 static VALUE 10118 create_dummy_encoding_for_tk(interp, name) 10119 VALUE interp; 10120 VALUE name; 10121 { 10122 return create_dummy_encoding_for_tk_core(interp, name, Qtrue); 10123 } 10124 10125 10126 #ifdef HAVE_RUBY_ENCODING_H 10127 static int 10128 update_encoding_table(table, interp, error_mode) 10129 VALUE table; 10130 VALUE interp; 10131 VALUE error_mode; 10132 { 10133 struct tcltkip *ptr; 10134 int retry = 0; 10135 int i, idx, objc; 10136 Tcl_Obj **objv; 10137 Tcl_Obj *enc_list; 10138 volatile VALUE encname = Qnil; 10139 volatile VALUE encobj = Qnil; 10140 10141 /* interpreter check */ 10142 if (NIL_P(interp)) return 0; 10143 ptr = get_ip(interp); 10144 if (ptr == (struct tcltkip *) NULL) return 0; 10145 if (deleted_ip(ptr)) return 0; 10146 10147 /* get Tcl's encoding list */ 10148 Tcl_GetEncodingNames(ptr->ip); 10149 enc_list = Tcl_GetObjResult(ptr->ip); 10150 Tcl_IncrRefCount(enc_list); 10151 10152 if (Tcl_ListObjGetElements(ptr->ip, enc_list, 10153 &objc, &objv) != TCL_OK) { 10154 Tcl_DecrRefCount(enc_list); 10155 /* rb_raise(rb_eRuntimeError, "failt to get Tcl's encoding names");*/ 10156 return 0; 10157 } 10158 10159 /* check each encoding name */ 10160 for(i = 0; i < objc; i++) { 10161 encname = rb_str_new2(Tcl_GetString(objv[i])); 10162 if (NIL_P(rb_hash_lookup(table, encname))) { 10163 /* new Tk encoding -> add to table */ 10164 idx = rb_enc_find_index(StringValueCStr(encname)); 10165 if (idx < 0) { 10166 encobj = create_dummy_encoding_for_tk_core(interp,encname,error_mode); 10167 } else { 10168 encobj = rb_enc_from_encoding(rb_enc_from_index(idx)); 10169 } 10170 encname = rb_obj_freeze(encname); 10171 rb_hash_aset(table, encname, encobj); 10172 if (!NIL_P(encobj) && NIL_P(rb_hash_lookup(table, encobj))) { 10173 rb_hash_aset(table, encobj, encname); 10174 } 10175 retry = 1; 10176 } 10177 } 10178 10179 Tcl_DecrRefCount(enc_list); 10180 10181 return retry; 10182 } 10183 10184 static VALUE 10185 encoding_table_get_name_core(table, enc_arg, error_mode) 10186 VALUE table; 10187 VALUE enc_arg; 10188 VALUE error_mode; 10189 { 10190 volatile VALUE enc = enc_arg; 10191 volatile VALUE name = Qnil; 10192 volatile VALUE tmp = Qnil; 10193 volatile VALUE interp = rb_ivar_get(table, ID_at_interp); 10194 struct tcltkip *ptr = (struct tcltkip *) NULL; 10195 int idx; 10196 10197 /* deleted interp ? */ 10198 if (!NIL_P(interp)) { 10199 ptr = get_ip(interp); 10200 if (deleted_ip(ptr)) { 10201 ptr = (struct tcltkip *) NULL; 10202 } 10203 } 10204 10205 /* encoding argument check */ 10206 /* 1st: default encoding setting of interp */ 10207 if (ptr && NIL_P(enc)) { 10208 if (rb_respond_to(interp, ID_encoding_name)) { 10209 enc = rb_funcall(interp, ID_encoding_name, 0, 0); 10210 } 10211 } 10212 /* 2nd: Encoding.default_internal */ 10213 if (NIL_P(enc)) { 10214 enc = rb_enc_default_internal(); 10215 } 10216 /* 3rd: encoding system of Tcl/Tk */ 10217 if (NIL_P(enc)) { 10218 enc = rb_str_new2(Tcl_GetEncodingName((Tcl_Encoding)NULL)); 10219 } 10220 /* 4th: Encoding.default_external */ 10221 if (NIL_P(enc)) { 10222 enc = rb_enc_default_external(); 10223 } 10224 /* 5th: Encoding.locale_charmap */ 10225 if (NIL_P(enc)) { 10226 enc = rb_locale_charmap(rb_cEncoding); 10227 } 10228 10229 if (RTEST(rb_obj_is_kind_of(enc, cRubyEncoding))) { 10230 /* Ruby's Encoding object */ 10231 name = rb_hash_lookup(table, enc); 10232 if (!NIL_P(name)) { 10233 /* find */ 10234 return name; 10235 } 10236 10237 /* is it new ? */ 10238 /* update check of Tk encoding names */ 10239 if (update_encoding_table(table, interp, error_mode)) { 10240 /* add new relations to the table */ 10241 /* RETRY: registered Ruby encoding? */ 10242 name = rb_hash_lookup(table, enc); 10243 if (!NIL_P(name)) { 10244 /* find */ 10245 return name; 10246 } 10247 } 10248 /* fail to find */ 10249 10250 } else { 10251 /* String or Symbol? */ 10252 name = rb_funcall(enc, ID_to_s, 0, 0); 10253 10254 if (!NIL_P(rb_hash_lookup(table, name))) { 10255 /* find */ 10256 return name; 10257 } 10258 10259 /* is it new ? */ 10260 idx = rb_enc_find_index(StringValueCStr(name)); 10261 if (idx >= 0) { 10262 enc = rb_enc_from_encoding(rb_enc_from_index(idx)); 10263 10264 /* registered Ruby encoding? */ 10265 tmp = rb_hash_lookup(table, enc); 10266 if (!NIL_P(tmp)) { 10267 /* find */ 10268 return tmp; 10269 } 10270 10271 /* update check of Tk encoding names */ 10272 if (update_encoding_table(table, interp, error_mode)) { 10273 /* add new relations to the table */ 10274 /* RETRY: registered Ruby encoding? */ 10275 tmp = rb_hash_lookup(table, enc); 10276 if (!NIL_P(tmp)) { 10277 /* find */ 10278 return tmp; 10279 } 10280 } 10281 } 10282 /* fail to find */ 10283 } 10284 10285 if (RTEST(error_mode)) { 10286 enc = rb_funcall(enc_arg, ID_to_s, 0, 0); 10287 rb_raise(rb_eArgError, "unsupported Tk encoding '%s'", RSTRING_PTR(enc)); 10288 } 10289 return Qnil; 10290 } 10291 static VALUE 10292 encoding_table_get_obj_core(table, enc, error_mode) 10293 VALUE table; 10294 VALUE enc; 10295 VALUE error_mode; 10296 { 10297 volatile VALUE obj = Qnil; 10298 10299 obj = rb_hash_lookup(table, 10300 encoding_table_get_name_core(table, enc, error_mode)); 10301 if (RTEST(rb_obj_is_kind_of(obj, cRubyEncoding))) { 10302 return obj; 10303 } else { 10304 return Qnil; 10305 } 10306 } 10307 10308 #else /* ! HAVE_RUBY_ENCODING_H */ 10309 #if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1) 10310 static int 10311 update_encoding_table(table, interp, error_mode) 10312 VALUE table; 10313 VALUE interp; 10314 VALUE error_mode; 10315 { 10316 struct tcltkip *ptr; 10317 int retry = 0; 10318 int i, objc; 10319 Tcl_Obj **objv; 10320 Tcl_Obj *enc_list; 10321 volatile VALUE encname = Qnil; 10322 10323 /* interpreter check */ 10324 if (NIL_P(interp)) return 0; 10325 ptr = get_ip(interp); 10326 if (ptr == (struct tcltkip *) NULL) return 0; 10327 if (deleted_ip(ptr)) return 0; 10328 10329 /* get Tcl's encoding list */ 10330 Tcl_GetEncodingNames(ptr->ip); 10331 enc_list = Tcl_GetObjResult(ptr->ip); 10332 Tcl_IncrRefCount(enc_list); 10333 10334 if (Tcl_ListObjGetElements(ptr->ip, enc_list, &objc, &objv) != TCL_OK) { 10335 Tcl_DecrRefCount(enc_list); 10336 /* rb_raise(rb_eRuntimeError, "failt to get Tcl's encoding names"); */ 10337 return 0; 10338 } 10339 10340 /* get encoding name and set it to table */ 10341 for(i = 0; i < objc; i++) { 10342 encname = rb_str_new2(Tcl_GetString(objv[i])); 10343 if (NIL_P(rb_hash_lookup(table, encname))) { 10344 /* new Tk encoding -> add to table */ 10345 encname = rb_obj_freeze(encname); 10346 rb_hash_aset(table, encname, encname); 10347 retry = 1; 10348 } 10349 } 10350 10351 Tcl_DecrRefCount(enc_list); 10352 10353 return retry; 10354 } 10355 10356 static VALUE 10357 encoding_table_get_name_core(table, enc, error_mode) 10358 VALUE table; 10359 VALUE enc; 10360 VALUE error_mode; 10361 { 10362 volatile VALUE name = Qnil; 10363 10364 enc = rb_funcall(enc, ID_to_s, 0, 0); 10365 name = rb_hash_lookup(table, enc); 10366 10367 if (!NIL_P(name)) { 10368 /* find */ 10369 return name; 10370 } 10371 10372 /* update check */ 10373 if (update_encoding_table(table, rb_ivar_get(table, ID_at_interp), 10374 error_mode)) { 10375 /* add new relations to the table */ 10376 /* RETRY: registered Ruby encoding? */ 10377 name = rb_hash_lookup(table, enc); 10378 if (!NIL_P(name)) { 10379 /* find */ 10380 return name; 10381 } 10382 } 10383 10384 if (RTEST(error_mode)) { 10385 rb_raise(rb_eArgError, "unsupported Tk encoding '%s'", RSTRING_PTR(enc)); 10386 } 10387 return Qnil; 10388 } 10389 static VALUE 10390 encoding_table_get_obj_core(table, enc, error_mode) 10391 VALUE table; 10392 VALUE enc; 10393 VALUE error_mode; 10394 { 10395 return encoding_table_get_name_core(table, enc, error_mode); 10396 } 10397 10398 #else /* Tcl/Tk 7.x or 8.0 */ 10399 static VALUE 10400 encoding_table_get_name_core(table, enc, error_mode) 10401 VALUE table; 10402 VALUE enc; 10403 VALUE error_mode; 10404 { 10405 return Qnil; 10406 } 10407 static VALUE 10408 encoding_table_get_obj_core(table, enc, error_mode) 10409 VALUE table; 10410 VALUE enc; 10411 VALUE error_mode; 10412 { 10413 return Qnil; 10414 } 10415 #endif /* end of dependency for the version of Tcl/Tk */ 10416 #endif 10417 10418 static VALUE 10419 encoding_table_get_name(table, enc) 10420 VALUE table; 10421 VALUE enc; 10422 { 10423 return encoding_table_get_name_core(table, enc, Qtrue); 10424 } 10425 static VALUE 10426 encoding_table_get_obj(table, enc) 10427 VALUE table; 10428 VALUE enc; 10429 { 10430 return encoding_table_get_obj_core(table, enc, Qtrue); 10431 } 10432 10433 #ifdef HAVE_RUBY_ENCODING_H 10434 static VALUE 10435 create_encoding_table_core(arg, interp) 10436 VALUE arg; 10437 VALUE interp; 10438 { 10439 struct tcltkip *ptr = get_ip(interp); 10440 volatile VALUE table = rb_hash_new(); 10441 volatile VALUE encname = Qnil; 10442 volatile VALUE encobj = Qnil; 10443 int i, idx, objc; 10444 Tcl_Obj **objv; 10445 Tcl_Obj *enc_list; 10446 10447 #ifdef HAVE_RB_SET_SAFE_LEVEL_FORCE 10448 rb_set_safe_level_force(0); 10449 #else 10450 rb_set_safe_level(0); 10451 #endif 10452 10453 /* set 'binary' encoding */ 10454 encobj = rb_enc_from_encoding(rb_enc_from_index(ENCODING_INDEX_BINARY)); 10455 rb_hash_aset(table, ENCODING_NAME_BINARY, encobj); 10456 rb_hash_aset(table, encobj, ENCODING_NAME_BINARY); 10457 10458 10459 /* Tcl stub check */ 10460 tcl_stubs_check(); 10461 10462 /* get Tcl's encoding list */ 10463 Tcl_GetEncodingNames(ptr->ip); 10464 enc_list = Tcl_GetObjResult(ptr->ip); 10465 Tcl_IncrRefCount(enc_list); 10466 10467 if (Tcl_ListObjGetElements(ptr->ip, enc_list, &objc, &objv) != TCL_OK) { 10468 Tcl_DecrRefCount(enc_list); 10469 rb_raise(rb_eRuntimeError, "failt to get Tcl's encoding names"); 10470 } 10471 10472 /* get encoding name and set it to table */ 10473 for(i = 0; i < objc; i++) { 10474 int name2obj, obj2name; 10475 10476 name2obj = 1; obj2name = 1; 10477 encname = rb_obj_freeze(rb_str_new2(Tcl_GetString(objv[i]))); 10478 idx = rb_enc_find_index(StringValueCStr(encname)); 10479 if (idx < 0) { 10480 /* fail to find ruby encoding -> check known encoding */ 10481 if (strcmp(RSTRING_PTR(encname), "identity") == 0) { 10482 name2obj = 1; obj2name = 0; 10483 idx = ENCODING_INDEX_BINARY; 10484 10485 } else if (strcmp(RSTRING_PTR(encname), "shiftjis") == 0) { 10486 name2obj = 1; obj2name = 0; 10487 idx = rb_enc_find_index("Shift_JIS"); 10488 10489 } else if (strcmp(RSTRING_PTR(encname), "unicode") == 0) { 10490 name2obj = 1; obj2name = 0; 10491 idx = ENCODING_INDEX_UTF8; 10492 10493 } else if (strcmp(RSTRING_PTR(encname), "symbol") == 0) { 10494 name2obj = 1; obj2name = 0; 10495 idx = rb_enc_find_index("ASCII-8BIT"); 10496 10497 } else { 10498 /* regist dummy encoding */ 10499 name2obj = 1; obj2name = 1; 10500 } 10501 } 10502 10503 if (idx < 0) { 10504 /* unknown encoding -> create dummy */ 10505 encobj = create_dummy_encoding_for_tk(interp, encname); 10506 } else { 10507 encobj = rb_enc_from_encoding(rb_enc_from_index(idx)); 10508 } 10509 10510 if (name2obj) { 10511 DUMP2("create_encoding_table: name2obj: %s", RSTRING_PTR(encname)); 10512 rb_hash_aset(table, encname, encobj); 10513 } 10514 if (obj2name) { 10515 DUMP2("create_encoding_table: obj2name: %s", RSTRING_PTR(encname)); 10516 rb_hash_aset(table, encobj, encname); 10517 } 10518 } 10519 10520 Tcl_DecrRefCount(enc_list); 10521 10522 rb_ivar_set(table, ID_at_interp, interp); 10523 rb_ivar_set(interp, ID_encoding_table, table); 10524 10525 return table; 10526 } 10527 10528 #else /* ! HAVE_RUBY_ENCODING_H */ 10529 #if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 1) 10530 static VALUE 10531 create_encoding_table_core(arg, interp) 10532 VALUE arg; 10533 VALUE interp; 10534 { 10535 struct tcltkip *ptr = get_ip(interp); 10536 volatile VALUE table = rb_hash_new(); 10537 volatile VALUE encname = Qnil; 10538 int i, objc; 10539 Tcl_Obj **objv; 10540 Tcl_Obj *enc_list; 10541 10542 rb_secure(4); 10543 10544 /* set 'binary' encoding */ 10545 rb_hash_aset(table, ENCODING_NAME_BINARY, ENCODING_NAME_BINARY); 10546 10547 /* get Tcl's encoding list */ 10548 Tcl_GetEncodingNames(ptr->ip); 10549 enc_list = Tcl_GetObjResult(ptr->ip); 10550 Tcl_IncrRefCount(enc_list); 10551 10552 if (Tcl_ListObjGetElements(ptr->ip, enc_list, &objc, &objv) != TCL_OK) { 10553 Tcl_DecrRefCount(enc_list); 10554 rb_raise(rb_eRuntimeError, "failt to get Tcl's encoding names"); 10555 } 10556 10557 /* get encoding name and set it to table */ 10558 for(i = 0; i < objc; i++) { 10559 encname = rb_obj_freeze(rb_str_new2(Tcl_GetString(objv[i]))); 10560 rb_hash_aset(table, encname, encname); 10561 } 10562 10563 Tcl_DecrRefCount(enc_list); 10564 10565 rb_ivar_set(table, ID_at_interp, interp); 10566 rb_ivar_set(interp, ID_encoding_table, table); 10567 10568 return table; 10569 } 10570 10571 #else /* Tcl/Tk 7.x or 8.0 */ 10572 static VALUE 10573 create_encoding_table_core(arg, interp) 10574 VALUE arg; 10575 VALUE interp; 10576 { 10577 volatile VALUE table = rb_hash_new(); 10578 rb_secure(4); 10579 rb_ivar_set(interp, ID_encoding_table, table); 10580 return table; 10581 } 10582 #endif 10583 #endif 10584 10585 static VALUE 10586 create_encoding_table(interp) 10587 VALUE interp; 10588 { 10589 return rb_funcall(rb_proc_new(create_encoding_table_core, interp), 10590 ID_call, 0); 10591 } 10592 10593 static VALUE 10594 ip_get_encoding_table(interp) 10595 VALUE interp; 10596 { 10597 volatile VALUE table = Qnil; 10598 10599 table = rb_ivar_get(interp, ID_encoding_table); 10600 10601 if (NIL_P(table)) { 10602 /* initialize encoding_table */ 10603 table = create_encoding_table(interp); 10604 rb_define_singleton_method(table, "get_name", encoding_table_get_name, 1); 10605 rb_define_singleton_method(table, "get_obj", encoding_table_get_obj, 1); 10606 } 10607 10608 return table; 10609 } 10610 10611 10612 /*###############################################*/ 10613 10614 /* 10615 * The following is based on tkMenu.[ch] 10616 * of Tcl/Tk (Tk8.0 -- Tk8.5b1) source code. 10617 */ 10618 #if TCL_MAJOR_VERSION >= 8 10619 10620 #define MASTER_MENU 0 10621 #define TEAROFF_MENU 1 10622 #define MENUBAR 2 10623 10624 struct dummy_TkMenuEntry { 10625 int type; 10626 struct dummy_TkMenu *menuPtr; 10627 /* , and etc. */ 10628 }; 10629 10630 struct dummy_TkMenu { 10631 Tk_Window tkwin; 10632 Display *display; 10633 Tcl_Interp *interp; 10634 Tcl_Command widgetCmd; 10635 struct dummy_TkMenuEntry **entries; 10636 int numEntries; 10637 int active; 10638 int menuType; /* MASTER_MENU, TEAROFF_MENU, or MENUBAR */ 10639 Tcl_Obj *menuTypePtr; 10640 /* , and etc. */ 10641 }; 10642 10643 struct dummy_TkMenuRef { 10644 struct dummy_TkMenu *menuPtr; 10645 char *dummy1; 10646 char *dummy2; 10647 char *dummy3; 10648 }; 10649 10650 #if 0 /* was available on Tk8.0 -- Tk8.4 */ 10651 EXTERN struct dummy_TkMenuRef *TkFindMenuReferences(Tcl_Interp*, char*); 10652 #else /* based on Tk8.0 -- Tk8.5.0 */ 10653 #define MENU_HASH_KEY "tkMenus" 10654 #endif 10655 10656 #endif 10657 10658 static VALUE 10659 ip_make_menu_embeddable_core(interp, argc, argv) 10660 VALUE interp; 10661 int argc; 10662 VALUE *argv; 10663 { 10664 #if TCL_MAJOR_VERSION >= 8 10665 volatile VALUE menu_path; 10666 struct tcltkip *ptr = get_ip(interp); 10667 struct dummy_TkMenuRef *menuRefPtr = NULL; 10668 XEvent event; 10669 Tcl_HashTable *menuTablePtr; 10670 Tcl_HashEntry *hashEntryPtr; 10671 10672 menu_path = argv[0]; 10673 StringValue(menu_path); 10674 10675 #if 0 /* was available on Tk8.0 -- Tk8.4 */ 10676 menuRefPtr = TkFindMenuReferences(ptr->ip, RSTRING_PTR(menu_path)); 10677 #else /* based on Tk8.0 -- Tk8.5b1 */ 10678 if ((menuTablePtr 10679 = (Tcl_HashTable *) Tcl_GetAssocData(ptr->ip, MENU_HASH_KEY, NULL)) 10680 != NULL) { 10681 if ((hashEntryPtr 10682 = Tcl_FindHashEntry(menuTablePtr, RSTRING_PTR(menu_path))) 10683 != NULL) { 10684 menuRefPtr = (struct dummy_TkMenuRef *) Tcl_GetHashValue(hashEntryPtr); 10685 } 10686 } 10687 #endif 10688 10689 if (menuRefPtr == (struct dummy_TkMenuRef *) NULL) { 10690 rb_raise(rb_eArgError, "not a menu widget, or invalid widget path"); 10691 } 10692 10693 if (menuRefPtr->menuPtr == (struct dummy_TkMenu *) NULL) { 10694 rb_raise(rb_eRuntimeError, 10695 "invalid menu widget (maybe already destroyed)"); 10696 } 10697 10698 if ((menuRefPtr->menuPtr)->menuType != MENUBAR) { 10699 rb_raise(rb_eRuntimeError, 10700 "target menu widget must be a MENUBAR type"); 10701 } 10702 10703 (menuRefPtr->menuPtr)->menuType = TEAROFF_MENU; 10704 #if 0 /* cause SEGV */ 10705 { 10706 /* char *s = "tearoff"; */ 10707 char *s = "normal"; 10708 /* Tcl_SetStringObj((menuRefPtr->menuPtr)->menuTypePtr, s, strlen(s));*/ 10709 (menuRefPtr->menuPtr)->menuTypePtr = Tcl_NewStringObj(s, strlen(s)); 10710 /* Tcl_IncrRefCount((menuRefPtr->menuPtr)->menuTypePtr); */ 10711 /* (menuRefPtr->menuPtr)->menuType = TEAROFF_MENU; */ 10712 (menuRefPtr->menuPtr)->menuType = MASTER_MENU; 10713 } 10714 #endif 10715 10716 #if 0 /* was available on Tk8.0 -- Tk8.4 */ 10717 TkEventuallyRecomputeMenu(menuRefPtr->menuPtr); 10718 TkEventuallyRedrawMenu(menuRefPtr->menuPtr, 10719 (struct dummy_TkMenuEntry *)NULL); 10720 #else /* based on Tk8.0 -- Tk8.5b1 */ 10721 memset((void *) &event, 0, sizeof(event)); 10722 event.xany.type = ConfigureNotify; 10723 event.xany.serial = NextRequest(Tk_Display((menuRefPtr->menuPtr)->tkwin)); 10724 event.xany.send_event = 0; /* FALSE */ 10725 event.xany.window = Tk_WindowId((menuRefPtr->menuPtr)->tkwin); 10726 event.xany.display = Tk_Display((menuRefPtr->menuPtr)->tkwin); 10727 event.xconfigure.window = event.xany.window; 10728 Tk_HandleEvent(&event); 10729 #endif 10730 10731 #else /* TCL_MAJOR_VERSION <= 7 */ 10732 rb_notimplement(); 10733 #endif 10734 10735 return interp; 10736 } 10737 10738 static VALUE 10739 ip_make_menu_embeddable(interp, menu_path) 10740 VALUE interp; 10741 VALUE menu_path; 10742 { 10743 VALUE argv[1]; 10744 10745 argv[0] = menu_path; 10746 return tk_funcall(ip_make_menu_embeddable_core, 1, argv, interp); 10747 } 10748 10749 10750 /*###############################################*/ 10751 10752 /*---- initialization ----*/ 10753 void 10754 Init_tcltklib() 10755 { 10756 int ret; 10757 10758 VALUE lib = rb_define_module("TclTkLib"); 10759 VALUE ip = rb_define_class("TclTkIp", rb_cObject); 10760 10761 VALUE ev_flag = rb_define_module_under(lib, "EventFlag"); 10762 VALUE var_flag = rb_define_module_under(lib, "VarAccessFlag"); 10763 VALUE release_type = rb_define_module_under(lib, "RELEASE_TYPE"); 10764 10765 /* --------------------------------------------------------------- */ 10766 10767 tcltkip_class = ip; 10768 10769 /* --------------------------------------------------------------- */ 10770 10771 #ifdef HAVE_RUBY_ENCODING_H 10772 rb_global_variable(&cRubyEncoding); 10773 cRubyEncoding = rb_path2class("Encoding"); 10774 10775 ENCODING_INDEX_UTF8 = rb_enc_to_index(rb_utf8_encoding()); 10776 ENCODING_INDEX_BINARY = rb_enc_find_index("binary"); 10777 #endif 10778 10779 rb_global_variable(&ENCODING_NAME_UTF8); 10780 rb_global_variable(&ENCODING_NAME_BINARY); 10781 10782 ENCODING_NAME_UTF8 = rb_obj_freeze(rb_str_new2("utf-8")); 10783 ENCODING_NAME_BINARY = rb_obj_freeze(rb_str_new2("binary")); 10784 10785 /* --------------------------------------------------------------- */ 10786 10787 rb_global_variable(&eTkCallbackReturn); 10788 rb_global_variable(&eTkCallbackBreak); 10789 rb_global_variable(&eTkCallbackContinue); 10790 10791 rb_global_variable(&eventloop_thread); 10792 rb_global_variable(&eventloop_stack); 10793 rb_global_variable(&watchdog_thread); 10794 10795 rb_global_variable(&rbtk_pending_exception); 10796 10797 /* --------------------------------------------------------------- */ 10798 10799 rb_define_const(lib, "COMPILE_INFO", tcltklib_compile_info()); 10800 10801 rb_define_const(lib, "RELEASE_DATE", 10802 rb_obj_freeze(rb_str_new2(tcltklib_release_date))); 10803 10804 rb_define_const(lib, "FINALIZE_PROC_NAME", 10805 rb_str_new2(finalize_hook_name)); 10806 10807 /* --------------------------------------------------------------- */ 10808 10809 #ifdef __WIN32__ 10810 # define TK_WINDOWING_SYSTEM "win32" 10811 #else 10812 # ifdef MAC_TCL 10813 # define TK_WINDOWING_SYSTEM "classic" 10814 # else 10815 # ifdef MAC_OSX_TK 10816 # define TK_WINDOWING_SYSTEM "aqua" 10817 # else 10818 # define TK_WINDOWING_SYSTEM "x11" 10819 # endif 10820 # endif 10821 #endif 10822 rb_define_const(lib, "WINDOWING_SYSTEM", 10823 rb_obj_freeze(rb_str_new2(TK_WINDOWING_SYSTEM))); 10824 10825 /* --------------------------------------------------------------- */ 10826 10827 rb_define_const(ev_flag, "NONE", INT2FIX(0)); 10828 rb_define_const(ev_flag, "WINDOW", INT2FIX(TCL_WINDOW_EVENTS)); 10829 rb_define_const(ev_flag, "FILE", INT2FIX(TCL_FILE_EVENTS)); 10830 rb_define_const(ev_flag, "TIMER", INT2FIX(TCL_TIMER_EVENTS)); 10831 rb_define_const(ev_flag, "IDLE", INT2FIX(TCL_IDLE_EVENTS)); 10832 rb_define_const(ev_flag, "ALL", INT2FIX(TCL_ALL_EVENTS)); 10833 rb_define_const(ev_flag, "DONT_WAIT", INT2FIX(TCL_DONT_WAIT)); 10834 10835 /* --------------------------------------------------------------- */ 10836 10837 rb_define_const(var_flag, "NONE", INT2FIX(0)); 10838 rb_define_const(var_flag, "GLOBAL_ONLY", INT2FIX(TCL_GLOBAL_ONLY)); 10839 #ifdef TCL_NAMESPACE_ONLY 10840 rb_define_const(var_flag, "NAMESPACE_ONLY", INT2FIX(TCL_NAMESPACE_ONLY)); 10841 #else /* probably Tcl7.6 */ 10842 rb_define_const(var_flag, "NAMESPACE_ONLY", INT2FIX(0)); 10843 #endif 10844 rb_define_const(var_flag, "LEAVE_ERR_MSG", INT2FIX(TCL_LEAVE_ERR_MSG)); 10845 rb_define_const(var_flag, "APPEND_VALUE", INT2FIX(TCL_APPEND_VALUE)); 10846 rb_define_const(var_flag, "LIST_ELEMENT", INT2FIX(TCL_LIST_ELEMENT)); 10847 #ifdef TCL_PARSE_PART1 10848 rb_define_const(var_flag, "PARSE_VARNAME", INT2FIX(TCL_PARSE_PART1)); 10849 #else /* probably Tcl7.6 */ 10850 rb_define_const(var_flag, "PARSE_VARNAME", INT2FIX(0)); 10851 #endif 10852 10853 /* --------------------------------------------------------------- */ 10854 10855 rb_define_module_function(lib, "get_version", lib_getversion, -1); 10856 rb_define_module_function(lib, "get_release_type_name", 10857 lib_get_reltype_name, -1); 10858 10859 rb_define_const(release_type, "ALPHA", INT2FIX(TCL_ALPHA_RELEASE)); 10860 rb_define_const(release_type, "BETA", INT2FIX(TCL_BETA_RELEASE)); 10861 rb_define_const(release_type, "FINAL", INT2FIX(TCL_FINAL_RELEASE)); 10862 10863 /* --------------------------------------------------------------- */ 10864 10865 eTkCallbackReturn = rb_define_class("TkCallbackReturn", rb_eStandardError); 10866 eTkCallbackBreak = rb_define_class("TkCallbackBreak", rb_eStandardError); 10867 eTkCallbackContinue = rb_define_class("TkCallbackContinue", 10868 rb_eStandardError); 10869 10870 /* --------------------------------------------------------------- */ 10871 10872 eLocalJumpError = rb_const_get(rb_cObject, rb_intern("LocalJumpError")); 10873 10874 eTkLocalJumpError = rb_define_class("TkLocalJumpError", eLocalJumpError); 10875 10876 eTkCallbackRetry = rb_define_class("TkCallbackRetry", eTkLocalJumpError); 10877 eTkCallbackRedo = rb_define_class("TkCallbackRedo", eTkLocalJumpError); 10878 eTkCallbackThrow = rb_define_class("TkCallbackThrow", eTkLocalJumpError); 10879 10880 /* --------------------------------------------------------------- */ 10881 10882 ID_at_enc = rb_intern("@encoding"); 10883 ID_at_interp = rb_intern("@interp"); 10884 ID_encoding_name = rb_intern("encoding_name"); 10885 ID_encoding_table = rb_intern("encoding_table"); 10886 10887 ID_stop_p = rb_intern("stop?"); 10888 ID_alive_p = rb_intern("alive?"); 10889 ID_kill = rb_intern("kill"); 10890 ID_join = rb_intern("join"); 10891 ID_value = rb_intern("value"); 10892 10893 ID_call = rb_intern("call"); 10894 ID_backtrace = rb_intern("backtrace"); 10895 ID_message = rb_intern("message"); 10896 10897 ID_at_reason = rb_intern("@reason"); 10898 ID_return = rb_intern("return"); 10899 ID_break = rb_intern("break"); 10900 ID_next = rb_intern("next"); 10901 10902 ID_to_s = rb_intern("to_s"); 10903 ID_inspect = rb_intern("inspect"); 10904 10905 /* --------------------------------------------------------------- */ 10906 10907 rb_define_module_function(lib, "mainloop", lib_mainloop, -1); 10908 rb_define_module_function(lib, "mainloop_thread?", 10909 lib_evloop_thread_p, 0); 10910 rb_define_module_function(lib, "mainloop_watchdog", 10911 lib_mainloop_watchdog, -1); 10912 rb_define_module_function(lib, "do_thread_callback", 10913 lib_thread_callback, -1); 10914 rb_define_module_function(lib, "do_one_event", lib_do_one_event, -1); 10915 rb_define_module_function(lib, "mainloop_abort_on_exception", 10916 lib_evloop_abort_on_exc, 0); 10917 rb_define_module_function(lib, "mainloop_abort_on_exception=", 10918 lib_evloop_abort_on_exc_set, 1); 10919 rb_define_module_function(lib, "set_eventloop_window_mode", 10920 set_eventloop_window_mode, 1); 10921 rb_define_module_function(lib, "get_eventloop_window_mode", 10922 get_eventloop_window_mode, 0); 10923 rb_define_module_function(lib, "set_eventloop_tick",set_eventloop_tick,1); 10924 rb_define_module_function(lib, "get_eventloop_tick",get_eventloop_tick,0); 10925 rb_define_module_function(lib, "set_no_event_wait", set_no_event_wait, 1); 10926 rb_define_module_function(lib, "get_no_event_wait", get_no_event_wait, 0); 10927 rb_define_module_function(lib, "set_eventloop_weight", 10928 set_eventloop_weight, 2); 10929 rb_define_module_function(lib, "set_max_block_time", set_max_block_time,1); 10930 rb_define_module_function(lib, "get_eventloop_weight", 10931 get_eventloop_weight, 0); 10932 rb_define_module_function(lib, "num_of_mainwindows", 10933 lib_num_of_mainwindows, 0); 10934 10935 /* --------------------------------------------------------------- */ 10936 10937 rb_define_module_function(lib, "_split_tklist", lib_split_tklist, 1); 10938 rb_define_module_function(lib, "_merge_tklist", lib_merge_tklist, -1); 10939 rb_define_module_function(lib, "_conv_listelement", 10940 lib_conv_listelement, 1); 10941 rb_define_module_function(lib, "_toUTF8", lib_toUTF8, -1); 10942 rb_define_module_function(lib, "_fromUTF8", lib_fromUTF8, -1); 10943 rb_define_module_function(lib, "_subst_UTF_backslash", 10944 lib_UTF_backslash, 1); 10945 rb_define_module_function(lib, "_subst_Tcl_backslash", 10946 lib_Tcl_backslash, 1); 10947 10948 rb_define_module_function(lib, "encoding_system", 10949 lib_get_system_encoding, 0); 10950 rb_define_module_function(lib, "encoding_system=", 10951 lib_set_system_encoding, 1); 10952 rb_define_module_function(lib, "encoding", 10953 lib_get_system_encoding, 0); 10954 rb_define_module_function(lib, "encoding=", 10955 lib_set_system_encoding, 1); 10956 10957 /* --------------------------------------------------------------- */ 10958 10959 rb_define_alloc_func(ip, ip_alloc); 10960 rb_define_method(ip, "initialize", ip_init, -1); 10961 rb_define_method(ip, "create_slave", ip_create_slave, -1); 10962 rb_define_method(ip, "slave_of?", ip_is_slave_of_p, 1); 10963 rb_define_method(ip, "make_safe", ip_make_safe, 0); 10964 rb_define_method(ip, "safe?", ip_is_safe_p, 0); 10965 rb_define_method(ip, "allow_ruby_exit?", ip_allow_ruby_exit_p, 0); 10966 rb_define_method(ip, "allow_ruby_exit=", ip_allow_ruby_exit_set, 1); 10967 rb_define_method(ip, "delete", ip_delete, 0); 10968 rb_define_method(ip, "deleted?", ip_is_deleted_p, 0); 10969 rb_define_method(ip, "has_mainwindow?", ip_has_mainwindow_p, 0); 10970 rb_define_method(ip, "invalid_namespace?", ip_has_invalid_namespace_p, 0); 10971 rb_define_method(ip, "_eval", ip_eval, 1); 10972 rb_define_method(ip, "_cancel_eval", ip_cancel_eval, -1); 10973 rb_define_method(ip, "_cancel_eval_unwind", ip_cancel_eval_unwind, -1); 10974 rb_define_method(ip, "_toUTF8", ip_toUTF8, -1); 10975 rb_define_method(ip, "_fromUTF8", ip_fromUTF8, -1); 10976 rb_define_method(ip, "_thread_vwait", ip_thread_vwait, 1); 10977 rb_define_method(ip, "_thread_tkwait", ip_thread_tkwait, 2); 10978 rb_define_method(ip, "_invoke", ip_invoke, -1); 10979 rb_define_method(ip, "_immediate_invoke", ip_invoke_immediate, -1); 10980 rb_define_method(ip, "_return_value", ip_retval, 0); 10981 10982 rb_define_method(ip, "_create_console", ip_create_console, 0); 10983 10984 /* --------------------------------------------------------------- */ 10985 10986 rb_define_method(ip, "create_dummy_encoding_for_tk", 10987 create_dummy_encoding_for_tk, 1); 10988 rb_define_method(ip, "encoding_table", ip_get_encoding_table, 0); 10989 10990 /* --------------------------------------------------------------- */ 10991 10992 rb_define_method(ip, "_get_variable", ip_get_variable, 2); 10993 rb_define_method(ip, "_get_variable2", ip_get_variable2, 3); 10994 rb_define_method(ip, "_set_variable", ip_set_variable, 3); 10995 rb_define_method(ip, "_set_variable2", ip_set_variable2, 4); 10996 rb_define_method(ip, "_unset_variable", ip_unset_variable, 2); 10997 rb_define_method(ip, "_unset_variable2", ip_unset_variable2, 3); 10998 rb_define_method(ip, "_get_global_var", ip_get_global_var, 1); 10999 rb_define_method(ip, "_get_global_var2", ip_get_global_var2, 2); 11000 rb_define_method(ip, "_set_global_var", ip_set_global_var, 2); 11001 rb_define_method(ip, "_set_global_var2", ip_set_global_var2, 3); 11002 rb_define_method(ip, "_unset_global_var", ip_unset_global_var, 1); 11003 rb_define_method(ip, "_unset_global_var2", ip_unset_global_var2, 2); 11004 11005 /* --------------------------------------------------------------- */ 11006 11007 rb_define_method(ip, "_make_menu_embeddable", ip_make_menu_embeddable, 1); 11008 11009 /* --------------------------------------------------------------- */ 11010 11011 rb_define_method(ip, "_split_tklist", ip_split_tklist, 1); 11012 rb_define_method(ip, "_merge_tklist", lib_merge_tklist, -1); 11013 rb_define_method(ip, "_conv_listelement", lib_conv_listelement, 1); 11014 11015 /* --------------------------------------------------------------- */ 11016 11017 rb_define_method(ip, "mainloop", ip_mainloop, -1); 11018 rb_define_method(ip, "mainloop_watchdog", ip_mainloop_watchdog, -1); 11019 rb_define_method(ip, "do_one_event", ip_do_one_event, -1); 11020 rb_define_method(ip, "mainloop_abort_on_exception", 11021 ip_evloop_abort_on_exc, 0); 11022 rb_define_method(ip, "mainloop_abort_on_exception=", 11023 ip_evloop_abort_on_exc_set, 1); 11024 rb_define_method(ip, "set_eventloop_tick", ip_set_eventloop_tick, 1); 11025 rb_define_method(ip, "get_eventloop_tick", ip_get_eventloop_tick, 0); 11026 rb_define_method(ip, "set_no_event_wait", ip_set_no_event_wait, 1); 11027 rb_define_method(ip, "get_no_event_wait", ip_get_no_event_wait, 0); 11028 rb_define_method(ip, "set_eventloop_weight", ip_set_eventloop_weight, 2); 11029 rb_define_method(ip, "get_eventloop_weight", ip_get_eventloop_weight, 0); 11030 rb_define_method(ip, "set_max_block_time", set_max_block_time, 1); 11031 rb_define_method(ip, "restart", ip_restart, 0); 11032 11033 /* --------------------------------------------------------------- */ 11034 11035 eventloop_thread = Qnil; 11036 eventloop_interp = (Tcl_Interp*)NULL; 11037 11038 #ifndef DEFAULT_EVENTLOOP_DEPTH 11039 #define DEFAULT_EVENTLOOP_DEPTH 7 11040 #endif 11041 eventloop_stack = rb_ary_new2(DEFAULT_EVENTLOOP_DEPTH); 11042 RbTk_OBJ_UNTRUST(eventloop_stack); 11043 11044 watchdog_thread = Qnil; 11045 11046 rbtk_pending_exception = Qnil; 11047 11048 /* --------------------------------------------------------------- */ 11049 11050 #ifdef HAVE_NATIVETHREAD 11051 /* if ruby->nativethread-supprt and tcltklib->doen't, 11052 the following will cause link-error. */ 11053 ruby_native_thread_p(); 11054 #endif 11055 11056 /* --------------------------------------------------------------- */ 11057 11058 rb_set_end_proc(lib_mark_at_exit, 0); 11059 11060 /* --------------------------------------------------------------- */ 11061 11062 ret = ruby_open_tcl_dll(rb_argv0 ? RSTRING_PTR(rb_argv0) : 0); 11063 switch(ret) { 11064 case TCLTK_STUBS_OK: 11065 break; 11066 case NO_TCL_DLL: 11067 rb_raise(rb_eLoadError, "tcltklib: fail to open tcl_dll"); 11068 case NO_FindExecutable: 11069 rb_raise(rb_eLoadError, "tcltklib: can't find Tcl_FindExecutable"); 11070 default: 11071 rb_raise(rb_eLoadError, "tcltklib: unknown error(%d) on ruby_open_tcl_dll", ret); 11072 } 11073 11074 /* --------------------------------------------------------------- */ 11075 11076 #if defined CREATE_RUBYTK_KIT || defined CREATE_RUBYKIT 11077 setup_rubytkkit(); 11078 #endif 11079 11080 /* --------------------------------------------------------------- */ 11081 11082 /* Tcl stub check */ 11083 tcl_stubs_check(); 11084 11085 Tcl_ObjType_ByteArray = Tcl_GetObjType(Tcl_ObjTypeName_ByteArray); 11086 Tcl_ObjType_String = Tcl_GetObjType(Tcl_ObjTypeName_String); 11087 11088 /* --------------------------------------------------------------- */ 11089 11090 (void)call_original_exit; 11091 } 11092 11093 /* eof */ 11094
1.7.6.1