rem: if (when) { RegisterFilterObj(itPtr, when, objv + 2); } }  if (when != 0) { return TCL_OK; } else { return TCL_ERROR; }
add: } RegisterFilterObj(itPtr, when, objc - 2, objv + 2); return TCL_OK;
context: static Ns_Callback FreeProc;static void AppendConnId(Tcl_DString *dsPtr, Ns_Conn *conn);static int RegisterFilter(NsInterp *itPtr, int when, char **argv);static int RegisterFilterObj(NsInterp *itPtr, int when, Tcl_Obj *CONST objv[]);static int GetNumArgs(Tcl_Interp *interp, Proc *procPtr);/* *---------------------------------------------------------------------- * * Ns_TclRequest -- * *	Dummy up a direct call to TclProcRequest for a connection. * * Results: *	See TclDoOp. * * Side effects: *	None.  * *---------------------------------------------------------------------- */intNs_TclRequest(Ns_Conn *conn, char *name){    Proc proc;    proc.name = name;    proc.args = NULL;    proc.nargs = 0;    return ProcRequest(&proc, conn);}/* *---------------------------------------------------------------------- * * NsTclRegisterProcCmd -- * *	Implements ns_register_proc.  * * Results: *	Tcl result.  * * Side effects: *	See docs.  * *---------------------------------------------------------------------- */intNsTclRegisterProcCmd(ClientData arg, Tcl_Interp *interp, int argc, char **argv, int adp){    int         flags, idx;    Proc       *procPtr;    NsInterp   *itPtr = arg;    char       *server, *method, *url;    if (argc < 4 || argc > 7) {badargs:	Tcl_AppendResult(interp, "wrong # of args:  should be \"",            argv[0], " ?-noinherit? method url proc ?args?\"", NULL);        return TCL_ERROR;    }    if (STREQ(argv[1], "-noinherit")) {	if (argc < 5) {	    goto badargs;	}	flags = NS_OP_NOINHERIT;	idx = 2;    } else {	if (argc == 7) {	    goto badargs;	}	flags = 0;	idx = 1;    }    server = itPtr->servPtr->server;    method = argv[idx++];    url = argv[idx++];    procPtr = NewProc(argv[idx], argv[idx+1]);    Ns_RegisterRequest(server, method, url, ProcRequest, FreeProc,	procPtr, flags);    return TCL_OK;}/* *---------------------------------------------------------------------- * * NsTclRegisterProcObjCmd -- * *	Implements ns_register_proc as obj command.  * * Results: *	Tcl result.  * * Side effects: *	See docs.  * *---------------------------------------------------------------------- */intNsTclRegisterProcObjCmd(ClientData arg, Tcl_Interp *interp, int objc, 				Tcl_Obj *CONST objv[], int adp){    int         flags, idx;    Proc       *procPtr;    NsInterp   *itPtr = arg;    char       *server, *method, *url;    if (objc < 4 || objc > 7) {badargs:        Tcl_WrongNumArgs(interp, 1, objv, "?-noinherit? method url proc ?args?");        return TCL_ERROR;    }    if (STREQ(Tcl_GetString(objv[1]), "-noinherit")) {	if (objc < 5) {	    goto badargs;	}	flags = NS_OP_NOINHERIT;	idx = 2;    } else {	if (objc == 7) {	    goto badargs;	}	flags = 0;	idx = 1;    }    server = itPtr->servPtr->server;    method = Tcl_GetString(objv[idx++]);    url = Tcl_GetString(objv[idx++]);    Ns_Log(Notice, "%d %d", idx, objc);    if (idx+1 > objc-1) {       procPtr = NewProc(Tcl_GetString(objv[idx]), "");    } else {       procPtr = NewProc(Tcl_GetString(objv[idx]), Tcl_GetString(objv[idx+1]));    }    Ns_RegisterRequest(server, method, url, ProcRequest, FreeProc,			procPtr, flags);    return TCL_OK;}/* *---------------------------------------------------------------------- * * NsTclRegisterAdpCmd -- * *	Implements ns_register_adp. * * Results: *	Tcl result.  * * Side effects: *	See docs.  * *---------------------------------------------------------------------- */intNsTclRegisterAdpCmd(ClientData arg, Tcl_Interp *interp, int argc, char **argv, int adp){    NsInterp   *itPtr = arg;    char       *server, *method, *url, *file;    if (argc != 4 && argc != 5) {badargs:	Tcl_AppendResult(interp, "wrong # of args:  should be \"",            argv[0], " ?-noinherit? method url file\"", NULL);        return TCL_ERROR;    }    if (argc == 5 && !STREQ(argv[1], "-noinherit")) {	goto badargs;    }    server = itPtr->servPtr->server;    method = argv[argc-3];    url = argv[argc-2];    file = ns_strdup(argv[argc-1]);    Ns_RegisterRequest(server, method, url, AdpRequest, ns_free,	file, argc == 5 ? NS_OP_NOINHERIT : 0);    return TCL_OK;}/* *---------------------------------------------------------------------- * * NsTclRegisterAdpObjCmd -- * *	Implements ns_register_adp as obj command. * * Results: *	Tcl result.  * * Side effects: *	See docs.  * *---------------------------------------------------------------------- */intNsTclRegisterAdpObjCmd(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]){    NsInterp   *itPtr = arg;    char       *server, *method, *url, *file;    if (objc != 4 && objc != 5) {badargs:        Tcl_WrongNumArgs(interp, 1, objv, "?-noinherit? method url file");        return TCL_ERROR;    }    if (objc == 5 && !STREQ(Tcl_GetString(objv[1]), "-noinherit")) {	goto badargs;    }    server = itPtr->servPtr->server;    method = Tcl_GetString(objv[objc-3]);    url = Tcl_GetString(objv[objc-2]);    file = ns_strdup(Tcl_GetString(objv[objc-1]));    Ns_RegisterRequest(server, method, url, AdpRequest, ns_free,			file, objc == 5 ? NS_OP_NOINHERIT : 0);    return TCL_OK;}/* *---------------------------------------------------------------------- * * NsTclUnRegisterCmd -- * *	Implements ns_unregister_proc and ns_unregister_adp commands. * * Results: *	Tcl result.  * * Side effects: *	See docs.  * *---------------------------------------------------------------------- */intNsTclUnRegisterCmd(ClientData arg, Tcl_Interp *interp, int argc,		    char **argv){    NsInterp *itPtr = arg;    char *server = itPtr->servPtr->server;        if (argc != 3 && argc != 4) {        Tcl_AppendResult(interp, "wrong # of args:  should be \"",                         argv[0], " ?-noinherit? method url\"", NULL);        return TCL_ERROR;    }    if (argc == 4 && !STREQ(argv[1], "-noinherit")) {	Tcl_AppendResult(interp, "unknown flag \"", argv[1],	    "\": should be -noinherit", NULL);	return TCL_ERROR;    }    Ns_UnRegisterRequest(server, argv[argc-2], argv[argc-1], argc == 3 ? 1 : 0);    return TCL_OK;}/* *---------------------------------------------------------------------- * * NsTclUnRegisterObjCmd -- * *	Implements ns_unregister_proc and ns_unregister_adp commands. * * Results: *	Tcl result.  * * Side effects: *	See docs.  * *---------------------------------------------------------------------- */intNsTclUnRegisterObjCmd(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]){    NsInterp *itPtr = arg;    char *server = itPtr->servPtr->server;        if (objc != 3 && objc != 4) {        Tcl_WrongNumArgs(interp, 1, objv, "?-noinherit? method url");        return TCL_ERROR;    }    if (objc == 4 && !STREQ(Tcl_GetString(objv[1]), "-noinherit")) {	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "unknown flag \"", 		Tcl_GetString(objv[1]),		"\": should be -noinherit", NULL);	return TCL_ERROR;    }    Ns_UnRegisterRequest(server, Tcl_GetString(objv[objc-2]), Tcl_GetString(objv[objc-1]), 			objc == 3 ? 1 : 0);    return TCL_OK;}/* *---------------------------------------------------------------------- * * NsTclRegisterFilter -- * *	Implements ns_register_filter.  * * Results: *	Tcl result.  * * Side effects: *	See docs.  * *---------------------------------------------------------------------- */intNsTclRegisterFilterCmd(ClientData arg, Tcl_Interp *interp, int argc, char **argv){    NsInterp *itPtr = arg;    int    largc;    char **largv;    int    when, i;    if (argc != 5 && argc != 6) {        Tcl_AppendResult(interp, "wrong # args: should be \"",            argv[0], " when method urlPattern script ?arg?\"", NULL);        return TCL_ERROR;    }    if (Tcl_SplitList(interp, argv[1], &largc, &largv) != TCL_OK) {        return TCL_ERROR;    }    when = 0;    if (largc == 0) {	Tcl_AppendResult(interp, "blank filter when specification", NULL);    } else {        for (i = 0; i < largc; ++i) {            if (STREQ(largv[i], "preauth")) {                when |= NS_FILTER_PRE_AUTH;            } else if (STREQ(largv[i], "postauth")) {                when |= NS_FILTER_POST_AUTH;            } else if (STREQ(largv[i], "trace")) {                when |= NS_FILTER_TRACE;            } else {                Tcl_AppendResult(interp, "unknown when \"", largv[i],                    "\": should be preauth, postauth, or trace", NULL);                when = 0;                break;            }        }        if (when) {            RegisterFilter(itPtr, when, argv + 2);        }    }    ckfree((char *) largv);    if (when != 0) {	return TCL_OK;    } else {	return TCL_ERROR;    }}/* *---------------------------------------------------------------------- * * NsTclRegisterFilterObjCmd -- * *	Implements ns_register_filter.  * * Results: *	Tcl result.  * * Side effects: *	See docs.  * *---------------------------------------------------------------------- */intNsTclRegisterFilterObjCmd(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]){    NsInterp *itPtr = arg;    int       lobjc;    Tcl_Obj **lobjv;    int       when, i;    if (objc != 5 && objc != 6) {        Tcl_WrongNumArgs(interp, 1, objv, "when method urlPattern script ?arg?");        return TCL_ERROR;    }	if (Tcl_ListObjGetElements(interp, objv[1], &lobjc, &lobjv) != TCL_OK) {	return TCL_ERROR;    }    when = 0;    if (lobjc == 0) {	Tcl_SetResult(interp, "blank filter when specification", TCL_STATIC);    } else {        for (i = 0; i < lobjc; ++i) {            if (STREQ(Tcl_GetString(lobjv[i]), "preauth")) {                when |= NS_FILTER_PRE_AUTH;            } else if (STREQ(Tcl_GetString(lobjv[i]), "postauth")) {                when |= NS_FILTER_POST_AUTH;            } else if (STREQ(Tcl_GetString(lobjv[i]), "trace")) {                when |= NS_FILTER_TRACE;            } else {		Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "unknown when \"", 			Tcl_GetString(lobjv[i]),			"\": should be preauth, postauth, or trace", NULL);                when = 0;                break;            }        }        if (when) {            RegisterFilterObj(itPtr, when, objv + 2);        }    }    if (when != 0) {	return TCL_OK;    } else {	return TCL_ERROR;    }}/* *---------------------------------------------------------------------- * * NsTclRegisterTraceCmd -- * *	Implements ns_register_trace  * * Results: *	Tcl result.  * * Side effects: *	See docs.  * *---------------------------------------------------------------------- */intNsTclRegisterTraceCmd(ClientData arg, Tcl_Interp *interp, int argc, char **argv){    NsInterp *itPtr = arg;    if (argc != 4 && argc != 5) {        Tcl_AppendResult(interp, "wrong # args: should be \"",            argv[0], " method urlPattern script ?arg?\"", NULL);        return TCL_ERROR;    }    return RegisterFilter(itPtr, NS_FILTER_VOID_TRACE, argv + 1);}/* *---------------------------------------------------------------------- * * NsTclRegisterTraceObjCmd -- * *	Implements ns_register_trace as obj command. * * Results: *	Tcl result.  * * Side effects: *	See docs.  * *---------------------------------------------------------------------- */intNsTclRegisterTraceObjCmd(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]){    NsInterp *itPtr = arg;    if (objc != 4 && objc != 5) {        Tcl_WrongNumArgs(interp, 1, objv, "method urlPattern script ?arg?");        return TCL_ERROR;    }    return RegisterFilterObj(itPtr, NS_FILTER_VOID_TRACE, objv + 1);}/* *---------------------------------------------------------------------- * * AdpRequest -- * *	Ns_OpProc for registered ADP's. * * Results: *	See Ns_AdpRequest. * * Side effects: *	None.  * *---------------------------------------------------------------------- */static intAdpRequest(void *arg, Ns_Conn *conn){    return Ns_AdpRequest(conn, (char *) arg);}/* *---------------------------------------------------------------------- * * RequstProc -- * *	Ns_OpProc for Tcl operations. Enters the header and form  *	connection sets, sets the current connection, concats the Tcl  *	command and args strings from the arg and evaluates the  *	resulting string.  * * Results: *	NS_OK or NS_ERROR.  * * Side effects: *	None.  * *---------------------------------------------------------------------- */static intProcRequest(void *arg, Ns_Conn *conn){    Proc	*procPtr = arg;    Tcl_Interp  *interp;    int     	 cnt;    Tcl_DString  cmd;    int          retval;    retval = NS_OK;    Tcl_DStringInit(&cmd);    Tcl_DStringAppendElement(&cmd, procPtr->name);    interp = Ns_GetConnInterp(conn);    /*     * Build the procedure arguments.  Now that we don't require the     * connId parameter, there are three cases to consider:     *   - no args -> don't add anything after the command name     *   - one arg -> just add the context (the arg specified at register time)     *   - two+ args-> (backward compatibility), the connId and the context     */    cnt = GetNumArgs(interp, procPtr);    if (cnt != 0) {	if (cnt > 1) {	    AppendConnId(&cmd, conn);	}	Tcl_DStringAppendElement(&cmd, procPtr->args ? procPtr->args : "");    }    if (Tcl_GlobalEval(interp, cmd.string) != TCL_OK) {        Ns_TclLogError(interp);        if (Ns_ConnResetReturn(conn) == NS_OK) {            retval = Ns_ConnReturnInternalError(conn);        }    }    Tcl_DStringFree(&cmd);    return retval;}/* *---------------------------------------------------------------------- * * ProcFilter -- * *	The callback for Tcl filters. Run the script.  * * Results: *	NS_OK, NS_FILTER_RETURN, or NS_FILTER_BREAK. * * Side effects: *	None.  * *---------------------------------------------------------------------- */static intProcFilter(void *arg, Ns_Conn *conn, int why){    Proc	        *procPtr = arg;    Tcl_DString          cmd;    Tcl_Interp          *interp;    int                  status;    int                  cnt;    const char		*result;    Tcl_DStringInit(&cmd);    /*     * Start building the command with the proc name     */        Tcl_DStringAppendElement(&cmd, procPtr->name);    interp = Ns_GetConnInterp(conn);    /*     * Now add the optional filter arg...     */        cnt = GetNumArgs(interp, procPtr);    if (cnt > 1) {	if (cnt > 2) {	    AppendConnId(&cmd, conn);	}	Tcl_DStringAppendElement(&cmd, procPtr->args ? procPtr->args : "");    }    /*     * Append the 'why'     */        switch (why) {	case NS_FILTER_PRE_AUTH:	    Tcl_DStringAppendElement(&cmd, "preauth");	    break;	case NS_FILTER_POST_AUTH:	    Tcl_DStringAppendElement(&cmd, "postauth");	    break;	case NS_FILTER_TRACE:	    Tcl_DStringAppendElement(&cmd, "trace");	    break;    }    /*     * Run the script.     */        Tcl_AllowExceptions(interp);    status = Tcl_GlobalEval(interp, cmd.string);    if (status != TCL_OK) {	Ns_TclLogError(interp);    }    /*     * Determine the filter result code.     */    result = Tcl_GetStringResult(interp);    if (why == NS_FILTER_VOID_TRACE) {	status = NS_OK;    } else if (status != TCL_OK) {	status = NS_ERROR;    } else if (STREQ(result, "filter_ok")) {	status = NS_OK;    } else if (STREQ(result, "filter_break")) {	status = NS_FILTER_BREAK;    } else if (STREQ(result, "filter_return")) {	status = NS_FILTER_RETURN;    } else {	Ns_Log(Warning, "tclfilter: %s return invalid result: %s",	    procPtr->name, result);	status = NS_ERROR;    }    Tcl_DStringFree(&cmd);    return status;}/* *---------------------------------------------------------------------- * * GetNumArgs -- * *	Get the number of arguments for a given callback, invoked *	the first time the callback is used. * * Results: *	Number of args or -1 on error. * * Side effects: *	Will invoke script to determine arg count. * *---------------------------------------------------------------------- */static intGetNumArgs(Tcl_Interp *interp, Proc *procPtr){    Tcl_Obj *objPtr;    Tcl_DString ds;    if (procPtr->nargs == ARGS_UNKNOWN) {    	Tcl_DStringInit(&ds);    	Tcl_DStringAppend(&ds, "llength [info args ", -1);    	Tcl_DStringAppendElement(&ds, procPtr->name);    	Tcl_DStringAppend(&ds, "]", 1);	if (Tcl_Eval(interp, ds.string) != TCL_OK) {	    procPtr->nargs = ARGS_FAILED;	} else {	    objPtr = Tcl_GetObjResult(interp);	    if (Tcl_GetIntFromObj(interp, objPtr, &procPtr->nargs) != TCL_OK) {	    	procPtr->nargs = ARGS_FAILED;	    }	}	Tcl_DStringFree(&ds);    }    return procPtr->nargs;}/* *---------------------------------------------------------------------- * * RegisterFilter -- * *	Register a Tcl filter.  * * Results: *	TCL_OK.  * * Side effects: *	Will allocate memory for TclContext as well as strdup all the  *	arguments.  * *---------------------------------------------------------------------- */static intRegisterFilter(NsInterp *itPtr, int when, char **argv){    Proc	    *procPtr;    char	    *server, *method, *url;    server = itPtr->servPtr->server;    method = argv[0];    url = argv[1];    procPtr = NewProc(argv[2], argv[3]);    Ns_RegisterFilter(server, method, url, ProcFilter, when, procPtr);    return TCL_OK;}/* *---------------------------------------------------------------------- * * RegisterFilterObj -- * *	Register a Tcl filter.  * * Results: *	TCL_OK.  * * Side effects: *	Will allocate memory for TclContext as well as strdup all the  *	arguments.  * *---------------------------------------------------------------------- */static intRegisterFilterObj(NsInterp *itPtr, int when, Tcl_Obj *CONST objv[]){    Proc	    *procPtr;    char	    *server, *method, *url;    server = itPtr->servPtr->server;    method = Tcl_GetString(objv[0]);    url = Tcl_GetString(objv[1]);    procPtr = NewProc(Tcl_GetString(objv[2]), Tcl_GetString(objv[3]));    Ns_RegisterFilter(server, method, url, ProcFilter, when, procPtr);    return TCL_OK;}/* *---------------------------------------------------------------------- * * AppendConnId -- * *	Append the tcl conn handle to a dstring.  * * Results: *	None.  * * Side effects: *	Appends to the dstring.  * *---------------------------------------------------------------------- */static voidAppendConnId(Tcl_DString *dsPtr, Ns_Conn *conn){    Conn *connPtr = (Conn *) conn;    Tcl_DStringAppendElement(dsPtr, connPtr->idstr);}/* *---------------------------------------------------------------------- * * NewProc, FreeProc -- * *	Create or delete a Proc structure. * * Results: *	For NewProc, pointer to new Proc. * * Side effects: *	None.  * *---------------------------------------------------------------------- */static Proc *NewProc(char *name, char *args){    Proc *procPtr;    procPtr = ns_malloc(sizeof(Proc));    procPtr->name = ns_strdup(name);    procPtr->args = ns_strcopy(args);    procPtr->nargs = ARGS_UNKNOWN;    return procPtr;}static voidFreeProc(void *arg){    Proc *procPtr = arg;        ns_free(procPtr->name);    if (procPtr->args != NULL) {	ns_free(procPtr->args);    }    ns_free(procPtr);}