summaryrefslogtreecommitdiffstats
path: root/generic/tclIO.c
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 /generic/tclIO.c
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.
Diffstat (limited to 'generic/tclIO.c')
-rw-r--r--generic/tclIO.c59
1 files changed, 53 insertions, 6 deletions
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);
}
}