| | @@ -39,10 +39,25 @@ |
| 39 | 39 | for(i=1; i<argc; i++){ \ |
| 40 | 40 | Tcl_DecrRefCount(objv[i-1]); \ |
| 41 | 41 | } \ |
| 42 | 42 | ckfree((char *)objv); |
| 43 | 43 | |
| 44 | +/* |
| 45 | +** Fetch the Tcl interpreter from the specified void pointer, cast to a Tcl |
| 46 | +** context. |
| 47 | + */ |
| 48 | +#define GET_CTX_TCL_INTERP(ctx) \ |
| 49 | + ((struct TclContext *)(ctx))->interp |
| 50 | + |
| 51 | +/* |
| 52 | +** Creates and initializes a Tcl interpreter for use with the specified TH1 |
| 53 | +** interpreter. Stores the created Tcl interpreter in the Tcl context supplied |
| 54 | +** by the caller. This must be declared here because quite a few functions in |
| 55 | +** this file need to use it before it can be defined. |
| 56 | + */ |
| 57 | +static int createTclInterp(Th_Interp *interp, void *pContext); |
| 58 | + |
| 44 | 59 | /* |
| 45 | 60 | ** Returns the Tcl interpreter result as a string with the associated length. |
| 46 | 61 | ** If the Tcl interpreter or the Tcl result are NULL, the length will be 0. |
| 47 | 62 | ** If the length pointer is NULL, the length will not be stored. |
| 48 | 63 | */ |
| | @@ -61,10 +76,20 @@ |
| 61 | 76 | return 0; |
| 62 | 77 | } |
| 63 | 78 | return Tcl_GetStringFromObj(resultPtr, pN); |
| 64 | 79 | } |
| 65 | 80 | |
| 81 | +/* |
| 82 | +** Tcl context information used by TH1. This structure definition has been |
| 83 | +** copied from and should be kept in sync with the one in "main.c". |
| 84 | +*/ |
| 85 | +struct TclContext { |
| 86 | + int argc; |
| 87 | + char **argv; |
| 88 | + Tcl_Interp *interp; |
| 89 | +}; |
| 90 | + |
| 66 | 91 | /* |
| 67 | 92 | ** Syntax: |
| 68 | 93 | ** |
| 69 | 94 | ** tclEval arg ?arg ...? |
| 70 | 95 | */ |
| | @@ -79,14 +104,17 @@ |
| 79 | 104 | Tcl_Obj *objPtr; |
| 80 | 105 | int rc; |
| 81 | 106 | int nResult; |
| 82 | 107 | const char *zResult; |
| 83 | 108 | |
| 109 | + if ( createTclInterp(interp, ctx)!=TH_OK ){ |
| 110 | + return TH_ERROR; |
| 111 | + } |
| 84 | 112 | if( argc<2 ){ |
| 85 | 113 | return Th_WrongNumArgs(interp, "tclEval arg ?arg ...?"); |
| 86 | 114 | } |
| 87 | | - tclInterp = (Tcl_Interp *)ctx; |
| 115 | + tclInterp = GET_CTX_TCL_INTERP(ctx); |
| 88 | 116 | if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){ |
| 89 | 117 | Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0); |
| 90 | 118 | return TH_ERROR; |
| 91 | 119 | } |
| 92 | 120 | Tcl_Preserve((ClientData)tclInterp); |
| | @@ -127,14 +155,17 @@ |
| 127 | 155 | Tcl_Obj *resultObjPtr; |
| 128 | 156 | int rc; |
| 129 | 157 | int nResult; |
| 130 | 158 | const char *zResult; |
| 131 | 159 | |
| 160 | + if ( createTclInterp(interp, ctx)!=TH_OK ){ |
| 161 | + return TH_ERROR; |
| 162 | + } |
| 132 | 163 | if( argc<2 ){ |
| 133 | 164 | return Th_WrongNumArgs(interp, "tclExpr arg ?arg ...?"); |
| 134 | 165 | } |
| 135 | | - tclInterp = (Tcl_Interp *)ctx; |
| 166 | + tclInterp = GET_CTX_TCL_INTERP(ctx); |
| 136 | 167 | if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){ |
| 137 | 168 | Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0); |
| 138 | 169 | return TH_ERROR; |
| 139 | 170 | } |
| 140 | 171 | Tcl_Preserve((ClientData)tclInterp); |
| | @@ -186,14 +217,17 @@ |
| 186 | 217 | #ifndef USE_TCL_EVALOBJV |
| 187 | 218 | Tcl_Obj *objPtr; |
| 188 | 219 | #endif |
| 189 | 220 | USE_ARGV_TO_OBJV(); |
| 190 | 221 | |
| 222 | + if ( createTclInterp(interp, ctx)!=TH_OK ){ |
| 223 | + return TH_ERROR; |
| 224 | + } |
| 191 | 225 | if( argc<2 ){ |
| 192 | 226 | return Th_WrongNumArgs(interp, "tclInvoke command ?arg ...?"); |
| 193 | 227 | } |
| 194 | | - tclInterp = (Tcl_Interp *)ctx; |
| 228 | + tclInterp = GET_CTX_TCL_INTERP(ctx); |
| 195 | 229 | if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){ |
| 196 | 230 | Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0); |
| 197 | 231 | return TH_ERROR; |
| 198 | 232 | } |
| 199 | 233 | Tcl_Preserve((ClientData)tclInterp); |
| | @@ -324,36 +358,65 @@ |
| 324 | 358 | Th_RenameCommand(th1Interp, aCommand[i].zName, -1, NULL, 0); |
| 325 | 359 | } |
| 326 | 360 | } |
| 327 | 361 | |
| 328 | 362 | /* |
| 329 | | -** Register the Tcl language commands with interpreter interp. |
| 330 | | -** Usually this is called soon after interpreter creation. |
| 331 | | -*/ |
| 332 | | -int th_register_tcl(Th_Interp *interp){ |
| 333 | | - int i; |
| 334 | | - Tcl_Interp *tclInterp = Tcl_CreateInterp(); |
| 363 | +** Creates and initializes a Tcl interpreter for use with the specified TH1 |
| 364 | +** interpreter. Stores the created Tcl interpreter in the Tcl context supplied |
| 365 | +** by the caller. |
| 366 | + */ |
| 367 | +static int createTclInterp( |
| 368 | + Th_Interp *interp, |
| 369 | + void *pContext |
| 370 | +){ |
| 371 | + struct TclContext *tclContext = (struct TclContext *)pContext; |
| 372 | + Tcl_Interp *tclInterp; |
| 335 | 373 | |
| 374 | + if ( !tclContext ){ |
| 375 | + Th_ErrorMessage(interp, |
| 376 | + "Invalid Tcl context", (const char *)"", 0); |
| 377 | + return TH_ERROR; |
| 378 | + } |
| 379 | + if ( tclContext->interp ){ |
| 380 | + return TH_OK; |
| 381 | + } |
| 382 | + if ( tclContext->argc>0 && tclContext->argv ) { |
| 383 | + Tcl_FindExecutable(tclContext->argv[0]); |
| 384 | + } |
| 385 | + tclInterp = tclContext->interp = Tcl_CreateInterp(); |
| 336 | 386 | if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){ |
| 337 | 387 | Th_ErrorMessage(interp, |
| 338 | 388 | "Could not create Tcl interpreter", (const char *)"", 0); |
| 339 | 389 | return TH_ERROR; |
| 340 | 390 | } |
| 341 | 391 | if( Tcl_Init(tclInterp)!=TCL_OK ){ |
| 342 | 392 | Th_ErrorMessage(interp, |
| 343 | 393 | "Tcl initialization error:", Tcl_GetStringResult(tclInterp), -1); |
| 344 | 394 | Tcl_DeleteInterp(tclInterp); |
| 395 | + tclContext->interp = tclInterp = 0; |
| 345 | 396 | return TH_ERROR; |
| 346 | 397 | } |
| 347 | 398 | /* Add the TH1 integration commands to Tcl. */ |
| 348 | 399 | Tcl_CallWhenDeleted(tclInterp, Th1DeleteProc, interp); |
| 349 | 400 | Tcl_CreateObjCommand(tclInterp, "th1Eval", Th1EvalObjCmd, interp, NULL); |
| 350 | 401 | Tcl_CreateObjCommand(tclInterp, "th1Expr", Th1ExprObjCmd, interp, NULL); |
| 402 | + return TH_OK; |
| 403 | +} |
| 404 | + |
| 405 | +/* |
| 406 | +** Register the Tcl language commands with interpreter interp. |
| 407 | +** Usually this is called soon after interpreter creation. |
| 408 | +*/ |
| 409 | +int th_register_tcl( |
| 410 | + Th_Interp *interp, |
| 411 | + void *pContext |
| 412 | +){ |
| 413 | + int i; |
| 351 | 414 | /* Add the Tcl integration commands to TH1. */ |
| 352 | 415 | for(i=0; i<(sizeof(aCommand)/sizeof(aCommand[0])); i++){ |
| 353 | 416 | void *ctx = aCommand[i].pContext; |
| 354 | 417 | /* Use Tcl interpreter for context? */ |
| 355 | | - if( !ctx ) ctx = tclInterp; |
| 418 | + if( !ctx ) ctx = pContext; |
| 356 | 419 | Th_CreateCommand(interp, aCommand[i].zName, aCommand[i].xProc, ctx, 0); |
| 357 | 420 | } |
| 358 | 421 | return TH_OK; |
| 359 | 422 | } |
| 360 | 423 | |