diff options
author | pooryorick <com.digitalsmarties@pooryorick.com> | 2023-02-04 14:10:40 (GMT) |
---|---|---|
committer | pooryorick <com.digitalsmarties@pooryorick.com> | 2023-02-04 14:10:40 (GMT) |
commit | 597d3b9e7bae377b0d1e04270c733542cd3b983c (patch) | |
tree | b56554771285557c8c2c82bda1ec77a845f9aba1 | |
parent | de0a637d7c24faa768c266bacda17bf6ac48171d (diff) | |
parent | f238eb1dbc93130d15f8b4e7dd32602c1870794a (diff) | |
download | tcl-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.c | 4 | ||||
-rw-r--r-- | generic/tclIO.c | 59 | ||||
-rw-r--r-- | generic/tclIOCmd.c | 25 | ||||
-rw-r--r-- | tests/io.test | 472 |
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] |