summaryrefslogtreecommitdiffstats
path: root/generic/tclTest.c
diff options
context:
space:
mode:
authorkjnash <k.j.nash@usa.net>2022-08-31 16:19:00 (GMT)
committerkjnash <k.j.nash@usa.net>2022-08-31 16:19:00 (GMT)
commitbca70ca3acaed162e49bc7616b7da4001c7fee41 (patch)
treee7f53f796bd576d7231fed8db0aa533ae65f59b6 /generic/tclTest.c
parent7e2bd5e5052a3fa8f5ee01c05e56fadf4cdfc592 (diff)
parent6cf74d1492b68e11b5a4cccf559ec5f69836b67b (diff)
downloadtcl-bca70ca3acaed162e49bc7616b7da4001c7fee41.zip
tcl-bca70ca3acaed162e49bc7616b7da4001c7fee41.tar.gz
tcl-bca70ca3acaed162e49bc7616b7da4001c7fee41.tar.bz2
Merge 8.7
Diffstat (limited to 'generic/tclTest.c')
-rw-r--r--generic/tclTest.c597
1 files changed, 513 insertions, 84 deletions
diff --git a/generic/tclTest.c b/generic/tclTest.c
index 39bd392..8d106f9 100644
--- a/generic/tclTest.c
+++ b/generic/tclTest.c
@@ -16,10 +16,13 @@
*/
#undef STATIC_BUILD
+#undef BUILD_tcl
#ifndef USE_TCL_STUBS
# define USE_TCL_STUBS
#endif
-#ifndef TCL_NO_DEPRECATED
+#ifdef TCL_NO_DEPRECATED
+# define TCL_UTF_MAX 4
+#else
# define TCL_NO_DEPRECATED
#endif
#include "tclInt.h"
@@ -41,6 +44,8 @@
*/
#include "tclIO.h"
+#include "tclUuid.h"
+
/*
* Declare external functions used in Windows tests.
*/
@@ -56,6 +61,21 @@ static Tcl_DString delString;
static Tcl_Interp *delInterp;
/*
+ * One of the following structures exists for each command created by the
+ * "testcmdtoken" command.
+ */
+
+typedef struct TestCommandTokenRef {
+ int id; /* Identifier for this reference. */
+ Tcl_Command token; /* Tcl's token for the command. */
+ struct TestCommandTokenRef *nextPtr;
+ /* Next in list of references. */
+} TestCommandTokenRef;
+
+static TestCommandTokenRef *firstCommandTokenRef = NULL;
+static int nextCommandTokenRefId = 1;
+
+/*
* One of the following structures exists for each asynchronous handler
* created by the "testasync" command".
*/
@@ -163,9 +183,7 @@ static TestChannel *firstDetached;
static int AsyncHandlerProc(void *clientData,
Tcl_Interp *interp, int code);
-#if TCL_THREADS
static Tcl_ThreadCreateType AsyncThreadProc(void *);
-#endif
static void CleanupTestSetassocdataTests(
void *clientData, Tcl_Interp *interp);
static void CmdDelProc1(void *clientData);
@@ -219,6 +237,7 @@ static Tcl_ObjCmdProc TestbytestringObjCmd;
static Tcl_ObjCmdProc TestsetbytearraylengthObjCmd;
static Tcl_ObjCmdProc TestpurebytesobjObjCmd;
static Tcl_ObjCmdProc TeststringbytesObjCmd;
+static Tcl_ObjCmdProc Testutf16stringObjCmd;
static Tcl_CmdProc TestcmdinfoCmd;
static Tcl_CmdProc TestcmdtokenCmd;
static Tcl_CmdProc TestcmdtraceCmd;
@@ -254,6 +273,7 @@ static Tcl_ObjCmdProc TestgetvarfullnameCmd;
static Tcl_CmdProc TestinterpdeleteCmd;
static Tcl_CmdProc TestlinkCmd;
static Tcl_ObjCmdProc TestlinkarrayCmd;
+static Tcl_ObjCmdProc TestlistrepCmd;
static Tcl_ObjCmdProc TestlocaleCmd;
static Tcl_CmdProc TestmainthreadCmd;
static Tcl_CmdProc TestsetmainloopCmd;
@@ -329,14 +349,16 @@ static Tcl_ObjCmdProc TestNumUtfCharsCmd;
static Tcl_ObjCmdProc TestFindFirstCmd;
static Tcl_ObjCmdProc TestFindLastCmd;
static Tcl_ObjCmdProc TestHashSystemHashCmd;
+static Tcl_ObjCmdProc TestGetIntForIndexCmd;
static Tcl_NRPostProc NREUnwind_callback;
static Tcl_ObjCmdProc TestNREUnwind;
static Tcl_ObjCmdProc TestNRELevels;
static Tcl_ObjCmdProc TestInterpResolverCmd;
-#if defined(HAVE_CPUID) || defined(_WIN32)
+#if defined(HAVE_CPUID) && !defined(MAC_OSX_TCL)
static Tcl_ObjCmdProc TestcpuidCmd;
#endif
+static Tcl_ObjCmdProc TestApplyLambdaObjCmd;
static const Tcl_Filesystem testReportingFilesystem = {
"reporting",
@@ -439,12 +461,87 @@ static const Tcl_Filesystem simpleFilesystem = {
*----------------------------------------------------------------------
*/
+#ifndef STRINGIFY
+# define STRINGIFY(x) STRINGIFY1(x)
+# define STRINGIFY1(x) #x
+#endif
+
+static const char version[] = TCL_PATCH_LEVEL "+" STRINGIFY(TCL_VERSION_UUID)
+#if defined(__clang__) && defined(__clang_major__)
+ ".clang-" STRINGIFY(__clang_major__)
+#if __clang_minor__ < 10
+ "0"
+#endif
+ STRINGIFY(__clang_minor__)
+#endif
+#ifdef TCL_COMPILE_DEBUG
+ ".compiledebug"
+#endif
+#ifdef TCL_COMPILE_STATS
+ ".compilestats"
+#endif
+#if defined(__cplusplus) && !defined(__OBJC__)
+ ".cplusplus"
+#endif
+#ifndef NDEBUG
+ ".debug"
+#endif
+#if !defined(__clang__) && !defined(__INTEL_COMPILER) && defined(__GNUC__)
+ ".gcc-" STRINGIFY(__GNUC__)
+#if __GNUC_MINOR__ < 10
+ "0"
+#endif
+ STRINGIFY(__GNUC_MINOR__)
+#endif
+#ifdef __INTEL_COMPILER
+ ".icc-" STRINGIFY(__INTEL_COMPILER)
+#endif
+#if (defined(_WIN32) && !defined(_WIN64)) || (ULONG_MAX == 0xffffffffUL)
+ ".ilp32"
+#endif
+#ifdef TCL_MEM_DEBUG
+ ".memdebug"
+#endif
+#if defined(_MSC_VER)
+ ".msvc-" STRINGIFY(_MSC_VER)
+#endif
+#ifdef USE_NMAKE
+ ".nmake"
+#endif
+#if !TCL_THREADS
+ ".no-thread"
+#endif
+#ifndef TCL_CFG_OPTIMIZED
+ ".no-optimize"
+#endif
+#ifdef __OBJC__
+ ".objective-c"
+#if defined(__cplusplus)
+ "plusplus"
+#endif
+#endif
+#ifdef TCL_CFG_PROFILED
+ ".profile"
+#endif
+#ifdef PURIFY
+ ".purify"
+#endif
+#ifdef STATIC_BUILD
+ ".static"
+#endif
+#if TCL_UTF_MAX < 4
+ ".utf-16"
+#endif
+;
+
int
Tcltest_Init(
Tcl_Interp *interp) /* Interpreter for application. */
{
+ Tcl_CmdInfo info;
Tcl_Obj **objv, *objPtr;
- int objc, index;
+ size_t objc;
+ int index;
static const char *const specialOptions[] = {
"-appinitprocerror", "-appinitprocdeleteinterp",
"-appinitprocclosestderr", "-appinitprocsetrcfile", NULL
@@ -461,8 +558,11 @@ Tcltest_Init(
if (Tcl_OOInitStubs(interp) == NULL) {
return TCL_ERROR;
}
- /* TIP #268: Full patchlevel instead of just major.minor */
+ if (Tcl_GetCommandInfo(interp, "::tcl::build-info", &info)) {
+ Tcl_CreateObjCommand(interp, "::tcl::test::build-info",
+ info.objProc, (void *)version, NULL);
+ }
if (Tcl_PkgProvideEx(interp, "tcl::test", TCL_PATCH_LEVEL, NULL) == TCL_ERROR) {
return TCL_ERROR;
}
@@ -478,6 +578,7 @@ Tcltest_Init(
Tcl_CreateObjCommand(interp, "testsetbytearraylength", TestsetbytearraylengthObjCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testbytestring", TestbytestringObjCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "teststringbytes", TeststringbytesObjCmd, NULL, NULL);
+ Tcl_CreateObjCommand(interp, "testutf16string", Testutf16stringObjCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testwrongnumargs", TestWrongNumArgsObjCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testfilesystem", TestFilesystemObjCmd,
@@ -556,6 +657,7 @@ Tcltest_Init(
NULL, NULL);
Tcl_CreateCommand(interp, "testlink", TestlinkCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testlinkarray", TestlinkarrayCmd, NULL, NULL);
+ Tcl_CreateObjCommand(interp, "testlistrep", TestlistrepCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testlocale", TestlocaleCmd, NULL,
NULL);
Tcl_CreateCommand(interp, "testpanic", TestpanicCmd, NULL, NULL);
@@ -600,6 +702,8 @@ Tcltest_Init(
TestFindFirstCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testfindlast",
TestFindLastCmd, NULL, NULL);
+ Tcl_CreateObjCommand(interp, "testgetintforindex",
+ TestGetIntForIndexCmd, NULL, NULL);
Tcl_CreateCommand(interp, "testsetplatform", TestsetplatformCmd,
NULL, NULL);
Tcl_CreateCommand(interp, "testsocket", TestSocketCmd,
@@ -615,7 +719,7 @@ Tcltest_Init(
NULL, NULL);
Tcl_CreateCommand(interp, "testexitmainloop", TestexitmainloopCmd,
NULL, NULL);
-#if defined(HAVE_CPUID) || defined(_WIN32)
+#if defined(HAVE_CPUID) && !defined(MAC_OSX_TCL)
Tcl_CreateObjCommand(interp, "testcpuid", TestcpuidCmd,
NULL, NULL);
#endif
@@ -629,6 +733,8 @@ Tcltest_Init(
NULL, NULL);
Tcl_CreateObjCommand(interp, "testsetencpath", TestsetencpathObjCmd,
NULL, NULL);
+ Tcl_CreateObjCommand(interp, "testapplylambda", TestApplyLambdaObjCmd,
+ NULL, NULL);
if (TclObjTest_Init(interp) != TCL_OK) {
return TCL_ERROR;
@@ -705,9 +811,18 @@ int
Tcltest_SafeInit(
Tcl_Interp *interp) /* Interpreter for application. */
{
+ Tcl_CmdInfo info;
+
if (Tcl_InitStubs(interp, "8.5-", 0) == NULL) {
return TCL_ERROR;
}
+ if (Tcl_GetCommandInfo(interp, "::tcl::build-info", &info)) {
+ Tcl_CreateObjCommand(interp, "::tcl::test::build-info",
+ info.objProc, (void *)version, NULL);
+ }
+ if (Tcl_PkgProvideEx(interp, "tcl::test", TCL_PATCH_LEVEL, NULL) == TCL_ERROR) {
+ return TCL_ERROR;
+ }
return Procbodytest_SafeInit(interp);
}
@@ -759,7 +874,7 @@ TestasyncCmd(
asyncPtr->nextPtr = firstHandler;
firstHandler = asyncPtr;
Tcl_MutexUnlock(&asyncTestMutex);
- Tcl_SetObjResult(interp, Tcl_NewIntObj(asyncPtr->id));
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(asyncPtr->id));
} else if (strcmp(argv[1], "delete") == 0) {
if (argc == 2) {
Tcl_MutexLock(&asyncTestMutex);
@@ -815,7 +930,6 @@ TestasyncCmd(
Tcl_SetObjResult(interp, Tcl_NewStringObj(argv[3], -1));
Tcl_MutexUnlock(&asyncTestMutex);
return code;
-#if TCL_THREADS
} else if (strcmp(argv[1], "marklater") == 0) {
if (argc != 3) {
goto wrongNumArgs;
@@ -843,12 +957,6 @@ TestasyncCmd(
Tcl_AppendResult(interp, "bad option \"", argv[1],
"\": must be create, delete, int, mark, or marklater", NULL);
return TCL_ERROR;
-#else /* !TCL_THREADS */
- } else {
- Tcl_AppendResult(interp, "bad option \"", argv[1],
- "\": must be create, delete, int, or mark", NULL);
- return TCL_ERROR;
-#endif
}
return TCL_OK;
}
@@ -914,7 +1022,6 @@ AsyncHandlerProc(
*----------------------------------------------------------------------
*/
-#if TCL_THREADS
static Tcl_ThreadCreateType
AsyncThreadProc(
void *clientData) /* Parameter is the id of a
@@ -936,7 +1043,6 @@ AsyncThreadProc(
Tcl_ExitThread(TCL_OK);
TCL_THREAD_CREATE_RETURN;
}
-#endif
static int
TestbumpinterpepochObjCmd(
@@ -1031,9 +1137,9 @@ TestcmdinfoCmd(
info.deleteProc = CmdDelProc2;
info.deleteData = (void *) "new_delete_data";
if (Tcl_SetCommandInfo(interp, argv[2], &info) == 0) {
- Tcl_SetObjResult(interp, Tcl_NewIntObj(0));
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(0));
} else {
- Tcl_SetObjResult(interp, Tcl_NewIntObj(1));
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(1));
}
} else {
Tcl_AppendResult(interp, "bad option \"", argv[1],
@@ -1107,9 +1213,9 @@ TestcmdtokenCmd(
int argc, /* Number of arguments. */
const char **argv) /* Argument strings. */
{
- Tcl_Command token;
- int *l;
+ TestCommandTokenRef *refPtr;
char buf[30];
+ int id;
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
@@ -1117,24 +1223,42 @@ TestcmdtokenCmd(
return TCL_ERROR;
}
if (strcmp(argv[1], "create") == 0) {
- token = Tcl_CreateCommand(interp, argv[2], CmdProc1,
+ refPtr = (TestCommandTokenRef *)Tcl_Alloc(sizeof(TestCommandTokenRef));
+ refPtr->token = Tcl_CreateCommand(interp, argv[2], CmdProc1,
(void *) "original", NULL);
- sprintf(buf, "%p", (void *)token);
+ refPtr->id = nextCommandTokenRefId;
+ nextCommandTokenRefId++;
+ refPtr->nextPtr = firstCommandTokenRef;
+ firstCommandTokenRef = refPtr;
+ sprintf(buf, "%d", refPtr->id);
Tcl_AppendResult(interp, buf, NULL);
} else if (strcmp(argv[1], "name") == 0) {
Tcl_Obj *objPtr;
- if (sscanf(argv[2], "%p", &l) != 1) {
+ if (sscanf(argv[2], "%d", &id) != 1) {
+ Tcl_AppendResult(interp, "bad command token \"", argv[2],
+ "\"", NULL);
+ return TCL_ERROR;
+ }
+
+ for (refPtr = firstCommandTokenRef; refPtr != NULL;
+ refPtr = refPtr->nextPtr) {
+ if (refPtr->id == id) {
+ break;
+ }
+ }
+
+ if (refPtr == NULL) {
Tcl_AppendResult(interp, "bad command token \"", argv[2],
"\"", NULL);
return TCL_ERROR;
}
objPtr = Tcl_NewObj();
- Tcl_GetCommandFullName(interp, (Tcl_Command) l, objPtr);
+ Tcl_GetCommandFullName(interp, refPtr->token, objPtr);
Tcl_AppendElement(interp,
- Tcl_GetCommandName(interp, (Tcl_Command) l));
+ Tcl_GetCommandName(interp, refPtr->token));
Tcl_AppendElement(interp, Tcl_GetString(objPtr));
Tcl_DecrRefCount(objPtr);
} else {
@@ -1628,7 +1752,7 @@ TestdoubledigitsObjCmd(
int objc, /* Parameter count */
Tcl_Obj* const objv[]) /* Parameter vector */
{
- static const char* options[] = {
+ static const char *options[] = {
"shortest",
"e",
"f",
@@ -1647,8 +1771,8 @@ TestdoubledigitsObjCmd(
int type;
int decpt;
int signum;
- char* str;
- char* endPtr;
+ char *str;
+ char *endPtr;
Tcl_Obj* strObj;
Tcl_Obj* retval;
@@ -1659,8 +1783,8 @@ TestdoubledigitsObjCmd(
status = Tcl_GetDoubleFromObj(interp, objv[1], &d);
if (status != TCL_OK) {
doubleType = Tcl_GetObjType("double");
- if (Tcl_FetchIntRep(objv[1], doubleType)
- && TclIsNaN(objv[1]->internalRep.doubleValue)) {
+ if (Tcl_FetchInternalRep(objv[1], doubleType)
+ && isnan(objv[1]->internalRep.doubleValue)) {
status = TCL_OK;
memcpy(&d, &(objv[1]->internalRep.doubleValue), sizeof(double));
}
@@ -1684,7 +1808,7 @@ TestdoubledigitsObjCmd(
strObj = Tcl_NewStringObj(str, endPtr-str);
ckfree(str);
retval = Tcl_NewListObj(1, &strObj);
- Tcl_ListObjAppendElement(NULL, retval, Tcl_NewIntObj(decpt));
+ Tcl_ListObjAppendElement(NULL, retval, Tcl_NewWideIntObj(decpt));
strObj = Tcl_NewStringObj(signum ? "-" : "+", 1);
Tcl_ListObjAppendElement(NULL, retval, strObj);
Tcl_SetObjResult(interp, retval);
@@ -1763,7 +1887,7 @@ TestdstringCmd(
strcpy(s, "This is a malloc-ed string");
Tcl_SetResult(interp, s, TCL_DYNAMIC);
} else if (strcmp(argv[2], "special") == 0) {
- char *s = (char*)ckalloc(100) + 16;
+ char *s = (char *)ckalloc(100) + 16;
strcpy(s, "This is a specially-allocated string");
Tcl_SetResult(interp, s, SpecialFree);
} else {
@@ -1778,7 +1902,7 @@ TestdstringCmd(
if (argc != 2) {
goto wrongNumArgs;
}
- Tcl_SetObjResult(interp, Tcl_NewIntObj(Tcl_DStringLength(&dstring)));
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(Tcl_DStringLength(&dstring)));
} else if (strcmp(argv[1], "result") == 0) {
if (argc != 2) {
goto wrongNumArgs;
@@ -1896,7 +2020,7 @@ TestencodingObjCmd(
}
Tcl_FreeEncoding(encoding); /* Free returned reference */
Tcl_FreeEncoding(encoding); /* Free to match CREATE */
- TclFreeIntRep(objv[2]); /* Free the cached ref */
+ TclFreeInternalRep(objv[2]); /* Free the cached ref */
break;
}
return TCL_OK;
@@ -2103,7 +2227,7 @@ TesteventObjCmd(
"head", "tail", "mark", NULL
};
int posIndex; /* Index of the chosen position */
- static const Tcl_QueuePosition posNum[] = {
+ static const int posNum[] = {
/* Interpretation of the chosen position */
TCL_QUEUE_HEAD,
TCL_QUEUE_TAIL,
@@ -3303,6 +3427,158 @@ TestlinkarrayCmd(
/*
*----------------------------------------------------------------------
*
+ * TestlistrepCmd --
+ *
+ * This function is invoked to generate a list object with a specific
+ * internal representation.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+TestlistrepCmd(
+ TCL_UNUSED(void *),
+ Tcl_Interp *interp, /* Current interpreter. */
+ int objc, /* Number of arguments. */
+ Tcl_Obj *const objv[]) /* Argument objects. */
+{
+ /* Subcommands supported by this command */
+ const char* subcommands[] = {
+ "new",
+ "describe",
+ "config",
+ "validate",
+ NULL
+ };
+ enum {
+ LISTREP_NEW,
+ LISTREP_DESCRIBE,
+ LISTREP_CONFIG,
+ LISTREP_VALIDATE
+ } cmdIndex;
+ Tcl_Obj *resultObj = NULL;
+
+ if (objc < 2) {
+ Tcl_WrongNumArgs(interp, 1, objv, "command ?arg ...?");
+ return TCL_ERROR;
+ }
+ if (Tcl_GetIndexFromObj(
+ interp, objv[1], subcommands, "command", 0, &cmdIndex)
+ != TCL_OK) {
+ return TCL_ERROR;
+ }
+ switch (cmdIndex) {
+ case LISTREP_NEW:
+ if (objc < 3 || objc > 5) {
+ Tcl_WrongNumArgs(interp, 2, objv, "length ?leadSpace endSpace?");
+ return TCL_ERROR;
+ } else {
+ int length;
+ int leadSpace = 0;
+ int endSpace = 0;
+ if (Tcl_GetIntFromObj(interp, objv[2], &length) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (objc > 3) {
+ if (Tcl_GetIntFromObj(interp, objv[3], &leadSpace) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (objc > 4) {
+ if (Tcl_GetIntFromObj(interp, objv[4], &endSpace)
+ != TCL_OK) {
+ return TCL_ERROR;
+ }
+ }
+ }
+ resultObj = TclListTestObj(length, leadSpace, endSpace);
+ }
+ break;
+
+ case LISTREP_DESCRIBE:
+#define APPEND_FIELD(targetObj_, structPtr_, fld_) \
+ do { \
+ Tcl_ListObjAppendElement( \
+ interp, (targetObj_), Tcl_NewStringObj(#fld_, -1)); \
+ Tcl_ListObjAppendElement( \
+ interp, (targetObj_), Tcl_NewWideIntObj((structPtr_)->fld_)); \
+ } while (0)
+ if (objc != 3) {
+ Tcl_WrongNumArgs(interp, 2, objv, "object");
+ return TCL_ERROR;
+ } else {
+ Tcl_Obj **objs;
+ ListSizeT nobjs;
+ ListRep listRep;
+ Tcl_Obj *listRepObjs[4];
+
+ /* Force list representation */
+ if (Tcl_ListObjGetElements(interp, objv[2], &nobjs, &objs) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ ListObjGetRep(objv[2], &listRep);
+ listRepObjs[0] = Tcl_NewStringObj("store", -1);
+ listRepObjs[1] = Tcl_NewListObj(12, NULL);
+ Tcl_ListObjAppendElement(
+ interp, listRepObjs[1], Tcl_NewStringObj("memoryAddress", -1));
+ Tcl_ListObjAppendElement(
+ interp, listRepObjs[1], Tcl_ObjPrintf("%p", listRep.storePtr));
+ APPEND_FIELD(listRepObjs[1], listRep.storePtr, firstUsed);
+ APPEND_FIELD(listRepObjs[1], listRep.storePtr, numUsed);
+ APPEND_FIELD(listRepObjs[1], listRep.storePtr, numAllocated);
+ APPEND_FIELD(listRepObjs[1], listRep.storePtr, refCount);
+ APPEND_FIELD(listRepObjs[1], listRep.storePtr, flags);
+ if (listRep.spanPtr) {
+ listRepObjs[2] = Tcl_NewStringObj("span", -1);
+ listRepObjs[3] = Tcl_NewListObj(8, NULL);
+ Tcl_ListObjAppendElement(interp,
+ listRepObjs[3],
+ Tcl_NewStringObj("memoryAddress", -1));
+ Tcl_ListObjAppendElement(
+ interp, listRepObjs[3], Tcl_ObjPrintf("%p", listRep.spanPtr));
+ APPEND_FIELD(listRepObjs[3], listRep.spanPtr, spanStart);
+ APPEND_FIELD(
+ listRepObjs[3], listRep.spanPtr, spanLength);
+ APPEND_FIELD(listRepObjs[3], listRep.spanPtr, refCount);
+ }
+ resultObj = Tcl_NewListObj(listRep.spanPtr ? 4 : 2, listRepObjs);
+ }
+#undef APPEND_FIELD
+ break;
+
+ case LISTREP_CONFIG:
+ if (objc != 2) {
+ Tcl_WrongNumArgs(interp, 2, objv, "object");
+ return TCL_ERROR;
+ }
+ resultObj = Tcl_NewListObj(2, NULL);
+ Tcl_ListObjAppendElement(
+ NULL, resultObj, Tcl_NewStringObj("LIST_SPAN_THRESHOLD", -1));
+ Tcl_ListObjAppendElement(
+ NULL, resultObj, Tcl_NewWideIntObj(LIST_SPAN_THRESHOLD));
+ break;
+
+ case LISTREP_VALIDATE:
+ if (objc != 3) {
+ Tcl_WrongNumArgs(interp, 2, objv, "object");
+ return TCL_ERROR;
+ }
+ TclListObjValidate(interp, objv[2]); /* Panics if invalid */
+ resultObj = Tcl_NewObj();
+ break;
+ }
+ Tcl_SetObjResult(interp, resultObj);
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TestlocaleCmd --
*
* This procedure implements the "testlocale" command. It is used
@@ -3542,7 +3818,7 @@ PrintParse(
Tcl_ListObjAppendElement(NULL, objPtr,
Tcl_NewStringObj(parsePtr->commandStart, parsePtr->commandSize));
Tcl_ListObjAppendElement(NULL, objPtr,
- Tcl_NewIntObj(parsePtr->numWords));
+ Tcl_NewWideIntObj(parsePtr->numWords));
for (i = 0; i < parsePtr->numTokens; i++) {
tokenPtr = &parsePtr->tokenPtr[i];
switch (tokenPtr->type) {
@@ -3582,11 +3858,12 @@ PrintParse(
Tcl_ListObjAppendElement(NULL, objPtr,
Tcl_NewStringObj(tokenPtr->start, tokenPtr->size));
Tcl_ListObjAppendElement(NULL, objPtr,
- Tcl_NewIntObj(tokenPtr->numComponents));
+ Tcl_NewWideIntObj(tokenPtr->numComponents));
}
Tcl_ListObjAppendElement(NULL, objPtr,
+ parsePtr->commandStart ?
Tcl_NewStringObj(parsePtr->commandStart + parsePtr->commandSize,
- -1));
+ -1) : Tcl_NewObj());
}
/*
@@ -3897,7 +4174,7 @@ TestregexpObjCmd(
* value 0.
*/
- Tcl_SetIntObj(Tcl_GetObjResult(interp), 0);
+ Tcl_SetWideIntObj(Tcl_GetObjResult(interp), 0);
if (objc > 2 && (cflags&REG_EXPECT) && indices) {
const char *varName;
const char *value;
@@ -3976,7 +4253,7 @@ TestregexpObjCmd(
if (ii == -1) {
TclRegExpRangeUniChar(regExpr, ii, &start, &end);
newPtr = Tcl_GetRange(objPtr, start, end);
- } else if (ii > info.nsubs) {
+ } else if (ii > info.nsubs || info.matches[ii].end <= 0) {
newPtr = Tcl_NewObj();
} else {
newPtr = Tcl_GetRange(objPtr, info.matches[ii].start,
@@ -3993,7 +4270,7 @@ TestregexpObjCmd(
* Set the interpreter's object result to an integer object w/ value 1.
*/
- Tcl_SetIntObj(Tcl_GetObjResult(interp), 1);
+ Tcl_SetWideIntObj(Tcl_GetObjResult(interp), 1);
return TCL_OK;
}
@@ -4226,7 +4503,7 @@ TestsetplatformCmd(
* A standard Tcl result.
*
* Side effects:
- * When the packge given by argv[1] is loaded into an interpeter,
+ * When the packge given by argv[1] is loaded into an interpreter,
* variable "x" in that interpreter is set to "loaded".
*
*----------------------------------------------------------------------
@@ -5072,7 +5349,7 @@ TestbytestringObjCmd(
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* The argument objects. */
{
- int n = 0;
+ size_t n = 0;
const char *p;
if (objc != 2) {
@@ -5080,7 +5357,7 @@ TestbytestringObjCmd(
return TCL_ERROR;
}
- p = (const char *)TclGetBytesFromObj(interp, objv[1], &n);
+ p = (const char *)Tcl_GetBytesFromObj(interp, objv[1], &n);
if (p == NULL) {
return TCL_ERROR;
}
@@ -5091,6 +5368,43 @@ TestbytestringObjCmd(
/*
*----------------------------------------------------------------------
*
+ * Testutf16stringObjCmd --
+ *
+ * This specifically tests the Tcl_GetUnicode and Tcl_NewUnicodeObj
+ * C functions which broke in Tcl 8.7 and were undetected by the
+ * existing test suite. Bug [b79df322a9]
+ *
+ * Results:
+ * Returns the TCL_OK result code.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+Testutf16stringObjCmd(
+ TCL_UNUSED(void *),
+ Tcl_Interp *interp, /* Current interpreter. */
+ int objc, /* Number of arguments. */
+ Tcl_Obj *const objv[]) /* The argument objects. */
+{
+ const unsigned short *p;
+
+ if (objc != 2) {
+ Tcl_WrongNumArgs(interp, 1, objv, "string");
+ return TCL_ERROR;
+ }
+
+ p = Tcl_GetUnicode(objv[1]);
+ Tcl_SetObjResult(interp, Tcl_NewUnicodeObj(p, -1));
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TestsetCmd --
*
* Implements the "testset{err,noerr}" cmds that are used when testing
@@ -6210,7 +6524,7 @@ TestServiceModeCmd(
Tcl_SetServiceMode(TCL_SERVICE_ALL);
}
}
- Tcl_SetObjResult(interp, Tcl_NewIntObj(oldmode));
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(oldmode));
return TCL_OK;
}
@@ -6294,31 +6608,39 @@ TestGetIndexFromObjStructObjCmd(
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *const ary[] = {
- "a", "b", "c", "d", "e", "f", NULL, NULL
+ "a", "b", "c", "d", "ee", "ff", NULL, NULL
};
- int idx,target;
+ int target, flags = 0;
+ signed char idx[8];
- if (objc != 3) {
- Tcl_WrongNumArgs(interp, 1, objv, "argument targetvalue");
+ if (objc != 3 && objc != 4) {
+ Tcl_WrongNumArgs(interp, 1, objv, "argument targetvalue ?flags?");
+ return TCL_ERROR;
+ }
+ if (Tcl_GetIntFromObj(interp, objv[2], &target) != TCL_OK) {
return TCL_ERROR;
}
- if (Tcl_GetIndexFromObjStruct(interp, objv[1], ary, 2*sizeof(char *),
- "dummy", 0, &idx) != TCL_OK) {
+ if ((objc > 3) && (Tcl_GetIntFromObj(interp, objv[3], &flags) != TCL_OK)) {
return TCL_ERROR;
}
- if (Tcl_GetIntFromObj(interp, objv[2], &target) != TCL_OK) {
+ memset(idx, 85, sizeof(idx));
+ if (Tcl_GetIndexFromObjStruct(interp, (Tcl_GetString(objv[1])[0] ? objv[1] : NULL), ary, 2*sizeof(char *),
+ "dummy", flags, &idx[1]) != TCL_OK) {
return TCL_ERROR;
}
- if (idx != target) {
+ if (idx[0] != 85 || idx[2] != 85) {
+ Tcl_AppendResult(interp, "Tcl_GetIndexFromObjStruct overwrites bytes near index variable", NULL);
+ return TCL_ERROR;
+ } else if (idx[1] != target) {
char buffer[64];
- sprintf(buffer, "%d", idx);
+ sprintf(buffer, "%d", idx[1]);
Tcl_AppendResult(interp, "index value comparison failed: got ",
buffer, NULL);
sprintf(buffer, "%d", target);
Tcl_AppendResult(interp, " when ", buffer, " expected", NULL);
return TCL_ERROR;
}
- Tcl_WrongNumArgs(interp, 3, objv, NULL);
+ Tcl_WrongNumArgs(interp, objc, objv, NULL);
return TCL_OK;
}
@@ -6794,7 +7116,7 @@ SimpleMatchInDirectory(
origPtr = SimpleRedirect(dirPtr);
res = Tcl_FSMatchInDirectory(interp, resPtr, origPtr, pattern, types);
if (res == TCL_OK) {
- int gLength, j;
+ size_t gLength, j;
Tcl_ListObjLength(NULL, resPtr, &gLength);
for (j = 0; j < gLength; j++) {
Tcl_Obj *gElt, *nElt;
@@ -6893,10 +7215,10 @@ TestUtfNextCmd(
}
bytes = Tcl_GetStringFromObj(objv[1], &numBytes);
- if (numBytes > (int)sizeof(buffer) - 4) {
+ if (numBytes + 4U > sizeof(buffer)) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "\"testutfnext\" can only handle %d bytes",
- (int)sizeof(buffer) - 4));
+ "\"testutfnext\" can only handle %" TCL_Z_MODIFIER "u bytes",
+ sizeof(buffer) - 4));
return TCL_ERROR;
}
@@ -6924,7 +7246,7 @@ TestUtfNextCmd(
}
}
- Tcl_SetObjResult(interp, Tcl_NewIntObj(first - buffer - 1));
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(first - buffer - 1));
return TCL_OK;
}
@@ -6966,7 +7288,7 @@ TestUtfPrevCmd(
offset = numBytes;
}
result = Tcl_UtfPrev(bytes + offset, bytes);
- Tcl_SetObjResult(interp, Tcl_NewIntObj(result - bytes));
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(result - bytes));
return TCL_OK;
}
@@ -6994,7 +7316,7 @@ TestNumUtfCharsCmd(
}
}
len = Tcl_NumUtfChars(bytes, limit);
- Tcl_SetObjResult(interp, Tcl_NewIntObj(len));
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(len));
}
return TCL_OK;
}
@@ -7043,7 +7365,34 @@ TestFindLastCmd(
return TCL_OK;
}
-#if defined(HAVE_CPUID) || defined(_WIN32)
+static int
+TestGetIntForIndexCmd(
+ TCL_UNUSED(void *),
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *const objv[])
+{
+ int result;
+ Tcl_WideInt endvalue;
+
+ if (objc != 3) {
+ Tcl_WrongNumArgs(interp, 1, objv, "index endvalue");
+ return TCL_ERROR;
+ }
+
+ if (Tcl_GetWideIntFromObj(interp, objv[2], &endvalue) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (Tcl_GetIntForIndex(interp, objv[1], endvalue, &result) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(result));
+ return TCL_OK;
+}
+
+
+
+#if defined(HAVE_CPUID) && !defined(MAC_OSX_TCL)
/*
*----------------------------------------------------------------------
*
@@ -7092,7 +7441,7 @@ TestcpuidCmd(
return status;
}
for (i=0 ; i<4 ; ++i) {
- regsObjs[i] = Tcl_NewIntObj(regs[i]);
+ regsObjs[i] = Tcl_NewWideIntObj(regs[i]);
}
Tcl_SetObjResult(interp, Tcl_NewListObj(4, regsObjs));
return TCL_OK;
@@ -7133,7 +7482,7 @@ TestHashSystemHashCmd(
for (i=0 ; i<limit ; i++) {
hPtr = Tcl_CreateHashEntry(&hash, INT2PTR(i), &isNew);
if (!isNew) {
- Tcl_SetObjResult(interp, Tcl_NewIntObj(i));
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(i));
Tcl_AppendToObj(Tcl_GetObjResult(interp)," creation problem",-1);
Tcl_DeleteHashTable(&hash);
return TCL_ERROR;
@@ -7150,13 +7499,13 @@ TestHashSystemHashCmd(
for (i=0 ; i<limit ; i++) {
hPtr = Tcl_FindHashEntry(&hash, (char *) INT2PTR(i));
if (hPtr == NULL) {
- Tcl_SetObjResult(interp, Tcl_NewIntObj(i));
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(i));
Tcl_AppendToObj(Tcl_GetObjResult(interp)," lookup problem",-1);
Tcl_DeleteHashTable(&hash);
return TCL_ERROR;
}
if (PTR2INT(Tcl_GetHashValue(hPtr)) != i+42) {
- Tcl_SetObjResult(interp, Tcl_NewIntObj(i));
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(i));
Tcl_AppendToObj(Tcl_GetObjResult(interp)," value problem",-1);
Tcl_DeleteHashTable(&hash);
return TCL_ERROR;
@@ -7198,7 +7547,7 @@ TestgetintCmd(
}
total += val;
}
- Tcl_SetObjResult(interp, Tcl_NewIntObj(total));
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(total));
return TCL_OK;
}
}
@@ -7217,7 +7566,7 @@ TestlongsizeCmd(
Tcl_AppendResult(interp, "wrong # args", NULL);
return TCL_ERROR;
}
- Tcl_SetObjResult(interp, Tcl_NewIntObj((int)sizeof(long)));
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sizeof(long)));
return TCL_OK;
}
@@ -7240,9 +7589,9 @@ NREUnwind_callback(
&none, NULL);
} else {
Tcl_Obj *idata[3];
- idata[0] = Tcl_NewIntObj((int) ((char *) data[1] - (char *) data[0]));
- idata[1] = Tcl_NewIntObj((int) ((char *) data[2] - (char *) data[0]));
- idata[2] = Tcl_NewIntObj((int) ((char *) &none - (char *) data[0]));
+ idata[0] = Tcl_NewWideIntObj((int) ((char *) data[1] - (char *) data[0]));
+ idata[1] = Tcl_NewWideIntObj((int) ((char *) data[2] - (char *) data[0]));
+ idata[2] = Tcl_NewWideIntObj((int) ((char *) &none - (char *) data[0]));
Tcl_SetObjResult(interp, Tcl_NewListObj(3, idata));
}
return TCL_OK;
@@ -7286,18 +7635,18 @@ TestNRELevels(
depth = (refDepth - &depth);
- levels[0] = Tcl_NewIntObj(depth);
- levels[1] = Tcl_NewIntObj(iPtr->numLevels);
- levels[2] = Tcl_NewIntObj(iPtr->cmdFramePtr->level);
- levels[3] = Tcl_NewIntObj(iPtr->varFramePtr->level);
- levels[4] = Tcl_NewIntObj(iPtr->execEnvPtr->execStackPtr->tosPtr
+ levels[0] = Tcl_NewWideIntObj(depth);
+ levels[1] = Tcl_NewWideIntObj(iPtr->numLevels);
+ levels[2] = Tcl_NewWideIntObj(iPtr->cmdFramePtr->level);
+ levels[3] = Tcl_NewWideIntObj(iPtr->varFramePtr->level);
+ levels[4] = Tcl_NewWideIntObj(iPtr->execEnvPtr->execStackPtr->tosPtr
- iPtr->execEnvPtr->execStackPtr->stackWords);
while (cbPtr) {
i++;
cbPtr = cbPtr->nextPtr;
}
- levels[5] = Tcl_NewIntObj(i);
+ levels[5] = Tcl_NewWideIntObj(i);
Tcl_SetObjResult(interp, Tcl_NewListObj(6, levels));
return TCL_OK;
@@ -7330,7 +7679,8 @@ TestconcatobjCmd(
TCL_UNUSED(const char **) /*argv*/)
{
Tcl_Obj *list1Ptr, *list2Ptr, *emptyPtr, *concatPtr, *tmpPtr;
- int result = TCL_OK, len;
+ int result = TCL_OK;
+ size_t len;
Tcl_Obj *objv[3];
/*
@@ -7687,7 +8037,7 @@ TestparseargsCmd(
Tcl_Obj *const objv[]) /* Arguments. */
{
static int foo = 0;
- int count = objc;
+ size_t count = objc;
Tcl_Obj **remObjv, *result[3];
Tcl_ArgvInfo argTable[] = {
{TCL_ARGV_CONSTANT, "-bool", INT2PTR(1), &foo, "booltest", NULL},
@@ -7698,8 +8048,8 @@ TestparseargsCmd(
if (Tcl_ParseArgsObjv(interp, argTable, &count, objv, &remObjv)!=TCL_OK) {
return TCL_ERROR;
}
- result[0] = Tcl_NewIntObj(foo);
- result[1] = Tcl_NewIntObj(count);
+ result[0] = Tcl_NewWideIntObj(foo);
+ result[1] = Tcl_NewWideIntObj(count);
result[2] = Tcl_NewListObj(count, remObjv);
Tcl_SetObjResult(interp, Tcl_NewListObj(3, result));
ckfree(remObjv);
@@ -7960,7 +8310,85 @@ TestInterpResolverCmd(
}
return TCL_OK;
}
-
+
+/*
+ *------------------------------------------------------------------------
+ *
+ * TestApplyLambdaObjCmd --
+ *
+ * Implements the Tcl command testapplylambda. This tests the apply
+ * implementation handling of a lambda where the lambda has a list
+ * internal representation where the second element's internal
+ * representation is already a byte code object.
+ *
+ * Results:
+ * TCL_OK - Success. Caller should check result is 42
+ * TCL_ERROR - Error.
+ *
+ * Side effects:
+ * In the presence of the apply bug, may panic. Otherwise
+ * Interpreter result holds result or error message.
+ *
+ *------------------------------------------------------------------------
+ */
+int TestApplyLambdaObjCmd (
+ TCL_UNUSED(void*),
+ Tcl_Interp *interp, /* Current interpreter. */
+ TCL_UNUSED(int), /* objc. */
+ TCL_UNUSED(Tcl_Obj *const *)) /* objv. */
+{
+ Tcl_Obj *lambdaObjs[2];
+ Tcl_Obj *evalObjs[2];
+ Tcl_Obj *lambdaObj;
+ int result;
+
+ /* Create a lambda {{} {set a 42}} */
+ lambdaObjs[0] = Tcl_NewObj(); /* No parameters */
+ lambdaObjs[1] = Tcl_NewStringObj("set a 42", -1); /* Body */
+ lambdaObj = Tcl_NewListObj(2, lambdaObjs);
+ Tcl_IncrRefCount(lambdaObj);
+
+ /* Create the command "apply {{} {set a 42}" */
+ evalObjs[0] = Tcl_NewStringObj("apply", -1);
+ Tcl_IncrRefCount(evalObjs[0]);
+ /*
+ * NOTE: IMPORTANT TO EXHIBIT THE BUG. We duplicate the lambda because
+ * it will get shimmered to a Lambda internal representation but we
+ * want to hold on to our list representation.
+ */
+ evalObjs[1] = Tcl_DuplicateObj(lambdaObj);
+ Tcl_IncrRefCount(evalObjs[1]);
+
+ /* Evaluate it */
+ result = Tcl_EvalObjv(interp, 2, evalObjs, TCL_EVAL_GLOBAL);
+ if (result != TCL_OK) {
+ Tcl_DecrRefCount(evalObjs[0]);
+ Tcl_DecrRefCount(evalObjs[1]);
+ return result;
+ }
+ /*
+ * So far so good. At this point,
+ * - evalObjs[1] has an internal representation of Lambda
+ * - lambdaObj[1] ({set a 42}) has been shimmered to
+ * an internal representation of ByteCode.
+ */
+ Tcl_DecrRefCount(evalObjs[1]); /* Don't need this anymore */
+ /*
+ * The bug trigger. Repeating the command but:
+ * - we are calling apply with a lambda that is a list (as BEFORE),
+ * BUT
+ * - The body of the lambda (lambdaObjs[1]) ALREADY has internal
+ * representation of ByteCode and thus will not be compiled again
+ */
+ evalObjs[1] = lambdaObj; /* lambdaObj already has a ref count so
+ no need for IncrRef */
+ result = Tcl_EvalObjv(interp, 2, evalObjs, TCL_EVAL_GLOBAL);
+ Tcl_DecrRefCount(evalObjs[0]);
+ Tcl_DecrRefCount(lambdaObj);
+
+ return result;
+}
+
/*
* Local Variables:
* mode: c
@@ -7970,3 +8398,4 @@ TestInterpResolverCmd(
* indent-tabs-mode: nil
* End:
*/
+