tcliogt.c

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

C
1,454
字号
	    break;    }    Tcl_ResetResult(dataPtr->interp);    if (preserve) {	Tcl_RestoreResult(dataPtr->interp, &ciSave);    }    return res;    cleanup:    if (preserve) {	Tcl_RestoreResult(dataPtr->interp, &ciSave);    }    if (command != (Tcl_Obj*) NULL) {        Tcl_DecrRefCount(command);    }    return res;}/* *------------------------------------------------------* * *	TransformBlockModeProc -- * *	Trap handler. Called by the generic IO system *	during option processing to change the blocking *	mode of the channel. * *	Sideeffects: *		Forwards the request to the underlying *		channel. * *	Result: *		0 if successful, errno when failed. * *------------------------------------------------------* */static intTransformBlockModeProc (instanceData, mode)    ClientData  instanceData; /* State of transformation */    int         mode;         /* New blocking mode */{    TransformChannelData* dataPtr = (TransformChannelData*) instanceData;    if (mode == TCL_MODE_NONBLOCKING) {        dataPtr->flags |= CHANNEL_ASYNC;    } else {        dataPtr->flags &= ~(CHANNEL_ASYNC);    }    return 0;}/* *------------------------------------------------------* * *	TransformCloseProc -- * *	Trap handler. Called by the generic IO system *	during destruction of the transformation channel. * *	Sideeffects: *		Releases the memory allocated in *		'Tcl_TransformObjCmd'. * *	Result: *		None. * *------------------------------------------------------* */static intTransformCloseProc (instanceData, interp)    ClientData  instanceData;    Tcl_Interp* interp;{    TransformChannelData* dataPtr = (TransformChannelData*) instanceData;    /*     * Important: In this procedure 'dataPtr->self' already points to     * the underlying channel.     */    /*     * There is no need to cancel an existing channel handler, this is already     * done. Either by 'Tcl_UnstackChannel' or by the general cleanup in     * 'Tcl_Close'.     *     * But we have to cancel an active timer to prevent it from firing on the     * removed channel.     */    if (dataPtr->timer != (Tcl_TimerToken) NULL) {        Tcl_DeleteTimerHandler (dataPtr->timer);	dataPtr->timer = (Tcl_TimerToken) NULL;    }    /*     * Now flush data waiting in internal buffers to output and input. The     * input must be done despite the fact that there is no real receiver     * for it anymore. But the scripts might have sideeffects other parts     * of the system rely on (f.e. signaling the close to interested parties).     */    if (dataPtr->mode & TCL_WRITABLE) {        ExecuteCallback (dataPtr, interp, A_FLUSH_WRITE,		NULL, 0, TRANSMIT_DOWN, 1);    }    if ((dataPtr->mode & TCL_READABLE) && !dataPtr->readIsFlushed) {	dataPtr->readIsFlushed = 1;        ExecuteCallback (dataPtr, interp, A_FLUSH_READ,		NULL, 0, TRANSMIT_IBUF, 1);    }    if (dataPtr->mode & TCL_WRITABLE) {        ExecuteCallback (dataPtr, interp, A_DELETE_WRITE,		NULL, 0, TRANSMIT_DONT, 1);    }    if (dataPtr->mode & TCL_READABLE) {        ExecuteCallback (dataPtr, interp, A_DELETE_READ,		NULL, 0, TRANSMIT_DONT, 1);    }    /*     * General cleanup     */    ResultClear(&dataPtr->result);    Tcl_DecrRefCount(dataPtr->command);    ckfree((VOID*) dataPtr);    return TCL_OK;}/* *------------------------------------------------------* * *	TransformInputProc -- * *	Called by the generic IO system to convert read data. * *	Sideeffects: *		As defined by the conversion. * *	Result: *		A transformed buffer. * *------------------------------------------------------* */static intTransformInputProc (instanceData, buf, toRead, errorCodePtr)    ClientData instanceData;    char*      buf;    int	       toRead;    int*       errorCodePtr;{    TransformChannelData* dataPtr = (TransformChannelData*) instanceData;    int gotBytes, read, res, copied;    Tcl_Channel downChan;    /* should assert (dataPtr->mode & TCL_READABLE) */    if (toRead == 0) {	/* Catch a no-op.	 */	return 0;    }    gotBytes = 0;    downChan = Tcl_GetStackedChannel(dataPtr->self);    while (toRead > 0) {        /*	 * Loop until the request is satisfied (or no data is available from	 * below, possibly EOF).	 */        copied    = ResultCopy (&dataPtr->result, UCHARP (buf), toRead);	toRead   -= copied;	buf      += copied;	gotBytes += copied;	if (toRead == 0) {	    /* The request was completely satisfied from our buffers.	     * We can break out of the loop and return to the caller.	     */	    return gotBytes;	}	/*	 * Length (dataPtr->result) == 0, toRead > 0 here . Use the incoming	 * 'buf'! as target to store the intermediary information read	 * from the underlying channel.	 *	 * Ask the tcl level how much data it allows us to read from	 * the underlying channel. This feature allows the transform to	 * signal EOF upstream although there is none downstream. Useful	 * to control an unbounded 'fcopy', either through counting bytes,	 * or by pattern matching.	 */	ExecuteCallback (dataPtr, NO_INTERP, A_QUERY_MAXREAD,		NULL, 0, TRANSMIT_NUM /* -> maxRead */, 1);	if (dataPtr->maxRead >= 0) {	    if (dataPtr->maxRead < toRead) {	        toRead = dataPtr->maxRead;	    }	} /* else: 'maxRead < 0' == Accept the current value of toRead */	if (toRead <= 0) {	    return gotBytes;	}	read = Tcl_ReadRaw(downChan, buf, toRead);	if (read < 0) {	    /* Report errors to caller. EAGAIN is a special situation.	     * If we had some data before we report that instead of the	     * request to re-try.	     */	    if ((Tcl_GetErrno() == EAGAIN) && (gotBytes > 0)) {	        return gotBytes;	    }	    *errorCodePtr = Tcl_GetErrno();	    return -1;      	}	if (read == 0) {	    /*	     * Check wether we hit on EOF in the underlying channel or	     * not. If not differentiate between blocking and	     * non-blocking modes. In non-blocking mode we ran	     * temporarily out of data. Signal this to the caller via	     * EWOULDBLOCK and error return (-1). In the other cases	     * we simply return what we got and let the caller wait	     * for more. On the other hand, if we got an EOF we have	     * to convert and flush all waiting partial data.	     */	    if (! Tcl_Eof (downChan)) {	        if ((gotBytes == 0) && (dataPtr->flags & CHANNEL_ASYNC)) {		    *errorCodePtr = EWOULDBLOCK;		    return -1;		} else {		    return gotBytes;		}	    } else {	        if (dataPtr->readIsFlushed) {		    /* Already flushed, nothing to do anymore		     */		    return gotBytes;		}		dataPtr->readIsFlushed = 1;		ExecuteCallback (dataPtr, NO_INTERP, A_FLUSH_READ,			NULL, 0, TRANSMIT_IBUF, P_PRESERVE);		if (ResultLength (&dataPtr->result) == 0) {		    /* we had nothing to flush */		    return gotBytes;		}		continue; /* at: while (toRead > 0) */	    }	} /* read == 0 */	/* Transform the read chunk and add the result to our	 * read buffer (dataPtr->result)	 */	res = ExecuteCallback (dataPtr, NO_INTERP, A_READ,		UCHARP (buf), read, TRANSMIT_IBUF, P_PRESERVE);	if (res != TCL_OK) {	    *errorCodePtr = EINVAL;	    return -1;	}    } /* while toRead > 0 */    return gotBytes;}/* *------------------------------------------------------* * *	TransformOutputProc -- * *	Called by the generic IO system to convert data *	waiting to be written. * *	Sideeffects: *		As defined by the transformation. * *	Result: *		A transformed buffer. * *------------------------------------------------------* */static intTransformOutputProc (instanceData, buf, toWrite, errorCodePtr)    ClientData instanceData;    CONST char*      buf;    int        toWrite;    int*       errorCodePtr;{    TransformChannelData* dataPtr = (TransformChannelData*) instanceData;    int res;    /* should assert (dataPtr->mode & TCL_WRITABLE) */    if (toWrite == 0) {	/* Catch a no-op.	 */	return 0;    }    res = ExecuteCallback (dataPtr, NO_INTERP, A_WRITE,	    UCHARP (buf), toWrite,	    TRANSMIT_DOWN, P_NO_PRESERVE);    if (res != TCL_OK) {        *errorCodePtr = EINVAL;	return -1;    }    return toWrite;}/* *------------------------------------------------------* * *	TransformSeekProc -- * *	This procedure is called by the generic IO level *	to move the access point in a channel. * *	Sideeffects: *		Moves the location at which the channel *		will be accessed in future operations. *		Flushes all transformation buffers, then *		forwards it to the underlying channel. * *	Result: *		-1 if failed, the new position if *		successful. An output argument contains *		the POSIX error code if an error *		occurred, or zero. * *------------------------------------------------------* */static intTransformSeekProc (instanceData, offset, mode, errorCodePtr)    ClientData  instanceData;	/* The channel to manipulate */    long	offset;		/* Size of movement. */    int         mode;		/* How to move */    int*        errorCodePtr;	/* Location of error flag. */{    TransformChannelData* dataPtr	= (TransformChannelData*) instanceData;    Tcl_Channel           parent        = Tcl_GetStackedChannel(dataPtr->self);    Tcl_ChannelType*      parentType	= Tcl_GetChannelType(parent);    Tcl_DriverSeekProc*   parentSeekProc = Tcl_ChannelSeekProc(parentType);    if ((offset == 0) && (mode == SEEK_CUR)) {        /* This is no seek but a request to tell the caller the current	 * location. Simply pass the request down.	 */	return (*parentSeekProc) (Tcl_GetChannelInstanceData(parent),		offset, mode, errorCodePtr);    }    /*     * It is a real request to change the position. Flush all data waiting     * for output and discard everything in the input buffers. Then pass     * the request down, unchanged.     */    if (dataPtr->mode & TCL_WRITABLE) {        ExecuteCallback (dataPtr, NO_INTERP, A_FLUSH_WRITE,		NULL, 0, TRANSMIT_DOWN, P_NO_PRESERVE);    }    if (dataPtr->mode & TCL_READABLE) {        ExecuteCallback (dataPtr, NO_INTERP, A_CLEAR_READ,		NULL, 0, TRANSMIT_DONT, P_NO_PRESERVE);	ResultClear(&dataPtr->result);	dataPtr->readIsFlushed = 0;    }    return (*parentSeekProc) (Tcl_GetChannelInstanceData(parent),	    offset, mode, errorCodePtr);}/* *---------------------------------------------------------------------- * * TransformWideSeekProc -- * *	This procedure is called by the generic IO level to move the *	access point in a channel, with a (potentially) 64-bit offset. * * Side effects: *	Moves the location at which the channel will be accessed in *	future operations.  Flushes all transformation buffers, then *	forwards it to the underlying channel. * * Result: *	-1 if failed, the new position if successful. An output *	argument contains the POSIX error code if an error occurred, *	or zero. * *---------------------------------------------------------------------- */static Tcl_WideIntTransformWideSeekProc (instanceData, offset, mode, errorCodePtr)    ClientData  instanceData;	/* The channel to manipulate */    Tcl_WideInt offset;		/* Size of movement. */    int         mode;		/* How to move */    int*        errorCodePtr;	/* Location of error flag. */{    TransformChannelData* dataPtr =	(TransformChannelData*) instanceData;    Tcl_Channel parent =	Tcl_GetStackedChannel(dataPtr->self);    Tcl_ChannelType* parentType	=	Tcl_GetChannelType(parent);    Tcl_DriverSeekProc* parentSeekProc =	Tcl_ChannelSeekProc(parentType);    Tcl_DriverWideSeekProc* parentWideSeekProc =	Tcl_ChannelWideSeekProc(parentType);    ClientData parentData =	Tcl_GetChannelInstanceData(parent);    if ((offset == Tcl_LongAsWide(0)) && (mode == SEEK_CUR)) {        /*	 * This is no seek but a request to tell the caller the current	 * location. Simply pass the request down.	 */	if (parentWideSeekProc != NULL) {	    return (*parentWideSeekProc) (parentData, offset, mode,		    errorCodePtr);	}	return Tcl_LongAsWide((*parentSeekProc) (parentData, 0, mode,		errorCodePtr));    }    /*     * It is a real request to change the position. Flush all data waiting     * for output and discard everything in the input buffers. Then pass     * the request down, unchanged.     */    if (dataPtr->mode & TCL_WRITABLE) {        ExecuteCallback (dataPtr, NO_INTERP, A_FLUSH_WRITE,		NULL, 0, TRANSMIT_DOWN, P_NO_PRESERVE);    }    if (dataPtr->mode & TCL_READABLE) {        ExecuteCallback (dataPtr, NO_INTERP, A_CLEAR_READ,		NULL, 0, TRANSMIT_DONT, P_NO_PRESERVE);	ResultClear(&dataPtr->result);	dataPtr->readIsFlushed = 0;    }    /*     * If we have a wide seek capability, we should stick with that.     */    if (parentWideSeekProc != NULL) {

⌨️ 快捷键说明

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