summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpooryorick <com.digitalsmarties@pooryorick.com>2023-02-04 14:10:40 (GMT)
committerpooryorick <com.digitalsmarties@pooryorick.com>2023-02-04 14:10:40 (GMT)
commit597d3b9e7bae377b0d1e04270c733542cd3b983c (patch)
treeb56554771285557c8c2c82bda1ec77a845f9aba1
parentde0a637d7c24faa768c266bacda17bf6ac48171d (diff)
parentf238eb1dbc93130d15f8b4e7dd32602c1870794a (diff)
downloadtcl-597d3b9e7bae377b0d1e04270c733542cd3b983c.zip
tcl-597d3b9e7bae377b0d1e04270c733542cd3b983c.tar.gz
tcl-597d3b9e7bae377b0d1e04270c733542cd3b983c.tar.bz2
Fix for [b8f575aa2398b0e4] and [154ed7ce564a7b4c], double-[read]/[gets]
problem. Partial-read functionality commented out.
-rw-r--r--generic/tclEncoding.c4
-rw-r--r--generic/tclIO.c59
-rw-r--r--generic/tclIOCmd.c25
-rw-r--r--tests/io.test472
4 files changed, 461 insertions, 99 deletions
diff --git a/generic/tclEncoding.c b/generic/tclEncoding.c
index 288b07c..357d04a 100644
--- a/generic/tclEncoding.c
+++ b/generic/tclEncoding.c
@@ -2387,7 +2387,9 @@ UtfToUtfProc(
*dst++ = *src++;
} else if ((UCHAR(*src) == 0xC0) && (src + 1 < srcEnd)
- && (UCHAR(src[1]) == 0x80) && (!(flags & TCL_ENCODING_MODIFIED) || ((flags & TCL_ENCODING_STRICT) == TCL_ENCODING_STRICT) || (flags & ENCODING_FAILINDEX))) {
+ && (UCHAR(src[1]) == 0x80) && (!(flags & TCL_ENCODING_MODIFIED)
+ || ((flags & TCL_ENCODING_STRICT) == TCL_ENCODING_STRICT)
+ || (flags & ENCODING_FAILINDEX))) {
/*
* If in input mode, and -strict or -failindex is specified: This is an error.
*/
diff --git a/generic/tclIO.c b/generic/tclIO.c
index fed469c..a3d8c75 100644
--- a/generic/tclIO.c
+++ b/generic/tclIO.c
@@ -4656,6 +4656,7 @@ Tcl_GetsObj(
/* State info for channel */
ChannelBuffer *bufPtr;
int inEofChar, skip, copiedTotal, oldFlags, oldRemoved;
+ int reportError = 0;
int oldLength;
Tcl_Encoding encoding;
char *dst, *dstEnd, *eol, *eof;
@@ -4664,6 +4665,7 @@ Tcl_GetsObj(
if (GotFlag(statePtr, CHANNEL_ENCODING_ERROR)) {
UpdateInterest(chanPtr);
Tcl_SetErrno(EILSEQ);
+ ResetFlag(statePtr, CHANNEL_ENCODING_ERROR);
return TCL_INDEX_NONE;
}
@@ -4938,6 +4940,19 @@ Tcl_GetsObj(
goto done;
}
goto gotEOL;
+ } else if (gs.bytesWrote == 0
+ && GotFlag(statePtr, CHANNEL_ENCODING_ERROR)) {
+ /* Set eol to the position that caused the encoding error, and then
+ * coninue 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
+ * succesfully decoded, allowing further processing at exactly that
+ * point, if desired.
+ */
+ eol = dstEnd;
+ reportError = 1;
+ goto gotEOL;
}
dst = dstEnd;
}
@@ -4981,7 +4996,16 @@ Tcl_GetsObj(
Tcl_SetObjLength(objPtr, eol - objPtr->bytes);
CommonGetsCleanup(chanPtr);
ResetFlag(statePtr, CHANNEL_BLOCKED);
- copiedTotal = gs.totalChars + gs.charsWrote - skip;
+ if (reportError) {
+ ResetFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR|CHANNEL_ENCODING_ERROR);
+ /* reset CHANNEL_ENCODING_ERROR to afford a chance to reconfigure
+ * the channel and try again
+ */
+ Tcl_SetErrno(EILSEQ);
+ copiedTotal = -1;
+ } else {
+ copiedTotal = gs.totalChars + gs.charsWrote - skip;
+ }
goto done;
/*
@@ -6024,8 +6048,9 @@ DoReadChars(
}
if (GotFlag(statePtr, CHANNEL_ENCODING_ERROR)) {
- /* TODO: We don't need this call? */
+ /* TODO: UpdateInterest not needed here? */
UpdateInterest(chanPtr);
+
Tcl_SetErrno(EILSEQ);
return -1;
}
@@ -6041,7 +6066,7 @@ DoReadChars(
assert(statePtr->inputEncodingFlags & TCL_ENCODING_END);
assert(!GotFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR));
- /* TODO: We don't need this call? */
+ /* TODO: UpdateInterest not needed here? */
UpdateInterest(chanPtr);
return 0;
}
@@ -6055,7 +6080,7 @@ DoReadChars(
}
ResetFlag(statePtr, CHANNEL_BLOCKED|CHANNEL_EOF);
statePtr->inputEncodingFlags &= ~TCL_ENCODING_END;
- /* TODO: We don't need this call? */
+ /* TODO: UpdateInterest not needed here? */
UpdateInterest(chanPtr);
return 0;
}
@@ -6086,7 +6111,7 @@ DoReadChars(
}
/*
- * If the current buffer is empty recycle it.
+ * Recycle current buffer if empty.
*/
bufPtr = statePtr->inQueueHead;
@@ -6099,6 +6124,24 @@ DoReadChars(
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)) {
+ /* Channel is synchronous. Return an error so that callers
+ * like [read] can return an error.
+ */
+ Tcl_SetErrno(EILSEQ);
+ copied = -1;
+ goto finish;
+ }
}
if (copiedNow < 0) {
@@ -6127,6 +6170,7 @@ 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
@@ -6805,11 +6849,14 @@ 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);
+ ResetFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR|CHANNEL_ENCODING_ERROR);
}
}
diff --git a/generic/tclIOCmd.c b/generic/tclIOCmd.c
index e8a534f..507e06c 100644
--- a/generic/tclIOCmd.c
+++ b/generic/tclIOCmd.c
@@ -296,6 +296,9 @@ Tcl_GetsObjCmd(
int lineLen; /* Length of line just read. */
int mode; /* Mode in which channel is opened. */
Tcl_Obj *linePtr, *chanObjPtr;
+ /*
+ Tcl_Obj *resultDictPtr, *returnOptsPtr;
+ */
int code = TCL_OK;
if ((objc != 2) && (objc != 3)) {
@@ -318,7 +321,6 @@ Tcl_GetsObjCmd(
lineLen = Tcl_GetsObj(chan, linePtr);
if (lineLen < 0) {
if (!Tcl_Eof(chan) && !Tcl_InputBlocked(chan)) {
- Tcl_DecrRefCount(linePtr);
/*
* TIP #219.
@@ -332,6 +334,15 @@ Tcl_GetsObjCmd(
"error reading \"%s\": %s",
TclGetString(chanObjPtr), Tcl_PosixError(interp)));
}
+ /*
+ resultDictPtr = Tcl_NewDictObj();
+ Tcl_DictObjPut(NULL, resultDictPtr, Tcl_NewStringObj("read", -1)
+ , linePtr);
+ returnOptsPtr = Tcl_NewDictObj();
+ Tcl_DictObjPut(NULL, returnOptsPtr, Tcl_NewStringObj("-result", -1)
+ , resultDictPtr);
+ Tcl_SetReturnOptions(interp, returnOptsPtr);
+ */
code = TCL_ERROR;
goto done;
}
@@ -382,6 +393,9 @@ Tcl_ReadObjCmd(
int charactersRead; /* How many characters were read? */
int mode; /* Mode in which channel is opened. */
Tcl_Obj *resultPtr, *chanObjPtr;
+ /*
+ Tcl_Obj *resultDictPtr, *returnOptsPtr;
+ */
if ((objc != 2) && (objc != 3)) {
Interp *iPtr;
@@ -470,8 +484,17 @@ Tcl_ReadObjCmd(
"error reading \"%s\": %s",
TclGetString(chanObjPtr), Tcl_PosixError(interp)));
}
+ /*
+ resultDictPtr = Tcl_NewDictObj();
+ Tcl_DictObjPut(NULL, resultDictPtr, Tcl_NewStringObj("read", -1)
+ , resultPtr);
+ returnOptsPtr = Tcl_NewDictObj();
+ Tcl_DictObjPut(NULL, returnOptsPtr, Tcl_NewStringObj("-result", -1)
+ , resultDictPtr);
TclChannelRelease(chan);
Tcl_DecrRefCount(resultPtr);
+ Tcl_SetReturnOptions(interp, returnOptsPtr);
+ */
return TCL_ERROR;
}
diff --git a/tests/io.test b/tests/io.test
index 2708906..75255ca 100644
--- a/tests/io.test
+++ b/tests/io.test
@@ -1547,19 +1547,53 @@ test io-12.8 {ReadChars: multibyte chars split} {
close $f
scan [string index $in end] %c
} 160
-test io-12.9 {ReadChars: multibyte chars split} -body {
- set f [open $path(test1) w]
- fconfigure $f -translation binary
- puts -nonewline $f [string repeat a 9]\xC2
- close $f
- set f [open $path(test1)]
- fconfigure $f -encoding utf-8 -buffersize 10
- set in [read $f]
- close $f
- scan [string index $in end] %c
-} -cleanup {
- catch {close $f}
-} -result 194
+
+
+apply [list {} {
+ set template {
+ test io-12.9.@variant@ {ReadChars: multibyte chars split, default (strict)} -body {
+ set res {}
+ set f [open $path(test1) w]
+ fconfigure $f -translation binary
+ puts -nonewline $f [string repeat a 9]\xC2
+ close $f
+ set f [open $path(test1)]
+ fconfigure $f -encoding utf-8 @strict@ -buffersize 10
+ set status [catch {read $f} cres copts]
+ #set in [dict get $copts -result]
+ #lappend res $in
+ lappend res $status $cres
+ set status [catch {read $f} cres copts]
+ #set in [dict get $copts -result]
+ #lappend res $in
+ lappend res $status $cres
+ set res
+ } -cleanup {
+ catch {close $f}
+ } -match glob\
+ }
+
+ #append template {\
+ # -result {{read aaaaaaaaa} 1\
+ # {error reading "*": illegal byte sequence}\
+ # {read {}} 1 {error reading "*": illegal byte sequence}}
+ #}
+
+ append template {\
+ -result {1\
+ {error reading "*": illegal byte sequence}\
+ 1 {error reading "*": illegal byte sequence}}
+ }
+
+ # strict encoding may be the default in Tcl 9, but in 8 it is not
+ foreach variant {encodingstrict} strict {{-strictencoding 1}} {
+ set script [string map [
+ list @variant@ $variant @strict@ $strict] $template]
+ uplevel 1 $script
+ }
+} [namespace current]]
+
+
test io-12.10 {ReadChars: multibyte chars split} -body {
set f [open $path(test1) w]
fconfigure $f -translation binary
@@ -9046,31 +9080,94 @@ test io-75.5 {invalid utf-8 encoding read is ignored (-nocomplainencoding 1)} -s
removeFile io-75.5
} -result 4181
-test io-75.6 {invalid utf-8 encoding read is not ignored (-strictencoding 1)} -setup {
- set fn [makeFile {} io-75.6]
- set f [open $fn w+]
- fconfigure $f -encoding binary
- # \x81 is invalid in utf-8
- puts -nonewline $f A\x81
- flush $f
- seek $f 0
- fconfigure $f -encoding utf-8 -buffering none -eofchar "" -translation lf -strictencoding 1
-} -body {
- set d [read $f]
- binary scan $d H* hd
- lappend hd [catch {read $f} msg]
- close $f
- lappend hd $msg
-} -cleanup {
- removeFile io-75.6
-} -match glob -result {41 1 {error reading "*": illegal byte sequence}}
-test io-75.7 {invalid utf-8 encoding eof handling (-strictencoding 1)} -setup {
- set fn [makeFile {} io-75.7]
+apply [list {} {
+
+
+ set test {
+ test io-75.6 {invalid utf-8 encoding read is not ignored (-strictencoding 1)} -setup {
+ set hd {}
+ set fn [makeFile {} io-75.6]
+ set f [open $fn w+]
+ fconfigure $f -encoding binary
+ # \x81 is invalid in utf-8
+ puts -nonewline $f A\x81
+ flush $f
+ seek $f 0
+ fconfigure $f -encoding utf-8 -buffering none -eofchar "" -translation lf -strictencoding 1
+ } -body {
+ set status [catch {read $f} cres copts]
+ #set d [dict get $copts -result read]
+ #binary scan $d H* hd
+ lappend hd $status $cres
+ } -cleanup {
+ close $f
+ removeFile io-75.6
+ } -match glob\
+ }
+
+ #append test {\
+ # -result {41 1 {error reading "*": illegal byte sequence}}
+ #}
+
+ append test {\
+ -result {1 {error reading "*": illegal byte sequence}}
+ }
+
+ uplevel 1 $test
+
+ set test {
+ test io-75.7 {invalid utf-8 encoding eof handling (-strictencoding 1)} -setup {
+ set hd {}
+ set fn [makeFile {} io-75.7]
+ set f [open $fn w+]
+ fconfigure $f -encoding binary
+ # \xA1 is invalid in utf-8. -eofchar is not detected, because it comes later.
+ puts -nonewline $f A\xA1\x1A
+ flush $f
+ seek $f 0
+ fconfigure $f -encoding utf-8 -buffering none -eofchar \x1A -translation lf -strictencoding 1
+ } -body {
+ set status [catch {read $f} cres copts]
+ #set d [dict get $copts -result read]
+ #binary scan $d H* hd
+ lappend hd [eof $f]
+ lappend hd $status
+ lappend hd $cres
+ fconfigure $f -encoding iso8859-1
+ lappend hd [read $f];# We changed encoding, so now we can read the \xA1
+ close $f
+ set hd
+ } -cleanup {
+ removeFile io-75.7
+ } -match glob\
+ }
+
+ #append test {\
+ # -result {41 0 1 {error reading "*": illegal byte sequence} ¡}
+ #}
+
+ append test {\
+ -result {0 1 {error reading "*": illegal byte sequence} ¡}
+ }
+
+ uplevel 1 $test
+
+
+} [namespace current]]
+
+
+
+test io-75.8.incomplete {
+ incomplete uft-8 char after eof char is not an error (-strictencoding 1)
+} -setup {
+ set hd {}
+ set fn [makeFile {} io-75.8]
set f [open $fn w+]
fconfigure $f -encoding binary
- # \xA1 is invalid in utf-8. -eofchar is not detected, because it comes later.
- puts -nonewline $f A\xA1\x1A
+ # \x81 is invalid and also incomplete utf-8 data, but because the eof
+ # character \x1A appears first, it's not an error.
+ puts -nonewline $f A\x1A\x81
flush $f
seek $f 0
fconfigure $f -encoding utf-8 -buffering none -eofchar \x1A -translation lf -strictencoding 1
@@ -9078,36 +9175,41 @@ test io-75.7 {invalid utf-8 encoding eof handling (-strictencoding 1)} -setup {
set d [read $f]
binary scan $d H* hd
lappend hd [eof $f]
- lappend hd [catch {read $f} msg]
- lappend hd $msg
- fconfigure $f -encoding iso8859-1
- lappend hd [read $f];# We changed encoding, so now we can read the \xA1
+ # there should be no error on additional reads
+ lappend hd [read $f]
close $f
set hd
} -cleanup {
- removeFile io-75.7
-} -match glob -result {41 0 1 {error reading "*": illegal byte sequence} ¡}
+ removeFile io-75.8
+} -result {41 1 {}}
-test io-75.8 {invalid utf-8 encoding eof handling (-strictencoding 1)} -setup {
+
+test io-75.8.invalid {invalid utf-8 after eof char is not an error (-strictencoding 1)} -setup {
+ set res {}
set fn [makeFile {} io-75.8]
set f [open $fn w+]
fconfigure $f -encoding binary
- # \x81 is invalid in utf-8, but since \x1A comes first, -eofchar takes precedence.
- puts -nonewline $f A\x1A\x81
+ # \xc0\x80 is invalid utf-8 data, but because the eof character \x1A
+ # appears first, it's not an error.
+ puts -nonewline $f A\x1a\xc0\x80
flush $f
seek $f 0
fconfigure $f -encoding utf-8 -buffering none -eofchar \x1A -translation lf -strictencoding 1
} -body {
set d [read $f]
- binary scan $d H* hd
- lappend hd [eof $f]
- lappend hd [read $f]
+ foreach char [split $d {}] {
+ lappend res [format %x [scan $char %c]]
+ }
+ lappend res [eof $f]
+ # there should be no error on additional reads
+ lappend res [read $f]
close $f
- set hd
+ set res
} -cleanup {
removeFile io-75.8
} -result {41 1 {}}
+
test io-75.9 {unrepresentable character write passes and is replaced by ?} -setup {
set fn [makeFile {} io-75.9]
set f [open $fn w+]
@@ -9122,9 +9224,7 @@ test io-75.9 {unrepresentable character write passes and is replaced by ?} -setu
removeFile io-75.9
} -match glob -result [list {A} {error writing "*": illegal byte sequence}]
-# Incomplete sequence test.
-# This error may IMHO only be detected with the close.
-# But the read already returns the incomplete sequence.
+
test io-75.10 {incomplete multibyte encoding read is ignored} -setup {
set fn [makeFile {} io-75.10]
set f [open $fn w+]
@@ -9132,7 +9232,7 @@ test io-75.10 {incomplete multibyte encoding read is ignored} -setup {
puts -nonewline $f A\xC0
flush $f
seek $f 0
- fconfigure $f -encoding utf-8 -buffering none
+ fconfigure $f -encoding utf-8 -strictencoding 0 -buffering none
} -body {
set d [read $f]
close $f
@@ -9141,39 +9241,135 @@ test io-75.10 {incomplete multibyte encoding read is ignored} -setup {
} -cleanup {
removeFile io-75.10
} -result 41c0
-# The current result returns the orphan byte as byte.
-# This may be expected due to special utf-8 handling.
-# As utf-8 has a special treatment in multi-byte decoding, also test another
-# one.
-test io-75.11 {shiftjis encoding error read results in raw bytes} -setup {
- set fn [makeFile {} io-75.11]
- 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 -strictencoding 1
-} -body {
- set d [read $f]
- binary scan $d H* hd
- lappend hd [catch {set d [read $f]} msg]
- lappend hd $msg
-} -cleanup {
- close $f
- removeFile io-75.11
-} -match glob -result {41 1 {error reading "*": illegal byte sequence}}
-test io-75.12 {invalid utf-8 encoding read is ignored} -setup {
+apply [list {} {
+
+ set test {
+ test io-75.10_strict {incomplete multibyte encoding read is an error} -setup {
+ set res {}
+ set fn [makeFile {} io-75.10]
+ set f [open $fn w+]
+ fconfigure $f -encoding binary
+ puts -nonewline $f A\xC0
+ flush $f
+ seek $f 0
+ fconfigure $f -encoding utf-8 -strictencoding 1 -buffering none
+ } -body {
+ set status [catch {read $f} cres copts]
+
+ #set d [dict get $copts -result read]
+ #binary scan $d H* hd
+ #lappend res $hd $cres
+ lappend res $cres
+
+ chan configure $f -encoding iso8859-1
+
+ set d [read $f]
+ binary scan $d H* hd
+ lappend res $hd
+ close $f
+ return $res
+ } -cleanup {
+ removeFile io-75.10
+ } -match glob\
+ }
+
+ #append test {\
+ # -result {41 {error reading "*": illegal byte sequence} c0}
+ #}
+
+ append test {\
+ -result {{error reading "*": illegal byte sequence} c0}
+ }
+
+ uplevel 1 $test
+
+
+
+ set test {
+ # As utf-8 has a special treatment in multi-byte decoding, also test another
+ # one.
+ test io-75.11 {shiftjis encoding error read results in raw bytes} -setup {
+ set hd {}
+ set fn [makeFile {} io-75.11]
+ 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 -strictencoding 1
+ } -body {
+ set status [catch {read $f} cres copts]
+ #set d [dict get $copts -result read]
+ #binary scan $d H* hd
+ lappend hd $status
+ lappend hd $cres
+ } -cleanup {
+ close $f
+ removeFile io-75.11
+ } -match glob
+ }
+
+ #append test {\
+ # -result {41 1 {error reading "*": illegal byte sequence}}
+ #}
+
+ append test {\
+ -result {1 {error reading "*": illegal byte sequence}}
+ }
+
+
+ set test {
+ test io-75.12 {invalid utf-8 encoding read is an error} -setup {
+ set hd {}
+ set res {}
+ set fn [makeFile {} io-75.12]
+ set f [open $fn w+]
+ fconfigure $f -encoding binary
+ puts -nonewline $f A\x81
+ flush $f
+ seek $f 0
+ fconfigure $f -encoding utf-8 -buffering none -eofchar {} -translation lf \
+ -strictencoding 1
+ } -body {
+ set status [catch {read $f} cres copts]
+ #set d [dict get $copts -result read]
+ #binary scan $d H* hd
+ #lappend res $hd
+ lappend res $status $cres
+ return $res
+ } -cleanup {
+ catch {close $f}
+ removeFile io-75.12
+ } -match glob\
+ }
+
+ #append test {\
+ # -result {41 1 {error reading "*": illegal byte sequence}}
+ #}
+
+
+ append test {\
+ -result {1 {error reading "*": illegal byte sequence}}
+ }
+
+ uplevel 1 $test
+} [namespace current]]
+
+
+test io-75.12_ignore {invalid utf-8 encoding read is ignored} -setup {
set fn [makeFile {} io-75.12]
set f [open $fn w+]
fconfigure $f -encoding binary
puts -nonewline $f A\x81
flush $f
seek $f 0
- fconfigure $f -encoding utf-8 -buffering none -eofchar "" -translation lf
+ fconfigure $f -encoding utf-8 -buffering none -eofchar {} \
+ -translation lf -strictencoding 0
} -body {
set d [read $f]
close $f
@@ -9182,28 +9378,122 @@ test io-75.12 {invalid utf-8 encoding read is ignored} -setup {
} -cleanup {
removeFile io-75.12
} -result 4181
-test io-75.13 {invalid utf-8 encoding read is not ignored (-strictencoding 1)} -setup {
- set fn [makeFile {} io-75.13]
+
+
+apply [list {} {
+
+ set test {
+ test io-75.13 {invalid utf-8 encoding read is not ignored (-strictencoding 1)} -setup {
+ set hd {}
+ set fn [makeFile {} io-75.13]
+ set f [open $fn w+]
+ fconfigure $f -encoding binary
+ # \x81 is invalid in utf-8
+ puts -nonewline $f A\x81
+ flush $f
+ seek $f 0
+ fconfigure $f -encoding utf-8 -buffering none -eofchar "" \
+ -translation lf -strictencoding 1
+ } -body {
+ set status [catch {read $f} cres copts]
+ #set d [dict get $copts -result read]
+ #binary scan $d H* hd
+ lappend hd $status
+ lappend hd $cres
+ } -cleanup {
+ catch {close $f}
+ removeFile io-75.13
+ } -match glob\
+ }
+
+ #append test {\
+ # -result {41 1 {error reading "*": illegal byte sequence}}
+ #}
+
+ append test {\
+ -result {1 {error reading "*": illegal byte sequence}}
+ }
+
+ uplevel 1 $test
+
+ set test {
+ }
+
+} [namespace current]]
+
+
+test io-75.14 {
+ invalid utf-8 encoding [gets] continues in non-strict mode after error
+} -setup {
+ set res {}
+ set fn [makeFile {} io-75.14]
set f [open $fn w+]
- fconfigure $f -encoding binary
- # \x81 is invalid in utf-8
- puts -nonewline $f "A\x81"
+ fconfigure $f -translation binary
+ # \xc0 is invalid in utf-8
+ puts -nonewline $f a\nb\xc0\nc\n
flush $f
seek $f 0
- fconfigure $f -encoding utf-8 -buffering none -eofchar "" -translation lf -strictencoding 1
+ fconfigure $f -encoding utf-8 -buffering none -eofchar {} -translation lf -strictencoding 1
} -body {
- set d [read $f]
- binary scan $d H* hd
- lappend hd [catch {read $f} msg]
- close $f
- lappend hd $msg
+ lappend res [gets $f]
+ set status [catch {gets $f} cres copts]
+ lappend res $status $cres
+ chan configure $f -strictencoding 0
+ lappend res [gets $f]
+ lappend res [gets $f]
+ close $f
+ return $res
} -cleanup {
- removeFile io-75.13
-} -match glob -result {41 1 {error reading "*": illegal byte sequence}}
+ removeFile io-75.14
+} -match glob -result {a 1 {error reading "*": illegal byte sequence} bÀ c}
-# ### ### ### ######### ######### #########
+apply [list {} {
+ set test {
+ test io-75.15 {invalid utf-8 encoding strict gets should not hang} -setup {
+ set res {}
+ set fn [makeFile {} io-75.15]
+ set chan [open $fn w+]
+ fconfigure $chan -encoding binary
+ # This is not valid UTF-8
+ puts $chan hello\nAB\xc0\x40CD\nEFG
+ close $chan
+ } -body {
+ #Now try to read it with [gets]
+ set chan [open $fn]
+ fconfigure $chan -encoding utf-8 -strictencoding 1
+ lappend res [gets $chan]
+ set status [catch {gets $chan} cres copts]
+ lappend res $status $cres
+ set status [catch {gets $chan} cres copts]
+ lappend res $status $cres
+ #lappend res [dict get $copts -result]
+ chan configur $chan -encoding binary
+ foreach char [split [read $chan 2] {}] {
+ lappend res [format %x [scan $char %c]]
+ }
+ return $res
+ } -cleanup {
+ close $chan
+ removeFile io-75.15
+ } -match glob\
+ }
+
+ #append test {\
+ # -result {hello 1 {error reading "*": illegal byte sequence}\
+ # 1 {error reading "*": illegal byte sequence} {read AB} c0 40}
+ #}
+
+ append test {\
+ -result {hello 1 {error reading "*": illegal byte sequence}\
+ 1 {error reading "*": illegal byte sequence} c0 40}
+ }
+
+ uplevel 1 $test
+
+} [namespace current]]
+
test io-76.0 {channel modes} -setup {
set datafile [makeFile {some characters} dummy]