Fossil SCM
Loading Tcl 8.4 only works when USE_TCL_EVALOBJV=1. Reason: the function Tcl_GetCommandFromObj is introduced in Tcl 8.5 (TIP #139)
Commit
2234fabe76cb4a976bf8dc9ada65329918494bbf
Parent
da96f916cb02bdb…
2 files changed
+1
-1
+19
-14
+1
-1
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -823,11 +823,11 @@ | ||
| 823 | 823 | #if defined(FOSSIL_ENABLE_SSL) |
| 824 | 824 | fossil_print("SSL (%s)\n", OPENSSL_VERSION_TEXT); |
| 825 | 825 | #endif |
| 826 | 826 | #if defined(FOSSIL_ENABLE_TCL) |
| 827 | 827 | Th_FossilInit(TH_INIT_DEFAULT | TH_INIT_FORCE_TCL); |
| 828 | - rc = Th_Eval(g.interp, 0, "tclEval {info patchlevel}", -1); | |
| 828 | + rc = Th_Eval(g.interp, 0, "tclInvoke info patchlevel", -1); | |
| 829 | 829 | zRc = Th_ReturnCodeName(rc, 0); |
| 830 | 830 | fossil_print("TCL (Tcl %s, loaded %s: %s)\n", |
| 831 | 831 | TCL_PATCH_LEVEL, zRc, Th_GetResult(g.interp, 0) |
| 832 | 832 | ); |
| 833 | 833 | #endif |
| 834 | 834 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -823,11 +823,11 @@ | |
| 823 | #if defined(FOSSIL_ENABLE_SSL) |
| 824 | fossil_print("SSL (%s)\n", OPENSSL_VERSION_TEXT); |
| 825 | #endif |
| 826 | #if defined(FOSSIL_ENABLE_TCL) |
| 827 | Th_FossilInit(TH_INIT_DEFAULT | TH_INIT_FORCE_TCL); |
| 828 | rc = Th_Eval(g.interp, 0, "tclEval {info patchlevel}", -1); |
| 829 | zRc = Th_ReturnCodeName(rc, 0); |
| 830 | fossil_print("TCL (Tcl %s, loaded %s: %s)\n", |
| 831 | TCL_PATCH_LEVEL, zRc, Th_GetResult(g.interp, 0) |
| 832 | ); |
| 833 | #endif |
| 834 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -823,11 +823,11 @@ | |
| 823 | #if defined(FOSSIL_ENABLE_SSL) |
| 824 | fossil_print("SSL (%s)\n", OPENSSL_VERSION_TEXT); |
| 825 | #endif |
| 826 | #if defined(FOSSIL_ENABLE_TCL) |
| 827 | Th_FossilInit(TH_INIT_DEFAULT | TH_INIT_FORCE_TCL); |
| 828 | rc = Th_Eval(g.interp, 0, "tclInvoke info patchlevel", -1); |
| 829 | zRc = Th_ReturnCodeName(rc, 0); |
| 830 | fossil_print("TCL (Tcl %s, loaded %s: %s)\n", |
| 831 | TCL_PATCH_LEVEL, zRc, Th_GetResult(g.interp, 0) |
| 832 | ); |
| 833 | #endif |
| 834 |
+19
-14
| --- src/th_tcl.c | ||
| +++ src/th_tcl.c | ||
| @@ -29,27 +29,28 @@ | ||
| 29 | 29 | ** Has the decision about whether or not to use Tcl_EvalObjv already been made |
| 30 | 30 | ** via the Makefile? |
| 31 | 31 | */ |
| 32 | 32 | #if !defined(USE_TCL_EVALOBJV) |
| 33 | 33 | /* |
| 34 | -** Are we being compiled against Tcl 8.6b1 or b2? This check is [mostly] | |
| 34 | +** Are we being compiled against Tcl 8.4, 8.6b1 or b2? This check is [mostly] | |
| 35 | 35 | ** wrong for at the following reason: |
| 36 | 36 | ** |
| 37 | 37 | ** 1. Technically, this check is completely useless when the stubs mechanism |
| 38 | 38 | ** is in use. In that case, a runtime version check would be required and |
| 39 | 39 | ** that has not been implemented. |
| 40 | 40 | ** |
| 41 | -** However, if a particular user compiles and runs against Tcl 8.6b1 or b2, | |
| 41 | +** However, if a particular user compiles and runs against Tcl 8.4, 8.6b1 or b2, | |
| 42 | 42 | ** this will cause a fallback to using the "conservative" method of directly |
| 43 | 43 | ** invoking a Tcl command. In that case, potential crashes will be avoided if |
| 44 | -** the user just so happened to compile or run against Tcl 8.6b1 or b2. | |
| 44 | +** the user just so happened to compile or run against Tcl 8.4, 8.6b1 or b2. | |
| 45 | 45 | */ |
| 46 | -#if (TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION == 6) && \ | |
| 46 | +#if (TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION < 5) || (TCL_MINOR_VERSION == 6) && \ | |
| 47 | 47 | (TCL_RELEASE_LEVEL == TCL_BETA_RELEASE) && (TCL_RELEASE_SERIAL < 3) |
| 48 | 48 | /* |
| 49 | 49 | ** Workaround NRE-specific issue in Tcl_EvalObjCmd (SF bug #3399564) by using |
| 50 | -** Tcl_EvalObjv instead of invoking the objProc directly. | |
| 50 | +** Tcl_EvalObjv instead of invoking the objProc directly. In addition, Tcl 8.4 | |
| 51 | +** doesn't have the function Tcl_GetCommandFromObj (see TIP #139) | |
| 51 | 52 | */ |
| 52 | 53 | # define USE_TCL_EVALOBJV (1) |
| 53 | 54 | #else |
| 54 | 55 | /* |
| 55 | 56 | ** We should be able to safely use Tcl_GetCommandInfoFromToken, when the need |
| @@ -443,20 +444,20 @@ | ||
| 443 | 444 | int argc, |
| 444 | 445 | const char **argv, |
| 445 | 446 | int *argl |
| 446 | 447 | ){ |
| 447 | 448 | Tcl_Interp *tclInterp; |
| 448 | -#if !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV | |
| 449 | +#if !USE_TCL_EVALOBJV | |
| 449 | 450 | Tcl_Command command; |
| 450 | 451 | Tcl_CmdInfo cmdInfo; |
| 451 | -#endif /* !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV */ | |
| 452 | +#endif /* !USE_TCL_EVALOBJV */ | |
| 452 | 453 | int rc = TH_OK; |
| 453 | 454 | int nResult; |
| 454 | 455 | const char *zResult; |
| 455 | -#if !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV | |
| 456 | +#if !USE_TCL_EVALOBJV | |
| 456 | 457 | Tcl_Obj *objPtr; |
| 457 | -#endif /* !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV */ | |
| 458 | +#endif /* !USE_TCL_EVALOBJV */ | |
| 458 | 459 | USE_ARGV_TO_OBJV(); |
| 459 | 460 | |
| 460 | 461 | if( createTclInterp(interp, ctx)!=TH_OK ){ |
| 461 | 462 | return TH_ERROR; |
| 462 | 463 | } |
| @@ -471,11 +472,11 @@ | ||
| 471 | 472 | rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, argl, rc); |
| 472 | 473 | if( rc!=TH_OK ){ |
| 473 | 474 | return rc; |
| 474 | 475 | } |
| 475 | 476 | Tcl_Preserve((ClientData)tclInterp); |
| 476 | -#if !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV | |
| 477 | +#if !USE_TCL_EVALOBJV | |
| 477 | 478 | objPtr = Tcl_NewStringObj(argv[1], argl[1]); |
| 478 | 479 | Tcl_IncrRefCount(objPtr); |
| 479 | 480 | command = Tcl_GetCommandFromObj(tclInterp, objPtr); |
| 480 | 481 | if( !command || Tcl_GetCommandInfoFromToken(command, &cmdInfo)==0 ){ |
| 481 | 482 | Th_ErrorMessage(interp, "Tcl command not found:", argv[1], argl[1]); |
| @@ -488,18 +489,18 @@ | ||
| 488 | 489 | Tcl_DecrRefCount(objPtr); |
| 489 | 490 | Tcl_Release((ClientData)tclInterp); |
| 490 | 491 | return TH_ERROR; |
| 491 | 492 | } |
| 492 | 493 | Tcl_DecrRefCount(objPtr); |
| 493 | -#endif /* !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV */ | |
| 494 | +#endif /* !USE_TCL_EVALOBJV */ | |
| 494 | 495 | COPY_ARGV_TO_OBJV(); |
| 495 | -#if defined(USE_TCL_EVALOBJV) && USE_TCL_EVALOBJV | |
| 496 | +#if USE_TCL_EVALOBJV | |
| 496 | 497 | rc = Tcl_EvalObjv(tclInterp, objc, objv, 0); |
| 497 | 498 | #else |
| 498 | 499 | Tcl_ResetResult(tclInterp); |
| 499 | 500 | rc = cmdInfo.objProc(cmdInfo.objClientData, tclInterp, objc, objv); |
| 500 | -#endif /* defined(USE_TCL_EVALOBJV) && USE_TCL_EVALOBJV */ | |
| 501 | +#endif /* USE_TCL_EVALOBJV */ | |
| 501 | 502 | FREE_ARGV_TO_OBJV(); |
| 502 | 503 | zResult = getTclResult(tclInterp, &nResult); |
| 503 | 504 | Th_SetResult(interp, zResult, nResult); |
| 504 | 505 | Tcl_Release((ClientData)tclInterp); |
| 505 | 506 | rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl, rc); |
| @@ -670,14 +671,18 @@ | ||
| 670 | 671 | *pxFindExecutable = xFindExecutable; |
| 671 | 672 | *pxCreateInterp = xCreateInterp; |
| 672 | 673 | *pxDeleteInterp = xDeleteInterp; |
| 673 | 674 | return TH_OK; |
| 674 | 675 | } |
| 675 | - } while( --fileName[TCL_MINOR_OFFSET]>'3' ); /* Tcl 8.4+ */ | |
| 676 | + } while( --fileName[TCL_MINOR_OFFSET]>(USE_TCL_EVALOBJV?'4':'3') ); /* Tcl 8.5+ or 4*/ | |
| 676 | 677 | fileName[TCL_MINOR_OFFSET] = 'x'; |
| 677 | 678 | Th_ErrorMessage(interp, |
| 679 | +#if USE_TCL_EVALOBJV | |
| 678 | 680 | "could not load any supported Tcl 8.6, 8.5, or 8.4 shared library \"", |
| 681 | +#else | |
| 682 | + "could not load any supported Tcl 8.6 or 8.5 shared library \"", | |
| 683 | +#endif | |
| 679 | 684 | fileName, -1); |
| 680 | 685 | return TH_ERROR; |
| 681 | 686 | #else |
| 682 | 687 | *pLibrary = 0; |
| 683 | 688 | *pxFindExecutable = Tcl_FindExecutable; |
| 684 | 689 |
| --- src/th_tcl.c | |
| +++ src/th_tcl.c | |
| @@ -29,27 +29,28 @@ | |
| 29 | ** Has the decision about whether or not to use Tcl_EvalObjv already been made |
| 30 | ** via the Makefile? |
| 31 | */ |
| 32 | #if !defined(USE_TCL_EVALOBJV) |
| 33 | /* |
| 34 | ** Are we being compiled against Tcl 8.6b1 or b2? This check is [mostly] |
| 35 | ** wrong for at the following reason: |
| 36 | ** |
| 37 | ** 1. Technically, this check is completely useless when the stubs mechanism |
| 38 | ** is in use. In that case, a runtime version check would be required and |
| 39 | ** that has not been implemented. |
| 40 | ** |
| 41 | ** However, if a particular user compiles and runs against Tcl 8.6b1 or b2, |
| 42 | ** this will cause a fallback to using the "conservative" method of directly |
| 43 | ** invoking a Tcl command. In that case, potential crashes will be avoided if |
| 44 | ** the user just so happened to compile or run against Tcl 8.6b1 or b2. |
| 45 | */ |
| 46 | #if (TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION == 6) && \ |
| 47 | (TCL_RELEASE_LEVEL == TCL_BETA_RELEASE) && (TCL_RELEASE_SERIAL < 3) |
| 48 | /* |
| 49 | ** Workaround NRE-specific issue in Tcl_EvalObjCmd (SF bug #3399564) by using |
| 50 | ** Tcl_EvalObjv instead of invoking the objProc directly. |
| 51 | */ |
| 52 | # define USE_TCL_EVALOBJV (1) |
| 53 | #else |
| 54 | /* |
| 55 | ** We should be able to safely use Tcl_GetCommandInfoFromToken, when the need |
| @@ -443,20 +444,20 @@ | |
| 443 | int argc, |
| 444 | const char **argv, |
| 445 | int *argl |
| 446 | ){ |
| 447 | Tcl_Interp *tclInterp; |
| 448 | #if !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV |
| 449 | Tcl_Command command; |
| 450 | Tcl_CmdInfo cmdInfo; |
| 451 | #endif /* !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV */ |
| 452 | int rc = TH_OK; |
| 453 | int nResult; |
| 454 | const char *zResult; |
| 455 | #if !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV |
| 456 | Tcl_Obj *objPtr; |
| 457 | #endif /* !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV */ |
| 458 | USE_ARGV_TO_OBJV(); |
| 459 | |
| 460 | if( createTclInterp(interp, ctx)!=TH_OK ){ |
| 461 | return TH_ERROR; |
| 462 | } |
| @@ -471,11 +472,11 @@ | |
| 471 | rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, argl, rc); |
| 472 | if( rc!=TH_OK ){ |
| 473 | return rc; |
| 474 | } |
| 475 | Tcl_Preserve((ClientData)tclInterp); |
| 476 | #if !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV |
| 477 | objPtr = Tcl_NewStringObj(argv[1], argl[1]); |
| 478 | Tcl_IncrRefCount(objPtr); |
| 479 | command = Tcl_GetCommandFromObj(tclInterp, objPtr); |
| 480 | if( !command || Tcl_GetCommandInfoFromToken(command, &cmdInfo)==0 ){ |
| 481 | Th_ErrorMessage(interp, "Tcl command not found:", argv[1], argl[1]); |
| @@ -488,18 +489,18 @@ | |
| 488 | Tcl_DecrRefCount(objPtr); |
| 489 | Tcl_Release((ClientData)tclInterp); |
| 490 | return TH_ERROR; |
| 491 | } |
| 492 | Tcl_DecrRefCount(objPtr); |
| 493 | #endif /* !defined(USE_TCL_EVALOBJV) || !USE_TCL_EVALOBJV */ |
| 494 | COPY_ARGV_TO_OBJV(); |
| 495 | #if defined(USE_TCL_EVALOBJV) && USE_TCL_EVALOBJV |
| 496 | rc = Tcl_EvalObjv(tclInterp, objc, objv, 0); |
| 497 | #else |
| 498 | Tcl_ResetResult(tclInterp); |
| 499 | rc = cmdInfo.objProc(cmdInfo.objClientData, tclInterp, objc, objv); |
| 500 | #endif /* defined(USE_TCL_EVALOBJV) && USE_TCL_EVALOBJV */ |
| 501 | FREE_ARGV_TO_OBJV(); |
| 502 | zResult = getTclResult(tclInterp, &nResult); |
| 503 | Th_SetResult(interp, zResult, nResult); |
| 504 | Tcl_Release((ClientData)tclInterp); |
| 505 | rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl, rc); |
| @@ -670,14 +671,18 @@ | |
| 670 | *pxFindExecutable = xFindExecutable; |
| 671 | *pxCreateInterp = xCreateInterp; |
| 672 | *pxDeleteInterp = xDeleteInterp; |
| 673 | return TH_OK; |
| 674 | } |
| 675 | } while( --fileName[TCL_MINOR_OFFSET]>'3' ); /* Tcl 8.4+ */ |
| 676 | fileName[TCL_MINOR_OFFSET] = 'x'; |
| 677 | Th_ErrorMessage(interp, |
| 678 | "could not load any supported Tcl 8.6, 8.5, or 8.4 shared library \"", |
| 679 | fileName, -1); |
| 680 | return TH_ERROR; |
| 681 | #else |
| 682 | *pLibrary = 0; |
| 683 | *pxFindExecutable = Tcl_FindExecutable; |
| 684 |
| --- src/th_tcl.c | |
| +++ src/th_tcl.c | |
| @@ -29,27 +29,28 @@ | |
| 29 | ** Has the decision about whether or not to use Tcl_EvalObjv already been made |
| 30 | ** via the Makefile? |
| 31 | */ |
| 32 | #if !defined(USE_TCL_EVALOBJV) |
| 33 | /* |
| 34 | ** Are we being compiled against Tcl 8.4, 8.6b1 or b2? This check is [mostly] |
| 35 | ** wrong for at the following reason: |
| 36 | ** |
| 37 | ** 1. Technically, this check is completely useless when the stubs mechanism |
| 38 | ** is in use. In that case, a runtime version check would be required and |
| 39 | ** that has not been implemented. |
| 40 | ** |
| 41 | ** However, if a particular user compiles and runs against Tcl 8.4, 8.6b1 or b2, |
| 42 | ** this will cause a fallback to using the "conservative" method of directly |
| 43 | ** invoking a Tcl command. In that case, potential crashes will be avoided if |
| 44 | ** the user just so happened to compile or run against Tcl 8.4, 8.6b1 or b2. |
| 45 | */ |
| 46 | #if (TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION < 5) || (TCL_MINOR_VERSION == 6) && \ |
| 47 | (TCL_RELEASE_LEVEL == TCL_BETA_RELEASE) && (TCL_RELEASE_SERIAL < 3) |
| 48 | /* |
| 49 | ** Workaround NRE-specific issue in Tcl_EvalObjCmd (SF bug #3399564) by using |
| 50 | ** Tcl_EvalObjv instead of invoking the objProc directly. In addition, Tcl 8.4 |
| 51 | ** doesn't have the function Tcl_GetCommandFromObj (see TIP #139) |
| 52 | */ |
| 53 | # define USE_TCL_EVALOBJV (1) |
| 54 | #else |
| 55 | /* |
| 56 | ** We should be able to safely use Tcl_GetCommandInfoFromToken, when the need |
| @@ -443,20 +444,20 @@ | |
| 444 | int argc, |
| 445 | const char **argv, |
| 446 | int *argl |
| 447 | ){ |
| 448 | Tcl_Interp *tclInterp; |
| 449 | #if !USE_TCL_EVALOBJV |
| 450 | Tcl_Command command; |
| 451 | Tcl_CmdInfo cmdInfo; |
| 452 | #endif /* !USE_TCL_EVALOBJV */ |
| 453 | int rc = TH_OK; |
| 454 | int nResult; |
| 455 | const char *zResult; |
| 456 | #if !USE_TCL_EVALOBJV |
| 457 | Tcl_Obj *objPtr; |
| 458 | #endif /* !USE_TCL_EVALOBJV */ |
| 459 | USE_ARGV_TO_OBJV(); |
| 460 | |
| 461 | if( createTclInterp(interp, ctx)!=TH_OK ){ |
| 462 | return TH_ERROR; |
| 463 | } |
| @@ -471,11 +472,11 @@ | |
| 472 | rc = notifyPreOrPostEval(0, interp, ctx, argc, argv, argl, rc); |
| 473 | if( rc!=TH_OK ){ |
| 474 | return rc; |
| 475 | } |
| 476 | Tcl_Preserve((ClientData)tclInterp); |
| 477 | #if !USE_TCL_EVALOBJV |
| 478 | objPtr = Tcl_NewStringObj(argv[1], argl[1]); |
| 479 | Tcl_IncrRefCount(objPtr); |
| 480 | command = Tcl_GetCommandFromObj(tclInterp, objPtr); |
| 481 | if( !command || Tcl_GetCommandInfoFromToken(command, &cmdInfo)==0 ){ |
| 482 | Th_ErrorMessage(interp, "Tcl command not found:", argv[1], argl[1]); |
| @@ -488,18 +489,18 @@ | |
| 489 | Tcl_DecrRefCount(objPtr); |
| 490 | Tcl_Release((ClientData)tclInterp); |
| 491 | return TH_ERROR; |
| 492 | } |
| 493 | Tcl_DecrRefCount(objPtr); |
| 494 | #endif /* !USE_TCL_EVALOBJV */ |
| 495 | COPY_ARGV_TO_OBJV(); |
| 496 | #if USE_TCL_EVALOBJV |
| 497 | rc = Tcl_EvalObjv(tclInterp, objc, objv, 0); |
| 498 | #else |
| 499 | Tcl_ResetResult(tclInterp); |
| 500 | rc = cmdInfo.objProc(cmdInfo.objClientData, tclInterp, objc, objv); |
| 501 | #endif /* USE_TCL_EVALOBJV */ |
| 502 | FREE_ARGV_TO_OBJV(); |
| 503 | zResult = getTclResult(tclInterp, &nResult); |
| 504 | Th_SetResult(interp, zResult, nResult); |
| 505 | Tcl_Release((ClientData)tclInterp); |
| 506 | rc = notifyPreOrPostEval(1, interp, ctx, argc, argv, argl, rc); |
| @@ -670,14 +671,18 @@ | |
| 671 | *pxFindExecutable = xFindExecutable; |
| 672 | *pxCreateInterp = xCreateInterp; |
| 673 | *pxDeleteInterp = xDeleteInterp; |
| 674 | return TH_OK; |
| 675 | } |
| 676 | } while( --fileName[TCL_MINOR_OFFSET]>(USE_TCL_EVALOBJV?'4':'3') ); /* Tcl 8.5+ or 4*/ |
| 677 | fileName[TCL_MINOR_OFFSET] = 'x'; |
| 678 | Th_ErrorMessage(interp, |
| 679 | #if USE_TCL_EVALOBJV |
| 680 | "could not load any supported Tcl 8.6, 8.5, or 8.4 shared library \"", |
| 681 | #else |
| 682 | "could not load any supported Tcl 8.6 or 8.5 shared library \"", |
| 683 | #endif |
| 684 | fileName, -1); |
| 685 | return TH_ERROR; |
| 686 | #else |
| 687 | *pLibrary = 0; |
| 688 | *pxFindExecutable = Tcl_FindExecutable; |
| 689 |