From 7a0f1c602ff55f99fe4c580b7d9f0eaad55793d2 Mon Sep 17 00:00:00 2001 From: Steve Bennett Date: Sat, 17 Sep 2016 09:48:16 +1000 Subject: [PATCH] jim.c: Replace 'dict with' with a C version Signed-off-by: Steve Bennett --- jim.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ stdlib.tcl | 21 -------------------- 2 files changed, 66 insertions(+), 21 deletions(-) diff --git a/jim.c b/jim.c index 28984d0..f3a423e 100644 --- a/jim.c +++ b/jim.c @@ -14340,6 +14340,10 @@ Jim_Obj *Jim_DictMerge(Jim_Interp *interp, int objc, Jim_Obj *const *objv) Jim_Obj *objPtr = Jim_NewDictObj(interp, NULL, 0); int i; + JimPanic((objc == 0, "Jim_DictMerge called with objc=0")); + + /* Note that we don't optimise the trivial case of a single argument */ + for (i = 0; i < objc; i++) { Jim_HashTable *ht; Jim_HashTableIterator htiter; @@ -14398,6 +14402,61 @@ static int Jim_EvalEnsemble(Jim_Interp *interp, const char *basecmd, const char return Jim_EvalObjPrefix(interp, prefixObj, argc, argv); } +/** + * Implements the [dict with] command + */ +static int JimDictWith(Jim_Interp *interp, Jim_Obj *dictVarName, Jim_Obj *const *keyv, int keyc, Jim_Obj *scriptObj) +{ + int i; + Jim_Obj *objPtr; + Jim_Obj *dictObj; + Jim_Obj **dictValues; + int len; + int ret = JIM_OK; + + /* Open up the appropriate level of the dictionary */ + dictObj = Jim_GetVariable(interp, dictVarName, JIM_ERRMSG); + if (dictObj == NULL || Jim_DictKeysVector(interp, dictObj, keyv, keyc, &objPtr, JIM_ERRMSG) != JIM_OK) { + return JIM_ERR; + } + /* Set the local variables */ + if (Jim_DictPairs(interp, objPtr, &dictValues, &len) == JIM_ERR) { + return JIM_ERR; + } + for (i = 0; i < len; i += 2) { + if (Jim_SetVariable(interp, dictValues[i], dictValues[i + 1]) == JIM_ERR) { + Jim_Free(dictValues); + return JIM_ERR; + } + } + + /* As an optimisation, if the script is empty, no need to evaluate it or update the dict */ + if (Jim_Length(scriptObj)) { + ret = Jim_EvalObj(interp, scriptObj); + + /* Now if the dictionary still exists, update it based on the local variables */ + if (ret == JIM_OK && Jim_GetVariable(interp, dictVarName, 0) != NULL) { + /* We need a copy of keyv with one extra element at the end for Jim_SetDictKeysVector() */ + Jim_Obj **newkeyv = Jim_Alloc(sizeof(*newkeyv) * (keyc + 1)); + for (i = 0; i < keyc; i++) { + newkeyv[i] = keyv[i]; + } + + for (i = 0; i < len; i += 2) { + /* This will be NULL if the variable no longer exists, thus deleting the variable */ + objPtr = Jim_GetVariable(interp, dictValues[i], 0); + newkeyv[keyc] = dictValues[i]; + Jim_SetDictKeysVector(interp, dictVarName, newkeyv, keyc + 1, objPtr, 0); + } + Jim_Free(newkeyv); + } + } + + Jim_Free(dictValues); + + return ret; +} + /* [dict] */ static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { @@ -14519,6 +14578,13 @@ static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg return JIM_ERR; } return Jim_DictInfo(interp, argv[2]); + + case OPT_WITH: + if (argc < 4) { + Jim_WrongNumArgs(interp, 2, argv, "dictVar ?key ...? script"); + return JIM_ERR; + } + return JimDictWith(interp, argv[2], argv + 3, argc - 4, argv[argc - 1]); } /* Handle command as an ensemble */ return Jim_EvalEnsemble(interp, "dict", options[option], argc - 2, argv + 2); diff --git a/stdlib.tcl b/stdlib.tcl index 917b0b6..aef6983 100644 --- a/stdlib.tcl +++ b/stdlib.tcl @@ -87,27 +87,6 @@ proc {info nameofexecutable} {} { } } -# Script-based implementation of 'dict with' -proc {dict with} {&dictVar {args key} script} { - set keys {} - foreach {n v} [dict get $dictVar {*}$key] { - upvar $n var_$n - set var_$n $v - lappend keys $n - } - catch {uplevel 1 $script} msg opts - if {[info exists dictVar] && ([llength $key] == 0 || [dict exists $dictVar {*}$key])} { - foreach n $keys { - if {[info exists var_$n]} { - dict set dictVar {*}$key $n [set var_$n] - } else { - dict unset dictVar {*}$key $n - } - } - } - return {*}$opts $msg -} - # Script-based implementation of 'dict update' proc {dict update} {&varName args script} { set keys {} -- 2.11.4.GIT