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 + -
显示快捷键?