summaryrefslogtreecommitdiffstats
path: root/generic/tclIO.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclIO.c')
-rw-r--r--generic/tclIO.c222
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.