summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/dict.n13
-rw-r--r--generic/tclDictObj.c69
-rw-r--r--tests/dict.test28
-rwxr-xr-x[-rw-r--r--]tools/encoding/ebcdic.txt0
-rwxr-xr-x[-rw-r--r--]tools/encoding/tis-620.txt0
5 files changed, 110 insertions, 0 deletions
diff --git a/doc/dict.n b/doc/dict.n
index 1829768..12c9b1a 100644
--- a/doc/dict.n
+++ b/doc/dict.n
@@ -120,6 +120,19 @@ It is an error to attempt to retrieve a value for a key that is not
present in the dictionary.
.RE
.TP
+\fBdict getwithdefault \fIdictionaryValue \fR?\fIkey ...\fR? \fIkey default\fR
+.VS "8.7, TIP342"
+This behaves the same as \fBdict get\fR (with at least one \fIkey\fR
+argument), returning the value that the key path maps to in the
+dictionary \fIdictionaryValue\fR, except that instead of producing an
+error because the \fIkey\fR (or one of the \fIkey\fRs on the key path)
+is absent, it returns the \fIdefault\fR argument instead.
+.RS
+.PP
+Note that there must always be at least one \fIkey\fR provided.
+.RE
+.VE "8.7, TIP342"
+.TP
\fBdict incr \fIdictionaryVariable key \fR?\fIincrement\fR?
.
This adds the given increment value (an integer that defaults to 1 if
diff --git a/generic/tclDictObj.c b/generic/tclDictObj.c
index baf96a8..75dcd09 100644
--- a/generic/tclDictObj.c
+++ b/generic/tclDictObj.c
@@ -34,6 +34,9 @@ static int DictFilterCmd(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 DictGetWithDefaultCmd(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,
@@ -89,6 +92,7 @@ static const EnsembleImplMap implementationMap[] = {
{"filter", DictFilterCmd, NULL, NULL, NULL, 0 },
{"for", NULL, TclCompileDictForCmd, DictForNRCmd, NULL, 0 },
{"get", DictGetCmd, TclCompileDictGetCmd, NULL, NULL, 0 },
+ {"getwithdefault", DictGetWithDefaultCmd, NULL, NULL, NULL, 0 },
{"incr", DictIncrCmd, TclCompileDictIncrCmd, NULL, NULL, 0 },
{"info", DictInfoCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0 },
{"keys", DictKeysCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0 },
@@ -1627,6 +1631,71 @@ DictGetCmd(
/*
*----------------------------------------------------------------------
*
+ * DictGetWithDefaultCmd --
+ *
+ * This function implements the "dict getwithdefault" Tcl command. 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
+DictGetWithDefaultCmd(
+ ClientData dummy,
+ 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
diff --git a/tests/dict.test b/tests/dict.test
index 904ec53..50e4db7 100644
--- a/tests/dict.test
+++ b/tests/dict.test
@@ -2047,6 +2047,34 @@ test dict-25.1 {compiled dict update with low-refcount values [Bug d553228d9f]}
dict update item item item two two {}
}}
} {}
+
+test dict-26.1 {dict getwithdefault command} -body {
+ dict getwithdefault {a b} a c
+} -result b
+test dict-26.2 {dict getwithdefault command} -body {
+ dict getwithdefault {a b} b c
+} -result c
+test dict-26.3 {dict getwithdefault command} -body {
+ dict getwithdefault {a {b c}} a b d
+} -result c
+test dict-26.4 {dict getwithdefault command} -body {
+ dict getwithdefault {a {b c}} a c d
+} -result d
+test dict-26.5 {dict getwithdefault command} -body {
+ dict getwithdefault {a {b c}} b c d
+} -result d
+test dict-26.6 {dict getwithdefault command} -returnCodes error -body {
+ dict getwithdefault {a {b c d}} a b d
+} -result {missing value to go with key}
+test dict-26.7 {dict getwithdefault command} -returnCodes error -body {
+ dict getwithdefault
+} -result {wrong # args: should be "dict getwithdefault dictionary ?key ...? key default"}
+test dict-26.8 {dict getwithdefault command} -returnCodes error -body {
+ dict getwithdefault {}
+} -result {wrong # args: should be "dict getwithdefault dictionary ?key ...? key default"}
+test dict-26.9 {dict getwithdefault command} -returnCodes error -body {
+ dict getwithdefault {} {}
+} -result {wrong # args: should be "dict getwithdefault dictionary ?key ...? key default"}
# cleanup
::tcltest::cleanupTests
diff --git a/tools/encoding/ebcdic.txt b/tools/encoding/ebcdic.txt
index d9fa42e..d9fa42e 100644..100755
--- a/tools/encoding/ebcdic.txt
+++ b/tools/encoding/ebcdic.txt
diff --git a/tools/encoding/tis-620.txt b/tools/encoding/tis-620.txt
index d3656c5..d3656c5 100644..100755
--- a/tools/encoding/tis-620.txt
+++ b/tools/encoding/tis-620.txt