diff options
-rw-r--r-- | generic/tclIO.c | 44 | ||||
-rw-r--r-- | generic/tclIO.h | 2 | ||||
-rw-r--r-- | tests/io.test | 97 | ||||
-rw-r--r-- | tests/ioCmd.test | 12 | ||||
-rw-r--r-- | tests/socket.test | 2 | ||||
-rw-r--r-- | tests/zlib.test | 4 |
6 files changed, 142 insertions, 19 deletions
diff --git a/generic/tclIO.c b/generic/tclIO.c index 15c348d..af3243a 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -4360,11 +4360,14 @@ Write( } /* - * Transfer encoding strict option to the encoding flags + * Transfer encoding strict/nocomplain option to the encoding flags */ + if (GotFlag(statePtr, CHANNEL_ENCODING_STRICT)) { statePtr->outputEncodingFlags |= TCL_ENCODING_STRICT; + } else if (GotFlag(statePtr, CHANNEL_ENCODING_NOCOMPLAIN)) { + statePtr->outputEncodingFlags |= TCL_ENCODING_NOCOMPLAIN; } /* @@ -4405,7 +4408,7 @@ Write( } dst = InsertPoint(bufPtr); dstLen = SpaceLeft(bufPtr); - + result = Tcl_UtfToExternal(NULL, encoding, src, srcLimit, statePtr->outputEncodingFlags, &statePtr->outputEncodingState, dst, @@ -4685,11 +4688,13 @@ Tcl_GetsObj( } /* - * Transfer encoding strict option to the encoding flags + * Transfer encoding nocomplain/strict option to the encoding flags */ if (GotFlag(statePtr, CHANNEL_ENCODING_STRICT)) { statePtr->inputEncodingFlags |= TCL_ENCODING_STRICT; + } else if (GotFlag(statePtr, CHANNEL_ENCODING_NOCOMPLAIN)) { + statePtr->inputEncodingFlags |= TCL_ENCODING_NOCOMPLAIN; } /* @@ -5451,11 +5456,13 @@ FilterInputBytes( gsPtr->state = statePtr->inputEncodingState; /* - * Transfer encoding strict option to the encoding flags + * Transfer encoding nocomplain/strict option to the encoding flags */ if (GotFlag(statePtr, CHANNEL_ENCODING_STRICT)) { statePtr->inputEncodingFlags |= TCL_ENCODING_STRICT; + } else if (GotFlag(statePtr, CHANNEL_ENCODING_NOCOMPLAIN)) { + statePtr->inputEncodingFlags |= TCL_ENCODING_NOCOMPLAIN; } result = Tcl_ExternalToUtf(NULL, gsPtr->encoding, raw, rawLen, @@ -6232,11 +6239,14 @@ ReadChars( } /* - * Transfer encoding strict option to the encoding flags + * Transfer encoding nocomplain/strict option to the encoding flags */ + if (GotFlag(statePtr, CHANNEL_ENCODING_STRICT)) { statePtr->inputEncodingFlags |= TCL_ENCODING_STRICT; + } else if (GotFlag(statePtr, CHANNEL_ENCODING_NOCOMPLAIN)) { + statePtr->inputEncodingFlags |= TCL_ENCODING_NOCOMPLAIN; } /* @@ -7969,6 +7979,16 @@ Tcl_GetChannelOption( return TCL_OK; } } + if (len == 0 || HaveOpt(1, "-nocomplainencoding")) { + if (len == 0) { + Tcl_DStringAppendElement(dsPtr, "-nocomplainencoding"); + } + Tcl_DStringAppendElement(dsPtr, + (flags & CHANNEL_ENCODING_NOCOMPLAIN) ? "1" : "0"); + if (len > 0) { + return TCL_OK; + } + } if (len == 0 || HaveOpt(1, "-strictencoding")) { if (len == 0) { Tcl_DStringAppendElement(dsPtr, "-strictencoding"); @@ -8242,6 +8262,18 @@ Tcl_SetChannelOption( ResetFlag(statePtr, CHANNEL_EOF|CHANNEL_STICKY_EOF|CHANNEL_BLOCKED); statePtr->inputEncodingFlags &= ~TCL_ENCODING_END; return TCL_OK; + } else if (HaveOpt(1, "-nocomplainencoding")) { + int newMode; + + if (Tcl_GetBoolean(interp, newValue, &newMode) == TCL_ERROR) { + return TCL_ERROR; + } + if (newMode) { + SetFlag(statePtr, CHANNEL_ENCODING_NOCOMPLAIN); + } else { + ResetFlag(statePtr, CHANNEL_ENCODING_NOCOMPLAIN); + } + return TCL_OK; } else if (HaveOpt(1, "-strictencoding")) { int newMode; @@ -8250,6 +8282,8 @@ Tcl_SetChannelOption( } if (newMode) { SetFlag(statePtr, CHANNEL_ENCODING_STRICT); + } else { + ResetFlag(statePtr, CHANNEL_ENCODING_STRICT); } return TCL_OK; } else if (HaveOpt(1, "-translation")) { diff --git a/generic/tclIO.h b/generic/tclIO.h index 7f19108..a4cc602 100644 --- a/generic/tclIO.h +++ b/generic/tclIO.h @@ -273,6 +273,8 @@ typedef struct ChannelState { * changes. */ #define CHANNEL_RAW_MODE (1<<16) /* When set, notes that the Raw API is * being used. */ +#define CHANNEL_ENCODING_NOCOMPLAIN (1<<17) /* set if option + * -nocomplainencoding is set to 1 */ #define CHANNEL_ENCODING_STRICT (1<<18) /* set if option * -strictencoding is set to 1 */ #define CHANNEL_INCLOSE (1<<19) /* Channel is currently being closed. diff --git a/tests/io.test b/tests/io.test index 44be164..4fd1a6b 100644 --- a/tests/io.test +++ b/tests/io.test @@ -8952,11 +8952,98 @@ test io-74.1 {[104f2885bb] improper cache validity check} -setup { removeFile io-74.1 } -returnCodes error -match glob -result {can not find channel named "*"} -# The following tests 75.1 to 75.5 exercise strict or tolerant channel -# encoding. -# They are left as a place-holder here. If TIP633 is voted, they will -# come back. -# Exercise strct channel encoding +test io-75.1 {multibyte encoding error read results in raw bytes (-nocomplainencoding 1)} -setup { + set fn [makeFile {} io-75.1] + set f [open $fn w+] + fconfigure $f -encoding binary + # In UTF-8, a byte 0xCx starts a multibyte sequence and must be followed + # by a byte > 0x7F. This is violated to get an invalid sequence. + puts -nonewline $f "A\xC0\x40" + flush $f + seek $f 0 + fconfigure $f -encoding utf-8 -nocomplainencoding 1 -buffering none +} -body { + set d [read $f] + binary scan $d H* hd + set hd +} -cleanup { + close $f + removeFile io-75.1 +} -result "41c040" + +test io-75.2 {unrepresentable character write passes and is replaced by ? (-nocomplainencoding 1)} -setup { + set fn [makeFile {} io-75.2] + set f [open $fn w+] + fconfigure $f -encoding iso8859-1 -nocomplainencoding 1 +} -body { + puts -nonewline $f "A\u2022" + flush $f + seek $f 0 + read $f +} -cleanup { + close $f + removeFile io-75.2 +} -result "A?" + +# Incomplete sequence test. +# This error may IMHO only be detected with the close. +# But the read already returns the incomplete sequence. +test io-75.3 {incomplete multibyte encoding read is ignored (-nocomplainencoding 1)} -setup { + set fn [makeFile {} io-75.3] + set f [open $fn w+] + fconfigure $f -encoding binary + puts -nonewline $f "A\xC0" + flush $f + seek $f 0 + fconfigure $f -encoding utf-8 -buffering none -nocomplainencoding 1 +} -body { + set d [read $f] + close $f + binary scan $d H* hd + set hd +} -cleanup { + removeFile io-75.3 +} -result "41c0" + +# As utf-8 has a special treatment in multi-byte decoding, also test another +# one. +test io-75.4 {shiftjis encoding error read results in raw bytes (-nocomplainencoding 1)} -setup { + set fn [makeFile {} io-75.4] + set f [open $fn w+] + fconfigure $f -encoding binary + # In shiftjis, \x81 starts a two-byte sequence. + # But 2nd byte \xFF is not allowed + puts -nonewline $f "A\x81\xFFA" + flush $f + seek $f 0 + fconfigure $f -encoding shiftjis -buffering none -eofchar "" -translation lf -nocomplainencoding 1 +} -body { + set d [read $f] + binary scan $d H* hd + set hd +} -cleanup { + close $f + removeFile io-75.4 +} -result "4181ff41" + +test io-75.5 {incomplete shiftjis encoding read is ignored (-nocomplainencoding 1)} -setup { + set fn [makeFile {} io-75.5] + set f [open $fn w+] + fconfigure $f -encoding binary + # \x81 announces a two byte sequence. + puts -nonewline $f "A\x81" + flush $f + seek $f 0 + fconfigure $f -encoding utf-8 -buffering none -eofchar "" -translation lf -nocomplainencoding 1 +} -body { + set d [read $f] + close $f + binary scan $d H* hd + set hd +} -cleanup { + removeFile io-75.5 +} -result "4181" + test io-75.6 {multibyte encoding error read results in raw bytes} -setup { set fn [makeFile {} io-75.6] set f [open $fn w+] diff --git a/tests/ioCmd.test b/tests/ioCmd.test index 4b61fff..409d4ec 100644 --- a/tests/ioCmd.test +++ b/tests/ioCmd.test @@ -245,7 +245,7 @@ test iocmd-8.7 {fconfigure command} -setup { fconfigure $f1 } -cleanup { catch {close $f1} -} -result {-blocking 1 -buffering full -buffersize 4096 -encoding utf-16 -eofchar {} -strictencoding 0 -translation lf} +} -result {-blocking 1 -buffering full -buffersize 4096 -encoding utf-16 -eofchar {} -nocomplainencoding 0 -strictencoding 0 -translation lf} test iocmd-8.8 {fconfigure command} -setup { file delete $path(test1) set x {} @@ -257,7 +257,7 @@ test iocmd-8.8 {fconfigure command} -setup { lappend x [fconfigure $f1] } -cleanup { catch {close $f1} -} -result {line {-blocking 1 -buffering line -buffersize 3030 -encoding utf-16 -eofchar {} -strictencoding 0 -translation lf}} +} -result {line {-blocking 1 -buffering line -buffersize 3030 -encoding utf-16 -eofchar {} -nocomplainencoding 0 -strictencoding 0 -translation lf}} test iocmd-8.9 {fconfigure command} -setup { file delete $path(test1) } -body { @@ -267,7 +267,7 @@ test iocmd-8.9 {fconfigure command} -setup { fconfigure $f1 } -cleanup { catch {close $f1} -} -result {-blocking 1 -buffering none -buffersize 4040 -encoding binary -eofchar {} -strictencoding 0 -translation lf} +} -result {-blocking 1 -buffering none -buffersize 4040 -encoding binary -eofchar {} -nocomplainencoding 0 -strictencoding 0 -translation lf} test iocmd-8.10 {fconfigure command} -returnCodes error -body { fconfigure a b } -result {can not find channel named "a"} @@ -1363,7 +1363,7 @@ test iocmd-25.1 {chan configure, cgetall, standard options} -match glob -body { close $c rename foo {} set res -} -result {{-blocking 1 -buffering full -buffersize 4096 -encoding * -eofchar {{} {}} -strictencoding 0 -translation {auto *}}} +} -result {{-blocking 1 -buffering full -buffersize 4096 -encoding * -eofchar {{} {}} -nocomplainencoding 0 -strictencoding 0 -translation {auto *}}} test iocmd-25.2 {chan configure, cgetall, no options} -match glob -body { set res {} proc foo {args} {oninit cget cgetall; onfinal; track; return ""} @@ -1372,7 +1372,7 @@ test iocmd-25.2 {chan configure, cgetall, no options} -match glob -body { close $c rename foo {} set res -} -result {{cgetall rc*} {-blocking 1 -buffering full -buffersize 4096 -encoding * -eofchar {{} {}} -strictencoding 0 -translation {auto *}}} +} -result {{cgetall rc*} {-blocking 1 -buffering full -buffersize 4096 -encoding * -eofchar {{} {}} -nocomplainencoding 0 -strictencoding 0 -translation {auto *}}} test iocmd-25.3 {chan configure, cgetall, regular result} -match glob -body { set res {} proc foo {args} { @@ -1384,7 +1384,7 @@ test iocmd-25.3 {chan configure, cgetall, regular result} -match glob -body { close $c rename foo {} set res -} -result {{cgetall rc*} {-blocking 1 -buffering full -buffersize 4096 -encoding * -eofchar {{} {}} -strictencoding 0 -translation {auto *} -bar foo -snarf x}} +} -result {{cgetall rc*} {-blocking 1 -buffering full -buffersize 4096 -encoding * -eofchar {{} {}} -nocomplainencoding 0 -strictencoding 0 -translation {auto *} -bar foo -snarf x}} test iocmd-25.4 {chan configure, cgetall, bad result, list of uneven length} -match glob -body { set res {} proc foo {args} { diff --git a/tests/socket.test b/tests/socket.test index c354f46..7250cb8 100644 --- a/tests/socket.test +++ b/tests/socket.test @@ -1071,7 +1071,7 @@ test socket_$af-7.3 {testing socket specific options} -constraints [list socket close $s update llength $l -} -result 16 +} -result 18 test socket_$af-7.4 {testing socket specific options} -constraints [list socket supported_$af] -setup { set timer [after 10000 "set x timed_out"] set l "" diff --git a/tests/zlib.test b/tests/zlib.test index a1c7aa4..1c9514d 100644 --- a/tests/zlib.test +++ b/tests/zlib.test @@ -292,7 +292,7 @@ test zlib-8.6 {transformation and fconfigure} -setup { } -cleanup { catch {close $fd} removeFile $file -} -result {{-blocking 1 -buffering full -buffersize 4096 -encoding binary -eofchar {} -strictencoding 0 -translation lf} {-blocking 1 -buffering full -buffersize 4096 -encoding binary -eofchar {} -strictencoding 0 -translation lf -checksum 1 -dictionary {}} {-blocking 1 -buffering full -buffersize 4096 -encoding binary -eofchar {} -strictencoding 0 -translation lf}} +} -result {{-blocking 1 -buffering full -buffersize 4096 -encoding binary -eofchar {} -nocomplainencoding 0 -strictencoding 0 -translation lf} {-blocking 1 -buffering full -buffersize 4096 -encoding binary -eofchar {} -nocomplainencoding 0 -strictencoding 0 -translation lf -checksum 1 -dictionary {}} {-blocking 1 -buffering full -buffersize 4096 -encoding binary -eofchar {} -nocomplainencoding 0 -strictencoding 0 -translation lf}} test zlib-8.7 {transformation and fconfigure} -setup { set file [makeFile {} test.gz] set fd [open $file wb] @@ -302,7 +302,7 @@ test zlib-8.7 {transformation and fconfigure} -setup { } -cleanup { catch {close $fd} removeFile $file -} -result {{-blocking 1 -buffering full -buffersize 4096 -encoding binary -eofchar {} -strictencoding 0 -translation lf} {-blocking 1 -buffering full -buffersize 4096 -encoding binary -eofchar {} -strictencoding 0 -translation lf -checksum 0} {-blocking 1 -buffering full -buffersize 4096 -encoding binary -eofchar {} -strictencoding 0 -translation lf}} +} -result {{-blocking 1 -buffering full -buffersize 4096 -encoding binary -eofchar {} -nocomplainencoding 0 -strictencoding 0 -translation lf} {-blocking 1 -buffering full -buffersize 4096 -encoding binary -eofchar {} -nocomplainencoding 0 -strictencoding 0 -translation lf -checksum 0} {-blocking 1 -buffering full -buffersize 4096 -encoding binary -eofchar {} -nocomplainencoding 0 -strictencoding 0 -translation lf}} # Input is headers from fetching SPDY draft # Dictionary is that which is proposed _in_ SPDY draft set spdyHeaders "HTTP/1.0 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nX-Robots-Tag: noarchive\r\nLast-Modified: Tue, 05 Jun 2012 02:43:25 GMT\r\nETag: \"1338864205129|#public|0|en|||0\"\r\nExpires: Tue, 05 Jun 2012 16:17:11 GMT\r\nDate: Tue, 05 Jun 2012 16:17:06 GMT\r\nCache-Control: public, max-age=5\r\nX-Content-Type-Options: nosniff\r\nX-XSS-Protection: 1; mode=block\r\nServer: GSE\r\n" |