diff options
Diffstat (limited to 'generic/tclIO.c')
| -rw-r--r-- | generic/tclIO.c | 1753 |
1 files changed, 562 insertions, 1191 deletions
diff --git a/generic/tclIO.c b/generic/tclIO.c index 506e6d5..7bc849e 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -35,15 +35,15 @@ typedef struct ChannelHandler { /* * This structure keeps track of the current ChannelHandler being invoked in - * the current invocation of Tcl_NotifyChannel. There is a potential + * the current invocation of ChannelHandlerEventProc. There is a potential * problem if a ChannelHandler is deleted while it is the current one, since - * Tcl_NotifyChannel needs to look at the nextPtr field. To handle this + * ChannelHandlerEventProc needs to look at the nextPtr field. To handle this * problem, structures of the type below indicate the next handler to be * processed for any (recursively nested) dispatches in progress. The * nextHandlerPtr field is updated if the handler being pointed to is deleted. - * The nestedHandlerPtr field is used to chain together all recursive - * invocations, so that Tcl_DeleteChannelHandler can find all the recursively - * nested invocations of Tcl_NotifyChannel and compare the handler being + * The nextPtr field is used to chain together all recursive invocations, so + * that Tcl_DeleteChannelHandler can find all the recursively nested + * invocations of ChannelHandlerEventProc and compare the handler being * deleted against the NEXT handler to be invoked in that invocation; when it * finds such a situation, Tcl_DeleteChannelHandler updates the nextHandlerPtr * field of the structure to the next handler. @@ -54,10 +54,21 @@ typedef struct NextChannelHandler { * this invocation. */ struct NextChannelHandler *nestedHandlerPtr; /* Next nested invocation of - * Tcl_NotifyChannel. */ + * ChannelHandlerEventProc. */ } NextChannelHandler; /* + * The following structure describes the event that is added to the Tcl + * event queue by the channel handler check procedure. + */ + +typedef struct ChannelHandlerEvent { + Tcl_Event header; /* Standard header for all events. */ + Channel *chanPtr; /* The channel that is ready. */ + int readyMask; /* Events that have occurred. */ +} ChannelHandlerEvent; + +/* * The following structure is used by Tcl_GetsObj() to encapsulates the * state for a "gets" operation. */ @@ -98,7 +109,7 @@ typedef struct CopyState { struct Channel *writePtr; /* Pointer to output channel. */ int readFlags; /* Original read channel flags. */ int writeFlags; /* Original write channel flags. */ - Tcl_WideInt toRead; /* Number of bytes to copy, or -1. */ + int toRead; /* Number of bytes to copy, or -1. */ Tcl_WideInt total; /* Total bytes transferred (written). */ Tcl_Interp *interp; /* Interp that started the copy. */ Tcl_Obj *cmdPtr; /* Command to be invoked at completion. */ @@ -119,7 +130,7 @@ typedef struct CopyState { typedef struct ThreadSpecificData { NextChannelHandler *nestedHandlerPtr; /* This variable holds the list of nested - * Tcl_NotifyChannel invocations. */ + * ChannelHandlerEventProc invocations. */ ChannelState *firstCSPtr; /* List of all channels currently open, * indexed by ChannelState, as only one * ChannelState exists per set of stacked @@ -167,19 +178,8 @@ static void CleanupChannelHandlers(Tcl_Interp *interp, Channel *chanPtr); static int CloseChannel(Tcl_Interp *interp, Channel *chanPtr, int errorCode); -static int CloseChannelPart(Tcl_Interp *interp, Channel *chanPtr, - int errorCode, int flags); -static int CloseWrite(Tcl_Interp *interp, Channel *chanPtr); static void CommonGetsCleanup(Channel *chanPtr); static int CopyData(CopyState *csPtr, int mask); -static int MoveBytes(CopyState *csPtr); - -static void MBCallback(CopyState *csPtr, Tcl_Obj *errObj); -static void MBError(CopyState *csPtr, int mask, int errorCode); -static int MBRead(CopyState *csPtr); -static int MBWrite(CopyState *csPtr); -static void MBEvent(ClientData clientData, int mask); - static void CopyEventProc(ClientData clientData, int mask); static void CreateScriptRecord(Tcl_Interp *interp, Channel *chanPtr, int mask, Tcl_Obj *scriptPtr); @@ -191,8 +191,7 @@ static int DetachChannel(Tcl_Interp *interp, Tcl_Channel chan); static void DiscardInputQueued(ChannelState *statePtr, int discardSavedBuffers); static void DiscardOutputQueued(ChannelState *chanPtr); -static int DoRead(Channel *chanPtr, char *dst, int bytesToRead, - int allowShortReads); +static int DoRead(Channel *chanPtr, char *dst, int bytesToRead); static int DoReadChars(Channel *chan, Tcl_Obj *objPtr, int toRead, int appendFlag); static int FilterInputBytes(Channel *chanPtr, @@ -226,7 +225,7 @@ static int Write(Channel *chanPtr, const char *src, static Tcl_Obj * FixLevelCode(Tcl_Obj *msg); static void SpliceChannel(Tcl_Channel chan); static void CutChannel(Tcl_Channel chan); -static int WillRead(Channel *chanPtr); +static int WillRead(Channel *chanPtr); #define WriteChars(chanPtr, src, srcLen) \ Write(chanPtr, src, srcLen, chanPtr->state->encoding) @@ -277,21 +276,21 @@ static int WillRead(Channel *chanPtr); * -------------------------------------------------------------------------- */ -#define BytesLeft(bufPtr) ((bufPtr)->nextAdded - (bufPtr)->nextRemoved) +#define BytesLeft(bufPtr) ((bufPtr)->nextAdded - (bufPtr)->nextRemoved) -#define SpaceLeft(bufPtr) ((bufPtr)->bufLength - (bufPtr)->nextAdded) +#define SpaceLeft(bufPtr) ((bufPtr)->bufLength - (bufPtr)->nextAdded) -#define IsBufferReady(bufPtr) ((bufPtr)->nextAdded > (bufPtr)->nextRemoved) +#define IsBufferReady(bufPtr) ((bufPtr)->nextAdded > (bufPtr)->nextRemoved) -#define IsBufferEmpty(bufPtr) ((bufPtr)->nextAdded == (bufPtr)->nextRemoved) +#define IsBufferEmpty(bufPtr) ((bufPtr)->nextAdded == (bufPtr)->nextRemoved) -#define IsBufferFull(bufPtr) ((bufPtr) && (bufPtr)->nextAdded >= (bufPtr)->bufLength) +#define IsBufferFull(bufPtr) ((bufPtr) && (bufPtr)->nextAdded >= (bufPtr)->bufLength) -#define IsBufferOverflowing(bufPtr) ((bufPtr)->nextAdded>(bufPtr)->bufLength) +#define IsBufferOverflowing(bufPtr) ((bufPtr)->nextAdded > (bufPtr)->bufLength) -#define InsertPoint(bufPtr) ((bufPtr)->buf + (bufPtr)->nextAdded) +#define InsertPoint(bufPtr) ((bufPtr)->buf + (bufPtr)->nextAdded) -#define RemovePoint(bufPtr) ((bufPtr)->buf + (bufPtr)->nextRemoved) +#define RemovePoint(bufPtr) ((bufPtr)->buf + (bufPtr)->nextRemoved) /* * For working with channel state flag bits. @@ -313,31 +312,34 @@ static int WillRead(Channel *chanPtr); && (strncmp(optionName, (nameString), len) == 0)) /* - * The ChannelObjType type. Used to store the result of looking up - * a channel name in the context of an interp. Saves the lookup - * result and values needed to check its continued validity. + * The ChannelObjType type. We actually store the ChannelState structure + * as that lives longest and we want to return the bottomChanPtr when + * requested (consistent with Tcl_GetChannel). The setFromAny and + * updateString can be NULL as they should not be called. */ -typedef struct ResolvedChanName { - ChannelState *statePtr; /* The saved lookup result */ - Tcl_Interp *interp; /* The interp in which the lookup was done. */ - int epoch; /* The epoch of the channel when the lookup - * was done. Use to verify validity. */ - size_t refCount; /* Share this struct among many Tcl_Obj. */ -} ResolvedChanName; - static void DupChannelIntRep(Tcl_Obj *objPtr, Tcl_Obj *copyPtr); +static int SetChannelFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr); static void FreeChannelIntRep(Tcl_Obj *objPtr); -static const Tcl_ObjType chanObjType = { +static Tcl_ObjType chanObjType = { "channel", /* name for this type */ FreeChannelIntRep, /* freeIntRepProc */ DupChannelIntRep, /* dupIntRepProc */ NULL, /* updateStringProc */ - NULL /* setFromAnyProc */ + NULL /* setFromAnyProc SetChannelFromAny */ }; -#define BUSY_STATE(st, fl) \ +#define GET_CHANNELSTATE(objPtr) \ + ((ChannelState *) (objPtr)->internalRep.twoPtrValue.ptr1) +#define SET_CHANNELSTATE(objPtr, storePtr) \ + ((objPtr)->internalRep.twoPtrValue.ptr1 = (void *) (storePtr)) +#define GET_CHANNELINTERP(objPtr) \ + ((Tcl_Interp *) (objPtr)->internalRep.twoPtrValue.ptr2) +#define SET_CHANNELINTERP(objPtr, storePtr) \ + ((objPtr)->internalRep.twoPtrValue.ptr2 = (void *) (storePtr)) + +#define BUSY_STATE(st,fl) \ ((((st)->csPtrR) && ((fl) & TCL_READABLE)) || \ (((st)->csPtrW) && ((fl) & TCL_WRITABLE))) @@ -346,39 +348,6 @@ static const Tcl_ObjType chanObjType = { /* *--------------------------------------------------------------------------- * - * ChanClose, ChanRead, ChanSeek, ChanThreadAction, ChanWatch, ChanWrite -- - * - * Simplify the access to selected channel driver "methods" that are used - * in multiple places in a stereotypical fashion. These are just thin - * wrappers around the driver functions. - * - *--------------------------------------------------------------------------- - */ - -static inline int -ChanClose( - Channel *chanPtr, - Tcl_Interp *interp) -{ - if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) { - return chanPtr->typePtr->closeProc(chanPtr->instanceData, interp); - } else { - return chanPtr->typePtr->close2Proc(chanPtr->instanceData, interp, 0); - } -} - -static inline int -ChanCloseHalf( - Channel *chanPtr, - Tcl_Interp *interp, - int flags) -{ - return chanPtr->typePtr->close2Proc(chanPtr->instanceData, interp, flags); -} - -/* - *--------------------------------------------------------------------------- - * * ChanRead -- * * Read up to dstSize bytes using the inputProc of chanPtr, store @@ -486,37 +455,6 @@ ChanSeek( Tcl_WideAsLong(offset), mode, errnoPtr)); } -static inline void -ChanThreadAction( - Channel *chanPtr, - int action) -{ - Tcl_DriverThreadActionProc *threadActionProc = - Tcl_ChannelThreadActionProc(chanPtr->typePtr); - - if (threadActionProc != NULL) { - threadActionProc(chanPtr->instanceData, action); - } -} - -static inline void -ChanWatch( - Channel *chanPtr, - int mask) -{ - chanPtr->typePtr->watchProc(chanPtr->instanceData, mask); -} - -static inline int -ChanWrite( - Channel *chanPtr, - const char *src, - int srcLen, - int *errnoPtr) -{ - return chanPtr->typePtr->outputProc(chanPtr->instanceData, src, srcLen, - errnoPtr); -} /* *--------------------------------------------------------------------------- @@ -572,19 +510,6 @@ TclFinalizeIOSubsystem(void) Channel *chanPtr = NULL; /* Iterates over open channels. */ ChannelState *statePtr; /* State of channel stack */ int active = 1; /* Flag == 1 while there's still work to do */ - int doflushnb; - - /* Fetch the pre-TIP#398 compatibility flag */ - { - const char *s; - Tcl_DString ds; - - s = TclGetEnv("TCL_FLUSH_NONBLOCKING_ON_EXIT", &ds); - doflushnb = ((s != NULL) && strcmp(s, "0")); - if (s != NULL) { - Tcl_DStringFree(&ds); - } - } /* * Walk all channel state structures known to this thread and close @@ -603,38 +528,26 @@ TclFinalizeIOSubsystem(void) statePtr != NULL; statePtr = statePtr->nextCSPtr) { chanPtr = statePtr->topChanPtr; - if (GotFlag(statePtr, CHANNEL_DEAD)) { - continue; - } - if (!GotFlag(statePtr, CHANNEL_INCLOSE | CHANNEL_CLOSED ) - || GotFlag(statePtr, BG_FLUSH_SCHEDULED)) { - ResetFlag(statePtr, BG_FLUSH_SCHEDULED); + if (!GotFlag(statePtr, CHANNEL_INCLOSE|CHANNEL_CLOSED|CHANNEL_DEAD)) { active = 1; break; } } /* - * We've found a live (or bg-closing) channel. Close it. + * We've found a live channel. Close it. */ if (active) { - - TclChannelPreserve((Tcl_Channel)chanPtr); /* - * TIP #398: by default, we no longer set the channel back into - * blocking mode. To restore the old blocking behavior, the - * environment variable TCL_FLUSH_NONBLOCKING_ON_EXIT must be set - * and not be "0". + * Set the channel back into blocking mode to ensure that we wait + * for all data to flush out. */ - if (doflushnb) { - /* Set the channel back into blocking mode to ensure that we wait - * for all data to flush out. - */ - (void) Tcl_SetChannelOption(NULL, (Tcl_Channel) chanPtr, - "-blocking", "on"); - } + TclChannelPreserve((Tcl_Channel)chanPtr); + + (void) Tcl_SetChannelOption(NULL, (Tcl_Channel) chanPtr, + "-blocking", "on"); if ((chanPtr == (Channel *) tsdPtr->stdinChannel) || (chanPtr == (Channel *) tsdPtr->stdoutChannel) || @@ -667,7 +580,12 @@ TclFinalizeIOSubsystem(void) * device for this channel. */ - (void) ChanClose(chanPtr, NULL); + if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) { + (chanPtr->typePtr->closeProc)(chanPtr->instanceData, NULL); + } else { + (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, + NULL, 0); + } /* * Finally, we clean up the fields in the channel data @@ -830,7 +748,7 @@ Tcl_CreateCloseHandler( ChannelState *statePtr = ((Channel *) chan)->state; CloseCallback *cbPtr; - cbPtr = ckalloc(sizeof(CloseCallback)); + cbPtr = (CloseCallback *) ckalloc(sizeof(CloseCallback)); cbPtr->proc = proc; cbPtr->clientData = clientData; @@ -876,10 +794,11 @@ Tcl_DeleteCloseHandler( } else { cbPrevPtr->nextPtr = cbPtr->nextPtr; } - ckfree(cbPtr); + ckfree((char *) cbPtr); break; + } else { + cbPrevPtr = cbPtr; } - cbPrevPtr = cbPtr; } } @@ -911,7 +830,7 @@ GetChannelTable( hTblPtr = Tcl_GetAssocData(interp, "tclIO", NULL); if (hTblPtr == NULL) { - hTblPtr = ckalloc(sizeof(Tcl_HashTable)); + hTblPtr = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable)); Tcl_InitHashTable(hTblPtr, TCL_STRING_KEYS); Tcl_SetAssocData(interp, "tclIO", (Tcl_InterpDeleteProc *) DeleteChannelTable, hTblPtr); @@ -1000,10 +919,10 @@ DeleteChannelTable( } Tcl_DeleteChannelHandler((Tcl_Channel) chanPtr, - TclChannelEventScriptInvoker, sPtr); + TclChannelEventScriptInvoker, (ClientData) sPtr); TclDecrRefCount(sPtr->scriptPtr); - ckfree(sPtr); + ckfree((char *) sPtr); } else { prevPtr = sPtr; } @@ -1017,8 +936,9 @@ DeleteChannelTable( */ Tcl_DeleteHashEntry(hPtr); - statePtr->epoch++; - if (statePtr->refCount-- <= 1) { + SetFlag(statePtr, CHANNEL_TAINTED); + statePtr->refCount--; + if (statePtr->refCount <= 0) { if (!GotFlag(statePtr, BG_FLUSH_SCHEDULED)) { (void) Tcl_Close(interp, (Tcl_Channel) chanPtr); } @@ -1026,7 +946,7 @@ DeleteChannelTable( } Tcl_DeleteHashTable(hTblPtr); - ckfree(hTblPtr); + ckfree((char *) hTblPtr); } /* @@ -1212,9 +1132,8 @@ Tcl_UnregisterChannel( if (GotFlag(statePtr, CHANNEL_INCLOSE)) { if (interp != NULL) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "illegal recursive call to close through close-handler" - " of channel", -1)); + Tcl_AppendResult(interp, "Illegal recursive call to close " + "through close-handler of channel", NULL); } return TCL_ERROR; } @@ -1240,7 +1159,7 @@ Tcl_UnregisterChannel( */ if (statePtr->refCount <= 0) { - Tcl_Preserve(statePtr); + Tcl_Preserve((ClientData)statePtr); if (!GotFlag(statePtr, BG_FLUSH_SCHEDULED)) { /* * We don't want to re-enter Tcl_Close(). @@ -1249,13 +1168,13 @@ Tcl_UnregisterChannel( if (!GotFlag(statePtr, CHANNEL_CLOSED)) { if (Tcl_Close(interp, chan) != TCL_OK) { SetFlag(statePtr, CHANNEL_CLOSED); - Tcl_Release(statePtr); + Tcl_Release((ClientData)statePtr); return TCL_ERROR; } } } SetFlag(statePtr, CHANNEL_CLOSED); - Tcl_Release(statePtr); + Tcl_Release((ClientData)statePtr); } return TCL_OK; } @@ -1361,7 +1280,7 @@ DetachChannel( return TCL_ERROR; } Tcl_DeleteHashEntry(hPtr); - statePtr->epoch++; + SetFlag(statePtr, CHANNEL_TAINTED); /* * Remove channel handlers that refer to this interpreter, so that @@ -1440,8 +1359,8 @@ Tcl_GetChannel( hTblPtr = GetChannelTable(interp); hPtr = Tcl_FindHashEntry(hTblPtr, name); if (hPtr == NULL) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "can not find channel named \"%s\"", chanName)); + Tcl_AppendResult(interp, "can not find channel named \"", chanName, + "\"", NULL); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CHANNEL", chanName, NULL); return NULL; } @@ -1455,7 +1374,7 @@ Tcl_GetChannel( chanPtr = Tcl_GetHashValue(hPtr); chanPtr = chanPtr->state->bottomChanPtr; if (modePtr != NULL) { - *modePtr = chanPtr->state->flags & (TCL_READABLE|TCL_WRITABLE); + *modePtr = GotFlag(chanPtr->state, TCL_READABLE|TCL_WRITABLE); } return (Tcl_Channel) chanPtr; @@ -1494,61 +1413,16 @@ TclGetChannelFromObj( int flags) { ChannelState *statePtr; - ResolvedChanName *resPtr = NULL; - Tcl_Channel chan; - if (interp == NULL) { + if (SetChannelFromAny(interp, objPtr) != TCL_OK) { return TCL_ERROR; } - if (objPtr->typePtr == &chanObjType) { - /* - * Confirm validity of saved lookup results. - */ - - resPtr = (ResolvedChanName *) objPtr->internalRep.twoPtrValue.ptr1; - statePtr = resPtr->statePtr; - if ((resPtr->interp == interp) /* Same interp context */ - /* No epoch change in channel since lookup */ - && (resPtr->epoch == statePtr->epoch)) { - - /* Have a valid saved lookup. Jump to end to return it. */ - goto valid; - } - } - - chan = Tcl_GetChannel(interp, TclGetString(objPtr), NULL); - - if (chan == NULL) { - if (resPtr) { - FreeChannelIntRep(objPtr); - } - return TCL_ERROR; - } - - if (resPtr && resPtr->refCount == 1) { - /* Re-use the ResolvedCmdName struct */ - Tcl_Release((ClientData) resPtr->statePtr); - - } else { - TclFreeIntRep(objPtr); - - resPtr = (ResolvedChanName *) ckalloc(sizeof(ResolvedChanName)); - resPtr->refCount = 1; - objPtr->internalRep.twoPtrValue.ptr1 = (ClientData) resPtr; - objPtr->typePtr = &chanObjType; - } - statePtr = ((Channel *)chan)->state; - resPtr->statePtr = statePtr; - Tcl_Preserve((ClientData) statePtr); - resPtr->interp = interp; - resPtr->epoch = statePtr->epoch; - - valid: - *channelPtr = (Tcl_Channel) statePtr->bottomChanPtr; + statePtr = GET_CHANNELSTATE(objPtr); + *channelPtr = (Tcl_Channel) (statePtr->bottomChanPtr); if (modePtr != NULL) { - *modePtr = statePtr->flags & (TCL_READABLE|TCL_WRITABLE); + *modePtr = GotFlag(statePtr, TCL_READABLE|TCL_WRITABLE); } return TCL_OK; @@ -1572,7 +1446,7 @@ TclGetChannelFromObj( Tcl_Channel Tcl_CreateChannel( - const Tcl_ChannelType *typePtr, /* The channel type record. */ + Tcl_ChannelType *typePtr, /* The channel type record. */ const char *chanName, /* Name of channel to record. */ ClientData instanceData, /* Instance specific data. */ int mask) /* TCL_READABLE & TCL_WRITABLE to indicate if @@ -1582,7 +1456,6 @@ Tcl_CreateChannel( ChannelState *statePtr; /* The stack-level independent state info for * the channel. */ const char *name; - char *tmp; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* @@ -1595,31 +1468,15 @@ Tcl_CreateChannel( * as well. */ - assert(sizeof(Tcl_ChannelTypeVersion) == sizeof(Tcl_DriverBlockModeProc *)); - assert(typePtr->typeName != NULL); - if (NULL == typePtr->closeProc) { - Tcl_Panic("channel type %s must define closeProc", typePtr->typeName); - } - if ((TCL_READABLE & mask) && (NULL == typePtr->inputProc)) { - Tcl_Panic("channel type %s must define inputProc when used for reader channel", typePtr->typeName); - } - if ((TCL_WRITABLE & mask) && (NULL == typePtr->outputProc)) { - Tcl_Panic("channel type %s must define outputProc when used for writer channel", typePtr->typeName); - } - if (NULL == typePtr->watchProc) { - Tcl_Panic("channel type %s must define watchProc", typePtr->typeName); - } - if ((NULL!=typePtr->wideSeekProc) && (NULL == typePtr->seekProc)) { - Tcl_Panic("channel type %s must define seekProc if defining wideSeekProc", typePtr->typeName); - } + assert(sizeof(Tcl_ChannelTypeVersion) == sizeof(Tcl_DriverBlockModeProc*)); /* * JH: We could subsequently memset these to 0 to avoid the numerous * assignments to 0/NULL below. */ - chanPtr = ckalloc(sizeof(Channel)); - statePtr = ckalloc(sizeof(ChannelState)); + chanPtr = (Channel *) ckalloc(sizeof(Channel)); + statePtr = (ChannelState *) ckalloc(sizeof(ChannelState)); chanPtr->state = statePtr; chanPtr->instanceData = instanceData; @@ -1631,20 +1488,14 @@ Tcl_CreateChannel( */ if (chanName != NULL) { - unsigned len = strlen(chanName) + 1; + char *tmp = ckalloc((unsigned) (strlen(chanName) + 1)); - /* - * Make sure we allocate at least 7 bytes, so it fits for "stdout" - * later. - */ - - tmp = ckalloc((len < 7) ? 7 : len); + statePtr->channelName = tmp; strcpy(tmp, chanName); } else { - tmp = ckalloc(7); - tmp[0] = '\0'; + Tcl_Panic("Tcl_CreateChannel: NULL channel name"); } - statePtr->channelName = tmp; + statePtr->flags = mask; /* @@ -1717,8 +1568,6 @@ Tcl_CreateChannel( statePtr->chanMsg = NULL; statePtr->unreportedMsg = NULL; - statePtr->epoch = 0; - /* * Link the channel into the list of all channels; create an on-exit * handler if there is not one already, to close off all the channels in @@ -1745,17 +1594,14 @@ Tcl_CreateChannel( */ if ((tsdPtr->stdinChannel == NULL) && (tsdPtr->stdinInitialized == 1)) { - strcpy(tmp, "stdin"); Tcl_SetStdChannel((Tcl_Channel) chanPtr, TCL_STDIN); Tcl_RegisterChannel(NULL, (Tcl_Channel) chanPtr); } else if ((tsdPtr->stdoutChannel == NULL) && (tsdPtr->stdoutInitialized == 1)) { - strcpy(tmp, "stdout"); Tcl_SetStdChannel((Tcl_Channel) chanPtr, TCL_STDOUT); Tcl_RegisterChannel(NULL, (Tcl_Channel) chanPtr); } else if ((tsdPtr->stderrChannel == NULL) && (tsdPtr->stderrInitialized == 1)) { - strcpy(tmp, "stderr"); Tcl_SetStdChannel((Tcl_Channel) chanPtr, TCL_STDERR); Tcl_RegisterChannel(NULL, (Tcl_Channel) chanPtr); } @@ -1792,8 +1638,7 @@ Tcl_CreateChannel( Tcl_Channel Tcl_StackChannel( Tcl_Interp *interp, /* The interpreter we are working in */ - const Tcl_ChannelType *typePtr, - /* The channel type record for the new + Tcl_ChannelType *typePtr, /* The channel type record for the new * channel. */ ClientData instanceData, /* Instance specific data for the new * channel. */ @@ -1804,6 +1649,7 @@ Tcl_StackChannel( ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); Channel *chanPtr, *prevChanPtr; ChannelState *statePtr; + Tcl_DriverThreadActionProc *threadActionProc; /* * Find the given channel (prevChan) in the list of all channels. If we do @@ -1821,9 +1667,8 @@ Tcl_StackChannel( if (statePtr == NULL) { if (interp) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "couldn't find state for channel \"%s\"", - Tcl_GetChannelName(prevChan))); + Tcl_AppendResult(interp, "couldn't find state for channel \"", + Tcl_GetChannelName(prevChan), "\"", NULL); } return NULL; } @@ -1841,11 +1686,11 @@ Tcl_StackChannel( * --+---+---+---+----+ */ - if ((mask & (statePtr->flags & (TCL_READABLE | TCL_WRITABLE))) == 0) { + if ((mask & (GotFlag(statePtr, TCL_READABLE | TCL_WRITABLE))) == 0) { if (interp) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "reading and writing both disallowed for channel \"%s\"", - Tcl_GetChannelName(prevChan))); + Tcl_AppendResult(interp, + "reading and writing both disallowed for channel \"", + Tcl_GetChannelName(prevChan), "\"", NULL); } return NULL; } @@ -1872,9 +1717,8 @@ Tcl_StackChannel( statePtr->csPtrR = csPtrR; statePtr->csPtrW = csPtrW; if (interp) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "could not flush channel \"%s\"", - Tcl_GetChannelName(prevChan))); + Tcl_AppendResult(interp, "could not flush channel \"", + Tcl_GetChannelName(prevChan), "\"", NULL); } return NULL; } @@ -1915,7 +1759,7 @@ Tcl_StackChannel( statePtr->inQueueTail = NULL; } - chanPtr = ckalloc(sizeof(Channel)); + chanPtr = (Channel *) ckalloc(sizeof(Channel)); /* * Save some of the current state into the new structure, reinitialize the @@ -1952,7 +1796,10 @@ Tcl_StackChannel( * time, mangling it. */ - ChanThreadAction(chanPtr, TCL_CHANNEL_THREAD_INSERT); + threadActionProc = Tcl_ChannelThreadActionProc(chanPtr->typePtr); + if (threadActionProc != NULL) { + (*threadActionProc)(chanPtr->instanceData, TCL_CHANNEL_THREAD_INSERT); + } return (Tcl_Channel) chanPtr; } @@ -1977,7 +1824,7 @@ TclChannelRelease( return; } if (chanPtr->typePtr == NULL) { - ckfree(chanPtr); + ckfree((char *)chanPtr); } } @@ -1986,7 +1833,7 @@ ChannelFree( Channel *chanPtr) { if (chanPtr->refCount == 0) { - ckfree(chanPtr); + ckfree((char *)chanPtr); return; } chanPtr->typePtr = NULL; @@ -2018,6 +1865,7 @@ Tcl_UnstackChannel( Channel *chanPtr = (Channel *) chan; ChannelState *statePtr = chanPtr->state; int result = 0; + Tcl_DriverThreadActionProc *threadActionProc; /* * This operation should occur at the top of a channel stack. @@ -2028,9 +1876,9 @@ Tcl_UnstackChannel( if (chanPtr->downChanPtr != NULL) { /* * Instead of manipulating the per-thread / per-interp list/hashtable - * of registered channels we wind down the state of the - * transformation, and then restore the state of underlying channel - * into the old structure. + * of registered channels we wind down the state of the transformation, + * and then restore the state of underlying channel into the old + * structure. */ /* @@ -2070,9 +1918,9 @@ Tcl_UnstackChannel( */ if (!TclChanCaughtErrorBypass(interp, chan) && interp) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "could not flush channel \"%s\"", - Tcl_GetChannelName((Tcl_Channel) chanPtr))); + Tcl_AppendResult(interp, "could not flush channel \"", + Tcl_GetChannelName((Tcl_Channel) chanPtr), "\"", + NULL); } return TCL_ERROR; } @@ -2122,7 +1970,11 @@ Tcl_UnstackChannel( * the state which are still active. */ - ChanThreadAction(chanPtr, TCL_CHANNEL_THREAD_REMOVE); + threadActionProc = Tcl_ChannelThreadActionProc(chanPtr->typePtr); + if (threadActionProc != NULL) { + (*threadActionProc)(chanPtr->instanceData, + TCL_CHANNEL_THREAD_REMOVE); + } statePtr->topChanPtr = downChanPtr; downChanPtr->upChanPtr = NULL; @@ -2136,7 +1988,14 @@ Tcl_UnstackChannel( * Close and free the channel driver state. */ - result = ChanClose(chanPtr, interp); + if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) { + result = (chanPtr->typePtr->closeProc)(chanPtr->instanceData, + interp); + } else { + result = (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, + interp, 0); + } + ChannelFree(chanPtr); UpdateInterest(statePtr->topChanPtr); @@ -2307,7 +2166,7 @@ Tcl_GetChannelThread( *---------------------------------------------------------------------- */ -const Tcl_ChannelType * +Tcl_ChannelType * Tcl_GetChannelType( Tcl_Channel chan) /* The channel to return type for. */ { @@ -2342,7 +2201,7 @@ Tcl_GetChannelMode( ChannelState *statePtr = ((Channel *) chan)->state; /* State of actual channel. */ - return (statePtr->flags & (TCL_READABLE | TCL_WRITABLE)); + return GotFlag(statePtr, TCL_READABLE | TCL_WRITABLE); } /* @@ -2366,9 +2225,9 @@ const char * Tcl_GetChannelName( Tcl_Channel chan) /* The channel for which to return the name. */ { - ChannelState *statePtr = ((Channel *) chan)->state; - /* State of actual channel. */ + ChannelState *statePtr; /* State of actual channel. */ + statePtr = ((Channel *) chan)->state; return statePtr->channelName; } @@ -2401,13 +2260,15 @@ Tcl_GetChannelHandle( chanPtr = ((Channel *) chan)->state->bottomChanPtr; if (!chanPtr->typePtr->getHandleProc) { - Tcl_SetChannelError(chan, Tcl_ObjPrintf( - "channel \"%s\" does not support OS handles", - Tcl_GetChannelName(chan))); + Tcl_Obj* err; + TclNewLiteralStringObj(err, "channel \""); + Tcl_AppendToObj(err, Tcl_GetChannelName(chan), -1); + Tcl_AppendToObj(err, "\" does not support OS handles", -1); + Tcl_SetChannelError (chan,err); return TCL_ERROR; } - result = chanPtr->typePtr->getHandleProc(chanPtr->instanceData, direction, - &handle); + result = (chanPtr->typePtr->getHandleProc)(chanPtr->instanceData, + direction, &handle); if (handlePtr) { *handlePtr = handle; } @@ -2446,7 +2307,7 @@ AllocChannelBuffer( int n; n = length + CHANNELBUFFER_HEADER_SIZE + BUFFER_PADDING + BUFFER_PADDING; - bufPtr = ckalloc(n); + bufPtr = (ChannelBuffer *) ckalloc((unsigned) n); bufPtr->nextAdded = BUFFER_PADDING; bufPtr->nextRemoved = BUFFER_PADDING; bufPtr->bufLength = length + BUFFER_PADDING; @@ -2459,9 +2320,6 @@ static void PreserveChannelBuffer( ChannelBuffer *bufPtr) { - if (bufPtr->refCount == 0) { - Tcl_Panic("Reuse of ChannelBuffer! %p", bufPtr); - } bufPtr->refCount++; } @@ -2472,7 +2330,7 @@ ReleaseChannelBuffer( if (--bufPtr->refCount) { return; } - ckfree(bufPtr); + ckfree((char *) bufPtr); } static int @@ -2629,16 +2487,15 @@ CheckForDeadChannel( Tcl_Interp *interp, /* For error reporting (can be NULL) */ ChannelState *statePtr) /* The channel state to check. */ { - if (!GotFlag(statePtr, CHANNEL_DEAD)) { - return 0; - } - - Tcl_SetErrno(EINVAL); - if (interp) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "unable to access channel: invalid channel", -1)); + if (GotFlag(statePtr, CHANNEL_DEAD)) { + Tcl_SetErrno(EINVAL); + if (interp) { + Tcl_AppendResult(interp, + "unable to access channel: invalid channel", NULL); + } + return 1; } - return 1; + return 0; } /* @@ -2646,9 +2503,9 @@ CheckForDeadChannel( * * FlushChannel -- * - * This function flushes as much of the queued output as is possible now. - * If calledFromAsyncFlush is nonzero, it is being called in an event - * handler to flush channel output asynchronously. + * This function flushes as much of the queued output as is possible + * now. If calledFromAsyncFlush is nonzero, it is being called in an + * event handler to flush channel output asynchronously. * * Results: * 0 if successful, else the error code that was returned by the channel @@ -2699,7 +2556,7 @@ FlushChannel( * the post-condition that on a successful return to caller we've * left space in the current output buffer for more writing (the flush * call was to make new room). - * If the channel is blocking, then yes, so we guarantee that + * If the channel is blocking, then yes, so we guarantee that * blocking flushes actually flush all pending data. * Otherwise, no. Keep the current output buffer where it is so more * can be written to it, possibly filling it, to promote more efficient @@ -2744,8 +2601,8 @@ FlushChannel( */ PreserveChannelBuffer(bufPtr); - written = ChanWrite(chanPtr, RemovePoint(bufPtr), BytesLeft(bufPtr), - &errorCode); + written = (chanPtr->typePtr->outputProc)(chanPtr->instanceData, + RemovePoint(bufPtr), BytesLeft(bufPtr), &errorCode); /* * If the write failed completely attempt to start the asynchronous @@ -2777,7 +2634,7 @@ FlushChannel( * it's a tty channel (dup'ed underneath) */ - if (!GotFlag(statePtr, BG_FLUSH_SCHEDULED) && !TclInExit()) { + if (!GotFlag(statePtr, BG_FLUSH_SCHEDULED)) { SetFlag(statePtr, BG_FLUSH_SCHEDULED); UpdateInterest(chanPtr); } @@ -2828,8 +2685,14 @@ FlushChannel( Tcl_SetErrno(errorCode); if (interp != NULL && !TclChanCaughtErrorBypass(interp, (Tcl_Channel) chanPtr)) { - Tcl_SetObjResult(interp, - Tcl_NewStringObj(Tcl_PosixError(interp), -1)); + /* + * Casting away const here is safe because the + * TCL_VOLATILE flag guarantees const treatment of the + * Posix error string. + */ + + Tcl_SetResult(interp, (char *) Tcl_PosixError(interp), + TCL_VOLATILE); } /* @@ -2880,26 +2743,14 @@ FlushChannel( goto done; } else if (statePtr->outQueueHead == NULL) { ResetFlag(statePtr, BG_FLUSH_SCHEDULED); - ChanWatch(chanPtr, statePtr->interestMask); + (chanPtr->typePtr->watchProc)(chanPtr->instanceData, + statePtr->interestMask); } else { - - /* - * When we are calledFromAsyncFlush, that means a writable - * state on the channel triggered the call, so we should be - * able to write something. Either we did write something - * and wroteSome should be set, or there was nothing left to - * write in this call, and we've completed the BG flush. - * These are the two cases above. If we get here, that means - * there is some kind failure in the writable event machinery. - * - * The tls extension indeed suffers from flaws in its channel - * event mgmt. See http://core.tcl.tk/tcl/info/c31ca233ca. - * Until that patch is broadly distributed, disable the - * assertion checking here, so that programs using Tcl and - * tls can be debugged. - - assert(!calledFromAsyncFlush); - */ + /* TODO: If code reaches this point, it means a writable + * event is being handled on the channel, but the channel + * could not in fact be written to. This ought not happen, + * but Unix pipes appear to act this way (see io-53.4). + * Also can imagine broken reflected channels. */ } } @@ -2914,23 +2765,7 @@ FlushChannel( ((statePtr->curOutPtr == NULL) || IsBufferEmpty(statePtr->curOutPtr))) { errorCode = CloseChannel(interp, chanPtr, errorCode); - goto done; } - - /* - * If the write-side of the channel is flagged as closed, delete it when - * the output queue is empty and there is no output in the current output - * buffer. - */ - - if (GotFlag(statePtr, CHANNEL_CLOSEDWRITE) && - (statePtr->outQueueHead == NULL) && - ((statePtr->curOutPtr == NULL) || - IsBufferEmpty(statePtr->curOutPtr))) { - errorCode = CloseChannelPart(interp, chanPtr, errorCode, TCL_CLOSE_WRITE); - goto done; - } - done: TclChannelRelease((Tcl_Channel)chanPtr); return errorCode; @@ -3007,7 +2842,7 @@ CloseChannel( int dummy; char c = (char) statePtr->outEofChar; - (void) ChanWrite(chanPtr, &c, 1, &dummy); + (chanPtr->typePtr->outputProc)(chanPtr->instanceData, &c, 1, &dummy); } /* @@ -3018,7 +2853,7 @@ CloseChannel( if (statePtr->chanMsg != NULL) { if (interp != NULL) { - Tcl_SetChannelErrorInterp(interp, statePtr->chanMsg); + Tcl_SetChannelErrorInterp(interp,statePtr->chanMsg); } TclDecrRefCount(statePtr->chanMsg); statePtr->chanMsg = NULL; @@ -3035,7 +2870,12 @@ CloseChannel( * This may leave a TIP #219 error message in the interp. */ - result = ChanClose(chanPtr, interp); + if (chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) { + result = (chanPtr->typePtr->closeProc)(chanPtr->instanceData, interp); + } else { + result = (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, + interp, 0); + } /* * Some resources can be cleared only if the bottom channel in a stack is @@ -3044,7 +2884,7 @@ CloseChannel( if (chanPtr == statePtr->bottomChanPtr) { if (statePtr->channelName != NULL) { - ckfree(statePtr->channelName); + ckfree((char *) statePtr->channelName); statePtr->channelName = NULL; } @@ -3070,7 +2910,7 @@ CloseChannel( statePtr->chanMsg = NULL; } if (interp) { - Tcl_SetChannelErrorInterp(interp, statePtr->unreportedMsg); + Tcl_SetChannelErrorInterp(interp,statePtr->unreportedMsg); } } if (errorCode == 0) { @@ -3153,6 +2993,7 @@ CutChannel( * the list on close. */ ChannelState *statePtr = ((Channel *) chan)->state; /* State of the channel stack. */ + Tcl_DriverThreadActionProc *threadActionProc; /* * Remove this channel from of the list of all channels (in the current @@ -3179,7 +3020,11 @@ CutChannel( * TIP #218, Channel Thread Actions */ - ChanThreadAction((Channel *) chan, TCL_CHANNEL_THREAD_REMOVE); + threadActionProc = Tcl_ChannelThreadActionProc(Tcl_GetChannelType(chan)); + if (threadActionProc != NULL) { + (*threadActionProc)(Tcl_GetChannelInstanceData(chan), + TCL_CHANNEL_THREAD_REMOVE); + } } void @@ -3194,6 +3039,7 @@ Tcl_CutChannel( * the list on close. */ ChannelState *statePtr = chanPtr->state; /* State of the channel stack. */ + Tcl_DriverThreadActionProc *threadActionProc; /* * Remove this channel from of the list of all channels (in the current @@ -3221,8 +3067,13 @@ Tcl_CutChannel( * For all transformations and the base channel. */ - for (; chanPtr != NULL ; chanPtr = chanPtr->upChanPtr) { - ChanThreadAction(chanPtr, TCL_CHANNEL_THREAD_REMOVE); + while (chanPtr) { + threadActionProc = Tcl_ChannelThreadActionProc(chanPtr->typePtr); + if (threadActionProc != NULL) { + (*threadActionProc)(chanPtr->instanceData, + TCL_CHANNEL_THREAD_REMOVE); + } + chanPtr= chanPtr->upChanPtr; } } @@ -3259,6 +3110,7 @@ SpliceChannel( { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); ChannelState *statePtr = ((Channel *) chan)->state; + Tcl_DriverThreadActionProc *threadActionProc; if (statePtr->nextCSPtr != NULL) { Tcl_Panic("SpliceChannel: trying to add channel used in different list"); @@ -3279,7 +3131,11 @@ SpliceChannel( * TIP #218, Channel Thread Actions */ - ChanThreadAction((Channel *) chan, TCL_CHANNEL_THREAD_INSERT); + threadActionProc = Tcl_ChannelThreadActionProc(Tcl_GetChannelType(chan)); + if (threadActionProc != NULL) { + (*threadActionProc) (Tcl_GetChannelInstanceData(chan), + TCL_CHANNEL_THREAD_INSERT); + } } void @@ -3290,6 +3146,7 @@ Tcl_SpliceChannel( Channel *chanPtr = ((Channel *) chan)->state->bottomChanPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); ChannelState *statePtr = chanPtr->state; + Tcl_DriverThreadActionProc *threadActionProc; if (statePtr->nextCSPtr != NULL) { Tcl_Panic("SpliceChannel: trying to add channel used in different list"); @@ -3311,8 +3168,13 @@ Tcl_SpliceChannel( * For all transformations and the base channel. */ - for (; chanPtr != NULL ; chanPtr = chanPtr->upChanPtr) { - ChanThreadAction(chanPtr, TCL_CHANNEL_THREAD_INSERT); + while (chanPtr) { + threadActionProc = Tcl_ChannelThreadActionProc(chanPtr->typePtr); + if (threadActionProc != NULL) { + (*threadActionProc)(chanPtr->instanceData, + TCL_CHANNEL_THREAD_INSERT); + } + chanPtr= chanPtr->upChanPtr; } } @@ -3381,9 +3243,8 @@ Tcl_Close( if (GotFlag(statePtr, CHANNEL_INCLOSE)) { if (interp) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "illegal recursive call to close through close-handler" - " of channel", -1)); + Tcl_AppendResult(interp, "Illegal recursive call to close " + "through close-handler of channel", NULL); } return TCL_ERROR; } @@ -3419,7 +3280,7 @@ Tcl_Close( if (statePtr->chanMsg != NULL) { if (interp != NULL) { - Tcl_SetChannelErrorInterp(interp, statePtr->chanMsg); + Tcl_SetChannelErrorInterp(interp,statePtr->chanMsg); } TclDecrRefCount(statePtr->chanMsg); statePtr->chanMsg = NULL; @@ -3435,8 +3296,8 @@ Tcl_Close( while (statePtr->closeCbPtr != NULL) { cbPtr = statePtr->closeCbPtr; statePtr->closeCbPtr = cbPtr->nextPtr; - cbPtr->proc(cbPtr->clientData); - ckfree(cbPtr); + (cbPtr->proc)(cbPtr->clientData); + ckfree((char *) cbPtr); } ResetFlag(statePtr, CHANNEL_INCLOSE); @@ -3447,7 +3308,7 @@ Tcl_Close( */ if (chanPtr->typePtr->closeProc == TCL_CLOSE2PROC) { - result = chanPtr->typePtr->close2Proc(chanPtr->instanceData, interp, + result = (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, interp, TCL_CLOSE_READ); } else { result = 0; @@ -3507,341 +3368,6 @@ Tcl_Close( /* *---------------------------------------------------------------------- * - * Tcl_CloseEx -- - * - * Closes one side of a channel, read or write. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * Closes one direction of the channel. - * - * NOTE: - * Tcl_CloseEx closes the specified direction of the channel as far as - * the user is concerned. The channel keeps existing however. You cannot - * calls this function to close the last possible direction of the - * channel. Use Tcl_Close for that. - * - *---------------------------------------------------------------------- - */ - - /* ARGSUSED */ -int -Tcl_CloseEx( - Tcl_Interp *interp, /* Interpreter for errors. */ - Tcl_Channel chan, /* The channel being closed. May still be used - * by some interpreter. */ - int flags) /* Flags telling us which side to close. */ -{ - Channel *chanPtr; /* The real IO channel. */ - ChannelState *statePtr; /* State of real IO channel. */ - - if (chan == NULL) { - return TCL_OK; - } - - /* TODO: assert flags validity ? */ - - chanPtr = (Channel *) chan; - statePtr = chanPtr->state; - - /* - * Does the channel support half-close anyway? Error if not. - */ - - if (!chanPtr->typePtr->close2Proc) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "half-close of channels not supported by %ss", - chanPtr->typePtr->typeName)); - return TCL_ERROR; - } - - /* - * Is the channel unstacked ? If not we fail. - */ - - if (chanPtr != statePtr->topChanPtr) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "half-close not applicable to stack of transformations", -1)); - return TCL_ERROR; - } - - /* - * Check direction against channel mode. It is an error if we try to close - * a direction not supported by the channel (already closed, or never - * opened for that direction). - */ - - if (!(statePtr->flags & (TCL_READABLE | TCL_WRITABLE) & flags)) { - const char *msg; - - if (flags & TCL_CLOSE_READ) { - msg = "read"; - } else { - msg = "write"; - } - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "Half-close of %s-side not possible, side not opened or" - " already closed", msg)); - return TCL_ERROR; - } - - /* - * A user may try to call half-close from within a channel close - * handler. That won't do. - */ - - if (statePtr->flags & CHANNEL_INCLOSE) { - if (interp) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "illegal recursive call to close through close-handler" - " of channel", -1)); - } - return TCL_ERROR; - } - - if (flags & TCL_CLOSE_READ) { - /* - * Call the finalization code directly. There are no events to handle, - * there cannot be for the read-side. - */ - - return CloseChannelPart(interp, chanPtr, 0, flags); - } else if (flags & TCL_CLOSE_WRITE) { - Tcl_Preserve(statePtr); - if (!GotFlag(statePtr, BG_FLUSH_SCHEDULED)) { - /* - * We don't want to re-enter CloseWrite(). - */ - - if (!GotFlag(statePtr, CHANNEL_CLOSEDWRITE)) { - if (CloseWrite(interp, chanPtr) != TCL_OK) { - SetFlag(statePtr, CHANNEL_CLOSEDWRITE); - Tcl_Release(statePtr); - return TCL_ERROR; - } - } - } - SetFlag(statePtr, CHANNEL_CLOSEDWRITE); - Tcl_Release(statePtr); - } - - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * CloseWrite -- - * - * Closes the write side a channel. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * Closes the write side of the channel. - * - * NOTE: - * CloseWrite removes the channel as far as the user is concerned. - * However, the ooutput data structures may continue to exist for a while - * longer if it has a background flush scheduled. The device itself is - * eventually closed and the channel structures modified, in - * CloseChannelPart, below. - * - *---------------------------------------------------------------------- - */ - -static int -CloseWrite( - Tcl_Interp *interp, /* Interpreter for errors. */ - Channel *chanPtr) /* The channel whose write side is being - * closed. May still be used by some - * interpreter */ -{ - /* Notes: clear-channel-handlers - write side only ? or keep around, just - * not called. */ - /* No close cllbacks are run - channel is still open (read side) */ - - ChannelState *statePtr = chanPtr->state; - /* State of real IO channel. */ - int flushcode; - int result = 0; - - /* - * The call to FlushChannel will flush any queued output and invoke the - * close function of the channel driver, or it will set up the channel to - * be flushed and closed asynchronously. - */ - - SetFlag(statePtr, CHANNEL_CLOSEDWRITE); - - flushcode = FlushChannel(interp, chanPtr, 0); - - /* - * TIP #219. - * Capture error messages put by the driver into the bypass area and put - * them into the regular interpreter result. - * - * Notes: Due to the assertion of CHANNEL_CLOSEDWRITE in the flags - * FlushChannel() has called CloseChannelPart(). While we can still access - * "chan" (no structures were freed), the only place which may still - * contain a message is the interpreter itself, and "CloseChannelPart" made - * sure to lift any channel message it generated into it. Hence the NULL - * argument in the call below. - */ - - if (TclChanCaughtErrorBypass(interp, NULL)) { - result = EINVAL; - } - - if ((flushcode != 0) || (result != 0)) { - return TCL_ERROR; - } - - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * CloseChannelPart -- - * - * Utility procedure to close a channel partially and free associated - * resources. If the channel was stacked it will never be run (The higher - * level forbid this). If the channel was not stacked, then we will free - * all the bits of the chosen side (read, or write) for the TOP channel. - * - * Results: - * Error code from an unreported error or the driver close2 operation. - * - * Side effects: - * May free memory, may change the value of errno. - * - *---------------------------------------------------------------------- - */ - -static int -CloseChannelPart( - Tcl_Interp *interp, /* Interpreter for errors. */ - Channel *chanPtr, /* The channel being closed. May still be used - * by some interpreter. */ - int errorCode, /* Status of operation so far. */ - int flags) /* Flags telling us which side to close. */ -{ - ChannelState *statePtr; /* State of real IO channel. */ - int result; /* Of calling the close2proc. */ - - statePtr = chanPtr->state; - - if (flags & TCL_CLOSE_READ) { - /* - * No more input can be consumed so discard any leftover input. - */ - - DiscardInputQueued(statePtr, 1); - } else if (flags & TCL_CLOSE_WRITE) { - /* - * The caller guarantees that there are no more buffers queued for - * output. - */ - - if (statePtr->outQueueHead != NULL) { - Tcl_Panic("ClosechanHalf, closed write-side of channel: " - "queued output left"); - } - - /* - * If the EOF character is set in the channel, append that to the - * output device. - */ - - if ((statePtr->outEofChar != 0) && GotFlag(statePtr, TCL_WRITABLE)) { - int dummy; - char c = (char) statePtr->outEofChar; - - (void) ChanWrite(chanPtr, &c, 1, &dummy); - } - - /* - * TIP #219, Tcl Channel Reflection API. - * Move a leftover error message in the channel bypass into the - * interpreter bypass. Just clear it if there is no interpreter. - */ - - if (statePtr->chanMsg != NULL) { - if (interp != NULL) { - Tcl_SetChannelErrorInterp(interp, statePtr->chanMsg); - } - TclDecrRefCount(statePtr->chanMsg); - statePtr->chanMsg = NULL; - } - } - - /* - * Finally do what is asked of us. Close and free the channel driver state - * for the chosen side of the channel. This may leave a TIP #219 error - * message in the interp. - */ - - result = ChanCloseHalf(chanPtr, interp, flags); - - /* - * If we are being called synchronously, report either any latent error on - * the channel or the current error. - */ - - if (statePtr->unreportedError != 0) { - errorCode = statePtr->unreportedError; - - /* - * TIP #219, Tcl Channel Reflection API. - * Move an error message found in the unreported area into the regular - * bypass (interp). This kills any message in the channel bypass area. - */ - - if (statePtr->chanMsg != NULL) { - TclDecrRefCount(statePtr->chanMsg); - statePtr->chanMsg = NULL; - } - if (interp) { - Tcl_SetChannelErrorInterp(interp, statePtr->unreportedMsg); - } - } - if (errorCode == 0) { - errorCode = result; - if (errorCode != 0) { - Tcl_SetErrno(errorCode); - } - } - - /* - * TIP #219. - * Capture error messages put by the driver into the bypass area and put - * them into the regular interpreter result. See also the bottom of - * CloseWrite(). - */ - - if (TclChanCaughtErrorBypass(interp, (Tcl_Channel) chanPtr)) { - result = EINVAL; - } - - if (result != 0) { - return TCL_ERROR; - } - - /* - * Remove the closed side from the channel mode/flags. - */ - - ResetFlag(statePtr, flags & (TCL_READABLE | TCL_WRITABLE)); - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * * Tcl_ClearChannelHandlers -- * * Removes all channel handlers and event scripts from the channel, @@ -3901,7 +3427,7 @@ Tcl_ClearChannelHandlers( for (chPtr = statePtr->chPtr; chPtr != NULL; chPtr = chNext) { chNext = chPtr->nextPtr; - ckfree(chPtr); + ckfree((char *) chPtr); } statePtr->chPtr = NULL; @@ -3928,7 +3454,7 @@ Tcl_ClearChannelHandlers( for (ePtr = statePtr->scriptRecordPtr; ePtr != NULL; ePtr = eNextPtr) { eNextPtr = ePtr->nextPtr; TclDecrRefCount(ePtr->scriptPtr); - ckfree(ePtr); + ckfree((char *) ePtr); } statePtr->scriptRecordPtr = NULL; } @@ -4036,7 +3562,9 @@ Tcl_WriteRaw( * The code was stolen from 'FlushChannel'. */ - written = ChanWrite(chanPtr, src, srcLen, &errorCode); + written = (chanPtr->typePtr->outputProc) (chanPtr->instanceData, + src, srcLen, &errorCode); + if (written < 0) { Tcl_SetErrno(errorCode); } @@ -4147,7 +3675,7 @@ Tcl_WriteObj( Channel *chanPtr; ChannelState *statePtr; /* State info for channel */ - const char *src; + char *src; int srcLen; statePtr = ((Channel *) chan)->state; @@ -4165,24 +3693,19 @@ Tcl_WriteObj( } } -static void -WillWrite( - Channel *chanPtr) +static void WillWrite(Channel *chanPtr) { int inputBuffered; - if ((chanPtr->typePtr->seekProc != NULL) && - ((inputBuffered = Tcl_InputBuffered((Tcl_Channel) chanPtr)) > 0)){ + if ((chanPtr->typePtr->seekProc != NULL) + && ((inputBuffered = Tcl_InputBuffered((Tcl_Channel) chanPtr)) > 0)) { int ignore; - DiscardInputQueued(chanPtr->state, 0); - ChanSeek(chanPtr, -inputBuffered, SEEK_CUR, &ignore); + ChanSeek(chanPtr, - inputBuffered, SEEK_CUR, &ignore); } } -static int -WillRead( - Channel *chanPtr) +static int WillRead(Channel *chanPtr) { if (chanPtr->typePtr == NULL) { /* Prevent read attempts on a closed channel */ @@ -4191,7 +3714,7 @@ WillRead( return -1; } if ((chanPtr->typePtr->seekProc != NULL) - && (Tcl_OutputBuffered((Tcl_Channel) chanPtr) > 0)) { + && (Tcl_OutputBuffered((Tcl_Channel) chanPtr) > 0)) { /* * CAVEAT - The assumption here is that FlushChannel() will @@ -4266,7 +3789,7 @@ Write( if (nextNewLine) { srcLimit = nextNewLine - src; } - + /* Get space to write into */ bufPtr = statePtr->curOutPtr; if (bufPtr == NULL) { @@ -4294,7 +3817,7 @@ Write( /* See chan-io-1.[89]. Tcl Bug 506297. */ statePtr->outputEncodingFlags &= ~TCL_ENCODING_START; - + if ((result != TCL_OK) && (srcRead + dstWrote == 0)) { /* We're reading from invalid/incomplete UTF-8 */ ReleaseChannelBuffer(bufPtr); @@ -4334,7 +3857,7 @@ Write( Tcl_Panic("unknown output translation requested"); break; } - + result |= Tcl_UtfToExternal(NULL, encoding, nl, nlLen, statePtr->outputEncodingFlags, &statePtr->outputEncodingState, dst, @@ -4431,12 +3954,14 @@ Tcl_Gets( * for managing the storage. */ { Tcl_Obj *objPtr; - int charsStored; + int charsStored, length; + char *string; TclNewObj(objPtr); charsStored = Tcl_GetsObj(chan, objPtr); if (charsStored > 0) { - TclDStringAppendObj(lineRead, objPtr); + string = TclGetStringFromObj(objPtr, &length); + Tcl_DStringAppend(lineRead, string, length); } TclDecrRefCount(objPtr); return charsStored; @@ -4658,14 +4183,14 @@ Tcl_GetsObj( * Skip the raw bytes that make up the '\n'. */ - char tmp[TCL_UTF_MAX]; + char tmp[1 + TCL_UTF_MAX]; int rawRead; bufPtr = gs.bufPtr; Tcl_ExternalToUtf(NULL, gs.encoding, RemovePoint(bufPtr), - gs.rawRead, statePtr->inputEncodingFlags - | TCL_ENCODING_NO_TERMINATE, &gs.state, tmp, - TCL_UTF_MAX, &rawRead, NULL, NULL); + gs.rawRead, statePtr->inputEncodingFlags, + &gs.state, tmp, 1 + TCL_UTF_MAX, &rawRead, NULL, + NULL); bufPtr->nextRemoved += rawRead; gs.rawRead -= rawRead; gs.bytesWrote--; @@ -4766,9 +4291,8 @@ Tcl_GetsObj( } statePtr->inputEncodingState = gs.state; Tcl_ExternalToUtf(NULL, gs.encoding, RemovePoint(bufPtr), gs.rawRead, - statePtr->inputEncodingFlags | TCL_ENCODING_NO_TERMINATE, - &statePtr->inputEncodingState, dst, - eol - dst + skip + TCL_UTF_MAX - 1, &gs.rawRead, NULL, + statePtr->inputEncodingFlags, &statePtr->inputEncodingState, dst, + eol - dst + skip + TCL_UTF_MAX, &gs.rawRead, NULL, &gs.charsWrote); bufPtr->nextRemoved += gs.rawRead; @@ -4922,11 +4446,7 @@ TclGetsObjBinary( skip = 0; eof = NULL; inEofChar = statePtr->inEofChar; - - /* - * Only handle TCL_TRANSLATE_LF and TCL_TRANSLATE_CR. - */ - + /* Only handle TCL_TRANSLATE_LF and TCL_TRANSLATE_CR */ eolChar = (statePtr->inputTranslation == TCL_TRANSLATE_LF) ? '\n' : '\r'; ResetFlag(statePtr, CHANNEL_BLOCKED); @@ -5300,9 +4820,9 @@ FilterInputBytes( } gsPtr->state = statePtr->inputEncodingState; result = Tcl_ExternalToUtf(NULL, gsPtr->encoding, raw, rawLen, - statePtr->inputEncodingFlags | TCL_ENCODING_NO_TERMINATE, - &statePtr->inputEncodingState, dst, spaceLeft, &gsPtr->rawRead, - &gsPtr->bytesWrote, &gsPtr->charsWrote); + statePtr->inputEncodingFlags, &statePtr->inputEncodingState, + dst, spaceLeft+1, &gsPtr->rawRead, &gsPtr->bytesWrote, + &gsPtr->charsWrote); /* * Make sure that if we go through 'gets', that we reset the @@ -5500,7 +5020,7 @@ CommonGetsCleanup( extra = SpaceLeft(bufPtr); if (extra > 0) { memcpy(InsertPoint(bufPtr), - nextPtr->buf + (BUFFER_PADDING - extra), + nextPtr->buf + BUFFER_PADDING - extra, (size_t) extra); bufPtr->nextAdded += extra; nextPtr->nextRemoved = BUFFER_PADDING; @@ -5552,7 +5072,7 @@ Tcl_Read( return -1; } - return DoRead(chanPtr, dst, bytesToRead, 0); + return DoRead(chanPtr, dst, bytesToRead); } /* @@ -5764,7 +5284,7 @@ DoReadChars( int factor = UTF_EXPANSION_FACTOR; binaryMode = (encoding == NULL) - && (statePtr->inputTranslation == TCL_TRANSLATE_LF) + && (statePtr->inputTranslation == TCL_TRANSLATE_LF) && (statePtr->inEofChar == '\0'); if (appendFlag == 0) { @@ -5821,7 +5341,7 @@ DoReadChars( chanPtr = statePtr->topChanPtr; TclChannelPreserve((Tcl_Channel)chanPtr); - /* Must clear the BLOCKED|EOF flags here since we check before reading */ + /* Must clear the BLOCKED flag here since we check before reading */ if (GotFlag(statePtr, CHANNEL_EOF)) { statePtr->inputEncodingFlags |= TCL_ENCODING_START; } @@ -5842,8 +5362,9 @@ DoReadChars( bufPtr = statePtr->inQueueHead; if (IsBufferEmpty(bufPtr)) { - ChannelBuffer *nextPtr = bufPtr->nextPtr; + ChannelBuffer *nextPtr; + nextPtr = bufPtr->nextPtr; RecycleBuffer(statePtr, bufPtr, 0); statePtr->inQueueHead = nextPtr; if (nextPtr == NULL) { @@ -6019,7 +5540,7 @@ ReadChars( int savedIEFlags = statePtr->inputEncodingFlags; int savedFlags = statePtr->flags; char *dst, *src = RemovePoint(bufPtr); - int numBytes, srcLen = BytesLeft(bufPtr); + int dstLimit, numBytes, srcLen = BytesLeft(bufPtr); /* * One src byte can yield at most one character. So when the @@ -6029,23 +5550,23 @@ ReadChars( * for sizing receiving buffers. */ - int toRead = ((charsToRead<0)||(charsToRead > srcLen)) ? srcLen : charsToRead; + int toRead = ((unsigned) charsToRead > (unsigned) srcLen) ? srcLen : charsToRead; /* * 'factor' is how much we guess that the bytes in the source buffer will * expand when converted to UTF-8 chars. This guess comes from analyzing * how many characters were produced by the previous pass. */ - + int factor = *factorPtr; - int dstLimit = TCL_UTF_MAX - 1 + toRead * factor / UTF_EXPANSION_FACTOR; + int dstNeeded = TCL_UTF_MAX - 1 + toRead * factor / UTF_EXPANSION_FACTOR; (void) TclGetStringFromObj(objPtr, &numBytes); - Tcl_AppendToObj(objPtr, NULL, dstLimit); + Tcl_AppendToObj(objPtr, NULL, dstNeeded); if (toRead == srcLen) { unsigned int size; dst = TclGetStringStorage(objPtr, &size) + numBytes; - dstLimit = size - numBytes; + dstNeeded = size - numBytes; } else { dst = TclGetString(objPtr) + numBytes; } @@ -6066,14 +5587,9 @@ ReadChars( * a consistent set of results. This takes the shape of a loop. */ + dstLimit = dstNeeded + 1; while (1) { int dstDecoded, dstRead, dstWrote, srcRead, numChars, code; - int flags = statePtr->inputEncodingFlags | TCL_ENCODING_NO_TERMINATE; - - if (charsToRead > 0) { - flags |= TCL_ENCODING_CHAR_LIMIT; - numChars = charsToRead; - } /* * Perform the encoding transformation. Read no more than @@ -6094,7 +5610,7 @@ ReadChars( || (statePtr->inputEncodingFlags & TCL_ENCODING_END) == 0); code = Tcl_ExternalToUtf(NULL, encoding, src, srcLen, - flags, &statePtr->inputEncodingState, + statePtr->inputEncodingFlags, &statePtr->inputEncodingState, dst, dstLimit, &srcRead, &dstDecoded, &numChars); /* @@ -6158,7 +5674,7 @@ ReadChars( * time. */ - dstLimit = dstRead - 1 + TCL_UTF_MAX; + dstLimit = dstRead + TCL_UTF_MAX; statePtr->flags = savedFlags; statePtr->inputEncodingFlags = savedIEFlags; statePtr->inputEncodingState = savedState; @@ -6184,7 +5700,7 @@ ReadChars( * up back here in this call. */ - dstLimit = dstRead - 1 + TCL_UTF_MAX; + dstLimit = dstRead + TCL_UTF_MAX; statePtr->flags = savedFlags; statePtr->inputEncodingFlags = savedIEFlags; statePtr->inputEncodingState = savedState; @@ -6201,10 +5717,10 @@ ReadChars( */ if (code != TCL_OK) { - char buffer[TCL_UTF_MAX + 1]; + char buffer[TCL_UTF_MAX + 2]; int read, decoded, count; - /* + /* * Didn't get everything the buffer could offer */ @@ -6217,9 +5733,8 @@ ReadChars( (statePtr->inputEncodingFlags & TCL_ENCODING_END)); Tcl_ExternalToUtf(NULL, encoding, src, srcLen, - (statePtr->inputEncodingFlags | TCL_ENCODING_NO_TERMINATE), - &statePtr->inputEncodingState, buffer, TCL_UTF_MAX + 1, - &read, &decoded, &count); + statePtr->inputEncodingFlags, &statePtr->inputEncodingState, + buffer, TCL_UTF_MAX + 2, &read, &decoded, &count); if (count == 2) { if (buffer[1] == '\n') { @@ -6231,13 +5746,14 @@ ReadChars( bufPtr->nextRemoved += srcRead; } + dst[1] = '\0'; statePtr->inputEncodingFlags &= ~TCL_ENCODING_START; Tcl_SetObjLength(objPtr, numBytes + 1); return 1; } - } else if (statePtr->flags & CHANNEL_EOF) { + } else if (GotFlag(statePtr, CHANNEL_EOF)) { /* * The bare \r is the only char and we will never read @@ -6260,7 +5776,7 @@ ReadChars( /* FALL THROUGH - get more data (dstWrote == 0) */ } - /* + /* * The translation transformation can only reduce the number * of chars when it converts \r\n into \n. The reduction in * the number of chars is the difference in bytes read and written. @@ -6270,16 +5786,14 @@ ReadChars( if (charsToRead > 0 && numChars > charsToRead) { - /* - * TODO: This cannot happen anymore. - * + /* * We read more chars than allowed. Reset limits to * prevent that and try again. Don't forget the extra * padding of TCL_UTF_MAX bytes demanded by the * Tcl_ExternalToUtf() call! */ - dstLimit = Tcl_UtfAtIndex(dst, charsToRead) - 1 + TCL_UTF_MAX - dst; + dstLimit = Tcl_UtfAtIndex(dst, charsToRead) + TCL_UTF_MAX - dst; statePtr->flags = savedFlags; statePtr->inputEncodingFlags = savedIEFlags; statePtr->inputEncodingState = savedState; @@ -6293,7 +5807,7 @@ ReadChars( assert (numChars == 0); - /* + /* * There is one situation where this is the correct final * result. If the src buffer contains only a single \n * byte, and we are in TCL_TRANSLATE_AUTO mode, and @@ -6303,8 +5817,9 @@ ReadChars( * empty string. */ - if (dstRead == 1 && dst[0] == '\n') { + if (dst[0] == '\n') { assert(statePtr->inputTranslation == TCL_TRANSLATE_AUTO); + assert(dstRead == 1); goto consume; } @@ -6386,7 +5901,7 @@ ReadChars( *--------------------------------------------------------------------------- */ -static void +static void TranslateInputEOL( ChannelState *statePtr, /* Channel being read, for EOL translation and * EOF character. */ @@ -6496,7 +6011,7 @@ TranslateInputEOL( char *dst = dstStart; int lesser; - if ((statePtr->flags & INPUT_SAW_CR) && srcLen) { + if (GotFlag(statePtr, INPUT_SAW_CR) && srcLen) { if (*src == '\n') { src++; srcLen--; } ResetFlag(statePtr, INPUT_SAW_CR); } @@ -6592,7 +6107,7 @@ Tcl_Ungets( /* * Clear the EOF flags, and clear the BLOCKED bit. */ - + if (GotFlag(statePtr, CHANNEL_EOF)) { statePtr->inputEncodingFlags |= TCL_ENCODING_START; } @@ -6749,7 +6264,7 @@ GetInput( ChannelState *statePtr = chanPtr->state; /* State info for channel */ - /* + /* * Verify that all callers know better than to call us when * it's recorded that the next char waiting to be read is the * eofchar. @@ -6971,8 +6486,8 @@ Tcl_Seek( if (GotFlag(statePtr, CHANNEL_EOF)) { statePtr->inputEncodingFlags |= TCL_ENCODING_START; } - ResetFlag(statePtr, CHANNEL_EOF | CHANNEL_STICKY_EOF | CHANNEL_BLOCKED | - INPUT_SAW_CR); + statePtr->flags &= + ~(CHANNEL_EOF | CHANNEL_STICKY_EOF | CHANNEL_BLOCKED | INPUT_SAW_CR); statePtr->inputEncodingFlags &= ~TCL_ENCODING_END; /* @@ -7008,10 +6523,23 @@ Tcl_Seek( } else { /* * Now seek to the new position in the channel as requested by the - * caller. + * caller. Note that we prefer the wideSeekProc if that is available + * and non-NULL... */ - curPos = ChanSeek(chanPtr, offset, mode, &result); + if (HaveVersion(chanPtr->typePtr, TCL_CHANNEL_VERSION_3) && + chanPtr->typePtr->wideSeekProc != NULL) { + curPos = (chanPtr->typePtr->wideSeekProc) (chanPtr->instanceData, + offset, mode, &result); + } else if (offset < Tcl_LongAsWide(LONG_MIN) || + offset > Tcl_LongAsWide(LONG_MAX)) { + result = EOVERFLOW; + curPos = Tcl_LongAsWide(-1); + } else { + curPos = Tcl_LongAsWide((chanPtr->typePtr->seekProc) ( + chanPtr->instanceData, Tcl_WideAsLong(offset), mode, + &result)); + } if (curPos == Tcl_LongAsWide(-1)) { Tcl_SetErrno(result); } @@ -7106,13 +6634,25 @@ Tcl_Tell( inputBuffered = Tcl_InputBuffered(chan); outputBuffered = Tcl_OutputBuffered(chan); + if ((inputBuffered != 0) && (outputBuffered != 0)) { + /*Tcl_SetErrno(EFAULT);*/ + /*return Tcl_LongAsWide(-1);*/ + } + /* * Get the current position in the device and compute the position where * the next character will be read or written. Note that we prefer the * wideSeekProc if that is available and non-NULL... */ - curPos = ChanSeek(chanPtr, Tcl_LongAsWide(0), SEEK_CUR, &result); + if (HaveVersion(chanPtr->typePtr, TCL_CHANNEL_VERSION_3) && + chanPtr->typePtr->wideSeekProc != NULL) { + curPos = (chanPtr->typePtr->wideSeekProc) (chanPtr->instanceData, + Tcl_LongAsWide(0), SEEK_CUR, &result); + } else { + curPos = Tcl_LongAsWide((chanPtr->typePtr->seekProc) ( + chanPtr->instanceData, 0, SEEK_CUR, &result)); + } if (curPos == Tcl_LongAsWide(-1)) { Tcl_SetErrno(result); return Tcl_LongAsWide(-1); @@ -7127,6 +6667,48 @@ Tcl_Tell( /* *--------------------------------------------------------------------------- * + * Tcl_SeekOld, Tcl_TellOld -- + * + * Backward-compatability versions of the seek/tell interface that do not + * support 64-bit offsets. This interface is not documented or expected + * to be supported indefinitely. + * + * Results: + * As for Tcl_Seek and Tcl_Tell respectively, except truncated to + * whatever value will fit in an 'int'. + * + * Side effects: + * As for Tcl_Seek and Tcl_Tell respectively. + * + *--------------------------------------------------------------------------- + */ + +int +Tcl_SeekOld( + Tcl_Channel chan, /* The channel on which to seek. */ + int offset, /* Offset to seek to. */ + int mode) /* Relative to which location to seek? */ +{ + Tcl_WideInt wOffset, wResult; + + wOffset = Tcl_LongAsWide((long)offset); + wResult = Tcl_Seek(chan, wOffset, mode); + return (int)Tcl_WideAsLong(wResult); +} + +int +Tcl_TellOld( + Tcl_Channel chan) /* The channel to return pos for. */ +{ + Tcl_WideInt wResult; + + wResult = Tcl_Tell(chan); + return (int)Tcl_WideAsLong(wResult); +} + +/* + *--------------------------------------------------------------------------- + * * Tcl_TruncateChannel -- * * Truncate a channel to the given length. @@ -7162,7 +6744,7 @@ Tcl_TruncateChannel( return TCL_ERROR; } - if (!GotFlag(chanPtr->state, TCL_WRITABLE)) { + if (!(chanPtr->state->flags & TCL_WRITABLE)) { /* * We require that the file was opened of writing. Do that check now * so that we only flush if we think we're going to succeed. @@ -7259,7 +6841,7 @@ CheckChannelErrors( * Fail if the channel is not opened for desired operation. */ - if ((statePtr->flags & direction) == 0) { + if (GotFlag(statePtr, direction) == 0) { Tcl_SetErrno(EACCES); return -1; } @@ -7486,9 +7068,9 @@ Tcl_SetChannelBufferSize( */ if (sz < 1) { - sz = 1; + sz = 1; } else if (sz > MAX_CHANNEL_BUFFER_SIZE) { - sz = MAX_CHANNEL_BUFFER_SIZE; + sz = MAX_CHANNEL_BUFFER_SIZE; } statePtr = ((Channel *) chan)->state; @@ -7585,12 +7167,11 @@ Tcl_BadChannelOption( const char **argv; int argc, i; Tcl_DString ds; - Tcl_Obj *errObj; Tcl_DStringInit(&ds); Tcl_DStringAppend(&ds, genericopt, -1); if (optionList && (*optionList)) { - TclDStringAppendLiteral(&ds, " "); + Tcl_DStringAppend(&ds, " ", 1); Tcl_DStringAppend(&ds, optionList, -1); } if (Tcl_SplitList(interp, Tcl_DStringValue(&ds), @@ -7598,16 +7179,15 @@ Tcl_BadChannelOption( Tcl_Panic("malformed option list in channel driver"); } Tcl_ResetResult(interp); - errObj = Tcl_ObjPrintf("bad option \"%s\": should be one of ", - optionName); + Tcl_AppendResult(interp, "bad option \"", optionName, + "\": should be one of ", NULL); argc--; for (i = 0; i < argc; i++) { - Tcl_AppendPrintfToObj(errObj, "-%s, ", argv[i]); + Tcl_AppendResult(interp, "-", argv[i], ", ", NULL); } - Tcl_AppendPrintfToObj(errObj, "or -%s", argv[i]); - Tcl_SetObjResult(interp, errObj); + Tcl_AppendResult(interp, "or -", argv[i], NULL); Tcl_DStringFree(&ds); - ckfree(argv); + ckfree((char *) argv); } Tcl_SetErrno(EINVAL); return TCL_ERROR; @@ -7669,9 +7249,9 @@ Tcl_GetChannelOption( */ if (statePtr->csPtrR) { - flags = statePtr->csPtrR->readFlags; + flags = statePtr->csPtrR->readFlags; } else if (statePtr->csPtrW) { - flags = statePtr->csPtrW->writeFlags; + flags = statePtr->csPtrW->writeFlags; } else { flags = statePtr->flags; } @@ -7831,8 +7411,8 @@ Tcl_GetChannelOption( * and message. */ - return chanPtr->typePtr->getOptionProc(chanPtr->instanceData, interp, - optionName, dsPtr); + return (chanPtr->typePtr->getOptionProc) (chanPtr->instanceData, + interp, optionName, dsPtr); } else { /* * No driver specific options case. @@ -7883,9 +7463,8 @@ Tcl_SetChannelOption( if (statePtr->csPtrR || statePtr->csPtrW) { if (interp) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "unable to set channel options: background copy in" - " progress", -1)); + Tcl_AppendResult(interp, "unable to set channel options: " + "background copy in progress", NULL); } return TCL_ERROR; } @@ -7924,7 +7503,8 @@ Tcl_SetChannelOption( } else if (HaveOpt(7, "-buffering")) { len = strlen(newValue); if ((newValue[0] == 'f') && (strncmp(newValue, "full", len) == 0)) { - ResetFlag(statePtr, CHANNEL_UNBUFFERED | CHANNEL_LINEBUFFERED); + statePtr->flags &= + ~(CHANNEL_UNBUFFERED|CHANNEL_LINEBUFFERED); } else if ((newValue[0] == 'l') && (strncmp(newValue, "line", len) == 0)) { ResetFlag(statePtr, CHANNEL_UNBUFFERED); @@ -7933,11 +7513,12 @@ Tcl_SetChannelOption( (strncmp(newValue, "none", len) == 0)) { ResetFlag(statePtr, CHANNEL_LINEBUFFERED); SetFlag(statePtr, CHANNEL_UNBUFFERED); - } else if (interp) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "bad value for -buffering: must be one of" - " full, line, or none", -1)); - return TCL_ERROR; + } else { + if (interp) { + Tcl_AppendResult(interp, "bad value for -buffering: " + "must be one of full, line, or none", NULL); + return TCL_ERROR; + } } return TCL_OK; } else if (HaveOpt(7, "-buffersize")) { @@ -7991,14 +7572,12 @@ Tcl_SetChannelOption( int outIndex = (argc - 1); int inValue = (int) argv[0][0]; int outValue = (int) argv[outIndex][0]; - if (inValue & 0x80 || outValue & 0x80) { if (interp) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "bad value for -eofchar: must be non-NUL ASCII" - " character", -1)); + Tcl_AppendResult(interp, "bad value for -eofchar: ", + "must be non-NUL ASCII character", NULL); } - ckfree(argv); + ckfree((char *) argv); return TCL_ERROR; } if (GotFlag(statePtr, TCL_READABLE)) { @@ -8009,15 +7588,15 @@ Tcl_SetChannelOption( } } else { if (interp) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( + Tcl_AppendResult(interp, "bad value for -eofchar: should be a list of zero," - " one, or two elements", -1)); + " one, or two elements", NULL); } - ckfree(argv); + ckfree((char *) argv); return TCL_ERROR; } if (argv != NULL) { - ckfree(argv); + ckfree((char *) argv); } /* @@ -8029,8 +7608,10 @@ Tcl_SetChannelOption( if (GotFlag(statePtr, CHANNEL_EOF)) { statePtr->inputEncodingFlags |= TCL_ENCODING_START; } - ResetFlag(statePtr, CHANNEL_EOF|CHANNEL_STICKY_EOF|CHANNEL_BLOCKED); + statePtr->flags &= + ~(CHANNEL_EOF | CHANNEL_STICKY_EOF | CHANNEL_BLOCKED); statePtr->inputEncodingFlags &= ~TCL_ENCODING_END; + return TCL_OK; } else if (HaveOpt(1, "-translation")) { const char *readMode, *writeMode; @@ -8047,17 +7628,16 @@ Tcl_SetChannelOption( writeMode = GotFlag(statePtr, TCL_WRITABLE) ? argv[1] : NULL; } else { if (interp) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( + Tcl_AppendResult(interp, "bad value for -translation: must be a one or two" - " element list", -1)); + " element list", NULL); } - ckfree(argv); + ckfree((char *) argv); return TCL_ERROR; } if (readMode) { TclEolTranslation translation; - if (*readMode == '\0') { translation = statePtr->inputTranslation; } else if (strcmp(readMode, "auto") == 0) { @@ -8077,11 +7657,12 @@ Tcl_SetChannelOption( translation = TCL_PLATFORM_TRANSLATION; } else { if (interp) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "bad value for -translation: must be one of " - "auto, binary, cr, lf, crlf, or platform", -1)); + Tcl_AppendResult(interp, + "bad value for -translation: " + "must be one of auto, binary, cr, lf, crlf," + " or platform", NULL); } - ckfree(argv); + ckfree((char *) argv); return TCL_ERROR; } @@ -8127,19 +7708,20 @@ Tcl_SetChannelOption( statePtr->outputTranslation = TCL_PLATFORM_TRANSLATION; } else { if (interp) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "bad value for -translation: must be one of " - "auto, binary, cr, lf, crlf, or platform", -1)); + Tcl_AppendResult(interp, + "bad value for -translation: " + "must be one of auto, binary, cr, lf, crlf," + " or platform", NULL); } - ckfree(argv); + ckfree((char *) argv); return TCL_ERROR; } } - ckfree(argv); + ckfree((char *) argv); return TCL_OK; } else if (chanPtr->typePtr->setOptionProc != NULL) { - return chanPtr->typePtr->setOptionProc(chanPtr->instanceData, interp, - optionName, newValue); + return (*chanPtr->typePtr->setOptionProc)(chanPtr->instanceData, + interp, optionName, newValue); } else { return Tcl_BadChannelOption(interp, optionName, NULL); } @@ -8194,7 +7776,7 @@ CleanupChannelHandlers( TclChannelEventScriptInvoker, sPtr); TclDecrRefCount(sPtr->scriptPtr); - ckfree(sPtr); + ckfree((char *) sPtr); } else { prevPtr = sPtr; } @@ -8247,14 +7829,14 @@ Tcl_NotifyChannel( * their own events and pass them upward. */ - while (mask && (chanPtr->upChanPtr != NULL)) { + while (mask && (chanPtr->upChanPtr != (NULL))) { Tcl_DriverHandlerProc *upHandlerProc; upChanPtr = chanPtr->upChanPtr; upTypePtr = upChanPtr->typePtr; upHandlerProc = Tcl_ChannelHandlerProc(upTypePtr); if (upHandlerProc != NULL) { - mask = upHandlerProc(upChanPtr->instanceData, mask); + mask = (*upHandlerProc) (upChanPtr->instanceData, mask); } /* @@ -8301,7 +7883,7 @@ Tcl_NotifyChannel( /* * Add this invocation to the list of recursive invocations of - * Tcl_NotifyChannel. + * ChannelHandlerEventProc. */ nh.nextHandlerPtr = NULL; @@ -8316,7 +7898,7 @@ Tcl_NotifyChannel( if ((chPtr->mask & mask) != 0) { nh.nextHandlerPtr = chPtr->nextPtr; - chPtr->proc(chPtr->clientData, chPtr->mask & mask); + (*(chPtr->proc))(chPtr->clientData, chPtr->mask & mask); chPtr = nh.nextHandlerPtr; } else { chPtr = chPtr->nextPtr; @@ -8437,12 +8019,12 @@ UpdateInterest( mask &= ~TCL_EXCEPTION; if (!statePtr->timer) { - statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME, - ChannelTimerProc, chanPtr); + statePtr->timer = Tcl_CreateTimerHandler(0, ChannelTimerProc, + chanPtr); } } } - ChanWatch(chanPtr, mask); + (chanPtr->typePtr->watchProc)(chanPtr->instanceData, mask); } /* @@ -8479,8 +8061,7 @@ ChannelTimerProc( * before UpdateInterest gets called by Tcl_NotifyChannel. */ - statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME, - ChannelTimerProc,chanPtr); + statePtr->timer = Tcl_CreateTimerHandler(0, ChannelTimerProc,chanPtr); Tcl_Preserve(statePtr); Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_READABLE); Tcl_Release(statePtr); @@ -8541,7 +8122,7 @@ Tcl_CreateChannelHandler( } } if (chPtr == NULL) { - chPtr = ckalloc(sizeof(ChannelHandler)); + chPtr = (ChannelHandler *) ckalloc(sizeof(ChannelHandler)); chPtr->mask = 0; chPtr->proc = proc; chPtr->clientData = clientData; @@ -8625,7 +8206,7 @@ Tcl_DeleteChannelHandler( } /* - * If Tcl_NotifyChannel is about to process this handler, tell it to + * If ChannelHandlerEventProc is about to process this handler, tell it to * process the next one instead - we are going to delete *this* one. */ @@ -8645,7 +8226,7 @@ Tcl_DeleteChannelHandler( } else { prevChPtr->nextPtr = chPtr->nextPtr; } - ckfree(chPtr); + ckfree((char *) chPtr); /* * Recompute the interest list for the channel, so that infinite loops @@ -8696,7 +8277,6 @@ DeleteScriptRecord( if (esPtr == statePtr->scriptRecordPtr) { statePtr->scriptRecordPtr = esPtr->nextPtr; } else { - CLANG_ASSERT(prevEsPtr); prevEsPtr->nextPtr = esPtr->nextPtr; } @@ -8704,7 +8284,7 @@ DeleteScriptRecord( TclChannelEventScriptInvoker, esPtr); TclDecrRefCount(esPtr->scriptPtr); - ckfree(esPtr); + ckfree((char *) esPtr); break; } @@ -8753,12 +8333,12 @@ CreateScriptRecord( makeCH = (esPtr == NULL); if (makeCH) { - esPtr = ckalloc(sizeof(EventScriptRecord)); + esPtr = (EventScriptRecord *) ckalloc(sizeof(EventScriptRecord)); } /* * Initialize the structure before calling Tcl_CreateChannelHandler, - * because a reflected channel calling 'chan postevent' aka + * because a reflected channel caling 'chan postevent' aka * 'Tcl_NotifyChannel' in its 'watch'Proc will invoke * 'TclChannelEventScriptInvoker' immediately, and we do not wish it to * see uninitialized memory and crash. See [Bug 2918110]. @@ -8836,7 +8416,7 @@ TclChannelEventScriptInvoker( if (chanPtr->typePtr != NULL) { DeleteScriptRecord(interp, chanPtr, mask); } - Tcl_BackgroundException(interp, result); + TclBackgroundException(interp, result); } TclChannelRelease((Tcl_Channel)chanPtr); Tcl_Release(interp); @@ -8873,11 +8453,11 @@ Tcl_FileEventObjCmd( Channel *chanPtr; /* The channel to create the handler for. */ ChannelState *statePtr; /* State info for channel */ Tcl_Channel chan; /* The opaque type for the channel. */ - const char *chanName; + char *chanName; int modeIndex; /* Index of mode argument. */ int mask; - static const char *const modeOptions[] = {"readable", "writable", NULL}; - static const int maskArray[] = {TCL_READABLE, TCL_WRITABLE}; + static const char *modeOptions[] = {"readable", "writable", NULL}; + static CONST int maskArray[] = {TCL_READABLE, TCL_WRITABLE}; if ((objc != 3) && (objc != 4)) { Tcl_WrongNumArgs(interp, 1, objv, "channelId event ?script?"); @@ -8896,9 +8476,9 @@ Tcl_FileEventObjCmd( } chanPtr = (Channel *) chan; statePtr = chanPtr->state; - if ((statePtr->flags & mask) == 0) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf("channel is not %s", - (mask == TCL_READABLE) ? "readable" : "writable")); + if (GotFlag(statePtr, mask) == 0) { + Tcl_AppendResult(interp, "channel is not ", + (mask == TCL_READABLE) ? "readable" : "writable", NULL); return TCL_ERROR; } @@ -8908,7 +8488,6 @@ Tcl_FileEventObjCmd( if (objc == 3) { EventScriptRecord *esPtr; - for (esPtr = statePtr->scriptRecordPtr; esPtr != NULL; esPtr = esPtr->nextPtr) { if ((esPtr->interp == interp) && (esPtr->mask == mask)) { @@ -8988,23 +8567,11 @@ ZeroTransferTimerProc( */ int -TclCopyChannelOld( - Tcl_Interp *interp, /* Current interpreter. */ - Tcl_Channel inChan, /* Channel to read from. */ - Tcl_Channel outChan, /* Channel to write to. */ - int toRead, /* Amount of data to copy, or -1 for all. */ - Tcl_Obj *cmdPtr) /* Pointer to script to execute or NULL. */ -{ - return TclCopyChannel(interp, inChan, outChan, (Tcl_WideInt) toRead, - cmdPtr); -} - -int TclCopyChannel( Tcl_Interp *interp, /* Current interpreter. */ Tcl_Channel inChan, /* Channel to read from. */ Tcl_Channel outChan, /* Channel to write to. */ - Tcl_WideInt toRead, /* Amount of data to copy, or -1 for all. */ + int toRead, /* Amount of data to copy, or -1 for all. */ Tcl_Obj *cmdPtr) /* Pointer to script to execute or NULL. */ { Channel *inPtr = (Channel *) inChan; @@ -9013,22 +8580,21 @@ TclCopyChannel( int readFlags, writeFlags; CopyState *csPtr; int nonBlocking = (cmdPtr) ? CHANNEL_NONBLOCKING : 0; - int moveBytes; inStatePtr = inPtr->state; outStatePtr = outPtr->state; - if (BUSY_STATE(inStatePtr, TCL_READABLE)) { + if (BUSY_STATE(inStatePtr,TCL_READABLE)) { if (interp) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "channel \"%s\" is busy", Tcl_GetChannelName(inChan))); + Tcl_AppendResult(interp, "channel \"", + Tcl_GetChannelName(inChan), "\" is busy", NULL); } return TCL_ERROR; } - if (BUSY_STATE(outStatePtr, TCL_WRITABLE)) { + if (BUSY_STATE(outStatePtr,TCL_WRITABLE)) { if (interp) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "channel \"%s\" is busy", Tcl_GetChannelName(outChan))); + Tcl_AppendResult(interp, "channel \"", + Tcl_GetChannelName(outChan), "\" is busy", NULL); } return TCL_ERROR; } @@ -9061,19 +8627,8 @@ TclCopyChannel( * Make sure the output side is unbuffered. */ - outStatePtr->flags = (outStatePtr->flags & ~CHANNEL_LINEBUFFERED) - | CHANNEL_UNBUFFERED; - - /* - * Test for conditions where we know we can just move bytes from input - * channel to output channel with no transformation or even examination - * of the bytes themselves. - */ - - moveBytes = inStatePtr->inEofChar == '\0' /* No eofChar to stop input */ - && inStatePtr->inputTranslation == TCL_TRANSLATE_LF - && outStatePtr->outputTranslation == TCL_TRANSLATE_LF - && inStatePtr->encoding == outStatePtr->encoding; + outStatePtr->flags = (outStatePtr->flags & ~(CHANNEL_LINEBUFFERED)) + | CHANNEL_UNBUFFERED; /* * Allocate a new CopyState to maintain info about the current copy in @@ -9081,14 +8636,14 @@ TclCopyChannel( * completed. */ - csPtr = ckalloc(sizeof(CopyState) + !moveBytes * inStatePtr->bufSize); - csPtr->bufSize = !moveBytes * inStatePtr->bufSize; + csPtr = (CopyState *) ckalloc(sizeof(CopyState) + inStatePtr->bufSize); + csPtr->bufSize = inStatePtr->bufSize; csPtr->readPtr = inPtr; csPtr->writePtr = outPtr; csPtr->readFlags = readFlags; csPtr->writeFlags = writeFlags; csPtr->toRead = toRead; - csPtr->total = (Tcl_WideInt) 0; + csPtr->total = 0; csPtr->interp = interp; if (cmdPtr) { Tcl_IncrRefCount(cmdPtr); @@ -9098,10 +8653,6 @@ TclCopyChannel( inStatePtr->csPtrR = csPtr; outStatePtr->csPtrW = csPtr; - if (moveBytes) { - return MoveBytes(csPtr); - } - /* * Special handling of -size 0 async transfers, so that the -command is * still called asynchronously. @@ -9136,236 +8687,6 @@ TclCopyChannel( *---------------------------------------------------------------------- */ -static void -MBCallback( - CopyState *csPtr, - Tcl_Obj *errObj) -{ - Tcl_Obj *cmdPtr = Tcl_DuplicateObj(csPtr->cmdPtr); - Tcl_WideInt total = csPtr->total; - Tcl_Interp *interp = csPtr->interp; - int code; - - Tcl_IncrRefCount(cmdPtr); - StopCopy(csPtr); - - /* TODO: What if cmdPtr is not a list?! */ - - Tcl_ListObjAppendElement(NULL, cmdPtr, Tcl_NewWideIntObj(total)); - if (errObj) { - Tcl_ListObjAppendElement(NULL, cmdPtr, errObj); - } - - Tcl_Preserve(interp); - code = Tcl_EvalObjEx(interp, cmdPtr, TCL_EVAL_GLOBAL); - if (code != TCL_OK) { - Tcl_BackgroundException(interp, code); - } - Tcl_Release(interp); - TclDecrRefCount(cmdPtr); -} - -static void -MBError( - CopyState *csPtr, - int mask, - int errorCode) -{ - Tcl_Channel inChan = (Tcl_Channel) csPtr->readPtr; - Tcl_Channel outChan = (Tcl_Channel) csPtr->writePtr; - Tcl_Obj *errObj; - - Tcl_SetErrno(errorCode); - - errObj = Tcl_ObjPrintf( "error %sing \"%s\": %s", - (mask & TCL_READABLE) ? "read" : "writ", - Tcl_GetChannelName((mask & TCL_READABLE) ? inChan : outChan), - Tcl_PosixError(csPtr->interp)); - - if (csPtr->cmdPtr) { - MBCallback(csPtr, errObj); - } else { - Tcl_SetObjResult(csPtr->interp, errObj); - StopCopy(csPtr); - } -} - -static void -MBEvent( - ClientData clientData, - int mask) -{ - CopyState *csPtr = (CopyState *) clientData; - Tcl_Channel inChan = (Tcl_Channel) csPtr->readPtr; - Tcl_Channel outChan = (Tcl_Channel) csPtr->writePtr; - ChannelState *inStatePtr = csPtr->readPtr->state; - - if (mask & TCL_WRITABLE) { - Tcl_DeleteChannelHandler(inChan, MBEvent, csPtr); - Tcl_DeleteChannelHandler(outChan, MBEvent, csPtr); - switch (MBWrite(csPtr)) { - case TCL_OK: - MBCallback(csPtr, NULL); - break; - case TCL_CONTINUE: - Tcl_CreateChannelHandler(inChan, TCL_READABLE, MBEvent, csPtr); - break; - } - } else if (mask & TCL_READABLE) { - if (TCL_OK == MBRead(csPtr)) { - /* When at least one full buffer is present, stop reading. */ - if (IsBufferFull(inStatePtr->inQueueHead) - || !Tcl_InputBlocked(inChan)) { - Tcl_DeleteChannelHandler(inChan, MBEvent, csPtr); - } - - /* Successful read -- set up to write the bytes we read */ - Tcl_CreateChannelHandler(outChan, TCL_WRITABLE, MBEvent, csPtr); - } - } -} - -static int -MBRead( - CopyState *csPtr) -{ - ChannelState *inStatePtr = csPtr->readPtr->state; - ChannelBuffer *bufPtr = inStatePtr->inQueueHead; - int code; - - if (bufPtr && BytesLeft(bufPtr) > 0) { - return TCL_OK; - } - - code = GetInput(inStatePtr->topChanPtr); - if (code == 0 || GotFlag(inStatePtr, CHANNEL_BLOCKED)) { - return TCL_OK; - } else { - MBError(csPtr, TCL_READABLE, code); - return TCL_ERROR; - } -} - -static int -MBWrite( - CopyState *csPtr) -{ - ChannelState *inStatePtr = csPtr->readPtr->state; - ChannelState *outStatePtr = csPtr->writePtr->state; - ChannelBuffer *bufPtr = inStatePtr->inQueueHead; - ChannelBuffer *tail = NULL; - int code; - Tcl_WideInt inBytes = 0; - - /* Count up number of bytes waiting in the input queue */ - while (bufPtr) { - inBytes += BytesLeft(bufPtr); - tail = bufPtr; - if (csPtr->toRead != -1 && csPtr->toRead < inBytes) { - /* Queue has enough bytes to complete the copy */ - break; - } - bufPtr = bufPtr->nextPtr; - } - - if (bufPtr) { - /* Split the overflowing buffer in two */ - int extra = (int) (inBytes - csPtr->toRead); - /* Note that going with int for extra assumes that inBytes is not too - * much over toRead to require a wide itself. If that gets violated - * then the calculations involving extra must be made wide too. - * - * Noted with Win32/MSVC debug build treating the warning (possible of - * data in int64 to int conversion) as error. - */ - - bufPtr = AllocChannelBuffer(extra); - - tail->nextAdded -= extra; - memcpy(InsertPoint(bufPtr), InsertPoint(tail), extra); - bufPtr->nextAdded += extra; - bufPtr->nextPtr = tail->nextPtr; - tail->nextPtr = NULL; - inBytes = csPtr->toRead; - } - - /* Update the byte counts */ - if (csPtr->toRead != -1) { - csPtr->toRead -= inBytes; - } - csPtr->total += inBytes; - - /* Move buffers from input to output channels */ - if (outStatePtr->outQueueTail) { - outStatePtr->outQueueTail->nextPtr = inStatePtr->inQueueHead; - } else { - outStatePtr->outQueueHead = inStatePtr->inQueueHead; - } - outStatePtr->outQueueTail = tail; - inStatePtr->inQueueHead = bufPtr; - if (inStatePtr->inQueueTail == tail) { - inStatePtr->inQueueTail = bufPtr; - } - if (bufPtr == NULL) { - inStatePtr->inQueueTail = NULL; - } - - code = FlushChannel(csPtr->interp, outStatePtr->topChanPtr, 0); - if (code) { - MBError(csPtr, TCL_WRITABLE, code); - return TCL_ERROR; - } - if (csPtr->toRead == 0 || GotFlag(inStatePtr, CHANNEL_EOF)) { - return TCL_OK; - } - return TCL_CONTINUE; -} - -static int -MoveBytes( - CopyState *csPtr) /* State of copy operation. */ -{ - ChannelState *outStatePtr = csPtr->writePtr->state; - ChannelBuffer *bufPtr = outStatePtr->curOutPtr; - int errorCode; - - if (bufPtr && BytesLeft(bufPtr)) { - /* If we start with unflushed bytes in the destination - * channel, flush them out of the way first. */ - - errorCode = FlushChannel(csPtr->interp, outStatePtr->topChanPtr, 0); - if (errorCode != 0) { - MBError(csPtr, TCL_WRITABLE, errorCode); - return TCL_ERROR; - } - } - - if (csPtr->cmdPtr) { - Tcl_Channel inChan = (Tcl_Channel) csPtr->readPtr; - Tcl_CreateChannelHandler(inChan, TCL_READABLE, MBEvent, csPtr); - return TCL_OK; - } - - while (1) { - int code; - - if (TCL_ERROR == MBRead(csPtr)) { - return TCL_ERROR; - } - code = MBWrite(csPtr); - if (code == TCL_OK) { - Tcl_SetObjResult(csPtr->interp, Tcl_NewWideIntObj(csPtr->total)); - StopCopy(csPtr); - return TCL_OK; - } - if (code == TCL_ERROR) { - return TCL_ERROR; - } - /* code == TCL_CONTINUE --> continue the loop */ - } - return TCL_OK; /* Silence compiler warnings */ -} - static int CopyData( CopyState *csPtr, /* State of copy operation. */ @@ -9377,7 +8698,7 @@ CopyData( ChannelState *inStatePtr, *outStatePtr; int result = TCL_OK, size, sizeb; Tcl_WideInt total; - const char *buffer; + char *buffer; int inBinary, outBinary, sameEncoding; /* Encoding control */ int underflow; /* Input underflow */ @@ -9406,7 +8727,7 @@ CopyData( Tcl_IncrRefCount(bufObj); } - while (csPtr->toRead != (Tcl_WideInt) 0) { + while (csPtr->toRead != 0) { /* * Check for unreported background errors. */ @@ -9430,26 +8751,24 @@ CopyData( * underflow instead to prime the readable fileevent. */ - size = 0; + size = 0; underflow = 1; } else { /* * Read up to bufSize bytes. */ - if ((csPtr->toRead == (Tcl_WideInt) -1) - || (csPtr->toRead > (Tcl_WideInt) csPtr->bufSize)) { + if ((csPtr->toRead == -1) || (csPtr->toRead > csPtr->bufSize)) { sizeb = csPtr->bufSize; } else { - sizeb = (int) csPtr->toRead; + sizeb = csPtr->toRead; } if (inBinary || sameEncoding) { - size = DoRead(inStatePtr->topChanPtr, csPtr->buffer, sizeb, - !GotFlag(inStatePtr, CHANNEL_NONBLOCKING)); + size = DoRead(inStatePtr->topChanPtr, csPtr->buffer, sizeb); } else { size = DoReadChars(inStatePtr->topChanPtr, bufObj, sizeb, - 0 /* No append */); + 0 /* No append */); } underflow = (size >= 0) && (size < sizeb); /* Input underflow */ } @@ -9482,8 +8801,8 @@ CopyData( if ((size == 0) && Tcl_Eof(inChan) && !(cmdPtr && (mask == 0))) { break; } - if (cmdPtr && (!Tcl_Eof(inChan) || (mask == 0)) && - !(mask & TCL_READABLE)) { + if (((!Tcl_Eof(inChan)) || (cmdPtr && (mask == 0))) && + !(mask & TCL_READABLE)) { if (mask & TCL_WRITABLE) { Tcl_DeleteChannelHandler(outChan, CopyEventProc, csPtr); } @@ -9491,10 +8810,6 @@ CopyData( csPtr); } if (size == 0) { - if (!GotFlag(inStatePtr, CHANNEL_NONBLOCKING)) { - /* We allowed a short read. Keep trying. */ - continue; - } if (bufObj != NULL) { TclDecrRefCount(bufObj); bufObj = NULL; @@ -9552,7 +8867,7 @@ CopyData( } /* - * Update the current byte count. Do it now so the count is valid + * (UP) Update the current byte count. Do it now so the count is valid * before a return or break takes us out of the loop. The invariant at * the top of the loop should be that csPtr->toRead holds the number * of bytes left to copy. @@ -9578,7 +8893,7 @@ CopyData( * therefore we don't need a writable handler. */ - if (!underflow && GotFlag(outStatePtr, BG_FLUSH_SCHEDULED)) { + if (!underflow && (outStatePtr->flags & BG_FLUSH_SCHEDULED)) { if (!(mask & TCL_WRITABLE)) { if (mask & TCL_READABLE) { Tcl_DeleteChannelHandler(inChan, CopyEventProc, csPtr); @@ -9629,7 +8944,6 @@ CopyData( total = csPtr->total; if (cmdPtr && interp) { int code; - /* * Get a private copy of the command so we can mutate it by adding * arguments. Note that StopCopy frees our saved reference to the @@ -9647,7 +8961,7 @@ CopyData( } code = Tcl_EvalObjEx(interp, cmdPtr, TCL_EVAL_GLOBAL); if (code != TCL_OK) { - Tcl_BackgroundException(interp, code); + TclBackgroundException(interp, code); result = TCL_ERROR; } TclDecrRefCount(cmdPtr); @@ -9673,9 +8987,10 @@ CopyData( * DoRead -- * * Stores up to "bytesToRead" bytes in memory pointed to by "dst". - * These bytes come from reading the channel "chanPtr" and - * performing the configured translations. No encoding conversions - * are applied to the bytes being read. + * These bytes come from reading the channel "chanPtr" and + * performing the configured translations. + * + * No encoding conversions are applied to the bytes being read. * * Results: * The number of bytes actually stored (<= bytesToRead), @@ -9699,9 +9014,8 @@ CopyData( static int DoRead( Channel *chanPtr, /* The channel from which to read. */ - char *dst, /* Where to store input read. */ - int bytesToRead, /* Maximum number of bytes to read. */ - int allowShortReads) /* Allow half-blocking (pipes,sockets) */ + char *dst, /* Where to store input read. */ + int bytesToRead) /* Maximum number of bytes to read. */ { ChannelState *statePtr = chanPtr->state; char *p = dst; @@ -9745,7 +9059,7 @@ DoRead( TclChannelPreserve((Tcl_Channel)chanPtr); while (bytesToRead) { /* - * Each pass through the loop is intended to process up to + * Each pass through the loop is intended to process up to * one channel buffer. */ @@ -9753,13 +9067,13 @@ DoRead( ChannelBuffer *bufPtr = statePtr->inQueueHead; /* - * Don't read more data if we have what we need. + * Don't read more data if we have what we need. */ while (!bufPtr || /* We got no buffer! OR */ (!IsBufferFull(bufPtr) && /* Our buffer has room AND */ (BytesLeft(bufPtr) < bytesToRead) ) ) { - /* Not enough bytes in it + /* Not enough bytes in it * yet to fill the dst */ int code; @@ -9827,13 +9141,13 @@ DoRead( if (bufPtr->nextPtr == NULL) { /* There's no more buffered data.... */ - if (statePtr->flags & CHANNEL_EOF) { + if (GotFlag(statePtr, CHANNEL_EOF)) { /* ...and there never will be. */ *p++ = '\r'; bytesToRead--; bufPtr->nextRemoved++; - } else if (statePtr->flags & CHANNEL_BLOCKED) { + } else if (GotFlag(statePtr, CHANNEL_BLOCKED)) { /* ...and we cannot get more now. */ SetFlag(statePtr, CHANNEL_NEED_MORE_DATA); break; @@ -9863,8 +9177,8 @@ DoRead( bufPtr = statePtr->inQueueHead; } - if ((GotFlag(statePtr, CHANNEL_NONBLOCKING) || allowShortReads) - && GotFlag(statePtr, CHANNEL_BLOCKED)) { + if (GotFlag(statePtr, CHANNEL_NONBLOCKING|CHANNEL_BLOCKED) + == (CHANNEL_NONBLOCKING|CHANNEL_BLOCKED)) { break; } @@ -9915,7 +9229,7 @@ CopyEventProc( ClientData clientData, int mask) { - (void) CopyData(clientData, mask); + (void) CopyData((CopyState *) clientData, mask); } /* @@ -9940,16 +9254,12 @@ StopCopy( CopyState *csPtr) /* State for bg copy to stop . */ { ChannelState *inStatePtr, *outStatePtr; - Tcl_Channel inChan, outChan; - int nonBlocking; if (!csPtr) { return; } - inChan = (Tcl_Channel) csPtr->readPtr; - outChan = (Tcl_Channel) csPtr->writePtr; inStatePtr = csPtr->readPtr->state; outStatePtr = csPtr->writePtr->state; @@ -9957,34 +9267,34 @@ StopCopy( * Restore the old blocking mode and output buffering mode. */ - nonBlocking = csPtr->readFlags & CHANNEL_NONBLOCKING; + nonBlocking = (csPtr->readFlags & CHANNEL_NONBLOCKING); if (nonBlocking != (inStatePtr->flags & CHANNEL_NONBLOCKING)) { SetBlockMode(NULL, csPtr->readPtr, nonBlocking ? TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING); } if (csPtr->readPtr != csPtr->writePtr) { - nonBlocking = csPtr->writeFlags & CHANNEL_NONBLOCKING; + nonBlocking = (csPtr->writeFlags & CHANNEL_NONBLOCKING); if (nonBlocking != (outStatePtr->flags & CHANNEL_NONBLOCKING)) { SetBlockMode(NULL, csPtr->writePtr, nonBlocking ? TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING); } } - ResetFlag(outStatePtr, CHANNEL_LINEBUFFERED | CHANNEL_UNBUFFERED); + outStatePtr->flags &= ~(CHANNEL_LINEBUFFERED | CHANNEL_UNBUFFERED); outStatePtr->flags |= csPtr->writeFlags & (CHANNEL_LINEBUFFERED | CHANNEL_UNBUFFERED); if (csPtr->cmdPtr) { - Tcl_DeleteChannelHandler(inChan, CopyEventProc, csPtr); - if (inChan != outChan) { - Tcl_DeleteChannelHandler(outChan, CopyEventProc, csPtr); + Tcl_DeleteChannelHandler((Tcl_Channel) csPtr->readPtr, CopyEventProc, + csPtr); + if (csPtr->readPtr != csPtr->writePtr) { + Tcl_DeleteChannelHandler((Tcl_Channel) csPtr->writePtr, + CopyEventProc, csPtr); } - Tcl_DeleteChannelHandler(inChan, MBEvent, csPtr); - Tcl_DeleteChannelHandler(outChan, MBEvent, csPtr); TclDecrRefCount(csPtr->cmdPtr); } inStatePtr->csPtrR = NULL; outStatePtr->csPtrW = NULL; - ckfree(csPtr); + ckfree((char *) csPtr); } /* @@ -10025,7 +9335,7 @@ StackSetBlockMode( while (chanPtr != NULL) { blockModeProc = Tcl_ChannelBlockModeProc(chanPtr->typePtr); if (blockModeProc != NULL) { - result = blockModeProc(chanPtr->instanceData, mode); + result = (*blockModeProc) (chanPtr->instanceData, mode); if (result != 0) { Tcl_SetErrno(result); return result; @@ -10080,9 +9390,8 @@ SetBlockMode( */ if (!TclChanCaughtErrorBypass(interp, (Tcl_Channel) chanPtr)) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "error setting blocking mode: %s", - Tcl_PosixError(interp))); + Tcl_AppendResult(interp, "error setting blocking mode: ", + Tcl_PosixError(interp), NULL); } } else { /* @@ -10179,11 +9488,10 @@ Tcl_GetChannelNamesEx( } goto done; } - for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch); hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSearch)) { - statePtr = ((Channel *) Tcl_GetHashValue(hPtr))->state; + statePtr = ((Channel *) Tcl_GetHashValue(hPtr))->state; if (statePtr->topChanPtr == (Channel *) tsdPtr->stdinChannel) { name = "stdin"; } else if (statePtr->topChanPtr == (Channel *) tsdPtr->stdoutChannel) { @@ -10329,8 +9637,11 @@ Tcl_IsChannelExisting( name = statePtr->channelName; } + /* Bug 2333466. Include \0 in the compare to prevent partial matching + * on prefixes. + */ if ((*chanName == *name) && - (memcmp(name, chanName, (size_t) chanNameLen + 1) == 0)) { + (memcmp(name, chanName, (size_t) chanNameLen+1) == 0)) { return 1; } } @@ -10449,13 +9760,13 @@ Tcl_ChannelBlockModeProc( { if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_2)) { return chanTypePtr->blockModeProc; - } - - /* - * The v1 structure had the blockModeProc in a different place. - */ + } else { + /* + * The v1 structure had the blockModeProc in a different place. + */ - return (Tcl_DriverBlockModeProc *) chanTypePtr->version; + return (Tcl_DriverBlockModeProc *) (chanTypePtr->version); + } } /* @@ -10697,8 +10008,9 @@ Tcl_ChannelFlushProc( { if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_2)) { return chanTypePtr->flushProc; + } else { + return NULL; } - return NULL; } /* @@ -10724,8 +10036,9 @@ Tcl_ChannelHandlerProc( { if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_2)) { return chanTypePtr->handlerProc; + } else { + return NULL; } - return NULL; } /* @@ -10751,8 +10064,9 @@ Tcl_ChannelWideSeekProc( { if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_3)) { return chanTypePtr->wideSeekProc; + } else { + return NULL; } - return NULL; } /* @@ -10779,8 +10093,9 @@ Tcl_ChannelThreadActionProc( { if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_4)) { return chanTypePtr->threadActionProc; + } else { + return NULL; } - return NULL; } /* @@ -10897,7 +10212,7 @@ FixLevelCode( res = Tcl_ListObjGetElements(NULL, msg, &lc, &lv); if (res != TCL_OK) { - Tcl_Panic("Tcl_SetChannelError: bad syntax of message"); + Tcl_Panic("Tcl_SetChannelError(Interp): Bad syntax of message"); } explicitResult = (1 == (lc % 2)); @@ -10957,7 +10272,7 @@ FixLevelCode( lcn += 2; } - lvn = ckalloc(lcn * sizeof(Tcl_Obj *)); + lvn = (Tcl_Obj **) ckalloc(lcn * sizeof(Tcl_Obj *)); /* * New level/code information is spliced into the first occurence of @@ -11010,7 +10325,7 @@ FixLevelCode( msg = Tcl_NewListObj(j, lvn); - ckfree(lvn); + ckfree((char *) lvn); return msg; } @@ -11094,8 +10409,9 @@ Tcl_ChannelTruncateProc( { if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_5)) { return chanTypePtr->truncateProc; + } else { + return NULL; } - return NULL; } /* @@ -11123,16 +10439,78 @@ DupChannelIntRep( register Tcl_Obj *copyPtr) /* Object with internal rep to set. Must not * currently have an internal rep.*/ { - ResolvedChanName *resPtr = srcPtr->internalRep.twoPtrValue.ptr1; + ChannelState *statePtr = GET_CHANNELSTATE(srcPtr); - resPtr->refCount++; - copyPtr->internalRep.twoPtrValue.ptr1 = resPtr; + SET_CHANNELSTATE(copyPtr, statePtr); + SET_CHANNELINTERP(copyPtr, GET_CHANNELINTERP(srcPtr)); + Tcl_Preserve((ClientData) statePtr); copyPtr->typePtr = srcPtr->typePtr; } /* *---------------------------------------------------------------------- * + * SetChannelFromAny -- + * + * Create an internal representation of type "Channel" for an object. + * + * Results: + * This operation always succeeds and returns TCL_OK. + * + * Side effects: + * Any old internal reputation for objPtr is freed and the internal + * representation is set to "Channel". + * + *---------------------------------------------------------------------- + */ + +static int +SetChannelFromAny( + Tcl_Interp *interp, /* Used for error reporting if not NULL. */ + register Tcl_Obj *objPtr) /* The object to convert. */ +{ + ChannelState *statePtr; + + if (interp == NULL) { + return TCL_ERROR; + } + if (objPtr->typePtr == &chanObjType) { + /* + * TODO: TAINT Flag and dup'd channel values? + * The channel is valid until any call to DetachChannel occurs. + * Ensure consistency checks are done. + */ + + statePtr = GET_CHANNELSTATE(objPtr); + if (GotFlag(statePtr, CHANNEL_TAINTED|CHANNEL_CLOSED)) { + ResetFlag(statePtr, CHANNEL_TAINTED); + Tcl_Release((ClientData) statePtr); + objPtr->typePtr = NULL; + } else if (interp != GET_CHANNELINTERP(objPtr)) { + Tcl_Release((ClientData) statePtr); + objPtr->typePtr = NULL; + } + } + if (objPtr->typePtr != &chanObjType) { + Tcl_Channel chan = Tcl_GetChannel(interp, TclGetString(objPtr), NULL); + + if (chan == NULL) { + return TCL_ERROR; + } + + TclFreeIntRep(objPtr); + statePtr = ((Channel *)chan)->state; + Tcl_Preserve((ClientData) statePtr); + SET_CHANNELSTATE(objPtr, statePtr); + SET_CHANNELINTERP(objPtr, interp); + objPtr->typePtr = &chanObjType; + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * * FreeChannelIntRep -- * * Release statePtr storage. @@ -11150,14 +10528,7 @@ static void FreeChannelIntRep( Tcl_Obj *objPtr) /* Object with internal rep to free. */ { - ResolvedChanName *resPtr = objPtr->internalRep.twoPtrValue.ptr1; - - objPtr->typePtr = NULL; - if (resPtr->refCount-- > 1) { - return; - } - Tcl_Release(resPtr->statePtr); - ckfree(resPtr); + Tcl_Release((ClientData) GET_CHANNELSTATE(objPtr)); } #if 0 @@ -11174,7 +10545,7 @@ DumpFlags( char buf[20]; int i = 0; -#define ChanFlag(chr, bit) (buf[i++] = ((flags & (bit)) ? (chr) : '_')) +#define ChanFlag(chr,bit) (buf[i++] = ((flags & (bit)) ? (chr) : '_')) ChanFlag('r', TCL_READABLE); ChanFlag('w', TCL_WRITABLE); |
