diff options
Diffstat (limited to 'generic/tclDictObj.c')
| -rw-r--r-- | generic/tclDictObj.c | 1611 |
1 files changed, 497 insertions, 1114 deletions
diff --git a/generic/tclDictObj.c b/generic/tclDictObj.c index c7e2c86..4fec2c1 100644 --- a/generic/tclDictObj.c +++ b/generic/tclDictObj.c @@ -4,15 +4,14 @@ * This file contains functions that implement the Tcl dict object type * and its accessor command. * - * Copyright © 2002-2010 Donal K. Fellows. + * Copyright (c) 2002 by Donal K. Fellows. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" -#include "tclTomMath.h" -#include <assert.h> +#include "tommath.h" /* * Forward declaration. @@ -23,74 +22,82 @@ struct Dict; * Prototypes for functions defined later in this file: */ -static void DeleteDict(struct Dict *dict); -static Tcl_ObjCmdProc DictAppendCmd; -static Tcl_ObjCmdProc DictCreateCmd; -static Tcl_ObjCmdProc DictExistsCmd; -static Tcl_ObjCmdProc DictFilterCmd; -static Tcl_ObjCmdProc DictGetCmd; -static Tcl_ObjCmdProc DictGetDefCmd; -static Tcl_ObjCmdProc DictIncrCmd; -static Tcl_ObjCmdProc DictInfoCmd; -static Tcl_ObjCmdProc DictKeysCmd; -static Tcl_ObjCmdProc DictLappendCmd; -static Tcl_ObjCmdProc DictMergeCmd; -static Tcl_ObjCmdProc DictRemoveCmd; -static Tcl_ObjCmdProc DictReplaceCmd; -static Tcl_ObjCmdProc DictSetCmd; -static Tcl_ObjCmdProc DictSizeCmd; -static Tcl_ObjCmdProc DictUnsetCmd; -static Tcl_ObjCmdProc DictUpdateCmd; -static Tcl_ObjCmdProc DictValuesCmd; -static Tcl_ObjCmdProc DictWithCmd; -static Tcl_DupInternalRepProc DupDictInternalRep; -static Tcl_FreeInternalRepProc FreeDictInternalRep; -static void InvalidateDictChain(Tcl_Obj *dictObj); -static Tcl_SetFromAnyProc SetDictFromAny; -static Tcl_UpdateStringProc UpdateStringOfDict; -static Tcl_AllocHashEntryProc AllocChainEntry; -static inline void InitChainTable(struct Dict *dict); -static inline void DeleteChainTable(struct Dict *dict); -static inline Tcl_HashEntry * CreateChainEntry(struct Dict *dict, - Tcl_Obj *keyPtr, int *newPtr); -static inline int DeleteChainEntry(struct Dict *dict, - Tcl_Obj *keyPtr); -static Tcl_NRPostProc FinalizeDictUpdate; -static Tcl_NRPostProc FinalizeDictWith; -static Tcl_ObjCmdProc DictForNRCmd; -static Tcl_ObjCmdProc DictMapNRCmd; -static Tcl_NRPostProc DictForLoopCallback; -static Tcl_NRPostProc DictMapLoopCallback; +static void DeleteDict(struct Dict *dict); +static int DictAppendCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv); +static int DictCreateCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv); +static int DictExistsCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv); +static int DictFilterCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv); +static int DictForCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv); +static int DictGetCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv); +static int DictIncrCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv); +static int DictInfoCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv); +static int DictKeysCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv); +static int DictLappendCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv); +static int DictMergeCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv); +static int DictRemoveCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv); +static int DictReplaceCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv); +static int DictSetCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv); +static int DictSizeCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv); +static int DictUnsetCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv); +static int DictUpdateCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv); +static int DictValuesCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv); +static int DictWithCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv); +static void DupDictInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr); +static void FreeDictInternalRep(Tcl_Obj *dictPtr); +static void InvalidateDictChain(Tcl_Obj *dictObj); +static int SetDictFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr); +static void UpdateStringOfDict(Tcl_Obj *dictPtr); +static Tcl_HashEntry * AllocChainEntry(Tcl_HashTable *tablePtr,void *keyPtr); +static inline void InitChainTable(struct Dict *dict); +static inline void DeleteChainTable(struct Dict *dict); +static inline Tcl_HashEntry *CreateChainEntry(struct Dict *dict, + Tcl_Obj *keyPtr, int *newPtr); +static inline int DeleteChainEntry(struct Dict *dict, Tcl_Obj *keyPtr); /* * Table of dict subcommand names and implementations. */ static const EnsembleImplMap implementationMap[] = { - {"append", DictAppendCmd, TclCompileDictAppendCmd, NULL, NULL, 0 }, - {"create", DictCreateCmd, TclCompileDictCreateCmd, NULL, NULL, 0 }, - {"exists", DictExistsCmd, TclCompileDictExistsCmd, NULL, NULL, 0 }, - {"filter", DictFilterCmd, NULL, NULL, NULL, 0 }, - {"for", NULL, TclCompileDictForCmd, DictForNRCmd, NULL, 0 }, - {"get", DictGetCmd, TclCompileDictGetCmd, NULL, NULL, 0 }, - {"getdef", DictGetDefCmd, TclCompileDictGetWithDefaultCmd, NULL,NULL,0}, - {"getwithdefault", DictGetDefCmd, TclCompileDictGetWithDefaultCmd, - NULL, NULL, 0 }, - {"incr", DictIncrCmd, TclCompileDictIncrCmd, NULL, NULL, 0 }, - {"info", DictInfoCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0 }, - {"keys", DictKeysCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0 }, - {"lappend", DictLappendCmd, TclCompileDictLappendCmd, NULL, NULL, 0 }, - {"map", NULL, TclCompileDictMapCmd, DictMapNRCmd, NULL, 0 }, - {"merge", DictMergeCmd, TclCompileDictMergeCmd, NULL, NULL, 0 }, - {"remove", DictRemoveCmd, TclCompileBasicMin1ArgCmd, NULL, NULL, 0 }, - {"replace", DictReplaceCmd, NULL, NULL, NULL, 0 }, - {"set", DictSetCmd, TclCompileDictSetCmd, NULL, NULL, 0 }, - {"size", DictSizeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0 }, - {"unset", DictUnsetCmd, TclCompileDictUnsetCmd, NULL, NULL, 0 }, - {"update", DictUpdateCmd, TclCompileDictUpdateCmd, NULL, NULL, 0 }, - {"values", DictValuesCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0 }, - {"with", DictWithCmd, TclCompileDictWithCmd, NULL, NULL, 0 }, - {NULL, NULL, NULL, NULL, NULL, 0} + {"append", DictAppendCmd, TclCompileDictAppendCmd }, + {"create", DictCreateCmd, NULL }, + {"exists", DictExistsCmd, NULL }, + {"filter", DictFilterCmd, NULL }, + {"for", DictForCmd, TclCompileDictForCmd }, + {"get", DictGetCmd, TclCompileDictGetCmd }, + {"incr", DictIncrCmd, TclCompileDictIncrCmd }, + {"info", DictInfoCmd, NULL }, + {"keys", DictKeysCmd, NULL }, + {"lappend", DictLappendCmd, TclCompileDictLappendCmd }, + {"merge", DictMergeCmd, NULL }, + {"remove", DictRemoveCmd, NULL }, + {"replace", DictReplaceCmd, NULL }, + {"set", DictSetCmd, TclCompileDictSetCmd }, + {"size", DictSizeCmd, NULL }, + {"unset", DictUnsetCmd, NULL }, + {"update", DictUpdateCmd, TclCompileDictUpdateCmd }, + {"values", DictValuesCmd, NULL }, + {"with", DictWithCmd, NULL }, + {NULL, NULL, NULL} }; /* @@ -129,8 +136,8 @@ typedef struct Dict { * the dictionary. Used for doing traversal of * the entries in the order that they are * created. */ - TCL_HASH_TYPE epoch; /* Epoch counter */ - size_t refCount; /* Reference counter (see above) */ + 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. */ @@ -141,29 +148,14 @@ typedef struct Dict { * functions that can be invoked by generic object code. */ -const Tcl_ObjType tclDictType = { +Tcl_ObjType tclDictType = { "dict", FreeDictInternalRep, /* freeIntRepProc */ - DupDictInternalRep, /* dupIntRepProc */ + DupDictInternalRep, /* dupIntRepProc */ UpdateStringOfDict, /* updateStringProc */ SetDictFromAny /* setFromAnyProc */ }; -#define DictSetInternalRep(objPtr, dictRepPtr) \ - do { \ - Tcl_ObjInternalRep ir; \ - ir.twoPtrValue.ptr1 = (dictRepPtr); \ - ir.twoPtrValue.ptr2 = NULL; \ - Tcl_StoreInternalRep((objPtr), &tclDictType, &ir); \ - } while (0) - -#define DictGetInternalRep(objPtr, dictRepPtr) \ - do { \ - const Tcl_ObjInternalRep *irPtr; \ - irPtr = TclFetchInternalRep((objPtr), &tclDictType); \ - (dictRepPtr) = irPtr ? (Dict *)irPtr->twoPtrValue.ptr1 : NULL; \ - } while (0) - /* * The type of the specially adapted version of the Tcl_Obj*-containing hash * table defined in the tclObj.c code. This version differs in that it @@ -174,7 +166,7 @@ const Tcl_ObjType tclDictType = { * *this* file. Everything else should use the dict iterator API. */ -static const Tcl_HashKeyType chainHashType = { +static Tcl_HashKeyType chainHashType = { TCL_HASH_KEY_TYPE_VERSION, 0, TclHashObjKey, @@ -182,23 +174,6 @@ static const Tcl_HashKeyType chainHashType = { AllocChainEntry, TclFreeObjEntry }; - -/* - * Structure used in implementation of 'dict map' to hold the state that gets - * passed between parts of the implementation. - */ - -typedef struct { - Tcl_Obj *keyVarObj; /* The name of the variable that will have - * keys assigned to it. */ - Tcl_Obj *valueVarObj; /* The name of the variable that will have - * values assigned to it. */ - Tcl_DictSearch search; /* The dictionary search structure. */ - Tcl_Obj *scriptObj; /* The script to evaluate each time through - * the loop. */ - Tcl_Obj *accumulatorObj; /* The dictionary used to accumulate the - * results. */ -} DictMapStorage; /***** START OF FUNCTIONS IMPLEMENTING DICT CORE API *****/ @@ -222,16 +197,16 @@ typedef struct { static Tcl_HashEntry * AllocChainEntry( - TCL_UNUSED(Tcl_HashTable *), + Tcl_HashTable *tablePtr, void *keyPtr) { - Tcl_Obj *objPtr = (Tcl_Obj *)keyPtr; + Tcl_Obj *objPtr = keyPtr; ChainEntry *cPtr; - cPtr = (ChainEntry *)ckalloc(sizeof(ChainEntry)); - cPtr->entry.key.objPtr = objPtr; + cPtr = (ChainEntry *) ckalloc(sizeof(ChainEntry)); + cPtr->entry.key.oneWordValue = (char *) objPtr; Tcl_IncrRefCount(objPtr); - Tcl_SetHashValue(&cPtr->entry, NULL); + cPtr->entry.clientData = NULL; cPtr->prevPtr = cPtr->nextPtr = NULL; return &cPtr->entry; @@ -261,7 +236,7 @@ DeleteChainTable( ChainEntry *cPtr; for (cPtr=dict->entryChainHead ; cPtr!=NULL ; cPtr=cPtr->nextPtr) { - Tcl_Obj *valuePtr = (Tcl_Obj *)Tcl_GetHashValue(&cPtr->entry); + Tcl_Obj *valuePtr = Tcl_GetHashValue(&cPtr->entry); TclDecrRefCount(valuePtr); } @@ -275,7 +250,7 @@ CreateChainEntry( int *newPtr) { ChainEntry *cPtr = (ChainEntry *) - Tcl_CreateHashEntry(&dict->table, keyPtr, newPtr); + Tcl_CreateHashEntry(&dict->table, (char *) keyPtr, newPtr); /* * If this is a new entry in the hash table, stitch it into the chain. @@ -303,13 +278,12 @@ DeleteChainEntry( Tcl_Obj *keyPtr) { ChainEntry *cPtr = (ChainEntry *) - Tcl_FindHashEntry(&dict->table, keyPtr); + Tcl_FindHashEntry(&dict->table, (char *) keyPtr); if (cPtr == NULL) { return 0; } else { - Tcl_Obj *valuePtr = (Tcl_Obj *)Tcl_GetHashValue(&cPtr->entry); - + Tcl_Obj *valuePtr = Tcl_GetHashValue(&cPtr->entry); TclDecrRefCount(valuePtr); } @@ -359,19 +333,18 @@ DupDictInternalRep( Tcl_Obj *srcPtr, Tcl_Obj *copyPtr) { - Dict *oldDict, *newDict = (Dict *)ckalloc(sizeof(Dict)); + Dict *oldDict = srcPtr->internalRep.twoPtrValue.ptr1; + Dict *newDict = (Dict *) ckalloc(sizeof(Dict)); ChainEntry *cPtr; - DictGetInternalRep(srcPtr, oldDict); - /* * Copy values across from the old hash table. */ InitChainTable(newDict); for (cPtr=oldDict->entryChainHead ; cPtr!=NULL ; cPtr=cPtr->nextPtr) { - Tcl_Obj *key = (Tcl_Obj *)Tcl_GetHashKey(&oldDict->table, &cPtr->entry); - Tcl_Obj *valuePtr = (Tcl_Obj *)Tcl_GetHashValue(&cPtr->entry); + void *key = Tcl_GetHashKey(&oldDict->table, &cPtr->entry); + Tcl_Obj *valuePtr = Tcl_GetHashValue(&cPtr->entry); int n; Tcl_HashEntry *hPtr = CreateChainEntry(newDict, key, &n); @@ -379,7 +352,7 @@ DupDictInternalRep( * Fill in the contents. */ - Tcl_SetHashValue(hPtr, valuePtr); + Tcl_SetHashValue(hPtr, (ClientData) valuePtr); Tcl_IncrRefCount(valuePtr); } @@ -387,15 +360,16 @@ DupDictInternalRep( * Initialise other fields. */ - newDict->epoch = 1; + newDict->epoch = 0; newDict->chain = NULL; - newDict->refCount = 1; + newDict->refcount = 1; /* * Store in the object. */ - DictSetInternalRep(copyPtr, newDict); + copyPtr->internalRep.twoPtrValue.ptr1 = newDict; + copyPtr->typePtr = &tclDictType; } /* @@ -420,13 +394,13 @@ static void FreeDictInternalRep( Tcl_Obj *dictPtr) { - Dict *dict; - - DictGetInternalRep(dictPtr, dict); + Dict *dict = dictPtr->internalRep.twoPtrValue.ptr1; - if (dict->refCount-- <= 1) { + --dict->refcount; + if (dict->refcount <= 0) { DeleteDict(dict); } + dictPtr->typePtr = NULL; } /* @@ -454,7 +428,7 @@ DeleteDict( Dict *dict) { DeleteChainTable(dict); - ckfree(dict); + ckfree((char *) dict); } /* @@ -483,32 +457,26 @@ static void UpdateStringOfDict( Tcl_Obj *dictPtr) { -#define LOCAL_SIZE 64 - char localFlags[LOCAL_SIZE], *flagPtr = NULL; - Dict *dict; +#define LOCAL_SIZE 20 + int localFlags[LOCAL_SIZE], *flagPtr = NULL; + Dict *dict = dictPtr->internalRep.twoPtrValue.ptr1; ChainEntry *cPtr; Tcl_Obj *keyPtr, *valuePtr; - int i, length; - TCL_HASH_TYPE bytesNeeded = 0; - const char *elem; - char *dst; + int i, length, bytesNeeded = 0; + char *elem, *dst; + const int maxFlags = UINT_MAX / sizeof(int); /* * This field is the most useful one in the whole hash structure, and it * is not exposed by any API function... */ - int numElems; - - DictGetInternalRep(dictPtr, dict); - - assert (dict != NULL); - - numElems = dict->table.numEntries * 2; + int numElems = dict->table.numEntries * 2; /* Handle empty list case first, simplifies what follows */ if (numElems == 0) { - Tcl_InitStringRep(dictPtr, NULL, 0); + dictPtr->bytes = tclEmptyStringRep; + dictPtr->length = 0; return; } @@ -518,8 +486,10 @@ UpdateStringOfDict( if (numElems <= LOCAL_SIZE) { flagPtr = localFlags; + } else if (numElems > maxFlags) { + Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } else { - flagPtr = (char *)ckalloc(numElems); + flagPtr = (int *) ckalloc((unsigned) numElems*sizeof(int)); } for (i=0,cPtr=dict->entryChainHead; i<numElems; i+=2,cPtr=cPtr->nextPtr) { /* @@ -528,22 +498,22 @@ UpdateStringOfDict( */ flagPtr[i] = ( i ? TCL_DONT_QUOTE_HASH : 0 ); - keyPtr = (Tcl_Obj *)Tcl_GetHashKey(&dict->table, &cPtr->entry); + keyPtr = (Tcl_Obj *) Tcl_GetHashKey(&dict->table, &cPtr->entry); elem = TclGetStringFromObj(keyPtr, &length); bytesNeeded += TclScanElement(elem, length, flagPtr+i); - if (bytesNeeded > INT_MAX) { + if (bytesNeeded < 0) { Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } flagPtr[i+1] = TCL_DONT_QUOTE_HASH; - valuePtr = (Tcl_Obj *)Tcl_GetHashValue(&cPtr->entry); + valuePtr = Tcl_GetHashValue(&cPtr->entry); elem = TclGetStringFromObj(valuePtr, &length); bytesNeeded += TclScanElement(elem, length, flagPtr+i+1); - if (bytesNeeded > INT_MAX) { + if (bytesNeeded < 0) { Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } } - if (bytesNeeded + numElems > INT_MAX + 1U) { + if (bytesNeeded > INT_MAX - numElems + 1) { Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } bytesNeeded += numElems; @@ -552,26 +522,26 @@ UpdateStringOfDict( * Pass 2: copy into string rep buffer. */ - dst = Tcl_InitStringRep(dictPtr, NULL, bytesNeeded - 1); - TclOOM(dst, bytesNeeded); + dictPtr->length = bytesNeeded - 1; + dictPtr->bytes = ckalloc((unsigned) bytesNeeded); + dst = dictPtr->bytes; for (i=0,cPtr=dict->entryChainHead; i<numElems; i+=2,cPtr=cPtr->nextPtr) { flagPtr[i] |= ( i ? TCL_DONT_QUOTE_HASH : 0 ); - keyPtr = (Tcl_Obj *)Tcl_GetHashKey(&dict->table, &cPtr->entry); + keyPtr = (Tcl_Obj *) Tcl_GetHashKey(&dict->table, &cPtr->entry); elem = TclGetStringFromObj(keyPtr, &length); dst += TclConvertElement(elem, length, dst, flagPtr[i]); *dst++ = ' '; flagPtr[i+1] |= TCL_DONT_QUOTE_HASH; - valuePtr = (Tcl_Obj *)Tcl_GetHashValue(&cPtr->entry); + valuePtr = Tcl_GetHashValue(&cPtr->entry); elem = TclGetStringFromObj(valuePtr, &length); dst += TclConvertElement(elem, length, dst, flagPtr[i+1]); *dst++ = ' '; } - /* Last space overwrote the terminating NUL; cal T_ISR again to restore */ - (void)Tcl_InitStringRep(dictPtr, NULL, bytesNeeded - 1); + dictPtr->bytes[dictPtr->length] = '\0'; if (flagPtr != localFlags) { - ckfree(flagPtr); + ckfree((char *) flagPtr); } } @@ -601,8 +571,8 @@ SetDictFromAny( Tcl_Obj *objPtr) { Tcl_HashEntry *hPtr; - int isNew; - Dict *dict = (Dict *)ckalloc(sizeof(Dict)); + int isNew, result; + Dict *dict = (Dict *) ckalloc(sizeof(Dict)); InitChainTable(dict); @@ -612,7 +582,7 @@ SetDictFromAny( * the conversion from lists to dictionaries. */ - if (TclHasInternalRep(objPtr, &tclListType)) { + if (objPtr->typePtr == &tclListType) { int objc, i; Tcl_Obj **objv; @@ -627,7 +597,7 @@ SetDictFromAny( /* Store key and value in the hash table we're building. */ hPtr = CreateChainEntry(dict, objv[i], &isNew); if (!isNew) { - Tcl_Obj *discardedValue = (Tcl_Obj *)Tcl_GetHashValue(hPtr); + Tcl_Obj *discardedValue = Tcl_GetHashValue(hPtr); /* * Not really a well-formed dictionary as there are duplicate @@ -635,7 +605,7 @@ SetDictFromAny( * convert back. */ - (void) TclGetString(objPtr); + (void) Tcl_GetString(objPtr); TclDecrRefCount(discardedValue); } @@ -650,12 +620,12 @@ SetDictFromAny( while (nextElem < limit) { Tcl_Obj *keyPtr, *valuePtr; const char *elemStart; - int elemSize; - int literal; + int elemSize, literal; - if (TclFindDictElement(interp, nextElem, (limit - nextElem), - &elemStart, &nextElem, &elemSize, &literal) != TCL_OK) { - goto errorInFindDictElement; + result = TclFindElement(interp, nextElem, (limit - nextElem), + &elemStart, &nextElem, &elemSize, &literal); + if (result != TCL_OK) { + goto errorExit; } if (elemStart == limit) { break; @@ -668,40 +638,33 @@ SetDictFromAny( TclNewStringObj(keyPtr, elemStart, elemSize); } else { /* Avoid double copy */ - char *dst; - TclNewObj(keyPtr); - Tcl_InvalidateStringRep(keyPtr); - dst = Tcl_InitStringRep(keyPtr, NULL, elemSize); - TclOOM(dst, elemSize); /* Consider error */ - (void)Tcl_InitStringRep(keyPtr, NULL, - TclCopyAndCollapse(elemSize, elemStart, dst)); + 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) { + result = TclFindElement(interp, nextElem, (limit - nextElem), + &elemStart, &nextElem, &elemSize, &literal); + if (result != TCL_OK) { TclDecrRefCount(keyPtr); - goto errorInFindDictElement; + goto errorExit; } if (literal) { TclNewStringObj(valuePtr, elemStart, elemSize); } else { /* Avoid double copy */ - char *dst; - TclNewObj(valuePtr); - Tcl_InvalidateStringRep(valuePtr); - dst = Tcl_InitStringRep(valuePtr, NULL, elemSize); - TclOOM(dst, elemSize); /* Consider error */ - (void)Tcl_InitStringRep(valuePtr, NULL, - TclCopyAndCollapse(elemSize, elemStart, dst)); + valuePtr->bytes = ckalloc((unsigned) elemSize + 1); + valuePtr->length = TclCopyAndCollapse(elemSize, elemStart, + valuePtr->bytes); } /* Store key and value in the hash table we're building. */ hPtr = CreateChainEntry(dict, keyPtr, &isNew); if (!isNew) { - Tcl_Obj *discardedValue = (Tcl_Obj *)Tcl_GetHashValue(hPtr); + Tcl_Obj *discardedValue = Tcl_GetHashValue(hPtr); TclDecrRefCount(keyPtr); TclDecrRefCount(discardedValue); @@ -717,39 +680,24 @@ SetDictFromAny( * Tcl_GetStringFromObj, to use that old internalRep. */ - dict->epoch = 1; + TclFreeIntRep(objPtr); + dict->epoch = 0; dict->chain = NULL; - dict->refCount = 1; - DictSetInternalRep(objPtr, dict); + dict->refcount = 1; + objPtr->internalRep.twoPtrValue.ptr1 = 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", (void *)NULL); + Tcl_SetResult(interp, "missing value to go with key", TCL_STATIC); } - errorInFindDictElement: - DeleteChainTable(dict); - ckfree(dict); - return TCL_ERROR; -} - -static Dict * -GetDictFromObj( - Tcl_Interp *interp, - Tcl_Obj *dictPtr) -{ - Dict *dict; + result = TCL_ERROR; - DictGetInternalRep(dictPtr, dict); - if (dict == NULL) { - if (SetDictFromAny(interp, dictPtr) != TCL_OK) { - return NULL; - } - DictGetInternalRep(dictPtr, dict); - } - return dict; + errorExit: + DeleteChainTable(dict); + ckfree((char *) dict); + return result; } /* @@ -778,7 +726,7 @@ GetDictFromObj( * the chain fields of the dictionaries (for easy invalidation of string * representations using InvalidateDictChain). If the flags argument has * the DICT_PATH_CREATE bits set (and not the DICT_PATH_EXISTS bit), - * non-extant keys will be inserted with a value of an empty + * non-existant keys will be inserted with a value of an empty * dictionary, resulting in the path being built. * *---------------------------------------------------------------------- @@ -795,19 +743,18 @@ TclTraceDictPath( Dict *dict, *newDict; int i; - DictGetInternalRep(dictPtr, dict); - if (dict == NULL) { + if (dictPtr->typePtr != &tclDictType) { if (SetDictFromAny(interp, dictPtr) != TCL_OK) { return NULL; } - DictGetInternalRep(dictPtr, dict); } + dict = dictPtr->internalRep.twoPtrValue.ptr1; if (flags & DICT_PATH_UPDATE) { dict->chain = NULL; } for (i=0 ; i<keyc ; i++) { - Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&dict->table, keyv[i]); + Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&dict->table, (char *)keyv[i]); Tcl_Obj *tmpObj; if (hPtr == NULL) { @@ -818,11 +765,11 @@ TclTraceDictPath( } if ((flags & DICT_PATH_CREATE) != DICT_PATH_CREATE) { if (interp != NULL) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "key \"%s\" not known in dictionary", - TclGetString(keyv[i]))); + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "key \"", TclGetString(keyv[i]), + "\" not known in dictionary", NULL); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "DICT", - TclGetString(keyv[i]), (void *)NULL); + TclGetString(keyv[i]), NULL); } return NULL; } @@ -836,26 +783,23 @@ TclTraceDictPath( Tcl_IncrRefCount(tmpObj); Tcl_SetHashValue(hPtr, tmpObj); } else { - tmpObj = (Tcl_Obj *)Tcl_GetHashValue(hPtr); - - DictGetInternalRep(tmpObj, newDict); - - if (newDict == NULL) { + tmpObj = Tcl_GetHashValue(hPtr); + if (tmpObj->typePtr != &tclDictType) { if (SetDictFromAny(interp, tmpObj) != TCL_OK) { return NULL; } } } - DictGetInternalRep(tmpObj, newDict); + newDict = tmpObj->internalRep.twoPtrValue.ptr1; if (flags & DICT_PATH_UPDATE) { if (Tcl_IsShared(tmpObj)) { TclDecrRefCount(tmpObj); tmpObj = Tcl_DuplicateObj(tmpObj); Tcl_IncrRefCount(tmpObj); - Tcl_SetHashValue(hPtr, tmpObj); + Tcl_SetHashValue(hPtr, (ClientData) tmpObj); dict->epoch++; - DictGetInternalRep(tmpObj, newDict); + newDict = tmpObj->internalRep.twoPtrValue.ptr1; } newDict->chain = dictPtr; @@ -871,7 +815,7 @@ TclTraceDictPath( * * InvalidateDictChain -- * - * Go through a dictionary chain (built by an updating invocation of + * Go through a dictionary chain (built by an updating invokation of * TclTraceDictPath) and invalidate the string representations of all the * dictionaries on the chain. * @@ -890,24 +834,17 @@ static void InvalidateDictChain( Tcl_Obj *dictObj) { - Dict *dict; - - DictGetInternalRep(dictObj, dict); - assert( dict != NULL); + Dict *dict = dictObj->internalRep.twoPtrValue.ptr1; do { - dict->refCount++; TclInvalidateStringRep(dictObj); - TclFreeInternalRep(dictObj); - DictSetInternalRep(dictObj, dict); - dict->epoch++; dictObj = dict->chain; if (dictObj == NULL) { break; } dict->chain = NULL; - DictGetInternalRep(dictObj, dict); + dict = dictObj->internalRep.twoPtrValue.ptr1; } while (dict != NULL); } @@ -945,19 +882,22 @@ Tcl_DictObjPut( Tcl_Panic("%s called with shared object", "Tcl_DictObjPut"); } - dict = GetDictFromObj(interp, dictPtr); - if (dict == NULL) { - return TCL_ERROR; + if (dictPtr->typePtr != &tclDictType) { + int result = SetDictFromAny(interp, dictPtr); + + if (result != TCL_OK) { + return result; + } } - TclInvalidateStringRep(dictPtr); + if (dictPtr->bytes != NULL) { + TclInvalidateStringRep(dictPtr); + } + dict = dictPtr->internalRep.twoPtrValue.ptr1; hPtr = CreateChainEntry(dict, keyPtr, &isNew); - dict->refCount++; - TclFreeInternalRep(dictPtr) - DictSetInternalRep(dictPtr, dict); Tcl_IncrRefCount(valuePtr); if (!isNew) { - Tcl_Obj *oldValuePtr = (Tcl_Obj *)Tcl_GetHashValue(hPtr); + Tcl_Obj *oldValuePtr = Tcl_GetHashValue(hPtr); TclDecrRefCount(oldValuePtr); } @@ -996,17 +936,20 @@ Tcl_DictObjGet( Dict *dict; Tcl_HashEntry *hPtr; - dict = GetDictFromObj(interp, dictPtr); - if (dict == NULL) { - *valuePtrPtr = NULL; - return TCL_ERROR; + if (dictPtr->typePtr != &tclDictType) { + int result = SetDictFromAny(interp, dictPtr); + if (result != TCL_OK) { + *valuePtrPtr = NULL; + return result; + } } - hPtr = Tcl_FindHashEntry(&dict->table, keyPtr); + dict = dictPtr->internalRep.twoPtrValue.ptr1; + hPtr = Tcl_FindHashEntry(&dict->table, (char *) keyPtr); if (hPtr == NULL) { *valuePtrPtr = NULL; } else { - *valuePtrPtr = (Tcl_Obj *)Tcl_GetHashValue(hPtr); + *valuePtrPtr = Tcl_GetHashValue(hPtr); } return TCL_OK; } @@ -1042,13 +985,18 @@ Tcl_DictObjRemove( Tcl_Panic("%s called with shared object", "Tcl_DictObjRemove"); } - dict = GetDictFromObj(interp, dictPtr); - if (dict == NULL) { - return TCL_ERROR; + if (dictPtr->typePtr != &tclDictType) { + int result = SetDictFromAny(interp, dictPtr); + if (result != TCL_OK) { + return result; + } } - if (DeleteChainEntry(dict, keyPtr)) { + if (dictPtr->bytes != NULL) { TclInvalidateStringRep(dictPtr); + } + dict = dictPtr->internalRep.twoPtrValue.ptr1; + if (DeleteChainEntry(dict, keyPtr)) { dict->epoch++; } return TCL_OK; @@ -1072,7 +1020,6 @@ Tcl_DictObjRemove( *---------------------------------------------------------------------- */ -#undef Tcl_DictObjSize int Tcl_DictObjSize( Tcl_Interp *interp, @@ -1081,11 +1028,14 @@ Tcl_DictObjSize( { Dict *dict; - dict = GetDictFromObj(interp, dictPtr); - if (dict == NULL) { - return TCL_ERROR; + if (dictPtr->typePtr != &tclDictType) { + int result = SetDictFromAny(interp, dictPtr); + if (result != TCL_OK) { + return result; + } } + dict = dictPtr->internalRep.twoPtrValue.ptr1; *sizePtr = dict->table.numEntries; return TCL_OK; } @@ -1132,26 +1082,31 @@ Tcl_DictObjFirst( Dict *dict; ChainEntry *cPtr; - dict = GetDictFromObj(interp, dictPtr); - if (dict == NULL) { - return TCL_ERROR; + if (dictPtr->typePtr != &tclDictType) { + int result = SetDictFromAny(interp, dictPtr); + + if (result != TCL_OK) { + return result; + } } + dict = dictPtr->internalRep.twoPtrValue.ptr1; cPtr = dict->entryChainHead; if (cPtr == NULL) { - searchPtr->epoch = 0; + searchPtr->epoch = -1; *donePtr = 1; } else { *donePtr = 0; searchPtr->dictionaryPtr = (Tcl_Dict) dict; searchPtr->epoch = dict->epoch; searchPtr->next = cPtr->nextPtr; - dict->refCount++; + dict->refcount++; if (keyPtrPtr != NULL) { - *keyPtrPtr = (Tcl_Obj *)Tcl_GetHashKey(&dict->table, &cPtr->entry); + *keyPtrPtr = (Tcl_Obj *) Tcl_GetHashKey(&dict->table, + &cPtr->entry); } if (valuePtrPtr != NULL) { - *valuePtrPtr = (Tcl_Obj *)Tcl_GetHashValue(&cPtr->entry); + *valuePtrPtr = Tcl_GetHashValue(&cPtr->entry); } } return TCL_OK; @@ -1197,10 +1152,10 @@ Tcl_DictObjNext( ChainEntry *cPtr; /* - * If the search is done; we do no work. + * If the searh is done; we do no work. */ - if (!searchPtr->epoch) { + if (searchPtr->epoch == -1) { *donePtr = 1; return; } @@ -1214,7 +1169,7 @@ Tcl_DictObjNext( Tcl_Panic("concurrent dictionary modification and search"); } - cPtr = (ChainEntry *)searchPtr->next; + cPtr = searchPtr->next; if (cPtr == NULL) { Tcl_DictObjDone(searchPtr); *donePtr = 1; @@ -1224,11 +1179,11 @@ Tcl_DictObjNext( searchPtr->next = cPtr->nextPtr; *donePtr = 0; if (keyPtrPtr != NULL) { - *keyPtrPtr = (Tcl_Obj *)Tcl_GetHashKey( + *keyPtrPtr = (Tcl_Obj *) Tcl_GetHashKey( &((Dict *)searchPtr->dictionaryPtr)->table, &cPtr->entry); } if (valuePtrPtr != NULL) { - *valuePtrPtr = (Tcl_Obj *)Tcl_GetHashValue(&cPtr->entry); + *valuePtrPtr = Tcl_GetHashValue(&cPtr->entry); } } @@ -1257,10 +1212,11 @@ Tcl_DictObjDone( { Dict *dict; - if (searchPtr->epoch) { - searchPtr->epoch = 0; + if (searchPtr->epoch != -1) { + searchPtr->epoch = -1; dict = (Dict *) searchPtr->dictionaryPtr; - if (dict->refCount-- <= 1) { + dict->refcount--; + if (dict->refcount <= 0) { DeleteDict(dict); } } @@ -1310,13 +1266,11 @@ Tcl_DictObjPutKeyList( return TCL_ERROR; } - DictGetInternalRep(dictPtr, dict); - assert(dict != NULL); + dict = dictPtr->internalRep.twoPtrValue.ptr1; hPtr = CreateChainEntry(dict, keyv[keyc-1], &isNew); Tcl_IncrRefCount(valuePtr); if (!isNew) { - Tcl_Obj *oldValuePtr = (Tcl_Obj *)Tcl_GetHashValue(hPtr); - + Tcl_Obj *oldValuePtr = Tcl_GetHashValue(hPtr); TclDecrRefCount(oldValuePtr); } Tcl_SetHashValue(hPtr, valuePtr); @@ -1368,8 +1322,7 @@ Tcl_DictObjRemoveKeyList( return TCL_ERROR; } - DictGetInternalRep(dictPtr, dict); - assert(dict != NULL); + dict = dictPtr->internalRep.twoPtrValue.ptr1; DeleteChainEntry(dict, keyv[keyc-1]); InvalidateDictChain(dictPtr); return TCL_OK; @@ -1410,12 +1363,13 @@ Tcl_NewDictObj(void) TclNewObj(dictPtr); TclInvalidateStringRep(dictPtr); - dict = (Dict *)ckalloc(sizeof(Dict)); + dict = (Dict *) ckalloc(sizeof(Dict)); InitChainTable(dict); - dict->epoch = 1; + dict->epoch = 0; dict->chain = NULL; - dict->refCount = 1; - DictSetInternalRep(dictPtr, dict); + dict->refcount = 1; + dictPtr->internalRep.twoPtrValue.ptr1 = dict; + dictPtr->typePtr = &tclDictType; return dictPtr; #endif } @@ -1447,34 +1401,29 @@ Tcl_NewDictObj(void) *---------------------------------------------------------------------- */ -#ifdef TCL_MEM_DEBUG Tcl_Obj * Tcl_DbNewDictObj( const char *file, int line) { +#ifdef TCL_MEM_DEBUG Tcl_Obj *dictPtr; Dict *dict; TclDbNewObj(dictPtr, file, line); TclInvalidateStringRep(dictPtr); - dict = (Dict *)ckalloc(sizeof(Dict)); + dict = (Dict *) ckalloc(sizeof(Dict)); InitChainTable(dict); - dict->epoch = 1; + dict->epoch = 0; dict->chain = NULL; - dict->refCount = 1; - DictSetInternalRep(dictPtr, dict); + dict->refcount = 1; + dictPtr->internalRep.twoPtrValue.ptr1 = dict; + dictPtr->typePtr = &tclDictType; return dictPtr; -} #else /* !TCL_MEM_DEBUG */ -Tcl_Obj * -Tcl_DbNewDictObj( - TCL_UNUSED(const char *) /*file*/, - TCL_UNUSED(int) /*line*/) -{ return Tcl_NewDictObj(); -} #endif +} /***** START OF FUNCTIONS IMPLEMENTING TCL COMMANDS *****/ @@ -1498,7 +1447,7 @@ Tcl_DbNewDictObj( static int DictCreateCmd( - TCL_UNUSED(void *), + ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) @@ -1522,7 +1471,7 @@ DictCreateCmd( /* * The next command is assumed to never fail... */ - Tcl_DictObjPut(NULL, dictObj, objv[i], objv[i+1]); + Tcl_DictObjPut(interp, dictObj, objv[i], objv[i+1]); } Tcl_SetObjResult(interp, dictObj); return TCL_OK; @@ -1548,7 +1497,7 @@ DictCreateCmd( static int DictGetCmd( - TCL_UNUSED(void *), + ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) @@ -1557,7 +1506,7 @@ DictGetCmd( int result; if (objc < 2) { - Tcl_WrongNumArgs(interp, 1, objv, "dictionary ?key ...?"); + Tcl_WrongNumArgs(interp, 1, objv, "dictionary ?key key ...?"); return TCL_ERROR; } @@ -1568,7 +1517,7 @@ DictGetCmd( */ if (objc == 2) { - Tcl_Obj *keyPtr = NULL, *listPtr; + Tcl_Obj *keyPtr, *listPtr; Tcl_DictSearch search; int done; @@ -1610,11 +1559,9 @@ DictGetCmd( return result; } if (valuePtr == NULL) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "key \"%s\" not known in dictionary", - TclGetString(objv[objc-1]))); - Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "DICT", - TclGetString(objv[objc-1]), (void *)NULL); + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "key \"", TclGetString(objv[objc-1]), + "\" not known in dictionary", NULL); return TCL_ERROR; } Tcl_SetObjResult(interp, valuePtr); @@ -1624,71 +1571,6 @@ DictGetCmd( /* *---------------------------------------------------------------------- * - * DictGetDefCmd -- - * - * This function implements the "dict getdef" and "dict getwithdefault" - * Tcl commands. See the user documentation for details on what it does, - * and TIP#342 for the formal specification. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *---------------------------------------------------------------------- - */ - -static int -DictGetDefCmd( - TCL_UNUSED(void *), - Tcl_Interp *interp, - int objc, - Tcl_Obj *const *objv) -{ - Tcl_Obj *dictPtr, *keyPtr, *valuePtr, *defaultPtr; - Tcl_Obj *const *keyPath; - int numKeys; - - if (objc < 4) { - Tcl_WrongNumArgs(interp, 1, objv, "dictionary ?key ...? key default"); - return TCL_ERROR; - } - - /* - * Give the bits of arguments names for clarity. - */ - - dictPtr = objv[1]; - keyPath = &objv[2]; - numKeys = objc - 4; /* Number of keys in keyPath; there's always - * one extra key afterwards too. */ - keyPtr = objv[objc - 2]; - defaultPtr = objv[objc - 1]; - - /* - * Implement the getting-with-default operation. - */ - - dictPtr = TclTraceDictPath(interp, dictPtr, numKeys, keyPath, - DICT_PATH_EXISTS); - if (dictPtr == NULL) { - return TCL_ERROR; - } else if (dictPtr == DICT_PATH_NON_EXISTENT) { - Tcl_SetObjResult(interp, defaultPtr); - } else if (Tcl_DictObjGet(interp, dictPtr, keyPtr, &valuePtr) != TCL_OK) { - return TCL_ERROR; - } else if (valuePtr == NULL) { - Tcl_SetObjResult(interp, defaultPtr); - } else { - Tcl_SetObjResult(interp, valuePtr); - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * * DictReplaceCmd -- * * This function implements the "dict replace" Tcl command. See the user @@ -1706,13 +1588,14 @@ DictGetDefCmd( static int DictReplaceCmd( - TCL_UNUSED(void *), + ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Tcl_Obj *dictPtr; - int i; + int i, result; + int allocatedDict = 0; if ((objc < 2) || (objc & 1)) { Tcl_WrongNumArgs(interp, 1, objv, "dictionary ?key value ...?"); @@ -1720,15 +1603,18 @@ DictReplaceCmd( } dictPtr = objv[1]; - if (GetDictFromObj(interp, dictPtr) == NULL) { - return TCL_ERROR; - } if (Tcl_IsShared(dictPtr)) { dictPtr = Tcl_DuplicateObj(dictPtr); + allocatedDict = 1; } - TclInvalidateStringRep(dictPtr); for (i=2 ; i<objc ; i+=2) { - Tcl_DictObjPut(NULL, dictPtr, objv[i], objv[i+1]); + result = Tcl_DictObjPut(interp, dictPtr, objv[i], objv[i+1]); + if (result != TCL_OK) { + if (allocatedDict) { + TclDecrRefCount(dictPtr); + } + return TCL_ERROR; + } } Tcl_SetObjResult(interp, dictPtr); return TCL_OK; @@ -1754,13 +1640,14 @@ DictReplaceCmd( static int DictRemoveCmd( - TCL_UNUSED(void *), + ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Tcl_Obj *dictPtr; - int i; + int i, result; + int allocatedDict = 0; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "dictionary ?key ...?"); @@ -1768,15 +1655,18 @@ DictRemoveCmd( } dictPtr = objv[1]; - if (GetDictFromObj(interp, dictPtr) == NULL) { - return TCL_ERROR; - } if (Tcl_IsShared(dictPtr)) { dictPtr = Tcl_DuplicateObj(dictPtr); + allocatedDict = 1; } - TclInvalidateStringRep(dictPtr); for (i=2 ; i<objc ; i++) { - Tcl_DictObjRemove(NULL, dictPtr, objv[i]); + result = Tcl_DictObjRemove(interp, dictPtr, objv[i]); + if (result != TCL_OK) { + if (allocatedDict) { + TclDecrRefCount(dictPtr); + } + return TCL_ERROR; + } } Tcl_SetObjResult(interp, dictPtr); return TCL_OK; @@ -1802,12 +1692,12 @@ DictRemoveCmd( static int DictMergeCmd( - TCL_UNUSED(void *), + ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { - Tcl_Obj *targetObj, *keyObj = NULL, *valueObj = NULL; + Tcl_Obj *targetObj, *keyObj, *valueObj; int allocatedDict = 0; int i, done; Tcl_DictSearch search; @@ -1825,8 +1715,10 @@ DictMergeCmd( */ targetObj = objv[1]; - if (GetDictFromObj(interp, targetObj) == NULL) { - return TCL_ERROR; + if (targetObj->typePtr != &tclDictType) { + if (SetDictFromAny(interp, targetObj) != TCL_OK) { + return TCL_ERROR; + } } if (objc == 2) { @@ -1889,13 +1781,13 @@ DictMergeCmd( static int DictKeysCmd( - TCL_UNUSED(void *), + ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Tcl_Obj *listPtr; - const char *pattern = NULL; + char *pattern = NULL; if (objc!=2 && objc!=3) { Tcl_WrongNumArgs(interp, 1, objv, "dictionary ?pattern?"); @@ -1908,8 +1800,12 @@ DictKeysCmd( * need. [Bug 1705778, leak K04] */ - if (GetDictFromObj(interp, objv[1]) == NULL) { - return TCL_ERROR; + if (objv[1]->typePtr != &tclDictType) { + int result = SetDictFromAny(interp, objv[1]); + + if (result != TCL_OK) { + return result; + } } if (objc == 3) { @@ -1925,8 +1821,8 @@ DictKeysCmd( } } else { Tcl_DictSearch search; - Tcl_Obj *keyPtr = NULL; - int done = 0; + Tcl_Obj *keyPtr; + int done; /* * At this point, we know we have a dictionary (or at least something @@ -1968,15 +1864,15 @@ DictKeysCmd( static int DictValuesCmd( - TCL_UNUSED(void *), + ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { - Tcl_Obj *valuePtr = NULL, *listPtr; + Tcl_Obj *valuePtr, *listPtr; Tcl_DictSearch search; int done; - const char *pattern; + char *pattern; if (objc!=2 && objc!=3) { Tcl_WrongNumArgs(interp, 1, objv, "dictionary ?pattern?"); @@ -2028,13 +1924,12 @@ DictValuesCmd( static int DictSizeCmd( - TCL_UNUSED(void *), + ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { - int result; - int size; + int result, size; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "dictionary"); @@ -2042,7 +1937,7 @@ DictSizeCmd( } result = Tcl_DictObjSize(interp, objv[1], &size); if (result == TCL_OK) { - Tcl_SetObjResult(interp, Tcl_NewWideIntObj(size)); + Tcl_SetObjResult(interp, Tcl_NewIntObj(size)); } return result; } @@ -2067,7 +1962,7 @@ DictSizeCmd( static int DictExistsCmd( - TCL_UNUSED(void *), + ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) @@ -2079,9 +1974,11 @@ DictExistsCmd( return TCL_ERROR; } - dictPtr = TclTraceDictPath(NULL, objv[1], objc-3, objv+2,DICT_PATH_EXISTS); - if (dictPtr == NULL || dictPtr == DICT_PATH_NON_EXISTENT || - Tcl_DictObjGet(NULL, dictPtr, objv[objc-1], &valuePtr) != TCL_OK) { + dictPtr = TclTraceDictPath(interp, objv[1], objc-3, objv+2, + DICT_PATH_EXISTS); + if (dictPtr == NULL || dictPtr == DICT_PATH_NON_EXISTENT + || Tcl_DictObjGet(interp, dictPtr, objv[objc-1], + &valuePtr) != TCL_OK) { Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); } else { Tcl_SetObjResult(interp, Tcl_NewBooleanObj(valuePtr != NULL)); @@ -2109,27 +2006,33 @@ DictExistsCmd( static int DictInfoCmd( - TCL_UNUSED(void *), + ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { + Tcl_Obj *dictPtr; Dict *dict; - char *statsStr; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "dictionary"); return TCL_ERROR; } - dict = GetDictFromObj(interp, objv[1]); - if (dict == NULL) { - return TCL_ERROR; + dictPtr = objv[1]; + if (dictPtr->typePtr != &tclDictType) { + int result = SetDictFromAny(interp, dictPtr); + if (result != TCL_OK) { + return result; + } } + dict = dictPtr->internalRep.twoPtrValue.ptr1; + + /* + * This next cast is actually OK. + */ - statsStr = Tcl_HashStats(&dict->table); - Tcl_SetObjResult(interp, Tcl_NewStringObj(statsStr, -1)); - ckfree(statsStr); + Tcl_SetResult(interp, (char *) Tcl_HashStats(&dict->table), TCL_DYNAMIC); return TCL_OK; } @@ -2153,7 +2056,7 @@ DictInfoCmd( static int DictIncrCmd( - TCL_UNUSED(void *), + ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) @@ -2162,7 +2065,7 @@ DictIncrCmd( Tcl_Obj *dictPtr, *valuePtr = NULL; if (objc < 3 || objc > 4) { - Tcl_WrongNumArgs(interp, 1, objv, "dictVarName key ?increment?"); + Tcl_WrongNumArgs(interp, 1, objv, "varName key ?increment?"); return TCL_ERROR; } @@ -2186,11 +2089,12 @@ DictIncrCmd( * soon be no good. */ + char *saved = dictPtr->bytes; Tcl_Obj *oldPtr = dictPtr; - TclNewObj(dictPtr); - TclInvalidateStringRep(dictPtr); - DupDictInternalRep(oldPtr, dictPtr); + dictPtr->bytes = NULL; + dictPtr = Tcl_DuplicateObj(dictPtr); + oldPtr->bytes = saved; } if (valuePtr == NULL) { /* @@ -2214,10 +2118,10 @@ DictIncrCmd( */ mp_clear(&increment); - Tcl_DictObjPut(NULL, dictPtr, objv[2], objv[3]); + Tcl_DictObjPut(interp, dictPtr, objv[2], objv[3]); } } else { - Tcl_DictObjPut(NULL, dictPtr, objv[2], Tcl_NewWideIntObj(1)); + Tcl_DictObjPut(interp, dictPtr, objv[2], Tcl_NewIntObj(1)); } } else { /* @@ -2226,17 +2130,16 @@ DictIncrCmd( if (Tcl_IsShared(valuePtr)) { valuePtr = Tcl_DuplicateObj(valuePtr); - Tcl_DictObjPut(NULL, dictPtr, objv[2], valuePtr); + Tcl_DictObjPut(interp, dictPtr, objv[2], valuePtr); } if (objc == 4) { code = TclIncrObj(interp, valuePtr, objv[3]); } else { - Tcl_Obj *incrPtr; + Tcl_Obj *incrPtr = Tcl_NewIntObj(1); - TclNewIntObj(incrPtr, 1); Tcl_IncrRefCount(incrPtr); code = TclIncrObj(interp, valuePtr, incrPtr); - TclDecrRefCount(incrPtr); + Tcl_DecrRefCount(incrPtr); } } if (code == TCL_OK) { @@ -2249,7 +2152,7 @@ DictIncrCmd( Tcl_SetObjResult(interp, valuePtr); } } else if (dictPtr->refCount == 0) { - TclDecrRefCount(dictPtr); + Tcl_DecrRefCount(dictPtr); } return code; } @@ -2274,7 +2177,7 @@ DictIncrCmd( static int DictLappendCmd( - TCL_UNUSED(void *), + ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) @@ -2283,7 +2186,7 @@ DictLappendCmd( int i, allocatedDict = 0, allocatedValue = 0; if (objc < 3) { - Tcl_WrongNumArgs(interp, 1, objv, "dictVarName key ?value ...?"); + Tcl_WrongNumArgs(interp, 1, objv, "varName key ?value ...?"); return TCL_ERROR; } @@ -2327,8 +2230,8 @@ DictLappendCmd( } if (allocatedValue) { - Tcl_DictObjPut(NULL, dictPtr, objv[2], valuePtr); - } else { + Tcl_DictObjPut(interp, dictPtr, objv[2], valuePtr); + } else if (dictPtr->bytes != NULL) { TclInvalidateStringRep(dictPtr); } @@ -2361,16 +2264,16 @@ DictLappendCmd( static int DictAppendCmd( - TCL_UNUSED(void *), + ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Tcl_Obj *dictPtr, *valuePtr, *resultPtr; - int allocatedDict = 0; + int i, allocatedDict = 0; if (objc < 3) { - Tcl_WrongNumArgs(interp, 1, objv, "dictVarName key ?value ...?"); + Tcl_WrongNumArgs(interp, 1, objv, "varName key ?value ...?"); return TCL_ERROR; } @@ -2390,49 +2293,19 @@ DictAppendCmd( return TCL_ERROR; } - if ((objc > 3) || (valuePtr == NULL)) { - /* Only go through append activites when something will change. */ - Tcl_Obj *appendObjPtr = NULL; - - if (objc > 3) { - /* Something to append */ - - if (objc == 4) { - appendObjPtr = objv[3]; - } else { - appendObjPtr = TclStringCat(interp, objc-3, objv+3, - TCL_STRING_IN_PLACE); - if (appendObjPtr == NULL) { - return TCL_ERROR; - } - } - } - - if (appendObjPtr == NULL) { - /* => (objc == 3) => (valuePtr == NULL) */ - TclNewObj(valuePtr); - } else if (valuePtr == NULL) { - valuePtr = appendObjPtr; - appendObjPtr = NULL; - } - - if (appendObjPtr) { - if (Tcl_IsShared(valuePtr)) { - valuePtr = Tcl_DuplicateObj(valuePtr); - } - - Tcl_IncrRefCount(appendObjPtr); - Tcl_AppendObjToObj(valuePtr, appendObjPtr); - Tcl_DecrRefCount(appendObjPtr); + if (valuePtr == NULL) { + TclNewObj(valuePtr); + } else { + if (Tcl_IsShared(valuePtr)) { + valuePtr = Tcl_DuplicateObj(valuePtr); } + } - Tcl_DictObjPut(NULL, dictPtr, objv[2], valuePtr); + for (i=3 ; i<objc ; i++) { + Tcl_AppendObjToObj(valuePtr, objv[i]); } - /* - * Even if nothing changed, we still overwrite so that variable - * trace expectations are met. - */ + Tcl_DictObjPut(interp, dictPtr, objv[2], valuePtr); resultPtr = Tcl_ObjSetVar2(interp, objv[1], NULL, dictPtr, TCL_LEAVE_ERR_MSG); @@ -2446,9 +2319,9 @@ DictAppendCmd( /* *---------------------------------------------------------------------- * - * DictForNRCmd -- + * DictForCmd -- * - * These functions implement the "dict for" Tcl command. See the user + * This function implements the "dict for" Tcl command. See the user * documentation for details on what it does, and TIP#111 for the formal * specification. * @@ -2462,8 +2335,8 @@ DictAppendCmd( */ static int -DictForNRCmd( - TCL_UNUSED(void *), +DictForCmd( + ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) @@ -2471,44 +2344,32 @@ DictForNRCmd( Interp *iPtr = (Interp *) interp; Tcl_Obj *scriptObj, *keyVarObj, *valueVarObj; Tcl_Obj **varv, *keyObj, *valueObj; - Tcl_DictSearch *searchPtr; - int varc; - int done; + Tcl_DictSearch search; + int varc, done, result; if (objc != 4) { Tcl_WrongNumArgs(interp, 1, objv, - "{keyVarName valueVarName} dictionary script"); + "{keyVar valueVar} dictionary script"); return TCL_ERROR; } - /* - * Parse arguments. - */ - 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", (void *)NULL); - return TCL_ERROR; - } - searchPtr = (Tcl_DictSearch *)TclStackAlloc(interp, sizeof(Tcl_DictSearch)); - if (Tcl_DictObjFirst(interp, objv[2], searchPtr, &keyObj, &valueObj, - &done) != TCL_OK) { - TclStackFree(interp, searchPtr); + Tcl_SetResult(interp, "must have exactly two variable names", + TCL_STATIC); return TCL_ERROR; } - if (done) { - TclStackFree(interp, searchPtr); - return TCL_OK; - } - TclListObjGetElements(NULL, objv[1], &varc, &varv); keyVarObj = varv[0]; valueVarObj = varv[1]; scriptObj = objv[3]; + if (Tcl_DictObjFirst(interp, objv[2], &search, &keyObj, &valueObj, + &done) != TCL_OK) { + return TCL_ERROR; + } + /* * Make sure that these objects (which we need throughout the body of the * loop) don't vanish. Note that the dictionary internal rep is locked @@ -2519,336 +2380,64 @@ DictForNRCmd( Tcl_IncrRefCount(valueVarObj); Tcl_IncrRefCount(scriptObj); - /* - * 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. - */ - - TclNRAddCallback(interp, DictForLoopCallback, searchPtr, keyVarObj, - valueVarObj, scriptObj); - return TclNREvalObjEx(interp, scriptObj, 0, iPtr->cmdFramePtr, 3); - - /* - * For unwinding everything on error. - */ - - error: - TclDecrRefCount(keyVarObj); - TclDecrRefCount(valueVarObj); - TclDecrRefCount(scriptObj); - Tcl_DictObjDone(searchPtr); - TclStackFree(interp, searchPtr); - return TCL_ERROR; -} - -static int -DictForLoopCallback( - void *data[], - Tcl_Interp *interp, - int result) -{ - Interp *iPtr = (Interp *) interp; - Tcl_DictSearch *searchPtr = (Tcl_DictSearch *)data[0]; - Tcl_Obj *keyVarObj = (Tcl_Obj *)data[1]; - Tcl_Obj *valueVarObj = (Tcl_Obj *)data[2]; - Tcl_Obj *scriptObj = (Tcl_Obj *)data[3]; - Tcl_Obj *keyObj, *valueObj; - int done; - - /* - * Process the result from the previous execution of the script body. - */ + result = TCL_OK; + while (!done) { + /* + * Stop the value from getting hit in any way by any traces on the key + * variable. + */ - if (result == TCL_CONTINUE) { - result = TCL_OK; - } else if (result != TCL_OK) { - if (result == TCL_BREAK) { + Tcl_IncrRefCount(valueObj); + if (Tcl_ObjSetVar2(interp, keyVarObj, NULL, keyObj, 0) == NULL) { Tcl_ResetResult(interp); - result = TCL_OK; - } else if (result == TCL_ERROR) { - Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( - "\n (\"dict for\" body line %d)", - Tcl_GetErrorLine(interp))); + Tcl_AppendResult(interp, "couldn't set key variable: \"", + TclGetString(keyVarObj), "\"", NULL); + TclDecrRefCount(valueObj); + result = TCL_ERROR; + break; } - goto done; - } - - /* - * Get the next mapping from the dictionary. - */ - - Tcl_DictObjNext(searchPtr, &keyObj, &valueObj, &done); - if (done) { - Tcl_ResetResult(interp); - goto done; - } - - /* - * 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); - result = TCL_ERROR; - goto done; - } - TclDecrRefCount(valueObj); - if (Tcl_ObjSetVar2(interp, valueVarObj, NULL, valueObj, - TCL_LEAVE_ERR_MSG) == NULL) { - result = TCL_ERROR; - goto done; - } - - /* - * Run the script. - */ - - TclNRAddCallback(interp, DictForLoopCallback, searchPtr, keyVarObj, - valueVarObj, scriptObj); - return TclNREvalObjEx(interp, scriptObj, 0, iPtr->cmdFramePtr, 3); - - /* - * For unwinding everything once the iterating is done. - */ - - done: - TclDecrRefCount(keyVarObj); - TclDecrRefCount(valueVarObj); - TclDecrRefCount(scriptObj); - Tcl_DictObjDone(searchPtr); - TclStackFree(interp, searchPtr); - return result; -} - -/* - *---------------------------------------------------------------------- - * - * DictMapNRCmd -- - * - * These functions implement the "dict map" Tcl command. See the user - * documentation for details on what it does, and TIP#405 for the formal - * specification. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * See the user documentation. - * - *---------------------------------------------------------------------- - */ - -static int -DictMapNRCmd( - TCL_UNUSED(void *), - Tcl_Interp *interp, - int objc, - Tcl_Obj *const *objv) -{ - Interp *iPtr = (Interp *) interp; - Tcl_Obj **varv, *keyObj, *valueObj; - DictMapStorage *storagePtr; - int varc; - int done; - - if (objc != 4) { - Tcl_WrongNumArgs(interp, 1, objv, - "{keyVarName valueVarName} dictionary script"); - return TCL_ERROR; - } - - /* - * Parse arguments. - */ + if (Tcl_ObjSetVar2(interp, valueVarObj, NULL, valueObj, 0) == NULL) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "couldn't set value variable: \"", + TclGetString(valueVarObj), "\"", NULL); + result = TCL_ERROR; + break; + } - 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", (void *)NULL); - return TCL_ERROR; - } - storagePtr = (DictMapStorage *)TclStackAlloc(interp, sizeof(DictMapStorage)); - if (Tcl_DictObjFirst(interp, objv[2], &storagePtr->search, &keyObj, - &valueObj, &done) != TCL_OK) { - TclStackFree(interp, storagePtr); - return TCL_ERROR; - } - if (done) { /* - * Note that this exit leaves an empty value in the result (due to - * command calling conventions) but that is OK since an empty value is - * an empty dictionary. + * TIP #280. Make invoking context available to loop body. */ - TclStackFree(interp, storagePtr); - return TCL_OK; - } - TclNewObj(storagePtr->accumulatorObj); - TclListObjGetElements(NULL, objv[1], &varc, &varv); - storagePtr->keyVarObj = varv[0]; - storagePtr->valueVarObj = varv[1]; - storagePtr->scriptObj = objv[3]; - - /* - * Make sure that these objects (which we need throughout the body of the - * loop) don't vanish. Note that the dictionary internal rep is locked - * internally so that updates, shimmering, etc are not a problem. - */ - - Tcl_IncrRefCount(storagePtr->accumulatorObj); - Tcl_IncrRefCount(storagePtr->keyVarObj); - Tcl_IncrRefCount(storagePtr->valueVarObj); - Tcl_IncrRefCount(storagePtr->scriptObj); - - /* - * Stop the value from getting hit in any way by any traces on the key - * variable. - */ - - Tcl_IncrRefCount(valueObj); - if (Tcl_ObjSetVar2(interp, storagePtr->keyVarObj, NULL, keyObj, - TCL_LEAVE_ERR_MSG) == NULL) { - TclDecrRefCount(valueObj); - goto error; - } - if (Tcl_ObjSetVar2(interp, storagePtr->valueVarObj, NULL, valueObj, - TCL_LEAVE_ERR_MSG) == NULL) { - TclDecrRefCount(valueObj); - goto error; - } - TclDecrRefCount(valueObj); - - /* - * Run the script. - */ - - TclNRAddCallback(interp, DictMapLoopCallback, storagePtr, NULL,NULL,NULL); - return TclNREvalObjEx(interp, storagePtr->scriptObj, 0, - iPtr->cmdFramePtr, 3); - - /* - * For unwinding everything on error. - */ - - error: - TclDecrRefCount(storagePtr->keyVarObj); - TclDecrRefCount(storagePtr->valueVarObj); - TclDecrRefCount(storagePtr->scriptObj); - TclDecrRefCount(storagePtr->accumulatorObj); - Tcl_DictObjDone(&storagePtr->search); - TclStackFree(interp, storagePtr); - return TCL_ERROR; -} - -static int -DictMapLoopCallback( - void *data[], - Tcl_Interp *interp, - int result) -{ - Interp *iPtr = (Interp *) interp; - DictMapStorage *storagePtr = (DictMapStorage *)data[0]; - Tcl_Obj *keyObj, *valueObj; - int done; - - /* - * Process the result from the previous execution of the script body. - */ - - if (result == TCL_CONTINUE) { - result = TCL_OK; - } else if (result != TCL_OK) { - if (result == TCL_BREAK) { - Tcl_ResetResult(interp); + result = TclEvalObjEx(interp, scriptObj, 0, iPtr->cmdFramePtr, 3); + if (result == TCL_CONTINUE) { result = TCL_OK; - } else if (result == TCL_ERROR) { - Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( - "\n (\"dict map\" body line %d)", - Tcl_GetErrorLine(interp))); - } - goto done; - } else { - keyObj = Tcl_ObjGetVar2(interp, storagePtr->keyVarObj, NULL, - TCL_LEAVE_ERR_MSG); - if (keyObj == NULL) { - result = TCL_ERROR; - goto done; + } else if (result != TCL_OK) { + if (result == TCL_BREAK) { + result = TCL_OK; + } else if (result == TCL_ERROR) { + Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( + "\n (\"dict for\" body line %d)", + interp->errorLine)); + } + break; } - Tcl_DictObjPut(NULL, storagePtr->accumulatorObj, keyObj, - Tcl_GetObjResult(interp)); - } - - /* - * Get the next mapping from the dictionary. - */ - Tcl_DictObjNext(&storagePtr->search, &keyObj, &valueObj, &done); - if (done) { - Tcl_SetObjResult(interp, storagePtr->accumulatorObj); - goto done; + Tcl_DictObjNext(&search, &keyObj, &valueObj, &done); } /* - * Stop the value from getting hit in any way by any traces on the key - * variable. + * Stop holding a reference to these objects. */ - Tcl_IncrRefCount(valueObj); - if (Tcl_ObjSetVar2(interp, storagePtr->keyVarObj, NULL, keyObj, - TCL_LEAVE_ERR_MSG) == NULL) { - TclDecrRefCount(valueObj); - result = TCL_ERROR; - goto done; - } - if (Tcl_ObjSetVar2(interp, storagePtr->valueVarObj, NULL, valueObj, - TCL_LEAVE_ERR_MSG) == NULL) { - TclDecrRefCount(valueObj); - result = TCL_ERROR; - goto done; - } - TclDecrRefCount(valueObj); - - /* - * Run the script. - */ - - TclNRAddCallback(interp, DictMapLoopCallback, storagePtr, NULL,NULL,NULL); - return TclNREvalObjEx(interp, storagePtr->scriptObj, 0, - iPtr->cmdFramePtr, 3); - - /* - * For unwinding everything once the iterating is done. - */ + TclDecrRefCount(keyVarObj); + TclDecrRefCount(valueVarObj); + TclDecrRefCount(scriptObj); - done: - TclDecrRefCount(storagePtr->keyVarObj); - TclDecrRefCount(storagePtr->valueVarObj); - TclDecrRefCount(storagePtr->scriptObj); - TclDecrRefCount(storagePtr->accumulatorObj); - Tcl_DictObjDone(&storagePtr->search); - TclStackFree(interp, storagePtr); + Tcl_DictObjDone(&search); + if (result == TCL_OK) { + Tcl_ResetResult(interp); + } return result; } @@ -2872,7 +2461,7 @@ DictMapLoopCallback( static int DictSetCmd( - TCL_UNUSED(void *), + ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) @@ -2881,7 +2470,7 @@ DictSetCmd( int result, allocatedDict = 0; if (objc < 4) { - Tcl_WrongNumArgs(interp, 1, objv, "dictVarName key ?key ...? value"); + Tcl_WrongNumArgs(interp, 1, objv, "varName key ?key ...? value"); return TCL_ERROR; } @@ -2932,7 +2521,7 @@ DictSetCmd( static int DictUnsetCmd( - TCL_UNUSED(void *), + ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) @@ -2941,7 +2530,7 @@ DictUnsetCmd( int result, allocatedDict = 0; if (objc < 3) { - Tcl_WrongNumArgs(interp, 1, objv, "dictVarName key ?key ...?"); + Tcl_WrongNumArgs(interp, 1, objv, "varName key ?key ...?"); return TCL_ERROR; } @@ -2991,27 +2580,26 @@ DictUnsetCmd( static int DictFilterCmd( - TCL_UNUSED(void *), + ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Interp *iPtr = (Interp *) interp; - static const char *const filters[] = { + static const char *filters[] = { "key", "script", "value", NULL }; enum FilterTypes { FILTER_KEYS, FILTER_SCRIPT, FILTER_VALUES }; Tcl_Obj *scriptObj, *keyVarObj, *valueVarObj; - Tcl_Obj **varv, *keyObj = NULL, *valueObj = NULL, *resultObj, *boolObj; + Tcl_Obj **varv, *keyObj, *valueObj, *resultObj, *boolObj; Tcl_DictSearch search; - int index, done, result, satisfied; - int varc; - const char *pattern; + int index, varc, done, result, satisfied; + char *pattern; if (objc < 3) { - Tcl_WrongNumArgs(interp, 1, objv, "dictionary filterType ?arg ...?"); + Tcl_WrongNumArgs(interp, 1, objv, "dictionary filterType ..."); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[2], filters, "filterType", @@ -3021,6 +2609,11 @@ DictFilterCmd( switch ((enum FilterTypes) index) { case FILTER_KEYS: + if (objc != 4) { + Tcl_WrongNumArgs(interp, 1, objv, "dictionary key globPattern"); + return TCL_ERROR; + } + /* * Create a dictionary whose keys all match a certain pattern. */ @@ -3029,52 +2622,23 @@ DictFilterCmd( &keyObj, &valueObj, &done) != TCL_OK) { return TCL_ERROR; } - if (objc == 3) { + pattern = TclGetString(objv[3]); + resultObj = Tcl_NewDictObj(); + if (TclMatchIsTrivial(pattern)) { /* - * Nothing to match, so return nothing (== empty dictionary). + * Must release the search lock here to prevent a memory leak + * since we are not exhausing the search. [Bug 1705778, leak K05] */ Tcl_DictObjDone(&search); - return TCL_OK; - } else if (objc == 4) { - pattern = TclGetString(objv[3]); - resultObj = Tcl_NewDictObj(); - if (TclMatchIsTrivial(pattern)) { - /* - * Must release the search lock here to prevent a memory leak - * 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); - } + Tcl_DictObjGet(interp, objv[1], objv[3], &valueObj); + if (valueObj != NULL) { + Tcl_DictObjPut(interp, resultObj, objv[3], valueObj); } } 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 */ - } + if (Tcl_StringMatch(TclGetString(keyObj), pattern)) { + Tcl_DictObjPut(interp, resultObj, keyObj, valueObj); } Tcl_DictObjNext(&search, &keyObj, &valueObj, &done); } @@ -3083,6 +2647,11 @@ DictFilterCmd( return TCL_OK; case FILTER_VALUES: + if (objc != 4) { + Tcl_WrongNumArgs(interp, 1, objv, "dictionary value globPattern"); + return TCL_ERROR; + } + /* * Create a dictionary whose values all match a certain pattern. */ @@ -3091,16 +2660,11 @@ DictFilterCmd( &keyObj, &valueObj, &done) != TCL_OK) { return TCL_ERROR; } + pattern = TclGetString(objv[3]); 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 */ - } + if (Tcl_StringMatch(TclGetString(valueObj), pattern)) { + Tcl_DictObjPut(interp, resultObj, keyObj, valueObj); } Tcl_DictObjNext(&search, &keyObj, &valueObj, &done); } @@ -3110,7 +2674,7 @@ DictFilterCmd( case FILTER_SCRIPT: if (objc != 5) { Tcl_WrongNumArgs(interp, 1, objv, - "dictionary script {keyVarName valueVarName} filterScript"); + "dictionary script {keyVar valueVar} filterScript"); return TCL_ERROR; } @@ -3124,9 +2688,8 @@ DictFilterCmd( 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", (void *)NULL); + Tcl_SetResult(interp, "must have exactly two variable names", + TCL_STATIC); return TCL_ERROR; } keyVarObj = varv[0]; @@ -3165,16 +2728,17 @@ DictFilterCmd( 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)"); + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "couldn't set key variable: \"", + TclGetString(keyVarObj), "\"", NULL); 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; + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "couldn't set value variable: \"", + TclGetString(valueVarObj), "\"", NULL); goto abnormalResult; } @@ -3196,7 +2760,7 @@ DictFilterCmd( } TclDecrRefCount(boolObj); if (satisfied) { - Tcl_DictObjPut(NULL, resultObj, keyObj, valueObj); + Tcl_DictObjPut(interp, resultObj, keyObj, valueObj); } break; case TCL_BREAK: @@ -3208,14 +2772,13 @@ DictFilterCmd( Tcl_ResetResult(interp); Tcl_DictObjDone(&search); - /* FALLTHRU */ case TCL_CONTINUE: result = TCL_OK; break; case TCL_ERROR: Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( "\n (\"dict filter\" script line %d)", - Tcl_GetErrorLine(interp))); + interp->errorLine)); default: goto abnormalResult; } @@ -3277,19 +2840,19 @@ DictFilterCmd( static int DictUpdateCmd( - TCL_UNUSED(void *), + ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Interp *iPtr = (Interp *) interp; Tcl_Obj *dictPtr, *objPtr; - int i; - int dummy; + int i, result, dummy; + Tcl_InterpState state; if (objc < 5 || !(objc & 1)) { Tcl_WrongNumArgs(interp, 1, objv, - "dictVarName key varName ?key varName ...? script"); + "varName key varName ?key varName ...? script"); return TCL_ERROR; } @@ -3308,7 +2871,7 @@ DictUpdateCmd( } if (objPtr == NULL) { /* ??? */ - Tcl_UnsetVar2(interp, TclGetString(objv[i+1]), NULL, 0); + Tcl_UnsetVar(interp, Tcl_GetString(objv[i+1]), 0); } else if (Tcl_ObjSetVar2(interp, objv[i+1], NULL, objPtr, TCL_LEAVE_ERR_MSG) == NULL) { TclDecrRefCount(dictPtr); @@ -3318,34 +2881,10 @@ DictUpdateCmd( TclDecrRefCount(dictPtr); /* - * Execute the body after setting up the NRE handler to process the - * results. - */ - - objPtr = Tcl_NewListObj(objc-3, objv+2); - Tcl_IncrRefCount(objPtr); - Tcl_IncrRefCount(objv[1]); - TclNRAddCallback(interp, FinalizeDictUpdate, objv[1], objPtr, NULL,NULL); - - return TclNREvalObjEx(interp, objv[objc-1], 0, iPtr->cmdFramePtr, objc-1); -} - -static int -FinalizeDictUpdate( - void *data[], - Tcl_Interp *interp, - int result) -{ - Tcl_Obj *dictPtr, *objPtr, **objv; - Tcl_InterpState state; - int i, objc; - Tcl_Obj *varName = (Tcl_Obj *)data[0]; - Tcl_Obj *argsObj = (Tcl_Obj *)data[1]; - - /* - * ErrorInfo handling. + * Execute the body. */ + result = TclEvalObjEx(interp, objv[objc-1], 0, iPtr->cmdFramePtr, objc-1); if (result == TCL_ERROR) { Tcl_AddErrorInfo(interp, "\n (body of \"dict update\")"); } @@ -3354,10 +2893,8 @@ FinalizeDictUpdate( * If the dictionary variable doesn't exist, drop everything silently. */ - dictPtr = Tcl_ObjGetVar2(interp, varName, NULL, 0); + dictPtr = Tcl_ObjGetVar2(interp, objv[1], NULL, 0); if (dictPtr == NULL) { - TclDecrRefCount(varName); - TclDecrRefCount(argsObj); return result; } @@ -3366,10 +2903,8 @@ FinalizeDictUpdate( */ state = Tcl_SaveInterpState(interp, result); - if (Tcl_DictObjSize(interp, dictPtr, &objc) != TCL_OK) { + if (Tcl_DictObjSize(interp, dictPtr, &dummy) != TCL_OK) { Tcl_DiscardInterpState(state); - TclDecrRefCount(varName); - TclDecrRefCount(argsObj); return TCL_ERROR; } @@ -3382,37 +2917,34 @@ FinalizeDictUpdate( * an instruction to remove the key. */ - TclListObjGetElements(NULL, argsObj, &objc, &objv); - for (i=0 ; i<objc ; i+=2) { + for (i=2 ; i+2<objc ; i+=2) { objPtr = Tcl_ObjGetVar2(interp, objv[i+1], NULL, 0); if (objPtr == NULL) { - Tcl_DictObjRemove(NULL, dictPtr, objv[i]); + Tcl_DictObjRemove(interp, 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)); + Tcl_DictObjPut(interp, dictPtr, objv[i], + Tcl_DuplicateObj(objPtr)); } else { /* Shouldn't fail */ - Tcl_DictObjPut(NULL, dictPtr, objv[i], objPtr); + Tcl_DictObjPut(interp, dictPtr, objv[i], objPtr); } } - TclDecrRefCount(argsObj); /* * Write the dictionary back to its variable. */ - if (Tcl_ObjSetVar2(interp, varName, NULL, dictPtr, + if (Tcl_ObjSetVar2(interp, objv[1], NULL, dictPtr, TCL_LEAVE_ERR_MSG) == NULL) { Tcl_DiscardInterpState(state); - TclDecrRefCount(varName); return TCL_ERROR; } - TclDecrRefCount(varName); return Tcl_RestoreInterpState(interp, state); } @@ -3436,16 +2968,19 @@ FinalizeDictUpdate( static int DictWithCmd( - TCL_UNUSED(void *), + ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Interp *iPtr = (Interp *) interp; - Tcl_Obj *dictPtr, *keysPtr, *pathPtr; + Tcl_Obj *dictPtr, *keysPtr, *keyPtr, *valPtr, **keyv, *leafPtr; + Tcl_DictSearch s; + Tcl_InterpState state; + int done, result, keyc, i, allocdict = 0; if (objc < 3) { - Tcl_WrongNumArgs(interp, 1, objv, "dictVarName ?key ...? script"); + Tcl_WrongNumArgs(interp, 1, objv, "dictVar ?key ...? script"); return TCL_ERROR; } @@ -3457,126 +2992,11 @@ DictWithCmd( if (dictPtr == NULL) { return TCL_ERROR; } - - keysPtr = TclDictWithInit(interp, dictPtr, objc-3, objv+2); - if (keysPtr == NULL) { - return TCL_ERROR; - } - Tcl_IncrRefCount(keysPtr); - - /* - * Execute the body, while making the invoking context available to the - * loop body (TIP#280) and postponing the cleanup until later (NRE). - */ - - pathPtr = NULL; if (objc > 3) { - pathPtr = Tcl_NewListObj(objc-3, objv+2); - Tcl_IncrRefCount(pathPtr); - } - Tcl_IncrRefCount(objv[1]); - TclNRAddCallback(interp, FinalizeDictWith, objv[1], keysPtr, pathPtr, - NULL); - - return TclNREvalObjEx(interp, objv[objc-1], 0, iPtr->cmdFramePtr, objc-1); -} - -static int -FinalizeDictWith( - void *data[], - Tcl_Interp *interp, - int result) -{ - Tcl_Obj **pathv; - int pathc; - Tcl_InterpState state; - Tcl_Obj *varName = (Tcl_Obj *)data[0]; - Tcl_Obj *keysPtr = (Tcl_Obj *)data[1]; - Tcl_Obj *pathPtr = (Tcl_Obj *)data[2]; - Var *varPtr, *arrayPtr; - - if (result == TCL_ERROR) { - Tcl_AddErrorInfo(interp, "\n (body of \"dict with\")"); - } - - /* - * Save the result state; TDWF doesn't guarantee to not modify that on - * TCL_OK result. - */ - - state = Tcl_SaveInterpState(interp, result); - if (pathPtr != NULL) { - TclListObjGetElements(NULL, pathPtr, &pathc, &pathv); - } else { - pathc = 0; - pathv = NULL; - } - - /* - * Pack from local variables back into the dictionary. - */ - - varPtr = TclObjLookupVarEx(interp, varName, NULL, TCL_LEAVE_ERR_MSG, "set", - /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); - if (varPtr == NULL) { - result = TCL_ERROR; - } else { - result = TclDictWithFinish(interp, varPtr, arrayPtr, varName, NULL, -1, - pathc, pathv, keysPtr); - } - - /* - * Tidy up and return the real result (unless we had an error). - */ - - TclDecrRefCount(varName); - TclDecrRefCount(keysPtr); - if (pathPtr != NULL) { - TclDecrRefCount(pathPtr); - } - if (result != TCL_OK) { - Tcl_DiscardInterpState(state); - return TCL_ERROR; - } - return Tcl_RestoreInterpState(interp, state); -} - -/* - *---------------------------------------------------------------------- - * - * TclDictWithInit -- - * - * Part of the core of [dict with]. Pokes into a dictionary and converts - * the mappings there into assignments to (presumably) local variables. - * Returns a list of all the names that were mapped so that removal of - * either the variable or the dictionary entry won't surprise us when we - * come to stuffing everything back. - * - * Result: - * List of mapped names, or NULL if there was an error. - * - * Side effects: - * Assigns to variables, so potentially legion due to traces. - * - *---------------------------------------------------------------------- - */ - -Tcl_Obj * -TclDictWithInit( - Tcl_Interp *interp, - Tcl_Obj *dictPtr, - int pathc, - Tcl_Obj *const pathv[]) -{ - Tcl_DictSearch s; - Tcl_Obj *keyPtr, *valPtr, *keysPtr; - int done; - - if (pathc > 0) { - dictPtr = TclTraceDictPath(interp, dictPtr, pathc, pathv, + dictPtr = TclTraceDictPath(interp, dictPtr, objc-3, objv+2, DICT_PATH_READ); if (dictPtr == NULL) { - return NULL; + return TCL_ERROR; } } @@ -3589,10 +3009,11 @@ TclDictWithInit( if (Tcl_DictObjFirst(interp, dictPtr, &s, &keyPtr, &valPtr, &done) != TCL_OK) { - return NULL; + return TCL_ERROR; } TclNewObj(keysPtr); + Tcl_IncrRefCount(keysPtr); for (; !done ; Tcl_DictObjNext(&s, &keyPtr, &valPtr, &done)) { Tcl_ListObjAppendElement(NULL, keysPtr, keyPtr); @@ -3600,109 +3021,72 @@ TclDictWithInit( TCL_LEAVE_ERR_MSG) == NULL) { TclDecrRefCount(keysPtr); Tcl_DictObjDone(&s); - return NULL; + return TCL_ERROR; } } - return keysPtr; -} - -/* - *---------------------------------------------------------------------- - * - * TclDictWithFinish -- - * - * Part of the core of [dict with]. Reassembles the piece of the dict (in - * varName, location given by pathc/pathv) from the variables named in - * the keysPtr argument. NB, does not try to preserve errors or manage - * argument lifetimes. - * - * Result: - * TCL_OK if we succeeded, or TCL_ERROR if we failed. - * - * Side effects: - * Assigns to a variable, so potentially legion due to traces. Updates - * the dictionary in the named variable. - * - *---------------------------------------------------------------------- - */ + /* + * Execute the body, while making the invoking context available to the + * loop body (TIP#280). + */ -int -TclDictWithFinish( - Tcl_Interp *interp, /* Command interpreter in which variable - * exists. Used for state management, traces - * and error reporting. */ - Var *varPtr, /* Reference to the variable holding the - * dictionary. */ - Var *arrayPtr, /* Reference to the array containing the - * variable, or NULL if the variable is a - * scalar. */ - Tcl_Obj *part1Ptr, /* Name of an array (if part2 is non-NULL) or - * the name of a variable. NULL if the 'index' - * parameter is >= 0 */ - Tcl_Obj *part2Ptr, /* If non-NULL, gives the name of an element - * in the array part1. */ - int index, /* Index into the local variable table of the - * variable, or -1. Only used when part1Ptr is - * NULL. */ - int pathc, /* The number of elements in the path into the - * dictionary. */ - Tcl_Obj *const pathv[], /* The elements of the path to the subdict. */ - Tcl_Obj *keysPtr) /* List of keys to be synchronized. This is - * the result value from TclDictWithInit. */ -{ - Tcl_Obj *dictPtr, *leafPtr, *valPtr; - int i, allocdict, keyc; - Tcl_Obj **keyv; + result = TclEvalObjEx(interp, objv[objc-1], 0, iPtr->cmdFramePtr, objc-1); + if (result == TCL_ERROR) { + Tcl_AddErrorInfo(interp, "\n (body of \"dict with\")"); + } /* * If the dictionary variable doesn't exist, drop everything silently. */ - dictPtr = TclPtrGetVarIdx(interp, varPtr, arrayPtr, part1Ptr, part2Ptr, - TCL_LEAVE_ERR_MSG, index); + dictPtr = Tcl_ObjGetVar2(interp, objv[1], NULL, 0); if (dictPtr == NULL) { - return TCL_OK; + TclDecrRefCount(keysPtr); + return result; } /* * Double-check that it is still a dictionary. */ + state = Tcl_SaveInterpState(interp, result); if (Tcl_DictObjSize(interp, dictPtr, &i) != TCL_OK) { + TclDecrRefCount(keysPtr); + Tcl_DiscardInterpState(state); return TCL_ERROR; } if (Tcl_IsShared(dictPtr)) { dictPtr = Tcl_DuplicateObj(dictPtr); allocdict = 1; - } else { - allocdict = 0; } - if (pathc > 0) { + if (objc > 3) { /* * Want to get to the dictionary which we will update; need to do - * prepare-for-update unsharing along the path *but* avoid generating - * an error on a non-extant path (we'll treat that the same as a - * non-extant variable. Luckily, the unsharing operation isn't + * prepare-for-update de-sharing along the path *but* avoid generating + * an error on a non-existant path (we'll treat that the same as a + * non-existant variable. Luckily, the de-sharing operation isn't * deeply damaging if we don't go on to update; it's just less than * perfectly efficient (but no memory should be leaked). */ - leafPtr = TclTraceDictPath(interp, dictPtr, pathc, pathv, + leafPtr = TclTraceDictPath(interp, dictPtr, objc-3, objv+2, DICT_PATH_EXISTS | DICT_PATH_UPDATE); if (leafPtr == NULL) { + TclDecrRefCount(keysPtr); if (allocdict) { TclDecrRefCount(dictPtr); } + Tcl_DiscardInterpState(state); return TCL_ERROR; } if (leafPtr == DICT_PATH_NON_EXISTENT) { + TclDecrRefCount(keysPtr); if (allocdict) { TclDecrRefCount(dictPtr); } - return TCL_OK; + return Tcl_RestoreInterpState(interp, state); } } else { leafPtr = dictPtr; @@ -3728,13 +3112,14 @@ TclDictWithFinish( Tcl_DictObjPut(NULL, leafPtr, keyv[i], valPtr); } } + TclDecrRefCount(keysPtr); /* * Ensure that none of the dictionaries in the chain still have a string * rep. */ - if (pathc > 0) { + if (objc > 3) { InvalidateDictChain(leafPtr); } @@ -3742,14 +3127,12 @@ TclDictWithFinish( * Write back the outermost dictionary to the variable. */ - if (TclPtrSetVarIdx(interp, varPtr, arrayPtr, part1Ptr, part2Ptr, - dictPtr, TCL_LEAVE_ERR_MSG, index) == NULL) { - if (allocdict) { - TclDecrRefCount(dictPtr); - } + if (Tcl_ObjSetVar2(interp, objv[1], NULL, dictPtr, + TCL_LEAVE_ERR_MSG) == NULL) { + Tcl_DiscardInterpState(state); return TCL_ERROR; } - return TCL_OK; + return Tcl_RestoreInterpState(interp, state); } /* |
