diff options
Diffstat (limited to 'generic/tclIO.c')
-rw-r--r-- | generic/tclIO.c | 222 |
1 files changed, 94 insertions, 128 deletions
diff --git a/generic/tclIO.c b/generic/tclIO.c index 3636861..c2a8cab 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -205,9 +205,9 @@ static int HaveVersion(const Tcl_ChannelType *typePtr, static void PeekAhead(Channel *chanPtr, char **dstEndPtr, GetsState *gsPtr); static int ReadBytes(ChannelState *statePtr, Tcl_Obj *objPtr, - int charsLeft, int *offsetPtr); + int charsLeft); static int ReadChars(ChannelState *statePtr, Tcl_Obj *objPtr, - int charsLeft, int *offsetPtr, int *factorPtr); + int charsLeft, int *factorPtr); static void RecycleBuffer(ChannelState *statePtr, ChannelBuffer *bufPtr, int mustDiscard); static int StackSetBlockMode(Channel *chanPtr, int mode); @@ -5058,8 +5058,9 @@ DoReadChars( ChannelState *statePtr = chanPtr->state; /* State info for channel */ ChannelBuffer *bufPtr; - int offset, factor, copied, copiedNow, result; + int factor, copied, copiedNow, result; Tcl_Encoding encoding; + int binaryMode; #define UTF_EXPANSION_FACTOR 1024 /* @@ -5070,8 +5071,12 @@ DoReadChars( encoding = statePtr->encoding; factor = UTF_EXPANSION_FACTOR; + binaryMode = (encoding == NULL) + && (statePtr->inputTranslation == TCL_TRANSLATE_LF) + && (statePtr->inEofChar == '\0'); + if (appendFlag == 0) { - if (encoding == NULL) { + if (binaryMode) { Tcl_SetByteArrayLength(objPtr, 0); } else { Tcl_SetObjLength(objPtr, 0); @@ -5080,27 +5085,21 @@ DoReadChars( * We're going to access objPtr->bytes directly, so we must ensure * that this is actually a string object (otherwise it might have * been pure Unicode). + * + * Probably not needed anymore. */ TclGetString(objPtr); } - offset = 0; - } else { - if (encoding == NULL) { - Tcl_GetByteArrayFromObj(objPtr, &offset); - } else { - TclGetStringFromObj(objPtr, &offset); - } } for (copied = 0; (unsigned) toRead > 0; ) { copiedNow = -1; if (statePtr->inQueueHead != NULL) { - if (encoding == NULL) { - copiedNow = ReadBytes(statePtr, objPtr, toRead, &offset); + if (binaryMode) { + copiedNow = ReadBytes(statePtr, objPtr, toRead); } else { - copiedNow = ReadChars(statePtr, objPtr, toRead, &offset, - &factor); + copiedNow = ReadChars(statePtr, objPtr, toRead, &factor); } /* @@ -5145,11 +5144,6 @@ DoReadChars( } ResetFlag(statePtr, CHANNEL_BLOCKED); - if (encoding == NULL) { - Tcl_SetByteArrayLength(objPtr, offset); - } else { - Tcl_SetObjLength(objPtr, offset); - } /* * Update the notifier state so we don't block while there is still data @@ -5175,13 +5169,11 @@ DoReadChars( * allocated to hold data read from the channel as needed. * * Results: - * The return value is the number of bytes appended to the object and - * *offsetPtr is filled with the total number of bytes in the object - * (greater than the return value if there were already bytes in the - * object). + * The return value is the number of bytes appended to the object, or + * -1 to indicate that zero bytes were read due to an EOF. * * Side effects: - * None. + * The storage of bytes in objPtr can cause (re-)allocation of memory. * *--------------------------------------------------------------------------- */ @@ -5194,72 +5186,22 @@ ReadBytes( * been allocated to hold data, not how many * bytes of data have been stored in the * object. */ - int bytesToRead, /* Maximum number of bytes to store, or < 0 to + int bytesToRead) /* Maximum number of bytes to store, or < 0 to * get all available bytes. Bytes are obtained * from the first buffer in the queue - even * if this number is larger than the number of * bytes available in the first buffer, only * the bytes from the first buffer are * returned. */ - int *offsetPtr) /* On input, contains how many bytes of objPtr - * have been used to hold data. On output, - * filled with how many bytes are now being - * used. */ { - int toRead, srcLen, offset, length, srcRead, dstWrote; - ChannelBuffer *bufPtr; - char *src, *dst; - - offset = *offsetPtr; - - bufPtr = statePtr->inQueueHead; - src = RemovePoint(bufPtr); - srcLen = BytesLeft(bufPtr); - - toRead = bytesToRead; - if ((unsigned) toRead > (unsigned) srcLen) { - toRead = srcLen; - } + ChannelBuffer *bufPtr = statePtr->inQueueHead; + int srcLen = BytesLeft(bufPtr); + int toRead = bytesToRead>srcLen || bytesToRead<0 ? srcLen : bytesToRead; - dst = (char *) Tcl_GetByteArrayFromObj(objPtr, &length); - if (toRead > length - offset - 1) { - /* - * Double the existing size of the object or make enough room to hold - * all the characters we may get from the source buffer, whichever is - * larger. - */ - - length = offset * 2; - if (offset < toRead) { - length = offset + toRead + 1; - } - dst = (char *) Tcl_SetByteArrayLength(objPtr, length); - } - dst += offset; - - if (statePtr->flags & INPUT_NEED_NL) { - ResetFlag(statePtr, INPUT_NEED_NL); - if ((srcLen == 0) || (*src != '\n')) { - *dst = '\r'; - *offsetPtr += 1; - return 1; - } - *dst++ = '\n'; - src++; - srcLen--; - toRead--; - } - - srcRead = srcLen; - dstWrote = toRead; - if (TranslateInputEOL(statePtr, dst, src, &dstWrote, &srcRead) != 0) { - if (dstWrote == 0) { - return -1; - } - } - bufPtr->nextRemoved += srcRead; - *offsetPtr += dstWrote; - return dstWrote; + TclAppendBytesToByteArray(objPtr, (unsigned char *) RemovePoint(bufPtr), + toRead); + bufPtr->nextRemoved += toRead; + return toRead; } /* @@ -5304,25 +5246,22 @@ ReadChars( * available in the first buffer, only the * characters from the first buffer are * returned. */ - int *offsetPtr, /* On input, contains how many bytes of objPtr - * have been used to hold data. On output, - * filled with how many bytes are now being - * used. */ int *factorPtr) /* On input, contains a guess of how many * bytes need to be allocated to hold the * result of converting N source bytes to * UTF-8. On output, contains another guess * based on the data seen so far. */ { - int toRead, factor, offset, spaceLeft, srcLen, dstNeeded; + int toRead, factor, srcLen, dstNeeded, numBytes; int srcRead, dstWrote, numChars, dstRead; ChannelBuffer *bufPtr; char *src, *dst; Tcl_EncodingState oldState; int encEndFlagSuppressed = 0; + Tcl_Encoding encoding = statePtr->encoding? statePtr->encoding + : GetBinaryEncoding(); factor = *factorPtr; - offset = *offsetPtr; bufPtr = statePtr->inQueueHead; src = RemovePoint(bufPtr); @@ -5340,37 +5279,15 @@ ReadChars( */ dstNeeded = TCL_UTF_MAX - 1 + toRead * factor / UTF_EXPANSION_FACTOR; - spaceLeft = objPtr->length - offset; - - if (dstNeeded > spaceLeft) { - /* - * Double the existing size of the object or make enough room to hold - * all the characters we want from the source buffer, whichever is - * larger. - */ - - int length = offset + ((offset < dstNeeded) ? dstNeeded : offset); - - if (Tcl_AttemptSetObjLength(objPtr, length) == 0) { - length = offset + dstNeeded; - if (Tcl_AttemptSetObjLength(objPtr, length) == 0) { - dstNeeded = TCL_UTF_MAX - 1 + toRead; - length = offset + dstNeeded; - Tcl_SetObjLength(objPtr, length); - } - } - spaceLeft = length - offset; - } + (void) TclGetStringFromObj(objPtr, &numBytes); + Tcl_AppendToObj(objPtr, NULL, dstNeeded); if (toRead == srcLen) { - /* - * Want to convert the whole buffer in one pass. If we have enough - * space, convert it using all available space in object rather than - * using the factor. - */ - - dstNeeded = spaceLeft; + unsigned int size; + dst = TclGetStringStorage(objPtr, &size) + numBytes; + dstNeeded = size - numBytes; + } else { + dst = TclGetString(objPtr) + numBytes; } - dst = objPtr->bytes + offset; /* * [Bug 1462248]: The cause of the crash reported in this bug is this: @@ -5424,7 +5341,7 @@ ReadChars( */ ResetFlag(statePtr, INPUT_NEED_NL); - Tcl_ExternalToUtf(NULL, statePtr->encoding, src, srcLen, + Tcl_ExternalToUtf(NULL, encoding, src, srcLen, statePtr->inputEncodingFlags, &statePtr->inputEncodingState, dst, TCL_UTF_MAX + 1, &srcRead, &dstWrote, &numChars); if ((dstWrote > 0) && (*dst == '\n')) { @@ -5441,7 +5358,7 @@ ReadChars( *dst = '\r'; } statePtr->inputEncodingFlags &= ~TCL_ENCODING_START; - *offsetPtr += 1; + Tcl_SetObjLength(objPtr, numBytes + 1); if (encEndFlagSuppressed) { statePtr->inputEncodingFlags |= TCL_ENCODING_END; @@ -5449,7 +5366,7 @@ ReadChars( return 1; } - Tcl_ExternalToUtf(NULL, statePtr->encoding, src, srcLen, + Tcl_ExternalToUtf(NULL, encoding, src, srcLen, statePtr->inputEncodingFlags, &statePtr->inputEncodingState, dst, dstNeeded + 1, &srcRead, &dstWrote, &numChars); @@ -5482,6 +5399,7 @@ ReadChars( SetFlag(statePtr, CHANNEL_NEED_MORE_DATA); } + Tcl_SetObjLength(objPtr, numBytes); return -1; } @@ -5506,7 +5424,8 @@ ReadChars( memcpy(RemovePoint(nextPtr), src, (size_t) srcLen); RecycleBuffer(statePtr, bufPtr, 0); statePtr->inQueueHead = nextPtr; - return ReadChars(statePtr, objPtr, charsToRead, offsetPtr, factorPtr); + Tcl_SetObjLength(objPtr, numBytes); + return ReadChars(statePtr, objPtr, charsToRead, factorPtr); } dstRead = dstWrote; @@ -5519,10 +5438,11 @@ ReadChars( */ if (dstWrote == 0) { + Tcl_SetObjLength(objPtr, numBytes); return -1; } statePtr->inputEncodingState = oldState; - Tcl_ExternalToUtf(NULL, statePtr->encoding, src, srcLen, + Tcl_ExternalToUtf(NULL, encoding, src, srcLen, statePtr->inputEncodingFlags, &statePtr->inputEncodingState, dst, dstRead + TCL_UTF_MAX, &srcRead, &dstWrote, &numChars); TranslateInputEOL(statePtr, dst, dst, &dstWrote, &dstRead); @@ -5545,7 +5465,7 @@ ReadChars( eof = Tcl_UtfAtIndex(dst, toRead); statePtr->inputEncodingState = oldState; - Tcl_ExternalToUtf(NULL, statePtr->encoding, src, srcLen, + Tcl_ExternalToUtf(NULL, encoding, src, srcLen, statePtr->inputEncodingFlags, &statePtr->inputEncodingState, dst, eof - dst + TCL_UTF_MAX, &srcRead, &dstWrote, &numChars); dstRead = dstWrote; @@ -5558,7 +5478,7 @@ ReadChars( if (dstWrote > srcRead + 1) { *factorPtr = dstWrote * UTF_EXPANSION_FACTOR / srcRead; } - *offsetPtr += dstWrote; + Tcl_SetObjLength(objPtr, numBytes + dstWrote); return numChars; } @@ -5724,7 +5644,7 @@ TranslateInputEOL( SetFlag(statePtr, CHANNEL_EOF | CHANNEL_STICKY_EOF); statePtr->inputEncodingFlags |= TCL_ENCODING_END; - ResetFlag(statePtr, INPUT_SAW_CR | INPUT_NEED_NL); +// ResetFlag(statePtr, INPUT_SAW_CR | INPUT_NEED_NL); return 1; } @@ -8856,8 +8776,7 @@ CopyAndTranslateBuffer( * in the current input buffer? */ int copied; /* How many characters were already copied * into the destination space? */ - int i; /* Iterates over the copied input looking for - * the input eofChar. */ + int toCopy; /* * If there is no input at all, return zero. The invariant is that either @@ -8873,6 +8792,50 @@ CopyAndTranslateBuffer( bytesInBuffer = BytesLeft(bufPtr); copied = 0; +#if 1 + if (statePtr->flags & INPUT_NEED_NL) { + + /* + * An earlier call to TranslateInputEOL ended in the read of a \r . + * Only the next read from the same channel can complete the + * translation sequence to tell us what character we should read. + */ + + if (bytesInBuffer) { + /* There's a next byte. It will settle things. */ + ResetFlag(statePtr, INPUT_NEED_NL); + + if (RemovePoint(bufPtr)[0] == '\n') { + bufPtr->nextRemoved++; + bytesInBuffer--; + *result++ = '\n'; + } else { + *result++ = '\r'; + } + copied++; + space--; + } else if (statePtr->flags & CHANNEL_EOF) { + /* There is no next byte, and there never will be (EOF). */ + ResetFlag(statePtr, INPUT_NEED_NL); + *result = '\r'; + return 1; + } else { + /* There is no next byte. Ask the caller to read more. */ + return 0; + } + } + toCopy = space; + if (bytesInBuffer <= toCopy) { + toCopy = bytesInBuffer; + } + if (toCopy == 0) { + return copied; + } + TranslateInputEOL(statePtr, result, RemovePoint(bufPtr), + &toCopy, &bytesInBuffer); + bufPtr->nextRemoved += bytesInBuffer; + copied += toCopy; +#else switch (statePtr->inputTranslation) { case TCL_TRANSLATE_LF: if (bytesInBuffer == 0) { @@ -9016,6 +8979,8 @@ CopyAndTranslateBuffer( */ if (statePtr->inEofChar != 0) { + int i; + for (i = 0; i < copied; i++) { if (result[i] == (char) statePtr->inEofChar) { /* @@ -9030,6 +8995,7 @@ CopyAndTranslateBuffer( } } } +#endif /* * If the current buffer is empty recycle it. |