📄 tclio.c
字号:
}/* *---------------------------------------------------------------------- * * Tcl_SetStdChannel -- * * This function is used to change the channels that are used * for stdin/stdout/stderr in new interpreters. * * Results: * None * * Side effects: * None. * *---------------------------------------------------------------------- */voidTcl_SetStdChannel(channel, type) Tcl_Channel channel; int type; /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */{ switch (type) { case TCL_STDIN: stdinInitialized = 1; stdinChannel = channel; break; case TCL_STDOUT: stdoutInitialized = 1; stdoutChannel = channel; break; case TCL_STDERR: stderrInitialized = 1; stderrChannel = channel; break; }}/* *---------------------------------------------------------------------- * * Tcl_GetStdChannel -- * * Returns the specified standard channel. * * Results: * Returns the specified standard channel, or NULL. * * Side effects: * May cause the creation of a standard channel and the underlying * file. * *---------------------------------------------------------------------- */Tcl_ChannelTcl_GetStdChannel(type) int type; /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */{ Tcl_Channel channel = NULL; /* * If the channels were not created yet, create them now and * store them in the static variables. Note that we need to set * stdinInitialized before calling TclGetDefaultStdChannel in order * to avoid recursive loops when TclGetDefaultStdChannel calls * Tcl_CreateChannel. */ switch (type) { case TCL_STDIN: if (!stdinInitialized) { stdinChannel = TclGetDefaultStdChannel(TCL_STDIN); stdinInitialized = 1; /* * Artificially bump the refcount to ensure that the channel * is only closed on exit. * * NOTE: Must only do this if stdinChannel is not NULL. It * can be NULL in situations where Tcl is unable to connect * to the standard input. */ if (stdinChannel != (Tcl_Channel) NULL) { (void) Tcl_RegisterChannel((Tcl_Interp *) NULL, stdinChannel); } } channel = stdinChannel; break; case TCL_STDOUT: if (!stdoutInitialized) { stdoutChannel = TclGetDefaultStdChannel(TCL_STDOUT); stdoutInitialized = 1; /* * Artificially bump the refcount to ensure that the channel * is only closed on exit. * * NOTE: Must only do this if stdoutChannel is not NULL. It * can be NULL in situations where Tcl is unable to connect * to the standard output. */ if (stdoutChannel != (Tcl_Channel) NULL) { (void) Tcl_RegisterChannel((Tcl_Interp *) NULL, stdoutChannel); } } channel = stdoutChannel; break; case TCL_STDERR: if (!stderrInitialized) { stderrChannel = TclGetDefaultStdChannel(TCL_STDERR); stderrInitialized = 1; /* * Artificially bump the refcount to ensure that the channel * is only closed on exit. * * NOTE: Must only do this if stderrChannel is not NULL. It * can be NULL in situations where Tcl is unable to connect * to the standard error. */ if (stderrChannel != (Tcl_Channel) NULL) { (void) Tcl_RegisterChannel((Tcl_Interp *) NULL, stderrChannel); } } channel = stderrChannel; break; } return channel;}/* *---------------------------------------------------------------------- * * Tcl_CreateCloseHandler * * Creates a close callback which will be called when the channel is * closed. * * Results: * None. * * Side effects: * Causes the callback to be called in the future when the channel * will be closed. * *---------------------------------------------------------------------- */voidTcl_CreateCloseHandler(chan, proc, clientData) Tcl_Channel chan; /* The channel for which to create the * close callback. */ Tcl_CloseProc *proc; /* The callback routine to call when the * channel will be closed. */ ClientData clientData; /* Arbitrary data to pass to the * close callback. */{ Channel *chanPtr; CloseCallback *cbPtr; chanPtr = (Channel *) chan; cbPtr = (CloseCallback *) ckalloc((unsigned) sizeof(CloseCallback)); cbPtr->proc = proc; cbPtr->clientData = clientData; cbPtr->nextPtr = chanPtr->closeCbPtr; chanPtr->closeCbPtr = cbPtr;}/* *---------------------------------------------------------------------- * * Tcl_DeleteCloseHandler -- * * Removes a callback that would have been called on closing * the channel. If there is no matching callback then this * function has no effect. * * Results: * None. * * Side effects: * The callback will not be called in the future when the channel * is eventually closed. * *---------------------------------------------------------------------- */voidTcl_DeleteCloseHandler(chan, proc, clientData) Tcl_Channel chan; /* The channel for which to cancel the * close callback. */ Tcl_CloseProc *proc; /* The procedure for the callback to * remove. */ ClientData clientData; /* The callback data for the callback * to remove. */{ Channel *chanPtr; CloseCallback *cbPtr, *cbPrevPtr; chanPtr = (Channel *) chan; for (cbPtr = chanPtr->closeCbPtr, cbPrevPtr = (CloseCallback *) NULL; cbPtr != (CloseCallback *) NULL; cbPtr = cbPtr->nextPtr) { if ((cbPtr->proc == proc) && (cbPtr->clientData == clientData)) { if (cbPrevPtr == (CloseCallback *) NULL) { chanPtr->closeCbPtr = cbPtr->nextPtr; } ckfree((char *) cbPtr); break; } else { cbPrevPtr = cbPtr; } }}/* *---------------------------------------------------------------------- * * CloseChannelsOnExit -- * * Closes all the existing channels, on exit. This routine is called * during exit processing. * * Results: * None. * * Side effects: * Closes all channels. * *---------------------------------------------------------------------- */ /* ARGSUSED */static voidCloseChannelsOnExit(clientData) ClientData clientData; /* NULL - unused. */{ Channel *chanPtr; /* Iterates over open channels. */ Channel *nextChanPtr; /* Iterates over open channels. */ for (chanPtr = firstChanPtr; chanPtr != (Channel *) NULL; chanPtr = nextChanPtr) { nextChanPtr = chanPtr->nextChanPtr; /* * Set the channel back into blocking mode to ensure that we wait * for all data to flush out. */ (void) Tcl_SetChannelOption(NULL, (Tcl_Channel) chanPtr, "-blocking", "on"); if ((chanPtr == (Channel *) stdinChannel) || (chanPtr == (Channel *) stdoutChannel) || (chanPtr == (Channel *) stderrChannel)) { /* * Decrement the refcount which was earlier artificially bumped * up to keep the channel from being closed. */ chanPtr->refCount--; } if (chanPtr->refCount <= 0) { /* * Close it only if the refcount indicates that the channel is not * referenced from any interpreter. If it is, that interpreter will * close the channel when it gets destroyed. */ (void) Tcl_Close((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr); } else { /* * The refcount is greater than zero, so flush the channel. */ Tcl_Flush((Tcl_Channel) chanPtr); /* * Call the device driver to actually close the underlying * device for this channel. */ (chanPtr->typePtr->closeProc) (chanPtr->instanceData, (Tcl_Interp *) NULL); /* * Finally, we clean up the fields in the channel data structure * since all of them have been deleted already. We mark the * channel with CHANNEL_DEAD to prevent any further IO operations * on it. */ chanPtr->instanceData = (ClientData) NULL; chanPtr->flags |= CHANNEL_DEAD; } } /* * Reinitialize all the variables to the initial state: */ firstChanPtr = (Channel *) NULL; nestedHandlerPtr = (NextChannelHandler *) NULL; channelExitHandlerCreated = 0; stdinChannel = NULL; stdinInitialized = 0; stdoutChannel = NULL; stdoutInitialized = 0; stderrChannel = NULL; stderrInitialized = 0;}/* *---------------------------------------------------------------------- * * GetChannelTable -- * * Gets and potentially initializes the channel table for an * interpreter. If it is initializing the table it also inserts * channels for stdin, stdout and stderr if the interpreter is * trusted. * * Results: * A pointer to the hash table created, for use by the caller. * * Side effects: * Initializes the channel table for an interpreter. May create * channels for stdin, stdout and stderr. * *---------------------------------------------------------------------- */static Tcl_HashTable *GetChannelTable(interp) Tcl_Interp *interp;{ Tcl_HashTable *hTblPtr; /* Hash table of channels. */ Tcl_Channel stdinChan, stdoutChan, stderrChan; hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL); if (hTblPtr == (Tcl_HashTable *) NULL) { hTblPtr = (Tcl_HashTable *) ckalloc((unsigned) sizeof(Tcl_HashTable)); Tcl_InitHashTable(hTblPtr, TCL_STRING_KEYS); (void) Tcl_SetAssocData(interp, "tclIO", (Tcl_InterpDeleteProc *) DeleteChannelTable, (ClientData) hTblPtr); /* * If the interpreter is trusted (not "safe"), insert channels * for stdin, stdout and stderr (possibly creating them in the * process). */ if (Tcl_IsSafe(interp) == 0) { stdinChan = Tcl_GetStdChannel(TCL_STDIN); if (stdinChan != NULL) { Tcl_RegisterChannel(interp, stdinChan); } stdoutChan = Tcl_GetStdChannel(TCL_STDOUT); if (stdoutChan != NULL) { Tcl_RegisterChannel(interp, stdoutChan); } stderrChan = Tcl_GetStdChannel(TCL_STDERR); if (stderrChan != NULL) { Tcl_RegisterChannel(interp, stderrChan); } } } return hTblPtr;}/* *---------------------------------------------------------------------- * * DeleteChannelTable -- * * Deletes the channel table for an interpreter, closing any open * channels whose refcount reaches zero. This procedure is invoked * when an interpreter is deleted, via the AssocData cleanup * mechanism. * * Results: * None. * * Side effects: * Deletes the hash table of channels. May close channels. May flush
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -