| | @@ -119,21 +119,27 @@ |
| 119 | 119 | # define TCL_FINDEXECUTABLE_NAME "_Tcl_FindExecutable" |
| 120 | 120 | # endif |
| 121 | 121 | # ifndef TCL_CREATEINTERP_NAME |
| 122 | 122 | # define TCL_CREATEINTERP_NAME "_Tcl_CreateInterp" |
| 123 | 123 | # endif |
| 124 | +# ifndef TCL_DELETEINTERP_NAME |
| 125 | +# define TCL_DELETEINTERP_NAME "_Tcl_DeleteInterp" |
| 126 | +# endif |
| 124 | 127 | #endif /* defined(USE_TCL_STUBS) */ |
| 125 | 128 | |
| 126 | 129 | /* |
| 127 | 130 | ** The function types for Tcl_FindExecutable and Tcl_CreateInterp are needed |
| 128 | 131 | ** when the Tcl library is being loaded dynamically by a stubs-enabled |
| 129 | 132 | ** application (i.e. the inverse of using a stubs-enabled package). These are |
| 130 | 133 | ** the only Tcl API functions that MUST be called prior to being able to call |
| 131 | | -** Tcl_InitStubs (i.e. because it requires a Tcl interpreter). |
| 134 | +** Tcl_InitStubs (i.e. because it requires a Tcl interpreter). For complete |
| 135 | +** cleanup if the Tcl stubs initialization fails somehow, the Tcl_DeleteInterp |
| 136 | +** function type is also required. |
| 132 | 137 | */ |
| 133 | 138 | typedef void (tcl_FindExecutableProc) (const char * argv0); |
| 134 | 139 | typedef Tcl_Interp *(tcl_CreateInterpProc) (void); |
| 140 | +typedef void (tcl_DeleteInterpProc) (Tcl_Interp *interp); |
| 135 | 141 | |
| 136 | 142 | /* |
| 137 | 143 | ** The function types for the "hook" functions to be called before and after a |
| 138 | 144 | ** TH1 command makes a call to evaluate a Tcl script. If the "pre" function |
| 139 | 145 | ** returns anything but TH_OK, then evaluation of the Tcl script is skipped and |
| | @@ -189,10 +195,11 @@ |
| 189 | 195 | int argc; /* Number of original arguments. */ |
| 190 | 196 | char **argv; /* Full copy of the original arguments. */ |
| 191 | 197 | void *library; /* The Tcl library module handle. */ |
| 192 | 198 | tcl_FindExecutableProc *xFindExecutable; /* Tcl_FindExecutable() pointer. */ |
| 193 | 199 | tcl_CreateInterpProc *xCreateInterp; /* Tcl_CreateInterp() pointer. */ |
| 200 | + tcl_DeleteInterpProc *xDeleteInterp; /* Tcl_DeleteInterp() pointer. */ |
| 194 | 201 | Tcl_Interp *interp; /* The on-demand created Tcl interpreter. */ |
| 195 | 202 | char *setup; /* The optional Tcl setup script. */ |
| 196 | 203 | tcl_NotifyProc *xPreEval; /* Optional, called before Tcl_Eval*(). */ |
| 197 | 204 | void *pPreContext; /* Optional, provided to xPreEval(). */ |
| 198 | 205 | tcl_NotifyProc *xPostEval; /* Optional, called after Tcl_Eval*(). */ |
| | @@ -526,11 +533,12 @@ |
| 526 | 533 | */ |
| 527 | 534 | static int loadTcl( |
| 528 | 535 | Th_Interp *interp, |
| 529 | 536 | void **pLibrary, |
| 530 | 537 | tcl_FindExecutableProc **pxFindExecutable, |
| 531 | | - tcl_CreateInterpProc **pxCreateInterp |
| 538 | + tcl_CreateInterpProc **pxCreateInterp, |
| 539 | + tcl_DeleteInterpProc **pxDeleteInterp |
| 532 | 540 | ){ |
| 533 | 541 | #if defined(USE_TCL_STUBS) |
| 534 | 542 | char fileName[] = TCL_LIBRARY_NAME; |
| 535 | 543 | #endif |
| 536 | 544 | if( !pLibrary || !pxFindExecutable || !pxCreateInterp ){ |
| | @@ -542,10 +550,11 @@ |
| 542 | 550 | do { |
| 543 | 551 | void *library = dlopen(fileName, RTLD_NOW | RTLD_GLOBAL); |
| 544 | 552 | if( library ){ |
| 545 | 553 | tcl_FindExecutableProc *xFindExecutable; |
| 546 | 554 | tcl_CreateInterpProc *xCreateInterp; |
| 555 | + tcl_DeleteInterpProc *xDeleteInterp; |
| 547 | 556 | const char *procName = TCL_FINDEXECUTABLE_NAME; |
| 548 | 557 | xFindExecutable = (tcl_FindExecutableProc *)dlsym(library, procName + 1); |
| 549 | 558 | if( !xFindExecutable ){ |
| 550 | 559 | xFindExecutable = (tcl_FindExecutableProc *)dlsym(library, procName); |
| 551 | 560 | } |
| | @@ -563,14 +572,26 @@ |
| 563 | 572 | if( !xCreateInterp ){ |
| 564 | 573 | Th_ErrorMessage(interp, |
| 565 | 574 | "could not locate Tcl_CreateInterp", (const char *)"", 0); |
| 566 | 575 | dlclose(library); |
| 567 | 576 | return TH_ERROR; |
| 577 | + } |
| 578 | + procName = TCL_DELETEINTERP_NAME; |
| 579 | + xDeleteInterp = (tcl_DeleteInterpProc *)dlsym(library, procName + 1); |
| 580 | + if( !xDeleteInterp ){ |
| 581 | + xDeleteInterp = (tcl_DeleteInterpProc *)dlsym(library, procName); |
| 582 | + } |
| 583 | + if( !xDeleteInterp ){ |
| 584 | + Th_ErrorMessage(interp, |
| 585 | + "could not locate Tcl_DeleteInterp", (const char *)"", 0); |
| 586 | + dlclose(library); |
| 587 | + return TH_ERROR; |
| 568 | 588 | } |
| 569 | 589 | *pLibrary = library; |
| 570 | 590 | *pxFindExecutable = xFindExecutable; |
| 571 | 591 | *pxCreateInterp = xCreateInterp; |
| 592 | + *pxDeleteInterp = xDeleteInterp; |
| 572 | 593 | return TH_OK; |
| 573 | 594 | } |
| 574 | 595 | } while( --fileName[TCL_MINOR_OFFSET]>'3' ); /* Tcl 8.4+ */ |
| 575 | 596 | Th_ErrorMessage(interp, |
| 576 | 597 | "could not load Tcl shared library \"" TCL_LIBRARY_NAME "\"", |
| | @@ -578,10 +599,11 @@ |
| 578 | 599 | return TH_ERROR; |
| 579 | 600 | #else |
| 580 | 601 | *pLibrary = 0; |
| 581 | 602 | *pxFindExecutable = Tcl_FindExecutable; |
| 582 | 603 | *pxCreateInterp = Tcl_CreateInterp; |
| 604 | + *pxDeleteInterp = Tcl_DeleteInterp; |
| 583 | 605 | return TH_OK; |
| 584 | 606 | #endif |
| 585 | 607 | } |
| 586 | 608 | |
| 587 | 609 | /* |
| | @@ -663,28 +685,38 @@ |
| 663 | 685 | } |
| 664 | 686 | if ( tclContext->interp ){ |
| 665 | 687 | return TH_OK; |
| 666 | 688 | } |
| 667 | 689 | if( loadTcl(interp, &tclContext->library, &tclContext->xFindExecutable, |
| 668 | | - &tclContext->xCreateInterp)!=TH_OK ){ |
| 690 | + &tclContext->xCreateInterp, &tclContext->xDeleteInterp)!=TH_OK ){ |
| 669 | 691 | return TH_ERROR; |
| 670 | 692 | } |
| 671 | 693 | argc = tclContext->argc; |
| 672 | 694 | argv = tclContext->argv; |
| 673 | 695 | if( argc>0 && argv ){ |
| 674 | 696 | argv0 = argv[0]; |
| 675 | 697 | } |
| 676 | 698 | tclContext->xFindExecutable(argv0); |
| 677 | 699 | tclInterp = tclContext->xCreateInterp(); |
| 678 | | - if( !tclInterp || |
| 679 | | -#if defined(USE_TCL_STUBS) |
| 680 | | - !Tcl_InitStubs(tclInterp, "8.4", 0) || |
| 681 | | -#endif |
| 682 | | - Tcl_InterpDeleted(tclInterp) ){ |
| 700 | + if( !tclInterp ){ |
| 683 | 701 | Th_ErrorMessage(interp, |
| 684 | 702 | "could not create Tcl interpreter", (const char *)"", 0); |
| 685 | 703 | return TH_ERROR; |
| 704 | + } |
| 705 | +#if defined(USE_TCL_STUBS) |
| 706 | + if( !Tcl_InitStubs(tclInterp, "8.4", 0) ){ |
| 707 | + Th_ErrorMessage(interp, |
| 708 | + "could not initialize Tcl stubs", (const char *)"", 0); |
| 709 | + tclContext->xDeleteInterp(tclInterp); |
| 710 | + return TH_ERROR; |
| 711 | + } |
| 712 | +#endif |
| 713 | + if( Tcl_InterpDeleted(tclInterp) ){ |
| 714 | + Th_ErrorMessage(interp, |
| 715 | + "Tcl interpreter appears to be deleted", (const char *)"", 0); |
| 716 | + tclContext->xDeleteInterp(tclInterp); /* TODO: Redundant? */ |
| 717 | + return TH_ERROR; |
| 686 | 718 | } |
| 687 | 719 | tclContext->interp = tclInterp; |
| 688 | 720 | if( Tcl_Init(tclInterp)!=TCL_OK ){ |
| 689 | 721 | Th_ErrorMessage(interp, |
| 690 | 722 | "Tcl initialization error:", Tcl_GetStringResult(tclInterp), -1); |
| 691 | 723 | |