Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | New function, TclDuplicatePureObj(), doesn't duplicate the string representation when duplicating an object, unless necessary. Remove TclListObjCopy() in favor of TclDuplicatePureObj(), allowing internal representation to change after the copy rather than before. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk | main |
Files: | files | file ages | folders |
SHA3-256: |
40af0258ecad67cd3ab9866485835093 |
User & Date: | pooryorick 2023-05-16 05:25:31.940 |
Original Comment: | New function, TclDuplicatePureObj(), doesn't duplicate the string representation when duplicating an object, unless necessary. Remove TclListCopy() in favor of TclDuplicatePureObj(), allowing internal representation to change after the copy rather than before. |
References
2023-05-17
| ||
15:55 | • Ticket [6022b9f946] Tk when built against Tcl 9.0 broken status still Open with 3 other changes artifact: 330b41de1f user: jan.nijtmans | |
15:22 | • New ticket [6022b9f946]. artifact: cb3a25bc39 user: jan.nijtmans | |
Context
2023-05-17
| ||
16:22 | Proposed fix for [6022b9f946]: Tk when built against Tcl 9.0 broken Closed-Leaf check-in: 47ae4a0262 user: jan.nijtmans tags: bug-6022b9f946 | |
2023-05-16
| ||
06:25 | Merge 8.7 check-in: 8e4d8a6053 user: jan.nijtmans tags: trunk, main | |
05:25 | New function, TclDuplicatePureObj(), doesn't duplicate the string representation when duplicating a... check-in: 40af0258ec user: pooryorick tags: trunk, main | |
2023-05-15
| ||
20:49 | Add Tcl_DecrRefCount() missing from [4b1a20629e]. check-in: 0785828c47 user: pooryorick tags: trunk, main | |
Changes
Changes to generic/tclBasic.c.
︙ | ︙ | |||
6148 6149 6150 6151 6152 6153 6154 | * both listPtr and objPtr. * * TODO: Create a test to demo this need, or eliminate it. * FIXME OPT: preserve just the internal rep? */ Tcl_IncrRefCount(objPtr); | | | 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 | * both listPtr and objPtr. * * TODO: Create a test to demo this need, or eliminate it. * FIXME OPT: preserve just the internal rep? */ Tcl_IncrRefCount(objPtr); listPtr = TclDuplicatePureObj(objPtr); Tcl_IncrRefCount(listPtr); if (word != INT_MIN) { /* * TIP #280 Structures for tracking lines. As we know that this is * dynamic execution we ignore the invoker, even if known. * |
︙ | ︙ |
Changes to generic/tclCmdAH.c.
︙ | ︙ | |||
2780 2781 2782 2783 2784 2785 2786 | /* * Break up the value lists and variable lists into elements. */ for (i=0 ; i<numLists ; i++) { /* List */ /* Variables */ | | | > > < < | 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 | /* * Break up the value lists and variable lists into elements. */ for (i=0 ; i<numLists ; i++) { /* List */ /* Variables */ statePtr->vCopyList[i] = TclDuplicatePureObj(objv[1+i*2]); result = TclListObjLengthM(interp, statePtr->vCopyList[i], &statePtr->varcList[i]); if (result != TCL_OK) { result = TCL_ERROR; goto done; } if (statePtr->varcList[i] < 1) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "%s varlist is empty", (statePtr->resultList != NULL ? "lmap" : "foreach"))); Tcl_SetErrorCode(interp, "TCL", "OPERATION", (statePtr->resultList != NULL ? "LMAP" : "FOREACH"), "NEEDVARS", NULL); |
︙ | ︙ | |||
2812 2813 2814 2815 2816 2817 2818 | result = TCL_ERROR; goto done; } /* Don't compute values here, wait until the last moment */ statePtr->argcList[i] = ABSTRACTLIST_PROC(statePtr->aCopyList[i], lengthProc)(statePtr->aCopyList[i]); } else { /* List values */ | | | > | < < | 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 | result = TCL_ERROR; goto done; } /* Don't compute values here, wait until the last moment */ statePtr->argcList[i] = ABSTRACTLIST_PROC(statePtr->aCopyList[i], lengthProc)(statePtr->aCopyList[i]); } else { /* List values */ statePtr->aCopyList[i] = TclDuplicatePureObj(objv[2+i*2]); result = TclListObjGetElementsM(interp, statePtr->aCopyList[i], &statePtr->argcList[i], &statePtr->argvList[i]); if (result != TCL_OK) { goto done; } } /* account for variable <> value mismatch */ j = statePtr->argcList[i] / statePtr->varcList[i]; if ((statePtr->argcList[i] % statePtr->varcList[i]) != 0) { j++; } if (j > statePtr->maxj) { |
︙ | ︙ |
Changes to generic/tclCmdIL.c.
︙ | ︙ | |||
2323 2324 2325 2326 2327 2328 2329 | int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { Tcl_Obj *listCopyPtr; Tcl_Obj **listObjv; /* The contents of the list. */ Tcl_Size listObjc; /* The length of the list. */ Tcl_Size origListObjc; /* Original length */ | | | | < | > > > | > | < | 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 | int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { Tcl_Obj *listCopyPtr; Tcl_Obj **listObjv; /* The contents of the list. */ Tcl_Size listObjc; /* The length of the list. */ Tcl_Size origListObjc; /* Original length */ int code; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "list ?varName ...?"); return TCL_ERROR; } listCopyPtr = TclDuplicatePureObj(objv[1]); Tcl_IncrRefCount(listCopyPtr); /* Important! fs */ code = TclListObjGetElementsM( interp, listCopyPtr, &listObjc, &listObjv); if (code != TCL_OK) { Tcl_DecrRefCount(listCopyPtr); return code; } origListObjc = listObjc; objc -= 2; objv += 2; while (code == TCL_OK && objc > 0 && listObjc > 0) { if (Tcl_ObjSetVar2(interp, *objv++, NULL, *listObjv++, TCL_LEAVE_ERR_MSG) == NULL) { |
︙ | ︙ | |||
2495 2496 2497 2498 2499 2500 2501 | /* * If the list object is unshared we can modify it directly. Otherwise we * create a copy to modify: this is "copy on write". */ listPtr = objv[1]; if (Tcl_IsShared(listPtr)) { | | | > > > | 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 | /* * If the list object is unshared we can modify it directly. Otherwise we * create a copy to modify: this is "copy on write". */ listPtr = objv[1]; if (Tcl_IsShared(listPtr)) { listPtr = TclDuplicatePureObj(listPtr); } if ((objc == 4) && (index == len)) { /* * Special case: insert one element at the end of the list. */ result = Tcl_ListObjAppendElement(NULL, listPtr, objv[3]); if (result != TCL_OK) { return result; } } else { if (TCL_OK != Tcl_ListObjReplace(interp, listPtr, index, 0, (objc-3), &(objv[3]))) { return TCL_ERROR; } } |
︙ | ︙ | |||
2682 2683 2684 2685 2686 2687 2688 | /* * Second, remove the element. * TclLsetFlat adds a ref count which is handled. */ if (objc == 2) { if (Tcl_IsShared(listPtr)) { | | | 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 | /* * Second, remove the element. * TclLsetFlat adds a ref count which is handled. */ if (objc == 2) { if (Tcl_IsShared(listPtr)) { listPtr = TclDuplicatePureObj(listPtr); } result = Tcl_ListObjReplace(interp, listPtr, listLen - 1, 1, 0, NULL); if (result != TCL_OK) { return result; } Tcl_IncrRefCount(listPtr); } else { |
︙ | ︙ | |||
2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 | Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { Tcl_Size i, idxc, prevIdx, first, num; Tcl_Size *idxv, listLen; Tcl_Obj *listObj; /* * Parse the arguments. */ if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "list ?index ...?"); | > | 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 | Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { Tcl_Size i, idxc, prevIdx, first, num; Tcl_Size *idxv, listLen; Tcl_Obj *listObj; int status = TCL_OK; /* * Parse the arguments. */ if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "list ?index ...?"); |
︙ | ︙ | |||
2837 2838 2839 2840 2841 2842 2843 | idxc = objc - 2; if (idxc == 0) { Tcl_SetObjResult(interp, listObj); return TCL_OK; } idxv = (Tcl_Size *)Tcl_Alloc((objc - 2) * sizeof(*idxv)); for (i = 2; i < objc; i++) { | | | < | > | | 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 | idxc = objc - 2; if (idxc == 0) { Tcl_SetObjResult(interp, listObj); return TCL_OK; } idxv = (Tcl_Size *)Tcl_Alloc((objc - 2) * sizeof(*idxv)); for (i = 2; i < objc; i++) { status = (TclGetIntForIndexM(interp, objv[i], /*endValue*/ listLen - 1, &idxv[i - 2]) != TCL_OK); if (status != TCL_OK) { goto done; } } /* * Sort the indices, large to small so that when we remove an index we * don't change the indices still to be processed. */ if (idxc > 1) { qsort(idxv, idxc, sizeof(*idxv), LremoveIndexCompare); } /* * Make our working copy, then do the actual removes piecemeal. */ if (Tcl_IsShared(listObj)) { listObj = TclDuplicatePureObj(listObj); } num = 0; first = listLen; for (i = 0, prevIdx = -1 ; i < idxc ; i++) { Tcl_Size idx = idxv[i]; /* |
︙ | ︙ | |||
2893 2894 2895 2896 2897 2898 2899 | first = idx; } else { /* * Note that this operation can't fail now; we know we have a list * and we're only ever contracting that list. */ | | > > > | > > | < > > > | | 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 | first = idx; } else { /* * Note that this operation can't fail now; we know we have a list * and we're only ever contracting that list. */ status = Tcl_ListObjReplace(interp, listObj, first, num, 0, NULL); if (status != TCL_OK) { goto done; } listLen -= num; num = 1; first = idx; } } if (num != 0) { status = Tcl_ListObjReplace(interp, listObj, first, num, 0, NULL); if (status != TCL_OK) { goto done; } } Tcl_SetObjResult(interp, listObj); done: Tcl_Free(idxv); return status; } /* *---------------------------------------------------------------------- * * Tcl_LrepeatObjCmd -- * |
︙ | ︙ | |||
3098 3099 3100 3101 3102 3103 3104 | /* * If the list object is unshared we can modify it directly, otherwise we * create a copy to modify: this is "copy on write". */ listPtr = objv[1]; if (Tcl_IsShared(listPtr)) { | | > | 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 | /* * If the list object is unshared we can modify it directly, otherwise we * create a copy to modify: this is "copy on write". */ listPtr = objv[1]; if (Tcl_IsShared(listPtr)) { listPtr = TclDuplicatePureObj(listPtr); } /* * Note that we call Tcl_ListObjReplace even when numToDelete == 0 and * objc == 4. In this case, the list value of listPtr is not changed (no * elements are removed or added), but by making the call we are assured * we end up with a list in canonical form. Resist any temptation to * optimize this case away. */ if (TCL_OK != Tcl_ListObjReplace(interp, listPtr, first, numToDelete, objc-4, objv+4)) { Tcl_DecrRefCount(listPtr); return TCL_ERROR; } /* * Set the interpreter's object result. */ |
︙ | ︙ | |||
4718 4719 4720 4721 4722 4723 4724 | /* * When sorting using a command, we are reentrant and therefore might * have the representation of the list being sorted shimmered out from * underneath our feet. Take a copy (cheap) to prevent this. [Bug * 1675116] */ | | < < | 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 | /* * When sorting using a command, we are reentrant and therefore might * have the representation of the list being sorted shimmered out from * underneath our feet. Take a copy (cheap) to prevent this. [Bug * 1675116] */ listObj = TclDuplicatePureObj(listObj); if (listObj == NULL) { sortInfo.resultCode = TCL_ERROR; goto done; } /* * The existing command is a list. We want to flatten it, append two * dummy arguments on the end, and replace these arguments later. */ newCommandPtr = Tcl_DuplicateObj(cmdPtr); TclNewObj(newObjPtr); Tcl_IncrRefCount(newCommandPtr); if (Tcl_ListObjAppendElement(interp, newCommandPtr, newObjPtr) != TCL_OK) { TclDecrRefCount(newCommandPtr); TclDecrRefCount(newObjPtr); sortInfo.resultCode = TCL_ERROR; goto done; } Tcl_ListObjAppendElement(interp, newCommandPtr, Tcl_NewObj()); sortInfo.compareCmdPtr = newCommandPtr; } |
︙ | ︙ | |||
5076 5077 5078 5079 5080 5081 5082 | if (first <= last) { numToDelete = last - first + 1; } else { numToDelete = 0; } if (Tcl_IsShared(listPtr)) { | | | 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 | if (first <= last) { numToDelete = last - first + 1; } else { numToDelete = 0; } if (Tcl_IsShared(listPtr)) { listPtr = TclDuplicatePureObj(listPtr); createdNewObj = 1; } else { createdNewObj = 0; } result = Tcl_ListObjReplace(interp, listPtr, first, numToDelete, objc - 4, objv + 4); |
︙ | ︙ |
Changes to generic/tclEnsemble.c.
︙ | ︙ | |||
1900 1901 1902 1903 1904 1905 1906 | * Will be freed by the dispatch engine. */ Tcl_Obj **copyObjv; Tcl_Size copyObjc, prefixObjc; TclListObjLengthM(NULL, prefixObj, &prefixObjc); if (objc == 2) { | | | 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 | * Will be freed by the dispatch engine. */ Tcl_Obj **copyObjv; Tcl_Size copyObjc, prefixObjc; TclListObjLengthM(NULL, prefixObj, &prefixObjc); if (objc == 2) { copyPtr = TclDuplicatePureObj(prefixObj); } else { copyPtr = Tcl_NewListObj(objc - 2 + prefixObjc, NULL); Tcl_ListObjAppendList(NULL, copyPtr, prefixObj); Tcl_ListObjReplace(NULL, copyPtr, LIST_MAX, 0, ensemblePtr->numParameters, objv + 1); Tcl_ListObjReplace(NULL, copyPtr, LIST_MAX, 0, objc - 2 - ensemblePtr->numParameters, |
︙ | ︙ |
Changes to generic/tclEvent.c.
︙ | ︙ | |||
228 229 230 231 232 233 234 | Tcl_Obj **prefixObjv, **tempObjv; /* * Note we copy the handler command prefix each pass through, so we do * support one handler setting another handler. */ | | | 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | Tcl_Obj **prefixObjv, **tempObjv; /* * Note we copy the handler command prefix each pass through, so we do * support one handler setting another handler. */ Tcl_Obj *copyObj = TclDuplicatePureObj(assocPtr->cmdPrefix); errPtr = assocPtr->firstBgPtr; TclListObjGetElementsM(NULL, copyObj, &prefixObjc, &prefixObjv); tempObjv = (Tcl_Obj**)Tcl_Alloc((prefixObjc+2) * sizeof(Tcl_Obj *)); memcpy(tempObjv, prefixObjv, prefixObjc*sizeof(Tcl_Obj *)); tempObjv[prefixObjc] = errPtr->errorMsg; |
︙ | ︙ |
Changes to generic/tclExecute.c.
︙ | ︙ | |||
6423 6424 6425 6426 6427 6428 6429 | listPtr = OBJ_AT_DEPTH(listTmpDepth); if (TclListObjLengthM(interp, listPtr, &listLen) != TCL_OK) { TRACE_APPEND(("ERROR converting list %" TCL_Z_MODIFIER "d, \"%s\": %s", i, O2S(listPtr), O2S(Tcl_GetObjResult(interp)))); goto gotError; } if (Tcl_IsShared(listPtr)) { | | | 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 | listPtr = OBJ_AT_DEPTH(listTmpDepth); if (TclListObjLengthM(interp, listPtr, &listLen) != TCL_OK) { TRACE_APPEND(("ERROR converting list %" TCL_Z_MODIFIER "d, \"%s\": %s", i, O2S(listPtr), O2S(Tcl_GetObjResult(interp)))); goto gotError; } if (Tcl_IsShared(listPtr)) { objPtr = TclDuplicatePureObj(listPtr); Tcl_IncrRefCount(objPtr); Tcl_DecrRefCount(listPtr); OBJ_AT_DEPTH(listTmpDepth) = objPtr; } iterTmp = (listLen + (numVars - 1))/numVars; if (iterTmp > iterMax) { iterMax = iterTmp; |
︙ | ︙ | |||
6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 | /* * If some list still has a remaining list element iterate one more * time. Assign to var the next element from its value list. */ if (iterNum < iterMax) { /* * Set the variables and jump back to run the body */ tmpPtr->internalRep.twoPtrValue.ptr1 =(void *)(iterNum + 1); listTmpDepth = numLists + 1; for (i = 0; i < numLists; i++) { varListPtr = infoPtr->varLists[i]; numVars = varListPtr->numVars; listPtr = OBJ_AT_DEPTH(listTmpDepth); | > > | > > > > | 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 | /* * If some list still has a remaining list element iterate one more * time. Assign to var the next element from its value list. */ if (iterNum < iterMax) { int status; /* * Set the variables and jump back to run the body */ tmpPtr->internalRep.twoPtrValue.ptr1 =(void *)(iterNum + 1); listTmpDepth = numLists + 1; for (i = 0; i < numLists; i++) { varListPtr = infoPtr->varLists[i]; numVars = varListPtr->numVars; listPtr = OBJ_AT_DEPTH(listTmpDepth); status = TclListObjGetElementsM( interp, listPtr, &listLen, &elements); if (status != TCL_OK) { goto gotError; } valIndex = (iterNum * numVars); for (j = 0; j < numVars; j++) { if (valIndex >= listLen) { TclNewObj(valuePtr); } else { valuePtr = elements[valIndex]; |
︙ | ︙ |
Changes to generic/tclIOGT.c.
︙ | ︙ | |||
375 376 377 378 379 380 381 | * interpreters. */ { Tcl_Obj *resObj; /* See below, switch (transmit). */ Tcl_Size resLen = 0; unsigned char *resBuf; Tcl_InterpState state = NULL; int res = TCL_OK; | | | > > > > > | 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 | * interpreters. */ { Tcl_Obj *resObj; /* See below, switch (transmit). */ Tcl_Size resLen = 0; unsigned char *resBuf; Tcl_InterpState state = NULL; int res = TCL_OK; Tcl_Obj *command = TclDuplicatePureObj(dataPtr->command); Tcl_Interp *eval = dataPtr->interp; Tcl_Preserve(eval); /* * Step 1, create the complete command to execute. Do this by appending * operation and buffer to operate upon to a copy of the callback * definition. We *cannot* create a list containing 3 objects and then use * 'Tcl_EvalObjv', because the command may contain additional prefixed * arguments. Feather's curried commands would come in handy here. */ if (preserve == P_PRESERVE) { state = Tcl_SaveInterpState(eval, res); } Tcl_IncrRefCount(command); res = Tcl_ListObjAppendElement(NULL, command, Tcl_NewStringObj((char *) op, -1)); if (res != TCL_OK) { Tcl_DecrRefCount(command); Tcl_Release(eval); return res; } /* * Use a byte-array to prevent the misinterpretation of binary data coming * through as Utf while at the tcl level. */ Tcl_ListObjAppendElement(NULL, command, Tcl_NewByteArrayObj(buf, bufLen)); |
︙ | ︙ |
Changes to generic/tclIORChan.c.
︙ | ︙ | |||
2255 2256 2257 2258 2259 2260 2261 | #if TCL_THREADS rcPtr->thread = Tcl_GetCurrentThread(); #endif rcPtr->mode = mode; rcPtr->interest = 0; /* Initially no interest registered */ /* ASSERT: cmdpfxObj is a Tcl List */ | | | 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 | #if TCL_THREADS rcPtr->thread = Tcl_GetCurrentThread(); #endif rcPtr->mode = mode; rcPtr->interest = 0; /* Initially no interest registered */ /* ASSERT: cmdpfxObj is a Tcl List */ rcPtr->cmd = TclDuplicatePureObj(cmdpfxObj); Tcl_IncrRefCount(rcPtr->cmd); rcPtr->methods = Tcl_NewListObj(METH_WRITE + 1, NULL); while (mn <= (int)METH_WRITE) { Tcl_ListObjAppendElement(NULL, rcPtr->methods, Tcl_NewStringObj(methodNames[mn++], -1)); } Tcl_IncrRefCount(rcPtr->methods); |
︙ | ︙ | |||
2392 2393 2394 2395 2396 2397 2398 | } /* * Insert method into the callback command, after the command prefix, * before the channel id. */ | | | 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 | } /* * Insert method into the callback command, after the command prefix, * before the channel id. */ cmd = TclDuplicatePureObj(rcPtr->cmd); Tcl_ListObjIndex(NULL, rcPtr->methods, method, &methObj); Tcl_ListObjAppendElement(NULL, cmd, methObj); Tcl_ListObjAppendElement(NULL, cmd, rcPtr->name); /* * Append the additional argument containing method specific details |
︙ | ︙ |
Changes to generic/tclInt.h.
︙ | ︙ | |||
3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 | Tcl_CmdDeleteProc *deleteProc); MODULE_SCOPE Tcl_Command TclCreateEnsembleInNs(Tcl_Interp *interp, const char *name, Tcl_Namespace *nameNamespacePtr, Tcl_Namespace *ensembleNamespacePtr, int flags); MODULE_SCOPE void TclDeleteNamespaceVars(Namespace *nsPtr); MODULE_SCOPE void TclDeleteNamespaceChildren(Namespace *nsPtr); MODULE_SCOPE Tcl_Size TclDictGetSize(Tcl_Obj *dictPtr); MODULE_SCOPE int TclFindDictElement(Tcl_Interp *interp, const char *dict, Tcl_Size dictLength, const char **elementPtr, const char **nextPtr, Tcl_Size *sizePtr, int *literalPtr); /* TIP #280 - Modified token based evaluation, with line information. */ MODULE_SCOPE int TclEvalEx(Tcl_Interp *interp, const char *script, Tcl_Size numBytes, int flags, Tcl_Size line, | > | 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 | Tcl_CmdDeleteProc *deleteProc); MODULE_SCOPE Tcl_Command TclCreateEnsembleInNs(Tcl_Interp *interp, const char *name, Tcl_Namespace *nameNamespacePtr, Tcl_Namespace *ensembleNamespacePtr, int flags); MODULE_SCOPE void TclDeleteNamespaceVars(Namespace *nsPtr); MODULE_SCOPE void TclDeleteNamespaceChildren(Namespace *nsPtr); MODULE_SCOPE Tcl_Size TclDictGetSize(Tcl_Obj *dictPtr); MODULE_SCOPE Tcl_Obj* TclDuplicatePureObj(Tcl_Obj * objPtr); MODULE_SCOPE int TclFindDictElement(Tcl_Interp *interp, const char *dict, Tcl_Size dictLength, const char **elementPtr, const char **nextPtr, Tcl_Size *sizePtr, int *literalPtr); /* TIP #280 - Modified token based evaluation, with line information. */ MODULE_SCOPE int TclEvalEx(Tcl_Interp *interp, const char *script, Tcl_Size numBytes, int flags, Tcl_Size line, |
︙ | ︙ | |||
3245 3246 3247 3248 3249 3250 3251 | Tcl_Size indexCount, Tcl_Obj *const indexArray[]); MODULE_SCOPE Tcl_Obj * TclListObjGetElement(Tcl_Obj *listObj, Tcl_Size index); /* TIP #280 */ MODULE_SCOPE void TclListLines(Tcl_Obj *listObj, Tcl_Size line, int n, int *lines, Tcl_Obj *const *elems); | < | 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 | Tcl_Size indexCount, Tcl_Obj *const indexArray[]); MODULE_SCOPE Tcl_Obj * TclListObjGetElement(Tcl_Obj *listObj, Tcl_Size index); /* TIP #280 */ MODULE_SCOPE void TclListLines(Tcl_Obj *listObj, Tcl_Size line, int n, int *lines, Tcl_Obj *const *elems); MODULE_SCOPE int TclListObjAppendElements(Tcl_Interp *interp, Tcl_Obj *toObj, Tcl_Size elemCount, Tcl_Obj *const elemObjv[]); MODULE_SCOPE Tcl_Obj * TclListObjRange(Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Size fromIdx, Tcl_Size toIdx); MODULE_SCOPE Tcl_Obj * TclLsetList(Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *indexPtr, Tcl_Obj *valuePtr); |
︙ | ︙ |
Changes to generic/tclListObj.c.
︙ | ︙ | |||
1350 1351 1352 1353 1354 1355 1356 | ListObjReplaceRepAndInvalidate(objPtr, &listRep); } else { TclFreeInternalRep(objPtr); TclInvalidateStringRep(objPtr); Tcl_InitStringRep(objPtr, NULL, 0); } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 | ListObjReplaceRepAndInvalidate(objPtr, &listRep); } else { TclFreeInternalRep(objPtr); TclInvalidateStringRep(objPtr); Tcl_InitStringRep(objPtr, NULL, 0); } } /* *------------------------------------------------------------------------ * * ListRepRange -- * * Initializes a ListRep as a range within the passed ListRep. |
︙ | ︙ | |||
2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 | Tcl_Obj *listObj, /* List being unpacked. */ Tcl_Obj *argObj) /* Index or index list. */ { Tcl_Size index; /* Index into the list. */ Tcl_Obj *indexListCopy; Tcl_Obj **indexObjs; Tcl_Size numIndexObjs; /* * Determine whether argPtr designates a list or a single index. We have * to be careful about the order of the checks to avoid repeated * shimmering; if internal rep is already a list do not shimmer it. * see TIP#22 and TIP#33 for the details. */ | > | 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 | Tcl_Obj *listObj, /* List being unpacked. */ Tcl_Obj *argObj) /* Index or index list. */ { Tcl_Size index; /* Index into the list. */ Tcl_Obj *indexListCopy; Tcl_Obj **indexObjs; Tcl_Size numIndexObjs; int status; /* * Determine whether argPtr designates a list or a single index. We have * to be careful about the order of the checks to avoid repeated * shimmering; if internal rep is already a list do not shimmer it. * see TIP#22 and TIP#33 for the details. */ |
︙ | ︙ | |||
2626 2627 2628 2629 2630 2631 2632 | * to show any error when this private copy is not made. But it's cheap, * and it offers some future-proofing insurance in case the TclLindexFlat * implementation changes in some unexpected way, or some new form of * trace or callback permits things to happen that the current * implementation does not. */ | | > > > | < < | 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 | * to show any error when this private copy is not made. But it's cheap, * and it offers some future-proofing insurance in case the TclLindexFlat * implementation changes in some unexpected way, or some new form of * trace or callback permits things to happen that the current * implementation does not. */ indexListCopy = Tcl_DuplicateObj(argObj); status = TclListObjGetElementsM( interp, indexListCopy, &numIndexObjs, &indexObjs); if (status != TCL_OK) { Tcl_DecrRefCount(indexListCopy); /* * The argument is neither an index nor a well-formed list. * Report the error via TclLindexFlat. * TODO - This is as original code. why not directly return an error? */ return TclLindexFlat(interp, listObj, 1, &argObj); } listObj = TclLindexFlat(interp, listObj, numIndexObjs, indexObjs); Tcl_DecrRefCount(indexListCopy); return listObj; } /* *---------------------------------------------------------------------- |
︙ | ︙ | |||
2817 2818 2819 2820 2821 2822 2823 | && TclGetIntForIndexM(NULL, indexArgObj, TCL_SIZE_MAX - 1, &index) == TCL_OK) { /* indexArgPtr designates a single index. */ /* T:listrep-1.{2.1,12.1,15.1,19.1},2.{2.3,9.3,10.1,13.1,16.1}, 3.{4,5,6}.3 */ return TclLsetFlat(interp, listObj, 1, &indexArgObj, valueObj); } | | > > | < < < | 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 | && TclGetIntForIndexM(NULL, indexArgObj, TCL_SIZE_MAX - 1, &index) == TCL_OK) { /* indexArgPtr designates a single index. */ /* T:listrep-1.{2.1,12.1,15.1,19.1},2.{2.3,9.3,10.1,13.1,16.1}, 3.{4,5,6}.3 */ return TclLsetFlat(interp, listObj, 1, &indexArgObj, valueObj); } indexListCopy = TclDuplicatePureObj(indexArgObj); if (TCL_OK != TclListObjGetElementsM( interp, indexListCopy, &indexCount, &indices)) { Tcl_DecrRefCount(indexListCopy); /* * indexArgPtr designates something that is neither an index nor a * well formed list. Report the error via TclLsetFlat. */ return TclLsetFlat(interp, listObj, 1, &indexArgObj, valueObj); } /* * Let TclLsetFlat perform the actual lset operation. */ retValueObj = TclLsetFlat(interp, listObj, indexCount, indices, valueObj); Tcl_DecrRefCount(indexListCopy); return retValueObj; } /* *---------------------------------------------------------------------- * |
︙ | ︙ | |||
2905 2906 2907 2908 2909 2910 2911 | Tcl_IncrRefCount(valueObj); } return valueObj; } /* * If the list is shared, make a copy we can modify (copy-on-write). We | < | 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 | Tcl_IncrRefCount(valueObj); } return valueObj; } /* * If the list is shared, make a copy we can modify (copy-on-write). We * 1) we have not yet confirmed listObj is actually a list; 2) We make a * verbatim copy of any existing string rep, and when we combine that with * the delayed invalidation of string reps of modified Tcl_Obj's * implemented below, the outcome is that any error condition that causes * this routine to return NULL, will leave the string rep of listObj and * all elements to be unchanged. */ |
︙ | ︙ |
Changes to generic/tclObj.c.
︙ | ︙ | |||
198 199 200 201 202 203 204 205 206 207 208 209 210 211 | static void UpdateStringOfDouble(Tcl_Obj *objPtr); static void UpdateStringOfInt(Tcl_Obj *objPtr); static void FreeBignum(Tcl_Obj *objPtr); static void DupBignum(Tcl_Obj *objPtr, Tcl_Obj *copyPtr); static void UpdateStringOfBignum(Tcl_Obj *objPtr); static int GetBignumFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int copy, mp_int *bignumValue); /* * Prototypes for the array hash key methods. */ static Tcl_HashEntry * AllocObjEntry(Tcl_HashTable *tablePtr, void *keyPtr); | > | 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | static void UpdateStringOfDouble(Tcl_Obj *objPtr); static void UpdateStringOfInt(Tcl_Obj *objPtr); static void FreeBignum(Tcl_Obj *objPtr); static void DupBignum(Tcl_Obj *objPtr, Tcl_Obj *copyPtr); static void UpdateStringOfBignum(Tcl_Obj *objPtr); static int GetBignumFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int copy, mp_int *bignumValue); static void SetDuplicatePureObj(Tcl_Obj *dupPtr, Tcl_Obj *objPtr); /* * Prototypes for the array hash key methods. */ static Tcl_HashEntry * AllocObjEntry(Tcl_HashTable *tablePtr, void *keyPtr); |
︙ | ︙ | |||
1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 | /* *---------------------------------------------------------------------- * * Tcl_DuplicateObj -- * * Create and return a new object that is a duplicate of the argument * object. * * Results: * The return value is a pointer to a newly created Tcl_Obj. This object * has reference count 0 and the same type, if any, as the source object * objPtr. Also: * 1) If the source object has a valid string rep, we copy it; * otherwise, the duplicate's string rep is set NULL to mark it | > > > > > > > | 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 | /* *---------------------------------------------------------------------- * * Tcl_DuplicateObj -- * * Create and return a new object that is a duplicate of the argument * object. * * Tcl_DuplicatePureObj -- * Like Tcl_DuplicateObj, except that it does not duplicate the 'bytes' * field unless it is necessary, i.e. the duplicated Tcl_Obj provides no * updateStringProc. This can avoid an expensive memory allocation since * the data in the 'bytes' field of each Tcl_Obj must reside in allocated * memory. * * Results: * The return value is a pointer to a newly created Tcl_Obj. This object * has reference count 0 and the same type, if any, as the source object * objPtr. Also: * 1) If the source object has a valid string rep, we copy it; * otherwise, the duplicate's string rep is set NULL to mark it |
︙ | ︙ | |||
1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 | typePtr->dupIntRepProc((objPtr), (dupPtr)); \ } else { \ (dupPtr)->internalRep = (objPtr)->internalRep; \ (dupPtr)->typePtr = typePtr; \ } \ } \ } Tcl_Obj * Tcl_DuplicateObj( Tcl_Obj *objPtr) /* The object to duplicate. */ { Tcl_Obj *dupPtr; TclNewObj(dupPtr); SetDuplicateObj(dupPtr, objPtr); return dupPtr; } void TclSetDuplicateObj( Tcl_Obj *dupPtr, Tcl_Obj *objPtr) { if (Tcl_IsShared(dupPtr)) { | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 | typePtr->dupIntRepProc((objPtr), (dupPtr)); \ } else { \ (dupPtr)->internalRep = (objPtr)->internalRep; \ (dupPtr)->typePtr = typePtr; \ } \ } \ } void SetDuplicatePureObj(Tcl_Obj *dupPtr, Tcl_Obj *objPtr) { const Tcl_ObjType *typePtr = objPtr->typePtr; const char *bytes = objPtr->bytes; /* Unfortunately, it is not documented that dupIntRepProc() must assign * null to Tcl_Obj.typePtr if it does not assign any other value, so it * must be done here. Maybe in the future it can be documented, and this * assignment deleted */ dupPtr->typePtr = NULL; if (typePtr) { if (typePtr->dupIntRepProc) { typePtr->dupIntRepProc(objPtr, dupPtr); } else { dupPtr->internalRep = objPtr->internalRep; dupPtr->typePtr = typePtr; } if (bytes && ( dupPtr->typePtr == NULL || dupPtr->typePtr->updateStringProc == NULL) ) { TclInitStringRep(dupPtr, bytes, objPtr->length); } else { dupPtr->bytes = NULL; } } else if (bytes) { TclInitStringRep(dupPtr, bytes, objPtr->length); } return; } Tcl_Obj * Tcl_DuplicateObj( Tcl_Obj *objPtr) /* The object to duplicate. */ { Tcl_Obj *dupPtr; TclNewObj(dupPtr); SetDuplicateObj(dupPtr, objPtr); return dupPtr; } Tcl_Obj * TclDuplicatePureObj( Tcl_Obj *objPtr) /* The object to duplicate. */ { Tcl_Obj *dupPtr; TclNewObj(dupPtr); SetDuplicatePureObj(dupPtr, objPtr); return dupPtr; } void TclSetDuplicateObj( Tcl_Obj *dupPtr, Tcl_Obj *objPtr) { if (Tcl_IsShared(dupPtr)) { |
︙ | ︙ |
Changes to generic/tclStringObj.c.
︙ | ︙ | |||
4317 4318 4319 4320 4321 4322 4323 | if (srcStringPtr->numChars == TCL_INDEX_NONE) { /* * The String struct in the source value holds zero useful data. Don't * bother copying it. Don't even bother allocating space in which to * copy it. Just let the copy be untyped. */ | < | 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 | if (srcStringPtr->numChars == TCL_INDEX_NONE) { /* * The String struct in the source value holds zero useful data. Don't * bother copying it. Don't even bother allocating space in which to * copy it. Just let the copy be untyped. */ return; } if (srcStringPtr->hasUnicode) { int copyMaxChars; if (srcStringPtr->maxChars / 2 >= srcStringPtr->numChars) { |
︙ | ︙ |
Changes to generic/tclUtil.c.
︙ | ︙ | |||
2000 2001 2002 2003 2004 2005 2006 | if (Tcl_GetString(elemPtr)[0] == '#' || TCL_OK != Tcl_ListObjAppendList(NULL, resPtr, objPtr)) { /* Abandon ship! */ Tcl_DecrRefCount(resPtr); goto slow; } } else { | | | 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 | if (Tcl_GetString(elemPtr)[0] == '#' || TCL_OK != Tcl_ListObjAppendList(NULL, resPtr, objPtr)) { /* Abandon ship! */ Tcl_DecrRefCount(resPtr); goto slow; } } else { resPtr = TclDuplicatePureObj(objPtr); } } if (!resPtr) { TclNewObj(resPtr); } return resPtr; } |
︙ | ︙ |
Changes to generic/tclVar.c.
︙ | ︙ | |||
3093 3094 3095 3096 3097 3098 3099 | ArrayPopulateSearch(interp, arrayNameObj, varPtr, searchPtr); /* * Make sure that these objects (which we need throughout the body of the * loop) don't vanish. */ | | | 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 | ArrayPopulateSearch(interp, arrayNameObj, varPtr, searchPtr); /* * Make sure that these objects (which we need throughout the body of the * loop) don't vanish. */ varListObj = TclDuplicatePureObj(objv[1]); scriptObj = objv[3]; Tcl_IncrRefCount(scriptObj); /* * Run the script. */ |
︙ | ︙ | |||
3172 3173 3174 3175 3176 3177 3178 | Tcl_SetErrorCode(interp, "TCL", "READ", "array", "for", NULL); varPtr->flags |= TCL_LEAVE_ERR_MSG; result = done; } goto arrayfordone; } | | > > > | 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 | Tcl_SetErrorCode(interp, "TCL", "READ", "array", "for", NULL); varPtr->flags |= TCL_LEAVE_ERR_MSG; result = done; } goto arrayfordone; } result = TclListObjGetElementsM(NULL, varListObj, &varc, &varv); if (result != TCL_OK) { goto arrayfordone; } if (Tcl_ObjSetVar2(interp, varv[0], NULL, keyObj, TCL_LEAVE_ERR_MSG) == NULL) { result = TCL_ERROR; goto arrayfordone; } if (valueObj != NULL) { if (Tcl_ObjSetVar2(interp, varv[1], NULL, valueObj, |
︙ | ︙ | |||
4063 4064 4065 4066 4067 4068 4069 | /* * We needn't worry about traces invalidating arrayPtr: should that be * the case, TclPtrSetVarIdx will return NULL so that we break out of * the loop and return an error. */ | | | 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 | /* * We needn't worry about traces invalidating arrayPtr: should that be * the case, TclPtrSetVarIdx will return NULL so that we break out of * the loop and return an error. */ copyListObj = TclDuplicatePureObj(arrayElemObj); for (i=0 ; i<elemLen ; i+=2) { Var *elemVarPtr = TclLookupArrayElement(interp, arrayNameObj, elemPtrs[i], TCL_LEAVE_ERR_MSG, "set", 1, 1, varPtr, -1); if ((elemVarPtr == NULL) || (TclPtrSetVarIdx(interp, elemVarPtr, varPtr, arrayNameObj, elemPtrs[i], elemPtrs[i+1], TCL_LEAVE_ERR_MSG, |
︙ | ︙ |