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