summaryrefslogtreecommitdiffstats
path: root/generic/tclIO.c
diff options
context:
space:
mode:
authordgp <dgp@users.sourceforge.net>2014-08-20 21:44:31 (GMT)
committerdgp <dgp@users.sourceforge.net>2014-08-20 21:44:31 (GMT)
commit32380b152911ac426b039bff40279187994bdca0 (patch)
treef1439ec5327ce6a5158329ff19cc0eca18e741e5 /generic/tclIO.c
parent1701073d70f7be8200bd59362047199dedbd60b6 (diff)
downloadtcl-32380b152911ac426b039bff40279187994bdca0.zip
tcl-32380b152911ac426b039bff40279187994bdca0.tar.gz
tcl-32380b152911ac426b039bff40279187994bdca0.tar.bz2
Copy Write() to WriteBytes() to create an arena for performance hacking.
Diffstat (limited to 'generic/tclIO.c')
-rw-r--r--generic/tclIO.c168
1 files changed, 166 insertions, 2 deletions
diff --git a/generic/tclIO.c b/generic/tclIO.c
index 4452ae9..7885eab 100644
--- a/generic/tclIO.c
+++ b/generic/tclIO.c
@@ -228,8 +228,10 @@ static int WillRead(Channel *chanPtr);
#define WriteChars(chanPtr, src, srcLen) \
Write(chanPtr, src, srcLen, chanPtr->state->encoding)
-#define WriteBytes(chanPtr, src, srcLen) \
- Write(chanPtr, src, srcLen, tclIdentityEncoding)
+//#define WriteBytes(chanPtr, src, srcLen) \
+// Write(chanPtr, src, srcLen, tclIdentityEncoding)
+static int WriteBytes(Channel *chanPtr, const char *src,
+ int srcLen);
/*
* Simplifying helper macros. All may use their argument(s) multiple times.
@@ -3888,6 +3890,168 @@ Write(
return total;
}
+
+static int
+WriteBytes(
+ Channel *chanPtr, /* The channel to buffer output for. */
+ const char *src, /* UTF-8 string to write. */
+ int srcLen) /* Length of UTF-8 string in bytes. */
+{
+ ChannelState *statePtr = chanPtr->state;
+ /* State info for channel */
+ Tcl_Encoding encoding = tclIdentityEncoding;
+
+ char *nextNewLine = NULL;
+ int endEncoding, saved = 0, total = 0, flushed = 0, needNlFlush = 0;
+
+ if (srcLen) {
+ WillWrite(chanPtr);
+ }
+
+ /*
+ * Write the terminated escape sequence even if srcLen is 0.
+ */
+
+ endEncoding = ((statePtr->outputEncodingFlags & TCL_ENCODING_END) != 0);
+
+ if (GotFlag(statePtr, CHANNEL_LINEBUFFERED)
+ || (statePtr->outputTranslation != TCL_TRANSLATE_LF)) {
+ nextNewLine = memchr(src, '\n', srcLen);
+ }
+
+ while (srcLen + saved + endEncoding > 0) {
+ ChannelBuffer *bufPtr;
+ char *dst, safe[BUFFER_PADDING];
+ int result, srcRead, dstLen, dstWrote, srcLimit = srcLen;
+
+ if (nextNewLine) {
+ srcLimit = nextNewLine - src;
+ }
+
+ /* Get space to write into */
+ bufPtr = statePtr->curOutPtr;
+ if (bufPtr == NULL) {
+ bufPtr = AllocChannelBuffer(statePtr->bufSize);
+ statePtr->curOutPtr = bufPtr;
+ }
+ if (saved) {
+ /*
+ * Here's some translated bytes left over from the last buffer
+ * that we need to stick at the beginning of this buffer.
+ */
+
+ memcpy(InsertPoint(bufPtr), safe, (size_t) saved);
+ bufPtr->nextAdded += saved;
+ saved = 0;
+ }
+ PreserveChannelBuffer(bufPtr);
+ dst = InsertPoint(bufPtr);
+ dstLen = SpaceLeft(bufPtr);
+
+ result = Tcl_UtfToExternal(NULL, encoding, src, srcLimit,
+ statePtr->outputEncodingFlags,
+ &statePtr->outputEncodingState, dst,
+ dstLen + BUFFER_PADDING, &srcRead, &dstWrote, NULL);
+
+ /* See chan-io-1.[89]. Tcl Bug 506297. */
+ statePtr->outputEncodingFlags &= ~TCL_ENCODING_START;
+
+ if ((result != TCL_OK) && (srcRead + dstWrote == 0)) {
+ /* We're reading from invalid/incomplete UTF-8 */
+ ReleaseChannelBuffer(bufPtr);
+ if (total == 0) {
+ Tcl_SetErrno(EINVAL);
+ return -1;
+ }
+ break;
+ }
+
+ bufPtr->nextAdded += dstWrote;
+ src += srcRead;
+ srcLen -= srcRead;
+ total += dstWrote;
+ dst += dstWrote;
+ dstLen -= dstWrote;
+
+ if (src == nextNewLine && dstLen > 0) {
+ static char crln[3] = "\r\n";
+ char *nl = NULL;
+ int nlLen = 0;
+
+ switch (statePtr->outputTranslation) {
+ case TCL_TRANSLATE_LF:
+ nl = crln + 1;
+ nlLen = 1;
+ break;
+ case TCL_TRANSLATE_CR:
+ nl = crln;
+ nlLen = 1;
+ break;
+ case TCL_TRANSLATE_CRLF:
+ nl = crln;
+ nlLen = 2;
+ break;
+ default:
+ Tcl_Panic("unknown output translation requested");
+ break;
+ }
+
+ result |= Tcl_UtfToExternal(NULL, encoding, nl, nlLen,
+ statePtr->outputEncodingFlags,
+ &statePtr->outputEncodingState, dst,
+ dstLen + BUFFER_PADDING, &srcRead, &dstWrote, NULL);
+
+ assert (srcRead == nlLen);
+
+ bufPtr->nextAdded += dstWrote;
+ src++;
+ srcLen--;
+ total += dstWrote;
+ dst += dstWrote;
+ dstLen -= dstWrote;
+ nextNewLine = memchr(src, '\n', srcLen);
+ needNlFlush = 1;
+ }
+
+ 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 ((srcLen + saved == 0) && (result == TCL_OK)) {
+ endEncoding = 0;
+ }
+
+ if (IsBufferFull(bufPtr)) {
+ if (FlushChannel(NULL, chanPtr, 0) != 0) {
+ ReleaseChannelBuffer(bufPtr);
+ return -1;
+ }
+ flushed += statePtr->bufSize;
+ if (saved == 0 || src[-1] != '\n') {
+ needNlFlush = 0;
+ }
+ }
+ ReleaseChannelBuffer(bufPtr);
+ }
+ if ((flushed < total) && (GotFlag(statePtr, CHANNEL_UNBUFFERED) ||
+ (needNlFlush && GotFlag(statePtr, CHANNEL_LINEBUFFERED)))) {
+ if (FlushChannel(NULL, chanPtr, 0) != 0) {
+ return -1;
+ }
+ }
+
+ return total;
+}
/*
*---------------------------------------------------------------------------