| | @@ -35,10 +35,16 @@ |
| 35 | 35 | ** Tcl_EvalObjv instead of invoking the objProc directly. |
| 36 | 36 | */ |
| 37 | 37 | #define USE_TCL_EVALOBJV 1 |
| 38 | 38 | #endif |
| 39 | 39 | |
| 40 | +#ifdef _WIN32 |
| 41 | +# include <windows.h> |
| 42 | +#else |
| 43 | +# include <dlfcn.h> |
| 44 | +#endif |
| 45 | + |
| 40 | 46 | /* |
| 41 | 47 | ** These macros are designed to reduce the redundant code required to marshal |
| 42 | 48 | ** arguments from TH1 to Tcl. |
| 43 | 49 | */ |
| 44 | 50 | #define USE_ARGV_TO_OBJV() \ |
| | @@ -445,10 +451,28 @@ |
| 445 | 451 | ){ |
| 446 | 452 | struct TclContext *tclContext = (struct TclContext *)pContext; |
| 447 | 453 | int argc; |
| 448 | 454 | char **argv; |
| 449 | 455 | char *argv0 = 0; |
| 456 | +#ifdef USE_TCL_STUBS |
| 457 | +#ifdef _WIN32 |
| 458 | + WCHAR lib[] = L"tcl87.dll"; |
| 459 | +#define minver lib[4] |
| 460 | +#define dlopen(a,b) (void *)LoadLibraryW(a); |
| 461 | +#define dlsym(a,b) GetProcAddress((HANDLE)(a),b); |
| 462 | +#else |
| 463 | +#ifdef __CYGWIN__ |
| 464 | + char lib[] = "libtcl8.7.dll"; |
| 465 | +#else |
| 466 | + char lib[] = "libtcl8.7.so"; |
| 467 | +#endif |
| 468 | +#define minver lib[8] |
| 469 | +#endif |
| 470 | + void *handle = NULL; |
| 471 | + void (*findExecutable)(const char *) = 0; |
| 472 | + Tcl_Interp *(*createInterp)() = 0; |
| 473 | +#endif /* USE_TCL_STUBS */ |
| 450 | 474 | Tcl_Interp *tclInterp; |
| 451 | 475 | |
| 452 | 476 | if ( !tclContext ){ |
| 453 | 477 | Th_ErrorMessage(interp, |
| 454 | 478 | "Invalid Tcl context", (const char *)"", 0); |
| | @@ -460,17 +484,44 @@ |
| 460 | 484 | argc = tclContext->argc; |
| 461 | 485 | argv = tclContext->argv; |
| 462 | 486 | if( argc>0 && argv ){ |
| 463 | 487 | argv0 = argv[0]; |
| 464 | 488 | } |
| 489 | +#ifdef USE_TCL_STUBS |
| 490 | + while( --minver>'3' ){ |
| 491 | + handle = dlopen(lib, RTLD_NOW | RTLD_LOCAL); |
| 492 | + if( handle ) { |
| 493 | + const char *sym = "_Tcl_FindExecutable"; |
| 494 | + findExecutable = (void (*)(const char *)) dlsym(handle, sym+1); |
| 495 | + if (!findExecutable) |
| 496 | + findExecutable = (void (*)(const char *)) dlsym(handle, sym); |
| 497 | + sym = "_Tcl_CreateInterp"; |
| 498 | + createInterp = (Tcl_Interp * (*)(void)) dlsym(handle, sym+1); |
| 499 | + if (!createInterp) |
| 500 | + createInterp = (Tcl_Interp * (*)(void)) dlsym(handle, sym); |
| 501 | + break; |
| 502 | + } |
| 503 | + } |
| 504 | + if( !handle ){ |
| 505 | + Th_ErrorMessage(interp, |
| 506 | + "Could not create Tcl interpreter", (const char *)"", 0); |
| 507 | + return TH_ERROR; |
| 508 | + } |
| 509 | +# undef Tcl_FindExecutable |
| 510 | +# define Tcl_FindExecutable findExecutable |
| 511 | +# undef Tcl_CreateInterp |
| 512 | +# define Tcl_CreateInterp createInterp |
| 513 | +#endif /* USE_TCL_STUBS */ |
| 465 | 514 | Tcl_FindExecutable(argv0); |
| 466 | | - tclInterp = tclContext->interp = Tcl_CreateInterp(); |
| 467 | | - if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){ |
| 515 | + tclInterp = Tcl_CreateInterp(); |
| 516 | + if( !tclInterp || !Tcl_InitStubs(tclInterp, "8.4", 0) |
| 517 | + || Tcl_InterpDeleted(tclInterp) ){ |
| 468 | 518 | Th_ErrorMessage(interp, |
| 469 | 519 | "Could not create Tcl interpreter", (const char *)"", 0); |
| 470 | 520 | return TH_ERROR; |
| 471 | 521 | } |
| 522 | + tclContext->interp = tclInterp; |
| 472 | 523 | if( Tcl_Init(tclInterp)!=TCL_OK ){ |
| 473 | 524 | Th_ErrorMessage(interp, |
| 474 | 525 | "Tcl initialization error:", Tcl_GetStringResult(tclInterp), -1); |
| 475 | 526 | Tcl_DeleteInterp(tclInterp); |
| 476 | 527 | tclContext->interp = tclInterp = 0; |
| 477 | 528 | |