summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tclIO.c211
1 files changed, 17 insertions, 194 deletions
diff --git a/generic/tclIO.c b/generic/tclIO.c
index 7203739..c7c11e7 100644
--- a/generic/tclIO.c
+++ b/generic/tclIO.c
@@ -3752,46 +3752,30 @@ WriteChars(
{
ChannelState *statePtr = chanPtr->state;
/* State info for channel */
- ChannelBuffer *bufPtr;
- char *dst, *stage;
- int saved, savedLF, sawLF, total, dstLen, stageMax, dstWrote;
- int stageLen, toWrite, stageRead, endEncoding, result;
- int consumedSomething, translate, flushed, needNlFlush;
- Tcl_Encoding encoding;
- char safe[BUFFER_PADDING];
char *nextNewLine = NULL;
+ int endEncoding, saved = 0, total = 0, flushed = 0, needNlFlush = 0;
+ Tcl_Encoding encoding = statePtr->encoding;
if (srcLen) {
WillWrite(chanPtr);
}
- flushed = 0;
- total = 0;
- sawLF = 0;
- savedLF = 0;
- saved = 0;
- needNlFlush = 0;
- encoding = statePtr->encoding;
-
/*
* Write the terminated escape sequence even if srcLen is 0.
*/
endEncoding = ((statePtr->outputEncodingFlags & TCL_ENCODING_END) != 0);
- translate = (statePtr->flags & CHANNEL_LINEBUFFERED)
- || (statePtr->outputTranslation != TCL_TRANSLATE_LF);
-
-#if 1
- if (translate) {
+ if ((statePtr->flags & CHANNEL_LINEBUFFERED)
+ || (statePtr->outputTranslation != TCL_TRANSLATE_LF)) {
nextNewLine = memchr(src, '\n', srcLen);
}
- consumedSomething = 1;
- while (consumedSomething && (srcLen + saved + endEncoding > 0)) {
- int srcRead;
- int srcLimit = srcLen;
- consumedSomething = 0;
+ while (srcLen + saved + endEncoding > 0) {
+ ChannelBuffer *bufPtr;
+ char *dst, safe[BUFFER_PADDING];
+ int result, srcRead, dstLen, dstWrote, srcLimit = srcLen;
+
if (nextNewLine) {
srcLimit = nextNewLine - src;
}
@@ -3820,14 +3804,18 @@ WriteChars(
&statePtr->outputEncodingState, dst,
dstLen + BUFFER_PADDING, &srcRead, &dstWrote, NULL);
+ /* See chan-io-1.[89]. Tcl Bug 506297. */
statePtr->outputEncodingFlags &= ~TCL_ENCODING_START;
- if ((result != 0) && (srcRead + dstWrote == 0)) {
+ if ((result != TCL_OK) && (srcRead + dstWrote == 0)) {
/* We're reading from invalid/incomplete UTF-8 */
+ if (total == 0) {
+ Tcl_SetErrno(EINVAL);
+ return -1;
+ }
break;
}
- consumedSomething = 1;
bufPtr->nextAdded += dstWrote;
src += srcRead;
srcLen -= srcRead;
@@ -3876,6 +3864,7 @@ WriteChars(
nextNewLine = memchr(src, '\n', srcLen);
needNlFlush = 1;
}
+
if (IsBufferOverflowing(bufPtr)) {
/*
* When translating from UTF-8 to external encoding, we
@@ -3890,11 +3879,10 @@ WriteChars(
bufPtr->nextAdded = bufPtr->bufLength;
}
- if ((srcLen + saved == 0) && (result == 0)) {
+ if ((srcLen + saved == 0) && (result == TCL_OK)) {
endEncoding = 0;
}
- /* FLUSH ! */
if (IsBufferFull(bufPtr)) {
if (FlushChannel(NULL, chanPtr, 0) != 0) {
return -1;
@@ -3912,172 +3900,7 @@ WriteChars(
return -1;
}
}
-#else
- /*
- * Loop over all UTF-8 characters in src, storing them in staging buffer
- * with proper EOL translation.
- */
-
- consumedSomething = 1;
- while (consumedSomething && (srcLen + savedLF + endEncoding > 0)) {
- consumedSomething = 0;
-
- if (translate) {
- stage = statePtr->outputStage;
- stageMax = statePtr->bufSize;
- stageLen = stageMax;
-
- toWrite = stageLen;
- if (toWrite > srcLen) {
- toWrite = srcLen;
- }
-
- if (savedLF) {
- /*
- * A '\n' was left over from last call to TranslateOutputEOL()
- * and we need to store it in the staging buffer. If the channel
- * is line-based, we will need to flush the output buffer (after
- * translating the staging buffer).
- */
-
- *stage++ = '\n';
- stageLen--;
- sawLF++;
- }
- if (TranslateOutputEOL(statePtr, stage, src, &stageLen, &toWrite)) {
- sawLF++;
- }
-
- stage -= savedLF;
- stageLen += savedLF;
- savedLF = 0;
-
- if (stageLen > stageMax) {
- savedLF = 1;
- stageLen = stageMax;
- }
- } else {
- stage = (char *) src;
- stageLen = srcLen;
- toWrite = stageLen;
- }
- src += toWrite;
- srcLen -= toWrite;
-
- /*
- * Loop over all UTF-8 characters in staging buffer, converting them
- * to external encoding, storing them in output buffer.
- */
-
- while (stageLen + saved + endEncoding > 0) {
- bufPtr = statePtr->curOutPtr;
- if (bufPtr == NULL) {
- bufPtr = AllocChannelBuffer(statePtr->bufSize);
- statePtr->curOutPtr = bufPtr;
- }
- dst = InsertPoint(bufPtr);
- dstLen = SpaceLeft(bufPtr);
- if (saved != 0) {
- /*
- * Here's some translated bytes left over from the last buffer
- * that we need to stick at the beginning of this buffer.
- */
-
- memcpy(dst, safe, (size_t) saved);
- bufPtr->nextAdded += saved;
- dst += saved;
- dstLen -= saved;
- saved = 0;
- }
-
- result = Tcl_UtfToExternal(NULL, encoding, stage, stageLen,
- statePtr->outputEncodingFlags,
- &statePtr->outputEncodingState, dst,
- dstLen + BUFFER_PADDING, &stageRead, &dstWrote, NULL);
-
- /*
- * Fix for SF #506297, reported by Martin Forssen
- * <ruric@users.sourceforge.net>.
- *
- * The encoding chosen in the script exposing the bug writes out
- * three intro characters when TCL_ENCODING_START is set, but does
- * not consume any input as TCL_ENCODING_END is cleared. As some
- * output was generated the enclosing loop calls UtfToExternal
- * again, again with START set. Three more characters in the out
- * and still no use of input ... To break this infinite loop we
- * remove TCL_ENCODING_START from the set of flags after the first
- * call (no condition is required, the later calls remove an unset
- * flag, which is a no-op). This causes the subsequent calls to
- * UtfToExternal to consume and convert the actual input.
- */
-
- statePtr->outputEncodingFlags &= ~TCL_ENCODING_START;
-
- /*
- * The following code must be executed only when result is not 0.
- */
-
- if ((result != 0) && (stageRead + dstWrote == 0)) {
- /*
- * We have an incomplete UTF-8 character at the end of the
- * staging buffer. It will get moved to the beginning of the
- * staging buffer followed by more bytes from src.
- */
-
- src -= stageLen;
- srcLen += stageLen;
- stageLen = 0;
- savedLF = 0;
- break;
- }
- bufPtr->nextAdded += dstWrote;
- if (IsBufferOverflowing(bufPtr)) {
- /*
- * When translating from UTF-8 to external encoding, we
- * allowed the translation to produce a character that crossed
- * the end of the output buffer, so that we would get a
- * completely full buffer before flushing it. The extra bytes
- * will be moved to the beginning of the next buffer.
- */
-
- saved = -SpaceLeft(bufPtr);
- memcpy(safe, dst + dstLen, (size_t) saved);
- bufPtr->nextAdded = bufPtr->bufLength;
- }
- if (CheckFlush(chanPtr, bufPtr, sawLF) != 0) {
- return -1;
- }
-
- total += dstWrote;
- stage += stageRead;
- stageLen -= stageRead;
- sawLF = 0;
-
- consumedSomething = 1;
-
- /*
- * If all translated characters are written to the buffer,
- * endEncoding is set to 0 because the escape sequence may be
- * output.
- */
-
- if ((stageLen + saved == 0) && (result == 0)) {
- endEncoding = 0;
- }
- }
- }
-#endif
-
- /*
- * If nothing was written and it happened because there was no progress in
- * the UTF conversion, we throw an error.
- */
-
- if (!consumedSomething && (total == 0)) {
- Tcl_SetErrno(EINVAL);
- return -1;
- }
return total;
}