📄 tclio.c
字号:
chanPtr->scriptRecordPtr = (EventScriptRecord *) NULL; chanPtr->bufSize = CHANNELBUFFER_DEFAULT_SIZE; chanPtr->timer = NULL; chanPtr->csPtr = NULL; /* * Link the channel into the list of all channels; create an on-exit * handler if there is not one already, to close off all the channels * in the list on exit. */ chanPtr->nextChanPtr = firstChanPtr; firstChanPtr = chanPtr; if (!channelExitHandlerCreated) { channelExitHandlerCreated = 1; Tcl_CreateExitHandler(CloseChannelsOnExit, (ClientData) NULL); } /* * Install this channel in the first empty standard channel slot, if * the channel was previously closed explicitly. */ if ((stdinChannel == NULL) && (stdinInitialized == 1)) { Tcl_SetStdChannel((Tcl_Channel)chanPtr, TCL_STDIN); Tcl_RegisterChannel((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr); } else if ((stdoutChannel == NULL) && (stdoutInitialized == 1)) { Tcl_SetStdChannel((Tcl_Channel)chanPtr, TCL_STDOUT); Tcl_RegisterChannel((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr); } else if ((stderrChannel == NULL) && (stderrInitialized == 1)) { Tcl_SetStdChannel((Tcl_Channel)chanPtr, TCL_STDERR); Tcl_RegisterChannel((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr); } return (Tcl_Channel) chanPtr;}/* *---------------------------------------------------------------------- * * 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. * *---------------------------------------------------------------------- */intTcl_GetChannelMode(chan) Tcl_Channel chan; /* The channel for which the mode is * being computed. */{ Channel *chanPtr; /* The actual channel. */ chanPtr = (Channel *) chan; return (chanPtr->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. * *---------------------------------------------------------------------- */char *Tcl_GetChannelName(chan) Tcl_Channel chan; /* The channel for which to return the name. */{ Channel *chanPtr; /* The actual channel. */ chanPtr = (Channel *) chan; return chanPtr->channelName;}/* *---------------------------------------------------------------------- * * 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; /* The actual channel. */ chanPtr = (Channel *) chan; return chanPtr->typePtr;}/* *---------------------------------------------------------------------- * * 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; result = (chanPtr->typePtr->getHandleProc)(chanPtr->instanceData, direction, &handle); if (handlePtr) { *handlePtr = handle; } return result;}/* *---------------------------------------------------------------------- * * 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; /* The actual channel. */ chanPtr = (Channel *) chan; return chanPtr->instanceData;}/* *---------------------------------------------------------------------- * * 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(chanPtr, bufPtr, mustDiscard) Channel *chanPtr; /* Channel for 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 for the input queue if the channel is readable. */ if (chanPtr->flags & TCL_READABLE) { if (chanPtr->inQueueHead == (ChannelBuffer *) NULL) { chanPtr->inQueueHead = bufPtr; chanPtr->inQueueTail = bufPtr; goto keepit; } if (chanPtr->saveInBufPtr == (ChannelBuffer *) NULL) { chanPtr->saveInBufPtr = bufPtr; goto keepit; } } /* * Only save buffers for the output queue if the channel is writable. */ if (chanPtr->flags & TCL_WRITABLE) { if (chanPtr->curOutPtr == (ChannelBuffer *) NULL) { chanPtr->curOutPtr = bufPtr; goto keepit; } } /* * If we reached this code we return the buffer to the OS. */ ckfree((char *) bufPtr); return;keepit: bufPtr->nextRemoved = 0; bufPtr->nextAdded = 0; bufPtr->nextPtr = (ChannelBuffer *) NULL;}/* *---------------------------------------------------------------------- * * DiscardOutputQueued -- * * Discards all output queued in the output queue of a channel. * * Results: * None. * * Side effects: * Recycles buffers. * *---------------------------------------------------------------------- */static voidDiscardOutputQueued(chanPtr) Channel *chanPtr; /* The channel for which to discard output. */{ ChannelBuffer *bufPtr; while (chanPtr->outQueueHead != (ChannelBuffer *) NULL) { bufPtr = chanPtr->outQueueHead; chanPtr->outQueueHead = bufPtr->nextPtr; RecycleBuffer(chanPtr, bufPtr, 0); } chanPtr->outQueueHead = (ChannelBuffer *) NULL; chanPtr->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, chanPtr) Tcl_Interp *interp; /* For error reporting (can be NULL) */ Channel *chanPtr; /* The channel to check. */{ if (chanPtr->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. */{ 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; /* Stores POSIX error codes from * channel driver operations. */ errorCode = 0; /* * 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,chanPtr)) 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 (((chanPtr->curOutPtr != (ChannelBuffer *) NULL) && (chanPtr->curOutPtr->nextAdded == chanPtr->curOutPtr->bufSize)) || ((chanPtr->flags & BUFFER_READY) && (chanPtr->outQueueHead == (ChannelBuffer *) NULL))) { chanPtr->flags &= (~(BUFFER_READY)); chanPtr->curOutPtr->nextPtr = (ChannelBuffer *) NULL; if (chanPtr->outQueueHead == (ChannelBuffer *) NULL) { chanPtr->outQueueHead = chanPtr->curOutPtr; } else { chanPtr->outQueueTail->nextPtr = chanPtr->curOutPtr; } chanPtr->outQueueTail = chanPtr->curOutPtr; chanPtr->curOutPtr = (ChannelBuffer *) NULL; } bufPtr = chanPtr->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) &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -