summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tclResult.c91
1 files changed, 50 insertions, 41 deletions
diff --git a/generic/tclResult.c b/generic/tclResult.c
index 2e7d378..1cf3910 100644
--- a/generic/tclResult.c
+++ b/generic/tclResult.c
@@ -793,6 +793,9 @@ TclProcessReturn(
*
* Parses, checks, and stores the options to the [return] command.
*
+ * The number of arguments (objc) must be even, with the corresponding
+ * objv holding values to be processed as key value .... key value.
+ *
* Results:
* Returns TCL_ERROR if any of the option values are invalid. Otherwise,
* returns TCL_OK, and writes the returnOpts, code, and level values to
@@ -804,6 +807,49 @@ TclProcessReturn(
*----------------------------------------------------------------------
*/
+static int
+ExpandedOptions(
+ Tcl_Interp *interp, /* Current interpreter. */
+ Tcl_Obj **keys, /* Built-in keys (per thread) */
+ Tcl_Obj *returnOpts, /* Options dict we are building */
+ int objc, /* Number of arguments. */
+ Tcl_Obj *const objv[]) /* Argument objects. */
+{
+ for (; objc > 1; objv += 2, objc -= 2) {
+ const char *opt = TclGetString(objv[0]);
+ const char *compare = TclGetString(keys[KEY_OPTIONS]);
+
+ if ((objv[0]->length == keys[KEY_OPTIONS]->length)
+ && (memcmp(opt, compare, objv[0]->length) == 0)) {
+ /* Process the -options switch to emulate {*} expansion.
+ *
+ * Use lists so duplicate keys are not lost.
+ */
+
+ Tcl_Size nestc;
+ Tcl_Obj **nestv;
+
+ if (TCL_ERROR == TclListObjGetElements(interp, objv[1],
+ &nestc, &nestv) || (nestc % 2)) {
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "bad -options value: expected dictionary but got"
+ " \"%s\"", TclGetString(objv[1])));
+ Tcl_SetErrorCode(interp, "TCL", "RESULT", "ILLEGAL_OPTIONS",
+ (char *)NULL);
+ return TCL_ERROR;
+ }
+
+ if (TCL_ERROR ==
+ ExpandedOptions(interp, keys, returnOpts, nestc, nestv)) {
+ return TCL_ERROR;
+ }
+ } else {
+ Tcl_DictObjPut(NULL, returnOpts, objv[0], objv[1]);
+ }
+ }
+ return TCL_OK;
+}
+
int
TclMergeReturnOptions(
Tcl_Interp *interp, /* Current interpreter. */
@@ -823,48 +869,11 @@ TclMergeReturnOptions(
Tcl_Obj *returnOpts;
Tcl_Obj **keys = GetKeys();
- TclNewObj(returnOpts);
- for (; objc > 1; objv += 2, objc -= 2) {
- const char *opt = TclGetString(objv[0]);
- const char *compare = TclGetString(keys[KEY_OPTIONS]);
-
- if ((objv[0]->length == keys[KEY_OPTIONS]->length)
- && (memcmp(opt, compare, objv[0]->length) == 0)) {
- Tcl_DictSearch search;
- int done = 0;
- Tcl_Obj *keyPtr;
- Tcl_Obj *dict = objv[1];
-
- nestedOptions:
- if (TCL_ERROR == Tcl_DictObjFirst(NULL, dict, &search,
- &keyPtr, &valuePtr, &done)) {
- /*
- * Value is not a legal dictionary.
- */
-
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "bad %s value: expected dictionary but got \"%s\"",
- compare, TclGetString(objv[1])));
- Tcl_SetErrorCode(interp, "TCL", "RESULT", "ILLEGAL_OPTIONS",
- (char *)NULL);
- goto error;
- }
-
- while (!done) {
- Tcl_DictObjPut(NULL, returnOpts, keyPtr, valuePtr);
- Tcl_DictObjNext(&search, &keyPtr, &valuePtr, &done);
- }
+ /* All callers are expected to pass an even value for objc. */
- Tcl_DictObjGet(NULL, returnOpts, keys[KEY_OPTIONS], &valuePtr);
- if (valuePtr != NULL) {
- dict = valuePtr;
- Tcl_DictObjRemove(NULL, returnOpts, keys[KEY_OPTIONS]);
- goto nestedOptions;
- }
-
- } else {
- Tcl_DictObjPut(NULL, returnOpts, objv[0], objv[1]);
- }
+ TclNewObj(returnOpts);
+ if (TCL_ERROR == ExpandedOptions(interp, keys, returnOpts, objc, objv)) {
+ goto error;
}
/*