4 * This file contains functions that implement the Tcl dict object type
5 * and its accessor command.
7 * Copyright (c) 2002-2010 by Donal K. Fellows.
9 * See the file "license.terms" for information on usage and redistribution of
10 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
17 * Forward declaration.
22 * Prototypes for functions defined later in this file:
25 static void DeleteDict(struct Dict *dict);
26 static int DictAppendCmd(ClientData dummy, Tcl_Interp *interp,
27 int objc, Tcl_Obj *const *objv);
28 static int DictCreateCmd(ClientData dummy, Tcl_Interp *interp,
29 int objc, Tcl_Obj *const *objv);
30 static int DictExistsCmd(ClientData dummy, Tcl_Interp *interp,
31 int objc, Tcl_Obj *const *objv);
32 static int DictFilterCmd(ClientData dummy, Tcl_Interp *interp,
33 int objc, Tcl_Obj *const *objv);
34 static int DictGetCmd(ClientData dummy, Tcl_Interp *interp,
35 int objc, Tcl_Obj *const *objv);
36 static int DictIncrCmd(ClientData dummy, Tcl_Interp *interp,
37 int objc, Tcl_Obj *const *objv);
38 static int DictInfoCmd(ClientData dummy, Tcl_Interp *interp,
39 int objc, Tcl_Obj *const *objv);
40 static int DictKeysCmd(ClientData dummy, Tcl_Interp *interp,
41 int objc, Tcl_Obj *const *objv);
42 static int DictLappendCmd(ClientData dummy, Tcl_Interp *interp,
43 int objc, Tcl_Obj *const *objv);
44 static int DictMergeCmd(ClientData dummy, Tcl_Interp *interp,
45 int objc, Tcl_Obj *const *objv);
46 static int DictRemoveCmd(ClientData dummy, Tcl_Interp *interp,
47 int objc, Tcl_Obj *const *objv);
48 static int DictReplaceCmd(ClientData dummy, Tcl_Interp *interp,
49 int objc, Tcl_Obj *const *objv);
50 static int DictSetCmd(ClientData dummy, Tcl_Interp *interp,
51 int objc, Tcl_Obj *const *objv);
52 static int DictSizeCmd(ClientData dummy, Tcl_Interp *interp,
53 int objc, Tcl_Obj *const *objv);
54 static int DictUnsetCmd(ClientData dummy, Tcl_Interp *interp,
55 int objc, Tcl_Obj *const *objv);
56 static int DictUpdateCmd(ClientData dummy, Tcl_Interp *interp,
57 int objc, Tcl_Obj *const *objv);
58 static int DictValuesCmd(ClientData dummy, Tcl_Interp *interp,
59 int objc, Tcl_Obj *const *objv);
60 static int DictWithCmd(ClientData dummy, Tcl_Interp *interp,
61 int objc, Tcl_Obj *const *objv);
62 static void DupDictInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr);
63 static void FreeDictInternalRep(Tcl_Obj *dictPtr);
64 static void InvalidateDictChain(Tcl_Obj *dictObj);
65 static int SetDictFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
66 static void UpdateStringOfDict(Tcl_Obj *dictPtr);
67 static Tcl_HashEntry * AllocChainEntry(Tcl_HashTable *tablePtr,void *keyPtr);
68 static inline void InitChainTable(struct Dict *dict);
69 static inline void DeleteChainTable(struct Dict *dict);
70 static inline Tcl_HashEntry *CreateChainEntry(struct Dict *dict,
71 Tcl_Obj *keyPtr, int *newPtr);
72 static inline int DeleteChainEntry(struct Dict *dict, Tcl_Obj *keyPtr);
73 static Tcl_NRPostProc FinalizeDictUpdate;
74 static Tcl_NRPostProc FinalizeDictWith;
75 static Tcl_ObjCmdProc DictForNRCmd;
76 static Tcl_ObjCmdProc DictMapNRCmd;
77 static Tcl_NRPostProc DictForLoopCallback;
78 static Tcl_NRPostProc DictMapLoopCallback;
81 * Table of dict subcommand names and implementations.
84 static const EnsembleImplMap implementationMap[] = {
85 {"append", DictAppendCmd, TclCompileDictAppendCmd, NULL, NULL, 0 },
86 {"create", DictCreateCmd, TclCompileDictCreateCmd, NULL, NULL, 0 },
87 {"exists", DictExistsCmd, TclCompileDictExistsCmd, NULL, NULL, 0 },
88 {"filter", DictFilterCmd, NULL, NULL, NULL, 0 },
89 {"for", NULL, TclCompileDictForCmd, DictForNRCmd, NULL, 0 },
90 {"get", DictGetCmd, TclCompileDictGetCmd, NULL, NULL, 0 },
91 {"incr", DictIncrCmd, TclCompileDictIncrCmd, NULL, NULL, 0 },
92 {"info", DictInfoCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0 },
93 {"keys", DictKeysCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0 },
94 {"lappend", DictLappendCmd, TclCompileDictLappendCmd, NULL, NULL, 0 },
95 {"map", NULL, TclCompileDictMapCmd, DictMapNRCmd, NULL, 0 },
96 {"merge", DictMergeCmd, TclCompileDictMergeCmd, NULL, NULL, 0 },
97 {"remove", DictRemoveCmd, TclCompileBasicMin1ArgCmd, NULL, NULL, 0 },
98 {"replace", DictReplaceCmd, NULL, NULL, NULL, 0 },
99 {"set", DictSetCmd, TclCompileDictSetCmd, NULL, NULL, 0 },
100 {"size", DictSizeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0 },
101 {"unset", DictUnsetCmd, TclCompileDictUnsetCmd, NULL, NULL, 0 },
102 {"update", DictUpdateCmd, TclCompileDictUpdateCmd, NULL, NULL, 0 },
103 {"values", DictValuesCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0 },
104 {"with", DictWithCmd, TclCompileDictWithCmd, NULL, NULL, 0 },
105 {NULL, NULL, NULL, NULL, NULL, 0}
109 * Internal representation of the entries in the hash table that backs a
113 typedef struct ChainEntry {
115 struct ChainEntry *prevPtr;
116 struct ChainEntry *nextPtr;
120 * Internal representation of a dictionary.
122 * The internal representation of a dictionary object is a hash table (with
123 * Tcl_Objs for both keys and values), a reference count and epoch number for
124 * detecting concurrent modifications of the dictionary, and a pointer to the
125 * parent object (used when invalidating string reps of pathed dictionary
126 * trees) which is NULL in normal use. The fact that hash tables know (with
127 * appropriate initialisation) already about objects makes key management /so/
130 * Reference counts are used to enable safe iteration across hashes while
131 * allowing the type of the containing object to be modified.
134 typedef struct Dict {
135 Tcl_HashTable table; /* Object hash table to store mapping in. */
136 ChainEntry *entryChainHead; /* Linked list of all entries in the
137 * dictionary. Used for doing traversal of the
138 * entries in the order that they are
140 ChainEntry *entryChainTail; /* Other end of linked list of all entries in
141 * the dictionary. Used for doing traversal of
142 * the entries in the order that they are
144 int epoch; /* Epoch counter */
145 size_t refCount; /* Reference counter (see above) */
146 Tcl_Obj *chain; /* Linked list used for invalidating the
147 * string representations of updated nested
152 * Accessor macro for converting between a Tcl_Obj* and a Dict. Note that this
153 * must be assignable as well as readable.
156 #define DICT(dictObj) ((dictObj)->internalRep.twoPtrValue.ptr1)
159 * The structure below defines the dictionary object type by means of
160 * functions that can be invoked by generic object code.
163 const Tcl_ObjType tclDictType = {
165 FreeDictInternalRep, /* freeIntRepProc */
166 DupDictInternalRep, /* dupIntRepProc */
167 UpdateStringOfDict, /* updateStringProc */
168 SetDictFromAny /* setFromAnyProc */
172 * The type of the specially adapted version of the Tcl_Obj*-containing hash
173 * table defined in the tclObj.c code. This version differs in that it
174 * allocates a bit more space in each hash entry in order to hold the pointers
175 * used to keep the hash entries in a linked list.
177 * Note that this type of hash table is *only* suitable for direct use in
178 * *this* file. Everything else should use the dict iterator API.
181 static const Tcl_HashKeyType chainHashType = {
182 TCL_HASH_KEY_TYPE_VERSION,
191 * Structure used in implementation of 'dict map' to hold the state that gets
192 * passed between parts of the implementation.
196 Tcl_Obj *keyVarObj; /* The name of the variable that will have
197 * keys assigned to it. */
198 Tcl_Obj *valueVarObj; /* The name of the variable that will have
199 * values assigned to it. */
200 Tcl_DictSearch search; /* The dictionary search structure. */
201 Tcl_Obj *scriptObj; /* The script to evaluate each time through
203 Tcl_Obj *accumulatorObj; /* The dictionary used to accumulate the
207 /***** START OF FUNCTIONS IMPLEMENTING DICT CORE API *****/
210 *----------------------------------------------------------------------
214 * Allocate space for a Tcl_HashEntry containing the Tcl_Obj * key, and
215 * which has a bit of extra space afterwards for storing pointers to the
216 * rest of the chain of entries (the extra pointers are left NULL).
219 * The return value is a pointer to the created entry.
222 * Increments the reference count on the object.
224 *----------------------------------------------------------------------
227 static Tcl_HashEntry *
229 Tcl_HashTable *tablePtr,
232 Tcl_Obj *objPtr = keyPtr;
235 cPtr = ckalloc(sizeof(ChainEntry));
236 cPtr->entry.key.objPtr = objPtr;
237 Tcl_IncrRefCount(objPtr);
238 cPtr->entry.clientData = NULL;
239 cPtr->prevPtr = cPtr->nextPtr = NULL;
245 * Helper functions that disguise most of the details relating to how the
246 * linked list of hash entries is managed. In particular, these manage the
247 * creation of the table and initializing of the chain, the deletion of the
248 * table and chain, the adding of an entry to the chain, and the removal of an
249 * entry from the chain.
256 Tcl_InitCustomHashTable(&dict->table, TCL_CUSTOM_PTR_KEYS,
258 dict->entryChainHead = dict->entryChainTail = NULL;
267 for (cPtr=dict->entryChainHead ; cPtr!=NULL ; cPtr=cPtr->nextPtr) {
268 Tcl_Obj *valuePtr = Tcl_GetHashValue(&cPtr->entry);
270 TclDecrRefCount(valuePtr);
272 Tcl_DeleteHashTable(&dict->table);
275 static inline Tcl_HashEntry *
281 ChainEntry *cPtr = (ChainEntry *)
282 Tcl_CreateHashEntry(&dict->table, keyPtr, newPtr);
285 * If this is a new entry in the hash table, stitch it into the chain.
289 cPtr->nextPtr = NULL;
290 if (dict->entryChainHead == NULL) {
291 cPtr->prevPtr = NULL;
292 dict->entryChainHead = cPtr;
293 dict->entryChainTail = cPtr;
295 cPtr->prevPtr = dict->entryChainTail;
296 dict->entryChainTail->nextPtr = cPtr;
297 dict->entryChainTail = cPtr;
309 ChainEntry *cPtr = (ChainEntry *)
310 Tcl_FindHashEntry(&dict->table, keyPtr);
315 Tcl_Obj *valuePtr = Tcl_GetHashValue(&cPtr->entry);
317 TclDecrRefCount(valuePtr);
321 * Unstitch from the chain.
325 cPtr->nextPtr->prevPtr = cPtr->prevPtr;
327 dict->entryChainTail = cPtr->prevPtr;
330 cPtr->prevPtr->nextPtr = cPtr->nextPtr;
332 dict->entryChainHead = cPtr->nextPtr;
335 Tcl_DeleteHashEntry(&cPtr->entry);
340 *----------------------------------------------------------------------
342 * DupDictInternalRep --
344 * Initialize the internal representation of a dictionary Tcl_Obj to a
345 * copy of the internal representation of an existing dictionary object.
351 * "srcPtr"s dictionary internal rep pointer should not be NULL and we
352 * assume it is not NULL. We set "copyPtr"s internal rep to a pointer to
353 * a newly allocated dictionary rep that, in turn, points to "srcPtr"s
354 * key and value objects. Those objects are not actually copied but are
355 * shared between "srcPtr" and "copyPtr". The ref count of each key and
356 * value object is incremented.
358 *----------------------------------------------------------------------
366 Dict *oldDict = DICT(srcPtr);
367 Dict *newDict = ckalloc(sizeof(Dict));
371 * Copy values across from the old hash table.
374 InitChainTable(newDict);
375 for (cPtr=oldDict->entryChainHead ; cPtr!=NULL ; cPtr=cPtr->nextPtr) {
376 Tcl_Obj *key = Tcl_GetHashKey(&oldDict->table, &cPtr->entry);
377 Tcl_Obj *valuePtr = Tcl_GetHashValue(&cPtr->entry);
379 Tcl_HashEntry *hPtr = CreateChainEntry(newDict, key, &n);
382 * Fill in the contents.
385 Tcl_SetHashValue(hPtr, valuePtr);
386 Tcl_IncrRefCount(valuePtr);
390 * Initialise other fields.
394 newDict->chain = NULL;
395 newDict->refCount = 1;
398 * Store in the object.
401 DICT(copyPtr) = newDict;
402 copyPtr->internalRep.twoPtrValue.ptr2 = NULL;
403 copyPtr->typePtr = &tclDictType;
407 *----------------------------------------------------------------------
409 * FreeDictInternalRep --
411 * Deallocate the storage associated with a dictionary object's internal
418 * Frees the memory holding the dictionary's internal hash table unless
419 * it is locked by an iteration going over it.
421 *----------------------------------------------------------------------
428 Dict *dict = DICT(dictPtr);
430 if (dict->refCount-- <= 1) {
433 dictPtr->typePtr = NULL;
437 *----------------------------------------------------------------------
441 * Delete the structure that is used to implement a dictionary's internal
442 * representation. Called when either the dictionary object loses its
443 * internal representation or when the last iteration over the dictionary
450 * Decrements the reference count of all key and value objects in the
451 * dictionary, which may free them.
453 *----------------------------------------------------------------------
460 DeleteChainTable(dict);
465 *----------------------------------------------------------------------
467 * UpdateStringOfDict --
469 * Update the string representation for a dictionary object. Note: This
470 * function does not invalidate an existing old string rep so storage
471 * will be lost if this has not already been done. This code is based on
472 * UpdateStringOfList in tclListObj.c
478 * The object's string is set to a valid string that results from the
479 * dict-to-string conversion. This string will be empty if the dictionary
480 * has no key/value pairs. The dictionary internal representation should
481 * not be NULL and we assume it is not NULL.
483 *----------------------------------------------------------------------
490 #define LOCAL_SIZE 64
491 char localFlags[LOCAL_SIZE], *flagPtr = NULL;
492 Dict *dict = DICT(dictPtr);
494 Tcl_Obj *keyPtr, *valuePtr;
495 int i, length, bytesNeeded = 0;
500 * This field is the most useful one in the whole hash structure, and it
501 * is not exposed by any API function...
504 int numElems = dict->table.numEntries * 2;
506 /* Handle empty list case first, simplifies what follows */
508 dictPtr->bytes = tclEmptyStringRep;
514 * Pass 1: estimate space, gather flags.
517 if (numElems <= LOCAL_SIZE) {
518 flagPtr = localFlags;
520 flagPtr = ckalloc(numElems);
522 for (i=0,cPtr=dict->entryChainHead; i<numElems; i+=2,cPtr=cPtr->nextPtr) {
524 * Assume that cPtr is never NULL since we know the number of array
528 flagPtr[i] = ( i ? TCL_DONT_QUOTE_HASH : 0 );
529 keyPtr = Tcl_GetHashKey(&dict->table, &cPtr->entry);
530 elem = TclGetStringFromObj(keyPtr, &length);
531 bytesNeeded += TclScanElement(elem, length, flagPtr+i);
532 if (bytesNeeded < 0) {
533 Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX);
536 flagPtr[i+1] = TCL_DONT_QUOTE_HASH;
537 valuePtr = Tcl_GetHashValue(&cPtr->entry);
538 elem = TclGetStringFromObj(valuePtr, &length);
539 bytesNeeded += TclScanElement(elem, length, flagPtr+i+1);
540 if (bytesNeeded < 0) {
541 Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX);
544 if (bytesNeeded > INT_MAX - numElems + 1) {
545 Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX);
547 bytesNeeded += numElems;
550 * Pass 2: copy into string rep buffer.
553 dictPtr->length = bytesNeeded - 1;
554 dictPtr->bytes = ckalloc(bytesNeeded);
555 dst = dictPtr->bytes;
556 for (i=0,cPtr=dict->entryChainHead; i<numElems; i+=2,cPtr=cPtr->nextPtr) {
557 flagPtr[i] |= ( i ? TCL_DONT_QUOTE_HASH : 0 );
558 keyPtr = Tcl_GetHashKey(&dict->table, &cPtr->entry);
559 elem = TclGetStringFromObj(keyPtr, &length);
560 dst += TclConvertElement(elem, length, dst, flagPtr[i]);
563 flagPtr[i+1] |= TCL_DONT_QUOTE_HASH;
564 valuePtr = Tcl_GetHashValue(&cPtr->entry);
565 elem = TclGetStringFromObj(valuePtr, &length);
566 dst += TclConvertElement(elem, length, dst, flagPtr[i+1]);
569 dictPtr->bytes[dictPtr->length] = '\0';
571 if (flagPtr != localFlags) {
577 *----------------------------------------------------------------------
581 * Convert a non-dictionary object into a dictionary object. This code is
582 * very closely related to SetListFromAny in tclListObj.c but does not
583 * actually guarantee that a dictionary object will have a string rep (as
584 * conversions from lists are handled with a special case.)
587 * A standard Tcl result.
590 * If the string can be converted, it loses any old internal
591 * representation that it had and gains a dictionary's internalRep.
593 *----------------------------------------------------------------------
603 Dict *dict = ckalloc(sizeof(Dict));
605 InitChainTable(dict);
608 * Since lists and dictionaries have very closely-related string
609 * representations (i.e. the same parsing code) we can safely special-case
610 * the conversion from lists to dictionaries.
613 if (objPtr->typePtr == &tclListType) {
617 /* Cannot fail, we already know the Tcl_ObjType is "list". */
618 TclListObjGetElements(NULL, objPtr, &objc, &objv);
623 for (i=0 ; i<objc ; i+=2) {
625 /* Store key and value in the hash table we're building. */
626 hPtr = CreateChainEntry(dict, objv[i], &isNew);
628 Tcl_Obj *discardedValue = Tcl_GetHashValue(hPtr);
631 * Not really a well-formed dictionary as there are duplicate
632 * keys, so better get the string rep here so that we can
636 (void) Tcl_GetString(objPtr);
638 TclDecrRefCount(discardedValue);
640 Tcl_SetHashValue(hPtr, objv[i+1]);
641 Tcl_IncrRefCount(objv[i+1]); /* Since hash now holds ref to it */
645 const char *nextElem = TclGetStringFromObj(objPtr, &length);
646 const char *limit = (nextElem + length);
648 while (nextElem < limit) {
649 Tcl_Obj *keyPtr, *valuePtr;
650 const char *elemStart;
651 int elemSize, literal;
653 if (TclFindDictElement(interp, nextElem, (limit - nextElem),
654 &elemStart, &nextElem, &elemSize, &literal) != TCL_OK) {
655 goto errorInFindDictElement;
657 if (elemStart == limit) {
660 if (nextElem == limit) {
665 TclNewStringObj(keyPtr, elemStart, elemSize);
667 /* Avoid double copy */
669 keyPtr->bytes = ckalloc((unsigned) elemSize + 1);
670 keyPtr->length = TclCopyAndCollapse(elemSize, elemStart,
674 if (TclFindDictElement(interp, nextElem, (limit - nextElem),
675 &elemStart, &nextElem, &elemSize, &literal) != TCL_OK) {
676 TclDecrRefCount(keyPtr);
677 goto errorInFindDictElement;
681 TclNewStringObj(valuePtr, elemStart, elemSize);
683 /* Avoid double copy */
685 valuePtr->bytes = ckalloc((unsigned) elemSize + 1);
686 valuePtr->length = TclCopyAndCollapse(elemSize, elemStart,
690 /* Store key and value in the hash table we're building. */
691 hPtr = CreateChainEntry(dict, keyPtr, &isNew);
693 Tcl_Obj *discardedValue = Tcl_GetHashValue(hPtr);
695 TclDecrRefCount(keyPtr);
696 TclDecrRefCount(discardedValue);
698 Tcl_SetHashValue(hPtr, valuePtr);
699 Tcl_IncrRefCount(valuePtr); /* since hash now holds ref to it */
704 * Free the old internalRep before setting the new one. We do this as late
705 * as possible to allow the conversion code, in particular
706 * Tcl_GetStringFromObj, to use that old internalRep.
709 TclFreeIntRep(objPtr);
714 objPtr->internalRep.twoPtrValue.ptr2 = NULL;
715 objPtr->typePtr = &tclDictType;
719 if (interp != NULL) {
720 Tcl_SetObjResult(interp, Tcl_NewStringObj(
721 "missing value to go with key", -1));
722 Tcl_SetErrorCode(interp, "TCL", "VALUE", "DICTIONARY", NULL);
724 errorInFindDictElement:
725 DeleteChainTable(dict);
731 *----------------------------------------------------------------------
733 * TclTraceDictPath --
735 * Trace through a tree of dictionaries using the array of keys given. If
736 * the flags argument has the DICT_PATH_UPDATE flag is set, a
737 * backward-pointing chain of dictionaries is also built (in the Dict's
738 * chain field) and the chained dictionaries are made into unshared
739 * dictionaries (if they aren't already.)
742 * The object at the end of the path, or NULL if there was an error. Note
743 * that this it is an error for an intermediate dictionary on the path to
744 * not exist. If the flags argument has the DICT_PATH_EXISTS set, a
745 * non-existent path gives a DICT_PATH_NON_EXISTENT result.
748 * If the flags argument is zero or DICT_PATH_EXISTS, there are no side
749 * effects (other than potential conversion of objects to dictionaries.)
750 * If the flags argument is DICT_PATH_UPDATE, the following additional
751 * side effects occur. Shared dictionaries along the path are converted
752 * into unshared objects, and a backward-pointing chain is built using
753 * the chain fields of the dictionaries (for easy invalidation of string
754 * representations using InvalidateDictChain). If the flags argument has
755 * the DICT_PATH_CREATE bits set (and not the DICT_PATH_EXISTS bit),
756 * non-existant keys will be inserted with a value of an empty
757 * dictionary, resulting in the path being built.
759 *----------------------------------------------------------------------
767 Tcl_Obj *const keyv[],
770 Dict *dict, *newDict;
773 if (dictPtr->typePtr != &tclDictType
774 && SetDictFromAny(interp, dictPtr) != TCL_OK) {
777 dict = DICT(dictPtr);
778 if (flags & DICT_PATH_UPDATE) {
782 for (i=0 ; i<keyc ; i++) {
783 Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&dict->table, keyv[i]);
787 int isNew; /* Dummy */
789 if (flags & DICT_PATH_EXISTS) {
790 return DICT_PATH_NON_EXISTENT;
792 if ((flags & DICT_PATH_CREATE) != DICT_PATH_CREATE) {
793 if (interp != NULL) {
794 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
795 "key \"%s\" not known in dictionary",
796 TclGetString(keyv[i])));
797 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "DICT",
798 TclGetString(keyv[i]), NULL);
804 * The next line should always set isNew to 1.
807 hPtr = CreateChainEntry(dict, keyv[i], &isNew);
808 tmpObj = Tcl_NewDictObj();
809 Tcl_IncrRefCount(tmpObj);
810 Tcl_SetHashValue(hPtr, tmpObj);
812 tmpObj = Tcl_GetHashValue(hPtr);
813 if (tmpObj->typePtr != &tclDictType
814 && SetDictFromAny(interp, tmpObj) != TCL_OK) {
819 newDict = DICT(tmpObj);
820 if (flags & DICT_PATH_UPDATE) {
821 if (Tcl_IsShared(tmpObj)) {
822 TclDecrRefCount(tmpObj);
823 tmpObj = Tcl_DuplicateObj(tmpObj);
824 Tcl_IncrRefCount(tmpObj);
825 Tcl_SetHashValue(hPtr, tmpObj);
827 newDict = DICT(tmpObj);
830 newDict->chain = dictPtr;
839 *----------------------------------------------------------------------
841 * InvalidateDictChain --
843 * Go through a dictionary chain (built by an updating invokation of
844 * TclTraceDictPath) and invalidate the string representations of all the
845 * dictionaries on the chain.
851 * String reps are invalidated and epoch counters (for detecting illegal
852 * concurrent modifications) are updated through the chain of updated
855 *----------------------------------------------------------------------
862 Dict *dict = DICT(dictObj);
865 TclInvalidateStringRep(dictObj);
867 dictObj = dict->chain;
868 if (dictObj == NULL) {
872 dict = DICT(dictObj);
873 } while (dict != NULL);
877 *----------------------------------------------------------------------
881 * Add a key,value pair to a dictionary, or update the value for a key if
882 * that key already has a mapping in the dictionary.
885 * A standard Tcl result.
888 * The object pointed to by dictPtr is converted to a dictionary if it is
889 * not already one, and any string representation that it has is
892 *----------------------------------------------------------------------
906 if (Tcl_IsShared(dictPtr)) {
907 Tcl_Panic("%s called with shared object", "Tcl_DictObjPut");
910 if (dictPtr->typePtr != &tclDictType
911 && SetDictFromAny(interp, dictPtr) != TCL_OK) {
915 if (dictPtr->bytes != NULL) {
916 TclInvalidateStringRep(dictPtr);
918 dict = DICT(dictPtr);
919 hPtr = CreateChainEntry(dict, keyPtr, &isNew);
920 Tcl_IncrRefCount(valuePtr);
922 Tcl_Obj *oldValuePtr = Tcl_GetHashValue(hPtr);
924 TclDecrRefCount(oldValuePtr);
926 Tcl_SetHashValue(hPtr, valuePtr);
932 *----------------------------------------------------------------------
936 * Given a key, get its value from the dictionary (or NULL if key is not
937 * found in dictionary.)
940 * A standard Tcl result. The variable pointed to by valuePtrPtr is
941 * updated with the value for the key. Note that it is not an error for
942 * the key to have no mapping in the dictionary.
945 * The object pointed to by dictPtr is converted to a dictionary if it is
948 *----------------------------------------------------------------------
956 Tcl_Obj **valuePtrPtr)
961 if (dictPtr->typePtr != &tclDictType
962 && SetDictFromAny(interp, dictPtr) != TCL_OK) {
967 dict = DICT(dictPtr);
968 hPtr = Tcl_FindHashEntry(&dict->table, keyPtr);
972 *valuePtrPtr = Tcl_GetHashValue(hPtr);
978 *----------------------------------------------------------------------
980 * Tcl_DictObjRemove --
982 * Remove the key,value pair with the given key from the dictionary; the
983 * key does not need to be present in the dictionary.
986 * A standard Tcl result.
989 * The object pointed to by dictPtr is converted to a dictionary if it is
990 * not already one, and any string representation that it has is
993 *----------------------------------------------------------------------
1004 if (Tcl_IsShared(dictPtr)) {
1005 Tcl_Panic("%s called with shared object", "Tcl_DictObjRemove");
1008 if (dictPtr->typePtr != &tclDictType
1009 && SetDictFromAny(interp, dictPtr) != TCL_OK) {
1013 dict = DICT(dictPtr);
1014 if (DeleteChainEntry(dict, keyPtr)) {
1015 if (dictPtr->bytes != NULL) {
1016 TclInvalidateStringRep(dictPtr);
1024 *----------------------------------------------------------------------
1026 * Tcl_DictObjSize --
1028 * How many key,value pairs are there in the dictionary?
1031 * A standard Tcl result. Updates the variable pointed to by sizePtr with
1032 * the number of key,value pairs in the dictionary.
1035 * The dictPtr object is converted to a dictionary type if it is not a
1036 * dictionary already.
1038 *----------------------------------------------------------------------
1049 if (dictPtr->typePtr != &tclDictType
1050 && SetDictFromAny(interp, dictPtr) != TCL_OK) {
1054 dict = DICT(dictPtr);
1055 *sizePtr = dict->table.numEntries;
1060 *----------------------------------------------------------------------
1062 * Tcl_DictObjFirst --
1064 * Start a traversal of the dictionary. Caller must supply the search
1065 * context, pointers for returning key and value, and a pointer to allow
1066 * indication of whether the dictionary has been traversed (i.e. the
1067 * dictionary is empty). The order of traversal is undefined.
1070 * A standard Tcl result. Updates the variables pointed to by keyPtrPtr,
1071 * valuePtrPtr and donePtr. Either of keyPtrPtr and valuePtrPtr may be
1072 * NULL, in which case the key/value is not made available to the caller.
1075 * The dictPtr object is converted to a dictionary type if it is not a
1076 * dictionary already. The search context is initialised if the search
1077 * has not finished. The dictionary's internal rep is Tcl_Preserve()d if
1078 * the dictionary has at least one element.
1080 *----------------------------------------------------------------------
1085 Tcl_Interp *interp, /* For error messages, or NULL if no error
1086 * messages desired. */
1087 Tcl_Obj *dictPtr, /* Dictionary to traverse. */
1088 Tcl_DictSearch *searchPtr, /* Pointer to a dict search context. */
1089 Tcl_Obj **keyPtrPtr, /* Pointer to a variable to have the first key
1090 * written into, or NULL. */
1091 Tcl_Obj **valuePtrPtr, /* Pointer to a variable to have the first
1092 * value written into, or NULL.*/
1093 int *donePtr) /* Pointer to a variable which will have a 1
1094 * written into when there are no further
1095 * values in the dictionary, or a 0
1101 if (dictPtr->typePtr != &tclDictType
1102 && SetDictFromAny(interp, dictPtr) != TCL_OK) {
1106 dict = DICT(dictPtr);
1107 cPtr = dict->entryChainHead;
1109 searchPtr->epoch = -1;
1113 searchPtr->dictionaryPtr = (Tcl_Dict) dict;
1114 searchPtr->epoch = dict->epoch;
1115 searchPtr->next = cPtr->nextPtr;
1117 if (keyPtrPtr != NULL) {
1118 *keyPtrPtr = Tcl_GetHashKey(&dict->table, &cPtr->entry);
1120 if (valuePtrPtr != NULL) {
1121 *valuePtrPtr = Tcl_GetHashValue(&cPtr->entry);
1128 *----------------------------------------------------------------------
1130 * Tcl_DictObjNext --
1132 * Continue a traversal of a dictionary previously started with
1133 * Tcl_DictObjFirst. This function is safe against concurrent
1134 * modification of the underlying object (including type shimmering),
1135 * treating such situations as if the search has terminated, though it is
1136 * up to the caller to ensure that the object itself is not disposed
1137 * until the search has finished. It is _not_ safe against modifications
1138 * from other threads.
1141 * Updates the variables pointed to by keyPtrPtr, valuePtrPtr and
1142 * donePtr. Either of keyPtrPtr and valuePtrPtr may be NULL, in which
1143 * case the key/value is not made available to the caller.
1146 * Removes a reference to the dictionary's internal rep if the search
1149 *----------------------------------------------------------------------
1154 Tcl_DictSearch *searchPtr, /* Pointer to a hash search context. */
1155 Tcl_Obj **keyPtrPtr, /* Pointer to a variable to have the first key
1156 * written into, or NULL. */
1157 Tcl_Obj **valuePtrPtr, /* Pointer to a variable to have the first
1158 * value written into, or NULL.*/
1159 int *donePtr) /* Pointer to a variable which will have a 1
1160 * written into when there are no further
1161 * values in the dictionary, or a 0
1167 * If the searh is done; we do no work.
1170 if (searchPtr->epoch == -1) {
1176 * Bail out if the dictionary has had any elements added, modified or
1177 * removed. This *shouldn't* happen, but...
1180 if (((Dict *)searchPtr->dictionaryPtr)->epoch != searchPtr->epoch) {
1181 Tcl_Panic("concurrent dictionary modification and search");
1184 cPtr = searchPtr->next;
1186 Tcl_DictObjDone(searchPtr);
1191 searchPtr->next = cPtr->nextPtr;
1193 if (keyPtrPtr != NULL) {
1194 *keyPtrPtr = Tcl_GetHashKey(
1195 &((Dict *)searchPtr->dictionaryPtr)->table, &cPtr->entry);
1197 if (valuePtrPtr != NULL) {
1198 *valuePtrPtr = Tcl_GetHashValue(&cPtr->entry);
1203 *----------------------------------------------------------------------
1205 * Tcl_DictObjDone --
1207 * Call this if you want to stop a search before you reach the end of the
1208 * dictionary (e.g. because of abnormal termination of the search). It
1209 * need not be used if the search reaches its natural end (i.e. if either
1210 * Tcl_DictObjFirst or Tcl_DictObjNext sets its donePtr variable to 1).
1216 * Removes a reference to the dictionary's internal rep.
1218 *----------------------------------------------------------------------
1223 Tcl_DictSearch *searchPtr) /* Pointer to a hash search context. */
1227 if (searchPtr->epoch != -1) {
1228 searchPtr->epoch = -1;
1229 dict = (Dict *) searchPtr->dictionaryPtr;
1230 if (dict->refCount-- <= 1) {
1237 *----------------------------------------------------------------------
1239 * Tcl_DictObjPutKeyList --
1241 * Add a key...key,value pair to a dictionary tree. The main dictionary
1242 * value must not be shared, though sub-dictionaries may be. All
1243 * intermediate dictionaries on the path must exist.
1246 * A standard Tcl result. Note that in the error case, a message is left
1247 * in interp unless that is NULL.
1250 * If the dictionary and any of its sub-dictionaries on the path have
1251 * string representations, these are invalidated.
1253 *----------------------------------------------------------------------
1257 Tcl_DictObjPutKeyList(
1261 Tcl_Obj *const keyv[],
1265 Tcl_HashEntry *hPtr;
1268 if (Tcl_IsShared(dictPtr)) {
1269 Tcl_Panic("%s called with shared object", "Tcl_DictObjPutKeyList");
1272 Tcl_Panic("%s called with empty key list", "Tcl_DictObjPutKeyList");
1275 dictPtr = TclTraceDictPath(interp, dictPtr, keyc-1,keyv, DICT_PATH_CREATE);
1276 if (dictPtr == NULL) {
1280 dict = DICT(dictPtr);
1281 hPtr = CreateChainEntry(dict, keyv[keyc-1], &isNew);
1282 Tcl_IncrRefCount(valuePtr);
1284 Tcl_Obj *oldValuePtr = Tcl_GetHashValue(hPtr);
1286 TclDecrRefCount(oldValuePtr);
1288 Tcl_SetHashValue(hPtr, valuePtr);
1289 InvalidateDictChain(dictPtr);
1295 *----------------------------------------------------------------------
1297 * Tcl_DictObjRemoveKeyList --
1299 * Remove a key...key,value pair from a dictionary tree (the value
1300 * removed is implicit in the key path). The main dictionary value must
1301 * not be shared, though sub-dictionaries may be. It is not an error if
1302 * there is no value associated with the given key list, but all
1303 * intermediate dictionaries on the key path must exist.
1306 * A standard Tcl result. Note that in the error case, a message is left
1307 * in interp unless that is NULL.
1310 * If the dictionary and any of its sub-dictionaries on the key path have
1311 * string representations, these are invalidated.
1313 *----------------------------------------------------------------------
1317 Tcl_DictObjRemoveKeyList(
1321 Tcl_Obj *const keyv[])
1325 if (Tcl_IsShared(dictPtr)) {
1326 Tcl_Panic("%s called with shared object", "Tcl_DictObjRemoveKeyList");
1329 Tcl_Panic("%s called with empty key list", "Tcl_DictObjRemoveKeyList");
1332 dictPtr = TclTraceDictPath(interp, dictPtr, keyc-1,keyv, DICT_PATH_UPDATE);
1333 if (dictPtr == NULL) {
1337 dict = DICT(dictPtr);
1338 DeleteChainEntry(dict, keyv[keyc-1]);
1339 InvalidateDictChain(dictPtr);
1344 *----------------------------------------------------------------------
1348 * This function is normally called when not debugging: i.e., when
1349 * TCL_MEM_DEBUG is not defined. It creates a new dict object without any
1352 * When TCL_MEM_DEBUG is defined, this function just returns the result
1353 * of calling the debugging version Tcl_DbNewDictObj.
1356 * A new dict object is returned; it has no keys defined in it. The new
1357 * object's string representation is left NULL, and the ref count of the
1363 *----------------------------------------------------------------------
1367 Tcl_NewDictObj(void)
1369 #ifdef TCL_MEM_DEBUG
1370 return Tcl_DbNewDictObj("unknown", 0);
1371 #else /* !TCL_MEM_DEBUG */
1377 TclInvalidateStringRep(dictPtr);
1378 dict = ckalloc(sizeof(Dict));
1379 InitChainTable(dict);
1383 DICT(dictPtr) = dict;
1384 dictPtr->internalRep.twoPtrValue.ptr2 = NULL;
1385 dictPtr->typePtr = &tclDictType;
1391 *----------------------------------------------------------------------
1393 * Tcl_DbNewDictObj --
1395 * This function is normally called when debugging: i.e., when
1396 * TCL_MEM_DEBUG is defined. It creates new dict objects. It is the same
1397 * as the Tcl_NewDictObj function above except that it calls
1398 * Tcl_DbCkalloc directly with the file name and line number from its
1399 * caller. This simplifies debugging since then the [memory active]
1400 * command will report the correct file name and line number when
1401 * reporting objects that haven't been freed.
1403 * When TCL_MEM_DEBUG is not defined, this function just returns the
1404 * result of calling Tcl_NewDictObj.
1407 * A new dict object is returned; it has no keys defined in it. The new
1408 * object's string representation is left NULL, and the ref count of the
1414 *----------------------------------------------------------------------
1422 #ifdef TCL_MEM_DEBUG
1426 TclDbNewObj(dictPtr, file, line);
1427 TclInvalidateStringRep(dictPtr);
1428 dict = ckalloc(sizeof(Dict));
1429 InitChainTable(dict);
1433 DICT(dictPtr) = dict;
1434 dictPtr->internalRep.twoPtrValue.ptr2 = NULL;
1435 dictPtr->typePtr = &tclDictType;
1437 #else /* !TCL_MEM_DEBUG */
1438 return Tcl_NewDictObj();
1442 /***** START OF FUNCTIONS IMPLEMENTING TCL COMMANDS *****/
1445 *----------------------------------------------------------------------
1449 * This function implements the "dict create" Tcl command. See the user
1450 * documentation for details on what it does, and TIP#111 for the formal
1454 * A standard Tcl result.
1457 * See the user documentation.
1459 *----------------------------------------------------------------------
1467 Tcl_Obj *const *objv)
1473 * Must have an even number of arguments; note that number of preceding
1474 * arguments (i.e. "dict create" is also even, which makes this much
1478 if ((objc & 1) == 0) {
1479 Tcl_WrongNumArgs(interp, 1, objv, "?key value ...?");
1483 dictObj = Tcl_NewDictObj();
1484 for (i=1 ; i<objc ; i+=2) {
1486 * The next command is assumed to never fail...
1488 Tcl_DictObjPut(NULL, dictObj, objv[i], objv[i+1]);
1490 Tcl_SetObjResult(interp, dictObj);
1495 *----------------------------------------------------------------------
1499 * This function implements the "dict get" Tcl command. See the user
1500 * documentation for details on what it does, and TIP#111 for the formal
1504 * A standard Tcl result.
1507 * See the user documentation.
1509 *----------------------------------------------------------------------
1517 Tcl_Obj *const *objv)
1519 Tcl_Obj *dictPtr, *valuePtr = NULL;
1523 Tcl_WrongNumArgs(interp, 1, objv, "dictionary ?key ...?");
1528 * Test for the special case of no keys, which returns a *list* of all
1529 * key,value pairs. We produce a copy here because that makes subsequent
1530 * list handling more efficient.
1534 Tcl_Obj *keyPtr = NULL, *listPtr;
1535 Tcl_DictSearch search;
1538 result = Tcl_DictObjFirst(interp, objv[1], &search,
1539 &keyPtr, &valuePtr, &done);
1540 if (result != TCL_OK) {
1543 listPtr = Tcl_NewListObj(0, NULL);
1546 * Assume these won't fail as we have complete control over the
1547 * types of things here.
1550 Tcl_ListObjAppendElement(interp, listPtr, keyPtr);
1551 Tcl_ListObjAppendElement(interp, listPtr, valuePtr);
1553 Tcl_DictObjNext(&search, &keyPtr, &valuePtr, &done);
1555 Tcl_SetObjResult(interp, listPtr);
1560 * Loop through the list of keys, looking up the key at the current index
1561 * in the current dictionary each time. Once we've done the lookup, we set
1562 * the current dictionary to be the value we looked up (in case the value
1563 * was not the last one and we are going through a chain of searches.)
1564 * Note that this loop always executes at least once.
1567 dictPtr = TclTraceDictPath(interp, objv[1], objc-3,objv+2, DICT_PATH_READ);
1568 if (dictPtr == NULL) {
1571 result = Tcl_DictObjGet(interp, dictPtr, objv[objc-1], &valuePtr);
1572 if (result != TCL_OK) {
1575 if (valuePtr == NULL) {
1576 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
1577 "key \"%s\" not known in dictionary",
1578 TclGetString(objv[objc-1])));
1579 Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "DICT",
1580 TclGetString(objv[objc-1]), NULL);
1583 Tcl_SetObjResult(interp, valuePtr);
1588 *----------------------------------------------------------------------
1592 * This function implements the "dict replace" Tcl command. See the user
1593 * documentation for details on what it does, and TIP#111 for the formal
1597 * A standard Tcl result.
1600 * See the user documentation.
1602 *----------------------------------------------------------------------
1610 Tcl_Obj *const *objv)
1615 if ((objc < 2) || (objc & 1)) {
1616 Tcl_WrongNumArgs(interp, 1, objv, "dictionary ?key value ...?");
1621 if (dictPtr->typePtr != &tclDictType
1622 && SetDictFromAny(interp, dictPtr) != TCL_OK) {
1625 if (Tcl_IsShared(dictPtr)) {
1626 dictPtr = Tcl_DuplicateObj(dictPtr);
1628 if (dictPtr->bytes != NULL) {
1629 TclInvalidateStringRep(dictPtr);
1631 for (i=2 ; i<objc ; i+=2) {
1632 Tcl_DictObjPut(NULL, dictPtr, objv[i], objv[i+1]);
1634 Tcl_SetObjResult(interp, dictPtr);
1639 *----------------------------------------------------------------------
1643 * This function implements the "dict remove" Tcl command. See the user
1644 * documentation for details on what it does, and TIP#111 for the formal
1648 * A standard Tcl result.
1651 * See the user documentation.
1653 *----------------------------------------------------------------------
1661 Tcl_Obj *const *objv)
1667 Tcl_WrongNumArgs(interp, 1, objv, "dictionary ?key ...?");
1672 if (dictPtr->typePtr != &tclDictType
1673 && SetDictFromAny(interp, dictPtr) != TCL_OK) {
1676 if (Tcl_IsShared(dictPtr)) {
1677 dictPtr = Tcl_DuplicateObj(dictPtr);
1679 if (dictPtr->bytes != NULL) {
1680 TclInvalidateStringRep(dictPtr);
1682 for (i=2 ; i<objc ; i++) {
1683 Tcl_DictObjRemove(NULL, dictPtr, objv[i]);
1685 Tcl_SetObjResult(interp, dictPtr);
1690 *----------------------------------------------------------------------
1694 * This function implements the "dict merge" Tcl command. See the user
1695 * documentation for details on what it does, and TIP#163 for the formal
1699 * A standard Tcl result.
1702 * See the user documentation.
1704 *----------------------------------------------------------------------
1712 Tcl_Obj *const *objv)
1714 Tcl_Obj *targetObj, *keyObj = NULL, *valueObj = NULL;
1715 int allocatedDict = 0;
1717 Tcl_DictSearch search;
1721 * No dictionary arguments; return default (empty value).
1728 * Make sure first argument is a dictionary.
1731 targetObj = objv[1];
1732 if (targetObj->typePtr != &tclDictType
1733 && SetDictFromAny(interp, targetObj) != TCL_OK) {
1739 * Single argument, return it.
1742 Tcl_SetObjResult(interp, objv[1]);
1747 * Normal behaviour: combining two (or more) dictionaries.
1750 if (Tcl_IsShared(targetObj)) {
1751 targetObj = Tcl_DuplicateObj(targetObj);
1754 for (i=2 ; i<objc ; i++) {
1755 if (Tcl_DictObjFirst(interp, objv[i], &search, &keyObj, &valueObj,
1757 if (allocatedDict) {
1758 TclDecrRefCount(targetObj);
1764 * Next line can't fail; already know we have a dictionary in
1768 Tcl_DictObjPut(NULL, targetObj, keyObj, valueObj);
1769 Tcl_DictObjNext(&search, &keyObj, &valueObj, &done);
1771 Tcl_DictObjDone(&search);
1773 Tcl_SetObjResult(interp, targetObj);
1778 *----------------------------------------------------------------------
1782 * This function implements the "dict keys" Tcl command. See the user
1783 * documentation for details on what it does, and TIP#111 for the formal
1787 * A standard Tcl result.
1790 * See the user documentation.
1792 *----------------------------------------------------------------------
1800 Tcl_Obj *const *objv)
1803 const char *pattern = NULL;
1805 if (objc!=2 && objc!=3) {
1806 Tcl_WrongNumArgs(interp, 1, objv, "dictionary ?pattern?");
1811 * A direct check that we have a dictionary. We don't start the iteration
1812 * yet because that might allocate memory or set locks that we do not
1813 * need. [Bug 1705778, leak K04]
1816 if (objv[1]->typePtr != &tclDictType
1817 && SetDictFromAny(interp, objv[1]) != TCL_OK) {
1822 pattern = TclGetString(objv[2]);
1824 listPtr = Tcl_NewListObj(0, NULL);
1825 if ((pattern != NULL) && TclMatchIsTrivial(pattern)) {
1826 Tcl_Obj *valuePtr = NULL;
1828 Tcl_DictObjGet(interp, objv[1], objv[2], &valuePtr);
1829 if (valuePtr != NULL) {
1830 Tcl_ListObjAppendElement(NULL, listPtr, objv[2]);
1833 Tcl_DictSearch search;
1834 Tcl_Obj *keyPtr = NULL;
1838 * At this point, we know we have a dictionary (or at least something
1839 * that can be represented; it could theoretically have shimmered away
1840 * when the pattern was fetched, but that shouldn't be damaging) so we
1841 * can start the iteration process without checking for failures.
1844 Tcl_DictObjFirst(NULL, objv[1], &search, &keyPtr, NULL, &done);
1845 for (; !done ; Tcl_DictObjNext(&search, &keyPtr, NULL, &done)) {
1846 if (!pattern || Tcl_StringMatch(TclGetString(keyPtr), pattern)) {
1847 Tcl_ListObjAppendElement(NULL, listPtr, keyPtr);
1850 Tcl_DictObjDone(&search);
1853 Tcl_SetObjResult(interp, listPtr);
1858 *----------------------------------------------------------------------
1862 * This function implements the "dict values" Tcl command. See the user
1863 * documentation for details on what it does, and TIP#111 for the formal
1867 * A standard Tcl result.
1870 * See the user documentation.
1872 *----------------------------------------------------------------------
1880 Tcl_Obj *const *objv)
1882 Tcl_Obj *valuePtr = NULL, *listPtr;
1883 Tcl_DictSearch search;
1885 const char *pattern;
1887 if (objc!=2 && objc!=3) {
1888 Tcl_WrongNumArgs(interp, 1, objv, "dictionary ?pattern?");
1892 if (Tcl_DictObjFirst(interp, objv[1], &search, NULL, &valuePtr,
1897 pattern = TclGetString(objv[2]);
1901 listPtr = Tcl_NewListObj(0, NULL);
1902 for (; !done ; Tcl_DictObjNext(&search, NULL, &valuePtr, &done)) {
1903 if (pattern==NULL || Tcl_StringMatch(TclGetString(valuePtr),pattern)) {
1905 * Assume this operation always succeeds.
1908 Tcl_ListObjAppendElement(interp, listPtr, valuePtr);
1911 Tcl_DictObjDone(&search);
1913 Tcl_SetObjResult(interp, listPtr);
1918 *----------------------------------------------------------------------
1922 * This function implements the "dict size" Tcl command. See the user
1923 * documentation for details on what it does, and TIP#111 for the formal
1927 * A standard Tcl result.
1930 * See the user documentation.
1932 *----------------------------------------------------------------------
1940 Tcl_Obj *const *objv)
1945 Tcl_WrongNumArgs(interp, 1, objv, "dictionary");
1948 result = Tcl_DictObjSize(interp, objv[1], &size);
1949 if (result == TCL_OK) {
1950 Tcl_SetObjResult(interp, Tcl_NewIntObj(size));
1956 *----------------------------------------------------------------------
1960 * This function implements the "dict exists" Tcl command. See the user
1961 * documentation for details on what it does, and TIP#111 for the formal
1965 * A standard Tcl result.
1968 * See the user documentation.
1970 *----------------------------------------------------------------------
1978 Tcl_Obj *const *objv)
1980 Tcl_Obj *dictPtr, *valuePtr;
1983 Tcl_WrongNumArgs(interp, 1, objv, "dictionary key ?key ...?");
1987 dictPtr = TclTraceDictPath(interp, objv[1], objc-3, objv+2,
1989 if (dictPtr == NULL || dictPtr == DICT_PATH_NON_EXISTENT
1990 || Tcl_DictObjGet(interp, dictPtr, objv[objc-1],
1991 &valuePtr) != TCL_OK) {
1992 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0));
1994 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(valuePtr != NULL));
2000 *----------------------------------------------------------------------
2004 * This function implements the "dict info" Tcl command. See the user
2005 * documentation for details on what it does, and TIP#111 for the formal
2009 * A standard Tcl result.
2012 * See the user documentation.
2014 *----------------------------------------------------------------------
2022 Tcl_Obj *const *objv)
2029 Tcl_WrongNumArgs(interp, 1, objv, "dictionary");
2034 if (dictPtr->typePtr != &tclDictType
2035 && SetDictFromAny(interp, dictPtr) != TCL_OK) {
2038 dict = DICT(dictPtr);
2040 statsStr = Tcl_HashStats(&dict->table);
2041 Tcl_SetObjResult(interp, Tcl_NewStringObj(statsStr, -1));
2047 *----------------------------------------------------------------------
2051 * This function implements the "dict incr" Tcl command. See the user
2052 * documentation for details on what it does, and TIP#111 for the formal
2056 * A standard Tcl result.
2059 * See the user documentation.
2061 *----------------------------------------------------------------------
2069 Tcl_Obj *const *objv)
2072 Tcl_Obj *dictPtr, *valuePtr = NULL;
2074 if (objc < 3 || objc > 4) {
2075 Tcl_WrongNumArgs(interp, 1, objv, "dictVarName key ?increment?");
2079 dictPtr = Tcl_ObjGetVar2(interp, objv[1], NULL, 0);
2080 if (dictPtr == NULL) {
2082 * Variable didn't yet exist. Create new dictionary value.
2085 dictPtr = Tcl_NewDictObj();
2086 } else if (Tcl_DictObjGet(interp, dictPtr, objv[2], &valuePtr) != TCL_OK) {
2088 * Variable contents are not a dict, report error.
2093 if (Tcl_IsShared(dictPtr)) {
2095 * A little internals surgery to avoid copying a string rep that will
2099 char *saved = dictPtr->bytes;
2100 Tcl_Obj *oldPtr = dictPtr;
2102 dictPtr->bytes = NULL;
2103 dictPtr = Tcl_DuplicateObj(dictPtr);
2104 oldPtr->bytes = saved;
2106 if (valuePtr == NULL) {
2108 * Key not in dictionary. Create new key with increment as value.
2113 * Verify increment is an integer.
2118 code = Tcl_GetBignumFromObj(interp, objv[3], &increment);
2119 if (code != TCL_OK) {
2120 Tcl_AddErrorInfo(interp, "\n (reading increment)");
2123 * Remember to dispose with the bignum as we're not actually
2124 * using it directly. [Bug 2874678]
2127 mp_clear(&increment);
2128 Tcl_DictObjPut(NULL, dictPtr, objv[2], objv[3]);
2131 Tcl_DictObjPut(NULL, dictPtr, objv[2], Tcl_NewIntObj(1));
2135 * Key in dictionary. Increment its value with minimum dup.
2138 if (Tcl_IsShared(valuePtr)) {
2139 valuePtr = Tcl_DuplicateObj(valuePtr);
2140 Tcl_DictObjPut(NULL, dictPtr, objv[2], valuePtr);
2143 code = TclIncrObj(interp, valuePtr, objv[3]);
2147 TclNewIntObj(incrPtr, 1);
2148 Tcl_IncrRefCount(incrPtr);
2149 code = TclIncrObj(interp, valuePtr, incrPtr);
2150 TclDecrRefCount(incrPtr);
2153 if (code == TCL_OK) {
2154 TclInvalidateStringRep(dictPtr);
2155 valuePtr = Tcl_ObjSetVar2(interp, objv[1], NULL,
2156 dictPtr, TCL_LEAVE_ERR_MSG);
2157 if (valuePtr == NULL) {
2160 Tcl_SetObjResult(interp, valuePtr);
2162 } else if (dictPtr->refCount == 0) {
2163 TclDecrRefCount(dictPtr);
2169 *----------------------------------------------------------------------
2173 * This function implements the "dict lappend" Tcl command. See the user
2174 * documentation for details on what it does, and TIP#111 for the formal
2178 * A standard Tcl result.
2181 * See the user documentation.
2183 *----------------------------------------------------------------------
2191 Tcl_Obj *const *objv)
2193 Tcl_Obj *dictPtr, *valuePtr, *resultPtr;
2194 int i, allocatedDict = 0, allocatedValue = 0;
2197 Tcl_WrongNumArgs(interp, 1, objv, "dictVarName key ?value ...?");
2201 dictPtr = Tcl_ObjGetVar2(interp, objv[1], NULL, 0);
2202 if (dictPtr == NULL) {
2204 dictPtr = Tcl_NewDictObj();
2205 } else if (Tcl_IsShared(dictPtr)) {
2207 dictPtr = Tcl_DuplicateObj(dictPtr);
2210 if (Tcl_DictObjGet(interp, dictPtr, objv[2], &valuePtr) != TCL_OK) {
2211 if (allocatedDict) {
2212 TclDecrRefCount(dictPtr);
2217 if (valuePtr == NULL) {
2218 valuePtr = Tcl_NewListObj(objc-3, objv+3);
2221 if (Tcl_IsShared(valuePtr)) {
2223 valuePtr = Tcl_DuplicateObj(valuePtr);
2226 for (i=3 ; i<objc ; i++) {
2227 if (Tcl_ListObjAppendElement(interp, valuePtr,
2228 objv[i]) != TCL_OK) {
2229 if (allocatedValue) {
2230 TclDecrRefCount(valuePtr);
2232 if (allocatedDict) {
2233 TclDecrRefCount(dictPtr);
2240 if (allocatedValue) {
2241 Tcl_DictObjPut(NULL, dictPtr, objv[2], valuePtr);
2242 } else if (dictPtr->bytes != NULL) {
2243 TclInvalidateStringRep(dictPtr);
2246 resultPtr = Tcl_ObjSetVar2(interp, objv[1], NULL, dictPtr,
2248 if (resultPtr == NULL) {
2251 Tcl_SetObjResult(interp, resultPtr);
2256 *----------------------------------------------------------------------
2260 * This function implements the "dict append" Tcl command. See the user
2261 * documentation for details on what it does, and TIP#111 for the formal
2265 * A standard Tcl result.
2268 * See the user documentation.
2270 *----------------------------------------------------------------------
2278 Tcl_Obj *const *objv)
2280 Tcl_Obj *dictPtr, *valuePtr, *resultPtr;
2281 int i, allocatedDict = 0;
2284 Tcl_WrongNumArgs(interp, 1, objv, "dictVarName key ?value ...?");
2288 dictPtr = Tcl_ObjGetVar2(interp, objv[1], NULL, 0);
2289 if (dictPtr == NULL) {
2291 dictPtr = Tcl_NewDictObj();
2292 } else if (Tcl_IsShared(dictPtr)) {
2294 dictPtr = Tcl_DuplicateObj(dictPtr);
2297 if (Tcl_DictObjGet(interp, dictPtr, objv[2], &valuePtr) != TCL_OK) {
2298 if (allocatedDict) {
2299 TclDecrRefCount(dictPtr);
2304 if (valuePtr == NULL) {
2305 TclNewObj(valuePtr);
2306 } else if (Tcl_IsShared(valuePtr)) {
2307 valuePtr = Tcl_DuplicateObj(valuePtr);
2310 for (i=3 ; i<objc ; i++) {
2311 Tcl_AppendObjToObj(valuePtr, objv[i]);
2314 Tcl_DictObjPut(NULL, dictPtr, objv[2], valuePtr);
2316 resultPtr = Tcl_ObjSetVar2(interp, objv[1], NULL, dictPtr,
2318 if (resultPtr == NULL) {
2321 Tcl_SetObjResult(interp, resultPtr);
2326 *----------------------------------------------------------------------
2330 * These functions implement the "dict for" Tcl command. See the user
2331 * documentation for details on what it does, and TIP#111 for the formal
2335 * A standard Tcl result.
2338 * See the user documentation.
2340 *----------------------------------------------------------------------
2348 Tcl_Obj *const *objv)
2350 Interp *iPtr = (Interp *) interp;
2351 Tcl_Obj *scriptObj, *keyVarObj, *valueVarObj;
2352 Tcl_Obj **varv, *keyObj, *valueObj;
2353 Tcl_DictSearch *searchPtr;
2357 Tcl_WrongNumArgs(interp, 1, objv,
2358 "{keyVarName valueVarName} dictionary script");
2366 if (TclListObjGetElements(interp, objv[1], &varc, &varv) != TCL_OK) {
2370 Tcl_SetObjResult(interp, Tcl_NewStringObj(
2371 "must have exactly two variable names", -1));
2372 Tcl_SetErrorCode(interp, "TCL", "SYNTAX", "dict", "for", NULL);
2375 searchPtr = TclStackAlloc(interp, sizeof(Tcl_DictSearch));
2376 if (Tcl_DictObjFirst(interp, objv[2], searchPtr, &keyObj, &valueObj,
2378 TclStackFree(interp, searchPtr);
2382 TclStackFree(interp, searchPtr);
2385 TclListObjGetElements(NULL, objv[1], &varc, &varv);
2386 keyVarObj = varv[0];
2387 valueVarObj = varv[1];
2388 scriptObj = objv[3];
2391 * Make sure that these objects (which we need throughout the body of the
2392 * loop) don't vanish. Note that the dictionary internal rep is locked
2393 * internally so that updates, shimmering, etc are not a problem.
2396 Tcl_IncrRefCount(keyVarObj);
2397 Tcl_IncrRefCount(valueVarObj);
2398 Tcl_IncrRefCount(scriptObj);
2401 * Stop the value from getting hit in any way by any traces on the key
2405 Tcl_IncrRefCount(valueObj);
2406 if (Tcl_ObjSetVar2(interp, keyVarObj, NULL, keyObj,
2407 TCL_LEAVE_ERR_MSG) == NULL) {
2408 TclDecrRefCount(valueObj);
2411 TclDecrRefCount(valueObj);
2412 if (Tcl_ObjSetVar2(interp, valueVarObj, NULL, valueObj,
2413 TCL_LEAVE_ERR_MSG) == NULL) {
2421 TclNRAddCallback(interp, DictForLoopCallback, searchPtr, keyVarObj,
2422 valueVarObj, scriptObj);
2423 return TclNREvalObjEx(interp, scriptObj, 0, iPtr->cmdFramePtr, 3);
2426 * For unwinding everything on error.
2430 TclDecrRefCount(keyVarObj);
2431 TclDecrRefCount(valueVarObj);
2432 TclDecrRefCount(scriptObj);
2433 Tcl_DictObjDone(searchPtr);
2434 TclStackFree(interp, searchPtr);
2439 DictForLoopCallback(
2444 Interp *iPtr = (Interp *) interp;
2445 Tcl_DictSearch *searchPtr = data[0];
2446 Tcl_Obj *keyVarObj = data[1];
2447 Tcl_Obj *valueVarObj = data[2];
2448 Tcl_Obj *scriptObj = data[3];
2449 Tcl_Obj *keyObj, *valueObj;
2453 * Process the result from the previous execution of the script body.
2456 if (result == TCL_CONTINUE) {
2458 } else if (result != TCL_OK) {
2459 if (result == TCL_BREAK) {
2460 Tcl_ResetResult(interp);
2462 } else if (result == TCL_ERROR) {
2463 Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
2464 "\n (\"dict for\" body line %d)",
2465 Tcl_GetErrorLine(interp)));
2471 * Get the next mapping from the dictionary.
2474 Tcl_DictObjNext(searchPtr, &keyObj, &valueObj, &done);
2476 Tcl_ResetResult(interp);
2481 * Stop the value from getting hit in any way by any traces on the key
2485 Tcl_IncrRefCount(valueObj);
2486 if (Tcl_ObjSetVar2(interp, keyVarObj, NULL, keyObj,
2487 TCL_LEAVE_ERR_MSG) == NULL) {
2488 TclDecrRefCount(valueObj);
2492 TclDecrRefCount(valueObj);
2493 if (Tcl_ObjSetVar2(interp, valueVarObj, NULL, valueObj,
2494 TCL_LEAVE_ERR_MSG) == NULL) {
2503 TclNRAddCallback(interp, DictForLoopCallback, searchPtr, keyVarObj,
2504 valueVarObj, scriptObj);
2505 return TclNREvalObjEx(interp, scriptObj, 0, iPtr->cmdFramePtr, 3);
2508 * For unwinding everything once the iterating is done.
2512 TclDecrRefCount(keyVarObj);
2513 TclDecrRefCount(valueVarObj);
2514 TclDecrRefCount(scriptObj);
2515 Tcl_DictObjDone(searchPtr);
2516 TclStackFree(interp, searchPtr);
2521 *----------------------------------------------------------------------
2525 * These functions implement the "dict map" Tcl command. See the user
2526 * documentation for details on what it does, and TIP#405 for the formal
2530 * A standard Tcl result.
2533 * See the user documentation.
2535 *----------------------------------------------------------------------
2543 Tcl_Obj *const *objv)
2545 Interp *iPtr = (Interp *) interp;
2546 Tcl_Obj **varv, *keyObj, *valueObj;
2547 DictMapStorage *storagePtr;
2551 Tcl_WrongNumArgs(interp, 1, objv,
2552 "{keyVarName valueVarName} dictionary script");
2560 if (TclListObjGetElements(interp, objv[1], &varc, &varv) != TCL_OK) {
2564 Tcl_SetObjResult(interp, Tcl_NewStringObj(
2565 "must have exactly two variable names", -1));
2566 Tcl_SetErrorCode(interp, "TCL", "SYNTAX", "dict", "map", NULL);
2569 storagePtr = TclStackAlloc(interp, sizeof(DictMapStorage));
2570 if (Tcl_DictObjFirst(interp, objv[2], &storagePtr->search, &keyObj,
2571 &valueObj, &done) != TCL_OK) {
2572 TclStackFree(interp, storagePtr);
2577 * Note that this exit leaves an empty value in the result (due to
2578 * command calling conventions) but that is OK since an empty value is
2579 * an empty dictionary.
2582 TclStackFree(interp, storagePtr);
2585 TclNewObj(storagePtr->accumulatorObj);
2586 TclListObjGetElements(NULL, objv[1], &varc, &varv);
2587 storagePtr->keyVarObj = varv[0];
2588 storagePtr->valueVarObj = varv[1];
2589 storagePtr->scriptObj = objv[3];
2592 * Make sure that these objects (which we need throughout the body of the
2593 * loop) don't vanish. Note that the dictionary internal rep is locked
2594 * internally so that updates, shimmering, etc are not a problem.
2597 Tcl_IncrRefCount(storagePtr->accumulatorObj);
2598 Tcl_IncrRefCount(storagePtr->keyVarObj);
2599 Tcl_IncrRefCount(storagePtr->valueVarObj);
2600 Tcl_IncrRefCount(storagePtr->scriptObj);
2603 * Stop the value from getting hit in any way by any traces on the key
2607 Tcl_IncrRefCount(valueObj);
2608 if (Tcl_ObjSetVar2(interp, storagePtr->keyVarObj, NULL, keyObj,
2609 TCL_LEAVE_ERR_MSG) == NULL) {
2610 TclDecrRefCount(valueObj);
2613 if (Tcl_ObjSetVar2(interp, storagePtr->valueVarObj, NULL, valueObj,
2614 TCL_LEAVE_ERR_MSG) == NULL) {
2615 TclDecrRefCount(valueObj);
2618 TclDecrRefCount(valueObj);
2624 TclNRAddCallback(interp, DictMapLoopCallback, storagePtr, NULL,NULL,NULL);
2625 return TclNREvalObjEx(interp, storagePtr->scriptObj, 0,
2626 iPtr->cmdFramePtr, 3);
2629 * For unwinding everything on error.
2633 TclDecrRefCount(storagePtr->keyVarObj);
2634 TclDecrRefCount(storagePtr->valueVarObj);
2635 TclDecrRefCount(storagePtr->scriptObj);
2636 TclDecrRefCount(storagePtr->accumulatorObj);
2637 Tcl_DictObjDone(&storagePtr->search);
2638 TclStackFree(interp, storagePtr);
2643 DictMapLoopCallback(
2648 Interp *iPtr = (Interp *) interp;
2649 DictMapStorage *storagePtr = data[0];
2650 Tcl_Obj *keyObj, *valueObj;
2654 * Process the result from the previous execution of the script body.
2657 if (result == TCL_CONTINUE) {
2659 } else if (result != TCL_OK) {
2660 if (result == TCL_BREAK) {
2661 Tcl_ResetResult(interp);
2663 } else if (result == TCL_ERROR) {
2664 Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
2665 "\n (\"dict map\" body line %d)",
2666 Tcl_GetErrorLine(interp)));
2670 keyObj = Tcl_ObjGetVar2(interp, storagePtr->keyVarObj, NULL,
2672 if (keyObj == NULL) {
2676 Tcl_DictObjPut(NULL, storagePtr->accumulatorObj, keyObj,
2677 Tcl_GetObjResult(interp));
2681 * Get the next mapping from the dictionary.
2684 Tcl_DictObjNext(&storagePtr->search, &keyObj, &valueObj, &done);
2686 Tcl_SetObjResult(interp, storagePtr->accumulatorObj);
2691 * Stop the value from getting hit in any way by any traces on the key
2695 Tcl_IncrRefCount(valueObj);
2696 if (Tcl_ObjSetVar2(interp, storagePtr->keyVarObj, NULL, keyObj,
2697 TCL_LEAVE_ERR_MSG) == NULL) {
2698 TclDecrRefCount(valueObj);
2702 if (Tcl_ObjSetVar2(interp, storagePtr->valueVarObj, NULL, valueObj,
2703 TCL_LEAVE_ERR_MSG) == NULL) {
2704 TclDecrRefCount(valueObj);
2708 TclDecrRefCount(valueObj);
2714 TclNRAddCallback(interp, DictMapLoopCallback, storagePtr, NULL,NULL,NULL);
2715 return TclNREvalObjEx(interp, storagePtr->scriptObj, 0,
2716 iPtr->cmdFramePtr, 3);
2719 * For unwinding everything once the iterating is done.
2723 TclDecrRefCount(storagePtr->keyVarObj);
2724 TclDecrRefCount(storagePtr->valueVarObj);
2725 TclDecrRefCount(storagePtr->scriptObj);
2726 TclDecrRefCount(storagePtr->accumulatorObj);
2727 Tcl_DictObjDone(&storagePtr->search);
2728 TclStackFree(interp, storagePtr);
2733 *----------------------------------------------------------------------
2737 * This function implements the "dict set" Tcl command. See the user
2738 * documentation for details on what it does, and TIP#111 for the formal
2742 * A standard Tcl result.
2745 * See the user documentation.
2747 *----------------------------------------------------------------------
2755 Tcl_Obj *const *objv)
2757 Tcl_Obj *dictPtr, *resultPtr;
2758 int result, allocatedDict = 0;
2761 Tcl_WrongNumArgs(interp, 1, objv, "dictVarName key ?key ...? value");
2765 dictPtr = Tcl_ObjGetVar2(interp, objv[1], NULL, 0);
2766 if (dictPtr == NULL) {
2768 dictPtr = Tcl_NewDictObj();
2769 } else if (Tcl_IsShared(dictPtr)) {
2771 dictPtr = Tcl_DuplicateObj(dictPtr);
2774 result = Tcl_DictObjPutKeyList(interp, dictPtr, objc-3, objv+2,
2776 if (result != TCL_OK) {
2777 if (allocatedDict) {
2778 TclDecrRefCount(dictPtr);
2783 resultPtr = Tcl_ObjSetVar2(interp, objv[1], NULL, dictPtr,
2785 if (resultPtr == NULL) {
2788 Tcl_SetObjResult(interp, resultPtr);
2793 *----------------------------------------------------------------------
2797 * This function implements the "dict unset" Tcl command. See the user
2798 * documentation for details on what it does, and TIP#111 for the formal
2802 * A standard Tcl result.
2805 * See the user documentation.
2807 *----------------------------------------------------------------------
2815 Tcl_Obj *const *objv)
2817 Tcl_Obj *dictPtr, *resultPtr;
2818 int result, allocatedDict = 0;
2821 Tcl_WrongNumArgs(interp, 1, objv, "dictVarName key ?key ...?");
2825 dictPtr = Tcl_ObjGetVar2(interp, objv[1], NULL, 0);
2826 if (dictPtr == NULL) {
2828 dictPtr = Tcl_NewDictObj();
2829 } else if (Tcl_IsShared(dictPtr)) {
2831 dictPtr = Tcl_DuplicateObj(dictPtr);
2834 result = Tcl_DictObjRemoveKeyList(interp, dictPtr, objc-2, objv+2);
2835 if (result != TCL_OK) {
2836 if (allocatedDict) {
2837 TclDecrRefCount(dictPtr);
2842 resultPtr = Tcl_ObjSetVar2(interp, objv[1], NULL, dictPtr,
2844 if (resultPtr == NULL) {
2847 Tcl_SetObjResult(interp, resultPtr);
2852 *----------------------------------------------------------------------
2856 * This function implements the "dict filter" Tcl command. See the user
2857 * documentation for details on what it does, and TIP#111 for the formal
2861 * A standard Tcl result.
2864 * See the user documentation.
2866 *----------------------------------------------------------------------
2874 Tcl_Obj *const *objv)
2876 Interp *iPtr = (Interp *) interp;
2877 static const char *const filters[] = {
2878 "key", "script", "value", NULL
2881 FILTER_KEYS, FILTER_SCRIPT, FILTER_VALUES
2883 Tcl_Obj *scriptObj, *keyVarObj, *valueVarObj;
2884 Tcl_Obj **varv, *keyObj = NULL, *valueObj = NULL, *resultObj, *boolObj;
2885 Tcl_DictSearch search;
2886 int index, varc, done, result, satisfied;
2887 const char *pattern;
2890 Tcl_WrongNumArgs(interp, 1, objv, "dictionary filterType ?arg ...?");
2893 if (Tcl_GetIndexFromObj(interp, objv[2], filters, "filterType",
2894 0, &index) != TCL_OK) {
2898 switch ((enum FilterTypes) index) {
2901 * Create a dictionary whose keys all match a certain pattern.
2904 if (Tcl_DictObjFirst(interp, objv[1], &search,
2905 &keyObj, &valueObj, &done) != TCL_OK) {
2910 * Nothing to match, so return nothing (== empty dictionary).
2913 Tcl_DictObjDone(&search);
2915 } else if (objc == 4) {
2916 pattern = TclGetString(objv[3]);
2917 resultObj = Tcl_NewDictObj();
2918 if (TclMatchIsTrivial(pattern)) {
2920 * Must release the search lock here to prevent a memory leak
2921 * since we are not exhausing the search. [Bug 1705778, leak
2925 Tcl_DictObjDone(&search);
2926 Tcl_DictObjGet(interp, objv[1], objv[3], &valueObj);
2927 if (valueObj != NULL) {
2928 Tcl_DictObjPut(NULL, resultObj, objv[3], valueObj);
2932 if (Tcl_StringMatch(TclGetString(keyObj), pattern)) {
2933 Tcl_DictObjPut(NULL, resultObj, keyObj, valueObj);
2935 Tcl_DictObjNext(&search, &keyObj, &valueObj, &done);
2940 * Can't optimize this match for trivial globbing: would disturb
2944 resultObj = Tcl_NewDictObj();
2948 for (i=3 ; i<objc ; i++) {
2949 pattern = TclGetString(objv[i]);
2950 if (Tcl_StringMatch(TclGetString(keyObj), pattern)) {
2951 Tcl_DictObjPut(NULL, resultObj, keyObj, valueObj);
2952 break; /* stop inner loop */
2955 Tcl_DictObjNext(&search, &keyObj, &valueObj, &done);
2958 Tcl_SetObjResult(interp, resultObj);
2963 * Create a dictionary whose values all match a certain pattern.
2966 if (Tcl_DictObjFirst(interp, objv[1], &search,
2967 &keyObj, &valueObj, &done) != TCL_OK) {
2970 resultObj = Tcl_NewDictObj();
2974 for (i=3 ; i<objc ; i++) {
2975 pattern = TclGetString(objv[i]);
2976 if (Tcl_StringMatch(TclGetString(valueObj), pattern)) {
2977 Tcl_DictObjPut(NULL, resultObj, keyObj, valueObj);
2978 break; /* stop inner loop */
2981 Tcl_DictObjNext(&search, &keyObj, &valueObj, &done);
2983 Tcl_SetObjResult(interp, resultObj);
2988 Tcl_WrongNumArgs(interp, 1, objv,
2989 "dictionary script {keyVarName valueVarName} filterScript");
2994 * Create a dictionary whose key,value pairs all satisfy a script
2995 * (i.e. get a true boolean result from its evaluation). Massive
2996 * copying from the "dict for" implementation has occurred!
2999 if (TclListObjGetElements(interp, objv[3], &varc, &varv) != TCL_OK) {
3003 Tcl_SetObjResult(interp, Tcl_NewStringObj(
3004 "must have exactly two variable names", -1));
3005 Tcl_SetErrorCode(interp, "TCL", "SYNTAX", "dict", "filter", NULL);
3008 keyVarObj = varv[0];
3009 valueVarObj = varv[1];
3010 scriptObj = objv[4];
3013 * Make sure that these objects (which we need throughout the body of
3014 * the loop) don't vanish. Note that the dictionary internal rep is
3015 * locked internally so that updates, shimmering, etc are not a
3019 Tcl_IncrRefCount(keyVarObj);
3020 Tcl_IncrRefCount(valueVarObj);
3021 Tcl_IncrRefCount(scriptObj);
3023 result = Tcl_DictObjFirst(interp, objv[1],
3024 &search, &keyObj, &valueObj, &done);
3025 if (result != TCL_OK) {
3026 TclDecrRefCount(keyVarObj);
3027 TclDecrRefCount(valueVarObj);
3028 TclDecrRefCount(scriptObj);
3032 resultObj = Tcl_NewDictObj();
3036 * Stop the value from getting hit in any way by any traces on the
3040 Tcl_IncrRefCount(keyObj);
3041 Tcl_IncrRefCount(valueObj);
3042 if (Tcl_ObjSetVar2(interp, keyVarObj, NULL, keyObj,
3043 TCL_LEAVE_ERR_MSG) == NULL) {
3044 Tcl_AddErrorInfo(interp,
3045 "\n (\"dict filter\" filter script key variable)");
3047 goto abnormalResult;
3049 if (Tcl_ObjSetVar2(interp, valueVarObj, NULL, valueObj,
3050 TCL_LEAVE_ERR_MSG) == NULL) {
3051 Tcl_AddErrorInfo(interp,
3052 "\n (\"dict filter\" filter script value variable)");
3054 goto abnormalResult;
3058 * TIP #280. Make invoking context available to loop body.
3061 result = TclEvalObjEx(interp, scriptObj, 0, iPtr->cmdFramePtr, 4);
3064 boolObj = Tcl_GetObjResult(interp);
3065 Tcl_IncrRefCount(boolObj);
3066 Tcl_ResetResult(interp);
3067 if (Tcl_GetBooleanFromObj(interp, boolObj,
3068 &satisfied) != TCL_OK) {
3069 TclDecrRefCount(boolObj);
3071 goto abnormalResult;
3073 TclDecrRefCount(boolObj);
3075 Tcl_DictObjPut(NULL, resultObj, keyObj, valueObj);
3080 * Force loop termination by calling Tcl_DictObjDone; this
3081 * makes the next Tcl_DictObjNext say there is nothing more to
3085 Tcl_ResetResult(interp);
3086 Tcl_DictObjDone(&search);
3092 Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
3093 "\n (\"dict filter\" script line %d)",
3094 Tcl_GetErrorLine(interp)));
3096 goto abnormalResult;
3099 TclDecrRefCount(keyObj);
3100 TclDecrRefCount(valueObj);
3102 Tcl_DictObjNext(&search, &keyObj, &valueObj, &done);
3106 * Stop holding a reference to these objects.
3109 TclDecrRefCount(keyVarObj);
3110 TclDecrRefCount(valueVarObj);
3111 TclDecrRefCount(scriptObj);
3112 Tcl_DictObjDone(&search);
3114 if (result == TCL_OK) {
3115 Tcl_SetObjResult(interp, resultObj);
3117 TclDecrRefCount(resultObj);
3122 Tcl_DictObjDone(&search);
3123 TclDecrRefCount(keyObj);
3124 TclDecrRefCount(valueObj);
3125 TclDecrRefCount(keyVarObj);
3126 TclDecrRefCount(valueVarObj);
3127 TclDecrRefCount(scriptObj);
3128 TclDecrRefCount(resultObj);
3131 Tcl_Panic("unexpected fallthrough");
3132 /* Control never reaches this point. */
3137 *----------------------------------------------------------------------
3141 * This function implements the "dict update" Tcl command. See the user
3142 * documentation for details on what it does, and TIP#212 for the formal
3146 * A standard Tcl result.
3149 * See the user documentation.
3151 *----------------------------------------------------------------------
3156 ClientData clientData,
3159 Tcl_Obj *const *objv)
3161 Interp *iPtr = (Interp *) interp;
3162 Tcl_Obj *dictPtr, *objPtr;
3165 if (objc < 5 || !(objc & 1)) {
3166 Tcl_WrongNumArgs(interp, 1, objv,
3167 "dictVarName key varName ?key varName ...? script");
3171 dictPtr = Tcl_ObjGetVar2(interp, objv[1], NULL, TCL_LEAVE_ERR_MSG);
3172 if (dictPtr == NULL) {
3175 if (Tcl_DictObjSize(interp, dictPtr, &dummy) != TCL_OK) {
3178 Tcl_IncrRefCount(dictPtr);
3179 for (i=2 ; i+2<objc ; i+=2) {
3180 if (Tcl_DictObjGet(interp, dictPtr, objv[i], &objPtr) != TCL_OK) {
3181 TclDecrRefCount(dictPtr);
3184 if (objPtr == NULL) {
3186 Tcl_UnsetVar(interp, Tcl_GetString(objv[i+1]), 0);
3187 } else if (Tcl_ObjSetVar2(interp, objv[i+1], NULL, objPtr,
3188 TCL_LEAVE_ERR_MSG) == NULL) {
3189 TclDecrRefCount(dictPtr);
3193 TclDecrRefCount(dictPtr);
3196 * Execute the body after setting up the NRE handler to process the
3200 objPtr = Tcl_NewListObj(objc-3, objv+2);
3201 Tcl_IncrRefCount(objPtr);
3202 Tcl_IncrRefCount(objv[1]);
3203 TclNRAddCallback(interp, FinalizeDictUpdate, objv[1], objPtr, NULL,NULL);
3205 return TclNREvalObjEx(interp, objv[objc-1], 0, iPtr->cmdFramePtr, objc-1);
3214 Tcl_Obj *dictPtr, *objPtr, **objv;
3215 Tcl_InterpState state;
3217 Tcl_Obj *varName = data[0];
3218 Tcl_Obj *argsObj = data[1];
3221 * ErrorInfo handling.
3224 if (result == TCL_ERROR) {
3225 Tcl_AddErrorInfo(interp, "\n (body of \"dict update\")");
3229 * If the dictionary variable doesn't exist, drop everything silently.
3232 dictPtr = Tcl_ObjGetVar2(interp, varName, NULL, 0);
3233 if (dictPtr == NULL) {
3234 TclDecrRefCount(varName);
3235 TclDecrRefCount(argsObj);
3240 * Double-check that it is still a dictionary.
3243 state = Tcl_SaveInterpState(interp, result);
3244 if (Tcl_DictObjSize(interp, dictPtr, &objc) != TCL_OK) {
3245 Tcl_DiscardInterpState(state);
3246 TclDecrRefCount(varName);
3247 TclDecrRefCount(argsObj);
3251 if (Tcl_IsShared(dictPtr)) {
3252 dictPtr = Tcl_DuplicateObj(dictPtr);
3256 * Write back the values from the variables, treating failure to read as
3257 * an instruction to remove the key.
3260 Tcl_ListObjGetElements(NULL, argsObj, &objc, &objv);
3261 for (i=0 ; i<objc ; i+=2) {
3262 objPtr = Tcl_ObjGetVar2(interp, objv[i+1], NULL, 0);
3263 if (objPtr == NULL) {
3264 Tcl_DictObjRemove(NULL, dictPtr, objv[i]);
3265 } else if (objPtr == dictPtr) {
3267 * Someone is messing us around, trying to build a recursive
3268 * structure. [Bug 1786481]
3271 Tcl_DictObjPut(NULL, dictPtr, objv[i], Tcl_DuplicateObj(objPtr));
3273 /* Shouldn't fail */
3274 Tcl_DictObjPut(NULL, dictPtr, objv[i], objPtr);
3277 TclDecrRefCount(argsObj);
3280 * Write the dictionary back to its variable.
3283 if (Tcl_ObjSetVar2(interp, varName, NULL, dictPtr,
3284 TCL_LEAVE_ERR_MSG) == NULL) {
3285 Tcl_DiscardInterpState(state);
3286 TclDecrRefCount(varName);
3290 TclDecrRefCount(varName);
3291 return Tcl_RestoreInterpState(interp, state);
3295 *----------------------------------------------------------------------
3299 * This function implements the "dict with" Tcl command. See the user
3300 * documentation for details on what it does, and TIP#212 for the formal
3304 * A standard Tcl result.
3307 * See the user documentation.
3309 *----------------------------------------------------------------------
3317 Tcl_Obj *const *objv)
3319 Interp *iPtr = (Interp *) interp;
3320 Tcl_Obj *dictPtr, *keysPtr, *pathPtr;
3323 Tcl_WrongNumArgs(interp, 1, objv, "dictVarName ?key ...? script");
3328 * Get the dictionary to open out.
3331 dictPtr = Tcl_ObjGetVar2(interp, objv[1], NULL, TCL_LEAVE_ERR_MSG);
3332 if (dictPtr == NULL) {
3336 keysPtr = TclDictWithInit(interp, dictPtr, objc-3, objv+2);
3337 if (keysPtr == NULL) {
3340 Tcl_IncrRefCount(keysPtr);
3343 * Execute the body, while making the invoking context available to the
3344 * loop body (TIP#280) and postponing the cleanup until later (NRE).
3349 pathPtr = Tcl_NewListObj(objc-3, objv+2);
3350 Tcl_IncrRefCount(pathPtr);
3352 Tcl_IncrRefCount(objv[1]);
3353 TclNRAddCallback(interp, FinalizeDictWith, objv[1], keysPtr, pathPtr,
3356 return TclNREvalObjEx(interp, objv[objc-1], 0, iPtr->cmdFramePtr, objc-1);
3367 Tcl_InterpState state;
3368 Tcl_Obj *varName = data[0];
3369 Tcl_Obj *keysPtr = data[1];
3370 Tcl_Obj *pathPtr = data[2];
3371 Var *varPtr, *arrayPtr;
3373 if (result == TCL_ERROR) {
3374 Tcl_AddErrorInfo(interp, "\n (body of \"dict with\")");
3378 * Save the result state; TDWF doesn't guarantee to not modify that on
3382 state = Tcl_SaveInterpState(interp, result);
3383 if (pathPtr != NULL) {
3384 Tcl_ListObjGetElements(NULL, pathPtr, &pathc, &pathv);
3391 * Pack from local variables back into the dictionary.
3394 varPtr = TclObjLookupVarEx(interp, varName, NULL, TCL_LEAVE_ERR_MSG, "set",
3395 /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr);
3396 if (varPtr == NULL) {
3399 result = TclDictWithFinish(interp, varPtr, arrayPtr, varName, NULL, -1,
3400 pathc, pathv, keysPtr);
3404 * Tidy up and return the real result (unless we had an error).
3407 TclDecrRefCount(varName);
3408 TclDecrRefCount(keysPtr);
3409 if (pathPtr != NULL) {
3410 TclDecrRefCount(pathPtr);
3412 if (result != TCL_OK) {
3413 Tcl_DiscardInterpState(state);
3416 return Tcl_RestoreInterpState(interp, state);
3420 *----------------------------------------------------------------------
3422 * TclDictWithInit --
3424 * Part of the core of [dict with]. Pokes into a dictionary and converts
3425 * the mappings there into assignments to (presumably) local variables.
3426 * Returns a list of all the names that were mapped so that removal of
3427 * either the variable or the dictionary entry won't surprise us when we
3428 * come to stuffing everything back.
3431 * List of mapped names, or NULL if there was an error.
3434 * Assigns to variables, so potentially legion due to traces.
3436 *----------------------------------------------------------------------
3444 Tcl_Obj *const pathv[])
3447 Tcl_Obj *keyPtr, *valPtr, *keysPtr;
3451 dictPtr = TclTraceDictPath(interp, dictPtr, pathc, pathv,
3453 if (dictPtr == NULL) {
3459 * Go over the list of keys and write each corresponding value to a
3460 * variable in the current context with the same name. Also keep a copy of
3461 * the keys so we can write back properly later on even if the dictionary
3462 * has been structurally modified.
3465 if (Tcl_DictObjFirst(interp, dictPtr, &s, &keyPtr, &valPtr,
3472 for (; !done ; Tcl_DictObjNext(&s, &keyPtr, &valPtr, &done)) {
3473 Tcl_ListObjAppendElement(NULL, keysPtr, keyPtr);
3474 if (Tcl_ObjSetVar2(interp, keyPtr, NULL, valPtr,
3475 TCL_LEAVE_ERR_MSG) == NULL) {
3476 TclDecrRefCount(keysPtr);
3477 Tcl_DictObjDone(&s);
3486 *----------------------------------------------------------------------
3488 * TclDictWithFinish --
3490 * Part of the core of [dict with]. Reassembles the piece of the dict (in
3491 * varName, location given by pathc/pathv) from the variables named in
3492 * the keysPtr argument. NB, does not try to preserve errors or manage
3493 * argument lifetimes.
3496 * TCL_OK if we succeeded, or TCL_ERROR if we failed.
3499 * Assigns to a variable, so potentially legion due to traces. Updates
3500 * the dictionary in the named variable.
3502 *----------------------------------------------------------------------
3507 Tcl_Interp *interp, /* Command interpreter in which variable
3508 * exists. Used for state management, traces
3509 * and error reporting. */
3510 Var *varPtr, /* Reference to the variable holding the
3512 Var *arrayPtr, /* Reference to the array containing the
3513 * variable, or NULL if the variable is a
3515 Tcl_Obj *part1Ptr, /* Name of an array (if part2 is non-NULL) or
3516 * the name of a variable. NULL if the 'index'
3517 * parameter is >= 0 */
3518 Tcl_Obj *part2Ptr, /* If non-NULL, gives the name of an element
3519 * in the array part1. */
3520 int index, /* Index into the local variable table of the
3521 * variable, or -1. Only used when part1Ptr is
3523 int pathc, /* The number of elements in the path into the
3525 Tcl_Obj *const pathv[], /* The elements of the path to the subdict. */
3526 Tcl_Obj *keysPtr) /* List of keys to be synchronized. This is
3527 * the result value from TclDictWithInit. */
3529 Tcl_Obj *dictPtr, *leafPtr, *valPtr;
3530 int i, allocdict, keyc;
3534 * If the dictionary variable doesn't exist, drop everything silently.
3537 dictPtr = TclPtrGetVarIdx(interp, varPtr, arrayPtr, part1Ptr, part2Ptr,
3538 TCL_LEAVE_ERR_MSG, index);
3539 if (dictPtr == NULL) {
3544 * Double-check that it is still a dictionary.
3547 if (Tcl_DictObjSize(interp, dictPtr, &i) != TCL_OK) {
3551 if (Tcl_IsShared(dictPtr)) {
3552 dictPtr = Tcl_DuplicateObj(dictPtr);
3560 * Want to get to the dictionary which we will update; need to do
3561 * prepare-for-update de-sharing along the path *but* avoid generating
3562 * an error on a non-existant path (we'll treat that the same as a
3563 * non-existant variable. Luckily, the de-sharing operation isn't
3564 * deeply damaging if we don't go on to update; it's just less than
3565 * perfectly efficient (but no memory should be leaked).
3568 leafPtr = TclTraceDictPath(interp, dictPtr, pathc, pathv,
3569 DICT_PATH_EXISTS | DICT_PATH_UPDATE);
3570 if (leafPtr == NULL) {
3572 TclDecrRefCount(dictPtr);
3576 if (leafPtr == DICT_PATH_NON_EXISTENT) {
3578 TclDecrRefCount(dictPtr);
3587 * Now process our updates on the leaf dictionary.
3590 TclListObjGetElements(NULL, keysPtr, &keyc, &keyv);
3591 for (i=0 ; i<keyc ; i++) {
3592 valPtr = Tcl_ObjGetVar2(interp, keyv[i], NULL, 0);
3593 if (valPtr == NULL) {
3594 Tcl_DictObjRemove(NULL, leafPtr, keyv[i]);
3595 } else if (leafPtr == valPtr) {
3597 * Someone is messing us around, trying to build a recursive
3598 * structure. [Bug 1786481]
3601 Tcl_DictObjPut(NULL, leafPtr, keyv[i], Tcl_DuplicateObj(valPtr));
3603 Tcl_DictObjPut(NULL, leafPtr, keyv[i], valPtr);
3608 * Ensure that none of the dictionaries in the chain still have a string
3613 InvalidateDictChain(leafPtr);
3617 * Write back the outermost dictionary to the variable.
3620 if (TclPtrSetVarIdx(interp, varPtr, arrayPtr, part1Ptr, part2Ptr,
3621 dictPtr, TCL_LEAVE_ERR_MSG, index) == NULL) {
3623 TclDecrRefCount(dictPtr);
3631 *----------------------------------------------------------------------
3635 * This function is create the "dict" Tcl command. See the user
3636 * documentation for details on what it does, and TIP#111 for the formal
3640 * A Tcl command handle.
3643 * May advance compilation epoch.
3645 *----------------------------------------------------------------------
3652 return TclMakeEnsemble(interp, "dict", implementationMap);