os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclIO.c
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 /* 
     2  * tclIO.c --
     3  *
     4  *	This file provides the generic portions (those that are the same on
     5  *	all platforms and for all channel types) of Tcl's IO facilities.
     6  *
     7  * Copyright (c) 1998-2000 Ajuba Solutions
     8  * Copyright (c) 1995-1997 Sun Microsystems, Inc.
     9  * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved.  
    10  *
    11  * See the file "license.terms" for information on usage and redistribution
    12  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
    13  *
    14  * RCS: @(#) $Id: tclIO.c,v 1.61.2.23 2007/05/24 19:31:55 dgp Exp $
    15  */
    16 
    17 #include "tclInt.h"
    18 #include "tclPort.h"
    19 #include "tclIO.h"
    20 #include <assert.h>
    21 #if defined(__SYMBIAN32__) && defined(__WINSCW__)
    22 #include "tclSymbianGlobals.h"
    23 #define dataKey getdataKey(3)
    24 #endif 
    25 
    26 #ifndef TCL_INHERIT_STD_CHANNELS
    27 #define TCL_INHERIT_STD_CHANNELS 1
    28 #endif
    29 
    30 
    31 /*
    32  * All static variables used in this file are collected into a single
    33  * instance of the following structure.  For multi-threaded implementations,
    34  * there is one instance of this structure for each thread.
    35  *
    36  * Notice that different structures with the same name appear in other
    37  * files.  The structure defined below is used in this file only.
    38  */
    39 
    40 typedef struct ThreadSpecificData {
    41 
    42     /*
    43      * This variable holds the list of nested ChannelHandlerEventProc 
    44      * invocations.
    45      */
    46     NextChannelHandler *nestedHandlerPtr;
    47 
    48     /*
    49      * List of all channels currently open, indexed by ChannelState,
    50      * as only one ChannelState exists per set of stacked channels.
    51      */
    52     ChannelState *firstCSPtr;
    53 #ifdef oldcode
    54     /*
    55      * Has a channel exit handler been created yet?
    56      */
    57     int channelExitHandlerCreated;
    58 
    59     /*
    60      * Has the channel event source been created and registered with the
    61      * notifier?
    62      */
    63     int channelEventSourceCreated;
    64 #endif
    65     /*
    66      * Static variables to hold channels for stdin, stdout and stderr.
    67      */
    68     Tcl_Channel stdinChannel;
    69     int stdinInitialized;
    70     Tcl_Channel stdoutChannel;
    71     int stdoutInitialized;
    72     Tcl_Channel stderrChannel;
    73     int stderrInitialized;
    74 
    75 } ThreadSpecificData;
    76 
    77 #if !defined(__SYMBIAN32__) || !defined(__WINSCW__)
    78 static Tcl_ThreadDataKey dataKey;
    79 #endif
    80 
    81 /*
    82  * Static functions in this file:
    83  */
    84 
    85 static ChannelBuffer *	AllocChannelBuffer _ANSI_ARGS_((int length));
    86 static void		ChannelTimerProc _ANSI_ARGS_((
    87 				ClientData clientData));
    88 static int		CheckChannelErrors _ANSI_ARGS_((ChannelState *statePtr,
    89 				int direction));
    90 static int		CheckFlush _ANSI_ARGS_((Channel *chanPtr,
    91 				ChannelBuffer *bufPtr, int newlineFlag));
    92 static int		CheckForDeadChannel _ANSI_ARGS_((Tcl_Interp *interp,
    93 				ChannelState *statePtr));
    94 static void		CheckForStdChannelsBeingClosed _ANSI_ARGS_((
    95 				Tcl_Channel chan));
    96 static void		CleanupChannelHandlers _ANSI_ARGS_((
    97 				Tcl_Interp *interp, Channel *chanPtr));
    98 static int		CloseChannel _ANSI_ARGS_((Tcl_Interp *interp,
    99 				Channel *chanPtr, int errorCode));
   100 static void		CommonGetsCleanup _ANSI_ARGS_((Channel *chanPtr,
   101 				Tcl_Encoding encoding));
   102 static int		CopyAndTranslateBuffer _ANSI_ARGS_((
   103 				ChannelState *statePtr, char *result,
   104 				int space));
   105 static int		CopyBuffer _ANSI_ARGS_((
   106 				Channel *chanPtr, char *result, int space));
   107 static int		CopyData _ANSI_ARGS_((CopyState *csPtr, int mask));
   108 static void		CopyEventProc _ANSI_ARGS_((ClientData clientData,
   109 				int mask));
   110 static void		CreateScriptRecord _ANSI_ARGS_((
   111 				Tcl_Interp *interp, Channel *chanPtr,
   112 				int mask, Tcl_Obj *scriptPtr));
   113 static void		DeleteChannelTable _ANSI_ARGS_((
   114 				ClientData clientData, Tcl_Interp *interp));
   115 static void		DeleteScriptRecord _ANSI_ARGS_((Tcl_Interp *interp,
   116 				Channel *chanPtr, int mask));
   117 static int              DetachChannel _ANSI_ARGS_((Tcl_Interp *interp,
   118 				Tcl_Channel chan));
   119 static void		DiscardInputQueued _ANSI_ARGS_((ChannelState *statePtr,
   120 				int discardSavedBuffers));
   121 static void		DiscardOutputQueued _ANSI_ARGS_((
   122 				ChannelState *chanPtr));
   123 static int		DoRead _ANSI_ARGS_((Channel *chanPtr, char *srcPtr,
   124 				int slen));
   125 static int		DoWrite _ANSI_ARGS_((Channel *chanPtr, CONST char *src,
   126 				int srcLen));
   127 static int		DoReadChars _ANSI_ARGS_ ((Channel* chan,
   128 				Tcl_Obj* objPtr, int toRead, int appendFlag));
   129 static int		DoWriteChars _ANSI_ARGS_ ((Channel* chan,
   130 				CONST char* src, int len));
   131 static int		FilterInputBytes _ANSI_ARGS_((Channel *chanPtr,
   132 				GetsState *statePtr));
   133 static int		FlushChannel _ANSI_ARGS_((Tcl_Interp *interp,
   134 				Channel *chanPtr, int calledFromAsyncFlush));
   135 static Tcl_HashTable *	GetChannelTable _ANSI_ARGS_((Tcl_Interp *interp));
   136 static int		GetInput _ANSI_ARGS_((Channel *chanPtr));
   137 static int		HaveVersion _ANSI_ARGS_((Tcl_ChannelType *typePtr,
   138 				Tcl_ChannelTypeVersion minimumVersion));
   139 static void		PeekAhead _ANSI_ARGS_((Channel *chanPtr,
   140 				char **dstEndPtr, GetsState *gsPtr));
   141 static int		ReadBytes _ANSI_ARGS_((ChannelState *statePtr,
   142 				Tcl_Obj *objPtr, int charsLeft,
   143 				int *offsetPtr));
   144 static int		ReadChars _ANSI_ARGS_((ChannelState *statePtr,
   145 				Tcl_Obj *objPtr, int charsLeft,
   146 				int *offsetPtr, int *factorPtr));
   147 static void		RecycleBuffer _ANSI_ARGS_((ChannelState *statePtr,
   148 				ChannelBuffer *bufPtr, int mustDiscard));
   149 static int		StackSetBlockMode _ANSI_ARGS_((Channel *chanPtr,
   150 				int mode));
   151 static int		SetBlockMode _ANSI_ARGS_((Tcl_Interp *interp,
   152 				Channel *chanPtr, int mode));
   153 static void		StopCopy _ANSI_ARGS_((CopyState *csPtr));
   154 static int		TranslateInputEOL _ANSI_ARGS_((ChannelState *statePtr,
   155 				char *dst, CONST char *src,
   156 				int *dstLenPtr, int *srcLenPtr));
   157 static int		TranslateOutputEOL _ANSI_ARGS_((ChannelState *statePtr,
   158 				char *dst, CONST char *src,
   159 				int *dstLenPtr, int *srcLenPtr));
   160 static void		UpdateInterest _ANSI_ARGS_((Channel *chanPtr));
   161 static int		WriteBytes _ANSI_ARGS_((Channel *chanPtr,
   162 				CONST char *src, int srcLen));
   163 static int		WriteChars _ANSI_ARGS_((Channel *chanPtr,
   164 				CONST char *src, int srcLen));
   165 
   166 
   167 /*
   168  *---------------------------------------------------------------------------
   169  *
   170  * TclInitIOSubsystem --
   171  *
   172  *	Initialize all resources used by this subsystem on a per-process
   173  *	basis.  
   174  *
   175  * Results:
   176  *	None.
   177  *
   178  * Side effects:
   179  *	Depends on the memory subsystems.
   180  *
   181  *---------------------------------------------------------------------------
   182  */
   183 
   184 void
   185 TclInitIOSubsystem()
   186 {
   187     /*
   188      * By fetching thread local storage we take care of
   189      * allocating it for each thread.
   190      */
   191     (void) TCL_TSD_INIT(&dataKey);
   192 }   
   193 
   194 /*
   195  *-------------------------------------------------------------------------
   196  *
   197  * TclFinalizeIOSubsystem --
   198  *
   199  *	Releases all resources used by this subsystem on a per-thread
   200  *	basis.  Closes all extant channels that have not already been 
   201  *	closed because they were not owned by any interp.  
   202  *
   203  * Results:
   204  *	None.
   205  *
   206  * Side effects:
   207  *	Depends on encoding and memory subsystems.
   208  *
   209  *-------------------------------------------------------------------------
   210  */
   211 
   212 	/* ARGSUSED */
   213 void
   214 TclFinalizeIOSubsystem(void)
   215 {
   216     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
   217     Channel *chanPtr = NULL;	/* Iterates over open channels. */
   218     ChannelState *statePtr;	/* State of channel stack */
   219     int active = 1;		/* Flag == 1 while there's still work to do */
   220 
   221     /*
   222      * Walk all channel state structures known to this thread and
   223      * close corresponding channels.
   224      */
   225 
   226     while (active) {
   227 
   228 	/*
   229 	 * Iterate through the open channel list, and find the first
   230 	 * channel that isn't dead. We start from the head of the list
   231 	 * each time, because the close action on one channel can close
   232 	 * others.
   233 	 */
   234 
   235 	active = 0;
   236 	for (statePtr = tsdPtr->firstCSPtr;
   237 	     statePtr != NULL;
   238 	     statePtr = statePtr->nextCSPtr) {
   239 	    chanPtr = statePtr->topChanPtr;
   240 	    if (!(statePtr->flags & CHANNEL_DEAD)) {
   241 		active = 1;
   242 		break;
   243 	    }
   244 	}
   245 
   246 	/*
   247 	 * We've found a live channel.  Close it.
   248 	 */
   249 
   250 	if (active) {
   251 
   252 	    /*
   253 	     * Set the channel back into blocking mode to ensure that we 
   254 	     * wait for all data to flush out.
   255 	     */
   256 	    
   257 	    (void) Tcl_SetChannelOption(NULL, (Tcl_Channel) chanPtr,
   258 					"-blocking", "on");
   259 	    
   260 	    if ((chanPtr == (Channel *) tsdPtr->stdinChannel) ||
   261 		(chanPtr == (Channel *) tsdPtr->stdoutChannel) ||
   262 		(chanPtr == (Channel *) tsdPtr->stderrChannel)) {
   263 		/*
   264 		 * Decrement the refcount which was earlier artificially 
   265 		 * bumped up to keep the channel from being closed.
   266 		 */
   267 		
   268 		statePtr->refCount--;
   269 	    }
   270 	    
   271 	    if (statePtr->refCount <= 0) {
   272 		/*
   273 		 * Close it only if the refcount indicates that the channel 
   274 		 * is not referenced from any interpreter. If it is, that
   275 		 * interpreter will close the channel when it gets destroyed.
   276 		 */
   277 		
   278 		(void) Tcl_Close(NULL, (Tcl_Channel) chanPtr);
   279 	    } else {
   280 		/*
   281 		 * The refcount is greater than zero, so flush the channel.
   282 		 */
   283 		
   284 		Tcl_Flush((Tcl_Channel) chanPtr);
   285 		
   286 		/*
   287 		 * Call the device driver to actually close the underlying 
   288 		 * device for this channel.
   289 		 */
   290 		
   291 		if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) {
   292 		    (chanPtr->typePtr->closeProc)(chanPtr->instanceData, NULL);
   293 		} else {
   294 		    (chanPtr->typePtr->close2Proc)(chanPtr->instanceData,
   295 						   NULL, 0);
   296 		}
   297 		
   298 		/*
   299 		 * Finally, we clean up the fields in the channel data 
   300 		 * structure since all of them have been deleted already. 
   301 		 * We mark the channel with CHANNEL_DEAD to prevent any 
   302 		 * further IO operations
   303 		 * on it.
   304 		 */
   305 		
   306 		chanPtr->instanceData = NULL;
   307 		statePtr->flags |= CHANNEL_DEAD;
   308 	    }
   309 	}
   310     }
   311 
   312     TclpFinalizeSockets();
   313     TclpFinalizePipes();
   314 }
   315 
   316 
   317 /*
   318  *----------------------------------------------------------------------
   319  *
   320  * Tcl_SetStdChannel --
   321  *
   322  *	This function is used to change the channels that are used
   323  *	for stdin/stdout/stderr in new interpreters.
   324  *
   325  * Results:
   326  *	None
   327  *
   328  * Side effects:
   329  *	None.
   330  *
   331  *----------------------------------------------------------------------
   332  */
   333 
   334 EXPORT_C void
   335 Tcl_SetStdChannel(channel, type)
   336     Tcl_Channel channel;
   337     int type;			/* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */
   338 {
   339     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
   340     switch (type) {
   341 	case TCL_STDIN:
   342 	    tsdPtr->stdinInitialized = 1;
   343 	    tsdPtr->stdinChannel = channel;
   344 	    break;
   345 	case TCL_STDOUT:
   346 	    tsdPtr->stdoutInitialized = 1;
   347 	    tsdPtr->stdoutChannel = channel;
   348 	    break;
   349 	case TCL_STDERR:
   350 	    tsdPtr->stderrInitialized = 1;
   351 	    tsdPtr->stderrChannel = channel;
   352 	    break;
   353     }
   354 }
   355 
   356 /*
   357  *----------------------------------------------------------------------
   358  *
   359  * Tcl_GetStdChannel --
   360  *
   361  *	Returns the specified standard channel.
   362  *
   363  * Results:
   364  *	Returns the specified standard channel, or NULL.
   365  *
   366  * Side effects:
   367  *	May cause the creation of a standard channel and the underlying
   368  *	file.
   369  *
   370  *----------------------------------------------------------------------
   371  */
   372 EXPORT_C Tcl_Channel
   373 Tcl_GetStdChannel(type)
   374     int type;			/* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */
   375 {
   376     Tcl_Channel channel = NULL;
   377     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
   378 
   379     /*
   380      * If the channels were not created yet, create them now and
   381      * store them in the static variables. 
   382      */
   383 
   384     switch (type) {
   385 	case TCL_STDIN:
   386 	    if (!tsdPtr->stdinInitialized) {
   387 		tsdPtr->stdinChannel = TclpGetDefaultStdChannel(TCL_STDIN);
   388 		tsdPtr->stdinInitialized = 1;
   389 
   390 		/*
   391                  * Artificially bump the refcount to ensure that the channel
   392                  * is only closed on exit.
   393                  *
   394                  * NOTE: Must only do this if stdinChannel is not NULL. It
   395                  * can be NULL in situations where Tcl is unable to connect
   396                  * to the standard input.
   397                  */
   398 
   399                 if (tsdPtr->stdinChannel != (Tcl_Channel) NULL) {
   400                     (void) Tcl_RegisterChannel((Tcl_Interp *) NULL,
   401                             tsdPtr->stdinChannel);
   402                 }
   403 	    }
   404 	    channel = tsdPtr->stdinChannel;
   405 	    break;
   406 	case TCL_STDOUT:
   407 	    if (!tsdPtr->stdoutInitialized) {
   408 		tsdPtr->stdoutChannel = TclpGetDefaultStdChannel(TCL_STDOUT);
   409 		tsdPtr->stdoutInitialized = 1;
   410                 if (tsdPtr->stdoutChannel != (Tcl_Channel) NULL) {
   411                     (void) Tcl_RegisterChannel((Tcl_Interp *) NULL,
   412                             tsdPtr->stdoutChannel);
   413                 }
   414 	    }
   415 	    channel = tsdPtr->stdoutChannel;
   416 	    break;
   417 	case TCL_STDERR:
   418 	    if (!tsdPtr->stderrInitialized) {
   419 		tsdPtr->stderrChannel = TclpGetDefaultStdChannel(TCL_STDERR);
   420 		tsdPtr->stderrInitialized = 1;
   421                 if (tsdPtr->stderrChannel != (Tcl_Channel) NULL) {
   422                     (void) Tcl_RegisterChannel((Tcl_Interp *) NULL,
   423                             tsdPtr->stderrChannel);
   424                 }
   425 	    }
   426 	    channel = tsdPtr->stderrChannel;
   427 	    break;
   428     }
   429     return channel;
   430 }
   431 
   432 
   433 /*
   434  *----------------------------------------------------------------------
   435  *
   436  * Tcl_CreateCloseHandler
   437  *
   438  *	Creates a close callback which will be called when the channel is
   439  *	closed.
   440  *
   441  * Results:
   442  *	None.
   443  *
   444  * Side effects:
   445  *	Causes the callback to be called in the future when the channel
   446  *	will be closed.
   447  *
   448  *----------------------------------------------------------------------
   449  */
   450 
   451 EXPORT_C void
   452 Tcl_CreateCloseHandler(chan, proc, clientData)
   453     Tcl_Channel chan;		/* The channel for which to create the
   454                                  * close callback. */
   455     Tcl_CloseProc *proc;	/* The callback routine to call when the
   456                                  * channel will be closed. */
   457     ClientData clientData;	/* Arbitrary data to pass to the
   458                                  * close callback. */
   459 {
   460     ChannelState *statePtr;
   461     CloseCallback *cbPtr;
   462 
   463     statePtr = ((Channel *) chan)->state;
   464 
   465     cbPtr = (CloseCallback *) ckalloc((unsigned) sizeof(CloseCallback));
   466     cbPtr->proc = proc;
   467     cbPtr->clientData = clientData;
   468 
   469     cbPtr->nextPtr = statePtr->closeCbPtr;
   470     statePtr->closeCbPtr = cbPtr;
   471 }
   472 
   473 /*
   474  *----------------------------------------------------------------------
   475  *
   476  * Tcl_DeleteCloseHandler --
   477  *
   478  *	Removes a callback that would have been called on closing
   479  *	the channel. If there is no matching callback then this
   480  *	function has no effect.
   481  *
   482  * Results:
   483  *	None.
   484  *
   485  * Side effects:
   486  *	The callback will not be called in the future when the channel
   487  *	is eventually closed.
   488  *
   489  *----------------------------------------------------------------------
   490  */
   491 
   492 EXPORT_C void
   493 Tcl_DeleteCloseHandler(chan, proc, clientData)
   494     Tcl_Channel chan;		/* The channel for which to cancel the
   495                                  * close callback. */
   496     Tcl_CloseProc *proc;	/* The procedure for the callback to
   497                                  * remove. */
   498     ClientData clientData;	/* The callback data for the callback
   499                                  * to remove. */
   500 {
   501     ChannelState *statePtr;
   502     CloseCallback *cbPtr, *cbPrevPtr;
   503 
   504     statePtr = ((Channel *) chan)->state;
   505     for (cbPtr = statePtr->closeCbPtr, cbPrevPtr = (CloseCallback *) NULL;
   506 	 cbPtr != (CloseCallback *) NULL;
   507 	 cbPtr = cbPtr->nextPtr) {
   508         if ((cbPtr->proc == proc) && (cbPtr->clientData == clientData)) {
   509             if (cbPrevPtr == (CloseCallback *) NULL) {
   510                 statePtr->closeCbPtr = cbPtr->nextPtr;
   511             }
   512             ckfree((char *) cbPtr);
   513             break;
   514         } else {
   515             cbPrevPtr = cbPtr;
   516         }
   517     }
   518 }
   519 
   520 /*
   521  *----------------------------------------------------------------------
   522  *
   523  * GetChannelTable --
   524  *
   525  *	Gets and potentially initializes the channel table for an
   526  *	interpreter. If it is initializing the table it also inserts
   527  *	channels for stdin, stdout and stderr if the interpreter is
   528  *	trusted.
   529  *
   530  * Results:
   531  *	A pointer to the hash table created, for use by the caller.
   532  *
   533  * Side effects:
   534  *	Initializes the channel table for an interpreter. May create
   535  *	channels for stdin, stdout and stderr.
   536  *
   537  *----------------------------------------------------------------------
   538  */
   539 
   540 static Tcl_HashTable *
   541 GetChannelTable(interp)
   542     Tcl_Interp *interp;
   543 {
   544     Tcl_HashTable *hTblPtr;	/* Hash table of channels. */
   545     Tcl_Channel stdinChan, stdoutChan, stderrChan;
   546 
   547     hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL);
   548     if (hTblPtr == (Tcl_HashTable *) NULL) {
   549         hTblPtr = (Tcl_HashTable *) ckalloc((unsigned) sizeof(Tcl_HashTable));
   550         Tcl_InitHashTable(hTblPtr, TCL_STRING_KEYS);
   551 
   552         (void) Tcl_SetAssocData(interp, "tclIO",
   553                 (Tcl_InterpDeleteProc *) DeleteChannelTable,
   554                 (ClientData) hTblPtr);
   555 
   556         /*
   557          * If the interpreter is trusted (not "safe"), insert channels
   558          * for stdin, stdout and stderr (possibly creating them in the
   559          * process).
   560          */
   561 
   562         if (Tcl_IsSafe(interp) == 0) {
   563             stdinChan = Tcl_GetStdChannel(TCL_STDIN);
   564             if (stdinChan != NULL) {
   565                 Tcl_RegisterChannel(interp, stdinChan);
   566             }
   567             stdoutChan = Tcl_GetStdChannel(TCL_STDOUT);
   568             if (stdoutChan != NULL) {
   569                 Tcl_RegisterChannel(interp, stdoutChan);
   570             }
   571             stderrChan = Tcl_GetStdChannel(TCL_STDERR);
   572             if (stderrChan != NULL) {
   573                 Tcl_RegisterChannel(interp, stderrChan);
   574             }
   575         }
   576 
   577     }
   578     return hTblPtr;
   579 }
   580 
   581 /*
   582  *----------------------------------------------------------------------
   583  *
   584  * DeleteChannelTable --
   585  *
   586  *	Deletes the channel table for an interpreter, closing any open
   587  *	channels whose refcount reaches zero. This procedure is invoked
   588  *	when an interpreter is deleted, via the AssocData cleanup
   589  *	mechanism.
   590  *
   591  * Results:
   592  *	None.
   593  *
   594  * Side effects:
   595  *	Deletes the hash table of channels. May close channels. May flush
   596  *	output on closed channels. Removes any channeEvent handlers that were
   597  *	registered in this interpreter.
   598  *
   599  *----------------------------------------------------------------------
   600  */
   601 
   602 static void
   603 DeleteChannelTable(clientData, interp)
   604     ClientData clientData;	/* The per-interpreter data structure. */
   605     Tcl_Interp *interp;		/* The interpreter being deleted. */
   606 {
   607     Tcl_HashTable *hTblPtr;	/* The hash table. */
   608     Tcl_HashSearch hSearch;	/* Search variable. */
   609     Tcl_HashEntry *hPtr;	/* Search variable. */
   610     Channel *chanPtr;		/* Channel being deleted. */
   611     ChannelState *statePtr;	/* State of Channel being deleted. */
   612     EventScriptRecord *sPtr, *prevPtr, *nextPtr;
   613     				/* Variables to loop over all channel events
   614                                  * registered, to delete the ones that refer
   615                                  * to the interpreter being deleted. */
   616 
   617     /*
   618      * Delete all the registered channels - this will close channels whose
   619      * refcount reaches zero.
   620      */
   621     
   622     hTblPtr = (Tcl_HashTable *) clientData;
   623     for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch);
   624 	 hPtr != (Tcl_HashEntry *) NULL;
   625 	 hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch)) {
   626 
   627         chanPtr = (Channel *) Tcl_GetHashValue(hPtr);
   628 	statePtr = chanPtr->state;
   629 
   630         /*
   631          * Remove any fileevents registered in this interpreter.
   632          */
   633         
   634         for (sPtr = statePtr->scriptRecordPtr,
   635                  prevPtr = (EventScriptRecord *) NULL;
   636 	     sPtr != (EventScriptRecord *) NULL;
   637 	     sPtr = nextPtr) {
   638             nextPtr = sPtr->nextPtr;
   639             if (sPtr->interp == interp) {
   640                 if (prevPtr == (EventScriptRecord *) NULL) {
   641                     statePtr->scriptRecordPtr = nextPtr;
   642                 } else {
   643                     prevPtr->nextPtr = nextPtr;
   644                 }
   645 
   646                 Tcl_DeleteChannelHandler((Tcl_Channel) chanPtr,
   647                         TclChannelEventScriptInvoker, (ClientData) sPtr);
   648 
   649 		Tcl_DecrRefCount(sPtr->scriptPtr);
   650                 ckfree((char *) sPtr);
   651             } else {
   652                 prevPtr = sPtr;
   653             }
   654         }
   655 
   656         /*
   657          * Cannot call Tcl_UnregisterChannel because that procedure calls
   658          * Tcl_GetAssocData to get the channel table, which might already
   659          * be inaccessible from the interpreter structure. Instead, we
   660          * emulate the behavior of Tcl_UnregisterChannel directly here.
   661          */
   662 
   663         Tcl_DeleteHashEntry(hPtr);
   664         statePtr->refCount--;
   665         if (statePtr->refCount <= 0) {
   666             if (!(statePtr->flags & BG_FLUSH_SCHEDULED)) {
   667                 (void) Tcl_Close(interp, (Tcl_Channel) chanPtr);
   668             }
   669         }
   670     }
   671     Tcl_DeleteHashTable(hTblPtr);
   672     ckfree((char *) hTblPtr);
   673 }
   674 
   675 /*
   676  *----------------------------------------------------------------------
   677  *
   678  * CheckForStdChannelsBeingClosed --
   679  *
   680  *	Perform special handling for standard channels being closed. When
   681  *	given a standard channel, if the refcount is now 1, it means that
   682  *	the last reference to the standard channel is being explicitly
   683  *	closed. Now bump the refcount artificially down to 0, to ensure the
   684  *	normal handling of channels being closed will occur. Also reset the
   685  *	static pointer to the channel to NULL, to avoid dangling references.
   686  *
   687  * Results:
   688  *	None.
   689  *
   690  * Side effects:
   691  *	Manipulates the refcount on standard channels. May smash the global
   692  *	static pointer to a standard channel.
   693  *
   694  *----------------------------------------------------------------------
   695  */
   696 
   697 static void
   698 CheckForStdChannelsBeingClosed(chan)
   699     Tcl_Channel chan;
   700 {
   701     ChannelState *statePtr = ((Channel *) chan)->state;
   702     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
   703 
   704     if ((chan == tsdPtr->stdinChannel) && (tsdPtr->stdinInitialized)) {
   705         if (statePtr->refCount < 2) {
   706             statePtr->refCount = 0;
   707             tsdPtr->stdinChannel = NULL;
   708             return;
   709         }
   710     } else if ((chan == tsdPtr->stdoutChannel)
   711 	    && (tsdPtr->stdoutInitialized)) {
   712         if (statePtr->refCount < 2) {
   713             statePtr->refCount = 0;
   714             tsdPtr->stdoutChannel = NULL;
   715             return;
   716         }
   717     } else if ((chan == tsdPtr->stderrChannel)
   718 	    && (tsdPtr->stderrInitialized)) {
   719         if (statePtr->refCount < 2) {
   720             statePtr->refCount = 0;
   721             tsdPtr->stderrChannel = NULL;
   722             return;
   723         }
   724     }
   725 }
   726 
   727 /*
   728  *----------------------------------------------------------------------
   729  *
   730  * Tcl_IsStandardChannel --
   731  *
   732  *	Test if the given channel is a standard channel.  No attempt
   733  *	is made to check if the channel or the standard channels
   734  *	are initialized or otherwise valid.
   735  *
   736  * Results:
   737  *	Returns 1 if true, 0 if false.
   738  *
   739  * Side effects:
   740  *      None.
   741  *
   742  *----------------------------------------------------------------------
   743  */
   744 EXPORT_C int 
   745 Tcl_IsStandardChannel(chan)
   746     Tcl_Channel chan;		/* Channel to check. */
   747 {
   748     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
   749 
   750     if ((chan == tsdPtr->stdinChannel) 
   751 	|| (chan == tsdPtr->stdoutChannel)
   752 	|| (chan == tsdPtr->stderrChannel)) {
   753 	return 1;
   754     } else {
   755 	return 0;
   756     }
   757 }
   758 
   759 /*
   760  *----------------------------------------------------------------------
   761  *
   762  * Tcl_RegisterChannel --
   763  *
   764  *	Adds an already-open channel to the channel table of an interpreter.
   765  *	If the interpreter passed as argument is NULL, it only increments
   766  *	the channel refCount.
   767  *
   768  * Results:
   769  *	None.
   770  *
   771  * Side effects:
   772  *	May increment the reference count of a channel.
   773  *
   774  *----------------------------------------------------------------------
   775  */
   776 
   777 EXPORT_C void
   778 Tcl_RegisterChannel(interp, chan)
   779     Tcl_Interp *interp;		/* Interpreter in which to add the channel. */
   780     Tcl_Channel chan;		/* The channel to add to this interpreter
   781                                  * channel table. */
   782 {
   783     Tcl_HashTable *hTblPtr;	/* Hash table of channels. */
   784     Tcl_HashEntry *hPtr;	/* Search variable. */
   785     int new;			/* Is the hash entry new or does it exist? */
   786     Channel *chanPtr;		/* The actual channel. */
   787     ChannelState *statePtr;	/* State of the actual channel. */
   788 
   789     /*
   790      * Always (un)register bottom-most channel in the stack.  This makes
   791      * management of the channel list easier because no manipulation is
   792      * necessary during (un)stack operation.
   793      */
   794     chanPtr = ((Channel *) chan)->state->bottomChanPtr;
   795     statePtr = chanPtr->state;
   796 
   797     if (statePtr->channelName == (CONST char *) NULL) {
   798         panic("Tcl_RegisterChannel: channel without name");
   799     }
   800     if (interp != (Tcl_Interp *) NULL) {
   801         hTblPtr = GetChannelTable(interp);
   802         hPtr = Tcl_CreateHashEntry(hTblPtr, statePtr->channelName, &new);
   803         if (new == 0) {
   804             if (chan == (Tcl_Channel) Tcl_GetHashValue(hPtr)) {
   805                 return;
   806             }
   807 
   808 	    panic("Tcl_RegisterChannel: duplicate channel names");
   809         }
   810         Tcl_SetHashValue(hPtr, (ClientData) chanPtr);
   811     }
   812 
   813     statePtr->refCount++;
   814 }
   815 
   816 /*
   817  *----------------------------------------------------------------------
   818  *
   819  * Tcl_UnregisterChannel --
   820  *
   821  *	Deletes the hash entry for a channel associated with an interpreter.
   822  *	If the interpreter given as argument is NULL, it only decrements the
   823  *	reference count.  (This all happens in the Tcl_DetachChannel helper
   824  *	function).
   825  *	
   826  *	Finally, if the reference count of the channel drops to zero,
   827  *	it is deleted.
   828  *
   829  * Results:
   830  *	A standard Tcl result.
   831  *
   832  * Side effects:
   833  *	Calls Tcl_DetachChannel which deletes the hash entry for a channel 
   834  *	associated with an interpreter.
   835  *	
   836  *	May delete the channel, which can have a variety of consequences,
   837  *	especially if we are forced to close the channel.
   838  *
   839  *----------------------------------------------------------------------
   840  */
   841 
   842 EXPORT_C int
   843 Tcl_UnregisterChannel(interp, chan)
   844     Tcl_Interp *interp;		/* Interpreter in which channel is defined. */
   845     Tcl_Channel chan;		/* Channel to delete. */
   846 {
   847     ChannelState *statePtr;	/* State of the real channel. */
   848 
   849     statePtr = ((Channel *) chan)->state->bottomChanPtr->state;
   850  
   851     if (statePtr->flags & CHANNEL_INCLOSE) {
   852         if (interp != (Tcl_Interp*) NULL) {
   853 	    Tcl_AppendResult(interp, 
   854 	     "Illegal recursive call to close through close-handler of channel",
   855 	     (char *) NULL);
   856 	}
   857         return TCL_ERROR;
   858     }
   859  
   860     if (DetachChannel(interp, chan) != TCL_OK) {
   861         return TCL_OK;
   862     }
   863     
   864     statePtr = ((Channel *) chan)->state->bottomChanPtr->state;
   865 
   866     /*
   867      * Perform special handling for standard channels being closed. If the
   868      * refCount is now 1 it means that the last reference to the standard
   869      * channel is being explicitly closed, so bump the refCount down
   870      * artificially to 0. This will ensure that the channel is actually
   871      * closed, below. Also set the static pointer to NULL for the channel.
   872      */
   873 
   874     CheckForStdChannelsBeingClosed(chan);
   875 
   876     /*
   877      * If the refCount reached zero, close the actual channel.
   878      */
   879 
   880     if (statePtr->refCount <= 0) {
   881 
   882         /*
   883          * Ensure that if there is another buffer, it gets flushed
   884          * whether or not we are doing a background flush.
   885          */
   886 
   887         if ((statePtr->curOutPtr != NULL) &&
   888                 (statePtr->curOutPtr->nextAdded >
   889                         statePtr->curOutPtr->nextRemoved)) {
   890             statePtr->flags |= BUFFER_READY;
   891         }
   892 	Tcl_Preserve((ClientData)statePtr);
   893         if (!(statePtr->flags & BG_FLUSH_SCHEDULED)) {
   894 	    /* We don't want to re-enter Tcl_Close */
   895 	    if (!(statePtr->flags & CHANNEL_CLOSED)) {
   896 		if (Tcl_Close(interp, chan) != TCL_OK) {
   897 		    statePtr->flags |= CHANNEL_CLOSED;
   898 		    Tcl_Release((ClientData)statePtr);
   899 		    return TCL_ERROR;
   900 		}
   901 	    }
   902         }
   903         statePtr->flags |= CHANNEL_CLOSED;
   904 	Tcl_Release((ClientData)statePtr);
   905     }
   906     return TCL_OK;
   907 }
   908 
   909 /*
   910  *----------------------------------------------------------------------
   911  *
   912  * Tcl_DetachChannel --
   913  *
   914  *	Deletes the hash entry for a channel associated with an interpreter.
   915  *	If the interpreter given as argument is NULL, it only decrements the
   916  *	reference count.  Even if the ref count drops to zero, the 
   917  *	channel is NOT closed or cleaned up.  This allows a channel to
   918  *	be detached from an interpreter and left in the same state it
   919  *	was in when it was originally returned by 'Tcl_OpenFileChannel',
   920  *	for example.
   921  *	
   922  *	This function cannot be used on the standard channels, and
   923  *	will return TCL_ERROR if that is attempted.
   924  *	
   925  *	This function should only be necessary for special purposes
   926  *	in which you need to generate a pristine channel from one
   927  *	that has already been used.  All ordinary purposes will almost
   928  *	always want to use Tcl_UnregisterChannel instead.
   929  *	
   930  *	Provided the channel is not attached to any other interpreter,
   931  *	it can then be closed with Tcl_Close, rather than with 
   932  *	Tcl_UnregisterChannel.
   933  *
   934  * Results:
   935  *	A standard Tcl result.  If the channel is not currently registered
   936  *	with the given interpreter, TCL_ERROR is returned, otherwise
   937  *	TCL_OK.  However no error messages are left in the interp's result.
   938  *
   939  * Side effects:
   940  *	Deletes the hash entry for a channel associated with an 
   941  *	interpreter.
   942  *
   943  *----------------------------------------------------------------------
   944  */
   945 
   946 EXPORT_C int
   947 Tcl_DetachChannel(interp, chan)
   948     Tcl_Interp *interp;		/* Interpreter in which channel is defined. */
   949     Tcl_Channel chan;		/* Channel to delete. */
   950 {
   951     if (Tcl_IsStandardChannel(chan)) {
   952         return TCL_ERROR;
   953     }
   954     
   955     return DetachChannel(interp, chan);
   956 }
   957 
   958 /*
   959  *----------------------------------------------------------------------
   960  *
   961  * DetachChannel --
   962  *
   963  *	Deletes the hash entry for a channel associated with an interpreter.
   964  *	If the interpreter given as argument is NULL, it only decrements the
   965  *	reference count.  Even if the ref count drops to zero, the 
   966  *	channel is NOT closed or cleaned up.  This allows a channel to
   967  *	be detached from an interpreter and left in the same state it
   968  *	was in when it was originally returned by 'Tcl_OpenFileChannel',
   969  *	for example.
   970  *
   971  * Results:
   972  *	A standard Tcl result.  If the channel is not currently registered
   973  *	with the given interpreter, TCL_ERROR is returned, otherwise
   974  *	TCL_OK.  However no error messages are left in the interp's result.
   975  *
   976  * Side effects:
   977  *	Deletes the hash entry for a channel associated with an 
   978  *	interpreter.
   979  *
   980  *----------------------------------------------------------------------
   981  */
   982 
   983 static int
   984 DetachChannel(interp, chan)
   985     Tcl_Interp *interp;		/* Interpreter in which channel is defined. */
   986     Tcl_Channel chan;		/* Channel to delete. */
   987 {
   988     Tcl_HashTable *hTblPtr;	/* Hash table of channels. */
   989     Tcl_HashEntry *hPtr;	/* Search variable. */
   990     Channel *chanPtr;		/* The real IO channel. */
   991     ChannelState *statePtr;	/* State of the real channel. */
   992 
   993     /*
   994      * Always (un)register bottom-most channel in the stack.  This makes
   995      * management of the channel list easier because no manipulation is
   996      * necessary during (un)stack operation.
   997      */
   998     chanPtr = ((Channel *) chan)->state->bottomChanPtr;
   999     statePtr = chanPtr->state;
  1000 
  1001     if (interp != (Tcl_Interp *) NULL) {
  1002 	hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL);
  1003 	if (hTblPtr == (Tcl_HashTable *) NULL) {
  1004 	    return TCL_ERROR;
  1005 	}
  1006 	hPtr = Tcl_FindHashEntry(hTblPtr, statePtr->channelName);
  1007 	if (hPtr == (Tcl_HashEntry *) NULL) {
  1008 	    return TCL_ERROR;
  1009 	}
  1010 	if ((Channel *) Tcl_GetHashValue(hPtr) != chanPtr) {
  1011 	    return TCL_ERROR;
  1012 	}
  1013 	Tcl_DeleteHashEntry(hPtr);
  1014 
  1015 	/*
  1016 	 * Remove channel handlers that refer to this interpreter, so that they
  1017 	 * will not be present if the actual close is delayed and more events
  1018 	 * happen on the channel. This may occur if the channel is shared
  1019 	 * between several interpreters, or if the channel has async
  1020 	 * flushing active.
  1021 	 */
  1022     
  1023 	CleanupChannelHandlers(interp, chanPtr);
  1024     }
  1025 
  1026     statePtr->refCount--;
  1027     
  1028     return TCL_OK;
  1029 }
  1030 
  1031 
  1032 /*
  1033  *---------------------------------------------------------------------------
  1034  *
  1035  * Tcl_GetChannel --
  1036  *
  1037  *	Finds an existing Tcl_Channel structure by name in a given
  1038  *	interpreter. This function is public because it is used by
  1039  *	channel-type-specific functions.
  1040  *
  1041  * Results:
  1042  *	A Tcl_Channel or NULL on failure. If failed, interp's result
  1043  *	object contains an error message.  *modePtr is filled with the
  1044  *	modes in which the channel was opened.
  1045  *
  1046  * Side effects:
  1047  *	None.
  1048  *
  1049  *---------------------------------------------------------------------------
  1050  */
  1051 
  1052 EXPORT_C Tcl_Channel
  1053 Tcl_GetChannel(interp, chanName, modePtr)
  1054     Tcl_Interp *interp;		/* Interpreter in which to find or create
  1055                                  * the channel. */
  1056     CONST char *chanName;	/* The name of the channel. */
  1057     int *modePtr;		/* Where to store the mode in which the
  1058                                  * channel was opened? Will contain an ORed
  1059                                  * combination of TCL_READABLE and
  1060                                  * TCL_WRITABLE, if non-NULL. */
  1061 {
  1062     Channel *chanPtr;		/* The actual channel. */
  1063     Tcl_HashTable *hTblPtr;	/* Hash table of channels. */
  1064     Tcl_HashEntry *hPtr;	/* Search variable. */
  1065     CONST char *name;		/* Translated name. */
  1066 
  1067     /*
  1068      * Substitute "stdin", etc.  Note that even though we immediately
  1069      * find the channel using Tcl_GetStdChannel, we still need to look
  1070      * it up in the specified interpreter to ensure that it is present
  1071      * in the channel table.  Otherwise, safe interpreters would always
  1072      * have access to the standard channels.
  1073      */
  1074 
  1075     name = chanName;
  1076     if ((chanName[0] == 's') && (chanName[1] == 't')) {
  1077 	chanPtr = NULL;
  1078 	if (strcmp(chanName, "stdin") == 0) {
  1079 	    chanPtr = (Channel *) Tcl_GetStdChannel(TCL_STDIN);
  1080 	} else if (strcmp(chanName, "stdout") == 0) {
  1081 	    chanPtr = (Channel *) Tcl_GetStdChannel(TCL_STDOUT);
  1082 	} else if (strcmp(chanName, "stderr") == 0) {
  1083 	    chanPtr = (Channel *) Tcl_GetStdChannel(TCL_STDERR);
  1084 	}
  1085 	if (chanPtr != NULL) {
  1086 	    name = chanPtr->state->channelName;
  1087 	}
  1088     }
  1089 
  1090     hTblPtr = GetChannelTable(interp);
  1091     hPtr = Tcl_FindHashEntry(hTblPtr, name);
  1092     if (hPtr == (Tcl_HashEntry *) NULL) {
  1093         Tcl_AppendResult(interp, "can not find channel named \"",
  1094                 chanName, "\"", (char *) NULL);
  1095         return NULL;
  1096     }
  1097 
  1098     /*
  1099      * Always return bottom-most channel in the stack.  This one lives
  1100      * the longest - other channels may go away unnoticed.
  1101      * The other APIs compensate where necessary to retrieve the
  1102      * topmost channel again.
  1103      */
  1104     chanPtr = (Channel *) Tcl_GetHashValue(hPtr);
  1105     chanPtr = chanPtr->state->bottomChanPtr;
  1106     if (modePtr != NULL) {
  1107         *modePtr = (chanPtr->state->flags & (TCL_READABLE|TCL_WRITABLE));
  1108     }
  1109     
  1110     return (Tcl_Channel) chanPtr;
  1111 }
  1112 
  1113 /*
  1114  *----------------------------------------------------------------------
  1115  *
  1116  * Tcl_CreateChannel --
  1117  *
  1118  *	Creates a new entry in the hash table for a Tcl_Channel
  1119  *	record.
  1120  *
  1121  * Results:
  1122  *	Returns the new Tcl_Channel.
  1123  *
  1124  * Side effects:
  1125  *	Creates a new Tcl_Channel instance and inserts it into the
  1126  *	hash table.
  1127  *
  1128  *----------------------------------------------------------------------
  1129  */
  1130 
  1131 EXPORT_C Tcl_Channel
  1132 Tcl_CreateChannel(typePtr, chanName, instanceData, mask)
  1133     Tcl_ChannelType *typePtr;	/* The channel type record. */
  1134     CONST char *chanName;	/* Name of channel to record. */
  1135     ClientData instanceData;	/* Instance specific data. */
  1136     int mask;			/* TCL_READABLE & TCL_WRITABLE to indicate
  1137                                  * if the channel is readable, writable. */
  1138 {
  1139     Channel *chanPtr;		/* The channel structure newly created. */
  1140     ChannelState *statePtr;	/* The stack-level independent state info
  1141 				 * for the channel. */
  1142     CONST char *name;
  1143     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
  1144 
  1145     /*
  1146      * With the change of the Tcl_ChannelType structure to use a version in
  1147      * 8.3.2+, we have to make sure that our assumption that the structure
  1148      * remains a binary compatible size is true.
  1149      *
  1150      * If this assertion fails on some system, then it can be removed
  1151      * only if the user recompiles code with older channel drivers in
  1152      * the new system as well.
  1153      */
  1154 
  1155     assert(sizeof(Tcl_ChannelTypeVersion) == sizeof(Tcl_DriverBlockModeProc*));
  1156 
  1157     /*
  1158      * JH: We could subsequently memset these to 0 to avoid the
  1159      * numerous assignments to 0/NULL below.
  1160      */
  1161     chanPtr  = (Channel *) ckalloc((unsigned) sizeof(Channel));
  1162     statePtr = (ChannelState *) ckalloc((unsigned) sizeof(ChannelState));
  1163     chanPtr->state = statePtr;
  1164 
  1165     chanPtr->instanceData	= instanceData;
  1166     chanPtr->typePtr		= typePtr;
  1167 
  1168     /*
  1169      * Set all the bits that are part of the stack-independent state
  1170      * information for the channel.
  1171      */
  1172 
  1173     if (chanName != (char *) NULL) {
  1174 	char *tmp = ckalloc((unsigned) (strlen(chanName) + 1));
  1175         statePtr->channelName = tmp;
  1176         strcpy(tmp, chanName);
  1177     } else {
  1178         panic("Tcl_CreateChannel: NULL channel name");
  1179     }
  1180 
  1181     statePtr->flags		= mask;
  1182 
  1183     /*
  1184      * Set the channel to system default encoding.
  1185      */
  1186 
  1187     statePtr->encoding = NULL;
  1188     name = Tcl_GetEncodingName(NULL);
  1189     if (strcmp(name, "binary") != 0) {
  1190     	statePtr->encoding = Tcl_GetEncoding(NULL, name);
  1191     }
  1192     statePtr->inputEncodingState	= NULL;
  1193     statePtr->inputEncodingFlags	= TCL_ENCODING_START;
  1194     statePtr->outputEncodingState	= NULL;
  1195     statePtr->outputEncodingFlags	= TCL_ENCODING_START;
  1196 
  1197     /*
  1198      * Set the channel up initially in AUTO input translation mode to
  1199      * accept "\n", "\r" and "\r\n". Output translation mode is set to
  1200      * a platform specific default value. The eofChar is set to 0 for both
  1201      * input and output, so that Tcl does not look for an in-file EOF
  1202      * indicator (e.g. ^Z) and does not append an EOF indicator to files.
  1203      */
  1204 
  1205     statePtr->inputTranslation	= TCL_TRANSLATE_AUTO;
  1206     statePtr->outputTranslation	= TCL_PLATFORM_TRANSLATION;
  1207     statePtr->inEofChar		= 0;
  1208     statePtr->outEofChar	= 0;
  1209 
  1210     statePtr->unreportedError	= 0;
  1211     statePtr->refCount		= 0;
  1212     statePtr->closeCbPtr	= (CloseCallback *) NULL;
  1213     statePtr->curOutPtr		= (ChannelBuffer *) NULL;
  1214     statePtr->outQueueHead	= (ChannelBuffer *) NULL;
  1215     statePtr->outQueueTail	= (ChannelBuffer *) NULL;
  1216     statePtr->saveInBufPtr	= (ChannelBuffer *) NULL;
  1217     statePtr->inQueueHead	= (ChannelBuffer *) NULL;
  1218     statePtr->inQueueTail	= (ChannelBuffer *) NULL;
  1219     statePtr->chPtr		= (ChannelHandler *) NULL;
  1220     statePtr->interestMask	= 0;
  1221     statePtr->scriptRecordPtr	= (EventScriptRecord *) NULL;
  1222     statePtr->bufSize		= CHANNELBUFFER_DEFAULT_SIZE;
  1223     statePtr->timer		= NULL;
  1224     statePtr->csPtr		= NULL;
  1225 
  1226     statePtr->outputStage	= NULL;
  1227     if ((statePtr->encoding != NULL) && (statePtr->flags & TCL_WRITABLE)) {
  1228 	statePtr->outputStage = (char *)
  1229 	    ckalloc((unsigned) (statePtr->bufSize + 2));
  1230     }
  1231 
  1232     /*
  1233      * As we are creating the channel, it is obviously the top for now
  1234      */
  1235     statePtr->topChanPtr	= chanPtr;
  1236     statePtr->bottomChanPtr	= chanPtr;
  1237     chanPtr->downChanPtr	= (Channel *) NULL;
  1238     chanPtr->upChanPtr		= (Channel *) NULL;
  1239     chanPtr->inQueueHead        = (ChannelBuffer*) NULL;
  1240     chanPtr->inQueueTail        = (ChannelBuffer*) NULL;
  1241 
  1242     /*
  1243      * Link the channel into the list of all channels; create an on-exit
  1244      * handler if there is not one already, to close off all the channels
  1245      * in the list on exit.
  1246      *
  1247      * JH: Could call Tcl_SpliceChannel, but need to avoid NULL check.
  1248      *
  1249      * TIP #218.
  1250      * AK: Just initialize the field to NULL before invoking Tcl_SpliceChannel
  1251      *     We need Tcl_SpliceChannel, for the threadAction calls.
  1252      *     There is no real reason to duplicate all of this.
  1253      * NOTE: All drivers using thread actions now have to perform their TSD
  1254      *       manipulation only in their thread action proc. Doing it when
  1255      *       creating their instance structures will collide with the thread
  1256      *       action activity and lead to damaged lists.
  1257      */
  1258 
  1259     statePtr->nextCSPtr = (ChannelState *) NULL;
  1260     Tcl_SpliceChannel ((Tcl_Channel) chanPtr);
  1261 
  1262     /*
  1263      * Install this channel in the first empty standard channel slot, if
  1264      * the channel was previously closed explicitly.
  1265      */
  1266 #if TCL_INHERIT_STD_CHANNELS
  1267     if ((tsdPtr->stdinChannel == NULL) &&
  1268 	    (tsdPtr->stdinInitialized == 1)) {
  1269 	Tcl_SetStdChannel((Tcl_Channel) chanPtr, TCL_STDIN);
  1270         Tcl_RegisterChannel((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr);
  1271     } else if ((tsdPtr->stdoutChannel == NULL) &&
  1272 	    (tsdPtr->stdoutInitialized == 1)) {
  1273 	Tcl_SetStdChannel((Tcl_Channel) chanPtr, TCL_STDOUT);
  1274         Tcl_RegisterChannel((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr);
  1275     } else if ((tsdPtr->stderrChannel == NULL) &&
  1276 	    (tsdPtr->stderrInitialized == 1)) {
  1277 	Tcl_SetStdChannel((Tcl_Channel) chanPtr, TCL_STDERR);
  1278         Tcl_RegisterChannel((Tcl_Interp *) NULL, (Tcl_Channel) chanPtr);
  1279     }
  1280 #endif
  1281     return (Tcl_Channel) chanPtr;
  1282 }
  1283 
  1284 /*
  1285  *----------------------------------------------------------------------
  1286  *
  1287  * Tcl_StackChannel --
  1288  *
  1289  *	Replaces an entry in the hash table for a Tcl_Channel
  1290  *	record. The replacement is a new channel with same name,
  1291  *	it supercedes the replaced channel. Input and output of
  1292  *	the superceded channel is now going through the newly
  1293  *	created channel and allows the arbitrary filtering/manipulation
  1294  *	of the dataflow.
  1295  *
  1296  *	Andreas Kupries <a.kupries@westend.com>, 12/13/1998
  1297  *	"Trf-Patch for filtering channels"
  1298  *
  1299  * Results:
  1300  *	Returns the new Tcl_Channel, which actually contains the
  1301  *      saved information about prevChan.
  1302  *
  1303  * Side effects:
  1304  *    A new channel structure is allocated and linked below
  1305  *    the existing channel.  The channel operations and client
  1306  *    data of the existing channel are copied down to the newly
  1307  *    created channel, and the current channel has its operations
  1308  *    replaced by the new typePtr.
  1309  *
  1310  *----------------------------------------------------------------------
  1311  */
  1312 
  1313 EXPORT_C Tcl_Channel
  1314 Tcl_StackChannel(interp, typePtr, instanceData, mask, prevChan)
  1315     Tcl_Interp	    *interp;	   /* The interpreter we are working in */
  1316     Tcl_ChannelType *typePtr;	   /* The channel type record for the new
  1317 				    * channel. */
  1318     ClientData	     instanceData; /* Instance specific data for the new
  1319 				    * channel. */
  1320     int		     mask;	   /* TCL_READABLE & TCL_WRITABLE to indicate
  1321 				    * if the channel is readable, writable. */
  1322     Tcl_Channel	     prevChan;	   /* The channel structure to replace */
  1323 {
  1324     ThreadSpecificData	*tsdPtr = TCL_TSD_INIT(&dataKey);
  1325     Channel		*chanPtr, *prevChanPtr;
  1326     ChannelState	*statePtr;
  1327 
  1328     /*
  1329      * Find the given channel in the list of all channels.
  1330      * If we don't find it, then it was never registered correctly.
  1331      *
  1332      * This operation should occur at the top of a channel stack.
  1333      */
  1334 
  1335     statePtr    = (ChannelState *) tsdPtr->firstCSPtr;
  1336     prevChanPtr = ((Channel *) prevChan)->state->topChanPtr;
  1337 
  1338     while ((statePtr != NULL) && (statePtr->topChanPtr != prevChanPtr)) {
  1339 	statePtr = statePtr->nextCSPtr;
  1340     }
  1341 
  1342     if (statePtr == NULL) {
  1343 	if (interp) {
  1344 	    Tcl_AppendResult(interp, "couldn't find state for channel \"",
  1345 		    Tcl_GetChannelName(prevChan), "\"", (char *) NULL);
  1346 	}
  1347         return (Tcl_Channel) NULL;
  1348     }
  1349 
  1350     /*
  1351      * Here we check if the given "mask" matches the "flags"
  1352      * of the already existing channel.
  1353      *
  1354      *	  | - | R | W | RW |
  1355      *	--+---+---+---+----+	<=>  0 != (chan->mask & prevChan->mask)
  1356      *	- |   |   |   |    |
  1357      *	R |   | + |   | +  |	The superceding channel is allowed to
  1358      *	W |   |   | + | +  |	restrict the capabilities of the
  1359      *	RW|   | + | + | +  |	superceded one !
  1360      *	--+---+---+---+----+
  1361      */
  1362 
  1363     if ((mask & (statePtr->flags & (TCL_READABLE | TCL_WRITABLE))) == 0) {
  1364 	if (interp) {
  1365 	    Tcl_AppendResult(interp,
  1366 		    "reading and writing both disallowed for channel \"",
  1367 		    Tcl_GetChannelName(prevChan), "\"", (char *) NULL);
  1368 	}
  1369         return (Tcl_Channel) NULL;
  1370     }
  1371 
  1372     /*
  1373      * Flush the buffers. This ensures that any data still in them
  1374      * at this time is not handled by the new transformation. Restrict
  1375      * this to writable channels. Take care to hide a possible bg-copy
  1376      * in progress from Tcl_Flush and the CheckForChannelErrors inside.
  1377      */
  1378 
  1379     if ((mask & TCL_WRITABLE) != 0) {
  1380         CopyState *csPtr;
  1381 
  1382         csPtr           = statePtr->csPtr;
  1383 	statePtr->csPtr = (CopyState*) NULL;
  1384 
  1385 	if (Tcl_Flush((Tcl_Channel) prevChanPtr) != TCL_OK) {
  1386 	    statePtr->csPtr = csPtr;
  1387 	    if (interp) {
  1388 		Tcl_AppendResult(interp, "could not flush channel \"",
  1389 			Tcl_GetChannelName(prevChan), "\"", (char *) NULL);
  1390 	    }
  1391 	    return (Tcl_Channel) NULL;
  1392 	}
  1393 
  1394 	statePtr->csPtr = csPtr;
  1395     }
  1396     /*
  1397      * Discard any input in the buffers. They are not yet read by the
  1398      * user of the channel, so they have to go through the new
  1399      * transformation before reading. As the buffers contain the
  1400      * untransformed form their contents are not only useless but actually
  1401      * distorts our view of the system.
  1402      *
  1403      * To preserve the information without having to read them again and
  1404      * to avoid problems with the location in the channel (seeking might
  1405      * be impossible) we move the buffers from the common state structure
  1406      * into the channel itself. We use the buffers in the channel below
  1407      * the new transformation to hold the data. In the future this allows
  1408      * us to write transformations which pre-read data and push the unused
  1409      * part back when they are going away.
  1410      */
  1411 
  1412     if (((mask & TCL_READABLE) != 0) &&
  1413 	(statePtr->inQueueHead != (ChannelBuffer*) NULL)) {
  1414       /*
  1415        * Remark: It is possible that the channel buffers contain data from
  1416        * some earlier push-backs.
  1417        */
  1418 
  1419       statePtr->inQueueTail->nextPtr = prevChanPtr->inQueueHead;
  1420       prevChanPtr->inQueueHead       = statePtr->inQueueHead;
  1421 
  1422       if (prevChanPtr->inQueueTail == (ChannelBuffer*) NULL) {
  1423 	prevChanPtr->inQueueTail = statePtr->inQueueTail;
  1424       }
  1425 
  1426       statePtr->inQueueHead          = (ChannelBuffer*) NULL;
  1427       statePtr->inQueueTail          = (ChannelBuffer*) NULL;
  1428     }
  1429 
  1430     chanPtr = (Channel *) ckalloc((unsigned) sizeof(Channel));
  1431 
  1432     /*
  1433      * Save some of the current state into the new structure,
  1434      * reinitialize the parts which will stay with the transformation.
  1435      *
  1436      * Remarks:
  1437      */
  1438 
  1439     chanPtr->state		= statePtr;
  1440     chanPtr->instanceData	= instanceData;
  1441     chanPtr->typePtr		= typePtr;
  1442     chanPtr->downChanPtr	= prevChanPtr;
  1443     chanPtr->upChanPtr		= (Channel *) NULL;
  1444     chanPtr->inQueueHead        = (ChannelBuffer*) NULL;
  1445     chanPtr->inQueueTail        = (ChannelBuffer*) NULL;
  1446 
  1447     /*
  1448      * Place new block at the head of a possibly existing list of previously
  1449      * stacked channels.
  1450      */
  1451 
  1452     prevChanPtr->upChanPtr	= chanPtr;
  1453     statePtr->topChanPtr	= chanPtr;
  1454 
  1455     return (Tcl_Channel) chanPtr;
  1456 }
  1457 
  1458 /*
  1459  *----------------------------------------------------------------------
  1460  *
  1461  * Tcl_UnstackChannel --
  1462  *
  1463  *	Unstacks an entry in the hash table for a Tcl_Channel
  1464  *	record. This is the reverse to 'Tcl_StackChannel'.
  1465  *
  1466  * Results:
  1467  *	A standard Tcl result.
  1468  *
  1469  * Side effects:
  1470  *	If TCL_ERROR is returned, the posix error code will be set
  1471  *	with Tcl_SetErrno.
  1472  *
  1473  *----------------------------------------------------------------------
  1474  */
  1475 
  1476 EXPORT_C int
  1477 Tcl_UnstackChannel (interp, chan)
  1478     Tcl_Interp *interp; /* The interpreter we are working in */
  1479     Tcl_Channel chan;   /* The channel to unstack */
  1480 {
  1481     Channel      *chanPtr  = (Channel *) chan;
  1482     ChannelState *statePtr = chanPtr->state;
  1483     int result = 0;
  1484 
  1485     /*
  1486      * This operation should occur at the top of a channel stack.
  1487      */
  1488 
  1489     chanPtr = statePtr->topChanPtr;
  1490 
  1491     if (chanPtr->downChanPtr != (Channel *) NULL) {
  1492         /*
  1493 	 * Instead of manipulating the per-thread / per-interp list/hashtable
  1494 	 * of registered channels we wind down the state of the transformation,
  1495 	 * and then restore the state of underlying channel into the old
  1496 	 * structure.
  1497 	 */
  1498 	Channel *downChanPtr = chanPtr->downChanPtr;
  1499 
  1500 	/*
  1501 	 * Flush the buffers. This ensures that any data still in them
  1502 	 * at this time _is_ handled by the transformation we are unstacking
  1503 	 * right now. Restrict this to writable channels. Take care to hide
  1504 	 * a possible bg-copy in progress from Tcl_Flush and the
  1505 	 * CheckForChannelErrors inside.
  1506 	 */
  1507 
  1508 	if (statePtr->flags & TCL_WRITABLE) {
  1509 	    CopyState*    csPtr;
  1510 
  1511 	    csPtr           = statePtr->csPtr;
  1512 	    statePtr->csPtr = (CopyState*) NULL;
  1513 
  1514 	    if (Tcl_Flush((Tcl_Channel) chanPtr) != TCL_OK) {
  1515 	        statePtr->csPtr = csPtr;
  1516 		if (interp) {
  1517 		    Tcl_AppendResult(interp, "could not flush channel \"",
  1518 			    Tcl_GetChannelName((Tcl_Channel) chanPtr), "\"",
  1519 			    (char *) NULL);
  1520 		}
  1521 		return TCL_ERROR;
  1522 	    }
  1523 
  1524 	    statePtr->csPtr = csPtr;
  1525 	}
  1526 
  1527 	/*
  1528 	 * Anything in the input queue and the push-back buffers of
  1529 	 * the transformation going away is transformed data, but not
  1530 	 * yet read. As unstacking means that the caller does not want
  1531 	 * to see transformed data any more we have to discard these
  1532 	 * bytes. To avoid writing an analogue to 'DiscardInputQueued'
  1533 	 * we move the information in the push back buffers to the
  1534 	 * input queue and then call 'DiscardInputQueued' on that.
  1535 	 */
  1536 
  1537 	if (((statePtr->flags & TCL_READABLE)  != 0) &&
  1538 	    ((statePtr->inQueueHead != (ChannelBuffer*) NULL) ||
  1539 	     (chanPtr->inQueueHead  != (ChannelBuffer*) NULL))) {
  1540 
  1541 	    if ((statePtr->inQueueHead != (ChannelBuffer*) NULL) &&
  1542 		(chanPtr->inQueueHead  != (ChannelBuffer*) NULL)) {
  1543 	        statePtr->inQueueTail->nextPtr = chanPtr->inQueueHead;
  1544 		statePtr->inQueueTail = chanPtr->inQueueTail;
  1545 	        statePtr->inQueueHead = statePtr->inQueueTail;
  1546 
  1547 	    } else if (chanPtr->inQueueHead != (ChannelBuffer*) NULL) {
  1548 	        statePtr->inQueueHead = chanPtr->inQueueHead;
  1549 		statePtr->inQueueTail = chanPtr->inQueueTail;
  1550 	    }
  1551 
  1552 	    chanPtr->inQueueHead          = (ChannelBuffer*) NULL;
  1553 	    chanPtr->inQueueTail          = (ChannelBuffer*) NULL;
  1554 
  1555 	    DiscardInputQueued (statePtr, 0);
  1556 	}
  1557 
  1558 	statePtr->topChanPtr	= downChanPtr;
  1559 	downChanPtr->upChanPtr	= (Channel *) NULL;
  1560 
  1561 	/*
  1562 	 * Leave this link intact for closeproc
  1563 	 *  chanPtr->downChanPtr	= (Channel *) NULL;
  1564 	 */
  1565 
  1566 	/*
  1567 	 * Close and free the channel driver state.
  1568 	 */
  1569 
  1570 	if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) {
  1571 	    result = (chanPtr->typePtr->closeProc)(chanPtr->instanceData,
  1572 		    interp);
  1573 	} else {
  1574 	    result = (chanPtr->typePtr->close2Proc)(chanPtr->instanceData,
  1575 		    interp, 0);
  1576 	}
  1577 
  1578 	chanPtr->typePtr	= NULL;
  1579 	/*
  1580 	 * AK: Tcl_NotifyChannel may hold a reference to this block of memory
  1581 	 */
  1582 	Tcl_EventuallyFree((ClientData) chanPtr, TCL_DYNAMIC);
  1583 	UpdateInterest(downChanPtr);
  1584 
  1585 	if (result != 0) {
  1586 	    Tcl_SetErrno(result);
  1587 	    return TCL_ERROR;
  1588 	}
  1589     } else {
  1590         /*
  1591 	 * This channel does not cover another one.
  1592 	 * Simply do a close, if necessary.
  1593 	 */
  1594 
  1595         if (statePtr->refCount <= 0) {
  1596             if (Tcl_Close(interp, chan) != TCL_OK) {
  1597                 return TCL_ERROR;
  1598             }
  1599 	}
  1600     }
  1601 
  1602     return TCL_OK;
  1603 }
  1604 
  1605 /*
  1606  *----------------------------------------------------------------------
  1607  *
  1608  * Tcl_GetStackedChannel --
  1609  *
  1610  *	Determines whether the specified channel is stacked upon another.
  1611  *
  1612  * Results:
  1613  *	NULL if the channel is not stacked upon another one, or a reference
  1614  *	to the channel it is stacked upon. This reference can be used in
  1615  *	queries, but modification is not allowed.
  1616  *
  1617  * Side effects:
  1618  *	None.
  1619  *
  1620  *----------------------------------------------------------------------
  1621  */
  1622 
  1623 EXPORT_C Tcl_Channel
  1624 Tcl_GetStackedChannel(chan)
  1625     Tcl_Channel chan;
  1626 {
  1627     Channel *chanPtr = (Channel *) chan;	/* The actual channel. */
  1628 
  1629     return (Tcl_Channel) chanPtr->downChanPtr;
  1630 }
  1631 
  1632 /*
  1633  *----------------------------------------------------------------------
  1634  *
  1635  * Tcl_GetTopChannel --
  1636  *
  1637  *	Returns the top channel of a channel stack.
  1638  *
  1639  * Results:
  1640  *	NULL if the channel is not stacked upon another one, or a reference
  1641  *	to the channel it is stacked upon. This reference can be used in
  1642  *	queries, but modification is not allowed.
  1643  *
  1644  * Side effects:
  1645  *	None.
  1646  *
  1647  *----------------------------------------------------------------------
  1648  */
  1649 
  1650 EXPORT_C Tcl_Channel
  1651 Tcl_GetTopChannel(chan)
  1652     Tcl_Channel chan;
  1653 {
  1654     Channel *chanPtr = (Channel *) chan;	/* The actual channel. */
  1655 
  1656     return (Tcl_Channel) chanPtr->state->topChanPtr;
  1657 }
  1658 
  1659 /*
  1660  *----------------------------------------------------------------------
  1661  *
  1662  * Tcl_GetChannelInstanceData --
  1663  *
  1664  *	Returns the client data associated with a channel.
  1665  *
  1666  * Results:
  1667  *	The client data.
  1668  *
  1669  * Side effects:
  1670  *	None.
  1671  *
  1672  *----------------------------------------------------------------------
  1673  */
  1674 
  1675 EXPORT_C ClientData
  1676 Tcl_GetChannelInstanceData(chan)
  1677     Tcl_Channel chan;		/* Channel for which to return client data. */
  1678 {
  1679     Channel *chanPtr = (Channel *) chan;	/* The actual channel. */
  1680 
  1681     return chanPtr->instanceData;
  1682 }
  1683 
  1684 /*
  1685  *----------------------------------------------------------------------
  1686  *
  1687  * Tcl_GetChannelThread --
  1688  *
  1689  *	Given a channel structure, returns the thread managing it.
  1690  *	TIP #10
  1691  *
  1692  * Results:
  1693  *	Returns the id of the thread managing the channel.
  1694  *
  1695  * Side effects:
  1696  *	None.
  1697  *
  1698  *----------------------------------------------------------------------
  1699  */
  1700 
  1701 EXPORT_C Tcl_ThreadId
  1702 Tcl_GetChannelThread(chan)
  1703     Tcl_Channel chan;		/* The channel to return managing thread for. */
  1704 {
  1705     Channel *chanPtr = (Channel *) chan;	/* The actual channel. */
  1706 
  1707     return chanPtr->state->managingThread;
  1708 }
  1709 
  1710 /*
  1711  *----------------------------------------------------------------------
  1712  *
  1713  * Tcl_GetChannelType --
  1714  *
  1715  *	Given a channel structure, returns the channel type structure.
  1716  *
  1717  * Results:
  1718  *	Returns a pointer to the channel type structure.
  1719  *
  1720  * Side effects:
  1721  *	None.
  1722  *
  1723  *----------------------------------------------------------------------
  1724  */
  1725 
  1726 EXPORT_C Tcl_ChannelType *
  1727 Tcl_GetChannelType(chan)
  1728     Tcl_Channel chan;		/* The channel to return type for. */
  1729 {
  1730     Channel *chanPtr = (Channel *) chan;	/* The actual channel. */
  1731 
  1732     return chanPtr->typePtr;
  1733 }
  1734 
  1735 /*
  1736  *----------------------------------------------------------------------
  1737  *
  1738  * Tcl_GetChannelMode --
  1739  *
  1740  *	Computes a mask indicating whether the channel is open for
  1741  *	reading and writing.
  1742  *
  1743  * Results:
  1744  *	An OR-ed combination of TCL_READABLE and TCL_WRITABLE.
  1745  *
  1746  * Side effects:
  1747  *	None.
  1748  *
  1749  *----------------------------------------------------------------------
  1750  */
  1751 
  1752 EXPORT_C int
  1753 Tcl_GetChannelMode(chan)
  1754     Tcl_Channel chan;		/* The channel for which the mode is
  1755                                  * being computed. */
  1756 {
  1757     ChannelState *statePtr = ((Channel *) chan)->state;
  1758 					/* State of actual channel. */
  1759 
  1760     return (statePtr->flags & (TCL_READABLE | TCL_WRITABLE));
  1761 }
  1762 
  1763 /*
  1764  *----------------------------------------------------------------------
  1765  *
  1766  * Tcl_GetChannelName --
  1767  *
  1768  *	Returns the string identifying the channel name.
  1769  *
  1770  * Results:
  1771  *	The string containing the channel name. This memory is
  1772  *	owned by the generic layer and should not be modified by
  1773  *	the caller.
  1774  *
  1775  * Side effects:
  1776  *	None.
  1777  *
  1778  *----------------------------------------------------------------------
  1779  */
  1780 
  1781 EXPORT_C CONST char *
  1782 Tcl_GetChannelName(chan)
  1783     Tcl_Channel chan;		/* The channel for which to return the name. */
  1784 {
  1785     ChannelState *statePtr;	/* State of actual channel. */
  1786 
  1787     statePtr = ((Channel *) chan)->state;
  1788     return statePtr->channelName;
  1789 }
  1790 
  1791 /*
  1792  *----------------------------------------------------------------------
  1793  *
  1794  * Tcl_GetChannelHandle --
  1795  *
  1796  *	Returns an OS handle associated with a channel.
  1797  *
  1798  * Results:
  1799  *	Returns TCL_OK and places the handle in handlePtr, or returns
  1800  *	TCL_ERROR on failure.
  1801  *
  1802  * Side effects:
  1803  *	None.
  1804  *
  1805  *----------------------------------------------------------------------
  1806  */
  1807 
  1808 EXPORT_C int
  1809 Tcl_GetChannelHandle(chan, direction, handlePtr)
  1810     Tcl_Channel chan;		/* The channel to get file from. */
  1811     int direction;		/* TCL_WRITABLE or TCL_READABLE. */
  1812     ClientData *handlePtr;	/* Where to store handle */
  1813 {
  1814     Channel *chanPtr;		/* The actual channel. */
  1815     ClientData handle;
  1816     int result;
  1817 
  1818     chanPtr = ((Channel *) chan)->state->bottomChanPtr;
  1819     result = (chanPtr->typePtr->getHandleProc)(chanPtr->instanceData,
  1820 	    direction, &handle);
  1821     if (handlePtr) {
  1822 	*handlePtr = handle;
  1823     }
  1824     return result;
  1825 }
  1826 
  1827 /*
  1828  *---------------------------------------------------------------------------
  1829  *
  1830  * AllocChannelBuffer --
  1831  *
  1832  *	A channel buffer has BUFFER_PADDING bytes extra at beginning to
  1833  *	hold any bytes of a native-encoding character that got split by
  1834  *	the end of the previous buffer and need to be moved to the
  1835  *	beginning of the next buffer to make a contiguous string so it
  1836  *	can be converted to UTF-8.
  1837  *
  1838  *	A channel buffer has BUFFER_PADDING bytes extra at the end to
  1839  *	hold any bytes of a native-encoding character (generated from a
  1840  *	UTF-8 character) that overflow past the end of the buffer and
  1841  *	need to be moved to the next buffer.
  1842  *
  1843  * Results:
  1844  *	A newly allocated channel buffer.
  1845  *
  1846  * Side effects:
  1847  *	None.
  1848  *
  1849  *---------------------------------------------------------------------------
  1850  */
  1851 
  1852 static ChannelBuffer *
  1853 AllocChannelBuffer(length)
  1854     int length;			/* Desired length of channel buffer. */
  1855 {
  1856     ChannelBuffer *bufPtr;
  1857     int n;
  1858 
  1859     n = length + CHANNELBUFFER_HEADER_SIZE + BUFFER_PADDING + BUFFER_PADDING;
  1860     bufPtr = (ChannelBuffer *) ckalloc((unsigned) n);
  1861     bufPtr->nextAdded	= BUFFER_PADDING;
  1862     bufPtr->nextRemoved	= BUFFER_PADDING;
  1863     bufPtr->bufLength	= length + BUFFER_PADDING;
  1864     bufPtr->nextPtr	= (ChannelBuffer *) NULL;
  1865     return bufPtr;
  1866 }
  1867 
  1868 /*
  1869  *----------------------------------------------------------------------
  1870  *
  1871  * RecycleBuffer --
  1872  *
  1873  *	Helper function to recycle input and output buffers. Ensures
  1874  *	that two input buffers are saved (one in the input queue and
  1875  *	another in the saveInBufPtr field) and that curOutPtr is set
  1876  *	to a buffer. Only if these conditions are met is the buffer
  1877  *	freed to the OS.
  1878  *
  1879  * Results:
  1880  *	None.
  1881  *
  1882  * Side effects:
  1883  *	May free a buffer to the OS.
  1884  *
  1885  *----------------------------------------------------------------------
  1886  */
  1887 
  1888 static void
  1889 RecycleBuffer(statePtr, bufPtr, mustDiscard)
  1890     ChannelState *statePtr;	/* ChannelState in which to recycle buffers. */
  1891     ChannelBuffer *bufPtr;	/* The buffer to recycle. */
  1892     int mustDiscard;		/* If nonzero, free the buffer to the
  1893                                  * OS, always. */
  1894 {
  1895     /*
  1896      * Do we have to free the buffer to the OS?
  1897      */
  1898 
  1899     if (mustDiscard) {
  1900         ckfree((char *) bufPtr);
  1901         return;
  1902     }
  1903 
  1904     /*
  1905      * Only save buffers which are at least as big as the requested
  1906      * buffersize for the channel. This is to honor dynamic changes
  1907      * of the buffersize made by the user.
  1908      */
  1909 
  1910     if ((bufPtr->bufLength - BUFFER_PADDING) < statePtr->bufSize) {
  1911         ckfree((char *) bufPtr);
  1912         return;
  1913     }
  1914 
  1915     /*
  1916      * Only save buffers for the input queue if the channel is readable.
  1917      */
  1918     
  1919     if (statePtr->flags & TCL_READABLE) {
  1920         if (statePtr->inQueueHead == (ChannelBuffer *) NULL) {
  1921             statePtr->inQueueHead = bufPtr;
  1922             statePtr->inQueueTail = bufPtr;
  1923             goto keepit;
  1924         }
  1925         if (statePtr->saveInBufPtr == (ChannelBuffer *) NULL) {
  1926             statePtr->saveInBufPtr = bufPtr;
  1927             goto keepit;
  1928         }
  1929     }
  1930 
  1931     /*
  1932      * Only save buffers for the output queue if the channel is writable.
  1933      */
  1934 
  1935     if (statePtr->flags & TCL_WRITABLE) {
  1936         if (statePtr->curOutPtr == (ChannelBuffer *) NULL) {
  1937             statePtr->curOutPtr = bufPtr;
  1938             goto keepit;
  1939         }
  1940     }
  1941 
  1942     /*
  1943      * If we reached this code we return the buffer to the OS.
  1944      */
  1945 
  1946     ckfree((char *) bufPtr);
  1947     return;
  1948 
  1949     keepit:
  1950     bufPtr->nextRemoved = BUFFER_PADDING;
  1951     bufPtr->nextAdded = BUFFER_PADDING;
  1952     bufPtr->nextPtr = (ChannelBuffer *) NULL;
  1953 }
  1954 
  1955 /*
  1956  *----------------------------------------------------------------------
  1957  *
  1958  * DiscardOutputQueued --
  1959  *
  1960  *	Discards all output queued in the output queue of a channel.
  1961  *
  1962  * Results:
  1963  *	None.
  1964  *
  1965  * Side effects:
  1966  *	Recycles buffers.
  1967  *
  1968  *----------------------------------------------------------------------
  1969  */
  1970 
  1971 static void
  1972 DiscardOutputQueued(statePtr)
  1973     ChannelState *statePtr;	/* ChannelState for which to discard output. */
  1974 {
  1975     ChannelBuffer *bufPtr;
  1976     
  1977     while (statePtr->outQueueHead != (ChannelBuffer *) NULL) {
  1978         bufPtr = statePtr->outQueueHead;
  1979         statePtr->outQueueHead = bufPtr->nextPtr;
  1980         RecycleBuffer(statePtr, bufPtr, 0);
  1981     }
  1982     statePtr->outQueueHead = (ChannelBuffer *) NULL;
  1983     statePtr->outQueueTail = (ChannelBuffer *) NULL;
  1984 }
  1985 
  1986 /*
  1987  *----------------------------------------------------------------------
  1988  *
  1989  * CheckForDeadChannel --
  1990  *
  1991  *	This function checks is a given channel is Dead.
  1992  *      (A channel that has been closed but not yet deallocated.)
  1993  *
  1994  * Results:
  1995  *	True (1) if channel is Dead, False (0) if channel is Ok
  1996  *
  1997  * Side effects:
  1998  *      None
  1999  *
  2000  *----------------------------------------------------------------------
  2001  */
  2002 
  2003 static int
  2004 CheckForDeadChannel(interp, statePtr)
  2005     Tcl_Interp *interp;		/* For error reporting (can be NULL) */
  2006     ChannelState *statePtr;	/* The channel state to check. */
  2007 {
  2008     if (statePtr->flags & CHANNEL_DEAD) {
  2009         Tcl_SetErrno(EINVAL);
  2010 	if (interp) {
  2011 	    Tcl_AppendResult(interp,
  2012 		    "unable to access channel: invalid channel",
  2013 		    (char *) NULL);   
  2014 	}
  2015 	return 1;
  2016     }
  2017     return 0;
  2018 }
  2019 
  2020 /*
  2021  *----------------------------------------------------------------------
  2022  *
  2023  * FlushChannel --
  2024  *
  2025  *	This function flushes as much of the queued output as is possible
  2026  *	now. If calledFromAsyncFlush is nonzero, it is being called in an
  2027  *	event handler to flush channel output asynchronously.
  2028  *
  2029  * Results:
  2030  *	0 if successful, else the error code that was returned by the
  2031  *	channel type operation.
  2032  *
  2033  * Side effects:
  2034  *	May produce output on a channel. May block indefinitely if the
  2035  *	channel is synchronous. May schedule an async flush on the channel.
  2036  *	May recycle memory for buffers in the output queue.
  2037  *
  2038  *----------------------------------------------------------------------
  2039  */
  2040 
  2041 static int
  2042 FlushChannel(interp, chanPtr, calledFromAsyncFlush)
  2043     Tcl_Interp *interp;			/* For error reporting during close. */
  2044     Channel *chanPtr;			/* The channel to flush on. */
  2045     int calledFromAsyncFlush;		/* If nonzero then we are being
  2046                                          * called from an asynchronous
  2047                                          * flush callback. */
  2048 {
  2049     ChannelState *statePtr = chanPtr->state;
  2050 					/* State of the channel stack. */
  2051     ChannelBuffer *bufPtr;		/* Iterates over buffered output
  2052                                          * queue. */
  2053     int toWrite;			/* Amount of output data in current
  2054                                          * buffer available to be written. */
  2055     int written;			/* Amount of output data actually
  2056                                          * written in current round. */
  2057     int errorCode = 0;			/* Stores POSIX error codes from
  2058                                          * channel driver operations. */
  2059     int wroteSome = 0;			/* Set to one if any data was
  2060 					 * written to the driver. */
  2061 
  2062     /*
  2063      * Prevent writing on a dead channel -- a channel that has been closed
  2064      * but not yet deallocated. This can occur if the exit handler for the
  2065      * channel deallocation runs before all channels are deregistered in
  2066      * all interpreters.
  2067      */
  2068     
  2069     if (CheckForDeadChannel(interp, statePtr)) return -1;
  2070     
  2071     /*
  2072      * Loop over the queued buffers and attempt to flush as
  2073      * much as possible of the queued output to the channel.
  2074      */
  2075 
  2076     while (1) {
  2077 
  2078         /*
  2079          * If the queue is empty and there is a ready current buffer, OR if
  2080          * the current buffer is full, then move the current buffer to the
  2081          * queue.
  2082          */
  2083 
  2084         if (((statePtr->curOutPtr != (ChannelBuffer *) NULL) &&
  2085                 (statePtr->curOutPtr->nextAdded == statePtr->curOutPtr->bufLength))
  2086                 || ((statePtr->flags & BUFFER_READY) &&
  2087                         (statePtr->outQueueHead == (ChannelBuffer *) NULL))) {
  2088             statePtr->flags &= (~(BUFFER_READY));
  2089             statePtr->curOutPtr->nextPtr = (ChannelBuffer *) NULL;
  2090             if (statePtr->outQueueHead == (ChannelBuffer *) NULL) {
  2091                 statePtr->outQueueHead = statePtr->curOutPtr;
  2092             } else {
  2093                 statePtr->outQueueTail->nextPtr = statePtr->curOutPtr;
  2094             }
  2095             statePtr->outQueueTail = statePtr->curOutPtr;
  2096             statePtr->curOutPtr = (ChannelBuffer *) NULL;
  2097         }
  2098         bufPtr = statePtr->outQueueHead;
  2099 
  2100         /*
  2101          * If we are not being called from an async flush and an async
  2102          * flush is active, we just return without producing any output.
  2103          */
  2104 
  2105         if ((!calledFromAsyncFlush) &&
  2106                 (statePtr->flags & BG_FLUSH_SCHEDULED)) {
  2107             return 0;
  2108         }
  2109 
  2110         /*
  2111          * If the output queue is still empty, break out of the while loop.
  2112          */
  2113 
  2114         if (bufPtr == (ChannelBuffer *) NULL) {
  2115             break;	/* Out of the "while (1)". */
  2116         }
  2117 
  2118         /*
  2119          * Produce the output on the channel.
  2120          */
  2121 
  2122         toWrite = bufPtr->nextAdded - bufPtr->nextRemoved;
  2123         written = (chanPtr->typePtr->outputProc) (chanPtr->instanceData,
  2124                 bufPtr->buf + bufPtr->nextRemoved, toWrite,
  2125 		&errorCode);
  2126 
  2127 	/*
  2128          * If the write failed completely attempt to start the asynchronous
  2129          * flush mechanism and break out of this loop - do not attempt to
  2130          * write any more output at this time.
  2131          */
  2132 
  2133         if (written < 0) {
  2134             
  2135             /*
  2136              * If the last attempt to write was interrupted, simply retry.
  2137              */
  2138             
  2139             if (errorCode == EINTR) {
  2140                 errorCode = 0;
  2141                 continue;
  2142             }
  2143 
  2144             /*
  2145              * If the channel is non-blocking and we would have blocked,
  2146              * start a background flushing handler and break out of the loop.
  2147              */
  2148 
  2149             if ((errorCode == EWOULDBLOCK) || (errorCode == EAGAIN)) {
  2150 		/*
  2151 		 * This used to check for CHANNEL_NONBLOCKING, and panic
  2152 		 * if the channel was blocking.  However, it appears
  2153 		 * that setting stdin to -blocking 0 has some effect on
  2154 		 * the stdout when it's a tty channel (dup'ed underneath)
  2155 		 */
  2156 		if (!(statePtr->flags & BG_FLUSH_SCHEDULED)) {
  2157 		    statePtr->flags |= BG_FLUSH_SCHEDULED;
  2158 		    UpdateInterest(chanPtr);
  2159 		}
  2160 		errorCode = 0;
  2161 		break;
  2162             }
  2163 
  2164             /*
  2165              * Decide whether to report the error upwards or defer it.
  2166              */
  2167 
  2168             if (calledFromAsyncFlush) {
  2169                 if (statePtr->unreportedError == 0) {
  2170                     statePtr->unreportedError = errorCode;
  2171                 }
  2172             } else {
  2173                 Tcl_SetErrno(errorCode);
  2174 		if (interp != NULL) {
  2175 
  2176 		    /*
  2177 		     * Casting away CONST here is safe because the
  2178 		     * TCL_VOLATILE flag guarantees CONST treatment
  2179 		     * of the Posix error string.
  2180 		     */
  2181 
  2182 		    Tcl_SetResult(interp,
  2183 			    (char *) Tcl_PosixError(interp), TCL_VOLATILE);
  2184 		}
  2185             }
  2186 
  2187             /*
  2188              * When we get an error we throw away all the output
  2189              * currently queued.
  2190              */
  2191 
  2192             DiscardOutputQueued(statePtr);
  2193             continue;
  2194         } else {
  2195 	    wroteSome = 1;
  2196 	}
  2197 
  2198         bufPtr->nextRemoved += written;
  2199 
  2200         /*
  2201          * If this buffer is now empty, recycle it.
  2202          */
  2203 
  2204         if (bufPtr->nextRemoved == bufPtr->nextAdded) {
  2205             statePtr->outQueueHead = bufPtr->nextPtr;
  2206             if (statePtr->outQueueHead == (ChannelBuffer *) NULL) {
  2207                 statePtr->outQueueTail = (ChannelBuffer *) NULL;
  2208             }
  2209             RecycleBuffer(statePtr, bufPtr, 0);
  2210         }
  2211     }	/* Closes "while (1)". */
  2212 
  2213     /*
  2214      * If we wrote some data while flushing in the background, we are done.
  2215      * We can't finish the background flush until we run out of data and
  2216      * the channel becomes writable again.  This ensures that all of the
  2217      * pending data has been flushed at the system level.
  2218      */
  2219 
  2220     if (statePtr->flags & BG_FLUSH_SCHEDULED) {
  2221 	if (wroteSome) {
  2222 	    return errorCode;
  2223 	} else if (statePtr->outQueueHead == (ChannelBuffer *) NULL) {
  2224 	    statePtr->flags &= (~(BG_FLUSH_SCHEDULED));
  2225 	    (chanPtr->typePtr->watchProc)(chanPtr->instanceData,
  2226 		    statePtr->interestMask);
  2227 	}
  2228     }
  2229 
  2230     /*
  2231      * If the channel is flagged as closed, delete it when the refCount
  2232      * drops to zero, the output queue is empty and there is no output
  2233      * in the current output buffer.
  2234      */
  2235 
  2236     if ((statePtr->flags & CHANNEL_CLOSED) && (statePtr->refCount <= 0) &&
  2237             (statePtr->outQueueHead == (ChannelBuffer *) NULL) &&
  2238             ((statePtr->curOutPtr == (ChannelBuffer *) NULL) ||
  2239                     (statePtr->curOutPtr->nextAdded ==
  2240                             statePtr->curOutPtr->nextRemoved))) {
  2241 	return CloseChannel(interp, chanPtr, errorCode);
  2242     }
  2243     return errorCode;
  2244 }
  2245 
  2246 /*
  2247  *----------------------------------------------------------------------
  2248  *
  2249  * CloseChannel --
  2250  *
  2251  *	Utility procedure to close a channel and free associated resources.
  2252  *
  2253  *	If the channel was stacked, then the it will copy the necessary
  2254  *	elements of the NEXT channel into the TOP channel, in essence
  2255  *	unstacking the channel.  The NEXT channel will then be freed.
  2256  *
  2257  *	If the channel was not stacked, then we will free all the bits
  2258  *	for the TOP channel, including the data structure itself.
  2259  *
  2260  * Results:
  2261  *	1 if the channel was stacked, 0 otherwise.
  2262  *
  2263  * Side effects:
  2264  *	May close the actual channel; may free memory.
  2265  *	May change the value of errno.
  2266  *
  2267  *----------------------------------------------------------------------
  2268  */
  2269 
  2270 static int
  2271 CloseChannel(interp, chanPtr, errorCode)
  2272     Tcl_Interp *interp;			/* For error reporting. */
  2273     Channel *chanPtr;			/* The channel to close. */
  2274     int errorCode;			/* Status of operation so far. */
  2275 {
  2276     int result = 0;			/* Of calling driver close
  2277                                          * operation. */
  2278     ChannelState *statePtr;		/* state of the channel stack. */
  2279     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
  2280 
  2281     if (chanPtr == NULL) {
  2282         return result;
  2283     }
  2284     statePtr = chanPtr->state;
  2285 
  2286     /*
  2287      * No more input can be consumed so discard any leftover input.
  2288      */
  2289 
  2290     DiscardInputQueued(statePtr, 1);
  2291 
  2292     /*
  2293      * Discard a leftover buffer in the current output buffer field.
  2294      */
  2295 
  2296     if (statePtr->curOutPtr != (ChannelBuffer *) NULL) {
  2297         ckfree((char *) statePtr->curOutPtr);
  2298         statePtr->curOutPtr = (ChannelBuffer *) NULL;
  2299     }
  2300     
  2301     /*
  2302      * The caller guarantees that there are no more buffers
  2303      * queued for output.
  2304      */
  2305 
  2306     if (statePtr->outQueueHead != (ChannelBuffer *) NULL) {
  2307         panic("TclFlush, closed channel: queued output left");
  2308     }
  2309 
  2310     /*
  2311      * If the EOF character is set in the channel, append that to the
  2312      * output device.
  2313      */
  2314 
  2315     if ((statePtr->outEofChar != 0) && (statePtr->flags & TCL_WRITABLE)) {
  2316         int dummy;
  2317         char c;
  2318 
  2319         c = (char) statePtr->outEofChar;
  2320         (chanPtr->typePtr->outputProc) (chanPtr->instanceData, &c, 1, &dummy);
  2321     }
  2322 
  2323     /*
  2324      * Remove this channel from of the list of all channels.
  2325      */
  2326     Tcl_CutChannel((Tcl_Channel) chanPtr);
  2327 
  2328     /*
  2329      * Close and free the channel driver state.
  2330      */
  2331 
  2332     if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) {
  2333 	result = (chanPtr->typePtr->closeProc)(chanPtr->instanceData, interp);
  2334     } else {
  2335 	result = (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, interp,
  2336 		0);
  2337     }
  2338 
  2339     /*
  2340      * Some resources can be cleared only if the bottom channel
  2341      * in a stack is closed. All the other channels in the stack
  2342      * are not allowed to remove.
  2343      */
  2344 
  2345     if (chanPtr == statePtr->bottomChanPtr) {
  2346 	if (statePtr->channelName != (char *) NULL) {
  2347 	    ckfree((char *) statePtr->channelName);
  2348 	    statePtr->channelName = NULL;
  2349 	}
  2350 
  2351 	Tcl_FreeEncoding(statePtr->encoding);
  2352 	if (statePtr->outputStage != NULL) {
  2353 	    ckfree((char *) statePtr->outputStage);
  2354 	    statePtr->outputStage = (char *) NULL;
  2355 	}
  2356     }
  2357 
  2358     /*
  2359      * If we are being called synchronously, report either
  2360      * any latent error on the channel or the current error.
  2361      */
  2362 
  2363     if (statePtr->unreportedError != 0) {
  2364         errorCode = statePtr->unreportedError;
  2365     }
  2366     if (errorCode == 0) {
  2367         errorCode = result;
  2368         if (errorCode != 0) {
  2369             Tcl_SetErrno(errorCode);
  2370         }
  2371     }
  2372 
  2373     /*
  2374      * Cancel any outstanding timer.
  2375      */
  2376 
  2377     Tcl_DeleteTimerHandler(statePtr->timer);
  2378 
  2379     /*
  2380      * Mark the channel as deleted by clearing the type structure.
  2381      */
  2382 
  2383     if (chanPtr->downChanPtr != (Channel *) NULL) {
  2384 	Channel *downChanPtr = chanPtr->downChanPtr;
  2385 
  2386 	statePtr->nextCSPtr	= tsdPtr->firstCSPtr;
  2387 	tsdPtr->firstCSPtr	= statePtr;
  2388 
  2389 	statePtr->topChanPtr	= downChanPtr;
  2390 	downChanPtr->upChanPtr	= (Channel *) NULL;
  2391 	chanPtr->typePtr	= NULL;
  2392 
  2393 	Tcl_EventuallyFree((ClientData) chanPtr, TCL_DYNAMIC);
  2394 	return Tcl_Close(interp, (Tcl_Channel) downChanPtr);
  2395     }
  2396 
  2397     /*
  2398      * There is only the TOP Channel, so we free the remaining
  2399      * pointers we have and then ourselves.  Since this is the
  2400      * last of the channels in the stack, make sure to free the
  2401      * ChannelState structure associated with it.  We use
  2402      * Tcl_EventuallyFree to allow for any last
  2403      */
  2404     chanPtr->typePtr = NULL;
  2405 
  2406     Tcl_EventuallyFree((ClientData) statePtr, TCL_DYNAMIC);
  2407     Tcl_EventuallyFree((ClientData) chanPtr, TCL_DYNAMIC);
  2408 
  2409     return errorCode;
  2410 }
  2411 
  2412 /*
  2413  *----------------------------------------------------------------------
  2414  *
  2415  * Tcl_CutChannel --
  2416  *
  2417  *	Removes a channel from the (thread-)global list of all channels
  2418  *	(in that thread).  This is actually the statePtr for the stack
  2419  *	of channel.
  2420  *
  2421  * Results:
  2422  *	Nothing.
  2423  *
  2424  * Side effects:
  2425  *	Resets the field 'nextCSPtr' of the specified channel state to NULL.
  2426  *
  2427  * NOTE:
  2428  *	The channel to cut out of the list must not be referenced
  2429  *	in any interpreter. This is something this procedure cannot
  2430  *	check (despite the refcount) because the caller usually wants
  2431  *	fiddle with the channel (like transfering it to a different
  2432  *	thread) and thus keeps the refcount artifically high to prevent
  2433  *	its destruction.
  2434  *
  2435  *----------------------------------------------------------------------
  2436  */
  2437 
  2438 EXPORT_C void
  2439 Tcl_CutChannel(chan)
  2440     Tcl_Channel chan;			/* The channel being removed. Must
  2441                                          * not be referenced in any
  2442                                          * interpreter. */
  2443 {
  2444     ThreadSpecificData* tsdPtr  = TCL_TSD_INIT(&dataKey);
  2445     ChannelState *prevCSPtr;		/* Preceding channel state in list of
  2446                                          * all states - used to splice a
  2447                                          * channel out of the list on close. */
  2448     ChannelState *statePtr = ((Channel *) chan)->state;
  2449 					/* state of the channel stack. */
  2450     Tcl_DriverThreadActionProc *threadActionProc;
  2451 
  2452     /*
  2453      * Remove this channel from of the list of all channels
  2454      * (in the current thread).
  2455      */
  2456 
  2457     if (tsdPtr->firstCSPtr && (statePtr == tsdPtr->firstCSPtr)) {
  2458         tsdPtr->firstCSPtr = statePtr->nextCSPtr;
  2459     } else {
  2460         for (prevCSPtr = tsdPtr->firstCSPtr;
  2461 	     prevCSPtr && (prevCSPtr->nextCSPtr != statePtr);
  2462 	     prevCSPtr = prevCSPtr->nextCSPtr) {
  2463             /* Empty loop body. */
  2464         }
  2465         if (prevCSPtr == (ChannelState *) NULL) {
  2466             panic("FlushChannel: damaged channel list");
  2467         }
  2468         prevCSPtr->nextCSPtr = statePtr->nextCSPtr;
  2469     }
  2470 
  2471     statePtr->nextCSPtr = (ChannelState *) NULL;
  2472 
  2473     /* TIP #218, Channel Thread Actions */
  2474     threadActionProc = Tcl_ChannelThreadActionProc (Tcl_GetChannelType (chan));
  2475     if (threadActionProc != NULL) {
  2476         (*threadActionProc) (Tcl_GetChannelInstanceData(chan),
  2477 			     TCL_CHANNEL_THREAD_REMOVE);
  2478     }
  2479 }
  2480 
  2481 /*
  2482  *----------------------------------------------------------------------
  2483  *
  2484  * Tcl_SpliceChannel --
  2485  *
  2486  *	Adds a channel to the (thread-)global list of all channels
  2487  *	(in that thread). Expects that the field 'nextChanPtr' in
  2488  *	the channel is set to NULL.
  2489  *
  2490  * Results:
  2491  *	Nothing.
  2492  *
  2493  * Side effects:
  2494  *	Nothing.
  2495  *
  2496  * NOTE:
  2497  *	The channel to splice into the list must not be referenced in any
  2498  *	interpreter. This is something this procedure cannot check
  2499  *	(despite the refcount) because the caller usually wants figgle
  2500  *	with the channel (like transfering it to a different thread)
  2501  *	and thus keeps the refcount artifically high to prevent its
  2502  *	destruction.
  2503  *
  2504  *----------------------------------------------------------------------
  2505  */
  2506 
  2507 EXPORT_C void
  2508 Tcl_SpliceChannel(chan)
  2509     Tcl_Channel chan;			/* The channel being added. Must
  2510                                          * not be referenced in any
  2511                                          * interpreter. */
  2512 {
  2513     ThreadSpecificData	*tsdPtr = TCL_TSD_INIT(&dataKey);
  2514     ChannelState	*statePtr = ((Channel *) chan)->state;
  2515     Tcl_DriverThreadActionProc *threadActionProc;
  2516 
  2517     if (statePtr->nextCSPtr != (ChannelState *) NULL) {
  2518         panic("Tcl_SpliceChannel: trying to add channel used in different list");
  2519     }
  2520 
  2521     statePtr->nextCSPtr	= tsdPtr->firstCSPtr;
  2522     tsdPtr->firstCSPtr	= statePtr;
  2523 
  2524     /*
  2525      * TIP #10. Mark the current thread as the new one managing this
  2526      *          channel. Note: 'Tcl_GetCurrentThread' returns sensible
  2527      *          values even for a non-threaded core.
  2528      */
  2529 
  2530     statePtr->managingThread = Tcl_GetCurrentThread ();
  2531 
  2532     /* TIP #218, Channel Thread Actions */
  2533     threadActionProc = Tcl_ChannelThreadActionProc (Tcl_GetChannelType (chan));
  2534     if (threadActionProc != NULL) {
  2535         (*threadActionProc) (Tcl_GetChannelInstanceData(chan),
  2536 			     TCL_CHANNEL_THREAD_INSERT);
  2537     }
  2538 }
  2539 
  2540 /*
  2541  *----------------------------------------------------------------------
  2542  *
  2543  * Tcl_Close --
  2544  *
  2545  *	Closes a channel.
  2546  *
  2547  * Results:
  2548  *	A standard Tcl result.
  2549  *
  2550  * Side effects:
  2551  *	Closes the channel if this is the last reference.
  2552  *
  2553  * NOTE:
  2554  *	Tcl_Close removes the channel as far as the user is concerned.
  2555  *	However, it may continue to exist for a while longer if it has
  2556  *	a background flush scheduled. The device itself is eventually
  2557  *	closed and the channel record removed, in CloseChannel, above.
  2558  *
  2559  *----------------------------------------------------------------------
  2560  */
  2561 
  2562 	/* ARGSUSED */
  2563 EXPORT_C int
  2564 Tcl_Close(interp, chan)
  2565     Tcl_Interp *interp;			/* Interpreter for errors. */
  2566     Tcl_Channel chan;			/* The channel being closed. Must
  2567                                          * not be referenced in any
  2568                                          * interpreter. */
  2569 {
  2570     CloseCallback *cbPtr;		/* Iterate over close callbacks
  2571                                          * for this channel. */
  2572     Channel *chanPtr;			/* The real IO channel. */
  2573     ChannelState *statePtr;		/* State of real IO channel. */
  2574     int result;				/* Of calling FlushChannel. */
  2575 
  2576     if (chan == (Tcl_Channel) NULL) {
  2577         return TCL_OK;
  2578     }
  2579 
  2580     /*
  2581      * Perform special handling for standard channels being closed. If the
  2582      * refCount is now 1 it means that the last reference to the standard
  2583      * channel is being explicitly closed, so bump the refCount down
  2584      * artificially to 0. This will ensure that the channel is actually
  2585      * closed, below. Also set the static pointer to NULL for the channel.
  2586      */
  2587 
  2588     CheckForStdChannelsBeingClosed(chan);
  2589 
  2590     /*
  2591      * This operation should occur at the top of a channel stack.
  2592      */
  2593 
  2594     chanPtr	= (Channel *) chan;
  2595     statePtr	= chanPtr->state;
  2596     chanPtr	= statePtr->topChanPtr;
  2597 
  2598     if (statePtr->refCount > 0) {
  2599         panic("called Tcl_Close on channel with refCount > 0");
  2600     }
  2601  
  2602     if (statePtr->flags & CHANNEL_INCLOSE) {
  2603 	if (interp) {
  2604             Tcl_AppendResult(interp,
  2605 	    "Illegal recursive call to close through close-handler of channel",
  2606 	    (char *) NULL);
  2607 	}
  2608         return TCL_ERROR;
  2609     }
  2610     statePtr->flags |= CHANNEL_INCLOSE;
  2611 
  2612     /*
  2613      * When the channel has an escape sequence driven encoding such as
  2614      * iso2022, the terminated escape sequence must write to the buffer.
  2615      */
  2616     if ((statePtr->encoding != NULL) && (statePtr->curOutPtr != NULL)
  2617 	    && (CheckChannelErrors(statePtr, TCL_WRITABLE) == 0)) {
  2618         statePtr->outputEncodingFlags |= TCL_ENCODING_END;
  2619         WriteChars(chanPtr, "", 0);
  2620     }
  2621 
  2622     Tcl_ClearChannelHandlers(chan);
  2623 
  2624     /*
  2625      * Invoke the registered close callbacks and delete their records.
  2626      */
  2627 
  2628     while (statePtr->closeCbPtr != (CloseCallback *) NULL) {
  2629         cbPtr = statePtr->closeCbPtr;
  2630         statePtr->closeCbPtr = cbPtr->nextPtr;
  2631         (cbPtr->proc) (cbPtr->clientData);
  2632         ckfree((char *) cbPtr);
  2633     }
  2634 
  2635     statePtr->flags &= ~CHANNEL_INCLOSE;
  2636 
  2637     /*
  2638      * Ensure that the last output buffer will be flushed.
  2639      */
  2640     
  2641     if ((statePtr->curOutPtr != (ChannelBuffer *) NULL) &&
  2642 	    (statePtr->curOutPtr->nextAdded > statePtr->curOutPtr->nextRemoved)) {
  2643         statePtr->flags |= BUFFER_READY;
  2644     }
  2645 
  2646     /*
  2647      * If this channel supports it, close the read side, since we don't need it
  2648      * anymore and this will help avoid deadlocks on some channel types.
  2649      */
  2650 
  2651     if (chanPtr->typePtr->closeProc == TCL_CLOSE2PROC) {
  2652 	result = (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, interp,
  2653 		TCL_CLOSE_READ);
  2654     } else {
  2655 	result = 0;
  2656     }
  2657 
  2658     /*
  2659      * The call to FlushChannel will flush any queued output and invoke
  2660      * the close function of the channel driver, or it will set up the
  2661      * channel to be flushed and closed asynchronously.
  2662      */
  2663 
  2664     statePtr->flags |= CHANNEL_CLOSED;
  2665     if ((FlushChannel(interp, chanPtr, 0) != 0) || (result != 0)) {
  2666         return TCL_ERROR;
  2667     }
  2668     return TCL_OK;
  2669 }
  2670 
  2671 /*
  2672  *----------------------------------------------------------------------
  2673  *
  2674  * Tcl_ClearChannelHandlers --
  2675  *
  2676  *	Removes all channel handlers and event scripts from the channel,
  2677  *	cancels all background copies involving the channel and any interest
  2678  *	in events.
  2679  *
  2680  * Results:
  2681  *	None.
  2682  *
  2683  * Side effects:
  2684  *	See above. Deallocates memory.
  2685  *
  2686  *----------------------------------------------------------------------
  2687  */
  2688 
  2689 EXPORT_C void
  2690 Tcl_ClearChannelHandlers (channel)
  2691     Tcl_Channel channel;
  2692 {
  2693     ChannelHandler *chPtr, *chNext;	/* Iterate over channel handlers. */
  2694     EventScriptRecord *ePtr, *eNextPtr;	/* Iterate over eventscript records. */
  2695     Channel *chanPtr;			/* The real IO channel. */
  2696     ChannelState *statePtr;		/* State of real IO channel. */
  2697     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
  2698     NextChannelHandler *nhPtr;
  2699 
  2700     /*
  2701      * This operation should occur at the top of a channel stack.
  2702      */
  2703 
  2704     chanPtr	= (Channel *) channel;
  2705     statePtr	= chanPtr->state;
  2706     chanPtr	= statePtr->topChanPtr;
  2707 
  2708     /*
  2709      * Cancel any outstanding timer.
  2710      */
  2711 
  2712     Tcl_DeleteTimerHandler(statePtr->timer);
  2713 
  2714     /*
  2715      * Remove any references to channel handlers for this channel that
  2716      * may be about to be invoked.
  2717      */
  2718 
  2719     for (nhPtr = tsdPtr->nestedHandlerPtr;
  2720 	 nhPtr != (NextChannelHandler *) NULL;
  2721 	 nhPtr = nhPtr->nestedHandlerPtr) {
  2722         if (nhPtr->nextHandlerPtr &&
  2723 		(nhPtr->nextHandlerPtr->chanPtr == chanPtr)) {
  2724 	    nhPtr->nextHandlerPtr = NULL;
  2725         }
  2726     }
  2727 
  2728     /*
  2729      * Remove all the channel handler records attached to the channel
  2730      * itself.
  2731      */
  2732 
  2733     for (chPtr = statePtr->chPtr;
  2734 	 chPtr != (ChannelHandler *) NULL;
  2735 	 chPtr = chNext) {
  2736         chNext = chPtr->nextPtr;
  2737         ckfree((char *) chPtr);
  2738     }
  2739     statePtr->chPtr = (ChannelHandler *) NULL;
  2740 
  2741     /*
  2742      * Cancel any pending copy operation.
  2743      */
  2744 
  2745     StopCopy(statePtr->csPtr);
  2746 
  2747     /*
  2748      * Must set the interest mask now to 0, otherwise infinite loops
  2749      * will occur if Tcl_DoOneEvent is called before the channel is
  2750      * finally deleted in FlushChannel. This can happen if the channel
  2751      * has a background flush active.
  2752      */
  2753 
  2754     statePtr->interestMask = 0;
  2755 
  2756     /*
  2757      * Remove any EventScript records for this channel.
  2758      */
  2759 
  2760     for (ePtr = statePtr->scriptRecordPtr;
  2761 	 ePtr != (EventScriptRecord *) NULL;
  2762 	 ePtr = eNextPtr) {
  2763         eNextPtr = ePtr->nextPtr;
  2764 	Tcl_DecrRefCount(ePtr->scriptPtr);
  2765         ckfree((char *) ePtr);
  2766     }
  2767     statePtr->scriptRecordPtr = (EventScriptRecord *) NULL;
  2768 }
  2769 
  2770 /*
  2771  *----------------------------------------------------------------------
  2772  *
  2773  * Tcl_Write --
  2774  *
  2775  *	Puts a sequence of bytes into an output buffer, may queue the
  2776  *	buffer for output if it gets full, and also remembers whether the
  2777  *	current buffer is ready e.g. if it contains a newline and we are in
  2778  *	line buffering mode. Compensates stacking, i.e. will redirect the
  2779  *	data from the specified channel to the topmost channel in a stack.
  2780  *
  2781  *	No encoding conversions are applied to the bytes being read.
  2782  *
  2783  * Results:
  2784  *	The number of bytes written or -1 in case of error. If -1,
  2785  *	Tcl_GetErrno will return the error code.
  2786  *
  2787  * Side effects:
  2788  *	May buffer up output and may cause output to be produced on the
  2789  *	channel.
  2790  *
  2791  *----------------------------------------------------------------------
  2792  */
  2793 
  2794 EXPORT_C int
  2795 Tcl_Write(chan, src, srcLen)
  2796     Tcl_Channel chan;			/* The channel to buffer output for. */
  2797     CONST char *src;			/* Data to queue in output buffer. */
  2798     int srcLen;				/* Length of data in bytes, or < 0 for
  2799 					 * strlen(). */
  2800 {
  2801     /*
  2802      * Always use the topmost channel of the stack
  2803      */
  2804     Channel *chanPtr;
  2805     ChannelState *statePtr;	/* state info for channel */
  2806 
  2807     statePtr = ((Channel *) chan)->state;
  2808     chanPtr  = statePtr->topChanPtr;
  2809 
  2810     if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) {
  2811 	return -1;
  2812     }
  2813 
  2814     if (srcLen < 0) {
  2815         srcLen = strlen(src);
  2816     }
  2817     return DoWrite(chanPtr, src, srcLen);
  2818 }
  2819 
  2820 /*
  2821  *----------------------------------------------------------------------
  2822  *
  2823  * Tcl_WriteRaw --
  2824  *
  2825  *	Puts a sequence of bytes into an output buffer, may queue the
  2826  *	buffer for output if it gets full, and also remembers whether the
  2827  *	current buffer is ready e.g. if it contains a newline and we are in
  2828  *	line buffering mode. Writes directly to the driver of the channel,
  2829  *	does not compensate for stacking.
  2830  *
  2831  *	No encoding conversions are applied to the bytes being read.
  2832  *
  2833  * Results:
  2834  *	The number of bytes written or -1 in case of error. If -1,
  2835  *	Tcl_GetErrno will return the error code.
  2836  *
  2837  * Side effects:
  2838  *	May buffer up output and may cause output to be produced on the
  2839  *	channel.
  2840  *
  2841  *----------------------------------------------------------------------
  2842  */
  2843 
  2844 EXPORT_C int
  2845 Tcl_WriteRaw(chan, src, srcLen)
  2846     Tcl_Channel chan;			/* The channel to buffer output for. */
  2847     CONST char *src;			/* Data to queue in output buffer. */
  2848     int srcLen;				/* Length of data in bytes, or < 0 for
  2849 					 * strlen(). */
  2850 {
  2851     Channel *chanPtr = ((Channel *) chan);
  2852     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  2853     int errorCode, written;
  2854 
  2855     if (CheckChannelErrors(statePtr, TCL_WRITABLE | CHANNEL_RAW_MODE) != 0) {
  2856 	return -1;
  2857     }
  2858 
  2859     if (srcLen < 0) {
  2860         srcLen = strlen(src);
  2861     }
  2862 
  2863     /*
  2864      * Go immediately to the driver, do all the error handling by ourselves.
  2865      * The code was stolen from 'FlushChannel'.
  2866      */
  2867 
  2868     written = (chanPtr->typePtr->outputProc) (chanPtr->instanceData,
  2869 	    src, srcLen, &errorCode);
  2870 
  2871     if (written < 0) {
  2872 	Tcl_SetErrno(errorCode);
  2873     }
  2874 
  2875     return written;
  2876 }
  2877 
  2878 /*
  2879  *---------------------------------------------------------------------------
  2880  *
  2881  * Tcl_WriteChars --
  2882  *
  2883  *	Takes a sequence of UTF-8 characters and converts them for output
  2884  *	using the channel's current encoding, may queue the buffer for
  2885  *	output if it gets full, and also remembers whether the current
  2886  *	buffer is ready e.g. if it contains a newline and we are in
  2887  *	line buffering mode. Compensates stacking, i.e. will redirect the
  2888  *	data from the specified channel to the topmost channel in a stack.
  2889  *
  2890  * Results:
  2891  *	The number of bytes written or -1 in case of error. If -1,
  2892  *	Tcl_GetErrno will return the error code.
  2893  *
  2894  * Side effects:
  2895  *	May buffer up output and may cause output to be produced on the
  2896  *	channel.
  2897  *
  2898  *----------------------------------------------------------------------
  2899  */
  2900 
  2901 EXPORT_C int
  2902 Tcl_WriteChars(chan, src, len)
  2903     Tcl_Channel chan;		/* The channel to buffer output for. */
  2904     CONST char *src;		/* UTF-8 characters to queue in output buffer. */
  2905     int len;			/* Length of string in bytes, or < 0 for 
  2906 				 * strlen(). */
  2907 {
  2908     ChannelState *statePtr;	/* state info for channel */
  2909 
  2910     statePtr = ((Channel *) chan)->state;
  2911 
  2912     if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) {
  2913 	return -1;
  2914     }
  2915 
  2916     return DoWriteChars ((Channel*) chan, src, len);
  2917 }
  2918 
  2919 /*
  2920  *---------------------------------------------------------------------------
  2921  *
  2922  * DoWriteChars --
  2923  *
  2924  *	Takes a sequence of UTF-8 characters and converts them for output
  2925  *	using the channel's current encoding, may queue the buffer for
  2926  *	output if it gets full, and also remembers whether the current
  2927  *	buffer is ready e.g. if it contains a newline and we are in
  2928  *	line buffering mode. Compensates stacking, i.e. will redirect the
  2929  *	data from the specified channel to the topmost channel in a stack.
  2930  *
  2931  * Results:
  2932  *	The number of bytes written or -1 in case of error. If -1,
  2933  *	Tcl_GetErrno will return the error code.
  2934  *
  2935  * Side effects:
  2936  *	May buffer up output and may cause output to be produced on the
  2937  *	channel.
  2938  *
  2939  *----------------------------------------------------------------------
  2940  */
  2941 
  2942 static int
  2943 DoWriteChars(chanPtr, src, len)
  2944     Channel* chanPtr;		/* The channel to buffer output for. */
  2945     CONST char *src;		/* UTF-8 characters to queue in output buffer. */
  2946     int len;			/* Length of string in bytes, or < 0 for 
  2947 				 * strlen(). */
  2948 {
  2949     /*
  2950      * Always use the topmost channel of the stack
  2951      */
  2952     ChannelState *statePtr;	/* state info for channel */
  2953 
  2954     statePtr = chanPtr->state;
  2955     chanPtr  = statePtr->topChanPtr;
  2956 
  2957     if (len < 0) {
  2958         len = strlen(src);
  2959     }
  2960     if (statePtr->encoding == NULL) {
  2961 	/*
  2962 	 * Inefficient way to convert UTF-8 to byte-array, but the  
  2963 	 * code parallels the way it is done for objects.
  2964 	 */
  2965 
  2966 	Tcl_Obj *objPtr;
  2967 	int result;
  2968 
  2969 	objPtr = Tcl_NewStringObj(src, len);
  2970 	src = (char *) Tcl_GetByteArrayFromObj(objPtr, &len);
  2971 	result = WriteBytes(chanPtr, src, len);
  2972 	Tcl_DecrRefCount(objPtr);
  2973 	return result;
  2974     }
  2975     return WriteChars(chanPtr, src, len);
  2976 }
  2977 
  2978 /*
  2979  *---------------------------------------------------------------------------
  2980  *
  2981  * Tcl_WriteObj --
  2982  *
  2983  *	Takes the Tcl object and queues its contents for output.  If the 
  2984  *	encoding of the channel is NULL, takes the byte-array representation 
  2985  *	of the object and queues those bytes for output.  Otherwise, takes 
  2986  *	the characters in the UTF-8 (string) representation of the object 
  2987  *	and converts them for output using the channel's current encoding.  
  2988  *	May flush internal buffers to output if one becomes full or is ready 
  2989  *	for some other reason, e.g. if it contains a newline and the channel 
  2990  *	is in line buffering mode.
  2991  *
  2992  * Results:
  2993  *	The number of bytes written or -1 in case of error. If -1, 
  2994  *	Tcl_GetErrno() will return the error code.
  2995  *
  2996  * Side effects:
  2997  *	May buffer up output and may cause output to be produced on the
  2998  *	channel.
  2999  *
  3000  *----------------------------------------------------------------------
  3001  */
  3002 
  3003 EXPORT_C int
  3004 Tcl_WriteObj(chan, objPtr)
  3005     Tcl_Channel chan;		/* The channel to buffer output for. */
  3006     Tcl_Obj *objPtr;		/* The object to write. */
  3007 {
  3008     /*
  3009      * Always use the topmost channel of the stack
  3010      */
  3011     Channel *chanPtr;
  3012     ChannelState *statePtr;	/* state info for channel */
  3013     char *src;
  3014     int srcLen;
  3015 
  3016     statePtr = ((Channel *) chan)->state;
  3017     chanPtr  = statePtr->topChanPtr;
  3018 
  3019     if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) {
  3020 	return -1;
  3021     }
  3022     if (statePtr->encoding == NULL) {
  3023 	src = (char *) Tcl_GetByteArrayFromObj(objPtr, &srcLen);
  3024 	return WriteBytes(chanPtr, src, srcLen);
  3025     } else {
  3026 	src = Tcl_GetStringFromObj(objPtr, &srcLen);
  3027 	return WriteChars(chanPtr, src, srcLen);
  3028     }
  3029 }
  3030 
  3031 /*
  3032  *----------------------------------------------------------------------
  3033  *
  3034  * WriteBytes --
  3035  *
  3036  *	Write a sequence of bytes into an output buffer, may queue the
  3037  *	buffer for output if it gets full, and also remembers whether the
  3038  *	current buffer is ready e.g. if it contains a newline and we are in
  3039  *	line buffering mode.
  3040  *
  3041  * Results:
  3042  *	The number of bytes written or -1 in case of error. If -1,
  3043  *	Tcl_GetErrno will return the error code.
  3044  *
  3045  * Side effects:
  3046  *	May buffer up output and may cause output to be produced on the
  3047  *	channel.
  3048  *
  3049  *----------------------------------------------------------------------
  3050  */
  3051 
  3052 static int
  3053 WriteBytes(chanPtr, src, srcLen)
  3054     Channel *chanPtr;		/* The channel to buffer output for. */
  3055     CONST char *src;		/* Bytes to write. */
  3056     int srcLen;			/* Number of bytes to write. */
  3057 {
  3058     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  3059     ChannelBuffer *bufPtr;
  3060     char *dst;
  3061     int dstMax, sawLF, savedLF, total, dstLen, toWrite;
  3062     
  3063     total = 0;
  3064     sawLF = 0;
  3065     savedLF = 0;
  3066 
  3067     /*
  3068      * Loop over all bytes in src, storing them in output buffer with
  3069      * proper EOL translation.
  3070      */
  3071 
  3072     while (srcLen + savedLF > 0) {
  3073 	bufPtr = statePtr->curOutPtr;
  3074 	if (bufPtr == NULL) {
  3075 	    bufPtr = AllocChannelBuffer(statePtr->bufSize);
  3076 	    statePtr->curOutPtr	= bufPtr;
  3077 	}
  3078 	dst = bufPtr->buf + bufPtr->nextAdded;
  3079 	dstMax = bufPtr->bufLength - bufPtr->nextAdded;
  3080 	dstLen = dstMax;
  3081 
  3082 	toWrite = dstLen;
  3083 	if (toWrite > srcLen) {
  3084 	    toWrite = srcLen;
  3085 	}
  3086 
  3087 	if (savedLF) {
  3088 	    /*
  3089 	     * A '\n' was left over from last call to TranslateOutputEOL()
  3090 	     * and we need to store it in this buffer.  If the channel is
  3091 	     * line-based, we will need to flush it.
  3092 	     */
  3093 
  3094 	    *dst++ = '\n';
  3095 	    dstLen--;
  3096 	    sawLF++;
  3097 	}
  3098 	sawLF += TranslateOutputEOL(statePtr, dst, src, &dstLen, &toWrite);
  3099 	dstLen += savedLF;
  3100 	savedLF = 0;
  3101 
  3102 	if (dstLen > dstMax) {
  3103 	    savedLF = 1;
  3104 	    dstLen = dstMax;
  3105 	}
  3106 	bufPtr->nextAdded += dstLen;
  3107 	if (CheckFlush(chanPtr, bufPtr, sawLF) != 0) {
  3108 	    return -1;
  3109 	}
  3110 	total += dstLen;
  3111 	src += toWrite;
  3112 	srcLen -= toWrite;
  3113 	sawLF = 0;
  3114     }
  3115     return total;
  3116 }
  3117 
  3118 /*
  3119  *----------------------------------------------------------------------
  3120  *
  3121  * WriteChars --
  3122  *
  3123  *	Convert UTF-8 bytes to the channel's external encoding and
  3124  *	write the produced bytes into an output buffer, may queue the 
  3125  *	buffer for output if it gets full, and also remembers whether the
  3126  *	current buffer is ready e.g. if it contains a newline and we are in
  3127  *	line buffering mode.
  3128  *
  3129  * Results:
  3130  *	The number of bytes written or -1 in case of error. If -1,
  3131  *	Tcl_GetErrno will return the error code.
  3132  *
  3133  * Side effects:
  3134  *	May buffer up output and may cause output to be produced on the
  3135  *	channel.
  3136  *
  3137  *----------------------------------------------------------------------
  3138  */
  3139 
  3140 static int
  3141 WriteChars(chanPtr, src, srcLen)
  3142     Channel *chanPtr;		/* The channel to buffer output for. */
  3143     CONST char *src;		/* UTF-8 string to write. */
  3144     int srcLen;			/* Length of UTF-8 string in bytes. */
  3145 {
  3146     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  3147     ChannelBuffer *bufPtr;
  3148     char *dst, *stage;
  3149     int saved, savedLF, sawLF, total, dstLen, stageMax, dstWrote;
  3150     int stageLen, toWrite, stageRead, endEncoding, result;
  3151     int consumedSomething;
  3152     Tcl_Encoding encoding;
  3153     char safe[BUFFER_PADDING];
  3154     
  3155     total = 0;
  3156     sawLF = 0;
  3157     savedLF = 0;
  3158     saved = 0;
  3159     encoding = statePtr->encoding;
  3160 
  3161     /*
  3162      * Write the terminated escape sequence even if srcLen is 0.
  3163      */
  3164 
  3165     endEncoding = ((statePtr->outputEncodingFlags & TCL_ENCODING_END) != 0);
  3166 
  3167     /*
  3168      * Loop over all UTF-8 characters in src, storing them in staging buffer
  3169      * with proper EOL translation.
  3170      */
  3171 
  3172     consumedSomething = 1;
  3173     while (consumedSomething && (srcLen + savedLF + endEncoding > 0)) {
  3174         consumedSomething = 0;
  3175 	stage = statePtr->outputStage;
  3176 	stageMax = statePtr->bufSize;
  3177 	stageLen = stageMax;
  3178 
  3179 	toWrite = stageLen;
  3180 	if (toWrite > srcLen) {
  3181 	    toWrite = srcLen;
  3182 	}
  3183 
  3184 	if (savedLF) {
  3185 	    /*
  3186 	     * A '\n' was left over from last call to TranslateOutputEOL()
  3187 	     * and we need to store it in the staging buffer.  If the
  3188 	     * channel is line-based, we will need to flush the output
  3189 	     * buffer (after translating the staging buffer).
  3190 	     */
  3191 	    
  3192 	    *stage++ = '\n';
  3193 	    stageLen--;
  3194 	    sawLF++;
  3195 	}
  3196 	sawLF += TranslateOutputEOL(statePtr, stage, src, &stageLen, &toWrite);
  3197 
  3198 	stage -= savedLF;
  3199 	stageLen += savedLF;
  3200 	savedLF = 0;
  3201 
  3202 	if (stageLen > stageMax) {
  3203 	    savedLF = 1;
  3204 	    stageLen = stageMax;
  3205 	}
  3206 	src += toWrite;
  3207 	srcLen -= toWrite;
  3208 
  3209 	/*
  3210 	 * Loop over all UTF-8 characters in staging buffer, converting them
  3211 	 * to external encoding, storing them in output buffer.
  3212 	 */
  3213 
  3214 	while (stageLen + saved + endEncoding > 0) {
  3215 	    bufPtr = statePtr->curOutPtr;
  3216 	    if (bufPtr == NULL) {
  3217 		bufPtr = AllocChannelBuffer(statePtr->bufSize);
  3218 		statePtr->curOutPtr = bufPtr;
  3219 	    }
  3220 	    dst = bufPtr->buf + bufPtr->nextAdded;
  3221 	    dstLen = bufPtr->bufLength - bufPtr->nextAdded;
  3222 
  3223 	    if (saved != 0) {
  3224 		/*
  3225 		 * Here's some translated bytes left over from the last
  3226 		 * buffer that we need to stick at the beginning of this
  3227 		 * buffer.
  3228 		 */
  3229 		 
  3230 		memcpy((VOID *) dst, (VOID *) safe, (size_t) saved);
  3231 		bufPtr->nextAdded += saved;
  3232 		dst += saved;
  3233 		dstLen -= saved;
  3234 		saved = 0;
  3235 	    }
  3236 
  3237 	    result = Tcl_UtfToExternal(NULL, encoding, stage, stageLen,
  3238 		    statePtr->outputEncodingFlags,
  3239 		    &statePtr->outputEncodingState, dst,
  3240 		    dstLen + BUFFER_PADDING, &stageRead, &dstWrote, NULL);
  3241 
  3242 	    /* Fix for SF #506297, reported by Martin Forssen
  3243 	     * <ruric@users.sourceforge.net>.
  3244 	     *
  3245 	     * The encoding chosen in the script exposing the bug writes out
  3246 	     * three intro characters when TCL_ENCODING_START is set, but does
  3247 	     * not consume any input as TCL_ENCODING_END is cleared. As some
  3248 	     * output was generated the enclosing loop calls UtfToExternal
  3249 	     * again, again with START set. Three more characters in the out
  3250 	     * and still no use of input ... To break this infinite loop we
  3251 	     * remove TCL_ENCODING_START from the set of flags after the first
  3252 	     * call (no condition is required, the later calls remove an unset
  3253 	     * flag, which is a no-op). This causes the subsequent calls to
  3254 	     * UtfToExternal to consume and convert the actual input.
  3255 	     */
  3256 
  3257 	    statePtr->outputEncodingFlags &= ~TCL_ENCODING_START;
  3258 	    /*
  3259 	     * The following code must be executed only when result is not 0.
  3260 	     */
  3261 	    if (result && ((stageRead + dstWrote) == 0)) {
  3262 		/*
  3263 		 * We have an incomplete UTF-8 character at the end of the
  3264 		 * staging buffer.  It will get moved to the beginning of the
  3265 		 * staging buffer followed by more bytes from src.
  3266 		 */
  3267 
  3268 		src -= stageLen;
  3269 		srcLen += stageLen;
  3270 		stageLen = 0;
  3271 		savedLF = 0;
  3272 		break;
  3273 	    }
  3274 	    bufPtr->nextAdded += dstWrote;
  3275 	    if (bufPtr->nextAdded > bufPtr->bufLength) {
  3276 		/*
  3277 		 * When translating from UTF-8 to external encoding, we
  3278 		 * allowed the translation to produce a character that
  3279 		 * crossed the end of the output buffer, so that we would
  3280 		 * get a completely full buffer before flushing it.  The
  3281 		 * extra bytes will be moved to the beginning of the next
  3282 		 * buffer.
  3283 		 */
  3284 
  3285 		saved = bufPtr->nextAdded - bufPtr->bufLength;
  3286 		memcpy((VOID *) safe, (VOID *) (dst + dstLen), (size_t) saved);
  3287 		bufPtr->nextAdded = bufPtr->bufLength;
  3288 	    }
  3289 	    if (CheckFlush(chanPtr, bufPtr, sawLF) != 0) {
  3290 		return -1;
  3291 	    }
  3292 
  3293 	    total += dstWrote;
  3294 	    stage += stageRead;
  3295 	    stageLen -= stageRead;
  3296 	    sawLF = 0;
  3297 
  3298 	    consumedSomething = 1;
  3299 
  3300 	    /*
  3301 	     * If all translated characters are written to the buffer,
  3302 	     * endEncoding is set to 0 because the escape sequence may be
  3303 	     * output.
  3304 	     */
  3305 
  3306 	    if ((stageLen + saved == 0) && (result == 0)) {
  3307 		endEncoding = 0;
  3308 	    }
  3309 	}
  3310     }
  3311 
  3312     /* If nothing was written and it happened because there was no progress
  3313      * in the UTF conversion, we throw an error.
  3314      */
  3315 
  3316     if (!consumedSomething && (total == 0)) {
  3317         Tcl_SetErrno (EINVAL);
  3318         return -1;
  3319     }
  3320     return total;
  3321 }
  3322 
  3323 /*
  3324  *---------------------------------------------------------------------------
  3325  *
  3326  * TranslateOutputEOL --
  3327  *
  3328  *	Helper function for WriteBytes() and WriteChars().  Converts the
  3329  *	'\n' characters in the source buffer into the appropriate EOL
  3330  *	form specified by the output translation mode.
  3331  *
  3332  *	EOL translation stops either when the source buffer is empty
  3333  *	or the output buffer is full.
  3334  *
  3335  *	When converting to CRLF mode and there is only 1 byte left in
  3336  *	the output buffer, this routine stores the '\r' in the last
  3337  *	byte and then stores the '\n' in the byte just past the end of the 
  3338  *	buffer.  The caller is responsible for passing in a buffer that
  3339  *	is large enough to hold the extra byte.
  3340  *
  3341  * Results:
  3342  *	The return value is 1 if a '\n' was translated from the source
  3343  *	buffer, or 0 otherwise -- this can be used by the caller to
  3344  *	decide to flush a line-based channel even though the channel
  3345  *	buffer is not full.
  3346  *
  3347  *	*dstLenPtr is filled with how many bytes of the output buffer
  3348  *	were used.  As mentioned above, this can be one more that
  3349  *	the output buffer's specified length if a CRLF was stored.
  3350  *
  3351  *	*srcLenPtr is filled with how many bytes of the source buffer
  3352  *	were consumed.  
  3353  *
  3354  * Side effects:
  3355  *	It may be obvious, but bears mentioning that when converting
  3356  *	in CRLF mode (which requires two bytes of storage in the output
  3357  *	buffer), the number of bytes consumed from the source buffer
  3358  *	will be less than the number of bytes stored in the output buffer.
  3359  *
  3360  *---------------------------------------------------------------------------
  3361  */
  3362 
  3363 static int
  3364 TranslateOutputEOL(statePtr, dst, src, dstLenPtr, srcLenPtr)
  3365     ChannelState *statePtr;	/* Channel being read, for translation and
  3366 				 * buffering modes. */
  3367     char *dst;			/* Output buffer filled with UTF-8 chars by
  3368 				 * applying appropriate EOL translation to
  3369 				 * source characters. */
  3370     CONST char *src;		/* Source UTF-8 characters. */
  3371     int *dstLenPtr;		/* On entry, the maximum length of output
  3372 				 * buffer in bytes.  On exit, the number of
  3373 				 * bytes actually used in output buffer. */
  3374     int *srcLenPtr;		/* On entry, the length of source buffer.
  3375 				 * On exit, the number of bytes read from
  3376 				 * the source buffer. */
  3377 {
  3378     char *dstEnd;
  3379     int srcLen, newlineFound;
  3380     
  3381     newlineFound = 0;
  3382     srcLen = *srcLenPtr;
  3383 
  3384     switch (statePtr->outputTranslation) {
  3385 	case TCL_TRANSLATE_LF: {
  3386 	    for (dstEnd = dst + srcLen; dst < dstEnd; ) {
  3387 		if (*src == '\n') {
  3388 		    newlineFound = 1;
  3389 		}
  3390 		*dst++ = *src++;
  3391 	    }
  3392 	    *dstLenPtr = srcLen;
  3393 	    break;
  3394 	}
  3395 	case TCL_TRANSLATE_CR: {
  3396 	    for (dstEnd = dst + srcLen; dst < dstEnd;) {
  3397 		if (*src == '\n') {
  3398 		    *dst++ = '\r';
  3399 		    newlineFound = 1;
  3400 		    src++;
  3401 		} else {
  3402 		    *dst++ = *src++;
  3403 		}
  3404 	    }
  3405 	    *dstLenPtr = srcLen;
  3406 	    break;
  3407 	}
  3408 	case TCL_TRANSLATE_CRLF: {
  3409 	    /*
  3410 	     * Since this causes the number of bytes to grow, we
  3411 	     * start off trying to put 'srcLen' bytes into the
  3412 	     * output buffer, but allow it to store more bytes, as
  3413 	     * long as there's still source bytes and room in the
  3414 	     * output buffer.
  3415 	     */
  3416 
  3417 	    char *dstStart, *dstMax;
  3418 	    CONST char *srcStart;
  3419 	    
  3420 	    dstStart = dst;
  3421 	    dstMax = dst + *dstLenPtr;
  3422 
  3423 	    srcStart = src;
  3424 	    
  3425 	    if (srcLen < *dstLenPtr) {
  3426 		dstEnd = dst + srcLen;
  3427 	    } else {
  3428 		dstEnd = dst + *dstLenPtr;
  3429 	    }
  3430 	    while (dst < dstEnd) {
  3431 		if (*src == '\n') {
  3432 		    if (dstEnd < dstMax) {
  3433 			dstEnd++;
  3434 		    }
  3435 		    *dst++ = '\r';
  3436 		    newlineFound = 1;
  3437 		}
  3438 		*dst++ = *src++;
  3439 	    }
  3440 	    *srcLenPtr = src - srcStart;
  3441 	    *dstLenPtr = dst - dstStart;
  3442 	    break;
  3443 	}
  3444 	default: {
  3445 	    break;
  3446 	}
  3447     }
  3448     return newlineFound;
  3449 }
  3450 
  3451 /*
  3452  *---------------------------------------------------------------------------
  3453  *
  3454  * CheckFlush --
  3455  *
  3456  *	Helper function for WriteBytes() and WriteChars().  If the
  3457  *	channel buffer is ready to be flushed, flush it.
  3458  *
  3459  * Results:
  3460  *	The return value is -1 if there was a problem flushing the
  3461  *	channel buffer, or 0 otherwise.
  3462  *
  3463  * Side effects:
  3464  *	The buffer will be recycled if it is flushed.
  3465  *
  3466  *---------------------------------------------------------------------------
  3467  */
  3468 
  3469 static int
  3470 CheckFlush(chanPtr, bufPtr, newlineFlag)
  3471     Channel *chanPtr;		/* Channel being read, for buffering mode. */
  3472     ChannelBuffer *bufPtr;	/* Channel buffer to possibly flush. */
  3473     int newlineFlag;		/* Non-zero if a the channel buffer
  3474 				 * contains a newline. */
  3475 {
  3476     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  3477     /*
  3478      * The current buffer is ready for output:
  3479      * 1. if it is full.
  3480      * 2. if it contains a newline and this channel is line-buffered.
  3481      * 3. if it contains any output and this channel is unbuffered.
  3482      */
  3483 
  3484     if ((statePtr->flags & BUFFER_READY) == 0) {
  3485 	if (bufPtr->nextAdded == bufPtr->bufLength) {
  3486 	    statePtr->flags |= BUFFER_READY;
  3487 	} else if (statePtr->flags & CHANNEL_LINEBUFFERED) {
  3488 	    if (newlineFlag != 0) {
  3489 		statePtr->flags |= BUFFER_READY;
  3490 	    }
  3491 	} else if (statePtr->flags & CHANNEL_UNBUFFERED) {
  3492 	    statePtr->flags |= BUFFER_READY;
  3493 	}
  3494     }
  3495     if (statePtr->flags & BUFFER_READY) {
  3496 	if (FlushChannel(NULL, chanPtr, 0) != 0) {
  3497 	    return -1;
  3498 	}
  3499     }
  3500     return 0;
  3501 }
  3502 
  3503 /*
  3504  *---------------------------------------------------------------------------
  3505  *
  3506  * Tcl_Gets --
  3507  *
  3508  *	Reads a complete line of input from the channel into a Tcl_DString.
  3509  *
  3510  * Results:
  3511  *	Length of line read (in characters) or -1 if error, EOF, or blocked.
  3512  *	If -1, use Tcl_GetErrno() to retrieve the POSIX error code for the
  3513  *	error or condition that occurred.
  3514  *
  3515  * Side effects:
  3516  *	May flush output on the channel.  May cause input to be consumed
  3517  *	from the channel.
  3518  *
  3519  *---------------------------------------------------------------------------
  3520  */
  3521 
  3522 EXPORT_C int
  3523 Tcl_Gets(chan, lineRead)
  3524     Tcl_Channel chan;		/* Channel from which to read. */
  3525     Tcl_DString *lineRead;	/* The line read will be appended to this
  3526 				 * DString as UTF-8 characters.  The caller
  3527 				 * must have initialized it and is responsible
  3528 				 * for managing the storage. */
  3529 {
  3530     Tcl_Obj *objPtr;
  3531     int charsStored, length;
  3532     char *string;
  3533 
  3534     objPtr = Tcl_NewObj();
  3535     charsStored = Tcl_GetsObj(chan, objPtr);
  3536     if (charsStored > 0) {
  3537 	string = Tcl_GetStringFromObj(objPtr, &length);
  3538 	Tcl_DStringAppend(lineRead, string, length);
  3539     }
  3540     Tcl_DecrRefCount(objPtr);
  3541     return charsStored;
  3542 }
  3543 
  3544 /*
  3545  *---------------------------------------------------------------------------
  3546  *
  3547  * Tcl_GetsObj --
  3548  *
  3549  *	Accumulate input from the input channel until end-of-line or
  3550  *	end-of-file has been seen.  Bytes read from the input channel
  3551  *	are converted to UTF-8 using the encoding specified by the
  3552  *	channel.
  3553  *
  3554  * Results:
  3555  *	Number of characters accumulated in the object or -1 if error,
  3556  *	blocked, or EOF.  If -1, use Tcl_GetErrno() to retrieve the
  3557  *	POSIX error code for the error or condition that occurred.
  3558  *
  3559  * Side effects:
  3560  *	Consumes input from the channel.
  3561  *
  3562  *	On reading EOF, leave channel pointing at EOF char.
  3563  *	On reading EOL, leave channel pointing after EOL, but don't
  3564  *	return EOL in dst buffer.
  3565  *
  3566  *---------------------------------------------------------------------------
  3567  */
  3568 
  3569 EXPORT_C int
  3570 Tcl_GetsObj(chan, objPtr)
  3571     Tcl_Channel chan;		/* Channel from which to read. */
  3572     Tcl_Obj *objPtr;		/* The line read will be appended to this
  3573 				 * object as UTF-8 characters. */
  3574 {
  3575     GetsState gs;
  3576     Channel *chanPtr = (Channel *) chan;
  3577     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  3578     ChannelBuffer *bufPtr;
  3579     int inEofChar, skip, copiedTotal, oldLength, oldFlags, oldRemoved;
  3580     Tcl_Encoding encoding;
  3581     char *dst, *dstEnd, *eol, *eof;
  3582     Tcl_EncodingState oldState;
  3583 
  3584     /*
  3585      * This operation should occur at the top of a channel stack.
  3586      */
  3587 
  3588     chanPtr = statePtr->topChanPtr;
  3589 
  3590     if (CheckChannelErrors(statePtr, TCL_READABLE) != 0) {
  3591 	copiedTotal = -1;
  3592 	goto done;
  3593     }
  3594 
  3595     bufPtr = statePtr->inQueueHead;
  3596     encoding = statePtr->encoding;
  3597 
  3598     /*
  3599      * Preserved so we can restore the channel's state in case we don't
  3600      * find a newline in the available input.
  3601      */
  3602 
  3603     Tcl_GetStringFromObj(objPtr, &oldLength);
  3604     oldFlags = statePtr->inputEncodingFlags;
  3605     oldState = statePtr->inputEncodingState;
  3606     oldRemoved = BUFFER_PADDING;
  3607     if (bufPtr != NULL) {
  3608 	oldRemoved = bufPtr->nextRemoved;
  3609     }
  3610 
  3611     /*
  3612      * If there is no encoding, use "iso8859-1" -- Tcl_GetsObj() doesn't
  3613      * produce ByteArray objects.  To avoid circularity problems,
  3614      * "iso8859-1" is builtin to Tcl.
  3615      */
  3616 
  3617     if (encoding == NULL) {
  3618 	encoding = Tcl_GetEncoding(NULL, "iso8859-1");
  3619     }
  3620 
  3621     /*
  3622      * Object used by FilterInputBytes to keep track of how much data has
  3623      * been consumed from the channel buffers.
  3624      */
  3625 
  3626     gs.objPtr		= objPtr;
  3627     gs.dstPtr		= &dst;
  3628     gs.encoding		= encoding;
  3629     gs.bufPtr		= bufPtr;
  3630     gs.state		= oldState;
  3631     gs.rawRead		= 0;
  3632     gs.bytesWrote	= 0;
  3633     gs.charsWrote	= 0;
  3634     gs.totalChars	= 0;
  3635 
  3636     dst = objPtr->bytes + oldLength;
  3637     dstEnd = dst;
  3638 
  3639     skip = 0;
  3640     eof = NULL;
  3641     inEofChar = statePtr->inEofChar;
  3642 
  3643     while (1) {
  3644 	if (dst >= dstEnd) {
  3645 	    if (FilterInputBytes(chanPtr, &gs) != 0) {
  3646 		goto restore;
  3647 	    }
  3648 	    dstEnd = dst + gs.bytesWrote;
  3649 	}
  3650 	
  3651 	/*
  3652 	 * Remember if EOF char is seen, then look for EOL anyhow, because
  3653 	 * the EOL might be before the EOF char.
  3654 	 */
  3655 
  3656 	if (inEofChar != '\0') {
  3657 	    for (eol = dst; eol < dstEnd; eol++) {
  3658 		if (*eol == inEofChar) {
  3659 		    dstEnd = eol;
  3660 		    eof = eol;
  3661 		    break;
  3662 		}
  3663 	    }
  3664 	}
  3665 
  3666 	/*
  3667 	 * On EOL, leave current file position pointing after the EOL, but
  3668 	 * don't store the EOL in the output string.
  3669 	 */
  3670 
  3671 	switch (statePtr->inputTranslation) {
  3672 	    case TCL_TRANSLATE_LF: {
  3673 		for (eol = dst; eol < dstEnd; eol++) {
  3674 		    if (*eol == '\n') {
  3675 			skip = 1;
  3676 			goto goteol;
  3677 		    }
  3678 		}
  3679 		break;
  3680 	    }
  3681 	    case TCL_TRANSLATE_CR: {
  3682 		for (eol = dst; eol < dstEnd; eol++) {
  3683 		    if (*eol == '\r') {
  3684 			skip = 1;
  3685 			goto goteol;
  3686 		    }
  3687 		}
  3688 		break;
  3689 	    }
  3690 	    case TCL_TRANSLATE_CRLF: {
  3691 		for (eol = dst; eol < dstEnd; eol++) {
  3692 		    if (*eol == '\r') {
  3693 			eol++;
  3694 			if (eol >= dstEnd) {
  3695 			    int offset;
  3696 			    
  3697 			    offset = eol - objPtr->bytes;
  3698 			    dst = dstEnd;
  3699 			    if (FilterInputBytes(chanPtr, &gs) != 0) {
  3700 				goto restore;
  3701 			    }
  3702 			    dstEnd = dst + gs.bytesWrote;
  3703 			    eol = objPtr->bytes + offset;
  3704 			    if (eol >= dstEnd) {
  3705 				skip = 0;
  3706 				goto goteol;
  3707 			    }
  3708 			}
  3709 			if (*eol == '\n') {
  3710 			    eol--;
  3711 			    skip = 2;
  3712 			    goto goteol;
  3713 			}
  3714 		    }
  3715 		}
  3716 		break;
  3717 	    }
  3718 	    case TCL_TRANSLATE_AUTO: {
  3719 		eol = dst;
  3720 		skip = 1;
  3721 		if (statePtr->flags & INPUT_SAW_CR) {
  3722 		    statePtr->flags &= ~INPUT_SAW_CR;
  3723 		    if (*eol == '\n') {
  3724 			/*
  3725 			 * Skip the raw bytes that make up the '\n'.
  3726 			 */
  3727 
  3728 			char tmp[1 + TCL_UTF_MAX];
  3729 			int rawRead;
  3730 
  3731 			bufPtr = gs.bufPtr;
  3732 			Tcl_ExternalToUtf(NULL, gs.encoding,
  3733 				bufPtr->buf + bufPtr->nextRemoved,
  3734 				gs.rawRead, statePtr->inputEncodingFlags,
  3735 				&gs.state, tmp, 1 + TCL_UTF_MAX, &rawRead,
  3736 				NULL, NULL);
  3737 			bufPtr->nextRemoved += rawRead;
  3738 			gs.rawRead -= rawRead;
  3739 			gs.bytesWrote--;
  3740 			gs.charsWrote--;
  3741 			memmove(dst, dst + 1, (size_t) (dstEnd - dst));
  3742 			dstEnd--;
  3743 		    }
  3744 		}
  3745 		for (eol = dst; eol < dstEnd; eol++) {
  3746 		    if (*eol == '\r') {
  3747 			eol++;
  3748 			if (eol == dstEnd) {
  3749 			    /*
  3750 			     * If buffer ended on \r, peek ahead to see if a
  3751 			     * \n is available.
  3752 			     */
  3753 
  3754 			    int offset;
  3755 			    
  3756 			    offset = eol - objPtr->bytes;
  3757 			    dst = dstEnd;
  3758 			    PeekAhead(chanPtr, &dstEnd, &gs);
  3759 			    eol = objPtr->bytes + offset;
  3760 			    if (eol >= dstEnd) {
  3761 				eol--;
  3762 				statePtr->flags |= INPUT_SAW_CR;
  3763 				goto goteol;
  3764 			    }
  3765 			}
  3766 			if (*eol == '\n') {
  3767 			    skip++;
  3768 			}
  3769 			eol--;
  3770 			goto goteol;
  3771 		    } else if (*eol == '\n') {
  3772 			goto goteol;
  3773 		    }
  3774 		}
  3775 	    }
  3776 	}
  3777 	if (eof != NULL) {
  3778 	    /*
  3779 	     * EOF character was seen.  On EOF, leave current file position
  3780 	     * pointing at the EOF character, but don't store the EOF
  3781 	     * character in the output string.
  3782 	     */
  3783 
  3784 	    dstEnd = eof;
  3785 	    statePtr->flags |= (CHANNEL_EOF | CHANNEL_STICKY_EOF);
  3786 	    statePtr->inputEncodingFlags |= TCL_ENCODING_END;
  3787 	}
  3788 	if (statePtr->flags & CHANNEL_EOF) {
  3789 	    skip = 0;
  3790 	    eol = dstEnd;
  3791 	    if (eol == objPtr->bytes + oldLength) {
  3792 		/*
  3793 		 * If we didn't append any bytes before encountering EOF,
  3794 		 * caller needs to see -1.
  3795 		 */
  3796 
  3797 		Tcl_SetObjLength(objPtr, oldLength);
  3798 		CommonGetsCleanup(chanPtr, encoding);
  3799 		copiedTotal = -1;
  3800 		goto done;
  3801 	    }
  3802 	    goto goteol;
  3803 	}
  3804 	dst = dstEnd;
  3805     }
  3806 
  3807     /*
  3808      * Found EOL or EOF, but the output buffer may now contain too many
  3809      * UTF-8 characters.  We need to know how many raw bytes correspond to
  3810      * the number of UTF-8 characters we want, plus how many raw bytes
  3811      * correspond to the character(s) making up EOL (if any), so we can
  3812      * remove the correct number of bytes from the channel buffer.
  3813      */
  3814      
  3815     goteol:
  3816     bufPtr = gs.bufPtr;
  3817     statePtr->inputEncodingState = gs.state;
  3818     Tcl_ExternalToUtf(NULL, gs.encoding, bufPtr->buf + bufPtr->nextRemoved,
  3819 	    gs.rawRead, statePtr->inputEncodingFlags,
  3820 	    &statePtr->inputEncodingState, dst,
  3821 	    eol - dst + skip + TCL_UTF_MAX, &gs.rawRead, NULL,
  3822 	    &gs.charsWrote);
  3823     bufPtr->nextRemoved += gs.rawRead;
  3824 
  3825     /*
  3826      * Recycle all the emptied buffers.
  3827      */
  3828 
  3829     Tcl_SetObjLength(objPtr, eol - objPtr->bytes);
  3830     CommonGetsCleanup(chanPtr, encoding);
  3831     statePtr->flags &= ~CHANNEL_BLOCKED;
  3832     copiedTotal = gs.totalChars + gs.charsWrote - skip;
  3833     goto done;
  3834 
  3835     /*
  3836      * Couldn't get a complete line.  This only happens if we get a error
  3837      * reading from the channel or we are non-blocking and there wasn't
  3838      * an EOL or EOF in the data available.
  3839      */
  3840 
  3841     restore:
  3842     bufPtr = statePtr->inQueueHead;
  3843     bufPtr->nextRemoved = oldRemoved;
  3844 
  3845     for (bufPtr = bufPtr->nextPtr; bufPtr != NULL; bufPtr = bufPtr->nextPtr) {
  3846 	bufPtr->nextRemoved = BUFFER_PADDING;
  3847     }
  3848     CommonGetsCleanup(chanPtr, encoding);
  3849 
  3850     statePtr->inputEncodingState = oldState;
  3851     statePtr->inputEncodingFlags = oldFlags;
  3852     Tcl_SetObjLength(objPtr, oldLength);
  3853 
  3854     /*
  3855      * We didn't get a complete line so we need to indicate to UpdateInterest
  3856      * that the gets blocked.  It will wait for more data instead of firing
  3857      * a timer, avoiding a busy wait.  This is where we are assuming that the
  3858      * next operation is a gets.  No more file events will be delivered on 
  3859      * this channel until new data arrives or some operation is performed
  3860      * on the channel (e.g. gets, read, fconfigure) that changes the blocking
  3861      * state.  Note that this means a file event will not be delivered even
  3862      * though a read would be able to consume the buffered data.
  3863      */
  3864 
  3865     statePtr->flags |= CHANNEL_NEED_MORE_DATA;
  3866     copiedTotal = -1;
  3867 
  3868     done:
  3869     /*
  3870      * Update the notifier state so we don't block while there is still
  3871      * data in the buffers.
  3872      */
  3873 
  3874     UpdateInterest(chanPtr);
  3875     return copiedTotal;
  3876 }
  3877 
  3878 /*
  3879  *---------------------------------------------------------------------------
  3880  *
  3881  * FilterInputBytes --
  3882  *
  3883  *	Helper function for Tcl_GetsObj.  Produces UTF-8 characters from
  3884  *	raw bytes read from the channel.  
  3885  *
  3886  *	Consumes available bytes from channel buffers.  When channel
  3887  *	buffers are exhausted, reads more bytes from channel device into
  3888  *	a new channel buffer.  It is the caller's responsibility to
  3889  *	free the channel buffers that have been exhausted.
  3890  *
  3891  * Results:
  3892  *	The return value is -1 if there was an error reading from the
  3893  *	channel, 0 otherwise.
  3894  *
  3895  * Side effects:
  3896  *	Status object keeps track of how much data from channel buffers
  3897  *	has been consumed and where UTF-8 bytes should be stored.
  3898  *
  3899  *---------------------------------------------------------------------------
  3900  */
  3901  
  3902 static int
  3903 FilterInputBytes(chanPtr, gsPtr)
  3904     Channel *chanPtr;		/* Channel to read. */
  3905     GetsState *gsPtr;		/* Current state of gets operation. */
  3906 {
  3907     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  3908     ChannelBuffer *bufPtr;
  3909     char *raw, *rawStart, *rawEnd;
  3910     char *dst;
  3911     int offset, toRead, dstNeeded, spaceLeft, result, rawLen, length;
  3912     Tcl_Obj *objPtr;
  3913 #define ENCODING_LINESIZE   20	/* Lower bound on how many bytes to convert
  3914 				 * at a time.  Since we don't know a priori
  3915 				 * how many bytes of storage this many source
  3916 				 * bytes will use, we actually need at least
  3917 				 * ENCODING_LINESIZE * TCL_MAX_UTF bytes of
  3918 				 * room. */
  3919 
  3920     objPtr = gsPtr->objPtr;
  3921 
  3922     /*
  3923      * Subtract the number of bytes that were removed from channel buffer
  3924      * during last call.
  3925      */
  3926 
  3927     bufPtr = gsPtr->bufPtr;
  3928     if (bufPtr != NULL) {
  3929 	bufPtr->nextRemoved += gsPtr->rawRead;
  3930 	if (bufPtr->nextRemoved >= bufPtr->nextAdded) {
  3931 	    bufPtr = bufPtr->nextPtr;
  3932 	}
  3933     }
  3934     gsPtr->totalChars += gsPtr->charsWrote;
  3935 
  3936     if ((bufPtr == NULL) || (bufPtr->nextAdded == BUFFER_PADDING)) {
  3937 	/*
  3938 	 * All channel buffers were exhausted and the caller still hasn't
  3939 	 * seen EOL.  Need to read more bytes from the channel device.
  3940 	 * Side effect is to allocate another channel buffer.
  3941 	 */
  3942 
  3943 	read:
  3944         if (statePtr->flags & CHANNEL_BLOCKED) {
  3945             if (statePtr->flags & CHANNEL_NONBLOCKING) {
  3946 		gsPtr->charsWrote = 0;
  3947 		gsPtr->rawRead = 0;
  3948 		return -1;
  3949 	    }
  3950             statePtr->flags &= ~CHANNEL_BLOCKED;
  3951         }
  3952 	if (GetInput(chanPtr) != 0) {
  3953 	    gsPtr->charsWrote = 0;
  3954 	    gsPtr->rawRead = 0;
  3955 	    return -1;
  3956 	}
  3957 	bufPtr = statePtr->inQueueTail;
  3958 	gsPtr->bufPtr = bufPtr;
  3959     }
  3960 
  3961     /*
  3962      * Convert some of the bytes from the channel buffer to UTF-8.  Space in
  3963      * objPtr's string rep is used to hold the UTF-8 characters.  Grow the
  3964      * string rep if we need more space.
  3965      */
  3966 
  3967     rawStart = bufPtr->buf + bufPtr->nextRemoved;
  3968     raw = rawStart;
  3969     rawEnd = bufPtr->buf + bufPtr->nextAdded;
  3970     rawLen = rawEnd - rawStart;
  3971 
  3972     dst = *gsPtr->dstPtr;
  3973     offset = dst - objPtr->bytes;
  3974     toRead = ENCODING_LINESIZE;
  3975     if (toRead > rawLen) {
  3976 	toRead = rawLen;
  3977     }
  3978     dstNeeded = toRead * TCL_UTF_MAX + 1;
  3979     spaceLeft = objPtr->length - offset - TCL_UTF_MAX - 1;
  3980     if (dstNeeded > spaceLeft) {
  3981 	length = offset * 2;
  3982 	if (offset < dstNeeded) {
  3983 	    length = offset + dstNeeded;
  3984 	}
  3985 	length += TCL_UTF_MAX + 1;
  3986 	Tcl_SetObjLength(objPtr, length);
  3987 	spaceLeft = length - offset;
  3988 	dst = objPtr->bytes + offset;
  3989 	*gsPtr->dstPtr = dst;
  3990     }
  3991     gsPtr->state = statePtr->inputEncodingState;
  3992     result = Tcl_ExternalToUtf(NULL, gsPtr->encoding, raw, rawLen,
  3993 	    statePtr->inputEncodingFlags, &statePtr->inputEncodingState,
  3994 	    dst, spaceLeft, &gsPtr->rawRead, &gsPtr->bytesWrote,
  3995 	    &gsPtr->charsWrote);
  3996 
  3997     /*
  3998      * Make sure that if we go through 'gets', that we reset the
  3999      * TCL_ENCODING_START flag still.  [Bug #523988]
  4000      */
  4001     statePtr->inputEncodingFlags &= ~TCL_ENCODING_START;
  4002 
  4003     if (result == TCL_CONVERT_MULTIBYTE) {
  4004 	/*
  4005 	 * The last few bytes in this channel buffer were the start of a
  4006 	 * multibyte sequence.  If this buffer was full, then move them to
  4007 	 * the next buffer so the bytes will be contiguous.  
  4008 	 */
  4009 
  4010 	ChannelBuffer *nextPtr;
  4011 	int extra;
  4012 	
  4013 	nextPtr = bufPtr->nextPtr;
  4014 	if (bufPtr->nextAdded < bufPtr->bufLength) {
  4015 	    if (gsPtr->rawRead > 0) {
  4016 		/*
  4017 		 * Some raw bytes were converted to UTF-8.  Fall through,
  4018 		 * returning those UTF-8 characters because a EOL might be
  4019 		 * present in them.
  4020 		 */
  4021 	    } else if (statePtr->flags & CHANNEL_EOF) {
  4022 		/*
  4023 		 * There was a partial character followed by EOF on the
  4024 		 * device.  Fall through, returning that nothing was found.
  4025 		 */
  4026 
  4027 		bufPtr->nextRemoved = bufPtr->nextAdded;
  4028 	    } else {
  4029 		/*
  4030 		 * There are no more cached raw bytes left.  See if we can
  4031 		 * get some more.
  4032 		 */
  4033 
  4034 		goto read;
  4035 	    }
  4036 	} else {
  4037 	    if (nextPtr == NULL) {
  4038 		nextPtr = AllocChannelBuffer(statePtr->bufSize);
  4039 		bufPtr->nextPtr = nextPtr;
  4040 		statePtr->inQueueTail = nextPtr;
  4041 	    }
  4042 	    extra = rawLen - gsPtr->rawRead;
  4043 	    memcpy((VOID *) (nextPtr->buf + BUFFER_PADDING - extra),
  4044 		    (VOID *) (raw + gsPtr->rawRead), (size_t) extra);
  4045 	    nextPtr->nextRemoved -= extra;
  4046 	    bufPtr->nextAdded -= extra;
  4047 	}
  4048     }
  4049 
  4050     gsPtr->bufPtr = bufPtr;
  4051     return 0;
  4052 }
  4053 
  4054 /*
  4055  *---------------------------------------------------------------------------
  4056  *
  4057  * PeekAhead --
  4058  *
  4059  *	Helper function used by Tcl_GetsObj().  Called when we've seen a
  4060  *	\r at the end of the UTF-8 string and want to look ahead one
  4061  *	character to see if it is a \n.
  4062  *
  4063  * Results:
  4064  *	*gsPtr->dstPtr is filled with a pointer to the start of the range of
  4065  *	UTF-8 characters that were found by peeking and *dstEndPtr is filled
  4066  *	with a pointer to the bytes just after the end of the range.
  4067  *
  4068  * Side effects:
  4069  *	If no more raw bytes were available in one of the channel buffers,
  4070  *	tries to perform a non-blocking read to get more bytes from the
  4071  *	channel device.
  4072  *
  4073  *---------------------------------------------------------------------------
  4074  */
  4075 
  4076 static void
  4077 PeekAhead(chanPtr, dstEndPtr, gsPtr)
  4078     Channel *chanPtr;		/* The channel to read. */
  4079     char **dstEndPtr;		/* Filled with pointer to end of new range
  4080 				 * of UTF-8 characters. */
  4081     GetsState *gsPtr;		/* Current state of gets operation. */
  4082 {
  4083     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  4084     ChannelBuffer *bufPtr;
  4085     Tcl_DriverBlockModeProc *blockModeProc;
  4086     int bytesLeft;
  4087 
  4088     bufPtr = gsPtr->bufPtr;
  4089 
  4090     /*
  4091      * If there's any more raw input that's still buffered, we'll peek into
  4092      * that.  Otherwise, only get more data from the channel driver if it
  4093      * looks like there might actually be more data.  The assumption is that
  4094      * if the channel buffer is filled right up to the end, then there
  4095      * might be more data to read.
  4096      */
  4097 
  4098     blockModeProc = NULL;
  4099     if (bufPtr->nextPtr == NULL) {
  4100 	bytesLeft = bufPtr->nextAdded - (bufPtr->nextRemoved + gsPtr->rawRead);
  4101 	if (bytesLeft == 0) {
  4102 	    if (bufPtr->nextAdded < bufPtr->bufLength) {
  4103 		/*
  4104 		 * Don't peek ahead if last read was short read.
  4105 		 */
  4106 		 
  4107 		goto cleanup;
  4108 	    }
  4109 	    if ((statePtr->flags & CHANNEL_NONBLOCKING) == 0) {
  4110 		blockModeProc = Tcl_ChannelBlockModeProc(chanPtr->typePtr);
  4111 		if (blockModeProc == NULL) {
  4112 		    /*
  4113 		     * Don't peek ahead if cannot set non-blocking mode.
  4114 		     */
  4115 
  4116 		    goto cleanup;
  4117 		}
  4118 		StackSetBlockMode(chanPtr, TCL_MODE_NONBLOCKING);
  4119 	    }
  4120 	}
  4121     }
  4122     if (FilterInputBytes(chanPtr, gsPtr) == 0) {
  4123 	*dstEndPtr = *gsPtr->dstPtr + gsPtr->bytesWrote;
  4124     }
  4125     if (blockModeProc != NULL) {
  4126 	StackSetBlockMode(chanPtr, TCL_MODE_BLOCKING);
  4127     }
  4128     return;
  4129 
  4130     cleanup:
  4131     bufPtr->nextRemoved += gsPtr->rawRead;
  4132     gsPtr->rawRead = 0;
  4133     gsPtr->totalChars += gsPtr->charsWrote;
  4134     gsPtr->bytesWrote = 0;
  4135     gsPtr->charsWrote = 0;
  4136 }
  4137 
  4138 /*
  4139  *---------------------------------------------------------------------------
  4140  *
  4141  * CommonGetsCleanup --
  4142  *
  4143  *	Helper function for Tcl_GetsObj() to restore the channel after
  4144  *	a "gets" operation.
  4145  *
  4146  * Results:
  4147  *	None.
  4148  *
  4149  * Side effects:
  4150  *	Encoding may be freed.
  4151  *
  4152  *---------------------------------------------------------------------------
  4153  */
  4154  
  4155 static void
  4156 CommonGetsCleanup(chanPtr, encoding)
  4157     Channel *chanPtr;
  4158     Tcl_Encoding encoding;
  4159 {
  4160     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  4161     ChannelBuffer *bufPtr, *nextPtr;
  4162     
  4163     bufPtr = statePtr->inQueueHead;
  4164     for ( ; bufPtr != NULL; bufPtr = nextPtr) {
  4165 	nextPtr = bufPtr->nextPtr;
  4166 	if (bufPtr->nextRemoved < bufPtr->nextAdded) {
  4167 	    break;
  4168 	}
  4169 	RecycleBuffer(statePtr, bufPtr, 0);
  4170     }
  4171     statePtr->inQueueHead = bufPtr;
  4172     if (bufPtr == NULL) {
  4173 	statePtr->inQueueTail = NULL;
  4174     } else {
  4175 	/*
  4176 	 * If any multi-byte characters were split across channel buffer
  4177 	 * boundaries, the split-up bytes were moved to the next channel
  4178 	 * buffer by FilterInputBytes().  Move the bytes back to their
  4179 	 * original buffer because the caller could change the channel's
  4180 	 * encoding which could change the interpretation of whether those
  4181 	 * bytes really made up multi-byte characters after all.
  4182 	 */
  4183 	 
  4184 	nextPtr = bufPtr->nextPtr;
  4185 	for ( ; nextPtr != NULL; nextPtr = bufPtr->nextPtr) {
  4186 	    int extra;
  4187 
  4188 	    extra = bufPtr->bufLength - bufPtr->nextAdded;
  4189 	    if (extra > 0) {
  4190 		memcpy((VOID *) (bufPtr->buf + bufPtr->nextAdded),
  4191 			(VOID *) (nextPtr->buf + BUFFER_PADDING - extra),
  4192 			(size_t) extra);
  4193 		bufPtr->nextAdded += extra;
  4194 		nextPtr->nextRemoved = BUFFER_PADDING;
  4195 	    }
  4196 	    bufPtr = nextPtr;
  4197 	}
  4198     }
  4199     if (statePtr->encoding == NULL) {
  4200 	Tcl_FreeEncoding(encoding);
  4201     }
  4202 }
  4203 
  4204 /*
  4205  *----------------------------------------------------------------------
  4206  *
  4207  * Tcl_Read --
  4208  *
  4209  *	Reads a given number of bytes from a channel.  EOL and EOF
  4210  *	translation is done on the bytes being read, so the the number
  4211  *	of bytes consumed from the channel may not be equal to the
  4212  *	number of bytes stored in the destination buffer.
  4213  *
  4214  *	No encoding conversions are applied to the bytes being read.
  4215  *
  4216  * Results:
  4217  *	The number of bytes read, or -1 on error. Use Tcl_GetErrno()
  4218  *	to retrieve the error code for the error that occurred.
  4219  *
  4220  * Side effects:
  4221  *	May cause input to be buffered.
  4222  *
  4223  *----------------------------------------------------------------------
  4224  */
  4225 
  4226 EXPORT_C int
  4227 Tcl_Read(chan, dst, bytesToRead)
  4228     Tcl_Channel chan;		/* The channel from which to read. */
  4229     char *dst;			/* Where to store input read. */
  4230     int bytesToRead;		/* Maximum number of bytes to read. */
  4231 {
  4232     Channel *chanPtr = (Channel *) chan;		
  4233     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  4234 
  4235     /*
  4236      * This operation should occur at the top of a channel stack.
  4237      */
  4238 
  4239     chanPtr = statePtr->topChanPtr;
  4240 
  4241     if (CheckChannelErrors(statePtr, TCL_READABLE) != 0) {
  4242 	return -1;
  4243     }
  4244 
  4245     return DoRead(chanPtr, dst, bytesToRead);
  4246 }
  4247 
  4248 /*
  4249  *----------------------------------------------------------------------
  4250  *
  4251  * Tcl_ReadRaw --
  4252  *
  4253  *	Reads a given number of bytes from a channel.  EOL and EOF
  4254  *	translation is done on the bytes being read, so the the number
  4255  *	of bytes consumed from the channel may not be equal to the
  4256  *	number of bytes stored in the destination buffer.
  4257  *
  4258  *	No encoding conversions are applied to the bytes being read.
  4259  *
  4260  * Results:
  4261  *	The number of bytes read, or -1 on error. Use Tcl_GetErrno()
  4262  *	to retrieve the error code for the error that occurred.
  4263  *
  4264  * Side effects:
  4265  *	May cause input to be buffered.
  4266  *
  4267  *----------------------------------------------------------------------
  4268  */
  4269 
  4270 EXPORT_C int
  4271 Tcl_ReadRaw(chan, bufPtr, bytesToRead)
  4272     Tcl_Channel chan;		/* The channel from which to read. */
  4273     char *bufPtr;		/* Where to store input read. */
  4274     int bytesToRead;		/* Maximum number of bytes to read. */
  4275 {
  4276     Channel *chanPtr = (Channel *) chan;		
  4277     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  4278     int nread, result;
  4279     int copied, copiedNow;
  4280 
  4281     /*
  4282      * The check below does too much because it will reject a call to this
  4283      * function with a channel which is part of an 'fcopy'. But we have to
  4284      * allow this here or else the chaining in the transformation drivers
  4285      * will fail with 'file busy' error instead of retrieving and
  4286      * transforming the data to copy.
  4287      *
  4288      * We let the check procedure now believe that there is no fcopy in
  4289      * progress. A better solution than this might be an additional flag
  4290      * argument to switch off specific checks.
  4291      */
  4292 
  4293     if (CheckChannelErrors(statePtr, TCL_READABLE | CHANNEL_RAW_MODE) != 0) {
  4294 	return -1;
  4295     }
  4296 
  4297     /*
  4298      * Check for information in the push-back buffers. If there is
  4299      * some, use it. Go to the driver only if there is none (anymore)
  4300      * and the caller requests more bytes.
  4301      */
  4302 
  4303     for (copied = 0; copied < bytesToRead; copied += copiedNow) {
  4304         copiedNow = CopyBuffer(chanPtr, bufPtr + copied,
  4305                 bytesToRead - copied);
  4306         if (copiedNow == 0) {
  4307             if (statePtr->flags & CHANNEL_EOF) {
  4308 		goto done;
  4309             }
  4310             if (statePtr->flags & CHANNEL_BLOCKED) {
  4311                 if (statePtr->flags & CHANNEL_NONBLOCKING) {
  4312 		    goto done;
  4313                 }
  4314                 statePtr->flags &= (~(CHANNEL_BLOCKED));
  4315             }
  4316 
  4317 #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING
  4318 	    /* [SF Tcl Bug 943274]. Better emulation of non-blocking
  4319 	     * channels for channels without BlockModeProc, by keeping
  4320 	     * track of true fileevents generated by the OS == Data
  4321 	     * waiting and reading if and only if we are sure to have
  4322 	     * data.
  4323 	     */
  4324 
  4325 	    if ((statePtr->flags & CHANNEL_NONBLOCKING) &&
  4326 		(Tcl_ChannelBlockModeProc(chanPtr->typePtr) == NULL) &&
  4327 		!(statePtr->flags & CHANNEL_HAS_MORE_DATA)) {
  4328 
  4329 	        /* We bypass the driver, it would block, as no data is available */
  4330 	        nread  = -1;
  4331 	        result = EWOULDBLOCK;
  4332 	    } else {
  4333 #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */
  4334 	      /*
  4335 	       * Now go to the driver to get as much as is possible to
  4336 	       * fill the remaining request. Do all the error handling
  4337 	       * by ourselves.  The code was stolen from 'GetInput' and
  4338 	       * slightly adapted (different return value here).
  4339 	       *
  4340 	       * The case of 'bytesToRead == 0' at this point cannot happen.
  4341 	       */
  4342 
  4343 	      nread = (chanPtr->typePtr->inputProc)(chanPtr->instanceData,
  4344 			  bufPtr + copied, bytesToRead - copied, &result);
  4345 #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING
  4346 	    }
  4347 #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */
  4348 	    if (nread > 0) {
  4349 	        /*
  4350 		 * If we get a short read, signal up that we may be
  4351 		 * BLOCKED. We should avoid calling the driver because
  4352 		 * on some platforms we will block in the low level
  4353 		 * reading code even though the channel is set into
  4354 		 * nonblocking mode.
  4355 		 */
  4356             
  4357 	        if (nread < (bytesToRead - copied)) {
  4358 		    statePtr->flags |= CHANNEL_BLOCKED;
  4359 		}
  4360 
  4361 #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING
  4362 	        if (nread <= (bytesToRead - copied)) {
  4363 		    /* [SF Tcl Bug 943274] We have read the available
  4364 		     * data, clear flag */
  4365 		    statePtr->flags &= ~CHANNEL_HAS_MORE_DATA;
  4366 		}
  4367 #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */
  4368 	    } else if (nread == 0) {
  4369 	        statePtr->flags |= CHANNEL_EOF;
  4370 		statePtr->inputEncodingFlags |= TCL_ENCODING_END;
  4371 	    } else if (nread < 0) {
  4372 	        if ((result == EWOULDBLOCK) || (result == EAGAIN)) {
  4373 		    if (copied > 0) {
  4374 		      /*
  4375 		       * Information that was copied earlier has precedence
  4376 		       * over EAGAIN/WOULDBLOCK handling.
  4377 		       */
  4378 		      return copied;
  4379 		    }
  4380 
  4381 		    statePtr->flags |= CHANNEL_BLOCKED;
  4382 		    result = EAGAIN;
  4383 		}
  4384 
  4385 		Tcl_SetErrno(result);
  4386 		return -1;
  4387 	    } 
  4388 
  4389 	    return copied + nread;
  4390         }
  4391     }
  4392 
  4393 done:
  4394     return copied;
  4395 }
  4396 
  4397 /*
  4398  *---------------------------------------------------------------------------
  4399  *
  4400  * Tcl_ReadChars --
  4401  *
  4402  *	Reads from the channel until the requested number of characters
  4403  *	have been seen, EOF is seen, or the channel would block.  EOL
  4404  *	and EOF translation is done.  If reading binary data, the raw
  4405  *	bytes are wrapped in a Tcl byte array object.  Otherwise, the raw
  4406  *	bytes are converted to UTF-8 using the channel's current encoding
  4407  *	and stored in a Tcl string object.
  4408  *
  4409  * Results:
  4410  *	The number of characters read, or -1 on error. Use Tcl_GetErrno()
  4411  *	to retrieve the error code for the error that occurred.
  4412  *
  4413  * Side effects:
  4414  *	May cause input to be buffered.
  4415  *
  4416  *---------------------------------------------------------------------------
  4417  */
  4418  
  4419 EXPORT_C int
  4420 Tcl_ReadChars(chan, objPtr, toRead, appendFlag)
  4421     Tcl_Channel chan;		/* The channel to read. */
  4422     Tcl_Obj *objPtr;		/* Input data is stored in this object. */
  4423     int toRead;			/* Maximum number of characters to store,
  4424 				 * or -1 to read all available data (up to EOF
  4425 				 * or when channel blocks). */
  4426     int appendFlag;		/* If non-zero, data read from the channel
  4427 				 * will be appended to the object.  Otherwise,
  4428 				 * the data will replace the existing contents
  4429 				 * of the object. */
  4430 
  4431 {
  4432     Channel*      chanPtr  = (Channel *) chan;
  4433     ChannelState* statePtr = chanPtr->state;	/* state info for channel */
  4434     
  4435     /*
  4436      * This operation should occur at the top of a channel stack.
  4437      */
  4438 
  4439     chanPtr = statePtr->topChanPtr;
  4440 
  4441     if (CheckChannelErrors(statePtr, TCL_READABLE) != 0) {
  4442         /*
  4443 	 * Update the notifier state so we don't block while there is still
  4444 	 * data in the buffers.
  4445 	 */
  4446         UpdateInterest(chanPtr);
  4447 	return -1;
  4448     }
  4449 
  4450     return DoReadChars (chanPtr, objPtr, toRead, appendFlag);
  4451 }
  4452 /*
  4453  *---------------------------------------------------------------------------
  4454  *
  4455  * DoReadChars --
  4456  *
  4457  *	Reads from the channel until the requested number of characters
  4458  *	have been seen, EOF is seen, or the channel would block.  EOL
  4459  *	and EOF translation is done.  If reading binary data, the raw
  4460  *	bytes are wrapped in a Tcl byte array object.  Otherwise, the raw
  4461  *	bytes are converted to UTF-8 using the channel's current encoding
  4462  *	and stored in a Tcl string object.
  4463  *
  4464  * Results:
  4465  *	The number of characters read, or -1 on error. Use Tcl_GetErrno()
  4466  *	to retrieve the error code for the error that occurred.
  4467  *
  4468  * Side effects:
  4469  *	May cause input to be buffered.
  4470  *
  4471  *---------------------------------------------------------------------------
  4472  */
  4473  
  4474 static int
  4475 DoReadChars(chanPtr, objPtr, toRead, appendFlag)
  4476     Channel* chanPtr;		/* The channel to read. */
  4477     Tcl_Obj *objPtr;		/* Input data is stored in this object. */
  4478     int toRead;			/* Maximum number of characters to store,
  4479 				 * or -1 to read all available data (up to EOF
  4480 				 * or when channel blocks). */
  4481     int appendFlag;		/* If non-zero, data read from the channel
  4482 				 * will be appended to the object.  Otherwise,
  4483 				 * the data will replace the existing contents
  4484 				 * of the object. */
  4485 
  4486 {
  4487     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  4488     ChannelBuffer *bufPtr;
  4489     int offset, factor, copied, copiedNow, result;
  4490     Tcl_Encoding encoding;
  4491 #define UTF_EXPANSION_FACTOR	1024
  4492 
  4493     /*
  4494      * This operation should occur at the top of a channel stack.
  4495      */
  4496 
  4497     chanPtr  = statePtr->topChanPtr;
  4498     encoding = statePtr->encoding;
  4499     factor   = UTF_EXPANSION_FACTOR;
  4500 
  4501     if (appendFlag == 0) {
  4502 	if (encoding == NULL) {
  4503 	    Tcl_SetByteArrayLength(objPtr, 0);
  4504 	} else {
  4505 	    Tcl_SetObjLength(objPtr, 0);
  4506 	    /* 
  4507 	     * We're going to access objPtr->bytes directly, so
  4508 	     * we must ensure that this is actually a string
  4509 	     * object (otherwise it might have been pure Unicode).
  4510 	     */
  4511 	    Tcl_GetString(objPtr);
  4512 	}
  4513 	offset = 0;
  4514     } else {
  4515 	if (encoding == NULL) {
  4516 	    Tcl_GetByteArrayFromObj(objPtr, &offset);
  4517 	} else {
  4518 	    Tcl_GetStringFromObj(objPtr, &offset);
  4519 	}
  4520     }
  4521 
  4522     for (copied = 0; (unsigned) toRead > 0; ) {
  4523 	copiedNow = -1;
  4524 	if (statePtr->inQueueHead != NULL) {
  4525 	    if (encoding == NULL) {
  4526 		copiedNow = ReadBytes(statePtr, objPtr, toRead, &offset);
  4527 	    } else {
  4528 		copiedNow = ReadChars(statePtr, objPtr, toRead, &offset,
  4529 			&factor);
  4530 	    }
  4531 
  4532 	    /*
  4533 	     * If the current buffer is empty recycle it.
  4534 	     */
  4535 
  4536 	    bufPtr = statePtr->inQueueHead;
  4537 	    if (bufPtr->nextRemoved == bufPtr->nextAdded) {
  4538 		ChannelBuffer *nextPtr;
  4539 
  4540 		nextPtr = bufPtr->nextPtr;
  4541 		RecycleBuffer(statePtr, bufPtr, 0);
  4542 		statePtr->inQueueHead = nextPtr;
  4543 		if (nextPtr == NULL) {
  4544 		    statePtr->inQueueTail = NULL;
  4545 		}
  4546 	    }
  4547 	}
  4548 	if (copiedNow < 0) {
  4549 	    if (statePtr->flags & CHANNEL_EOF) {
  4550 		break;
  4551 	    }
  4552 	    if (statePtr->flags & CHANNEL_BLOCKED) {
  4553 		if (statePtr->flags & CHANNEL_NONBLOCKING) {
  4554 		    break;
  4555 		}
  4556 		statePtr->flags &= ~CHANNEL_BLOCKED;
  4557 	    }
  4558 	    result = GetInput(chanPtr);
  4559 	    if (result != 0) {
  4560 		if (result == EAGAIN) {
  4561 		    break;
  4562 		}
  4563 		copied = -1;
  4564 		goto done;
  4565 	    }
  4566 	} else {
  4567 	    copied += copiedNow;
  4568 	    toRead -= copiedNow;
  4569 	}
  4570     }
  4571     statePtr->flags &= ~CHANNEL_BLOCKED;
  4572     if (encoding == NULL) {
  4573 	Tcl_SetByteArrayLength(objPtr, offset);
  4574     } else {
  4575 	Tcl_SetObjLength(objPtr, offset);
  4576     }
  4577 
  4578     done:
  4579     /*
  4580      * Update the notifier state so we don't block while there is still
  4581      * data in the buffers.
  4582      */
  4583 
  4584     UpdateInterest(chanPtr);
  4585     return copied;
  4586 }
  4587 /*
  4588  *---------------------------------------------------------------------------
  4589  *
  4590  * ReadBytes --
  4591  *
  4592  *	Reads from the channel until the requested number of bytes have
  4593  *	been seen, EOF is seen, or the channel would block.  Bytes from
  4594  *	the channel are stored in objPtr as a ByteArray object.  EOL
  4595  *	and EOF translation are done.
  4596  *
  4597  *	'bytesToRead' can safely be a very large number because
  4598  *	space is only allocated to hold data read from the channel
  4599  *	as needed.
  4600  *
  4601  * Results:
  4602  *	The return value is the number of bytes appended to the object
  4603  *	and *offsetPtr is filled with the total number of bytes in the
  4604  *	object (greater than the return value if there were already bytes
  4605  *	in the object).
  4606  *
  4607  * Side effects:
  4608  *	None.
  4609  *
  4610  *---------------------------------------------------------------------------
  4611  */
  4612 
  4613 static int
  4614 ReadBytes(statePtr, objPtr, bytesToRead, offsetPtr)
  4615     ChannelState *statePtr;	/* State of the channel to read. */
  4616     Tcl_Obj *objPtr;		/* Input data is appended to this ByteArray
  4617 				 * object.  Its length is how much space
  4618 				 * has been allocated to hold data, not how
  4619 				 * many bytes of data have been stored in the
  4620 				 * object. */
  4621     int bytesToRead;		/* Maximum number of bytes to store,
  4622 				 * or < 0 to get all available bytes.
  4623 				 * Bytes are obtained from the first
  4624 				 * buffer in the queue -- even if this number
  4625 				 * is larger than the number of bytes
  4626 				 * available in the first buffer, only the
  4627 				 * bytes from the first buffer are
  4628 				 * returned. */
  4629     int *offsetPtr;		/* On input, contains how many bytes of
  4630 				 * objPtr have been used to hold data.  On
  4631 				 * output, filled with how many bytes are now
  4632 				 * being used. */
  4633 {
  4634     int toRead, srcLen, offset, length, srcRead, dstWrote;
  4635     ChannelBuffer *bufPtr;
  4636     char *src, *dst;
  4637 
  4638     offset = *offsetPtr;
  4639 
  4640     bufPtr = statePtr->inQueueHead; 
  4641     src = bufPtr->buf + bufPtr->nextRemoved;
  4642     srcLen = bufPtr->nextAdded - bufPtr->nextRemoved;
  4643 
  4644     toRead = bytesToRead;
  4645     if ((unsigned) toRead > (unsigned) srcLen) {
  4646 	toRead = srcLen;
  4647     }
  4648 
  4649     dst = (char *) Tcl_GetByteArrayFromObj(objPtr, &length);
  4650     if (toRead > length - offset - 1) {
  4651 	/*
  4652 	 * Double the existing size of the object or make enough room to
  4653 	 * hold all the characters we may get from the source buffer,
  4654 	 * whichever is larger.
  4655 	 */
  4656 
  4657 	length = offset * 2;
  4658 	if (offset < toRead) {
  4659 	    length = offset + toRead + 1;
  4660 	}
  4661 	dst = (char *) Tcl_SetByteArrayLength(objPtr, length);
  4662     }
  4663     dst += offset;
  4664 
  4665     if (statePtr->flags & INPUT_NEED_NL) {
  4666 	statePtr->flags &= ~INPUT_NEED_NL;
  4667 	if ((srcLen == 0) || (*src != '\n')) {
  4668 	    *dst = '\r';
  4669 	    *offsetPtr += 1;
  4670 	    return 1;
  4671 	}
  4672 	*dst++ = '\n';
  4673 	src++;
  4674 	srcLen--;
  4675 	toRead--;
  4676     }
  4677 
  4678     srcRead = srcLen;
  4679     dstWrote = toRead;
  4680     if (TranslateInputEOL(statePtr, dst, src, &dstWrote, &srcRead) != 0) {
  4681 	if (dstWrote == 0) {
  4682 	    return -1;
  4683 	}
  4684     }
  4685     bufPtr->nextRemoved += srcRead;
  4686     *offsetPtr += dstWrote;
  4687     return dstWrote;
  4688 }
  4689 
  4690 /*
  4691  *---------------------------------------------------------------------------
  4692  *
  4693  * ReadChars --
  4694  *
  4695  *	Reads from the channel until the requested number of UTF-8
  4696  *	characters have been seen, EOF is seen, or the channel would
  4697  *	block.  Raw bytes from the channel are converted to UTF-8
  4698  *	and stored in objPtr.  EOL and EOF translation is done.
  4699  *
  4700  *	'charsToRead' can safely be a very large number because
  4701  *	space is only allocated to hold data read from the channel
  4702  *	as needed.
  4703  *
  4704  * Results:
  4705  *	The return value is the number of characters appended to
  4706  *	the object, *offsetPtr is filled with the number of bytes that
  4707  *	were appended, and *factorPtr is filled with the expansion
  4708  *	factor used to guess how many bytes of UTF-8 to allocate to
  4709  *	hold N source bytes.
  4710  *
  4711  * Side effects:
  4712  *	None.
  4713  *
  4714  *---------------------------------------------------------------------------
  4715  */
  4716 
  4717 static int
  4718 ReadChars(statePtr, objPtr, charsToRead, offsetPtr, factorPtr)
  4719     ChannelState *statePtr;	/* State of channel to read. */
  4720     Tcl_Obj *objPtr;		/* Input data is appended to this object.
  4721 				 * objPtr->length is how much space has been
  4722 				 * allocated to hold data, not how many bytes
  4723 				 * of data have been stored in the object. */
  4724     int charsToRead;		/* Maximum number of characters to store,
  4725 				 * or -1 to get all available characters.
  4726 				 * Characters are obtained from the first
  4727 				 * buffer in the queue -- even if this number
  4728 				 * is larger than the number of characters
  4729 				 * available in the first buffer, only the
  4730 				 * characters from the first buffer are
  4731 				 * returned. */
  4732     int *offsetPtr;		/* On input, contains how many bytes of
  4733 				 * objPtr have been used to hold data.  On
  4734 				 * output, filled with how many bytes are now
  4735 				 * being used. */
  4736     int *factorPtr;		/* On input, contains a guess of how many
  4737 				 * bytes need to be allocated to hold the
  4738 				 * result of converting N source bytes to
  4739 				 * UTF-8.  On output, contains another guess
  4740 				 * based on the data seen so far. */
  4741 {
  4742     int toRead, factor, offset, spaceLeft, length, srcLen, dstNeeded;
  4743     int srcRead, dstWrote, numChars, dstRead;
  4744     ChannelBuffer *bufPtr;
  4745     char *src, *dst;
  4746     Tcl_EncodingState oldState;
  4747     int encEndFlagSuppressed = 0;
  4748 
  4749     factor = *factorPtr;
  4750     offset = *offsetPtr;
  4751 
  4752     bufPtr = statePtr->inQueueHead; 
  4753     src    = bufPtr->buf + bufPtr->nextRemoved;
  4754     srcLen = bufPtr->nextAdded - bufPtr->nextRemoved;
  4755 
  4756     toRead = charsToRead;
  4757     if ((unsigned)toRead > (unsigned)srcLen) {
  4758 	toRead = srcLen;
  4759     }
  4760 
  4761     /*
  4762      * 'factor' is how much we guess that the bytes in the source buffer
  4763      * will expand when converted to UTF-8 chars.  This guess comes from
  4764      * analyzing how many characters were produced by the previous
  4765      * pass.
  4766      */
  4767 
  4768     dstNeeded = toRead * factor / UTF_EXPANSION_FACTOR;
  4769     spaceLeft = objPtr->length - offset - TCL_UTF_MAX - 1;
  4770 
  4771     if (dstNeeded > spaceLeft) {
  4772 	/*
  4773 	 * Double the existing size of the object or make enough room to
  4774 	 * hold all the characters we want from the source buffer,
  4775 	 * whichever is larger.
  4776 	 */
  4777 
  4778 	length = offset * 2;
  4779 	if (offset < dstNeeded) {
  4780 	    length = offset + dstNeeded;
  4781 	}
  4782 	spaceLeft = length - offset;
  4783 	length += TCL_UTF_MAX + 1;
  4784 	Tcl_SetObjLength(objPtr, length);
  4785     }
  4786     if (toRead == srcLen) {
  4787 	/*
  4788 	 * Want to convert the whole buffer in one pass.  If we have
  4789 	 * enough space, convert it using all available space in object
  4790 	 * rather than using the factor.
  4791 	 */
  4792 
  4793 	dstNeeded = spaceLeft;
  4794     }
  4795     dst = objPtr->bytes + offset;
  4796 
  4797     /*
  4798      * SF Tcl Bug 1462248
  4799      * The cause of the crash reported in the referenced bug is this:
  4800      *
  4801      * - ReadChars, called with a single buffer, with a incomplete
  4802      *   multi-byte character at the end (only the first byte of it).
  4803      * - Encoding translation fails, asks for more data
  4804      * - Data is read, and eof is reached, TCL_ENCODING_END (TEE) is set.
  4805      * - ReadChar is called again, converts the first buffer, but due
  4806      *   to TEE it does not check for incomplete multi-byte data, and the
  4807      *   character just after the end of the first buffer is a valid
  4808      *   completion of the multi-byte header in the actual buffer. The
  4809      *   conversion reads more characters from the buffer then present.
  4810      *   This causes nextRemoved to overshoot nextAdded and the next
  4811      *   reads compute a negative srcLen, cause further translations to
  4812      *   fail, causing copying of data into the next buffer using bad
  4813      *   arguments, causing the mecpy for to eventually fail.
  4814      *
  4815      * In the end it is a memory access bug spiraling out of control
  4816      * if the conditions are _just so_. And ultimate cause is that TEE
  4817      * is given to a conversion where it should not. TEE signals that
  4818      * this is the last buffer. Except in our case it is not.
  4819      *
  4820      * My solution is to suppress TEE if the first buffer is not the
  4821      * last. We will eventually need it given that EOF has been
  4822      * reached, but not right now. This is what the new flag
  4823      * "endEncSuppressFlag" is for.
  4824      *
  4825      * The bug in 'Tcl_Utf2UtfProc' where it read from memory behind
  4826      * the actual buffer has been fixed as well, and fixes the problem
  4827      * with the crash too, but this would still allow the generic
  4828      * layer to accidentially break a multi-byte sequence if the
  4829      * conditions are just right, because again the ExternalToUtf
  4830      * would be successful where it should not.
  4831      */
  4832 
  4833     if ((statePtr->inputEncodingFlags & TCL_ENCODING_END) &&
  4834 	(bufPtr->nextPtr != NULL)) {
  4835 
  4836         /* TEE is set for a buffer which is not the last. Squash it
  4837 	 * for now, and restore it later, before yielding control to
  4838 	 * our caller.
  4839 	 */
  4840 
  4841         statePtr->inputEncodingFlags &= ~TCL_ENCODING_END;
  4842         encEndFlagSuppressed = 1;
  4843     }
  4844 
  4845     oldState = statePtr->inputEncodingState;
  4846     if (statePtr->flags & INPUT_NEED_NL) {
  4847 	/*
  4848 	 * We want a '\n' because the last character we saw was '\r'.
  4849 	 */
  4850 
  4851 	statePtr->flags &= ~INPUT_NEED_NL;
  4852 	Tcl_ExternalToUtf(NULL, statePtr->encoding, src, srcLen,
  4853 		statePtr->inputEncodingFlags, &statePtr->inputEncodingState,
  4854 		dst, TCL_UTF_MAX + 1, &srcRead, &dstWrote, &numChars);
  4855 	if ((dstWrote > 0) && (*dst == '\n')) {
  4856 	    /*
  4857 	     * The next char was a '\n'.  Consume it and produce a '\n'.
  4858 	     */
  4859 
  4860 	    bufPtr->nextRemoved += srcRead;
  4861 	} else {
  4862 	    /*
  4863 	     * The next char was not a '\n'.  Produce a '\r'.
  4864 	     */
  4865 
  4866 	    *dst = '\r';
  4867 	}
  4868 	statePtr->inputEncodingFlags &= ~TCL_ENCODING_START;
  4869 	*offsetPtr += 1;
  4870 
  4871 	if (encEndFlagSuppressed) {
  4872 	    statePtr->inputEncodingFlags |= TCL_ENCODING_END;
  4873 	}
  4874         return 1;
  4875     }
  4876 
  4877     Tcl_ExternalToUtf(NULL, statePtr->encoding, src, srcLen,
  4878 	    statePtr->inputEncodingFlags, &statePtr->inputEncodingState, dst,
  4879 	    dstNeeded + TCL_UTF_MAX, &srcRead, &dstWrote, &numChars);
  4880 
  4881     if (encEndFlagSuppressed) {
  4882         statePtr->inputEncodingFlags |= TCL_ENCODING_END;
  4883     }
  4884 
  4885     if (srcRead == 0) {
  4886 	/*
  4887 	 * Not enough bytes in src buffer to make a complete char.  Copy
  4888 	 * the bytes to the next buffer to make a new contiguous string,
  4889 	 * then tell the caller to fill the buffer with more bytes.
  4890 	 */
  4891 
  4892 	ChannelBuffer *nextPtr;
  4893 	
  4894 	nextPtr = bufPtr->nextPtr;
  4895 	if (nextPtr == NULL) {
  4896 	    if (srcLen > 0) {
  4897 	        /*
  4898 		 * There isn't enough data in the buffers to complete the next
  4899 		 * character, so we need to wait for more data before the next
  4900 		 * file event can be delivered.
  4901 		 *
  4902 		 * SF #478856.
  4903 		 *
  4904 		 * The exception to this is if the input buffer was
  4905 		 * completely empty before we tried to convert its
  4906 		 * contents. Nothing in, nothing out, and no incomplete
  4907 		 * character data. The conversion before the current one
  4908 		 * was complete.
  4909 		 */
  4910 
  4911 	        statePtr->flags |= CHANNEL_NEED_MORE_DATA;
  4912 	    }
  4913 	    return -1;
  4914 	}
  4915 
  4916 	/* Space is made at the beginning of the buffer to copy the
  4917 	 * previous unused bytes there. Check first if the buffer we
  4918 	 * are using actually has enough space at its beginning for
  4919 	 * the data we are copying. Because if not we will write over the
  4920 	 * buffer management information, especially the 'nextPtr'.
  4921 	 *
  4922 	 * Note that the BUFFER_PADDING (See AllocChannelBuffer) is
  4923 	 * used to prevent exactly this situation. I.e. it should
  4924 	 * never happen. Therefore it is ok to panic should it happen
  4925 	 * despite the precautions.
  4926 	 */
  4927 
  4928 	if (nextPtr->nextRemoved - srcLen < 0) {
  4929 	    Tcl_Panic ("Buffer Underflow, BUFFER_PADDING not enough");
  4930 	}
  4931 
  4932 	nextPtr->nextRemoved -= srcLen;
  4933 	memcpy((VOID *) (nextPtr->buf + nextPtr->nextRemoved), (VOID *) src,
  4934 		(size_t) srcLen);
  4935 	RecycleBuffer(statePtr, bufPtr, 0);
  4936 	statePtr->inQueueHead = nextPtr;
  4937 	return ReadChars(statePtr, objPtr, charsToRead, offsetPtr, factorPtr);
  4938     }
  4939 
  4940     dstRead = dstWrote;
  4941     if (TranslateInputEOL(statePtr, dst, dst, &dstWrote, &dstRead) != 0) {
  4942 	/*
  4943 	 * Hit EOF char.  How many bytes of src correspond to where the
  4944 	 * EOF was located in dst? Run the conversion again with an
  4945 	 * output buffer just big enough to hold the data so we can
  4946 	 * get the correct value for srcRead.
  4947 	 */
  4948 	 
  4949 	if (dstWrote == 0) {
  4950 	    return -1;
  4951 	}
  4952 	statePtr->inputEncodingState = oldState;
  4953 	Tcl_ExternalToUtf(NULL, statePtr->encoding, src, srcLen,
  4954 		statePtr->inputEncodingFlags, &statePtr->inputEncodingState,
  4955 		dst, dstRead + TCL_UTF_MAX, &srcRead, &dstWrote, &numChars);
  4956 	TranslateInputEOL(statePtr, dst, dst, &dstWrote, &dstRead);
  4957     } 
  4958 
  4959     /*
  4960      * The number of characters that we got may be less than the number
  4961      * that we started with because "\r\n" sequences may have been
  4962      * turned into just '\n' in dst.
  4963      */
  4964 
  4965     numChars -= (dstRead - dstWrote);
  4966 
  4967     if ((unsigned) numChars > (unsigned) toRead) {
  4968 	/*
  4969 	 * Got too many chars.
  4970 	 */
  4971 
  4972 	CONST char *eof;
  4973 
  4974 	eof = Tcl_UtfAtIndex(dst, toRead);
  4975 	statePtr->inputEncodingState = oldState;
  4976 	Tcl_ExternalToUtf(NULL, statePtr->encoding, src, srcLen,
  4977 		statePtr->inputEncodingFlags, &statePtr->inputEncodingState,
  4978 		dst, eof - dst + TCL_UTF_MAX, &srcRead, &dstWrote, &numChars);
  4979 	dstRead = dstWrote;
  4980 	TranslateInputEOL(statePtr, dst, dst, &dstWrote, &dstRead);
  4981 	numChars -= (dstRead - dstWrote);
  4982     }
  4983     statePtr->inputEncodingFlags &= ~TCL_ENCODING_START;
  4984 
  4985     bufPtr->nextRemoved += srcRead;
  4986     if (dstWrote > srcRead + 1) {
  4987 	*factorPtr = dstWrote * UTF_EXPANSION_FACTOR / srcRead;
  4988     }
  4989     *offsetPtr += dstWrote;
  4990     return numChars;
  4991 }
  4992 
  4993 /*
  4994  *---------------------------------------------------------------------------
  4995  *
  4996  * TranslateInputEOL --
  4997  *
  4998  *	Perform input EOL and EOF translation on the source buffer,
  4999  *	leaving the translated result in the destination buffer.  
  5000  *
  5001  * Results:
  5002  *	The return value is 1 if the EOF character was found when copying
  5003  *	bytes to the destination buffer, 0 otherwise.  
  5004  *
  5005  * Side effects:
  5006  *	None.
  5007  *
  5008  *---------------------------------------------------------------------------
  5009  */
  5010 
  5011 static int
  5012 TranslateInputEOL(statePtr, dstStart, srcStart, dstLenPtr, srcLenPtr)
  5013     ChannelState *statePtr;	/* Channel being read, for EOL translation
  5014 				 * and EOF character. */
  5015     char *dstStart;		/* Output buffer filled with chars by
  5016 				 * applying appropriate EOL translation to
  5017 				 * source characters. */
  5018     CONST char *srcStart;	/* Source characters. */
  5019     int *dstLenPtr;		/* On entry, the maximum length of output
  5020 				 * buffer in bytes; must be <= *srcLenPtr.  On
  5021 				 * exit, the number of bytes actually used in
  5022 				 * output buffer. */
  5023     int *srcLenPtr;		/* On entry, the length of source buffer.
  5024 				 * On exit, the number of bytes read from
  5025 				 * the source buffer. */
  5026 {
  5027     int dstLen, srcLen, inEofChar;
  5028     CONST char *eof;
  5029 
  5030     dstLen = *dstLenPtr;
  5031 
  5032     eof = NULL;
  5033     inEofChar = statePtr->inEofChar;
  5034     if (inEofChar != '\0') {
  5035 	/*
  5036 	 * Find EOF in translated buffer then compress out the EOL.  The
  5037 	 * source buffer may be much longer than the destination buffer --
  5038 	 * we only want to return EOF if the EOF has been copied to the
  5039 	 * destination buffer.
  5040 	 */
  5041 
  5042 	CONST char *src, *srcMax;
  5043 
  5044 	srcMax = srcStart + *srcLenPtr;
  5045 	for (src = srcStart; src < srcMax; src++) {
  5046 	    if (*src == inEofChar) {
  5047 		eof = src;
  5048 		srcLen = src - srcStart;
  5049 		if (srcLen < dstLen) {
  5050 		    dstLen = srcLen;
  5051 		}
  5052 		*srcLenPtr = srcLen;
  5053 		break;
  5054 	    }
  5055 	}
  5056     }
  5057     switch (statePtr->inputTranslation) {
  5058 	case TCL_TRANSLATE_LF: {
  5059 	    if (dstStart != srcStart) {
  5060 		memcpy((VOID *) dstStart, (VOID *) srcStart, (size_t) dstLen);
  5061 	    }
  5062 	    srcLen = dstLen;
  5063 	    break;
  5064 	}
  5065 	case TCL_TRANSLATE_CR: {
  5066 	    char *dst, *dstEnd;
  5067 	    
  5068 	    if (dstStart != srcStart) {
  5069 		memcpy((VOID *) dstStart, (VOID *) srcStart, (size_t) dstLen);
  5070 	    }
  5071 	    dstEnd = dstStart + dstLen;
  5072 	    for (dst = dstStart; dst < dstEnd; dst++) {
  5073 		if (*dst == '\r') {
  5074 		    *dst = '\n';
  5075 		}
  5076 	    }
  5077 	    srcLen = dstLen;
  5078 	    break;
  5079 	}
  5080 	case TCL_TRANSLATE_CRLF: {
  5081 	    char *dst;
  5082 	    CONST char *src, *srcEnd, *srcMax;
  5083 	    
  5084 	    dst = dstStart;
  5085 	    src = srcStart;
  5086 	    srcEnd = srcStart + dstLen;
  5087 	    srcMax = srcStart + *srcLenPtr;
  5088 
  5089 	    for ( ; src < srcEnd; ) {
  5090 		if (*src == '\r') {
  5091 		    src++;
  5092 		    if (src >= srcMax) {
  5093 			statePtr->flags |= INPUT_NEED_NL;
  5094 		    } else if (*src == '\n') {
  5095 			*dst++ = *src++;
  5096 		    } else {
  5097 			*dst++ = '\r';
  5098 		    }
  5099 		} else {
  5100 		    *dst++ = *src++;
  5101 		}
  5102 	    }
  5103 	    srcLen = src - srcStart;
  5104 	    dstLen = dst - dstStart;
  5105 	    break;
  5106 	}
  5107 	case TCL_TRANSLATE_AUTO: {
  5108 	    char *dst;
  5109 	    CONST char *src, *srcEnd, *srcMax;
  5110 
  5111 	    dst = dstStart;
  5112 	    src = srcStart;
  5113 	    srcEnd = srcStart + dstLen;
  5114 	    srcMax = srcStart + *srcLenPtr;
  5115 
  5116 	    if ((statePtr->flags & INPUT_SAW_CR) && (src < srcMax)) {
  5117 		if (*src == '\n') {
  5118 		    src++;
  5119 		}
  5120 		statePtr->flags &= ~INPUT_SAW_CR;
  5121 	    }
  5122 	    for ( ; src < srcEnd; ) {
  5123 		if (*src == '\r') {
  5124 		    src++;
  5125 		    if (src >= srcMax) {
  5126 			statePtr->flags |= INPUT_SAW_CR;
  5127 		    } else if (*src == '\n') {
  5128 			if (srcEnd < srcMax) {
  5129 			    srcEnd++;
  5130 			}
  5131 			src++;
  5132 		    }
  5133 		    *dst++ = '\n';
  5134 		} else {
  5135 		    *dst++ = *src++;
  5136 		}
  5137 	    }
  5138 	    srcLen = src - srcStart;
  5139 	    dstLen = dst - dstStart;
  5140 	    break;
  5141 	}
  5142 	default: {		/* lint. */
  5143 	    return 0;
  5144 	}
  5145     }
  5146     *dstLenPtr = dstLen;
  5147 
  5148     if ((eof != NULL) && (srcStart + srcLen >= eof)) {
  5149 	/*
  5150 	 * EOF character was seen in EOL translated range.  Leave current
  5151 	 * file position pointing at the EOF character, but don't store the
  5152 	 * EOF character in the output string.
  5153 	 */
  5154 
  5155 	statePtr->flags |= (CHANNEL_EOF | CHANNEL_STICKY_EOF);
  5156 	statePtr->inputEncodingFlags |= TCL_ENCODING_END;
  5157 	statePtr->flags &= ~(INPUT_SAW_CR | INPUT_NEED_NL);
  5158 	return 1;
  5159     }
  5160 
  5161     *srcLenPtr = srcLen;
  5162     return 0;
  5163 }
  5164 
  5165 /*
  5166  *----------------------------------------------------------------------
  5167  *
  5168  * Tcl_Ungets --
  5169  *
  5170  *	Causes the supplied string to be added to the input queue of
  5171  *	the channel, at either the head or tail of the queue.
  5172  *
  5173  * Results:
  5174  *	The number of bytes stored in the channel, or -1 on error.
  5175  *
  5176  * Side effects:
  5177  *	Adds input to the input queue of a channel.
  5178  *
  5179  *----------------------------------------------------------------------
  5180  */
  5181 
  5182 EXPORT_C int
  5183 Tcl_Ungets(chan, str, len, atEnd)
  5184     Tcl_Channel chan;		/* The channel for which to add the input. */
  5185     CONST char *str;		/* The input itself. */
  5186     int len;			/* The length of the input. */
  5187     int atEnd;			/* If non-zero, add at end of queue; otherwise
  5188                                  * add at head of queue. */    
  5189 {
  5190     Channel *chanPtr;		/* The real IO channel. */
  5191     ChannelState *statePtr;	/* State of actual channel. */
  5192     ChannelBuffer *bufPtr;	/* Buffer to contain the data. */
  5193     int i, flags;
  5194 
  5195     chanPtr = (Channel *) chan;
  5196     statePtr = chanPtr->state;
  5197 
  5198     /*
  5199      * This operation should occur at the top of a channel stack.
  5200      */
  5201 
  5202     chanPtr = statePtr->topChanPtr;
  5203 
  5204     /*
  5205      * CheckChannelErrors clears too many flag bits in this one case.
  5206      */
  5207      
  5208     flags = statePtr->flags;
  5209     if (CheckChannelErrors(statePtr, TCL_READABLE) != 0) {
  5210 	len = -1;
  5211 	goto done;
  5212     }
  5213     statePtr->flags = flags;
  5214 
  5215     /*
  5216      * If we have encountered a sticky EOF, just punt without storing.
  5217      * (sticky EOF is set if we have seen the input eofChar, to prevent
  5218      * reading beyond the eofChar). Otherwise, clear the EOF flags, and
  5219      * clear the BLOCKED bit. We want to discover these conditions anew
  5220      * in each operation.
  5221      */
  5222 
  5223     if (statePtr->flags & CHANNEL_STICKY_EOF) {
  5224 	goto done;
  5225     }
  5226     statePtr->flags &= (~(CHANNEL_BLOCKED | CHANNEL_EOF));
  5227 
  5228     bufPtr = AllocChannelBuffer(len);
  5229     for (i = 0; i < len; i++) {
  5230         bufPtr->buf[bufPtr->nextAdded++] = str[i];
  5231     }
  5232 
  5233     if (statePtr->inQueueHead == (ChannelBuffer *) NULL) {
  5234         bufPtr->nextPtr = (ChannelBuffer *) NULL;
  5235         statePtr->inQueueHead = bufPtr;
  5236         statePtr->inQueueTail = bufPtr;
  5237     } else if (atEnd) {
  5238         bufPtr->nextPtr = (ChannelBuffer *) NULL;
  5239         statePtr->inQueueTail->nextPtr = bufPtr;
  5240         statePtr->inQueueTail = bufPtr;
  5241     } else {
  5242         bufPtr->nextPtr = statePtr->inQueueHead;
  5243         statePtr->inQueueHead = bufPtr;
  5244     }
  5245 
  5246     done:
  5247     /*
  5248      * Update the notifier state so we don't block while there is still
  5249      * data in the buffers.
  5250      */
  5251 
  5252     UpdateInterest(chanPtr);
  5253     return len;
  5254 }
  5255 
  5256 /*
  5257  *----------------------------------------------------------------------
  5258  *
  5259  * Tcl_Flush --
  5260  *
  5261  *	Flushes output data on a channel.
  5262  *
  5263  * Results:
  5264  *	A standard Tcl result.
  5265  *
  5266  * Side effects:
  5267  *	May flush output queued on this channel.
  5268  *
  5269  *----------------------------------------------------------------------
  5270  */
  5271 
  5272 EXPORT_C int
  5273 Tcl_Flush(chan)
  5274     Tcl_Channel chan;			/* The Channel to flush. */
  5275 {
  5276     int result;				/* Of calling FlushChannel. */
  5277     Channel *chanPtr  = (Channel *) chan;	/* The actual channel. */
  5278     ChannelState *statePtr = chanPtr->state;	/* State of actual channel. */
  5279 
  5280     /*
  5281      * This operation should occur at the top of a channel stack.
  5282      */
  5283 
  5284     chanPtr = statePtr->topChanPtr;
  5285 
  5286     if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) {
  5287 	return -1;
  5288     }
  5289 
  5290     /*
  5291      * Force current output buffer to be output also.
  5292      */
  5293 
  5294     if ((statePtr->curOutPtr != NULL)
  5295 	    && (statePtr->curOutPtr->nextAdded > 0)) {
  5296         statePtr->flags |= BUFFER_READY;
  5297     }
  5298     
  5299     result = FlushChannel(NULL, chanPtr, 0);
  5300     if (result != 0) {
  5301         return TCL_ERROR;
  5302     }
  5303 
  5304     return TCL_OK;
  5305 }
  5306 
  5307 /*
  5308  *----------------------------------------------------------------------
  5309  *
  5310  * DiscardInputQueued --
  5311  *
  5312  *	Discards any input read from the channel but not yet consumed
  5313  *	by Tcl reading commands.
  5314  *
  5315  * Results:
  5316  *	None.
  5317  *
  5318  * Side effects:
  5319  *	May discard input from the channel. If discardLastBuffer is zero,
  5320  *	leaves one buffer in place for back-filling.
  5321  *
  5322  *----------------------------------------------------------------------
  5323  */
  5324 
  5325 static void
  5326 DiscardInputQueued(statePtr, discardSavedBuffers)
  5327     ChannelState *statePtr;	/* Channel on which to discard
  5328                                  * the queued input. */
  5329     int discardSavedBuffers;	/* If non-zero, discard all buffers including
  5330                                  * last one. */
  5331 {
  5332     ChannelBuffer *bufPtr, *nxtPtr;	/* Loop variables. */
  5333 
  5334     bufPtr = statePtr->inQueueHead;
  5335     statePtr->inQueueHead = (ChannelBuffer *) NULL;
  5336     statePtr->inQueueTail = (ChannelBuffer *) NULL;
  5337     for (; bufPtr != (ChannelBuffer *) NULL; bufPtr = nxtPtr) {
  5338         nxtPtr = bufPtr->nextPtr;
  5339         RecycleBuffer(statePtr, bufPtr, discardSavedBuffers);
  5340     }
  5341 
  5342     /*
  5343      * If discardSavedBuffers is nonzero, must also discard any previously
  5344      * saved buffer in the saveInBufPtr field.
  5345      */
  5346     
  5347     if (discardSavedBuffers) {
  5348         if (statePtr->saveInBufPtr != (ChannelBuffer *) NULL) {
  5349             ckfree((char *) statePtr->saveInBufPtr);
  5350             statePtr->saveInBufPtr = (ChannelBuffer *) NULL;
  5351         }
  5352     }
  5353 }
  5354 
  5355 /*
  5356  *---------------------------------------------------------------------------
  5357  *
  5358  * GetInput --
  5359  *
  5360  *	Reads input data from a device into a channel buffer.  
  5361  *
  5362  * Results:
  5363  *	The return value is the Posix error code if an error occurred while
  5364  *	reading from the file, or 0 otherwise.  
  5365  *
  5366  * Side effects:
  5367  *	Reads from the underlying device.
  5368  *
  5369  *---------------------------------------------------------------------------
  5370  */
  5371 
  5372 static int
  5373 GetInput(chanPtr)
  5374     Channel *chanPtr;		/* Channel to read input from. */
  5375 {
  5376     int toRead;			/* How much to read? */
  5377     int result;			/* Of calling driver. */
  5378     int nread;			/* How much was read from channel? */
  5379     ChannelBuffer *bufPtr;	/* New buffer to add to input queue. */
  5380     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  5381 
  5382     /*
  5383      * Prevent reading from a dead channel -- a channel that has been closed
  5384      * but not yet deallocated, which can happen if the exit handler for
  5385      * channel cleanup has run but the channel is still registered in some
  5386      * interpreter.
  5387      */
  5388     
  5389     if (CheckForDeadChannel(NULL, statePtr)) {
  5390 	return EINVAL;
  5391     }
  5392 
  5393     /*
  5394      * First check for more buffers in the pushback area of the
  5395      * topmost channel in the stack and use them. They can be the
  5396      * result of a transformation which went away without reading all
  5397      * the information placed in the area when it was stacked.
  5398      *
  5399      * Two possibilities for the state: No buffers in it, or a single
  5400      * empty buffer. In the latter case we can recycle it now.
  5401      */
  5402 
  5403     if (chanPtr->inQueueHead != (ChannelBuffer*) NULL) {
  5404         if (statePtr->inQueueHead != (ChannelBuffer*) NULL) {
  5405 	    RecycleBuffer(statePtr, statePtr->inQueueHead, 0);
  5406 	    statePtr->inQueueHead = (ChannelBuffer*) NULL;
  5407 	}
  5408 
  5409 	statePtr->inQueueHead = chanPtr->inQueueHead;
  5410 	statePtr->inQueueTail = chanPtr->inQueueTail;
  5411 	chanPtr->inQueueHead  = (ChannelBuffer*) NULL;
  5412 	chanPtr->inQueueTail  = (ChannelBuffer*) NULL;
  5413 	return 0;
  5414     }
  5415 
  5416     /*
  5417      * Nothing in the pushback area, fall back to the usual handling
  5418      * (driver, etc.)
  5419      */
  5420 
  5421     /*
  5422      * See if we can fill an existing buffer. If we can, read only
  5423      * as much as will fit in it. Otherwise allocate a new buffer,
  5424      * add it to the input queue and attempt to fill it to the max.
  5425      */
  5426 
  5427     bufPtr = statePtr->inQueueTail;
  5428     if ((bufPtr != NULL) && (bufPtr->nextAdded < bufPtr->bufLength)) {
  5429         toRead = bufPtr->bufLength - bufPtr->nextAdded;
  5430     } else {
  5431 	bufPtr = statePtr->saveInBufPtr;
  5432 	statePtr->saveInBufPtr = NULL;
  5433 
  5434 	/*
  5435 	 * Check the actual buffersize against the requested
  5436 	 * buffersize. Buffers which are smaller than requested are
  5437 	 * squashed. This is done to honor dynamic changes of the
  5438 	 * buffersize made by the user.
  5439 	 */
  5440 
  5441 	if ((bufPtr != NULL) && ((bufPtr->bufLength - BUFFER_PADDING) < statePtr->bufSize)) {
  5442 	  ckfree((char *) bufPtr);
  5443 	  bufPtr = NULL;
  5444 	}
  5445 
  5446 	if (bufPtr == NULL) {
  5447 	    bufPtr = AllocChannelBuffer(statePtr->bufSize);
  5448 	}
  5449         bufPtr->nextPtr = (ChannelBuffer *) NULL;
  5450 
  5451 	/* SF #427196: Use the actual size of the buffer to determine
  5452 	 * the number of bytes to read from the channel and not the
  5453 	 * size for new buffers. They can be different if the
  5454 	 * buffersize was changed between reads.
  5455 	 *
  5456 	 * Note: This affects performance negatively if the buffersize
  5457 	 * was extended but this small buffer is reused for all
  5458 	 * subsequent reads. The system never uses buffers with the
  5459 	 * requested bigger size in that case. An adjunct patch could
  5460 	 * try and delete all unused buffers it encounters and which
  5461 	 * are smaller than the formally requested buffersize.
  5462 	 */
  5463 
  5464 	toRead = bufPtr->bufLength - bufPtr->nextAdded;
  5465 
  5466         if (statePtr->inQueueTail == NULL) {
  5467             statePtr->inQueueHead = bufPtr;
  5468         } else {
  5469             statePtr->inQueueTail->nextPtr = bufPtr;
  5470         }
  5471         statePtr->inQueueTail = bufPtr;
  5472     }
  5473 
  5474     /*
  5475      * If EOF is set, we should avoid calling the driver because on some
  5476      * platforms it is impossible to read from a device after EOF.
  5477      */
  5478 
  5479     if (statePtr->flags & CHANNEL_EOF) {
  5480 	return 0;
  5481     }
  5482 
  5483 #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING
  5484     /* [SF Tcl Bug 943274]. Better emulation of non-blocking channels
  5485      * for channels without BlockModeProc, by keeping track of true
  5486      * fileevents generated by the OS == Data waiting and reading if
  5487      * and only if we are sure to have data.
  5488      */
  5489 
  5490     if ((statePtr->flags & CHANNEL_NONBLOCKING) &&
  5491 	(Tcl_ChannelBlockModeProc(chanPtr->typePtr) == NULL) &&
  5492 	!(statePtr->flags & CHANNEL_HAS_MORE_DATA)) {
  5493 
  5494         /* Bypass the driver, it would block, as no data is available */
  5495         nread = -1;
  5496         result = EWOULDBLOCK;
  5497     } else {
  5498 #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */
  5499 
  5500         nread = (chanPtr->typePtr->inputProc)(chanPtr->instanceData,
  5501 		    bufPtr->buf + bufPtr->nextAdded, toRead, &result);
  5502 
  5503 #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING
  5504     }
  5505 #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */
  5506 
  5507     if (nread > 0) {
  5508 	bufPtr->nextAdded += nread;
  5509 
  5510 	/*
  5511 	 * If we get a short read, signal up that we may be BLOCKED. We
  5512 	 * should avoid calling the driver because on some platforms we
  5513 	 * will block in the low level reading code even though the
  5514 	 * channel is set into nonblocking mode.
  5515 	 */
  5516             
  5517 	if (nread < toRead) {
  5518 	    statePtr->flags |= CHANNEL_BLOCKED;
  5519 	}
  5520 
  5521 #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING
  5522 	if (nread <= toRead) {
  5523 	  /* [SF Tcl Bug 943274] We have read the available data,
  5524 	   * clear flag */
  5525 	  statePtr->flags &= ~CHANNEL_HAS_MORE_DATA;
  5526 	}
  5527 #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */
  5528 
  5529     } else if (nread == 0) {
  5530 	statePtr->flags |= CHANNEL_EOF;
  5531 	statePtr->inputEncodingFlags |= TCL_ENCODING_END;
  5532     } else if (nread < 0) {
  5533 	if ((result == EWOULDBLOCK) || (result == EAGAIN)) {
  5534 	    statePtr->flags |= CHANNEL_BLOCKED;
  5535 	    result = EAGAIN;
  5536 	}
  5537 	Tcl_SetErrno(result);
  5538 	return result;
  5539     }
  5540     return 0;
  5541 }
  5542 
  5543 /*
  5544  *----------------------------------------------------------------------
  5545  *
  5546  * Tcl_Seek --
  5547  *
  5548  *	Implements seeking on Tcl Channels. This is a public function
  5549  *	so that other C facilities may be implemented on top of it.
  5550  *
  5551  * Results:
  5552  *	The new access point or -1 on error. If error, use Tcl_GetErrno()
  5553  *	to retrieve the POSIX error code for the error that occurred.
  5554  *
  5555  * Side effects:
  5556  *	May flush output on the channel. May discard queued input.
  5557  *
  5558  *----------------------------------------------------------------------
  5559  */
  5560 
  5561 EXPORT_C Tcl_WideInt
  5562 Tcl_Seek(chan, offset, mode)
  5563     Tcl_Channel chan;		/* The channel on which to seek. */
  5564     Tcl_WideInt offset;		/* Offset to seek to. */
  5565     int mode;			/* Relative to which location to seek? */
  5566 {
  5567     Channel *chanPtr = (Channel *) chan;	/* The real IO channel. */
  5568     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  5569     int inputBuffered, outputBuffered;
  5570 				/* # bytes held in buffers. */
  5571     int result;			/* Of device driver operations. */
  5572     Tcl_WideInt curPos;		/* Position on the device. */
  5573     int wasAsync;		/* Was the channel nonblocking before the
  5574                                  * seek operation? If so, must restore to
  5575                                  * nonblocking mode after the seek. */
  5576 
  5577     if (CheckChannelErrors(statePtr, TCL_WRITABLE | TCL_READABLE) != 0) {
  5578 	return Tcl_LongAsWide(-1);
  5579     }
  5580 
  5581     /*
  5582      * Disallow seek on dead channels -- channels that have been closed but
  5583      * not yet been deallocated. Such channels can be found if the exit
  5584      * handler for channel cleanup has run but the channel is still
  5585      * registered in an interpreter.
  5586      */
  5587 
  5588     if (CheckForDeadChannel(NULL, statePtr)) {
  5589 	return Tcl_LongAsWide(-1);
  5590     }
  5591 
  5592     /*
  5593      * This operation should occur at the top of a channel stack.
  5594      */
  5595 
  5596     chanPtr = statePtr->topChanPtr;
  5597 
  5598     /*
  5599      * Disallow seek on channels whose type does not have a seek procedure
  5600      * defined. This means that the channel does not support seeking.
  5601      */
  5602 
  5603     if (chanPtr->typePtr->seekProc == (Tcl_DriverSeekProc *) NULL) {
  5604         Tcl_SetErrno(EINVAL);
  5605         return Tcl_LongAsWide(-1);
  5606     }
  5607 
  5608     /*
  5609      * Compute how much input and output is buffered. If both input and
  5610      * output is buffered, cannot compute the current position.
  5611      */
  5612 
  5613     inputBuffered = Tcl_InputBuffered(chan);
  5614     outputBuffered = Tcl_OutputBuffered(chan);
  5615 
  5616     if ((inputBuffered != 0) && (outputBuffered != 0)) {
  5617         Tcl_SetErrno(EFAULT);
  5618         return Tcl_LongAsWide(-1);
  5619     }
  5620 
  5621     /*
  5622      * If we are seeking relative to the current position, compute the
  5623      * corrected offset taking into account the amount of unread input.
  5624      */
  5625 
  5626     if (mode == SEEK_CUR) {
  5627         offset -= inputBuffered;
  5628     }
  5629 
  5630     /*
  5631      * Discard any queued input - this input should not be read after
  5632      * the seek.
  5633      */
  5634 
  5635     DiscardInputQueued(statePtr, 0);
  5636 
  5637     /*
  5638      * Reset EOF and BLOCKED flags. We invalidate them by moving the
  5639      * access point. Also clear CR related flags.
  5640      */
  5641 
  5642     statePtr->flags &=
  5643         (~(CHANNEL_EOF | CHANNEL_STICKY_EOF | CHANNEL_BLOCKED | INPUT_SAW_CR));
  5644     
  5645     /*
  5646      * If the channel is in asynchronous output mode, switch it back
  5647      * to synchronous mode and cancel any async flush that may be
  5648      * scheduled. After the flush, the channel will be put back into
  5649      * asynchronous output mode.
  5650      */
  5651 
  5652     wasAsync = 0;
  5653     if (statePtr->flags & CHANNEL_NONBLOCKING) {
  5654         wasAsync = 1;
  5655         result = StackSetBlockMode(chanPtr, TCL_MODE_BLOCKING);
  5656 	if (result != 0) {
  5657 	    return Tcl_LongAsWide(-1);
  5658 	}
  5659         statePtr->flags &= (~(CHANNEL_NONBLOCKING));
  5660         if (statePtr->flags & BG_FLUSH_SCHEDULED) {
  5661             statePtr->flags &= (~(BG_FLUSH_SCHEDULED));
  5662         }
  5663     }
  5664     
  5665     /*
  5666      * If the flush fails we cannot recover the original position. In
  5667      * that case the seek is not attempted because we do not know where
  5668      * the access position is - instead we return the error. FlushChannel
  5669      * has already called Tcl_SetErrno() to report the error upwards.
  5670      * If the flush succeeds we do the seek also.
  5671      */
  5672     
  5673     if (FlushChannel(NULL, chanPtr, 0) != 0) {
  5674         curPos = -1;
  5675     } else {
  5676 
  5677         /*
  5678          * Now seek to the new position in the channel as requested by the
  5679          * caller.  Note that we prefer the wideSeekProc if that is
  5680 	 * available and non-NULL...
  5681          */
  5682 
  5683 	if (HaveVersion(chanPtr->typePtr, TCL_CHANNEL_VERSION_3) &&
  5684 		chanPtr->typePtr->wideSeekProc != NULL) {
  5685 	    curPos = (chanPtr->typePtr->wideSeekProc) (chanPtr->instanceData,
  5686 		    offset, mode, &result);
  5687 	} else if (offset < Tcl_LongAsWide(LONG_MIN) ||
  5688 		offset > Tcl_LongAsWide(LONG_MAX)) {
  5689 	    result = EOVERFLOW;
  5690 	    curPos = Tcl_LongAsWide(-1);
  5691 	} else {
  5692 	    curPos = Tcl_LongAsWide((chanPtr->typePtr->seekProc) (
  5693 		    chanPtr->instanceData, Tcl_WideAsLong(offset), mode,
  5694 		    &result));
  5695 	}
  5696 	if (curPos == Tcl_LongAsWide(-1)) {
  5697 	    Tcl_SetErrno(result);
  5698 	}
  5699     }
  5700     
  5701     /*
  5702      * Restore to nonblocking mode if that was the previous behavior.
  5703      *
  5704      * NOTE: Even if there was an async flush active we do not restore
  5705      * it now because we already flushed all the queued output, above.
  5706      */
  5707     
  5708     if (wasAsync) {
  5709         statePtr->flags |= CHANNEL_NONBLOCKING;
  5710         result = StackSetBlockMode(chanPtr, TCL_MODE_NONBLOCKING);
  5711 	if (result != 0) {
  5712 	    return Tcl_LongAsWide(-1);
  5713 	}
  5714     }
  5715 
  5716     return curPos;
  5717 }
  5718 
  5719 /*
  5720  *----------------------------------------------------------------------
  5721  *
  5722  * Tcl_Tell --
  5723  *
  5724  *	Returns the position of the next character to be read/written on
  5725  *	this channel.
  5726  *
  5727  * Results:
  5728  *	A nonnegative integer on success, -1 on failure. If failed,
  5729  *	use Tcl_GetErrno() to retrieve the POSIX error code for the
  5730  *	error that occurred.
  5731  *
  5732  * Side effects:
  5733  *	None.
  5734  *
  5735  *----------------------------------------------------------------------
  5736  */
  5737 
  5738 EXPORT_C Tcl_WideInt
  5739 Tcl_Tell(chan)
  5740     Tcl_Channel chan;			/* The channel to return pos for. */
  5741 {
  5742     Channel *chanPtr = (Channel *) chan;	/* The real IO channel. */
  5743     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  5744     int inputBuffered, outputBuffered;	/* # bytes held in buffers. */
  5745     int result;				/* Of calling device driver. */
  5746     Tcl_WideInt curPos;			/* Position on device. */
  5747 
  5748     if (CheckChannelErrors(statePtr, TCL_WRITABLE | TCL_READABLE) != 0) {
  5749 	return Tcl_LongAsWide(-1);
  5750     }
  5751 
  5752     /*
  5753      * Disallow tell on dead channels -- channels that have been closed but
  5754      * not yet been deallocated. Such channels can be found if the exit
  5755      * handler for channel cleanup has run but the channel is still
  5756      * registered in an interpreter.
  5757      */
  5758 
  5759     if (CheckForDeadChannel(NULL, statePtr)) {
  5760 	return Tcl_LongAsWide(-1);
  5761     }
  5762 
  5763     /*
  5764      * This operation should occur at the top of a channel stack.
  5765      */
  5766 
  5767     chanPtr = statePtr->topChanPtr;
  5768 
  5769     /*
  5770      * Disallow tell on channels whose type does not have a seek procedure
  5771      * defined. This means that the channel does not support seeking.
  5772      */
  5773 
  5774     if (chanPtr->typePtr->seekProc == (Tcl_DriverSeekProc *) NULL) {
  5775         Tcl_SetErrno(EINVAL);
  5776         return Tcl_LongAsWide(-1);
  5777     }
  5778 
  5779     /*
  5780      * Compute how much input and output is buffered. If both input and
  5781      * output is buffered, cannot compute the current position.
  5782      */
  5783 
  5784     inputBuffered = Tcl_InputBuffered(chan);
  5785     outputBuffered = Tcl_OutputBuffered(chan);
  5786 
  5787     if ((inputBuffered != 0) && (outputBuffered != 0)) {
  5788         Tcl_SetErrno(EFAULT);
  5789         return Tcl_LongAsWide(-1);
  5790     }
  5791 
  5792     /*
  5793      * Get the current position in the device and compute the position
  5794      * where the next character will be read or written.  Note that we
  5795      * prefer the wideSeekProc if that is available and non-NULL...
  5796      */
  5797 
  5798     if (HaveVersion(chanPtr->typePtr, TCL_CHANNEL_VERSION_3) &&
  5799 	    chanPtr->typePtr->wideSeekProc != NULL) {
  5800 	curPos = (chanPtr->typePtr->wideSeekProc) (chanPtr->instanceData,
  5801 		Tcl_LongAsWide(0), SEEK_CUR, &result);
  5802     } else {
  5803 	curPos = Tcl_LongAsWide((chanPtr->typePtr->seekProc) (
  5804 		chanPtr->instanceData, 0, SEEK_CUR, &result));
  5805     }
  5806     if (curPos == Tcl_LongAsWide(-1)) {
  5807         Tcl_SetErrno(result);
  5808         return Tcl_LongAsWide(-1);
  5809     }
  5810     if (inputBuffered != 0) {
  5811         return curPos - inputBuffered;
  5812     }
  5813     return curPos + outputBuffered;
  5814 }
  5815 
  5816 /*
  5817  *---------------------------------------------------------------------------
  5818  *
  5819  * Tcl_SeekOld, Tcl_TellOld --
  5820  *
  5821  *	Backward-compatability versions of the seek/tell interface that
  5822  *	do not support 64-bit offsets.  This interface is not documented
  5823  *	or expected to be supported indefinitely.
  5824  *
  5825  * Results:
  5826  *	As for Tcl_Seek and Tcl_Tell respectively, except truncated to
  5827  *	whatever value will fit in an 'int'.
  5828  *
  5829  * Side effects:
  5830  *	As for Tcl_Seek and Tcl_Tell respectively.
  5831  *
  5832  *---------------------------------------------------------------------------
  5833  */
  5834 
  5835 EXPORT_C int
  5836 Tcl_SeekOld(chan, offset, mode)
  5837     Tcl_Channel chan;		/* The channel on which to seek. */
  5838     int offset;			/* Offset to seek to. */
  5839     int mode;			/* Relative to which location to seek? */
  5840 {
  5841     Tcl_WideInt wOffset, wResult;
  5842 
  5843     wOffset = Tcl_LongAsWide((long)offset);
  5844     wResult = Tcl_Seek(chan, wOffset, mode);
  5845     return (int)Tcl_WideAsLong(wResult);
  5846 }
  5847 
  5848 EXPORT_C int
  5849 Tcl_TellOld(chan)
  5850     Tcl_Channel chan;		/* The channel to return pos for. */
  5851 {
  5852     Tcl_WideInt wResult;
  5853 
  5854     wResult = Tcl_Tell(chan);
  5855     return (int)Tcl_WideAsLong(wResult);
  5856 }
  5857 
  5858 /*
  5859  *---------------------------------------------------------------------------
  5860  *
  5861  * CheckChannelErrors --
  5862  *
  5863  *	See if the channel is in an ready state and can perform the
  5864  *	desired operation.
  5865  *
  5866  * Results:
  5867  *	The return value is 0 if the channel is OK, otherwise the
  5868  *	return value is -1 and errno is set to indicate the error.
  5869  *
  5870  * Side effects:
  5871  *	May clear the EOF and/or BLOCKED bits if reading from channel.
  5872  *
  5873  *---------------------------------------------------------------------------
  5874  */
  5875  
  5876 static int
  5877 CheckChannelErrors(statePtr, flags)
  5878     ChannelState *statePtr;	/* Channel to check. */
  5879     int flags;			/* Test if channel supports desired operation:
  5880 				 * TCL_READABLE, TCL_WRITABLE.  Also indicates
  5881 				 * Raw read or write for special close
  5882 				 * processing*/
  5883 {
  5884     int direction = flags & (TCL_READABLE|TCL_WRITABLE);
  5885 
  5886     /*
  5887      * Check for unreported error.
  5888      */
  5889 
  5890     if (statePtr->unreportedError != 0) {
  5891         Tcl_SetErrno(statePtr->unreportedError);
  5892         statePtr->unreportedError = 0;
  5893         return -1;
  5894     }
  5895 
  5896     /*
  5897      * Only the raw read and write operations are allowed during close
  5898      * in order to drain data from stacked channels.
  5899      */
  5900 
  5901     if ((statePtr->flags & CHANNEL_CLOSED) &&
  5902 	    ((flags & CHANNEL_RAW_MODE) == 0)) {
  5903         Tcl_SetErrno(EACCES);
  5904         return -1;
  5905     }
  5906 
  5907     /*
  5908      * Fail if the channel is not opened for desired operation.
  5909      */
  5910 
  5911     if ((statePtr->flags & direction) == 0) {
  5912         Tcl_SetErrno(EACCES);
  5913         return -1;
  5914     }
  5915 
  5916     /*
  5917      * Fail if the channel is in the middle of a background copy.
  5918      *
  5919      * Don't do this tests for raw channels here or else the chaining in the
  5920      * transformation drivers will fail with 'file busy' error instead of
  5921      * retrieving and transforming the data to copy.
  5922      */
  5923 
  5924     if ((statePtr->csPtr != NULL) && ((flags & CHANNEL_RAW_MODE) == 0)) {
  5925 	Tcl_SetErrno(EBUSY);
  5926 	return -1;
  5927     }
  5928 
  5929     if (direction == TCL_READABLE) {
  5930 	/*
  5931 	 * If we have not encountered a sticky EOF, clear the EOF bit
  5932 	 * (sticky EOF is set if we have seen the input eofChar, to prevent
  5933 	 * reading beyond the eofChar). Also, always clear the BLOCKED bit.
  5934 	 * We want to discover these conditions anew in each operation.
  5935 	 */
  5936 
  5937 	if ((statePtr->flags & CHANNEL_STICKY_EOF) == 0) {
  5938 	    statePtr->flags &= ~CHANNEL_EOF;
  5939 	}
  5940 	statePtr->flags &= ~(CHANNEL_BLOCKED | CHANNEL_NEED_MORE_DATA);
  5941     }
  5942 
  5943     return 0;
  5944 }
  5945 
  5946 /*
  5947  *----------------------------------------------------------------------
  5948  *
  5949  * Tcl_Eof --
  5950  *
  5951  *	Returns 1 if the channel is at EOF, 0 otherwise.
  5952  *
  5953  * Results:
  5954  *	1 or 0, always.
  5955  *
  5956  * Side effects:
  5957  *	None.
  5958  *
  5959  *----------------------------------------------------------------------
  5960  */
  5961 
  5962 EXPORT_C int
  5963 Tcl_Eof(chan)
  5964     Tcl_Channel chan;			/* Does this channel have EOF? */
  5965 {
  5966     ChannelState *statePtr = ((Channel *) chan)->state;
  5967 					/* State of real channel structure. */
  5968 
  5969     return ((statePtr->flags & CHANNEL_STICKY_EOF) ||
  5970             ((statePtr->flags & CHANNEL_EOF) &&
  5971 		    (Tcl_InputBuffered(chan) == 0))) ? 1 : 0;
  5972 }
  5973 
  5974 /*
  5975  *----------------------------------------------------------------------
  5976  *
  5977  * Tcl_InputBlocked --
  5978  *
  5979  *	Returns 1 if input is blocked on this channel, 0 otherwise.
  5980  *
  5981  * Results:
  5982  *	0 or 1, always.
  5983  *
  5984  * Side effects:
  5985  *	None.
  5986  *
  5987  *----------------------------------------------------------------------
  5988  */
  5989 
  5990 EXPORT_C int
  5991 Tcl_InputBlocked(chan)
  5992     Tcl_Channel chan;			/* Is this channel blocked? */
  5993 {
  5994     ChannelState *statePtr = ((Channel *) chan)->state;
  5995 					/* State of real channel structure. */
  5996 
  5997     return (statePtr->flags & CHANNEL_BLOCKED) ? 1 : 0;
  5998 }
  5999 
  6000 /*
  6001  *----------------------------------------------------------------------
  6002  *
  6003  * Tcl_InputBuffered --
  6004  *
  6005  *	Returns the number of bytes of input currently buffered in the
  6006  *	common internal buffer of a channel.
  6007  *
  6008  * Results:
  6009  *	The number of input bytes buffered, or zero if the channel is not
  6010  *	open for reading.
  6011  *
  6012  * Side effects:
  6013  *	None.
  6014  *
  6015  *----------------------------------------------------------------------
  6016  */
  6017 
  6018 EXPORT_C int
  6019 Tcl_InputBuffered(chan)
  6020     Tcl_Channel chan;			/* The channel to query. */
  6021 {
  6022     ChannelState *statePtr = ((Channel *) chan)->state;
  6023 					/* State of real channel structure. */
  6024     ChannelBuffer *bufPtr;
  6025     int bytesBuffered;
  6026 
  6027     for (bytesBuffered = 0, bufPtr = statePtr->inQueueHead;
  6028 	 bufPtr != (ChannelBuffer *) NULL;
  6029 	 bufPtr = bufPtr->nextPtr) {
  6030         bytesBuffered += (bufPtr->nextAdded - bufPtr->nextRemoved);
  6031     }
  6032 
  6033     /*
  6034      * Don't forget the bytes in the topmost pushback area.
  6035      */
  6036 
  6037     for (bufPtr = statePtr->topChanPtr->inQueueHead;
  6038 	 bufPtr != (ChannelBuffer *) NULL;
  6039 	 bufPtr = bufPtr->nextPtr) {
  6040         bytesBuffered += (bufPtr->nextAdded - bufPtr->nextRemoved);
  6041     }
  6042 
  6043     return bytesBuffered;
  6044 }
  6045 
  6046 /*
  6047  *----------------------------------------------------------------------
  6048  *
  6049  * Tcl_OutputBuffered --
  6050  *
  6051  *    Returns the number of bytes of output currently buffered in the
  6052  *    common internal buffer of a channel.
  6053  *
  6054  * Results:
  6055  *    The number of output bytes buffered, or zero if the channel is not
  6056  *    open for writing.
  6057  *
  6058  * Side effects:
  6059  *    None.
  6060  *
  6061  *----------------------------------------------------------------------
  6062  */
  6063 
  6064 EXPORT_C int
  6065 Tcl_OutputBuffered(chan)
  6066     Tcl_Channel chan;                 /* The channel to query. */
  6067 {
  6068     ChannelState *statePtr = ((Channel *) chan)->state;
  6069                                       /* State of real channel structure. */
  6070     ChannelBuffer *bufPtr;
  6071     int bytesBuffered;
  6072 
  6073     for (bytesBuffered = 0, bufPtr = statePtr->outQueueHead;
  6074 	bufPtr != (ChannelBuffer *) NULL;
  6075 	bufPtr = bufPtr->nextPtr) {
  6076 	bytesBuffered += (bufPtr->nextAdded - bufPtr->nextRemoved);
  6077     }
  6078     if ((statePtr->curOutPtr != (ChannelBuffer *) NULL) &&
  6079 	(statePtr->curOutPtr->nextAdded > statePtr->curOutPtr->nextRemoved)) {
  6080 	statePtr->flags |= BUFFER_READY;
  6081 	bytesBuffered +=
  6082 	    (statePtr->curOutPtr->nextAdded - statePtr->curOutPtr->nextRemoved);
  6083     }
  6084 
  6085     return bytesBuffered;
  6086 }
  6087 
  6088 /*
  6089  *----------------------------------------------------------------------
  6090  *
  6091  * Tcl_ChannelBuffered --
  6092  *
  6093  *	Returns the number of bytes of input currently buffered in the
  6094  *	internal buffer (push back area) of a channel.
  6095  *
  6096  * Results:
  6097  *	The number of input bytes buffered, or zero if the channel is not
  6098  *	open for reading.
  6099  *
  6100  * Side effects:
  6101  *	None.
  6102  *
  6103  *----------------------------------------------------------------------
  6104  */
  6105 
  6106 EXPORT_C int
  6107 Tcl_ChannelBuffered(chan)
  6108     Tcl_Channel chan;			/* The channel to query. */
  6109 {
  6110     Channel *chanPtr = (Channel *) chan;
  6111 					/* real channel structure. */
  6112     ChannelBuffer *bufPtr;
  6113     int bytesBuffered;
  6114 
  6115     for (bytesBuffered = 0, bufPtr = chanPtr->inQueueHead;
  6116 	 bufPtr != (ChannelBuffer *) NULL;
  6117 	 bufPtr = bufPtr->nextPtr) {
  6118         bytesBuffered += (bufPtr->nextAdded - bufPtr->nextRemoved);
  6119     }
  6120 
  6121     return bytesBuffered;
  6122 }
  6123 
  6124 /*
  6125  *----------------------------------------------------------------------
  6126  *
  6127  * Tcl_SetChannelBufferSize --
  6128  *
  6129  *	Sets the size of buffers to allocate to store input or output
  6130  *	in the channel. The size must be between 1 byte and 1 MByte.
  6131  *
  6132  * Results:
  6133  *	None.
  6134  *
  6135  * Side effects:
  6136  *	Sets the size of buffers subsequently allocated for this channel.
  6137  *
  6138  *----------------------------------------------------------------------
  6139  */
  6140 
  6141 EXPORT_C void
  6142 Tcl_SetChannelBufferSize(chan, sz)
  6143     Tcl_Channel chan;			/* The channel whose buffer size
  6144                                          * to set. */
  6145     int sz;				/* The size to set. */
  6146 {
  6147     ChannelState *statePtr;		/* State of real channel structure. */
  6148     
  6149     /*
  6150      * If the buffer size is smaller than 1 byte or larger than one MByte,
  6151      * do not accept the requested size and leave the current buffer size.
  6152      */
  6153     
  6154     if (sz < 1) {
  6155         return;
  6156     }
  6157     if (sz > (1024 * 1024)) {
  6158         return;
  6159     }
  6160 
  6161     statePtr = ((Channel *) chan)->state;
  6162     statePtr->bufSize = sz;
  6163 
  6164     if (statePtr->outputStage != NULL) {
  6165 	ckfree((char *) statePtr->outputStage);
  6166 	statePtr->outputStage = NULL;
  6167     }
  6168     if ((statePtr->encoding != NULL) && (statePtr->flags & TCL_WRITABLE)) {
  6169 	statePtr->outputStage = (char *)
  6170 	    ckalloc((unsigned) (statePtr->bufSize + 2));
  6171     }
  6172 }
  6173 
  6174 /*
  6175  *----------------------------------------------------------------------
  6176  *
  6177  * Tcl_GetChannelBufferSize --
  6178  *
  6179  *	Retrieves the size of buffers to allocate for this channel.
  6180  *
  6181  * Results:
  6182  *	The size.
  6183  *
  6184  * Side effects:
  6185  *	None.
  6186  *
  6187  *----------------------------------------------------------------------
  6188  */
  6189 
  6190 EXPORT_C int
  6191 Tcl_GetChannelBufferSize(chan)
  6192     Tcl_Channel chan;		/* The channel for which to find the
  6193                                  * buffer size. */
  6194 {
  6195     ChannelState *statePtr = ((Channel *) chan)->state;
  6196 					/* State of real channel structure. */
  6197 
  6198     return statePtr->bufSize;
  6199 }
  6200 
  6201 /*
  6202  *----------------------------------------------------------------------
  6203  *
  6204  * Tcl_BadChannelOption --
  6205  *
  6206  *	This procedure generates a "bad option" error message in an
  6207  *	(optional) interpreter.  It is used by channel drivers when 
  6208  *      a invalid Set/Get option is requested. Its purpose is to concatenate
  6209  *      the generic options list to the specific ones and factorize
  6210  *      the generic options error message string.
  6211  *
  6212  * Results:
  6213  *	TCL_ERROR.
  6214  *
  6215  * Side effects:
  6216  *	An error message is generated in interp's result object to
  6217  *	indicate that a command was invoked with the a bad option
  6218  *	The message has the form
  6219  *		bad option "blah": should be one of 
  6220  *              <...generic options...>+<...specific options...>
  6221  *	"blah" is the optionName argument and "<specific options>"
  6222  *	is a space separated list of specific option words.
  6223  *      The function takes good care of inserting minus signs before
  6224  *      each option, commas after, and an "or" before the last option.
  6225  *
  6226  *----------------------------------------------------------------------
  6227  */
  6228 
  6229 EXPORT_C int
  6230 Tcl_BadChannelOption(interp, optionName, optionList)
  6231     Tcl_Interp *interp;			/* Current interpreter. (can be NULL)*/
  6232     CONST char *optionName;		/* 'bad option' name */
  6233     CONST char *optionList;		/* Specific options list to append 
  6234 					 * to the standard generic options.
  6235 					 * can be NULL for generic options 
  6236 					 * only.
  6237 					 */
  6238 {
  6239     if (interp) {
  6240 	CONST char *genericopt = 
  6241 	    "blocking buffering buffersize encoding eofchar translation";
  6242 	CONST char **argv;
  6243 	int  argc, i;
  6244 	Tcl_DString ds;
  6245 
  6246 	Tcl_DStringInit(&ds);
  6247 	Tcl_DStringAppend(&ds, genericopt, -1);
  6248 	if (optionList && (*optionList)) {
  6249 	    Tcl_DStringAppend(&ds, " ", 1);
  6250 	    Tcl_DStringAppend(&ds, optionList, -1);
  6251 	}
  6252 	if (Tcl_SplitList(interp, Tcl_DStringValue(&ds), 
  6253 		&argc, &argv) != TCL_OK) {
  6254 	    panic("malformed option list in channel driver");
  6255 	}
  6256 	Tcl_ResetResult(interp);
  6257 	Tcl_AppendResult(interp, "bad option \"", optionName, 
  6258 		"\": should be one of ", (char *) NULL);
  6259 	argc--;
  6260 	for (i = 0; i < argc; i++) {
  6261 	    Tcl_AppendResult(interp, "-", argv[i], ", ", (char *) NULL);
  6262 	}
  6263 	Tcl_AppendResult(interp, "or -", argv[i], (char *) NULL);
  6264 	Tcl_DStringFree(&ds);
  6265 	ckfree((char *) argv);
  6266     }
  6267     Tcl_SetErrno(EINVAL);
  6268     return TCL_ERROR;
  6269 }
  6270 
  6271 /*
  6272  *----------------------------------------------------------------------
  6273  *
  6274  * Tcl_GetChannelOption --
  6275  *
  6276  *	Gets a mode associated with an IO channel. If the optionName arg
  6277  *	is non NULL, retrieves the value of that option. If the optionName
  6278  *	arg is NULL, retrieves a list of alternating option names and
  6279  *	values for the given channel.
  6280  *
  6281  * Results:
  6282  *	A standard Tcl result. Also sets the supplied DString to the
  6283  *	string value of the option(s) returned.
  6284  *
  6285  * Side effects:
  6286  *      None.
  6287  *
  6288  *----------------------------------------------------------------------
  6289  */
  6290 
  6291 EXPORT_C int
  6292 Tcl_GetChannelOption(interp, chan, optionName, dsPtr)
  6293     Tcl_Interp *interp;		/* For error reporting - can be NULL. */
  6294     Tcl_Channel chan;		/* Channel on which to get option. */
  6295     CONST char *optionName;	/* Option to get. */
  6296     Tcl_DString *dsPtr;		/* Where to store value(s). */
  6297 {
  6298     size_t len;			/* Length of optionName string. */
  6299     char optionVal[128];	/* Buffer for sprintf. */
  6300     Channel *chanPtr = (Channel *) chan;
  6301     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  6302     int flags;
  6303 
  6304     /*
  6305      * Disallow options on dead channels -- channels that have been closed but
  6306      * not yet been deallocated. Such channels can be found if the exit
  6307      * handler for channel cleanup has run but the channel is still
  6308      * registered in an interpreter.
  6309      */
  6310 
  6311     if (CheckForDeadChannel(interp, statePtr)) {
  6312 	return TCL_ERROR;
  6313     }
  6314 
  6315     /*
  6316      * This operation should occur at the top of a channel stack.
  6317      */
  6318 
  6319     chanPtr = statePtr->topChanPtr;
  6320 
  6321     /*
  6322      * If we are in the middle of a background copy, use the saved flags.
  6323      */
  6324 
  6325     if (statePtr->csPtr) {
  6326 	if (chanPtr == statePtr->csPtr->readPtr) {
  6327 	    flags = statePtr->csPtr->readFlags;
  6328 	} else {
  6329 	    flags = statePtr->csPtr->writeFlags;
  6330 	}
  6331     } else {
  6332 	flags = statePtr->flags;
  6333     }
  6334 
  6335     /*
  6336      * If the optionName is NULL it means that we want a list of all
  6337      * options and values.
  6338      */
  6339     
  6340     if (optionName == (char *) NULL) {
  6341         len = 0;
  6342     } else {
  6343         len = strlen(optionName);
  6344     }
  6345     
  6346     if ((len == 0) || ((len > 2) && (optionName[1] == 'b') &&
  6347             (strncmp(optionName, "-blocking", len) == 0))) {
  6348         if (len == 0) {
  6349             Tcl_DStringAppendElement(dsPtr, "-blocking");
  6350         }
  6351         Tcl_DStringAppendElement(dsPtr,
  6352 		(flags & CHANNEL_NONBLOCKING) ? "0" : "1");
  6353         if (len > 0) {
  6354             return TCL_OK;
  6355         }
  6356     }
  6357     if ((len == 0) || ((len > 7) && (optionName[1] == 'b') &&
  6358             (strncmp(optionName, "-buffering", len) == 0))) {
  6359         if (len == 0) {
  6360             Tcl_DStringAppendElement(dsPtr, "-buffering");
  6361         }
  6362         if (flags & CHANNEL_LINEBUFFERED) {
  6363             Tcl_DStringAppendElement(dsPtr, "line");
  6364         } else if (flags & CHANNEL_UNBUFFERED) {
  6365             Tcl_DStringAppendElement(dsPtr, "none");
  6366         } else {
  6367             Tcl_DStringAppendElement(dsPtr, "full");
  6368         }
  6369         if (len > 0) {
  6370             return TCL_OK;
  6371         }
  6372     }
  6373     if ((len == 0) || ((len > 7) && (optionName[1] == 'b') &&
  6374             (strncmp(optionName, "-buffersize", len) == 0))) {
  6375         if (len == 0) {
  6376             Tcl_DStringAppendElement(dsPtr, "-buffersize");
  6377         }
  6378         TclFormatInt(optionVal, statePtr->bufSize);
  6379         Tcl_DStringAppendElement(dsPtr, optionVal);
  6380         if (len > 0) {
  6381             return TCL_OK;
  6382         }
  6383     }
  6384     if ((len == 0) ||
  6385 	    ((len > 2) && (optionName[1] == 'e') &&
  6386 		    (strncmp(optionName, "-encoding", len) == 0))) {
  6387 	if (len == 0) {
  6388 	    Tcl_DStringAppendElement(dsPtr, "-encoding");
  6389 	}
  6390 	if (statePtr->encoding == NULL) {
  6391 	    Tcl_DStringAppendElement(dsPtr, "binary");
  6392 	} else {
  6393 	    Tcl_DStringAppendElement(dsPtr,
  6394 		    Tcl_GetEncodingName(statePtr->encoding));
  6395 	}
  6396 	if (len > 0) {
  6397 	    return TCL_OK;
  6398 	}
  6399     }
  6400     if ((len == 0) ||
  6401             ((len > 2) && (optionName[1] == 'e') &&
  6402                     (strncmp(optionName, "-eofchar", len) == 0))) {
  6403         if (len == 0) {
  6404             Tcl_DStringAppendElement(dsPtr, "-eofchar");
  6405         }
  6406         if (((flags & (TCL_READABLE|TCL_WRITABLE)) ==
  6407                 (TCL_READABLE|TCL_WRITABLE)) && (len == 0)) {
  6408             Tcl_DStringStartSublist(dsPtr);
  6409         }
  6410         if (flags & TCL_READABLE) {
  6411             if (statePtr->inEofChar == 0) {
  6412                 Tcl_DStringAppendElement(dsPtr, "");
  6413             } else {
  6414                 char buf[4];
  6415 
  6416                 sprintf(buf, "%c", statePtr->inEofChar);
  6417                 Tcl_DStringAppendElement(dsPtr, buf);
  6418             }
  6419         }
  6420         if (flags & TCL_WRITABLE) {
  6421             if (statePtr->outEofChar == 0) {
  6422                 Tcl_DStringAppendElement(dsPtr, "");
  6423             } else {
  6424                 char buf[4];
  6425 
  6426                 sprintf(buf, "%c", statePtr->outEofChar);
  6427                 Tcl_DStringAppendElement(dsPtr, buf);
  6428             }
  6429         }
  6430         if ( !(flags & (TCL_READABLE|TCL_WRITABLE))) {
  6431             /* Not readable or writable (server socket) */
  6432             Tcl_DStringAppendElement(dsPtr, "");
  6433         }
  6434         if (((flags & (TCL_READABLE|TCL_WRITABLE)) ==
  6435                 (TCL_READABLE|TCL_WRITABLE)) && (len == 0)) {
  6436             Tcl_DStringEndSublist(dsPtr);
  6437         }
  6438         if (len > 0) {
  6439             return TCL_OK;
  6440         }
  6441     }
  6442     if ((len == 0) ||
  6443             ((len > 1) && (optionName[1] == 't') &&
  6444                     (strncmp(optionName, "-translation", len) == 0))) {
  6445         if (len == 0) {
  6446             Tcl_DStringAppendElement(dsPtr, "-translation");
  6447         }
  6448         if (((flags & (TCL_READABLE|TCL_WRITABLE)) ==
  6449                 (TCL_READABLE|TCL_WRITABLE)) && (len == 0)) {
  6450             Tcl_DStringStartSublist(dsPtr);
  6451         }
  6452         if (flags & TCL_READABLE) {
  6453             if (statePtr->inputTranslation == TCL_TRANSLATE_AUTO) {
  6454                 Tcl_DStringAppendElement(dsPtr, "auto");
  6455             } else if (statePtr->inputTranslation == TCL_TRANSLATE_CR) {
  6456                 Tcl_DStringAppendElement(dsPtr, "cr");
  6457             } else if (statePtr->inputTranslation == TCL_TRANSLATE_CRLF) {
  6458                 Tcl_DStringAppendElement(dsPtr, "crlf");
  6459             } else {
  6460                 Tcl_DStringAppendElement(dsPtr, "lf");
  6461             }
  6462         }
  6463         if (flags & TCL_WRITABLE) {
  6464             if (statePtr->outputTranslation == TCL_TRANSLATE_AUTO) {
  6465                 Tcl_DStringAppendElement(dsPtr, "auto");
  6466             } else if (statePtr->outputTranslation == TCL_TRANSLATE_CR) {
  6467                 Tcl_DStringAppendElement(dsPtr, "cr");
  6468             } else if (statePtr->outputTranslation == TCL_TRANSLATE_CRLF) {
  6469                 Tcl_DStringAppendElement(dsPtr, "crlf");
  6470             } else {
  6471                 Tcl_DStringAppendElement(dsPtr, "lf");
  6472             }
  6473         }
  6474         if ( !(flags & (TCL_READABLE|TCL_WRITABLE))) {
  6475             /* Not readable or writable (server socket) */
  6476             Tcl_DStringAppendElement(dsPtr, "auto");
  6477         }
  6478         if (((flags & (TCL_READABLE|TCL_WRITABLE)) ==
  6479                 (TCL_READABLE|TCL_WRITABLE)) && (len == 0)) {
  6480             Tcl_DStringEndSublist(dsPtr);
  6481         }
  6482         if (len > 0) {
  6483             return TCL_OK;
  6484         }
  6485     }
  6486     if (chanPtr->typePtr->getOptionProc != (Tcl_DriverGetOptionProc *) NULL) {
  6487 	/*
  6488 	 * let the driver specific handle additional options
  6489 	 * and result code and message.
  6490 	 */
  6491 
  6492         return (chanPtr->typePtr->getOptionProc) (chanPtr->instanceData,
  6493 		interp, optionName, dsPtr);
  6494     } else {
  6495 	/*
  6496 	 * no driver specific options case.
  6497 	 */
  6498 
  6499         if (len == 0) {
  6500             return TCL_OK;
  6501         }
  6502 	return Tcl_BadChannelOption(interp, optionName, NULL);
  6503     }
  6504 }
  6505 
  6506 /*
  6507  *---------------------------------------------------------------------------
  6508  *
  6509  * Tcl_SetChannelOption --
  6510  *
  6511  *	Sets an option on a channel.
  6512  *
  6513  * Results:
  6514  *	A standard Tcl result.  On error, sets interp's result object
  6515  *	if interp is not NULL.
  6516  *
  6517  * Side effects:
  6518  *	May modify an option on a device.
  6519  *
  6520  *---------------------------------------------------------------------------
  6521  */
  6522 
  6523 EXPORT_C int
  6524 Tcl_SetChannelOption(interp, chan, optionName, newValue)
  6525     Tcl_Interp *interp;		/* For error reporting - can be NULL. */
  6526     Tcl_Channel chan;		/* Channel on which to set mode. */
  6527     CONST char *optionName;	/* Which option to set? */
  6528     CONST char *newValue;	/* New value for option. */
  6529 {
  6530     Channel *chanPtr = (Channel *) chan;	/* The real IO channel. */
  6531     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  6532     size_t len;			/* Length of optionName string. */
  6533     int argc;
  6534     CONST char **argv;
  6535 
  6536     /*
  6537      * If the channel is in the middle of a background copy, fail.
  6538      */
  6539 
  6540     if (statePtr->csPtr) {
  6541 	if (interp) {
  6542 	    Tcl_AppendResult(interp,
  6543 		    "unable to set channel options: background copy in progress",
  6544 		    (char *) NULL);
  6545 	}
  6546         return TCL_ERROR;
  6547     }
  6548 
  6549     /*
  6550      * Disallow options on dead channels -- channels that have been closed but
  6551      * not yet been deallocated. Such channels can be found if the exit
  6552      * handler for channel cleanup has run but the channel is still
  6553      * registered in an interpreter.
  6554      */
  6555 
  6556     if (CheckForDeadChannel(NULL, statePtr)) {
  6557 	return TCL_ERROR;
  6558     }
  6559 
  6560     /*
  6561      * This operation should occur at the top of a channel stack.
  6562      */
  6563 
  6564     chanPtr = statePtr->topChanPtr;
  6565 
  6566     len = strlen(optionName);
  6567 
  6568     if ((len > 2) && (optionName[1] == 'b') &&
  6569             (strncmp(optionName, "-blocking", len) == 0)) {
  6570 	int newMode;
  6571         if (Tcl_GetBoolean(interp, newValue, &newMode) == TCL_ERROR) {
  6572             return TCL_ERROR;
  6573         }
  6574         if (newMode) {
  6575             newMode = TCL_MODE_BLOCKING;
  6576         } else {
  6577             newMode = TCL_MODE_NONBLOCKING;
  6578         }
  6579 	return SetBlockMode(interp, chanPtr, newMode);
  6580     } else if ((len > 7) && (optionName[1] == 'b') &&
  6581             (strncmp(optionName, "-buffering", len) == 0)) {
  6582         len = strlen(newValue);
  6583         if ((newValue[0] == 'f') && (strncmp(newValue, "full", len) == 0)) {
  6584             statePtr->flags &=
  6585                 (~(CHANNEL_UNBUFFERED|CHANNEL_LINEBUFFERED));
  6586         } else if ((newValue[0] == 'l') &&
  6587                 (strncmp(newValue, "line", len) == 0)) {
  6588             statePtr->flags &= (~(CHANNEL_UNBUFFERED));
  6589             statePtr->flags |= CHANNEL_LINEBUFFERED;
  6590         } else if ((newValue[0] == 'n') &&
  6591                 (strncmp(newValue, "none", len) == 0)) {
  6592             statePtr->flags &= (~(CHANNEL_LINEBUFFERED));
  6593             statePtr->flags |= CHANNEL_UNBUFFERED;
  6594         } else {
  6595             if (interp) {
  6596                 Tcl_AppendResult(interp, "bad value for -buffering: ",
  6597                         "must be one of full, line, or none",
  6598                         (char *) NULL);
  6599                 return TCL_ERROR;
  6600             }
  6601         }
  6602 	return TCL_OK;
  6603     } else if ((len > 7) && (optionName[1] == 'b') &&
  6604             (strncmp(optionName, "-buffersize", len) == 0)) {
  6605 	int newBufferSize;
  6606 	if (Tcl_GetInt(interp, newValue, &newBufferSize) == TCL_ERROR) {
  6607 	    return TCL_ERROR;
  6608 	}
  6609 	Tcl_SetChannelBufferSize(chan, newBufferSize);
  6610     } else if ((len > 2) && (optionName[1] == 'e') &&
  6611 	    (strncmp(optionName, "-encoding", len) == 0)) {
  6612 	Tcl_Encoding encoding;
  6613 
  6614 	if ((newValue[0] == '\0') || (strcmp(newValue, "binary") == 0)) {
  6615 	    encoding = NULL;
  6616 	} else {
  6617 	    encoding = Tcl_GetEncoding(interp, newValue);
  6618 	    if (encoding == NULL) {
  6619 		return TCL_ERROR;
  6620 	    }
  6621 	}
  6622 	/*
  6623 	 * When the channel has an escape sequence driven encoding such as
  6624 	 * iso2022, the terminated escape sequence must write to the buffer.
  6625 	 */
  6626 	if ((statePtr->encoding != NULL) && (statePtr->curOutPtr != NULL)
  6627 		&& (CheckChannelErrors(statePtr, TCL_WRITABLE) == 0)) {
  6628 	    statePtr->outputEncodingFlags |= TCL_ENCODING_END;
  6629 	    WriteChars(chanPtr, "", 0);
  6630 	}
  6631 	Tcl_FreeEncoding(statePtr->encoding);
  6632 	statePtr->encoding = encoding;
  6633 	statePtr->inputEncodingState = NULL;
  6634 	statePtr->inputEncodingFlags = TCL_ENCODING_START;
  6635 	statePtr->outputEncodingState = NULL;
  6636 	statePtr->outputEncodingFlags = TCL_ENCODING_START;
  6637 	statePtr->flags &= ~CHANNEL_NEED_MORE_DATA;
  6638 	UpdateInterest(chanPtr);
  6639     } else if ((len > 2) && (optionName[1] == 'e') &&
  6640             (strncmp(optionName, "-eofchar", len) == 0)) {
  6641         if (Tcl_SplitList(interp, newValue, &argc, &argv) == TCL_ERROR) {
  6642             return TCL_ERROR;
  6643         }
  6644         if (argc == 0) {
  6645             statePtr->inEofChar = 0;
  6646             statePtr->outEofChar = 0;
  6647         } else if (argc == 1) {
  6648             if (statePtr->flags & TCL_WRITABLE) {
  6649                 statePtr->outEofChar = (int) argv[0][0];
  6650             }
  6651             if (statePtr->flags & TCL_READABLE) {
  6652                 statePtr->inEofChar = (int) argv[0][0];
  6653             }
  6654         } else if (argc != 2) {
  6655             if (interp) {
  6656                 Tcl_AppendResult(interp,
  6657                         "bad value for -eofchar: should be a list of zero,",
  6658                         " one, or two elements", (char *) NULL);
  6659             }
  6660             ckfree((char *) argv);
  6661             return TCL_ERROR;
  6662         } else {
  6663             if (statePtr->flags & TCL_READABLE) {
  6664                 statePtr->inEofChar = (int) argv[0][0];
  6665             }
  6666             if (statePtr->flags & TCL_WRITABLE) {
  6667                 statePtr->outEofChar = (int) argv[1][0];
  6668             }
  6669         }
  6670         if (argv != NULL) {
  6671             ckfree((char *) argv);
  6672         }
  6673 
  6674 	/*
  6675 	 * [SF Tcl Bug 930851] Reset EOF and BLOCKED flags. Changing
  6676 	 * the character which signals eof can transform a current eof
  6677 	 * condition into a 'go ahead'. Ditto for blocked.
  6678 	 */
  6679 
  6680 	statePtr->flags &= (~(CHANNEL_EOF | CHANNEL_STICKY_EOF | CHANNEL_BLOCKED));
  6681 
  6682 	return TCL_OK;
  6683     } else if ((len > 1) && (optionName[1] == 't') &&
  6684             (strncmp(optionName, "-translation", len) == 0)) {
  6685 	CONST char *readMode, *writeMode;
  6686 
  6687         if (Tcl_SplitList(interp, newValue, &argc, &argv) == TCL_ERROR) {
  6688             return TCL_ERROR;
  6689         }
  6690 
  6691         if (argc == 1) {
  6692 	    readMode = (statePtr->flags & TCL_READABLE) ? argv[0] : NULL;
  6693 	    writeMode = (statePtr->flags & TCL_WRITABLE) ? argv[0] : NULL;
  6694 	} else if (argc == 2) {
  6695 	    readMode = (statePtr->flags & TCL_READABLE) ? argv[0] : NULL;
  6696 	    writeMode = (statePtr->flags & TCL_WRITABLE) ? argv[1] : NULL;
  6697 	} else {
  6698             if (interp) {
  6699                 Tcl_AppendResult(interp,
  6700                         "bad value for -translation: must be a one or two",
  6701                         " element list", (char *) NULL);
  6702             }
  6703             ckfree((char *) argv);
  6704             return TCL_ERROR;
  6705 	}
  6706 
  6707 	if (readMode) {
  6708 	    TclEolTranslation translation;
  6709 	    if (*readMode == '\0') {
  6710 		translation = statePtr->inputTranslation;
  6711 	    } else if (strcmp(readMode, "auto") == 0) {
  6712 		translation = TCL_TRANSLATE_AUTO;
  6713 	    } else if (strcmp(readMode, "binary") == 0) {
  6714 		translation = TCL_TRANSLATE_LF;
  6715 		statePtr->inEofChar = 0;
  6716 		Tcl_FreeEncoding(statePtr->encoding);		    
  6717 		statePtr->encoding = NULL;
  6718 	    } else if (strcmp(readMode, "lf") == 0) {
  6719 		translation = TCL_TRANSLATE_LF;
  6720 	    } else if (strcmp(readMode, "cr") == 0) {
  6721 		translation = TCL_TRANSLATE_CR;
  6722 	    } else if (strcmp(readMode, "crlf") == 0) {
  6723 		translation = TCL_TRANSLATE_CRLF;
  6724 	    } else if (strcmp(readMode, "platform") == 0) {
  6725 		translation = TCL_PLATFORM_TRANSLATION;
  6726 	    } else {
  6727 		if (interp) {
  6728 		    Tcl_AppendResult(interp,
  6729 			    "bad value for -translation: ",
  6730 			    "must be one of auto, binary, cr, lf, crlf,",
  6731 			    " or platform", (char *) NULL);
  6732 		}
  6733 		ckfree((char *) argv);
  6734 		return TCL_ERROR;
  6735 	    }
  6736 
  6737 	    /*
  6738 	     * Reset the EOL flags since we need to look at any buffered
  6739 	     * data to see if the new translation mode allows us to
  6740 	     * complete the line.
  6741 	     */
  6742 
  6743 	    if (translation != statePtr->inputTranslation) {
  6744 		statePtr->inputTranslation = translation;
  6745 		statePtr->flags &= ~(INPUT_SAW_CR);
  6746 		statePtr->flags &= ~(CHANNEL_NEED_MORE_DATA);
  6747 		UpdateInterest(chanPtr);
  6748 	    }
  6749 	}
  6750 	if (writeMode) {
  6751 	    if (*writeMode == '\0') {
  6752 		/* Do nothing. */
  6753 	    } else if (strcmp(writeMode, "auto") == 0) {
  6754 		/*
  6755 		 * This is a hack to get TCP sockets to produce output
  6756 		 * in CRLF mode if they are being set into AUTO mode.
  6757 		 * A better solution for achieving this effect will be
  6758 		 * coded later.
  6759 		 */
  6760 
  6761 		if (strcmp(Tcl_ChannelName(chanPtr->typePtr), "tcp") == 0) {
  6762 		    statePtr->outputTranslation = TCL_TRANSLATE_CRLF;
  6763 		} else {
  6764 		    statePtr->outputTranslation = TCL_PLATFORM_TRANSLATION;
  6765 		}
  6766 	    } else if (strcmp(writeMode, "binary") == 0) {
  6767 		statePtr->outEofChar = 0;
  6768 		statePtr->outputTranslation = TCL_TRANSLATE_LF;
  6769 		Tcl_FreeEncoding(statePtr->encoding);		    
  6770 		statePtr->encoding = NULL;
  6771 	    } else if (strcmp(writeMode, "lf") == 0) {
  6772 		statePtr->outputTranslation = TCL_TRANSLATE_LF;
  6773 	    } else if (strcmp(writeMode, "cr") == 0) {
  6774 		statePtr->outputTranslation = TCL_TRANSLATE_CR;
  6775 	    } else if (strcmp(writeMode, "crlf") == 0) {
  6776 		statePtr->outputTranslation = TCL_TRANSLATE_CRLF;
  6777 	    } else if (strcmp(writeMode, "platform") == 0) {
  6778 		statePtr->outputTranslation = TCL_PLATFORM_TRANSLATION;
  6779 	    } else {
  6780 		if (interp) {
  6781 		    Tcl_AppendResult(interp,
  6782 			    "bad value for -translation: ",
  6783 			    "must be one of auto, binary, cr, lf, crlf,",
  6784 			    " or platform", (char *) NULL);
  6785 		}
  6786 		ckfree((char *) argv);
  6787 		return TCL_ERROR;
  6788 	    }
  6789 	}
  6790         ckfree((char *) argv);            
  6791         return TCL_OK;
  6792     } else if (chanPtr->typePtr->setOptionProc != NULL) {
  6793         return (*chanPtr->typePtr->setOptionProc)(chanPtr->instanceData,
  6794                 interp, optionName, newValue);
  6795     } else {
  6796 	return Tcl_BadChannelOption(interp, optionName, (char *) NULL);
  6797     }
  6798 
  6799     /*
  6800      * If bufsize changes, need to get rid of old utility buffer.
  6801      */
  6802 
  6803     if (statePtr->saveInBufPtr != NULL) {
  6804 	RecycleBuffer(statePtr, statePtr->saveInBufPtr, 1);
  6805 	statePtr->saveInBufPtr = NULL;
  6806     }
  6807     if (statePtr->inQueueHead != NULL) {
  6808 	if ((statePtr->inQueueHead->nextPtr == NULL)
  6809 		&& (statePtr->inQueueHead->nextAdded ==
  6810 			statePtr->inQueueHead->nextRemoved)) {
  6811 	    RecycleBuffer(statePtr, statePtr->inQueueHead, 1);
  6812 	    statePtr->inQueueHead = NULL;
  6813 	    statePtr->inQueueTail = NULL;
  6814 	}
  6815     }
  6816 
  6817     /*
  6818      * If encoding or bufsize changes, need to update output staging buffer.
  6819      */
  6820 
  6821     if (statePtr->outputStage != NULL) {
  6822 	ckfree((char *) statePtr->outputStage);
  6823 	statePtr->outputStage = NULL;
  6824     }
  6825     if ((statePtr->encoding != NULL) && (statePtr->flags & TCL_WRITABLE)) {
  6826 	statePtr->outputStage = (char *) 
  6827 	    ckalloc((unsigned) (statePtr->bufSize + 2));
  6828     }
  6829     return TCL_OK;
  6830 }
  6831 
  6832 /*
  6833  *----------------------------------------------------------------------
  6834  *
  6835  * CleanupChannelHandlers --
  6836  *
  6837  *	Removes channel handlers that refer to the supplied interpreter,
  6838  *	so that if the actual channel is not closed now, these handlers
  6839  *	will not run on subsequent events on the channel. This would be
  6840  *	erroneous, because the interpreter no longer has a reference to
  6841  *	this channel.
  6842  *
  6843  * Results:
  6844  *	None.
  6845  *
  6846  * Side effects:
  6847  *	Removes channel handlers.
  6848  *
  6849  *----------------------------------------------------------------------
  6850  */
  6851 
  6852 static void
  6853 CleanupChannelHandlers(interp, chanPtr)
  6854     Tcl_Interp *interp;
  6855     Channel *chanPtr;
  6856 {
  6857     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  6858     EventScriptRecord *sPtr, *prevPtr, *nextPtr;
  6859 
  6860     /*
  6861      * Remove fileevent records on this channel that refer to the
  6862      * given interpreter.
  6863      */
  6864     
  6865     for (sPtr = statePtr->scriptRecordPtr,
  6866              prevPtr = (EventScriptRecord *) NULL;
  6867 	 sPtr != (EventScriptRecord *) NULL;
  6868 	 sPtr = nextPtr) {
  6869         nextPtr = sPtr->nextPtr;
  6870         if (sPtr->interp == interp) {
  6871             if (prevPtr == (EventScriptRecord *) NULL) {
  6872                 statePtr->scriptRecordPtr = nextPtr;
  6873             } else {
  6874                 prevPtr->nextPtr = nextPtr;
  6875             }
  6876 
  6877             Tcl_DeleteChannelHandler((Tcl_Channel) chanPtr,
  6878                     TclChannelEventScriptInvoker, (ClientData) sPtr);
  6879 
  6880 	    Tcl_DecrRefCount(sPtr->scriptPtr);
  6881             ckfree((char *) sPtr);
  6882         } else {
  6883             prevPtr = sPtr;
  6884         }
  6885     }
  6886 }
  6887 
  6888 /*
  6889  *----------------------------------------------------------------------
  6890  *
  6891  * Tcl_NotifyChannel --
  6892  *
  6893  *	This procedure is called by a channel driver when a driver
  6894  *	detects an event on a channel.  This procedure is responsible
  6895  *	for actually handling the event by invoking any channel
  6896  *	handler callbacks.
  6897  *
  6898  * Results:
  6899  *	None.
  6900  *
  6901  * Side effects:
  6902  *	Whatever the channel handler callback procedure does.
  6903  *
  6904  *----------------------------------------------------------------------
  6905  */
  6906 
  6907 EXPORT_C void
  6908 Tcl_NotifyChannel(channel, mask)
  6909     Tcl_Channel channel;	/* Channel that detected an event. */
  6910     int mask;			/* OR'ed combination of TCL_READABLE,
  6911 				 * TCL_WRITABLE, or TCL_EXCEPTION: indicates
  6912 				 * which events were detected. */
  6913 {
  6914     Channel *chanPtr = (Channel *) channel;
  6915     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  6916     ChannelHandler *chPtr;
  6917     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
  6918     NextChannelHandler nh;
  6919     Channel* upChanPtr;
  6920     Tcl_ChannelType* upTypePtr;
  6921 
  6922 #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING
  6923     /* [SF Tcl Bug 943274]
  6924      * For a non-blocking channel without blockmodeproc we keep track
  6925      * of actual input coming from the OS so that we can do a credible
  6926      * imitation of non-blocking behaviour.
  6927      */
  6928 
  6929     if ((mask & TCL_READABLE) &&
  6930 	(statePtr->flags & CHANNEL_NONBLOCKING) &&
  6931 	(Tcl_ChannelBlockModeProc(chanPtr->typePtr) == NULL) &&
  6932 	!(statePtr->flags & CHANNEL_TIMER_FEV)) {
  6933 
  6934         statePtr->flags |= CHANNEL_HAS_MORE_DATA;
  6935     }
  6936 #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */
  6937 
  6938     /*
  6939      * In contrast to the other API functions this procedure walks towards
  6940      * the top of a stack and not down from it.
  6941      *
  6942      * The channel calling this procedure is the one who generated the event,
  6943      * and thus does not take part in handling it. IOW, its HandlerProc is
  6944      * not called, instead we begin with the channel above it.
  6945      *
  6946      * This behaviour also allows the transformation channels to
  6947      * generate their own events and pass them upward.
  6948      */
  6949 
  6950     while (mask && (chanPtr->upChanPtr != ((Channel*) NULL))) {
  6951 	Tcl_DriverHandlerProc* upHandlerProc;
  6952 
  6953         upChanPtr = chanPtr->upChanPtr;
  6954 	upTypePtr = upChanPtr->typePtr;
  6955 	upHandlerProc = Tcl_ChannelHandlerProc(upTypePtr);
  6956 	if (upHandlerProc != NULL) {
  6957 	    mask = (*upHandlerProc) (upChanPtr->instanceData, mask);
  6958 	}
  6959 
  6960 	/* ELSE:
  6961 	 * Ignore transformations which are unable to handle the event
  6962 	 * coming from below. Assume that they don't change the mask and
  6963 	 * pass it on.
  6964 	 */
  6965 
  6966 	chanPtr = upChanPtr;
  6967     }
  6968 
  6969     channel = (Tcl_Channel) chanPtr;
  6970 
  6971     /*
  6972      * Here we have either reached the top of the stack or the mask is
  6973      * empty.  We break out of the procedure if it is the latter.
  6974      */
  6975 
  6976     if (!mask) {
  6977         return;
  6978     }
  6979 
  6980     /*
  6981      * We are now above the topmost channel in a stack and have events
  6982      * left. Now call the channel handlers as usual.
  6983      *
  6984      * Preserve the channel struct in case the script closes it.
  6985      */
  6986      
  6987     Tcl_Preserve((ClientData) channel);
  6988     Tcl_Preserve((ClientData) statePtr);
  6989 
  6990     /*
  6991      * If we are flushing in the background, be sure to call FlushChannel
  6992      * for writable events.  Note that we have to discard the writable
  6993      * event so we don't call any write handlers before the flush is
  6994      * complete.
  6995      */
  6996 
  6997     if ((statePtr->flags & BG_FLUSH_SCHEDULED) && (mask & TCL_WRITABLE)) {
  6998 	FlushChannel(NULL, chanPtr, 1);
  6999 	mask &= ~TCL_WRITABLE;
  7000     }
  7001 
  7002     /*
  7003      * Add this invocation to the list of recursive invocations of
  7004      * ChannelHandlerEventProc.
  7005      */
  7006     
  7007     nh.nextHandlerPtr = (ChannelHandler *) NULL;
  7008     nh.nestedHandlerPtr = tsdPtr->nestedHandlerPtr;
  7009     tsdPtr->nestedHandlerPtr = &nh;
  7010 
  7011     for (chPtr = statePtr->chPtr; chPtr != (ChannelHandler *) NULL; ) {
  7012 	/*
  7013 	 * If this channel handler is interested in any of the events that
  7014 	 * have occurred on the channel, invoke its procedure.
  7015 	 */
  7016 
  7017 	if ((chPtr->mask & mask) != 0) {
  7018 	    nh.nextHandlerPtr = chPtr->nextPtr;
  7019 	    (*(chPtr->proc))(chPtr->clientData, mask);
  7020 	    chPtr = nh.nextHandlerPtr;
  7021 	} else {
  7022 	    chPtr = chPtr->nextPtr;
  7023 	}
  7024     }
  7025 
  7026     /*
  7027      * Update the notifier interest, since it may have changed after
  7028      * invoking event handlers. Skip that if the channel was deleted
  7029      * in the call to the channel handler.
  7030      */
  7031 
  7032     if (chanPtr->typePtr != NULL) {
  7033         UpdateInterest(chanPtr);
  7034     }
  7035 
  7036     Tcl_Release((ClientData) statePtr);
  7037     Tcl_Release((ClientData) channel);
  7038 
  7039     tsdPtr->nestedHandlerPtr = nh.nestedHandlerPtr;
  7040 }
  7041 
  7042 /*
  7043  *----------------------------------------------------------------------
  7044  *
  7045  * UpdateInterest --
  7046  *
  7047  *	Arrange for the notifier to call us back at appropriate times
  7048  *	based on the current state of the channel.
  7049  *
  7050  * Results:
  7051  *	None.
  7052  *
  7053  * Side effects:
  7054  *	May schedule a timer or driver handler.
  7055  *
  7056  *----------------------------------------------------------------------
  7057  */
  7058 
  7059 static void
  7060 UpdateInterest(chanPtr)
  7061     Channel *chanPtr;		/* Channel to update. */
  7062 {
  7063     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  7064     int mask = statePtr->interestMask;
  7065 
  7066     /*
  7067      * If there are flushed buffers waiting to be written, then
  7068      * we need to watch for the channel to become writable.
  7069      */
  7070 
  7071     if (statePtr->flags & BG_FLUSH_SCHEDULED) {
  7072 	mask |= TCL_WRITABLE;
  7073     }
  7074 
  7075     /*
  7076      * If there is data in the input queue, and we aren't waiting for more
  7077      * data, then we need to schedule a timer so we don't block in the
  7078      * notifier.  Also, cancel the read interest so we don't get duplicate
  7079      * events.
  7080      */
  7081 
  7082     if (mask & TCL_READABLE) {
  7083 	if (!(statePtr->flags & CHANNEL_NEED_MORE_DATA)
  7084 		&& (statePtr->inQueueHead != (ChannelBuffer *) NULL)
  7085 		&& (statePtr->inQueueHead->nextRemoved <
  7086 			statePtr->inQueueHead->nextAdded)) {
  7087 	    mask &= ~TCL_READABLE;
  7088 
  7089 	    /*
  7090 	     * Andreas Kupries, April 11, 2003
  7091 	     *
  7092 	     * Some operating systems (Solaris 2.6 and higher (but not
  7093 	     * Solaris 2.5, go figure)) generate READABLE and
  7094 	     * EXCEPTION events when select()'ing [*] on a plain file,
  7095 	     * even if EOF was not yet reached. This is a problem in
  7096 	     * the following situation:
  7097 	     *
  7098 	     * - An extension asks to get both READABLE and EXCEPTION
  7099 	     *   events.
  7100 	     * - It reads data into a buffer smaller than the buffer
  7101 	     *   used by Tcl itself.
  7102 	     * - It does not process all events in the event queue, but
  7103 	     *   only only one, at least in some situations.
  7104 	     *
  7105 	     * In that case we can get into a situation where
  7106 	     *
  7107 	     * - Tcl drops READABLE here, because it has data in its own
  7108 	     *   buffers waiting to be read by the extension.
  7109 	     * - A READABLE event is syntesized via timer.
  7110 	     * - The OS still reports the EXCEPTION condition on the file.
  7111 	     * - And the extension gets the EXCPTION event first, and
  7112 	     *   handles this as EOF.
  7113 	     *
  7114 	     * End result ==> Premature end of reading from a file.
  7115 	     *
  7116 	     * The concrete example is 'Expect', and its [expect]
  7117 	     * command (and at the C-level, deep in the bowels of
  7118 	     * Expect, 'exp_get_next_event'. See marker 'SunOS' for
  7119 	     * commentary in that function too).
  7120 	     *
  7121 	     * [*] As the Tcl notifier does. See also for marker
  7122 	     * 'SunOS' in file 'exp_event.c' of Expect.
  7123 	     *
  7124 	     * Our solution here is to drop the interest in the
  7125 	     * EXCEPTION events too. This compiles on all platforms,
  7126 	     * and also passes the testsuite on all of them.
  7127 	     */
  7128 
  7129 	    mask &= ~TCL_EXCEPTION;
  7130 
  7131 	    if (!statePtr->timer) {
  7132 		statePtr->timer = Tcl_CreateTimerHandler(0, ChannelTimerProc,
  7133 			(ClientData) chanPtr);
  7134 	    }
  7135 	}
  7136     }
  7137     (chanPtr->typePtr->watchProc)(chanPtr->instanceData, mask);
  7138 }
  7139 
  7140 /*
  7141  *----------------------------------------------------------------------
  7142  *
  7143  * ChannelTimerProc --
  7144  *
  7145  *	Timer handler scheduled by UpdateInterest to monitor the
  7146  *	channel buffers until they are empty.
  7147  *
  7148  * Results:
  7149  *	None.
  7150  *
  7151  * Side effects:
  7152  *	May invoke channel handlers.
  7153  *
  7154  *----------------------------------------------------------------------
  7155  */
  7156 
  7157 static void
  7158 ChannelTimerProc(clientData)
  7159     ClientData clientData;
  7160 {
  7161     Channel *chanPtr = (Channel *) clientData;
  7162     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  7163 
  7164     if (!(statePtr->flags & CHANNEL_NEED_MORE_DATA)
  7165 	    && (statePtr->interestMask & TCL_READABLE)
  7166 	    && (statePtr->inQueueHead != (ChannelBuffer *) NULL)
  7167 	    && (statePtr->inQueueHead->nextRemoved <
  7168 		    statePtr->inQueueHead->nextAdded)) {
  7169 	/*
  7170 	 * Restart the timer in case a channel handler reenters the
  7171 	 * event loop before UpdateInterest gets called by Tcl_NotifyChannel.
  7172 	 */
  7173 
  7174 	statePtr->timer = Tcl_CreateTimerHandler(0, ChannelTimerProc,
  7175 		(ClientData) chanPtr);
  7176 
  7177 #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING
  7178 	/* Set the TIMER flag to notify the higher levels that the
  7179 	 * driver might have no data for us. We do this only if we are
  7180 	 * in non-blocking mode and the driver has no BlockModeProc
  7181 	 * because only then we really don't know if the driver will
  7182 	 * block or not. A similar test is done in "PeekAhead".
  7183 	 */
  7184 
  7185 	if ((statePtr->flags & CHANNEL_NONBLOCKING) &&
  7186 	    (Tcl_ChannelBlockModeProc(chanPtr->typePtr) == NULL)) {
  7187 	    statePtr->flags |= CHANNEL_TIMER_FEV;
  7188 	}
  7189 #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */
  7190 
  7191 	Tcl_Preserve((ClientData) statePtr);
  7192 	Tcl_NotifyChannel((Tcl_Channel)chanPtr, TCL_READABLE);
  7193 
  7194 #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING
  7195 	statePtr->flags &= ~CHANNEL_TIMER_FEV; 
  7196 #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */
  7197 
  7198 	Tcl_Release((ClientData) statePtr);
  7199     } else {
  7200 	statePtr->timer = NULL;
  7201 	UpdateInterest(chanPtr);
  7202     }
  7203 }
  7204 
  7205 /*
  7206  *----------------------------------------------------------------------
  7207  *
  7208  * Tcl_CreateChannelHandler --
  7209  *
  7210  *	Arrange for a given procedure to be invoked whenever the
  7211  *	channel indicated by the chanPtr arg becomes readable or
  7212  *	writable.
  7213  *
  7214  * Results:
  7215  *	None.
  7216  *
  7217  * Side effects:
  7218  *	From now on, whenever the I/O channel given by chanPtr becomes
  7219  *	ready in the way indicated by mask, proc will be invoked.
  7220  *	See the manual entry for details on the calling sequence
  7221  *	to proc.  If there is already an event handler for chan, proc
  7222  *	and clientData, then the mask will be updated.
  7223  *
  7224  *----------------------------------------------------------------------
  7225  */
  7226 
  7227 EXPORT_C void
  7228 Tcl_CreateChannelHandler(chan, mask, proc, clientData)
  7229     Tcl_Channel chan;		/* The channel to create the handler for. */
  7230     int mask;			/* OR'ed combination of TCL_READABLE,
  7231 				 * TCL_WRITABLE, and TCL_EXCEPTION:
  7232 				 * indicates conditions under which
  7233 				 * proc should be called. Use 0 to
  7234                                  * disable a registered handler. */
  7235     Tcl_ChannelProc *proc;	/* Procedure to call for each
  7236 				 * selected event. */
  7237     ClientData clientData;	/* Arbitrary data to pass to proc. */
  7238 {
  7239     ChannelHandler *chPtr;
  7240     Channel *chanPtr = (Channel *) chan;
  7241     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  7242 
  7243     /*
  7244      * Check whether this channel handler is not already registered. If
  7245      * it is not, create a new record, else reuse existing record (smash
  7246      * current values).
  7247      */
  7248 
  7249     for (chPtr = statePtr->chPtr;
  7250 	 chPtr != (ChannelHandler *) NULL;
  7251 	 chPtr = chPtr->nextPtr) {
  7252         if ((chPtr->chanPtr == chanPtr) && (chPtr->proc == proc) &&
  7253                 (chPtr->clientData == clientData)) {
  7254             break;
  7255         }
  7256     }
  7257     if (chPtr == (ChannelHandler *) NULL) {
  7258         chPtr = (ChannelHandler *) ckalloc((unsigned) sizeof(ChannelHandler));
  7259         chPtr->mask = 0;
  7260         chPtr->proc = proc;
  7261         chPtr->clientData = clientData;
  7262         chPtr->chanPtr = chanPtr;
  7263         chPtr->nextPtr = statePtr->chPtr;
  7264         statePtr->chPtr = chPtr;
  7265     }
  7266 
  7267     /*
  7268      * The remainder of the initialization below is done regardless of
  7269      * whether or not this is a new record or a modification of an old
  7270      * one.
  7271      */
  7272 
  7273     chPtr->mask = mask;
  7274 
  7275     /*
  7276      * Recompute the interest mask for the channel - this call may actually
  7277      * be disabling an existing handler.
  7278      */
  7279     
  7280     statePtr->interestMask = 0;
  7281     for (chPtr = statePtr->chPtr;
  7282 	 chPtr != (ChannelHandler *) NULL;
  7283 	 chPtr = chPtr->nextPtr) {
  7284 	statePtr->interestMask |= chPtr->mask;
  7285     }
  7286 
  7287     UpdateInterest(statePtr->topChanPtr);
  7288 }
  7289 
  7290 /*
  7291  *----------------------------------------------------------------------
  7292  *
  7293  * Tcl_DeleteChannelHandler --
  7294  *
  7295  *	Cancel a previously arranged callback arrangement for an IO
  7296  *	channel.
  7297  *
  7298  * Results:
  7299  *	None.
  7300  *
  7301  * Side effects:
  7302  *	If a callback was previously registered for this chan, proc and
  7303  *	 clientData , it is removed and the callback will no longer be called
  7304  *	when the channel becomes ready for IO.
  7305  *
  7306  *----------------------------------------------------------------------
  7307  */
  7308 
  7309 EXPORT_C void
  7310 Tcl_DeleteChannelHandler(chan, proc, clientData)
  7311     Tcl_Channel chan;		/* The channel for which to remove the
  7312                                  * callback. */
  7313     Tcl_ChannelProc *proc;	/* The procedure in the callback to delete. */
  7314     ClientData clientData;	/* The client data in the callback
  7315                                  * to delete. */
  7316     
  7317 {
  7318     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
  7319     ChannelHandler *chPtr, *prevChPtr;
  7320     Channel *chanPtr = (Channel *) chan;
  7321     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  7322     NextChannelHandler *nhPtr;
  7323 
  7324     /*
  7325      * Find the entry and the previous one in the list.
  7326      */
  7327 
  7328     for (prevChPtr = (ChannelHandler *) NULL, chPtr = statePtr->chPtr;
  7329 	 chPtr != (ChannelHandler *) NULL;
  7330 	 chPtr = chPtr->nextPtr) {
  7331         if ((chPtr->chanPtr == chanPtr) && (chPtr->clientData == clientData)
  7332                 && (chPtr->proc == proc)) {
  7333             break;
  7334         }
  7335         prevChPtr = chPtr;
  7336     }
  7337 
  7338     /*
  7339      * If not found, return without doing anything.
  7340      */
  7341 
  7342     if (chPtr == (ChannelHandler *) NULL) {
  7343         return;
  7344     }
  7345 
  7346     /*
  7347      * If ChannelHandlerEventProc is about to process this handler, tell it to
  7348      * process the next one instead - we are going to delete *this* one.
  7349      */
  7350 
  7351     for (nhPtr = tsdPtr->nestedHandlerPtr;
  7352 	 nhPtr != (NextChannelHandler *) NULL;
  7353 	 nhPtr = nhPtr->nestedHandlerPtr) {
  7354         if (nhPtr->nextHandlerPtr == chPtr) {
  7355             nhPtr->nextHandlerPtr = chPtr->nextPtr;
  7356         }
  7357     }
  7358 
  7359     /*
  7360      * Splice it out of the list of channel handlers.
  7361      */
  7362     
  7363     if (prevChPtr == (ChannelHandler *) NULL) {
  7364         statePtr->chPtr = chPtr->nextPtr;
  7365     } else {
  7366         prevChPtr->nextPtr = chPtr->nextPtr;
  7367     }
  7368     ckfree((char *) chPtr);
  7369 
  7370     /*
  7371      * Recompute the interest list for the channel, so that infinite loops
  7372      * will not result if Tcl_DeleteChannelHandler is called inside an
  7373      * event.
  7374      */
  7375 
  7376     statePtr->interestMask = 0;
  7377     for (chPtr = statePtr->chPtr;
  7378 	 chPtr != (ChannelHandler *) NULL;
  7379 	 chPtr = chPtr->nextPtr) {
  7380         statePtr->interestMask |= chPtr->mask;
  7381     }
  7382 
  7383     UpdateInterest(statePtr->topChanPtr);
  7384 }
  7385 
  7386 /*
  7387  *----------------------------------------------------------------------
  7388  *
  7389  * DeleteScriptRecord --
  7390  *
  7391  *	Delete a script record for this combination of channel, interp
  7392  *	and mask.
  7393  *
  7394  * Results:
  7395  *	None.
  7396  *
  7397  * Side effects:
  7398  *	Deletes a script record and cancels a channel event handler.
  7399  *
  7400  *----------------------------------------------------------------------
  7401  */
  7402 
  7403 static void
  7404 DeleteScriptRecord(interp, chanPtr, mask)
  7405     Tcl_Interp *interp;		/* Interpreter in which script was to be
  7406                                  * executed. */
  7407     Channel *chanPtr;		/* The channel for which to delete the
  7408                                  * script record (if any). */
  7409     int mask;			/* Events in mask must exactly match mask
  7410                                  * of script to delete. */
  7411 {
  7412     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  7413     EventScriptRecord *esPtr, *prevEsPtr;
  7414 
  7415     for (esPtr = statePtr->scriptRecordPtr,
  7416              prevEsPtr = (EventScriptRecord *) NULL;
  7417 	 esPtr != (EventScriptRecord *) NULL;
  7418 	 prevEsPtr = esPtr, esPtr = esPtr->nextPtr) {
  7419         if ((esPtr->interp == interp) && (esPtr->mask == mask)) {
  7420             if (esPtr == statePtr->scriptRecordPtr) {
  7421                 statePtr->scriptRecordPtr = esPtr->nextPtr;
  7422             } else {
  7423                 prevEsPtr->nextPtr = esPtr->nextPtr;
  7424             }
  7425 
  7426             Tcl_DeleteChannelHandler((Tcl_Channel) chanPtr,
  7427                     TclChannelEventScriptInvoker, (ClientData) esPtr);
  7428             
  7429 	    Tcl_DecrRefCount(esPtr->scriptPtr);
  7430             ckfree((char *) esPtr);
  7431 
  7432             break;
  7433         }
  7434     }
  7435 }
  7436 
  7437 /*
  7438  *----------------------------------------------------------------------
  7439  *
  7440  * CreateScriptRecord --
  7441  *
  7442  *	Creates a record to store a script to be executed when a specific
  7443  *	event fires on a specific channel.
  7444  *
  7445  * Results:
  7446  *	None.
  7447  *
  7448  * Side effects:
  7449  *	Causes the script to be stored for later execution.
  7450  *
  7451  *----------------------------------------------------------------------
  7452  */
  7453 
  7454 static void
  7455 CreateScriptRecord(interp, chanPtr, mask, scriptPtr)
  7456     Tcl_Interp *interp;			/* Interpreter in which to execute
  7457                                          * the stored script. */
  7458     Channel *chanPtr;			/* Channel for which script is to
  7459                                          * be stored. */
  7460     int mask;				/* Set of events for which script
  7461                                          * will be invoked. */
  7462     Tcl_Obj *scriptPtr;			/* Pointer to script object. */
  7463 {
  7464     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  7465     EventScriptRecord *esPtr;
  7466 
  7467     for (esPtr = statePtr->scriptRecordPtr;
  7468 	 esPtr != (EventScriptRecord *) NULL;
  7469 	 esPtr = esPtr->nextPtr) {
  7470         if ((esPtr->interp == interp) && (esPtr->mask == mask)) {
  7471 	    Tcl_DecrRefCount(esPtr->scriptPtr);
  7472 	    esPtr->scriptPtr = (Tcl_Obj *) NULL;
  7473             break;
  7474         }
  7475     }
  7476     if (esPtr == (EventScriptRecord *) NULL) {
  7477         esPtr = (EventScriptRecord *) ckalloc((unsigned)
  7478                 sizeof(EventScriptRecord));
  7479         Tcl_CreateChannelHandler((Tcl_Channel) chanPtr, mask,
  7480                 TclChannelEventScriptInvoker, (ClientData) esPtr);
  7481         esPtr->nextPtr = statePtr->scriptRecordPtr;
  7482         statePtr->scriptRecordPtr = esPtr;
  7483     }
  7484     esPtr->chanPtr = chanPtr;
  7485     esPtr->interp = interp;
  7486     esPtr->mask = mask;
  7487     Tcl_IncrRefCount(scriptPtr);
  7488     esPtr->scriptPtr = scriptPtr;
  7489 }
  7490 
  7491 /*
  7492  *----------------------------------------------------------------------
  7493  *
  7494  * TclChannelEventScriptInvoker --
  7495  *
  7496  *	Invokes a script scheduled by "fileevent" for when the channel
  7497  *	becomes ready for IO. This function is invoked by the channel
  7498  *	handler which was created by the Tcl "fileevent" command.
  7499  *
  7500  * Results:
  7501  *	None.
  7502  *
  7503  * Side effects:
  7504  *	Whatever the script does.
  7505  *
  7506  *----------------------------------------------------------------------
  7507  */
  7508 
  7509 void
  7510 TclChannelEventScriptInvoker(clientData, mask)
  7511     ClientData clientData;	/* The script+interp record. */
  7512     int mask;			/* Not used. */
  7513 {
  7514     Tcl_Interp *interp;		/* Interpreter in which to eval the script. */
  7515     Channel *chanPtr;		/* The channel for which this handler is
  7516                                  * registered. */
  7517     EventScriptRecord *esPtr;	/* The event script + interpreter to eval it
  7518                                  * in. */
  7519     int result;			/* Result of call to eval script. */
  7520 
  7521     esPtr	= (EventScriptRecord *) clientData;
  7522     chanPtr	= esPtr->chanPtr;
  7523     mask	= esPtr->mask;
  7524     interp	= esPtr->interp;
  7525 
  7526     /*
  7527      * We must preserve the interpreter so we can report errors on it
  7528      * later.  Note that we do not need to preserve the channel because
  7529      * that is done by Tcl_NotifyChannel before calling channel handlers.
  7530      */
  7531     
  7532     Tcl_Preserve((ClientData) interp);
  7533     result = Tcl_EvalObjEx(interp, esPtr->scriptPtr, TCL_EVAL_GLOBAL);
  7534 
  7535     /*
  7536      * On error, cause a background error and remove the channel handler
  7537      * and the script record.
  7538      *
  7539      * NOTE: Must delete channel handler before causing the background error
  7540      * because the background error may want to reinstall the handler.
  7541      */
  7542     
  7543     if (result != TCL_OK) {
  7544 	if (chanPtr->typePtr != NULL) {
  7545 	    DeleteScriptRecord(interp, chanPtr, mask);
  7546 	}
  7547         Tcl_BackgroundError(interp);
  7548     }
  7549     Tcl_Release((ClientData) interp);
  7550 }
  7551 
  7552 /*
  7553  *----------------------------------------------------------------------
  7554  *
  7555  * Tcl_FileEventObjCmd --
  7556  *
  7557  *	This procedure implements the "fileevent" Tcl command. See the
  7558  *	user documentation for details on what it does. This command is
  7559  *	based on the Tk command "fileevent" which in turn is based on work
  7560  *	contributed by Mark Diekhans.
  7561  *
  7562  * Results:
  7563  *	A standard Tcl result.
  7564  *
  7565  * Side effects:
  7566  *	May create a channel handler for the specified channel.
  7567  *
  7568  *----------------------------------------------------------------------
  7569  */
  7570 
  7571 	/* ARGSUSED */
  7572 int
  7573 Tcl_FileEventObjCmd(clientData, interp, objc, objv)
  7574     ClientData clientData;		/* Not used. */
  7575     Tcl_Interp *interp;			/* Interpreter in which the channel
  7576                                          * for which to create the handler
  7577                                          * is found. */
  7578     int objc;				/* Number of arguments. */
  7579     Tcl_Obj *CONST objv[];		/* Argument objects. */
  7580 {
  7581     Channel *chanPtr;			/* The channel to create
  7582                                          * the handler for. */
  7583     ChannelState *statePtr;		/* state info for channel */
  7584     Tcl_Channel chan;			/* The opaque type for the channel. */
  7585     char *chanName;
  7586     int modeIndex;			/* Index of mode argument. */
  7587     int mask;
  7588     static CONST char *modeOptions[] = {"readable", "writable", NULL};
  7589     static int maskArray[] = {TCL_READABLE, TCL_WRITABLE};
  7590 
  7591     if ((objc != 3) && (objc != 4)) {
  7592 	Tcl_WrongNumArgs(interp, 1, objv, "channelId event ?script?");
  7593 	return TCL_ERROR;
  7594     }
  7595     if (Tcl_GetIndexFromObj(interp, objv[2], modeOptions, "event name", 0,
  7596 	    &modeIndex) != TCL_OK) {
  7597 	return TCL_ERROR;
  7598     }
  7599     mask = maskArray[modeIndex];
  7600 
  7601     chanName = Tcl_GetString(objv[1]);
  7602     chan = Tcl_GetChannel(interp, chanName, NULL);
  7603     if (chan == (Tcl_Channel) NULL) {
  7604 	return TCL_ERROR;
  7605     }
  7606     chanPtr  = (Channel *) chan;
  7607     statePtr = chanPtr->state;
  7608     if ((statePtr->flags & mask) == 0) {
  7609         Tcl_AppendResult(interp, "channel is not ",
  7610                 (mask == TCL_READABLE) ? "readable" : "writable",
  7611                 (char *) NULL);
  7612         return TCL_ERROR;
  7613     }
  7614     
  7615     /*
  7616      * If we are supposed to return the script, do so.
  7617      */
  7618 
  7619     if (objc == 3) {
  7620 	EventScriptRecord *esPtr;
  7621 	for (esPtr = statePtr->scriptRecordPtr;
  7622              esPtr != (EventScriptRecord *) NULL;
  7623              esPtr = esPtr->nextPtr) {
  7624 	    if ((esPtr->interp == interp) && (esPtr->mask == mask)) {
  7625 		Tcl_SetObjResult(interp, esPtr->scriptPtr);
  7626 		break;
  7627 	    }
  7628 	}
  7629         return TCL_OK;
  7630     }
  7631 
  7632     /*
  7633      * If we are supposed to delete a stored script, do so.
  7634      */
  7635 
  7636     if (*(Tcl_GetString(objv[3])) == '\0') {
  7637         DeleteScriptRecord(interp, chanPtr, mask);
  7638         return TCL_OK;
  7639     }
  7640 
  7641     /*
  7642      * Make the script record that will link between the event and the
  7643      * script to invoke. This also creates a channel event handler which
  7644      * will evaluate the script in the supplied interpreter.
  7645      */
  7646 
  7647     CreateScriptRecord(interp, chanPtr, mask, objv[3]);
  7648     
  7649     return TCL_OK;
  7650 }
  7651 
  7652 /*
  7653  *----------------------------------------------------------------------
  7654  *
  7655  * TclCopyChannel --
  7656  *
  7657  *	This routine copies data from one channel to another, either
  7658  *	synchronously or asynchronously.  If a command script is
  7659  *	supplied, the operation runs in the background.  The script
  7660  *	is invoked when the copy completes.  Otherwise the function
  7661  *	waits until the copy is completed before returning.
  7662  *
  7663  * Results:
  7664  *	A standard Tcl result.
  7665  *
  7666  * Side effects:
  7667  *	May schedule a background copy operation that causes both
  7668  *	channels to be marked busy.
  7669  *
  7670  *----------------------------------------------------------------------
  7671  */
  7672 
  7673 int
  7674 TclCopyChannel(interp, inChan, outChan, toRead, cmdPtr)
  7675     Tcl_Interp *interp;		/* Current interpreter. */
  7676     Tcl_Channel inChan;		/* Channel to read from. */
  7677     Tcl_Channel outChan;	/* Channel to write to. */
  7678     int toRead;			/* Amount of data to copy, or -1 for all. */
  7679     Tcl_Obj *cmdPtr;		/* Pointer to script to execute or NULL. */
  7680 {
  7681     Channel *inPtr = (Channel *) inChan;
  7682     Channel *outPtr = (Channel *) outChan;
  7683     ChannelState *inStatePtr, *outStatePtr;
  7684     int readFlags, writeFlags;
  7685     CopyState *csPtr;
  7686     int nonBlocking = (cmdPtr) ? CHANNEL_NONBLOCKING : 0;
  7687 
  7688     inStatePtr	= inPtr->state;
  7689     outStatePtr	= outPtr->state;
  7690 
  7691     if (inStatePtr->csPtr) {
  7692 	if (interp) {
  7693 	    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "channel \"",
  7694 		    Tcl_GetChannelName(inChan), "\" is busy", NULL);
  7695 	}
  7696 	return TCL_ERROR;
  7697     }
  7698     if (outStatePtr->csPtr) {
  7699 	if (interp) {
  7700 	    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "channel \"",
  7701 		    Tcl_GetChannelName(outChan), "\" is busy", NULL);
  7702 	}
  7703 	return TCL_ERROR;
  7704     }
  7705 
  7706     readFlags	= inStatePtr->flags;
  7707     writeFlags	= outStatePtr->flags;
  7708 
  7709     /*
  7710      * Set up the blocking mode appropriately.  Background copies need
  7711      * non-blocking channels.  Foreground copies need blocking channels.
  7712      * If there is an error, restore the old blocking mode.
  7713      */
  7714 
  7715     if (nonBlocking != (readFlags & CHANNEL_NONBLOCKING)) {
  7716 	if (SetBlockMode(interp, inPtr,
  7717 		nonBlocking ? TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING)
  7718 		!= TCL_OK) {
  7719 	    return TCL_ERROR;
  7720 	}
  7721     }	    
  7722     if (inPtr != outPtr) {
  7723 	if (nonBlocking != (writeFlags & CHANNEL_NONBLOCKING)) {
  7724 	    if (SetBlockMode(NULL, outPtr,
  7725 		    nonBlocking ? TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING)
  7726 		    != TCL_OK) {
  7727 		if (nonBlocking != (readFlags & CHANNEL_NONBLOCKING)) {
  7728 		    SetBlockMode(NULL, inPtr,
  7729 			    (readFlags & CHANNEL_NONBLOCKING)
  7730 			    ? TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING);
  7731 		    return TCL_ERROR;
  7732 		}
  7733 	    }
  7734 	}
  7735     }
  7736 
  7737     /*
  7738      * Make sure the output side is unbuffered.
  7739      */
  7740 
  7741     outStatePtr->flags = (outStatePtr->flags & ~(CHANNEL_LINEBUFFERED))
  7742 	| CHANNEL_UNBUFFERED;
  7743 
  7744     /*
  7745      * Allocate a new CopyState to maintain info about the current copy in
  7746      * progress.  This structure will be deallocated when the copy is
  7747      * completed.
  7748      */
  7749 
  7750     csPtr = (CopyState*) ckalloc(sizeof(CopyState) + inStatePtr->bufSize);
  7751     csPtr->bufSize    = inStatePtr->bufSize;
  7752     csPtr->readPtr    = inPtr;
  7753     csPtr->writePtr   = outPtr;
  7754     csPtr->readFlags  = readFlags;
  7755     csPtr->writeFlags = writeFlags;
  7756     csPtr->toRead     = toRead;
  7757     csPtr->total      = 0;
  7758     csPtr->interp     = interp;
  7759     if (cmdPtr) {
  7760 	Tcl_IncrRefCount(cmdPtr);
  7761     }
  7762     csPtr->cmdPtr = cmdPtr;
  7763     inStatePtr->csPtr = csPtr;
  7764     outStatePtr->csPtr = csPtr;
  7765 
  7766     /*
  7767      * Start copying data between the channels.
  7768      */
  7769 
  7770     return CopyData(csPtr, 0);
  7771 }
  7772 
  7773 /*
  7774  *----------------------------------------------------------------------
  7775  *
  7776  * CopyData --
  7777  *
  7778  *	This function implements the lowest level of the copying
  7779  *	mechanism for TclCopyChannel.
  7780  *
  7781  * Results:
  7782  *	Returns TCL_OK on success, else TCL_ERROR.
  7783  *
  7784  * Side effects:
  7785  *	Moves data between channels, may create channel handlers.
  7786  *
  7787  *----------------------------------------------------------------------
  7788  */
  7789 
  7790 static int
  7791 CopyData(csPtr, mask)
  7792     CopyState *csPtr;		/* State of copy operation. */
  7793     int mask;			/* Current channel event flags. */
  7794 {
  7795     Tcl_Interp *interp;
  7796     Tcl_Obj *cmdPtr, *errObj = NULL, *bufObj = NULL;
  7797     Tcl_Channel inChan, outChan;
  7798     ChannelState *inStatePtr, *outStatePtr;
  7799     int result = TCL_OK, size, total, sizeb;
  7800     char* buffer;
  7801 
  7802     int inBinary, outBinary, sameEncoding; /* Encoding control */
  7803     int underflow;	/* input underflow */
  7804 
  7805     inChan	= (Tcl_Channel) csPtr->readPtr;
  7806     outChan	= (Tcl_Channel) csPtr->writePtr;
  7807     inStatePtr	= csPtr->readPtr->state;
  7808     outStatePtr	= csPtr->writePtr->state;
  7809     interp	= csPtr->interp;
  7810     cmdPtr	= csPtr->cmdPtr;
  7811 
  7812     /*
  7813      * Copy the data the slow way, using the translation mechanism.
  7814      *
  7815      * Note: We have make sure that we use the topmost channel in a stack
  7816      * for the copying. The caller uses Tcl_GetChannel to access it, and
  7817      * thus gets the bottom of the stack.
  7818      */
  7819 
  7820     inBinary     = (inStatePtr->encoding  == NULL);
  7821     outBinary    = (outStatePtr->encoding == NULL);
  7822     sameEncoding = (inStatePtr->encoding  == outStatePtr->encoding);
  7823 
  7824     if (!(inBinary || sameEncoding)) {
  7825         bufObj = Tcl_NewObj ();
  7826 	Tcl_IncrRefCount (bufObj);
  7827     }
  7828 
  7829     while (csPtr->toRead != 0) {
  7830 	/*
  7831 	 * Check for unreported background errors.
  7832 	 */
  7833 
  7834 	if (inStatePtr->unreportedError != 0) {
  7835 	    Tcl_SetErrno(inStatePtr->unreportedError);
  7836 	    inStatePtr->unreportedError = 0;
  7837 	    goto readError;
  7838 	}
  7839 	if (outStatePtr->unreportedError != 0) {
  7840 	    Tcl_SetErrno(outStatePtr->unreportedError);
  7841 	    outStatePtr->unreportedError = 0;
  7842 	    goto writeError;
  7843 	}
  7844 	
  7845 	/*
  7846 	 * Read up to bufSize bytes.
  7847 	 */
  7848 
  7849 	if ((csPtr->toRead == -1) || (csPtr->toRead > csPtr->bufSize)) {
  7850 	    sizeb = csPtr->bufSize;
  7851 	} else {
  7852 	    sizeb = csPtr->toRead;
  7853 	}
  7854 
  7855 	if (inBinary || sameEncoding) {
  7856 	    size = DoRead(inStatePtr->topChanPtr, csPtr->buffer, sizeb);
  7857 	} else {
  7858 	    size = DoReadChars(inStatePtr->topChanPtr, bufObj, sizeb, 0 /* No append */);
  7859 	}
  7860 	underflow = (size >= 0) && (size < sizeb);	/* input underflow */
  7861 
  7862 	if (size < 0) {
  7863 	    readError:
  7864 	    errObj = Tcl_NewObj();
  7865 	    Tcl_AppendStringsToObj(errObj, "error reading \"",
  7866 		    Tcl_GetChannelName(inChan), "\": ",
  7867 		    Tcl_PosixError(interp), (char *) NULL);
  7868 	    break;
  7869 	} else if (underflow) {
  7870 	    /*
  7871 	     * We had an underflow on the read side.  If we are at EOF,
  7872 	     * then the copying is done, otherwise set up a channel
  7873 	     * handler to detect when the channel becomes readable again.
  7874 	     */
  7875 	    
  7876 	    if ((size == 0) && Tcl_Eof(inChan)) {
  7877 		break;
  7878 	    }
  7879 	    if (! Tcl_Eof(inChan) && !(mask & TCL_READABLE)) {
  7880 		if (mask & TCL_WRITABLE) {
  7881 		    Tcl_DeleteChannelHandler(outChan, CopyEventProc,
  7882 			    (ClientData) csPtr);
  7883 		}
  7884 		Tcl_CreateChannelHandler(inChan, TCL_READABLE,
  7885 			CopyEventProc, (ClientData) csPtr);
  7886 	    }
  7887 	    if (size == 0) {
  7888 	        if (bufObj != (Tcl_Obj*) NULL) {
  7889 		    Tcl_DecrRefCount (bufObj);
  7890 		    bufObj = (Tcl_Obj*) NULL;
  7891 		}
  7892 		return TCL_OK;
  7893 	    }
  7894 	}
  7895 
  7896 	/*
  7897 	 * Now write the buffer out.
  7898 	 */
  7899 
  7900 	if (inBinary || sameEncoding) {
  7901 	    buffer = csPtr->buffer;
  7902 	    sizeb = size;
  7903 	} else {
  7904 	    buffer = Tcl_GetStringFromObj (bufObj, &sizeb);
  7905 	}
  7906 
  7907 	if (outBinary || sameEncoding) {
  7908 	    sizeb = DoWrite(outStatePtr->topChanPtr, buffer, sizeb);
  7909 	} else {
  7910 	    sizeb = DoWriteChars(outStatePtr->topChanPtr, buffer, sizeb);
  7911 	}
  7912 
  7913 	if (inBinary || sameEncoding) {
  7914 	    /* Both read and write counted bytes */
  7915 	    size = sizeb;
  7916 	} /* else : Read counted characters, write counted bytes, i.e. size != sizeb */
  7917 
  7918 	if (sizeb < 0) {
  7919 	    writeError:
  7920 	    errObj = Tcl_NewObj();
  7921 	    Tcl_AppendStringsToObj(errObj, "error writing \"",
  7922 		    Tcl_GetChannelName(outChan), "\": ",
  7923 		    Tcl_PosixError(interp), (char *) NULL);
  7924 	    break;
  7925 	}
  7926 
  7927 	/*
  7928 	 * Update the current byte count.  Do it now so the count is
  7929 	 * valid before a return or break takes us out of the loop.
  7930 	 * The invariant at the top of the loop should be that 
  7931 	 * csPtr->toRead holds the number of bytes left to copy.
  7932 	 */
  7933 
  7934 	if (csPtr->toRead != -1) {
  7935 	    csPtr->toRead -= size;
  7936 	}
  7937 	csPtr->total += size;
  7938 
  7939 	/*
  7940 	 * Break loop if EOF && (size>0)
  7941 	 */
  7942 
  7943         if (Tcl_Eof(inChan)) {
  7944             break;
  7945         }
  7946 
  7947 	/*
  7948 	 * Check to see if the write is happening in the background.  If so,
  7949 	 * stop copying and wait for the channel to become writable again.
  7950 	 * After input underflow we already installed a readable handler
  7951 	 * therefore we don't need a writable handler.
  7952 	 */
  7953 
  7954 	if ( ! underflow && (outStatePtr->flags & BG_FLUSH_SCHEDULED) ) {
  7955 	    if (!(mask & TCL_WRITABLE)) {
  7956 		if (mask & TCL_READABLE) {
  7957 		    Tcl_DeleteChannelHandler(inChan, CopyEventProc,
  7958 			    (ClientData) csPtr);
  7959 		}
  7960 		Tcl_CreateChannelHandler(outChan, TCL_WRITABLE,
  7961 			CopyEventProc, (ClientData) csPtr);
  7962 	    }
  7963 	    if (bufObj != (Tcl_Obj*) NULL) {
  7964 	        Tcl_DecrRefCount (bufObj);
  7965 		bufObj = (Tcl_Obj*) NULL;
  7966 	    }
  7967 	    return TCL_OK;
  7968 	}
  7969 
  7970 	/*
  7971 	 * For background copies, we only do one buffer per invocation so
  7972 	 * we don't starve the rest of the system.
  7973 	 */
  7974 
  7975 	if (cmdPtr) {
  7976 	    /*
  7977 	     * The first time we enter this code, there won't be a
  7978 	     * channel handler established yet, so do it here.
  7979 	     */
  7980 
  7981 	    if (mask == 0) {
  7982 		Tcl_CreateChannelHandler(outChan, TCL_WRITABLE,
  7983 			CopyEventProc, (ClientData) csPtr);
  7984 	    }
  7985 	    if (bufObj != (Tcl_Obj*) NULL) {
  7986 	        Tcl_DecrRefCount (bufObj);
  7987 		bufObj = (Tcl_Obj*) NULL;
  7988 	    }
  7989 	    return TCL_OK;
  7990 	}
  7991     } /* while */
  7992 
  7993     if (bufObj != (Tcl_Obj*) NULL) {
  7994         Tcl_DecrRefCount (bufObj);
  7995 	bufObj = (Tcl_Obj*) NULL;
  7996     }
  7997 
  7998     /*
  7999      * Make the callback or return the number of bytes transferred.
  8000      * The local total is used because StopCopy frees csPtr.
  8001      */
  8002 
  8003     total = csPtr->total;
  8004     if (cmdPtr && interp) {
  8005 	/*
  8006 	 * Get a private copy of the command so we can mutate it
  8007 	 * by adding arguments.  Note that StopCopy frees our saved
  8008 	 * reference to the original command obj.
  8009 	 */
  8010 
  8011 	cmdPtr = Tcl_DuplicateObj(cmdPtr);
  8012 	Tcl_IncrRefCount(cmdPtr);
  8013 	StopCopy(csPtr);
  8014 	Tcl_Preserve((ClientData) interp);
  8015 
  8016 	Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewIntObj(total));
  8017 	if (errObj) {
  8018 	    Tcl_ListObjAppendElement(interp, cmdPtr, errObj);
  8019 	}
  8020 	if (Tcl_EvalObjEx(interp, cmdPtr, TCL_EVAL_GLOBAL) != TCL_OK) {
  8021 	    Tcl_BackgroundError(interp);
  8022 	    result = TCL_ERROR;
  8023 	}
  8024 	Tcl_DecrRefCount(cmdPtr);
  8025 	Tcl_Release((ClientData) interp);
  8026     } else {
  8027 	StopCopy(csPtr);
  8028 	if (interp) {
  8029 	    if (errObj) {
  8030 		Tcl_SetObjResult(interp, errObj);
  8031 		result = TCL_ERROR;
  8032 	    } else {
  8033 		Tcl_ResetResult(interp);
  8034 		Tcl_SetIntObj(Tcl_GetObjResult(interp), total);
  8035 	    }
  8036 	}
  8037     }
  8038     return result;
  8039 }
  8040 
  8041 /*
  8042  *----------------------------------------------------------------------
  8043  *
  8044  * DoRead --
  8045  *
  8046  *	Reads a given number of bytes from a channel.
  8047  *
  8048  *	No encoding conversions are applied to the bytes being read.
  8049  *
  8050  * Results:
  8051  *	The number of characters read, or -1 on error. Use Tcl_GetErrno()
  8052  *	to retrieve the error code for the error that occurred.
  8053  *
  8054  * Side effects:
  8055  *	May cause input to be buffered.
  8056  *
  8057  *----------------------------------------------------------------------
  8058  */
  8059 
  8060 static int
  8061 DoRead(chanPtr, bufPtr, toRead)
  8062     Channel *chanPtr;		/* The channel from which to read. */
  8063     char *bufPtr;		/* Where to store input read. */
  8064     int toRead;			/* Maximum number of bytes to read. */
  8065 {
  8066     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  8067     int copied;			/* How many characters were copied into
  8068                                  * the result string? */
  8069     int copiedNow;		/* How many characters were copied from
  8070                                  * the current input buffer? */
  8071     int result;			/* Of calling GetInput. */
  8072 
  8073     /*
  8074      * If we have not encountered a sticky EOF, clear the EOF bit. Either
  8075      * way clear the BLOCKED bit. We want to discover these anew during
  8076      * each operation.
  8077      */
  8078 
  8079     if (!(statePtr->flags & CHANNEL_STICKY_EOF)) {
  8080         statePtr->flags &= ~CHANNEL_EOF;
  8081     }
  8082     statePtr->flags &= ~(CHANNEL_BLOCKED | CHANNEL_NEED_MORE_DATA);
  8083     
  8084     for (copied = 0; copied < toRead; copied += copiedNow) {
  8085         copiedNow = CopyAndTranslateBuffer(statePtr, bufPtr + copied,
  8086                 toRead - copied);
  8087         if (copiedNow == 0) {
  8088             if (statePtr->flags & CHANNEL_EOF) {
  8089 		goto done;
  8090             }
  8091             if (statePtr->flags & CHANNEL_BLOCKED) {
  8092                 if (statePtr->flags & CHANNEL_NONBLOCKING) {
  8093 		    goto done;
  8094                 }
  8095                 statePtr->flags &= (~(CHANNEL_BLOCKED));
  8096             }
  8097             result = GetInput(chanPtr);
  8098             if (result != 0) {
  8099                 if (result != EAGAIN) {
  8100                     copied = -1;
  8101                 }
  8102 		goto done;
  8103             }
  8104         }
  8105     }
  8106 
  8107     statePtr->flags &= (~(CHANNEL_BLOCKED));
  8108 
  8109     done:
  8110     /*
  8111      * Update the notifier state so we don't block while there is still
  8112      * data in the buffers.
  8113      */
  8114 
  8115     UpdateInterest(chanPtr);
  8116     return copied;
  8117 }
  8118 
  8119 /*
  8120  *----------------------------------------------------------------------
  8121  *
  8122  * CopyAndTranslateBuffer --
  8123  *
  8124  *	Copy at most one buffer of input to the result space, doing
  8125  *	eol translations according to mode in effect currently.
  8126  *
  8127  * Results:
  8128  *	Number of bytes stored in the result buffer (as opposed to the
  8129  *	number of bytes read from the channel).  May return
  8130  *	zero if no input is available to be translated.
  8131  *
  8132  * Side effects:
  8133  *	Consumes buffered input. May deallocate one buffer.
  8134  *
  8135  *----------------------------------------------------------------------
  8136  */
  8137 
  8138 static int
  8139 CopyAndTranslateBuffer(statePtr, result, space)
  8140     ChannelState *statePtr;	/* Channel state from which to read input. */
  8141     char *result;		/* Where to store the copied input. */
  8142     int space;			/* How many bytes are available in result
  8143                                  * to store the copied input? */
  8144 {
  8145     ChannelBuffer *bufPtr;	/* The buffer from which to copy bytes. */
  8146     int bytesInBuffer;		/* How many bytes are available to be
  8147                                  * copied in the current input buffer? */
  8148     int copied;			/* How many characters were already copied
  8149                                  * into the destination space? */
  8150     int i;			/* Iterates over the copied input looking
  8151                                  * for the input eofChar. */
  8152     
  8153     /*
  8154      * If there is no input at all, return zero. The invariant is that either
  8155      * there is no buffer in the queue, or if the first buffer is empty, it
  8156      * is also the last buffer (and thus there is no input in the queue).
  8157      * Note also that if the buffer is empty, we leave it in the queue.
  8158      */
  8159     
  8160     if (statePtr->inQueueHead == (ChannelBuffer *) NULL) {
  8161         return 0;
  8162     }
  8163     bufPtr = statePtr->inQueueHead;
  8164     bytesInBuffer = bufPtr->nextAdded - bufPtr->nextRemoved;
  8165 
  8166     copied = 0;
  8167     switch (statePtr->inputTranslation) {
  8168         case TCL_TRANSLATE_LF: {
  8169             if (bytesInBuffer == 0) {
  8170                 return 0;
  8171             }
  8172 
  8173 	    /*
  8174              * Copy the current chunk into the result buffer.
  8175              */
  8176 
  8177 	    if (bytesInBuffer < space) {
  8178 		space = bytesInBuffer;
  8179 	    }
  8180 	    memcpy((VOID *) result,
  8181 		    (VOID *) (bufPtr->buf + bufPtr->nextRemoved),
  8182 		    (size_t) space);
  8183 	    bufPtr->nextRemoved += space;
  8184 	    copied = space;
  8185             break;
  8186 	}
  8187         case TCL_TRANSLATE_CR: {
  8188 	    char *end;
  8189 	    
  8190             if (bytesInBuffer == 0) {
  8191                 return 0;
  8192             }
  8193 
  8194 	    /*
  8195              * Copy the current chunk into the result buffer, then
  8196              * replace all \r with \n.
  8197              */
  8198 
  8199 	    if (bytesInBuffer < space) {
  8200 		space = bytesInBuffer;
  8201 	    }
  8202 	    memcpy((VOID *) result,
  8203 		    (VOID *) (bufPtr->buf + bufPtr->nextRemoved),
  8204 		    (size_t) space);
  8205 	    bufPtr->nextRemoved += space;
  8206 	    copied = space;
  8207 
  8208 	    for (end = result + copied; result < end; result++) {
  8209 		if (*result == '\r') {
  8210 		    *result = '\n';
  8211 		}
  8212             }
  8213             break;
  8214 	}
  8215         case TCL_TRANSLATE_CRLF: {
  8216 	    char *src, *end, *dst;
  8217 	    int curByte;
  8218 	    
  8219             /*
  8220              * If there is a held-back "\r" at EOF, produce it now.
  8221              */
  8222             
  8223 	    if (bytesInBuffer == 0) {
  8224                 if ((statePtr->flags & (INPUT_SAW_CR | CHANNEL_EOF)) ==
  8225                         (INPUT_SAW_CR | CHANNEL_EOF)) {
  8226                     result[0] = '\r';
  8227                     statePtr->flags &= ~INPUT_SAW_CR;
  8228                     return 1;
  8229                 }
  8230                 return 0;
  8231             }
  8232 
  8233             /*
  8234              * Copy the current chunk and replace "\r\n" with "\n"
  8235              * (but not standalone "\r"!).
  8236              */
  8237 
  8238 	    if (bytesInBuffer < space) {
  8239 		space = bytesInBuffer;
  8240 	    }
  8241 	    memcpy((VOID *) result,
  8242 		    (VOID *) (bufPtr->buf + bufPtr->nextRemoved),
  8243 		    (size_t) space);
  8244 	    bufPtr->nextRemoved += space;
  8245 	    copied = space;
  8246 
  8247 	    end = result + copied;
  8248 	    dst = result;
  8249 	    for (src = result; src < end; src++) {
  8250 		curByte = *src;
  8251 		if (curByte == '\n') {
  8252                     statePtr->flags &= ~INPUT_SAW_CR;
  8253 		} else if (statePtr->flags & INPUT_SAW_CR) {
  8254 		    statePtr->flags &= ~INPUT_SAW_CR;
  8255 		    *dst = '\r';
  8256 		    dst++;
  8257 		}
  8258 		if (curByte == '\r') {
  8259 		    statePtr->flags |= INPUT_SAW_CR;
  8260 		} else {
  8261 		    *dst = (char) curByte;
  8262 		    dst++;
  8263 		}
  8264 	    }
  8265 	    copied = dst - result;
  8266 	    break;
  8267 	}
  8268         case TCL_TRANSLATE_AUTO: {
  8269 	    char *src, *end, *dst;
  8270 	    int curByte;
  8271 	
  8272             if (bytesInBuffer == 0) {
  8273                 return 0;
  8274             }
  8275 
  8276             /*
  8277              * Loop over the current buffer, converting "\r" and "\r\n"
  8278              * to "\n".
  8279              */
  8280 
  8281 	    if (bytesInBuffer < space) {
  8282 		space = bytesInBuffer;
  8283 	    }
  8284 	    memcpy((VOID *) result,
  8285 		    (VOID *) (bufPtr->buf + bufPtr->nextRemoved),
  8286 		    (size_t) space);
  8287 	    bufPtr->nextRemoved += space;
  8288 	    copied = space;
  8289 
  8290 	    end = result + copied;
  8291 	    dst = result;
  8292 	    for (src = result; src < end; src++) {
  8293 		curByte = *src;
  8294 		if (curByte == '\r') {
  8295 		    statePtr->flags |= INPUT_SAW_CR;
  8296 		    *dst = '\n';
  8297 		    dst++;
  8298 		} else {
  8299 		    if ((curByte != '\n') || 
  8300 			    !(statePtr->flags & INPUT_SAW_CR)) {
  8301 			*dst = (char) curByte;
  8302 			dst++;
  8303 		    }
  8304 		    statePtr->flags &= ~INPUT_SAW_CR;
  8305 		}
  8306 	    }
  8307 	    copied = dst - result;
  8308             break;
  8309 	}
  8310         default: {
  8311             panic("unknown eol translation mode");
  8312 	}
  8313     }
  8314 
  8315     /*
  8316      * If an in-stream EOF character is set for this channel, check that
  8317      * the input we copied so far does not contain the EOF char.  If it does,
  8318      * copy only up to and excluding that character.
  8319      */
  8320     
  8321     if (statePtr->inEofChar != 0) {
  8322         for (i = 0; i < copied; i++) {
  8323             if (result[i] == (char) statePtr->inEofChar) {
  8324 		/*
  8325 		 * Set sticky EOF so that no further input is presented
  8326 		 * to the caller.
  8327 		 */
  8328 		
  8329 		statePtr->flags |= (CHANNEL_EOF | CHANNEL_STICKY_EOF);
  8330 		statePtr->inputEncodingFlags |= TCL_ENCODING_END;
  8331 		copied = i;
  8332                 break;
  8333             }
  8334         }
  8335     }
  8336 
  8337     /*
  8338      * If the current buffer is empty recycle it.
  8339      */
  8340 
  8341     if (bufPtr->nextRemoved == bufPtr->nextAdded) {
  8342         statePtr->inQueueHead = bufPtr->nextPtr;
  8343         if (statePtr->inQueueHead == (ChannelBuffer *) NULL) {
  8344             statePtr->inQueueTail = (ChannelBuffer *) NULL;
  8345         }
  8346         RecycleBuffer(statePtr, bufPtr, 0);
  8347     }
  8348 
  8349     /*
  8350      * Return the number of characters copied into the result buffer.
  8351      * This may be different from the number of bytes consumed, because
  8352      * of EOL translations.
  8353      */
  8354 
  8355     return copied;
  8356 }
  8357 
  8358 /*
  8359  *----------------------------------------------------------------------
  8360  *
  8361  * CopyBuffer --
  8362  *
  8363  *	Copy at most one buffer of input to the result space.
  8364  *
  8365  * Results:
  8366  *	Number of bytes stored in the result buffer.  May return
  8367  *	zero if no input is available.
  8368  *
  8369  * Side effects:
  8370  *	Consumes buffered input. May deallocate one buffer.
  8371  *
  8372  *----------------------------------------------------------------------
  8373  */
  8374 
  8375 static int
  8376 CopyBuffer(chanPtr, result, space)
  8377     Channel *chanPtr;		/* Channel from which to read input. */
  8378     char *result;		/* Where to store the copied input. */
  8379     int space;			/* How many bytes are available in result
  8380                                  * to store the copied input? */
  8381 {
  8382     ChannelBuffer *bufPtr;	/* The buffer from which to copy bytes. */
  8383     int bytesInBuffer;		/* How many bytes are available to be
  8384                                  * copied in the current input buffer? */
  8385     int copied;			/* How many characters were already copied
  8386                                  * into the destination space? */
  8387     
  8388     /*
  8389      * If there is no input at all, return zero. The invariant is that
  8390      * either there is no buffer in the queue, or if the first buffer
  8391      * is empty, it is also the last buffer (and thus there is no
  8392      * input in the queue).  Note also that if the buffer is empty, we
  8393      * don't leave it in the queue, but recycle it.
  8394      */
  8395     
  8396     if (chanPtr->inQueueHead == (ChannelBuffer *) NULL) {
  8397         return 0;
  8398     }
  8399     bufPtr = chanPtr->inQueueHead;
  8400     bytesInBuffer = bufPtr->nextAdded - bufPtr->nextRemoved;
  8401 
  8402     copied = 0;
  8403 
  8404     if (bytesInBuffer == 0) {
  8405         RecycleBuffer(chanPtr->state, bufPtr, 0);
  8406 	chanPtr->inQueueHead = (ChannelBuffer*) NULL;
  8407 	chanPtr->inQueueTail = (ChannelBuffer*) NULL;
  8408         return 0;
  8409     }
  8410 
  8411     /*
  8412      * Copy the current chunk into the result buffer.
  8413      */
  8414 
  8415     if (bytesInBuffer < space) {
  8416         space = bytesInBuffer;
  8417     }
  8418 
  8419     memcpy((VOID *) result,
  8420 	   (VOID *) (bufPtr->buf + bufPtr->nextRemoved),
  8421 	   (size_t) space);
  8422     bufPtr->nextRemoved += space;
  8423     copied = space;
  8424 
  8425     /*
  8426      * We don't care about in-stream EOF characters here as the data
  8427      * read here may still flow through one or more transformations,
  8428      * i.e. is not in its final state yet.
  8429      */
  8430 
  8431     /*
  8432      * If the current buffer is empty recycle it.
  8433      */
  8434 
  8435     if (bufPtr->nextRemoved == bufPtr->nextAdded) {
  8436         chanPtr->inQueueHead = bufPtr->nextPtr;
  8437         if (chanPtr->inQueueHead == (ChannelBuffer *) NULL) {
  8438             chanPtr->inQueueTail = (ChannelBuffer *) NULL;
  8439         }
  8440         RecycleBuffer(chanPtr->state, bufPtr, 0);
  8441     }
  8442 
  8443     /*
  8444      * Return the number of characters copied into the result buffer.
  8445      */
  8446 
  8447     return copied;
  8448 }
  8449 
  8450 /*
  8451  *----------------------------------------------------------------------
  8452  *
  8453  * DoWrite --
  8454  *
  8455  *	Puts a sequence of characters into an output buffer, may queue the
  8456  *	buffer for output if it gets full, and also remembers whether the
  8457  *	current buffer is ready e.g. if it contains a newline and we are in
  8458  *	line buffering mode.
  8459  *
  8460  * Results:
  8461  *	The number of bytes written or -1 in case of error. If -1,
  8462  *	Tcl_GetErrno will return the error code.
  8463  *
  8464  * Side effects:
  8465  *	May buffer up output and may cause output to be produced on the
  8466  *	channel.
  8467  *
  8468  *----------------------------------------------------------------------
  8469  */
  8470 
  8471 static int
  8472 DoWrite(chanPtr, src, srcLen)
  8473     Channel *chanPtr;			/* The channel to buffer output for. */
  8474     CONST char *src;			/* Data to write. */
  8475     int srcLen;				/* Number of bytes to write. */
  8476 {
  8477     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  8478     ChannelBuffer *outBufPtr;		/* Current output buffer. */
  8479     int foundNewline;			/* Did we find a newline in output? */
  8480     char *dPtr;
  8481     CONST char *sPtr;			/* Search variables for newline. */
  8482     int crsent;				/* In CRLF eol translation mode,
  8483                                          * remember the fact that a CR was
  8484                                          * output to the channel without
  8485                                          * its following NL. */
  8486     int i;				/* Loop index for newline search. */
  8487     int destCopied;			/* How many bytes were used in this
  8488                                          * destination buffer to hold the
  8489                                          * output? */
  8490     int totalDestCopied;		/* How many bytes total were
  8491                                          * copied to the channel buffer? */
  8492     int srcCopied;			/* How many bytes were copied from
  8493                                          * the source string? */
  8494     char *destPtr;			/* Where in line to copy to? */
  8495 
  8496     /*
  8497      * If we are in network (or windows) translation mode, record the fact
  8498      * that we have not yet sent a CR to the channel.
  8499      */
  8500 
  8501     crsent = 0;
  8502     
  8503     /*
  8504      * Loop filling buffers and flushing them until all output has been
  8505      * consumed.
  8506      */
  8507 
  8508     srcCopied = 0;
  8509     totalDestCopied = 0;
  8510 
  8511     while (srcLen > 0) {
  8512         
  8513         /*
  8514          * Make sure there is a current output buffer to accept output.
  8515          */
  8516 
  8517         if (statePtr->curOutPtr == (ChannelBuffer *) NULL) {
  8518             statePtr->curOutPtr = AllocChannelBuffer(statePtr->bufSize);
  8519         }
  8520 
  8521         outBufPtr = statePtr->curOutPtr;
  8522 
  8523         destCopied = outBufPtr->bufLength - outBufPtr->nextAdded;
  8524         if (destCopied > srcLen) {
  8525             destCopied = srcLen;
  8526         }
  8527         
  8528         destPtr = outBufPtr->buf + outBufPtr->nextAdded;
  8529         switch (statePtr->outputTranslation) {
  8530             case TCL_TRANSLATE_LF:
  8531                 srcCopied = destCopied;
  8532                 memcpy((VOID *) destPtr, (VOID *) src, (size_t) destCopied);
  8533                 break;
  8534             case TCL_TRANSLATE_CR:
  8535                 srcCopied = destCopied;
  8536                 memcpy((VOID *) destPtr, (VOID *) src, (size_t) destCopied);
  8537                 for (dPtr = destPtr; dPtr < destPtr + destCopied; dPtr++) {
  8538                     if (*dPtr == '\n') {
  8539                         *dPtr = '\r';
  8540                     }
  8541                 }
  8542                 break;
  8543             case TCL_TRANSLATE_CRLF:
  8544                 for (srcCopied = 0, dPtr = destPtr, sPtr = src;
  8545                      dPtr < destPtr + destCopied;
  8546                      dPtr++, sPtr++, srcCopied++) {
  8547                     if (*sPtr == '\n') {
  8548                         if (crsent) {
  8549                             *dPtr = '\n';
  8550                             crsent = 0;
  8551                         } else {
  8552                             *dPtr = '\r';
  8553                             crsent = 1;
  8554                             sPtr--, srcCopied--;
  8555                         }
  8556                     } else {
  8557                         *dPtr = *sPtr;
  8558                     }
  8559                 }
  8560                 break;
  8561             case TCL_TRANSLATE_AUTO:
  8562                 panic("Tcl_Write: AUTO output translation mode not supported");
  8563             default:
  8564                 panic("Tcl_Write: unknown output translation mode");
  8565         }
  8566 
  8567         /*
  8568          * The current buffer is ready for output if it is full, or if it
  8569          * contains a newline and this channel is line-buffered, or if it
  8570          * contains any output and this channel is unbuffered.
  8571          */
  8572 
  8573         outBufPtr->nextAdded += destCopied;
  8574         if (!(statePtr->flags & BUFFER_READY)) {
  8575             if (outBufPtr->nextAdded == outBufPtr->bufLength) {
  8576                 statePtr->flags |= BUFFER_READY;
  8577             } else if (statePtr->flags & CHANNEL_LINEBUFFERED) {
  8578                 for (sPtr = src, i = 0, foundNewline = 0;
  8579 		     (i < srcCopied) && (!foundNewline);
  8580 		     i++, sPtr++) {
  8581                     if (*sPtr == '\n') {
  8582                         foundNewline = 1;
  8583                         break;
  8584                     }
  8585                 }
  8586                 if (foundNewline) {
  8587                     statePtr->flags |= BUFFER_READY;
  8588                 }
  8589             } else if (statePtr->flags & CHANNEL_UNBUFFERED) {
  8590                 statePtr->flags |= BUFFER_READY;
  8591             }
  8592         }
  8593         
  8594         totalDestCopied += srcCopied;
  8595         src += srcCopied;
  8596         srcLen -= srcCopied;
  8597 
  8598         if (statePtr->flags & BUFFER_READY) {
  8599             if (FlushChannel(NULL, chanPtr, 0) != 0) {
  8600                 return -1;
  8601             }
  8602         }
  8603     } /* Closes "while" */
  8604 
  8605     return totalDestCopied;
  8606 }
  8607 
  8608 /*
  8609  *----------------------------------------------------------------------
  8610  *
  8611  * CopyEventProc --
  8612  *
  8613  *	This routine is invoked as a channel event handler for
  8614  *	the background copy operation.  It is just a trivial wrapper
  8615  *	around the CopyData routine.
  8616  *
  8617  * Results:
  8618  *	None.
  8619  *
  8620  * Side effects:
  8621  *	None.
  8622  *
  8623  *----------------------------------------------------------------------
  8624  */
  8625 
  8626 static void
  8627 CopyEventProc(clientData, mask)
  8628     ClientData clientData;
  8629     int mask;
  8630 {
  8631     (void) CopyData((CopyState *)clientData, mask);
  8632 }
  8633 
  8634 /*
  8635  *----------------------------------------------------------------------
  8636  *
  8637  * StopCopy --
  8638  *
  8639  *	This routine halts a copy that is in progress.
  8640  *
  8641  * Results:
  8642  *	None.
  8643  *
  8644  * Side effects:
  8645  *	Removes any pending channel handlers and restores the blocking
  8646  *	and buffering modes of the channels.  The CopyState is freed.
  8647  *
  8648  *----------------------------------------------------------------------
  8649  */
  8650 
  8651 static void
  8652 StopCopy(csPtr)
  8653     CopyState *csPtr;		/* State for bg copy to stop . */
  8654 {
  8655     ChannelState *inStatePtr, *outStatePtr;
  8656     int nonBlocking;
  8657 
  8658     if (!csPtr) {
  8659 	return;
  8660     }
  8661 
  8662     inStatePtr	= csPtr->readPtr->state;
  8663     outStatePtr	= csPtr->writePtr->state;
  8664 
  8665     /*
  8666      * Restore the old blocking mode and output buffering mode.
  8667      */
  8668 
  8669     nonBlocking = (csPtr->readFlags & CHANNEL_NONBLOCKING);
  8670     if (nonBlocking != (inStatePtr->flags & CHANNEL_NONBLOCKING)) {
  8671 	SetBlockMode(NULL, csPtr->readPtr,
  8672 		nonBlocking ? TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING);
  8673     }
  8674     if (csPtr->readPtr != csPtr->writePtr) {
  8675 	nonBlocking = (csPtr->writeFlags & CHANNEL_NONBLOCKING);
  8676 	if (nonBlocking != (outStatePtr->flags & CHANNEL_NONBLOCKING)) {
  8677 	    SetBlockMode(NULL, csPtr->writePtr,
  8678 		    nonBlocking ? TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING);
  8679 	}
  8680     }
  8681     outStatePtr->flags &= ~(CHANNEL_LINEBUFFERED | CHANNEL_UNBUFFERED);
  8682     outStatePtr->flags |=
  8683 	csPtr->writeFlags & (CHANNEL_LINEBUFFERED | CHANNEL_UNBUFFERED);
  8684 
  8685     if (csPtr->cmdPtr) {
  8686 	Tcl_DeleteChannelHandler((Tcl_Channel)csPtr->readPtr, CopyEventProc,
  8687 		(ClientData)csPtr);
  8688 	if (csPtr->readPtr != csPtr->writePtr) {
  8689 	    Tcl_DeleteChannelHandler((Tcl_Channel)csPtr->writePtr,
  8690 		    CopyEventProc, (ClientData)csPtr);
  8691 	}
  8692         Tcl_DecrRefCount(csPtr->cmdPtr);
  8693     }
  8694     inStatePtr->csPtr  = NULL;
  8695     outStatePtr->csPtr = NULL;
  8696     ckfree((char*) csPtr);
  8697 }
  8698 
  8699 /*
  8700  *----------------------------------------------------------------------
  8701  *
  8702  * StackSetBlockMode --
  8703  *
  8704  *	This function sets the blocking mode for a channel, iterating
  8705  *	through each channel in a stack and updates the state flags.
  8706  *
  8707  * Results:
  8708  *	0 if OK, result code from failed blockModeProc otherwise.
  8709  *
  8710  * Side effects:
  8711  *	Modifies the blocking mode of the channel and possibly generates
  8712  *	an error.
  8713  *
  8714  *----------------------------------------------------------------------
  8715  */
  8716 
  8717 static int
  8718 StackSetBlockMode(chanPtr, mode)
  8719     Channel *chanPtr;		/* Channel to modify. */
  8720     int mode;			/* One of TCL_MODE_BLOCKING or
  8721 				 * TCL_MODE_NONBLOCKING. */
  8722 {
  8723     int result = 0;
  8724     Tcl_DriverBlockModeProc *blockModeProc;
  8725 
  8726     /*
  8727      * Start at the top of the channel stack
  8728      */
  8729 
  8730     chanPtr = chanPtr->state->topChanPtr;
  8731     while (chanPtr != (Channel *) NULL) {
  8732 	blockModeProc = Tcl_ChannelBlockModeProc(chanPtr->typePtr);
  8733 	if (blockModeProc != NULL) {
  8734 	    result = (*blockModeProc) (chanPtr->instanceData, mode);
  8735 	    if (result != 0) {
  8736 		Tcl_SetErrno(result);
  8737 		return result;
  8738 	    }
  8739 	}
  8740 	chanPtr = chanPtr->downChanPtr;
  8741     }
  8742     return 0;
  8743 }
  8744 
  8745 /*
  8746  *----------------------------------------------------------------------
  8747  *
  8748  * SetBlockMode --
  8749  *
  8750  *	This function sets the blocking mode for a channel and updates
  8751  *	the state flags.
  8752  *
  8753  * Results:
  8754  *	A standard Tcl result.
  8755  *
  8756  * Side effects:
  8757  *	Modifies the blocking mode of the channel and possibly generates
  8758  *	an error.
  8759  *
  8760  *----------------------------------------------------------------------
  8761  */
  8762 
  8763 static int
  8764 SetBlockMode(interp, chanPtr, mode)
  8765     Tcl_Interp *interp;		/* Interp for error reporting. */
  8766     Channel *chanPtr;		/* Channel to modify. */
  8767     int mode;			/* One of TCL_MODE_BLOCKING or
  8768 				 * TCL_MODE_NONBLOCKING. */
  8769 {
  8770     ChannelState *statePtr = chanPtr->state;	/* state info for channel */
  8771     int result = 0;
  8772 
  8773     result = StackSetBlockMode(chanPtr, mode);
  8774     if (result != 0) {
  8775 	if (interp != (Tcl_Interp *) NULL) {
  8776 	    Tcl_AppendResult(interp, "error setting blocking mode: ",
  8777 		    Tcl_PosixError(interp), (char *) NULL);
  8778 	}
  8779 	return TCL_ERROR;
  8780     }
  8781     if (mode == TCL_MODE_BLOCKING) {
  8782 	statePtr->flags &= (~(CHANNEL_NONBLOCKING | BG_FLUSH_SCHEDULED));
  8783     } else {
  8784 	statePtr->flags |= CHANNEL_NONBLOCKING;
  8785     }
  8786     return TCL_OK;
  8787 }
  8788 
  8789 /*
  8790  *----------------------------------------------------------------------
  8791  *
  8792  * Tcl_GetChannelNames --
  8793  *
  8794  *	Return the names of all open channels in the interp.
  8795  *
  8796  * Results:
  8797  *	TCL_OK or TCL_ERROR.
  8798  *
  8799  * Side effects:
  8800  *	Interp result modified with list of channel names.
  8801  *
  8802  *----------------------------------------------------------------------
  8803  */
  8804 
  8805 EXPORT_C int
  8806 Tcl_GetChannelNames(interp)
  8807     Tcl_Interp *interp;		/* Interp for error reporting. */
  8808 {
  8809     return Tcl_GetChannelNamesEx(interp, (char *) NULL);
  8810 }
  8811 
  8812 /*
  8813  *----------------------------------------------------------------------
  8814  *
  8815  * Tcl_GetChannelNamesEx --
  8816  *
  8817  *	Return the names of open channels in the interp filtered
  8818  *	filtered through a pattern.  If pattern is NULL, it returns
  8819  *	all the open channels.
  8820  *
  8821  * Results:
  8822  *	TCL_OK or TCL_ERROR.
  8823  *
  8824  * Side effects:
  8825  *	Interp result modified with list of channel names.
  8826  *
  8827  *----------------------------------------------------------------------
  8828  */
  8829 
  8830 EXPORT_C int
  8831 Tcl_GetChannelNamesEx(interp, pattern)
  8832     Tcl_Interp *interp;		/* Interp for error reporting. */
  8833     CONST char *pattern;	/* pattern to filter on. */
  8834 {
  8835     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
  8836     ChannelState *statePtr;
  8837     CONST char *name;		/* name for channel */
  8838     Tcl_Obj *resultPtr;		/* pointer to result object */
  8839     Tcl_HashTable *hTblPtr;	/* Hash table of channels. */
  8840     Tcl_HashEntry *hPtr;	/* Search variable. */
  8841     Tcl_HashSearch hSearch;	/* Search variable. */
  8842 
  8843     if (interp == (Tcl_Interp *) NULL) {
  8844 	return TCL_OK;
  8845     }
  8846 
  8847     /*
  8848      * Get the channel table that stores the channels registered
  8849      * for this interpreter.
  8850      */
  8851     hTblPtr	= GetChannelTable(interp);
  8852     resultPtr	= Tcl_GetObjResult(interp);
  8853 
  8854     for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch);
  8855 	 hPtr != (Tcl_HashEntry *) NULL;
  8856 	 hPtr = Tcl_NextHashEntry(&hSearch)) {
  8857 
  8858 	statePtr = ((Channel *) Tcl_GetHashValue(hPtr))->state;
  8859         if (statePtr->topChanPtr == (Channel *) tsdPtr->stdinChannel) {
  8860 	    name = "stdin";
  8861 	} else if (statePtr->topChanPtr == (Channel *) tsdPtr->stdoutChannel) {
  8862 	    name = "stdout";
  8863 	} else if (statePtr->topChanPtr == (Channel *) tsdPtr->stderrChannel) {
  8864 	    name = "stderr";
  8865 	} else {
  8866 	    /*
  8867 	     * This is also stored in Tcl_GetHashKey(hTblPtr, hPtr),
  8868 	     * but it's simpler to just grab the name from the statePtr.
  8869 	     */
  8870 	    name = statePtr->channelName;
  8871 	}
  8872 
  8873 	if (((pattern == NULL) || Tcl_StringMatch(name, pattern)) &&
  8874 		(Tcl_ListObjAppendElement(interp, resultPtr,
  8875 			Tcl_NewStringObj(name, -1)) != TCL_OK)) {
  8876 	    return TCL_ERROR;
  8877 	}
  8878     }
  8879     return TCL_OK;
  8880 }
  8881 
  8882 /*
  8883  *----------------------------------------------------------------------
  8884  *
  8885  * Tcl_IsChannelRegistered --
  8886  *
  8887  *	Checks whether the channel is associated with the interp.
  8888  *	See also Tcl_RegisterChannel and Tcl_UnregisterChannel.
  8889  *
  8890  * Results:
  8891  *	0 if the channel is not registered in the interpreter, 1 else.
  8892  *
  8893  * Side effects:
  8894  *	None.
  8895  *
  8896  *----------------------------------------------------------------------
  8897  */
  8898 
  8899 EXPORT_C int
  8900 Tcl_IsChannelRegistered (interp, chan)
  8901      Tcl_Interp* interp;	/* The interp to query of the channel */
  8902      Tcl_Channel chan;		/* The channel to check */
  8903 {
  8904     Tcl_HashTable	*hTblPtr;	/* Hash table of channels. */
  8905     Tcl_HashEntry	*hPtr;		/* Search variable. */
  8906     Channel		*chanPtr;	/* The real IO channel. */
  8907     ChannelState	*statePtr;	/* State of the real channel. */
  8908 
  8909     /*
  8910      * Always check bottom-most channel in the stack.  This is the one
  8911      * that gets registered.
  8912      */
  8913     chanPtr = ((Channel *) chan)->state->bottomChanPtr;
  8914     statePtr = chanPtr->state;
  8915 
  8916     hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL);
  8917     if (hTblPtr == (Tcl_HashTable *) NULL) {
  8918         return 0;
  8919     }
  8920     hPtr = Tcl_FindHashEntry(hTblPtr, statePtr->channelName);
  8921     if (hPtr == (Tcl_HashEntry *) NULL) {
  8922         return 0;
  8923     }
  8924     if ((Channel *) Tcl_GetHashValue(hPtr) != chanPtr) {
  8925         return 0;
  8926     }
  8927 
  8928     return 1;
  8929 }
  8930 
  8931 /*
  8932  *----------------------------------------------------------------------
  8933  *
  8934  * Tcl_IsChannelShared --
  8935  *
  8936  *	Checks whether the channel is shared by multiple interpreters.
  8937  *
  8938  * Results:
  8939  *	A boolean value (0 = Not shared, 1 = Shared).
  8940  *
  8941  * Side effects:
  8942  *	None.
  8943  *
  8944  *----------------------------------------------------------------------
  8945  */
  8946 
  8947 EXPORT_C int
  8948 Tcl_IsChannelShared (chan)
  8949     Tcl_Channel chan;	/* The channel to query */
  8950 {
  8951     ChannelState *statePtr = ((Channel *) chan)->state;
  8952 					/* State of real channel structure. */
  8953 
  8954     return ((statePtr->refCount > 1) ? 1 : 0);
  8955 }
  8956 
  8957 /*
  8958  *----------------------------------------------------------------------
  8959  *
  8960  * Tcl_IsChannelExisting --
  8961  *
  8962  *	Checks whether a channel of the given name exists in the
  8963  *	(thread)-global list of all channels.
  8964  *	See Tcl_GetChannelNamesEx for function exposed at the Tcl level.
  8965  *
  8966  * Results:
  8967  *	A boolean value (0 = Does not exist, 1 = Does exist).
  8968  *
  8969  * Side effects:
  8970  *	None.
  8971  *
  8972  *----------------------------------------------------------------------
  8973  */
  8974 
  8975 EXPORT_C int
  8976 Tcl_IsChannelExisting(chanName)
  8977     CONST char* chanName;	/* The name of the channel to look for. */
  8978 {
  8979     ChannelState *statePtr;
  8980     ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
  8981     CONST char *name;
  8982     int chanNameLen;
  8983 
  8984     chanNameLen = strlen(chanName);
  8985     for (statePtr = tsdPtr->firstCSPtr;
  8986 	 statePtr != NULL;
  8987 	 statePtr = statePtr->nextCSPtr) {
  8988         if (statePtr->topChanPtr == (Channel *) tsdPtr->stdinChannel) {
  8989 	    name = "stdin";
  8990 	} else if (statePtr->topChanPtr == (Channel *) tsdPtr->stdoutChannel) {
  8991 	    name = "stdout";
  8992 	} else if (statePtr->topChanPtr == (Channel *) tsdPtr->stderrChannel) {
  8993 	    name = "stderr";
  8994 	} else {
  8995 	    name = statePtr->channelName;
  8996 	}
  8997 
  8998 	if ((*chanName == *name) &&
  8999 		(memcmp(name, chanName, (size_t) chanNameLen) == 0)) {
  9000 	    return 1;
  9001 	}
  9002     }
  9003 
  9004     return 0;
  9005 }
  9006 
  9007 /*
  9008  *----------------------------------------------------------------------
  9009  *
  9010  * Tcl_ChannelName --
  9011  *
  9012  *	Return the name of the channel type.
  9013  *
  9014  * Results:
  9015  *	A pointer the name of the channel type.
  9016  *
  9017  * Side effects:
  9018  *	None.
  9019  *
  9020  *----------------------------------------------------------------------
  9021  */
  9022 
  9023 EXPORT_C CONST char *
  9024 Tcl_ChannelName(chanTypePtr)
  9025     Tcl_ChannelType *chanTypePtr;	/* Pointer to channel type. */
  9026 {
  9027     return chanTypePtr->typeName;
  9028 }
  9029 
  9030 /*
  9031  *----------------------------------------------------------------------
  9032  *
  9033  * Tcl_ChannelVersion --
  9034  *
  9035  *	Return the of version of the channel type.
  9036  *
  9037  * Results:
  9038  *	One of the TCL_CHANNEL_VERSION_* constants from tcl.h
  9039  *
  9040  * Side effects:
  9041  *	None.
  9042  *
  9043  *----------------------------------------------------------------------
  9044  */
  9045 
  9046 EXPORT_C Tcl_ChannelTypeVersion
  9047 Tcl_ChannelVersion(chanTypePtr)
  9048     Tcl_ChannelType *chanTypePtr;	/* Pointer to channel type. */
  9049 {
  9050     if (chanTypePtr->version == TCL_CHANNEL_VERSION_2) {
  9051 	return TCL_CHANNEL_VERSION_2;
  9052     } else if (chanTypePtr->version == TCL_CHANNEL_VERSION_3) {
  9053 	return TCL_CHANNEL_VERSION_3;
  9054     } else if (chanTypePtr->version == TCL_CHANNEL_VERSION_4) {
  9055 	return TCL_CHANNEL_VERSION_4;
  9056     } else {
  9057 	/*
  9058 	 * In <v2 channel versions, the version field is occupied
  9059 	 * by the Tcl_DriverBlockModeProc
  9060 	 */
  9061 	return TCL_CHANNEL_VERSION_1;
  9062     }
  9063 }
  9064 
  9065 /*
  9066  *----------------------------------------------------------------------
  9067  *
  9068  * HaveVersion --
  9069  *
  9070  *	Return whether a channel type is (at least) of a given version.
  9071  *
  9072  * Results:
  9073  *	True if the minimum version is exceeded by the version actually
  9074  *	present.
  9075  *
  9076  * Side effects:
  9077  *	None.
  9078  *
  9079  *----------------------------------------------------------------------
  9080  */
  9081 
  9082 static int
  9083 HaveVersion(chanTypePtr, minimumVersion)
  9084     Tcl_ChannelType *chanTypePtr;
  9085     Tcl_ChannelTypeVersion minimumVersion;
  9086 {
  9087     Tcl_ChannelTypeVersion actualVersion = Tcl_ChannelVersion(chanTypePtr);
  9088 
  9089     return ((int)actualVersion) >= ((int)minimumVersion);
  9090 }
  9091 
  9092 /*
  9093  *----------------------------------------------------------------------
  9094  *
  9095  * Tcl_ChannelBlockModeProc --
  9096  *
  9097  *	Return the Tcl_DriverBlockModeProc of the channel type.
  9098  *
  9099  * Results:
  9100  *	A pointer to the proc.
  9101  *
  9102  * Side effects:
  9103  *	None.
  9104  *
  9105  *---------------------------------------------------------------------- */
  9106 
  9107 EXPORT_C Tcl_DriverBlockModeProc *
  9108 Tcl_ChannelBlockModeProc(chanTypePtr)
  9109     Tcl_ChannelType *chanTypePtr;	/* Pointer to channel type. */
  9110 {
  9111     if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_2)) {
  9112 	return chanTypePtr->blockModeProc;
  9113     } else {
  9114 	/*
  9115 	 * The v1 structure had the blockModeProc in a different place.
  9116 	 */
  9117 	return (Tcl_DriverBlockModeProc *) (chanTypePtr->version);
  9118     }
  9119 }
  9120 
  9121 /*
  9122  *----------------------------------------------------------------------
  9123  *
  9124  * Tcl_ChannelCloseProc --
  9125  *
  9126  *	Return the Tcl_DriverCloseProc of the channel type.
  9127  *
  9128  * Results:
  9129  *	A pointer to the proc.
  9130  *
  9131  * Side effects:
  9132  *	None.
  9133  *
  9134  *----------------------------------------------------------------------
  9135  */
  9136 
  9137 EXPORT_C Tcl_DriverCloseProc *
  9138 Tcl_ChannelCloseProc(chanTypePtr)
  9139     Tcl_ChannelType *chanTypePtr;	/* Pointer to channel type. */
  9140 {
  9141     return chanTypePtr->closeProc;
  9142 }
  9143 
  9144 /*
  9145  *----------------------------------------------------------------------
  9146  *
  9147  * Tcl_ChannelClose2Proc --
  9148  *
  9149  *	Return the Tcl_DriverClose2Proc of the channel type.
  9150  *
  9151  * Results:
  9152  *	A pointer to the proc.
  9153  *
  9154  * Side effects:
  9155  *	None.
  9156  *
  9157  *----------------------------------------------------------------------
  9158  */
  9159 
  9160 EXPORT_C Tcl_DriverClose2Proc *
  9161 Tcl_ChannelClose2Proc(chanTypePtr)
  9162     Tcl_ChannelType *chanTypePtr;	/* Pointer to channel type. */
  9163 {
  9164     return chanTypePtr->close2Proc;
  9165 }
  9166 
  9167 /*
  9168  *----------------------------------------------------------------------
  9169  *
  9170  * Tcl_ChannelInputProc --
  9171  *
  9172  *	Return the Tcl_DriverInputProc of the channel type.
  9173  *
  9174  * Results:
  9175  *	A pointer to the proc.
  9176  *
  9177  * Side effects:
  9178  *	None.
  9179  *
  9180  *----------------------------------------------------------------------
  9181  */
  9182 
  9183 EXPORT_C Tcl_DriverInputProc *
  9184 Tcl_ChannelInputProc(chanTypePtr)
  9185     Tcl_ChannelType *chanTypePtr;	/* Pointer to channel type. */
  9186 {
  9187     return chanTypePtr->inputProc;
  9188 }
  9189 
  9190 /*
  9191  *----------------------------------------------------------------------
  9192  *
  9193  * Tcl_ChannelOutputProc --
  9194  *
  9195  *	Return the Tcl_DriverOutputProc of the channel type.
  9196  *
  9197  * Results:
  9198  *	A pointer to the proc.
  9199  *
  9200  * Side effects:
  9201  *	None.
  9202  *
  9203  *----------------------------------------------------------------------
  9204  */
  9205 
  9206 EXPORT_C Tcl_DriverOutputProc *
  9207 Tcl_ChannelOutputProc(chanTypePtr)
  9208     Tcl_ChannelType *chanTypePtr;	/* Pointer to channel type. */
  9209 {
  9210     return chanTypePtr->outputProc;
  9211 }
  9212 
  9213 /*
  9214  *----------------------------------------------------------------------
  9215  *
  9216  * Tcl_ChannelSeekProc --
  9217  *
  9218  *	Return the Tcl_DriverSeekProc of the channel type.
  9219  *
  9220  * Results:
  9221  *	A pointer to the proc.
  9222  *
  9223  * Side effects:
  9224  *	None.
  9225  *
  9226  *----------------------------------------------------------------------
  9227  */
  9228 
  9229 EXPORT_C Tcl_DriverSeekProc *
  9230 Tcl_ChannelSeekProc(chanTypePtr)
  9231     Tcl_ChannelType *chanTypePtr;	/* Pointer to channel type. */
  9232 {
  9233     return chanTypePtr->seekProc;
  9234 }
  9235 
  9236 /*
  9237  *----------------------------------------------------------------------
  9238  *
  9239  * Tcl_ChannelSetOptionProc --
  9240  *
  9241  *	Return the Tcl_DriverSetOptionProc of the channel type.
  9242  *
  9243  * Results:
  9244  *	A pointer to the proc.
  9245  *
  9246  * Side effects:
  9247  *	None.
  9248  *
  9249  *----------------------------------------------------------------------
  9250  */
  9251 
  9252 EXPORT_C Tcl_DriverSetOptionProc *
  9253 Tcl_ChannelSetOptionProc(chanTypePtr)
  9254     Tcl_ChannelType *chanTypePtr;	/* Pointer to channel type. */
  9255 {
  9256     return chanTypePtr->setOptionProc;
  9257 }
  9258 
  9259 /*
  9260  *----------------------------------------------------------------------
  9261  *
  9262  * Tcl_ChannelGetOptionProc --
  9263  *
  9264  *	Return the Tcl_DriverGetOptionProc of the channel type.
  9265  *
  9266  * Results:
  9267  *	A pointer to the proc.
  9268  *
  9269  * Side effects:
  9270  *	None.
  9271  *
  9272  *----------------------------------------------------------------------
  9273  */
  9274 
  9275 EXPORT_C Tcl_DriverGetOptionProc *
  9276 Tcl_ChannelGetOptionProc(chanTypePtr)
  9277     Tcl_ChannelType *chanTypePtr;	/* Pointer to channel type. */
  9278 {
  9279     return chanTypePtr->getOptionProc;
  9280 }
  9281 
  9282 /*
  9283  *----------------------------------------------------------------------
  9284  *
  9285  * Tcl_ChannelWatchProc --
  9286  *
  9287  *	Return the Tcl_DriverWatchProc of the channel type.
  9288  *
  9289  * Results:
  9290  *	A pointer to the proc.
  9291  *
  9292  * Side effects:
  9293  *	None.
  9294  *
  9295  *----------------------------------------------------------------------
  9296  */
  9297 
  9298 EXPORT_C Tcl_DriverWatchProc *
  9299 Tcl_ChannelWatchProc(chanTypePtr)
  9300     Tcl_ChannelType *chanTypePtr;	/* Pointer to channel type. */
  9301 {
  9302     return chanTypePtr->watchProc;
  9303 }
  9304 
  9305 /*
  9306  *----------------------------------------------------------------------
  9307  *
  9308  * Tcl_ChannelGetHandleProc --
  9309  *
  9310  *	Return the Tcl_DriverGetHandleProc of the channel type.
  9311  *
  9312  * Results:
  9313  *	A pointer to the proc.
  9314  *
  9315  * Side effects:
  9316  *	None.
  9317  *
  9318  *----------------------------------------------------------------------
  9319  */
  9320 
  9321 EXPORT_C Tcl_DriverGetHandleProc *
  9322 Tcl_ChannelGetHandleProc(chanTypePtr)
  9323     Tcl_ChannelType *chanTypePtr;	/* Pointer to channel type. */
  9324 {
  9325     return chanTypePtr->getHandleProc;
  9326 }
  9327 
  9328 /*
  9329  *----------------------------------------------------------------------
  9330  *
  9331  * Tcl_ChannelFlushProc --
  9332  *
  9333  *	Return the Tcl_DriverFlushProc of the channel type.
  9334  *
  9335  * Results:
  9336  *	A pointer to the proc.
  9337  *
  9338  * Side effects:
  9339  *	None.
  9340  *
  9341  *----------------------------------------------------------------------
  9342  */
  9343 
  9344 EXPORT_C Tcl_DriverFlushProc *
  9345 Tcl_ChannelFlushProc(chanTypePtr)
  9346     Tcl_ChannelType *chanTypePtr;	/* Pointer to channel type. */
  9347 {
  9348     if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_2)) {
  9349 	return chanTypePtr->flushProc;
  9350     } else {
  9351 	return NULL;
  9352     }
  9353 }
  9354 
  9355 /*
  9356  *----------------------------------------------------------------------
  9357  *
  9358  * Tcl_ChannelHandlerProc --
  9359  *
  9360  *	Return the Tcl_DriverHandlerProc of the channel type.
  9361  *
  9362  * Results:
  9363  *	A pointer to the proc.
  9364  *
  9365  * Side effects:
  9366  *	None.
  9367  *
  9368  *----------------------------------------------------------------------
  9369  */
  9370 
  9371 EXPORT_C Tcl_DriverHandlerProc *
  9372 Tcl_ChannelHandlerProc(chanTypePtr)
  9373     Tcl_ChannelType *chanTypePtr;	/* Pointer to channel type. */
  9374 {
  9375     if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_2)) {
  9376 	return chanTypePtr->handlerProc;
  9377     } else {
  9378 	return NULL;
  9379     }
  9380 }
  9381 
  9382 /*
  9383  *----------------------------------------------------------------------
  9384  *
  9385  * Tcl_ChannelWideSeekProc --
  9386  *
  9387  *	Return the Tcl_DriverWideSeekProc of the channel type.
  9388  *
  9389  * Results:
  9390  *	A pointer to the proc.
  9391  *
  9392  * Side effects:
  9393  *	None.
  9394  *
  9395  *----------------------------------------------------------------------
  9396  */
  9397 
  9398 EXPORT_C Tcl_DriverWideSeekProc *
  9399 Tcl_ChannelWideSeekProc(chanTypePtr)
  9400     Tcl_ChannelType *chanTypePtr;	/* Pointer to channel type. */
  9401 {
  9402     if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_3)) {
  9403 	return chanTypePtr->wideSeekProc;
  9404     } else {
  9405 	return NULL;
  9406     }
  9407 }
  9408 
  9409 /*
  9410  *----------------------------------------------------------------------
  9411  *
  9412  * Tcl_ChannelThreadActionProc --
  9413  *
  9414  *	Return the Tcl_DriverThreadActionProc of the channel type.
  9415  *
  9416  * Results:
  9417  *	A pointer to the proc.
  9418  *
  9419  * Side effects:
  9420  *	None.
  9421  *
  9422  *----------------------------------------------------------------------
  9423  */
  9424 
  9425 EXPORT_C Tcl_DriverThreadActionProc *
  9426 Tcl_ChannelThreadActionProc(chanTypePtr)
  9427     Tcl_ChannelType *chanTypePtr;	/* Pointer to channel type. */
  9428 {
  9429     if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_4)) {
  9430 	return chanTypePtr->threadActionProc;
  9431     } else {
  9432 	return NULL;
  9433     }
  9434 }
  9435 
  9436 #if 0
  9437 /* For future debugging work, a simple function to print the flags of
  9438  * a channel in semi-readable form.
  9439  */
  9440 
  9441 static int
  9442 DumpFlags (str, flags)
  9443      char* str;
  9444      int flags;
  9445 {
  9446   char buf [20];
  9447   int i = 0;
  9448 
  9449   if (flags & TCL_READABLE)           {buf[i] = 'r';} else {buf [i]='_';}; i++;
  9450   if (flags & TCL_WRITABLE)           {buf[i] = 'w';} else {buf [i]='_';}; i++;
  9451   if (flags & CHANNEL_NONBLOCKING)    {buf[i] = 'n';} else {buf [i]='_';}; i++;
  9452   if (flags & CHANNEL_LINEBUFFERED)   {buf[i] = 'l';} else {buf [i]='_';}; i++;
  9453   if (flags & CHANNEL_UNBUFFERED)     {buf[i] = 'u';} else {buf [i]='_';}; i++;
  9454   if (flags & BUFFER_READY)           {buf[i] = 'R';} else {buf [i]='_';}; i++;
  9455   if (flags & BG_FLUSH_SCHEDULED)     {buf[i] = 'F';} else {buf [i]='_';}; i++;
  9456   if (flags & CHANNEL_CLOSED)         {buf[i] = 'c';} else {buf [i]='_';}; i++;
  9457   if (flags & CHANNEL_EOF)            {buf[i] = 'E';} else {buf [i]='_';}; i++;
  9458   if (flags & CHANNEL_STICKY_EOF)     {buf[i] = 'S';} else {buf [i]='_';}; i++;
  9459   if (flags & CHANNEL_BLOCKED)        {buf[i] = 'B';} else {buf [i]='_';}; i++;
  9460   if (flags & INPUT_SAW_CR)           {buf[i] = '/';} else {buf [i]='_';}; i++;
  9461   if (flags & INPUT_NEED_NL)          {buf[i] = '*';} else {buf [i]='_';}; i++;
  9462   if (flags & CHANNEL_DEAD)           {buf[i] = 'D';} else {buf [i]='_';}; i++;
  9463   if (flags & CHANNEL_RAW_MODE)       {buf[i] = 'R';} else {buf [i]='_';}; i++;
  9464 #ifdef TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING
  9465   if (flags & CHANNEL_TIMER_FEV)      {buf[i] = 'T';} else {buf [i]='_';}; i++;
  9466   if (flags & CHANNEL_HAS_MORE_DATA)  {buf[i] = 'H';} else {buf [i]='_';}; i++;
  9467 #endif /* TCL_IO_TRACK_OS_FOR_DRIVER_WITH_BAD_BLOCKING */
  9468   if (flags & CHANNEL_INCLOSE)        {buf[i] = 'x';} else {buf [i]='_';}; i++;
  9469   buf [i] ='\0';
  9470 
  9471   fprintf (stderr,"%s: %s\n", str, buf); fflush(stderr);
  9472   return 0;
  9473 }
  9474 #endif