Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | [1b0266d8bb] Make [dict replace] and [dict remove] have canonicalization semantics close to [lrange] and [lreplace]. [dict merge] is also improved, but is not as strict. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk | potential incompatibility |
Files: | files | file ages | folders |
SHA1: |
847fa2261d016aac0c70ea1c39075827 |
User & Date: | dkf 2014-06-15 16:14:18 |
Context
2014-06-15
| ||
16:50 | [cb042d294e] Improve consistency of [dict] wrong-args error messages. check-in: 968e9ac311 user: dkf tags: trunk | |
16:14 | [1b0266d8bb] Make [dict replace] and [dict remove] have canonicalization semantics close to [lrange]... check-in: 847fa2261d user: dkf tags: trunk, potential incompatibility | |
16:11 | Some more cleaning up Closed-Leaf check-in: fd9995590d user: dkf tags: bug-1b0266d8bb | |
2014-06-05
| ||
19:13 | Tests socket*-2.12 test for DiscardOutput() updates. check-in: 39da5e7464 user: dgp tags: trunk | |
Changes
Changes to generic/tclDictObj.c.
︙ | ︙ | |||
150 151 152 153 154 155 156 157 158 159 160 161 162 163 | int epoch; /* Epoch counter */ int refcount; /* Reference counter (see above) */ Tcl_Obj *chain; /* Linked list used for invalidating the * string representations of updated nested * dictionaries. */ } Dict; /* * The structure below defines the dictionary object type by means of * functions that can be invoked by generic object code. */ const Tcl_ObjType tclDictType = { "dict", | > > > > > > > | 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | int epoch; /* Epoch counter */ int refcount; /* Reference counter (see above) */ Tcl_Obj *chain; /* Linked list used for invalidating the * string representations of updated nested * dictionaries. */ } Dict; /* * Accessor macro for converting between a Tcl_Obj* and a Dict. Note that this * must be assignable as well as readable. */ #define DICT(dictObj) (*((Dict **)&(dictObj)->internalRep.twoPtrValue.ptr1)) /* * The structure below defines the dictionary object type by means of * functions that can be invoked by generic object code. */ const Tcl_ObjType tclDictType = { "dict", |
︙ | ︙ | |||
308 309 310 311 312 313 314 315 316 317 318 319 320 321 | ChainEntry *cPtr = (ChainEntry *) Tcl_FindHashEntry(&dict->table, keyPtr); if (cPtr == NULL) { return 0; } else { Tcl_Obj *valuePtr = Tcl_GetHashValue(&cPtr->entry); TclDecrRefCount(valuePtr); } /* * Unstitch from the chain. */ | > | 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | ChainEntry *cPtr = (ChainEntry *) Tcl_FindHashEntry(&dict->table, keyPtr); if (cPtr == NULL) { return 0; } else { Tcl_Obj *valuePtr = Tcl_GetHashValue(&cPtr->entry); TclDecrRefCount(valuePtr); } /* * Unstitch from the chain. */ |
︙ | ︙ | |||
357 358 359 360 361 362 363 | */ static void DupDictInternalRep( Tcl_Obj *srcPtr, Tcl_Obj *copyPtr) { | | | 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 | */ static void DupDictInternalRep( Tcl_Obj *srcPtr, Tcl_Obj *copyPtr) { Dict *oldDict = DICT(srcPtr); Dict *newDict = ckalloc(sizeof(Dict)); ChainEntry *cPtr; /* * Copy values across from the old hash table. */ |
︙ | ︙ | |||
392 393 394 395 396 397 398 | newDict->chain = NULL; newDict->refcount = 1; /* * Store in the object. */ | | | 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 | newDict->chain = NULL; newDict->refcount = 1; /* * Store in the object. */ DICT(copyPtr) = newDict; copyPtr->typePtr = &tclDictType; } /* *---------------------------------------------------------------------- * * FreeDictInternalRep -- |
︙ | ︙ | |||
418 419 420 421 422 423 424 | *---------------------------------------------------------------------- */ static void FreeDictInternalRep( Tcl_Obj *dictPtr) { | | | 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 | *---------------------------------------------------------------------- */ static void FreeDictInternalRep( Tcl_Obj *dictPtr) { Dict *dict = DICT(dictPtr); dict->refcount--; if (dict->refcount <= 0) { DeleteDict(dict); } dictPtr->typePtr = NULL; } |
︙ | ︙ | |||
483 484 485 486 487 488 489 | static void UpdateStringOfDict( Tcl_Obj *dictPtr) { #define LOCAL_SIZE 20 int localFlags[LOCAL_SIZE], *flagPtr = NULL; | | | 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 | static void UpdateStringOfDict( Tcl_Obj *dictPtr) { #define LOCAL_SIZE 20 int localFlags[LOCAL_SIZE], *flagPtr = NULL; Dict *dict = DICT(dictPtr); ChainEntry *cPtr; Tcl_Obj *keyPtr, *valuePtr; int i, length, bytesNeeded = 0; const char *elem; char *dst; const int maxFlags = UINT_MAX / sizeof(int); |
︙ | ︙ | |||
596 597 598 599 600 601 602 | static int SetDictFromAny( Tcl_Interp *interp, Tcl_Obj *objPtr) { Tcl_HashEntry *hPtr; | | | 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 | static int SetDictFromAny( Tcl_Interp *interp, Tcl_Obj *objPtr) { Tcl_HashEntry *hPtr; int isNew; Dict *dict = ckalloc(sizeof(Dict)); InitChainTable(dict); /* * Since lists and dictionaries have very closely-related string * representations (i.e. the same parsing code) we can safely special-case |
︙ | ︙ | |||
647 648 649 650 651 652 653 | const char *limit = (nextElem + length); while (nextElem < limit) { Tcl_Obj *keyPtr, *valuePtr; const char *elemStart; int elemSize, literal; | | | < | | | < | | 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 | const char *limit = (nextElem + length); while (nextElem < limit) { Tcl_Obj *keyPtr, *valuePtr; const char *elemStart; int elemSize, literal; if (TclFindDictElement(interp, nextElem, (limit - nextElem), &elemStart, &nextElem, &elemSize, &literal) != TCL_OK) { goto errorInFindDictElement; } if (elemStart == limit) { break; } if (nextElem == limit) { goto missingValue; } if (literal) { TclNewStringObj(keyPtr, elemStart, elemSize); } else { /* Avoid double copy */ TclNewObj(keyPtr); keyPtr->bytes = ckalloc((unsigned) elemSize + 1); keyPtr->length = TclCopyAndCollapse(elemSize, elemStart, keyPtr->bytes); } if (TclFindDictElement(interp, nextElem, (limit - nextElem), &elemStart, &nextElem, &elemSize, &literal) != TCL_OK) { TclDecrRefCount(keyPtr); goto errorInFindDictElement; } if (literal) { TclNewStringObj(valuePtr, elemStart, elemSize); } else { /* Avoid double copy */ TclNewObj(valuePtr); |
︙ | ︙ | |||
709 710 711 712 713 714 715 | * Tcl_GetStringFromObj, to use that old internalRep. */ TclFreeIntRep(objPtr); dict->epoch = 0; dict->chain = NULL; dict->refcount = 1; | | < | < < < < | | 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 | * Tcl_GetStringFromObj, to use that old internalRep. */ TclFreeIntRep(objPtr); dict->epoch = 0; dict->chain = NULL; dict->refcount = 1; DICT(objPtr) = dict; objPtr->typePtr = &tclDictType; return TCL_OK; missingValue: if (interp != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "missing value to go with key", -1)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "DICTIONARY", NULL); } errorInFindDictElement: DeleteChainTable(dict); ckfree(dict); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TclTraceDictPath -- * |
︙ | ︙ | |||
773 774 775 776 777 778 779 | int keyc, Tcl_Obj *const keyv[], int flags) { Dict *dict, *newDict; int i; | | | | | < | | 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 | int keyc, Tcl_Obj *const keyv[], int flags) { Dict *dict, *newDict; int i; if (dictPtr->typePtr != &tclDictType && SetDictFromAny(interp, dictPtr) != TCL_OK) { return NULL; } dict = DICT(dictPtr); if (flags & DICT_PATH_UPDATE) { dict->chain = NULL; } for (i=0 ; i<keyc ; i++) { Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&dict->table, keyv[i]); Tcl_Obj *tmpObj; |
︙ | ︙ | |||
814 815 816 817 818 819 820 | hPtr = CreateChainEntry(dict, keyv[i], &isNew); tmpObj = Tcl_NewDictObj(); Tcl_IncrRefCount(tmpObj); Tcl_SetHashValue(hPtr, tmpObj); } else { tmpObj = Tcl_GetHashValue(hPtr); | | | | < | | | 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 | hPtr = CreateChainEntry(dict, keyv[i], &isNew); tmpObj = Tcl_NewDictObj(); Tcl_IncrRefCount(tmpObj); Tcl_SetHashValue(hPtr, tmpObj); } else { tmpObj = Tcl_GetHashValue(hPtr); if (tmpObj->typePtr != &tclDictType && SetDictFromAny(interp, tmpObj) != TCL_OK) { return NULL; } } newDict = DICT(tmpObj); if (flags & DICT_PATH_UPDATE) { if (Tcl_IsShared(tmpObj)) { TclDecrRefCount(tmpObj); tmpObj = Tcl_DuplicateObj(tmpObj); Tcl_IncrRefCount(tmpObj); Tcl_SetHashValue(hPtr, tmpObj); dict->epoch++; newDict = DICT(tmpObj); } newDict->chain = dictPtr; } dict = newDict; dictPtr = tmpObj; } |
︙ | ︙ | |||
864 865 866 867 868 869 870 | *---------------------------------------------------------------------- */ static void InvalidateDictChain( Tcl_Obj *dictObj) { | | | | 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 | *---------------------------------------------------------------------- */ static void InvalidateDictChain( Tcl_Obj *dictObj) { Dict *dict = DICT(dictObj); do { TclInvalidateStringRep(dictObj); dict->epoch++; dictObj = dict->chain; if (dictObj == NULL) { break; } dict->chain = NULL; dict = DICT(dictObj); } while (dict != NULL); } /* *---------------------------------------------------------------------- * * Tcl_DictObjPut -- |
︙ | ︙ | |||
912 913 914 915 916 917 918 | Tcl_HashEntry *hPtr; int isNew; if (Tcl_IsShared(dictPtr)) { Tcl_Panic("%s called with shared object", "Tcl_DictObjPut"); } | | | < < | < | | 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 | Tcl_HashEntry *hPtr; int isNew; if (Tcl_IsShared(dictPtr)) { Tcl_Panic("%s called with shared object", "Tcl_DictObjPut"); } if (dictPtr->typePtr != &tclDictType && SetDictFromAny(interp, dictPtr) != TCL_OK) { return TCL_ERROR; } if (dictPtr->bytes != NULL) { TclInvalidateStringRep(dictPtr); } dict = DICT(dictPtr); hPtr = CreateChainEntry(dict, keyPtr, &isNew); Tcl_IncrRefCount(valuePtr); if (!isNew) { Tcl_Obj *oldValuePtr = Tcl_GetHashValue(hPtr); TclDecrRefCount(oldValuePtr); } |
︙ | ︙ | |||
966 967 968 969 970 971 972 | Tcl_Obj *dictPtr, Tcl_Obj *keyPtr, Tcl_Obj **valuePtrPtr) { Dict *dict; Tcl_HashEntry *hPtr; | | | < | | | | | < | 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 | Tcl_Obj *dictPtr, Tcl_Obj *keyPtr, Tcl_Obj **valuePtrPtr) { Dict *dict; Tcl_HashEntry *hPtr; if (dictPtr->typePtr != &tclDictType && SetDictFromAny(interp, dictPtr) != TCL_OK) { *valuePtrPtr = NULL; return TCL_ERROR; } dict = DICT(dictPtr); hPtr = Tcl_FindHashEntry(&dict->table, keyPtr); if (hPtr == NULL) { *valuePtrPtr = NULL; } else { *valuePtrPtr = Tcl_GetHashValue(hPtr); } return TCL_OK; |
︙ | ︙ | |||
1015 1016 1017 1018 1019 1020 1021 | { Dict *dict; if (Tcl_IsShared(dictPtr)) { Tcl_Panic("%s called with shared object", "Tcl_DictObjRemove"); } | | | < | | | | > | | | < < | 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 | { Dict *dict; if (Tcl_IsShared(dictPtr)) { Tcl_Panic("%s called with shared object", "Tcl_DictObjRemove"); } if (dictPtr->typePtr != &tclDictType && SetDictFromAny(interp, dictPtr) != TCL_OK) { return TCL_ERROR; } dict = DICT(dictPtr); if (DeleteChainEntry(dict, keyPtr)) { if (dictPtr->bytes != NULL) { TclInvalidateStringRep(dictPtr); } dict->epoch++; } return TCL_OK; } /* *---------------------------------------------------------------------- |
︙ | ︙ | |||
1058 1059 1060 1061 1062 1063 1064 | Tcl_DictObjSize( Tcl_Interp *interp, Tcl_Obj *dictPtr, int *sizePtr) { Dict *dict; | | | < | | | | < | 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 | Tcl_DictObjSize( Tcl_Interp *interp, Tcl_Obj *dictPtr, int *sizePtr) { Dict *dict; if (dictPtr->typePtr != &tclDictType && SetDictFromAny(interp, dictPtr) != TCL_OK) { return TCL_ERROR; } dict = DICT(dictPtr); *sizePtr = dict->table.numEntries; return TCL_OK; } /* *---------------------------------------------------------------------- * |
︙ | ︙ | |||
1112 1113 1114 1115 1116 1117 1118 | * written into when there are no further * values in the dictionary, or a 0 * otherwise. */ { Dict *dict; ChainEntry *cPtr; | | | < < | | | | < | 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 | * written into when there are no further * values in the dictionary, or a 0 * otherwise. */ { Dict *dict; ChainEntry *cPtr; if (dictPtr->typePtr != &tclDictType && SetDictFromAny(interp, dictPtr) != TCL_OK) { return TCL_ERROR; } dict = DICT(dictPtr); cPtr = dict->entryChainHead; if (cPtr == NULL) { searchPtr->epoch = -1; *donePtr = 1; } else { *donePtr = 0; searchPtr->dictionaryPtr = (Tcl_Dict) dict; |
︙ | ︙ | |||
1295 1296 1297 1298 1299 1300 1301 | } dictPtr = TclTraceDictPath(interp, dictPtr, keyc-1,keyv, DICT_PATH_CREATE); if (dictPtr == NULL) { return TCL_ERROR; } | | > | 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 | } dictPtr = TclTraceDictPath(interp, dictPtr, keyc-1,keyv, DICT_PATH_CREATE); if (dictPtr == NULL) { return TCL_ERROR; } dict = DICT(dictPtr); hPtr = CreateChainEntry(dict, keyv[keyc-1], &isNew); Tcl_IncrRefCount(valuePtr); if (!isNew) { Tcl_Obj *oldValuePtr = Tcl_GetHashValue(hPtr); TclDecrRefCount(oldValuePtr); } Tcl_SetHashValue(hPtr, valuePtr); InvalidateDictChain(dictPtr); return TCL_OK; } |
︙ | ︙ | |||
1351 1352 1353 1354 1355 1356 1357 | } dictPtr = TclTraceDictPath(interp, dictPtr, keyc-1,keyv, DICT_PATH_UPDATE); if (dictPtr == NULL) { return TCL_ERROR; } | | | 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 | } dictPtr = TclTraceDictPath(interp, dictPtr, keyc-1,keyv, DICT_PATH_UPDATE); if (dictPtr == NULL) { return TCL_ERROR; } dict = DICT(dictPtr); DeleteChainEntry(dict, keyv[keyc-1]); InvalidateDictChain(dictPtr); return TCL_OK; } /* *---------------------------------------------------------------------- |
︙ | ︙ | |||
1397 1398 1399 1400 1401 1402 1403 | TclNewObj(dictPtr); TclInvalidateStringRep(dictPtr); dict = ckalloc(sizeof(Dict)); InitChainTable(dict); dict->epoch = 0; dict->chain = NULL; dict->refcount = 1; | | | 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 | TclNewObj(dictPtr); TclInvalidateStringRep(dictPtr); dict = ckalloc(sizeof(Dict)); InitChainTable(dict); dict->epoch = 0; dict->chain = NULL; dict->refcount = 1; DICT(dictPtr) = dict; dictPtr->typePtr = &tclDictType; return dictPtr; #endif } /* *---------------------------------------------------------------------- |
︙ | ︙ | |||
1446 1447 1448 1449 1450 1451 1452 | TclDbNewObj(dictPtr, file, line); TclInvalidateStringRep(dictPtr); dict = ckalloc(sizeof(Dict)); InitChainTable(dict); dict->epoch = 0; dict->chain = NULL; dict->refcount = 1; | | | 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 | TclDbNewObj(dictPtr, file, line); TclInvalidateStringRep(dictPtr); dict = ckalloc(sizeof(Dict)); InitChainTable(dict); dict->epoch = 0; dict->chain = NULL; dict->refcount = 1; DICT(dictPtr) = dict; dictPtr->typePtr = &tclDictType; return dictPtr; #else /* !TCL_MEM_DEBUG */ return Tcl_NewDictObj(); #endif } |
︙ | ︙ | |||
1500 1501 1502 1503 1504 1505 1506 | } dictObj = Tcl_NewDictObj(); for (i=1 ; i<objc ; i+=2) { /* * The next command is assumed to never fail... */ | | | 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 | } dictObj = Tcl_NewDictObj(); for (i=1 ; i<objc ; i+=2) { /* * The next command is assumed to never fail... */ Tcl_DictObjPut(NULL, dictObj, objv[i], objv[i+1]); } Tcl_SetObjResult(interp, dictObj); return TCL_OK; } /* *---------------------------------------------------------------------- |
︙ | ︙ | |||
1625 1626 1627 1628 1629 1630 1631 | DictReplaceCmd( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Tcl_Obj *dictPtr; | | < > > > > < < < < | | | | < > | 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 1638 1639 1640 1641 1642 1643 1644 1645 1646 | DictReplaceCmd( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Tcl_Obj *dictPtr; int i; if ((objc < 2) || (objc & 1)) { Tcl_WrongNumArgs(interp, 1, objv, "dictionary ?key value ...?"); return TCL_ERROR; } dictPtr = objv[1]; if (dictPtr->typePtr != &tclDictType && SetDictFromAny(interp, dictPtr) != TCL_OK) { return TCL_ERROR; } if (Tcl_IsShared(dictPtr)) { dictPtr = Tcl_DuplicateObj(dictPtr); } if (dictPtr->bytes != NULL) { TclInvalidateStringRep(dictPtr); } for (i=2 ; i<objc ; i+=2) { Tcl_DictObjPut(NULL, dictPtr, objv[i], objv[i+1]); } Tcl_SetObjResult(interp, dictPtr); return TCL_OK; } /* *---------------------------------------------------------------------- |
︙ | ︙ | |||
1677 1678 1679 1680 1681 1682 1683 | DictRemoveCmd( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Tcl_Obj *dictPtr; | | < > > > > < < | < < | | | < > | 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 | DictRemoveCmd( ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Tcl_Obj *dictPtr; int i; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "dictionary ?key ...?"); return TCL_ERROR; } dictPtr = objv[1]; if (dictPtr->typePtr != &tclDictType && SetDictFromAny(interp, dictPtr) != TCL_OK) { return TCL_ERROR; } if (Tcl_IsShared(dictPtr)) { dictPtr = Tcl_DuplicateObj(dictPtr); } if (dictPtr->bytes != NULL) { TclInvalidateStringRep(dictPtr); } for (i=2 ; i<objc ; i++) { Tcl_DictObjRemove(NULL, dictPtr, objv[i]); } Tcl_SetObjResult(interp, dictPtr); return TCL_OK; } /* *---------------------------------------------------------------------- |
︙ | ︙ | |||
1746 1747 1748 1749 1750 1751 1752 | } /* * Make sure first argument is a dictionary. */ targetObj = objv[1]; | | | | < | 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 | } /* * Make sure first argument is a dictionary. */ targetObj = objv[1]; if (targetObj->typePtr != &tclDictType && SetDictFromAny(interp, targetObj) != TCL_OK) { return TCL_ERROR; } if (objc == 2) { /* * Single argument, return it. */ |
︙ | ︙ | |||
1831 1832 1833 1834 1835 1836 1837 | /* * A direct check that we have a dictionary. We don't start the iteration * yet because that might allocate memory or set locks that we do not * need. [Bug 1705778, leak K04] */ | | | < < | < | 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 | /* * A direct check that we have a dictionary. We don't start the iteration * yet because that might allocate memory or set locks that we do not * need. [Bug 1705778, leak K04] */ if (objv[1]->typePtr != &tclDictType && SetDictFromAny(interp, objv[1]) != TCL_OK) { return TCL_ERROR; } if (objc == 3) { pattern = TclGetString(objv[2]); } listPtr = Tcl_NewListObj(0, NULL); if ((pattern != NULL) && TclMatchIsTrivial(pattern)) { |
︙ | ︙ | |||
2052 2053 2054 2055 2056 2057 2058 | if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "dictionary"); return TCL_ERROR; } dictPtr = objv[1]; | | | < | | < | | 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 | if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "dictionary"); return TCL_ERROR; } dictPtr = objv[1]; if (dictPtr->typePtr != &tclDictType && SetDictFromAny(interp, dictPtr) != TCL_OK) { return TCL_ERROR; } dict = DICT(dictPtr); statsStr = Tcl_HashStats(&dict->table); Tcl_SetObjResult(interp, Tcl_NewStringObj(statsStr, -1)); ckfree(statsStr); return TCL_OK; } |
︙ | ︙ | |||
2148 2149 2150 2151 2152 2153 2154 | } else { /* * Remember to dispose with the bignum as we're not actually * using it directly. [Bug 2874678] */ mp_clear(&increment); | | | | | | | 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 | } else { /* * Remember to dispose with the bignum as we're not actually * using it directly. [Bug 2874678] */ mp_clear(&increment); Tcl_DictObjPut(NULL, dictPtr, objv[2], objv[3]); } } else { Tcl_DictObjPut(NULL, dictPtr, objv[2], Tcl_NewIntObj(1)); } } else { /* * Key in dictionary. Increment its value with minimum dup. */ if (Tcl_IsShared(valuePtr)) { valuePtr = Tcl_DuplicateObj(valuePtr); Tcl_DictObjPut(NULL, dictPtr, objv[2], valuePtr); } if (objc == 4) { code = TclIncrObj(interp, valuePtr, objv[3]); } else { Tcl_Obj *incrPtr = Tcl_NewIntObj(1); Tcl_IncrRefCount(incrPtr); code = TclIncrObj(interp, valuePtr, incrPtr); TclDecrRefCount(incrPtr); } } if (code == TCL_OK) { TclInvalidateStringRep(dictPtr); valuePtr = Tcl_ObjSetVar2(interp, objv[1], NULL, dictPtr, TCL_LEAVE_ERR_MSG); if (valuePtr == NULL) { code = TCL_ERROR; } else { Tcl_SetObjResult(interp, valuePtr); } } else if (dictPtr->refCount == 0) { TclDecrRefCount(dictPtr); } return code; } /* *---------------------------------------------------------------------- * |
︙ | ︙ | |||
2260 2261 2262 2263 2264 2265 2266 | } return TCL_ERROR; } } } if (allocatedValue) { | | | 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 | } return TCL_ERROR; } } } if (allocatedValue) { Tcl_DictObjPut(NULL, dictPtr, objv[2], valuePtr); } else if (dictPtr->bytes != NULL) { TclInvalidateStringRep(dictPtr); } resultPtr = Tcl_ObjSetVar2(interp, objv[1], NULL, dictPtr, TCL_LEAVE_ERR_MSG); if (resultPtr == NULL) { |
︙ | ︙ | |||
2325 2326 2327 2328 2329 2330 2331 | TclDecrRefCount(dictPtr); } return TCL_ERROR; } if (valuePtr == NULL) { TclNewObj(valuePtr); | < | | < | | 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 | TclDecrRefCount(dictPtr); } return TCL_ERROR; } if (valuePtr == NULL) { TclNewObj(valuePtr); } else if (Tcl_IsShared(valuePtr)) { valuePtr = Tcl_DuplicateObj(valuePtr); } for (i=3 ; i<objc ; i++) { Tcl_AppendObjToObj(valuePtr, objv[i]); } Tcl_DictObjPut(NULL, dictPtr, objv[2], valuePtr); resultPtr = Tcl_ObjSetVar2(interp, objv[1], NULL, dictPtr, TCL_LEAVE_ERR_MSG); if (resultPtr == NULL) { return TCL_ERROR; } Tcl_SetObjResult(interp, resultPtr); |
︙ | ︙ | |||
2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 | if (TclListObjGetElements(interp, objv[1], &varc, &varv) != TCL_OK) { return TCL_ERROR; } if (varc != 2) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "must have exactly two variable names", -1)); return TCL_ERROR; } searchPtr = TclStackAlloc(interp, sizeof(Tcl_DictSearch)); if (Tcl_DictObjFirst(interp, objv[2], searchPtr, &keyObj, &valueObj, &done) != TCL_OK) { TclStackFree(interp, searchPtr); return TCL_ERROR; | > | 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 | if (TclListObjGetElements(interp, objv[1], &varc, &varv) != TCL_OK) { return TCL_ERROR; } if (varc != 2) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "must have exactly two variable names", -1)); Tcl_SetErrorCode(interp, "TCL", "SYNTAX", "dict", "for", NULL); return TCL_ERROR; } searchPtr = TclStackAlloc(interp, sizeof(Tcl_DictSearch)); if (Tcl_DictObjFirst(interp, objv[2], searchPtr, &keyObj, &valueObj, &done) != TCL_OK) { TclStackFree(interp, searchPtr); return TCL_ERROR; |
︙ | ︙ | |||
2426 2427 2428 2429 2430 2431 2432 | /* * Stop the value from getting hit in any way by any traces on the key * variable. */ Tcl_IncrRefCount(valueObj); | | > | > | 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 | /* * Stop the value from getting hit in any way by any traces on the key * variable. */ Tcl_IncrRefCount(valueObj); if (Tcl_ObjSetVar2(interp, keyVarObj, NULL, keyObj, TCL_LEAVE_ERR_MSG) == NULL) { TclDecrRefCount(valueObj); goto error; } TclDecrRefCount(valueObj); if (Tcl_ObjSetVar2(interp, valueVarObj, NULL, valueObj, TCL_LEAVE_ERR_MSG) == NULL) { goto error; } /* * Run the script. */ |
︙ | ︙ | |||
2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 | if (TclListObjGetElements(interp, objv[1], &varc, &varv) != TCL_OK) { return TCL_ERROR; } if (varc != 2) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "must have exactly two variable names", -1)); return TCL_ERROR; } storagePtr = TclStackAlloc(interp, sizeof(DictMapStorage)); if (Tcl_DictObjFirst(interp, objv[2], &storagePtr->search, &keyObj, &valueObj, &done) != TCL_OK) { TclStackFree(interp, storagePtr); return TCL_ERROR; | > | 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 | if (TclListObjGetElements(interp, objv[1], &varc, &varv) != TCL_OK) { return TCL_ERROR; } if (varc != 2) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "must have exactly two variable names", -1)); Tcl_SetErrorCode(interp, "TCL", "SYNTAX", "dict", "map", NULL); return TCL_ERROR; } storagePtr = TclStackAlloc(interp, sizeof(DictMapStorage)); if (Tcl_DictObjFirst(interp, objv[2], &storagePtr->search, &keyObj, &valueObj, &done) != TCL_OK) { TclStackFree(interp, storagePtr); return TCL_ERROR; |
︙ | ︙ | |||
2945 2946 2947 2948 2949 2950 2951 | * since we are not exhausing the search. [Bug 1705778, leak * K05] */ Tcl_DictObjDone(&search); Tcl_DictObjGet(interp, objv[1], objv[3], &valueObj); if (valueObj != NULL) { | | | | | 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 | * since we are not exhausing the search. [Bug 1705778, leak * K05] */ Tcl_DictObjDone(&search); Tcl_DictObjGet(interp, objv[1], objv[3], &valueObj); if (valueObj != NULL) { Tcl_DictObjPut(NULL, resultObj, objv[3], valueObj); } } else { while (!done) { if (Tcl_StringMatch(TclGetString(keyObj), pattern)) { Tcl_DictObjPut(NULL, resultObj, keyObj, valueObj); } Tcl_DictObjNext(&search, &keyObj, &valueObj, &done); } } } else { /* * Can't optimize this match for trivial globbing: would disturb * order. */ resultObj = Tcl_NewDictObj(); while (!done) { int i; for (i=3 ; i<objc ; i++) { pattern = TclGetString(objv[i]); if (Tcl_StringMatch(TclGetString(keyObj), pattern)) { Tcl_DictObjPut(NULL, resultObj, keyObj, valueObj); break; /* stop inner loop */ } } Tcl_DictObjNext(&search, &keyObj, &valueObj, &done); } } Tcl_SetObjResult(interp, resultObj); |
︙ | ︙ | |||
2994 2995 2996 2997 2998 2999 3000 | resultObj = Tcl_NewDictObj(); while (!done) { int i; for (i=3 ; i<objc ; i++) { pattern = TclGetString(objv[i]); if (Tcl_StringMatch(TclGetString(valueObj), pattern)) { | | | 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 | resultObj = Tcl_NewDictObj(); while (!done) { int i; for (i=3 ; i<objc ; i++) { pattern = TclGetString(objv[i]); if (Tcl_StringMatch(TclGetString(valueObj), pattern)) { Tcl_DictObjPut(NULL, resultObj, keyObj, valueObj); break; /* stop inner loop */ } } Tcl_DictObjNext(&search, &keyObj, &valueObj, &done); } Tcl_SetObjResult(interp, resultObj); return TCL_OK; |
︙ | ︙ | |||
3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 | if (TclListObjGetElements(interp, objv[3], &varc, &varv) != TCL_OK) { return TCL_ERROR; } if (varc != 2) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "must have exactly two variable names", -1)); return TCL_ERROR; } keyVarObj = varv[0]; valueVarObj = varv[1]; scriptObj = objv[4]; /* | > | 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 | if (TclListObjGetElements(interp, objv[3], &varc, &varv) != TCL_OK) { return TCL_ERROR; } if (varc != 2) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "must have exactly two variable names", -1)); Tcl_SetErrorCode(interp, "TCL", "SYNTAX", "dict", "filter", NULL); return TCL_ERROR; } keyVarObj = varv[0]; valueVarObj = varv[1]; scriptObj = objv[4]; /* |
︙ | ︙ | |||
3060 3061 3062 3063 3064 3065 3066 | * key variable. */ Tcl_IncrRefCount(keyObj); Tcl_IncrRefCount(valueObj); if (Tcl_ObjSetVar2(interp, keyVarObj, NULL, keyObj, TCL_LEAVE_ERR_MSG) == NULL) { | | < | < | < | < | 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 | * key variable. */ Tcl_IncrRefCount(keyObj); Tcl_IncrRefCount(valueObj); if (Tcl_ObjSetVar2(interp, keyVarObj, NULL, keyObj, TCL_LEAVE_ERR_MSG) == NULL) { Tcl_AddErrorInfo(interp, "\n (\"dict filter\" filter script key variable)"); result = TCL_ERROR; goto abnormalResult; } if (Tcl_ObjSetVar2(interp, valueVarObj, NULL, valueObj, TCL_LEAVE_ERR_MSG) == NULL) { Tcl_AddErrorInfo(interp, "\n (\"dict filter\" filter script value variable)"); result = TCL_ERROR; goto abnormalResult; } /* * TIP #280. Make invoking context available to loop body. */ |
︙ | ︙ | |||
3095 3096 3097 3098 3099 3100 3101 | &satisfied) != TCL_OK) { TclDecrRefCount(boolObj); result = TCL_ERROR; goto abnormalResult; } TclDecrRefCount(boolObj); if (satisfied) { | | | 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 | &satisfied) != TCL_OK) { TclDecrRefCount(boolObj); result = TCL_ERROR; goto abnormalResult; } TclDecrRefCount(boolObj); if (satisfied) { Tcl_DictObjPut(NULL, resultObj, keyObj, valueObj); } break; case TCL_BREAK: /* * Force loop termination by calling Tcl_DictObjDone; this * makes the next Tcl_DictObjNext say there is nothing more to * do. |
︙ | ︙ | |||
3283 3284 3285 3286 3287 3288 3289 | * an instruction to remove the key. */ Tcl_ListObjGetElements(NULL, argsObj, &objc, &objv); for (i=0 ; i<objc ; i+=2) { objPtr = Tcl_ObjGetVar2(interp, objv[i+1], NULL, 0); if (objPtr == NULL) { | | < | | | 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 | * an instruction to remove the key. */ Tcl_ListObjGetElements(NULL, argsObj, &objc, &objv); for (i=0 ; i<objc ; i+=2) { objPtr = Tcl_ObjGetVar2(interp, objv[i+1], NULL, 0); if (objPtr == NULL) { Tcl_DictObjRemove(NULL, dictPtr, objv[i]); } else if (objPtr == dictPtr) { /* * Someone is messing us around, trying to build a recursive * structure. [Bug 1786481] */ Tcl_DictObjPut(NULL, dictPtr, objv[i], Tcl_DuplicateObj(objPtr)); } else { /* Shouldn't fail */ Tcl_DictObjPut(NULL, dictPtr, objv[i], objPtr); } } TclDecrRefCount(argsObj); /* * Write the dictionary back to its variable. */ |
︙ | ︙ |
Changes to generic/tclInt.h.
︙ | ︙ | |||
2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 | int start, int *clNext); MODULE_SCOPE ContLineLoc *TclContinuationsGet(Tcl_Obj *objPtr); MODULE_SCOPE void TclContinuationsCopy(Tcl_Obj *objPtr, Tcl_Obj *originObjPtr); MODULE_SCOPE int TclConvertElement(const char *src, int length, char *dst, int flags); MODULE_SCOPE void TclDeleteNamespaceVars(Namespace *nsPtr); /* TIP #280 - Modified token based evulation, with line information. */ MODULE_SCOPE int TclEvalEx(Tcl_Interp *interp, const char *script, int numBytes, int flags, int line, int *clNextOuter, const char *outerScript); MODULE_SCOPE Tcl_ObjCmdProc TclFileAttrsCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileCopyCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileDeleteCmd; | > > > > | 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 | int start, int *clNext); MODULE_SCOPE ContLineLoc *TclContinuationsGet(Tcl_Obj *objPtr); MODULE_SCOPE void TclContinuationsCopy(Tcl_Obj *objPtr, Tcl_Obj *originObjPtr); MODULE_SCOPE int TclConvertElement(const char *src, int length, char *dst, int flags); MODULE_SCOPE void TclDeleteNamespaceVars(Namespace *nsPtr); MODULE_SCOPE int TclFindDictElement(Tcl_Interp *interp, const char *dict, int dictLength, const char **elementPtr, const char **nextPtr, int *sizePtr, int *literalPtr); /* TIP #280 - Modified token based evulation, with line information. */ MODULE_SCOPE int TclEvalEx(Tcl_Interp *interp, const char *script, int numBytes, int flags, int line, int *clNextOuter, const char *outerScript); MODULE_SCOPE Tcl_ObjCmdProc TclFileAttrsCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileCopyCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileDeleteCmd; |
︙ | ︙ |
Changes to generic/tclUtil.c.
︙ | ︙ | |||
107 108 109 110 111 112 113 | static void ClearHash(Tcl_HashTable *tablePtr); static void FreeProcessGlobalValue(ClientData clientData); static void FreeThreadHash(ClientData clientData); static Tcl_HashTable * GetThreadHash(Tcl_ThreadDataKey *keyPtr); static int SetEndOffsetFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr); static void UpdateStringOfEndOffset(Tcl_Obj *objPtr); | | > > > > | 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | static void ClearHash(Tcl_HashTable *tablePtr); static void FreeProcessGlobalValue(ClientData clientData); static void FreeThreadHash(ClientData clientData); static Tcl_HashTable * GetThreadHash(Tcl_ThreadDataKey *keyPtr); static int SetEndOffsetFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr); static void UpdateStringOfEndOffset(Tcl_Obj *objPtr); static int FindElement(Tcl_Interp *interp, const char *string, int stringLength, const char *typeStr, const char *typeCode, const char **elementPtr, const char **nextPtr, int *sizePtr, int *literalPtr); /* * The following is the Tcl object type definition for an object that * represents a list index in the form, "end-offset". It is used as a * performance optimization in TclGetIntForIndex. The internal rep is an * integer, so no memory management is required for it. */ |
︙ | ︙ | |||
233 234 235 236 237 238 239 | * * NOTE: Any element value can be represented by this style of formatting, * given suitable choice of backslash escape sequences, with one exception. * The empty string cannot be represented as a list element without the use * of either braces or quotes to delimit it. * * This collection of parsing rules is implemented in the routine | | | 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | * * NOTE: Any element value can be represented by this style of formatting, * given suitable choice of backslash escape sequences, with one exception. * The empty string cannot be represented as a list element without the use * of either braces or quotes to delimit it. * * This collection of parsing rules is implemented in the routine * FindElement(). * * In order to produce lists that can be parsed by these rules, we need the * ability to distinguish between characters that are part of a list element * value from characters providing syntax that define the structure of the * list. This means that our code that generates lists must at a minimum be * able to produce escape sequences for the 10 characters identified above * that have significance to a list parser. |
︙ | ︙ | |||
501 502 503 504 505 506 507 | int *literalPtr) /* If non-zero, fill in with non-zero/zero to * indicate that the substring of *sizePtr * bytes starting at **elementPtr is/is not * the literal list element and therefore * does not/does require a call to * TclCopyAndCollapse() by the caller. */ { | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 | int *literalPtr) /* If non-zero, fill in with non-zero/zero to * indicate that the substring of *sizePtr * bytes starting at **elementPtr is/is not * the literal list element and therefore * does not/does require a call to * TclCopyAndCollapse() by the caller. */ { return FindElement(interp, list, listLength, "list", "LIST", elementPtr, nextPtr, sizePtr, literalPtr); } int TclFindDictElement( Tcl_Interp *interp, /* Interpreter to use for error reporting. If * NULL, then no error message is left after * errors. */ const char *dict, /* Points to the first byte of a string * containing a Tcl dictionary with zero or * more keys and values (possibly in * braces). */ int dictLength, /* Number of bytes in the dict's string. */ const char **elementPtr, /* Where to put address of first significant * character in the first element (i.e., key * or value) of dict. */ const char **nextPtr, /* Fill in with location of character just * after all white space following end of * element (next arg or end of list). */ int *sizePtr, /* If non-zero, fill in with size of * element. */ int *literalPtr) /* If non-zero, fill in with non-zero/zero to * indicate that the substring of *sizePtr * bytes starting at **elementPtr is/is not * the literal key or value and therefore * does not/does require a call to * TclCopyAndCollapse() by the caller. */ { return FindElement(interp, dict, dictLength, "dict", "DICTIONARY", elementPtr, nextPtr, sizePtr, literalPtr); } static int FindElement( Tcl_Interp *interp, /* Interpreter to use for error reporting. If * NULL, then no error message is left after * errors. */ const char *string, /* Points to the first byte of a string * containing a Tcl list or dictionary with * zero or more elements (possibly in * braces). */ int stringLength, /* Number of bytes in the string. */ const char *typeStr, /* The name of the type of thing we are * parsing, for error messages. */ const char *typeCode, /* The type code for thing we are parsing, for * error messages. */ const char **elementPtr, /* Where to put address of first significant * character in first element. */ const char **nextPtr, /* Fill in with location of character just * after all white space following end of * argument (next arg or end of list/dict). */ int *sizePtr, /* If non-zero, fill in with size of * element. */ int *literalPtr) /* If non-zero, fill in with non-zero/zero to * indicate that the substring of *sizePtr * bytes starting at **elementPtr is/is not * the literal list/dict element and therefore * does not/does require a call to * TclCopyAndCollapse() by the caller. */ { const char *p = string; const char *elemStart; /* Points to first byte of first element. */ const char *limit; /* Points just after list/dict's last byte. */ int openBraces = 0; /* Brace nesting level during parse. */ int inQuotes = 0; int size = 0; /* lint. */ int numChars; int literal = 1; const char *p2; /* * Skim off leading white space and check for an opening brace or quote. * We treat embedded NULLs in the list/dict as bytes belonging to a list * element (or dictionary key or value). */ limit = (string + stringLength); while ((p < limit) && (TclIsSpaceProc(*p))) { p++; } if (p == limit) { /* no element found */ elemStart = limit; goto done; } |
︙ | ︙ | |||
578 579 580 581 582 583 584 | if (interp != NULL) { p2 = p; while ((p2 < limit) && (!TclIsSpaceProc(*p2)) && (p2 < p+20)) { p2++; } Tcl_SetObjResult(interp, Tcl_ObjPrintf( | | | | | 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 | if (interp != NULL) { p2 = p; while ((p2 < limit) && (!TclIsSpaceProc(*p2)) && (p2 < p+20)) { p2++; } Tcl_SetObjResult(interp, Tcl_ObjPrintf( "%s element in braces followed by \"%.*s\" " "instead of space", typeStr, (int) (p2-p), p)); Tcl_SetErrorCode(interp, "TCL", "VALUE", typeCode, "JUNK", NULL); } return TCL_ERROR; } break; /* |
︙ | ︙ | |||
647 648 649 650 651 652 653 | if (interp != NULL) { p2 = p; while ((p2 < limit) && (!TclIsSpaceProc(*p2)) && (p2 < p+20)) { p2++; } Tcl_SetObjResult(interp, Tcl_ObjPrintf( | | | | | | | | | | | | 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 | if (interp != NULL) { p2 = p; while ((p2 < limit) && (!TclIsSpaceProc(*p2)) && (p2 < p+20)) { p2++; } Tcl_SetObjResult(interp, Tcl_ObjPrintf( "%s element in quotes followed by \"%.*s\" " "instead of space", typeStr, (int) (p2-p), p)); Tcl_SetErrorCode(interp, "TCL", "VALUE", typeCode, "JUNK", NULL); } return TCL_ERROR; } break; } p++; } /* * End of list/dict: terminate element. */ if (p == limit) { if (openBraces != 0) { if (interp != NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "unmatched open brace in %s", typeStr)); Tcl_SetErrorCode(interp, "TCL", "VALUE", typeCode, "BRACE", NULL); } return TCL_ERROR; } else if (inQuotes) { if (interp != NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "unmatched open quote in %s", typeStr)); Tcl_SetErrorCode(interp, "TCL", "VALUE", typeCode, "QUOTE", NULL); } return TCL_ERROR; } size = (p - elemStart); } |
︙ | ︙ |
Changes to tests/dict.test.
︙ | ︙ | |||
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | dict replace {a a a} a b } -result {missing value to go with key} test dict-4.8 {dict replace command} -returnCodes error -body { dict replace [list a a a] a b } -result {missing value to go with key} test dict-4.9 {dict replace command} {dict replace [list a a] a b} {a b} test dict-4.10 {dict replace command} {dict replace [list a a] a b a c} {a c} test dict-5.1 {dict remove command} {dict remove {a b c d} a} {c d} test dict-5.2 {dict remove command} {dict remove {a b c d} c} {a b} test dict-5.3 {dict remove command} {dict remove {a b c d} a c} {} test dict-5.4 {dict remove command} {dict remove {a b c d} c a} {} test dict-5.5 {dict remove command} { dict remove {a b c d} } {a b c d} test dict-5.6 {dict remove command} {dict remove {a b} c} {a b} test dict-5.7 {dict remove command} -returnCodes error -body { dict remove } -result {wrong # args: should be "dict remove dictionary ?key ...?"} test dict-6.1 {dict keys command} {dict keys {a b}} a test dict-6.2 {dict keys command} {dict keys {c d}} c test dict-6.3 {dict keys command} {lsort [dict keys {a b c d}]} {a c} test dict-6.4 {dict keys command} {dict keys {a b c d} a} a test dict-6.5 {dict keys command} {dict keys {a b c d} c} c test dict-6.6 {dict keys command} {dict keys {a b c d} e} {} | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 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 | dict replace {a a a} a b } -result {missing value to go with key} test dict-4.8 {dict replace command} -returnCodes error -body { dict replace [list a a a] a b } -result {missing value to go with key} test dict-4.9 {dict replace command} {dict replace [list a a] a b} {a b} test dict-4.10 {dict replace command} {dict replace [list a a] a b a c} {a c} test dict-4.11 {dict replace command: canonicality is forced} { dict replace { a b c d } } {a b c d} test dict-4.12 {dict replace command: canonicality is forced} { dict replace {a b c d a e} } {a e c d} test dict-4.13 {dict replace command: type check is mandatory} -body { dict replace { a b c d e } } -returnCodes error -result {missing value to go with key} test dict-4.13a {dict replace command: type check is mandatory} { catch {dict replace { a b c d e }} -> opt dict get $opt -errorcode } {TCL VALUE DICTIONARY} test dict-4.14 {dict replace command: type check is mandatory} -body { dict replace { a b {}c d } } -returnCodes error -result {dict element in braces followed by "c" instead of space} test dict-4.14a {dict replace command: type check is mandatory} { catch {dict replace { a b {}c d }} -> opt dict get $opt -errorcode } {TCL VALUE DICTIONARY JUNK} test dict-4.15 {dict replace command: type check is mandatory} -body { dict replace { a b ""c d } } -returnCodes error -result {dict element in quotes followed by "c" instead of space} test dict-4.15a {dict replace command: type check is mandatory} { catch {dict replace { a b ""c d }} -> opt dict get $opt -errorcode } {TCL VALUE DICTIONARY JUNK} test dict-4.16 {dict replace command: type check is mandatory} -body { dict replace " a b \"c d " } -returnCodes error -result {unmatched open quote in dict} test dict-4.16a {dict replace command: type check is mandatory} { catch {dict replace " a b \"c d "} -> opt dict get $opt -errorcode } {TCL VALUE DICTIONARY QUOTE} test dict-4.17 {dict replace command: type check is mandatory} -body { dict replace " a b \{c d " } -returnCodes error -result {unmatched open brace in dict} test dict-4.17a {dict replace command: type check is mandatory} { catch {dict replace " a b \{c d "} -> opt dict get $opt -errorcode } {TCL VALUE DICTIONARY BRACE} test dict-4.18 {dict replace command: canonicality forcing doesn't leak} { set example { a b c d } list $example [dict replace $example] } {{ a b c d } {a b c d}} test dict-5.1 {dict remove command} {dict remove {a b c d} a} {c d} test dict-5.2 {dict remove command} {dict remove {a b c d} c} {a b} test dict-5.3 {dict remove command} {dict remove {a b c d} a c} {} test dict-5.4 {dict remove command} {dict remove {a b c d} c a} {} test dict-5.5 {dict remove command} { dict remove {a b c d} } {a b c d} test dict-5.6 {dict remove command} {dict remove {a b} c} {a b} test dict-5.7 {dict remove command} -returnCodes error -body { dict remove } -result {wrong # args: should be "dict remove dictionary ?key ...?"} test dict-5.8 {dict remove command: canonicality is forced} { dict remove { a b c d } } {a b c d} test dict-5.9 {dict remove command: canonicality is forced} { dict remove {a b c d a e} } {a e c d} test dict-5.10 {dict remove command: canonicality forced by update} { dict remove { a b c d } c } {a b} test dict-5.11 {dict remove command: type check is mandatory} -body { dict remove { a b c d e } } -returnCodes error -result {missing value to go with key} test dict-5.12 {dict remove command: type check is mandatory} -body { dict remove { a b {}c d } } -returnCodes error -result {dict element in braces followed by "c" instead of space} test dict-5.13 {dict remove command: canonicality forcing doesn't leak} { set example { a b c d } list $example [dict remove $example] } {{ a b c d } {a b c d}} test dict-6.1 {dict keys command} {dict keys {a b}} a test dict-6.2 {dict keys command} {dict keys {c d}} c test dict-6.3 {dict keys command} {lsort [dict keys {a b c d}]} {a c} test dict-6.4 {dict keys command} {dict keys {a b c d} a} a test dict-6.5 {dict keys command} {dict keys {a b c d} c} c test dict-6.6 {dict keys command} {dict keys {a b c d} e} {} |
︙ | ︙ | |||
1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 | } {a x c y} test dict-20.19 {dict merge command} { apply {{} {dict merge {a b c d} {c y a x}}} } {a x c y} test dict-20.20 {dict merge command} { apply {{} {dict merge {a b c d e f} {a x 1 2 3 4} {a - 1 -}}} } {a - c d e f 1 - 3 4} test dict-21.1 {dict update command} -returnCodes 1 -body { dict update } -result {wrong # args: should be "dict update varName key varName ?key varName ...? script"} test dict-21.2 {dict update command} -returnCodes 1 -body { dict update v } -result {wrong # args: should be "dict update varName key varName ?key varName ...? script"} | > > > > > > > > > > > > > > > | 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 | } {a x c y} test dict-20.19 {dict merge command} { apply {{} {dict merge {a b c d} {c y a x}}} } {a x c y} test dict-20.20 {dict merge command} { apply {{} {dict merge {a b c d e f} {a x 1 2 3 4} {a - 1 -}}} } {a - c d e f 1 - 3 4} test dict-20.21 {dict merge command: canonicality not forced} { dict merge { a b c d } } { a b c d } test dict-20.22 {dict merge command: canonicality not forced} { dict merge { a b c d } {} } { a b c d } test dict-20.23 {dict merge command: canonicality forced by update} { dict merge { a b c d } {a b} } {a b c d} test dict-20.24 {dict merge command: type check is mandatory} -body { dict merge { a b c d e } } -returnCodes error -result {missing value to go with key} test dict-20.25 {dict merge command: type check is mandatory} -body { dict merge { a b {}c d } } -returnCodes error -result {dict element in braces followed by "c" instead of space} test dict-21.1 {dict update command} -returnCodes 1 -body { dict update } -result {wrong # args: should be "dict update varName key varName ?key varName ...? script"} test dict-21.2 {dict update command} -returnCodes 1 -body { dict update v } -result {wrong # args: should be "dict update varName key varName ?key varName ...? script"} |
︙ | ︙ |