rem: Tcl_WrongNumArgs(interp, 2, objv, "queue id");
add: Tcl_WrongNumArgs(interp, 2, objv, "queue");
context: NsTclJobObjCmd(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj **objv){    NsInterp *itPtr = arg;    Queue *queuePtr;    Job *jobPtr = NULL, **nextPtrPtr;    int code, new, create = 0, running = 0, max;    char *id = NULL, buf[20], *queue;    Tcl_HashEntry *hPtr;    Tcl_HashSearch search;    static CONST char *opts[] = {        "cancel", "create", "jobs", "queue", "queues", "wait", NULL    };    enum {        JCancelIdx, JCreateIdx, JJobsIdx, JQueueIdx, JQueuesIdx, JWaitIdx     } opt;    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;    }    code = TCL_OK;    switch (opt) {    case JCreateIdx:	if (objc != 3 && objc != 4) {	    Tcl_WrongNumArgs(interp, 2, objv, "queue ?maxthreads?");	    return TCL_ERROR;	}	max = 4;	if (objc == 4 && Tcl_GetIntFromObj(interp, objv[3], &max) != TCL_OK) {	    return TCL_ERROR;	}	queue = Tcl_GetString(objv[2]);	Ns_MutexLock(&queuelock);	hPtr = Tcl_CreateHashEntry(&queues, queue, &new);	if (new) {	    queuePtr = ns_calloc(1, sizeof(Queue));	    queuePtr->name = Tcl_GetHashKey(&queues, hPtr);	    queuePtr->maxthreads = max;	    Ns_MutexSetName2(&queuePtr->lock, "tcljob", queue);	    Tcl_InitHashTable(&queuePtr->jobs, TCL_STRING_KEYS);	    Tcl_SetHashValue(hPtr, queuePtr);	}	Ns_MutexUnlock(&queuelock);	if (!new) {	    Tcl_AppendResult(interp, "queue already exists: ", queue, NULL);	    return TCL_ERROR;	}	SetQueueInternalRep(objv[2], queuePtr);	Tcl_SetObjResult(interp, objv[2]);	break;    case JQueueIdx:	if (objc != 4) {	    Tcl_WrongNumArgs(interp, 2, objv, "queue script");	    return TCL_ERROR;	}	if (GetQueueFromObj(interp, objv[2], &queuePtr) != TCL_OK) {	    return TCL_ERROR;	}	jobPtr = ns_malloc(sizeof(Job));	jobPtr->flags = jobPtr->code = 0;	jobPtr->server = (itPtr->servPtr ? itPtr->servPtr->server : NULL);	jobPtr->nextPtr = NULL;	jobPtr->errorCode = jobPtr->errorInfo = NULL;	Tcl_DStringInit(&jobPtr->ds);	Tcl_DStringAppend(&jobPtr->ds, Tcl_GetString(objv[3]), -1);	Ns_MutexLock(&queuePtr->lock);	if (!queuePtr->stopping) {	    nextPtrPtr = &queuePtr->firstPtr;	    while (*nextPtrPtr != NULL) {		nextPtrPtr = &((*nextPtrPtr)->nextPtr);	    }	    *nextPtrPtr = jobPtr;	    if (queuePtr->nidle == 0 && queuePtr->nthreads < queuePtr->maxthreads) {		create = 1;		++queuePtr->nthreads;	    } else {		create = 0;	    }	    id = buf;	    do {		sprintf(id, "job%d", queuePtr->nextid++);		hPtr = Tcl_CreateHashEntry(&queuePtr->jobs, id, &new);	    } while (!new);	    Tcl_SetHashValue(hPtr, jobPtr);	    Ns_CondBroadcast(&queuePtr->cond);	    jobPtr = NULL;	}	Ns_MutexUnlock(&queuePtr->lock);	if (jobPtr != NULL) {	    FreeJob(jobPtr);	    Tcl_SetResult(interp, "server stopping", TCL_STATIC);	    return TCL_ERROR;	}	if (create) {	    Ns_ThreadCreate(JobThread, queuePtr, 0, NULL);	}	Tcl_SetResult(interp, id, TCL_VOLATILE);	break;    case JWaitIdx:    case JCancelIdx:	if (objc != 4) {	    Tcl_WrongNumArgs(interp, 2, objv, "queue id");	    return TCL_ERROR;	}	if (GetQueueFromObj(interp, objv[2], &queuePtr) != TCL_OK) {	    return TCL_ERROR;	}	id = Tcl_GetString(objv[3]);	Ns_MutexLock(&queuePtr->lock);	hPtr = Tcl_FindHashEntry(&queuePtr->jobs, id);	if (hPtr != NULL) {	    jobPtr = Tcl_GetHashValue(hPtr);	    Tcl_DeleteHashEntry(hPtr);	    if (opt == JCancelIdx) {		jobPtr->flags |= JOB_CANCEL;		running = jobPtr->flags & JOB_RUNNING;	    } else {		while (!(jobPtr->flags & JOB_DONE)) {		    Ns_CondWait(&queuePtr->cond, &queuePtr->lock);		}	    }	}	Ns_MutexUnlock(&queuePtr->lock);	if (hPtr == NULL) {	    Tcl_AppendResult(interp, "no such job: ", id, NULL);	    return TCL_ERROR;	}	if (opt == JCancelIdx) {	    Tcl_SetBooleanObj(Tcl_GetObjResult(interp), running);	} else {	    Tcl_DStringResult(interp, &jobPtr->ds);	    if (jobPtr->errorCode != NULL) {		Tcl_SetVar(interp, "errorCode", jobPtr->errorCode, TCL_GLOBAL_ONLY);	    }	    if (jobPtr->errorInfo != NULL) {	 	Tcl_SetVar(interp, "errorInfo", jobPtr->errorInfo, TCL_GLOBAL_ONLY);	    }	    code = jobPtr->code;	    FreeJob(jobPtr);	}	break;    case JJobsIdx:	if (objc != 3) {	    Tcl_WrongNumArgs(interp, 2, objv, "queue id");	    return TCL_ERROR;	}	if (GetQueueFromObj(interp, objv[2], &queuePtr) != TCL_OK) {	    return TCL_ERROR;	}	Ns_MutexLock(&queuePtr->lock);	hPtr = Tcl_FirstHashEntry(&queuePtr->jobs, &search);	while (hPtr != NULL) {	    jobPtr = Tcl_GetHashValue(hPtr);	    AppendJob(interp, jobPtr);	    hPtr = Tcl_NextHashEntry(&search);	}	Ns_MutexUnlock(&queuePtr->lock);	break;    case JQueuesIdx:        hPtr = Tcl_FirstHashEntry(&queues, &search);        while (hPtr != NULL) {            queuePtr = Tcl_GetHashValue(hPtr);            Tcl_AppendElement(interp, queuePtr->name);            hPtr = Tcl_NextHashEntry(&search);        }        break;     }        return code;}