Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/tcl8.5.2/generic/tclIO.c @ 42

Last change on this file since 42 was 25, checked in by landauf, 17 years ago

added tcl to libs

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