Tcl Source Code

Check-in [6828d86c67]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:merge trunk
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | novem
Files: files | file ages | folders
SHA1: 6828d86c67c06761874c302a90349a4379de1a65
User & Date: jan.nijtmans 2014-02-06 22:10:55
Context
2014-02-11
11:13
Merge trunk check-in: 73afad5c30 user: jan.nijtmans tags: novem
2014-02-06
22:10
merge trunk check-in: 6828d86c67 user: jan.nijtmans tags: novem
21:45
check for existance of __BORLANDC__ before using its value check-in: e212ae9cf1 user: jan.nijtmans tags: trunk
2014-02-03
15:29
merge trunk check-in: eb01b5b26b user: jan.nijtmans tags: novem
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/tcl.h.

168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
 *
 * Note: when building static but linking dynamically to MSVCRT we must still
 *       correctly decorate the C library imported function.  Use CRTIMPORT
 *       for this purpose.  _DLL is defined by the compiler when linking to
 *       MSVCRT.
 */

#if (defined(__WIN32__) && (defined(_MSC_VER) || (__BORLANDC__ >= 0x0550) || defined(__LCC__) || defined(__WATCOMC__) || (defined(__GNUC__) && defined(__declspec))))
#   define HAVE_DECLSPEC 1
#   ifdef STATIC_BUILD
#       define DLLIMPORT
#       define DLLEXPORT
#       ifdef _DLL
#           define CRTIMPORT __declspec(dllimport)
#       else







|







168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
 *
 * Note: when building static but linking dynamically to MSVCRT we must still
 *       correctly decorate the C library imported function.  Use CRTIMPORT
 *       for this purpose.  _DLL is defined by the compiler when linking to
 *       MSVCRT.
 */

#if (defined(__WIN32__) && (defined(_MSC_VER) || (defined(__BORLANDC__) && (__BORLANDC__ >= 0x0550)) || defined(__LCC__) || defined(__WATCOMC__) || (defined(__GNUC__) && defined(__declspec))))
#   define HAVE_DECLSPEC 1
#   ifdef STATIC_BUILD
#       define DLLIMPORT
#       define DLLEXPORT
#       ifdef _DLL
#           define CRTIMPORT __declspec(dllimport)
#       else

Changes to generic/tclCompile.c.

5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330



5331
5332
5333

5334
5335
5336

5337
5338
5339

5340
5341
5342

5343
5344
5345

5346
5347
5348

5349
5350

5351





5352
5353
5354
5355



5356
5357
5358
5359
5360
5361
5362
static void
PrintSourceToObj(
    Tcl_Obj *appendObj,		/* The object to print the source to. */
    const char *stringPtr,	/* The string to print. */
    int maxChars)		/* Maximum number of chars to print. */
{
    register const char *p;
    register int i = 0;

    if (stringPtr == NULL) {
	Tcl_AppendToObj(appendObj, "\"\"", -1);
	return;
    }

    Tcl_AppendToObj(appendObj, "\"", -1);
    p = stringPtr;
    for (;  (*p != '\0') && (i < maxChars);  p++, i++) {



	switch (*p) {
	case '"':
	    Tcl_AppendToObj(appendObj, "\\\"", -1);

	    continue;
	case '\f':
	    Tcl_AppendToObj(appendObj, "\\f", -1);

	    continue;
	case '\n':
	    Tcl_AppendToObj(appendObj, "\\n", -1);

	    continue;
	case '\r':
	    Tcl_AppendToObj(appendObj, "\\r", -1);

	    continue;
	case '\t':
	    Tcl_AppendToObj(appendObj, "\\t", -1);

	    continue;
	case '\v':
	    Tcl_AppendToObj(appendObj, "\\v", -1);

	    continue;
	default:

	    Tcl_AppendPrintfToObj(appendObj, "%c", *p);





	    continue;
	}
    }
    Tcl_AppendToObj(appendObj, "\"", -1);



}

#ifdef TCL_COMPILE_STATS
/*
 *----------------------------------------------------------------------
 *
 * RecordByteCodeStats --







|








|
>
>
>
|


>



>



>



>



>



>


>
|
>
>
>
>
>




>
>
>







5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336
5337
5338
5339
5340
5341
5342
5343
5344
5345
5346
5347
5348
5349
5350
5351
5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
5364
5365
5366
5367
5368
5369
5370
5371
5372
5373
5374
5375
5376
5377
5378
5379
5380
static void
PrintSourceToObj(
    Tcl_Obj *appendObj,		/* The object to print the source to. */
    const char *stringPtr,	/* The string to print. */
    int maxChars)		/* Maximum number of chars to print. */
{
    register const char *p;
    register int i = 0, len;

    if (stringPtr == NULL) {
	Tcl_AppendToObj(appendObj, "\"\"", -1);
	return;
    }

    Tcl_AppendToObj(appendObj, "\"", -1);
    p = stringPtr;
    for (;  (*p != '\0') && (i < maxChars);  p+=len) {
	Tcl_UniChar ch;

	len = TclUtfToUniChar(p, &ch);
	switch (ch) {
	case '"':
	    Tcl_AppendToObj(appendObj, "\\\"", -1);
	    i += 2;
	    continue;
	case '\f':
	    Tcl_AppendToObj(appendObj, "\\f", -1);
	    i += 2;
	    continue;
	case '\n':
	    Tcl_AppendToObj(appendObj, "\\n", -1);
	    i += 2;
	    continue;
	case '\r':
	    Tcl_AppendToObj(appendObj, "\\r", -1);
	    i += 2;
	    continue;
	case '\t':
	    Tcl_AppendToObj(appendObj, "\\t", -1);
	    i += 2;
	    continue;
	case '\v':
	    Tcl_AppendToObj(appendObj, "\\v", -1);
	    i += 2;
	    continue;
	default:
	    if (ch < 0x20 || ch >= 0x7f) {
		Tcl_AppendPrintfToObj(appendObj, "\\u%04x", ch);
		i += 6;
	    } else {
		Tcl_AppendPrintfToObj(appendObj, "%c", ch);
		i++;
	    }
	    continue;
	}
    }
    Tcl_AppendToObj(appendObj, "\"", -1);
    if (*p != '\0') {
	Tcl_AppendToObj(appendObj, "...", -1);
    }
}

#ifdef TCL_COMPILE_STATS
/*
 *----------------------------------------------------------------------
 *
 * RecordByteCodeStats --

Changes to generic/tclEncoding.c.

178
179
180
181
182
183
184

185
186
187
188
189
190
191
 * The following are used to hold the default and current system encodings.
 * If NULL is passed to one of the conversion routines, the current setting of
 * the system encoding will be used to perform the conversion.
 */

static Tcl_Encoding defaultEncoding;
static Tcl_Encoding systemEncoding;


/*
 * The following variable is used in the sparse matrix code for a
 * TableEncoding to represent a page in the table that has no entries.
 */

static unsigned short emptyPage[256];







>







178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
 * The following are used to hold the default and current system encodings.
 * If NULL is passed to one of the conversion routines, the current setting of
 * the system encoding will be used to perform the conversion.
 */

static Tcl_Encoding defaultEncoding;
static Tcl_Encoding systemEncoding;
Tcl_Encoding tclIdentityEncoding;

/*
 * The following variable is used in the sparse matrix code for a
 * TableEncoding to represent a page in the table that has no entries.
 */

static unsigned short emptyPage[256];
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577

    type.encodingName	= "identity";
    type.toUtfProc	= BinaryProc;
    type.fromUtfProc	= BinaryProc;
    type.freeProc	= NULL;
    type.nullSize	= 1;
    type.clientData	= NULL;
    Tcl_CreateEncoding(&type);

    type.encodingName	= "utf-8";
    type.toUtfProc	= UtfExtToUtfIntProc;
    type.fromUtfProc	= UtfIntToUtfExtProc;
    type.freeProc	= NULL;
    type.nullSize	= 1;
    type.clientData	= NULL;







|







564
565
566
567
568
569
570
571
572
573
574
575
576
577
578

    type.encodingName	= "identity";
    type.toUtfProc	= BinaryProc;
    type.fromUtfProc	= BinaryProc;
    type.freeProc	= NULL;
    type.nullSize	= 1;
    type.clientData	= NULL;
    tclIdentityEncoding = Tcl_CreateEncoding(&type);

    type.encodingName	= "utf-8";
    type.toUtfProc	= UtfExtToUtfIntProc;
    type.fromUtfProc	= UtfIntToUtfExtProc;
    type.freeProc	= NULL;
    type.nullSize	= 1;
    type.clientData	= NULL;
647
648
649
650
651
652
653

654
655
656
657
658
659
660
{
    Tcl_HashSearch search;
    Tcl_HashEntry *hPtr;

    Tcl_MutexLock(&encodingMutex);
    encodingsInitialized = 0;
    FreeEncoding(systemEncoding);


    hPtr = Tcl_FirstHashEntry(&encodingTable, &search);
    while (hPtr != NULL) {
	/*
	 * Call FreeEncoding instead of doing it directly to handle refcounts
	 * like escape encodings use. [Bug 524674] Make sure to call
	 * Tcl_FirstHashEntry repeatedly so that all encodings are eventually







>







648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
{
    Tcl_HashSearch search;
    Tcl_HashEntry *hPtr;

    Tcl_MutexLock(&encodingMutex);
    encodingsInitialized = 0;
    FreeEncoding(systemEncoding);
    FreeEncoding(tclIdentityEncoding);

    hPtr = Tcl_FirstHashEntry(&encodingTable, &search);
    while (hPtr != NULL) {
	/*
	 * Call FreeEncoding instead of doing it directly to handle refcounts
	 * like escape encodings use. [Bug 524674] Make sure to call
	 * Tcl_FirstHashEntry repeatedly so that all encodings are eventually

Changes to generic/tclExecute.c.

5769
5770
5771
5772
5773
5774
5775












5776
5777


5778



5779
5780
5781
5782

5783



5784
5785
5786
5787
5788
5789
5790
	trim1 = TclTrimLeft(string1, length, string2, length2);
	if (trim1 < length) {
	    trim2 = TclTrimRight(string1, length, string2, length2);
	} else {
	    trim2 = 0;
	}
    createTrimmedString:












	if (trim1 == 0 && trim2 == 0) {
	    TRACE_WITH_OBJ(("\"%.30s\" \"%.30s\" => ",


		    O2S(valuePtr), O2S(value2Ptr)), valuePtr);



	    NEXT_INST_F(1, 1, 0);
	} else {
	    objResultPtr = Tcl_NewStringObj(string1+trim1, length-trim1-trim2);
	    TRACE_WITH_OBJ(("\"%.30s\" \"%.30s\" => ",

		    O2S(valuePtr), O2S(value2Ptr)), objResultPtr);



	    NEXT_INST_F(1, 2, 1);
	}
    }

    case INST_REGEXP:
	cflags = TclGetInt1AtPtr(pc+1); /* RE compile flages like NOCASE */
	valuePtr = OBJ_AT_TOS;		/* String */







>
>
>
>
>
>
>
>
>
>
>
>

<
>
>
|
>
>
>



|
>
|
>
>
>







5769
5770
5771
5772
5773
5774
5775
5776
5777
5778
5779
5780
5781
5782
5783
5784
5785
5786
5787
5788

5789
5790
5791
5792
5793
5794
5795
5796
5797
5798
5799
5800
5801
5802
5803
5804
5805
5806
5807
5808
5809
5810
	trim1 = TclTrimLeft(string1, length, string2, length2);
	if (trim1 < length) {
	    trim2 = TclTrimRight(string1, length, string2, length2);
	} else {
	    trim2 = 0;
	}
    createTrimmedString:
	/*
	 * Careful here; trim set often contains non-ASCII characters so we
	 * take care when printing. [Bug 971cb4f1db]
	 */

#ifdef TCL_COMPILE_DEBUG
	if (traceInstructions) {
	    TRACE(("\"%.30s\" ", O2S(valuePtr)));
	    TclPrintObject(stdout, value2Ptr, 30);
	    printf(" => ");
	}
#endif
	if (trim1 == 0 && trim2 == 0) {

#ifdef TCL_COMPILE_DEBUG
	    if (traceInstructions) {
		TclPrintObject(stdout, valuePtr, 30);
		printf("\n");
	    }
#endif
	    NEXT_INST_F(1, 1, 0);
	} else {
	    objResultPtr = Tcl_NewStringObj(string1+trim1, length-trim1-trim2);
#ifdef TCL_COMPILE_DEBUG
	    if (traceInstructions) {
		TclPrintObject(stdout, objResultPtr, 30);
		printf("\n");
	    }
#endif
	    NEXT_INST_F(1, 2, 1);
	}
    }

    case INST_REGEXP:
	cflags = TclGetInt1AtPtr(pc+1); /* RE compile flages like NOCASE */
	valuePtr = OBJ_AT_TOS;		/* String */

Changes to generic/tclIO.c.

161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
 * Static functions in this file:
 */

static ChannelBuffer *	AllocChannelBuffer(int length);
static void		ChannelTimerProc(ClientData clientData);
static int		CheckChannelErrors(ChannelState *statePtr,
			    int direction);
static int		CheckFlush(Channel *chanPtr, ChannelBuffer *bufPtr,
			    int newlineFlag);
static int		CheckForDeadChannel(Tcl_Interp *interp,
			    ChannelState *statePtr);
static void		CheckForStdChannelsBeingClosed(Tcl_Channel chan);
static void		CleanupChannelHandlers(Tcl_Interp *interp,
			    Channel *chanPtr);
static int		CloseChannel(Tcl_Interp *interp, Channel *chanPtr,
			    int errorCode);







<
<







161
162
163
164
165
166
167


168
169
170
171
172
173
174
 * Static functions in this file:
 */

static ChannelBuffer *	AllocChannelBuffer(int length);
static void		ChannelTimerProc(ClientData clientData);
static int		CheckChannelErrors(ChannelState *statePtr,
			    int direction);


static int		CheckForDeadChannel(Tcl_Interp *interp,
			    ChannelState *statePtr);
static void		CheckForStdChannelsBeingClosed(Tcl_Channel chan);
static void		CleanupChannelHandlers(Tcl_Interp *interp,
			    Channel *chanPtr);
static int		CloseChannel(Tcl_Interp *interp, Channel *chanPtr,
			    int errorCode);
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205

206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236





237
238
239
240
241
242
243
static void		DeleteScriptRecord(Tcl_Interp *interp,
			    Channel *chanPtr, int mask);
static int		DetachChannel(Tcl_Interp *interp, Tcl_Channel chan);
static void		DiscardInputQueued(ChannelState *statePtr,
			    int discardSavedBuffers);
static void		DiscardOutputQueued(ChannelState *chanPtr);
static int		DoRead(Channel *chanPtr, char *srcPtr, int slen, int allowShortReads);
static int		DoWrite(Channel *chanPtr, const char *src, int srcLen);
static int		DoReadChars(Channel *chan, Tcl_Obj *objPtr, int toRead,
			    int appendFlag);
static int		DoWriteChars(Channel *chan, const char *src, int len);
static int		FilterInputBytes(Channel *chanPtr,
			    GetsState *statePtr);
static int		FlushChannel(Tcl_Interp *interp, Channel *chanPtr,
			    int calledFromAsyncFlush);
static int		TclGetsObjBinary(Tcl_Channel chan, Tcl_Obj *objPtr);

static void		FreeBinaryEncoding(ClientData clientData);
static Tcl_HashTable *	GetChannelTable(Tcl_Interp *interp);
static int		GetInput(Channel *chanPtr);
static int		HaveVersion(const Tcl_ChannelType *typePtr,
			    Tcl_ChannelTypeVersion minimumVersion);
static void		PeekAhead(Channel *chanPtr, char **dstEndPtr,
			    GetsState *gsPtr);
static int		ReadBytes(ChannelState *statePtr, Tcl_Obj *objPtr,
			    int charsLeft, int *offsetPtr);
static int		ReadChars(ChannelState *statePtr, Tcl_Obj *objPtr,
			    int charsLeft, int *offsetPtr, int *factorPtr);
static void		RecycleBuffer(ChannelState *statePtr,
			    ChannelBuffer *bufPtr, int mustDiscard);
static int		StackSetBlockMode(Channel *chanPtr, int mode);
static int		SetBlockMode(Tcl_Interp *interp, Channel *chanPtr,
			    int mode);
static void		StopCopy(CopyState *csPtr);
static int		TranslateInputEOL(ChannelState *statePtr, char *dst,
			    const char *src, int *dstLenPtr, int *srcLenPtr);
static int		TranslateOutputEOL(ChannelState *statePtr, char *dst,
			    const char *src, int *dstLenPtr, int *srcLenPtr);
static void		UpdateInterest(Channel *chanPtr);
static int		WriteBytes(Channel *chanPtr, const char *src,
			    int srcLen);
static int		WriteChars(Channel *chanPtr, const char *src,
			    int srcLen);
static Tcl_Obj *	FixLevelCode(Tcl_Obj *msg);
static void		SpliceChannel(Tcl_Channel chan);
static void		CutChannel(Tcl_Channel chan);
static int              WillRead(Channel *chanPtr);






/*
 * Simplifying helper macros. All may use their argument(s) multiple times.
 * The ANSI C "prototypes" for the macros are listed below, together with a
 * short description of what the macro does.
 *
 * --------------------------------------------------------------------------
 * int BytesLeft(ChannelBuffer *bufPtr)







<


<





>



















<
<

|
|
<
<





>
>
>
>
>







188
189
190
191
192
193
194

195
196

197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221


222
223
224


225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
static void		DeleteScriptRecord(Tcl_Interp *interp,
			    Channel *chanPtr, int mask);
static int		DetachChannel(Tcl_Interp *interp, Tcl_Channel chan);
static void		DiscardInputQueued(ChannelState *statePtr,
			    int discardSavedBuffers);
static void		DiscardOutputQueued(ChannelState *chanPtr);
static int		DoRead(Channel *chanPtr, char *srcPtr, int slen, int allowShortReads);

static int		DoReadChars(Channel *chan, Tcl_Obj *objPtr, int toRead,
			    int appendFlag);

static int		FilterInputBytes(Channel *chanPtr,
			    GetsState *statePtr);
static int		FlushChannel(Tcl_Interp *interp, Channel *chanPtr,
			    int calledFromAsyncFlush);
static int		TclGetsObjBinary(Tcl_Channel chan, Tcl_Obj *objPtr);
static Tcl_Encoding	GetBinaryEncoding();
static void		FreeBinaryEncoding(ClientData clientData);
static Tcl_HashTable *	GetChannelTable(Tcl_Interp *interp);
static int		GetInput(Channel *chanPtr);
static int		HaveVersion(const Tcl_ChannelType *typePtr,
			    Tcl_ChannelTypeVersion minimumVersion);
static void		PeekAhead(Channel *chanPtr, char **dstEndPtr,
			    GetsState *gsPtr);
static int		ReadBytes(ChannelState *statePtr, Tcl_Obj *objPtr,
			    int charsLeft, int *offsetPtr);
static int		ReadChars(ChannelState *statePtr, Tcl_Obj *objPtr,
			    int charsLeft, int *offsetPtr, int *factorPtr);
static void		RecycleBuffer(ChannelState *statePtr,
			    ChannelBuffer *bufPtr, int mustDiscard);
static int		StackSetBlockMode(Channel *chanPtr, int mode);
static int		SetBlockMode(Tcl_Interp *interp, Channel *chanPtr,
			    int mode);
static void		StopCopy(CopyState *csPtr);
static int		TranslateInputEOL(ChannelState *statePtr, char *dst,
			    const char *src, int *dstLenPtr, int *srcLenPtr);


static void		UpdateInterest(Channel *chanPtr);
static int		Write(Channel *chanPtr, const char *src,
			    int srcLen, Tcl_Encoding encoding);


static Tcl_Obj *	FixLevelCode(Tcl_Obj *msg);
static void		SpliceChannel(Tcl_Channel chan);
static void		CutChannel(Tcl_Channel chan);
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)

/*
 * Simplifying helper macros. All may use their argument(s) multiple times.
 * The ANSI C "prototypes" for the macros are listed below, together with a
 * short description of what the macro does.
 *
 * --------------------------------------------------------------------------
 * int BytesLeft(ChannelBuffer *bufPtr)
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
 * requested (consistent with Tcl_GetChannel).  The setFromAny and
 * updateString can be NULL as they should not be called.
 */

static void		DupChannelIntRep(Tcl_Obj *objPtr, Tcl_Obj *copyPtr);
static int		SetChannelFromAny(Tcl_Interp *interp,
			    Tcl_Obj *objPtr);
static void		UpdateStringOfChannel(Tcl_Obj *objPtr);
static void		FreeChannelIntRep(Tcl_Obj *objPtr);

static const Tcl_ObjType tclChannelType = {
    "channel",			/* name for this type */
    FreeChannelIntRep,		/* freeIntRepProc */
    DupChannelIntRep,		/* dupIntRepProc */
    NULL,			/* updateStringProc UpdateStringOfChannel */
    NULL			/* setFromAnyProc SetChannelFromAny */
};

#define GET_CHANNELSTATE(objPtr) \
    ((ChannelState *) (objPtr)->internalRep.twoPtrValue.ptr1)
#define SET_CHANNELSTATE(objPtr, storePtr) \
    ((objPtr)->internalRep.twoPtrValue.ptr1 = (void *) (storePtr))
#define GET_CHANNELINTERP(objPtr) \
    ((Interp *) (objPtr)->internalRep.twoPtrValue.ptr2)
#define SET_CHANNELINTERP(objPtr, storePtr) \
    ((objPtr)->internalRep.twoPtrValue.ptr2 = (void *) (storePtr))

#define BUSY_STATE(st, fl) \
     ((((st)->csPtrR) && ((fl) & TCL_READABLE)) || \
      (((st)->csPtrW) && ((fl) & TCL_WRITABLE)))








<


|



|








|







317
318
319
320
321
322
323

324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
 * requested (consistent with Tcl_GetChannel).  The setFromAny and
 * updateString can be NULL as they should not be called.
 */

static void		DupChannelIntRep(Tcl_Obj *objPtr, Tcl_Obj *copyPtr);
static int		SetChannelFromAny(Tcl_Interp *interp,
			    Tcl_Obj *objPtr);

static void		FreeChannelIntRep(Tcl_Obj *objPtr);

static const Tcl_ObjType chanObjType = {
    "channel",			/* name for this type */
    FreeChannelIntRep,		/* freeIntRepProc */
    DupChannelIntRep,		/* dupIntRepProc */
    NULL,			/* updateStringProc */
    NULL			/* setFromAnyProc SetChannelFromAny */
};

#define GET_CHANNELSTATE(objPtr) \
    ((ChannelState *) (objPtr)->internalRep.twoPtrValue.ptr1)
#define SET_CHANNELSTATE(objPtr, storePtr) \
    ((objPtr)->internalRep.twoPtrValue.ptr1 = (void *) (storePtr))
#define GET_CHANNELINTERP(objPtr) \
    ((Tcl_Interp *) (objPtr)->internalRep.twoPtrValue.ptr2)
#define SET_CHANNELINTERP(objPtr, storePtr) \
    ((objPtr)->internalRep.twoPtrValue.ptr2 = (void *) (storePtr))

#define BUSY_STATE(st, fl) \
     ((((st)->csPtrR) && ((fl) & TCL_READABLE)) || \
      (((st)->csPtrW) && ((fl) & TCL_WRITABLE)))

3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
    if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) {
	return -1;
    }

    if (srcLen < 0) {
	srcLen = strlen(src);
    }
    return DoWrite(chanPtr, src, srcLen);
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_WriteRaw --
 *







|







3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
    if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) {
	return -1;
    }

    if (srcLen < 0) {
	srcLen = strlen(src);
    }
    return WriteBytes(chanPtr, src, srcLen);
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_WriteRaw --
 *
3857
3858
3859
3860
3861
3862
3863

3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918



3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929

3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
Tcl_WriteChars(
    Tcl_Channel chan,		/* The channel to buffer output for. */
    const char *src,		/* UTF-8 characters to queue in output
				 * buffer. */
    int len)			/* Length of string in bytes, or < 0 for
				 * strlen(). */
{

    ChannelState *statePtr;	/* State info for channel */

    statePtr = ((Channel *) chan)->state;

    if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) {
	return -1;
    }

    return DoWriteChars((Channel *) chan, src, len);
}

/*
 *---------------------------------------------------------------------------
 *
 * DoWriteChars --
 *
 *	Takes a sequence of UTF-8 characters and converts them for output
 *	using the channel's current encoding, may queue the buffer for output
 *	if it gets full, and also remembers whether the current buffer is
 *	ready e.g. if it contains a newline and we are in line buffering mode.
 *	Compensates stacking, i.e. will redirect the data from the specified
 *	channel to the topmost channel in a stack.
 *
 * Results:
 *	The number of bytes written or -1 in case of error. If -1,
 *	Tcl_GetErrno will return the error code.
 *
 * Side effects:
 *	May buffer up output and may cause output to be produced on the
 *	channel.
 *
 *----------------------------------------------------------------------
 */

static int
DoWriteChars(
    Channel *chanPtr,		/* The channel to buffer output for. */
    const char *src,		/* UTF-8 characters to queue in output
				 * buffer. */
    int len)			/* Length of string in bytes, or < 0 for
				 * strlen(). */
{
    /*
     * Always use the topmost channel of the stack
     */

    ChannelState *statePtr;	/* State info for channel */

    statePtr = chanPtr->state;
    chanPtr = statePtr->topChanPtr;

    if (len < 0) {
	len = strlen(src);
    }
    if (statePtr->encoding == NULL) {



	/*
	 * Inefficient way to convert UTF-8 to byte-array, but the code
	 * parallels the way it is done for objects.
	 * Special case for 1-byte (used by eg [puts] for the \n) could
	 * be extended to more efficient translation of the src string.
	 */

	int result;

	if ((len == 1) && (UCHAR(*src) < 0xC0)) {
	    result = WriteBytes(chanPtr, src, len);

	} else {
	    Tcl_Obj *objPtr = Tcl_NewStringObj(src, len);

	    src = (char *) Tcl_GetByteArrayFromObj(objPtr, &len);
	    result = WriteBytes(chanPtr, src, len);
	    TclDecrRefCount(objPtr);
	}
	return result;
    }
    return WriteChars(chanPtr, src, len);
}

/*
 *---------------------------------------------------------------------------
 *
 * Tcl_WriteObj --
 *







>
|
|
|





<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<





|
>
>
>
|
|
|
|
|
|

<
<
|
|
>
|
|
<
|
|
|
<
|
<
<







3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869









































3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885


3886
3887
3888
3889
3890

3891
3892
3893

3894


3895
3896
3897
3898
3899
3900
3901
Tcl_WriteChars(
    Tcl_Channel chan,		/* The channel to buffer output for. */
    const char *src,		/* UTF-8 characters to queue in output
				 * buffer. */
    int len)			/* Length of string in bytes, or < 0 for
				 * strlen(). */
{
    Channel *chanPtr = (Channel *) chan;
    ChannelState *statePtr = chanPtr->state;	/* State info for channel */
    int result;
    Tcl_Obj *objPtr;

    if (CheckChannelErrors(statePtr, TCL_WRITABLE) != 0) {
	return -1;
    }










































    chanPtr = statePtr->topChanPtr;

    if (len < 0) {
	len = strlen(src);
    }
    if (statePtr->encoding) {
	return WriteChars(chanPtr, src, len);
    }

    /*
     * Inefficient way to convert UTF-8 to byte-array, but the code
     * parallels the way it is done for objects.  Special case for 1-byte
     * (used by eg [puts] for the \n) could be extended to more efficient
     * translation of the src string.
     */



    if ((len == 1) && (UCHAR(*src) < 0xC0)) {
	return WriteBytes(chanPtr, src, len);
    }

    objPtr = Tcl_NewStringObj(src, len);

    src = (char *) Tcl_GetByteArrayFromObj(objPtr, &len);
    result = WriteBytes(chanPtr, src, len);
    TclDecrRefCount(objPtr);

    return result;


}

/*
 *---------------------------------------------------------------------------
 *
 * Tcl_WriteObj --
 *
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154

4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
    }
    return 0;
}

/*
 *----------------------------------------------------------------------
 *
 * WriteBytes --
 *
 *	Write a sequence of bytes into an output buffer, may queue the buffer
 *	for output if it gets full, and also remembers whether the current
 *	buffer is ready e.g. if it contains a newline and we are in line
 *	buffering mode.
 *
 * Results:
 *	The number of bytes written or -1 in case of error. If -1,
 *	Tcl_GetErrno will return the error code.
 *
 * Side effects:
 *	May buffer up output and may cause output to be produced on the
 *	channel.
 *
 *----------------------------------------------------------------------
 */

static int
WriteBytes(
    Channel *chanPtr,		/* The channel to buffer output for. */
    const char *src,		/* Bytes to write. */
    int srcLen)			/* Number of bytes to write. */
{
    ChannelState *statePtr = chanPtr->state;
				/* State info for channel */
    ChannelBuffer *bufPtr;
    char *dst;
    int dstMax, sawLF, savedLF, total, dstLen, toWrite, translate;

    if (srcLen) {
        WillWrite(chanPtr);
    }

    total = 0;
    sawLF = 0;
    savedLF = 0;
    translate = GotFlag(statePtr, CHANNEL_LINEBUFFERED)
	    || (statePtr->outputTranslation != TCL_TRANSLATE_LF);

    /*
     * Loop over all bytes in src, storing them in output buffer with proper
     * EOL translation.
     */

    while (srcLen + savedLF > 0) {
	bufPtr = statePtr->curOutPtr;
	if (bufPtr == NULL) {
	    bufPtr = AllocChannelBuffer(statePtr->bufSize);
	    statePtr->curOutPtr = bufPtr;
	}
	dst = InsertPoint(bufPtr);
	dstMax = SpaceLeft(bufPtr);
	dstLen = dstMax;

	toWrite = dstLen;
	if (toWrite > srcLen) {
	    toWrite = srcLen;
	}

	if (translate) {
	    if (savedLF) {
		/*
		 * A '\n' was left over from last call to TranslateOutputEOL()
		 * and we need to store it in this buffer. If the channel is
		 * line-based, we will need to flush it.
		 */

		*dst++ = '\n';
		dstLen--;
		sawLF++;
	    }
	    if (TranslateOutputEOL(statePtr, dst, src, &dstLen, &toWrite)) {
		sawLF++;
	    }
	    dstLen += savedLF;
	    savedLF = 0;
	    if (dstLen > dstMax) {
		savedLF = 1;
		dstLen = dstMax;
	    }
	} else {
	    memcpy(dst, src, toWrite);
	    dstLen = toWrite;
	}

	bufPtr->nextAdded += dstLen;
	if (CheckFlush(chanPtr, bufPtr, sawLF) != 0) {
	    return -1;
	}
	total += dstLen;
	src += toWrite;
	srcLen -= toWrite;
	sawLF = 0;
    }
    return total;
}

/*
 *----------------------------------------------------------------------
 *
 * WriteChars --
 *
 *	Convert UTF-8 bytes to the channel's external encoding and write the
 *	produced bytes into an output buffer, may queue the buffer for output
 *	if it gets full, and also remembers whether the current buffer is
 *	ready e.g. if it contains a newline and we are in line buffering mode.
 *
 * Results:
 *	The number of bytes written or -1 in case of error. If -1,
 *	Tcl_GetErrno will return the error code.
 *
 * Side effects:
 *	May buffer up output and may cause output to be produced on the
 *	channel.
 *
 *----------------------------------------------------------------------
 */

static int
WriteChars(
    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 */
    char *nextNewLine = NULL;
    int endEncoding, saved = 0, total = 0, flushed = 0, needNlFlush = 0;
    Tcl_Encoding encoding = statePtr->encoding;

    if (srcLen) {
        WillWrite(chanPtr);
    }

    /*
     * Write the terminated escape sequence even if srcLen is 0.







|

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
















|


|
>





<







3979
3980
3981
3982
3983
3984
3985
3986
3987















3988






















































































3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014

4015
4016
4017
4018
4019
4020
4021
    }
    return 0;
}

/*
 *----------------------------------------------------------------------
 *
 * Write --
 *















 *	Convert srcLen bytes starting at src according to encoding and write






















































































 *	produced bytes into an output buffer, may queue the buffer for output
 *	if it gets full, and also remembers whether the current buffer is
 *	ready e.g. if it contains a newline and we are in line buffering mode.
 *
 * Results:
 *	The number of bytes written or -1 in case of error. If -1,
 *	Tcl_GetErrno will return the error code.
 *
 * Side effects:
 *	May buffer up output and may cause output to be produced on the
 *	channel.
 *
 *----------------------------------------------------------------------
 */

static int
Write(
    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. */
    Tcl_Encoding encoding)
{
    ChannelState *statePtr = chanPtr->state;
				/* State info for channel */
    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.
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496

    return total;
}

/*
 *---------------------------------------------------------------------------
 *
 * TranslateOutputEOL --
 *
 *	Helper function for WriteBytes() and WriteChars(). Converts the '\n'
 *	characters in the source buffer into the appropriate EOL form
 *	specified by the output translation mode.
 *
 *	EOL translation stops either when the source buffer is empty or the
 *	output buffer is full.
 *
 *	When converting to CRLF mode and there is only 1 byte left in the
 *	output buffer, this routine stores the '\r' in the last byte and then
 *	stores the '\n' in the byte just past the end of the buffer. The
 *	caller is responsible for passing in a buffer that is large enough to
 *	hold the extra byte.
 *
 * Results:
 *	The return value is 1 if a '\n' was translated from the source buffer,
 *	or 0 otherwise -- this can be used by the caller to decide to flush a
 *	line-based channel even though the channel buffer is not full.
 *
 *	*dstLenPtr is filled with how many bytes of the output buffer were
 *	used. As mentioned above, this can be one more that the output
 *	buffer's specified length if a CRLF was stored.
 *
 *	*srcLenPtr is filled with how many bytes of the source buffer were
 *	consumed.
 *
 * Side effects:
 *	It may be obvious, but bears mentioning that when converting in CRLF
 *	mode (which requires two bytes of storage in the output buffer), the
 *	number of bytes consumed from the source buffer will be less than the
 *	number of bytes stored in the output buffer.
 *
 *---------------------------------------------------------------------------
 */

static int
TranslateOutputEOL(
    ChannelState *statePtr,	/* Channel being read, for translation and
				 * buffering modes. */
    char *dst,			/* Output buffer filled with UTF-8 chars by
				 * applying appropriate EOL translation to
				 * source characters. */
    const char *src,		/* Source UTF-8 characters. */
    int *dstLenPtr,		/* On entry, the maximum length of output
				 * buffer in bytes. On exit, the number of
				 * bytes actually used in output buffer. */
    int *srcLenPtr)		/* On entry, the length of source buffer. On
				 * exit, the number of bytes read from the
				 * source buffer. */
{
    char *dstEnd;
    int srcLen, newlineFound;

    newlineFound = 0;
    srcLen = *srcLenPtr;

    switch (statePtr->outputTranslation) {
    case TCL_TRANSLATE_LF:
	for (dstEnd = dst + srcLen; dst < dstEnd; ) {
	    if (*src == '\n') {
		newlineFound = 1;
	    }
	    *dst++ = *src++;
	}
	*dstLenPtr = srcLen;
	break;
    case TCL_TRANSLATE_CR:
	for (dstEnd = dst + srcLen; dst < dstEnd;) {
	    if (*src == '\n') {
		*dst++ = '\r';
		newlineFound = 1;
		src++;
	    } else {
		*dst++ = *src++;
	    }
	}
	*dstLenPtr = srcLen;
	break;
    case TCL_TRANSLATE_CRLF: {
	/*
	 * Since this causes the number of bytes to grow, we start off trying
	 * to put 'srcLen' bytes into the output buffer, but allow it to store
	 * more bytes, as long as there's still source bytes and room in the
	 * output buffer.
	 */

	char *dstStart, *dstMax;
	const char *srcStart;

	dstStart = dst;
	dstMax = dst + *dstLenPtr;

	srcStart = src;

	if (srcLen < *dstLenPtr) {
	    dstEnd = dst + srcLen;
	} else {
	    dstEnd = dst + *dstLenPtr;
	}
	while (dst < dstEnd) {
	    if (*src == '\n') {
		if (dstEnd < dstMax) {
		    dstEnd++;
		}
		*dst++ = '\r';
		newlineFound = 1;
	    }
	    *dst++ = *src++;
	}
	*srcLenPtr = src - srcStart;
	*dstLenPtr = dst - dstStart;
	break;
    }
    default:
	break;
    }
    return newlineFound;
}

/*
 *---------------------------------------------------------------------------
 *
 * CheckFlush --
 *
 *	Helper function for WriteBytes() and WriteChars(). If the channel
 *	buffer is ready to be flushed, flush it.
 *
 * Results:
 *	The return value is -1 if there was a problem flushing the channel
 *	buffer, or 0 otherwise.
 *
 * Side effects:
 *	The buffer will be recycled if it is flushed.
 *
 *---------------------------------------------------------------------------
 */

static int
CheckFlush(
    Channel *chanPtr,		/* Channel being read, for buffering mode. */
    ChannelBuffer *bufPtr,	/* Channel buffer to possibly flush. */
    int newlineFlag)		/* Non-zero if a the channel buffer contains a
				 * newline. */
{
    ChannelState *statePtr = chanPtr->state;
				/* State info for channel */

    /*
     * The current buffer is ready for output:
     * 1. if it is full.
     * 2. if it contains a newline and this channel is line-buffered.
     * 3. if it contains any output and this channel is unbuffered.
     */

    if (!GotFlag(statePtr, BUFFER_READY)) {
	if (IsBufferFull(bufPtr)) {
	    SetFlag(statePtr, BUFFER_READY);
	} else if (GotFlag(statePtr, CHANNEL_LINEBUFFERED)) {
	    if (newlineFlag != 0) {
		SetFlag(statePtr, BUFFER_READY);
	    }
	} else if (GotFlag(statePtr, CHANNEL_UNBUFFERED)) {
	    SetFlag(statePtr, BUFFER_READY);
	}
    }
    if (GotFlag(statePtr, BUFFER_READY)) {
	if (FlushChannel(NULL, chanPtr, 0) != 0) {
	    return -1;
	}
    }
    return 0;
}

/*
 *---------------------------------------------------------------------------
 *
 * Tcl_Gets --
 *
 *	Reads a complete line of input from the channel into a Tcl_DString.
 *
 * Results:
 *	Length of line read (in characters) or -1 if error, EOF, or blocked.
 *	If -1, use Tcl_GetErrno() to retrieve the POSIX error code for the







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







4160
4161
4162
4163
4164
4165
4166

















































































































































































4167
4168
4169
4170
4171
4172
4173

    return total;
}

/*
 *---------------------------------------------------------------------------
 *

















































































































































































 * Tcl_Gets --
 *
 *	Reads a complete line of input from the channel into a Tcl_DString.
 *
 * Results:
 *	Length of line read (in characters) or -1 if error, EOF, or blocked.
 *	If -1, use Tcl_GetErrno() to retrieve the POSIX error code for the
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626

    /*
     * If there is no encoding, use "iso8859-1" -- Tcl_GetsObj() doesn't
     * produce ByteArray objects.
     */

    if (encoding == NULL) {
	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

	if (tsdPtr->binaryEncoding == NULL) {
	    tsdPtr->binaryEncoding = Tcl_GetEncoding(NULL, "iso8859-1");
	    Tcl_CreateThreadExitHandler(FreeBinaryEncoding, NULL);
	}
	encoding = tsdPtr->binaryEncoding;
	if (encoding == NULL) {
	    Tcl_Panic("attempted gets on binary channel where no iso8859-1 encoding available");
	}
    }

    /*
     * Object used by FilterInputBytes to keep track of how much data has been
     * consumed from the channel buffers.
     */








<
<
|
<
<
<
<
<
<
<







4280
4281
4282
4283
4284
4285
4286


4287







4288
4289
4290
4291
4292
4293
4294

    /*
     * If there is no encoding, use "iso8859-1" -- Tcl_GetsObj() doesn't
     * produce ByteArray objects.
     */

    if (encoding == NULL) {


	encoding = GetBinaryEncoding();







    }

    /*
     * Object used by FilterInputBytes to keep track of how much data has been
     * consumed from the channel buffers.
     */

5178
5179
5180
5181
5182
5183
5184















5185
5186
5187
5188
5189
5190
5191
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    if (tsdPtr->binaryEncoding != NULL) {
	Tcl_FreeEncoding(tsdPtr->binaryEncoding);
	tsdPtr->binaryEncoding = NULL;
    }
}
















/*
 *---------------------------------------------------------------------------
 *
 * FilterInputBytes --
 *
 *	Helper function for Tcl_GetsObj. Produces UTF-8 characters from raw







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    if (tsdPtr->binaryEncoding != NULL) {
	Tcl_FreeEncoding(tsdPtr->binaryEncoding);
	tsdPtr->binaryEncoding = NULL;
    }
}

static Tcl_Encoding
GetBinaryEncoding()
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    if (tsdPtr->binaryEncoding == NULL) {
	tsdPtr->binaryEncoding = Tcl_GetEncoding(NULL, "iso8859-1");
	Tcl_CreateThreadExitHandler(FreeBinaryEncoding, NULL);
    }
    if (tsdPtr->binaryEncoding == NULL) {
	Tcl_Panic("binary encoding is not available");
    }
    return tsdPtr->binaryEncoding;
}

/*
 *---------------------------------------------------------------------------
 *
 * FilterInputBytes --
 *
 *	Helper function for Tcl_GetsObj. Produces UTF-8 characters from raw
9274
9275
9276
9277
9278
9279
9280
9281
9282
9283
9284
9285
9286
9287
9288
9289
9290
	    buffer = csPtr->buffer;
	    sizeb = size;
	} else {
	    buffer = TclGetStringFromObj(bufObj, &sizeb);
	}

	if (outBinary || sameEncoding) {
	    sizeb = DoWrite(outStatePtr->topChanPtr, buffer, sizeb);
	} else {
	    sizeb = DoWriteChars(outStatePtr->topChanPtr, buffer, sizeb);
	}

	/*
	 * [Bug 2895565]. At this point 'size' still contains the number of
	 * bytes or characters which have been read. We keep this to later to
	 * update the totals and toRead information, see marker (UP) below. We
	 * must not overwrite it with 'sizeb', which is the number of written







|

|







8957
8958
8959
8960
8961
8962
8963
8964
8965
8966
8967
8968
8969
8970
8971
8972
8973
	    buffer = csPtr->buffer;
	    sizeb = size;
	} else {
	    buffer = TclGetStringFromObj(bufObj, &sizeb);
	}

	if (outBinary || sameEncoding) {
	    sizeb = WriteBytes(outStatePtr->topChanPtr, buffer, sizeb);
	} else {
	    sizeb = WriteChars(outStatePtr->topChanPtr, buffer, sizeb);
	}

	/*
	 * [Bug 2895565]. At this point 'size' still contains the number of
	 * bytes or characters which have been read. We keep this to later to
	 * update the totals and toRead information, see marker (UP) below. We
	 * must not overwrite it with 'sizeb', which is the number of written
9824
9825
9826
9827
9828
9829
9830
9831
9832
9833
9834
9835
9836
9837
9838
9839
9840
9841
9842
9843
9844
9845
9846
9847
9848
9849
9850
9851
9852
9853
9854
9855
9856
9857
9858
9859
9860
9861
9862
9863
9864
9865
9866
9867
9868
9869
9870
9871
9872
9873
9874
9875
9876
9877
9878
9879
9880
9881
9882
9883
9884
9885
9886
9887
9888
9889
9890
9891
9892
9893
9894
9895
9896
9897
9898
9899
9900
9901
9902
9903
9904
9905
9906
9907
9908
9909
9910
9911
9912
9913
9914
9915
9916
9917
9918
9919
9920
9921
9922
9923
9924
9925
9926
9927
9928
9929
9930
9931
9932
9933
9934
9935
9936
9937
9938
9939
9940
9941
9942
9943
9944
9945
9946
9947
9948
9949
9950
9951
9952
9953
9954
9955
9956
9957
9958
9959
9960
9961
9962
9963
9964
9965
9966
9967
9968
9969
9970
9971
9972
9973
9974
9975
9976
9977
9978
9979
9980
9981
9982
9983
9984
9985
9986
9987
9988
9989
9990
9991
9992
9993

    /*
     * Return the number of characters copied into the result buffer.
     */

    return copied;
}

/*
 *----------------------------------------------------------------------
 *
 * DoWrite --
 *
 *	Puts a sequence of characters into an output buffer, may queue the
 *	buffer for output if it gets full, and also remembers whether the
 *	current buffer is ready e.g. if it contains a newline and we are in
 *	line buffering mode.
 *
 * Results:
 *	The number of bytes written or -1 in case of error. If -1,
 *	Tcl_GetErrno will return the error code.
 *
 * Side effects:
 *	May buffer up output and may cause output to be produced on the
 *	channel.
 *
 *----------------------------------------------------------------------
 */

static int
DoWrite(
    Channel *chanPtr,		/* The channel to buffer output for. */
    const char *src,		/* Data to write. */
    int srcLen)			/* Number of bytes to write. */
{
    ChannelState *statePtr = chanPtr->state;
				/* State info for channel */
    ChannelBuffer *outBufPtr;	/* Current output buffer. */
    int foundNewline;		/* Did we find a newline in output? */
    char *dPtr;
    const char *sPtr;		/* Search variables for newline. */
    int crsent;			/* In CRLF eol translation mode, remember the
				 * fact that a CR was output to the channel
				 * without its following NL. */
    int i;			/* Loop index for newline search. */
    int destCopied;		/* How many bytes were used in this
				 * destination buffer to hold the output? */
    int totalDestCopied;	/* How many bytes total were copied to the
				 * channel buffer? */
    int srcCopied;		/* How many bytes were copied from the source
				 * string? */
    char *destPtr;		/* Where in line to copy to? */

    /*
     * If we are in network (or windows) translation mode, record the fact
     * that we have not yet sent a CR to the channel.
     */

    crsent = 0;

    /*
     * Loop filling buffers and flushing them until all output has been
     * consumed.
     */

    srcCopied = 0;
    totalDestCopied = 0;

    while (srcLen > 0) {
	/*
	 * Make sure there is a current output buffer to accept output.
	 */

	if (statePtr->curOutPtr == NULL) {
	    statePtr->curOutPtr = AllocChannelBuffer(statePtr->bufSize);
	}

	outBufPtr = statePtr->curOutPtr;

	destCopied = SpaceLeft(outBufPtr);
	if (destCopied > srcLen) {
	    destCopied = srcLen;
	}

	destPtr = InsertPoint(outBufPtr);
	switch (statePtr->outputTranslation) {
	case TCL_TRANSLATE_LF:
	    srcCopied = destCopied;
	    memcpy(destPtr, src, (size_t) destCopied);
	    break;
	case TCL_TRANSLATE_CR:
	    srcCopied = destCopied;
	    memcpy(destPtr, src, (size_t) destCopied);
	    for (dPtr = destPtr; dPtr < destPtr + destCopied; dPtr++) {
		if (*dPtr == '\n') {
		    *dPtr = '\r';
		}
	    }
	    break;
	case TCL_TRANSLATE_CRLF:
	    for (srcCopied = 0, dPtr = destPtr, sPtr = src;
		    dPtr < destPtr + destCopied;
		    dPtr++, sPtr++, srcCopied++) {
		if (*sPtr == '\n') {
		    if (crsent) {
			*dPtr = '\n';
			crsent = 0;
		    } else {
			*dPtr = '\r';
			crsent = 1;
			sPtr--, srcCopied--;
		    }
		} else {
		    *dPtr = *sPtr;
		}
	    }
	    break;
	case TCL_TRANSLATE_AUTO:
	    Tcl_Panic("Tcl_Write: AUTO output translation mode not supported");
	default:
	    Tcl_Panic("Tcl_Write: unknown output translation mode");
	}

	/*
	 * The current buffer is ready for output if it is full, or if it
	 * contains a newline and this channel is line-buffered, or if it
	 * contains any output and this channel is unbuffered.
	 */

	outBufPtr->nextAdded += destCopied;
	if (!GotFlag(statePtr, BUFFER_READY)) {
	    if (IsBufferFull(outBufPtr)) {
		SetFlag(statePtr, BUFFER_READY);
	    } else if (GotFlag(statePtr, CHANNEL_LINEBUFFERED)) {
		for (sPtr = src, i = 0, foundNewline = 0;
			(i < srcCopied) && (!foundNewline);
			i++, sPtr++) {
		    if (*sPtr == '\n') {
			foundNewline = 1;
			break;
		    }
		}
		if (foundNewline) {
		    SetFlag(statePtr, BUFFER_READY);
		}
	    } else if (GotFlag(statePtr, CHANNEL_UNBUFFERED)) {
		SetFlag(statePtr, BUFFER_READY);
	    }
	}

	totalDestCopied += srcCopied;
	src += srcCopied;
	srcLen -= srcCopied;

	if (GotFlag(statePtr, BUFFER_READY)) {
	    if (FlushChannel(NULL, chanPtr, 0) != 0) {
		return -1;
	    }
	}
    } /* Closes "while" */

    return totalDestCopied;
}

/*
 *----------------------------------------------------------------------
 *
 * CopyEventProc --
 *
 *	This routine is invoked as a channel event handler for the background







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







9507
9508
9509
9510
9511
9512
9513




























































































































































9514
9515
9516
9517
9518
9519
9520

    /*
     * Return the number of characters copied into the result buffer.
     */

    return copied;
}





























































































































































/*
 *----------------------------------------------------------------------
 *
 * CopyEventProc --
 *
 *	This routine is invoked as a channel event handler for the background
11206
11207
11208
11209
11210
11211
11212
11213
11214
11215
11216
11217
11218
11219
11220
11221
11222
11223
11224
11225
DupChannelIntRep(
    register Tcl_Obj *srcPtr,	/* Object with internal rep to copy. Must have
				 * an internal rep of type "Channel". */
    register Tcl_Obj *copyPtr)	/* Object with internal rep to set. Must not
				 * currently have an internal rep.*/
{
    ChannelState *statePtr  = GET_CHANNELSTATE(srcPtr);
    Interp *interpPtr = GET_CHANNELINTERP(srcPtr);

    SET_CHANNELSTATE(copyPtr, statePtr);
    SET_CHANNELINTERP(copyPtr, interpPtr);
    Tcl_Preserve(statePtr);
    copyPtr->typePtr = &tclChannelType;
}

/*
 *----------------------------------------------------------------------
 *
 * SetChannelFromAny --
 *







<


|

|







10733
10734
10735
10736
10737
10738
10739

10740
10741
10742
10743
10744
10745
10746
10747
10748
10749
10750
10751
DupChannelIntRep(
    register Tcl_Obj *srcPtr,	/* Object with internal rep to copy. Must have
				 * an internal rep of type "Channel". */
    register Tcl_Obj *copyPtr)	/* Object with internal rep to set. Must not
				 * currently have an internal rep.*/
{
    ChannelState *statePtr  = GET_CHANNELSTATE(srcPtr);


    SET_CHANNELSTATE(copyPtr, statePtr);
    SET_CHANNELINTERP(copyPtr, GET_CHANNELINTERP(srcPtr));
    Tcl_Preserve(statePtr);
    copyPtr->typePtr = srcPtr->typePtr;
}

/*
 *----------------------------------------------------------------------
 *
 * SetChannelFromAny --
 *
11237
11238
11239
11240
11241
11242
11243
11244
11245
11246
11247
11248
11249
11250
11251
11252
11253
11254
11255
11256
11257
11258
11259
11260
11261
11262
11263
11264
11265
11266
11267
11268
11269
11270
11271
11272
11273
11274
11275
11276
11277
11278
11279
11280
11281
11282
11283
11284
11285
11286
11287
11288
11289
11290
11291
11292
11293
11294
11295
11296
11297
11298
11299
11300
11301
11302
11303
11304
11305
11306
11307
11308
11309
11310
11311
11312
11313
11314
11315
11316
11317
11318
11319
11320
11321
11322
11323
11324
11325
11326
11327
11328
11329
11330
11331
11332
11333
11334
11335
11336
11337
11338
11339

static int
SetChannelFromAny(
    Tcl_Interp *interp,		/* Used for error reporting if not NULL. */
    register Tcl_Obj *objPtr)	/* The object to convert. */
{
    ChannelState *statePtr;
    Interp *interpPtr;

    if (interp == NULL) {
	return TCL_ERROR;
    }
    if (objPtr->typePtr == &tclChannelType) {
	/*
	 * The channel is valid until any call to DetachChannel occurs.
	 * Ensure consistency checks are done.
	 */

	statePtr = GET_CHANNELSTATE(objPtr);
	interpPtr = GET_CHANNELINTERP(objPtr);
	if (GotFlag(statePtr, CHANNEL_TAINTED|CHANNEL_CLOSED)) {
	    ResetFlag(statePtr, CHANNEL_TAINTED);
	    Tcl_Release(statePtr);
	    UpdateStringOfChannel(objPtr);
	    objPtr->typePtr = NULL;
	} else if (interpPtr != (Interp*) interp) {
	    Tcl_Release(statePtr);
	    UpdateStringOfChannel(objPtr);
	    objPtr->typePtr = NULL;
	}
    }
    if (objPtr->typePtr != &tclChannelType) {
	Tcl_Channel chan;

	/*
	 * We need a valid string with which to check for a valid channel, but
	 * make sure not to free internal rep until validated. [Bug 1847044]
	 */

	if ((objPtr->typePtr != NULL) && (objPtr->bytes == NULL)) {
	    objPtr->typePtr->updateStringProc(objPtr);
	}

	chan = Tcl_GetChannel(interp, objPtr->bytes, NULL);
	if (chan == NULL) {
	    return TCL_ERROR;
	}

	TclFreeIntRep(objPtr);
	statePtr = ((Channel *) chan)->state;
	Tcl_Preserve(statePtr);
	SET_CHANNELSTATE(objPtr, statePtr);
	SET_CHANNELINTERP(objPtr, interp);
	objPtr->typePtr = &tclChannelType;
    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * UpdateStringOfChannel --
 *
 *	Update the string representation for an object whose internal
 *	representation is "Channel".
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The object's string may be set by converting its Unicode represention
 *	to UTF format.
 *
 *----------------------------------------------------------------------
 */

static void
UpdateStringOfChannel(
    Tcl_Obj *objPtr)		/* Object with string rep to update. */
{
    if (objPtr->bytes == NULL) {
	ChannelState *statePtr = GET_CHANNELSTATE(objPtr);
	const char *name = statePtr->channelName;

	if (name) {
	    size_t len = strlen(name);

	    objPtr->bytes = ckalloc(len + 1);
	    objPtr->length = len;
	    memcpy(objPtr->bytes, name, len);
	} else {
	    objPtr->bytes = tclEmptyStringRep;
	    objPtr->length = 0;
	}
    }
}

/*
 *----------------------------------------------------------------------
 *
 * FreeChannelIntRep --
 *
 *	Release statePtr storage.







<




|






<



<

|

<



|
|

<
<
<
<
<
<
<
<
<
<









|



<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







10763
10764
10765
10766
10767
10768
10769

10770
10771
10772
10773
10774
10775
10776
10777
10778
10779
10780

10781
10782
10783

10784
10785
10786

10787
10788
10789
10790
10791
10792










10793
10794
10795
10796
10797
10798
10799
10800
10801
10802
10803
10804
10805







































10806
10807
10808
10809
10810
10811
10812

static int
SetChannelFromAny(
    Tcl_Interp *interp,		/* Used for error reporting if not NULL. */
    register Tcl_Obj *objPtr)	/* The object to convert. */
{
    ChannelState *statePtr;


    if (interp == NULL) {
	return TCL_ERROR;
    }
    if (objPtr->typePtr == &chanObjType) {
	/*
	 * The channel is valid until any call to DetachChannel occurs.
	 * Ensure consistency checks are done.
	 */

	statePtr = GET_CHANNELSTATE(objPtr);

	if (GotFlag(statePtr, CHANNEL_TAINTED|CHANNEL_CLOSED)) {
	    ResetFlag(statePtr, CHANNEL_TAINTED);
	    Tcl_Release(statePtr);

	    objPtr->typePtr = NULL;
	} else if (interp != GET_CHANNELINTERP(objPtr)) {
	    Tcl_Release(statePtr);

	    objPtr->typePtr = NULL;
	}
    }
    if (objPtr->typePtr != &chanObjType) {
	Tcl_Channel chan = Tcl_GetChannel(interp, TclGetString(objPtr), NULL);











	if (chan == NULL) {
	    return TCL_ERROR;
	}

	TclFreeIntRep(objPtr);
	statePtr = ((Channel *) chan)->state;
	Tcl_Preserve(statePtr);
	SET_CHANNELSTATE(objPtr, statePtr);
	SET_CHANNELINTERP(objPtr, interp);
	objPtr->typePtr = &chanObjType;
    }
    return TCL_OK;
}








































/*
 *----------------------------------------------------------------------
 *
 * FreeChannelIntRep --
 *
 *	Release statePtr storage.

Changes to generic/tclInt.h.

2591
2592
2593
2594
2595
2596
2597


2598
2599
2600
2601
2602
2603
2604
 */

MODULE_SCOPE char *tclNativeExecutableName;
MODULE_SCOPE int tclFindExecutableSearchDone;
MODULE_SCOPE char *tclMemDumpFileName;
MODULE_SCOPE TclPlatformType tclPlatform;
MODULE_SCOPE Tcl_NotifierProcs tclNotifierHooks;



/*
 * TIP #233 (Virtualized Time)
 * Data for the time hooks, if any.
 */

MODULE_SCOPE Tcl_GetTimeProc *tclGetTimeProcPtr;







>
>







2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
 */

MODULE_SCOPE char *tclNativeExecutableName;
MODULE_SCOPE int tclFindExecutableSearchDone;
MODULE_SCOPE char *tclMemDumpFileName;
MODULE_SCOPE TclPlatformType tclPlatform;
MODULE_SCOPE Tcl_NotifierProcs tclNotifierHooks;

MODULE_SCOPE Tcl_Encoding tclIdentityEncoding;

/*
 * TIP #233 (Virtualized Time)
 * Data for the time hooks, if any.
 */

MODULE_SCOPE Tcl_GetTimeProc *tclGetTimeProcPtr;

Changes to unix/tclUnixInit.c.

861
862
863
864
865
866
867
868

869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
    Tcl_SetVar2(interp, "tcl_platform", "platform", "unix", TCL_GLOBAL_ONLY);
#endif

    unameOK = 0;
#ifdef __CYGWIN__
	unameOK = 1;
    if (!osInfoInitialized) {
      HANDLE handle = LoadLibraryW(L"NTDLL");

      int(*getversion)(void *) = (int(*)(void *))GetProcAddress(handle, "RtlGetVersion");
      osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
      if (!getversion || getversion(&osInfo)) {
        GetVersionExW(&osInfo);
      }
      if (handle) {
        FreeLibrary(handle);
      }
      osInfoInitialized = 1;
    }

    GetSystemInfo(&sysInfo);

    if (osInfo.dwPlatformId < NUMPLATFORMS) {
	Tcl_SetVar2(interp, "tcl_platform", "os",
		platforms[osInfo.dwPlatformId], TCL_GLOBAL_ONLY);







|
>
|
|
|
|
|
|
|
|
|







861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
    Tcl_SetVar2(interp, "tcl_platform", "platform", "unix", TCL_GLOBAL_ONLY);
#endif

    unameOK = 0;
#ifdef __CYGWIN__
	unameOK = 1;
    if (!osInfoInitialized) {
	HANDLE handle = LoadLibraryW(L"NTDLL");
	int(__stdcall *getversion)(void *) =
		(int(__stdcall *)(void *))GetProcAddress(handle, "RtlGetVersion");
	osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
	if (!getversion || getversion(&osInfo)) {
	    GetVersionExW(&osInfo);
	}
	if (handle) {
	    FreeLibrary(handle);
	}
	osInfoInitialized = 1;
    }

    GetSystemInfo(&sysInfo);

    if (osInfo.dwPlatformId < NUMPLATFORMS) {
	Tcl_SetVar2(interp, "tcl_platform", "os",
		platforms[osInfo.dwPlatformId], TCL_GLOBAL_ONLY);

Changes to win/tclWinInit.c.

536
537
538
539
540
541
542
543

544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
    TCHAR szUserName[UNLEN+1];
    DWORD cchUserNameLen = UNLEN;

    Tcl_SetVar2Ex(interp, "tclDefaultLibrary", NULL,
	    TclGetProcessGlobalValue(&defaultLibraryDir), TCL_GLOBAL_ONLY);

    if (!osInfoInitialized) {
      HANDLE handle = LoadLibraryW(L"NTDLL");

      int(*getversion)(void *) = (int(*)(void *))GetProcAddress(handle, "RtlGetVersion");
      osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
      if (!getversion || getversion(&osInfo)) {
        GetVersionExW(&osInfo);
      }
      if (handle) {
        FreeLibrary(handle);
      }
      osInfoInitialized = 1;
    }
    GetSystemInfo(&sys.info);

    /*
     * Define the tcl_platform array.
     */








|
>
|
|
|
|
|
|
|
|
|







536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
    TCHAR szUserName[UNLEN+1];
    DWORD cchUserNameLen = UNLEN;

    Tcl_SetVar2Ex(interp, "tclDefaultLibrary", NULL,
	    TclGetProcessGlobalValue(&defaultLibraryDir), TCL_GLOBAL_ONLY);

    if (!osInfoInitialized) {
	HANDLE handle = LoadLibraryW(L"NTDLL");
	int(__stdcall *getversion)(void *) =
		(int(__stdcall *)(void *)) GetProcAddress(handle, "RtlGetVersion");
	osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
	if (!getversion || getversion(&osInfo)) {
	    GetVersionExW(&osInfo);
	}
	if (handle) {
		FreeLibrary(handle);
	}
	osInfoInitialized = 1;
    }
    GetSystemInfo(&sys.info);

    /*
     * Define the tcl_platform array.
     */