summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tclIO.c44
-rw-r--r--generic/tclIO.h2
-rw-r--r--tests/io.test97
-rw-r--r--tests/ioCmd.test12
-rw-r--r--tests/socket.test2
-rw-r--r--tests/zlib.test4
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"