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