rem: IOnDeleteIdx, ITraceIdx, IGetInterpIdx, IInterpsIdx, ICancelIdx
add: IOnDeleteIdx, ITraceIdx, IThreadsIdx, ICancelIdx
context: NsTclICtlObjCmd(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj **objv){    NsInterp *itPtr = arg;    NsInterp *citPtr;    NsServer *servPtr = itPtr->servPtr;    Defer    *deferPtr;    ScriptTrace *stPtr;    Tcl_HashEntry *hPtr;    Tcl_HashSearch search;    int	      when, length, result;    char     *script, *iname, *pattern;    static CONST char *opts[] = {	"addmodule", "cleanup", "epoch", "get", "getmodules", "save",	"update", "oncreate", "oncleanup", "oninit", "ondelete", "trace",	"getinterp", "interps", "cancel",	NULL    };    enum {	IAddModuleIdx, ICleanupIdx, IEpochIdx, IGetIdx, IGetModulesIdx,	ISaveIdx, IUpdateIdx, IOnCreateIdx, IOnCleanupIdx, IOnInitIdx,        IOnDeleteIdx, ITraceIdx, IGetInterpIdx, IInterpsIdx, ICancelIdx    } opt;    static CONST char *topts[] = {	"create", "delete", "allocate", "deallocate", "getconn", "freeconn",	NULL    };    enum {	TCreateIdx, TDeleteIdx, TAllocateIdx, TDeAllocateIdx,	TGetConnIdx, TFreeConnIdx    } topt;    static int twhen[] = {	NS_TCL_TRACE_CREATE, NS_TCL_TRACE_DELETE,	NS_TCL_TRACE_ALLOCATE, NS_TCL_TRACE_DEALLOCATE,	NS_TCL_TRACE_GETCONN, NS_TCL_TRACE_FREECONN    };    if (objc < 2) {        Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?");	return TCL_ERROR;    }    if (Tcl_GetIndexFromObj(interp, objv[1], opts, "option", 0,			    (int *) &opt) != TCL_OK) {	return TCL_ERROR;    }    result = TCL_OK;    switch (opt) {    case IAddModuleIdx:	/*	 * Add a Tcl module to the list of for later initialization.	 */	if (objc != 3) {            Tcl_WrongNumArgs(interp, 2, objv, "module");	    return TCL_ERROR;	}	if (Tcl_ListObjAppendElement(interp, servPtr->tcl.modules,				     objv[2]) != TCL_OK) {	    return TCL_ERROR;	}	Tcl_SetObjResult(interp, servPtr->tcl.modules);	break;    case IGetModulesIdx:	/*	 * Get the list of modules for initialization.  See init.tcl	 * for expected use.	 */	if (objc != 2) {            Tcl_WrongNumArgs(interp, 2, objv, NULL);	    return TCL_ERROR;	}	Tcl_SetObjResult(interp, servPtr->tcl.modules);	break;    case IGetIdx:	/*	 * Get the current init script to evaluate in new interps.	 */	if (objc != 2) {            Tcl_WrongNumArgs(interp, 2, objv, NULL);	    return TCL_ERROR;	}	Ns_RWLockRdLock(&servPtr->tcl.lock);	Tcl_SetResult(interp, servPtr->tcl.script, TCL_VOLATILE);	Ns_RWLockUnlock(&servPtr->tcl.lock);	break;    case IEpochIdx:	/*	 * Check the version of this interp against current init script.	 */	if (objc != 2) {            Tcl_WrongNumArgs(interp, 2, objv, NULL);	    return TCL_ERROR;	}	Ns_RWLockRdLock(&servPtr->tcl.lock);	Tcl_SetIntObj(Tcl_GetObjResult(interp), servPtr->tcl.epoch);	Ns_RWLockUnlock(&servPtr->tcl.lock);	break;       case ISaveIdx:	/*	 * Save the init script.	 */	if (objc != 3) {            Tcl_WrongNumArgs(interp, 2, objv, "script");	    return TCL_ERROR;    	}	script = ns_strdup(Tcl_GetStringFromObj(objv[2], &length));	Ns_RWLockWrLock(&servPtr->tcl.lock);	ns_free(servPtr->tcl.script);	servPtr->tcl.script = script;	servPtr->tcl.length = length;	if (++servPtr->tcl.epoch == 0) {	    /* NB: Epoch zero reserved for new interps. */	    ++servPtr->tcl.epoch;	}	Ns_RWLockUnlock(&servPtr->tcl.lock);	break;    case IUpdateIdx:	/*	 * Check for and process possible change in the init script.	 */	if (objc != 2) {            Tcl_WrongNumArgs(interp, 2, objv, NULL);	    return TCL_ERROR;	}	result = UpdateInterp(itPtr);	break;    case ICleanupIdx:	/*	 * Invoke the legacy defer callbacks.	 */	if (objc != 2) {            Tcl_WrongNumArgs(interp, 2, objv, NULL);	    return TCL_ERROR;	}    	while ((deferPtr = itPtr->firstDeferPtr) != NULL) {	    itPtr->firstDeferPtr = deferPtr->nextPtr;	    (*deferPtr->proc)(interp, deferPtr->arg);	    ns_free(deferPtr);	}	break;    case IOnInitIdx:    case IOnCreateIdx:    case IOnCleanupIdx:    case IOnDeleteIdx:	/*	 * Register script-level interp traces.	 */        if (objc != 3) {            Tcl_WrongNumArgs(interp, 2, objv, "script");	    return TCL_ERROR;        }	switch (opt) {	case IOnInitIdx:	case IOnCreateIdx:	    when = NS_TCL_TRACE_CREATE;	    break;	case IOnCleanupIdx:	    when = NS_TCL_TRACE_DEALLOCATE;	    break;	case IOnDeleteIdx:	    when = NS_TCL_TRACE_DELETE;	    break;	default:	    /* NB: Silence compiler. */	    break;	}	goto trace;	break;    case ITraceIdx:        if (objc != 4) {            Tcl_WrongNumArgs(interp, 2, objv, "when script");	    return TCL_ERROR;        }    	if (Tcl_GetIndexFromObj(interp, objv[2], topts, "when", 0,			    (int *) &topt) != TCL_OK) {	    return TCL_ERROR;    	}	when = twhen[topt];    trace:	if (servPtr != NsGetInitServer()) {	    Tcl_AppendResult(interp, "attempt to call ", opts[opt],		" after startup", NULL);	    return TCL_ERROR;	}	script = Tcl_GetString(objv[objc-1]);	length = strlen(script);	stPtr = ns_malloc(sizeof(ScriptTrace) + length);	stPtr->length = length;	strcpy(stPtr->script,  script);	(void) Ns_TclRegisterTrace(servPtr->server, EvalTrace, stPtr, when);	break;    case IGetInterpIdx:	Tcl_SetResult(interp, itPtr->name, TCL_STATIC);	break;    case IInterpsIdx:        if (objc != 2 && objc != 3) {            Tcl_WrongNumArgs(interp, 2, objv, "?pattern?");	    return TCL_ERROR;        }	if (objc == 2) {	    pattern = NULL;	} else {	    pattern = Tcl_GetString(objv[2]);	}	Ns_MutexLock(&ilock);	hPtr = Tcl_FirstHashEntry(&interps, &search);	while (hPtr != NULL) {	    iname = Tcl_GetHashKey(&interps, hPtr);	    if (pattern == NULL || Tcl_StringMatch(iname, pattern)) {	    	Tcl_AppendElement(interp, iname);	    }	    hPtr = Tcl_NextHashEntry(&search);	}	Ns_MutexUnlock(&ilock);	break;    case ICancelIdx:	if (objc != 3) {            Tcl_WrongNumArgs(interp, 2, objv, "interp");	    return TCL_ERROR;        }	iname = Tcl_GetString(objv[2]);	Ns_MutexLock(&ilock);	hPtr = Tcl_FindHashEntry(&interps, iname);	if (hPtr != NULL) {	    citPtr = Tcl_GetHashValue(hPtr);	    Tcl_AsyncMark(citPtr->cancel);	}	Ns_MutexUnlock(&ilock);	if (hPtr == NULL) {	    Tcl_AppendResult(interp, "no such interp: ", iname, NULL);	    return TCL_ERROR;	}	break;    }    return result;}