tclio.c

来自「tcl是工具命令语言」· C语言 代码 · 共 2,110 行 · 第 1/5 页

C
2,110
字号
    ClientData	     instanceData; /* Instance specific data for the new				    * channel. */    int		     mask;	   /* TCL_READABLE & TCL_WRITABLE to indicate				    * if the channel is readable, writable. */    Tcl_Channel	     prevChan;	   /* The channel structure to replace */{    ThreadSpecificData	*tsdPtr = TCL_TSD_INIT(&dataKey);    Channel		*chanPtr, *prevChanPtr;    ChannelState	*statePtr;    /*     * Find the given channel in the list of all channels.     * If we don't find it, then it was never registered correctly.     *     * This operation should occur at the top of a channel stack.     */    statePtr    = (ChannelState *) tsdPtr->firstCSPtr;    prevChanPtr = ((Channel *) prevChan)->state->topChanPtr;    while (statePtr->topChanPtr != prevChanPtr) {	statePtr = statePtr->nextCSPtr;    }    if (statePtr == NULL) {	Tcl_AppendResult(interp, "couldn't find state for channel \"",		Tcl_GetChannelName(prevChan), "\"", (char *) NULL);        return (Tcl_Channel) NULL;    }    /*     * Here we check if the given "mask" matches the "flags"     * of the already existing channel.     *     *	  | - | R | W | RW |     *	--+---+---+---+----+	<=>  0 != (chan->mask & prevChan->mask)     *	- |   |   |   |    |     *	R |   | + |   | +  |	The superceding channel is allowed to     *	W |   |   | + | +  |	restrict the capabilities of the     *	RW|   | + | + | +  |	superceded one !     *	--+---+---+---+----+     */    if ((mask & (statePtr->flags & (TCL_READABLE | TCL_WRITABLE))) == 0) {	Tcl_AppendResult(interp,		"reading and writing both disallowed for channel \"",		Tcl_GetChannelName(prevChan), "\"", (char *) NULL);        return (Tcl_Channel) NULL;    }    /*     * Flush the buffers. This ensures that any data still in them     * at this time is not handled by the new transformation. Restrict     * this to writable channels. Take care to hide a possible bg-copy     * in progress from Tcl_Flush and the CheckForChannelErrors inside.     */    if ((mask & TCL_WRITABLE) != 0) {        CopyState *csPtr;        csPtr           = statePtr->csPtr;	statePtr->csPtr = (CopyState*) NULL;	if (Tcl_Flush((Tcl_Channel) prevChanPtr) != TCL_OK) {	    statePtr->csPtr = csPtr;	    Tcl_AppendResult(interp, "could not flush channel \"",		    Tcl_GetChannelName(prevChan), "\"", (char *) NULL);	    return (Tcl_Channel) NULL;	}	statePtr->csPtr = csPtr;    }    /*     * Discard any input in the buffers. They are not yet read by the     * user of the channel, so they have to go through the new     * transformation before reading. As the buffers contain the     * untransformed form their contents are not only useless but actually     * distorts our view of the system.     *     * To preserve the information without having to read them again and     * to avoid problems with the location in the channel (seeking might     * be impossible) we move the buffers from the common state structure     * into the channel itself. We use the buffers in the channel below     * the new transformation to hold the data. In the future this allows     * us to write transformations which pre-read data and push the unused     * part back when they are going away.     */    if (((mask & TCL_READABLE) != 0) &&	(statePtr->inQueueHead != (ChannelBuffer*) NULL)) {      /*       * Remark: It is possible that the channel buffers contain data from       * some earlier push-backs.       */      statePtr->inQueueTail->nextPtr = prevChanPtr->inQueueHead;      prevChanPtr->inQueueHead       = statePtr->inQueueHead;      if (prevChanPtr->inQueueTail == (ChannelBuffer*) NULL) {	prevChanPtr->inQueueTail = statePtr->inQueueTail;      }      statePtr->inQueueHead          = (ChannelBuffer*) NULL;      statePtr->inQueueTail          = (ChannelBuffer*) NULL;    }    chanPtr = (Channel *) ckalloc((unsigned) sizeof(Channel));    /*     * Save some of the current state into the new structure,     * reinitialize the parts which will stay with the transformation.     *     * Remarks:     */    chanPtr->state		= statePtr;    chanPtr->instanceData	= instanceData;    chanPtr->typePtr		= typePtr;    chanPtr->downChanPtr	= prevChanPtr;    chanPtr->upChanPtr		= (Channel *) NULL;    chanPtr->inQueueHead        = (ChannelBuffer*) NULL;    chanPtr->inQueueTail        = (ChannelBuffer*) NULL;    /*     * Place new block at the head of a possibly existing list of previously     * stacked channels.     */    prevChanPtr->upChanPtr	= chanPtr;    statePtr->topChanPtr	= chanPtr;    return (Tcl_Channel) chanPtr;}/* *---------------------------------------------------------------------- * * Tcl_UnstackChannel -- * *	Unstacks an entry in the hash table for a Tcl_Channel *	record. This is the reverse to 'Tcl_StackChannel'. * * Results: *	A standard Tcl result. * * Side effects: *	If TCL_ERROR is returned, the posix error code will be set *	with Tcl_SetErrno. * *---------------------------------------------------------------------- */intTcl_UnstackChannel (interp, chan)    Tcl_Interp *interp; /* The interpreter we are working in */    Tcl_Channel chan;   /* The channel to unstack */{    Channel      *chanPtr  = (Channel *) chan;    ChannelState *statePtr = chanPtr->state;    int result = 0;    /*     * This operation should occur at the top of a channel stack.     */    chanPtr = statePtr->topChanPtr;    if (chanPtr->downChanPtr != (Channel *) NULL) {        /*	 * Instead of manipulating the per-thread / per-interp list/hashtable	 * of registered channels we wind down the state of the transformation,	 * and then restore the state of underlying channel into the old	 * structure.	 */	Channel *downChanPtr = chanPtr->downChanPtr;	/*	 * Flush the buffers. This ensures that any data still in them	 * at this time _is_ handled by the transformation we are unstacking	 * right now. Restrict this to writable channels. Take care to hide	 * a possible bg-copy in progress from Tcl_Flush and the	 * CheckForChannelErrors inside.	 */	if (statePtr->flags & TCL_WRITABLE) {	    CopyState*    csPtr;	    csPtr           = statePtr->csPtr;	    statePtr->csPtr = (CopyState*) NULL;	    if (Tcl_Flush((Tcl_Channel) chanPtr) != TCL_OK) {	        statePtr->csPtr = csPtr;		Tcl_AppendResult(interp, "could not flush channel \"",			Tcl_GetChannelName((Tcl_Channel) chanPtr), "\"",			(char *) NULL);		return TCL_ERROR;	    }	    statePtr->csPtr = csPtr;	}	/*	 * Anything in the input queue and the push-back buffers of	 * the transformation going away is transformed data, but not	 * yet read. As unstacking means that the caller does not want	 * to see transformed data any more we have to discard these	 * bytes. To avoid writing an analogue to 'DiscardInputQueued'	 * we move the information in the push back buffers to the	 * input queue and then call 'DiscardInputQueued' on that.	 */	if (((statePtr->flags & TCL_READABLE)  != 0) &&	    ((statePtr->inQueueHead != (ChannelBuffer*) NULL) ||	     (chanPtr->inQueueHead  != (ChannelBuffer*) NULL))) {	    if ((statePtr->inQueueHead != (ChannelBuffer*) NULL) &&		(chanPtr->inQueueHead  != (ChannelBuffer*) NULL)) {	        statePtr->inQueueTail->nextPtr = chanPtr->inQueueHead;		statePtr->inQueueTail = chanPtr->inQueueTail;	        statePtr->inQueueHead = statePtr->inQueueTail;	    } else if (chanPtr->inQueueHead != (ChannelBuffer*) NULL) {	        statePtr->inQueueHead = chanPtr->inQueueHead;		statePtr->inQueueTail = chanPtr->inQueueTail;	    }	    chanPtr->inQueueHead          = (ChannelBuffer*) NULL;	    chanPtr->inQueueTail          = (ChannelBuffer*) NULL;	    DiscardInputQueued (statePtr, 0);	}	statePtr->topChanPtr	= downChanPtr;	downChanPtr->upChanPtr	= (Channel *) NULL;	/*	 * Leave this link intact for closeproc	 *  chanPtr->downChanPtr	= (Channel *) NULL;	 */	/*	 * Close and free the channel driver state.	 */	if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) {	    result = (chanPtr->typePtr->closeProc)(chanPtr->instanceData,		    interp);	} else {	    result = (chanPtr->typePtr->close2Proc)(chanPtr->instanceData,		    interp, 0);	}	chanPtr->typePtr	= NULL;	/*	 * AK: Tcl_NotifyChannel may hold a reference to this block of memory	 */	Tcl_EventuallyFree((ClientData) chanPtr, TCL_DYNAMIC);	UpdateInterest(downChanPtr);	if (result != 0) {	    Tcl_SetErrno(result);	    return TCL_ERROR;	}    } else {        /*	 * This channel does not cover another one.	 * Simply do a close, if necessary.	 */        if (statePtr->refCount <= 0) {            if (Tcl_Close(interp, chan) != TCL_OK) {                return TCL_ERROR;            }	}    }    return TCL_OK;}/* *---------------------------------------------------------------------- * * Tcl_GetStackedChannel -- * *	Determines whether the specified channel is stacked upon another. * * Results: *	NULL if the channel is not stacked upon another one, or a reference *	to the channel it is stacked upon. This reference can be used in *	queries, but modification is not allowed. * * Side effects: *	None. * *---------------------------------------------------------------------- */Tcl_ChannelTcl_GetStackedChannel(chan)    Tcl_Channel chan;{    Channel *chanPtr = (Channel *) chan;	/* The actual channel. */    return (Tcl_Channel) chanPtr->downChanPtr;}/* *---------------------------------------------------------------------- * * Tcl_GetTopChannel -- * *	Returns the top channel of a channel stack. * * Results: *	NULL if the channel is not stacked upon another one, or a reference *	to the channel it is stacked upon. This reference can be used in *	queries, but modification is not allowed. * * Side effects: *	None. * *---------------------------------------------------------------------- */Tcl_ChannelTcl_GetTopChannel(chan)    Tcl_Channel chan;{    Channel *chanPtr = (Channel *) chan;	/* The actual channel. */    return (Tcl_Channel) chanPtr->state->topChanPtr;}/* *---------------------------------------------------------------------- * * Tcl_GetChannelInstanceData -- * *	Returns the client data associated with a channel. * * Results: *	The client data. * * Side effects: *	None. * *---------------------------------------------------------------------- */ClientDataTcl_GetChannelInstanceData(chan)    Tcl_Channel chan;		/* Channel for which to return client data. */{    Channel *chanPtr = (Channel *) chan;	/* The actual channel. */    return chanPtr->instanceData;}/* *---------------------------------------------------------------------- * * Tcl_GetChannelThread -- * *	Given a channel structure, returns the thread managing it. *	TIP #10 * * Results: *	Returns the id of the thread managing the channel. * * Side effects: *	None. * *---------------------------------------------------------------------- */Tcl_ThreadIdTcl_GetChannelThread(chan)    Tcl_Channel chan;		/* The channel to return managing thread for. */{    Channel *chanPtr = (Channel *) chan;	/* The actual channel. */    return chanPtr->state->managingThread;}/* *---------------------------------------------------------------------- * * Tcl_GetChannelType -- * *	Given a channel structure, returns the channel type structure. * * Results: *	Returns a pointer to the channel type structure. * * Side effects: *	None. * *---------------------------------------------------------------------- */Tcl_ChannelType *Tcl_GetChannelType(chan)    Tcl_Channel chan;		/* The channel to return type for. */{    Channel *chanPtr = (Channel *) chan;	/* The actual channel. */    return chanPtr->typePtr;}/* *---------------------------------------------------------------------- * * Tcl_GetChannelMode -- * *	Computes a mask indicating whether the channel is open for *	reading and writing. * * Results: *	An OR-ed combination of TCL_READABLE and TCL_WRITABLE. * * Side effects: *	None.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?