00001
00002
00003
00004
00005
00006
00007 #include "ruby.h"
00008 #include "stubs.h"
00009
00010 #if !defined(RSTRING_PTR)
00011 #define RSTRING_PTR(s) (RSTRING(s)->ptr)
00012 #define RSTRING_LEN(s) (RSTRING(s)->len)
00013 #endif
00014
00015 #include <tcl.h>
00016 #include <tk.h>
00017
00018
00019
00020 #ifdef __MACOS__
00021 # include <tkMac.h>
00022 # include <Quickdraw.h>
00023
00024 static int call_macinit = 0;
00025
00026 static void
00027 _macinit()
00028 {
00029 if (!call_macinit) {
00030 tcl_macQdPtr = &qd;
00031 Tcl_MacSetEventProc(TkMacConvertEvent);
00032 call_macinit = 1;
00033 }
00034 }
00035 #endif
00036
00037
00038
00039 static int nativethread_checked = 0;
00040
00041 static void
00042 _nativethread_consistency_check(ip)
00043 Tcl_Interp *ip;
00044 {
00045 if (nativethread_checked || ip == (Tcl_Interp *)NULL) {
00046 return;
00047 }
00048
00049
00050
00051 if (Tcl_GetVar2(ip, "tcl_platform", "threaded", TCL_GLOBAL_ONLY) != (char*)NULL) {
00052 #ifdef HAVE_NATIVETHREAD
00053
00054 #else
00055 rb_warn("Inconsistency. Loaded Tcl/Tk libraries are enabled nativethread-support. But `tcltklib' is not. The inconsistency causes SEGV or other troubles frequently.");
00056 #endif
00057 } else {
00058 #ifdef HAVE_NATIVETHREAD
00059 rb_warning("Inconsistency.`tcltklib' is enabled nativethread-support. But loaded Tcl/Tk libraries are not. (Probably, the inconsistency doesn't cause any troubles.)");
00060 #else
00061
00062 #endif
00063 }
00064
00065 Tcl_ResetResult(ip);
00066
00067 nativethread_checked = 1;
00068 }
00069
00070
00071
00072 #if defined USE_TCL_STUBS && defined USE_TK_STUBS
00073
00074 #if defined _WIN32 || defined __CYGWIN__
00075 # ifdef HAVE_RUBY_RUBY_H
00076 # include "ruby/util.h"
00077 # else
00078 # include "util.h"
00079 # endif
00080 # include <windows.h>
00081 typedef HINSTANCE DL_HANDLE;
00082 # define DL_OPEN LoadLibrary
00083 # define DL_SYM GetProcAddress
00084 # define TCL_INDEX 4
00085 # define TK_INDEX 3
00086 # define TCL_NAME "tcl89%s"
00087 # define TK_NAME "tk89%s"
00088 # undef DLEXT
00089 # define DLEXT ".dll"
00090 #elif defined HAVE_DLOPEN
00091 # include <dlfcn.h>
00092 typedef void *DL_HANDLE;
00093 # define DL_OPEN(file) dlopen(file, RTLD_LAZY|RTLD_GLOBAL)
00094 # define DL_SYM dlsym
00095 # define TCL_INDEX 8
00096 # define TK_INDEX 7
00097 # define TCL_NAME "libtcl8.9%s"
00098 # define TK_NAME "libtk8.9%s"
00099 # if defined(__APPLE__) && defined(__MACH__)
00100 # undef DLEXT
00101 # define DLEXT ".dylib"
00102 # endif
00103 #endif
00104
00105 static DL_HANDLE tcl_dll = (DL_HANDLE)0;
00106 static DL_HANDLE tk_dll = (DL_HANDLE)0;
00107
00108 int
00109 #ifdef HAVE_PROTOTYPES
00110 ruby_open_tcl_dll(char *appname)
00111 #else
00112 ruby_open_tcl_dll(appname)
00113 char *appname;
00114 #endif
00115 {
00116 void (*p_Tcl_FindExecutable)(const char *);
00117 int n;
00118 char *ruby_tcl_dll = 0;
00119 char tcl_name[20];
00120
00121 if (tcl_dll) return TCLTK_STUBS_OK;
00122
00123 ruby_tcl_dll = getenv("RUBY_TCL_DLL");
00124 #if defined _WIN32
00125 if (ruby_tcl_dll) ruby_tcl_dll = ruby_strdup(ruby_tcl_dll);
00126 #endif
00127 if (ruby_tcl_dll) {
00128 tcl_dll = (DL_HANDLE)DL_OPEN(ruby_tcl_dll);
00129 } else {
00130 snprintf(tcl_name, sizeof tcl_name, TCL_NAME, DLEXT);
00131
00132 for (n = '9'; n > '0'; n--) {
00133 tcl_name[TCL_INDEX] = n;
00134 tcl_dll = (DL_HANDLE)DL_OPEN(tcl_name);
00135 if (tcl_dll)
00136 break;
00137 }
00138 }
00139
00140 #if defined _WIN32
00141 if (ruby_tcl_dll) ruby_xfree(ruby_tcl_dll);
00142 #endif
00143
00144 if (!tcl_dll)
00145 return NO_TCL_DLL;
00146
00147 p_Tcl_FindExecutable = (void (*)(const char *))DL_SYM(tcl_dll, "Tcl_FindExecutable");
00148 if (!p_Tcl_FindExecutable)
00149 return NO_FindExecutable;
00150
00151 if (appname) {
00152 p_Tcl_FindExecutable(appname);
00153 } else {
00154 p_Tcl_FindExecutable("ruby");
00155 }
00156
00157 return TCLTK_STUBS_OK;
00158 }
00159
00160 int
00161 ruby_open_tk_dll()
00162 {
00163 int n;
00164 char *ruby_tk_dll = 0;
00165 char tk_name[20];
00166
00167 if (!tcl_dll) {
00168
00169 int ret = ruby_open_tcl_dll(rb_argv0 ? RSTRING_PTR(rb_argv0) : 0);
00170 if (ret != TCLTK_STUBS_OK) return ret;
00171 }
00172
00173 if (tk_dll) return TCLTK_STUBS_OK;
00174
00175 ruby_tk_dll = getenv("RUBY_TK_DLL");
00176 if (ruby_tk_dll) {
00177 tk_dll = (DL_HANDLE)DL_OPEN(ruby_tk_dll);
00178 } else {
00179 snprintf(tk_name, sizeof tk_name, TK_NAME, DLEXT);
00180
00181 for (n = '9'; n > '0'; n--) {
00182 tk_name[TK_INDEX] = n;
00183 tk_dll = (DL_HANDLE)DL_OPEN(tk_name);
00184 if (tk_dll)
00185 break;
00186 }
00187 }
00188
00189 if (!tk_dll)
00190 return NO_TK_DLL;
00191
00192 return TCLTK_STUBS_OK;
00193 }
00194
00195 int
00196 #ifdef HAVE_PROTOTYPES
00197 ruby_open_tcltk_dll(char *appname)
00198 #else
00199 ruby_open_tcltk_dll(appname)
00200 char *appname;
00201 #endif
00202 {
00203 return( ruby_open_tcl_dll(appname) || ruby_open_tk_dll() );
00204 }
00205
00206 int
00207 tcl_stubs_init_p()
00208 {
00209 return(tclStubsPtr != (TclStubs*)NULL);
00210 }
00211
00212 int
00213 tk_stubs_init_p()
00214 {
00215 return(tkStubsPtr != (TkStubs*)NULL);
00216 }
00217
00218
00219 Tcl_Interp *
00220 #ifdef HAVE_PROTOTYPES
00221 ruby_tcl_create_ip_and_stubs_init(int *st)
00222 #else
00223 ruby_tcl_create_ip_and_stubs_init(st)
00224 int *st;
00225 #endif
00226 {
00227 Tcl_Interp *tcl_ip;
00228
00229 if (st) *st = 0;
00230
00231 if (tcl_stubs_init_p()) {
00232 tcl_ip = Tcl_CreateInterp();
00233
00234 if (!tcl_ip) {
00235 if (st) *st = FAIL_CreateInterp;
00236 return (Tcl_Interp*)NULL;
00237 }
00238
00239 _nativethread_consistency_check(tcl_ip);
00240
00241 return tcl_ip;
00242
00243 } else {
00244 Tcl_Interp *(*p_Tcl_CreateInterp)();
00245 Tcl_Interp *(*p_Tcl_DeleteInterp)();
00246
00247 if (!tcl_dll) {
00248
00249 int ret = ruby_open_tcl_dll(rb_argv0 ? RSTRING_PTR(rb_argv0) : 0);
00250
00251 if (ret != TCLTK_STUBS_OK) {
00252 if (st) *st = ret;
00253 return (Tcl_Interp*)NULL;
00254 }
00255 }
00256
00257 p_Tcl_CreateInterp
00258 = (Tcl_Interp *(*)())DL_SYM(tcl_dll, "Tcl_CreateInterp");
00259 if (!p_Tcl_CreateInterp) {
00260 if (st) *st = NO_CreateInterp;
00261 return (Tcl_Interp*)NULL;
00262 }
00263
00264 p_Tcl_DeleteInterp
00265 = (Tcl_Interp *(*)())DL_SYM(tcl_dll, "Tcl_DeleteInterp");
00266 if (!p_Tcl_DeleteInterp) {
00267 if (st) *st = NO_DeleteInterp;
00268 return (Tcl_Interp*)NULL;
00269 }
00270
00271 tcl_ip = (*p_Tcl_CreateInterp)();
00272 if (!tcl_ip) {
00273 if (st) *st = FAIL_CreateInterp;
00274 return (Tcl_Interp*)NULL;
00275 }
00276
00277 if (!Tcl_InitStubs(tcl_ip, "8.1", 0)) {
00278 if (st) *st = FAIL_Tcl_InitStubs;
00279 (*p_Tcl_DeleteInterp)(tcl_ip);
00280 return (Tcl_Interp*)NULL;
00281 }
00282
00283 _nativethread_consistency_check(tcl_ip);
00284
00285 return tcl_ip;
00286 }
00287 }
00288
00289 int
00290 ruby_tcl_stubs_init()
00291 {
00292 int st;
00293 Tcl_Interp *tcl_ip;
00294
00295 if (!tcl_stubs_init_p()) {
00296 tcl_ip = ruby_tcl_create_ip_and_stubs_init(&st);
00297
00298 if (!tcl_ip) return st;
00299
00300 Tcl_DeleteInterp(tcl_ip);
00301 }
00302
00303 return TCLTK_STUBS_OK;
00304 }
00305
00306 int
00307 #ifdef HAVE_PROTOTYPES
00308 ruby_tk_stubs_init(Tcl_Interp *tcl_ip)
00309 #else
00310 ruby_tk_stubs_init(tcl_ip)
00311 Tcl_Interp *tcl_ip;
00312 #endif
00313 {
00314 Tcl_ResetResult(tcl_ip);
00315
00316 if (tk_stubs_init_p()) {
00317 if (Tk_Init(tcl_ip) == TCL_ERROR) {
00318 return FAIL_Tk_Init;
00319 }
00320 } else {
00321 int (*p_Tk_Init)(Tcl_Interp *);
00322
00323 if (!tk_dll) {
00324 int ret = ruby_open_tk_dll();
00325 if (ret != TCLTK_STUBS_OK) return ret;
00326 }
00327
00328 p_Tk_Init = (int (*)(Tcl_Interp *))DL_SYM(tk_dll, "Tk_Init");
00329 if (!p_Tk_Init)
00330 return NO_Tk_Init;
00331
00332 #if defined USE_TK_STUBS && defined TK_FRAMEWORK && defined(__APPLE__) && defined(__MACH__)
00333
00334
00335
00336
00337
00338
00339
00340
00341 if (Tcl_Eval(tcl_ip,
00342 "if {[array get env TK_LIBRARY] == {}} { set env(TK_LIBRARY) [regsub -all -nocase {(t)cl} $tcl_library {\\1k}] }"
00343 ) != TCL_OK) {
00344 return FAIL_Tk_Init;
00345 }
00346 #endif
00347
00348 if ((*p_Tk_Init)(tcl_ip) == TCL_ERROR)
00349 return FAIL_Tk_Init;
00350
00351 if (!Tk_InitStubs(tcl_ip, (char *)"8.1", 0))
00352 return FAIL_Tk_InitStubs;
00353
00354 #ifdef __MACOS__
00355 _macinit();
00356 #endif
00357 }
00358
00359 return TCLTK_STUBS_OK;
00360 }
00361
00362 int
00363 #ifdef HAVE_PROTOTYPES
00364 ruby_tk_stubs_safeinit(Tcl_Interp *tcl_ip)
00365 #else
00366 ruby_tk_stubs_safeinit(tcl_ip)
00367 Tcl_Interp *tcl_ip;
00368 #endif
00369 {
00370 Tcl_ResetResult(tcl_ip);
00371
00372 if (tk_stubs_init_p()) {
00373 if (Tk_SafeInit(tcl_ip) == TCL_ERROR)
00374 return FAIL_Tk_Init;
00375 } else {
00376 int (*p_Tk_SafeInit)(Tcl_Interp *);
00377
00378 if (!tk_dll) {
00379 int ret = ruby_open_tk_dll();
00380 if (ret != TCLTK_STUBS_OK) return ret;
00381 }
00382
00383 p_Tk_SafeInit = (int (*)(Tcl_Interp *))DL_SYM(tk_dll, "Tk_SafeInit");
00384 if (!p_Tk_SafeInit)
00385 return NO_Tk_Init;
00386
00387 if ((*p_Tk_SafeInit)(tcl_ip) == TCL_ERROR)
00388 return FAIL_Tk_Init;
00389
00390 if (!Tk_InitStubs(tcl_ip, (char *)"8.1", 0))
00391 return FAIL_Tk_InitStubs;
00392
00393 #ifdef __MACOS__
00394 _macinit();
00395 #endif
00396 }
00397
00398 return TCLTK_STUBS_OK;
00399 }
00400
00401 int
00402 ruby_tcltk_stubs()
00403 {
00404 int st;
00405 Tcl_Interp *tcl_ip;
00406
00407
00408 st = ruby_open_tcltk_dll(rb_argv0 ? RSTRING_PTR(rb_argv0) : 0);
00409 switch(st) {
00410 case NO_FindExecutable:
00411 return -7;
00412 case NO_TCL_DLL:
00413 case NO_TK_DLL:
00414 return -1;
00415 }
00416
00417 tcl_ip = ruby_tcl_create_ip_and_stubs_init(&st);
00418 if (!tcl_ip) {
00419 switch(st) {
00420 case NO_CreateInterp:
00421 case NO_DeleteInterp:
00422 return -2;
00423 case FAIL_CreateInterp:
00424 return -3;
00425 case FAIL_Tcl_InitStubs:
00426 return -5;
00427 }
00428 }
00429
00430 st = ruby_tk_stubs_init(tcl_ip);
00431 switch(st) {
00432 case NO_Tk_Init:
00433 Tcl_DeleteInterp(tcl_ip);
00434 return -4;
00435 case FAIL_Tk_Init:
00436 case FAIL_Tk_InitStubs:
00437 Tcl_DeleteInterp(tcl_ip);
00438 return -6;
00439 }
00440
00441 Tcl_DeleteInterp(tcl_ip);
00442
00443 return 0;
00444 }
00445
00446
00447 #else
00448
00449
00450 static int open_tcl_dll = 0;
00451 static int call_tk_stubs_init = 0;
00452
00453 int
00454 #ifdef HAVE_PROTOTYPES
00455 ruby_open_tcl_dll(char *appname)
00456 #else
00457 ruby_open_tcl_dll(appname)
00458 char *appname;
00459 #endif
00460 {
00461 if (appname) {
00462 Tcl_FindExecutable(appname);
00463 } else {
00464 Tcl_FindExecutable("ruby");
00465 }
00466 open_tcl_dll = 1;
00467
00468 return TCLTK_STUBS_OK;
00469 }
00470
00471 int
00472 ruby_open_tk_dll()
00473 {
00474 if (!open_tcl_dll) {
00475
00476 ruby_open_tcl_dll(rb_argv0 ? RSTRING_PTR(rb_argv0) : 0);
00477 }
00478
00479 return TCLTK_STUBS_OK;
00480 }
00481
00482 int
00483 #ifdef HAVE_PROTOTYPES
00484 ruby_open_tcltk_dll(char *appname)
00485 #else
00486 ruby_open_tcltk_dll(appname)
00487 char *appname;
00488 #endif
00489 {
00490 return( ruby_open_tcl_dll(appname) || ruby_open_tk_dll() );
00491 }
00492
00493 int
00494 tcl_stubs_init_p()
00495 {
00496 return 1;
00497 }
00498
00499 int
00500 tk_stubs_init_p()
00501 {
00502 return call_tk_stubs_init;
00503 }
00504
00505 Tcl_Interp *
00506 #ifdef HAVE_PROTOTYPES
00507 ruby_tcl_create_ip_and_stubs_init(int *st)
00508 #else
00509 ruby_tcl_create_ip_and_stubs_init(st)
00510 int *st;
00511 #endif
00512 {
00513 Tcl_Interp *tcl_ip;
00514
00515 if (!open_tcl_dll) {
00516
00517 ruby_open_tcl_dll(rb_argv0 ? RSTRING_PTR(rb_argv0) : 0);
00518 }
00519
00520 if (st) *st = 0;
00521 tcl_ip = Tcl_CreateInterp();
00522 if (!tcl_ip) {
00523 if (st) *st = FAIL_CreateInterp;
00524 return (Tcl_Interp*)NULL;
00525 }
00526
00527 _nativethread_consistency_check(tcl_ip);
00528
00529 return tcl_ip;
00530 }
00531
00532 int
00533 ruby_tcl_stubs_init()
00534 {
00535 return TCLTK_STUBS_OK;
00536 }
00537
00538 int
00539 #ifdef HAVE_PROTOTYPES
00540 ruby_tk_stubs_init(Tcl_Interp *tcl_ip)
00541 #else
00542 ruby_tk_stubs_init(tcl_ip)
00543 Tcl_Interp *tcl_ip;
00544 #endif
00545 {
00546 if (Tk_Init(tcl_ip) == TCL_ERROR)
00547 return FAIL_Tk_Init;
00548
00549 if (!call_tk_stubs_init) {
00550 #ifdef __MACOS__
00551 _macinit();
00552 #endif
00553 call_tk_stubs_init = 1;
00554 }
00555
00556 return TCLTK_STUBS_OK;
00557 }
00558
00559 int
00560 #ifdef HAVE_PROTOTYPES
00561 ruby_tk_stubs_safeinit(Tcl_Interp *tcl_ip)
00562 #else
00563 ruby_tk_stubs_safeinit(tcl_ip)
00564 Tcl_Interp *tcl_ip;
00565 #endif
00566 {
00567 #if TCL_MAJOR_VERSION >= 8
00568 if (Tk_SafeInit(tcl_ip) == TCL_ERROR)
00569 return FAIL_Tk_Init;
00570
00571 if (!call_tk_stubs_init) {
00572 #ifdef __MACOS__
00573 _macinit();
00574 #endif
00575 call_tk_stubs_init = 1;
00576 }
00577
00578 return TCLTK_STUBS_OK;
00579
00580 #else
00581
00582 return FAIL_Tk_Init;
00583 #endif
00584 }
00585
00586 int
00587 ruby_tcltk_stubs()
00588 {
00589
00590 Tcl_FindExecutable(rb_argv0 ? RSTRING_PTR(rb_argv0) : 0);
00591 return 0;
00592 }
00593
00594 #endif
00595