diff options
Diffstat (limited to 'generic/tclDictObj.c')
| -rw-r--r-- | generic/tclDictObj.c | 569 |
1 files changed, 197 insertions, 372 deletions
diff --git a/generic/tclDictObj.c b/generic/tclDictObj.c index 83fc3a6..4fec2c1 100644 --- a/generic/tclDictObj.c +++ b/generic/tclDictObj.c @@ -4,7 +4,7 @@ * This file contains functions that implement the Tcl dict object type * and its accessor command. * - * Copyright (c) 2002-2010 by 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. @@ -31,6 +31,8 @@ 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, @@ -70,41 +72,32 @@ 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 int FinalizeDictUpdate(ClientData data[], - Tcl_Interp *interp, int result); -static int FinalizeDictWith(ClientData data[], - Tcl_Interp *interp, int result); -static int DictForNRCmd(ClientData dummy, Tcl_Interp *interp, - int objc, Tcl_Obj *const *objv); -static int DictForLoopCallback(ClientData data[], - Tcl_Interp *interp, int result); - /* * Table of dict subcommand names and implementations. */ static const EnsembleImplMap implementationMap[] = { - {"append", DictAppendCmd, TclCompileDictAppendCmd, NULL, NULL, 0 }, - {"create", DictCreateCmd, NULL, NULL, NULL, 0 }, - {"exists", DictExistsCmd, NULL, NULL, NULL, 0 }, - {"filter", DictFilterCmd, NULL, NULL, NULL, 0 }, - {"for", NULL, TclCompileDictForCmd, DictForNRCmd, NULL, 0 }, - {"get", DictGetCmd, TclCompileDictGetCmd, NULL, NULL, 0 }, - {"incr", DictIncrCmd, TclCompileDictIncrCmd, NULL, NULL, 0 }, - {"info", DictInfoCmd, NULL, NULL, NULL, 0 }, - {"keys", DictKeysCmd, NULL, NULL, NULL, 0 }, - {"lappend", DictLappendCmd, TclCompileDictLappendCmd, NULL, NULL, 0 }, - {"merge", DictMergeCmd, NULL, NULL, NULL, 0 }, - {"remove", DictRemoveCmd, NULL, NULL, NULL, 0 }, - {"replace", DictReplaceCmd, NULL, NULL, NULL, 0 }, - {"set", DictSetCmd, TclCompileDictSetCmd, NULL, NULL, 0 }, - {"size", DictSizeCmd, NULL, NULL, NULL, 0 }, - {"unset", DictUnsetCmd, NULL, NULL, NULL, 0 }, - {"update", DictUpdateCmd, TclCompileDictUpdateCmd, NULL, NULL, 0 }, - {"values", DictValuesCmd, NULL, NULL, NULL, 0 }, - {"with", DictWithCmd, NULL, 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} }; /* @@ -155,10 +148,10 @@ 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 */ }; @@ -173,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, @@ -210,8 +203,8 @@ AllocChainEntry( Tcl_Obj *objPtr = keyPtr; ChainEntry *cPtr; - cPtr = ckalloc(sizeof(ChainEntry)); - cPtr->entry.key.objPtr = objPtr; + cPtr = (ChainEntry *) ckalloc(sizeof(ChainEntry)); + cPtr->entry.key.oneWordValue = (char *) objPtr; Tcl_IncrRefCount(objPtr); cPtr->entry.clientData = NULL; cPtr->prevPtr = cPtr->nextPtr = NULL; @@ -257,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. @@ -285,7 +278,7 @@ DeleteChainEntry( Tcl_Obj *keyPtr) { ChainEntry *cPtr = (ChainEntry *) - Tcl_FindHashEntry(&dict->table, keyPtr); + Tcl_FindHashEntry(&dict->table, (char *) keyPtr); if (cPtr == NULL) { return 0; @@ -340,8 +333,8 @@ DupDictInternalRep( Tcl_Obj *srcPtr, Tcl_Obj *copyPtr) { - Dict *oldDict = srcPtr->internalRep.otherValuePtr; - Dict *newDict = ckalloc(sizeof(Dict)); + Dict *oldDict = srcPtr->internalRep.twoPtrValue.ptr1; + Dict *newDict = (Dict *) ckalloc(sizeof(Dict)); ChainEntry *cPtr; /* @@ -350,7 +343,7 @@ DupDictInternalRep( InitChainTable(newDict); for (cPtr=oldDict->entryChainHead ; cPtr!=NULL ; cPtr=cPtr->nextPtr) { - Tcl_Obj *key = Tcl_GetHashKey(&oldDict->table, &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); @@ -359,7 +352,7 @@ DupDictInternalRep( * Fill in the contents. */ - Tcl_SetHashValue(hPtr, valuePtr); + Tcl_SetHashValue(hPtr, (ClientData) valuePtr); Tcl_IncrRefCount(valuePtr); } @@ -375,7 +368,7 @@ DupDictInternalRep( * Store in the object. */ - copyPtr->internalRep.otherValuePtr = newDict; + copyPtr->internalRep.twoPtrValue.ptr1 = newDict; copyPtr->typePtr = &tclDictType; } @@ -401,14 +394,12 @@ static void FreeDictInternalRep( Tcl_Obj *dictPtr) { - Dict *dict = dictPtr->internalRep.otherValuePtr; + Dict *dict = dictPtr->internalRep.twoPtrValue.ptr1; - dict->refcount--; + --dict->refcount; if (dict->refcount <= 0) { DeleteDict(dict); } - - dictPtr->internalRep.otherValuePtr = NULL; /* Belt and braces! */ dictPtr->typePtr = NULL; } @@ -437,7 +428,7 @@ DeleteDict( Dict *dict) { DeleteChainTable(dict); - ckfree(dict); + ckfree((char *) dict); } /* @@ -468,12 +459,11 @@ UpdateStringOfDict( { #define LOCAL_SIZE 20 int localFlags[LOCAL_SIZE], *flagPtr = NULL; - Dict *dict = dictPtr->internalRep.otherValuePtr; + Dict *dict = dictPtr->internalRep.twoPtrValue.ptr1; ChainEntry *cPtr; Tcl_Obj *keyPtr, *valuePtr; int i, length, bytesNeeded = 0; - const char *elem; - char *dst; + char *elem, *dst; const int maxFlags = UINT_MAX / sizeof(int); /* @@ -499,7 +489,7 @@ UpdateStringOfDict( } else if (numElems > maxFlags) { Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } else { - flagPtr = ckalloc(numElems * sizeof(int)); + flagPtr = (int *) ckalloc((unsigned) numElems*sizeof(int)); } for (i=0,cPtr=dict->entryChainHead; i<numElems; i+=2,cPtr=cPtr->nextPtr) { /* @@ -508,7 +498,7 @@ UpdateStringOfDict( */ flagPtr[i] = ( i ? TCL_DONT_QUOTE_HASH : 0 ); - keyPtr = 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 < 0) { @@ -533,11 +523,11 @@ UpdateStringOfDict( */ dictPtr->length = bytesNeeded - 1; - dictPtr->bytes = ckalloc(bytesNeeded); + 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_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++ = ' '; @@ -551,7 +541,7 @@ UpdateStringOfDict( dictPtr->bytes[dictPtr->length] = '\0'; if (flagPtr != localFlags) { - ckfree(flagPtr); + ckfree((char *) flagPtr); } } @@ -582,7 +572,7 @@ SetDictFromAny( { Tcl_HashEntry *hPtr; int isNew, result; - Dict *dict = ckalloc(sizeof(Dict)); + Dict *dict = (Dict *) ckalloc(sizeof(Dict)); InitChainTable(dict); @@ -603,7 +593,7 @@ SetDictFromAny( } for (i=0 ; i<objc ; i+=2) { - + /* Store key and value in the hash table we're building. */ hPtr = CreateChainEntry(dict, objv[i], &isNew); if (!isNew) { @@ -694,23 +684,19 @@ SetDictFromAny( dict->epoch = 0; dict->chain = NULL; dict->refcount = 1; - objPtr->internalRep.otherValuePtr = dict; + objPtr->internalRep.twoPtrValue.ptr1 = dict; objPtr->typePtr = &tclDictType; return TCL_OK; missingValue: if (interp != NULL) { Tcl_SetResult(interp, "missing value to go with key", TCL_STATIC); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "DICTIONARY", NULL); } result = TCL_ERROR; errorExit: - if (interp != NULL) { - Tcl_SetErrorCode(interp, "TCL", "VALUE", "DICTIONARY", NULL); - } DeleteChainTable(dict); - ckfree(dict); + ckfree((char *) dict); return result; } @@ -762,13 +748,13 @@ TclTraceDictPath( return NULL; } } - dict = dictPtr->internalRep.otherValuePtr; + 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) { @@ -805,15 +791,15 @@ TclTraceDictPath( } } - newDict = tmpObj->internalRep.otherValuePtr; + 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++; - newDict = tmpObj->internalRep.otherValuePtr; + newDict = tmpObj->internalRep.twoPtrValue.ptr1; } newDict->chain = dictPtr; @@ -848,17 +834,17 @@ static void InvalidateDictChain( Tcl_Obj *dictObj) { - Dict *dict = dictObj->internalRep.otherValuePtr; + Dict *dict = dictObj->internalRep.twoPtrValue.ptr1; do { - Tcl_InvalidateStringRep(dictObj); + TclInvalidateStringRep(dictObj); dict->epoch++; dictObj = dict->chain; if (dictObj == NULL) { break; } dict->chain = NULL; - dict = dictObj->internalRep.otherValuePtr; + dict = dictObj->internalRep.twoPtrValue.ptr1; } while (dict != NULL); } @@ -905,9 +891,9 @@ Tcl_DictObjPut( } if (dictPtr->bytes != NULL) { - Tcl_InvalidateStringRep(dictPtr); + TclInvalidateStringRep(dictPtr); } - dict = dictPtr->internalRep.otherValuePtr; + dict = dictPtr->internalRep.twoPtrValue.ptr1; hPtr = CreateChainEntry(dict, keyPtr, &isNew); Tcl_IncrRefCount(valuePtr); if (!isNew) { @@ -953,12 +939,13 @@ Tcl_DictObjGet( if (dictPtr->typePtr != &tclDictType) { int result = SetDictFromAny(interp, dictPtr); if (result != TCL_OK) { + *valuePtrPtr = NULL; return result; } } - dict = dictPtr->internalRep.otherValuePtr; - hPtr = Tcl_FindHashEntry(&dict->table, keyPtr); + dict = dictPtr->internalRep.twoPtrValue.ptr1; + hPtr = Tcl_FindHashEntry(&dict->table, (char *) keyPtr); if (hPtr == NULL) { *valuePtrPtr = NULL; } else { @@ -1006,9 +993,9 @@ Tcl_DictObjRemove( } if (dictPtr->bytes != NULL) { - Tcl_InvalidateStringRep(dictPtr); + TclInvalidateStringRep(dictPtr); } - dict = dictPtr->internalRep.otherValuePtr; + dict = dictPtr->internalRep.twoPtrValue.ptr1; if (DeleteChainEntry(dict, keyPtr)) { dict->epoch++; } @@ -1048,7 +1035,7 @@ Tcl_DictObjSize( } } - dict = dictPtr->internalRep.otherValuePtr; + dict = dictPtr->internalRep.twoPtrValue.ptr1; *sizePtr = dict->table.numEntries; return TCL_OK; } @@ -1103,7 +1090,7 @@ Tcl_DictObjFirst( } } - dict = dictPtr->internalRep.otherValuePtr; + dict = dictPtr->internalRep.twoPtrValue.ptr1; cPtr = dict->entryChainHead; if (cPtr == NULL) { searchPtr->epoch = -1; @@ -1115,7 +1102,8 @@ Tcl_DictObjFirst( searchPtr->next = cPtr->nextPtr; dict->refcount++; if (keyPtrPtr != NULL) { - *keyPtrPtr = Tcl_GetHashKey(&dict->table, &cPtr->entry); + *keyPtrPtr = (Tcl_Obj *) Tcl_GetHashKey(&dict->table, + &cPtr->entry); } if (valuePtrPtr != NULL) { *valuePtrPtr = Tcl_GetHashValue(&cPtr->entry); @@ -1191,7 +1179,7 @@ Tcl_DictObjNext( searchPtr->next = cPtr->nextPtr; *donePtr = 0; if (keyPtrPtr != NULL) { - *keyPtrPtr = Tcl_GetHashKey( + *keyPtrPtr = (Tcl_Obj *) Tcl_GetHashKey( &((Dict *)searchPtr->dictionaryPtr)->table, &cPtr->entry); } if (valuePtrPtr != NULL) { @@ -1278,7 +1266,7 @@ Tcl_DictObjPutKeyList( return TCL_ERROR; } - dict = dictPtr->internalRep.otherValuePtr; + dict = dictPtr->internalRep.twoPtrValue.ptr1; hPtr = CreateChainEntry(dict, keyv[keyc-1], &isNew); Tcl_IncrRefCount(valuePtr); if (!isNew) { @@ -1334,7 +1322,7 @@ Tcl_DictObjRemoveKeyList( return TCL_ERROR; } - dict = dictPtr->internalRep.otherValuePtr; + dict = dictPtr->internalRep.twoPtrValue.ptr1; DeleteChainEntry(dict, keyv[keyc-1]); InvalidateDictChain(dictPtr); return TCL_OK; @@ -1374,13 +1362,13 @@ Tcl_NewDictObj(void) Dict *dict; TclNewObj(dictPtr); - Tcl_InvalidateStringRep(dictPtr); - dict = ckalloc(sizeof(Dict)); + TclInvalidateStringRep(dictPtr); + dict = (Dict *) ckalloc(sizeof(Dict)); InitChainTable(dict); dict->epoch = 0; dict->chain = NULL; dict->refcount = 1; - dictPtr->internalRep.otherValuePtr = dict; + dictPtr->internalRep.twoPtrValue.ptr1 = dict; dictPtr->typePtr = &tclDictType; return dictPtr; #endif @@ -1423,13 +1411,13 @@ Tcl_DbNewDictObj( Dict *dict; TclDbNewObj(dictPtr, file, line); - Tcl_InvalidateStringRep(dictPtr); - dict = ckalloc(sizeof(Dict)); + TclInvalidateStringRep(dictPtr); + dict = (Dict *) ckalloc(sizeof(Dict)); InitChainTable(dict); dict->epoch = 0; dict->chain = NULL; dict->refcount = 1; - dictPtr->internalRep.otherValuePtr = dict; + dictPtr->internalRep.twoPtrValue.ptr1 = dict; dictPtr->typePtr = &tclDictType; return dictPtr; #else /* !TCL_MEM_DEBUG */ @@ -1518,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; } @@ -1529,7 +1517,7 @@ DictGetCmd( */ if (objc == 2) { - Tcl_Obj *keyPtr = NULL, *listPtr; + Tcl_Obj *keyPtr, *listPtr; Tcl_DictSearch search; int done; @@ -1574,8 +1562,6 @@ DictGetCmd( Tcl_ResetResult(interp); Tcl_AppendResult(interp, "key \"", TclGetString(objv[objc-1]), "\" not known in dictionary", NULL); - Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "DICT", - TclGetString(objv[objc-1]), NULL); return TCL_ERROR; } Tcl_SetObjResult(interp, valuePtr); @@ -1711,7 +1697,7 @@ DictMergeCmd( 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; @@ -1801,7 +1787,7 @@ DictKeysCmd( 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?"); @@ -1835,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 @@ -1883,10 +1869,10 @@ DictValuesCmd( 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?"); @@ -1982,7 +1968,6 @@ DictExistsCmd( Tcl_Obj *const *objv) { Tcl_Obj *dictPtr, *valuePtr; - int result; if (objc < 3) { Tcl_WrongNumArgs(interp, 1, objv, "dictionary key ?key ...?"); @@ -1991,18 +1976,13 @@ DictExistsCmd( dictPtr = TclTraceDictPath(interp, objv[1], objc-3, objv+2, DICT_PATH_EXISTS); - if (dictPtr == NULL) { - return TCL_ERROR; - } - if (dictPtr == DICT_PATH_NON_EXISTENT) { + if (dictPtr == NULL || dictPtr == DICT_PATH_NON_EXISTENT + || Tcl_DictObjGet(interp, dictPtr, objv[objc-1], + &valuePtr) != TCL_OK) { Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0)); - return TCL_OK; - } - result = Tcl_DictObjGet(interp, dictPtr, objv[objc-1], &valuePtr); - if (result != TCL_OK) { - return result; + } else { + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(valuePtr != NULL)); } - Tcl_SetObjResult(interp, Tcl_NewBooleanObj(valuePtr != NULL)); return TCL_OK; } @@ -2046,9 +2026,13 @@ DictInfoCmd( return result; } } - dict = dictPtr->internalRep.otherValuePtr; + dict = dictPtr->internalRep.twoPtrValue.ptr1; - Tcl_SetResult(interp, Tcl_HashStats(&dict->table), TCL_DYNAMIC); + /* + * This next cast is actually OK. + */ + + Tcl_SetResult(interp, (char *) Tcl_HashStats(&dict->table), TCL_DYNAMIC); return TCL_OK; } @@ -2159,7 +2143,7 @@ DictIncrCmd( } } if (code == TCL_OK) { - Tcl_InvalidateStringRep(dictPtr); + TclInvalidateStringRep(dictPtr); valuePtr = Tcl_ObjSetVar2(interp, objv[1], NULL, dictPtr, TCL_LEAVE_ERR_MSG); if (valuePtr == NULL) { @@ -2248,7 +2232,7 @@ DictLappendCmd( if (allocatedValue) { Tcl_DictObjPut(interp, dictPtr, objv[2], valuePtr); } else if (dictPtr->bytes != NULL) { - Tcl_InvalidateStringRep(dictPtr); + TclInvalidateStringRep(dictPtr); } resultPtr = Tcl_ObjSetVar2(interp, objv[1], NULL, dictPtr, @@ -2335,7 +2319,7 @@ DictAppendCmd( /* *---------------------------------------------------------------------- * - * DictForNRCmd -- + * DictForCmd -- * * This function implements the "dict for" Tcl command. See the user * documentation for details on what it does, and TIP#111 for the formal @@ -2351,7 +2335,7 @@ DictAppendCmd( */ static int -DictForNRCmd( +DictForCmd( ClientData dummy, Tcl_Interp *interp, int objc, @@ -2360,8 +2344,8 @@ DictForNRCmd( Interp *iPtr = (Interp *) interp; Tcl_Obj *scriptObj, *keyVarObj, *valueVarObj; Tcl_Obj **varv, *keyObj, *valueObj; - Tcl_DictSearch *searchPtr; - int varc, done; + Tcl_DictSearch search; + int varc, done, result; if (objc != 4) { Tcl_WrongNumArgs(interp, 1, objv, @@ -2369,10 +2353,6 @@ DictForNRCmd( return TCL_ERROR; } - /* - * Parse arguments. - */ - if (TclListObjGetElements(interp, objv[1], &varc, &varv) != TCL_OK) { return TCL_ERROR; } @@ -2381,21 +2361,15 @@ DictForNRCmd( TCL_STATIC); return TCL_ERROR; } - searchPtr = TclStackAlloc(interp, sizeof(Tcl_DictSearch)); - if (Tcl_DictObjFirst(interp, objv[2], searchPtr, &keyObj, &valueObj, - &done) != TCL_OK) { - TclStackFree(interp, searchPtr); - return TCL_ERROR; - } - 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 @@ -2406,119 +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. - */ + result = TCL_OK; + while (!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) { + Tcl_IncrRefCount(valueObj); + if (Tcl_ObjSetVar2(interp, keyVarObj, NULL, keyObj, 0) == NULL) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "couldn't set key variable: \"", + TclGetString(keyVarObj), "\"", NULL); + TclDecrRefCount(valueObj); + result = TCL_ERROR; + break; + } 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( - ClientData data[], - Tcl_Interp *interp, - int result) -{ - Interp *iPtr = (Interp *) interp; - Tcl_DictSearch *searchPtr = data[0]; - Tcl_Obj *keyVarObj = data[1]; - Tcl_Obj *valueVarObj = data[2]; - Tcl_Obj *scriptObj = data[3]; - 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) { + if (Tcl_ObjSetVar2(interp, valueVarObj, NULL, valueObj, 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 value variable: \"", + TclGetString(valueVarObj), "\"", NULL); + 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; - } + /* + * TIP #280. Make invoking context available to loop body. + */ - /* - * Stop the value from getting hit in any way by any traces on the key - * variable. - */ + result = TclEvalObjEx(interp, scriptObj, 0, iPtr->cmdFramePtr, 3); + if (result == TCL_CONTINUE) { + result = TCL_OK; + } 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_IncrRefCount(valueObj); - if (Tcl_ObjSetVar2(interp, keyVarObj, NULL, keyObj, TCL_LEAVE_ERR_MSG) == NULL) { - TclDecrRefCount(valueObj); - result = TCL_ERROR; - goto done; + Tcl_DictObjNext(&search, &keyObj, &valueObj, &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. + * Stop holding a reference to these objects. */ - done: TclDecrRefCount(keyVarObj); TclDecrRefCount(valueVarObj); TclDecrRefCount(scriptObj); - Tcl_DictObjDone(searchPtr); - TclStackFree(interp, searchPtr); + + Tcl_DictObjDone(&search); + if (result == TCL_OK) { + Tcl_ResetResult(interp); + } return result; } @@ -2667,20 +2586,20 @@ DictFilterCmd( 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, varc, done, result, satisfied; - const char *pattern; + 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", @@ -2690,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. */ @@ -2698,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(interp, resultObj, objv[3], valueObj); - } - } else { - while (!done) { - if (Tcl_StringMatch(TclGetString(keyObj), pattern)) { - Tcl_DictObjPut(interp, 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(interp, 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); } @@ -2752,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. */ @@ -2760,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(interp, 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); } @@ -2883,7 +2778,7 @@ DictFilterCmd( case TCL_ERROR: Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( "\n (\"dict filter\" script line %d)", - Tcl_GetErrorLine(interp))); + interp->errorLine)); default: goto abnormalResult; } @@ -2952,7 +2847,8 @@ DictUpdateCmd( { Interp *iPtr = (Interp *) interp; Tcl_Obj *dictPtr, *objPtr; - int i, dummy; + int i, result, dummy; + Tcl_InterpState state; if (objc < 5 || !(objc & 1)) { Tcl_WrongNumArgs(interp, 1, objv, @@ -2985,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( - ClientData data[], - Tcl_Interp *interp, - int result) -{ - Tcl_Obj *dictPtr, *objPtr, **objv; - Tcl_InterpState state; - int i, objc; - Tcl_Obj *varName = data[0]; - Tcl_Obj *argsObj = 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\")"); } @@ -3021,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; } @@ -3033,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; } @@ -3049,8 +2917,7 @@ FinalizeDictUpdate( * an instruction to remove the key. */ - Tcl_ListObjGetElements(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(interp, dictPtr, objv[i]); @@ -3067,20 +2934,17 @@ FinalizeDictUpdate( 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); } @@ -3110,9 +2974,10 @@ DictWithCmd( Tcl_Obj *const *objv) { Interp *iPtr = (Interp *) interp; - Tcl_Obj *dictPtr, *keysPtr, *keyPtr = NULL, *valPtr = NULL, *pathPtr; + Tcl_Obj *dictPtr, *keysPtr, *keyPtr, *valPtr, **keyv, *leafPtr; Tcl_DictSearch s; - int done; + Tcl_InterpState state; + int done, result, keyc, i, allocdict = 0; if (objc < 3) { Tcl_WrongNumArgs(interp, 1, objv, "dictVar ?key ...? script"); @@ -3162,34 +3027,10 @@ DictWithCmd( /* * Execute the body, while making the invoking context available to the - * loop body (TIP#280) and postponing the cleanup until later (NRE). + * loop body (TIP#280). */ - 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( - ClientData data[], - Tcl_Interp *interp, - int result) -{ - Tcl_Obj **keyv, *leafPtr, *dictPtr, *valPtr; - int keyc, i, allocdict = 0; - Tcl_InterpState state; - Tcl_Obj *varName = data[0]; - Tcl_Obj *keysPtr = data[1]; - Tcl_Obj *pathPtr = data[2]; - + result = TclEvalObjEx(interp, objv[objc-1], 0, iPtr->cmdFramePtr, objc-1); if (result == TCL_ERROR) { Tcl_AddErrorInfo(interp, "\n (body of \"dict with\")"); } @@ -3198,13 +3039,9 @@ FinalizeDictWith( * 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(keysPtr); - if (pathPtr) { - TclDecrRefCount(pathPtr); - } return result; } @@ -3214,11 +3051,7 @@ FinalizeDictWith( state = Tcl_SaveInterpState(interp, result); if (Tcl_DictObjSize(interp, dictPtr, &i) != TCL_OK) { - TclDecrRefCount(varName); TclDecrRefCount(keysPtr); - if (pathPtr) { - TclDecrRefCount(pathPtr); - } Tcl_DiscardInterpState(state); return TCL_ERROR; } @@ -3228,10 +3061,7 @@ FinalizeDictWith( allocdict = 1; } - if (pathPtr != NULL) { - Tcl_Obj **pathv; - int pathc; - + if (objc > 3) { /* * Want to get to the dictionary which we will update; need to do * prepare-for-update de-sharing along the path *but* avoid generating @@ -3241,12 +3071,9 @@ FinalizeDictWith( * perfectly efficient (but no memory should be leaked). */ - Tcl_ListObjGetElements(NULL, pathPtr, &pathc, &pathv); - leafPtr = TclTraceDictPath(interp, dictPtr, pathc, pathv, + leafPtr = TclTraceDictPath(interp, dictPtr, objc-3, objv+2, DICT_PATH_EXISTS | DICT_PATH_UPDATE); - TclDecrRefCount(pathPtr); if (leafPtr == NULL) { - TclDecrRefCount(varName); TclDecrRefCount(keysPtr); if (allocdict) { TclDecrRefCount(dictPtr); @@ -3255,7 +3082,6 @@ FinalizeDictWith( return TCL_ERROR; } if (leafPtr == DICT_PATH_NON_EXISTENT) { - TclDecrRefCount(varName); TclDecrRefCount(keysPtr); if (allocdict) { TclDecrRefCount(dictPtr); @@ -3293,7 +3119,7 @@ FinalizeDictWith( * rep. */ - if (pathPtr != NULL) { + if (objc > 3) { InvalidateDictChain(leafPtr); } @@ -3301,12 +3127,11 @@ FinalizeDictWith( * Write back the outermost dictionary to the variable. */ - if (Tcl_ObjSetVar2(interp, varName, NULL, dictPtr, + if (Tcl_ObjSetVar2(interp, objv[1], NULL, dictPtr, TCL_LEAVE_ERR_MSG) == NULL) { Tcl_DiscardInterpState(state); return TCL_ERROR; } - TclDecrRefCount(varName); return Tcl_RestoreInterpState(interp, state); } @@ -3334,7 +3159,7 @@ TclInitDictCmd( { return TclMakeEnsemble(interp, "dict", implementationMap); } - + /* * Local Variables: * mode: c |
