tclio.c

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

C
2,110
字号
 * *---------------------------------------------------------------------- */intTcl_GetChannelMode(chan)    Tcl_Channel chan;		/* The channel for which the mode is                                 * being computed. */{    ChannelState *statePtr = ((Channel *) chan)->state;					/* State of actual channel. */    return (statePtr->flags & (TCL_READABLE | TCL_WRITABLE));}/* *---------------------------------------------------------------------- * * Tcl_GetChannelName -- * *	Returns the string identifying the channel name. * * Results: *	The string containing the channel name. This memory is *	owned by the generic layer and should not be modified by *	the caller. * * Side effects: *	None. * *---------------------------------------------------------------------- */CONST char *Tcl_GetChannelName(chan)    Tcl_Channel chan;		/* The channel for which to return the name. */{    ChannelState *statePtr;	/* State of actual channel. */    statePtr = ((Channel *) chan)->state;    return statePtr->channelName;}/* *---------------------------------------------------------------------- * * Tcl_GetChannelHandle -- * *	Returns an OS handle associated with a channel. * * Results: *	Returns TCL_OK and places the handle in handlePtr, or returns *	TCL_ERROR on failure. * * Side effects: *	None. * *---------------------------------------------------------------------- */intTcl_GetChannelHandle(chan, direction, handlePtr)    Tcl_Channel chan;		/* The channel to get file from. */    int direction;		/* TCL_WRITABLE or TCL_READABLE. */    ClientData *handlePtr;	/* Where to store handle */{    Channel *chanPtr;		/* The actual channel. */    ClientData handle;    int result;    chanPtr = ((Channel *) chan)->state->bottomChanPtr;    result = (chanPtr->typePtr->getHandleProc)(chanPtr->instanceData,	    direction, &handle);    if (handlePtr) {	*handlePtr = handle;    }    return result;}/* *--------------------------------------------------------------------------- * * AllocChannelBuffer -- * *	A channel buffer has BUFFER_PADDING bytes extra at beginning to *	hold any bytes of a native-encoding character that got split by *	the end of the previous buffer and need to be moved to the *	beginning of the next buffer to make a contiguous string so it *	can be converted to UTF-8. * *	A channel buffer has BUFFER_PADDING bytes extra at the end to *	hold any bytes of a native-encoding character (generated from a *	UTF-8 character) that overflow past the end of the buffer and *	need to be moved to the next buffer. * * Results: *	A newly allocated channel buffer. * * Side effects: *	None. * *--------------------------------------------------------------------------- */static ChannelBuffer *AllocChannelBuffer(length)    int length;			/* Desired length of channel buffer. */{    ChannelBuffer *bufPtr;    int n;    n = length + CHANNELBUFFER_HEADER_SIZE + BUFFER_PADDING + BUFFER_PADDING;    bufPtr = (ChannelBuffer *) ckalloc((unsigned) n);    bufPtr->nextAdded	= BUFFER_PADDING;    bufPtr->nextRemoved	= BUFFER_PADDING;    bufPtr->bufLength	= length + BUFFER_PADDING;    bufPtr->nextPtr	= (ChannelBuffer *) NULL;    return bufPtr;}/* *---------------------------------------------------------------------- * * RecycleBuffer -- * *	Helper function to recycle input and output buffers. Ensures *	that two input buffers are saved (one in the input queue and *	another in the saveInBufPtr field) and that curOutPtr is set *	to a buffer. Only if these conditions are met is the buffer *	freed to the OS. * * Results: *	None. * * Side effects: *	May free a buffer to the OS. * *---------------------------------------------------------------------- */static voidRecycleBuffer(statePtr, bufPtr, mustDiscard)    ChannelState *statePtr;	/* ChannelState in which to recycle buffers. */    ChannelBuffer *bufPtr;	/* The buffer to recycle. */    int mustDiscard;		/* If nonzero, free the buffer to the                                 * OS, always. */{    /*     * Do we have to free the buffer to the OS?     */    if (mustDiscard) {        ckfree((char *) bufPtr);        return;    }    /*     * Only save buffers which are at least as big as the requested     * buffersize for the channel. This is to honor dynamic changes     * of the buffersize made by the user.     */    if ((bufPtr->bufLength - BUFFER_PADDING) < statePtr->bufSize) {        ckfree((char *) bufPtr);        return;    }    /*     * Only save buffers for the input queue if the channel is readable.     */        if (statePtr->flags & TCL_READABLE) {        if (statePtr->inQueueHead == (ChannelBuffer *) NULL) {            statePtr->inQueueHead = bufPtr;            statePtr->inQueueTail = bufPtr;            goto keepit;        }        if (statePtr->saveInBufPtr == (ChannelBuffer *) NULL) {            statePtr->saveInBufPtr = bufPtr;            goto keepit;        }    }    /*     * Only save buffers for the output queue if the channel is writable.     */    if (statePtr->flags & TCL_WRITABLE) {        if (statePtr->curOutPtr == (ChannelBuffer *) NULL) {            statePtr->curOutPtr = bufPtr;            goto keepit;        }    }    /*     * If we reached this code we return the buffer to the OS.     */    ckfree((char *) bufPtr);    return;    keepit:    bufPtr->nextRemoved = BUFFER_PADDING;    bufPtr->nextAdded = BUFFER_PADDING;    bufPtr->nextPtr = (ChannelBuffer *) NULL;}/* *---------------------------------------------------------------------- * * DiscardOutputQueued -- * *	Discards all output queued in the output queue of a channel. * * Results: *	None. * * Side effects: *	Recycles buffers. * *---------------------------------------------------------------------- */static voidDiscardOutputQueued(statePtr)    ChannelState *statePtr;	/* ChannelState for which to discard output. */{    ChannelBuffer *bufPtr;        while (statePtr->outQueueHead != (ChannelBuffer *) NULL) {        bufPtr = statePtr->outQueueHead;        statePtr->outQueueHead = bufPtr->nextPtr;        RecycleBuffer(statePtr, bufPtr, 0);    }    statePtr->outQueueHead = (ChannelBuffer *) NULL;    statePtr->outQueueTail = (ChannelBuffer *) NULL;}/* *---------------------------------------------------------------------- * * CheckForDeadChannel -- * *	This function checks is a given channel is Dead. *      (A channel that has been closed but not yet deallocated.) * * Results: *	True (1) if channel is Dead, False (0) if channel is Ok * * Side effects: *      None * *---------------------------------------------------------------------- */static intCheckForDeadChannel(interp, statePtr)    Tcl_Interp *interp;		/* For error reporting (can be NULL) */    ChannelState *statePtr;	/* The channel state to check. */{    if (statePtr->flags & CHANNEL_DEAD) {        Tcl_SetErrno(EINVAL);	if (interp) {	    Tcl_AppendResult(interp,		    "unable to access channel: invalid channel",		    (char *) NULL);   	}	return 1;    }    return 0;}/* *---------------------------------------------------------------------- * * FlushChannel -- * *	This function flushes as much of the queued output as is possible *	now. If calledFromAsyncFlush is nonzero, it is being called in an *	event handler to flush channel output asynchronously. * * Results: *	0 if successful, else the error code that was returned by the *	channel type operation. * * Side effects: *	May produce output on a channel. May block indefinitely if the *	channel is synchronous. May schedule an async flush on the channel. *	May recycle memory for buffers in the output queue. * *---------------------------------------------------------------------- */static intFlushChannel(interp, chanPtr, calledFromAsyncFlush)    Tcl_Interp *interp;			/* For error reporting during close. */    Channel *chanPtr;			/* The channel to flush on. */    int calledFromAsyncFlush;		/* If nonzero then we are being                                         * called from an asynchronous                                         * flush callback. */{    ChannelState *statePtr = chanPtr->state;					/* State of the channel stack. */    ChannelBuffer *bufPtr;		/* Iterates over buffered output                                         * queue. */    int toWrite;			/* Amount of output data in current                                         * buffer available to be written. */    int written;			/* Amount of output data actually                                         * written in current round. */    int errorCode = 0;			/* Stores POSIX error codes from                                         * channel driver operations. */    int wroteSome = 0;			/* Set to one if any data was					 * written to the driver. */    /*     * Prevent writing on a dead channel -- a channel that has been closed     * but not yet deallocated. This can occur if the exit handler for the     * channel deallocation runs before all channels are deregistered in     * all interpreters.     */        if (CheckForDeadChannel(interp, statePtr)) return -1;        /*     * Loop over the queued buffers and attempt to flush as     * much as possible of the queued output to the channel.     */    while (1) {        /*         * If the queue is empty and there is a ready current buffer, OR if         * the current buffer is full, then move the current buffer to the         * queue.         */        if (((statePtr->curOutPtr != (ChannelBuffer *) NULL) &&                (statePtr->curOutPtr->nextAdded == statePtr->curOutPtr->bufLength))                || ((statePtr->flags & BUFFER_READY) &&                        (statePtr->outQueueHead == (ChannelBuffer *) NULL))) {            statePtr->flags &= (~(BUFFER_READY));            statePtr->curOutPtr->nextPtr = (ChannelBuffer *) NULL;            if (statePtr->outQueueHead == (ChannelBuffer *) NULL) {                statePtr->outQueueHead = statePtr->curOutPtr;            } else {                statePtr->outQueueTail->nextPtr = statePtr->curOutPtr;            }            statePtr->outQueueTail = statePtr->curOutPtr;            statePtr->curOutPtr = (ChannelBuffer *) NULL;        }        bufPtr = statePtr->outQueueHead;        /*         * If we are not being called from an async flush and an async         * flush is active, we just return without producing any output.         */        if ((!calledFromAsyncFlush) &&                (statePtr->flags & BG_FLUSH_SCHEDULED)) {            return 0;        }        /*         * If the output queue is still empty, break out of the while loop.         */        if (bufPtr == (ChannelBuffer *) NULL) {            break;	/* Out of the "while (1)". */        }        /*         * Produce the output on the channel.         */        toWrite = bufPtr->nextAdded - bufPtr->nextRemoved;        written = (chanPtr->typePtr->outputProc) (chanPtr->instanceData,                bufPtr->buf + bufPtr->nextRemoved, toWrite,		&errorCode);	/*         * If the write failed completely attempt to start the asynchronous         * flush mechanism and break out of this loop - do not attempt to         * write any more output at this time.         */        if (written < 0) {                        /*             * If the last attempt to write was interrupted, simply retry.             */                        if (errorCode == EINTR) {                errorCode = 0;                continue;            }            /*             * If the channel is non-blocking and we would have blocked,             * start a background flushing handler and break out of the loop.             */            if ((errorCode == EWOULDBLOCK) || (errorCode == EAGAIN)) {		/*		 * This used to check for CHANNEL_NONBLOCKING, and panic		 * if the channel was blocking.  However, it appears		 * that setting stdin to -blocking 0 has some effect on		 * the stdout when it's a tty channel (dup'ed underneath)		 */		if (!(statePtr->flags & BG_FLUSH_SCHEDULED)) {		    statePtr->flags |= BG_FLUSH_SCHEDULED;		    UpdateInterest(chanPtr);		}		errorCode = 0;		break;            }            /*             * Decide whether to report the error upwards or defer it.             */            if (calledFromAsyncFlush) {                if (statePtr->unreportedError =

⌨️ 快捷键说明

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