Tcl Source Code

Artifact [d7a3811d76]
Login

Artifact d7a3811d762080acdbfba00c49b74e9c3efaac31:

Attachment "ensemble-parameters.patch" to ticket [1901783fff] added by lars_h 2008-02-26 07:34:19.
Index: generic/tcl.decls
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tcl.decls,v
retrieving revision 1.129
diff -c -r1.129 tcl.decls
*** generic/tcl.decls	13 Dec 2007 15:23:14 -0000	1.129
--- generic/tcl.decls	25 Feb 2008 23:06:48 -0000
***************
*** 2099,2104 ****
--- 2099,2115 ----
      void Tcl_AppendPrintfToObj(Tcl_Obj *objPtr, CONST char *format, ...)
  }
  
+ # TIP xxx Ensembles with parameters
+ declare 580 generic {
+     int Tcl_SetEnsembleParameterList(Tcl_Interp *interp, Tcl_Command token,
+ 	    Tcl_Obj *paramList)
+ }
+ declare 581 generic {
+     int Tcl_GetEnsembleParameterList(Tcl_Interp *interp, Tcl_Command token,
+ 	    Tcl_Obj **paramListPtr)
+ }
+ 
+ 
  ##############################################################################
  
  # Define the platform specific public Tcl interface.  These functions are
Index: generic/tclDecls.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclDecls.h,v
retrieving revision 1.130
diff -c -r1.130 tclDecls.h
*** generic/tclDecls.h	13 Dec 2007 15:23:16 -0000	1.130
--- generic/tclDecls.h	25 Feb 2008 23:06:56 -0000
***************
*** 3501,3506 ****
--- 3501,3518 ----
  EXTERN void		Tcl_AppendPrintfToObj (Tcl_Obj * objPtr, 
  				CONST char * format, ...);
  #endif
+ #ifndef Tcl_SetEnsembleParameterList_TCL_DECLARED
+ #define Tcl_SetEnsembleParameterList_TCL_DECLARED
+ /* 580 */
+ EXTERN int		Tcl_SetEnsembleParameterList (Tcl_Interp * interp, 
+ 				Tcl_Command token, Tcl_Obj * paramList);
+ #endif
+ #ifndef Tcl_GetEnsembleParameterList_TCL_DECLARED
+ #define Tcl_GetEnsembleParameterList_TCL_DECLARED
+ /* 581 */
+ EXTERN int		Tcl_GetEnsembleParameterList (Tcl_Interp * interp, 
+ 				Tcl_Command token, Tcl_Obj ** paramListPtr);
+ #endif
  
  typedef struct TclStubHooks {
      struct TclPlatStubs *tclPlatStubs;
***************
*** 4140,4145 ****
--- 4152,4159 ----
      int (*tcl_AppendFormatToObj) (Tcl_Interp * interp, Tcl_Obj * objPtr, CONST char * format, int objc, Tcl_Obj * CONST objv[]); /* 577 */
      Tcl_Obj * (*tcl_ObjPrintf) (CONST char * format, ...); /* 578 */
      void (*tcl_AppendPrintfToObj) (Tcl_Obj * objPtr, CONST char * format, ...); /* 579 */
+     int (*tcl_SetEnsembleParameterList) (Tcl_Interp * interp, Tcl_Command token, Tcl_Obj * paramList); /* 580 */
+     int (*tcl_GetEnsembleParameterList) (Tcl_Interp * interp, Tcl_Command token, Tcl_Obj ** paramListPtr); /* 581 */
  } TclStubs;
  
  #ifdef __cplusplus
***************
*** 6536,6541 ****
--- 6550,6563 ----
  #define Tcl_AppendPrintfToObj \
  	(tclStubsPtr->tcl_AppendPrintfToObj) /* 579 */
  #endif
+ #ifndef Tcl_SetEnsembleParameterList
+ #define Tcl_SetEnsembleParameterList \
+ 	(tclStubsPtr->tcl_SetEnsembleParameterList) /* 580 */
+ #endif
+ #ifndef Tcl_GetEnsembleParameterList
+ #define Tcl_GetEnsembleParameterList \
+ 	(tclStubsPtr->tcl_GetEnsembleParameterList) /* 581 */
+ #endif
  
  #endif /* defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) */
  
Index: generic/tclNamesp.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclNamesp.c,v
retrieving revision 1.161
diff -c -r1.161 tclNamesp.c
*** generic/tclNamesp.c	13 Dec 2007 15:23:19 -0000	1.161
--- generic/tclNamesp.c	25 Feb 2008 23:07:05 -0000
***************
*** 111,119 ****
--- 111,121 ----
  				 * field. */
      int flags;			/* ORed combo of TCL_ENSEMBLE_PREFIX, ENS_DEAD
  				 * and ENSEMBLE_COMPILE. */
+     int numParameters;		/* Cached number of parameters. */ 
  
      /* OBJECT FIELDS FOR ENSEMBLE CONFIGURATION */
  
+     Tcl_Obj *parameterList;	/* List of ensemble parameter names. */
      Tcl_Obj *subcommandDict;	/* Dictionary providing mapping from
  				 * subcommands to their implementing command
  				 * prefixes, or NULL if we are to build the
***************
*** 144,149 ****
--- 146,154 ----
  #define ENS_DEAD	0x1	/* Flag value to say that the ensemble is dead
  				 * and on its way out. */
  
+ 
+ 
+ 
  /*
   * Declarations for functions local to this file:
   */
***************
*** 4745,4760 ****
  	ENS_CONFIG, ENS_CREATE, ENS_EXISTS
      };
      static const char *createOptions[] = {
! 	"-command", "-map", "-prefixes", "-subcommands", "-unknown", NULL
      };
      enum EnsCreateOpts {
! 	CRT_CMD, CRT_MAP, CRT_PREFIX, CRT_SUBCMDS, CRT_UNKNOWN
      };
      static const char *configOptions[] = {
! 	"-map", "-namespace", "-prefixes", "-subcommands", "-unknown", NULL
      };
      enum EnsConfigOpts {
! 	CONF_MAP, CONF_NAMESPACE, CONF_PREFIX, CONF_SUBCMDS, CONF_UNKNOWN
      };
      int index;
  
--- 4750,4769 ----
  	ENS_CONFIG, ENS_CREATE, ENS_EXISTS
      };
      static const char *createOptions[] = {
! 	"-command", "-map", "-parameters", "-prefixes", "-subcommands", 
!         "-unknown", NULL
      };
      enum EnsCreateOpts {
! 	CRT_CMD, CRT_MAP, CRT_PARAM, CRT_PREFIX, CRT_SUBCMDS, 
!         CRT_UNKNOWN
      };
      static const char *configOptions[] = {
! 	"-map", "-namespace", "-parameters", "-prefixes", "-subcommands", 
!         "-unknown", NULL
      };
      enum EnsConfigOpts {
! 	CONF_MAP, CONF_NAMESPACE, CONF_PARAM, CONF_PREFIX, CONF_SUBCMDS, 
!         CONF_UNKNOWN
      };
      int index;
  
***************
*** 4789,4794 ****
--- 4798,4804 ----
  	Tcl_Obj *mapObj = NULL;
  	int permitPrefix = 1;
  	Tcl_Obj *unknownObj = NULL;
+ 	Tcl_Obj *paramObj = NULL;
  
  	objv += 3;
  	objc -= 3;
***************
*** 4829,4834 ****
--- 4839,4853 ----
  		}
  		subcmdObj = (len > 0 ? objv[1] : NULL);
  		continue;
+ 	    case CRT_PARAM:
+ 		if (TclListObjLength(interp, objv[1], &len) != TCL_OK) {
+ 		    if (allocatedMapFlag) {
+ 			Tcl_DecrRefCount(mapObj);
+ 		    }
+ 		    return TCL_ERROR;
+ 		}
+ 		paramObj = (len > 0 ? objv[1] : NULL);
+ 		continue;
  	    case CRT_MAP: {
  		Tcl_Obj *patchedDict = NULL, *subcmdObj;
  
***************
*** 4935,4940 ****
--- 4954,4960 ----
  	Tcl_SetEnsembleSubcommandList(interp, token, subcmdObj);
  	Tcl_SetEnsembleMappingDict(interp, token, mapObj);
  	Tcl_SetEnsembleUnknownHandler(interp, token, unknownObj);
+ 	Tcl_SetEnsembleParameterList(interp, token, paramObj);
  
  	/*
  	 * Tricky! Must ensure that the result is not shared (command delete
***************
*** 4980,4985 ****
--- 5000,5011 ----
  		    Tcl_SetObjResult(interp, resultObj);
  		}
  		break;
+ 	    case CONF_PARAM:
+ 		Tcl_GetEnsembleParameterList(NULL, token, &resultObj);
+ 		if (resultObj != NULL) {
+ 		    Tcl_SetObjResult(interp, resultObj);
+ 		}
+ 		break;
  	    case CONF_MAP:
  		Tcl_GetEnsembleMappingDict(NULL, token, &resultObj);
  		if (resultObj != NULL) {
***************
*** 5037,5042 ****
--- 5063,5075 ----
  		    Tcl_NewStringObj(((Namespace *)namespacePtr)->fullName,
  		    -1));
  
+ 	    /* -parameters option */
+ 	    Tcl_ListObjAppendElement(NULL, resultObj,
+ 		    Tcl_NewStringObj(configOptions[CONF_PARAM], -1));
+ 	    Tcl_GetEnsembleParameterList(NULL, token, &tmpObj);
+ 	    Tcl_ListObjAppendElement(NULL, resultObj,
+ 		    (tmpObj != NULL) ? tmpObj : Tcl_NewObj());
+ 
  	    /* -prefix option */
  	    Tcl_ListObjAppendElement(NULL, resultObj,
  		    Tcl_NewStringObj(configOptions[CONF_PREFIX], -1));
***************
*** 5064,5075 ****
  	    Tcl_DictSearch search;
  	    Tcl_Obj *listObj;
  	    int done, len, allocatedMapFlag = 0;
! 	    Tcl_Obj *subcmdObj = NULL, *mapObj = NULL,
  		    *unknownObj = NULL; /* Defaults, silence gcc 4 warnings */
  	    int permitPrefix, flags = 0;	/* silence gcc 4 warning */
  
  	    Tcl_GetEnsembleSubcommandList(NULL, token, &subcmdObj);
  	    Tcl_GetEnsembleMappingDict(NULL, token, &mapObj);
  	    Tcl_GetEnsembleUnknownHandler(NULL, token, &unknownObj);
  	    Tcl_GetEnsembleFlags(NULL, token, &flags);
  	    permitPrefix = (flags & TCL_ENSEMBLE_PREFIX) != 0;
--- 5097,5109 ----
  	    Tcl_DictSearch search;
  	    Tcl_Obj *listObj;
  	    int done, len, allocatedMapFlag = 0;
! 	    Tcl_Obj *subcmdObj = NULL, *mapObj = NULL, *paramObj = NULL,
  		    *unknownObj = NULL; /* Defaults, silence gcc 4 warnings */
  	    int permitPrefix, flags = 0;	/* silence gcc 4 warning */
  
  	    Tcl_GetEnsembleSubcommandList(NULL, token, &subcmdObj);
  	    Tcl_GetEnsembleMappingDict(NULL, token, &mapObj);
+ 	    Tcl_GetEnsembleParameterList(NULL, token, &paramObj);
  	    Tcl_GetEnsembleUnknownHandler(NULL, token, &unknownObj);
  	    Tcl_GetEnsembleFlags(NULL, token, &flags);
  	    permitPrefix = (flags & TCL_ENSEMBLE_PREFIX) != 0;
***************
*** 5102,5107 ****
--- 5136,5150 ----
  		    }
  		    subcmdObj = (len > 0 ? objv[1] : NULL);
  		    continue;
+ 		case CONF_PARAM:
+ 		    if (TclListObjLength(interp, objv[1], &len) != TCL_OK) {
+ 			if (allocatedMapFlag) {
+ 			    Tcl_DecrRefCount(mapObj);
+ 			}
+ 			return TCL_ERROR;
+ 		    }
+ 		    paramObj = (len > 0 ? objv[1] : NULL);
+ 		    continue;
  		case CONF_MAP: {
  		    Tcl_Obj *patchedDict = NULL, *subcmdObj;
  
***************
*** 5211,5216 ****
--- 5254,5260 ----
  		    : flags&~TCL_ENSEMBLE_PREFIX);
  	    Tcl_SetEnsembleSubcommandList(interp, token, subcmdObj);
  	    Tcl_SetEnsembleMappingDict(interp, token, mapObj);
+ 	    Tcl_SetEnsembleParameterList(interp, token, paramObj);
  	    Tcl_SetEnsembleUnknownHandler(interp, token, unknownObj);
  	    Tcl_SetEnsembleFlags(interp, token, flags);
  	    return TCL_OK;
***************
*** 5277,5282 ****
--- 5321,5328 ----
      ensemblePtr->subcmdList = NULL;
      ensemblePtr->subcommandDict = NULL;
      ensemblePtr->flags = flags;
+     ensemblePtr->numParameters = 0;
+     ensemblePtr->parameterList = NULL;
      ensemblePtr->unknownHandler = NULL;
      ensemblePtr->token = Tcl_CreateObjCommand(interp, name,
  	    NsEnsembleImplementationCmd, ensemblePtr, DeleteEnsembleConfig);
***************
*** 5378,5383 ****
--- 5424,5505 ----
  /*
   *----------------------------------------------------------------------
   *
+  * Tcl_SetEnsembleParameterList --
+  *
+  *	Set the parameter list for a particular ensemble.
+  *
+  * Results:
+  *	Tcl result code (error if command token does not indicate an ensemble
+  *	or the parameter list - if non-NULL - is not a list).
+  *
+  * Side effects:
+  *	The ensemble is updated and marked for recompilation.
+  *	((Q: Is the latter necessary?))
+  *
+  *----------------------------------------------------------------------
+  */
+ 
+ int
+ Tcl_SetEnsembleParameterList(
+     Tcl_Interp *interp,
+     Tcl_Command token,
+     Tcl_Obj *paramList)
+ {
+     Command *cmdPtr = (Command *) token;
+     EnsembleConfig *ensemblePtr;
+     Tcl_Obj *oldList;
+     int length;
+ 
+     if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
+ 	Tcl_AppendResult(interp, "command is not an ensemble", NULL);
+ 	return TCL_ERROR;
+     }
+     if (paramList == NULL) {
+         length = 0;
+     } else {
+ 	if (TclListObjLength(interp, paramList, &length) != TCL_OK) {
+ 	    return TCL_ERROR;
+ 	}
+ 	if (length < 1) {
+ 	    paramList = NULL;
+ 	}
+     }
+ 
+     ensemblePtr = cmdPtr->objClientData;
+     oldList = ensemblePtr->parameterList;
+     ensemblePtr->parameterList = paramList;
+     if (paramList != NULL) {
+ 	Tcl_IncrRefCount(paramList);
+     }
+     if (oldList != NULL) {
+ 	TclDecrRefCount(oldList);
+     }
+     ensemblePtr->numParameters = length;
+ 
+     /*
+      * Trigger an eventual recomputation of the ensemble command set. Note
+      * that this is slightly tricky, as it means that we are not actually
+      * counting the number of namespace export actions, but it is the simplest
+      * way to go!
+      */
+ 
+     ensemblePtr->nsPtr->exportLookupEpoch++;
+ 
+     /*
+      * Special hack to make compiling of [info exists] work when the
+      * dictionary is modified.
+      */
+ 
+     if (cmdPtr->compileProc != NULL) {
+ 	((Interp *)interp)->compileEpoch++;
+     }
+ 
+     return TCL_OK;
+ }
+ 
+ /*
+  *----------------------------------------------------------------------
+  *
   * Tcl_SetEnsembleMappingDict --
   *
   *	Set the mapping dictionary for a particular ensemble.
***************
*** 5650,5655 ****
--- 5772,5817 ----
  /*
   *----------------------------------------------------------------------
   *
+  * Tcl_GetEnsembleParameterList --
+  *
+  *	Get the list of parameters associated with a particular ensemble.
+  *
+  * Results:
+  *	Tcl result code (error if command token does not indicate an
+  *	ensemble). The list of parameters is returned by updating the
+  *	variable pointed to by the last parameter (NULL if there are 
+  *	no parameters).
+  *
+  * Side effects:
+  *	None
+  *
+  *----------------------------------------------------------------------
+  */
+ 
+ int
+ Tcl_GetEnsembleParameterList(
+     Tcl_Interp *interp,
+     Tcl_Command token,
+     Tcl_Obj **paramListPtr)
+ {
+     Command *cmdPtr = (Command *) token;
+     EnsembleConfig *ensemblePtr;
+ 
+     if (cmdPtr->objProc != NsEnsembleImplementationCmd) {
+ 	if (interp != NULL) {
+ 	    Tcl_AppendResult(interp, "command is not an ensemble", NULL);
+ 	}
+ 	return TCL_ERROR;
+     }
+ 
+     ensemblePtr = cmdPtr->objClientData;
+     *paramListPtr = ensemblePtr->parameterList;
+     return TCL_OK;
+ }
+ 
+ /*
+  *----------------------------------------------------------------------
+  *
   * Tcl_GetEnsembleMappingDict --
   *
   *	Get the command mapping dictionary associated with a particular
***************
*** 6015,6026 ****
      int prefixObjc;		/* Size of prefixObjv of course! */
      int reparseCount = 0;	/* Number of reparses. */
  
!     if (objc < 2) {
! 	Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?argument ...?");
  	return TCL_ERROR;
      }
  
-   restartEnsembleParse:
      if (ensemblePtr->nsPtr->flags & NS_DYING) {
  	/*
  	 * Don't know how we got here, but make things give up quickly.
--- 6177,6215 ----
      int prefixObjc;		/* Size of prefixObjv of course! */
      int reparseCount = 0;	/* Number of reparses. */
  
!   restartEnsembleParse:
!     /* 
!      * Must recheck objc, since numParameters may have changed.
!      * Cf. test namespace-53.9.
!      */
!     if (objc < 2 + ensemblePtr->numParameters) {
! 	/* 
! 	 * We don't have a subcommand argument.
! 	 * Make error message.
! 	 */
!         Tcl_DString buf;	/* Message being built */
!         Tcl_Obj **elemPtrs;     /* Parameter names */
!         int len;		/* Number of parameters to append */
!         
!         Tcl_DStringInit(&buf);
!         if (ensemblePtr->parameterList == NULL) {
!             len = 0;
!         } else if (TclListObjGetElements(NULL, ensemblePtr->parameterList, 
!                                   &len, &elemPtrs) != TCL_OK) {
!             /* This can't happen. */
!             Tcl_Panic("List of ensemble parameters is not a list");
!         }
!         for (; len>0; len--,elemPtrs++) {
!             Tcl_DStringAppend(&buf, Tcl_GetString(*elemPtrs), -1);
!             Tcl_DStringAppend(&buf, " ", -1);
!         }
!         Tcl_DStringAppend(&buf, "subcommand ?argument ...?", -1);
! 	Tcl_WrongNumArgs(interp, 1, objv, Tcl_DStringValue(&buf));
!         Tcl_DStringFree(&buf);
!         
  	return TCL_ERROR;
      }
  
      if (ensemblePtr->nsPtr->flags & NS_DYING) {
  	/*
  	 * Don't know how we got here, but make things give up quickly.
***************
*** 6046,6053 ****
  	 * part where we do the invocation of the subcommand.
  	 */
  
! 	if (objv[1]->typePtr == &tclEnsembleCmdType) {
! 	    EnsembleCmdRep *ensembleCmd = objv[1]->internalRep.otherValuePtr;
  
  	    if (ensembleCmd->nsPtr == ensemblePtr->nsPtr &&
  		    ensembleCmd->epoch == ensemblePtr->epoch &&
--- 6235,6243 ----
  	 * part where we do the invocation of the subcommand.
  	 */
  
! 	if (objv[1 + ensemblePtr->numParameters]->typePtr == &tclEnsembleCmdType) {
! 	    EnsembleCmdRep *ensembleCmd = 
!               objv[1 + ensemblePtr->numParameters]->internalRep.otherValuePtr;
  
  	    if (ensembleCmd->nsPtr == ensemblePtr->nsPtr &&
  		    ensembleCmd->epoch == ensemblePtr->epoch &&
***************
*** 6068,6074 ****
       */
  
      hPtr = Tcl_FindHashEntry(&ensemblePtr->subcommandTable,
! 	    TclGetString(objv[1]));
      if (hPtr != NULL) {
  	char *fullName = Tcl_GetHashKey(&ensemblePtr->subcommandTable, hPtr);
  
--- 6258,6264 ----
       */
  
      hPtr = Tcl_FindHashEntry(&ensemblePtr->subcommandTable,
! 	    TclGetString(objv[1 + ensemblePtr->numParameters]));
      if (hPtr != NULL) {
  	char *fullName = Tcl_GetHashKey(&ensemblePtr->subcommandTable, hPtr);
  
***************
*** 6078,6084 ****
  	 * Cache for later in the subcommand object.
  	 */
  
! 	MakeCachedEnsembleCommand(objv[1], ensemblePtr, fullName, prefixObj);
      } else if (!(ensemblePtr->flags & TCL_ENSEMBLE_PREFIX)) {
  	/*
  	 * Could not map, no prefixing, go to unknown/error handling.
--- 6268,6275 ----
  	 * Cache for later in the subcommand object.
  	 */
  
! 	MakeCachedEnsembleCommand(objv[1 + ensemblePtr->numParameters], 
!                                   ensemblePtr, fullName, prefixObj);
      } else if (!(ensemblePtr->flags & TCL_ENSEMBLE_PREFIX)) {
  	/*
  	 * Could not map, no prefixing, go to unknown/error handling.
***************
*** 6099,6106 ****
  	int stringLength, i;
  	int tableLength = ensemblePtr->subcommandTable.numEntries;
  
! 	subcmdName = TclGetString(objv[1]);
! 	stringLength = objv[1]->length;
  	for (i=0 ; i<tableLength ; i++) {
  	    register int cmp = strncmp(subcmdName,
  		    ensemblePtr->subcommandArrayPtr[i],
--- 6290,6297 ----
  	int stringLength, i;
  	int tableLength = ensemblePtr->subcommandTable.numEntries;
  
! 	subcmdName = TclGetString(objv[1 + ensemblePtr->numParameters]);
! 	stringLength = objv[1 + ensemblePtr->numParameters]->length;
  	for (i=0 ; i<tableLength ; i++) {
  	    register int cmp = strncmp(subcmdName,
  		    ensemblePtr->subcommandArrayPtr[i],
***************
*** 6146,6152 ****
  	 * Cache for later in the subcommand object.
  	 */
  
! 	MakeCachedEnsembleCommand(objv[1], ensemblePtr, fullName, prefixObj);
      }
  
      Tcl_IncrRefCount(prefixObj);
--- 6337,6344 ----
  	 * Cache for later in the subcommand object.
  	 */
  
! 	MakeCachedEnsembleCommand(objv[1 + ensemblePtr->numParameters], 
!                                   ensemblePtr, fullName, prefixObj);
      }
  
      Tcl_IncrRefCount(prefixObj);
***************
*** 6158,6164 ****
       * number of arguments to this ensemble command), populating it and then
       * feeding it back through the main command-lookup engine. In theory, we
       * could look up the command in the namespace ourselves, as we already
!      * have the namespace in which it is guaranteed to exist, but we don't do
       * that (the cacheing of the command object used should help with that.)
       */
  
--- 6350,6360 ----
       * number of arguments to this ensemble command), populating it and then
       * feeding it back through the main command-lookup engine. In theory, we
       * could look up the command in the namespace ourselves, as we already
!      * have the namespace in which it is guaranteed to exist, 
!      * 
!      *   ((Q: That's not true if the -map option is used, is it?))
!      * 
!      * but we don't do
       * that (the cacheing of the command object used should help with that.)
       */
  
***************
*** 6180,6197 ****
  	/*
  	 * Record what arguments the script sent in so that things like
  	 * Tcl_WrongNumArgs can give the correct error message.
  	 */
  
  	isRootEnsemble = (iPtr->ensembleRewrite.sourceObjs == NULL);
  	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;
--- 6376,6396 ----
  	/*
  	 * Record what arguments the script sent in so that things like
  	 * Tcl_WrongNumArgs can give the correct error message.
+ 	 * Parameters count both as inserted and removed arguments.
  	 */
  
  	isRootEnsemble = (iPtr->ensembleRewrite.sourceObjs == NULL);
  	if (isRootEnsemble) {
  	    iPtr->ensembleRewrite.sourceObjs = objv;
! 	    iPtr->ensembleRewrite.numRemovedObjs = 2 + ensemblePtr->numParameters;
! 	    iPtr->ensembleRewrite.numInsertedObjs = prefixObjc + ensemblePtr->numParameters;
  	} else {
! 	    int ni = 2 + ensemblePtr->numParameters
!                      -  iPtr->ensembleRewrite.numInsertedObjs;
! 				/* Position in objv of new front 
! 				 * of insertion relative to old one. */
! 	    if (ni > 0) {
! 		iPtr->ensembleRewrite.numRemovedObjs += ni;
  		iPtr->ensembleRewrite.numInsertedObjs += prefixObjc-1;
  	    } else {
  		iPtr->ensembleRewrite.numInsertedObjs += prefixObjc-2;
***************
*** 6206,6212 ****
  	tempObjv = (Tcl_Obj **) TclStackAlloc(interp,
  		(int) sizeof(Tcl_Obj *) * (objc - 2 + prefixObjc));
  	memcpy(tempObjv, prefixObjv, sizeof(Tcl_Obj *) * prefixObjc);
! 	memcpy(tempObjv+prefixObjc, objv+2, sizeof(Tcl_Obj *) * (objc-2));
  
  	/*
  	 * Hand off to the target command.
--- 6405,6415 ----
  	tempObjv = (Tcl_Obj **) TclStackAlloc(interp,
  		(int) sizeof(Tcl_Obj *) * (objc - 2 + prefixObjc));
  	memcpy(tempObjv, prefixObjv, sizeof(Tcl_Obj *) * prefixObjc);
! 	memcpy(tempObjv+prefixObjc, objv+1, 
!                sizeof(Tcl_Obj *) * ensemblePtr->numParameters);
! 	memcpy(tempObjv+prefixObjc+ensemblePtr->numParameters, 
!                objv+ensemblePtr->numParameters+2, 
!                sizeof(Tcl_Obj *) * (objc-ensemblePtr->numParameters-2));
  
  	/*
  	 * Hand off to the target command.
***************
*** 6334,6351 ****
  
      Tcl_ResetResult(interp);
      Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ENSEMBLE",
! 	    TclGetString(objv[1]), NULL);
      if (ensemblePtr->subcommandTable.numEntries == 0) {
! 	Tcl_AppendResult(interp, "unknown subcommand \"",TclGetString(objv[1]),
  		"\": namespace ", ensemblePtr->nsPtr->fullName,
  		" does not export any commands", NULL);
  	Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "SUBCOMMAND",
! 		TclGetString(objv[1]), NULL);
  	return TCL_ERROR;
      }
      Tcl_AppendResult(interp, "unknown ",
  	    (ensemblePtr->flags & TCL_ENSEMBLE_PREFIX ? "or ambiguous " : ""),
! 	    "subcommand \"", TclGetString(objv[1]), "\": must be ", NULL);
      if (ensemblePtr->subcommandTable.numEntries == 1) {
  	Tcl_AppendResult(interp, ensemblePtr->subcommandArrayPtr[0], NULL);
      } else {
--- 6537,6556 ----
  
      Tcl_ResetResult(interp);
      Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ENSEMBLE",
! 	    TclGetString(objv[1+ensemblePtr->numParameters]), NULL);
      if (ensemblePtr->subcommandTable.numEntries == 0) {
! 	Tcl_AppendResult(interp, "unknown subcommand \"",
!                 TclGetString(objv[1+ensemblePtr->numParameters]),
  		"\": namespace ", ensemblePtr->nsPtr->fullName,
  		" does not export any commands", NULL);
  	Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "SUBCOMMAND",
! 		TclGetString(objv[1+ensemblePtr->numParameters]), NULL);
  	return TCL_ERROR;
      }
      Tcl_AppendResult(interp, "unknown ",
  	    (ensemblePtr->flags & TCL_ENSEMBLE_PREFIX ? "or ambiguous " : ""),
! 	    "subcommand \"", TclGetString(objv[1+ensemblePtr->numParameters]), 
!             "\": must be ", NULL);
      if (ensemblePtr->subcommandTable.numEntries == 1) {
  	Tcl_AppendResult(interp, ensemblePtr->subcommandArrayPtr[0], NULL);
      } else {
***************
*** 6359,6365 ****
  		ensemblePtr->subcommandArrayPtr[i], NULL);
      }
      Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "SUBCOMMAND",
! 	    TclGetString(objv[1]), NULL);
      return TCL_ERROR;
  }
  
--- 6564,6570 ----
  		ensemblePtr->subcommandArrayPtr[i], NULL);
      }
      Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "SUBCOMMAND",
! 	    TclGetString(objv[1+ensemblePtr->numParameters]), NULL);
      return TCL_ERROR;
  }
  
***************
*** 6502,6507 ****
--- 6707,6715 ----
      if (ensemblePtr->subcmdList != NULL) {
  	Tcl_DecrRefCount(ensemblePtr->subcmdList);
      }
+     if (ensemblePtr->parameterList != NULL) {
+ 	Tcl_DecrRefCount(ensemblePtr->parameterList);
+     }
      if (ensemblePtr->subcommandDict != NULL) {
  	Tcl_DecrRefCount(ensemblePtr->subcommandDict);
      }
Index: generic/tclStubInit.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclStubInit.c,v
retrieving revision 1.150
diff -c -r1.150 tclStubInit.c
*** generic/tclStubInit.c	23 Jan 2008 17:31:42 -0000	1.150
--- generic/tclStubInit.c	25 Feb 2008 23:07:08 -0000
***************
*** 1128,1133 ****
--- 1128,1135 ----
      Tcl_AppendFormatToObj, /* 577 */
      Tcl_ObjPrintf, /* 578 */
      Tcl_AppendPrintfToObj, /* 579 */
+     Tcl_SetEnsembleParameterList, /* 580 */
+     Tcl_GetEnsembleParameterList, /* 581 */
  };
  
  /* !END!: Do not edit above this line. */
Index: tests/namespace.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/namespace.test,v
retrieving revision 1.70
diff -c -r1.70 namespace.test
*** tests/namespace.test	13 Dec 2007 15:26:06 -0000	1.70
--- tests/namespace.test	25 Feb 2008 23:07:12 -0000
***************
*** 1696,1702 ****
      }
      namespace delete ns
      set result
! } {-map {} -namespace ::ns -prefixes 1 -subcommands {} -unknown {}}
  test namespace-45.2 {ensemble: introspection} {
      namespace eval ns {
  	namespace export x
--- 1696,1702 ----
      }
      namespace delete ns
      set result
! } {-map {} -namespace ::ns -parameters {} -prefixes 1 -subcommands {} -unknown {}}
  test namespace-45.2 {ensemble: introspection} {
      namespace eval ns {
  	namespace export x
***************
*** 1910,1916 ****
      lappend result [catch {foo bar} msg] $msg [namespace ensemble config foo]
      rename foo {}
      set result
! } {{LOG ::foo bar} 1 {unknown subcommand "bar": namespace :: does not export any commands} {LOG ::foo bar} boo hoo 0 {{LOG ::foo bar} 1 {unknown subcommand "bar": namespace :: does not export any commands} {LOG ::foo bar} boo hoo} {-map {} -namespace :: -prefixes 1 -subcommands {} -unknown bar}}
  test namespace-47.6 {ensemble: unknown handler} {
      namespace ensemble create -command foo -unknown bar
      proc bar {args} {
--- 1910,1916 ----
      lappend result [catch {foo bar} msg] $msg [namespace ensemble config foo]
      rename foo {}
      set result
! } {{LOG ::foo bar} 1 {unknown subcommand "bar": namespace :: does not export any commands} {LOG ::foo bar} boo hoo 0 {{LOG ::foo bar} 1 {unknown subcommand "bar": namespace :: does not export any commands} {LOG ::foo bar} boo hoo} {-map {} -namespace :: -parameters {} -prefixes 1 -subcommands {} -unknown bar}}
  test namespace-47.6 {ensemble: unknown handler} {
      namespace ensemble create -command foo -unknown bar
      proc bar {args} {
***************
*** 1977,1983 ****
      bar z 789
      namespace delete foo
      set result
! } {{-map {} -namespace ::foo -prefixes 1 -subcommands x -unknown ::foo::u} XXX 123 ::foo::bar {y 456} YYY 456 ::foo::bar {z 789} ZZZ 789}
  test namespace-48.2 {ensembles and namespace import: exists} {
      namespace eval foo {
  	namespace ensemble create -command ::foo::bar
--- 1977,1983 ----
      bar z 789
      namespace delete foo
      set result
! } {{-map {} -namespace ::foo -parameters {} -prefixes 1 -subcommands x -unknown ::foo::u} XXX 123 ::foo::bar {y 456} YYY 456 ::foo::bar {z 789} ZZZ 789}
  test namespace-48.2 {ensembles and namespace import: exists} {
      namespace eval foo {
  	namespace ensemble create -command ::foo::bar
***************
*** 2619,2625 ****
      rename unknown.save ::unknown
      namespace eval :: [list namespace unknown $handler]
  } -result SUCCESS
!     
  # cleanup
  catch {rename cmd1 {}}
  catch {unset l}
--- 2619,2840 ----
      rename unknown.save ::unknown
      namespace eval :: [list namespace unknown $handler]
  } -result SUCCESS
! 
! # TIP xxx - ensembles with parameters
! 
! test namespace-53.1 {ensembles: parameters} {
!     namespace eval ns {
! 	namespace export x
! 	proc x {para} {list 1 $para}
! 	namespace ensemble create -parameters {para1}
!     }
!     list [info command ns] [ns bar x] [namespace delete ns] [info command ns]
! } {ns {1 bar} {} {}}
! 
! test namespace-53.2 {ensembles: parameters} -setup {
!     namespace eval ns {
! 	namespace export x
! 	proc x {para} {list 1 $para}
! 	namespace ensemble create
!     }
! } -body {
!     namespace ensemble configure ns -parameters {para1}
!     rename ns foo
!     list [info command foo] [foo bar x] [namespace delete ns] [info command foo]
! } -result {foo {1 bar} {} {}}
! 
! test namespace-53.3 {ensembles: parameters} -setup {
!     namespace eval ns {
! 	namespace export x*
! 	proc x1 {para} {list 1 $para}
! 	proc x2 {para} {list 2 $para}
! 	namespace ensemble create -parameters param1
!     }
! } -body {
!     set result [list [ns x2 x1] [ns x1 x2]]
!     lappend result [catch {ns x} msg] $msg
!     lappend result [catch {ns x x} msg] $msg
!     rename ns {}
!     lappend result [info command ns::x1]
!     namespace delete ns
!     lappend result [info command ns::x1]
! } -result\
!    {{1 x2} {2 x1}\
!     1 {wrong # args: should be "ns param1 subcommand ?argument ...?"}\
!     1 {unknown or ambiguous subcommand "x": must be x1, or x2}\
!     ::ns::x1 {}}
! 
! test namespace-53.4 {ensembles: parameters} -setup {
!     namespace eval ns {
! 	namespace export x*
! 	proc x1 {a1 a2} {list 1 $a1 $a2}
! 	proc x2 {a1 a2} {list 2 $a1 $a2}
! 	proc x3 {a1 a2} {list 3 $a1 $a2}
! 	namespace ensemble create
!     }
! } -body {
!     set result {}
!     lappend result [ns x1 x2 x3]
!     namespace ensemble configure ns -parameters p1
!     lappend result [ns x1 x2 x3]
!     namespace ensemble configure ns -parameters {p1 p2}
!     lappend result [ns x1 x2 x3]
! } -cleanup {
!     namespace delete ns
! } -result {{1 x2 x3} {2 x1 x3} {3 x1 x2}}
! 
! test namespace-53.5 {ensembles: parameters} -setup {
!     namespace eval ns {
! 	namespace export x*
! 	proc x1 {para} {list 1 $para}
! 	proc x2 {para} {list 2 $para}
! 	proc x3 {para} {list 3 $para}
! 	namespace ensemble create
!     }
! } -body {
!     set result [list [catch {ns x x1} msg] $msg]
!     lappend result [catch {ns x1 x} msg] $msg
!     namespace ensemble configure ns -parameters p1
!     lappend result [catch {ns x1 x} msg] $msg
!     lappend result [catch {ns x x1} msg] $msg
! } -cleanup {
!     namespace delete ns
! } -result\
!    {1 {unknown or ambiguous subcommand "x": must be x1, x2, or x3}\
!     0 {1 x}\
!     1 {unknown or ambiguous subcommand "x": must be x1, x2, or x3}\
!     0 {1 x}}
! 
! test namespace-53.6 {ensembles: nested} -setup {
!     namespace eval ns {
! 	namespace export x*
! 	namespace eval x0 {
! 	    proc z {args} {list 0 $args}
! 	    namespace export z
! 	    namespace ensemble create
! 	}
! 	proc x1 {args} {list 1 $args}
! 	proc x2 {args} {list 2 $args}
! 	proc x3 {args} {list 3 $args}
! 	namespace ensemble create -parameters p
!     }
! } -body {
!     list [ns z x0] [ns z x1] [ns z x2] [ns z x3]
! } -cleanup {
!     namespace delete ns
! } -result {{0 {}} {1 z} {2 z} {3 z}}
! 
! test namespace-53.7 {ensembles: parameters & wrong # args} -setup {
!     namespace eval ns {
! 	namespace export x*
! 	proc x1 {a1 a2 a3 a4} {list x1 $a1 $a2 $a3 $a4}
! 	namespace ensemble create -parameters p1
!     }
! } -body {
!     set result {}
!     lappend result [catch {ns} msg] $msg
!     lappend result [catch {ns x1} msg] $msg
!     lappend result [catch {ns x1 x1} msg] $msg
!     lappend result [catch {ns x1 x1 x1} msg] $msg
!     lappend result [catch {ns x1 x1 x1 x1} msg] $msg
!     lappend result [catch {ns x1 x1 x1 x1 x1} msg] $msg
! } -cleanup {
!     namespace delete ns
! } -result\
!    {1 {wrong # args: should be "ns p1 subcommand ?argument ...?"}\
!     1 {wrong # args: should be "ns p1 subcommand ?argument ...?"}\
!     1 {wrong # args: should be "ns x1 x1 a2 a3 a4"}\
!     1 {wrong # args: should be "ns x1 x1 a2 a3 a4"}\
!     1 {wrong # args: should be "ns x1 x1 a2 a3 a4"}\
!     0 {x1 x1 x1 x1 x1}}
! 
! test namespace-53.8 {ensemble: unknown handler changing -parameters} -setup {
!     namespace eval ns {
! 	namespace export x*
! 	proc x1 {a1} {list 1 $a1}
! 	proc Magic {ensemble subcmd args} {
! 	    namespace ensemble configure $ensemble\
!               -parameters [lrange p1 [llength [
!                 namespace ensemble configure $ensemble -parameters
!               ]] 0]
!             list
! 	}
! 	namespace ensemble create -unknown ::ns::Magic
!     }
! } -body {
!     set result {}
!     lappend result [catch {ns x1 x2} msg] $msg [namespace ensemble configure ns -parameters]
!     lappend result [catch {ns x2 x1} msg] $msg [namespace ensemble configure ns -parameters]
!     lappend result [catch {ns x2 x3} msg] $msg [namespace ensemble configure ns -parameters]
! } -cleanup {
!     namespace delete ns
! } -result\
!    {0 {1 x2} {}\
!     0 {1 x2} p1\
!     1 {unknown or ambiguous subcommand "x2": must be x1} {}}
! 
! test namespace-53.9 {ensemble: unknown handler changing -parameters,\
!   thereby eating all args} -setup {
!     namespace eval ns {
! 	namespace export x*
! 	proc x1 {args} {list 1 $args}
! 	proc Magic {ensemble subcmd args} {
! 	    namespace ensemble configure $ensemble\
!               -parameters {p1 p2 p3 p4 p5}
!             list
! 	}
! 	namespace ensemble create -unknown ::ns::Magic
!     }
! } -body {
!     set result {}
!     lappend result [catch {ns x1 x2} msg] $msg [namespace ensemble configure ns -parameters]
!     lappend result [catch {ns x2 x1} msg] $msg [namespace ensemble configure ns -parameters]
!     lappend result [catch {ns a1 a2 a3 a4 a5 x1} msg] $msg [namespace ensemble configure ns -parameters]
! } -cleanup {
!     namespace delete ns
! } -result\
!    {0 {1 x2} {}\
!     1 {wrong # args: should be "ns p1 p2 p3 p4 p5 subcommand ?argument ...?"} {p1 p2 p3 p4 p5}\
!     0 {1 {a1 a2 a3 a4 a5}} {p1 p2 p3 p4 p5}}
! 
! test namespace-53.10 {ensembles: nested rewrite} -setup {
!     namespace eval ns {
! 	namespace export x
! 	namespace eval x {
! 	    proc z0 {} {list 0}
! 	    proc z1 {a1} {list 1 $a1}
! 	    proc z2 {a1 a2} {list 2 $a1 $a2}
! 	    proc z3 {a1 a2 a3} {list 3 $a1 $a2 $a3}
! 	    namespace export z*
! 	    namespace ensemble create
! 	}
! 	namespace ensemble create -parameters p
!     }
! } -body {
!     set result {}
!     # In these cases, parsing the subensemble does not grab a new word.
!     lappend result [catch {ns z0 x} msg] $msg
!     lappend result [catch {ns z1 x} msg] $msg
!     lappend result [catch {ns z2 x} msg] $msg
!     lappend result [catch {ns z2 x v} msg] $msg
!     namespace ensemble configure ns::x -parameters q1
!     # In these cases, parsing the subensemble grabs a new word.
!     lappend result [catch {ns v x z0} msg] $msg
!     lappend result [catch {ns v x z1} msg] $msg
!     lappend result [catch {ns v x z2} msg] $msg
!     lappend result [catch {ns v x z2 v2} msg] $msg
! } -cleanup {
!     namespace delete ns
! } -result\
!    {0 0\
!     1 {wrong # args: should be "ns z1 x a1"}\
!     1 {wrong # args: should be "ns z2 x a1 a2"}\
!     1 {wrong # args: should be "ns z2 x a1 a2"}\
!     1 {wrong # args: should be "::ns::x::z0"}\
!     0 {1 v}\
!     1 {wrong # args: should be "ns v x z2 a2"}\
!     0 {2 v v2}}
! 
  # cleanup
  catch {rename cmd1 {}}
  catch {unset l}