summaryrefslogtreecommitdiffstats
path: root/generic/tclIO.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclIO.c')
-rw-r--r--generic/tclIO.c3676
1 files changed, 1273 insertions, 2403 deletions
diff --git a/generic/tclIO.c b/generic/tclIO.c
index 15e0785..7bc849e 100644
--- a/generic/tclIO.c
+++ b/generic/tclIO.c
@@ -4,8 +4,8 @@
* This file provides the generic portions (those that are the same on
* all platforms and for all channel types) of Tcl's IO facilities.
*
- * Copyright © 1998-2000 Ajuba Solutions
- * Copyright © 1995-1997 Sun Microsystems, Inc.
+ * Copyright (c) 1998-2000 Ajuba Solutions
+ * Copyright (c) 1995-1997 Sun Microsystems, Inc.
* Contributions from Don Porter, NIST, 2014. (not subject to US copyright)
*
* See the file "license.terms" for information on usage and redistribution of
@@ -28,22 +28,22 @@ typedef struct ChannelHandler {
int mask; /* Mask of desired events. */
Tcl_ChannelProc *proc; /* Procedure to call in the type of
* Tcl_CreateChannelHandler. */
- void *clientData; /* Argument to pass to procedure. */
+ ClientData clientData; /* Argument to pass to procedure. */
struct ChannelHandler *nextPtr;
/* Next one in list of registered handlers. */
} 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,12 +109,12 @@ 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. */
- Tcl_Size bufSize; /* Size of appended buffer. */
- char buffer[TCLFLEXARRAY]; /* Copy buffer, this must be the last
+ int bufSize; /* Size of appended buffer. */
+ char buffer[1]; /* Copy buffer, this must be the last
* field. */
} CopyState;
@@ -116,21 +127,21 @@ typedef struct CopyState {
* The structure defined below is used in this file only.
*/
-typedef struct {
+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
* channels. */
Tcl_Channel stdinChannel; /* Static variable for the stdin channel. */
- Tcl_Channel stdoutChannel; /* Static variable for the stdout channel. */
- Tcl_Channel stderrChannel; /* Static variable for the stderr channel. */
- Tcl_Encoding binaryEncoding;
int stdinInitialized;
+ Tcl_Channel stdoutChannel; /* Static variable for the stdout channel. */
int stdoutInitialized;
+ Tcl_Channel stderrChannel; /* Static variable for the stderr channel. */
int stderrInitialized;
+ Tcl_Encoding binaryEncoding;
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
@@ -142,7 +153,7 @@ static Tcl_ThreadDataKey dataKey;
typedef struct CloseCallback {
Tcl_CloseProc *proc; /* The procedure to call. */
- void *clientData; /* Arbitrary one-word data to pass
+ ClientData clientData; /* Arbitrary one-word data to pass
* to the callback. */
struct CloseCallback *nextPtr; /* For chaining close callbacks. */
} CloseCallback;
@@ -151,12 +162,12 @@ typedef struct CloseCallback {
* Static functions in this file:
*/
-static ChannelBuffer * AllocChannelBuffer(Tcl_Size length);
+static ChannelBuffer * AllocChannelBuffer(int length);
static void PreserveChannelBuffer(ChannelBuffer *bufPtr);
static void ReleaseChannelBuffer(ChannelBuffer *bufPtr);
static int IsShared(ChannelBuffer *bufPtr);
static void ChannelFree(Channel *chanPtr);
-static void ChannelTimerProc(void *clientData);
+static void ChannelTimerProc(ClientData clientData);
static int ChanRead(Channel *chanPtr, char *dst, int dstSize);
static int CheckChannelErrors(ChannelState *statePtr,
int direction);
@@ -165,27 +176,14 @@ static int CheckForDeadChannel(Tcl_Interp *interp,
static void CheckForStdChannelsBeingClosed(Tcl_Channel chan);
static void CleanupChannelHandlers(Tcl_Interp *interp,
Channel *chanPtr);
-static void CleanupTimerHandler(ChannelState *statePtr);
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 void DeleteTimerHandler(ChannelState *statePtr);
-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(void *clientData, int mask);
-
-static void CopyEventProc(void *clientData, int mask);
+static void CopyEventProc(ClientData clientData, int mask);
static void CreateScriptRecord(Tcl_Interp *interp,
Channel *chanPtr, int mask, Tcl_Obj *scriptPtr);
-static void DeleteChannelTable(void *clientData,
+static void DeleteChannelTable(ClientData clientData,
Tcl_Interp *interp);
static void DeleteScriptRecord(Tcl_Interp *interp,
Channel *chanPtr, int mask);
@@ -193,19 +191,20 @@ static int DetachChannel(Tcl_Interp *interp, Tcl_Channel chan);
static void DiscardInputQueued(ChannelState *statePtr,
int discardSavedBuffers);
static void DiscardOutputQueued(ChannelState *chanPtr);
-static Tcl_Size DoRead(Channel *chanPtr, char *dst, Tcl_Size bytesToRead,
- int allowShortReads);
-static Tcl_Size DoReadChars(Channel *chan, Tcl_Obj *objPtr, Tcl_Size toRead,
- int allowShortReads, int appendFlag);
+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,
GetsState *statePtr);
static int FlushChannel(Tcl_Interp *interp, Channel *chanPtr,
int calledFromAsyncFlush);
static int TclGetsObjBinary(Tcl_Channel chan, Tcl_Obj *objPtr);
-static Tcl_Encoding GetBinaryEncoding(void);
-static Tcl_ExitProc FreeBinaryEncoding;
+static Tcl_Encoding GetBinaryEncoding();
+static void FreeBinaryEncoding(ClientData clientData);
static Tcl_HashTable * GetChannelTable(Tcl_Interp *interp);
static int GetInput(Channel *chanPtr);
+static int HaveVersion(const Tcl_ChannelType *typePtr,
+ Tcl_ChannelTypeVersion minimumVersion);
static void PeekAhead(Channel *chanPtr, char **dstEndPtr,
GetsState *gsPtr);
static int ReadBytes(ChannelState *statePtr, Tcl_Obj *objPtr,
@@ -221,12 +220,12 @@ static void StopCopy(CopyState *csPtr);
static void TranslateInputEOL(ChannelState *statePtr, char *dst,
const char *src, int *dstLenPtr, int *srcLenPtr);
static void UpdateInterest(Channel *chanPtr);
-static Tcl_Size Write(Channel *chanPtr, const char *src,
- Tcl_Size srcLen, Tcl_Encoding encoding);
+static int Write(Channel *chanPtr, const char *src,
+ int srcLen, Tcl_Encoding encoding);
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)
@@ -239,7 +238,7 @@ static int WillRead(Channel *chanPtr);
* short description of what the macro does.
*
* --------------------------------------------------------------------------
- * Tcl_Size BytesLeft(ChannelBuffer *bufPtr)
+ * int BytesLeft(ChannelBuffer *bufPtr)
*
* Returns the number of bytes of data remaining in the buffer.
*
@@ -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,47 +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. */
- size_t 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 DupChannelInternalRep(Tcl_Obj *objPtr, Tcl_Obj *copyPtr);
-static void FreeChannelInternalRep(Tcl_Obj *objPtr);
+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 */
- FreeChannelInternalRep, /* freeIntRepProc */
- DupChannelInternalRep, /* dupIntRepProc */
+ FreeChannelIntRep, /* freeIntRepProc */
+ DupChannelIntRep, /* dupIntRepProc */
NULL, /* updateStringProc */
- NULL /* setFromAnyProc */
+ NULL /* setFromAnyProc SetChannelFromAny */
};
-#define ChanSetInternalRep(objPtr, resPtr) \
- do { \
- Tcl_ObjInternalRep ir; \
- (resPtr)->refCount++; \
- ir.twoPtrValue.ptr1 = (resPtr); \
- ir.twoPtrValue.ptr2 = NULL; \
- Tcl_StoreInternalRep((objPtr), &chanObjType, &ir); \
- } while (0)
-
-#define ChanGetInternalRep(objPtr, resPtr) \
- do { \
- const Tcl_ObjInternalRep *irPtr; \
- irPtr = TclFetchInternalRep((objPtr), &chanObjType); \
- (resPtr) = irPtr ? (ResolvedChanName *)irPtr->twoPtrValue.ptr1 : NULL; \
- } while (0)
-
-#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)))
@@ -362,47 +348,22 @@ 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)
-{
-#ifndef TCL_NO_DEPRECATED
- if ((chanPtr->typePtr->closeProc != TCL_CLOSE2PROC) && (chanPtr->typePtr->closeProc != NULL)) {
- return chanPtr->typePtr->closeProc(chanPtr->instanceData, interp);
- }
-#endif
- return chanPtr->typePtr->close2Proc(chanPtr->instanceData, interp, 0);
-}
-
-/*
- *---------------------------------------------------------------------------
- *
* ChanRead --
*
- * Read up to dstSize bytes using the inputProc of chanPtr, store them at
- * dst, and return the number of bytes stored.
+ * Read up to dstSize bytes using the inputProc of chanPtr, store
+ * them at dst, and return the number of bytes stored.
*
* Results:
* The return value of the driver inputProc,
* - number of bytes stored at dst, ot
- * - -1 on error, with a Posix error code available to the caller by
- * calling Tcl_GetErrno().
+ * - -1 on error, with a Posix error code available to the
+ * caller by calling Tcl_GetErrno().
*
* Side effects:
- * The CHANNEL_ENCODING_ERROR, CHANNEL_BLOCKED and CHANNEL_EOF flags
- * of the channel state are set as appropriate. On EOF, the
- * inputEncodingFlags are set to perform ending operations on decoding.
- *
+ * The CHANNEL_BLOCKED and CHANNEL_EOF flags of the channel state are
+ * set as appropriate.
+ * On EOF, the inputEncodingFlags are set to perform ending operations
+ * on decoding.
* TODO - Is this really the right place for that?
*
*---------------------------------------------------------------------------
@@ -416,17 +377,15 @@ ChanRead(
int bytesRead, result;
/*
- * If the caller asked for zero bytes, we'd force the inputProc to return
- * zero bytes, and then misinterpret that as EOF.
+ * If the caller asked for zero bytes, we'd force the inputProc
+ * to return zero bytes, and then misinterpret that as EOF.
*/
-
assert(dstSize > 0);
/*
* Each read op must set the blocked and eof states anew, not let
* the effect of prior reads leak through.
*/
-
if (GotFlag(chanPtr->state, CHANNEL_EOF)) {
chanPtr->state->inputEncodingFlags |= TCL_ENCODING_START;
}
@@ -439,35 +398,32 @@ ChanRead(
bytesRead = chanPtr->typePtr->inputProc(chanPtr->instanceData,
dst, dstSize, &result);
- /*
- * Stop any flag leakage through stacked channel levels.
- */
-
+ /* Stop any flag leakage through stacked channel levels */
if (GotFlag(chanPtr->state, CHANNEL_EOF)) {
chanPtr->state->inputEncodingFlags |= TCL_ENCODING_START;
}
ResetFlag(chanPtr->state, CHANNEL_BLOCKED | CHANNEL_EOF);
chanPtr->state->inputEncodingFlags &= ~TCL_ENCODING_END;
- if (bytesRead < 0) {
- if ((result == EWOULDBLOCK) || (result == EAGAIN)) {
+ if (bytesRead > 0) {
+ /*
+ * If we get a short read, signal up that we may be BLOCKED.
+ * We should avoid calling the driver because on some
+ * platforms we will block in the low level reading code even
+ * though the channel is set into nonblocking mode.
+ */
+
+ if (bytesRead < dstSize) {
SetFlag(chanPtr->state, CHANNEL_BLOCKED);
- result = EAGAIN;
}
- Tcl_SetErrno(result);
} else if (bytesRead == 0) {
SetFlag(chanPtr->state, CHANNEL_EOF);
chanPtr->state->inputEncodingFlags |= TCL_ENCODING_END;
- } else {
- /*
- * If we get a short read, signal up that we may be BLOCKED. We should
- * avoid calling the driver because on some platforms we will block in
- * the low level reading code even though the channel is set into
- * nonblocking mode.
- */
-
- if (bytesRead < dstSize) {
+ } else if (bytesRead < 0) {
+ if ((result == EWOULDBLOCK) || (result == EAGAIN)) {
SetFlag(chanPtr->state, CHANNEL_BLOCKED);
+ result = EAGAIN;
}
+ Tcl_SetErrno(result);
}
return bytesRead;
}
@@ -484,56 +440,21 @@ ChanSeek(
* type and non-NULL.
*/
- if (Tcl_ChannelWideSeekProc(chanPtr->typePtr) == NULL) {
-#ifndef TCL_NO_DEPRECATED
- if (offset<LONG_MIN || offset>LONG_MAX) {
- *errnoPtr = EOVERFLOW;
- return TCL_INDEX_NONE;
- }
-
- return Tcl_ChannelSeekProc(chanPtr->typePtr)(chanPtr->instanceData,
+ if (HaveVersion(chanPtr->typePtr, TCL_CHANNEL_VERSION_3) &&
+ chanPtr->typePtr->wideSeekProc != NULL) {
+ return chanPtr->typePtr->wideSeekProc(chanPtr->instanceData,
offset, mode, errnoPtr);
-#else
- *errnoPtr = EINVAL;
- return TCL_INDEX_NONE;
-#endif
}
- return Tcl_ChannelWideSeekProc(chanPtr->typePtr)(chanPtr->instanceData,
- 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);
+ if (offset<Tcl_LongAsWide(LONG_MIN) || offset>Tcl_LongAsWide(LONG_MAX)) {
+ *errnoPtr = EOVERFLOW;
+ return Tcl_LongAsWide(-1);
}
-}
-static inline void
-ChanWatch(
- Channel *chanPtr,
- int mask)
-{
- chanPtr->typePtr->watchProc(chanPtr->instanceData, mask);
+ return Tcl_LongAsWide(chanPtr->typePtr->seekProc(chanPtr->instanceData,
+ Tcl_WideAsLong(offset), mode, errnoPtr));
}
-static inline int
-ChanWrite(
- Channel *chanPtr,
- const char *src,
- int srcLen,
- int *errnoPtr)
-{
- return chanPtr->typePtr->outputProc(chanPtr->instanceData, src, srcLen,
- errnoPtr);
-}
/*
*---------------------------------------------------------------------------
@@ -581,6 +502,7 @@ TclInitIOSubsystem(void)
*-------------------------------------------------------------------------
*/
+ /* ARGSUSED */
void
TclFinalizeIOSubsystem(void)
{
@@ -588,22 +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
@@ -622,40 +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.
- */
+ TclChannelPreserve((Tcl_Channel)chanPtr);
- (void) Tcl_SetChannelOption(NULL, (Tcl_Channel) chanPtr,
- "-blocking", "on");
- }
+ (void) Tcl_SetChannelOption(NULL, (Tcl_Channel) chanPtr,
+ "-blocking", "on");
if ((chanPtr == (Channel *) tsdPtr->stdinChannel) ||
(chanPtr == (Channel *) tsdPtr->stdoutChannel) ||
@@ -688,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
@@ -732,18 +629,17 @@ Tcl_SetStdChannel(
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- int init = channel ? 1 : -1;
switch (type) {
case TCL_STDIN:
- tsdPtr->stdinInitialized = init;
+ tsdPtr->stdinInitialized = 1;
tsdPtr->stdinChannel = channel;
break;
case TCL_STDOUT:
- tsdPtr->stdoutInitialized = init;
+ tsdPtr->stdoutInitialized = 1;
tsdPtr->stdoutChannel = channel;
break;
case TCL_STDERR:
- tsdPtr->stderrInitialized = init;
+ tsdPtr->stderrInitialized = 1;
tsdPtr->stderrChannel = channel;
break;
}
@@ -780,8 +676,8 @@ Tcl_GetStdChannel(
switch (type) {
case TCL_STDIN:
if (!tsdPtr->stdinInitialized) {
- tsdPtr->stdinInitialized = -1;
tsdPtr->stdinChannel = TclpGetDefaultStdChannel(TCL_STDIN);
+ tsdPtr->stdinInitialized = 1;
/*
* Artificially bump the refcount to ensure that the channel is
@@ -793,7 +689,6 @@ Tcl_GetStdChannel(
*/
if (tsdPtr->stdinChannel != NULL) {
- tsdPtr->stdinInitialized = 1;
Tcl_RegisterChannel(NULL, tsdPtr->stdinChannel);
}
}
@@ -801,10 +696,9 @@ Tcl_GetStdChannel(
break;
case TCL_STDOUT:
if (!tsdPtr->stdoutInitialized) {
- tsdPtr->stdoutInitialized = -1;
tsdPtr->stdoutChannel = TclpGetDefaultStdChannel(TCL_STDOUT);
+ tsdPtr->stdoutInitialized = 1;
if (tsdPtr->stdoutChannel != NULL) {
- tsdPtr->stdoutInitialized = 1;
Tcl_RegisterChannel(NULL, tsdPtr->stdoutChannel);
}
}
@@ -812,10 +706,9 @@ Tcl_GetStdChannel(
break;
case TCL_STDERR:
if (!tsdPtr->stderrInitialized) {
- tsdPtr->stderrInitialized = -1;
tsdPtr->stderrChannel = TclpGetDefaultStdChannel(TCL_STDERR);
+ tsdPtr->stderrInitialized = 1;
if (tsdPtr->stderrChannel != NULL) {
- tsdPtr->stderrInitialized = 1;
Tcl_RegisterChannel(NULL, tsdPtr->stderrChannel);
}
}
@@ -849,13 +742,13 @@ Tcl_CreateCloseHandler(
* callback. */
Tcl_CloseProc *proc, /* The callback routine to call when the
* channel will be closed. */
- void *clientData) /* Arbitrary data to pass to the close
+ ClientData clientData) /* Arbitrary data to pass to the close
* callback. */
{
ChannelState *statePtr = ((Channel *) chan)->state;
CloseCallback *cbPtr;
- cbPtr = (CloseCallback *)ckalloc(sizeof(CloseCallback));
+ cbPtr = (CloseCallback *) ckalloc(sizeof(CloseCallback));
cbPtr->proc = proc;
cbPtr->clientData = clientData;
@@ -887,7 +780,7 @@ Tcl_DeleteCloseHandler(
* callback. */
Tcl_CloseProc *proc, /* The procedure for the callback to
* remove. */
- void *clientData) /* The callback data for the callback to
+ ClientData clientData) /* The callback data for the callback to
* remove. */
{
ChannelState *statePtr = ((Channel *) chan)->state;
@@ -901,10 +794,11 @@ Tcl_DeleteCloseHandler(
} else {
cbPrevPtr->nextPtr = cbPtr->nextPtr;
}
- ckfree(cbPtr);
+ ckfree((char *) cbPtr);
break;
+ } else {
+ cbPrevPtr = cbPtr;
}
- cbPrevPtr = cbPtr;
}
}
@@ -934,9 +828,9 @@ GetChannelTable(
Tcl_HashTable *hTblPtr; /* Hash table of channels. */
Tcl_Channel stdinChan, stdoutChan, stderrChan;
- hTblPtr = (Tcl_HashTable *)Tcl_GetAssocData(interp, "tclIO", NULL);
+ hTblPtr = Tcl_GetAssocData(interp, "tclIO", NULL);
if (hTblPtr == NULL) {
- hTblPtr = (Tcl_HashTable *)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);
@@ -978,7 +872,7 @@ GetChannelTable(
*
* Side effects:
* Deletes the hash table of channels. May close channels. May flush
- * output on closed channels. Removes any channelEvent handlers that were
+ * output on closed channels. Removes any channeEvent handlers that were
* registered in this interpreter.
*
*----------------------------------------------------------------------
@@ -986,7 +880,7 @@ GetChannelTable(
static void
DeleteChannelTable(
- void *clientData, /* The per-interpreter data structure. */
+ ClientData clientData, /* The per-interpreter data structure. */
Tcl_Interp *interp) /* The interpreter being deleted. */
{
Tcl_HashTable *hTblPtr; /* The hash table. */
@@ -1004,14 +898,14 @@ DeleteChannelTable(
* refcount reaches zero.
*/
- hTblPtr = (Tcl_HashTable *)clientData;
+ hTblPtr = clientData;
for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch); hPtr != NULL;
hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch)) {
- chanPtr = (Channel *)Tcl_GetHashValue(hPtr);
+ chanPtr = Tcl_GetHashValue(hPtr);
statePtr = chanPtr->state;
/*
- * Remove any file events registered in this interpreter.
+ * Remove any fileevents registered in this interpreter.
*/
for (sPtr = statePtr->scriptRecordPtr, prevPtr = NULL;
@@ -1025,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;
}
@@ -1042,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);
}
@@ -1051,7 +946,7 @@ DeleteChannelTable(
}
Tcl_DeleteHashTable(hTblPtr);
- ckfree(hTblPtr);
+ ckfree((char *) hTblPtr);
}
/*
@@ -1083,7 +978,7 @@ CheckForStdChannelsBeingClosed(
ChannelState *statePtr = ((Channel *) chan)->state;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- if (tsdPtr->stdinInitialized == 1
+ if (tsdPtr->stdinInitialized
&& tsdPtr->stdinChannel != NULL
&& statePtr == ((Channel *)tsdPtr->stdinChannel)->state) {
if (statePtr->refCount < 2) {
@@ -1091,7 +986,7 @@ CheckForStdChannelsBeingClosed(
tsdPtr->stdinChannel = NULL;
return;
}
- } else if (tsdPtr->stdoutInitialized == 1
+ } else if (tsdPtr->stdoutInitialized
&& tsdPtr->stdoutChannel != NULL
&& statePtr == ((Channel *)tsdPtr->stdoutChannel)->state) {
if (statePtr->refCount < 2) {
@@ -1099,7 +994,7 @@ CheckForStdChannelsBeingClosed(
tsdPtr->stdoutChannel = NULL;
return;
}
- } else if (tsdPtr->stderrInitialized == 1
+ } else if (tsdPtr->stderrInitialized
&& tsdPtr->stderrChannel != NULL
&& statePtr == ((Channel *)tsdPtr->stderrChannel)->state) {
if (statePtr->refCount < 2) {
@@ -1237,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;
}
@@ -1265,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().
@@ -1274,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;
}
@@ -1374,7 +1268,7 @@ DetachChannel(
statePtr = chanPtr->state;
if (interp != NULL) {
- hTblPtr = (Tcl_HashTable *)Tcl_GetAssocData(interp, "tclIO", NULL);
+ hTblPtr = Tcl_GetAssocData(interp, "tclIO", NULL);
if (hTblPtr == NULL) {
return TCL_ERROR;
}
@@ -1386,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
@@ -1430,7 +1324,7 @@ Tcl_GetChannel(
* channel. */
const char *chanName, /* The name of the channel. */
int *modePtr) /* Where to store the mode in which the
- * channel was opened? Will contain an OR'ed
+ * channel was opened? Will contain an ORed
* combination of TCL_READABLE and
* TCL_WRITABLE, if non-NULL. */
{
@@ -1465,9 +1359,9 @@ 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_SetErrorCode(interp, "TCL", "LOOKUP", "CHANNEL", chanName, (void *)NULL);
+ Tcl_AppendResult(interp, "can not find channel named \"", chanName,
+ "\"", NULL);
+ Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CHANNEL", chanName, NULL);
return NULL;
}
@@ -1477,7 +1371,7 @@ Tcl_GetChannel(
* compensate where necessary to retrieve the topmost channel again.
*/
- chanPtr = (Channel *)Tcl_GetHashValue(hPtr);
+ chanPtr = Tcl_GetHashValue(hPtr);
chanPtr = chanPtr->state->bottomChanPtr;
if (modePtr != NULL) {
*modePtr = GotFlag(chanPtr->state, TCL_READABLE|TCL_WRITABLE);
@@ -1513,65 +1407,19 @@ TclGetChannelFromObj(
Tcl_Obj *objPtr,
Tcl_Channel *channelPtr,
int *modePtr, /* Where to store the mode in which the
- * channel was opened? Will contain an OR'ed
+ * channel was opened? Will contain an ORed
* combination of TCL_READABLE and
* TCL_WRITABLE, if non-NULL. */
- TCL_UNUSED(int) /*flags*/)
+ int flags)
{
ChannelState *statePtr;
- ResolvedChanName *resPtr = NULL;
- Tcl_Channel chan;
- if (interp == NULL) {
+ if (SetChannelFromAny(interp, objPtr) != TCL_OK) {
return TCL_ERROR;
}
- ChanGetInternalRep(objPtr, resPtr);
- if (resPtr) {
- /*
- * Confirm validity of saved lookup results.
- */
-
- 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) {
- Tcl_StoreInternalRep(objPtr, &chanObjType, NULL);
- }
- return TCL_ERROR;
- }
-
- if (resPtr && resPtr->refCount == 1) {
- /*
- * Re-use the ResolvedCmdName struct.
- */
-
- Tcl_Release((void *) resPtr->statePtr);
- } else {
- resPtr = (ResolvedChanName *) ckalloc(sizeof(ResolvedChanName));
- resPtr->refCount = 0;
- ChanSetInternalRep(objPtr, resPtr); /* Overwrites, if needed */
- }
- statePtr = ((Channel *)chan)->state;
- resPtr->statePtr = statePtr;
- Tcl_Preserve((void *) 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 = GotFlag(statePtr, TCL_READABLE|TCL_WRITABLE);
@@ -1598,9 +1446,9 @@ 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. */
- void *instanceData, /* Instance specific data. */
+ ClientData instanceData, /* Instance specific data. */
int mask) /* TCL_READABLE & TCL_WRITABLE to indicate if
* the channel is readable, writable. */
{
@@ -1608,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);
/*
@@ -1621,42 +1468,15 @@ Tcl_CreateChannel(
* as well.
*/
- assert(sizeof(Tcl_ChannelTypeVersion) == sizeof(Tcl_DriverBlockModeProc *));
- assert(typePtr->typeName != NULL);
-#ifndef TCL_NO_DEPRECATED
- if (((NULL == typePtr->closeProc) || (TCL_CLOSE2PROC == typePtr->closeProc)) && (typePtr->close2Proc == NULL)) {
- Tcl_Panic("channel type %s must define closeProc or close2Proc", typePtr->typeName);
- }
-#else
- if (Tcl_ChannelVersion(typePtr) < TCL_CHANNEL_VERSION_5) {
- Tcl_Panic("channel type %s must be version TCL_CHANNEL_VERSION_5", typePtr->typeName);
- }
- if (typePtr->close2Proc == NULL) {
- Tcl_Panic("channel type %s must define close2Proc", typePtr->typeName);
- }
-#endif
- 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);
- }
-#ifndef TCL_NO_DEPRECATED
- if ((NULL != typePtr->wideSeekProc) && (NULL == typePtr->seekProc)) {
- Tcl_Panic("channel type %s must define seekProc if defining wideSeekProc", typePtr->typeName);
- }
-#endif
+ 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 = (Channel *)ckalloc(sizeof(Channel));
- statePtr = (ChannelState *)ckalloc(sizeof(ChannelState));
+ chanPtr = (Channel *) ckalloc(sizeof(Channel));
+ statePtr = (ChannelState *) ckalloc(sizeof(ChannelState));
chanPtr->state = statePtr;
chanPtr->instanceData = instanceData;
@@ -1668,22 +1488,15 @@ Tcl_CreateChannel(
*/
if (chanName != NULL) {
- unsigned len = strlen(chanName) + 1;
-
- /*
- * Make sure we allocate at least 7 bytes, so it fits for "stdout"
- * later.
- */
+ char *tmp = ckalloc((unsigned) (strlen(chanName) + 1));
- tmp = (char *)ckalloc((len < 7) ? 7 : len);
+ statePtr->channelName = tmp;
strcpy(tmp, chanName);
} else {
- tmp = (char *)ckalloc(7);
- tmp[0] = '\0';
+ Tcl_Panic("Tcl_CreateChannel: NULL channel name");
}
- statePtr->channelName = tmp;
+
statePtr->flags = mask;
- statePtr->maxPerms = mask; /* Save max privileges for close callback */
/*
* Set the channel to system default encoding.
@@ -1702,18 +1515,14 @@ Tcl_CreateChannel(
}
statePtr->inputEncodingState = NULL;
statePtr->inputEncodingFlags = TCL_ENCODING_START;
- ENCODING_PROFILE_SET(statePtr->inputEncodingFlags,
- TCL_ENCODING_PROFILE_TCL8);
statePtr->outputEncodingState = NULL;
statePtr->outputEncodingFlags = TCL_ENCODING_START;
- ENCODING_PROFILE_SET(statePtr->outputEncodingFlags,
- TCL_ENCODING_PROFILE_TCL8);
/*
* Set the channel up initially in AUTO input translation mode to accept
* "\n", "\r" and "\r\n". Output translation mode is set to a platform
* specific default value. The eofChar is set to 0 for both input and
- * output, so that Tcl does not look for an in-file EOF indicator (e.g.,
+ * output, so that Tcl does not look for an in-file EOF indicator (e.g.
* ^Z) and does not append an EOF indicator to files.
*/
@@ -1736,7 +1545,6 @@ Tcl_CreateChannel(
statePtr->scriptRecordPtr = NULL;
statePtr->bufSize = CHANNELBUFFER_DEFAULT_SIZE;
statePtr->timer = NULL;
- statePtr->timerChanPtr = NULL;
statePtr->csPtrR = NULL;
statePtr->csPtrW = NULL;
statePtr->outputStage = NULL;
@@ -1760,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
@@ -1788,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);
}
@@ -1835,10 +1638,9 @@ 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. */
- void *instanceData, /* Instance specific data for the new
+ ClientData instanceData, /* Instance specific data for the new
* channel. */
int mask, /* TCL_READABLE & TCL_WRITABLE to indicate if
* the channel is readable, writable. */
@@ -1847,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
@@ -1864,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;
}
@@ -1884,11 +1686,11 @@ Tcl_StackChannel(
* --+---+---+---+----+
*/
- if ((mask & GotFlag(statePtr, 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;
}
@@ -1915,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;
}
@@ -1937,11 +1738,12 @@ Tcl_StackChannel(
* impossible) we move the buffers from the common state structure into
* the channel itself. We use the buffers in the channel below the new
* transformation to hold the data. In the future this allows us to write
- * transformations which preread data and push the unused part back when
+ * transformations which pre-read data and push the unused part back when
* they are going away.
*/
if (((mask & TCL_READABLE) != 0) && (statePtr->inQueueHead != NULL)) {
+
/*
* When statePtr->inQueueHead is not NULL, we know
* prevChanPtr->inQueueHead must be NULL.
@@ -1957,7 +1759,7 @@ Tcl_StackChannel(
statePtr->inQueueTail = NULL;
}
- chanPtr = (Channel *)ckalloc(sizeof(Channel));
+ chanPtr = (Channel *) ckalloc(sizeof(Channel));
/*
* Save some of the current state into the new structure, reinitialize the
@@ -1994,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;
}
@@ -2019,7 +1824,7 @@ TclChannelRelease(
return;
}
if (chanPtr->typePtr == NULL) {
- ckfree(chanPtr);
+ ckfree((char *)chanPtr);
}
}
@@ -2028,7 +1833,7 @@ ChannelFree(
Channel *chanPtr)
{
if (chanPtr->refCount == 0) {
- ckfree(chanPtr);
+ ckfree((char *)chanPtr);
return;
}
chanPtr->typePtr = NULL;
@@ -2046,7 +1851,7 @@ ChannelFree(
* A standard Tcl result.
*
* Side effects:
- * If TCL_ERROR is returned, the Posix error code will be set with
+ * If TCL_ERROR is returned, the posix error code will be set with
* Tcl_SetErrno. May leave a message in interp result as well.
*
*----------------------------------------------------------------------
@@ -2060,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.
@@ -2069,11 +1875,13 @@ Tcl_UnstackChannel(
if (chanPtr->downChanPtr != NULL) {
/*
- * Instead of manipulating the per-thread / per-interp list/hash table
- * of registered channels we wind down the state of the
- * transformation, and then restore the state of underlying channel
- * into the old structure.
- *
+ * 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.
+ */
+
+ /*
* TODO: Figure out how to handle the situation where the chan
* operations called below by this unstacking operation cause
* another unstacking recursively. In that case the downChanPtr
@@ -2110,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;
}
@@ -2162,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;
@@ -2174,12 +1986,16 @@ Tcl_UnstackChannel(
/*
* Close and free the channel driver state.
- * TIP #220: This is done with maximum privileges (as created).
*/
- ResetFlag(statePtr, TCL_READABLE|TCL_WRITABLE);
- SetFlag(statePtr, statePtr->maxPerms);
- 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);
@@ -2297,7 +2113,7 @@ Tcl_GetTopChannel(
*----------------------------------------------------------------------
*/
-void *
+ClientData
Tcl_GetChannelInstanceData(
Tcl_Channel chan) /* Channel for which to return client data. */
{
@@ -2350,7 +2166,7 @@ Tcl_GetChannelThread(
*----------------------------------------------------------------------
*/
-const Tcl_ChannelType *
+Tcl_ChannelType *
Tcl_GetChannelType(
Tcl_Channel chan) /* The channel to return type for. */
{
@@ -2385,7 +2201,7 @@ Tcl_GetChannelMode(
ChannelState *statePtr = ((Channel *) chan)->state;
/* State of actual channel. */
- return GotFlag(statePtr, TCL_READABLE|TCL_WRITABLE);
+ return GotFlag(statePtr, TCL_READABLE | TCL_WRITABLE);
}
/*
@@ -2409,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;
}
@@ -2436,21 +2252,23 @@ int
Tcl_GetChannelHandle(
Tcl_Channel chan, /* The channel to get file from. */
int direction, /* TCL_WRITABLE or TCL_READABLE. */
- void **handlePtr) /* Where to store handle */
+ ClientData *handlePtr) /* Where to store handle */
{
Channel *chanPtr; /* The actual channel. */
- void *handle;
+ ClientData handle;
int result;
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;
}
@@ -2458,54 +2276,6 @@ Tcl_GetChannelHandle(
}
/*
- *----------------------------------------------------------------------
- *
- * Tcl_RemoveChannelMode --
- *
- * Remove either read or write privileges from the channel.
- *
- * Results:
- * A standard Tcl result code.
- *
- * Side effects:
- * May change the access mode of the channel.
- * May leave an error message in the interp.
- *
- *----------------------------------------------------------------------
- */
-
-int
-Tcl_RemoveChannelMode(
- Tcl_Interp* interp, /* The interp for an error message. Allowed to be NULL. */
- Tcl_Channel chan, /* The channel which is modified. */
- int mode) /* The access mode to drop from the channel */
-{
- const char* emsg;
- ChannelState *statePtr = ((Channel *) chan)->state;
- /* State of actual channel. */
-
- if ((mode != TCL_READABLE) && (mode != TCL_WRITABLE)) {
- emsg = "Illegal mode value.";
- goto error;
- }
- if (0 == (GotFlag(statePtr, TCL_READABLE|TCL_WRITABLE) & ~mode)) {
- emsg = "Bad mode, would make channel inacessible";
- goto error;
- }
-
- ResetFlag(statePtr, mode);
- return TCL_OK;
-
- error:
- if (interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "Tcl_RemoveChannelMode error: %s. Channel: \"%s\"",
- emsg, Tcl_GetChannelName((Tcl_Channel) chan)));
- }
- return TCL_ERROR;
-}
-
-/*
*---------------------------------------------------------------------------
*
* AllocChannelBuffer --
@@ -2531,13 +2301,13 @@ Tcl_RemoveChannelMode(
static ChannelBuffer *
AllocChannelBuffer(
- Tcl_Size length) /* Desired length of channel buffer. */
+ int length) /* Desired length of channel buffer. */
{
ChannelBuffer *bufPtr;
- Tcl_Size n;
+ int n;
n = length + CHANNELBUFFER_HEADER_SIZE + BUFFER_PADDING + BUFFER_PADDING;
- bufPtr = (ChannelBuffer *)ckalloc(n);
+ bufPtr = (ChannelBuffer *) ckalloc((unsigned) n);
bufPtr->nextAdded = BUFFER_PADDING;
bufPtr->nextRemoved = BUFFER_PADDING;
bufPtr->bufLength = length + BUFFER_PADDING;
@@ -2550,9 +2320,6 @@ static void
PreserveChannelBuffer(
ChannelBuffer *bufPtr)
{
- if (!bufPtr->refCount) {
- Tcl_Panic("Reuse of ChannelBuffer! %p", bufPtr);
- }
bufPtr->refCount++;
}
@@ -2563,7 +2330,7 @@ ReleaseChannelBuffer(
if (--bufPtr->refCount) {
return;
}
- ckfree(bufPtr);
+ ckfree((char *) bufPtr);
}
static int
@@ -2602,7 +2369,6 @@ RecycleBuffer(
/*
* Do we have to free the buffer to the OS?
*/
-
if (IsShared(bufPtr)) {
mustDiscard = 1;
}
@@ -2613,11 +2379,12 @@ RecycleBuffer(
}
/*
- * Only save buffers which have the requested buffer size for the channel.
- * This is to honor dynamic changes of the buffe rsize made by the user.
+ * Only save buffers which have the requested buffersize for the
+ * channel. This is to honor dynamic changes of the buffersize
+ * made by the user.
*/
- if ((bufPtr->bufLength) != statePtr->bufSize + BUFFER_PADDING) {
+ if ((bufPtr->bufLength - BUFFER_PADDING) != statePtr->bufSize) {
ReleaseChannelBuffer(bufPtr);
return;
}
@@ -2720,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;
}
/*
@@ -2737,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
@@ -2770,11 +2536,10 @@ FlushChannel(
int wroteSome = 0; /* Set to one if any data was written to the
* driver. */
- int bufExists;
/*
* Prevent writing on a dead channel -- a channel that has been closed but
* not yet deallocated. This can occur if the exit handler for the channel
- * deallocation runs before all channels are unregistered in all
+ * deallocation runs before all channels are deregistered in all
* interpreters.
*/
@@ -2785,18 +2550,14 @@ FlushChannel(
/*
* Should we shift the current output buffer over to the output queue?
* First check that there are bytes in it. If so then...
- *
- * If the output queue is empty, then yes, trusting the caller called us
- * only when written bytes ought to be flushed.
- *
- * If the current output buffer is full, then yes, so we can meet 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 blocking
- * flushes actually flush all pending data.
- *
+ * If the output queue is empty, then yes, trusting the caller called
+ * us only when written bytes ought to be flushed.
+ * If the current output buffer is full, then yes, so we can meet
+ * 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
+ * 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
* buffer usage.
@@ -2840,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
@@ -2873,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);
}
@@ -2889,9 +2650,9 @@ FlushChannel(
if (calledFromAsyncFlush) {
/*
* TIP #219, Tcl Channel Reflection API.
- * When deferring the error copy a message from the bypass into
- * the unreported area. Or discard it if the new error is to
- * be ignored in favor of an earlier deferred error.
+ * When defering the error copy a message from the bypass into
+ * the unreported area. Or discard it if the new error is to be
+ * ignored in favor of an earlier defered error.
*/
Tcl_Obj *msg = statePtr->chanMsg;
@@ -2924,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);
}
/*
@@ -2939,44 +2706,29 @@ FlushChannel(
* queued.
*/
- ReleaseChannelBuffer(bufPtr);
DiscardOutputQueued(statePtr);
+ ReleaseChannelBuffer(bufPtr);
break;
} else {
- /*
- * TODO: Consider detecting and reacting to short writes on
- * blocking channels. Ought not happen. See iocmd-24.2.
- */
-
+ /* TODO: Consider detecting and reacting to short writes
+ * on blocking channels. Ought not happen. See iocmd-24.2. */
wroteSome = 1;
}
- bufExists = bufPtr->refCount > 1;
- ReleaseChannelBuffer(bufPtr);
- if (bufExists) {
- /* There is still a reference to this buffer other than the one
- * this routine just released, meaning that final cleanup of the
- * buffer hasn't been ordered by, e.g. by a reflected channel
- * closing the channel from within one of its handler scripts (not
- * something one would expecte, but it must be considered). Normal
- * operations on the buffer can proceed.
- */
-
- bufPtr->nextRemoved += written;
+ bufPtr->nextRemoved += written;
- /*
- * If this buffer is now empty, recycle it.
- */
+ /*
+ * If this buffer is now empty, recycle it.
+ */
- if (IsBufferEmpty(bufPtr)) {
- statePtr->outQueueHead = bufPtr->nextPtr;
- if (statePtr->outQueueHead == NULL) {
- statePtr->outQueueTail = NULL;
- }
- RecycleBuffer(statePtr, bufPtr, 0);
+ if (IsBufferEmpty(bufPtr)) {
+ statePtr->outQueueHead = bufPtr->nextPtr;
+ if (statePtr->outQueueHead == NULL) {
+ statePtr->outQueueTail = NULL;
}
+ RecycleBuffer(statePtr, bufPtr, 0);
}
-
+ ReleaseChannelBuffer(bufPtr);
} /* Closes "while". */
/*
@@ -2991,25 +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 https://core.tcl-lang.org/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. */
}
}
@@ -3024,24 +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;
@@ -3118,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);
}
/*
@@ -3129,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;
@@ -3146,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
@@ -3155,7 +2884,7 @@ CloseChannel(
if (chanPtr == statePtr->bottomChanPtr) {
if (statePtr->channelName != NULL) {
- ckfree(statePtr->channelName);
+ ckfree((char *) statePtr->channelName);
statePtr->channelName = NULL;
}
@@ -3181,7 +2910,7 @@ CloseChannel(
statePtr->chanMsg = NULL;
}
if (interp) {
- Tcl_SetChannelErrorInterp(interp, statePtr->unreportedMsg);
+ Tcl_SetChannelErrorInterp(interp,statePtr->unreportedMsg);
}
}
if (errorCode == 0) {
@@ -3194,8 +2923,8 @@ CloseChannel(
/*
* Cancel any outstanding timer.
*/
- DeleteTimerHandler(statePtr);
+ Tcl_DeleteTimerHandler(statePtr->timer);
/*
* Mark the channel as deleted by clearing the type structure.
@@ -3247,8 +2976,8 @@ CloseChannel(
* The channel to cut out of the list must not be referenced in any
* interpreter. This is something this procedure cannot check (despite
* the refcount) because the caller usually wants fiddle with the channel
- * (like transferring it to a different thread) and thus keeps the
- * refcount artificially high to prevent its destruction.
+ * (like transfering it to a different thread) and thus keeps the
+ * refcount artifically high to prevent its destruction.
*
*----------------------------------------------------------------------
*/
@@ -3264,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
@@ -3290,10 +3020,11 @@ CutChannel(
* TIP #218, Channel Thread Actions
*/
- ChanThreadAction((Channel *) chan, TCL_CHANNEL_THREAD_REMOVE);
-
- /* Channel is not managed by any thread */
- statePtr->managingThread = NULL;
+ threadActionProc = Tcl_ChannelThreadActionProc(Tcl_GetChannelType(chan));
+ if (threadActionProc != NULL) {
+ (*threadActionProc)(Tcl_GetChannelInstanceData(chan),
+ TCL_CHANNEL_THREAD_REMOVE);
+ }
}
void
@@ -3308,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
@@ -3335,12 +3067,14 @@ 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;
}
-
- /* Channel is not managed by any thread */
- statePtr->managingThread = NULL;
}
/*
@@ -3362,9 +3096,9 @@ Tcl_CutChannel(
* NOTE:
* The channel to splice into the list must not be referenced in any
* interpreter. This is something this procedure cannot check (despite
- * the refcount) because the caller usually wants fiddle with the channel
- * (like transferring it to a different thread) and thus keeps the
- * refcount artificially high to prevent its destruction.
+ * the refcount) because the caller usually wants figgle with the channel
+ * (like transfering it to a different thread) and thus keeps the
+ * refcount artifically high to prevent its destruction.
*
*----------------------------------------------------------------------
*/
@@ -3376,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");
@@ -3396,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
@@ -3407,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");
@@ -3428,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;
}
}
@@ -3455,18 +3200,18 @@ Tcl_SpliceChannel(
*----------------------------------------------------------------------
*/
+ /* ARGSUSED */
int
Tcl_Close(
Tcl_Interp *interp, /* Interpreter for errors. */
Tcl_Channel chan) /* The channel being closed. Must not be
- * referenced in any interpreter. May be NULL,
- * in which case this is a no-op. */
+ * referenced in any interpreter. */
{
CloseCallback *cbPtr; /* Iterate over close callbacks for this
* channel. */
Channel *chanPtr; /* The real IO channel. */
ChannelState *statePtr; /* State of real IO channel. */
- int result = 0; /* Of calling FlushChannel. */
+ int result; /* Of calling FlushChannel. */
int flushcode;
int stickyError;
@@ -3498,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;
}
@@ -3515,6 +3259,7 @@ Tcl_Close(
if (GotFlag(statePtr, TCL_WRITABLE) && (statePtr->encoding != NULL)
&& !(statePtr->outputEncodingFlags & TCL_ENCODING_START)) {
+
int code = CheckChannelErrors(statePtr, TCL_WRITABLE);
if (code == 0) {
@@ -3535,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;
@@ -3545,19 +3290,14 @@ Tcl_Close(
Tcl_ClearChannelHandlers(chan);
/*
- * Cancel any outstanding timer.
- */
- DeleteTimerHandler(statePtr);
-
- /*
* Invoke the registered close callbacks and delete their records.
*/
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);
@@ -3567,20 +3307,12 @@ Tcl_Close(
* it anymore and this will help avoid deadlocks on some channel types.
*/
-#ifndef TCL_NO_DEPRECATED
- if ((chanPtr->typePtr->closeProc == TCL_CLOSE2PROC) || (chanPtr->typePtr->closeProc == NULL)) {
- /* If this half-close gives a EINVAL or ENOTCONN, just continue the full close */
- result = chanPtr->typePtr->close2Proc(chanPtr->instanceData, interp, TCL_CLOSE_READ);
- if ((result == EINVAL) || result == ENOTCONN) {
- result = 0;
- }
- }
-#else
- result = chanPtr->typePtr->close2Proc(chanPtr->instanceData, interp, TCL_CLOSE_READ);
- if ((result == EINVAL) || result == ENOTCONN) {
+ if (chanPtr->typePtr->closeProc == TCL_CLOSE2PROC) {
+ result = (chanPtr->typePtr->close2Proc)(chanPtr->instanceData, interp,
+ TCL_CLOSE_READ);
+ } else {
result = 0;
}
-#endif
/*
* The call to FlushChannel will flush any queued output and invoke the
@@ -3617,368 +3349,19 @@ Tcl_Close(
}
return TCL_ERROR;
}
-
/*
* Bug 97069ea11a: set error message if a flush code is set and no error
* message set up to now.
*/
-
- if (flushcode != 0) {
- /* flushcode has precedence, if available */
- result = flushcode;
- }
- if ((result != 0) && (result != TCL_ERROR) && (interp != NULL)
- && 0 == TclGetCharLength(Tcl_GetObjResult(interp))) {
- Tcl_SetErrno(result);
+ if (flushcode != 0 && interp != NULL
+ && 0 == Tcl_GetCharLength(Tcl_GetObjResult(interp)) ) {
+ Tcl_SetErrno(flushcode);
Tcl_SetObjResult(interp,
Tcl_NewStringObj(Tcl_PosixError(interp), -1));
}
- if (result != 0) {
- return TCL_ERROR;
- }
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_CloseEx --
- *
- * Closes one side of a channel, read or write, close all.
- *
- * Results:
- * A standard Tcl result.
- *
- * Side effects:
- * Closes one direction of the channel, or do a full close.
- *
- * NOTE:
- * Tcl_CloseEx closes the specified direction of the channel as far as
- * the user is concerned. If flags = 0, this is equivalent to Tcl_Close.
- *
- *----------------------------------------------------------------------
- */
-
-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;
- }
-
- chanPtr = (Channel *) chan;
- statePtr = chanPtr->state;
-
- if ((flags & (TCL_READABLE | TCL_WRITABLE)) == 0) {
- return Tcl_Close(interp, chan);
- }
- if ((flags & (TCL_READABLE | TCL_WRITABLE)) == (TCL_READABLE | TCL_WRITABLE)) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "double-close of channels not supported by %ss",
- chanPtr->typePtr->typeName));
- return TCL_ERROR;
- }
-
- /*
- * 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 (!(GotFlag(statePtr, 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 (GotFlag(statePtr, 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 output 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 callbacks 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 = chanPtr->typePtr->close2Proc(chanPtr->instanceData, NULL, 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;
}
@@ -4022,7 +3405,8 @@ Tcl_ClearChannelHandlers(
/*
* Cancel any outstanding timer.
*/
- DeleteTimerHandler(statePtr);
+
+ Tcl_DeleteTimerHandler(statePtr->timer);
/*
* Remove any references to channel handlers for this channel that may be
@@ -4043,7 +3427,7 @@ Tcl_ClearChannelHandlers(
for (chPtr = statePtr->chPtr; chPtr != NULL; chPtr = chNext) {
chNext = chPtr->nextPtr;
- ckfree(chPtr);
+ ckfree((char *) chPtr);
}
statePtr->chPtr = NULL;
@@ -4055,10 +3439,10 @@ Tcl_ClearChannelHandlers(
StopCopy(statePtr->csPtrW);
/*
- * Must set the interest mask now to 0, otherwise infinite loops will
- * occur if Tcl_DoOneEvent is called before the channel is finally deleted
- * in FlushChannel. This can happen if the channel has a background flush
- * active.
+ * Must set the interest mask now to 0, otherwise infinite loops
+ * will occur if Tcl_DoOneEvent is called before the channel is
+ * finally deleted in FlushChannel. This can happen if the channel
+ * has a background flush active.
*/
statePtr->interestMask = 0;
@@ -4070,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;
}
@@ -4089,8 +3473,8 @@ Tcl_ClearChannelHandlers(
* No encoding conversions are applied to the bytes being read.
*
* Results:
- * The number of bytes written or TCL_INDEX_NONE in case of error. If
- * TCL_INDEX_NONE, Tcl_GetErrno will return the error code.
+ * The number of bytes written or -1 in case of error. If -1,
+ * Tcl_GetErrno will return the error code.
*
* Side effects:
* May buffer up output and may cause output to be produced on the
@@ -4099,11 +3483,11 @@ Tcl_ClearChannelHandlers(
*----------------------------------------------------------------------
*/
-Tcl_Size
+int
Tcl_Write(
Tcl_Channel chan, /* The channel to buffer output for. */
const char *src, /* Data to queue in output buffer. */
- Tcl_Size srcLen) /* Length of data in bytes, or < 0 for
+ int srcLen) /* Length of data in bytes, or < 0 for
* strlen(). */
{
/*
@@ -4117,14 +3501,14 @@ Tcl_Write(
chanPtr = statePtr->topChanPtr;
if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) {
- return TCL_INDEX_NONE;
+ return -1;
}
if (srcLen < 0) {
srcLen = strlen(src);
}
if (WriteBytes(chanPtr, src, srcLen) < 0) {
- return TCL_INDEX_NONE;
+ return -1;
}
return srcLen;
}
@@ -4143,8 +3527,8 @@ Tcl_Write(
* No encoding conversions are applied to the bytes being read.
*
* Results:
- * The number of bytes written or TCL_INDEX_NONE in case of error. If
- * TCL_INDEX_NONE, Tcl_GetErrno will return the error code.
+ * The number of bytes written or -1 in case of error. If -1,
+ * Tcl_GetErrno will return the error code.
*
* Side effects:
* May buffer up output and may cause output to be produced on the
@@ -4153,21 +3537,20 @@ Tcl_Write(
*----------------------------------------------------------------------
*/
-Tcl_Size
+int
Tcl_WriteRaw(
Tcl_Channel chan, /* The channel to buffer output for. */
const char *src, /* Data to queue in output buffer. */
- Tcl_Size srcLen) /* Length of data in bytes, or TCL_INDEX_NONE for
+ int srcLen) /* Length of data in bytes, or < 0 for
* strlen(). */
{
Channel *chanPtr = ((Channel *) chan);
ChannelState *statePtr = chanPtr->state;
/* State info for channel */
- int errorCode;
- Tcl_Size written;
+ int errorCode, written;
if (CheckChannelErrors(statePtr, TCL_WRITABLE | CHANNEL_RAW_MODE) != 0) {
- return TCL_INDEX_NONE;
+ return -1;
}
if (srcLen < 0) {
@@ -4179,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);
}
@@ -4200,8 +3585,8 @@ Tcl_WriteRaw(
* specified channel to the topmost channel in a stack.
*
* Results:
- * The number of bytes written or TCL_INDEX_NONE in case of error. If
- * TCL_INDEX_NONE, Tcl_GetErrno will return the error code.
+ * The number of bytes written or -1 in case of error. If -1,
+ * Tcl_GetErrno will return the error code.
*
* Side effects:
* May buffer up output and may cause output to be produced on the
@@ -4210,21 +3595,21 @@ Tcl_WriteRaw(
*----------------------------------------------------------------------
*/
-Tcl_Size
+int
Tcl_WriteChars(
Tcl_Channel chan, /* The channel to buffer output for. */
const char *src, /* UTF-8 characters to queue in output
* buffer. */
- Tcl_Size len) /* Length of string in bytes, or TCL_INDEX_NONE for
+ int len) /* Length of string in bytes, or < 0 for
* strlen(). */
{
Channel *chanPtr = (Channel *) chan;
ChannelState *statePtr = chanPtr->state; /* State info for channel */
- Tcl_Size result;
+ int result;
Tcl_Obj *objPtr;
if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) {
- return TCL_INDEX_NONE;
+ return -1;
}
chanPtr = statePtr->topChanPtr;
@@ -4239,7 +3624,7 @@ Tcl_WriteChars(
/*
* Inefficient way to convert UTF-8 to byte-array, but the code
* parallels the way it is done for objects. Special case for 1-byte
- * (used by e.g. [puts] for the \n) could be extended to more efficient
+ * (used by eg [puts] for the \n) could be extended to more efficient
* translation of the src string.
*/
@@ -4269,8 +3654,8 @@ Tcl_WriteChars(
* line buffering mode.
*
* Results:
- * The number of bytes written or TCL_INDEX_NONE in case of error. If
- * TCL_INDEX_NONE, Tcl_GetErrno() will return the error code.
+ * The number of bytes written or -1 in case of error. If -1,
+ * Tcl_GetErrno() will return the error code.
*
* Side effects:
* May buffer up output and may cause output to be produced on the
@@ -4279,7 +3664,7 @@ Tcl_WriteChars(
*----------------------------------------------------------------------
*/
-Tcl_Size
+int
Tcl_WriteObj(
Tcl_Channel chan, /* The channel to buffer output for. */
Tcl_Obj *objPtr) /* The object to write. */
@@ -4290,14 +3675,14 @@ Tcl_WriteObj(
Channel *chanPtr;
ChannelState *statePtr; /* State info for channel */
- const char *src;
- Tcl_Size srcLen;
+ char *src;
+ int srcLen;
statePtr = ((Channel *) chan)->state;
chanPtr = statePtr->topChanPtr;
if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) {
- return TCL_INDEX_NONE;
+ return -1;
}
if (statePtr->encoding == NULL) {
src = (char *) Tcl_GetByteArrayFromObj(objPtr, &srcLen);
@@ -4308,55 +3693,42 @@ Tcl_WriteObj(
}
}
-static void
-WillWrite(
- Channel *chanPtr)
+static void WillWrite(Channel *chanPtr)
{
int inputBuffered;
- if (((Tcl_ChannelWideSeekProc(chanPtr->typePtr) != NULL)
-#ifndef TCL_NO_DEPRECATED
- || (Tcl_ChannelSeekProc(chanPtr->typePtr) != NULL)
-#endif
- ) && ((inputBuffered = Tcl_InputBuffered((Tcl_Channel) chanPtr)) > 0)){
- int ignore;
-
- DiscardInputQueued(chanPtr->state, 0);
- ChanSeek(chanPtr, -inputBuffered, SEEK_CUR, &ignore);
+ if ((chanPtr->typePtr->seekProc != NULL)
+ && ((inputBuffered = Tcl_InputBuffered((Tcl_Channel) chanPtr)) > 0)) {
+ int ignore;
+ DiscardInputQueued(chanPtr->state, 0);
+ 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.
- */
-
- DiscardInputQueued(chanPtr->state, 0);
+ /* Prevent read attempts on a closed channel */
+ DiscardInputQueued(chanPtr->state, 0);
Tcl_SetErrno(EINVAL);
return -1;
}
- if (((Tcl_ChannelWideSeekProc(chanPtr->typePtr) != NULL)
-#ifndef TCL_NO_DEPRECATED
- || (Tcl_ChannelSeekProc(chanPtr->typePtr) != NULL)
-#endif
- ) && (Tcl_OutputBuffered((Tcl_Channel) chanPtr) > 0)) {
+ if ((chanPtr->typePtr->seekProc != NULL)
+ && (Tcl_OutputBuffered((Tcl_Channel) chanPtr) > 0)) {
+
/*
- * CAVEAT - The assumption here is that FlushChannel() will push out
- * the bytes of any writes that are in progress. Since this is a
- * seekable channel, we assume it is not one that can block and force
- * bg flushing. Channels we know that can do that - sockets, pipes -
- * are not seekable. If the assumption is wrong, more drastic measures
- * may be required here like temporarily setting the channel into
- * blocking mode.
+ * CAVEAT - The assumption here is that FlushChannel() will
+ * push out the bytes of any writes that are in progress.
+ * Since this is a seekable channel, we assume it is not one
+ * that can block and force bg flushing. Channels we know that
+ * can do that -- sockets, pipes -- are not seekable. If the
+ * assumption is wrong, more drastic measures may be required here
+ * like temporarily setting the channel into blocking mode.
*/
- if (FlushChannel(NULL, chanPtr, 0) != 0) {
- return -1;
- }
+ if (FlushChannel(NULL, chanPtr, 0) != 0) {
+ return -1;
+ }
}
return 0;
}
@@ -4372,7 +3744,7 @@ WillRead(
* ready e.g. if it contains a newline and we are in line buffering mode.
*
* Results:
- * The number of bytes written or TCL_INDEX_NONE in case of error. If TCL_INDEX_NONE,
+ * The number of bytes written or -1 in case of error. If -1,
* Tcl_GetErrno will return the error code.
*
* Side effects:
@@ -4382,20 +3754,17 @@ WillRead(
*----------------------------------------------------------------------
*/
-static Tcl_Size
+static int
Write(
Channel *chanPtr, /* The channel to buffer output for. */
const char *src, /* UTF-8 string to write. */
- Tcl_Size srcLen, /* Length of UTF-8 string in bytes. */
+ int srcLen, /* Length of UTF-8 string in bytes. */
Tcl_Encoding encoding)
{
ChannelState *statePtr = chanPtr->state;
/* State info for channel */
char *nextNewLine = NULL;
- int endEncoding, needNlFlush = 0;
- int saved = 0, total = 0, flushed = 0;
- char safe[BUFFER_PADDING];
- int encodingError = 0;
+ int endEncoding, saved = 0, total = 0, flushed = 0, needNlFlush = 0;
if (srcLen) {
WillWrite(chanPtr);
@@ -4406,21 +3775,21 @@ Write(
*/
endEncoding = ((statePtr->outputEncodingFlags & TCL_ENCODING_END) != 0);
+
if (GotFlag(statePtr, CHANNEL_LINEBUFFERED)
|| (statePtr->outputTranslation != TCL_TRANSLATE_LF)) {
- nextNewLine = (char *)memchr(src, '\n', srcLen);
+ nextNewLine = memchr(src, '\n', srcLen);
}
- while (srcLen + saved + endEncoding > 0 && !encodingError) {
+ while (srcLen + saved + endEncoding > 0) {
ChannelBuffer *bufPtr;
- char *dst;
- int result, srcRead, dstLen, dstWrote;
- Tcl_Size srcLimit = srcLen;
+ char *dst, safe[BUFFER_PADDING];
+ int result, srcRead, dstLen, dstWrote, srcLimit = srcLen;
if (nextNewLine) {
srcLimit = nextNewLine - src;
}
-
+
/* Get space to write into */
bufPtr = statePtr->curOutPtr;
if (bufPtr == NULL) {
@@ -4433,10 +3802,11 @@ Write(
* that we need to stick at the beginning of this buffer.
*/
- memcpy(InsertPoint(bufPtr), safe, saved);
+ memcpy(InsertPoint(bufPtr), safe, (size_t) saved);
bufPtr->nextAdded += saved;
saved = 0;
}
+ PreserveChannelBuffer(bufPtr);
dst = InsertPoint(bufPtr);
dstLen = SpaceLeft(bufPtr);
@@ -4445,32 +3815,17 @@ Write(
&statePtr->outputEncodingState, dst,
dstLen + BUFFER_PADDING, &srcRead, &dstWrote, NULL);
- /*
- * See chan-io-1.[89]. Tcl Bug 506297.
- */
-
+ /* See chan-io-1.[89]. Tcl Bug 506297. */
statePtr->outputEncodingFlags &= ~TCL_ENCODING_START;
-
- /*
- * See io-75.2, TCL bug 6978c01b65.
- * Check, if an encoding error occured and should be reported to the
- * script level.
- * This happens, if a written character may not be represented by the
- * current output encoding and strict encoding is active.
- */
-
- if (result == TCL_CONVERT_UNKNOWN || result == TCL_CONVERT_SYNTAX) {
- encodingError = 1;
- result = TCL_OK;
- }
-
+
if ((result != TCL_OK) && (srcRead + dstWrote == 0)) {
- /*
- * We're reading from invalid/incomplete UTF-8.
- */
-
- encodingError = 1;
- result = TCL_OK;
+ /* We're reading from invalid/incomplete UTF-8 */
+ ReleaseChannelBuffer(bufPtr);
+ if (total == 0) {
+ Tcl_SetErrno(EINVAL);
+ return -1;
+ }
+ break;
}
bufPtr->nextAdded += dstWrote;
@@ -4502,12 +3857,13 @@ Write(
Tcl_Panic("unknown output translation requested");
break;
}
-
+
result |= Tcl_UtfToExternal(NULL, encoding, nl, nlLen,
- statePtr->outputEncodingFlags,
- &statePtr->outputEncodingState, dst,
- dstLen + BUFFER_PADDING, &srcRead, &dstWrote, NULL);
- assert(srcRead == nlLen);
+ statePtr->outputEncodingFlags,
+ &statePtr->outputEncodingState, dst,
+ dstLen + BUFFER_PADDING, &srcRead, &dstWrote, NULL);
+
+ assert (srcRead == nlLen);
bufPtr->nextAdded += dstWrote;
src++;
@@ -4515,21 +3871,21 @@ Write(
total += dstWrote;
dst += dstWrote;
dstLen -= dstWrote;
- nextNewLine = (char *)memchr(src, '\n', srcLen);
+ nextNewLine = memchr(src, '\n', srcLen);
needNlFlush = 1;
}
if (IsBufferOverflowing(bufPtr)) {
/*
- * When translating from UTF-8 to external encoding, we allowed
- * the translation to produce a character that crossed the end of
- * the output buffer, so that we would get a completely full
- * buffer before flushing it. The extra bytes will be moved to the
- * beginning of the next buffer.
+ * When translating from UTF-8 to external encoding, we
+ * allowed the translation to produce a character that crossed
+ * the end of the output buffer, so that we would get a
+ * completely full buffer before flushing it. The extra bytes
+ * will be moved to the beginning of the next buffer.
*/
saved = -SpaceLeft(bufPtr);
- memcpy(safe, dst + dstLen, saved);
+ memcpy(safe, dst + dstLen, (size_t) saved);
bufPtr->nextAdded = bufPtr->bufLength;
}
@@ -4539,39 +3895,34 @@ Write(
if (IsBufferFull(bufPtr)) {
if (FlushChannel(NULL, chanPtr, 0) != 0) {
+ ReleaseChannelBuffer(bufPtr);
return -1;
}
flushed += statePtr->bufSize;
/*
- * We just flushed. So if we have needNlFlush set to record that
- * we need to flush because there is a (translated) newline in the
- * buffer, that's likely not true any more. But there is a tricky
- * exception. If we have saved bytes that did not really get
- * flushed and those bytes came from a translation of a newline as
- * the last thing taken from the src array, then needNlFlush needs
- * to remain set to flag that the next buffer still needs a
- * newline flush.
+ * We just flushed. So if we have needNlFlush set to record
+ * that we need to flush because theres a (translated) newline
+ * in the buffer, that's likely not true any more. But there
+ * is a tricky exception. If we have saved bytes that did not
+ * really get flushed and those bytes came from a translation
+ * of a newline as the last thing taken from the src array,
+ * then needNlFlush needs to remain set to flag that the
+ * next buffer still needs a newline flush.
*/
-
if (needNlFlush && (saved == 0 || src[-1] != '\n')) {
needNlFlush = 0;
}
}
+ ReleaseChannelBuffer(bufPtr);
}
- if (((flushed < total) && GotFlag(statePtr, CHANNEL_UNBUFFERED)) ||
- (needNlFlush && GotFlag(statePtr, CHANNEL_LINEBUFFERED))) {
+ if ((flushed < total) && (GotFlag(statePtr, CHANNEL_UNBUFFERED) ||
+ (needNlFlush && GotFlag(statePtr, CHANNEL_LINEBUFFERED)))) {
if (FlushChannel(NULL, chanPtr, 0) != 0) {
return -1;
}
}
- UpdateInterest(chanPtr);
-
- if (encodingError) {
- Tcl_SetErrno(EILSEQ);
- return -1;
- }
return total;
}
@@ -4583,8 +3934,8 @@ Write(
* Reads a complete line of input from the channel into a Tcl_DString.
*
* Results:
- * Length of line read (in characters) or TCL_INDEX_NONE if error, EOF, or blocked.
- * If TCL_INDEX_NONE, use Tcl_GetErrno() to retrieve the POSIX error code for the
+ * Length of line read (in characters) or -1 if error, EOF, or blocked.
+ * If -1, use Tcl_GetErrno() to retrieve the POSIX error code for the
* error or condition that occurred.
*
* Side effects:
@@ -4594,7 +3945,7 @@ Write(
*---------------------------------------------------------------------------
*/
-Tcl_Size
+int
Tcl_Gets(
Tcl_Channel chan, /* Channel from which to read. */
Tcl_DString *lineRead) /* The line read will be appended to this
@@ -4603,12 +3954,14 @@ Tcl_Gets(
* for managing the storage. */
{
Tcl_Obj *objPtr;
- Tcl_Size 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;
@@ -4624,8 +3977,8 @@ Tcl_Gets(
* converted to UTF-8 using the encoding specified by the channel.
*
* Results:
- * Number of characters accumulated in the object or TCL_INDEX_NONE if error,
- * blocked, or EOF. If TCL_INDEX_NONE, use Tcl_GetErrno() to retrieve the POSIX error
+ * Number of characters accumulated in the object or -1 if error,
+ * blocked, or EOF. If -1, use Tcl_GetErrno() to retrieve the POSIX error
* code for the error or condition that occurred.
*
* Side effects:
@@ -4637,7 +3990,7 @@ Tcl_Gets(
*---------------------------------------------------------------------------
*/
-Tcl_Size
+int
Tcl_GetsObj(
Tcl_Channel chan, /* Channel from which to read. */
Tcl_Obj *objPtr) /* The line read will be appended to this
@@ -4648,21 +4001,13 @@ Tcl_GetsObj(
ChannelState *statePtr = chanPtr->state;
/* State info for channel */
ChannelBuffer *bufPtr;
- int inEofChar, skip, copiedTotal, oldFlags, oldRemoved;
- Tcl_Size oldLength;
+ int inEofChar, skip, copiedTotal, oldLength, oldFlags, oldRemoved;
Tcl_Encoding encoding;
char *dst, *dstEnd, *eol, *eof;
Tcl_EncodingState oldState;
- if (GotFlag(statePtr, CHANNEL_ENCODING_ERROR)) {
- UpdateInterest(chanPtr);
- ResetFlag(statePtr, CHANNEL_EOF|CHANNEL_ENCODING_ERROR);
- Tcl_SetErrno(EILSEQ);
- return TCL_INDEX_NONE;
- }
-
if (CheckChannelErrors(statePtr, TCL_READABLE) != 0) {
- return TCL_INDEX_NONE;
+ return -1;
}
/*
@@ -4672,12 +4017,12 @@ Tcl_GetsObj(
if (GotFlag(statePtr, CHANNEL_STICKY_EOF)) {
SetFlag(statePtr, CHANNEL_EOF);
- assert(statePtr->inputEncodingFlags & TCL_ENCODING_END);
- assert(!GotFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR));
+ assert( statePtr->inputEncodingFlags & TCL_ENCODING_END );
+ assert( !GotFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR) );
/* TODO: Do we need this? */
UpdateInterest(chanPtr);
- return TCL_INDEX_NONE;
+ return -1;
}
/*
@@ -4749,12 +4094,6 @@ Tcl_GetsObj(
ResetFlag(statePtr, CHANNEL_BLOCKED);
while (1) {
if (dst >= dstEnd) {
- /*
- * In case of encoding errors, state gets flag
- * CHANNEL_ENCODING_ERROR set in the call below. First, the
- * EOF/EOL condition is checked, as we may have valid data with
- * EOF/EOL before the encoding error.
- */
if (FilterInputBytes(chanPtr, &gs) != 0) {
goto restore;
}
@@ -4805,12 +4144,12 @@ Tcl_GetsObj(
/*
* If a CR is at the end of the buffer, then check for a
- * LF at the beginning of the next buffer, unless EOF char
+ * LF at the begining of the next buffer, unless EOF char
* was found already.
*/
if (eol >= dstEnd) {
- Tcl_Size offset;
+ int offset;
if (eol != eof) {
offset = eol - objPtr->bytes;
@@ -4838,24 +4177,25 @@ Tcl_GetsObj(
eol = dst;
skip = 1;
if (GotFlag(statePtr, INPUT_SAW_CR)) {
+ ResetFlag(statePtr, INPUT_SAW_CR);
if ((eol < dstEnd) && (*eol == '\n')) {
/*
* Skip the raw bytes that make up the '\n'.
*/
+ char tmp[1 + TCL_UTF_MAX];
int rawRead;
- char tmp[TCL_UTF_MAX];
bufPtr = gs.bufPtr;
Tcl_ExternalToUtf(NULL, gs.encoding, RemovePoint(bufPtr),
- gs.rawRead, statePtr->inputEncodingFlags
- | TCL_ENCODING_NO_TERMINATE, &gs.state, tmp,
- sizeof(tmp), &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--;
gs.charsWrote--;
- memmove(dst, dst + 1, dstEnd - dst);
+ memmove(dst, dst + 1, (size_t) (dstEnd - dst));
dstEnd--;
}
}
@@ -4887,10 +4227,8 @@ Tcl_GetsObj(
skip++;
}
eol--;
- ResetFlag(statePtr, INPUT_SAW_CR);
goto gotEOL;
} else if (*eol == '\n') {
- ResetFlag(statePtr, INPUT_SAW_CR);
goto gotEOL;
}
}
@@ -4919,32 +4257,10 @@ Tcl_GetsObj(
Tcl_SetObjLength(objPtr, oldLength);
CommonGetsCleanup(chanPtr);
copiedTotal = -1;
- ResetFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR);
+ ResetFlag(statePtr, CHANNEL_BLOCKED);
goto done;
}
goto gotEOL;
- } else if (gs.bytesWrote == 0
- && GotFlag(statePtr, CHANNEL_ENCODING_ERROR)) {
- /* Ticket c4eb46a1 Harald Oehlmann 2023-11-12 debugging session.
- * In non blocking mode we loop indifenitly on a decoding error in
- * this while-loop.
- * Removed the following from the upper condition:
- * "&& !GotFlag(statePtr, CHANNEL_NONBLOCKING)"
- * In case of an encoding error with leading correct bytes, we pass here
- * two times, as gs.bytesWrote is not 0 on the first pass. This feels
- * once to much, as the data is anyway not used.
- */
-
- /* Set eol to the position that caused the encoding error, and then
- * continue to gotEOL, which stores the data that was decoded
- * without error to objPtr. This allows the caller to do something
- * useful with the data decoded so far, and also results in the
- * position of the file being the first byte that was not
- * successfully decoded, allowing further processing at exactly that
- * point, if desired.
- */
- eol = dstEnd;
- goto gotEOL;
}
dst = dstEnd;
}
@@ -4975,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;
@@ -5042,18 +4357,17 @@ Tcl_GetsObj(
*/
done:
- assert(!GotFlag(statePtr, CHANNEL_EOF)
- || GotFlag(statePtr, CHANNEL_STICKY_EOF)
- || GotFlag(statePtr, CHANNEL_ENCODING_ERROR)
- || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0);
- assert(!(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED)
- == (CHANNEL_EOF|CHANNEL_BLOCKED)));
+ assert(!GotFlag(statePtr, CHANNEL_EOF)
+ || GotFlag(statePtr, CHANNEL_STICKY_EOF)
+ || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0);
+
+ assert( !(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED)
+ == (CHANNEL_EOF|CHANNEL_BLOCKED)) );
/*
* Regenerate the top channel, in case it was changed due to
* self-modifying reflected transforms.
*/
-
if (chanPtr != statePtr->topChanPtr) {
TclChannelRelease((Tcl_Channel)chanPtr);
chanPtr = statePtr->topChanPtr;
@@ -5061,12 +4375,6 @@ Tcl_GetsObj(
}
UpdateInterest(chanPtr);
TclChannelRelease((Tcl_Channel)chanPtr);
- if (GotFlag(statePtr, CHANNEL_ENCODING_ERROR) && gs.bytesWrote == 0) {
- bufPtr->nextRemoved = oldRemoved;
- Tcl_SetErrno(EILSEQ);
- copiedTotal = -1;
- }
- ResetFlag(statePtr, CHANNEL_ENCODING_ERROR);
return copiedTotal;
}
@@ -5079,13 +4387,14 @@ Tcl_GetsObj(
* end-of-line or end-of-file has been seen. Bytes read from the input
* channel return as a ByteArray obj.
*
- * WARNING! The notion of "binary" used here is different from notions
- * of "binary" used in other places. In particular, this "binary" routine
- * may be called when an -eofchar is set on the channel.
+ * WARNING! The notion of "binary" used here is different from
+ * notions of "binary" used in other places. In particular, this
+ * "binary" routine may be called when an -eofchar is set on the
+ * channel.
*
* Results:
- * Number of characters accumulated in the object or TCL_INDEX_NONE if error,
- * blocked, or EOF. If TCL_INDEX_NONE, use Tcl_GetErrno() to retrieve the POSIX error
+ * Number of characters accumulated in the object or -1 if error,
+ * blocked, or EOF. If -1, use Tcl_GetErrno() to retrieve the POSIX error
* code for the error or condition that occurred.
*
* Side effects:
@@ -5107,9 +4416,8 @@ TclGetsObjBinary(
ChannelState *statePtr = chanPtr->state;
/* State info for channel */
ChannelBuffer *bufPtr;
- int inEofChar, skip, copiedTotal, oldFlags, oldRemoved;
- Tcl_Size rawLen, byteLen, oldLength;
- int eolChar;
+ int inEofChar, skip, copiedTotal, oldLength, oldFlags, oldRemoved;
+ int rawLen, byteLen, eolChar;
unsigned char *dst, *dstEnd, *eol, *eof, *byteArray;
/*
@@ -5138,18 +4446,14 @@ 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);
while (1) {
/*
- * Subtract the number of bytes that were removed from channel buffer
- * during last call.
+ * Subtract the number of bytes that were removed from channel
+ * buffer during last call.
*/
if (bufPtr != NULL) {
@@ -5161,11 +4465,10 @@ TclGetsObjBinary(
if ((bufPtr == NULL) || (bufPtr->nextAdded == BUFFER_PADDING)) {
/*
- * All channel buffers were exhausted and the caller still hasn't
- * seen EOL. Need to read more bytes from the channel device. Side
- * effect is to allocate another channel buffer.
+ * All channel buffers were exhausted and the caller still
+ * hasn't seen EOL. Need to read more bytes from the channel
+ * device. Side effect is to allocate another channel buffer.
*/
-
if (GetInput(chanPtr) != 0) {
goto restore;
}
@@ -5175,15 +4478,15 @@ TclGetsObjBinary(
}
} else {
/*
- * Incoming CHANNEL_STICKY_EOF is filtered out on entry. A new
- * CHANNEL_STICKY_EOF set in this routine leads to return before
- * coming back here. When we are not dealing with
- * CHANNEL_STICKY_EOF, a CHANNEL_EOF implies an empty buffer.
- * Here the buffer is non-empty so we know we're a non-EOF.
- */
+ * Incoming CHANNEL_STICKY_EOF is filtered out on entry.
+ * A new CHANNEL_STICKY_EOF set in this routine leads to
+ * return before coming back here. When we are not dealing
+ * with CHANNEL_STICKY_EOF, a CHANNEL_EOF implies an
+ * empty buffer. Here the buffer is non-empty so we know
+ * we're a non-EOF */
- assert(!GotFlag(statePtr, CHANNEL_STICKY_EOF));
- assert(!GotFlag(statePtr, CHANNEL_EOF));
+ assert ( !GotFlag(statePtr, CHANNEL_STICKY_EOF) );
+ assert ( !GotFlag(statePtr, CHANNEL_EOF) );
}
dst = (unsigned char *) RemovePoint(bufPtr);
@@ -5233,7 +4536,7 @@ TclGetsObjBinary(
if ((dst == dstEnd) && (byteLen == oldLength)) {
/*
* If we didn't append any bytes before encountering EOF,
- * caller needs to see TCL_INDEX_NONE.
+ * caller needs to see -1.
*/
byteArray = Tcl_SetByteArrayLength(objPtr, oldLength);
@@ -5250,13 +4553,13 @@ TclGetsObjBinary(
}
/*
- * Copy bytes from the channel buffer to the ByteArray. This may
- * realloc space, so keep track of result.
+ * Copy bytes from the channel buffer to the ByteArray.
+ * This may realloc space, so keep track of result.
*/
rawLen = dstEnd - dst;
byteArray = Tcl_SetByteArrayLength(objPtr, byteLen + rawLen);
- memcpy(byteArray + byteLen, dst, rawLen);
+ memcpy(byteArray + byteLen, dst, (size_t) rawLen);
byteLen += rawLen;
}
@@ -5273,7 +4576,7 @@ TclGetsObjBinary(
rawLen = eol - dst;
byteArray = Tcl_SetByteArrayLength(objPtr, byteLen + rawLen);
- memcpy(byteArray + byteLen, dst, rawLen);
+ memcpy(byteArray + byteLen, dst, (size_t) rawLen);
byteLen += rawLen;
bufPtr->nextRemoved += rawLen + skip;
@@ -5335,11 +4638,11 @@ TclGetsObjBinary(
*/
done:
- assert(!GotFlag(statePtr, CHANNEL_EOF)
- || GotFlag(statePtr, CHANNEL_STICKY_EOF)
- || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0);
- assert(!(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED)
- == (CHANNEL_EOF|CHANNEL_BLOCKED)));
+ assert(!GotFlag(statePtr, CHANNEL_EOF)
+ || GotFlag(statePtr, CHANNEL_STICKY_EOF)
+ || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0);
+ assert( !(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED)
+ == (CHANNEL_EOF|CHANNEL_BLOCKED)) );
UpdateInterest(chanPtr);
TclChannelRelease((Tcl_Channel)chanPtr);
return copiedTotal;
@@ -5361,7 +4664,7 @@ TclGetsObjBinary(
static void
FreeBinaryEncoding(
- TCL_UNUSED(void *))
+ ClientData dummy) /* Not used */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
@@ -5372,7 +4675,7 @@ FreeBinaryEncoding(
}
static Tcl_Encoding
-GetBinaryEncoding(void)
+GetBinaryEncoding()
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
@@ -5472,15 +4775,15 @@ FilterInputBytes(
}
} else {
/*
- * Incoming CHANNEL_STICKY_EOF is filtered out on entry. A new
- * CHANNEL_STICKY_EOF set in this routine leads to return before
- * coming back here. When we are not dealing with CHANNEL_STICKY_EOF,
- * a CHANNEL_EOF implies an empty buffer. Here the buffer is
- * non-empty so we know we're a non-EOF.
- */
+ * Incoming CHANNEL_STICKY_EOF is filtered out on entry.
+ * A new CHANNEL_STICKY_EOF set in this routine leads to
+ * return before coming back here. When we are not dealing
+ * with CHANNEL_STICKY_EOF, a CHANNEL_EOF implies an
+ * empty buffer. Here the buffer is non-empty so we know
+ * we're a non-EOF */
- assert(!GotFlag(statePtr, CHANNEL_STICKY_EOF));
- assert(!GotFlag(statePtr, CHANNEL_EOF));
+ assert ( !GotFlag(statePtr, CHANNEL_STICKY_EOF) );
+ assert ( !GotFlag(statePtr, CHANNEL_EOF) );
}
/*
@@ -5516,18 +4819,10 @@ FilterInputBytes(
*gsPtr->dstPtr = dst;
}
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);
-
- if (result == TCL_CONVERT_UNKNOWN || result == TCL_CONVERT_SYNTAX) {
- SetFlag(statePtr, CHANNEL_ENCODING_ERROR);
- ResetFlag(statePtr, CHANNEL_STICKY_EOF);
- ResetFlag(statePtr, CHANNEL_EOF);
- result = TCL_OK;
- }
+ 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
@@ -5725,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;
@@ -5748,7 +5043,7 @@ CommonGetsCleanup(
* No encoding conversions are applied to the bytes being read.
*
* Results:
- * The number of bytes read, or TCL_INDEX_NONE on error. Use Tcl_GetErrno() to
+ * The number of bytes read, or -1 on error. Use Tcl_GetErrno() to
* retrieve the error code for the error that occurred.
*
* Side effects:
@@ -5757,11 +5052,11 @@ CommonGetsCleanup(
*----------------------------------------------------------------------
*/
-Tcl_Size
+int
Tcl_Read(
Tcl_Channel chan, /* The channel from which to read. */
char *dst, /* Where to store input read. */
- Tcl_Size bytesToRead) /* Maximum number of bytes to read. */
+ int bytesToRead) /* Maximum number of bytes to read. */
{
Channel *chanPtr = (Channel *) chan;
ChannelState *statePtr = chanPtr->state;
@@ -5774,10 +5069,10 @@ Tcl_Read(
chanPtr = statePtr->topChanPtr;
if (CheckChannelErrors(statePtr, TCL_READABLE) != 0) {
- return TCL_INDEX_NONE;
+ return -1;
}
- return DoRead(chanPtr, dst, bytesToRead, 0);
+ return DoRead(chanPtr, dst, bytesToRead);
}
/*
@@ -5793,7 +5088,7 @@ Tcl_Read(
* No encoding conversions are applied to the bytes being read.
*
* Results:
- * The number of bytes read, or TCL_INDEX_NONE on error. Use Tcl_GetErrno() to
+ * The number of bytes read, or -1 on error. Use Tcl_GetErrno() to
* retrieve the error code for the error that occurred.
*
* Side effects:
@@ -5802,11 +5097,11 @@ Tcl_Read(
*----------------------------------------------------------------------
*/
-Tcl_Size
+int
Tcl_ReadRaw(
Tcl_Channel chan, /* The channel from which to read. */
char *readBuf, /* Where to store input read. */
- Tcl_Size bytesToRead) /* Maximum number of bytes to read. */
+ int bytesToRead) /* Maximum number of bytes to read. */
{
Channel *chanPtr = (Channel *) chan;
ChannelState *statePtr = chanPtr->state;
@@ -5815,12 +5110,10 @@ Tcl_ReadRaw(
assert(bytesToRead > 0);
if (CheckChannelErrors(statePtr, TCL_READABLE | CHANNEL_RAW_MODE) != 0) {
- return TCL_INDEX_NONE;
+ return -1;
}
- /*
- * First read bytes from the push-back buffers.
- */
+ /* First read bytes from the push-back buffers. */
while (chanPtr->inQueueHead && bytesToRead > 0) {
ChannelBuffer *bufPtr = chanPtr->inQueueHead;
@@ -5828,19 +5121,15 @@ Tcl_ReadRaw(
int toCopy = (bytesInBuffer < bytesToRead) ? bytesInBuffer
: bytesToRead;
- /*
- * Copy the current chunk into the read buffer.
- */
+ /* Copy the current chunk into the read buffer. */
- memcpy(readBuf, RemovePoint(bufPtr), toCopy);
+ memcpy(readBuf, RemovePoint(bufPtr), (size_t) toCopy);
bufPtr->nextRemoved += toCopy;
copied += toCopy;
readBuf += toCopy;
bytesToRead -= toCopy;
- /*
- * If the current buffer is empty recycle it.
- */
+ /* If the current buffer is empty recycle it. */
if (IsBufferEmpty(bufPtr)) {
chanPtr->inQueueHead = bufPtr->nextPtr;
@@ -5852,43 +5141,40 @@ Tcl_ReadRaw(
}
/*
- * Go to the driver only if we got nothing from pushback. Have to do it
- * this way to avoid EOF mistimings when we consider the ability that EOF
- * may not be a permanent condition in the driver, and in that case we
- * have to synchronize.
+ * Go to the driver only if we got nothing from pushback.
+ * Have to do it this way to avoid EOF mis-timings when we
+ * consider the ability that EOF may not be a permanent
+ * condition in the driver, and in that case we have to
+ * synchronize.
*/
if (copied) {
return copied;
}
- /*
- * This test not needed.
- */
-
+ /* This test not needed. */
if (bytesToRead > 0) {
+
int nread = ChanRead(chanPtr, readBuf, bytesToRead);
- if (nread < 0) {
+ if (nread > 0) {
+ /* Successful read (short is OK) - add to bytes copied */
+ copied += nread;
+ } else if (nread < 0) {
/*
- * An error signaled. If CHANNEL_BLOCKED, then the error is not
- * real, but an indication of blocked state. In that case, retain
- * the flag and let caller receive the short read of copied bytes
- * from the pushback. HOWEVER, if copied==0 bytes from pushback
- * then repeat signalling the blocked state as an error to caller
- * so there is no false report of an EOF. When !CHANNEL_BLOCKED,
- * the error is real and passes on to caller.
+ * An error signaled. If CHANNEL_BLOCKED, then the error
+ * is not real, but an indication of blocked state. In
+ * that case, retain the flag and let caller receive the
+ * short read of copied bytes from the pushback.
+ * HOWEVER, if copied==0 bytes from pushback then repeat
+ * signalling the blocked state as an error to caller so
+ * there is no false report of an EOF.
+ * When !CHANNEL_BLOCKED, the error is real and passes on
+ * to caller.
*/
-
if (!GotFlag(statePtr, CHANNEL_BLOCKED) || copied == 0) {
copied = -1;
}
- } else if (nread > 0) {
- /*
- * Successful read (short is OK) - add to bytes copied.
- */
-
- copied += nread;
} else {
/*
* nread == 0. Driver is at EOF. Let that state filter up.
@@ -5911,7 +5197,7 @@ Tcl_ReadRaw(
* object.
*
* Results:
- * The number of characters read, or TCL_INDEX_NONE on error. Use Tcl_GetErrno() to
+ * The number of characters read, or -1 on error. Use Tcl_GetErrno() to
* retrieve the error code for the error that occurred.
*
* Side effects:
@@ -5920,12 +5206,12 @@ Tcl_ReadRaw(
*---------------------------------------------------------------------------
*/
-Tcl_Size
+int
Tcl_ReadChars(
Tcl_Channel chan, /* The channel to read. */
Tcl_Obj *objPtr, /* Input data is stored in this object. */
- Tcl_Size toRead, /* Maximum number of characters to store, or
- * TCL_INDEX_NONE to read all available data (up to EOF or
+ int toRead, /* Maximum number of characters to store, or
+ * -1 to read all available data (up to EOF or
* when channel blocks). */
int appendFlag) /* If non-zero, data read from the channel
* will be appended to the object. Otherwise,
@@ -5949,10 +5235,10 @@ Tcl_ReadChars(
*/
UpdateInterest(chanPtr);
- return TCL_INDEX_NONE;
+ return -1;
}
- return DoReadChars(chanPtr, objPtr, toRead, 0, appendFlag);
+ return DoReadChars(chanPtr, objPtr, toRead, appendFlag);
}
/*
*---------------------------------------------------------------------------
@@ -5967,7 +5253,7 @@ Tcl_ReadChars(
* object.
*
* Results:
- * The number of characters read, or TCL_INDEX_NONE on error. Use Tcl_GetErrno() to
+ * The number of characters read, or -1 on error. Use Tcl_GetErrno() to
* retrieve the error code for the error that occurred.
*
* Side effects:
@@ -5976,14 +5262,13 @@ Tcl_ReadChars(
*---------------------------------------------------------------------------
*/
-static Tcl_Size
+static int
DoReadChars(
Channel *chanPtr, /* The channel to read. */
Tcl_Obj *objPtr, /* Input data is stored in this object. */
- Tcl_Size toRead, /* Maximum number of characters to store, or
- * TCL_INDEX_NONE to read all available data (up to EOF or
+ int toRead, /* Maximum number of characters to store, or
+ * -1 to read all available data (up to EOF or
* when channel blocks). */
- int allowShortReads, /* Allow half-blocking (pipes,sockets) */
int appendFlag) /* If non-zero, data read from the channel
* will be appended to the object. Otherwise,
* the data will replace the existing contents
@@ -5992,47 +5277,59 @@ DoReadChars(
ChannelState *statePtr = chanPtr->state;
/* State info for channel */
ChannelBuffer *bufPtr;
- Tcl_Size copied;
- int result;
+ int copied, copiedNow, result;
Tcl_Encoding encoding = statePtr->encoding;
int binaryMode;
#define UTF_EXPANSION_FACTOR 1024
int factor = UTF_EXPANSION_FACTOR;
- if (GotFlag(statePtr, CHANNEL_ENCODING_ERROR)) {
- ResetFlag(statePtr, CHANNEL_EOF|CHANNEL_ENCODING_ERROR);
- /* TODO: UpdateInterest not needed here? */
- UpdateInterest(chanPtr);
- Tcl_SetErrno(EILSEQ);
- return -1;
+ binaryMode = (encoding == NULL)
+ && (statePtr->inputTranslation == TCL_TRANSLATE_LF)
+ && (statePtr->inEofChar == '\0');
+
+ if (appendFlag == 0) {
+ if (binaryMode) {
+ Tcl_SetByteArrayLength(objPtr, 0);
+ } else {
+ Tcl_SetObjLength(objPtr, 0);
+
+ /*
+ * We're going to access objPtr->bytes directly, so we must ensure
+ * that this is actually a string object (otherwise it might have
+ * been pure Unicode).
+ *
+ * Probably not needed anymore.
+ */
+
+ TclGetString(objPtr);
+ }
}
+
/*
* Early out when next read will see eofchar.
*
- * NOTE: See DoRead for argument that it's a bug (one we're keeping) to
- * have this escape before the one for zero-char read request.
+ * NOTE: See DoRead for argument that it's a bug (one we're keeping)
+ * to have this escape before the one for zero-char read request.
*/
if (GotFlag(statePtr, CHANNEL_STICKY_EOF)) {
SetFlag(statePtr, CHANNEL_EOF);
- assert(statePtr->inputEncodingFlags & TCL_ENCODING_END);
- assert(!GotFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR));
+ assert( statePtr->inputEncodingFlags & TCL_ENCODING_END );
+ assert( !GotFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR) );
- /* TODO: UpdateInterest not needed here? */
+ /* TODO: We don't need this call? */
UpdateInterest(chanPtr);
return 0;
}
- /*
- * Special handling for zero-char read request.
- */
+ /* Special handling for zero-char read request. */
if (toRead == 0) {
if (GotFlag(statePtr, CHANNEL_EOF)) {
statePtr->inputEncodingFlags |= TCL_ENCODING_START;
}
ResetFlag(statePtr, CHANNEL_BLOCKED|CHANNEL_EOF);
statePtr->inputEncodingFlags &= ~TCL_ENCODING_END;
- /* TODO: UpdateInterest not needed here? */
+ /* TODO: We don't need this call? */
UpdateInterest(chanPtr);
return 0;
}
@@ -6044,43 +5341,14 @@ DoReadChars(
chanPtr = statePtr->topChanPtr;
TclChannelPreserve((Tcl_Channel)chanPtr);
- binaryMode = (encoding == NULL)
- && (statePtr->inputTranslation == TCL_TRANSLATE_LF)
- && (statePtr->inEofChar == '\0');
-
- if (appendFlag) {
- if (binaryMode && (NULL == Tcl_GetBytesFromObj(NULL, objPtr, NULL))) {
- binaryMode = 0;
- }
- } else {
- if (binaryMode) {
- Tcl_SetByteArrayLength(objPtr, 0);
- } else {
- Tcl_SetObjLength(objPtr, 0);
-
- /*
- * We're going to access objPtr->bytes directly, so we must ensure
- * that this is actually a string object (otherwise it might have
- * been pure Unicode).
- *
- * Probably not needed anymore.
- */
-
- TclGetString(objPtr);
- }
- }
-
- /*
- * 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;
}
ResetFlag(statePtr, CHANNEL_BLOCKED|CHANNEL_EOF);
statePtr->inputEncodingFlags &= ~TCL_ENCODING_END;
- for (copied = 0; toRead != 0 ; ) {
- int copiedNow = -1;
+ for (copied = 0; (unsigned) toRead > 0; ) {
+ copiedNow = -1;
if (statePtr->inQueueHead != NULL) {
if (binaryMode) {
copiedNow = ReadBytes(statePtr, objPtr, toRead);
@@ -6089,40 +5357,28 @@ DoReadChars(
}
/*
- * Recycle current buffer if empty.
+ * If the current buffer is empty recycle it.
*/
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) {
statePtr->inQueueTail = NULL;
}
}
-
- /*
- * If CHANNEL_ENCODING_ERROR and CHANNEL_STICKY_EOF are both set,
- * then CHANNEL_ENCODING_ERROR was caused by data that occurred
- * after the EOF character was encountered, so it doesn't count as
- * a real error.
- */
-
- if (GotFlag(statePtr, CHANNEL_ENCODING_ERROR)
- && !GotFlag(statePtr, CHANNEL_STICKY_EOF)
- && (!GotFlag(statePtr, CHANNEL_NONBLOCKING))) {
- goto finish;
- }
}
if (copiedNow < 0) {
if (GotFlag(statePtr, CHANNEL_EOF)) {
break;
}
- if ((GotFlag(statePtr, CHANNEL_NONBLOCKING) || allowShortReads)
- && GotFlag(statePtr, CHANNEL_BLOCKED)) {
+ if (GotFlag(statePtr, CHANNEL_NONBLOCKING|CHANNEL_BLOCKED)
+ == (CHANNEL_NONBLOCKING|CHANNEL_BLOCKED)) {
break;
}
result = GetInput(chanPtr);
@@ -6143,22 +5399,19 @@ DoReadChars(
}
}
-finish:
/*
- * Failure to fill a channel buffer may have left channel reporting a
- * "blocked" state, but so long as we fulfilled the request here, the
- * caller does not consider us blocked.
+ * Failure to fill a channel buffer may have left channel reporting
+ * a "blocked" state, but so long as we fulfilled the request here,
+ * the caller does not consider us blocked.
*/
-
if (toRead == 0) {
ResetFlag(statePtr, CHANNEL_BLOCKED);
}
/*
- * Regenerate chanPtr in case it was changed due to
+ * Regenerate the top channel, in case it was changed due to
* self-modifying reflected transforms.
*/
-
if (chanPtr != statePtr->topChanPtr) {
TclChannelRelease((Tcl_Channel)chanPtr);
chanPtr = statePtr->topChanPtr;
@@ -6169,26 +5422,12 @@ finish:
* Update the notifier state so we don't block while there is still data
* in the buffers.
*/
-
- assert(!GotFlag(statePtr, CHANNEL_EOF)
- || GotFlag(statePtr, CHANNEL_STICKY_EOF)
- || GotFlag(statePtr, CHANNEL_ENCODING_ERROR)
- || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0);
- assert(!(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED)
- == (CHANNEL_EOF|CHANNEL_BLOCKED)));
+ assert(!GotFlag(statePtr, CHANNEL_EOF)
+ || GotFlag(statePtr, CHANNEL_STICKY_EOF)
+ || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0);
+ assert( !(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED)
+ == (CHANNEL_EOF|CHANNEL_BLOCKED)) );
UpdateInterest(chanPtr);
-
- /* This must comes after UpdateInterest(), which may set errno */
- if (GotFlag(statePtr, CHANNEL_ENCODING_ERROR)
- && (!copied || !GotFlag(statePtr, CHANNEL_NONBLOCKING))) {
- /* Channel either is blocking or is nonblocking with no data
- * succesfully red before the error. Return an error so that callers
- * like [read] can also return an error.
- */
- ResetFlag(statePtr, CHANNEL_EOF|CHANNEL_ENCODING_ERROR);
- Tcl_SetErrno(EILSEQ);
- copied = -1;
- }
TclChannelRelease((Tcl_Channel)chanPtr);
return copied;
}
@@ -6208,7 +5447,7 @@ finish:
*
* Results:
* The return value is the number of bytes appended to the object, or
- * TCL_INDEX_NONE to indicate that zero bytes were read due to an EOF.
+ * -1 to indicate that zero bytes were read due to an EOF.
*
* Side effects:
* The storage of bytes in objPtr can cause (re-)allocation of memory.
@@ -6224,7 +5463,7 @@ ReadBytes(
* been allocated to hold data, not how many
* bytes of data have been stored in the
* object. */
- int bytesToRead) /* Maximum number of bytes to store, or -1 to
+ int bytesToRead) /* Maximum number of bytes to store, or < 0 to
* get all available bytes. Bytes are obtained
* from the first buffer in the queue - even
* if this number is larger than the number of
@@ -6277,13 +5516,13 @@ ReadChars(
* allocated to hold data, not how many bytes
* of data have been stored in the object. */
int charsToRead, /* Maximum number of characters to store, or
- * TCL_INDEX_NONE to get all available characters.
+ * -1 to get all available characters.
* Characters are obtained from the first
* buffer in the queue -- even if this number
* is larger than the number of characters
* available in the first buffer, only the
* characters from the first buffer are
- * returned. The exception is when there is
+ * returned. The execption is when there is
* not any complete character in the first
* buffer. In that case, a recursive call
* effectively obtains chars from the
@@ -6301,99 +5540,84 @@ ReadChars(
int savedIEFlags = statePtr->inputEncodingFlags;
int savedFlags = statePtr->flags;
char *dst, *src = RemovePoint(bufPtr);
- Tcl_Size numBytes;
- int srcLen = BytesLeft(bufPtr);
+ int dstLimit, numBytes, srcLen = BytesLeft(bufPtr);
/*
- * One src byte can yield at most one character. So when the number of
- * src bytes we plan to read is less than the limit on character count to
- * be read, clearly we will remain within that limit, and we can use the
- * value of "srcLen" as a tighter limit for sizing receiving buffers.
+ * One src byte can yield at most one character. So when the
+ * number of src bytes we plan to read is less than the limit on
+ * character count to be read, clearly we will remain within that
+ * limit, and we can use the value of "srcLen" as a tighter limit
+ * 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;
- if (dstLimit <= 0) dstLimit = INT_MAX; /* avoid overflow */
(void) TclGetStringFromObj(objPtr, &numBytes);
- TclAppendUtfToUtf(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;
}
/*
- * This routine is burdened with satisfying several constraints. It cannot
- * append more than 'charsToRead` chars onto objPtr. This is measured
- * after encoding and translation transformations are completed. There is
- * no precise number of src bytes that can be associated with the limit.
- * Yet, when we are done, we must know precisely the number of src bytes
- * that were consumed to produce the appended chars, so that all
- * subsequent bytes are left in the buffers for future read operations.
+ * This routine is burdened with satisfying several constraints.
+ * It cannot append more than 'charsToRead` chars onto objPtr.
+ * This is measured after encoding and translation transformations
+ * are completed. There is no precise number of src bytes that can
+ * be associated with the limit. Yet, when we are done, we must know
+ * precisely the number of src bytes that were consumed to produce
+ * the appended chars, so that all subsequent bytes are left in
+ * the buffers for future read operations.
*
- * The consequence is that we have no choice but to implement a "trial and
- * error" approach, where in general we may need to perform
- * transformations and copies multiple times to achieve a consistent set
- * of results. This takes the shape of a loop.
+ * The consequence is that we have no choice but to implement a
+ * "trial and error" approach, where in general we may need to
+ * perform transformations and copies multiple times to achieve
+ * 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 srcLen
- * bytes, write no more than dstLimit bytes.
+ * Perform the encoding transformation. Read no more than
+ * srcLen bytes, write no more than dstLimit bytes.
*
- * Some trickiness with encoding flags here. We do not want the end
- * of a buffer to be treated as the end of all input when the presence
- * of bytes in a next buffer are already known to exist. This is
- * checked with an assert() because so far no test case causing the
- * assertion to be false has been created. The normal operations of
- * channel reading appear to cause EOF and TCL_ENCODING_END setting to
- * appear only in situations where there are no further bytes in any
- * buffers.
+ * Some trickiness with encoding flags here. We do not want
+ * the end of a buffer to be treated as the end of all input
+ * when the presence of bytes in a next buffer are already
+ * known to exist. This is checked with an assert() because
+ * so far no test case causing the assertion to be false has
+ * been created. The normal operations of channel reading
+ * appear to cause EOF and TCL_ENCODING_END setting to appear
+ * only in situations where there are no further bytes in
+ * any buffers.
*/
assert(bufPtr->nextPtr == NULL || BytesLeft(bufPtr->nextPtr) == 0
|| (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);
- if (code == TCL_CONVERT_UNKNOWN || code == TCL_CONVERT_SYNTAX
- || (
- code == TCL_CONVERT_MULTIBYTE
- && GotFlag(statePtr, CHANNEL_EOF
- ))
- ) {
- SetFlag(statePtr, CHANNEL_ENCODING_ERROR);
- code = TCL_OK;
- }
-
/*
- * Perform the translation transformation in place. Read no more than
- * the dstDecoded bytes the encoding transformation actually produced.
- * Capture the number of bytes written in dstWrote. Capture the number
- * of bytes actually consumed in dstRead.
+ * Perform the translation transformation in place. Read no more
+ * than the dstDecoded bytes the encoding transformation actually
+ * produced. Capture the number of bytes written in dstWrote.
+ * Capture the number of bytes actually consumed in dstRead.
*/
dstWrote = dstLimit;
@@ -6401,9 +5625,11 @@ ReadChars(
TranslateInputEOL(statePtr, dst, dst, &dstWrote, &dstRead);
if (dstRead < dstDecoded) {
+
/*
- * The encoding transformation produced bytes that the translation
- * transformation did not consume. Why did this happen?
+ * The encoding transformation produced bytes that the
+ * translation transformation did not consume. Why did
+ * this happen?
*/
if (statePtr->inEofChar && dst[dstRead] == statePtr->inEofChar) {
@@ -6412,41 +5638,43 @@ ReadChars(
* we saw it and stopped translating at that point.
*
* NOTE the bizarre spec of TranslateInputEOL in this case.
- * Clearly the eof char had to be read in order to account for
- * the stopping, but the value of dstRead does not include it.
+ * Clearly the eof char had to be read in order to account
+ * for the stopping, but the value of dstRead does not
+ * include it.
*
- * Also rather bizarre, our caller can only notice an EOF
- * condition if we return the value TCL_INDEX_NONE as the number of chars
- * read. This forces us to perform a 2-call dance where the
- * first call can read all the chars up to the eof char, and
- * the second call is solely for consuming the encoded eof
- * char then pointed at by src so that we can return that
- * magic TCL_INDEX_NONE value. This seems really wasteful, especially
- * since the first decoding pass of each call is likely to
- * decode many bytes beyond that eof char that's all we care
- * about.
+ * Also rather bizarre, our caller can only notice an
+ * EOF condition if we return the value -1 as the number
+ * of chars read. This forces us to perform a 2-call
+ * dance where the first call can read all the chars
+ * up to the eof char, and the second call is solely
+ * for consuming the encoded eof char then pointed at
+ * by src so that we can return that magic -1 value.
+ * This seems really wasteful, especially since
+ * the first decoding pass of each call is likely to
+ * decode many bytes beyond that eof char that's all we
+ * care about.
*/
if (dstRead == 0) {
/*
- * Curious choice in the eof char handling. We leave the
- * eof char in the buffer. So, no need to compute a proper
- * srcRead value. At this point, there are no chars before
- * the eof char in the buffer.
+ * Curious choice in the eof char handling. We leave
+ * the eof char in the buffer. So, no need to compute
+ * a proper srcRead value. At this point, there
+ * are no chars before the eof char in the buffer.
*/
-
Tcl_SetObjLength(objPtr, numBytes);
return -1;
}
{
/*
- * There are chars leading the buffer before the eof char.
- * Adjust the dstLimit so we go back and read only those
- * and do not encounter the eof char this time.
+ * There are chars leading the buffer before the eof
+ * char. Adjust the dstLimit so we go back and read
+ * only those and do not encounter the eof char this
+ * time.
*/
- dstLimit = dstRead + (TCL_UTF_MAX - 1);
+ dstLimit = dstRead + TCL_UTF_MAX;
statePtr->flags = savedFlags;
statePtr->inputEncodingFlags = savedIEFlags;
statePtr->inputEncodingState = savedState;
@@ -6455,9 +5683,10 @@ ReadChars(
}
/*
- * 2) The other way to read fewer bytes than are decoded is when
- * the final byte is \r and we're in a CRLF translation mode so
- * we cannot decide whether to record \r or \n yet.
+ * 2) The other way to read fewer bytes than are decoded
+ * is when the final byte is \r and we're in a CRLF
+ * translation mode so we cannot decide whether to
+ * record \r or \n yet.
*/
assert(dst[dstRead] == '\r');
@@ -6465,13 +5694,13 @@ ReadChars(
if (dstWrote > 0) {
/*
- * There are chars we can read before we hit the bare CR. Go
- * back with a smaller dstLimit so we get them in the next
- * pass, compute a matching srcRead, and don't end up back
- * here in this call.
+ * There are chars we can read before we hit the bare cr.
+ * Go back with a smaller dstLimit so we get them in the
+ * next pass, compute a matching srcRead, and don't end
+ * up back here in this call.
*/
- dstLimit = dstRead + (TCL_UTF_MAX - 1);
+ dstLimit = dstRead + TCL_UTF_MAX;
statePtr->flags = savedFlags;
statePtr->inputEncodingFlags = savedIEFlags;
statePtr->inputEncodingState = savedState;
@@ -6482,16 +5711,16 @@ ReadChars(
assert(dstRead == 0);
/*
- * We decoded only the bare CR, and we cannot read a translated
- * char from that alone. We have to know what's next. So why do
- * we only have the one decoded char?
+ * We decoded only the bare cr, and we cannot read a
+ * translated char from that alone. We have to know what's
+ * next. So why do we only have the one decoded char?
*/
if (code != TCL_OK) {
+ char buffer[TCL_UTF_MAX + 2];
int read, decoded, count;
- char buffer[TCL_UTF_MAX + 1];
- /*
+ /*
* Didn't get everything the buffer could offer
*/
@@ -6504,9 +5733,8 @@ ReadChars(
(statePtr->inputEncodingFlags & TCL_ENCODING_END));
Tcl_ExternalToUtf(NULL, encoding, src, srcLen,
- (statePtr->inputEncodingFlags | TCL_ENCODING_NO_TERMINATE),
- &statePtr->inputEncodingState, buffer, sizeof(buffer),
- &read, &decoded, &count);
+ statePtr->inputEncodingFlags, &statePtr->inputEncodingState,
+ buffer, TCL_UTF_MAX + 2, &read, &decoded, &count);
if (count == 2) {
if (buffer[1] == '\n') {
@@ -6518,6 +5746,7 @@ ReadChars(
bufPtr->nextRemoved += srcRead;
}
+ dst[1] = '\0';
statePtr->inputEncodingFlags &= ~TCL_ENCODING_START;
Tcl_SetObjLength(objPtr, numBytes + 1);
@@ -6525,9 +5754,10 @@ ReadChars(
}
} else if (GotFlag(statePtr, CHANNEL_EOF)) {
+
/*
- * The bare \r is the only char and we will never read a
- * subsequent char to make the determination.
+ * The bare \r is the only char and we will never read
+ * a subsequent char to make the determination.
*/
dst[0] = '\r';
@@ -6537,8 +5767,8 @@ ReadChars(
}
/*
- * Revise the dstRead value so that the numChars calc below
- * correctly computes zero characters read.
+ * Revise the dstRead value so that the numChars calc
+ * below correctly computes zero characters read.
*/
dstRead = numChars;
@@ -6546,25 +5776,24 @@ 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.
+ /*
+ * 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.
*/
numChars -= (dstRead - dstWrote);
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!
+ /*
+ * 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 = TclUtfAtIndex(dst, charsToRead) - dst + (TCL_UTF_MAX - 1);
+ dstLimit = Tcl_UtfAtIndex(dst, charsToRead) + TCL_UTF_MAX - dst;
statePtr->flags = savedFlags;
statePtr->inputEncodingFlags = savedIEFlags;
statePtr->inputEncodingState = savedState;
@@ -6574,34 +5803,33 @@ ReadChars(
if (dstWrote == 0) {
ChannelBuffer *nextPtr;
- /*
- * We were not able to read any chars.
- */
+ /* We were not able to read any chars. */
- assert(numChars == 0);
+ 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 when the translation pass was made
- * the INPUT_SAW_CR flag was set on the channel. In that case, the
- * correct behavior is to consume that \n and produce the empty
- * string.
+ /*
+ * 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
+ * when the translation pass was made the INPUT_SAW_CR
+ * flag was set on the channel. In that case, the
+ * correct behavior is to consume that \n and produce the
+ * empty string.
*/
- if (dstRead == 1 && dst[0] == '\n') {
+ if (dst[0] == '\n') {
assert(statePtr->inputTranslation == TCL_TRANSLATE_AUTO);
+ assert(dstRead == 1);
goto consume;
}
- /*
- * Otherwise, reading zero characters indicates there's something
- * incomplete at the end of the src buffer. Maybe there were not
- * enough src bytes to decode into a char. Maybe a lone \r could
- * not be translated (crlf mode). Need to combine any unused src
- * bytes we have in the first buffer with subsequent bytes to try
- * again.
+ /* Otherwise, reading zero characters indicates there's
+ * something incomplete at the end of the src buffer.
+ * Maybe there were not enough src bytes to decode into
+ * a char. Maybe a lone \r could not be translated (crlf
+ * mode). Need to combine any unused src bytes we have
+ * in the first buffer with subsequent bytes to try again.
*/
nextPtr = bufPtr->nextPtr;
@@ -6616,23 +5844,23 @@ ReadChars(
/*
* Space is made at the beginning of the buffer to copy the
- * previous unused bytes there. Check first if the buffer we are
- * using actually has enough space at its beginning for the data
- * we are copying. Because if not we will write over the buffer
- * management information, especially the 'nextPtr'.
+ * previous unused bytes there. Check first if the buffer we
+ * are using actually has enough space at its beginning for
+ * the data we are copying. Because if not we will write over
+ * the buffer management information, especially the 'nextPtr'.
*
- * Note that the BUFFER_PADDING (See AllocChannelBuffer) is used
- * to prevent exactly this situation. I.e. it should never happen.
- * Therefore it is ok to panic should it happen despite the
- * precautions.
+ * Note that the BUFFER_PADDING (See AllocChannelBuffer) is
+ * used to prevent exactly this situation. I.e. it should never
+ * happen. Therefore it is ok to panic should it happen despite
+ * the precautions.
*/
- if (nextPtr->nextRemoved < srcLen) {
+ if (nextPtr->nextRemoved - srcLen < 0) {
Tcl_Panic("Buffer Underflow, BUFFER_PADDING not enough");
}
nextPtr->nextRemoved -= srcLen;
- memcpy(RemovePoint(nextPtr), src, srcLen);
+ memcpy(RemovePoint(nextPtr), src, (size_t) srcLen);
RecycleBuffer(statePtr, bufPtr, 0);
statePtr->inQueueHead = nextPtr;
Tcl_SetObjLength(objPtr, numBytes);
@@ -6643,12 +5871,10 @@ ReadChars(
consume:
bufPtr->nextRemoved += srcRead;
-
/*
- * If this read contained multibyte characters, revise factorPtr so
- * the next read will allocate bigger buffers.
+ * If this read contained multibyte characters, revise factorPtr
+ * so the next read will allocate bigger buffers.
*/
-
if (numChars && numChars < srcRead) {
*factorPtr = srcRead * UTF_EXPANSION_FACTOR / numChars;
}
@@ -6675,7 +5901,7 @@ ReadChars(
*---------------------------------------------------------------------------
*/
-static void
+static void
TranslateInputEOL(
ChannelState *statePtr, /* Channel being read, for EOL translation and
* EOF character. */
@@ -6696,27 +5922,22 @@ TranslateInputEOL(
int inEofChar = statePtr->inEofChar;
/*
- * Depending on the translation mode in use, there's no need to scan more
- * srcLen bytes at srcStart than can possibly transform to dstLen bytes.
- * This keeps the scan for eof char below from being pointlessly long.
+ * Depending on the translation mode in use, there's no need
+ * to scan more srcLen bytes at srcStart than can possibly transform
+ * to dstLen bytes. This keeps the scan for eof char below from
+ * being pointlessly long.
*/
switch (statePtr->inputTranslation) {
case TCL_TRANSLATE_LF:
case TCL_TRANSLATE_CR:
if (srcLen > dstLen) {
- /*
- * In these modes, each src byte become a dst byte.
- */
-
+ /* In these modes, each src byte become a dst byte. */
srcLen = dstLen;
}
break;
default:
- /*
- * In other modes, at most 2 src bytes become a dst byte.
- */
-
+ /* In other modes, at most 2 src bytes become a dst byte. */
if (srcLen/2 > dstLen) {
srcLen = 2 * dstLen;
}
@@ -6729,7 +5950,7 @@ TranslateInputEOL(
* created by the presence of the input eof char.
*/
- if ((eof = (const char *)memchr(srcStart, inEofChar, srcLen))) {
+ if ((eof = memchr(srcStart, inEofChar, srcLen))) {
srcLen = eof - srcStart;
}
}
@@ -6738,13 +5959,13 @@ TranslateInputEOL(
case TCL_TRANSLATE_LF:
case TCL_TRANSLATE_CR:
if (dstStart != srcStart) {
- memcpy(dstStart, srcStart, srcLen);
+ memcpy(dstStart, srcStart, (size_t) srcLen);
}
if (statePtr->inputTranslation == TCL_TRANSLATE_CR) {
char *dst = dstStart;
char *dstEnd = dstStart + srcLen;
- while ((dst = (char *)memchr(dst, '\r', dstEnd - dst))) {
+ while ((dst = memchr(dst, '\r', dstEnd - dst))) {
*dst++ = '\n';
}
}
@@ -6755,7 +5976,7 @@ TranslateInputEOL(
char *dst = dstStart;
int lesser = (dstLen < srcLen) ? dstLen : srcLen;
- while ((crFound = (const char *)memchr(src, '\r', lesser))) {
+ while ((crFound = memchr(src, '\r', lesser))) {
int numBytes = crFound - src;
memmove(dst, src, numBytes);
@@ -6795,7 +6016,7 @@ TranslateInputEOL(
ResetFlag(statePtr, INPUT_SAW_CR);
}
lesser = (dstLen < srcLen) ? dstLen : srcLen;
- while ((crFound = (const char *)memchr(src, '\r', lesser))) {
+ while ((crFound = memchr(src, '\r', lesser))) {
int numBytes = crFound - src;
memmove(dst, src, numBytes);
@@ -6825,14 +6046,11 @@ TranslateInputEOL(
* EOF character was seen in EOL translated range. Leave current file
* position pointing at the EOF character, but don't store the EOF
* character in the output string.
- *
- * If CHANNEL_ENCODING_ERROR is set, it can only be because of data
- * encountered after the EOF character, so it is nonsense. Unset it.
*/
SetFlag(statePtr, CHANNEL_EOF | CHANNEL_STICKY_EOF);
statePtr->inputEncodingFlags |= TCL_ENCODING_END;
- ResetFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR|CHANNEL_ENCODING_ERROR);
+ ResetFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR);
}
}
@@ -6845,7 +6063,7 @@ TranslateInputEOL(
* channel, at either the head or tail of the queue.
*
* Results:
- * The number of bytes stored in the channel, or TCL_INDEX_NONE on error.
+ * The number of bytes stored in the channel, or -1 on error.
*
* Side effects:
* Adds input to the input queue of a channel.
@@ -6853,11 +6071,11 @@ TranslateInputEOL(
*----------------------------------------------------------------------
*/
-Tcl_Size
+int
Tcl_Ungets(
Tcl_Channel chan, /* The channel for which to add the input. */
const char *str, /* The input itself. */
- Tcl_Size len, /* The length of the input. */
+ int len, /* The length of the input. */
int atEnd) /* If non-zero, add at end of queue; otherwise
* add at head of queue. */
{
@@ -6881,7 +6099,7 @@ Tcl_Ungets(
flags = statePtr->flags;
if (CheckChannelErrors(statePtr, TCL_READABLE) != 0) {
- len = TCL_INDEX_NONE;
+ len = -1;
goto done;
}
statePtr->flags = flags;
@@ -6889,7 +6107,7 @@ Tcl_Ungets(
/*
* Clear the EOF flags, and clear the BLOCKED bit.
*/
-
+
if (GotFlag(statePtr, CHANNEL_EOF)) {
statePtr->inputEncodingFlags |= TCL_ENCODING_START;
}
@@ -6898,7 +6116,7 @@ Tcl_Ungets(
statePtr->inputEncodingFlags &= ~TCL_ENCODING_END;
bufPtr = AllocChannelBuffer(len);
- memcpy(InsertPoint(bufPtr), str, len);
+ memcpy(InsertPoint(bufPtr), str, (size_t) len);
bufPtr->nextAdded += len;
if (statePtr->inQueueHead == NULL) {
@@ -6957,7 +6175,7 @@ Tcl_Flush(
chanPtr = statePtr->topChanPtr;
if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) {
- return TCL_ERROR;
+ return -1;
}
result = FlushChannel(NULL, chanPtr, 0);
@@ -7046,13 +6264,13 @@ 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.
*/
- assert(!GotFlag(statePtr, CHANNEL_STICKY_EOF));
+ assert( !GotFlag(statePtr, CHANNEL_STICKY_EOF) );
/*
* Prevent reading from a dead channel -- a channel that has been closed
@@ -7066,21 +6284,24 @@ GetInput(
}
/*
- * WARNING: There was once a comment here claiming that it was a bad idea
- * to make another call to the inputproc of a channel driver when EOF has
- * already been detected on the channel. Through much of Tcl's history,
- * this warning was then completely negated by having all (most?) read
- * paths clear the EOF setting before reaching here. So we had a guard
- * that was never triggered.
- *
- * Don't be tempted to restore the guard. Even if EOF is set on the
- * channel, continue through and call the inputproc again. This is the
- * way to enable the ability to [read] again beyond the EOF, which seems a
- * strange thing to do, but for which use cases exist [Tcl Bug 5adc350683]
- * and which may even be essential for channels representing things like
- * ttys or other devices where the stream might take the logical form of a
- * series of 'files' separated by an EOF condition.
+ * WARNING: There was once a comment here claiming that it was
+ * a bad idea to make another call to the inputproc of a channel
+ * driver when EOF has already been detected on the channel. Through
+ * much of Tcl's history, this warning was then completely negated
+ * by having all (most?) read paths clear the EOF setting before
+ * reaching here. So we had a guard that was never triggered.
*
+ * Don't be tempted to restore the guard. Even if EOF is set on
+ * the channel, continue through and call the inputproc again. This
+ * is the way to enable the ability to [read] again beyond the EOF,
+ * which seems a strange thing to do, but for which use cases exist
+ * [Tcl Bug 5adc350683] and which may even be essential for channels
+ * representing things like ttys or other devices where the stream
+ * might take the logical form of a series of 'files' separated by
+ * an EOF condition.
+ */
+
+ /*
* First check for more buffers in the pushback area of the topmost
* channel in the stack and use them. They can be the result of a
* transformation which went away without reading all the information
@@ -7088,6 +6309,7 @@ GetInput(
*/
if (chanPtr->inQueueHead != NULL) {
+
/* TODO: Tests to cover this. */
assert(statePtr->inQueueHead == NULL);
@@ -7117,14 +6339,13 @@ GetInput(
/*
* Check the actual buffersize against the requested buffersize.
- * Saved buffers of the wrong size are squashed. This is done to honor
- * dynamic changes of the buffersize made by the user.
- *
+ * Saved buffers of the wrong size are squashed. This is done
+ * to honor dynamic changes of the buffersize made by the user.
* TODO: Tests to cover this.
*/
if ((bufPtr != NULL)
- && (bufPtr->bufLength != statePtr->bufSize + BUFFER_PADDING)) {
+ && (bufPtr->bufLength - BUFFER_PADDING != statePtr->bufSize)) {
ReleaseChannelBuffer(bufPtr);
bufPtr = NULL;
}
@@ -7149,17 +6370,15 @@ GetInput(
PreserveChannelBuffer(bufPtr);
nread = ChanRead(chanPtr, InsertPoint(bufPtr), toRead);
- ReleaseChannelBuffer(bufPtr);
if (nread < 0) {
result = Tcl_GetErrno();
} else {
result = 0;
- if (statePtr->inQueueTail != NULL) {
- statePtr->inQueueTail->nextAdded += nread;
- }
+ bufPtr->nextAdded += nread;
}
+ ReleaseChannelBuffer(bufPtr);
return result;
}
@@ -7181,10 +6400,10 @@ GetInput(
*----------------------------------------------------------------------
*/
-long long
+Tcl_WideInt
Tcl_Seek(
Tcl_Channel chan, /* The channel on which to seek. */
- long long offset, /* Offset to seek to. */
+ Tcl_WideInt offset, /* Offset to seek to. */
int mode) /* Relative to which location to seek? */
{
Channel *chanPtr = (Channel *) chan;
@@ -7194,13 +6413,13 @@ Tcl_Seek(
int inputBuffered, outputBuffered;
/* # bytes held in buffers. */
int result; /* Of device driver operations. */
- long long curPos; /* Position on the device. */
+ Tcl_WideInt curPos; /* Position on the device. */
int wasAsync; /* Was the channel nonblocking before the seek
* operation? If so, must restore to
* non-blocking mode after the seek. */
if (CheckChannelErrors(statePtr, TCL_WRITABLE | TCL_READABLE) != 0) {
- return -1;
+ return Tcl_LongAsWide(-1);
}
/*
@@ -7211,7 +6430,7 @@ Tcl_Seek(
*/
if (CheckForDeadChannel(NULL, statePtr)) {
- return -1;
+ return Tcl_LongAsWide(-1);
}
/*
@@ -7225,13 +6444,9 @@ Tcl_Seek(
* defined. This means that the channel does not support seeking.
*/
- if ((Tcl_ChannelWideSeekProc(chanPtr->typePtr) == NULL)
-#ifndef TCL_NO_DEPRECATED
- && (Tcl_ChannelSeekProc(chanPtr->typePtr) == NULL)
-#endif
- ) {
+ if (chanPtr->typePtr->seekProc == NULL) {
Tcl_SetErrno(EINVAL);
- return -1;
+ return Tcl_LongAsWide(-1);
}
/*
@@ -7244,7 +6459,7 @@ Tcl_Seek(
if ((inputBuffered != 0) && (outputBuffered != 0)) {
Tcl_SetErrno(EFAULT);
- return -1;
+ return Tcl_LongAsWide(-1);
}
/*
@@ -7271,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;
/*
@@ -7287,7 +6502,7 @@ Tcl_Seek(
wasAsync = 1;
result = StackSetBlockMode(chanPtr, TCL_MODE_BLOCKING);
if (result != 0) {
- return -1;
+ return Tcl_LongAsWide(-1);
}
ResetFlag(statePtr, CHANNEL_NONBLOCKING);
if (GotFlag(statePtr, BG_FLUSH_SCHEDULED)) {
@@ -7308,11 +6523,24 @@ 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 (curPos == -1) {
+ 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);
}
}
@@ -7328,7 +6556,7 @@ Tcl_Seek(
SetFlag(statePtr, CHANNEL_NONBLOCKING);
result = StackSetBlockMode(chanPtr, TCL_MODE_NONBLOCKING);
if (result != 0) {
- return -1;
+ return Tcl_LongAsWide(-1);
}
}
@@ -7354,7 +6582,7 @@ Tcl_Seek(
*----------------------------------------------------------------------
*/
-long long
+Tcl_WideInt
Tcl_Tell(
Tcl_Channel chan) /* The channel to return pos for. */
{
@@ -7365,10 +6593,10 @@ Tcl_Tell(
int inputBuffered, outputBuffered;
/* # bytes held in buffers. */
int result; /* Of calling device driver. */
- long long curPos; /* Position on device. */
+ Tcl_WideInt curPos; /* Position on device. */
if (CheckChannelErrors(statePtr, TCL_WRITABLE | TCL_READABLE) != 0) {
- return -1;
+ return Tcl_LongAsWide(-1);
}
/*
@@ -7379,7 +6607,7 @@ Tcl_Tell(
*/
if (CheckForDeadChannel(NULL, statePtr)) {
- return -1;
+ return Tcl_LongAsWide(-1);
}
/*
@@ -7393,13 +6621,9 @@ Tcl_Tell(
* defined. This means that the channel does not support seeking.
*/
- if ((Tcl_ChannelWideSeekProc(chanPtr->typePtr) == NULL)
-#ifndef TCL_NO_DEPRECATED
- && (Tcl_ChannelSeekProc(chanPtr->typePtr) == NULL)
-#endif
- ) {
+ if (chanPtr->typePtr->seekProc == NULL) {
Tcl_SetErrno(EINVAL);
- return -1;
+ return Tcl_LongAsWide(-1);
}
/*
@@ -7410,16 +6634,28 @@ 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, 0, SEEK_CUR, &result);
- if (curPos == -1) {
+ 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 -1;
+ return Tcl_LongAsWide(-1);
}
if (inputBuffered != 0) {
@@ -7431,12 +6667,54 @@ 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.
*
* Results:
- * TCL_OK on success, TCL_ERROR if the operation failed (e.g., is not
+ * TCL_OK on success, TCL_ERROR if the operation failed (e.g. is not
* supported by the type of channel, or the underlying OS operation
* failed in some way).
*
@@ -7449,7 +6727,7 @@ Tcl_Tell(
int
Tcl_TruncateChannel(
Tcl_Channel chan, /* Channel to truncate. */
- long long length) /* Length to truncate it to. */
+ Tcl_WideInt length) /* Length to truncate it to. */
{
Channel *chanPtr = (Channel *) chan;
Tcl_DriverTruncateProc *truncateProc =
@@ -7466,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.
@@ -7478,7 +6756,7 @@ Tcl_TruncateChannel(
/*
* Seek first to force a total flush of all pending buffers and ditch any
- * preread input data.
+ * pre-read input data.
*/
WillWrite(chanPtr);
@@ -7538,7 +6816,7 @@ CheckChannelErrors(
/*
* TIP #219, Tcl Channel Reflection API.
- * Move a deferred error message back into the channel bypass.
+ * Move a defered error message back into the channel bypass.
*/
if (statePtr->chanMsg != NULL) {
@@ -7611,39 +6889,9 @@ Tcl_Eof(
ChannelState *statePtr = ((Channel *) chan)->state;
/* State of real channel structure. */
- if (GotFlag(statePtr, CHANNEL_ENCODING_ERROR)) {
- return 0;
- }
return GotFlag(statePtr, CHANNEL_EOF) ? 1 : 0;
}
-
-/*
- *----------------------------------------------------------------------
- *
- * TclChannelGetBlockingMode --
- *
- * Returns 1 if the channel is in blocking mode (default), 0 otherwise.
- *
- * Results:
- * 1 or 0, always.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TclChannelGetBlockingMode(
- Tcl_Channel chan)
-{
- ChannelState *statePtr = ((Channel *) chan)->state;
- /* State of real channel structure. */
-
- return GotFlag(statePtr, CHANNEL_NONBLOCKING) ? 0 : 1;
-}
-
/*
*----------------------------------------------------------------------
*
@@ -7703,7 +6951,7 @@ Tcl_InputBuffered(
}
/*
- * Remember the bytes in the topmost pushback area.
+ * Don't forget the bytes in the topmost pushback area.
*/
for (bufPtr = statePtr->topChanPtr->inQueueHead; bufPtr != NULL;
@@ -7746,7 +6994,7 @@ Tcl_OutputBuffered(
bytesBuffered += BytesLeft(bufPtr);
}
if (statePtr->curOutPtr != NULL) {
- ChannelBuffer *curOutPtr = statePtr->curOutPtr;
+ register ChannelBuffer *curOutPtr = statePtr->curOutPtr;
if (IsBufferReady(curOutPtr)) {
bytesBuffered += BytesLeft(curOutPtr);
@@ -7811,7 +7059,7 @@ Tcl_ChannelBuffered(
void
Tcl_SetChannelBufferSize(
Tcl_Channel chan, /* The channel whose buffer size to set. */
- Tcl_Size sz) /* The size to set. */
+ int sz) /* The size to set. */
{
ChannelState *statePtr; /* State of real channel structure. */
@@ -7820,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;
@@ -7865,7 +7113,7 @@ Tcl_SetChannelBufferSize(
*----------------------------------------------------------------------
*/
-Tcl_Size
+int
Tcl_GetChannelBufferSize(
Tcl_Channel chan) /* The channel for which to find the buffer
* size. */
@@ -7893,7 +7141,7 @@ Tcl_GetChannelBufferSize(
* Side effects:
* An error message is generated in interp's result object to indicate
- * that a command was invoked with a bad option. The message has the
+ * that a command was invoked with the a bad option. The message has the
* form:
* bad option "blah": should be one of
* <...generic options...>+<...specific options...>
@@ -7915,16 +7163,15 @@ Tcl_BadChannelOption(
{
if (interp != NULL) {
const char *genericopt =
- "blocking buffering buffersize encoding eofchar profile translation";
+ "blocking buffering buffersize encoding eofchar translation";
const char **argv;
- Tcl_Size argc, i;
+ 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),
@@ -7932,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 ? 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;
@@ -7975,7 +7221,7 @@ Tcl_GetChannelOption(
Tcl_DString *dsPtr) /* Where to store value(s). */
{
size_t len; /* Length of optionName string. */
- char optionVal[128]; /* Buffer for snprintf. */
+ char optionVal[128]; /* Buffer for sprintf. */
Channel *chanPtr = (Channel *) chan;
ChannelState *statePtr = chanPtr->state;
/* State info for channel */
@@ -8003,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;
}
@@ -8082,10 +7328,9 @@ Tcl_GetChannelOption(
if (statePtr->inEofChar == 0) {
Tcl_DStringAppendElement(dsPtr, "");
} else {
- char buf[2];
+ char buf[4];
- buf[1] = '\0';
- buf[0] = statePtr->inEofChar;
+ sprintf(buf, "%c", statePtr->inEofChar);
Tcl_DStringAppendElement(dsPtr, buf);
}
}
@@ -8093,10 +7338,9 @@ Tcl_GetChannelOption(
if (statePtr->outEofChar == 0) {
Tcl_DStringAppendElement(dsPtr, "");
} else {
- char buf[2];
+ char buf[4];
- buf[1] = '\0';
- buf[0] = statePtr->outEofChar;
+ sprintf(buf, "%c", statePtr->outEofChar);
Tcl_DStringAppendElement(dsPtr, buf);
}
}
@@ -8115,23 +7359,6 @@ Tcl_GetChannelOption(
return TCL_OK;
}
}
- if (len == 0 || HaveOpt(1, "-profile")) {
- int profile;
- const char *profileName;
- if (len == 0) {
- Tcl_DStringAppendElement(dsPtr, "-profile");
- }
- /* Note currently input and output profiles are same */
- profile = ENCODING_PROFILE_GET(statePtr->inputEncodingFlags);
- profileName = TclEncodingProfileIdToName(interp, profile);
- if (profileName == NULL) {
- return TCL_ERROR;
- }
- Tcl_DStringAppendElement(dsPtr, profileName);
- if (len > 0) {
- return TCL_OK;
- }
- }
if (len == 0 || HaveOpt(1, "-translation")) {
if (len == 0) {
Tcl_DStringAppendElement(dsPtr, "-translation");
@@ -8184,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.
@@ -8227,8 +7454,8 @@ Tcl_SetChannelOption(
ChannelState *statePtr = chanPtr->state;
/* State info for channel */
size_t len; /* Length of optionName string. */
- Tcl_Size argc;
- const char **argv = NULL;
+ int argc;
+ const char **argv;
/*
* If the channel is in the middle of a background copy, fail.
@@ -8236,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;
}
@@ -8277,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);
@@ -8286,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")) {
@@ -8303,7 +7531,6 @@ Tcl_SetChannelOption(
return TCL_OK;
} else if (HaveOpt(2, "-encoding")) {
Tcl_Encoding encoding;
- int profile;
if ((newValue[0] == '\0') || (strcmp(newValue, "binary") == 0)) {
encoding = NULL;
@@ -8328,37 +7555,29 @@ Tcl_SetChannelOption(
Tcl_FreeEncoding(statePtr->encoding);
statePtr->encoding = encoding;
statePtr->inputEncodingState = NULL;
- profile = ENCODING_PROFILE_GET(statePtr->inputEncodingFlags);
statePtr->inputEncodingFlags = TCL_ENCODING_START;
- ENCODING_PROFILE_SET(statePtr->inputEncodingFlags, profile);
statePtr->outputEncodingState = NULL;
statePtr->outputEncodingFlags = TCL_ENCODING_START;
- ENCODING_PROFILE_SET(statePtr->outputEncodingFlags, profile); /* Same as input */
- ResetFlag(statePtr, CHANNEL_NEED_MORE_DATA|CHANNEL_ENCODING_ERROR);
+ ResetFlag(statePtr, CHANNEL_NEED_MORE_DATA);
UpdateInterest(chanPtr);
return TCL_OK;
} else if (HaveOpt(2, "-eofchar")) {
- if (!newValue[0] || (!(newValue[0] & 0x80) && !newValue[1])) {
- if (GotFlag(statePtr, TCL_READABLE)) {
- statePtr->inEofChar = newValue[0];
- }
- statePtr->outEofChar = 0;
- } else if (Tcl_SplitList(interp, newValue, &argc, &argv) == TCL_ERROR) {
+ if (Tcl_SplitList(interp, newValue, &argc, &argv) == TCL_ERROR) {
return TCL_ERROR;
- } else if (argc == 0) {
+ }
+ if (argc == 0) {
statePtr->inEofChar = 0;
statePtr->outEofChar = 0;
} else if (argc == 1 || argc == 2) {
+ int outIndex = (argc - 1);
int inValue = (int) argv[0][0];
- int outValue = (argc == 2) ? (int) argv[1][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", TCL_INDEX_NONE));
+ 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)) {
@@ -8369,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", TCL_INDEX_NONE));
+ " one, or two elements", NULL);
}
- ckfree(argv);
+ ckfree((char *) argv);
return TCL_ERROR;
}
if (argv != NULL) {
- ckfree(argv);
+ ckfree((char *) argv);
}
/*
@@ -8389,17 +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, "-profile")) {
- int profile;
- if (TclEncodingProfileNameToId(interp, newValue, &profile) != TCL_OK) {
- return TCL_ERROR;
- }
- ENCODING_PROFILE_SET(statePtr->inputEncodingFlags, profile);
- ENCODING_PROFILE_SET(statePtr->outputEncodingFlags, profile);
- ResetFlag(statePtr, CHANNEL_NEED_MORE_DATA|CHANNEL_ENCODING_ERROR);
+
return TCL_OK;
} else if (HaveOpt(1, "-translation")) {
const char *readMode, *writeMode;
@@ -8416,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) {
@@ -8446,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;
}
@@ -8496,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);
}
@@ -8563,7 +7776,7 @@ CleanupChannelHandlers(
TclChannelEventScriptInvoker, sPtr);
TclDecrRefCount(sPtr->scriptPtr);
- ckfree(sPtr);
+ ckfree((char *) sPtr);
} else {
prevPtr = sPtr;
}
@@ -8616,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);
}
/*
@@ -8657,13 +7870,6 @@ Tcl_NotifyChannel(
Tcl_Preserve(statePtr);
/*
- * Avoid processing if the channel owner has been changed.
- */
- if (statePtr->managingThread != Tcl_GetCurrentThread()) {
- goto done;
- }
-
- /*
* If we are flushing in the background, be sure to call FlushChannel for
* writable events. Note that we have to discard the writable event so we
* don't call any write handlers before the flush is complete.
@@ -8677,7 +7883,7 @@ Tcl_NotifyChannel(
/*
* Add this invocation to the list of recursive invocations of
- * Tcl_NotifyChannel.
+ * ChannelHandlerEventProc.
*/
nh.nextHandlerPtr = NULL;
@@ -8692,18 +7898,11 @@ 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;
}
-
- /*
- * Stop if the channel owner has been changed in-between.
- */
- if (chanPtr->state->managingThread != Tcl_GetCurrentThread()) {
- goto done;
- }
}
/*
@@ -8721,7 +7920,6 @@ Tcl_NotifyChannel(
UpdateInterest(chanPtr);
}
-done:
Tcl_Release(statePtr);
TclChannelRelease(channel);
@@ -8798,9 +7996,9 @@ UpdateInterest(
*
* - Tcl drops READABLE here, because it has data in its own
* buffers waiting to be read by the extension.
- * - A READABLE event is synthesized via timer.
+ * - A READABLE event is syntesized via timer.
* - The OS still reports the EXCEPTION condition on the file.
- * - And the extension gets the EXCEPTION event first, and handles
+ * - And the extension gets the EXCPTION event first, and handles
* this as EOF.
*
* End result ==> Premature end of reading from a file.
@@ -8821,26 +8019,12 @@ UpdateInterest(
mask &= ~TCL_EXCEPTION;
if (!statePtr->timer) {
- TclChannelPreserve((Tcl_Channel)chanPtr);
- statePtr->timerChanPtr = chanPtr;
- statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
- ChannelTimerProc, chanPtr);
+ statePtr->timer = Tcl_CreateTimerHandler(0, ChannelTimerProc,
+ chanPtr);
}
}
}
-
- if (!statePtr->timer
- && mask & TCL_WRITABLE
- && GotFlag(statePtr, CHANNEL_NONBLOCKING)) {
-
- TclChannelPreserve((Tcl_Channel)chanPtr);
- statePtr->timerChanPtr = chanPtr;
- statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
- ChannelTimerProc,chanPtr);
- }
-
-
- ChanWatch(chanPtr, mask);
+ (chanPtr->typePtr->watchProc)(chanPtr->instanceData, mask);
}
/*
@@ -8862,80 +8046,31 @@ UpdateInterest(
static void
ChannelTimerProc(
- void *clientData)
+ ClientData clientData)
{
- Channel *chanPtr = (Channel *)clientData;
- /* State info for channel */
+ Channel *chanPtr = clientData;
ChannelState *statePtr = chanPtr->state;
+ /* State info for channel */
- /* TclChannelPreserve() must be called before the current function was
- * scheduled, is already in effect. In this function it guards against
- * deallocation in Tcl_NotifyChannel and also keps the channel preserved
- * until ChannelTimerProc is later called again.
- */
+ if (!GotFlag(statePtr, CHANNEL_NEED_MORE_DATA)
+ && (statePtr->interestMask & TCL_READABLE)
+ && (statePtr->inQueueHead != NULL)
+ && IsBufferReady(statePtr->inQueueHead)) {
+ /*
+ * Restart the timer in case a channel handler reenters the event loop
+ * before UpdateInterest gets called by Tcl_NotifyChannel.
+ */
- if (chanPtr->typePtr == NULL) {
- CleanupTimerHandler(statePtr);
- } else {
+ statePtr->timer = Tcl_CreateTimerHandler(0, ChannelTimerProc,chanPtr);
Tcl_Preserve(statePtr);
- statePtr->timer = NULL;
- if (statePtr->interestMask & TCL_WRITABLE
- && GotFlag(statePtr, CHANNEL_NONBLOCKING)
- && !GotFlag(statePtr, BG_FLUSH_SCHEDULED)
- ) {
- /*
- * Restart the timer in case a channel handler reenters the event loop
- * before UpdateInterest gets called by Tcl_NotifyChannel.
- */
- statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
- ChannelTimerProc,chanPtr);
- Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_WRITABLE);
- } else {
- /* The channel may have just been closed from within Tcl_NotifyChannel */
- if (!GotFlag(statePtr, CHANNEL_INCLOSE)) {
- if (!GotFlag(statePtr, CHANNEL_NEED_MORE_DATA)
- && (statePtr->interestMask & TCL_READABLE)
- && (statePtr->inQueueHead != NULL)
- && IsBufferReady(statePtr->inQueueHead)) {
- /*
- * Restart the timer in case a channel handler reenters the event loop
- * before UpdateInterest gets called by Tcl_NotifyChannel.
- */
-
- statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
- ChannelTimerProc,chanPtr);
- Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_READABLE);
- } else {
- CleanupTimerHandler(statePtr);
- UpdateInterest(chanPtr);
- }
- } else {
- CleanupTimerHandler(statePtr);
- }
- }
+ Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_READABLE);
Tcl_Release(statePtr);
+ } else {
+ statePtr->timer = NULL;
+ UpdateInterest(chanPtr);
}
}
-static void
-DeleteTimerHandler(
- ChannelState *statePtr
-)
-{
- if (statePtr->timer != NULL) {
- Tcl_DeleteTimerHandler(statePtr->timer);
- CleanupTimerHandler(statePtr);
- }
-}
-static void
-CleanupTimerHandler(
- ChannelState *statePtr
-){
- TclChannelRelease((Tcl_Channel)statePtr->timerChanPtr);
- statePtr->timer = NULL;
- statePtr->timerChanPtr = NULL;
-}
-
/*
*----------------------------------------------------------------------
*
@@ -8967,7 +8102,7 @@ Tcl_CreateChannelHandler(
* handler. */
Tcl_ChannelProc *proc, /* Procedure to call for each selected
* event. */
- void *clientData) /* Arbitrary data to pass to proc. */
+ ClientData clientData) /* Arbitrary data to pass to proc. */
{
ChannelHandler *chPtr;
Channel *chanPtr = (Channel *) chan;
@@ -8987,7 +8122,7 @@ Tcl_CreateChannelHandler(
}
}
if (chPtr == NULL) {
- chPtr = (ChannelHandler *)ckalloc(sizeof(ChannelHandler));
+ chPtr = (ChannelHandler *) ckalloc(sizeof(ChannelHandler));
chPtr->mask = 0;
chPtr->proc = proc;
chPtr->clientData = clientData;
@@ -8998,7 +8133,7 @@ Tcl_CreateChannelHandler(
/*
* The remainder of the initialization below is done regardless of whether
- * this is a new record or a modification of an old one.
+ * or not this is a new record or a modification of an old one.
*/
chPtr->mask = mask;
@@ -9039,7 +8174,7 @@ Tcl_DeleteChannelHandler(
Tcl_Channel chan, /* The channel for which to remove the
* callback. */
Tcl_ChannelProc *proc, /* The procedure in the callback to delete. */
- void *clientData) /* The client data in the callback to
+ ClientData clientData) /* The client data in the callback to
* delete. */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
@@ -9071,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.
*/
@@ -9091,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
@@ -9142,7 +8277,6 @@ DeleteScriptRecord(
if (esPtr == statePtr->scriptRecordPtr) {
statePtr->scriptRecordPtr = esPtr->nextPtr;
} else {
- CLANG_ASSERT(prevEsPtr);
prevEsPtr->nextPtr = esPtr->nextPtr;
}
@@ -9150,7 +8284,7 @@ DeleteScriptRecord(
TclChannelEventScriptInvoker, esPtr);
TclDecrRefCount(esPtr->scriptPtr);
- ckfree(esPtr);
+ ckfree((char *) esPtr);
break;
}
@@ -9199,12 +8333,12 @@ CreateScriptRecord(
makeCH = (esPtr == NULL);
if (makeCH) {
- esPtr = (EventScriptRecord *)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].
@@ -9245,24 +8379,20 @@ CreateScriptRecord(
void
TclChannelEventScriptInvoker(
- void *clientData, /* The script+interp record. */
- TCL_UNUSED(int) /*mask*/)
+ ClientData clientData, /* The script+interp record. */
+ int mask) /* Not used. */
{
- EventScriptRecord *esPtr = (EventScriptRecord *)clientData;
- /* The event script + interpreter to eval it
- * in. */
- Channel *chanPtr = esPtr->chanPtr;
- /* The channel for which this handler is
+ Tcl_Interp *interp; /* Interpreter in which to eval the script. */
+ Channel *chanPtr; /* The channel for which this handler is
* registered. */
- Tcl_Interp *interp = esPtr->interp;
- /* Interpreter in which to eval the script. */
- int mask = esPtr->mask;
+ EventScriptRecord *esPtr; /* The event script + interpreter to eval it
+ * in. */
int result; /* Result of call to eval script. */
- /*
- * Be sure event executed in managed channel (covering bugs similar [f583715154]).
- */
- assert(chanPtr->state->managingThread == Tcl_GetCurrentThread());
+ esPtr = clientData;
+ chanPtr = esPtr->chanPtr;
+ mask = esPtr->mask;
+ interp = esPtr->interp;
/*
* We must preserve the interpreter so we can report errors on it later.
@@ -9286,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);
@@ -9311,9 +8441,10 @@ TclChannelEventScriptInvoker(
*----------------------------------------------------------------------
*/
+ /* ARGSUSED */
int
Tcl_FileEventObjCmd(
- TCL_UNUSED(void *),
+ ClientData clientData, /* Not used. */
Tcl_Interp *interp, /* Interpreter in which the channel for which
* to create the handler is found. */
int objc, /* Number of arguments. */
@@ -9322,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?");
@@ -9346,8 +8477,8 @@ Tcl_FileEventObjCmd(
chanPtr = (Channel *) chan;
statePtr = chanPtr->state;
if (GotFlag(statePtr, mask) == 0) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf("channel is not %s",
- (mask == TCL_READABLE) ? "readable" : "writable"));
+ Tcl_AppendResult(interp, "channel is not ",
+ (mask == TCL_READABLE) ? "readable" : "writable", NULL);
return TCL_ERROR;
}
@@ -9357,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)) {
@@ -9407,12 +8537,12 @@ Tcl_FileEventObjCmd(
static void
ZeroTransferTimerProc(
- void *clientData)
+ ClientData clientData)
{
/* calling CopyData with mask==0 still implies immediate invocation of the
* -command callback, and completion of the fcopy.
*/
- CopyData((CopyState *)clientData, 0);
+ CopyData(clientData, 0);
}
/*
@@ -9436,26 +8566,12 @@ ZeroTransferTimerProc(
*----------------------------------------------------------------------
*/
-#if !defined(TCL_NO_DEPRECATED)
-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);
-}
-#endif
-
int
TclCopyChannel(
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Channel inChan, /* Channel to read from. */
Tcl_Channel outChan, /* Channel to write to. */
- long long 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;
@@ -9464,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;
}
@@ -9512,21 +8627,8 @@ TclCopyChannel(
* Make sure the output side is unbuffered.
*/
- ResetFlag(outStatePtr, CHANNEL_LINEBUFFERED);
- SetFlag(outStatePtr, 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
- && ENCODING_PROFILE_GET(inStatePtr->inputEncodingFlags) == TCL_ENCODING_PROFILE_TCL8
- && ENCODING_PROFILE_GET(outStatePtr->outputEncodingFlags) == TCL_ENCODING_PROFILE_TCL8;
+ outStatePtr->flags = (outStatePtr->flags & ~(CHANNEL_LINEBUFFERED))
+ | CHANNEL_UNBUFFERED;
/*
* Allocate a new CopyState to maintain info about the current copy in
@@ -9534,14 +8636,14 @@ TclCopyChannel(
* completed.
*/
- csPtr = (CopyState *)ckalloc(offsetof(CopyState, buffer) + 1U + !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);
@@ -9551,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.
@@ -9589,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(
- void *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 long long 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. */
@@ -9828,12 +8696,9 @@ CopyData(
Tcl_Obj *cmdPtr, *errObj = NULL, *bufObj = NULL, *msg = NULL;
Tcl_Channel inChan, outChan;
ChannelState *inStatePtr, *outStatePtr;
- int result = TCL_OK;
- Tcl_Size sizeb;
- Tcl_Size sizePart;
+ int result = TCL_OK, size, sizeb;
Tcl_WideInt total;
- int size;
- const char *buffer;
+ char *buffer;
int inBinary, outBinary, sameEncoding;
/* Encoding control */
int underflow; /* Input underflow */
@@ -9855,16 +8720,14 @@ CopyData(
inBinary = (inStatePtr->encoding == NULL);
outBinary = (outStatePtr->encoding == NULL);
- sameEncoding = inStatePtr->encoding == outStatePtr->encoding
- && ENCODING_PROFILE_GET(inStatePtr->inputEncodingFlags) == TCL_ENCODING_PROFILE_TCL8
- && ENCODING_PROFILE_GET(outStatePtr->outputEncodingFlags) == TCL_ENCODING_PROFILE_TCL8;
+ sameEncoding = (inStatePtr->encoding == outStatePtr->encoding);
if (!(inBinary || sameEncoding)) {
TclNewObj(bufObj);
Tcl_IncrRefCount(bufObj);
}
- while (csPtr->toRead != (Tcl_WideInt) 0) {
+ while (csPtr->toRead != 0) {
/*
* Check for unreported background errors.
*/
@@ -9874,20 +8737,12 @@ CopyData(
Tcl_SetErrno(inStatePtr->unreportedError);
inStatePtr->unreportedError = 0;
goto readError;
- } else if (inStatePtr->flags & CHANNEL_ENCODING_ERROR) {
- Tcl_SetErrno(EILSEQ);
- inStatePtr->flags &= ~CHANNEL_ENCODING_ERROR;
- goto readError;
}
Tcl_GetChannelError(outChan, &msg);
if ((outStatePtr->unreportedError != 0) || (msg != NULL)) {
Tcl_SetErrno(outStatePtr->unreportedError);
outStatePtr->unreportedError = 0;
goto writeError;
- } else if (outStatePtr->flags & CHANNEL_ENCODING_ERROR) {
- Tcl_SetErrno(EILSEQ);
- outStatePtr->flags &= ~CHANNEL_ENCODING_ERROR;
- goto writeError;
}
if (cmdPtr && (mask == 0)) {
@@ -9896,44 +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,
- !GotFlag(inStatePtr, CHANNEL_NONBLOCKING)
- ,0 /* No append */);
- /*
- * In case of a recoverable encoding error, any data before
- * the error should be written. This data is in the bufObj.
- * Program flow for this case:
- * - Check, if there are any remaining bytes to write
- * - If yes, simulate a successful read to write them out
- * - Come back here by the outer loop and read again
- * - Do not enter in the if below, as there are no pending
- * writes
- * - Fail below with a read error
- */
- if (size < 0 && Tcl_GetErrno() == EILSEQ) {
- Tcl_GetStringFromObj(bufObj, &sizePart);
- if (sizePart > 0) {
- size = sizePart;
- }
- }
+ 0 /* No append */);
}
underflow = (size >= 0) && (size < sizeb); /* Input underflow */
}
@@ -9943,12 +8778,12 @@ CopyData(
if (interp) {
TclNewObj(errObj);
Tcl_AppendStringsToObj(errObj, "error reading \"",
- Tcl_GetChannelName(inChan), "\": ", (void *)NULL);
+ Tcl_GetChannelName(inChan), "\": ", NULL);
if (msg != NULL) {
Tcl_AppendObjToObj(errObj, msg);
} else {
Tcl_AppendStringsToObj(errObj, Tcl_PosixError(interp),
- (void *)NULL);
+ NULL);
}
}
if (msg != NULL) {
@@ -9966,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);
}
@@ -9975,13 +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;
@@ -10024,12 +8852,12 @@ CopyData(
if (interp) {
TclNewObj(errObj);
Tcl_AppendStringsToObj(errObj, "error writing \"",
- Tcl_GetChannelName(outChan), "\": ", (void *)NULL);
+ Tcl_GetChannelName(outChan), "\": ", NULL);
if (msg != NULL) {
Tcl_AppendObjToObj(errObj, msg);
} else {
Tcl_AppendStringsToObj(errObj, Tcl_PosixError(interp),
- (void *)NULL);
+ NULL);
}
}
if (msg != NULL) {
@@ -10039,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.
@@ -10065,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);
@@ -10116,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
@@ -10134,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);
@@ -10160,13 +8987,14 @@ 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),
- * or TCL_INDEX_NONE if there is an error in reading the channel. Use
+ * or -1 if there is an error in reading the channel. Use
* Tcl_GetErrno() to retrieve the error code for the error
* that occurred.
*
@@ -10175,7 +9003,7 @@ CopyData(
* - EOF is reached on the channel; or
* - the channel is non-blocking, and we've read all we can
* without blocking.
- * - a channel reading error occurs (and we return TCL_INDEX_NONE)
+ * - a channel reading error occurs (and we return -1)
*
* Side effects:
* May cause input to be buffered.
@@ -10183,17 +9011,16 @@ CopyData(
*----------------------------------------------------------------------
*/
-static Tcl_Size
+static int
DoRead(
Channel *chanPtr, /* The channel from which to read. */
- char *dst, /* Where to store input read. */
- Tcl_Size 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;
- assert(bytesToRead >= 0);
+ assert (bytesToRead >= 0);
/*
* Early out when we know a read will get the eofchar.
@@ -10207,25 +9034,17 @@ DoRead(
* too. Keep on keeping on for now.
*/
- if (GotFlag(statePtr, CHANNEL_ENCODING_ERROR)) {
- UpdateInterest(chanPtr);
- Tcl_SetErrno(EILSEQ);
- return -1;
- }
if (GotFlag(statePtr, CHANNEL_STICKY_EOF)) {
SetFlag(statePtr, CHANNEL_EOF);
- assert(statePtr->inputEncodingFlags & TCL_ENCODING_END);
- assert(!GotFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR));
+ assert( statePtr->inputEncodingFlags & TCL_ENCODING_END );
+ assert( !GotFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR) );
/* TODO: Don't need this call */
UpdateInterest(chanPtr);
return 0;
}
- /*
- * Special handling for zero-char read request.
- */
-
+ /* Special handling for zero-char read request. */
if (bytesToRead == 0) {
if (GotFlag(statePtr, CHANNEL_EOF)) {
statePtr->inputEncodingFlags |= TCL_ENCODING_START;
@@ -10240,52 +9059,46 @@ DoRead(
TclChannelPreserve((Tcl_Channel)chanPtr);
while (bytesToRead) {
/*
- * Each pass through the loop is intended to process up to one channel
- * buffer.
+ * Each pass through the loop is intended to process up to
+ * one channel buffer.
*/
int bytesRead, bytesWritten;
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 yet
- * to fill the dst */
+ (BytesLeft(bufPtr) < bytesToRead) ) ) {
+ /* Not enough bytes in it
+ * yet to fill the dst */
int code;
moreData:
code = GetInput(chanPtr);
bufPtr = statePtr->inQueueHead;
- assert(bufPtr != NULL);
+ assert (bufPtr != NULL);
if (GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED)) {
- /*
- * Further reads cannot do any more.
- */
-
+ /* Further reads cannot do any more */
break;
}
if (code) {
- /*
- * Read error
- */
-
+ /* Read error */
UpdateInterest(chanPtr);
TclChannelRelease((Tcl_Channel)chanPtr);
return -1;
}
- assert(IsBufferFull(bufPtr));
+ assert (IsBufferFull(bufPtr));
}
- assert(bufPtr != NULL);
+ assert (bufPtr != NULL);
bytesRead = BytesLeft(bufPtr);
bytesWritten = bytesToRead;
@@ -10300,8 +9113,8 @@ DoRead(
/*
* Buffer is not empty. How can that be?
*
- * 0) We stopped early because we got all the bytes we were
- * seeking. That's fine.
+ * 0) We stopped early because we got all the bytes
+ * we were seeking. That's fine.
*/
if (bytesToRead == 0) {
@@ -10309,16 +9122,16 @@ DoRead(
}
/*
- * 1) We're @EOF because we saw eof char, or there was an encoding error.
+ * 1) We're @EOF because we saw eof char.
*/
- if (GotFlag(statePtr, CHANNEL_STICKY_EOF|CHANNEL_ENCODING_ERROR)) {
+ if (GotFlag(statePtr, CHANNEL_STICKY_EOF)) {
break;
}
/*
- * 2) The buffer holds a \r while in CRLF translation, followed by
- * the end of the buffer.
+ * 2) The buffer holds a \r while in CRLF translation,
+ * followed by the end of the buffer.
*/
assert(statePtr->inputTranslation == TCL_TRANSLATE_CRLF);
@@ -10326,38 +9139,26 @@ DoRead(
assert(BytesLeft(bufPtr) == 1);
if (bufPtr->nextPtr == NULL) {
- /*
- * There's no more buffered data...
- */
+ /* There's no more buffered data.... */
if (GotFlag(statePtr, CHANNEL_EOF)) {
- /*
- * ...and there never will be.
- */
+ /* ...and there never will be. */
*p++ = '\r';
bytesToRead--;
bufPtr->nextRemoved++;
} else if (GotFlag(statePtr, CHANNEL_BLOCKED)) {
- /*
- * ...and we cannot get more now.
- */
-
+ /* ...and we cannot get more now. */
SetFlag(statePtr, CHANNEL_NEED_MORE_DATA);
break;
} else {
- /*
- * ...so we need to get some.
- */
-
+ /* ... so we need to get some. */
goto moreData;
}
}
if (bufPtr->nextPtr) {
- /*
- * There's a next buffer. Shift orphan \r to it.
- */
+ /* There's a next buffer. Shift orphan \r to it. */
ChannelBuffer *nextPtr = bufPtr->nextPtr;
@@ -10376,14 +9177,14 @@ 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;
}
/*
- * When there's no buffered data to read, and we're at EOF, escape to
- * the caller.
+ * When there's no buffered data to read, and we're at EOF,
+ * escape to the caller.
*/
if (GotFlag(statePtr, CHANNEL_EOF)
@@ -10395,12 +9196,11 @@ DoRead(
ResetFlag(statePtr, CHANNEL_BLOCKED);
}
- assert(!GotFlag(statePtr, CHANNEL_EOF)
- || GotFlag(statePtr, CHANNEL_STICKY_EOF)
- || GotFlag(statePtr, CHANNEL_ENCODING_ERROR)
- || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0);
- assert(!(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED)
- == (CHANNEL_EOF|CHANNEL_BLOCKED)));
+ assert(!GotFlag(statePtr, CHANNEL_EOF)
+ || GotFlag(statePtr, CHANNEL_STICKY_EOF)
+ || Tcl_InputBuffered((Tcl_Channel)chanPtr) == 0);
+ assert( !(GotFlag(statePtr, CHANNEL_EOF|CHANNEL_BLOCKED)
+ == (CHANNEL_EOF|CHANNEL_BLOCKED)) );
UpdateInterest(chanPtr);
TclChannelRelease((Tcl_Channel)chanPtr);
return (int)(p - dst);
@@ -10426,10 +9226,10 @@ DoRead(
static void
CopyEventProc(
- void *clientData,
+ ClientData clientData,
int mask)
{
- (void) CopyData((CopyState *)clientData, mask);
+ (void) CopyData((CopyState *) clientData, mask);
}
/*
@@ -10454,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;
@@ -10471,34 +9267,34 @@ StopCopy(
* Restore the old blocking mode and output buffering mode.
*/
- nonBlocking = csPtr->readFlags & CHANNEL_NONBLOCKING;
- if (nonBlocking != GotFlag(inStatePtr, 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;
- if (nonBlocking != GotFlag(outStatePtr, 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);
- SetFlag(outStatePtr,
- csPtr->writeFlags & (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);
}
/*
@@ -10539,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;
@@ -10594,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 {
/*
@@ -10693,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) {
@@ -10762,7 +9556,7 @@ Tcl_IsChannelRegistered(
chanPtr = ((Channel *) chan)->state->bottomChanPtr;
statePtr = chanPtr->state;
- hTblPtr = (Tcl_HashTable *)Tcl_GetAssocData(interp, "tclIO", NULL);
+ hTblPtr = Tcl_GetAssocData(interp, "tclIO", NULL);
if (hTblPtr == NULL) {
return 0;
}
@@ -10843,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, chanNameLen + 1) == 0)) {
+ (memcmp(name, chanName, (size_t) chanNameLen+1) == 0)) {
return 1;
}
}
@@ -10896,17 +9693,49 @@ Tcl_ChannelVersion(
const Tcl_ChannelType *chanTypePtr)
/* Pointer to channel type. */
{
-#ifndef TCL_NO_DEPRECATED
- if ((chanTypePtr->version < TCL_CHANNEL_VERSION_2)
- || (chanTypePtr->version > TCL_CHANNEL_VERSION_5)) {
+ if (chanTypePtr->version == TCL_CHANNEL_VERSION_2) {
+ return TCL_CHANNEL_VERSION_2;
+ } else if (chanTypePtr->version == TCL_CHANNEL_VERSION_3) {
+ return TCL_CHANNEL_VERSION_3;
+ } else if (chanTypePtr->version == TCL_CHANNEL_VERSION_4) {
+ return TCL_CHANNEL_VERSION_4;
+ } else if (chanTypePtr->version == TCL_CHANNEL_VERSION_5) {
+ return TCL_CHANNEL_VERSION_5;
+ } else {
/*
* In <v2 channel versions, the version field is occupied by the
* Tcl_DriverBlockModeProc
*/
+
return TCL_CHANNEL_VERSION_1;
}
-#endif
- return chanTypePtr->version;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * HaveVersion --
+ *
+ * Return whether a channel type is (at least) of a given version.
+ *
+ * Results:
+ * True if the minimum version is exceeded by the version actually
+ * present.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+HaveVersion(
+ const Tcl_ChannelType *chanTypePtr,
+ Tcl_ChannelTypeVersion minimumVersion)
+{
+ Tcl_ChannelTypeVersion actualVersion = Tcl_ChannelVersion(chanTypePtr);
+
+ return (PTR2INT(actualVersion)) >= (PTR2INT(minimumVersion));
}
/*
@@ -10929,15 +9758,15 @@ Tcl_ChannelBlockModeProc(
const Tcl_ChannelType *chanTypePtr)
/* Pointer to channel type. */
{
-#ifndef TCL_NO_DEPRECATED
- if (Tcl_ChannelVersion(chanTypePtr) < TCL_CHANNEL_VERSION_2) {
+ if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_2)) {
+ return chanTypePtr->blockModeProc;
+ } else {
/*
* The v1 structure had the blockModeProc in a different place.
*/
- return (Tcl_DriverBlockModeProc *) chanTypePtr->version;
+
+ return (Tcl_DriverBlockModeProc *) (chanTypePtr->version);
}
-#endif
- return chanTypePtr->blockModeProc;
}
/*
@@ -10956,7 +9785,6 @@ Tcl_ChannelBlockModeProc(
*----------------------------------------------------------------------
*/
-#ifndef TCL_NO_DEPRECATED
Tcl_DriverCloseProc *
Tcl_ChannelCloseProc(
const Tcl_ChannelType *chanTypePtr)
@@ -10964,7 +9792,6 @@ Tcl_ChannelCloseProc(
{
return chanTypePtr->closeProc;
}
-#endif
/*
*----------------------------------------------------------------------
@@ -11054,7 +9881,6 @@ Tcl_ChannelOutputProc(
*----------------------------------------------------------------------
*/
-#ifndef TCL_NO_DEPRECATED
Tcl_DriverSeekProc *
Tcl_ChannelSeekProc(
const Tcl_ChannelType *chanTypePtr)
@@ -11062,7 +9888,6 @@ Tcl_ChannelSeekProc(
{
return chanTypePtr->seekProc;
}
-#endif
/*
*----------------------------------------------------------------------
@@ -11181,12 +10006,11 @@ Tcl_ChannelFlushProc(
const Tcl_ChannelType *chanTypePtr)
/* Pointer to channel type. */
{
-#ifndef TCL_NO_DEPRECATED
- if (Tcl_ChannelVersion(chanTypePtr) < TCL_CHANNEL_VERSION_2) {
+ if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_2)) {
+ return chanTypePtr->flushProc;
+ } else {
return NULL;
}
-#endif
- return chanTypePtr->flushProc;
}
/*
@@ -11210,12 +10034,11 @@ Tcl_ChannelHandlerProc(
const Tcl_ChannelType *chanTypePtr)
/* Pointer to channel type. */
{
-#ifndef TCL_NO_DEPRECATED
- if (Tcl_ChannelVersion(chanTypePtr) < TCL_CHANNEL_VERSION_2) {
+ if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_2)) {
+ return chanTypePtr->handlerProc;
+ } else {
return NULL;
}
-#endif
- return chanTypePtr->handlerProc;
}
/*
@@ -11239,12 +10062,11 @@ Tcl_ChannelWideSeekProc(
const Tcl_ChannelType *chanTypePtr)
/* Pointer to channel type. */
{
-#ifndef TCL_NO_DEPRECATED
- if (Tcl_ChannelVersion(chanTypePtr) < TCL_CHANNEL_VERSION_3) {
+ if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_3)) {
+ return chanTypePtr->wideSeekProc;
+ } else {
return NULL;
}
-#endif
- return chanTypePtr->wideSeekProc;
}
/*
@@ -11269,12 +10091,11 @@ Tcl_ChannelThreadActionProc(
const Tcl_ChannelType *chanTypePtr)
/* Pointer to channel type. */
{
-#ifndef TCL_NO_DEPRECATED
- if (Tcl_ChannelVersion(chanTypePtr) < TCL_CHANNEL_VERSION_4) {
+ if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_4)) {
+ return chanTypePtr->threadActionProc;
+ } else {
return NULL;
}
-#endif
- return chanTypePtr->threadActionProc;
}
/*
@@ -11300,17 +10121,15 @@ Tcl_SetChannelErrorInterp(
Tcl_Obj *msg) /* Error message to store. */
{
Interp *iPtr = (Interp *) interp;
- Tcl_Obj *disposePtr = iPtr->chanMsg;
- if (msg != NULL) {
- iPtr->chanMsg = FixLevelCode(msg);
- Tcl_IncrRefCount(iPtr->chanMsg);
- } else {
+ if (iPtr->chanMsg != NULL) {
+ TclDecrRefCount(iPtr->chanMsg);
iPtr->chanMsg = NULL;
}
- if (disposePtr != NULL) {
- TclDecrRefCount(disposePtr);
+ if (msg != NULL) {
+ iPtr->chanMsg = FixLevelCode(msg);
+ Tcl_IncrRefCount(iPtr->chanMsg);
}
return;
}
@@ -11338,17 +10157,15 @@ Tcl_SetChannelError(
Tcl_Obj *msg) /* Error message to store. */
{
ChannelState *statePtr = ((Channel *) chan)->state;
- Tcl_Obj *disposePtr = statePtr->chanMsg;
- if (msg != NULL) {
- statePtr->chanMsg = FixLevelCode(msg);
- Tcl_IncrRefCount(statePtr->chanMsg);
- } else {
+ if (statePtr->chanMsg != NULL) {
+ TclDecrRefCount(statePtr->chanMsg);
statePtr->chanMsg = NULL;
}
- if (disposePtr != NULL) {
- TclDecrRefCount(disposePtr);
+ if (msg != NULL) {
+ statePtr->chanMsg = FixLevelCode(msg);
+ Tcl_IncrRefCount(statePtr->chanMsg);
}
return;
}
@@ -11376,8 +10193,7 @@ static Tcl_Obj *
FixLevelCode(
Tcl_Obj *msg)
{
- int explicitResult, numOptions, lcn;
- Tcl_Size lc;
+ int explicitResult, numOptions, lc, lcn;
Tcl_Obj **lv, **lvn;
int res, i, j, val, lignore, cignore;
int newlevel = -1, newcode = -1;
@@ -11390,13 +10206,13 @@ FixLevelCode(
* Syntax = (option value)... ?message?
*
* Bad message syntax causes a panic, because the other side uses
- * Tcl_GetReturnOptions and list construction functions to marshal the
+ * Tcl_GetReturnOptions and list construction functions to marshall the
* information. Hence an error means that we've got serious breakage.
*/
- res = TclListObjGetElements(NULL, msg, &lc, &lv);
+ 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));
@@ -11456,11 +10272,11 @@ FixLevelCode(
lcn += 2;
}
- lvn = (Tcl_Obj **)ckalloc(lcn * sizeof(Tcl_Obj *));
+ lvn = (Tcl_Obj **) ckalloc(lcn * sizeof(Tcl_Obj *));
/*
- * New level/code information is spliced into the first occurrence of
- * -level, -code, further occurrences are ignored. The options cannot be
+ * New level/code information is spliced into the first occurence of
+ * -level, -code, further occurences are ignored. The options cannot be
* not present, we would not come here. Options which are ok are simply
* copied over.
*/
@@ -11470,7 +10286,7 @@ FixLevelCode(
if (0 == strcmp(TclGetString(lv[i]), "-level")) {
if (newlevel >= 0) {
lvn[j++] = lv[i];
- lvn[j++] = Tcl_NewWideIntObj(newlevel);
+ lvn[j++] = Tcl_NewIntObj(newlevel);
newlevel = -1;
lignore = 1;
continue;
@@ -11480,7 +10296,7 @@ FixLevelCode(
} else if (0 == strcmp(TclGetString(lv[i]), "-code")) {
if (newcode >= 0) {
lvn[j++] = lv[i];
- lvn[j++] = Tcl_NewWideIntObj(newcode);
+ lvn[j++] = Tcl_NewIntObj(newcode);
newcode = -1;
cignore = 1;
continue;
@@ -11509,7 +10325,7 @@ FixLevelCode(
msg = Tcl_NewListObj(j, lvn);
- ckfree(lvn);
+ ckfree((char *) lvn);
return msg;
}
@@ -11591,16 +10407,17 @@ Tcl_ChannelTruncateProc(
const Tcl_ChannelType *chanTypePtr)
/* Pointer to channel type. */
{
- if (Tcl_ChannelVersion(chanTypePtr) < TCL_CHANNEL_VERSION_5) {
+ if (HaveVersion(chanTypePtr, TCL_CHANNEL_VERSION_5)) {
+ return chanTypePtr->truncateProc;
+ } else {
return NULL;
}
- return chanTypePtr->truncateProc;
}
/*
*----------------------------------------------------------------------
*
- * DupChannelInternalRep --
+ * DupChannelIntRep --
*
* Initialize the internal representation of a new Tcl_Obj to a copy of
* the internal representation of an existing string object.
@@ -11616,23 +10433,85 @@ Tcl_ChannelTruncateProc(
*/
static void
-DupChannelInternalRep(
- Tcl_Obj *srcPtr, /* Object with internal rep to copy. Must have
+DupChannelIntRep(
+ register Tcl_Obj *srcPtr, /* Object with internal rep to copy. Must have
* an internal rep of type "Channel". */
- Tcl_Obj *copyPtr) /* Object with internal rep to set. Must not
+ register Tcl_Obj *copyPtr) /* Object with internal rep to set. Must not
* currently have an internal rep.*/
{
- ResolvedChanName *resPtr;
+ ChannelState *statePtr = GET_CHANNELSTATE(srcPtr);
- ChanGetInternalRep(srcPtr, resPtr);
- assert(resPtr);
- ChanSetInternalRep(copyPtr, resPtr);
+ SET_CHANNELSTATE(copyPtr, statePtr);
+ SET_CHANNELINTERP(copyPtr, GET_CHANNELINTERP(srcPtr));
+ Tcl_Preserve((ClientData) statePtr);
+ copyPtr->typePtr = srcPtr->typePtr;
}
/*
*----------------------------------------------------------------------
*
- * FreeChannelInternalRep --
+ * 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.
*
@@ -11646,18 +10525,10 @@ DupChannelInternalRep(
*/
static void
-FreeChannelInternalRep(
+FreeChannelIntRep(
Tcl_Obj *objPtr) /* Object with internal rep to free. */
{
- ResolvedChanName *resPtr;
-
- ChanGetInternalRep(objPtr, resPtr);
- assert(resPtr);
- if (resPtr->refCount-- > 1) {
- return;
- }
- Tcl_Release(resPtr->statePtr);
- ckfree(resPtr);
+ Tcl_Release((ClientData) GET_CHANNELSTATE(objPtr));
}
#if 0
@@ -11671,10 +10542,10 @@ DumpFlags(
char *str,
int flags)
{
+ char buf[20];
int i = 0;
- char buf[24];
-#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);
@@ -11685,7 +10556,6 @@ DumpFlags(
ChanFlag('c', CHANNEL_CLOSED);
ChanFlag('E', CHANNEL_EOF);
ChanFlag('S', CHANNEL_STICKY_EOF);
- ChanFlag('U', CHANNEL_ENCODING_ERROR);
ChanFlag('B', CHANNEL_BLOCKED);
ChanFlag('/', INPUT_SAW_CR);
ChanFlag('D', CHANNEL_DEAD);