| | @@ -80,17 +80,17 @@ |
| 80 | 80 | # endif |
| 81 | 81 | # ifndef TCL_MINOR_OFFSET |
| 82 | 82 | # define TCL_MINOR_OFFSET (4) |
| 83 | 83 | # endif |
| 84 | 84 | # ifndef dlopen |
| 85 | | -# define dlopen(a,b) (void *)LoadLibrary((a)); |
| 85 | +# define dlopen(a,b) (void *)LoadLibrary((a)) |
| 86 | 86 | # endif |
| 87 | 87 | # ifndef dlsym |
| 88 | | -# define dlsym(a,b) GetProcAddress((HANDLE)(a),(b)); |
| 88 | +# define dlsym(a,b) GetProcAddress((HANDLE)(a),(b)) |
| 89 | 89 | # endif |
| 90 | 90 | # ifndef dlclose |
| 91 | | -# define dlclose(a) FreeLibrary((HANDLE)(a)); |
| 91 | +# define dlclose(a) FreeLibrary((HANDLE)(a)) |
| 92 | 92 | # endif |
| 93 | 93 | # else |
| 94 | 94 | # include <dlfcn.h> |
| 95 | 95 | # if defined(__CYGWIN__) |
| 96 | 96 | # ifndef TCL_LIBRARY_NAME |
| | @@ -122,18 +122,36 @@ |
| 122 | 122 | # define TCL_CREATEINTERP_NAME "_Tcl_CreateInterp" |
| 123 | 123 | # endif |
| 124 | 124 | #endif /* defined(USE_TCL_STUBS) */ |
| 125 | 125 | |
| 126 | 126 | /* |
| 127 | | -** The function pointer types for Tcl_FindExecutable and Tcl_CreateInterp are |
| 128 | | -** needed when the Tcl library is being loaded dynamically by a stubs-enabled |
| 127 | +** The function types for Tcl_FindExecutable and Tcl_CreateInterp are needed |
| 128 | +** when the Tcl library is being loaded dynamically by a stubs-enabled |
| 129 | 129 | ** application (i.e. the inverse of using a stubs-enabled package). These are |
| 130 | 130 | ** the only Tcl API functions that MUST be called prior to being able to call |
| 131 | 131 | ** Tcl_InitStubs (i.e. because it requires a Tcl interpreter). |
| 132 | 132 | */ |
| 133 | 133 | typedef void (tcl_FindExecutableProc) (CONST char * argv0); |
| 134 | 134 | typedef Tcl_Interp *(tcl_CreateInterpProc) (void); |
| 135 | + |
| 136 | +/* |
| 137 | +** The function types for the "hook" functions to be called before and after a |
| 138 | +** TH1 command makes a call to evaluate a Tcl script. If the "pre" function |
| 139 | +** returns anything but TH_OK, then evaluation of the Tcl script is skipped and |
| 140 | +** that value is used as the return code. If the "post" function returns |
| 141 | +** anything other than its rc argument, that will become the new return code |
| 142 | +** for the command. |
| 143 | + */ |
| 144 | +typedef int (tcl_NotifyProc) ( |
| 145 | + void *pContext, /* The context for this notification. */ |
| 146 | + Th_Interp *interp, /* The TH1 interpreter being used. */ |
| 147 | + void *ctx, /* The original TH1 command context. */ |
| 148 | + int argc, /* Number of arguments for the TH1 command. */ |
| 149 | + const char **argv, /* Array of arguments for the TH1 command. */ |
| 150 | + int *argl, /* Array of lengths for the TH1 command arguments. */ |
| 151 | + int rc /* Recommended notification return value. */ |
| 152 | +); |
| 135 | 153 | |
| 136 | 154 | /* |
| 137 | 155 | ** Creates and initializes a Tcl interpreter for use with the specified TH1 |
| 138 | 156 | ** interpreter. Stores the created Tcl interpreter in the Tcl context supplied |
| 139 | 157 | ** by the caller. This must be declared here because quite a few functions in |
| | @@ -173,11 +191,47 @@ |
| 173 | 191 | void *library; /* The Tcl library module handle. */ |
| 174 | 192 | tcl_FindExecutableProc *xFindExecutable; /* Tcl_FindExecutable() pointer. */ |
| 175 | 193 | tcl_CreateInterpProc *xCreateInterp; /* Tcl_CreateInterp() pointer. */ |
| 176 | 194 | Tcl_Interp *interp; /* The on-demand created Tcl interpreter. */ |
| 177 | 195 | char *setup; /* The optional Tcl setup script. */ |
| 196 | + tcl_NotifyProc *xPreEval; /* Optional, called before Tcl_Eval*(). */ |
| 197 | + void *pPreContext; /* Optional, provided to xPreEval(). */ |
| 198 | + tcl_NotifyProc *xPostEval; /* Optional, called after Tcl_Eval*(). */ |
| 199 | + void *pPostContext; /* Optional, provided to xPostEval(). */ |
| 178 | 200 | }; |
| 201 | + |
| 202 | +/* |
| 203 | +** This function calls the configured xPreEval or xPostEval functions, if any. |
| 204 | +** May have arbitrary side-effects. This function returns the result of the |
| 205 | +** called notification function or the value of the rc argument if there is no |
| 206 | +** notification function configured. |
| 207 | +*/ |
| 208 | +static int notifyPreOrPostEval( |
| 209 | + int bIsPost, |
| 210 | + Th_Interp *interp, |
| 211 | + void *ctx, |
| 212 | + int argc, |
| 213 | + const char **argv, |
| 214 | + int *argl, |
| 215 | + int rc |
| 216 | +){ |
| 217 | + struct TclContext *tclContext = (struct TclContext *)ctx; |
| 218 | + tcl_NotifyProc *xNotifyProc; |
| 219 | + |
| 220 | + if ( !tclContext ){ |
| 221 | + Th_ErrorMessage(interp, |
| 222 | + "Invalid Tcl context", (const char *)"", 0); |
| 223 | + return TH_ERROR; |
| 224 | + } |
| 225 | + xNotifyProc = bIsPost ? tclContext->xPostEval : tclContext->xPreEval; |
| 226 | + if ( xNotifyProc ){ |
| 227 | + rc = xNotifyProc(bIsPost ? |
| 228 | + tclContext->pPostContext : tclContext->pPreContext, |
| 229 | + interp, ctx, argc, argv, argl, rc); |
| 230 | + } |
| 231 | + return rc; |
| 232 | +} |
| 179 | 233 | |
| 180 | 234 | /* |
| 181 | 235 | ** Syntax: |
| 182 | 236 | ** |
| 183 | 237 | ** tclEval arg ?arg ...? |
| | @@ -189,24 +243,28 @@ |
| 189 | 243 | const char **argv, |
| 190 | 244 | int *argl |
| 191 | 245 | ){ |
| 192 | 246 | Tcl_Interp *tclInterp; |
| 193 | 247 | Tcl_Obj *objPtr; |
| 194 | | - int rc; |
| 248 | + int rc = TH_OK; |
| 195 | 249 | int nResult; |
| 196 | 250 | const char *zResult; |
| 197 | 251 | |
| 198 | | - if ( createTclInterp(interp, ctx)!=TH_OK ){ |
| 252 | + if( createTclInterp(interp, ctx)!=TH_OK ){ |
| 199 | 253 | return TH_ERROR; |
| 200 | 254 | } |
| 201 | 255 | if( argc<2 ){ |
| 202 | 256 | return Th_WrongNumArgs(interp, "tclEval arg ?arg ...?"); |
| 203 | 257 | } |
| 204 | 258 | tclInterp = GET_CTX_TCL_INTERP(ctx); |
| 205 | 259 | if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){ |
| 206 | 260 | Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0); |
| 207 | 261 | return TH_ERROR; |
| 262 | + } |
| 263 | + rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, argl, rc); |
| 264 | + if( rc!=TH_OK ){ |
| 265 | + return rc; |
| 208 | 266 | } |
| 209 | 267 | Tcl_Preserve((ClientData)tclInterp); |
| 210 | 268 | if( argc==2 ){ |
| 211 | 269 | objPtr = Tcl_NewStringObj(argv[1], argl[1]); |
| 212 | 270 | Tcl_IncrRefCount(objPtr); |
| | @@ -222,10 +280,11 @@ |
| 222 | 280 | FREE_ARGV_TO_OBJV(); |
| 223 | 281 | } |
| 224 | 282 | zResult = getTclResult(tclInterp, &nResult); |
| 225 | 283 | Th_SetResult(interp, zResult, nResult); |
| 226 | 284 | Tcl_Release((ClientData)tclInterp); |
| 285 | + rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl, rc); |
| 227 | 286 | return rc; |
| 228 | 287 | } |
| 229 | 288 | |
| 230 | 289 | /* |
| 231 | 290 | ** Syntax: |
| | @@ -240,24 +299,28 @@ |
| 240 | 299 | int *argl |
| 241 | 300 | ){ |
| 242 | 301 | Tcl_Interp *tclInterp; |
| 243 | 302 | Tcl_Obj *objPtr; |
| 244 | 303 | Tcl_Obj *resultObjPtr; |
| 245 | | - int rc; |
| 304 | + int rc = TH_OK; |
| 246 | 305 | int nResult; |
| 247 | 306 | const char *zResult; |
| 248 | 307 | |
| 249 | | - if ( createTclInterp(interp, ctx)!=TH_OK ){ |
| 308 | + if( createTclInterp(interp, ctx)!=TH_OK ){ |
| 250 | 309 | return TH_ERROR; |
| 251 | 310 | } |
| 252 | 311 | if( argc<2 ){ |
| 253 | 312 | return Th_WrongNumArgs(interp, "tclExpr arg ?arg ...?"); |
| 254 | 313 | } |
| 255 | 314 | tclInterp = GET_CTX_TCL_INTERP(ctx); |
| 256 | 315 | if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){ |
| 257 | 316 | Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0); |
| 258 | 317 | return TH_ERROR; |
| 318 | + } |
| 319 | + rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, argl, rc); |
| 320 | + if( rc!=TH_OK ){ |
| 321 | + return rc; |
| 259 | 322 | } |
| 260 | 323 | Tcl_Preserve((ClientData)tclInterp); |
| 261 | 324 | if( argc==2 ){ |
| 262 | 325 | objPtr = Tcl_NewStringObj(argv[1], argl[1]); |
| 263 | 326 | Tcl_IncrRefCount(objPtr); |
| | @@ -278,10 +341,11 @@ |
| 278 | 341 | zResult = getTclResult(tclInterp, &nResult); |
| 279 | 342 | } |
| 280 | 343 | Th_SetResult(interp, zResult, nResult); |
| 281 | 344 | if( rc==TCL_OK ) Tcl_DecrRefCount(resultObjPtr); |
| 282 | 345 | Tcl_Release((ClientData)tclInterp); |
| 346 | + rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl, rc); |
| 283 | 347 | return rc; |
| 284 | 348 | } |
| 285 | 349 | |
| 286 | 350 | /* |
| 287 | 351 | ** Syntax: |
| | @@ -298,28 +362,32 @@ |
| 298 | 362 | Tcl_Interp *tclInterp; |
| 299 | 363 | #if !defined(USE_TCL_EVALOBJV) |
| 300 | 364 | Tcl_Command command; |
| 301 | 365 | Tcl_CmdInfo cmdInfo; |
| 302 | 366 | #endif |
| 303 | | - int rc; |
| 367 | + int rc = TH_OK; |
| 304 | 368 | int nResult; |
| 305 | 369 | const char *zResult; |
| 306 | 370 | #if !defined(USE_TCL_EVALOBJV) |
| 307 | 371 | Tcl_Obj *objPtr; |
| 308 | 372 | #endif |
| 309 | 373 | USE_ARGV_TO_OBJV(); |
| 310 | 374 | |
| 311 | | - if ( createTclInterp(interp, ctx)!=TH_OK ){ |
| 375 | + if( createTclInterp(interp, ctx)!=TH_OK ){ |
| 312 | 376 | return TH_ERROR; |
| 313 | 377 | } |
| 314 | 378 | if( argc<2 ){ |
| 315 | 379 | return Th_WrongNumArgs(interp, "tclInvoke command ?arg ...?"); |
| 316 | 380 | } |
| 317 | 381 | tclInterp = GET_CTX_TCL_INTERP(ctx); |
| 318 | 382 | if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){ |
| 319 | 383 | Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0); |
| 320 | 384 | return TH_ERROR; |
| 385 | + } |
| 386 | + rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, argl, rc); |
| 387 | + if( rc!=TH_OK ){ |
| 388 | + return rc; |
| 321 | 389 | } |
| 322 | 390 | Tcl_Preserve((ClientData)tclInterp); |
| 323 | 391 | #if !defined(USE_TCL_EVALOBJV) |
| 324 | 392 | objPtr = Tcl_NewStringObj(argv[1], argl[1]); |
| 325 | 393 | Tcl_IncrRefCount(objPtr); |
| | @@ -347,10 +415,11 @@ |
| 347 | 415 | #endif |
| 348 | 416 | FREE_ARGV_TO_OBJV(); |
| 349 | 417 | zResult = getTclResult(tclInterp, &nResult); |
| 350 | 418 | Th_SetResult(interp, zResult, nResult); |
| 351 | 419 | Tcl_Release((ClientData)tclInterp); |
| 420 | + rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl, rc); |
| 352 | 421 | return rc; |
| 353 | 422 | } |
| 354 | 423 | |
| 355 | 424 | /* |
| 356 | 425 | ** Syntax: |
| 357 | 426 | |