tclio.c
来自「tcl是工具命令语言」· C语言 代码 · 共 2,110 行 · 第 1/5 页
C
2,110 行
/* * tclIO.c -- * * This file provides the generic portions (those that are the same on * all platforms and for all channel types) of Tcl's IO facilities. * * Copyright (c) 1998-2000 Ajuba Solutions * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id: tclIO.c,v 1.61 2003/02/19 01:04:57 hobbs Exp $ */#include "tclInt.h"#include "tclPort.h"#include "tclIO.h"#include <assert.h>/* * All static variables used in this file are collected into a single * instance of the following structure. For multi-threaded implementations, * there is one instance of this structure for each thread. * * Notice that different structures with the same name appear in other * files. The structure defined below is used in this file only. */typedef struct ThreadSpecificData { /* * This variable holds the list of nested ChannelHandlerEventProc * invocations. */ NextChannelHandler *nestedHandlerPtr; /* * List of all channels currently open, indexed by ChannelState, * as only one ChannelState exists per set of stacked channels. */ ChannelState *firstCSPtr;#ifdef oldcode /* * Has a channel exit handler been created yet? */ int channelExitHandlerCreated; /* * Has the channel event source been created and registered with the * notifier? */ int channelEventSourceCreated;#endif /* * Static variables to hold channels for stdin, stdout and stderr. */ Tcl_Channel stdinChannel; int stdinInitialized; Tcl_Channel stdoutChannel; int stdoutInitialized; Tcl_Channel stderrChannel; int stderrInitialized;} ThreadSpecificData;static Tcl_ThreadDataKey dataKey;/* * Static functions in this file: */static ChannelBuffer * AllocChannelBuffer _ANSI_ARGS_((int length));static void ChannelTimerProc _ANSI_ARGS_(( ClientData clientData));static int CheckChannelErrors _ANSI_ARGS_((ChannelState *statePtr, int direction));static int CheckFlush _ANSI_ARGS_((Channel *chanPtr, ChannelBuffer *bufPtr, int newlineFlag));static int CheckForDeadChannel _ANSI_ARGS_((Tcl_Interp *interp, ChannelState *statePtr));static void CheckForStdChannelsBeingClosed _ANSI_ARGS_(( Tcl_Channel chan));static void CleanupChannelHandlers _ANSI_ARGS_(( Tcl_Interp *interp, Channel *chanPtr));static int CloseChannel _ANSI_ARGS_((Tcl_Interp *interp, Channel *chanPtr, int errorCode));static void CommonGetsCleanup _ANSI_ARGS_((Channel *chanPtr, Tcl_Encoding encoding));static int CopyAndTranslateBuffer _ANSI_ARGS_(( ChannelState *statePtr, char *result, int space));static int CopyBuffer _ANSI_ARGS_(( Channel *chanPtr, char *result, int space));static int CopyData _ANSI_ARGS_((CopyState *csPtr, int mask));static void CopyEventProc _ANSI_ARGS_((ClientData clientData, int mask));static void CreateScriptRecord _ANSI_ARGS_(( Tcl_Interp *interp, Channel *chanPtr, int mask, Tcl_Obj *scriptPtr));static void DeleteChannelTable _ANSI_ARGS_(( ClientData clientData, Tcl_Interp *interp));static void DeleteScriptRecord _ANSI_ARGS_((Tcl_Interp *interp, Channel *chanPtr, int mask));static int DetachChannel _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Channel chan));static void DiscardInputQueued _ANSI_ARGS_((ChannelState *statePtr, int discardSavedBuffers));static void DiscardOutputQueued _ANSI_ARGS_(( ChannelState *chanPtr));static int DoRead _ANSI_ARGS_((Channel *chanPtr, char *srcPtr, int slen));static int DoWrite _ANSI_ARGS_((Channel *chanPtr, CONST char *src, int srcLen));static int DoReadChars _ANSI_ARGS_ ((Channel* chan, Tcl_Obj* objPtr, int toRead, int appendFlag));static int DoWriteChars _ANSI_ARGS_ ((Channel* chan, CONST char* src, int len));static int FilterInputBytes _ANSI_ARGS_((Channel *chanPtr, GetsState *statePtr));static int FlushChannel _ANSI_ARGS_((Tcl_Interp *interp, Channel *chanPtr, int calledFromAsyncFlush));static Tcl_HashTable * GetChannelTable _ANSI_ARGS_((Tcl_Interp *interp));static int GetInput _ANSI_ARGS_((Channel *chanPtr));static int HaveVersion _ANSI_ARGS_((Tcl_ChannelType *typePtr, Tcl_ChannelTypeVersion minimumVersion));static void PeekAhead _ANSI_ARGS_((Channel *chanPtr, char **dstEndPtr, GetsState *gsPtr));static int ReadBytes _ANSI_ARGS_((ChannelState *statePtr, Tcl_Obj *objPtr, int charsLeft, int *offsetPtr));static int ReadChars _ANSI_ARGS_((ChannelState *statePtr, Tcl_Obj *objPtr, int charsLeft, int *offsetPtr, int *factorPtr));static void RecycleBuffer _ANSI_ARGS_((ChannelState *statePtr, ChannelBuffer *bufPtr, int mustDiscard));static int StackSetBlockMode _ANSI_ARGS_((Channel *chanPtr, int mode));static int SetBlockMode _ANSI_ARGS_((Tcl_Interp *interp, Channel *chanPtr, int mode));static void StopCopy _ANSI_ARGS_((CopyState *csPtr));static int TranslateInputEOL _ANSI_ARGS_((ChannelState *statePtr, char *dst, CONST char *src, int *dstLenPtr, int *srcLenPtr));static int TranslateOutputEOL _ANSI_ARGS_((ChannelState *statePtr, char *dst, CONST char *src, int *dstLenPtr, int *srcLenPtr));static void UpdateInterest _ANSI_ARGS_((Channel *chanPtr));static int WriteBytes _ANSI_ARGS_((Channel *chanPtr, CONST char *src, int srcLen));static int WriteChars _ANSI_ARGS_((Channel *chanPtr, CONST char *src, int srcLen));/* *--------------------------------------------------------------------------- * * TclInitIOSubsystem -- * * Initialize all resources used by this subsystem on a per-process * basis. * * Results: * None. * * Side effects: * Depends on the memory subsystems. * *--------------------------------------------------------------------------- */voidTclInitIOSubsystem(){ /* * By fetching thread local storage we take care of * allocating it for each thread. */ (void) TCL_TSD_INIT(&dataKey);} /* *------------------------------------------------------------------------- * * TclFinalizeIOSubsystem -- * * Releases all resources used by this subsystem on a per-process * basis. Closes all extant channels that have not already been * closed because they were not owned by any interp. * * Results: * None. * * Side effects: * Depends on encoding and memory subsystems. * *------------------------------------------------------------------------- */ /* ARGSUSED */voidTclFinalizeIOSubsystem(){ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); Channel *chanPtr; /* Iterates over open channels. */ ChannelState *nextCSPtr; /* Iterates over open channels. */ ChannelState *statePtr; /* state of channel stack */ for (statePtr = tsdPtr->firstCSPtr; statePtr != (ChannelState *) NULL; statePtr = nextCSPtr) { chanPtr = statePtr->topChanPtr; nextCSPtr = statePtr->nextCSPtr; /* * 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 *) tsdPtr->stdinChannel) || (chanPtr == (Channel *) tsdPtr->stdoutChannel) || (chanPtr == (Channel *) tsdPtr->stderrChannel)) { /* * Decrement the refcount which was earlier artificially bumped * up to keep the channel from being closed. */ statePtr->refCount--; } if (statePtr->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. */ if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) { (chanPtr->typePtr->closeProc)(chanPtr->instanceData, (Tcl_Interp *) NULL); } else { (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, (Tcl_Interp *) NULL, 0); } /* * 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; statePtr->flags |= CHANNEL_DEAD; } }}/* *---------------------------------------------------------------------- * * 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. */{ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); switch (type) { case TCL_STDIN: tsdPtr->stdinInitialized = 1; tsdPtr->stdinChannel = channel; break; case TCL_STDOUT: tsdPtr->stdoutInitialized = 1; tsdPtr->stdoutChannel = channel; break; case TCL_STDERR: tsdPtr->stderrInitialized = 1; tsdPtr->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; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* * If the channels were not created yet, create them now and * store them in the static variables. */ switch (type) { case TCL_STDIN: if (!tsdPtr->stdinInitialized) { tsdPtr->stdinChannel = TclpGetDefaultStdChannel(TCL_STDIN); tsdPtr->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 (tsdPtr->stdinChannel != (Tcl_Channel) NULL) { (void) Tcl_RegisterChannel((Tcl_Interp *) NULL, tsdPtr->stdinChannel); } } channel = tsdPtr->stdinChannel; break; case TCL_STDOUT: if (!tsdPtr->stdoutInitialized) { tsdPtr->stdoutChannel = TclpGetDefaultStdChannel(TCL_STDOUT); tsdPtr->stdoutInitialized = 1; if (tsdPtr->stdoutChannel != (Tcl_Channel) NULL) { (void) Tcl_RegisterChannel((Tcl_Interp *) NULL, tsdPtr->stdoutChannel); } } channel = tsdPtr->stdoutChannel; break; case TCL_STDERR: if (!tsdPtr->stderrInitialized) { tsdPtr->stderrChannel = TclpGetDefaultStdChannel(TCL_STDERR); tsdPtr->stderrInitialized = 1; if (tsdPtr->stderrChannel != (Tcl_Channel) NULL) { (void) Tcl_RegisterChannel((Tcl_Interp *) NULL, tsdPtr->stderrChannel); } } channel = tsdPtr->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. */{
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?