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: |
239fb8a769c161357ad6bc7d64d5e1aa |
User & Date: | jan.nijtmans 2014-05-09 13:50:41 |
Context
2014-05-16
| ||
15:33 | merge trunk check-in: 44638ca040 user: dgp tags: novem | |
2014-05-09
| ||
13:50 | merge trunk check-in: 239fb8a769 user: jan.nijtmans tags: novem | |
13:33 | Test iocmd-32.1 is not "impossible" but after writing it properly it does segfault trying to use a d... check-in: 0a4dfac63e user: dgp tags: trunk | |
2014-05-02
| ||
06:58 | Update Unicode tables to Unicode 7.0 beta check-in: 872972ea94 user: jan.nijtmans tags: novem | |
Changes
Changes to doc/tclvars.n.
︙ | ︙ | |||
343 344 345 346 347 348 349 | If this variable exists, then the interpreter was compiled with threads enabled. .TP \fBuser\fR . This identifies the current user based on the login information available on the platform. | | | | 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 | If this variable exists, then the interpreter was compiled with threads enabled. .TP \fBuser\fR . This identifies the current user based on the login information available on the platform. This value comes from the getuid() and getpwuid() system calls on Unix, and the value from the GetUserName() system call on Windows. .TP \fBwordSize\fR . This gives the size of the native-machine word in bytes (strictly, it is same as the result of evaluating \fIsizeof(long)\fR in C.) .RE .TP |
︙ | ︙ |
Changes to generic/tcl.h.
︙ | ︙ | |||
2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 | #include "tclDecls.h" /* * Include platform specific public function declarations that are accessible * via the stubs table. */ #include "tclPlatDecls.h" /* *---------------------------------------------------------------------------- * The following declarations either map ckalloc and ckfree to malloc and * free, or they map them to functions with all sorts of debugging hooks | > > > > > | 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 | #include "tclDecls.h" /* * Include platform specific public function declarations that are accessible * via the stubs table. */ #if defined(BUILD_tcl) # undef TCLAPI # define TCLAPI MODULE_SCOPE #endif #include "tclPlatDecls.h" /* *---------------------------------------------------------------------------- * The following declarations either map ckalloc and ckfree to malloc and * free, or they map them to functions with all sorts of debugging hooks |
︙ | ︙ |
Changes to generic/tclIO.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /* * tclIO.c -- * * This file provides the generic portions (those that are the same on * all platforms and for all channel types) of Tcl's IO facilities. * * Copyright (c) 1998-2000 Ajuba Solutions * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclIO.h" | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /* * tclIO.c -- * * This file provides the generic portions (those that are the same on * all platforms and for all channel types) of Tcl's IO facilities. * * Copyright (c) 1998-2000 Ajuba Solutions * Copyright (c) 1995-1997 Sun Microsystems, Inc. * Contributions from Don Porter, NIST, 2014. (not subject to US copyright) * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclIO.h" |
︙ | ︙ | |||
175 176 177 178 179 180 181 | Channel *chanPtr); static int CloseChannel(Tcl_Interp *interp, Channel *chanPtr, int errorCode); static int CloseChannelPart(Tcl_Interp *interp, Channel *chanPtr, int errorCode, int flags); static int CloseWrite(Tcl_Interp *interp, Channel *chanPtr); static void CommonGetsCleanup(Channel *chanPtr); | < < | > | | | | 176 177 178 179 180 181 182 183 184 185 186 187 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 | Channel *chanPtr); static int CloseChannel(Tcl_Interp *interp, Channel *chanPtr, int errorCode); static int CloseChannelPart(Tcl_Interp *interp, Channel *chanPtr, int errorCode, int flags); static int CloseWrite(Tcl_Interp *interp, Channel *chanPtr); static void CommonGetsCleanup(Channel *chanPtr); static int CopyBuffer(Channel *chanPtr, char *result, int space); static int CopyData(CopyState *csPtr, int mask); static void CopyEventProc(ClientData clientData, int mask); static void CreateScriptRecord(Tcl_Interp *interp, Channel *chanPtr, int mask, Tcl_Obj *scriptPtr); static void DeleteChannelTable(ClientData clientData, Tcl_Interp *interp); 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 *dst, int bytesToRead, 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); static int ReadChars(ChannelState *statePtr, Tcl_Obj *objPtr, int charsLeft, 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 void 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); |
︙ | ︙ | |||
1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 | if ((mask & TCL_WRITABLE) != 0) { CopyState *csPtrR = statePtr->csPtrR; CopyState *csPtrW = statePtr->csPtrW; statePtr->csPtrR = NULL; statePtr->csPtrW = NULL; if (Tcl_Flush((Tcl_Channel) prevChanPtr) != TCL_OK) { statePtr->csPtrR = csPtrR; statePtr->csPtrW = csPtrW; if (interp) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "could not flush channel \"%s\"", Tcl_GetChannelName(prevChan))); | > > > > | 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 | if ((mask & TCL_WRITABLE) != 0) { CopyState *csPtrR = statePtr->csPtrR; CopyState *csPtrW = statePtr->csPtrW; statePtr->csPtrR = NULL; statePtr->csPtrW = NULL; /* * TODO: Examine what can go wrong if Tcl_Flush() call disturbs * the stacking state of this channel during its operations. */ if (Tcl_Flush((Tcl_Channel) prevChanPtr) != TCL_OK) { statePtr->csPtrR = csPtrR; statePtr->csPtrW = csPtrW; if (interp) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "could not flush channel \"%s\"", Tcl_GetChannelName(prevChan))); |
︙ | ︙ | |||
1774 1775 1776 1777 1778 1779 1780 1781 | * the channel itself. We use the buffers in the channel below the new * transformation to hold the data. In the future this allows us to write * transformations which pre-read data and push the unused part back when * they are going away. */ if (((mask & TCL_READABLE) != 0) && (statePtr->inQueueHead != NULL)) { /* | > < | > | | | | < | 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 | * the channel itself. We use the buffers in the channel below the new * transformation to hold the data. In the future this allows us to write * transformations which pre-read data and push the unused part back when * they are going away. */ if (((mask & TCL_READABLE) != 0) && (statePtr->inQueueHead != NULL)) { /* * When statePtr->inQueueHead is not NULL, we know * prevChanPtr->inQueueHead must be NULL. */ assert(prevChanPtr->inQueueHead == NULL); assert(prevChanPtr->inQueueTail == NULL); prevChanPtr->inQueueHead = statePtr->inQueueHead; prevChanPtr->inQueueTail = statePtr->inQueueTail; statePtr->inQueueHead = NULL; statePtr->inQueueTail = NULL; } chanPtr = ckalloc(sizeof(Channel)); |
︙ | ︙ | |||
1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 | /* * Instead of manipulating the per-thread / per-interp list/hashtable * of registered channels we wind down the state of the * transformation, and then restore the state of underlying channel * into the old structure. */ Channel *downChanPtr = chanPtr->downChanPtr; /* * Flush the buffers. This ensures that any data still in them at this * time _is_ handled by the transformation we are unstacking right * now. Restrict this to writable channels. Take care to hide a * possible bg-copy in progress from Tcl_Flush and the | > > > > > > > | 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 | /* * Instead of manipulating the per-thread / per-interp list/hashtable * of registered channels we wind down the state of the * transformation, and then restore the state of underlying channel * into the old structure. */ /* * TODO: Figure out how to handle the situation where the chan * operations called below by this unstacking operation cause * another unstacking recursively. In that case the downChanPtr * value we're holding on to will not be the right thing. */ Channel *downChanPtr = chanPtr->downChanPtr; /* * Flush the buffers. This ensures that any data still in them at this * time _is_ handled by the transformation we are unstacking right * now. Restrict this to writable channels. Take care to hide a * possible bg-copy in progress from Tcl_Flush and the |
︙ | ︙ | |||
1976 1977 1978 1979 1980 1981 1982 | chanPtr->typePtr = NULL; /* * AK: Tcl_NotifyChannel may hold a reference to this block of memory */ Tcl_EventuallyFree(chanPtr, TCL_DYNAMIC); | | | 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 | chanPtr->typePtr = NULL; /* * AK: Tcl_NotifyChannel may hold a reference to this block of memory */ Tcl_EventuallyFree(chanPtr, TCL_DYNAMIC); UpdateInterest(statePtr->topChanPtr); if (result != 0) { Tcl_SetErrno(result); /* * TIP #219, Tcl Channel Reflection API. * Move error messages put by the driver into the chan/ip bypass |
︙ | ︙ | |||
2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 | return bufPtr; } static void PreserveChannelBuffer( ChannelBuffer *bufPtr) { bufPtr->refCount++; } static void ReleaseChannelBuffer( ChannelBuffer *bufPtr) { | > > > | 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 | return bufPtr; } static void PreserveChannelBuffer( ChannelBuffer *bufPtr) { if (bufPtr->refCount == 0) { Tcl_Panic("Reuse of ChannelBuffer! %p", bufPtr); } bufPtr->refCount++; } static void ReleaseChannelBuffer( ChannelBuffer *bufPtr) { |
︙ | ︙ | |||
2355 2356 2357 2358 2359 2360 2361 | if (mustDiscard) { ReleaseChannelBuffer(bufPtr); return; } /* | | | | | 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 | if (mustDiscard) { ReleaseChannelBuffer(bufPtr); return; } /* * Only save buffers which have the requested buffersize for the * channel. This is to honor dynamic changes of the buffersize * made by the user. */ if ((bufPtr->bufLength - BUFFER_PADDING) != statePtr->bufSize) { ReleaseChannelBuffer(bufPtr); return; } /* * Only save buffers for the input queue if the channel is readable. */ |
︙ | ︙ | |||
2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 | if (written < 0) { /* * If the last attempt to write was interrupted, simply retry. */ if (errorCode == EINTR) { errorCode = 0; continue; } /* * If the channel is non-blocking and we would have blocked, start * a background flushing handler and break out of the loop. */ | > | 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 | if (written < 0) { /* * If the last attempt to write was interrupted, simply retry. */ if (errorCode == EINTR) { errorCode = 0; ReleaseChannelBuffer(bufPtr); continue; } /* * If the channel is non-blocking and we would have blocked, start * a background flushing handler and break out of the loop. */ |
︙ | ︙ | |||
2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 | */ if (!GotFlag(statePtr, BG_FLUSH_SCHEDULED) && !TclInExit()) { SetFlag(statePtr, BG_FLUSH_SCHEDULED); UpdateInterest(chanPtr); } errorCode = 0; break; } /* * Decide whether to report the error upwards or defer it. */ | > | 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 | */ if (!GotFlag(statePtr, BG_FLUSH_SCHEDULED) && !TclInExit()) { SetFlag(statePtr, BG_FLUSH_SCHEDULED); UpdateInterest(chanPtr); } errorCode = 0; ReleaseChannelBuffer(bufPtr); break; } /* * Decide whether to report the error upwards or defer it. */ |
︙ | ︙ | |||
2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 | /* * When we get an error we throw away all the output currently * queued. */ DiscardOutputQueued(statePtr); continue; } else { wroteSome = 1; } | > < | < | 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 | /* * When we get an error we throw away all the output currently * queued. */ DiscardOutputQueued(statePtr); ReleaseChannelBuffer(bufPtr); continue; } else { wroteSome = 1; } bufPtr->nextRemoved += written; /* * If this buffer is now empty, recycle it. */ if (IsBufferEmpty(bufPtr)) { statePtr->outQueueHead = bufPtr->nextPtr; |
︙ | ︙ | |||
4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 | static int WillRead( Channel *chanPtr) { if (chanPtr->typePtr == NULL) { /* Prevent read attempts on a closed channel */ Tcl_SetErrno(EINVAL); return -1; } if ((chanPtr->typePtr->seekProc != NULL) && (Tcl_OutputBuffered((Tcl_Channel) chanPtr) > 0)) { if ((chanPtr->state->curOutPtr != NULL) && IsBufferReady(chanPtr->state->curOutPtr)) { | > | 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 | static int WillRead( Channel *chanPtr) { if (chanPtr->typePtr == NULL) { /* Prevent read attempts on a closed channel */ DiscardInputQueued(chanPtr->state, 0); Tcl_SetErrno(EINVAL); return -1; } if ((chanPtr->typePtr->seekProc != NULL) && (Tcl_OutputBuffered((Tcl_Channel) chanPtr) > 0)) { if ((chanPtr->state->curOutPtr != NULL) && IsBufferReady(chanPtr->state->curOutPtr)) { |
︙ | ︙ | |||
4156 4157 4158 4159 4160 4161 4162 | } result |= Tcl_UtfToExternal(NULL, encoding, nl, nlLen, statePtr->outputEncodingFlags, &statePtr->outputEncodingState, dst, dstLen + BUFFER_PADDING, &srcRead, &dstWrote, NULL); | | < < | 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 | } result |= Tcl_UtfToExternal(NULL, encoding, nl, nlLen, statePtr->outputEncodingFlags, &statePtr->outputEncodingState, dst, dstLen + BUFFER_PADDING, &srcRead, &dstWrote, NULL); assert (srcRead == nlLen); bufPtr->nextAdded += dstWrote; src++; srcLen--; total += dstWrote; dst += dstWrote; dstLen -= dstWrote; |
︙ | ︙ | |||
4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 | if ((srcLen + saved == 0) && (result == TCL_OK)) { endEncoding = 0; } if (IsBufferFull(bufPtr)) { if (FlushChannel(NULL, chanPtr, 0) != 0) { return -1; } flushed += statePtr->bufSize; if (saved == 0 || src[-1] != '\n') { needNlFlush = 0; } } | > | 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 | if ((srcLen + saved == 0) && (result == TCL_OK)) { endEncoding = 0; } if (IsBufferFull(bufPtr)) { if (FlushChannel(NULL, chanPtr, 0) != 0) { ReleaseChannelBuffer(bufPtr); return -1; } flushed += statePtr->bufSize; if (saved == 0 || src[-1] != '\n') { needNlFlush = 0; } } |
︙ | ︙ | |||
4543 4544 4545 4546 4547 4548 4549 | */ gotEOL: /* * Regenerate the top channel, in case it was changed due to * self-modifying reflected transforms. */ | | > > | < > > | 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 | */ gotEOL: /* * Regenerate the top channel, in case it was changed due to * self-modifying reflected transforms. */ if (chanPtr != statePtr->topChanPtr) { Tcl_Release(chanPtr); chanPtr = statePtr->topChanPtr; Tcl_Preserve(chanPtr); } bufPtr = gs.bufPtr; if (bufPtr == NULL) { Tcl_Panic("Tcl_GetsObj: gotEOL reached with bufPtr==NULL"); } statePtr->inputEncodingState = gs.state; Tcl_ExternalToUtf(NULL, gs.encoding, RemovePoint(bufPtr), gs.rawRead, |
︙ | ︙ | |||
4579 4580 4581 4582 4583 4584 4585 | */ restore: /* * Regenerate the top channel, in case it was changed due to * self-modifying reflected transforms. */ | < > > | < > > | 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 | */ restore: /* * Regenerate the top channel, in case it was changed due to * self-modifying reflected transforms. */ if (chanPtr != statePtr->topChanPtr) { Tcl_Release(chanPtr); chanPtr = statePtr->topChanPtr; Tcl_Preserve(chanPtr); } bufPtr = statePtr->inQueueHead; if (bufPtr != NULL) { bufPtr->nextRemoved = oldRemoved; bufPtr = bufPtr->nextPtr; } for ( ; bufPtr != NULL; bufPtr = bufPtr->nextPtr) { |
︙ | ︙ | |||
4621 4622 4623 4624 4625 4626 4627 | */ done: /* * Regenerate the top channel, in case it was changed due to * self-modifying reflected transforms. */ | < > > | < > > | 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 | */ done: /* * Regenerate the top channel, in case it was changed due to * self-modifying reflected transforms. */ if (chanPtr != statePtr->topChanPtr) { Tcl_Release(chanPtr); chanPtr = statePtr->topChanPtr; Tcl_Preserve(chanPtr); } UpdateInterest(chanPtr); Tcl_Release(chanPtr); return copiedTotal; } /* *--------------------------------------------------------------------------- |
︙ | ︙ | |||
4955 4956 4957 4958 4959 4960 4961 | FilterInputBytes( Channel *chanPtr, /* Channel to read. */ GetsState *gsPtr) /* Current state of gets operation. */ { ChannelState *statePtr = chanPtr->state; /* State info for channel */ ChannelBuffer *bufPtr; | | | 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 | FilterInputBytes( Channel *chanPtr, /* Channel to read. */ GetsState *gsPtr) /* Current state of gets operation. */ { ChannelState *statePtr = chanPtr->state; /* State info for channel */ ChannelBuffer *bufPtr; char *raw, *dst; int offset, toRead, dstNeeded, spaceLeft, result, rawLen; Tcl_Obj *objPtr; #define ENCODING_LINESIZE 20 /* Lower bound on how many bytes to convert at * a time. Since we don't know a priori how * many bytes of storage this many source * bytes will use, we actually need at least * ENCODING_LINESIZE * TCL_MAX_UTF bytes of |
︙ | ︙ | |||
5017 5018 5019 5020 5021 5022 5023 | /* * Convert some of the bytes from the channel buffer to UTF-8. Space in * objPtr's string rep is used to hold the UTF-8 characters. Grow the * string rep if we need more space. */ | | < | 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 | /* * Convert some of the bytes from the channel buffer to UTF-8. Space in * objPtr's string rep is used to hold the UTF-8 characters. Grow the * string rep if we need more space. */ raw = RemovePoint(bufPtr); rawLen = BytesLeft(bufPtr); dst = *gsPtr->dstPtr; offset = dst - objPtr->bytes; toRead = ENCODING_LINESIZE; if (toRead > rawLen) { toRead = rawLen; |
︙ | ︙ | |||
5371 5372 5373 5374 5375 5376 5377 | if (GotFlag(statePtr, CHANNEL_BLOCKED)) { if (GotFlag(statePtr, CHANNEL_NONBLOCKING)) { goto done; } ResetFlag(statePtr, CHANNEL_BLOCKED); } | < < < < < < < < < < < < < < < < < < < < < | | | | | | > | | | < < < < < < < < < < < < | 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 | if (GotFlag(statePtr, CHANNEL_BLOCKED)) { if (GotFlag(statePtr, CHANNEL_NONBLOCKING)) { goto done; } ResetFlag(statePtr, CHANNEL_BLOCKED); } /* * Now go to the driver to get as much as is possible to * fill the remaining request. Do all the error handling by * ourselves. The code was stolen from 'GetInput' and * slightly adapted (different return value here). * * The case of 'bytesToRead == 0' at this point cannot * happen. */ nread = ChanRead(chanPtr, bufPtr + copied, bytesToRead - copied, &result); if (nread > 0) { /* * If we get a short read, signal up that we may be BLOCKED. * We should avoid calling the driver because on some * platforms we will block in the low level reading code even * though the channel is set into nonblocking mode. */ if (nread < (bytesToRead - copied)) { SetFlag(statePtr, CHANNEL_BLOCKED); } } else if (nread == 0) { SetFlag(statePtr, CHANNEL_EOF); statePtr->inputEncodingFlags |= TCL_ENCODING_END; } else if (nread < 0) { if ((result == EWOULDBLOCK) || (result == EAGAIN)) { if (copied > 0) { |
︙ | ︙ | |||
5554 5555 5556 5557 5558 5559 5560 | * will be appended to the object. Otherwise, * the data will replace the existing contents * of the object. */ { ChannelState *statePtr = chanPtr->state; /* State info for channel */ ChannelBuffer *bufPtr; | | > > > > > | > > < < < < < < < | | | < | 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 | * will be appended to the object. Otherwise, * the data will replace the existing contents * of the object. */ { ChannelState *statePtr = chanPtr->state; /* State info for channel */ ChannelBuffer *bufPtr; int factor, copied, copiedNow, result; Tcl_Encoding encoding; int binaryMode; #define UTF_EXPANSION_FACTOR 1024 /* * This operation should occur at the top of a channel stack. */ chanPtr = statePtr->topChanPtr; encoding = statePtr->encoding; factor = UTF_EXPANSION_FACTOR; Tcl_Preserve(chanPtr); binaryMode = (encoding == NULL) && (statePtr->inputTranslation == TCL_TRANSLATE_LF) && (statePtr->inEofChar == '\0'); if (appendFlag == 0) { if (binaryMode) { Tcl_SetByteArrayLength(objPtr, 0); } else { Tcl_SetObjLength(objPtr, 0); /* * We're going to access objPtr->bytes directly, so we must ensure * that this is actually a string object (otherwise it might have * been pure Unicode). * * Probably not needed anymore. */ TclGetString(objPtr); } } for (copied = 0; (unsigned) toRead > 0; ) { copiedNow = -1; if (statePtr->inQueueHead != NULL) { if (binaryMode) { copiedNow = ReadBytes(statePtr, objPtr, toRead); } else { copiedNow = ReadChars(statePtr, objPtr, toRead, &factor); } /* * If the current buffer is empty recycle it. */ bufPtr = statePtr->inQueueHead; |
︙ | ︙ | |||
5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 | if (GotFlag(statePtr, CHANNEL_BLOCKED)) { if (GotFlag(statePtr, CHANNEL_NONBLOCKING)) { break; } ResetFlag(statePtr, CHANNEL_BLOCKED); } result = GetInput(chanPtr); if (result != 0) { if (result == EAGAIN) { break; } copied = -1; goto done; } } else { copied += copiedNow; toRead -= copiedNow; } } ResetFlag(statePtr, CHANNEL_BLOCKED); | > > > > > < < < < < < > > | < > > | | < < < > | < < < < < | < < < < < < | < | < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < | < | | 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 | if (GotFlag(statePtr, CHANNEL_BLOCKED)) { if (GotFlag(statePtr, CHANNEL_NONBLOCKING)) { break; } ResetFlag(statePtr, CHANNEL_BLOCKED); } result = GetInput(chanPtr); if (chanPtr != statePtr->topChanPtr) { Tcl_Release(chanPtr); chanPtr = statePtr->topChanPtr; Tcl_Preserve(chanPtr); } if (result != 0) { if (result == EAGAIN) { break; } copied = -1; goto done; } } else { copied += copiedNow; toRead -= copiedNow; } } ResetFlag(statePtr, CHANNEL_BLOCKED); /* * Update the notifier state so we don't block while there is still data * in the buffers. */ done: /* * Regenerate the top channel, in case it was changed due to * self-modifying reflected transforms. */ if (chanPtr != statePtr->topChanPtr) { Tcl_Release(chanPtr); chanPtr = statePtr->topChanPtr; Tcl_Preserve(chanPtr); } UpdateInterest(chanPtr); Tcl_Release(chanPtr); return copied; } /* *--------------------------------------------------------------------------- * * ReadBytes -- * * Reads from the channel until the requested number of bytes have been * seen, EOF is seen, or the channel would block. Bytes from the channel * are stored in objPtr as a ByteArray object. EOL and EOF translation * are done. * * 'bytesToRead' can safely be a very large number because space is only * allocated to hold data read from the channel as needed. * * Results: * The return value is the number of bytes appended to the object, or * -1 to indicate that zero bytes were read due to an EOF. * * Side effects: * The storage of bytes in objPtr can cause (re-)allocation of memory. * *--------------------------------------------------------------------------- */ static int ReadBytes( ChannelState *statePtr, /* State of the channel to read. */ Tcl_Obj *objPtr, /* Input data is appended to this ByteArray * object. Its length is how much space has * been allocated to hold data, not how many * bytes of data have been stored in the * object. */ int bytesToRead) /* Maximum number of bytes to store, or < 0 to * get all available bytes. Bytes are obtained * from the first buffer in the queue - even * if this number is larger than the number of * bytes available in the first buffer, only * the bytes from the first buffer are * returned. */ { ChannelBuffer *bufPtr = statePtr->inQueueHead; int srcLen = BytesLeft(bufPtr); int toRead = bytesToRead>srcLen || bytesToRead<0 ? srcLen : bytesToRead; TclAppendBytesToByteArray(objPtr, (unsigned char *) RemovePoint(bufPtr), toRead); bufPtr->nextRemoved += toRead; return toRead; } /* *--------------------------------------------------------------------------- * * ReadChars -- * |
︙ | ︙ | |||
5807 5808 5809 5810 5811 5812 5813 | int charsToRead, /* Maximum number of characters to store, or * -1 to get all available characters. * Characters are obtained from the first * buffer in the queue -- even if this number * is larger than the number of characters * available in the first buffer, only the * characters from the first buffer are | | | | | | | < < | | < | < < | | | | > > > | < | > > | > | > | | > > > > > > > > | | | < > > > > > > > | < > > > > > | | | < | < < < < | > > > > | > | > > | < < | | > > > > > | > | > > > > > | | | | > | < | | < | | < < < < < < < | < > | > | > > > > > > | | < < < | < > > > | | < | < | > > | | < > | | < > > > | > > | > > > > | > > > > > > | > > > > > > | | | | < | > | | | > > | | > > > < > > > > > | | | < > | > | | > | > | > > | > > > > > > > > | | > | | > | | < < < | < < | > > > > > > > > > | > > > | < < > > | | < | | | > > > | < < > > > > > > | | | > > | < > > > | > > > > | | > | | | | | | | | | | | | | | | | | | | | | > | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | > | < | | < | < | | < | | | | < < > > | | > > > > > | | < < | | > | | | < | | | > > > > > | > > > > > > | < < | | | < < | | < < | | < > | < > | | | < | | | | < | | > | > > > > | > > > > | | < | < | < | < | | < < > > > > | | > | | | | < < < | | | < < | < > | | < > > | | < < < < | 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 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 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 | int charsToRead, /* Maximum number of characters to store, or * -1 to get all available characters. * Characters are obtained from the first * buffer in the queue -- even if this number * is larger than the number of characters * available in the first buffer, only the * characters from the first buffer are * returned. The execption is when there is * not any complete character in the first * buffer. In that case, a recursive call * effectively obtains chars from the * second buffer. */ int *factorPtr) /* On input, contains a guess of how many * bytes need to be allocated to hold the * result of converting N source bytes to * UTF-8. On output, contains another guess * based on the data seen so far. */ { Tcl_Encoding encoding = statePtr->encoding? statePtr->encoding : GetBinaryEncoding(); Tcl_EncodingState savedState = statePtr->inputEncodingState; ChannelBuffer *bufPtr = statePtr->inQueueHead; int savedIEFlags = statePtr->inputEncodingFlags; int savedFlags = statePtr->flags; char *dst, *src = RemovePoint(bufPtr); int dstLimit, numBytes, srcLen = BytesLeft(bufPtr); /* * One src byte can yield at most one character. So when the * number of src bytes we plan to read is less than the limit on * character count to be read, clearly we will remain within that * limit, and we can use the value of "srcLen" as a tighter limit * for sizing receiving buffers. */ int toRead = ((unsigned) charsToRead > srcLen) ? srcLen : charsToRead; /* * 'factor' is how much we guess that the bytes in the source buffer will * expand when converted to UTF-8 chars. This guess comes from analyzing * how many characters were produced by the previous pass. */ int factor = *factorPtr; int dstNeeded = TCL_UTF_MAX - 1 + toRead * factor / UTF_EXPANSION_FACTOR; (void) TclGetStringFromObj(objPtr, &numBytes); Tcl_AppendToObj(objPtr, NULL, dstNeeded); if (toRead == srcLen) { unsigned int size; dst = TclGetStringStorage(objPtr, &size) + numBytes; dstNeeded = size - numBytes; } else { dst = TclGetString(objPtr) + numBytes; } /* * This routine is burdened with satisfying several constraints. * It cannot append more than 'charsToRead` chars onto objPtr. * This is measured after encoding and translation transformations * are completed. There is no precise number of src bytes that can * be associated with the limit. Yet, when we are done, we must know * precisely the number of src bytes that were consumed to produce * the appended chars, so that all subsequent bytes are left in * the buffers for future read operations. * * The consequence is that we have no choice but to implement a * "trial and error" approach, where in general we may need to * perform transformations and copies multiple times to achieve * a consistent set of results. This takes the shape of a loop. */ dstLimit = dstNeeded + 1; while (1) { int dstDecoded, dstRead, dstWrote, srcRead, numChars; /* * Perform the encoding transformation. Read no more than * srcLen bytes, write no more than dstLimit bytes. */ int code = Tcl_ExternalToUtf(NULL, encoding, src, srcLen, statePtr->inputEncodingFlags & (bufPtr->nextPtr ? ~0 : ~TCL_ENCODING_END), &statePtr->inputEncodingState, dst, dstLimit, &srcRead, &dstDecoded, &numChars); /* * Perform the translation transformation in place. Read no more * than the dstDecoded bytes the encoding transformation actually * produced. Capture the number of bytes written in dstWrote. * Capture the number of bytes actually consumed in dstRead. */ dstWrote = dstLimit; dstRead = dstDecoded; TranslateInputEOL(statePtr, dst, dst, &dstWrote, &dstRead); if (dstRead < dstDecoded) { /* * The encoding transformation produced bytes that the * translation transformation did not consume. Why did * this happen? */ if (statePtr->inEofChar && dst[dstRead] == statePtr->inEofChar) { /* * 1) There's an eof char set on the channel, and * we saw it and stopped translating at that point. * * NOTE the bizarre spec of TranslateInputEOL in this case. * Clearly the eof char had to be read in order to account * for the stopping, but the value of dstRead does not * include it. * * Also rather bizarre, our caller can only notice an * EOF condition if we return the value -1 as the number * of chars read. This forces us to perform a 2-call * dance where the first call can read all the chars * up to the eof char, and the second call is solely * for consuming the encoded eof char then pointed at * by src so that we can return that magic -1 value. * This seems really wasteful, especially since * the first decoding pass of each call is likely to * decode many bytes beyond that eof char that's all we * care about. */ if (dstRead == 0) { /* * Curious choice in the eof char handling. We leave * the eof char in the buffer. So, no need to compute * a proper srcRead value. At this point, there * are no chars before the eof char in the buffer. */ Tcl_SetObjLength(objPtr, numBytes); return -1; } { /* * There are chars leading the buffer before the eof * char. Adjust the dstLimit so we go back and read * only those and do not encounter the eof char this * time. */ dstLimit = dstRead + TCL_UTF_MAX; statePtr->flags = savedFlags; statePtr->inputEncodingFlags = savedIEFlags; statePtr->inputEncodingState = savedState; continue; } } /* * 2) The other way to read fewer bytes than are decoded * is when the final byte is \r and we're in a CRLF * translation mode so we cannot decide whether to * record \r or \n yet. */ assert(dstRead + 1 == dstDecoded); assert(dst[dstRead] == '\r'); assert(statePtr->inputTranslation == TCL_TRANSLATE_CRLF); if (dstWrote > 0) { /* * There are chars we can read before we hit the bare cr. * Go back with a smaller dstLimit so we get them in the * next pass, compute a matching srcRead, and don't end * up back here in this call. */ dstLimit = dstRead + TCL_UTF_MAX; statePtr->flags = savedFlags; statePtr->inputEncodingFlags = savedIEFlags; statePtr->inputEncodingState = savedState; continue; } assert(dstWrote == 0); assert(dstRead == 0); assert(dstDecoded == 1); /* * We decoded only the bare cr, and we cannot read a * translated char from that alone. We have to know what's * next. So why do we only have the one decoded char? */ if (code != TCL_OK) { char buffer[TCL_UTF_MAX + 2]; int read, decoded, count; /* * Didn't get everything the buffer could offer */ statePtr->flags = savedFlags; statePtr->inputEncodingFlags = savedIEFlags; statePtr->inputEncodingState = savedState; Tcl_ExternalToUtf(NULL, encoding, src, srcLen, statePtr->inputEncodingFlags & (bufPtr->nextPtr ? ~0 : ~TCL_ENCODING_END), &statePtr->inputEncodingState, buffer, TCL_UTF_MAX + 2, &read, &decoded, &count); if (count == 2) { if (buffer[1] == '\n') { /* \r\n translate to \n */ dst[0] = '\n'; bufPtr->nextRemoved += read; } else { dst[0] = '\r'; bufPtr->nextRemoved += srcRead; } dst[1] = '\0'; statePtr->inputEncodingFlags &= ~TCL_ENCODING_START; Tcl_SetObjLength(objPtr, numBytes + 1); return 1; } } else if (statePtr->flags & CHANNEL_EOF) { /* * The bare \r is the only char and we will never read * a subsequent char to make the determination. */ dst[0] = '\r'; bufPtr->nextRemoved = bufPtr->nextAdded; Tcl_SetObjLength(objPtr, numBytes + 1); return 1; } /* FALL THROUGH - get more data (dstWrote == 0) */ } /* * The translation transformation can only reduce the number * of chars when it converts \r\n into \n. The reduction in * the number of chars is the difference in bytes read and written. */ numChars -= (dstRead - dstWrote); if (charsToRead > 0 && numChars > charsToRead) { /* * We read more chars than allowed. Reset limits to * prevent that and try again. */ dstLimit = Tcl_UtfAtIndex(dst, charsToRead + 1) - dst; statePtr->flags = savedFlags; statePtr->inputEncodingFlags = savedIEFlags; statePtr->inputEncodingState = savedState; continue; } if (dstWrote == 0) { /* * We were not able to read any chars. Maybe there were * not enough src bytes to decode into a char. Maybe * a lone \r could not be translated (crlf mode). Need * to combine any unused src bytes we have in the first * buffer with subsequent bytes to try again. */ ChannelBuffer *nextPtr = bufPtr->nextPtr; if (nextPtr == NULL) { if (srcLen > 0) { SetFlag(statePtr, CHANNEL_NEED_MORE_DATA); } Tcl_SetObjLength(objPtr, numBytes); return -1; } /* * Space is made at the beginning of the buffer to copy the * previous unused bytes there. Check first if the buffer we * are using actually has enough space at its beginning for * the data we are copying. Because if not we will write over * the buffer management information, especially the 'nextPtr'. * * Note that the BUFFER_PADDING (See AllocChannelBuffer) is * used to prevent exactly this situation. I.e. it should never * happen. Therefore it is ok to panic should it happen despite * the precautions. */ if (nextPtr->nextRemoved - srcLen < 0) { Tcl_Panic("Buffer Underflow, BUFFER_PADDING not enough"); } nextPtr->nextRemoved -= srcLen; memcpy(RemovePoint(nextPtr), src, (size_t) srcLen); RecycleBuffer(statePtr, bufPtr, 0); statePtr->inQueueHead = nextPtr; Tcl_SetObjLength(objPtr, numBytes); return ReadChars(statePtr, objPtr, charsToRead, factorPtr); } statePtr->inputEncodingFlags &= ~TCL_ENCODING_START; bufPtr->nextRemoved += srcRead; if (dstWrote > srcRead + 1) { *factorPtr = dstWrote * UTF_EXPANSION_FACTOR / srcRead; } Tcl_SetObjLength(objPtr, numBytes + dstWrote); return numChars; } } /* *--------------------------------------------------------------------------- * * TranslateInputEOL -- * * Perform input EOL and EOF translation on the source buffer, leaving * the translated result in the destination buffer. * * Results: * The return value is 1 if the EOF character was found when copying * bytes to the destination buffer, 0 otherwise. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static void TranslateInputEOL( ChannelState *statePtr, /* Channel being read, for EOL translation and * EOF character. */ char *dstStart, /* Output buffer filled with chars by applying * appropriate EOL translation to source * characters. */ const char *srcStart, /* Source 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. */ { const char *eof = NULL; int dstLen = *dstLenPtr; int srcLen = *srcLenPtr; int inEofChar = statePtr->inEofChar; /* * Depending on the translation mode in use, there's no need * to scan more srcLen bytes at srcStart than can possibly transform * to dstLen bytes. This keeps the scan for eof char below from * being pointlessly long. */ switch (statePtr->inputTranslation) { case TCL_TRANSLATE_LF: case TCL_TRANSLATE_CR: if (srcLen > dstLen) { /* In these modes, each src byte become a dst byte. */ srcLen = dstLen; } break; default: /* In other modes, at most 2 src bytes become a dst byte. */ if (srcLen > 2 * dstLen) { srcLen = 2 * dstLen; } break; } if (inEofChar != '\0') { /* * Make sure we do not read past any logical end of channel input * created by the presence of the input eof char. */ if ((eof = memchr(srcStart, inEofChar, srcLen))) { srcLen = eof - srcStart; } } switch (statePtr->inputTranslation) { case TCL_TRANSLATE_LF: case TCL_TRANSLATE_CR: if (dstStart != srcStart) { memcpy(dstStart, srcStart, (size_t) srcLen); } if (statePtr->inputTranslation == TCL_TRANSLATE_CR) { char *dst = dstStart; char *dstEnd = dstStart + srcLen; while ((dst = memchr(dst, '\r', dstEnd - dst))) { *dst++ = '\n'; } } dstLen = srcLen; break; case TCL_TRANSLATE_CRLF: { const char *crFound, *src = srcStart; char *dst = dstStart; int lesser = (dstLen < srcLen) ? dstLen : srcLen; while ((crFound = memchr(src, '\r', lesser))) { int numBytes = crFound - src; memmove(dst, src, numBytes); dst += numBytes; dstLen -= numBytes; src += numBytes; srcLen -= numBytes; if (srcLen == 1) { /* valid src bytes end in \r */ if (eof) { *dst++ = '\r'; src++; srcLen--; } else { lesser = 0; break; } } else if (src[1] == '\n') { *dst++ = '\n'; src += 2; srcLen -= 2; } else { *dst++ = '\r'; src++; srcLen--; } dstLen--; lesser = (dstLen < srcLen) ? dstLen : srcLen; } memmove(dst, src, lesser); srcLen = src + lesser - srcStart; dstLen = dst + lesser - dstStart; break; } case TCL_TRANSLATE_AUTO: { const char *crFound, *src = srcStart; char *dst = dstStart; int lesser; if ((statePtr->flags & INPUT_SAW_CR) && srcLen) { if (*src == '\n') { src++; srcLen--; } ResetFlag(statePtr, INPUT_SAW_CR); } lesser = (dstLen < srcLen) ? dstLen : srcLen; while ((crFound = memchr(src, '\r', lesser))) { int numBytes = crFound - src; memmove(dst, src, numBytes); dst[numBytes] = '\n'; dst += numBytes + 1; dstLen -= numBytes + 1; src += numBytes + 1; srcLen -= numBytes + 1; if (srcLen == 0) { SetFlag(statePtr, INPUT_SAW_CR); } else if (*src == '\n') { src++; srcLen--; } lesser = (dstLen < srcLen) ? dstLen : srcLen; } memmove(dst, src, lesser); srcLen = src + lesser - srcStart; dstLen = dst + lesser - dstStart; break; } default: Tcl_Panic("unknown input translation %d", statePtr->inputTranslation); } *dstLenPtr = dstLen; *srcLenPtr = srcLen; if (srcStart + srcLen == eof) { /* * EOF character was seen in EOL translated range. Leave current file * position pointing at the EOF character, but don't store the EOF * character in the output string. */ SetFlag(statePtr, CHANNEL_EOF | CHANNEL_STICKY_EOF); statePtr->inputEncodingFlags |= TCL_ENCODING_END; ResetFlag(statePtr, INPUT_SAW_CR); } } /* *---------------------------------------------------------------------- * * Tcl_Ungets -- * |
︙ | ︙ | |||
6285 6286 6287 6288 6289 6290 6291 | if (CheckChannelErrors(statePtr, TCL_READABLE) != 0) { len = -1; goto done; } statePtr->flags = flags; /* | < < | < | < < | | 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 | if (CheckChannelErrors(statePtr, TCL_READABLE) != 0) { len = -1; goto done; } statePtr->flags = flags; /* * Clear the EOF flags, and clear the BLOCKED bit. */ ResetFlag(statePtr, CHANNEL_BLOCKED | CHANNEL_STICKY_EOF | CHANNEL_EOF | INPUT_SAW_CR); bufPtr = AllocChannelBuffer(len); memcpy(InsertPoint(bufPtr), str, (size_t) len); bufPtr->nextAdded += len; if (statePtr->inQueueHead == NULL) { bufPtr->nextPtr = NULL; |
︙ | ︙ | |||
6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 | /* *--------------------------------------------------------------------------- * * GetInput -- * * Reads input data from a device into a channel buffer. * * Results: * The return value is the Posix error code if an error occurred while * reading from the file, or 0 otherwise. * * Side effects: * Reads from the underlying device. * | > > > | 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 | /* *--------------------------------------------------------------------------- * * GetInput -- * * Reads input data from a device into a channel buffer. * * IMPORTANT! This routine is only called on a chanPtr argument * that is the top channel of a stack! * * Results: * The return value is the Posix error code if an error occurred while * reading from the file, or 0 otherwise. * * Side effects: * Reads from the underlying device. * |
︙ | ︙ | |||
6466 6467 6468 6469 6470 6471 6472 | } /* * First check for more buffers in the pushback area of the topmost * channel in the stack and use them. They can be the result of a * transformation which went away without reading all the information * placed in the area when it was stacked. | < < < < < < | > | 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 | } /* * First check for more buffers in the pushback area of the topmost * channel in the stack and use them. They can be the result of a * transformation which went away without reading all the information * placed in the area when it was stacked. */ if (chanPtr->inQueueHead != NULL) { assert(statePtr->inQueueHead == NULL); statePtr->inQueueHead = chanPtr->inQueueHead; statePtr->inQueueTail = chanPtr->inQueueTail; chanPtr->inQueueHead = NULL; chanPtr->inQueueTail = NULL; return 0; } |
︙ | ︙ | |||
6504 6505 6506 6507 6508 6509 6510 | toRead = SpaceLeft(bufPtr); } else { bufPtr = statePtr->saveInBufPtr; statePtr->saveInBufPtr = NULL; /* * Check the actual buffersize against the requested buffersize. | | | < < < < < < < < < < < < < < > > < < < < < < < < < < < < < < < < < < < < | | < < < < < < < < < < < < | 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 | toRead = SpaceLeft(bufPtr); } else { bufPtr = statePtr->saveInBufPtr; statePtr->saveInBufPtr = NULL; /* * Check the actual buffersize against the requested buffersize. * Saved buffers of the wrong size are squashed. This is done * to honor dynamic changes of the buffersize made by the user. */ if ((bufPtr != NULL) && (bufPtr->bufLength - BUFFER_PADDING != statePtr->bufSize)) { ReleaseChannelBuffer(bufPtr); bufPtr = NULL; } if (bufPtr == NULL) { bufPtr = AllocChannelBuffer(statePtr->bufSize); } bufPtr->nextPtr = NULL; toRead = SpaceLeft(bufPtr); assert(toRead == statePtr->bufSize); if (statePtr->inQueueTail == NULL) { statePtr->inQueueHead = bufPtr; } else { statePtr->inQueueTail->nextPtr = bufPtr; } statePtr->inQueueTail = bufPtr; } /* * TODO - consider escape before buffer alloc * If EOF is set, we should avoid calling the driver because on some * platforms it is impossible to read from a device after EOF. */ if (GotFlag(statePtr, CHANNEL_EOF)) { return 0; } PreserveChannelBuffer(bufPtr); nread = ChanRead(chanPtr, InsertPoint(bufPtr), toRead, &result); if (nread > 0) { result = 0; bufPtr->nextAdded += nread; /* * If we get a short read, signal up that we may be BLOCKED. We should * avoid calling the driver because on some platforms we will block in * the low level reading code even though the channel is set into * nonblocking mode. */ if (nread < toRead) { SetFlag(statePtr, CHANNEL_BLOCKED); } } else if (nread == 0) { result = 0; SetFlag(statePtr, CHANNEL_EOF); statePtr->inputEncodingFlags |= TCL_ENCODING_END; } else if (nread < 0) { if ((result == EWOULDBLOCK) || (result == EAGAIN)) { SetFlag(statePtr, CHANNEL_BLOCKED); |
︙ | ︙ | |||
7032 7033 7034 7035 7036 7037 7038 | if (BUSY_STATE(statePtr, flags) && ((flags & CHANNEL_RAW_MODE) == 0)) { Tcl_SetErrno(EBUSY); return -1; } if (direction == TCL_READABLE) { /* | < < | | < < < | 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 | if (BUSY_STATE(statePtr, flags) && ((flags & CHANNEL_RAW_MODE) == 0)) { Tcl_SetErrno(EBUSY); return -1; } if (direction == TCL_READABLE) { /* * Clear the BLOCKED bit. We want to discover this condition * anew in each operation. */ ResetFlag(statePtr, CHANNEL_BLOCKED | CHANNEL_NEED_MORE_DATA); } return 0; } /* |
︙ | ︙ | |||
7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 | if (sz < 1) { sz = 1; } else if (sz > MAX_CHANNEL_BUFFER_SIZE) { sz = MAX_CHANNEL_BUFFER_SIZE; } statePtr = ((Channel *) chan)->state; statePtr->bufSize = sz; } /* *---------------------------------------------------------------------- * * Tcl_GetChannelBufferSize -- * | > > > > > > > > > > > > > > > > > > > > | 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 | if (sz < 1) { sz = 1; } else if (sz > MAX_CHANNEL_BUFFER_SIZE) { sz = MAX_CHANNEL_BUFFER_SIZE; } statePtr = ((Channel *) chan)->state; if (statePtr->bufSize == sz) { return; } statePtr->bufSize = sz; /* * If bufsize changes, need to get rid of old utility buffer. */ if (statePtr->saveInBufPtr != NULL) { RecycleBuffer(statePtr, statePtr->saveInBufPtr, 1); statePtr->saveInBufPtr = NULL; } if ((statePtr->inQueueHead != NULL) && (statePtr->inQueueHead->nextPtr == NULL) && IsBufferEmpty(statePtr->inQueueHead)) { RecycleBuffer(statePtr, statePtr->inQueueHead, 1); statePtr->inQueueHead = NULL; statePtr->inQueueTail = NULL; } } /* *---------------------------------------------------------------------- * * Tcl_GetChannelBufferSize -- * |
︙ | ︙ | |||
7692 7693 7694 7695 7696 7697 7698 7699 7700 7701 7702 7703 7704 7705 | } else if (HaveOpt(7, "-buffersize")) { int newBufferSize; if (Tcl_GetInt(interp, newValue, &newBufferSize) == TCL_ERROR) { return TCL_ERROR; } Tcl_SetChannelBufferSize(chan, newBufferSize); } else if (HaveOpt(2, "-encoding")) { Tcl_Encoding encoding; if ((newValue[0] == '\0') || (strcmp(newValue, "binary") == 0)) { encoding = NULL; } else { encoding = Tcl_GetEncoding(interp, newValue); | > | 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 | } else if (HaveOpt(7, "-buffersize")) { int newBufferSize; if (Tcl_GetInt(interp, newValue, &newBufferSize) == TCL_ERROR) { return TCL_ERROR; } Tcl_SetChannelBufferSize(chan, newBufferSize); return TCL_OK; } else if (HaveOpt(2, "-encoding")) { Tcl_Encoding encoding; if ((newValue[0] == '\0') || (strcmp(newValue, "binary") == 0)) { encoding = NULL; } else { encoding = Tcl_GetEncoding(interp, newValue); |
︙ | ︙ | |||
7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 | statePtr->encoding = encoding; statePtr->inputEncodingState = NULL; statePtr->inputEncodingFlags = TCL_ENCODING_START; statePtr->outputEncodingState = NULL; statePtr->outputEncodingFlags = TCL_ENCODING_START; ResetFlag(statePtr, CHANNEL_NEED_MORE_DATA); UpdateInterest(chanPtr); } else if (HaveOpt(2, "-eofchar")) { if (Tcl_SplitList(interp, newValue, &argc, &argv) == TCL_ERROR) { return TCL_ERROR; } if (argc == 0) { statePtr->inEofChar = 0; statePtr->outEofChar = 0; | > | 7682 7683 7684 7685 7686 7687 7688 7689 7690 7691 7692 7693 7694 7695 7696 | statePtr->encoding = encoding; statePtr->inputEncodingState = NULL; statePtr->inputEncodingFlags = TCL_ENCODING_START; statePtr->outputEncodingState = NULL; statePtr->outputEncodingFlags = TCL_ENCODING_START; ResetFlag(statePtr, CHANNEL_NEED_MORE_DATA); UpdateInterest(chanPtr); return TCL_OK; } else if (HaveOpt(2, "-eofchar")) { if (Tcl_SplitList(interp, newValue, &argc, &argv) == TCL_ERROR) { return TCL_ERROR; } if (argc == 0) { statePtr->inEofChar = 0; statePtr->outEofChar = 0; |
︙ | ︙ | |||
7883 7884 7885 7886 7887 7888 7889 | } else if (chanPtr->typePtr->setOptionProc != NULL) { return chanPtr->typePtr->setOptionProc(chanPtr->instanceData, interp, optionName, newValue); } else { return Tcl_BadChannelOption(interp, optionName, NULL); } | < < < < < < < < < < < < < < < < | 7843 7844 7845 7846 7847 7848 7849 7850 7851 7852 7853 7854 7855 7856 | } else if (chanPtr->typePtr->setOptionProc != NULL) { return chanPtr->typePtr->setOptionProc(chanPtr->instanceData, interp, optionName, newValue); } else { return Tcl_BadChannelOption(interp, optionName, NULL); } return TCL_OK; } /* *---------------------------------------------------------------------- * * CleanupChannelHandlers -- |
︙ | ︙ | |||
7990 7991 7992 7993 7994 7995 7996 | /* State info for channel */ ChannelHandler *chPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); NextChannelHandler nh; Channel *upChanPtr; const Tcl_ChannelType *upTypePtr; | < < < < < < < < < < < < < < < | 7934 7935 7936 7937 7938 7939 7940 7941 7942 7943 7944 7945 7946 7947 | /* State info for channel */ ChannelHandler *chPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); NextChannelHandler nh; Channel *upChanPtr; const Tcl_ChannelType *upTypePtr; /* * In contrast to the other API functions this procedure walks towards the * top of a stack and not down from it. * * The channel calling this procedure is the one who generated the event, * and thus does not take part in handling it. IOW, its HandlerProc is not * called, instead we begin with the channel above it. |
︙ | ︙ | |||
8245 8246 8247 8248 8249 8250 8251 | /* * Restart the timer in case a channel handler reenters the event loop * before UpdateInterest gets called by Tcl_NotifyChannel. */ statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME, ChannelTimerProc,chanPtr); | < < < < < < < < < < < < < < < < < < < < < | 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189 | /* * Restart the timer in case a channel handler reenters the event loop * before UpdateInterest gets called by Tcl_NotifyChannel. */ statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME, ChannelTimerProc,chanPtr); Tcl_Preserve(statePtr); Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_READABLE); Tcl_Release(statePtr); } else { statePtr->timer = NULL; UpdateInterest(chanPtr); } } |
︙ | ︙ | |||
9195 9196 9197 9198 9199 9200 9201 | } /* *---------------------------------------------------------------------- * * DoRead -- * | > > | | > | > > > > > > > > | | | < < < < < > > | < < > | | < < > | | < | < < < < < > | < < < < < < < < > < < < | < < | < > | | | | < < | | < > | | | < | | < < < < < < < < < < < < | > > | < < < < | < < < < < < | < < < < | < | > > > | | < < < | < | < < | < < | < < < < < | | < < < | < < | | > | < < < < | | < | | | < < > > > > | | < < < < < | < < < < < | | < < < | < > | < | < < | | < | < | > | > | < | < | < | < < | < < < < < < < < < < | | < < < < < < | < < < < < | | | | < < < | < < < < | < | | < < < < | < | > | < < > | < < | | < < | < < > > | | < < < < < | < < < < < < | < | < < < < < < < | | | | | | | < > | < | < | > > > | | 9103 9104 9105 9106 9107 9108 9109 9110 9111 9112 9113 9114 9115 9116 9117 9118 9119 9120 9121 9122 9123 9124 9125 9126 9127 9128 9129 9130 9131 9132 9133 9134 9135 9136 9137 9138 9139 9140 9141 9142 9143 9144 9145 9146 9147 9148 9149 9150 9151 9152 9153 9154 9155 9156 9157 9158 9159 9160 9161 9162 9163 9164 9165 9166 9167 9168 9169 9170 9171 9172 9173 9174 9175 9176 9177 9178 9179 9180 9181 9182 9183 9184 9185 9186 9187 9188 9189 9190 9191 9192 9193 9194 9195 9196 9197 9198 9199 9200 9201 9202 9203 9204 9205 9206 9207 9208 9209 9210 9211 9212 9213 9214 9215 9216 9217 9218 9219 9220 9221 9222 9223 9224 9225 9226 9227 9228 9229 9230 9231 9232 9233 9234 9235 9236 9237 9238 9239 9240 9241 9242 9243 9244 9245 9246 9247 9248 9249 9250 9251 9252 9253 9254 9255 9256 9257 9258 9259 9260 9261 9262 9263 9264 9265 9266 9267 9268 9269 9270 9271 9272 9273 9274 9275 9276 9277 9278 9279 9280 9281 9282 9283 9284 9285 9286 9287 | } /* *---------------------------------------------------------------------- * * DoRead -- * * Stores up to "bytesToRead" bytes in memory pointed to by "dst". * These bytes come from reading the channel "chanPtr" and * performing the configured translations. No encoding conversions * are applied to the bytes being read. * * Results: * The number of bytes actually stored (<= bytesToRead), * or -1 if there is an error in reading the channel. Use * Tcl_GetErrno() to retrieve the error code for the error * that occurred. * * The number of bytes stored can be less than the number * requested when * - EOF is reached on the channel; or * - the channel is non-blocking, and we've read all we can * without blocking. * - a channel reading error occurs (and we return -1) * * Side effects: * May cause input to be buffered. * *---------------------------------------------------------------------- */ static int DoRead( Channel *chanPtr, /* The channel from which to read. */ char *dst, /* Where to store input read. */ int bytesToRead, /* Maximum number of bytes to read. */ int allowShortReads) /* Allow half-blocking (pipes,sockets) */ { ChannelState *statePtr = chanPtr->state; char *p = dst; Tcl_Preserve(chanPtr); while (bytesToRead) { /* * Each pass through the loop is intended to process up to * one channel buffer. */ int bytesRead, bytesWritten; ChannelBuffer *bufPtr = statePtr->inQueueHead; /* * When there's no buffered data to read, and we're at EOF, * escape to the caller. */ if (statePtr->flags & CHANNEL_EOF && (bufPtr == NULL || IsBufferEmpty(bufPtr))) { break; } /* If there is no full buffer, attempt to create and/or fill one. */ while (bufPtr == NULL || !IsBufferFull(bufPtr)) { int code; ResetFlag(statePtr, CHANNEL_BLOCKED); moreData: code = GetInput(chanPtr); bufPtr = statePtr->inQueueHead; assert (bufPtr != NULL); if (statePtr->flags & (CHANNEL_EOF|CHANNEL_BLOCKED)) { /* Further reads cannot do any more */ break; } if (code) { /* Read error */ UpdateInterest(chanPtr); Tcl_Release(chanPtr); return -1; } assert (IsBufferFull(bufPtr)); } assert (bufPtr != NULL); bytesRead = BytesLeft(bufPtr); bytesWritten = bytesToRead; TranslateInputEOL(statePtr, p, RemovePoint(bufPtr), &bytesWritten, &bytesRead); bufPtr->nextRemoved += bytesRead; p += bytesWritten; bytesToRead -= bytesWritten; if (!IsBufferEmpty(bufPtr)) { /* * Buffer is not empty. How can that be? * * 0) We stopped early because we got all the bytes * we were seeking. That's fine. */ if (bytesToRead == 0) { UpdateInterest(chanPtr); break; } /* * 1) We're @EOF because we saw eof char. */ if (statePtr->inEofChar && RemovePoint(bufPtr)[0] == statePtr->inEofChar) { UpdateInterest(chanPtr); break; } /* * 2) The buffer holds a \r while in CRLF translation, * followed by the end of the buffer. */ assert(statePtr->inputTranslation == TCL_TRANSLATE_CRLF); assert(RemovePoint(bufPtr)[0] == '\r'); assert(BytesLeft(bufPtr) == 1); if (bufPtr->nextPtr == NULL) { /* There's no more buffered data.... */ if (statePtr->flags & CHANNEL_EOF) { /* ...and there never will be. */ *p++ = '\r'; bytesToRead--; bufPtr->nextRemoved++; } else if (statePtr->flags & CHANNEL_BLOCKED) { /* ...and we cannot get more now. */ SetFlag(statePtr, CHANNEL_NEED_MORE_DATA); UpdateInterest(chanPtr); break; } else { /* ... so we need to get some. */ goto moreData; } } if (bufPtr->nextPtr) { /* There's a next buffer. Shift orphan \r to it. */ ChannelBuffer *nextPtr = bufPtr->nextPtr; nextPtr->nextRemoved -= 1; RemovePoint(nextPtr)[0] = '\r'; bufPtr->nextRemoved++; } } if (IsBufferEmpty(bufPtr)) { statePtr->inQueueHead = bufPtr->nextPtr; if (statePtr->inQueueHead == NULL) { statePtr->inQueueTail = NULL; } RecycleBuffer(statePtr, bufPtr, 0); } if ((statePtr->flags & CHANNEL_NONBLOCKING || allowShortReads) && statePtr->flags & CHANNEL_BLOCKED) { break; } } Tcl_Release(chanPtr); return (int)(p - dst); } /* *---------------------------------------------------------------------- * * CopyBuffer -- * |
︙ | ︙ | |||
9708 9709 9710 9711 9712 9713 9714 9715 9716 9717 9718 9719 | StackSetBlockMode( Channel *chanPtr, /* Channel to modify. */ int mode) /* One of TCL_MODE_BLOCKING or * TCL_MODE_NONBLOCKING. */ { int result = 0; Tcl_DriverBlockModeProc *blockModeProc; /* * Start at the top of the channel stack */ | > > > | | 9483 9484 9485 9486 9487 9488 9489 9490 9491 9492 9493 9494 9495 9496 9497 9498 9499 9500 9501 9502 9503 9504 9505 | StackSetBlockMode( Channel *chanPtr, /* Channel to modify. */ int mode) /* One of TCL_MODE_BLOCKING or * TCL_MODE_NONBLOCKING. */ { int result = 0; Tcl_DriverBlockModeProc *blockModeProc; ChannelState *statePtr = chanPtr->state; /* * Start at the top of the channel stack * TODO: Examine what can go wrong when blockModeProc calls * disturb the stacking state of the channel. */ chanPtr = statePtr->topChanPtr; while (chanPtr != NULL) { blockModeProc = Tcl_ChannelBlockModeProc(chanPtr->typePtr); if (blockModeProc != NULL) { result = blockModeProc(chanPtr->instanceData, mode); if (result != 0) { Tcl_SetErrno(result); return result; |
︙ | ︙ | |||
10852 10853 10854 10855 10856 10857 10858 10859 10860 10861 10862 10863 10864 10865 | 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); | > | 10630 10631 10632 10633 10634 10635 10636 10637 10638 10639 10640 10641 10642 10643 10644 | ChannelState *statePtr; if (interp == NULL) { return TCL_ERROR; } if (objPtr->typePtr == &chanObjType) { /* * TODO: TAINT Flag and dup'd channel values? * 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); |
︙ | ︙ | |||
10935 10936 10937 10938 10939 10940 10941 | ChanFlag('R', BUFFER_READY); ChanFlag('F', BG_FLUSH_SCHEDULED); ChanFlag('c', CHANNEL_CLOSED); ChanFlag('E', CHANNEL_EOF); ChanFlag('S', CHANNEL_STICKY_EOF); ChanFlag('B', CHANNEL_BLOCKED); ChanFlag('/', INPUT_SAW_CR); | < < < < < | 10714 10715 10716 10717 10718 10719 10720 10721 10722 10723 10724 10725 10726 10727 10728 10729 | ChanFlag('R', BUFFER_READY); ChanFlag('F', BG_FLUSH_SCHEDULED); ChanFlag('c', CHANNEL_CLOSED); ChanFlag('E', CHANNEL_EOF); ChanFlag('S', CHANNEL_STICKY_EOF); ChanFlag('B', CHANNEL_BLOCKED); ChanFlag('/', INPUT_SAW_CR); ChanFlag('D', CHANNEL_DEAD); ChanFlag('R', CHANNEL_RAW_MODE); ChanFlag('x', CHANNEL_INCLOSE); buf[i] ='\0'; fprintf(stderr, "%s: %s\n", str, buf); return 0; } |
︙ | ︙ |
Changes to generic/tclIO.h.
︙ | ︙ | |||
249 250 251 252 253 254 255 | #define CHANNEL_BLOCKED (1<<11) /* EWOULDBLOCK or EAGAIN occurred on * this channel. This bit is cleared * before every input or output * operation. */ #define INPUT_SAW_CR (1<<12) /* Channel is in CRLF eol input * translation mode and the last byte * seen was a "\r". */ | < < < < < < < < < < < < < < < < < < < < < < < < < < | 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 | #define CHANNEL_BLOCKED (1<<11) /* EWOULDBLOCK or EAGAIN occurred on * this channel. This bit is cleared * before every input or output * operation. */ #define INPUT_SAW_CR (1<<12) /* Channel is in CRLF eol input * translation mode and the last byte * seen was a "\r". */ #define CHANNEL_DEAD (1<<13) /* The channel has been closed by the * exit handler (on exit) but not * deallocated. When any IO operation * sees this flag on a channel, it * does not call driver level * functions to avoid referring to * deallocated data. */ #define CHANNEL_NEED_MORE_DATA (1<<14) /* The last input operation failed * because there was not enough data * to complete the operation. This * flag is set when gets fails to get * a complete line or when read fails * to get a complete character. When * set, file events will not be * delivered for buffered data until * the state of the channel * changes. */ #define CHANNEL_RAW_MODE (1<<16) /* When set, notes that the Raw API is * being used. */ #define CHANNEL_INCLOSE (1<<19) /* Channel is currently being closed. * Its structures are still live and * usable, but it may not be closed * again from within the close * handler. */ #define CHANNEL_TAINTED (1<<20) /* Channel stack structure has changed. |
︙ | ︙ |
Changes to generic/tclIOCmd.c.
︙ | ︙ | |||
332 333 334 335 336 337 338 | goto done; } lineLen = -1; } if (objc == 3) { if (Tcl_ObjSetVar2(interp, objv[2], NULL, linePtr, TCL_LEAVE_ERR_MSG) == NULL) { | | > | 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | goto done; } lineLen = -1; } if (objc == 3) { if (Tcl_ObjSetVar2(interp, objv[2], NULL, linePtr, TCL_LEAVE_ERR_MSG) == NULL) { code = TCL_ERROR; goto done; } Tcl_SetObjResult(interp, Tcl_NewIntObj(lineLen)); } else { Tcl_SetObjResult(interp, linePtr); } done: Tcl_Release(chan); |
︙ | ︙ |
Changes to generic/tclIOGT.c.
︙ | ︙ | |||
294 295 296 297 298 299 300 | dataPtr->readIsFlushed = 0; dataPtr->flags = 0; if (ds.string[0] == '0') { dataPtr->flags |= CHANNEL_ASYNC; } Tcl_DStringFree(&ds); | < > | 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | dataPtr->readIsFlushed = 0; dataPtr->flags = 0; if (ds.string[0] == '0') { dataPtr->flags |= CHANNEL_ASYNC; } Tcl_DStringFree(&ds); dataPtr->watchMask = 0; dataPtr->mode = mode; dataPtr->timer = NULL; dataPtr->maxRead = 4096; /* Initial value not relevant. */ dataPtr->interp = interp; dataPtr->command = cmdObjPtr; Tcl_IncrRefCount(dataPtr->command); ResultInit(&dataPtr->result); dataPtr->self = Tcl_StackChannel(interp, &transformChannelType, dataPtr, mode, chan); if (dataPtr->self == NULL) { Tcl_AppendPrintfToObj(Tcl_GetObjResult(interp), "\nfailed to stack channel \"%s\"", Tcl_GetChannelName(chan)); ReleaseData(dataPtr); return TCL_ERROR; } Tcl_Preserve(dataPtr->self); /* * At last initialize the transformation at the script level. */ PreserveData(dataPtr); if ((dataPtr->mode & TCL_WRITABLE) && ExecuteCallback(dataPtr, NULL, |
︙ | ︙ | |||
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 | switch (transmit) { case TRANSMIT_DONT: /* nothing to do */ break; case TRANSMIT_DOWN: resObj = Tcl_GetObjResult(eval); resBuf = Tcl_GetByteArrayFromObj(resObj, &resLen); Tcl_WriteRaw(Tcl_GetStackedChannel(dataPtr->self), (char *) resBuf, resLen); break; case TRANSMIT_SELF: resObj = Tcl_GetObjResult(eval); resBuf = Tcl_GetByteArrayFromObj(resObj, &resLen); Tcl_WriteRaw(dataPtr->self, (char *) resBuf, resLen); break; case TRANSMIT_IBUF: resObj = Tcl_GetObjResult(eval); | > > > > > > | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 | switch (transmit) { case TRANSMIT_DONT: /* nothing to do */ break; case TRANSMIT_DOWN: if (dataPtr->self == NULL) { break; } resObj = Tcl_GetObjResult(eval); resBuf = Tcl_GetByteArrayFromObj(resObj, &resLen); Tcl_WriteRaw(Tcl_GetStackedChannel(dataPtr->self), (char *) resBuf, resLen); break; case TRANSMIT_SELF: if (dataPtr->self == NULL) { break; } resObj = Tcl_GetObjResult(eval); resBuf = Tcl_GetByteArrayFromObj(resObj, &resLen); Tcl_WriteRaw(dataPtr->self, (char *) resBuf, resLen); break; case TRANSMIT_IBUF: resObj = Tcl_GetObjResult(eval); |
︙ | ︙ | |||
575 576 577 578 579 580 581 582 583 584 585 586 587 588 | } ReleaseData(dataPtr); /* * General cleanup. */ ReleaseData(dataPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * | > > | 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 | } ReleaseData(dataPtr); /* * General cleanup. */ Tcl_Release(dataPtr->self); dataPtr->self = NULL; ReleaseData(dataPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * |
︙ | ︙ | |||
610 611 612 613 614 615 616 | int gotBytes, read, copied; Tcl_Channel downChan; /* * Should assert(dataPtr->mode & TCL_READABLE); */ | | | 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 | int gotBytes, read, copied; Tcl_Channel downChan; /* * Should assert(dataPtr->mode & TCL_READABLE); */ if (toRead == 0 || dataPtr->self == NULL) { /* * Catch a no-op. */ return 0; } gotBytes = 0; |
︙ | ︙ | |||
1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 | * events on the channel below via a call to our 'TransformNotifyProc'. * But we have to pass the interest down now. We are allowed to add * additional 'interest' to the mask if we want to. But this * transformation has no such interest. It just passes the request down, * unchanged. */ downChan = Tcl_GetStackedChannel(dataPtr->self); Tcl_GetChannelType(downChan)->watchProc( Tcl_GetChannelInstanceData(downChan), mask); /* * Management of the internal timer. | > > > | 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 | * events on the channel below via a call to our 'TransformNotifyProc'. * But we have to pass the interest down now. We are allowed to add * additional 'interest' to the mask if we want to. But this * transformation has no such interest. It just passes the request down, * unchanged. */ if (dataPtr->self == NULL) { return; } downChan = Tcl_GetStackedChannel(dataPtr->self); Tcl_GetChannelType(downChan)->watchProc( Tcl_GetChannelInstanceData(downChan), mask); /* * Management of the internal timer. |
︙ | ︙ |
Changes to generic/tclIORChan.c.
︙ | ︙ | |||
446 447 448 449 450 451 452 | static const char *msg_read_toomuch = "{read delivered more than requested}"; static const char *msg_write_toomuch = "{write wrote more than requested}"; static const char *msg_write_nothing = "{write wrote nothing}"; static const char *msg_seek_beforestart = "{Tried to seek before origin}"; #ifdef TCL_THREADS static const char *msg_send_originlost = "{Channel thread lost}"; | < > | 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 | static const char *msg_read_toomuch = "{read delivered more than requested}"; static const char *msg_write_toomuch = "{write wrote more than requested}"; static const char *msg_write_nothing = "{write wrote nothing}"; static const char *msg_seek_beforestart = "{Tried to seek before origin}"; #ifdef TCL_THREADS static const char *msg_send_originlost = "{Channel thread lost}"; #endif /* TCL_THREADS */ static const char *msg_send_dstlost = "{Owner lost}"; static const char *msg_dstlost = "-code 1 -level 0 -errorcode NONE -errorinfo {} -errorline 1 {Owner lost}"; /* * Main methods to plug into the 'chan' ensemble'. ================== */ /* |
︙ | ︙ | |||
1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 | { ReflectedChannel *rcPtr = clientData; int result; /* Result code for 'close' */ Tcl_Obj *resObj; /* Result data for 'close' */ ReflectedChannelMap *rcmPtr;/* Map of reflected channels with handlers in * this interp */ Tcl_HashEntry *hPtr; /* Entry in the above map */ if (TclInThreadExit()) { /* * This call comes from TclFinalizeIOSystem. There are no * interpreters, and therefore we cannot call upon the handler command * anymore. Threading is irrelevant as well. We simply clean up all * our C level data structures and leave the Tcl level to the other | > | 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 | { ReflectedChannel *rcPtr = clientData; int result; /* Result code for 'close' */ Tcl_Obj *resObj; /* Result data for 'close' */ ReflectedChannelMap *rcmPtr;/* Map of reflected channels with handlers in * this interp */ Tcl_HashEntry *hPtr; /* Entry in the above map */ const Tcl_ChannelType *tctPtr; if (TclInThreadExit()) { /* * This call comes from TclFinalizeIOSystem. There are no * interpreters, and therefore we cannot call upon the handler command * anymore. Threading is irrelevant as well. We simply clean up all * our C level data structures and leave the Tcl level to the other |
︙ | ︙ | |||
1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 | if (result != TCL_OK) { FreeReceivedError(&p); } return EOK; } #endif Tcl_EventuallyFree(rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); return EOK; } /* * Are we in the correct thread? */ | > > > > > | 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 | if (result != TCL_OK) { FreeReceivedError(&p); } return EOK; } #endif tctPtr = ((Channel *)rcPtr->chan)->typePtr; if (tctPtr && tctPtr != &tclRChannelType) { ckfree((char *)tctPtr); ((Channel *)rcPtr->chan)->typePtr = NULL; } Tcl_EventuallyFree(rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); return EOK; } /* * Are we in the correct thread? */ |
︙ | ︙ | |||
1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 | hPtr = Tcl_FindHashEntry(&rcmPtr->map, Tcl_GetChannelName(rcPtr->chan)); if (hPtr) { Tcl_DeleteHashEntry(hPtr); } #endif Tcl_EventuallyFree(rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); #ifdef TCL_THREADS } #endif return (result == TCL_OK) ? EOK : EINVAL; } | > > > > > | 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 | hPtr = Tcl_FindHashEntry(&rcmPtr->map, Tcl_GetChannelName(rcPtr->chan)); if (hPtr) { Tcl_DeleteHashEntry(hPtr); } #endif tctPtr = ((Channel *)rcPtr->chan)->typePtr; if (tctPtr && tctPtr != &tclRChannelType) { ckfree((char *)tctPtr); ((Channel *)rcPtr->chan)->typePtr = NULL; } Tcl_EventuallyFree(rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); #ifdef TCL_THREADS } #endif return (result == TCL_OK) ? EOK : EINVAL; } |
︙ | ︙ | |||
1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 | } #endif /* ASSERT: rcPtr->method & FLAG(METH_WRITE) */ /* ASSERT: rcPtr->mode & TCL_WRITABLE */ Tcl_Preserve(rcPtr); bufObj = Tcl_NewByteArrayObj((unsigned char *) buf, toWrite); Tcl_IncrRefCount(bufObj); if (InvokeTclMethod(rcPtr, METH_WRITE, bufObj, NULL, &resObj) != TCL_OK) { int code = ErrnoReturn(rcPtr, resObj); if (code < 0) { *errorCodePtr = -code; goto error; } Tcl_SetChannelError(rcPtr->chan, resObj); goto invalid; } if (Tcl_GetIntFromObj(rcPtr->interp, resObj, &written) != TCL_OK) { Tcl_SetChannelError(rcPtr->chan, MarshallError(rcPtr->interp)); goto invalid; } if ((written == 0) && (toWrite > 0)) { /* | > > > > > > > > > | 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 | } #endif /* ASSERT: rcPtr->method & FLAG(METH_WRITE) */ /* ASSERT: rcPtr->mode & TCL_WRITABLE */ Tcl_Preserve(rcPtr); Tcl_Preserve(rcPtr->interp); bufObj = Tcl_NewByteArrayObj((unsigned char *) buf, toWrite); Tcl_IncrRefCount(bufObj); if (InvokeTclMethod(rcPtr, METH_WRITE, bufObj, NULL, &resObj) != TCL_OK) { int code = ErrnoReturn(rcPtr, resObj); if (code < 0) { *errorCodePtr = -code; goto error; } Tcl_SetChannelError(rcPtr->chan, resObj); goto invalid; } if (Tcl_InterpDeleted(rcPtr->interp)) { /* * The interp was destroyed during InvokeTclMethod(). */ SetChannelErrorStr(rcPtr->chan, msg_send_dstlost); goto invalid; } if (Tcl_GetIntFromObj(rcPtr->interp, resObj, &written) != TCL_OK) { Tcl_SetChannelError(rcPtr->chan, MarshallError(rcPtr->interp)); goto invalid; } if ((written == 0) && (toWrite > 0)) { /* |
︙ | ︙ | |||
1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 | goto invalid; } *errorCodePtr = EOK; stop: Tcl_DecrRefCount(bufObj); Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */ Tcl_Release(rcPtr); return written; invalid: *errorCodePtr = EINVAL; error: written = -1; goto stop; | > | 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 | goto invalid; } *errorCodePtr = EOK; stop: Tcl_DecrRefCount(bufObj); Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */ Tcl_Release(rcPtr->interp); Tcl_Release(rcPtr); return written; invalid: *errorCodePtr = EINVAL; error: written = -1; goto stop; |
︙ | ︙ | |||
2166 2167 2168 2169 2170 2171 2172 | static void FreeReflectedChannel( ReflectedChannel *rcPtr) { Channel *chanPtr = (Channel *) rcPtr->chan; | < < < < < < < < | 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 | static void FreeReflectedChannel( ReflectedChannel *rcPtr) { Channel *chanPtr = (Channel *) rcPtr->chan; Tcl_Release(chanPtr); Tcl_DecrRefCount(rcPtr->name); Tcl_DecrRefCount(rcPtr->methods); Tcl_DecrRefCount(rcPtr->cmd); ckfree(rcPtr); } |
︙ | ︙ | |||
2869 2870 2871 2872 2873 2874 2875 | switch (evPtr->op) { /* * The destination thread for the following operations is * rcPtr->thread, which contains rcPtr->interp, the interp we have to * call upon for the driver. */ | | > > | 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 | switch (evPtr->op) { /* * The destination thread for the following operations is * rcPtr->thread, which contains rcPtr->interp, the interp we have to * call upon for the driver. */ case ForwardedClose: { /* * No parameters/results. */ const Tcl_ChannelType *tctPtr; if (InvokeTclMethod(rcPtr, METH_FINAL, NULL, NULL, &resObj)!=TCL_OK) { ForwardSetObjError(paramPtr, resObj); } /* * Freeing is done here, in the origin thread, callback command |
︙ | ︙ | |||
2898 2899 2900 2901 2902 2903 2904 | Tcl_DeleteHashEntry(hPtr); rcmPtr = GetThreadReflectedChannelMap(); hPtr = Tcl_FindHashEntry(&rcmPtr->map, Tcl_GetChannelName(rcPtr->chan)); Tcl_DeleteHashEntry(hPtr); | > > > > > | > | 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 | Tcl_DeleteHashEntry(hPtr); rcmPtr = GetThreadReflectedChannelMap(); hPtr = Tcl_FindHashEntry(&rcmPtr->map, Tcl_GetChannelName(rcPtr->chan)); Tcl_DeleteHashEntry(hPtr); tctPtr = ((Channel *)rcPtr->chan)->typePtr; if (tctPtr && tctPtr != &tclRChannelType) { ckfree((char *)tctPtr); ((Channel *)rcPtr->chan)->typePtr = NULL; } Tcl_EventuallyFree(rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); break; } case ForwardedInput: { Tcl_Obj *toReadObj = Tcl_NewIntObj(paramPtr->input.toRead); Tcl_IncrRefCount(toReadObj); Tcl_Preserve(rcPtr); if (InvokeTclMethod(rcPtr, METH_READ, toReadObj, NULL, &resObj)!=TCL_OK){ |
︙ | ︙ |
Changes to generic/tclInt.h.
︙ | ︙ | |||
2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 | int *typePtr); MODULE_SCOPE int TclGetOpenModeEx(Tcl_Interp *interp, const char *modeString, int *seekFlagPtr, int *binaryPtr); MODULE_SCOPE Tcl_Obj * TclGetProcessGlobalValue(ProcessGlobalValue *pgvPtr); MODULE_SCOPE Tcl_Obj * TclGetSourceFromFrame(CmdFrame *cfPtr, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TclIncrObj(Tcl_Interp *interp, Tcl_Obj *valuePtr, Tcl_Obj *incrPtr); MODULE_SCOPE Tcl_Obj * TclIncrObjVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *incrPtr, int flags); MODULE_SCOPE int TclInfoExistsCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TclInfoCoroutineCmd(ClientData dummy, Tcl_Interp *interp, | > > | 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 | int *typePtr); MODULE_SCOPE int TclGetOpenModeEx(Tcl_Interp *interp, const char *modeString, int *seekFlagPtr, int *binaryPtr); MODULE_SCOPE Tcl_Obj * TclGetProcessGlobalValue(ProcessGlobalValue *pgvPtr); MODULE_SCOPE Tcl_Obj * TclGetSourceFromFrame(CmdFrame *cfPtr, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE char * TclGetStringStorage(Tcl_Obj *objPtr, unsigned int *sizePtr); MODULE_SCOPE int TclIncrObj(Tcl_Interp *interp, Tcl_Obj *valuePtr, Tcl_Obj *incrPtr); MODULE_SCOPE Tcl_Obj * TclIncrObjVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *incrPtr, int flags); MODULE_SCOPE int TclInfoExistsCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE int TclInfoCoroutineCmd(ClientData dummy, Tcl_Interp *interp, |
︙ | ︙ |
Changes to generic/tclStringObj.c.
︙ | ︙ | |||
1119 1120 1121 1122 1123 1124 1125 | if (length <= limit) { toCopy = length; } else { if (ellipsis == NULL) { ellipsis = "..."; } | > | | 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 | if (length <= limit) { toCopy = length; } else { if (ellipsis == NULL) { ellipsis = "..."; } toCopy = (bytes == NULL) ? limit : Tcl_UtfPrev(bytes+limit+1-strlen(ellipsis), bytes) - bytes; } /* * If objPtr has a valid Unicode rep, then append the Unicode conversion * of "bytes" to the objPtr's Unicode rep, otherwise append "bytes" to * objPtr's string rep. */ |
︙ | ︙ | |||
1431 1432 1433 1434 1435 1436 1437 | /* * Protect against case where unicode points into the existing * stringPtr->unicode array. Force it to follow any relocations due to * the reallocs below. */ | | | 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 | /* * Protect against case where unicode points into the existing * stringPtr->unicode array. Force it to follow any relocations due to * the reallocs below. */ if (unicode && unicode >= stringPtr->unicode && unicode <= stringPtr->unicode + stringPtr->maxChars) { offset = unicode - stringPtr->unicode; } GrowUnicodeBuffer(objPtr, numChars); stringPtr = GET_STRING(objPtr); |
︙ | ︙ | |||
1453 1454 1455 1456 1457 1458 1459 | } /* * Copy the new string onto the end of the old string, then add the * trailing null. */ | > | | > | 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 | } /* * Copy the new string onto the end of the old string, then add the * trailing null. */ if (unicode) { memmove(stringPtr->unicode + stringPtr->numChars, unicode, appendNumChars * sizeof(Tcl_UniChar)); } stringPtr->unicode[numChars] = 0; stringPtr->numChars = numChars; stringPtr->allocated = 0; TclInvalidateStringRep(objPtr); } |
︙ | ︙ | |||
1593 1594 1595 1596 1597 1598 1599 | /* * Protect against case where unicode points into the existing * stringPtr->unicode array. Force it to follow any relocations due to * the reallocs below. */ | | | 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 | /* * Protect against case where unicode points into the existing * stringPtr->unicode array. Force it to follow any relocations due to * the reallocs below. */ if (bytes && bytes >= objPtr->bytes && bytes <= objPtr->bytes + objPtr->length) { offset = bytes - objPtr->bytes; } /* * TODO: consider passing flag=1: no overalloc on first append. This * would make test stringObj-8.1 fail. |
︙ | ︙ | |||
1621 1622 1623 1624 1625 1626 1627 | /* * Invalidate the unicode data. */ stringPtr->numChars = -1; stringPtr->hasUnicode = 0; | > | > | 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 | /* * Invalidate the unicode data. */ stringPtr->numChars = -1; stringPtr->hasUnicode = 0; if (bytes) { memmove(objPtr->bytes + oldLength, bytes, numBytes); } objPtr->bytes[newLength] = 0; objPtr->length = newLength; } /* *---------------------------------------------------------------------- * |
︙ | ︙ | |||
2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 | va_end(argList); return objPtr; } /* *--------------------------------------------------------------------------- * * TclStringObjReverse -- * * Implements the [string reverse] operation. * * Results: * An unshared Tcl value which is the [string reverse] of the argument * supplied. When sharing rules permit, the returned value might be the | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 | va_end(argList); return objPtr; } /* *--------------------------------------------------------------------------- * * TclGetStringStorage -- * * Returns the string storage space of a Tcl_Obj. * * Results: * The pointer value objPtr->bytes is returned and the number of bytes * allocated there is written to *sizePtr (if known). * * Side effects: * May set objPtr->bytes. * *--------------------------------------------------------------------------- */ char * TclGetStringStorage( Tcl_Obj *objPtr, unsigned int *sizePtr) { String *stringPtr; if (objPtr->typePtr != &tclStringType || objPtr->bytes == NULL) { return TclGetStringFromObj(objPtr, (int *)sizePtr); } stringPtr = GET_STRING(objPtr); *sizePtr = stringPtr->allocated; return objPtr->bytes; } /* *--------------------------------------------------------------------------- * * TclStringObjReverse -- * * Implements the [string reverse] operation. * * Results: * An unshared Tcl value which is the [string reverse] of the argument * supplied. When sharing rules permit, the returned value might be the |
︙ | ︙ | |||
2844 2845 2846 2847 2848 2849 2850 | if (needed > stringPtr->maxChars) { GrowUnicodeBuffer(objPtr, needed); stringPtr = GET_STRING(objPtr); } stringPtr->hasUnicode = 1; | > | > > > | 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 | if (needed > stringPtr->maxChars) { GrowUnicodeBuffer(objPtr, needed); stringPtr = GET_STRING(objPtr); } stringPtr->hasUnicode = 1; if (bytes) { stringPtr->numChars = needed; } else { numAppendChars = 0; } for (dst=stringPtr->unicode + numOrigChars; numAppendChars-- > 0; dst++) { bytes += TclUtfToUniChar(bytes, dst); } *dst = 0; } /* |
︙ | ︙ |
Changes to tests/io.test.
︙ | ︙ | |||
4749 4750 4751 4752 4753 4754 4755 | set f [open $path(test1) r] fconfigure $f -translation crlf -eofchar \x1a set l [string length [set in [read $f]]] set e [eof $f] close $f list $s $l $e [scan [string index $in end] %c] } -result {9 8 1 13} | | | 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 | set f [open $path(test1) r] fconfigure $f -translation crlf -eofchar \x1a set l [string length [set in [read $f]]] set e [eof $f] close $f list $s $l $e [scan [string index $in end] %c] } -result {9 8 1 13} test io-35.18b {Tcl_Eof, eof char, cr write, crlf read} -body { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr -eofchar \x1a puts $f {} close $f set s [file size $path(test1)] set f [open $path(test1) r] |
︙ | ︙ | |||
4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 | set f [open $path(test1) r] fconfigure $f -translation crlf -eofchar \x1a set l [string length [set in [read $f]]] set e [eof $f] close $f list $c $l $e [scan [string index $in end] %c] } -result {17 8 1 13} # Test Tcl_InputBlocked test io-36.1 {Tcl_InputBlocked on nonblocking pipe} {stdio openpipe} { set f1 [open "|[list [interpreter]]" r+] puts $f1 {puts hello_from_pipe} flush $f1 | > > > > > > > > > > > > > > > | 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 | set f [open $path(test1) r] fconfigure $f -translation crlf -eofchar \x1a set l [string length [set in [read $f]]] set e [eof $f] close $f list $c $l $e [scan [string index $in end] %c] } -result {17 8 1 13} test io-35.20 {Tcl_Eof, eof char in middle, cr write, crlf read} { file delete $path(test1) set f [open $path(test1) w] fconfigure $f -translation cr -eofchar {} set i [format \n%cqrsuvw 26] puts $f $i close $f set c [file size $path(test1)] set f [open $path(test1) r] fconfigure $f -translation crlf -eofchar \x1a set l [string length [set in [read $f]]] set e [eof $f] close $f list $c $l $e [scan [string index $in end] %c] } {9 1 1 13} # Test Tcl_InputBlocked test io-36.1 {Tcl_InputBlocked on nonblocking pipe} {stdio openpipe} { set f1 [open "|[list [interpreter]]" r+] puts $f1 {puts hello_from_pipe} flush $f1 |
︙ | ︙ | |||
6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 | fcopy $in $out close $in close $out file size $path(kyrillic.txt) } 3 test io-53.1 {CopyData} {fcopy} { file delete $path(test1) set f1 [open $thisScript] set f2 [open $path(test1) w] fconfigure $f1 -translation lf -blocking 0 fconfigure $f2 -translation cr -blocking 0 | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 | fcopy $in $out close $in close $out file size $path(kyrillic.txt) } 3 test io-52.12 {coverage of -translation auto} { file delete $path(test1) $path(test2) set out [open $path(test1) wb] chan configure $out -translation lf puts -nonewline $out abcdefg\rhijklmn\nopqrstu\r\nvwxyz close $out set in [open $path(test1)] chan configure $in -buffersize 8 set out [open $path(test2) w] fcopy $in $out close $in close $out file size $path(test2) } 29 test io-52.13 {coverage of -translation cr} { file delete $path(test1) $path(test2) set out [open $path(test1) wb] chan configure $out -translation lf puts -nonewline $out abcdefg\rhijklmn\nopqrstu\r\nvwxyz close $out set in [open $path(test1)] chan configure $in -buffersize 8 -translation cr set out [open $path(test2) w] fcopy $in $out close $in close $out file size $path(test2) } 30 test io-52.14 {coverage of -translation crlf} { file delete $path(test1) $path(test2) set out [open $path(test1) wb] chan configure $out -translation lf puts -nonewline $out abcdefg\rhijklmn\nopqrstu\r\nvwxyz close $out set in [open $path(test1)] chan configure $in -buffersize 8 -translation crlf set out [open $path(test2) w] fcopy $in $out close $in close $out file size $path(test2) } 29 test io-52.14.1 {coverage of -translation crlf} { file delete $path(test1) $path(test2) set out [open $path(test1) wb] chan configure $out -translation lf puts -nonewline $out abcdefg\rhijklmn\nopqrstu\r\nvwxyz close $out set in [open $path(test1)] chan configure $in -buffersize 8 -translation crlf set out [open $path(test2) w] fcopy $in $out -size 2 close $in close $out file size $path(test2) } 2 test io-52.14.2 {coverage of -translation crlf} { file delete $path(test1) $path(test2) set out [open $path(test1) wb] chan configure $out -translation lf puts -nonewline $out abcdefg\rhijklmn\nopqrstu\r\nvwxyz close $out set in [open $path(test1)] chan configure $in -translation crlf set out [open $path(test2) w] fcopy $in $out -size 9 close $in close $out file size $path(test2) } 9 test io-52.15 {coverage of -translation crlf} { file delete $path(test1) $path(test2) set out [open $path(test1) wb] chan configure $out -translation lf puts -nonewline $out abcdefg\r close $out set in [open $path(test1)] chan configure $in -buffersize 8 -translation crlf set out [open $path(test2) w] fcopy $in $out close $in close $out file size $path(test2) } 8 test io-52.16 {coverage of eofChar handling} { file delete $path(test1) $path(test2) set out [open $path(test1) wb] chan configure $out -translation lf puts -nonewline $out abcdefg\rhijklmn\nopqrstu\r\nvwxyz close $out set in [open $path(test1)] chan configure $in -buffersize 8 -translation lf -eofchar a set out [open $path(test2) w] fcopy $in $out close $in close $out file size $path(test2) } 0 test io-52.17 {coverage of eofChar handling} { file delete $path(test1) $path(test2) set out [open $path(test1) wb] chan configure $out -translation lf puts -nonewline $out abcdefg\rhijklmn\nopqrstu\r\nvwxyz close $out set in [open $path(test1)] chan configure $in -buffersize 8 -translation lf -eofchar d set out [open $path(test2) w] fcopy $in $out close $in close $out file size $path(test2) } 3 test io-52.18 {coverage of eofChar handling} { file delete $path(test1) $path(test2) set out [open $path(test1) wb] chan configure $out -translation lf puts -nonewline $out abcdefg\rhijklmn\nopqrstu\r\nvwxyz close $out set in [open $path(test1)] chan configure $in -buffersize 8 -translation crlf -eofchar h set out [open $path(test2) w] fcopy $in $out close $in close $out file size $path(test2) } 8 test io-52.19 {coverage of eofChar handling} { file delete $path(test1) $path(test2) set out [open $path(test1) wb] chan configure $out -translation lf puts -nonewline $out abcdefg\rhijklmn\nopqrstu\r\nvwxyz close $out set in [open $path(test1)] chan configure $in -buffersize 10 -translation crlf -eofchar h set out [open $path(test2) w] fcopy $in $out close $in close $out file size $path(test2) } 8 test io-53.1 {CopyData} {fcopy} { file delete $path(test1) set f1 [open $thisScript] set f2 [open $path(test1) w] fconfigure $f1 -translation lf -blocking 0 fconfigure $f2 -translation cr -blocking 0 |
︙ | ︙ | |||
7290 7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 | set done } -cleanup { close $outChan close $inChan removeFile out removeFile in } -result {40 bytes copied} test io-54.1 {Recursive channel events} {socket fileevent} { # This test checks to see if file events are delivered during recursive # event loops when there is buffered data on the channel. proc accept {s a p} { variable as | > > > > > > > > > > > > > > > > > > > | 7446 7447 7448 7449 7450 7451 7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 | set done } -cleanup { close $outChan close $inChan removeFile out removeFile in } -result {40 bytes copied} test io-53.12 {CopyData: foreground short reads, aka bug 3096275} {stdio unix openpipe fcopy} { file delete $path(pipe) set f1 [open $path(pipe) w] puts -nonewline $f1 { fconfigure stdin -translation binary -blocking 0 fconfigure stdout -buffering none -translation binary fcopy stdin stdout } close $f1 set f1 [open "|[list [interpreter] $path(pipe)]" r+] fconfigure $f1 -translation binary -buffering none puts -nonewline $f1 A after 2000 {set ::done timeout} fileevent $f1 readable {set ::done ok} vwait ::done set ch [read $f1 1] close $f1 list $::done $ch } {ok A} test io-54.1 {Recursive channel events} {socket fileevent} { # This test checks to see if file events are delivered during recursive # event loops when there is buffered data on the channel. proc accept {s a p} { variable as |
︙ | ︙ |
Changes to tests/ioCmd.test.
︙ | ︙ | |||
2072 2073 2074 2075 2076 2077 2078 | # Set up channel in thread set chan [interp eval $ida $helperscript] set chan [interp eval $ida { proc foo {args} { oninit; onfinal; track; # destroy interpreter during channel access | < < | > > | < | 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 | # Set up channel in thread set chan [interp eval $ida $helperscript] set chan [interp eval $ida { proc foo {args} { oninit; onfinal; track; # destroy interpreter during channel access suicide } set chan [chan create {r w} foo] fconfigure $chan -buffering none set chan }] interp alias $ida suicide {} interp delete $ida # Move channel to 2nd thread. interp eval $ida [list testchannel cut $chan] interp eval $idb [list testchannel splice $chan] # Run access from interpreter B, this will give us a synchronous # response. interp eval $idb [list set chan $chan] set res [interp eval $idb { # wait a bit, give the main thread the time to start its event # loop to wait for the response from B after 2000 catch { puts $chan shoo } res set res }] set res } -constraints {testchannel} -result {Owner lost} test iocmd-32.2 {delete interp of reflected chan} { # Bug 3034840 # Run this test in an interp with memory debugging to panic # on the double free interp create slave slave eval { |
︙ | ︙ | |||
2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 | LOG MAIN_WAITING vwait forever LOG MAIN_DONE set res } -cleanup { rename LOG {} rename POST {} rename HANDLER {} | > | | 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 | LOG MAIN_WAITING vwait forever LOG MAIN_DONE set res } -cleanup { after cancel $::timer rename LOG {} rename POST {} rename HANDLER {} unset beat drive data forever res tid ch timer } -match glob \ -result {{initialize rc* read} {watch rc* read} {read rc* 4096} {watch rc* {}} {watch rc* read} {read rc* 4096} {watch rc* {}} {finalize rc*}} # --- === *** ########################### # method cgetall test iocmd.tf-25.1 {chan configure, cgetall, standard options} -match glob -body { |
︙ | ︙ |
Changes to tests/ioTrans.test.
︙ | ︙ | |||
535 536 537 538 539 540 541 | set c [chan push [set c [tempchan]] [list foo $c]] lappend res [read $c] #lappend res [gets $c] } -cleanup { tempdone rename foo {} } -result {{read rt* {test data | | | | > > > > > > > > > > > > > > > > > > > > | | 535 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 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 | set c [chan push [set c [tempchan]] [list foo $c]] lappend res [read $c] #lappend res [gets $c] } -cleanup { tempdone rename foo {} } -result {{read rt* {test data }} {}} test iortrans-4.8.1 {chan read, bug 721ec69271} -setup { set res {} } -match glob -body { proc foo {fd args} { handle.initialize handle.finalize lappend ::res $args # Kill and recreate transform while it is operating chan pop $fd chan push $fd [list foo $fd] } set c [chan push [set c [tempchan]] [list foo $c]] chan configure $c -buffersize 2 lappend res [read $c] } -cleanup { tempdone rename foo {} } -result {{read rt* te} {read rt* st} {read rt* { d}} {read rt* at} {read rt* {a }} {}} test iortrans-4.8.2 {chan read, bug 721ec69271} -setup { set res {} } -match glob -body { proc foo {fd args} { handle.initialize handle.finalize lappend ::res $args # Kill and recreate transform while it is operating chan pop $fd chan push $fd [list foo $fd] return x } set c [chan push [set c [tempchan]] [list foo $c]] chan configure $c -buffersize 1 lappend res [read $c] } -cleanup { tempdone rename foo {} } -result {{read rt* t} {read rt* e} {read rt* s} {read rt* t} {read rt* { }} {read rt* d} {read rt* a} {read rt* t} {read rt* a} {read rt* { }} {}} test iortrans-4.9 {chan read, gets, bug 2921116} -setup { set res {} } -match glob -body { proc foo {fd args} { handle.initialize handle.finalize lappend ::res $args # Kill and recreate transform while it is operating chan pop $fd chan push $fd [list foo $fd] } set c [chan push [set c [tempchan]] [list foo $c]] lappend res [gets $c] } -cleanup { tempdone rename foo {} } -result {{read rt* {test data }} {}} # --- === *** ########################### # method write (via puts) test iortrans-5.1 {chan write, regular write} -setup { set res {} } -match glob -body { |
︙ | ︙ |
Changes to tests/iogt.test.
︙ | ︙ | |||
224 225 226 227 228 229 230 | switch -- $op { create/write - create/read - delete/write - delete/read - clear_read {;#ignore} flush/write - | | | > > > > > > > > > > | 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 | switch -- $op { create/write - create/read - delete/write - delete/read - clear_read {;#ignore} flush/write - flush/read {} write { global level if {$level} { return } incr level testchannel unstack $chan testchannel transform $chan \ -command [namespace code [list id_torture $chan]] return $data } read { testchannel unstack $chan testchannel transform $chan \ -command [namespace code [list id_torture $chan]] return $data } query/maxRead {return -1} |
︙ | ︙ | |||
575 576 577 578 579 580 581 582 583 584 585 586 587 588 | set fh [open $path(dummy) r] torture -attach $fh chan configure $fh -buffersize 2 set x [read $fh] testchannel unstack $fh close $fh set x } {} test iogt-3.0 {Tcl_Channel valid after stack/unstack, fevent handling} -setup { proc DoneCopy {n {err {}}} { variable copy 1 } } -constraints {testchannel hangs} -body { | > > > > > > > > > | 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 | set fh [open $path(dummy) r] torture -attach $fh chan configure $fh -buffersize 2 set x [read $fh] testchannel unstack $fh close $fh set x } {} test iogt-2.5 {basic I/O, mixed trail} {testchannel} { set ::level 0 set fh [open $path(dummyout) w] torture -attach $fh puts -nonewline $fh abcdef flush $fh testchannel unstack $fh close $fh } {} test iogt-3.0 {Tcl_Channel valid after stack/unstack, fevent handling} -setup { proc DoneCopy {n {err {}}} { variable copy 1 } } -constraints {testchannel hangs} -body { |
︙ | ︙ |
Changes to tests/winFCmd.test.
︙ | ︙ | |||
1381 1382 1383 1384 1385 1386 1387 | test winFCmd-19.5 {Windows extended path names} -constraints nt -setup { set tmpfile [file join $::env(TEMP) tcl[string repeat x 248].tmp] set tmpfile [file normalize $tmpfile] } -body { list [catch { set f [open $tmpfile [list WRONLY CREAT]] close $f | | | | 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 | test winFCmd-19.5 {Windows extended path names} -constraints nt -setup { set tmpfile [file join $::env(TEMP) tcl[string repeat x 248].tmp] set tmpfile [file normalize $tmpfile] } -body { list [catch { set f [open $tmpfile [list WRONLY CREAT]] close $f } res] $res } -cleanup { catch {file delete $tmpfile} } -result [list 0 {}] test winFCmd-19.6 {Windows extended path names} -constraints nt -setup { set tmpfile [file join $::env(TEMP) tcl[string repeat x 248].tmp] set tmpfile //?/[file normalize $tmpfile] } -body { list [catch { set f [open $tmpfile [list WRONLY CREAT]] close $f |
︙ | ︙ |
Changes to unix/configure.
︙ | ︙ | |||
7075 7076 7077 7078 7079 7080 7081 | if test "x${TCL_THREADS}" = "x0"; then { { echo "$as_me:$LINENO: error: CYGWIN compile is only supported with --enable-threads" >&5 echo "$as_me: error: CYGWIN compile is only supported with --enable-threads" >&2;} { (exit 1); exit 1; }; } fi do64bit_ok=yes if test "x${SHARED_BUILD}" = "x1"; then | | | | 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 | if test "x${TCL_THREADS}" = "x0"; then { { echo "$as_me:$LINENO: error: CYGWIN compile is only supported with --enable-threads" >&5 echo "$as_me: error: CYGWIN compile is only supported with --enable-threads" >&2;} { (exit 1); exit 1; }; } fi do64bit_ok=yes if test "x${SHARED_BUILD}" = "x1"; then echo "running cd ${TCL_SRC_DIR}/win; ${CONFIG_SHELL-/bin/sh} ./configure $ac_configure_args" # The eval makes quoting arguments work. if cd ${TCL_SRC_DIR}/win; eval ${CONFIG_SHELL-/bin/sh} ./configure $ac_configure_args; cd ../unix then : else { echo "configure: error: configure failed for ../win" 1>&2; exit 1; } fi fi ;; dgux*) |
︙ | ︙ |
Changes to unix/tcl.m4.
︙ | ︙ | |||
1233 1234 1235 1236 1237 1238 1239 | AC_MSG_ERROR([${CC} is not a cygwin compiler.]) fi if test "x${TCL_THREADS}" = "x0"; then AC_MSG_ERROR([CYGWIN compile is only supported with --enable-threads]) fi do64bit_ok=yes if test "x${SHARED_BUILD}" = "x1"; then | | | | 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 | AC_MSG_ERROR([${CC} is not a cygwin compiler.]) fi if test "x${TCL_THREADS}" = "x0"; then AC_MSG_ERROR([CYGWIN compile is only supported with --enable-threads]) fi do64bit_ok=yes if test "x${SHARED_BUILD}" = "x1"; then echo "running cd ${TCL_SRC_DIR}/win; ${CONFIG_SHELL-/bin/sh} ./configure $ac_configure_args" # The eval makes quoting arguments work. if cd ${TCL_SRC_DIR}/win; eval ${CONFIG_SHELL-/bin/sh} ./configure $ac_configure_args; cd ../unix then : else { echo "configure: error: configure failed for ../win" 1>&2; exit 1; } fi fi ;; dgux*) |
︙ | ︙ |
Changes to win/tclWinFile.c.
︙ | ︙ | |||
2893 2894 2895 2896 2897 2898 2899 | *--------------------------------------------------------------------------- */ ClientData TclNativeCreateNativeRep( Tcl_Obj *pathPtr) { | | | | | 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 | *--------------------------------------------------------------------------- */ ClientData TclNativeCreateNativeRep( Tcl_Obj *pathPtr) { WCHAR *nativePathPtr; const char *str; Tcl_Obj *validPathPtr; int len; WCHAR *wp; if (TclFSCwdIsNative()) { /* * The cwd is native, which means we can use the translated path * without worrying about normalization (this will also usually be * shorter so the utf-to-external conversion will be somewhat faster). |
︙ | ︙ | |||
2923 2924 2925 2926 2927 2928 2929 | if (validPathPtr == NULL) { return NULL; } Tcl_IncrRefCount(validPathPtr); } str = Tcl_GetStringFromObj(validPathPtr, &len); | | | | < < | > > | > > > > > > | < | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > < < < < < | 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 | if (validPathPtr == NULL) { return NULL; } Tcl_IncrRefCount(validPathPtr); } str = Tcl_GetStringFromObj(validPathPtr, &len); if (strlen(str)!=len) { /* String contains NUL-bytes. This is invalid. */ return 0; } /* Let MultiByteToWideChar check for other invalid sequences, like * 0xC0 0x80 (== overlong NUL). See bug [3118489]: NUL in filenames */ len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, -1, 0, 0); if (len==0) { return 0; } /* Overallocate 6 chars, making some room for extended paths */ wp = nativePathPtr = ckalloc( (len+6) * sizeof(WCHAR) ); if (nativePathPtr==0) { return 0; } MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, -1, nativePathPtr, len); /* ** If path starts with "//?/" or "\\?\" (extended path), translate ** any slashes to backslashes but leave the '?' intact */ if ((str[0]=='\\' || str[0]=='/') && (str[1]=='\\' || str[1]=='/') && str[2]=='?' && (str[3]=='\\' || str[3]=='/')) { wp[0] = wp[1] = wp[3] = '\\'; str += 4; wp += 4; } /* ** If there is no "\\?\" prefix but there is a drive or UNC ** path prefix and the path is larger than MAX_PATH chars, ** no Win32 API function can handle that unless it is ** prefixed with the extended path prefix. See: ** <http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath> **/ if (((str[0]>='A'&&str[0]<='Z') || (str[0]>='a'&&str[0]<='z')) && str[1]==':' && (str[2]=='\\' || str[2]=='/')) { if (wp==nativePathPtr && len>MAX_PATH) { memmove(wp+4, wp, len*sizeof(WCHAR)); memcpy(wp, L"\\\\?\\", 4*sizeof(WCHAR)); wp += 4; } /* ** If (remainder of) path starts with "<drive>:/" or "<drive>:\", ** leave the ':' intact but translate the backslash to a slash. */ wp[2] = '\\'; wp += 3; } else if (wp==nativePathPtr && len>MAX_PATH && (str[0]=='\\' || str[0]=='/') && (str[1]=='\\' || str[1]=='/') && str[2]!='?') { memmove(wp+6, wp, len*sizeof(WCHAR)); memcpy(wp, L"\\\\?\\UNC", 7*sizeof(WCHAR)); wp += 7; } /* ** In the remainder of the path, translate invalid characters to ** characters in the Unicode private use area. */ while (*wp != '\0') { if ((*wp < ' ') || wcschr(L"\"*:<>?|", *wp)) { *wp |= 0xF000; } else if (*wp == '/') { *wp = '\\'; } ++wp; } return nativePathPtr; } /* *--------------------------------------------------------------------------- * * TclNativeDupInternalRep -- |
︙ | ︙ |