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