Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Merge 9.0 |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | bug-7c2716733a |
Files: | files | file ages | folders |
SHA3-256: |
120749f8c4ff2d79aa9c58b070eca71e |
User & Date: | apnadkarni 2025-06-25 03:29:27.806 |
Context
2025-06-25
| ||
16:23 | Fix [7c2716733a] - use after free on Windows pipe handles check-in: a9351d85f3 user: apnadkarni tags: core-9-0-branch | |
03:29 | Merge 9.0 Closed-Leaf check-in: 120749f8c4 user: apnadkarni tags: bug-7c2716733a | |
2025-06-24
| ||
16:23 | [ecf35c7120] Correct nested handling of return option -options check-in: a9446eea4d user: dgp tags: core-9-0-branch | |
2025-06-15
| ||
10:15 | Fat fingers in constraints check-in: c1f1232e47 user: apnadkarni tags: bug-7c2716733a | |
Changes
Changes to README.md.
︙ | ︙ | |||
27 28 29 30 31 32 33 | 9. [Tracking Development](#watch) 10. [Thank You](#thanks) ## <a id="intro">1.</a> Introduction Tcl provides a powerful platform for creating integration applications that tie together diverse applications, protocols, devices, and frameworks. When paired with the Tk toolkit, Tcl provides the fastest and most powerful | | | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 9. [Tracking Development](#watch) 10. [Thank You](#thanks) ## <a id="intro">1.</a> Introduction Tcl provides a powerful platform for creating integration applications that tie together diverse applications, protocols, devices, and frameworks. When paired with the Tk toolkit, Tcl provides the fastest and most powerful way to create GUI applications that run on PCs, Unix, and macOS. Tcl can also be used for a variety of web-related tasks and for creating powerful command languages for applications. Tcl is maintained, enhanced, and distributed freely by the Tcl community. Source code development and tracking of bug reports and feature requests take place at [core.tcl-lang.org](https://core.tcl-lang.org/). Tcl/Tk release and mailing list services are [hosted by |
︙ | ︙ |
Changes to doc/OpenFileChnl.3.
1 2 3 4 5 6 7 8 9 10 11 | '\" '\" Copyright (c) 1996-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. '\" .TH Tcl_OpenFileChannel 3 8.3 Tcl "Tcl Library Procedures" .so man.macros .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | '\" '\" Copyright (c) 1996-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. '\" .TH Tcl_OpenFileChannel 3 8.3 Tcl "Tcl Library Procedures" .so man.macros .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME Tcl_OpenFileChannel, Tcl_OpenCommandChannel, Tcl_MakeFileChannel, Tcl_GetChannel, Tcl_GetChannelNames, Tcl_GetChannelNamesEx, Tcl_RegisterChannel, Tcl_UnregisterChannel, Tcl_DetachChannel, Tcl_IsStandardChannel, Tcl_Close, Tcl_CloseEx, Tcl_ReadChars, Tcl_Read, Tcl_GetsObj, Tcl_Gets, Tcl_WriteObj, Tcl_WriteChars, Tcl_Write, Tcl_Flush, Tcl_Seek, Tcl_Tell, Tcl_TruncateChannel, Tcl_GetChannelOption, Tcl_SetChannelOption, Tcl_Eof, Tcl_InputBlocked, Tcl_InputBuffered, Tcl_OutputBuffered, Tcl_Ungets, Tcl_ReadRaw, Tcl_WriteRaw \- buffered I/O facilities using channels .SH SYNOPSIS .nf \fB#include <tcl.h>\fR .sp Tcl_Channel \fBTcl_OpenFileChannel\fR(\fIinterp, fileName, mode, permissions\fR) .sp |
︙ | ︙ | |||
42 43 44 45 46 47 48 49 50 51 52 53 54 55 | .sp int \fBTcl_IsStandardChannel\fR(\fIchannel\fR) .sp int \fBTcl_Close\fR(\fIinterp, channel\fR) .sp Tcl_Size \fBTcl_ReadChars\fR(\fIchannel, readObjPtr, charsToRead, appendFlag\fR) .sp Tcl_Size \fBTcl_Read\fR(\fIchannel, readBuf, bytesToRead\fR) .sp Tcl_Size | > > > | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | .sp int \fBTcl_IsStandardChannel\fR(\fIchannel\fR) .sp int \fBTcl_Close\fR(\fIinterp, channel\fR) .sp int \fBTcl_CloseEx\fR(\fIinterp, channel, closeFlags\fR) .sp Tcl_Size \fBTcl_ReadChars\fR(\fIchannel, readObjPtr, charsToRead, appendFlag\fR) .sp Tcl_Size \fBTcl_Read\fR(\fIchannel, readBuf, bytesToRead\fR) .sp Tcl_Size |
︙ | ︙ | |||
153 154 155 156 157 158 159 160 161 162 163 164 165 166 | .AP Tcl_Obj *readObjPtr in/out A pointer to a Tcl value in which to store the characters read from the channel. .AP Tcl_Size charsToRead in The number of characters to read from the channel. If the channel's encoding is \fBbinary\fR, this is equivalent to the number of bytes to read from the channel. .AP int appendFlag in If non-zero, data read from the channel will be appended to the value. Otherwise, the data will replace the existing contents of the value. .AP char *readBuf out A buffer in which to store the bytes read from the channel. .AP Tcl_Size bytesToRead in The number of bytes to read from the channel. The buffer \fIreadBuf\fR must | > > > > | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | .AP Tcl_Obj *readObjPtr in/out A pointer to a Tcl value in which to store the characters read from the channel. .AP Tcl_Size charsToRead in The number of characters to read from the channel. If the channel's encoding is \fBbinary\fR, this is equivalent to the number of bytes to read from the channel. .AP int closeFlags in If \fB0\fR, the channel is closed in both directions. If \fBTCL_CLOSE_READ\fR, the channel is only closed for reading. If \fBTCL_CLOSE_WRITE\fR, the channel is only closed for writing. These flags must not be combined. .AP int appendFlag in If non-zero, data read from the channel will be appended to the value. Otherwise, the data will replace the existing contents of the value. .AP char *readBuf out A buffer in which to store the bytes read from the channel. .AP Tcl_Size bytesToRead in The number of bytes to read from the channel. The buffer \fIreadBuf\fR must |
︙ | ︙ | |||
365 366 367 368 369 370 371 | .PP \fBTcl_IsStandardChannel\fR tests whether a channel is one of the three standard channels, \fBstdin\fR, \fBstdout\fR or \fBstderr\fR. If so, it returns 1, otherwise 0. .PP No attempt is made to check whether the given channel or the standard channels are initialized or otherwise valid. | | > > > > > > > | | | | | | | 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 | .PP \fBTcl_IsStandardChannel\fR tests whether a channel is one of the three standard channels, \fBstdin\fR, \fBstdout\fR or \fBstderr\fR. If so, it returns 1, otherwise 0. .PP No attempt is made to check whether the given channel or the standard channels are initialized or otherwise valid. .SH "TCL_CLOSE AND TCL_CLOSEEX" .PP \fBTcl_Close\fR destroys the channel \fIchannel\fR, which must denote a currently open channel. The channel should not be registered in any interpreter when \fBTcl_Close\fR is called. Buffered output is flushed to the channel's output device prior to destroying the channel, and any buffered input is discarded. If this is a blocking channel, the call does not return until all buffered data is successfully sent to the channel's output device. If this is a nonblocking channel and there is buffered output that cannot be written without blocking, the call returns immediately; output is flushed in the background and the channel will be closed once all of the buffered data has been output. In this case errors during flushing are not reported. .PP \fBTcl_CloseEx\fR allows for both full closing and half-closing of channels depending on its \fBcloseFlags\fR parameter. See the description of the parameter above. It is an error to attempt to close the channel for a direction for which it is not open. The channel is destroyed only when it has been closed for both reading and writing. Only socket and command pipe channels support half-closing. .PP If the channel was closed successfully, \fBTcl_Close\fR and \fBTcl_CloseEx\fR return \fBTCL_OK\fR. If an error occurs, they return \fBTCL_ERROR\fR and record a POSIX error code that can be retrieved with \fBTcl_GetErrno\fR. If the channel is being closed synchronously and an error occurs during closing of the channel and \fIinterp\fR is not NULL, an error message is left in the interpreter's result. .PP Note that it is not safe to call the channel closing functions on a channel that has been registered using \fBTcl_RegisterChannel\fR; see the documentation for \fBTcl_RegisterChannel\fR, above, for details. If the channel has ever been given as the \fBchan\fR argument in a call to \fBTcl_RegisterChannel\fR, you should instead use \fBTcl_UnregisterChannel\fR, which will internally call \fBTcl_Close\fR when all calls to \fBTcl_RegisterChannel\fR have been matched by corresponding calls to \fBTcl_UnregisterChannel\fR. .SH "TCL_READCHARS AND TCL_READ" .PP |
︙ | ︙ |
Changes to generic/tclCmdAH.c.
︙ | ︙ | |||
547 548 549 550 551 552 553 554 555 556 557 558 559 | if (bytesPtr == NULL) { return TCL_ERROR; } result = Tcl_ExternalToUtfDStringEx(interp, encoding, bytesPtr, length, flags, &ds, failVarObj ? &errorLocation : NULL); /* NOTE: ds must be freed beyond this point even on error */ switch (result) { case TCL_OK: errorLocation = TCL_INDEX_NONE; break; case TCL_ERROR: /* Error in parameters. Should not happen. interp will have error */ | > | < < | > < | > > | | > | < | > | 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 607 608 609 | if (bytesPtr == NULL) { return TCL_ERROR; } result = Tcl_ExternalToUtfDStringEx(interp, encoding, bytesPtr, length, flags, &ds, failVarObj ? &errorLocation : NULL); /* NOTE: ds must be freed beyond this point even on error */ switch (result) { case TCL_OK: errorLocation = TCL_INDEX_NONE; break; case TCL_ERROR: /* Error in parameters. Should not happen. interp will have error */ goto done; default: /* * One of the TCL_CONVERT_* errors. If we were not interested in the * error location, interp result would already have been filled in * and we can just return the error. Otherwise, we have to return * what could be decoded and the returned error location. */ if (failVarObj == NULL) { result = TCL_ERROR; goto done; } break; } /* * TCL_OK or a TCL_CONVERT_* error where the caller wants back as much * data as was converted. */ if (failVarObj) { Tcl_Obj *failIndex; TclNewIndexObj(failIndex, errorLocation); if (Tcl_ObjSetVar2(interp, failVarObj, NULL, failIndex, TCL_LEAVE_ERR_MSG) == NULL) { result = TCL_ERROR; goto done; } } /* * Note that we cannot use Tcl_DStringResult here because it will * truncate the string at the first null byte. */ Tcl_SetObjResult(interp, Tcl_DStringToObj(&ds)); result = TCL_OK; done: Tcl_DStringFree(&ds); if (encoding) { Tcl_FreeEncoding(encoding); } return result; } /* *---------------------------------------------------------------------- * * EncodingConverttoObjCmd -- * |
︙ | ︙ | |||
647 648 649 650 651 652 653 | switch (result) { case TCL_OK: errorLocation = TCL_INDEX_NONE; break; case TCL_ERROR: /* Error in parameters. Should not happen. interp will have error */ | | < < | > < | > < < > > > > | > | | 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 | switch (result) { case TCL_OK: errorLocation = TCL_INDEX_NONE; break; case TCL_ERROR: /* Error in parameters. Should not happen. interp will have error */ goto done; default: /* * One of the TCL_CONVERT_* errors. If we were not interested in the * error location, interp result would already have been filled in * and we can just return the error. Otherwise, we have to return * what could be decoded and the returned error location. */ if (failVarObj == NULL) { result = TCL_ERROR; goto done; } break; } /* * TCL_OK or a TCL_CONVERT_* error where the caller wants back as much * data as was converted. */ if (failVarObj) { Tcl_Obj *failIndex; TclNewIndexObj(failIndex, errorLocation); if (Tcl_ObjSetVar2(interp, failVarObj, NULL, failIndex, TCL_LEAVE_ERR_MSG) == NULL) { result = TCL_ERROR; goto done; } } Tcl_SetObjResult(interp, Tcl_NewByteArrayObj( (unsigned char*) Tcl_DStringValue(&ds), Tcl_DStringLength(&ds))); result = TCL_OK; done: Tcl_DStringFree(&ds); if (encoding) { Tcl_FreeEncoding(encoding); } return result; } /* *---------------------------------------------------------------------- * * EncodingDirsObjCmd -- |
︙ | ︙ |
Changes to generic/tclIOCmd.c.
︙ | ︙ | |||
944 945 946 947 948 949 950 | ignoreStderr = 1; break; case EXEC_ENCODING: if (++skip >= objc) { Tcl_SetResult(interp, "No value given for option -encoding.", TCL_STATIC); return TCL_ERROR; | > > > > > > > | | > | 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 | ignoreStderr = 1; break; case EXEC_ENCODING: if (++skip >= objc) { Tcl_SetResult(interp, "No value given for option -encoding.", TCL_STATIC); return TCL_ERROR; } else { Tcl_Encoding encoding; encodingObj = objv[skip]; /* Verify validity - bug [da5e1bc7bc] */ if (Tcl_GetEncodingFromObj(interp, encodingObj, &encoding) != TCL_OK) { return TCL_ERROR; } Tcl_FreeEncoding(encoding); } break; } } if (objc <= skip) { Tcl_WrongNumArgs(interp, 1, objv, "?-option ...? arg ?arg ...?"); return TCL_ERROR; } |
︙ | ︙ | |||
1010 1011 1012 1013 1014 1015 1016 | return TCL_ERROR; } return TCL_OK; } /* Bug [0f1ddc0df7] - encoding errors - use replace profile */ if (Tcl_SetChannelOption(interp, chan, "-profile", "replace") != TCL_OK) { | | | | | | < < | | 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 | return TCL_ERROR; } return TCL_OK; } /* Bug [0f1ddc0df7] - encoding errors - use replace profile */ if (Tcl_SetChannelOption(interp, chan, "-profile", "replace") != TCL_OK) { goto errorWithOpenChannel; } /* TIP 716 */ if (encodingObj && Tcl_SetChannelOption(interp, chan, "-encoding", Tcl_GetString(encodingObj)) != TCL_OK) { goto errorWithOpenChannel; } TclNewObj(resultPtr); if (Tcl_GetChannelHandle(chan, TCL_READABLE, NULL) == TCL_OK) { if (Tcl_ReadChars(chan, resultPtr, -1, 0) == TCL_IO_FAILURE) { /* * TIP #219. * Capture error messages put by the driver into the bypass area * and put them into the regular interpreter result. Fall back to * the regular message if nothing was found in the bypass. */ if (!TclChanCaughtErrorBypass(interp, chan)) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "error reading output from command: %s", Tcl_PosixError(interp))); Tcl_DecrRefCount(resultPtr); } goto errorWithOpenChannel; } } /* * If the process produced anything on stderr, it will have been returned * in the interpreter result. It needs to be appended to the result * string. |
︙ | ︙ | |||
1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 | if ((length > 0) && (string[length - 1] == '\n')) { Tcl_SetObjLength(resultPtr, length - 1); } } Tcl_SetObjResult(interp, resultPtr); return result; } /* *--------------------------------------------------------------------------- * * Tcl_FblockedObjCmd -- * | > > > > > | 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 | if ((length > 0) && (string[length - 1] == '\n')) { Tcl_SetObjLength(resultPtr, length - 1); } } Tcl_SetObjResult(interp, resultPtr); return result; errorWithOpenChannel: /* Interpreter should already contain error. Pass NULL to not overwrite */ (void)Tcl_CloseEx(NULL, chan, 0); return TCL_ERROR; } /* *--------------------------------------------------------------------------- * * Tcl_FblockedObjCmd -- * |
︙ | ︙ |
Changes to generic/tclResult.c.
︙ | ︙ | |||
789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 | /* *---------------------------------------------------------------------- * * TclMergeReturnOptions -- * * Parses, checks, and stores the options to the [return] command. * * Results: * Returns TCL_ERROR if any of the option values are invalid. Otherwise, * returns TCL_OK, and writes the returnOpts, code, and level values to * the pointers provided. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TclMergeReturnOptions( Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[], /* Argument objects. */ Tcl_Obj **optionsPtrPtr, /* If not NULL, points to space for a (Tcl_Obj * *) where the pointer to the merged return * options dictionary should be written. */ int *codePtr, /* If not NULL, points to space where the * -code value should be written. */ int *levelPtr) /* If not NULL, points to space where the * -level value should be written. */ { int code = TCL_OK; int level = 1; Tcl_Obj *valuePtr; Tcl_Obj *returnOpts; Tcl_Obj **keys = GetKeys(); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < | < < < < < < | < < < < < | < < < < < | < < < < < < < < < < < < < < < < < | 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 | /* *---------------------------------------------------------------------- * * TclMergeReturnOptions -- * * Parses, checks, and stores the options to the [return] command. * * The number of arguments (objc) must be even, with the corresponding * objv holding values to be processed as key value .... key value. * * Results: * Returns TCL_ERROR if any of the option values are invalid. Otherwise, * returns TCL_OK, and writes the returnOpts, code, and level values to * the pointers provided. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ExpandedOptions( Tcl_Interp *interp, /* Current interpreter. */ Tcl_Obj **keys, /* Built-in keys (per thread) */ Tcl_Obj *returnOpts, /* Options dict we are building */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { for (; objc > 1; objv += 2, objc -= 2) { const char *opt = TclGetString(objv[0]); const char *compare = TclGetString(keys[KEY_OPTIONS]); if ((objv[0]->length == keys[KEY_OPTIONS]->length) && (memcmp(opt, compare, objv[0]->length) == 0)) { /* Process the -options switch to emulate {*} expansion. * * Use lists so duplicate keys are not lost. */ Tcl_Size nestc; Tcl_Obj **nestv; if (TCL_ERROR == TclListObjGetElements(interp, objv[1], &nestc, &nestv) || (nestc % 2)) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "bad -options value: expected dictionary but got" " \"%s\"", TclGetString(objv[1]))); Tcl_SetErrorCode(interp, "TCL", "RESULT", "ILLEGAL_OPTIONS", (char *)NULL); return TCL_ERROR; } if (TCL_ERROR == ExpandedOptions(interp, keys, returnOpts, nestc, nestv)) { return TCL_ERROR; } } else { Tcl_DictObjPut(NULL, returnOpts, objv[0], objv[1]); } } return TCL_OK; } int TclMergeReturnOptions( Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[], /* Argument objects. */ Tcl_Obj **optionsPtrPtr, /* If not NULL, points to space for a (Tcl_Obj * *) where the pointer to the merged return * options dictionary should be written. */ int *codePtr, /* If not NULL, points to space where the * -code value should be written. */ int *levelPtr) /* If not NULL, points to space where the * -level value should be written. */ { int code = TCL_OK; int level = 1; Tcl_Obj *valuePtr; Tcl_Obj *returnOpts; Tcl_Obj **keys = GetKeys(); /* All callers are expected to pass an even value for objc. */ TclNewObj(returnOpts); if (TCL_ERROR == ExpandedOptions(interp, keys, returnOpts, objc, objv)) { goto error; } /* * Check for bogus -code value. */ Tcl_DictObjGet(NULL, returnOpts, keys[KEY_CODE], &valuePtr); |
︙ | ︙ |
Changes to macosx/README.
|
| | | | 1 2 3 4 5 6 7 8 9 10 11 | Tcl macOS README ------------------- This is the README file for the macOS/Darwin version of Tcl. 1. Where to go for support -------------------------- - The tcl-mac mailing list on sourceforge is the best place to ask questions specific to Tcl & Tk on Mac OS X: |
︙ | ︙ | |||
59 60 61 62 63 64 65 | framework directories: $HOME/Library/Frameworks /Library/Frameworks 3. Building Tcl on Mac OS X --------------------------- | | | > | | | | | | | | | < | | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | framework directories: $HOME/Library/Frameworks /Library/Frameworks 3. Building Tcl on Mac OS X --------------------------- - Tcl supports macOS 10.13 and newer. While Tcl may build on earlier versions of the OS, it is not tested on versions older than 10.13. You will need to install an Apple clang toolchain either by downloading the Xcode app from Apple's App Store, or by installing the Command Line Tools. The Command Line Tools can be installed by running the command: xcode-select --install in the Terminal. - Tcl is most easily built as a macOS framework via the GNUmakefile in tcl/macosx (see below for details), but can also be built with the standard unix configure and make buildsystem in tcl/unix as on any other unix platform (indeed, the GNUmakefile is just a wrapper around the unix buildsystem). The Mac OS X specific configure flags are --enable-framework and --disable-corefoundation (which disables CF and notably reverts to the standard select based notifier). - To build universal binaries for macOS 10.13 and newer set CFLAGS as follows: export CFLAGS="-arch x86_64 -arch arm64 -mmacosx-version-min=10.13" (This will cause clang to set macOS 11 as the target OS for the arm64 architecture since Apple Silicon was not supported until macOS 11.) Universal builds of Tcl TEA extensions are also possible with CFLAGS set as above, they will be [load]able by universal as well as thin binaries of Tcl. Detailed Instructions for building with macosx/GNUmakefile ---------------------------------------------------------- - Unpack the Tcl source release archive. - The following instructions assume the Tcl source tree is named "tcl${ver}", (where ${ver} is a shell variable containing the Tcl version number e.g. '9.0'). Setup this shell variable as follows: ver="9.0" - Setup environment variables as desired, for example: CFLAGS="-arch x86_64 -arch arm64 -mmacosx-version-min=10.13" export CFLAGS - Change to the directory containing the Tcl source tree and build: make -C tcl${ver}/macosx - Install Tcl onto the root volume (admin password required): sudo make -C tcl${ver}/macosx install |
︙ | ︙ |
Changes to tests/cmdMZ.test.
︙ | ︙ | |||
193 194 195 196 197 198 199 200 201 202 203 204 205 206 | } result] $result $::errorCode } {1 c {a b}} test cmdMZ-return-2.18 {return option handling} { list [catch { return -code error -errorstack [list CALL a CALL b] yo } -> foo] [dictSort $foo] [info errorstack] } {2 {-code 1 -errorcode NONE -errorstack {CALL a CALL b} -level 1} {CALL a CALL b}} # Check that the result of a [return -options $opts $result] is # indistinguishable from that of the originally caught script, no matter what # the script is/does. (TIP 90) foreach {testid script} { cmdMZ-return-3.0 {} cmdMZ-return-3.1 {format x} | > > > > > > > > > > > > > | 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 | } result] $result $::errorCode } {1 c {a b}} test cmdMZ-return-2.18 {return option handling} { list [catch { return -code error -errorstack [list CALL a CALL b] yo } -> foo] [dictSort $foo] [info errorstack] } {2 {-code 1 -errorcode NONE -errorstack {CALL a CALL b} -level 1} {CALL a CALL b}} test cmdMZ-return-2.19 {return option handling} -body { return -level 0 -options {-options {-code break} -code continue} } -returnCodes continue -result {} test cmdMZ-return-2.20 {return option handling} { list [catch { return -level 0 -options {-foo 1} -options {-bar 2} } -> foo] $foo } {0 {-foo 1 -bar 2 -code 0 -level 0}} test cmdMZ-return-2.21 {return option handling} { list [catch { return -level 0 -options {-options {-foo 1} -options {-bar 2}} } -> foo] $foo } {0 {-foo 1 -bar 2 -code 0 -level 0}} # Check that the result of a [return -options $opts $result] is # indistinguishable from that of the originally caught script, no matter what # the script is/does. (TIP 90) foreach {testid script} { cmdMZ-return-3.0 {} cmdMZ-return-3.1 {format x} |
︙ | ︙ |
Changes to tests/exec.test.
︙ | ︙ | |||
28 29 30 31 32 33 34 35 36 37 38 39 40 41 | # no idea how to check it in GHA programmatically, so simply disable it (todo: rewrite with better check later) if {[testConstraint win] && ![info exists ::env(CI)] && [info exists ::env(LOCALAPPDATA)] && [file exists [file join $::env(LOCALAPPDATA) "Microsoft" "WindowsApps" "winget.exe"]]} { testConstraint haveWinget 1 } unset -nocomplain path # Utilities that are like Bourne shell stalwarts, but cross-platform. set path(echo) [makeFile { puts -nonewline [lindex $argv 0] foreach str [lrange $argv 1 end] { puts -nonewline " $str" | > > | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | # no idea how to check it in GHA programmatically, so simply disable it (todo: rewrite with better check later) if {[testConstraint win] && ![info exists ::env(CI)] && [info exists ::env(LOCALAPPDATA)] && [file exists [file join $::env(LOCALAPPDATA) "Microsoft" "WindowsApps" "winget.exe"]]} { testConstraint haveWinget 1 } testConstraint testhandlecount [expr {[llength [info commands testhandlecount]] != 0}] unset -nocomplain path # Utilities that are like Bourne shell stalwarts, but cross-platform. set path(echo) [makeFile { puts -nonewline [lindex $argv 0] foreach str [lrange $argv 1 end] { puts -nonewline " $str" |
︙ | ︙ | |||
150 151 152 153 154 155 156 157 158 159 160 161 162 163 | } {3 1 4} set arg {12345678901234567890123456789012345678901234567890} set arg "$arg$arg$arg$arg$arg$arg" test exec-1.4 {long command lines} {exec} { exec [interpreter] $path(echo) $arg } $arg set arg {} # I/O redirection: input from Tcl command. test exec-2.1 {redirecting input from immediate source} {exec stdio} { exec [interpreter] $path(cat) << "Sample text" } {Sample text} test exec-2.2 {redirecting input from immediate source} {exec stdio} { | > > > > > > | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | } {3 1 4} set arg {12345678901234567890123456789012345678901234567890} set arg "$arg$arg$arg$arg$arg$arg" test exec-1.4 {long command lines} {exec} { exec [interpreter] $path(echo) $arg } $arg set arg {} test exec-1.5 {pipelining - handle leaks} -constraints {exec stdio testhandlecount} -body { set numHandles [testhandlecount] set a [exec [interpreter] $path(echo) a b c d | [interpreter] $path(cat) | [interpreter] $path(wc)] list [scan $a "%d %d %d" b c d] $b $c [expr {[testhandlecount] - $numHandles}] } -result {3 1 4 0} # I/O redirection: input from Tcl command. test exec-2.1 {redirecting input from immediate source} {exec stdio} { exec [interpreter] $path(cat) << "Sample text" } {Sample text} test exec-2.2 {redirecting input from immediate source} {exec stdio} { |
︙ | ︙ | |||
186 187 188 189 190 191 192 193 194 195 196 197 198 199 | # If it does, this means that the UTF -> external conversion did not occur # before writing out the temp file. quotenonascii [exec [interpreter] $path(cat) << "\xE9\xE0\xFC\xF1"] } -cleanup { encoding system $sysenc rename quotenonascii {} } -result {\xE9\xE0\xFC\xF1} # I/O redirection: output to file. set path(gorp.file) [makeFile {} gorp.file] file delete $path(gorp.file) test exec-3.1 {redirecting output to file} {exec} { | > > > > > > > | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | # If it does, this means that the UTF -> external conversion did not occur # before writing out the temp file. quotenonascii [exec [interpreter] $path(cat) << "\xE9\xE0\xFC\xF1"] } -cleanup { encoding system $sysenc rename quotenonascii {} } -result {\xE9\xE0\xFC\xF1} test exec-2.7 {handle count redirecting input from immediate source} -constraints { exec stdio testhandlecount } -body { set numHandles [testhandlecount] list [exec [interpreter] $path(cat) | [interpreter] $path(cat) << "Sample text"] \ [expr {[testhandlecount] - $numHandles}] } -result [list {Sample text} 0] # I/O redirection: output to file. set path(gorp.file) [makeFile {} gorp.file] file delete $path(gorp.file) test exec-3.1 {redirecting output to file} {exec} { |
︙ | ︙ | |||
228 229 230 231 232 233 234 235 236 237 238 239 240 241 | flush $f exec [interpreter] $path(echo) "More text" >@ $f exec [interpreter] $path(echo) >@$f "Even more" puts $f "Line 3" close $f exec [interpreter] $path(cat) $path(gorp.file) } "Line 1\nMore text\nEven more\nLine 3" # I/O redirection: output and stderr to file. file delete $path(gorp.file) test exec-4.1 {redirecting output and stderr to file} {exec} { exec [interpreter] $path(echo) "test output" >& $path(gorp.file) | > > > > > > > > | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | flush $f exec [interpreter] $path(echo) "More text" >@ $f exec [interpreter] $path(echo) >@$f "Even more" puts $f "Line 3" close $f exec [interpreter] $path(cat) $path(gorp.file) } "Line 1\nMore text\nEven more\nLine 3" test exec-3.8 {handle count redirecting output to file} -constraints { exec stdio testhandlecount } -body { set numHandles [testhandlecount] exec > $path(gorp.file) [interpreter] $path(echo) "Different simple words" | [interpreter] $path(cat) | [interpreter] $path(cat) list [exec [interpreter] $path(cat) $path(gorp.file)] \ [expr {[testhandlecount] - $numHandles}] } -result [list "Different simple words" 0] # I/O redirection: output and stderr to file. file delete $path(gorp.file) test exec-4.1 {redirecting output and stderr to file} {exec} { exec [interpreter] $path(echo) "test output" >& $path(gorp.file) |
︙ | ︙ | |||
299 300 301 302 303 304 305 306 307 308 309 310 311 312 | } -result {Just a few thoughts} test exec-5.7 {redirecting input from file} -constraints {exec} -body { set f [open $path(gorp.file) r] exec <@$f [interpreter] $path(cat) } -cleanup { close $f } -result {Just a few thoughts} # I/O redirection: standard error through a pipeline. test exec-6.1 {redirecting stderr through a pipeline} {exec stdio} { exec [interpreter] $path(sh) -c "\"$path(echo)\" foo bar" |& [interpreter] $path(cat) } "foo bar" test exec-6.2 {redirecting stderr through a pipeline} {exec stdio} { | > > > > > > > | 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 | } -result {Just a few thoughts} test exec-5.7 {redirecting input from file} -constraints {exec} -body { set f [open $path(gorp.file) r] exec <@$f [interpreter] $path(cat) } -cleanup { close $f } -result {Just a few thoughts} test exec-5.8 {handle count redirecting input from file} -constraints { exec stdio testhandlecount } -body { set numHandles [testhandlecount] list [exec [interpreter] $path(cat) | [interpreter] $path(cat) < $path(gorp.file)] \ [expr {[testhandlecount] - $numHandles}] } -result [list {Just a few thoughts} 0] # I/O redirection: standard error through a pipeline. test exec-6.1 {redirecting stderr through a pipeline} {exec stdio} { exec [interpreter] $path(sh) -c "\"$path(echo)\" foo bar" |& [interpreter] $path(cat) } "foo bar" test exec-6.2 {redirecting stderr through a pipeline} {exec stdio} { |
︙ | ︙ | |||
480 481 482 483 484 485 486 487 488 489 490 491 492 493 | } 3 test exec-11.5 {commands in background} {exec} { set f [open $path(gorp.file) w] puts $f [list catch [list exec [info nameofexecutable] $path(echo) foo &]] close $f exec [interpreter] $path(gorp.file) } foo # Make sure that background commands are properly reaped when they # eventually die. if {[testConstraint exec] && [testConstraint nonPortable]} { after 1300 exec [interpreter] $path(sleep) 1 | > > > > > > > > > | 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 | } 3 test exec-11.5 {commands in background} {exec} { set f [open $path(gorp.file) w] puts $f [list catch [list exec [info nameofexecutable] $path(echo) foo &]] close $f exec [interpreter] $path(gorp.file) } foo test exec-11.6 {commands in background} -constraints { exec stdio testhandlecount } -body { set numHandles [testhandlecount] set n [llength [exec [interpreter] $path(sleep) 1 | [interpreter] $path(sleep) 1 | [interpreter] $path(sleep) 1 &]] after 1100 tcl::process::purge list $n [expr {([testhandlecount] - $numHandles) <= 0}]; # Could be < 0 if prior processes were reaped } -result {3 1} # Make sure that background commands are properly reaped when they # eventually die. if {[testConstraint exec] && [testConstraint nonPortable]} { after 1300 exec [interpreter] $path(sleep) 1 |
︙ | ︙ |