diff options
| author | dgp <dgp@users.sourceforge.net> | 2017-12-05 14:36:33 (GMT) |
|---|---|---|
| committer | dgp <dgp@users.sourceforge.net> | 2017-12-05 14:36:33 (GMT) |
| commit | 8a44c35e8c34860fe2ea418899c8f62fc25e06bb (patch) | |
| tree | 3fd1e941780108266cbc903f020422d7c402735e | |
| parent | 92f8ce13dfb1299030dc844252d7478caaaa7687 (diff) | |
| download | tcl-8a44c35e8c34860fe2ea418899c8f62fc25e06bb.zip tcl-8a44c35e8c34860fe2ea418899c8f62fc25e06bb.tar.gz tcl-8a44c35e8c34860fe2ea418899c8f62fc25e06bb.tar.bz2 | |
Another revised fix, much closer to sebres' patch now.
| -rw-r--r-- | generic/tclNamesp.c | 152 |
1 files changed, 90 insertions, 62 deletions
diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index 18cd07c..1556ec9 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -6583,7 +6583,7 @@ BuildEnsembleConfig( Tcl_HashTable *hash = &ensemblePtr->subcommandTable; Tcl_HashEntry *hPtr; Tcl_Obj *mapDict = ensemblePtr->subcommandDict; - Tcl_Obj *exportList = ensemblePtr->subcmdList; + Tcl_Obj *subList = ensemblePtr->subcmdList; if (hash->numEntries != 0) { /* @@ -6603,78 +6603,106 @@ BuildEnsembleConfig( Tcl_InitHashTable(hash, TCL_STRING_KEYS); } - if (mapDict) { + if (subList) { + int subc; + Tcl_Obj **subv, *target, *cmdObj, *cmdPrefixObj; + char *name; + /* - * We have a mapping dictionary to direct filling of the subcommand - * table. Every key, value in the dict should go into the table - * unless we have an export list that holds some of the keys back. + * There is a list of exactly what subcommands go in the table. + * Must determine the target for each. */ - Tcl_DictSearch dictSearch; - Tcl_Obj *keyObj, *valueObj; - int done; - - Tcl_DictObjFirst(NULL, mapDict, &dictSearch, &keyObj, &valueObj, &done); - while (!done) { - int nameLen, insert = 1; - char *name = TclGetStringFromObj(keyObj, &nameLen); - - if (exportList && (exportList != mapDict)) { - Tcl_Obj **subv; - int subc; - - insert = 0; - TclListObjGetElements(NULL, exportList, &subc, &subv); - for (i = 0; i < subc; i++) { - int compareLen; - const char *compare - = TclGetStringFromObj(subv[i], &compareLen); - - if ((nameLen == compareLen) - && (memcmp(name, compare, (size_t)nameLen) == 0)) { - insert = 1; - break; - } + Tcl_ListObjGetElements(NULL, subList, &subc, &subv); + if (subList == mapDict) { + /* + * Strange case where explicit list of subcommands is same value + * as the dict mapping to targets. + */ + + for (i = 0; i < subc; i += 2) { + name = TclGetString(subv[i]); + hPtr = Tcl_CreateHashEntry(hash, name, &isNew); + if (!isNew) { + cmdObj = (Tcl_Obj *)Tcl_GetHashValue(hPtr); + Tcl_DecrRefCount(cmdObj); } - } - if (insert) { + Tcl_SetHashValue(hPtr, subv[i+1]); + Tcl_IncrRefCount(subv[i+1]); + + name = TclGetString(subv[i+1]); hPtr = Tcl_CreateHashEntry(hash, name, &isNew); - Tcl_SetHashValue(hPtr, valueObj); - Tcl_IncrRefCount(valueObj); + if (isNew) { + cmdObj = Tcl_NewStringObj(ensemblePtr->nsPtr->fullName, -1); + if (ensemblePtr->nsPtr->parentPtr != NULL) { + Tcl_AppendStringsToObj(cmdObj, "::", name, NULL); + } else { + Tcl_AppendStringsToObj(cmdObj, name, NULL); + } + cmdPrefixObj = Tcl_NewListObj(1, &cmdObj); + Tcl_SetHashValue(hPtr, cmdPrefixObj); + Tcl_IncrRefCount(cmdPrefixObj); + } } - Tcl_DictObjNext(&dictSearch, &keyObj, &valueObj, &done); - } - } - if (exportList) { - /* - * We have an export list. Put into the table each element that's - * not already there. - */ - int subc; - Tcl_Obj **subv, *cmdObj, *cmdPrefixObj; + } else { + /* Usual case where we can freely act on the list and dict. */ - TclListObjGetElements(NULL, exportList, &subc, &subv); - for (i=0 ; i<subc ; i++) { - char *name = TclGetString(subv[i]); + for (i = 0; i < subc; i++) { + name = TclGetString(subv[i]); + hPtr = Tcl_CreateHashEntry(hash, name, &isNew); + if (!isNew) { + continue; + } - hPtr = Tcl_CreateHashEntry(hash, name, &isNew); - if (!isNew) { - /* Subcommand already in the table, from the mapDict. */ - continue; - } + /* Lookup target in the dictionary */ + if (mapDict) { + Tcl_DictObjGet(NULL, mapDict, subv[i], &target); + if (target) { + Tcl_SetHashValue(hPtr, target); + Tcl_IncrRefCount(target); + continue; + } + } - /* Need to put entry in table, but it's not in mapDict */ - cmdObj = Tcl_NewStringObj(ensemblePtr->nsPtr->fullName, -1); - if (ensemblePtr->nsPtr->parentPtr != NULL) { - Tcl_AppendStringsToObj(cmdObj, "::", name, NULL); - } else { - Tcl_AppendStringsToObj(cmdObj, name, NULL); + /* + * target was not in the dictionary so map onto the namespace. + * Note in this case that we do not guarantee that the + * command is actually there; that is the programmer's + * responsibility (or [::unknown] of course). + */ + cmdObj = Tcl_NewStringObj(ensemblePtr->nsPtr->fullName, -1); + if (ensemblePtr->nsPtr->parentPtr != NULL) { + Tcl_AppendStringsToObj(cmdObj, "::", name, NULL); + } else { + Tcl_AppendStringsToObj(cmdObj, name, NULL); + } + cmdPrefixObj = Tcl_NewListObj(1, &cmdObj); + Tcl_SetHashValue(hPtr, cmdPrefixObj); + Tcl_IncrRefCount(cmdPrefixObj); } - cmdPrefixObj = Tcl_NewListObj(1, &cmdObj); - Tcl_SetHashValue(hPtr, cmdPrefixObj); - Tcl_IncrRefCount(cmdPrefixObj); } - } else if (mapDict == NULL) { + } else if (mapDict) { + /* + * No subcmd list, but we do have a mapping dictionary so we should + * use the keys of that. Convert the dictionary's contents into the + * form required for the ensemble's internal hashtable. + */ + + Tcl_DictSearch dictSearch; + Tcl_Obj *keyObj, *valueObj; + int done; + + Tcl_DictObjFirst(NULL, ensemblePtr->subcommandDict, &dictSearch, + &keyObj, &valueObj, &done); + while (!done) { + char *name = TclGetString(keyObj); + + hPtr = Tcl_CreateHashEntry(hash, name, &isNew); + Tcl_SetHashValue(hPtr, valueObj); + Tcl_IncrRefCount(valueObj); + Tcl_DictObjNext(&dictSearch, &keyObj, &valueObj, &done); + } + } else { /* * Discover what commands are actually exported by the namespace. * What we have is an array of patterns and a hash table whose keys |
