/Tests/FindMPI/

d3af3ad5]: * Move the server code from CreateSocket to Tcl_OpenTcpServer. * Rename CreateSocket to CreateClientSocket. * Unify the naming convention of socket channels with Unix (sock + hex representation of the state/info structure). --- win/tclWinSock.c | 368 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 203 insertions(+), 165 deletions(-) diff --git a/win/tclWinSock.c b/win/tclWinSock.c index 5ac8f47..bd993fa 100644 --- a/win/tclWinSock.c +++ b/win/tclWinSock.c @@ -74,6 +74,10 @@ #undef getsockopt #undef setsockopt +/* "sock" + a pointer in hex + \0 */ +#define SOCK_CHAN_LENGTH (4 + sizeof(void *) * 2 + 1) +#define SOCK_TEMPLATE "sock%lx" + /* * The following variable is used to tell whether this module has been * initialized. If 1, initialization of sockets was successful, if -1 then @@ -210,8 +214,8 @@ static WNDCLASS windowClass; * Static functions defined in this file. */ -static SocketInfo * CreateSocket(Tcl_Interp *interp, int port, - const char *host, int server, const char *myaddr, +static SocketInfo * CreateClientSocket(Tcl_Interp *interp, int port, + const char *host, const char *myaddr, int myport, int async); static void InitSockets(void); static SocketInfo * NewSocketInfo(SOCKET socket); @@ -1101,10 +1105,10 @@ NewSocketInfo( /* *---------------------------------------------------------------------- * - * CreateSocket -- + * CreateClientSocket -- * - * This function opens a new socket and initializes the SocketInfo - * structure. + * This function opens a new client socket and initializes the + * SocketInfo structure. * * Results: * Returns a new SocketInfo, or NULL with an error in interp. @@ -1116,12 +1120,10 @@ NewSocketInfo( */ static SocketInfo * -CreateSocket( +CreateClientSocket( Tcl_Interp *interp, /* For error reporting; can be NULL. */ int port, /* Port number to open. */ const char *host, /* Name of host on which to open port. */ - int server, /* 1 if socket should be a server socket, else - * 0 for a client socket. */ const char *myaddr, /* Optional client-side address */ int myport, /* Optional client-side port */ int async) /* If nonzero, connect client socket @@ -1155,7 +1157,7 @@ CreateSocket( * Construct the addresses for each end of the socket. */ - if (!TclCreateSocketAddress(interp, &addrlist, host, port, server, + if (!TclCreateSocketAddress(interp, &addrlist, host, port, 0, &errorMsg)) { goto error; } @@ -1164,10 +1166,20 @@ CreateSocket( goto error; } - if (server) { + for (addrPtr = addrlist; addrPtr != NULL; + addrPtr = addrPtr->ai_next) { + for (myaddrPtr = myaddrlist; myaddrPtr != NULL; + myaddrPtr = myaddrPtr->ai_next) { + /* + * No need to try combinations of local and remote addresses + * of different families. + */ - for (addrPtr = addrlist; addrPtr != NULL; addrPtr = addrPtr->ai_next) { - sock = socket(addrPtr->ai_family, SOCK_STREAM, 0); + if (myaddrPtr->ai_family != addrPtr->ai_family) { + continue; + } + + sock = socket(myaddrPtr->ai_family, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { TclWinConvertError((DWORD) WSAGetLastError()); continue; @@ -1187,158 +1199,52 @@ CreateSocket( TclSockMinimumBuffers((void *)sock, TCP_BUFFER_SIZE); /* - * Make sure we use the same port when opening two server sockets - * for IPv4 and IPv6. - * - * As sockaddr_in6 uses the same offset and size for the port - * member as sockaddr_in, we can handle both through the IPv4 API. + * Try to bind to a local port. */ - if (port == 0 && chosenport != 0) { - ((struct sockaddr_in *) addrPtr->ai_addr)->sin_port = - htons(chosenport); + if (bind(sock, myaddrPtr->ai_addr, myaddrPtr->ai_addrlen) + == SOCKET_ERROR) { + TclWinConvertError((DWORD) WSAGetLastError()); + goto looperror; } - /* - * Bind to the specified port. Note that we must not call - * setsockopt with SO_REUSEADDR because Microsoft allows addresses - * to be reused even if they are still in use. - * - * Bind should not be affected by the socket having already been - * set into nonblocking mode. If there is trouble, this is one - * place to look for bugs. + * Set the socket into nonblocking mode if the connect should + * be done in the background. */ - - if (bind(sock, addrPtr->ai_addr, addrPtr->ai_addrlen) - == SOCKET_ERROR) { + if (async && ioctlsocket(sock, (long) FIONBIO, &flag) + == SOCKET_ERROR) { TclWinConvertError((DWORD) WSAGetLastError()); - closesocket(sock); - continue; - } - if (port == 0 && chosenport == 0) { - address sockname; - socklen_t namelen = sizeof(sockname); - - /* - * Synchronize port numbers when binding to port 0 of multiple - * addresses. - */ - - if (getsockname(sock, &sockname.sa, &namelen) >= 0) { - chosenport = ntohs(sockname.sa4.sin_port); - } + goto looperror; } /* - * Set the maximum number of pending connect requests to the max - * value allowed on each platform (Win32 and Win32s may be - * different, and there may be differences between TCP/IP stacks). + * Attempt to connect to the remote socket. */ - if (listen(sock, SOMAXCONN) == SOCKET_ERROR) { - TclWinConvertError((DWORD) WSAGetLastError()); - closesocket(sock); - continue; - } - - if (infoPtr == NULL) { - /* - * Add this socket to the global list of sockets. - */ - - infoPtr = NewSocketInfo(sock); - - /* - * Set up the select mask for connection request events. - */ - - infoPtr->selectEvents = FD_ACCEPT; - infoPtr->watchEvents |= FD_ACCEPT; - - } else { - AddSocketInfoFd( infoPtr, sock ); - } - } - } else { - for (addrPtr = addrlist; addrPtr != NULL; - addrPtr = addrPtr->ai_next) { - for (myaddrPtr = myaddrlist; myaddrPtr != NULL; - myaddrPtr = myaddrPtr->ai_next) { - /* - * No need to try combinations of local and remote addresses - * of different families. - */ - - if (myaddrPtr->ai_family != addrPtr->ai_family) { - continue; - } - - sock = socket(myaddrPtr->ai_family, SOCK_STREAM, 0); - if (sock == INVALID_SOCKET) { - TclWinConvertError((DWORD) WSAGetLastError()); - continue; - } - - /* - * Win-NT has a misfeature that sockets are inherited in child - * processes by default. Turn off the inherit bit. - */ - - SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0); - - /* - * Set kernel space buffering - */ - - TclSockMinimumBuffers((void *) sock, TCP_BUFFER_SIZE); - - /* - * Try to bind to a local port. - */ - - if (bind(sock, myaddrPtr->ai_addr, myaddrPtr->ai_addrlen) - == SOCKET_ERROR) { - TclWinConvertError((DWORD) WSAGetLastError()); + if (connect(sock, addrPtr->ai_addr, addrPtr->ai_addrlen) + == SOCKET_ERROR) { + DWORD error = (DWORD) WSAGetLastError(); + if (error != WSAEWOULDBLOCK) { + TclWinConvertError(error); goto looperror; } + /* - * Set the socket into nonblocking mode if the connect should - * be done in the background. + * The connection is progressing in the background. */ - if (async && ioctlsocket(sock, (long) FIONBIO, &flag) - == SOCKET_ERROR) { - TclWinConvertError((DWORD) WSAGetLastError()); - goto looperror; - } - - /* - * Attempt to connect to the remote socket. - */ - - if (connect(sock, addrPtr->ai_addr, addrPtr->ai_addrlen) - == SOCKET_ERROR) { - DWORD error = (DWORD) WSAGetLastError(); - if (error != WSAEWOULDBLOCK) { - TclWinConvertError(error); - goto looperror; - } - - /* - * The connection is progressing in the background. - */ - asyncConnect = 1; - } - goto connected; - - looperror: - if (sock != INVALID_SOCKET) { - closesocket(sock); - sock = INVALID_SOCKET; - } + asyncConnect = 1; + } + goto connected; + + looperror: + if (sock != INVALID_SOCKET) { + closesocket(sock); + sock = INVALID_SOCKET; } } - goto error; + } + goto error; connected: /* @@ -1357,7 +1263,6 @@ CreateSocket( infoPtr->flags |= SOCKET_ASYNC_CONNECT; infoPtr->selectEvents |= FD_CONNECT; } - } error: if (addrlist != NULL) { @@ -1496,12 +1401,12 @@ Tcl_OpenTcpClient( * Create a new client socket and wrap it in a channel. */ - infoPtr = CreateSocket(interp, port, host, 0, myaddr, myport, async); + infoPtr = CreateClientSocket(interp, port, host, myaddr, myport, async); if (infoPtr == NULL) { return NULL; } - sprintf(channelName, "sock%" TCL_I_MODIFIER "u", (size_t) infoPtr->sockets->fd); + sprintf(channelName, SOCK_TEMPLATE, infoPtr); infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, infoPtr, (TCL_READABLE | TCL_WRITABLE)); @@ -1564,7 +1469,7 @@ Tcl_MakeTcpClientChannel( infoPtr->selectEvents = FD_READ | FD_CLOSE | FD_WRITE; SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM)SELECT, (LPARAM)infoPtr); - sprintf(channelName, "sock%" TCL_I_MODIFIER "u", (size_t) infoPtr->sockets->fd); + sprintf(channelName, SOCK_TEMPLATE, infoPtr); infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, infoPtr, (TCL_READABLE | TCL_WRITABLE)); Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto crlf"); @@ -1598,36 +1503,169 @@ Tcl_OpenTcpServer( * clients. */ ClientData acceptProcData) /* Data for the callback. */ { - SocketInfo *infoPtr; - char channelName[16 + TCL_INTEGER_SPACE]; + SOCKET sock = INVALID_SOCKET; + unsigned short chosenport = 0; + struct addrinfo *addrPtr; /* Socket address to listen on. */ + SocketInfo *infoPtr = NULL; /* The returned value. */ + void *addrlist = NULL; + char channelName[SOCK_CHAN_LENGTH]; + u_long flag = 1; /* Indicates nonblocking mode. */ + const char *errorMsg = NULL; + ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey); if (TclpHasSockets(interp) != TCL_OK) { return NULL; } /* - * Create a new client socket and wrap it in a channel. + * Check that WinSock is initialized; do not call it if not, to prevent + * system crashes. This can happen at exit time if the exit handler for + * WinSock ran before other exit handlers that want to use sockets. */ - infoPtr = CreateSocket(interp, port, host, 1, NULL, 0, 0); - if (infoPtr == NULL) { + if (!SocketsEnabled()) { return NULL; } - infoPtr->acceptProc = acceptProc; - infoPtr->acceptProcData = acceptProcData; + /* + * Construct the addresses for each end of the socket. + */ - sprintf(channelName, "sock%" TCL_I_MODIFIER "u", (size_t) infoPtr->sockets->fd); + if (!TclCreateSocketAddress(interp, &addrlist, host, port, 1, &errorMsg)) { + goto error; + } - infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, - infoPtr, 0); - if (Tcl_SetChannelOption(interp, infoPtr->channel, "-eofchar", "") + for (addrPtr = addrlist; addrPtr != NULL; addrPtr = addrPtr->ai_next) { + sock = socket(addrPtr->ai_family, addrPtr->ai_socktype, + addrPtr->ai_protocol); + if (sock == INVALID_SOCKET) { + TclWinConvertError((DWORD) WSAGetLastError()); + continue; + } + + /* + * Win-NT has a misfeature that sockets are inherited in child + * processes by default. Turn off the inherit bit. + */ + + SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0); + + /* + * Set kernel space buffering + */ + + TclSockMinimumBuffers((void *)sock, TCP_BUFFER_SIZE); + + /* + * Make sure we use the same port when opening two server sockets + * for IPv4 and IPv6. + * + * As sockaddr_in6 uses the same offset and size for the port + * member as sockaddr_in, we can handle both through the IPv4 API. + */ + + if (port == 0 && chosenport != 0) { + ((struct sockaddr_in *) addrPtr->ai_addr)->sin_port = + htons(chosenport); + } + + /* + * Bind to the specified port. Note that we must not call + * setsockopt with SO_REUSEADDR because Microsoft allows addresses + * to be reused even if they are still in use. + * + * Bind should not be affected by the socket having already been + * set into nonblocking mode. If there is trouble, this is one + * place to look for bugs. + */ + + if (bind(sock, addrPtr->ai_addr, addrPtr->ai_addrlen) + == SOCKET_ERROR) { + TclWinConvertError((DWORD) WSAGetLastError()); + closesocket(sock); + continue; + } + if (port == 0 && chosenport == 0) { + address sockname; + socklen_t namelen = sizeof(sockname); + + /* + * Synchronize port numbers when binding to port 0 of multiple + * addresses. + */ + + if (getsockname(sock, &sockname.sa, &namelen) >= 0) { + chosenport = ntohs(sockname.sa4.sin_port); + } + } + + /* + * Set the maximum number of pending connect requests to the max + * value allowed on each platform (Win32 and Win32s may be + * different, and there may be differences between TCP/IP stacks). + */ + + if (listen(sock, SOMAXCONN) == SOCKET_ERROR) { + TclWinConvertError((DWORD) WSAGetLastError()); + closesocket(sock); + continue; + } + + if (infoPtr == NULL) { + /* + * Add this socket to the global list of sockets. + */ + infoPtr = NewSocketInfo(sock); + } else { + AddSocketInfoFd( infoPtr, sock ); + } + } + +error: + if (addrlist != NULL) { + freeaddrinfo(addrlist); + } + + if (infoPtr != NULL) { + + infoPtr->acceptProc = acceptProc; + infoPtr->acceptProcData = acceptProcData; + sprintf(channelName, SOCK_TEMPLATE, infoPtr); + infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, + infoPtr, 0); + /* + * Set up the select mask for connection request events. + */ + + infoPtr->selectEvents = FD_ACCEPT; + infoPtr->watchEvents |= FD_ACCEPT; + + /* + * Register for interest in events in the select mask. Note that this + * automatically places the socket into non-blocking mode. + */ + + ioctlsocket(sock, (long) FIONBIO, &flag); + SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, + (LPARAM) infoPtr); + if (Tcl_SetChannelOption(interp, infoPtr->channel, "-eofchar", "") == TCL_ERROR) { - Tcl_Close(NULL, infoPtr->channel); - return NULL; + Tcl_Close(NULL, infoPtr->channel); + return NULL; + } + return infoPtr->channel; } - return infoPtr->channel; + if (interp != NULL) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't open socket: %s", + (errorMsg ? errorMsg : Tcl_PosixError(interp)))); + } + + if (sock != INVALID_SOCKET) { + closesocket(sock); + } + return NULL; } /* @@ -1682,7 +1720,7 @@ TcpAccept( SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, (LPARAM) newInfoPtr); - sprintf(channelName, "sock%" TCL_I_MODIFIER "u", (size_t) newInfoPtr->sockets->fd); + sprintf(channelName, SOCK_TEMPLATE, newInfoPtr); newInfoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName, newInfoPtr, (TCL_READABLE | TCL_WRITABLE)); if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-translation", -- cgit v0.12 From 7460f22cc7e783b1dd480c2fbf8ef6fc90a0360c Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 21 Jan 2014 21:32:53 +0000 Subject: Backport of bytearray append machinery to support bug fixes in ReadBytes. --- generic/tclBinary.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++ generic/tclIO.c | 17 +++------- generic/tclInt.h | 2 ++ 3 files changed, 98 insertions(+), 13 deletions(-) diff --git a/generic/tclBinary.c b/generic/tclBinary.c index dbb296b..68289f2 100644 --- a/generic/tclBinary.c +++ b/generic/tclBinary.c @@ -549,6 +549,98 @@ UpdateStringOfByteArray( /* *---------------------------------------------------------------------- * + * TclAppendBytesToByteArray -- + * + * This function appends an array of bytes to a byte array object. Note + * that the object *must* be unshared, and the array of bytes *must not* + * refer to the object being appended to. + * + * Results: + * None. + * + * Side effects: + * Allocates enough memory for an array of bytes of the requested total + * size, or possibly larger. [Bug 2992970] + * + *---------------------------------------------------------------------- + */ + +#define TCL_MIN_GROWTH 1024 +void +TclAppendBytesToByteArray( + Tcl_Obj *objPtr, + const unsigned char *bytes, + int len) +{ + ByteArray *byteArrayPtr; + int needed; + + if (Tcl_IsShared(objPtr)) { + Tcl_Panic("%s called with shared object","TclAppendBytesToByteArray"); + } + if (len < 0) { + Tcl_Panic("%s must be called with definite number of bytes to append", + "TclAppendBytesToByteArray"); + } + if (len == 0) { + /* Append zero bytes is a no-op. */ + return; + } + if (objPtr->typePtr != &tclByteArrayType) { + SetByteArrayFromAny(NULL, objPtr); + } + byteArrayPtr = GET_BYTEARRAY(objPtr); + + if (len > INT_MAX - byteArrayPtr->used) { + Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); + } + + needed = byteArrayPtr->used + len; + /* + * If we need to, resize the allocated space in the byte array. + */ + + if (needed > byteArrayPtr->allocated) { + ByteArray *ptr = NULL; + int attempt; + + if (needed <= INT_MAX/2) { + /* Try to allocate double the total space that is needed. */ + attempt = 2 * needed; + ptr = (ByteArray *) attemptckrealloc((void *) byteArrayPtr, + BYTEARRAY_SIZE(attempt)); + } + if (ptr == NULL) { + /* Try to allocate double the increment that is needed (plus). */ + unsigned int limit = INT_MAX - needed; + unsigned int extra = len + TCL_MIN_GROWTH; + int growth = (int) ((extra > limit) ? limit : extra); + + attempt = needed + growth; + ptr = (ByteArray *) attemptckrealloc((void *) byteArrayPtr, + BYTEARRAY_SIZE(attempt)); + } + if (ptr == NULL) { + /* Last chance: Try to allocate exactly what is needed. */ + attempt = needed; + ptr = (ByteArray *) ckrealloc((void *)byteArrayPtr, + BYTEARRAY_SIZE(attempt)); + } + byteArrayPtr = ptr; + byteArrayPtr->allocated = attempt; + SET_BYTEARRAY(objPtr, byteArrayPtr); + } + + if (bytes) { + memcpy(byteArrayPtr->bytes + byteArrayPtr->used, bytes, len); + } + byteArrayPtr->used += len; + TclInvalidateStringRep(objPtr); +} + +/* + *---------------------------------------------------------------------- + * * Tcl_BinaryObjCmd -- * * This procedure implements the "binary" Tcl command. diff --git a/generic/tclIO.c b/generic/tclIO.c index f1d8909..c1b7ee9 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -5586,20 +5586,8 @@ ReadBytes( toRead = srcLen; } + TclAppendBytesToByteArray(objPtr, NULL, toRead); dst = (char *) Tcl_GetByteArrayFromObj(objPtr, &length); - if (toRead > length - offset - 1) { - /* - * Double the existing size of the object or make enough room to hold - * all the characters we may get from the source buffer, whichever is - * larger. - */ - - length = offset * 2; - if (offset < toRead) { - length = offset + toRead + 1; - } - dst = (char *) Tcl_SetByteArrayLength(objPtr, length); - } dst += offset; if (statePtr->flags & INPUT_NEED_NL) { @@ -5607,6 +5595,7 @@ ReadBytes( if ((srcLen == 0) || (*src != '\n')) { *dst = '\r'; *offsetPtr += 1; + Tcl_SetByteArrayLength(objPtr, *offsetPtr); return 1; } *dst++ = '\n'; @@ -5619,11 +5608,13 @@ ReadBytes( dstWrote = toRead; if (TranslateInputEOL(statePtr, dst, src, &dstWrote, &srcRead) != 0) { if (dstWrote == 0) { + Tcl_SetByteArrayLength(objPtr, *offsetPtr); return -1; } } bufPtr->nextRemoved += srcRead; *offsetPtr += dstWrote; + Tcl_SetByteArrayLength(objPtr, *offsetPtr); return dstWrote; } diff --git a/generic/tclInt.h b/generic/tclInt.h index dc28b97..64d39a0 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -2477,6 +2477,8 @@ MODULE_SCOPE char tclEmptyString; *---------------------------------------------------------------- */ +MODULE_SCOPE void TclAppendBytesToByteArray(Tcl_Obj *objPtr, + const unsigned char *bytes, int len); MODULE_SCOPE void TclAdvanceContinuations(int* line, int** next, int loc); MODULE_SCOPE void TclAdvanceLines(int *line, const char *start, const char *end); -- cgit v0.12 From abe23bfb4ef65eb899170e5ae7c4efc030294b31 Mon Sep 17 00:00:00 2001 From: dgp Date: Tue, 21 Jan 2014 22:08:16 +0000 Subject: There is no need for ReadBytes() or its caller(s) to track how many bytes are actually stored in objPtr. The ByteArray Tcl_ObjType already has the machinery to take care of this. --- generic/tclIO.c | 47 ++++++++++++++++++----------------------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/generic/tclIO.c b/generic/tclIO.c index c1b7ee9..4a5d8f1 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -208,7 +208,7 @@ static int HaveVersion(const Tcl_ChannelType *typePtr, static void PeekAhead(Channel *chanPtr, char **dstEndPtr, GetsState *gsPtr); static int ReadBytes(ChannelState *statePtr, Tcl_Obj *objPtr, - int charsLeft, int *offsetPtr); + int charsLeft); static int ReadChars(ChannelState *statePtr, Tcl_Obj *objPtr, int charsLeft, int *offsetPtr, int *factorPtr); static void RecycleBuffer(ChannelState *statePtr, @@ -5448,12 +5448,10 @@ DoReadChars( */ TclGetString(objPtr); + offset = 0; } - offset = 0; } else { - if (encoding == NULL) { - Tcl_GetByteArrayFromObj(objPtr, &offset); - } else { + if (encoding) { TclGetStringFromObj(objPtr, &offset); } } @@ -5462,7 +5460,7 @@ DoReadChars( copiedNow = -1; if (statePtr->inQueueHead != NULL) { if (encoding == NULL) { - copiedNow = ReadBytes(statePtr, objPtr, toRead, &offset); + copiedNow = ReadBytes(statePtr, objPtr, toRead); } else { copiedNow = ReadChars(statePtr, objPtr, toRead, &offset, &factor); @@ -5510,9 +5508,7 @@ DoReadChars( } ResetFlag(statePtr, CHANNEL_BLOCKED); - if (encoding == NULL) { - Tcl_SetByteArrayLength(objPtr, offset); - } else { + if (encoding) { Tcl_SetObjLength(objPtr, offset); } @@ -5540,13 +5536,11 @@ DoReadChars( * allocated to hold data read from the channel as needed. * * Results: - * The return value is the number of bytes appended to the object and - * *offsetPtr is filled with the total number of bytes in the object - * (greater than the return value if there were already bytes in the - * object). + * The return value is the number of bytes appended to the object, or + * -1 to indicate that zero bytes were read due to an EOF. * * Side effects: - * None. + * The storage of bytes in objPtr can cause (re-)allocation of memory. * *--------------------------------------------------------------------------- */ @@ -5559,24 +5553,18 @@ 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 < 0 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 * bytes available in the first buffer, only * the bytes from the first buffer are * returned. */ - int *offsetPtr) /* On input, contains how many bytes of objPtr - * have been used to hold data. On output, - * filled with how many bytes are now being - * used. */ { - int toRead, srcLen, offset, length, srcRead, dstWrote; + int toRead, srcLen, length, srcRead, dstWrote; ChannelBuffer *bufPtr; char *src, *dst; - offset = *offsetPtr; - bufPtr = statePtr->inQueueHead; src = RemovePoint(bufPtr); srcLen = BytesLeft(bufPtr); @@ -5586,16 +5574,17 @@ ReadBytes( toRead = srcLen; } + (void) Tcl_GetByteArrayFromObj(