diff options
| author | apnadkarni <apnmbx-wits@yahoo.com> | 2023-04-05 04:47:52 (GMT) |
|---|---|---|
| committer | apnadkarni <apnmbx-wits@yahoo.com> | 2023-04-05 04:47:52 (GMT) |
| commit | 543bde3f267b817f06c56f74d3480c691866ecb1 (patch) | |
| tree | e542ef53f829700969740db4e9d1f5b3e9a4a845 | |
| parent | d9bef75f08c6f69d631963242bdd1b887f8cb093 (diff) | |
| parent | 096c6ef84ff367ccee30eb44d9833fe3f61c45cc (diff) | |
| download | tcl-543bde3f267b817f06c56f74d3480c691866ecb1.zip tcl-543bde3f267b817f06c56f74d3480c691866ecb1.tar.gz tcl-543bde3f267b817f06c56f74d3480c691866ecb1.tar.bz2 | |
Merge 9.0
| -rw-r--r-- | doc/chan.n | 153 | ||||
| -rw-r--r-- | doc/fcopy.n | 114 | ||||
| -rw-r--r-- | generic/tclCompile.h | 4 | ||||
| -rw-r--r-- | generic/tclEncoding.c | 8 | ||||
| -rw-r--r-- | generic/tclExecute.c | 4 | ||||
| -rw-r--r-- | generic/tclIO.c | 110 | ||||
| -rw-r--r-- | generic/tclInt.h | 18 | ||||
| -rw-r--r-- | generic/tclLiteral.c | 2 | ||||
| -rw-r--r-- | generic/tclOO.c | 6 | ||||
| -rw-r--r-- | generic/tclOO.decls | 8 | ||||
| -rw-r--r-- | generic/tclOODefineCmds.c | 4 | ||||
| -rw-r--r-- | generic/tclOOIntDecls.h | 18 | ||||
| -rw-r--r-- | generic/tclObj.c | 20 | ||||
| -rw-r--r-- | generic/tclPathObj.c | 12 | ||||
| -rw-r--r-- | generic/tclUtil.c | 36 | ||||
| -rw-r--r-- | tests/chanio.test | 23 | ||||
| -rw-r--r-- | tests/io.test | 82 | ||||
| -rw-r--r-- | unix/dltest/pkgt.c | 4 | ||||
| -rw-r--r-- | unix/tclUnixInit.c | 2 | ||||
| -rw-r--r-- | win/tclWinInit.c | 2 |
20 files changed, 377 insertions, 253 deletions
@@ -226,50 +226,119 @@ typically used on UNIX platforms, .TP \fBchan copy \fIinputChan outputChan\fR ?\fB\-size \fIsize\fR? ?\fB\-command \fIcallback\fR? . -Copies data from \fIinputChan\fR to \fIoutputChan\fR, leveraging internal -buffers to avoid extra copies and to avoid buffering too much data in main -memory when copying large files to slow destinations like network sockets. +Reads characters from \fIinputChan\fR and writes them to \fIoutputChan\fR until +all characters are copied, blocking until the copy is complete and returning +the number of characters copied. Leverages internal buffers to avoid extra +copies and to avoid buffering too much data in main memory when copying large +files to slow destinations like network sockets. .RS .PP -If \fB\-size\fR is given, the size is in bytes if the two channels have the -same encoding and in characters otherwise, and only that amount is copied. -Otherwise, all data until the end of the file is copied. - -\fBchan copy\fR blocks until the copy is complete and returns the number of -bytes or characters written to \fIoutputChan\fR. -.PP -If \fB\-command\fR is given, \fBchan copy\fR returns immediately, the copy is -carried out in the background, and then \fIcallback\fR is called with the -number of bytes written to \fIoutputChan\fR as its first argument, and the -error message for any error that occurred as its second argument. -\fIinputChan\fR and \fIoutputChan\fR are automatically configured for -non-blocking mode if needed. Background copying only works correctly if the -event loop is active, e.g. via \fBvwait\fR or Tk. -.PP -During a background copy no other read or write operation may be performed on -\fIinputChan\fR or \fIoutputChan\fR. If either \fIinputChan\fR or -\fIoutputChan\fR is closed while the copy is in progress copying ceases and -\fBno\fR callback is made. If \fIinputChan\fR is closed all data already queued -is written to \fIoutputChan\fR. -.PP -The should be no event handler established for \fIinputChan\fR because it may -become readable during a background copy. An attempt to read or write -from within an event handler results result in the error, "channel busy". -.PP -Due to end-of-line translation the number of bytes read from \fIinputChan\fR -may be different than the number of bytes written to \fIoutputChan\fR. Only -the number of bytes written to \fIoutputChan\fR is reported. -.PP -\fBChan copy\fR reads the data according to the \fB\-encoding\fR, -\fB\-translation\fR, and \fB\-eofchar\fR of the source and writes to the -destination according to the configuration for that channel. If the encoding -and translation of both channels is \fBbinary\fR and the \fB\-eofchar\fR of -both channels is the empty string, an identical copy is made. If only the -encoding of the destination is \fBbinary\fR, Tcl's internal modified UTF-8 -representation of the characters read from the source is written to the -destination. If only the encoding of the source is \fBbinary\fR, each byte read -becomes one Unicode character in the range of 0 to 255, and that character is -subject to the encoding and translation of the destination as it is written. +\fB\-size\fR limits the number of characters copied. +.PP +If \fB\-command\fR is gviven, \fBchan copy\fR returns immediately, works in the +background, and calls \fIcallback\fR when the copy completes, providing as an +additional argument the number of characters written to \fIoutputChan\fR. If +an error occurres during the background copy, another argument provides message +for the error. \fIinputChan\fR and \fIoutputChan\fR are automatically +configured for non-blocking mode if needed. Background copying only works +correctly if events are being processed, e.g. via \fBvwait\fR or Tk. +.PP +During a background copy no other read operation may be performed on +\fIinputChan\fR, and no write operation may be performed on +\fIoutputChan\fR. However, write operations may by performed on +\fIinputChan\fR and read operations may be performed on \fIoutputChan\fR, as +exhibited by the bidirectional copy example below. +.PP +If either \fIinputChan\fR or \fIoutputChan\fR is closed while the copy is in +progress, copying ceases and \fBno\fR callback is made. If \fIinputChan\fR is +closed all data already queued is written to \fIoutputChan\fR. +.PP +There should be no event handler established for \fIinputChan\fR because it +may become readable during a background copy. An attempt to read or write from +within an event handler results result in the error, "channel busy". Any +wrong-sided I/O attempted (by a \fBfileevent\fR handler or otherwise) results +in a +.QW "channel busy" +error. +.PP +.PP +.IP \fBEXAMPLES\fR +.PP +The first example transfers the contents of one channel exactly to +another. Note that when copying one file to another, it is better to +use \fBfile copy\fR which also copies file metadata (e.g. the file +access permissions) where possible. +.PP +.CS +fconfigure $in -translation binary +fconfigure $out -translation binary +\fBfcopy\fR $in $out +.CE +.PP +This second example shows how the callback gets +passed the number of bytes transferred. +It also uses vwait to put the application into the event loop. +Of course, this simplified example could be done without the command +callback. +.PP +.CS +proc Cleanup {in out bytes {error {}}} { + global total + set total $bytes + close $in + close $out + if {[string length $error] != 0} { + # error occurred during the copy + } +} +set in [open $file1] +set out [socket $server $port] +\fBfcopy\fR $in $out -command [list Cleanup $in $out] +vwait total +.CE +.PP +The third example copies in chunks and tests for end of file +in the command callback. +.PP +.CS +proc CopyMore {in out chunk bytes {error {}}} { + global total done + incr total $bytes + if {([string length $error] != 0) || [eof $in]} { + set done $total + close $in + close $out + } else { + \fBfcopy\fR $in $out -size $chunk \e + -command [list CopyMore $in $out $chunk] + } +} +set in [open $file1] +set out [socket $server $port] +set chunk 1024 +set total 0 +\fBfcopy\fR $in $out -size $chunk \e + -command [list CopyMore $in $out $chunk] +vwait done +.CE +.PP +The fourth example starts an asynchronous, bidirectional fcopy between +two sockets. Those could also be pipes from two [open "|hal 9000" r+] +(though their conversation would remain secret to the script, since +all four fileevent slots are busy). +.PP +.CS +set flows 2 +proc Done {dir args} { + global flows done + puts "$dir is over." + incr flows -1 + if {$flows<=0} {set done 1} +} +\fBfcopy\fR $sok1 $sok2 -command [list Done UP] +\fBfcopy\fR $sok2 $sok1 -command [list Done DOWN] +vwait done +.CE .RE .TP \fBchan create \fImode cmdPrefix\fR diff --git a/doc/fcopy.n b/doc/fcopy.n index 477f242..b043898 100644 --- a/doc/fcopy.n +++ b/doc/fcopy.n @@ -12,90 +12,44 @@ .SH NAME fcopy \- Copy data from one channel to another .SH SYNOPSIS -\fBfcopy \fIinchan\fR \fIoutchan\fR ?\fB\-size \fIsize\fR? ?\fB\-command \fIcallback\fR? +\fBfcopy \fIinputChan\fR \fIoutputChan\fR ?\fB\-size \fIsize\fR? ?\fB\-command \fIcallback\fR? .BE .SH DESCRIPTION .PP -The \fBfcopy\fR command copies data from one I/O channel, \fIinchan\fR to another I/O channel, \fIoutchan\fR. -The \fBfcopy\fR command leverages the buffering in the Tcl I/O system to -avoid extra copies and to avoid buffering too much data in -main memory when copying large files to slow destinations like -network sockets. -.PP -The \fBfcopy\fR -command transfers data from \fIinchan\fR until end of file -or \fIsize\fR bytes or characters have been -transferred; \fIsize\fR is in bytes if the input channel is in binary mode, -and is in characters otherwise. -If no \fB\-size\fR argument is given, -then the copy goes until end of file. -All the data read from \fIinchan\fR is copied to \fIoutchan\fR. -Without the \fB\-command\fR option, \fBfcopy\fR blocks until the copy is complete -and returns the number of bytes or characters (using the same rules as -for the \fB\-size\fR option) written to \fIoutchan\fR. -.PP -The \fB\-command\fR argument makes \fBfcopy\fR work in the background. -In this case it returns immediately and the \fIcallback\fR is invoked -later when the copy completes. -The \fIcallback\fR is called with -one or two additional -arguments that indicates how many bytes were written to \fIoutchan\fR. -If an error occurred during the background copy, the second argument is the -error string associated with the error. -With a background copy, -it is not necessary to put \fIinchan\fR or \fIoutchan\fR into -non-blocking mode; the \fBfcopy\fR command takes care of that automatically. -However, it is necessary to enter the event loop by using -the \fBvwait\fR command or by using Tk. -.PP -You are not allowed to do other input operations with \fIinchan\fR, or -output operations with \fIoutchan\fR, during a background -\fBfcopy\fR. The converse is entirely legitimate, as exhibited by the -bidirectional fcopy example below. -.PP -If either \fIinchan\fR or \fIoutchan\fR get closed -while the copy is in progress, the current copy is stopped -and the command callback is \fInot\fR made. -If \fIinchan\fR is closed, -then all data already queued for \fIoutchan\fR is written out. -.PP -Note that \fIinchan\fR can become readable during a background copy. -You should turn off any \fBfileevent\fR handlers during a background -copy so those handlers do not interfere with the copy. -Any wrong-sided I/O attempted (by a \fBfileevent\fR handler or otherwise) will get a +Reads characters from \fIinputChan\fR and writes them to \fIoutputChan\fR until +all characters are copied, blocking until the copy is complete and returning +the number of characters copied. Leverages internal buffers to avoid extra +copies and to avoid buffering too much data in main memory when copying large +files to slow destinations like network sockets. +.PP +\fB\-size\fR limits the number of characters copied. +.PP +\fB\-command\fR makes \fBfcopy\fR return immediately, work in the background, +and call \fIcallback\fR when the copy completes, providing as an additional +argument the number of characters written to \fIoutputChan\fR. If an error +occurres during the background copy, another argument provides the message for +the error. \fIinputChan\fR and \fIoutputChan\fR are automatically configured +for non-blocking mode if needed. Background copying only works correctly if +events are being processed e.g. via \fBvwait\fR or Tk. +.PP +During a background copy no other read operation may be performed on +\fIinputChan\fR, and no other write operation may be performed on +\fIoutputChan\fR. However, write operations may by performed on +\fIinputChan\fR and read operations may be performed on \fIoutputChan\fR, as +exhibited by the bidirectional copy example below. +.PP +If either \fIinputChan\fR or \fIoutputChan\fR is closed while the copy is in +progress, copying ceases and \fBno\fR callback is made. If \fIinputChan\fR is +closed all data already queued is written to \fIoutputChan\fR. +.PP +There should be no event handler established for \fIinputChan\fR because it +may become readable during a background copy. An attempt to read or write from +within an event handler results result in the error, "channel busy". Any +wrong-sided I/O attempted (by a \fBfileevent\fR handler or otherwise) results +in a .QW "channel busy" error. -.PP -\fBFcopy\fR translates end-of-line sequences in \fIinchan\fR and \fIoutchan\fR -according to the \fB\-translation\fR option -for these channels. -See the manual entry for \fBfconfigure\fR for details on the -\fB\-translation\fR option. -The translations mean that the number of bytes read from \fIinchan\fR -can be different than the number of bytes written to \fIoutchan\fR. -Only the number of bytes written to \fIoutchan\fR is reported, -either as the return value of a synchronous \fBfcopy\fR or -as the argument to the callback for an asynchronous \fBfcopy\fR. -.PP -\fBFcopy\fR obeys the encodings and character translations configured -for the channels. This -means that the incoming characters are converted internally first -UTF-8 and then into the encoding of the channel \fBfcopy\fR writes -to. See the manual entry for \fBfconfigure\fR for details on the -\fB\-encoding\fR and \fB\-translation\fR options. No conversion is -done if both channels are -set to encoding -.QW binary -and have matching translations. If only the output channel is set to encoding -.QW binary -the system will write the internal UTF-8 representation of the incoming -characters. If only the input channel is set to encoding -.QW binary -the system will assume that the incoming -bytes are valid UTF-8 characters and convert them according to the -output encoding. The behaviour of the system for bytes which are not -valid UTF-8 characters is undefined in this case. .SH EXAMPLES .PP The first example transfers the contents of one channel exactly to @@ -144,7 +98,7 @@ proc CopyMore {in out chunk bytes {error {}}} { close $out } else { \fBfcopy\fR $in $out -size $chunk \e - -command [list CopyMore $in $out $chunk] + -command [list CopyMore $in $out $chunk] } } set in [open $file1] @@ -152,7 +106,7 @@ set out [socket $server $port] set chunk 1024 set total 0 \fBfcopy\fR $in $out -size $chunk \e - -command [list CopyMore $in $out $chunk] + -command [list CopyMore $in $out $chunk] vwait done .CE .PP diff --git a/generic/tclCompile.h b/generic/tclCompile.h index 5772dec..bb3c42e 100644 --- a/generic/tclCompile.h +++ b/generic/tclCompile.h @@ -1115,7 +1115,7 @@ MODULE_SCOPE Tcl_Size TclCreateExceptRange(ExceptionRangeType type, CompileEnv *envPtr); MODULE_SCOPE ExecEnv * TclCreateExecEnv(Tcl_Interp *interp, size_t size); MODULE_SCOPE Tcl_Obj * TclCreateLiteral(Interp *iPtr, const char *bytes, - Tcl_Size length, TCL_HASH_TYPE hash, int *newPtr, + Tcl_Size length, size_t hash, int *newPtr, Namespace *nsPtr, int flags, LiteralEntry **globalPtrPtr); MODULE_SCOPE void TclDeleteExecEnv(ExecEnv *eePtr); @@ -1129,7 +1129,7 @@ MODULE_SCOPE ExceptionRange * TclGetExceptionRangeForPc(unsigned char *pc, MODULE_SCOPE void TclExpandJumpFixupArray(JumpFixupArray *fixupArrayPtr); MODULE_SCOPE int TclNRExecuteByteCode(Tcl_Interp *interp, ByteCode *codePtr); -MODULE_SCOPE Tcl_Obj * TclFetchLiteral(CompileEnv *envPtr, int index); +MODULE_SCOPE Tcl_Obj * TclFetchLiteral(CompileEnv *envPtr, Tcl_Size index); MODULE_SCOPE Tcl_Size TclFindCompiledLocal(const char *name, Tcl_Size nameChars, int create, CompileEnv *envPtr); MODULE_SCOPE int TclFixupForwardJump(CompileEnv *envPtr, diff --git a/generic/tclEncoding.c b/generic/tclEncoding.c index 37e8638..f73666e 100644 --- a/generic/tclEncoding.c +++ b/generic/tclEncoding.c @@ -2570,8 +2570,7 @@ UtfToUtfProc( } } else { /* - * Convert 0xC080 to real nulls when we are in output mode, - * irrespective of the profile. + * For output convert 0xC080 to a real null. */ *dst++ = 0; src += 2; @@ -2822,6 +2821,11 @@ Utf32ToUtfProc( if ((unsigned)ch - 1 < 0x7F) { *dst++ = (ch & 0xFF); } else { +#if TCL_UTF_MAX < 4 + if (!HIGH_SURROGATE(prev) && LOW_SURROGATE(ch)) { + *dst = 0; /* In case of lower surrogate, don't try to combine */ + } +#endif dst += Tcl_UniCharToUtf(ch, dst); } src += 4; diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 047fff5..356f522 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -1240,13 +1240,13 @@ void * TclStackRealloc( Tcl_Interp *interp, void *ptr, - size_t numBytes) + Tcl_Size numBytes) { Interp *iPtr = (Interp *) interp; ExecEnv *eePtr; ExecStack *esPtr; Tcl_Obj **markerPtr; - size_t numWords; + Tcl_Size numWords; if (iPtr == NULL || iPtr->execEnvPtr == NULL) { return Tcl_Realloc(ptr, numBytes); diff --git a/generic/tclIO.c b/generic/tclIO.c index 2ae4290..c5e6965 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -174,6 +174,8 @@ static int CloseWrite(Tcl_Interp *interp, Channel *chanPtr); static void CommonGetsCleanup(Channel *chanPtr); static int CopyData(CopyState *csPtr, int mask); static void DeleteTimerHandler(ChannelState *statePtr); +int Lossless(ChannelState *inStatePtr, + ChannelState *outStatePtr, long long toRead); static int MoveBytes(CopyState *csPtr); static void MBCallback(CopyState *csPtr, Tcl_Obj *errObj); @@ -196,7 +198,7 @@ static void DiscardOutputQueued(ChannelState *chanPtr); static Tcl_Size DoRead(Channel *chanPtr, char *dst, Tcl_Size bytesToRead, int allowShortReads); static Tcl_Size DoReadChars(Channel *chan, Tcl_Obj *objPtr, Tcl_Size toRead, - int appendFlag); + int allowShortReads, int appendFlag); static int FilterInputBytes(Channel *chanPtr, GetsState *statePtr); static int FlushChannel(Tcl_Interp *interp, Channel *chanPtr, @@ -338,6 +340,9 @@ static const Tcl_ObjType chanObjType = { TCL_OBJTYPE_V0 }; +#define GetIso88591() \ + (binaryEncoding ? Tcl_GetEncoding(NULL, "iso8859-1") : binaryEncoding) + #define ChanSetInternalRep(objPtr, resPtr) \ do { \ Tcl_ObjInternalRep ir; \ @@ -5899,7 +5904,7 @@ Tcl_ReadChars( return TCL_INDEX_NONE; } - return DoReadChars(chanPtr, objPtr, toRead, appendFlag); + return DoReadChars(chanPtr, objPtr, toRead, 0, appendFlag); } /* *--------------------------------------------------------------------------- @@ -5930,6 +5935,7 @@ DoReadChars( Tcl_Size toRead, /* Maximum number of characters to store, or * TCL_INDEX_NONE to read all available data (up to EOF or * when channel blocks). */ + int allowShortReads, /* Allow half-blocking (pipes,sockets) */ int appendFlag) /* If non-zero, data read from the channel * will be appended to the object. Otherwise, * the data will replace the existing contents @@ -6070,8 +6076,8 @@ DoReadChars( if (GotFlag(statePtr, CHANNEL_EOF)) { break; } - if (GotFlag(statePtr, CHANNEL_NONBLOCKING|CHANNEL_BLOCKED) - == (CHANNEL_NONBLOCKING|CHANNEL_BLOCKED)) { + if ((GotFlag(statePtr, CHANNEL_NONBLOCKING) || allowShortReads) + && GotFlag(statePtr, CHANNEL_BLOCKED)) { break; } result = GetInput(chanPtr); @@ -9363,18 +9369,7 @@ TclCopyChannel( ResetFlag(outStatePtr, CHANNEL_LINEBUFFERED); SetFlag(outStatePtr, CHANNEL_UNBUFFERED); - /* - * Test for conditions where we know we can just move bytes from input - * channel to output channel with no transformation or even examination - * of the bytes themselves. - */ - - moveBytes = inStatePtr->inEofChar == '\0' /* No eofChar to stop input */ - && inStatePtr->inputTranslation == TCL_TRANSLATE_LF - && outStatePtr->outputTranslation == TCL_TRANSLATE_LF - && inStatePtr->encoding == outStatePtr->encoding - && CHANNEL_PROFILE_GET(inStatePtr->inputEncodingFlags) == TCL_ENCODING_PROFILE_TCL8 - && CHANNEL_PROFILE_GET(outStatePtr->outputEncodingFlags) == TCL_ENCODING_PROFILE_TCL8; + moveBytes = Lossless(inStatePtr, outStatePtr, toRead); /* * Allocate a new CopyState to maintain info about the current copy in @@ -9681,8 +9676,7 @@ CopyData( Tcl_WideInt total; Tcl_WideInt size; const char *buffer; - int inBinary, outBinary, sameEncoding; - /* Encoding control */ + int moveBytes; int underflow; /* Input underflow */ inChan = (Tcl_Channel) csPtr->readPtr; @@ -9700,13 +9694,9 @@ CopyData( * the bottom of the stack. */ - inBinary = (inStatePtr->encoding == NULL); - outBinary = (outStatePtr->encoding == NULL); - sameEncoding = inStatePtr->encoding == outStatePtr->encoding - && CHANNEL_PROFILE_GET(inStatePtr->inputEncodingFlags) == TCL_ENCODING_PROFILE_TCL8 - && CHANNEL_PROFILE_GET(outStatePtr->outputEncodingFlags) == TCL_ENCODING_PROFILE_TCL8; + moveBytes = Lossless(inStatePtr, outStatePtr, csPtr->toRead); - if (!(inBinary || sameEncoding)) { + if (!moveBytes) { TclNewObj(bufObj); Tcl_IncrRefCount(bufObj); } @@ -9747,7 +9737,7 @@ CopyData( underflow = 1; } else { /* - * Read up to bufSize bytes. + * Read up to bufSize characters. */ if ((csPtr->toRead == (Tcl_WideInt) -1) @@ -9757,12 +9747,13 @@ CopyData( sizeb = csPtr->toRead; } - if (inBinary || sameEncoding) { + if (moveBytes) { size = DoRead(inStatePtr->topChanPtr, csPtr->buffer, sizeb, !GotFlag(inStatePtr, CHANNEL_NONBLOCKING)); } else { size = DoReadChars(inStatePtr->topChanPtr, bufObj, sizeb, - 0 /* No append */); + !GotFlag(inStatePtr, CHANNEL_NONBLOCKING) + ,0 /* No append */); } underflow = (size >= 0) && (size < sizeb); /* Input underflow */ } @@ -9823,25 +9814,20 @@ CopyData( * Now write the buffer out. */ - if (inBinary || sameEncoding) { + if (moveBytes) { buffer = csPtr->buffer; - sizeb = size; + sizeb = WriteBytes(outStatePtr->topChanPtr, buffer, size); } else { buffer = Tcl_GetStringFromObj(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 + * 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 - * bytes or characters, and both EOL translation and encoding + * characters, and both EOL translation and encoding * conversion may have changed this number unpredictably in relation * to 'size' (It can be smaller or larger, in the latter case able to * drive toRead below -1, causing infinite looping). Completely @@ -9868,10 +9854,10 @@ CopyData( } /* - * Update the current byte count. Do it now so the count is valid + * Update the current character count. Do it now so the count is valid * before a return or break takes us out of the loop. The invariant at * the top of the loop should be that csPtr->toRead holds the number - * of bytes left to copy. + * of characters left to copy. */ if (csPtr->toRead != -1) { @@ -9938,8 +9924,8 @@ CopyData( } /* - * Make the callback or return the number of bytes transferred. The local - * total is used because StopCopy frees csPtr. + * Make the callback or return the number of characters transferred. The + * local total is used because StopCopy frees csPtr. */ total = csPtr->total; @@ -10262,6 +10248,50 @@ CopyEventProc( /* *---------------------------------------------------------------------- * + * Lossless -- + * + * Determines whether copying characters between two channel states would + * be lossless, i.e. whether one byte corresponds to one character, every + * character appears in the Unicode character set, there are no + * translations to be performed, and no inline signals to respond to. + * + * Result: + * True if copying would be lossless. + * + *---------------------------------------------------------------------- + */ +int +Lossless( + ChannelState *inStatePtr, + ChannelState *outStatePtr, + long long toRead) +{ + return inStatePtr->inEofChar == '\0' /* No eofChar to stop input */ + && inStatePtr->inputTranslation == TCL_TRANSLATE_LF + && outStatePtr->outputTranslation == TCL_TRANSLATE_LF + && ( + ( + (inStatePtr->encoding == NULL + || inStatePtr->encoding == GetBinaryEncoding() + ) + && + (outStatePtr->encoding == NULL + || outStatePtr->encoding == GetBinaryEncoding() + ) + ) + || + ( + toRead == -1 + && inStatePtr->encoding == outStatePtr->encoding + && CHANNEL_PROFILE_GET(inStatePtr->inputEncodingFlags) == TCL_ENCODING_PROFILE_TCL8 + && CHANNEL_PROFILE_GET(outStatePtr->inputEncodingFlags) == TCL_ENCODING_PROFILE_TCL8 + ) + ); +} + +/* + *---------------------------------------------------------------------- + * * StopCopy -- * * This routine halts a copy that is in progress. diff --git a/generic/tclInt.h b/generic/tclInt.h index 5b9762d..e65a3ee 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -3076,8 +3076,8 @@ MODULE_SCOPE int TclAsyncNotifier(int sigNumber, Tcl_ThreadId threadId, MODULE_SCOPE void TclAsyncMarkFromNotifier(void); MODULE_SCOPE double TclBignumToDouble(const void *bignum); MODULE_SCOPE int TclByteArrayMatch(const unsigned char *string, - size_t strLen, const unsigned char *pattern, - size_t ptnLen, int flags); + Tcl_Size strLen, const unsigned char *pattern, + Tcl_Size ptnLen, int flags); MODULE_SCOPE double TclCeil(const void *a); MODULE_SCOPE void TclChannelPreserve(Tcl_Channel chan); MODULE_SCOPE void TclChannelRelease(Tcl_Channel chan); @@ -3090,7 +3090,7 @@ MODULE_SCOPE Tcl_ObjCmdProc TclChannelNamesCmd; MODULE_SCOPE Tcl_NRPostProc TclClearRootEnsemble; MODULE_SCOPE int TclCompareTwoNumbers(Tcl_Obj *valuePtr, Tcl_Obj *value2Ptr); -MODULE_SCOPE ContLineLoc *TclContinuationsEnter(Tcl_Obj *objPtr, size_t num, +MODULE_SCOPE ContLineLoc *TclContinuationsEnter(Tcl_Obj *objPtr, Tcl_Size num, int *loc); MODULE_SCOPE void TclContinuationsEnterDerived(Tcl_Obj *objPtr, int start, int *clNext); @@ -3220,7 +3220,7 @@ MODULE_SCOPE void TclInitObjSubsystem(void); MODULE_SCOPE int TclInterpReady(Tcl_Interp *interp); MODULE_SCOPE int TclIsDigitProc(int byte); MODULE_SCOPE int TclIsBareword(int byte); -MODULE_SCOPE Tcl_Obj * TclJoinPath(size_t elements, Tcl_Obj * const objv[], +MODULE_SCOPE Tcl_Obj * TclJoinPath(Tcl_Size elements, Tcl_Obj * const objv[], int forceRelative); MODULE_SCOPE int MakeTildeRelativePath(Tcl_Interp *interp, const char *user, const char *subPath, Tcl_DString *dsPtr); @@ -3285,7 +3285,7 @@ MODULE_SCOPE Tcl_Obj * TclpTempFileName(void); MODULE_SCOPE Tcl_Obj * TclpTempFileNameForLibrary(Tcl_Interp *interp, Tcl_Obj* pathPtr); MODULE_SCOPE Tcl_Obj * TclNewFSPathObj(Tcl_Obj *dirPtr, const char *addStrRep, - size_t len); + Tcl_Size len); MODULE_SCOPE void TclpAlertNotifier(void *clientData); MODULE_SCOPE void *TclpNotifierData(void); MODULE_SCOPE void TclpServiceModeHook(int mode); @@ -3360,9 +3360,9 @@ MODULE_SCOPE void TclRememberJoinableThread(Tcl_ThreadId id); MODULE_SCOPE void TclRememberMutex(Tcl_Mutex *mutex); MODULE_SCOPE void TclRemoveScriptLimitCallbacks(Tcl_Interp *interp); MODULE_SCOPE int TclReToGlob(Tcl_Interp *interp, const char *reStr, - size_t reStrLen, Tcl_DString *dsPtr, int *flagsPtr, + Tcl_Size reStrLen, Tcl_DString *dsPtr, int *flagsPtr, int *quantifiersFoundPtr); -MODULE_SCOPE TCL_HASH_TYPE TclScanElement(const char *string, Tcl_Size length, +MODULE_SCOPE Tcl_Size TclScanElement(const char *string, Tcl_Size length, char *flagPtr); MODULE_SCOPE void TclSetBgErrorHandler(Tcl_Interp *interp, Tcl_Obj *cmdPrefix); @@ -3380,14 +3380,14 @@ MODULE_SCOPE void TclSpellFix(Tcl_Interp *interp, Tcl_Obj *const *objv, Tcl_Size objc, Tcl_Size subIdx, Tcl_Obj *bad, Tcl_Obj *fix); MODULE_SCOPE void * TclStackRealloc(Tcl_Interp *interp, void *ptr, - size_t numBytes); + Tcl_Size numBytes); typedef int (*memCmpFn_t)(const void*, const void*, size_t); MODULE_SCOPE int TclStringCmp(Tcl_Obj *value1Ptr, Tcl_Obj *value2Ptr, int checkEq, int nocase, Tcl_Size reqlength); MODULE_SCOPE int TclStringCmpOpts(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], int *nocase, int *reqlength); -MODULE_SCOPE int TclStringMatch(const char *str, size_t strLen, +MODULE_SCOPE int TclStringMatch(const char *str, Tcl_Size strLen, const char *pattern, int ptnLen, int flags); MODULE_SCOPE int TclStringMatchObj(Tcl_Obj *stringObj, Tcl_Obj *patternObj, int flags); diff --git a/generic/tclLiteral.c b/generic/tclLiteral.c index 9bc9d10..17546b8 100644 --- a/generic/tclLiteral.c +++ b/generic/tclLiteral.c @@ -351,7 +351,7 @@ Tcl_Obj * TclFetchLiteral( CompileEnv *envPtr, /* Points to the CompileEnv from which to * fetch the registered literal value. */ - int index) /* Index of the desired literal, as returned + Tcl_Size index) /* Index of the desired literal, as returned * by prior call to TclRegisterLiteral() */ { if (index >= envPtr->literalArrayNext) { diff --git a/generic/tclOO.c b/generic/tclOO.c index b4c739e..64f769c 100644 --- a/generic/tclOO.c +++ b/generic/tclOO.c @@ -2556,7 +2556,7 @@ TclOOInvokeObject( * (PRIVATE_METHOD), or a *really* private * context (any other value; conventionally * 0). */ - size_t objc, /* Number of arguments. */ + Tcl_Size objc, /* Number of arguments. */ Tcl_Obj *const *objv) /* Array of argument objects. It is assumed * that the name of the method to invoke will * be at index 1. */ @@ -2627,7 +2627,7 @@ int TclOOObjectCmdCore( Object *oPtr, /* The object being invoked. */ Tcl_Interp *interp, /* The interpreter containing the object. */ - size_t objc, /* How many arguments are being passed in. */ + Tcl_Size objc, /* How many arguments are being passed in. */ Tcl_Obj *const *objv, /* The array of arguments. */ int flags, /* Whether this is an invocation through the * public or the private command interface. */ @@ -2648,7 +2648,7 @@ TclOOObjectCmdCore( * processing. */ - if (objc + 1 < 3) { + if (objc < 2) { flags |= FORCE_UNKNOWN; methodNamePtr = NULL; goto noMapping; diff --git a/generic/tclOO.decls b/generic/tclOO.decls index 44fda7d..2df34d0 100644 --- a/generic/tclOO.decls +++ b/generic/tclOO.decls @@ -184,7 +184,7 @@ declare 4 { ProcedureMethod **pmPtrPtr) } declare 5 { - int TclOOObjectCmdCore(Object *oPtr, Tcl_Interp *interp, size_t objc, + int TclOOObjectCmdCore(Object *oPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const *objv, int publicOnly, Class *startCls) } declare 6 { @@ -214,7 +214,7 @@ declare 10 { } declare 11 { int TclOOInvokeObject(Tcl_Interp *interp, Tcl_Object object, - Tcl_Class startCls, int publicPrivate, size_t objc, + Tcl_Class startCls, int publicPrivate, Tcl_Size objc, Tcl_Obj *const *objv) } declare 12 { @@ -226,12 +226,12 @@ declare 13 { Tcl_Size numFilters, Tcl_Obj *const *filters) } declare 14 { - void TclOOObjectSetMixins(Object *oPtr, size_t numMixins, + void TclOOObjectSetMixins(Object *oPtr, Tcl_Size numMixins, Class *const *mixins) } declare 15 { void TclOOClassSetMixins(Tcl_Interp *interp, Class *classPtr, - size_t numMixins, Class *const *mixins) + Tcl_Size numMixins, Class *const *mixins) } return diff --git a/generic/tclOODefineCmds.c b/generic/tclOODefineCmds.c index f559786..bde8203 100644 --- a/generic/tclOODefineCmds.c +++ b/generic/tclOODefineCmds.c @@ -371,7 +371,7 @@ TclOOClassSetFilters( void TclOOObjectSetMixins( Object *oPtr, - size_t numMixins, + Tcl_Size numMixins, Class *const *mixins) { Class *mixinPtr; @@ -432,7 +432,7 @@ void TclOOClassSetMixins( Tcl_Interp *interp, Class *classPtr, - size_t numMixins, + Tcl_Size numMixins, Class *const *mixins) { Class *mixinPtr; diff --git a/generic/tclOOIntDecls.h b/generic/tclOOIntDecls.h index 17c20b6..730a73a 100644 --- a/generic/tclOOIntDecls.h +++ b/generic/tclOOIntDecls.h @@ -42,7 +42,7 @@ TCLAPI Method * TclOONewProcMethod(Tcl_Interp *interp, Class *clsPtr, ProcedureMethod **pmPtrPtr); /* 5 */ TCLAPI int TclOOObjectCmdCore(Object *oPtr, Tcl_Interp *interp, - size_t objc, Tcl_Obj *const *objv, + Tcl_Size objc, Tcl_Obj *const *objv, int publicOnly, Class *startCls); /* 6 */ TCLAPI int TclOOIsReachable(Class *targetPtr, Class *startPtr); @@ -75,7 +75,7 @@ TCLAPI Tcl_Method TclOONewProcMethodEx(Tcl_Interp *interp, /* 11 */ TCLAPI int TclOOInvokeObject(Tcl_Interp *interp, Tcl_Object object, Tcl_Class startCls, - int publicPrivate, size_t objc, + int publicPrivate, Tcl_Size objc, Tcl_Obj *const *objv); /* 12 */ TCLAPI void TclOOObjectSetFilters(Object *oPtr, @@ -85,11 +85,11 @@ TCLAPI void TclOOClassSetFilters(Tcl_Interp *interp, Class *classPtr, Tcl_Size numFilters, Tcl_Obj *const *filters); /* 14 */ -TCLAPI void TclOOObjectSetMixins(Object *oPtr, size_t numMixins, - Class *const *mixins); +TCLAPI void TclOOObjectSetMixins(Object *oPtr, + Tcl_Size numMixins, Class *const *mixins); /* 15 */ TCLAPI void TclOOClassSetMixins(Tcl_Interp *interp, - Class *classPtr, size_t numMixins, + Class *classPtr, Tcl_Size numMixins, Class *const *mixins); typedef struct TclOOIntStubs { @@ -101,17 +101,17 @@ typedef struct TclOOIntStubs { Tcl_Method (*tclOOMakeProcMethod) (Tcl_Interp *interp, Class *clsPtr, int flags, Tcl_Obj *nameObj, const char *namePtr, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, const Tcl_MethodType *typePtr, void *clientData, Proc **procPtrPtr); /* 2 */ Method * (*tclOONewProcInstanceMethod) (Tcl_Interp *interp, Object *oPtr, int flags, Tcl_Obj *nameObj, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, ProcedureMethod **pmPtrPtr); /* 3 */ Method * (*tclOONewProcMethod) (Tcl_Interp *interp, Class *clsPtr, int flags, Tcl_Obj *nameObj, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, ProcedureMethod **pmPtrPtr); /* 4 */ - int (*tclOOObjectCmdCore) (Object *oPtr, Tcl_Interp *interp, size_t objc, Tcl_Obj *const *objv, int publicOnly, Class *startCls); /* 5 */ + int (*tclOOObjectCmdCore) (Object *oPtr, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const *objv, int publicOnly, Class *startCls); /* 5 */ int (*tclOOIsReachable) (Class *targetPtr, Class *startPtr); /* 6 */ Method * (*tclOONewForwardMethod) (Tcl_Interp *interp, Class *clsPtr, int isPublic, Tcl_Obj *nameObj, Tcl_Obj *prefixObj); /* 7 */ Method * (*tclOONewForwardInstanceMethod) (Tcl_Interp *interp, Object *oPtr, int isPublic, Tcl_Obj *nameObj, Tcl_Obj *prefixObj); /* 8 */ Tcl_Method (*tclOONewProcInstanceMethodEx) (Tcl_Interp *interp, Tcl_Object oPtr, TclOO_PreCallProc *preCallPtr, TclOO_PostCallProc *postCallPtr, ProcErrorProc *errProc, void *clientData, Tcl_Obj *nameObj, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, int flags, void **internalTokenPtr); /* 9 */ Tcl_Method (*tclOONewProcMethodEx) (Tcl_Interp *interp, Tcl_Class clsPtr, TclOO_PreCallProc *preCallPtr, TclOO_PostCallProc *postCallPtr, ProcErrorProc *errProc, void *clientData, Tcl_Obj *nameObj, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, int flags, void **internalTokenPtr); /* 10 */ - int (*tclOOInvokeObject) (Tcl_Interp *interp, Tcl_Object object, Tcl_Class startCls, int publicPrivate, size_t objc, Tcl_Obj *const *objv); /* 11 */ + int (*tclOOInvokeObject) (Tcl_Interp *interp, Tcl_Object object, Tcl_Class startCls, int publicPrivate, Tcl_Size objc, Tcl_Obj *const *objv); /* 11 */ void (*tclOOObjectSetFilters) (Object *oPtr, Tcl_Size numFilters, Tcl_Obj *const *filters); /* 12 */ void (*tclOOClassSetFilters) (Tcl_Interp *interp, Class *classPtr, Tcl_Size numFilters, Tcl_Obj *const *filters); /* 13 */ - void (*tclOOObjectSetMixins) (Object *oPtr, size_t numMixins, Class *const *mixins); /* 14 */ - void (*tclOOClassSetMixins) (Tcl_Interp *interp, Class *classPtr, size_t numMixins, Class *const *mixins); /* 15 */ + void (*tclOOObjectSetMixins) (Object *oPtr, Tcl_Size numMixins, Class *const *mixins); /* 14 */ + void (*tclOOClassSetMixins) (Tcl_Interp *interp, Class *classPtr, Tcl_Size numMixins, Class *const *mixins); /* 15 */ } TclOOIntStubs; extern const TclOOIntStubs *tclOOIntStubsPtr; diff --git a/generic/tclObj.c b/generic/tclObj.c index 0817686..d0daa24 100644 --- a/generic/tclObj.c +++ b/generic/tclObj.c @@ -346,6 +346,18 @@ typedef struct ResolvedCmdName { * structure can be freed when refCount * becomes zero. */ } ResolvedCmdName; + +#ifdef TCL_MEM_DEBUG +/* + * Filler matches the value used for filling freed memory in tclCkalloc. + * On 32-bit systems, the ref counts do not cross 0x7fffffff. On 64-bit + * implementations, ref counts will never reach this value (unless explicitly + * incremented without actual references!) + */ +#define FREEDREFCOUNTFILLER \ + (sizeof(objPtr->refCount) == 4 ? 0xe8e8e8e8 : 0xe8e8e8e8e8e8e8e8) +#endif + /* *------------------------------------------------------------------------- @@ -538,7 +550,7 @@ TclGetContLineTable(void) ContLineLoc * TclContinuationsEnter( Tcl_Obj *objPtr, - size_t num, + Tcl_Size num, int *loc) { int newEntry; @@ -3736,7 +3748,7 @@ Tcl_DbIncrRefCount( int line) /* Line number in the source file; used for * debugging. */ { - if (objPtr->refCount == 0x61616161) { + if (objPtr->refCount == FREEDREFCOUNTFILLER) { fprintf(stderr, "file = %s, line = %d\n", file, line); fflush(stderr); Tcl_Panic("incrementing refCount of previously disposed object"); @@ -3809,7 +3821,7 @@ Tcl_DbDecrRefCount( int line) /* Line number in the source file; used for * debugging. */ { - if (objPtr->refCount == 0x61616161) { + if (objPtr->refCount == FREEDREFCOUNTFILLER) { fprintf(stderr, "file = %s, line = %d\n", file, line); fflush(stderr); Tcl_Panic("decrementing refCount of previously disposed object"); @@ -3891,7 +3903,7 @@ Tcl_DbIsShared( #endif { #ifdef TCL_MEM_DEBUG - if (objPtr->refCount == 0x61616161) { + if (objPtr->refCount == FREEDREFCOUNTFILLER) { fprintf(stderr, "file = %s, line = %d\n", file, line); fflush(stderr); Tcl_Panic("checking whether previously disposed object is shared"); diff --git a/generic/tclPathObj.c b/generic/tclPathObj.c index df6f04b..aa678a0 100644 --- a/generic/tclPathObj.c +++ b/generic/tclPathObj.c @@ -813,13 +813,13 @@ Tcl_FSJoinPath( Tcl_Obj * TclJoinPath( - size_t elements, /* Number of elements to use */ + Tcl_Size elements, /* Number of elements to use */ Tcl_Obj * const objv[], /* Path elements to join */ int forceRelative) /* If non-zero, assume all more paths are * relative (e. g. simple normalization) */ { Tcl_Obj *res = NULL; - size_t i; + Tcl_Size i; const Tcl_Filesystem *fsPtr = NULL; if (elements == 0) { @@ -856,7 +856,7 @@ TclJoinPath( TclGetPathType(tailObj, NULL, NULL, NULL); if (type == TCL_PATH_RELATIVE) { const char *str; - size_t len; + Tcl_Size len; str = Tcl_GetStringFromObj(tailObj, &len); if (len == 0) { @@ -1220,7 +1220,7 @@ Tcl_Obj * TclNewFSPathObj( Tcl_Obj *dirPtr, const char *addStrRep, - size_t len) + Tcl_Size len) { FsPath *fsPathPtr; Tcl_Obj *pathPtr; @@ -1273,7 +1273,7 @@ TclNewFSPathObj( * things as needing more aggressive normalization that don't actually * need it. No harm done. */ - for (p = addStrRep; len+1 > 1; p++, len--) { + for (p = addStrRep; len > 0; p++, len--) { switch (state) { case 0: /* So far only "." since last dirsep or start */ switch (*p) { @@ -1317,7 +1317,7 @@ AppendPath( { const char *bytes; Tcl_Obj *copy = Tcl_DuplicateObj(head); - size_t length; + Tcl_Size length; /* * This is likely buggy when dealing with virtual filesystem drivers diff --git a/generic/tclUtil.c b/generic/tclUtil.c index 0e90b6a..9b5a1b1 100644 --- a/generic/tclUtil.c +++ b/generic/tclUtil.c @@ -1022,7 +1022,7 @@ Tcl_ScanCountedElement( *---------------------------------------------------------------------- */ -TCL_HASH_TYPE +Tcl_Size TclScanElement( const char *src, /* String to convert to Tcl list element. */ Tcl_Size length, /* Number of bytes in src, or TCL_INDEX_NONE. */ @@ -1465,7 +1465,7 @@ TclConvertElement( } *p = '}'; p++; - return (size_t)(p - dst); + return (p - dst); } /* conversion == CONVERT_ESCAPE or CONVERT_MASK */ @@ -1972,7 +1972,7 @@ Tcl_ConcatObj( */ for (i = 0; i < objc; i++) { - size_t length; + Tcl_Size length; objPtr = objv[i]; if (TclListObjIsCanonical(objPtr)) { @@ -2331,11 +2331,11 @@ Tcl_StringCaseMatch( int TclByteArrayMatch( const unsigned char *string,/* String. */ - size_t strLen, /* Length of String */ + Tcl_Size strLen, /* Length of String */ const unsigned char *pattern, /* Pattern, which may contain special * characters. */ - size_t ptnLen, /* Length of Pattern */ + Tcl_Size ptnLen, /* Length of Pattern */ TCL_UNUSED(int) /*flags*/) { const unsigned char *stringEnd, *patternEnd; @@ -2513,7 +2513,7 @@ TclStringMatchObj( * 0. */ { int match; - size_t length = 0, plen = 0; + Tcl_Size length = 0, plen = 0; /* * Promote based on the type of incoming object. @@ -3353,7 +3353,7 @@ GetWideForIndex( * NULL, then no error message is left after * errors. */ Tcl_Obj *objPtr, /* Points to the value to be parsed */ - Tcl_WideInt endValue, /* The value to be stored at *widePtr if + Tcl_WideInt endValue, /* The value to be stored at *widePtr if * objPtr holds "end". * NOTE: this value may be TCL_INDEX_NONE. */ Tcl_WideInt *widePtr) /* Location filled in with a wide integer @@ -3732,8 +3732,8 @@ GetEndOffsetFromObj( * are possible. The value objPtr might be parsed as an absolute * index value in the Tcl_Size range. Note that this includes * index values that are integers as presented and it includes index - * arithmetic expressions. - * + * arithmetic expressions. + * * The largest string supported in Tcl 8 has byte length TCL_SIZE_MAX. * This means the largest supported character length is also TCL_SIZE_MAX, * and the index of the last character in a string of length TCL_SIZE_MAX @@ -3741,8 +3741,8 @@ GetEndOffsetFromObj( * directly meaningful as an index into either a list or a string are * integer values in the range 0 to TCL_SIZE_MAX - 1. * - * This function however can only handle integer indices in the range - * 0 : INT_MAX-1. + * This function however can only handle integer indices in the range + * 0 : INT_MAX-1. * * Any absolute index value parsed outside that range is encoded * using the before and after values passed in by the @@ -3808,18 +3808,18 @@ TclIndexEncode( * (3) 2*INT_MAX:WIDE_MAX when * (a,b) as above * (c) objPtr was of the form end+N - * (4) (2*INT_MAX)-TCL_SIZE_MAX : -1 when + * (4) (2*INT_MAX)-TCL_SIZE_MAX : -1 when * (a,b) as above * (c) objPtr was of the form end-N where N was in the range 0:TCL_SIZE_MAX * (5) WIDE_MIN:(2*INT_MAX)-TCL_SIZE_MAX * (a,b) as above * (c) objPtr was of the form end-N where N was > TCL_SIZE_MAX - * + * * For all cases (b) and (c), the internal representation of objPtr * will be shimmered to endOffsetType. That allows us to distinguish between * (for example) 1a (encodable) and 1c (not encodable) though the computed * index value is the same. - * + * * Further note, the values TCL_SIZE_MAX < N < WIDE_MAX come into play * only in the 32-bit builds as TCL_SIZE_MAX == WIDE_MAX for 64-bits. */ @@ -3846,7 +3846,7 @@ TclIndexEncode( * error is raised. On 32-bit systems, indices in that range indicate * the position after the end and so do not raise an error. */ - if ((sizeof(int) != sizeof(size_t)) && + if ((sizeof(int) != sizeof(size_t)) && (wide > INT_MAX) && (wide < WIDE_MAX-1)) { /* 2(a,b) on 64-bit systems*/ goto rangeerror; @@ -3876,7 +3876,7 @@ TclIndexEncode( * indices in that range indicate the position before the beginning * and so do not raise an error. */ - if ((sizeof(int) != sizeof(size_t)) && + if ((sizeof(int) != sizeof(size_t)) && (wide > (ENDVALUE - LIST_MAX)) && (wide <= INT_MAX)) { /* 1(c), 4(a,b) on 64-bit systems */ goto rangeerror; @@ -4166,7 +4166,7 @@ TclGetProcessGlobalValue( Tcl_Obj *value = NULL; Tcl_HashTable *cacheMap; Tcl_HashEntry *hPtr; - size_t epoch = pgvPtr->epoch; + Tcl_Size epoch = pgvPtr->epoch; if (pgvPtr->encoding) { Tcl_Encoding current = Tcl_GetEncoding(NULL, NULL); @@ -4373,7 +4373,7 @@ int TclReToGlob( Tcl_Interp *interp, const char *reStr, - size_t reStrLen, + Tcl_Size reStrLen, Tcl_DString *dsPtr, int *exactPtr, int *quantifiersFoundPtr) diff --git a/tests/chanio.test b/tests/chanio.test index 09e71ca..c3caa1c 100644 --- a/tests/chanio.test +++ b/tests/chanio.test @@ -6868,7 +6868,7 @@ test chan-io-52.9 {TclCopyChannel & encodings} {fcopy} { [file size $path(utf8-fcopy.txt)] \ [file size $path(utf8-rp.txt)] } {3 5 5} -test chan-io-52.10 {TclCopyChannel & encodings} {fcopy} { +test chan-io-52.10 {TclCopyChannel & encodings} {fcopy notWinCI} { # encoding to binary (=> implies that the internal utf-8 is written) set in [open $path(kyrillic.txt) r] set out [open $path(utf8-fcopy.txt) w] @@ -6886,18 +6886,23 @@ test chan-io-52.11 {TclCopyChannel & encodings} -setup { puts $f АА close $f } -constraints {fcopy} -body { - # binary to encoding => the input has to be in utf-8 to make sense to the - # encoder set in [open $path(utf8-fcopy.txt) r] set out [open $path(kyrillic.txt) w] # -translation binary is also -encoding binary chan configure $in -translation binary - chan configure $out -encoding koi8-r -translation lf - chan copy $in $out - chan close $in - chan close $out - file size $path(kyrillic.txt) -} -result 3 + chan configure $out -encoding koi8-r -translation lf -profile strict + catch {chan copy $in $out} cres copts + return $cres +} -cleanup { + if {$in in [chan names]} { + close $in + } + if {$out in [chan names]} { + close $out + } + catch {unset cres} +} -match glob -result {error writing "*": invalid or incomplete\ + multibyte or wide character} test chan-io-53.1 {CopyData} -setup { file delete $path(test1) diff --git a/tests/io.test b/tests/io.test index 96e5ea6..5fd255c 100644 --- a/tests/io.test +++ b/tests/io.test @@ -7500,7 +7500,7 @@ test io-52.9 {TclCopyChannel & encodings} {fcopy} { [file size $path(utf8-fcopy.txt)] \ [file size $path(utf8-rp.txt)] } {3 5 5} -test io-52.10 {TclCopyChannel & encodings} {fcopy} { +test io-52.10 {TclCopyChannel & encodings} {fcopy notWinCI} { # encoding to binary (=> implies that the # internal utf-8 is written) @@ -7519,26 +7519,27 @@ test io-52.10 {TclCopyChannel & encodings} {fcopy} { } 5 test io-52.11 {TclCopyChannel & encodings} -setup { set out [open $path(utf8-fcopy.txt) w] - fconfigure $out -encoding utf-8 -translation lf - puts $out "АА" + fconfigure $out -encoding utf-8 -translation lf -profile strict + puts $out АА close $out } -constraints {fcopy} -body { - # binary to encoding => the input has to be - # in utf-8 to make sense to the encoder - set in [open $path(utf8-fcopy.txt) r] set out [open $path(kyrillic.txt) w] - # -translation binary is also -encoding binary fconfigure $in -translation binary - fconfigure $out -encoding koi8-r -translation lf - - fcopy $in $out - close $in - close $out - - file size $path(kyrillic.txt) -} -result 3 + fconfigure $out -encoding koi8-r -translation lf -profile strict + catch {fcopy $in $out} cres copts + return $cres +} -cleanup { + if {$in in [chan names]} { + close $in + } + if {$out in [chan names]} { + close $out + } + catch {unset cres} +} -match glob -result {error writing "*": invalid or incomplete\ + multibyte or wide character} test io-52.12 {coverage of -translation auto} { file delete $path(test1) $path(test2) @@ -7780,6 +7781,29 @@ test io-52.23 {TclCopyChannel & encodings} -setup { unset ::s0 } -match glob -result {0 {error writing "file*": invalid or incomplete multibyte or wide character}} +test io-52.24 {fcopy -size should always be characters} -setup { + set out [open utf8-fcopy-52.24.txt w] + fconfigure $out -encoding utf-8 -translation lf + puts $out "Á" + close $out +} -constraints {fcopy} -body { + set in [open utf8-fcopy-52.24.txt r] + set out [open utf8-fcopy-52.24.out.txt w+] + + fconfigure $in -encoding utf-8 -profile tcl8 + fconfigure $out -encoding utf-8 -profile tcl8 + fcopy $in $out -size 1 + seek $out 0 + # a result of \xc3 means that only the first byte of the utf-8 encoding of + # Á made it into to the output file. + read $out +} -cleanup { + close $in + close $out + catch {file delete utf8-fcopy-52.24.txt} + catch {file delete utf8-fcopy-52.24.out.txt} +} -result Á + test io-53.1 {CopyData} {fcopy} { file delete $path(test1) @@ -8276,7 +8300,7 @@ test io-53.11 {Bug 2895565} -setup { removeFile out removeFile in } -result {40 bytes copied} -test io-53.12 {CopyData: foreground short reads, aka bug 3096275} {stdio unix fcopy} { +test io-53.12.0 {CopyData: foreground short reads, aka bug 3096275} {stdio unix fcopy} { file delete $path(pipe) set f1 [open $path(pipe) w] puts -nonewline $f1 { @@ -8295,6 +8319,32 @@ test io-53.12 {CopyData: foreground short reads, aka bug 3096275} {stdio unix fc close $f1 list $::done $ch } {ok A} +test io-53.12.1 { + Issue 9ca87e6286262a62. + CopyData: foreground short reads via ReadChars(). + Related to report 3096275 for ReadBytes(). + + Prior to the fix this test waited forever for read() to return. +} {stdio unix fcopy} { + file delete $path(output) + set f1 [open $path(output) w] + puts -nonewline $f1 { + chan configure stdin -encoding iso8859-1 -translation lf -buffering none + fcopy stdin stdout + } + close $f1 + set f1 [open "|[list [info nameofexecutable] $path(output)]" r+] + try { + chan configure $f1 -encoding utf-8 -buffering none + puts -nonewline $f1 A + set ch [read $f1 1] + } finally { + if {$f1 in [chan names]} { + close $f1 + } + } + lindex $ch +} A test io-53.13 {TclCopyChannel: read error reporting} -setup { proc driver {cmd args} { variable buffer diff --git a/unix/dltest/pkgt.c b/unix/dltest/pkgt.c index 7a32c35..1f326f5 100644 --- a/unix/dltest/pkgt.c +++ b/unix/dltest/pkgt.c @@ -16,11 +16,11 @@ static int TraceProc2 ( void *clientData, Tcl_Interp *interp, - Tcl_Size level, + Tcl_Size level, const char *command, Tcl_Command commandInfo, Tcl_Size objc, - struct Tcl_Obj *const *objv) + struct Tcl_Obj *const *objv) { (void)clientData; (void)interp; diff --git a/unix/tclUnixInit.c b/unix/tclUnixInit.c index 376e72b..ed9058e 100644 --- a/unix/tclUnixInit.c +++ b/unix/tclUnixInit.c @@ -455,7 +455,7 @@ TclpInitPlatform(void) void TclpInitLibraryPath( char **valuePtr, - size_t *lengthPtr, + TCL_HASH_TYPE *lengthPtr, Tcl_Encoding *encodingPtr) { #define LIBRARY_SIZE 32 diff --git a/win/tclWinInit.c b/win/tclWinInit.c index a466a30..bb9ef66 100644 --- a/win/tclWinInit.c +++ b/win/tclWinInit.c @@ -124,7 +124,7 @@ TclpInitPlatform(void) void TclpInitLibraryPath( char **valuePtr, - size_t *lengthPtr, + TCL_HASH_TYPE *lengthPtr, Tcl_Encoding *encodingPtr) { #define LIBRARY_SIZE 64 |
