Compare commits

...
Author SHA1 Message Date
dgp 9befca04cc Make simplificiations possible when we know just bytes are getting copied
without complications of encodings
2014-08-21 04:13:35 +00:00
dgp d8f1034a21 Copy Write() to WriteBytes() to create an arena for performance hacking. 2014-08-20 21:44:31 +00:00
andreask ce04ed5ad3 Fix reviewed and accepted. 2014-08-20 18:59:31 +00:00
dgp eda831ff7e Make test io-36.1.1 more portable. 2014-08-20 18:40:07 +00:00
dgp bc9dca8ca6 Docs for Tcl_CreateChannelHandler() state that the registered handler proc
will be called back with a mask value. "Mask is an integer mask indicating
which of the requested conditions actually exists for the channel; it will
contain ***a subset of the bits from the mask argument*** to
Tcl_CreateChannelHandler when the handler was created." (emhpasis added).

Tcl_NotifyChannel is not honoring this.  It passes a mask value that may
contain bits not in common with the mask argument to T_CCH().

This commit is a one-liner patch adding in the masking step to make things
behave as documented.  Thanks to apn for digging this out.  (In combination
with other questionable code, this led to a hang in test http-4.6 on Windows)

Tcl_NotifyChannel() has had this error in all of recorded Tcl history.
It's hard to imagine any code dependent on it though.  If any exists, it
can be revised to pass the mask value it truly needs to T_CCH() and end up
with code suitable both before and after this change.

If you concur, please merge to core-8-5-branch, and I'll take it from there.
2014-08-20 17:50:41 +00:00
jan.nijtmans 71f6f450b2 [74e073599e5e7c5eb535e2f60f1b06feb468eaae|74e073599e]: tclsh is using old style dialogs when Tk is loaded on Windows 2014-08-20 11:13:29 +00:00
3 changed files with 149 additions and 4 deletions
+127 -3
View File
@@ -228,8 +228,8 @@ static int WillRead(Channel *chanPtr);
#define WriteChars(chanPtr, src, srcLen) \
Write(chanPtr, src, srcLen, chanPtr->state->encoding)
#define WriteBytes(chanPtr, src, srcLen) \
Write(chanPtr, src, srcLen, tclIdentityEncoding)
static int WriteBytes(Channel *chanPtr, const char *src,
int srcLen);
/*
* Simplifying helper macros. All may use their argument(s) multiple times.
@@ -3888,6 +3888,130 @@ Write(
return total;
}
static int
WriteBytes(
Channel *chanPtr, /* The channel to buffer output for. */
const char *src, /* UTF-8 string to write. */
int srcLen) /* Length of UTF-8 string in bytes. */
{
ChannelState *statePtr = chanPtr->state;
/* State info for channel */
char *nextNewLine = NULL;
int saved = 0, total = 0, flushed = 0, needNlFlush = 0;
if (srcLen) {
WillWrite(chanPtr);
}
if (GotFlag(statePtr, CHANNEL_LINEBUFFERED)
|| (statePtr->outputTranslation != TCL_TRANSLATE_LF)) {
nextNewLine = memchr(src, '\n', srcLen);
}
while (srcLen + saved > 0) {
ChannelBuffer *bufPtr;
char *dst;
int dstLen, srcLimit = srcLen;
if (nextNewLine) {
srcLimit = nextNewLine - src;
}
/* Get space to write into */
bufPtr = statePtr->curOutPtr;
if (bufPtr == NULL) {
bufPtr = AllocChannelBuffer(statePtr->bufSize);
statePtr->curOutPtr = bufPtr;
}
if (saved) {
/* Start new buffer with \n straddled over from last one */
InsertPoint(bufPtr)[0] = '\n';
bufPtr->nextAdded++;
saved = 0;
needNlFlush = 1;
}
PreserveChannelBuffer(bufPtr);
dst = InsertPoint(bufPtr);
dstLen = SpaceLeft(bufPtr);
if (srcLimit < 0) {
srcLimit = strlen(src);
}
if (srcLimit > dstLen) {
srcLimit = dstLen;
}
memcpy(dst, src, (size_t) srcLimit);
bufPtr->nextAdded += srcLimit;
src += srcLimit;
srcLen -= srcLimit;
total += srcLimit;
dst += srcLimit;
dstLen -= srcLimit;
if (src == nextNewLine && dstLen > 0) {
static char crln[3] = "\r\n";
char *nl = NULL;
int nlLen = 0;
switch (statePtr->outputTranslation) {
case TCL_TRANSLATE_LF:
nl = crln + 1;
nlLen = 1;
break;
case TCL_TRANSLATE_CR:
nl = crln;
nlLen = 1;
break;
case TCL_TRANSLATE_CRLF:
nl = crln;
nlLen = 2;
break;
default:
Tcl_Panic("unknown output translation requested");
break;
}
memcpy(dst, nl, (size_t) nlLen);
bufPtr->nextAdded += nlLen;
src++;
srcLen--;
total += nlLen;
dst += nlLen;
dstLen -= nlLen;
nextNewLine = memchr(src, '\n', srcLen);
needNlFlush = 1;
}
if (IsBufferOverflowing(bufPtr)) {
/* Can only happend when \r\n straddles buffers */
saved = 1;
bufPtr->nextAdded = bufPtr->bufLength;
}
if (IsBufferFull(bufPtr)) {
if (FlushChannel(NULL, chanPtr, 0) != 0) {
ReleaseChannelBuffer(bufPtr);
return -1;
}
/* TODO: ought to add bytes actually flushed */
flushed += statePtr->bufSize;
needNlFlush = 0;
}
ReleaseChannelBuffer(bufPtr);
}
if ((flushed < total) && (GotFlag(statePtr, CHANNEL_UNBUFFERED) ||
(needNlFlush && GotFlag(statePtr, CHANNEL_LINEBUFFERED)))) {
if (FlushChannel(NULL, chanPtr, 0) != 0) {
return -1;
}
}
return total;
}
/*
*---------------------------------------------------------------------------
@@ -7716,7 +7840,7 @@ Tcl_NotifyChannel(
if ((chPtr->mask & mask) != 0) {
nh.nextHandlerPtr = chPtr->nextPtr;
(*(chPtr->proc))(chPtr->clientData, mask);
(*(chPtr->proc))(chPtr->clientData, chPtr->mask & mask);
chPtr = nh.nextHandlerPtr;
} else {
chPtr = chPtr->nextPtr;
+4 -1
View File
@@ -4924,7 +4924,10 @@ test io-36.1 {Tcl_InputBlocked on nonblocking pipe} {stdio openpipe} {
test io-36.1.1 {Tcl_InputBlocked on nonblocking binary pipe} {stdio openpipe} {
set f1 [open "|[list [interpreter]]" r+]
chan configure $f1 -encoding binary -translation lf -eofchar {}
puts $f1 {puts hello_from_pipe}
puts $f1 {
chan configure stdout -encoding binary -translation lf -eofchar {}
puts hello_from_pipe
}
flush $f1
gets $f1
fconfigure $f1 -blocking off -buffering full
+18
View File
@@ -30,4 +30,22 @@
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
</application>
</compatibility>
<asmv3:application>
<asmv3:windowsSettings
xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="@MACHINE@"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>