Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Enhance Tcl integration with support for notifications before and after Tcl scripts are evaluated. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA1: |
49c63f8c78a38b4632a1c4255078c5b6 |
| User & Date: | mistachkin 2012-10-07 13:55:39.920 |
Context
|
2012-10-08
| ||
| 13:50 | Fix references to uninitialized memory when existing the SQL shell. ... (check-in: 1955e6a69d user: drh tags: trunk) | |
|
2012-10-07
| ||
| 17:18 | merge trunk make Notepad the default comment editor on Windows ... (check-in: 10cf72bd3b user: jan.nijtmans tags: use-utf8-in-win-external-editor) | |
| 14:22 | Experimental proof-of-concept for the 'tcl-rdonly' setting and related functionality. ... (check-in: 851e0755e5 user: mistachkin tags: tclRdOnly) | |
| 13:55 | Enhance Tcl integration with support for notifications before and after Tcl scripts are evaluated. ... (check-in: 49c63f8c78 user: mistachkin tags: trunk) | |
| 10:12 | Add 'tcl-setup' setting for the optional Tcl script to evaluate after creating and initializing the Tcl interpreter. Make sure Tcl gets a copy of all the original expanded arguments. ... (check-in: fa4e828653 user: mistachkin tags: trunk) | |
Changes
Changes to src/main.c.
| ︙ | ︙ | |||
93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
int argc; /* Number of original (expanded) arguments. */
char **argv; /* Full copy of the original (expanded) arguments. */
void *library; /* The Tcl library module handle. */
void *xFindExecutable; /* See tcl_FindExecutableProc in th_tcl.c. */
void *xCreateInterp; /* See tcl_CreateInterpProc in th_tcl.c. */
Tcl_Interp *interp; /* The on-demand created Tcl interpreter. */
char *setup; /* The optional Tcl setup script. */
};
#endif
/*
** All global variables are in this structure.
*/
struct Global {
| > > > > | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
int argc; /* Number of original (expanded) arguments. */
char **argv; /* Full copy of the original (expanded) arguments. */
void *library; /* The Tcl library module handle. */
void *xFindExecutable; /* See tcl_FindExecutableProc in th_tcl.c. */
void *xCreateInterp; /* See tcl_CreateInterpProc in th_tcl.c. */
Tcl_Interp *interp; /* The on-demand created Tcl interpreter. */
char *setup; /* The optional Tcl setup script. */
void *xPreEval; /* Optional, called before Tcl_Eval*(). */
void *pPreContext; /* Optional, provided to xPreEval(). */
void *xPostEval; /* Optional, called after Tcl_Eval*(). */
void *pPostContext; /* Optional, provided to xPostEval(). */
};
#endif
/*
** All global variables are in this structure.
*/
struct Global {
|
| ︙ | ︙ |
Changes to src/th_tcl.c.
| ︙ | ︙ | |||
78 79 80 81 82 83 84 | # ifndef TCL_LIBRARY_NAME # define TCL_LIBRARY_NAME "tcl86.dll\0" # endif # ifndef TCL_MINOR_OFFSET # define TCL_MINOR_OFFSET (4) # endif # ifndef dlopen | | | | | 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | # ifndef TCL_LIBRARY_NAME # define TCL_LIBRARY_NAME "tcl86.dll\0" # endif # ifndef TCL_MINOR_OFFSET # define TCL_MINOR_OFFSET (4) # endif # ifndef dlopen # define dlopen(a,b) (void *)LoadLibrary((a)) # endif # ifndef dlsym # define dlsym(a,b) GetProcAddress((HANDLE)(a),(b)) # endif # ifndef dlclose # define dlclose(a) FreeLibrary((HANDLE)(a)) # endif # else # include <dlfcn.h> # if defined(__CYGWIN__) # ifndef TCL_LIBRARY_NAME # define TCL_LIBRARY_NAME "libtcl8.6.dll\0" # endif |
| ︙ | ︙ | |||
120 121 122 123 124 125 126 | # endif # ifndef TCL_CREATEINTERP_NAME # define TCL_CREATEINTERP_NAME "_Tcl_CreateInterp" # endif #endif /* defined(USE_TCL_STUBS) */ /* | | | > > > > > > > > > > > > > > > > > > | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | # endif # ifndef TCL_CREATEINTERP_NAME # define TCL_CREATEINTERP_NAME "_Tcl_CreateInterp" # endif #endif /* defined(USE_TCL_STUBS) */ /* ** The function types for Tcl_FindExecutable and Tcl_CreateInterp are needed ** when the Tcl library is being loaded dynamically by a stubs-enabled ** application (i.e. the inverse of using a stubs-enabled package). These are ** the only Tcl API functions that MUST be called prior to being able to call ** Tcl_InitStubs (i.e. because it requires a Tcl interpreter). */ typedef void (tcl_FindExecutableProc) (CONST char * argv0); typedef Tcl_Interp *(tcl_CreateInterpProc) (void); /* ** The function types for the "hook" functions to be called before and after a ** TH1 command makes a call to evaluate a Tcl script. If the "pre" function ** returns anything but TH_OK, then evaluation of the Tcl script is skipped and ** that value is used as the return code. If the "post" function returns ** anything other than its rc argument, that will become the new return code ** for the command. */ typedef int (tcl_NotifyProc) ( void *pContext, /* The context for this notification. */ Th_Interp *interp, /* The TH1 interpreter being used. */ void *ctx, /* The original TH1 command context. */ int argc, /* Number of arguments for the TH1 command. */ const char **argv, /* Array of arguments for the TH1 command. */ int *argl, /* Array of lengths for the TH1 command arguments. */ int rc /* Recommended notification return value. */ ); /* ** Creates and initializes a Tcl interpreter for use with the specified TH1 ** interpreter. Stores the created Tcl interpreter in the Tcl context supplied ** by the caller. This must be declared here because quite a few functions in ** this file need to use it before it can be defined. */ |
| ︙ | ︙ | |||
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
int argc; /* Number of original arguments. */
char **argv; /* Full copy of the original arguments. */
void *library; /* The Tcl library module handle. */
tcl_FindExecutableProc *xFindExecutable; /* Tcl_FindExecutable() pointer. */
tcl_CreateInterpProc *xCreateInterp; /* Tcl_CreateInterp() pointer. */
Tcl_Interp *interp; /* The on-demand created Tcl interpreter. */
char *setup; /* The optional Tcl setup script. */
};
/*
** Syntax:
**
** tclEval arg ?arg ...?
*/
static int tclEval_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
Tcl_Interp *tclInterp;
Tcl_Obj *objPtr;
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > | | > > > > | 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 |
int argc; /* Number of original arguments. */
char **argv; /* Full copy of the original arguments. */
void *library; /* The Tcl library module handle. */
tcl_FindExecutableProc *xFindExecutable; /* Tcl_FindExecutable() pointer. */
tcl_CreateInterpProc *xCreateInterp; /* Tcl_CreateInterp() pointer. */
Tcl_Interp *interp; /* The on-demand created Tcl interpreter. */
char *setup; /* The optional Tcl setup script. */
tcl_NotifyProc *xPreEval; /* Optional, called before Tcl_Eval*(). */
void *pPreContext; /* Optional, provided to xPreEval(). */
tcl_NotifyProc *xPostEval; /* Optional, called after Tcl_Eval*(). */
void *pPostContext; /* Optional, provided to xPostEval(). */
};
/*
** This function calls the configured xPreEval or xPostEval functions, if any.
** May have arbitrary side-effects. This function returns the result of the
** called notification function or the value of the rc argument if there is no
** notification function configured.
*/
static int notifyPreOrPostEval(
int bIsPost,
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl,
int rc
){
struct TclContext *tclContext = (struct TclContext *)ctx;
tcl_NotifyProc *xNotifyProc;
if ( !tclContext ){
Th_ErrorMessage(interp,
"Invalid Tcl context", (const char *)"", 0);
return TH_ERROR;
}
xNotifyProc = bIsPost ? tclContext->xPostEval : tclContext->xPreEval;
if ( xNotifyProc ){
rc = xNotifyProc(bIsPost ?
tclContext->pPostContext : tclContext->pPreContext,
interp, ctx, argc, argv, argl, rc);
}
return rc;
}
/*
** Syntax:
**
** tclEval arg ?arg ...?
*/
static int tclEval_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
Tcl_Interp *tclInterp;
Tcl_Obj *objPtr;
int rc = TH_OK;
int nResult;
const char *zResult;
if( createTclInterp(interp, ctx)!=TH_OK ){
return TH_ERROR;
}
if( argc<2 ){
return Th_WrongNumArgs(interp, "tclEval arg ?arg ...?");
}
tclInterp = GET_CTX_TCL_INTERP(ctx);
if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
return TH_ERROR;
}
rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, argl, rc);
if( rc!=TH_OK ){
return rc;
}
Tcl_Preserve((ClientData)tclInterp);
if( argc==2 ){
objPtr = Tcl_NewStringObj(argv[1], argl[1]);
Tcl_IncrRefCount(objPtr);
rc = Tcl_EvalObjEx(tclInterp, objPtr, 0);
Tcl_DecrRefCount(objPtr);
}else{
USE_ARGV_TO_OBJV();
COPY_ARGV_TO_OBJV();
objPtr = Tcl_ConcatObj(objc, objv);
Tcl_IncrRefCount(objPtr);
rc = Tcl_EvalObjEx(tclInterp, objPtr, 0);
Tcl_DecrRefCount(objPtr);
FREE_ARGV_TO_OBJV();
}
zResult = getTclResult(tclInterp, &nResult);
Th_SetResult(interp, zResult, nResult);
Tcl_Release((ClientData)tclInterp);
rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl, rc);
return rc;
}
/*
** Syntax:
**
** tclExpr arg ?arg ...?
*/
static int tclExpr_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
Tcl_Interp *tclInterp;
Tcl_Obj *objPtr;
Tcl_Obj *resultObjPtr;
int rc = TH_OK;
int nResult;
const char *zResult;
if( createTclInterp(interp, ctx)!=TH_OK ){
return TH_ERROR;
}
if( argc<2 ){
return Th_WrongNumArgs(interp, "tclExpr arg ?arg ...?");
}
tclInterp = GET_CTX_TCL_INTERP(ctx);
if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
return TH_ERROR;
}
rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, argl, rc);
if( rc!=TH_OK ){
return rc;
}
Tcl_Preserve((ClientData)tclInterp);
if( argc==2 ){
objPtr = Tcl_NewStringObj(argv[1], argl[1]);
Tcl_IncrRefCount(objPtr);
rc = Tcl_ExprObj(tclInterp, objPtr, &resultObjPtr);
Tcl_DecrRefCount(objPtr);
|
| ︙ | ︙ | |||
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 |
zResult = Tcl_GetStringFromObj(resultObjPtr, &nResult);
}else{
zResult = getTclResult(tclInterp, &nResult);
}
Th_SetResult(interp, zResult, nResult);
if( rc==TCL_OK ) Tcl_DecrRefCount(resultObjPtr);
Tcl_Release((ClientData)tclInterp);
return rc;
}
/*
** Syntax:
**
** tclInvoke command ?arg ...?
*/
static int tclInvoke_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
Tcl_Interp *tclInterp;
#if !defined(USE_TCL_EVALOBJV)
Tcl_Command command;
Tcl_CmdInfo cmdInfo;
#endif
| > | | > > > > | 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 |
zResult = Tcl_GetStringFromObj(resultObjPtr, &nResult);
}else{
zResult = getTclResult(tclInterp, &nResult);
}
Th_SetResult(interp, zResult, nResult);
if( rc==TCL_OK ) Tcl_DecrRefCount(resultObjPtr);
Tcl_Release((ClientData)tclInterp);
rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl, rc);
return rc;
}
/*
** Syntax:
**
** tclInvoke command ?arg ...?
*/
static int tclInvoke_command(
Th_Interp *interp,
void *ctx,
int argc,
const char **argv,
int *argl
){
Tcl_Interp *tclInterp;
#if !defined(USE_TCL_EVALOBJV)
Tcl_Command command;
Tcl_CmdInfo cmdInfo;
#endif
int rc = TH_OK;
int nResult;
const char *zResult;
#if !defined(USE_TCL_EVALOBJV)
Tcl_Obj *objPtr;
#endif
USE_ARGV_TO_OBJV();
if( createTclInterp(interp, ctx)!=TH_OK ){
return TH_ERROR;
}
if( argc<2 ){
return Th_WrongNumArgs(interp, "tclInvoke command ?arg ...?");
}
tclInterp = GET_CTX_TCL_INTERP(ctx);
if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
return TH_ERROR;
}
rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, argl, rc);
if( rc!=TH_OK ){
return rc;
}
Tcl_Preserve((ClientData)tclInterp);
#if !defined(USE_TCL_EVALOBJV)
objPtr = Tcl_NewStringObj(argv[1], argl[1]);
Tcl_IncrRefCount(objPtr);
command = Tcl_GetCommandFromObj(tclInterp, objPtr);
if( !command || Tcl_GetCommandInfoFromToken(command,&cmdInfo)==0 ){
|
| ︙ | ︙ | |||
345 346 347 348 349 350 351 352 353 354 355 356 357 358 | Tcl_ResetResult(tclInterp); rc = cmdInfo.objProc(cmdInfo.objClientData, tclInterp, objc, objv); #endif FREE_ARGV_TO_OBJV(); zResult = getTclResult(tclInterp, &nResult); Th_SetResult(interp, zResult, nResult); Tcl_Release((ClientData)tclInterp); return rc; } /* ** Syntax: ** ** th1Eval arg | > | 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 | Tcl_ResetResult(tclInterp); rc = cmdInfo.objProc(cmdInfo.objClientData, tclInterp, objc, objv); #endif FREE_ARGV_TO_OBJV(); zResult = getTclResult(tclInterp, &nResult); Th_SetResult(interp, zResult, nResult); Tcl_Release((ClientData)tclInterp); rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl, rc); return rc; } /* ** Syntax: ** ** th1Eval arg |
| ︙ | ︙ |
Changes to test/th1-tcl2.txt.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<th1>
#
# This is a "TH1 fragment" used to test the Tcl integration features of TH1.
# The corresponding test file executes this file using the test-th-render
# Fossil command.
#
# NOTE: This test requires that the SQLite package be available for the Tcl
# interpreter that is linked to the Fossil executable.
#
tclInvoke set repository_name [repository 1]
proc doOut {msg} {puts $msg; puts \n}
doOut [tclEval {
package require sqlite3
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<th1>
#
# This is a "TH1 fragment" used to test the Tcl integration features of TH1.
# The corresponding test file executes this file using the test-th-render
# Fossil command.
#
# NOTE: This test requires that the SQLite package be available for the Tcl
# interpreter that is linked to the Fossil executable.
#
tclInvoke set repository_name [repository 1]
proc doOut {msg} {puts $msg; puts \n}
doOut [tclEval {
package require sqlite3
sqlite3 db $repository_name -readonly true
set x [db eval {SELECT COUNT(*) FROM user;}]
db close
return $x
}]
</th1>
|