Tcl Source Code

Artifact [5f86cdf22d]
Login

Artifact 5f86cdf22ddb9ca6d6e034bbd84ecddd28a3d7b6:

Attachment "rw.diff" to ticket [1056864fff] added by dkf 2004-10-29 22:36:41.
Index: ChangeLog
===================================================================
RCS file: /cvsroot/tcl/tcl/ChangeLog,v
retrieving revision 1.2359
diff -u -r1.2359 ChangeLog
--- ChangeLog	28 Oct 2004 17:21:18 -0000	1.2359
+++ ChangeLog	29 Oct 2004 15:32:42 -0000
@@ -1,3 +1,30 @@
+2004-10-29  Donal K. Fellows  <[email protected]>
+
+	* library/tm.tcl (::tcl::tm::*): Use the core proc engine to
+	generate the wrong-num-args error messages for the path ensemble.
+
+	Ensembles can now (sometimes) rewrite the error messages of their
+	subcommands so they appear more like the arguments that the user
+	passed to the ensemble. Below is a description of changes involved
+	in doing this.
+
+	* tests/namespace.test (namespace-50.*): Tests of ensemble
+	subcommand error message rewriting.
+	* generic/tclProc.c (TclObjInterpProc): Make procedures implement
+	their wrong-num-args message using Tcl_WrongNumArgs instead of
+	something baked-at-home.
+	* generic/tclNamesp.c (TclIsEnsemble, NsEnsembleImplementationCmd): 
+	Added test of ensemble-hood (available to rest of core) and made
+	ensembles set up the rewriting for Tcl_WrongNumArgs to take
+	advantage of.
+	* generic/tclInt.h (Interp.ensembleRewrite): Extra fields.
+	* generic/tclIndexObj.c (Tcl_WrongNumArgs): Add knowledge of what
+	is going on in ensembles' command rewriting so this command can
+	generate the right error message itself.
+	* generic/tclBasic.c (Tcl_CreateInterp, TclEvalObjvInternal):
+	Added code to initialize (as empty) the rewriting fields and reset
+	them when we leak outside an ensemble implementation.
+
 2004-10-28  Miguel Sofer <[email protected]>
 
 	* generic/tclExecute.c (INST_START_CMD):
Index: generic/tclBasic.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclBasic.c,v
retrieving revision 1.133
diff -u -r1.133 tclBasic.c
--- generic/tclBasic.c	24 Oct 2004 22:25:12 -0000	1.133
+++ generic/tclBasic.c	29 Oct 2004 15:32:43 -0000
@@ -314,6 +314,14 @@
     iPtr->stubTable = &tclStubs;
 
     /*
+     * Initialize the ensemble error message rewriting support.
+     */
+
+    iPtr->ensembleRewrite.sourceObjs = NULL;
+    iPtr->ensembleRewrite.numRemovedObjs = 0;
+    iPtr->ensembleRewrite.numInsertedObjs = 0;
+
+    /*
      * TIP#143: Initialise the resource limit support.
      */
 
@@ -3031,6 +3039,11 @@
 	if (flags & TCL_EVAL_GLOBAL) {
 	    iPtr->varFramePtr = NULL;
 	}
+	if (!(flags & TCL_EVAL_INVOKE) &&
+		(iPtr->ensembleRewrite.sourceObjs != NULL) &&
+		!TclIsEnsemble(cmdPtr)) {
+	    iPtr->ensembleRewrite.sourceObjs = NULL;
+	}
 	code = (*cmdPtr->objProc)(cmdPtr->objClientData, interp, objc, objv);
 	iPtr->varFramePtr = savedVarFramePtr;
     }
Index: generic/tclClock.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclClock.c,v
retrieving revision 1.35
diff -u -r1.35 tclClock.c
--- generic/tclClock.c	21 Oct 2004 03:53:04 -0000	1.35
+++ generic/tclClock.c	29 Oct 2004 15:32:43 -0000
@@ -336,7 +336,6 @@
 
 }
 
-
 /*----------------------------------------------------------------------
  *
  * TclClockClicksObjCmd --
@@ -356,7 +355,7 @@
  */
 
 int
-TclClockClicksObjCmd( clientData, interp, objc, objv )
+TclClockClicksObjCmd(clientData, interp, objc, objv)
     ClientData clientData;	/* Client data is unused */
     Tcl_Interp* interp;		/* Tcl interpreter */
     int objc;			/* Parameter count */
@@ -371,46 +370,43 @@
     int index = CLICKS_NATIVE;
     Tcl_Time now;
 
-    switch ( objc ) {
-        case 1:
-	    break;
-        case 2:
-	    if ( Tcl_GetIndexFromObj( interp, objv[1], clicksSwitches,
-				      "option", 0, &index) != TCL_OK ) {
-		return TCL_ERROR;
-	    }
-	    break;
-        default:
-	    Tcl_WrongNumArgs( interp, 1, objv, "?option?" );
+    switch (objc) {
+    case 1:
+	break;
+    case 2:
+	if (Tcl_GetIndexFromObj(interp, objv[1], clicksSwitches, "option", 0,
+		&index) != TCL_OK) {
 	    return TCL_ERROR;
+	}
+	break;
+    default:
+	Tcl_WrongNumArgs(interp, 1, objv, "?option?");
+	return TCL_ERROR;
     }
 
-    switch ( index ) {
-        case CLICKS_MILLIS:
-	    Tcl_GetTime( &now );
-	    Tcl_SetObjResult( interp,
-			      Tcl_NewWideIntObj( (Tcl_WideInt) now.sec * 1000
-						 + now.usec / 1000 ) );
-	    break;
-        case CLICKS_NATIVE:
+    switch (index) {
+    case CLICKS_MILLIS:
+	Tcl_GetTime(&now);
+	Tcl_SetObjResult(interp, Tcl_NewWideIntObj( (Tcl_WideInt)
+		now.sec * 1000 + now.usec / 1000 ) );
+	break;
+    case CLICKS_NATIVE:
 #if 0
-	    /* 
-	     * The following code will be used once this is incorporated
-	     * into Tcl.  But TEA bugs prevent it for right now. :(
-	     * So we fall through this case and return the microseconds
-	     * instead.
-	     */
-	    Tcl_SetObjResult( interp,
-			      Tcl_NewWideIntObj( (Tcl_WideInt) TclpGetClicks() ) );
-	    break;
+	/* 
+	 * The following code will be used once this is incorporated
+	 * into Tcl.  But TEA bugs prevent it for right now. :(
+	 * So we fall through this case and return the microseconds
+	 * instead.
+	 */
+	Tcl_SetObjResult(interp, Tcl_NewWideIntObj( (Tcl_WideInt)
+		TclpGetClicks()));
+	break;
 #endif
-        case CLICKS_MICROS:
-	    Tcl_GetTime( &now );
-	    Tcl_SetObjResult( interp,
-			      Tcl_NewWideIntObj( ( (Tcl_WideInt) now.sec 
-						   * 1000000 )
-						 + now.usec ) );
-	    break;
+    case CLICKS_MICROS:
+	Tcl_GetTime(&now);
+	Tcl_SetObjResult(interp, Tcl_NewWideIntObj(
+		((Tcl_WideInt) now.sec * 1000000) + now.usec));
+	break;
     }
 
     return TCL_OK;
@@ -435,21 +431,20 @@
  */
 
 int
-TclClockMillisecondsObjCmd( clientData, interp, objc, objv )
+TclClockMillisecondsObjCmd(clientData, interp, objc, objv)
     ClientData clientData;	/* Client data is unused */
     Tcl_Interp* interp;		/* Tcl interpreter */
     int objc;			/* Parameter count */
     Tcl_Obj* CONST* objv;	/* Parameter values */
 {
     Tcl_Time now;
-    if ( objc != 1 ) {
-	Tcl_WrongNumArgs( interp, 1, objv, "" );
+    if (objc != 1) {
+	Tcl_WrongNumArgs(interp, 1, objv, NULL);
 	return TCL_ERROR;
     }
-    Tcl_GetTime( &now );
-    Tcl_SetObjResult( interp,
-		      Tcl_NewWideIntObj( (Tcl_WideInt) now.sec * 1000
-					 + now.usec / 1000 ) );
+    Tcl_GetTime(&now);
+    Tcl_SetObjResult(interp, Tcl_NewWideIntObj( (Tcl_WideInt)
+	    now.sec * 1000 + now.usec / 1000));
     return TCL_OK;
 }
 
@@ -472,21 +467,20 @@
  */
 
 int
-TclClockMicrosecondsObjCmd( clientData, interp, objc, objv )
+TclClockMicrosecondsObjCmd(clientData, interp, objc, objv)
     ClientData clientData;	/* Client data is unused */
     Tcl_Interp* interp;		/* Tcl interpreter */
     int objc;			/* Parameter count */
     Tcl_Obj* CONST* objv;	/* Parameter values */
 {
     Tcl_Time now;
-    if ( objc != 1 ) {
-	Tcl_WrongNumArgs( interp, 1, objv, "" );
+    if (objc != 1) {
+	Tcl_WrongNumArgs(interp, 1, objv, NULL);
 	return TCL_ERROR;
     }
-    Tcl_GetTime( &now );
-    Tcl_SetObjResult( interp,
-		      Tcl_NewWideIntObj( ( (Tcl_WideInt) now.sec * 1000000 )
-					 + now.usec ) );
+    Tcl_GetTime(&now);
+    Tcl_SetObjResult(interp, Tcl_NewWideIntObj(
+	    ((Tcl_WideInt) now.sec * 1000000) + now.usec));
     return TCL_OK;
 }
 
@@ -509,19 +503,19 @@
  */
 
 int
-TclClockSecondsObjCmd( clientData, interp, objc, objv )
+TclClockSecondsObjCmd(clientData, interp, objc, objv)
     ClientData clientData;	/* Client data is unused */
     Tcl_Interp* interp;		/* Tcl interpreter */
     int objc;			/* Parameter count */
     Tcl_Obj* CONST* objv;	/* Parameter values */
 {
     Tcl_Time now;
-    if ( objc != 1 ) {
-	Tcl_WrongNumArgs( interp, 1, objv, "" );
+    if (objc != 1) {
+	Tcl_WrongNumArgs(interp, 1, objv, NULL);
 	return TCL_ERROR;
     }
-    Tcl_GetTime( &now );
-    Tcl_SetObjResult( interp, Tcl_NewWideIntObj( (Tcl_WideInt) now.sec ) );
+    Tcl_GetTime(&now);
+    Tcl_SetObjResult(interp, Tcl_NewWideIntObj((Tcl_WideInt) now.sec));
     return TCL_OK;
 }
 
Index: generic/tclConfig.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclConfig.c,v
retrieving revision 1.5
diff -u -r1.5 tclConfig.c
--- generic/tclConfig.c	24 Dec 2003 04:18:19 -0000	1.5
+++ generic/tclConfig.c	29 Oct 2004 15:32:43 -0000
@@ -209,7 +209,7 @@
     };
 
     if ((objc < 2) || (objc > 3)) {
-        Tcl_WrongNumArgs (interp, 0, NULL, "list | get key");
+	Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?argument?");
 	return TCL_ERROR;
     }
     if (Tcl_GetIndexFromObj(interp, objv[1], subcmdStrings,
@@ -228,7 +228,7 @@
     switch ((enum subcmds) index) {
     case CFG_GET:
 	if (objc != 3) {
-	    Tcl_WrongNumArgs(interp, 0, NULL, "get key");
+	    Tcl_WrongNumArgs(interp, 1, objv, "get key");
 	    return TCL_ERROR;
 	}
 
@@ -243,7 +243,7 @@
 
     case CFG_LIST:
 	if (objc != 2) {
-	    Tcl_WrongNumArgs(interp, 0, NULL, "list");
+	    Tcl_WrongNumArgs(interp, 1, objv, "list");
 	    return TCL_ERROR;
 	}
 
Index: generic/tclIndexObj.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclIndexObj.c,v
retrieving revision 1.20
diff -u -r1.20 tclIndexObj.c
--- generic/tclIndexObj.c	6 Oct 2004 14:59:02 -0000	1.20
+++ generic/tclIndexObj.c	29 Oct 2004 15:32:43 -0000
@@ -445,12 +445,69 @@
 					 * message may be NULL. */
 {
     Tcl_Obj *objPtr;
-    int i;
+    int i, len, elemLen, flags;
     register IndexRep *indexRep;
+    Interp *iPtr = (Interp *) interp;
+    char *elementStr;
 
     TclNewObj(objPtr);
-    Tcl_SetObjResult(interp, objPtr);
     Tcl_AppendToObj(objPtr, "wrong # args: should be \"", -1);
+
+    /*
+     * Check to see if we are processing an ensemble implementation,
+     * and if so rewrite the results in terms of how the ensemble was
+     * invoked.
+     */
+
+    if (iPtr->ensembleRewrite.sourceObjs != NULL) {
+	/*
+	 * We only know how to do rewriting if all the replaced
+	 * objects are actually arguments (in objv) to this function.
+	 * Otherwise it just gets too complicated...
+	 */
+
+	if (objc >= iPtr->ensembleRewrite.numInsertedObjs) {
+	    objv += iPtr->ensembleRewrite.numInsertedObjs;
+	    objc -= iPtr->ensembleRewrite.numInsertedObjs;
+	    /*
+	     * We assume no object is of index type.
+	     */
+	    for (i=0 ; i<iPtr->ensembleRewrite.numRemovedObjs ; i++) {
+		/*
+		 * Add the element, quoting it if necessary.
+		 */
+
+		elementStr = Tcl_GetStringFromObj(
+			iPtr->ensembleRewrite.sourceObjs[i], &elemLen);
+		len = Tcl_ScanCountedElement(elementStr, elemLen, &flags);
+		if (len != elemLen) {
+		    char *quotedElementStr = ckalloc((unsigned) len);
+		    len = Tcl_ConvertCountedElement(elementStr, elemLen,
+			    quotedElementStr, flags);
+		    Tcl_AppendToObj(objPtr, quotedElementStr, len);
+		    ckfree(quotedElementStr);
+		} else {
+		    Tcl_AppendToObj(objPtr, elementStr, elemLen);
+		}
+
+		/*
+		 * Add a space if the word is not the last one (which
+		 * has a moderately complex condition here).
+		 */
+
+		if ((i < (iPtr->ensembleRewrite.numRemovedObjs - 1))
+			|| objc || message) {
+		    Tcl_AppendStringsToObj(objPtr, " ", (char *) NULL);
+		}
+	    }
+	}
+    }
+
+    /*
+     * Now add the arguments (other than those rewritten) that the
+     * caller took from its calling context.
+     */
+
     for (i = 0; i < objc; i++) {
 	/*
 	 * If the object is an index type use the index table which allows
@@ -462,8 +519,21 @@
 	    indexRep = (IndexRep *) objv[i]->internalRep.otherValuePtr;
 	    Tcl_AppendStringsToObj(objPtr, EXPAND_OF(indexRep), (char *) NULL);
 	} else {
-	    Tcl_AppendStringsToObj(objPtr, Tcl_GetString(objv[i]),
-		    (char *) NULL);
+	    /*
+	     * Quote the argument if it contains spaces (Bug 942757).
+	     */
+
+	    elementStr = Tcl_GetStringFromObj(objv[i], &elemLen);
+	    len = Tcl_ScanCountedElement(elementStr, elemLen, &flags);
+	    if (len != elemLen) {
+		char *quotedElementStr = ckalloc((unsigned) len);
+		len = Tcl_ConvertCountedElement(elementStr, elemLen,
+			quotedElementStr, flags);
+		Tcl_AppendToObj(objPtr, quotedElementStr, len);
+		ckfree(quotedElementStr);
+	    } else {
+		Tcl_AppendToObj(objPtr, elementStr, elemLen);
+	    }
 	}
 
 	/*
@@ -475,8 +545,15 @@
 	}
     }
 
+    /*
+     * Add any trailing message bits and set the resulting string as
+     * the interpreter result. Caller is responsible for reporting
+     * this as an actual error.
+     */
+
     if (message) {
 	Tcl_AppendStringsToObj(objPtr, message, (char *) NULL);
     }
     Tcl_AppendStringsToObj(objPtr, "\"", (char *) NULL);
+    Tcl_SetObjResult(interp, objPtr);
 }
Index: generic/tclInt.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclInt.h,v
retrieving revision 1.189
diff -u -r1.189 tclInt.h
--- generic/tclInt.h	27 Oct 2004 17:13:58 -0000	1.189
+++ generic/tclInt.h	29 Oct 2004 15:32:43 -0000
@@ -1400,6 +1400,23 @@
     } limit;
 
     /*
+     * Information for improved default error generation from
+     * ensembles (TIP#112).
+     */
+
+    struct {
+	Tcl_Obj * CONST *sourceObjs;
+				/* What arguments were actually input into
+				 * the *root* ensemble command?  (Nested
+				 * ensembles don't rewrite this.)  NULL if
+				 * we're not processing an ensemble. */
+	int numRemovedObjs;	/* How many arguments have been stripped off
+				 * because of ensemble processing. */
+	int numInsertedObjs;	/* How many of the current arguments were
+				 * inserted by an ensemble. */
+    } ensembleRewrite;
+
+    /*
      * Statistical information about the bytecode compiler and interpreter's
      * operation.
      */
@@ -1949,6 +1966,7 @@
 		            Tcl_FSUnloadFileProc **unloadProcPtr));
 EXTERN int              TclpUtime _ANSI_ARGS_((Tcl_Obj *pathPtr,
 					       struct utimbuf *tval));
+EXTERN int		TclIsEnsemble _ANSI_ARGS_((Command *cmdPtr));
 
 /*
  *----------------------------------------------------------------
Index: generic/tclNamesp.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclNamesp.c,v
retrieving revision 1.63
diff -u -r1.63 tclNamesp.c
--- generic/tclNamesp.c	22 Oct 2004 15:46:37 -0000	1.63
+++ generic/tclNamesp.c	29 Oct 2004 15:32:44 -0000
@@ -3367,8 +3367,7 @@
     int firstArg, patternCt, i, result;
 
     if (objc < 2) {
-	Tcl_WrongNumArgs(interp, 2, objv,
-	        "?-clear? ?pattern pattern...?");
+	Tcl_WrongNumArgs(interp, 2, objv, "?-clear? ?pattern pattern...?");
         return TCL_ERROR;
     }
 
@@ -3526,8 +3525,7 @@
     int firstArg;
 
     if (objc < 2) {
-        Tcl_WrongNumArgs(interp, 2, objv,
-	        "?-force? ?pattern pattern...?");
+        Tcl_WrongNumArgs(interp, 2, objv, "?-force? ?pattern pattern...?");
         return TCL_ERROR;
     }
 
@@ -4863,6 +4861,37 @@
 /*
  *----------------------------------------------------------------------
  *
+ * TclIsEnsemble --
+ *
+ *	Simple test for ensemble-hood that takes into account imported
+ *	ensemble commands as well.
+ *
+ * Results:
+ *	Boolean value
+ *
+ * Side effects:
+ *	None
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TclIsEnsemble(cmdPtr)
+    Command *cmdPtr;
+{
+    if (cmdPtr->objProc == NsEnsembleImplementationCmd) {
+	return 1;
+    }
+    cmdPtr = (Command *) TclGetOriginalCommand((Tcl_Command) cmdPtr);
+    if (cmdPtr == NULL || cmdPtr->objProc != NsEnsembleImplementationCmd) {
+	return 0;
+    }
+    return 1;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
  * NsEnsembleImplementationCmd --
  *
  *	Implements an ensemble of commands (being those exported by a
@@ -5045,15 +5074,38 @@
 
     Tcl_IncrRefCount(prefixObj);
   runResultingSubcommand:
-    Tcl_ListObjGetElements(NULL, prefixObj, &prefixObjc, &prefixObjv);
-    tempObjv = (Tcl_Obj **) ckalloc(sizeof(Tcl_Obj *)*(objc-2+prefixObjc));
-    memcpy(tempObjv,            prefixObjv, sizeof(Tcl_Obj *) * prefixObjc);
-    memcpy(tempObjv+prefixObjc, objv+2,     sizeof(Tcl_Obj *) * (objc-2));
-    result = Tcl_EvalObjv(interp, objc-2+prefixObjc, tempObjv,
-	    TCL_EVAL_INVOKE);
-    Tcl_DecrRefCount(prefixObj);
-    ckfree((char *)tempObjv);
-    return result;
+    {
+	Interp *iPtr = (Interp *) interp;
+	int isRootEnsemble = (iPtr->ensembleRewrite.sourceObjs == NULL);
+
+	Tcl_ListObjGetElements(NULL, prefixObj, &prefixObjc, &prefixObjv);
+	if (isRootEnsemble) {
+	    iPtr->ensembleRewrite.sourceObjs = objv;
+	    iPtr->ensembleRewrite.numRemovedObjs = 2;
+	    iPtr->ensembleRewrite.numInsertedObjs = prefixObjc;
+	} else {
+	    int ni = iPtr->ensembleRewrite.numInsertedObjs;
+	    if (ni < 2) {
+		iPtr->ensembleRewrite.numRemovedObjs += 2 - ni;
+		iPtr->ensembleRewrite.numInsertedObjs += prefixObjc - 1;
+	    } else {
+		iPtr->ensembleRewrite.numInsertedObjs += prefixObjc - 2;
+	    }
+	}
+	tempObjv = (Tcl_Obj **) ckalloc(sizeof(Tcl_Obj *)*(objc-2+prefixObjc));
+	memcpy(tempObjv, prefixObjv, sizeof(Tcl_Obj *) * prefixObjc);
+	memcpy(tempObjv+prefixObjc, objv+2, sizeof(Tcl_Obj *) * (objc-2));
+	result = Tcl_EvalObjv(interp, objc-2+prefixObjc, tempObjv,
+		TCL_EVAL_INVOKE);
+	Tcl_DecrRefCount(prefixObj);
+	ckfree((char *)tempObjv);
+	if (isRootEnsemble) {
+	    iPtr->ensembleRewrite.sourceObjs = NULL;
+	    iPtr->ensembleRewrite.numRemovedObjs = 0;
+	    iPtr->ensembleRewrite.numInsertedObjs = 0;
+	}
+	return result;
+    }
 
   unknownOrAmbiguousSubcommand:
     /*
Index: generic/tclProc.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclProc.c,v
retrieving revision 1.63
diff -u -r1.63 tclProc.c
--- generic/tclProc.c	22 Oct 2004 13:48:58 -0000	1.63
+++ generic/tclProc.c	29 Oct 2004 15:32:44 -0000
@@ -1043,47 +1043,39 @@
 	localPtr = localPtr->nextPtr;
     }
     if (argCt > 0) {
-	Tcl_Obj *objResult;
-	int len, flags;
+	Tcl_Obj **desiredObjs, *argObj;
 
-	incorrectArgs:
+    incorrectArgs:
 	/*
-	 * Build up equivalent to Tcl_WrongNumArgs message for proc
+	 * Build up desired argument list for Tcl_WrongNumArgs
 	 */
 
-	Tcl_ResetResult(interp);
-	TclNewObj(objResult);
-	Tcl_AppendToObj(objResult, "wrong # args: should be \"", -1);
-
-	/*
-	 * Quote the proc name if it contains spaces (Bug 942757).
-	 */
-
-	len = Tcl_ScanCountedElement(procName, nameLen, &flags);
-	if (len != nameLen) {
-	    char *procName1 = ckalloc((unsigned) len);
-	    len = Tcl_ConvertCountedElement(procName, nameLen, procName1, flags);
-	    Tcl_AppendToObj(objResult, procName1, len);
-	    ckfree(procName1);
-	} else {
-	    Tcl_AppendToObj(objResult, procName, len);
-	}
-
+	desiredObjs = (Tcl_Obj **)
+		ckalloc(sizeof(Tcl_Obj *) * (unsigned)(numArgs+1));
+	desiredObjs[0] = objv[0];
 	localPtr = procPtr->firstLocalPtr;
-	for (i = 1;  i <= numArgs;  i++) {
+	for (i=1 ; i<=numArgs ; i++) {
+	    TclNewObj(argObj);
 	    if (localPtr->defValuePtr != NULL) {
-		Tcl_AppendStringsToObj(objResult,
-			" ?", localPtr->name, "?", (char *) NULL);
+		Tcl_AppendStringsToObj(argObj,
+			"?", localPtr->name, "?", (char *) NULL);
+	    } else if ((i==numArgs) && (strcmp(localPtr->name, "args")==0)) {
+		Tcl_AppendStringsToObj(argObj, "...", (char *) NULL);
 	    } else {
-		Tcl_AppendStringsToObj(objResult,
-			" ", localPtr->name, (char *) NULL);
+		Tcl_AppendStringsToObj(argObj, localPtr->name, (char *) NULL);
 	    }
+	    desiredObjs[i] = argObj;
 	    localPtr = localPtr->nextPtr;
 	}
-	Tcl_AppendStringsToObj(objResult, "\"", (char *) NULL);
-	Tcl_SetObjResult(interp, objResult);
 
+	Tcl_ResetResult(interp);
+	Tcl_WrongNumArgs(interp, numArgs+1, desiredObjs, NULL);
 	result = TCL_ERROR;
+
+	for (i=1 ; i<=numArgs ; i++) {
+	    TclDecrRefCount(desiredObjs[i]);
+	}
+	ckfree((char *) desiredObjs);
 	goto procDone;
     }
 
Index: generic/tclVar.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclVar.c,v
retrieving revision 1.97
diff -u -r1.97 tclVar.c
--- generic/tclVar.c	26 Oct 2004 16:19:58 -0000	1.97
+++ generic/tclVar.c	29 Oct 2004 15:32:44 -0000
@@ -2729,8 +2729,7 @@
 	    ArraySearch *searchPtr;
 	    
 	    if (objc != 4) {
-	        Tcl_WrongNumArgs(interp, 2, objv, 
-                        "arrayName searchId");
+	        Tcl_WrongNumArgs(interp, 2, objv, "arrayName searchId");
 		return TCL_ERROR;
 	    }
 	    if (notArray) {
@@ -2762,8 +2761,7 @@
 	    ArraySearch *searchPtr, *prevPtr;
 
 	    if (objc != 4) {
-	        Tcl_WrongNumArgs(interp, 2, objv, 
-                        "arrayName searchId");
+	        Tcl_WrongNumArgs(interp, 2, objv, "arrayName searchId");
 		return TCL_ERROR;
 	    }
 	    if (notArray) {
@@ -2914,8 +2912,7 @@
 	    mode = OPT_GLOB;
 	    
 	    if ((objc < 3) || (objc > 5)) {
-  	        Tcl_WrongNumArgs(interp, 2, objv,
-			"arrayName ?mode? ?pattern?");
+  	        Tcl_WrongNumArgs(interp, 2,objv, "arrayName ?mode? ?pattern?");
 		return TCL_ERROR;
 	    }
 	    if (notArray) {
@@ -2975,8 +2972,7 @@
 	    Tcl_HashEntry *hPtr;
 	    
 	    if (objc != 4) {
-	        Tcl_WrongNumArgs(interp, 2, objv, 
-                        "arrayName searchId");
+	        Tcl_WrongNumArgs(interp, 2, objv, "arrayName searchId");
 		return TCL_ERROR;
 	    }
 	    if (notArray) {
Index: library/tm.tcl
===================================================================
RCS file: /cvsroot/tcl/tcl/library/tm.tcl,v
retrieving revision 1.4
diff -u -r1.4 tm.tcl
--- library/tm.tcl	27 Oct 2004 17:01:46 -0000	1.4
+++ library/tm.tcl	29 Oct 2004 15:32:44 -0000
@@ -79,7 +79,7 @@
 #	paths to search for Tcl Modules. The subcommand 'list' has no
 #	sideeffects.
 
-proc ::tcl::tm::add {args} {
+proc ::tcl::tm::add {path args} {
     # PART OF THE ::tcl::tm::path ENSEMBLE
     #
     # The path is added at the head to the list of module paths.
@@ -91,11 +91,6 @@
     # If the path is already present as is no error will be raised and
     # no action will be taken.
 
-    if {[llength $args] == 0} {
-	return -code error \
-	    "wrong # args: should be \"::tcl::tm::path add path ?path ...?\""
-    }
-
     variable paths
 
     # We use a copy of the path as source during validation, and
@@ -107,7 +102,7 @@
     # paths to the official state var.
 
     set newpaths $paths
-    foreach p $args {
+    foreach p [linsert $args 0 $path] {
 	if {$p in $newpaths} {
 	    # Ignore a path already on the list.
 	    continue
@@ -148,20 +143,15 @@
     return
 }
 
-proc ::tcl::tm::remove {args} {
+proc ::tcl::tm::remove {path args} {
     # PART OF THE ::tcl::tm::path ENSEMBLE
     #
     # Removes the path from the list of module paths. The command is
     # silently ignored if the path is not on the list.
 
-    if {[llength $args] == 0} {
-	return -code error \
-	    "wrong # args: should be \"::tcl::tm::path remove path ?path ...?\""
-    }
-
     variable paths
 
-    foreach p $args {
+    foreach p [linsert $args 0 $path] {
 	set pos [lsearch -exact $paths $p]
 	if {$pos >= 0} {
 	    set paths [lreplace $paths $pos $pos]
@@ -169,12 +159,9 @@
     }
 }
 
-proc ::tcl::tm::list {args} {
+proc ::tcl::tm::list {} {
     # PART OF THE ::tcl::tm::path ENSEMBLE
 
-    if {[llength $args] != 0} {
-	return -code error "wrong # args: should be \"::tcl::tm::path list\""
-    }
     variable paths
     return  $paths
 }
Index: tests/clock.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/clock.test,v
retrieving revision 1.49
diff -u -r1.49 clock.test
--- tests/clock.test	28 Oct 2004 00:04:33 -0000	1.49
+++ tests/clock.test	29 Oct 2004 15:32:50 -0000
@@ -35223,7 +35223,7 @@
 } {}
 test clock-35.2 {clock seconds tests} {
     list [catch {clock seconds foo} msg] $msg
-} {1 {wrong # args: should be "::tcl::clock::seconds "}}
+} {1 {wrong # args: should be "clock seconds"}}
 test clock-35.3 {clock seconds tests} {
     set start [clock seconds]
     after 2000
Index: tests/config.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/config.test,v
retrieving revision 1.3
diff -u -r1.3 config.test
--- tests/config.test	19 May 2004 12:22:13 -0000	1.3
+++ tests/config.test	29 Oct 2004 15:32:50 -0000
@@ -35,7 +35,7 @@
 test pkgconfig-2.0 {error: missing subcommand} {
     catch {::tcl::pkgconfig} msg
     set msg
-} {wrong # args: should be "list | get key"}
+} {wrong # args: should be "::tcl::pkgconfig subcommand ?argument?"}
 test pkgconfig-2.1 {error: illegal subcommand} {
     catch {::tcl::pkgconfig foo} msg
     set msg
@@ -43,11 +43,11 @@
 test pkgconfig-2.2 {error: list with arguments} {
     catch {::tcl::pkgconfig list foo} msg
     set msg
-} {wrong # args: should be "list"}
+} {wrong # args: should be "::tcl::pkgconfig list"}
 test pkgconfig-2.3 {error: get without arguments} {
     catch {::tcl::pkgconfig get} msg
     set msg
-} {wrong # args: should be "get key"}
+} {wrong # args: should be "::tcl::pkgconfig get key"}
 test pkgconfig-2.4 {error: query unknown key} {
     catch {::tcl::pkgconfig get foo} msg
     set msg
@@ -55,7 +55,7 @@
 test pkgconfig-2.5 {error: query with to many arguments} {
     catch {::tcl::pkgconfig get foo bar} msg
     set msg
-} {wrong # args: should be "list | get key"}
+} {wrong # args: should be "::tcl::pkgconfig subcommand ?argument?"}
 
 # cleanup
 ::tcltest::cleanupTests
Index: tests/namespace.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/namespace.test,v
retrieving revision 1.42
diff -u -r1.42 namespace.test
--- tests/namespace.test	28 Oct 2004 00:04:39 -0000	1.42
+++ tests/namespace.test	29 Oct 2004 15:32:50 -0000
@@ -1925,6 +1925,37 @@
     rename x {}
 }
 
+test namespace-50.1 {ensembles affect proc arguments error messages} -body {
+    namespace ens cre -command a -map {b {bb foo}}
+    proc bb {c d {e f} args} {list $c $args}
+    a b
+} -returnCodes error -result "wrong # args: should be \"a b d ?e? ...\"" -cleanup {
+    rename a {}
+    rename bb {}
+}
+test namespace-50.2 {ensembles affect WrongNumArgs error messages} -body {
+    namespace ens cre -command a -map {b {string is}}
+    a b boolean
+} -returnCodes error -result "wrong # args: should be \"a b class ?-strict? ?-failindex var? str\"" -cleanup {
+    rename a {}
+}
+test namespace-50.3 {chained ensembles affect error messages} -body {
+    namespace ens cre -command a -map {b c}
+    namespace ens cre -command c -map {d e}
+    proc e f {}
+    a b d
+} -returnCodes error -result "wrong # args: should be \"a b d f\"" -cleanup {
+    rename a {}
+}
+test namespace-50.4 {chained ensembles affect error messages} -body {
+    namespace ens cre -command a -map {b {c d}}
+    namespace ens cre -command c -map {d {e f}}
+    proc e f {}
+    a b d
+} -returnCodes error -result "wrong # args: should be \"a b\"" -cleanup {
+    rename a {}
+}
+
 # cleanup
 catch {rename cmd1 {}}
 catch {unset l}
Index: tests/proc-old.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/proc-old.test,v
retrieving revision 1.12
diff -u -r1.12 proc-old.test
--- tests/proc-old.test	19 May 2004 12:56:54 -0000	1.12
+++ tests/proc-old.test	29 Oct 2004 15:32:50 -0000
@@ -233,7 +233,7 @@
 	return [list $x $y $args]
     }
     list [catch {tproc} msg] $msg
-} {1 {wrong # args: should be "tproc x ?y? args"}}
+} {1 {wrong # args: should be "tproc x ?y? ..."}}
 
 test proc-old-4.1 {variable numbers of arguments} {
     proc tproc args {return $args}
@@ -258,7 +258,7 @@
 test proc-old-4.6 {variable numbers of arguments} {
     proc tproc {x missing args} {return $args}
     list [catch {tproc 1} msg] $msg
-} {1 {wrong # args: should be "tproc x missing args"}}
+} {1 {wrong # args: should be "tproc x missing ..."}}
 
 test proc-old-5.1 {error conditions} {
     list [catch {proc} msg] $msg
Index: tests/tm.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/tm.test,v
retrieving revision 1.3
diff -u -r1.3 tm.test
--- tests/tm.test	27 Oct 2004 17:01:46 -0000	1.3
+++ tests/tm.test	29 Oct 2004 15:32:50 -0000
@@ -23,10 +23,10 @@
 } -result {unknown or ambiguous subcommand "foo": must be add, list, or remove}
 test tm-1.3 {tm: path command syntax} -returnCodes error -body {
     ::tcl::tm::path add
-} -result "wrong # args: should be \"::tcl::tm::path add path ?path ...?\""
+} -result "wrong # args: should be \"::tcl::tm::path add path ...\""
 test tm-1.4 {tm: path command syntax} -returnCodes error -body {
     ::tcl::tm::path remove
-} -result "wrong # args: should be \"::tcl::tm::path remove path ?path ...?\""
+} -result "wrong # args: should be \"::tcl::tm::path remove path ...\""
 test tm-1.5 {tm: path command syntax} -returnCodes error -body {
     ::tcl::tm::path list foobar
 } -result "wrong # args: should be \"::tcl::tm::path list\""