diff options
author | dgp <dgp@users.sourceforge.net> | 2012-11-16 22:51:18 (GMT) |
---|---|---|
committer | dgp <dgp@users.sourceforge.net> | 2012-11-16 22:51:18 (GMT) |
commit | 809f3d7568286e5221fdc48fecf9ad9b5c5b1173 (patch) | |
tree | be5a399ed574820d42a50aa0bc73bf00f69ded73 | |
parent | 5bf41fe2eb79370375e30562f224f88cb98b33a5 (diff) | |
parent | 2bf2abcb4f1c88fbddc3ce4d5800c438851aaf95 (diff) | |
download | tcl-809f3d7568286e5221fdc48fecf9ad9b5c5b1173.zip tcl-809f3d7568286e5221fdc48fecf9ad9b5c5b1173.tar.gz tcl-809f3d7568286e5221fdc48fecf9ad9b5c5b1173.tar.bz2 |
merge trunk
289 files changed, 12518 insertions, 8155 deletions
@@ -1,3 +1,344 @@ +2012-11-15 Jan Nijtmans <nijtmans@users.sf.net> + + IMPLEMENTATION OF TIP#416 + + New Options for 'load': -global and -lazy + + * generic/tcl.h: + * generic/tclLoad.c + * unix/tclLoadDl.c + * unix/tclLoadDyld.c + * tests/load.test + * doc/Load.3 + * doc/load.n + +2012-11-14 Donal K. Fellows <dkf@users.sf.net> + + * unix/tclUnixFCmd.c (TclUnixOpenTemporaryFile): [Bug 2933003]: Factor + out all the code to do temporary file creation so that it is possible + to make it correct in one place. Allow overriding of the back-stop + default temporary file location at compile time by setting the + TCL_TEMPORARY_FILE_DIRECTORY #def to a string containing the directory + name (defaults to "/tmp" as that is the most common default). + +2012-11-13 Joe Mistachkin <joe@mistachkin.com> + + * win/tclWinInit.c: also search for the library directory (init.tcl, + encodings, etc) relative to the build directory associated with the + source checkout. + +2012-11-10 Miguel Sofer <msofer@users.sf.net> + + * generic/tclBasic.c: re-enable bcc-tailcall, after fixing an + * generic/tclExecute.c: infinite loop in the TCL_COMPILE_DEBUG mode + + +2012-11-07 Kevin B. Kenny <kennykb@acm.org> + + * library/tzdata/Africa/Casablanca: + * library/tzdata/America/Araguaina: + * library/tzdata/America/Bahia: + * library/tzdata/America/Havana: + * library/tzdata/Asia/Amman: + * library/tzdata/Asia/Gaza: + * library/tzdata/Asia/Hebron: + * library/tzdata/Asia/Jerusalem: + * library/tzdata/Pacific/Apia: + * library/tzdata/Pacific/Fakaofo: + * library/tzdata/Pacific/Fiji: Import tzdata2012i. + +2012-11-06 Donal K. Fellows <dkf@users.sf.net> + + * library/http/http.tcl (http::Finish): [Bug 3581754]: Ensure that + callbacks are done at most once to prevent problems with timeouts on a + keep-alive connection (combined with reentrant http package use) + causing excessive stack growth. Not a fix for the underlying problem, + but ensures that pain will be mostly kept away from users. + Bump http package to 2.8.5. + +2012-11-05 Donal K. Fellows <dkf@users.sf.net> + + Added bytecode compilation of many Tcl commands. Some of these are + total compilations and some are only partial (i.e., only compile in + some cases). The (sub-)commands affected are: + * array: exists, set, unset + * dict: create, exists, merge + * format: (simple cases only) + * info: commands, coroutine, level, object + * info object: class, isa object, namespace + * namespace: current, code, qualifiers, tail, which + * regsub: (only cases convertable to simple [string map]) + * self: (only no-argument and [self object] cases) + * string: first, last, map, range + * tailcall: + * yield: + + [This was work originally done on the 'dkf-compile-misc-info' branch.] + +2012-11-05 Jan Nijtmans <nijtmans@users.sf.net> + + IMPLEMENTATION OF TIP#413 + + Align the [string trim] and [string is space] commands, such that + [string trim] by default trims all characters for which [string is + space] returns 1, augmented with the NUL character. + + * generic/tclUtf.c: Add NEL, BOM and two more characters to [string is + space] + * generic/tclCmdMZ.c: Modify [string trim] for Unicode modifications. + * generic/regc_locale.c: Regexp engine must match [string is space] + * doc/string.n + * tests/string.test + ***POTENTIAL INCOMPATIBILITY*** + Code that relied on characters not previously trimmed being not + removed will notice a difference; it is believed that this is rare, + but a workaround to get the behavior in Tcl 8.5 is to use " \t\n\r" as + an explicit trim set. + +2012-10-31 Jan Nijtmans <nijtmans@users.sf.net> + + * win/Makefile.in: Dde version number to 1.4.0, ready for Tcl 8.6.0rc1 + * win/makefile.vc + * win/tclWinDde.c + * library/dde/pkgIndex.tcl + * tests/winDde.test + +2012-10-24 Donal K. Fellows <dkf@users.sf.net> + + * generic/tclCompCmds.c (TclCompileDictUnsetCmd): Added compilation of + the [dict unset] command (for scalar var in LVT only). + +2012-10-23 Jan Nijtmans <nijtmans@users.sf.net> + + * generic/tclInt.h: Add "flags" parameter from Tcl_LoadFile to + * generic/tclIOUtil.c: to various internal functions, so these + * generic/tclLoadNone.c: flags are available through the whole + * unix/tclLoad*.c: filesystem for (future) internal use. + * win/tclWinLoad.c: + +2012-10-17 Miguel Sofer <msofer@users.sf.net> + + * generic/tclBasic.c (TclNRCoroutineObjCmd): insure that numlevels + are properly set, fix bug discovered by dkf and reported at + http://code.activestate.com/lists/tcl-core/12213/ + +2012-10-16 Donal K. Fellows <dkf@users.sf.net> + + IMPLEMENTATION OF TIP#405 + + New commands for applying a transformation to the elements of a list + to produce another list (the [lmap] command) and to the mappings of a + dictionary to produce another dictionary (the [dict map] command). In + both cases, a [continue] will cause the skipping of an element/pair, + and a [break] will terminate the construction early and successfully. + + * generic/tclCmdAH.c (Tcl_LmapObjCmd, TclNRLmapCmd): Implementation of + the new [lmap] command, based on (and sharing much of) [foreach]. + * generic/tclDictObj.c (DictMapNRCmd): Implementation of the new [dict + map] subcommand, based on (and sharing much of) [dict for]. + * generic/tclCompCmds.c (TclCompileLmapCmd, TclCompileDictMapCmd): + Compilation engines for [lmap] and [dict map]. + + IMPLEMENTATION OF TIP#400 + + * generic/tclZlib.c: Allow the specification of a compression + dictionary (a binary blob used to seed the compression engine) in both + streams and channel transformations. Also some reorganization to allow + for getting gzip header dictionaries and controlling buffering levels + in channel transformations (allowing a trade-off between formal + correctness and speed). + (Tcl_ZlibStreamSetCompressionDictionary): New C API to allow setting + the compression dictionary without using a Tcl script. + +2012-10-14 Jan Nijtmans <nijtmans@users.sf.net> + + * generic/tclDictObj.c: [Bug 3576509]: ::tcl::Bgerror crashes with + * generic/tclEvent.c: invalid arguments. Better fix, which helps + for all Tcl_DictObjGet() calls in Tcl's source code. + +2012-10-13 Jan Nijtmans <nijtmans@users.sf.net> + + * generic/tclEvent.c: [Bug 3576509]: tcl::Bgerror crashes with invalid + arguments + +2012-10-06 Jan Nijtmans <nijtmans@users.sf.net> + + * win/Makefile.in: [Bug 2459774]: tcl/win/Makefile.in not compatible + with msys 0.8. + +2012-10-03 Don Porter <dgp@users.sourceforge.net> + + * generic/tclIO.c: When checking for std channels being closed, + compare the channel state, not the channel itself so that stacked + channels do not cause trouble. + +2012-09-26 Reinhard Max <max@suse.de> + + * generic/tclIOSock.c (TclCreateSocketAddress): Work around a bug in + getaddrinfo() on OSX that caused name resolution to fail for [socket + -server foo -myaddr localhost 0]. + +2012-09-20 Jan Nijtmans <nijtmans@users.sf.net> + + * win/configure.in: New import libraries for zlib 1.2.7, usable for + * win/configure: all win32/win64 compilers + * compat/zlib/win32/zdll.lib: + * compat/zlib/win64/zdll.lib: + + * win/tclWinDde.c: [FRQ 3527238]: Full unicode support for dde. Dde + version is now 1.4.0b2. + ***POTENTIAL INCOMPATIBILITY*** + +2012-09-19 Jan Nijtmans <nijtmans@users.sf.net> + + * generic/tcl.h: Make Tcl_Interp a fully opaque structure if + TCL_NO_DEPRECATED is set (TIP 330 and 336). + * win/nmakehlp.c: Let "nmakehlp -V" start searching digits after the + found match (suggested by Harald Oehlmann). + +2012-09-07 Harald Oehlmann <oehhar@users.sf.net> + + *** 8.6b3 TAGGED FOR RELEASE *** + + IMPLEMENTATION OF TIP#404. + + * library/msgcat/msgcat.tcl: [FRQ 3544988]: New commands [mcflset] + * library/msgcat/pkgIndex.tcl: and [mcflmset] to set mc entries with + * unix/Makefile.in: implicit message file locale. + * win/Makefile.in: Bump to 1.5.0. + +2012-08-25 Donal K. Fellows <dkf@users.sf.net> + + * library/msgs/uk.msg: [Bug 3561330]: Use the correct full name of + March in Ukrainian. Thanks to Mikhail Teterin for reporting. + +2012-08-23 Jan Nijtmans <nijtmans@users.sf.net> + + * generic/tclBinary.c: [Bug 3496014]: Unecessary memset() in + Tcl_SetByteArrayObj(). + +2012-08-20 Don Porter <dgp@users.sourceforge.net> + + * generic/tclPathObj.c: [Bug 3559678]: Fix bad filename normalization + when the last component is the empty string. + +2012-08-20 Jan Nijtmans <nijtmans@users.sf.net> + + * win/tclWinPort.h: Remove wrapper macro for ntohs(): unnecessary, + because it doesn't require an initialized winsock_2 library. See: + <http://msdn.microsoft.com/en-us/library/windows/desktop/ms740075%28v=vs.85%29.aspx> + * win/tclWinSock.c: + * generic/tclStubInit.c: + +2012-08-17 Jan Nijtmans <nijtmans@users.sf.net> + + * win/nmakehlp.c: Add "-V<num>" option, in order to be able to detect + partial version numbers. + +2012-08-15 Jan Nijtmans <nijtmans@users.sf.net> + + * win/buildall.vc.bat: Only build the threaded builds by default + * win/rules.vc: Some code cleanup + +2010-08-13 Stuart Cassoff <stwo@users.sourceforge.net> + + * unix/tclUnixCompat.c: [Bug 3555454]: Rearrange a bit to quash + 'declared but never defined' compiler warnings. + +2012-08-13 Jan Nijtmans <nijtmans@users.sf.net> + + * compat/zlib/win64/zlib1.dll: Add 64-bit build of zlib1.dll, and use + * compat/zlib/win64/zdll.lib: it for the dynamic mingw-w64 build. + * win/Makefile.in: + * win/configure.in: + * win/configure: + +2012-08-09 Reinhard Max <max@suse.de> + + * tests/http.test: Fix http-3.29 for machines without IPv6 support. + +2010-08-08 Stuart Cassoff <stwo@users.sourceforge.net> + + * unix/tclUnixCompat.c: Change one '#ifdef' to '#if defined()' for + improved consistency within the file. + +2012-08-08 Jan Nijtmans <nijtmans@users.sf.net> + + * generic/tclfileName.c: [Bug #1536227]: Cygwin network pathname + * tests/fileName.test: support + +2012-08-07 Don Porter <dgp@users.sourceforge.net> + + * generic/tclIOUtil.c: [Bug 3554250]: Overlooked one field of cleanup + in the thread exit handler for the filesystem subsystem. + +2012-07-31 Donal K. Fellows <dkf@users.sf.net> + + * generic/tclInterp.c (Tcl_GetInterpPath): + * unix/tclUnixPipe.c (TclGetAndDetachPids, Tcl_PidObjCmd): + * win/tclWinPipe.c (TclGetAndDetachPids, Tcl_PidObjCmd): + Purge use of Tcl_AppendElement, and corrected conversion of PIDs to + integer objects. + +2012-07-31 Jan Nijtmans <nijtmans@users.sf.net> + + * win/nmakehlp.c: Add -Q option from sampleextension. + * win/Makefile.in: [FRQ 3544967]: Missing objectfiles in static lib + * win/makefile.vc: (Thanks to Jos Decoster). + +2012-07-29 Jan Nijtmans <nijtmans@users.sf.net> + + * win/Makefile.in: No longer build tcltest.exe to run the tests, + but use tclsh86.exe in combination with tcltest86.dll to do that. + * tests/*.test: load tcltest86.dll if necessary. + +2012-07-28 Jan Nijtmans <nijtmans@users.sf.net> + + * tests/clock.test: [Bug 3549770]: Multiple test failures running + * tests/registry.test: tcltest outside build tree + * tests/winDde.test: + +2012-07-27 Jan Nijtmans <nijtmans@users.sf.net> + + * generic/tclUniData.c: Support Unicode 6.2 (Add Turkish lira sign) + * generic/regc_locale.c: + +2012-07-25 Alexandre Ferrieux <ferrieux@users.sourceforge.net> + + * win/tclWinPipe.c: [Bug 3547994]: Abandon the synchronous Windows + pipe driver to its fate when needed to honour TIP#398. + +2012-07-24 Trevor Davel <twylite@crypt.co.za> + + * win/tclWinSock.c: [Bug: 3545363]: Loop over multiple underlying file + descriptors for a socket where required (TcpCloseProc, SocketProc). + Refactor socket/descriptor setup to manage linked list operations in + one place. Fix memory leak in socket close (TcpCloseProc) and related + dangling pointers in SocketEventProc. + +2012-07-19 Reinhard Max <max@suse.de> + + * win/tclWinSock.c (TcpAccept): [Bug: 3545363]: Use a large enough + buffer for accept()ing IPv6 connections. Fix conversion of host and + port for passing to the accept proc to be independent of the IP + version. + +2012-07-23 Alexandre Ferrieux <ferrieux@users.sourceforge.net> + + * generic/tclIO.c: [Bug 3545365]: Never try a bg-flush on a dead + channel, just like before 2011-08-17. + +2012-07-19 Joe Mistachkin <joe@mistachkin.com> + + * generic/tclTest.c: Fix several more missing mutex-locks in + TestasyncCmd. + +2012-07-19 Alexandre Ferrieux <ferrieux@users.sourceforge.net> + + * generic/tclTest.c: [Bug 3544685]: Missing mutex-lock in + TestasyncCmd since 2011-08-19. Unbounded gratitude to Stuart + Cassoff for spotting it. + 2012-07-17 Jan Nijtmans <nijtmans@users.sf.net> * win/makefile.vc: [Bug 3544932]: Visual studio compiler check fails @@ -15,13 +356,14 @@ 2012-07-11 Jan Nijtmans <nijtmans@users.sf.net> - * win/tclWinReg.c: [Bug #3362446]: registry keys command fails + * win/tclWinReg.c: [Bug 3362446]: registry keys command fails with 8.5/8.6. Follow Microsofts example better in order to prevent problems when using HKEY_PERFORMANCE_DATA. 2012-07-10 Jan Nijtmans <nijtmans@users.sf.net> - * unix/tclUnixNotfy.c: [Bug 3541646] Don't panic on triggerPipe overrun + * unix/tclUnixNotfy.c: [Bug 3541646]: Don't panic on triggerPipe + overrun. 2012-07-10 Donal K. Fellows <dkf@users.sf.net> @@ -32,12 +374,12 @@ 2012-07-08 Reinhard Max <max@suse.de> - * library/http/http.tcl: Add fix and test for URLs that contain - * tests/http.test: literal IPv6 addresses. [Bug 3531209] + * library/http/http.tcl: [Bug 3531209]: Add fix and test for URLs that + * tests/http.test: contain literal IPv6 addresses. 2012-07-05 Don Porter <dgp@users.sourceforge.net> - * unix/tclUnixPipe.c: [Bug 1189293] Make "<<" binary safe. + * unix/tclUnixPipe.c: [Bug 1189293]: Make "<<" binary safe. * win/tclWinPipe.c: 2012-07-03 Donal K. Fellows <dkf@users.sf.net> @@ -53,12 +395,12 @@ * library/msgcat/msgcat.tcl: Add tn, ro_MO and ru_MO to msgcat. -2012-06-29 Harald Oehlmann <harald.oehlmann@elmicron.de> +2012-06-29 Harald Oehlmann <oehhar@users.sf.net> - * library/msgcat/msgcat.tcl: [Bug 3536888] Locale guessing of msgcat - * library/msgcat/pkgIndex.tcl: fails on (some) Windows 7. Bump to 1.4.5 - * unix/Makefile.in - * win/Makefile.in + * library/msgcat/msgcat.tcl: [Bug 3536888]: Locale guessing of + * library/msgcat/pkgIndex.tcl: msgcat fails on (some) Windows 7. Bump + * unix/Makefile.in: to 1.4.5 + * win/Makefile.in: 2012-06-29 Donal K. Fellows <dkf@users.sf.net> @@ -82,7 +424,7 @@ 2012-06-25 Don Porter <dgp@users.sourceforge.net> - * generic/tclFileSystem.h: [Bug 3024359] Make sure that the + * generic/tclFileSystem.h: [Bug 3024359]: Make sure that the * generic/tclIOUtil.c: per-thread cache of the list of file systems * generic/tclPathObj.c: currently registered is only updated at times when no active loops are traversing it. Also reduce the amount of @@ -117,9 +459,9 @@ 2012-06-11 Don Porter <dgp@users.sourceforge.net> * generic/tclBasic.c: [Bug 3532959]: Make sure the lifetime - * generic/tclProc.c: management of entries in the linePBodyPtr hash - * tests/proc.test: table can tolerate either order of teardown, - interp first, or Proc first. + * generic/tclProc.c: management of entries in the linePBodyPtr + * tests/proc.test: hash table can tolerate either order of + teardown, interp first, or Proc first. 2012-06-08 Don Porter <dgp@users.sourceforge.net> @@ -296,17 +638,17 @@ 2012-05-09 Andreas Kupries <andreask@activestate.com> - * generic/tclIORChan.c [Bug 3522560]: Fixed the crash, enabled the - test case. Modified [chan postevent] to properly inject the - event(s) into the owner thread's event queue for execution in the - correct context. Renamed the ForwardOpTo...Thread() function to - match with our terminology. + * generic/tclIORChan.c: [Bug 3522560]: Fixed the crash, enabled the + test case. Modified [chan postevent] to properly inject the event(s) + into the owner thread's event queue for execution in the correct + context. Renamed the ForwardOpTo...Thread() function to match with our + terminology. - * tests/ioCmd.test [Bug 3522560]: Added a test which crashes the - core if it were not disabled as knownBug. For a reflected channel + * tests/ioCmd.test: [Bug 3522560]: Added a test which crashes the core + if it were not disabled as knownBug. For a reflected channel transfered to a different thread the [chan postevent] run in the - handler thread tries to execute the owner threads's fileevent - scripts by itself, wrongly reaching across thread boundaries. + handler thread tries to execute the owner threads's fileevent scripts + by itself, wrongly reaching across thread boundaries. 2012-04-28 Alexandre Ferrieux <ferrieux@users.sourceforge.net> @@ -362,11 +704,11 @@ 2012-04-26 Jan Nijtmans <nijtmans@users.sf.net> - * generic/tclStubInit.c: get rid of _ANSI_ARGS_ and CONST - * generic/tclIO.c - * generic/tclIOCmd.c - * generic/tclTest.c - * unix/tclUnixChan.c + * generic/tclStubInit.c: Get rid of _ANSI_ARGS_ and CONST + * generic/tclIO.c: + * generic/tclIOCmd.c: + * generic/tclTest.c: + * unix/tclUnixChan.c: 2012-04-25 Donal K. Fellows <dkf@users.sf.net> @@ -431,8 +773,8 @@ * unix/tcl.m4: Use NDEBUG consistantly meaning: no debugging. * unix/configure: * generic/tclBasic.c: - * library/dde/pkgIndex.tcl Use [::tcl::pkgconfig get debug] instead - * library/reg/pkgIndex.tcl of [info exists ::tcl_platform(debug)] + * library/dde/pkgIndex.tcl: Use [::tcl::pkgconfig get debug] instead + * library/reg/pkgIndex.tcl: of [info exists ::tcl_platform(debug)] 2012-04-10 Donal K. Fellows <dkf@users.sf.net> @@ -465,8 +807,8 @@ 2012-04-04 Jan Nijtmans <nijtmans@users.sf.net> - * win/tclWinSock.c: [Bug 510001]: TclSockMinimumBuffers needs plat imp - * generic/tclIOSock.c: + * win/tclWinSock.c: [Bug 510001]: TclSockMinimumBuffers needs + * generic/tclIOSock.c: platform implementation. * generic/tclInt.decls: * generic/tclIntDecls.h: * generic/tclStubInit.c: @@ -522,7 +864,7 @@ * generic/tclCmdAH.c: on windows (but now for cygwin as well). * generic/tclOODefineCmds.c: minor gcc warning * win/tclWinPort.h: Use lower numbers, preventing integer overflow. - Remove the workaround for mingw-w64 [bug 3407992]. It's long fixed. + Remove the workaround for mingw-w64 [Bug 3407992]. It's long fixed. 2012-03-27 Donal K. Fellows <dkf@users.sf.net> @@ -597,31 +939,31 @@ 2012-03-19 Venkat Iyer <venkat@comit.com> * library/tzdata/America/Atikokan: Update to tzdata2012b. - * library/tzdata/America/Blanc-Sablon - * library/tzdata/America/Dawson_Creek - * library/tzdata/America/Edmonton - * library/tzdata/America/Glace_Bay - * library/tzdata/America/Goose_Bay - * library/tzdata/America/Halifax - * library/tzdata/America/Havana - * library/tzdata/America/Moncton - * library/tzdata/America/Montreal - * library/tzdata/America/Nipigon - * library/tzdata/America/Rainy_River - * library/tzdata/America/Regina - * library/tzdata/America/Santiago - * library/tzdata/America/St_Johns - * library/tzdata/America/Swift_Current - * library/tzdata/America/Toronto - * library/tzdata/America/Vancouver - * library/tzdata/America/Winnipeg - * library/tzdata/Antarctica/Casey - * library/tzdata/Antarctica/Davis - * library/tzdata/Antarctica/Palmer - * library/tzdata/Asia/Yerevan - * library/tzdata/Atlantic/Stanley - * library/tzdata/Pacific/Easter - * library/tzdata/Pacific/Fakaofo + * library/tzdata/America/Blanc-Sablon: + * library/tzdata/America/Dawson_Creek: + * library/tzdata/America/Edmonton: + * library/tzdata/America/Glace_Bay: + * library/tzdata/America/Goose_Bay: + * library/tzdata/America/Halifax: + * library/tzdata/America/Havana: + * library/tzdata/America/Moncton: + * library/tzdata/America/Montreal: + * library/tzdata/America/Nipigon: + * library/tzdata/America/Rainy_River: + * library/tzdata/America/Regina: + * library/tzdata/America/Santiago: + * library/tzdata/America/St_Johns: + * library/tzdata/America/Swift_Current: + * library/tzdata/America/Toronto: + * library/tzdata/America/Vancouver: + * library/tzdata/America/Winnipeg: + * library/tzdata/Antarctica/Casey: + * library/tzdata/Antarctica/Davis: + * library/tzdata/Antarctica/Palmer: + * library/tzdata/Asia/Yerevan: + * library/tzdata/Atlantic/Stanley: + * library/tzdata/Pacific/Easter: + * library/tzdata/Pacific/Fakaofo: * library/tzdata/America/Creston: (new) 2012-03-19 Reinhard Max <max@suse.de> @@ -635,11 +977,11 @@ 2012-03-15 Jan Nijtmans <nijtmans@users.sf.net> * generic/tcl.h: [Bug 3288345]: Wrong Tcl_StatBuf used on Cygwin - * unix/tclUnixFile.c - * unix/tclUnixPort.h + * unix/tclUnixFile.c: + * unix/tclUnixPort.h: * win/cat.c: Remove cygwin stuff no longer needed - * win/tclWinFile.c - * win/tclWinPort.h + * win/tclWinFile.c: + * win/tclWinPort.h: 2012-03-12 Jan Nijtmans <nijtmans@users.sf.net> @@ -683,7 +1025,7 @@ * generic/tclIOUtil.c: [Bug 3466099]: BOM in Unicode * generic/tclEncoding.c: - * tests/source.test + * tests/source.test: 2012-02-23 Donal K. Fellows <dkf@users.sf.net> @@ -837,13 +1179,13 @@ 2011-12-30 Venkat Iyer <venkat@comit.com> - * library/tzdata/America/Bahia : Update to Olson's tzdata2011n - * library/tzdata/America/Havana - * library/tzdata/Europe/Kiev - * library/tzdata/Europe/Simferopol - * library/tzdata/Europe/Uzhgorod - * library/tzdata/Europe/Zaporozhye - * library/tzdata/Pacific/Fiji + * library/tzdata/America/Bahia: Update to Olson's tzdata2011n + * library/tzdata/America/Havana: + * library/tzdata/Europe/Kiev: + * library/tzdata/Europe/Simferopol: + * library/tzdata/Europe/Uzhgorod: + * library/tzdata/Europe/Zaporozhye: + * library/tzdata/Pacific/Fiji: 2011-12-23 Jan Nijtmans <nijtmans@users.sf.net> @@ -895,7 +1237,7 @@ 2011-11-22 Jan Nijtmans <nijtmans@users.sf.net> - * win/tclWinPort.h: [Bug 2935503]: Windows: [file mtime] sets wrong + * win/tclWinPort.h: [Bug 3354324]: Windows: [file mtime] sets wrong * win/tclWinFile.c: time (VS2005+ only). * generic/tclTest.c: @@ -982,9 +1324,9 @@ 2011-10-15 Venkat Iyer <venkat@comit.com> - * library/tzdata/America/Sitka : Update to Olson's tzdata2011l - * library/tzdata/Pacific/Fiji - * library/tzdata/Asia/Hebron (New) + * library/tzdata/America/Sitka: Update to Olson's tzdata2011l + * library/tzdata/Pacific/Fiji: + * library/tzdata/Asia/Hebron: (New) 2011-10-11 Jan Nijtmans <nijtmans@users.sf.net> @@ -1018,16 +1360,16 @@ 2011-10-03 Venkat Iyer <venkat@comit.com> * library/tzdata/Africa/Dar_es_Salaam: Update to Olson's tzdata2011k - * library/tzdata/Africa/Kampala - * library/tzdata/Africa/Nairobi - * library/tzdata/Asia/Gaza - * library/tzdata/Europe/Kaliningrad - * library/tzdata/Europe/Kiev - * library/tzdata/Europe/Minsk - * library/tzdata/Europe/Simferopol - * library/tzdata/Europe/Uzhgorod - * library/tzdata/Europe/Zaporozhye - * library/tzdata/Pacific/Apia + * library/tzdata/Africa/Kampala: + * library/tzdata/Africa/Nairobi: + * library/tzdata/Asia/Gaza: + * library/tzdata/Europe/Kaliningrad: + * library/tzdata/Europe/Kiev: + * library/tzdata/Europe/Minsk: + * library/tzdata/Europe/Simferopol: + * library/tzdata/Europe/Uzhgorod: + * library/tzdata/Europe/Zaporozhye: + * library/tzdata/Pacific/Apia: 2011-09-29 Donal K. Fellows <dkf@users.sf.net> @@ -1126,15 +1468,15 @@ IMPLEMENTATION OF TIP #388 - * doc/Tcl.n - * doc/re_syntax.n - * generic/regc_lex.c - * generic/regcomp.c - * generic/regcustom.h - * generic/tcl.h - * generic/tclParse.c - * tests/reg.test - * tests/utf.test + * doc/Tcl.n: + * doc/re_syntax.n: + * generic/regc_lex.c: + * generic/regcomp.c: + * generic/regcustom.h: + * generic/tcl.h: + * generic/tclParse.c: + * tests/reg.test: + * tests/utf.test: 2011-09-16 Donal K. Fellows <dkf@users.sf.net> @@ -1213,8 +1555,8 @@ 2011-09-06 Jan Nijtmans <nijtmans@users.sf.net> * generic/tcl.h: [RFE 1711975]: Tcl_MainEx() (like Tk_MainEx()) - * generic/tclDecls.h - * generic/tclMain.c + * generic/tclDecls.h: + * generic/tclMain.c: 2011-09-02 Don Porter <dgp@users.sourceforge.net> @@ -1285,8 +1627,8 @@ 2011-08-18 Jan Nijtmans <nijtmans@users.sf.net> * generic/tclUniData.c: [Bug 3393714]: Overflow in toupper delta - * tools/uniParse.tcl - * tests/utf.test + * tools/uniParse.tcl: + * tests/utf.test: 2011-08-17 Alexandre Ferrieux <ferrieux@users.sourceforge.net> @@ -1323,8 +1665,8 @@ * generic/tclPosixStr.c: [Bug 3388350]: mingw64 compiler warnings * win/tclWinPort.h: - * win/configure.in - * win/configure + * win/configure.in: + * win/configure: 2011-08-14 Jan Nijtmans <nijtmans@users.sf.net> @@ -1362,9 +1704,9 @@ 2011-08-09 Jan Nijtmans <nijtmans@users.sf.net> * win/tclWinConsole.c: [Bug 3388350]: mingw64 compiler warnings - * win/tclWinDde.c - * win/tclWinPipe.c - * win/tclWinSerial.c + * win/tclWinDde.c: + * win/tclWinPipe.c: + * win/tclWinSerial.c: 2011-08-09 Jan Nijtmans <nijtmans@users.sf.net> @@ -1690,8 +2032,8 @@ * library/msgcat/msgcat.tcl: Bump to msgcat 1.4.4. * library/msgcat/pkgIndex.tcl: - * unix/Makefile.in - * win/Makefile.in + * unix/Makefile.in: + * win/Makefile.in: 2011-05-25 Donal K. Fellows <dkf@users.sf.net> @@ -2097,7 +2439,7 @@ 2011-03-21 Jan Nijtmans <nijtmans@users.sf.net> - * unix/tclLoadDl.c: [Bug #3216070]: Loading extension libraries + * unix/tclLoadDl.c: [Bug 3216070]: Loading extension libraries * unix/tclLoadDyld.c: from embedded Tcl applications. ***POTENTIAL INCOMPATIBILITY*** For extensions which rely on symbols from other extensions being @@ -2374,20 +2716,20 @@ * win/tclWinChan.c: Fix various gcc-4.5.2 64-bit warning * win/tclWinConsole.c: messages, e.g. by using full 64-bits for * win/tclWinDde.c: socket fd's - * win/tclWinPipe.c - * win/tclWinReg.c - * win/tclWinSerial.c - * win/tclWinSock.c - * win/tclWinThrd.c + * win/tclWinPipe.c: + * win/tclWinReg.c: + * win/tclWinSerial.c: + * win/tclWinSock.c: + * win/tclWinThrd.c: 2011-01-19 Jan Nijtmans <nijtmans@users.sf.net> - * tools/genStubs.tcl: [Enh #3159920]: Tcl_ObjPrintf() crashes with + * tools/genStubs.tcl: [FRQ 3159920]: Tcl_ObjPrintf() crashes with * generic/tcl.decls bad format specifier. - * generic/tcl.h - * generic/tclDecls.h + * generic/tcl.h: + * generic/tclDecls.h: -2011-01-18 Donal K. Fellows <dkf@users.sf.net>3159920 +2011-01-18 Donal K. Fellows <dkf@users.sf.net> * generic/tclOOMethod.c (PushMethodCallFrame): [Bug 3001438]: Make sure that the cmdPtr field of the procPtr is correct and relevant at @@ -2400,10 +2742,10 @@ * generic/tclBasic.c: Various mismatches between Tcl_Panic * generic/tclCompCmds.c: format string and its arguments, * generic/tclCompCmdsSZ.c: discovered thanks to [Bug 3159920] - * generic/tclCompExpr.c - * generic/tclEnsemble.c - * generic/tclPreserve.c - * generic/tclTest.c + * generic/tclCompExpr.c: + * generic/tclEnsemble.c: + * generic/tclPreserve.c: + * generic/tclTest.c: 2011-01-17 Jan Nijtmans <nijtmans@users.sf.net> @@ -2646,7 +2988,7 @@ * generic/tclBinary.c: [Bug 3129448]: Possible over-allocation on * generic/tclCkalloc.c: 64-bit platforms. - * generic/tclTrace.c + * generic/tclTrace.c: 2010-12-05 Jan Nijtmans <nijtmans@users.sf.net> @@ -2782,7 +3124,7 @@ * win/cat.c: to reality. See for what's missing: * win/tcl.m4: <https://sourceforge.net/apps/trac/mingw-w64/wiki/Unicode%20apps> * win/configure: (re-generated) - * win/tclWinPort.h: [Bug #3110161]: Extensions using TCHAR don't + * win/tclWinPort.h: [Bug 3110161]: Extensions using TCHAR don't compile on VS2005 SP1 2010-11-15 Andreas Kupries <andreask@activestate.com> @@ -6936,9 +7278,9 @@ * unix/tclUnixChan.c: TclUnixWaitForFile(): use FD_* macros * macosx/tclMacOSXNotify.c: to manipulate select masks (Cassoff). - [Freq 1960647] [Bug 3486554] + [FRQ 1960647] [Bug 3486554] - * unix/tclLoadDyld.c: use RTLD_GLOBAL instead of RTLD_LOCAL. + * unix/tclLoadDyld.c: Use RTLD_GLOBAL instead of RTLD_LOCAL. [Bug 1961211] * macosx/tclMacOSXNotify.c: revise CoreFoundation notifier to allow @@ -7134,9 +7476,8 @@ 2009-03-15 Joe Mistachkin <joe@mistachkin.com> - * generic/tclThread.c: Modify fix for TSD leak to match Tcl 8.5 - * generic/tclThreadStorage.c: (and prior) allocation semantics. [Bug - 2687952] + * generic/tclThread.c: [Bug 2687952]: Modify fix for TSD leak to match + * generic/tclThreadStorage.c: Tcl 8.5 (and prior) allocation semantics 2009-03-15 Donal K. Fellows <dkf@users.sf.net> @@ -7224,10 +7565,10 @@ 2009-02-20 Don Porter <dgp@users.sourceforge.net> - * generic/tclPathObj.c: Fixed mistaken logic in TclFSGetPathType() - * tests/fileName.test: that assumed (not "absolute" => "relative"). - This is a false assumption on Windows, where "volumerelative" is - another possibility. [Bug 2571597] + * generic/tclPathObj.c: [Bug 2571597]: Fixed mistaken logic in + * tests/fileName.test: TclFSGetPathType() that assumed (not + "absolute") => "relative". This is a false assumption on Windows, + where "volumerelative" is another possibility. 2009-02-18 Don Porter <dgp@users.sourceforge.net> @@ -7281,23 +7622,23 @@ 2009-02-16 Jan Nijtmans <nijtmans@users.sf.net> - * generic/tclZlib.c: hack needed for official zlib1.dll build. + * generic/tclZlib.c: Hack needed for official zlib1.dll build. * win/configure.in: fix [Feature Request 2605263] use official * win/Makefile.in: zlib build. * win/configure: (regenerated) * compat/zlib/zdll.lib: new files * compat/zlib/zlib1.dll: - * win/Makefile.in: fix [Bug 2605232] tdbc doesn't build when - Tcl is compiled with --disable-shared. + * win/Makefile.in: [Bug 2605232]: tdbc doesn't build when Tcl is + compiled with --disable-shared. 2009-02-15 Don Porter <dgp@users.sourceforge.net> - * generic/tclStringObj.c: Added protections from invalid memory - * generic/tclTestObj.c: accesses when we append (some part of) - * tests/stringObj.test: a Tcl_Obj to itself. Added the - appendself and appendself2 subcommands to the [teststringobj] testing - command and added tests to the test suite. [Bug 2603158] + * generic/tclStringObj.c: [Bug 2603158]: Added protections from + * generic/tclTestObj.c: invalid memory accesses when we append + * tests/stringObj.test: (some part of) a Tcl_Obj to itself. + Added the appendself and appendself2 subcommands to the + [teststringobj] testing command and added tests to the test suite. * generic/tclStringObj.c: Factor out duplicate code from Tcl_AppendObjToObj. @@ -7433,7 +7774,7 @@ 2009-02-09 Jan Nijtmans <nijtmans@users.sf.net> - * generic/tclCompile.c: fix [Bug 2555129] const compiler warning (as + * generic/tclCompile.c: [Bug 2555129]: const compiler warning (as error) in tclCompile.c 2009-02-07 Donal K. Fellows <dkf@users.sf.net> @@ -7445,8 +7786,8 @@ 2009-02-05 Joe Mistachkin <joe@mistachkin.com> - * generic/tclInterp.c: Fix argument checking for [interp cancel]. [Bug - 2544618] + * generic/tclInterp.c: [Bug 2544618]: Fix argument checking for + [interp cancel]. * unix/Makefile.in: Fix build issue with zlib on FreeBSD (and possibly other platforms). @@ -7468,12 +7809,12 @@ 2009-02-04 Don Porter <dgp@users.sourceforge.net> - * generic/tclStringObj.c: Added overflow protections to the - AppendUtfToUtfRep routine to either avoid invalid arguments and - crashes, or to replace them with controlled panics. [Bug 2561794] + * generic/tclStringObj.c: [Bug 2561794]: Added overflow protections to + the AppendUtfToUtfRep routine to either avoid invalid arguments and + crashes, or to replace them with controlled panics. - * generic/tclCmdMZ.c: Prevent crashes due to int overflow of the - length of the result of [string repeat]. [Bug 2561746] + * generic/tclCmdMZ.c: [Bug 2561746]: Prevent crashes due to int + overflow of the length of the result of [string repeat]. 2009-02-03 Jan Nijtmans <nijtmans@users.sf.net> @@ -7505,9 +7846,9 @@ 2009-02-03 Don Porter <dgp@users.sourceforge.net> - * generic/tclStringObj.c (SetUnicodeObj): Corrected failure of - Tcl_SetUnicodeObj() to panic on a shared object. [Bug 2561488]. Also - factored out common code to reduce duplication. + * generic/tclStringObj.c (SetUnicodeObj): [Bug 2561488]: + Corrected failure of Tcl_SetUnicodeObj() to panic on a shared object. + Also factored out common code to reduce duplication. * generic/tclObj.c (Tcl_GetStringFromObj): Reduce code duplication. @@ -7582,19 +7923,19 @@ 2009-01-26 Alexandre Ferrieux <ferrieux@users.sourceforge.net> - * generic/tclInt.h: Fix [Bug 1028264]: WSACleanup() too early. - * generic/tclEvent.c: The fix introduces "late exit handlers" - * win/tclWinSock.c: for similar late process-wide cleanups. + * generic/tclInt.h: [Bug 1028264]: WSACleanup() too early. + * generic/tclEvent.c: The fix introduces "late exit handlers" for + * win/tclWinSock.c: similar late process-wide cleanups. 2009-01-26 Alexandre Ferrieux <ferrieux@users.sourceforge.net> - * win/tclWinSock.c: Fix [Bug 2446662]: resync Win behavior on RST - with that of unix (EOF). + * win/tclWinSock.c: [Bug 2446662]: Resync Win behavior on RST with + that of unix (EOF). 2009-01-26 Donal K. Fellows <dkf@users.sf.net> - * generic/tclZlib.c (ChanClose): Only generate error messages in the - interpreter when the thread is not being closed down. [Bug 2536400] + * generic/tclZlib.c (ChanClose): [Bug 2536400]: Only generate error + messages in the interpreter when the thread is not being closed down. 2009-01-23 Donal K. Fellows <dkf@users.sf.net> @@ -7621,7 +7962,7 @@ 2009-01-21 Andreas Kupries <andreask@activestate.com> - * generic/tclIORChan.c (ReflectClose): Fix for [Bug 2458202]. + * generic/tclIORChan.c (ReflectClose): [Bug 2458202]: * generic/tclIORTrans.c (ReflectClose): Closing a channel may supply NULL for the 'interp'. Test for finalization needs to be different, and one place has to pull the interp out of the channel instead. @@ -7633,12 +7974,12 @@ 2009-01-19 Kevin B. Kenny <kennykb@acm.org> - * unix/Makefile.in: Added a CONFIG_INSTALL_DIR parameter so that - * unix/tcl.m4: distributors can control where tclConfig.sh goes. - Made the installation of 'ldAix' conditional upon actually being on an - AIX system. Allowed for downstream packagers to customize - SHLIB_VERSION on BSD-derived systems. Thanks to Stuart Cassoff for - [Patch 907924]. + * unix/Makefile.in: [Patch 907924]:Added a CONFIG_INSTALL_DIR + * unix/tcl.m4: parameter so that distributors can control where + tclConfig.sh goes. Made the installation of 'ldAix' conditional upon + actually being on an AIX system. Allowed for downstream packagers to + customize SHLIB_VERSION on BSD-derived systems. Thanks to Stuart + Cassoff for his help. * unix/configure: Autoconf 2.59 2009-01-19 David Gravereaux <davygrvy@pobox.com> @@ -7675,8 +8016,8 @@ 2009-01-13 Jan Nijtmans <nijtmans@users.sf.net> - * unix/tcl.m4: fix [tcl-Bug 2502365] Building of head on HPUX is - broken when using the native CC. + * unix/tcl.m4: [Bug 2502365]: Building of head on HPUX is broken when + using the native CC. * unix/configure (autoconf-2.59) 2009-01-13 Donal K. Fellows <dkf@users.sf.net> @@ -7699,20 +8040,20 @@ 2009-01-09 Don Porter <dgp@users.sourceforge.net> - * generic/tclStringObj.c (STRING_SIZE): Corrected failure to limit - memory allocation requests to the sizes that can be supported by Tcl's - memory allocation routines. [Bug 2494093] + * generic/tclStringObj.c (STRING_SIZE): [Bug 2494093]: Corrected + failure to limit memory allocation requests to the sizes that can be + supported by Tcl's memory allocation routines. 2009-01-09 Donal K. Fellows <dkf@users.sf.net> - * generic/tclNamesp.c (NamespaceEnsembleCmd): Error out when someone - gives wrong # of args to [namespace ensemble create]. [Bug 1558654] + * generic/tclNamesp.c (NamespaceEnsembleCmd): [Bug 1558654]: Error out + when someone gives wrong # of args to [namespace ensemble create]. 2009-01-08 Don Porter <dgp@users.sourceforge.net> - * generic/tclStringObj.c (STRING_UALLOC): Added missing parens - required to get correct results out of things like - STRING_UALLOC(num + append). [Bug 2494093] + * generic/tclStringObj.c (STRING_UALLOC): [Bug 2494093]: Added missing + parens required to get correct results out of things like + STRING_UALLOC(num + append). 2009-01-08 Donal K. Fellows <dkf@users.sf.net> @@ -7724,7 +8065,7 @@ 2009-01-07 Donal K. Fellows <dkf@users.sf.net> - * doc/dict.n: Added more examples. [Tk Bug 2491235] + * doc/dict.n: [Tk Bug 2491235]: Added more examples. * tests/oo.test (oo-22.1): Adjusted test to be less dependent on the specifics of how [info frame] reports general frame information, and @@ -7743,20 +8084,20 @@ * generic/tclDictObj.c (DictIncrCmd): Corrected twiddling in internals of dictionaries so that literals can't get destroyed. - * tests/expr.test: Eliminate non-ASCII char. [Bug 2006879] + * tests/expr.test: [Bug 2006879]: Eliminate non-ASCII char. - * generic/tclOOInfo.c (InfoObjectMethodsCmd,InfoClassMethodsCmd): Only - delete pointers that were actually allocated! [Bug 2489836] + * generic/tclOOInfo.c (InfoObjectMethodsCmd,InfoClassMethodsCmd): + [Bug 2489836]: Only delete pointers that were actually allocated! * generic/tclOO.c (TclNRNewObjectInstance, Tcl_NewObjectInstance): - Perform search for existing commands in right context. [Bug 2481109] + [Bug 2481109]: Perform search for existing commands in right context. 2009-01-05 Donal K. Fellows <dkf@users.sf.net> - * generic/tclCmdMZ.c (TclNRSourceObjCmd): Make implementation of the - * generic/tclIOUtil.c (TclNREvalFile): [source] command be NRE - enabled so that [yield] inside a script sourced in a coroutine can - work. [Bug 2412068] + * generic/tclCmdMZ.c (TclNRSourceObjCmd): [Bug 2412068]: Make + * generic/tclIOUtil.c (TclNREvalFile): implementation of the + [source] command be NRE enabled so that [yield] inside a script + sourced in a coroutine can work. 2009-01-04 Donal K. Fellows <dkf@users.sf.net> @@ -7771,12 +8112,12 @@ 2009-01-02 Donal K. Fellows <dkf@users.sf.net> - * unix/tcl.m4 (SC_CONFIG_CFLAGS): Force the use of the compatibility - version of mkstemp() on IRIX. [Bug 878333] + * unix/tcl.m4 (SC_CONFIG_CFLAGS): [Bug 878333]: Force the use of the + compatibility version of mkstemp() on IRIX. * unix/configure.in, unix/Makefile.in (mkstemp.o): - * compat/mkstemp.c (new file): Added a compatibility implementation of - the mkstemp() function, which is apparently needed on some platforms. - [Bug 741967] + * compat/mkstemp.c (new file): [Bug 741967]: Added a compatibility + implementation of the mkstemp() function, which is apparently needed + on some platforms. ****************************************************************** *** CHANGELOG ENTRIES FOR 2008 IN "ChangeLog.2008" *** diff --git a/ChangeLog.2000 b/ChangeLog.2000 index 2ebdd23..0d20eaf 100644 --- a/ChangeLog.2000 +++ b/ChangeLog.2000 @@ -746,7 +746,7 @@ * doc/trace.n: minor doc cleanup -2000-09-06 André Pönitz <poenitz@htwm.de> +2000-09-06 André Pönitz <poenitz@htwm.de> * doc/*.n: added or changed "SEE ALSO:" section @@ -1086,7 +1086,7 @@ * unix/tcl.m4 (SC_ENABLE_GCC): Don't set CC=gcc before running AC_PROG_CC if CC is already set. -2000-07-13 André Pönitz <poenitz@mathematik.tu-chemnitz.de> +2000-07-13 André Pönitz <poenitz@mathematik.tu-chemnitz.de> * doc/lappend.n: * doc/lindex.n: diff --git a/ChangeLog.2001 b/ChangeLog.2001 index 6579651..06e7c36 100644 --- a/ChangeLog.2001 +++ b/ChangeLog.2001 @@ -939,7 +939,7 @@ version of Tcl with Cygwin gcc. Users should compile with Mingw gcc instead. -2001-11-06 Andreas Kupries <andreas_kupries@users.sourceforge.net> +2001-11-06 Andreas Kupries <andreas_kupries@users.sourceforge.net> * generic/tclIO.c (ReadChars): Fixed [Bug 478856] reported by Stuart Cassoff <stwo@users.sourceforge.net>. The bug caused loss of diff --git a/ChangeLog.2003 b/ChangeLog.2003 index b12cd2c..c586ba9 100644 --- a/ChangeLog.2003 +++ b/ChangeLog.2003 @@ -3284,7 +3284,7 @@ 2003-01-10 Vince Darley <vincentdarley@users.sourceforge.net> - * generic/tclIOUtil.c: + * generic/tclIOUtil.c: * win/tclWinInt.h: * win/tclWinInit.c: fix to new WinTcl crash on exit with vfs, introduced on 2002-12-06. Encodings must be cleaned up after the @@ -1,5 +1,5 @@ README: Tcl - This is the Tcl 8.6b2 source distribution. + This is the Tcl 8.6b3 source distribution. http://tcl.sourceforge.net/ You can get any source release of Tcl from the file distributions link at the above URL. @@ -126,7 +126,7 @@ Tcl_Eval. that came after version 3.3 was released. 40. 5/17/91 Changed tests to conform to Mary Ann May-Pumphrey's approach. - + 41. 5/23/91 Massive revision to Tcl parser to simplify the implementation of string and floating-point support in expressions. Newlines inside [] are now treated as command separators rather than word separators @@ -260,7 +260,7 @@ argument (before file name), for consistency with other Tcl commands. *** POTENTIAL INCOMPATIBILITY *** 72. 8/20/91 Changed format of information in $errorInfo variable: -comments such as +comments such as ("while" body line 1) are now on separate lines from commands being executed. *** POTENTIAL INCOMPATIBILITY *** @@ -1192,7 +1192,7 @@ under some dynamic loading systems (e.g. SunOS 4.1 and Windows). 6/8/95 (feature change) Modified interface to Tcl_Main to pass in the address of the application-specific initialization procedure. Tcl_AppInit is no longer hardwired into Tcl_Main. This is needed -in order to make Tcl a shared library. +in order to make Tcl a shared library. 6/8/95 (feature change) Modified Makefile so that the installed versions of tclsh and libtcl.a have version number in them (e.g. tclsh7.4 and @@ -1616,7 +1616,7 @@ file name. Under Windows '95, this is incorrectly interpreted as a UNC path. They delays came from the network timeouts needed to determine that the file name was invalid. Tcl_TranslateFileName now suppresses duplicate slashes that aren't at the beginning of the file name. (SS) - + 1/25/96 (bug fix) Changed exec and open to create children so they are attached to the application's console if it exists. (SS) @@ -2254,21 +2254,21 @@ version of Tcl. It's quite a bit faster than MetroWerk's version. (RJ) 8/26/96 (documentation update) Removed old change bars (for all changes in Tcl 7.5 and earlier releases) from manual entries. (JO) -8/27/96 (enhancement) The exec and open commands behave better and work in -more situations under Windows NT and Windows 95. Documentation describes +8/27/96 (enhancement) The exec and open commands behave better and work in +more situations under Windows NT and Windows 95. Documentation describes what is still lacking. (CS) 8/27/96 (enhancement) The Windows makefiles will now compile even if the compiler is not in the path and/or the compiler's environment variables -have not been set up. (CS) +have not been set up. (CS) -8/27/96 (configuration improvement) The Windows resource files are +8/27/96 (configuration improvement) The Windows resource files are automatically updated when the version/patch level changes. The header file now has a comment that reminds the user which other files must be manually updated when the version/patch level changes. (CS) 8/28/96 (new feature) Added file manipulation features (copy, rename, delete, -mkdir) that are supported on all platforms. They are implemented as +mkdir) that are supported on all platforms. They are implemented as subcommands to the "file" command. See the documentation for the "file" command for more information. (JH) @@ -2371,7 +2371,7 @@ the Tcl script in the fileevent wasn't closing the socket immediately. (JL) package goes in a separate subdirectory of a directory in $tcl_pkgPath). These directories are included in auto_path by default. - - Changed the package auto-loader to look for pkgIndex.tcl files + - Changed the package auto-loader to look for pkgIndex.tcl files not only in the auto_path directories but also in their immediate children. This should make it easier to install and uninstall packages (don't have to change auto_path or merge pkgIndex.tcl @@ -2621,7 +2621,7 @@ lookups of keyword arguments. (JO) 1/12/97 (new feature) Serial IO channel drivers for Windows and Unix, available by using Tcl open command to open pseudo-files like "com1:" or -"/dev/ttya". New option to Tcl fconfigure command for serial files: +"/dev/ttya". New option to Tcl fconfigure command for serial files: "-mode baud,parity,data,stop" to specify baud rate, parity, data bits, and stop bits. Serial IO is not yet available on Mac. @@ -2701,7 +2701,7 @@ to Feb 31.) The code now will return the last valid day of the month in these situations. Thanks to Hume Smith for sending in this bug fix. (RJ) -2/10/97 (feature change) Eliminated Tcl_StringObjAppend and +2/10/97 (feature change) Eliminated Tcl_StringObjAppend and Tcl_StringObjAppendObj procedures, replaced them with Tcl_AppendToObj and Tcl_AppendStringsToObj procedures. Added new procedure Tcl_SetObjLength. (JO) @@ -3068,7 +3068,7 @@ compilation errors from "invoked from within" to "while compiling". (BL) modified the interpreter result even if there was no error. - The argument parsing procedure used by several compile procedures always treated "]" as end of a command: e.g., "set a ]" would fail. - - Changed errorInfo traceback message for compilation errors from + - Changed errorInfo traceback message for compilation errors from "invoked from within" to "while compiling". - Problem initializing Tcl object managers during interpreter creation. - Added check and error message if formal parameter to a procedure is @@ -3143,7 +3143,7 @@ is leaked to safe interps. Error message fixes for interp sub commands. Likewise changes in safealias.tcl; tcl_safeCreateInterp can now be called without argument to generate the slave name (like in interp create). (DL) -7/10/97 (bug fixes) Bytecode compiler now generates more detailed +7/10/97 (bug fixes) Bytecode compiler now generates more detailed command location information: subcommands as well as commands now have location information. This means command trace procedures now get the correct source string for each command in their command parameter. (BL) @@ -3181,7 +3181,7 @@ malloc and free. (SS) sourcing/loading (see safe.n) to hide pathnames, use virtual paths tokens instead, improved security in several respects and made it more tunable. Multi level interp loading can work too now. Package auto -loading now works in safe interps as long as the package directory is in +loading now works in safe interps as long as the package directory is in the auto_path (no deep crawling allowed in safe interps). (DL) *** POTENTIAL INCOMPATIBILITY with previous alpha and beta releases *** @@ -3209,7 +3209,7 @@ exists" command returns 0 for them. (BL) 7/29/97 (feature change) Changed the http package to use the ::http namespace. http_get renamed to http::geturl, http_config renamed to http::config, http_formatQuery renamed to http::formatQuery. -It now provides the 2.0 version of the package. +It now provides the 2.0 version of the package. The 1.0 version is still available with the old names. *** POTENTIAL INCOMPATIBILITY with Tcl 8.0b2 but not with Tcl 7.6 *** @@ -3273,7 +3273,7 @@ except that the default precision is 12 instead of 6. (JO) ----------------- Released 8.0, 8/18/97 ----------------------- 8/19/97 (bug fix) Minimal fix for glob -nocomplain bugs: -"glob -nocomplain unreadableDir/*" was generating an anonymous +"glob -nocomplain unreadableDir/*" was generating an anonymous error. More in depth fixes will come with 8.1. (DL). 8/20/97 (bug fix) Removed check for FLT_MIN in binary command so @@ -3318,7 +3318,7 @@ does not prevent stack overflow by multi-interps recursion or aliasing} (DL) 9/11/97 (bug fix) An uninitialized variable in Tcl_WaitPid caused pipes to fail to report eof properly under Windows. (SS) -9/12/97 (bug fix) "exec" was misidentifying some DOS executables as not +9/12/97 (bug fix) "exec" was misidentifying some DOS executables as not executable. (CCS) 9/14/97 (bug fix) Was using the wrong structure in sizeof operation in @@ -3342,7 +3342,7 @@ Roseman for the pointer on the fix.) (RJ) cause the compare function to run off the end of an array if the number only contained 0's. (Thanks to Greg Couch for the report.) (RJ) -9/18/97 (bug fix) TclFinalizeEnvironment was not cleaning up +9/18/97 (bug fix) TclFinalizeEnvironment was not cleaning up properly. (DL, JI) 9/18/97 (bug fix) Fixed long-standing bug where an "array get" command @@ -3378,9 +3378,9 @@ Now you can "join $list \0" for instance. (DL) non-existent directory, exec would fail when trying to create its temporary files. (CCS) -10/9/97 (bug fix) Under mac and windows, "info hostname" would crash if +10/9/97 (bug fix) Under mac and windows, "info hostname" would crash if sockets were installed but the hostname could not be determined anyhow. -Tcl_GetHostName() was returning NULL when it should have been returning +Tcl_GetHostName() was returning NULL when it should have been returning an empty string. (CCS) 10/10/97 (bug fix) "file attribute /" returned error on windows. (CCS) @@ -3468,7 +3468,7 @@ around to be really closed in this case. (JL) 12/8/97 (bug fix) Need to protect the channel in a fileevent so that it is not deleted before the fileevent handler returns. (CS, JL) -12/18/97 (bug fix) In the opt argument parsing package: if the description +12/18/97 (bug fix) In the opt argument parsing package: if the description had only flags, the "too many arguments" case was not detected. The default value was not used for the special "args" ending argument. (DL) @@ -3511,7 +3511,7 @@ that could lead to a crash. (SS) non-local variable references. (SS) 6/25/98 (new features) Added name resolution hooks to support [incr Tcl]. -There are new internal Tcl_*Resolver* APIs to add, query and remove the hooks. +There are new internal Tcl_*Resolver* APIs to add, query and remove the hooks. With this changes it should be possible to dynamically load [incr Tcl] as an extension. (MM) @@ -3539,7 +3539,7 @@ TclAccessInsertProc, TclStatInsertProc, & TclOpenFileChannelInsertProc insert pointers to such routines; TclAccessDeleteProc, TclStatDeleteProc, & TclOpenFileChannelDeleteProc delete pointers to such routines. See the file generic/tclIOUtils.c for more details. (SKS) - + 7/1/98 (enhancement) Added a new internal C variable tclPreInitScript. This is a pointer to a string that may hold an initialization script; If this pointer is non-NULL it is evaluated in @@ -3623,7 +3623,7 @@ internal representation holds a pointer to a Proc structure. Extended TclCreateProc to take both strings and "procbody". (EMS) 10/13/98 (bug fix) The "info complete" command can now handle strings -with NULLs embedded. Thanks to colin@field.medicine.adelaide.edu.au +with NULLs embedded. Thanks to colin@field.medicine.adelaide.edu.au for providing this fix. (RJ) 10/13/98 (bug fix) The "lsort -dictionary" command did not properly @@ -3691,7 +3691,7 @@ by default. Fixed socket code so it turns off this bit right after creation so sockets aren't kept open by exec'ed processes. [Bug: 892] Thanks to Kevin Kenny for this fix. (SS) -1/11/98 (bug fix) On HP, "info sharedlibextension" was returning +1/11/98 (bug fix) On HP, "info sharedlibextension" was returning empty string on static apps. It now always returns ".sl". (RJ) 1/28/99 (configure change) Now support -pipe option on gcc. (RJ) @@ -3736,7 +3736,7 @@ panic. (stanton) 2/2/99 (feature change/bug fix) Changed the behavior of "file extension" so that it splits at the last period. Now the extension of -a file like "foo..o" is ".o" instead of "..o" as in previous versions. +a file like "foo..o" is ".o" instead of "..o" as in previous versions. *** POTENTIAL INCOMPATIBILITY *** ----------------- Released 8.0.5, 3/9/99 ------------------------- @@ -3757,15 +3757,15 @@ a file like "foo..o" is ".o" instead of "..o" as in previous versions. of a UTF-8 string remains \0. Thus Tcl strings once again do not contain null bytes, except for termination bytes. - For Java compatibility, "\uXXXX" is used in Tcl to enter a Unicode - character. "\u0000" through "\uffff" are acceptable Unicode - characters. + character. "\u0000" through "\uffff" are acceptable Unicode + characters. - "\xXX" is used to enter a small Unicode character (between 0 and 255) in Tcl. - Tcl automatically translates between UTF-8 and the normal encoding for the platform during interactions with the system. - The fconfigure command now supports a -encoding option for specifying the encoding of an open file or socket. Tcl will automatically - translate between the specified encoding and UTF-8 during I/O. + translate between the specified encoding and UTF-8 during I/O. See the directory library/encoding to find out what encodings are supported (eventually there will be an "encoding" command that makes this information more accessible). @@ -3839,7 +3839,7 @@ imported procedures as well as procedures defined in a namespace. (BL) in place of Tcl_GetStringFromObj() if the string representation's length isn't needed. (BL) -12/18/97 (bug fix) In the opt argument parsing package: if the description +12/18/97 (bug fix) In the opt argument parsing package: if the description had only flags, the "too many arguments" case was not detected. The default value was not used for the special "args" ending argument. (DL) @@ -3849,11 +3849,11 @@ procs now in auto.tcl and package.tcl can be autoloaded if needed. (DL) 1/7/98 (enhancement) tcltest made at install time will search for it's init.tcl where it is, even when using virtual path compilation. (DL) -1/8/98 (os bug workaround) when needed, using a replacement for memcmp so +1/8/98 (os bug workaround) when needed, using a replacement for memcmp so string compare "char with high bit set" "char w/o high bit set" returns the expected value on all platforms. (DL) -1/8/98 (unix portability/configure) building from .../unix/targetName/ +1/8/98 (unix portability/configure) building from .../unix/targetName/ subdirectories and simply using "../configure" should now work fine. (DL) 1/14/98 (enhancement) Added new regular expression package that @@ -3885,7 +3885,7 @@ to generate direct loading package indexes (such those you need if you use namespaces and plan on using namespace import just after package require). pkg_mkIndex still has limitations regarding package dependencies but errors are now ignored and with -direct, correct -package indexes can be generated even if there are dependencies as long +package indexes can be generated even if there are dependencies as long as the "package provide" are done early enough in the files. (DL) 1/28/98 (enhancement) Performance tuning of regexp and regsub. (CCS) @@ -3909,7 +3909,7 @@ continue to use the argv array after calling Tcl_OpenCommandChannel(). (CCS) 2/1/98 (bug fix) More bugs with %Z in format string argument to strftime(): 1. Borland always returned empty string. 2. MSVC always returned the timezone string for the current time, not the - timezone string for the specified time. + timezone string for the specified time. 3. With MSVC, "clock format 0 -format %Z -gmt 1" would return "GMT" the first time it was called, but would return the current timezone string on all subsequent calls. (CCS) @@ -3931,7 +3931,7 @@ root directory was returning error. (CCS) determine the attributes for a file. Previously it would return different error messages on Unix vs. Windows vs. Mac. (CCS) -2/4/98 (bug fixes) Fixed several instances of bugs where the parser/compiler +2/4/98 (bug fixes) Fixed several instances of bugs where the parser/compiler would reach outside the range of allocated memory. Improved the array lookup algorithm in set compilation. (DL) @@ -3939,13 +3939,13 @@ lookup algorithm in set compilation. (DL) deprecated and ignored. The part1 is always parsed when the part2 argument is NULL. This is to avoid a pattern of errors for extension writers converting from string based Tcl_SetVar() to new Tcl_SetObjVar2() and who could easily -forget to provide the flag and thus get code working for normal variables +forget to provide the flag and thus get code working for normal variables but not for array elements. The performance hit is minimal. A side effect of that change is that is is no longer possible to create scalar variables -that can't be accessed by tcl scripts because of their invalid name -(ending with parenthesis). Likewise it is also parsed and checked to -ensure that you don't create array elements of array whose name is a valid -array element because they would not be accessible from scripts anyway. +that can't be accessed by tcl scripts because of their invalid name +(ending with parenthesis). Likewise it is also parsed and checked to +ensure that you don't create array elements of array whose name is a valid +array element because they would not be accessible from scripts anyway. Note: There is still duplicate array elements parsing code. (DL) *** POTENTIAL INCOMPATIBILITY *** @@ -3991,7 +3991,7 @@ registry call. (CCS) 2/11/98 (enhancement) Eliminate the TCL_USE_TIMEZONE_VAR definition from configure.in, because it was the same information as the already existing HAVE_TM_ZONE definition. The lack of HAVE_TM_ZONE is used to work around a -Solaris and Windows bug where "clock format [clock sec] -format %Z -gmt 1" +Solaris and Windows bug where "clock format [clock sec] -format %Z -gmt 1" produces the local timezone string instead of "GMT". (CCS) 2/11/98 (bug fix) Memleaks and dereferencing of uninitialized memory in @@ -4349,7 +4349,7 @@ strings that are already null terminated. [Bug: 1793] (stanton) 5/3/99 (new feature) Applied Jeff Hobbs's string patch which includes the following changes: - - added new subcommands: equal, repeat, map, is, replace + - added new subcommands: equal, repeat, map, is, replace - added -length option to "string compare|equal" - added -nocase option to "string compare|equal|match" - string and list indices can be an integer or end?-integer?. @@ -4378,7 +4378,7 @@ improvements for many Tcl scripts. [Bug: 1063] (stanton) encoding subfield from the LANG/LC_ALL environment variables in cases where the locale is not found in the built-in locale table. It also attempts to initialize the locale subsystem so X11 is happy. [Bug: 1989] -(stanton) +(stanton) 5/14/99 (bug fix) Applied the patch to fix 100-year and 400-year boundaries in leap year code, from Isaac Hollander. [Bug: 2066] (redman) @@ -4466,7 +4466,7 @@ harness package. Modified test files to use new tcltest package. 6/26/99 (new feature) Applied patch from Peter Hardie to add poke command to dde and changed the dde package version number to -1.1. (redman) +1.1. (redman) 6/28/99 (bug fix) Applied patch from Peter Hardie to fix problem in Tcl_GetIndexFromObj() when the key being passed is the empty string. @@ -4529,7 +4529,7 @@ notation for opening serial ports on Windows. (redman) instead of the platform-specific "size_t", primarily after SunOS 4 users could no longer compile. (redman) -7/22/99 (bug fix) Fixed crashing during "array set a(b) {}". +7/22/99 (bug fix) Fixed crashing during "array set a(b) {}". [Bug: 2427] (redman) 7/22/99 (bug fix) The install-sh script must be given execute @@ -4564,7 +4564,7 @@ pack-old.n [Bug: 2469]. Patches from Don Porter. (redman) 7/29/99 (bug fix) Allow tcl to open CON and NUL, even for redirection of std channels. [Bug: 2393 2392 2209 2458] (redman) -7/30/99 (bug fix) Applied fixed Trf patch from Andreas Kupries. +7/30/99 (bug fix) Applied fixed Trf patch from Andreas Kupries. [Bug: 2386] (hobbs) 7/30/99 (bug fix) Fixed bug in info complete. [Bug: 2383 2466] (hobbs) @@ -4574,7 +4574,7 @@ provided by James Dennett. [Bug: 2450] (redman) 7/30/99 (bug fix) Fixed launching of 16bit applications on Win9x from wish. The command line was being primed with tclpip82.dll, but it was -ignored later. +ignored later. 7/30/99 (bug fix) Added functions to stub table, patch provided by Jan Nijtmans. [Bug: 2445] (hobbs) @@ -4587,7 +4587,7 @@ thread's stack space. (redman) --------------- Released 8.2b2, August 5, 1999 ---------------------- 8/4/99 (bug fix) Applied patches supplied by Henry Spencer to greatly -enhance performance of certain classes of regular expressions. +enhance performance of certain classes of regular expressions. [Bug: 2440 2447] (stanton) 8/5/99 (doc change) Made it clear that tcl_pkgPath was not set for @@ -4601,7 +4601,7 @@ terminated in tclLiteral.c. [Bug: 2496] (hobbs) 8/9/99 (bug fix) Fixed test suite to handle larger integers (64bit). Patch from Don Porter. (hobbs) -8/9/99 (documentation fix) Clarified Tcl_DecrRefCount docs +8/9/99 (documentation fix) Clarified Tcl_DecrRefCount docs [Bug: 1952]. Clarified array pattern docs [Bug: 1330]. Fixed clock docs [Bug: 693]. Fixed formatting errors [Bug: 2188 2189]. Fixed doc error in tclvars.n [Bug: 2042]. (hobbs) @@ -4661,7 +4661,7 @@ and in testthread code. No more known (reported) mem leaks for Tcl built using gcc on Solaris 2.5.1. Also none reported for Tcl on NT (using Purify 6.0). (hobbs) -10/30/99 (bug fix) fixed improper bytecode handling of +10/30/99 (bug fix) fixed improper bytecode handling of 'eval {set array($unknownvar) 5}' (also for incr) (hobbs) 10/30/99 (bug fix) fixed event/io threading problems by making @@ -5115,7 +5115,7 @@ bits for Tcl_UniChar though) (hobbs) 2001-05-30 (new feature)[TIP 15] Tcl_GetMathFuncInfo, Tcl_ListMathFuncs, Tcl_InfoObjCmd, InfoFunctionsCmd APIs (fellows) -2001-06-08 (bug fix,feature enhancement)[219170,414936] all Tcl_Panic +2001-06-08 (bug fix,feature enhancement)[219170,414936] all Tcl_Panic definitions brought into agreement (porter) 2001-06-12 (bug fix)[219232] regexp returned non-matching sub-pairs to have @@ -5284,7 +5284,7 @@ compiles to 0 bytecodes (sofer) 2001-09-13 (new feature) Old ChangeLog entries => ChangeLog.1999 (hobbs) -2001-09-17 (new feature) compiling with TCL_COMPILE_DEBUG now required to +2001-09-17 (new feature) compiling with TCL_COMPILE_DEBUG now required to enable all compile and execution tracing (sofer) *** POTENTIAL INCOMPATIBILITY *** @@ -5566,7 +5566,7 @@ options to configure (max) 2002-07-30 (bug fix)[584603] WriteChars infinite loop non-UTF-8 string (kupries) -2002-08-04 (new feature)[584051,580433,585105,582429][TIP 27] Tcl interfaces +2002-08-04 (new feature)[584051,580433,585105,582429][TIP 27] Tcl interfaces are now fully CONST-ified. Use the symbols USE_NON_CONST or USE_COMPAT_CONST to select interfaces with fewer changes. *** POTENTIAL INCOMPATIBILITY *** @@ -5576,7 +5576,7 @@ options to configure (max) => tcltest 2.2 2002-08-07 (bug fix)[587488] mem leak with USE_THREAD_ALLOC (sofer,sass) - + 2002-08-07 (feature enhancement)[584794,584650,472576] boolean values are no longer always re-parsed from string. (sofer) @@ -5710,7 +5710,7 @@ packages in multiple interps. 2003-02-01 (bug fix)[675356] [clock clicks {}]; [clock clicks -] - syntax errs -2003-02-01 (bug fix)[656660] MT-safety for [clock format] +2003-02-01 (bug fix)[656660] MT-safety for [clock format] 2003-02-03 (bug fix)[651271] command rename traces get fully-qualified names *** POTENTIAL INCOMPATIBILITY *** @@ -5929,7 +5929,7 @@ various odd regexp "can't happen" bugs. 2003-12-09 (platform support)[852369] update errno usage for recent glibc -2003-12-12 (bug fix)[858937] fix for [file normalize ~nobody] +2003-12-12 (bug fix)[858937] fix for [file normalize ~nobody] 2003-12-17 (bug fix)[839519] fixed two memory leaks (vasiljevic) @@ -5944,7 +5944,7 @@ various odd regexp "can't happen" bugs. 2004-02-12 (feature enhancement) update HP-11 build libs setup -2004-02-17 (bug fix)[849514,859251] corrected [file normailze] of $link/.. +2004-02-17 (bug fix)[849514,859251] corrected [file normailze] of $link/.. 2004-02-17 (bug fix)[772288] Unix std channels forced to exist at startup. @@ -6037,7 +6037,7 @@ in this changeset (new minor version) rather than bug fixes: * [TIP #139] documented portions of Tcl's namespace C APIs * [TIP #148] correct [list]-quoting of the '#' character - *** POTENTIAL INCOMPATIBILITY *** + *** POTENTIAL INCOMPATIBILITY *** For scripts that assume a particular (buggy) string rep for lists. * [TIP #156] add "root locale" to msgcat @@ -6532,7 +6532,7 @@ Reduces the ***POTENTIAL INCOMPATIBILITY*** from 2005-05-17. 2005-07-22 (enhancement)[1237755] 8.4 features in script library (fradin,porter) -2005-07-24 (new feature) configure macros SC_PROG_TCLSH, SC_BUILD_TCLSH (dejong) +2005-07-24 (new feature) configure macros SC_PROG_TCLSH, SC_BUILD_TCLSH (dejong) 2005-07-26 (bug fix)[1047286] cmd delete traces during namespace delete (porter) 2005-07-26 (new unix feature)[1231015] ${prefix}/share on ::tcl_pkgPath (dejong) @@ -6627,7 +6627,7 @@ registered by [package ifneeded] provides the version it claims (lavana,porter) 2005-11-09 (bug fix)[1350293,1350291] [after $negative $script] fixed (kenny) -2005-11-12 (bug fix)[1352734,1354540,1355942,1355342] [namespace delete] +2005-11-12 (bug fix)[1352734,1354540,1355942,1355342] [namespace delete] issues with [namespace path] and command delete traces (sofer,fellows) 2005-11-18 (bug fix)[1358369] URL parsing standards compliance (wu,fellows) @@ -6756,7 +6756,7 @@ naked-fork safe on Tiger (steffen) 2006-06-20 (internal change) Dropped the internal routines used to hook into filesystem operations back in the pre-Tcl_Filesystem days. (porter) ***POTENTIAL INCOMPATIBILITY*** -For extensions and programs that have never migrated to the supported Tcl 8.4 +For extensions and programs that have never migrated to the supported Tcl 8.4 interface for virtual filesystems 2006-07-05 (enhancement) Expression parser rewrite avoids stack overflow, @@ -7603,7 +7603,7 @@ avoid otherwise very tricky multi-thread finalization bugs. (staplin,ferrieux) 2009-10-04 (bug fix)[2569449] Core Foundation memory bug in Tiger (steffen) -2009-10-06 (bug fix) repair intrep loss in slave interp evaluations +2009-10-06 (bug fix) repair intrep loss in slave interp evaluations introduced by first versions of the NRE conversion (nadkarni,porter) 2009-10-06 (bug fix)[1941434] broken tclTomMath.h includes (porter) @@ -7995,7 +7995,7 @@ like "nano()" instead of parsing as "nan o()" with missing op (duquette,porter) 2011-10-31 (bug fix)[3414754] EIAS violation in fs paths (porter) -2011-11-22 (bug fix)[2935503] Win: [file mtime] sets wrong time (nijtmans) +2011-11-22 (bug fix)[3354324] Win: [file mtime] sets wrong time (nijtmans) 2011-11-30 (bug fix)[967195] Simply args passed to child processes (nijtmans) => tcltest 2.3.4 @@ -8023,8 +8023,6 @@ like "nano()" instead of parsing as "nan o()" with missing op (duquette,porter) 2012-02-02 (bug fix)[2974459,2879351,1951574,1852572,1661378,1613456] Fix problems where [file *able] would return false results on Win/Samba (porter) -2012-02-02 (update)[3464401] Support Unicode 6.1 (nijtmans) - 2012-02-06 (bug fix)[3484621] bump bytecode epoch on exec traces (kuhn,sofer) 2012-02-15 (bug fix)[3487626] crash compiling [dict for] (fellows) @@ -8094,13 +8092,36 @@ problems where [file *able] would return false results on Win/Samba (porter) and Tcl_FSMountsChanged(). (porter) 2012-06-29 (bug fix)[3536888] fix locale guessing (oehlmann,nijtmans) -=> msgcat 1.4.5 2012-07-05 (bug fix)[1189293] make "<<" redirect binary safe (porter) 2012-07-08 (bug fix)[3531209] accept IPv6 URLs (max) => http 2.8.4 +2012-07-24 (bug fix) stop mem corruption in stacked channel events (max,porter) + +2012-07-25 (bug fix)[3546275] [auto_execok] search match [exec] (danckaert) + +2012-07-27 (update)[3464401] Support Unicode 6.2 (nijtmans) + +2012-08-20 (bug fix)[3559678] [file normalize] EIAS failure (phao,dgp) + +2012-08-25 (bug fix)[3561330] Ukranian translation of "March" (teterin) + +2012-09-07 (TIP 404) New msgcat commands [mcflset], [mcflmset] (oehlmann) +=> msgcat 1.5.0 + Many revisions to better support a Cygwin environment (nijtmans) ---- Released 8.6b3, July 30, 2012 --- See ChangeLog for details --- +Dropped support for OS X versions less than 10.4 (Tiger) (fellows) + +--- Released 8.6b3, September 18, 2012 --- See ChangeLog for details --- + +2012-10-03 (bug fix) exit panic on stacked std channel (griffin,porter) + +2012-10-14 (bug fix) [tcl::Bgerror] crash on non-dict options (nijtmans) + +2012-11-06 (bug fix)[3581754] avoid multiple callback on keep-alive (fellows) +=> http 2.8.5 + +--- Released 8.6.0, ??? ??, 2012 --- See ChangeLog for details --- diff --git a/compat/zlib/win32/zdll.lib b/compat/zlib/win32/zdll.lib Binary files differindex 4e53491..669b186 100644 --- a/compat/zlib/win32/zdll.lib +++ b/compat/zlib/win32/zdll.lib diff --git a/compat/zlib/win64/zdll.lib b/compat/zlib/win64/zdll.lib Binary files differnew file mode 100644 index 0000000..d7dfb09 --- /dev/null +++ b/compat/zlib/win64/zdll.lib diff --git a/compat/zlib/win64/zlib1.dll b/compat/zlib/win64/zlib1.dll Binary files differnew file mode 100644 index 0000000..631439b --- /dev/null +++ b/compat/zlib/win64/zlib1.dll diff --git a/doc/AddErrInfo.3 b/doc/AddErrInfo.3 index e450a3e..b9c6a63 100644 --- a/doc/AddErrInfo.3 +++ b/doc/AddErrInfo.3 @@ -107,7 +107,7 @@ with the value of \fIcode\fR. The \fB(Tcl_Obj *)\fR returned by \fBTcl_GetReturnOptions\fR points to an unshared \fBTcl_Obj\fR with reference count of zero. The dictionary may be written to, either adding, removing, or overwriting -any entries in it, without the need to check for a shared object. +any entries in it, without the need to check for a shared value. As with any \fBTcl_Obj\fR with reference count of zero, it is up to the caller to arrange for its disposal with \fBTcl_DecrRefCount\fR or to a reference to it via \fBTcl_IncrRefCount\fR (or one of the many @@ -232,7 +232,7 @@ the need for a null byte. If the \fBTcl_AddObjErrorInfo\fR interface is used at all, it should be with a negative \fIlength\fR value. .PP The procedure \fBTcl_SetObjErrorCode\fR is used to set the -\fB\-errorcode\fR return option to the list object \fIerrorObjPtr\fR +\fB\-errorcode\fR return option to the list value \fIerrorObjPtr\fR built up by the caller. \fBTcl_SetObjErrorCode\fR is typically invoked just before returning an error. If an error is @@ -242,7 +242,7 @@ the \fB\-errorcode\fR return option to \fBNONE\fR. .PP The procedure \fBTcl_SetErrorCode\fR is also used to set the \fB\-errorcode\fR return option. However, it takes one or more strings to -record instead of an object. Otherwise, it is similar to +record instead of a value. Otherwise, it is similar to \fBTcl_SetObjErrorCode\fR in behavior. .PP \fBTcl_SetErrorCodeVA\fR is the same as \fBTcl_SetErrorCode\fR except that @@ -309,4 +309,4 @@ most recent error seen in an interpreter. Tcl_DecrRefCount(3), Tcl_IncrRefCount(3), Tcl_Interp(3), Tcl_ResetResult(3), Tcl_SetErrno(3), tclvars(n) .SH KEYWORDS -error, object, object result, stack, trace, variable +error, value, value result, stack, trace, variable diff --git a/doc/BoolObj.3 b/doc/BoolObj.3 index 395d159..6691140 100644 --- a/doc/BoolObj.3 +++ b/doc/BoolObj.3 @@ -30,7 +30,7 @@ Points to the Tcl_Obj in which to store, or from which to retrieve a boolean value. .AP Tcl_Interp *interp in/out If a boolean value cannot be retrieved, -an error message is left in the interpreter's result object +an error message is left in the interpreter's result value unless \fIinterp\fR is NULL. .AP int *boolPtr out Points to place where \fBTcl_GetBooleanFromObj\fR @@ -92,4 +92,4 @@ a \fBTCL_ERROR\fR return. Tcl_NewObj, Tcl_IsShared, Tcl_GetBoolean .SH KEYWORDS -boolean, object +boolean, value diff --git a/doc/ByteArrObj.3 b/doc/ByteArrObj.3 index 77c94ac..2921f68 100644 --- a/doc/ByteArrObj.3 +++ b/doc/ByteArrObj.3 @@ -8,7 +8,7 @@ .TH Tcl_ByteArrayObj 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME -Tcl_NewByteArrayObj, Tcl_SetByteArrayObj, Tcl_GetByteArrayFromObj, Tcl_SetByteArrayLength \- manipulate Tcl objects as a arrays of bytes +Tcl_NewByteArrayObj, Tcl_SetByteArrayObj, Tcl_GetByteArrayFromObj, Tcl_SetByteArrayLength \- manipulate Tcl values as a arrays of bytes .SH SYNOPSIS .nf \fB#include <tcl.h>\fR @@ -27,65 +27,65 @@ unsigned char * .SH ARGUMENTS .AS "const unsigned char" *lengthPtr in/out .AP "const unsigned char" *bytes in -The array of bytes used to initialize or set a byte-array object. May be NULL +The array of bytes used to initialize or set a byte-array value. May be NULL even if \fIlength\fR is non-zero. .AP int length in The length of the array of bytes. It must be >= 0. .AP Tcl_Obj *objPtr in/out -For \fBTcl_SetByteArrayObj\fR, this points to the object to be converted to +For \fBTcl_SetByteArrayObj\fR, this points to the value to be converted to byte-array type. For \fBTcl_GetByteArrayFromObj\fR and -\fBTcl_SetByteArrayLength\fR, this points to the object from which to get +\fBTcl_SetByteArrayLength\fR, this points to the value from which to get the byte-array value; if \fIobjPtr\fR does not already point to a byte-array -object, it will be converted to one. +value, it will be converted to one. .AP int *lengthPtr out -If non-NULL, filled with the length of the array of bytes in the object. +If non-NULL, filled with the length of the array of bytes in the value. .BE .SH DESCRIPTION .PP -These procedures are used to create, modify, and read Tcl byte-array objects -from C code. Byte-array objects are typically used to hold the +These procedures are used to create, modify, and read Tcl byte-array values +from C code. Byte-array values are typically used to hold the results of binary IO operations or data structures created with the \fBbinary\fR command. In Tcl, an array of bytes is not equivalent to a string. Conceptually, a string is an array of Unicode characters, while a byte-array is an array of 8-bit quantities with no implicit meaning. Accessor functions are provided to get the string representation of a -byte-array or to convert an arbitrary object to a byte-array. Obtaining the -string representation of a byte-array object (by calling +byte-array or to convert an arbitrary value to a byte-array. Obtaining the +string representation of a byte-array value (by calling \fBTcl_GetStringFromObj\fR) produces a properly formed UTF-8 sequence with a one-to-one mapping between the bytes in the internal representation and the UTF-8 characters in the string representation. .PP \fBTcl_NewByteArrayObj\fR and \fBTcl_SetByteArrayObj\fR will -create a new object of byte-array type or modify an existing object to have a -byte-array type. Both of these procedures set the object's type to be -byte-array and set the object's internal representation to a copy of the +create a new value of byte-array type or modify an existing value to have a +byte-array type. Both of these procedures set the value's type to be +byte-array and set the value's internal representation to a copy of the array of bytes given by \fIbytes\fR. \fBTcl_NewByteArrayObj\fR returns a -pointer to a newly allocated object with a reference count of zero. +pointer to a newly allocated value with a reference count of zero. \fBTcl_SetByteArrayObj\fR invalidates any old string representation and, if -the object is not already a byte-array object, frees any old internal +the value is not already a byte-array value, frees any old internal representation. If \fIbytes\fR is NULL then the new byte array contains arbitrary values. .PP -\fBTcl_GetByteArrayFromObj\fR converts a Tcl object to byte-array type and -returns a pointer to the object's new internal representation as an array of +\fBTcl_GetByteArrayFromObj\fR converts a Tcl value to byte-array type and +returns a pointer to the value's new internal representation as an array of bytes. The length of this array is stored in \fIlengthPtr\fR if \fIlengthPtr\fR is non-NULL. The storage for the array of bytes is owned by -the object and should not be freed. The contents of the array may be -modified by the caller only if the object is not shared and the caller +the value and should not be freed. The contents of the array may be +modified by the caller only if the value is not shared and the caller invalidates the string representation. .PP -\fBTcl_SetByteArrayLength\fR converts the Tcl object to byte-array type -and changes the length of the object's internal representation as an +\fBTcl_SetByteArrayLength\fR converts the Tcl value to byte-array type +and changes the length of the value's internal representation as an array of bytes. If \fIlength\fR is greater than the space currently allocated for the array, the array is reallocated to the new length; the newly allocated bytes at the end of the array have arbitrary values. If \fIlength\fR is less than the space currently allocated for the array, the length of array is reduced to the new length. The return value is a -pointer to the object's new array of bytes. +pointer to the value's new array of bytes. .SH "SEE ALSO" Tcl_GetStringFromObj, Tcl_NewObj, Tcl_IncrRefCount, Tcl_DecrRefCount .SH KEYWORDS -object, byte array, utf, unicode, internationalization +value, binary data, byte array, utf, unicode, internationalization diff --git a/doc/CrtChannel.3 b/doc/CrtChannel.3 index 478ef0b..55a4024 100644 --- a/doc/CrtChannel.3 +++ b/doc/CrtChannel.3 @@ -846,7 +846,7 @@ the generic options error message string. .PP It always returns \fBTCL_ERROR\fR .PP -An error message is generated in \fIinterp\fR's result object to +An error message is generated in \fIinterp\fR's result value to indicate that a command was invoked with a bad option. The message has the form .CS diff --git a/doc/CrtCommand.3 b/doc/CrtCommand.3 index f0a7b43..c921999 100644 --- a/doc/CrtCommand.3 +++ b/doc/CrtCommand.3 @@ -41,18 +41,18 @@ will call \fIproc\fR to process the command. It differs from \fBTcl_CreateObjCommand\fR in that a new string-based command is defined; that is, a command procedure is defined that takes an array of -argument strings instead of objects. -The object-based command procedures registered by \fBTcl_CreateObjCommand\fR +argument strings instead of values. +The value-based command procedures registered by \fBTcl_CreateObjCommand\fR can execute significantly faster than the string-based command procedures defined by \fBTcl_CreateCommand\fR. -This is because they take Tcl objects as arguments -and those objects can retain an internal representation that +This is because they take Tcl values as arguments +and those values can retain an internal representation that can be manipulated more efficiently. -Also, Tcl's interpreter now uses objects internally. +Also, Tcl's interpreter now uses values internally. In order to invoke a string-based command procedure registered by \fBTcl_CreateCommand\fR, it must generate and fetch a string representation -from each argument object before the call. +from each argument value before the call. New commands should be defined using \fBTcl_CreateObjCommand\fR. We support \fBTcl_CreateCommand\fR for backwards compatibility. .PP diff --git a/doc/CrtMathFnc.3 b/doc/CrtMathFnc.3 index 3f2c84e..cdde20b 100644 --- a/doc/CrtMathFnc.3 +++ b/doc/CrtMathFnc.3 @@ -10,6 +10,13 @@ .BS .SH NAME Tcl_CreateMathFunc, Tcl_GetMathFuncInfo, Tcl_ListMathFuncs \- Define, query and enumerate math functions for expressions +.SH "NOTICE OF EVENTUAL DEPRECATION" +.PP +The \fBTcl_CreateMathFunc\fR and \fBTcl_GetMathFuncInfo\fR functions +are rendered somewhat obsolete by the ability to create functions for +expressions by placing commands in the \fBtcl::mathfunc\fR namespace, +as described in the \fBmathfunc\fR manual page; the API described on +this page is not expected to be maintained indefinitely. .SH SYNOPSIS .nf \fB#include <tcl.h>\fR @@ -146,9 +153,9 @@ will not be modified. The variable pointed to by \fInumArgsPointer\fR will contain -1, and no argument types will be stored in the variable pointed to by \fIargTypesPointer\fR. .PP -\fBTcl_ListMathFuncs\fR returns a Tcl object containing a list of all +\fBTcl_ListMathFuncs\fR returns a Tcl value containing a list of all the math functions defined in the interpreter whose name matches -\fIpattern\fR. The returned object has a reference count of zero. +\fIpattern\fR. The returned value has a reference count of zero. .SH "SEE ALSO" expr(n), info(n), Tcl_CreateObjCommand(3), Tcl_Free(3), Tcl_NewListObj(3) .SH KEYWORDS diff --git a/doc/CrtObjCmd.3 b/doc/CrtObjCmd.3 index 343b3dd..faf8b74 100644 --- a/doc/CrtObjCmd.3 +++ b/doc/CrtObjCmd.3 @@ -64,7 +64,7 @@ The command must not have been deleted. Pointer to structure containing various information about a Tcl command. .AP Tcl_Obj *objPtr in -Object containing the name of a Tcl command. +Value containing the name of a Tcl command. .BE .SH DESCRIPTION .PP @@ -102,10 +102,10 @@ will be copies of the \fIclientData\fR and \fIinterp\fR arguments given to \fBTcl_CreateObjCommand\fR. Typically, \fIclientData\fR points to an application-specific data structure that describes what to do when the command procedure is invoked. \fIObjc\fR and \fIobjv\fR describe the -arguments to the command, \fIobjc\fR giving the number of argument objects +arguments to the command, \fIobjc\fR giving the number of argument values (including the command name) and \fIobjv\fR giving the values of the arguments. The \fIobjv\fR array will contain \fIobjc\fR values, pointing to -the argument objects. Unlike \fIargv\fR[\fIargv\fR] used in a +the argument values. Unlike \fIargv\fR[\fIargv\fR] used in a string-based command procedure, \fIobjv\fR[\fIobjc\fR] will not contain NULL. .PP Additionally, when \fIproc\fR is invoked, it must not modify the contents @@ -115,9 +115,9 @@ cause memory to be lost and the runtime stack to be corrupted. The \fBconst\fR in the declaration of \fIobjv\fR will cause ANSI-compliant compilers to report any such attempted assignment as an error. However, it is acceptable to modify the internal representation of any individual -object argument. For instance, the user may call +value argument. For instance, the user may call \fBTcl_GetIntFromObj\fR on \fIobjv\fR[\fB2\fR] to obtain the integer -representation of that object; that call may change the type of the object +representation of that value; that call may change the type of the value that \fIobjv\fR[\fB2\fR] points at, but will not change where \fIobjv\fR[\fB2\fR] points. .PP @@ -133,7 +133,7 @@ of the command, and in the case of \fBTCL_ERROR\fR this gives an error message. Before invoking a command procedure, \fBTcl_EvalObjEx\fR sets interpreter's result to -point to an object representing an empty string, so simple +point to a value representing an empty string, so simple commands can return an empty result by doing nothing at all. .PP The contents of the \fIobjv\fR array belong to Tcl and are not @@ -225,7 +225,7 @@ if \fIisNativeObjectProc\fR has the value 1. The fields \fIobjProc\fR and \fIobjClientData\fR have the same meaning as the \fIproc\fR and \fIclientData\fR arguments to \fBTcl_CreateObjCommand\fR; -they hold information about the object-based command procedure +they hold information about the value-based command procedure that the Tcl interpreter calls to implement the command. The fields \fIproc\fR and \fIclientData\fR hold information about the string-based command procedure @@ -235,7 +235,7 @@ this is the procedure passed to it; otherwise, this is a compatibility procedure registered by \fBTcl_CreateObjCommand\fR that simply calls the command's -object-based procedure after converting its string arguments to Tcl objects. +value-based procedure after converting its string arguments to Tcl values. The field \fIdeleteData\fR is the ClientData value to pass to \fIdeleteProc\fR; it is normally the same as \fIclientData\fR but may be set independently using the @@ -290,7 +290,7 @@ they need to keep it for a long time. \fBTcl_GetCommandFullName\fR produces the fully qualified name of a command from a command token. The name, including all namespace prefixes, -is appended to the object specified by \fIobjPtr\fR. +is appended to the value specified by \fIobjPtr\fR. .PP \fBTcl_GetCommandFromObj\fR returns a token for the command specified by the name in a \fBTcl_Obj\fR. @@ -299,4 +299,4 @@ Returns NULL if the command is not found. .SH "SEE ALSO" Tcl_CreateCommand(3), Tcl_ResetResult(3), Tcl_SetObjResult(3) .SH KEYWORDS -bind, command, create, delete, namespace, object +bind, command, create, delete, namespace, value diff --git a/doc/CrtSlave.3 b/doc/CrtSlave.3 index 3863373..000ae58 100644 --- a/doc/CrtSlave.3 +++ b/doc/CrtSlave.3 @@ -78,10 +78,10 @@ Count of additional arguments to pass to the alias command. Vector of strings, the additional arguments to pass to the alias command. This storage is owned by the caller. .AP int objc in -Count of additional object arguments to pass to the alias object command. +Count of additional value arguments to pass to the aliased command. .AP Tcl_Obj **objv in -Vector of Tcl_Obj structures, the additional object arguments to pass to -the alias object command. +Vector of Tcl_Obj structures, the additional value arguments to pass to +the aliased command. This storage is owned by the caller. .AP Tcl_Interp **targetInterpPtr in Pointer to location to store the address of the interpreter where a target @@ -97,11 +97,11 @@ Pointer to location to store a vector of strings, the additional arguments to pass to an alias. The location is in storage owned by the caller, the vector of strings is owned by the called function. .AP int *objcPtr out -Pointer to location to store count of additional object arguments to be +Pointer to location to store count of additional value arguments to be passed to the alias. The location is in storage owned by the caller. .AP Tcl_Obj ***objvPtr out Pointer to location to store a vector of Tcl_Obj structures, the additional -arguments to pass to an object alias command. The location is in storage +arguments to pass to an alias command. The location is in storage owned by the caller, the vector of Tcl_Obj structures is owned by the called function. .AP "const char" *cmdName in @@ -165,13 +165,13 @@ of the relative path succeeds, \fBTCL_OK\fR is returned, else \fBTCL_ERROR\fR is returned and the \fIresult\fR field in \fIaskingInterp\fR contains the error message. .PP -\fBTcl_CreateAlias\fR creates an object command named \fIslaveCmd\fR in +\fBTcl_CreateAlias\fR creates a command named \fIslaveCmd\fR in \fIslaveInterp\fR that when invoked, will cause the command \fItargetCmd\fR to be invoked in \fItargetInterp\fR. The arguments specified by the strings contained in \fIargv\fR are always prepended to any arguments supplied in the invocation of \fIslaveCmd\fR and passed to \fItargetCmd\fR. This operation returns \fBTCL_OK\fR if it succeeds, or \fBTCL_ERROR\fR if -it fails; in that case, an error message is left in the object result +it fails; in that case, an error message is left in the value result of \fIslaveInterp\fR. Note that there are no restrictions on the ancestry relationship (as created by \fBTcl_CreateSlave\fR) between \fIslaveInterp\fR and @@ -179,7 +179,7 @@ created by \fBTcl_CreateSlave\fR) between \fIslaveInterp\fR and restrictions on how they are related. .PP \fBTcl_CreateAliasObj\fR is similar to \fBTcl_CreateAlias\fR except -that it takes a vector of objects to pass as additional arguments instead +that it takes a vector of values to pass as additional arguments instead of a vector of strings. .PP \fBTcl_GetAlias\fR returns information about an alias \fIaliasName\fR @@ -202,7 +202,7 @@ command, or the operation will return \fBTCL_ERROR\fR and leave an error message in the \fIresult\fR field in \fIinterp\fR. If an exposed command named \fIcmdName\fR already exists, the operation returns \fBTCL_ERROR\fR and leaves an error message in the -object result of \fIinterp\fR. +value result of \fIinterp\fR. If the operation succeeds, it returns \fBTCL_OK\fR. After executing this command, attempts to use \fIcmdName\fR in a call to \fBTcl_Eval\fR or with the Tcl \fBeval\fR command will again succeed. @@ -212,10 +212,10 @@ exposed commands to the set of hidden commands, under the name \fIhiddenCmdName\fR. \fICmdName\fR must be the name of an existing exposed command, or the operation will return \fBTCL_ERROR\fR and leave an error -message in the object result of \fIinterp\fR. +message in the value result of \fIinterp\fR. Currently both \fIcmdName\fR and \fIhiddenCmdName\fR must not contain namespace qualifiers, or the operation will return \fBTCL_ERROR\fR and -leave an error message in the object result of \fIinterp\fR. +leave an error message in the value result of \fIinterp\fR. The \fICmdName\fR will be looked up in the global namespace, and not relative to the current namespace, even if the current namespace is not the global one. diff --git a/doc/DictObj.3 b/doc/DictObj.3 index a5dc9e5..db8f39a 100644 --- a/doc/DictObj.3 +++ b/doc/DictObj.3 @@ -9,7 +9,7 @@ .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME -Tcl_NewDictObj, Tcl_DictObjPut, Tcl_DictObjGet, Tcl_DictObjRemove, Tcl_DictObjSize, Tcl_DictObjFirst, Tcl_DictObjNext, Tcl_DictObjDone, Tcl_DictObjPutKeyList, Tcl_DictObjRemoveKeyList \- manipulate Tcl objects as dictionaries +Tcl_NewDictObj, Tcl_DictObjPut, Tcl_DictObjGet, Tcl_DictObjRemove, Tcl_DictObjSize, Tcl_DictObjFirst, Tcl_DictObjNext, Tcl_DictObjDone, Tcl_DictObjPutKeyList, Tcl_DictObjRemoveKeyList \- manipulate Tcl values as dictionaries .SH SYNOPSIS .nf \fB#include <tcl.h>\fR @@ -47,23 +47,23 @@ int .SH ARGUMENTS .AS Tcl_DictSearch "**valuePtrPtr" in/out .AP Tcl_Interp *interp in -If an error occurs while converting an object to be a dictionary object, -an error message is left in the interpreter's result object +If an error occurs while converting a value to be a dictionary value, +an error message is left in the interpreter's result value unless \fIinterp\fR is NULL. .AP Tcl_Obj *dictPtr in/out -Points to the dictionary object to be manipulated. -If \fIdictPtr\fR does not already point to a dictionary object, +Points to the dictionary value to be manipulated. +If \fIdictPtr\fR does not already point to a dictionary value, an attempt will be made to convert it to one. .AP Tcl_Obj *keyPtr in Points to the key for the key/value pair being manipulated within the -dictionary object. +dictionary value. .AP Tcl_Obj **keyPtrPtr out Points to a variable that will have the key from a key/value pair placed within it. May be NULL to indicate that the caller is not interested in the key. .AP Tcl_Obj *valuePtr in Points to the value for the key/value pair being manipulated within the -dictionary object (or sub-object, in the case of +dictionary value (or sub-value, in the case of \fBTcl_DictObjPutKeyList\fR.) .AP Tcl_Obj **valuePtrPtr out Points to a variable that will have the value from a key/value pair @@ -88,15 +88,15 @@ completed, and a zero otherwise. Indicates the number of keys that will be supplied in the \fIkeyv\fR array. .AP "Tcl_Obj *const" *keyv in -Array of \fIkeyc\fR pointers to objects that +Array of \fIkeyc\fR pointers to values that \fBTcl_DictObjPutKeyList\fR and \fBTcl_DictObjRemoveKeyList\fR will use to locate the key/value pair to manipulate within the -sub-dictionaries of the main dictionary object passed to them. +sub-dictionaries of the main dictionary value passed to them. .BE .SH DESCRIPTION .PP -Tcl dictionary objects have an internal representation that supports +Tcl dictionary values have an internal representation that supports efficient mapping from keys to values and which guarantees that the particular ordering of keys within the dictionary remains the same modulo any keys being deleted (which removes them from the order) or @@ -106,11 +106,11 @@ keys of the dictionary, and each will be followed (in the odd-valued index) by the value associated with that key. .PP The procedures described in this man page are used to -create, modify, index, and iterate over dictionary objects from C code. +create, modify, index, and iterate over dictionary values from C code. .PP -\fBTcl_NewDictObj\fR creates a new, empty dictionary object. The -string representation of the object will be invalid, and the reference -count of the object will be zero. +\fBTcl_NewDictObj\fR creates a new, empty dictionary value. The +string representation of the value will be invalid, and the reference +count of the value will be zero. .PP \fBTcl_DictObjGet\fR looks up the given key within the given dictionary and writes a pointer to the value associated with that key @@ -217,7 +217,7 @@ if (\fBTcl_DictObjFirst\fR(interp, objPtr, &search, for (; !done ; \fBTcl_DictObjNext\fR(&search, &key, &value, &done)) { /* * Note that strcmp() is not a good way of comparing - * objects and is just used here for demonstration + * values and is just used here for demonstration * purposes. */ if (!strcmp(Tcl_GetString(key), Tcl_GetString(value))) { @@ -231,4 +231,4 @@ return TCL_OK; .SH "SEE ALSO" Tcl_NewObj, Tcl_DecrRefCount, Tcl_IncrRefCount, Tcl_InitObjHashTable .SH KEYWORDS -dict, dict object, dictionary, dictionary object, hash table, iteration, object +dict, dict value, dictionary, dictionary value, hash table, iteration, value diff --git a/doc/DoubleObj.3 b/doc/DoubleObj.3 index 12818b0..f811c89 100644 --- a/doc/DoubleObj.3 +++ b/doc/DoubleObj.3 @@ -8,7 +8,7 @@ .TH Tcl_DoubleObj 3 8.0 Tcl "Tcl Library Procedures" .BS .SH NAME -Tcl_NewDoubleObj, Tcl_SetDoubleObj, Tcl_GetDoubleFromObj \- manipulate Tcl objects as floating-point values +Tcl_NewDoubleObj, Tcl_SetDoubleObj, Tcl_GetDoubleFromObj \- manipulate Tcl values as floating-point values .SH SYNOPSIS .nf \fB#include <tcl.h>\fR @@ -23,11 +23,11 @@ int .SH ARGUMENTS .AS Tcl_Interp doubleValue in/out .AP double doubleValue in -A double-precision floating-point value used to initialize or set a Tcl object. +A double-precision floating-point value used to initialize or set a Tcl value. .AP Tcl_Obj *objPtr in/out -For \fBTcl_SetDoubleObj\fR, this points to the object in which to store a +For \fBTcl_SetDoubleObj\fR, this points to the value in which to store a double value. -For \fBTcl_GetDoubleFromObj\fR, this refers to the object +For \fBTcl_GetDoubleFromObj\fR, this refers to the value from which to retrieve a double value. .AP Tcl_Interp *interp in/out When non-NULL, an error message is left here when double value retrieval fails. @@ -37,21 +37,21 @@ Points to place to store the double value obtained from \fIobjPtr\fR. .SH DESCRIPTION .PP -These procedures are used to create, modify, and read Tcl objects that +These procedures are used to create, modify, and read Tcl values that hold double-precision floating-point values. .PP -\fBTcl_NewDoubleObj\fR creates and returns a new Tcl object initialized to -the double value \fIdoubleValue\fR. The returned Tcl object is unshared. +\fBTcl_NewDoubleObj\fR creates and returns a new Tcl value initialized to +the double value \fIdoubleValue\fR. The returned Tcl value is unshared. .PP -\fBTcl_SetDoubleObj\fR sets the value of an existing Tcl object pointed to +\fBTcl_SetDoubleObj\fR sets the value of an existing Tcl value pointed to by \fIobjPtr\fR to the double value \fIdoubleValue\fR. The \fIobjPtr\fR -argument must point to an unshared Tcl object. Any attempt to set the value -of a shared Tcl object violates Tcl's copy-on-write policy. Any existing -string representation or internal representation in the unshared Tcl object +argument must point to an unshared Tcl value. Any attempt to set the value +of a shared Tcl value violates Tcl's copy-on-write policy. Any existing +string representation or internal representation in the unshared Tcl value will be freed as a consequence of setting the new value. .PP \fBTcl_GetDoubleFromObj\fR attempts to retrieve a double value from the -Tcl object \fIobjPtr\fR. If the attempt succeeds, then \fBTCL_OK\fR is +Tcl value \fIobjPtr\fR. If the attempt succeeds, then \fBTCL_OK\fR is returned, and the double value is written to the storage pointed to by \fIdoublePtr\fR. If the attempt fails, then \fBTCL_ERROR\fR is returned, and if \fIinterp\fR is non-NULL, an error message is left in \fIinterp\fR. @@ -61,4 +61,4 @@ calls to \fBTcl_GetDoubleFromObj\fR more efficient. .SH "SEE ALSO" Tcl_NewObj, Tcl_DecrRefCount, Tcl_IncrRefCount, Tcl_GetObjResult .SH KEYWORDS -double, double object, double type, internal representation, object, object type, string representation +double, double value, double type, internal representation, value, value type, string representation @@ -47,17 +47,17 @@ int Interpreter in which to execute the script. The interpreter's result is modified to hold the result or error message from the script. .AP Tcl_Obj *objPtr in -A Tcl object containing the script to execute. +A Tcl value containing the script to execute. .AP int flags in ORed combination of flag bits that specify additional options. \fBTCL_EVAL_GLOBAL\fR and \fBTCL_EVAL_DIRECT\fR are currently supported. .AP "const char" *fileName in Name of a file containing a Tcl script. .AP int objc in -The number of objects in the array pointed to by \fIobjPtr\fR; +The number of values in the array pointed to by \fIobjPtr\fR; this is also the number of words in the command. .AP Tcl_Obj **objv in -Points to an array of pointers to objects; each object holds the +Points to an array of pointers to values; each value holds the value of a single word in the command to execute. .AP int numBytes in The number of bytes in \fIscript\fR, not including any @@ -83,7 +83,7 @@ If this is the first time \fIobjPtr\fR has been executed, its commands are compiled into bytecode instructions which are then executed. The bytecodes are saved in \fIobjPtr\fR so that the compilation step -can be skipped if the object is evaluated again in the future. +can be skipped if the value is evaluated again in the future. .PP The return value from \fBTcl_EvalObjEx\fR (and all the other procedures described here) is a Tcl completion code with @@ -111,15 +111,15 @@ which will be safely substituted by the Tcl interpreter into .PP \fBTcl_EvalObjv\fR executes a single pre-parsed command instead of a script. The \fIobjc\fR and \fIobjv\fR arguments contain the values -of the words for the Tcl command, one word in each object in +of the words for the Tcl command, one word in each value in \fIobjv\fR. \fBTcl_EvalObjv\fR evaluates the command and returns a completion code and result just like \fBTcl_EvalObjEx\fR. The caller of \fBTcl_EvalObjv\fR has to manage the reference count of the -elements of \fIobjv\fR, insuring that the objects are valid until +elements of \fIobjv\fR, insuring that the values are valid until \fBTcl_EvalObjv\fR returns. .PP \fBTcl_Eval\fR is similar to \fBTcl_EvalObjEx\fR except that the script to -be executed is supplied as a string instead of an object and no compilation +be executed is supplied as a string instead of a value and no compilation occurs. The string should be a proper UTF-8 string as converted by \fBTcl_ExternalToUtfDString\fR or \fBTcl_ExternalToUtf\fR when it is known to possibly contain upper ASCII characters whose possible combinations @@ -129,7 +129,7 @@ bytecodes. In situations where it is known that the script will never be executed again, \fBTcl_Eval\fR may be faster than \fBTcl_EvalObjEx\fR. \fBTcl_Eval\fR returns a completion code and result just like \fBTcl_EvalObjEx\fR. Note: for backward compatibility with versions before -Tcl 8.0, \fBTcl_Eval\fR copies the object result in \fIinterp\fR to +Tcl 8.0, \fBTcl_Eval\fR copies the value result in \fIinterp\fR to \fIinterp->result\fR (use is deprecated) where it can be accessed directly. This makes \fBTcl_Eval\fR somewhat slower than \fBTcl_EvalEx\fR, which does not do the copy. @@ -170,7 +170,7 @@ other procedures. If this flag bit is set, the script is not compiled to bytecodes; instead it is executed directly as is done by \fBTcl_EvalEx\fR. The \fBTCL_EVAL_DIRECT\fR flag is useful in situations where the -contents of an object are going to change immediately, so the +contents of a value are going to change immediately, so the bytecodes will not be reused in a future execution. In this case, it is faster to execute the script directly. .TP 23 @@ -208,4 +208,4 @@ This means that top-level applications should never see a return code from \fBTcl_EvalObjEx\fR other then \fBTCL_OK\fR or \fBTCL_ERROR\fR. .SH KEYWORDS -execute, file, global, object, result, script +execute, file, global, result, script, value diff --git a/doc/ExprLong.3 b/doc/ExprLong.3 index ef93284..4fa972e 100644 --- a/doc/ExprLong.3 +++ b/doc/ExprLong.3 @@ -49,11 +49,11 @@ given by the \fIexpr\fR argument and return the result in one of four different forms. The expression can have any of the forms accepted by the \fBexpr\fR command. Note that these procedures have been largely replaced by the -object-based procedures \fBTcl_ExprLongObj\fR, \fBTcl_ExprDoubleObj\fR, +value-based procedures \fBTcl_ExprLongObj\fR, \fBTcl_ExprDoubleObj\fR, \fBTcl_ExprBooleanObj\fR, and \fBTcl_ExprObj\fR. -Those object-based procedures evaluate an expression held in a Tcl object +Those value-based procedures evaluate an expression held in a Tcl value instead of a string. -The object argument can retain an internal representation +The value argument can retain an internal representation that is more efficient to execute. .PP The \fIinterp\fR argument refers to an interpreter used to @@ -103,4 +103,4 @@ string stored in the interpreter's result. Tcl_ExprLongObj, Tcl_ExprDoubleObj, Tcl_ExprBooleanObj, Tcl_ExprObj .SH KEYWORDS -boolean, double, evaluate, expression, integer, object, string +boolean, double, evaluate, expression, integer, value, string diff --git a/doc/ExprLongObj.3 b/doc/ExprLongObj.3 index c8a564d..686c1cb 100644 --- a/doc/ExprLongObj.3 +++ b/doc/ExprLongObj.3 @@ -29,7 +29,7 @@ int .AP Tcl_Interp *interp in Interpreter in whose context to evaluate \fIobjPtr\fR. .AP Tcl_Obj *objPtr in -Pointer to an object containing the expression to evaluate. +Pointer to a value containing the expression to evaluate. .AP long *longPtr out Pointer to location in which to store the integer value of the expression. @@ -40,7 +40,7 @@ expression. Pointer to location in which to store the 0/1 boolean value of the expression. .AP Tcl_Obj **resultPtrPtr out -Pointer to location in which to store a pointer to the object +Pointer to location in which to store a pointer to the value that is the result of the expression. .BE @@ -93,14 +93,14 @@ or or else an error occurs. .PP If \fBTcl_ExprObj\fR successfully evaluates the expression, -it stores a pointer to the Tcl object +it stores a pointer to the Tcl value containing the expression's value at \fI*resultPtrPtr\fR. In this case, the caller is responsible for calling -\fBTcl_DecrRefCount\fR to decrement the object's reference count -when it is finished with the object. +\fBTcl_DecrRefCount\fR to decrement the value's reference count +when it is finished with the value. .SH "SEE ALSO" Tcl_ExprLong, Tcl_ExprDouble, Tcl_ExprBoolean, Tcl_ExprString, Tcl_GetObjResult .SH KEYWORDS -boolean, double, evaluate, expression, integer, object, string +boolean, double, evaluate, expression, integer, value, string diff --git a/doc/FileSystem.3 b/doc/FileSystem.3 index d7198b1..dd9eb77 100644 --- a/doc/FileSystem.3 +++ b/doc/FileSystem.3 @@ -86,7 +86,7 @@ int int \fBTcl_FSFileAttrsSet\fR(\fIinterp, int index, pathPtr, Tcl_Obj *objPtr\fR) .sp -const char ** +const char *const * \fBTcl_FSFileAttrStrings\fR(\fIpathPtr, objPtrRef\fR) .sp int @@ -192,8 +192,8 @@ int Points to a structure containing the addresses of procedures that can be called to perform the various filesystem operations. .AP Tcl_Obj *pathPtr in -The path represented by this object is used for the operation in -question. If the object does not already have an internal \fBpath\fR +The path represented by this value is used for the operation in +question. If the value does not already have an internal \fBpath\fR representation, it will be converted to have one. .AP Tcl_Obj *srcPathPtr in As for \fIpathPtr\fR, but used for the source file for a copy or @@ -213,12 +213,12 @@ this structure will be returned. This parameter may be NULL. Interpreter to use either for results, evaluation, or reporting error messages. .AP ClientData clientData in -The native description of the path object to create. +The native description of the path value to create. .AP Tcl_Obj *firstPtr in -The first of two path objects to compare. The object may be converted +The first of two path values to compare. The value may be converted to \fBpath\fR type. .AP Tcl_Obj *secondPtr in -The second of two path objects to compare. The object may be converted +The second of two path values to compare. The value may be converted to \fBpath\fR type. .AP Tcl_Obj *listObj in The list of path elements to operate on with a \fBjoin\fR operation. @@ -226,12 +226,12 @@ The list of path elements to operate on with a \fBjoin\fR operation. If non-negative, the number of elements in the \fIlistObj\fR which should be joined together. If negative, then all elements are joined. .AP Tcl_Obj **errorPtr out -In the case of an error, filled with an object containing the name of +In the case of an error, filled with a value containing the name of the file which caused an error in the various copy/rename operations. .AP Tcl_Obj **objPtrRef out -Filled with an object containing the result of the operation. +Filled with a value containing the result of the operation. .AP Tcl_Obj *resultPtr out -Pre-allocated object in which to store (using +Pre-allocated value in which to store (using \fBTcl_ListObjAppendElement\fR) the list of files or directories which are successfully matched. .AP int mode in @@ -331,17 +331,17 @@ buffer is actually declared to be, allowing the same code to be used both on systems with and systems without support for files larger than 2GB in size. .PP -The \fBTcl_FS\fR API is objectified and may cache internal +The \fBTcl_FS\fR API is \fBTcl_Obj\fR-ified and may cache internal representations and other path-related strings (e.g.\ the current working -directory). One side-effect of this is that one must not pass in objects +directory). One side-effect of this is that one must not pass in values with a reference count of zero to any of these functions. If such calls were handled, they might result in memory leaks (under some circumstances, the filesystem code may wish -to retain a reference to the passed in object, and so one must not assume -that after any of these calls return, the object still has a reference count of +to retain a reference to the passed in value, and so one must not assume +that after any of these calls return, the value still has a reference count of zero - it may have been incremented) or in a direct segmentation fault (or other memory access error) -due to the object being freed part way through the complex object +due to the value being freed part way through the complex value manipulation required to ensure that the path is fully normalized and absolute for filesystem determination. The practical lesson to learn from this is that @@ -354,9 +354,9 @@ Tcl_DecrRefCount(path); .PP is wrong, and may cause memory errors. The \fIpath\fR must have its reference count incremented before passing it in, or -decrementing it. For this reason, objects with a reference count of zero are +decrementing it. For this reason, values with a reference count of zero are considered not to be valid filesystem paths and calling any Tcl_FS API -function with such an object will result in no action being taken. +function with such a value will result in no action being taken. .SS "FS API FUNCTIONS" \fBTcl_FSCopyFile\fR attempts to copy the file given by \fIsrcPathPtr\fR to the path name given by \fIdestPathPtr\fR. If the two paths given lie in the same @@ -484,7 +484,7 @@ If the \fItoPtr\fR is NULL, a action is performed. The result is a Tcl_Obj specifying the contents of the symbolic link given by \fIlinkNamePtr\fR, or NULL if the link could not be read. The result is owned -by the caller, which should call Tcl_DecrRefCount when the result is no +by the caller, which should call \fBTcl_DecrRefCount\fR when the result is no longer needed. If the \fItoPtr\fR is not NULL, Tcl should create a link of one of the types passed in in the \fIlinkAction\fR flag. This flag is an ORed combination of \fBTCL_CREATE_SYMBOLIC_LINK\fR and \fBTCL_CREATE_HARD_LINK\fR. @@ -523,7 +523,7 @@ values of the file given. attributes\fR subcommand. The appropriate function for the filesystem to which \fIpathPtr\fR belongs will be called. .PP -If the result is \fBTCL_OK\fR, then an object was placed in +If the result is \fBTCL_OK\fR, then a value was placed in \fIobjPtrRef\fR, which will only be temporarily valid (unless \fBTcl_IncrRefCount\fR is called). .PP @@ -541,7 +541,7 @@ will take that list and first increment its reference count before using it. On completion of that use, Tcl will decrement its reference count. Hence if the list should be disposed of by Tcl when done, it should have a reference count of zero, and if the list should not be disposed of, the -filesystem should ensure it retains a reference count to the object. +filesystem should ensure it retains a reference count to the value. .PP \fBTcl_FSAccess\fR checks whether the process would be allowed to read, write or test for existence of the file (or other filesystem object) @@ -622,29 +622,29 @@ The separator is returned as a Tcl_Obj containing a string of length .PP \fBTcl_FSJoinPath\fR takes the given Tcl_Obj, which must be a valid list (which is allowed to have a reference count of zero), and returns the path -object given by considering the first \fIelements\fR elements as valid path +value given by considering the first \fIelements\fR elements as valid path segments (each path segment may be a complete path, a partial path or just a single possible directory or file name). If any path segment is actually an absolute path, then all prior path segments are discarded. If \fIelements\fR is less than 0, we use the entire list. .PP -It is possible that the returned object is actually an element +It is possible that the returned value is actually an element of the given list, so the caller should be careful to increment the reference count of the result before freeing the list. .PP -The returned object, typically with a reference count of zero (but it +The returned value, typically with a reference count of zero (but it could be shared under some conditions), contains the joined path. The caller must -add a reference count to the object before using it. In particular, the -returned object could be an element of the given list, so freeing the -list might free the object prematurely if no reference count has been taken. -If the number of elements is zero, then the returned object will be +add a reference count to the value before using it. In particular, the +returned value could be an element of the given list, so freeing the +list might free the value prematurely if no reference count has been taken. +If the number of elements is zero, then the returned value will be an empty-string Tcl_Obj. .PP \fBTcl_FSSplitPath\fR takes the given Tcl_Obj, which should be a valid path, -and returns a Tcl list object containing each segment of that path as +and returns a Tcl list value containing each segment of that path as an element. -It returns a list object with a reference count of zero. If the +It returns a list value with a reference count of zero. If the passed in \fIlenPtr\fR is non-NULL, the variable it points to will be updated to contain the number of elements in the returned list. .PP @@ -657,7 +657,7 @@ either path is NULL, 0 is always returned. from the given Tcl_Obj a unique normalized path representation, whose string value can be used as a unique identifier for the file. .PP -It returns the normalized path object, owned by Tcl, or NULL if the path +It returns the normalized path value, owned by Tcl, or NULL if the path was invalid or could otherwise not be successfully converted. Extraction of absolute, normalized paths is very efficient (because the filesystem operates on these representations internally), although the @@ -665,35 +665,36 @@ result when the filesystem contains numerous symbolic links may not be the most user-friendly version of a path. The return value is owned by Tcl and has a lifetime equivalent to that of the \fIpathPtr\fR passed in (unless that is a relative path, in which case the normalized path -object may be freed any time the cwd changes) - the caller can of -course increment the refCount if it wishes to maintain a copy for longer. +value may be freed any time the cwd changes) - the caller can of +course increment the reference count if it wishes to maintain a copy for longer. .PP -\fBTcl_FSJoinToPath\fR takes the given object, which should usually be a +\fBTcl_FSJoinToPath\fR takes the given value, which should usually be a valid path or NULL, and joins onto it the array of paths segments given. .PP -Returns object, typically with refCount of zero (but it could be shared +Returns a value, typically with reference count of zero (but it could be shared under some conditions), containing the joined path. The caller must -add a refCount to the object before using it. If any of the objects -passed into this function (pathPtr or path elements) have a refCount +add a reference count to the value before using it. If any of the values +passed into this function (\fIpathPtr\fR or \fIpath\fR elements) have +a reference count of zero, they will be freed when this function returns. .PP \fBTcl_FSConvertToPathType\fR tries to convert the given Tcl_Obj to a valid Tcl path type, taking account of the fact that the cwd may have changed -even if this object is already supposedly of the correct type. +even if this value is already supposedly of the correct type. The filename may begin with .QW ~ (to indicate current user's home directory) or .QW ~<user> (to indicate any user's home directory). .PP -If the conversion succeeds (i.e.\ the object is a valid path in one of +If the conversion succeeds (i.e.\ the value is a valid path in one of the current filesystems), then \fBTCL_OK\fR is returned. Otherwise \fBTCL_ERROR\fR is returned, and an error message may be left in the interpreter. .PP \fBTcl_FSGetInternalRep\fR extracts the internal representation of a given -path object, in the given filesystem. If the path object belongs to a +path value, in the given filesystem. If the path value belongs to a different filesystem, we return NULL. If the internal representation is currently NULL, we attempt to generate it, by calling the filesystem's \fBTcl_FSCreateInternalRepProc\fR. @@ -705,7 +706,7 @@ not require additional conversions. \fBTcl_FSGetTranslatedPath\fR attempts to extract the translated path from the given Tcl_Obj. .PP -If the translation succeeds (i.e.\ the object is a valid path), then it is +If the translation succeeds (i.e.\ the value is a valid path), then it is returned. Otherwise NULL will be returned, and an error message may be left in the interpreter. A .QW translated @@ -714,8 +715,8 @@ path is one which contains no or .QW ~user sequences (these have been expanded to their current -representation in the filesystem). The object returned is owned by the -caller, which must store it or call Tcl_DecrRefCount to ensure memory is +representation in the filesystem). The value returned is owned by the +caller, which must store it or call \fBTcl_DecrRefCount\fR to ensure memory is freed. This function is of little practical use, and \fBTcl_FSGetNormalizedPath\fR or \fBTcl_FSGetNativePath\fR are usually better functions to use for most purposes. @@ -731,11 +732,11 @@ better functions to use for most purposes. usual obj->path->nativerep conversions. If some code retrieves a path in native form (from, e.g.\ \fBreadlink\fR or a native dialog), and that path is to be used at the Tcl level, then calling this function is an -efficient way of creating the appropriate path object type. +efficient way of creating the appropriate path value type. .PP -The resulting object is a pure +The resulting value is a pure .QW path -object, which will only receive +value, which will only receive a UTF-8 string representation if that is required by some Tcl code. .PP \fBTcl_FSGetNativePath\fR is for use by the Win/Unix native @@ -773,7 +774,7 @@ given path within that filesystem (which is filesystem dependent). The second element may be empty if the filesystem does not provide a further categorization of files. .PP -A valid list object is returned, unless the path object is not +A valid list value is returned, unless the path value is not recognized, when NULL will be returned. .PP \fBTcl_FSGetFileSystemForPath\fR returns a pointer to the @@ -1001,14 +1002,14 @@ The \fIversion\fR field should be set to \fBTCL_FILESYSTEM_VERSION_1\fR. .SS PATHINFILESYSTEMPROC .PP The \fIpathInFilesystemProc\fR field contains the address of a function -which is called to determine whether a given path object belongs to this +which is called to determine whether a given path value belongs to this filesystem or not. Tcl will only call the rest of the filesystem functions with a path for which this function has returned \fBTCL_OK\fR. If the path does not belong, -1 should be returned (the behavior of Tcl for any other return value is not defined). If \fBTCL_OK\fR is returned, then the optional \fIclientDataPtr\fR output parameter can be used to return an internal (filesystem specific) representation of the path, -which will be cached inside the path object, and may be retrieved +which will be cached inside the path value, and may be retrieved efficiently by the other filesystem functions. Tcl will simultaneously cache the fact that this path belongs to this filesystem. Such caches are invalidated when filesystem structures are added or removed from @@ -1022,7 +1023,7 @@ typedef int \fBTcl_FSPathInFilesystemProc\fR( .SS DUPINTERNALREPPROC .PP This function makes a copy of a path's internal representation, and is -called when Tcl needs to duplicate a path object. If NULL, Tcl will +called when Tcl needs to duplicate a path value. If NULL, Tcl will simply not copy the internal representation, which may then need to be regenerated later. .PP @@ -1042,8 +1043,8 @@ typedef void \fBTcl_FSFreeInternalRepProc\fR( .SS INTERNALTONORMALIZEDPROC .PP Function to convert internal representation to a normalized path. Only -required if the filesystem creates pure path objects with no string/path -representation. The return value is a Tcl object whose string +required if the filesystem creates pure path values with no string/path +representation. The return value is a Tcl value whose string representation is the normalized path. .PP .CS @@ -1052,9 +1053,9 @@ typedef Tcl_Obj *\fBTcl_FSInternalToNormalizedProc\fR( .CE .SS CREATEINTERNALREPPROC .PP -Function to take a path object, and calculate an internal +Function to take a path value, and calculate an internal representation for it, and store that native representation in the -object. May be NULL if paths have no internal representation, or if +value. May be NULL if paths have no internal representation, or if the \fITcl_FSPathInFilesystemProc\fR for this filesystem always immediately creates an internal representation for paths it accepts. .PP @@ -1066,7 +1067,7 @@ typedef ClientData \fBTcl_FSCreateInternalRepProc\fR( .PP Function to normalize a path. Should be implemented for all filesystems which can have multiple string representations for the same -path object. In Tcl, every +path value. In Tcl, every .QW path must have a single unique .QW normalized @@ -1078,7 +1079,7 @@ reference to a home directory such as .QW ~ , a path containing symbolic links, etc). If the very last component in the path is a symbolic -link, it should not be converted into the object it points to (but +link, it should not be converted into the value it points to (but its case or other aspects should be made unique). All other path components should be converted from symbolic links. This one exception is required to agree with Tcl's semantics with \fBfile @@ -1122,7 +1123,7 @@ which is returned. A typical return value might be or .QW ftp . The Tcl_Obj result is owned by the filesystem and so Tcl will -increment the refCount of that object if it wishes to retain a reference +increment the reference count of that value if it wishes to retain a reference to it. .PP .CS @@ -1137,7 +1138,7 @@ different separator than the standard string .QW / . Amongst other uses, it is returned by the \fBfile separator\fR command. The -return value should be an object with refCount of zero. +return value should be a value with reference count of zero. .PP .CS typedef Tcl_Obj *\fBTcl_FSFilesystemSeparatorProc\fR( @@ -1256,7 +1257,7 @@ The return value is a standard Tcl result indicating whether an error occurred in the matching process. Error messages are placed in \fIinterp\fR, unless \fIinterp\fR in NULL in which case no error message need be generated; on a \fBTCL_OK\fR result, results should be -added to the \fIresultPtr\fR object given (which can be assumed to be a +added to the \fIresultPtr\fR value given (which can be assumed to be a valid unshared Tcl list). The matches added to \fIresultPtr\fR should include any path prefix given in \fIpathPtr\fR (this usually means they will be absolute path specifications). @@ -1326,7 +1327,7 @@ contents of a link. The result is a Tcl_Obj specifying the contents of the link given by \fIlinkNamePtr\fR, or NULL if the link could not be read. The result is owned by the caller (and should therefore have its ref count incremented before being returned). Any callers -should call Tcl_DecrRefCount on this result when it is no longer needed. +should call \fBTcl_DecrRefCount\fR on this result when it is no longer needed. If \fItoPtr\fR is not NULL, the function should attempt to create a link. The result in this case should be \fItoPtr\fR if the link was successful and NULL otherwise. In this case the result is not owned by the caller @@ -1344,16 +1345,16 @@ typedef Tcl_Obj *\fBTcl_FSListVolumesProc\fR(void); .CE .PP The result should be a list of volumes added by this filesystem, or -NULL (or an empty list) if no volumes are provided. The result object +NULL (or an empty list) if no volumes are provided. The result value is considered to be owned by the filesystem (not by Tcl's core), but -should be given a refCount for Tcl. Tcl will use the contents of the -list and then decrement that refCount. This allows filesystems to +should be given a reference count for Tcl. Tcl will use the contents of the +list and then decrement that reference count. This allows filesystems to choose whether they actually want to retain a .QW "master list" of volumes or not (if not, they generate the list on the fly and pass it to Tcl -with a refCount of 1 and then forget about the list, if yes, then -they simply increment the refCount of their master list and pass it +with a reference count of 1 and then forget about the list, if yes, then +they simply increment the reference count of their master list and pass it to Tcl which will copy the contents and then decrement the count back to where it was). .PP @@ -1379,7 +1380,7 @@ will take that list and first increment its reference count before using it. On completion of that use, Tcl will decrement its reference count. Hence if the list should be disposed of by Tcl when done, it should have a reference count of zero, and if the list should not be disposed of, the -filesystem should ensure it returns an object with a reference count +filesystem should ensure it returns a value with a reference count of at least one. .SS FILEATTRSGETPROC .PP diff --git a/doc/GetIndex.3 b/doc/GetIndex.3 index 50607ae..d32561a 100644 --- a/doc/GetIndex.3 +++ b/doc/GetIndex.3 @@ -26,7 +26,7 @@ int Interpreter to use for error reporting; if NULL, then no message is provided on errors. .AP Tcl_Obj *objPtr in/out -The string value of this object is used to search through \fItablePtr\fR. +The string value of this value is used to search through \fItablePtr\fR. The internal representation is modified to hold the index of the matching table entry. .AP "const char *const" *tablePtr in @@ -58,8 +58,8 @@ The index of the string in \fItablePtr\fR that matches the value of .SH DESCRIPTION .PP These procedures provide an efficient way for looking up keywords, -switch names, option names, and similar things where the value of -an object must be one of a predefined set of values. +switch names, option names, and similar things where the literal value of +a Tcl value must be chosen from a predefined set. \fBTcl_GetIndexFromObj\fR compares \fIobjPtr\fR against each of the strings in \fItablePtr\fR to find a match. A match occurs if \fIobjPtr\fR's string value is identical to one of the strings in @@ -101,4 +101,4 @@ each of several array elements. .SH "SEE ALSO" prefix(n), Tcl_WrongNumArgs(3) .SH KEYWORDS -index, object, table lookup +index, option, value, table lookup @@ -310,14 +310,14 @@ typedef Tcl_HashEntry *\fBTcl_AllocHashEntryProc\fR( void *\fIkeyPtr\fR); .CE .PP -If this is NULL then Tcl_Alloc is used to allocate enough space for a +If this is NULL then \fBTcl_Alloc\fR is used to allocate enough space for a Tcl_HashEntry, the key pointer is assigned to key.oneWordValue and the clientData is set to NULL. String keys and array keys use this function to allocate enough space for the entry and the key in one block, rather than doing it in two blocks. This saves space for a pointer to the key from the entry and another memory allocation. Tcl_Obj* keys use this function to allocate enough space for an entry and increment the reference count on the -object. +value. .PP The \fIfreeEntryProc\fR member contains the address of a function called to free space for an entry. @@ -327,8 +327,8 @@ typedef void \fBTcl_FreeHashEntryProc\fR( Tcl_HashEntry *\fIhPtr\fR); .CE .PP -If this is NULL then Tcl_Free is used to free the space for the entry. +If this is NULL then \fBTcl_Free\fR is used to free the space for the entry. Tcl_Obj* keys use this function to decrement the reference count on the -object. +value. .SH KEYWORDS hash table, key, lookup, search, value diff --git a/doc/IntObj.3 b/doc/IntObj.3 index cde96f8..4b7b8a6 100644 --- a/doc/IntObj.3 +++ b/doc/IntObj.3 @@ -8,7 +8,7 @@ .TH Tcl_IntObj 3 8.5 Tcl "Tcl Library Procedures" .BS .SH NAME -Tcl_NewIntObj, Tcl_NewLongObj, Tcl_NewWideIntObj, Tcl_SetIntObj, Tcl_SetLongObj, Tcl_SetWideIntObj, Tcl_GetIntFromObj, Tcl_GetLongFromObj, Tcl_GetWideIntFromObj, Tcl_NewBignumObj, Tcl_SetBignumObj, Tcl_GetBignumFromObj, Tcl_TakeBignumFromObj \- manipulate Tcl objects as integer values +Tcl_NewIntObj, Tcl_NewLongObj, Tcl_NewWideIntObj, Tcl_SetIntObj, Tcl_SetLongObj, Tcl_SetWideIntObj, Tcl_GetIntFromObj, Tcl_GetLongFromObj, Tcl_GetWideIntFromObj, Tcl_NewBignumObj, Tcl_SetBignumObj, Tcl_GetBignumFromObj, Tcl_TakeBignumFromObj \- manipulate Tcl values as integers .SH SYNOPSIS .nf \fB#include <tcl.h>\fR @@ -56,17 +56,17 @@ int .SH ARGUMENTS .AS Tcl_WideInt doubleValue in/out .AP int intValue in -Integer value used to initialize or set a Tcl object. +Integer value used to initialize or set a Tcl value. .AP long longValue in -Long integer value used to initialize or set a Tcl object. +Long integer value used to initialize or set a Tcl value. .AP Tcl_WideInt wideValue in -Wide integer value used to initialize or set a Tcl object. +Wide integer value used to initialize or set a Tcl value. .AP Tcl_Obj *objPtr in/out For \fBTcl_SetIntObj\fR, \fBTcl_SetLongObj\fR, \fBTcl_SetWideIntObj\fR, -and \fBTcl_SetBignumObj\fR, this points to the object in which to store an +and \fBTcl_SetBignumObj\fR, this points to the value in which to store an integral value. For \fBTcl_GetIntFromObj\fR, \fBTcl_GetLongFromObj\fR, \fBTcl_GetWideIntFromObj\fR, \fBTcl_GetBignumFromObj\fR, and -\fBTcl_TakeBignumFromObj\fR, this refers to the object from which +\fBTcl_TakeBignumFromObj\fR, this refers to the value from which to retrieve an integral value. .AP Tcl_Interp *interp in/out When non-NULL, an error message is left here when integral value @@ -86,7 +86,7 @@ used to initialize a multi-precision integer value. .BE .SH DESCRIPTION .PP -These procedures are used to create, modify, and read Tcl objects +These procedures are used to create, modify, and read Tcl values that hold integral values. .PP The different routines exist to accommodate different integral types in C @@ -103,22 +103,22 @@ by the LibTomMath multiple-precision integer library. .PP The \fBTcl_NewIntObj\fR, \fBTcl_NewLongObj\fR, \fBTcl_NewWideIntObj\fR, and \fBTcl_NewBignumObj\fR routines each create and return a new -Tcl object initialized to the integral value of the argument. The -returned Tcl object is unshared. +Tcl value initialized to the integral value of the argument. The +returned Tcl value is unshared. .PP The \fBTcl_SetIntObj\fR, \fBTcl_SetLongObj\fR, \fBTcl_SetWideIntObj\fR, and \fBTcl_SetBignumObj\fR routines each set the value of an existing -Tcl object pointed to by \fIobjPtr\fR to the integral value provided +Tcl value pointed to by \fIobjPtr\fR to the integral value provided by the other argument. The \fIobjPtr\fR argument must point to an -unshared Tcl object. Any attempt to set the value of a shared Tcl object +unshared Tcl value. Any attempt to set the value of a shared Tcl value violates Tcl's copy-on-write policy. Any existing string representation -or internal representation in the unshared Tcl object will be freed +or internal representation in the unshared Tcl value will be freed as a consequence of setting the new value. .PP The \fBTcl_GetIntFromObj\fR, \fBTcl_GetLongFromObj\fR, \fBTcl_GetWideIntFromObj\fR, \fBTcl_GetBignumFromObj\fR, and \fBTcl_TakeBignumFromObj\fR routines attempt to retrieve an integral -value of the appropriate type from the Tcl object \fIobjPtr\fR. If the +value of the appropriate type from the Tcl value \fIobjPtr\fR. If the attempt succeeds, then \fBTCL_OK\fR is returned, and the value is written to the storage provided by the caller. The attempt might fail if \fIobjPtr\fR does not hold an integral value, or if the @@ -127,7 +127,7 @@ then \fBTCL_ERROR\fR is returned, and if \fIinterp\fR is non-NULL, an error message is left in \fIinterp\fR. The \fBTcl_ObjType\fR of \fIobjPtr\fR may be changed to make subsequent calls to the same routine more efficient. Unlike the other functions, -\fBTcl_TakeBignumFromObj\fR may set the content of the Tcl object +\fBTcl_TakeBignumFromObj\fR may set the content of the Tcl value \fIobjPtr\fR to an empty string in the process of retrieving the multiple-precision integer value. .PP @@ -148,4 +148,5 @@ integer value in the \fBmp_int\fR value \fIbigValue\fR. .SH "SEE ALSO" Tcl_NewObj, Tcl_DecrRefCount, Tcl_IncrRefCount, Tcl_GetObjResult .SH KEYWORDS -integer, integer object, integer type, internal representation, object, object type, string representation +integer, integer value, integer type, internal representation, value, +value type, string representation diff --git a/doc/ListObj.3 b/doc/ListObj.3 index b93e52b..bc6917d 100644 --- a/doc/ListObj.3 +++ b/doc/ListObj.3 @@ -8,7 +8,7 @@ .TH Tcl_ListObj 3 8.0 Tcl "Tcl Library Procedures" .BS .SH NAME -Tcl_ListObjAppendList, Tcl_ListObjAppendElement, Tcl_NewListObj, Tcl_SetListObj, Tcl_ListObjGetElements, Tcl_ListObjLength, Tcl_ListObjIndex, Tcl_ListObjReplace \- manipulate Tcl objects as lists +Tcl_ListObjAppendList, Tcl_ListObjAppendElement, Tcl_NewListObj, Tcl_SetListObj, Tcl_ListObjGetElements, Tcl_ListObjLength, Tcl_ListObjIndex, Tcl_ListObjReplace \- manipulate Tcl values as lists .SH SYNOPSIS .nf \fB#include <tcl.h>\fR @@ -38,44 +38,44 @@ int .SH ARGUMENTS .AS "Tcl_Obj *const" *elemListPtr in/out .AP Tcl_Interp *interp in -If an error occurs while converting an object to be a list object, -an error message is left in the interpreter's result object +If an error occurs while converting a value to be a list value, +an error message is left in the interpreter's result value unless \fIinterp\fR is NULL. .AP Tcl_Obj *listPtr in/out -Points to the list object to be manipulated. -If \fIlistPtr\fR does not already point to a list object, +Points to the list value to be manipulated. +If \fIlistPtr\fR does not already point to a list value, an attempt will be made to convert it to one. .AP Tcl_Obj *elemListPtr in/out -For \fBTcl_ListObjAppendList\fR, this points to a list object +For \fBTcl_ListObjAppendList\fR, this points to a list value containing elements to be appended onto \fIlistPtr\fR. Each element of *\fIelemListPtr\fR will become a new element of \fIlistPtr\fR. If *\fIelemListPtr\fR is not NULL and -does not already point to a list object, +does not already point to a list value, an attempt will be made to convert it to one. .AP Tcl_Obj *objPtr in For \fBTcl_ListObjAppendElement\fR, -points to the Tcl object that will be appended to \fIlistPtr\fR. +points to the Tcl value that will be appended to \fIlistPtr\fR. For \fBTcl_SetListObj\fR, -this points to the Tcl object that will be converted to a list object +this points to the Tcl value that will be converted to a list value containing the \fIobjc\fR elements of the array referenced by \fIobjv\fR. .AP int *objcPtr in Points to location where \fBTcl_ListObjGetElements\fR -stores the number of element objects in \fIlistPtr\fR. +stores the number of element values in \fIlistPtr\fR. .AP Tcl_Obj ***objvPtr out A location where \fBTcl_ListObjGetElements\fR stores a pointer to an array -of pointers to the element objects of \fIlistPtr\fR. +of pointers to the element values of \fIlistPtr\fR. .AP int objc in -The number of Tcl objects that \fBTcl_NewListObj\fR -will insert into a new list object, +The number of Tcl values that \fBTcl_NewListObj\fR +will insert into a new list value, and \fBTcl_ListObjReplace\fR will insert into \fIlistPtr\fR. For \fBTcl_SetListObj\fR, -the number of Tcl objects to insert into \fIobjPtr\fR. +the number of Tcl values to insert into \fIobjPtr\fR. .AP "Tcl_Obj *const" objv[] in -An array of pointers to objects. -\fBTcl_NewListObj\fR will insert these objects into a new list object +An array of pointers to values. +\fBTcl_NewListObj\fR will insert these values into a new list value and \fBTcl_ListObjReplace\fR will insert them into an existing \fIlistPtr\fR. -Each object will become a separate list element. +Each value will become a separate list element. .AP int *intPtr out Points to location where \fBTcl_ListObjLength\fR stores the length of the list. @@ -85,7 +85,7 @@ is to return. The first element has index 0. .AP Tcl_Obj **objPtrPtr out Points to place where \fBTcl_ListObjIndex\fR is to store -a pointer to the resulting list element object. +a pointer to the resulting list element value. .AP int first in Index of the starting list element that \fBTcl_ListObjReplace\fR is to replace. @@ -97,85 +97,85 @@ is to replace. .SH DESCRIPTION .PP -Tcl list objects have an internal representation that supports +Tcl list values have an internal representation that supports the efficient indexing and appending. The procedures described in this man page are used to -create, modify, index, and append to Tcl list objects from C code. +create, modify, index, and append to Tcl list values from C code. .PP \fBTcl_ListObjAppendList\fR and \fBTcl_ListObjAppendElement\fR -both add one or more objects -to the end of the list object referenced by \fIlistPtr\fR. -\fBTcl_ListObjAppendList\fR appends each element of the list object +both add one or more values +to the end of the list value referenced by \fIlistPtr\fR. +\fBTcl_ListObjAppendList\fR appends each element of the list value referenced by \fIelemListPtr\fR while -\fBTcl_ListObjAppendElement\fR appends the single object +\fBTcl_ListObjAppendElement\fR appends the single value referenced by \fIobjPtr\fR. -Both procedures will convert the object referenced by \fIlistPtr\fR -to a list object if necessary. +Both procedures will convert the value referenced by \fIlistPtr\fR +to a list value if necessary. If an error occurs during conversion, both procedures return \fBTCL_ERROR\fR and leave an error message -in the interpreter's result object if \fIinterp\fR is not NULL. -Similarly, if \fIelemListPtr\fR does not already refer to a list object, +in the interpreter's result value if \fIinterp\fR is not NULL. +Similarly, if \fIelemListPtr\fR does not already refer to a list value, \fBTcl_ListObjAppendList\fR will attempt to convert it to one and if an error occurs during conversion, will return \fBTCL_ERROR\fR -and leave an error message in the interpreter's result object +and leave an error message in the interpreter's result value if interp is not NULL. Both procedures invalidate any old string representation of \fIlistPtr\fR -and, if it was converted to a list object, +and, if it was converted to a list value, free any old internal representation. Similarly, \fBTcl_ListObjAppendList\fR frees any old internal representation -of \fIelemListPtr\fR if it converts it to a list object. +of \fIelemListPtr\fR if it converts it to a list value. After appending each element in \fIelemListPtr\fR, \fBTcl_ListObjAppendList\fR increments the element's reference count since \fIlistPtr\fR now also refers to it. For the same reason, \fBTcl_ListObjAppendElement\fR increments \fIobjPtr\fR's reference count. If no error occurs, -the two procedures return \fBTCL_OK\fR after appending the objects. +the two procedures return \fBTCL_OK\fR after appending the values. .PP \fBTcl_NewListObj\fR and \fBTcl_SetListObj\fR -create a new object or modify an existing object to hold +create a new value or modify an existing value to hold the \fIobjc\fR elements of the array referenced by \fIobjv\fR -where each element is a pointer to a Tcl object. +where each element is a pointer to a Tcl value. If \fIobjc\fR is less than or equal to zero, -they return an empty object. -The new object's string representation is left invalid. +they return an empty value. +The new value's string representation is left invalid. The two procedures increment the reference counts -of the elements in \fIobjc\fR since the list object now refers to them. -The new list object returned by \fBTcl_NewListObj\fR +of the elements in \fIobjc\fR since the list value now refers to them. +The new list value returned by \fBTcl_NewListObj\fR has reference count zero. .PP \fBTcl_ListObjGetElements\fR returns a count and a pointer to an array of -the elements in a list object. It returns the count by storing it in the +the elements in a list value. It returns the count by storing it in the address \fIobjcPtr\fR. Similarly, it returns the array pointer by storing it in the address \fIobjvPtr\fR. The memory pointed to is managed by Tcl and should not be freed or written to by the caller. If the list is empty, 0 is stored at \fIobjcPtr\fR and NULL at \fIobjvPtr\fR. -If \fIlistPtr\fR is not already a list object, \fBTcl_ListObjGetElements\fR +If \fIlistPtr\fR is not already a list value, \fBTcl_ListObjGetElements\fR will attempt to convert it to one; if the conversion fails, it returns \fBTCL_ERROR\fR and leaves an error message in the interpreter's result -object if \fIinterp\fR is not NULL. +value if \fIinterp\fR is not NULL. Otherwise it returns \fBTCL_OK\fR after storing the count and array pointer. .PP -\fBTcl_ListObjLength\fR returns the number of elements in the list object +\fBTcl_ListObjLength\fR returns the number of elements in the list value referenced by \fIlistPtr\fR. It returns this count by storing an integer in the address \fIintPtr\fR. -If the object is not already a list object, +If the value is not already a list value, \fBTcl_ListObjLength\fR will attempt to convert it to one; if the conversion fails, it returns \fBTCL_ERROR\fR -and leaves an error message in the interpreter's result object +and leaves an error message in the interpreter's result value if \fIinterp\fR is not NULL. Otherwise it returns \fBTCL_OK\fR after storing the list's length. .PP -The procedure \fBTcl_ListObjIndex\fR returns a pointer to the object +The procedure \fBTcl_ListObjIndex\fR returns a pointer to the value at element \fIindex\fR in the list referenced by \fIlistPtr\fR. -It returns this object by storing a pointer to it +It returns this value by storing a pointer to it in the address \fIobjPtrPtr\fR. -If \fIlistPtr\fR does not already refer to a list object, +If \fIlistPtr\fR does not already refer to a list value, \fBTcl_ListObjIndex\fR will attempt to convert it to one; if the conversion fails, it returns \fBTCL_ERROR\fR -and leaves an error message in the interpreter's result object +and leaves an error message in the interpreter's result value if \fIinterp\fR is not NULL. If the index is out of range, that is, \fIindex\fR is negative or @@ -183,19 +183,19 @@ greater than or equal to the number of elements in the list, \fBTcl_ListObjIndex\fR stores a NULL in \fIobjPtrPtr\fR and returns \fBTCL_OK\fR. Otherwise it returns \fBTCL_OK\fR after storing the element's -object pointer. +value pointer. The reference count for the list element is not incremented; the caller must do that if it needs to retain a pointer to the element. .PP \fBTcl_ListObjReplace\fR replaces zero or more elements of the list referenced by \fIlistPtr\fR -with the \fIobjc\fR objects in the array referenced by \fIobjv\fR. -If \fIlistPtr\fR does not point to a list object, +with the \fIobjc\fR values in the array referenced by \fIobjv\fR. +If \fIlistPtr\fR does not point to a list value, \fBTcl_ListObjReplace\fR will attempt to convert it to one; if the conversion fails, it returns \fBTCL_ERROR\fR -and leaves an error message in the interpreter's result object +and leaves an error message in the interpreter's result value if \fIinterp\fR is not NULL. -Otherwise, it returns \fBTCL_OK\fR after replacing the objects. +Otherwise, it returns \fBTCL_OK\fR after replacing the values. If \fIobjv\fR is NULL, no new elements are added. If the argument \fIfirst\fR is zero or negative, it refers to the first element. @@ -210,13 +210,13 @@ designated by \fIfirst\fR. old string representation. The reference counts of any elements inserted from \fIobjv\fR are incremented since the resulting list now refers to them. -Similarly, the reference counts for any replaced objects are decremented. +Similarly, the reference counts for any replaced values are decremented. .PP Because \fBTcl_ListObjReplace\fR combines both element insertion and deletion, it can be used to implement a number of list operations. -For example, the following code inserts the \fIobjc\fR objects -referenced by the array of object pointers \fIobjv\fR +For example, the following code inserts the \fIobjc\fR values +referenced by the array of value pointers \fIobjv\fR just before the element \fIindex\fR of the list referenced by \fIlistPtr\fR: .PP .CS @@ -224,7 +224,7 @@ result = \fBTcl_ListObjReplace\fR(interp, listPtr, index, 0, objc, objv); .CE .PP -Similarly, the following code appends the \fIobjc\fR objects +Similarly, the following code appends the \fIobjc\fR values referenced by the array \fIobjv\fR to the end of the list \fIlistPtr\fR: .PP @@ -247,4 +247,5 @@ result = \fBTcl_ListObjReplace\fR(interp, listPtr, first, count, .SH "SEE ALSO" Tcl_NewObj(3), Tcl_DecrRefCount(3), Tcl_IncrRefCount(3), Tcl_GetObjResult(3) .SH KEYWORDS -append, index, insert, internal representation, length, list, list object, list type, object, object type, replace, string representation +append, index, insert, internal representation, length, list, list value, +list type, value, value type, replace, string representation @@ -31,7 +31,8 @@ Array of names of symbols to be resolved during the load of the library, or NULL if no symbols are to be resolved. If an array is given, the last entry in the array must be NULL. .AP int flags in -Reserved for future expansion. Must be 0. +The value should normally be 0, but \fITCL_LOAD_GLOBALfR or \fITCL_LOAD_LAZYfR +or a combination of those two is allowed as well. .AP void *procPtrs out Points to an array that will hold the addresses of the functions described in the \fIsymbols\fR argument. Should be NULL if no symbols are to be resolved. @@ -57,7 +57,7 @@ is \fBNULL\fR, then no procedure is called before the command is deleted. .AP int objc in Count of parameters provided to the implementation of a command. .AP Tcl_Obj **objv in -Pointer to an array of Tcl objects. Each object holds the value of a +Pointer to an array of Tcl values. Each value holds the value of a single word in the command to execute. .AP Tcl_Obj *objPtr in Pointer to a Tcl_Obj whose value is a script or expression to execute. @@ -141,7 +141,7 @@ trampoline. .PP \fBTcl_NRCmdSwap\fR allows for trampoline evaluation of a command whose resolution is already known. The \fIcmd\fR parameter gives a -\fBTcl_Command\fR object (returned from \fBTcl_CreateObjCommand\fR or +\fBTcl_Command\fR token (returned from \fBTcl_CreateObjCommand\fR or \fBTcl_GetCommandFromObj\fR) identifying the command to be invoked in the trampoline; this command must match the word in \fIobjv[0]\fR. The remaining arguments are as for \fBTcl_NREvalObj\fR. @@ -323,6 +323,6 @@ and the second is for use when there is already a trampoline in place. .SH "SEE ALSO" Tcl_CreateCommand(3), Tcl_CreateObjCommand(3), Tcl_EvalObjEx(3), Tcl_GetCommandFromObj(3), Tcl_ExprObj(3) .SH KEYWORDS -stackless, nonrecursive, execute, command, global, object, result, script +stackless, nonrecursive, execute, command, global, value, result, script .SH COPYRIGHT Copyright (c) 2008 by Kevin B. Kenny diff --git a/doc/Namespace.3 b/doc/Namespace.3 index 50cc559..2b47128 100644 --- a/doc/Namespace.3 +++ b/doc/Namespace.3 @@ -67,7 +67,7 @@ if no such callback is to be performed. The namespace to be manipulated, or NULL (for other than \fBTcl_DeleteNamespace\fR) to manipulate the current namespace. .AP Tcl_Obj *objPtr out -A reference to an unshared object to which the function output will be +A reference to an unshared value to which the function output will be written. .AP "const char" *pattern in The glob-style pattern (see \fBTcl_StringMatch\fR) that describes the diff --git a/doc/Object.3 b/doc/Object.3 index 1c60449..3d52f61 100644 --- a/doc/Object.3 +++ b/doc/Object.3 @@ -8,7 +8,7 @@ .TH Tcl_Obj 3 8.5 Tcl "Tcl Library Procedures" .BS .SH NAME -Tcl_NewObj, Tcl_DuplicateObj, Tcl_IncrRefCount, Tcl_DecrRefCount, Tcl_IsShared, Tcl_InvalidateStringRep \- manipulate Tcl objects +Tcl_NewObj, Tcl_DuplicateObj, Tcl_IncrRefCount, Tcl_DecrRefCount, Tcl_IsShared, Tcl_InvalidateStringRep \- manipulate Tcl values .SH SYNOPSIS .nf \fB#include <tcl.h>\fR @@ -30,35 +30,36 @@ int .SH ARGUMENTS .AS Tcl_Obj *objPtr .AP Tcl_Obj *objPtr in -Points to an object; +Points to a value; must have been the result of a previous call to \fBTcl_NewObj\fR. .BE .SH INTRODUCTION .PP -This man page presents an overview of Tcl objects and how they are used. -It also describes generic procedures for managing Tcl objects. -These procedures are used to create and copy objects, -and increment and decrement the count of references (pointers) to objects. +This man page presents an overview of Tcl values (called \fBTcl_Obj\fRs for +historical reasons) and how they are used. +It also describes generic procedures for managing Tcl values. +These procedures are used to create and copy values, +and increment and decrement the count of references (pointers) to values. The procedures are used in conjunction with ones -that operate on specific types of objects such as +that operate on specific types of values such as \fBTcl_GetIntFromObj\fR and \fBTcl_ListObjAppendElement\fR. The individual procedures are described along with the data structures they manipulate. .PP -Tcl's \fIdual-ported\fR objects provide a general-purpose mechanism +Tcl's \fIdual-ported\fR values provide a general-purpose mechanism for storing and exchanging Tcl values. They largely replace the use of strings in Tcl. For example, they are used to store variable values, command arguments, command results, and scripts. -Tcl objects behave like strings but also hold an internal representation +Tcl values behave like strings but also hold an internal representation that can be manipulated more efficiently. -For example, a Tcl list is now represented as an object +For example, a Tcl list is now represented as a value that holds the list's string representation -as well as an array of pointers to the objects for each list element. -Dual-ported objects avoid most runtime type conversions. +as well as an array of pointers to the values for each list element. +Dual-ported values avoid most runtime type conversions. They also improve the speed of many operations since an appropriate representation is immediately available. -The compiler itself uses Tcl objects to +The compiler itself uses Tcl values to cache the instruction bytecodes resulting from compiling scripts. .PP The two representations are a cache of each other and are computed lazily. @@ -73,39 +74,39 @@ between integers and strings. Only when it needs a string representing the variable's value, say to print it, will the program regenerate the string representation from the integer. -Although objects contain an internal representation, +Although values contain an internal representation, their semantics are defined in terms of strings: an up-to-date string can always be obtained, -and any change to the object will be reflected in that string -when the object's string representation is fetched. +and any change to the value will be reflected in that string +when the value's string representation is fetched. Because of this representation invalidation and regeneration, it is dangerous for extension writers to access \fBTcl_Obj\fR fields directly. It is better to access Tcl_Obj information using procedures like \fBTcl_GetStringFromObj\fR and \fBTcl_GetString\fR. .PP -Objects are allocated on the heap +Values are allocated on the heap and are referenced using a pointer to their \fBTcl_Obj\fR structure. -Objects are shared as much as possible. +Values are shared as much as possible. This significantly reduces storage requirements -because some objects such as long lists are very large. +because some values such as long lists are very large. Also, most Tcl values are only read and never modified. This is especially true for procedure arguments, which can be shared between the caller and the called procedure. Assignment and argument binding is done by simply assigning a pointer to the value. Reference counting is used to determine when it is safe to -reclaim an object's storage. +reclaim a value's storage. .PP -Tcl objects are typed. -An object's internal representation is controlled by its type. +Tcl values are typed. +A value's internal representation is controlled by its type. Several types are predefined in the Tcl core including integer, double, list, and bytecode. Extension writers can extend the set of types by defining their own \fBTcl_ObjType\fR structs. .SH "THE TCL_OBJ STRUCTURE" .PP -Each Tcl object is represented by a \fBTcl_Obj\fR structure +Each Tcl value is represented by a \fBTcl_Obj\fR structure which is defined as follows. .PP .CS @@ -132,7 +133,7 @@ typedef struct Tcl_Obj { .CE .PP The \fIbytes\fR and the \fIlength\fR members together hold -an object's UTF-8 string representation, +a value's UTF-8 string representation, which is a \fIcounted string\fR not containing null bytes (UTF-8 null characters should be encoded as a two byte sequence: 192, 128.) \fIbytes\fR points to the first byte of the string representation. @@ -142,31 +143,31 @@ at offset \fIlength\fR; this allows string representations to be treated as conventional null-terminated C strings. C programs use \fBTcl_GetStringFromObj\fR and \fBTcl_GetString\fR to get -an object's string representation. +a value's string representation. If \fIbytes\fR is NULL, the string representation is invalid. .PP -An object's type manages its internal representation. +A value's type manages its internal representation. The member \fItypePtr\fR points to the Tcl_ObjType structure that describes the type. If \fItypePtr\fR is NULL, the internal representation is invalid. .PP The \fIinternalRep\fR union member holds -an object's internal representation. +a value's internal representation. This is either a (long) integer, a double-precision floating-point number, a pointer to a value containing additional information -needed by the object's type to represent the object, a Tcl_WideInt +needed by the value's type to represent the value, a Tcl_WideInt integer, two arbitrary pointers, or a pair made up of an unsigned long integer and a pointer. .PP The \fIrefCount\fR member is used to tell when it is safe to free -an object's storage. -It holds the count of active references to the object. +a value's storage. +It holds the count of active references to the value. Maintaining the correct reference count is a key responsibility of extension writers. Reference counting is discussed below -in the section \fBSTORAGE MANAGEMENT OF OBJECTS\fR. +in the section \fBSTORAGE MANAGEMENT OF VALUES\fR. .PP Although extension writers can directly access the members of a Tcl_Obj structure, @@ -176,21 +177,21 @@ read or update \fIrefCount\fR directly; they should use macros such as \fBTcl_IncrRefCount\fR and \fBTcl_IsShared\fR instead. .PP -A key property of Tcl objects is that they hold two representations. -An object typically starts out containing only a string representation: +A key property of Tcl values is that they hold two representations. +A value typically starts out containing only a string representation: it is untyped and has a NULL \fItypePtr\fR. -An object containing an empty string or a copy of a specified string +A value containing an empty string or a copy of a specified string is created using \fBTcl_NewObj\fR or \fBTcl_NewStringObj\fR respectively. -An object's string value is gotten with +A value's string value is gotten with \fBTcl_GetStringFromObj\fR or \fBTcl_GetString\fR and changed with \fBTcl_SetStringObj\fR. -If the object is later passed to a procedure like \fBTcl_GetIntFromObj\fR +If the value is later passed to a procedure like \fBTcl_GetIntFromObj\fR that requires a specific internal representation, -the procedure will create one and set the object's \fItypePtr\fR. +the procedure will create one and set the value's \fItypePtr\fR. The internal representation is computed from the string representation. -An object's two representations are duals of each other: +A value's two representations are duals of each other: changes made to one are reflected in the other. -For example, \fBTcl_ListObjReplace\fR will modify an object's +For example, \fBTcl_ListObjReplace\fR will modify a value's internal representation and the next call to \fBTcl_GetStringFromObj\fR or \fBTcl_GetString\fR will reflect that change. .PP @@ -203,43 +204,43 @@ so that it is only regenerated if it is needed later. Most C programmers never have to be concerned with how this is done and simply use procedures such as \fBTcl_GetBooleanFromObj\fR or \fBTcl_ListObjIndex\fR. -Programmers that implement their own object types +Programmers that implement their own value types must check for invalid representations and mark representations invalid when necessary. The procedure \fBTcl_InvalidateStringRep\fR is used -to mark an object's string representation invalid and to +to mark a value's string representation invalid and to free any storage associated with the old string representation. .PP -Objects usually remain one type over their life, -but occasionally an object must be converted from one type to another. -For example, a C program might build up a string in an object +Values usually remain one type over their life, +but occasionally a value must be converted from one type to another. +For example, a C program might build up a string in a value with repeated calls to \fBTcl_AppendToObj\fR, and then call \fBTcl_ListObjIndex\fR to extract a list element from -the object. -The same object holding the same string value +the value. +The same value holding the same string value can have several different internal representations at different times. -Extension writers can also force an object to be converted from one type +Extension writers can also force a value to be converted from one type to another using the \fBTcl_ConvertToType\fR procedure. -Only programmers that create new object types need to be concerned +Only programmers that create new value types need to be concerned about how this is done. -A procedure defined as part of the object type's implementation -creates a new internal representation for an object +A procedure defined as part of the value type's implementation +creates a new internal representation for a value and changes its \fItypePtr\fR. See the man page for \fBTcl_RegisterObjType\fR -to see how to create a new object type. -.SH "EXAMPLE OF THE LIFETIME OF AN OBJECT" +to see how to create a new value type. +.SH "EXAMPLE OF THE LIFETIME OF A VALUE" .PP -As an example of the lifetime of an object, +As an example of the lifetime of a value, consider the following sequence of commands: .PP .CS \fBset x 123\fR .CE .PP -This assigns to \fIx\fR an untyped object whose +This assigns to \fIx\fR an untyped value whose \fIbytes\fR member points to \fB123\fR and \fIlength\fR member contains 3. -The object's \fItypePtr\fR member is NULL. +The value's \fItypePtr\fR member is NULL. .PP .CS \fBputs "x is $x"\fR @@ -252,16 +253,16 @@ and is fetched for the command. \fBincr x\fR .CE .PP -The \fBincr\fR command first gets an integer from \fIx\fR's object +The \fBincr\fR command first gets an integer from \fIx\fR's value by calling \fBTcl_GetIntFromObj\fR. -This procedure checks whether the object is already an integer object. -Since it is not, it converts the object -by setting the object's \fIinternalRep.longValue\fR member +This procedure checks whether the value is already an integer value. +Since it is not, it converts the value +by setting the value's \fIinternalRep.longValue\fR member to the integer \fB123\fR -and setting the object's \fItypePtr\fR +and setting the value's \fItypePtr\fR to point to the integer Tcl_ObjType structure. Both representations are now valid. -\fBincr\fR increments the object's integer internal representation +\fBincr\fR increments the value's integer internal representation then invalidates its string representation (by calling \fBTcl_InvalidateStringRep\fR) since the string representation @@ -271,31 +272,31 @@ no longer corresponds to the internal representation. \fBputs "x is now $x"\fR .CE .PP -The string representation of \fIx\fR's object is needed +The string representation of \fIx\fR's value is needed and is recomputed. The string representation is now \fB124\fR and both representations are again valid. -.SH "STORAGE MANAGEMENT OF OBJECTS" +.SH "STORAGE MANAGEMENT OF VALUES" .PP -Tcl objects are allocated on the heap and are shared as much as possible +Tcl values are allocated on the heap and are shared as much as possible to reduce storage requirements. -Reference counting is used to determine when an object is +Reference counting is used to determine when a value is no longer needed and can safely be freed. -An object just created by \fBTcl_NewObj\fR or \fBTcl_NewStringObj\fR +A value just created by \fBTcl_NewObj\fR or \fBTcl_NewStringObj\fR has \fIrefCount\fR 0. The macro \fBTcl_IncrRefCount\fR increments the reference count -when a new reference to the object is created. +when a new reference to the value is created. The macro \fBTcl_DecrRefCount\fR decrements the count when a reference is no longer needed and, -if the object's reference count drops to zero, frees its storage. -An object shared by different code or data structures has +if the value's reference count drops to zero, frees its storage. +A value shared by different code or data structures has \fIrefCount\fR greater than 1. -Incrementing an object's reference count ensures that +Incrementing a value's reference count ensures that it will not be freed too early or have its value change accidentally. .PP -As an example, the bytecode interpreter shares argument objects -between calling and called Tcl procedures to avoid having to copy objects. -It assigns the call's argument objects to the procedure's +As an example, the bytecode interpreter shares argument values +between calling and called Tcl procedures to avoid having to copy values. +It assigns the call's argument values to the procedure's formal parameter variables. In doing so, it calls \fBTcl_IncrRefCount\fR to increment the reference count of each argument since there is now a new @@ -303,31 +304,31 @@ reference to it from the formal parameter. When the called procedure returns, the interpreter calls \fBTcl_DecrRefCount\fR to decrement each argument's reference count. -When an object's reference count drops less than or equal to zero, +When a value's reference count drops less than or equal to zero, \fBTcl_DecrRefCount\fR reclaims its storage. Most command procedures do not have to be concerned about -reference counting since they use an object's value immediately -and do not retain a pointer to the object after they return. -However, if they do retain a pointer to an object in a data structure, +reference counting since they use a value's value immediately +and do not retain a pointer to the value after they return. +However, if they do retain a pointer to a value in a data structure, they must be careful to increment its reference count since the retained pointer is a new reference. .PP -Command procedures that directly modify objects +Command procedures that directly modify values such as those for \fBlappend\fR and \fBlinsert\fR must be careful to -copy a shared object before changing it. -They must first check whether the object is shared +copy a shared value before changing it. +They must first check whether the value is shared by calling \fBTcl_IsShared\fR. -If the object is shared they must copy the object +If the value is shared they must copy the value by using \fBTcl_DuplicateObj\fR; -this returns a new duplicate of the original object +this returns a new duplicate of the original value that has \fIrefCount\fR 0. -If the object is not shared, +If the value is not shared, the command procedure .QW "owns" -the object and can safely modify it directly. +the value and can safely modify it directly. For example, the following code appears in the command procedure that implements \fBlinsert\fR. -This procedure modifies the list object passed to it in \fIobjv[1]\fR +This procedure modifies the list value passed to it in \fIobjv[1]\fR by inserting \fIobjc-3\fR new elements before \fIindex\fR. .PP .CS @@ -340,11 +341,12 @@ result = Tcl_ListObjReplace(interp, listPtr, index, 0, .CE .PP As another example, \fBincr\fR's command procedure -must check whether the variable's object is shared before +must check whether the variable's value is shared before incrementing the integer in its internal representation. -If it is shared, it needs to duplicate the object +If it is shared, it needs to duplicate the value in order to avoid accidentally changing values in other data structures. .SH "SEE ALSO" Tcl_ConvertToType(3), Tcl_GetIntFromObj(3), Tcl_ListObjAppendElement(3), Tcl_ListObjIndex(3), Tcl_ListObjReplace(3), Tcl_RegisterObjType(3) .SH KEYWORDS -internal representation, object, object creation, object type, reference counting, string representation, type conversion +internal representation, value, value creation, value type, +reference counting, string representation, type conversion diff --git a/doc/ObjectType.3 b/doc/ObjectType.3 index 0c11187..ca2c7a0 100644 --- a/doc/ObjectType.3 +++ b/doc/ObjectType.3 @@ -8,7 +8,7 @@ .TH Tcl_ObjType 3 8.0 Tcl "Tcl Library Procedures" .BS .SH NAME -Tcl_RegisterObjType, Tcl_GetObjType, Tcl_AppendAllObjTypes, Tcl_ConvertToType \- manipulate Tcl object types +Tcl_RegisterObjType, Tcl_GetObjType, Tcl_AppendAllObjTypes, Tcl_ConvertToType \- manipulate Tcl value types .SH SYNOPSIS .nf \fB#include <tcl.h>\fR @@ -26,31 +26,32 @@ int .SH ARGUMENTS .AS "const char" *typeName .AP "const Tcl_ObjType" *typePtr in -Points to the structure containing information about the Tcl object type. +Points to the structure containing information about the Tcl value type. This storage must live forever, typically by being statically allocated. .AP "const char" *typeName in -The name of a Tcl object type that \fBTcl_GetObjType\fR should look up. +The name of a Tcl value type that \fBTcl_GetObjType\fR should look up. .AP Tcl_Interp *interp in Interpreter to use for error reporting. .AP Tcl_Obj *objPtr in -For \fBTcl_AppendAllObjTypes\fR, this points to the object onto which -it appends the name of each object type as a list element. -For \fBTcl_ConvertToType\fR, this points to an object that +For \fBTcl_AppendAllObjTypes\fR, this points to the value onto which +it appends the name of each value type as a list element. +For \fBTcl_ConvertToType\fR, this points to a value that must have been the result of a previous call to \fBTcl_NewObj\fR. .BE .SH DESCRIPTION .PP -The procedures in this man page manage Tcl object types. -They are used to register new object types, look up types, +The procedures in this man page manage Tcl value types (sometimes +referred to as object types or \fBTcl_ObjType\fRs for historical reasons). +They are used to register new value types, look up types, and force conversions from one type to another. .PP -\fBTcl_RegisterObjType\fR registers a new Tcl object type -in the table of all object types that \fBTcl_GetObjType\fR -can look up by name. There are other object types supported by Tcl +\fBTcl_RegisterObjType\fR registers a new Tcl value type +in the table of all value types that \fBTcl_GetObjType\fR +can look up by name. There are other value types supported by Tcl as well, which Tcl chooses not to register. Extensions can likewise -choose to register the object types they create or not. +choose to register the value types they create or not. The argument \fItypePtr\fR points to a Tcl_ObjType structure that describes the new type by giving its name and by supplying pointers to four procedures @@ -65,13 +66,13 @@ in the section \fBTHE TCL_OBJTYPE STRUCTURE\fR below. with name \fItypeName\fR. It returns NULL if no type with that name is registered. .PP -\fBTcl_AppendAllObjTypes\fR appends the name of each registered object type -as a list element onto the Tcl object referenced by \fIobjPtr\fR. +\fBTcl_AppendAllObjTypes\fR appends the name of each registered value type +as a list element onto the Tcl value referenced by \fIobjPtr\fR. The return value is \fBTCL_OK\fR unless there was an error -converting \fIobjPtr\fR to a list object; +converting \fIobjPtr\fR to a list value; in that case \fBTCL_ERROR\fR is returned. .PP -\fBTcl_ConvertToType\fR converts an object from one type to another +\fBTcl_ConvertToType\fR converts a value from one type to another if possible. It creates a new internal representation for \fIobjPtr\fR appropriate for the target type \fItypePtr\fR @@ -79,7 +80,7 @@ and sets its \fItypePtr\fR member as determined by calling the \fItypePtr->setFromAnyProc\fR routine. Any internal representation for \fIobjPtr\fR's old type is freed. If an error occurs during conversion, it returns \fBTCL_ERROR\fR -and leaves an error message in the result object for \fIinterp\fR +and leaves an error message in the result value for \fIinterp\fR unless \fIinterp\fR is NULL. Otherwise, it returns \fBTCL_OK\fR. Passing a NULL \fIinterp\fR allows this procedure to be used @@ -94,7 +95,7 @@ use of another related Tcl_ObjType, if it sees fit. .VE 8.5 .SH "THE TCL_OBJTYPE STRUCTURE" .PP -Extension writers can define new object types by defining four +Extension writers can define new value types by defining four procedures and initializing a Tcl_ObjType structure to describe the type. Extension writers may also pass a pointer to their Tcl_ObjType @@ -119,12 +120,12 @@ When a type is registered, this is the name used by callers of \fBTcl_GetObjType\fR to lookup the type. For unregistered types, the \fIname\fR field is primarily of value for debugging. The remaining four members are pointers to procedures -called by the generic Tcl object code: +called by the generic Tcl value code: .SS "THE SETFROMANYPROC FIELD" .PP The \fIsetFromAnyProc\fR member contains the address of a function called to create a valid internal representation -from an object's string representation. +from a value's string representation. .PP .CS typedef int \fBTcl_SetFromAnyProc\fR( @@ -134,7 +135,7 @@ typedef int \fBTcl_SetFromAnyProc\fR( .PP If an internal representation cannot be created from the string, it returns \fBTCL_ERROR\fR and puts a message -describing the error in the result object for \fIinterp\fR +describing the error in the result value for \fIinterp\fR unless \fIinterp\fR is NULL. If \fIsetFromAnyProc\fR is successful, it stores the new internal representation, @@ -169,7 +170,7 @@ should \fInot\fR be registered. .PP The \fIupdateStringProc\fR member contains the address of a function called to create a valid string representation -from an object's internal representation. +from a value's internal representation. .PP .CS typedef void \fBTcl_UpdateStringProc\fR( @@ -203,7 +204,7 @@ or other similar routines ask for the string representation. .SS "THE DUPINTREPPROC FIELD" .PP The \fIdupIntRepProc\fR member contains the address of a function -called to copy an internal representation from one object to another. +called to copy an internal representation from one value to another. .PP .CS typedef void \fBTcl_DupInternalRepProc\fR( @@ -215,7 +216,7 @@ typedef void \fBTcl_DupInternalRepProc\fR( internal representation. Before the call, \fIsrcPtr\fR's internal representation is valid and \fIdupPtr\fR's is not. -\fIsrcPtr\fR's object type determines what +\fIsrcPtr\fR's value type determines what copying its internal representation means. .PP For example, the \fIdupIntRepProc\fR for the Tcl integer type @@ -226,7 +227,7 @@ reasonably can. .SS "THE FREEINTREPPROC FIELD" .PP The \fIfreeIntRepProc\fR member contains the address of a function -that is called when an object is freed. +that is called when a value is freed. .PP .CS typedef void \fBTcl_FreeInternalRepProc\fR( @@ -234,22 +235,22 @@ typedef void \fBTcl_FreeInternalRepProc\fR( .CE .PP The \fIfreeIntRepProc\fR function can deallocate the storage -for the object's internal representation -and do other type-specific processing necessary when an object is freed. +for the value's internal representation +and do other type-specific processing necessary when a value is freed. .PP For example, the list type's \fIfreeIntRepProc\fR respects the storage sharing scheme established by the \fIdupIntRepProc\fR -so that it only frees storage when the last object sharing it +so that it only frees storage when the last value sharing it is being freed. .PP The \fIfreeIntRepProc\fR member can be set to NULL to indicate that the internal representation does not require freeing. The \fIfreeIntRepProc\fR implementation must not access the -\fIbytes\fR member of the object, since Tcl makes its own internal -uses of that field during object deletion. The defined tasks for +\fIbytes\fR member of the value, since Tcl makes its own internal +uses of that field during value deletion. The defined tasks for the \fIfreeIntRepProc\fR have no need to consult the \fIbytes\fR member. .SH "SEE ALSO" Tcl_NewObj(3), Tcl_DecrRefCount(3), Tcl_IncrRefCount(3) .SH KEYWORDS -internal representation, object, object type, string representation, type conversion +internal representation, value, value type, string representation, type conversion diff --git a/doc/OpenFileChnl.3 b/doc/OpenFileChnl.3 index 2368492..82f51ce 100644 --- a/doc/OpenFileChnl.3 +++ b/doc/OpenFileChnl.3 @@ -152,24 +152,24 @@ The pattern to match on, passed to Tcl_StringMatch, or NULL. A Tcl channel for input or output. Must have been the return value from a procedure such as \fBTcl_OpenFileChannel\fR. .AP Tcl_Obj *readObjPtr in/out -A pointer to a Tcl Object in which to store the characters read from the +A pointer to a Tcl value in which to store the characters read from the channel. .AP int 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 object. -Otherwise, the data will replace the existing contents of the object. +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 int bytesToRead in The number of bytes to read from the channel. The buffer \fIreadBuf\fR must be large enough to hold this many bytes. .AP Tcl_Obj *lineObjPtr in/out -A pointer to a Tcl object in which to store the line read from the +A pointer to a Tcl value in which to store the line read from the channel. The line read will be appended to the current value of the -object. +value. .AP Tcl_DString *lineRead in/out A pointer to a Tcl dynamic string in which to store the line read from the channel. Must have been initialized by the caller. The line read will be @@ -182,7 +182,7 @@ Length of the input Flag indicating whether the input should be added to the end or beginning of the channel buffer. .AP Tcl_Obj *writeObjPtr in -A pointer to a Tcl Object whose contents will be output to the channel. +A pointer to a Tcl value whose contents will be output to the channel. .AP "const char" *charBuf in A buffer containing the characters to output to the channel. .AP "const char" *byteBuf in @@ -239,7 +239,7 @@ returns NULL and records a POSIX error code that can be retrieved with \fBTcl_GetErrno\fR. In addition, if \fIinterp\fR is non-NULL, \fBTcl_OpenFileChannel\fR leaves an error message in \fIinterp\fR's result after any error. -As of Tcl 8.4, the object-based API \fBTcl_FSOpenFileChannel\fR should +As of Tcl 8.4, the value-based API \fBTcl_FSOpenFileChannel\fR should be used in preference to \fBTcl_OpenFileChannel\fR wherever possible. .PP The newly created channel is not registered in the supplied interpreter; to @@ -305,7 +305,7 @@ open for reading and writing. .PP \fBTcl_GetChannelNames\fR and \fBTcl_GetChannelNamesEx\fR write the names of the registered channels to the interpreter's result as a -list object. \fBTcl_GetChannelNamesEx\fR will filter these names +list value. \fBTcl_GetChannelNamesEx\fR will filter these names according to the \fIpattern\fR. If \fIpattern\fR is NULL, then it will not do any filtering. The return value is \fBTCL_OK\fR if no errors occurred writing to the result, otherwise it is \fBTCL_ERROR\fR, @@ -435,7 +435,7 @@ platform-specific modes are described in the manual entry for the Tcl As a performance optimization, when reading from a channel with the encoding \fBbinary\fR, the bytes are not converted to UTF-8 as they are read. Instead, they are stored in \fIreadObjPtr\fR's internal representation as a -byte-array object. The string representation of this object will only be +byte-array value. The string representation of this value will only be constructed if it is needed (e.g., because of a call to \fBTcl_GetStringFromObj\fR). In this way, byte-oriented data can be read from a channel, manipulated by calling \fBTcl_GetByteArrayFromObj\fR and @@ -484,7 +484,7 @@ of input unavailability. .PP \fBTcl_Gets\fR is the same as \fBTcl_GetsObj\fR except the resulting characters are appended to the dynamic string given by -\fIlineRead\fR rather than a Tcl object. +\fIlineRead\fR rather than a Tcl value. .SH "TCL_UNGETS" .PP \fBTcl_Ungets\fR is used to add data to the input queue of a channel, @@ -523,14 +523,14 @@ end-of-line sequences according to the \fB\-translation\fR option for the channel. This is done even if the channel has no encoding. .PP \fBTcl_WriteObj\fR is similar to \fBTcl_WriteChars\fR except it -accepts a Tcl object whose contents will be output to the channel. The +accepts a Tcl value whose contents will be output to the channel. The UTF-8 characters in \fIwriteObjPtr\fR's string representation are converted to the channel's encoding and queued for output to \fIchannel\fR. As a performance optimization, when writing to a channel with the encoding \fBbinary\fR, UTF-8 characters are not converted as they are written. Instead, the bytes in \fIwriteObjPtr\fR's internal representation as a -byte-array object are written to the channel. The byte-array representation -of the object will be constructed if it is needed. In this way, +byte-array value are written to the channel. The byte-array representation +of the value will be constructed if it is needed. In this way, byte-oriented data can be read from a channel, manipulated by calling \fBTcl_GetByteArrayFromObj\fR and related functions, and then written to a channel without the expense of ever converting to or from UTF-8. diff --git a/doc/ParseArgs.3 b/doc/ParseArgs.3 index dd33830..1ceafe5 100644 --- a/doc/ParseArgs.3 +++ b/doc/ParseArgs.3 @@ -134,7 +134,7 @@ typedef int (\fBTcl_ArgvFuncProc\fR)( .PP The result is a boolean value indicating whether to consume the following argument. The \fIclientData\fR is the value from the table entry, the -\fIobjPtr\fR is the object that represents the following argument or NULL if +\fIobjPtr\fR is the value that represents the following argument or NULL if there are no following arguments at all, and the \fIdstPtr\fR argument to the \fBTcl_ArgvFuncProc\fR is the location to write the parsed value to. .RE @@ -186,7 +186,7 @@ marks all following arguments to be left unprocessed. The \fIsrcPtr\fR, . This argument takes a following string value argument. A pointer to the string will be stored at \fIdstPtr\fR; the string inside will have a lifetime linked -to the lifetime of the string representation of the argument object that it +to the lifetime of the string representation of the argument value that it came from, and so should be copied if it needs to be retained. The \fIsrcPtr\fR and \fIclientData\fR fields are ignored. .SH "SEE ALSO" diff --git a/doc/ParseCmd.3 b/doc/ParseCmd.3 index f3b3aeb..5fd9b9c 100644 --- a/doc/ParseCmd.3 +++ b/doc/ParseCmd.3 @@ -194,9 +194,9 @@ result; it can be retrieved using \fBTcl_GetObjResult\fR. .PP \fBTcl_EvalTokens\fR differs from \fBTcl_EvalTokensStandard\fR only in the return convention used: it returns the result in a new Tcl_Obj. -The reference count of the object returned as result has been +The reference count of the value returned as result has been incremented, so the caller must -invoke \fBTcl_DecrRefCount\fR when it is finished with the object. +invoke \fBTcl_DecrRefCount\fR when it is finished with the value. If an error or other exception occurs while evaluating the tokens (such as a reference to a non-existent variable) then the return value is NULL and an error message is left in \fIinterp\fR's result. The use diff --git a/doc/RecEvalObj.3 b/doc/RecEvalObj.3 index 2eed471..44888f6 100644 --- a/doc/RecEvalObj.3 +++ b/doc/RecEvalObj.3 @@ -20,7 +20,7 @@ int .AP Tcl_Interp *interp in Tcl interpreter in which to evaluate command. .AP Tcl_Obj *cmdPtr in -Points to a Tcl object containing a command (or sequence of commands) +Points to a Tcl value containing a command (or sequence of commands) to execute. .AP int flags in An OR'ed combination of flag bits. \fBTCL_NO_EVAL\fR means record the @@ -35,7 +35,7 @@ on the history list and then execute it using \fBTcl_EvalObjEx\fR (or \fBTcl_GlobalEvalObj\fR if the \fBTCL_EVAL_GLOBAL\fR bit is set in \fIflags\fR). It returns a completion code such as \fBTCL_OK\fR just like \fBTcl_EvalObjEx\fR, -as well as a result object containing additional information +as well as a result value containing additional information (a result value or error message) that can be retrieved using \fBTcl_GetObjResult\fR. If you do not want the command recorded on the history list then @@ -50,4 +50,4 @@ the command is recorded without being evaluated. Tcl_EvalObjEx, Tcl_GetObjResult .SH KEYWORDS -command, event, execute, history, interpreter, object, record +command, event, execute, history, interpreter, value, record diff --git a/doc/RecordEval.3 b/doc/RecordEval.3 index a8f3087..a29f974 100644 --- a/doc/RecordEval.3 +++ b/doc/RecordEval.3 @@ -44,9 +44,9 @@ If the \fIflags\fR argument contains the \fBTCL_NO_EVAL\fR bit then the command is recorded without being evaluated. .PP Note that \fBTcl_RecordAndEval\fR has been largely replaced by the -object-based procedure \fBTcl_RecordAndEvalObj\fR. -That object-based procedure records and optionally executes -a command held in a Tcl object instead of a string. +value-based procedure \fBTcl_RecordAndEvalObj\fR. +That value-based procedure records and optionally executes +a command held in a Tcl value instead of a string. .SH "SEE ALSO" Tcl_RecordAndEvalObj diff --git a/doc/RegExp.3 b/doc/RegExp.3 index e10314a..882976c 100644 --- a/doc/RegExp.3 +++ b/doc/RegExp.3 @@ -45,12 +45,12 @@ void Tcl interpreter to use for error reporting. The interpreter may be NULL if no error reporting is desired. .AP Tcl_Obj *textObj in/out -Refers to the object from which to get the text to search. The -internal representation of the object may be converted to a form that +Refers to the value from which to get the text to search. The +internal representation of the value may be converted to a form that can be efficiently searched. .AP Tcl_Obj *patObj in/out -Refers to the object from which to get a regular expression. The -compiled regular expression is cached in the object. +Refers to the value from which to get a regular expression. The +compiled regular expression is cached in the value. .AP char *text in Text to search for a match with a regular expression. .AP "const char" *pattern in @@ -110,7 +110,7 @@ If an error occurs in the matching process (e.g. \fIpattern\fR is not a valid regular expression) then \fBTcl_RegExpMatch\fR returns \-1 and leaves an error message in the interpreter result. \fBTcl_RegExpMatchObj\fR is similar to \fBTcl_RegExpMatch\fR except it -operates on the Tcl objects \fItextObj\fR and \fIpatObj\fR instead of +operates on the Tcl values \fItextObj\fR and \fIpatObj\fR instead of UTF strings. \fBTcl_RegExpMatchObj\fR is generally more efficient than \fBTcl_RegExpMatch\fR, so it is the preferred interface. @@ -164,18 +164,18 @@ If there is no range corresponding to \fIindex\fR then NULL is stored in \fI*startPtr\fR and \fI*endPtr\fR. .PP \fBTcl_GetRegExpFromObj\fR, \fBTcl_RegExpExecObj\fR, and -\fBTcl_RegExpGetInfo\fR are object interfaces that provide the most +\fBTcl_RegExpGetInfo\fR are value interfaces that provide the most direct control of Henry Spencer's regular expression library. For users that need to modify compilation and execution options directly, it is recommended that you use these interfaces instead of calling the internal regexp functions. These interfaces handle the details of UTF to Unicode translations as well as providing improved performance -through caching in the pattern and string objects. +through caching in the pattern and string values. .PP \fBTcl_GetRegExpFromObj\fR attempts to return a compiled regular -expression from the \fIpatObj\fR. If the object does not already +expression from the \fIpatObj\fR. If the value does not already contain a compiled regular expression it will attempt to create one -from the string in the object and assign it to the internal +from the string in the value and assign it to the internal representation of the \fIpatObj\fR. The return value of this function is of type \fBTcl_RegExp\fR. The return value is a token for this compiled form, which can be used in subsequent calls to diff --git a/doc/SaveResult.3 b/doc/SaveResult.3 index d6ea48d..8eaf38f 100644 --- a/doc/SaveResult.3 +++ b/doc/SaveResult.3 @@ -96,12 +96,12 @@ or \fBTcl_DiscardInterpState\fR to avoid a memory leak. Once the \fBTcl_InterpState\fR token is passed to one of them, the token is no longer valid and should not be used anymore. .PP -\fBTcl_SaveResult\fR moves the string and object results +\fBTcl_SaveResult\fR moves the string and value results of \fIinterp\fR into the location specified by \fIstatePtr\fR. \fBTcl_SaveResult\fR clears the result for \fIinterp\fR and leaves the result in its normal empty initialized state. .PP -\fBTcl_RestoreResult\fR moves the string and object results from +\fBTcl_RestoreResult\fR moves the string and value results from \fIstatePtr\fR back into \fIinterp\fR. Any result or error that was already in the interpreter will be cleared. The \fIstatePtr\fR is left in an uninitialized state and cannot be used until another call to diff --git a/doc/SetChanErr.3 b/doc/SetChanErr.3 index 0a62dac..3d37f59 100644 --- a/doc/SetChanErr.3 +++ b/doc/SetChanErr.3 @@ -55,12 +55,12 @@ arrange for their return as errors. The POSIX error codes set by a driver are used now if and only if no messages are present. .PP \fBTcl_SetChannelError\fR stores error information in the bypass area of the -specified channel. The number of references to the \fBmsg\fR object goes up by +specified channel. The number of references to the \fBmsg\fR value goes up by one. Previously stored information will be discarded, by releasing the reference held by the channel. The channel reference must not be NULL. .PP \fBTcl_SetChannelErrorInterp\fR stores error information in the bypass area of -the specified interpreter. The number of references to the \fBmsg\fR object +the specified interpreter. The number of references to the \fBmsg\fR value goes up by one. Previously stored information will be discarded, by releasing the reference held by the interpreter. The interpreter reference must not be NULL. @@ -72,7 +72,7 @@ NULL, until an intervening invocation of \fBTcl_SetChannelError\fR with a non-NULL message. The \fImsgPtr\fR must not be NULL. The reference count of the message is not touched. The reference previously held by the channel is now held by the caller of the function and it is its responsibility to release -that reference when it is done with the object. +that reference when it is done with the value. .PP \fBTcl_GetChannelErrorInterp\fR places either the error message held in the bypass area of the specified interpreter into \fImsgPtr\fR, or NULL; and @@ -82,7 +82,7 @@ return NULL, until an intervening invocation of not be NULL. The reference count of the message is not touched. The reference previously held by the interpreter is now held by the caller of the function and it is its responsibility to release that reference when it is done with -the object. +the value. .PP Which functions of a channel driver are allowed to use which bypass function is listed below, as is which functions of the public channel API may leave a diff --git a/doc/SetResult.3 b/doc/SetResult.3 index c308193..bbeedf1 100644 --- a/doc/SetResult.3 +++ b/doc/SetResult.3 @@ -42,7 +42,7 @@ const char * .AP Tcl_Interp *interp out Interpreter whose result is to be modified or read. .AP Tcl_Obj *objPtr in -Object value to become result for \fIinterp\fR. +Tcl value to become result for \fIinterp\fR. .AP char *result in String value to become result for \fIinterp\fR or to be appended to the existing result. @@ -74,32 +74,32 @@ information as well. .PP The procedures described here are utilities for manipulating the result value in a Tcl interpreter. -The interpreter result may be either a Tcl object or a string. +The interpreter result may be either a Tcl value or a string. For example, \fBTcl_SetObjResult\fR and \fBTcl_SetResult\fR -set the interpreter result to, respectively, an object and a string. +set the interpreter result to, respectively, a value and a string. Similarly, \fBTcl_GetObjResult\fR and \fBTcl_GetStringResult\fR -return the interpreter result as an object and as a string. -The procedures always keep the string and object forms +return the interpreter result as a value and as a string. +The procedures always keep the string and value forms of the interpreter result consistent. For example, if \fBTcl_SetObjResult\fR is called to set -the result to an object, +the result to a value, then \fBTcl_GetStringResult\fR is called, -it will return the object's string value. +it will return the value's string representation. .PP \fBTcl_SetObjResult\fR arranges for \fIobjPtr\fR to be the result for \fIinterp\fR, replacing any existing result. -The result is left pointing to the object +The result is left pointing to the value referenced by \fIobjPtr\fR. \fIobjPtr\fR's reference count is incremented since there is now a new reference to it from \fIinterp\fR. -The reference count for any old result object -is decremented and the old result object is freed if no +The reference count for any old result value +is decremented and the old result value is freed if no references to it remain. .PP -\fBTcl_GetObjResult\fR returns the result for \fIinterp\fR as an object. -The object's reference count is not incremented; -if the caller needs to retain a long-term pointer to the object +\fBTcl_GetObjResult\fR returns the result for \fIinterp\fR as a value. +The value's reference count is not incremented; +if the caller needs to retain a long-term pointer to the value they should use \fBTcl_IncrRefCount\fR to increment its reference count in order to keep it from being freed too early or accidentally changed. .PP @@ -115,19 +115,19 @@ and \fBTcl_SetResult\fR re-initializes \fIinterp\fR's result to point to an empty string. .PP \fBTcl_GetStringResult\fR returns the result for \fIinterp\fR as a string. -If the result was set to an object by a \fBTcl_SetObjResult\fR call, -the object form will be converted to a string and returned. -If the object's string representation contains null bytes, +If the result was set to a value by a \fBTcl_SetObjResult\fR call, +the value form will be converted to a string and returned. +If the value's string representation contains null bytes, this conversion will lose information. For this reason, programmers are encouraged to -write their code to use the new object API procedures +write their code to use the new value API procedures and to call \fBTcl_GetObjResult\fR instead. .PP \fBTcl_ResetResult\fR clears the result for \fIinterp\fR and leaves the result in its normal empty initialized state. -If the result is an object, +If the result is a value, its reference count is decremented and the result is left -pointing to an unshared object representing an empty string. +pointing to an unshared value representing an empty string. If the result is a dynamically allocated string, its memory is free*d and the result is left as a empty string. \fBTcl_ResetResult\fR also clears the error state managed by @@ -167,7 +167,7 @@ The source interpreter will have its result reset by this operation. Use of the following procedures (is deprecated since they manipulate the Tcl result as a string. Procedures such as \fBTcl_SetObjResult\fR -that manipulate the result as an object +that manipulate the result as a value can be significantly more efficient. .PP \fBTcl_AppendElement\fR is similar to \fBTcl_AppendResult\fR in @@ -252,4 +252,4 @@ the value of \fIresult\fR passed to \fBTcl_SetResult\fR. .SH "SEE ALSO" Tcl_AddErrorInfo, Tcl_CreateObjCommand, Tcl_SetErrorCode, Tcl_Interp .SH KEYWORDS -append, command, element, list, object, result, return value, interpreter +append, command, element, list, value, result, return value, interpreter diff --git a/doc/SetVar.3 b/doc/SetVar.3 index ce47a73..0605ff2 100644 --- a/doc/SetVar.3 +++ b/doc/SetVar.3 @@ -57,7 +57,7 @@ to specify a variable in a particular namespace. If non-NULL, gives name of element within array; in this case \fIname1\fR must refer to an array variable. .AP Tcl_Obj *newValuePtr in -Points to a Tcl object containing the new value for the variable. +Points to a Tcl value containing the new value for the variable. .AP int flags in OR-ed combination of bits providing additional information. See below for valid values. @@ -71,12 +71,12 @@ an array. New value for variable, specified as a null-terminated string. A copy of this value is stored in the variable. .AP Tcl_Obj *part1Ptr in -Points to a Tcl object containing the variable's name. +Points to a Tcl value containing the variable's name. The name may include a series of \fB::\fR namespace qualifiers to specify a variable in a particular namespace. May refer to a scalar variable or an element of an array variable. .AP Tcl_Obj *part2Ptr in -If non-NULL, points to an object containing the name of an element +If non-NULL, points to a value containing the name of an element within an array and \fIpart1Ptr\fR must refer to an array variable. .BE @@ -246,4 +246,4 @@ array is removed. Tcl_GetObjResult, Tcl_GetStringResult, Tcl_TraceVar .SH KEYWORDS -array, get variable, interpreter, object, scalar, set, unset, variable +array, get variable, interpreter, scalar, set, unset, value, variable diff --git a/doc/SplitPath.3 b/doc/SplitPath.3 index 7fdfce6..3fd92ac 100644 --- a/doc/SplitPath.3 +++ b/doc/SplitPath.3 @@ -43,7 +43,7 @@ A pointer to an initialized \fBTcl_DString\fR to which the result of .SH DESCRIPTION .PP -These procedures have been superseded by the objectified procedures in +These procedures have been superseded by the Tcl-value-aware procedures in the \fBFileSystem\fR man page, which are more efficient. .PP These procedures may be used to disassemble and reassemble file diff --git a/doc/StringObj.3 b/doc/StringObj.3 index 412ab78..e6f9d32 100644 --- a/doc/StringObj.3 +++ b/doc/StringObj.3 @@ -8,7 +8,7 @@ .TH Tcl_StringObj 3 8.1 Tcl "Tcl Library Procedures" .BS .SH NAME -Tcl_NewStringObj, Tcl_NewUnicodeObj, Tcl_SetStringObj, Tcl_SetUnicodeObj, Tcl_GetStringFromObj, Tcl_GetString, Tcl_GetUnicodeFromObj, Tcl_GetUnicode, Tcl_GetUniChar, Tcl_GetCharLength, Tcl_GetRange, Tcl_AppendToObj, Tcl_AppendUnicodeToObj, Tcl_AppendObjToObj, Tcl_AppendStringsToObj, Tcl_AppendStringsToObjVA, Tcl_AppendLimitedToObj, Tcl_Format, Tcl_AppendFormatToObj, Tcl_ObjPrintf, Tcl_AppendPrintfToObj, Tcl_SetObjLength, Tcl_AttemptSetObjLength, Tcl_ConcatObj \- manipulate Tcl objects as strings +Tcl_NewStringObj, Tcl_NewUnicodeObj, Tcl_SetStringObj, Tcl_SetUnicodeObj, Tcl_GetStringFromObj, Tcl_GetString, Tcl_GetUnicodeFromObj, Tcl_GetUnicode, Tcl_GetUniChar, Tcl_GetCharLength, Tcl_GetRange, Tcl_AppendToObj, Tcl_AppendUnicodeToObj, Tcl_AppendObjToObj, Tcl_AppendStringsToObj, Tcl_AppendStringsToObjVA, Tcl_AppendLimitedToObj, Tcl_Format, Tcl_AppendFormatToObj, Tcl_ObjPrintf, Tcl_AppendPrintfToObj, Tcl_SetObjLength, Tcl_AttemptSetObjLength, Tcl_ConcatObj \- manipulate Tcl values as strings .SH SYNOPSIS .nf \fB#include <tcl.h>\fR @@ -88,7 +88,7 @@ Tcl_Obj * .AS "const Tcl_UniChar" *appendObjPtr in/out .AP "const char" *bytes in Points to the first byte of an array of UTF-8-encoded bytes -used to set or append to a string object. +used to set or append to a string value. This byte array may contain embedded null characters unless \fInumChars\fR is negative. (Applications needing null bytes should represent them as the two-byte sequence \fI\e700\e600\fR, use @@ -96,32 +96,32 @@ should represent them as the two-byte sequence \fI\e700\e600\fR, use the string is a collection of uninterpreted bytes.) .AP int length in The number of bytes to copy from \fIbytes\fR when -initializing, setting, or appending to a string object. +initializing, setting, or appending to a string value. If negative, all bytes up to the first null are used. .AP "const Tcl_UniChar" *unicode in Points to the first byte of an array of Unicode characters -used to set or append to a string object. +used to set or append to a string value. This byte array may contain embedded null characters unless \fInumChars\fR is negative. .AP int numChars in The number of Unicode characters to copy from \fIunicode\fR when -initializing, setting, or appending to a string object. +initializing, setting, or appending to a string value. If negative, all characters up to the first null character are used. .AP int index in The index of the Unicode character to return. .AP int first in The index of the first Unicode character in the Unicode range to be -returned as a new object. +returned as a new value. .AP int last in The index of the last Unicode character in the Unicode range to be -returned as a new object. +returned as a new value. .AP Tcl_Obj *objPtr in/out -Points to an object to manipulate. +Points to a value to manipulate. .AP Tcl_Obj *appendObjPtr in -The object to append to \fIobjPtr\fR in \fBTcl_AppendObjToObj\fR. +The value to append to \fIobjPtr\fR in \fBTcl_AppendObjToObj\fR. .AP int *lengthPtr out If non-NULL, the location where \fBTcl_GetStringFromObj\fR will store -the length of an object's string representation. +the length of a value's string representation. .AP "const char" *string in Null-terminated string value to append to \fIobjPtr\fR. .AP va_list argList in @@ -139,46 +139,46 @@ Format control string including % conversion specifiers. .AP int objc in The number of elements to format or concatenate. .AP Tcl_Obj *objv[] in -The array of objects to format or concatenate. +The array of values to format or concatenate. .AP int newLength in New length for the string value of \fIobjPtr\fR, not including the final null character. .BE .SH DESCRIPTION .PP -The procedures described in this manual entry allow Tcl objects to +The procedures described in this manual entry allow Tcl values to be manipulated as string values. They use the internal representation -of the object to store additional information to make the string +of the value to store additional information to make the string manipulations more efficient. In particular, they make a series of append operations efficient by allocating extra storage space for the string so that it does not have to be copied for each append. Also, indexing and length computations are optimized because the Unicode string representation is calculated and cached as needed. When using the \fBTcl_Append*\fR family of functions where the -interpreter's result is the object being appended to, it is important +interpreter's result is the value being appended to, it is important to call Tcl_ResetResult first to ensure you are not unintentionally -appending to existing data in the result object. +appending to existing data in the result value. .PP -\fBTcl_NewStringObj\fR and \fBTcl_SetStringObj\fR create a new object -or modify an existing object to hold a copy of the string given by +\fBTcl_NewStringObj\fR and \fBTcl_SetStringObj\fR create a new value +or modify an existing value to hold a copy of the string given by \fIbytes\fR and \fIlength\fR. \fBTcl_NewUnicodeObj\fR and -\fBTcl_SetUnicodeObj\fR create a new object or modify an existing -object to hold a copy of the Unicode string given by \fIunicode\fR and +\fBTcl_SetUnicodeObj\fR create a new value or modify an existing +value to hold a copy of the Unicode string given by \fIunicode\fR and \fInumChars\fR. \fBTcl_NewStringObj\fR and \fBTcl_NewUnicodeObj\fR -return a pointer to a newly created object with reference count zero. -All four procedures set the object to hold a copy of the specified +return a pointer to a newly created value with reference count zero. +All four procedures set the value to hold a copy of the specified string. \fBTcl_SetStringObj\fR and \fBTcl_SetUnicodeObj\fR free any old string representation as well as any old internal representation -of the object. +of the value. .PP -\fBTcl_GetStringFromObj\fR and \fBTcl_GetString\fR return an object's +\fBTcl_GetStringFromObj\fR and \fBTcl_GetString\fR return a value's string representation. This is given by the returned byte pointer and (for \fBTcl_GetStringFromObj\fR) length, which is stored in -\fIlengthPtr\fR if it is non-NULL. If the object's UTF string +\fIlengthPtr\fR if it is non-NULL. If the value's UTF string representation is invalid (its byte pointer is NULL), the string -representation is regenerated from the object's internal +representation is regenerated from the value's internal representation. The storage referenced by the returned byte pointer -is owned by the object manager. It is passed back as a writable +is owned by the value manager. It is passed back as a writable pointer so that extension author creating their own \fBTcl_ObjType\fR will be able to modify the string representation within the \fBTcl_UpdateStringProc\fR of their \fBTcl_ObjType\fR. Except for that @@ -194,45 +194,45 @@ The procedure \fBTcl_GetString\fR is used in the common case where the caller does not need the length of the string representation. .PP -\fBTcl_GetUnicodeFromObj\fR and \fBTcl_GetUnicode\fR return an object's +\fBTcl_GetUnicodeFromObj\fR and \fBTcl_GetUnicode\fR return a value's value as a Unicode string. This is given by the returned pointer and (for \fBTcl_GetUnicodeFromObj\fR) length, which is stored in \fIlengthPtr\fR if it is non-NULL. The storage referenced by the returned -byte pointer is owned by the object manager and should not be modified by +byte pointer is owned by the value manager and should not be modified by the caller. The procedure \fBTcl_GetUnicode\fR is used in the common case where the caller does not need the length of the unicode string representation. .PP \fBTcl_GetUniChar\fR returns the \fIindex\fR'th character in the -object's Unicode representation. +value's Unicode representation. .PP -\fBTcl_GetRange\fR returns a newly created object comprised of the +\fBTcl_GetRange\fR returns a newly created value comprised of the characters between \fIfirst\fR and \fIlast\fR (inclusive) in the -object's Unicode representation. If the object's Unicode +value's Unicode representation. If the value's Unicode representation is invalid, the Unicode representation is regenerated -from the object's string representation. +from the value's string representation. .PP \fBTcl_GetCharLength\fR returns the number of characters (as opposed -to bytes) in the string object. +to bytes) in the string value. .PP \fBTcl_AppendToObj\fR appends the data given by \fIbytes\fR and -\fIlength\fR to the string representation of the object specified by -\fIobjPtr\fR. If the object has an invalid string representation, +\fIlength\fR to the string representation of the value specified by +\fIobjPtr\fR. If the value has an invalid string representation, then an attempt is made to convert \fIbytes\fR is to the Unicode format. If the conversion is successful, then the converted form of -\fIbytes\fR is appended to the object's Unicode representation. -Otherwise, the object's Unicode representation is invalidated and +\fIbytes\fR is appended to the value's Unicode representation. +Otherwise, the value's Unicode representation is invalidated and converted to the UTF format, and \fIbytes\fR is appended to the -object's new string representation. +value's new string representation. .PP \fBTcl_AppendUnicodeToObj\fR appends the Unicode string given by -\fIunicode\fR and \fInumChars\fR to the object specified by -\fIobjPtr\fR. If the object has an invalid Unicode representation, +\fIunicode\fR and \fInumChars\fR to the value specified by +\fIobjPtr\fR. If the value has an invalid Unicode representation, then \fIunicode\fR is converted to the UTF format and appended to the -object's string representation. Appends are optimized to handle +value's string representation. Appends are optimized to handle repeated appends relatively efficiently (it over-allocates the string or Unicode space to avoid repeated reallocations and copies of -object's string value). +value's string value). .PP \fBTcl_AppendObjToObj\fR is similar to \fBTcl_AppendToObj\fR, but it appends the string or Unicode value (whichever exists and is best @@ -345,14 +345,14 @@ functionality is needed. .PP The \fBTcl_SetObjLength\fR procedure changes the length of the string value of its \fIobjPtr\fR argument. If the \fInewLength\fR -argument is greater than the space allocated for the object's +argument is greater than the space allocated for the value's string, then the string space is reallocated and the old value is copied to the new space; the bytes between the old length of the string and the new length may have arbitrary values. If the \fInewLength\fR argument is less than the current length -of the object's string, with \fIobjPtr->length\fR is reduced without +of the value's string, with \fIobjPtr->length\fR is reduced without reallocating the string space; the original allocated size for the -string is recorded in the object, so that the string length can be +string is recorded in the value, so that the string length can be enlarged in a subsequent call to \fBTcl_SetObjLength\fR without reallocating storage. In all cases \fBTcl_SetObjLength\fR leaves a null character at \fIobjPtr->bytes[newLength]\fR. @@ -361,24 +361,24 @@ a null character at \fIobjPtr->bytes[newLength]\fR. \fBTcl_SetObjLength\fR except that if sufficient memory to satisfy the request cannot be allocated, it does not cause the Tcl interpreter to \fBpanic\fR. Thus, if \fInewLength\fR is greater than the space -allocated for the object's string, and there is not enough memory +allocated for the value's string, and there is not enough memory available to satisfy the request, \fBTcl_AttemptSetObjLength\fR will take no action and return 0 to indicate failure. If there is enough memory to satisfy the request, \fBTcl_AttemptSetObjLength\fR behaves just like \fBTcl_SetObjLength\fR and returns 1 to indicate success. .PP -The \fBTcl_ConcatObj\fR function returns a new string object whose +The \fBTcl_ConcatObj\fR function returns a new string value whose value is the space-separated concatenation of the string -representations of all of the objects in the \fIobjv\fR +representations of all of the values in the \fIobjv\fR array. \fBTcl_ConcatObj\fR eliminates leading and trailing white space as it copies the string representations of the \fIobjv\fR array to the result. If an element of the \fIobjv\fR array consists of nothing but -white space, then that object is ignored entirely. This white-space +white space, then that value is ignored entirely. This white-space removal was added to make the output of the \fBconcat\fR command cleaner-looking. \fBTcl_ConcatObj\fR returns a pointer to a -newly-created object whose ref count is zero. +newly-created value whose ref count is zero. .SH "SEE ALSO" Tcl_NewObj(3), Tcl_IncrRefCount(3), Tcl_DecrRefCount(3), format(n), sprintf(3) .SH KEYWORDS -append, internal representation, object, object type, string object, +append, internal representation, value, value type, string value, string type, string representation, concat, concatenate, unicode diff --git a/doc/SubstObj.3 b/doc/SubstObj.3 index 786b595..d5a52c3 100644 --- a/doc/SubstObj.3 +++ b/doc/SubstObj.3 @@ -8,7 +8,7 @@ .TH Tcl_SubstObj 3 8.4 Tcl "Tcl Library Procedures" .BS .SH NAME -Tcl_SubstObj \- perform substitutions on Tcl objects +Tcl_SubstObj \- perform substitutions on Tcl values .SH SYNOPSIS .nf \fB#include <tcl.h>\fR @@ -22,7 +22,7 @@ Interpreter in which to execute Tcl scripts and lookup variables. If an error occurs, the interpreter's result is modified to hold an error message. .AP Tcl_Obj *objPtr in -A Tcl object containing the string to perform substitutions on. +A Tcl value containing the string to perform substitutions on. .AP int flags in ORed combination of flag bits that specify which substitutions to perform. The flags \fBTCL_SUBST_COMMANDS\fR, @@ -36,7 +36,7 @@ The \fBTcl_SubstObj\fR function is used to perform substitutions on strings in the fashion of the \fBsubst\fR command. It gets the value of the string contained in \fIobjPtr\fR and scans it, copying characters and performing the chosen substitutions as it goes to an -output object which is returned as the result of the function. In the +output value which is returned as the result of the function. In the event of an error occurring during the execution of a command or variable substitution, the function returns NULL and an error message is left in \fIinterp\fR's result. diff --git a/doc/TCL_MEM_DEBUG.3 b/doc/TCL_MEM_DEBUG.3 index 05d4564..5a3e08a 100644 --- a/doc/TCL_MEM_DEBUG.3 +++ b/doc/TCL_MEM_DEBUG.3 @@ -26,7 +26,7 @@ version of \fBTcl_InitMemory\fR to add the \fBmemory\fR command to Tcl. \fBTCL_MEM_DEBUG\fR must be either left defined for all modules or undefined for all modules that are going to be linked together. If they are not, link errors will occur, with either \fBTcl_DbCkfree\fR and \fBTcl_DbCkalloc\fR or -\fBTcl_Ckalloc\fR and \fBTcl_Ckfree\fR being undefined. +\fBTcl_Alloc\fR and \fBTcl_Free\fR being undefined. .PP Once memory debugging support has been compiled into Tcl, the C functions \fBTcl_ValidateAllMemory\fR, and \fBTcl_DumpActiveMemory\fR, diff --git a/doc/TclZlib.3 b/doc/TclZlib.3 index 1b5e892..854a525 100644 --- a/doc/TclZlib.3 +++ b/doc/TclZlib.3 @@ -49,9 +49,11 @@ int .sp int \fBTcl_ZlibStreamGet\fR(\fIzshandle, dataObj, count\fR) +.sp +\fBTcl_ZlibStreamSetCompressionDictionary\fR(\fIzshandle, compDict\fR) .fi .SH ARGUMENTS -.AS Tcl_ZlibStream *zshandlePtr out +.AS Tcl_ZlibStream zshandle in .AP Tcl_Interp *interp in The interpreter to store resulting compressed or uncompressed data in. Also where any error messages are written. For \fBTcl_ZlibStreamInit\fR, this can @@ -64,7 +66,7 @@ addition, for decompression only, \fBTCL_ZLIB_FORMAT_AUTO\fR may also be chosen which can automatically detect whether the compressed data was in zlib or gzip format. .AP Tcl_Obj *dataObj in/out -A byte-array object containing the data to be compressed or decompressed, or +A byte-array value containing the data to be compressed or decompressed, or to which the data extracted from the stream is appended when passed to \fBTcl_ZlibStreamGet\fR. .AP int level in @@ -108,6 +110,13 @@ trailer demanded by the format is written. .AP int count in The maximum number of bytes to get from the stream, or -1 to get all remaining bytes from the stream's buffers. +.AP Tcl_Obj *compDict in +A byte array value that is the compression dictionary to use with the stream. +Note that this is \fInot a Tcl dictionary\fR, and it is recommended that this +only ever be used with streams that were created with their \fIformat\fR set +to \fBTCL_ZLIB_FORMAT_ZLIB\fR because the other formats have no mechanism to +indicate whether a compression dictionary was present other than to fail on +decompression. .BE .SH DESCRIPTION These functions form the interface from the Tcl library to the Zlib @@ -122,7 +131,7 @@ the dictionary is only used when the \fIformat\fR parameter is \fBTCL_ZLIB_FORMAT_GZIP\fR or \fBTCL_ZLIB_FORMAT_AUTO\fR. For details of the contents of the dictionary, see the \fBGZIP OPTIONS DICTIONARY\fR section below. Upon success, both functions leave the resulting compressed or -decompressed data in a byte-array object that is the Tcl interpreter's result; +decompressed data in a byte-array value that is the Tcl interpreter's result; the returned value is a standard Tcl result code. .PP \fBTcl_ZlibAdler32\fR and \fBTcl_ZlibCRC32\fR compute checksums on arrays of @@ -154,7 +163,7 @@ the \fBGZIP OPTIONS DICTIONARY\fR section below) can be given via the headers, and on decompression allows discovery of the existing headers. Note that the dictionary will be written to on decompression once sufficient data has been read to have a complete header. This means that the dictionary must -be an unshared object in that case; a blank object created with +be an unshared value in that case; a blank value created with \fBTcl_NewObj\fR is suggested. .PP Once a stream has been constructed, \fBTcl_ZlibStreamPut\fR is used to add @@ -162,8 +171,8 @@ data to the stream and \fBTcl_ZlibStreamGet\fR is used to retrieve data from the stream after processing. Both return normal Tcl result codes and leave an error message in the result of the interpreter that the stream is registered with in the error case (if such a registration has been performed). With -\fBTcl_ZlibStreamPut\fR, the data buffer object passed to it should not be -modified afterwards. With \fBTcl_ZlibStreamGet\fR, the data buffer object +\fBTcl_ZlibStreamPut\fR, the data buffer value passed to it should not be +modified afterwards. With \fBTcl_ZlibStreamGet\fR, the data buffer value passed to it will have the data bytes appended to it. Internally to the stream, data is kept compressed so as to minimize the cost of buffer space. .PP @@ -172,6 +181,25 @@ uncompressed data according to the format, and \fBTcl_ZlibStreamEof\fR returns a boolean value indicating whether the end of the uncompressed data has been reached. .PP +\fBTcl_ZlibStreamSetCompressionDictionary\fR is used to control the +compression dictionary used with the stream, a compression dictionary being an +array of bytes (such as might be created with \fBTcl_NewByteArrayObj\fR) that +is used to initialize the compression engine rather than leaving it to create +it on the fly from the data being compressed. Setting a compression dictionary +allows for more efficient compression in the case where the start of the data +is highly regular, but it does require both the compressor and the +decompressor to agreee on the value to use. Compression dictionaries are only +fully supported for zlib-format data; on compression, they must be set before +any data is sent in with \fBTcl_ZlibStreamPut\fR, and on decompression they +should be set when \fBTcl_ZlibStreamGet\fR produces an \fBerror\fR with its +\fB\-errorcode\fR set to +.QW "\fBZLIB NEED_DICT\fI code\fR" ; +the \fIcode\fR will be the Adler-32 checksum (see \fBTcl_ZlibAdler32\fR) of +the compression dictionary sought. (Note that this is only true for +zlib-format streams; gzip streams ignore compression dictionaries as the +format specification doesn't permit them, and raw streams just produce a data +error if the compression dictionary is missing or incorrect.) +.PP If you wish to clear a stream and reuse it for a new compression or decompression action, \fBTcl_ZlibStreamReset\fR will do this and return a normal Tcl result code to indicate whether it was successful; if the stream is @@ -187,9 +215,9 @@ and \fBTcl_ZlibStreamInit\fR is used to pass a dictionary of options about that is used to describe the gzip header in the compressed data. When creating compressed data, the dictionary is read and when unpacking compressed data the dictionary is written (in which case the \fIdictObj\fR parameter must refer to -an unshared dictionary object). +an unshared dictionary value). .PP -The following fields in the dictionary object are understood. All other fields +The following fields in the dictionary value are understood. All other fields are ignored. No field is required when creating a gzip-format stream. .TP \fBcomment\fR diff --git a/doc/WrongNumArgs.3 b/doc/WrongNumArgs.3 index a2908e9..15d5caf 100644 --- a/doc/WrongNumArgs.3 +++ b/doc/WrongNumArgs.3 @@ -18,7 +18,7 @@ Tcl_WrongNumArgs \- generate standard error message for wrong number of argument .AS "Tcl_Obj *const" *message .AP Tcl_Interp interp in Interpreter in which error will be reported: error message gets stored -in its result object. +in its result value. .AP int objc in Number of leading arguments from \fIobjv\fR to include in error message. @@ -34,13 +34,13 @@ of the command. This argument may be NULL. \fBTcl_WrongNumArgs\fR is a utility procedure that is invoked by command procedures when they discover that they have received the wrong number of arguments. \fBTcl_WrongNumArgs\fR generates a -standard error message and stores it in the result object of +standard error message and stores it in the result value of \fIinterp\fR. The message includes the \fIobjc\fR initial elements of \fIobjv\fR plus \fImessage\fR. For example, if \fIobjv\fR consists of the values \fBfoo\fR and \fBbar\fR, \fIobjc\fR is 1, and \fImessage\fR is .QW "\fBfileName count\fR" -then \fIinterp\fR's result object will be set to the following +then \fIinterp\fR's result value will be set to the following string: .PP .CS @@ -57,17 +57,17 @@ wrong # args: should be "foo bar fileName count" \fBstring\fR and the Tk widget commands, which use the first argument as a subcommand. .PP -Some of the objects in the \fIobjv\fR array may be abbreviations for +Some of the values in the \fIobjv\fR array may be abbreviations for a subcommand. The command -\fBTcl_GetIndexFromObj\fR will convert the abbreviated string object +\fBTcl_GetIndexFromObj\fR will convert the abbreviated string value into an \fIindexObject\fR. If an error occurs in the parsing of the subcommand we would like to use the full subcommand name rather than the abbreviation. If the \fBTcl_WrongNumArgs\fR command finds any \fIindexObjects\fR in the \fIobjv\fR array it will use the full subcommand name in the error message instead of the abbreviated name that was originally passed in. Using the above example, let us assume that -\fIbar\fR is actually an abbreviation for \fIbarfly\fR and the object -is now an indexObject because it was passed to +\fIbar\fR is actually an abbreviation for \fIbarfly\fR and the value +is now an \fIindexObject\fR because it was passed to \fBTcl_GetIndexFromObj\fR. In this case the error message would be: .PP .CS @@ -83,12 +83,14 @@ asynchronous invocation. The command returns an error message if the script did not run, unless the \fB\-async\fR flag was used, in which case the command returns immediately with no error. .VS 8.6 -The \fB\-binary\fR option treats \fIdata\fR as binary data, otherwise an utf-8 -string is sent. Combining \fB-binary\fR with the result of -\fBencoding convertto\fR may be used to send data in arbitrary encodings. +Without the \fB\-binary\fR option all data will be sent in unicode. For +dde clients which don't implement the CF_UNICODE clipboard format, this +will automatically be translated to the system encoding. You can use +the \fB\-binary\fR option in combination with the result of +\fBencoding convertto\fR to send data in any other encoding. .VE 8.6 .TP -\fBdde poke ?\fB\-binary\fR? \fIservice topic item data\fR +\fBdde poke\fR ?\fB\-binary\fR? \fIservice topic item data\fR . \fBdde poke\fR passes the \fIdata\fR to the server indicated by \fIservice\fR using the \fItopic\fR and \fIitem\fR specified. Typically, @@ -98,8 +100,11 @@ on. The \fIitem\fR is also application specific and is often not used, but it must always be non-null. The \fIdata\fR field is given to the remote application. .VS 8.6 -The \fB\-binary\fR option treats \fIdata\fR as binary data, otherwise an utf-8 -string is sent. +Without the \fB\-binary\fR option all data will be sent in unicode. For +dde clients which don't implement the CF_UNICODE clipboard format, this +will automatically be translated to the system encoding. You can use +the \fB\-binary\fR option in combination with the result of +\fBencoding convertto\fR to send data in any other encoding. .VE 8.6 .TP \fBdde request\fR ?\fB\-binary\fR? \fIservice topic item\fR diff --git a/doc/define.n b/doc/define.n index 6bdd9c5..1c36ca3 100644 --- a/doc/define.n +++ b/doc/define.n @@ -152,7 +152,7 @@ and operates identically to .QW "\fBoo::objdefine \fIcls subcommand ...\fR" . .TP -\fBsuperclass\fI ?\fI\-slotOperation\fR? \fR?\fIclassName ...\fR? +\fBsuperclass\fR ?\fI\-slotOperation\fR? ?\fIclassName ...\fR? .VS This slot (see \fBSLOTTED DEFINITIONS\fR below) .VE @@ -147,6 +147,31 @@ keys are treated as if they map to an empty list, and it is legal for there to be no items to append to the list. It is an error for the value that the key maps to to not be representable as a list. .TP +\fBdict map \fR{\fIkeyVar valueVar\fR} \fIdictionaryValue body\fR +. +This command applies a transformation to each element of a dictionary, +returning a new dictionary. It takes three arguments: the first is a +two-element list of variable names (for the key and value respectively of each +mapping in the dictionary), the second the dictionary value to iterate across, +and the third a script to be evaluated for each mapping with the key and value +variables set appropriately (in the manner of \fBlmap\fR). In an iteration +where the evaluated script completes normally (\fBTCL_OK\fR, as opposed to an +\fBerror\fR, etc.) the result of the script is put into an accumulator +dictionary using the key that is the current contents of the \fIkeyVar\fR +variable at that point. The result of the \fBdict map\fR command is the +accumulator dictionary after all keys have been iterated over. +.RS +.PP +If the evaluation of the body for any particular step generates a \fBbreak\fR, +no further pairs from the dictionary will be iterated over and the \fBdict +map\fR command will terminate successfully immediately. If the evaluation of +the body for a particular step generates a \fBcontinue\fR result, the current +iteration is aborted and the accumulator dictionary is not modified. The order +of iteration is the natural order of the dictionary (typically the order in +which the keys were added to the dictionary; the order is the same as that +used in \fBdict for\fR). +.RE +.TP \fBdict merge \fR?\fIdictionaryValue ...\fR? . Return a dictionary that contains the contents of each of the @@ -408,9 +433,9 @@ puts $foo # prints: \fIa b foo {a b} bar 2 baz 3\fR .CE .SH "SEE ALSO" -append(n), array(n), foreach(n), incr(n), list(n), lappend(n), set(n) +append(n), array(n), foreach(n), mapeach(n), incr(n), list(n), lappend(n), set(n) .SH KEYWORDS -dictionary, create, update, lookup, iterate, filter +dictionary, create, update, lookup, iterate, filter, map '\" Local Variables: '\" mode: nroff '\" End: diff --git a/doc/lmap.n b/doc/lmap.n new file mode 100644 index 0000000..880b05a --- /dev/null +++ b/doc/lmap.n @@ -0,0 +1,85 @@ +'\" +'\" Copyright (c) 2012 Trevor Davel +'\" +'\" See the file "license.terms" for information on usage and redistribution +'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. +'\" +.so man.macros +.TH lmap n "" Tcl "Tcl Built-In Commands" +.BS +'\" Note: do not modify the .SH NAME line immediately below! +.SH NAME +lmap \- Iterate over all elements in one or more lists and collect results +.SH SYNOPSIS +\fBlmap \fIvarname list body\fR +.br +\fBlmap \fIvarlist1 list1\fR ?\fIvarlist2 list2 ...\fR? \fIbody\fR +.BE +.SH DESCRIPTION +.PP +The \fBlmap\fR command implements a loop where the loop variable(s) take on +values from one or more lists, and the loop returns a list of results +collected from each iteration. +.PP +In the simplest case there is one loop variable, \fIvarname\fR, and one list, +\fIlist\fR, that is a list of values to assign to \fIvarname\fR. The +\fIbody\fR argument is a Tcl script. For each element of \fIlist\fR (in order +from first to last), \fBlmap\fR assigns the contents of the element to +\fIvarname\fR as if the \fBlindex\fR command had been used to extract the +element, then calls the Tcl interpreter to execute \fIbody\fR. If execution of +the body completes normally then the result of the body is appended to an +accumulator list. \fBlmap\fR returns the accumulator list. +.PP +In the general case there can be more than one value list (e.g., \fIlist1\fR +and \fIlist2\fR), and each value list can be associated with a list of loop +variables (e.g., \fIvarlist1\fR and \fIvarlist2\fR). During each iteration of +the loop the variables of each \fIvarlist\fR are assigned consecutive values +from the corresponding \fIlist\fR. Values in each \fIlist\fR are used in order +from first to last, and each value is used exactly once. The total number of +loop iterations is large enough to use up all the values from all the value +lists. If a value list does not contain enough elements for each of its loop +variables in each iteration, empty values are used for the missing elements. +.PP +The \fBbreak\fR and \fBcontinue\fR statements may be invoked inside +\fIbody\fR, with the same effect as in the \fBfor\fR and \fBforeach\fR +commands. In these cases the body does not complete normally and the result is +not appended to the accumulator list. +.SH EXAMPLES +.PP +Zip lists together: +.PP +.CS +set list1 {a b c d} +set list2 {1 2 3 4} +set zipped [\fBlmap\fR a $list1 b $list2 {list $a $b}] +# The value of zipped is "{a 1} {b 2} {c 3} {d 4}" +.CE +.PP +Filter a list to remove odd values: +.PP +.CS +set values {1 2 3 4 5 6 7 8} +proc isEven {n} {expr {($n % 2) == 0}} +set goodOnes [\fBlmap\fR x $values {expr { + [isEven $x] ? $x : [continue] +}}] +# The value of goodOnes is "2 4 6 8" +.CE +.PP +Take a prefix from a list based on the contents of the list: +.PP +.CS +set values {8 7 6 5 4 3 2 1} +proc isGood {counter} {expr {$n > 3}} +set prefix [\fBlmap\fR x $values {expr { + [isGood $x] ? $x : [break] +}}] +# The value of prefix is "8 7 6 5 4" +.CE +.SH "SEE ALSO" +break(n), continue(n), for(n), foreach(n), while(n) +.SH KEYWORDS +foreach, iteration, list, loop, map +'\" Local Variables: +'\" mode: nroff +'\" End: @@ -11,11 +11,11 @@ .SH NAME load \- Load machine code and initialize new commands .SH SYNOPSIS -\fBload \fIfileName\fR +\fBload\fR ?\fB\-global\fR? ?\fB\-lazy\fR? ?\fB\-\-\fR? \fIfileName\fR .br -\fBload \fIfileName packageName\fR +\fBload\fR ?\fB\-global\fR? ?\fB\-lazy\fR? ?\fB\-\-\fR? \fIfileName packageName\fR .br -\fBload \fIfileName packageName interp\fR +\fBload\fR ?\fB\-global\fR? ?\fB\-lazy\fR? ?\fB\-\-\fR? \fIfileName packageName interp\fR .BE .SH DESCRIPTION .PP @@ -104,6 +104,22 @@ Otherwise, the \fBload\fR command searches for a dynamically loaded package by that name, and uses it if it is found. If several different files have been \fBload\fRed with different versions of the package, Tcl picks the file that was loaded first. +.PP +If \fB\-global\fR is specified preceding the filename, all symbols +found in the shared library are exported for global use by other +libraries. The option \fB\-lazy\fR delays the actual loading of +symbols until their first actual use. The options may be abbreviated. +The option \fB\-\-\fR indicates the end of the options, and should +be used if you wish to use a filename which starts with \fB\-\fR +and you provide a packageName to the \fBload\fR command. +.PP +On platforms which do not support the \fB\-global\fR or \fB\-lazy\fR +options, the options still exist but have no effect. Note that use +of the \fB\-global\fR or \fB\-lazy\fR option may lead to crashes +in your application later (in case of symbol conflicts resp. missing +symbols), which cannot be detected during the \fBload\fR. So, only +use this when you know what you are doing, you will not get a nice +error message when something is wrong with the loaded library. .SH "PORTABILITY ISSUES" .TP \fBWindows\fR\0\0\0\0\0 diff --git a/doc/msgcat.n b/doc/msgcat.n index 595c85f..57fbb78 100644 --- a/doc/msgcat.n +++ b/doc/msgcat.n @@ -5,7 +5,7 @@ '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .so man.macros -.TH "msgcat" n 1.4 msgcat "Tcl Bundled Packages" +.TH "msgcat" n 1.5 msgcat "Tcl Bundled Packages" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME @@ -13,7 +13,7 @@ msgcat \- Tcl message catalog .SH SYNOPSIS \fBpackage require Tcl 8.5\fR .sp -\fBpackage require msgcat 1.4.5\fR +\fBpackage require msgcat 1.5.0\fR .sp \fB::msgcat::mc \fIsrc-string\fR ?\fIarg arg ...\fR? .sp @@ -29,6 +29,12 @@ msgcat \- Tcl message catalog .sp \fB::msgcat::mcmset \fIlocale src-trans-list\fR .sp +.VS "TIP 404" +\fB::msgcat::mcflset \fIsrc-string \fR?\fItranslate-string\fR? +.sp +\fB::msgcat::mcflmset \fIsrc-trans-list\fR +.VE "TIP 404" +.sp \fB::msgcat::mcunknown \fIlocale src-string\fR .BE .SH DESCRIPTION @@ -131,6 +137,26 @@ translate-string ...\fR?} \fB::msgcat::mcmset\fR can be significantly faster than multiple invocations of \fB::msgcat::mcset\fR. The function returns the number of translations set. .TP +\fB::msgcat::mcflset \fIsrc-string \fR?\fItranslate-string\fR? +.VS "TIP 404" +Sets the translation for \fIsrc-string\fR to \fItranslate-string\fR in the +current namespace for the locale implied by the name of the message catalog +being loaded via \fB::msgcat::mcload\fR. If \fItranslate-string\fR is not +specified, \fIsrc-string\fR is used for both. The function returns +\fItranslate-string\fR. +.VE "TIP 404" +.TP +\fB::msgcat::mcflmset \fIsrc-trans-list\fR +.VS "TIP 404" +Sets the translation for multiple source strings in \fIsrc-trans-list\fR in +the current namespace for the locale implied by the name of the message +catalog being loaded via \fB::msgcat::mcload\fR. \fIsrc-trans-list\fR must +have an even number of elements and is in the form {\fIsrc-string +translate-string\fR ?\fIsrc-string translate-string ...\fR?} +\fB::msgcat::mcflmset\fR can be significantly faster than multiple invocations +of \fB::msgcat::mcflset\fR. The function returns the number of translations set. +.VE "TIP 404" +.TP \fB::msgcat::mcunknown \fIlocale src-string\fR . This routine is called by \fB::msgcat::mc\fR in the case when @@ -286,15 +312,15 @@ cause peculiar behavior, such as marking the message file as .QW hidden on Unix file systems. .IP [3] -The file contains a series of calls to \fBmcset\fR and -\fBmcmset\fR, setting the necessary translation strings +The file contains a series of calls to \fBmcflset\fR and +\fBmcflmset\fR, setting the necessary translation strings for the language, likely enclosed in a \fBnamespace eval\fR so that all source strings are tied to the namespace of the package. For example, a short \fBes.msg\fR might contain: .PP .CS namespace eval ::mypackage { - \fB::msgcat::mcset\fR es "Free Beer!" "Cerveza Gracias!" + \fB::msgcat::mcflset\fR "Free Beer!" "Cerveza Gracias!" } .CE .SH "RECOMMENDED MESSAGE SETUP FOR PACKAGES" @@ -9,7 +9,7 @@ .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME -next \- invoke superclass method implementations +next, nextto \- invoke superclass method implementations .SH SYNOPSIS .nf package require TclOO diff --git a/doc/string.n b/doc/string.n index 1cbea16..6b3cc59 100644 --- a/doc/string.n +++ b/doc/string.n @@ -25,11 +25,13 @@ Returns a decimal string giving the number of bytes used to represent \fIstring\fR in memory. Because UTF\-8 uses one to three bytes to represent Unicode characters, the byte length will not be the same as the character length in general. The cases where a script cares about -the byte length are rare. In almost all cases, you should use the +the byte length are rare. +.RS +.PP +In almost all cases, you should use the \fBstring length\fR operation (including determining the length of a -Tcl ByteArray object). Refer to the \fBTcl_NumUtfChars\fR manual +Tcl byte array value). Refer to the \fBTcl_NumUtfChars\fR manual entry for more details on the UTF\-8 representation. -.RS .PP \fICompatibility note:\fR it is likely that this subcommand will be withdrawn in a future version of Tcl. It is better to use the @@ -149,7 +151,8 @@ Any Unicode printing character, including space. .IP \fBpunct\fR 12 Any Unicode punctuation character. .IP \fBspace\fR 12 -Any Unicode space character. +Any Unicode whitespace character, zero width space (U+200b), +word joiner (U+2060) and zero width no-break space (U+feff) (=BOM). .IP \fBtrue\fR 12 Any of the forms allowed to \fBTcl_GetBoolean\fR where the value is true. @@ -198,9 +201,9 @@ will return \fB1\fR. . Returns a decimal string giving the number of characters in \fIstring\fR. Note that this is not necessarily the same as the -number of bytes used to store the string. If the object is a -ByteArray object (such as those returned from reading a binary encoded -channel), then this will return the actual byte length of the object. +number of bytes used to store the string. If the value is a +byte array value (such as those returned from reading a binary encoded +channel), then this will return the actual byte length of the value. .TP \fBstring map\fR ?\fB\-nocase\fR? \fImapping string\fR . @@ -335,22 +338,22 @@ specified using the forms described in \fBSTRING INDICES\fR. . Returns a value equal to \fIstring\fR except that any leading or trailing characters present in the string given by \fIchars\fR are removed. If -\fIchars\fR is not specified then white space is removed (spaces, -tabs, newlines, and carriage returns). +\fIchars\fR is not specified then white space is removed (any character +for which \fBstring is space\fR returns 1, and "\0"). .TP \fBstring trimleft \fIstring\fR ?\fIchars\fR? . Returns a value equal to \fIstring\fR except that any leading characters present in the string given by \fIchars\fR are removed. If -\fIchars\fR is not specified then white space is removed (spaces, -tabs, newlines, and carriage returns). +\fIchars\fR is not specified then white space is removed (any character +for which \fBstring is space\fR returns 1, and "\0"). .TP \fBstring trimright \fIstring\fR ?\fIchars\fR? . Returns a value equal to \fIstring\fR except that any trailing characters present in the string given by \fIchars\fR are removed. If -\fIchars\fR is not specified then white space is removed (spaces, -tabs, newlines, and carriage returns). +\fIchars\fR is not specified then white space is removed (any character +for which \fBstring is space\fR returns 1, and "\0"). .TP \fBstring wordend \fIstring charIndex\fR . diff --git a/doc/tclsh.1 b/doc/tclsh.1 index 2819408..8e7fb9e 100644 --- a/doc/tclsh.1 +++ b/doc/tclsh.1 @@ -12,7 +12,7 @@ .SH NAME tclsh \- Simple shell containing Tcl interpreter .SH SYNOPSIS -\fBtclsh\fR ?-encoding \fIname\fR? ?\fIfileName arg arg ...\fR? +\fBtclsh\fR ?\fB\-encoding \fIname\fR? ?\fIfileName arg arg ...\fR? .BE .SH DESCRIPTION .PP diff --git a/doc/trace.n b/doc/trace.n index 940a1e9..63ed1cb 100644 --- a/doc/trace.n +++ b/doc/trace.n @@ -143,7 +143,7 @@ error will occur. For \fBleave\fR and \fBleavestep\fR operations: .PP .CS -\fIcommand command-string code result op\fR +\fIcommandPrefix command-string code result op\fR .CE .PP \fICommand-string\fR gives the complete current command being @@ -1,5 +1,5 @@ '\" -'\" Copyright (c) 2008 Donal K. Fellows +'\" Copyright (c) 2008-2012 Donal K. Fellows '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -170,6 +170,13 @@ the .QW "\fIoptions ...\fR" to the \fBzlib push\fR command: .TP +\fB\-dictionary\fI binData\fR +.VS "TIP 400" +Sets the compression dictionary to use when working with compressing or +decompressing the data to be \fIbinData\fR. Not valid for transformations that +work with gzip-format data. +.VE +.TP \fB\-header\fI dictionary\fR . Passes a description of the gzip header to create, in the same format that @@ -179,15 +186,33 @@ Passes a description of the gzip header to create, in the same format that . How hard to compress the data. Must be an integer from 0 (uncompressed) to 9 (maximally compressed). -'\".TP -'\"\fB\-limit\fI readaheadLimit\fR -'\". -'\"The maximum number of bytes ahead to read. -'\"\fITODO: not yet implemented!\fR +.TP +\fB\-limit\fI readaheadLimit\fR +. +The maximum number of bytes ahead to read when decompressing. This defaults to +1, which ensures that data is always decompressed correctly, but may be +increased to improve performance. This is more useful when the channel is +non-blocking. .PP Both compressing and decompressing channel transformations add extra -configuration options that may be accessed through \fBchan configure\fR. Each -option is either a read-only or a write-only option. The options are: +configuration options that may be accessed through \fBchan configure\fR. The +options are: +.TP +\fB\-checksum\fI checksum\fR +. +This read-only option gets the current checksum for the uncompressed data that +the compression engine has seen so far. It is valid for both compressing and +decompressing transforms, but not for the raw inflate and deflate formats. The +compression algorithm depends on what format is being produced or consumed. +.TP +\fB\-dictionary\fI binData\fR +.VS "TIP 400" +This read-write options gets or sets the compression dictionary to use when +working with compressing or decompressing the data to be \fIbinData\fR. It is +not valid for transformations that work with gzip-format data, and should not +normally be set on compressing transformations other than at the point where +the transformation is stacked. +.VE .TP \fB\-flush\fI type\fR . @@ -198,63 +223,80 @@ expensive flush respectively. Flushing degrades the compression ratio, but makes it easier for a decompressor to recover more of the file in the case of data corruption. .TP -\fB\-checksum\fR -. -This read-only option gets the current checksum for the uncompressed data -that the compression engine has seen so far. It is valid for both -compressing and decompressing transforms, but not for the raw inflate -and deflate formats. The compression algorithm depends on what -format is being produced or consumed. -.TP -\fB\-header\fR +\fB\-header\fI dictionary\fR . This read-only option, only valid for decompressing transforms that are processing gzip-format data, returns the dictionary describing the header read off the data stream. +.TP +\fB\-limit\fI readaheadLimit\fR +. +This read-write option is used by decompressing channels to control the +maximum number of bytes ahead to read from the underlying data source. This +defaults to 1, which ensures that data is always decompressed correctly, but +may be increased to improve performance. This is more useful when the channel +is non-blocking. .RE .SS "STREAMING SUBCOMMAND" .TP -\fBzlib stream\fI mode\fR ?\fIlevel\fR? +\fBzlib stream\fI mode\fR ?\fIoptions\fR? . Creates a streaming compression or decompression command based on the \fImode\fR, and return the name of the command. For a description of how that command works, see \fBSTREAMING INSTANCE COMMAND\fR below. The following modes -are supported: +and \fIoptions\fR are supported: .RS .TP -\fBzlib stream compress\fR ?\fIlevel\fR? +\fBzlib stream compress\fR ?\fB\-dictionary \fIbindata\fR? ?\fB\-level \fIlevel\fR? . The stream will be a compressing stream that produces zlib-format output, using compression level \fIlevel\fR (if specified) which will be an integer -from 0 to 9. +from 0 to 9, +.VS "TIP 400" +and the compression dictionary \fIbindata\fR (if specified). +.VE .TP -\fBzlib stream decompress\fR +\fBzlib stream decompress\fR ?\fB\-dictionary \fIbindata\fR? . The stream will be a decompressing stream that takes zlib-format input and produces uncompressed output. +.VS "TIP 400" +If \fIbindata\fR is supplied, it is a compression dictionary to use if +required. +.VE .TP -\fBzlib stream deflate\fR ?\fIlevel\fR? +\fBzlib stream deflate\fR ?\fB\-dictionary \fIbindata\fR? ?\fB\-level \fIlevel\fR? . The stream will be a compressing stream that produces raw output, using compression level \fIlevel\fR (if specified) which will be an integer from 0 -to 9. +to 9, +.VS "TIP 400" +and the compression dictionary \fIbindata\fR (if specified). Note that +the raw compressed data includes no metadata about what compression +dictionary was used, if any; that is a feature of the zlib-format data. +.VE .TP \fBzlib stream gunzip\fR . The stream will be a decompressing stream that takes gzip-format input and produces uncompressed output. .TP -\fBzlib stream gzip\fR ?\fIlevel\fR? +\fBzlib stream gzip\fR ?\fB\-header \fIheader\fR? ?\fB\-level \fIlevel\fR? . The stream will be a compressing stream that produces gzip-format output, using compression level \fIlevel\fR (if specified) which will be an integer -from 0 to 9. -'\" TODO: Header dictionary! +from 0 to 9, and the header descriptor dictionary \fIheader\fR (if specified; +for keys see \fBzlib gzip\fR). .TP -\fBzlib stream inflate\fR +\fBzlib stream inflate\fR ?\fB\-dictionary \fIbindata\fR? . The stream will be a decompressing stream that takes raw compressed input and produces uncompressed output. +.VS "TIP 400" +If \fIbindata\fR is supplied, it is a compression dictionary to use. Note that +there are no checks in place to determine whether the compression dictionary +is correct. +.VE .RE .SS "CHECKSUMMING SUBCOMMANDS" .TP @@ -277,10 +319,10 @@ the transformed data. The full set of subcommands supported by a streaming instance command, \fIstream\fR, is as follows: .TP -\fIstream \fBadd\fR ?\fIoption\fR? \fIdata\fR +\fIstream \fBadd\fR ?\fIoption...\fR? \fIdata\fR . A short-cut for -.QW "\fIstream \fBput \fIoption data\fR" +.QW "\fIstream \fBput \fR?\fIoption...\fR? \fIdata\fR" followed by .QW "\fIstream \fBget\fR" . .TP @@ -318,15 +360,27 @@ A short-cut for Return up to \fIcount\fR bytes from \fIstream\fR's internal buffers with the transformation applied. If \fIcount\fR is omitted, the entire contents of the buffers are returned. +. +\fIstream \fBheader\fR +. +Return the gzip header description dictionary extracted from the stream. Only +supported for streams created with their \fImode\fR parameter set to +\fBgunzip\fR. .TP -\fIstream \fBput\fR ?\fIoption\fR? \fIdata\fR +\fIstream \fBput\fR ?\fIoption...\fR? \fIdata\fR . Append the contents of the binary string \fIdata\fR to \fIstream\fR's internal -buffers while applying the transformation. If present, \fIoption\fR must be -one of the following (or an unambiguous prefix) which are used to modify the +buffers while applying the transformation. The following \fIoption\fRs are +supported (or an unambiguous prefix of them), which are used to modify the way in which the transformation is applied: .RS .TP +\fB\-dictionary\fI binData\fR +.VS "TIP 400" +Sets the compression dictionary to use when working with compressing or +decompressing the data to be \fIbinData\fR. +.VE +.TP \fB\-finalize\fR . Mark the stream as finished, ensuring that all bytes have been wholly @@ -334,12 +388,22 @@ compressed or decompressed. For gzip streams, this also ensures that the footer is written to the stream. The stream will need to be reset before having more data written to it after this, though data can still be read out of the stream with the \fBget\fR subcommand. +.RS +.PP +This option is mutually exclusive with the \fB\-flush\fR and \fB\-fullflush\fR +options. +.RE .TP \fB\-flush\fR . Ensure that a decompressor consuming the bytes that the current (compressing) stream is producing will be able to produce all the bytes that have been compressed so far, at some performance penalty. +.RS +.PP +This option is mutually exclusive with the \fB\-finalize\fR and +\fB\-fullflush\fR options. +.RE .TP \fB\-fullflush\fR . @@ -347,6 +411,11 @@ Ensure that not only can a decompressor handle all the bytes produced so far (as with \fB\-flush\fR above) but also that it can restart from this point if it detects that the stream is partially corrupt. This incurs a substantial performance penalty. +.RS +.PP +This option is mutually exclusive with the \fB\-finalize\fR and \fB\-flush\fR +options. +.RE .RE .TP \fIstream \fBreset\fR @@ -385,7 +454,7 @@ $\fIstrm \fBclose\fR .SH "SEE ALSO" binary(n), chan(n), encoding(n), Tcl_ZlibDeflate(3), RFC1950 \- RFC1952 .SH "KEYWORDS" -compress, decompress, deflate, gzip, inflate +compress, decompress, deflate, gzip, inflate, zlib '\" Local Variables: '\" mode: nroff '\" End: diff --git a/generic/regc_locale.c b/generic/regc_locale.c index 188d6de..f3db471 100644 --- a/generic/regc_locale.c +++ b/generic/regc_locale.c @@ -354,13 +354,14 @@ static const chr punctCharTable[] = { */ static const crange spaceRangeTable[] = { - {0x9, 0xd}, {0x2000, 0x200a} + {0x9, 0xd}, {0x2000, 0x200b} }; #define NUM_SPACE_RANGE (sizeof(spaceRangeTable)/sizeof(crange)) static const chr spaceCharTable[] = { - 0x20, 0xa0, 0x1680, 0x180e, 0x2028, 0x2029, 0x202f, 0x205f, 0x3000 + 0x20, 0x85, 0xa0, 0x1680, 0x180e, 0x2028, 0x2029, 0x202f, 0x205f, + 0x2060, 0x3000, 0xfeff }; #define NUM_SPACE_CHAR (sizeof(spaceCharTable)/sizeof(chr)) @@ -617,7 +618,7 @@ static const crange graphRangeTable[] = { {0x1f48, 0x1f4d}, {0x1f50, 0x1f57}, {0x1f5f, 0x1f7d}, {0x1f80, 0x1fb4}, {0x1fb6, 0x1fc4}, {0x1fc6, 0x1fd3}, {0x1fd6, 0x1fdb}, {0x1fdd, 0x1fef}, {0x1ff2, 0x1ff4}, {0x1ff6, 0x1ffe}, {0x2010, 0x2027}, {0x2030, 0x205e}, - {0x2074, 0x208e}, {0x2090, 0x209c}, {0x20a0, 0x20b9}, {0x20d0, 0x20f0}, + {0x2074, 0x208e}, {0x2090, 0x209c}, {0x20a0, 0x20ba}, {0x20d0, 0x20f0}, {0x2100, 0x2189}, {0x2190, 0x23f3}, {0x2400, 0x2426}, {0x2440, 0x244a}, {0x2460, 0x26ff}, {0x2701, 0x2b4c}, {0x2b50, 0x2b59}, {0x2c00, 0x2c2e}, {0x2c30, 0x2c5e}, {0x2c60, 0x2cf3}, {0x2cf9, 0x2d25}, {0x2d30, 0x2d67}, diff --git a/generic/tcl.decls b/generic/tcl.decls index b421ae2..1829249 100644 --- a/generic/tcl.decls +++ b/generic/tcl.decls @@ -2318,6 +2318,12 @@ declare 629 { int Tcl_FSUnloadFile(Tcl_Interp *interp, Tcl_LoadHandle handlePtr) } +# TIP #400 +declare 630 { + void Tcl_ZlibStreamSetCompressionDictionary(Tcl_ZlibStream zhandle, + Tcl_Obj *compressionDictionaryObj) +} + # ----- BASELINE -- FOR -- 8.6.0 ----- # ############################################################################## diff --git a/generic/tcl.h b/generic/tcl.h index a7d3917..300614c 100644 --- a/generic/tcl.h +++ b/generic/tcl.h @@ -51,17 +51,15 @@ extern "C" { * win/README (not patchlevel) (sections 0 and 2) * unix/tcl.spec (1 LOC patch) * tools/tcl.hpj.in (not patchlevel, for windows installer) - * tools/tcl.wse.in (for windows installer) - * tools/tclSplash.bmp (not patchlevel) */ #define TCL_MAJOR_VERSION 8 #define TCL_MINOR_VERSION 6 #define TCL_RELEASE_LEVEL TCL_BETA_RELEASE -#define TCL_RELEASE_SERIAL 2 +#define TCL_RELEASE_SERIAL 3 #define TCL_VERSION "8.6" -#define TCL_PATCH_LEVEL "8.6b2" +#define TCL_PATCH_LEVEL "8.6b3" /* *---------------------------------------------------------------------------- @@ -2332,6 +2330,14 @@ typedef int (Tcl_ArgvGenFuncProc)(ClientData clientData, Tcl_Interp *interp, /* *---------------------------------------------------------------------------- + * Definitions needed for the Tcl_LoadFile function. [TIP #416] + */ + +#define TCL_LOAD_GLOBAL 1 +#define TCL_LOAD_LAZY 2 + +/* + *---------------------------------------------------------------------------- * Single public declaration for NRE. */ diff --git a/generic/tclAssembly.c b/generic/tclAssembly.c index 83f4fe9..7833105 100644 --- a/generic/tclAssembly.c +++ b/generic/tclAssembly.c @@ -362,6 +362,10 @@ static const TalInstDesc TalInstructionTable[] = { | INST_APPEND_ARRAY4), 2, 1}, {"appendArrayStk", ASSEM_1BYTE, INST_APPEND_ARRAY_STK, 3, 1}, {"appendStk", ASSEM_1BYTE, INST_APPEND_STK, 2, 1}, + {"arrayExistsImm", ASSEM_LVT4, INST_ARRAY_EXISTS_IMM, 0, 1}, + {"arrayExistsStk", ASSEM_1BYTE, INST_ARRAY_EXISTS_STK, 1, 1}, + {"arrayMakeImm", ASSEM_LVT4, INST_ARRAY_MAKE_IMM, 0, 0}, + {"arrayMakeStk", ASSEM_1BYTE, INST_ARRAY_MAKE_STK, 1, 0}, {"beginCatch", ASSEM_BEGIN_CATCH, INST_BEGIN_CATCH4, 0, 0}, {"bitand", ASSEM_1BYTE, INST_BITAND, 2, 1}, @@ -369,7 +373,10 @@ static const TalInstDesc TalInstructionTable[] = { {"bitor", ASSEM_1BYTE, INST_BITOR, 2, 1}, {"bitxor", ASSEM_1BYTE, INST_BITXOR, 2, 1}, {"concat", ASSEM_CONCAT1, INST_CONCAT1, INT_MIN,1}, + {"coroName", ASSEM_1BYTE, INST_COROUTINE_NAME, 0, 1}, + {"currentNamespace",ASSEM_1BYTE, INST_NS_CURRENT, 0, 1}, {"dictAppend", ASSEM_LVT4, INST_DICT_APPEND, 2, 1}, + {"dictExists", ASSEM_DICT_GET, INST_DICT_EXISTS, INT_MIN,1}, {"dictExpand", ASSEM_1BYTE, INST_DICT_EXPAND, 3, 1}, {"dictGet", ASSEM_DICT_GET, INST_DICT_GET, INT_MIN,1}, {"dictIncrImm", ASSEM_SINT4_LVT4, @@ -406,6 +413,8 @@ static const TalInstDesc TalInstructionTable[] = { {"incrStk", ASSEM_1BYTE, INST_INCR_SCALAR_STK, 2, 1}, {"incrStkImm", ASSEM_SINT1, INST_INCR_SCALAR_STK_IMM, 1, 1}, + {"infoLevelArgs", ASSEM_1BYTE, INST_INFO_LEVEL_ARGS, 1, 1}, + {"infoLevelNumber", ASSEM_1BYTE, INST_INFO_LEVEL_NUM, 0, 1}, {"invokeStk", ASSEM_INVOKE, (INST_INVOKE_STK1 << 8 | INST_INVOKE_STK4), INT_MIN,1}, {"jump", ASSEM_JUMP, INST_JUMP1, 0, 0}, @@ -457,6 +466,7 @@ static const TalInstDesc TalInstructionTable[] = { 0, 1}, {"pushResult", ASSEM_1BYTE, INST_PUSH_RESULT, 0, 1}, {"regexp", ASSEM_REGEXP, INST_REGEXP, 2, 1}, + {"resolveCmd", ASSEM_1BYTE, INST_RESOLVE_COMMAND, 1, 1}, {"reverse", ASSEM_REVERSE, INST_REVERSE, INT_MIN,-1-0}, {"rshift", ASSEM_1BYTE, INST_RSHIFT, 2, 1}, {"store", ASSEM_LVT, (INST_STORE_SCALAR1<<8 @@ -467,11 +477,19 @@ static const TalInstDesc TalInstructionTable[] = { {"storeStk", ASSEM_1BYTE, INST_STORE_SCALAR_STK, 2, 1}, {"strcmp", ASSEM_1BYTE, INST_STR_CMP, 2, 1}, {"streq", ASSEM_1BYTE, INST_STR_EQ, 2, 1}, + {"strfind", ASSEM_1BYTE, INST_STR_FIND, 2, 1}, {"strindex", ASSEM_1BYTE, INST_STR_INDEX, 2, 1}, {"strlen", ASSEM_1BYTE, INST_STR_LEN, 1, 1}, + {"strmap", ASSEM_1BYTE, INST_STR_MAP, 3, 1}, {"strmatch", ASSEM_BOOL, INST_STR_MATCH, 2, 1}, {"strneq", ASSEM_1BYTE, INST_STR_NEQ, 2, 1}, + {"strrange", ASSEM_1BYTE, INST_STR_RANGE, 3, 1}, + {"strrfind", ASSEM_1BYTE, INST_STR_FIND_LAST, 2, 1}, {"sub", ASSEM_1BYTE, INST_SUB, 2, 1}, + {"tclooClass", ASSEM_1BYTE, INST_TCLOO_CLASS, 1, 1}, + {"tclooIsObject", ASSEM_1BYTE, INST_TCLOO_IS_OBJECT, 1, 1}, + {"tclooNamespace", ASSEM_1BYTE, INST_TCLOO_NS, 1, 1}, + {"tclooSelf", ASSEM_1BYTE, INST_TCLOO_SELF, 0, 1}, {"tryCvtToNumeric", ASSEM_1BYTE, INST_TRY_CVT_TO_NUMERIC,1, 1}, {"uminus", ASSEM_1BYTE, INST_UMINUS, 1, 1}, {"unset", ASSEM_BOOL_LVT4,INST_UNSET_SCALAR, 0, 0}, @@ -481,6 +499,8 @@ static const TalInstDesc TalInstructionTable[] = { {"uplus", ASSEM_1BYTE, INST_UPLUS, 1, 1}, {"upvar", ASSEM_LVT4, INST_UPVAR, 2, 1}, {"variable", ASSEM_LVT4, INST_VARIABLE, 1, 0}, + {"verifyDict", ASSEM_1BYTE, INST_DICT_VERIFY, 1, 0}, + {"yield", ASSEM_1BYTE, INST_YIELD, 1, 1}, {NULL, 0, 0, 0, 0} }; @@ -499,7 +519,13 @@ static const unsigned char NonThrowingByteCodes[] = { INST_OVER, /* 95 */ INST_PUSH_RETURN_OPTIONS, /* 108 */ INST_REVERSE, /* 126 */ - INST_NOP /* 132 */ + INST_NOP, /* 132 */ + INST_STR_MAP, /* 143 */ + INST_STR_FIND, /* 144 */ + INST_COROUTINE_NAME, /* 149 */ + INST_NS_CURRENT, /* 151 */ + INST_INFO_LEVEL_NUM, /* 152 */ + INST_RESOLVE_COMMAND /* 154 */ }; /* diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 4d6ff0c..971ae36 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -131,13 +131,11 @@ static Tcl_Obj * GetCommandSource(Interp *iPtr, int objc, Tcl_Obj *const objv[], int lookup); static void MathFuncWrongNumArgs(Tcl_Interp *interp, int expected, int actual, Tcl_Obj *const *objv); -static Tcl_NRPostProc NRCoroutineActivateCallback; static Tcl_NRPostProc NRCoroutineCallerCallback; static Tcl_NRPostProc NRCoroutineExitCallback; static int NRCommand(ClientData data[], Tcl_Interp *interp, int result); static Tcl_NRPostProc NRRunObjProc; -static Tcl_NRPostProc NRTailcallEval; static Tcl_ObjCmdProc OldMathFuncProc; static void OldMathFuncDeleteProc(ClientData clientData); static void ProcessUnexpectedResult(Tcl_Interp *interp, @@ -219,7 +217,7 @@ static const CmdInfo builtInCmds[] = { {"expr", Tcl_ExprObjCmd, TclCompileExprCmd, TclNRExprObjCmd, 1}, {"for", Tcl_ForObjCmd, TclCompileForCmd, TclNRForObjCmd, 1}, {"foreach", Tcl_ForeachObjCmd, TclCompileForeachCmd, TclNRForeachCmd, 1}, - {"format", Tcl_FormatObjCmd, NULL, NULL, 1}, + {"format", Tcl_FormatObjCmd, TclCompileFormatCmd, NULL, 1}, {"global", Tcl_GlobalObjCmd, TclCompileGlobalCmd, NULL, 1}, {"if", Tcl_IfObjCmd, TclCompileIfCmd, TclNRIfObjCmd, 1}, {"incr", Tcl_IncrObjCmd, TclCompileIncrCmd, NULL, 1}, @@ -230,6 +228,7 @@ static const CmdInfo builtInCmds[] = { {"linsert", Tcl_LinsertObjCmd, NULL, NULL, 1}, {"list", Tcl_ListObjCmd, TclCompileListCmd, NULL, 1}, {"llength", Tcl_LlengthObjCmd, TclCompileLlengthCmd, NULL, 1}, + {"lmap", Tcl_LmapObjCmd, TclCompileLmapCmd, TclNRLmapCmd, 1}, {"lrange", Tcl_LrangeObjCmd, TclCompileLrangeCmd, NULL, 1}, {"lrepeat", Tcl_LrepeatObjCmd, NULL, NULL, 1}, {"lreplace", Tcl_LreplaceObjCmd, TclCompileLreplaceCmd, NULL, 1}, @@ -240,7 +239,7 @@ static const CmdInfo builtInCmds[] = { {"package", Tcl_PackageObjCmd, NULL, NULL, 1}, {"proc", Tcl_ProcObjCmd, NULL, NULL, 1}, {"regexp", Tcl_RegexpObjCmd, TclCompileRegexpCmd, NULL, 1}, - {"regsub", Tcl_RegsubObjCmd, NULL, NULL, 1}, + {"regsub", Tcl_RegsubObjCmd, TclCompileRegsubCmd, NULL, 1}, {"rename", Tcl_RenameObjCmd, NULL, NULL, 1}, {"return", Tcl_ReturnObjCmd, TclCompileReturnCmd, NULL, 1}, {"scan", Tcl_ScanObjCmd, NULL, NULL, 1}, @@ -248,7 +247,7 @@ static const CmdInfo builtInCmds[] = { {"split", Tcl_SplitObjCmd, NULL, NULL, 1}, {"subst", Tcl_SubstObjCmd, TclCompileSubstCmd, TclNRSubstObjCmd, 1}, {"switch", Tcl_SwitchObjCmd, TclCompileSwitchCmd, TclNRSwitchObjCmd, 1}, - {"tailcall", NULL, NULL, TclNRTailcallObjCmd, 1}, + {"tailcall", NULL, TclCompileTailcallCmd, TclNRTailcallObjCmd, 1}, {"throw", Tcl_ThrowObjCmd, TclCompileThrowCmd, NULL, 1}, {"trace", Tcl_TraceObjCmd, NULL, NULL, 1}, {"try", Tcl_TryObjCmd, TclCompileTryCmd, TclNRTryObjCmd, 1}, @@ -257,7 +256,7 @@ static const CmdInfo builtInCmds[] = { {"upvar", Tcl_UpvarObjCmd, TclCompileUpvarCmd, NULL, 1}, {"variable", Tcl_VariableObjCmd, TclCompileVariableCmd, NULL, 1}, {"while", Tcl_WhileObjCmd, TclCompileWhileCmd, TclNRWhileObjCmd, 1}, - {"yield", NULL, NULL, TclNRYieldObjCmd, 1}, + {"yield", NULL, TclCompileYieldCmd, TclNRYieldObjCmd, 1}, {"yieldto", NULL, NULL, TclNRYieldToObjCmd, 1}, /* @@ -1696,9 +1695,9 @@ Tcl_HideCommand( */ if (strstr(hiddenCmdToken, "::") != NULL) { - Tcl_AppendResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "cannot use namespace qualifiers in hidden command" - " token (rename)", NULL); + " token (rename)", -1)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "HIDDENTOKEN", NULL); return TCL_ERROR; } @@ -1721,8 +1720,9 @@ Tcl_HideCommand( */ if (cmdPtr->nsPtr != iPtr->globalNsPtr) { - Tcl_AppendResult(interp, "can only hide global namespace commands" - " (use rename then hide)", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "can only hide global namespace commands (use rename then hide)", + -1)); Tcl_SetErrorCode(interp, "TCL", "HIDE", "NON_GLOBAL", NULL); return TCL_ERROR; } @@ -1746,8 +1746,9 @@ Tcl_HideCommand( hPtr = Tcl_CreateHashEntry(hiddenCmdTablePtr, hiddenCmdToken, &isNew); if (!isNew) { - Tcl_AppendResult(interp, "hidden command named \"", hiddenCmdToken, - "\" already exists", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "hidden command named \"%s\" already exists", + hiddenCmdToken)); Tcl_SetErrorCode(interp, "TCL", "HIDE", "ALREADY_HIDDEN", NULL); return TCL_ERROR; } @@ -1849,8 +1850,9 @@ Tcl_ExposeCommand( */ if (strstr(cmdName, "::") != NULL) { - Tcl_AppendResult(interp, "cannot expose to a namespace " - "(use expose to toplevel, then rename)", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "cannot expose to a namespace (use expose to toplevel, then rename)", + -1)); Tcl_SetErrorCode(interp, "TCL", "EXPOSE", "NON_GLOBAL", NULL); return TCL_ERROR; } @@ -1865,8 +1867,8 @@ Tcl_ExposeCommand( hPtr = Tcl_FindHashEntry(hiddenCmdTablePtr, hiddenCmdToken); } if (hPtr == NULL) { - Tcl_AppendResult(interp, "unknown hidden command \"", hiddenCmdToken, - "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unknown hidden command \"%s\"", hiddenCmdToken)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "HIDDENTOKEN", hiddenCmdToken, NULL); return TCL_ERROR; @@ -1885,9 +1887,9 @@ Tcl_ExposeCommand( * than 'nicely' erroring out ? */ - Tcl_AppendResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "trying to expose a non-global command namespace command", - NULL); + -1)); return TCL_ERROR; } @@ -1904,8 +1906,8 @@ Tcl_ExposeCommand( hPtr = Tcl_CreateHashEntry(&nsPtr->cmdTable, cmdName, &isNew); if (!isNew) { - Tcl_AppendResult(interp, "exposed command \"", cmdName, - "\" already exists", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "exposed command \"%s\" already exists", cmdName)); Tcl_SetErrorCode(interp, "TCL", "EXPOSE", "COMMAND_EXISTS", NULL); return TCL_ERROR; } @@ -2478,9 +2480,10 @@ TclRenameCommand( cmd = Tcl_FindCommand(interp, oldName, NULL, /*flags*/ 0); cmdPtr = (Command *) cmd; if (cmdPtr == NULL) { - Tcl_AppendResult(interp, "can't ", + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't %s \"%s\": command doesn't exist", ((newName == NULL)||(*newName == '\0'))? "delete":"rename", - " \"", oldName, "\": command doesn't exist", NULL); + oldName)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COMMAND", oldName, NULL); return TCL_ERROR; } @@ -2510,15 +2513,15 @@ TclRenameCommand( TCL_CREATE_NS_IF_UNKNOWN, &newNsPtr, &dummy1, &dummy2, &newTail); if ((newNsPtr == NULL) || (newTail == NULL)) { - Tcl_AppendResult(interp, "can't rename to \"", newName, - "\": bad command name", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't rename to \"%s\": bad command name", newName)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "COMMAND", NULL); result = TCL_ERROR; goto done; } if (Tcl_FindHashEntry(&newNsPtr->cmdTable, newTail) != NULL) { - Tcl_AppendResult(interp, "can't rename to \"", newName, - "\": command already exists", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't rename to \"%s\": command already exists", newName)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "RENAME", "TARGET_EXISTS", NULL); result = TCL_ERROR; @@ -3519,9 +3522,9 @@ OldMathFuncProc( * We have a non-numeric argument. */ - Tcl_SetResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "argument to math function didn't have numeric value", - TCL_STATIC); + -1)); TclCheckBadOctal(interp, Tcl_GetString(valuePtr)); ckfree(args); return TCL_ERROR; @@ -3734,41 +3737,28 @@ Tcl_ListMathFuncs( Tcl_Interp *interp, const char *pattern) { - Namespace *globalNsPtr = (Namespace *) Tcl_GetGlobalNamespace(interp); - Namespace *nsPtr; - Namespace *dummy1NsPtr; - Namespace *dummy2NsPtr; - const char *dummyNamePtr; - Tcl_Obj *result = Tcl_NewObj(); - - TclGetNamespaceForQualName(interp, "::tcl::mathfunc", - globalNsPtr, TCL_FIND_ONLY_NS | TCL_GLOBAL_ONLY, - &nsPtr, &dummy1NsPtr, &dummy2NsPtr, &dummyNamePtr); - if (nsPtr == NULL) { - return result; + Tcl_Obj *script = Tcl_NewStringObj("::info functions ", -1); + Tcl_Obj *result; + Tcl_InterpState state; + + if (pattern) { + Tcl_Obj *patternObj = Tcl_NewStringObj(pattern, -1); + Tcl_Obj *arg = Tcl_NewListObj(1, &patternObj); + + Tcl_AppendObjToObj(script, arg); + Tcl_DecrRefCount(arg); /* Should tear down patternObj too */ } - if ((pattern != NULL) && TclMatchIsTrivial(pattern)) { - if (Tcl_FindHashEntry(&nsPtr->cmdTable, pattern) != NULL) { - Tcl_ListObjAppendElement(NULL, result, - Tcl_NewStringObj(pattern, -1)); - } + state = Tcl_SaveInterpState(interp, TCL_OK); + Tcl_IncrRefCount(script); + if (TCL_OK == Tcl_EvalObjEx(interp, script, 0)) { + result = Tcl_DuplicateObj(Tcl_GetObjResult(interp)); } else { - Tcl_HashSearch cmdHashSearch; - Tcl_HashEntry *cmdHashEntry = - Tcl_FirstHashEntry(&nsPtr->cmdTable,&cmdHashSearch); - - for (; cmdHashEntry != NULL; - cmdHashEntry = Tcl_NextHashEntry(&cmdHashSearch)) { - const char *cmdNamePtr = - Tcl_GetHashKey(&nsPtr->cmdTable, cmdHashEntry); - - if (pattern == NULL || Tcl_StringMatch(cmdNamePtr, pattern)) { - Tcl_ListObjAppendElement(NULL, result, - Tcl_NewStringObj(cmdNamePtr, -1)); - } - } + result = Tcl_NewObj(); } + Tcl_DecrRefCount(script); + Tcl_RestoreInterpState(interp, state); + return result; } @@ -3808,9 +3798,8 @@ TclInterpReady( */ if (iPtr->flags & DELETED) { - /* JJM - Superfluous Tcl_ResetResult call removed. */ - Tcl_AppendResult(interp, - "attempt to call eval in deleted interpreter", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "attempt to call eval in deleted interpreter", -1)); Tcl_SetErrorCode(interp, "TCL", "IDELETE", "attempt to call eval in deleted interpreter", NULL); return TCL_ERROR; @@ -3838,8 +3827,8 @@ TclInterpReady( return TCL_OK; } - Tcl_AppendResult(interp, - "too many nested evaluations (infinite loop?)", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "too many nested evaluations (infinite loop?)", -1)); Tcl_SetErrorCode(interp, "TCL", "LIMIT", "STACK", NULL); return TCL_ERROR; } @@ -3973,8 +3962,7 @@ Tcl_Canceled( } } - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, message, NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj(message, -1)); Tcl_SetErrorCode(interp, "TCL", "CANCEL", id, message, NULL); } @@ -4582,8 +4570,8 @@ TEOV_NotFound( cmdPtr = TEOV_LookupCmdFromObj(interp, newObjv[0], lookupNsPtr); if (cmdPtr == NULL) { - Tcl_AppendResult(interp, "invalid command name \"", - TclGetString(objv[0]), "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "invalid command name \"%s\"", TclGetString(objv[0]))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COMMAND", TclGetString(objv[0]), NULL); @@ -6242,11 +6230,11 @@ ProcessUnexpectedResult( Tcl_ResetResult(interp); if (returnCode == TCL_BREAK) { - Tcl_AppendResult(interp, - "invoked \"break\" outside of a loop", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "invoked \"break\" outside of a loop", -1)); } else if (returnCode == TCL_CONTINUE) { - Tcl_AppendResult(interp, - "invoked \"continue\" outside of a loop", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "invoked \"continue\" outside of a loop", -1)); } else { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "command returned bad code: %d", returnCode)); @@ -6567,7 +6555,8 @@ TclObjInvoke( } if ((objc < 1) || (objv == NULL)) { - Tcl_AppendResult(interp, "illegal argument vector", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "illegal argument vector", -1)); return TCL_ERROR; } @@ -6585,8 +6574,8 @@ TclObjInvoke( hPtr = Tcl_FindHashEntry(hTblPtr, cmdName); } if (hPtr == NULL) { - Tcl_AppendResult(interp, "invalid hidden command name \"", - cmdName, "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "invalid hidden command name \"%s\"", cmdName)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "HIDDENTOKEN", cmdName, NULL); return TCL_ERROR; @@ -7194,7 +7183,8 @@ ExprIsqrtFunc( return TCL_OK; negarg: - Tcl_SetResult(interp, "square root of negative argument", TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "square root of negative argument", -1)); Tcl_SetErrorCode(interp, "ARITH", "DOMAIN", "domain error: argument not in valid range", NULL); return TCL_ERROR; @@ -8243,10 +8233,9 @@ TclNRTailcallObjCmd( return TCL_ERROR; } - if (!iPtr->varFramePtr->isProcCallFrame) { /* or is upleveled */ - Tcl_SetResult(interp, - "tailcall can only be called from a proc or lambda", - TCL_STATIC); + if (!(iPtr->varFramePtr->isProcCallFrame & 1)) { /* or is upleveled */ + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "tailcall can only be called from a proc or lambda", -1)); Tcl_SetErrorCode(interp, "TCL", "TAILCALL", "ILLEGAL", NULL); return TCL_ERROR; } @@ -8284,7 +8273,7 @@ TclNRTailcallObjCmd( } Tcl_IncrRefCount(nsObjPtr); - TclNRAddCallback(interp, NRTailcallEval, listPtr, nsObjPtr, + TclNRAddCallback(interp, TclNRTailcallEval, listPtr, nsObjPtr, NULL, NULL); tailcallPtr = TOP_CB(interp); TOP_CB(interp) = tailcallPtr->nextPtr; @@ -8294,7 +8283,7 @@ TclNRTailcallObjCmd( } int -NRTailcallEval( +TclNRTailcallEval( ClientData data[], Tcl_Interp *interp, int result) @@ -8405,8 +8394,8 @@ TclNRYieldObjCmd( } if (!corPtr) { - Tcl_SetResult(interp, "yield can only be called in a coroutine", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "yield can only be called in a coroutine", -1)); Tcl_SetErrorCode(interp, "TCL", "COROUTINE", "ILLEGAL_YIELD", NULL); return TCL_ERROR; } @@ -8416,7 +8405,7 @@ TclNRYieldObjCmd( } NRE_ASSERT(!COR_IS_SUSPENDED(corPtr)); - TclNRAddCallback(interp, NRCoroutineActivateCallback, corPtr, + TclNRAddCallback(interp, TclNRCoroutineActivateCallback, corPtr, clientData, NULL, NULL); return TCL_OK; } @@ -8439,8 +8428,8 @@ TclNRYieldToObjCmd( } if (!corPtr) { - Tcl_SetResult(interp, "yieldto can only be called in a coroutine", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "yieldto can only be called in a coroutine", -1)); Tcl_SetErrorCode(interp, "TCL", "COROUTINE", "ILLEGAL_YIELD", NULL); return TCL_ERROR; } @@ -8488,7 +8477,7 @@ YieldToCallback( * yieldTo: invoke the command using tailcall tech. */ - TclNRAddCallback(interp, NRTailcallEval, listPtr, nsPtr, NULL, NULL); + TclNRAddCallback(interp, TclNRTailcallEval, listPtr, nsPtr, NULL, NULL); cbPtr = TOP_CB(interp); TOP_CB(interp) = cbPtr->nextPtr; @@ -8633,7 +8622,7 @@ NRCoroutineExitCallback( /* *---------------------------------------------------------------------- * - * NRCoroutineActivateCallback -- + * TclNRCoroutineActivateCallback -- * * This is the workhorse for coroutines: it implements both yield and * resume. @@ -8647,8 +8636,8 @@ NRCoroutineExitCallback( *---------------------------------------------------------------------- */ -static int -NRCoroutineActivateCallback( +int +TclNRCoroutineActivateCallback( ClientData data[], Tcl_Interp *interp, int result) @@ -8688,8 +8677,8 @@ NRCoroutineActivateCallback( */ if (corPtr->stackLevel != stackLevel) { - Tcl_SetResult(interp, "cannot yield: C stack busy", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "cannot yield: C stack busy", -1)); Tcl_SetErrorCode(interp, "TCL", "COROUTINE", "CANT_YIELD", NULL); return TCL_ERROR; @@ -8748,8 +8737,8 @@ NRCoroInjectObjCmd( cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, objv[1]); if ((!cmdPtr) || (cmdPtr->nreProc != TclNRInterpCoroutine)) { - Tcl_AppendResult(interp, "can only inject a command into a coroutine", - NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "can only inject a command into a coroutine", -1)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COROUTINE", TclGetString(objv[1]), NULL); return TCL_ERROR; @@ -8757,8 +8746,8 @@ NRCoroInjectObjCmd( corPtr = cmdPtr->objClientData; if (!COR_IS_SUSPENDED(corPtr)) { - Tcl_AppendResult(interp, - "can only inject a command into a suspended coroutine", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "can only inject a command into a suspended coroutine", -1)); Tcl_SetErrorCode(interp, "TCL", "COROUTINE", "ACTIVE", NULL); return TCL_ERROR; } @@ -8774,7 +8763,7 @@ NRCoroInjectObjCmd( return TCL_OK; } - + int TclNRInterpCoroutine( ClientData clientData, @@ -8785,9 +8774,9 @@ TclNRInterpCoroutine( CoroutineData *corPtr = clientData; if (!COR_IS_SUSPENDED(corPtr)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "coroutine \"", Tcl_GetString(objv[0]), - "\" is already running", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "coroutine \"%s\" is already running", + Tcl_GetString(objv[0]))); Tcl_SetErrorCode(interp, "TCL", "COROUTINE", "BUSY", NULL); return TCL_ERROR; } @@ -8823,7 +8812,7 @@ TclNRInterpCoroutine( break; } - TclNRAddCallback(interp, NRCoroutineActivateCallback, corPtr, + TclNRAddCallback(interp, TclNRCoroutineActivateCallback, corPtr, NULL, NULL, NULL); return TCL_OK; } @@ -8868,22 +8857,24 @@ TclNRCoroutineObjCmd( &nsPtr, &altNsPtr, &cxtNsPtr, &procName); if (nsPtr == NULL) { - Tcl_AppendResult(interp, "can't create procedure \"", fullName, - "\": unknown namespace", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't create procedure \"%s\": unknown namespace", + fullName)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "NAMESPACE", NULL); return TCL_ERROR; } if (procName == NULL) { - Tcl_AppendResult(interp, "can't create procedure \"", fullName, - "\": bad procedure name", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't create procedure \"%s\": bad procedure name", + fullName)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "COMMAND", fullName, NULL); return TCL_ERROR; } if ((nsPtr != iPtr->globalNsPtr) && (procName != NULL) && (procName[0] == ':')) { - Tcl_AppendResult(interp, "can't create procedure \"", procName, - "\" in non-global namespace with name starting with \":\"", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't create procedure \"%s\" in non-global namespace with" + " name starting with \":\"", procName)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "COMMAND", procName, NULL); return TCL_ERROR; } @@ -8947,7 +8938,6 @@ TclNRCoroutineObjCmd( corPtr->running.lineLABCPtr = corPtr->lineLABCPtr; corPtr->stackLevel = NULL; corPtr->auxNumLevels = 0; - iPtr->numLevels--; /* * Create the coro's execEnv, switch to it to push the exit and coro @@ -8966,19 +8956,20 @@ TclNRCoroutineObjCmd( TclNRAddCallback(interp, NRCoroutineExitCallback, corPtr, NULL, NULL, NULL); + /* insure that the command is looked up in the correct namespace */ iPtr->lookupNsPtr = lookupNsPtr; Tcl_NREvalObj(interp, Tcl_NewListObj(objc-2, objv+2), 0); + iPtr->numLevels--; SAVE_CONTEXT(corPtr->running); RESTORE_CONTEXT(corPtr->caller); iPtr->execEnvPtr = corPtr->callerEEPtr; /* - * Now just resume the coroutine. Take care to insure that the command is - * looked up in the correct namespace. + * Now just resume the coroutine. */ - TclNRAddCallback(interp, NRCoroutineActivateCallback, corPtr, + TclNRAddCallback(interp, TclNRCoroutineActivateCallback, corPtr, NULL, NULL, NULL); return TCL_OK; } diff --git a/generic/tclBinary.c b/generic/tclBinary.c index 444e7fa..3d8b24c 100644 --- a/generic/tclBinary.c +++ b/generic/tclBinary.c @@ -303,18 +303,16 @@ Tcl_SetByteArrayObj( TclFreeIntRep(objPtr); Tcl_InvalidateStringRep(objPtr); - length = (length < 0) ? 0 : length; + if (length < 0) { + length = 0; + } byteArrayPtr = ckalloc(BYTEARRAY_SIZE(length)); byteArrayPtr->used = length; byteArrayPtr->allocated = length; - if (length) { - if (bytes) { - memcpy(byteArrayPtr->bytes, bytes, (size_t) length); - } else { - memset(byteArrayPtr->bytes, 0, (size_t) length); - } - } + if ((bytes != NULL) && (length > 0)) { + memcpy(byteArrayPtr->bytes, bytes, (size_t) length); + } objPtr->typePtr = &tclByteArrayType; SET_BYTEARRAY(objPtr, byteArrayPtr); } @@ -873,9 +871,9 @@ BinaryFormatCmd( if (count == BINARY_ALL) { count = listc; } else if (count > listc) { - Tcl_AppendResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "number of elements in list does not match count", - NULL); + -1)); return TCL_ERROR; } } @@ -884,9 +882,8 @@ BinaryFormatCmd( case 'x': if (count == BINARY_ALL) { - Tcl_AppendResult(interp, - "cannot use \"*\" in format string with \"x\"", - NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "cannot use \"*\" in format string with \"x\"", -1)); return TCL_ERROR; } else if (count == BINARY_NOCOUNT) { count = 1; @@ -1198,8 +1195,9 @@ BinaryFormatCmd( badValue: Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "expected ", errorString, - " string but got \"", errorValue, "\" instead", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "expected %s string but got \"%s\" instead", + errorString, errorValue)); return TCL_ERROR; badCount: @@ -1217,12 +1215,13 @@ BinaryFormatCmd( Tcl_UtfToUniChar(errorString, &ch); buf[Tcl_UniCharToUtf(ch, buf)] = '\0'; - Tcl_AppendResult(interp, "bad field specifier \"", buf, "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad field specifier \"%s\"", buf)); return TCL_ERROR; } error: - Tcl_AppendResult(interp, errorString, NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj(errorString, -1)); return TCL_ERROR; } @@ -1586,12 +1585,13 @@ BinaryScanCmd( Tcl_UtfToUniChar(errorString, &ch); buf[Tcl_UniCharToUtf(ch, buf)] = '\0'; - Tcl_AppendResult(interp, "bad field specifier \"", buf, "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad field specifier \"%s\"", buf)); return TCL_ERROR; } error: - Tcl_AppendResult(interp, errorString, NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj(errorString, -1)); return TCL_ERROR; } diff --git a/generic/tclCkalloc.c b/generic/tclCkalloc.c index 5b5a0d6..ab977cb 100644 --- a/generic/tclCkalloc.c +++ b/generic/tclCkalloc.c @@ -170,11 +170,15 @@ TclInitDbCkalloc(void) */ int -TclDumpMemoryInfo(ClientData clientData, int flags) +TclDumpMemoryInfo( + ClientData clientData, + int flags) { char buf[1024]; - if (clientData == NULL) { return 0; } + if (clientData == NULL) { + return 0; + } sprintf(buf, "total mallocs %10d\n" "total frees %10d\n" @@ -815,15 +819,16 @@ MemoryCmd( size_t len; if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " option [args..]\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "wrong # args: should be \"%s option [args..]\"", argv[0])); return TCL_ERROR; } - if ((strcmp(argv[1],"active") == 0) || (strcmp(argv[1],"display") == 0)) { + if (strcmp(argv[1], "active") == 0 || strcmp(argv[1], "display") == 0) { if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " ", argv[1], " file\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "wrong # args: should be \"%s %s file\"", + argv[0], argv[1])); return TCL_ERROR; } fileName = Tcl_TranslateFileName(interp, argv[2], &buffer); @@ -833,7 +838,8 @@ MemoryCmd( result = Tcl_DumpActiveMemory(fileName); Tcl_DStringFree(&buffer); if (result != TCL_OK) { - Tcl_AppendResult(interp, "error accessing ", argv[2], NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf("error accessing %s: %s", + argv[2], Tcl_PosixError(interp))); return TCL_ERROR; } return TCL_OK; @@ -857,17 +863,17 @@ MemoryCmd( "maximum bytes allocated", (unsigned long)maximum_bytes_malloced)); return TCL_OK; } - if (strcmp(argv[1],"init") == 0) { + if (strcmp(argv[1], "init") == 0) { if (argc != 3) { goto bad_suboption; } init_malloced_bodies = (strcmp(argv[2],"on") == 0); return TCL_OK; } - if (strcmp(argv[1],"objs") == 0) { + if (strcmp(argv[1], "objs") == 0) { if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " objs file\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "wrong # args: should be \"%s objs file\"", argv[0])); return TCL_ERROR; } fileName = Tcl_TranslateFileName(interp, argv[2], &buffer); @@ -876,7 +882,9 @@ MemoryCmd( } fileP = fopen(fileName, "w"); if (fileP == NULL) { - Tcl_AppendResult(interp, "cannot open output file", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "cannot open output file: %s", + Tcl_PosixError(interp))); return TCL_ERROR; } TclDbDumpActiveObjects(fileP); @@ -886,8 +894,8 @@ MemoryCmd( } if (strcmp(argv[1],"onexit") == 0) { if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " onexit file\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "wrong # args: should be \"%s onexit file\"", argv[0])); return TCL_ERROR; } fileName = Tcl_TranslateFileName(interp, argv[2], &buffer); @@ -901,8 +909,8 @@ MemoryCmd( } if (strcmp(argv[1],"tag") == 0) { if (argc != 3) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " tag string\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "wrong # args: should be \"%s tag string\"", argv[0])); return TCL_ERROR; } if ((curTagPtr != NULL) && (curTagPtr->refCount == 0)) { @@ -939,19 +947,20 @@ MemoryCmd( return TCL_OK; } - Tcl_AppendResult(interp, "bad option \"", argv[1], - "\": should be active, break_on_malloc, info, init, objs, onexit, " - "tag, trace, trace_on_at_malloc, or validate", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad option \"%s\": should be active, break_on_malloc, info, " + "init, objs, onexit, tag, trace, trace_on_at_malloc, or validate", + argv[1])); return TCL_ERROR; argError: - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " ", argv[1], " count\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "wrong # args: should be \"%s %s count\"", argv[0], argv[1])); return TCL_ERROR; bad_suboption: - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " ", argv[1], " on|off\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "wrong # args: should be \"%s %s on|off\"", argv[0], argv[1])); return TCL_ERROR; } @@ -981,8 +990,8 @@ CheckmemCmd( const char *argv[]) /* String values of arguments. */ { if (argc != 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " fileName\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "wrong # args: should be \"%s fileName\"", argv[0])); return TCL_ERROR; } tclMemDumpFileName = dumpFile; @@ -1250,7 +1259,9 @@ Tcl_ValidateAllMemory( } int -TclDumpMemoryInfo(ClientData clientData, int flags) +TclDumpMemoryInfo( + ClientData clientData, + int flags) { return 1; } diff --git a/generic/tclClock.c b/generic/tclClock.c index 7fa4017..6d2976d 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -878,8 +878,8 @@ ConvertLocalToUTCUsingC( if (localErrno != 0 || (fields->seconds == -1 && timeVal.tm_yday == -1)) { - Tcl_SetResult(interp, "time value too large/small to represent", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "time value too large/small to represent", -1)); return TCL_ERROR; } return TCL_OK; @@ -1018,17 +1018,17 @@ ConvertUTCToLocalUsingC( tock = (time_t) fields->seconds; if ((Tcl_WideInt) tock != fields->seconds) { - Tcl_AppendResult(interp, - "number too large to represent as a Posix time", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "number too large to represent as a Posix time", -1)); Tcl_SetErrorCode(interp, "CLOCK", "argTooLarge", NULL); return TCL_ERROR; } TzsetIfNecessary(); timeVal = ThreadSafeLocalTime(&tock); if (timeVal == NULL) { - Tcl_AppendResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "localtime failed (clock value may be too " - "large/small to represent)", NULL); + "large/small to represent)", -1)); Tcl_SetErrorCode(interp, "CLOCK", "localtimeFailed", NULL); return TCL_ERROR; } diff --git a/generic/tclCmdAH.c b/generic/tclCmdAH.c index f09ee70..14951e4 100644 --- a/generic/tclCmdAH.c +++ b/generic/tclCmdAH.c @@ -32,6 +32,9 @@ struct ForeachState { int *argcList; /* Array of value list sizes. */ Tcl_Obj ***argvList; /* Array of value lists. */ Tcl_Obj **aCopyList; /* Copies of value list arguments. */ + Tcl_Obj *resultList; /* List of result values from the loop body, + * or NULL if we're not collecting them + * ([lmap] vs [foreach]). */ }; /* @@ -52,6 +55,8 @@ static int GetStatBuf(Tcl_Interp *interp, Tcl_Obj *pathPtr, static const char * GetTypeFromMode(int mode); static int StoreStatData(Tcl_Interp *interp, Tcl_Obj *varName, Tcl_StatBuf *statPtr); +static inline int EachloopCmd(Tcl_Interp *interp, int collect, + int objc, Tcl_Obj *const objv[]); static Tcl_NRPostProc CatchObjCmdCallback; static Tcl_NRPostProc ExprCallback; static Tcl_NRPostProc ForSetupCallback; @@ -194,7 +199,8 @@ Tcl_CaseObjCmd( if (i == caseObjc-1) { Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "extra case pattern with no body", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "extra case pattern with no body", -1)); return TCL_ERROR; } @@ -409,8 +415,9 @@ Tcl_CdObjCmd( } else { result = Tcl_FSChdir(dir); if (result != TCL_OK) { - Tcl_AppendResult(interp, "couldn't change working directory to \"", - TclGetString(dir), "\": ", Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't change working directory to \"%s\": %s", + TclGetString(dir), Tcl_PosixError(interp))); result = TCL_ERROR; } } @@ -642,8 +649,9 @@ EncodingDirsObjCmd( dirListObj = objv[2]; if (Tcl_SetEncodingSearchPath(dirListObj) == TCL_ERROR) { - Tcl_AppendResult(interp, "expected directory list but got \"", - TclGetString(dirListObj), "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "expected directory list but got \"%s\"", + TclGetString(dirListObj))); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "ENCODING", "BADPATH", NULL); return TCL_ERROR; @@ -1165,9 +1173,9 @@ FileAttrAccessTimeCmd( tval.modtime = buf.st_mtime; if (Tcl_FSUtime(objv[1], &tval) != 0) { - Tcl_AppendResult(interp, "could not set access time for file \"", - TclGetString(objv[1]), "\": ", Tcl_PosixError(interp), - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not set access time for file \"%s\": %s", + TclGetString(objv[1]), Tcl_PosixError(interp))); return TCL_ERROR; } @@ -1237,9 +1245,9 @@ FileAttrModifyTimeCmd( tval.modtime = newTime; if (Tcl_FSUtime(objv[1], &tval) != 0) { - Tcl_AppendResult(interp, "could not set modification time for " - "file \"", TclGetString(objv[1]), "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not set modification time for file \"%s\": %s", + TclGetString(objv[1]), Tcl_PosixError(interp))); return TCL_ERROR; } @@ -1842,7 +1850,7 @@ PathFilesystemCmd( } fsInfo = Tcl_FSFileSystemInfo(objv[1]); if (fsInfo == NULL) { - Tcl_SetResult(interp, "unrecognised path", TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj("unrecognised path", -1)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "FILESYSTEM", Tcl_GetString(objv[1]), NULL); return TCL_ERROR; @@ -1990,8 +1998,9 @@ PathSplitCmd( } res = Tcl_FSSplitPath(objv[1], NULL); if (res == NULL) { - Tcl_AppendResult(interp, "could not read \"", TclGetString(objv[1]), - "\": no such file or directory", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read \"%s\": no such file or directory", + TclGetString(objv[1]))); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PATHSPLIT", "NONESUCH", NULL); return TCL_ERROR; @@ -2092,7 +2101,8 @@ FilesystemSeparatorCmd( Tcl_Obj *separatorObj = Tcl_FSPathSeparator(objv[1]); if (separatorObj == NULL) { - Tcl_SetResult(interp, "unrecognised path", TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "unrecognised path", -1)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "FILESYSTEM", Tcl_GetString(objv[1]), NULL); return TCL_ERROR; @@ -2211,9 +2221,9 @@ GetStatBuf( if (status < 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not read \"", - TclGetString(pathPtr), "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read \"%s\": %s", + TclGetString(pathPtr), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -2560,7 +2570,7 @@ ForPostNextCallback( /* *---------------------------------------------------------------------- * - * Tcl_ForeachObjCmd, TclNRForeachCmd -- + * Tcl_ForeachObjCmd, TclNRForeachCmd, EachloopCmd -- * * This object-based procedure is invoked to process the "foreach" Tcl * command. See the user documentation for details on what it does. @@ -2592,6 +2602,38 @@ TclNRForeachCmd( int objc, Tcl_Obj *const objv[]) { + return EachloopCmd(interp, TCL_EACH_KEEP_NONE, objc, objv); +} + +int +Tcl_LmapObjCmd( + ClientData dummy, /* Not used. */ + Tcl_Interp *interp, /* Current interpreter. */ + int objc, /* Number of arguments. */ + Tcl_Obj *const objv[]) /* Argument objects. */ +{ + return Tcl_NRCallObjProc(interp, TclNRLmapCmd, dummy, objc, objv); +} + +int +TclNRLmapCmd( + ClientData dummy, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + return EachloopCmd(interp, TCL_EACH_COLLECT, objc, objv); +} + +static inline int +EachloopCmd( + Tcl_Interp *interp, /* Our context for variables and script + * evaluation. */ + int collect, /* Select collecting or accumulating mode + * (TCL_EACH_*) */ + int objc, /* The arguments being passed in... */ + Tcl_Obj *const objv[]) +{ int numLists = (objc-2) / 2; register struct ForeachState *statePtr; int i, j, result; @@ -2635,6 +2677,12 @@ TclNRForeachCmd( statePtr->bodyPtr = objv[objc - 1]; statePtr->bodyIdx = objc - 1; + if (collect == TCL_EACH_COLLECT) { + statePtr->resultList = Tcl_NewListObj(0, NULL); + } else { + statePtr->resultList = NULL; + } + /* * Break up the value lists and variable lists into elements. */ @@ -2648,8 +2696,11 @@ TclNRForeachCmd( TclListObjGetElements(NULL, statePtr->vCopyList[i], &statePtr->varcList[i], &statePtr->varvList[i]); if (statePtr->varcList[i] < 1) { - Tcl_AppendResult(interp, "foreach varlist is empty", NULL); - Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FOREACH", + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "%s varlist is empty", + (statePtr->resultList != NULL ? "lmap" : "foreach"))); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", + (statePtr->resultList != NULL ? "LMAP" : "FOREACH"), "NEEDVARS", NULL); result = TCL_ERROR; goto done; @@ -2719,14 +2770,21 @@ ForeachLoopStep( switch (result) { case TCL_CONTINUE: result = TCL_OK; + break; case TCL_OK: + if (statePtr->resultList != NULL) { + Tcl_ListObjAppendElement(interp, statePtr->resultList, + Tcl_GetObjResult(interp)); + } break; case TCL_BREAK: result = TCL_OK; - goto done; + goto finish; case TCL_ERROR: Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( - "\n (\"foreach\" body line %d)", Tcl_GetErrorLine(interp))); + "\n (\"%s\" body line %d)", + (statePtr->resultList != NULL ? "lmap" : "foreach"), + Tcl_GetErrorLine(interp))); default: goto done; } @@ -2751,7 +2809,14 @@ ForeachLoopStep( * We're done. Tidy up our work space and finish off. */ - Tcl_ResetResult(interp); + finish: + if (statePtr->resultList == NULL) { + Tcl_ResetResult(interp); + } else { + Tcl_SetObjResult(interp, statePtr->resultList); + statePtr->resultList = NULL; /* Don't clean it up */ + } + done: ForeachCleanup(interp, statePtr); return result; @@ -2784,7 +2849,8 @@ ForeachAssignments( if (varValuePtr == NULL) { Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( - "\n (setting foreach loop variable \"%s\")", + "\n (setting %s loop variable \"%s\")", + (statePtr->resultList != NULL ? "lmap" : "foreach"), TclGetString(statePtr->varvList[i][v]))); return TCL_ERROR; } @@ -2813,6 +2879,9 @@ ForeachCleanup( TclDecrRefCount(statePtr->aCopyList[i]); } } + if (statePtr->resultList != NULL) { + TclDecrRefCount(statePtr->resultList); + } TclStackFree(interp, statePtr); } diff --git a/generic/tclCmdIL.c b/generic/tclCmdIL.c index b312026..155e8e4 100644 --- a/generic/tclCmdIL.c +++ b/generic/tclCmdIL.c @@ -27,15 +27,15 @@ */ typedef struct SortElement { - union { /* The value that we sorting by. */ + union { /* The value that we sorting by. */ const char *strValuePtr; long intValue; double doubleValue; Tcl_Obj *objValuePtr; } collationKey; - union { /* Object being sorted, or its index. */ - Tcl_Obj *objPtr; - int index; + union { /* Object being sorted, or its index. */ + Tcl_Obj *objPtr; + int index; } payload; struct SortElement *nextPtr;/* Next element in the list, or NULL for end * of list. */ @@ -164,9 +164,9 @@ static const EnsembleImplMap defaultInfoMap[] = { {"args", InfoArgsCmd, NULL, NULL, NULL, 0}, {"body", InfoBodyCmd, NULL, NULL, NULL, 0}, {"cmdcount", InfoCmdCountCmd, NULL, NULL, NULL, 0}, - {"commands", InfoCommandsCmd, NULL, NULL, NULL, 0}, + {"commands", InfoCommandsCmd, TclCompileInfoCommandsCmd, NULL, NULL, 0}, {"complete", InfoCompleteCmd, NULL, NULL, NULL, 0}, - {"coroutine", TclInfoCoroutineCmd, NULL, NULL, NULL, 0}, + {"coroutine", TclInfoCoroutineCmd, TclCompileInfoCoroutineCmd, NULL, NULL, 0}, {"default", InfoDefaultCmd, NULL, NULL, NULL, 0}, {"errorstack", InfoErrorStackCmd, NULL, NULL, NULL, 0}, {"exists", TclInfoExistsCmd, TclCompileInfoExistsCmd, NULL, NULL, 0}, @@ -174,7 +174,7 @@ static const EnsembleImplMap defaultInfoMap[] = { {"functions", InfoFunctionsCmd, NULL, NULL, NULL, 0}, {"globals", TclInfoGlobalsCmd, NULL, NULL, NULL, 0}, {"hostname", InfoHostnameCmd, NULL, NULL, NULL, 0}, - {"level", InfoLevelCmd, NULL, NULL, NULL, 0}, + {"level", InfoLevelCmd, TclCompileInfoLevelCmd, NULL, NULL, 0}, {"library", InfoLibraryCmd, NULL, NULL, NULL, 0}, {"loaded", InfoLoadedCmd, NULL, NULL, NULL, 0}, {"locals", TclInfoLocalsCmd, NULL, NULL, NULL, 0}, @@ -229,8 +229,9 @@ TclNRIfObjCmd( Tcl_Obj *boolObj; if (objc <= 1) { - Tcl_AppendResult(interp, "wrong # args: no expression after \"", - TclGetString(objv[0]), "\" argument", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "wrong # args: no expression after \"%s\" argument", + TclGetString(objv[0]))); Tcl_SetErrorCode(interp, "TCL", "WRONGARGS", NULL); return TCL_ERROR; } @@ -319,8 +320,9 @@ IfConditionCallback( */ if (i >= objc) { - Tcl_AppendResult(interp, "wrong # args: ", - "no expression after \"", clause, "\" argument", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "wrong # args: no expression after \"%s\" argument", + clause)); Tcl_SetErrorCode(interp, "TCL", "WRONGARGS", NULL); return TCL_ERROR; } @@ -345,8 +347,9 @@ IfConditionCallback( } } if (i < objc - 1) { - Tcl_AppendResult(interp, "wrong # args: ", - "extra words after \"else\" clause in \"if\" command", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "wrong # args: extra words after \"else\" clause in \"if\" command", + -1)); Tcl_SetErrorCode(interp, "TCL", "WRONGARGS", NULL); return TCL_ERROR; } @@ -361,9 +364,9 @@ IfConditionCallback( return TclNREvalObjEx(interp, objv[i], 0, iPtr->cmdFramePtr, i); missingScript: - clause = TclGetString(objv[i-1]); - Tcl_AppendResult(interp, "wrong # args: no script following \"", clause, - "\" argument", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "wrong # args: no script following \"%s\" argument", + TclGetString(objv[i-1]))); Tcl_SetErrorCode(interp, "TCL", "WRONGARGS", NULL); return TCL_ERROR; } @@ -491,7 +494,8 @@ InfoArgsCmd( name = TclGetString(objv[1]); procPtr = TclFindProc(iPtr, name); if (procPtr == NULL) { - Tcl_AppendResult(interp, "\"", name, "\" isn't a procedure", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "\"%s\" isn't a procedure", name)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "PROCEDURE", name, NULL); return TCL_ERROR; } @@ -552,7 +556,8 @@ InfoBodyCmd( name = TclGetString(objv[1]); procPtr = TclFindProc(iPtr, name); if (procPtr == NULL) { - Tcl_AppendResult(interp, "\"", name, "\" isn't a procedure", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "\"%s\" isn't a procedure", name)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "PROCEDURE", name, NULL); return TCL_ERROR; } @@ -981,7 +986,8 @@ InfoDefaultCmd( procPtr = TclFindProc(iPtr, procName); if (procPtr == NULL) { - Tcl_AppendResult(interp, "\"", procName, "\" isn't a procedure",NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "\"%s\" isn't a procedure", procName)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "PROCEDURE", procName, NULL); return TCL_ERROR; @@ -1012,8 +1018,9 @@ InfoDefaultCmd( } } - Tcl_AppendResult(interp, "procedure \"", procName, - "\" doesn't have an argument \"", argName, "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "procedure \"%s\" doesn't have an argument \"%s\"", + procName, argName)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ARGUMENT", argName, NULL); return TCL_ERROR; } @@ -1055,10 +1062,10 @@ InfoErrorStackCmd( target = interp; if (objc == 2) { - target = Tcl_GetSlave(interp, Tcl_GetString(objv[1])); - if (target == NULL) { - return TCL_ERROR; - } + target = Tcl_GetSlave(interp, Tcl_GetString(objv[1])); + if (target == NULL) { + return TCL_ERROR; + } } iPtr = (Interp *) target; @@ -1158,12 +1165,13 @@ InfoFrameCmd( * A coroutine: must fix the level computations AND the cmdFrame chain, * which is interrupted at the base. */ + CmdFrame *lastPtr = NULL; - runPtr = iPtr->cmdFramePtr; + runPtr = iPtr->cmdFramePtr; /* TODO - deal with overflow */ - topLevel += corPtr->caller.cmdFramePtr->level; + topLevel += corPtr->caller.cmdFramePtr->level; while (runPtr) { runPtr->level += corPtr->caller.cmdFramePtr->level; lastPtr = runPtr; @@ -1196,8 +1204,8 @@ InfoFrameCmd( if ((level > topLevel) || (level <= - topLevel)) { levelError: - Tcl_AppendResult(interp, "bad level \"", TclGetString(objv[1]), "\"", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad level \"%s\"", TclGetString(objv[1]))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "STACK_FRAME", TclGetString(objv[1]), NULL); code = TCL_ERROR; @@ -1401,15 +1409,15 @@ TclInfoFrame( Tcl_HashEntry *namePtr = procPtr->cmdPtr->hPtr; if (namePtr) { - Tcl_Obj *procNameObj; + Tcl_Obj *procNameObj; /* * This is a regular command. */ - TclNewObj(procNameObj); - Tcl_GetCommandFullName(interp, (Tcl_Command) procPtr->cmdPtr, - procNameObj); + TclNewObj(procNameObj); + Tcl_GetCommandFullName(interp, (Tcl_Command) procPtr->cmdPtr, + procNameObj); ADD_PAIR("proc", procNameObj); } else if (procPtr->cmdPtr->clientData) { ExtraFrameInfo *efiPtr = procPtr->cmdPtr->clientData; @@ -1484,19 +1492,42 @@ InfoFunctionsCmd( int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { - const char *pattern; + Tcl_Obj *script; + int code; - if (objc == 1) { - pattern = NULL; - } else if (objc == 2) { - pattern = TclGetString(objv[1]); - } else { + if (objc > 2) { Tcl_WrongNumArgs(interp, 1, objv, "?pattern?"); return TCL_ERROR; } - Tcl_SetObjResult(interp, Tcl_ListMathFuncs(interp, pattern)); - return TCL_OK; + script = Tcl_NewStringObj( +" ::apply [::list {{pattern *}} {\n" +" ::set cmds {}\n" +" ::foreach cmd [::info commands ::tcl::mathfunc::$pattern] {\n" +" ::lappend cmds [::namespace tail $cmd]\n" +" }\n" +" ::foreach cmd [::info commands tcl::mathfunc::$pattern] {\n" +" ::set cmd [::namespace tail $cmd]\n" +" ::if {$cmd ni $cmds} {\n" +" ::lappend cmds $cmd\n" +" }\n" +" }\n" +" ::return $cmds\n" +" } [::namespace current]] ", -1); + + if (objc == 2) { + Tcl_Obj *arg = Tcl_NewListObj(1, &(objv[1])); + + Tcl_AppendObjToObj(script, arg); + Tcl_DecrRefCount(arg); + } + + Tcl_IncrRefCount(script); + code = Tcl_EvalObjEx(interp, script, 0); + + Tcl_DecrRefCount(script); + + return code; } /* @@ -1538,7 +1569,9 @@ InfoHostnameCmd( Tcl_SetObjResult(interp, Tcl_NewStringObj(name, -1)); return TCL_OK; } - Tcl_SetResult(interp, "unable to determine name of host", TCL_STATIC); + + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "unable to determine name of host", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "HOSTNAME", "UNKNOWN", NULL); return TCL_ERROR; } @@ -1609,8 +1642,8 @@ InfoLevelCmd( return TCL_ERROR; levelError: - Tcl_AppendResult(interp, "bad level \"", TclGetString(objv[1]), "\"", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad level \"%s\"", TclGetString(objv[1]))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "STACK_LEVEL", TclGetString(objv[1]), NULL); return TCL_ERROR; @@ -1656,7 +1689,9 @@ InfoLibraryCmd( Tcl_SetObjResult(interp, Tcl_NewStringObj(libDirName, -1)); return TCL_OK; } - Tcl_SetResult(interp, "no library has been specified for Tcl",TCL_STATIC); + + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "no library has been specified for Tcl", -1)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "VARIABLE", "tcl_library",NULL); return TCL_ERROR; } @@ -2590,9 +2625,10 @@ Tcl_LrepeatObjCmd( return TCL_ERROR; } if (elementCount < 0) { - Tcl_SetObjResult(interp, Tcl_Format(NULL, - "bad count \"%d\": must be integer >= 0", 1, objv+1)); - Tcl_SetErrorCode(interp, "TCL","OPERATION","LREPEAT","NEGARG", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad count \"%d\": must be integer >= 0", elementCount)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LREPEAT", "NEGARG", + NULL); return TCL_ERROR; } @@ -2608,7 +2644,7 @@ Tcl_LrepeatObjCmd( if (elementCount && objc > LIST_MAX/elementCount) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "max length of a Tcl list (%d elements) exceeded", LIST_MAX)); - Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL); + Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL); return TCL_ERROR; } totalElems = objc * elementCount; @@ -2723,9 +2759,10 @@ Tcl_LreplaceObjCmd( */ if ((first >= listLen) && (listLen > 0)) { - Tcl_AppendResult(interp, "list doesn't contain element ", - TclGetString(objv[2]), NULL); - Tcl_SetErrorCode(interp, "TCL","OPERATION","LREPLACE","BADIDX", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "list doesn't contain element %s", TclGetString(objv[2]))); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LREPLACE", "BADIDX", + NULL); return TCL_ERROR; } if (last >= listLen) { @@ -2996,8 +3033,9 @@ Tcl_LsearchObjCmd( Tcl_DecrRefCount(startPtr); } if (i > objc-4) { - Tcl_AppendResult(interp, "missing starting index", NULL); - Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "missing starting index", -1)); + Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING", NULL); result = TCL_ERROR; goto done; } @@ -3027,10 +3065,10 @@ Tcl_LsearchObjCmd( if (startPtr != NULL) { Tcl_DecrRefCount(startPtr); } - Tcl_AppendResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "\"-index\" option must be followed by list index", - NULL); - Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING", NULL); + -1)); + Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING", NULL); return TCL_ERROR; } @@ -3088,18 +3126,18 @@ Tcl_LsearchObjCmd( if (startPtr != NULL) { Tcl_DecrRefCount(startPtr); } - Tcl_AppendResult(interp, - "-subindices cannot be used without -index option", NULL); - Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSEARCH", - "BAD_OPTION_MIX", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "-subindices cannot be used without -index option", -1)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSEARCH", + "BAD_OPTION_MIX", NULL); return TCL_ERROR; } if (bisect && (allMatches || negatedMatch)) { - Tcl_AppendResult(interp, - "-bisect is not compatible with -all or -not", NULL); - Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSEARCH", - "BAD_OPTION_MIX", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "-bisect is not compatible with -all or -not", -1)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSEARCH", + "BAD_OPTION_MIX", NULL); return TCL_ERROR; } @@ -3531,7 +3569,7 @@ Tcl_LsetObjCmd( if (objc < 3) { Tcl_WrongNumArgs(interp, 1, objv, - "listVar ?index? ?index ...? value"); + "listVar ?index? ?index ...? value"); return TCL_ERROR; } @@ -3664,10 +3702,10 @@ Tcl_LsortObjCmd( break; case LSORT_COMMAND: if (i == objc-2) { - Tcl_AppendResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "\"-command\" option must be followed " - "by comparison command", NULL); - Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING", NULL); + "by comparison command", -1)); + Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING", NULL); sortInfo.resultCode = TCL_ERROR; goto done2; } @@ -3685,29 +3723,30 @@ Tcl_LsortObjCmd( sortInfo.isIncreasing = 1; break; case LSORT_INDEX: { - int indexc, dummy; + int indexc, dummy; Tcl_Obj **indexv; if (i == objc-2) { - Tcl_AppendResult(interp, "\"-index\" option must be " - "followed by list index", NULL); - Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING", NULL); - sortInfo.resultCode = TCL_ERROR; - goto done2; + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "\"-index\" option must be followed by list index", + -1)); + Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING", NULL); + sortInfo.resultCode = TCL_ERROR; + goto done2; } if (TclListObjGetElements(interp, objv[i+1], &indexc, &indexv) != TCL_OK) { - sortInfo.resultCode = TCL_ERROR; - goto done2; + sortInfo.resultCode = TCL_ERROR; + goto done2; } - /* - * Check each of the indices for syntactic correctness. Note that - * we do not store the converted values here because we do not - * know if this is the only -index option yet and so we can't - * allocate any space; that happens after the scan through all the - * options is done. - */ + /* + * Check each of the indices for syntactic correctness. Note that + * we do not store the converted values here because we do not + * know if this is the only -index option yet and so we can't + * allocate any space; that happens after the scan through all the + * options is done. + */ for (j=0 ; j<indexc ; j++) { if (TclGetIntForIndexM(interp, indexv[j], SORTIDX_END, @@ -3719,7 +3758,7 @@ Tcl_LsortObjCmd( } } indexPtr = objv[i+1]; - i++; + i++; break; } case LSORT_INTEGER: @@ -3739,9 +3778,10 @@ Tcl_LsortObjCmd( break; case LSORT_STRIDE: if (i == objc-2) { - Tcl_AppendResult(interp, "\"-stride\" option must be ", - "followed by stride length", NULL); - Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "\"-stride\" option must be " + "followed by stride length", -1)); + Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING", NULL); sortInfo.resultCode = TCL_ERROR; goto done2; } @@ -3750,10 +3790,10 @@ Tcl_LsortObjCmd( goto done2; } if (groupSize < 2) { - Tcl_AppendResult(interp, "stride length must be at least 2", - NULL); - Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSORT", - "BADSTRIDE", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "stride length must be at least 2", -1)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSORT", + "BADSTRIDE", NULL); sortInfo.resultCode = TCL_ERROR; goto done2; } @@ -3773,26 +3813,26 @@ Tcl_LsortObjCmd( */ if (indexPtr) { - Tcl_Obj **indexv; - - TclListObjGetElements(interp, indexPtr, &sortInfo.indexc, &indexv); - switch (sortInfo.indexc) { - case 0: - sortInfo.indexv = NULL; - break; - case 1: - sortInfo.indexv = &sortInfo.singleIndex; - break; - default: - sortInfo.indexv = + Tcl_Obj **indexv; + + TclListObjGetElements(interp, indexPtr, &sortInfo.indexc, &indexv); + switch (sortInfo.indexc) { + case 0: + sortInfo.indexv = NULL; + break; + case 1: + sortInfo.indexv = &sortInfo.singleIndex; + break; + default: + sortInfo.indexv = TclStackAlloc(interp, sizeof(int) * sortInfo.indexc); - allocatedIndexVector = 1; /* Cannot use indexc field, as it - * might be decreased by 1 later. */ - } - for (j=0 ; j<sortInfo.indexc ; j++) { - TclGetIntForIndexM(interp, indexv[j], SORTIDX_END, + allocatedIndexVector = 1; /* Cannot use indexc field, as it + * might be decreased by 1 later. */ + } + for (j=0 ; j<sortInfo.indexc ; j++) { + TclGetIntForIndexM(interp, indexv[j], SORTIDX_END, &sortInfo.indexv[j]); - } + } } listObj = objv[objc-1]; @@ -3847,11 +3887,11 @@ Tcl_LsortObjCmd( if (group) { if (length % groupSize) { - Tcl_AppendResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "list size must be a multiple of the stride length", + -1)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSORT", "BADSTRIDE", NULL); - Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSORT", "BADSTRIDE", - NULL); sortInfo.resultCode = TCL_ERROR; goto done; } @@ -3867,11 +3907,11 @@ Tcl_LsortObjCmd( groupOffset = (groupOffset - SORTIDX_END) + groupSize - 1; } if (groupOffset < 0 || groupOffset >= groupSize) { - Tcl_AppendResult(interp, "when used with \"-stride\", the " - "leading \"-index\" value must be within the group", - NULL); - Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSORT", - "BADINDEX", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "when used with \"-stride\", the leading \"-index\"" + " value must be within the group", -1)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSORT", + "BADINDEX", NULL); sortInfo.resultCode = TCL_ERROR; goto done; } @@ -4255,11 +4295,10 @@ SortCompare( if (TclGetIntFromObj(infoPtr->interp, Tcl_GetObjResult(infoPtr->interp), &order) != TCL_OK) { - Tcl_ResetResult(infoPtr->interp); - Tcl_AppendResult(infoPtr->interp, - "-compare command returned non-integer result", NULL); - Tcl_SetErrorCode(infoPtr->interp, "TCL", "OPERATION", "LSORT", - "COMPARISONFAILED", NULL); + Tcl_SetObjResult(infoPtr->interp, Tcl_NewStringObj( + "-compare command returned non-integer result", -1)); + Tcl_SetErrorCode(infoPtr->interp, "TCL", "OPERATION", "LSORT", + "COMPARISONFAILED", NULL); infoPtr->resultCode = TCL_ERROR; return 0; } @@ -4470,11 +4509,11 @@ SelectObjFromSublist( return NULL; } if (currentObj == NULL) { - Tcl_SetObjResult(infoPtr->interp, Tcl_ObjPrintf( - "element %d missing from sublist \"%s\"", - index, TclGetString(objPtr))); - Tcl_SetErrorCode(infoPtr->interp, "TCL", "OPERATION", "LSORT", - "INDEXFAILED", NULL); + Tcl_SetObjResult(infoPtr->interp, Tcl_ObjPrintf( + "element %d missing from sublist \"%s\"", + index, TclGetString(objPtr))); + Tcl_SetErrorCode(infoPtr->interp, "TCL", "OPERATION", "LSORT", + "INDEXFAILED", NULL); infoPtr->resultCode = TCL_ERROR; return NULL; } @@ -4489,6 +4528,5 @@ SelectObjFromSublist( * c-basic-offset: 4 * fill-column: 78 * tab-width: 8 - * indent-tabs-mode: nil * End: */ diff --git a/generic/tclCmdMZ.c b/generic/tclCmdMZ.c index 7e94d9f..fc957c4 100644 --- a/generic/tclCmdMZ.c +++ b/generic/tclCmdMZ.c @@ -34,12 +34,35 @@ static int UniCharIsHexDigit(int character); /* * Default set of characters to trim in [string trim] and friends. This is a - * UTF-8 literal string containing space, tab, newline, carriage return, - * ethiopic wordspace (U+1361), ogham space mark (U+1680), and ideographic - * space (U+3000). [TIP #318] + * UTF-8 literal string containing all Unicode space characters [TIP #413] */ -#define DEFAULT_TRIM_SET " \t\n\r\xe1\x8d\xa1\xe1\x9a\x80\xe3\x80\x80" +#define DEFAULT_TRIM_SET \ + "\x09\x0a\x0b\x0c\x0d " /* ASCII */\ + "\xc0\x80" /* nul (U+0000) */\ + "\xc2\x85" /* next line (U+0085) */\ + "\xc2\xa0" /* non-breaking space (U+00a0) */\ + "\xe1\x9a\x80" /* ogham space mark (U+1680) */ \ + "\xe1\xa0\x8e" /* mongolian vowel separator (U+180e) */\ + "\xe2\x80\x80" /* en quad (U+2000) */\ + "\xe2\x80\x81" /* em quad (U+2001) */\ + "\xe2\x80\x82" /* en space (U+2002) */\ + "\xe2\x80\x83" /* em space (U+2003) */\ + "\xe2\x80\x84" /* three-per-em space (U+2004) */\ + "\xe2\x80\x85" /* four-per-em space (U+2005) */\ + "\xe2\x80\x86" /* six-per-em space (U+2006) */\ + "\xe2\x80\x87" /* figure space (U+2007) */\ + "\xe2\x80\x88" /* punctuation space (U+2008) */\ + "\xe2\x80\x89" /* thin space (U+2009) */\ + "\xe2\x80\x8a" /* hair space (U+200a) */\ + "\xe2\x80\x8b" /* zero width space (U+200b) */\ + "\xe2\x80\xa8" /* line separator (U+2028) */\ + "\xe2\x80\xa9" /* paragraph separator (U+2029) */\ + "\xe2\x80\xaf" /* narrow no-break space (U+202f) */\ + "\xe2\x81\x9f" /* medium mathematical space (U+205f) */\ + "\xe2\x81\xa0" /* word joiner (U+2060) */\ + "\xe3\x80\x80" /* ideographic space (U+3000) */\ + "\xef\xbb\xbf" /* zero width no-break space (U+feff) */ /* *---------------------------------------------------------------------- @@ -204,8 +227,8 @@ Tcl_RegexpObjCmd( */ if (doinline && ((objc - 2) != 0)) { - Tcl_AppendResult(interp, "regexp match variables not allowed" - " when using -inline", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "regexp match variables not allowed when using -inline", -1)); goto optionError; } @@ -1839,8 +1862,8 @@ StringMapCmd( strncmp(string, "-nocase", (size_t) length2) == 0) { nocase = 1; } else { - Tcl_AppendResult(interp, "bad option \"", string, - "\": must be -nocase", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad option \"%s\": must be -nocase", string)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "INDEX", "option", string, NULL); return TCL_ERROR; @@ -2106,8 +2129,8 @@ StringMatchCmd( strncmp(string, "-nocase", (size_t) length) == 0) { nocase = TCL_MATCH_NOCASE; } else { - Tcl_AppendResult(interp, "bad option \"", string, - "\": must be -nocase", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad option \"%s\": must be -nocase", string)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "INDEX", "option", string, NULL); return TCL_ERROR; @@ -2567,8 +2590,9 @@ StringEqualCmd( return TCL_ERROR; } } else { - Tcl_AppendResult(interp, "bad option \"", string2, - "\": must be -nocase or -length", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad option \"%s\": must be -nocase or -length", + string2)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "INDEX", "option", string2, NULL); return TCL_ERROR; @@ -2716,8 +2740,9 @@ StringCmpCmd( return TCL_ERROR; } } else { - Tcl_AppendResult(interp, "bad option \"", string2, - "\": must be -nocase or -length", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad option \"%s\": must be -nocase or -length", + string2)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "INDEX", "option", string2, NULL); return TCL_ERROR; @@ -3302,14 +3327,14 @@ TclInitStringCmd( {"bytelength", StringBytesCmd, NULL, NULL, NULL, 0}, {"compare", StringCmpCmd, TclCompileStringCmpCmd, NULL, NULL, 0}, {"equal", StringEqualCmd, TclCompileStringEqualCmd, NULL, NULL, 0}, - {"first", StringFirstCmd, NULL, NULL, NULL, 0}, + {"first", StringFirstCmd, TclCompileStringFirstCmd, NULL, NULL, 0}, {"index", StringIndexCmd, TclCompileStringIndexCmd, NULL, NULL, 0}, {"is", StringIsCmd, NULL, NULL, NULL, 0}, - {"last", StringLastCmd, NULL, NULL, NULL, 0}, + {"last", StringLastCmd, TclCompileStringLastCmd, NULL, NULL, 0}, {"length", StringLenCmd, TclCompileStringLenCmd, NULL, NULL, 0}, - {"map", StringMapCmd, NULL, NULL, NULL, 0}, + {"map", StringMapCmd, TclCompileStringMapCmd, NULL, NULL, 0}, {"match", StringMatchCmd, TclCompileStringMatchCmd, NULL, NULL, 0}, - {"range", StringRangeCmd, NULL, NULL, NULL, 0}, + {"range", StringRangeCmd, TclCompileStringRangeCmd, NULL, NULL, 0}, {"repeat", StringReptCmd, NULL, NULL, NULL, 0}, {"replace", StringRplcCmd, NULL, NULL, NULL, 0}, {"reverse", StringRevCmd, NULL, NULL, NULL, 0}, @@ -3515,9 +3540,9 @@ TclNRSwitchObjCmd( * Mode already set via -exact, -glob, or -regexp. */ - Tcl_AppendResult(interp, "bad option \"", - TclGetString(objv[i]), "\": ", options[mode], - " option already found", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad option \"%s\": %s option already found", + TclGetString(objv[i]), options[mode])); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SWITCH", "DOUBLEOPT", NULL); return TCL_ERROR; @@ -3534,8 +3559,9 @@ TclNRSwitchObjCmd( case OPT_INDEXV: i++; if (i >= objc-2) { - Tcl_AppendResult(interp, "missing variable name argument to ", - "-indexvar", " option", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "missing variable name argument to %s option", + "-indexvar")); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SWITCH", "NOVAR", NULL); return TCL_ERROR; @@ -3546,8 +3572,9 @@ TclNRSwitchObjCmd( case OPT_MATCHV: i++; if (i >= objc-2) { - Tcl_AppendResult(interp, "missing variable name argument to ", - "-matchvar", " option", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "missing variable name argument to %s option", + "-matchvar")); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SWITCH", "NOVAR", NULL); return TCL_ERROR; @@ -3565,15 +3592,15 @@ TclNRSwitchObjCmd( return TCL_ERROR; } if (indexVarObj != NULL && mode != OPT_REGEXP) { - Tcl_AppendResult(interp, - "-indexvar option requires -regexp option", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "%s option requires -regexp option", "-indexvar")); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SWITCH", "MODERESTRICTION", NULL); return TCL_ERROR; } if (matchVarObj != NULL && mode != OPT_REGEXP) { - Tcl_AppendResult(interp, - "-matchvar option requires -regexp option", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "%s option requires -regexp option", "-matchvar")); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SWITCH", "MODERESTRICTION", NULL); return TCL_ERROR; @@ -3622,7 +3649,8 @@ TclNRSwitchObjCmd( if (objc % 2) { Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "extra switch pattern with no body", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "extra switch pattern with no body", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SWITCH", "BADARM", NULL); @@ -3637,10 +3665,10 @@ TclNRSwitchObjCmd( if (splitObjs) { for (i=0 ; i<objc ; i+=2) { if (TclGetString(objv[i])[0] == '#') { - Tcl_AppendResult(interp, ", this may be due to a " - "comment incorrectly placed outside of a " - "switch body - see the \"switch\" " - "documentation", NULL); + Tcl_AppendToObj(Tcl_GetObjResult(interp), + ", this may be due to a comment incorrectly" + " placed outside of a switch body - see the" + " \"switch\" documentation", -1); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SWITCH", "BADARM", "COMMENT?", NULL); break; @@ -3657,9 +3685,9 @@ TclNRSwitchObjCmd( */ if (strcmp(TclGetString(objv[objc-1]), "-") == 0) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "no body specified for pattern \"", - TclGetString(objv[objc-2]), "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "no body specified for pattern \"%s\"", + TclGetString(objv[objc-2]))); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SWITCH", "BADARM", "FALLTHROUGH", NULL); return TCL_ERROR; @@ -3985,7 +4013,8 @@ Tcl_ThrowObjCmd( if (Tcl_ListObjLength(interp, objv[1], &len) != TCL_OK) { return TCL_ERROR; } else if (len < 1) { - Tcl_AppendResult(interp, "type must be non-empty list", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "type must be non-empty list", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "THROW", "BADEXCEPTION", NULL); return TCL_ERROR; @@ -4169,15 +4198,16 @@ TclNRTryObjCmd( switch ((enum Handlers) type) { case TryFinally: /* finally script */ if (i < objc-2) { - Tcl_AppendResult(interp, "finally clause must be last", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "finally clause must be last", -1)); Tcl_DecrRefCount(handlersObj); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRY", "FINALLY", "NONTERMINAL", NULL); return TCL_ERROR; } else if (i == objc-1) { - Tcl_AppendResult(interp, "wrong # args to finally clause: ", - "must be \"", TclGetString(objv[0]), - " ... finally script\"", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "wrong # args to finally clause: must be" + " \"... finally script\"", -1)); Tcl_DecrRefCount(handlersObj); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRY", "FINALLY", "ARGUMENT", NULL); @@ -4188,15 +4218,16 @@ TclNRTryObjCmd( case TryOn: /* on code variableList script */ if (i > objc-4) { - Tcl_AppendResult(interp, "wrong # args to on clause: ", - "must be \"", TclGetString(objv[0]), - " ... on code variableList script\"", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "wrong # args to on clause: must be \"... on code" + " variableList script\"", -1)); Tcl_DecrRefCount(handlersObj); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRY", "ON", "ARGUMENT", NULL); return TCL_ERROR; } - if (TCL_ERROR == TclGetCompletionCodeFromObj(interp, objv[i+1], &code)) { + if (TclGetCompletionCodeFromObj(interp, objv[i+1], + &code) != TCL_OK) { Tcl_DecrRefCount(handlersObj); return TCL_ERROR; } @@ -4205,9 +4236,10 @@ TclNRTryObjCmd( case TryTrap: /* trap pattern variableList script */ if (i > objc-4) { - Tcl_AppendResult(interp, "wrong # args to trap clause: ", + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "wrong # args to trap clause: " "must be \"... trap pattern variableList script\"", - NULL); + -1)); Tcl_DecrRefCount(handlersObj); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRY", "TRAP", "ARGUMENT", NULL); @@ -4248,9 +4280,8 @@ TclNRTryObjCmd( } } if (bodyShared) { - Tcl_AppendResult(interp, - "last non-finally clause must not have a body of \"-\"", - NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "last non-finally clause must not have a body of \"-\"", -1)); Tcl_DecrRefCount(handlersObj); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRY", "BADFALLTHROUGH", NULL); diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 3540716..160fa3c 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -15,6 +15,7 @@ #include "tclInt.h" #include "tclCompile.h" +#include <assert.h> /* * Prototypes for procedures defined later in this file: @@ -40,6 +41,13 @@ static int PushVarName(Tcl_Interp *interp, int flags, int *localIndexPtr, int *simpleVarNamePtr, int *isScalarPtr, int line, int *clNext); +static int CompileEachloopCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + CompileEnv *envPtr, int collect); +static int CompileDictEachCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr, int collect); + /* * Macro that encapsulates an efficiency trick that avoids a function call for @@ -218,6 +226,245 @@ TclCompileAppendCmd( /* *---------------------------------------------------------------------- * + * TclCompileArray*Cmd -- + * + * Functions called to compile "array" sucommands. + * + * Results: + * All return TCL_OK for a successful compile, and TCL_ERROR to defer + * evaluation to runtime. + * + * Side effects: + * Instructions are added to envPtr to execute the "array" subcommand at + * runtime. + * + *---------------------------------------------------------------------- + */ + +int +TclCompileArrayExistsCmd( + Tcl_Interp *interp, /* Used for looking up stuff. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + DefineLineInformation; /* TIP #280 */ + Tcl_Token *tokenPtr; + int simpleVarName, isScalar, localIndex; + + if (parsePtr->numWords != 2) { + return TCL_ERROR; + } + + tokenPtr = TokenAfter(parsePtr->tokenPtr); + PushVarNameWord(interp, tokenPtr, envPtr, 0, + &localIndex, &simpleVarName, &isScalar, 1); + if (!isScalar) { + return TCL_ERROR; + } + + if (localIndex >= 0) { + TclEmitInstInt4(INST_ARRAY_EXISTS_IMM, localIndex, envPtr); + } else { + TclEmitOpcode( INST_ARRAY_EXISTS_STK, envPtr); + } + return TCL_OK; +} + +int +TclCompileArraySetCmd( + Tcl_Interp *interp, /* Used for looking up stuff. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + DefineLineInformation; /* TIP #280 */ + Tcl_Token *tokenPtr; + int simpleVarName, isScalar, localIndex; + int dataVar, iterVar, keyVar, valVar, infoIndex; + int back, fwd, offsetBack, offsetFwd, savedStackDepth; + ForeachInfo *infoPtr; + + if (parsePtr->numWords != 3) { + return TCL_ERROR; + } + + tokenPtr = TokenAfter(parsePtr->tokenPtr); + PushVarNameWord(interp, tokenPtr, envPtr, 0, + &localIndex, &simpleVarName, &isScalar, 1); + if (!isScalar) { + return TCL_ERROR; + } + tokenPtr = TokenAfter(tokenPtr); + + /* + * Special case: literal empty value argument is just an "ensure array" + * operation. + */ + + if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD && tokenPtr[1].size == 0) { + if (localIndex >= 0) { + TclEmitInstInt4(INST_ARRAY_EXISTS_IMM, localIndex, envPtr); + TclEmitInstInt1(INST_JUMP_TRUE1, 7, envPtr); + TclEmitInstInt4(INST_ARRAY_MAKE_IMM, localIndex, envPtr); + } else { + TclEmitOpcode( INST_DUP, envPtr); + TclEmitOpcode( INST_ARRAY_EXISTS_STK, envPtr); + TclEmitInstInt1(INST_JUMP_TRUE1, 5, envPtr); + savedStackDepth = envPtr->currStackDepth; + TclEmitOpcode( INST_ARRAY_MAKE_STK, envPtr); + TclEmitInstInt1(INST_JUMP1, 3, envPtr); + envPtr->currStackDepth = savedStackDepth; + TclEmitOpcode( INST_POP, envPtr); + } + PushLiteral(envPtr, "", 0); + return TCL_OK; + } + + /* + * Prepare for the internal foreach. + */ + + if (envPtr->procPtr == NULL) { + return TCL_ERROR; + } + dataVar = TclFindCompiledLocal(NULL, 0, 1, envPtr); + iterVar = TclFindCompiledLocal(NULL, 0, 1, envPtr); + keyVar = TclFindCompiledLocal(NULL, 0, 1, envPtr); + valVar = TclFindCompiledLocal(NULL, 0, 1, envPtr); + + infoPtr = ckalloc(sizeof(ForeachInfo) + sizeof(ForeachVarList *)); + infoPtr->numLists = 1; + infoPtr->firstValueTemp = dataVar; + infoPtr->loopCtTemp = iterVar; + infoPtr->varLists[0] = ckalloc(sizeof(ForeachVarList) * 2*sizeof(int)); + infoPtr->varLists[0]->numVars = 2; + infoPtr->varLists[0]->varIndexes[0] = keyVar; + infoPtr->varLists[0]->varIndexes[1] = valVar; + infoIndex = TclCreateAuxData(infoPtr, &tclForeachInfoType, envPtr); + + /* + * Start issuing instructions to write to the array. + */ + + CompileWord(envPtr, tokenPtr, interp, 2); + TclEmitOpcode( INST_DUP, envPtr); + TclEmitOpcode( INST_LIST_LENGTH, envPtr); + PushLiteral(envPtr, "1", 1); + TclEmitOpcode( INST_BITAND, envPtr); + offsetFwd = CurrentOffset(envPtr); + TclEmitInstInt1( INST_JUMP_FALSE1, 0, envPtr); + savedStackDepth = envPtr->currStackDepth; + PushLiteral(envPtr, "list must have an even number of elements", + strlen("list must have an even number of elements")); + PushLiteral(envPtr, "-errorCode {TCL ARGUMENT FORMAT}", + strlen("-errorCode {TCL ARGUMENT FORMAT}")); + TclEmitInstInt4( INST_RETURN_IMM, 1, envPtr); + TclEmitInt4( 0, envPtr); + envPtr->currStackDepth = savedStackDepth; + fwd = CurrentOffset(envPtr) - offsetFwd; + TclStoreInt1AtPtr(fwd, envPtr->codeStart+offsetFwd+1); + Emit14Inst( INST_STORE_SCALAR, dataVar, envPtr); + TclEmitOpcode( INST_POP, envPtr); + + if (localIndex >= 0) { + TclEmitInstInt4(INST_ARRAY_EXISTS_IMM, localIndex, envPtr); + TclEmitInstInt1(INST_JUMP_TRUE1, 7, envPtr); + TclEmitInstInt4(INST_ARRAY_MAKE_IMM, localIndex, envPtr); + TclEmitInstInt4(INST_FOREACH_START4, infoIndex, envPtr); + offsetBack = CurrentOffset(envPtr); + TclEmitInstInt4(INST_FOREACH_STEP4, infoIndex, envPtr); + offsetFwd = CurrentOffset(envPtr); + TclEmitInstInt1(INST_JUMP_FALSE1, 0, envPtr); + savedStackDepth = envPtr->currStackDepth; + Emit14Inst( INST_LOAD_SCALAR, keyVar, envPtr); + Emit14Inst( INST_LOAD_SCALAR, valVar, envPtr); + Emit14Inst( INST_STORE_ARRAY, localIndex, envPtr); + TclEmitOpcode( INST_POP, envPtr); + back = offsetBack - CurrentOffset(envPtr); + TclEmitInstInt1(INST_JUMP1, back, envPtr); + fwd = CurrentOffset(envPtr) - offsetFwd; + TclStoreInt1AtPtr(fwd, envPtr->codeStart+offsetFwd+1); + envPtr->currStackDepth = savedStackDepth; + } else { + TclEmitOpcode( INST_DUP, envPtr); + TclEmitOpcode( INST_ARRAY_EXISTS_STK, envPtr); + TclEmitInstInt1(INST_JUMP_TRUE1, 4, envPtr); + TclEmitOpcode( INST_DUP, envPtr); + TclEmitOpcode( INST_ARRAY_MAKE_STK, envPtr); + TclEmitInstInt4(INST_FOREACH_START4, infoIndex, envPtr); + offsetBack = CurrentOffset(envPtr); + TclEmitInstInt4(INST_FOREACH_STEP4, infoIndex, envPtr); + offsetFwd = CurrentOffset(envPtr); + TclEmitInstInt1(INST_JUMP_FALSE1, 0, envPtr); + savedStackDepth = envPtr->currStackDepth; + TclEmitOpcode( INST_DUP, envPtr); + Emit14Inst( INST_LOAD_SCALAR, keyVar, envPtr); + Emit14Inst( INST_LOAD_SCALAR, valVar, envPtr); + TclEmitOpcode( INST_STORE_ARRAY_STK, envPtr); + TclEmitOpcode( INST_POP, envPtr); + back = offsetBack - CurrentOffset(envPtr); + TclEmitInstInt1(INST_JUMP1, back, envPtr); + fwd = CurrentOffset(envPtr) - offsetFwd; + TclStoreInt1AtPtr(fwd, envPtr->codeStart+offsetFwd+1); + envPtr->currStackDepth = savedStackDepth; + TclEmitOpcode( INST_POP, envPtr); + } + TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr); + TclEmitInt4( dataVar, envPtr); + PushLiteral(envPtr, "", 0); + return TCL_OK; +} + +int +TclCompileArrayUnsetCmd( + Tcl_Interp *interp, /* Used for looking up stuff. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + DefineLineInformation; /* TIP #280 */ + Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr); + int simpleVarName, isScalar, localIndex, savedStackDepth; + + if (parsePtr->numWords != 2) { + return TCL_ERROR; + } + + PushVarNameWord(interp, tokenPtr, envPtr, 0, + &localIndex, &simpleVarName, &isScalar, 1); + if (!isScalar) { + return TCL_ERROR; + } + + if (localIndex >= 0) { + TclEmitInstInt4(INST_ARRAY_EXISTS_IMM, localIndex, envPtr); + TclEmitInstInt1(INST_JUMP_FALSE1, 8, envPtr); + TclEmitInstInt1(INST_UNSET_SCALAR, 1, envPtr); + TclEmitInt4( localIndex, envPtr); + } else { + TclEmitOpcode( INST_DUP, envPtr); + TclEmitOpcode( INST_ARRAY_EXISTS_STK, envPtr); + TclEmitInstInt1(INST_JUMP_FALSE1, 6, envPtr); + savedStackDepth = envPtr->currStackDepth; + TclEmitInstInt1(INST_UNSET_STK, 1, envPtr); + TclEmitInstInt1(INST_JUMP1, 3, envPtr); + envPtr->currStackDepth = savedStackDepth; + TclEmitOpcode( INST_POP, envPtr); + } + PushLiteral(envPtr, "", 0); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * * TclCompileBreakCmd -- * * Procedure called to compile the "break" command. @@ -251,6 +498,7 @@ TclCompileBreakCmd( */ TclEmitOpcode(INST_BREAK, envPtr); + PushLiteral(envPtr, "", 0); /* Evil hack! */ return TCL_OK; } @@ -557,6 +805,7 @@ TclCompileContinueCmd( */ TclEmitOpcode(INST_CONTINUE, envPtr); + PushLiteral(envPtr, "", 0); /* Evil hack! */ return TCL_OK; } @@ -575,25 +824,6 @@ TclCompileContinueCmd( * Instructions are added to envPtr to execute the "dict" subcommand at * runtime. * - * Notes: - * The following commands are in fairly common use and are possibly worth - * bytecoding: - * dict append - * dict create [*] - * dict exists [*] - * dict for - * dict get [*] - * dict incr - * dict keys [*] - * dict lappend - * dict set - * dict unset - * - * In practice, those that are pure-value operators (marked with [*]) can - * probably be left alone (except perhaps [dict get] which is very very - * common) and [dict update] should be considered instead (really big - * win!) - * *---------------------------------------------------------------------- */ @@ -658,6 +888,7 @@ TclCompileDictSetCmd( TclEmitInstInt4( INST_DICT_SET, numWords-2, envPtr); TclEmitInt4( dictVarIndex, envPtr); + TclAdjustStackDepth(-1, envPtr); return TCL_OK; } @@ -775,6 +1006,310 @@ TclCompileDictGetCmd( tokenPtr = TokenAfter(tokenPtr); } TclEmitInstInt4(INST_DICT_GET, numWords-1, envPtr); + TclAdjustStackDepth(-1, envPtr); + return TCL_OK; +} + +int +TclCompileDictExistsCmd( + Tcl_Interp *interp, /* Used for looking up stuff. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + Tcl_Token *tokenPtr; + int numWords, i; + DefineLineInformation; /* TIP #280 */ + + /* + * There must be at least two arguments after the command (the single-arg + * case is legal, but too special and magic for us to deal with here). + */ + + if (parsePtr->numWords < 3) { + return TCL_ERROR; + } + tokenPtr = TokenAfter(parsePtr->tokenPtr); + numWords = parsePtr->numWords-1; + + /* + * Now we do the code generation. + */ + + for (i=0 ; i<numWords ; i++) { + CompileWord(envPtr, tokenPtr, interp, i); + tokenPtr = TokenAfter(tokenPtr); + } + TclEmitInstInt4(INST_DICT_EXISTS, numWords-1, envPtr); + TclAdjustStackDepth(-1, envPtr); + return TCL_OK; +} + +int +TclCompileDictUnsetCmd( + Tcl_Interp *interp, /* Used for looking up stuff. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + Tcl_Token *tokenPtr; + DefineLineInformation; /* TIP #280 */ + int i, dictVarIndex, nameChars; + const char *name; + + /* + * There must be at least one argument after the variable name for us to + * compile to bytecode. + */ + + if (parsePtr->numWords < 3) { + return TCL_ERROR; + } + + /* + * The dictionary variable must be a local scalar that is knowable at + * compile time; anything else exceeds the complexity of the opcode. So + * discover what the index is. + */ + + tokenPtr = TokenAfter(parsePtr->tokenPtr); + if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { + return TCL_ERROR; + } + name = tokenPtr[1].start; + nameChars = tokenPtr[1].size; + if (!TclIsLocalScalar(name, nameChars)) { + return TCL_ERROR; + } + dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, envPtr); + if (dictVarIndex < 0) { + return TCL_ERROR; + } + + /* + * Remaining words (the key path) can be handled normally. + */ + + for (i=2 ; i<parsePtr->numWords ; i++) { + tokenPtr = TokenAfter(tokenPtr); + CompileWord(envPtr, tokenPtr, interp, i); + } + + /* + * Now emit the instruction to do the dict manipulation. + */ + + TclEmitInstInt4( INST_DICT_UNSET, parsePtr->numWords-2, envPtr); + TclEmitInt4( dictVarIndex, envPtr); + return TCL_OK; +} + +int +TclCompileDictCreateCmd( + Tcl_Interp *interp, /* Used for looking up stuff. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + DefineLineInformation; /* TIP #280 */ + int worker; /* Temp var for building the value in. */ + Tcl_Token *tokenPtr; + Tcl_Obj *keyObj, *valueObj, *dictObj; + const char *bytes; + int i, len; + + if ((parsePtr->numWords & 1) == 0) { + return TCL_ERROR; + } + + /* + * See if we can build the value at compile time... + */ + + tokenPtr = TokenAfter(parsePtr->tokenPtr); + dictObj = Tcl_NewObj(); + Tcl_IncrRefCount(dictObj); + for (i=1 ; i<parsePtr->numWords ; i+=2) { + keyObj = Tcl_NewObj(); + Tcl_IncrRefCount(keyObj); + if (!TclWordKnownAtCompileTime(tokenPtr, keyObj)) { + Tcl_DecrRefCount(keyObj); + Tcl_DecrRefCount(dictObj); + goto nonConstant; + } + tokenPtr = TokenAfter(tokenPtr); + valueObj = Tcl_NewObj(); + Tcl_IncrRefCount(valueObj); + if (!TclWordKnownAtCompileTime(tokenPtr, valueObj)) { + Tcl_DecrRefCount(keyObj); + Tcl_DecrRefCount(valueObj); + Tcl_DecrRefCount(dictObj); + goto nonConstant; + } + tokenPtr = TokenAfter(tokenPtr); + Tcl_DictObjPut(NULL, dictObj, keyObj, valueObj); + Tcl_DecrRefCount(keyObj); + Tcl_DecrRefCount(valueObj); + } + + /* + * We did! Excellent. The "verifyDict" is to do type forcing. + */ + + bytes = Tcl_GetStringFromObj(dictObj, &len); + PushLiteral(envPtr, bytes, len); + TclEmitOpcode( INST_DUP, envPtr); + TclEmitOpcode( INST_DICT_VERIFY, envPtr); + Tcl_DecrRefCount(dictObj); + return TCL_OK; + + /* + * Otherwise, we've got to issue runtime code to do the building, which we + * do by [dict set]ting into an unnamed local variable. This requires that + * we are in a context with an LVT. + */ + + nonConstant: + worker = TclFindCompiledLocal(NULL, 0, 1, envPtr); + if (worker < 0) { + return TCL_ERROR; + } + + PushLiteral(envPtr, "", 0); + Emit14Inst( INST_STORE_SCALAR, worker, envPtr); + TclEmitOpcode( INST_POP, envPtr); + tokenPtr = TokenAfter(parsePtr->tokenPtr); + for (i=1 ; i<parsePtr->numWords ; i+=2) { + CompileWord(envPtr, tokenPtr, interp, i); + tokenPtr = TokenAfter(tokenPtr); + CompileWord(envPtr, tokenPtr, interp, i+1); + tokenPtr = TokenAfter(tokenPtr); + TclEmitInstInt4( INST_DICT_SET, 1, envPtr); + TclEmitInt4( worker, envPtr); + TclAdjustStackDepth(-1, envPtr); + TclEmitOpcode( INST_POP, envPtr); + } + Emit14Inst( INST_LOAD_SCALAR, worker, envPtr); + TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr); + TclEmitInt4( worker, envPtr); + return TCL_OK; +} + +int +TclCompileDictMergeCmd( + Tcl_Interp *interp, /* Used for looking up stuff. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + DefineLineInformation; /* TIP #280 */ + Tcl_Token *tokenPtr; + int i, workerIndex, infoIndex, outLoop; + + /* + * Deal with some special edge cases. Note that in the case with one + * argument, the only thing to do is to verify the dict-ness. + */ + + if (parsePtr->numWords < 2) { + PushLiteral(envPtr, "", 0); + return TCL_OK; + } else if (parsePtr->numWords == 2) { + tokenPtr = TokenAfter(parsePtr->tokenPtr); + CompileWord(envPtr, tokenPtr, interp, 1); + TclEmitOpcode( INST_DUP, envPtr); + TclEmitOpcode( INST_DICT_VERIFY, envPtr); + return TCL_OK; + } + + /* + * There's real merging work to do. + * + * Allocate some working space. This means we'll only ever compile this + * command when there's an LVT present. + */ + + workerIndex = TclFindCompiledLocal(NULL, 0, 1, envPtr); + if (workerIndex < 0) { + return TCL_ERROR; + } + infoIndex = TclFindCompiledLocal(NULL, 0, 1, envPtr); + + /* + * Get the first dictionary and verify that it is so. + */ + + tokenPtr = TokenAfter(parsePtr->tokenPtr); + CompileWord(envPtr, tokenPtr, interp, 1); + TclEmitOpcode( INST_DUP, envPtr); + TclEmitOpcode( INST_DICT_VERIFY, envPtr); + Emit14Inst( INST_STORE_SCALAR, workerIndex, envPtr); + TclEmitOpcode( INST_POP, envPtr); + + /* + * For each of the remaining dictionaries... + */ + + outLoop = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE); + TclEmitInstInt4( INST_BEGIN_CATCH4, outLoop, envPtr); + ExceptionRangeStarts(envPtr, outLoop); + for (i=2 ; i<parsePtr->numWords ; i++) { + /* + * Get the dictionary, and merge its pairs into the first dict (using + * a small loop). + */ + + tokenPtr = TokenAfter(tokenPtr); + CompileWord(envPtr, tokenPtr, interp, i); + TclEmitInstInt4( INST_DICT_FIRST, infoIndex, envPtr); + TclEmitInstInt1( INST_JUMP_TRUE1, 24, envPtr); + TclEmitInstInt4( INST_REVERSE, 2, envPtr); + TclEmitInstInt4( INST_DICT_SET, 1, envPtr); + TclEmitInt4( workerIndex, envPtr); + TclAdjustStackDepth(-1, envPtr); + TclEmitOpcode( INST_POP, envPtr); + TclEmitInstInt4( INST_DICT_NEXT, infoIndex, envPtr); + TclEmitInstInt1( INST_JUMP_FALSE1, -20, envPtr); + TclEmitOpcode( INST_POP, envPtr); + TclEmitOpcode( INST_POP, envPtr); + TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr); + TclEmitInt4( infoIndex, envPtr); + } + ExceptionRangeEnds(envPtr, outLoop); + TclEmitOpcode( INST_END_CATCH, envPtr); + + /* + * Clean up any state left over. + */ + + Emit14Inst( INST_LOAD_SCALAR, workerIndex, envPtr); + TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr); + TclEmitInt4( workerIndex, envPtr); + TclEmitInstInt1( INST_JUMP1, 18, envPtr); + + /* + * If an exception happens when starting to iterate over the second (and + * subsequent) dicts. This is strictly not necessary, but it is nice. + */ + + ExceptionRangeTarget(envPtr, outLoop, catchOffset); + TclEmitOpcode( INST_PUSH_RETURN_OPTIONS, envPtr); + TclEmitOpcode( INST_PUSH_RESULT, envPtr); + TclEmitOpcode( INST_END_CATCH, envPtr); + TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr); + TclEmitInt4( workerIndex, envPtr); + TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr); + TclEmitInt4( infoIndex, envPtr); + TclEmitOpcode( INST_RETURN_STK, envPtr); + return TCL_OK; } @@ -787,11 +1322,42 @@ TclCompileDictForCmd( * compiled. */ CompileEnv *envPtr) /* Holds resulting instructions. */ { + return CompileDictEachCmd(interp, parsePtr, cmdPtr, envPtr, + TCL_EACH_KEEP_NONE); +} + +int +TclCompileDictMapCmd( + Tcl_Interp *interp, /* Used for looking up stuff. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + return CompileDictEachCmd(interp, parsePtr, cmdPtr, envPtr, + TCL_EACH_COLLECT); +} + +int +CompileDictEachCmd( + Tcl_Interp *interp, /* Used for looking up stuff. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr, /* Holds resulting instructions. */ + int collect) /* Flag == TCL_EACH_COLLECT to collect and + * construct a new dictionary with the loop + * body result. */ +{ DefineLineInformation; /* TIP #280 */ Tcl_Token *varsTokenPtr, *dictTokenPtr, *bodyTokenPtr; int keyVarIndex, valueVarIndex, nameChars, loopRange, catchRange; int infoIndex, jumpDisplacement, bodyTargetOffset, emptyTargetOffset; int numVars, endTargetOffset; + int collectVar = -1; /* Index of temp var holding the result + * dict. */ int savedStackDepth = envPtr->currStackDepth; /* Needed because jumps confuse the stack * space calculator. */ @@ -815,6 +1381,19 @@ TclCompileDictForCmd( } /* + * Create temporary variable to capture return values from loop body when + * we're collecting results. + */ + + if (collect == TCL_EACH_COLLECT) { + collectVar = TclFindCompiledLocal(NULL, /*nameChars*/ 0, /*create*/ 1, + envPtr); + if (collectVar < 0) { + return TCL_ERROR; + } + } + + /* * Check we've got a pair of variables and that they are local variables. * Then extract their indices in the LVT. */ @@ -867,8 +1446,18 @@ TclCompileDictForCmd( * Preparation complete; issue instructions. Note that this code issues * fixed-sized jumps. That simplifies things a lot! * - * First up, get the dictionary and start the iteration. No catching of - * errors at this point. + * First up, initialize the accumulator dictionary if needed. + */ + + if (collect == TCL_EACH_COLLECT) { + PushLiteral(envPtr, "", 0); + Emit14Inst( INST_STORE_SCALAR, collectVar, envPtr); + TclEmitOpcode( INST_POP, envPtr); + } + + /* + * Get the dictionary and start the iteration. No catching of errors at + * this point. */ CompileWord(envPtr, dictTokenPtr, interp, 3); @@ -908,6 +1497,14 @@ TclCompileDictForCmd( SetLineInformation(3); CompileBody(envPtr, bodyTokenPtr, interp); + if (collect == TCL_EACH_COLLECT) { + Emit14Inst( INST_LOAD_SCALAR, keyVarIndex, envPtr); + TclEmitInstInt4(INST_OVER, 1, envPtr); + TclEmitInstInt4(INST_DICT_SET, 1, envPtr); + TclEmitInt4( collectVar, envPtr); + TclAdjustStackDepth(-1, envPtr); + TclEmitOpcode( INST_POP, envPtr); + } TclEmitOpcode( INST_POP, envPtr); /* @@ -940,7 +1537,7 @@ TclCompileDictForCmd( ExceptionRangeTarget(envPtr, loopRange, breakOffset); TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr); - TclEmitInt4( infoIndex, envPtr); + TclEmitInt4( infoIndex, envPtr); TclEmitOpcode( INST_END_CATCH, envPtr); endTargetOffset = CurrentOffset(envPtr); TclEmitInstInt4( INST_JUMP4, 0, envPtr); @@ -954,8 +1551,12 @@ TclCompileDictForCmd( TclEmitOpcode( INST_PUSH_RETURN_OPTIONS, envPtr); TclEmitOpcode( INST_PUSH_RESULT, envPtr); TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr); - TclEmitInt4( infoIndex, envPtr); + TclEmitInt4( infoIndex, envPtr); TclEmitOpcode( INST_END_CATCH, envPtr); + if (collect == TCL_EACH_COLLECT) { + TclEmitInstInt1(INST_UNSET_SCALAR, 0, envPtr); + TclEmitInt4( collectVar, envPtr); + } TclEmitOpcode( INST_RETURN_STK, envPtr); /* @@ -964,25 +1565,31 @@ TclCompileDictForCmd( * easy!) Note that we skip the END_CATCH. [Bug 1382528] */ - envPtr->currStackDepth = savedStackDepth+2; + envPtr->currStackDepth = savedStackDepth + 2; jumpDisplacement = CurrentOffset(envPtr) - emptyTargetOffset; TclUpdateInstInt4AtPc(INST_JUMP_TRUE4, jumpDisplacement, envPtr->codeStart + emptyTargetOffset); TclEmitOpcode( INST_POP, envPtr); TclEmitOpcode( INST_POP, envPtr); TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr); - TclEmitInt4( infoIndex, envPtr); + TclEmitInt4( infoIndex, envPtr); /* * Final stage of the command (normal case) is that we push an empty - * object. This is done last to promote peephole optimization when it's - * dropped immediately. + * object (or push the accumulator as the result object). This is done + * last to promote peephole optimization when it's dropped immediately. */ jumpDisplacement = CurrentOffset(envPtr) - endTargetOffset; TclUpdateInstInt4AtPc(INST_JUMP4, jumpDisplacement, envPtr->codeStart + endTargetOffset); - PushLiteral(envPtr, "", 0); + if (collect == TCL_EACH_COLLECT) { + Emit14Inst( INST_LOAD_SCALAR, collectVar, envPtr); + TclEmitInstInt1(INST_UNSET_SCALAR, 0, envPtr); + TclEmitInt4( collectVar, envPtr); + } else { + PushLiteral(envPtr, "", 0); + } return TCL_OK; } @@ -1154,6 +1761,7 @@ TclCompileDictUpdateCmd( (int) (CurrentOffset(envPtr) - jumpFixup.codeOffset)); } TclStackFree(interp, keyTokenPtrs); + envPtr->currStackDepth = savedStackDepth + 1; return TCL_OK; } @@ -1402,6 +2010,7 @@ TclCompileDictWithCmd( PushLiteral(envPtr, "", 0); } } + envPtr->currStackDepth = savedStackDepth + 1; return TCL_OK; } @@ -1520,6 +2129,7 @@ TclCompileDictWithCmd( * Prepare for the start of the next command. */ + envPtr->currStackDepth = savedStackDepth + 1; if (TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127)) { Tcl_Panic("TclCompileDictCmd(update): bad jump distance %d", (int) (CurrentOffset(envPtr) - jumpFixup.codeOffset)); @@ -1619,6 +2229,7 @@ TclCompileErrorCmd( * However, we only deal with the case where there is just a message. */ Tcl_Token *messageTokenPtr; + int savedStackDepth = envPtr->currStackDepth; DefineLineInformation; /* TIP #280 */ if (parsePtr->numWords != 2) { @@ -1629,6 +2240,7 @@ TclCompileErrorCmd( PushLiteral(envPtr, "-code error -level 0", 20); CompileWord(envPtr, messageTokenPtr, interp, 1); TclEmitOpcode(INST_RETURN_STK, envPtr); + envPtr->currStackDepth = savedStackDepth + 1; return TCL_OK; } @@ -1870,6 +2482,39 @@ TclCompileForeachCmd( * compiled. */ CompileEnv *envPtr) /* Holds resulting instructions. */ { + return CompileEachloopCmd(interp, parsePtr, cmdPtr, envPtr, + TCL_EACH_KEEP_NONE); +} + +/* + *---------------------------------------------------------------------- + * + * CompileEachloopCmd -- + * + * Procedure called to compile the "foreach" and "lmap" commands. + * + * Results: + * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer + * evaluation to runtime. + * + * Side effects: + * Instructions are added to envPtr to execute the "foreach" command at + * runtime. + * + *---------------------------------------------------------------------- + */ + +static int +CompileEachloopCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr, /* Holds resulting instructions. */ + int collect) /* Select collecting or accumulating mode + * (TCL_EACH_*) */ +{ Proc *procPtr = envPtr->procPtr; ForeachInfo *infoPtr; /* Points to the structure describing this * foreach command. Stored in a AuxData @@ -1878,6 +2523,9 @@ TclCompileForeachCmd( * used to point to a value list. */ int loopCtTemp; /* Index of temp var holding the loop's * iteration count. */ + int collectVar = -1; /* Index of temp var holding the result var + * index. */ + Tcl_Token *tokenPtr, *bodyTokenPtr; unsigned char *jumpPc; JumpFixup jumpFalseFixup; @@ -1993,6 +2641,14 @@ TclCompileForeachCmd( loopIndex++; } + if (collect == TCL_EACH_COLLECT) { + collectVar = TclFindCompiledLocal(NULL, /*nameChars*/ 0, /*create*/ 1, + envPtr); + if (collectVar < 0) { + return TCL_ERROR; + } + } + /* * We will compile the foreach command. Reserve (numLists + 1) temporary * variables: @@ -2069,6 +2725,16 @@ TclCompileForeachCmd( } /* + * Create temporary variable to capture return values from loop body. + */ + + if (collect == TCL_EACH_COLLECT) { + PushLiteral(envPtr, "", 0); + Emit14Inst( INST_STORE_SCALAR, collectVar, envPtr); + TclEmitOpcode( INST_POP, envPtr); + } + + /* * Initialize the temporary var that holds the count of loop iterations. */ @@ -2092,6 +2758,10 @@ TclCompileForeachCmd( CompileBody(envPtr, bodyTokenPtr, interp); ExceptionRangeEnds(envPtr, range); envPtr->currStackDepth = savedStackDepth + 1; + + if (collect == TCL_EACH_COLLECT) { + Emit14Inst( INST_LAPPEND_SCALAR, collectVar,envPtr); + } TclEmitOpcode( INST_POP, envPtr); /* @@ -2142,11 +2812,18 @@ TclCompileForeachCmd( ExceptionRangeTarget(envPtr, range, breakOffset); /* - * The foreach command's result is an empty string. + * The command's result is an empty string if not collecting, or the + * list of results from evaluating the loop body. */ envPtr->currStackDepth = savedStackDepth; - PushLiteral(envPtr, "", 0); + if (collect == TCL_EACH_COLLECT) { + Emit14Inst( INST_LOAD_SCALAR, collectVar, envPtr); + TclEmitInstInt1(INST_UNSET_SCALAR, 0, envPtr); + TclEmitInt4( collectVar, envPtr); + } else { + PushLiteral(envPtr, "", 0); + } envPtr->currStackDepth = savedStackDepth + 1; done: @@ -2307,6 +2984,226 @@ PrintForeachInfo( /* *---------------------------------------------------------------------- * + * TclCompileFormatCmd -- + * + * Procedure called to compile the "format" command. Handles cases that + * can be done as constants or simple string concatenation only. + * + * Results: + * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer + * evaluation to runtime. + * + * Side effects: + * Instructions are added to envPtr to execute the "format" command at + * runtime. + * + *---------------------------------------------------------------------- + */ + +int +TclCompileFormatCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + DefineLineInformation; /* TIP #280 */ + Tcl_Token *tokenPtr = parsePtr->tokenPtr; + Tcl_Obj **objv, *formatObj, *tmpObj; + char *bytes, *start; + int i, j, len; + + /* + * Don't handle any guaranteed-error cases. + */ + + if (parsePtr->numWords < 2) { + return TCL_ERROR; + } + + /* + * Check if the argument words are all compile-time-known literals; that's + * a case we can handle by compiling to a constant. + */ + + formatObj = Tcl_NewObj(); + Tcl_IncrRefCount(formatObj); + tokenPtr = TokenAfter(tokenPtr); + if (!TclWordKnownAtCompileTime(tokenPtr, formatObj)) { + Tcl_DecrRefCount(formatObj); + return TCL_ERROR; + } + + objv = ckalloc((parsePtr->numWords-2) * sizeof(Tcl_Obj *)); + for (i=0 ; i+2 < parsePtr->numWords ; i++) { + tokenPtr = TokenAfter(tokenPtr); + objv[i] = Tcl_NewObj(); + Tcl_IncrRefCount(objv[i]); + if (!TclWordKnownAtCompileTime(tokenPtr, objv[i])) { + goto checkForStringConcatCase; + } + } + + /* + * Everything is a literal, so the result is constant too (or an error if + * the format is broken). Do the format now. + */ + + tmpObj = Tcl_Format(interp, Tcl_GetString(formatObj), + parsePtr->numWords-2, objv); + for (; --i>=0 ;) { + Tcl_DecrRefCount(objv[i]); + } + ckfree(objv); + Tcl_DecrRefCount(formatObj); + if (tmpObj == NULL) { + return TCL_ERROR; + } + + /* + * Not an error, always a constant result, so just push the result as a + * literal. Job done. + */ + + bytes = Tcl_GetStringFromObj(tmpObj, &len); + PushLiteral(envPtr, bytes, len); + Tcl_DecrRefCount(tmpObj); + return TCL_OK; + + checkForStringConcatCase: + /* + * See if we can generate a sequence of things to concatenate. This + * requires that all the % sequences be %s or %%, as everything else is + * sufficiently complex that we don't bother. + * + * First, get the state of the system relatively sensible (cleaning up + * after our attempt to spot a literal). + */ + + for (; --i>=0 ;) { + Tcl_DecrRefCount(objv[i]); + } + ckfree(objv); + tokenPtr = TokenAfter(parsePtr->tokenPtr); + tokenPtr = TokenAfter(tokenPtr); + i = 0; + + /* + * Now scan through and check for non-%s and non-%% substitutions. + */ + + for (bytes = Tcl_GetString(formatObj) ; *bytes ; bytes++) { + if (*bytes == '%') { + bytes++; + if (*bytes == 's') { + i++; + continue; + } else if (*bytes == '%') { + continue; + } + Tcl_DecrRefCount(formatObj); + return TCL_ERROR; + } + } + + /* + * Check if the number of things to concatenate will fit in a byte. + */ + + if (i+2 != parsePtr->numWords || i > 125) { + Tcl_DecrRefCount(formatObj); + return TCL_ERROR; + } + + /* + * Generate the pushes of the things to concatenate, a sequence of + * literals and compiled tokens (of which at least one is non-literal or + * we'd have the case in the first half of this function) which we will + * concatenate. + */ + + i = 0; /* The count of things to concat. */ + j = 2; /* The index into the argument tokens, for + * TIP#280 handling. */ + start = Tcl_GetString(formatObj); + /* The start of the currently-scanned literal + * in the format string. */ + tmpObj = Tcl_NewObj(); /* The buffer used to accumulate the literal + * being built. */ + for (bytes = start ; *bytes ; bytes++) { + if (*bytes == '%') { + Tcl_AppendToObj(tmpObj, start, bytes - start); + if (*++bytes == '%') { + Tcl_AppendToObj(tmpObj, "%", 1); + } else { + char *b = Tcl_GetStringFromObj(tmpObj, &len); + + /* + * If there is a non-empty literal from the format string, + * push it and reset. + */ + + if (len > 0) { + PushLiteral(envPtr, b, len); + Tcl_DecrRefCount(tmpObj); + tmpObj = Tcl_NewObj(); + i++; + } + + /* + * Push the code to produce the string that would be + * substituted with %s, except we'll be concatenating + * directly. + */ + + CompileWord(envPtr, tokenPtr, interp, j); + tokenPtr = TokenAfter(tokenPtr); + j++; + i++; + } + start = bytes + 1; + } + } + + /* + * Handle the case of a trailing literal. + */ + + Tcl_AppendToObj(tmpObj, start, bytes - start); + bytes = Tcl_GetStringFromObj(tmpObj, &len); + if (len > 0) { + PushLiteral(envPtr, bytes, len); + i++; + } + Tcl_DecrRefCount(tmpObj); + Tcl_DecrRefCount(formatObj); + + if (i > 1) { + /* + * Do the concatenation, which produces the result. + */ + + TclEmitInstInt1(INST_CONCAT1, i, envPtr); + } else { + /* + * EVIL HACK! Force there to be a string representation in the case + * where there's just a "%s" in the format; case covered by the test + * format-20.1 (and it is horrible...) + */ + + TclEmitOpcode(INST_DUP, envPtr); + PushLiteral(envPtr, "", 0); + TclEmitOpcode(INST_STR_EQ, envPtr); + TclEmitOpcode(INST_POP, envPtr); + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * * TclCompileGlobalCmd -- * * Procedure called to compile the "global" command. @@ -2817,22 +3714,105 @@ TclCompileIncrCmd( /* *---------------------------------------------------------------------- * - * TclCompileInfoExistsCmd -- + * TclCompileInfo*Cmd -- * - * Procedure called to compile the "info exists" subcommand. + * Procedures called to compile "info" subcommands. * * Results: * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer * evaluation to runtime. * * Side effects: - * Instructions are added to envPtr to execute the "info exists" - * subcommand at runtime. + * Instructions are added to envPtr to execute the "info" subcommand at + * runtime. * *---------------------------------------------------------------------- */ int +TclCompileInfoCommandsCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) +{ + DefineLineInformation; /* TIP #280 */ + Tcl_Token *tokenPtr; + Tcl_Obj *objPtr; + char *bytes; + + /* + * We require one compile-time known argument for the case we can compile. + */ + + if (parsePtr->numWords != 2) { + return TCL_ERROR; + } + tokenPtr = TokenAfter(parsePtr->tokenPtr); + objPtr = Tcl_NewObj(); + Tcl_IncrRefCount(objPtr); + if (!TclWordKnownAtCompileTime(tokenPtr, objPtr)) { + goto notCompilable; + } + bytes = Tcl_GetString(objPtr); + + /* + * We require that the argument start with "::" and not have any of "*\[?" + * in it. (Theoretically, we should look in only the final component, but + * the difference is so slight given current naming practices.) + */ + + if (bytes[0] != ':' || bytes[1] != ':' || !TclMatchIsTrivial(bytes)) { + goto notCompilable; + } + Tcl_DecrRefCount(objPtr); + + /* + * Confirmed as a literal that will not frighten the horses. Compile. Note + * that the result needs to be list-ified. + */ + + CompileWord(envPtr, tokenPtr, interp, 1); + TclEmitOpcode( INST_RESOLVE_COMMAND, envPtr); + TclEmitOpcode( INST_DUP, envPtr); + TclEmitOpcode( INST_STR_LEN, envPtr); + TclEmitInstInt1( INST_JUMP_FALSE1, 7, envPtr); + TclEmitInstInt4( INST_LIST, 1, envPtr); + return TCL_OK; + + notCompilable: + Tcl_DecrRefCount(objPtr); + return TCL_ERROR; +} + +int +TclCompileInfoCoroutineCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + /* + * Only compile [info coroutine] without arguments. + */ + + if (parsePtr->numWords != 1) { + return TCL_ERROR; + } + + /* + * Not much to do; we compile to a single instruction... + */ + + TclEmitOpcode( INST_COROUTINE_NAME, envPtr); + return TCL_OK; +} + +int TclCompileInfoExistsCmd( Tcl_Interp *interp, /* Used for error reporting. */ Tcl_Parse *parsePtr, /* Points to a parse structure for the command @@ -2883,6 +3863,118 @@ TclCompileInfoExistsCmd( return TCL_OK; } + +int +TclCompileInfoLevelCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + /* + * Only compile [info level] without arguments or with a single argument. + */ + + if (parsePtr->numWords == 1) { + /* + * Not much to do; we compile to a single instruction... + */ + + TclEmitOpcode( INST_INFO_LEVEL_NUM, envPtr); + } else if (parsePtr->numWords != 2) { + return TCL_ERROR; + } else { + DefineLineInformation; /* TIP #280 */ + + /* + * Compile the argument, then add the instruction to convert it into a + * list of arguments. + */ + + SetLineInformation(1); + CompileTokens(envPtr, TokenAfter(parsePtr->tokenPtr), interp); + TclEmitOpcode( INST_INFO_LEVEL_ARGS, envPtr); + } + return TCL_OK; +} + +int +TclCompileInfoObjectClassCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) +{ + DefineLineInformation; /* TIP #280 */ + Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr); + + if (parsePtr->numWords != 2) { + return TCL_ERROR; + } + CompileWord(envPtr, tokenPtr, interp, 1); + TclEmitOpcode( INST_TCLOO_CLASS, envPtr); + return TCL_OK; +} + +int +TclCompileInfoObjectIsACmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) +{ + DefineLineInformation; /* TIP #280 */ + Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr); + + /* + * We only handle [info object isa object <somevalue>]. The first three + * words are compressed to a single token by the ensemble compilation + * engine. + */ + + if (parsePtr->numWords != 3) { + return TCL_ERROR; + } + if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || tokenPtr[1].size < 1 + || strncmp(tokenPtr[1].start, "object", tokenPtr[1].size)) { + return TCL_ERROR; + } + tokenPtr = TokenAfter(tokenPtr); + + /* + * Issue the code. + */ + + CompileWord(envPtr, tokenPtr, interp, 2); + TclEmitOpcode( INST_TCLOO_IS_OBJECT, envPtr); + return TCL_OK; +} + +int +TclCompileInfoObjectNamespaceCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) +{ + DefineLineInformation; /* TIP #280 */ + Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr); + + if (parsePtr->numWords != 2) { + return TCL_ERROR; + } + CompileWord(envPtr, tokenPtr, interp, 1); + TclEmitOpcode( INST_TCLOO_NS, envPtr); + return TCL_OK; +} /* *---------------------------------------------------------------------- @@ -3700,11 +4792,42 @@ TclCompileLsetCmd( /* *---------------------------------------------------------------------- * - * TclCompileNamespaceCmd -- + * TclCompileLmapCmd -- + * + * Procedure called to compile the "lmap" command. + * + * Results: + * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer + * evaluation to runtime. + * + * Side effects: + * Instructions are added to envPtr to execute the "lmap" command at + * runtime. + * + *---------------------------------------------------------------------- + */ + +int +TclCompileLmapCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + return CompileEachloopCmd(interp, parsePtr, cmdPtr, envPtr, + TCL_EACH_COLLECT); +} + +/* + *---------------------------------------------------------------------- + * + * TclCompileNamespace*Cmd -- * - * Procedure called to compile the "namespace" command; currently, only - * the subcommand "namespace upvar" is compiled to bytecodes, and then - * only inside a procedure(-like) context. + * Procedures called to compile the "namespace" command; currently, only + * the subcommands "namespace current" and "namespace upvar" are compiled + * to bytecodes, and the latter only inside a procedure(-like) context. * * Results: * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer @@ -3718,6 +4841,154 @@ TclCompileLsetCmd( */ int +TclCompileNamespaceCurrentCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + /* + * Only compile [namespace current] without arguments. + */ + + if (parsePtr->numWords != 1) { + return TCL_ERROR; + } + + /* + * Not much to do; we compile to a single instruction... + */ + + TclEmitOpcode( INST_NS_CURRENT, envPtr); + return TCL_OK; +} + +int +TclCompileNamespaceCodeCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + Tcl_Token *tokenPtr; + DefineLineInformation; /* TIP #280 */ + + if (parsePtr->numWords != 2) { + return TCL_ERROR; + } + tokenPtr = TokenAfter(parsePtr->tokenPtr); + + /* + * The specification of [namespace code] is rather shocking, in that it is + * supposed to check if the argument is itself the result of [namespace + * code] and not apply itself in that case. Which is excessively cautious, + * but what the test suite checks for. + */ + + if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || (tokenPtr[1].size > 20 + && strncmp(tokenPtr[1].start, "::namespace inscope ", 20) == 0)) { + /* + * Technically, we could just pass a literal '::namespace inscope ' + * term through, but that's something which really shouldn't be + * occurring as something that the user writes so we'll just punt it. + */ + + return TCL_ERROR; + } + + /* + * Now we can compile using the same strategy as [namespace code]'s normal + * implementation does internally. Note that we can't bind the namespace + * name directly here, because TclOO plays complex games with namespaces; + * the value needs to be determined at runtime for safety. + */ + + PushLiteral(envPtr, "::namespace", 11); + PushLiteral(envPtr, "inscope", 7); + TclEmitOpcode( INST_NS_CURRENT, envPtr); + CompileWord(envPtr, tokenPtr, interp, 1); + TclEmitInstInt4( INST_LIST, 4, envPtr); + return TCL_OK; +} + +int +TclCompileNamespaceQualifiersCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr); + DefineLineInformation; /* TIP #280 */ + int off; + + if (parsePtr->numWords != 2) { + return TCL_ERROR; + } + + CompileWord(envPtr, tokenPtr, interp, 1); + PushLiteral(envPtr, "0", 1); + PushLiteral(envPtr, "::", 2); + TclEmitInstInt4( INST_OVER, 2, envPtr); + TclEmitOpcode( INST_STR_FIND_LAST, envPtr); + off = CurrentOffset(envPtr); + PushLiteral(envPtr, "1", 1); + TclEmitOpcode( INST_SUB, envPtr); + TclEmitInstInt4( INST_OVER, 2, envPtr); + TclEmitInstInt4( INST_OVER, 1, envPtr); + TclEmitOpcode( INST_STR_INDEX, envPtr); + PushLiteral(envPtr, ":", 1); + TclEmitOpcode( INST_STR_EQ, envPtr); + off = off - CurrentOffset(envPtr); + TclEmitInstInt1( INST_JUMP_TRUE1, off, envPtr); + TclEmitOpcode( INST_STR_RANGE, envPtr); + return TCL_OK; +} + +int +TclCompileNamespaceTailCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr); + DefineLineInformation; /* TIP #280 */ + JumpFixup jumpFixup; + + if (parsePtr->numWords != 2) { + return TCL_ERROR; + } + + /* + * Take care; only add 2 to found index if the string was actually found. + */ + + CompileWord(envPtr, tokenPtr, interp, 1); + PushLiteral(envPtr, "::", 2); + TclEmitInstInt4( INST_OVER, 1, envPtr); + TclEmitOpcode( INST_STR_FIND_LAST, envPtr); + TclEmitOpcode( INST_DUP, envPtr); + PushLiteral(envPtr, "0", 1); + TclEmitOpcode( INST_GE, envPtr); + TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpFixup); + PushLiteral(envPtr, "2", 1); + TclEmitOpcode( INST_ADD, envPtr); + TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127); + PushLiteral(envPtr, "end", 3); + TclEmitOpcode( INST_STR_RANGE, envPtr); + return TCL_OK; +} + +int TclCompileNamespaceUpvarCmd( Tcl_Interp *interp, /* Used for error reporting. */ Tcl_Parse *parsePtr, /* Points to a parse structure for the command @@ -3779,6 +5050,52 @@ TclCompileNamespaceUpvarCmd( PushLiteral(envPtr, "", 0); return TCL_OK; } + +int +TclCompileNamespaceWhichCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + DefineLineInformation; /* TIP #280 */ + Tcl_Token *tokenPtr, *opt; + int idx; + + if (parsePtr->numWords < 2 || parsePtr->numWords > 3) { + return TCL_ERROR; + } + tokenPtr = TokenAfter(parsePtr->tokenPtr); + idx = 1; + + /* + * If there's an option, check that it's "-command". We don't handle + * "-variable" (currently) and anything else is an error. + */ + + if (parsePtr->numWords == 3) { + if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { + return TCL_ERROR; + } + opt = tokenPtr + 1; + if (opt->size < 2 || opt->size > 8 + || strncmp(opt->start, "-command", opt->size) != 0) { + return TCL_ERROR; + } + tokenPtr = TokenAfter(tokenPtr); + idx++; + } + + /* + * Issue the bytecode. + */ + + CompileWord(envPtr, tokenPtr, interp, idx); + TclEmitOpcode( INST_RESOLVE_COMMAND, envPtr); + return TCL_OK; +} /* *---------------------------------------------------------------------- @@ -3948,6 +5265,180 @@ TclCompileRegexpCmd( /* *---------------------------------------------------------------------- * + * TclCompileRegsubCmd -- + * + * Procedure called to compile the "regsub" command. + * + * Results: + * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer + * evaluation to runtime. + * + * Side effects: + * Instructions are added to envPtr to execute the "regsub" command at + * runtime. + * + *---------------------------------------------------------------------- + */ + +int +TclCompileRegsubCmd( + Tcl_Interp *interp, /* Tcl interpreter for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the + * command. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds the resulting instructions. */ +{ + /* + * We only compile the case with [regsub -all] where the pattern is both + * known at compile time and simple (i.e., no RE metacharacters). That is, + * the pattern must be translatable into a glob like "*foo*" with no other + * glob metacharacters inside it; there must be some "foo" in there too. + * The substitution string must also be known at compile time and free of + * metacharacters ("\digit" and "&"). Finally, there must not be a + * variable mentioned in the [regsub] to write the result back to (because + * we can't get the count of substitutions that would be the result in + * that case). The key is that these are the conditions under which a + * [string map] could be used instead, in particular a [string map] of the + * form we can compile to bytecode. + * + * In short, we look for: + * + * regsub -all [--] simpleRE string simpleReplacement + * + * The only optional part is the "--", and no other options are handled. + */ + + DefineLineInformation; /* TIP #280 */ + Tcl_Token *tokenPtr, *stringTokenPtr; + Tcl_Obj *patternObj = NULL, *replacementObj = NULL; + Tcl_DString pattern; + const char *bytes; + int len, exact, result = TCL_ERROR; + + if (parsePtr->numWords < 5 || parsePtr->numWords > 6) { + return TCL_ERROR; + } + + /* + * Parse the "-all", which must be the first argument (other options not + * supported, non-"-all" substitution we can't compile). + */ + + tokenPtr = TokenAfter(parsePtr->tokenPtr); + if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || tokenPtr[1].size != 4 + || strncmp(tokenPtr[1].start, "-all", 4)) { + return TCL_ERROR; + } + + /* + * Get the pattern into patternObj, checking for "--" in the process. + */ + + Tcl_DStringInit(&pattern); + tokenPtr = TokenAfter(tokenPtr); + patternObj = Tcl_NewObj(); + if (!TclWordKnownAtCompileTime(tokenPtr, patternObj)) { + goto done; + } + if (Tcl_GetString(patternObj)[0] == '-') { + if (strcmp(Tcl_GetString(patternObj), "--") != 0 + || parsePtr->numWords == 5) { + goto done; + } + tokenPtr = TokenAfter(tokenPtr); + Tcl_DecrRefCount(patternObj); + patternObj = Tcl_NewObj(); + if (!TclWordKnownAtCompileTime(tokenPtr, patternObj)) { + goto done; + } + } else if (parsePtr->numWords == 6) { + goto done; + } + + /* + * Identify the code which produces the string to apply the substitution + * to (stringTokenPtr), and the replacement string (into replacementObj). + */ + + stringTokenPtr = TokenAfter(tokenPtr); + tokenPtr = TokenAfter(stringTokenPtr); + replacementObj = Tcl_NewObj(); + if (!TclWordKnownAtCompileTime(tokenPtr, replacementObj)) { + goto done; + } + + /* + * Next, higher-level checks. Is the RE a very simple glob? Is the + * replacement "simple"? + */ + + bytes = Tcl_GetStringFromObj(patternObj, &len); + if (TclReToGlob(NULL, bytes, len, &pattern, &exact) != TCL_OK || exact) { + goto done; + } + bytes = Tcl_DStringValue(&pattern); + if (*bytes++ != '*') { + goto done; + } + while (1) { + switch (*bytes) { + case '*': + if (bytes[1] == '\0') { + /* + * OK, we've proved there are no metacharacters except for the + * '*' at each end. + */ + + len = Tcl_DStringLength(&pattern) - 2; + if (len > 0) { + goto isSimpleGlob; + } + + /* + * The pattern is "**"! I believe that should be impossible, + * but we definitely can't handle that at all. + */ + } + case '\0': case '?': case '[': case '\\': + goto done; + } + bytes++; + } + isSimpleGlob: + for (bytes = Tcl_GetString(replacementObj); *bytes; bytes++) { + switch (*bytes) { + case '\\': case '&': + goto done; + } + } + + /* + * Proved the simplicity constraints! Time to issue the code. + */ + + result = TCL_OK; + bytes = Tcl_DStringValue(&pattern) + 1; + PushLiteral(envPtr, bytes, len); + bytes = Tcl_GetStringFromObj(replacementObj, &len); + PushLiteral(envPtr, bytes, len); + CompileWord(envPtr, stringTokenPtr, interp, parsePtr->numWords-2); + TclEmitOpcode( INST_STR_MAP, envPtr); + + done: + Tcl_DStringFree(&pattern); + if (patternObj) { + Tcl_DecrRefCount(patternObj); + } + if (replacementObj) { + Tcl_DecrRefCount(replacementObj); + } + return result; +} + +/* + *---------------------------------------------------------------------- + * * TclCompileReturnCmd -- * * Procedure called to compile the "return" command. @@ -3980,6 +5471,7 @@ TclCompileReturnCmd( int numWords = parsePtr->numWords; int explicitResult = (0 == (numWords % 2)); int numOptionWords = numWords - 1 - explicitResult; + int savedStackDepth = envPtr->currStackDepth; Tcl_Obj *returnOpts, **objv; Tcl_Token *wordTokenPtr = TokenAfter(parsePtr->tokenPtr); DefineLineInformation; /* TIP #280 */ @@ -4002,6 +5494,7 @@ TclCompileReturnCmd( CompileWord(envPtr, optsTokenPtr, interp, 2); CompileWord(envPtr, msgTokenPtr, interp, 3); TclEmitOpcode(INST_RETURN_STK, envPtr); + envPtr->currStackDepth = savedStackDepth + 1; return TCL_OK; } @@ -4426,6 +5919,69 @@ IndexTailVarIfKnown( return localIndex; } +int +TclCompileObjectSelfCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + /* + * We only handle [self] and [self object] (which is the same operation). + * These are the only very common operations on [self] for which + * bytecoding is at all reasonable. + */ + + if (parsePtr->numWords == 1) { + goto compileSelfObject; + } else if (parsePtr->numWords == 2) { + Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr), *subcmd; + + if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || tokenPtr[1].size==0) { + return TCL_ERROR; + } + + subcmd = tokenPtr + 1; + if (strncmp(subcmd->start, "object", subcmd->size) == 0) { + goto compileSelfObject; + } else if (strncmp(subcmd->start, "namespace", subcmd->size) == 0) { + goto compileSelfNamespace; + } + } + + /* + * Can't compile; handle with runtime call. + */ + + return TCL_ERROR; + + compileSelfObject: + + /* + * This delegates the entire problem to a single opcode. + */ + + TclEmitOpcode( INST_TCLOO_SELF, envPtr); + return TCL_OK; + + compileSelfNamespace: + + /* + * This is formally only correct with TclOO methods as they are currently + * implemented; it assumes that the current namespace is invariably when a + * TclOO context is present is the object's namespace, and that's + * technically only something that's a matter of current policy. But it + * avoids creating another opcode, so that's all good! + */ + + TclEmitOpcode( INST_TCLOO_SELF, envPtr); + TclEmitOpcode( INST_POP, envPtr); + TclEmitOpcode( INST_NS_CURRENT, envPtr); + return TCL_OK; +} + /* *---------------------------------------------------------------------- * diff --git a/generic/tclCompCmdsSZ.c b/generic/tclCompCmdsSZ.c index 8ed3a95..be63e0e 100644 --- a/generic/tclCompCmdsSZ.c +++ b/generic/tclCompCmdsSZ.c @@ -133,6 +133,8 @@ const AuxDataType tclJumptableInfoType = { #define OP(name) TclEmitOpcode(INST_##name, envPtr) #define OP1(name,val) TclEmitInstInt1(INST_##name,(val),envPtr) #define OP4(name,val) TclEmitInstInt4(INST_##name,(val),envPtr) +#define OP14(name,val1,val2) \ + TclEmitInstInt1(INST_##name,(val1),envPtr);TclEmitInt4((val2),envPtr) #define OP44(name,val1,val2) \ TclEmitInstInt4(INST_##name,(val1),envPtr);TclEmitInt4((val2),envPtr) #define BODY(token,index) \ @@ -249,18 +251,18 @@ TclCompileSetCmd( /* *---------------------------------------------------------------------- * - * TclCompileStringCmpCmd -- + * TclCompileString*Cmd -- * - * Procedure called to compile the simplest and most common form of the - * "string compare" command. + * Procedures called to compile various subcommands of the "string" + * command. * * Results: * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer * evaluation to runtime. * * Side effects: - * Instructions are added to envPtr to execute the "string compare" - * command at runtime. + * Instructions are added to envPtr to execute the "string" command at + * runtime. * *---------------------------------------------------------------------- */ @@ -296,25 +298,6 @@ TclCompileStringCmpCmd( TclEmitOpcode(INST_STR_CMP, envPtr); return TCL_OK; } - -/* - *---------------------------------------------------------------------- - * - * TclCompileStringEqualCmd -- - * - * Procedure called to compile the simplest and most common form of the - * "string equal" command. - * - * Results: - * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer - * evaluation to runtime. - * - * Side effects: - * Instructions are added to envPtr to execute the "string equal" command - * at runtime. - * - *---------------------------------------------------------------------- - */ int TclCompileStringEqualCmd( @@ -347,25 +330,70 @@ TclCompileStringEqualCmd( TclEmitOpcode(INST_STR_EQ, envPtr); return TCL_OK; } - -/* - *---------------------------------------------------------------------- - * - * TclCompileStringIndexCmd -- - * - * Procedure called to compile the simplest and most common form of the - * "string index" command. - * - * Results: - * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer - * evaluation to runtime. - * - * Side effects: - * Instructions are added to envPtr to execute the "string index" command - * at runtime. - * - *---------------------------------------------------------------------- - */ + +int +TclCompileStringFirstCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + DefineLineInformation; /* TIP #280 */ + Tcl_Token *tokenPtr; + + /* + * We don't support any flags; the bytecode isn't that sophisticated. + */ + + if (parsePtr->numWords != 3) { + return TCL_ERROR; + } + + /* + * Push the two operands onto the stack and then the test. + */ + + tokenPtr = TokenAfter(parsePtr->tokenPtr); + CompileWord(envPtr, tokenPtr, interp, 1); + tokenPtr = TokenAfter(tokenPtr); + CompileWord(envPtr, tokenPtr, interp, 2); + OP(STR_FIND); + return TCL_OK; +} + +int +TclCompileStringLastCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + DefineLineInformation; /* TIP #280 */ + Tcl_Token *tokenPtr; + + /* + * We don't support any flags; the bytecode isn't that sophisticated. + */ + + if (parsePtr->numWords != 3) { + return TCL_ERROR; + } + + /* + * Push the two operands onto the stack and then the test. + */ + + tokenPtr = TokenAfter(parsePtr->tokenPtr); + CompileWord(envPtr, tokenPtr, interp, 1); + tokenPtr = TokenAfter(tokenPtr); + CompileWord(envPtr, tokenPtr, interp, 2); + OP(STR_FIND_LAST); + return TCL_OK; +} int TclCompileStringIndexCmd( @@ -394,25 +422,6 @@ TclCompileStringIndexCmd( TclEmitOpcode(INST_STR_INDEX, envPtr); return TCL_OK; } - -/* - *---------------------------------------------------------------------- - * - * TclCompileStringMatchCmd -- - * - * Procedure called to compile the simplest and most common form of the - * "string match" command. - * - * Results: - * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer - * evaluation to runtime. - * - * Side effects: - * Instructions are added to envPtr to execute the "string match" command - * at runtime. - * - *---------------------------------------------------------------------- - */ int TclCompileStringMatchCmd( @@ -494,25 +503,6 @@ TclCompileStringMatchCmd( } return TCL_OK; } - -/* - *---------------------------------------------------------------------- - * - * TclCompileStringLenCmd -- - * - * Procedure called to compile the simplest and most common form of the - * "string length" command. - * - * Results: - * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer - * evaluation to runtime. - * - * Side effects: - * Instructions are added to envPtr to execute the "string length" - * command at runtime. - * - *---------------------------------------------------------------------- - */ int TclCompileStringLenCmd( @@ -553,6 +543,158 @@ TclCompileStringLenCmd( TclDecrRefCount(objPtr); return TCL_OK; } + +int +TclCompileStringMapCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + DefineLineInformation; /* TIP #280 */ + Tcl_Token *mapTokenPtr, *stringTokenPtr; + Tcl_Obj *mapObj, **objv; + char *bytes; + int len; + + /* + * We only handle the case: + * + * string map {foo bar} $thing + * + * That is, a literal two-element list (doesn't need to be brace-quoted, + * but does need to be compile-time knowable) and any old argument (the + * thing to map). + */ + + if (parsePtr->numWords != 3) { + return TCL_ERROR; + } + mapTokenPtr = TokenAfter(parsePtr->tokenPtr); + stringTokenPtr = TokenAfter(mapTokenPtr); + mapObj = Tcl_NewObj(); + Tcl_IncrRefCount(mapObj); + if (!TclWordKnownAtCompileTime(mapTokenPtr, mapObj)) { + Tcl_DecrRefCount(mapObj); + return TCL_ERROR; + } else if (Tcl_ListObjGetElements(NULL, mapObj, &len, &objv) != TCL_OK) { + Tcl_DecrRefCount(mapObj); + return TCL_ERROR; + } else if (len != 2) { + Tcl_DecrRefCount(mapObj); + return TCL_ERROR; + } + + /* + * Now issue the opcodes. Note that in the case that we know that the + * first word is an empty word, we don't issue the map at all. That is the + * correct semantics for mapping. + */ + + bytes = Tcl_GetStringFromObj(objv[0], &len); + if (len == 0) { + CompileWord(envPtr, stringTokenPtr, interp, 2); + } else { + PushLiteral(envPtr, bytes, len); + bytes = Tcl_GetStringFromObj(objv[1], &len); + PushLiteral(envPtr, bytes, len); + CompileWord(envPtr, stringTokenPtr, interp, 2); + OP(STR_MAP); + } + Tcl_DecrRefCount(mapObj); + return TCL_OK; +} + +int +TclCompileStringRangeCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + DefineLineInformation; /* TIP #280 */ + Tcl_Token *stringTokenPtr, *fromTokenPtr, *toTokenPtr; + Tcl_Obj *tmpObj; + int idx1, idx2, result; + + if (parsePtr->numWords != 4) { + return TCL_ERROR; + } + stringTokenPtr = TokenAfter(parsePtr->tokenPtr); + fromTokenPtr = TokenAfter(stringTokenPtr); + toTokenPtr = TokenAfter(fromTokenPtr); + + /* + * Parse the first index. Will only compile if it is constant and not an + * _integer_ less than zero (since we reserve negative indices here for + * end-relative indexing). + */ + + tmpObj = Tcl_NewObj(); + result = TCL_ERROR; + if (TclWordKnownAtCompileTime(fromTokenPtr, tmpObj)) { + if (TclGetIntFromObj(NULL, tmpObj, &idx1) == TCL_OK) { + if (idx1 >= 0) { + result = TCL_OK; + } + } else if (TclGetIntForIndexM(NULL, tmpObj, -2, &idx1) == TCL_OK) { + if (idx1 <= -2) { + result = TCL_OK; + } + } + } + TclDecrRefCount(tmpObj); + if (result != TCL_OK) { + goto nonConstantIndices; + } + + /* + * Parse the second index. Will only compile if it is constant and not an + * _integer_ less than zero (since we reserve negative indices here for + * end-relative indexing). + */ + + tmpObj = Tcl_NewObj(); + result = TCL_ERROR; + if (TclWordKnownAtCompileTime(toTokenPtr, tmpObj)) { + if (TclGetIntFromObj(NULL, tmpObj, &idx2) == TCL_OK) { + if (idx2 >= 0) { + result = TCL_OK; + } + } else if (TclGetIntForIndexM(NULL, tmpObj, -2, &idx2) == TCL_OK) { + if (idx2 <= -2) { + result = TCL_OK; + } + } + } + TclDecrRefCount(tmpObj); + if (result != TCL_OK) { + goto nonConstantIndices; + } + + /* + * Push the operand onto the stack and then the substring operation. + */ + + CompileWord(envPtr, stringTokenPtr, interp, 1); + OP44( STR_RANGE_IMM, idx1, idx2); + return TCL_OK; + + /* + * Push the operands onto the stack and then the substring operation. + */ + + nonConstantIndices: + CompileWord(envPtr, stringTokenPtr, interp, 1); + CompileWord(envPtr, fromTokenPtr, interp, 2); + CompileWord(envPtr, toTokenPtr, interp, 3); + OP( STR_RANGE); + return TCL_OK; +} /* *---------------------------------------------------------------------- @@ -697,11 +839,11 @@ TclSubstCompile( } while (count > 255) { - TclEmitInstInt1(INST_CONCAT1, 255, envPtr); + OP1( CONCAT1, 255); count -= 254; } if (count > 1) { - TclEmitInstInt1(INST_CONCAT1, count, envPtr); + OP1( CONCAT1, count); count = 1; } @@ -722,7 +864,7 @@ TclSubstCompile( envPtr->line = bline; catchRange = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE); - TclEmitInstInt4(INST_BEGIN_CATCH4, catchRange, envPtr); + OP4( BEGIN_CATCH4, catchRange); ExceptionRangeStarts(envPtr, catchRange); switch (tokenPtr->type) { @@ -743,20 +885,20 @@ TclSubstCompile( ExceptionRangeEnds(envPtr, catchRange); /* Substitution produced TCL_OK */ - TclEmitOpcode(INST_END_CATCH, envPtr); + OP( END_CATCH); TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &okFixup); /* Exceptional return codes processed here */ ExceptionRangeTarget(envPtr, catchRange, catchOffset); - TclEmitOpcode(INST_PUSH_RETURN_OPTIONS, envPtr); - TclEmitOpcode(INST_PUSH_RESULT, envPtr); - TclEmitOpcode(INST_PUSH_RETURN_CODE, envPtr); - TclEmitOpcode(INST_END_CATCH, envPtr); - TclEmitOpcode(INST_RETURN_CODE_BRANCH, envPtr); + OP( PUSH_RETURN_OPTIONS); + OP( PUSH_RESULT); + OP( PUSH_RETURN_CODE); + OP( END_CATCH); + OP( RETURN_CODE_BRANCH); /* ERROR -> reraise it */ - TclEmitOpcode(INST_RETURN_STK, envPtr); - TclEmitOpcode(INST_NOP, envPtr); + OP( RETURN_STK); + OP( NOP); /* RETURN */ TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &returnFixup); @@ -775,14 +917,14 @@ TclSubstCompile( Tcl_Panic("TclCompileSubstCmd: bad break jump distance %d", (int) (CurrentOffset(envPtr) - breakFixup.codeOffset)); } - TclEmitOpcode(INST_POP, envPtr); - TclEmitOpcode(INST_POP, envPtr); + OP( POP); + OP( POP); breakJump = CurrentOffset(envPtr) - breakOffset; if (breakJump > 127) { - TclEmitInstInt4(INST_JUMP4, -breakJump, envPtr); + OP4(JUMP4, -breakJump); } else { - TclEmitInstInt1(INST_JUMP1, -breakJump, envPtr); + OP1(JUMP1, -breakJump); } /* CONTINUE destination */ @@ -790,8 +932,8 @@ TclSubstCompile( Tcl_Panic("TclCompileSubstCmd: bad continue jump distance %d", (int) (CurrentOffset(envPtr) - continueFixup.codeOffset)); } - TclEmitOpcode(INST_POP, envPtr); - TclEmitOpcode(INST_POP, envPtr); + OP( POP); + OP( POP); TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &endFixup); /* RETURN + other destination */ @@ -808,8 +950,8 @@ TclSubstCompile( * Pull the result to top of stack, discard options dict. */ - TclEmitInstInt4(INST_REVERSE, 2, envPtr); - TclEmitOpcode(INST_POP, envPtr); + OP4( REVERSE, 2); + OP( POP); /* * We've emitted several POP instructions, and the automatic @@ -828,7 +970,7 @@ TclSubstCompile( (int) (CurrentOffset(envPtr) - okFixup.codeOffset)); } if (count > 1) { - TclEmitInstInt1(INST_CONCAT1, count, envPtr); + OP1(CONCAT1, count); count = 1; } @@ -840,13 +982,12 @@ TclSubstCompile( bline = envPtr->line; } - while (count > 255) { - TclEmitInstInt1(INST_CONCAT1, 255, envPtr); + OP1( CONCAT1, 255); count -= 254; } if (count > 1) { - TclEmitInstInt1(INST_CONCAT1, count, envPtr); + OP1( CONCAT1, count); } Tcl_FreeParse(&parse); @@ -854,6 +995,7 @@ TclSubstCompile( if (state != NULL) { Tcl_RestoreInterpState(interp, state); TclCompileSyntaxError(interp, envPtr); + TclAdjustStackDepth(-1, envPtr); } /* Final target of the multi-jump from all BREAKs */ @@ -1277,14 +1419,14 @@ IssueSwitchChainedTests( switch (mode) { case Switch_Exact: - TclEmitOpcode(INST_DUP, envPtr); + OP( DUP); TclCompileTokens(interp, bodyToken[i], 1, envPtr); - TclEmitOpcode(INST_STR_EQ, envPtr); + OP( STR_EQ); break; case Switch_Glob: TclCompileTokens(interp, bodyToken[i], 1, envPtr); - TclEmitInstInt4(INST_OVER, 1, envPtr); - TclEmitInstInt1(INST_STR_MATCH, noCase, envPtr); + OP4( OVER, 1); + OP1( STR_MATCH, noCase); break; case Switch_Regexp: simple = exact = 0; @@ -1323,7 +1465,7 @@ IssueSwitchChainedTests( TclCompileTokens(interp, bodyToken[i], 1, envPtr); } - TclEmitInstInt4(INST_OVER, 1, envPtr); + OP4( OVER, 1); if (!simple) { /* * Pass correct RE compile flags. We use only Int1 @@ -1335,11 +1477,11 @@ IssueSwitchChainedTests( int cflags = TCL_REG_ADVANCED | (noCase ? TCL_REG_NOCASE : 0); - TclEmitInstInt1(INST_REGEXP, cflags, envPtr); + OP1(REGEXP, cflags); } else if (exact && !noCase) { - TclEmitOpcode(INST_STR_EQ, envPtr); + OP( STR_EQ); } else { - TclEmitInstInt1(INST_STR_MATCH, noCase, envPtr); + OP1(STR_MATCH, noCase); } break; default: @@ -1404,7 +1546,7 @@ IssueSwitchChainedTests( * pattern. */ - TclEmitOpcode(INST_POP, envPtr); + OP( POP); envPtr->currStackDepth = savedStackDepth + 1; envPtr->line = bodyLines[i+1]; /* TIP #280 */ envPtr->clNext = bodyContLines[i+1]; /* TIP #280 */ @@ -1426,7 +1568,7 @@ IssueSwitchChainedTests( */ if (!foundDefault) { - TclEmitOpcode(INST_POP, envPtr); + OP( POP); PushLiteral(envPtr, "", 0); } @@ -1498,6 +1640,7 @@ IssueSwitchJumpTable( int **bodyContLines) /* Array of continuation line info. */ { JumptableInfo *jtPtr; + int savedStackDepth = envPtr->currStackDepth; int infoIndex, isNew, *finalFixups, numRealBodies = 0, jumpLocation; int mustGenerate, foundDefault, jumpToDefault, i; Tcl_DString buffer; @@ -1537,9 +1680,9 @@ IssueSwitchJumpTable( */ jumpLocation = CurrentOffset(envPtr); - TclEmitInstInt4(INST_JUMP_TABLE, infoIndex, envPtr); + OP4( JUMP_TABLE, infoIndex); jumpToDefault = CurrentOffset(envPtr); - TclEmitInstInt4(INST_JUMP4, 0, envPtr); + OP4( JUMP4, 0); for (i=0 ; i<numBodyTokens ; i+=2) { /* @@ -1610,6 +1753,7 @@ IssueSwitchJumpTable( * Compile the body of the arm. */ + envPtr->currStackDepth = savedStackDepth; envPtr->line = bodyLines[i+1]; /* TIP #280 */ envPtr->clNext = bodyContLines[i+1]; /* TIP #280 */ TclCompileCmdWord(interp, bodyToken[i+1], 1, envPtr); @@ -1630,7 +1774,7 @@ IssueSwitchJumpTable( * rewriting when we fixed this all up. */ - TclEmitInstInt4(INST_JUMP4, 0, envPtr); + OP4( JUMP4, 0); } } @@ -1641,6 +1785,7 @@ IssueSwitchJumpTable( */ if (!foundDefault) { + envPtr->currStackDepth = savedStackDepth; TclStoreInt4AtPtr(CurrentOffset(envPtr)-jumpToDefault, envPtr->codeStart+jumpToDefault+1); PushLiteral(envPtr, "", 0); @@ -1661,6 +1806,7 @@ IssueSwitchJumpTable( */ TclStackFree(interp, finalFixups); + envPtr->currStackDepth = savedStackDepth + 1; } /* @@ -1746,6 +1892,50 @@ PrintJumptableInfo( /* *---------------------------------------------------------------------- * + * TclCompileTailcallCmd -- + * + * Procedure called to compile the "tailcall" command. + * + * Results: + * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer + * evaluation to runtime. + * + * Side effects: + * Instructions are added to envPtr to execute the "tailcall" command at + * runtime. + * + *---------------------------------------------------------------------- + */ + +int +TclCompileTailcallCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + DefineLineInformation; /* TIP #280 */ + Tcl_Token *tokenPtr = parsePtr->tokenPtr; + int i; + + if (parsePtr->numWords < 2 || parsePtr->numWords > 256 + || envPtr->procPtr == NULL) { + return TCL_ERROR; + } + + for (i=1 ; i<parsePtr->numWords ; i++) { + tokenPtr = TokenAfter(tokenPtr); + CompileWord(envPtr, tokenPtr, interp, i); + } + TclEmitInstInt1( INST_TAILCALL, parsePtr->numWords-1, envPtr); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * * TclCompileThrowCmd -- * * Procedure called to compile the "throw" command. @@ -1772,6 +1962,7 @@ TclCompileThrowCmd( { DefineLineInformation; /* TIP #280 */ int numWords = parsePtr->numWords; + int savedStackDepth = envPtr->currStackDepth; Tcl_Token *codeToken, *msgToken; Tcl_Obj *objPtr; @@ -1802,6 +1993,7 @@ TclCompileThrowCmd( CompileWord(envPtr, msgToken, interp, 2); TclCompileSyntaxError(interp, envPtr); Tcl_DecrRefCount(objPtr); + envPtr->currStackDepth = savedStackDepth + 1; return TCL_OK; } if (len == 0) { @@ -1822,6 +2014,7 @@ TclCompileThrowCmd( PushLiteral(envPtr, string, len); TclDecrRefCount(dictPtr); OP44( RETURN_IMM, 1, 0); + envPtr->currStackDepth = savedStackDepth + 1; } else { /* * When the code token is not known at compilation time, we need to do @@ -1850,6 +2043,7 @@ TclCompileThrowCmd( PUSH( ""); OP44( RETURN_IMM, 1, 0); } + envPtr->currStackDepth = savedStackDepth + 1; TclDecrRefCount(objPtr); return TCL_OK; } @@ -2117,6 +2311,7 @@ IssueTryInstructions( { DefineLineInformation; /* TIP #280 */ int range, resultVar, optionsVar; + int savedStackDepth = envPtr->currStackDepth; int i, j, len, forwardsNeedFixing = 0; int *addrsToFix, *forwardsToFix, notCodeJumpSource, notECJumpSource; char buf[TCL_INTEGER_SPACE]; @@ -2178,6 +2373,7 @@ IssueTryInstructions( LOAD( optionsVar); PUSH( "-errorcode"); OP4( DICT_GET, 1); + TclAdjustStackDepth(-1, envPtr); OP44( LIST_RANGE_IMM, 0, len-1); PUSH( TclGetString(matchClauses[i])); OP( STR_EQ); @@ -2218,6 +2414,7 @@ IssueTryInstructions( forwardsToFix[j] = -1; } } + envPtr->currStackDepth = savedStackDepth; BODY( handlerTokens[i], 5+i*4); } @@ -2249,6 +2446,7 @@ IssueTryInstructions( } TclStackFree(interp, forwardsToFix); TclStackFree(interp, addrsToFix); + envPtr->currStackDepth = savedStackDepth + 1; return TCL_OK; } @@ -2285,6 +2483,7 @@ IssueTryFinallyInstructions( range = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE); OP4( BEGIN_CATCH4, range); ExceptionRangeStarts(envPtr, range); + envPtr->currStackDepth = savedStackDepth; BODY( bodyToken, 1); ExceptionRangeEnds(envPtr, range); PUSH( "0"); @@ -2329,6 +2528,7 @@ IssueTryFinallyInstructions( LOAD( optionsVar); PUSH( "-errorcode"); OP4( DICT_GET, 1); + TclAdjustStackDepth(-1, envPtr); OP44( LIST_RANGE_IMM, 0, len-1); PUSH( TclGetString(matchClauses[i])); OP( STR_EQ); @@ -2401,6 +2601,7 @@ IssueTryFinallyInstructions( } OP4( BEGIN_CATCH4, range); } + envPtr->currStackDepth = savedStackDepth; BODY( handlerTokens[i], 5+i*4); ExceptionRangeEnds(envPtr, range); OP( PUSH_RETURN_OPTIONS); @@ -2452,7 +2653,6 @@ IssueTryFinallyInstructions( */ OP( POP); - envPtr->currStackDepth = savedStackDepth; /* * Process the finally clause (at last!) Note that we do not wrap this in @@ -2462,11 +2662,13 @@ IssueTryFinallyInstructions( * next command (or some inter-command manipulation). */ + envPtr->currStackDepth = savedStackDepth; BODY( finallyToken, 3 + 4*numHandlers); OP( POP); LOAD( optionsVar); LOAD( resultVar); OP( RETURN_STK); + envPtr->currStackDepth = savedStackDepth + 1; return TCL_OK; } @@ -2547,20 +2749,18 @@ TclCompileUnsetCmd( */ if (!simpleVarName) { - TclEmitInstInt1( INST_UNSET_STK, flags, envPtr); + OP1( UNSET_STK, flags); } else if (isScalar) { if (localIndex < 0) { - TclEmitInstInt1(INST_UNSET_STK, flags, envPtr); + OP1( UNSET_STK, flags); } else { - TclEmitInstInt1(INST_UNSET_SCALAR, flags, envPtr); - TclEmitInt4( localIndex, envPtr); + OP14( UNSET_SCALAR, flags, localIndex); } } else { if (localIndex < 0) { - TclEmitInstInt1(INST_UNSET_ARRAY_STK, flags, envPtr); + OP1( UNSET_ARRAY_STK, flags); } else { - TclEmitInstInt1(INST_UNSET_ARRAY, flags, envPtr); - TclEmitInt4( localIndex, envPtr); + OP14( UNSET_ARRAY, flags, localIndex); } } @@ -2697,7 +2897,7 @@ TclCompileWhileCmd( CompileBody(envPtr, bodyTokenPtr, interp); ExceptionRangeEnds(envPtr, range); envPtr->currStackDepth = savedStackDepth + 1; - TclEmitOpcode(INST_POP, envPtr); + OP( POP); /* * Compile the test expression then emit the conditional jump that @@ -2752,6 +2952,49 @@ TclCompileWhileCmd( /* *---------------------------------------------------------------------- * + * TclCompileYieldCmd -- + * + * Procedure called to compile the "yield" command. + * + * Results: + * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer + * evaluation to runtime. + * + * Side effects: + * Instructions are added to envPtr to execute the "yield" command at + * runtime. + * + *---------------------------------------------------------------------- + */ + +int +TclCompileYieldCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + if (parsePtr->numWords < 1 || parsePtr->numWords > 2) { + return TCL_ERROR; + } + + if (parsePtr->numWords == 1) { + PushLiteral(envPtr, "", 0); + } else { + DefineLineInformation; /* TIP #280 */ + Tcl_Token *valueTokenPtr = TokenAfter(parsePtr->tokenPtr); + + CompileWord(envPtr, valueTokenPtr, interp, 1); + } + OP( YIELD); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * * PushVarName -- * * Procedure used in the compiling where pushing a variable name is @@ -3074,7 +3317,7 @@ CompileAssociativeBinaryOpCmd( * calcuations, including roundoff errors. */ - TclEmitInstInt4(INST_REVERSE, words-1, envPtr); + OP4( REVERSE, words-1); } while (--words > 1) { TclEmitOpcode(instruction, envPtr); @@ -3165,31 +3408,19 @@ CompileComparisonOpCmd( CompileWord(envPtr, tokenPtr, interp, 1); tokenPtr = TokenAfter(tokenPtr); CompileWord(envPtr, tokenPtr, interp, 2); - if (tmpIndex <= 255) { - TclEmitInstInt1(INST_STORE_SCALAR1, tmpIndex, envPtr); - } else { - TclEmitInstInt4(INST_STORE_SCALAR4, tmpIndex, envPtr); - } + STORE(tmpIndex); TclEmitOpcode(instruction, envPtr); for (words=3 ; words<parsePtr->numWords ;) { - if (tmpIndex <= 255) { - TclEmitInstInt1(INST_LOAD_SCALAR1, tmpIndex, envPtr); - } else { - TclEmitInstInt4(INST_LOAD_SCALAR4, tmpIndex, envPtr); - } + LOAD(tmpIndex); tokenPtr = TokenAfter(tokenPtr); CompileWord(envPtr, tokenPtr, interp, words); if (++words < parsePtr->numWords) { - if (tmpIndex <= 255) { - TclEmitInstInt1(INST_STORE_SCALAR1, tmpIndex, envPtr); - } else { - TclEmitInstInt4(INST_STORE_SCALAR4, tmpIndex, envPtr); - } + STORE(tmpIndex); } TclEmitOpcode(instruction, envPtr); } for (; words>3 ; words--) { - TclEmitOpcode(INST_BITAND, envPtr); + OP( BITAND); } /* @@ -3197,13 +3428,7 @@ CompileComparisonOpCmd( * might be expensive elsewhere. */ - PushLiteral(envPtr, "", 0); - if (tmpIndex <= 255) { - TclEmitInstInt1(INST_STORE_SCALAR1, tmpIndex, envPtr); - } else { - TclEmitInstInt4(INST_STORE_SCALAR4, tmpIndex, envPtr); - } - TclEmitOpcode(INST_POP, envPtr); + OP14( UNSET_SCALAR, 0, tmpIndex); } return TCL_OK; } diff --git a/generic/tclCompile.c b/generic/tclCompile.c index d4ca284..309682d 100644 --- a/generic/tclCompile.c +++ b/generic/tclCompile.c @@ -37,7 +37,7 @@ TCL_DECLARE_MUTEX(tableMutex) int tclTraceCompile = 0; static int traceInitialized = 0; #endif - + /* * A table describing the Tcl bytecode instructions. Entries in this table * must correspond to the instruction opcode definitions in tclCompile.h. The @@ -372,13 +372,13 @@ InstructionDesc const tclInstructionTable[] = { * Stack: ... value => ... * Note that the jump table contains offsets relative to the PC when * it points to this instruction; the code is relocatable. */ - {"upvar", 5, 0, 1, {OPERAND_LVT4}}, + {"upvar", 5, -1, 1, {OPERAND_LVT4}}, /* finds level and otherName in stack, links to local variable at * index op1. Leaves the level on stack. */ - {"nsupvar", 5, 0, 1, {OPERAND_LVT4}}, + {"nsupvar", 5, -1, 1, {OPERAND_LVT4}}, /* finds namespace and otherName in stack, links to local variable at * index op1. Leaves the namespace on stack. */ - {"variable", 5, 0, 1, {OPERAND_LVT4}}, + {"variable", 5, -1, 1, {OPERAND_LVT4}}, /* finds namespace and otherName in stack, links to local variable at * index op1. Leaves the namespace on stack. */ {"syntax", 9, -1, 2, {OPERAND_INT4, OPERAND_UINT4}}, @@ -434,6 +434,100 @@ InstructionDesc const tclInstructionTable[] = { /* Map variable contents back into a dictionary in the local variable * indicated by the LVT index. Part of [dict with]. * Stack: ... path keyList => ... */ + {"dictExists", 5, INT_MIN, 1, {OPERAND_UINT4}}, + /* The top op4 words (min 1) are a key path into the dictionary just + * below the keys on the stack, and all those values are replaced by a + * boolean indicating whether it is possible to read out a value from + * that key-path (like [dict exists]). + * Stack: ... dict key1 ... keyN => ... boolean */ + {"verifyDict", 1, -1, 0, {OPERAND_NONE}}, + /* Verifies that the word on the top of the stack is a dictionary, + * popping it if it is and throwing an error if it is not. + * Stack: ... value => ... */ + + {"strmap", 1, -2, 0, {OPERAND_NONE}}, + /* Simplified version of [string map] that only applies one change + * string, and only case-sensitively. + * Stack: ... from to string => ... changedString */ + {"strfind", 1, -1, 0, {OPERAND_NONE}}, + /* Find the first index of a needle string in a haystack string, + * producing the index (integer) or -1 if nothing found. + * Stack: ... needle haystack => ... index */ + {"strrfind", 1, -1, 0, {OPERAND_NONE}}, + /* Find the last index of a needle string in a haystack string, + * producing the index (integer) or -1 if nothing found. + * Stack: ... needle haystack => ... index */ + {"strrangeImm", 9, 0, 2, {OPERAND_IDX4, OPERAND_IDX4}}, + /* String Range: push (string range stktop op4 op4) */ + {"strrange", 1, -2, 0, {OPERAND_NONE}}, + /* String Range with non-constant arguments. + * Stack: ... string idxA idxB => ... substring */ + + {"yield", 1, 0, 0, {OPERAND_NONE}}, + /* Makes the current coroutine yield the value at the top of the + * stack, and places the response back on top of the stack when it + * resumes. + * Stack: ... valueToYield => ... resumeValue */ + {"coroName", 1, +1, 0, {OPERAND_NONE}}, + /* Push the name of the interpreter's current coroutine as an object + * on the stack. */ + {"tailcall", 2, INT_MIN, 1, {OPERAND_UINT1}}, + /* Do a tailcall with the opnd items on the stack as the thing to + * tailcall to; opnd must be greater than 0 for the semantics to work + * right. */ + + {"currentNamespace", 1, +1, 0, {OPERAND_NONE}}, + /* Push the name of the interpreter's current namespace as an object + * on the stack. */ + {"infoLevelNumber", 1, +1, 0, {OPERAND_NONE}}, + /* Push the stack depth (i.e., [info level]) of the interpreter as an + * object on the stack. */ + {"infoLevelArgs", 1, 0, 0, {OPERAND_NONE}}, + /* Push the argument words to a stack depth (i.e., [info level <n>]) + * of the interpreter as an object on the stack. + * Stack: ... depth => ... argList */ + {"resolveCmd", 1, 0, 0, {OPERAND_NONE}}, + /* Resolves the command named on the top of the stack to its fully + * qualified version, or produces the empty string if no such command + * exists. Never generates errors. + * Stack: ... cmdName => ... fullCmdName */ + {"tclooSelf", 1, +1, 0, {OPERAND_NONE}}, + /* Push the identity of the current TclOO object (i.e., the name of + * its current public access command) on the stack. */ + {"tclooClass", 1, 0, 0, {OPERAND_NONE}}, + /* Push the class of the TclOO object named at the top of the stack + * onto the stack. + * Stack: ... object => ... class */ + {"tclooNamespace", 1, 0, 0, {OPERAND_NONE}}, + /* Push the namespace of the TclOO object named at the top of the + * stack onto the stack. + * Stack: ... object => ... namespace */ + {"tclooIsObject", 1, 0, 0, {OPERAND_NONE}}, + /* Push whether the value named at the top of the stack is a TclOO + * object (i.e., a boolean). Can corrupt the interpreter result + * despite not throwing, so not safe for use in a post-exception + * context. + * Stack: ... value => ... boolean */ + + {"arrayExistsStk", 1, 0, 0, {OPERAND_NONE}}, + /* Looks up the element on the top of the stack and tests whether it + * is an array. Pushes a boolean describing whether this is the + * case. Also runs the whole-array trace on the named variable, so can + * throw anything. + * Stack: ... varName => ... boolean */ + {"arrayExistsImm", 5, +1, 1, {OPERAND_UINT4}}, + /* Looks up the variable indexed by opnd and tests whether it is an + * array. Pushes a boolean describing whether this is the case. Also + * runs the whole-array trace on the named variable, so can throw + * anything. + * Stack: ... => ... boolean */ + {"arrayMakeStk", 1, -1, 0, {OPERAND_NONE}}, + /* Forces the element on the top of the stack to be the name of an + * array. + * Stack: ... varName => ... */ + {"arrayMakeImm", 5, 0, 1, {OPERAND_UINT4}}, + /* Forces the variable indexed by opnd to be an array. Does not touch + * the stack. */ {NULL, 0, 0, 0, {OPERAND_NONE}} }; @@ -1673,10 +1767,13 @@ TclCompileScript( && !(cmdPtr->nsPtr->flags&NS_SUPPRESS_COMPILATION) && !(cmdPtr->flags & CMD_HAS_EXEC_TRACES) && !(iPtr->flags & DONT_COMPILE_CMDS_INLINE)) { - int savedNumCmds = envPtr->numCommands; + int code, savedNumCmds = envPtr->numCommands; unsigned savedCodeNext = envPtr->codeNext - envPtr->codeStart; - int update = 0, code; + int update = 0; +#ifdef TCL_COMPILE_DEBUG + int startStackDepth = envPtr->currStackDepth; +#endif /* * Mark the start of the command; the proper bytecode @@ -1720,6 +1817,25 @@ TclCompileScript( envPtr); if (code == TCL_OK) { + /* + * Confirm that the command compiler generated a + * single value on the stack as its result. This + * is only done in debugging mode, as it *should* + * be correct and normal users have no reasonable + * way to fix it anyway. + */ + +#ifdef TCL_COMPILE_DEBUG + int diff = envPtr->currStackDepth-startStackDepth; + + if (diff != 1 && (diff != 0 || + *(envPtr->codeNext-1) != INST_DONE)) { + Tcl_Panic("bad stack adjustment when compiling" + " %.*s (was %d instead of 1)", + parsePtr->tokenPtr->size, + parsePtr->tokenPtr->start, diff); + } +#endif if (update) { /* * Fix the bytecode length. @@ -4620,6 +4736,5 @@ RecordByteCodeStats( * c-basic-offset: 4 * fill-column: 78 * tab-width: 8 - * indent-tabs-mode: nil * End: */ diff --git a/generic/tclCompile.h b/generic/tclCompile.h index ba78c36..3302f9b 100644 --- a/generic/tclCompile.h +++ b/generic/tclCompile.h @@ -676,13 +676,43 @@ typedef struct ByteCode { #define INST_UNSET_ARRAY_STK 136 #define INST_UNSET_STK 137 -/* For [dict with] compilation */ +/* For [dict with], [dict exists], [dict create] and [dict merge] */ #define INST_DICT_EXPAND 138 #define INST_DICT_RECOMBINE_STK 139 #define INST_DICT_RECOMBINE_IMM 140 +#define INST_DICT_EXISTS 141 +#define INST_DICT_VERIFY 142 + +/* For [string map] and [regsub] compilation */ +#define INST_STR_MAP 143 +#define INST_STR_FIND 144 +#define INST_STR_FIND_LAST 145 +#define INST_STR_RANGE_IMM 146 +#define INST_STR_RANGE 147 + +/* For operations to do with coroutines and other NRE-manipulators */ +#define INST_YIELD 148 +#define INST_COROUTINE_NAME 149 +#define INST_TAILCALL 150 + +/* For compilation of basic information operations */ +#define INST_NS_CURRENT 151 +#define INST_INFO_LEVEL_NUM 152 +#define INST_INFO_LEVEL_ARGS 153 +#define INST_RESOLVE_COMMAND 154 +#define INST_TCLOO_SELF 155 +#define INST_TCLOO_CLASS 156 +#define INST_TCLOO_NS 157 +#define INST_TCLOO_IS_OBJECT 158 + +/* For compilation of [array] subcommands */ +#define INST_ARRAY_EXISTS_STK 159 +#define INST_ARRAY_EXISTS_IMM 160 +#define INST_ARRAY_MAKE_STK 161 +#define INST_ARRAY_MAKE_IMM 162 /* The last opcode */ -#define LAST_INST_OPCODE 140 +#define LAST_INST_OPCODE 162 /* * Table describing the Tcl bytecode instructions: their name (for displaying diff --git a/generic/tclConfig.c b/generic/tclConfig.c index dea487a..a4ba71a 100644 --- a/generic/tclConfig.c +++ b/generic/tclConfig.c @@ -236,7 +236,7 @@ QueryConfigObjCmd( * present. */ - Tcl_SetResult(interp, "package not known", TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj("package not known", -1)); Tcl_SetErrorCode(interp, "TCL", "FATAL", "PKGCFG_BASE", Tcl_GetString(pkgName), NULL); return TCL_ERROR; @@ -251,7 +251,7 @@ QueryConfigObjCmd( if (Tcl_DictObjGet(interp, pkgDict, objv[2], &val) != TCL_OK || val == NULL) { - Tcl_SetResult(interp, "key not known", TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj("key not known", -1)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CONFIG", Tcl_GetString(objv[2]), NULL); return TCL_ERROR; @@ -270,8 +270,8 @@ QueryConfigObjCmd( listPtr = Tcl_NewListObj(n, NULL); if (!listPtr) { - Tcl_SetResult(interp, "insufficient memory to create list", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "insufficient memory to create list", -1)); Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL); return TCL_ERROR; } diff --git a/generic/tclDecls.h b/generic/tclDecls.h index 1e2a68b..2801102 100644 --- a/generic/tclDecls.h +++ b/generic/tclDecls.h @@ -1807,8 +1807,12 @@ EXTERN void * Tcl_FindSymbol(Tcl_Interp *interp, /* 629 */ EXTERN int Tcl_FSUnloadFile(Tcl_Interp *interp, Tcl_LoadHandle handlePtr); +/* 630 */ +EXTERN void Tcl_ZlibStreamSetCompressionDictionary( + Tcl_ZlibStream zhandle, + Tcl_Obj *compressionDictionaryObj); -typedef struct TclStubHooks { +typedef struct { const struct TclPlatStubs *tclPlatStubs; const struct TclIntStubs *tclIntStubs; const struct TclIntPlatStubs *tclIntPlatStubs; @@ -1816,7 +1820,7 @@ typedef struct TclStubHooks { typedef struct TclStubs { int magic; - const struct TclStubHooks *hooks; + const TclStubHooks *hooks; int (*tcl_PkgProvideEx) (Tcl_Interp *interp, const char *name, const char *version, const void *clientData); /* 0 */ CONST84_RETURN char * (*tcl_PkgRequireEx) (Tcl_Interp *interp, const char *name, const char *version, int exact, void *clientDataPtr); /* 1 */ @@ -2472,6 +2476,7 @@ typedef struct TclStubs { int (*tcl_LoadFile) (Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *const symv[], int flags, void *procPtrs, Tcl_LoadHandle *handlePtr); /* 627 */ void * (*tcl_FindSymbol) (Tcl_Interp *interp, Tcl_LoadHandle handle, const char *symbol); /* 628 */ int (*tcl_FSUnloadFile) (Tcl_Interp *interp, Tcl_LoadHandle handlePtr); /* 629 */ + void (*tcl_ZlibStreamSetCompressionDictionary) (Tcl_ZlibStream zhandle, Tcl_Obj *compressionDictionaryObj); /* 630 */ } TclStubs; #ifdef __cplusplus @@ -3764,6 +3769,8 @@ extern const TclStubs *tclStubsPtr; (tclStubsPtr->tcl_FindSymbol) /* 628 */ #define Tcl_FSUnloadFile \ (tclStubsPtr->tcl_FSUnloadFile) /* 629 */ +#define Tcl_ZlibStreamSetCompressionDictionary \ + (tclStubsPtr->tcl_ZlibStreamSetCompressionDictionary) /* 630 */ #endif /* defined(USE_TCL_STUBS) */ diff --git a/generic/tclDictObj.c b/generic/tclDictObj.c index ac2cb62..eb3625e 100644 --- a/generic/tclDictObj.c +++ b/generic/tclDictObj.c @@ -76,9 +76,12 @@ static int FinalizeDictWith(ClientData data[], Tcl_Interp *interp, int result); static int DictForNRCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); +static int DictMapNRCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const *objv); static int DictForLoopCallback(ClientData data[], Tcl_Interp *interp, int result); - +static int DictMapLoopCallback(ClientData data[], + Tcl_Interp *interp, int result); /* * Table of dict subcommand names and implementations. @@ -86,8 +89,8 @@ static int DictForLoopCallback(ClientData data[], static const EnsembleImplMap implementationMap[] = { {"append", DictAppendCmd, TclCompileDictAppendCmd, NULL, NULL, 0 }, - {"create", DictCreateCmd, NULL, NULL, NULL, 0 }, - {"exists", DictExistsCmd, NULL, NULL, NULL, 0 }, + {"create", DictCreateCmd, TclCompileDictCreateCmd, NULL, NULL, 0 }, + {"exists", DictExistsCmd, TclCompileDictExistsCmd, NULL, NULL, 0 }, {"filter", DictFilterCmd, NULL, NULL, NULL, 0 }, {"for", NULL, TclCompileDictForCmd, DictForNRCmd, NULL, 0 }, {"get", DictGetCmd, TclCompileDictGetCmd, NULL, NULL, 0 }, @@ -95,12 +98,13 @@ static const EnsembleImplMap implementationMap[] = { {"info", DictInfoCmd, NULL, NULL, NULL, 0 }, {"keys", DictKeysCmd, NULL, NULL, NULL, 0 }, {"lappend", DictLappendCmd, TclCompileDictLappendCmd, NULL, NULL, 0 }, - {"merge", DictMergeCmd, NULL, NULL, NULL, 0 }, + {"map", NULL, TclCompileDictMapCmd, DictMapNRCmd, NULL, 0 }, + {"merge", DictMergeCmd, TclCompileDictMergeCmd, NULL, NULL, 0 }, {"remove", DictRemoveCmd, NULL, NULL, NULL, 0 }, {"replace", DictReplaceCmd, NULL, NULL, NULL, 0 }, {"set", DictSetCmd, TclCompileDictSetCmd, NULL, NULL, 0 }, {"size", DictSizeCmd, NULL, NULL, NULL, 0 }, - {"unset", DictUnsetCmd, NULL, NULL, NULL, 0 }, + {"unset", DictUnsetCmd, TclCompileDictUnsetCmd, NULL, NULL, 0 }, {"update", DictUpdateCmd, TclCompileDictUpdateCmd, NULL, NULL, 0 }, {"values", DictValuesCmd, NULL, NULL, NULL, 0 }, {"with", DictWithCmd, TclCompileDictWithCmd, NULL, NULL, 0 }, @@ -181,6 +185,23 @@ static const Tcl_HashKeyType chainHashType = { AllocChainEntry, TclFreeObjEntry }; + +/* + * Structure used in implementation of 'dict map' to hold the state that gets + * passed between parts of the implementation. + */ + +typedef struct { + Tcl_Obj *keyVarObj; /* The name of the variable that will have + * keys assigned to it. */ + Tcl_Obj *valueVarObj; /* The name of the variable that will have + * values assigned to it. */ + Tcl_DictSearch search; /* The dictionary search structure. */ + Tcl_Obj *scriptObj; /* The script to evaluate each time through + * the loop. */ + Tcl_Obj *accumulatorObj; /* The dictionary used to accumulate the + * results. */ +} DictMapStorage; /***** START OF FUNCTIONS IMPLEMENTING DICT CORE API *****/ @@ -700,7 +721,8 @@ SetDictFromAny( missingValue: if (interp != NULL) { - Tcl_SetResult(interp, "missing value to go with key", TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "missing value to go with key", -1)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "DICTIONARY", NULL); } result = TCL_ERROR; @@ -779,9 +801,9 @@ TclTraceDictPath( } if ((flags & DICT_PATH_CREATE) != DICT_PATH_CREATE) { if (interp != NULL) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "key \"", TclGetString(keyv[i]), - "\" not known in dictionary", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "key \"%s\" not known in dictionary", + TclGetString(keyv[i]))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "DICT", TclGetString(keyv[i]), NULL); } @@ -953,6 +975,7 @@ Tcl_DictObjGet( if (dictPtr->typePtr != &tclDictType) { int result = SetDictFromAny(interp, dictPtr); if (result != TCL_OK) { + *valuePtrPtr = NULL; return result; } } @@ -1571,9 +1594,9 @@ DictGetCmd( return result; } if (valuePtr == NULL) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "key \"", TclGetString(objv[objc-1]), - "\" not known in dictionary", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "key \"%s\" not known in dictionary", + TclGetString(objv[objc-1]))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "DICT", TclGetString(objv[objc-1]), NULL); return TCL_ERROR; @@ -2027,6 +2050,7 @@ DictInfoCmd( { Tcl_Obj *dictPtr; Dict *dict; + char *statsStr; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "dictionary"); @@ -2042,7 +2066,9 @@ DictInfoCmd( } dict = dictPtr->internalRep.otherValuePtr; - Tcl_SetResult(interp, Tcl_HashStats(&dict->table), TCL_DYNAMIC); + statsStr = Tcl_HashStats(&dict->table); + Tcl_SetObjResult(interp, Tcl_NewStringObj(statsStr, -1)); + ckfree(statsStr); return TCL_OK; } @@ -2331,7 +2357,7 @@ DictAppendCmd( * * DictForNRCmd -- * - * This function implements the "dict for" Tcl command. See the user + * These functions implement the "dict for" Tcl command. See the user * documentation for details on what it does, and TIP#111 for the formal * specification. * @@ -2371,8 +2397,8 @@ DictForNRCmd( return TCL_ERROR; } if (varc != 2) { - Tcl_SetResult(interp, "must have exactly two variable names", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "must have exactly two variable names", -1)); return TCL_ERROR; } searchPtr = TclStackAlloc(interp, sizeof(Tcl_DictSearch)); @@ -2484,13 +2510,15 @@ DictForLoopCallback( */ Tcl_IncrRefCount(valueObj); - if (Tcl_ObjSetVar2(interp, keyVarObj, NULL, keyObj, TCL_LEAVE_ERR_MSG) == NULL) { + if (Tcl_ObjSetVar2(interp, keyVarObj, NULL, keyObj, + TCL_LEAVE_ERR_MSG) == NULL) { TclDecrRefCount(valueObj); result = TCL_ERROR; goto done; } TclDecrRefCount(valueObj); - if (Tcl_ObjSetVar2(interp, valueVarObj, NULL, valueObj, TCL_LEAVE_ERR_MSG) == NULL) { + if (Tcl_ObjSetVar2(interp, valueVarObj, NULL, valueObj, + TCL_LEAVE_ERR_MSG) == NULL) { result = TCL_ERROR; goto done; } @@ -2519,6 +2547,217 @@ DictForLoopCallback( /* *---------------------------------------------------------------------- * + * DictMapNRCmd -- + * + * These functions implement the "dict map" Tcl command. See the user + * documentation for details on what it does, and TIP#405 for the formal + * specification. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *---------------------------------------------------------------------- + */ + +static int +DictMapNRCmd( + ClientData dummy, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const *objv) +{ + Interp *iPtr = (Interp *) interp; + Tcl_Obj **varv, *keyObj, *valueObj; + DictMapStorage *storagePtr; + int varc, done; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 1, objv, + "{keyVar valueVar} dictionary script"); + return TCL_ERROR; + } + + /* + * Parse arguments. + */ + + if (TclListObjGetElements(interp, objv[1], &varc, &varv) != TCL_OK) { + return TCL_ERROR; + } + if (varc != 2) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "must have exactly two variable names", -1)); + return TCL_ERROR; + } + storagePtr = TclStackAlloc(interp, sizeof(DictMapStorage)); + if (Tcl_DictObjFirst(interp, objv[2], &storagePtr->search, &keyObj, + &valueObj, &done) != TCL_OK) { + TclStackFree(interp, storagePtr); + return TCL_ERROR; + } + if (done) { + /* + * Note that this exit leaves an empty value in the result (due to + * command calling conventions) but that is OK since an empty value is + * an empty dictionary. + */ + + TclStackFree(interp, storagePtr); + return TCL_OK; + } + TclNewObj(storagePtr->accumulatorObj); + TclListObjGetElements(NULL, objv[1], &varc, &varv); + storagePtr->keyVarObj = varv[0]; + storagePtr->valueVarObj = varv[1]; + storagePtr->scriptObj = objv[3]; + + /* + * Make sure that these objects (which we need throughout the body of the + * loop) don't vanish. Note that the dictionary internal rep is locked + * internally so that updates, shimmering, etc are not a problem. + */ + + Tcl_IncrRefCount(storagePtr->accumulatorObj); + Tcl_IncrRefCount(storagePtr->keyVarObj); + Tcl_IncrRefCount(storagePtr->valueVarObj); + Tcl_IncrRefCount(storagePtr->scriptObj); + + /* + * Stop the value from getting hit in any way by any traces on the key + * variable. + */ + + Tcl_IncrRefCount(valueObj); + if (Tcl_ObjSetVar2(interp, storagePtr->keyVarObj, NULL, keyObj, + TCL_LEAVE_ERR_MSG) == NULL) { + TclDecrRefCount(valueObj); + goto error; + } + if (Tcl_ObjSetVar2(interp, storagePtr->valueVarObj, NULL, valueObj, + TCL_LEAVE_ERR_MSG) == NULL) { + TclDecrRefCount(valueObj); + goto error; + } + TclDecrRefCount(valueObj); + + /* + * Run the script. + */ + + TclNRAddCallback(interp, DictMapLoopCallback, storagePtr, NULL,NULL,NULL); + return TclNREvalObjEx(interp, storagePtr->scriptObj, 0, + iPtr->cmdFramePtr, 3); + + /* + * For unwinding everything on error. + */ + + error: + TclDecrRefCount(storagePtr->keyVarObj); + TclDecrRefCount(storagePtr->valueVarObj); + TclDecrRefCount(storagePtr->scriptObj); + TclDecrRefCount(storagePtr->accumulatorObj); + Tcl_DictObjDone(&storagePtr->search); + TclStackFree(interp, storagePtr); + return TCL_ERROR; +} + +static int +DictMapLoopCallback( + ClientData data[], + Tcl_Interp *interp, + int result) +{ + Interp *iPtr = (Interp *) interp; + DictMapStorage *storagePtr = data[0]; + Tcl_Obj *keyObj, *valueObj; + int done; + + /* + * Process the result from the previous execution of the script body. + */ + + if (result == TCL_CONTINUE) { + result = TCL_OK; + } else if (result != TCL_OK) { + if (result == TCL_BREAK) { + Tcl_ResetResult(interp); + result = TCL_OK; + } else if (result == TCL_ERROR) { + Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( + "\n (\"dict map\" body line %d)", + Tcl_GetErrorLine(interp))); + } + goto done; + } else { + keyObj = Tcl_ObjGetVar2(interp, storagePtr->keyVarObj, NULL, + TCL_LEAVE_ERR_MSG); + if (keyObj == NULL) { + result = TCL_ERROR; + goto done; + } + Tcl_DictObjPut(NULL, storagePtr->accumulatorObj, keyObj, + Tcl_GetObjResult(interp)); + } + + /* + * Get the next mapping from the dictionary. + */ + + Tcl_DictObjNext(&storagePtr->search, &keyObj, &valueObj, &done); + if (done) { + Tcl_SetObjResult(interp, storagePtr->accumulatorObj); + goto done; + } + + /* + * Stop the value from getting hit in any way by any traces on the key + * variable. + */ + + Tcl_IncrRefCount(valueObj); + if (Tcl_ObjSetVar2(interp, storagePtr->keyVarObj, NULL, keyObj, + TCL_LEAVE_ERR_MSG) == NULL) { + TclDecrRefCount(valueObj); + result = TCL_ERROR; + goto done; + } + if (Tcl_ObjSetVar2(interp, storagePtr->valueVarObj, NULL, valueObj, + TCL_LEAVE_ERR_MSG) == NULL) { + TclDecrRefCount(valueObj); + result = TCL_ERROR; + goto done; + } + TclDecrRefCount(valueObj); + + /* + * Run the script. + */ + + TclNRAddCallback(interp, DictMapLoopCallback, storagePtr, NULL,NULL,NULL); + return TclNREvalObjEx(interp, storagePtr->scriptObj, 0, + iPtr->cmdFramePtr, 3); + + /* + * For unwinding everything once the iterating is done. + */ + + done: + TclDecrRefCount(storagePtr->keyVarObj); + TclDecrRefCount(storagePtr->valueVarObj); + TclDecrRefCount(storagePtr->scriptObj); + TclDecrRefCount(storagePtr->accumulatorObj); + Tcl_DictObjDone(&storagePtr->search); + TclStackFree(interp, storagePtr); + return result; +} + +/* + *---------------------------------------------------------------------- + * * DictSetCmd -- * * This function implements the "dict set" Tcl command. See the user @@ -2787,8 +3026,8 @@ DictFilterCmd( return TCL_ERROR; } if (varc != 2) { - Tcl_SetResult(interp, "must have exactly two variable names", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "must have exactly two variable names", -1)); return TCL_ERROR; } keyVarObj = varv[0]; @@ -2828,16 +3067,19 @@ DictFilterCmd( if (Tcl_ObjSetVar2(interp, keyVarObj, NULL, keyObj, TCL_LEAVE_ERR_MSG) == NULL) { Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "couldn't set key variable: \"", - TclGetString(keyVarObj), "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't set key variable: \"%s\"", + TclGetString(keyVarObj))); result = TCL_ERROR; goto abnormalResult; } if (Tcl_ObjSetVar2(interp, valueVarObj, NULL, valueObj, TCL_LEAVE_ERR_MSG) == NULL) { Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "couldn't set value variable: \"", - TclGetString(valueVarObj), "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't set value variable: \"%s\"", + TclGetString(valueVarObj))); + result = TCL_ERROR; goto abnormalResult; } @@ -3438,7 +3680,7 @@ TclInitDictCmd( { return TclMakeEnsemble(interp, "dict", implementationMap); } - + /* * Local Variables: * mode: c diff --git a/generic/tclEncoding.c b/generic/tclEncoding.c index 0fa6661..7a55724 100644 --- a/generic/tclEncoding.c +++ b/generic/tclEncoding.c @@ -1542,7 +1542,8 @@ OpenEncodingFileChannel( } if ((NULL == chan) && (interp != NULL)) { - Tcl_AppendResult(interp, "unknown encoding \"", name, "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unknown encoding \"%s\"", name)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ENCODING", name, NULL); } Tcl_DecrRefCount(fileNameObj); @@ -1616,7 +1617,8 @@ LoadEncodingFile( break; } if ((encoding == NULL) && (interp != NULL)) { - Tcl_AppendResult(interp, "invalid encoding file \"", name, "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "invalid encoding file \"%s\"", name)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ENCODING", name, NULL); } Tcl_Close(NULL, chan); diff --git a/generic/tclEnsemble.c b/generic/tclEnsemble.c index 754e480..b76c603 100644 --- a/generic/tclEnsemble.c +++ b/generic/tclEnsemble.c @@ -17,6 +17,7 @@ * Declarations for functions local to this file: */ +static inline Tcl_Obj * NewNsObj(Tcl_Namespace *namespacePtr); static inline int EnsembleUnknownCallback(Tcl_Interp *interp, EnsembleConfig *ensemblePtr, int objc, Tcl_Obj *const objv[], Tcl_Obj **prefixObjPtr); @@ -78,6 +79,19 @@ const Tcl_ObjType tclEnsembleCmdType = { NULL /* setFromAnyProc */ }; +static inline Tcl_Obj * +NewNsObj( + Tcl_Namespace *namespacePtr) +{ + register Namespace *nsPtr = (Namespace *) namespacePtr; + + if (namespacePtr == TclGetGlobalNamespace(nsPtr->interp)) { + return Tcl_NewStringObj("::", 2); + } else { + return Tcl_NewStringObj(nsPtr->fullName, -1); + } +} + /* *---------------------------------------------------------------------- * @@ -116,9 +130,10 @@ TclNamespaceEnsembleCmd( if (nsPtr == NULL || nsPtr->flags & NS_DYING) { if (!Tcl_InterpDeleted(interp)) { - Tcl_AppendResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "tried to manipulate ensemble of deleted namespace", - NULL); + -1)); + Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "DEAD", NULL); } return TCL_ERROR; } @@ -235,9 +250,11 @@ TclNamespaceEnsembleCmd( return TCL_ERROR; } if (len < 1) { - Tcl_SetResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "ensemble subcommand implementations " - "must be non-empty lists", TCL_STATIC); + "must be non-empty lists", -1)); + Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", + "EMPTY_TARGET", NULL); Tcl_DictObjDone(&search); if (patchedDict) { Tcl_DecrRefCount(patchedDict); @@ -250,7 +267,7 @@ TclNamespaceEnsembleCmd( cmd = TclGetString(listv[0]); if (!(cmd[0] == ':' && cmd[1] == ':')) { Tcl_Obj *newList = Tcl_NewListObj(len, listv); - Tcl_Obj *newCmd = Tcl_NewStringObj(nsPtr->fullName,-1); + Tcl_Obj *newCmd = NewNsObj((Tcl_Namespace *) nsPtr); if (nsPtr->parentPtr) { Tcl_AppendStringsToObj(newCmd, "::", NULL); @@ -370,8 +387,7 @@ TclNamespaceEnsembleCmd( case CONF_NAMESPACE: namespacePtr = NULL; /* silence gcc 4 warning */ Tcl_GetEnsembleNamespace(NULL, token, &namespacePtr); - Tcl_SetResult(interp, ((Namespace *) namespacePtr)->fullName, - TCL_VOLATILE); + Tcl_SetObjResult(interp, NewNsObj(namespacePtr)); break; case CONF_PREFIX: { int flags = 0; /* silence gcc 4 warning */ @@ -411,9 +427,7 @@ TclNamespaceEnsembleCmd( -1)); namespacePtr = NULL; /* silence gcc 4 warning */ Tcl_GetEnsembleNamespace(NULL, token, &namespacePtr); - Tcl_ListObjAppendElement(NULL, resultObj, - Tcl_NewStringObj(((Namespace *) namespacePtr)->fullName, - -1)); + Tcl_ListObjAppendElement(NULL, resultObj, NewNsObj(namespacePtr)); /* -parameters option */ Tcl_ListObjAppendElement(NULL, resultObj, @@ -515,9 +529,11 @@ TclNamespaceEnsembleCmd( goto freeMapAndError; } if (len < 1) { - Tcl_SetResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "ensemble subcommand implementations " - "must be non-empty lists", TCL_STATIC); + "must be non-empty lists", -1)); + Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", + "EMPTY_TARGET", NULL); Tcl_DictObjDone(&search); if (patchedDict) { Tcl_DecrRefCount(patchedDict); @@ -527,8 +543,7 @@ TclNamespaceEnsembleCmd( cmd = TclGetString(listv[0]); if (!(cmd[0] == ':' && cmd[1] == ':')) { Tcl_Obj *newList = Tcl_DuplicateObj(listObj); - Tcl_Obj *newCmd = - Tcl_NewStringObj(nsPtr->fullName, -1); + Tcl_Obj *newCmd = NewNsObj((Tcl_Namespace*)nsPtr); if (nsPtr->parentPtr) { Tcl_AppendStringsToObj(newCmd, "::", NULL); @@ -554,7 +569,9 @@ TclNamespaceEnsembleCmd( continue; } case CONF_NAMESPACE: - Tcl_AppendResult(interp, "option -namespace is read-only", + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "option -namespace is read-only", -1)); + Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "READ_ONLY", NULL); goto freeMapAndError; case CONF_PREFIX: @@ -629,7 +646,7 @@ Tcl_CreateEnsemble( */ if (!(name[0] == ':' && name[1] == ':')) { - nameObj = Tcl_NewStringObj(nsPtr->fullName, -1); + nameObj = NewNsObj((Tcl_Namespace *) nsPtr); if (nsPtr->parentPtr == NULL) { Tcl_AppendStringsToObj(nameObj, name, NULL); } else { @@ -702,7 +719,9 @@ Tcl_SetEnsembleSubcommandList( Tcl_Obj *oldList; if (cmdPtr->objProc != NsEnsembleImplementationCmd) { - Tcl_AppendResult(interp, "command is not an ensemble", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "command is not an ensemble", -1)); + Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL); return TCL_ERROR; } if (subcmdList != NULL) { @@ -776,7 +795,9 @@ Tcl_SetEnsembleParameterList( int length; if (cmdPtr->objProc != NsEnsembleImplementationCmd) { - Tcl_AppendResult(interp, "command is not an ensemble", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "command is not an ensemble", -1)); + Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL); return TCL_ERROR; } if (paramList == NULL) { @@ -850,7 +871,9 @@ Tcl_SetEnsembleMappingDict( Tcl_Obj *oldDict; if (cmdPtr->objProc != NsEnsembleImplementationCmd) { - Tcl_AppendResult(interp, "command is not an ensemble", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "command is not an ensemble", -1)); + Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL); return TCL_ERROR; } if (mapDict != NULL) { @@ -873,9 +896,11 @@ Tcl_SetEnsembleMappingDict( } bytes = TclGetString(cmdObjPtr); if (bytes[0] != ':' || bytes[1] != ':') { - Tcl_AppendResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "ensemble target is not a fully-qualified command", - NULL); + -1)); + Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", + "UNQUALIFIED_TARGET", NULL); Tcl_DictObjDone(&search); return TCL_ERROR; } @@ -945,7 +970,9 @@ Tcl_SetEnsembleUnknownHandler( Tcl_Obj *oldList; if (cmdPtr->objProc != NsEnsembleImplementationCmd) { - Tcl_AppendResult(interp, "command is not an ensemble", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "command is not an ensemble", -1)); + Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL); return TCL_ERROR; } if (unknownList != NULL) { @@ -1009,7 +1036,9 @@ Tcl_SetEnsembleFlags( int wasCompiled; if (cmdPtr->objProc != NsEnsembleImplementationCmd) { - Tcl_AppendResult(interp, "command is not an ensemble", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "command is not an ensemble", -1)); + Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL); return TCL_ERROR; } @@ -1084,7 +1113,9 @@ Tcl_GetEnsembleSubcommandList( if (cmdPtr->objProc != NsEnsembleImplementationCmd) { if (interp != NULL) { - Tcl_AppendResult(interp, "command is not an ensemble", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "command is not an ensemble", -1)); + Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL); } return TCL_ERROR; } @@ -1124,7 +1155,9 @@ Tcl_GetEnsembleParameterList( if (cmdPtr->objProc != NsEnsembleImplementationCmd) { if (interp != NULL) { - Tcl_AppendResult(interp, "command is not an ensemble", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "command is not an ensemble", -1)); + Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL); } return TCL_ERROR; } @@ -1164,7 +1197,9 @@ Tcl_GetEnsembleMappingDict( if (cmdPtr->objProc != NsEnsembleImplementationCmd) { if (interp != NULL) { - Tcl_AppendResult(interp, "command is not an ensemble", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "command is not an ensemble", -1)); + Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL); } return TCL_ERROR; } @@ -1203,7 +1238,9 @@ Tcl_GetEnsembleUnknownHandler( if (cmdPtr->objProc != NsEnsembleImplementationCmd) { if (interp != NULL) { - Tcl_AppendResult(interp, "command is not an ensemble", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "command is not an ensemble", -1)); + Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL); } return TCL_ERROR; } @@ -1242,7 +1279,9 @@ Tcl_GetEnsembleFlags( if (cmdPtr->objProc != NsEnsembleImplementationCmd) { if (interp != NULL) { - Tcl_AppendResult(interp, "command is not an ensemble", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "command is not an ensemble", -1)); + Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL); } return TCL_ERROR; } @@ -1281,7 +1320,9 @@ Tcl_GetEnsembleNamespace( if (cmdPtr->objProc != NsEnsembleImplementationCmd) { if (interp != NULL) { - Tcl_AppendResult(interp, "command is not an ensemble", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "command is not an ensemble", -1)); + Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "NOT_ENSEMBLE", NULL); } return TCL_ERROR; } @@ -1337,8 +1378,9 @@ Tcl_FindEnsemble( if (cmdPtr == NULL || cmdPtr->objProc != NsEnsembleImplementationCmd){ if (flags & TCL_LEAVE_ERR_MSG) { - Tcl_AppendResult(interp, "\"", TclGetString(cmdNameObj), - "\" is not an ensemble command", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "\"%s\" is not an ensemble command", + TclGetString(cmdNameObj))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ENSEMBLE", TclGetString(cmdNameObj), NULL); } @@ -1591,6 +1633,7 @@ NsEnsembleImplementationCmdNR( * specified but not yet cached command * names. */ int reparseCount = 0; /* Number of reparses. */ + Tcl_Obj *errorObj; /* Used for building error messages. */ /* * Must recheck objc, since numParameters might have changed. Cf. test @@ -1631,8 +1674,9 @@ NsEnsembleImplementationCmdNR( */ if (!Tcl_InterpDeleted(interp)) { - Tcl_AppendResult(interp, - "ensemble activated for deleted namespace", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "ensemble activated for deleted namespace", -1)); + Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "DEAD", NULL); } return TCL_ERROR; } @@ -1880,35 +1924,34 @@ NsEnsembleImplementationCmdNR( */ Tcl_ResetResult(interp); - Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ENSEMBLE", + Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "SUBCOMMAND", TclGetString(objv[1+ensemblePtr->numParameters]), NULL); if (ensemblePtr->subcommandTable.numEntries == 0) { - Tcl_AppendResult(interp, "unknown subcommand \"", + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unknown subcommand \"%s\": namespace %s does not" + " export any commands", TclGetString(objv[1+ensemblePtr->numParameters]), - "\": namespace ", ensemblePtr->nsPtr->fullName, - " does not export any commands", NULL); + ensemblePtr->nsPtr->fullName)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "SUBCOMMAND", TclGetString(objv[1+ensemblePtr->numParameters]), NULL); return TCL_ERROR; } - Tcl_AppendResult(interp, "unknown ", - (ensemblePtr->flags & TCL_ENSEMBLE_PREFIX ? "or ambiguous " : ""), - "subcommand \"", TclGetString(objv[1+ensemblePtr->numParameters]), - "\": must be ", NULL); + errorObj = Tcl_ObjPrintf("unknown%s subcommand \"%s\": must be ", + (ensemblePtr->flags & TCL_ENSEMBLE_PREFIX ? " or ambiguous" : ""), + TclGetString(objv[1+ensemblePtr->numParameters])); if (ensemblePtr->subcommandTable.numEntries == 1) { - Tcl_AppendResult(interp, ensemblePtr->subcommandArrayPtr[0], NULL); + Tcl_AppendToObj(errorObj, ensemblePtr->subcommandArrayPtr[0], -1); } else { int i; for (i=0 ; i<ensemblePtr->subcommandTable.numEntries-1 ; i++) { - Tcl_AppendResult(interp, - ensemblePtr->subcommandArrayPtr[i], ", ", NULL); + Tcl_AppendToObj(errorObj, ensemblePtr->subcommandArrayPtr[i], -1); + Tcl_AppendToObj(errorObj, ", ", 2); } - Tcl_AppendResult(interp, "or ", - ensemblePtr->subcommandArrayPtr[i], NULL); + Tcl_AppendPrintfToObj(errorObj, "or %s", + ensemblePtr->subcommandArrayPtr[i]); } - Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "SUBCOMMAND", - TclGetString(objv[1+ensemblePtr->numParameters]), NULL); + Tcl_SetObjResult(interp, errorObj); return TCL_ERROR; } @@ -2034,7 +2077,6 @@ EnsembleUnknownCallback( { int paramc, i, result, prefixObjc; Tcl_Obj **paramv, *unknownCmd, *ensObj; - char buf[TCL_INTEGER_SPACE]; /* * Create the unknown command callback to determine what to do. @@ -2061,9 +2103,12 @@ EnsembleUnknownCallback( ((Interp *) interp)->evalFlags |= TCL_EVAL_REDIRECT; result = Tcl_EvalObjv(interp, paramc, paramv, 0); if ((result == TCL_OK) && (ensemblePtr->flags & ENSEMBLE_DEAD)) { - Tcl_SetResult(interp, - "unknown subcommand handler deleted its ensemble", - TCL_STATIC); + if (!Tcl_InterpDeleted(interp)) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "unknown subcommand handler deleted its ensemble", -1)); + Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "UNKNOWN_DELETED", + NULL); + } result = TCL_ERROR; } Tcl_Release(ensemblePtr); @@ -2112,26 +2157,26 @@ EnsembleUnknownCallback( if (!Tcl_InterpDeleted(interp)) { if (result != TCL_ERROR) { Tcl_ResetResult(interp); - Tcl_SetResult(interp, - "unknown subcommand handler returned bad code: ", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "unknown subcommand handler returned bad code: ", -1)); switch (result) { case TCL_RETURN: - Tcl_AppendResult(interp, "return", NULL); + Tcl_AppendToObj(Tcl_GetObjResult(interp), "return", -1); break; case TCL_BREAK: - Tcl_AppendResult(interp, "break", NULL); + Tcl_AppendToObj(Tcl_GetObjResult(interp), "break", -1); break; case TCL_CONTINUE: - Tcl_AppendResult(interp, "continue", NULL); + Tcl_AppendToObj(Tcl_GetObjResult(interp), "continue", -1); break; default: - sprintf(buf, "%d", result); - Tcl_AppendResult(interp, buf, NULL); + Tcl_AppendPrintfToObj(Tcl_GetObjResult(interp), "%d", result); } Tcl_AddErrorInfo(interp, "\n result of " "ensemble unknown subcommand handler: "); Tcl_AddErrorInfo(interp, TclGetString(unknownCmd)); + Tcl_SetErrorCode(interp, "TCL", "ENSEMBLE", "UNKNOWN_RESULT", + NULL); } else { Tcl_AddErrorInfo(interp, "\n (ensemble unknown subcommand handler)"); @@ -2392,7 +2437,7 @@ BuildEnsembleConfig( * the programmer's responsibility (or [::unknown] of course). */ - cmdObj = Tcl_NewStringObj(ensemblePtr->nsPtr->fullName, -1); + cmdObj = NewNsObj((Tcl_Namespace *) ensemblePtr->nsPtr); if (ensemblePtr->nsPtr->parentPtr != NULL) { Tcl_AppendStringsToObj(cmdObj, "::", name, NULL); } else { diff --git a/generic/tclEvent.c b/generic/tclEvent.c index e65862c..0b585b6 100644 --- a/generic/tclEvent.c +++ b/generic/tclEvent.c @@ -1416,7 +1416,7 @@ Tcl_VwaitObjCmd( } if (Tcl_LimitExceeded(interp)) { Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "limit exceeded", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj("limit exceeded", -1)); break; } } @@ -1426,8 +1426,9 @@ Tcl_VwaitObjCmd( if (!foundEvent) { Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "can't wait for variable \"", nameString, - "\": would wait forever", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't wait for variable \"%s\": would wait forever", + nameString)); Tcl_SetErrorCode(interp, "TCL", "EVENT", "NO_SOURCES", NULL); return TCL_ERROR; } @@ -1519,7 +1520,7 @@ Tcl_UpdateObjCmd( } if (Tcl_LimitExceeded(interp)) { Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "limit exceeded", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj("limit exceeded", -1)); return TCL_ERROR; } } diff --git a/generic/tclExecute.c b/generic/tclExecute.c index e402634..cf8f9e7 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -17,6 +17,7 @@ #include "tclInt.h" #include "tclCompile.h" +#include "tclOOInt.h" #include "tommath.h" #include <math.h> @@ -2331,6 +2332,101 @@ TEBCresume( cleanup = 1; goto processExceptionReturn; + case INST_YIELD: { + CoroutineData *corPtr = iPtr->execEnvPtr->corPtr; + + TRACE(("%.30s => ", O2S(OBJ_AT_TOS))); + if (!corPtr) { + TRACE_APPEND(("ERROR: yield outside coroutine\n")); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "yield can only be called in a coroutine", -1)); + Tcl_SetErrorCode(interp, "TCL", "COROUTINE", "ILLEGAL_YIELD", + NULL); + goto gotError; + } + +#ifdef TCL_COMPILE_DEBUG + TRACE_WITH_OBJ(("yield, result="), iPtr->objResultPtr); + if (traceInstructions) { + fprintf(stdout, "\n"); + } +#endif + /* TIP #280: Record the last piece of info needed by + * 'TclGetSrcInfoForPc', and push the frame. + */ + + bcFramePtr->data.tebc.pc = (char *) pc; + iPtr->cmdFramePtr = bcFramePtr; + + if (iPtr->flags & INTERP_DEBUG_FRAME) { + TclArgumentBCEnter((Tcl_Interp *) iPtr, objv, objc, + codePtr, bcFramePtr, pc - codePtr->codeStart); + } + + pc++; + cleanup = 1; + TEBC_YIELD(); + + Tcl_SetObjResult(interp, OBJ_AT_TOS); + TclNRAddCallback(interp, TclNRCoroutineActivateCallback, corPtr, + INT2PTR(0), NULL, NULL); + + return TCL_OK; + } + + case INST_TAILCALL: { + Tcl_Obj *listPtr, *nsObjPtr; + NRE_callback *tailcallPtr; + + opnd = TclGetUInt1AtPtr(pc+1); + + if (!(iPtr->varFramePtr->isProcCallFrame & 1)) { + TRACE(("%d => ERROR: tailcall in non-proc context\n", opnd)); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "tailcall can only be called from a proc or lambda", -1)); + Tcl_SetErrorCode(interp, "TCL", "TAILCALL", "ILLEGAL", NULL); + goto gotError; + } + +#ifdef TCL_COMPILE_DEBUG + { + register int i; + + TRACE(("%d [", opnd)); + for (i=opnd-1 ; i>=0 ; i--) { + TRACE_APPEND(("\"%.30s\"", O2S(OBJ_AT_DEPTH(i)))); + if (i > 0) { + TRACE_APPEND((" ")); + } + } + TRACE_APPEND(("] => RETURN...")); + } +#endif + + /* + * Push the evaluation of the called command into the NR callback + * stack. + */ + + listPtr = Tcl_NewListObj(opnd, &OBJ_AT_DEPTH(opnd-1)); + nsObjPtr = Tcl_NewStringObj(iPtr->varFramePtr->nsPtr->fullName, -1); + Tcl_IncrRefCount(listPtr); + Tcl_IncrRefCount(nsObjPtr); + TclNRAddCallback(interp, TclNRTailcallEval, listPtr, nsObjPtr, + NULL, NULL); + + /* + * Unstitch ourselves and do a [return]. + */ + + tailcallPtr = TOP_CB(interp); + TOP_CB(interp) = tailcallPtr->nextPtr; + iPtr->varFramePtr->tailcallPtr = tailcallPtr; + result = TCL_RETURN; + cleanup = opnd; + goto processExceptionReturn; + } + case INST_DONE: if (tosPtr > initTosPtr) { /* @@ -3785,6 +3881,104 @@ TEBCresume( /* * End of INST_UNSET instructions. * ----------------------------------------------------------------- + * Start of INST_ARRAY instructions. + */ + + case INST_ARRAY_EXISTS_IMM: + opnd = TclGetUInt4AtPtr(pc+1); + pcAdjustment = 5; + cleanup = 0; + part1Ptr = NULL; + arrayPtr = NULL; + TRACE(("%u => ", opnd)); + varPtr = LOCAL(opnd); + while (TclIsVarLink(varPtr)) { + varPtr = varPtr->value.linkPtr; + } + goto doArrayExists; + case INST_ARRAY_EXISTS_STK: + opnd = -1; + pcAdjustment = 1; + cleanup = 1; + part1Ptr = OBJ_AT_TOS; + TRACE(("\"%.30s\" => ", O2S(part1Ptr))); + varPtr = TclObjLookupVarEx(interp, part1Ptr, NULL, 0, NULL, + /*createPart1*/0, /*createPart2*/0, &arrayPtr); + doArrayExists: + if (varPtr && (varPtr->flags & VAR_TRACED_ARRAY) + && (TclIsVarArray(varPtr) || TclIsVarUndefined(varPtr))) { + DECACHE_STACK_INFO(); + result = TclObjCallVarTraces(iPtr, arrayPtr, varPtr, part1Ptr, + NULL, (TCL_LEAVE_ERR_MSG|TCL_NAMESPACE_ONLY| + TCL_GLOBAL_ONLY|TCL_TRACE_ARRAY), 1, opnd); + CACHE_STACK_INFO(); + if (result == TCL_ERROR) { + TRACE_APPEND(("ERROR: %.30s\n", + O2S(Tcl_GetObjResult(interp)))); + goto gotError; + } + } + if (varPtr && TclIsVarArray(varPtr) && !TclIsVarUndefined(varPtr)) { + objResultPtr = TCONST(1); + } else { + objResultPtr = TCONST(0); + } + TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); + NEXT_INST_V(pcAdjustment, cleanup, 1); + + case INST_ARRAY_MAKE_IMM: + opnd = TclGetUInt4AtPtr(pc+1); + pcAdjustment = 5; + cleanup = 0; + part1Ptr = NULL; + arrayPtr = NULL; + TRACE(("%u => ", opnd)); + varPtr = LOCAL(opnd); + while (TclIsVarLink(varPtr)) { + varPtr = varPtr->value.linkPtr; + } + goto doArrayMake; + case INST_ARRAY_MAKE_STK: + opnd = -1; + pcAdjustment = 1; + cleanup = 1; + part1Ptr = OBJ_AT_TOS; + TRACE(("\"%.30s\" => ", O2S(part1Ptr))); + varPtr = TclObjLookupVarEx(interp, part1Ptr, NULL, TCL_LEAVE_ERR_MSG, + "set", /*createPart1*/1, /*createPart2*/0, &arrayPtr); + if (varPtr == NULL) { + TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp)))); + goto gotError; + } + doArrayMake: + if (varPtr && !TclIsVarArray(varPtr)) { + if (TclIsVarArrayElement(varPtr) || !TclIsVarUndefined(varPtr)) { + /* + * Either an array element, or a scalar: lose! + */ + + TclObjVarErrMsg(interp, part1Ptr, NULL, "array set", + "variable isn't array", opnd); + Tcl_SetErrorCode(interp, "TCL", "WRITE", "ARRAY", NULL); + TRACE_APPEND(("ERROR: bad array ref: %.30s\n", + O2S(Tcl_GetObjResult(interp)))); + goto gotError; + } + TclSetVarArray(varPtr); + varPtr->value.tablePtr = ckalloc(sizeof(TclVarHashTable)); + TclInitVarHashTable(varPtr->value.tablePtr, + TclGetVarNsPtr(varPtr)); +#ifdef TCL_COMPILE_DEBUG + TRACE_APPEND(("done\n")); + } else { + TRACE_APPEND(("nothing to do\n")); +#endif + } + NEXT_INST_V(pcAdjustment, cleanup, 0); + + /* + * End of INST_ARRAY instructions. + * ----------------------------------------------------------------- * Start of variable linking instructions. */ @@ -4045,6 +4239,136 @@ TEBCresume( /* * ----------------------------------------------------------------- + * Start of general introspector instructions. + */ + + case INST_NS_CURRENT: { + Namespace *currNsPtr = (Namespace *) TclGetCurrentNamespace(interp); + + if (currNsPtr == (Namespace *) TclGetGlobalNamespace(interp)) { + TclNewLiteralStringObj(objResultPtr, "::"); + } else { + TclNewStringObj(objResultPtr, currNsPtr->fullName, + strlen(currNsPtr->fullName)); + } + TRACE_WITH_OBJ(("=> "), objResultPtr); + NEXT_INST_F(1, 0, 1); + } + case INST_COROUTINE_NAME: { + CoroutineData *corPtr = iPtr->execEnvPtr->corPtr; + + TclNewObj(objResultPtr); + if (corPtr && !(corPtr->cmdPtr->flags & CMD_IS_DELETED)) { + Tcl_GetCommandFullName(interp, (Tcl_Command) corPtr->cmdPtr, + objResultPtr); + } + TRACE_WITH_OBJ(("=> "), objResultPtr); + NEXT_INST_F(1, 0, 1); + } + case INST_INFO_LEVEL_NUM: + TclNewIntObj(objResultPtr, iPtr->varFramePtr->level); + TRACE_WITH_OBJ(("=> "), objResultPtr); + NEXT_INST_F(1, 0, 1); + case INST_INFO_LEVEL_ARGS: { + int level; + register CallFrame *framePtr = iPtr->varFramePtr; + register CallFrame *rootFramePtr = iPtr->rootFramePtr; + + valuePtr = OBJ_AT_TOS; + if (TclGetIntFromObj(interp, valuePtr, &level) != TCL_OK) { + TRACE_WITH_OBJ(("%.30s => ERROR: ", O2S(valuePtr)), + Tcl_GetObjResult(interp)); + goto gotError; + } + TRACE(("%d => ", level)); + if (level <= 0) { + level += framePtr->level; + } + for (; (framePtr->level!=level) && (framePtr!=rootFramePtr) ; + framePtr = framePtr->callerVarPtr) { + /* Empty loop body */ + } + if (framePtr == rootFramePtr) { + Tcl_AppendResult(interp, "bad level \"", TclGetString(valuePtr), + "\"", NULL); + TRACE_APPEND(("ERROR: bad level\n")); + Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "STACK_LEVEL", + TclGetString(valuePtr), NULL); + goto gotError; + } + objResultPtr = Tcl_NewListObj(framePtr->objc, framePtr->objv); + TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); + NEXT_INST_F(1, 1, 1); + } + case INST_RESOLVE_COMMAND: { + Tcl_Command cmd = Tcl_GetCommandFromObj(interp, OBJ_AT_TOS); + + TclNewObj(objResultPtr); + if (cmd != NULL) { + Tcl_GetCommandFullName(interp, cmd, objResultPtr); + } + TRACE_WITH_OBJ(("\"%.20s\" => ", O2S(OBJ_AT_TOS)), objResultPtr); + NEXT_INST_F(1, 1, 1); + } + case INST_TCLOO_SELF: { + CallFrame *framePtr = iPtr->varFramePtr; + CallContext *contextPtr; + + if (framePtr == NULL || + !(framePtr->isProcCallFrame & FRAME_IS_METHOD)) { + TRACE(("=> ERROR: no TclOO call context\n")); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "self may only be called from inside a method", + -1)); + Tcl_SetErrorCode(interp, "TCL", "OO", "CONTEXT_REQUIRED", NULL); + goto gotError; + } + contextPtr = framePtr->clientData; + + /* + * Call out to get the name; it's expensive to compute but cached. + */ + + objResultPtr = TclOOObjectName(interp, contextPtr->oPtr); + TRACE_WITH_OBJ(("=> "), objResultPtr); + NEXT_INST_F(1, 0, 1); + } + { + Object *oPtr; + + case INST_TCLOO_IS_OBJECT: + oPtr = (Object *) Tcl_GetObjectFromObj(interp, OBJ_AT_TOS); + objResultPtr = TCONST(oPtr != NULL ? 1 : 0); + TRACE_WITH_OBJ(("%.30s => ", O2S(OBJ_AT_TOS)), objResultPtr); + NEXT_INST_F(1, 1, 1); + case INST_TCLOO_CLASS: + oPtr = (Object *) Tcl_GetObjectFromObj(interp, OBJ_AT_TOS); + if (oPtr == NULL) { + TRACE(("%.30s => ERROR: not object\n", O2S(OBJ_AT_TOS))); + goto gotError; + } + objResultPtr = TclOOObjectName(interp, oPtr->selfCls->thisPtr); + TRACE_WITH_OBJ(("%.30s => ", O2S(OBJ_AT_TOS)), objResultPtr); + NEXT_INST_F(1, 1, 1); + case INST_TCLOO_NS: + oPtr = (Object *) Tcl_GetObjectFromObj(interp, OBJ_AT_TOS); + if (oPtr == NULL) { + TRACE(("%.30s => ERROR: not object\n", O2S(OBJ_AT_TOS))); + goto gotError; + } + + /* + * TclOO objects *never* have the global namespace as their NS. + */ + + TclNewStringObj(objResultPtr, oPtr->namespacePtr->fullName, + strlen(oPtr->namespacePtr->fullName)); + TRACE_WITH_OBJ(("%.30s => ", O2S(OBJ_AT_TOS)), objResultPtr); + NEXT_INST_F(1, 1, 1); + } + + /* + * ----------------------------------------------------------------- * Start of INST_LIST and related instructions. */ @@ -4592,6 +4916,179 @@ TEBCresume( O2S(objResultPtr))); NEXT_INST_F(1, 2, 1); + case INST_STR_RANGE: + TRACE(("\"%.20s\" %s %s =>", + O2S(OBJ_AT_DEPTH(2)), O2S(OBJ_UNDER_TOS), O2S(OBJ_AT_TOS))); + length = Tcl_GetCharLength(OBJ_AT_DEPTH(2)) - 1; + if (TclGetIntForIndexM(interp, OBJ_UNDER_TOS, length, + &fromIdx) != TCL_OK + || TclGetIntForIndexM(interp, OBJ_AT_TOS, length, + &toIdx) != TCL_OK) { + goto gotError; + } + + if (fromIdx < 0) { + fromIdx = 0; + } + if (toIdx >= length) { + toIdx = length; + } + if (toIdx >= fromIdx) { + objResultPtr = Tcl_GetRange(OBJ_AT_DEPTH(2), fromIdx, toIdx); + } else { + TclNewObj(objResultPtr); + } + TRACE_APPEND(("\"%.30s\"\n", O2S(objResultPtr))); + NEXT_INST_V(1, 3, 1); + + case INST_STR_RANGE_IMM: + valuePtr = OBJ_AT_TOS; + fromIdx = TclGetInt4AtPtr(pc+1); + toIdx = TclGetInt4AtPtr(pc+5); + length = Tcl_GetCharLength(valuePtr); + TRACE(("\"%.20s\" %d %d => ", O2S(valuePtr), fromIdx, toIdx)); + + /* + * Adjust indices for end-based indexing. + */ + + if (fromIdx < -1) { + fromIdx += 1 + length; + if (fromIdx < 0) { + fromIdx = 0; + } + } else if (fromIdx >= length) { + fromIdx = length; + } + if (toIdx < -1) { + toIdx += 1 + length; + if (toIdx < 0) { + toIdx = 0; + } + } else if (toIdx >= length) { + toIdx = length - 1; + } + + /* + * Check if we can do a sane substring. + */ + + if (fromIdx <= toIdx) { + objResultPtr = Tcl_GetRange(valuePtr, fromIdx, toIdx); + } else { + TclNewObj(objResultPtr); + } + TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); + NEXT_INST_F(9, 1, 1); + + { + Tcl_UniChar *ustring1, *ustring2, *ustring3, *end, *p; + int length3; + Tcl_Obj *value3Ptr; + + case INST_STR_MAP: + valuePtr = OBJ_AT_TOS; /* "Main" string. */ + value3Ptr = OBJ_UNDER_TOS; /* "Target" string. */ + value2Ptr = OBJ_AT_DEPTH(2); /* "Source" string. */ + if (value3Ptr == value2Ptr) { + objResultPtr = valuePtr; + NEXT_INST_V(1, 3, 1); + } else if (valuePtr == value2Ptr) { + objResultPtr = value3Ptr; + NEXT_INST_V(1, 3, 1); + } + ustring1 = Tcl_GetUnicodeFromObj(valuePtr, &length); + if (length == 0) { + objResultPtr = valuePtr; + NEXT_INST_V(1, 3, 1); + } + ustring2 = Tcl_GetUnicodeFromObj(value2Ptr, &length2); + if (length2 > length || length2 == 0) { + objResultPtr = valuePtr; + NEXT_INST_V(1, 3, 1); + } else if (length2 == length) { + if (memcmp(ustring1, ustring2, sizeof(Tcl_UniChar) * length)) { + objResultPtr = valuePtr; + } else { + objResultPtr = value3Ptr; + } + NEXT_INST_V(1, 3, 1); + } + ustring3 = Tcl_GetUnicodeFromObj(value3Ptr, &length3); + + objResultPtr = Tcl_NewUnicodeObj(ustring1, 0); + p = ustring1; + end = ustring1 + length; + for (; ustring1 < end; ustring1++) { + if ((*ustring1 == *ustring2) && (length2==1 || + memcmp(ustring1, ustring2, sizeof(Tcl_UniChar) * length2) + == 0)) { + if (p != ustring1) { + Tcl_AppendUnicodeToObj(objResultPtr, p, ustring1-p); + p = ustring1 + length2; + } else { + p += length2; + } + ustring1 = p - 1; + + Tcl_AppendUnicodeToObj(objResultPtr, ustring3, length3); + } + } + if (p != ustring1) { + /* + * Put the rest of the unmapped chars onto result. + */ + + Tcl_AppendUnicodeToObj(objResultPtr, p, ustring1 - p); + } + TRACE_WITH_OBJ(("%.20s %.20s %.20s => ", + O2S(value2Ptr), O2S(value3Ptr), O2S(valuePtr)), objResultPtr); + NEXT_INST_V(1, 3, 1); + + case INST_STR_FIND: + ustring1 = Tcl_GetUnicodeFromObj(OBJ_AT_TOS, &length); /* Haystack */ + ustring2 = Tcl_GetUnicodeFromObj(OBJ_UNDER_TOS, &length2);/* Needle */ + + match = -1; + if (length2 > 0 && length2 <= length) { + end = ustring1 + length - length2 + 1; + for (p=ustring1 ; p<end ; p++) { + if ((*p == *ustring2) && + memcmp(ustring2,p,sizeof(Tcl_UniChar)*length2) == 0) { + match = p - ustring1; + break; + } + } + } + + TRACE(("%.20s %.20s => %d\n", + O2S(OBJ_UNDER_TOS), O2S(OBJ_AT_TOS), match)); + + TclNewIntObj(objResultPtr, match); + NEXT_INST_F(1, 2, 1); + + case INST_STR_FIND_LAST: + ustring1 = Tcl_GetUnicodeFromObj(OBJ_AT_TOS, &length); /* Haystack */ + ustring2 = Tcl_GetUnicodeFromObj(OBJ_UNDER_TOS, &length2);/* Needle */ + + match = -1; + if (length2 > 0 && length2 <= length) { + for (p=ustring1+length-length2 ; p>=ustring1 ; p--) { + if ((*p == *ustring2) && + memcmp(ustring2,p,sizeof(Tcl_UniChar)*length2) == 0) { + match = p - ustring1; + break; + } + } + } + + TRACE(("%.20s %.20s => %d\n", + O2S(OBJ_UNDER_TOS), O2S(OBJ_AT_TOS), match)); + + TclNewIntObj(objResultPtr, match); + NEXT_INST_F(1, 2, 1); + } + case INST_STR_MATCH: nocase = TclGetInt1AtPtr(pc+1); valuePtr = OBJ_AT_TOS; /* String */ @@ -4896,8 +5393,8 @@ TEBCresume( case INST_RSHIFT: if (l2 < 0) { - Tcl_SetResult(interp, "negative shift argument", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "negative shift argument", -1)); #if 0 DECACHE_STACK_INFO(); Tcl_SetErrorCode(interp, "ARITH", "DOMAIN", @@ -4944,8 +5441,8 @@ TEBCresume( case INST_LSHIFT: if (l2 < 0) { - Tcl_SetResult(interp, "negative shift argument", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "negative shift argument", -1)); #if 0 DECACHE_STACK_INFO(); Tcl_SetErrorCode(interp, "ARITH", "DOMAIN", @@ -4967,9 +5464,8 @@ TEBCresume( * good place to draw the line. */ - Tcl_SetResult(interp, - "integer value too large to represent", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "integer value too large to represent", -1)); #if 0 DECACHE_STACK_INFO(); Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", @@ -5649,41 +6145,73 @@ TEBCresume( Tcl_DictSearch *searchPtr; DictUpdateInfo *duiPtr; + case INST_DICT_VERIFY: + dictPtr = OBJ_AT_TOS; + TRACE(("=> ")); + if (Tcl_DictObjSize(interp, dictPtr, &done) != TCL_OK) { + TRACE_APPEND(("ERROR verifying dictionary nature of \"%s\": %s\n", + O2S(OBJ_AT_DEPTH(opnd)), O2S(Tcl_GetObjResult(interp)))); + goto gotError; + } + TRACE_APPEND(("OK\n")); + NEXT_INST_F(1, 1, 0); + case INST_DICT_GET: + case INST_DICT_EXISTS: { + register Tcl_Interp *interp2 = interp; + opnd = TclGetUInt4AtPtr(pc+1); TRACE(("%u => ", opnd)); dictPtr = OBJ_AT_DEPTH(opnd); + if (*pc == INST_DICT_EXISTS) { + interp2 = NULL; + } if (opnd > 1) { - dictPtr = TclTraceDictPath(interp, dictPtr, opnd-1, + dictPtr = TclTraceDictPath(interp2, dictPtr, opnd-1, &OBJ_AT_DEPTH(opnd-1), DICT_PATH_READ); if (dictPtr == NULL) { + if (*pc == INST_DICT_EXISTS) { + goto dictNotExists; + } TRACE_WITH_OBJ(( - "%u => ERROR tracing dictionary path into \"%s\": ", - opnd, O2S(OBJ_AT_DEPTH(opnd))), + "ERROR tracing dictionary path into \"%s\": ", + O2S(OBJ_AT_DEPTH(opnd))), Tcl_GetObjResult(interp)); goto gotError; } } - if (Tcl_DictObjGet(interp, dictPtr, OBJ_AT_TOS, + if (Tcl_DictObjGet(interp2, dictPtr, OBJ_AT_TOS, &objResultPtr) == TCL_OK) { + if (*pc == INST_DICT_EXISTS) { + objResultPtr = TCONST(objResultPtr ? 1 : 0); + TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); + NEXT_INST_V(5, opnd+1, 1); + } if (objResultPtr) { TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); NEXT_INST_V(5, opnd+1, 1); } DECACHE_STACK_INFO(); - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "key \"", TclGetString(OBJ_AT_TOS), - "\" not known in dictionary", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "key \"%s\" not known in dictionary", + TclGetString(OBJ_AT_TOS))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "DICT", TclGetString(OBJ_AT_TOS), NULL); CACHE_STACK_INFO(); TRACE_WITH_OBJ(("%u => ERROR ", opnd), Tcl_GetObjResult(interp)); } else { + if (*pc == INST_DICT_EXISTS) { + dictNotExists: + objResultPtr = TCONST(0); + TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); + NEXT_INST_V(5, opnd+1, 1); + } TRACE_WITH_OBJ(( "%u => ERROR reading leaf dictionary key \"%s\": ", opnd, O2S(dictPtr)), Tcl_GetObjResult(interp)); } goto gotError; + } case INST_DICT_SET: case INST_DICT_UNSET: @@ -6304,7 +6832,7 @@ TEBCresume( divideByZero: DECACHE_STACK_INFO(); - Tcl_SetResult(interp, "divide by zero", TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj("divide by zero", -1)); Tcl_SetErrorCode(interp, "ARITH", "DIVZERO", "divide by zero", NULL); CACHE_STACK_INFO(); goto gotError; @@ -6316,8 +6844,8 @@ TEBCresume( exponOfZero: DECACHE_STACK_INFO(); - Tcl_SetResult(interp, "exponentiation of zero by negative power", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "exponentiation of zero by negative power", -1)); Tcl_SetErrorCode(interp, "ARITH", "DOMAIN", "exponentiation of zero by negative power", NULL); CACHE_STACK_INFO(); @@ -6693,7 +7221,8 @@ ExecuteExtendedBinaryMathOp( invalid = 0; } if (invalid) { - Tcl_SetResult(interp, "negative shift argument", TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "negative shift argument", -1)); return GENERAL_ARITHMETIC_ERROR; } @@ -6723,8 +7252,8 @@ ExecuteExtendedBinaryMathOp( * place to draw the line. */ - Tcl_SetResult(interp, "integer value too large to represent", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "integer value too large to represent", -1)); return GENERAL_ARITHMETIC_ERROR; } shift = (int)(*((const long *)ptr2)); @@ -7125,7 +7654,8 @@ ExecuteExtendedBinaryMathOp( */ if (type2 != TCL_NUMBER_LONG) { - Tcl_SetResult(interp, "exponent too large", TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "exponent too large", -1)); return GENERAL_ARITHMETIC_ERROR; } @@ -7363,7 +7893,8 @@ ExecuteExtendedBinaryMathOp( Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2); if (big2.used > 1) { mp_clear(&big2); - Tcl_SetResult(interp, "exponent too large", TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "exponent too large", -1)); return GENERAL_ARITHMETIC_ERROR; } Tcl_TakeBignumFromObj(NULL, valuePtr, &big1); diff --git a/generic/tclFCmd.c b/generic/tclFCmd.c index a868fe3..33c1496 100644 --- a/generic/tclFCmd.c +++ b/generic/tclFCmd.c @@ -10,11 +10,6 @@ * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ -#ifndef _WIN64 -/* See [Bug 2935503]: file mtime sets wrong time */ -# define _USE_32BIT_TIME_T -#endif - #include "tclInt.h" #include "tclFileSystem.h" @@ -152,9 +147,9 @@ FileCopyRename( if ((objc - i) > 2) { errno = ENOTDIR; Tcl_PosixError(interp); - Tcl_AppendResult(interp, "error ", - (copyFlag ? "copying" : "renaming"), ": target \"", - TclGetString(target), "\" is not a directory", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error %s: target \"%s\" is not a directory", + (copyFlag?"copying":"renaming"), TclGetString(target))); result = TCL_ERROR; } else { /* @@ -304,8 +299,9 @@ TclFileMakeDirsCmd( done: if (errfile != NULL) { - Tcl_AppendResult(interp, "can't create directory \"", - TclGetString(errfile), "\": ", Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't create directory \"%s\": %s", + TclGetString(errfile), Tcl_PosixError(interp))); result = TCL_ERROR; } if (split != NULL) { @@ -384,9 +380,9 @@ TclFileDeleteCmd( result = Tcl_FSRemoveDirectory(objv[i], force, &errorBuffer); if (result != TCL_OK) { if ((force == 0) && (errno == EEXIST)) { - Tcl_AppendResult(interp, "error deleting \"", - TclGetString(objv[i]), "\": directory not empty", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error deleting \"%s\": directory not empty", + TclGetString(objv[i]))); Tcl_PosixError(interp); goto done; } @@ -426,12 +422,13 @@ TclFileDeleteCmd( * We try to accomodate poor error results from our Tcl_FS calls. */ - Tcl_AppendResult(interp, "error deleting unknown file: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error deleting unknown file: %s", + Tcl_PosixError(interp))); } else { - Tcl_AppendResult(interp, "error deleting \"", - TclGetString(errfile), "\": ", Tcl_PosixError(interp), - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error deleting \"%s\": %s", + TclGetString(errfile), Tcl_PosixError(interp))); } } @@ -540,17 +537,17 @@ CopyRenameOneFile( if (S_ISDIR(sourceStatBuf.st_mode) && !S_ISDIR(targetStatBuf.st_mode)) { errno = EISDIR; - Tcl_AppendResult(interp, "can't overwrite file \"", - TclGetString(target), "\" with directory \"", - TclGetString(source), "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't overwrite file \"%s\" with directory \"%s\"", + TclGetString(target), TclGetString(source))); goto done; } if (!S_ISDIR(sourceStatBuf.st_mode) && S_ISDIR(targetStatBuf.st_mode)) { errno = EISDIR; - Tcl_AppendResult(interp, "can't overwrite directory \"", - TclGetString(target), "\" with file \"", - TclGetString(source), "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't overwrite directory \"%s\" with file \"%s\"", + TclGetString(target), TclGetString(source))); goto done; } @@ -581,10 +578,10 @@ CopyRenameOneFile( } if (errno == EINVAL) { - Tcl_AppendResult(interp, "error renaming \"", - TclGetString(source), "\" to \"", TclGetString(target), - "\": trying to rename a volume or " - "move a directory into itself", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error renaming \"%s\" to \"%s\": trying to rename a" + " volume or move a directory into itself", + TclGetString(source), TclGetString(target))); goto done; } else if (errno != EXDEV) { errfile = target; @@ -628,8 +625,9 @@ CopyRenameOneFile( * Actual file doesn't exist. */ - Tcl_AppendResult(interp, "error copying \"", TclGetString(source), - "\": the target of this link doesn't exist", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error copying \"%s\": the target of this link doesn't" + " exist", TclGetString(source))); goto done; } else { int counter = 0; @@ -764,23 +762,27 @@ CopyRenameOneFile( } } if (result != TCL_OK) { - Tcl_AppendResult(interp, "can't unlink \"", TclGetString(errfile), - "\": ", Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf("can't unlink \"%s\": %s", + TclGetString(errfile), Tcl_PosixError(interp))); errfile = NULL; } } done: if (errfile != NULL) { - Tcl_AppendResult(interp, "error ", (copyFlag ? "copying" : "renaming"), - " \"", TclGetString(source), NULL); + Tcl_Obj *errorMsg = Tcl_ObjPrintf("error %s \"%s\"", + (copyFlag ? "copying" : "renaming"), TclGetString(source)); + if (errfile != source) { - Tcl_AppendResult(interp, "\" to \"", TclGetString(target), NULL); + Tcl_AppendPrintfToObj(errorMsg, " to \"%s\"", + TclGetString(target)); if (errfile != target) { - Tcl_AppendResult(interp, "\": \"", TclGetString(errfile),NULL); + Tcl_AppendPrintfToObj(errorMsg, ": \"%s\"", + TclGetString(errfile)); } } - Tcl_AppendResult(interp, "\": ", Tcl_PosixError(interp), NULL); + Tcl_AppendPrintfToObj(errorMsg, ": %s", Tcl_PosixError(interp)); + Tcl_SetObjResult(interp, errorMsg); } if (errorBuffer != NULL) { Tcl_DecrRefCount(errorBuffer); @@ -983,9 +985,10 @@ TclFileAttrsCmd( * There was an error, probably that the filePtr is not * accepted by any filesystem */ - Tcl_AppendResult(interp, "could not read \"", - TclGetString(filePtr), "\": ", Tcl_PosixError(interp), - NULL); + + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read \"%s\": %s", + TclGetString(filePtr), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -1071,9 +1074,9 @@ TclFileAttrsCmd( Tcl_Obj *objPtr = NULL; if (numObjStrings == 0) { - Tcl_AppendResult(interp, "bad option \"", TclGetString(objv[0]), - "\", there are no file attributes in this filesystem.", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad option \"%s\", there are no file attributes in this" + " filesystem", TclGetString(objv[0]))); Tcl_SetErrorCode(interp, "TCL","OPERATION","FATTR","NONE", NULL); goto end; } @@ -1098,9 +1101,9 @@ TclFileAttrsCmd( int i, index; if (numObjStrings == 0) { - Tcl_AppendResult(interp, "bad option \"", TclGetString(objv[0]), - "\", there are no file attributes in this filesystem.", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad option \"%s\", there are no file attributes in this" + " filesystem", TclGetString(objv[0]))); Tcl_SetErrorCode(interp, "TCL","OPERATION","FATTR","NONE", NULL); goto end; } @@ -1114,8 +1117,8 @@ TclFileAttrsCmd( TclFreeIntRep(objv[i]); } if (i + 1 == objc) { - Tcl_AppendResult(interp, "value for \"", - TclGetString(objv[i]), "\" missing", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "value for \"%s\" missing", TclGetString(objv[i]))); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FATTR", "NOVALUE", NULL); goto end; @@ -1224,9 +1227,9 @@ TclFileLinkCmd( */ if (errno == EEXIST) { - Tcl_AppendResult(interp, "could not create new link \"", - TclGetString(objv[index]), - "\": that path already exists", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not create new link \"%s\": that path already" + " exists", TclGetString(objv[index]))); Tcl_PosixError(interp); } else if (errno == ENOENT) { /* @@ -1244,23 +1247,23 @@ TclFileLinkCmd( access = Tcl_FSAccess(dirPtr, F_OK); Tcl_DecrRefCount(dirPtr); if (access != 0) { - Tcl_AppendResult(interp, "could not create new link \"", - TclGetString(objv[index]), - "\": no such file or directory", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not create new link \"%s\": no such file" + " or directory", TclGetString(objv[index]))); Tcl_PosixError(interp); } else { - Tcl_AppendResult(interp, "could not create new link \"", - TclGetString(objv[index]), "\": target \"", - TclGetString(objv[index+1]), "\" doesn't exist", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not create new link \"%s\": target \"%s\" " + "doesn't exist", TclGetString(objv[index]), + TclGetString(objv[index+1]))); errno = ENOENT; Tcl_PosixError(interp); } } else { - Tcl_AppendResult(interp, "could not create new link \"", - TclGetString(objv[index]), "\" pointing to \"", - TclGetString(objv[index+1]), "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not create new link \"%s\" pointing to \"%s\": %s", + TclGetString(objv[index]), + TclGetString(objv[index+1]), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -1275,9 +1278,9 @@ TclFileLinkCmd( contents = Tcl_FSLink(objv[index], NULL, 0); if (contents == NULL) { - Tcl_AppendResult(interp, "could not read link \"", - TclGetString(objv[index]), "\": ", Tcl_PosixError(interp), - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read link \"%s\": %s", + TclGetString(objv[index]), Tcl_PosixError(interp))); return TCL_ERROR; } } @@ -1332,8 +1335,9 @@ TclFileReadLinkCmd( contents = Tcl_FSLink(objv[1], NULL, 0); if (contents == NULL) { - Tcl_AppendResult(interp, "could not readlink \"", - TclGetString(objv[1]), "\": ", Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read link \"%s\": %s", + TclGetString(objv[1]), Tcl_PosixError(interp))); return TCL_ERROR; } Tcl_SetObjResult(interp, contents); @@ -1487,8 +1491,8 @@ TclFileTemporaryCmd( if (nameVarObj) { TclDecrRefCount(nameObj); } - Tcl_AppendResult(interp, "can't create temporary file: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't create temporary file: %s", Tcl_PosixError(interp))); return TCL_ERROR; } Tcl_RegisterChannel(interp, chan); @@ -1499,7 +1503,7 @@ TclFileTemporaryCmd( return TCL_ERROR; } } - Tcl_AppendResult(interp, Tcl_GetChannelName(chan), NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_GetChannelName(chan), -1)); return TCL_OK; } diff --git a/generic/tclFileName.c b/generic/tclFileName.c index edb6581..5d4702b 100644 --- a/generic/tclFileName.c +++ b/generic/tclFileName.c @@ -411,25 +411,28 @@ TclpGetNativePathType( * Paths that begin with / are absolute. */ -#ifdef __QNX__ - /* - * Check for QNX //<node id> prefix - */ - if (*path && (pathLen > 3) && (path[0] == '/') - && (path[1] == '/') && isdigit(UCHAR(path[2]))) { - path += 3; - while (isdigit(UCHAR(*path))) { - path++; - } - } -#endif if (path[0] == '/') { -#ifdef __CYGWIN__ + ++path; +#if defined(__CYGWIN__) || defined(__QNX__) /* - * Check for Cygwin // network path prefix + * Check for "//" network path prefix */ - if (path[1] == '/') { - path++; + if ((*path == '/') && path[1] && (path[1] != '/')) { + path += 2; + while (*path && *path != '/') { + ++path; + } +#if defined(__CYGWIN__) + /* UNC paths need to be followed by a share name */ + if (*path++ && (*path && *path != '/')) { + ++path; + while (*path && *path != '/') { + ++path; + } + } else { + path = origPath + 1; + } +#endif } #endif if (driveNameLengthPtr != NULL) { @@ -437,7 +440,7 @@ TclpGetNativePathType( * We need this addition in case the QNX or Cygwin code was used. */ - *driveNameLengthPtr = (1 + path - origPath); + *driveNameLengthPtr = (path - origPath); } } else { type = TCL_PATH_RELATIVE; @@ -640,41 +643,43 @@ SplitUnixPath( const char *path) /* Pointer to string containing a path. */ { int length; - const char *p, *elementStart; + const char *origPath = path, *elementStart; Tcl_Obj *result = Tcl_NewObj(); /* * Deal with the root directory as a special case. */ -#ifdef __QNX__ - /* - * Check for QNX //<node id> prefix - */ - - if ((path[0] == '/') && (path[1] == '/') - && isdigit(UCHAR(path[2]))) { /* INTL: digit */ - path += 3; - while (isdigit(UCHAR(*path))) { /* INTL: digit */ - path++; - } - } -#endif - - p = path; - if (*p == '/') { - Tcl_Obj *rootElt = Tcl_NewStringObj("/", 1); - p++; -#ifdef __CYGWIN__ + if (*path == '/') { + Tcl_Obj *rootElt; + ++path; +#if defined(__CYGWIN__) || defined(__QNX__) /* - * Check for Cygwin // network path prefix + * Check for "//" network path prefix */ - if (*p == '/') { - Tcl_AppendToObj(rootElt, "/", 1); - p++; + if ((*path == '/') && path[1] && (path[1] != '/')) { + path += 2; + while (*path && *path != '/') { + ++path; + } +#if defined(__CYGWIN__) + /* UNC paths need to be followed by a share name */ + if (*path++ && (*path && *path != '/')) { + ++path; + while (*path && *path != '/') { + ++path; + } + } else { + path = origPath + 1; + } +#endif } #endif + rootElt = Tcl_NewStringObj(origPath, path - origPath); Tcl_ListObjAppendElement(NULL, result, rootElt); + while (*path == '/') { + ++path; + } } /* @@ -683,14 +688,14 @@ SplitUnixPath( */ for (;;) { - elementStart = p; - while ((*p != '\0') && (*p != '/')) { - p++; + elementStart = path; + while ((*path != '\0') && (*path != '/')) { + path++; } - length = p - elementStart; + length = path - elementStart; if (length > 0) { Tcl_Obj *nextElt; - if ((elementStart[0] == '~') && (elementStart != path)) { + if ((elementStart[0] == '~') && (elementStart != origPath)) { TclNewLiteralStringObj(nextElt, "./"); Tcl_AppendToObj(nextElt, elementStart, length); } else { @@ -698,7 +703,7 @@ SplitUnixPath( } Tcl_ListObjAppendElement(NULL, result, nextElt); } - if (*p++ == '\0') { + if (*path++ == '\0') { break; } } @@ -1174,9 +1179,10 @@ DoTildeSubst( dir = TclGetEnv("HOME", &dirString); if (dir == NULL) { if (interp) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "couldn't find HOME environment " - "variable to expand path", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "couldn't find HOME environment " + "variable to expand path", -1)); + Tcl_SetErrorCode(interp, "TCL", "FILENAME", "NO_HOME", NULL); } return NULL; } @@ -1185,8 +1191,9 @@ DoTildeSubst( } else if (TclpGetUserHome(user, resultPtr) == NULL) { if (interp) { Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "user \"", user, "\" doesn't exist", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "user \"%s\" doesn't exist", user)); + Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "USER", user, NULL); } return NULL; } @@ -1329,9 +1336,9 @@ Tcl_GlobObjCmd( endOfForLoop: if ((globFlags & TCL_GLOBMODE_TAILS) && (pathOrDir == NULL)) { - Tcl_AppendResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "\"-tails\" must be used with either " - "\"-directory\" or \"-path\"", NULL); + "\"-directory\" or \"-path\"", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "GLOB", "BADOPTIONCOMBINATION", NULL); return TCL_ERROR; @@ -1625,20 +1632,23 @@ Tcl_GlobObjCmd( } if (length == 0) { - Tcl_AppendResult(interp, "no files matched glob pattern", - (join || (objc == 1)) ? " \"" : "s \"", NULL); + Tcl_Obj *errorMsg = + Tcl_ObjPrintf("no files matched glob pattern%s \"", + (join || (objc == 1)) ? "" : "s"); + if (join) { - Tcl_AppendResult(interp, Tcl_DStringValue(&prefix), NULL); + Tcl_AppendToObj(errorMsg, Tcl_DStringValue(&prefix), -1); } else { const char *sep = ""; for (i = 0; i < objc; i++) { - string = Tcl_GetString(objv[i]); - Tcl_AppendResult(interp, sep, string, NULL); + Tcl_AppendPrintfToObj(errorMsg, "%s%s", + sep, Tcl_GetString(objv[i])); sep = " "; } } - Tcl_AppendResult(interp, "\"", NULL); + Tcl_AppendToObj(errorMsg, "\"", -1); + Tcl_SetObjResult(interp, errorMsg); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "GLOB", "NOMATCH", NULL); result = TCL_ERROR; @@ -1769,6 +1779,7 @@ TclGlob( if (c != '\0') { tail++; } + Tcl_DStringFree(&buffer); } else { tail = pattern; } @@ -2206,15 +2217,15 @@ DoGlob( closeBrace = p; break; } - Tcl_SetResult(interp, "unmatched open-brace in file name", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "unmatched open-brace in file name", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "GLOB", "BALANCE", NULL); return TCL_ERROR; } else if (*p == '}') { - Tcl_SetResult(interp, "unmatched close-brace in file name", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "unmatched close-brace in file name", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "GLOB", "BALANCE", NULL); return TCL_ERROR; diff --git a/generic/tclIO.c b/generic/tclIO.c index ea6c2d7..0cb9fa9 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -427,7 +427,10 @@ TclFinalizeIOSubsystem(void) statePtr != NULL; statePtr = statePtr->nextCSPtr) { chanPtr = statePtr->topChanPtr; - if (!GotFlag(statePtr, CHANNEL_INCLOSE | CHANNEL_CLOSED | CHANNEL_DEAD) + if (GotFlag(statePtr, CHANNEL_DEAD)) { + continue; + } + if (!GotFlag(statePtr, CHANNEL_INCLOSE | CHANNEL_CLOSED ) || GotFlag(statePtr, BG_FLUSH_SCHEDULED)) { ResetFlag(statePtr, BG_FLUSH_SCHEDULED); active = 1; @@ -876,19 +879,25 @@ CheckForStdChannelsBeingClosed( ChannelState *statePtr = ((Channel *) chan)->state; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - if ((chan == tsdPtr->stdinChannel) && tsdPtr->stdinInitialized) { + if (tsdPtr->stdinInitialized + && tsdPtr->stdinChannel != NULL + && statePtr == ((Channel *)tsdPtr->stdinChannel)->state) { if (statePtr->refCount < 2) { statePtr->refCount = 0; tsdPtr->stdinChannel = NULL; return; } - } else if ((chan == tsdPtr->stdoutChannel) && tsdPtr->stdoutInitialized) { + } else if (tsdPtr->stdoutInitialized + && tsdPtr->stdoutChannel != NULL + && statePtr == ((Channel *)tsdPtr->stdoutChannel)->state) { if (statePtr->refCount < 2) { statePtr->refCount = 0; tsdPtr->stdoutChannel = NULL; return; } - } else if ((chan == tsdPtr->stderrChannel) && tsdPtr->stderrInitialized) { + } else if (tsdPtr->stderrInitialized + && tsdPtr->stderrChannel != NULL + && statePtr == ((Channel *)tsdPtr->stderrChannel)->state) { if (statePtr->refCount < 2) { statePtr->refCount = 0; tsdPtr->stderrChannel = NULL; @@ -1024,8 +1033,9 @@ Tcl_UnregisterChannel( if (GotFlag(statePtr, CHANNEL_INCLOSE)) { if (interp != NULL) { - Tcl_AppendResult(interp, "Illegal recursive call to close " - "through close-handler of channel", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "illegal recursive call to close through close-handler" + " of channel", -1)); } return TCL_ERROR; } @@ -1260,8 +1270,8 @@ Tcl_GetChannel( hTblPtr = GetChannelTable(interp); hPtr = Tcl_FindHashEntry(hTblPtr, name); if (hPtr == NULL) { - Tcl_AppendResult(interp, "can not find channel named \"", chanName, - "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can not find channel named \"%s\"", chanName)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CHANNEL", chanName, NULL); return NULL; } @@ -1581,8 +1591,9 @@ Tcl_StackChannel( if (statePtr == NULL) { if (interp) { - Tcl_AppendResult(interp, "couldn't find state for channel \"", - Tcl_GetChannelName(prevChan), "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't find state for channel \"%s\"", + Tcl_GetChannelName(prevChan))); } return NULL; } @@ -1602,9 +1613,9 @@ Tcl_StackChannel( if ((mask & (statePtr->flags & (TCL_READABLE | TCL_WRITABLE))) == 0) { if (interp) { - Tcl_AppendResult(interp, - "reading and writing both disallowed for channel \"", - Tcl_GetChannelName(prevChan), "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "reading and writing both disallowed for channel \"%s\"", + Tcl_GetChannelName(prevChan))); } return NULL; } @@ -1627,8 +1638,9 @@ Tcl_StackChannel( statePtr->csPtrR = csPtrR; statePtr->csPtrW = csPtrW; if (interp) { - Tcl_AppendResult(interp, "could not flush channel \"", - Tcl_GetChannelName(prevChan), "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not flush channel \"%s\"", + Tcl_GetChannelName(prevChan))); } return NULL; } @@ -1781,9 +1793,9 @@ Tcl_UnstackChannel( */ if (!TclChanCaughtErrorBypass(interp, chan) && interp) { - Tcl_AppendResult(interp, "could not flush channel \"", - Tcl_GetChannelName((Tcl_Channel) chanPtr), "\"", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not flush channel \"%s\"", + Tcl_GetChannelName((Tcl_Channel) chanPtr))); } return TCL_ERROR; } @@ -2315,8 +2327,8 @@ CheckForDeadChannel( Tcl_SetErrno(EINVAL); if (interp) { - Tcl_AppendResult(interp, "unable to access channel: invalid channel", - NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "unable to access channel: invalid channel", -1)); } return 1; } @@ -3048,8 +3060,9 @@ Tcl_Close( if (GotFlag(statePtr, CHANNEL_INCLOSE)) { if (interp) { - Tcl_AppendResult(interp, "Illegal recursive call to close " - "through close-handler of channel", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "illegal recursive call to close through close-handler" + " of channel", -1)); } return TCL_ERROR; } @@ -3207,8 +3220,9 @@ Tcl_CloseEx( */ if (!chanPtr->typePtr->close2Proc) { - Tcl_AppendResult(interp, "Half-close of channels not supported by ", - chanPtr->typePtr->typeName, "s", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "half-close of channels not supported by %ss", + chanPtr->typePtr->typeName)); return TCL_ERROR; } @@ -3217,9 +3231,8 @@ Tcl_CloseEx( */ if (chanPtr != statePtr->topChanPtr) { - Tcl_AppendResult(interp, - "Half-close not applicable to stack of transformations", - NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "half-close not applicable to stack of transformations", -1)); return TCL_ERROR; } @@ -3237,9 +3250,9 @@ Tcl_CloseEx( } else { msg = "write"; } - Tcl_AppendResult(interp, "Half-close of ", msg, - "-side not possible, side not opened or already closed", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "Half-close of %s-side not possible, side not opened or" + " already closed", msg)); return TCL_ERROR; } @@ -3250,8 +3263,9 @@ Tcl_CloseEx( if (statePtr->flags & CHANNEL_INCLOSE) { if (interp) { - Tcl_AppendResult(interp, "Illegal recursive call to close " - "through close-handler of channel", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "illegal recursive call to close through close-handler" + " of channel", -1)); } return TCL_ERROR; } @@ -7544,6 +7558,7 @@ Tcl_BadChannelOption( const char **argv; int argc, i; Tcl_DString ds; + Tcl_Obj *errObj; Tcl_DStringInit(&ds); Tcl_DStringAppend(&ds, genericopt, -1); @@ -7556,13 +7571,14 @@ Tcl_BadChannelOption( Tcl_Panic("malformed option list in channel driver"); } Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad option \"", optionName, - "\": should be one of ", NULL); + errObj = Tcl_ObjPrintf("bad option \"%s\": should be one of ", + optionName); argc--; for (i = 0; i < argc; i++) { - Tcl_AppendResult(interp, "-", argv[i], ", ", NULL); + Tcl_AppendPrintfToObj(errObj, "-%s, ", argv[i]); } - Tcl_AppendResult(interp, "or -", argv[i], NULL); + Tcl_AppendPrintfToObj(errObj, "or -%s", argv[i]); + Tcl_SetObjResult(interp, errObj); Tcl_DStringFree(&ds); ckfree(argv); } @@ -7840,8 +7856,9 @@ Tcl_SetChannelOption( if (statePtr->csPtrR || statePtr->csPtrW) { if (interp) { - Tcl_AppendResult(interp, "unable to set channel options: " - "background copy in progress", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "unable to set channel options: background copy in" + " progress", -1)); } return TCL_ERROR; } @@ -7890,8 +7907,9 @@ Tcl_SetChannelOption( ResetFlag(statePtr, CHANNEL_LINEBUFFERED); SetFlag(statePtr, CHANNEL_UNBUFFERED); } else if (interp) { - Tcl_AppendResult(interp, "bad value for -buffering: " - "must be one of full, line, or none", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "bad value for -buffering: must be one of" + " full, line, or none", -1)); return TCL_ERROR; } return TCL_OK; @@ -7946,8 +7964,9 @@ Tcl_SetChannelOption( if (inValue & 0x80 || outValue & 0x80) { if (interp) { - Tcl_AppendResult(interp, "bad value for -eofchar: ", - "must be non-NUL ASCII character", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "bad value for -eofchar: must be non-NUL ASCII" + " character", -1)); } ckfree(argv); return TCL_ERROR; @@ -7960,9 +7979,9 @@ Tcl_SetChannelOption( } } else { if (interp) { - Tcl_AppendResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "bad value for -eofchar: should be a list of zero," - " one, or two elements", NULL); + " one, or two elements", -1)); } ckfree(argv); return TCL_ERROR; @@ -7994,9 +8013,9 @@ Tcl_SetChannelOption( writeMode = GotFlag(statePtr, TCL_WRITABLE) ? argv[1] : NULL; } else { if (interp) { - Tcl_AppendResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "bad value for -translation: must be a one or two" - " element list", NULL); + " element list", -1)); } ckfree(argv); return TCL_ERROR; @@ -8024,10 +8043,9 @@ Tcl_SetChannelOption( translation = TCL_PLATFORM_TRANSLATION; } else { if (interp) { - Tcl_AppendResult(interp, - "bad value for -translation: " - "must be one of auto, binary, cr, lf, crlf," - " or platform", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "bad value for -translation: must be one of " + "auto, binary, cr, lf, crlf, or platform", -1)); } ckfree(argv); return TCL_ERROR; @@ -8075,10 +8093,9 @@ Tcl_SetChannelOption( statePtr->outputTranslation = TCL_PLATFORM_TRANSLATION; } else { if (interp) { - Tcl_AppendResult(interp, - "bad value for -translation: " - "must be one of auto, binary, cr, lf, crlf," - " or platform", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "bad value for -translation: must be one of " + "auto, binary, cr, lf, crlf, or platform", -1)); } ckfree(argv); return TCL_ERROR; @@ -8822,6 +8839,7 @@ TclChannelEventScriptInvoker( */ Tcl_Preserve(interp); + Tcl_Preserve(chanPtr); result = Tcl_EvalObjEx(interp, esPtr->scriptPtr, TCL_EVAL_GLOBAL); /* @@ -8838,6 +8856,7 @@ TclChannelEventScriptInvoker( } Tcl_BackgroundException(interp, result); } + Tcl_Release(chanPtr); Tcl_Release(interp); } @@ -8896,8 +8915,8 @@ Tcl_FileEventObjCmd( chanPtr = (Channel *) chan; statePtr = chanPtr->state; if ((statePtr->flags & mask) == 0) { - Tcl_AppendResult(interp, "channel is not ", - (mask == TCL_READABLE) ? "readable" : "writable", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf("channel is not %s", + (mask == TCL_READABLE) ? "readable" : "writable")); return TCL_ERROR; } @@ -9018,15 +9037,15 @@ TclCopyChannel( if (BUSY_STATE(inStatePtr, TCL_READABLE)) { if (interp) { - Tcl_AppendResult(interp, "channel \"", - Tcl_GetChannelName(inChan), "\" is busy", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "channel \"%s\" is busy", Tcl_GetChannelName(inChan))); } return TCL_ERROR; } if (BUSY_STATE(outStatePtr, TCL_WRITABLE)) { if (interp) { - Tcl_AppendResult(interp, "channel \"", - Tcl_GetChannelName(outChan), "\" is busy", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "channel \"%s\" is busy", Tcl_GetChannelName(outChan))); } return TCL_ERROR; } @@ -10152,8 +10171,9 @@ SetBlockMode( */ if (!TclChanCaughtErrorBypass(interp, (Tcl_Channel) chanPtr)) { - Tcl_AppendResult(interp, "error setting blocking mode: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error setting blocking mode: %s", + Tcl_PosixError(interp))); } } else { /* diff --git a/generic/tclIOCmd.c b/generic/tclIOCmd.c index 59856d0..005713d 100644 --- a/generic/tclIOCmd.c +++ b/generic/tclIOCmd.c @@ -174,9 +174,10 @@ Tcl_PutsObjCmd( if (TclGetChannelFromObj(interp, chanObjPtr, &chan, &mode, 0) != TCL_OK) { return TCL_ERROR; } - if ((mode & TCL_WRITABLE) == 0) { - Tcl_AppendResult(interp, "channel \"", TclGetString(chanObjPtr), - "\" wasn't opened for writing", NULL); + if (!(mode & TCL_WRITABLE)) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "channel \"%s\" wasn't opened for writing", + TclGetString(chanObjPtr))); return TCL_ERROR; } @@ -201,8 +202,8 @@ Tcl_PutsObjCmd( error: if (!TclChanCaughtErrorBypass(interp, chan)) { - Tcl_AppendResult(interp, "error writing \"", TclGetString(chanObjPtr), - "\": ", Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf("error writing \"%s\": %s", + TclGetString(chanObjPtr), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -244,9 +245,10 @@ Tcl_FlushObjCmd( if (TclGetChannelFromObj(interp, chanObjPtr, &chan, &mode, 0) != TCL_OK) { return TCL_ERROR; } - if ((mode & TCL_WRITABLE) == 0) { - Tcl_AppendResult(interp, "channel \"", TclGetString(chanObjPtr), - "\" wasn't opened for writing", NULL); + if (!(mode & TCL_WRITABLE)) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "channel \"%s\" wasn't opened for writing", + TclGetString(chanObjPtr))); return TCL_ERROR; } @@ -259,9 +261,9 @@ Tcl_FlushObjCmd( */ if (!TclChanCaughtErrorBypass(interp, chan)) { - Tcl_AppendResult(interp, "error flushing \"", - TclGetString(chanObjPtr), "\": ", Tcl_PosixError(interp), - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error flushing \"%s\": %s", + TclGetString(chanObjPtr), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -306,9 +308,10 @@ Tcl_GetsObjCmd( if (TclGetChannelFromObj(interp, chanObjPtr, &chan, &mode, 0) != TCL_OK) { return TCL_ERROR; } - if ((mode & TCL_READABLE) == 0) { - Tcl_AppendResult(interp, "channel \"", TclGetString(chanObjPtr), - "\" wasn't opened for reading", NULL); + if (!(mode & TCL_READABLE)) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "channel \"%s\" wasn't opened for reading", + TclGetString(chanObjPtr))); return TCL_ERROR; } @@ -326,10 +329,9 @@ Tcl_GetsObjCmd( */ if (!TclChanCaughtErrorBypass(interp, chan)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "error reading \"", - TclGetString(chanObjPtr), "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error reading \"%s\": %s", + TclGetString(chanObjPtr), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -411,9 +413,10 @@ Tcl_ReadObjCmd( if (TclGetChannelFromObj(interp, chanObjPtr, &chan, &mode, 0) != TCL_OK) { return TCL_ERROR; } - if ((mode & TCL_READABLE) == 0) { - Tcl_AppendResult(interp, "channel \"", TclGetString(chanObjPtr), - "\" wasn't opened for reading", NULL); + if (!(mode & TCL_READABLE)) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "channel \"%s\" wasn't opened for reading", + TclGetString(chanObjPtr))); return TCL_ERROR; } i++; /* Consumed channel name. */ @@ -436,11 +439,11 @@ Tcl_ReadObjCmd( if (strcmp(TclGetString(objv[i]), "nonewline") != 0) { #endif - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "expected non-negative integer but got \"", - TclGetString(objv[i]), "\"", NULL); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "NUMBER", NULL); - return TCL_ERROR; + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "expected non-negative integer but got \"%s\"", + TclGetString(objv[i]))); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "NUMBER", NULL); + return TCL_ERROR; #if TCL_MAJOR_VERSION < 9 } newline = 1; @@ -460,10 +463,9 @@ Tcl_ReadObjCmd( */ if (!TclChanCaughtErrorBypass(interp, chan)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "error reading \"", - TclGetString(chanObjPtr), "\": ", Tcl_PosixError(interp), - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error reading \"%s\": %s", + TclGetString(chanObjPtr), Tcl_PosixError(interp))); } Tcl_DecrRefCount(resultPtr); return TCL_ERROR; @@ -552,9 +554,9 @@ Tcl_SeekObjCmd( */ if (!TclChanCaughtErrorBypass(interp, chan)) { - Tcl_AppendResult(interp, "error during seek on \"", - TclGetString(objv[1]), "\": ", Tcl_PosixError(interp), - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error during seek on \"%s\": %s", + TclGetString(objv[1]), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -679,9 +681,9 @@ Tcl_CloseObjCmd( */ if (!(dir & Tcl_GetChannelMode(chan))) { - Tcl_AppendResult(interp, "Half-close of ", dirOptions[index], - "-side not possible, side not opened or already closed", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "Half-close of %s-side not possible, side not opened" + " or already closed", dirOptions[index])); return TCL_ERROR; } @@ -977,9 +979,9 @@ Tcl_ExecObjCmd( */ if (!TclChanCaughtErrorBypass(interp, chan)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "error reading output from command: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error reading output from command: %s", + Tcl_PosixError(interp))); Tcl_DecrRefCount(resultPtr); } return TCL_ERROR; @@ -1048,9 +1050,10 @@ Tcl_FblockedObjCmd( if (TclGetChannelFromObj(interp, objv[1], &chan, &mode, 0) != TCL_OK) { return TCL_ERROR; } - if ((mode & TCL_READABLE) == 0) { - Tcl_AppendResult(interp, "channel \"", TclGetString(objv[1]), - "\" wasn't opened for reading", NULL); + if (!(mode & TCL_READABLE)) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "channel \"%s\" wasn't opened for reading", + TclGetString(objv[1]))); return TCL_ERROR; } @@ -1174,7 +1177,7 @@ Tcl_OpenObjCmd( return TCL_ERROR; } Tcl_RegisterChannel(interp, chan); - Tcl_AppendResult(interp, Tcl_GetChannelName(chan), NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_GetChannelName(chan), -1)); return TCL_OK; } @@ -1479,8 +1482,8 @@ Tcl_SocketObjCmd( switch ((enum socketOptions) optionIndex) { case SKT_ASYNC: if (server == 1) { - Tcl_AppendResult(interp, - "cannot set -async option for server sockets", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "cannot set -async option for server sockets", -1)); return TCL_ERROR; } async = 1; @@ -1488,8 +1491,8 @@ Tcl_SocketObjCmd( case SKT_MYADDR: a++; if (a >= objc) { - Tcl_AppendResult(interp, - "no argument given for -myaddr option", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "no argument given for -myaddr option", -1)); return TCL_ERROR; } myaddr = TclGetString(objv[a]); @@ -1499,8 +1502,8 @@ Tcl_SocketObjCmd( a++; if (a >= objc) { - Tcl_AppendResult(interp, - "no argument given for -myport option", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "no argument given for -myport option", -1)); return TCL_ERROR; } myPortName = TclGetString(objv[a]); @@ -1511,15 +1514,15 @@ Tcl_SocketObjCmd( } case SKT_SERVER: if (async == 1) { - Tcl_AppendResult(interp, - "cannot set -async option for server sockets", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "cannot set -async option for server sockets", -1)); return TCL_ERROR; } server = 1; a++; if (a >= objc) { - Tcl_AppendResult(interp, - "no argument given for -server option", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "no argument given for -server option", -1)); return TCL_ERROR; } script = TclGetString(objv[a]); @@ -1531,8 +1534,8 @@ Tcl_SocketObjCmd( if (server) { host = myaddr; /* NULL implies INADDR_ANY */ if (myport != 0) { - Tcl_AppendResult(interp, "option -myport is not valid for servers", - NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "option -myport is not valid for servers", -1)); return TCL_ERROR; } } else if (a < objc) { @@ -1599,9 +1602,9 @@ Tcl_SocketObjCmd( return TCL_ERROR; } } - Tcl_RegisterChannel(interp, chan); - Tcl_AppendResult(interp, Tcl_GetChannelName(chan), NULL); + Tcl_RegisterChannel(interp, chan); + Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_GetChannelName(chan), -1)); return TCL_OK; } @@ -1651,17 +1654,19 @@ Tcl_FcopyObjCmd( if (TclGetChannelFromObj(interp, objv[1], &inChan, &mode, 0) != TCL_OK) { return TCL_ERROR; } - if ((mode & TCL_READABLE) == 0) { - Tcl_AppendResult(interp, "channel \"", TclGetString(objv[1]), - "\" wasn't opened for reading", NULL); + if (!(mode & TCL_READABLE)) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "channel \"%s\" wasn't opened for reading", + TclGetString(objv[1]))); return TCL_ERROR; } if (TclGetChannelFromObj(interp, objv[2], &outChan, &mode, 0) != TCL_OK) { return TCL_ERROR; } - if ((mode & TCL_WRITABLE) == 0) { - Tcl_AppendResult(interp, "channel \"", TclGetString(objv[2]), - "\" wasn't opened for writing", NULL); + if (!(mode & TCL_WRITABLE)) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "channel \"%s\" wasn't opened for writing", + TclGetString(objv[2]))); return TCL_ERROR; } @@ -1745,14 +1750,14 @@ ChanPendingObjCmd( switch ((enum options) index) { case PENDING_INPUT: - if ((mode & TCL_READABLE) == 0) { + if (!(mode & TCL_READABLE)) { Tcl_SetObjResult(interp, Tcl_NewIntObj(-1)); } else { Tcl_SetObjResult(interp, Tcl_NewIntObj(Tcl_InputBuffered(chan))); } break; case PENDING_OUTPUT: - if ((mode & TCL_WRITABLE) == 0) { + if (!(mode & TCL_WRITABLE)) { Tcl_SetObjResult(interp, Tcl_NewIntObj(-1)); } else { Tcl_SetObjResult(interp, Tcl_NewIntObj(Tcl_OutputBuffered(chan))); @@ -1806,8 +1811,8 @@ ChanTruncateObjCmd( return TCL_ERROR; } if (length < 0) { - Tcl_AppendResult(interp, - "cannot truncate to negative length of file", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "cannot truncate to negative length of file", -1)); return TCL_ERROR; } } else { @@ -1817,18 +1822,17 @@ ChanTruncateObjCmd( length = Tcl_Tell(chan); if (length == Tcl_WideAsLong(-1)) { - Tcl_AppendResult(interp, - "could not determine current location in \"", - TclGetString(objv[1]), "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not determine current location in \"%s\": %s", + TclGetString(objv[1]), Tcl_PosixError(interp))); return TCL_ERROR; } } if (Tcl_TruncateChannel(chan, length) != TCL_OK) { - Tcl_AppendResult(interp, "error during truncate on \"", - TclGetString(objv[1]), "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error during truncate on \"%s\": %s", + TclGetString(objv[1]), Tcl_PosixError(interp))); return TCL_ERROR; } diff --git a/generic/tclIOGT.c b/generic/tclIOGT.c index 6f80c25..bfe6a10 100644 --- a/generic/tclIOGT.c +++ b/generic/tclIOGT.c @@ -284,8 +284,8 @@ TclChannelTransform( dataPtr->self = Tcl_StackChannel(interp, &transformChannelType, dataPtr, mode, chan); if (dataPtr->self == NULL) { - Tcl_AppendResult(interp, "\nfailed to stack channel \"", - Tcl_GetChannelName(chan), "\"", NULL); + Tcl_AppendPrintfToObj(Tcl_GetObjResult(interp), + "\nfailed to stack channel \"%s\"", Tcl_GetChannelName(chan)); Tcl_DecrRefCount(dataPtr->command); ResultClear(&dataPtr->result); ckfree(dataPtr); diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c index 6fec40a..cb0282a 100644 --- a/generic/tclIORChan.c +++ b/generic/tclIORChan.c @@ -404,25 +404,25 @@ static int ForwardProc(Tcl_Event *evPtr, int mask); static void SrcExitProc(ClientData clientData); #define FreeReceivedError(p) \ - if ((p)->base.mustFree) { \ - ckfree((p)->base.msgStr); \ + if ((p)->base.mustFree) { \ + ckfree((p)->base.msgStr); \ } #define PassReceivedErrorInterp(i,p) \ - if ((i) != NULL) { \ - Tcl_SetChannelErrorInterp((i), \ - Tcl_NewStringObj((p)->base.msgStr, -1)); \ - } \ + if ((i) != NULL) { \ + Tcl_SetChannelErrorInterp((i), \ + Tcl_NewStringObj((p)->base.msgStr, -1)); \ + } \ FreeReceivedError(p) #define PassReceivedError(c,p) \ Tcl_SetChannelError((c), Tcl_NewStringObj((p)->base.msgStr, -1)); \ FreeReceivedError(p) #define ForwardSetStaticError(p,emsg) \ - (p)->base.code = TCL_ERROR; \ - (p)->base.mustFree = 0; \ + (p)->base.code = TCL_ERROR; \ + (p)->base.mustFree = 0; \ (p)->base.msgStr = (char *) (emsg) #define ForwardSetDynamicError(p,emsg) \ - (p)->base.code = TCL_ERROR; \ - (p)->base.mustFree = 1; \ + (p)->base.code = TCL_ERROR; \ + (p)->base.mustFree = 1; \ (p)->base.msgStr = (char *) (emsg) static void ForwardSetObjError(ForwardParam *p, Tcl_Obj *objPtr); @@ -739,7 +739,8 @@ TclChanCreateObjCmd( * Return handle as result of command. */ - Tcl_SetResult(interp, (char *)chanPtr->state->channelName, TCL_VOLATILE); + Tcl_SetObjResult(interp, + Tcl_NewStringObj(chanPtr->state->channelName, -1)); return TCL_OK; error: @@ -774,13 +775,15 @@ TclChanCreateObjCmd( */ typedef struct ReflectEvent { - Tcl_Event header; - ReflectedChannel* rcPtr; - int events; + Tcl_Event header; + ReflectedChannel *rcPtr; + int events; } ReflectEvent; static int -ReflectEventRun (Tcl_Event* ev, int flags) +ReflectEventRun( + Tcl_Event *ev, + int flags) { /* OWNER thread * @@ -789,14 +792,16 @@ ReflectEventRun (Tcl_Event* ev, int flags) * accomplishing that. */ - ReflectEvent* e = (ReflectEvent*) ev; + ReflectEvent *e = (ReflectEvent *) ev; - Tcl_NotifyChannel (e->rcPtr->chan, e->events); + Tcl_NotifyChannel(e->rcPtr->chan, e->events); return 1; } static int -ReflectEventDelete (Tcl_Event* ev, ClientData cd) +ReflectEventDelete( + Tcl_Event *ev, + ClientData cd) { /* OWNER thread * @@ -805,11 +810,9 @@ ReflectEventDelete (Tcl_Event* ev, ClientData cd) * invalid channel. */ - ReflectEvent* e = (ReflectEvent*) ev; + ReflectEvent *e = (ReflectEvent *) ev; - if ((ev->proc != ReflectEventRun) || - ((cd != NULL) && - (cd != e->rcPtr))) { + if ((ev->proc != ReflectEventRun) || ((cd != NULL) && (cd != e->rcPtr))) { return 0; } return 1; @@ -867,8 +870,8 @@ TclChanPostEventObjCmd( hPtr = Tcl_FindHashEntry(&rcmPtr->map, chanId); if (hPtr == NULL) { - Tcl_AppendResult(interp, "can not find reflected channel named \"", - chanId, "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can not find reflected channel named \"%s\"", chanId)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CHANNEL", chanId, NULL); return TCL_ERROR; } @@ -925,8 +928,9 @@ TclChanPostEventObjCmd( */ if (events & ~rcPtr->interest) { - Tcl_AppendResult(interp, "tried to post events channel \"", chanId, - "\" is not interested in", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "tried to post events channel \"%s\" is not interested in", + chanId)); return TCL_ERROR; } @@ -937,10 +941,11 @@ TclChanPostEventObjCmd( #ifdef TCL_THREADS if (rcPtr->owner == rcPtr->thread) { #endif - Tcl_NotifyChannel (chan, events); + Tcl_NotifyChannel(chan, events); #ifdef TCL_THREADS } else { - ReflectEvent* ev = ckalloc (sizeof (ReflectEvent)); + ReflectEvent *ev = ckalloc(sizeof(ReflectEvent)); + ev->header.proc = ReflectEventRun; ev->events = events; ev->rcPtr = rcPtr; @@ -957,7 +962,8 @@ TclChanPostEventObjCmd( * The teardown of unprocessed events is currently coupled to the * thread reflected channel map */ - (void) GetThreadReflectedChannelMap (); + + (void) GetThreadReflectedChannelMap(); /* XXX Race condition !! * XXX The destination thread may not exist anymore already. @@ -965,8 +971,9 @@ TclChanPostEventObjCmd( * XXX Can we detect this ? (check the validity of the owner threadid ?) * XXX Actually, in that case the channel should be dead also ! */ - Tcl_ThreadQueueEvent (rcPtr->owner, (Tcl_Event*) ev, TCL_QUEUE_TAIL); - Tcl_ThreadAlert (rcPtr->owner); + + Tcl_ThreadQueueEvent(rcPtr->owner, (Tcl_Event *) ev, TCL_QUEUE_TAIL); + Tcl_ThreadAlert(rcPtr->owner); } #endif @@ -1156,8 +1163,11 @@ ReflectClose( ForwardOpToHandlerThread(rcPtr, ForwardedClose, &p); result = p.base.code; - /* Now squash the pending reflection events for this channel. */ - Tcl_DeleteEvents (ReflectEventDelete, rcPtr); + /* + * Now squash the pending reflection events for this channel. + */ + + Tcl_DeleteEvents(ReflectEventDelete, rcPtr); if (result != TCL_OK) { FreeReceivedError(&p); @@ -1165,7 +1175,7 @@ ReflectClose( } #endif - Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); + Tcl_EventuallyFree(rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); return EOK; } @@ -1177,7 +1187,7 @@ ReflectClose( */ if (rcPtr->methods == 0) { - Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); + Tcl_EventuallyFree(rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); return EOK; } @@ -1192,10 +1202,13 @@ ReflectClose( ForwardOpToHandlerThread(rcPtr, ForwardedClose, &p); result = p.base.code; - /* Now squash the pending reflection events for this channel. */ - Tcl_DeleteEvents (ReflectEventDelete, rcPtr); + /* + * Now squash the pending reflection events for this channel. + */ + + Tcl_DeleteEvents(ReflectEventDelete, rcPtr); - Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); + Tcl_EventuallyFree(rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); if (result != TCL_OK) { PassReceivedErrorInterp(interp, &p); @@ -1240,7 +1253,7 @@ ReflectClose( } #endif - Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); + Tcl_EventuallyFree(rcPtr, (Tcl_FreeProc *) FreeReflectedChannel); #ifdef TCL_THREADS } #endif @@ -1348,7 +1361,7 @@ ReflectInput( *errorCodePtr = EOK; if (bytec > 0) { - memcpy(buf, bytev, (size_t)bytec); + memcpy(buf, bytev, (size_t) bytec); } stop: @@ -1549,12 +1562,13 @@ ReflectSeekWide( Tcl_Preserve(rcPtr); offObj = Tcl_NewWideIntObj(offset); - baseObj = Tcl_NewStringObj((seekMode == SEEK_SET) ? "start" : - ((seekMode == SEEK_CUR) ? "current" : "end"), -1); + baseObj = Tcl_NewStringObj( + (seekMode == SEEK_SET) ? "start" : + (seekMode == SEEK_CUR) ? "current" : "end", -1); Tcl_IncrRefCount(offObj); Tcl_IncrRefCount(baseObj); - if (InvokeTclMethod(rcPtr, "seek", offObj, baseObj, &resObj)!=TCL_OK) { + if (InvokeTclMethod(rcPtr, "seek", offObj, baseObj, &resObj) != TCL_OK) { Tcl_SetChannelError(rcPtr->chan, resObj); goto invalid; } @@ -1760,7 +1774,9 @@ ReflectBlock( */ static void -ReflectThread(ClientData clientData, int action) +ReflectThread( + ClientData clientData, + int action) { ReflectedChannel *rcPtr = clientData; @@ -1772,7 +1788,7 @@ ReflectThread(ClientData clientData, int action) rcPtr->owner = NULL; break; default: - Tcl_Panic ("Unknown thread action code."); + Tcl_Panic("Unknown thread action code."); break; } } @@ -2046,7 +2062,8 @@ EncodeEventMask( } if (listc < 1) { - Tcl_AppendResult(interp, "bad ", objName, " list: is empty", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad %s list: is empty", objName)); return TCL_ERROR; } @@ -2807,7 +2824,7 @@ DeleteThreadReflectedChannelMap( * actually. */ - Tcl_DeleteEvents (ReflectEventDelete, NULL); + Tcl_DeleteEvents(ReflectEventDelete, NULL); /* * Get the map of all channels handled by the current thread. This is a @@ -2978,9 +2995,8 @@ ForwardProc( Tcl_Interp *interp = rcPtr->interp; ForwardParam *paramPtr = evPtr->param; Tcl_Obj *resObj = NULL; /* Interp result of InvokeTclMethod */ - ReflectedChannelMap *rcmPtr; - /* Map of reflected channels with handlers in - * this interp. */ + ReflectedChannelMap *rcmPtr;/* Map of reflected channels with handlers in + * this interp. */ Tcl_HashEntry *hPtr; /* Entry in the above map */ /* @@ -3023,12 +3039,12 @@ ForwardProc( rcmPtr = GetReflectedChannelMap(interp); hPtr = Tcl_FindHashEntry(&rcmPtr->map, - Tcl_GetChannelName(rcPtr->chan)); + Tcl_GetChannelName(rcPtr->chan)); Tcl_DeleteHashEntry(hPtr); rcmPtr = GetThreadReflectedChannelMap(); hPtr = Tcl_FindHashEntry(&rcmPtr->map, - Tcl_GetChannelName(rcPtr->chan)); + Tcl_GetChannelName(rcPtr->chan)); Tcl_DeleteHashEntry(hPtr); FreeReflectedChannelArgs(rcPtr); @@ -3063,7 +3079,7 @@ ForwardProc( paramPtr->input.toRead = -1; } else { if (bytec > 0) { - memcpy(paramPtr->input.buf, bytev, (size_t)bytec); + memcpy(paramPtr->input.buf, bytev, (size_t) bytec); } paramPtr->input.toRead = bytec; } @@ -3075,7 +3091,7 @@ ForwardProc( case ForwardedOutput: { Tcl_Obj *bufObj = Tcl_NewByteArrayObj((unsigned char *) - paramPtr->output.buf, paramPtr->output.toWrite); + paramPtr->output.buf, paramPtr->output.toWrite); Tcl_IncrRefCount(bufObj); Tcl_Preserve(rcPtr); @@ -3115,8 +3131,8 @@ ForwardProc( case ForwardedSeek: { Tcl_Obj *offObj = Tcl_NewWideIntObj(paramPtr->seek.offset); Tcl_Obj *baseObj = Tcl_NewStringObj( - (paramPtr->seek.seekMode==SEEK_SET) ? "start" : - (paramPtr->seek.seekMode==SEEK_CUR) ? "current" : "end", -1); + (paramPtr->seek.seekMode==SEEK_SET) ? "start" : + (paramPtr->seek.seekMode==SEEK_CUR) ? "current" : "end", -1); Tcl_IncrRefCount(offObj); Tcl_IncrRefCount(baseObj); @@ -3166,11 +3182,11 @@ ForwardProc( case ForwardedBlock: { Tcl_Obj *blockObj = Tcl_NewBooleanObj(!paramPtr->block.nonblocking); - Tcl_IncrRefCount(blockObj); + Tcl_IncrRefCount(blockObj); Tcl_Preserve(rcPtr); if (InvokeTclMethod(rcPtr, "blocking", blockObj, NULL, - &resObj) != TCL_OK) { + &resObj) != TCL_OK) { ForwardSetObjError(paramPtr, resObj); } Tcl_Release(rcPtr); @@ -3186,7 +3202,7 @@ ForwardProc( Tcl_IncrRefCount(valueObj); Tcl_Preserve(rcPtr); if (InvokeTclMethod(rcPtr, "configure", optionObj, valueObj, - &resObj) != TCL_OK) { + &resObj) != TCL_OK) { ForwardSetObjError(paramPtr, resObj); } Tcl_Release(rcPtr); @@ -3201,8 +3217,8 @@ ForwardProc( */ Tcl_Obj *optionObj = Tcl_NewStringObj(paramPtr->getOpt.name, -1); - Tcl_IncrRefCount(optionObj); + Tcl_IncrRefCount(optionObj); Tcl_Preserve(rcPtr); if (InvokeTclMethod(rcPtr, "cget", optionObj, NULL, &resObj)!=TCL_OK){ ForwardSetObjError(paramPtr, resObj); diff --git a/generic/tclIORTrans.c b/generic/tclIORTrans.c index 8f111b0..2b9efb9 100644 --- a/generic/tclIORTrans.c +++ b/generic/tclIORTrans.c @@ -363,33 +363,43 @@ static int ForwardProc(Tcl_Event *evPtr, int mask); static void SrcExitProc(ClientData clientData); #define FreeReceivedError(p) \ - if ((p)->base.mustFree) { \ - ckfree((p)->base.msgStr); \ - } + do { \ + if ((p)->base.mustFree) { \ + ckfree((p)->base.msgStr); \ + } \ + } while (0) #define PassReceivedErrorInterp(i,p) \ - if ((i) != NULL) { \ - Tcl_SetChannelErrorInterp((i), \ - Tcl_NewStringObj((p)->base.msgStr, -1)); \ - } \ - FreeReceivedError(p) + do { \ + if ((i) != NULL) { \ + Tcl_SetChannelErrorInterp((i), \ + Tcl_NewStringObj((p)->base.msgStr, -1)); \ + } \ + FreeReceivedError(p); \ + } while (0) #define PassReceivedError(c,p) \ - Tcl_SetChannelError((c), Tcl_NewStringObj((p)->base.msgStr, -1)); \ - FreeReceivedError(p) + do { \ + Tcl_SetChannelError((c), \ + Tcl_NewStringObj((p)->base.msgStr, -1)); \ + FreeReceivedError(p); \ + } while (0) #define ForwardSetStaticError(p,emsg) \ - (p)->base.code = TCL_ERROR; \ - (p)->base.mustFree = 0; \ - (p)->base.msgStr = (char *) (emsg) + do { \ + (p)->base.code = TCL_ERROR; \ + (p)->base.mustFree = 0; \ + (p)->base.msgStr = (char *) (emsg); \ + } while (0) #define ForwardSetDynamicError(p,emsg) \ - (p)->base.code = TCL_ERROR; \ - (p)->base.mustFree = 1; \ - (p)->base.msgStr = (char *) (emsg) + do { \ + (p)->base.code = TCL_ERROR; \ + (p)->base.mustFree = 1; \ + (p)->base.msgStr = (char *) (emsg); \ + } while (0) static void ForwardSetObjError(ForwardParam *p, Tcl_Obj *objPtr); - static ReflectedTransformMap * GetThreadReflectedTransformMap(void); -static void DeleteThreadReflectedTransformMap(ClientData clientData); - +static void DeleteThreadReflectedTransformMap( + ClientData clientData); #endif /* TCL_THREADS */ #define SetChannelErrorStr(c,msgStr) \ @@ -513,7 +523,6 @@ TclChanPushObjCmd( int result; /* Result code for 'initialize' */ Tcl_Obj *resObj; /* Result data for 'initialize' */ int methods; /* Bitmask for supported methods. */ - Tcl_Obj *err; /* Error message */ ReflectedTransformMap *rtmPtr; /* Map of reflected transforms with handlers * in this interp. */ @@ -608,11 +617,10 @@ TclChanPushObjCmd( while (listc > 0) { if (Tcl_GetIndexFromObj(interp, listv[listc-1], methodNames, "method", TCL_EXACT, &methIndex) != TCL_OK) { - TclNewLiteralStringObj(err, "chan handler \""); - Tcl_AppendObjToObj(err, cmdObj); - Tcl_AppendToObj(err, " initialize\" returned ", -1); - Tcl_AppendObjToObj(err, Tcl_GetObjResult(interp)); - Tcl_SetObjResult(interp, err); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "chan handler \"%s initialize\" returned %s", + Tcl_GetString(cmdObj), + Tcl_GetString(Tcl_GetObjResult(interp)))); Tcl_DecrRefCount(resObj); goto error; } @@ -695,13 +703,14 @@ TclChanPushObjCmd( rtmPtr = GetThreadReflectedTransformMap(); hPtr = Tcl_CreateHashEntry(&rtmPtr->map, Tcl_GetString(rtId), &isNew); Tcl_SetHashValue(hPtr, rtPtr); -#endif +#endif /* TCL_THREADS */ /* * Return the channel as the result of the command. */ - Tcl_AppendResult(interp, Tcl_GetChannelName(rtPtr->chan), NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + Tcl_GetChannelName(rtPtr->chan), -1)); return TCL_OK; error: @@ -710,7 +719,7 @@ TclChanPushObjCmd( * structure. */ - Tcl_EventuallyFree (rtPtr, (Tcl_FreeProc *) FreeReflectedTransform); + Tcl_EventuallyFree(rtPtr, (Tcl_FreeProc *) FreeReflectedTransform); return TCL_ERROR; #undef CHAN @@ -913,9 +922,9 @@ ReflectClose( FreeReceivedError(&p); } } -#endif +#endif /* TCL_THREADS */ - Tcl_EventuallyFree (rtPtr, (Tcl_FreeProc *) FreeReflectedTransform); + Tcl_EventuallyFree(rtPtr, (Tcl_FreeProc *) FreeReflectedTransform); return EOK; } @@ -931,11 +940,11 @@ ReflectClose( if (!TransformDrain(rtPtr, &errorCode)) { #ifdef TCL_THREADS if (rtPtr->thread != Tcl_GetCurrentThread()) { - Tcl_EventuallyFree (rtPtr, + Tcl_EventuallyFree(rtPtr, (Tcl_FreeProc *) FreeReflectedTransform); return errorCode; } -#endif +#endif /* TCL_THREADS */ errorCodeSet = 1; goto cleanup; } @@ -945,11 +954,11 @@ ReflectClose( if (!TransformFlush(rtPtr, &errorCode, FLUSH_WRITE)) { #ifdef TCL_THREADS if (rtPtr->thread != Tcl_GetCurrentThread()) { - Tcl_EventuallyFree (rtPtr, + Tcl_EventuallyFree(rtPtr, (Tcl_FreeProc *) FreeReflectedTransform); return errorCode; } -#endif +#endif /* TCL_THREADS */ errorCodeSet = 1; goto cleanup; } @@ -966,7 +975,7 @@ ReflectClose( ForwardOpToOwnerThread(rtPtr, ForwardedClose, &p); result = p.base.code; - Tcl_EventuallyFree (rtPtr, (Tcl_FreeProc *) FreeReflectedTransform); + Tcl_EventuallyFree(rtPtr, (Tcl_FreeProc *) FreeReflectedTransform); if (result != TCL_OK) { PassReceivedErrorInterp(interp, &p); @@ -974,7 +983,7 @@ ReflectClose( } return EOK; } -#endif +#endif /* TCL_THREADS */ /* * Do the actual invokation of "finalize" now; we're in the right thread. @@ -1022,7 +1031,7 @@ ReflectClose( if (hPtr) { Tcl_DeleteHashEntry(hPtr); } -#endif +#endif /* TCL_THREADS */ } Tcl_EventuallyFree (rtPtr, (Tcl_FreeProc *) FreeReflectedTransform); @@ -1348,7 +1357,7 @@ ReflectSeekWide( * transformation. */ - if ((rtPtr->methods & FLAG(METH_CLEAR))) { + if (rtPtr->methods & FLAG(METH_CLEAR)) { TransformClear(rtPtr); } @@ -2140,7 +2149,7 @@ DeleteReflectedTransformMap( ForwardingResult *resultPtr; ForwardingEvent *evPtr; ForwardParam *paramPtr; -#endif +#endif /* TCL_THREADS */ /* * Delete all entries. The channels may have been closed already, or will @@ -2232,8 +2241,7 @@ DeleteReflectedTransformMap( Tcl_ConditionNotify(&resultPtr->done); } Tcl_MutexUnlock(&rtForwardMutex); - -#endif +#endif /* TCL_THREADS */ } #ifdef TCL_THREADS @@ -2631,7 +2639,7 @@ ForwardProc( break; } - case ForwardedDrain: { + case ForwardedDrain: if (InvokeTclMethod(rtPtr, "drain", NULL, NULL, &resObj) != TCL_OK) { ForwardSetObjError(paramPtr, resObj); paramPtr->transform.size = -1; @@ -2656,9 +2664,8 @@ ForwardProc( } } break; - } - case ForwardedFlush: { + case ForwardedFlush: if (InvokeTclMethod(rtPtr, "flush", NULL, NULL, &resObj) != TCL_OK) { ForwardSetObjError(paramPtr, resObj); paramPtr->transform.size = -1; @@ -2684,12 +2691,10 @@ ForwardProc( } } break; - } - case ForwardedClear: { + case ForwardedClear: (void) InvokeTclMethod(rtPtr, "clear", NULL, NULL, NULL); break; - } case ForwardedLimit: if (InvokeTclMethod(rtPtr, "limit?", NULL, NULL, &resObj) != TCL_OK) { @@ -2795,7 +2800,7 @@ ForwardSetObjError( ForwardSetDynamicError(paramPtr, ckalloc(len)); memcpy(paramPtr->base.msgStr, msgStr, (unsigned) len); } -#endif +#endif /* TCL_THREADS */ /* *---------------------------------------------------------------------- @@ -3092,7 +3097,7 @@ TransformRead( ckfree(p.transform.buf); return 1; } -#endif +#endif /* TCL_THREADS */ /* ASSERT: rtPtr->method & FLAG(METH_READ) */ /* ASSERT: rtPtr->mode & TCL_READABLE */ @@ -3153,7 +3158,7 @@ TransformWrite( p.transform.size); ckfree(p.transform.buf); } else -#endif +#endif /* TCL_THREADS */ { /* ASSERT: rtPtr->method & FLAG(METH_WRITE) */ /* ASSERT: rtPtr->mode & TCL_WRITABLE */ @@ -3215,7 +3220,7 @@ TransformDrain( ResultAdd(&rtPtr->result, UCHARP(p.transform.buf), p.transform.size); ckfree(p.transform.buf); } else -#endif +#endif /* TCL_THREADS */ { if (InvokeTclMethod(rtPtr, "drain", NULL, NULL, &resObj)!=TCL_OK) { Tcl_SetChannelError(rtPtr->chan, resObj); @@ -3270,7 +3275,7 @@ TransformFlush( } ckfree(p.transform.buf); } else -#endif +#endif /* TCL_THREADS */ { if (InvokeTclMethod(rtPtr, "flush", NULL, NULL, &resObj)!=TCL_OK) { Tcl_SetChannelError(rtPtr->chan, resObj); @@ -3311,7 +3316,7 @@ TransformClear( ForwardOpToOwnerThread(rtPtr, ForwardedClear, &p); return; } -#endif +#endif /* TCL_THREADS */ /* ASSERT: rtPtr->method & FLAG(METH_READ) */ /* ASSERT: rtPtr->mode & TCL_READABLE */ diff --git a/generic/tclIOSock.c b/generic/tclIOSock.c index 018f9f5..694501f 100644 --- a/generic/tclIOSock.c +++ b/generic/tclIOSock.c @@ -64,8 +64,8 @@ TclSockGetPort( return TCL_ERROR; } if (*portPtr > 0xFFFF) { - Tcl_AppendResult(interp, "couldn't open socket: port number too high", - NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "couldn't open socket: port number too high", -1)); return TCL_ERROR; } return TCL_OK; @@ -100,16 +100,20 @@ TclSockMinimumBuffers( socklen_t len; len = sizeof(int); - getsockopt((SOCKET)(size_t)sock, SOL_SOCKET, SO_SNDBUF, (char *)¤t, &len); + getsockopt((SOCKET)(size_t) sock, SOL_SOCKET, SO_SNDBUF, + (char *) ¤t, &len); if (current < size) { len = sizeof(int); - setsockopt((SOCKET)(size_t)sock, SOL_SOCKET, SO_SNDBUF, (char *)&size, len); + setsockopt((SOCKET)(size_t) sock, SOL_SOCKET, SO_SNDBUF, + (char *) &size, len); } len = sizeof(int); - getsockopt((SOCKET)(size_t)sock, SOL_SOCKET, SO_RCVBUF, (char *)¤t, &len); + getsockopt((SOCKET)(size_t) sock, SOL_SOCKET, SO_RCVBUF, + (char *) ¤t, &len); if (current < size) { len = sizeof(int); - setsockopt((SOCKET)(size_t)sock, SOL_SOCKET, SO_RCVBUF, (char *)&size, len); + setsockopt((SOCKET)(size_t) sock, SOL_SOCKET, SO_RCVBUF, + (char *) &size, len); } return TCL_OK; } @@ -147,24 +151,34 @@ TclCreateSocketAddress( struct addrinfo *p; struct addrinfo *v4head = NULL, *v4ptr = NULL; struct addrinfo *v6head = NULL, *v6ptr = NULL; - char *native = NULL, portstring[TCL_INTEGER_SPACE]; + char *native = NULL, portbuf[TCL_INTEGER_SPACE], *portstring; const char *family = NULL; Tcl_DString ds; int result, i; - TclFormatInt(portstring, port); - if (host != NULL) { native = Tcl_UtfToExternalDString(NULL, host, -1, &ds); } + + /* + * Workaround for OSX's apparent inability to resolve "localhost", "0" + * when the loopback device is the only available network interface. + */ + if (host != NULL && port == 0) { + portstring = NULL; + } else { + TclFormatInt(portbuf, port); + portstring = portbuf; + } (void) memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; + /* * Magic variable to enforce a certain address family - to be superseded * by a TIP that adds explicit switches to [socket] */ + if (interp != NULL) { family = Tcl_GetVar(interp, "::tcl::unsupported::socketAF", 0); if (family != NULL) { @@ -182,7 +196,7 @@ TclCreateSocketAddress( /* * We found some problems when using AI_ADDRCONFIG, e.g. on systems that * have no networking besides the loopback interface and want to resolve - * localhost. See bugs 3385024, 3382419, 3382431. As the advantage of + * localhost. See [Bugs 3385024, 3382419, 3382431]. As the advantage of * using AI_ADDRCONFIG in situations where it works, is probably low, * we'll leave it out for now. After all, it is just an optimisation. * @@ -206,12 +220,11 @@ TclCreateSocketAddress( } if (result != 0) { -#ifdef EAI_SYSTEM /* Doesn't exist on Windows */ - if (result == EAI_SYSTEM) - *errorMsgPtr = Tcl_PosixError(interp); - else -#endif - *errorMsgPtr = gai_strerror(result); + *errorMsgPtr = +#ifdef EAI_SYSTEM /* Doesn't exist on Windows */ + (result == EAI_SYSTEM) ? Tcl_PosixError(interp) : +#endif /* EAI_SYSTEM */ + gai_strerror(result); return 0; } diff --git a/generic/tclIOUtil.c b/generic/tclIOUtil.c index 41a5aac..ab08353 100644 --- a/generic/tclIOUtil.c +++ b/generic/tclIOUtil.c @@ -182,8 +182,8 @@ const Tcl_Filesystem tclNativeFilesystem = { TclpObjRenameFile, TclpObjCopyDirectory, TclpObjLstat, - TclpDlopen, - /* Needs a cast since we're using version_2. */ + /* Needs casts since we're using version_2. */ + (Tcl_FSLoadFileProc *) TclpDlopen, (Tcl_FSGetCwdProc *) TclpGetNativeCwd, TclpObjChdir }; @@ -460,6 +460,7 @@ FsThrExitProc( ckfree(fsRecPtr); fsRecPtr = tmpFsRecPtr; } + tsdPtr->filesystemList = NULL; tsdPtr->initialized = 0; } @@ -647,23 +648,26 @@ TclFSEpochOk( } static void -Claim() +Claim(void) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&fsDataKey); + tsdPtr->claims++; } static void -Disclaim() +Disclaim(void) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&fsDataKey); + tsdPtr->claims--; } int -TclFSEpoch() +TclFSEpoch(void) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&fsDataKey); + return tsdPtr->filesystemEpoch; } @@ -1094,8 +1098,9 @@ Tcl_FSMatchInDirectory( cwd = Tcl_FSGetCwd(NULL); if (cwd == NULL) { if (interp != NULL) { - Tcl_SetResult(interp, "glob couldn't determine " - "the current working directory", TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "glob couldn't determine the current working directory", + -1)); } return TCL_ERROR; } @@ -1572,8 +1577,8 @@ TclGetOpenModeEx( *seekFlagPtr = 0; *binaryPtr = 0; if (interp != NULL) { - Tcl_AppendResult(interp, "illegal access mode \"", modeString, - "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "illegal access mode \"%s\"", modeString)); } return -1; } @@ -1622,8 +1627,9 @@ TclGetOpenModeEx( mode |= O_NOCTTY; #else if (interp != NULL) { - Tcl_AppendResult(interp, "access mode \"", flag, - "\" not supported by this system", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "access mode \"%s\" not supported by this system", + flag)); } ckfree(modeArgv); return -1; @@ -1634,8 +1640,9 @@ TclGetOpenModeEx( mode |= O_NONBLOCK; #else if (interp != NULL) { - Tcl_AppendResult(interp, "access mode \"", flag, - "\" not supported by this system", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "access mode \"%s\" not supported by this system", + flag)); } ckfree(modeArgv); return -1; @@ -1648,9 +1655,10 @@ TclGetOpenModeEx( } else { if (interp != NULL) { - Tcl_AppendResult(interp, "invalid access mode \"", flag, - "\": must be RDONLY, WRONLY, RDWR, APPEND, BINARY, " - "CREAT, EXCL, NOCTTY, NONBLOCK, or TRUNC", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "invalid access mode \"%s\": must be RDONLY, WRONLY, " + "RDWR, APPEND, BINARY, CREAT, EXCL, NOCTTY, NONBLOCK," + " or TRUNC", flag)); } ckfree(modeArgv); return -1; @@ -1661,8 +1669,9 @@ TclGetOpenModeEx( if (!gotRW) { if (interp != NULL) { - Tcl_AppendResult(interp, "access mode must include either" - " RDONLY, WRONLY, or RDWR", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "access mode must include either RDONLY, WRONLY, or RDWR", + -1)); } return -1; } @@ -1721,15 +1730,16 @@ Tcl_FSEvalFileEx( if (Tcl_FSStat(pathPtr, &statBuf) == -1) { Tcl_SetErrno(errno); - Tcl_AppendResult(interp, "couldn't read file \"", - Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't read file \"%s\": %s", + Tcl_GetString(pathPtr), Tcl_PosixError(interp))); return result; } chan = Tcl_FSOpenFileChannel(interp, pathPtr, "r", 0644); if (chan == NULL) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "couldn't read file \"", - Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't read file \"%s\": %s", + Tcl_GetString(pathPtr), Tcl_PosixError(interp))); return result; } @@ -1763,8 +1773,9 @@ Tcl_FSEvalFileEx( if (Tcl_ReadChars(chan, objPtr, 1, 0) < 0) { Tcl_Close(interp, chan); - Tcl_AppendResult(interp, "couldn't read file \"", - Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't read file \"%s\": %s", + Tcl_GetString(pathPtr), Tcl_PosixError(interp))); goto end; } string = Tcl_GetString(objPtr); @@ -1777,8 +1788,9 @@ Tcl_FSEvalFileEx( if (Tcl_ReadChars(chan, objPtr, -1, memcmp(string, "\xef\xbb\xbf", 3)) < 0) { Tcl_Close(interp, chan); - Tcl_AppendResult(interp, "couldn't read file \"", - Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't read file \"%s\": %s", + Tcl_GetString(pathPtr), Tcl_PosixError(interp))); goto end; } @@ -1852,15 +1864,16 @@ TclNREvalFile( if (Tcl_FSStat(pathPtr, &statBuf) == -1) { Tcl_SetErrno(errno); - Tcl_AppendResult(interp, "couldn't read file \"", - Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't read file \"%s\": %s", + Tcl_GetString(pathPtr), Tcl_PosixError(interp))); return TCL_ERROR; } chan = Tcl_FSOpenFileChannel(interp, pathPtr, "r", 0644); if (chan == NULL) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "couldn't read file \"", - Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't read file \"%s\": %s", + Tcl_GetString(pathPtr), Tcl_PosixError(interp))); return TCL_ERROR; } @@ -1894,8 +1907,9 @@ TclNREvalFile( if (Tcl_ReadChars(chan, objPtr, 1, 0) < 0) { Tcl_Close(interp, chan); - Tcl_AppendResult(interp, "couldn't read file \"", - Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't read file \"%s\": %s", + Tcl_GetString(pathPtr), Tcl_PosixError(interp))); Tcl_DecrRefCount(objPtr); return TCL_ERROR; } @@ -1909,8 +1923,9 @@ TclNREvalFile( if (Tcl_ReadChars(chan, objPtr, -1, memcmp(string, "\xef\xbb\xbf", 3)) < 0) { Tcl_Close(interp, chan); - Tcl_AppendResult(interp, "couldn't read file \"", - Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't read file \"%s\": %s", + Tcl_GetString(pathPtr), Tcl_PosixError(interp))); Tcl_DecrRefCount(objPtr); return TCL_ERROR; } @@ -2246,9 +2261,9 @@ Tcl_FSOpenFileChannel( if (seekFlag && Tcl_Seek(retVal, (Tcl_WideInt) 0, SEEK_END) < (Tcl_WideInt) 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not seek to end of file " - "while opening \"", Tcl_GetString(pathPtr), "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not seek to end of file while opening \"%s\": %s", + Tcl_GetString(pathPtr), Tcl_PosixError(interp))); } Tcl_Close(NULL, retVal); return NULL; @@ -2265,8 +2280,9 @@ Tcl_FSOpenFileChannel( Tcl_SetErrno(ENOENT); if (interp != NULL) { - Tcl_AppendResult(interp, "couldn't open \"", Tcl_GetString(pathPtr), - "\": ", Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't open \"%s\": %s", + Tcl_GetString(pathPtr), Tcl_PosixError(interp))); } return NULL; } @@ -2684,9 +2700,9 @@ Tcl_FSGetCwd( Disclaim(); goto cdDidNotChange; } else if (interp != NULL) { - Tcl_AppendResult(interp, - "error getting working directory name: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error getting working directory name: %s", + Tcl_PosixError(interp))); } } Disclaim(); @@ -2760,9 +2776,9 @@ Tcl_FSGetCwd( retCd = proc2(tsdPtr->cwdClientData); if (retCd == NULL && interp != NULL) { - Tcl_AppendResult(interp, - "error getting working directory name: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error getting working directory name: %s", + Tcl_PosixError(interp))); } if (retCd == tsdPtr->cwdClientData) { @@ -3104,7 +3120,7 @@ Tcl_LoadFile( * code. */ const char *const symbols[],/* Names of functions to look up in the file's * symbol table. */ - int flags, /* Flags (unused) */ + int flags, /* Flags */ void *procVPtrs, /* Where to return the addresses corresponding * to symbols[]. */ Tcl_LoadHandle *handlePtr) /* Filled with token for shared library @@ -3129,8 +3145,8 @@ Tcl_LoadFile( } if (fsPtr->loadFileProc != NULL) { - int retVal = fsPtr->loadFileProc(interp, pathPtr, handlePtr, - &unloadProcPtr); + int retVal = ((Tcl_FSLoadFileProc2 *)(fsPtr->loadFileProc)) + (interp, pathPtr, handlePtr, &unloadProcPtr, flags); if (retVal == TCL_OK) { if (*handlePtr == NULL) { @@ -3152,8 +3168,9 @@ Tcl_LoadFile( */ if (Tcl_FSAccess(pathPtr, R_OK) != 0) { - Tcl_AppendResult(interp, "couldn't load library \"", - Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't load library \"%s\": %s", + Tcl_GetString(pathPtr), Tcl_PosixError(interp))); return TCL_ERROR; } @@ -3195,7 +3212,7 @@ Tcl_LoadFile( ret = Tcl_Read(data, buffer, size); Tcl_Close(interp, data); ret = TclpLoadMemory(interp, buffer, size, ret, handlePtr, - &unloadProcPtr); + &unloadProcPtr, flags); if (ret == TCL_OK && *handlePtr != NULL) { goto resolveSymbols; } @@ -3203,7 +3220,7 @@ Tcl_LoadFile( mustCopyToTempAnyway: Tcl_ResetResult(interp); -#endif +#endif /* TCL_LOAD_FROM_MEMORY */ /* * Get a temporary filename to use, first to copy the file into, and then @@ -3223,8 +3240,8 @@ Tcl_LoadFile( Tcl_FSDeleteFile(copyToPtr); Tcl_DecrRefCount(copyToPtr); - Tcl_AppendResult(interp, "couldn't load from current filesystem", - NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "couldn't load from current filesystem", -1)); return TCL_ERROR; } @@ -3266,7 +3283,7 @@ Tcl_LoadFile( Tcl_ResetResult(interp); - retVal = Tcl_LoadFile(interp, copyToPtr, symbols, 0, procPtrs, + retVal = Tcl_LoadFile(interp, copyToPtr, symbols, flags, procPtrs, &newLoadHandle); if (retVal != TCL_OK) { /* @@ -3498,50 +3515,6 @@ DivertUnloadFile( } /* - * This function used to be in the platform specific directories, but it has - * now been made to work cross-platform. - */ - -int -TclpLoadFile( - Tcl_Interp *interp, /* Used for error reporting. */ - Tcl_Obj *pathPtr, /* Name of the file containing the desired - * code (UTF-8). */ - const char *sym1, const char *sym2, - /* Names of two functions to look up in the - * file's symbol table. */ - Tcl_PackageInitProc **proc1Ptr, Tcl_PackageInitProc **proc2Ptr, - /* Where to return the addresses corresponding - * to sym1 and sym2. */ - ClientData *clientDataPtr, /* Filled with token for dynamically loaded - * file which will be passed back to - * (*unloadProcPtr)() to unload the file. */ - Tcl_FSUnloadFileProc **unloadProcPtr) - /* Filled with address of Tcl_FSUnloadFileProc - * function which should be used for this - * file. */ -{ - Tcl_LoadHandle handle = NULL; - int res; - - res = TclpDlopen(interp, pathPtr, &handle, unloadProcPtr); - - if (res != TCL_OK) { - return res; - } - - if (handle == NULL) { - return TCL_ERROR; - } - - *clientDataPtr = handle; - - *proc1Ptr = (Tcl_PackageInitProc*) Tcl_FindSymbol(interp, handle, sym1); - *proc2Ptr = (Tcl_PackageInitProc*) Tcl_FindSymbol(interp, handle, sym2); - return TCL_OK; -} - -/* *---------------------------------------------------------------------- * * Tcl_FindSymbol -- diff --git a/generic/tclIndexObj.c b/generic/tclIndexObj.c index 85e0730..731d759 100644 --- a/generic/tclIndexObj.c +++ b/generic/tclIndexObj.c @@ -600,8 +600,9 @@ PrefixMatchObjCmd( flags |= TCL_EXACT; break; case PRFMATCH_MESSAGE: - if (i > (objc - 4)) { - Tcl_AppendResult(interp, "missing message", NULL); + if (i > objc-4) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "missing value for -message", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "NOARG", NULL); return TCL_ERROR; } @@ -610,7 +611,8 @@ PrefixMatchObjCmd( break; case PRFMATCH_ERROR: if (i > objc-4) { - Tcl_AppendResult(interp, "missing error options", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "missing value for -error", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "NOARG", NULL); return TCL_ERROR; } @@ -620,8 +622,9 @@ PrefixMatchObjCmd( return TCL_ERROR; } if ((errorLength % 2) != 0) { - Tcl_AppendResult(interp, "error options must have an even" - " number of elements", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "error options must have an even number of elements", + -1)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "DICTIONARY", NULL); return TCL_ERROR; } @@ -1174,8 +1177,8 @@ Tcl_ParseArgsObjv( goto gotMatch; } if (matchPtr != NULL) { - Tcl_AppendResult(interp, "ambiguous option \"", str, "\"", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "ambiguous option \"%s\"", str)); goto error; } matchPtr = infoPtr; @@ -1187,8 +1190,8 @@ Tcl_ParseArgsObjv( */ if (remObjv == NULL) { - Tcl_AppendResult(interp, "unrecognized argument \"", str, - "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unrecognized argument \"%s\"", str)); goto error; } @@ -1213,9 +1216,9 @@ Tcl_ParseArgsObjv( } if (Tcl_GetIntFromObj(interp, objv[srcIndex], (int *) infoPtr->dstPtr) == TCL_ERROR) { - Tcl_AppendResult(interp, "expected integer argument for \"", - infoPtr->keyStr, "\" but got \"", - Tcl_GetString(objv[srcIndex]), "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "expected integer argument for \"%s\" but got \"%s\"", + infoPtr->keyStr, Tcl_GetString(objv[srcIndex]))); goto error; } srcIndex++; @@ -1246,9 +1249,9 @@ Tcl_ParseArgsObjv( } if (Tcl_GetDoubleFromObj(interp, objv[srcIndex], (double *) infoPtr->dstPtr) == TCL_ERROR) { - Tcl_AppendResult(interp, "expected floating-point argument ", - "for \"", infoPtr->keyStr, "\" but got \"", - Tcl_GetString(objv[srcIndex]), "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "expected floating-point argument for \"%s\" but got \"%s\"", + infoPtr->keyStr, Tcl_GetString(objv[srcIndex]))); goto error; } srcIndex++; @@ -1322,8 +1325,8 @@ Tcl_ParseArgsObjv( */ missingArg: - Tcl_AppendResult(interp, "\"", str, - "\" option requires an additional argument", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "\"%s\" option requires an additional argument", str)); error: if (leftovers != NULL) { ckfree(leftovers); @@ -1361,6 +1364,7 @@ PrintUsage( #define NUM_SPACES 20 static const char spaces[] = " "; char tmp[TCL_DOUBLE_SPACE]; + Tcl_Obj *msg; /* * First, compute the width of the widest option key, so that we can make @@ -1384,39 +1388,39 @@ PrintUsage( * Now add the option information, with pretty-printing. */ - Tcl_AppendResult(interp, "Command-specific options:", NULL); + msg = Tcl_NewStringObj("Command-specific options:", -1); for (infoPtr = argTable; infoPtr->type != TCL_ARGV_END; infoPtr++) { if ((infoPtr->type == TCL_ARGV_HELP) && (infoPtr->keyStr == NULL)) { - Tcl_AppendResult(interp, "\n", infoPtr->helpStr, NULL); + Tcl_AppendPrintfToObj(msg, "\n%s", infoPtr->helpStr); continue; } - Tcl_AppendResult(interp, "\n ", infoPtr->keyStr, ":", NULL); + Tcl_AppendPrintfToObj(msg, "\n %s:", infoPtr->keyStr); numSpaces = width + 1 - strlen(infoPtr->keyStr); while (numSpaces > 0) { if (numSpaces >= NUM_SPACES) { - Tcl_AppendResult(interp, spaces, NULL); + Tcl_AppendToObj(msg, spaces, NUM_SPACES); } else { - Tcl_AppendResult(interp, spaces+NUM_SPACES-numSpaces, NULL); + Tcl_AppendToObj(msg, spaces, numSpaces); } numSpaces -= NUM_SPACES; } - Tcl_AppendResult(interp, infoPtr->helpStr, NULL); + Tcl_AppendToObj(msg, infoPtr->helpStr, -1); switch (infoPtr->type) { case TCL_ARGV_INT: - sprintf(tmp, "%d", *((int *) infoPtr->dstPtr)); - Tcl_AppendResult(interp, "\n\t\tDefault value: ", tmp, NULL); + Tcl_AppendPrintfToObj(msg, "\n\t\tDefault value: %d", + *((int *) infoPtr->dstPtr)); break; case TCL_ARGV_FLOAT: + Tcl_AppendPrintfToObj(msg, "\n\t\tDefault value: %g", + *((double *) infoPtr->dstPtr)); sprintf(tmp, "%g", *((double *) infoPtr->dstPtr)); - Tcl_AppendResult(interp, "\n\t\tDefault value: ", tmp, NULL); break; case TCL_ARGV_STRING: { - char *string; + char *string = *((char **) infoPtr->dstPtr); - string = *((char **) infoPtr->dstPtr); if (string != NULL) { - Tcl_AppendResult(interp, "\n\t\tDefault value: \"", string, - "\"", NULL); + Tcl_AppendPrintfToObj(msg, "\n\t\tDefault value: \"%s\"", + string); } break; } @@ -1424,6 +1428,7 @@ PrintUsage( break; } } + Tcl_SetObjResult(interp, msg); } /* @@ -1435,8 +1440,8 @@ PrintUsage( * * Results: * Returns TCL_ERROR if the value is an invalid completion code. - * Otherwise, returns TCL_OK, and writes the completion code to - * the pointer provided. + * Otherwise, returns TCL_OK, and writes the completion code to the + * pointer provided. * * Side effects: * None. @@ -1448,30 +1453,30 @@ int TclGetCompletionCodeFromObj( Tcl_Interp *interp, /* Current interpreter. */ Tcl_Obj *value, - int *code) /* Argument objects. */ + int *codePtr) /* Argument objects. */ { static const char *const returnCodes[] = { "ok", "error", "return", "break", "continue", NULL }; if ((value->typePtr != &indexType) - && (TCL_OK == TclGetIntFromObj(NULL, value, code))) { + && TclGetIntFromObj(NULL, value, codePtr) == TCL_OK) { return TCL_OK; } - if (TCL_OK == Tcl_GetIndexFromObj(NULL, value, returnCodes, NULL, - TCL_EXACT, code)) { + if (Tcl_GetIndexFromObj(NULL, value, returnCodes, NULL, TCL_EXACT, + codePtr) == TCL_OK) { return TCL_OK; } + /* * Value is not a legal completion code. */ if (interp != NULL) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad completion code \"", - TclGetString(value), - "\": must be ok, error, return, break, " - "continue, or an integer", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad completion code \"%s\": must be" + " ok, error, return, break, continue, or an integer", + TclGetString(value))); Tcl_SetErrorCode(interp, "TCL", "RESULT", "ILLEGAL_CODE", NULL); } return TCL_ERROR; diff --git a/generic/tclInt.decls b/generic/tclInt.decls index 9f73a31..8f8b992 100644 --- a/generic/tclInt.decls +++ b/generic/tclInt.decls @@ -1219,6 +1219,12 @@ declare 14 unix { const Tcl_StatBuf *statBufPtr, int dontCopyAtts) } +# Added in 8.6; core of TclpOpenTemporaryFile +declare 20 unix { + int TclUnixOpenTemporaryFile(Tcl_Obj *dirObj, Tcl_Obj *basenameObj, + Tcl_Obj *extensionObj, Tcl_Obj *resultingNameObj) +} + ################################ # Mac OS X specific functions diff --git a/generic/tclInt.h b/generic/tclInt.h index feb7fd4..9e062ad 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -801,13 +801,17 @@ typedef struct VarInHash { #define TclSetVarNamespaceVar(varPtr) \ if (!TclIsVarNamespaceVar(varPtr)) {\ (varPtr)->flags |= VAR_NAMESPACE_VAR;\ - ((VarInHash *)(varPtr))->refCount++;\ + if (TclIsVarInHash(varPtr)) {\ + ((VarInHash *)(varPtr))->refCount++;\ + }\ } #define TclClearVarNamespaceVar(varPtr) \ if (TclIsVarNamespaceVar(varPtr)) {\ (varPtr)->flags &= ~VAR_NAMESPACE_VAR;\ - ((VarInHash *)(varPtr))->refCount--;\ + if (TclIsVarInHash(varPtr)) {\ + ((VarInHash *)(varPtr))->refCount--;\ + }\ } /* @@ -2467,6 +2471,14 @@ typedef struct List { (((listPtr)->typePtr == &tclListType) ? ListObjIsCanonical((listPtr)) : 0) /* + * Modes for collecting (or not) in the implementations of TclNRForeachCmd, + * TclNRLmapCmd and their compilations. + */ + +#define TCL_EACH_KEEP_NONE 0 /* Discard iteration result like [foreach] */ +#define TCL_EACH_COLLECT 1 /* Collect iteration result like [lmap] */ + +/* * Macros providing a faster path to integers: Tcl_GetLongFromObj everywhere, * Tcl_GetIntFromObj and TclGetIntForIndex on platforms where longs are ints. * @@ -2536,6 +2548,8 @@ typedef struct List { #define TCL_FILESYSTEM_VERSION_2 ((Tcl_FSVersion) 0x2) typedef ClientData (TclFSGetCwdProc2)(ClientData clientData); +typedef int (Tcl_FSLoadFileProc2) (Tcl_Interp *interp, Tcl_Obj *pathPtr, + Tcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr, int flags); /* * The following types are used for getting and storing platform-specific file @@ -2758,6 +2772,7 @@ MODULE_SCOPE Tcl_ObjCmdProc TclNRExprObjCmd; MODULE_SCOPE Tcl_ObjCmdProc TclNRForObjCmd; MODULE_SCOPE Tcl_ObjCmdProc TclNRForeachCmd; MODULE_SCOPE Tcl_ObjCmdProc TclNRIfObjCmd; +MODULE_SCOPE Tcl_ObjCmdProc TclNRLmapCmd; MODULE_SCOPE Tcl_ObjCmdProc TclNRSourceObjCmd; MODULE_SCOPE Tcl_ObjCmdProc TclNRSubstObjCmd; MODULE_SCOPE Tcl_ObjCmdProc TclNRSwitchObjCmd; @@ -2766,7 +2781,9 @@ MODULE_SCOPE Tcl_ObjCmdProc TclNRUplevelObjCmd; MODULE_SCOPE Tcl_ObjCmdProc TclNRWhileObjCmd; MODULE_SCOPE Tcl_NRPostProc TclNRForIterCallback; +MODULE_SCOPE Tcl_NRPostProc TclNRCoroutineActivateCallback; MODULE_SCOPE Tcl_ObjCmdProc TclNRTailcallObjCmd; +MODULE_SCOPE Tcl_NRPostProc TclNRTailcallEval; MODULE_SCOPE Tcl_ObjCmdProc TclNRCoroutineObjCmd; MODULE_SCOPE Tcl_ObjCmdProc TclNRYieldObjCmd; MODULE_SCOPE Tcl_ObjCmdProc TclNRYieldmObjCmd; @@ -3053,12 +3070,6 @@ MODULE_SCOPE void TclpInitLibraryPath(char **valuePtr, MODULE_SCOPE void TclpInitLock(void); MODULE_SCOPE void TclpInitPlatform(void); MODULE_SCOPE void TclpInitUnlock(void); -MODULE_SCOPE int TclpLoadFile(Tcl_Interp *interp, Tcl_Obj *pathPtr, - const char *sym1, const char *sym2, - Tcl_PackageInitProc **proc1Ptr, - Tcl_PackageInitProc **proc2Ptr, - ClientData *clientDataPtr, - Tcl_FSUnloadFileProc **unloadProcPtr); MODULE_SCOPE Tcl_Obj * TclpObjListVolumes(void); MODULE_SCOPE void TclpMasterLock(void); MODULE_SCOPE void TclpMasterUnlock(void); @@ -3137,13 +3148,13 @@ MODULE_SCOPE Tcl_Obj * TclpNativeToNormalized(ClientData clientData); MODULE_SCOPE Tcl_Obj * TclpFilesystemPathType(Tcl_Obj *pathPtr); MODULE_SCOPE int TclpDlopen(Tcl_Interp *interp, Tcl_Obj *pathPtr, Tcl_LoadHandle *loadHandle, - Tcl_FSUnloadFileProc **unloadProcPtr); + Tcl_FSUnloadFileProc **unloadProcPtr, int flags); MODULE_SCOPE int TclpUtime(Tcl_Obj *pathPtr, struct utimbuf *tval); #ifdef TCL_LOAD_FROM_MEMORY MODULE_SCOPE void * TclpLoadMemoryGetBuffer(Tcl_Interp *interp, int size); MODULE_SCOPE int TclpLoadMemory(Tcl_Interp *interp, void *buffer, int size, int codeSize, Tcl_LoadHandle *loadHandle, - Tcl_FSUnloadFileProc **unloadProcPtr); + Tcl_FSUnloadFileProc **unloadProcPtr, int flags); #endif MODULE_SCOPE void TclInitThreadStorage(void); MODULE_SCOPE void TclFinalizeThreadDataThread(void); @@ -3326,6 +3337,9 @@ MODULE_SCOPE int Tcl_LlengthObjCmd(ClientData clientData, MODULE_SCOPE int Tcl_ListObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); +MODULE_SCOPE int Tcl_LmapObjCmd(ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *const objv[]); MODULE_SCOPE int Tcl_LoadObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); @@ -3461,6 +3475,15 @@ MODULE_SCOPE int Tcl_WhileObjCmd(ClientData clientData, MODULE_SCOPE int TclCompileAppendCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileArrayExistsCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileArraySetCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileArrayUnsetCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileBreakCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); @@ -3473,6 +3496,12 @@ MODULE_SCOPE int TclCompileContinueCmd(Tcl_Interp *interp, MODULE_SCOPE int TclCompileDictAppendCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileDictCreateCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileDictExistsCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileDictForCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); @@ -3485,9 +3514,18 @@ MODULE_SCOPE int TclCompileDictIncrCmd(Tcl_Interp *interp, MODULE_SCOPE int TclCompileDictLappendCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileDictMapCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileDictMergeCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileDictSetCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileDictUnsetCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileDictUpdateCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); @@ -3509,15 +3547,36 @@ MODULE_SCOPE int TclCompileForCmd(Tcl_Interp *interp, MODULE_SCOPE int TclCompileForeachCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileFormatCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileGlobalCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileIfCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileInfoCommandsCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileInfoCoroutineCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileInfoExistsCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileInfoLevelCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileInfoObjectClassCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileInfoObjectIsACmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileInfoObjectNamespaceCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileIncrCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); @@ -3536,6 +3595,9 @@ MODULE_SCOPE int TclCompileListCmd(Tcl_Interp *interp, MODULE_SCOPE int TclCompileLlengthCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileLmapCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileLrangeCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); @@ -3545,15 +3607,36 @@ MODULE_SCOPE int TclCompileLreplaceCmd(Tcl_Interp *interp, MODULE_SCOPE int TclCompileLsetCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileNamespaceCodeCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileNamespaceCurrentCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileNamespaceQualifiersCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileNamespaceTailCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileNamespaceUpvarCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileNamespaceWhichCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileNoOp(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileObjectSelfCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileRegexpCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileRegsubCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileReturnCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); @@ -3566,21 +3649,36 @@ MODULE_SCOPE int TclCompileStringCmpCmd(Tcl_Interp *interp, MODULE_SCOPE int TclCompileStringEqualCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileStringFirstCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileStringIndexCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileStringLastCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileStringLenCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileStringMapCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileStringMatchCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileStringRangeCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileSubstCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileSwitchCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileTailcallCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileThrowCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); @@ -3599,6 +3697,9 @@ MODULE_SCOPE int TclCompileVariableCmd(Tcl_Interp *interp, MODULE_SCOPE int TclCompileWhileCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileYieldCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); MODULE_SCOPE int TclInvertOpCmd(ClientData clientData, Tcl_Interp *interp, int objc, diff --git a/generic/tclIntDecls.h b/generic/tclIntDecls.h index d01d10a..df5ac97 100644 --- a/generic/tclIntDecls.h +++ b/generic/tclIntDecls.h @@ -604,7 +604,7 @@ EXTERN void TclSetSlaveCancelFlags(Tcl_Interp *interp, int flags, typedef struct TclIntStubs { int magic; - const struct TclIntStubHooks *hooks; + void *hooks; void (*reserved0)(void); void (*reserved1)(void); diff --git a/generic/tclIntPlatDecls.h b/generic/tclIntPlatDecls.h index 7322a37..f265e7e 100644 --- a/generic/tclIntPlatDecls.h +++ b/generic/tclIntPlatDecls.h @@ -84,7 +84,10 @@ EXTERN int TclUnixCopyFile(const char *src, const char *dst, /* Slot 17 is reserved */ /* Slot 18 is reserved */ /* Slot 19 is reserved */ -/* Slot 20 is reserved */ +/* 20 */ +EXTERN int TclUnixOpenTemporaryFile(Tcl_Obj *dirObj, + Tcl_Obj *basenameObj, Tcl_Obj *extensionObj, + Tcl_Obj *resultingNameObj); /* Slot 21 is reserved */ /* Slot 22 is reserved */ /* Slot 23 is reserved */ @@ -225,7 +228,10 @@ EXTERN int TclMacOSXMatchType(Tcl_Interp *interp, /* 19 */ EXTERN void TclMacOSXNotifierAddRunLoopMode( const void *runLoopMode); -/* Slot 20 is reserved */ +/* 20 */ +EXTERN int TclUnixOpenTemporaryFile(Tcl_Obj *dirObj, + Tcl_Obj *basenameObj, Tcl_Obj *extensionObj, + Tcl_Obj *resultingNameObj); /* Slot 21 is reserved */ /* Slot 22 is reserved */ /* Slot 23 is reserved */ @@ -240,7 +246,7 @@ EXTERN int TclWinCPUID(unsigned int index, unsigned int *regs); typedef struct TclIntPlatStubs { int magic; - const struct TclIntPlatStubHooks *hooks; + void *hooks; #if !defined(__WIN32__) && !defined(__CYGWIN__) && !defined(MAC_OSX_TCL) /* UNIX */ void (*tclGetAndDetachPids) (Tcl_Interp *interp, Tcl_Channel chan); /* 0 */ @@ -263,7 +269,7 @@ typedef struct TclIntPlatStubs { void (*reserved17)(void); void (*reserved18)(void); void (*reserved19)(void); - void (*reserved20)(void); + int (*tclUnixOpenTemporaryFile) (Tcl_Obj *dirObj, Tcl_Obj *basenameObj, Tcl_Obj *extensionObj, Tcl_Obj *resultingNameObj); /* 20 */ void (*reserved21)(void); void (*reserved22)(void); void (*reserved23)(void); @@ -327,7 +333,7 @@ typedef struct TclIntPlatStubs { int (*tclMacOSXCopyFileAttributes) (const char *src, const char *dst, const Tcl_StatBuf *statBufPtr); /* 17 */ int (*tclMacOSXMatchType) (Tcl_Interp *interp, const char *pathName, const char *fileName, Tcl_StatBuf *statBufPtr, Tcl_GlobTypeData *types); /* 18 */ void (*tclMacOSXNotifierAddRunLoopMode) (const void *runLoopMode); /* 19 */ - void (*reserved20)(void); + int (*tclUnixOpenTemporaryFile) (Tcl_Obj *dirObj, Tcl_Obj *basenameObj, Tcl_Obj *extensionObj, Tcl_Obj *resultingNameObj); /* 20 */ void (*reserved21)(void); void (*reserved22)(void); void (*reserved23)(void); @@ -389,7 +395,8 @@ extern const TclIntPlatStubs *tclIntPlatStubsPtr; /* Slot 17 is reserved */ /* Slot 18 is reserved */ /* Slot 19 is reserved */ -/* Slot 20 is reserved */ +#define TclUnixOpenTemporaryFile \ + (tclIntPlatStubsPtr->tclUnixOpenTemporaryFile) /* 20 */ /* Slot 21 is reserved */ /* Slot 22 is reserved */ /* Slot 23 is reserved */ @@ -501,7 +508,8 @@ extern const TclIntPlatStubs *tclIntPlatStubsPtr; (tclIntPlatStubsPtr->tclMacOSXMatchType) /* 18 */ #define TclMacOSXNotifierAddRunLoopMode \ (tclIntPlatStubsPtr->tclMacOSXNotifierAddRunLoopMode) /* 19 */ -/* Slot 20 is reserved */ +#define TclUnixOpenTemporaryFile \ + (tclIntPlatStubsPtr->tclUnixOpenTemporaryFile) /* 20 */ /* Slot 21 is reserved */ /* Slot 22 is reserved */ /* Slot 23 is reserved */ @@ -525,7 +533,10 @@ extern const TclIntPlatStubs *tclIntPlatStubsPtr; #undef TclWinConvertWSAError #define TclWinConvertWSAError TclWinConvertError -#if !defined(__WIN32__) && !defined(__CYGWIN__) +#if defined(__WIN32__) || defined(__CYGWIN__) +# undef TclWinNToHS +# define TclWinNToHS ntohs +#else # undef TclpGetPid # define TclpGetPid(pid) ((unsigned long) (pid)) #endif diff --git a/generic/tclInterp.c b/generic/tclInterp.c index 5b6d14f..0b0f652 100644 --- a/generic/tclInterp.c +++ b/generic/tclInterp.c @@ -1043,18 +1043,18 @@ Tcl_InterpObjCmd( iiPtr = (InterpInfo *) ((Interp *) slaveInterp)->interpInfo; hPtr = Tcl_FindHashEntry(&iiPtr->slave.aliasTable, aliasName); if (hPtr == NULL) { - Tcl_AppendResult(interp, "alias \"", aliasName, "\" in path \"", - Tcl_GetString(objv[2]), "\" not found", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "alias \"%s\" in path \"%s\" not found", + aliasName, Tcl_GetString(objv[2]))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ALIAS", aliasName, NULL); return TCL_ERROR; } aliasPtr = Tcl_GetHashValue(hPtr); if (Tcl_GetInterpPath(interp, aliasPtr->targetInterp) != TCL_OK) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "target interpreter for alias \"", - aliasName, "\" in path \"", Tcl_GetString(objv[2]), - "\" is not my descendant", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "target interpreter for alias \"%s\" in path \"%s\" is " + "not my descendant", aliasName, Tcl_GetString(objv[2]))); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "INTERP", "TARGETSHROUDED", NULL); return TCL_ERROR; @@ -1234,7 +1234,8 @@ Tcl_GetAlias( hPtr = Tcl_FindHashEntry(&iiPtr->slave.aliasTable, aliasName); if (hPtr == NULL) { - Tcl_AppendResult(interp, "alias \"", aliasName, "\" not found", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "alias \"%s\" not found", aliasName)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ALIAS", aliasName, NULL); return TCL_ERROR; } @@ -1295,7 +1296,8 @@ Tcl_GetAliasObj( hPtr = Tcl_FindHashEntry(&iiPtr->slave.aliasTable, aliasName); if (hPtr == NULL) { - Tcl_AppendResult(interp, "alias \"", aliasName, "\" not found", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "alias \"%s\" not found", aliasName)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ALIAS", aliasName, NULL); return TCL_ERROR; } @@ -1383,9 +1385,9 @@ TclPreventAliasLoop( * [Bug #641195] */ - Tcl_AppendResult(interp, "cannot define or rename alias \"", - Tcl_GetCommandName(cmdInterp, cmd), - "\": interpreter deleted", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "cannot define or rename alias \"%s\": interpreter deleted", + Tcl_GetCommandName(cmdInterp, cmd))); return TCL_ERROR; } cmdNamePtr = nextAliasPtr->objPtr; @@ -1398,9 +1400,9 @@ TclPreventAliasLoop( } aliasCmdPtr = (Command *) aliasCmd; if (aliasCmdPtr == cmdPtr) { - Tcl_AppendResult(interp, "cannot define or rename alias \"", - Tcl_GetCommandName(cmdInterp, cmd), - "\": would create a loop", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "cannot define or rename alias \"%s\": would create a loop", + Tcl_GetCommandName(cmdInterp, cmd))); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "INTERP", "ALIASLOOP", NULL); return TCL_ERROR; @@ -1621,8 +1623,8 @@ AliasDelete( slavePtr = &((InterpInfo *) ((Interp *) slaveInterp)->interpInfo)->slave; hPtr = Tcl_FindHashEntry(&slavePtr->aliasTable, TclGetString(namePtr)); if (hPtr == NULL) { - Tcl_AppendResult(interp, "alias \"", TclGetString(namePtr), - "\" not found", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "alias \"%s\" not found", TclGetString(namePtr))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ALIAS", TclGetString(namePtr), NULL); return TCL_ERROR; @@ -2154,17 +2156,19 @@ Tcl_GetInterpPath( InterpInfo *iiPtr; if (targetInterp == askingInterp) { + Tcl_SetObjResult(askingInterp, Tcl_NewObj()); return TCL_OK; } if (targetInterp == NULL) { return TCL_ERROR; } iiPtr = (InterpInfo *) ((Interp *) targetInterp)->interpInfo; - if (Tcl_GetInterpPath(askingInterp, iiPtr->slave.masterInterp) != TCL_OK) { + if (Tcl_GetInterpPath(askingInterp, iiPtr->slave.masterInterp) != TCL_OK){ return TCL_ERROR; } - Tcl_AppendElement(askingInterp, Tcl_GetHashKey(&iiPtr->master.slaveTable, - iiPtr->slave.slaveEntryPtr)); + Tcl_ListObjAppendElement(NULL, Tcl_GetObjResult(askingInterp), + Tcl_NewStringObj(Tcl_GetHashKey(&iiPtr->master.slaveTable, + iiPtr->slave.slaveEntryPtr), -1)); return TCL_OK; } @@ -2218,8 +2222,8 @@ GetInterp( } } if (searchInterp == NULL) { - Tcl_AppendResult(interp, "could not find interpreter \"", - TclGetString(pathPtr), "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not find interpreter \"%s\"", TclGetString(pathPtr))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "INTERP", TclGetString(pathPtr), NULL); } @@ -2256,8 +2260,8 @@ SlaveBgerror( if (TCL_ERROR == TclListObjLength(NULL, objv[0], &length) || (length < 1)) { - Tcl_AppendResult(interp, "cmdPrefix must be list of length >= 1", - NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "cmdPrefix must be list of length >= 1", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "INTERP", "BGERRORFORMAT", NULL); return TCL_ERROR; @@ -2326,8 +2330,9 @@ SlaveCreate( hPtr = Tcl_CreateHashEntry(&masterInfoPtr->master.slaveTable, path, &isNew); if (isNew == 0) { - Tcl_AppendResult(interp, "interpreter named \"", path, - "\" already exists, cannot create", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "interpreter named \"%s\" already exists, cannot create", + path)); return NULL; } @@ -2860,8 +2865,8 @@ SlaveRecursionLimit( if (objc) { if (Tcl_IsSafe(interp)) { - Tcl_AppendResult(interp, "permission denied: " - "safe interpreters cannot change recursion limit", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj("permission denied: " + "safe interpreters cannot change recursion limit", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "INTERP", "UNSAFE", NULL); return TCL_ERROR; @@ -3320,8 +3325,8 @@ Tcl_LimitCheck( if (iPtr->limit.cmdCount >= iPtr->cmdCount) { iPtr->limit.exceeded &= ~TCL_LIMIT_COMMANDS; } else if (iPtr->limit.exceeded & TCL_LIMIT_COMMANDS) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "command count limit exceeded", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "command count limit exceeded", -1)); Tcl_SetErrorCode(interp, "TCL", "LIMIT", "COMMANDS", NULL); Tcl_Release(interp); return TCL_ERROR; @@ -3346,8 +3351,8 @@ Tcl_LimitCheck( iPtr->limit.time.usec >= now.usec)) { iPtr->limit.exceeded &= ~TCL_LIMIT_TIME; } else if (iPtr->limit.exceeded & TCL_LIMIT_TIME) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "time limit exceeded", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "time limit exceeded", -1)); Tcl_SetErrorCode(interp, "TCL", "LIMIT", "TIME", NULL); Tcl_Release(interp); return TCL_ERROR; @@ -4353,8 +4358,9 @@ SlaveCommandLimitCmd( */ if (interp == slaveInterp) { - Tcl_AppendResult(interp, - "limits on current interpreter inaccessible", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "limits on current interpreter inaccessible", -1)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "INTERP", "SELF", NULL); return TCL_ERROR; } @@ -4450,8 +4456,8 @@ SlaveCommandLimitCmd( return TCL_ERROR; } if (gran < 1) { - Tcl_AppendResult(interp, "granularity must be at " - "least 1", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "granularity must be at least 1", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "INTERP", "BADVALUE", NULL); return TCL_ERROR; @@ -4467,8 +4473,8 @@ SlaveCommandLimitCmd( return TCL_ERROR; } if (limit < 0) { - Tcl_AppendResult(interp, "command limit value must be at " - "least 0", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "command limit value must be at least 0", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "INTERP", "BADVALUE", NULL); return TCL_ERROR; @@ -4540,8 +4546,9 @@ SlaveTimeLimitCmd( */ if (interp == slaveInterp) { - Tcl_AppendResult(interp, - "limits on current interpreter inaccessible", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "limits on current interpreter inaccessible", -1)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "INTERP", "SELF", NULL); return TCL_ERROR; } @@ -4658,8 +4665,8 @@ SlaveTimeLimitCmd( return TCL_ERROR; } if (gran < 1) { - Tcl_AppendResult(interp, "granularity must be at " - "least 1", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "granularity must be at least 1", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "INTERP", "BADVALUE", NULL); return TCL_ERROR; @@ -4675,13 +4682,13 @@ SlaveTimeLimitCmd( return TCL_ERROR; } if (tmp < 0) { - Tcl_AppendResult(interp, "milliseconds must be at least 0", - NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "milliseconds must be at least 0", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "INTERP", "BADVALUE", NULL); return TCL_ERROR; } - limitMoment.usec = ((long)tmp)*1000; + limitMoment.usec = ((long) tmp)*1000; break; case OPT_SEC: secObj = objv[i+1]; @@ -4693,8 +4700,8 @@ SlaveTimeLimitCmd( return TCL_ERROR; } if (tmp < 0) { - Tcl_AppendResult(interp, "seconds must be at least 0", - NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "seconds must be at least 0", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "INTERP", "BADVALUE", NULL); return TCL_ERROR; @@ -4711,15 +4718,17 @@ SlaveTimeLimitCmd( */ if (secObj != NULL && secLen == 0 && milliLen > 0) { - Tcl_AppendResult(interp, "may only set -milliseconds " - "if -seconds is not also being reset", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "may only set -milliseconds if -seconds is not " + "also being reset", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "INTERP", "BADUSAGE", NULL); return TCL_ERROR; } if (milliLen == 0 && (secObj == NULL || secLen > 0)) { - Tcl_AppendResult(interp, "may only reset -milliseconds " - "if -seconds is also being reset", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "may only reset -milliseconds if -seconds is " + "also being reset", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "INTERP", "BADUSAGE", NULL); return TCL_ERROR; diff --git a/generic/tclLoad.c b/generic/tclLoad.c index ce4d6a4..5cacab1 100644 --- a/generic/tclLoad.c +++ b/generic/tclLoad.c @@ -132,9 +132,34 @@ Tcl_LoadObjCmd( Tcl_LoadHandle loadHandle; Tcl_UniChar ch; unsigned len; + int index, flags = 0; + Tcl_Obj *const *savedobjv = objv; + static const char *const options[] = { + "-global", "-lazy", "--", NULL + }; + enum options { + LOAD_GLOBAL, LOAD_LAZY, LOAD_LAST + }; + while (objc > 2) { + if (TclGetString(objv[1])[0] != '-') { + break; + } + if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + ++objv; --objc; + if (LOAD_GLOBAL == (enum options) index) { + flags |= TCL_LOAD_GLOBAL; + } else if (LOAD_LAZY == (enum options) index) { + flags |= TCL_LOAD_LAZY; + } else { + break; + } + } if ((objc < 2) || (objc > 4)) { - Tcl_WrongNumArgs(interp, 1, objv, "fileName ?packageName? ?interp?"); + Tcl_WrongNumArgs(interp, 1, savedobjv, "?-global? ?-lazy? ?--? fileName ?packageName? ?interp?"); return TCL_ERROR; } if (Tcl_FSConvertToPathType(interp, objv[1]) != TCL_OK) { @@ -157,9 +182,8 @@ Tcl_LoadObjCmd( } } if ((fullFileName[0] == 0) && (packageName == NULL)) { - Tcl_SetResult(interp, - "must specify either file name or package name", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "must specify either file name or package name", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LOAD", "NOLIBRARY", NULL); code = TCL_ERROR; @@ -225,9 +249,9 @@ Tcl_LoadObjCmd( * Can't have two different packages loaded from the same file. */ - Tcl_AppendResult(interp, "file \"", fullFileName, - "\" is already loaded for package \"", - pkgPtr->packageName, "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "file \"%s\" is already loaded for package \"%s\"", + fullFileName, pkgPtr->packageName)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LOAD", "SPLITPERSONALITY", NULL); code = TCL_ERROR; @@ -263,8 +287,8 @@ Tcl_LoadObjCmd( */ if (fullFileName[0] == 0) { - Tcl_AppendResult(interp, "package \"", packageName, - "\" isn't loaded statically", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "package \"%s\" isn't loaded statically", packageName)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LOAD", "NOTSTATIC", NULL); code = TCL_ERROR; @@ -321,9 +345,9 @@ Tcl_LoadObjCmd( } if (p == pkgGuess) { Tcl_DecrRefCount(splitPtr); - Tcl_AppendResult(interp, - "couldn't figure out package name for ", - fullFileName, NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't figure out package name for %s", + fullFileName)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LOAD", "WHATPACKAGE", NULL); code = TCL_ERROR; @@ -366,7 +390,7 @@ Tcl_LoadObjCmd( symbols[1] = NULL; Tcl_MutexLock(&packageMutex); - code = Tcl_LoadFile(interp, objv[1], symbols, 0, &initProc, + code = Tcl_LoadFile(interp, objv[1], symbols, flags, &initProc, &loadHandle); Tcl_MutexUnlock(&packageMutex); if (code != TCL_OK) { @@ -392,7 +416,7 @@ Tcl_LoadObjCmd( pkgPtr->unloadProc = (Tcl_PackageUnloadProc *) Tcl_FindSymbol(interp, loadHandle, Tcl_DStringValue(&unloadName)); - pkgPtr->safeUnloadProc = (Tcl_PackageUnloadProc *) + pkgPtr->safeUnloadProc = (Tcl_PackageUnloadProc *) Tcl_FindSymbol(interp, loadHandle, Tcl_DStringValue(&safeUnloadName)); pkgPtr->interpRefCount = 0; @@ -418,9 +442,9 @@ Tcl_LoadObjCmd( if (Tcl_IsSafe(target)) { if (pkgPtr->safeInitProc == NULL) { - Tcl_AppendResult(interp, - "can't use package in a safe interpreter: no ", - pkgPtr->packageName, "_SafeInit procedure", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't use package in a safe interpreter: no" + " %s_SafeInit procedure", pkgPtr->packageName)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LOAD", "UNSAFE", NULL); code = TCL_ERROR; @@ -429,9 +453,9 @@ Tcl_LoadObjCmd( code = pkgPtr->safeInitProc(target); } else { if (pkgPtr->initProc == NULL) { - Tcl_AppendResult(interp, - "can't attach package to interpreter: no ", - pkgPtr->packageName, "_Init procedure", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't attach package to interpreter: no %s_Init procedure", + pkgPtr->packageName)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LOAD", "ENTRYPOINT", NULL); code = TCL_ERROR; @@ -581,9 +605,8 @@ Tcl_UnloadObjCmd( } } if ((fullFileName[0] == 0) && (packageName == NULL)) { - Tcl_SetResult(interp, - "must specify either file name or package name", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "must specify either file name or package name", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "UNLOAD", "NOLIBRARY", NULL); code = TCL_ERROR; @@ -655,8 +678,9 @@ Tcl_UnloadObjCmd( * It's an error to try unload a static package. */ - Tcl_AppendResult(interp, "package \"", packageName, - "\" is loaded statically and cannot be unloaded", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "package \"%s\" is loaded statically and cannot be unloaded", + packageName)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "UNLOAD", "STATIC", NULL); code = TCL_ERROR; @@ -667,8 +691,8 @@ Tcl_UnloadObjCmd( * The DLL pointed by the provided filename has never been loaded. */ - Tcl_AppendResult(interp, "file \"", fullFileName, - "\" has never been loaded", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "file \"%s\" has never been loaded", fullFileName)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "UNLOAD", "NEVERLOADED", NULL); code = TCL_ERROR; @@ -696,8 +720,9 @@ Tcl_UnloadObjCmd( * The package has not been loaded in this interpreter. */ - Tcl_AppendResult(interp, "file \"", fullFileName, - "\" has never been loaded in this interpreter", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "file \"%s\" has never been loaded in this interpreter", + fullFileName)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "UNLOAD", "NEVERLOADED", NULL); code = TCL_ERROR; @@ -712,8 +737,9 @@ Tcl_UnloadObjCmd( if (Tcl_IsSafe(target)) { if (pkgPtr->safeUnloadProc == NULL) { - Tcl_AppendResult(interp, "file \"", fullFileName, - "\" cannot be unloaded under a safe interpreter", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "file \"%s\" cannot be unloaded under a safe interpreter", + fullFileName)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "UNLOAD", "CANNOT", NULL); code = TCL_ERROR; @@ -722,8 +748,9 @@ Tcl_UnloadObjCmd( unloadProc = pkgPtr->safeUnloadProc; } else { if (pkgPtr->unloadProc == NULL) { - Tcl_AppendResult(interp, "file \"", fullFileName, - "\" cannot be unloaded under a trusted interpreter", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "file \"%s\" cannot be unloaded under a trusted interpreter", + fullFileName)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "UNLOAD", "CANNOT", NULL); code = TCL_ERROR; @@ -862,8 +889,9 @@ Tcl_UnloadObjCmd( } } #else - Tcl_AppendResult(interp, "file \"", fullFileName, - "\" cannot be unloaded: unloading disabled", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "file \"%s\" cannot be unloaded: unloading disabled", + fullFileName)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "UNLOAD", "DISABLED", NULL); code = TCL_ERROR; diff --git a/generic/tclLoadNone.c b/generic/tclLoadNone.c index ac094e6..f030d89 100644 --- a/generic/tclLoadNone.c +++ b/generic/tclLoadNone.c @@ -39,14 +39,15 @@ TclpDlopen( Tcl_LoadHandle *loadHandle, /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ - Tcl_FSUnloadFileProc **unloadProcPtr) + Tcl_FSUnloadFileProc **unloadProcPtr, /* Filled with address of Tcl_FSUnloadFileProc * function which should be used for this * file. */ + int flags) { - Tcl_SetResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "dynamic loading is not currently available on this system", - TCL_STATIC); + -1)); return TCL_ERROR; } diff --git a/generic/tclMain.c b/generic/tclMain.c index 88b4e51..f445383 100644 --- a/generic/tclMain.c +++ b/generic/tclMain.c @@ -16,11 +16,12 @@ * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ -/** - * On Windows, this file needs to be compiled twice, once with - * TCL_ASCII_MAIN defined. This way both Tcl_Main and Tcl_MainExW - * can be implemented, sharing the same source code. +/* + * On Windows, this file needs to be compiled twice, once with TCL_ASCII_MAIN + * defined. This way both Tcl_Main and Tcl_MainExW can be implemented, sharing + * the same source code. */ + #if defined(TCL_ASCII_MAIN) # ifdef UNICODE # undef UNICODE @@ -40,12 +41,12 @@ #define DEFAULT_PRIMARY_PROMPT "% " /* - * This file can be compiled on Windows in UNICODE mode, as well as - * on all other platforms using the native encoding. This is done - * by using the normal Windows functions like _tcscmp, but on - * platforms which don't have <tchar.h> we have to translate that - * to strcmp here. + * This file can be compiled on Windows in UNICODE mode, as well as on all + * other platforms using the native encoding. This is done by using the normal + * Windows functions like _tcscmp, but on platforms which don't have <tchar.h> + * we have to translate that to strcmp here. */ + #ifndef __WIN32__ # define TCHAR char # define TEXT(arg) arg @@ -128,10 +129,11 @@ typedef struct InteractiveState { MODULE_SCOPE Tcl_MainLoopProc *TclGetMainLoop(void); static void Prompt(Tcl_Interp *interp, InteractiveState *isPtr); static void StdinProc(ClientData clientData, int mask); -static void FreeMainInterp(ClientData clientData); +static void FreeMainInterp(ClientData clientData); #ifndef TCL_ASCII_MAIN static Tcl_ThreadDataKey dataKey; + /* *---------------------------------------------------------------------- * @@ -332,13 +334,14 @@ Tcl_MainEx( */ if ((argc > 3) && (0 == _tcscmp(TEXT("-encoding"), argv[1])) - && (TEXT('-') != argv[3][0])) { - Tcl_Obj *value = NewNativeObj(argv[2], -1); - Tcl_SetStartupScript(NewNativeObj(argv[3], -1), Tcl_GetString(value)); + && ('-' != argv[3][0])) { + Tcl_Obj *value = NewNativeObj(argv[2], -1); + Tcl_SetStartupScript(NewNativeObj(argv[3], -1), + Tcl_GetString(value)); Tcl_DecrRefCount(value); argc -= 3; argv += 3; - } else if ((argc > 1) && (TEXT('-') != argv[1][0])) { + } else if ((argc > 1) && ('-' != argv[1][0])) { Tcl_SetStartupScript(NewNativeObj(argv[1], -1), NULL); argc--; argv++; @@ -395,8 +398,9 @@ Tcl_MainEx( /* * Arrange for final deletion of the main interp */ - /* ARGH Munchhausen effect */ - Tcl_CreateExitHandler(FreeMainInterp, (ClientData)interp); + + /* ARGH Munchhausen effect */ + Tcl_CreateExitHandler(FreeMainInterp, interp); } /* @@ -458,6 +462,7 @@ Tcl_MainEx( mainLoopProc = TclGetMainLoop(); if (mainLoopProc == NULL) { int length; + if (is.tty) { Prompt(interp, &is); if (Tcl_InterpDeleted(interp)) { @@ -523,7 +528,8 @@ Tcl_MainEx( Tcl_GetStringFromObj(is.commandPtr, &length); Tcl_SetObjLength(is.commandPtr, --length); - code = Tcl_RecordAndEvalObj(interp, is.commandPtr, TCL_EVAL_GLOBAL); + code = Tcl_RecordAndEvalObj(interp, is.commandPtr, + TCL_EVAL_GLOBAL); is.input = Tcl_GetStdChannel(TCL_STDIN); Tcl_DecrRefCount(is.commandPtr); is.commandPtr = Tcl_NewObj(); @@ -557,7 +563,8 @@ Tcl_MainEx( Prompt(interp, &is); } - Tcl_CreateChannelHandler(is.input, TCL_READABLE, StdinProc, &is); + Tcl_CreateChannelHandler(is.input, TCL_READABLE, + StdinProc, &is); } mainLoopProc(); @@ -568,24 +575,23 @@ Tcl_MainEx( } is.input = Tcl_GetStdChannel(TCL_STDIN); } -#ifdef TCL_MEM_DEBUG /* * This code here only for the (unsupported and deprecated) [checkmem] * command. */ +#ifdef TCL_MEM_DEBUG if (tclMemDumpFileName != NULL) { Tcl_SetMainLoop(NULL); Tcl_DeleteInterp(interp); } -#endif +#endif /* TCL_MEM_DEBUG */ } done: mainLoopProc = TclGetMainLoop(); - if ((exitCode == 0) && (mainLoopProc != NULL) - && !Tcl_LimitExceeded(interp)) { + if ((exitCode == 0) && mainLoopProc && !Tcl_LimitExceeded(interp)) { /* * If everything has gone OK so far, call the main loop proc, if it * exists. Packages (like Tk) can set it to start processing events at @@ -605,21 +611,21 @@ Tcl_MainEx( * exit. The Tcl_EvalObjEx call should never return. */ - if (!Tcl_InterpDeleted(interp)) { - if (!Tcl_LimitExceeded(interp)) { - Tcl_Obj *cmd = Tcl_ObjPrintf("exit %d", exitCode); + if (!Tcl_InterpDeleted(interp) && !Tcl_LimitExceeded(interp)) { + Tcl_Obj *cmd = Tcl_ObjPrintf("exit %d", exitCode); - Tcl_IncrRefCount(cmd); - Tcl_EvalObjEx(interp, cmd, TCL_EVAL_GLOBAL); - Tcl_DecrRefCount(cmd); - } + Tcl_IncrRefCount(cmd); + Tcl_EvalObjEx(interp, cmd, TCL_EVAL_GLOBAL); + Tcl_DecrRefCount(cmd); } - /* - * If Tcl_EvalObjEx returns, trying to eval [exit], something unusual - * is happening. Maybe interp has been deleted; maybe [exit] was - * redefined, maybe we've blown up because of an exceeded limit. We - * still want to cleanup and exit. - */ + + /* + * If Tcl_EvalObjEx returns, trying to eval [exit], something unusual is + * happening. Maybe interp has been deleted; maybe [exit] was redefined, + * maybe we've blown up because of an exceeded limit. We still want to + * cleanup and exit. + */ + Tcl_Exit(exitCode); } @@ -637,7 +643,7 @@ Tcl_Main( Tcl_FindExecutable(argv[0]); Tcl_MainEx(argc, argv, appInitProc, Tcl_CreateInterp()); } -#endif +#endif /* TCL_MAJOR_VERSION == 8 && !UNICODE */ #ifndef TCL_ASCII_MAIN @@ -711,6 +717,7 @@ TclGetMainLoop(void) * *---------------------------------------------------------------------- */ + MODULE_SCOPE int TclFullFinalizationRequested(void) { @@ -727,7 +734,7 @@ TclFullFinalizationRequested(void) Tcl_DStringFree(&ds); } return finalize; -#endif +#endif /* PURIFY */ } #endif /* !TCL_ASCII_MAIN */ @@ -866,9 +873,8 @@ StdinProc( static void Prompt( Tcl_Interp *interp, /* Interpreter to use for prompting. */ - InteractiveState *isPtr) /* InteractiveState. Filled - * with PROMPT_NONE after a prompt is - * printed. */ + InteractiveState *isPtr) /* InteractiveState. Filled with PROMPT_NONE + * after a prompt is printed. */ { Tcl_Obj *promptCmdPtr; int code; @@ -879,7 +885,7 @@ Prompt( } promptCmdPtr = Tcl_GetVar2Ex(interp, - ((isPtr->prompt == PROMPT_CONTINUE) ? "tcl_prompt2" : "tcl_prompt1"), + (isPtr->prompt==PROMPT_CONTINUE ? "tcl_prompt2" : "tcl_prompt1"), NULL, TCL_GLOBAL_ONLY); if (Tcl_InterpDeleted(interp)) { @@ -920,8 +926,8 @@ Prompt( * * FreeMainInterp -- * - * Exit handler used to cleanup the main interpreter and ancillary startup - * script storage at exit. + * Exit handler used to cleanup the main interpreter and ancillary + * startup script storage at exit. * *---------------------------------------------------------------------- */ @@ -930,13 +936,13 @@ static void FreeMainInterp( ClientData clientData) { - Tcl_Interp *interp = (Tcl_Interp *) clientData; + Tcl_Interp *interp = clientData; - /*if (TclInExit()) return;*/ + /*if (TclInExit()) return;*/ - if (!Tcl_InterpDeleted(interp)) { - Tcl_DeleteInterp(interp); - } + if (!Tcl_InterpDeleted(interp)) { + Tcl_DeleteInterp(interp); + } Tcl_SetStartupScript(NULL, NULL); Tcl_Release(interp); } diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index 6a241f0..02d517f 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -104,7 +104,7 @@ static int NamespaceDeleteCmd(ClientData dummy,Tcl_Interp *interp, static int NamespaceEvalCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static int NRNamespaceEvalCmd(ClientData dummy, - Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]); + Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]); static int NamespaceExistsCmd(ClientData dummy,Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static int NamespaceExportCmd(ClientData dummy,Tcl_Interp *interp, @@ -160,25 +160,25 @@ static const Tcl_ObjType nsNameType = { */ static const EnsembleImplMap defaultNamespaceMap[] = { - {"children", NamespaceChildrenCmd, NULL, NULL, NULL, 0}, - {"code", NamespaceCodeCmd, NULL, NULL, NULL, 0}, - {"current", NamespaceCurrentCmd, NULL, NULL, NULL, 0}, - {"delete", NamespaceDeleteCmd, NULL, NULL, NULL, 0}, - {"ensemble", TclNamespaceEnsembleCmd, NULL, NULL, NULL, 0}, - {"eval", NamespaceEvalCmd, NULL, NRNamespaceEvalCmd, NULL, 0}, - {"exists", NamespaceExistsCmd, NULL, NULL, NULL, 0}, - {"export", NamespaceExportCmd, NULL, NULL, NULL, 0}, - {"forget", NamespaceForgetCmd, NULL, NULL, NULL, 0}, - {"import", NamespaceImportCmd, NULL, NULL, NULL, 0}, - {"inscope", NamespaceInscopeCmd, NULL, NRNamespaceInscopeCmd, NULL, 0}, - {"origin", NamespaceOriginCmd, NULL, NULL, NULL, 0}, - {"parent", NamespaceParentCmd, NULL, NULL, NULL, 0}, - {"path", NamespacePathCmd, NULL, NULL, NULL, 0}, - {"qualifiers", NamespaceQualifiersCmd, NULL, NULL, NULL, 0}, - {"tail", NamespaceTailCmd, NULL, NULL, NULL, 0}, - {"unknown", NamespaceUnknownCmd, NULL, NULL, NULL, 0}, - {"upvar", NamespaceUpvarCmd, TclCompileNamespaceUpvarCmd, NULL, NULL, 0}, - {"which", NamespaceWhichCmd, NULL, NULL, NULL, 0}, + {"children", NamespaceChildrenCmd, NULL, NULL, NULL, 0}, + {"code", NamespaceCodeCmd, TclCompileNamespaceCodeCmd, NULL, NULL, 0}, + {"current", NamespaceCurrentCmd, TclCompileNamespaceCurrentCmd, NULL, NULL, 0}, + {"delete", NamespaceDeleteCmd, NULL, NULL, NULL, 0}, + {"ensemble", TclNamespaceEnsembleCmd, NULL, NULL, NULL, 0}, + {"eval", NamespaceEvalCmd, NULL, NRNamespaceEvalCmd, NULL, 0}, + {"exists", NamespaceExistsCmd, NULL, NULL, NULL, 0}, + {"export", NamespaceExportCmd, NULL, NULL, NULL, 0}, + {"forget", NamespaceForgetCmd, NULL, NULL, NULL, 0}, + {"import", NamespaceImportCmd, NULL, NULL, NULL, 0}, + {"inscope", NamespaceInscopeCmd, NULL, NRNamespaceInscopeCmd, NULL, 0}, + {"origin", NamespaceOriginCmd, NULL, NULL, NULL, 0}, + {"parent", NamespaceParentCmd, NULL, NULL, NULL, 0}, + {"path", NamespacePathCmd, NULL, NULL, NULL, 0}, + {"qualifiers", NamespaceQualifiersCmd, TclCompileNamespaceQualifiersCmd, NULL, NULL, 0}, + {"tail", NamespaceTailCmd, TclCompileNamespaceTailCmd, NULL, NULL, 0}, + {"unknown", NamespaceUnknownCmd, NULL, NULL, NULL, 0}, + {"upvar", NamespaceUpvarCmd, TclCompileNamespaceUpvarCmd, NULL, NULL, 0}, + {"which", NamespaceWhichCmd, TclCompileNamespaceWhichCmd, NULL, NULL, 0}, {NULL, NULL, NULL, NULL, NULL, 0} }; @@ -423,7 +423,7 @@ Tcl_PopCallFrame( framePtr->nsPtr = NULL; if (framePtr->tailcallPtr) { - TclSpliceTailcall(interp, framePtr->tailcallPtr); + TclSpliceTailcall(interp, framePtr->tailcallPtr); } } @@ -687,11 +687,10 @@ Tcl_CreateNamespace( parentPtr = NULL; simpleName = ""; } else if (*name == '\0') { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "can't create namespace \"\": " - "only global namespace can have empty name", NULL); - Tcl_SetErrorCode(interp, "TCL", "OPERATION", "NAMESPACE", - "CREATEGLOBAL", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj("can't create namespace" + " \"\": only global namespace can have empty name", -1)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "NAMESPACE", + "CREATEGLOBAL", NULL); return NULL; } else { /* @@ -725,10 +724,10 @@ Tcl_CreateNamespace( Tcl_FindHashEntry(parentPtr->childTablePtr, simpleName) != NULL #endif ) { - Tcl_AppendResult(interp, "can't create namespace \"", name, - "\": already exists", NULL); - Tcl_SetErrorCode(interp, "TCL", "OPERATION", "NAMESPACE", - "CREATEEXISTING", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't create namespace \"%s\": already exists", name)); + Tcl_SetErrorCode(interp, "TCL", "OPERATION", "NAMESPACE", + "CREATEEXISTING", NULL); return NULL; } } @@ -1336,9 +1335,9 @@ Tcl_Export( &exportNsPtr, &dummyPtr, &dummyPtr, &simplePattern); if ((exportNsPtr != nsPtr) || (strcmp(pattern, simplePattern) != 0)) { - Tcl_AppendResult(interp, "invalid export pattern \"", pattern, - "\": pattern can't specify a namespace", NULL); - Tcl_SetErrorCode(interp, "TCL", "EXPORT", "INVALID", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf("invalid export pattern" + " \"%s\": pattern can't specify a namespace", pattern)); + Tcl_SetErrorCode(interp, "TCL", "EXPORT", "INVALID", NULL); return TCL_ERROR; } @@ -1543,7 +1542,7 @@ Tcl_Import( if (strlen(pattern) == 0) { Tcl_SetObjResult(interp, Tcl_NewStringObj("empty import pattern",-1)); - Tcl_SetErrorCode(interp, "TCL", "IMPORT", "EMPTY", NULL); + Tcl_SetErrorCode(interp, "TCL", "IMPORT", "EMPTY", NULL); return TCL_ERROR; } TclGetNamespaceForQualName(interp, pattern, nsPtr, @@ -1551,22 +1550,22 @@ Tcl_Import( &importNsPtr, &dummyPtr, &dummyPtr, &simplePattern); if (importNsPtr == NULL) { - Tcl_AppendResult(interp, "unknown namespace in import pattern \"", - pattern, "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unknown namespace in import pattern \"%s\"", pattern)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "NAMESPACE", pattern, NULL); return TCL_ERROR; } if (importNsPtr == nsPtr) { if (pattern == simplePattern) { - Tcl_AppendResult(interp, - "no namespace specified in import pattern \"", pattern, - "\"", NULL); - Tcl_SetErrorCode(interp, "TCL", "IMPORT", "ORIGIN", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "no namespace specified in import pattern \"%s\"", + pattern)); + Tcl_SetErrorCode(interp, "TCL", "IMPORT", "ORIGIN", NULL); } else { - Tcl_AppendResult(interp, "import pattern \"", pattern, - "\" tries to import from namespace \"", - importNsPtr->name, "\" into itself", NULL); - Tcl_SetErrorCode(interp, "TCL", "IMPORT", "SELF", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "import pattern \"%s\" tries to import from namespace" + " \"%s\" into itself", pattern, importNsPtr->name)); + Tcl_SetErrorCode(interp, "TCL", "IMPORT", "SELF", NULL); } return TCL_ERROR; } @@ -1684,11 +1683,12 @@ DoImport( dataPtr = linkCmd->objClientData; linkCmd = dataPtr->realCmdPtr; if (overwrite == linkCmd) { - Tcl_AppendResult(interp, "import pattern \"", pattern, - "\" would create a loop containing command \"", - Tcl_DStringValue(&ds), "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "import pattern \"%s\" would create a loop" + " containing command \"%s\"", + pattern, Tcl_DStringValue(&ds))); Tcl_DStringFree(&ds); - Tcl_SetErrorCode(interp, "TCL", "IMPORT", "LOOP", NULL); + Tcl_SetErrorCode(interp, "TCL", "IMPORT", "LOOP", NULL); return TCL_ERROR; } } @@ -1726,9 +1726,9 @@ DoImport( return TCL_OK; } } - Tcl_AppendResult(interp, "can't import command \"", cmdName, - "\": already exists", NULL); - Tcl_SetErrorCode(interp, "TCL", "IMPORT", "OVERWRITE", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't import command \"%s\": already exists", cmdName)); + Tcl_SetErrorCode(interp, "TCL", "IMPORT", "OVERWRITE", NULL); return TCL_ERROR; } return TCL_OK; @@ -1796,9 +1796,9 @@ Tcl_ForgetImport( &sourceNsPtr, &dummyPtr, &dummyPtr, &simplePattern); if (sourceNsPtr == NULL) { - Tcl_AppendResult(interp, - "unknown namespace in namespace forget pattern \"", - pattern, "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unknown namespace in namespace forget pattern \"%s\"", + pattern)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "NAMESPACE", pattern, NULL); return TCL_ERROR; } @@ -2402,8 +2402,8 @@ Tcl_FindNamespace( } if (flags & TCL_LEAVE_ERR_MSG) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "unknown namespace \"", name, "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unknown namespace \"%s\"", name)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "NAMESPACE", name, NULL); } return NULL; @@ -2589,8 +2589,8 @@ Tcl_FindCommand( } if (flags & TCL_LEAVE_ERR_MSG) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "unknown command \"", name, "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unknown command \"%s\"", name)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COMMAND", name, NULL); } return NULL; @@ -3170,9 +3170,9 @@ NamespaceDeleteCmd( namespacePtr = Tcl_FindNamespace(interp, name, NULL, /*flags*/ 0); if ((namespacePtr == NULL) || (((Namespace *) namespacePtr)->flags & NS_KILLED)) { - Tcl_AppendResult(interp, "unknown namespace \"", - TclGetString(objv[i]), - "\" in namespace delete command", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unknown namespace \"%s\" in namespace delete command", + TclGetString(objv[i]))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "NAMESPACE", TclGetString(objv[i]), NULL); return TCL_ERROR; @@ -3285,12 +3285,12 @@ NRNamespaceEvalCmd( } if (iPtr->ensembleRewrite.sourceObjs == NULL) { - framePtr->objc = objc; - framePtr->objv = objv; + framePtr->objc = objc; + framePtr->objv = objv; } else { - framePtr->objc = objc + iPtr->ensembleRewrite.numRemovedObjs - - iPtr->ensembleRewrite.numInsertedObjs; - framePtr->objv = iPtr->ensembleRewrite.sourceObjs; + framePtr->objc = objc + iPtr->ensembleRewrite.numRemovedObjs + - iPtr->ensembleRewrite.numInsertedObjs; + framePtr->objv = iPtr->ensembleRewrite.sourceObjs; } if (objc == 3) { @@ -3748,12 +3748,12 @@ NRNamespaceInscopeCmd( } if (iPtr->ensembleRewrite.sourceObjs == NULL) { - framePtr->objc = objc; - framePtr->objv = objv; + framePtr->objc = objc; + framePtr->objv = objv; } else { - framePtr->objc = objc + iPtr->ensembleRewrite.numRemovedObjs - - iPtr->ensembleRewrite.numInsertedObjs; - framePtr->objv = iPtr->ensembleRewrite.sourceObjs; + framePtr->objc = objc + iPtr->ensembleRewrite.numRemovedObjs + - iPtr->ensembleRewrite.numInsertedObjs; + framePtr->objv = iPtr->ensembleRewrite.sourceObjs; } /* @@ -3834,8 +3834,8 @@ NamespaceOriginCmd( command = Tcl_GetCommandFromObj(interp, objv[1]); if (command == NULL) { - Tcl_AppendResult(interp, "invalid command name \"", - TclGetString(objv[1]), "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "invalid command name \"%s\"", TclGetString(objv[1]))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COMMAND", TclGetString(objv[1]), NULL); return TCL_ERROR; @@ -3958,15 +3958,15 @@ NamespacePathCmd( */ if (objc == 1) { - Tcl_Obj *resultObj = Tcl_NewObj(); + Tcl_Obj *resultObj = Tcl_NewObj(); for (i=0 ; i<nsPtr->commandPathLength ; i++) { if (nsPtr->commandPathArray[i].nsPtr != NULL) { - Tcl_ListObjAppendElement(NULL, resultObj, Tcl_NewStringObj( - nsPtr->commandPathArray[i].nsPtr->fullName, -1)); + Tcl_ListObjAppendElement(NULL, resultObj, Tcl_NewStringObj( + nsPtr->commandPathArray[i].nsPtr->fullName, -1)); } } - Tcl_SetObjResult(interp, resultObj); + Tcl_SetObjResult(interp, resultObj); return TCL_OK; } @@ -4843,8 +4843,8 @@ TclLogCommandInfo( int length, /* Number of bytes in command (-1 means use * all bytes up to first null byte). */ const unsigned char *pc, /* Current pc of bytecode execution context */ - Tcl_Obj **tosPtr) /* Current stack of bytecode execution - * context */ + Tcl_Obj **tosPtr) /* Current stack of bytecode execution + * context */ { register const char *p; Interp *iPtr = (Interp *) interp; @@ -4861,55 +4861,55 @@ TclLogCommandInfo( } if (command != NULL) { - /* - * Compute the line number where the error occurred. - */ - - iPtr->errorLine = 1; - for (p = script; p != command; p++) { - if (*p == '\n') { - iPtr->errorLine++; - } - } - - if (length < 0) { - length = strlen(command); - } - overflow = (length > limit); - Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( + /* + * Compute the line number where the error occurred. + */ + + iPtr->errorLine = 1; + for (p = script; p != command; p++) { + if (*p == '\n') { + iPtr->errorLine++; + } + } + + if (length < 0) { + length = strlen(command); + } + overflow = (length > limit); + Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( "\n %s\n\"%.*s%s\"", ((iPtr->errorInfo == NULL) ? "while executing" : "invoked from within"), (overflow ? limit : length), command, (overflow ? "..." : ""))); - varPtr = TclObjLookupVarEx(interp, iPtr->eiVar, NULL, TCL_GLOBAL_ONLY, + varPtr = TclObjLookupVarEx(interp, iPtr->eiVar, NULL, TCL_GLOBAL_ONLY, NULL, 0, 0, &arrayPtr); - if ((varPtr == NULL) || !TclIsVarTraced(varPtr)) { - /* - * Should not happen. - */ - - return; - } else { - Tcl_HashEntry *hPtr + if ((varPtr == NULL) || !TclIsVarTraced(varPtr)) { + /* + * Should not happen. + */ + + return; + } else { + Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&iPtr->varTraces, (char *) varPtr); - VarTrace *tracePtr = Tcl_GetHashValue(hPtr); + VarTrace *tracePtr = Tcl_GetHashValue(hPtr); - if (tracePtr->traceProc != EstablishErrorInfoTraces) { - /* - * The most recent trace set on ::errorInfo is not the one the - * core itself puts on last. This means some other code is + if (tracePtr->traceProc != EstablishErrorInfoTraces) { + /* + * The most recent trace set on ::errorInfo is not the one the + * core itself puts on last. This means some other code is * tracing the variable, and the additional trace(s) might be * write traces that expect the timing of writes to * ::errorInfo that existed Tcl releases before 8.5. To * satisfy that compatibility need, we write the current * -errorinfo value to the ::errorInfo variable. - */ + */ - Tcl_ObjSetVar2(interp, iPtr->eiVar, NULL, iPtr->errorInfo, + Tcl_ObjSetVar2(interp, iPtr->eiVar, NULL, iPtr->errorInfo, TCL_GLOBAL_ONLY); - } - } + } + } } /* @@ -4917,60 +4917,60 @@ TclLogCommandInfo( */ if (Tcl_IsShared(iPtr->errorStack)) { - Tcl_Obj *newObj; - - newObj = Tcl_DuplicateObj(iPtr->errorStack); - Tcl_DecrRefCount(iPtr->errorStack); - Tcl_IncrRefCount(newObj); - iPtr->errorStack = newObj; + Tcl_Obj *newObj; + + newObj = Tcl_DuplicateObj(iPtr->errorStack); + Tcl_DecrRefCount(iPtr->errorStack); + Tcl_IncrRefCount(newObj); + iPtr->errorStack = newObj; } if (iPtr->resetErrorStack) { int len; - iPtr->resetErrorStack = 0; + iPtr->resetErrorStack = 0; Tcl_ListObjLength(interp, iPtr->errorStack, &len); - /* - * Reset while keeping the list intrep as much as possible. - */ - - Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, 0, NULL); - if (pc != NULL) { - Tcl_Obj *innerContext; - - innerContext = TclGetInnerContext(interp, pc, tosPtr); - if (innerContext != NULL) { - Tcl_ListObjAppendElement(NULL, iPtr->errorStack, - iPtr->innerLiteral); - Tcl_ListObjAppendElement(NULL, iPtr->errorStack, innerContext); - } - } else if (command != NULL) { - Tcl_ListObjAppendElement(NULL, iPtr->errorStack, - iPtr->innerLiteral); - Tcl_ListObjAppendElement(NULL, iPtr->errorStack, - Tcl_NewStringObj(command, length)); - } + /* + * Reset while keeping the list intrep as much as possible. + */ + + Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, 0, NULL); + if (pc != NULL) { + Tcl_Obj *innerContext; + + innerContext = TclGetInnerContext(interp, pc, tosPtr); + if (innerContext != NULL) { + Tcl_ListObjAppendElement(NULL, iPtr->errorStack, + iPtr->innerLiteral); + Tcl_ListObjAppendElement(NULL, iPtr->errorStack, innerContext); + } + } else if (command != NULL) { + Tcl_ListObjAppendElement(NULL, iPtr->errorStack, + iPtr->innerLiteral); + Tcl_ListObjAppendElement(NULL, iPtr->errorStack, + Tcl_NewStringObj(command, length)); + } } if (!iPtr->framePtr->objc) { - /* - * Special frame, nothing to report. - */ + /* + * Special frame, nothing to report. + */ } else if (iPtr->varFramePtr != iPtr->framePtr) { - /* - * uplevel case, [lappend errorstack UP $relativelevel] - */ + /* + * uplevel case, [lappend errorstack UP $relativelevel] + */ - Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->upLiteral); - Tcl_ListObjAppendElement(NULL, iPtr->errorStack, Tcl_NewIntObj( + Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->upLiteral); + Tcl_ListObjAppendElement(NULL, iPtr->errorStack, Tcl_NewIntObj( iPtr->framePtr->level - iPtr->varFramePtr->level)); } else if (iPtr->framePtr != iPtr->rootFramePtr) { - /* - * normal case, [lappend errorstack CALL [info level 0]] - */ + /* + * normal case, [lappend errorstack CALL [info level 0]] + */ - Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->callLiteral); - Tcl_ListObjAppendElement(NULL, iPtr->errorStack, Tcl_NewListObj( + Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->callLiteral); + Tcl_ListObjAppendElement(NULL, iPtr->errorStack, Tcl_NewListObj( iPtr->framePtr->objc, iPtr->framePtr->objv)); } } @@ -4980,8 +4980,8 @@ TclLogCommandInfo( * * TclErrorStackResetIf -- * - * The TIP 348 reset/no-bc part of TLCI, for specific use by - * TclCompileSyntaxError. + * The TIP 348 reset/no-bc part of TLCI, for specific use by + * TclCompileSyntaxError. * * Results: * None. @@ -5002,27 +5002,27 @@ TclErrorStackResetIf( Interp *iPtr = (Interp *) interp; if (Tcl_IsShared(iPtr->errorStack)) { - Tcl_Obj *newObj; - - newObj = Tcl_DuplicateObj(iPtr->errorStack); - Tcl_DecrRefCount(iPtr->errorStack); - Tcl_IncrRefCount(newObj); - iPtr->errorStack = newObj; + Tcl_Obj *newObj; + + newObj = Tcl_DuplicateObj(iPtr->errorStack); + Tcl_DecrRefCount(iPtr->errorStack); + Tcl_IncrRefCount(newObj); + iPtr->errorStack = newObj; } if (iPtr->resetErrorStack) { int len; - iPtr->resetErrorStack = 0; + iPtr->resetErrorStack = 0; Tcl_ListObjLength(interp, iPtr->errorStack, &len); - /* - * Reset while keeping the list intrep as much as possible. - */ + /* + * Reset while keeping the list intrep as much as possible. + */ - Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, 0, NULL); - Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->innerLiteral); - Tcl_ListObjAppendElement(NULL, iPtr->errorStack, - Tcl_NewStringObj(msg, length)); + Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, 0, NULL); + Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->innerLiteral); + Tcl_ListObjAppendElement(NULL, iPtr->errorStack, + Tcl_NewStringObj(msg, length)); } } @@ -5065,6 +5065,5 @@ Tcl_LogCommandInfo( * c-basic-offset: 4 * fill-column: 78 * tab-width: 8 - * indent-tabs-mode: nil * End: */ diff --git a/generic/tclOO.c b/generic/tclOO.c index 821befd..d6d2d6a 100644 --- a/generic/tclOO.c +++ b/generic/tclOO.c @@ -3,7 +3,7 @@ * * This file contains the object-system core (NB: not Tcl_Obj, but ::oo) * - * Copyright (c) 2005-2011 by Donal K. Fellows + * Copyright (c) 2005-2012 by Donal K. Fellows * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -81,6 +81,7 @@ static void ObjectRenamedTrace(ClientData clientData, Tcl_Interp *interp, const char *oldName, const char *newName, int flags); static void ReleaseClassContents(Tcl_Interp *interp,Object *oPtr); +static inline void SquelchCachedName(Object *oPtr); static void SquelchedNsFirst(ClientData clientData); static int PublicObjectCmd(ClientData clientData, @@ -313,6 +314,7 @@ InitFoundation( Foundation *fPtr = ckalloc(sizeof(Foundation)); Tcl_Obj *namePtr, *argsPtr, *bodyPtr; Tcl_DString buffer; + Command *cmdPtr; int i; /* @@ -439,8 +441,9 @@ InitFoundation( NULL); Tcl_CreateObjCommand(interp, "::oo::Helpers::nextto", TclOONextToObjCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "::oo::Helpers::self", TclOOSelfObjCmd, NULL, - NULL); + cmdPtr = (Command *) Tcl_CreateObjCommand(interp, "::oo::Helpers::self", + TclOOSelfObjCmd, NULL, NULL); + cmdPtr->compileProc = TclCompileObjectSelfCmd; Tcl_CreateObjCommand(interp, "::oo::define", TclOODefineObjCmd, NULL, NULL); Tcl_CreateObjCommand(interp, "::oo::objdefine", TclOOObjDefObjCmd, NULL, @@ -704,6 +707,27 @@ AllocObject( /* * ---------------------------------------------------------------------- * + * SquelchCachedName -- + * + * Encapsulates how to throw away a cached object name. Called from + * object rename traces and at object destruction. + * + * ---------------------------------------------------------------------- + */ + +static inline void +SquelchCachedName( + Object *oPtr) +{ + if (oPtr->cachedNameObj) { + Tcl_DecrRefCount(oPtr->cachedNameObj); + oPtr->cachedNameObj = NULL; + } +} + +/* + * ---------------------------------------------------------------------- + * * MyDeleted -- * * This callback is triggered when the object's [my] command is deleted @@ -778,10 +802,7 @@ ObjectRenamedTrace( */ if (flags & TCL_TRACE_RENAME) { - if (oPtr->cachedNameObj) { - TclDecrRefCount(oPtr->cachedNameObj); - oPtr->cachedNameObj = NULL; - } + SquelchCachedName(oPtr); return; } @@ -1138,10 +1159,7 @@ ObjectNamespaceDeleted( TclOODeleteChainCache(oPtr->chainCache); } - if (oPtr->cachedNameObj) { - TclDecrRefCount(oPtr->cachedNameObj); - oPtr->cachedNameObj = NULL; - } + SquelchCachedName(oPtr); if (oPtr->metadataPtr != NULL) { Tcl_ObjectMetadataType *metadataTypePtr; @@ -1566,8 +1584,9 @@ Tcl_NewObjectInstance( if (nameStr && Tcl_FindCommand(interp, nameStr, NULL, TCL_NAMESPACE_ONLY)) { - Tcl_AppendResult(interp, "can't create object \"", nameStr, - "\": command already exists with that name", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't create object \"%s\": command already exists with" + " that name", nameStr)); Tcl_SetErrorCode(interp, "TCL", "OO", "OVERWRITE_OBJECT", NULL); return NULL; } @@ -1633,8 +1652,8 @@ Tcl_NewObjectInstance( */ if (result != TCL_ERROR && Deleted(oPtr)) { - Tcl_SetResult(interp, "object deleted in constructor", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "object deleted in constructor", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "STILLBORN", NULL); result = TCL_ERROR; } @@ -1689,8 +1708,9 @@ TclNRNewObjectInstance( if (nameStr && Tcl_FindCommand(interp, nameStr, NULL, TCL_NAMESPACE_ONLY)) { - Tcl_AppendResult(interp, "can't create object \"", nameStr, - "\": command already exists with that name", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't create object \"%s\": command already exists with" + " that name", nameStr)); Tcl_SetErrorCode(interp, "TCL", "OO", "OVERWRITE_OBJECT", NULL); return TCL_ERROR; } @@ -1778,7 +1798,8 @@ FinalizeAlloc( */ if (result != TCL_ERROR && Deleted(oPtr)) { - Tcl_SetResult(interp, "object deleted in constructor", TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "object deleted in constructor", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "STILLBORN", NULL); result = TCL_ERROR; } @@ -1835,7 +1856,8 @@ Tcl_CopyObjectInstance( */ if (IsRootClass(oPtr)) { - Tcl_AppendResult(interp, "may not clone the class of classes", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "may not clone the class of classes", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "CLONING_CLASS", NULL); return NULL; } @@ -2498,9 +2520,9 @@ TclOOObjectCmdCore( flags | (oPtr->flags & FILTER_HANDLING), methodNamePtr); TclDecrRefCount(mappedMethodName); if (contextPtr == NULL) { - Tcl_AppendResult(interp, "impossible to invoke method \"", - TclGetString(methodNamePtr), - "\": no defined method or unknown method", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "impossible to invoke method \"%s\": no defined method or" + " unknown method", TclGetString(methodNamePtr))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD_MAPPED", TclGetString(methodNamePtr), NULL); return TCL_ERROR; @@ -2514,9 +2536,9 @@ TclOOObjectCmdCore( contextPtr = TclOOGetCallContext(oPtr, methodNamePtr, flags | (oPtr->flags & FILTER_HANDLING), NULL); if (contextPtr == NULL) { - Tcl_AppendResult(interp, "impossible to invoke method \"", - TclGetString(methodNamePtr), - "\": no defined method or unknown method", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "impossible to invoke method \"%s\": no defined method or" + " unknown method", TclGetString(methodNamePtr))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD", TclGetString(methodNamePtr), NULL); return TCL_ERROR; @@ -2542,8 +2564,8 @@ TclOOObjectCmdCore( } } if (contextPtr->index >= contextPtr->callPtr->numChain) { - Tcl_SetResult(interp, "no valid method implementation", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "no valid method implementation", -1)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD", TclGetString(methodNamePtr), NULL); TclOODeleteContext(contextPtr); @@ -2624,8 +2646,8 @@ Tcl_ObjectContextInvokeNext( methodType = "method"; } - Tcl_AppendResult(interp, "no next ", methodType, " implementation", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "no next %s implementation", methodType)); Tcl_SetErrorCode(interp, "TCL", "OO", "NOTHING_NEXT", NULL); return TCL_ERROR; } @@ -2693,8 +2715,8 @@ TclNRObjectContextInvokeNext( methodType = "method"; } - Tcl_AppendResult(interp, "no next ", methodType, " implementation", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "no next %s implementation", methodType)); Tcl_SetErrorCode(interp, "TCL", "OO", "NOTHING_NEXT", NULL); return TCL_ERROR; } @@ -2771,8 +2793,8 @@ Tcl_GetObjectFromObj( return cmdPtr->objClientData; notAnObject: - Tcl_AppendResult(interp, TclGetString(objPtr), - " does not refer to an object", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "%s does not refer to an object", TclGetString(objPtr))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "OBJECT", TclGetString(objPtr), NULL); return NULL; diff --git a/generic/tclOO.h b/generic/tclOO.h index fef2bd0..280481c 100644 --- a/generic/tclOO.h +++ b/generic/tclOO.h @@ -4,7 +4,7 @@ * This file contains the public API definitions and some of the function * declarations for the object-system (NB: not Tcl_Obj, but ::oo). * - * Copyright (c) 2006-2008 by Donal K. Fellows + * Copyright (c) 2006-2010 by Donal K. Fellows * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -34,11 +34,12 @@ extern const char *TclOOInitializeStubs( * version in the files: * * tests/oo.test + * tests/ooNext2.test * unix/tclooConfig.sh * win/tclooConfig.sh */ -#define TCLOO_VERSION "0.6.3" +#define TCLOO_VERSION "0.7" #define TCLOO_PATCHLEVEL TCLOO_VERSION /* diff --git a/generic/tclOOBasic.c b/generic/tclOOBasic.c index 35ad1eb..0676618 100644 --- a/generic/tclOOBasic.c +++ b/generic/tclOOBasic.c @@ -4,7 +4,7 @@ * This file contains implementations of the "simple" commands and * methods from the object-system core. * - * Copyright (c) 2005-2011 by Donal K. Fellows + * Copyright (c) 2005-2012 by Donal K. Fellows * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -168,8 +168,8 @@ TclOO_Class_Create( if (oPtr->classPtr == NULL) { Tcl_Obj *cmdnameObj = TclOOObjectName(interp, oPtr); - Tcl_AppendResult(interp, "object \"", TclGetString(cmdnameObj), - "\" is not a class", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "object \"%s\" is not a class", TclGetString(cmdnameObj))); Tcl_SetErrorCode(interp, "TCL", "OO", "INSTANTIATE_NONCLASS", NULL); return TCL_ERROR; } @@ -186,7 +186,8 @@ TclOO_Class_Create( objName = Tcl_GetStringFromObj( objv[Tcl_ObjectContextSkippedArgs(context)], &len); if (len == 0) { - Tcl_AppendResult(interp, "object name must not be empty", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "object name must not be empty", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "EMPTY_NAME", NULL); return TCL_ERROR; } @@ -232,8 +233,8 @@ TclOO_Class_CreateNs( if (oPtr->classPtr == NULL) { Tcl_Obj *cmdnameObj = TclOOObjectName(interp, oPtr); - Tcl_AppendResult(interp, "object \"", TclGetString(cmdnameObj), - "\" is not a class", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "object \"%s\" is not a class", TclGetString(cmdnameObj))); Tcl_SetErrorCode(interp, "TCL", "OO", "INSTANTIATE_NONCLASS", NULL); return TCL_ERROR; } @@ -250,14 +251,16 @@ TclOO_Class_CreateNs( objName = Tcl_GetStringFromObj( objv[Tcl_ObjectContextSkippedArgs(context)], &len); if (len == 0) { - Tcl_AppendResult(interp, "object name must not be empty", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "object name must not be empty", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "EMPTY_NAME", NULL); return TCL_ERROR; } nsName = Tcl_GetStringFromObj( objv[Tcl_ObjectContextSkippedArgs(context)+1], &len); if (len == 0) { - Tcl_AppendResult(interp, "namespace name must not be empty", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "namespace name must not be empty", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "EMPTY_NAME", NULL); return TCL_ERROR; } @@ -301,8 +304,8 @@ TclOO_Class_New( if (oPtr->classPtr == NULL) { Tcl_Obj *cmdnameObj = TclOOObjectName(interp, oPtr); - Tcl_AppendResult(interp, "object \"", TclGetString(cmdnameObj), - "\" is not a class", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "object \"%s\" is not a class", TclGetString(cmdnameObj))); Tcl_SetErrorCode(interp, "TCL", "OO", "INSTANTIATE_NONCLASS", NULL); return TCL_ERROR; } @@ -504,6 +507,7 @@ TclOO_Object_Unknown( Object *oPtr = contextPtr->oPtr; const char **methodNames; int numMethodNames, i, skip = Tcl_ObjectContextSkippedArgs(context); + Tcl_Obj *errorMsg; /* * If no method name, generate an error asking for a method name. (Only by @@ -529,31 +533,34 @@ TclOO_Object_Unknown( if (numMethodNames == 0) { Tcl_Obj *tmpBuf = TclOOObjectName(interp, oPtr); + const char *piece; - Tcl_AppendResult(interp, "object \"", TclGetString(tmpBuf), NULL); if (contextPtr->callPtr->flags & PUBLIC_METHOD) { - Tcl_AppendResult(interp, "\" has no visible methods", NULL); + piece = "visible methods"; } else { - Tcl_AppendResult(interp, "\" has no methods", NULL); + piece = "methods"; } + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "object \"%s\" has no %s", TclGetString(tmpBuf), piece)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD", TclGetString(objv[skip]), NULL); return TCL_ERROR; } - Tcl_AppendResult(interp, "unknown method \"", TclGetString(objv[skip]), - "\": must be ", NULL); + errorMsg = Tcl_ObjPrintf("unknown method \"%s\": must be ", + TclGetString(objv[skip])); for (i=0 ; i<numMethodNames-1 ; i++) { if (i) { - Tcl_AppendResult(interp, ", ", NULL); + Tcl_AppendToObj(errorMsg, ", ", -1); } - Tcl_AppendResult(interp, methodNames[i], NULL); + Tcl_AppendToObj(errorMsg, methodNames[i], -1); } if (i) { - Tcl_AppendResult(interp, " or ", NULL); + Tcl_AppendToObj(errorMsg, " or ", -1); } - Tcl_AppendResult(interp, methodNames[i], NULL); + Tcl_AppendToObj(errorMsg, methodNames[i], -1); ckfree(methodNames); + Tcl_SetObjResult(interp, errorMsg); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD", TclGetString(objv[skip]), NULL); return TCL_ERROR; @@ -609,8 +616,9 @@ TclOO_Object_LinkVar( */ if (strstr(varName, "::") != NULL) { - Tcl_AppendResult(interp, "variable name \"", varName, - "\" illegal: must not contain namespace separator", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "variable name \"%s\" illegal: must not contain namespace" + " separator", varName)); Tcl_SetErrorCode(interp, "TCL", "UPVAR", "INVERTED", NULL); return TCL_ERROR; } @@ -784,8 +792,9 @@ TclOONextObjCmd( */ if (framePtr == NULL || !(framePtr->isProcCallFrame & FRAME_IS_METHOD)) { - Tcl_AppendResult(interp, TclGetString(objv[0]), - " may only be called from inside a method", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "%s may only be called from inside a method", + TclGetString(objv[0]))); Tcl_SetErrorCode(interp, "TCL", "OO", "CONTEXT_REQUIRED", NULL); return TCL_ERROR; } @@ -822,8 +831,9 @@ TclOONextToObjCmd( */ if (framePtr == NULL || !(framePtr->isProcCallFrame & FRAME_IS_METHOD)) { - Tcl_AppendResult(interp, TclGetString(objv[0]), - " may only be called from inside a method", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "%s may only be called from inside a method", + TclGetString(objv[0]))); Tcl_SetErrorCode(interp, "TCL", "OO", "CONTEXT_REQUIRED", NULL); return TCL_ERROR; } @@ -843,8 +853,9 @@ TclOONextToObjCmd( } classPtr = ((Object *)object)->classPtr; if (classPtr == NULL) { - Tcl_AppendResult(interp, "\"", TclGetString(objv[1]), - "\" is not a class", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "\"%s\" is not a class", TclGetString(objv[1]))); + Tcl_SetErrorCode(interp, "TCL", "OO", "CLASS_REQUIRED", NULL); return TCL_ERROR; } @@ -881,14 +892,15 @@ TclOONextToObjCmd( struct MInvoke *miPtr = contextPtr->callPtr->chain + i; if (!miPtr->isFilter && miPtr->mPtr->declaringClassPtr == classPtr) { - Tcl_AppendResult(interp, "method implementation by \"", - TclGetString(objv[1]), "\" not reachable from here", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "method implementation by \"%s\" not reachable from here", + TclGetString(objv[1]))); return TCL_ERROR; } } - Tcl_AppendResult(interp, "method has no non-filter implementation by \"", - TclGetString(objv[1]), "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "method has no non-filter implementation by \"%s\"", + TclGetString(objv[1]))); return TCL_ERROR; } @@ -948,8 +960,9 @@ TclOOSelfObjCmd( */ if (framePtr == NULL || !(framePtr->isProcCallFrame & FRAME_IS_METHOD)) { - Tcl_AppendResult(interp, TclGetString(objv[0]), - " may only be called from inside a method", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "%s may only be called from inside a method", + TclGetString(objv[0]))); Tcl_SetErrorCode(interp, "TCL", "OO", "CONTEXT_REQUIRED", NULL); return TCL_ERROR; } @@ -983,7 +996,8 @@ TclOOSelfObjCmd( Class *clsPtr = CurrentlyInvoked(contextPtr).mPtr->declaringClassPtr; if (clsPtr == NULL) { - Tcl_AppendResult(interp, "method not defined by a class", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "method not defined by a class", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "UNMATCHED_CONTEXT", NULL); return TCL_ERROR; } @@ -1003,7 +1017,8 @@ TclOOSelfObjCmd( return TCL_OK; case SELF_FILTER: if (!CurrentlyInvoked(contextPtr).isFilter) { - Tcl_AppendResult(interp, "not inside a filtering context", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "not inside a filtering context", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "UNMATCHED_CONTEXT", NULL); return TCL_ERROR; } else { @@ -1028,7 +1043,8 @@ TclOOSelfObjCmd( case SELF_CALLER: if ((framePtr->callerVarPtr == NULL) || !(framePtr->callerVarPtr->isProcCallFrame & FRAME_IS_METHOD)){ - Tcl_AppendResult(interp, "caller is not an object", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "caller is not an object", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "CONTEXT_REQUIRED", NULL); return TCL_ERROR; } else { @@ -1045,7 +1061,8 @@ TclOOSelfObjCmd( * This should be unreachable code. */ - Tcl_AppendResult(interp, "method without declarer!", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "method without declarer!", -1)); return TCL_ERROR; } @@ -1076,7 +1093,8 @@ TclOOSelfObjCmd( * This should be unreachable code. */ - Tcl_AppendResult(interp, "method without declarer!", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "method without declarer!", -1)); return TCL_ERROR; } @@ -1093,7 +1111,8 @@ TclOOSelfObjCmd( return TCL_OK; case SELF_TARGET: if (!CurrentlyInvoked(contextPtr).isFilter) { - Tcl_AppendResult(interp, "not inside a filtering context", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "not inside a filtering context", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "UNMATCHED_CONTEXT", NULL); return TCL_ERROR; } else { @@ -1119,7 +1138,8 @@ TclOOSelfObjCmd( * This should be unreachable code. */ - Tcl_AppendResult(interp, "method without declarer!", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "method without declarer!", -1)); return TCL_ERROR; } result[0] = TclOOObjectName(interp, declarerPtr); diff --git a/generic/tclOOCall.c b/generic/tclOOCall.c index 760bd7b..a79e4fa 100644 --- a/generic/tclOOCall.c +++ b/generic/tclOOCall.c @@ -4,7 +4,7 @@ * This file contains the method call chain management code for the * object-system core. * - * Copyright (c) 2005-2011 by Donal K. Fellows + * Copyright (c) 2005-2012 by Donal K. Fellows * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. diff --git a/generic/tclOODecls.h b/generic/tclOODecls.h index 6316303..58871c6 100644 --- a/generic/tclOODecls.h +++ b/generic/tclOODecls.h @@ -100,13 +100,13 @@ TCLOOAPI void Tcl_ClassSetDestructor(Tcl_Interp *interp, TCLOOAPI Tcl_Obj * Tcl_GetObjectName(Tcl_Interp *interp, Tcl_Object object); -typedef struct TclOOStubHooks { +typedef struct { const struct TclOOIntStubs *tclOOIntStubs; } TclOOStubHooks; typedef struct TclOOStubs { int magic; - const struct TclOOStubHooks *hooks; + const TclOOStubHooks *hooks; Tcl_Object (*tcl_CopyObjectInstance) (Tcl_Interp *interp, Tcl_Object sourceObject, const char *targetName, const char *targetNamespaceName); /* 0 */ Tcl_Object (*tcl_GetClassAsObject) (Tcl_Class clazz); /* 1 */ diff --git a/generic/tclOODefineCmds.c b/generic/tclOODefineCmds.c index 69cffb0..bacab38 100644 --- a/generic/tclOODefineCmds.c +++ b/generic/tclOODefineCmds.c @@ -4,7 +4,7 @@ * This file contains the implementation of the ::oo::define command, * part of the object-system core (NB: not Tcl_Obj, but ::oo). * - * Copyright (c) 2006-2008 by Donal K. Fellows + * Copyright (c) 2006-2012 by Donal K. Fellows * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -423,8 +423,8 @@ RenameDeleteMethod( if (!useClass) { if (!oPtr->methodsPtr) { noSuchMethod: - Tcl_AppendResult(interp, "method ", TclGetString(fromPtr), - " does not exist", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "method %s does not exist", TclGetString(fromPtr))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD", TclGetString(fromPtr), NULL); return TCL_ERROR; @@ -438,14 +438,15 @@ RenameDeleteMethod( &isNew); if (hPtr == newHPtr) { renameToSelf: - Tcl_AppendResult(interp, "cannot rename method to itself", - NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "cannot rename method to itself", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "RENAME_TO_SELF", NULL); return TCL_ERROR; } else if (!isNew) { renameToExisting: - Tcl_AppendResult(interp, "method called ", - TclGetString(toPtr), " already exists", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "method called %s already exists", + TclGetString(toPtr))); Tcl_SetErrorCode(interp, "TCL", "OO", "RENAME_OVER", NULL); return TCL_ERROR; } @@ -513,7 +514,8 @@ TclOOUnknownDefinition( const char *soughtStr, *matchedStr = NULL; if (objc < 2) { - Tcl_AppendResult(interp, "bad call of unknown handler", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "bad call of unknown handler", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "BAD_UNKNOWN", NULL); return TCL_ERROR; } @@ -558,7 +560,8 @@ TclOOUnknownDefinition( } noMatch: - Tcl_AppendResult(interp, "invalid command name \"",soughtStr,"\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "invalid command name \"%s\"", soughtStr)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COMMAND", soughtStr, NULL); return TCL_ERROR; } @@ -646,9 +649,9 @@ InitDefineContext( int result; if (namespacePtr == NULL) { - Tcl_AppendResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "cannot process definitions; support namespace deleted", - NULL); + -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); return TCL_ERROR; } @@ -686,16 +689,17 @@ TclOOGetDefineCmdContext( if ((iPtr->varFramePtr == NULL) || (iPtr->varFramePtr->isProcCallFrame != FRAME_IS_OO_DEFINE)) { - Tcl_AppendResult(interp, "this command may only be called from within" - " the context of an ::oo::define or ::oo::objdefine command", - NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "this command may only be called from within the context of" + " an ::oo::define or ::oo::objdefine command", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); return NULL; } object = iPtr->varFramePtr->clientData; if (Tcl_ObjectDeleted(object)) { - Tcl_AppendResult(interp, "this command cannot be called when the " - "object has been deleted", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "this command cannot be called when the object has been" + " deleted", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); return NULL; } @@ -736,7 +740,7 @@ GetClassInOuterContext( return NULL; } if (oPtr->classPtr == NULL) { - Tcl_AppendResult(interp, errMsg, NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj(errMsg, -1)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CLASS", TclGetString(className), NULL); return NULL; @@ -816,8 +820,8 @@ TclOODefineObjCmd( return TCL_ERROR; } if (oPtr->classPtr == NULL) { - Tcl_AppendResult(interp, TclGetString(objv[1]), - " does not refer to a class", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "%s does not refer to a class",TclGetString(objv[1]))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CLASS", TclGetString(objv[1]), NULL); return TCL_ERROR; @@ -1161,14 +1165,14 @@ TclOODefineClassObjCmd( return TCL_ERROR; } if (oPtr->flags & ROOT_OBJECT) { - Tcl_AppendResult(interp, - "may not modify the class of the root object class", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "may not modify the class of the root object class", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); return TCL_ERROR; } if (oPtr->flags & ROOT_CLASS) { - Tcl_AppendResult(interp, - "may not modify the class of the class of classes", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "may not modify the class of the class of classes", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); return TCL_ERROR; } @@ -1194,9 +1198,10 @@ TclOODefineClassObjCmd( */ if ((oPtr->classPtr==NULL) == TclOOIsReachable(fPtr->classCls, clsPtr)) { - Tcl_AppendResult(interp, "may not change a ", - (oPtr->classPtr==NULL ? "non-" : ""), "class object into a ", - (oPtr->classPtr==NULL ? "" : "non-"), "class object", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "may not change a %sclass object into a %sclass object", + (oPtr->classPtr==NULL ? "non-" : ""), + (oPtr->classPtr==NULL ? "" : "non-"))); Tcl_SetErrorCode(interp, "TCL", "OO", "TRANSMUTATION", NULL); return TCL_ERROR; } @@ -1317,7 +1322,8 @@ TclOODefineDeleteMethodObjCmd( return TCL_ERROR; } if (!isInstanceDeleteMethod && !oPtr->classPtr) { - Tcl_AppendResult(interp, "attempt to misuse API", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "attempt to misuse API", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); return TCL_ERROR; } @@ -1440,7 +1446,8 @@ TclOODefineExportObjCmd( } clsPtr = oPtr->classPtr; if (!isInstanceExport && !clsPtr) { - Tcl_AppendResult(interp, "attempt to misuse API", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "attempt to misuse API", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); return TCL_ERROR; } @@ -1531,7 +1538,8 @@ TclOODefineForwardObjCmd( return TCL_ERROR; } if (!isInstanceForward && !oPtr->classPtr) { - Tcl_AppendResult(interp, "attempt to misuse API", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "attempt to misuse API", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); return TCL_ERROR; } @@ -1588,7 +1596,8 @@ TclOODefineMethodObjCmd( return TCL_ERROR; } if (!isInstanceMethod && !oPtr->classPtr) { - Tcl_AppendResult(interp, "attempt to misuse API", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "attempt to misuse API", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); return TCL_ERROR; } @@ -1639,7 +1648,8 @@ TclOODefineMixinObjCmd( return TCL_ERROR; } if (!isInstanceMixin && !oPtr->classPtr) { - Tcl_AppendResult(interp, "attempt to misuse API", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "attempt to misuse API", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); return TCL_ERROR; } @@ -1653,7 +1663,8 @@ TclOODefineMixinObjCmd( goto freeAndError; } if (!isInstanceMixin && TclOOIsReachable(oPtr->classPtr, clsPtr)) { - Tcl_AppendResult(interp, "may not mix a class into itself", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "may not mix a class into itself", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "SELF_MIXIN", NULL); goto freeAndError; } @@ -1704,7 +1715,8 @@ TclOODefineRenameMethodObjCmd( return TCL_ERROR; } if (!isInstanceRenameMethod && !oPtr->classPtr) { - Tcl_AppendResult(interp, "attempt to misuse API", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "attempt to misuse API", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); return TCL_ERROR; } @@ -1764,7 +1776,8 @@ TclOODefineUnexportObjCmd( } clsPtr = oPtr->classPtr; if (!isInstanceUnexport && !clsPtr) { - Tcl_AppendResult(interp, "attempt to misuse API", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "attempt to misuse API", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); return TCL_ERROR; } @@ -1949,7 +1962,8 @@ ClassFilterGet( if (oPtr == NULL) { return TCL_ERROR; } else if (!oPtr->classPtr) { - Tcl_AppendResult(interp, "attempt to misuse API", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "attempt to misuse API", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); return TCL_ERROR; } @@ -1984,7 +1998,8 @@ ClassFilterSet( if (oPtr == NULL) { return TCL_ERROR; } else if (!oPtr->classPtr) { - Tcl_AppendResult(interp, "attempt to misuse API", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "attempt to misuse API", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); return TCL_ERROR; } else if (Tcl_ListObjGetElements(interp, objv[0], &filterc, @@ -2027,7 +2042,8 @@ ClassMixinGet( if (oPtr == NULL) { return TCL_ERROR; } else if (!oPtr->classPtr) { - Tcl_AppendResult(interp, "attempt to misuse API", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "attempt to misuse API", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); return TCL_ERROR; } @@ -2065,7 +2081,8 @@ ClassMixinSet( if (oPtr == NULL) { return TCL_ERROR; } else if (!oPtr->classPtr) { - Tcl_AppendResult(interp, "attempt to misuse API", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "attempt to misuse API", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); return TCL_ERROR; } else if (Tcl_ListObjGetElements(interp, objv[0], &mixinc, @@ -2082,7 +2099,8 @@ ClassMixinSet( goto freeAndError; } if (TclOOIsReachable(oPtr->classPtr, mixins[i])) { - Tcl_AppendResult(interp, "may not mix a class into itself", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "may not mix a class into itself", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "SELF_MIXIN", NULL); goto freeAndError; } @@ -2128,7 +2146,8 @@ ClassSuperGet( if (oPtr == NULL) { return TCL_ERROR; } else if (!oPtr->classPtr) { - Tcl_AppendResult(interp, "attempt to misuse API", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "attempt to misuse API", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); return TCL_ERROR; } @@ -2165,12 +2184,13 @@ ClassSuperSet( if (oPtr == NULL) { return TCL_ERROR; } else if (!oPtr->classPtr) { - Tcl_AppendResult(interp, "attempt to misuse API", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "attempt to misuse API", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); return TCL_ERROR; } else if (oPtr == oPtr->fPtr->objectCls->thisPtr) { - Tcl_AppendResult(interp, - "may not modify the superclass of the root object", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "may not modify the superclass of the root object", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); return TCL_ERROR; } else if (Tcl_ListObjGetElements(interp, objv[0], &superc, @@ -2196,15 +2216,15 @@ ClassSuperSet( } for (j=0 ; j<i ; j++) { if (superclasses[j] == superclasses[i]) { - Tcl_AppendResult(interp, - "class should only be a direct superclass once",NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "class should only be a direct superclass once", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "REPETITIOUS", NULL); goto failedAfterAlloc; } } if (TclOOIsReachable(oPtr->classPtr, superclasses[i])) { - Tcl_AppendResult(interp, - "attempt to form circular dependency graph", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "attempt to form circular dependency graph", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "CIRCULARITY", NULL); failedAfterAlloc: ckfree((char *) superclasses); @@ -2265,7 +2285,8 @@ ClassVarsGet( if (oPtr == NULL) { return TCL_ERROR; } else if (!oPtr->classPtr) { - Tcl_AppendResult(interp, "attempt to misuse API", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "attempt to misuse API", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); return TCL_ERROR; } @@ -2301,7 +2322,8 @@ ClassVarsSet( if (oPtr == NULL) { return TCL_ERROR; } else if (!oPtr->classPtr) { - Tcl_AppendResult(interp, "attempt to misuse API", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "attempt to misuse API", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); return TCL_ERROR; } else if (Tcl_ListObjGetElements(interp, objv[0], &varc, @@ -2313,15 +2335,16 @@ ClassVarsSet( const char *varName = Tcl_GetString(varv[i]); if (strstr(varName, "::") != NULL) { - Tcl_AppendResult(interp, "invalid declared variable name \"", - varName, "\": must not contain namespace separators", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "invalid declared variable name \"%s\": must not %s", + varName, "contain namespace separators")); Tcl_SetErrorCode(interp, "TCL", "OO", "BAD_DECLVAR", NULL); return TCL_ERROR; } if (Tcl_StringMatch(varName, "*(*)")) { - Tcl_AppendResult(interp, "invalid declared variable name \"", - varName, "\": must not refer to an array element", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "invalid declared variable name \"%s\": must not %s", + varName, "refer to an array element")); Tcl_SetErrorCode(interp, "TCL", "OO", "BAD_DECLVAR", NULL); return TCL_ERROR; } @@ -2591,15 +2614,16 @@ ObjVarsSet( const char *varName = Tcl_GetString(varv[i]); if (strstr(varName, "::") != NULL) { - Tcl_AppendResult(interp, "invalid declared variable name \"", - varName, "\": must not contain namespace separators", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "invalid declared variable name \"%s\": must not %s", + varName, "contain namespace separators")); Tcl_SetErrorCode(interp, "TCL", "OO", "BAD_DECLVAR", NULL); return TCL_ERROR; } if (Tcl_StringMatch(varName, "*(*)")) { - Tcl_AppendResult(interp, "invalid declared variable name \"", - varName, "\": must not refer to an array element", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "invalid declared variable name \"%s\": must not %s", + varName, "refer to an array element")); Tcl_SetErrorCode(interp, "TCL", "OO", "BAD_DECLVAR", NULL); return TCL_ERROR; } diff --git a/generic/tclOOInfo.c b/generic/tclOOInfo.c index f298320..e09ee4e 100644 --- a/generic/tclOOInfo.c +++ b/generic/tclOOInfo.c @@ -4,7 +4,7 @@ * This file contains the implementation of the ::oo-related [info] * subcommands. * - * Copyright (c) 2006-2008 by Donal K. Fellows + * Copyright (c) 2006-2011 by Donal K. Fellows * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -43,47 +43,45 @@ static Tcl_ObjCmdProc InfoClassSubsCmd; static Tcl_ObjCmdProc InfoClassSupersCmd; static Tcl_ObjCmdProc InfoClassVariablesCmd; -struct NameProcMap { const char *name; Tcl_ObjCmdProc *proc; }; - /* * List of commands that are used to implement the [info object] subcommands. */ -static const struct NameProcMap infoObjectCmds[] = { - {"::oo::InfoObject::call", InfoObjectCallCmd}, - {"::oo::InfoObject::class", InfoObjectClassCmd}, - {"::oo::InfoObject::definition", InfoObjectDefnCmd}, - {"::oo::InfoObject::filters", InfoObjectFiltersCmd}, - {"::oo::InfoObject::forward", InfoObjectForwardCmd}, - {"::oo::InfoObject::isa", InfoObjectIsACmd}, - {"::oo::InfoObject::methods", InfoObjectMethodsCmd}, - {"::oo::InfoObject::methodtype", InfoObjectMethodTypeCmd}, - {"::oo::InfoObject::mixins", InfoObjectMixinsCmd}, - {"::oo::InfoObject::namespace", InfoObjectNsCmd}, - {"::oo::InfoObject::variables", InfoObjectVariablesCmd}, - {"::oo::InfoObject::vars", InfoObjectVarsCmd}, - {NULL, NULL} +static const EnsembleImplMap infoObjectCmds[] = { + {"call", InfoObjectCallCmd, NULL, NULL, NULL, 0}, + {"class", InfoObjectClassCmd, TclCompileInfoObjectClassCmd, NULL, NULL, 0}, + {"definition", InfoObjectDefnCmd, NULL, NULL, NULL, 0}, + {"filters", InfoObjectFiltersCmd, NULL, NULL, NULL, 0}, + {"forward", InfoObjectForwardCmd, NULL, NULL, NULL, 0}, + {"isa", InfoObjectIsACmd, TclCompileInfoObjectIsACmd, NULL, NULL, 0}, + {"methods", InfoObjectMethodsCmd, NULL, NULL, NULL, 0}, + {"methodtype", InfoObjectMethodTypeCmd, NULL, NULL, NULL, 0}, + {"mixins", InfoObjectMixinsCmd, NULL, NULL, NULL, 0}, + {"namespace", InfoObjectNsCmd, TclCompileInfoObjectNamespaceCmd, NULL, NULL, 0}, + {"variables", InfoObjectVariablesCmd, NULL, NULL, NULL, 0}, + {"vars", InfoObjectVarsCmd, NULL, NULL, NULL, 0}, + {NULL, NULL, NULL, NULL, NULL, 0} }; /* * List of commands that are used to implement the [info class] subcommands. */ -static const struct NameProcMap infoClassCmds[] = { - {"::oo::InfoClass::call", InfoClassCallCmd}, - {"::oo::InfoClass::constructor", InfoClassConstrCmd}, - {"::oo::InfoClass::definition", InfoClassDefnCmd}, - {"::oo::InfoClass::destructor", InfoClassDestrCmd}, - {"::oo::InfoClass::filters", InfoClassFiltersCmd}, - {"::oo::InfoClass::forward", InfoClassForwardCmd}, - {"::oo::InfoClass::instances", InfoClassInstancesCmd}, - {"::oo::InfoClass::methods", InfoClassMethodsCmd}, - {"::oo::InfoClass::methodtype", InfoClassMethodTypeCmd}, - {"::oo::InfoClass::mixins", InfoClassMixinsCmd}, - {"::oo::InfoClass::subclasses", InfoClassSubsCmd}, - {"::oo::InfoClass::superclasses", InfoClassSupersCmd}, - {"::oo::InfoClass::variables", InfoClassVariablesCmd}, - {NULL, NULL} +static const EnsembleImplMap infoClassCmds[] = { + {"call", InfoClassCallCmd, NULL, NULL, NULL, 0}, + {"constructor", InfoClassConstrCmd, NULL, NULL, NULL, 0}, + {"definition", InfoClassDefnCmd, NULL, NULL, NULL, 0}, + {"destructor", InfoClassDestrCmd, NULL, NULL, NULL, 0}, + {"filters", InfoClassFiltersCmd, NULL, NULL, NULL, 0}, + {"forward", InfoClassForwardCmd, NULL, NULL, NULL, 0}, + {"instances", InfoClassInstancesCmd, NULL, NULL, NULL, 0}, + {"methods", InfoClassMethodsCmd, NULL, NULL, NULL, 0}, + {"methodtype", InfoClassMethodTypeCmd, NULL, NULL, NULL, 0}, + {"mixins", InfoClassMixinsCmd, NULL, NULL, NULL, 0}, + {"subclasses", InfoClassSubsCmd, NULL, NULL, NULL, 0}, + {"superclasses", InfoClassSupersCmd, NULL, NULL, NULL, 0}, + {"variables", InfoClassVariablesCmd, NULL, NULL, NULL, 0}, + {NULL, NULL, NULL, NULL, NULL, 0} }; /* @@ -101,33 +99,14 @@ void TclOOInitInfo( Tcl_Interp *interp) { - Tcl_Namespace *nsPtr; Tcl_Command infoCmd; - int i; - - /* - * Build the ensemble used to implement [info object]. - */ - - nsPtr = Tcl_CreateNamespace(interp, "::oo::InfoObject", NULL, NULL); - Tcl_CreateEnsemble(interp, nsPtr->fullName, nsPtr, TCL_ENSEMBLE_PREFIX); - Tcl_Export(interp, nsPtr, "[a-z]*", 1); - for (i=0 ; infoObjectCmds[i].name!=NULL ; i++) { - Tcl_CreateObjCommand(interp, infoObjectCmds[i].name, - infoObjectCmds[i].proc, NULL, NULL); - } /* - * Build the ensemble used to implement [info class]. + * Build the ensembles used to implement [info object] and [info class]. */ - nsPtr = Tcl_CreateNamespace(interp, "::oo::InfoClass", NULL, NULL); - Tcl_CreateEnsemble(interp, nsPtr->fullName, nsPtr, TCL_ENSEMBLE_PREFIX); - Tcl_Export(interp, nsPtr, "[a-z]*", 1); - for (i=0 ; infoClassCmds[i].name!=NULL ; i++) { - Tcl_CreateObjCommand(interp, infoClassCmds[i].name, - infoClassCmds[i].proc, NULL, NULL); - } + TclMakeEnsemble(interp, "::oo::InfoObject", infoObjectCmds); + TclMakeEnsemble(interp, "::oo::InfoClass", infoClassCmds); /* * Install into the master [info] ensemble. @@ -177,8 +156,8 @@ GetClassFromObj( return NULL; } if (oPtr->classPtr == NULL) { - Tcl_AppendResult(interp, "\"", TclGetString(objPtr), - "\" is not a class", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "\"%s\" is not a class", TclGetString(objPtr))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CLASS", TclGetString(objPtr), NULL); return NULL; @@ -279,16 +258,16 @@ InfoObjectDefnCmd( hPtr = Tcl_FindHashEntry(oPtr->methodsPtr, (char *) objv[2]); if (hPtr == NULL) { unknownMethod: - Tcl_AppendResult(interp, "unknown method \"", TclGetString(objv[2]), - "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unknown method \"%s\"", TclGetString(objv[2]))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD", TclGetString(objv[2]), NULL); return TCL_ERROR; } procPtr = TclOOGetProcFromMethod(Tcl_GetHashValue(hPtr)); if (procPtr == NULL) { - Tcl_AppendResult(interp, - "definition not available for this kind of method", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "definition not available for this kind of method", -1)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD", TclGetString(objv[2]), NULL); return TCL_ERROR; @@ -390,17 +369,17 @@ InfoObjectForwardCmd( hPtr = Tcl_FindHashEntry(oPtr->methodsPtr, (char *) objv[2]); if (hPtr == NULL) { unknownMethod: - Tcl_AppendResult(interp, "unknown method \"", TclGetString(objv[2]), - "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unknown method \"%s\"", TclGetString(objv[2]))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD", TclGetString(objv[2]), NULL); return TCL_ERROR; } prefixObj = TclOOGetFwdFromMethod(Tcl_GetHashValue(hPtr)); if (prefixObj == NULL) { - Tcl_AppendResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "prefix argument list not available for this kind of method", - NULL); + -1)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD", TclGetString(objv[2]), NULL); return TCL_ERROR; @@ -491,7 +470,8 @@ InfoObjectIsACmd( return TCL_ERROR; } if (o2Ptr->classPtr == NULL) { - Tcl_AppendResult(interp, "non-classes cannot be mixins", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "non-classes cannot be mixins", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "NONCLASS", NULL); return TCL_ERROR; } else { @@ -516,7 +496,8 @@ InfoObjectIsACmd( return TCL_ERROR; } if (o2Ptr->classPtr == NULL) { - Tcl_AppendResult(interp, "non-classes cannot be types", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "non-classes cannot be types", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "NONCLASS", NULL); return TCL_ERROR; } @@ -651,8 +632,8 @@ InfoObjectMethodTypeCmd( hPtr = Tcl_FindHashEntry(oPtr->methodsPtr, (char *) objv[2]); if (hPtr == NULL) { unknownMethod: - Tcl_AppendResult(interp, "unknown method \"", TclGetString(objv[2]), - "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unknown method \"%s\"", TclGetString(objv[2]))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD", TclGetString(objv[2]), NULL); return TCL_ERROR; @@ -878,8 +859,8 @@ InfoClassConstrCmd( } procPtr = TclOOGetProcFromMethod(clsPtr->constructorPtr); if (procPtr == NULL) { - Tcl_AppendResult(interp, - "definition not available for this kind of method", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "definition not available for this kind of method", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "METHOD_TYPE", NULL); return TCL_ERROR; } @@ -937,16 +918,16 @@ InfoClassDefnCmd( } hPtr = Tcl_FindHashEntry(&clsPtr->classMethods, (char *) objv[2]); if (hPtr == NULL) { - Tcl_AppendResult(interp, "unknown method \"", TclGetString(objv[2]), - "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unknown method \"%s\"", TclGetString(objv[2]))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD", TclGetString(objv[2]), NULL); return TCL_ERROR; } procPtr = TclOOGetProcFromMethod(Tcl_GetHashValue(hPtr)); if (procPtr == NULL) { - Tcl_AppendResult(interp, - "definition not available for this kind of method", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "definition not available for this kind of method", -1)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD", TclGetString(objv[2]), NULL); return TCL_ERROR; @@ -1006,8 +987,8 @@ InfoClassDestrCmd( } procPtr = TclOOGetProcFromMethod(clsPtr->destructorPtr); if (procPtr == NULL) { - Tcl_AppendResult(interp, - "definition not available for this kind of method", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "definition not available for this kind of method", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "METHOD_TYPE", NULL); return TCL_ERROR; } @@ -1085,17 +1066,17 @@ InfoClassForwardCmd( } hPtr = Tcl_FindHashEntry(&clsPtr->classMethods, (char *) objv[2]); if (hPtr == NULL) { - Tcl_AppendResult(interp, "unknown method \"", TclGetString(objv[2]), - "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unknown method \"%s\"", TclGetString(objv[2]))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD", TclGetString(objv[2]), NULL); return TCL_ERROR; } prefixObj = TclOOGetFwdFromMethod(Tcl_GetHashValue(hPtr)); if (prefixObj == NULL) { - Tcl_AppendResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "prefix argument list not available for this kind of method", - NULL); + -1)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD", TclGetString(objv[2]), NULL); return TCL_ERROR; @@ -1269,8 +1250,8 @@ InfoClassMethodTypeCmd( hPtr = Tcl_FindHashEntry(&clsPtr->classMethods, (char *) objv[2]); if (hPtr == NULL) { unknownMethod: - Tcl_AppendResult(interp, "unknown method \"", TclGetString(objv[2]), - "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unknown method \"%s\"", TclGetString(objv[2]))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD", TclGetString(objv[2]), NULL); return TCL_ERROR; @@ -1494,7 +1475,8 @@ InfoObjectCallCmd( contextPtr = TclOOGetCallContext(oPtr, objv[2], PUBLIC_METHOD, NULL); if (contextPtr == NULL) { - Tcl_AppendResult(interp, "cannot construct any call chain", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "cannot construct any call chain", -1)); return TCL_ERROR; } Tcl_SetObjResult(interp, @@ -1538,7 +1520,8 @@ InfoClassCallCmd( callPtr = TclOOGetStereotypeCallChain(clsPtr, objv[2], PUBLIC_METHOD); if (callPtr == NULL) { - Tcl_AppendResult(interp, "cannot construct any call chain", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "cannot construct any call chain", -1)); return TCL_ERROR; } Tcl_SetObjResult(interp, TclOORenderCallChain(interp, callPtr)); diff --git a/generic/tclOOInt.h b/generic/tclOOInt.h index 631961f..ab54964 100644 --- a/generic/tclOOInt.h +++ b/generic/tclOOInt.h @@ -4,7 +4,7 @@ * This file contains the structure definitions and some of the function * declarations for the object-system (NB: not Tcl_Obj, but ::oo). * - * Copyright (c) 2006-2011 by Donal K. Fellows + * Copyright (c) 2006-2012 by Donal K. Fellows * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. diff --git a/generic/tclOOIntDecls.h b/generic/tclOOIntDecls.h index c751838..acafb18 100644 --- a/generic/tclOOIntDecls.h +++ b/generic/tclOOIntDecls.h @@ -90,7 +90,7 @@ TCLOOAPI void TclOOClassSetMixins(Tcl_Interp *interp, typedef struct TclOOIntStubs { int magic; - const struct TclOOIntStubHooks *hooks; + void *hooks; Tcl_Object (*tclOOGetDefineCmdContext) (Tcl_Interp *interp); /* 0 */ Tcl_Method (*tclOOMakeProcInstanceMethod) (Tcl_Interp *interp, Object *oPtr, int flags, Tcl_Obj *nameObj, Tcl_Obj *argsObj, Tcl_Obj *bodyObj, const Tcl_MethodType *typePtr, ClientData clientData, Proc **procPtrPtr); /* 1 */ diff --git a/generic/tclOOMethod.c b/generic/tclOOMethod.c index 877c3db..28820e0 100644 --- a/generic/tclOOMethod.c +++ b/generic/tclOOMethod.c @@ -3,7 +3,7 @@ * * This file contains code to create and manage methods. * - * Copyright (c) 2005-2008 by Donal K. Fellows + * Copyright (c) 2005-2011 by Donal K. Fellows * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -1329,8 +1329,8 @@ TclOONewForwardInstanceMethod( return NULL; } if (prefixLen < 1) { - Tcl_AppendResult(interp, "method forward prefix must be non-empty", - NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "method forward prefix must be non-empty", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "BAD_FORWARD", NULL); return NULL; } @@ -1371,8 +1371,8 @@ TclOONewForwardMethod( return NULL; } if (prefixLen < 1) { - Tcl_AppendResult(interp, "method forward prefix must be non-empty", - NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "method forward prefix must be non-empty", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "BAD_FORWARD", NULL); return NULL; } diff --git a/generic/tclOOStubLib.c b/generic/tclOOStubLib.c index 3b6ce37..55f2378 100644 --- a/generic/tclOOStubLib.c +++ b/generic/tclOOStubLib.c @@ -53,8 +53,9 @@ TclOOInitializeStubs( if (clientData == NULL) { Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "Error loading ", packageName, " package; ", - "package not present or incomplete", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error loading %s package; package not present or incomplete", + packageName)); return NULL; } else { const TclOOStubs * const stubsPtr = clientData; @@ -76,9 +77,9 @@ TclOOInitializeStubs( error: Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "Error loading ", packageName, " package", - " (requested version '", version, "', loaded version '", - actualVersion, "'): ", errMsg, NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf("Error loading %s package" + " (requested version '%s', loaded version '%s'): %s", + packageName, version, actualVersion, errMsg)); return NULL; } } diff --git a/generic/tclObj.c b/generic/tclObj.c index 099b67d..74cb29e 100644 --- a/generic/tclObj.c +++ b/generic/tclObj.c @@ -4462,11 +4462,8 @@ Tcl_RepresentationCmd( int objc, Tcl_Obj *const objv[]) { - char refcountBuffer[TCL_INTEGER_SPACE+1]; - char objPtrBuffer[TCL_INTEGER_SPACE+3]; - char internalRepBuffer[2*(TCL_INTEGER_SPACE+2)+2]; -#define TCLOBJ_TRUNCATE_STRINGREP 16 - char stringRepBuffer[TCLOBJ_TRUNCATE_STRINGREP+1]; + char ptrBuffer[2*TCL_INTEGER_SPACE+6]; + Tcl_Obj *descObj; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "value"); @@ -4479,27 +4476,30 @@ Tcl_RepresentationCmd( * "1872361827361287" */ - sprintf(refcountBuffer, "%d", objv[1]->refCount); - sprintf(objPtrBuffer, "%p", (void *)objv[1]); - Tcl_AppendResult(interp, "value is a ", objv[1]->typePtr ? - objv[1]->typePtr->name : "pure string", " with a refcount of ", - refcountBuffer, ", object pointer at ", objPtrBuffer, NULL); + sprintf(ptrBuffer, "%p", (void *) objv[1]); + descObj = Tcl_ObjPrintf("value is a %s with a refcount of %d," + " object pointer at %s", + objv[1]->typePtr ? objv[1]->typePtr->name : "pure string", + objv[1]->refCount, ptrBuffer); + if (objv[1]->typePtr) { - sprintf(internalRepBuffer, "%p:%p", - (void *)objv[1]->internalRep.twoPtrValue.ptr1, - (void *)objv[1]->internalRep.twoPtrValue.ptr2); - Tcl_AppendResult(interp, ", internal representation ", - internalRepBuffer, NULL); + sprintf(ptrBuffer, "%p:%p", + (void *) objv[1]->internalRep.twoPtrValue.ptr1, + (void *) objv[1]->internalRep.twoPtrValue.ptr2); + Tcl_AppendPrintfToObj(descObj, ", internal representation %s", + ptrBuffer); } + if (objv[1]->bytes) { - strncpy(stringRepBuffer, objv[1]->bytes, TCLOBJ_TRUNCATE_STRINGREP); - stringRepBuffer[TCLOBJ_TRUNCATE_STRINGREP] = 0; - Tcl_AppendResult(interp, ", string representation \"", - stringRepBuffer, objv[1]->length > TCLOBJ_TRUNCATE_STRINGREP ? - "\"..." : "\".", NULL); + Tcl_AppendToObj(descObj, ", string representation \"", -1); + Tcl_AppendLimitedToObj(descObj, objv[1]->bytes, objv[1]->length, + 16, "..."); + Tcl_AppendToObj(descObj, "\"", -1); } else { - Tcl_AppendResult(interp, ", no string representation.", NULL); + Tcl_AppendToObj(descObj, ", no string representation", -1); } + + Tcl_SetObjResult(interp, descObj); return TCL_OK; } diff --git a/generic/tclParse.c b/generic/tclParse.c index f0050c6..309e232 100644 --- a/generic/tclParse.c +++ b/generic/tclParse.c @@ -258,7 +258,8 @@ Tcl_ParseCommand( if ((start == NULL) && (numBytes != 0)) { if (interp != NULL) { - Tcl_SetResult(interp, "can't parse a NULL pointer", TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "can't parse a NULL pointer", -1)); } return TCL_ERROR; } @@ -568,14 +569,14 @@ Tcl_ParseCommand( } if (src[-1] == '"') { if (interp != NULL) { - Tcl_SetResult(interp, "extra characters after close-quote", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "extra characters after close-quote", -1)); } parsePtr->errorType = TCL_PARSE_QUOTE_EXTRA; } else { if (interp != NULL) { - Tcl_SetResult(interp, "extra characters after close-brace", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "extra characters after close-brace", -1)); } parsePtr->errorType = TCL_PARSE_BRACE_EXTRA; } @@ -1175,8 +1176,8 @@ ParseTokens( } if (numBytes == 0) { if (parsePtr->interp != NULL) { - Tcl_SetResult(parsePtr->interp, - "missing close-bracket", TCL_STATIC); + Tcl_SetObjResult(parsePtr->interp, Tcl_NewStringObj( + "missing close-bracket", -1)); } parsePtr->errorType = TCL_PARSE_MISSING_BRACKET; parsePtr->term = tokenPtr->start; @@ -1411,8 +1412,8 @@ Tcl_ParseVarName( } if (numBytes == 0) { if (parsePtr->interp != NULL) { - Tcl_SetResult(parsePtr->interp, - "missing close-brace for variable name", TCL_STATIC); + Tcl_SetObjResult(parsePtr->interp, Tcl_NewStringObj( + "missing close-brace for variable name", -1)); } parsePtr->errorType = TCL_PARSE_MISSING_VAR_BRACE; parsePtr->term = tokenPtr->start-1; @@ -1479,8 +1480,8 @@ Tcl_ParseVarName( } if ((parsePtr->term == src+numBytes) || (*parsePtr->term != ')')){ if (parsePtr->interp != NULL) { - Tcl_SetResult(parsePtr->interp, "missing )", - TCL_STATIC); + Tcl_SetObjResult(parsePtr->interp, Tcl_NewStringObj( + "missing )", -1)); } parsePtr->errorType = TCL_PARSE_MISSING_PAREN; parsePtr->term = src; @@ -1755,7 +1756,8 @@ Tcl_ParseBraces( goto error; } - Tcl_SetResult(parsePtr->interp, "missing close-brace", TCL_STATIC); + Tcl_SetObjResult(parsePtr->interp, Tcl_NewStringObj( + "missing close-brace", -1)); /* * Guess if the problem is due to comments by searching the source string @@ -1777,8 +1779,8 @@ Tcl_ParseBraces( break; case '#' : if (openBrace && TclIsSpaceProc(src[-1])) { - Tcl_AppendResult(parsePtr->interp, - ": possible unbalanced brace in comment", NULL); + Tcl_AppendToObj(Tcl_GetObjResult(parsePtr->interp), + ": possible unbalanced brace in comment", -1); goto error; } break; @@ -1857,7 +1859,8 @@ Tcl_ParseQuotedString( } if (*parsePtr->term != '"') { if (parsePtr->interp != NULL) { - Tcl_SetResult(parsePtr->interp, "missing \"", TCL_STATIC); + Tcl_SetObjResult(parsePtr->interp, Tcl_NewStringObj( + "missing \"", -1)); } parsePtr->errorType = TCL_PARSE_MISSING_QUOTE; parsePtr->term = start; diff --git a/generic/tclPathObj.c b/generic/tclPathObj.c index 8bae4fb..2b9ff87 100644 --- a/generic/tclPathObj.c +++ b/generic/tclPathObj.c @@ -1492,9 +1492,8 @@ MakePathFromNormalized( if (pathPtr->bytes == NULL) { if (pathPtr->typePtr->updateStringProc == NULL) { if (interp != NULL) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "can't find object" - "string representation", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "can't find object string representation", -1)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "PATH", "WTF", NULL); } @@ -1765,7 +1764,7 @@ Tcl_FSGetNormalizedPath( */ Tcl_Obj *dir, *copy; - int cwdLen, pathType; + int tailLen, cwdLen, pathType; pathType = Tcl_FSGetPathType(fsPathPtr->cwdPtr); dir = Tcl_FSGetNormalizedPath(interp, fsPathPtr->cwdPtr); @@ -1777,7 +1776,12 @@ Tcl_FSGetNormalizedPath( UpdateStringOfFsPath(pathPtr); } - copy = AppendPath(dir, fsPathPtr->normPathPtr); + Tcl_GetStringFromObj(fsPathPtr->normPathPtr, &tailLen); + if (tailLen) { + copy = AppendPath(dir, fsPathPtr->normPathPtr); + } else { + copy = Tcl_DuplicateObj(dir); + } Tcl_IncrRefCount(dir); Tcl_IncrRefCount(copy); @@ -2368,9 +2372,9 @@ SetFsPathFromAny( dir = TclGetEnv("HOME", &dirString); if (dir == NULL) { if (interp) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "couldn't find HOME environment " - "variable to expand path", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "couldn't find HOME environment variable to" + " expand path", -1)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "PATH", "HOMELESS", NULL); } @@ -2387,9 +2391,8 @@ SetFsPathFromAny( Tcl_DStringInit(&temp); if (TclpGetUserHome(name+1, &temp) == NULL) { if (interp != NULL) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "user \"", name+1, - "\" doesn't exist", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "user \"%s\" doesn't exist", name+1)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "PATH", "NOUSER", NULL); } diff --git a/generic/tclPipe.c b/generic/tclPipe.c index d0b136d..83fb818 100644 --- a/generic/tclPipe.c +++ b/generic/tclPipe.c @@ -106,9 +106,10 @@ FileForRedirect( if (msg) { Tcl_SetObjResult(interp, msg); } else { - Tcl_AppendResult(interp, "channel \"", - Tcl_GetChannelName(chan), "\" wasn't opened for ", - ((writing) ? "writing" : "reading"), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "channel \"%s\" wasn't opened for %s", + Tcl_GetChannelName(chan), + ((writing) ? "writing" : "reading"))); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", "BADCHAN", NULL); } @@ -141,9 +142,10 @@ FileForRedirect( file = TclpOpenFile(name, flags); Tcl_DStringFree(&nameString); if (file == NULL) { - Tcl_AppendResult(interp, "couldn't ", - ((writing) ? "write" : "read"), " file \"", spec, "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't %s file \"%s\": %s", + (writing ? "write" : "read"), spec, + Tcl_PosixError(interp))); return NULL; } *closePtr = 1; @@ -151,8 +153,8 @@ FileForRedirect( return file; badLastArg: - Tcl_AppendResult(interp, "can't specify \"", arg, - "\" as last word in command", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't specify \"%s\" as last word in command", arg)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", "SYNTAX", NULL); return NULL; } @@ -304,8 +306,8 @@ TclCleanupChildren( msg = "child process lost (is SIGCHLD ignored or trapped?)"; } - Tcl_AppendResult(interp, "error waiting for process to exit: ", - msg, NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error waiting for process to exit: %s", msg)); } continue; } @@ -335,16 +337,17 @@ TclCleanupChildren( p = Tcl_SignalMsg(WTERMSIG(waitStatus)); Tcl_SetErrorCode(interp, "CHILDKILLED", msg1, Tcl_SignalId(WTERMSIG(waitStatus)), p, NULL); - Tcl_AppendResult(interp, "child killed: ", p, "\n", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "child killed: %s\n", p)); } else if (WIFSTOPPED(waitStatus)) { p = Tcl_SignalMsg(WSTOPSIG(waitStatus)); Tcl_SetErrorCode(interp, "CHILDSUSP", msg1, Tcl_SignalId(WSTOPSIG(waitStatus)), p, NULL); - Tcl_AppendResult(interp, "child suspended: ", p, "\n", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "child suspended: %s\n", p)); } else { - Tcl_AppendResult(interp, - "child wait status didn't make sense\n", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "child wait status didn't make sense\n", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", "ODDWAITRESULT", msg1, NULL); } @@ -374,8 +377,9 @@ TclCleanupChildren( result = TCL_ERROR; Tcl_DecrRefCount(objPtr); Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "error reading stderr output file: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error reading stderr output file: %s", + Tcl_PosixError(interp))); } else if (count > 0) { anyErrorInfo = 1; Tcl_SetObjResult(interp, objPtr); @@ -393,7 +397,8 @@ TclCleanupChildren( */ if ((abnormalExit != 0) && (anyErrorInfo == 0) && (interp != NULL)) { - Tcl_AppendResult(interp, "child process exited abnormally", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "child process exited abnormally", -1)); } return result; } @@ -542,8 +547,8 @@ TclCreatePipeline( } if (*p == '\0') { if ((i == (lastBar + 1)) || (i == (argc - 1))) { - Tcl_SetResult(interp, "illegal use of | or |& in command", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "illegal use of | or |& in command", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", "PIPESYNTAX", NULL); goto error; @@ -570,8 +575,9 @@ TclCreatePipeline( if (*inputLiteral == '\0') { inputLiteral = ((i + 1) == argc) ? NULL : argv[i + 1]; if (inputLiteral == NULL) { - Tcl_AppendResult(interp, "can't specify \"", argv[i], - "\" as last word in command", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't specify \"%s\" as last word in command", + argv[i])); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", "PIPESYNTAX", NULL); goto error; @@ -680,8 +686,9 @@ TclCreatePipeline( */ if (i != argc-1) { - Tcl_AppendResult(interp, "must specify \"", argv[i], - "\" as last word in command", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "must specify \"%s\" as last word in command", + argv[i])); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", "PIPESYNTAX", NULL); goto error; @@ -722,8 +729,8 @@ TclCreatePipeline( * We had a bar followed only by redirections. */ - Tcl_SetResult(interp, "illegal use of | or |& in command", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "illegal use of | or |& in command", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", "PIPESYNTAX", NULL); goto error; @@ -739,9 +746,9 @@ TclCreatePipeline( inputFile = TclpCreateTempFile(inputLiteral); if (inputFile == NULL) { - Tcl_AppendResult(interp, - "couldn't create input file for command: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't create input file for command: %s", + Tcl_PosixError(interp))); goto error; } inputClose = 1; @@ -752,9 +759,9 @@ TclCreatePipeline( */ if (TclpCreatePipe(&inputFile, inPipePtr) == 0) { - Tcl_AppendResult(interp, - "couldn't create input pipe for command: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't create input pipe for command: %s", + Tcl_PosixError(interp))); goto error; } inputClose = 1; @@ -781,9 +788,9 @@ TclCreatePipeline( */ if (TclpCreatePipe(outPipePtr, &outputFile) == 0) { - Tcl_AppendResult(interp, - "couldn't create output pipe for command: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't create output pipe for command: %s", + Tcl_PosixError(interp))); goto error; } outputClose = 1; @@ -821,9 +828,9 @@ TclCreatePipeline( errorFile = TclpCreateTempFile(NULL); if (errorFile == NULL) { - Tcl_AppendResult(interp, - "couldn't create error file for command: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't create error file for command: %s", + Tcl_PosixError(interp))); goto error; } *errFilePtr = errorFile; @@ -894,8 +901,8 @@ TclCreatePipeline( } else { argv[lastArg] = NULL; if (TclpCreatePipe(&pipeIn, &curOutFile) == 0) { - Tcl_AppendResult(interp, "couldn't create pipe: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't create pipe: %s", Tcl_PosixError(interp))); goto error; } } @@ -1074,15 +1081,17 @@ Tcl_OpenCommandChannel( if (flags & TCL_ENFORCE_MODE) { if ((flags & TCL_STDOUT) && (outPipe == NULL)) { - Tcl_AppendResult(interp, "can't read output from command:" - " standard output was redirected", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "can't read output from command:" + " standard output was redirected", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", "BADREDIRECT", NULL); goto error; } if ((flags & TCL_STDIN) && (inPipe == NULL)) { - Tcl_AppendResult(interp, "can't write input to command:" - " standard input was redirected", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "can't write input to command:" + " standard input was redirected", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", "BADREDIRECT", NULL); goto error; @@ -1093,8 +1102,8 @@ Tcl_OpenCommandChannel( numPids, pidPtr); if (channel == NULL) { - Tcl_AppendResult(interp, "pipe for command could not be created", - NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "pipe for command could not be created", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", "NOPIPE", NULL); goto error; } diff --git a/generic/tclPkg.c b/generic/tclPkg.c index 382ffe3..9b6e942 100644 --- a/generic/tclPkg.c +++ b/generic/tclPkg.c @@ -154,8 +154,9 @@ Tcl_PkgProvideEx( } return TCL_OK; } - Tcl_AppendResult(interp, "conflicting versions provided for package \"", - name, "\": ", pkgPtr->version, ", then ", version, NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "conflicting versions provided for package \"%s\": %s, then %s", + name, pkgPtr->version, version)); Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "VERSIONCONFLICT", NULL); return TCL_ERROR; } @@ -284,9 +285,9 @@ Tcl_PkgRequireEx( */ tclEmptyStringRep = &tclEmptyString; - Tcl_AppendResult(interp, "Cannot load package \"", name, - "\" in standalone executable: This package is not " - "compiled with stub support", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "Cannot load package \"%s\" in standalone executable:" + " This package is not compiled with stub support", name)); Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "UNSTUBBED", NULL); return NULL; } @@ -374,9 +375,10 @@ PkgRequireCore( */ if (pkgPtr->clientData != NULL) { - Tcl_AppendResult(interp, "circular package dependency: " - "attempt to provide ", name, " ", - (char *) pkgPtr->clientData, " requires ", name, NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "circular package dependency:" + " attempt to provide %s %s requires %s", + name, (char *) pkgPtr->clientData, name)); AddRequirementsToResult(interp, reqc, reqv); Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "CIRCULARITY", NULL); return NULL; @@ -494,10 +496,10 @@ PkgRequireCore( Tcl_ResetResult(interp); if (pkgPtr->version == NULL) { code = TCL_ERROR; - Tcl_AppendResult(interp, "attempt to provide package ", - name, " ", versionToProvide, - " failed: no version of package ", name, - " provided", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "attempt to provide package %s %s failed:" + " no version of package %s provided", + name, versionToProvide, name)); Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "UNPROVIDED", NULL); } else { @@ -517,11 +519,11 @@ PkgRequireCore( ckfree(vi); if (res != 0) { code = TCL_ERROR; - Tcl_AppendResult(interp, - "attempt to provide package ", name, " ", - versionToProvide, " failed: package ", - name, " ", pkgPtr->version, - " provided instead", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "attempt to provide package %s %s failed:" + " package %s %s provided instead", + name, versionToProvide, + name, pkgPtr->version)); Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "WRONGPROVIDE", NULL); } @@ -530,10 +532,10 @@ PkgRequireCore( } else if (code != TCL_ERROR) { Tcl_Obj *codePtr = Tcl_NewIntObj(code); - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "attempt to provide package ", name, - " ", versionToProvide, " failed: bad return code: ", - TclGetString(codePtr), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "attempt to provide package %s %s failed:" + " bad return code: %s", + name, versionToProvide, TclGetString(codePtr))); Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "BADRESULT", NULL); TclDecrRefCount(codePtr); code = TCL_ERROR; @@ -591,13 +593,9 @@ PkgRequireCore( Tcl_DStringFree(&command); if ((code != TCL_OK) && (code != TCL_ERROR)) { - Tcl_Obj *codePtr = Tcl_NewIntObj(code); - - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad return code: ", - TclGetString(codePtr), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad return code: %d", code)); Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "BADRESULT", NULL); - Tcl_DecrRefCount(codePtr); code = TCL_ERROR; } if (code == TCL_ERROR) { @@ -610,7 +608,8 @@ PkgRequireCore( } if (pkgPtr->version == NULL) { - Tcl_AppendResult(interp, "can't find package ", name, NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't find package %s", name)); Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "UNFOUND", NULL); AddRequirementsToResult(interp, reqc, reqv); return NULL; @@ -628,8 +627,9 @@ PkgRequireCore( ckfree(pkgVersionI); if (!satisfies) { - Tcl_AppendResult(interp, "version conflict for package \"", name, - "\": have ", pkgPtr->version, ", need", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "version conflict for package \"%s\": have %s, need", + name, pkgPtr->version)); Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "VERSIONCONFLICT", NULL); AddRequirementsToResult(interp, reqc, reqv); @@ -721,10 +721,11 @@ Tcl_PkgPresentEx( } if (version != NULL) { - Tcl_AppendResult(interp, "package ", name, " ", version, - " is not present", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "package %s %s is not present", name, version)); } else { - Tcl_AppendResult(interp, "package ", name, " is not present", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "package %s is not present", name)); } Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "PACKAGE", name, NULL); return NULL; @@ -850,7 +851,8 @@ Tcl_PackageObjCmd( if (res == 0){ if (objc == 4) { ckfree(argv3i); - Tcl_SetResult(interp, availPtr->script, TCL_VOLATILE); + Tcl_SetObjResult(interp, + Tcl_NewStringObj(availPtr->script, -1)); return TCL_OK; } Tcl_EventuallyFree(availPtr->script, TCL_DYNAMIC); @@ -955,7 +957,8 @@ Tcl_PackageObjCmd( if (hPtr != NULL) { pkgPtr = Tcl_GetHashValue(hPtr); if (pkgPtr->version != NULL) { - Tcl_SetResult(interp, pkgPtr->version, TCL_VOLATILE); + Tcl_SetObjResult(interp, + Tcl_NewStringObj(pkgPtr->version, -1)); } } return TCL_OK; @@ -1017,7 +1020,8 @@ Tcl_PackageObjCmd( if (objc == 2) { if (iPtr->packageUnknown != NULL) { - Tcl_SetResult(interp, iPtr->packageUnknown, TCL_VOLATILE); + Tcl_SetObjResult(interp, + Tcl_NewStringObj(iPtr->packageUnknown, -1)); } } else if (objc == 3) { if (iPtr->packageUnknown != NULL) { @@ -1351,8 +1355,8 @@ CheckVersionAndConvert( error: ckfree(ibuf); - Tcl_AppendResult(interp, "expected version number but got \"", string, - "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "expected version number but got \"%s\"", string)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "VERSION", NULL); return TCL_ERROR; } @@ -1614,8 +1618,8 @@ CheckRequirement( * More dashes found after the first. This is wrong. */ - Tcl_AppendResult(interp, "expected versionMin-versionMax but got \"", - string, "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "expected versionMin-versionMax but got \"%s\"", string)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "VERSIONRANGE", NULL); return TCL_ERROR; } @@ -1667,19 +1671,17 @@ AddRequirementsToResult( Tcl_Obj *const reqv[]) /* 0 means to use the latest version * available. */ { - if (reqc > 0) { - int i; + Tcl_Obj *result = Tcl_GetObjResult(interp); + int i, length; - for (i = 0; i < reqc; i++) { - int length; - const char *v = Tcl_GetStringFromObj(reqv[i], &length); + for (i = 0; i < reqc; i++) { + const char *v = Tcl_GetStringFromObj(reqv[i], &length); - if ((length & 0x1) && (v[length/2] == '-') - && (strncmp(v, v+((length+1)/2), length/2) == 0)) { - Tcl_AppendResult(interp, " exactly ", v+((length+1)/2), NULL); - } else { - Tcl_AppendResult(interp, " ", v, NULL); - } + if ((length & 0x1) && (v[length/2] == '-') + && (strncmp(v, v+((length+1)/2), length/2) == 0)) { + Tcl_AppendPrintfToObj(result, " exactly %s", v+((length+1)/2)); + } else { + Tcl_AppendPrintfToObj(result, " %s", v); } } } @@ -1708,9 +1710,9 @@ AddRequirementsToDString( Tcl_Obj *const reqv[]) /* 0 means to use the latest version * available. */ { - if (reqc > 0) { - int i; + int i; + if (reqc > 0) { for (i = 0; i < reqc; i++) { TclDStringAppendLiteral(dsPtr, " "); TclDStringAppendObj(dsPtr, reqv[i]); diff --git a/generic/tclPlatDecls.h b/generic/tclPlatDecls.h index 48ad390..e9b92fe 100644 --- a/generic/tclPlatDecls.h +++ b/generic/tclPlatDecls.h @@ -69,7 +69,7 @@ EXTERN int Tcl_MacOSXOpenVersionedBundleResources( typedef struct TclPlatStubs { int magic; - const struct TclPlatStubHooks *hooks; + void *hooks; #if defined(__WIN32__) || defined(__CYGWIN__) /* WIN */ TCHAR * (*tcl_WinUtfToTChar) (const char *str, int len, Tcl_DString *dsPtr); /* 0 */ diff --git a/generic/tclProc.c b/generic/tclProc.c index 537008c..933e7d2 100644 --- a/generic/tclProc.c +++ b/generic/tclProc.c @@ -152,22 +152,24 @@ Tcl_ProcObjCmd( &nsPtr, &altNsPtr, &cxtNsPtr, &procName); if (nsPtr == NULL) { - Tcl_AppendResult(interp, "can't create procedure \"", fullName, - "\": unknown namespace", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't create procedure \"%s\": unknown namespace", + fullName)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "COMMAND", NULL); return TCL_ERROR; } if (procName == NULL) { - Tcl_AppendResult(interp, "can't create procedure \"", fullName, - "\": bad procedure name", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't create procedure \"%s\": bad procedure name", + fullName)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "COMMAND", NULL); return TCL_ERROR; } if ((nsPtr != iPtr->globalNsPtr) && (procName != NULL) && (procName[0] == ':')) { - Tcl_AppendResult(interp, "can't create procedure \"", procName, - "\" in non-global namespace with name starting with \":\"", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't create procedure \"%s\" in non-global namespace with" + " name starting with \":\"", procName)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "COMMAND", NULL); return TCL_ERROR; } @@ -518,16 +520,17 @@ TclCreateProc( } if (fieldCount > 2) { ckfree(fieldValues); - Tcl_AppendResult(interp, - "too many fields in argument specifier \"", - argArray[i], "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "too many fields in argument specifier \"%s\"", + argArray[i])); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC", "FORMALARGUMENTFORMAT", NULL); goto procError; } if ((fieldCount == 0) || (*fieldValues[0] == 0)) { ckfree(fieldValues); - Tcl_AppendResult(interp, "argument with no name", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "argument with no name", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC", "FORMALARGUMENTFORMAT", NULL); goto procError; @@ -553,16 +556,18 @@ TclCreateProc( } while (*q != '\0'); q--; if (*q == ')') { /* We have an array element. */ - Tcl_AppendResult(interp, "formal parameter \"", - fieldValues[0], "\" is an array element", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "formal parameter \"%s\" is an array element", + fieldValues[0])); ckfree(fieldValues); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC", "FORMALARGUMENTFORMAT", NULL); goto procError; } } else if ((*p == ':') && (*(p+1) == ':')) { - Tcl_AppendResult(interp, "formal parameter \"", - fieldValues[0], "\" is not a simple name", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "formal parameter \"%s\" is not a simple name", + fieldValues[0])); ckfree(fieldValues); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC", "FORMALARGUMENTFORMAT", NULL); @@ -767,8 +772,7 @@ TclGetFrame( return result; levelError: - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad level \"", name, "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf("bad level \"%s\"", name)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "STACKLEVEL", NULL); return -1; } @@ -900,8 +904,7 @@ TclObjGetFrame( return result; levelError: - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad level \"", name, "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf("bad level \"%s\"", name)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "STACKLEVEL", NULL); return -1; } @@ -1879,10 +1882,9 @@ InterpProcNR2( * transform to an error now. */ - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "invoked \"", - ((result == TCL_BREAK) ? "break" : "continue"), - "\" outside of a loop", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "invoked \"%s\" outside of a loop", + ((result == TCL_BREAK) ? "break" : "continue"))); Tcl_SetErrorCode(interp, "TCL", "RESULT", "UNEXPECTED", NULL); result = TCL_ERROR; @@ -1999,8 +2001,8 @@ TclProcCompileProc( if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) { if ((Interp *) *codePtr->interpHandle != iPtr) { - Tcl_AppendResult(interp, - "a precompiled script jumped interps", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "a precompiled script jumped interps", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC", "CROSSINTERPBYTECODE", NULL); return TCL_ERROR; @@ -2932,8 +2934,8 @@ Tcl_DisassembleObjCmd( procPtr = TclFindProc((Interp *) interp, TclGetString(objv[2])); if (procPtr == NULL) { - Tcl_AppendResult(interp, "\"", TclGetString(objv[2]), - "\" isn't a procedure", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "\"%s\" isn't a procedure", TclGetString(objv[2]))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "PROC", TclGetString(objv[2]), NULL); return TCL_ERROR; @@ -2982,8 +2984,8 @@ Tcl_DisassembleObjCmd( return TCL_ERROR; } if (oPtr->classPtr == NULL) { - Tcl_AppendResult(interp, "\"", TclGetString(objv[2]), - "\" is not a class", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "\"%s\" is not a class", TclGetString(objv[2]))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CLASS", TclGetString(objv[2]), NULL); return TCL_ERROR; @@ -3017,16 +3019,16 @@ Tcl_DisassembleObjCmd( methodBody: if (hPtr == NULL) { unknownMethod: - Tcl_AppendResult(interp, "unknown method \"", - TclGetString(objv[3]), "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unknown method \"%s\"", TclGetString(objv[3]))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD", TclGetString(objv[3]), NULL); return TCL_ERROR; } procPtr = TclOOGetProcFromMethod(Tcl_GetHashValue(hPtr)); if (procPtr == NULL) { - Tcl_AppendResult(interp, - "body not available for this kind of method", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "body not available for this kind of method", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "DISASSEMBLE", "METHODTYPE", NULL); return TCL_ERROR; @@ -3061,7 +3063,8 @@ Tcl_DisassembleObjCmd( if (((ByteCode *) codeObjPtr->internalRep.otherValuePtr)->flags & TCL_BYTECODE_PRECOMPILED) { - Tcl_AppendResult(interp,"may not disassemble prebuilt bytecode",NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "may not disassemble prebuilt bytecode", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "DISASSEMBLE", "BYTECODE", NULL); return TCL_ERROR; diff --git a/generic/tclRegexp.c b/generic/tclRegexp.c index 53d7153..6c1dc08 100644 --- a/generic/tclRegexp.c +++ b/generic/tclRegexp.c @@ -714,14 +714,14 @@ TclRegError( int status) /* Status code to report. */ { char buf[100]; /* ample in practice */ - char cbuf[100]; /* lots in practice */ + char cbuf[TCL_INTEGER_SPACE]; size_t n; const char *p; Tcl_ResetResult(interp); n = TclReError(status, NULL, buf, sizeof(buf)); p = (n > sizeof(buf)) ? "..." : ""; - Tcl_AppendResult(interp, msg, buf, p, NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf("%s%s%s", msg, buf, p)); sprintf(cbuf, "%d", status); (void) TclReError(REG_ITOA, NULL, cbuf, sizeof(cbuf)); diff --git a/generic/tclResult.c b/generic/tclResult.c index 693c650..b8f9c92 100644 --- a/generic/tclResult.c +++ b/generic/tclResult.c @@ -812,9 +812,7 @@ Tcl_SetObjErrorCode( * * Tcl_GetErrorLine -- * - * Results: - * - * Side effects: + * Returns the line number associated with the current error. * *---------------------------------------------------------------------- */ @@ -831,9 +829,7 @@ Tcl_GetErrorLine( * * Tcl_SetErrorLine -- * - * Results: - * - * Side effects: + * Sets the line number associated with the current error. * *---------------------------------------------------------------------- */ @@ -980,7 +976,8 @@ TclProcessReturn( Tcl_DecrRefCount(iPtr->errorInfo); iPtr->errorInfo = NULL; } - Tcl_DictObjGet(NULL, iPtr->returnOpts, keys[KEY_ERRORINFO], &valuePtr); + Tcl_DictObjGet(NULL, iPtr->returnOpts, keys[KEY_ERRORINFO], + &valuePtr); if (valuePtr != NULL) { int infoLen; @@ -991,7 +988,8 @@ TclProcessReturn( iPtr->flags |= ERR_ALREADY_LOGGED; } } - Tcl_DictObjGet(NULL, iPtr->returnOpts, keys[KEY_ERRORSTACK], &valuePtr); + Tcl_DictObjGet(NULL, iPtr->returnOpts, keys[KEY_ERRORSTACK], + &valuePtr); if (valuePtr != NULL) { int len, valueObjc; Tcl_Obj **valueObjv; @@ -1004,26 +1002,36 @@ TclProcessReturn( Tcl_IncrRefCount(newObj); iPtr->errorStack = newObj; } + /* * List extraction done after duplication to avoid moving the rug * if someone does [return -errorstack [info errorstack]] */ - if (Tcl_ListObjGetElements(interp, valuePtr, &valueObjc, &valueObjv) == TCL_ERROR) { + + if (Tcl_ListObjGetElements(interp, valuePtr, &valueObjc, + &valueObjv) == TCL_ERROR) { return TCL_ERROR; } iPtr->resetErrorStack = 0; Tcl_ListObjLength(interp, iPtr->errorStack, &len); - /* reset while keeping the list intrep as much as possible */ - Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, valueObjc, valueObjv); + + /* + * Reset while keeping the list intrep as much as possible. + */ + + Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, valueObjc, + valueObjv); } - Tcl_DictObjGet(NULL, iPtr->returnOpts, keys[KEY_ERRORCODE], &valuePtr); + Tcl_DictObjGet(NULL, iPtr->returnOpts, keys[KEY_ERRORCODE], + &valuePtr); if (valuePtr != NULL) { Tcl_SetObjErrorCode(interp, valuePtr); } else { Tcl_SetErrorCode(interp, "NONE", NULL); } - Tcl_DictObjGet(NULL, iPtr->returnOpts, keys[KEY_ERRORLINE], &valuePtr); + Tcl_DictObjGet(NULL, iPtr->returnOpts, keys[KEY_ERRORLINE], + &valuePtr); if (valuePtr != NULL) { TclGetIntFromObj(NULL, valuePtr, &iPtr->errorLine); } @@ -1096,10 +1104,9 @@ TclMergeReturnOptions( * Value is not a legal dictionary. */ - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad ", compare, - " value: expected dictionary but got \"", - TclGetString(objv[1]), "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad %s value: expected dictionary but got \"%s\"", + compare, TclGetString(objv[1]))); Tcl_SetErrorCode(interp, "TCL", "RESULT", "ILLEGAL_OPTIONS", NULL); goto error; @@ -1128,7 +1135,8 @@ TclMergeReturnOptions( Tcl_DictObjGet(NULL, returnOpts, keys[KEY_CODE], &valuePtr); if (valuePtr != NULL) { - if (TCL_ERROR == TclGetCompletionCodeFromObj(interp, valuePtr, &code)) { + if (TclGetCompletionCodeFromObj(interp, valuePtr, + &code) == TCL_ERROR) { goto error; } Tcl_DictObjRemove(NULL, returnOpts, keys[KEY_CODE]); @@ -1146,10 +1154,9 @@ TclMergeReturnOptions( * Value is not a legal level. */ - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad -level value: " - "expected non-negative integer but got \"", - TclGetString(valuePtr), "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad -level value: expected non-negative integer but got" + " \"%s\"", TclGetString(valuePtr))); Tcl_SetErrorCode(interp, "TCL", "RESULT", "ILLEGAL_LEVEL", NULL); goto error; } @@ -1168,10 +1175,10 @@ TclMergeReturnOptions( /* * Value is not a list, which is illegal for -errorcode. */ - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad -errorcode value: " - "expected a list but got \"", - TclGetString(valuePtr), "\"", NULL); + + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad -errorcode value: expected a list but got \"%s\"", + TclGetString(valuePtr))); Tcl_SetErrorCode(interp, "TCL", "RESULT", "ILLEGAL_ERRORCODE", NULL); goto error; @@ -1190,10 +1197,10 @@ TclMergeReturnOptions( /* * Value is not a list, which is illegal for -errorstack. */ - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad -errorstack value: " - "expected a list but got \"", TclGetString(valuePtr), - "\"", NULL); + + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad -errorstack value: expected a list but got \"%s\"", + TclGetString(valuePtr))); Tcl_SetErrorCode(interp, "TCL", "RESULT", "NONLIST_ERRORSTACK", NULL); goto error; @@ -1202,10 +1209,10 @@ TclMergeReturnOptions( /* * Errorstack must always be an even-sized list */ - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, - "forbidden odd-sized list for -errorstack: \"", - TclGetString(valuePtr), "\"", NULL); + + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "forbidden odd-sized list for -errorstack: \"%s\"", + TclGetString(valuePtr))); Tcl_SetErrorCode(interp, "TCL", "RESULT", "ODDSIZEDLIST_ERRORSTACK", NULL); goto error; @@ -1307,7 +1314,8 @@ Tcl_GetReturnOptions( * * TclNoErrorStack -- * - * Removes the -errorstack entry from an options dict to avoid reference cycles + * Removes the -errorstack entry from an options dict to avoid reference + * cycles. * * Results: * The (unshared) argument options dict, modified in -place. @@ -1316,12 +1324,13 @@ Tcl_GetReturnOptions( */ Tcl_Obj * -TclNoErrorStack(Tcl_Interp *interp, Tcl_Obj *options) +TclNoErrorStack( + Tcl_Interp *interp, + Tcl_Obj *options) { Tcl_Obj **keys = GetKeys(); Tcl_DictObjRemove(interp, options, keys[KEY_ERRORSTACK]); - return options; } @@ -1356,9 +1365,8 @@ Tcl_SetReturnOptions( Tcl_IncrRefCount(options); if (TCL_ERROR == TclListObjGetElements(interp, options, &objc, &objv) || (objc % 2)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "expected dict but got \"", - TclGetString(options), "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "expected dict but got \"%s\"", TclGetString(options))); Tcl_SetErrorCode(interp, "TCL", "RESULT", "ILLEGAL_OPTIONS", NULL); code = TCL_ERROR; } else if (TCL_ERROR == TclMergeReturnOptions(interp, objc, objv, diff --git a/generic/tclScan.c b/generic/tclScan.c index d21bfaf..ef7eedf 100644 --- a/generic/tclScan.c +++ b/generic/tclScan.c @@ -261,6 +261,10 @@ ValidateFormat( int objIndex, xpgSize, nspace = numVars; int *nassign = TclStackAlloc(interp, nspace * sizeof(int)); char buf[TCL_UTF_MAX+1]; + Tcl_Obj *errorMsg; /* Place to build an error messages. Note that + * these are messy operations because we do + * not want to use the formatting engine; + * we're inside there! */ /* * Initialize an array that records the number of times a variable is @@ -328,9 +332,9 @@ ValidateFormat( gotSequential = 1; if (gotXpg) { mixedXPG: - Tcl_SetResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "cannot mix \"%\" and \"%n$\" conversion specifiers", - TCL_STATIC); + -1)); Tcl_SetErrorCode(interp, "TCL", "FORMAT", "MIXEDSPECTYPES", NULL); goto error; } @@ -375,9 +379,9 @@ ValidateFormat( switch (ch) { case 'c': if (flags & SCAN_WIDTH) { - Tcl_SetResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "field width may not be specified in %c conversion", - TCL_STATIC); + -1)); Tcl_SetErrorCode(interp, "TCL", "FORMAT", "BADWIDTH", NULL); goto error; } @@ -389,9 +393,11 @@ ValidateFormat( if (flags & (SCAN_LONGER|SCAN_BIG)) { invalidFieldSize: buf[Tcl_UniCharToUtf(ch, buf)] = '\0'; - Tcl_AppendResult(interp, - "field size modifier may not be specified in %", buf, - " conversion", NULL); + errorMsg = Tcl_NewStringObj( + "field size modifier may not be specified in %", -1); + Tcl_AppendToObj(errorMsg, buf, -1); + Tcl_AppendToObj(errorMsg, " conversion", -1); + Tcl_SetObjResult(interp, errorMsg); Tcl_SetErrorCode(interp, "TCL", "FORMAT", "BADSIZE", NULL); goto error; } @@ -409,8 +415,8 @@ ValidateFormat( break; case 'u': if (flags & SCAN_BIG) { - Tcl_SetResult(interp, - "unsigned bignum scans are invalid", TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "unsigned bignum scans are invalid", -1)); Tcl_SetErrorCode(interp, "TCL", "FORMAT", "BADUNSIGNED",NULL); goto error; } @@ -446,15 +452,18 @@ ValidateFormat( } break; badSet: - Tcl_SetResult(interp, "unmatched [ in format string", - TCL_STATIC); - Tcl_SetErrorCode(interp, "TCL", "FORMAT", "BRACKET", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "unmatched [ in format string", -1)); + Tcl_SetErrorCode(interp, "TCL", "FORMAT", "BRACKET", NULL); goto error; default: buf[Tcl_UniCharToUtf(ch, buf)] = '\0'; - Tcl_AppendResult(interp, "bad scan conversion character \"", buf, - "\"", NULL); - Tcl_SetErrorCode(interp, "TCL", "FORMAT", "BADTYPE", NULL); + errorMsg = Tcl_NewStringObj( + "bad scan conversion character \"", -1); + Tcl_AppendToObj(errorMsg, buf, -1); + Tcl_AppendToObj(errorMsg, "\"", -1); + Tcl_SetObjResult(interp, errorMsg); + Tcl_SetErrorCode(interp, "TCL", "FORMAT", "BADTYPE", NULL); goto error; } if (!(flags & SCAN_SUPPRESS)) { @@ -498,9 +507,9 @@ ValidateFormat( } for (i = 0; i < numVars; i++) { if (nassign[i] > 1) { - Tcl_SetResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "variable is assigned by multiple \"%n$\" conversion specifiers", - TCL_STATIC); + -1)); Tcl_SetErrorCode(interp, "TCL", "FORMAT", "POLYASSIGNED", NULL); goto error; } else if (!xpgSize && (nassign[i] == 0)) { @@ -509,9 +518,9 @@ ValidateFormat( * and/or numVars != 0), then too many vars were given */ - Tcl_SetResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "variable is not assigned by any conversion specifiers", - TCL_STATIC); + -1)); Tcl_SetErrorCode(interp, "TCL", "FORMAT", "UNASSIGNED", NULL); goto error; } @@ -522,13 +531,13 @@ ValidateFormat( badIndex: if (gotXpg) { - Tcl_SetResult(interp, "\"%n$\" argument index out of range", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "\"%n$\" argument index out of range", -1)); Tcl_SetErrorCode(interp, "TCL", "FORMAT", "INDEXRANGE", NULL); } else { - Tcl_SetResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "different numbers of variable names and field specifiers", - TCL_STATIC); + -1)); Tcl_SetErrorCode(interp, "TCL", "FORMAT", "FIELDVARMISMATCH", NULL); } diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c index 87cd4eb..0bede56 100644 --- a/generic/tclStubInit.c +++ b/generic/tclStubInit.c @@ -53,6 +53,15 @@ static int TclSockMinimumBuffersOld(int sock, int size) } #endif + +#if defined(_WIN32) || defined(__CYGWIN__) +#undef TclWinNToHS +#define TclWinNToHS winNToHS +static unsigned short TclWinNToHS(unsigned short ns) { + return ntohs(ns); +} +#endif + #ifdef __WIN32__ # define TclUnixWaitForFile 0 # define TclUnixCopyFile 0 @@ -89,12 +98,6 @@ void *TclWinGetTclInstance() return hInstance; } -unsigned short -TclWinNToHS(unsigned short ns) -{ - return ntohs(ns); -} - int TclWinSetSockOpt(SOCKET s, int level, int optname, const char *optval, int optlen) @@ -166,14 +169,6 @@ Tcl_WinTCharToUtf( string, len, dsPtr); } -#define TclMacOSXGetFileAttribute (int (*) (Tcl_Interp *, \ - int, Tcl_Obj *, Tcl_Obj **)) TclpCreateProcess -#define TclMacOSXMatchType (int (*) (Tcl_Interp *, const char *, \ - const char *, Tcl_StatBuf *, Tcl_GlobTypeData *)) TclpMakeFile -#define TclMacOSXNotifierAddRunLoopMode (void (*) (const void *)) TclpOpenFile -#define TclpLocaltime_unix (struct tm *(*) (const time_t *)) TclGetAndDetachPids -#define TclpGmtime_unix (struct tm *(*) (const time_t *)) TclpCloseFile - #else /* UNIX and MAC */ # define TclpLocaltime_unix TclpLocaltime # define TclpGmtime_unix TclpGmtime @@ -470,7 +465,7 @@ static const TclIntPlatStubs tclIntPlatStubs = { 0, /* 17 */ 0, /* 18 */ 0, /* 19 */ - 0, /* 20 */ + TclUnixOpenTemporaryFile, /* 20 */ 0, /* 21 */ 0, /* 22 */ 0, /* 23 */ @@ -534,7 +529,7 @@ static const TclIntPlatStubs tclIntPlatStubs = { TclMacOSXCopyFileAttributes, /* 17 */ TclMacOSXMatchType, /* 18 */ TclMacOSXNotifierAddRunLoopMode, /* 19 */ - 0, /* 20 */ + TclUnixOpenTemporaryFile, /* 20 */ 0, /* 21 */ 0, /* 22 */ 0, /* 23 */ @@ -1292,6 +1287,7 @@ const TclStubs tclStubs = { Tcl_LoadFile, /* 627 */ Tcl_FindSymbol, /* 628 */ Tcl_FSUnloadFile, /* 629 */ + Tcl_ZlibStreamSetCompressionDictionary, /* 630 */ }; /* !END!: Do not edit above this line. */ diff --git a/generic/tclTest.c b/generic/tclTest.c index 5337b99..484f851 100644 --- a/generic/tclTest.c +++ b/generic/tclTest.c @@ -15,11 +15,6 @@ * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ -#ifndef _WIN64 -/* See [Bug 2935503]: file mtime sets wrong time */ -# define _USE_32BIT_TIME_T -#endif - #undef STATIC_BUILD #ifndef USE_TCL_STUBS # define USE_TCL_STUBS @@ -306,11 +301,8 @@ static int TestexitmainloopCmd(ClientData dummy, Tcl_Interp *interp, int argc, const char **argv); static int TestpanicCmd(ClientData dummy, Tcl_Interp *interp, int argc, const char **argv); -static int TestfinexitObjCmd(ClientData dummy, - Tcl_Interp *interp, int objc, - Tcl_Obj *const objv[]); -static int TestparseargsCmd(ClientData dummy, Tcl_Interp *interp, - int objc, Tcl_Obj *const objv[]); +static int TestparseargsCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *const objv[]); static int TestparserObjCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); @@ -382,7 +374,8 @@ static Tcl_FSRenameFileProc TestReportRenameFile; static Tcl_FSCreateDirectoryProc TestReportCreateDirectory; static Tcl_FSCopyDirectoryProc TestReportCopyDirectory; static Tcl_FSRemoveDirectoryProc TestReportRemoveDirectory; -static Tcl_FSLoadFileProc TestReportLoadFile; +static int TestReportLoadFile(Tcl_Interp *interp, Tcl_Obj *pathPtr, + Tcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr); static Tcl_FSLinkProc TestReportLink; static Tcl_FSFileAttrStringsProc TestReportFileAttrStrings; static Tcl_FSFileAttrsGetProc TestReportFileAttrsGet; @@ -415,7 +408,7 @@ static int TestInterpResolverCmd(ClientData clientData, #if defined(HAVE_CPUID) || defined(__WIN32__) static int TestcpuidCmd(ClientData dummy, Tcl_Interp* interp, int objc, - Tcl_Obj *CONST objv[]); + Tcl_Obj *const objv[]); #endif static const Tcl_Filesystem testReportingFilesystem = { @@ -447,7 +440,7 @@ static const Tcl_Filesystem testReportingFilesystem = { TestReportRenameFile, TestReportCopyDirectory, TestReportLstat, - TestReportLoadFile, + (Tcl_FSLoadFileProc *) TestReportLoadFile, NULL /* cwd */, TestReportChdir }; @@ -631,7 +624,6 @@ Tcltest_Init( Tcl_CreateObjCommand(interp, "testlocale", TestlocaleCmd, NULL, NULL); Tcl_CreateCommand(interp, "testpanic", TestpanicCmd, NULL, NULL); - Tcl_CreateObjCommand(interp, "testfinexit", TestfinexitObjCmd, NULL, NULL); Tcl_CreateObjCommand(interp, "testparseargs", TestparseargsCmd,NULL,NULL); Tcl_CreateObjCommand(interp, "testparser", TestparserObjCmd, NULL, NULL); @@ -863,6 +855,7 @@ TestasyncCmd( || (Tcl_GetInt(interp, argv[4], &code) != TCL_OK)) { return TCL_ERROR; } + Tcl_MutexLock(&asyncTestMutex); for (asyncPtr = firstHandler; asyncPtr != NULL; asyncPtr = asyncPtr->nextPtr) { if (asyncPtr->id == id) { @@ -871,6 +864,7 @@ TestasyncCmd( } } Tcl_SetObjResult(interp, Tcl_NewStringObj(argv[3], -1)); + Tcl_MutexUnlock(&asyncTestMutex); return code; #ifdef TCL_THREADS } else if (strcmp(argv[1], "marklater") == 0) { @@ -880,6 +874,7 @@ TestasyncCmd( if (Tcl_GetInt(interp, argv[2], &id) != TCL_OK) { return TCL_ERROR; } + Tcl_MutexLock(&asyncTestMutex); for (asyncPtr = firstHandler; asyncPtr != NULL; asyncPtr = asyncPtr->nextPtr) { if (asyncPtr->id == id) { @@ -888,11 +883,13 @@ TestasyncCmd( INT2PTR(id), TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS) != TCL_OK) { Tcl_SetResult(interp, "can't create thread", TCL_STATIC); + Tcl_MutexUnlock(&asyncTestMutex); return TCL_ERROR; } break; } } + Tcl_MutexUnlock(&asyncTestMutex); } else { Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be create, delete, int, mark, or marklater", NULL); @@ -4540,47 +4537,6 @@ TestpanicCmd( return TCL_OK; } -/* - *---------------------------------------------------------------------- - * - * TestfinexitObjCmd -- - * - * Calls a variant of [exit] including the full finalization path. - * - * Results: - * Error, or doesn't return. - * - * Side effects: - * Exits application. - * - *---------------------------------------------------------------------- - */ - -static int -TestfinexitObjCmd( - ClientData dummy, /* Not used. */ - Tcl_Interp *interp, /* Current interpreter. */ - int objc, /* Number of arguments. */ - Tcl_Obj *const objv[]) /* Argument objects. */ -{ - int value; - - if ((objc != 1) && (objc != 2)) { - Tcl_WrongNumArgs(interp, 1, objv, "?returnCode?"); - return TCL_ERROR; - } - - if (objc == 1) { - value = 0; - } else if (Tcl_GetIntFromObj(interp, objv[1], &value) != TCL_OK) { - return TCL_ERROR; - } - Tcl_Finalize(); - TclpExit(value); - /*NOTREACHED*/ - return TCL_ERROR; /* Better not ever reach this! */ -} - static int TestfileCmd( ClientData dummy, /* Not used. */ diff --git a/generic/tclTimer.c b/generic/tclTimer.c index 36adaad..6b17825 100644 --- a/generic/tclTimer.c +++ b/generic/tclTimer.c @@ -829,8 +829,9 @@ Tcl_AfterObjCmd( if (Tcl_GetWideIntFromObj(NULL, objv[1], &ms) != TCL_OK) { const char *arg = Tcl_GetString(objv[1]); - Tcl_AppendResult(interp, "bad argument \"", arg, - "\": must be cancel, idle, info, or an integer", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad argument \"%s\": must be" + " cancel, idle, info, or an integer", arg)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "INDEX", "argument", arg, NULL); return TCL_ERROR; @@ -968,8 +969,8 @@ Tcl_AfterObjCmd( if (afterPtr == NULL) { const char *eventStr = TclGetString(objv[2]); - Tcl_AppendResult(interp, "event \"", eventStr, "\" doesn't exist", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "event \"%s\" doesn't exist", eventStr)); Tcl_SetErrorCode(interp, "TCL","LOOKUP","EVENT", eventStr, NULL); return TCL_ERROR; } else { diff --git a/generic/tclTomMathDecls.h b/generic/tclTomMathDecls.h index 4f6c3bf..ef22153 100644 --- a/generic/tclTomMathDecls.h +++ b/generic/tclTomMathDecls.h @@ -278,7 +278,7 @@ EXTERN int TclBN_mp_cnt_lsb(const mp_int *a); typedef struct TclTomMathStubs { int magic; - const struct TclTomMathStubHooks *hooks; + void *hooks; int (*tclBN_epoch) (void); /* 0 */ int (*tclBN_revision) (void); /* 1 */ diff --git a/generic/tclTomMathStubLib.c b/generic/tclTomMathStubLib.c index e7e4aea..a3bc4b3 100644 --- a/generic/tclTomMathStubLib.c +++ b/generic/tclTomMathStubLib.c @@ -73,10 +73,10 @@ TclTomMathInitializeStubs( tclTomMathStubsPtr = stubsPtr; return actualVersion; } - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "error loading ", packageName, - " (requested version ", version, ", actual version ", - actualVersion, "): ", errMsg, NULL); + + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error loading %s (requested version %s, actual version %s): %s", + packageName, version, actualVersion, errMsg)); return NULL; } diff --git a/generic/tclTrace.c b/generic/tclTrace.c index 529c38a..519f201 100644 --- a/generic/tclTrace.c +++ b/generic/tclTrace.c @@ -366,8 +366,9 @@ Tcl_TraceObjCmd( return TCL_OK; badVarOps: - Tcl_AppendResult(interp, "bad operations \"", flagOps, - "\": should be one or more of rwua", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad operations \"%s\": should be one or more of rwua", + flagOps)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRACE", "BADOPS", NULL); return TCL_ERROR; } @@ -434,9 +435,9 @@ TraceExecutionObjCmd( return result; } if (listLen == 0) { - Tcl_SetResult(interp, "bad operation list \"\": must be " - "one or more of enter, leave, enterstep, or leavestep", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "bad operation list \"\": must be one or more of" + " enter, leave, enterstep, or leavestep", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRACE", "NOOPS", NULL); return TCL_ERROR; @@ -677,8 +678,9 @@ TraceCommandObjCmd( return result; } if (listLen == 0) { - Tcl_SetResult(interp, "bad operation list \"\": must be " - "one or more of delete or rename", TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "bad operation list \"\": must be one or more of" + " delete or rename", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRACE", "NOOPS", NULL); return TCL_ERROR; @@ -875,8 +877,9 @@ TraceVariableObjCmd( return result; } if (listLen == 0) { - Tcl_SetResult(interp, "bad operation list \"\": must be " - "one or more of array, read, unset, or write", TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "bad operation list \"\": must be one or more of" + " array, read, unset, or write", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRACE", "NOOPS", NULL); return TCL_ERROR; @@ -2715,7 +2718,8 @@ TclCallVarTraces( if (disposeFlags & TCL_TRACE_RESULT_OBJECT) { Tcl_SetObjResult((Tcl_Interp *)iPtr, (Tcl_Obj *) result); } else { - Tcl_SetResult((Tcl_Interp *)iPtr, result, TCL_STATIC); + Tcl_SetObjResult((Tcl_Interp *)iPtr, + Tcl_NewStringObj(result, -1)); } Tcl_AddErrorInfo((Tcl_Interp *)iPtr, ""); diff --git a/generic/tclUniData.c b/generic/tclUniData.c index 2fabe58..5c88639 100644 --- a/generic/tclUniData.c +++ b/generic/tclUniData.c @@ -882,7 +882,7 @@ static const unsigned char groupMap[] = { 18, 18, 18, 18, 7, 7, 7, 5, 6, 85, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 7, 7, 7, 5, 6, 0, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 111, 111, 111, 111, 86, 111, 111, 111, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, diff --git a/generic/tclUtf.c b/generic/tclUtf.c index f0d08e7..4b5b37b 100644 --- a/generic/tclUtf.c +++ b/generic/tclUtf.c @@ -1516,6 +1516,9 @@ Tcl_UniCharIsSpace( if (((Tcl_UniChar) ch) < ((Tcl_UniChar) 0x80)) { return isspace(UCHAR(ch)); /* INTL: ISO space */ + } else if ((Tcl_UniChar) ch == 0x0085 || (Tcl_UniChar) ch == 0x200b + || (Tcl_UniChar) ch == 0x2060 || (Tcl_UniChar) ch == 0xfeff) { + return 1; } else { return ((SPACE_BITS >> GetCategory(ch)) & 1); } diff --git a/generic/tclUtil.c b/generic/tclUtil.c index 5c62cb7..0cbb7c9 100644 --- a/generic/tclUtil.c +++ b/generic/tclUtil.c @@ -26,9 +26,9 @@ static ProcessGlobalValue executableName = { }; /* - * The following values are used in the flags arguments of Tcl*Scan*Element and - * Tcl*Convert*Element. The values TCL_DONT_USE_BRACES and TCL_DONT_QUOTE_HASH - * are defined in tcl.h, like so: + * The following values are used in the flags arguments of Tcl*Scan*Element + * and Tcl*Convert*Element. The values TCL_DONT_USE_BRACES and + * TCL_DONT_QUOTE_HASH are defined in tcl.h, like so: * #define TCL_DONT_USE_BRACES 1 #define TCL_DONT_QUOTE_HASH 8 @@ -54,8 +54,8 @@ static ProcessGlobalValue executableName = { * conversion is most appropriate for Tcl*Convert*Element() to perform, and * sets two bits of the flags value to indicate the mode selected. * - * CONVERT_NONE The element needs no quoting. Its literal string - * is suitable as is. + * CONVERT_NONE The element needs no quoting. Its literal string is + * suitable as is. * CONVERT_BRACE The conversion should be enclosing the literal string * in braces. * CONVERT_ESCAPE The conversion should be using backslashes to escape @@ -63,19 +63,19 @@ static ProcessGlobalValue executableName = { * CONVERT_MASK A mask value used to extract the conversion mode from * the flags argument. * Also indicates a strange conversion mode where all - * special characters are escaped with backslashes - * *except for braces*. This is a strange and unnecessary + * special characters are escaped with backslashes + * *except for braces*. This is a strange and unnecessary * case, but it's part of the historical way in which - * lists have been formatted in Tcl. To experiment with + * lists have been formatted in Tcl. To experiment with * removing this case, set the value of COMPAT to 0. * - * One last flag value is used only by callers of TclScanElement(). The flag + * One last flag value is used only by callers of TclScanElement(). The flag * value produced by a call to Tcl*Scan*Element() will never leave this bit * set. * - * CONVERT_ANY The caller of TclScanElement() declares it can make - * no promise about what public flags will be passed to - * the matching call of TclConvertElement(). As such, + * CONVERT_ANY The caller of TclScanElement() declares it can make no + * promise about what public flags will be passed to the + * matching call of TclConvertElement(). As such, * TclScanElement() has to determine the worst case * destination buffer length over all possibilities, and * in other cases this means an overestimate of the @@ -129,17 +129,17 @@ const Tcl_ObjType tclEndOffsetType = { /* * * STRING REPRESENTATION OF LISTS * * * * - * The next several routines implement the conversions of strings to and - * from Tcl lists. To understand their operation, the rules of parsing - * and generating the string representation of lists must be known. Here - * we describe them in one place. + * The next several routines implement the conversions of strings to and from + * Tcl lists. To understand their operation, the rules of parsing and + * generating the string representation of lists must be known. Here we + * describe them in one place. * - * A list is made up of zero or more elements. Any string is a list if - * it is made up of alternating substrings of element-separating ASCII - * whitespace and properly formatted elements. + * A list is made up of zero or more elements. Any string is a list if it is + * made up of alternating substrings of element-separating ASCII whitespace + * and properly formatted elements. * - * The ASCII characters which can make up the whitespace between list - * elements are: + * The ASCII characters which can make up the whitespace between list elements + * are: * * \u0009 \t TAB * \u000A \n NEWLINE @@ -158,69 +158,68 @@ const Tcl_ObjType tclEndOffsetType = { * * Unlike command parsing, the BACKSLASH NEWLINE sequence is not * considered to be a whitespace character. * - * * Other Unicode whitespace characters (recognized by - * [string is space] or Tcl_UniCharIsSpace()) do not play any role - * as element separators in Tcl lists. + * * Other Unicode whitespace characters (recognized by [string is space] + * or Tcl_UniCharIsSpace()) do not play any role as element separators + * in Tcl lists. * * * The NUL byte ought not appear, as it is not in strings properly * encoded for Tcl, but if it is present, it is not treated as - * separating whitespace, or a string terminator. It is just - * another character in a list element. - * - * The interpretaton of a formatted substring as a list element follows - * rules similar to the parsing of the words of a command in a Tcl script. - * Backslash substitution plays a key role, and is defined exactly as it is - * in command parsing. The same routine, TclParseBackslash() is used in both - * command parsing and list parsing. - * - * NOTE: This means that if and when backslash substitution rules ever - * change for command parsing, the interpretation of strings as lists also - * changes. + * separating whitespace, or a string terminator. It is just another + * character in a list element. + * + * The interpretaton of a formatted substring as a list element follows rules + * similar to the parsing of the words of a command in a Tcl script. Backslash + * substitution plays a key role, and is defined exactly as it is in command + * parsing. The same routine, TclParseBackslash() is used in both command + * parsing and list parsing. + * + * NOTE: This means that if and when backslash substitution rules ever change + * for command parsing, the interpretation of strings as lists also changes. * * Backslash substitution replaces an "escape sequence" of one or more * characters starting with * \u005c \ BACKSLASH - * with a single character. The one character escape sequent case happens - * only when BACKSLASH is the last character in the string. In all other - * cases, the escape sequence is at least two characters long. + * with a single character. The one character escape sequent case happens only + * when BACKSLASH is the last character in the string. In all other cases, the + * escape sequence is at least two characters long. * - * The formatted substrings are interpreted as element values according to - * the following cases: + * The formatted substrings are interpreted as element values according to the + * following cases: * * * If the first character of a formatted substring is * \u007b { OPEN BRACE * then the end of the substring is the matching * \u007d } CLOSE BRACE - * character, where matching is determined by counting nesting levels, - * and not including any brace characters that are contained within a - * backslash escape sequence in the nesting count. Having found the - * matching brace, all characters between the braces are the string - * value of the element. If no matching close brace is found before the - * end of the string, the string is not a Tcl list. If the character - * following the close brace is not an element separating whitespace - * character, or the end of the string, then the string is not a Tcl list. - * - * NOTE: this differs from a brace-quoted word in the parsing of a - * Tcl command only in its treatment of the backslash-newline sequence. - * In a list element, the literal characters in the backslash-newline - * sequence become part of the element value. In a script word, - * conversion to a single SPACE character is done. + * character, where matching is determined by counting nesting levels, and + * not including any brace characters that are contained within a backslash + * escape sequence in the nesting count. Having found the matching brace, + * all characters between the braces are the string value of the element. + * If no matching close brace is found before the end of the string, the + * string is not a Tcl list. If the character following the close brace is + * not an element separating whitespace character, or the end of the string, + * then the string is not a Tcl list. + * + * NOTE: this differs from a brace-quoted word in the parsing of a Tcl + * command only in its treatment of the backslash-newline sequence. In a + * list element, the literal characters in the backslash-newline sequence + * become part of the element value. In a script word, conversion to a + * single SPACE character is done. * * NOTE: Most list element values can be represented by a formatted - * substring using brace quoting. The exceptions are any element value - * that includes an unbalanced brace not in a backslash escape sequence, - * and any value that ends with a backslash not itself in a backslash - * escape sequence. + * substring using brace quoting. The exceptions are any element value that + * includes an unbalanced brace not in a backslash escape sequence, and any + * value that ends with a backslash not itself in a backslash escape + * sequence. * * * If the first character of a formatted substring is * \u0022 " QUOTE * then the end of the substring is the next QUOTE character, not counting * any QUOTE characters that are contained within a backslash escape - * sequence. If no next QUOTE is found before the end of the string, the - * string is not a Tcl list. If the character following the closing QUOTE - * is not an element separating whitespace character, or the end of the - * string, then the string is not a Tcl list. Having found the limits - * of the substring, the element value is produced by performing backslash + * sequence. If no next QUOTE is found before the end of the string, the + * string is not a Tcl list. If the character following the closing QUOTE is + * not an element separating whitespace character, or the end of the string, + * then the string is not a Tcl list. Having found the limits of the + * substring, the element value is produced by performing backslash * substitution on the character sequence between the open and close QUOTEs. * * NOTE: Any element value can be represented by this style of formatting, @@ -231,7 +230,7 @@ const Tcl_ObjType tclEndOffsetType = { * of the substring, the element value is produced by performing backslash * substitution on it. * - * NOTE: Any element value can be represented by this style of formatting, + * NOTE: Any element value can be represented by this style of formatting, * given suitable choice of backslash escape sequences, with one exception. * The empty string cannot be represented as a list element without the use * of either braces or quotes to delimit it. @@ -239,32 +238,32 @@ const Tcl_ObjType tclEndOffsetType = { * This collection of parsing rules is implemented in the routine * TclFindElement(). * - * In order to produce lists that can be parsed by these rules, we need - * the ability to distinguish between characters that are part of a list - * element value from characters providing syntax that define the structure - * of the list. This means that our code that generates lists must at a - * minimum be able to produce escape sequences for the 10 characters - * identified above that have significance to a list parser. + * In order to produce lists that can be parsed by these rules, we need the + * ability to distinguish between characters that are part of a list element + * value from characters providing syntax that define the structure of the + * list. This means that our code that generates lists must at a minimum be + * able to produce escape sequences for the 10 characters identified above + * that have significance to a list parser. * - * * * CANONICAL LISTS * * * * * + * * * CANONICAL LISTS * * * * * * * In addition to the basic rules for parsing strings into Tcl lists, there * are additional properties to be met by the set of list values that are * generated by Tcl. Such list values are often said to be in "canonical * form": * - * * When any canonical list is evaluated as a Tcl script, it is a script - * of either zero commands (an empty list) or exactly one command. The - * command word is exactly the first element of the list, and each argument - * word is exactly one of the following elements of the list. This means - * that any characters that have special meaning during script evaluation - * need special treatment when canonical lists are produced: + * * When any canonical list is evaluated as a Tcl script, it is a script of + * either zero commands (an empty list) or exactly one command. The command + * word is exactly the first element of the list, and each argument word is + * exactly one of the following elements of the list. This means that any + * characters that have special meaning during script evaluation need + * special treatment when canonical lists are produced: * * * Whitespace between elements may not include NEWLINE. * * The command terminating character, * \u003b ; SEMICOLON - * must be BRACEd, QUOTEd, or escaped so that it does not terminate - * the command prematurely. + * must be BRACEd, QUOTEd, or escaped so that it does not terminate the + * command prematurely. * * Any of the characters that begin substitutions in scripts, * \u0024 $ DOLLAR * \u005b [ OPEN BRACKET @@ -274,11 +273,10 @@ const Tcl_ObjType tclEndOffsetType = { * \u0023 # HASH * that HASH character must be BRACEd, QUOTEd, or escaped so that it * does not convert the command into a comment. - * * Any list element that contains the character sequence - * BACKSLASH NEWLINE cannot be formatted with BRACEs. The - * BACKSLASH character must be represented by an escape - * sequence, and unless QUOTEs are used, the NEWLINE must - * be as well. + * * Any list element that contains the character sequence BACKSLASH + * NEWLINE cannot be formatted with BRACEs. The BACKSLASH character + * must be represented by an escape sequence, and unless QUOTEs are + * used, the NEWLINE must be as well. * * * It is also guaranteed that one can use a canonical list as a building * block of a larger script within command substitution, as in this example: @@ -289,66 +287,66 @@ const Tcl_ObjType tclEndOffsetType = { * * * Finally it is guaranteed that enclosing a canonical list in braces * produces a new value that is also a canonical list. This new list has - * length 1, and its only element is the original canonical list. This - * same guarantee also makes it possible to construct scripts where an - * argument word is given a list value by enclosing the canonical form - * of that list in braces: + * length 1, and its only element is the original canonical list. This same + * guarantee also makes it possible to construct scripts where an argument + * word is given a list value by enclosing the canonical form of that list + * in braces: * set script "puts {[list $one $two $three]}"; eval $script * This sort of coding was once fairly common, though it's become more * idiomatic to see the following instead: * set script [list puts [list $one $two $three]]; eval $script - * In order to support this guarantee, every canonical list must have + * In order to support this guarantee, every canonical list must have * balance when counting those braces that are not in escape sequences. * * Within these constraints, the canonical list generation routines - * TclScanElement() and TclConvertElement() attempt to generate the string - * for any list that is easiest to read. When an element value is itself + * TclScanElement() and TclConvertElement() attempt to generate the string for + * any list that is easiest to read. When an element value is itself * acceptable as the formatted substring, it is usually used (CONVERT_NONE). - * When some quoting or escaping is required, use of BRACEs (CONVERT_BRACE) - * is usually preferred over the use of escape sequences (CONVERT_ESCAPE). - * There are some exceptions to both of these preferences for reasons of - * code simplicity, efficiency, and continuation of historical habits. - * Canonical lists never use the QUOTE formatting to delimit their elements - * because that form of quoting does not nest, which makes construction of - * nested lists far too much trouble. Canonical lists always use only a - * single SPACE character for element-separating whitespace. + * When some quoting or escaping is required, use of BRACEs (CONVERT_BRACE) is + * usually preferred over the use of escape sequences (CONVERT_ESCAPE). There + * are some exceptions to both of these preferences for reasons of code + * simplicity, efficiency, and continuation of historical habits. Canonical + * lists never use the QUOTE formatting to delimit their elements because that + * form of quoting does not nest, which makes construction of nested lists far + * too much trouble. Canonical lists always use only a single SPACE character + * for element-separating whitespace. * * * * FUTURE CONSIDERATIONS * * * * * When a list element requires quoting or escaping due to a CLOSE BRACKET * character or an internal QUOTE character, a strange formatting mode is - * recommended. For example, if the value "a{b]c}d" is converted by the - * usual modes: + * recommended. For example, if the value "a{b]c}d" is converted by the usual + * modes: * * CONVERT_BRACE: a{b]c}d => {a{b]c}d} * CONVERT_ESCAPE: a{b]c}d => a\{b\]c\}d * - * we get perfectly usable formatted list elements. However, this is not - * what Tcl releases have been producing. Instead, we have: + * we get perfectly usable formatted list elements. However, this is not what + * Tcl releases have been producing. Instead, we have: * * CONVERT_MASK: a{b]c}d => a{b\]c}d * - * where the CLOSE BRACKET is escaped, but the BRACEs are not. The same - * effect can be seen replacing ] with " in this example. There does not - * appear to be any functional or aesthetic purpose for this strange - * additional mode. The sole purpose I can see for preserving it is to - * keep generating the same formatted lists programmers have become accustomed - * to, and perhaps written tests to expect. That is, compatibility only. - * The additional code complexity required to support this mode is significant. - * The lines of code supporting it are delimited in the routines below with - * #if COMPAT directives. This makes it easy to experiment with eliminating - * this formatting mode simply with "#define COMPAT 0" above. I believe - * this is worth considering. + * where the CLOSE BRACKET is escaped, but the BRACEs are not. The same effect + * can be seen replacing ] with " in this example. There does not appear to be + * any functional or aesthetic purpose for this strange additional mode. The + * sole purpose I can see for preserving it is to keep generating the same + * formatted lists programmers have become accustomed to, and perhaps written + * tests to expect. That is, compatibility only. The additional code + * complexity required to support this mode is significant. The lines of code + * supporting it are delimited in the routines below with #if COMPAT + * directives. This makes it easy to experiment with eliminating this + * formatting mode simply with "#define COMPAT 0" above. I believe this is + * worth considering. * - * Another consideration is the treatment of QUOTE characters in list elements. - * TclConvertElement() must have the ability to produce the escape sequence - * \" so that when a list element begins with a QUOTE we do not confuse - * that first character with a QUOTE used as list syntax to define list - * structure. However, that is the only place where QUOTE characters need - * quoting. In this way, handling QUOTE could really be much more like - * the way we handle HASH which also needs quoting and escaping only in - * particular situations. Following up this could increase the set of - * list elements that can use the CONVERT_NONE formatting mode. + * Another consideration is the treatment of QUOTE characters in list + * elements. TclConvertElement() must have the ability to produce the escape + * sequence \" so that when a list element begins with a QUOTE we do not + * confuse that first character with a QUOTE used as list syntax to define + * list structure. However, that is the only place where QUOTE characters need + * quoting. In this way, handling QUOTE could really be much more like the way + * we handle HASH which also needs quoting and escaping only in particular + * situations. Following up this could increase the set of list elements that + * can use the CONVERT_NONE formatting mode. * * More speculative is that the demands of canonical list form require brace * balance for the list as a whole, while the current implementation achieves @@ -366,15 +364,15 @@ const Tcl_ObjType tclEndOffsetType = { * * Given 'bytes' pointing to 'numBytes' bytes, scan through them and * count the number of whitespace runs that could be list element - * separators. If 'numBytes' is -1, scan to the terminating '\0'. - * Not a full list parser. Typically used to get a quick and dirty - * overestimate of length size in order to allocate space for an - * actual list parser to operate with. + * separators. If 'numBytes' is -1, scan to the terminating '\0'. Not a + * full list parser. Typically used to get a quick and dirty overestimate + * of length size in order to allocate space for an actual list parser to + * operate with. * * Results: - * Returns the largest number of list elements that could possibly - * be in this string, interpreted as a Tcl list. If 'endPtr' is not - * NULL, writes a pointer to the end of the string scanned there. + * Returns the largest number of list elements that could possibly be in + * this string, interpreted as a Tcl list. If 'endPtr' is not NULL, + * writes a pointer to the end of the string scanned there. * * Side effects: * None. @@ -395,16 +393,25 @@ TclMaxListLength( goto done; } - /* No list element before leading white space */ + /* + * No list element before leading white space. + */ + count += 1 - TclIsSpaceProc(*bytes); - /* Count white space runs as potential element separators */ + /* + * Count white space runs as potential element separators. + */ + while (numBytes) { if ((numBytes == -1) && (*bytes == '\0')) { break; } if (TclIsSpaceProc(*bytes)) { - /* Space run started; bump count */ + /* + * Space run started; bump count. + */ + count++; do { bytes++; @@ -413,16 +420,22 @@ TclMaxListLength( if ((numBytes == 0) || ((numBytes == -1) && (*bytes == '\0'))) { break; } - /* (*bytes) is non-space; return to counting state */ + + /* + * (*bytes) is non-space; return to counting state. + */ } bytes++; numBytes -= (numBytes != -1); } - /* No list element following trailing white space */ + /* + * No list element following trailing white space. + */ + count -= TclIsSpaceProc(bytes[-1]); - done: + done: if (endPtr) { *endPtr = bytes; } @@ -449,18 +462,18 @@ TclMaxListLength( * that's part of the element. If this is the last argument in the list, * then *nextPtr will point just after the last character in the list * (i.e., at the character at list+listLength). If sizePtr is non-NULL, - * *sizePtr is filled in with the number of bytes in the element. If - * the element is in braces, then *elementPtr will point to the character + * *sizePtr is filled in with the number of bytes in the element. If the + * element is in braces, then *elementPtr will point to the character * after the opening brace and *sizePtr will not include either of the * braces. If there isn't an element in the list, *sizePtr will be zero, * and both *elementPtr and *nextPtr will point just after the last * character in the list. If literalPtr is non-NULL, *literalPtr is set - * to a boolean value indicating whether the substring returned as - * the values of **elementPtr and *sizePtr is the literal value of - * a list element. If not, a call to TclCopyAndCollapse() is needed - * to produce the actual value of the list element. Note: this function - * does NOT collapse backslash sequences, but uses *literalPtr to tell - * callers when it is required for them to do so. + * to a boolean value indicating whether the substring returned as the + * values of **elementPtr and *sizePtr is the literal value of a list + * element. If not, a call to TclCopyAndCollapse() is needed to produce + * the actual value of the list element. Note: this function does NOT + * collapse backslash sequences, but uses *literalPtr to tell callers + * when it is required for them to do so. * * Side effects: * None. @@ -587,9 +600,10 @@ TclFindElement( /* * A backslash sequence not within a brace quoted element * means the value of the element is different from the - * substring we are parsing. A call to TclCopyAndCollapse() - * is needed to produce the element value. Inform the caller. + * substring we are parsing. A call to TclCopyAndCollapse() is + * needed to produce the element value. Inform the caller. */ + literal = 0; } TclParseBackslash(p, limit - p, &numChars, NULL); @@ -655,16 +669,16 @@ TclFindElement( if (p == limit) { if (openBraces != 0) { if (interp != NULL) { - Tcl_SetResult(interp, "unmatched open brace in list", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "unmatched open brace in list", -1)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "LIST", "BRACE", NULL); } return TCL_ERROR; } else if (inQuotes) { if (interp != NULL) { - Tcl_SetResult(interp, "unmatched open quote in list", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "unmatched open quote in list", -1)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "LIST", "QUOTE", NULL); } @@ -697,9 +711,9 @@ TclFindElement( * * Results: * Count bytes get copied from src to dst. Along the way, backslash - * sequences are substituted in the copy. After scanning count bytes - * from src, a null character is placed at the end of dst. Returns - * the number of bytes that got written to dst. + * sequences are substituted in the copy. After scanning count bytes from + * src, a null character is placed at the end of dst. Returns the number + * of bytes that got written to dst. * * Side effects: * None. @@ -717,6 +731,7 @@ TclCopyAndCollapse( while (count > 0) { char c = *src; + if (c == '\\') { int numRead; int backslashCount = TclParseBackslash(src, count, &numRead, dst); @@ -780,12 +795,11 @@ Tcl_SplitList( int length, size, i, result, elSize; /* - * Allocate enough space to work in. A (const char *) for each - * (possible) list element plus one more for terminating NULL, - * plus as many bytes as in the original string value, plus one - * more for a terminating '\0'. Space used to hold element separating - * white space in the original string gets re-purposed to hold '\0' - * characters in the argv array. + * Allocate enough space to work in. A (const char *) for each (possible) + * list element plus one more for terminating NULL, plus as many bytes as + * in the original string value, plus one more for a terminating '\0'. + * Space used to hold element separating white space in the original + * string gets re-purposed to hold '\0' characters in the argv array. */ size = TclMaxListLength(list, -1, &end) + 1; @@ -810,8 +824,8 @@ Tcl_SplitList( if (i >= size) { ckfree(argv); if (interp != NULL) { - Tcl_SetResult(interp, "internal error in Tcl_SplitList", - TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "internal error in Tcl_SplitList", -1)); Tcl_SetErrorCode(interp, "TCL", "INTERNAL", "Tcl_SplitList", NULL); } @@ -844,9 +858,9 @@ Tcl_SplitList( * enclosing braces) to make the string into a valid Tcl list element. * * Results: - * The return value is an overestimate of the number of bytes that - * will be needed by Tcl_ConvertElement to produce a valid list element - * from src. The word at *flagPtr is filled in with a value needed by + * The return value is an overestimate of the number of bytes that will + * be needed by Tcl_ConvertElement to produce a valid list element from + * src. The word at *flagPtr is filled in with a value needed by * Tcl_ConvertElement when doing the actual conversion. * * Side effects: @@ -876,10 +890,10 @@ Tcl_ScanElement( * to the first null byte. * * Results: - * The return value is an overestimate of the number of bytes that - * will be needed by Tcl_ConvertCountedElement to produce a valid list - * element from src. The word at *flagPtr is filled in with a value - * needed by Tcl_ConvertCountedElement when doing the actual conversion. + * The return value is an overestimate of the number of bytes that will + * be needed by Tcl_ConvertCountedElement to produce a valid list element + * from src. The word at *flagPtr is filled in with a value needed by + * Tcl_ConvertCountedElement when doing the actual conversion. * * Side effects: * None. @@ -906,24 +920,24 @@ Tcl_ScanCountedElement( * * TclScanElement -- * - * This function is a companion function to TclConvertElement. It - * scans a string to see what needs to be done to it (e.g. add - * backslashes or enclosing braces) to make the string into a valid Tcl - * list element. If length is -1, then the string is scanned from src up - * to the first null byte. A NULL value for src is treated as an - * empty string. The incoming value of *flagPtr is a report from the - * caller what additional flags it will pass to TclConvertElement(). + * This function is a companion function to TclConvertElement. It scans a + * string to see what needs to be done to it (e.g. add backslashes or + * enclosing braces) to make the string into a valid Tcl list element. If + * length is -1, then the string is scanned from src up to the first null + * byte. A NULL value for src is treated as an empty string. The incoming + * value of *flagPtr is a report from the caller what additional flags it + * will pass to TclConvertElement(). * * Results: - * The recommended formatting mode for the element is determined and - * a value is written to *flagPtr indicating that recommendation. This + * The recommended formatting mode for the element is determined and a + * value is written to *flagPtr indicating that recommendation. This * recommendation is combined with the incoming flag values in *flagPtr * set by the caller to determine how many bytes will be needed by * TclConvertElement() in which to write the formatted element following - * the recommendation modified by the flag values. This number of bytes - * is the return value of the routine. In some situations it may be - * an overestimate, but so long as the caller passes the same flags - * to TclConvertElement(), it will be large enough. + * the recommendation modified by the flag values. This number of bytes + * is the return value of the routine. In some situations it may be an + * overestimate, but so long as the caller passes the same flags to + * TclConvertElement(), it will be large enough. * * Side effects: * None. @@ -941,7 +955,7 @@ TclScanElement( const char *p = src; int nestingLevel = 0; /* Brace nesting count */ int forbidNone = 0; /* Do not permit CONVERT_NONE mode. Something - needs protection or escape. */ + * needs protection or escape. */ int requireEscape = 0; /* Force use of CONVERT_ESCAPE mode. For some * reason bare or brace-quoted form fails. */ int extra = 0; /* Count of number of extra bytes needed for @@ -953,10 +967,13 @@ TclScanElement( int preferEscape = 0; /* Use preferences to track whether to use */ int preferBrace = 0; /* CONVERT_MASK mode. */ int braceCount = 0; /* Count of all braces '{' '}' seen. */ -#endif +#endif /* COMPAT */ if ((p == NULL) || (length == 0) || ((*p == '\0') && (length == -1))) { - /* Empty string element must be brace quoted. */ + /* + * Empty string element must be brace quoted. + */ + *flagPtr = CONVERT_BRACE; return 2; } @@ -966,10 +983,11 @@ TclScanElement( * Must escape or protect so leading character of value is not * misinterpreted as list element delimiting syntax. */ + forbidNone = 1; #if COMPAT preferBrace = 1; -#endif +#endif /* COMPAT */ } while (length) { @@ -978,18 +996,21 @@ TclScanElement( case '{': /* TYPE_BRACE */ #if COMPAT braceCount++; -#endif +#endif /* COMPAT */ extra++; /* Escape '{' => '\{' */ nestingLevel++; break; case '}': /* TYPE_BRACE */ #if COMPAT braceCount++; -#endif +#endif /* COMPAT */ extra++; /* Escape '}' => '\}' */ nestingLevel--; if (nestingLevel < 0) { - /* Unbalanced braces! Cannot format with brace quoting. */ + /* + * Unbalanced braces! Cannot format with brace quoting. + */ + requireEscape = 1; } break; @@ -1002,7 +1023,7 @@ TclScanElement( break; #else /* FLOW THROUGH */ -#endif +#endif /* COMPAT */ case '[': /* TYPE_SUBS */ case '$': /* TYPE_SUBS */ case ';': /* TYPE_COMMAND_END */ @@ -1016,18 +1037,25 @@ TclScanElement( extra++; /* Escape sequences all one byte longer. */ #if COMPAT preferBrace = 1; -#endif +#endif /* COMPAT */ break; case '\\': /* TYPE_SUBS */ extra++; /* Escape '\' => '\\' */ if ((length == 1) || ((length == -1) && (p[1] == '\0'))) { - /* Final backslash. Cannot format with brace quoting. */ + /* + * Final backslash. Cannot format with brace quoting. + */ + requireEscape = 1; break; } if (p[1] == '\n') { extra++; /* Escape newline => '\n', one byte longer */ - /* Backslash newline sequence. Brace quoting not permitted. */ + + /* + * Backslash newline sequence. Brace quoting not permitted. + */ + requireEscape = 1; length -= (length > 0); p++; @@ -1041,7 +1069,7 @@ TclScanElement( forbidNone = 1; #if COMPAT preferBrace = 1; -#endif +#endif /* COMPAT */ break; case '\0': /* TYPE_SUBS */ if (length == -1) { @@ -1055,22 +1083,33 @@ TclScanElement( p++; } - endOfString: + endOfString: if (nestingLevel != 0) { - /* Unbalanced braces! Cannot format with brace quoting. */ + /* + * Unbalanced braces! Cannot format with brace quoting. + */ + requireEscape = 1; } - /* We need at least as many bytes as are in the element value... */ + /* + * We need at least as many bytes as are in the element value... + */ + bytesNeeded = p - src; if (requireEscape) { /* - * We must use escape sequences. Add all the extra bytes needed - * to have room to create them. + * We must use escape sequences. Add all the extra bytes needed to + * have room to create them. */ + bytesNeeded += extra; - /* Make room to escape leading #, if needed. */ + + /* + * Make room to escape leading #, if needed. + */ + if ((*src == '#') && !(*flagPtr & TCL_DONT_QUOTE_HASH)) { bytesNeeded++; } @@ -1080,12 +1119,13 @@ TclScanElement( if (*flagPtr & CONVERT_ANY) { /* * The caller has not let us know what flags it will pass to - * TclConvertElement() so compute the max size we might need for - * any possible choice. Normally the formatting using escape - * sequences is the longer one, and a minimum "extra" value of 2 - * makes sure we don't request too small a buffer in those edge - * cases where that's not true. + * TclConvertElement() so compute the max size we might need for any + * possible choice. Normally the formatting using escape sequences is + * the longer one, and a minimum "extra" value of 2 makes sure we + * don't request too small a buffer in those edge cases where that's + * not true. */ + if (extra < 2) { extra = 2; } @@ -1093,59 +1133,78 @@ TclScanElement( *flagPtr |= TCL_DONT_USE_BRACES; } if (forbidNone) { - /* We must request some form of quoting of escaping... */ + /* + * We must request some form of quoting of escaping... + */ + #if COMPAT if (preferEscape && !preferBrace) { /* - * If we are quoting solely due to ] or internal " characters - * use the CONVERT_MASK mode where we escape all special - * characters except for braces. "extra" counted space needed - * to escape braces too, so substract "braceCount" to get our - * actual needs. + * If we are quoting solely due to ] or internal " characters use + * the CONVERT_MASK mode where we escape all special characters + * except for braces. "extra" counted space needed to escape + * braces too, so substract "braceCount" to get our actual needs. */ + bytesNeeded += (extra - braceCount); /* Make room to escape leading #, if needed. */ if ((*src == '#') && !(*flagPtr & TCL_DONT_QUOTE_HASH)) { bytesNeeded++; } + /* * If the caller reports it will direct TclConvertElement() to * use full escapes on the element, add back the bytes needed to * escape the braces. */ + if (*flagPtr & TCL_DONT_USE_BRACES) { bytesNeeded += braceCount; } *flagPtr = CONVERT_MASK; goto overflowCheck; } -#endif +#endif /* COMPAT */ if (*flagPtr & TCL_DONT_USE_BRACES) { /* * If the caller reports it will direct TclConvertElement() to * use escapes, add the extra bytes needed to have room for them. */ + bytesNeeded += extra; - /* Make room to escape leading #, if needed. */ + + /* + * Make room to escape leading #, if needed. + */ + if ((*src == '#') && !(*flagPtr & TCL_DONT_QUOTE_HASH)) { bytesNeeded++; } } else { - /* Add 2 bytes for room for the enclosing braces. */ + /* + * Add 2 bytes for room for the enclosing braces. + */ + bytesNeeded += 2; } *flagPtr = CONVERT_BRACE; goto overflowCheck; } - /* So far, no need to quote or escape anything. */ + /* + * So far, no need to quote or escape anything. + */ + if ((*src == '#') && !(*flagPtr & TCL_DONT_QUOTE_HASH)) { - /* If we need to quote a leading #, make room to enclose in braces. */ + /* + * If we need to quote a leading #, make room to enclose in braces. + */ + bytesNeeded += 2; } *flagPtr = CONVERT_NONE; - overflowCheck: + overflowCheck: if (bytesNeeded < 0) { Tcl_Panic("TclScanElement: string length overflow"); } @@ -1220,9 +1279,9 @@ Tcl_ConvertCountedElement( * * TclConvertElement -- * - * This is a companion function to TclScanElement. Given the - * information produced by TclScanElement, this function converts - * a string to a list element equal to that string. + * This is a companion function to TclScanElement. Given the information + * produced by TclScanElement, this function converts a string to a list + * element equal to that string. * * Results: * Information is copied to *dst in the form of a list element identical @@ -1236,7 +1295,8 @@ Tcl_ConvertCountedElement( *---------------------------------------------------------------------- */ -int TclConvertElement( +int +TclConvertElement( register const char *src, /* Source information for list element. */ int length, /* Number of bytes in src, or -1. */ char *dst, /* Place to put list-ified element. */ @@ -1245,19 +1305,28 @@ int TclConvertElement( int conversion = flags & CONVERT_MASK; char *p = dst; - /* Let the caller demand we use escape sequences rather than braces. */ + /* + * Let the caller demand we use escape sequences rather than braces. + */ + if ((flags & TCL_DONT_USE_BRACES) && (conversion & CONVERT_BRACE)) { conversion = CONVERT_ESCAPE; } - /* No matter what the caller demands, empty string must be braced! */ - if ((src == NULL) || (length == 0) || ((*src == '\0') && (length == -1))) { + /* + * No matter what the caller demands, empty string must be braced! + */ + + if ((src == NULL) || (length == 0) || (*src == '\0' && length == -1)) { src = tclEmptyStringRep; length = 0; conversion = CONVERT_BRACE; } - /* Escape leading hash as needed and requested. */ + /* + * Escape leading hash as needed and requested. + */ + if ((*src == '#') && !(flags & TCL_DONT_QUOTE_HASH)) { if (conversion == CONVERT_ESCAPE) { p[0] = '\\'; @@ -1270,7 +1339,10 @@ int TclConvertElement( } } - /* No escape or quoting needed. Copy the literal string value. */ + /* + * No escape or quoting needed. Copy the literal string value. + */ + if (conversion == CONVERT_NONE) { if (length == -1) { /* TODO: INT_MAX overflow? */ @@ -1284,7 +1356,10 @@ int TclConvertElement( } } - /* Formatted string is original string enclosed in braces. */ + /* + * Formatted string is original string enclosed in braces. + */ + if (conversion == CONVERT_BRACE) { *p = '{'; p++; @@ -1304,7 +1379,10 @@ int TclConvertElement( /* conversion == CONVERT_ESCAPE or CONVERT_MASK */ - /* Formatted string is original string converted to escape sequences. */ + /* + * Formatted string is original string converted to escape sequences. + */ + for ( ; length; src++, length -= (length > 0)) { switch (*src) { case ']': @@ -1320,13 +1398,12 @@ int TclConvertElement( case '{': case '}': #if COMPAT - if (conversion == CONVERT_ESCAPE) { -#endif + if (conversion == CONVERT_ESCAPE) +#endif /* COMPAT */ + { *p = '\\'; p++; -#if COMPAT } -#endif break; case '\f': *p = '\\'; @@ -1362,13 +1439,15 @@ int TclConvertElement( if (length == -1) { return p - dst; } + /* - * If we reach this point, there's an embedded NULL in the - * string range being processed, which should not happen when - * the encoding rules for Tcl strings are properly followed. - * If the day ever comes when we stop tolerating such things, - * this is where to put the Tcl_Panic(). + * If we reach this point, there's an embedded NULL in the string + * range being processed, which should not happen when the + * encoding rules for Tcl strings are properly followed. If the + * day ever comes when we stop tolerating such things, this is + * where to put the Tcl_Panic(). */ + break; } *p = *src; @@ -1402,17 +1481,18 @@ Tcl_Merge( int argc, /* How many strings to merge. */ const char *const *argv) /* Array of string values. */ { -# define LOCAL_SIZE 20 +#define LOCAL_SIZE 20 int localFlags[LOCAL_SIZE], *flagPtr = NULL; int i, bytesNeeded = 0; char *result, *dst; const int maxFlags = UINT_MAX / sizeof(int); + /* + * Handle empty list case first, so logic of the general case can be + * simpler. + */ + if (argc == 0) { - /* - * Handle empty list case first, so logic of the general case - * can be simpler. - */ result = ckalloc(1); result[0] = '\0'; return result; @@ -1426,17 +1506,17 @@ Tcl_Merge( flagPtr = localFlags; } else if (argc > maxFlags) { /* - * We cannot allocate a large enough flag array to format this - * list in one pass. We could imagine converting this routine - * to a multi-pass implementation, but for sizeof(int) == 4, - * the limit is a max of 2^30 list elements and since each element - * is at least one byte formatted, and requires one byte space - * between it and the next one, that a minimum space requirement - * of 2^31 bytes, which is already INT_MAX. If we tried to format - * a list of > maxFlags elements, we're just going to overflow - * the size limits on the formatted string anyway, so just issue - * that same panic early. + * We cannot allocate a large enough flag array to format this list in + * one pass. We could imagine converting this routine to a multi-pass + * implementation, but for sizeof(int) == 4, the limit is a max of + * 2^30 list elements and since each element is at least one byte + * formatted, and requires one byte space between it and the next one, + * that a minimum space requirement of 2^31 bytes, which is already + * INT_MAX. If we tried to format a list of > maxFlags elements, we're + * just going to overflow the size limits on the formatted string + * anyway, so just issue that same panic early. */ + Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); } else { flagPtr = ckalloc(argc * sizeof(int)); @@ -1511,9 +1591,10 @@ Tcl_Backslash( *---------------------------------------------------------------------- * * TclTrimRight -- - * Takes two counted strings in the Tcl encoding which must both be - * null terminated. Conceptually trims from the right side of the - * first string all characters found in the second string. + * + * Takes two counted strings in the Tcl encoding which must both be null + * terminated. Conceptually trims from the right side of the first string + * all characters found in the second string. * * Results: * The number of bytes to be removed from the end of the string. @@ -1526,10 +1607,10 @@ Tcl_Backslash( int TclTrimRight( - const char *bytes, /* String to be trimmed... */ - int numBytes, /* ...and its length in bytes */ - const char *trim, /* String of trim characters... */ - int numTrim) /* ...and its length in bytes */ + const char *bytes, /* String to be trimmed... */ + int numBytes, /* ...and its length in bytes */ + const char *trim, /* String of trim characters... */ + int numTrim) /* ...and its length in bytes */ { const char *p = bytes + numBytes; int pInc; @@ -1538,12 +1619,18 @@ TclTrimRight( Tcl_Panic("TclTrimRight works only on null-terminated strings"); } - /* Empty strings -> nothing to do */ + /* + * Empty strings -> nothing to do. + */ + if ((numBytes == 0) || (numTrim == 0)) { return 0; } - /* Outer loop: iterate over string to be trimmed */ + /* + * Outer loop: iterate over string to be trimmed. + */ + do { Tcl_UniChar ch1; const char *q = trim; @@ -1552,7 +1639,10 @@ TclTrimRight( p = Tcl_UtfPrev(p, bytes); pInc = TclUtfToUniChar(p, &ch1); - /* Inner loop: scan trim string for match to current character */ + /* + * Inner loop: scan trim string for match to current character. + */ + do { Tcl_UniChar ch2; int qInc = TclUtfToUniChar(q, &ch2); @@ -1566,7 +1656,10 @@ TclTrimRight( } while (bytesLeft); if (bytesLeft == 0) { - /* No match; trim task done; *p is last non-trimmed char */ + /* + * No match; trim task done; *p is last non-trimmed char. + */ + p += pInc; break; } @@ -1579,9 +1672,10 @@ TclTrimRight( *---------------------------------------------------------------------- * * TclTrimLeft -- - * Takes two counted strings in the Tcl encoding which must both be - * null terminated. Conceptually trims from the left side of the - * first string all characters found in the second string. + * + * Takes two counted strings in the Tcl encoding which must both be null + * terminated. Conceptually trims from the left side of the first string + * all characters found in the second string. * * Results: * The number of bytes to be removed from the start of the string. @@ -1594,10 +1688,10 @@ TclTrimRight( int TclTrimLeft( - const char *bytes, /* String to be trimmed... */ - int numBytes, /* ...and its length in bytes */ - const char *trim, /* String of trim characters... */ - int numTrim) /* ...and its length in bytes */ + const char *bytes, /* String to be trimmed... */ + int numBytes, /* ...and its length in bytes */ + const char *trim, /* String of trim characters... */ + int numTrim) /* ...and its length in bytes */ { const char *p = bytes; @@ -1605,19 +1699,28 @@ TclTrimLeft( Tcl_Panic("TclTrimLeft works only on null-terminated strings"); } - /* Empty strings -> nothing to do */ + /* + * Empty strings -> nothing to do. + */ + if ((numBytes == 0) || (numTrim == 0)) { return 0; } - /* Outer loop: iterate over string to be trimmed */ + /* + * Outer loop: iterate over string to be trimmed. + */ + do { Tcl_UniChar ch1; int pInc = TclUtfToUniChar(p, &ch1); const char *q = trim; int bytesLeft = numTrim; - /* Inner loop: scan trim string for match to current character */ + /* + * Inner loop: scan trim string for match to current character. + */ + do { Tcl_UniChar ch2; int qInc = TclUtfToUniChar(q, &ch2); @@ -1631,7 +1734,10 @@ TclTrimLeft( } while (bytesLeft); if (bytesLeft == 0) { - /* No match; trim task done; *p is first non-trimmed char */ + /* + * No match; trim task done; *p is first non-trimmed char. + */ + break; } @@ -1673,14 +1779,20 @@ Tcl_Concat( int i, needSpace = 0, bytesNeeded = 0; char *result, *p; - /* Dispose of the empty result corner case first to simplify later code */ + /* + * Dispose of the empty result corner case first to simplify later code. + */ + if (argc == 0) { result = (char *) ckalloc(1); result[0] = '\0'; return result; } - /* First allocate the result buffer at the size required */ + /* + * First allocate the result buffer at the size required. + */ + for (i = 0; i < argc; i++) { bytesNeeded += strlen(argv[i]); if (bytesNeeded < 0) { @@ -1689,13 +1801,18 @@ Tcl_Concat( } if (bytesNeeded + argc - 1 < 0) { /* - * Panic test could be tighter, but not going to bother for - * this legacy routine. + * Panic test could be tighter, but not going to bother for this + * legacy routine. */ + Tcl_Panic("Tcl_Concat: max size of Tcl value exceeded"); } - /* All element bytes + (argc - 1) spaces + 1 terminating NULL */ - result = (char *) ckalloc((unsigned) (bytesNeeded + argc)); + + /* + * All element bytes + (argc - 1) spaces + 1 terminating NULL. + */ + + result = ckalloc((unsigned) (bytesNeeded + argc)); for (p = result, i = 0; i < argc; i++) { int trim, elemLength; @@ -1704,26 +1821,35 @@ Tcl_Concat( element = argv[i]; elemLength = strlen(argv[i]); - /* Trim away the leading whitespace */ + /* + * Trim away the leading whitespace. + */ + trim = TclTrimLeft(element, elemLength, CONCAT_WS, CONCAT_WS_SIZE); element += trim; elemLength -= trim; /* - * Trim away the trailing whitespace. Do not permit trimming - * to expose a final backslash character. + * Trim away the trailing whitespace. Do not permit trimming to expose + * a final backslash character. */ trim = TclTrimRight(element, elemLength, CONCAT_WS, CONCAT_WS_SIZE); trim -= trim && (element[elemLength - trim - 1] == '\\'); elemLength -= trim; - /* If we're left with empty element after trimming, do nothing */ + /* + * If we're left with empty element after trimming, do nothing. + */ + if (elemLength == 0) { continue; } - /* Append to the result with space if needed */ + /* + * Append to the result with space if needed. + */ + if (needSpace) { *p++ = ' '; } @@ -1802,9 +1928,10 @@ Tcl_ConcatObj( /* * Something cannot be determined to be safe, so build the concatenation * the slow way, using the string representations. + * + * First try to pre-allocate the size required. */ - /* First try to pre-allocate the size required */ for (i = 0; i < objc; i++) { element = TclGetStringFromObj(objv[i], &elemLength); bytesNeeded += elemLength; @@ -1812,11 +1939,13 @@ Tcl_ConcatObj( break; } } + /* - * Does not matter if this fails, will simply try later to build up - * the string with each Append reallocating as needed with the usual - * string append algorithm. When that fails it will report the error. + * Does not matter if this fails, will simply try later to build up the + * string with each Append reallocating as needed with the usual string + * append algorithm. When that fails it will report the error. */ + TclNewObj(resPtr); Tcl_AttemptSetObjLength(resPtr, bytesNeeded + objc - 1); Tcl_SetObjLength(resPtr, 0); @@ -1826,26 +1955,35 @@ Tcl_ConcatObj( element = TclGetStringFromObj(objv[i], &elemLength); - /* Trim away the leading whitespace */ + /* + * Trim away the leading whitespace. + */ + trim = TclTrimLeft(element, elemLength, CONCAT_WS, CONCAT_WS_SIZE); element += trim; elemLength -= trim; /* - * Trim away the trailing whitespace. Do not permit trimming - * to expose a final backslash character. + * Trim away the trailing whitespace. Do not permit trimming to expose + * a final backslash character. */ trim = TclTrimRight(element, elemLength, CONCAT_WS, CONCAT_WS_SIZE); trim -= trim && (element[elemLength - trim - 1] == '\\'); elemLength -= trim; - /* If we're left with empty element after trimming, do nothing */ + /* + * If we're left with empty element after trimming, do nothing. + */ + if (elemLength == 0) { continue; } - /* Append to the result with space if needed */ + /* + * Append to the result with space if needed. + */ + if (needSpace) { Tcl_AppendToObj(resPtr, " ", 1); } @@ -2249,6 +2387,7 @@ TclByteArrayMatch( /* * Matches ranges of form [a-z] or [z-a]. */ + break; } } else if (startChar == ch1) { @@ -2295,9 +2434,9 @@ TclByteArrayMatch( * * TclStringMatchObj -- * - * See if a particular string matches a particular pattern. - * Allows case insensitivity. This is the generic multi-type handler - * for the various matching algorithms. + * See if a particular string matches a particular pattern. Allows case + * insensitivity. This is the generic multi-type handler for the various + * matching algorithms. * * Results: * The return value is 1 if string matches pattern, and 0 otherwise. The @@ -2898,12 +3037,12 @@ Tcl_PrintDouble( * Tcl 8.4 implements the first of these, which gives rise to * anomalies in formatting: * - * % expr 0.1 - * 0.10000000000000001 - * % expr 0.01 - * 0.01 - * % expr 1e-7 - * 9.9999999999999995e-08 + * % expr 0.1 + * 0.10000000000000001 + * % expr 0.01 + * 0.01 + * % expr 1e-7 + * 9.9999999999999995e-08 * * For human readability, it appears better to choose the second rule, * and let [expr 0.1] return 0.1. But for 8.4 compatibility, we prefer @@ -2916,8 +3055,8 @@ Tcl_PrintDouble( */ digits = TclDoubleDigits(value, *precisionPtr, - TCL_DD_E_FORMAT /* | TCL_DD_SHORTEN_FLAG */, - &exponent, &signum, &end); + TCL_DD_E_FORMAT /* | TCL_DD_SHORTEN_FLAG */, + &exponent, &signum, &end); } if (signum) { *dst++ = '-'; @@ -3173,10 +3312,10 @@ TclNeedSpace( */ int -TclFormatInt(buffer, n) - char *buffer; /* Points to the storage into which the +TclFormatInt( + char *buffer, /* Points to the storage into which the * formatted characters are written. */ - long n; /* The integer to format. */ + long n) /* The integer to format. */ { long intVal; int i; @@ -3194,9 +3333,9 @@ TclFormatInt(buffer, n) } /* - * Check whether "n" is the maximum negative value. This is - * -2^(m-1) for an m-bit word, and has no positive equivalent; - * negating it produces the same value. + * Check whether "n" is the maximum negative value. This is -2^(m-1) for + * an m-bit word, and has no positive equivalent; negating it produces the + * same value. */ intVal = -n; /* [Bug 3390638] Workaround for*/ @@ -3228,6 +3367,7 @@ TclFormatInt(buffer, n) for (j = 0; j < i; j++, i--) { char tmp = buffer[i]; + buffer[i] = buffer[j]; buffer[j] = tmp; } @@ -3333,16 +3473,10 @@ TclGetIntForIndex( parseError: if (interp != NULL) { - /* - * The result might not be empty; this resets it which should be both - * a cheap operation, and of little problem because this is an - * error-generation path anyway. - */ - bytes = Tcl_GetString(objPtr); - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad index \"", bytes, - "\": must be integer?[+-]integer? or end?[+-]integer?", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad index \"%s\": must be integer?[+-]integer? or" + " end?[+-]integer?", bytes)); if (!strncmp(bytes, "end-", 4)) { bytes += 4; } @@ -3434,9 +3568,8 @@ SetEndOffsetFromAny( if ((*bytes != 'e') || (strncmp(bytes, "end", (size_t)((length > 3) ? 3 : length)) != 0)) { if (interp != NULL) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad index \"", bytes, - "\": must be end?[+-]integer?", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad index \"%s\": must be end?[+-]integer?", bytes)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "INDEX", NULL); } return TCL_ERROR; @@ -3470,9 +3603,8 @@ SetEndOffsetFromAny( badIndexFormat: if (interp != NULL) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "bad index \"", bytes, - "\": must be end?[+-]integer?", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad index \"%s\": must be end?[+-]integer?", bytes)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "INDEX", NULL); } return TCL_ERROR; @@ -3548,8 +3680,8 @@ TclCheckBadOctal( * be added to an existing error message as extra info. */ - Tcl_AppendResult(interp, " (looks like invalid octal number)", - NULL); + Tcl_AppendToObj(Tcl_GetObjResult(interp), + " (looks like invalid octal number)", -1); } return 1; } @@ -3701,7 +3833,7 @@ TclSetProcessGlobalValue( if (NULL != pgvPtr->value) { ckfree(pgvPtr->value); } else { - Tcl_CreateExitHandler(FreeProcessGlobalValue, (ClientData) pgvPtr); + Tcl_CreateExitHandler(FreeProcessGlobalValue, pgvPtr); } bytes = Tcl_GetStringFromObj(newValue, &pgvPtr->numBytes); pgvPtr->value = ckalloc(pgvPtr->numBytes + 1); @@ -4165,7 +4297,7 @@ TclReToGlob( invalidGlob: if (interp != NULL) { - Tcl_AppendResult(interp, msg, NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj(msg, -1)); Tcl_SetErrorCode(interp, "TCL", "RE2GLOB", code, NULL); } Tcl_DStringFree(dsPtr); diff --git a/generic/tclVar.c b/generic/tclVar.c index e92dc5f..1c01e41 100644 --- a/generic/tclVar.c +++ b/generic/tclVar.c @@ -3065,7 +3065,8 @@ ArrayStartSearchCmd( if ((varPtr == NULL) || !TclIsVarArray(varPtr) || TclIsVarUndefined(varPtr)) { - Tcl_AppendResult(interp, "\"", varName, "\" isn't an array", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "\"%s\" isn't an array", varName)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ARRAY", varName, NULL); return TCL_ERROR; } @@ -3160,8 +3161,8 @@ ArrayAnyMoreCmd( if ((varPtr == NULL) || !TclIsVarArray(varPtr) || TclIsVarUndefined(varPtr)) { - Tcl_AppendResult(interp, "\"", TclGetString(varNameObj), - "\" isn't an array", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "\"%s\" isn't an array", TclGetString(varNameObj))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ARRAY", TclGetString(varNameObj), NULL); return TCL_ERROR; @@ -3266,8 +3267,8 @@ ArrayNextElementCmd( if ((varPtr == NULL) || !TclIsVarArray(varPtr) || TclIsVarUndefined(varPtr)) { - Tcl_AppendResult(interp, "\"", TclGetString(varNameObj), - "\" isn't an array", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "\"%s\" isn't an array", TclGetString(varNameObj))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ARRAY", TclGetString(varNameObj), NULL); return TCL_ERROR; @@ -3376,8 +3377,8 @@ ArrayDoneSearchCmd( if ((varPtr == NULL) || !TclIsVarArray(varPtr) || TclIsVarUndefined(varPtr)) { - Tcl_AppendResult(interp, "\"", TclGetString(varNameObj), - "\" isn't an array", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "\"%s\" isn't an array", TclGetString(varNameObj))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ARRAY", TclGetString(varNameObj), NULL); return TCL_ERROR; @@ -4019,8 +4020,8 @@ ArrayStatsCmd( if ((varPtr == NULL) || !TclIsVarArray(varPtr) || TclIsVarUndefined(varPtr)) { - Tcl_AppendResult(interp, "\"", TclGetString(varNameObj), - "\" isn't an array", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "\"%s\" isn't an array", TclGetString(varNameObj))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ARRAY", TclGetString(varNameObj), NULL); return TCL_ERROR; @@ -4028,7 +4029,8 @@ ArrayStatsCmd( stats = Tcl_HashStats((Tcl_HashTable *) varPtr->value.tablePtr); if (stats == NULL) { - Tcl_SetResult(interp, "error reading array statistics", TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "error reading array statistics", -1)); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewStringObj(stats, -1)); @@ -4222,15 +4224,15 @@ TclInitArrayCmd( static const EnsembleImplMap arrayImplMap[] = { {"anymore", ArrayAnyMoreCmd, NULL, NULL, NULL, 0}, {"donesearch", ArrayDoneSearchCmd, NULL, NULL, NULL, 0}, - {"exists", ArrayExistsCmd, NULL, NULL, NULL, 0}, + {"exists", ArrayExistsCmd, TclCompileArrayExistsCmd, NULL, NULL, 0}, {"get", ArrayGetCmd, NULL, NULL, NULL, 0}, {"names", ArrayNamesCmd, NULL, NULL, NULL, 0}, {"nextelement", ArrayNextElementCmd, NULL, NULL, NULL, 0}, - {"set", ArraySetCmd, NULL, NULL, NULL, 0}, + {"set", ArraySetCmd, TclCompileArraySetCmd, NULL, NULL, 0}, {"size", ArraySizeCmd, NULL, NULL, NULL, 0}, {"startsearch", ArrayStartSearchCmd, NULL, NULL, NULL, 0}, {"statistics", ArrayStatsCmd, NULL, NULL, NULL, 0}, - {"unset", ArrayUnsetCmd, NULL, NULL, NULL, 0}, + {"unset", ArrayUnsetCmd, TclCompileArrayUnsetCmd, NULL, NULL, 0}, {NULL, NULL, NULL, NULL, NULL, 0} }; @@ -4317,10 +4319,10 @@ ObjMakeUpvar( || (varFramePtr == NULL) || !HasLocalVars(varFramePtr) || (strstr(TclGetString(myNamePtr), "::") != NULL))) { - Tcl_AppendResult((Tcl_Interp *) iPtr, "bad variable name \"", - TclGetString(myNamePtr), "\": upvar won't create " + Tcl_SetObjResult((Tcl_Interp *) iPtr, Tcl_ObjPrintf( + "bad variable name \"%s\": upvar won't create " "namespace variable that refers to procedure variable", - NULL); + TclGetString(myNamePtr))); Tcl_SetErrorCode(interp, "TCL", "UPVAR", "INVERTED", NULL); return TCL_ERROR; } @@ -4418,9 +4420,10 @@ TclPtrObjMakeUpvar( * myName looks like an array reference. */ - Tcl_AppendResult((Tcl_Interp *) iPtr, "bad variable name \"", - myName, "\": upvar won't create a scalar variable " - "that looks like an array element", NULL); + Tcl_SetObjResult((Tcl_Interp *) iPtr, Tcl_ObjPrintf( + "bad variable name \"%s\": upvar won't create a" + " scalar variable that looks like an array element", + myName)); Tcl_SetErrorCode(interp, "TCL", "UPVAR", "LOCAL_ELEMENT", NULL); return TCL_ERROR; @@ -4447,15 +4450,15 @@ TclPtrObjMakeUpvar( } if (varPtr == otherPtr) { - Tcl_SetResult((Tcl_Interp *) iPtr, - "can't upvar from variable to itself", TCL_STATIC); + Tcl_SetObjResult((Tcl_Interp *) iPtr, Tcl_NewStringObj( + "can't upvar from variable to itself", -1)); Tcl_SetErrorCode(interp, "TCL", "UPVAR", "SELF", NULL); return TCL_ERROR; } if (TclIsVarTraced(varPtr)) { - Tcl_AppendResult((Tcl_Interp *) iPtr, "variable \"", myName, - "\" has traces: can't use for upvar", NULL); + Tcl_SetObjResult((Tcl_Interp *) iPtr, Tcl_ObjPrintf( + "variable \"%s\" has traces: can't use for upvar", myName)); Tcl_SetErrorCode(interp, "TCL", "UPVAR", "TRACED", NULL); return TCL_ERROR; } else if (!TclIsVarUndefined(varPtr)) { @@ -4469,8 +4472,8 @@ TclPtrObjMakeUpvar( */ if (!TclIsVarLink(varPtr)) { - Tcl_AppendResult((Tcl_Interp *) iPtr, "variable \"", myName, - "\" already exists", NULL); + Tcl_SetObjResult((Tcl_Interp *) iPtr, Tcl_ObjPrintf( + "variable \"%s\" already exists", myName)); Tcl_SetErrorCode(interp, "TCL", "UPVAR", "EXISTS", NULL); return TCL_ERROR; } @@ -4968,8 +4971,8 @@ Tcl_UpvarObjCmd( * for this particular case. */ - Tcl_AppendResult(interp, "bad level \"", TclGetString(levelObj), "\"", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad level \"%s\"", TclGetString(levelObj))); Tcl_SetErrorCode(interp, "TCL", "VALUE", "LEVEL", NULL); return TCL_ERROR; } @@ -4978,8 +4981,8 @@ Tcl_UpvarObjCmd( * We've now finished with parsing levels; skip to the variable names. */ - objc -= hasLevel+1; - objv += hasLevel+1; + objc -= hasLevel + 1; + objv += hasLevel + 1; /* * Iterate over each (other variable, local variable) pair. Divide the @@ -5060,8 +5063,8 @@ SetArraySearchObj( return TCL_OK; syntax: - Tcl_AppendResult(interp, "illegal search identifier \"", string, "\"", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "illegal search identifier \"%s\"", string)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ARRAYSEARCH", string, NULL); return TCL_ERROR; } @@ -5126,10 +5129,9 @@ ParseSearchId( */ if (strcmp(string+offset, varName) != 0) { - Tcl_AppendResult(interp, "search identifier \"", string, - "\" isn't for variable \"", varName, "\"", NULL); - Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ARRAYSEARCH", string, - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "search identifier \"%s\" isn't for variable \"%s\"", + string, varName)); goto badLookup; } @@ -5153,7 +5155,8 @@ ParseSearchId( } } } - Tcl_AppendResult(interp, "couldn't find search \"", string, "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't find search \"%s\"", string)); badLookup: Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ARRAYSEARCH", string, NULL); return NULL; @@ -5894,8 +5897,8 @@ ObjFindNamespaceVar( Tcl_DecrRefCount(simpleNamePtr); } if ((varPtr == NULL) && (flags & TCL_LEAVE_ERR_MSG)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "unknown variable \"", name, "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unknown variable \"%s\"", name)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "VARIABLE", name, NULL); } return (Tcl_Var) varPtr; diff --git a/generic/tclZlib.c b/generic/tclZlib.c index a799639..11490f1 100644 --- a/generic/tclZlib.c +++ b/generic/tclZlib.c @@ -5,7 +5,7 @@ * * Copyright (C) 2004-2005 Pascal Scheffers <pascal@scheffers.net> * Copyright (C) 2005 Unitas Software B.V. - * Copyright (c) 2008-2009 Donal K. Fellows + * Copyright (c) 2008-2012 Donal K. Fellows * * Parts written by Jean-Claude Wippler, as part of Tclkit, placed in the * public domain March 2003. @@ -74,8 +74,27 @@ typedef struct { int wbits; /* The encoded compression mode, so we can * restart the stream if necessary. */ Tcl_Command cmd; /* Token for the associated Tcl command. */ + Tcl_Obj *compDictObj; /* Byte-array object containing compression + * dictionary (not dictObj!) to use if + * necessary. */ + int flags; /* Miscellaneous flag bits. */ + GzipHeader *gzHeaderPtr; /* If we've allocated a gzip header + * structure. */ } ZlibStreamHandle; +#define DICT_TO_SET 0x1 /* If we need to set a compression dictionary + * in the low-level engine at the next + * opportunity. */ + +/* + * Macros to make it clearer in some of the twiddlier accesses what is + * happening. + */ + +#define IsRawStream(zshPtr) ((zshPtr)->format == TCL_ZLIB_FORMAT_RAW) +#define HaveDictToSet(zshPtr) ((zshPtr)->flags & DICT_TO_SET) +#define DictWasSet(zshPtr) ((zshPtr)->flags |= ~DICT_TO_SET) + /* * Structure used for stacked channel compression and decompression. */ @@ -88,6 +107,11 @@ typedef struct { * for compression on output, or * TCL_ZLIB_STREAM_INFLATE for decompression * on input. */ + int format; /* What format of data is going on the wire. + * Needed so that the correct [fconfigure] + * options can be enabled. */ + int readAheadLimit; /* The maximum number of bytes to read from + * the underlying stream in one go. */ z_stream inStream; /* Structure used by zlib for decompression of * input. */ z_stream outStream; /* Structure used by zlib for compression of @@ -101,6 +125,9 @@ typedef struct { * compressing a gzip stream. */ Tcl_TimerToken timer; /* Timer used for keeping events fresh. */ Tcl_DString decompressed; /* Buffer for decompression results. */ + Tcl_Obj *compDictObj; /* Byte-array object containing compression + * dictionary (not dictObj!) to use if + * necessary. */ } ZlibChannelData; /* @@ -117,10 +144,15 @@ typedef struct { #define OUT_HEADER 0x4 /* - * Size of buffers allocated by default. Should be enough... + * Size of buffers allocated by default, and the range it can be set to. The + * same sorts of values apply to streams, except with different limits (they + * permit byte-level activity). Channels always use bytes unless told to use + * larger buffers. */ #define DEFAULT_BUFFER_SIZE 4096 +#define MIN_NONSTREAM_BUFFER_SIZE 16 +#define MAX_BUFFER_SIZE 65536 /* * Prototypes for private procedures defined later in this file: @@ -138,19 +170,29 @@ static Tcl_DriverSetOptionProc ZlibTransformSetOption; static Tcl_DriverWatchProc ZlibTransformWatch; static Tcl_ObjCmdProc ZlibCmd; static Tcl_ObjCmdProc ZlibStreamCmd; +static Tcl_ObjCmdProc ZlibStreamAddCmd; +static Tcl_ObjCmdProc ZlibStreamHeaderCmd; +static Tcl_ObjCmdProc ZlibStreamPutCmd; -static void ConvertError(Tcl_Interp *interp, int code); +static void ConvertError(Tcl_Interp *interp, int code, + uLong adler); +static Tcl_Obj * ConvertErrorToList(int code, uLong adler); static void ExtractHeader(gz_header *headerPtr, Tcl_Obj *dictObj); static int GenerateHeader(Tcl_Interp *interp, Tcl_Obj *dictObj, GzipHeader *headerPtr, int *extraSizePtr); +static int ZlibPushSubcmd(Tcl_Interp *interp, int objc, + Tcl_Obj *const objv[]); static inline int ResultCopy(ZlibChannelData *cd, char *buf, int toRead); static int ResultGenerate(ZlibChannelData *cd, int n, int flush, int *errorCodePtr); static Tcl_Channel ZlibStackChannelTransform(Tcl_Interp *interp, - int mode, int format, int level, - Tcl_Channel channel, Tcl_Obj *gzipHeaderDictPtr); + int mode, int format, int level, int limit, + Tcl_Channel channel, Tcl_Obj *gzipHeaderDictPtr, + Tcl_Obj *compDictObj); static void ZlibStreamCleanup(ZlibStreamHandle *zshPtr); +static int ZlibStreamSubcmd(Tcl_Interp *interp, int objc, + Tcl_Obj *const objv[]); static inline void ZlibTransformEventTimerKill(ZlibChannelData *cd); static void ZlibTransformTimerRun(ClientData clientData); @@ -198,38 +240,139 @@ static void ConvertError( Tcl_Interp *interp, /* Interpreter to store the error in. May be * NULL, in which case nothing happens. */ - int code) /* The zlib error code. */ + int code, /* The zlib error code. */ + uLong adler) /* The checksum expected (for Z_NEED_DICT) */ { + const char *codeStr, *codeStr2 = NULL; + char codeStrBuf[TCL_INTEGER_SPACE]; + if (interp == NULL) { return; } - if (code == Z_ERRNO) { + switch (code) { + /* + * Firstly, the case that is *different* because it's really coming + * from the OS and is just being reported via zlib. It should be + * really uncommon because Tcl handles all I/O rather than delegating + * it to zlib, but proving it can't happen is hard. + */ + + case Z_ERRNO: Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_PosixError(interp),-1)); - } else { - const char *codeStr, *codeStr2 = NULL; - char codeStrBuf[TCL_INTEGER_SPACE]; - - switch (code) { - case Z_STREAM_ERROR: codeStr = "STREAM"; break; - case Z_DATA_ERROR: codeStr = "DATA"; break; - case Z_MEM_ERROR: codeStr = "MEM"; break; - case Z_BUF_ERROR: codeStr = "BUF"; break; - case Z_VERSION_ERROR: codeStr = "VERSION"; break; - default: - codeStr = "unknown"; - codeStr2 = codeStrBuf; - sprintf(codeStrBuf, "%d", code); - break; - } - Tcl_SetObjResult(interp, Tcl_NewStringObj(zError(code), -1)); + return; + + /* + * Normal errors/conditions, some of which have additional detail and + * some which don't. (This is not defined by array lookup because zlib + * error codes are sometimes negative.) + */ + + case Z_STREAM_ERROR: + codeStr = "STREAM"; + break; + case Z_DATA_ERROR: + codeStr = "DATA"; + break; + case Z_MEM_ERROR: + codeStr = "MEM"; + break; + case Z_BUF_ERROR: + codeStr = "BUF"; + break; + case Z_VERSION_ERROR: + codeStr = "VERSION"; + break; + case Z_NEED_DICT: + codeStr = "NEED_DICT"; + codeStr2 = codeStrBuf; + sprintf(codeStrBuf, "%lu", adler); + break; + + /* + * These should _not_ happen! This function is for dealing with error + * cases, not non-errors! + */ + + case Z_OK: + Tcl_Panic("unexpected zlib result in error handler: Z_OK"); + case Z_STREAM_END: + Tcl_Panic("unexpected zlib result in error handler: Z_STREAM_END"); + + /* + * Anything else is bad news; it's unexpected. Convert to generic + * error. + */ + + default: + codeStr = "UNKNOWN"; + codeStr2 = codeStrBuf; + sprintf(codeStrBuf, "%d", code); + break; + } + Tcl_SetObjResult(interp, Tcl_NewStringObj(zError(code), -1)); + + /* + * Tricky point! We might pass NULL twice here (and will when the error + * type is known). + */ + + Tcl_SetErrorCode(interp, "TCL", "ZLIB", codeStr, codeStr2, NULL); +} + +static Tcl_Obj * +ConvertErrorToList( + int code, /* The zlib error code. */ + uLong adler) /* The checksum expected (for Z_NEED_DICT) */ +{ + Tcl_Obj *objv[4]; + + TclNewLiteralStringObj(objv[0], "TCL"); + TclNewLiteralStringObj(objv[1], "ZLIB"); + switch (code) { + case Z_STREAM_ERROR: + TclNewLiteralStringObj(objv[2], "STREAM"); + return Tcl_NewListObj(3, objv); + case Z_DATA_ERROR: + TclNewLiteralStringObj(objv[2], "DATA"); + return Tcl_NewListObj(3, objv); + case Z_MEM_ERROR: + TclNewLiteralStringObj(objv[2], "MEM"); + return Tcl_NewListObj(3, objv); + case Z_BUF_ERROR: + TclNewLiteralStringObj(objv[2], "BUF"); + return Tcl_NewListObj(3, objv); + case Z_VERSION_ERROR: + TclNewLiteralStringObj(objv[2], "VERSION"); + return Tcl_NewListObj(3, objv); + case Z_ERRNO: + TclNewLiteralStringObj(objv[2], "POSIX"); + objv[3] = Tcl_NewStringObj(Tcl_ErrnoId(), -1); + return Tcl_NewListObj(4, objv); + case Z_NEED_DICT: + TclNewLiteralStringObj(objv[2], "NEED_DICT"); + objv[3] = Tcl_NewWideIntObj((Tcl_WideInt) adler); + return Tcl_NewListObj(4, objv); + + /* + * These should _not_ happen! This function is for dealing with error + * cases, not non-errors! + */ + + case Z_OK: + Tcl_Panic("unexpected zlib result in error handler: Z_OK"); + case Z_STREAM_END: + Tcl_Panic("unexpected zlib result in error handler: Z_STREAM_END"); /* - * Tricky point! We might pass NULL twice here (and will when the - * error type is known). + * Catch-all. Should be unreachable because all cases are already + * listed above. */ - Tcl_SetErrorCode(interp, "TCL", "ZLIB", codeStr, codeStr2, NULL); + default: + TclNewLiteralStringObj(objv[2], "UNKNOWN"); + TclNewIntObj(objv[3], code); + return Tcl_NewListObj(4, objv); } } @@ -301,7 +444,9 @@ GenerateHeader( NULL); headerPtr->nativeCommentBuf[len] = '\0'; headerPtr->header.comment = (Bytef *) headerPtr->nativeCommentBuf; - *extraSizePtr += len; + if (extraSizePtr != NULL) { + *extraSizePtr += len; + } } if (GetValue(interp, dictObj, "crc", &value) != TCL_OK) { @@ -319,7 +464,9 @@ GenerateHeader( headerPtr->nativeFilenameBuf, MAXPATHLEN-1, NULL, &len, NULL); headerPtr->nativeFilenameBuf[len] = '\0'; headerPtr->header.name = (Bytef *) headerPtr->nativeFilenameBuf; - *extraSizePtr += len; + if (extraSizePtr != NULL) { + *extraSizePtr += len; + } } if (GetValue(interp, dictObj, "os", &value) != TCL_OK) { @@ -441,6 +588,34 @@ ExtractHeader( } } +static int +SetInflateDictionary( + z_streamp strm, + Tcl_Obj *compDictObj) +{ + if (compDictObj != NULL) { + int length; + unsigned char *bytes = Tcl_GetByteArrayFromObj(compDictObj, &length); + + return inflateSetDictionary(strm, bytes, (unsigned) length); + } + return Z_OK; +} + +static int +SetDeflateDictionary( + z_streamp strm, + Tcl_Obj *compDictObj) +{ + if (compDictObj != NULL) { + int length; + unsigned char *bytes = Tcl_GetByteArrayFromObj(compDictObj, &length); + + return deflateSetDictionary(strm, bytes, (unsigned) length); + } + return Z_OK; +} + /* *---------------------------------------------------------------------- * @@ -479,6 +654,7 @@ Tcl_ZlibStreamInit( ZlibStreamHandle *zshPtr = NULL; Tcl_DString cmdname; Tcl_CmdInfo cmdinfo; + GzipHeader *gzHeaderPtr = NULL; switch (mode) { case TCL_ZLIB_STREAM_DEFLATE: @@ -493,6 +669,15 @@ Tcl_ZlibStreamInit( break; case TCL_ZLIB_FORMAT_GZIP: wbits = WBITS_GZIP; + if (dictObj) { + gzHeaderPtr = ckalloc(sizeof(GzipHeader)); + memset(gzHeaderPtr, 0, sizeof(GzipHeader)); + if (GenerateHeader(interp, dictObj, gzHeaderPtr, + NULL) != TCL_OK) { + ckfree(gzHeaderPtr); + return TCL_ERROR; + } + } break; case TCL_ZLIB_FORMAT_ZLIB: wbits = WBITS_ZLIB; @@ -519,6 +704,14 @@ Tcl_ZlibStreamInit( break; case TCL_ZLIB_FORMAT_GZIP: wbits = WBITS_GZIP; + gzHeaderPtr = ckalloc(sizeof(GzipHeader)); + memset(gzHeaderPtr, 0, sizeof(GzipHeader)); + gzHeaderPtr->header.name = (Bytef *) + gzHeaderPtr->nativeFilenameBuf; + gzHeaderPtr->header.name_max = MAXPATHLEN - 1; + gzHeaderPtr->header.comment = (Bytef *) + gzHeaderPtr->nativeCommentBuf; + gzHeaderPtr->header.name_max = MAX_COMMENT_LEN - 1; break; case TCL_ZLIB_FORMAT_ZLIB: wbits = WBITS_ZLIB; @@ -545,6 +738,9 @@ Tcl_ZlibStreamInit( zshPtr->wbits = wbits; zshPtr->currentInput = NULL; zshPtr->streamEnd = 0; + zshPtr->compDictObj = NULL; + zshPtr->flags = 0; + zshPtr->gzHeaderPtr = gzHeaderPtr; memset(&zshPtr->stream, 0, sizeof(z_stream)); zshPtr->stream.adler = 1; @@ -555,12 +751,20 @@ Tcl_ZlibStreamInit( if (mode == TCL_ZLIB_STREAM_DEFLATE) { e = deflateInit2(&zshPtr->stream, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY); + if (e == Z_OK && zshPtr->gzHeaderPtr) { + e = deflateSetHeader(&zshPtr->stream, + &zshPtr->gzHeaderPtr->header); + } } else { e = inflateInit2(&zshPtr->stream, wbits); + if (e == Z_OK && zshPtr->gzHeaderPtr) { + e = inflateGetHeader(&zshPtr->stream, + &zshPtr->gzHeaderPtr->header); + } } if (e != Z_OK) { - ConvertError(interp, e); + ConvertError(interp, e, zshPtr->stream.adler); goto error; } @@ -577,8 +781,8 @@ Tcl_ZlibStreamInit( TclDStringAppendObj(&cmdname, Tcl_GetObjResult(interp)); if (Tcl_GetCommandInfo(interp, Tcl_DStringValue(&cmdname), &cmdinfo) == 1) { - Tcl_SetResult(interp, - "BUG: Stream command name already exists", TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "BUG: Stream command name already exists", -1)); Tcl_SetErrorCode(interp, "TCL", "BUG", "EXISTING_CMD", NULL); Tcl_DStringFree(&cmdname); goto error; @@ -620,7 +824,14 @@ Tcl_ZlibStreamInit( } return TCL_OK; - error: + + error: + if (zshPtr->compDictObj) { + Tcl_DecrRefCount(zshPtr->compDictObj); + } + if (zshPtr->gzHeaderPtr) { + ckfree(zshPtr->gzHeaderPtr); + } ckfree(zshPtr); return TCL_ERROR; } @@ -728,6 +939,12 @@ ZlibStreamCleanup( if (zshPtr->currentInput) { Tcl_DecrRefCount(zshPtr->currentInput); } + if (zshPtr->compDictObj) { + Tcl_DecrRefCount(zshPtr->compDictObj); + } + if (zshPtr->gzHeaderPtr) { + ckfree(zshPtr->gzHeaderPtr); + } ckfree(zshPtr); } @@ -780,12 +997,24 @@ Tcl_ZlibStreamReset( if (zshPtr->mode == TCL_ZLIB_STREAM_DEFLATE) { e = deflateInit2(&zshPtr->stream, zshPtr->level, Z_DEFLATED, zshPtr->wbits, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY); + if (e == Z_OK && HaveDictToSet(zshPtr)) { + e = SetDeflateDictionary(&zshPtr->stream, zshPtr->compDictObj); + if (e == Z_OK) { + DictWasSet(zshPtr); + } + } } else { e = inflateInit2(&zshPtr->stream, zshPtr->wbits); + if (IsRawStream(zshPtr) && HaveDictToSet(zshPtr) && e == Z_OK) { + e = SetInflateDictionary(&zshPtr->stream, zshPtr->compDictObj); + if (e == Z_OK) { + DictWasSet(zshPtr); + } + } } if (e != Z_OK) { - ConvertError(zshPtr->interp, e); + ConvertError(zshPtr->interp, e, zshPtr->stream.adler); /* TODO:cleanup */ return TCL_ERROR; } @@ -878,6 +1107,41 @@ Tcl_ZlibStreamChecksum( /* *---------------------------------------------------------------------- * + * Tcl_ZlibStreamSetCompressionDictionary -- + * + * Sets the compression dictionary for a stream. This will be used as + * appropriate for the next compression or decompression action performed + * on the stream. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_ZlibStreamSetCompressionDictionary( + Tcl_ZlibStream zshandle, + Tcl_Obj *compressionDictionaryObj) +{ + ZlibStreamHandle *zshPtr = (ZlibStreamHandle *) zshandle; + + if (compressionDictionaryObj != NULL) { + if (Tcl_IsShared(compressionDictionaryObj)) { + compressionDictionaryObj = + Tcl_DuplicateObj(compressionDictionaryObj); + } + Tcl_IncrRefCount(compressionDictionaryObj); + zshPtr->flags |= DICT_TO_SET; + } else { + zshPtr->flags &= ~DICT_TO_SET; + } + if (zshPtr->compDictObj != NULL) { + Tcl_DecrRefCount(zshPtr->compDictObj); + } + zshPtr->compDictObj = compressionDictionaryObj; +} + +/* + *---------------------------------------------------------------------- + * * Tcl_ZlibStreamPut -- * * Add data to the stream for compression or decompression from a @@ -900,8 +1164,8 @@ Tcl_ZlibStreamPut( if (zshPtr->streamEnd) { if (zshPtr->interp) { - Tcl_SetResult(zshPtr->interp, - "already past compressed stream end", TCL_STATIC); + Tcl_SetObjResult(zshPtr->interp, Tcl_NewStringObj( + "already past compressed stream end", -1)); Tcl_SetErrorCode(zshPtr->interp, "TCL", "ZIP", "CLOSED", NULL); } return TCL_ERROR; @@ -911,6 +1175,17 @@ Tcl_ZlibStreamPut( zshPtr->stream.next_in = Tcl_GetByteArrayFromObj(data, &size); zshPtr->stream.avail_in = size; + if (HaveDictToSet(zshPtr)) { + e = SetDeflateDictionary(&zshPtr->stream, zshPtr->compDictObj); + if (e != Z_OK) { + if (zshPtr->interp) { + ConvertError(zshPtr->interp, e, zshPtr->stream.adler); + } + return TCL_ERROR; + } + DictWasSet(zshPtr); + } + /* * Deflatebound doesn't seem to take various header sizes into * account, so we add 100 extra bytes. @@ -948,6 +1223,12 @@ Tcl_ZlibStreamPut( e = deflate(&zshPtr->stream, flush); } + if (e != Z_OK && !(flush==Z_FINISH && e==Z_STREAM_END)) { + if (zshPtr->interp) { + ConvertError(zshPtr->interp, e, zshPtr->stream.adler); + } + return TCL_ERROR; + } /* * And append the final data block. @@ -1025,7 +1306,7 @@ Tcl_ZlibStreamGet( * panic for out of memory if we just kept growing the buffer. */ - count = 65536; + count = MAX_BUFFER_SIZE; } /* @@ -1073,7 +1354,30 @@ Tcl_ZlibStreamGet( } } + /* + * When dealing with a raw stream, we set the dictionary here, once. + * (You can't do it in response to getting Z_NEED_DATA as raw streams + * don't ever issue that.) + */ + + if (IsRawStream(zshPtr) && HaveDictToSet(zshPtr)) { + e = SetInflateDictionary(&zshPtr->stream, zshPtr->compDictObj); + if (e != Z_OK) { + if (zshPtr->interp) { + ConvertError(zshPtr->interp, e, zshPtr->stream.adler); + } + return TCL_ERROR; + } + DictWasSet(zshPtr); + } e = inflate(&zshPtr->stream, zshPtr->flush); + if (e == Z_NEED_DICT && HaveDictToSet(zshPtr)) { + e = SetInflateDictionary(&zshPtr->stream, zshPtr->compDictObj); + if (e == Z_OK) { + DictWasSet(zshPtr); + e = inflate(&zshPtr->stream, zshPtr->flush); + } + }; Tcl_ListObjLength(NULL, zshPtr->inData, &listLen); while ((zshPtr->stream.avail_out > 0) @@ -1085,9 +1389,9 @@ Tcl_ZlibStreamGet( if (zshPtr->stream.avail_in > 0) { if (zshPtr->interp) { - Tcl_SetResult(zshPtr->interp, - "Unexpected zlib internal state during decompression", - TCL_STATIC); + Tcl_SetObjResult(zshPtr->interp, Tcl_NewStringObj( + "unexpected zlib internal state during" + " decompression", -1)); Tcl_SetErrorCode(zshPtr->interp, "TCL", "ZIP", "STATE", NULL); } @@ -1127,7 +1431,14 @@ Tcl_ZlibStreamGet( * And call inflate again. */ - e = inflate(&zshPtr->stream, zshPtr->flush); + do { + e = inflate(&zshPtr->stream, zshPtr->flush); + if (e != Z_NEED_DICT || !HaveDictToSet(zshPtr)) { + break; + } + e = SetInflateDictionary(&zshPtr->stream,zshPtr->compDictObj); + DictWasSet(zshPtr); + } while (e == Z_OK); } if (zshPtr->stream.avail_out > 0) { Tcl_SetByteArrayLength(data, @@ -1135,7 +1446,7 @@ Tcl_ZlibStreamGet( } if (!(e==Z_OK || e==Z_STREAM_END || e==Z_BUF_ERROR)) { Tcl_SetByteArrayLength(data, existing); - ConvertError(zshPtr->interp, e); + ConvertError(zshPtr->interp, e, zshPtr->stream.adler); return TCL_ERROR; } if (e == Z_STREAM_END) { @@ -1351,7 +1662,7 @@ Tcl_ZlibDeflate( return TCL_OK; error: - ConvertError(interp, e); + ConvertError(interp, e, stream.adler); TclDecrRefCount(obj); return TCL_ERROR; } @@ -1530,7 +1841,7 @@ Tcl_ZlibInflate( error: TclDecrRefCount(obj); - ConvertError(interp, e); + ConvertError(interp, e, stream.adler); if (nameBuf) { ckfree(nameBuf); } @@ -1586,11 +1897,10 @@ ZlibCmd( int objc, Tcl_Obj *const objv[]) { - int command, dlen, mode, format, i, option, level = -1; + int command, dlen, i, option, level = -1; unsigned start, buffersize = 0; - Tcl_ZlibStream zh; Byte *data; - Tcl_Obj *headerDictObj, *headerVarObj; + Tcl_Obj *headerDictObj; const char *extraInfoStr = NULL; static const char *const commands[] = { "adler32", "compress", "crc32", "decompress", "deflate", "gunzip", @@ -1601,14 +1911,6 @@ ZlibCmd( CMD_ADLER, CMD_COMPRESS, CMD_CRC, CMD_DECOMPRESS, CMD_DEFLATE, CMD_GUNZIP, CMD_GZIP, CMD_INFLATE, CMD_PUSH, CMD_STREAM }; - static const char *const stream_formats[] = { - "compress", "decompress", "deflate", "gunzip", "gzip", "inflate", - NULL - }; - enum zlibFormats { - FMT_COMPRESS, FMT_DECOMPRESS, FMT_DEFLATE, FMT_GUNZIP, FMT_GZIP, - FMT_INFLATE - }; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "command arg ?...?"); @@ -1635,7 +1937,7 @@ ZlibCmd( } data = Tcl_GetByteArrayFromObj(objv[2], &dlen); Tcl_SetObjResult(interp, Tcl_NewWideIntObj((Tcl_WideInt) - Tcl_ZlibAdler32(start, data, dlen))); + (uLong) Tcl_ZlibAdler32(start, data, dlen))); return TCL_OK; case CMD_CRC: /* crc32 str ?startvalue? * -> checksum */ @@ -1652,7 +1954,7 @@ ZlibCmd( } data = Tcl_GetByteArrayFromObj(objv[2], &dlen); Tcl_SetObjResult(interp, Tcl_NewWideIntObj((Tcl_WideInt) - Tcl_ZlibCRC32(start, data, dlen))); + (uLong) Tcl_ZlibCRC32(start, data, dlen))); return TCL_OK; case CMD_DEFLATE: /* deflate data ?level? * -> rawCompressedData */ @@ -1688,12 +1990,27 @@ ZlibCmd( NULL); case CMD_GZIP: /* gzip data ?level? * -> gzippedCompressedData */ + headerDictObj = NULL; + + /* + * Legacy argument format support. + */ + + if (objc == 4 + && Tcl_GetIntFromObj(interp, objv[3], &level) == TCL_OK) { + if (level < 0 || level > 9) { + extraInfoStr = "\n (in -level option)"; + goto badLevel; + } + return Tcl_ZlibDeflate(interp, TCL_ZLIB_FORMAT_GZIP, objv[2], + level, NULL); + } + if (objc < 3 || objc > 7 || ((objc & 1) == 0)) { Tcl_WrongNumArgs(interp, 2, objv, "data ?-level level? ?-header header?"); return TCL_ERROR; } - headerDictObj = NULL; for (i=3 ; i<objc ; i+=2) { static const char *const gzipopts[] = { "-header", "-level", NULL @@ -1732,7 +2049,8 @@ ZlibCmd( (int *) &buffersize) != TCL_OK) { return TCL_ERROR; } - if (buffersize < 16 || buffersize > 65536) { + if (buffersize < MIN_NONSTREAM_BUFFER_SIZE + || buffersize > MAX_BUFFER_SIZE) { goto badBuffer; } } @@ -1750,14 +2068,17 @@ ZlibCmd( (int *) &buffersize) != TCL_OK) { return TCL_ERROR; } - if (buffersize < 16 || buffersize > 65536) { + if (buffersize < MIN_NONSTREAM_BUFFER_SIZE + || buffersize > MAX_BUFFER_SIZE) { goto badBuffer; } } return Tcl_ZlibInflate(interp, TCL_ZLIB_FORMAT_ZLIB, objv[2], buffersize, NULL); - case CMD_GUNZIP: /* gunzip gzippeddata ?bufferSize? + case CMD_GUNZIP: { /* gunzip gzippeddata ?bufferSize? * -> decompressedData */ + Tcl_Obj *headerVarObj; + if (objc < 3 || objc > 5 || ((objc & 1) == 0)) { Tcl_WrongNumArgs(interp, 2, objv, "data ?-headerVar varName?"); return TCL_ERROR; @@ -1778,7 +2099,8 @@ ZlibCmd( (int *) &buffersize) != TCL_OK) { return TCL_ERROR; } - if (buffersize < 16 || buffersize > 65536) { + if (buffersize < MIN_NONSTREAM_BUFFER_SIZE + || buffersize > MAX_BUFFER_SIZE) { goto badBuffer; } break; @@ -1803,208 +2125,353 @@ ZlibCmd( return TCL_ERROR; } return TCL_OK; + } case CMD_STREAM: /* stream deflate/inflate/...gunzip \ - * ?level? + * ?options...? * -> handleCmd */ - if (objc < 3 || objc > 4) { - Tcl_WrongNumArgs(interp, 2, objv, "mode ?level?"); - return TCL_ERROR; - } - if (Tcl_GetIndexFromObj(interp, objv[2], stream_formats, "mode", 0, - &format) != TCL_OK) { - return TCL_ERROR; - } - mode = TCL_ZLIB_STREAM_INFLATE; - switch ((enum zlibFormats) format) { - case FMT_DEFLATE: - mode = TCL_ZLIB_STREAM_DEFLATE; - case FMT_INFLATE: - format = TCL_ZLIB_FORMAT_RAW; - break; - case FMT_COMPRESS: - mode = TCL_ZLIB_STREAM_DEFLATE; - case FMT_DECOMPRESS: - format = TCL_ZLIB_FORMAT_ZLIB; - break; - case FMT_GZIP: - mode = TCL_ZLIB_STREAM_DEFLATE; - case FMT_GUNZIP: - format = TCL_ZLIB_FORMAT_GZIP; - break; - } - if (objc == 4) { - if (Tcl_GetIntFromObj(interp, objv[3], - (int *) &level) != TCL_OK) { - return TCL_ERROR; - } - if (level < 0 || level > 9) { - goto badLevel; - } - } else { - level = Z_DEFAULT_COMPRESSION; - } - if (Tcl_ZlibStreamInit(interp, mode, format, level, NULL, - &zh) != TCL_OK) { - return TCL_ERROR; - } - Tcl_SetObjResult(interp, Tcl_ZlibStreamGetCommandName(zh)); - return TCL_OK; - case CMD_PUSH: { /* push mode channel options... + return ZlibStreamSubcmd(interp, objc, objv); + case CMD_PUSH: /* push mode channel options... * -> channel */ - Tcl_Channel chan; - int chanMode; - static const char *const pushOptions[] = { - "-header", "-level", "-limit", - NULL - }; - enum pushOptions {poHeader, poLevel, poLimit}; - Tcl_Obj *headerObj = NULL; - int limit = 1, dummy; + return ZlibPushSubcmd(interp, objc, objv); + }; - if (objc < 4) { - Tcl_WrongNumArgs(interp, 2, objv, "mode channel ?options...?"); - return TCL_ERROR; - } + return TCL_ERROR; - if (Tcl_GetIndexFromObj(interp, objv[2], stream_formats, "mode", 0, - &format) != TCL_OK) { - return TCL_ERROR; - } - switch ((enum zlibFormats) format) { - case FMT_DEFLATE: - mode = TCL_ZLIB_STREAM_DEFLATE; - format = TCL_ZLIB_FORMAT_RAW; - break; - case FMT_INFLATE: - mode = TCL_ZLIB_STREAM_INFLATE; - format = TCL_ZLIB_FORMAT_RAW; - break; - case FMT_COMPRESS: - mode = TCL_ZLIB_STREAM_DEFLATE; - format = TCL_ZLIB_FORMAT_ZLIB; - break; - case FMT_DECOMPRESS: - mode = TCL_ZLIB_STREAM_INFLATE; - format = TCL_ZLIB_FORMAT_ZLIB; - break; - case FMT_GZIP: - mode = TCL_ZLIB_STREAM_DEFLATE; - format = TCL_ZLIB_FORMAT_GZIP; - break; - case FMT_GUNZIP: - mode = TCL_ZLIB_STREAM_INFLATE; - format = TCL_ZLIB_FORMAT_GZIP; - break; - default: - Tcl_AppendResult(interp, "IMPOSSIBLE", NULL); - return TCL_ERROR; - } + badLevel: + Tcl_SetObjResult(interp, Tcl_NewStringObj("level must be 0 to 9", -1)); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "COMPRESSIONLEVEL", NULL); + if (extraInfoStr) { + Tcl_AddErrorInfo(interp, extraInfoStr); + } + return TCL_ERROR; + badBuffer: + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "buffer size must be %d to %d", + MIN_NONSTREAM_BUFFER_SIZE, MAX_BUFFER_SIZE)); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "BUFFERSIZE", NULL); + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * ZlibStreamSubcmd -- + * + * Implementation of the [zlib stream] subcommand. + * + *---------------------------------------------------------------------- + */ + +static int +ZlibStreamSubcmd( + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + static const char *const stream_formats[] = { + "compress", "decompress", "deflate", "gunzip", "gzip", "inflate", + NULL + }; + enum zlibFormats { + FMT_COMPRESS, FMT_DECOMPRESS, FMT_DEFLATE, FMT_GUNZIP, FMT_GZIP, + FMT_INFLATE + }; + int i, format, mode = 0, option, level; + typedef struct { + const char *name; + Tcl_Obj **valueVar; + } OptDescriptor; + Tcl_Obj *compDictObj = NULL; + Tcl_Obj *gzipHeaderObj = NULL; + Tcl_Obj *levelObj = NULL; + const OptDescriptor compressionOpts[] = { + { "-dictionary", &compDictObj }, + { "-level", &levelObj }, + { NULL, NULL } + }; + const OptDescriptor gzipOpts[] = { + { "-header", &gzipHeaderObj }, + { "-level", &levelObj }, + { NULL, NULL } + }; + const OptDescriptor expansionOpts[] = { + { "-dictionary", &compDictObj }, + { NULL, NULL } + }; + const OptDescriptor gunzipOpts[] = { + { NULL, NULL } + }; + const OptDescriptor *desc = NULL; + Tcl_ZlibStream zh; + + if (objc < 3 || !(objc & 1)) { + Tcl_WrongNumArgs(interp, 2, objv, "mode ?-option value...?"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[2], stream_formats, "mode", 0, + &format) != TCL_OK) { + return TCL_ERROR; + } + + /* + * The format determines the compression mode and the options that may be + * specified. + */ + + switch ((enum zlibFormats) format) { + case FMT_DEFLATE: + desc = compressionOpts; + mode = TCL_ZLIB_STREAM_DEFLATE; + format = TCL_ZLIB_FORMAT_RAW; + break; + case FMT_INFLATE: + desc = expansionOpts; + mode = TCL_ZLIB_STREAM_INFLATE; + format = TCL_ZLIB_FORMAT_RAW; + break; + case FMT_COMPRESS: + desc = compressionOpts; + mode = TCL_ZLIB_STREAM_DEFLATE; + format = TCL_ZLIB_FORMAT_ZLIB; + break; + case FMT_DECOMPRESS: + desc = expansionOpts; + mode = TCL_ZLIB_STREAM_INFLATE; + format = TCL_ZLIB_FORMAT_ZLIB; + break; + case FMT_GZIP: + desc = gzipOpts; + mode = TCL_ZLIB_STREAM_DEFLATE; + format = TCL_ZLIB_FORMAT_GZIP; + break; + case FMT_GUNZIP: + desc = gunzipOpts; + mode = TCL_ZLIB_STREAM_INFLATE; + format = TCL_ZLIB_FORMAT_GZIP; + break; + default: + Tcl_Panic("should be unreachable"); + } - if (TclGetChannelFromObj(interp, objv[3], &chan, &chanMode, - 0) != TCL_OK) { + /* + * Parse the options. + */ + + for (i=3 ; i<objc ; i+=2) { + if (Tcl_GetIndexFromObjStruct(interp, objv[i], desc, + sizeof(OptDescriptor), "option", 0, &option) != TCL_OK) { return TCL_ERROR; } + *desc[option].valueVar = objv[i+1]; /* - * Sanity checks. + * Drop the cache on the option name; table address not constant. */ - if (mode == TCL_ZLIB_STREAM_DEFLATE && !(chanMode & TCL_WRITABLE)) { - Tcl_AppendResult(interp, - "compression may only be applied to writable channels", - NULL); - Tcl_SetErrorCode(interp, "TCL", "ZIP", "UNWRITABLE", NULL); + TclFreeIntRep(objv[i]); + } + + /* + * If a compression level was given, parse it (integral: 0..9). Otherwise + * use the default. + */ + + if (levelObj == NULL) { + level = Z_DEFAULT_COMPRESSION; + } else if (Tcl_GetIntFromObj(interp, levelObj, &level) != TCL_OK) { + return TCL_ERROR; + } else if (level < 0 || level > 9) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("level must be 0 to 9",-1)); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "COMPRESSIONLEVEL", NULL); + Tcl_AddErrorInfo(interp, "\n (in -level option)"); + return TCL_ERROR; + } + + /* + * Construct the stream now we know its configuration. + */ + + if (Tcl_ZlibStreamInit(interp, mode, format, level, gzipHeaderObj, + &zh) != TCL_OK) { + return TCL_ERROR; + } + if (compDictObj != NULL) { + Tcl_ZlibStreamSetCompressionDictionary(zh, compDictObj); + } + Tcl_SetObjResult(interp, Tcl_ZlibStreamGetCommandName(zh)); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ZlibPushSubcmd -- + * + * Implementation of the [zlib push] subcommand. + * + *---------------------------------------------------------------------- + */ + +static int +ZlibPushSubcmd( + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + static const char *const stream_formats[] = { + "compress", "decompress", "deflate", "gunzip", "gzip", "inflate", + NULL + }; + enum zlibFormats { + FMT_COMPRESS, FMT_DECOMPRESS, FMT_DEFLATE, FMT_GUNZIP, FMT_GZIP, + FMT_INFLATE + }; + Tcl_Channel chan; + int chanMode, format, mode = 0, level, i, option; + static const char *const pushCompressOptions[] = { + "-dictionary", "-header", "-level", NULL + }; + static const char *const pushDecompressOptions[] = { + "-dictionary", "-header", "-level", "-limit", NULL + }; + const char *const *pushOptions = pushDecompressOptions; + enum pushOptions {poDictionary, poHeader, poLevel, poLimit}; + Tcl_Obj *headerObj = NULL, *compDictObj = NULL; + int limit = 1, dummy; + + if (objc < 4) { + Tcl_WrongNumArgs(interp, 2, objv, "mode channel ?options...?"); + return TCL_ERROR; + } + + if (Tcl_GetIndexFromObj(interp, objv[2], stream_formats, "mode", 0, + &format) != TCL_OK) { + return TCL_ERROR; + } + switch ((enum zlibFormats) format) { + case FMT_DEFLATE: + mode = TCL_ZLIB_STREAM_DEFLATE; + format = TCL_ZLIB_FORMAT_RAW; + pushOptions = pushCompressOptions; + break; + case FMT_INFLATE: + mode = TCL_ZLIB_STREAM_INFLATE; + format = TCL_ZLIB_FORMAT_RAW; + break; + case FMT_COMPRESS: + mode = TCL_ZLIB_STREAM_DEFLATE; + format = TCL_ZLIB_FORMAT_ZLIB; + pushOptions = pushCompressOptions; + break; + case FMT_DECOMPRESS: + mode = TCL_ZLIB_STREAM_INFLATE; + format = TCL_ZLIB_FORMAT_ZLIB; + break; + case FMT_GZIP: + mode = TCL_ZLIB_STREAM_DEFLATE; + format = TCL_ZLIB_FORMAT_GZIP; + pushOptions = pushCompressOptions; + break; + case FMT_GUNZIP: + mode = TCL_ZLIB_STREAM_INFLATE; + format = TCL_ZLIB_FORMAT_GZIP; + break; + default: + Tcl_Panic("should be unreachable"); + } + + if (TclGetChannelFromObj(interp, objv[3], &chan, &chanMode, 0) != TCL_OK){ + return TCL_ERROR; + } + + /* + * Sanity checks. + */ + + if (mode == TCL_ZLIB_STREAM_DEFLATE && !(chanMode & TCL_WRITABLE)) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "compression may only be applied to writable channels", -1)); + Tcl_SetErrorCode(interp, "TCL", "ZIP", "UNWRITABLE", NULL); + return TCL_ERROR; + } + if (mode == TCL_ZLIB_STREAM_INFLATE && !(chanMode & TCL_READABLE)) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "decompression may only be applied to readable channels",-1)); + Tcl_SetErrorCode(interp, "TCL", "ZIP", "UNREADABLE", NULL); + return TCL_ERROR; + } + + /* + * Parse options. + */ + + level = Z_DEFAULT_COMPRESSION; + for (i=4 ; i<objc ; i++) { + if (Tcl_GetIndexFromObj(interp, objv[i], pushOptions, "option", 0, + &option) != TCL_OK) { return TCL_ERROR; } - if (mode == TCL_ZLIB_STREAM_INFLATE && !(chanMode & TCL_READABLE)) { - Tcl_AppendResult(interp, - "decompression may only be applied to readable channels", - NULL); - Tcl_SetErrorCode(interp, "TCL", "ZIP", "UNREADABLE", NULL); + if (++i > objc-1) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "value missing for %s option", pushOptions[option])); + Tcl_SetErrorCode(interp, "TCL", "ZIP", "NOVAL", NULL); return TCL_ERROR; } - - /* - * Parse options. - */ - - level = Z_DEFAULT_COMPRESSION; - for (i=4 ; i<objc ; i++) { - if (Tcl_GetIndexFromObj(interp, objv[i], pushOptions, "option", 0, - &option) != TCL_OK) { - return TCL_ERROR; + switch ((enum pushOptions) option) { + case poHeader: + headerObj = objv[i]; + if (Tcl_DictObjSize(interp, headerObj, &dummy) != TCL_OK) { + goto genericOptionError; } - switch ((enum pushOptions) option) { - case poHeader: - if (++i > objc-1) { - Tcl_AppendResult(interp, - "value missing for -header option", NULL); - Tcl_SetErrorCode(interp, "TCL", "ZIP", "NOVAL", NULL); - return TCL_ERROR; - } - headerObj = objv[i]; - if (Tcl_DictObjSize(interp, headerObj, &dummy) != TCL_OK) { - Tcl_AddErrorInfo(interp, "\n (in -header option)"); - return TCL_ERROR; - } - break; - case poLevel: - if (++i > objc-1) { - Tcl_AppendResult(interp, - "value missing for -level option", NULL); - Tcl_SetErrorCode(interp, "TCL", "ZIP", "NOVAL", NULL); - return TCL_ERROR; - } - if (Tcl_GetIntFromObj(interp, objv[i], - (int *) &level) != TCL_OK) { - Tcl_AddErrorInfo(interp, "\n (in -level option)"); - return TCL_ERROR; - } - if (level < 0 || level > 9) { - extraInfoStr = "\n (in -level option)"; - goto badLevel; - } - break; - case poLimit: - if (++i > objc-1) { - Tcl_AppendResult(interp, - "value missing for -limit option", NULL); - Tcl_SetErrorCode(interp, "TCL", "ZIP", "NOVAL", NULL); - return TCL_ERROR; - } - if (Tcl_GetIntFromObj(interp, objv[i], - (int *) &limit) != TCL_OK) { - Tcl_AddErrorInfo(interp, "\n (in -limit option)"); - return TCL_ERROR; - } - if (limit < 1) { - limit = 1; - } - break; + break; + case poLevel: + if (Tcl_GetIntFromObj(interp, objv[i], (int*) &level) != TCL_OK) { + goto genericOptionError; } + if (level < 0 || level > 9) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "level must be 0 to 9", -1)); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "COMPRESSIONLEVEL", + NULL); + goto genericOptionError; + } + break; + case poLimit: + if (Tcl_GetIntFromObj(interp, objv[i], (int*) &limit) != TCL_OK) { + goto genericOptionError; + } + if (limit < 1 || limit > MAX_BUFFER_SIZE) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "read ahead limit must be 1 to %d", + MAX_BUFFER_SIZE)); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "BUFFERSIZE", NULL); + goto genericOptionError; + } + break; + case poDictionary: + if (format == TCL_ZLIB_FORMAT_GZIP) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "a compression dictionary may not be set in the " + "gzip format", -1)); + Tcl_SetErrorCode(interp, "TCL", "ZIP", "BADOPT", NULL); + goto genericOptionError; + } + compDictObj = objv[i]; + break; } - - if (ZlibStackChannelTransform(interp, mode, format, level, chan, - headerObj) == NULL) { - return TCL_ERROR; - } - Tcl_SetObjResult(interp, objv[3]); - return TCL_OK; } - }; - - return TCL_ERROR; - badLevel: - Tcl_AppendResult(interp, "level must be 0 to 9", NULL); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "COMPRESSIONLEVEL", NULL); - if (extraInfoStr) { - Tcl_AddErrorInfo(interp, extraInfoStr); + if (ZlibStackChannelTransform(interp, mode, format, level, limit, chan, + headerObj, compDictObj) == NULL) { + return TCL_ERROR; } - return TCL_ERROR; - badBuffer: - Tcl_AppendResult(interp, "buffer size must be 32 to 65536", NULL); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "BUFFERSIZE", NULL); + Tcl_SetObjResult(interp, objv[3]); + return TCL_OK; + + genericOptionError: + Tcl_AddErrorInfo(interp, "\n (in "); + Tcl_AddErrorInfo(interp, pushOptions[option]); + Tcl_AddErrorInfo(interp, " option)"); return TCL_ERROR; } @@ -2026,22 +2493,16 @@ ZlibStreamCmd( Tcl_Obj *const objv[]) { Tcl_ZlibStream zstream = cd; - int command, index, count, code, buffersize = -1, flush = -1, i; + int command, count, code; Tcl_Obj *obj; static const char *const cmds[] = { "add", "checksum", "close", "eof", "finalize", "flush", - "fullflush", "get", "put", "reset", + "fullflush", "get", "header", "put", "reset", NULL }; enum zlibStreamCommands { zs_add, zs_checksum, zs_close, zs_eof, zs_finalize, zs_flush, - zs_fullflush, zs_get, zs_put, zs_reset - }; - static const char *const add_options[] = { - "-buffer", "-finalize", "-flush", "-fullflush", NULL - }; - enum addOptions { - ao_buffer, ao_finalize, ao_flush, ao_fullflush + zs_fullflush, zs_get, zs_header, zs_put, zs_reset }; if (objc < 2) { @@ -2056,123 +2517,11 @@ ZlibStreamCmd( switch ((enum zlibStreamCommands) command) { case zs_add: /* $strm add ?$flushopt? $data */ - for (i=2; i<objc-1; i++) { - if (Tcl_GetIndexFromObj(interp, objv[i], add_options, "option", 0, - &index) != TCL_OK) { - return TCL_ERROR; - } - - switch ((enum addOptions) index) { - case ao_flush: /* -flush */ - if (flush > -1) { - flush = -2; - } else { - flush = Z_SYNC_FLUSH; - } - break; - case ao_fullflush: /* -fullflush */ - if (flush > -1) { - flush = -2; - } else { - flush = Z_FULL_FLUSH; - } - break; - case ao_finalize: /* -finalize */ - if (flush > -1) { - flush = -2; - } else { - flush = Z_FINISH; - } - break; - case ao_buffer: /* -buffer */ - if (i == objc-2) { - Tcl_AppendResult(interp, "\"-buffer\" option must be " - "followed by integer decompression buffersize", - NULL); - Tcl_SetErrorCode(interp, "TCL", "ZIP", "NOVAL", NULL); - return TCL_ERROR; - } - if (Tcl_GetIntFromObj(interp, objv[i+1], - &buffersize) != TCL_OK) { - return TCL_ERROR; - } - if (buffersize < 1 || buffersize > 65536) { - Tcl_AppendResult(interp, - "buffer size must be 32 to 65536", NULL); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "BUFFERSIZE", - NULL); - return TCL_ERROR; - } - } - - if (flush == -2) { - Tcl_AppendResult(interp, "\"-flush\", \"-fullflush\" and " - "\"-finalize\" options are mutually exclusive", NULL); - Tcl_SetErrorCode(interp, "TCL", "ZIP", "EXCLUSIVE", NULL); - return TCL_ERROR; - } - } - if (flush == -1) { - flush = 0; - } - - if (Tcl_ZlibStreamPut(zstream, objv[objc-1], flush) != TCL_OK) { - return TCL_ERROR; - } - TclNewObj(obj); - code = Tcl_ZlibStreamGet(zstream, obj, buffersize); - if (code == TCL_OK) { - Tcl_SetObjResult(interp, obj); - } else { - TclDecrRefCount(obj); - } - return code; - + return ZlibStreamAddCmd(zstream, interp, objc, objv); + case zs_header: /* $strm header */ + return ZlibStreamHeaderCmd(zstream, interp, objc, objv); case zs_put: /* $strm put ?$flushopt? $data */ - for (i=2; i<objc-1; i++) { - if (Tcl_GetIndexFromObj(interp, objv[i], add_options, "option", 0, - &index) != TCL_OK) { - return TCL_ERROR; - } - - switch ((enum addOptions) index) { - case ao_flush: /* -flush */ - if (flush > -1) { - flush = -2; - } else { - flush = Z_SYNC_FLUSH; - } - break; - case ao_fullflush: /* -fullflush */ - if (flush > -1) { - flush = -2; - } else { - flush = Z_FULL_FLUSH; - } - break; - case ao_finalize: /* -finalize */ - if (flush > -1) { - flush = -2; - } else { - flush = Z_FINISH; - } - break; - case ao_buffer: - Tcl_AppendResult(interp, - "\"-buffer\" option not supported here", NULL); - return TCL_ERROR; - } - if (flush == -2) { - Tcl_AppendResult(interp, "\"-flush\", \"-fullflush\" and " - "\"-finalize\" options are mutually exclusive", NULL); - Tcl_SetErrorCode(interp, "TCL", "ZIP", "EXCLUSIVE", NULL); - return TCL_ERROR; - } - } - if (flush == -1) { - flush = 0; - } - return Tcl_ZlibStreamPut(zstream, objv[objc-1], flush); + return ZlibStreamPutCmd(zstream, interp, objc, objv); case zs_get: /* $strm get ?count? */ if (objc > 3) { @@ -2249,7 +2598,7 @@ ZlibStreamCmd( return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewWideIntObj((Tcl_WideInt) - Tcl_ZlibStreamChecksum(zstream))); + (uLong) Tcl_ZlibStreamChecksum(zstream))); return TCL_OK; case zs_reset: /* $strm reset */ if (objc != 2) { @@ -2261,6 +2610,246 @@ ZlibStreamCmd( return TCL_OK; } + +static int +ZlibStreamAddCmd( + ClientData cd, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_ZlibStream zstream = cd; + int index, code, buffersize = -1, flush = -1, i; + Tcl_Obj *obj, *compDictObj = NULL; + static const char *const add_options[] = { + "-buffer", "-dictionary", "-finalize", "-flush", "-fullflush", NULL + }; + enum addOptions { + ao_buffer, ao_dictionary, ao_finalize, ao_flush, ao_fullflush + }; + + for (i=2; i<objc-1; i++) { + if (Tcl_GetIndexFromObj(interp, objv[i], add_options, "option", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + + switch ((enum addOptions) index) { + case ao_flush: /* -flush */ + if (flush > -1) { + flush = -2; + } else { + flush = Z_SYNC_FLUSH; + } + break; + case ao_fullflush: /* -fullflush */ + if (flush > -1) { + flush = -2; + } else { + flush = Z_FULL_FLUSH; + } + break; + case ao_finalize: /* -finalize */ + if (flush > -1) { + flush = -2; + } else { + flush = Z_FINISH; + } + break; + case ao_buffer: /* -buffer */ + if (i == objc-2) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "\"-buffer\" option must be followed by integer " + "decompression buffersize", -1)); + Tcl_SetErrorCode(interp, "TCL", "ZIP", "NOVAL", NULL); + return TCL_ERROR; + } + if (Tcl_GetIntFromObj(interp, objv[++i], &buffersize) != TCL_OK) { + return TCL_ERROR; + } + if (buffersize < 1 || buffersize > MAX_BUFFER_SIZE) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "buffer size must be 1 to %d", + MAX_BUFFER_SIZE)); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "BUFFERSIZE", NULL); + return TCL_ERROR; + } + break; + case ao_dictionary: + if (i == objc-2) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "\"-dictionary\" option must be followed by" + " compression dictionary bytes", -1)); + Tcl_SetErrorCode(interp, "TCL", "ZIP", "NOVAL", NULL); + return TCL_ERROR; + } + compDictObj = objv[++i]; + break; + } + + if (flush == -2) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "\"-flush\", \"-fullflush\" and \"-finalize\" options" + " are mutually exclusive", -1)); + Tcl_SetErrorCode(interp, "TCL", "ZIP", "EXCLUSIVE", NULL); + return TCL_ERROR; + } + } + if (flush == -1) { + flush = 0; + } + + /* + * Set the compression dictionary if requested. + */ + + if (compDictObj != NULL) { + int len; + + (void) Tcl_GetByteArrayFromObj(compDictObj, &len); + if (len == 0) { + compDictObj = NULL; + } + Tcl_ZlibStreamSetCompressionDictionary(zstream, compDictObj); + } + + /* + * Send the data to the stream core, along with any flushing directive. + */ + + if (Tcl_ZlibStreamPut(zstream, objv[objc-1], flush) != TCL_OK) { + return TCL_ERROR; + } + + /* + * Get such data out as we can (up to the requested length). + */ + + TclNewObj(obj); + code = Tcl_ZlibStreamGet(zstream, obj, buffersize); + if (code == TCL_OK) { + Tcl_SetObjResult(interp, obj); + } else { + TclDecrRefCount(obj); + } + return code; +} + +static int +ZlibStreamPutCmd( + ClientData cd, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + Tcl_ZlibStream zstream = cd; + int index, flush = -1, i; + Tcl_Obj *compDictObj = NULL; + static const char *const put_options[] = { + "-dictionary", "-finalize", "-flush", "-fullflush", NULL + }; + enum putOptions { + po_dictionary, po_finalize, po_flush, po_fullflush + }; + + for (i=2; i<objc-1; i++) { + if (Tcl_GetIndexFromObj(interp, objv[i], put_options, "option", 0, + &index) != TCL_OK) { + return TCL_ERROR; + } + + switch ((enum putOptions) index) { + case po_flush: /* -flush */ + if (flush > -1) { + flush = -2; + } else { + flush = Z_SYNC_FLUSH; + } + break; + case po_fullflush: /* -fullflush */ + if (flush > -1) { + flush = -2; + } else { + flush = Z_FULL_FLUSH; + } + break; + case po_finalize: /* -finalize */ + if (flush > -1) { + flush = -2; + } else { + flush = Z_FINISH; + } + break; + case po_dictionary: + if (i == objc-2) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "\"-dictionary\" option must be followed by" + " compression dictionary bytes", -1)); + Tcl_SetErrorCode(interp, "TCL", "ZIP", "NOVAL", NULL); + return TCL_ERROR; + } + compDictObj = objv[++i]; + break; + } + if (flush == -2) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "\"-flush\", \"-fullflush\" and \"-finalize\" options" + " are mutually exclusive", -1)); + Tcl_SetErrorCode(interp, "TCL", "ZIP", "EXCLUSIVE", NULL); + return TCL_ERROR; + } + } + if (flush == -1) { + flush = 0; + } + + /* + * Set the compression dictionary if requested. + */ + + if (compDictObj != NULL) { + int len; + + (void) Tcl_GetByteArrayFromObj(compDictObj, &len); + if (len == 0) { + compDictObj = NULL; + } + Tcl_ZlibStreamSetCompressionDictionary(zstream, compDictObj); + } + + /* + * Send the data to the stream core, along with any flushing directive. + */ + + return Tcl_ZlibStreamPut(zstream, objv[objc-1], flush); +} + +static int +ZlibStreamHeaderCmd( + ClientData cd, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + ZlibStreamHandle *zshPtr = cd; + Tcl_Obj *resultObj; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + return TCL_ERROR; + } else if (zshPtr->mode != TCL_ZLIB_STREAM_INFLATE + || zshPtr->format != TCL_ZLIB_FORMAT_GZIP) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "only gunzip streams can produce header information", -1)); + Tcl_SetErrorCode(interp, "TCL", "ZIP", "BADOP", NULL); + return TCL_ERROR; + } + + TclNewObj(resultObj); + ExtractHeader(&zshPtr->gzHeaderPtr->header, resultObj); + Tcl_SetObjResult(interp, resultObj); + return TCL_OK; +} /* *---------------------------------------------------------------------- @@ -2301,7 +2890,7 @@ ZlibTransformClose( if (e != Z_OK && e != Z_STREAM_END) { /* TODO: is this the right way to do errors on close? */ if (!TclInThreadExit()) { - ConvertError(interp, e); + ConvertError(interp, e, cd->outStream.adler); } result = TCL_ERROR; break; @@ -2312,12 +2901,10 @@ ZlibTransformClose( /* TODO: is this the right way to do errors on close? * Note: when close is called from FinalizeIOSubsystem * then interp may be NULL */ - if (!TclInThreadExit()) { - if (interp) { - Tcl_AppendResult(interp, - "error while finalizing file: ", - Tcl_PosixError(interp), NULL); - } + if (!TclInThreadExit() && interp) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error while finalizing file: %s", + Tcl_PosixError(interp))); } result = TCL_ERROR; break; @@ -2403,7 +2990,7 @@ ZlibTransformInput( * reading over the border. */ - readBytes = Tcl_ReadRaw(cd->parent, cd->inBuffer, 1); + readBytes = Tcl_ReadRaw(cd->parent, cd->inBuffer, cd->readAheadLimit); /* * Three cases here: @@ -2517,6 +3104,7 @@ ZlibTransformOutput( Tcl_DriverOutputProc *outProc = Tcl_ChannelOutputProc(Tcl_GetChannelType(cd->parent)); int e, produced; + Tcl_Obj *errObj; if (cd->mode == TCL_ZLIB_STREAM_INFLATE) { return outProc(Tcl_GetChannelInstanceData(cd->parent), buf, toWrite, @@ -2540,14 +3128,19 @@ ZlibTransformOutput( } } while (e == Z_OK && produced > 0 && cd->outStream.avail_in > 0); - if (e != Z_OK) { - Tcl_SetChannelError(cd->parent, - Tcl_NewStringObj(cd->outStream.msg, -1)); - *errorCodePtr = EINVAL; - return -1; + if (e == Z_OK) { + return toWrite - cd->outStream.avail_in; } - return toWrite - cd->outStream.avail_in; + errObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(NULL, errObj, Tcl_NewStringObj("-errorcode",-1)); + Tcl_ListObjAppendElement(NULL, errObj, + ConvertErrorToList(e, cd->outStream.adler)); + Tcl_ListObjAppendElement(NULL, errObj, + Tcl_NewStringObj(cd->outStream.msg, -1)); + Tcl_SetChannelError(cd->parent, errObj); + *errorCodePtr = EINVAL; + return -1; } /* @@ -2570,56 +3163,113 @@ ZlibTransformSetOption( /* not used */ ZlibChannelData *cd = instanceData; Tcl_DriverSetOptionProc *setOptionProc = Tcl_ChannelSetOptionProc(Tcl_GetChannelType(cd->parent)); - static const char *chanOptions = "flush"; + static const char *compressChanOptions = "dictionary flush"; + static const char *gzipChanOptions = "flush"; + static const char *decompressChanOptions = "dictionary limit"; + static const char *gunzipChanOptions = "flush limit"; int haveFlushOpt = (cd->mode == TCL_ZLIB_STREAM_DEFLATE); - if (haveFlushOpt && optionName && strcmp(optionName, "-flush") == 0) { - int flushType; + if (optionName && (strcmp(optionName, "-dictionary") == 0) + && (cd->format != TCL_ZLIB_FORMAT_GZIP)) { + Tcl_Obj *compDictObj; + int code; - if (value[0] == 'f' && strcmp(value, "full") == 0) { - flushType = Z_FULL_FLUSH; - } else if (value[0] == 's' && strcmp(value, "sync") == 0) { - flushType = Z_SYNC_FLUSH; - } else { - Tcl_AppendResult(interp, "unknown -flush type \"", value, - "\": must be full or sync", NULL); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "FLUSH", NULL); - return TCL_ERROR; + TclNewStringObj(compDictObj, value, strlen(value)); + Tcl_IncrRefCount(compDictObj); + (void) Tcl_GetByteArrayFromObj(compDictObj, NULL); + if (cd->compDictObj) { + TclDecrRefCount(cd->compDictObj); + } + cd->compDictObj = compDictObj; + code = Z_OK; + if (cd->mode == TCL_ZLIB_STREAM_DEFLATE) { + code = SetDeflateDictionary(&cd->outStream, compDictObj); + if (code != Z_OK) { + ConvertError(interp, code, cd->outStream.adler); + return TCL_ERROR; + } + } else if (cd->format == TCL_ZLIB_FORMAT_RAW) { + code = SetInflateDictionary(&cd->inStream, compDictObj); + if (code != Z_OK) { + ConvertError(interp, code, cd->inStream.adler); + return TCL_ERROR; + } } + return TCL_OK; + } - /* - * Try to actually do the flush now. - */ + if (haveFlushOpt) { + if (optionName && strcmp(optionName, "-flush") == 0) { + int flushType; - cd->outStream.avail_in = 0; - while (1) { - int e; + if (value[0] == 'f' && strcmp(value, "full") == 0) { + flushType = Z_FULL_FLUSH; + } else if (value[0] == 's' && strcmp(value, "sync") == 0) { + flushType = Z_SYNC_FLUSH; + } else { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unknown -flush type \"%s\": must be full or sync", + value)); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "FLUSH", NULL); + return TCL_ERROR; + } - cd->outStream.next_out = (Bytef *) cd->outBuffer; - cd->outStream.avail_out = cd->outAllocated; + /* + * Try to actually do the flush now. + */ - e = deflate(&cd->outStream, flushType); - if (e == Z_BUF_ERROR) { - break; - } else if (e != Z_OK) { - ConvertError(interp, e); - return TCL_ERROR; - } else if (cd->outStream.avail_out == 0) { - break; + cd->outStream.avail_in = 0; + while (1) { + int e; + + cd->outStream.next_out = (Bytef *) cd->outBuffer; + cd->outStream.avail_out = cd->outAllocated; + + e = deflate(&cd->outStream, flushType); + if (e == Z_BUF_ERROR) { + break; + } else if (e != Z_OK) { + ConvertError(interp, e, cd->outStream.adler); + return TCL_ERROR; + } else if (cd->outStream.avail_out == 0) { + break; + } + + if (Tcl_WriteRaw(cd->parent, cd->outBuffer, + cd->outStream.next_out - (Bytef *) cd->outBuffer)<0) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "problem flushing channel: %s", + Tcl_PosixError(interp))); + return TCL_ERROR; + } } + return TCL_OK; + } + } else { + if (optionName && strcmp(optionName, "-limit") == 0) { + int newLimit; - if (Tcl_WriteRaw(cd->parent, cd->outBuffer, - cd->outStream.next_out - (Bytef *) cd->outBuffer) < 0) { - Tcl_AppendResult(interp, "problem flushing channel: ", - Tcl_PosixError(interp), NULL); + if (Tcl_GetInt(interp, value, &newLimit) != TCL_OK) { + return TCL_ERROR; + } else if (newLimit < 1 || newLimit > MAX_BUFFER_SIZE) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "-limit must be between 1 and 65536", -1)); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "READLIMIT", NULL); return TCL_ERROR; } } - return TCL_OK; } if (setOptionProc == NULL) { - return Tcl_BadChannelOption(interp, optionName, chanOptions); + if (cd->format == TCL_ZLIB_FORMAT_GZIP) { + return Tcl_BadChannelOption(interp, optionName, + (cd->mode == TCL_ZLIB_STREAM_DEFLATE) + ? gzipChanOptions : gunzipChanOptions); + } else { + return Tcl_BadChannelOption(interp, optionName, + (cd->mode == TCL_ZLIB_STREAM_DEFLATE) + ? compressChanOptions : decompressChanOptions); + } } /* @@ -2651,7 +3301,10 @@ ZlibTransformGetOption( ZlibChannelData *cd = instanceData; Tcl_DriverGetOptionProc *getOptionProc = Tcl_ChannelGetOptionProc(Tcl_GetChannelType(cd->parent)); - static const char *chanOptions = "checksum header"; + static const char *compressChanOptions = "checksum dictionary"; + static const char *gzipChanOptions = "checksum"; + static const char *decompressChanOptions = "checksum dictionary limit"; + static const char *gunzipChanOptions = "checksum header limit"; /* * The "crc" option reports the current CRC (calculated with the Adler32 @@ -2679,6 +3332,28 @@ ZlibTransformGetOption( } } + if ((cd->format != TCL_ZLIB_FORMAT_GZIP) && + (optionName == NULL || strcmp(optionName, "-dictionary") == 0)) { + /* + * Embedded NUL bytes are ok; they'll be C080-encoded. + */ + + if (optionName == NULL) { + Tcl_DStringAppendElement(dsPtr, "-dictionary"); + if (cd->compDictObj) { + Tcl_DStringAppendElement(dsPtr, + Tcl_GetString(cd->compDictObj)); + } else { + Tcl_DStringAppendElement(dsPtr, ""); + } + } else { + int len; + const char *str = Tcl_GetStringFromObj(cd->compDictObj, &len); + + Tcl_DStringAppend(dsPtr, str, len); + } + } + /* * The "header" option, which is only valid on inflating gzip channels, * reports the header that has been read from the start of the stream. @@ -2711,7 +3386,15 @@ ZlibTransformGetOption( if (optionName == NULL) { return TCL_OK; } - return Tcl_BadChannelOption(interp, optionName, chanOptions); + if (cd->format == TCL_ZLIB_FORMAT_GZIP) { + return Tcl_BadChannelOption(interp, optionName, + (cd->mode == TCL_ZLIB_STREAM_DEFLATE) + ? gzipChanOptions : gunzipChanOptions); + } else { + return Tcl_BadChannelOption(interp, optionName, + (cd->mode == TCL_ZLIB_STREAM_DEFLATE) + ? compressChanOptions : decompressChanOptions); + } } /* @@ -2856,10 +3539,15 @@ ZlibStackChannelTransform( * decompressing transforms. */ int level, /* What compression level to use. Ignored for * decompressing transforms. */ + int limit, /* The limit on the number of bytes to read + * ahead; always at least 1. */ Tcl_Channel channel, /* The channel to attach to. */ - Tcl_Obj *gzipHeaderDictPtr) /* A description of header to use, or NULL to + Tcl_Obj *gzipHeaderDictPtr, /* A description of header to use, or NULL to * use a default. Ignored if not compressing * to produce gzip-format data. */ + Tcl_Obj *compDictObj) /* Byte-array object containing compression + * dictionary (not dictObj!) to use if + * necessary. */ { ZlibChannelData *cd = ckalloc(sizeof(ZlibChannelData)); Tcl_Channel chan; @@ -2872,15 +3560,15 @@ ZlibStackChannelTransform( memset(cd, 0, sizeof(ZlibChannelData)); cd->mode = mode; + cd->format = format; + cd->readAheadLimit = limit; if (format == TCL_ZLIB_FORMAT_GZIP || format == TCL_ZLIB_FORMAT_AUTO) { if (mode == TCL_ZLIB_STREAM_DEFLATE) { if (gzipHeaderDictPtr) { - int dummy = 0; - cd->flags |= OUT_HEADER; if (GenerateHeader(interp, gzipHeaderDictPtr, &cd->outHeader, - &dummy) != TCL_OK) { + NULL) != TCL_OK) { goto error; } } @@ -2895,6 +3583,12 @@ ZlibStackChannelTransform( } } + if (compDictObj != NULL) { + cd->compDictObj = Tcl_DuplicateObj(compDictObj); + Tcl_IncrRefCount(cd->compDictObj); + Tcl_GetByteArrayFromObj(cd->compDictObj, NULL); + } + if (format == TCL_ZLIB_FORMAT_RAW) { wbits = WBITS_RAW; } else if (format == TCL_ZLIB_FORMAT_ZLIB) { @@ -2924,6 +3618,14 @@ ZlibStackChannelTransform( goto error; } } + if (cd->format == TCL_ZLIB_FORMAT_RAW && cd->compDictObj) { + e = SetInflateDictionary(&cd->inStream, cd->compDictObj); + if (e != Z_OK) { + goto error; + } + TclDecrRefCount(cd->compDictObj); + cd->compDictObj = NULL; + } } else { e = deflateInit2(&cd->outStream, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY); @@ -2938,6 +3640,12 @@ ZlibStackChannelTransform( goto error; } } + if (cd->compDictObj) { + e = SetDeflateDictionary(&cd->outStream, cd->compDictObj); + if (e != Z_OK) { + goto error; + } + } } Tcl_DStringInit(&cd->decompressed); @@ -2961,6 +3669,9 @@ ZlibStackChannelTransform( ckfree(cd->outBuffer); deflateEnd(&cd->outStream); } + if (cd->compDictObj) { + Tcl_DecrRefCount(cd->compDictObj); + } ckfree(cd); return NULL; } @@ -3050,6 +3761,7 @@ ResultGenerate( #define MAXBUF 1024 unsigned char buf[MAXBUF]; int e, written; + Tcl_Obj *errObj; cd->inStream.next_in = (Bytef *) cd->inBuffer; cd->inStream.avail_in = n; @@ -3059,6 +3771,18 @@ ResultGenerate( cd->inStream.avail_out = MAXBUF; e = inflate(&cd->inStream, flush); + if (e == Z_NEED_DICT && cd->compDictObj) { + e = SetInflateDictionary(&cd->inStream, cd->compDictObj); + if (e == Z_OK) { + /* + * A repetition of Z_NEED_DICT is just an error. + */ + + cd->inStream.next_out = (Bytef *) buf; + cd->inStream.avail_out = MAXBUF; + e = inflate(&cd->inStream, flush); + } + } /* * avail_out is now the left over space in the output. Therefore @@ -3090,13 +3814,7 @@ ResultGenerate( */ if ((e != Z_OK) && (e != Z_BUF_ERROR)) { - Tcl_Obj *errObj = Tcl_NewListObj(0, NULL); - - Tcl_ListObjAppendElement(NULL, errObj, - Tcl_NewStringObj(cd->inStream.msg, -1)); - Tcl_SetChannelError(cd->parent, errObj); - *errorCodePtr = EINVAL; - return TCL_ERROR; + goto handleError; } /* @@ -3107,6 +3825,17 @@ ResultGenerate( return TCL_OK; } } + + handleError: + errObj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(NULL, errObj, Tcl_NewStringObj("-errorcode",-1)); + Tcl_ListObjAppendElement(NULL, errObj, + ConvertErrorToList(e, cd->inStream.adler)); + Tcl_ListObjAppendElement(NULL, errObj, + Tcl_NewStringObj(cd->inStream.msg, -1)); + Tcl_SetChannelError(cd->parent, errObj); + *errorCodePtr = EINVAL; + return TCL_ERROR; } /* @@ -3119,6 +3848,8 @@ int TclZlibInit( Tcl_Interp *interp) { + Tcl_Config cfg[2]; + /* * This does two things. It creates a counter used in the creation of * stream commands, and it creates the namespace that will contain those @@ -3132,6 +3863,23 @@ TclZlibInit( */ Tcl_CreateObjCommand(interp, "zlib", ZlibCmd, 0, 0); + + /* + * Store the underlying configuration information. + * + * TODO: Describe whether we're using the system version of the library or + * a compatibility version built into Tcl? + */ + + cfg[0].key = "zlibVersion"; + cfg[0].value = zlibVersion(); + cfg[1].key = NULL; + Tcl_RegisterConfig(interp, "zlib", cfg, "ascii"); + + /* + * Formally provide the package as a Tcl built-in. + */ + return Tcl_PkgProvide(interp, "zlib", TCL_ZLIB_VERSION); } @@ -3152,7 +3900,7 @@ Tcl_ZlibStreamInit( Tcl_Obj *dictObj, Tcl_ZlibStream *zshandle) { - Tcl_SetResult(interp, "unimplemented", TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj("unimplemented", -1)); Tcl_SetErrorCode(interp, "TCL", "UNIMPLEMENTED", NULL); return TCL_ERROR; } @@ -3218,7 +3966,7 @@ Tcl_ZlibDeflate( int level, Tcl_Obj *gzipHeaderDictObj) { - Tcl_SetResult(interp, "unimplemented", TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj("unimplemented", -1)); Tcl_SetErrorCode(interp, "TCL", "UNIMPLEMENTED", NULL); return TCL_ERROR; } @@ -3231,7 +3979,7 @@ Tcl_ZlibInflate( int bufferSize, Tcl_Obj *gzipHeaderDictObj) { - Tcl_SetResult(interp, "unimplemented", TCL_STATIC); + Tcl_SetObjResult(interp, Tcl_NewStringObj("unimplemented", -1)); Tcl_SetErrorCode(interp, "TCL", "UNIMPLEMENTED", NULL); return TCL_ERROR; } @@ -3253,6 +4001,14 @@ Tcl_ZlibAdler32( { return 0; } + +void +Tcl_ZlibStreamSetCompressionDictionary( + Tcl_ZlibStream zshandle, + Tcl_Obj *compressionDictionaryObj) +{ + /* Do nothing. */ +} #endif /* HAVE_ZLIB */ /* diff --git a/library/dde/pkgIndex.tcl b/library/dde/pkgIndex.tcl index ce8276b..4cf73d0 100644 --- a/library/dde/pkgIndex.tcl +++ b/library/dde/pkgIndex.tcl @@ -1,7 +1,7 @@ if {([info commands ::tcl::pkgconfig] eq "") || ([info sharedlibextension] ne ".dll")} return if {[::tcl::pkgconfig get debug]} { - package ifneeded dde 1.4.0b1 [list load [file join $dir tcldde14g.dll] dde] + package ifneeded dde 1.4.0 [list load [file join $dir tcldde14g.dll] dde] } else { - package ifneeded dde 1.4.0b1 [list load [file join $dir tcldde14.dll] dde] + package ifneeded dde 1.4.0 [list load [file join $dir tcldde14.dll] dde] } diff --git a/library/http/http.tcl b/library/http/http.tcl index 2653c3e..d57e3ce 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -11,7 +11,7 @@ package require Tcl 8.6 # Keep this in sync with pkgIndex.tcl and with the install directories in # Makefiles -package provide http 2.8.4 +package provide http 2.8.5 namespace eval http { # Allow resourcing to not clobber existing data @@ -205,15 +205,13 @@ proc http::Finish {token {errormsg ""} {skipCB 0}} { if {[info exists state(after)]} { after cancel $state(after) } - if {[info exists state(-command)] && !$skipCB} { - if {[catch {eval $state(-command) {$token}} err]} { - if {$errormsg eq ""} { - set state(error) [list $err $errorInfo $errorCode] - set state(status) error - } + if {[info exists state(-command)] && !$skipCB + && ![info exists state(done-command-cb)]} { + set state(done-command-cb) yes + if {[catch {eval $state(-command) {$token}} err] && $errormsg eq ""} { + set state(error) [list $err $errorInfo $errorCode] + set state(status) error } - # Command callback may already have unset our state - unset -nocomplain state(-command) } } diff --git a/library/http/pkgIndex.tcl b/library/http/pkgIndex.tcl index d51f8a8..303d3bd 100644 --- a/library/http/pkgIndex.tcl +++ b/library/http/pkgIndex.tcl @@ -1,2 +1,2 @@ if {![package vsatisfies [package provide Tcl] 8.6]} {return} -package ifneeded http 2.8.4 [list tclPkgSetup $dir http 2.8.4 {{http.tcl source {::http::config ::http::formatQuery ::http::geturl ::http::reset ::http::wait ::http::register ::http::unregister ::http::mapReply}}}] +package ifneeded http 2.8.5 [list tclPkgSetup $dir http 2.8.5 {{http.tcl source {::http::config ::http::formatQuery ::http::geturl ::http::reset ::http::wait ::http::register ::http::unregister ::http::mapReply}}}] diff --git a/library/init.tcl b/library/init.tcl index d8de540..3ec78af 100644 --- a/library/init.tcl +++ b/library/init.tcl @@ -15,7 +15,7 @@ if {[info commands package] == ""} { error "version mismatch: library\nscripts expect Tcl version 7.5b1 or later but the loaded version is\nonly [info patchlevel]" } -package require -exact Tcl 8.6b2 +package require -exact Tcl 8.6b3 # Compute the auto path to use in this interpreter. # The values on the path come from several locations: @@ -689,13 +689,14 @@ proc auto_execok name { } } - foreach dir [split $path {;}] { - # Skip already checked directories - if {[info exists checked($dir)] || ($dir eq "")} { - continue - } - set checked($dir) {} - foreach ext $execExtensions { + foreach ext $execExtensions { + unset -nocomplain checked + foreach dir [split $path {;}] { + # Skip already checked directories + if {[info exists checked($dir)] || ($dir eq "")} { + continue + } + set checked($dir) {} set file [file join $dir ${name}${ext}] if {[file exists $file] && ![file isdirectory $file]} { return [set auto_execs($name) [list $file]] diff --git a/library/msgcat/msgcat.tcl b/library/msgcat/msgcat.tcl index 3377b47..112507a 100644 --- a/library/msgcat/msgcat.tcl +++ b/library/msgcat/msgcat.tcl @@ -13,11 +13,11 @@ package require Tcl 8.5 # When the version number changes, be sure to update the pkgIndex.tcl file, # and the installation directory in the Makefiles. -package provide msgcat 1.4.5 +package provide msgcat 1.5.0 namespace eval msgcat { namespace export mc mcload mclocale mcmax mcmset mcpreferences mcset \ - mcunknown + mcunknown mcflset mcflmset # Records the current locale as passed to mclocale variable Locale "" @@ -25,6 +25,9 @@ namespace eval msgcat { # Records the list of locales to search variable Loclist {} + # Records the locale of the currently sourced message catalogue file + variable FileLocale + # Records the mapping between source strings and translated strings. The # dict key is of the form "<locale> <namespace> <src>", where locale and # namespace should be themselves dict values and the value is @@ -277,6 +280,11 @@ proc msgcat::mcpreferences {} { # Returns the number of message catalogs that were loaded. proc msgcat::mcload {langdir} { + variable FileLocale + # Save the file locale if we are recursively called + if {[info exists FileLocale]} { + set nestedFileLocale $FileLocale + } set x 0 foreach p [mcpreferences] { if { $p eq {} } { @@ -285,9 +293,17 @@ proc msgcat::mcload {langdir} { set langfile [file join $langdir $p.msg] if {[file exists $langfile]} { incr x + set FileLocale [string tolower [file tail [file rootname $langfile]]] + if {"root" eq $FileLocale} { + set FileLocale "" + } uplevel 1 [list ::source -encoding utf-8 $langfile] + unset FileLocale } } + if {[info exists nestedFileLocale]} { + set FileLocale $nestedFileLocale + } return $x } @@ -318,6 +334,35 @@ proc msgcat::mcset {locale src {dest ""}} { return $dest } +# msgcat::mcflset -- +# +# Set the translation for a given string in the current file locale. +# +# Arguments: +# src The source string. +# dest (Optional) The translated string. If omitted, +# the source string is used. +# +# Results: +# Returns the new locale. + +proc msgcat::mcflset {src {dest ""}} { + variable FileLocale + variable Msgs + + if {![info exists FileLocale]} { + return -code error \ + "must only be used inside a message catalog loaded with ::msgcat::mcload" + } + if {[llength [info level 0]] == 2} { ;# dest not specified + set dest $src + } + + set ns [uplevel 1 [list ::namespace current]] + dict set Msgs $FileLocale $ns $src $dest + return $dest +} + # msgcat::mcmset -- # # Set the translation for multiple strings in a specified locale. @@ -345,7 +390,38 @@ proc msgcat::mcmset {locale pairs } { dict set Msgs $locale $ns $src $dest } - return $length + return [expr {$length / 2}] +} + +# msgcat::mcflmset -- +# +# Set the translation for multiple strings in the mc file locale. +# +# Arguments: +# pairs One or more src/dest pairs (must be even length) +# +# Results: +# Returns the number of pairs processed + +proc msgcat::mcflmset {pairs} { + variable FileLocale + variable Msgs + + if {![info exists FileLocale]} { + return -code error \ + "must only be used inside a message catalog loaded with ::msgcat::mcload" + } + set length [llength $pairs] + if {$length % 2} { + return -code error "bad translation list:\ + should be \"[lindex [info level 0] 0] locale {src dest ...}\"" + } + + set ns [uplevel 1 [list ::namespace current]] + foreach {src dest} $pairs { + dict set Msgs $FileLocale $ns $src $dest + } + return [expr {$length / 2}] } # msgcat::mcunknown -- diff --git a/library/msgcat/pkgIndex.tcl b/library/msgcat/pkgIndex.tcl index 60c2d3c..832bf81 100644 --- a/library/msgcat/pkgIndex.tcl +++ b/library/msgcat/pkgIndex.tcl @@ -1,2 +1,2 @@ if {![package vsatisfies [package provide Tcl] 8.5]} {return} -package ifneeded msgcat 1.4.5 [list source [file join $dir msgcat.tcl]] +package ifneeded msgcat 1.5.0 [list source [file join $dir msgcat.tcl]] diff --git a/library/msgs/uk.msg b/library/msgs/uk.msg index 3e24f86..7d4c64a 100755 --- a/library/msgs/uk.msg +++ b/library/msgs/uk.msg @@ -33,7 +33,7 @@ namespace eval ::tcl::clock { ::msgcat::mcset uk MONTHS_FULL [list \ "\u0441\u0456\u0447\u043d\u044f"\ "\u043b\u044e\u0442\u043e\u0433\u043e"\ - "\u0431\u0435\u0440\u0435\u0436\u043d\u044f"\ + "\u0431\u0435\u0440\u0435\u0437\u043d\u044f"\ "\u043a\u0432\u0456\u0442\u043d\u044f"\ "\u0442\u0440\u0430\u0432\u043d\u044f"\ "\u0447\u0435\u0440\u0432\u043d\u044f"\ diff --git a/library/tzdata/Africa/Casablanca b/library/tzdata/Africa/Casablanca index 3817077..41f8742 100644 --- a/library/tzdata/Africa/Casablanca +++ b/library/tzdata/Africa/Casablanca @@ -30,6 +30,8 @@ set TZData(:Africa/Casablanca) { {1301788800 3600 1 WEST} {1312066800 0 0 WET} {1335664800 3600 1 WEST} + {1342749600 0 0 WET} + {1345428000 3600 1 WEST} {1348970400 0 0 WET} {1367114400 3600 1 WEST} {1380420000 0 0 WET} diff --git a/library/tzdata/America/Araguaina b/library/tzdata/America/Araguaina index 5073c56..dc1b543 100644 --- a/library/tzdata/America/Araguaina +++ b/library/tzdata/America/Araguaina @@ -54,4 +54,179 @@ set TZData(:America/Araguaina) { {1036292400 -7200 1 BRST} {1045360800 -10800 0 BRT} {1064368800 -10800 0 BRT} + {1350788400 -7200 0 BRST} + {1361066400 -10800 0 BRT} + {1382238000 -7200 1 BRST} + {1392516000 -10800 0 BRT} + {1413687600 -7200 1 BRST} + {1424570400 -10800 0 BRT} + {1445137200 -7200 1 BRST} + {1456020000 -10800 0 BRT} + {1476586800 -7200 1 BRST} + {1487469600 -10800 0 BRT} + {1508036400 -7200 1 BRST} + {1518919200 -10800 0 BRT} + {1540090800 -7200 1 BRST} + {1550368800 -10800 0 BRT} + {1571540400 -7200 1 BRST} + {1581818400 -10800 0 BRT} + {1602990000 -7200 1 BRST} + {1613872800 -10800 0 BRT} + {1634439600 -7200 1 BRST} + {1645322400 -10800 0 BRT} + {1665889200 -7200 1 BRST} + {1677376800 -10800 0 BRT} + {1697338800 -7200 1 BRST} + {1708221600 -10800 0 BRT} + {1729393200 -7200 1 BRST} + {1739671200 -10800 0 BRT} + {1760842800 -7200 1 BRST} + {1771725600 -10800 0 BRT} + {1792292400 -7200 1 BRST} + {1803175200 -10800 0 BRT} + {1823742000 -7200 1 BRST} + {1834624800 -10800 0 BRT} + {1855191600 -7200 1 BRST} + {1866074400 -10800 0 BRT} + {1887246000 -7200 1 BRST} + {1897524000 -10800 0 BRT} + {1918695600 -7200 1 BRST} + {1928973600 -10800 0 BRT} + {1950145200 -7200 1 BRST} + {1960423200 -10800 0 BRT} + {1981594800 -7200 1 BRST} + {1992477600 -10800 0 BRT} + {2013044400 -7200 1 BRST} + {2024532000 -10800 0 BRT} + {2044494000 -7200 1 BRST} + {2055376800 -10800 0 BRT} + {2076548400 -7200 1 BRST} + {2086826400 -10800 0 BRT} + {2107998000 -7200 1 BRST} + {2118880800 -10800 0 BRT} + {2139447600 -7200 1 BRST} + {2150330400 -10800 0 BRT} + {2170897200 -7200 1 BRST} + {2181780000 -10800 0 BRT} + {2202346800 -7200 1 BRST} + {2213229600 -10800 0 BRT} + {2234401200 -7200 1 BRST} + {2244679200 -10800 0 BRT} + {2265850800 -7200 1 BRST} + {2276128800 -10800 0 BRT} + {2297300400 -7200 1 BRST} + {2307578400 -10800 0 BRT} + {2328750000 -7200 1 BRST} + {2339632800 -10800 0 BRT} + {2360199600 -7200 1 BRST} + {2371082400 -10800 0 BRT} + {2391649200 -7200 1 BRST} + {2402532000 -10800 0 BRT} + {2423703600 -7200 1 BRST} + {2433981600 -10800 0 BRT} + {2455153200 -7200 1 BRST} + {2465431200 -10800 0 BRT} + {2486602800 -7200 1 BRST} + {2497485600 -10800 0 BRT} + {2518052400 -7200 1 BRST} + {2528935200 -10800 0 BRT} + {2549502000 -7200 1 BRST} + {2560384800 -10800 0 BRT} + {2580951600 -7200 1 BRST} + {2591834400 -10800 0 BRT} + {2613006000 -7200 1 BRST} + {2623284000 -10800 0 BRT} + {2644455600 -7200 1 BRST} + {2654733600 -10800 0 BRT} + {2675905200 -7200 1 BRST} + {2686788000 -10800 0 BRT} + {2707354800 -7200 1 BRST} + {2718237600 -10800 0 BRT} + {2738804400 -7200 1 BRST} + {2749687200 -10800 0 BRT} + {2770858800 -7200 1 BRST} + {2781136800 -10800 0 BRT} + {2802308400 -7200 1 BRST} + {2812586400 -10800 0 BRT} + {2833758000 -7200 1 BRST} + {2844036000 -10800 0 BRT} + {2865207600 -7200 1 BRST} + {2876090400 -10800 0 BRT} + {2896657200 -7200 1 BRST} + {2907540000 -10800 0 BRT} + {2928106800 -7200 1 BRST} + {2938989600 -10800 0 BRT} + {2960161200 -7200 1 BRST} + {2970439200 -10800 0 BRT} + {2991610800 -7200 1 BRST} + {3001888800 -10800 0 BRT} + {3023060400 -7200 1 BRST} + {3033943200 -10800 0 BRT} + {3054510000 -7200 1 BRST} + {3065392800 -10800 0 BRT} + {3085959600 -7200 1 BRST} + {3096842400 -10800 0 BRT} + {3118014000 -7200 1 BRST} + {3128292000 -10800 0 BRT} + {3149463600 -7200 1 BRST} + {3159741600 -10800 0 BRT} + {3180913200 -7200 1 BRST} + {3191191200 -10800 0 BRT} + {3212362800 -7200 1 BRST} + {3223245600 -10800 0 BRT} + {3243812400 -7200 1 BRST} + {3254695200 -10800 0 BRT} + {3275262000 -7200 1 BRST} + {3286144800 -10800 0 BRT} + {3307316400 -7200 1 BRST} + {3317594400 -10800 0 BRT} + {3338766000 -7200 1 BRST} + {3349044000 -10800 0 BRT} + {3370215600 -7200 1 BRST} + {3381098400 -10800 0 BRT} + {3401665200 -7200 1 BRST} + {3412548000 -10800 0 BRT} + {3433114800 -7200 1 BRST} + {3443997600 -10800 0 BRT} + {3464564400 -7200 1 BRST} + {3475447200 -10800 0 BRT} + {3496618800 -7200 1 BRST} + {3506896800 -10800 0 BRT} + {3528068400 -7200 1 BRST} + {3538346400 -10800 0 BRT} + {3559518000 -7200 1 BRST} + {3570400800 -10800 0 BRT} + {3590967600 -7200 1 BRST} + {3601850400 -10800 0 BRT} + {3622417200 -7200 1 BRST} + {3633300000 -10800 0 BRT} + {3654471600 -7200 1 BRST} + {3664749600 -10800 0 BRT} + {3685921200 -7200 1 BRST} + {3696199200 -10800 0 BRT} + {3717370800 -7200 1 BRST} + {3727648800 -10800 0 BRT} + {3748820400 -7200 1 BRST} + {3759703200 -10800 0 BRT} + {3780270000 -7200 1 BRST} + {3791152800 -10800 0 BRT} + {3811719600 -7200 1 BRST} + {3822602400 -10800 0 BRT} + {3843774000 -7200 1 BRST} + {3854052000 -10800 0 BRT} + {3875223600 -7200 1 BRST} + {3885501600 -10800 0 BRT} + {3906673200 -7200 1 BRST} + {3917556000 -10800 0 BRT} + {3938122800 -7200 1 BRST} + {3949005600 -10800 0 BRT} + {3969572400 -7200 1 BRST} + {3980455200 -10800 0 BRT} + {4001626800 -7200 1 BRST} + {4011904800 -10800 0 BRT} + {4033076400 -7200 1 BRST} + {4043354400 -10800 0 BRT} + {4064526000 -7200 1 BRST} + {4074804000 -10800 0 BRT} + {4095975600 -7200 1 BRST} } diff --git a/library/tzdata/America/Bahia b/library/tzdata/America/Bahia index 86c9411..ac67b71 100644 --- a/library/tzdata/America/Bahia +++ b/library/tzdata/America/Bahia @@ -64,179 +64,5 @@ set TZData(:America/Bahia) { {1064368800 -10800 0 BRT} {1318734000 -7200 0 BRST} {1330221600 -10800 0 BRT} - {1350788400 -7200 1 BRST} - {1361066400 -10800 0 BRT} - {1382238000 -7200 1 BRST} - {1392516000 -10800 0 BRT} - {1413687600 -7200 1 BRST} - {1424570400 -10800 0 BRT} - {1445137200 -7200 1 BRST} - {1456020000 -10800 0 BRT} - {1476586800 -7200 1 BRST} - {1487469600 -10800 0 BRT} - {1508036400 -7200 1 BRST} - {1518919200 -10800 0 BRT} - {1540090800 -7200 1 BRST} - {1550368800 -10800 0 BRT} - {1571540400 -7200 1 BRST} - {1581818400 -10800 0 BRT} - {1602990000 -7200 1 BRST} - {1613872800 -10800 0 BRT} - {1634439600 -7200 1 BRST} - {1645322400 -10800 0 BRT} - {1665889200 -7200 1 BRST} - {1677376800 -10800 0 BRT} - {1697338800 -7200 1 BRST} - {1708221600 -10800 0 BRT} - {1729393200 -7200 1 BRST} - {1739671200 -10800 0 BRT} - {1760842800 -7200 1 BRST} - {1771725600 -10800 0 BRT} - {1792292400 -7200 1 BRST} - {1803175200 -10800 0 BRT} - {1823742000 -7200 1 BRST} - {1834624800 -10800 0 BRT} - {1855191600 -7200 1 BRST} - {1866074400 -10800 0 BRT} - {1887246000 -7200 1 BRST} - {1897524000 -10800 0 BRT} - {1918695600 -7200 1 BRST} - {1928973600 -10800 0 BRT} - {1950145200 -7200 1 BRST} - {1960423200 -10800 0 BRT} - {1981594800 -7200 1 BRST} - {1992477600 -10800 0 BRT} - {2013044400 -7200 1 BRST} - {2024532000 -10800 0 BRT} - {2044494000 -7200 1 BRST} - {2055376800 -10800 0 BRT} - {2076548400 -7200 1 BRST} - {2086826400 -10800 0 BRT} - {2107998000 -7200 1 BRST} - {2118880800 -10800 0 BRT} - {2139447600 -7200 1 BRST} - {2150330400 -10800 0 BRT} - {2170897200 -7200 1 BRST} - {2181780000 -10800 0 BRT} - {2202346800 -7200 1 BRST} - {2213229600 -10800 0 BRT} - {2234401200 -7200 1 BRST} - {2244679200 -10800 0 BRT} - {2265850800 -7200 1 BRST} - {2276128800 -10800 0 BRT} - {2297300400 -7200 1 BRST} - {2307578400 -10800 0 BRT} - {2328750000 -7200 1 BRST} - {2339632800 -10800 0 BRT} - {2360199600 -7200 1 BRST} - {2371082400 -10800 0 BRT} - {2391649200 -7200 1 BRST} - {2402532000 -10800 0 BRT} - {2423703600 -7200 1 BRST} - {2433981600 -10800 0 BRT} - {2455153200 -7200 1 BRST} - {2465431200 -10800 0 BRT} - {2486602800 -7200 1 BRST} - {2497485600 -10800 0 BRT} - {2518052400 -7200 1 BRST} - {2528935200 -10800 0 BRT} - {2549502000 -7200 1 BRST} - {2560384800 -10800 0 BRT} - {2580951600 -7200 1 BRST} - {2591834400 -10800 0 BRT} - {2613006000 -7200 1 BRST} - {2623284000 -10800 0 BRT} - {2644455600 -7200 1 BRST} - {2654733600 -10800 0 BRT} - {2675905200 -7200 1 BRST} - {2686788000 -10800 0 BRT} - {2707354800 -7200 1 BRST} - {2718237600 -10800 0 BRT} - {2738804400 -7200 1 BRST} - {2749687200 -10800 0 BRT} - {2770858800 -7200 1 BRST} - {2781136800 -10800 0 BRT} - {2802308400 -7200 1 BRST} - {2812586400 -10800 0 BRT} - {2833758000 -7200 1 BRST} - {2844036000 -10800 0 BRT} - {2865207600 -7200 1 BRST} - {2876090400 -10800 0 BRT} - {2896657200 -7200 1 BRST} - {2907540000 -10800 0 BRT} - {2928106800 -7200 1 BRST} - {2938989600 -10800 0 BRT} - {2960161200 -7200 1 BRST} - {2970439200 -10800 0 BRT} - {2991610800 -7200 1 BRST} - {3001888800 -10800 0 BRT} - {3023060400 -7200 1 BRST} - {3033943200 -10800 0 BRT} - {3054510000 -7200 1 BRST} - {3065392800 -10800 0 BRT} - {3085959600 -7200 1 BRST} - {3096842400 -10800 0 BRT} - {3118014000 -7200 1 BRST} - {3128292000 -10800 0 BRT} - {3149463600 -7200 1 BRST} - {3159741600 -10800 0 BRT} - {3180913200 -7200 1 BRST} - {3191191200 -10800 0 BRT} - {3212362800 -7200 1 BRST} - {3223245600 -10800 0 BRT} - {3243812400 -7200 1 BRST} - {3254695200 -10800 0 BRT} - {3275262000 -7200 1 BRST} - {3286144800 -10800 0 BRT} - {3307316400 -7200 1 BRST} - {3317594400 -10800 0 BRT} - {3338766000 -7200 1 BRST} - {3349044000 -10800 0 BRT} - {3370215600 -7200 1 BRST} - {3381098400 -10800 0 BRT} - {3401665200 -7200 1 BRST} - {3412548000 -10800 0 BRT} - {3433114800 -7200 1 BRST} - {3443997600 -10800 0 BRT} - {3464564400 -7200 1 BRST} - {3475447200 -10800 0 BRT} - {3496618800 -7200 1 BRST} - {3506896800 -10800 0 BRT} - {3528068400 -7200 1 BRST} - {3538346400 -10800 0 BRT} - {3559518000 -7200 1 BRST} - {3570400800 -10800 0 BRT} - {3590967600 -7200 1 BRST} - {3601850400 -10800 0 BRT} - {3622417200 -7200 1 BRST} - {3633300000 -10800 0 BRT} - {3654471600 -7200 1 BRST} - {3664749600 -10800 0 BRT} - {3685921200 -7200 1 BRST} - {3696199200 -10800 0 BRT} - {3717370800 -7200 1 BRST} - {3727648800 -10800 0 BRT} - {3748820400 -7200 1 BRST} - {3759703200 -10800 0 BRT} - {3780270000 -7200 1 BRST} - {3791152800 -10800 0 BRT} - {3811719600 -7200 1 BRST} - {3822602400 -10800 0 BRT} - {3843774000 -7200 1 BRST} - {3854052000 -10800 0 BRT} - {3875223600 -7200 1 BRST} - {3885501600 -10800 0 BRT} - {3906673200 -7200 1 BRST} - {3917556000 -10800 0 BRT} - {3938122800 -7200 1 BRST} - {3949005600 -10800 0 BRT} - {3969572400 -7200 1 BRST} - {3980455200 -10800 0 BRT} - {4001626800 -7200 1 BRST} - {4011904800 -10800 0 BRT} - {4033076400 -7200 1 BRST} - {4043354400 -10800 0 BRT} - {4064526000 -7200 1 BRST} - {4074804000 -10800 0 BRT} - {4095975600 -7200 1 BRST} + {1350784800 -10800 0 BRT} } diff --git a/library/tzdata/America/Havana b/library/tzdata/America/Havana index 3f29a35..89cbc9a 100644 --- a/library/tzdata/America/Havana +++ b/library/tzdata/America/Havana @@ -107,179 +107,179 @@ set TZData(:America/Havana) { {1300597200 -14400 1 CDT} {1321160400 -18000 0 CST} {1333256400 -14400 1 CDT} - {1351400400 -18000 0 CST} + {1352005200 -18000 0 CST} {1362891600 -14400 1 CDT} - {1382850000 -18000 0 CST} + {1383454800 -18000 0 CST} {1394341200 -14400 1 CDT} - {1414299600 -18000 0 CST} + {1414904400 -18000 0 CST} {1425790800 -14400 1 CDT} - {1445749200 -18000 0 CST} + {1446354000 -18000 0 CST} {1457845200 -14400 1 CDT} - {1477803600 -18000 0 CST} + {1478408400 -18000 0 CST} {1489294800 -14400 1 CDT} - {1509253200 -18000 0 CST} + {1509858000 -18000 0 CST} {1520744400 -14400 1 CDT} - {1540702800 -18000 0 CST} + {1541307600 -18000 0 CST} {1552194000 -14400 1 CDT} - {1572152400 -18000 0 CST} + {1572757200 -18000 0 CST} {1583643600 -14400 1 CDT} - {1603602000 -18000 0 CST} + {1604206800 -18000 0 CST} {1615698000 -14400 1 CDT} - {1635656400 -18000 0 CST} + {1636261200 -18000 0 CST} {1647147600 -14400 1 CDT} - {1667106000 -18000 0 CST} + {1667710800 -18000 0 CST} {1678597200 -14400 1 CDT} - {1698555600 -18000 0 CST} + {1699160400 -18000 0 CST} {1710046800 -14400 1 CDT} - {1730005200 -18000 0 CST} + {1730610000 -18000 0 CST} {1741496400 -14400 1 CDT} - {1761454800 -18000 0 CST} + {1762059600 -18000 0 CST} {1772946000 -14400 1 CDT} - {1792904400 -18000 0 CST} + {1793509200 -18000 0 CST} {1805000400 -14400 1 CDT} - {1824958800 -18000 0 CST} + {1825563600 -18000 0 CST} {1836450000 -14400 1 CDT} - {1856408400 -18000 0 CST} + {1857013200 -18000 0 CST} {1867899600 -14400 1 CDT} - {1887858000 -18000 0 CST} + {1888462800 -18000 0 CST} {1899349200 -14400 1 CDT} - {1919307600 -18000 0 CST} + {1919912400 -18000 0 CST} {1930798800 -14400 1 CDT} - {1950757200 -18000 0 CST} + {1951362000 -18000 0 CST} {1962853200 -14400 1 CDT} - {1982811600 -18000 0 CST} + {1983416400 -18000 0 CST} {1994302800 -14400 1 CDT} - {2014261200 -18000 0 CST} + {2014866000 -18000 0 CST} {2025752400 -14400 1 CDT} - {2045710800 -18000 0 CST} + {2046315600 -18000 0 CST} {2057202000 -14400 1 CDT} - {2077160400 -18000 0 CST} + {2077765200 -18000 0 CST} {2088651600 -14400 1 CDT} - {2108610000 -18000 0 CST} + {2109214800 -18000 0 CST} {2120101200 -14400 1 CDT} - {2140059600 -18000 0 CST} + {2140664400 -18000 0 CST} {2152155600 -14400 1 CDT} - {2172114000 -18000 0 CST} + {2172718800 -18000 0 CST} {2183605200 -14400 1 CDT} - {2203563600 -18000 0 CST} + {2204168400 -18000 0 CST} {2215054800 -14400 1 CDT} - {2235013200 -18000 0 CST} + {2235618000 -18000 0 CST} {2246504400 -14400 1 CDT} - {2266462800 -18000 0 CST} + {2267067600 -18000 0 CST} {2277954000 -14400 1 CDT} - {2297912400 -18000 0 CST} + {2298517200 -18000 0 CST} {2309403600 -14400 1 CDT} - {2329362000 -18000 0 CST} + {2329966800 -18000 0 CST} {2341458000 -14400 1 CDT} - {2361416400 -18000 0 CST} + {2362021200 -18000 0 CST} {2372907600 -14400 1 CDT} - {2392866000 -18000 0 CST} + {2393470800 -18000 0 CST} {2404357200 -14400 1 CDT} - {2424315600 -18000 0 CST} + {2424920400 -18000 0 CST} {2435806800 -14400 1 CDT} - {2455765200 -18000 0 CST} + {2456370000 -18000 0 CST} {2467256400 -14400 1 CDT} - {2487214800 -18000 0 CST} + {2487819600 -18000 0 CST} {2499310800 -14400 1 CDT} - {2519269200 -18000 0 CST} + {2519874000 -18000 0 CST} {2530760400 -14400 1 CDT} - {2550718800 -18000 0 CST} + {2551323600 -18000 0 CST} {2562210000 -14400 1 CDT} - {2582168400 -18000 0 CST} + {2582773200 -18000 0 CST} {2593659600 -14400 1 CDT} - {2613618000 -18000 0 CST} + {2614222800 -18000 0 CST} {2625109200 -14400 1 CDT} - {2645067600 -18000 0 CST} + {2645672400 -18000 0 CST} {2656558800 -14400 1 CDT} - {2676517200 -18000 0 CST} + {2677122000 -18000 0 CST} {2688613200 -14400 1 CDT} - {2708571600 -18000 0 CST} + {2709176400 -18000 0 CST} {2720062800 -14400 1 CDT} - {2740021200 -18000 0 CST} + {2740626000 -18000 0 CST} {2751512400 -14400 1 CDT} - {2771470800 -18000 0 CST} + {2772075600 -18000 0 CST} {2782962000 -14400 1 CDT} - {2802920400 -18000 0 CST} + {2803525200 -18000 0 CST} {2814411600 -14400 1 CDT} - {2834370000 -18000 0 CST} + {2834974800 -18000 0 CST} {2846466000 -14400 1 CDT} - {2866424400 -18000 0 CST} + {2867029200 -18000 0 CST} {2877915600 -14400 1 CDT} - {2897874000 -18000 0 CST} + {2898478800 -18000 0 CST} {2909365200 -14400 1 CDT} - {2929323600 -18000 0 CST} + {2929928400 -18000 0 CST} {2940814800 -14400 1 CDT} - {2960773200 -18000 0 CST} + {2961378000 -18000 0 CST} {2972264400 -14400 1 CDT} - {2992222800 -18000 0 CST} + {2992827600 -18000 0 CST} {3003714000 -14400 1 CDT} - {3023672400 -18000 0 CST} + {3024277200 -18000 0 CST} {3035768400 -14400 1 CDT} - {3055726800 -18000 0 CST} + {3056331600 -18000 0 CST} {3067218000 -14400 1 CDT} - {3087176400 -18000 0 CST} + {3087781200 -18000 0 CST} {3098667600 -14400 1 CDT} - {3118626000 -18000 0 CST} + {3119230800 -18000 0 CST} {3130117200 -14400 1 CDT} - {3150075600 -18000 0 CST} + {3150680400 -18000 0 CST} {3161566800 -14400 1 CDT} - {3181525200 -18000 0 CST} + {3182130000 -18000 0 CST} {3193016400 -14400 1 CDT} - {3212974800 -18000 0 CST} + {3213579600 -18000 0 CST} {3225070800 -14400 1 CDT} - {3245029200 -18000 0 CST} + {3245634000 -18000 0 CST} {3256520400 -14400 1 CDT} - {3276478800 -18000 0 CST} + {3277083600 -18000 0 CST} {3287970000 -14400 1 CDT} - {3307928400 -18000 0 CST} + {3308533200 -18000 0 CST} {3319419600 -14400 1 CDT} - {3339378000 -18000 0 CST} + {3339982800 -18000 0 CST} {3350869200 -14400 1 CDT} - {3370827600 -18000 0 CST} + {3371432400 -18000 0 CST} {3382923600 -14400 1 CDT} - {3402882000 -18000 0 CST} + {3403486800 -18000 0 CST} {3414373200 -14400 1 CDT} - {3434331600 -18000 0 CST} + {3434936400 -18000 0 CST} {3445822800 -14400 1 CDT} - {3465781200 -18000 0 CST} + {3466386000 -18000 0 CST} {3477272400 -14400 1 CDT} - {3497230800 -18000 0 CST} + {3497835600 -18000 0 CST} {3508722000 -14400 1 CDT} - {3528680400 -18000 0 CST} + {3529285200 -18000 0 CST} {3540171600 -14400 1 CDT} - {3560130000 -18000 0 CST} + {3560734800 -18000 0 CST} {3572226000 -14400 1 CDT} - {3592184400 -18000 0 CST} + {3592789200 -18000 0 CST} {3603675600 -14400 1 CDT} - {3623634000 -18000 0 CST} + {3624238800 -18000 0 CST} {3635125200 -14400 1 CDT} - {3655083600 -18000 0 CST} + {3655688400 -18000 0 CST} {3666574800 -14400 1 CDT} - {3686533200 -18000 0 CST} + {3687138000 -18000 0 CST} {3698024400 -14400 1 CDT} - {3717982800 -18000 0 CST} + {3718587600 -18000 0 CST} {3730078800 -14400 1 CDT} - {3750037200 -18000 0 CST} + {3750642000 -18000 0 CST} {3761528400 -14400 1 CDT} - {3781486800 -18000 0 CST} + {3782091600 -18000 0 CST} {3792978000 -14400 1 CDT} - {3812936400 -18000 0 CST} + {3813541200 -18000 0 CST} {3824427600 -14400 1 CDT} - {3844386000 -18000 0 CST} + {3844990800 -18000 0 CST} {3855877200 -14400 1 CDT} - {3875835600 -18000 0 CST} + {3876440400 -18000 0 CST} {3887326800 -14400 1 CDT} - {3907285200 -18000 0 CST} + {3907890000 -18000 0 CST} {3919381200 -14400 1 CDT} - {3939339600 -18000 0 CST} + {3939944400 -18000 0 CST} {3950830800 -14400 1 CDT} - {3970789200 -18000 0 CST} + {3971394000 -18000 0 CST} {3982280400 -14400 1 CDT} - {4002238800 -18000 0 CST} + {4002843600 -18000 0 CST} {4013730000 -14400 1 CDT} - {4033688400 -18000 0 CST} + {4034293200 -18000 0 CST} {4045179600 -14400 1 CDT} - {4065138000 -18000 0 CST} + {4065742800 -18000 0 CST} {4076629200 -14400 1 CDT} - {4096587600 -18000 0 CST} + {4097192400 -18000 0 CST} } diff --git a/library/tzdata/Asia/Amman b/library/tzdata/Asia/Amman index bf30508..33f0ba7 100644 --- a/library/tzdata/Asia/Amman +++ b/library/tzdata/Asia/Amman @@ -70,8 +70,7 @@ set TZData(:Asia/Amman) { {1301608800 10800 1 EEST} {1319752800 7200 0 EET} {1333058400 10800 1 EEST} - {1351202400 7200 0 EET} - {1364508000 10800 1 EEST} + {1364504400 10800 1 EEST} {1382652000 7200 0 EET} {1395957600 10800 1 EEST} {1414706400 7200 0 EET} diff --git a/library/tzdata/Asia/Gaza b/library/tzdata/Asia/Gaza index 2094969..43e1847 100644 --- a/library/tzdata/Asia/Gaza +++ b/library/tzdata/Asia/Gaza @@ -97,5 +97,5 @@ set TZData(:Asia/Gaza) { {1301738460 10800 1 EEST} {1312146000 7200 0 EET} {1333058400 10800 1 EEST} - {1348779600 7200 0 EET} + {1348178400 7200 0 EET} } diff --git a/library/tzdata/Asia/Hebron b/library/tzdata/Asia/Hebron index 69addd8..98bb353 100644 --- a/library/tzdata/Asia/Hebron +++ b/library/tzdata/Asia/Hebron @@ -100,5 +100,5 @@ set TZData(:Asia/Hebron) { {1314655200 10800 1 EEST} {1317340800 7200 0 EET} {1333058400 10800 1 EEST} - {1348790400 7200 0 EET} + {1348178400 7200 0 EET} } diff --git a/library/tzdata/Asia/Jerusalem b/library/tzdata/Asia/Jerusalem index 48e213d..613eadd 100644 --- a/library/tzdata/Asia/Jerusalem +++ b/library/tzdata/Asia/Jerusalem @@ -96,53 +96,177 @@ set TZData(:Asia/Jerusalem) { {1333065600 10800 1 IDT} {1348354800 7200 0 IST} {1364515200 10800 1 IDT} - {1378594800 7200 0 IST} + {1381014000 7200 0 IST} {1395964800 10800 1 IDT} - {1411858800 7200 0 IST} + {1412463600 7200 0 IST} {1427414400 10800 1 IDT} - {1442703600 7200 0 IST} - {1459468800 10800 1 IDT} - {1475967600 7200 0 IST} - {1490918400 10800 1 IDT} - {1506207600 7200 0 IST} - {1522368000 10800 1 IDT} - {1537052400 7200 0 IST} + {1443913200 7200 0 IST} + {1458864000 10800 1 IDT} + {1475362800 7200 0 IST} + {1490313600 10800 1 IDT} + {1507417200 7200 0 IST} + {1521763200 10800 1 IDT} + {1538866800 7200 0 IST} {1553817600 10800 1 IDT} {1570316400 7200 0 IST} {1585267200 10800 1 IDT} - {1601161200 7200 0 IST} + {1601766000 7200 0 IST} {1616716800 10800 1 IDT} - {1631401200 7200 0 IST} - {1648771200 10800 1 IDT} + {1633215600 7200 0 IST} + {1648166400 10800 1 IDT} {1664665200 7200 0 IST} - {1680220800 10800 1 IDT} - {1695510000 7200 0 IST} + {1679616000 10800 1 IDT} + {1696719600 7200 0 IST} {1711670400 10800 1 IDT} {1728169200 7200 0 IST} {1743120000 10800 1 IDT} - {1759014000 7200 0 IST} + {1759618800 7200 0 IST} {1774569600 10800 1 IDT} - {1789858800 7200 0 IST} + {1791068400 7200 0 IST} {1806019200 10800 1 IDT} - {1823122800 7200 0 IST} - {1838073600 10800 1 IDT} - {1853362800 7200 0 IST} - {1869523200 10800 1 IDT} - {1884207600 7200 0 IST} + {1822604400 7200 0 IST} + {1837468800 10800 1 IDT} + {1854572400 7200 0 IST} + {1868918400 10800 1 IDT} + {1886022000 7200 0 IST} {1900972800 10800 1 IDT} {1917471600 7200 0 IST} {1932422400 10800 1 IDT} - {1947711600 7200 0 IST} + {1948921200 7200 0 IST} {1963872000 10800 1 IDT} - {1978556400 7200 0 IST} - {1995926400 10800 1 IDT} + {1980370800 7200 0 IST} + {1995321600 10800 1 IDT} {2011820400 7200 0 IST} - {2027376000 10800 1 IDT} - {2042060400 7200 0 IST} - {2058825600 10800 1 IDT} + {2026771200 10800 1 IDT} + {2043874800 7200 0 IST} + {2058220800 10800 1 IDT} {2075324400 7200 0 IST} {2090275200 10800 1 IDT} - {2106169200 7200 0 IST} + {2106774000 7200 0 IST} {2121724800 10800 1 IDT} - {2136409200 7200 0 IST} + {2138223600 7200 0 IST} + {2153174400 10800 1 IDT} + {2169673200 7200 0 IST} + {2184624000 10800 1 IDT} + {2201122800 7200 0 IST} + {2216073600 10800 1 IDT} + {2233177200 7200 0 IST} + {2248128000 10800 1 IDT} + {2264626800 7200 0 IST} + {2279577600 10800 1 IDT} + {2296076400 7200 0 IST} + {2311027200 10800 1 IDT} + {2327526000 7200 0 IST} + {2342476800 10800 1 IDT} + {2358975600 7200 0 IST} + {2373926400 10800 1 IDT} + {2391030000 7200 0 IST} + {2405376000 10800 1 IDT} + {2422479600 7200 0 IST} + {2437430400 10800 1 IDT} + {2453929200 7200 0 IST} + {2468880000 10800 1 IDT} + {2485378800 7200 0 IST} + {2500329600 10800 1 IDT} + {2516828400 7200 0 IST} + {2531779200 10800 1 IDT} + {2548278000 7200 0 IST} + {2563228800 10800 1 IDT} + {2580332400 7200 0 IST} + {2595283200 10800 1 IDT} + {2611782000 7200 0 IST} + {2626732800 10800 1 IDT} + {2643231600 7200 0 IST} + {2658182400 10800 1 IDT} + {2674681200 7200 0 IST} + {2689632000 10800 1 IDT} + {2706130800 7200 0 IST} + {2721081600 10800 1 IDT} + {2738185200 7200 0 IST} + {2752531200 10800 1 IDT} + {2769634800 7200 0 IST} + {2784585600 10800 1 IDT} + {2801084400 7200 0 IST} + {2816035200 10800 1 IDT} + {2832534000 7200 0 IST} + {2847484800 10800 1 IDT} + {2863983600 7200 0 IST} + {2878934400 10800 1 IDT} + {2895433200 7200 0 IST} + {2910384000 10800 1 IDT} + {2927487600 7200 0 IST} + {2941833600 10800 1 IDT} + {2958937200 7200 0 IST} + {2973888000 10800 1 IDT} + {2990386800 7200 0 IST} + {3005337600 10800 1 IDT} + {3021836400 7200 0 IST} + {3036787200 10800 1 IDT} + {3053286000 7200 0 IST} + {3068236800 10800 1 IDT} + {3084735600 7200 0 IST} + {3099686400 10800 1 IDT} + {3116790000 7200 0 IST} + {3131740800 10800 1 IDT} + {3148239600 7200 0 IST} + {3163190400 10800 1 IDT} + {3179689200 7200 0 IST} + {3194640000 10800 1 IDT} + {3211138800 7200 0 IST} + {3226089600 10800 1 IDT} + {3242588400 7200 0 IST} + {3257539200 10800 1 IDT} + {3274642800 7200 0 IST} + {3288988800 10800 1 IDT} + {3306092400 7200 0 IST} + {3321043200 10800 1 IDT} + {3337542000 7200 0 IST} + {3352492800 10800 1 IDT} + {3368991600 7200 0 IST} + {3383942400 10800 1 IDT} + {3400441200 7200 0 IST} + {3415392000 10800 1 IDT} + {3431890800 7200 0 IST} + {3446841600 10800 1 IDT} + {3463945200 7200 0 IST} + {3478896000 10800 1 IDT} + {3495394800 7200 0 IST} + {3510345600 10800 1 IDT} + {3526844400 7200 0 IST} + {3541795200 10800 1 IDT} + {3558294000 7200 0 IST} + {3573244800 10800 1 IDT} + {3589743600 7200 0 IST} + {3604694400 10800 1 IDT} + {3621798000 7200 0 IST} + {3636144000 10800 1 IDT} + {3653247600 7200 0 IST} + {3668198400 10800 1 IDT} + {3684697200 7200 0 IST} + {3699648000 10800 1 IDT} + {3716146800 7200 0 IST} + {3731097600 10800 1 IDT} + {3747596400 7200 0 IST} + {3762547200 10800 1 IDT} + {3779046000 7200 0 IST} + {3793996800 10800 1 IDT} + {3811100400 7200 0 IST} + {3825446400 10800 1 IDT} + {3842550000 7200 0 IST} + {3857500800 10800 1 IDT} + {3873999600 7200 0 IST} + {3888950400 10800 1 IDT} + {3905449200 7200 0 IST} + {3920400000 10800 1 IDT} + {3936898800 7200 0 IST} + {3951849600 10800 1 IDT} + {3968348400 7200 0 IST} + {3983299200 10800 1 IDT} + {4000402800 7200 0 IST} + {4015353600 10800 1 IDT} + {4031852400 7200 0 IST} + {4046803200 10800 1 IDT} + {4063302000 7200 0 IST} + {4078252800 10800 1 IDT} + {4094751600 7200 0 IST} } diff --git a/library/tzdata/Pacific/Apia b/library/tzdata/Pacific/Apia index 2e8e128..e6f33ad 100644 --- a/library/tzdata/Pacific/Apia +++ b/library/tzdata/Pacific/Apia @@ -10,4 +10,179 @@ set TZData(:Pacific/Apia) { {1316872800 -36000 1 WSDT} {1325239200 50400 1 WSDT} {1333202400 46800 0 WST} + {1348927200 50400 1 WSDT} + {1365256800 46800 0 WST} + {1380376800 50400 1 WSDT} + {1396706400 46800 0 WST} + {1411826400 50400 1 WSDT} + {1428156000 46800 0 WST} + {1443276000 50400 1 WSDT} + {1459605600 46800 0 WST} + {1474725600 50400 1 WSDT} + {1491055200 46800 0 WST} + {1506175200 50400 1 WSDT} + {1522504800 46800 0 WST} + {1538229600 50400 1 WSDT} + {1554559200 46800 0 WST} + {1569679200 50400 1 WSDT} + {1586008800 46800 0 WST} + {1601128800 50400 1 WSDT} + {1617458400 46800 0 WST} + {1632578400 50400 1 WSDT} + {1648908000 46800 0 WST} + {1664028000 50400 1 WSDT} + {1680357600 46800 0 WST} + {1695477600 50400 1 WSDT} + {1712412000 46800 0 WST} + {1727532000 50400 1 WSDT} + {1743861600 46800 0 WST} + {1758981600 50400 1 WSDT} + {1775311200 46800 0 WST} + {1790431200 50400 1 WSDT} + {1806760800 46800 0 WST} + {1821880800 50400 1 WSDT} + {1838210400 46800 0 WST} + {1853330400 50400 1 WSDT} + {1869660000 46800 0 WST} + {1885384800 50400 1 WSDT} + {1901714400 46800 0 WST} + {1916834400 50400 1 WSDT} + {1933164000 46800 0 WST} + {1948284000 50400 1 WSDT} + {1964613600 46800 0 WST} + {1979733600 50400 1 WSDT} + {1996063200 46800 0 WST} + {2011183200 50400 1 WSDT} + {2027512800 46800 0 WST} + {2042632800 50400 1 WSDT} + {2058962400 46800 0 WST} + {2074687200 50400 1 WSDT} + {2091016800 46800 0 WST} + {2106136800 50400 1 WSDT} + {2122466400 46800 0 WST} + {2137586400 50400 1 WSDT} + {2153916000 46800 0 WST} + {2169036000 50400 1 WSDT} + {2185365600 46800 0 WST} + {2200485600 50400 1 WSDT} + {2216815200 46800 0 WST} + {2232540000 50400 1 WSDT} + {2248869600 46800 0 WST} + {2263989600 50400 1 WSDT} + {2280319200 46800 0 WST} + {2295439200 50400 1 WSDT} + {2311768800 46800 0 WST} + {2326888800 50400 1 WSDT} + {2343218400 46800 0 WST} + {2358338400 50400 1 WSDT} + {2374668000 46800 0 WST} + {2389788000 50400 1 WSDT} + {2406117600 46800 0 WST} + {2421842400 50400 1 WSDT} + {2438172000 46800 0 WST} + {2453292000 50400 1 WSDT} + {2469621600 46800 0 WST} + {2484741600 50400 1 WSDT} + {2501071200 46800 0 WST} + {2516191200 50400 1 WSDT} + {2532520800 46800 0 WST} + {2547640800 50400 1 WSDT} + {2563970400 46800 0 WST} + {2579090400 50400 1 WSDT} + {2596024800 46800 0 WST} + {2611144800 50400 1 WSDT} + {2627474400 46800 0 WST} + {2642594400 50400 1 WSDT} + {2658924000 46800 0 WST} + {2674044000 50400 1 WSDT} + {2690373600 46800 0 WST} + {2705493600 50400 1 WSDT} + {2721823200 46800 0 WST} + {2736943200 50400 1 WSDT} + {2753272800 46800 0 WST} + {2768997600 50400 1 WSDT} + {2785327200 46800 0 WST} + {2800447200 50400 1 WSDT} + {2816776800 46800 0 WST} + {2831896800 50400 1 WSDT} + {2848226400 46800 0 WST} + {2863346400 50400 1 WSDT} + {2879676000 46800 0 WST} + {2894796000 50400 1 WSDT} + {2911125600 46800 0 WST} + {2926245600 50400 1 WSDT} + {2942575200 46800 0 WST} + {2958300000 50400 1 WSDT} + {2974629600 46800 0 WST} + {2989749600 50400 1 WSDT} + {3006079200 46800 0 WST} + {3021199200 50400 1 WSDT} + {3037528800 46800 0 WST} + {3052648800 50400 1 WSDT} + {3068978400 46800 0 WST} + {3084098400 50400 1 WSDT} + {3100428000 46800 0 WST} + {3116152800 50400 1 WSDT} + {3132482400 46800 0 WST} + {3147602400 50400 1 WSDT} + {3163932000 46800 0 WST} + {3179052000 50400 1 WSDT} + {3195381600 46800 0 WST} + {3210501600 50400 1 WSDT} + {3226831200 46800 0 WST} + {3241951200 50400 1 WSDT} + {3258280800 46800 0 WST} + {3273400800 50400 1 WSDT} + {3289730400 46800 0 WST} + {3305455200 50400 1 WSDT} + {3321784800 46800 0 WST} + {3336904800 50400 1 WSDT} + {3353234400 46800 0 WST} + {3368354400 50400 1 WSDT} + {3384684000 46800 0 WST} + {3399804000 50400 1 WSDT} + {3416133600 46800 0 WST} + {3431253600 50400 1 WSDT} + {3447583200 46800 0 WST} + {3462703200 50400 1 WSDT} + {3479637600 46800 0 WST} + {3494757600 50400 1 WSDT} + {3511087200 46800 0 WST} + {3526207200 50400 1 WSDT} + {3542536800 46800 0 WST} + {3557656800 50400 1 WSDT} + {3573986400 46800 0 WST} + {3589106400 50400 1 WSDT} + {3605436000 46800 0 WST} + {3620556000 50400 1 WSDT} + {3636885600 46800 0 WST} + {3652610400 50400 1 WSDT} + {3668940000 46800 0 WST} + {3684060000 50400 1 WSDT} + {3700389600 46800 0 WST} + {3715509600 50400 1 WSDT} + {3731839200 46800 0 WST} + {3746959200 50400 1 WSDT} + {3763288800 46800 0 WST} + {3778408800 50400 1 WSDT} + {3794738400 46800 0 WST} + {3809858400 50400 1 WSDT} + {3826188000 46800 0 WST} + {3841912800 50400 1 WSDT} + {3858242400 46800 0 WST} + {3873362400 50400 1 WSDT} + {3889692000 46800 0 WST} + {3904812000 50400 1 WSDT} + {3921141600 46800 0 WST} + {3936261600 50400 1 WSDT} + {3952591200 46800 0 WST} + {3967711200 50400 1 WSDT} + {3984040800 46800 0 WST} + {3999765600 50400 1 WSDT} + {4016095200 46800 0 WST} + {4031215200 50400 1 WSDT} + {4047544800 46800 0 WST} + {4062664800 50400 1 WSDT} + {4078994400 46800 0 WST} + {4094114400 50400 1 WSDT} } diff --git a/library/tzdata/Pacific/Fakaofo b/library/tzdata/Pacific/Fakaofo index 6cfdbd1..6ec98eb 100644 --- a/library/tzdata/Pacific/Fakaofo +++ b/library/tzdata/Pacific/Fakaofo @@ -2,6 +2,6 @@ set TZData(:Pacific/Fakaofo) { {-9223372036854775808 -41096 0 LMT} - {-2177411704 -36000 0 TKT} - {1325239200 50400 0 TKT} + {-2177411704 -39600 0 TKT} + {1325242800 46800 0 TKT} } diff --git a/library/tzdata/Pacific/Fiji b/library/tzdata/Pacific/Fiji index a408094..e067377 100644 --- a/library/tzdata/Pacific/Fiji +++ b/library/tzdata/Pacific/Fiji @@ -13,4 +13,179 @@ set TZData(:Pacific/Fiji) { {1299333600 43200 0 FJT} {1319292000 46800 1 FJST} {1327154400 43200 0 FJT} + {1350741600 46800 1 FJST} + {1358604000 43200 0 FJT} + {1382191200 46800 1 FJST} + {1390053600 43200 0 FJT} + {1413640800 46800 1 FJST} + {1421503200 43200 0 FJT} + {1445090400 46800 1 FJST} + {1453557600 43200 0 FJT} + {1477144800 46800 1 FJST} + {1485007200 43200 0 FJT} + {1508594400 46800 1 FJST} + {1516456800 43200 0 FJT} + {1540044000 46800 1 FJST} + {1547906400 43200 0 FJT} + {1571493600 46800 1 FJST} + {1579356000 43200 0 FJT} + {1602943200 46800 1 FJST} + {1611410400 43200 0 FJT} + {1634997600 46800 1 FJST} + {1642860000 43200 0 FJT} + {1666447200 46800 1 FJST} + {1674309600 43200 0 FJT} + {1697896800 46800 1 FJST} + {1705759200 43200 0 FJT} + {1729346400 46800 1 FJST} + {1737208800 43200 0 FJT} + {1760796000 46800 1 FJST} + {1768658400 43200 0 FJT} + {1792245600 46800 1 FJST} + {1800712800 43200 0 FJT} + {1824300000 46800 1 FJST} + {1832162400 43200 0 FJT} + {1855749600 46800 1 FJST} + {1863612000 43200 0 FJT} + {1887199200 46800 1 FJST} + {1895061600 43200 0 FJT} + {1918648800 46800 1 FJST} + {1926511200 43200 0 FJT} + {1950098400 46800 1 FJST} + {1957960800 43200 0 FJT} + {1982152800 46800 1 FJST} + {1990015200 43200 0 FJT} + {2013602400 46800 1 FJST} + {2021464800 43200 0 FJT} + {2045052000 46800 1 FJST} + {2052914400 43200 0 FJT} + {2076501600 46800 1 FJST} + {2084364000 43200 0 FJT} + {2107951200 46800 1 FJST} + {2115813600 43200 0 FJT} + {2139400800 46800 1 FJST} + {2147868000 43200 0 FJT} + {2171455200 46800 1 FJST} + {2179317600 43200 0 FJT} + {2202904800 46800 1 FJST} + {2210767200 43200 0 FJT} + {2234354400 46800 1 FJST} + {2242216800 43200 0 FJT} + {2265804000 46800 1 FJST} + {2273666400 43200 0 FJT} + {2297253600 46800 1 FJST} + {2305116000 43200 0 FJT} + {2328703200 46800 1 FJST} + {2337170400 43200 0 FJT} + {2360757600 46800 1 FJST} + {2368620000 43200 0 FJT} + {2392207200 46800 1 FJST} + {2400069600 43200 0 FJT} + {2423656800 46800 1 FJST} + {2431519200 43200 0 FJT} + {2455106400 46800 1 FJST} + {2462968800 43200 0 FJT} + {2486556000 46800 1 FJST} + {2495023200 43200 0 FJT} + {2518610400 46800 1 FJST} + {2526472800 43200 0 FJT} + {2550060000 46800 1 FJST} + {2557922400 43200 0 FJT} + {2581509600 46800 1 FJST} + {2589372000 43200 0 FJT} + {2612959200 46800 1 FJST} + {2620821600 43200 0 FJT} + {2644408800 46800 1 FJST} + {2652271200 43200 0 FJT} + {2675858400 46800 1 FJST} + {2684325600 43200 0 FJT} + {2707912800 46800 1 FJST} + {2715775200 43200 0 FJT} + {2739362400 46800 1 FJST} + {2747224800 43200 0 FJT} + {2770812000 46800 1 FJST} + {2778674400 43200 0 FJT} + {2802261600 46800 1 FJST} + {2810124000 43200 0 FJT} + {2833711200 46800 1 FJST} + {2841573600 43200 0 FJT} + {2865765600 46800 1 FJST} + {2873628000 43200 0 FJT} + {2897215200 46800 1 FJST} + {2905077600 43200 0 FJT} + {2928664800 46800 1 FJST} + {2936527200 43200 0 FJT} + {2960114400 46800 1 FJST} + {2967976800 43200 0 FJT} + {2991564000 46800 1 FJST} + {2999426400 43200 0 FJT} + {3023013600 46800 1 FJST} + {3031480800 43200 0 FJT} + {3055068000 46800 1 FJST} + {3062930400 43200 0 FJT} + {3086517600 46800 1 FJST} + {3094380000 43200 0 FJT} + {3117967200 46800 1 FJST} + {3125829600 43200 0 FJT} + {3149416800 46800 1 FJST} + {3157279200 43200 0 FJT} + {3180866400 46800 1 FJST} + {3188728800 43200 0 FJT} + {3212316000 46800 1 FJST} + {3220783200 43200 0 FJT} + {3244370400 46800 1 FJST} + {3252232800 43200 0 FJT} + {3275820000 46800 1 FJST} + {3283682400 43200 0 FJT} + {3307269600 46800 1 FJST} + {3315132000 43200 0 FJT} + {3338719200 46800 1 FJST} + {3346581600 43200 0 FJT} + {3370168800 46800 1 FJST} + {3378636000 43200 0 FJT} + {3402223200 46800 1 FJST} + {3410085600 43200 0 FJT} + {3433672800 46800 1 FJST} + {3441535200 43200 0 FJT} + {3465122400 46800 1 FJST} + {3472984800 43200 0 FJT} + {3496572000 46800 1 FJST} + {3504434400 43200 0 FJT} + {3528021600 46800 1 FJST} + {3535884000 43200 0 FJT} + {3559471200 46800 1 FJST} + {3567938400 43200 0 FJT} + {3591525600 46800 1 FJST} + {3599388000 43200 0 FJT} + {3622975200 46800 1 FJST} + {3630837600 43200 0 FJT} + {3654424800 46800 1 FJST} + {3662287200 43200 0 FJT} + {3685874400 46800 1 FJST} + {3693736800 43200 0 FJT} + {3717324000 46800 1 FJST} + {3725186400 43200 0 FJT} + {3749378400 46800 1 FJST} + {3757240800 43200 0 FJT} + {3780828000 46800 1 FJST} + {3788690400 43200 0 FJT} + {3812277600 46800 1 FJST} + {3820140000 43200 0 FJT} + {3843727200 46800 1 FJST} + {3851589600 43200 0 FJT} + {3875176800 46800 1 FJST} + {3883039200 43200 0 FJT} + {3906626400 46800 1 FJST} + {3915093600 43200 0 FJT} + {3938680800 46800 1 FJST} + {3946543200 43200 0 FJT} + {3970130400 46800 1 FJST} + {3977992800 43200 0 FJT} + {4001580000 46800 1 FJST} + {4009442400 43200 0 FJT} + {4033029600 46800 1 FJST} + {4040892000 43200 0 FJT} + {4064479200 46800 1 FJST} + {4072341600 43200 0 FJT} + {4095928800 46800 1 FJST} } diff --git a/macosx/Tcl.xcode/project.pbxproj b/macosx/Tcl.xcode/project.pbxproj index 6801d54..a2a703b 100644 --- a/macosx/Tcl.xcode/project.pbxproj +++ b/macosx/Tcl.xcode/project.pbxproj @@ -787,7 +787,6 @@ F96D443208F272B8004A47F5 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; }; F96D443308F272B8004A47F5 /* regexpTestLib.tcl */ = {isa = PBXFileReference; explicitFileType = text.script; fileEncoding = 4; path = regexpTestLib.tcl; sourceTree = "<group>"; }; F96D443508F272B8004A47F5 /* tcl.hpj.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = tcl.hpj.in; sourceTree = "<group>"; }; - F96D443608F272B8004A47F5 /* tcl.wse.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = tcl.wse.in; sourceTree = "<group>"; }; F96D443908F272B9004A47F5 /* tcltk-man2html.tcl */ = {isa = PBXFileReference; explicitFileType = text.script; fileEncoding = 4; path = "tcltk-man2html.tcl"; sourceTree = "<group>"; }; F96D443A08F272B9004A47F5 /* tclZIC.tcl */ = {isa = PBXFileReference; explicitFileType = text.script; fileEncoding = 4; path = tclZIC.tcl; sourceTree = "<group>"; }; F96D443B08F272B9004A47F5 /* uniClass.tcl */ = {isa = PBXFileReference; explicitFileType = text.script; fileEncoding = 4; path = uniClass.tcl; sourceTree = "<group>"; }; @@ -1686,7 +1685,6 @@ F96D443208F272B8004A47F5 /* README */, F96D443308F272B8004A47F5 /* regexpTestLib.tcl */, F96D443508F272B8004A47F5 /* tcl.hpj.in */, - F96D443608F272B8004A47F5 /* tcl.wse.in */, F96D443908F272B9004A47F5 /* tcltk-man2html.tcl */, F96D443A08F272B9004A47F5 /* tclZIC.tcl */, F92D7F100DE777240033A13A /* tsdPerf.tcl */, diff --git a/macosx/Tcl.xcodeproj/project.pbxproj b/macosx/Tcl.xcodeproj/project.pbxproj index b37f2e3..9c18ac0 100644 --- a/macosx/Tcl.xcodeproj/project.pbxproj +++ b/macosx/Tcl.xcodeproj/project.pbxproj @@ -787,7 +787,6 @@ F96D443208F272B8004A47F5 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; }; F96D443308F272B8004A47F5 /* regexpTestLib.tcl */ = {isa = PBXFileReference; explicitFileType = text.script; fileEncoding = 4; path = regexpTestLib.tcl; sourceTree = "<group>"; }; F96D443508F272B8004A47F5 /* tcl.hpj.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = tcl.hpj.in; sourceTree = "<group>"; }; - F96D443608F272B8004A47F5 /* tcl.wse.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = tcl.wse.in; sourceTree = "<group>"; }; F96D443908F272B9004A47F5 /* tcltk-man2html.tcl */ = {isa = PBXFileReference; explicitFileType = text.script; fileEncoding = 4; path = "tcltk-man2html.tcl"; sourceTree = "<group>"; }; F96D443A08F272B9004A47F5 /* tclZIC.tcl */ = {isa = PBXFileReference; explicitFileType = text.script; fileEncoding = 4; path = tclZIC.tcl; sourceTree = "<group>"; }; F96D443B08F272B9004A47F5 /* uniClass.tcl */ = {isa = PBXFileReference; explicitFileType = text.script; fileEncoding = 4; path = uniClass.tcl; sourceTree = "<group>"; }; @@ -1686,7 +1685,6 @@ F96D443208F272B8004A47F5 /* README */, F96D443308F272B8004A47F5 /* regexpTestLib.tcl */, F96D443508F272B8004A47F5 /* tcl.hpj.in */, - F96D443608F272B8004A47F5 /* tcl.wse.in */, F96D443908F272B9004A47F5 /* tcltk-man2html.tcl */, F96D443A08F272B9004A47F5 /* tclZIC.tcl */, F92D7F100DE777240033A13A /* tsdPerf.tcl */, diff --git a/macosx/tclMacOSXFCmd.c b/macosx/tclMacOSXFCmd.c index 9193c1a..f266443 100644 --- a/macosx/tclMacOSXFCmd.c +++ b/macosx/tclMacOSXFCmd.c @@ -148,8 +148,9 @@ TclMacOSXGetFileAttribute( result = TclpObjStat(fileName, &statBuf); if (result != 0) { - Tcl_AppendResult(interp, "could not read \"", TclGetString(fileName), - "\": ", Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); return TCL_ERROR; } @@ -159,8 +160,8 @@ TclMacOSXGetFileAttribute( */ errno = EISDIR; - Tcl_AppendResult(interp, "invalid attribute: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "invalid attribute: %s", Tcl_PosixError(interp))); return TCL_ERROR; } @@ -175,8 +176,9 @@ TclMacOSXGetFileAttribute( result = getattrlist(native, &alist, &finfo, sizeof(fileinfobuf), 0); if (result != 0) { - Tcl_AppendResult(interp, "could not read attributes of \"", - TclGetString(fileName), "\": ", Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read attributes of \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); return TCL_ERROR; } @@ -199,10 +201,11 @@ TclMacOSXGetFileAttribute( } return TCL_OK; #else - Tcl_AppendResult(interp, "Mac OS X file attributes not supported", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "Mac OS X file attributes not supported", -1)); Tcl_SetErrorCode(interp, "TCL", "UNSUPPORTED", NULL); return TCL_ERROR; -#endif +#endif /* HAVE_GETATTRLIST */ } /* @@ -241,8 +244,9 @@ TclMacOSXSetFileAttribute( result = TclpObjStat(fileName, &statBuf); if (result != 0) { - Tcl_AppendResult(interp, "could not read \"", TclGetString(fileName), - "\": ", Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); return TCL_ERROR; } @@ -252,8 +256,8 @@ TclMacOSXSetFileAttribute( */ errno = EISDIR; - Tcl_AppendResult(interp, "invalid attribute: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "invalid attribute: %s", Tcl_PosixError(interp))); return TCL_ERROR; } @@ -268,8 +272,9 @@ TclMacOSXSetFileAttribute( result = getattrlist(native, &alist, &finfo, sizeof(fileinfobuf), 0); if (result != 0) { - Tcl_AppendResult(interp, "could not read attributes of \"", - TclGetString(fileName), "\": ", Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read attributes of \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); return TCL_ERROR; } @@ -306,9 +311,9 @@ TclMacOSXSetFileAttribute( &finfo.data, sizeof(finfo.data), 0); if (result != 0) { - Tcl_AppendResult(interp, "could not set attributes of \"", - TclGetString(fileName), "\": ", Tcl_PosixError(interp), - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not set attributes of \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); return TCL_ERROR; } } else { @@ -328,8 +333,8 @@ TclMacOSXSetFileAttribute( */ if (newRsrcForkSize != 0) { - Tcl_AppendResult(interp, - "setting nonzero rsrclength not supported", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "setting nonzero rsrclength not supported", -1)); Tcl_SetErrorCode(interp, "TCL", "UNSUPPORTED", NULL); return TCL_ERROR; } @@ -360,17 +365,17 @@ TclMacOSXSetFileAttribute( Tcl_DStringFree(&ds); if (result != 0) { - Tcl_AppendResult(interp, - "could not truncate resource fork of \"", - TclGetString(fileName), "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not truncate resource fork of \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); return TCL_ERROR; } } } return TCL_OK; #else - Tcl_AppendResult(interp, "Mac OS X file attributes not supported", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "Mac OS X file attributes not supported", -1)); Tcl_SetErrorCode(interp, "TCL", "UNSUPPORTED", NULL); return TCL_ERROR; #endif @@ -640,8 +645,8 @@ SetOSTypeFromAny( if (Tcl_DStringLength(&ds) > 4) { if (interp) { - Tcl_AppendResult(interp, "expected Macintosh OS type but got \"", - string, "\": ", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "expected Macintosh OS type but got \"%s\": ", string)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "MAC_OSTYPE", NULL); } result = TCL_ERROR; diff --git a/pkgs/README b/pkgs/README index e2b33f5..01c6f43 100644 --- a/pkgs/README +++ b/pkgs/README @@ -1 +1,57 @@ -Add notes here about bundling packages with Tcl. + +The 'pkgs' subdirectory of the Tcl source code distribution is meant to be +a place where the source code distribution of Tcl packages may be placed so +that they are built, installed, and tested along with Tcl. As originally +distributed, Tcl re-distributes a number of packages in this location. The +build systems for Tcl are written so that additional packages may be added, +or the original packages removed in any number and still have all packages +present get built, installed, and tested along with Tcl. + +In order for a package to work properly under the pkgs subdirectory, it +needs to conform to the following conventions. + + All files of the package need to be contained in (subdirs of ...) a + single subdirectory of the "pkgs" directrory. + + In that subdirectory of "pkgs" there must be an executable file named + "configure". When the program "configure" is run, it should generate + a file "Makefile" in the current working directory. The "configure" + program should be able to accept as command line arguments all the + arguments that can be passed to the master unix/configure program. It + should also accept the --with-tcl= and --with-tclinclude= options in + the conventional way. + + The generated "Makefile" must be one suitable for controlling the operations + of a `make` program. The following targets must be defined: + + <default>: Perform a build of the runtime components of the + package from sources. + + install: Copy the runtime components of the package into their + installed location. Must respect the DESTDIR variable + for determining the installation location. + + test: Run the test suite of the package. Must respect the + TCLSH_PROG, TESTFLAGS variables. + + clean: Delete all files generated by the default build target. + + distclean: Delete all generated files. + + dist: Produce a copy of the package's source code distribution. + Must respect the DIST_ROOT variable determing where to + write the generated directory. + +Packages that are written to make use of the Tcl Extension Architecture (TEA) +and that make use of the tclconfig collection of support files, should +conform to these conventions without further efforts. + +These conventions are subject to revision and refinement over time to +better support the needs of the build system. Efforts will be made to +keep the TEA support scripts consistent with the demands of this system. + +In addition, it is requested that packages also support building with +Microsoft Visual Studio tools. This means the file win/makefile.vc +should be included, suitable for use by the nmake program, defining the +targets <default>, install, test, and clean. + diff --git a/pkgs/package.list.txt b/pkgs/package.list.txt new file mode 100644 index 0000000..5020506 --- /dev/null +++ b/pkgs/package.list.txt @@ -0,0 +1,21 @@ +# This file contains the mapping of directory names to package names for +# documentation purposes. Each non-blank non-comment line is a two-element +# list that says a possible name of directory (multiple lines may be needed +# because of capitalization issues) and the documentation name of the package +# to match. Pseudo-numeric suffixes are interpreted as version numbers. + +# [incr Tcl] +itcl {[incr Tcl]} +Itcl {[incr Tcl]} + +# SQLite +sqlite SQLite + +# Thread +Thread Thread +thread Thread + +# Tcl Database Connectivity +tdbc TDBC +Tdbc TDBC +TDBC TDBC diff --git a/tests/all.tcl b/tests/all.tcl index 05d3024..715d2e2 100644 --- a/tests/all.tcl +++ b/tests/all.tcl @@ -12,6 +12,7 @@ package prefer latest package require Tcl 8.5 +proc tcl::info::hostname {} {return localhost} package require tcltest 2.2 namespace import tcltest::* configure {*}$argv -testdir [file dir [info script]] diff --git a/tests/assocd.test b/tests/assocd.test index 1ca1c9b..d1489b3 100644 --- a/tests/assocd.test +++ b/tests/assocd.test @@ -16,6 +16,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testgetassocdata [llength [info commands testgetassocdata]] testConstraint testsetassocdata [llength [info commands testsetassocdata]] testConstraint testdelassocdata [llength [info commands testdelassocdata]] diff --git a/tests/async.test b/tests/async.test index 35dda88..cb67cc2 100644 --- a/tests/async.test +++ b/tests/async.test @@ -16,6 +16,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testasync [llength [info commands testasync]] testConstraint threaded [::tcl::pkgconfig get threaded] diff --git a/tests/basic.test b/tests/basic.test index e072bea..7435571 100644 --- a/tests/basic.test +++ b/tests/basic.test @@ -18,6 +18,9 @@ package require tcltest 2 namespace import -force ::tcltest::* +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testevalex [llength [info commands testevalex]] testConstraint testcmdtoken [llength [info commands testcmdtoken]] testConstraint testcreatecommand [llength [info commands testcreatecommand]] diff --git a/tests/chanio.test b/tests/chanio.test index fbc9854..665df50 100644 --- a/tests/chanio.test +++ b/tests/chanio.test @@ -29,6 +29,9 @@ namespace eval ::tcl::test::io { variable msg variable expected + ::tcltest::loadTestedCommands + catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testchannel [llength [info commands testchannel]] testConstraint exec [llength [info commands exec]] testConstraint openpipe 1 @@ -37,7 +40,7 @@ namespace eval ::tcl::test::io { testConstraint testfevent [llength [info commands testfevent]] testConstraint testchannelevent [llength [info commands testchannelevent]] testConstraint testmainthread [llength [info commands testmainthread]] - testConstraint thread [expr {0 == [catch {package require Thread 2.6}]}] + testConstraint thread [expr {0 == [catch {package require Thread 2.7-}]}] # You need a *very* special environment to do some tests. In particular, # many file systems do not support large-files... diff --git a/tests/clock.test b/tests/clock.test index fd74512..0202fc7 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -17,11 +17,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { } if {[testConstraint win]} { - if {[catch {package require registry 1.1}] - && [catch {load {} Registry}] - && [catch { + if {[catch { ::tcltest::loadTestedCommands - load $::reglib Registry + package require registry }]} { namespace eval ::tcl::clock {variable NoRegistry {}} } diff --git a/tests/cmdAH.test b/tests/cmdAH.test index 291df8d..2ecf626 100644 --- a/tests/cmdAH.test +++ b/tests/cmdAH.test @@ -15,6 +15,9 @@ if {"::tcltest" ni [namespace children]} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testchmod [llength [info commands testchmod]] testConstraint testsetplatform [llength [info commands testsetplatform]] testConstraint testvolumetype [llength [info commands testvolumetype]] diff --git a/tests/cmdIL.test b/tests/cmdIL.test index 4b1002a..721773f 100644 --- a/tests/cmdIL.test +++ b/tests/cmdIL.test @@ -13,6 +13,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + # Used for constraining memory leak tests testConstraint memory [llength [info commands memory]] testConstraint testobj [llength [info commands testobj]] @@ -714,6 +717,16 @@ test cmdIL-7.8 {lreverse command - shared intrep [Bug 1675044]} -setup { rename K {} } -result 1 +# This belongs in info test, but adding tests there breaks tests +# that compute source file line numbers. +test info-20.6 {Bug 3587651} -setup { + namespace eval my {namespace eval tcl {namespace eval mathfunc { + proc demo x {return 42} + }}}} -body { namespace eval my {expr {"demo" in [info functions]}}} -cleanup { + namespace delete my +} -result 1 + + # cleanup ::tcltest::cleanupTests return diff --git a/tests/cmdInfo.test b/tests/cmdInfo.test index 86aa6e1..69d7171 100644 --- a/tests/cmdInfo.test +++ b/tests/cmdInfo.test @@ -18,6 +18,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testcmdinfo [llength [info commands testcmdinfo]] testConstraint testcmdtoken [llength [info commands testcmdtoken]] diff --git a/tests/compExpr-old.test b/tests/compExpr-old.test index bb19151..bae26a0 100644 --- a/tests/compExpr-old.test +++ b/tests/compExpr-old.test @@ -17,6 +17,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + if {[catch {expr T1()} msg] && $msg eq {invalid command name "tcl::mathfunc::T1"}} { testConstraint testmathfunctions 0 } else { diff --git a/tests/compExpr.test b/tests/compExpr.test index 8e27f1f..14c875d 100644 --- a/tests/compExpr.test +++ b/tests/compExpr.test @@ -13,6 +13,9 @@ if {"::tcltest" ni [namespace children]} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + if {[catch {expr T1()} msg] && $msg eq {invalid command name "tcl::mathfunc::T1"}} { testConstraint testmathfunctions 0 } else { diff --git a/tests/compile.test b/tests/compile.test index d6048be..4d91940 100644 --- a/tests/compile.test +++ b/tests/compile.test @@ -14,6 +14,9 @@ package require tcltest 2 namespace import -force ::tcltest::* +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint exec [llength [info commands exec]] testConstraint memory [llength [info commands memory]] testConstraint testevalex [llength [info commands testevalex]] diff --git a/tests/coroutine.test b/tests/coroutine.test index 7f40a7b..8272717 100644 --- a/tests/coroutine.test +++ b/tests/coroutine.test @@ -14,6 +14,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testnrelevels [llength [info commands testnrelevels]] testConstraint memory [llength [info commands memory]] diff --git a/tests/dcall.test b/tests/dcall.test index 8977c31..3df0ac8 100644 --- a/tests/dcall.test +++ b/tests/dcall.test @@ -16,6 +16,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testdcall [llength [info commands testdcall]] test dcall-1.1 {deletion callbacks} testdcall { diff --git a/tests/dict.test b/tests/dict.test index 77bacf6..72a336c 100644 --- a/tests/dict.test +++ b/tests/dict.test @@ -78,6 +78,24 @@ test dict-2.7 {dict create command - #-quoting in string rep} { test dict-2.8 {dict create command - #-quoting in string rep} -body { dict create #a x #b x } -match glob -result {{#?} x #? x} +test dict-2.9 {dict create command: compilation} { + apply {{} {dict create [format a] b}} +} {a b} +test dict-2.10 {dict create command: compilation} { + apply {{} {dict create [format a] b c d}} +} {a b c d} +test dict-2.11 {dict create command: compilation} { + apply {{} {dict create [format a] b c d a x}} +} {a x c d} +test dict-2.12 {dict create command: non-compilation} { + dict create [format a] b +} {a b} +test dict-2.13 {dict create command: non-compilation} { + dict create [format a] b c d +} {a b c d} +test dict-2.14 {dict create command: non-compilation} { + dict create [format a] b c d a x +} {a x c d} test dict-3.1 {dict get command} {dict get {a b} a} b test dict-3.2 {dict get command} {dict get {a b c d} a} b @@ -781,6 +799,55 @@ test dict-16.9 {dict unset command: write failure} -setup { } -returnCodes error -cleanup { unset dictVar } -result {can't set "dictVar": variable is array} +# Now test with an LVT present (i.e., the bytecoded version). +test dict-16.10 {dict unset command} -body { + apply {{} { + set dictVar {a b c d} + dict unset dictVar a + }} +} -result {c d} +test dict-16.11 {dict unset command} -body { + apply {{} { + set dictVar {a b c d} + dict unset dictVar c + }} +} -result {a b} +test dict-16.12 {dict unset command} -body { + apply {{} { + set dictVar {a b} + dict unset dictVar c + }} +} -result {a b} +test dict-16.13 {dict unset command} -body { + apply {{} { + set dictVar {a {b c d e}} + dict unset dictVar a b + }} +} -result {a {d e}} +test dict-16.14 {dict unset command} -returnCodes error -body { + apply {{} { + set dictVar a + dict unset dictVar a + }} +} -result {missing value to go with key} +test dict-16.15 {dict unset command} -returnCodes error -body { + apply {{} { + set dictVar {a b} + dict unset dictVar c d + }} +} -result {key "c" not known in dictionary} +test dict-16.16 {dict unset command} -body { + apply {{} {list [info exists dictVar] [dict unset dictVar a] [info exists dictVar]}} +} -result {0 {} 1} +test dict-16.17 {dict unset command} -returnCodes error -body { + apply {{} {dict unset dictVar}} +} -result {wrong # args: should be "dict unset varName key ?key ...?"} +test dict-16.18 {dict unset command: write failure} -body { + apply {{} { + set dictVar(block) {} + dict unset dictVar a + }} +} -returnCodes error -result {can't set "dictVar": variable is array} test dict-17.1 {dict filter command: key} -body { set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo} @@ -1111,6 +1178,36 @@ test dict-20.9 {dict merge command} { test dict-20.10 {dict merge command} { dict merge {a b c d e f} {a x 1 2 3 4} {a - 1 -} } {a - c d e f 1 - 3 4} +test dict-20.11 {dict merge command} { + apply {{} {dict merge}} +} {} +test dict-20.12 {dict merge command} { + apply {{} {dict merge {a b c d e f}}} +} {a b c d e f} +test dict-20.13 {dict merge command} -body { + apply {{} {dict merge {a b c d e}}} +} -result {missing value to go with key} -returnCodes error +test dict-20.14 {dict merge command} { + apply {{} {dict merge {a b c d} {e f g h}}} +} {a b c d e f g h} +test dict-20.15 {dict merge command} -body { + apply {{} {dict merge {a b c d e} {e f g h}}} +} -result {missing value to go with key} -returnCodes error +test dict-20.16 {dict merge command} -body { + apply {{} {dict merge {a b c d} {e f g h i}}} +} -result {missing value to go with key} -returnCodes error +test dict-20.17 {dict merge command} { + apply {{} {dict merge {a b c d e f} {e x g h}}} +} {a b c d e x g h} +test dict-20.18 {dict merge command} { + apply {{} {dict merge {a b c d} {a x c y}}} +} {a x c y} +test dict-20.19 {dict merge command} { + apply {{} {dict merge {a b c d} {c y a x}}} +} {a x c y} +test dict-20.20 {dict merge command} { + apply {{} {dict merge {a b c d e f} {a x 1 2 3 4} {a - 1 -}}} +} {a - c d e f 1 - 3 4} test dict-21.1 {dict update command} -returnCodes 1 -body { dict update @@ -1521,6 +1618,268 @@ j }} [linenumber]}} } 5 rename linenumber {} + +test dict-24.1 {dict map command: syntax} -returnCodes error -body { + dict map +} -result {wrong # args: should be "dict map {keyVar valueVar} dictionary script"} +test dict-24.2 {dict map command: syntax} -returnCodes error -body { + dict map x +} -result {wrong # args: should be "dict map {keyVar valueVar} dictionary script"} +test dict-24.3 {dict map command: syntax} -returnCodes error -body { + dict map x x +} -result {wrong # args: should be "dict map {keyVar valueVar} dictionary script"} +test dict-24.4 {dict map command: syntax} -returnCodes error -body { + dict map x x x x +} -result {wrong # args: should be "dict map {keyVar valueVar} dictionary script"} +test dict-24.5 {dict map command: syntax} -returnCodes error -body { + dict map x x x +} -result {must have exactly two variable names} +test dict-24.6 {dict map command: syntax} -returnCodes error -body { + dict map {x x x} x x +} -result {must have exactly two variable names} +test dict-24.7 {dict map command: syntax} -returnCodes error -body { + dict map "\{x" x x +} -result {unmatched open brace in list} +test dict-24.8 {dict map command} -setup { + set values {} + set keys {} +} -body { + # This test confirms that [dict keys], [dict values] and [dict map] + # all traverse a dictionary in the same order. + set dictv {a A b B c C} + dict map {k v} $dictv { + lappend keys $k + lappend values $v + } + set result [expr { + $keys eq [dict keys $dictv] && $values eq [dict values $dictv] + }] + expr {$result ? "YES" : [list "NO" $dictv $keys $values]} +} -cleanup { + unset result keys values k v dictv +} -result YES +test dict-24.9 {dict map command} { + dict map {k v} {} { + error "unexpected execution of 'dict map' body" + } +} {} +test dict-24.10 {dict map command: script results} -body { + set times 0 + dict map {k v} {a a b b} { + incr times + continue + error "shouldn't get here" + } + return $times +} -cleanup { + unset times k v +} -result 2 +test dict-24.11 {dict map command: script results} -body { + set times 0 + dict map {k v} {a a b b} { + incr times + break + error "shouldn't get here" + } + return $times +} -cleanup { + unset times k v +} -result 1 +test dict-24.12 {dict map command: script results} -body { + set times 0 + list [catch { + dict map {k v} {a a b b} { + incr times + error test + } + } msg] $msg $times $::errorInfo +} -cleanup { + unset times k v msg +} -result {1 test 1 {test + while executing +"error test" + ("dict map" body line 3) + invoked from within +"dict map {k v} {a a b b} { + incr times + error test + }"}} +test dict-24.13 {dict map command: script results} { + apply {{} { + dict map {k v} {a b} { + return ok,$k,$v + error "skipped return completely" + } + error "return didn't go far enough" + }} +} ok,a,b +test dict-24.14 {dict map command: handle representation loss} -setup { + set keys {} + set values {} +} -body { + set dictVar {a b c d e f g h} + list [dict size [dict map {k v} $dictVar { + if {[llength $dictVar]} { + lappend keys $k + lappend values $v + return -level 0 $k + } + }]] [lsort $keys] [lsort $values] +} -cleanup { + unset dictVar keys values k v +} -result {4 {a c e g} {b d f h}} +test dict-24.14a {dict map command: handle representation loss} -body { + apply {{} { + set dictVar {a b c d e f g h} + list [dict size [dict map {k v} $dictVar { + if {[llength $dictVar]} { + lappend keys $k + lappend values $v + return -level 0 $k + } + }]] [lsort $keys] [lsort $values] + }} +} -result {4 {a c e g} {b d f h}} +test dict-24.15 {dict map command: keys are unique and iterated over once only} -setup { + unset -nocomplain accum + array set accum {} +} -body { + set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo} + dict map {k v} $dictVar { + append accum($k) $v, + } + set result [lsort [array names accum]] + lappend result : + foreach k $result { + catch {lappend result $accum($k)} + } + return $result +} -cleanup { + unset dictVar k v result accum +} -result {a1 a2 b1 b2 bar foo : a, b, c, d, foo, bar,} +test dict-24.16 {dict map command in compilation context} { + apply {{} { + set res {x x x x x x} + dict map {k v} {a 0 b 1 c 2 d 3 e 4 f 5} { + lset res $v $k + continue + } + return $res + }} +} {a b c d e f} +test dict-24.17 {dict map command in compilation context} { + # Bug 1379349 (dict for) + apply {{} { + set d [dict create a 1] ;# Dict must be unshared! + dict map {k v} $d { + dict set d $k 0 ;# Any modification will do + } + return $d + }} +} {a 0} +test dict-24.17a {dict map command in compilation context} { + # Bug 1379349 (dict for) + apply {{} { + set d [dict create a 1] ;# Dict must be unshared! + dict map {k v} $d { + dict set d $k 0 ;# Any modification will do + } + }} +} {a {a 0}} +test dict-24.18 {dict map command in compilation context} { + # Bug 1382528 (dict for) + apply {{} { + dict map {k v} {} {} ;# Note empty dict + catch { error foo } ;# Note compiled [catch] + }} +} 1 +test dict-24.19 {dict map and invalid dicts: 'dict for' bug 1531184} -body { + di[list]ct map {k v} x {} +} -returnCodes 1 -result {missing value to go with key} +test dict-24.20 {dict map stack space compilation: 'dict for' bug 1903325} { + apply {{x y args} { + dict map {a b} $x {} + concat "c=$y,$args" + }} {} 1 2 3 +} {c=1,2 3} +proc linenumber {} { + dict get [info frame -1] line +} +test dict-24.20.1 {dict compilation crash: 'dict for' bug 3487626} { + apply {{} {apply {n { + set e {} + set k {} + dict map {a b} {c {d {e {f g}}}} { + ::tcl::dict::map {h i} $b { + dict update i e j { + ::tcl::dict::update j f k { + return [expr {$n - [linenumber]}] + } + } + } + } + }} [linenumber]}} +} 5 +test dict-24.21 {dict compilation crash: 'dict for' bug 3487626} knownBug { + apply {{} {apply {n { + set e {} + set k {} + dict map {a { +b +}} {c {d {e {f g}}}} { + ::tcl::dict::map {h { +i +}} ${ +b +} { + dict update { +i +} e { +j +} { + ::tcl::dict::update { +j +} f k { + return [expr {$n - [linenumber]}] + } + } + } + } + }} [linenumber]}} +} 5 +rename linenumber {} +test dict-24.22 {dict map results (non-compiled)} { + dict map {k v} [dict map {k v} {a 1 b 2 c 3 d 4} { list $v $k }] { + return -level 0 "$k,$v" + } +} {a {a,1 a} b {b,2 b} c {c,3 c} d {d,4 d}} +test dict-24.23 {dict map results (compiled)} { + apply {{} { + dict map {k v} [dict map {k v} {a 1 b 2 c 3 d 4} { list $v $k }] { + return -level 0 "$k,$v" + } + }} +} {a {a,1 a} b {b,2 b} c {c,3 c} d {d,4 d}} +test dict-24.23a {dict map results (compiled)} { + apply {{list} { + dict map {k v} [dict map {k v} $list { list $v $k }] { + return -level 0 "$k,$v" + } + }} {a 1 b 2 c 3 d 4} +} {a {a,1 a} b {b,2 b} c {c,3 c} d {d,4 d}} +test dict-24.24 {dict map with huge dict (non-compiled)} { + tcl::mathop::+ {*}[dict map {k v} [lsearch -all [lrepeat 100000 x] x] { + expr { $k * $v } + }] +} 166666666600000 +test dict-24.25 {dict map with huge dict (compiled)} { + apply {{n} { + tcl::mathop::+ {*}[dict map {k v} [lsearch -all [lrepeat $n y] y] { + expr { $k * $v } + }] + }} 100000 +} 166666666600000 + # cleanup ::tcltest::cleanupTests diff --git a/tests/dstring.test b/tests/dstring.test index bcc304d..06121a3 100644 --- a/tests/dstring.test +++ b/tests/dstring.test @@ -16,6 +16,9 @@ if {"::tcltest" ni [namespace children]} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testdstring [llength [info commands testdstring]] if {[testConstraint testdstring]} { testdstring free diff --git a/tests/encoding.test b/tests/encoding.test index b4ee7c3..0374e2d 100644 --- a/tests/encoding.test +++ b/tests/encoding.test @@ -15,6 +15,11 @@ namespace eval ::tcl::test::encoding { namespace import -force ::tcltest::* +catch { + ::tcltest::loadTestedCommands + package require -exact Tcltest [info patchlevel] +} + proc toutf {args} { variable x lappend x "toutf $args" @@ -31,7 +36,6 @@ proc runtests {} { testConstraint testencoding [llength [info commands testencoding]] testConstraint exec [llength [info commands exec]] testConstraint testgetdefenc [llength [info commands testgetdefenc]] -testConstraint testfinexit [llength [info commands testfinexit]] # TclInitEncodingSubsystem is tested by the rest of this file # TclFinalizeEncodingSubsystem is not currently tested @@ -418,13 +422,14 @@ test encoding-24.1 {EscapeFreeProc on open channels} exec { gets $f } } {} -test encoding-24.2 {EscapeFreeProc on open channels} {exec testfinexit} { +test encoding-24.2 {EscapeFreeProc on open channels} {exec} { # Bug #524674 output viewable [runInSubprocess { encoding system cp1252; # Bug #2891556 crash revelator fconfigure stdout -encoding iso2022-jp puts ab\u4e4e\u68d9g - testfinexit + set env(TCL_FINALIZE_ON_EXIT) 1 + exit }] } "ab\x1b\$B8C\x1b\$(DD%\x1b(Bg (ab\\u001b\$B8C\\u001b\$(DD%\\u001b(Bg)" test encoding-24.3 {EscapeFreeProc on open channels} {stdio} { diff --git a/tests/event.test b/tests/event.test index 0ee7558..0d1b06c 100644 --- a/tests/event.test +++ b/tests/event.test @@ -12,6 +12,13 @@ package require tcltest 2 namespace import -force ::tcltest::* +catch { + ::tcltest::loadTestedCommands + package require -exact Tcltest [info patchlevel] + set ::tcltestlib [lindex [package ifneeded Tcltest [info patchlevel]] 1] +} + + testConstraint testfilehandler [llength [info commands testfilehandler]] testConstraint testexithandler [llength [info commands testexithandler]] testConstraint testfilewait [llength [info commands testfilewait]] @@ -427,6 +434,7 @@ catch {rename bgerror {}} test event-8.1 {Tcl_CreateExitHandler procedure} {stdio testexithandler} { set child [open |[list [interpreter]] r+] + puts $child "catch {load $::tcltestlib Tcltest}" puts $child "testexithandler create 41; testexithandler create 4" puts $child "testexithandler create 6; exit" flush $child @@ -440,6 +448,7 @@ odd 41 test event-9.1 {Tcl_DeleteExitHandler procedure} {stdio testexithandler} { set child [open |[list [interpreter]] r+] + puts $child "catch {load $::tcltestlib Tcltest}" puts $child "testexithandler create 41; testexithandler create 4" puts $child "testexithandler create 6; testexithandler delete 41" puts $child "testexithandler create 16; exit" @@ -453,6 +462,7 @@ even 4 } test event-9.2 {Tcl_DeleteExitHandler procedure} {stdio testexithandler} { set child [open |[list [interpreter]] r+] + puts $child "catch {load $::tcltestlib Tcltest}" puts $child "testexithandler create 41; testexithandler create 4" puts $child "testexithandler create 6; testexithandler delete 4" puts $child "testexithandler create 16; exit" @@ -466,6 +476,7 @@ odd 41 } test event-9.3 {Tcl_DeleteExitHandler procedure} {stdio testexithandler} { set child [open |[list [interpreter]] r+] + puts $child "catch {load $::tcltestlib Tcltest}" puts $child "testexithandler create 41; testexithandler create 4" puts $child "testexithandler create 6; testexithandler delete 6" puts $child "testexithandler create 16; exit" @@ -479,6 +490,7 @@ odd 41 } test event-9.4 {Tcl_DeleteExitHandler procedure} {stdio testexithandler} { set child [open |[list [interpreter]] r+] + puts $child "catch {load $::tcltestlib Tcltest}" puts $child "testexithandler create 41; testexithandler delete 41" puts $child "testexithandler create 16; exit" flush $child diff --git a/tests/execute.test b/tests/execute.test index 012b3a7..94af158 100644 --- a/tests/execute.test +++ b/tests/execute.test @@ -19,6 +19,9 @@ if {"::tcltest" ni [namespace children]} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + catch {namespace delete {*}[namespace children :: test_ns_*]} catch {rename foo ""} catch {unset x} diff --git a/tests/expr-old.test b/tests/expr-old.test index c05a925..4f3cb2e 100644 --- a/tests/expr-old.test +++ b/tests/expr-old.test @@ -18,6 +18,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testexprlong [llength [info commands testexprlong]] testConstraint testexprdouble [llength [info commands testexprdouble]] testConstraint testexprstring [llength [info commands testexprstring]] diff --git a/tests/expr.test b/tests/expr.test index 6679569..6ad7208 100644 --- a/tests/expr.test +++ b/tests/expr.test @@ -15,6 +15,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testmathfunctions [expr { ([catch {expr T1()} msg] != 1) || ($msg ne {invalid command name "tcl::mathfunc::T1"}) }] diff --git a/tests/fCmd.test b/tests/fCmd.test index 72b7da9..325b374 100644 --- a/tests/fCmd.test +++ b/tests/fCmd.test @@ -15,6 +15,9 @@ if {"::tcltest" ni [namespace children]} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + cd [temporaryDirectory] testConstraint testsetplatform [llength [info commands testsetplatform]] diff --git a/tests/fileName.test b/tests/fileName.test index 251f12c..51f00d1 100644 --- a/tests/fileName.test +++ b/tests/fileName.test @@ -15,6 +15,9 @@ if {"::tcltest" ni [namespace children]} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testsetplatform [llength [info commands testsetplatform]] testConstraint testtranslatefilename [llength [info commands testtranslatefilename]] testConstraint linkDirectory 1 @@ -196,7 +199,7 @@ test filename-4.12 {Tcl_SplitPath: unix} {testsetplatform} { test filename-4.13 {Tcl_SplitPath: unix} {testsetplatform} { testsetplatform unix file split //foo -} "[file split //] foo" +} "/ foo" test filename-4.14 {Tcl_SplitPath: unix} {testsetplatform} { testsetplatform unix file split foo//bar @@ -433,11 +436,11 @@ test filename-7.16 {Tcl_JoinPath: unix} {testsetplatform} { test filename-7.17 {Tcl_JoinPath: unix} {testsetplatform} { testsetplatform unix file join //a b -} "[file split //]a/b" +} "/a/b" test filename-7.18 {Tcl_JoinPath: unix} {testsetplatform} { testsetplatform unix file join /// a b -} "[file split //]a/b" +} "/a/b" test filename-9.1 {Tcl_JoinPath: win} {testsetplatform} { testsetplatform win @@ -746,7 +749,7 @@ test filename-11.13 {Tcl_GlobCmd} { } [file join $env(HOME)] set oldpwd [pwd] set oldhome $env(HOME) -cd [temporaryDirectory] +catch {cd [makeDirectory tcl[pid]]} set env(HOME) [pwd] file delete -force globTest file mkdir globTest/a1/b1 @@ -1613,6 +1616,7 @@ catch {file delete -force C:/globTest} cd [temporaryDirectory] file delete -force globTest cd $oldpwd +catch {removeDirectory tcl[pid]} set env(HOME) $oldhome if {[testConstraint testsetplatform]} { testsetplatform $platform diff --git a/tests/fileSystem.test b/tests/fileSystem.test index 64f4d45..b098f35 100644 --- a/tests/fileSystem.test +++ b/tests/fileSystem.test @@ -19,6 +19,17 @@ namespace eval ::tcl::test::fileSystem { file delete -force [file join dir.dir linkinside.file] } +testConstraint loaddll 0 +catch { + ::tcltest::loadTestedCommands + package require -exact Tcltest [info patchlevel] + set ::ddever [package require dde] + set ::ddelib [lindex [package ifneeded dde $::ddever] 1] + set ::regver [package require registry] + set ::reglib [lindex [package ifneeded registry $::regver] 1] + testConstraint loaddll 1 +} + # Test for commands defined in Tcltest executable testConstraint testfilesystem [llength [info commands ::testfilesystem]] testConstraint testsetplatform [llength [info commands ::testsetplatform]] @@ -473,7 +484,7 @@ test filesystem-6.22 {empty file name} {file pathtype ""} relative test filesystem-6.23 {empty file name} {file readable ""} 0 test filesystem-6.24 {empty file name} -returnCodes error -body { file readlink "" -} -result {could not readlink "": no such file or directory} +} -result {could not read link "": no such file or directory} test filesystem-6.25 {empty file name} -returnCodes error -body { file rename "" "" } -result {error renaming "": no such file or directory} @@ -501,13 +512,12 @@ if {[testConstraint testfilesystem]} { test filesystem-7.1.1 {load from vfs} -setup { set dir [pwd] -} -constraints {win testsimplefilesystem} -body { +} -constraints {win testsimplefilesystem loaddll} -body { # This may cause a crash on exit - cd [file dirname [info nameof]] - set dde [lindex [glob *dde*[info sharedlib]] 0] + cd [file dirname $::ddelib] testsimplefilesystem 1 # This loads dde via a complex copy-to-temp operation - load simplefs:/$dde dde + load simplefs:/[file tail $::ddelib] dde testsimplefilesystem 0 return ok # The real result of this test is what happens when Tcl exits. @@ -516,14 +526,13 @@ test filesystem-7.1.1 {load from vfs} -setup { } -result ok test filesystem-7.1.2 {load from vfs, and then unload again} -setup { set dir [pwd] -} -constraints {win testsimplefilesystem} -body { +} -constraints {win testsimplefilesystem loaddll} -body { # This may cause a crash on exit - cd [file dirname [info nameof]] - set reg [lindex [glob tclreg*[info sharedlib]] 0] + cd [file dirname $::reglib] testsimplefilesystem 1 # This loads reg via a complex copy-to-temp operation - load simplefs:/$reg Registry - unload simplefs:/$reg + load simplefs:/[file tail $::reglib] Registry + unload simplefs:/[file tail $::reglib] testsimplefilesystem 0 return ok # The real result of this test is what happens when Tcl exits. diff --git a/tests/foreach.test b/tests/foreach.test index a4b652a..6c69b29 100644 --- a/tests/foreach.test +++ b/tests/foreach.test @@ -266,6 +266,15 @@ test foreach-10.1 {foreach: [Bug 1671087]} -setup { rename demo {} } -result {} +test foreach-11.1 {error then dereference loop var (dev bug)} { + catch { foreach a 0 b {1 2 3} { error x } } + set a +} 0 +test foreach-11.2 {error then dereference loop var (dev bug)} { + catch { foreach a 0 b {1 2 3} { incr a $b; error x } } + set a +} 1 + # cleanup catch {unset a} catch {unset x} diff --git a/tests/format.test b/tests/format.test index 2d53eba..27eac31 100644 --- a/tests/format.test +++ b/tests/format.test @@ -549,10 +549,7 @@ test format-18.2 {do not demote existing numeric values} {wideBiggerThanInt} { list [format %08x $a] [expr {$a == $b}] } {aaaaaaab 1} -test format-19.1 { - regression test - tcl-core message by Brian Griffin on - 26 0ctober 2004 -} -body { +test format-19.1 {regression test - tcl-core message by Brian Griffin on 26 0ctober 2004} -body { set x 0x8fedc654 list [expr { ~ $x }] [format %08x [expr { ~$x }]] } -match regexp -result {-2414724693 f*701239ab} @@ -569,7 +566,7 @@ test format-20.1 {Bug 2932421: plain %s caused intrep change of args} -body { format %s $x # After this, obj in $x should be a dict with a non-NULL bytes field tcl::unsupported::representation $x -} -match glob -result {value is a dict with *, string representation "*".} +} -match glob -result {value is a dict with *, string representation "*"} # cleanup catch {unset a} diff --git a/tests/get.test b/tests/get.test index 40ec98f..d51ec6d 100644 --- a/tests/get.test +++ b/tests/get.test @@ -15,6 +15,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testgetint [llength [info commands testgetint]] testConstraint longIs32bit [expr {int(0x80000000) < 0}] testConstraint longIs64bit [expr {int(0x8000000000000000) < 0}] diff --git a/tests/http.test b/tests/http.test index fe44b47..9861e0e 100644 --- a/tests/http.test +++ b/tests/http.test @@ -51,7 +51,7 @@ if {![file exists $httpdFile]} { set removeHttpd 1 } -catch {package require Thread 2.6} +catch {package require Thread 2.7-} if {[catch {package present Thread}] == 0 && [file exists $httpdFile]} { set httpthread [thread::create -preserved] thread::send $httpthread [list source $httpdFile] @@ -392,11 +392,19 @@ Content-Type {text/plain;charset=utf-8} Accept-Encoding .* Content-Length 5} test http-3.29 "http::geturl $ipv6url" -body { - set token [http::geturl $ipv6url -validate 1] - http::code $token + # We only want to see if the URL gets parsed correctly. This is + # the case if http::geturl succeeds or returns a socket related + # error. If the parsing is wrong, we'll get a parse error. + # It'd be better to separate the URL parser from http::geturl, so + # that it can be tested without also trying to make a connection. + set error [catch {http::geturl $ipv6url -validate 1} token] + if {$error && [string match "couldn't open socket: *" $token]} { + set error 0 + } + set error } -cleanup { - http::cleanup $token -} -result "HTTP/1.0 200 OK" + catch { http::cleanup $token } +} -result 0 test http-4.1 {http::Event} -body { set token [http::geturl $url -keepalive 0] diff --git a/tests/indexObj.test b/tests/indexObj.test index 479cc3b..646cb02 100644 --- a/tests/indexObj.test +++ b/tests/indexObj.test @@ -13,6 +13,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testindexobj [llength [info commands testindexobj]] testConstraint testparseargs [llength [info commands testparseargs]] diff --git a/tests/info.test b/tests/info.test index 3323281..5078e11 100644 --- a/tests/info.test +++ b/tests/info.test @@ -20,6 +20,9 @@ if {{::tcltest} ni [namespace children]} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + # Set up namespaces needed to test operation of "info args", "info body", # "info default", and "info procs" with imported procedures. @@ -231,7 +234,6 @@ test info-6.11 {info default option} { } } {0 {} 1 27} - test info-7.1 {info exists option} -body { set value foo info exists value @@ -731,8 +733,6 @@ proc etrace {} { return $res } -## - test info-22.0 {info frame, levels} {!singleTestInterp} { info frame } 7 @@ -763,7 +763,7 @@ test info-22.7 {info frame, global, absolute} {!singleTestInterp} { } {type source line 761 file info.test cmd test\ info-22.7\ \{info\ frame,\ global,\ absolute\}\ \{!singleTestInter level 0} test info-22.8 {info frame, basic trace} -match glob -body { join [lrange [etrace] 0 2] \n -} -result {* {type source line 728 file info.test cmd {info frame $level} proc ::etrace level 0} +} -result {* {type source line 730 file info.test cmd {info frame $level} proc ::etrace level 0} * {type source line 765 file info.test cmd etrace proc ::tcltest::RunTest} * {type source line * file tcltest* cmd {uplevel 1 $script} proc ::tcltest::RunTest}} unset -nocomplain msg @@ -803,7 +803,7 @@ test info-23.5 {eval'd info frame, dynamic} -cleanup {unset script} -body { test info-23.6 {eval'd info frame, trace} -match glob -cleanup {unset script} -body { set script {etrace} join [lrange [eval $script] 0 2] \n -} -result {* {type source line 728 file info.test cmd {info frame $level} proc ::etrace level 0} +} -result {* {type source line 730 file info.test cmd {info frame $level} proc ::etrace level 0} * {type eval line 1 cmd etrace proc ::tcltest::RunTest} * {type source line 805 file info.test cmd {eval $script} proc ::tcltest::RunTest}} @@ -1318,7 +1318,7 @@ test info-37.0 {eval pure list, single line} -match glob -body { }] eval $cmd return $res -} -result {* {type source line 728 file info.test cmd {info frame $level} proc ::etrace level 0} +} -result {* {type source line 730 file info.test cmd {info frame $level} proc ::etrace level 0} * {type eval line 2 cmd etrace proc ::tcltest::RunTest} * {type eval line 1 cmd foreac proc ::tcltest::RunTest}} -cleanup {unset foo cmd res b c} @@ -1359,7 +1359,7 @@ test info-38.1 {location information for uplevel, dv, direct-var} -match glob -b etrace } join [lrange [uplevel \#0 $script] 0 2] \n -} -result {* {type source line 728 file info.test cmd {info frame $level} proc ::etrace level 0} +} -result {* {type source line 730 file info.test cmd {info frame $level} proc ::etrace level 0} * {type eval line 3 cmd etrace proc ::tcltest::RunTest} * {type source line 1361 file info.test cmd {uplevel \\#0 $script} proc ::tcltest::RunTest}} -cleanup {unset script y} @@ -1378,7 +1378,7 @@ test info-38.3 {location information for uplevel, dpv, direct-proc-var} -match g etrace } join [lrange [control y $script] 0 3] \n -} -result {* {type source line 728 file info.test cmd {info frame $level} proc ::etrace level 0} +} -result {* {type source line 730 file info.test cmd {info frame $level} proc ::etrace level 0} * {type eval line 3 cmd etrace proc ::control} * {type source line 1338 file info.test cmd {uplevel 1 $script} proc ::control} * {type source line 1380 file info.test cmd {control y $script} proc ::tcltest::RunTest}} -cleanup {unset script y} @@ -1395,7 +1395,7 @@ test info-38.3 {location information for uplevel, dpv, direct-proc-var} -match g test info-38.5 {location information for uplevel, ppv, proc-proc-var} -match glob -body { join [lrange [datav] 0 4] \n -} -result {* {type source line 728 file info.test cmd {info frame $level} proc ::etrace level 0} +} -result {* {type source line 730 file info.test cmd {info frame $level} proc ::etrace level 0} * {type eval line 3 cmd etrace proc ::control} * {type source line 1338 file info.test cmd {uplevel 1 $script} proc ::control} * {type source line 1353 file info.test cmd {control y $script} proc ::datav level 1} @@ -1412,7 +1412,7 @@ test info-38.5 {location information for uplevel, ppv, proc-proc-var} -match glo testConstraint testevalex [llength [info commands testevalex]] test info-38.7 {location information for arg substitution} -constraints testevalex -match glob -body { join [lrange [testevalex {return -level 0 [etrace]}] 0 3] \n -} -result {* {type source line 728 file info.test cmd {info frame \$level} proc ::etrace level 0} +} -result {* {type source line 730 file info.test cmd {info frame \$level} proc ::etrace level 0} * {type eval line 1 cmd etrace proc ::tcltest::RunTest} * {type source line 1414 file info.test cmd {testevalex {return -level 0 \[etrace]}} proc ::tcltest::RunTest} * {type source line * file tcltest* cmd {uplevel 1 $script} proc ::tcltest::RunTest}} @@ -1955,6 +1955,12 @@ test info-38.2 {location information for uplevel, dl, direct-literal} -match glo * {type source line 1951 file info.test cmd etrace level 1} * {type source line 1949 file info.test cmd uplevel\\ \\\\ level 1}} -cleanup {interp delete sub} +# This test at the end of this file _only_ to avoid disturbing above line +# numbers. It _belongs_ after info-9.12 +test info-9.13 {info level option, value in global context} -body { + uplevel #0 {info level 2} +} -returnCodes error -result {bad level "2"} + # ------------------------------------------------------------------------- unset -nocomplain res diff --git a/tests/interp.test b/tests/interp.test index ab91f77..0af9887 100644 --- a/tests/interp.test +++ b/tests/interp.test @@ -15,6 +15,9 @@ if {"::tcltest" ni [namespace children]} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testinterpdelete [llength [info commands testinterpdelete]] set hidden_cmds {cd encoding exec exit fconfigure file glob load open pwd socket source tcl:file:atime tcl:file:attributes tcl:file:copy tcl:file:delete tcl:file:dirname tcl:file:executable tcl:file:exists tcl:file:extension tcl:file:isdirectory tcl:file:isfile tcl:file:link tcl:file:lstat tcl:file:mkdir tcl:file:mtime tcl:file:nativename tcl:file:normalize tcl:file:owned tcl:file:readable tcl:file:readlink tcl:file:rename tcl:file:rootname tcl:file:size tcl:file:stat tcl:file:tail tcl:file:tempfile tcl:file:type tcl:file:volumes tcl:file:writable unload} diff --git a/tests/io.test b/tests/io.test index f3c39f4..0688c14 100644 --- a/tests/io.test +++ b/tests/io.test @@ -17,6 +17,10 @@ if {[catch {package require tcltest 2}]} { puts stderr "Skipping tests in [info script]. tcltest 2 required." return } + +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + namespace eval ::tcl::test::io { namespace import ::tcltest::* @@ -37,7 +41,7 @@ testConstraint fcopy [llength [info commands fcopy]] testConstraint testfevent [llength [info commands testfevent]] testConstraint testchannelevent [llength [info commands testchannelevent]] testConstraint testmainthread [llength [info commands testmainthread]] -testConstraint thread [expr {0 == [catch {package require Thread 2.6}]}] +testConstraint thread [expr {0 == [catch {package require Thread 2.7-}]}] # You need a *very* special environment to do some tests. In # particular, many file systems do not support large-files... diff --git a/tests/ioCmd.test b/tests/ioCmd.test index cf913ff..03242be 100644 --- a/tests/ioCmd.test +++ b/tests/ioCmd.test @@ -18,10 +18,13 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + # Custom constraints used in this file testConstraint fcopy [llength [info commands fcopy]] testConstraint testchannel [llength [info commands testchannel]] -testConstraint thread [expr {0 == [catch {package require Thread 2.6}]}] +testConstraint thread [expr {0 == [catch {package require Thread 2.7-}]}] #---------------------------------------------------------------------- diff --git a/tests/ioTrans.test b/tests/ioTrans.test index 7da4329..5a8874c 100644 --- a/tests/ioTrans.test +++ b/tests/ioTrans.test @@ -16,9 +16,12 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + # Custom constraints used in this file testConstraint testchannel [llength [info commands testchannel]] -testConstraint thread [expr {0 == [catch {package require Thread 2.6}]}] +testConstraint thread [expr {0 == [catch {package require Thread 2.7-}]}] # testchannel cut|splice Both needed to test the reflection in threads. # thread::send @@ -280,6 +283,8 @@ test iortrans-3.1 {chan finalize, handler destruction has no effect on channel} lappend res [catch {close $c} msg] $msg lappend res [file channels file*] lappend res [file channels rt*] +} -cleanup { + tempdone } -result {{initialize rt* {read write}} file* file* {} 1 {invalid command name "foo"} {} {}} test iortrans-3.2 {chan finalize, for close} -setup { set res {} @@ -297,6 +302,7 @@ test iortrans-3.2 {chan finalize, for close} -setup { lappend res [info command foo] } -cleanup { rename foo {} + tempdone } -result {{initialize rt* {read write}} file* {finalize rt*} {} foo} test iortrans-3.3 {chan finalize, for close, error, close error} -setup { set res {} @@ -312,6 +318,7 @@ test iortrans-3.3 {chan finalize, for close, error, close error} -setup { lappend res [file channels rt*] } -cleanup { rename foo {} + tempdone } -result {{initialize rt* {read write}} file* {finalize rt*} 1 5 {}} test iortrans-3.4 {chan finalize, for close, error, close error} -setup { set res {} @@ -325,6 +332,7 @@ test iortrans-3.4 {chan finalize, for close, error, close error} -setup { lappend res [catch {close $c} msg] $msg $::errorInfo } -cleanup { rename foo {} + tempdone } -result {{initialize rt* {read write}} file* {finalize rt*} 1 FOO {FOO *"close $c"}} test iortrans-3.5 {chan finalize, for close, arbitrary result, ignored} -setup { @@ -339,6 +347,7 @@ test iortrans-3.5 {chan finalize, for close, arbitrary result, ignored} -setup { lappend res [catch {close $c} msg] $msg } -cleanup { rename foo {} + tempdone } -result {{initialize rt* {read write}} file* {finalize rt*} 0 {}} test iortrans-3.6 {chan finalize, for close, break, close error} -setup { set res {} @@ -352,6 +361,7 @@ test iortrans-3.6 {chan finalize, for close, break, close error} -setup { lappend res [catch {close $c} msg] $msg } -cleanup { rename foo {} + tempdone } -result {{initialize rt* {read write}} file* {finalize rt*} 1 *bad code*} test iortrans-3.7 {chan finalize, for close, continue, close error} -setup { set res {} @@ -365,6 +375,7 @@ test iortrans-3.7 {chan finalize, for close, continue, close error} -setup { lappend res [catch {close $c} msg] $msg } -cleanup { rename foo {} + tempdone } -result {{initialize rt* {read write}} file* {finalize rt*} 1 *bad code*} test iortrans-3.8 {chan finalize, for close, custom code, close error} -setup { set res {} @@ -378,6 +389,7 @@ test iortrans-3.8 {chan finalize, for close, custom code, close error} -setup { lappend res [catch {close $c} msg] $msg } -cleanup { rename foo {} + tempdone } -result {{initialize rt* {read write}} file* {finalize rt*} 1 *bad code*} test iortrans-3.9 {chan finalize, for close, ignore level, close error} -setup { set res {} @@ -392,6 +404,7 @@ test iortrans-3.9 {chan finalize, for close, ignore level, close error} -setup { noteOpts $opt } -match glob -cleanup { rename foo {} + tempdone } -result {{initialize rt* {read write}} file* {finalize rt*} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "finalize"*}} # --- === *** ########################### @@ -1033,6 +1046,8 @@ test iortrans-11.2 {delete interp of reflected transform} -setup { chan event $c readable no-op } interp delete slave +} -cleanup { + tempdone } -result {} # ### ### ### ######### ######### ######### diff --git a/tests/iogt.test b/tests/iogt.test index 60d7ab8..d4c31d2 100644 --- a/tests/iogt.test +++ b/tests/iogt.test @@ -14,6 +14,10 @@ if {[catch {package require tcltest 2.1}]} { puts stderr "Skipping tests in [info script]. tcltest 2.1 required." return } + +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + namespace eval ::tcl::test::iogt { namespace import ::tcltest::* diff --git a/tests/lindex.test b/tests/lindex.test index 07abff8..b86e2e0 100644 --- a/tests/lindex.test +++ b/tests/lindex.test @@ -17,6 +17,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + set minus - testConstraint testevalex [llength [info commands testevalex]] diff --git a/tests/link.test b/tests/link.test index 60d0799..00e490c 100644 --- a/tests/link.test +++ b/tests/link.test @@ -16,6 +16,9 @@ if {"::tcltest" ni [namespace children]} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testlink [llength [info commands testlink]] foreach i {int real bool string} { diff --git a/tests/listObj.test b/tests/listObj.test index 53017b1..8b24aa9 100644 --- a/tests/listObj.test +++ b/tests/listObj.test @@ -16,6 +16,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testobj [llength [info commands testobj]] catch {unset x} diff --git a/tests/lmap.test b/tests/lmap.test new file mode 100644 index 0000000..7baa77b --- /dev/null +++ b/tests/lmap.test @@ -0,0 +1,464 @@ +# Commands covered: lmap, continue, break +# +# This file contains a collection of tests for one or more of the Tcl +# built-in commands. Sourcing this file into Tcl runs the tests and +# generates output for errors. No output means no errors were found. +# +# Copyright (c) 1991-1993 The Regents of the University of California. +# Copyright (c) 1994-1997 Sun Microsystems, Inc. +# Copyright (c) 2011 Trevor Davel +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# +# RCS: @(#) $Id: $ + +if {"::tcltest" ni [namespace children]} { + package require tcltest 2 + namespace import -force ::tcltest::* +} + +unset -nocomplain a i x + +# ----- Non-compiled operation ----------------------------------------------- + +# Basic "lmap" operation (non-compiled) +test lmap-1.1 {basic lmap tests} { + set a {} + lmap i {a b c d} { + set a [concat $a $i] + } +} {a {a b} {a b c} {a b c d}} +test lmap-1.2 {basic lmap tests} { + lmap i {a b {{c d} e} {123 {{x}}}} { + set i + } +} {a b {{c d} e} {123 {{x}}}} +test lmap-1.2a {basic lmap tests} { + lmap i {a b {{c d} e} {123 {{x}}}} { + return -level 0 $i + } +} {a b {{c d} e} {123 {{x}}}} +test lmap-1.4 {basic lmap tests} -returnCodes error -body { + lmap +} -result {wrong # args: should be "lmap varList list ?varList list ...? command"} +test lmap-1.6 {basic lmap tests} -returnCodes error -body { + lmap i +} -result {wrong # args: should be "lmap varList list ?varList list ...? command"} +test lmap-1.8 {basic lmap tests} -returnCodes error -body { + lmap i j +} -result {wrong # args: should be "lmap varList list ?varList list ...? command"} +test lmap-1.10 {basic lmap tests} -returnCodes error -body { + lmap i j k l +} -result {wrong # args: should be "lmap varList list ?varList list ...? command"} +test lmap-1.11 {basic lmap tests} { + lmap i {} { + set i + } +} {} +test lmap-1.12 {basic lmap tests} { + lmap i {} { + return -level 0 x + } +} {} +test lmap-1.13 {lmap errors} -returnCodes error -body { + lmap {{a}{b}} {1 2 3} {} +} -result {list element in braces followed by "{b}" instead of space} +test lmap-1.14 {lmap errors} -returnCodes error -body { + lmap a {{1 2}3} {} +} -result {list element in braces followed by "3" instead of space} +unset -nocomplain a +test lmap-1.15 {lmap errors} -setup { + unset -nocomplain a +} -body { + set a(0) 44 + list [catch {lmap a {1 2 3} {}} msg o] $msg $::errorInfo +} -result {1 {can't set "a": variable is array} {can't set "a": variable is array + (setting lmap loop variable "a") + invoked from within +"lmap a {1 2 3} {}"}} +test lmap-1.16 {lmap errors} -returnCodes error -body { + lmap {} {} {} +} -result {lmap varlist is empty} +unset -nocomplain a + +# Parallel "lmap" operation (non-compiled) +test lmap-2.1 {parallel lmap tests} { + lmap {a b} {1 2 3 4} { + list $b $a + } +} {{2 1} {4 3}} +test lmap-2.2 {parallel lmap tests} { + lmap {a b} {1 2 3 4 5} { + list $b $a + } +} {{2 1} {4 3} {{} 5}} +test lmap-2.3 {parallel lmap tests} { + lmap a {1 2 3} b {4 5 6} { + list $b $a + } +} {{4 1} {5 2} {6 3}} +test lmap-2.4 {parallel lmap tests} { + lmap a {1 2 3} b {4 5 6 7 8} { + list $b $a + } +} {{4 1} {5 2} {6 3} {7 {}} {8 {}}} +test lmap-2.5 {parallel lmap tests} { + lmap {a b} {a b A B aa bb} c {c C cc CC} { + list $a $b $c + } +} {{a b c} {A B C} {aa bb cc} {{} {} CC}} +test lmap-2.6 {parallel lmap tests} { + lmap a {1 2 3} b {1 2 3} c {1 2 3} d {1 2 3} e {1 2 3} { + list $a$b$c$d$e + } +} {11111 22222 33333} +test lmap-2.7 {parallel lmap tests} { + lmap a {} b {1 2 3} c {1 2} d {1 2 3 4} e {{1 2}} { + set x $a$b$c$d$e + } +} {{1111 2} 222 33 4} +test lmap-2.8 {parallel lmap tests} { + lmap a {} b {1 2 3} c {1 2} d {1 2 3 4} e {{1 2}} { + join [list $a $b $c $d $e] . + } +} {{.1.1.1.1 2} .2.2.2. .3..3. ...4.} +test lmap-2.9 {lmap only sets vars if repeating loop} { + namespace eval ::lmap_test { + set rgb {65535 0 0} + lmap {r g b} [set rgb] {} + set ::x "r=$r, g=$g, b=$b" + } + namespace delete ::lmap_test + set x +} {r=65535, g=0, b=0} +test lmap-2.10 {lmap only supports local scalar variables} -setup { + unset -nocomplain a +} -body { + lmap {a(3)} {1 2 3 4} {set {a(3)}} +} -result {1 2 3 4} +unset -nocomplain a + +# "lmap" with "continue" and "break" (non-compiled) +test lmap-3.1 {continue tests} { + lmap i {a b c d} { + if {[string compare $i "b"] == 0} continue + set i + } +} {a c d} +test lmap-3.2 {continue tests} { + set x 0 + list [lmap i {a b c d} { + incr x + if {[string compare $i "b"] != 0} continue + set i + }] $x +} {b 4} +test lmap-3.3 {break tests} { + set x 0 + list [lmap i {a b c d} { + incr x + if {[string compare $i "c"] == 0} break + set i + }] $x +} {{a b} 3} +# Check for bug similar to #406709 +test lmap-3.4 {break tests} { + set a 1 + lmap b b {list [concat a; break]; incr a} + incr a +} {2} + +# ----- Compiled operation --------------------------------------------------- + +# Basic "lmap" operation (compiled) +test lmap-4.1 {basic lmap tests} { + apply {{} { + set a {} + lmap i {a b c d} { + set a [concat $a $i] + } + }} +} {a {a b} {a b c} {a b c d}} +test lmap-4.2 {basic lmap tests} { + apply {{} { + lmap i {a b {{c d} e} {123 {{x}}}} { + set i + } + }} +} {a b {{c d} e} {123 {{x}}}} +test lmap-4.2a {basic lmap tests} { + apply {{} { + lmap i {a b {{c d} e} {123 {{x}}}} { + return -level 0 $i + } + }} +} {a b {{c d} e} {123 {{x}}}} +test lmap-4.4 {basic lmap tests} -returnCodes error -body { + apply {{} { lmap }} +} -result {wrong # args: should be "lmap varList list ?varList list ...? command"} +test lmap-4.6 {basic lmap tests} -returnCodes error -body { + apply {{} { lmap i }} +} -result {wrong # args: should be "lmap varList list ?varList list ...? command"} +test lmap-4.8 {basic lmap tests} -returnCodes error -body { + apply {{} { lmap i j }} +} -result {wrong # args: should be "lmap varList list ?varList list ...? command"} +test lmap-4.10 {basic lmap tests} -returnCodes error -body { + apply {{} { lmap i j k l }} +} -result {wrong # args: should be "lmap varList list ?varList list ...? command"} +test lmap-4.11 {basic lmap tests} { + apply {{} { lmap i {} { set i } }} +} {} +test lmap-4.12 {basic lmap tests} { + apply {{} { lmap i {} { return -level 0 x } }} +} {} +test lmap-4.13 {lmap errors} -returnCodes error -body { + apply {{} { lmap {{a}{b}} {1 2 3} {} }} +} -result {list element in braces followed by "{b}" instead of space} +test lmap-4.14 {lmap errors} -returnCodes error -body { + apply {{} { lmap a {{1 2}3} {} }} +} -result {list element in braces followed by "3" instead of space} +unset -nocomplain a +test lmap-4.15 {lmap errors} { + apply {{} { + set a(0) 44 + list [catch {lmap a {1 2 3} {}} msg o] $msg $::errorInfo + }} +} {1 {can't set "a": variable is array} {can't set "a": variable is array + while executing +"lmap a {1 2 3} {}"}} +test lmap-4.16 {lmap errors} -returnCodes error -body { + apply {{} { + lmap {} {} {} + }} +} -result {lmap varlist is empty} +unset -nocomplain a + +# Parallel "lmap" operation (compiled) +test lmap-5.1 {parallel lmap tests} { + apply {{} { + lmap {a b} {1 2 3 4} { + list $b $a + } + }} +} {{2 1} {4 3}} +test lmap-5.2 {parallel lmap tests} { + apply {{} { + lmap {a b} {1 2 3 4 5} { + list $b $a + } + }} +} {{2 1} {4 3} {{} 5}} +test lmap-5.3 {parallel lmap tests} { + apply {{} { + lmap a {1 2 3} b {4 5 6} { + list $b $a + } + }} +} {{4 1} {5 2} {6 3}} +test lmap-5.4 {parallel lmap tests} { + apply {{} { + lmap a {1 2 3} b {4 5 6 7 8} { + list $b $a + } + }} +} {{4 1} {5 2} {6 3} {7 {}} {8 {}}} +test lmap-5.5 {parallel lmap tests} { + apply {{} { + lmap {a b} {a b A B aa bb} c {c C cc CC} { + list $a $b $c + } + }} +} {{a b c} {A B C} {aa bb cc} {{} {} CC}} +test lmap-5.6 {parallel lmap tests} { + apply {{} { + lmap a {1 2 3} b {1 2 3} c {1 2 3} d {1 2 3} e {1 2 3} { + list $a$b$c$d$e + } + }} +} {11111 22222 33333} +test lmap-5.7 {parallel lmap tests} { + apply {{} { + lmap a {} b {1 2 3} c {1 2} d {1 2 3 4} e {{1 2}} { + set x $a$b$c$d$e + } + }} +} {{1111 2} 222 33 4} +test lmap-5.8 {parallel lmap tests} { + apply {{} { + lmap a {} b {1 2 3} c {1 2} d {1 2 3 4} e {{1 2}} { + join [list $a $b $c $d $e] . + } + }} +} {{.1.1.1.1 2} .2.2.2. .3..3. ...4.} +test lmap-5.9 {lmap only sets vars if repeating loop} { + apply {{} { + set rgb {65535 0 0} + lmap {r g b} [set rgb] {} + return "r=$r, g=$g, b=$b" + }} +} {r=65535, g=0, b=0} +test lmap-5.10 {lmap only supports local scalar variables} { + apply {{} { + lmap {a(3)} {1 2 3 4} {set {a(3)}} + }} +} {1 2 3 4} + +# "lmap" with "continue" and "break" (compiled) +test lmap-6.1 {continue tests} { + apply {{} { + lmap i {a b c d} { + if {[string compare $i "b"] == 0} continue + set i + } + }} +} {a c d} +test lmap-6.2 {continue tests} { + apply {{} { + list [lmap i {a b c d} { + incr x + if {[string compare $i "b"] != 0} continue + set i + }] $x + }} +} {b 4} +test lmap-6.3 {break tests} { + apply {{} { + list [lmap i {a b c d} { + incr x + if {[string compare $i "c"] == 0} break + set i + }] $x + }} +} {{a b} 3} +# Check for bug similar to #406709 +test lmap-6.4 {break tests} { + apply {{} { + set a 1 + lmap b b {list [concat a; break]; incr a} + incr a + }} +} {2} + +# ----- Special cases and bugs ----------------------------------------------- +test lmap-7.1 {compiled lmap backward jump works correctly} -setup { + unset -nocomplain x +} -body { + array set x {0 zero 1 one 2 two 3 three} + lsort [apply {{arrayName} { + upvar 1 $arrayName a + lmap member [array names a] { + list $member [set a($member)] + } + }} x] +} -result [lsort {{0 zero} {1 one} {2 two} {3 three}}] +test lmap-7.2 {noncompiled lmap and shared variable or value list objects that are converted to another type} -setup { + unset -nocomplain x +} -body { + lmap {12.0} {a b c} { + set x 12.0 + set x [expr $x + 1] + } +} -result {13.0 13.0 13.0} +# Test for incorrect "double evaluation" semantics +test lmap-7.3 {delayed substitution of body} { + apply {{} { + set a 0 + lmap a [list 1 2 3] " + set x $a + " + return $x + }} +} {0} +# Related to "foreach" test for [Bug 1189274]; crash on failure +test lmap-7.4 {empty list handling} { + proc crash {} { + rename crash {} + set a "x y z" + set b "" + lmap aa $a bb $b { set x "aa = $aa bb = $bb" } + } + crash +} {{aa = x bb = } {aa = y bb = } {aa = z bb = }} +# Related to [Bug 1671138]; infinite loop with empty var list in bytecompiled +# version. +test lmap-7.5 {compiled empty var list} -returnCodes error -body { + proc foo {} { + lmap {} x { + error "reached body" + } + } + foo +} -cleanup { + catch {rename foo ""} +} -result {lmap varlist is empty} +test lmap-7.6 {lmap: related to "foreach" [Bug 1671087]} -setup { + proc demo {} { + set vals {1 2 3 4} + trace add variable x write {string length $vals ;# } + lmap {x y} $vals {format $y} + } +} -body { + demo +} -cleanup { + rename demo {} +} -result {2 4} +# Huge lists must not overflow the bytecode interpreter (development bug) +test lmap-7.7 {huge list non-compiled} { + set x [lmap a [lrepeat 1000000 x] { set b y$a }] + list $b [llength $x] [string length $x] +} {yx 1000000 2999999} +test lmap-7.8 {huge list compiled} { + set x [apply {{times} { lmap a [lrepeat $times x] { set b y$a }}} 1000000] + list $b [llength $x] [string length $x] +} {yx 1000000 2999999} +test lmap-7.9 {error then dereference loop var (dev bug)} { + catch { lmap a 0 b {1 2 3} { error x } } + set a +} 0 +test lmap-7.9a {error then dereference loop var (dev bug)} { + catch { lmap a 0 b {1 2 3} { incr a $b; error x } } + set a +} 1 + +# ----- Coroutines ----------------------------------------------------------- +test lmap-8.1 {lmap non-compiled with coroutines} -body { + coroutine coro apply {{} { + set values [yield [info coroutine]] + eval lmap i [list $values] {{ yield $i }} + }} ;# returns 'coro' + coro {a b c d e f} ;# -> a + coro 1 ;# -> b + coro 2 ;# -> c + coro 3 ;# -> d + coro 4 ;# -> e + coro 5 ;# -> f + list [coro 6] [info commands coro] +} -cleanup { + catch {rename coro ""} +} -result {{1 2 3 4 5 6} {}} +test lmap-8.2 {lmap compiled with coroutines} -body { + coroutine coro apply {{} { + set values [yield [info coroutine]] + lmap i $values { yield $i } + }} ;# returns 'coro' + coro {a b c d e f} ;# -> a + coro 1 ;# -> b + coro 2 ;# -> c + coro 3 ;# -> d + coro 4 ;# -> e + coro 5 ;# -> f + list [coro 6] [info commands coro] +} -cleanup { + catch {rename coro ""} +} -result {{1 2 3 4 5 6} {}} + +# cleanup +unset -nocomplain a x +catch {rename foo {}} +::tcltest::cleanupTests +return + +# Local Variables: +# mode: tcl +# End: diff --git a/tests/load.test b/tests/load.test index b7c1a59..eef677f 100644 --- a/tests/load.test +++ b/tests/load.test @@ -15,6 +15,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + # Figure out what extension is used for shared libraries on this # platform. if {![info exists ext]} { @@ -44,32 +47,38 @@ testConstraint testsimplefilesystem \ test load-1.1 {basic errors} {} { list [catch {load} msg] $msg -} "1 {wrong \# args: should be \"load fileName ?packageName? ?interp?\"}" +} "1 {wrong \# args: should be \"load ?-global? ?-lazy? ?--? fileName ?packageName? ?interp?\"}" test load-1.2 {basic errors} {} { list [catch {load a b c d} msg] $msg -} "1 {wrong \# args: should be \"load fileName ?packageName? ?interp?\"}" +} "1 {wrong \# args: should be \"load ?-global? ?-lazy? ?--? fileName ?packageName? ?interp?\"}" test load-1.3 {basic errors} {} { list [catch {load a b foobar} msg] $msg } {1 {could not find interpreter "foobar"}} test load-1.4 {basic errors} {} { - list [catch {load {}} msg] $msg + list [catch {load -global {}} msg] $msg } {1 {must specify either file name or package name}} test load-1.5 {basic errors} {} { - list [catch {load {} {}} msg] $msg + list [catch {load -lazy {} {}} msg] $msg } {1 {must specify either file name or package name}} test load-1.6 {basic errors} {} { list [catch {load {} Unknown} msg] $msg } {1 {package "Unknown" isn't loaded statically}} +test load-1.7 {basic errors} {} { + list [catch {load -abc foo} msg] $msg +} "1 {bad option \"-abc\": must be -global, -lazy, or --}" +test load-1.8 {basic errors} {} { + list [catch {load -global} msg] $msg +} "1 {couldn't figure out package name for -global}" test load-2.1 {basic loading, with guess for package name} \ [list $dll $loaded] { - load [file join $testDir pkga$ext] + load -global [file join $testDir pkga$ext] list [pkga_eq abc def] [lsort [info commands pkga_*]] } {0 {pkga_eq pkga_quote}} interp create -safe child test load-2.2 {loading into a safe interpreter, with package name conversion} \ [list $dll $loaded] { - load [file join $testDir pkgb$ext] pKgB child + load -lazy [file join $testDir pkgb$ext] pKgB child list [child eval pkgb_sub 44 13] [catch {child eval pkgb_unsafe} msg] $msg \ [catch {pkgb_sub 12 10} msg2] $msg2 } {31 1 {invalid command name "pkgb_unsafe"} 1 {invalid command name "pkgb_sub"}} @@ -123,7 +132,7 @@ test load-5.1 {file name not specified and no static package: pick default} \ [list $dll $loaded] { catch {interp delete x} interp create x - load [file join $testDir pkga$ext] pkga + load -global [file join $testDir pkga$ext] pkga load {} pkga x set result [info loaded x] interp delete x @@ -197,7 +206,7 @@ test load-9.1 {Tcl_StaticPackage, load already-loaded package into another inter [child1 eval { info loaded {} }] \ [child2 eval { info loaded {} }] } \ - -result {{{{} Loadninepointone} {{} Tcltest}} {{{} Loadninepointone} {{} Tcltest}}} \ + -match glob -result {{{{} Loadninepointone} {* Tcltest}} {{{} Loadninepointone} {* Tcltest}}} \ -cleanup { interp delete child1 ; interp delete child2 } test load-10.1 {load from vfs} \ diff --git a/tests/lset.test b/tests/lset.test index 3f4914d..1c1300b 100644 --- a/tests/lset.test +++ b/tests/lset.test @@ -16,6 +16,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + proc failTrace {name1 name2 op} { error "trace failed" } diff --git a/tests/misc.test b/tests/misc.test index fe19ebe..6ddc718 100644 --- a/tests/misc.test +++ b/tests/misc.test @@ -17,6 +17,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testhashsystemhash [llength [info commands testhashsystemhash]] test misc-1.1 {error in variable ref. in command in array reference} { diff --git a/tests/msgcat.test b/tests/msgcat.test index bbcd023..1522354 100644 --- a/tests/msgcat.test +++ b/tests/msgcat.test @@ -17,8 +17,8 @@ if {[catch {package require tcltest 2}]} { puts stderr "Skipping tests in [info script]. tcltest 2 required." return } -if {[catch {package require msgcat 1.4.5}]} { - puts stderr "Skipping tests in [info script]. No msgcat 1.4.5 found to test." +if {[catch {package require msgcat 1.5.0}]} { + puts stderr "Skipping tests in [info script]. No msgcat 1.5.0 found to test." return } @@ -56,6 +56,13 @@ namespace eval ::msgcat::test { set result [string tolower \ [msgcat::ConvertLocale $::tcl::mac::locale]] } else { + if {([info sharedlibextension] == ".dll") + && ![catch {package require registry}]} { + # Windows and Cygwin have other ways to determine the + # locale when the environment variables are missing + # and the registry package is present + continue + } set result c } } @@ -611,6 +618,45 @@ namespace eval ::msgcat::test { mc "this is a %s" "good test" } -result "this is a good test" + # Tests msgcat-8.*: [mcflset] + + set msgdir1 [makeDirectory msgdir1] + makeFile {::msgcat::mcflset k1 v1} l1.msg $msgdir1 + + test msgcat-8.1 {mcflset} -setup { + variable locale [mclocale] + mclocale l1 + mcload $msgdir1 + } -cleanup { + mclocale $locale + } -body { + mc k1 + } -result v1 + + removeFile l1.msg $msgdir1 + removeDirectory msgdir1 + + set msgdir2 [makeDirectory msgdir2] + set msgdir3 [makeDirectory msgdir3] + makeFile "::msgcat::mcflset k2 v2 ; ::msgcat::mcload [list $msgdir3]"\ + l2.msg $msgdir2 + makeFile {::msgcat::mcflset k3 v3} l2.msg $msgdir3 + + # chained mcload + test msgcat-8.2 {mcflset} -setup { + variable locale [mclocale] + mclocale l2 + mcload $msgdir2 + } -cleanup { + mclocale $locale + } -body { + return [mc k2][mc k3] + } -result v2v3 + + removeFile l2.msg $msgdir2 + removeDirectory msgdir2 + removeDirectory msgdir3 + cleanupTests } namespace delete ::msgcat::test diff --git a/tests/namespace.test b/tests/namespace.test index f07d8cf..1d46bf0 100644 --- a/tests/namespace.test +++ b/tests/namespace.test @@ -16,6 +16,9 @@ package require tcltest 2 namespace import -force ::tcltest::* testConstraint memory [llength [info commands memory]] +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + # # REMARK: the tests for 'namespace upvar' are not done here. They are to be # found in the file 'upvar.test'. diff --git a/tests/notify.test b/tests/notify.test index ba52c50..d2b9123 100755 --- a/tests/notify.test +++ b/tests/notify.test @@ -18,6 +18,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testevent [llength [info commands testevent]] test notify-1.1 {Tcl_QueueEvent and delivery of a single event} \ diff --git a/tests/nre.test b/tests/nre.test index 295f02e..b8ef2e0 100644 --- a/tests/nre.test +++ b/tests/nre.test @@ -14,6 +14,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testnrelevels [llength [info commands testnrelevels]] # diff --git a/tests/obj.test b/tests/obj.test index 126d5ca..71a39b4 100644 --- a/tests/obj.test +++ b/tests/obj.test @@ -16,6 +16,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testobj [llength [info commands testobj]] testConstraint longIs32bit [expr {int(0x80000000) < 0}] testConstraint wideBiggerThanInt [expr {wide(0x80000000) != int(0x80000000)}] diff --git a/tests/oo.test b/tests/oo.test index 00663e9..540cdf3 100644 --- a/tests/oo.test +++ b/tests/oo.test @@ -2,12 +2,12 @@ # Sourcing this file into Tcl runs the tests and generates output for errors. # No output means no errors were found. # -# Copyright (c) 2006-2011 Donal K. Fellows +# Copyright (c) 2006-2012 Donal K. Fellows # # See the file "license.terms" for information on usage and redistribution of # this file, and for a DISCLAIMER OF ALL WARRANTIES. -package require -exact TclOO 0.6.3 ;# Must match value in generic/tclOO.h +package require -exact TclOO 0.7 ;# Must match value in generic/tclOO.h package require tcltest 2 if {"::tcltest" in [namespace children]} { namespace import -force ::tcltest::* diff --git a/tests/ooNext2.test b/tests/ooNext2.test index eeade11..e78e0d0 100644 --- a/tests/ooNext2.test +++ b/tests/ooNext2.test @@ -2,16 +2,14 @@ # Sourcing this file into Tcl runs the tests and generates output for errors. # No output means no errors were found. # -# Copyright (c) 2006-2008 Donal K. Fellows +# Copyright (c) 2006-2011 Donal K. Fellows # # See the file "license.terms" for information on usage and redistribution of # this file, and for a DISCLAIMER OF ALL WARRANTIES. -# -# RCS: @(#) $Id: oo.test,v 1.59 2011/01/18 16:10:48 dkf Exp $ -package require -exact TclOO 0.6.3 ;# Must match value in configure.in -if {[lsearch [namespace children] ::tcltest] == -1} { - package require tcltest 2 +package require -exact TclOO 0.7 ;# Must match value in configure.in +package require tcltest 2 +if {"::tcltest" in [namespace children]} { namespace import -force ::tcltest::* } diff --git a/tests/parse.test b/tests/parse.test index 3523975..0f76d64 100644 --- a/tests/parse.test +++ b/tests/parse.test @@ -16,6 +16,9 @@ if {[catch {package require tcltest 2.0.2}]} { namespace eval ::tcl::test::parse { namespace import ::tcltest::* +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testparser [llength [info commands testparser]] testConstraint testevalobjv [llength [info commands testevalobjv]] testConstraint testevalex [llength [info commands testevalex]] diff --git a/tests/parseExpr.test b/tests/parseExpr.test index cd0342a..7910974 100644 --- a/tests/parseExpr.test +++ b/tests/parseExpr.test @@ -13,6 +13,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + # Note that the Tcl expression parser (tclCompExpr.c) does not check # the semantic validity of the expressions it parses. It does not check, # for example, that a math function actually exists, or that the operands diff --git a/tests/parseOld.test b/tests/parseOld.test index 132481c..0edcbf0 100644 --- a/tests/parseOld.test +++ b/tests/parseOld.test @@ -18,6 +18,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testwordend [llength [info commands testwordend]] # Save the argv value for restoration later diff --git a/tests/platform.test b/tests/platform.test index 92ca7ab..aab7c78 100644 --- a/tests/platform.test +++ b/tests/platform.test @@ -14,6 +14,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testCPUID [llength [info commands testcpuid]] test platform-1.1 {TclpSetVariables: tcl_platform} { diff --git a/tests/reg.test b/tests/reg.test index abfc9ca..a0ea850 100644 --- a/tests/reg.test +++ b/tests/reg.test @@ -13,6 +13,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + # All tests require the testregexp command, return if this # command doesn't exist diff --git a/tests/registry.test b/tests/registry.test index 400277f..77588e3 100644 --- a/tests/registry.test +++ b/tests/registry.test @@ -17,13 +17,10 @@ if {[lsearch [namespace children] ::tcltest] == -1} { testConstraint reg 0 if {[testConstraint win]} { - catch { - # Is the registry extension already static to this shell? - if [catch {load {} Registry; set ::reglib {}}] { - # try the location given to use on the commandline to tcltest + if {![catch { ::tcltest::loadTestedCommands - load $::reglib Registry - } + set ::regver [package require registry 1.3.0] + }]} { testConstraint reg 1 } } @@ -34,6 +31,9 @@ testConstraint english [expr { && [string match "English*" [testlocale all ""]] }] +test registry-1.0 {check if we are testing the right dll} {win reg} { + set ::regver +} {1.3.0} test registry-1.1 {argument parsing for registry command} {win reg} { list [catch {registry} msg] $msg } {1 {wrong # args: should be "registry ?-32bit|-64bit? option ?arg ...?"}} @@ -505,7 +505,7 @@ test registry-6.20 {GetValue: values with Unicode strings with embedded nulls} { registry delete HKEY_CURRENT_USER\\TclFoobar set result } "foo ba r baz" -test registry-6.21 {GetValue: very long value names and values} {pcOnly} { +test registry-6.21 {GetValue: very long value names and values} {pcOnly reg} { registry set HKEY_CURRENT_USER\\TclFoobar [string repeat k 16383] [string repeat x 16383] multi_sz set result [registry get HKEY_CURRENT_USER\\TclFoobar [string repeat k 16383]] registry delete HKEY_CURRENT_USER\\TclFoobar diff --git a/tests/rename.test b/tests/rename.test index 9ac49b4..1fa0441 100644 --- a/tests/rename.test +++ b/tests/rename.test @@ -16,6 +16,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testdel [llength [info commands testdel]] # Must eliminate the "unknown" command while the test is running, especially diff --git a/tests/resolver.test b/tests/resolver.test index bb9f59d..e73ea50 100644 --- a/tests/resolver.test +++ b/tests/resolver.test @@ -15,6 +15,9 @@ if {"::tcltest" in [namespace children]} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testinterpresolver [llength [info commands testinterpresolver]] test resolver-1.1 {cmdNameObj sharing vs. cmd resolver: namespace import} -setup { diff --git a/tests/result.test b/tests/result.test index f080654..3391ce1 100644 --- a/tests/result.test +++ b/tests/result.test @@ -15,6 +15,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + # Some tests require the testsaveresult command testConstraint testsaveresult [llength [info commands testsaveresult]] diff --git a/tests/set.test b/tests/set.test index 9e0ddc0..1d88553 100644 --- a/tests/set.test +++ b/tests/set.test @@ -15,6 +15,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testset2 [llength [info commands testset2]] catch {unset x} diff --git a/tests/socket.test b/tests/socket.test index 9f1cc78..5542c09 100644 --- a/tests/socket.test +++ b/tests/socket.test @@ -64,7 +64,7 @@ package require tcltest 2 namespace import -force ::tcltest::* # Some tests require the Thread package or exec command -testConstraint thread [expr {0 == [catch {package require Thread 2.6.6}]}] +testConstraint thread [expr {0 == [catch {package require Thread 2.7-}]}] testConstraint exec [llength [info commands exec]] # Produce a random port number in the Dynamic/Private range diff --git a/tests/string.test b/tests/string.test index b3326ae..f558d30 100644 --- a/tests/string.test +++ b/tests/string.test @@ -17,6 +17,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + # Some tests require the testobj command testConstraint testobj [expr {[info commands testobj] != {}}] @@ -1481,8 +1484,8 @@ test string-18.11 {string trim, unicode} { string trim "\xe7\xe8 AB\xe7C \xe8\xe7" \xe7\xe8 } " AB\xe7C " test string-18.12 {string trim, unicode default} { - string trim ABC\u1361\u1680\u3000 -} ABC + string trim \ufeff\x00\u0085\u00a0\u1680\u180eABC\u1361\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u202f\u205f\u3000 +} ABC\u1361 test string-19.1 {string trimleft} { list [catch {string trimleft} msg] $msg @@ -1491,8 +1494,8 @@ test string-19.2 {string trimleft} { string trimleft " XYZ " } {XYZ } test string-19.3 {string trimleft, unicode default} { - string trimleft \u1361\u1680\u3000ABC -} ABC + string trimleft \ufeff\u0085\u00a0\x00\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u202f\u205f\u3000\u1361ABC +} \u1361ABC test string-20.1 {string trimright errors} { list [catch {string trimright} msg] $msg @@ -1510,8 +1513,8 @@ test string-20.5 {string trimright} { string trimright "" } {} test string-20.6 {string trimright, unicode default} { - string trimright ABC\u1361\u1680\u3000 -} ABC + string trimright ABC\u1361\u0085\x00\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u202f\u205f\u3000 +} ABC\u1361 test string-21.1 {string wordend} { list [catch {string wordend a} msg] $msg @@ -1773,10 +1776,10 @@ test string-26.3.1 {tcl::prefix, bad args} -body { } -returnCodes 1 -result {error options must have an even number of elements} test string-26.3.2 {tcl::prefix, bad args} -body { tcl::prefix match -error str1 str2 -} -returnCodes 1 -result {missing error options} +} -returnCodes 1 -result {missing value for -error} test string-26.4 {tcl::prefix, bad args} -body { tcl::prefix match -message str1 str2 -} -returnCodes 1 -result {missing message} +} -returnCodes 1 -result {missing value for -message} test string-26.5 {tcl::prefix} { tcl::prefix match {apa bepa cepa depa} cepa } cepa diff --git a/tests/stringComp.test b/tests/stringComp.test index ff18819..56fb69d 100644 --- a/tests/stringComp.test +++ b/tests/stringComp.test @@ -20,6 +20,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + # Some tests require the testobj command testConstraint testobj [expr {[info commands testobj] != {}}] diff --git a/tests/stringObj.test b/tests/stringObj.test index d93bb82..6f331d3 100644 --- a/tests/stringObj.test +++ b/tests/stringObj.test @@ -17,6 +17,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testobj [llength [info commands testobj]] testConstraint testdstring [llength [info commands testdstring]] diff --git a/tests/tailcall.test b/tests/tailcall.test index e9ec188..2d04f82 100644 --- a/tests/tailcall.test +++ b/tests/tailcall.test @@ -14,6 +14,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testnrelevels [llength [info commands testnrelevels]] # diff --git a/tests/thread.test b/tests/thread.test index 44789fa..d79f693 100644 --- a/tests/thread.test +++ b/tests/thread.test @@ -16,13 +16,16 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + # Some tests require the testthread command testConstraint testthread [expr {[info commands testthread] != {}}] # Some tests require the Thread package -testConstraint thread [expr {0 == [catch {package require Thread 2.7}]}] +testConstraint thread [expr {0 == [catch {package require Thread 2.7-}]}] # Some tests may not work under valgrind @@ -76,7 +79,7 @@ if {[testConstraint thread]} { if {[testConstraint testthread]} { proc drainEventQueue {} { while {[set x [testthread event]]} { - puts "WARNING: drained $x event(s) on main thread" + #puts "WARNING: drained $x event(s) on main thread" } } diff --git a/tests/trace.test b/tests/trace.test index 693dbad..0f48dcf 100644 --- a/tests/trace.test +++ b/tests/trace.test @@ -16,6 +16,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testcmdtrace [llength [info commands testcmdtrace]] testConstraint testevalobjv [llength [info commands testevalobjv]] diff --git a/tests/unixFCmd.test b/tests/unixFCmd.test index e8148e9..2453e01 100644 --- a/tests/unixFCmd.test +++ b/tests/unixFCmd.test @@ -14,6 +14,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testchmod [llength [info commands testchmod]] # These tests really need to be run from a writable directory, which diff --git a/tests/unixFile.test b/tests/unixFile.test index 0ea0ec1..8147f48 100644 --- a/tests/unixFile.test +++ b/tests/unixFile.test @@ -14,6 +14,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testfindexecutable [llength [info commands testfindexecutable]] set oldpwd [pwd] diff --git a/tests/unixNotfy.test b/tests/unixNotfy.test index 0646a3d..2f03529 100644 --- a/tests/unixNotfy.test +++ b/tests/unixNotfy.test @@ -17,7 +17,7 @@ if {[lsearch [namespace children] ::tcltest] == -1} { # When run in a Tk shell, these tests hang. testConstraint noTk [expr {0 != [catch {package present Tk}]}] -testConstraint thread [expr {0 == [catch {package require Thread 2.6}]}] +testConstraint thread [expr {0 == [catch {package require Thread 2.7-}]}] # Darwin always uses a threaded notifier testConstraint unthreaded [expr { ![::tcl::pkgconfig get threaded] diff --git a/tests/unload.test b/tests/unload.test index a103cc5..5a374c4 100644 --- a/tests/unload.test +++ b/tests/unload.test @@ -16,6 +16,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + # Figure out what extension is used for shared libraries on this # platform. if {![info exists ext]} { diff --git a/tests/upvar.test b/tests/upvar.test index cd78c31..e2c9ffd 100644 --- a/tests/upvar.test +++ b/tests/upvar.test @@ -16,6 +16,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testupvar [llength [info commands testupvar]] test upvar-1.1 {reading variables with upvar} { diff --git a/tests/utf.test b/tests/utf.test index fcd2a73..c41cfe3 100644 --- a/tests/utf.test +++ b/tests/utf.test @@ -13,6 +13,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + catch {unset x} test utf-1.1 {Tcl_UniCharToUtf: 1 byte sequences} { diff --git a/tests/util.test b/tests/util.test index 1da533c..0e50483 100644 --- a/tests/util.test +++ b/tests/util.test @@ -12,6 +12,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint controversialNaN 1 testConstraint testdstring [llength [info commands testdstring]] testConstraint testconcatobj [llength [info commands testconcatobj]] diff --git a/tests/var.test b/tests/var.test index f2923de..ed7e930 100644 --- a/tests/var.test +++ b/tests/var.test @@ -19,6 +19,9 @@ if {"::tcltest" ni [namespace children]} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testupvar [llength [info commands testupvar]] testConstraint testgetvarfullname [llength [info commands testgetvarfullname]] testConstraint testsetnoerr [llength [info commands testsetnoerr]] diff --git a/tests/winDde.test b/tests/winDde.test index 83f3598..f04fb45 100644 --- a/tests/winDde.test +++ b/tests/winDde.test @@ -15,16 +15,15 @@ if {"::tcltest" ni [namespace children]} { namespace import -force ::tcltest::* } -if [catch { - # Is the dde extension already static to this shell? - if [catch {load {} Dde; set ::ddelib {}}] { - # try the location given to use on the commandline to tcltest - ::tcltest::loadTestedCommands - load $::ddelib Dde +testConstraint debug [::tcl::pkgconfig get debug] +testConstraint dde 0 +if {[testConstraint win]} { + if {![catch { + ::tcltest::loadTestedCommands + set ::ddever [package require dde 1.4.0] + set ::ddelib [lindex [package ifneeded dde $::ddever] 1]}]} { + testConstraint dde 1 } - testConstraint dde 1 -}] { - testConstraint dde 0 } @@ -39,9 +38,7 @@ proc createChildProcess {ddeServerName args} { set f [open $::scriptName w+] puts $f [list set ddeServerName $ddeServerName] - if {$::ddelib != ""} { - puts $f [list load $::ddelib Dde] - } + puts $f [list load $::ddelib dde] puts $f { # DDE child server - # @@ -105,6 +102,9 @@ proc createChildProcess {ddeServerName args} { } # ------------------------------------------------------------------------- +test winDde-1.0 {check if we are testing the right dll} {win dde} { + set ::ddever +} {1.4.0} test winDde-1.1 {Settings the server's topic name} -constraints dde -body { list [dde servername foobar] [dde servername] [dde servername self] @@ -140,33 +140,43 @@ test winDde-3.2 {DDE execute -async locally} -constraints dde -body { set \xe1 } -result foo test winDde-3.3 {DDE request locally} -constraints dde -body { - set a "" - dde execute TclEval self [list set a foo] - dde request TclEval self a + set \xe1 "" + dde execute TclEval self [list set \xe1 foo] + dde request TclEval self \xe1 } -result foo test winDde-3.4 {DDE eval locally} -constraints dde -body { set \xe1 "" dde eval self set \xe1 foo } -result foo test winDde-3.5 {DDE request locally} -constraints dde -body { - set a "" - dde execute TclEval self [list set a foo] - dde request -binary TclEval self a + set \xe1 "" + dde execute TclEval self [list set \xe1 foo] + dde request -binary TclEval self \xe1 } -result "foo\x00" # Set variable a to A with diaeresis (unicode C4) by relying on the fact # that utf8 is sent (e.g. "c3 84" on the wire) test winDde-3.6 {DDE request utf8} -constraints dde -body { - set a "not set" - dde execute TclEval self "set a \xc4" - scan $a %c + set \xe1 "not set" + dde execute TclEval self "set \xe1 \xc4" + scan [set \xe1] %c } -result 196 # Set variable a to A with diaeresis (unicode C4) using binary execute # and compose utf-8 (e.g. "c3 84" ) manualy test winDde-3.7 {DDE request binary} -constraints dde -body { - set a "not set" - dde execute -binary TclEval self [list set a \xc3\x84\x00] - scan $a %c + set \xe1 "not set" + dde execute -binary TclEval self [list set \xc3\xa1 \xc3\x84\x00] + scan [set \xe1] %c } -result 196 +test winDde-3.8 {DDE poke locally} -constraints {dde debug} -body { + set \xe1 "" + dde poke TclEval self \xe1 \xc4 + dde request TclEval self \xe1 +} -result \xc4 +test winDde-3.9 {DDE poke -binary locally} -constraints {dde debug} -body { + set \xe1 "" + dde poke -binary TclEval self \xe1 \xc3\x84\x00 + dde request TclEval self \xe1 +} -result \xc4 # ------------------------------------------------------------------------- @@ -190,24 +200,34 @@ test winDde-4.2 {DDE execute async remotely} -constraints {dde stdio} -body { set \xe1 } -result "" test winDde-4.3 {DDE request remotely} -constraints {dde stdio} -body { - set a "" + set \xe1 "" set name ch\xEDld-4.3 set child [createChildProcess $name] - dde execute TclEval $name [list set a foo] - set a [dde request TclEval $name a] + dde execute TclEval $name [list set \xe1 foo] + set \xe1 [dde request TclEval $name \xe1] dde execute TclEval $name {set done 1} update - set a + set \xe1 } -result foo test winDde-4.4 {DDE eval remotely} -constraints {dde stdio} -body { - set a "" + set \xe1 "" set name ch\xEDld-4.4 set child [createChildProcess $name] - set a [dde eval $name set a foo] + set \xe1 [dde eval $name set \xe1 foo] dde execute TclEval $name {set done 1} update - set a + set \xe1 } -result foo +test winDde-4.5 {DDE poke remotely} -constraints {dde debug stdio} -body { + set \xe1 "" + set name ch\xEDld-4.5 + set child [createChildProcess $name] + dde poke TclEval $name \xe1 foo + set \xe1 [dde request TclEval $name \xe1] + dde execute TclEval $name {set done 1} + update + set \xe1 +} -result foo # ------------------------------------------------------------------------- diff --git a/tests/winFCmd.test b/tests/winFCmd.test index b49356d..28a0e9f 100644 --- a/tests/winFCmd.test +++ b/tests/winFCmd.test @@ -15,6 +15,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + # Initialise the test constraints testConstraint winVista 0 diff --git a/tests/winFile.test b/tests/winFile.test index ad34624..fba9bcb 100644 --- a/tests/winFile.test +++ b/tests/winFile.test @@ -16,6 +16,9 @@ if {[catch {package require tcltest 2.0.2}]} { } namespace import -force ::tcltest::* +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testvolumetype [llength [info commands testvolumetype]] testConstraint notNTFS 0 testConstraint win2000 0 diff --git a/tests/winNotify.test b/tests/winNotify.test index f9c75a3..3e9aa29 100644 --- a/tests/winNotify.test +++ b/tests/winNotify.test @@ -15,6 +15,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testeventloop [expr {[info commands testeventloop] != {}}] # There is no explicit test for InitNotifier or NotifierExitHandler diff --git a/tests/winPipe.test b/tests/winPipe.test index 62d7d0d..d2e804d 100644 --- a/tests/winPipe.test +++ b/tests/winPipe.test @@ -16,6 +16,12 @@ package require tcltest namespace import -force ::tcltest::* unset -nocomplain path +catch { + ::tcltest::loadTestedCommands + package require -exact Tcltest [info patchlevel] + set ::tcltestlib [lindex [package ifneeded Tcltest [info patchlevel]] 1] +} + set bindir [file join [pwd] [file dirname [info nameofexecutable]]] set cat32 [file join $bindir cat32.exe] @@ -23,6 +29,8 @@ testConstraint exec [llength [info commands exec]] testConstraint cat32 [file exists $cat32] testConstraint AllocConsole [catch {puts console1 ""}] testConstraint RealConsole [expr {![testConstraint AllocConsole]}] +testConstraint testexcept [llength [info commands testexcept]] + set big bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n append big $big @@ -190,30 +198,34 @@ test winpipe-4.1 {Tcl_WaitPid} {win nt exec cat32} { vwait x list $result $x [contents $path(stderr)] } "{$big} 1 stderr32" -test winpipe-4.2 {Tcl_WaitPid: return of exception codes, SIGFPE} {win exec} { +test winpipe-4.2 {Tcl_WaitPid: return of exception codes, SIGFPE} {win exec testexcept} { set f [open "|[list [interpreter]]" w+] set pid [pid $f] + puts $f "load $::tcltestlib Tcltest" puts $f "testexcept float_underflow" set status [catch {close $f}] list $status [expr {$pid == [lindex $::errorCode 1]}] [lindex $::errorCode 2] } {1 1 SIGFPE} -test winpipe-4.3 {Tcl_WaitPid: return of exception codes, SIGSEGV} {win exec} { +test winpipe-4.3 {Tcl_WaitPid: return of exception codes, SIGSEGV} {win exec testexcept} { set f [open "|[list [interpreter]]" w+] set pid [pid $f] + puts $f "load $::tcltestlib Tcltest" puts $f "testexcept access_violation" set status [catch {close $f}] list $status [expr {$pid == [lindex $::errorCode 1]}] [lindex $::errorCode 2] } {1 1 SIGSEGV} -test winpipe-4.4 {Tcl_WaitPid: return of exception codes, SIGILL} {win exec} { +test winpipe-4.4 {Tcl_WaitPid: return of exception codes, SIGILL} {win exec testexcept} { set f [open "|[list [interpreter]]" w+] set pid [pid $f] + puts $f "load $::tcltestlib Tcltest" puts $f "testexcept illegal_instruction" set status [catch {close $f}] list $status [expr {$pid == [lindex $::errorCode 1]}] [lindex $::errorCode 2] } {1 1 SIGILL} -test winpipe-4.5 {Tcl_WaitPid: return of exception codes, SIGINT} {win exec} { +test winpipe-4.5 {Tcl_WaitPid: return of exception codes, SIGINT} {win exec testexcept} { set f [open "|[list [interpreter]]" w+] set pid [pid $f] + puts $f "load $::tcltestlib Tcltest" puts $f "testexcept ctrl+c" set status [catch {close $f}] list $status [expr {$pid == [lindex $::errorCode 1]}] [lindex $::errorCode 2] diff --git a/tests/winTime.test b/tests/winTime.test index 278db32..add8f98 100644 --- a/tests/winTime.test +++ b/tests/winTime.test @@ -15,6 +15,9 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +::tcltest::loadTestedCommands +catch [list package require -exact Tcltest [info patchlevel]] + testConstraint testwinclock [llength [info commands testwinclock]] # The next two tests will crash on Windows if the check for negative diff --git a/tests/zlib.test b/tests/zlib.test index 8212082..5f1e5fc 100644 --- a/tests/zlib.test +++ b/tests/zlib.test @@ -10,7 +10,7 @@ # See the file "license.terms" for information on usage and redistribution of # this file, and for a DISCLAIMER OF ALL WARRANTIES. -if {[lsearch [namespace children] ::tcltest] == -1} { +if {"::tcltest" ni [namespace children]} { package require tcltest 2.1 namespace import -force ::tcltest::* } @@ -23,6 +23,12 @@ test zlib-1.1 {zlib basics} -constraints zlib -returnCodes error -body { test zlib-1.2 {zlib basics} -constraints zlib -returnCodes error -body { zlib ? {} } -result {bad command "?": must be adler32, compress, crc32, decompress, deflate, gunzip, gzip, inflate, push, or stream} +test zlib-1.3 {zlib basics} -constraints zlib -body { + zlib::pkgconfig list +} -result zlibVersion +test zlib-1.4 {zlib basics} -constraints zlib -body { + package present zlib +} -result 2.0 test zlib-2.1 {zlib compress/decompress} zlib { zlib decompress [zlib compress abcdefghijklm] @@ -70,7 +76,7 @@ test zlib-7.0 {zlib stream} -constraints zlib -returnCodes error -setup { $s ? } -cleanup { $s close -} -result {bad option "?": must be add, checksum, close, eof, finalize, flush, fullflush, get, put, or reset} +} -result {bad option "?": must be add, checksum, close, eof, finalize, flush, fullflush, get, header, put, or reset} test zlib-7.1 {zlib stream} zlib { set s [zlib stream compress] $s put -finalize abcdeEDCBA @@ -203,6 +209,163 @@ test zlib-8.5 {transformation and flushing and fileevents: Bug 3525907} -setup { } -cleanup { catch {close $r} } -result {qwertyuiop MIDDLE asdfghjkl} +test zlib-8.6 {transformation and fconfigure} -setup { + set file [makeFile {} test.z] + set fd [open $file wb] +} -constraints zlib -body { + list [fconfigure $fd] [zlib push compress $fd; fconfigure $fd] \ + [chan pop $fd; fconfigure $fd] +} -cleanup { + catch {close $fd} + removeFile $file +} -result {{-blocking 1 -buffering full -buffersize 4096 -encoding binary -eofchar {} -translation lf} {-blocking 1 -buffering full -buffersize 4096 -encoding binary -eofchar {} -translation lf -checksum 1 -dictionary {}} {-blocking 1 -buffering full -buffersize 4096 -encoding binary -eofchar {} -translation lf}} +test zlib-8.7 {transformation and fconfigure} -setup { + set file [makeFile {} test.gz] + set fd [open $file wb] +} -constraints zlib -body { + list [fconfigure $fd] [zlib push gzip $fd; fconfigure $fd] \ + [chan pop $fd; fconfigure $fd] +} -cleanup { + catch {close $fd} + removeFile $file +} -result {{-blocking 1 -buffering full -buffersize 4096 -encoding binary -eofchar {} -translation lf} {-blocking 1 -buffering full -buffersize 4096 -encoding binary -eofchar {} -translation lf -checksum 0} {-blocking 1 -buffering full -buffersize 4096 -encoding binary -eofchar {} -translation lf}} +# Input is headers from fetching SPDY draft +# Dictionary is that which is proposed _in_ SPDY draft +set spdyHeaders "HTTP/1.0 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nX-Robots-Tag: noarchive\r\nLast-Modified: Tue, 05 Jun 2012 02:43:25 GMT\r\nETag: \"1338864205129|#public|0|en|||0\"\r\nExpires: Tue, 05 Jun 2012 16:17:11 GMT\r\nDate: Tue, 05 Jun 2012 16:17:06 GMT\r\nCache-Control: public, max-age=5\r\nX-Content-Type-Options: nosniff\r\nX-XSS-Protection: 1; mode=block\r\nServer: GSE\r\n" +set spdyDict "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchif-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser-agent100101200201202203204205206300301302303304305306307400401402403404405406407408409410411412413414415416417500501502503504505accept-rangesageetaglocationproxy-authenticatepublicretry-afterservervarywarningwww-authenticateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertransfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locationcontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMondayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSepOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplication/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1.1statusversionurl" +test zlib-8.8 {transformtion and fconfigure} -setup { + lassign [chan pipe] inSide outSide +} -constraints zlib -body { + zlib push compress $outSide -dictionary $spdyDict + fconfigure $outSide -blocking 0 -translation binary -buffering none + fconfigure $inSide -blocking 0 -translation binary + puts -nonewline $outSide $spdyHeaders + chan pop $outSide + set compressed [read $inSide] + catch {zlib decompress $compressed} err opt + list [string length [zlib compress $spdyHeaders]] \ + [string length $compressed] \ + $err [dict get $opt -errorcode] [zlib adler32 $spdyDict] +} -cleanup { + catch {close $outSide} + catch {close $inSide} +} -result {260 222 {need dictionary} {TCL ZLIB NEED_DICT 2381337010} 2381337010} +test zlib-8.9 {transformtion and fconfigure} -setup { + lassign [chan pipe] inSide outSide + set strm [zlib stream decompress] +} -constraints zlib -body { + zlib push compress $outSide -dictionary $spdyDict + fconfigure $outSide -blocking 0 -translation binary -buffering none + fconfigure $inSide -blocking 0 -translation binary + puts -nonewline $outSide $spdyHeaders + set result [fconfigure $outSide -checksum] + chan pop $outSide + $strm put -dictionary $spdyDict [read $inSide] + lappend result [string length $spdyHeaders] [string length [$strm get]] +} -cleanup { + catch {close $outSide} + catch {close $inSide} + catch {$strm close} +} -result {3064818174 358 358} +test zlib-8.10 {transformtion and fconfigure} -setup { + lassign [chan pipe] inSide outSide +} -constraints zlib -body { + zlib push deflate $outSide -dictionary $spdyDict + fconfigure $outSide -blocking 0 -translation binary -buffering none + fconfigure $inSide -blocking 0 -translation binary + puts -nonewline $outSide $spdyHeaders + chan pop $outSide + set compressed [read $inSide] + catch {zlib inflate $compressed} err opt + list [string length [zlib deflate $spdyHeaders]] \ + [string length $compressed] \ + $err [dict get $opt -errorcode] +} -cleanup { + catch {close $outSide} + catch {close $inSide} +} -result {254 212 {data error} {TCL ZLIB DATA}} +test zlib-8.11 {transformtion and fconfigure} -setup { + lassign [chan pipe] inSide outSide + set strm [zlib stream inflate] +} -constraints zlib -body { + zlib push deflate $outSide -dictionary $spdyDict + fconfigure $outSide -blocking 0 -translation binary -buffering none + fconfigure $inSide -blocking 0 -translation binary + puts -nonewline $outSide $spdyHeaders + chan pop $outSide + $strm put -dictionary $spdyDict [read $inSide] + list [string length $spdyHeaders] [string length [$strm get]] +} -cleanup { + catch {close $outSide} + catch {close $inSide} + catch {$strm close} +} -result {358 358} +test zlib-8.12 {transformtion and fconfigure} -setup { + lassign [chan pipe] inSide outSide + set strm [zlib stream compress] +} -constraints zlib -body { + $strm put -dictionary $spdyDict -finalize $spdyHeaders + zlib push decompress $inSide + fconfigure $outSide -blocking 0 -translation binary + fconfigure $inSide -translation binary -dictionary $spdyDict + puts -nonewline $outSide [$strm get] + close $outSide + list [string length $spdyHeaders] [string length [read $inSide]] \ + [fconfigure $inSide -checksum] +} -cleanup { + catch {close $outSide} + catch {close $inSide} + catch {$strm close} +} -result {358 358 3064818174} +test zlib-8.13 {transformtion and fconfigure} -setup { + lassign [chan pipe] inSide outSide + set strm [zlib stream compress] +} -constraints zlib -body { + $strm put -dictionary $spdyDict -finalize $spdyHeaders + zlib push decompress $inSide -dictionary $spdyDict + fconfigure $outSide -blocking 0 -translation binary + fconfigure $inSide -translation binary + puts -nonewline $outSide [$strm get] + close $outSide + list [string length $spdyHeaders] [string length [read $inSide]] \ + [fconfigure $inSide -checksum] +} -cleanup { + catch {close $outSide} + catch {close $inSide} + catch {$strm close} +} -result {358 358 3064818174} +test zlib-8.14 {transformtion and fconfigure} -setup { + lassign [chan pipe] inSide outSide + set strm [zlib stream deflate] +} -constraints zlib -body { + $strm put -finalize -dictionary $spdyDict $spdyHeaders + zlib push inflate $inSide + fconfigure $outSide -blocking 0 -buffering none -translation binary + fconfigure $inSide -translation binary -dictionary $spdyDict + puts -nonewline $outSide [$strm get] + close $outSide + list [string length $spdyHeaders] [string length [read $inSide]] +} -cleanup { + catch {close $outSide} + catch {close $inSide} + catch {$strm close} +} -result {358 358} +test zlib-8.15 {transformtion and fconfigure} -setup { + lassign [chan pipe] inSide outSide + set strm [zlib stream deflate] +} -constraints zlib -body { + $strm put -finalize -dictionary $spdyDict $spdyHeaders + zlib push inflate $inSide -dictionary $spdyDict + fconfigure $outSide -blocking 0 -buffering none -translation binary + fconfigure $inSide -translation binary + puts -nonewline $outSide [$strm get] + close $outSide + list [string length $spdyHeaders] [string length [read $inSide]] +} -cleanup { + catch {close $outSide} + catch {close $inSide} + catch {$strm close} +} -result {358 358} test zlib-9.1 "check fcopy with push" -constraints zlib -setup { set sfile [makeFile {} testsrc.gz] diff --git a/tools/README b/tools/README index 821b2b3..f4bf627 100644 --- a/tools/README +++ b/tools/README @@ -23,6 +23,3 @@ Generating Windows Help Files: this converts the Nroff to RTF files. 2) On Windows, convert the RTF to a Help doc, do nmake helpfile - -Generating Windows binary distribution. -Update and compile the WYSE tcl.wse configuration. diff --git a/tools/genStubs.tcl b/tools/genStubs.tcl index dea63e6..93e0a9a 100644 --- a/tools/genStubs.tcl +++ b/tools/genStubs.tcl @@ -828,7 +828,7 @@ proc genStubs::forAllStubs {name slotProc onAll textVar append text [addPlatformGuard $plat $temp {} true] } ## macosx ## - if {$block(macosx) && !$block(aqua) && !$block(x11)} { + if {($block(unix) || $block(macosx)) && !$block(aqua) && !$block(x11)} { set temp {} set lastNum -1 foreach plat {unix macosx} { @@ -986,7 +986,7 @@ proc genStubs::emitHeader {name} { emitDeclarations $name text if {[info exists hooks($name)]} { - append text "\ntypedef struct ${capName}StubHooks {\n" + append text "\ntypedef struct {\n" foreach hook $hooks($name) { set capHook [string toupper [string index $hook 0]] append capHook [string range $hook 1 end] @@ -1000,7 +1000,11 @@ proc genStubs::emitHeader {name} { append text " int epoch;\n" append text " int revision;\n" } - append text " const struct ${capName}StubHooks *hooks;\n\n" + if {[info exists hooks($name)]} { + append text " const ${capName}StubHooks *hooks;\n\n" + } else { + append text " void *hooks;\n\n" + } emitSlots $name text diff --git a/tools/str2c b/tools/str2c index 971e552..cff7ba2 100644 --- a/tools/str2c +++ b/tools/str2c @@ -36,7 +36,7 @@ static char data\[\]=\"[translate $r]\";" puts "/* * Multi parts read only string generated by str2c */ -static CONST char * CONST data\[\]= {" +static const char * const data\[\]= {" set n 1 for {set i 0} {$i<$lg} {incr i $MAX} { set part [string range $r $i [expr $i+$MAX-1]] @@ -48,7 +48,7 @@ static CONST char * CONST data\[\]= {" } puts "\tNULL\t/* End of data marker */\n};" puts "\n/* use for instance with: - CONST char * CONST *chunk; + const char * const *chunk; for (chunk=data; *chunk; chunk++) { Tcl_AppendResult(interp, *chunk, (char *) NULL); } diff --git a/tools/tcl.wse.in b/tools/tcl.wse.in deleted file mode 100644 index 653b1e1..0000000 --- a/tools/tcl.wse.in +++ /dev/null @@ -1,2376 +0,0 @@ -Document Type: WSE -item: Global - Version=6.01 - Title=Tcl 8.6 for Windows Installation - Flags=00010100 - Languages=65 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 - Japanese Font Name=MS Gothic - Japanese Font Size=10 - Start Gradient=0 0 255 - End Gradient=0 0 0 - Windows Flags=00000000000000010010110000001000 - Log Pathname=%MAINDIR%\INSTALL.LOG - Message Font=MS Sans Serif - Font Size=8 - Disk Label=tcl8.6b2 - Disk Filename=setup - Patch Flags=0000000000000001 - Patch Threshold=85 - Patch Memory=4000 - Variable Name1=_SYS_ - Variable Default1=C:\WINDOWS\SYSTEM - Variable Flags1=00001000 - Variable Name2=_ODBC16_ - Variable Default2=C:\WINDOWS\SYSTEM - Variable Flags2=00001000 - Variable Name3=_WISE_ - Variable Default3=${__WISE__} - Variable Flags3=00001000 -end -item: Open/Close INSTALL.LOG - Flags=00000001 -end -item: Check if File/Dir Exists - Pathname=%SYS% - Flags=10000100 -end -item: Set Variable - Variable=SYS - Value=%WIN% -end -item: End Block -end -item: Set Variable - Variable=VER - Value=8.6 -end -item: Set Variable - Variable=PATCHLEVEL - Value=${__TCL_PATCH_LEVEL__} -end -item: Set Variable - Variable=APPTITLE - Value=Tcl/Tk %PATCHLEVEL% for Windows -end -item: Set Variable - Variable=URL - Value=http://www.tcl.tk/ -end -item: Set Variable - Variable=GROUP - Value=Tcl -end -item: Set Variable - Variable=DISABLED - Value=! -end -item: Set Variable - Variable=MAINDIR - Value=Tcl -end -item: Check Configuration - Flags=10111011 -end -item: Get Registry Key Value - Variable=PROGRAM_FILES - Key=SOFTWARE\Microsoft\Windows\CurrentVersion - Default=C:\Program Files - Value Name=ProgramFilesDir - Flags=00000100 -end -item: Set Variable - Variable=MAINDIR - Value=%PROGRAM_FILES%\%MAINDIR% -end -item: Set Variable - Variable=EXPLORER - Value=1 -end -item: Else Statement -end -item: Set Variable - Variable=MAINDIR - Value=C:\%MAINDIR% -end -item: End Block -end -item: Set Variable - Variable=BACKUP - Value=%MAINDIR%\BACKUP -end -item: Set Variable - Variable=DOBACKUP - Value=B -end -item: Set Variable - Variable=BRANDING - Value=0 -end -remarked item: If/While Statement - Variable=BRANDING - Value=1 -end -remarked item: Read INI Value - Variable=NAME - Pathname=%INST%\CUSTDATA.INI - Section=Registration - Item=Name -end -remarked item: Read INI Value - Variable=COMPANY - Pathname=%INST%\CUSTDATA.INI - Section=Registration - Item=Company -end -remarked item: If/While Statement - Variable=NAME -end -remarked item: Set Variable - Variable=DOBRAND - Value=1 -end -remarked item: End Block -end -remarked item: End Block -end -item: Set Variable - Variable=TYPE - Value=C -end -item: Set Variable - Variable=COMPONENTS - Value=ABC -end -item: Wizard Block - Direction Variable=DIRECTION - Display Variable=DISPLAY - X Position=0 - Y Position=0 - Filler Color=8421440 - Flags=00000001 -end -item: Custom Dialog Set - Name=Splash - Display Variable=DISPLAY - item: Dialog - Title=%APPTITLE% Installation - Title French=Bienvenue - Title German=Willkommen - Title Portuguese=Bem-vindo - Title Spanish=Bienvenido - Title Italian=Benvenuto - Title Danish=Velkommen - Title Dutch=Welkom - Title Norwegian=Velkommen - Title Swedish=Välkommen - Width=273 - Height=250 - Font Name=Helv - Font Size=8 - item: Push Button - Rectangle=166 214 208 228 - Variable=DIRECTION - Value=N - Create Flags=01010000000000010000000000000001 - Text=&Next > - end - item: Push Button - Rectangle=212 214 254 228 - Action=3 - Create Flags=01010000000000010000000000000000 - Text=Cancel - end - item: Static - Rectangle=0 0 268 233 - Action=2 - Enabled Color=00000000000000001111111111111111 - Create Flags=01010000000000000000000000001011 - Pathname=${__TCLBASEDIR__}\tools\white.bmp - end - item: Static - Rectangle=5 5 268 215 - Destination Dialog=1 - Action=2 - Enabled Color=00000000000000001111111111111111 - Create Flags=01010000000000000000000000001011 - Pathname=${__TCLBASEDIR__}\tools\tclSplash.bmp - end - end -end -item: End Block -end -item: Wizard Block - Direction Variable=DIRECTION - Display Variable=DISPLAY - Bitmap Pathname=%_WISE_%\DIALOGS\TEMPLATE\WIZARD.BMP - X Position=9 - Y Position=10 - Filler Color=8421440 - Dialog=Welcome - Dialog=Select Destination Directory - Dialog=Select Installation Type - Dialog=Select Components - Dialog=Select Program Manager Group - Variable= - Variable= - Variable= - Variable=TYPE - Variable=EXPLORER - Value= - Value= - Value= - Value=C - Value=1 - Compare=0 - Compare=0 - Compare=0 - Compare=1 - Compare=0 - Flags=00000011 -end -item: Custom Dialog Set - Name=Welcome - Display Variable=DISPLAY - item: Dialog - Title=%APPTITLE% Installation - Title French=Installation de %APPTITLE% - Title German=Installation von %APPTITLE% - Title Spanish=Instalación de %APPTITLE% - Title Italian=Installazione di %APPTITLE% - Width=271 - Height=224 - Font Name=Helv - Font Size=8 - item: Static - Rectangle=86 8 258 42 - Create Flags=01010000000000000000000000000000 - Flags=0000000000000001 - Name=Times New Roman - Font Style=-24 0 0 0 700 255 0 0 0 3 2 1 18 - Text=Welcome! - Text French=Bienvenue ! - Text German=Willkommen! - Text Spanish=¡Bienvenido! - Text Italian=Benvenuti! - end - item: Push Button - Rectangle=150 187 195 202 - Variable=DIRECTION - Value=N - Create Flags=01010000000000010000000000000001 - Text=&Next > - Text French=&Suite > - Text German=&Weiter > - Text Spanish=&Siguiente > - Text Italian=&Avanti > - end - item: Push Button - Rectangle=105 187 150 202 - Variable=DISABLED - Value=! - Create Flags=01010000000000010000000000000000 - Text=< &Back - Text French=< &Retour - Text German=< &Zurück - Text Spanish=< &Atrás - Text Italian=< &Indietro - end - item: Push Button - Rectangle=211 187 256 202 - Action=3 - Create Flags=01010000000000010000000000000000 - Text=&Cancel - Text French=&Annuler - Text German=&Abbrechen - Text Spanish=&Cancelar - Text Italian=&Annulla - end - item: Static - Rectangle=85 41 255 130 - Create Flags=01010000000000000000000000000000 - Text=This installation program will install %APPTITLE%. - Text= - Text=Press the Next button to start the installation. You can press the Exit Setup button now if you do not want to install %APPTITLE% at this time. - Text= - Text=It is strongly recommended that you exit all Windows programs before running this installation program. - Text French=Ce programme d'installation va installer %APPTITLE%. - Text French= - Text French=Cliquez sur le bouton Suite pour démarrer l'installation. Vous pouvez cliquer sur le bouton Quitter l'installation si vous ne voulez pas installer %APPTITLE% tout de suite. - Text German=Mit diesem Installationsprogramm wird %APPTITLE% installiert. - Text German= - Text German=Klicken Sie auf "Weiter", um mit der Installation zu beginnen. Klicken Sie auf "Abbrechen", um die Installation von %APPTITLE% abzubrechen. - Text Spanish=Este programa de instalación instalará %APPTITLE%. - Text Spanish= - Text Spanish=Presione el botón Siguiente para iniciar la instalación. Puede presionar el botón Salir de instalación si no desea instalar %APPTITLE% en este momento. - Text Italian=Questo programma installerà %APPTITLE%. - Text Italian= - Text Italian=Per avvviare l'installazione premere il pulsante Avanti. Se non si desidera installare %APPTITLE% ora, premere il pulsante Esci dall'installazione. - end - item: Static - Rectangle=8 180 256 181 - Action=3 - Create Flags=01010000000000000000000000000111 - end - end -end -item: Custom Dialog Set - Name=Select Destination Directory - Display Variable=DISPLAY - item: Dialog - Title=%APPTITLE% Installation - Title French=Installation de %APPTITLE% - Title German=Installation von %APPTITLE% - Title Spanish=Instalación de %APPTITLE% - Title Italian=Installazione di %APPTITLE% - Width=271 - Height=224 - Font Name=Helv - Font Size=8 - item: Push Button - Rectangle=150 187 195 202 - Variable=DIRECTION - Value=N - Create Flags=01010000000000010000000000000001 - Text=&Next > - Text French=&Suite > - Text German=&Weiter > - Text Spanish=&Siguiente > - Text Italian=&Avanti > - end - item: Push Button - Rectangle=105 187 150 202 - Variable=DIRECTION - Value=B - Create Flags=01010000000000010000000000000000 - Flags=0000000000000001 - Text=< &Back - Text French=< &Retour - Text German=< &Zurück - Text Spanish=< &Atrás - Text Italian=< &Indietro - end - item: Push Button - Rectangle=211 187 256 202 - Action=3 - Create Flags=01010000000000010000000000000000 - Text=&Cancel - Text French=&Annuler - Text German=&Abbrechen - Text Spanish=&Cancelar - Text Italian=&Annulla - end - item: Static - Rectangle=8 180 256 181 - Action=3 - Create Flags=01010000000000000000000000000111 - end - item: Static - Rectangle=86 8 258 42 - Create Flags=01010000000000000000000000000000 - Flags=0000000000000001 - Name=Times New Roman - Font Style=-24 0 0 0 700 255 0 0 0 3 2 1 18 - Text=Select Destination Directory - Text French=Sélectionner le répertoire de destination - Text German=Zielverzeichnis wählen - Text Spanish=Seleccione el directorio de destino - Text Italian=Selezionare Directory di destinazione - end - item: Static - Rectangle=86 39 256 114 - Create Flags=01010000000000000000000000000000 - Text=Please select the directory where the %APPTITLE% files are to be installed. - Text= - Text=To install in the default directory below, click Next. - Text= - Text=To install in a different directory, click Browse and select another directory. - Text French=Veuillez sélectionner le répertoire dans lequel les fichiers %APPTITLE% doivent être installés. - Text German=Geben Sie an, in welchem Verzeichnis die %APPTITLE%-Dateien installiert werden sollen. - Text Spanish=Por favor seleccione el directorio donde desee instalar los archivos de %APPTITLE%. - Text Italian=Selezionare la directory dove verranno installati i file %APPTITLE%. - end - item: Static - Rectangle=86 130 256 157 - Action=1 - Create Flags=01010000000000000000000000000111 - end - item: Push Button - Rectangle=205 138 250 153 - Variable=MAINDIR_SAVE - Value=%MAINDIR% - Destination Dialog=1 - Action=2 - Create Flags=01010000000000010000000000000000 - Text=Browse - Text French=Parcourir - Text German=Durchsuchen - Text Spanish=Buscar - Text Italian=Sfoglie - end - item: Static - Rectangle=91 140 198 151 - Create Flags=01010000000000000000000000000000 - Text=%MAINDIR% - Text French=%MAINDIR% - Text German=%MAINDIR% - Text Spanish=%MAINDIR% - Text Italian=%MAINDIR% - end - end - item: Dialog - Title=Select Destination Directory - Title French=Sélectionner le répertoire de destination - Title German=Zielverzeichnis wählen - Title Spanish=Seleccione el directorio de destino - Title Italian=Selezionare Directory di destinazione - Width=221 - Height=173 - Font Name=Helv - Font Size=8 - item: Listbox - Rectangle=5 5 163 149 - Variable=MAINDIR - Create Flags=01010000100000010000000101000000 - Flags=0000110000100010 - Text=%MAINDIR% - Text French=%MAINDIR% - Text German=%MAINDIR% - Text Spanish=%MAINDIR% - Text Italian=%MAINDIR% - end - item: Push Button - Rectangle=167 6 212 21 - Create Flags=01010000000000010000000000000001 - Text=OK - Text French=OK - Text German=OK - Text Spanish=Aceptar - Text Italian=OK - end - item: Push Button - Rectangle=167 25 212 40 - Variable=MAINDIR - Value=%MAINDIR_SAVE% - Create Flags=01010000000000010000000000000000 - Flags=0000000000000001 - Text=Cancel - Text French=Annuler - Text German=Abbrechen - Text Spanish=Cancelar - Text Italian=Annulla - end - end -end -remarked item: Custom Dialog Set - Name=Select Installation Type - Display Variable=DISPLAY - item: Dialog - Title=%APPTITLE% Installation - Title French=Installation de %APPTITLE% - Title German=Installation von %APPTITLE% - Title Spanish=Instalación de %APPTITLE% - Title Italian=Installazione di %APPTITLE% - Width=271 - Height=224 - Font Name=Helv - Font Size=8 - item: Push Button - Rectangle=150 187 195 202 - Variable=DIRECTION - Value=N - Create Flags=01010000000000010000000000000001 - Text=&Next > - Text French=&Suite > - Text German=&Weiter > - Text Spanish=&Siguiente > - Text Italian=&Avanti > - end - item: Push Button - Rectangle=105 187 150 202 - Variable=DIRECTION - Value=B - Create Flags=01010000000000010000000000000000 - Text=< &Back - Text French=< &Retour - Text German=< &Zurück - Text Spanish=< &Atrás - Text Italian=< &Indietro - end - item: Push Button - Rectangle=211 187 256 202 - Action=3 - Create Flags=01010000000000010000000000000000 - Text=&Cancel - Text French=&Annuler - Text German=&Abbrechen - Text Spanish=&Cancelar - Text Italian=&Annulla - end - item: Static - Rectangle=8 180 256 181 - Action=3 - Create Flags=01010000000000000000000000000111 - end - item: Static - Rectangle=86 8 258 42 - Create Flags=01010000000000000000000000000000 - Flags=0000000000000001 - Name=Times New Roman - Font Style=-24 0 0 0 700 255 0 0 0 3 2 1 18 - Text=Select Installation Type - Text French=Sélectionner les composants - Text German=Komponenten auswählen - Text Spanish=Seleccione componentes - Text Italian=Selezionare i componenti - end - item: Static - Rectangle=194 162 242 172 - Variable=COMPONENTS - Value=MAINDIR - Create Flags=01010000000000000000000000000010 - end - item: Static - Rectangle=194 153 242 162 - Variable=COMPONENTS - Create Flags=01010000000000000000000000000010 - end - item: Static - Rectangle=107 153 196 164 - Create Flags=01010000000000000000000000000000 - Text=Disk Space Required: - Text French=Espace disque requis : - Text German=Notwendiger Speicherplatz: - Text Spanish=Espacio requerido en el disco: - Text Italian=Spazio su disco necessario: - end - item: Static - Rectangle=107 162 196 172 - Create Flags=01010000000000000000000000000000 - Text=Disk Space Remaining: - Text French=Espace disque disponible : - Text German=Verbleibender Speicherplatz: - Text Spanish=Espacio en disco disponible: - Text Italian=Spazio su disco disponibile: - end - item: Static - Rectangle=86 145 256 175 - Action=1 - Create Flags=01010000000000000000000000000111 - end - item: Static - Rectangle=86 42 256 61 - Create Flags=01010000000000000000000000000000 - Text=Choose which type of installation to perform by selecting one of the buttons below. - Text French=Choisissez les composants que vous voulez installer en cochant les cases ci-dessous. - Text German=Wählen Sie die zu installierenden Komponenten, indem Sie in die entsprechenden Kästchen klicken. - Text Spanish=Elija los componentes que desee instalar marcando los cuadros de abajo. - Text Italian=Scegliere quali componenti installare selezionando le caselle sottostanti. - end - item: Radio Button - Rectangle=86 74 256 128 - Variable=TYPE - Create Flags=01010000000000010000000000001001 - Text=&Full Installation (Recommended) - Text=&Minimal Installation - Text=C&ustom Installation - Text= - end - end -end -item: Custom Dialog Set - Name=Select Components - Display Variable=DISPLAY - item: Dialog - Title=%APPTITLE% Installation - Title French=Installation de %APPTITLE% - Title German=Installation von %APPTITLE% - Title Spanish=Instalación de %APPTITLE% - Title Italian=Installazione di %APPTITLE% - Width=271 - Height=224 - Font Name=Helv - Font Size=8 - item: Push Button - Rectangle=150 187 195 202 - Variable=DIRECTION - Value=N - Create Flags=01010000000000010000000000000001 - Text=&Next > - Text French=&Suite > - Text German=&Weiter > - Text Spanish=&Siguiente > - Text Italian=&Avanti > - end - item: Push Button - Rectangle=105 187 150 202 - Variable=DIRECTION - Value=B - Create Flags=01010000000000010000000000000000 - Text=< &Back - Text French=< &Retour - Text German=< &Zurück - Text Spanish=< &Atrás - Text Italian=< &Indietro - end - item: Push Button - Rectangle=211 187 256 202 - Action=3 - Create Flags=01010000000000010000000000000000 - Text=&Cancel - Text French=&Annuler - Text German=&Abbrechen - Text Spanish=&Cancelar - Text Italian=&Annulla - end - item: Static - Rectangle=8 180 256 181 - Action=3 - Create Flags=01010000000000000000000000000111 - end - item: Static - Rectangle=86 8 258 42 - Create Flags=01010000000000000000000000000000 - Flags=0000000000000001 - Name=Times New Roman - Font Style=-24 0 0 0 700 255 0 0 0 3 2 1 18 - Text=Select Components - Text French=Sélectionner les composants - Text German=Komponenten auswählen - Text Spanish=Seleccione componentes - Text Italian=Selezionare i componenti - end - item: Checkbox - Rectangle=86 75 256 129 - Variable=COMPONENTS - Create Flags=01010000000000010000000000000011 - Flags=0000000000000110 - Text=Tcl Run-Time Files - Text=Example Scripts - Text=Help Files - Text=Header and Library Files - Text= - Text French=Tcl Run-Time Files - Text French=Example Scripts - Text French=Help Files - Text French=Header and Library Files - Text French= - Text German=Tcl Run-Time Files - Text German=Example Scripts - Text German=Help Files - Text German=Header and Library Files - Text German= - Text Spanish=Tcl Run-Time Files - Text Spanish=Example Scripts - Text Spanish=Help Files - Text Spanish=Header and Library Files - Text Spanish= - Text Italian=Tcl Run-Time Files - Text Italian=Example Scripts - Text Italian=Help Files - Text Italian=Header and Library Files - Text Italian= - end - item: Static - Rectangle=194 162 242 172 - Variable=COMPONENTS - Value=MAINDIR - Create Flags=01010000000000000000000000000010 - end - item: Static - Rectangle=194 153 242 162 - Variable=COMPONENTS - Create Flags=01010000000000000000000000000010 - end - item: Static - Rectangle=107 153 196 164 - Create Flags=01010000000000000000000000000000 - Text=Disk Space Required: - Text French=Espace disque requis : - Text German=Notwendiger Speicherplatz: - Text Spanish=Espacio requerido en el disco: - Text Italian=Spazio su disco necessario: - end - item: Static - Rectangle=107 162 196 172 - Create Flags=01010000000000000000000000000000 - Text=Disk Space Remaining: - Text French=Espace disque disponible : - Text German=Verbleibender Speicherplatz: - Text Spanish=Espacio en disco disponible: - Text Italian=Spazio su disco disponibile: - end - item: Static - Rectangle=86 145 256 175 - Action=1 - Create Flags=01010000000000000000000000000111 - end - item: Static - Rectangle=86 42 256 61 - Create Flags=01010000000000000000000000000000 - Text=Choose which components to install by checking the boxes below. - Text French=Choisissez les composants que vous voulez installer en cochant les cases ci-dessous. - Text German=Wählen Sie die zu installierenden Komponenten, indem Sie in die entsprechenden Kästchen klicken. - Text Spanish=Elija los componentes que desee instalar marcando los cuadros de abajo. - Text Italian=Scegliere quali componenti installare selezionando le caselle sottostanti. - end - end -end -item: Custom Dialog Set - Name=Select Program Manager Group - Display Variable=DISPLAY - item: Dialog - Title=%APPTITLE% Installation - Title French=Installation de %APPTITLE% - Title German=Installation von %APPTITLE% - Title Spanish=Instalación de %APPTITLE% - Title Italian=Installazione di %APPTITLE% - Width=271 - Height=224 - Font Name=Helv - Font Size=8 - item: Push Button - Rectangle=150 187 195 202 - Variable=DIRECTION - Value=N - Create Flags=01010000000000010000000000000001 - Text=&Next > - Text French=&Suite > - Text German=&Weiter > - Text Spanish=&Siguiente > - Text Italian=&Avanti > - end - item: Push Button - Rectangle=105 187 150 202 - Variable=DIRECTION - Value=B - Create Flags=01010000000000010000000000000000 - Flags=0000000000000001 - Text=< &Back - Text French=< &Retour - Text German=< &Zurück - Text Spanish=< &Atrás - Text Italian=< &Indietro - end - item: Push Button - Rectangle=211 187 256 202 - Action=3 - Create Flags=01010000000000010000000000000000 - Text=&Cancel - Text French=&Annuler - Text German=&Abbrechen - Text Spanish=&Cancelar - Text Italian=&Annulla - end - item: Static - Rectangle=8 180 256 181 - Action=3 - Create Flags=01010000000000000000000000000111 - end - item: Static - Rectangle=86 8 258 42 - Create Flags=01010000000000000000000000000000 - Flags=0000000000000001 - Name=Times New Roman - Font Style=-24 0 0 0 700 255 0 0 0 3 2 1 18 - Text=Select ProgMan Group - Text French=Sélectionner le groupe du Gestionnaire de programme - Text German=Bestimmung der Programm-Managergruppe - Text Spanish=Seleccione grupo del Administrador de programas - Text Italian=Selezionare il gruppo ProgMan - end - item: Static - Rectangle=86 44 256 68 - Create Flags=01010000000000000000000000000000 - Text=Enter the name of the Program Manager group to add the %APPTITLE% icons to: - Text French=Entrez le nom du groupe du Gestionnaire de programme dans lequel vous souhaitez ajouter les icônes de %APPTITLE% : - Text German=Geben Sie den Namen der Programmgruppe ein, der das Symbol %APPTITLE% hinzugefügt werden soll: - Text Spanish=Escriba el nombre del grupo del Administrador de programas en el que desea agregar los iconos de %APPTITLE%: - Text Italian=Inserire il nome del gruppo Program Manager per aggiungere le icone %APPTITLE% a: - end - item: Combobox - Rectangle=86 69 256 175 - Variable=GROUP - Create Flags=01010000000000010000001000000001 - Flags=0000000000000001 - Text=%GROUP% - Text French=%GROUP% - Text German=%GROUP% - Text Spanish=%GROUP% - Text Italian=%GROUP% - end - end -end -item: Custom Dialog Set - Name=Start Installation - Display Variable=DISPLAY - item: Dialog - Title=%APPTITLE% Installation - Title French=Installation de %APPTITLE% - Title German=Installation von %APPTITLE% - Title Spanish=Instalación de %APPTITLE% - Title Italian=Installazione di %APPTITLE% - Width=271 - Height=224 - Font Name=Helv - Font Size=8 - item: Push Button - Rectangle=150 187 195 202 - Variable=DIRECTION - Value=N - Create Flags=01010000000000010000000000000001 - Text=&Next > - Text French=&Suite > - Text German=&Weiter > - Text Spanish=&Siguiente > - Text Italian=&Avanti > - end - item: Push Button - Rectangle=105 187 150 202 - Variable=DIRECTION - Value=B - Create Flags=01010000000000010000000000000000 - Text=< &Back - Text French=< &Retour - Text German=< &Zurück - Text Spanish=< &Atrás - Text Italian=< &Indietro - end - item: Push Button - Rectangle=211 187 256 202 - Action=3 - Create Flags=01010000000000010000000000000000 - Text=&Cancel - Text French=&Annuler - Text German=&Abbrechen - Text Spanish=&Cancelar - Text Italian=&Annulla - end - item: Static - Rectangle=8 180 256 181 - Action=3 - Create Flags=01010000000000000000000000000111 - end - item: Static - Rectangle=86 8 258 42 - Create Flags=01010000000000000000000000000000 - Flags=0000000000000001 - Name=Times New Roman - Font Style=-24 0 0 0 700 255 0 0 0 3 2 1 18 - Text=Ready to Install! - Text French=Prêt à installer ! - Text German=Installationsbereit! - Text Spanish=¡Preparado para la instalación! - Text Italian=Pronto per l'installazione! - end - item: Static - Rectangle=86 42 256 102 - Create Flags=01010000000000000000000000000000 - Text=You are now ready to install %APPTITLE%. - Text= - Text=Press the Next button to begin the installation or the Back button to reenter the installation information. - Text French=Vous êtes maintenant prêt à installer les fichiers %APPTITLE%. - Text French= - Text French=Cliquez sur le bouton Suite pour commencer l'installation ou sur le bouton Retour pour entrer les informations d'installation à nouveau. - Text German=Sie können %APPTITLE% nun installieren. - Text German= - Text German=Klicken Sie auf "Weiter", um mit der Installation zu beginnen. Klicken Sie auf "Zurück", um die Installationsinformationen neu einzugeben. - Text Spanish=Ya está listo para instalar %APPTITLE%. - Text Spanish= - Text Spanish=Presione el botón Siguiente para comenzar la instalación o presione Atrás para volver a ingresar la información para la instalación. - Text Italian=Ora è possibile installare %APPTITLE%. - Text Italian= - Text Italian=Premere il pulsante Avanti per avviare l'installazione o il pulsante Indietro per reinserire le informazioni di installazione. - end - end -end -item: If/While Statement - Variable=DISPLAY - Value=Select Destination Directory -end -item: Set Variable - Variable=BACKUP - Value=%MAINDIR%\BACKUP -end -item: End Block -end -item: End Block -end -item: If/While Statement - Variable=TYPE - Value=B -end -item: Set Variable - Variable=COMPONENTS - Value=A -end -item: End Block -end -item: If/While Statement - Variable=DOBACKUP - Value=A -end -item: Set Variable - Variable=BACKUPDIR - Value=%BACKUP% -end -item: End Block -end -remarked item: If/While Statement - Variable=BRANDING - Value=1 -end -remarked item: If/While Statement - Variable=DOBRAND - Value=1 -end -remarked item: Edit INI File - Pathname=%INST%\CUSTDATA.INI - Settings=[Registration] - Settings=NAME=%NAME% - Settings=COMPANY=%COMPANY% - Settings= -end -remarked item: End Block -end -remarked item: End Block -end -item: Set Variable - Variable=MAINDIRSHORT - Value=%MAINDIR% - Flags=00010100 -end -item: Open/Close INSTALL.LOG -end -item: Check Disk Space - Component=COMPONENTS -end -item: Install File - Source=${__TCLBASEDIR__}\license.txt - Destination=%MAINDIR%\license.txt - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\win\Readme.txt - Destination=%MAINDIR%\Readme.txt - Flags=0000000000000010 -end -item: If/While Statement - Variable=COMPONENTS - Value=D - Flags=00001010 -end -item: Install File - Source=${__TKBASEDIR__}\win\release\tk85.lib - Destination=%MAINDIR%\lib\tk85.lib - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\win\release\tkstub85.lib - Destination=%MAINDIR%\lib\tkstub85.lib - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\win\release\tcl85.lib - Destination=%MAINDIR%\lib\tcl85.lib - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\win\release\tclstub85.lib - Destination=%MAINDIR%\lib\tclstub85.lib - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\xlib\X11\Xutil.h - Destination=%MAINDIR%\include\X11\Xutil.h - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\xlib\X11\Xlib.h - Destination=%MAINDIR%\include\X11\Xlib.h - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\xlib\X11\Xfuncproto.h - Destination=%MAINDIR%\include\X11\Xfuncproto.h - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\xlib\X11\Xatom.h - Destination=%MAINDIR%\include\X11\Xatom.h - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\xlib\X11\X.h - Destination=%MAINDIR%\include\X11\X.h - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\xlib\X11\keysymdef.h - Destination=%MAINDIR%\include\X11\keysymdef.h - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\xlib\X11\keysym.h - Destination=%MAINDIR%\include\X11\keysym.h - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\xlib\X11\cursorfont.h - Destination=%MAINDIR%\include\X11\cursorfont.h - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\generic\tk.h - Destination=%MAINDIR%\include\tk.h - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\generic\tkDecls.h - Destination=%MAINDIR%\include\tkDecls.h - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\generic\tkPlatDecls.h - Destination=%MAINDIR%\include\tkPlatDecls.h - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\generic\tkIntXlibDecls.h - Destination=%MAINDIR%\include\tkIntXlibDecls.h - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\generic\tcl.h - Destination=%MAINDIR%\include\tcl.h - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\generic\tclDecls.h - Destination=%MAINDIR%\include\tclDecls.h - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\generic\tclPlatDecls.h - Destination=%MAINDIR%\include\tclPlatDecls.h - Flags=0000000000000010 -end -item: End Block -end -item: If/While Statement - Variable=COMPONENTS - Value=A - Flags=00001010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\msgcat\pkgIndex.tcl - Destination=%MAINDIR%\lib\tcl%VER%\msgcat1.4\pkgIndex.tcl - Flags=0000000010000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\msgcat\msgcat.tcl - Destination=%MAINDIR%\lib\tcl%VER%\msgcat1.4\msgcat.tcl - Flags=0000000010000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\tcltest\pkgIndex.tcl - Destination=%MAINDIR%\lib\tcl%VER%\tcltest2.0\pkgIndex.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\tcltest\tcltest.tcl - Destination=%MAINDIR%\lib\tcl%VER%\tcltest2.0\tcltest.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\symbol.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\symbol.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\shiftjis.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\shiftjis.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\macUkraine.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\macUkraine.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\macTurkish.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\macTurkish.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\macThai.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\macThai.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\macRomania.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\macRomania.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\macRoman.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\macRoman.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\macJapan.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\macJapan.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\macIceland.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\macIceland.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\macGreek.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\macGreek.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\macDingbats.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\macDingbats.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\macCyrillic.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\macCyrillic.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\macCroatian.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\macCroatian.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\macCentEuro.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\macCentEuro.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\ksc5601.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\ksc5601.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\koi8-r.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\koi8-r.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\jis0212.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\jis0212.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\jis0208.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\jis0208.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\jis0201.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\jis0201.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\iso8859-15.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso8859-15.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\iso8859-9.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso8859-9.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\iso8859-8.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso8859-8.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\iso8859-7.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso8859-7.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\iso8859-6.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso8859-6.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\iso8859-5.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso8859-5.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\iso8859-4.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso8859-4.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\iso8859-3.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso8859-3.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\iso8859-2.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso8859-2.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\iso8859-1.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso8859-1.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\iso2022.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso2022.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\iso2022-kr.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso2022-kr.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\iso2022-jp.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\iso2022-jp.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\gb2312.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\gb2312.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\gb1988.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\gb1988.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\gb12345.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\gb12345.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\euc-cn.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\euc-cn.enc - Flags=0000000010000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\euc-jp.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\euc-jp.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\euc-kr.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\euc-kr.enc - Flags=0000000010000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\dingbats.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\dingbats.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp950.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp950.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp949.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp949.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp936.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp936.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp932.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp932.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp874.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp874.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp869.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp869.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp866.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp866.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp865.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp865.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp864.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp864.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp863.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp863.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp862.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp862.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp861.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp861.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp860.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp860.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp857.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp857.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp855.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp855.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp852.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp852.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp850.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp850.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp775.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp775.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp737.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp737.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp437.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp437.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp1258.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp1258.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp1257.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp1257.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp1256.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp1256.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp1255.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp1255.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp1254.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp1254.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp1253.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp1253.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp1252.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp1252.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp1251.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp1251.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\cp1250.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\cp1250.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\ascii.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\ascii.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\encoding\big5.enc - Destination=%MAINDIR%\lib\tcl%VER%\encoding\big5.enc - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\opt\pkgIndex.tcl - Destination=%MAINDIR%\lib\tcl%VER%\opt0.4\pkgIndex.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\opt\optparse.tcl - Destination=%MAINDIR%\lib\tcl%VER%\opt0.4\optparse.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\http\pkgIndex.tcl - Destination=%MAINDIR%\lib\tcl%VER%\http2.4\pkgIndex.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\http\http.tcl - Destination=%MAINDIR%\lib\tcl%VER%\http2.4\http.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\msgbox.tcl - Destination=%MAINDIR%\lib\tk%VER%\msgbox.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\optMenu.tcl - Destination=%MAINDIR%\lib\tk%VER%\optMenu.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\clrpick.tcl - Destination=%MAINDIR%\lib\tk%VER%\clrpick.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\entry.tcl - Destination=%MAINDIR%\lib\tk%VER%\entry.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\spinbox.tcl - Destination=%MAINDIR%\lib\tk%VER%\spinbox.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\comdlg.tcl - Destination=%MAINDIR%\lib\tk%VER%\comdlg.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\bgerror.tcl - Destination=%MAINDIR%\lib\tk%VER%\bgerror.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\obsolete.tcl - Destination=%MAINDIR%\lib\tk%VER%\obsolete.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\button.tcl - Destination=%MAINDIR%\lib\tk%VER%\button.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\xmfbox.tcl - Destination=%MAINDIR%\lib\tk%VER%\xmfbox.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\console.tcl - Destination=%MAINDIR%\lib\tk%VER%\console.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\listbox.tcl - Destination=%MAINDIR%\lib\tk%VER%\listbox.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\menu.tcl - Destination=%MAINDIR%\lib\tk%VER%\menu.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\dialog.tcl - Destination=%MAINDIR%\lib\tk%VER%\dialog.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\focus.tcl - Destination=%MAINDIR%\lib\tk%VER%\focus.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\palette.tcl - Destination=%MAINDIR%\lib\tk%VER%\palette.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\tkfbox.tcl - Destination=%MAINDIR%\lib\tk%VER%\tkfbox.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\tk.tcl - Destination=%MAINDIR%\lib\tk%VER%\tk.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\text.tcl - Destination=%MAINDIR%\lib\tk%VER%\text.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\tearoff.tcl - Destination=%MAINDIR%\lib\tk%VER%\tearoff.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\tclIndex - Destination=%MAINDIR%\lib\tk%VER%\tclIndex - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\scrlbar.tcl - Destination=%MAINDIR%\lib\tk%VER%\scrlbar.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\scale.tcl - Destination=%MAINDIR%\lib\tk%VER%\scale.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\safetk.tcl - Destination=%MAINDIR%\lib\tk%VER%\safetk.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\http1.0\pkgIndex.tcl - Destination=%MAINDIR%\lib\tcl%VER%\http1.0\pkgIndex.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\http1.0\http.tcl - Destination=%MAINDIR%\lib\tcl%VER%\http1.0\http.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\reg\pkgIndex.tcl - Destination=%MAINDIR%\lib\tcl%VER%\reg1.0\pkgIndex.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\win\release\tclreg10.dll - Destination=%MAINDIR%\lib\tcl%VER%\reg1.0\tclreg10.dll - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\dde\pkgIndex.tcl - Destination=%MAINDIR%\lib\tcl%VER%\dde1.2\pkgIndex.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\win\release\tcldde12.dll - Destination=%MAINDIR%\lib\tcl%VER%\dde1.2\tcldde12.dll - Flags=0000000000000010 -end -item: Install File - Source=C:\WINNT\SYSTEM32\Msvcrt.dll - Destination=%MAINDIR%\bin\msvcrt.dll - Flags=0010001000000011 -end -item: Install File - Source=${__TKBASEDIR__}\win\release\wish85.exe - Destination=%MAINDIR%\bin\wish85.exe - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\win\release\tclsh85.exe - Destination=%MAINDIR%\bin\tclsh85.exe - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\win\release\tclpip85.dll - Destination=%MAINDIR%\bin\tclpip85.dll - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\win\release\tcl85.dll - Destination=%MAINDIR%\bin\tcl85.dll - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\win\release\tk85.dll - Destination=%MAINDIR%\bin\tk85.dll - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\auto.tcl - Destination=%MAINDIR%\lib\tcl%VER%\auto.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\history.tcl - Destination=%MAINDIR%\lib\tcl%VER%\history.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\init.tcl - Destination=%MAINDIR%\lib\tcl%VER%\init.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\package.tcl - Destination=%MAINDIR%\lib\tcl%VER%\package.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\parray.tcl - Destination=%MAINDIR%\lib\tcl%VER%\parray.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\safe.tcl - Destination=%MAINDIR%\lib\tcl%VER%\safe.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\tclIndex - Destination=%MAINDIR%\lib\tcl%VER%\tclIndex - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\library\word.tcl - Destination=%MAINDIR%\lib\tcl%VER%\word.tcl - Flags=0000000000000010 -end -item: End Block -end -item: If/While Statement - Variable=COMPONENTS - Value=B - Flags=00001010 -end -item: Install File - Source=${__TKBASEDIR__}\library\images\tai-ku.gif - Destination=%MAINDIR%\lib\tk%VER%\images\tai-ku.gif - Flags=0000000010000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\images\teapot.ppm - Destination=%MAINDIR%\lib\tk%VER%\demos\images\teapot.ppm - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\images\tcllogo.gif - Destination=%MAINDIR%\lib\tk%VER%\demos\images\tcllogo.gif - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\images\pattern.bmp - Destination=%MAINDIR%\lib\tk%VER%\demos\images\pattern.bmp - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\images\noletter.bmp - Destination=%MAINDIR%\lib\tk%VER%\demos\images\noletter.bmp - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\images\letters.bmp - Destination=%MAINDIR%\lib\tk%VER%\demos\images\letters.bmp - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\images\gray25.bmp - Destination=%MAINDIR%\lib\tk%VER%\demos\images\gray25.bmp - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\images\flagup.bmp - Destination=%MAINDIR%\lib\tk%VER%\demos\images\flagup.bmp - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\images\flagdown.bmp - Destination=%MAINDIR%\lib\tk%VER%\demos\images\flagdown.bmp - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\images\face.bmp - Destination=%MAINDIR%\lib\tk%VER%\demos\images\face.bmp - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\images\earthris.gif - Destination=%MAINDIR%\lib\tk%VER%\demos\images\earthris.gif - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\images\earth.gif - Destination=%MAINDIR%\lib\tk%VER%\demos\images\earth.gif - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\vscale.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\vscale.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\twind.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\twind.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\text.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\text.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\style.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\style.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\states.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\states.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\search.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\search.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\sayings.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\sayings.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\ruler.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\ruler.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\radio.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\radio.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\puzzle.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\puzzle.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\plot.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\plot.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\msgbox.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\msgbox.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\menubu.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\menubu.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\menu.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\menu.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\label.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\label.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\items.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\items.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\image2.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\image2.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\image1.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\image1.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\icon.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\icon.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\hscale.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\hscale.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\form.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\form.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\ixset - Destination=%MAINDIR%\lib\tk%VER%\demos\ixset.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\rolodex - Destination=%MAINDIR%\lib\tk%VER%\demos\rolodex.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\square - Destination=%MAINDIR%\lib\tk%VER%\demos\square.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\Readme - Destination=%MAINDIR%\lib\tk%VER%\demos\Readme - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\hello - Destination=%MAINDIR%\lib\tk%VER%\demos\hello.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\tclIndex - Destination=%MAINDIR%\lib\tk%VER%\demos\tclIndex - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\browse - Destination=%MAINDIR%\lib\tk%VER%\demos\browse.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\timer - Destination=%MAINDIR%\lib\tk%VER%\demos\timer.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\widget - Destination=%MAINDIR%\lib\tk%VER%\demos\widget.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\tcolor - Destination=%MAINDIR%\lib\tk%VER%\demos\tcolor.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\rmt - Destination=%MAINDIR%\lib\tk%VER%\demos\rmt.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\floor.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\floor.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\filebox.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\filebox.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\images\pwrdLogo75.gif - Destination=%MAINDIR%\lib\tk%VER%\images\pwrdLogo75.gif - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\images\pwrdLogo200.gif - Destination=%MAINDIR%\lib\tk%VER%\images\pwrdLogo200.gif - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\images\pwrdLogo175.gif - Destination=%MAINDIR%\lib\tk%VER%\images\pwrdLogo175.gif - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\images\pwrdLogo150.gif - Destination=%MAINDIR%\lib\tk%VER%\images\pwrdLogo150.gif - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\images\pwrdLogo100.gif - Destination=%MAINDIR%\lib\tk%VER%\images\pwrdLogo100.gif - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\images\logoMed.gif - Destination=%MAINDIR%\lib\tk%VER%\images\logoMed.gif - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\images\logoLarge.gif - Destination=%MAINDIR%\lib\tk%VER%\images\logoLarge.gif - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\images\logo64.gif - Destination=%MAINDIR%\lib\tk%VER%\images\logo64.gif - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\images\logo100.gif - Destination=%MAINDIR%\lib\tk%VER%\images\logo100.gif - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\images\Readme - Destination=%MAINDIR%\lib\tk%VER%\images\Readme - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\arrow.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\arrow.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\bind.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\bind.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\bitmap.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\bitmap.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\button.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\button.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\check.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\check.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\clrpick.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\clrpick.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\colors.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\colors.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\cscroll.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\cscroll.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\ctext.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\ctext.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\dialog1.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\dialog1.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\dialog2.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\dialog2.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\entry1.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\entry1.tcl - Flags=0000000000000010 -end -item: Install File - Source=${__TKBASEDIR__}\library\demos\entry2.tcl - Destination=%MAINDIR%\lib\tk%VER%\demos\entry2.tcl - Flags=0000000000000010 -end -item: End Block -end -item: If/While Statement - Variable=COMPONENTS - Value=C - Flags=00001010 -end -item: Install File - Source=${__TCLBASEDIR__}\tools\tcl85.cnt - Destination=%MAINDIR%\doc\tcl85.cnt - Flags=0000000000000010 -end -item: Install File - Source=${__TCLBASEDIR__}\tools\tcl85.hlp - Destination=%MAINDIR%\doc\tcl85.hlp - Flags=0000000000000010 -end -item: End Block -end -item: Set Variable - Variable=MAINDIR - Value=%MAINDIR% - Flags=00010100 -end -item: Include Script - Pathname=\\pop\tools\1.2\win32-ix86\wise\INCLUDE\uninstal.wse -end -item: Check Configuration - Flags=10111011 -end -item: Get Registry Key Value - Variable=GROUPDIR - Key=Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders - Default=%WIN%\Start Menu\Programs - Value Name=Programs - Flags=00000010 -end -item: Set Variable - Variable=GROUP - Value=%GROUPDIR%\%GROUP% -end -item: If/While Statement - Variable=COMPONENTS - Value=A - Flags=00001010 -end -item: Create Shortcut - Source=%MAINDIR%\bin\wish85.exe - Destination=%GROUP%\Wish.lnk - Working Directory=%MAINDIR% -end -item: End Block -end -item: If/While Statement - Variable=COMPONENTS - Value=A - Flags=00001010 -end -item: Create Shortcut - Source=%MAINDIR%\bin\tclsh85.exe - Destination=%GROUP%\Tclsh.lnk - Working Directory=%MAINDIR% - Key Type=1536 - Flags=00000001 -end -item: End Block -end -item: If/While Statement - Variable=COMPONENTS - Value=C - Flags=00001010 -end -item: Create Shortcut - Source=%MAINDIR%\doc\tcl85.hlp - Destination=%GROUP%\Tcl Help.lnk - Working Directory=%MAINDIR% -end -item: End Block -end -item: Create Shortcut - Source=%MAINDIR%\Readme.txt - Destination=%GROUP%\Readme.lnk - Working Directory=%MAINDIR% -end -item: If/While Statement - Variable=COMPONENTS - Value=B - Flags=00001010 -end -item: Create Shortcut - Source=%MAINDIR%\lib\tk%VER%\demos\widget.tcl - Destination=%GROUP%\Widget Tour.lnk - Working Directory=%MAINDIR% - Key Type=1536 - Flags=00000001 -end -item: End Block -end -item: Else Statement -end -item: If/While Statement - Variable=COMPONENTS - Value=B - Flags=00001010 -end -item: Add ProgMan Icon - Group=%GROUP% - Icon Name=Widget Tour - Command Line=%MAINDIR%\lib\tk%VER%\demos\widget.tcl - Icon Pathname=%MAINDIR%\bin\wish85.exe - Default Directory=%MAINDIR% -end -item: End Block -end -item: If/While Statement - Variable=COMPONENTS - Value=C - Flags=00001010 -end -item: Add ProgMan Icon - Group=%GROUP% - Icon Name=Tcl Help - Command Line=%MAINDIR%\doc\tcl85.hlp - Default Directory=%MAINDIR% -end -item: End Block -end -item: Add ProgMan Icon - Group=%GROUP% - Icon Name=Readme - Command Line=%MAINDIR%\Readme.txt - Default Directory=%MAINDIR% -end -item: If/While Statement - Variable=COMPONENTS - Value=A - Flags=00001010 -end -item: Add ProgMan Icon - Group=%GROUP% - Icon Name=Wish - Command Line=%MAINDIR%\bin\wish85.exe - Default Directory=%MAINDIR% -end -item: End Block -end -item: If/While Statement - Variable=COMPONENTS - Value=A - Flags=00001010 -end -item: Add ProgMan Icon - Group=%GROUP% - Icon Name=Tclsh - Command Line=%MAINDIR%\bin\tclsh85.exe - Default Directory=%MAINDIR% -end -item: End Block -end -item: End Block -end -item: Self-Register OCXs/DLLs - Description=Updating System Configuration, Please Wait... -end -item: Edit Registry - Total Keys=1 - Key=SOFTWARE\Scriptics\Tcl\%VER% - New Value=%MAINDIR% - Value Name=Root - Root=2 -end -item: Edit Registry - Total Keys=1 - Key=TclScript\DefaultIcon - New Value=%MAINDIR%\bin\tk85.dll -end -item: Edit Registry - Total Keys=1 - Key=.tcl - New Value=TclScript -end -item: Edit Registry - Total Keys=1 - Key=TclScript - New Value=TclScript -end -item: Edit Registry - Total Keys=1 - Key=TclScript\shell\open\command - New Value=%MAINDIRSHORT%\bin\wish85.exe "%%1" %%* -end -item: Edit Registry - Total Keys=1 - Key=TclScript\shell\edit - New Value=&Edit -end -item: Edit Registry - Total Keys=1 - Key=TclScript\shell\edit\command - New Value=notepad "%%1" -end -item: Add Directory to Path - Directory=%MAINDIR%\bin -end -item: Check Configuration - Flags=10111011 -end -item: Set Variable - Variable=TO_SCRIPTICS - Value=A -end -item: Else Statement -end -item: Set Variable - Variable=TO_SCRIPTICS -end -item: End Block -end -item: Wizard Block - Direction Variable=DIRECTION - Display Variable=DISPLAY - Bitmap Pathname=%_WISE_%\DIALOGS\TEMPLATE\WIZARD.BMP - X Position=9 - Y Position=10 - Filler Color=8421440 - Flags=00000011 -end -item: Custom Dialog Set - Name=Finished - Display Variable=DISPLAY - item: Dialog - Title=%APPTITLE% Installation - Title French=Installation de %APPTITLE% - Title German=Installation von %APPTITLE% - Title Spanish=Instalación de %APPTITLE% - Title Italian=Installazione di %APPTITLE% - Width=271 - Height=224 - Font Name=Helv - Font Size=8 - item: Push Button - Rectangle=150 187 195 202 - Variable=DIRECTION - Value=N - Create Flags=01010000000000010000000000000001 - Text=&Finish - Text French=&Fin - Text German=&Weiter - Text Spanish=&Terminar - Text Italian=&Fine - end - item: Push Button - Rectangle=105 187 150 202 - Variable=DISABLED - Value=! - Create Flags=01010000000000010000000000000000 - Text=< &Back - Text French=< &Retour - Text German=< &Zurück - Text Spanish=< &Atrás - Text Italian=< &Indietro - end - item: Push Button - Rectangle=211 187 256 202 - Variable=DISABLED - Value=! - Action=3 - Create Flags=01010000000000010000000000000000 - Text=&Cancel - Text French=&Annuler - Text German=&Abbrechen - Text Spanish=&Cancelar - Text Italian=&Annulla - end - item: Static - Rectangle=8 180 256 181 - Action=3 - Create Flags=01010000000000000000000000000111 - end - item: Static - Rectangle=86 8 258 42 - Create Flags=01010000000000000000000000000000 - Flags=0000000000000001 - Name=Times New Roman - Font Style=-24 0 0 0 700 255 0 0 0 3 2 1 18 - Text=Installation Completed! - Text French=Installation terminée ! - Text German=Die Installation ist abgeschlossen! - Text Spanish=¡Instalación terminada! - Text Italian=Installazione completata! - end - item: Static - Rectangle=86 42 256 153 - Create Flags=01010000000000000000000000000000 - Text=%APPTITLE% has been successfully installed. - Text= - Text=Click the Finish button to exit this installation. - Text= - Text=You can learn more about Tcl/Tk %VER%, including release notes, updates, tutorials, and more at %URL%. Check the box below to start your web browser and go there now. - Text= - Text=The installer may ask you to reboot your computer, this is to update your PATH and is not necessary to do immediately. - Text French=%APPTITLE% est maintenant installé. - Text French= - Text French=Cliquez sur le bouton Fin pour quitter l'installation. - Text German=%APPTITLE% wurde erfolgreich installiert. - Text German= - Text German=Klicken Sie auf "Weiter", um die Installation zu beenden. - Text Spanish=%APPTITLE% se ha instalado con éxito. - Text Spanish= - Text Spanish=Presione el botón Terminar para salir de esta instalación. - Text Italian=L'installazione %APPTITLE% è stata portata a termine con successo. - Text Italian= - Text Italian=Premere il pulsante Fine per uscire dall'installazione. - end - item: Checkbox - Rectangle=88 143 245 157 - Variable=TO_SCRIPTICS - Enabled Color=00000000000000001111111111111111 - Create Flags=01010000000000010000000000000011 - Text=Show me important information about - Text= - end - item: Static - Rectangle=99 156 245 170 - Enabled Color=00000000000000001111111111111111 - Create Flags=01010000000000000000000000000000 - Text=Tcl/Tk %VER% and TclPro - end - end -end -item: End Block -end -item: Check Configuration - Flags=10111011 -end -item: If/While Statement - Variable=TO_SCRIPTICS - Value=A - Flags=00000010 -end -item: Execute Program - Command Line=%URL% -end -item: End Block -end -item: Execute Program - Pathname=explorer - Command Line=%GROUP% -end -item: End Block -end diff --git a/tools/tclSplash.bmp b/tools/tclSplash.bmp Binary files differdeleted file mode 100644 index db8a17e..0000000 --- a/tools/tclSplash.bmp +++ /dev/null diff --git a/tools/tclmin.wse b/tools/tclmin.wse deleted file mode 100644 index 2fd8185..0000000 --- a/tools/tclmin.wse +++ /dev/null @@ -1,247 +0,0 @@ -Document Type: WSE -item: Global - Version=5.0 - Flags=00000100 - Split=1420 - Languages=65 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 - Japanese Font Name=MS Gothic - Japanese Font Size=10 - Start Gradient=0 0 255 - End Gradient=0 0 0 - Windows Flags=00000000000000010010110000001000 - Message Font=MS Sans Serif - Font Size=8 - Disk Filename=SETUP - Patch Flags=0000000000000001 - Patch Threshold=85 - Patch Memory=4000 -end -item: Remark - Text=------- -end -item: Remark - Text=Tcl 8.0 Minimal Installation -end -item: Remark - Text=------- -end -item: Install File - Source=n:\dist\tcl8.0\library\opt0.4\pkgIndex.tcl - Destination=%MAINDIR%\lib\tcl%VER%\opt0.4\pkgIndex.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tcl8.0\library\opt0.4\optparse.tcl - Destination=%MAINDIR%\lib\tcl%VER%\opt0.4\optparse.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tcl8.0\library\http\pkgIndex.tcl - Destination=%MAINDIR%\lib\tcl%VER%\http2.4\pkgIndex.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tcl8.0\library\http\http.tcl - Destination=%MAINDIR%\lib\tcl%VER%\http2.4\http.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tcl8.0\library\safe.tcl - Destination=%MAINDIR%\lib\tcl%VER%\safe.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tcl8.0\library\history.tcl - Destination=%MAINDIR%\lib\tcl%VER%\history.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\msgbox.tcl - Destination=%MAINDIR%\lib\tk%VER%\msgbox.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\optMenu.tcl - Destination=%MAINDIR%\lib\tk%VER%\optMenu.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\clrpick.tcl - Destination=%MAINDIR%\lib\tk%VER%\clrpick.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\entry.tcl - Destination=%MAINDIR%\lib\tk%VER%\entry.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\comdlg.tcl - Destination=%MAINDIR%\lib\tk%VER%\comdlg.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\bgerror.tcl - Destination=%MAINDIR%\lib\tk%VER%\bgerror.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\obsolete.tcl - Destination=%MAINDIR%\lib\tk%VER%\obsolete.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\button.tcl - Destination=%MAINDIR%\lib\tk%VER%\button.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\xmfbox.tcl - Destination=%MAINDIR%\lib\tk%VER%\xmfbox.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\console.tcl - Destination=%MAINDIR%\lib\tk%VER%\console.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\listbox.tcl - Destination=%MAINDIR%\lib\tk%VER%\listbox.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\menu.tcl - Destination=%MAINDIR%\lib\tk%VER%\menu.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\dialog.tcl - Destination=%MAINDIR%\lib\tk%VER%\dialog.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\focus.tcl - Destination=%MAINDIR%\lib\tk%VER%\focus.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\palette.tcl - Destination=%MAINDIR%\lib\tk%VER%\palette.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\tkfbox.tcl - Destination=%MAINDIR%\lib\tk%VER%\tkfbox.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\tk.tcl - Destination=%MAINDIR%\lib\tk%VER%\tk.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\text.tcl - Destination=%MAINDIR%\lib\tk%VER%\text.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\tearoff.tcl - Destination=%MAINDIR%\lib\tk%VER%\tearoff.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\tclIndex - Destination=%MAINDIR%\lib\tk%VER%\tclIndex - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\scrlbar.tcl - Destination=%MAINDIR%\lib\tk%VER%\scrlbar.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\scale.tcl - Destination=%MAINDIR%\lib\tk%VER%\scale.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tk8.0\library\safetk.tcl - Destination=%MAINDIR%\lib\tk%VER%\safetk.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tcl8.0\library\http1.0\pkgIndex.tcl - Destination=%MAINDIR%\lib\tcl%VER%\http1.0\pkgIndex.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tcl8.0\library\http1.0\http.tcl - Destination=%MAINDIR%\lib\tcl%VER%\http1.0\http.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tcl8.0\win\pkgIndex.tcl - Destination=%MAINDIR%\lib\tcl%VER%\reg1.0\pkgIndex.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tcl8.0\win\tclreg80.dll - Destination=%MAINDIR%\lib\tcl%VER%\reg1.0\tclreg80.dll - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tcl8.0\win\Tcl1680.dll - Destination=%SYS32%\Tcl1680.dll - Flags=0000001000000010 -end -item: Install File - Source=n:\dist\tcl8.0\win\tcl80.dll - Destination=%SYS32%\tcl80.dll - Flags=0000001000000010 -end -item: Install File - Source=n:\dist\tcl8.0\win\tclpip80.dll - Destination=%SYS32%\tclpip80.dll - Flags=0000001000000010 -end -item: Install File - Source=n:\dist\Bc45\Bin\cw3215.dll - Destination=%SYS32%\cw3215.dll - Flags=0000001000000010 -end -item: Install File - Source=n:\dist\tk8.0\win\tk80.dll - Destination=%SYS32%\tk80.dll - Flags=0000001000000010 -end -item: Install File - Source=n:\dist\tk8.0\win\wish80.exe - Destination=%MAINDIR%\bin\wish80.exe - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tcl8.0\win\tclsh80.exe - Destination=%MAINDIR%\bin\tclsh80.exe - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tcl8.0\library\tclIndex - Destination=%MAINDIR%\lib\tcl%VER%\tclIndex - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tcl8.0\library\init.tcl - Destination=%MAINDIR%\lib\tcl%VER%\init.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tcl8.0\library\parray.tcl - Destination=%MAINDIR%\lib\tcl%VER%\parray.tcl - Flags=0000000000000010 -end -item: Install File - Source=n:\dist\tcl8.0\library\word.tcl - Destination=%MAINDIR%\lib\tcl%VER%\word.tcl - Flags=0000000000000010 -end diff --git a/tools/tcltk-man2html-utils.tcl b/tools/tcltk-man2html-utils.tcl index c0c6a75..d02bcb6 100644 --- a/tools/tcltk-man2html-utils.tcl +++ b/tools/tcltk-man2html-utils.tcl @@ -636,6 +636,7 @@ proc output-name {line} { lappend manual(wing-toc) $name lappend manual(name-$name) $manual(wing-file)/$manual(name) } + set manual(tooltip-$manual(wing-file)/$manual(name).htm) $line } ## @@ -943,7 +944,9 @@ proc output-directive {line} { set line [next-text] if {[is-a-directive $line]} { backup-text 1 - output-name [join $names { }] + if {[llength $names]} { + output-name [join $names { }] + } return } lappend names [string trim $line] @@ -1254,7 +1257,11 @@ proc make-manpage-section {outputDir sectionDescriptor} { # whistle puts stderr "scanning section $manual(wing-name)" # put the entry for this section into the short table of contents - puts $manual(short-toc-fp) "<DT><A HREF=\"$manual(wing-file)/[indexfile]\">$manual(wing-name)</A></DT><DD>$manual(wing-description)</DD>" + if {[regexp {^(.+), version (.+)$} $manual(wing-name) -> name version]} { + puts $manual(short-toc-fp) "<DT><A HREF=\"$manual(wing-file)/[indexfile]\" TITLE=\"version $version\">$name</A></DT><DD>$manual(wing-description)</DD>" + } else { + puts $manual(short-toc-fp) "<DT><A HREF=\"$manual(wing-file)/[indexfile]\">$manual(wing-name)</A></DT><DD>$manual(wing-description)</DD>" + } # initialize the wing table of contents puts $manual(wing-toc-fp) [htmlhead $manual(wing-name) \ $manual(wing-name) $overall_title "../[indexfile]"] @@ -1329,7 +1336,7 @@ proc make-manpage-section {outputDir sectionDescriptor} { } switch -exact -- $code { .if - .nr - .ti - .in - .ie - .el - - .ad - .na - .so - .ne - .AS - .VE - .VS - . { + .ad - .na - .so - .ne - .AS - .HS - .VE - .VS - . { # ignore continue } @@ -1565,8 +1572,16 @@ proc make-manpage-section {outputDir sectionDescriptor} { set tail [lindex $tail [expr {[llength $tail]-1}]] } set tail [file tail $tail] - append rows([expr {$n%$nrows}]) \ - "<td> <a href=\"$tail.htm\">$name</a> </td>" + if {[info exists manual(tooltip-$manual(wing-file)/$tail.htm)]} { + set tooltip $manual(tooltip-$manual(wing-file)/$tail.htm) + set tooltip [string map {[ {\[} ] {\]} $ {\$} \\ \\\\} $tooltip] + regsub {^[^-]+-\s*(.)} $tooltip {[string totitle \1]} tooltip + append rows([expr {$n%$nrows}]) \ + "<td> <a href=\"$tail.htm\" title=\"[subst $tooltip]\">$name</a> </td>" + } else { + append rows([expr {$n%$nrows}]) \ + "<td> <a href=\"$tail.htm\">$name</a> </td>" + } incr n } puts $manual(wing-toc-fp) <table> diff --git a/tools/tcltk-man2html.tcl b/tools/tcltk-man2html.tcl index 585d76a..665a1d4 100755 --- a/tools/tcltk-man2html.tcl +++ b/tools/tcltk-man2html.tcl @@ -328,7 +328,15 @@ proc make-man-pages {html args} { foreach man $manual(keyword-$k) { set name [lindex $man 0] set file [lindex $man 1] - lappend refs "<A HREF=\"../$file\">$name</A>" + if {[info exists manual(tooltip-$file)]} { + set tooltip $manual(tooltip-$file) + if {[string match {*[<>""]*} $tooltip]} { + manerror "bad tooltip for $file: \"$tooltip\"" + } + lappend refs "<A HREF=\"../$file\" TITLE=\"$tooltip\">$name</A>" + } else { + lappend refs "<A HREF=\"../$file\">$name</A>" + } } puts $afp "[join $refs {, }]</DD>" } @@ -420,9 +428,18 @@ proc make-man-pages {html args} { ## ## Helper for assembling the descriptions of base packages (i.e., Tcl and Tk). ## -proc plus-base {var glob name dir desc} { +proc plus-base {var root glob name dir desc} { global tcltkdir if {$var} { + if {[file exists $tcltkdir/$root/README]} { + set f [open $tcltkdir/$root/README] + set d [read $f] + close $f + if {[regexp {This is the \w+ (\S+) source distribution} $d -> version]} { + append name ", version $version" + } + } + set glob $root/$glob return [list $tcltkdir/$glob $name $dir $desc] } } @@ -655,14 +672,14 @@ try { make-man-pages $webdir \ [list $tcltkdir/{$appdir}/doc/*.1 "$tcltkdesc Applications" UserCmd \ "The interpreters which implement $cmdesc."] \ - [plus-base $build_tcl $tcldir/doc/*.n {Tcl Commands} TclCmd \ + [plus-base $build_tcl $tcldir doc/*.n {Tcl Commands} TclCmd \ "The commands which the <B>tclsh</B> interpreter implements."] \ - [plus-base $build_tk $tkdir/doc/*.n {Tk Commands} TkCmd \ + [plus-base $build_tk $tkdir doc/*.n {Tk Commands} TkCmd \ "The additional commands which the <B>wish</B> interpreter implements."] \ {*}[plus-pkgs n {*}$packageDirNameMap] \ - [plus-base $build_tcl $tcldir/doc/*.3 {Tcl C API} TclLib \ + [plus-base $build_tcl $tcldir doc/*.3 {Tcl C API} TclLib \ "The C functions which a Tcl extended C program may use."] \ - [plus-base $build_tk $tkdir/doc/*.3 {Tk C API} TkLib \ + [plus-base $build_tk $tkdir doc/*.3 {Tk C API} TkLib \ "The additional C functions which a Tk extended C program may use."] \ {*}[plus-pkgs 3 {*}$packageDirNameMap] } on error {msg opts} { diff --git a/unix/Makefile.in b/unix/Makefile.in index 068cb12..4f66646 100644 --- a/unix/Makefile.in +++ b/unix/Makefile.in @@ -839,15 +839,15 @@ install-libraries: libraries do \ $(INSTALL_DATA) $$i "$(SCRIPT_INSTALL_DIR)"/http1.0; \ done; - @echo "Installing package http 2.8.4 as a Tcl Module"; - @$(INSTALL_DATA) $(TOP_DIR)/library/http/http.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.6/http-2.8.4.tm; + @echo "Installing package http 2.8.5 as a Tcl Module"; + @$(INSTALL_DATA) $(TOP_DIR)/library/http/http.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.6/http-2.8.5.tm; @echo "Installing package opt0.4 files to $(SCRIPT_INSTALL_DIR)/opt0.4/"; @for i in $(TOP_DIR)/library/opt/*.tcl ; \ do \ $(INSTALL_DATA) $$i "$(SCRIPT_INSTALL_DIR)"/opt0.4; \ done; - @echo "Installing package msgcat 1.4.5 as a Tcl Module"; - @$(INSTALL_DATA) $(TOP_DIR)/library/msgcat/msgcat.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.5/msgcat-1.4.5.tm; + @echo "Installing package msgcat 1.5.0 as a Tcl Module"; + @$(INSTALL_DATA) $(TOP_DIR)/library/msgcat/msgcat.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.5/msgcat-1.5.0.tm; @echo "Installing package tcltest 2.3.4 as a Tcl Module"; @$(INSTALL_DATA) $(TOP_DIR)/library/tcltest/tcltest.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.5/tcltest-2.3.4.tm; @@ -856,7 +856,7 @@ install-libraries: libraries @echo "Installing package platform::shell 1.1.4 as a Tcl Module"; @$(INSTALL_DATA) $(TOP_DIR)/library/platform/shell.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.4/platform/shell-1.1.4.tm; - @echo "Installing library encoding files to $(SCRIPT_INSTALL_DIR)/encoding/"; + @echo "Installing encoding files to $(SCRIPT_INSTALL_DIR)/encoding/"; @for i in $(TOP_DIR)/library/encoding/*.enc ; do \ $(INSTALL_DATA) $$i "$(SCRIPT_INSTALL_DIR)"/encoding; \ done; @@ -867,7 +867,7 @@ install-libraries: libraries fi install-tzdata: ${NATIVE_TCLSH} - @echo "Installing time zone data" + @echo "Installing time zone files to $(SCRIPT_INSTALL_DIR)/tzdata/" @${NATIVE_TCLSH} $(TOOL_DIR)/installData.tcl \ $(TOP_DIR)/library/tzdata "$(SCRIPT_INSTALL_DIR)"/tzdata @@ -894,17 +894,17 @@ install-doc: doc else true; \ fi; \ done; - @echo "Installing and cross-linking top-level (.1) docs"; + @echo "Installing and cross-linking top-level (.1) docs to $(MAN1_INSTALL_DIR)/"; @for i in $(TOP_DIR)/doc/*.1; do \ $(SHELL) $(UNIX_DIR)/installManPage $(MAN_FLAGS) $$i "$(MAN1_INSTALL_DIR)"; \ done - @echo "Installing and cross-linking C API (.3) docs"; + @echo "Installing and cross-linking C API (.3) docs to $(MAN3_INSTALL_DIR)/"; @for i in $(TOP_DIR)/doc/*.3; do \ $(SHELL) $(UNIX_DIR)/installManPage $(MAN_FLAGS) $$i "$(MAN3_INSTALL_DIR)"; \ done - @echo "Installing and cross-linking command (.n) docs"; + @echo "Installing and cross-linking command (.n) docs to $(MANN_INSTALL_DIR)/"; @for i in $(TOP_DIR)/doc/*.n; do \ $(SHELL) $(UNIX_DIR)/installManPage $(MAN_FLAGS) $$i "$(MANN_INSTALL_DIR)"; \ done @@ -1928,7 +1928,6 @@ dist: $(UNIX_DIR)/configure $(UNIX_DIR)/tclConfig.h.in $(UNIX_DIR)/tcl.pc.in $(M $(UNIX_DIR)/tcl.pc.in $(DISTDIR)/unix chmod 775 $(DISTDIR)/unix/configure $(DISTDIR)/unix/configure.in chmod 775 $(DISTDIR)/unix/ldAix - chmod +x $(DISTDIR)/unix/install-sh mkdir $(DISTDIR)/generic cp -p $(GENERIC_DIR)/*.[cdh] $(DISTDIR)/generic cp -p $(GENERIC_DIR)/*.decls $(DISTDIR)/generic @@ -2013,11 +2012,9 @@ dist: $(UNIX_DIR)/configure $(UNIX_DIR)/tclConfig.h.in $(UNIX_DIR)/tcl.pc.in $(M cp -p $(TOOL_DIR)/Makefile.in $(TOOL_DIR)/README \ $(TOOL_DIR)/configure $(TOOL_DIR)/configure.in \ $(TOOL_DIR)/*.tcl $(TOOL_DIR)/man2tcl.c \ - $(TOOL_DIR)/tcl.wse.in $(TOOL_DIR)/*.bmp \ - $(TOOL_DIR)/tcl.hpj.in \ + $(TOOL_DIR)/*.bmp $(TOOL_DIR)/tcl.hpj.in \ $(DISTDIR)/tools - $(NATIVE_TCLSH) $(TOOL_DIR)/eolFix.tcl -crlf $(DISTDIR)/tools/tcl.hpj.in \ - $(DISTDIR)/tools/tcl.wse.in + $(NATIVE_TCLSH) $(TOOL_DIR)/eolFix.tcl -crlf $(DISTDIR)/tools/tcl.hpj.in mkdir $(DISTDIR)/libtommath cp -p $(TOMMATH_SRCS) $(TOMMATH_DIR)/*.h \ $(DISTDIR)/libtommath diff --git a/unix/configure b/unix/configure index 2e36ad2..cbb10b4 100755 --- a/unix/configure +++ b/unix/configure @@ -1335,7 +1335,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu TCL_VERSION=8.6 TCL_MAJOR_VERSION=8 TCL_MINOR_VERSION=6 -TCL_PATCH_LEVEL="b2" +TCL_PATCH_LEVEL="b3" VERSION=${TCL_VERSION} #------------------------------------------------------------------------ @@ -1355,7 +1355,10 @@ fi #------------------------------------------------------------------------ # Empty slate for bundled packages, to avoid stale configuration #------------------------------------------------------------------------ -rm -Rf pkgs +#rm -Rf pkgs +if test -f Makefile; then + make distclean-packages +fi #------------------------------------------------------------------------ # Handle the --prefix=... option @@ -8757,7 +8760,7 @@ else arch=`isainfo` echo "$as_me:$LINENO: checking whether to use -lsunmath for fp rounding control" >&5 echo $ECHO_N "checking whether to use -lsunmath for fp rounding control... $ECHO_C" >&6 - if test "$arch" = "amd64 i386"; then + if test "$arch" = "amd64 i386" -o "$arch" = "i386"; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 @@ -8956,7 +8959,7 @@ else fi case $system in - SunOS-5.[1-9][0-9]*) + SunOS-5.[1-9][0-9]*|SunOS-5.[7-9]) SHLIB_LD="\${CC} -G -z $textmode \${LDFLAGS}";; *) SHLIB_LD="/usr/ccs/bin/ld -G -z $textmode";; @@ -19437,8 +19440,8 @@ _ACEOF HTML_DIR="${libdir}/Resources/Documentation/Reference/Tcl" EXTRA_INSTALL="install-private-headers html-tcl" EXTRA_BUILD_HTML='@ln -fs contents.htm "$(HTML_INSTALL_DIR)"/TclTOC.html' - EXTRA_INSTALL_BINARIES='@echo "Installing Info.plist to $(LIB_INSTALL_DIR)/Resources" && mkdir -p "$(LIB_INSTALL_DIR)/Resources" && $(INSTALL_DATA) Tcl-Info.plist "$(LIB_INSTALL_DIR)/Resources/Info.plist"' - EXTRA_INSTALL_BINARIES="$EXTRA_INSTALL_BINARIES"' && echo "Installing license.terms to $(LIB_INSTALL_DIR)/Resources" && $(INSTALL_DATA) "$(TOP_DIR)/license.terms" "$(LIB_INSTALL_DIR)/Resources"' + EXTRA_INSTALL_BINARIES='@echo "Installing Info.plist to $(LIB_INSTALL_DIR)/Resources/" && $(INSTALL_DATA_DIR) "$(LIB_INSTALL_DIR)/Resources" && $(INSTALL_DATA) Tcl-Info.plist "$(LIB_INSTALL_DIR)/Resources/Info.plist"' + EXTRA_INSTALL_BINARIES="$EXTRA_INSTALL_BINARIES"' && echo "Installing license.terms to $(LIB_INSTALL_DIR)/Resources/" && $(INSTALL_DATA) "$(TOP_DIR)/license.terms" "$(LIB_INSTALL_DIR)/Resources"' EXTRA_INSTALL_BINARIES="$EXTRA_INSTALL_BINARIES"' && echo "Finalizing Tcl.framework" && rm -f "$(LIB_INSTALL_DIR)/../Current" && ln -s "$(VERSION)" "$(LIB_INSTALL_DIR)/../Current" && for f in "$(LIB_FILE)" tclConfig.sh Resources Headers PrivateHeaders; do rm -f "$(LIB_INSTALL_DIR)/../../$$f" && ln -s "Versions/Current/$$f" "$(LIB_INSTALL_DIR)/../.."; done && f="$(STUB_LIB_FILE)" && rm -f "$(LIB_INSTALL_DIR)/../../$$f" && ln -s "Versions/$(VERSION)/$$f" "$(LIB_INSTALL_DIR)/../.."' # Don't use AC_DEFINE for the following as the framework version define # needs to go into the Makefile even when using autoheader, so that we diff --git a/unix/configure.in b/unix/configure.in index 79a546d..f4b695d 100644 --- a/unix/configure.in +++ b/unix/configure.in @@ -25,7 +25,7 @@ m4_ifdef([SC_USE_CONFIG_HEADERS], [ TCL_VERSION=8.6 TCL_MAJOR_VERSION=8 TCL_MINOR_VERSION=6 -TCL_PATCH_LEVEL="b2" +TCL_PATCH_LEVEL="b3" VERSION=${TCL_VERSION} #------------------------------------------------------------------------ @@ -45,7 +45,10 @@ fi #------------------------------------------------------------------------ # Empty slate for bundled packages, to avoid stale configuration #------------------------------------------------------------------------ -rm -Rf pkgs +#rm -Rf pkgs +if test -f Makefile; then + make distclean-packages +fi #------------------------------------------------------------------------ # Handle the --prefix=... option @@ -220,7 +223,7 @@ AC_CHECK_FUNC(realpath, , [AC_DEFINE(NO_REALPATH, 1, [Do we have realpath()])]) SC_TCL_IPV6 -#-------------------------------------------------------------------- +#-------------------------------------------------------------------- # Look for thread-safe variants of some library functions. #-------------------------------------------------------------------- @@ -398,7 +401,7 @@ AC_CHECK_TYPE([intptr_t], [ for tcl_cv_intptr_t in "int" "long" "long long" none; do if test "$tcl_cv_intptr_t" != none; then AC_COMPILE_IFELSE([AC_LANG_BOOL_COMPILE_TRY([AC_INCLUDES_DEFAULT], - [[sizeof (void *) <= sizeof ($tcl_cv_intptr_t)]])], + [[sizeof (void *) <= sizeof ($tcl_cv_intptr_t)]])], [tcl_ok=yes], [tcl_ok=no]) test "$tcl_ok" = yes && break; fi done]) @@ -414,7 +417,7 @@ AC_CHECK_TYPE([uintptr_t], [ none; do if test "$tcl_cv_uintptr_t" != none; then AC_COMPILE_IFELSE([AC_LANG_BOOL_COMPILE_TRY([AC_INCLUDES_DEFAULT], - [[sizeof (void *) <= sizeof ($tcl_cv_uintptr_t)]])], + [[sizeof (void *) <= sizeof ($tcl_cv_uintptr_t)]])], [tcl_ok=yes], [tcl_ok=no]) test "$tcl_ok" = yes && break; fi done]) @@ -681,7 +684,7 @@ AC_ARG_WITH(tzdata, # Any directories that get added here must also be added to the # search path in ::tcl::clock::Initialize (library/clock.tcl). # -case $tcl_ok in +case $tcl_ok in no) AC_MSG_RESULT([supplied by OS vendor]) ;; @@ -708,7 +711,7 @@ case $tcl_ok in fi ;; *) - AC_MSG_ERROR([invalid argument: $tcl_ok]) + AC_MSG_ERROR([invalid argument: $tcl_ok]) ;; esac if test $tcl_ok = yes @@ -782,7 +785,7 @@ TCL_SHARED_LIB_SUFFIX=${SHARED_LIB_SUFFIX} eval "TCL_LIB_FILE=libtcl${LIB_SUFFIX}" # tclConfig.sh needs a version of the _LIB_SUFFIX that has been eval'ed -# since on some platforms TCL_LIB_FILE contains shell escapes. +# since on some platforms TCL_LIB_FILE contains shell escapes. # (See also: TCL_TRIM_DOTS). eval "TCL_LIB_FILE=${TCL_LIB_FILE}" @@ -841,8 +844,8 @@ if test "$FRAMEWORK_BUILD" = "1" ; then HTML_DIR="${libdir}/Resources/Documentation/Reference/Tcl" EXTRA_INSTALL="install-private-headers html-tcl" EXTRA_BUILD_HTML='@ln -fs contents.htm "$(HTML_INSTALL_DIR)"/TclTOC.html' - EXTRA_INSTALL_BINARIES='@echo "Installing Info.plist to $(LIB_INSTALL_DIR)/Resources" && mkdir -p "$(LIB_INSTALL_DIR)/Resources" && $(INSTALL_DATA) Tcl-Info.plist "$(LIB_INSTALL_DIR)/Resources/Info.plist"' - EXTRA_INSTALL_BINARIES="$EXTRA_INSTALL_BINARIES"' && echo "Installing license.terms to $(LIB_INSTALL_DIR)/Resources" && $(INSTALL_DATA) "$(TOP_DIR)/license.terms" "$(LIB_INSTALL_DIR)/Resources"' + EXTRA_INSTALL_BINARIES='@echo "Installing Info.plist to $(LIB_INSTALL_DIR)/Resources/" && $(INSTALL_DATA_DIR) "$(LIB_INSTALL_DIR)/Resources" && $(INSTALL_DATA) Tcl-Info.plist "$(LIB_INSTALL_DIR)/Resources/Info.plist"' + EXTRA_INSTALL_BINARIES="$EXTRA_INSTALL_BINARIES"' && echo "Installing license.terms to $(LIB_INSTALL_DIR)/Resources/" && $(INSTALL_DATA) "$(TOP_DIR)/license.terms" "$(LIB_INSTALL_DIR)/Resources"' EXTRA_INSTALL_BINARIES="$EXTRA_INSTALL_BINARIES"' && echo "Finalizing Tcl.framework" && rm -f "$(LIB_INSTALL_DIR)/../Current" && ln -s "$(VERSION)" "$(LIB_INSTALL_DIR)/../Current" && for f in "$(LIB_FILE)" tclConfig.sh Resources Headers PrivateHeaders; do rm -f "$(LIB_INSTALL_DIR)/../../$$f" && ln -s "Versions/Current/$$f" "$(LIB_INSTALL_DIR)/../.."; done && f="$(STUB_LIB_FILE)" && rm -f "$(LIB_INSTALL_DIR)/../../$$f" && ln -s "Versions/$(VERSION)/$$f" "$(LIB_INSTALL_DIR)/../.."' # Don't use AC_DEFINE for the following as the framework version define # needs to go into the Makefile even when using autoheader, so that we diff --git a/unix/install-sh b/unix/install-sh index c68581d..7c34c3f 100755 --- a/unix/install-sh +++ b/unix/install-sh @@ -156,8 +156,8 @@ while test $# -ne 0; do -s) stripcmd=$stripprog;; - -S) stripcmd="$stripprog $2" - shift;; + -S) stripcmd="$stripprog $2" + shift;; -t) dst_arg=$2 shift;; diff --git a/unix/tcl.m4 b/unix/tcl.m4 index a142baf..b13fddd 100644 --- a/unix/tcl.m4 +++ b/unix/tcl.m4 @@ -1968,7 +1968,7 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ AS_IF([test "$GCC" = yes],[use_sunmath=no],[ arch=`isainfo` AC_MSG_CHECKING([whether to use -lsunmath for fp rounding control]) - AS_IF([test "$arch" = "amd64 i386"], [ + AS_IF([test "$arch" = "amd64 i386" -o "$arch" = "i386"], [ AC_MSG_RESULT([yes]) MATH_LIBS="-lsunmath $MATH_LIBS" AC_CHECK_HEADER(sunmath.h) @@ -2001,7 +2001,7 @@ AC_DEFUN([SC_CONFIG_CFLAGS], [ ], [ AS_IF([test "$use_sunmath" = yes], [textmode=textoff],[textmode=text]) case $system in - SunOS-5.[[1-9]][[0-9]]*) + SunOS-5.[[1-9]][[0-9]]*|SunOS-5.[[7-9]]) SHLIB_LD="\${CC} -G -z $textmode \${LDFLAGS}";; *) SHLIB_LD="/usr/ccs/bin/ld -G -z $textmode";; diff --git a/unix/tcl.spec b/unix/tcl.spec index b35e220..0c42aa4 100644 --- a/unix/tcl.spec +++ b/unix/tcl.spec @@ -4,7 +4,7 @@ Name: tcl Summary: Tcl scripting language development environment -Version: 8.6b2 +Version: 8.6b3 Release: 2 License: BSD Group: Development/Languages diff --git a/unix/tclConfig.h.in b/unix/tclConfig.h.in index 31466bc..f171cce 100644 --- a/unix/tclConfig.h.in +++ b/unix/tclConfig.h.in @@ -4,6 +4,9 @@ #ifndef _TCLCONFIG #define _TCLCONFIG +/* Define if building universal (internal helper macro) */ +#undef AC_APPLE_UNIVERSAL_BUILD + /* Is gettimeofday() actually declared in <sys/time.h>? */ #undef GETTOD_NOT_DECLARED @@ -13,8 +16,8 @@ /* Define to 1 if the system has the type `blkcnt_t'. */ #undef HAVE_BLKCNT_T -/* Do we have BSDgettimeofday()? */ -#undef HAVE_BSDGETTIMEOFDAY +/* Defined when compiler supports casting to union type. */ +#undef HAVE_CAST_TO_UNION /* Define to 1 if you have the `chflags' function. */ #undef HAVE_CHFLAGS @@ -28,6 +31,9 @@ /* Do we have access to Darwin CoreFoundation.framework? */ #undef HAVE_COREFOUNDATION +/* Is the cpuid instruction usable? */ +#undef HAVE_CPUID + /* Define to 1 if you have the `freeaddrinfo' function. */ #undef HAVE_FREEADDRINFO @@ -205,10 +211,10 @@ /* Is 'struct stat64' in <sys/stat.h>? */ #undef HAVE_STRUCT_STAT64 -/* Define to 1 if `st_blksize' is member of `struct stat'. */ +/* Define to 1 if `st_blksize' is a member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_BLKSIZE -/* Define to 1 if `st_blocks' is member of `struct stat'. */ +/* Define to 1 if `st_blocks' is a member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_BLOCKS /* Define to 1 if you have the <sys/filio.h> header file. */ @@ -271,6 +277,9 @@ /* Default libtommath precision. */ #undef MP_PREC +/* Is no debugging enabled? */ +#undef NDEBUG + /* Use compat implementation of getaddrinfo() and friends */ #undef NEED_FAKE_RFC2553 @@ -349,6 +358,9 @@ /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME +/* Define to the home page for this package. */ +#undef PACKAGE_URL + /* Define to the version of this package. */ #undef PACKAGE_VERSION @@ -361,9 +373,6 @@ /* What encoding should be used for embedded configuration info? */ #undef TCL_CFGVAL_ENCODING -/* Is debugging enabled? */ -#undef NDEBUG - /* Is this a 64-bit build? */ #undef TCL_CFG_DO64BIT @@ -439,9 +448,17 @@ /* Should we use vfork() instead of fork()? */ #undef USE_VFORK -/* Define to 1 if your processor stores words with the most significant byte - first (like Motorola and SPARC, unlike Intel and VAX). */ -#undef WORDS_BIGENDIAN +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +# undef WORDS_BIGENDIAN +# endif +#endif /* Are Darwin SUSv3 extensions available? */ #undef _DARWIN_C_SOURCE @@ -496,7 +513,7 @@ /* Define to `int' if <sys/types.h> does not define. */ #undef pid_t -/* Define to `unsigned' if <sys/types.h> does not define. */ +/* Define to `unsigned int' if <sys/types.h> does not define. */ #undef size_t /* Define as int if socklen_t is not available */ diff --git a/unix/tclLoadDl.c b/unix/tclLoadDl.c index d86e7fd..dc711f8 100644 --- a/unix/tclLoadDl.c +++ b/unix/tclLoadDl.c @@ -66,14 +66,16 @@ TclpDlopen( Tcl_LoadHandle *loadHandle, /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ - Tcl_FSUnloadFileProc **unloadProcPtr) + Tcl_FSUnloadFileProc **unloadProcPtr, /* Filled with address of Tcl_FSUnloadFileProc * function which should be used for this * file. */ + int flags) { void *handle; Tcl_LoadHandle newHandle; const char *native; + int dlopenflags = 0; /* * First try the full path the user gave us. This is particularly @@ -83,9 +85,19 @@ TclpDlopen( native = Tcl_FSGetNativePath(pathPtr); /* - * Use (RTLD_NOW|RTLD_LOCAL) always, see [Bug #3216070] + * Use (RTLD_NOW|RTLD_LOCAL) as default, see [Bug #3216070] */ - handle = dlopen(native, RTLD_NOW | RTLD_LOCAL); + if (flags & TCL_LOAD_GLOBAL) { + dlopenflags |= RTLD_GLOBAL; + } else { + dlopenflags |= RTLD_LOCAL; + } + if (flags & TCL_LOAD_LAZY) { + dlopenflags |= RTLD_LAZY; + } else { + dlopenflags |= RTLD_NOW; + } + handle = dlopen(native, dlopenflags); if (handle == NULL) { /* * Let the OS loader examine the binary search path for whatever @@ -98,9 +110,9 @@ TclpDlopen( native = Tcl_UtfToExternalDString(NULL, fileName, -1, &ds); /* - * Use (RTLD_NOW|RTLD_LOCAL) always, see [Bug #3216070] + * Use (RTLD_NOW|RTLD_LOCAL) as default, see [Bug #3216070] */ - handle = dlopen(native, RTLD_NOW | RTLD_LOCAL); + handle = dlopen(native, dlopenflags); Tcl_DStringFree(&ds); } @@ -112,8 +124,9 @@ TclpDlopen( const char *errorStr = dlerror(); - Tcl_AppendResult(interp, "couldn't load file \"", - Tcl_GetString(pathPtr), "\": ", errorStr, NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't load file \"%s\": %s", + Tcl_GetString(pathPtr), errorStr)); return TCL_ERROR; } newHandle = ckalloc(sizeof(*newHandle)); @@ -151,7 +164,7 @@ FindSymbol( const char *native; /* Name of the library to be loaded, in * system encoding */ Tcl_DString newName, ds; /* Buffers for converting the name to - * system encoding and prepending an + * system encoding and prepending an * underscore*/ void *handle = (void *) loadHandle->clientData; /* Native handle to the loaded library */ @@ -175,9 +188,14 @@ FindSymbol( } Tcl_DStringFree(&ds); if (proc == NULL && interp != NULL) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "cannot find symbol \"", symbol, "\": ", - dlerror(), NULL); + const char *errorStr = dlerror(); + + if (!errorStr) { + errorStr = "unknown"; + } + + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "cannot find symbol \"%s\": %s", symbol, errorStr)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "LOAD_SYMBOL", symbol, NULL); } diff --git a/unix/tclLoadDyld.c b/unix/tclLoadDyld.c index 31d15b2..50c283d 100644 --- a/unix/tclLoadDyld.c +++ b/unix/tclLoadDyld.c @@ -16,42 +16,36 @@ #include "tclInt.h" #ifndef MODULE_SCOPE -#define MODULE_SCOPE extern +# define MODULE_SCOPE extern #endif -#ifndef TCL_DYLD_USE_DLFCN /* * Use preferred dlfcn API on 10.4 and later */ -# if !defined(NO_DLFCN_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1040 -# define TCL_DYLD_USE_DLFCN 1 -# else + +#ifndef TCL_DYLD_USE_DLFCN +# ifdef NO_DLFCN_H # define TCL_DYLD_USE_DLFCN 0 +# else +# define TCL_DYLD_USE_DLFCN 1 # endif #endif -#ifndef TCL_DYLD_USE_NSMODULE + /* * Use deprecated NSModule API only to support 10.3 and earlier: */ -# if MAC_OS_X_VERSION_MIN_REQUIRED < 1040 -# define TCL_DYLD_USE_NSMODULE 1 -# else -# define TCL_DYLD_USE_NSMODULE 0 -# endif + +#ifndef TCL_DYLD_USE_NSMODULE +# define TCL_DYLD_USE_NSMODULE 0 #endif -#if TCL_DYLD_USE_DLFCN -#include <dlfcn.h> -#if defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1040 /* - * Support for weakly importing dlfcn API. + * Use includes for the API we're using. */ -extern void *dlopen(const char *path, int mode) WEAK_IMPORT_ATTRIBUTE; -extern void *dlsym(void *handle, const char *symbol) WEAK_IMPORT_ATTRIBUTE; -extern int dlclose(void *handle) WEAK_IMPORT_ATTRIBUTE; -extern char *dlerror(void) WEAK_IMPORT_ATTRIBUTE; -#endif -#endif + +#if TCL_DYLD_USE_DLFCN +# include <dlfcn.h> +#endif /* TCL_DYLD_USE_DLFCN */ #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY) #include <mach-o/dyld.h> @@ -60,38 +54,23 @@ extern char *dlerror(void) WEAK_IMPORT_ATTRIBUTE; #include <mach-o/arch.h> #include <libkern/OSByteOrder.h> #include <mach/mach.h> -#include <stdbool.h> typedef struct Tcl_DyldModuleHandle { struct Tcl_DyldModuleHandle *nextPtr; NSModule module; } Tcl_DyldModuleHandle; -#endif /* TCL_DYLD_USE_NSMODULE */ +#endif /* TCL_DYLD_USE_NSMODULE || TCL_LOAD_FROM_MEMORY */ -typedef struct Tcl_DyldLoadHandle { -#if TCL_DYLD_USE_DLFCN +typedef struct { void *dlHandle; -#endif #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY) const struct mach_header *dyldLibHeader; Tcl_DyldModuleHandle *modulePtr; #endif } Tcl_DyldLoadHandle; -#if (TCL_DYLD_USE_DLFCN && MAC_OS_X_VERSION_MIN_REQUIRED < 1040) || \ - defined(TCL_LOAD_FROM_MEMORY) -MODULE_SCOPE long tclMacOSXDarwinRelease; -#endif - -#ifdef TCL_DEBUG_LOAD -#define TclLoadDbgMsg(m, ...) \ - do { \ - fprintf(stderr, "%s:%d: %s(): " m ".\n", \ - strrchr(__FILE__, '/')+1, __LINE__, __func__, \ - ##__VA_ARGS__); \ - } while (0) -#else -#define TclLoadDbgMsg(m, ...) +#if TCL_DYLD_USE_DLFCN || defined(TCL_LOAD_FROM_MEMORY) +MODULE_SCOPE long tclMacOSXDarwinRelease; #endif /* @@ -102,7 +81,6 @@ static void * FindSymbol(Tcl_Interp *interp, Tcl_LoadHandle loadHandle, const char *symbol); static void UnloadFile(Tcl_LoadHandle handle); -#if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY) /* *---------------------------------------------------------------------- * @@ -120,6 +98,7 @@ static void UnloadFile(Tcl_LoadHandle handle); *---------------------------------------------------------------------- */ +#if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY) static const char * DyldOFIErrorMsg( int err) @@ -141,7 +120,7 @@ DyldOFIErrorMsg( return "unknown error"; } } -#endif /* TCL_DYLD_USE_NSMODULE */ +#endif /* TCL_DYLD_USE_NSMODULE || TCL_LOAD_FROM_MEMORY */ /* *---------------------------------------------------------------------- @@ -169,16 +148,15 @@ TclpDlopen( Tcl_LoadHandle *loadHandle, /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ - Tcl_FSUnloadFileProc **unloadProcPtr) + Tcl_FSUnloadFileProc **unloadProcPtr, /* Filled with address of Tcl_FSUnloadFileProc * function which should be used for this * file. */ + int flags) { Tcl_DyldLoadHandle *dyldLoadHandle; Tcl_LoadHandle newHandle; -#if TCL_DYLD_USE_DLFCN void *dlHandle = NULL; -#endif #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY) const struct mach_header *dyldLibHeader = NULL; Tcl_DyldModuleHandle *modulePtr = NULL; @@ -187,12 +165,14 @@ TclpDlopen( NSLinkEditErrors editError; int errorNumber; const char *errorName, *objFileImageErrMsg = NULL; -#endif +#endif /* TCL_DYLD_USE_NSMODULE */ const char *errMsg = NULL; int result; Tcl_DString ds; - char *fileName = NULL; const char *nativePath, *nativeFileName = NULL; +#if TCL_DYLD_USE_DLFCN + int dlopenflags = 0; +#endif /* TCL_DYLD_USE_DLFCN */ /* * First try the full path the user gave us. This is particularly @@ -201,46 +181,44 @@ TclpDlopen( */ nativePath = Tcl_FSGetNativePath(pathPtr); + nativeFileName = Tcl_UtfToExternalDString(NULL, Tcl_GetString(pathPtr), + -1, &ds); #if TCL_DYLD_USE_DLFCN -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1040 - if (tclMacOSXDarwinRelease >= 8) -#endif - { /* - * Use (RTLD_NOW|RTLD_LOCAL) always, see [Bug #3216070] + * Use (RTLD_NOW|RTLD_LOCAL) as default, see [Bug #3216070] */ - dlHandle = dlopen(nativePath, RTLD_NOW | RTLD_LOCAL); - if (!dlHandle) { - /* - * Let the OS loader examine the binary search path for whatever - * string the user gave us which hopefully refers to a file on the - * binary path. - */ - fileName = Tcl_GetString(pathPtr); - nativeFileName = Tcl_UtfToExternalDString(NULL, fileName, -1, &ds); - /* - * Use (RTLD_NOW|RTLD_LOCAL) always, see [Bug #3216070] - */ - dlHandle = dlopen(nativeFileName, RTLD_NOW | RTLD_LOCAL); - } - if (dlHandle) { - TclLoadDbgMsg("dlopen() successful"); - } else { + if (flags & TCL_LOAD_GLOBAL) { + dlopenflags |= RTLD_GLOBAL; + } else { + dlopenflags |= RTLD_LOCAL; + } + if (flags & TCL_LOAD_LAZY) { + dlopenflags |= RTLD_LAZY; + } else { + dlopenflags |= RTLD_NOW; + } + dlHandle = dlopen(nativePath, dlopenflags); + if (!dlHandle) { + /* + * Let the OS loader examine the binary search path for whatever string + * the user gave us which hopefully refers to a file on the binary + * path. + */ + + dlHandle = dlopen(nativeFileName, dlopenflags); + if (!dlHandle) { errMsg = dlerror(); - TclLoadDbgMsg("dlopen() failed: %s", errMsg); } } - if (!dlHandle) #endif /* TCL_DYLD_USE_DLFCN */ - { + + if (!dlHandle) { #if TCL_DYLD_USE_NSMODULE dyldLibHeader = NSAddImage(nativePath, NSADDIMAGE_OPTION_RETURN_ON_ERROR); - if (dyldLibHeader) { - TclLoadDbgMsg("NSAddImage() successful"); - } else { + if (!dyldLibHeader) { NSLinkEditError(&editError, &errorNumber, &errorName, &errMsg); if (editError == NSLinkEditFileAccessError) { /* @@ -249,20 +227,12 @@ TclpDlopen( * which hopefully refers to a file on the binary path. */ - if (!fileName) { - fileName = Tcl_GetString(pathPtr); - nativeFileName = Tcl_UtfToExternalDString(NULL, fileName, - -1, &ds); - } dyldLibHeader = NSAddImage(nativeFileName, NSADDIMAGE_OPTION_WITH_SEARCHING | NSADDIMAGE_OPTION_RETURN_ON_ERROR); - if (dyldLibHeader) { - TclLoadDbgMsg("NSAddImage() successful"); - } else { + if (!dyldLibHeader) { NSLinkEditError(&editError, &errorNumber, &errorName, &errMsg); - TclLoadDbgMsg("NSAddImage() failed: %s", errMsg); } } else if ((editError == NSLinkEditFileFormatError && errorNumber == EBADMACHO) @@ -279,47 +249,38 @@ TclpDlopen( err = NSCreateObjectFileImageFromFile(nativePath, &dyldObjFileImage); if (err == NSObjectFileImageSuccess && dyldObjFileImage) { - TclLoadDbgMsg("NSCreateObjectFileImageFromFile() " - "successful"); - module = NSLinkModule(dyldObjFileImage, nativePath, - NSLINKMODULE_OPTION_BINDNOW - | NSLINKMODULE_OPTION_RETURN_ON_ERROR); + int nsflags = NSLINKMODULE_OPTION_RETURN_ON_ERROR; + if (!(flags & 1)) nsflags |= NSLINKMODULE_OPTION_PRIVATE; + if (!(flags & 2)) nsflags |= NSLINKMODULE_OPTION_BINDNOW; + module = NSLinkModule(dyldObjFileImage, nativePath, nsflags); NSDestroyObjectFileImage(dyldObjFileImage); if (module) { modulePtr = ckalloc(sizeof(Tcl_DyldModuleHandle)); modulePtr->module = module; modulePtr->nextPtr = NULL; - TclLoadDbgMsg("NSLinkModule() successful"); } else { NSLinkEditError(&editError, &errorNumber, &errorName, &errMsg); - TclLoadDbgMsg("NSLinkModule() failed: %s", errMsg); } } else { objFileImageErrMsg = DyldOFIErrorMsg(err); - TclLoadDbgMsg("NSCreateObjectFileImageFromFile() failed: " - "%s", objFileImageErrMsg); } } } #endif /* TCL_DYLD_USE_NSMODULE */ } - if (0 -#if TCL_DYLD_USE_DLFCN - || dlHandle -#endif + + if (dlHandle #if TCL_DYLD_USE_NSMODULE || dyldLibHeader || modulePtr -#endif +#endif /* TCL_DYLD_USE_NSMODULE */ ) { dyldLoadHandle = ckalloc(sizeof(Tcl_DyldLoadHandle)); -#if TCL_DYLD_USE_DLFCN dyldLoadHandle->dlHandle = dlHandle; -#endif #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY) dyldLoadHandle->dyldLibHeader = dyldLibHeader; dyldLoadHandle->modulePtr = modulePtr; -#endif +#endif /* TCL_DYLD_USE_NSMODULE || TCL_LOAD_FROM_MEMORY */ newHandle = ckalloc(sizeof(*newHandle)); newHandle->clientData = dyldLoadHandle; newHandle->findSymbolProcPtr = &FindSymbol; @@ -328,18 +289,23 @@ TclpDlopen( *loadHandle = newHandle; result = TCL_OK; } else { - Tcl_AppendResult(interp, errMsg, NULL); + Tcl_Obj *errObj = Tcl_NewObj(); + + if (errMsg != NULL) { + Tcl_AppendToObj(errObj, errMsg, -1); + } #if TCL_DYLD_USE_NSMODULE if (objFileImageErrMsg) { - Tcl_AppendResult(interp, "\nNSCreateObjectFileImageFromFile() " - "error: ", objFileImageErrMsg, NULL); + Tcl_AppendPrintfToObj(errObj, + "\nNSCreateObjectFileImageFromFile() error: %s", + objFileImageErrMsg); } -#endif +#endif /* TCL_DYLD_USE_NSMODULE */ + Tcl_SetObjResult(interp, errObj); result = TCL_ERROR; } - if(fileName) { - Tcl_DStringFree(&ds); - } + + Tcl_DStringFree(&ds); return result; } @@ -372,18 +338,14 @@ FindSymbol( const char *native; native = Tcl_UtfToExternalDString(NULL, symbol, -1, &ds); -#if TCL_DYLD_USE_DLFCN if (dyldLoadHandle->dlHandle) { +#if TCL_DYLD_USE_DLFCN proc = dlsym(dyldLoadHandle->dlHandle, native); - if (proc) { - TclLoadDbgMsg("dlsym() successful"); - } else { + if (!proc) { errMsg = dlerror(); - TclLoadDbgMsg("dlsym() failed: %s", errMsg); } - } else #endif /* TCL_DYLD_USE_DLFCN */ - { + } else { #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY) NSSymbol nsSymbol = NULL; Tcl_DString newName; @@ -400,13 +362,12 @@ FindSymbol( native, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); if (nsSymbol) { - TclLoadDbgMsg("NSLookupSymbolInImage() successful"); -#ifdef DYLD_SUPPORTS_DYLIB_UNLOADING /* * Until dyld supports unloading of MY_DYLIB binaries, the * following is not needed. */ +#ifdef DYLD_SUPPORTS_DYLIB_UNLOADING NSModule module = NSModuleForSymbol(nsSymbol); Tcl_DyldModuleHandle *modulePtr = dyldLoadHandle->modulePtr; @@ -429,32 +390,21 @@ FindSymbol( const char *errorName; NSLinkEditError(&editError, &errorNumber, &errorName, &errMsg); - TclLoadDbgMsg("NSLookupSymbolInImage() failed: %s", errMsg); } } else if (dyldLoadHandle->modulePtr) { nsSymbol = NSLookupSymbolInModule( dyldLoadHandle->modulePtr->module, native); - if (nsSymbol) { - TclLoadDbgMsg("NSLookupSymbolInModule() successful"); - } else { - TclLoadDbgMsg("NSLookupSymbolInModule() failed"); - } } if (nsSymbol) { proc = NSAddressOfSymbol(nsSymbol); - if (proc) { - TclLoadDbgMsg("NSAddressOfSymbol() successful"); - } else { - TclLoadDbgMsg("NSAddressOfSymbol() failed"); - } } Tcl_DStringFree(&newName); #endif /* TCL_DYLD_USE_NSMODULE */ } Tcl_DStringFree(&ds); if (errMsg && (interp != NULL)) { - Tcl_AppendResult(interp, "cannot find symbol \"", symbol, "\": ", - errMsg, NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "cannot find symbol \"%s\": %s", symbol, errMsg)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "LOAD_SYMBOL", symbol, NULL); } @@ -489,34 +439,19 @@ UnloadFile( { Tcl_DyldLoadHandle *dyldLoadHandle = loadHandle->clientData; -#if TCL_DYLD_USE_DLFCN if (dyldLoadHandle->dlHandle) { - int result; - - result = dlclose(dyldLoadHandle->dlHandle); - if (!result) { - TclLoadDbgMsg("dlclose() successful"); - } else { - TclLoadDbgMsg("dlclose() failed: %s", dlerror()); - } - } else +#if TCL_DYLD_USE_DLFCN + (void) dlclose(dyldLoadHandle->dlHandle); #endif /* TCL_DYLD_USE_DLFCN */ - { + } else { #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY) Tcl_DyldModuleHandle *modulePtr = dyldLoadHandle->modulePtr; while (modulePtr != NULL) { - void *ptr; - bool result; + void *ptr = modulePtr; - result = NSUnLinkModule(modulePtr->module, + (void) NSUnLinkModule(modulePtr->module, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES); - if (result) { - TclLoadDbgMsg("NSUnLinkModule() successful"); - } else { - TclLoadDbgMsg("NSUnLinkModule() failed"); - } - ptr = modulePtr; modulePtr = modulePtr->nextPtr; ckfree(ptr); } @@ -556,7 +491,6 @@ TclGuessPackageName( return 0; } -#ifdef TCL_LOAD_FROM_MEMORY /* *---------------------------------------------------------------------- * @@ -573,6 +507,7 @@ TclGuessPackageName( *---------------------------------------------------------------------- */ +#ifdef TCL_LOAD_FROM_MEMORY MODULE_SCOPE void * TclpLoadMemoryGetBuffer( Tcl_Interp *interp, /* Used for error reporting. */ @@ -597,6 +532,7 @@ TclpLoadMemoryGetBuffer( } return buffer; } +#endif /* TCL_LOAD_FROM_MEMORY */ /* *---------------------------------------------------------------------- @@ -616,6 +552,7 @@ TclpLoadMemoryGetBuffer( *---------------------------------------------------------------------- */ +#ifdef TCL_LOAD_FROM_MEMORY MODULE_SCOPE int TclpLoadMemory( Tcl_Interp *interp, /* Used for error reporting. */ @@ -628,10 +565,11 @@ TclpLoadMemory( Tcl_LoadHandle *loadHandle, /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ - Tcl_FSUnloadFileProc **unloadProcPtr) + Tcl_FSUnloadFileProc **unloadProcPtr, /* Filled with address of Tcl_FSUnloadFileProc * function which should be used for this * file. */ + int flags) { Tcl_LoadHandle newHandle; Tcl_DyldLoadHandle *dyldLoadHandle; @@ -639,6 +577,7 @@ TclpLoadMemory( Tcl_DyldModuleHandle *modulePtr; NSModule module; const char *objFileImageErrMsg = NULL; + int nsflags = NSLINKMODULE_OPTION_RETURN_ON_ERROR; /* * Try to create an object file image that we can load from. @@ -658,7 +597,7 @@ TclpLoadMemory( # define mh_size sizeof(struct mach_header_64) # define mh_magic MH_MAGIC_64 # define arch_abi CPU_ARCH_ABI64 -#endif +#endif /* __LP64__ */ if ((size_t) codeSize >= sizeof(struct fat_header) && fh->magic == OSSwapHostToBigInt32(FAT_MAGIC)) { @@ -668,7 +607,6 @@ TclpLoadMemory( * Fat binary, try to find mach_header for our architecture */ - TclLoadDbgMsg("Fat binary, %d archs", fh_nfat_arch); if ((size_t) codeSize >= sizeof(struct fat_header) + fh_nfat_arch * sizeof(struct fat_arch)) { void *fatarchs = (char*)buffer + sizeof(struct fat_header); @@ -681,22 +619,15 @@ TclpLoadMemory( fa = NXFindBestFatArch(arch->cputype | arch_abi, arch->cpusubtype, fatarchs, fh_nfat_arch); if (fa) { - TclLoadDbgMsg("NXFindBestFatArch() successful: " - "local cputype %d subtype %d, " - "fat cputype %d subtype %d", - arch->cputype | arch_abi, arch->cpusubtype, - fa->cputype, fa->cpusubtype); - mh = (void*)((char*)buffer + fa->offset); + mh = (void *)((char *) buffer + fa->offset); ms = fa->size; } else { - TclLoadDbgMsg("NXFindBestFatArch() failed"); err = NSObjectFileImageInappropriateFile; } if (fh->magic != FAT_MAGIC) { swap_fat_arch(fatarchs, fh_nfat_arch, arch->byteorder); } } else { - TclLoadDbgMsg("Fat binary header failure"); err = NSObjectFileImageInappropriateFile; } } else { @@ -704,26 +635,18 @@ TclpLoadMemory( * Thin binary */ - TclLoadDbgMsg("Thin binary"); mh = buffer; ms = codeSize; } if (ms && !(ms >= mh_size && mh->magic == mh_magic && mh->filetype == MH_BUNDLE)) { - TclLoadDbgMsg("Inappropriate file: magic %x filetype %d", - mh->magic, mh->filetype); err = NSObjectFileImageInappropriateFile; } if (err == NSObjectFileImageSuccess) { err = NSCreateObjectFileImageFromMemory(buffer, codeSize, &dyldObjFileImage); - if (err == NSObjectFileImageSuccess) { - TclLoadDbgMsg("NSCreateObjectFileImageFromMemory() " - "successful"); - } else { + if (err != NSObjectFileImageSuccess) { objFileImageErrMsg = DyldOFIErrorMsg(err); - TclLoadDbgMsg("NSCreateObjectFileImageFromMemory() failed: %s", - objFileImageErrMsg); } } else { objFileImageErrMsg = DyldOFIErrorMsg(err); @@ -738,8 +661,9 @@ TclpLoadMemory( if (dyldObjFileImage == NULL) { vm_deallocate(mach_task_self(), (vm_address_t) buffer, size); if (objFileImageErrMsg != NULL) { - Tcl_AppendResult(interp, "NSCreateObjectFileImageFromMemory() " - "error: ", objFileImageErrMsg, NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "NSCreateObjectFileImageFromMemory() error: %s", + objFileImageErrMsg)); } return TCL_ERROR; } @@ -748,19 +672,17 @@ TclpLoadMemory( * Extract the module we want from the image of the object file. */ - module = NSLinkModule(dyldObjFileImage, "[Memory Based Bundle]", - NSLINKMODULE_OPTION_BINDNOW | NSLINKMODULE_OPTION_RETURN_ON_ERROR); + if (!(flags & 1)) nsflags |= NSLINKMODULE_OPTION_PRIVATE; + if (!(flags & 2)) nsflags |= NSLINKMODULE_OPTION_BINDNOW; + module = NSLinkModule(dyldObjFileImage, "[Memory Based Bundle]", nsflags); NSDestroyObjectFileImage(dyldObjFileImage); - if (module) { - TclLoadDbgMsg("NSLinkModule() successful"); - } else { + if (!module) { NSLinkEditErrors editError; int errorNumber; const char *errorName, *errMsg; NSLinkEditError(&editError, &errorNumber, &errorName, &errMsg); - TclLoadDbgMsg("NSLinkModule() failed: %s", errMsg); - Tcl_AppendResult(interp, errMsg, NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj(errMsg, -1)); return TCL_ERROR; } @@ -772,9 +694,7 @@ TclpLoadMemory( modulePtr->module = module; modulePtr->nextPtr = NULL; dyldLoadHandle = ckalloc(sizeof(Tcl_DyldLoadHandle)); -#if TCL_DYLD_USE_DLFCN dyldLoadHandle->dlHandle = NULL; -#endif dyldLoadHandle->dyldLibHeader = NULL; dyldLoadHandle->modulePtr = modulePtr; newHandle = ckalloc(sizeof(*newHandle)); diff --git a/unix/tclLoadNext.c b/unix/tclLoadNext.c index c74a29a..eb0affa 100644 --- a/unix/tclLoadNext.c +++ b/unix/tclLoadNext.c @@ -16,10 +16,9 @@ /* Static procedures defined within this file */ -static void* FindSymbol(Tcl_Interp* interp, Tcl_LoadHandle loadHandle, - const char* symbol); -static void UnloadFile(Tcl_LoadHandle loadHandle); - +static void * FindSymbol(Tcl_Interp *interp, + Tcl_LoadHandle loadHandle, const char* symbol); +static void UnloadFile(Tcl_LoadHandle loadHandle); /* *---------------------------------------------------------------------- @@ -47,10 +46,11 @@ TclpDlopen( Tcl_LoadHandle *loadHandle, /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ - Tcl_FSUnloadFileProc **unloadProcPtr) + Tcl_FSUnloadFileProc **unloadProcPtr, /* Filled with address of Tcl_FSUnloadFileProc * function which should be used for this * file. */ + int flags) { Tcl_LoadHandle newHandle; struct mach_header *header; @@ -93,15 +93,15 @@ TclpDlopen( char *data; int len, maxlen; - NXGetMemoryBuffer(errorStream,&data,&len,&maxlen); - Tcl_AppendResult(interp, "couldn't load file \"", fileName, "\": ", - data, NULL); + NXGetMemoryBuffer(errorStream, &data, &len, &maxlen); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't load file \"%s\": %s", fileName, data)); NXCloseMemory(errorStream, NX_FREEBUFFER); return TCL_ERROR; } NXCloseMemory(errorStream, NX_FREEBUFFER); - newHandle = ckalloc(sizeof(*newHandle)); + newHandle = ckalloc(sizeof(Tcl_LoadHandle)); newHandle->clientData = INT2PTR(1); newHandle->findSymbolProcPtr = &FindSymbol; newHandle->unloadFileProcPtr = &UnloadFile; @@ -127,25 +127,25 @@ TclpDlopen( *---------------------------------------------------------------------- */ -static void* +static void * FindSymbol( Tcl_Interp *interp, Tcl_LoadHandle loadHandle, const char *symbol) { Tcl_PackageInitProc *proc = NULL; + if (symbol) { char sym[strlen(symbol) + 2]; sym[0] = '_'; sym[1] = 0; strcat(sym, symbol); - rld_lookup(NULL, sym, (unsigned long *)&proc); + rld_lookup(NULL, sym, (unsigned long *) &proc); } if (proc == NULL && interp != NULL) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "cannot find symbol \"", symbol, - "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "cannot find symbol \"%s\"", symbol)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "LOAD_SYMBOL", symbol, NULL); } return proc; diff --git a/unix/tclLoadOSF.c b/unix/tclLoadOSF.c index fbd4d5f..377ed28 100644 --- a/unix/tclLoadOSF.c +++ b/unix/tclLoadOSF.c @@ -35,12 +35,14 @@ #include "tclInt.h" #include <sys/types.h> #include <loader.h> - -/* Static functions defined within this file */ -static void* FindSymbol(Tcl_Interp* interp, Tcl_LoadHandle loadHandle, - const char* symbol); -static void UnloadFile(Tcl_LoadHandle handle); +/* + * Static functions defined within this file. + */ + +static void * FindSymbol(Tcl_Interp *interp, + Tcl_LoadHandle loadHandle, const char* symbol); +static void UnloadFile(Tcl_LoadHandle handle); /* *---------------------------------------------------------------------- @@ -68,10 +70,11 @@ TclpDlopen( Tcl_LoadHandle *loadHandle, /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ - Tcl_FSUnloadFileProc **unloadProcPtr) + Tcl_FSUnloadFileProc **unloadProcPtr, /* Filled with address of Tcl_FSUnloadFileProc * function which should be used for this * file. */ + int flags) { Tcl_LoadHandle newHandle; ldr_module_t lm; @@ -103,8 +106,9 @@ TclpDlopen( } if (lm == LDR_NULL_MODULE) { - Tcl_AppendResult(interp, "couldn't load file \"", fileName, "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't load file \"%s\": %s", + fileName, Tcl_PosixError(interp))); return TCL_ERROR; } @@ -155,10 +159,11 @@ FindSymbol( Tcl_LoadHandle loadHandle, const char *symbol) { - void* retval = ldr_lookup_package((char *)loadHandle, symbol); + void *retval = ldr_lookup_package((char *) loadHandle, symbol); + if (retval == NULL && interp != NULL) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "cannot find symbol\"", symbol, "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "cannot find symbol \"%s\"", symbol)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "LOAD_SYMBOL", symbol, NULL); } return retval; diff --git a/unix/tclLoadShl.c b/unix/tclLoadShl.c index eddd80a..f73c164 100644 --- a/unix/tclLoadShl.c +++ b/unix/tclLoadShl.c @@ -22,14 +22,14 @@ #endif #include "tclInt.h" - -/* Static functions defined within this file */ -static void* FindSymbol(Tcl_Interp* interp, Tcl_LoadHandle loadHandle, - const char* symbol); -static void -UnloadFile(Tcl_LoadHandle handle); +/* + * Static functions defined within this file. + */ +static void * FindSymbol(Tcl_Interp *interp, + Tcl_LoadHandle loadHandle, const char *symbol); +static void UnloadFile(Tcl_LoadHandle handle); /* *---------------------------------------------------------------------- @@ -57,10 +57,11 @@ TclpDlopen( Tcl_LoadHandle *loadHandle, /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ - Tcl_FSUnloadFileProc **unloadProcPtr) + Tcl_FSUnloadFileProc **unloadProcPtr, /* Filled with address of Tcl_FSUnloadFileProc * function which should be used for this * file. */ + int flags) { shl_t handle; Tcl_LoadHandle newHandle; @@ -100,8 +101,9 @@ TclpDlopen( } if (handle == NULL) { - Tcl_AppendResult(interp, "couldn't load file \"", fileName, "\": ", - Tcl_PosixError(interp), (char *) NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't load file \"%s\": %s", + fileName, Tcl_PosixError(interp))); return TCL_ERROR; } newHandle = ckalloc(sizeof(*newHandle)); @@ -136,7 +138,7 @@ FindSymbol( { Tcl_DString newName; Tcl_PackageInitProc *proc = NULL; - shl_t handle = (shl_t)(loadHandle->clientData); + shl_t handle = (shl_t) loadHandle->clientData; /* * Some versions of the HP system software still use "_" at the beginning @@ -155,9 +157,9 @@ FindSymbol( Tcl_DStringFree(&newName); } if (proc == NULL && interp != NULL) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "cannot find symbol\"", symbol, "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "cannot find symbol \"%s\": %s", + symbol, Tcl_PosixError(interp))); } return proc; } @@ -186,9 +188,8 @@ UnloadFile( * TclpDlopen(). The loadHandle is a token * that represents the loaded file. */ { - shl_t handle; + shl_t handle = (shl_t) loadHandle->clientData; - handle = (shl_t) (loadHandle -> clientData); shl_unload(handle); ckfree(loadHandle); } diff --git a/unix/tclUnixChan.c b/unix/tclUnixChan.c index 3845c44..9ee37f1 100644 --- a/unix/tclUnixChan.c +++ b/unix/tclUnixChan.c @@ -136,10 +136,10 @@ typedef struct TtyAttrs { #endif /* !SUPPORTS_TTY */ #define UNSUPPORTED_OPTION(detail) \ - if (interp) { \ - Tcl_AppendResult(interp, (detail), \ - " not supported for this platform", NULL); \ - Tcl_SetErrorCode(interp, "TCL", "UNSUPPORTED", NULL); \ + if (interp) { \ + Tcl_SetObjResult(interp, Tcl_ObjPrintf( \ + "%s not supported for this platform", (detail))); \ + Tcl_SetErrorCode(interp, "TCL", "UNSUPPORTED", NULL); \ } /* @@ -697,9 +697,9 @@ TtySetOptionProc( return TCL_ERROR; } else { if (interp) { - Tcl_AppendResult(interp, "bad value for -handshake: " - "must be one of xonxoff, rtscts, dtrdsr or none", - NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "bad value for -handshake: must be one of" + " xonxoff, rtscts, dtrdsr or none", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FCONFIGURE", "VALUE", NULL); } @@ -720,8 +720,9 @@ TtySetOptionProc( return TCL_ERROR; } else if (argc != 2) { if (interp) { - Tcl_AppendResult(interp, "bad value for -xchar: " - "should be a list of two elements", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "bad value for -xchar: should be a list of" + " two elements", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FCONFIGURE", "VALUE", NULL); } @@ -773,8 +774,9 @@ TtySetOptionProc( } if ((argc % 2) == 1) { if (interp) { - Tcl_AppendResult(interp, "bad value for -ttycontrol: " - "should be a list of signal,value pairs", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "bad value for -ttycontrol: should be a list of" + " signal,value pairs", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FCONFIGURE", "VALUE", NULL); } @@ -822,9 +824,9 @@ TtySetOptionProc( #endif /* SETBREAK */ } else { if (interp) { - Tcl_AppendResult(interp, "bad signal \"", argv[i], - "\" for -ttycontrol: must be " - "DTR, RTS or BREAK", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad signal \"%s\" for -ttycontrol: must be" + " DTR, RTS or BREAK", argv[i])); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FCONFIGURE", "VALUE", NULL); } @@ -1388,8 +1390,8 @@ TtyParseMode( stopPtr, &end); if ((i != 4) || (mode[end] != '\0')) { if (interp != NULL) { - Tcl_AppendResult(interp, bad, ": should be baud,parity,data,stop", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "%s: should be baud,parity,data,stop", bad)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "SERIALMODE", NULL); } return TCL_ERROR; @@ -1412,13 +1414,14 @@ TtyParseMode( #endif /* PAREXT|USE_TERMIO */ == NULL) { if (interp != NULL) { - Tcl_AppendResult(interp, bad, " parity: should be ", + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "%s parity: should be %s", bad, #if defined(PAREXT) || defined(USE_TERMIO) - "n, o, e, m, or s", + "n, o, e, m, or s" #else - "n, o, or e", + "n, o, or e" #endif /* PAREXT|USE_TERMIO */ - NULL); + )); Tcl_SetErrorCode(interp, "TCL", "VALUE", "SERIALMODE", NULL); } return TCL_ERROR; @@ -1426,15 +1429,16 @@ TtyParseMode( *parityPtr = parity; if ((*dataPtr < 5) || (*dataPtr > 8)) { if (interp != NULL) { - Tcl_AppendResult(interp, bad, " data: should be 5, 6, 7, or 8", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "%s data: should be 5, 6, 7, or 8", bad)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "SERIALMODE", NULL); } return TCL_ERROR; } if ((*stopPtr < 0) || (*stopPtr > 2)) { if (interp != NULL) { - Tcl_AppendResult(interp, bad, " stop: should be 1 or 2", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "%s stop: should be 1 or 2", bad)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "SERIALMODE", NULL); } return TCL_ERROR; @@ -1583,8 +1587,9 @@ TclpOpenFileChannel( if (fd < 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "couldn't open \"", TclGetString(pathPtr), - "\": ", Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't open \"%s\": %s", + TclGetString(pathPtr), Tcl_PosixError(interp))); } return NULL; } @@ -1842,15 +1847,15 @@ Tcl_GetOpenFile( if (chan == NULL) { return TCL_ERROR; } - if ((forWriting) && ((chanMode & TCL_WRITABLE) == 0)) { - Tcl_AppendResult(interp, "\"", chanID, "\" wasn't opened for writing", - NULL); + if (forWriting && !(chanMode & TCL_WRITABLE)) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "\"%s\" wasn't opened for writing", chanID)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "CHANNEL", "NOT_WRITABLE", NULL); return TCL_ERROR; - } else if ((!forWriting) && ((chanMode & TCL_READABLE) == 0)) { - Tcl_AppendResult(interp, "\"", chanID, "\" wasn't opened for reading", - NULL); + } else if (!forWriting && !(chanMode & TCL_READABLE)) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "\"%s\" wasn't opened for reading", chanID)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "CHANNEL", "NOT_READABLE", NULL); return TCL_ERROR; @@ -1881,8 +1886,8 @@ Tcl_GetOpenFile( f = fdopen(fd, (forWriting ? "w" : "r")); if (f == NULL) { - Tcl_AppendResult(interp, "cannot get a FILE * for \"", chanID, - "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "cannot get a FILE * for \"%s\"", chanID)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "CHANNEL", "FILE_FAILURE", NULL); return TCL_ERROR; @@ -1892,8 +1897,8 @@ Tcl_GetOpenFile( } } - Tcl_AppendResult(interp, "\"", chanID, - "\" cannot be used to get a FILE *", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "\"%s\" cannot be used to get a FILE *", chanID)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "CHANNEL", "NO_DESCRIPTOR", NULL); return TCL_ERROR; diff --git a/unix/tclUnixCompat.c b/unix/tclUnixCompat.c index 3818121..e201018 100644 --- a/unix/tclUnixCompat.c +++ b/unix/tclUnixCompat.c @@ -99,12 +99,20 @@ static Tcl_Mutex compatLock; #undef NEED_COPYPWD #undef NEED_COPYSTRING +#if !defined(HAVE_GETGRNAM_R_5) && !defined(HAVE_GETGRNAM_R_4) +#define NEED_COPYGRP 1 +static int CopyGrp(struct group *tgtPtr, char *buf, int buflen); +#endif + +#if !defined(HAVE_GETPWNAM_R_5) && !defined(HAVE_GETPWNAM_R_4) +#define NEED_COPYPWD 1 +static int CopyPwd(struct passwd *tgtPtr, char *buf, int buflen); +#endif + static int CopyArray(char **src, int elsize, char *buf, int buflen); -static int CopyGrp(struct group *tgtPtr, char *buf, int buflen); static int CopyHostent(struct hostent *tgtPtr, char *buf, int buflen); -static int CopyPwd(struct passwd *tgtPtr, char *buf, int buflen); static int CopyString(const char *src, char *buf, int buflen); #endif @@ -214,7 +222,6 @@ TclpGetPwNam( return getpwnam_r(name, &tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf)); #else -#define NEED_COPYPWD 1 struct passwd *pwPtr; Tcl_MutexLock(&compatLock); @@ -295,7 +302,6 @@ TclpGetPwUid( return getpwuid_r(uid, &tsdPtr->pwd, tsdPtr->pbuf, sizeof(tsdPtr->pbuf)); #else -#define NEED_COPYPWD 1 struct passwd *pwPtr; Tcl_MutexLock(&compatLock); @@ -364,7 +370,7 @@ TclpGetGrNam( #else ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); -#ifdef HAVE_GETGRNAM_R_5 +#if defined(HAVE_GETGRNAM_R_5) struct group *grPtr = NULL; /* @@ -399,7 +405,6 @@ TclpGetGrNam( return getgrnam_r(name, &tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf)); #else -#define NEED_COPYGRP 1 struct group *grPtr; Tcl_MutexLock(&compatLock); @@ -480,7 +485,6 @@ TclpGetGrGid( return getgrgid_r(gid, &tsdPtr->grp, tsdPtr->gbuf, sizeof(tsdPtr->gbuf)); #else -#define NEED_COPYGRP 1 struct group *grPtr; Tcl_MutexLock(&compatLock); diff --git a/unix/tclUnixFCmd.c b/unix/tclUnixFCmd.c index a695e9c..559992f 100644 --- a/unix/tclUnixFCmd.c +++ b/unix/tclUnixFCmd.c @@ -62,6 +62,16 @@ #define DOTREE_F 3 /* regular file */ /* + * Fallback temporary file location the temporary file generation code. Can be + * overridden at compile time for when it is known that temp files can't be + * written to /tmp (hello, iOS!). + */ + +#ifndef TCL_TEMPORARY_FILE_DIRECTORY +#define TCL_TEMPORARY_FILE_DIRECTORY "/tmp" +#endif + +/* * Callbacks for file attributes code. */ @@ -1320,9 +1330,9 @@ GetGroupAttribute( if (result != 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not read \"", - TclGetString(fileName), "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -1374,9 +1384,9 @@ GetOwnerAttribute( if (result != 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not read \"", - TclGetString(fileName), "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -1425,9 +1435,9 @@ GetPermissionsAttribute( if (result != 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not read \"", - TclGetString(fileName), "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -1478,9 +1488,10 @@ SetGroupAttribute( if (groupPtr == NULL) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not set group for file \"", - TclGetString(fileName), "\": group \"", string, - "\" does not exist", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not set group for file \"%s\":" + " group \"%s\" does not exist", + TclGetString(fileName), string)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SETGRP", "NO_GROUP", NULL); } @@ -1494,9 +1505,9 @@ SetGroupAttribute( if (result != 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not set group for file \"", - TclGetString(fileName), "\": ", Tcl_PosixError(interp), - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not set group for file \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -1544,9 +1555,10 @@ SetOwnerAttribute( if (pwPtr == NULL) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not set owner for file \"", - TclGetString(fileName), "\": user \"", string, - "\" does not exist", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not set owner for file \"%s\":" + " user \"%s\" does not exist", + TclGetString(fileName), string)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SETOWN", "NO_USER", NULL); } @@ -1560,9 +1572,9 @@ SetOwnerAttribute( if (result != 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not set owner for file \"", - TclGetString(fileName), "\": ", Tcl_PosixError(interp), - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not set owner for file \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -1630,9 +1642,9 @@ SetPermissionsAttribute( result = TclpObjStat(fileName, &buf); if (result != 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not read \"", - TclGetString(fileName), "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -1640,8 +1652,9 @@ SetPermissionsAttribute( if (GetModeFromPermString(NULL, modeStringPtr, &newMode) != TCL_OK) { if (interp != NULL) { - Tcl_AppendResult(interp, "unknown permission string format \"", - modeStringPtr, "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unknown permission string format \"%s\"", + modeStringPtr)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "PERMISSION", NULL); } return TCL_ERROR; @@ -1652,9 +1665,9 @@ SetPermissionsAttribute( result = chmod(native, newMode); /* INTL: Native. */ if (result != 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not set permissions for file \"", - TclGetString(fileName), "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not set permissions for file \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -2090,7 +2103,7 @@ TclpObjNormalizePath( /* *---------------------------------------------------------------------- * - * TclpOpenTemporaryFile -- + * TclpOpenTemporaryFile, TclUnixOpenTemporaryFile -- * * Creates a temporary file, possibly based on the supplied bits and * pieces of template supplied in the first three arguments. If the @@ -2100,7 +2113,12 @@ TclpObjNormalizePath( * file to go away once it is no longer needed. * * Results: - * A read-write Tcl Channel open on the file. + * A read-write Tcl Channel open on the file for TclpOpenTemporaryFile, + * or a file descriptor (or -1 on failure) for TclUnixOpenTemporaryFile. + * + * Side effects: + * Accesses the filesystem. Will set the contents of the Tcl_Obj fourth + * argument (if that is non-NULL). * *---------------------------------------------------------------------- */ @@ -2112,11 +2130,30 @@ TclpOpenTemporaryFile( Tcl_Obj *extensionObj, Tcl_Obj *resultingNameObj) { - Tcl_Channel chan; + int fd = TclUnixOpenTemporaryFile(dirObj, basenameObj, extensionObj, + resultingNameObj); + + if (fd == -1) { + return NULL; + } + return Tcl_MakeFileChannel(INT2PTR(fd), TCL_READABLE|TCL_WRITABLE); +} + +int +TclUnixOpenTemporaryFile( + Tcl_Obj *dirObj, + Tcl_Obj *basenameObj, + Tcl_Obj *extensionObj, + Tcl_Obj *resultingNameObj) +{ Tcl_DString template, tmp; const char *string; int len, fd; + /* + * We should also check against making more then TMP_MAX of these. + */ + if (dirObj) { string = Tcl_GetStringFromObj(dirObj, &len); Tcl_UtfToExternalDString(NULL, string, len, &template); @@ -2152,9 +2189,10 @@ TclpOpenTemporaryFile( } if (fd == -1) { - return NULL; + Tcl_DStringFree(&template); + return -1; } - chan = Tcl_MakeFileChannel(INT2PTR(fd), TCL_READABLE|TCL_WRITABLE); + if (resultingNameObj) { Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(&template), Tcl_DStringLength(&template), &tmp); @@ -2173,7 +2211,7 @@ TclpOpenTemporaryFile( } Tcl_DStringFree(&template); - return chan; + return fd; } /* @@ -2200,11 +2238,12 @@ DefaultTempDir(void) #endif /* - * Assume that "/tmp" is always an existing writable directory; we've no - * recovery mechanism if it isn't. + * Assume that the default location ("/tmp" if not overridden) is always + * an existing writable directory; we've no recovery mechanism if it + * isn't. */ - return "/tmp"; + return TCL_TEMPORARY_FILE_DIRECTORY; } #if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE) @@ -2239,14 +2278,14 @@ GetReadOnlyAttribute( if (result != 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not read \"", - TclGetString(fileName), "\": ", Tcl_PosixError(interp), - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); } return TCL_ERROR; } - *attributePtrPtr = Tcl_NewBooleanObj((statBuf.st_flags&UF_IMMUTABLE) != 0); + *attributePtrPtr = Tcl_NewBooleanObj(statBuf.st_flags&UF_IMMUTABLE); return TCL_OK; } @@ -2286,9 +2325,9 @@ SetReadOnlyAttribute( if (result != 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not read \"", - TclGetString(fileName), "\": ", Tcl_PosixError(interp), - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -2303,9 +2342,9 @@ SetReadOnlyAttribute( result = chflags(native, statBuf.st_flags); /* INTL: Native. */ if (result != 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not set flags for file \"", - TclGetString(fileName), "\": ", Tcl_PosixError(interp), - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not set flags for file \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); } return TCL_ERROR; } diff --git a/unix/tclUnixFile.c b/unix/tclUnixFile.c index c213050..38504d9 100644 --- a/unix/tclUnixFile.c +++ b/unix/tclUnixFile.c @@ -310,10 +310,9 @@ TclpMatchInDirectory( if (d == NULL) { Tcl_DStringFree(&ds); if (interp != NULL) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "couldn't read directory \"", - Tcl_DStringValue(&dsOrig), "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't read directory \"%s\": %s", + Tcl_DStringValue(&dsOrig), Tcl_PosixError(interp))); } Tcl_DStringFree(&dsOrig); Tcl_DecrRefCount(fileNamePtr); @@ -471,7 +470,7 @@ NativeMatchType( #ifndef MAC_OSX_TCL || ((types->perm & TCL_GLOB_PERM_HIDDEN) && (*nativeName != '.')) -#endif +#endif /* MAC_OSX_TCL */ ) { return 0; } @@ -489,12 +488,10 @@ NativeMatchType( * check that here: */ - if (types->type & TCL_GLOB_TYPE_LINK) { - if (TclOSlstat(nativeEntry, &buf) == 0) { - if (S_ISLNK(buf.st_mode)) { - return 1; - } - } + if ((types->type & TCL_GLOB_TYPE_LINK) + && (TclOSlstat(nativeEntry, &buf) == 0) + && S_ISLNK(buf.st_mode)) { + return 1; } return 0; } @@ -517,12 +514,10 @@ NativeMatchType( */ } else { #ifdef S_ISLNK - if (types->type & TCL_GLOB_TYPE_LINK) { - if (TclOSlstat(nativeEntry, &buf) == 0) { - if (S_ISLNK(buf.st_mode)) { - goto filetypeOK; - } - } + if ((types->type & TCL_GLOB_TYPE_LINK) + && (TclOSlstat(nativeEntry, &buf) == 0) + && S_ISLNK(buf.st_mode)) { + goto filetypeOK; } #endif /* S_ISLNK */ return 0; @@ -718,9 +713,9 @@ TclpGetNativeCwd( if (getcwd(buffer, MAXPATHLEN+1) == NULL) { /* INTL: Native. */ return NULL; } -#endif +#endif /* USEGETWD */ - if ((clientData == NULL) || strcmp(buffer, (const char*)clientData)) { + if ((clientData == NULL) || strcmp(buffer, (const char *) clientData)) { char *newCd = ckalloc(strlen(buffer) + 1); strcpy(newCd, buffer); @@ -768,12 +763,12 @@ TclpGetCwd( if (getwd(buffer) == NULL) /* INTL: Native. */ #else if (getcwd(buffer, MAXPATHLEN+1) == NULL) /* INTL: Native. */ -#endif +#endif /* USEGETWD */ { if (interp != NULL) { - Tcl_AppendResult(interp, - "error getting working directory name: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error getting working directory name: %s", + Tcl_PosixError(interp))); } return NULL; } @@ -824,7 +819,7 @@ TclpReadlink( return Tcl_DStringValue(linkPtr); #else return NULL; -#endif +#endif /* !DJGPP */ } /* @@ -858,7 +853,7 @@ TclpObjStat( #ifdef S_IFLNK -Tcl_Obj* +Tcl_Obj * TclpObjLink( Tcl_Obj *pathPtr, Tcl_Obj *toPtr, @@ -1180,10 +1175,17 @@ TclpUtime( { return utime(Tcl_FSGetNativePath(pathPtr), tval); } + #ifdef __CYGWIN__ -int TclOSstat(const char *name, Tcl_StatBuf *statBuf) { + +int +TclOSstat( + const char *name, + Tcl_StatBuf *statBuf) +{ struct stat buf; int result = stat(name, &buf); + statBuf->st_mode = buf.st_mode; statBuf->st_ino = buf.st_ino; statBuf->st_dev = buf.st_dev; @@ -1197,9 +1199,15 @@ int TclOSstat(const char *name, Tcl_StatBuf *statBuf) { statBuf->st_ctime = buf.st_ctime; return result; } -int TclOSlstat(const char *name, Tcl_StatBuf *statBuf) { + +int +TclOSlstat( + const char *name, + Tcl_StatBuf *statBuf) +{ struct stat buf; int result = lstat(name, &buf); + statBuf->st_mode = buf.st_mode; statBuf->st_ino = buf.st_ino; statBuf->st_dev = buf.st_dev; @@ -1213,7 +1221,7 @@ int TclOSlstat(const char *name, Tcl_StatBuf *statBuf) { statBuf->st_ctime = buf.st_ctime; return result; } -#endif +#endif /* CYGWIN */ /* * Local Variables: diff --git a/unix/tclUnixNotfy.c b/unix/tclUnixNotfy.c index ca95f40..b87af1b 100644 --- a/unix/tclUnixNotfy.c +++ b/unix/tclUnixNotfy.c @@ -96,7 +96,7 @@ typedef struct ThreadSpecificData { * that an event is ready to be processed * by sending this event. */ void *hwnd; /* Messaging window. */ -#else /* !__CYGWIN__ */ +#else Tcl_Condition waitCV; /* Any other thread alerts a notifier that an * event is ready to be processed by signaling * this condition variable. */ @@ -104,7 +104,7 @@ typedef struct ThreadSpecificData { int eventReady; /* True if an event is ready to be processed. * Used as condition flag together with waitCV * above. */ -#endif +#endif /* TCL_THREADS */ } ThreadSpecificData; static Tcl_ThreadDataKey dataKey; @@ -187,25 +187,12 @@ static Tcl_ThreadId notifierThread; static void NotifierThreadProc(ClientData clientData); #endif static int FileHandlerEventProc(Tcl_Event *evPtr, int flags); - + /* - *---------------------------------------------------------------------- - * - * Tcl_InitNotifier -- - * - * Initializes the platform specific notifier state. - * - * Results: - * Returns a handle to the notifier state for this thread. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- + * Import of Windows API when building threaded with Cygwin. */ #if defined(TCL_THREADS) && defined(__CYGWIN__) - typedef struct { void *hwnd; unsigned int *message; @@ -217,34 +204,60 @@ typedef struct { } MSG; typedef struct { - unsigned int style; - void *lpfnWndProc; - int cbClsExtra; - int cbWndExtra; - void *hInstance; - void *hIcon; - void *hCursor; - void *hbrBackground; - void *lpszMenuName; - void *lpszClassName; + unsigned int style; + void *lpfnWndProc; + int cbClsExtra; + int cbWndExtra; + void *hInstance; + void *hIcon; + void *hCursor; + void *hbrBackground; + void *lpszMenuName; + void *lpszClassName; } WNDCLASS; -extern unsigned char __stdcall PeekMessageW(MSG *, void *, int, int, int); -extern unsigned char __stdcall GetMessageW(MSG *, void *, int, int); -extern unsigned char __stdcall TranslateMessage(const MSG *); -extern int __stdcall DispatchMessageW(const MSG *); -extern void __stdcall PostQuitMessage(int); -extern void * __stdcall CreateWindowExW(void *, void *, void *, DWORD, int, int, int, int, void *, void *, void *, void *); -extern unsigned char __stdcall DestroyWindow(void *); -extern unsigned char __stdcall PostMessageW(void *, unsigned int, void *, void *); -extern void *__stdcall RegisterClassW(const WNDCLASS *); -extern DWORD __stdcall DefWindowProcW(void *, int, void *, void *); -extern void *__stdcall CreateEventW(void *, unsigned char, unsigned char, void *); -extern void __stdcall CloseHandle(void *); -extern void __stdcall MsgWaitForMultipleObjects(DWORD, void *, unsigned char, DWORD, DWORD); -extern unsigned char __stdcall ResetEvent(void *); +extern void __stdcall CloseHandle(void *); +extern void *__stdcall CreateEventW(void *, unsigned char, unsigned char, + void *); +extern void * __stdcall CreateWindowExW(void *, void *, void *, DWORD, int, + int, int, int, void *, void *, void *, void *); +extern DWORD __stdcall DefWindowProcW(void *, int, void *, void *); +extern unsigned char __stdcall DestroyWindow(void *); +extern int __stdcall DispatchMessageW(const MSG *); +extern unsigned char __stdcall GetMessageW(MSG *, void *, int, int); +extern void __stdcall MsgWaitForMultipleObjects(DWORD, void *, + unsigned char, DWORD, DWORD); +extern unsigned char __stdcall PeekMessageW(MSG *, void *, int, int, int); +extern unsigned char __stdcall PostMessageW(void *, unsigned int, void *, + void *); +extern void __stdcall PostQuitMessage(int); +extern void *__stdcall RegisterClassW(const WNDCLASS *); +extern unsigned char __stdcall ResetEvent(void *); +extern unsigned char __stdcall TranslateMessage(const MSG *); -#endif +/* + * Threaded-cygwin specific functions in this file: + */ + +static DWORD __stdcall NotifierProc(void *hwnd, unsigned int message, + void *wParam, void *lParam); +#endif /* TCL_THREADS && __CYGWIN__ */ + +/* + *---------------------------------------------------------------------- + * + * Tcl_InitNotifier -- + * + * Initializes the platform specific notifier state. + * + * Results: + * Returns a handle to the notifier state for this thread. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ ClientData Tcl_InitNotifier(void) @@ -403,11 +416,11 @@ Tcl_AlertNotifier( Tcl_MutexLock(¬ifierMutex); tsdPtr->eventReady = 1; -#ifdef __CYGWIN__ +# ifdef __CYGWIN__ PostMessageW(tsdPtr->hwnd, 1024, 0, 0); -#else +# else Tcl_ConditionNotify(&tsdPtr->waitCV); -#endif +# endif /* __CYGWIN__ */ Tcl_MutexUnlock(¬ifierMutex); #endif /* TCL_THREADS */ } @@ -732,12 +745,12 @@ NotifierProc( * Process all of the runnable events. */ - tsdPtr->eventReady = 1; + tsdPtr->eventReady = 1; Tcl_ServiceAll(); return 0; } -#endif /* __CYGWIN__ */ - +#endif /* TCL_THREADS && __CYGWIN__ */ + /* *---------------------------------------------------------------------- * @@ -768,9 +781,9 @@ Tcl_WaitForEvent( Tcl_Time vTime; #ifdef TCL_THREADS int waitForFiles; -# ifdef __CYGWIN__ - MSG msg; -# endif +# ifdef __CYGWIN__ + MSG msg; +# endif /* __CYGWIN__ */ #else /* * Impl. notes: timeout & timeoutPtr are used if, and only if threads @@ -792,8 +805,8 @@ Tcl_WaitForEvent( if (timePtr != NULL) { /* * TIP #233 (Virtualized Time). Is virtual time in effect? And do - * we actually have something to scale? If yes to both then we call - * the handler to do this scaling. + * we actually have something to scale? If yes to both then we + * call the handler to do this scaling. */ if (timePtr->sec != 0 || timePtr->usec != 0) { @@ -807,17 +820,17 @@ Tcl_WaitForEvent( timeoutPtr = &timeout; } else if (tsdPtr->numFdBits == 0) { /* - * If there are no threads, no timeout, and no fds registered, then - * there are no events possible and we must avoid deadlock. Note - * that this is not entirely correct because there might be a - * signal that could interrupt the select call, but we don't handle - * that case if we aren't using threads. + * If there are no threads, no timeout, and no fds registered, + * then there are no events possible and we must avoid deadlock. + * Note that this is not entirely correct because there might be a + * signal that could interrupt the select call, but we don't + * handle that case if we aren't using threads. */ return -1; } else { timeoutPtr = NULL; -#endif /* TCL_THREADS */ +#endif /* !TCL_THREADS */ } #ifdef TCL_THREADS @@ -828,7 +841,7 @@ Tcl_WaitForEvent( #ifdef __CYGWIN__ if (!tsdPtr->hwnd) { - WNDCLASS class; + WNDCLASS class; class.style = 0; class.cbClsExtra = 0; @@ -842,24 +855,24 @@ Tcl_WaitForEvent( class.hCursor = NULL; RegisterClassW(&class); - tsdPtr->hwnd = CreateWindowExW(NULL, class.lpszClassName, class.lpszClassName, - 0, 0, 0, 0, 0, NULL, NULL, TclWinGetTclInstance(), NULL); + tsdPtr->hwnd = CreateWindowExW(NULL, class.lpszClassName, + class.lpszClassName, 0, 0, 0, 0, 0, NULL, NULL, + TclWinGetTclInstance(), NULL); tsdPtr->event = CreateEventW(NULL, 1 /* manual */, 0 /* !signaled */, NULL); - } - -#endif + } +#endif /* __CYGWIN */ Tcl_MutexLock(¬ifierMutex); if (timePtr != NULL && timePtr->sec == 0 && (timePtr->usec == 0 #if defined(__APPLE__) && defined(__LP64__) /* - * On 64-bit Darwin, pthread_cond_timedwait() appears to have a - * bug that causes it to wait forever when passed an absolute - * time which has already been exceeded by the system time; as - * a workaround, when given a very brief timeout, just do a - * poll. [Bug 1457797] + * On 64-bit Darwin, pthread_cond_timedwait() appears to have + * a bug that causes it to wait forever when passed an + * absolute time which has already been exceeded by the system + * time; as a workaround, when given a very brief timeout, + * just do a poll. [Bug 1457797] */ || timePtr->usec < 10 #endif /* __APPLE__ && __LP64__ */ @@ -883,8 +896,8 @@ Tcl_WaitForEvent( if (waitForFiles) { /* * Add the ThreadSpecificData structure of this thread to the list - * of ThreadSpecificData structures of all threads that are waiting - * on file events. + * of ThreadSpecificData structures of all threads that are + * waiting on file events. */ tsdPtr->nextPtr = waitingListPtr; @@ -909,6 +922,7 @@ Tcl_WaitForEvent( #ifdef __CYGWIN__ if (!PeekMessageW(&msg, NULL, 0, 0, 0)) { DWORD timeout; + if (timePtr) { timeout = timePtr->sec * 1000 + timePtr->usec / 1000; } else { @@ -920,7 +934,7 @@ Tcl_WaitForEvent( } #else Tcl_ConditionWait(&tsdPtr->waitCV, ¬ifierMutex, timePtr); -#endif +#endif /* __CYGWIN__ */ } tsdPtr->eventReady = 0; @@ -929,17 +943,20 @@ Tcl_WaitForEvent( /* * Retrieve and dispatch the message. */ + DWORD result = GetMessageW(&msg, NULL, 0, 0); + if (result == 0) { PostQuitMessage(msg.wParam); /* What to do here? */ - } else if (result != (DWORD)-1) { + } else if (result != (DWORD) -1) { TranslateMessage(&msg); DispatchMessageW(&msg); } } ResetEvent(tsdPtr->event); -#endif +#endif /* __CYGWIN__ */ + if (waitForFiles && tsdPtr->onList) { /* * Remove the ThreadSpecificData structure of this thread from the @@ -1211,9 +1228,9 @@ NotifierThreadProc( tsdPtr->pollState = 0; } #ifdef __CYGWIN__ - PostMessageW(tsdPtr->hwnd, 1024, 0, 0); -#else /* __CYGWIN__ */ - Tcl_ConditionNotify(&tsdPtr->waitCV); + PostMessageW(tsdPtr->hwnd, 1024, 0, 0); +#else + Tcl_ConditionNotify(&tsdPtr->waitCV); #endif /* __CYGWIN__ */ } } @@ -1255,7 +1272,7 @@ NotifierThreadProc( } #endif /* TCL_THREADS */ -#endif /* HAVE_COREFOUNDATION */ +#endif /* !HAVE_COREFOUNDATION */ /* * Local Variables: diff --git a/unix/tclUnixPipe.c b/unix/tclUnixPipe.c index a505bef..9c21b28 100644 --- a/unix/tclUnixPipe.c +++ b/unix/tclUnixPipe.c @@ -188,28 +188,16 @@ TclFile TclpCreateTempFile( const char *contents) /* String to write into temp file, or NULL. */ { - char fileName[L_tmpnam + 9]; - const char *native; - Tcl_DString dstring; - int fd; - - /* - * We should also check against making more then TMP_MAX of these. - */ + int fd = TclUnixOpenTemporaryFile(NULL, NULL, NULL, NULL); - strcpy(fileName, P_tmpdir); /* INTL: Native. */ - if (fileName[strlen(fileName) - 1] != '/') { - strcat(fileName, "/"); /* INTL: Native. */ - } - strcat(fileName, "tclXXXXXX"); - fd = mkstemp(fileName); /* INTL: Native. */ if (fd == -1) { return NULL; } fcntl(fd, F_SETFD, FD_CLOEXEC); - unlink(fileName); /* INTL: Native. */ - if (contents != NULL) { + Tcl_DString dstring; + char *native; + native = Tcl_UtfToExternalDString(NULL, contents, -1, &dstring); if (write(fd, native, Tcl_DStringLength(&dstring)) == -1) { close(fd); @@ -241,61 +229,51 @@ TclpCreateTempFile( Tcl_Obj * TclpTempFileName(void) { - char fileName[L_tmpnam + 9]; - Tcl_Obj *result = NULL; + Tcl_Obj *nameObj = Tcl_NewObj(); int fd; - /* - * We should also check against making more then TMP_MAX of these. - */ - - strcpy(fileName, P_tmpdir); /* INTL: Native. */ - if (fileName[strlen(fileName) - 1] != '/') { - strcat(fileName, "/"); /* INTL: Native. */ - } - strcat(fileName, "tclXXXXXX"); - fd = mkstemp(fileName); /* INTL: Native. */ + Tcl_IncrRefCount(nameObj); + fd = TclUnixOpenTemporaryFile(NULL, NULL, NULL, nameObj); if (fd == -1) { + Tcl_DecrRefCount(nameObj); return NULL; } - fcntl(fd, F_SETFD, FD_CLOEXEC); - unlink(fileName); /* INTL: Native. */ - result = TclpNativeToNormalized(fileName); + fcntl(fd, F_SETFD, FD_CLOEXEC); + TclpObjDeleteFile(nameObj); close(fd); - return result; + return nameObj; } /* - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------------- * * TclpTempFileNameForLibrary -- * - * Constructs a file name in the native file system where a - * dynamically loaded library may be placed. + * Constructs a file name in the native file system where a dynamically + * loaded library may be placed. * * Results: - * Returns the constructed file name. If an error occurs, - * returns NULL and leaves an error message in the interpreter - * result. + * Returns the constructed file name. If an error occurs, returns NULL + * and leaves an error message in the interpreter result. * - * On Unix, it works to load a shared object from a file of any - * name, so this function is merely a thin wrapper around - * TclpTempFileName(). + * On Unix, it works to load a shared object from a file of any name, so this + * function is merely a thin wrapper around TclpTempFileName(). * - *----------------------------------------------------------------------------- + *---------------------------------------------------------------------------- */ -Tcl_Obj* -TclpTempFileNameForLibrary(Tcl_Interp* interp, /* Tcl interpreter */ - Tcl_Obj* path) /* Path name of the library - * in the VFS */ +Tcl_Obj * +TclpTempFileNameForLibrary( + Tcl_Interp *interp, /* Tcl interpreter. */ + Tcl_Obj *path) /* Path name of the library in the VFS. */ { - Tcl_Obj* retval; - retval = TclpTempFileName(); + Tcl_Obj *retval = TclpTempFileName(); + if (retval == NULL) { - Tcl_AppendResult(interp, "couldn't create temporary file: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't create temporary file: %s", + Tcl_PosixError(interp))); } return retval; } @@ -442,8 +420,8 @@ TclpCreateProcess( */ if (TclpCreatePipe(&errPipeIn, &errPipeOut) == 0) { - Tcl_AppendResult(interp, "couldn't create pipe: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't create pipe: %s", Tcl_PosixError(interp))); goto error; } @@ -463,8 +441,9 @@ TclpCreateProcess( /* * After vfork(), do not call code in the child that changes global state, * because it is using the parent's memory space at that point and writes - * might corrupt the parent: so ensure standard channels are initialized in - * the parent, otherwise SetupStdFile() might initialize them in the child. + * might corrupt the parent: so ensure standard channels are initialized + * in the parent, otherwise SetupStdFile() might initialize them in the + * child. */ if (!inputFile) { @@ -495,7 +474,7 @@ TclpCreateProcess( || (joinThisError && ((dup2(1,2) == -1) || (fcntl(2, F_SETFD, 0) != 0)))) { sprintf(errSpace, - "%dforked process couldn't set up input/output: ", errno); + "%dforked process couldn't set up input/output", errno); len = strlen(errSpace); if (len != (size_t) write(fd, errSpace, len)) { Tcl_Panic("TclpCreateProcess: unable to write to errPipeOut"); @@ -509,11 +488,11 @@ TclpCreateProcess( RestoreSignals(); execvp(newArgv[0], newArgv); /* INTL: Native. */ - sprintf(errSpace, "%dcouldn't execute \"%.150s\": ", errno, argv[0]); + sprintf(errSpace, "%dcouldn't execute \"%.150s\"", errno, argv[0]); len = strlen(errSpace); - if (len != (size_t) write(fd, errSpace, len)) { + if (len != (size_t) write(fd, errSpace, len)) { Tcl_Panic("TclpCreateProcess: unable to write to errPipeOut"); - } + } _exit(1); } @@ -528,8 +507,8 @@ TclpCreateProcess( TclStackFree(interp, dsArray); if (pid == -1) { - Tcl_AppendResult(interp, "couldn't fork child process: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't fork child process: %s", Tcl_PosixError(interp))); goto error; } @@ -546,9 +525,11 @@ TclpCreateProcess( count = read(fd, errSpace, (size_t) (sizeof(errSpace) - 1)); if (count > 0) { char *end; + errSpace[count] = 0; errno = strtol(errSpace, &end, 10); - Tcl_AppendResult(interp, end, Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf("%s: %s", + end, Tcl_PosixError(interp))); goto error; } @@ -832,8 +813,8 @@ Tcl_CreatePipe( int fileNums[2]; if (pipe(fileNums) < 0) { - Tcl_AppendResult(interp, "pipe creation failed: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf("pipe creation failed: %s", + Tcl_PosixError(interp))); return TCL_ERROR; } @@ -874,8 +855,8 @@ TclGetAndDetachPids( { PipeState *pipePtr; const Tcl_ChannelType *chanTypePtr; + Tcl_Obj *pidsObj; int i; - char buf[TCL_INTEGER_SPACE]; /* * Punt if the channel is not a command channel. @@ -886,12 +867,14 @@ TclGetAndDetachPids( return; } - pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan); + pipePtr = Tcl_GetChannelInstanceData(chan); + TclNewObj(pidsObj); for (i = 0; i < pipePtr->numPids; i++) { - TclFormatInt(buf, (long) TclpGetPid(pipePtr->pidPtr[i])); - Tcl_AppendElement(interp, buf); - Tcl_DetachPids(1, &(pipePtr->pidPtr[i])); + Tcl_ListObjAppendElement(NULL, pidsObj, Tcl_NewIntObj( + PTR2INT(pipePtr->pidPtr[i]))); + Tcl_DetachPids(1, &pipePtr->pidPtr[i]); } + Tcl_SetObjResult(interp, pidsObj); if (pipePtr->numPids > 0) { ckfree(pipePtr->pidPtr); pipePtr->numPids = 0; @@ -1275,7 +1258,7 @@ Tcl_PidObjCmd( Tcl_Channel chan; PipeState *pipePtr; int i; - Tcl_Obj *resultPtr, *longObjPtr; + Tcl_Obj *resultPtr; if (objc > 2) { Tcl_WrongNumArgs(interp, 1, objv, "?channelId?"); @@ -1301,11 +1284,11 @@ Tcl_PidObjCmd( * Extract the process IDs from the pipe structure. */ - pipePtr = (PipeState *) Tcl_GetChannelInstanceData(chan); + pipePtr = Tcl_GetChannelInstanceData(chan); resultPtr = Tcl_NewObj(); for (i = 0; i < pipePtr->numPids; i++) { - longObjPtr = Tcl_NewLongObj((long) TclpGetPid(pipePtr->pidPtr[i])); - Tcl_ListObjAppendElement(NULL, resultPtr, longObjPtr); + Tcl_ListObjAppendElement(NULL, resultPtr, + Tcl_NewIntObj(PTR2INT(TclpGetPid(pipePtr->pidPtr[i])))); } Tcl_SetObjResult(interp, resultPtr); } diff --git a/unix/tclUnixSock.c b/unix/tclUnixSock.c index 1e9d4eb..102c620 100644 --- a/unix/tclUnixSock.c +++ b/unix/tclUnixSock.c @@ -21,10 +21,10 @@ #define CLEAR_BITS(var, bits) ((var) &= ~(bits)) /* "sock" + a pointer in hex + \0 */ -#define SOCK_CHAN_LENGTH 4 + sizeof(void*) * 2 + 1 -#define SOCK_TEMPLATE "sock%lx" +#define SOCK_CHAN_LENGTH (4 + sizeof(void *) * 2 + 1) +#define SOCK_TEMPLATE "sock%lx" -#undef SOCKET /* Possible conflict with win32 SOCKET */ +#undef SOCKET /* Possible conflict with win32 SOCKET */ /* * This is needed to comply with the strict aliasing rules of GCC, but it also @@ -58,19 +58,23 @@ struct TcpState { /* * Only needed for server sockets */ - Tcl_TcpAcceptProc *acceptProc; /* Proc to call on accept. */ - ClientData acceptProcData; /* The data for the accept proc. */ + + Tcl_TcpAcceptProc *acceptProc; + /* Proc to call on accept. */ + ClientData acceptProcData; /* The data for the accept proc. */ + /* * Only needed for client sockets */ - struct addrinfo *addrlist; /* addresses to connect to */ - struct addrinfo *addr; /* iterator over addrlist */ - struct addrinfo *myaddrlist; /* local address */ - struct addrinfo *myaddr; /* iterator over myaddrlist */ - int filehandlers; /* Caches FileHandlers that get set up while - * an async socket is not yet connected */ - int status; /* Cache status of async socket */ - int cachedBlocking; /* Cache blocking mode of async socket */ + + struct addrinfo *addrlist; /* Addresses to connect to. */ + struct addrinfo *addr; /* Iterator over addrlist. */ + struct addrinfo *myaddrlist;/* Local address. */ + struct addrinfo *myaddr; /* Iterator over myaddrlist. */ + int filehandlers; /* Caches FileHandlers that get set up while + * an async socket is not yet connected. */ + int status; /* Cache status of async socket. */ + int cachedBlocking; /* Cache blocking mode of async socket. */ }; /* @@ -90,9 +94,7 @@ struct TcpState { #ifndef SOMAXCONN # define SOMAXCONN 100 -#endif /* SOMAXCONN */ - -#if (SOMAXCONN < 100) +#elif (SOMAXCONN < 100) # undef SOMAXCONN # define SOMAXCONN 100 #endif /* SOMAXCONN < 100 */ @@ -217,7 +219,7 @@ InitializeHostName( if (native == NULL) { native = tclEmptyStringRep; } -#else +#else /* !NO_UNAME */ /* * Uname doesn't exist; try gethostname instead. * @@ -242,7 +244,7 @@ InitializeHostName( if (gethostname(buffer, sizeof(buffer)) > -1) { /* INTL: Native. */ native = buffer; } -#endif +#endif /* NO_UNAME */ *encodingPtr = Tcl_GetEncoding(NULL, NULL); *lengthPtr = strlen(native); @@ -344,7 +346,7 @@ TcpBlockModeProc( * TCL_MODE_BLOCKING or * TCL_MODE_NONBLOCKING. */ { - TcpState *statePtr = (TcpState *) instanceData; + TcpState *statePtr = instanceData; if (mode == TCL_MODE_BLOCKING) { CLEAR_BITS(statePtr->flags, TCP_ASYNC_SOCKET); @@ -443,7 +445,7 @@ TcpInputProc( * buffer? */ int *errorCodePtr) /* Where to store error code. */ { - TcpState *statePtr = (TcpState *) instanceData; + TcpState *statePtr = instanceData; int bytesRead; *errorCodePtr = 0; @@ -493,7 +495,7 @@ TcpOutputProc( int toWrite, /* How many bytes to write? */ int *errorCodePtr) /* Where to store error code. */ { - TcpState *statePtr = (TcpState *) instanceData; + TcpState *statePtr = instanceData; int written; *errorCodePtr = 0; @@ -532,7 +534,7 @@ TcpCloseProc( ClientData instanceData, /* The socket to close. */ Tcl_Interp *interp) /* For error reporting - unused. */ { - TcpState *statePtr = (TcpState *) instanceData; + TcpState *statePtr = instanceData; int errorCode = 0; TcpFdList *fds; @@ -593,7 +595,7 @@ TcpClose2Proc( Tcl_Interp *interp, /* For error reporting. */ int flags) /* Flags that indicate which side to close. */ { - TcpState *statePtr = (TcpState *) instanceData; + TcpState *statePtr = instanceData; int errorCode = 0; int sd; @@ -610,8 +612,8 @@ TcpClose2Proc( break; default: if (interp) { - Tcl_AppendResult(interp, - "Socket close2proc called bidirectionally", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "socket close2proc called bidirectionally", -1)); } return TCL_ERROR; } @@ -653,7 +655,7 @@ TcpGetOptionProc( Tcl_DString *dsPtr) /* Where to store the computed value; * initialized by caller. */ { - TcpState *statePtr = (TcpState *) instanceData; + TcpState *statePtr = instanceData; char host[NI_MAXHOST], port[NI_MAXSERV]; size_t len = 0; int reverseDNS = 0; @@ -670,7 +672,7 @@ TcpGetOptionProc( if (statePtr->status == 0) { ret = getsockopt(statePtr->fds.fd, SOL_SOCKET, SO_ERROR, - (char *)&err, &optlen); + (char *) &err, &optlen); if (ret < 0) { err = errno; } @@ -688,9 +690,8 @@ TcpGetOptionProc( reverseDNS = NI_NUMERICHOST; } - if ((len == 0) || - ((len > 1) && (optionName[1] == 'p') && - (strncmp(optionName, "-peername", len) == 0))) { + if ((len == 0) || ((len > 1) && (optionName[1] == 'p') && + (strncmp(optionName, "-peername", len) == 0))) { address peername; socklen_t size = sizeof(peername); @@ -721,16 +722,16 @@ TcpGetOptionProc( if (len) { if (interp) { - Tcl_AppendResult(interp, "can't get peername: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't get peername: %s", + Tcl_PosixError(interp))); } return TCL_ERROR; } } } - if ((len == 0) || - ((len > 1) && (optionName[1] == 's') && + if ((len == 0) || ((len > 1) && (optionName[1] == 's') && (strncmp(optionName, "-sockname", len) == 0))) { TcpFdList *fds; address sockname; @@ -772,7 +773,7 @@ TcpGetOptionProc( sockname.sa6.sin6_addr.s6_addr[15] == 0)) { flags |= NI_NUMERICHOST; } -#endif +#endif /* NEED_FAKE_RFC2553 */ } getnameinfo(&sockname.sa, size, host, sizeof(host), port, sizeof(port), flags); @@ -787,8 +788,8 @@ TcpGetOptionProc( Tcl_DStringEndSublist(dsPtr); } else { if (interp) { - Tcl_AppendResult(interp, "can't get sockname: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't get sockname: %s", Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -825,7 +826,7 @@ TcpWatchProc( * TCL_READABLE, TCL_WRITABLE and * TCL_EXCEPTION. */ { - TcpState *statePtr = (TcpState *) instanceData; + TcpState *statePtr = instanceData; if (statePtr->acceptProc != NULL) { /* @@ -842,8 +843,7 @@ TcpWatchProc( statePtr->filehandlers = mask; } else if (mask) { Tcl_CreateFileHandler(statePtr->fds.fd, mask, - (Tcl_FileProc *) Tcl_NotifyChannel, - (ClientData) statePtr->channel); + (Tcl_FileProc *) Tcl_NotifyChannel, statePtr->channel); } else { Tcl_DeleteFileHandler(statePtr->fds.fd); } @@ -874,7 +874,7 @@ TcpGetHandleProc( int direction, /* Not used. */ ClientData *handlePtr) /* Where to store the handle. */ { - TcpState *statePtr = (TcpState *) instanceData; + TcpState *statePtr = instanceData; *handlePtr = INT2PTR(statePtr->fds.fd); return TCL_OK; @@ -946,12 +946,11 @@ CreateClientSocket( } for (state->addr = state->addrlist; state->addr != NULL; - state->addr = state->addr->ai_next) { - + state->addr = state->addr->ai_next) { status = -1; for (state->myaddr = state->myaddrlist; state->myaddr != NULL; - state->myaddr = state->myaddr->ai_next) { + state->myaddr = state->myaddr->ai_next) { int reuseaddr; /* @@ -967,6 +966,7 @@ CreateClientSocket( * Close the socket if it is still open from the last unsuccessful * iteration. */ + if (state->fds.fd >= 0) { close(state->fds.fd); state->fds.fd = -1; @@ -991,7 +991,8 @@ CreateClientSocket( TclSockMinimumBuffers(INT2PTR(state->fds.fd), SOCKET_BUFSIZE); if (async) { - status = TclUnixSetBlockingMode(state->fds.fd, TCL_MODE_NONBLOCKING); + status = TclUnixSetBlockingMode(state->fds.fd, + TCL_MODE_NONBLOCKING); if (status < 0) { continue; } @@ -1001,7 +1002,7 @@ CreateClientSocket( (void) setsockopt(state->fds.fd, SOL_SOCKET, SO_REUSEADDR, (char *) &reuseaddr, sizeof(reuseaddr)); status = bind(state->fds.fd, state->myaddr->ai_addr, - state->myaddr->ai_addrlen); + state->myaddr->ai_addrlen); if (status < 0) { continue; } @@ -1014,24 +1015,25 @@ CreateClientSocket( */ status = connect(state->fds.fd, state->addr->ai_addr, - state->addr->ai_addrlen); + state->addr->ai_addrlen); if (status < 0 && errno == EINPROGRESS) { Tcl_CreateFileHandler(state->fds.fd, - TCL_WRITABLE | TCL_EXCEPTION, - TcpAsyncCallback, state); + TCL_WRITABLE|TCL_EXCEPTION, TcpAsyncCallback, state); return TCL_OK; reenter: Tcl_DeleteFileHandler(state->fds.fd); + /* * Read the error state from the socket to see if the async * connection has succeeded or failed. As this clears the * error condition, we cache the status in the socket state * struct for later retrieval by [fconfigure -error]. */ + optlen = sizeof(int); getsockopt(state->fds.fd, SOL_SOCKET, SO_ERROR, - (char *)&status, &optlen); + (char *) &status, &optlen); state->status = status; } if (status == 0) { @@ -1047,6 +1049,7 @@ out: /* * An asynchonous connection has finally succeeded or failed. */ + TcpWatchProc(state, state->filehandlers); TclUnixSetBlockingMode(state->fds.fd, state->cachedBlocking); @@ -1058,17 +1061,18 @@ out: * hurt that this is also called in the successful case and will save * the event mechanism one roundtrip through select(). */ - Tcl_NotifyChannel(state->channel, TCL_WRITABLE); + Tcl_NotifyChannel(state->channel, TCL_WRITABLE); } else if (status != 0) { /* * Failure for either a synchronous connection, or an async one that * failed before it could enter background mode, e.g. because an * invalid -myaddr was given. */ + if (interp != NULL) { - Tcl_AppendResult(interp, "couldn't open socket: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't open socket: %s", Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -1111,13 +1115,16 @@ Tcl_OpenTcpClient( /* * Do the name lookups for the local and remote addresses. */ - if (!TclCreateSocketAddress(interp, &addrlist, host, port, 0, &errorMsg) || - !TclCreateSocketAddress(interp, &myaddrlist, myaddr, myport, 1, &errorMsg)) { + + if (!TclCreateSocketAddress(interp, &addrlist, host, port, 0, &errorMsg) + || !TclCreateSocketAddress(interp, &myaddrlist, myaddr, myport, 1, + &errorMsg)) { if (addrlist != NULL) { freeaddrinfo(addrlist); } if (interp != NULL) { - Tcl_AppendResult(interp, "couldn't open socket: ", errorMsg, NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't open socket: %s", errorMsg)); } return NULL; } @@ -1141,10 +1148,10 @@ Tcl_OpenTcpClient( return NULL; } - sprintf(channelName, SOCK_TEMPLATE, (long)state); + sprintf(channelName, SOCK_TEMPLATE, (long) state); - state->channel = Tcl_CreateChannel(&tcpChannelType, channelName, - state, (TCL_READABLE | TCL_WRITABLE)); + state->channel = Tcl_CreateChannel(&tcpChannelType, channelName, state, + (TCL_READABLE | TCL_WRITABLE)); if (Tcl_SetChannelOption(interp, state->channel, "-translation", "auto crlf") == TCL_ERROR) { Tcl_Close(NULL, state->channel); @@ -1257,6 +1264,7 @@ Tcl_OpenTcpServer( * Try to record and return the most meaningful error message, i.e. the * one from the first socket that went the farthest before it failed. */ + enum { LOOKUP, SOCKET, BIND, LISTEN } howfar = LOOKUP; int my_errno = 0; @@ -1267,7 +1275,7 @@ Tcl_OpenTcpServer( for (addrPtr = addrlist; addrPtr != NULL; addrPtr = addrPtr->ai_next) { sock = socket(addrPtr->ai_family, addrPtr->ai_socktype, - addrPtr->ai_protocol); + addrPtr->ai_protocol); if (sock == -1) { if (howfar < SOCKET) { howfar = SOCKET; @@ -1318,7 +1326,7 @@ Tcl_OpenTcpServer( (void) setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)); } -#endif +#endif /* IPV6_V6ONLY */ status = bind(sock, addrPtr->ai_addr, addrPtr->ai_addrlen); if (status == -1) { @@ -1360,7 +1368,7 @@ Tcl_OpenTcpServer( memset(statePtr, 0, sizeof(TcpState)); statePtr->acceptProc = acceptProc; statePtr->acceptProcData = acceptProcData; - sprintf(channelName, SOCK_TEMPLATE, (long)statePtr); + sprintf(channelName, SOCK_TEMPLATE, (long) statePtr); newfds = &statePtr->fds; } else { newfds = ckalloc(sizeof(TcpFdList)); @@ -1389,13 +1397,15 @@ Tcl_OpenTcpServer( return statePtr->channel; } if (interp != NULL) { - Tcl_AppendResult(interp, "couldn't open socket: ", NULL); + Tcl_Obj *errorObj = Tcl_NewStringObj("couldn't open socket: ", -1); + if (errorMsg == NULL) { errno = my_errno; - Tcl_AppendResult(interp, Tcl_PosixError(interp), NULL); + Tcl_AppendToObj(errorObj, Tcl_PosixError(interp), -1); } else { - Tcl_AppendResult(interp, errorMsg, NULL); + Tcl_AppendToObj(errorObj, errorMsg, -1); } + Tcl_SetObjResult(interp, errorObj); } if (sock != -1) { close(sock); @@ -1434,7 +1444,7 @@ TcpAccept( char host[NI_MAXHOST], port[NI_MAXSERV]; len = sizeof(addr); - newsock = accept(fds->fd, &(addr.sa), &len); + newsock = accept(fds->fd, &addr.sa, &len); if (newsock < 0) { return; } @@ -1451,7 +1461,7 @@ TcpAccept( newSockState->flags = 0; newSockState->fds.fd = newsock; - sprintf(channelName, SOCK_TEMPLATE, (long)newSockState); + sprintf(channelName, SOCK_TEMPLATE, (long) newSockState); newSockState->channel = Tcl_CreateChannel(&tcpChannelType, channelName, newSockState, (TCL_READABLE | TCL_WRITABLE)); @@ -1459,7 +1469,7 @@ TcpAccept( "auto crlf"); if (fds->statePtr->acceptProc != NULL) { - getnameinfo(&(addr.sa), len, host, sizeof(host), port, sizeof(port), + getnameinfo(&addr.sa, len, host, sizeof(host), port, sizeof(port), NI_NUMERICHOST|NI_NUMERICSERV); fds->statePtr->acceptProc(fds->statePtr->acceptProcData, newSockState->channel, host, atoi(port)); diff --git a/unix/tclXtNotify.c b/unix/tclXtNotify.c index 50eb4a2..e289e8c 100644 --- a/unix/tclXtNotify.c +++ b/unix/tclXtNotify.c @@ -16,9 +16,6 @@ #include <X11/Intrinsic.h> #include "tclInt.h" -#ifndef CONST86 -# define CONST86 -#endif /* * This structure is used to keep track of the notifier info for a a * registered file. @@ -87,8 +84,8 @@ static void TimerProc(ClientData clientData, XtIntervalId *id); static void CreateFileHandler(int fd, int mask, Tcl_FileProc *proc, ClientData clientData); static void DeleteFileHandler(int fd); -static void SetTimer(CONST86 Tcl_Time * timePtr); -static int WaitForEvent(CONST86 Tcl_Time * timePtr); +static void SetTimer(const Tcl_Time * timePtr); +static int WaitForEvent(const Tcl_Time * timePtr); /* * Functions defined in this file for use by users of the Xt Notifier: @@ -265,7 +262,7 @@ NotifierExitHandler( static void SetTimer( - CONST86 Tcl_Time *timePtr) /* Timeout value, may be NULL. */ + const Tcl_Time *timePtr) /* Timeout value, may be NULL. */ { long timeout; @@ -629,7 +626,7 @@ FileHandlerEventProc( static int WaitForEvent( - CONST86 Tcl_Time *timePtr) /* Maximum block time, or NULL. */ + const Tcl_Time *timePtr) /* Maximum block time, or NULL. */ { int timeout; diff --git a/unix/tclooConfig.sh b/unix/tclooConfig.sh index 68de106..5cb4d99 100644 --- a/unix/tclooConfig.sh +++ b/unix/tclooConfig.sh @@ -15,5 +15,5 @@ TCLOO_LIB_SPEC="" TCLOO_STUB_LIB_SPEC="" TCLOO_INCLUDE_SPEC="" TCLOO_PRIVATE_INCLUDE_SPEC="" -TCLOO_CFLAGS=-DUSE_TCLOO_STUBS -TCLOO_VERSION=0.6.3 +TCLOO_CFLAGS="" +TCLOO_VERSION=0.7 diff --git a/win/Makefile.in b/win/Makefile.in index d5a335d..dacbbb5 100644 --- a/win/Makefile.in +++ b/win/Makefile.in @@ -90,7 +90,7 @@ COMPILE_DEBUG_FLAGS = SRC_DIR = @srcdir@ ROOT_DIR = @srcdir@/.. -TOP_DIR = $(shell cd @srcdir@/..; pwd) +TOP_DIR = $(shell cd @srcdir@/..; pwd -P) GENERIC_DIR = $(TOP_DIR)/generic TOMMATH_DIR = $(TOP_DIR)/libtommath WIN_DIR = $(TOP_DIR)/win @@ -112,7 +112,7 @@ ROOT_DIR_NATIVE = $(shell $(CYGPATH) '$(ROOT_DIR)' | sed 's!\\!/!g') # Fully qualify library path so that `make test` # does not depend on the current directory. -LIBRARY_DIR1 = $(shell cd '$(ROOT_DIR_NATIVE)/library' ; pwd) +LIBRARY_DIR1 = $(shell cd '$(ROOT_DIR_NATIVE)/library' ; pwd -P) LIBRARY_DIR = $(shell $(CYGPATH) '$(LIBRARY_DIR1)' | sed 's!\\!/!g') DLLSUFFIX = @DLLSUFFIX@ LIBSUFFIX = @LIBSUFFIX@ @@ -137,10 +137,9 @@ TEST_LIB_FILE = @LIBPREFIX@tcltest$(VER)${LIBSUFFIX} ZLIB_DLL_FILE = zlib1.dll SHARED_LIBRARIES = $(TCL_DLL_FILE) @ZLIB_DLL_FILE@ -STATIC_LIBRARIES = $(TCL_LIB_FILE) $(REG_LIB_FILE) $(DDE_LIB_FILE) +STATIC_LIBRARIES = $(TCL_LIB_FILE) TCLSH = tclsh$(VER)${EXESUFFIX} -TCLTEST = tcltest${EXEEXT} CAT32 = cat32$(EXEEXT) MAN2TCL = man2tcl$(EXEEXT) @@ -403,7 +402,7 @@ TCL_DOCS = "$(ROOT_DIR_NATIVE)"/doc/*.[13n] all: binaries libraries doc packages -tcltest: $(TCLTEST) +tcltest: $(TCLSH) $(TEST_DLL_FILE) binaries: $(TCL_STUB_LIB_FILE) @LIBRARIES@ $(DDE_DLL_FILE) $(REG_DLL_FILE) $(TCLSH) @@ -416,11 +415,6 @@ $(TCLSH): $(TCLSH_OBJS) @LIBRARIES@ $(TCL_STUB_LIB_FILE) tclsh.$(RES) tclsh.$(RES) $(CC_EXENAME) $(LDFLAGS_CONSOLE) @VC_MANIFEST_EMBED_EXE@ -$(TCLTEST): testMain.$(OBJEXT) ${TEST_DLL_FILE} @LIBRARIES@ $(TCL_STUB_LIB_FILE) $(CAT32) tclsh.$(RES) - $(CC) $(CFLAGS) testMain.$(OBJEXT) ${TEST_LIB_FILE} $(TCL_LIB_FILE) $(TCL_STUB_LIB_FILE) $(LIBS) \ - tclsh.$(RES) $(CC_EXENAME) $(LDFLAGS_CONSOLE) - @VC_MANIFEST_EMBED_EXE@ - cat32.$(OBJEXT): cat.c $(CC) -c $(CC_SWITCHES) @DEPARG@ $(CC_OBJNAME) @@ -440,50 +434,28 @@ ${TCL_DLL_FILE}: ${TCL_OBJS} tcl.$(RES) @ZLIB_DLL_FILE@ @MAKE_DLL@ ${TCL_OBJS} tcl.$(RES) $(SHLIB_LD_LIBS) @VC_MANIFEST_EMBED_DLL@ -${TCL_LIB_FILE}: ${TCL_OBJS} +${TCL_LIB_FILE}: ${TCL_OBJS} ${DDE_OBJS} ${REG_OBJS} @$(RM) ${TCL_LIB_FILE} - @MAKE_LIB@ ${TCL_OBJS} + @MAKE_LIB@ ${TCL_OBJS} ${DDE_OBJS} ${REG_OBJS} @POST_MAKE_LIB@ -# assume GNU make - -# To enable concurrent parallel make of tcl<x>.dll and tcl<x>.lib, the tcl<x>.dll -# targets have to depend on tcl<x>.lib, this ensures that linking of tcl<x>.dll -# does not execute concurrently with the renaming and recompiling of tcl<x>.lib - -${DDE_DLL_FILE}: ${DDE_OBJS} ${DDE_LIB_FILE} ${TCL_STUB_LIB_FILE} - @-$(RM) ${DDE_DLL_FILE} ${DDE_LIB_FILE}.sav - @-$(COPY) ${DDE_LIB_FILE} ${DDE_LIB_FILE}.sav +${DDE_DLL_FILE}: ${DDE_OBJS} ${TCL_STUB_LIB_FILE} @MAKE_DLL@ ${DDE_OBJS} $(TCL_STUB_LIB_FILE) $(SHLIB_LD_LIBS) - @-$(RM) ${DDE_LIB_FILE} - @-$(COPY) ${DDE_LIB_FILE}.sav ${DDE_LIB_FILE} - @-$(RM) ${DDE_LIB_FILE}.sav -${DDE_LIB_FILE}: ${DDE_OBJS} - @$(RM) ${DDE_LIB_FILE} - @MAKE_LIB@ ${DDE_OBJS} - @POST_MAKE_LIB@ - -${REG_DLL_FILE}: ${REG_OBJS} ${REG_LIB_FILE} ${TCL_STUB_LIB_FILE} - @-$(RM) ${REG_DLL_FILE} ${REG_LIB_FILE}.sav - @-$(COPY) ${REG_LIB_FILE} ${REG_LIB_FILE}.sav +${REG_DLL_FILE}: ${REG_OBJS} ${TCL_STUB_LIB_FILE} @MAKE_DLL@ ${REG_OBJS} $(TCL_STUB_LIB_FILE) $(SHLIB_LD_LIBS) - @-$(RM) ${REG_LIB_FILE} - @-$(COPY) ${REG_LIB_FILE}.sav ${REG_LIB_FILE} - @-$(RM) ${REG_LIB_FILE}.sav - -${REG_LIB_FILE}: ${REG_OBJS} - @$(RM) ${REG_LIB_FILE} - @MAKE_LIB@ ${REG_OBJS} - @POST_MAKE_LIB@ ${TEST_DLL_FILE}: ${TCLTEST_OBJS} ${TCL_STUB_LIB_FILE} @$(RM) ${TEST_DLL_FILE} ${TEST_LIB_FILE} @MAKE_DLL@ ${TCLTEST_OBJS} $(TCL_STUB_LIB_FILE) $(SHLIB_LD_LIBS) # use pre-built zlib1.dll -${ZLIB_DLL_FILE}: $(ZLIB_DIR)/win32/${ZLIB_DLL_FILE} - @$(COPY) $(ZLIB_DIR)/win32/${ZLIB_DLL_FILE} ${ZLIB_DLL_FILE} +${ZLIB_DLL_FILE}: ${TCL_STUB_LIB_FILE} + @if test "@ZLIB_LIBS@set" == "${ZLIB_DIR}/win64/zdll.libset" ; then \ + $(COPY) $(ZLIB_DIR)/win64/${ZLIB_DLL_FILE} ${ZLIB_DLL_FILE}; \ + else \ + $(COPY) $(ZLIB_DIR)/win32/${ZLIB_DLL_FILE} ${ZLIB_DLL_FILE}; \ + fi; # Add the object extension to the implicit rules. By default .obj is not # automatically added. @@ -566,9 +538,9 @@ gendate: # run (and the results checked) after updating to a new release of libtommath. gentommath_h: - $(TCL_EXE) "$(ROOT_DIR_NATIVE)\tools\fix_tommath_h.tcl" \ - "$(TOMMATH_DIR_NATIVE)\tommath.h" \ - > "$(GENERIC_DIR_NATIVE)\tclTomMath.h" + $(TCL_EXE) "$(ROOT_DIR_NATIVE)/tools/fix_tommath_h.tcl" \ + "$(TOMMATH_DIR_NATIVE)/tommath.h" \ + > "$(GENERIC_DIR_NATIVE)/tclTomMath.h" install: all install-binaries install-libraries install-doc install-packages @@ -662,15 +634,15 @@ install-libraries: libraries install-tzdata install-msgs do \ $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/http1.0"; \ done; - @echo "Installing package http 2.8.4 as a Tcl Module"; - @$(COPY) $(ROOT_DIR)/library/http/http.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.6/http-2.8.4.tm; + @echo "Installing package http 2.8.5 as a Tcl Module"; + @$(COPY) $(ROOT_DIR)/library/http/http.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.6/http-2.8.5.tm; @echo "Installing library opt0.4 directory"; @for j in $(ROOT_DIR)/library/opt/*.tcl; \ do \ $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/opt0.4"; \ done; - @echo "Installing package msgcat 1.4.5 as a Tcl Module"; - @$(COPY) $(ROOT_DIR)/library/msgcat/msgcat.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.5/msgcat-1.4.5.tm; + @echo "Installing package msgcat 1.5.0 as a Tcl Module"; + @$(COPY) $(ROOT_DIR)/library/msgcat/msgcat.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.5/msgcat-1.5.0.tm; @echo "Installing package tcltest 2.3.4 as a Tcl Module"; @$(COPY) $(ROOT_DIR)/library/tcltest/tcltest.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.5/tcltest-2.3.4.tm; @echo "Installing package platform 1.0.10 as a Tcl Module"; @@ -719,17 +691,19 @@ install-private-headers: libraries test: test-tcl test-packages -test-tcl: binaries $(TCLTEST) +test-tcl: binaries $(TCLSH) $(CAT32) $(TEST_DLL_FILE) TCL_LIBRARY="$(LIBRARY_DIR)"; export TCL_LIBRARY; \ - ./$(TCLTEST) "$(ROOT_DIR_NATIVE)/tests/all.tcl" $(TESTFLAGS) \ - -load "set ::ddelib [file normalize ${DDE_DLL_FILE}]; \ - set ::reglib [file normalize ${REG_DLL_FILE}]" | ./$(CAT32) + ./$(TCLSH) "$(ROOT_DIR_NATIVE)/tests/all.tcl" $(TESTFLAGS) \ + -load "package ifneeded Tcltest ${VERSION}@TCL_PATCH_LEVEL@ [list load [file normalize ${TEST_DLL_FILE}] Tcltest]; \ + package ifneeded dde 1.4.0 [list load [file normalize ${DDE_DLL_FILE}] dde]; \ + package ifneeded registry 1.3.0 [list load [file normalize ${REG_DLL_FILE}] registry]" | ./$(CAT32) -# Useful target to launch a built tcltest with the proper path,... -runtest: binaries $(TCLTEST) +# Useful target to launch a built tclsh with the proper path,... +runtest: binaries $(TCLSH) $(TEST_DLL_FILE) @TCL_LIBRARY="$(LIBRARY_DIR)"; export TCL_LIBRARY; \ - ./$(TCLTEST) $(TESTFLAGS) -load "set ::ddelib [file normalize ${DDE_DLL_FILE}]; \ - set ::reglib [file normalize ${REG_DLL_FILE}]" $(SCRIPT) + ./$(TCLSH) $(TESTFLAGS) -load "package ifneeded Tcltest ${VERSION}@TCL_PATCH_LEVEL@ [list load [file normalize ${TEST_DLL_FILE}] Tcltest]; \ + package ifneeded dde 1.4.0 [list load [file normalize ${DDE_DLL_FILE}] dde]; \ + package ifneeded registry 1.3.0 [list load [file normalize ${REG_DLL_FILE}] registry]" $(SCRIPT) # This target can be used to run tclsh from the build directory via # `make shell SCRIPT=foo.tcl` @@ -753,7 +727,7 @@ cleanhelp: clean: cleanhelp clean-packages $(RM) *.lib *.a *.exp *.dll *.$(RES) *.${OBJEXT} *~ \#* TAGS a.out - $(RM) $(TCLSH) $(TCLTEST) $(CAT32) + $(RM) $(TCLSH) $(CAT32) $(RM) *.pch *.ilk *.pdb distclean: distclean-packages clean @@ -768,7 +742,7 @@ PKG_CFG_ARGS = @PKG_CFG_ARGS@ PKG_DIR = ./pkgs packages: - @builddir=`pwd`; \ + @builddir=`pwd -P`; \ for i in $(PKGS_DIR)/*; do \ if [ -d $$i ] ; then \ if [ -x $$i/configure ] ; then \ @@ -776,7 +750,7 @@ packages: mkdir -p $(PKG_DIR)/$$pkg; \ if [ ! -f $(PKG_DIR)/$$pkg/Makefile ]; then \ ( cd $(PKG_DIR)/$$pkg; \ - echo "Configuring package '$$i' wd = `pwd`"; \ + echo "Configuring package '$$i' wd = `pwd -P`"; \ $$i/configure --with-tcl=$(PWD) --with-tclinclude=$(GENERIC_DIR) $(PKG_CFG_ARGS) --enable-shared --enable-threads; ) \ fi ; \ echo "Building package '$$pkg'"; \ @@ -787,7 +761,7 @@ packages: cd $$builddir install-packages: packages - @builddir=`pwd`; \ + @builddir=`pwd -P`; \ for i in $(PKGS_DIR)/*; do \ if [ -d $$i ]; then \ pkg=`basename $$i`; \ @@ -800,20 +774,20 @@ install-packages: packages cd $$builddir test-packages: tcltest packages - @builddir=`pwd`; \ + @builddir=`pwd -P`; \ for i in $(PKGS_DIR)/*; do \ if [ -d $$i ]; then \ pkg=`basename $$i`; \ if [ -f $(PKG_DIR)/$$pkg/Makefile ]; then \ echo "Testing package '$$pkg'"; \ - ( cd $(PKG_DIR)/$$pkg; $(MAKE) "LD_LIBRARY_PATH=$$builddir:${LD_LIBRARY_PATH}" "TCL_LIBRARY=${TCL_BUILDTIME_LIBRARY}" "TCLLIBPATH=$$builddir/pkgs" test "TCLSH_PROG=$$builddir/tcltest"; ) \ + ( cd $(PKG_DIR)/$$pkg; $(MAKE) "LD_LIBRARY_PATH=$$builddir:${LD_LIBRARY_PATH}" "TCL_LIBRARY=${TCL_BUILDTIME_LIBRARY}" "TCLLIBPATH=$$builddir/pkgs" test "TCLSH_PROG=$$builddir/${TCLSH}"; ) \ fi; \ fi; \ done; \ cd $$builddir clean-packages: - @builddir=`pwd`; \ + @builddir=`pwd -P`; \ for i in $(PKGS_DIR)/*; do \ if [ -d $$i ]; then \ pkg=`basename $$i`; \ @@ -825,7 +799,7 @@ clean-packages: cd $$builddir distclean-packages: - @builddir=`pwd`; \ + @builddir=`pwd -P`; \ for i in $(PKGS_DIR)/*; do \ if [ -d $$i ]; then \ pkg=`basename $$i`; \ @@ -24,28 +24,28 @@ In order to compile Tcl for Windows, you need the following: or - Linux + MinGW-w64 (any distribution e.g. Ubuntu) - (for either 32-bit or 64-bit executables) + Linux + MinGW-w64 [http://mingw-w64.sourceforge.net/] + (win32 or win64) or Cygwin + MinGW-w64 [http://cygwin.com/install.html] - (for either 32-bit or 64-bit executables) + (win32 or win64) or Darwin + MinGW-w64 [http://mingw-w64.sourceforge.net/] - (for either 32-bit or 64-bit executables) + (win32 or win64) or Msys + MinGW-w64 [http://mingw-w64.sourceforge.net/] - (for either 32-bit or 64-bit executables) + (win32 or win64) or - Msys + Mingw [http://www.mingw.org/download.shtml] - (32-bit executables only) + Msys + MinGW [http://www.mingw.org/download.shtml] + (win32 only) In practice, this release is built with Visual C++ 6.0 and the TEA @@ -67,20 +67,20 @@ configure/build process works just like the UNIX one, so you will want to refer to ../unix/README for available configure options. If you want 64-bit executables (x86_64), you need to configure using -the --enable-64bit option. Then make sure that the x86_64-w64-mingw32 +the --enable-64bit option. Make sure that the x86_64-w64-mingw32 compiler is present. For Cygwin this compiler can be found in the "mingw64-x86_64-gcc-core" package, which can be installed through the normal Cygwin install process. If you only want 32-bit executables, -the "mingw64-i686-gcc-core" package is what you need. If your Linux -distribution does not have a MinGW-w64 package, you can download one -from [https://sourceforge.net/projects/mingw-w64/files/] +the "mingw64-i686-gcc-core" package is what you need. For Linux, Darwin +and Msys, you can download a suitable win32 or win64 compiler from +[https://sourceforge.net/projects/mingw-w64/files/] Use the Makefile "install" target to install Tcl. It will install it according to the prefix options you provided in the correct directory structure. -Note that in order to run tclsh86.exe, you must ensure that tcl86.dll is on -your path, in the system directory, or in the directory containing +Note that in order to run tclsh85.exe, you must ensure that tcl85.dll is +on your path, in the system directory, or in the directory containing tclsh86.exe. Note: Tcl no longer provides support for Win32s. diff --git a/win/buildall.vc.bat b/win/buildall.vc.bat index c33aefd..e4f0a30 100755 --- a/win/buildall.vc.bat +++ b/win/buildall.vc.bat @@ -1,4 +1,5 @@ @echo off + :: This is an example batchfile for building everything. Please :: edit this (or make your own) for your needs and wants using :: the instructions for calling makefile.vc found in makefile.vc @@ -26,10 +27,11 @@ cd > nul :: path or have already run vcvars32.bat. Testing these envars proves :: cl.exe and friends are in your path. :: -if defined VCINSTALLDIR (goto :startBuilding) -if defined MSDRVDIR (goto :startBuilding) -if defined MSVCDIR (goto :startBuilding) -if defined MSSDK (goto :startBuilding) +if defined VCINSTALLDIR (goto :startBuilding) +if defined MSDEVDIR (goto :startBuilding) +if defined MSVCDIR (goto :startBuilding) +if defined MSSDK (goto :startBuilding) +if defined WINDOWSSDKDIR (goto :startBuilding) :: We need to run the development environment batch script that comes :: with developer studio (v4,5,6,7,etc...) All have it. This path @@ -62,42 +64,13 @@ if not %SYMBOLS%.==. set OPTS=symbols nmake -nologo -f makefile.vc release htmlhelp OPTS=%OPTS% %1 if errorlevel 1 goto error -:: Build the static core, dlls and shell. -:: -set OPTS=static -if not %SYMBOLS%.==. set OPTS=symbols,static -nmake -nologo -f makefile.vc release OPTS=%OPTS% %1 -if errorlevel 1 goto error - -:: Build the special static libraries that use the dynamic runtime. +:: Build the static core and shell. :: set OPTS=static,msvcrt if not %SYMBOLS%.==. set OPTS=symbols,static,msvcrt -nmake -nologo -f makefile.vc core dlls OPTS=%OPTS% %1 -if errorlevel 1 goto error - -:: Build the core and shell for thread support. -:: -set OPTS=threads -if not %SYMBOLS%.==. set OPTS=symbols,threads nmake -nologo -f makefile.vc shell OPTS=%OPTS% %1 if errorlevel 1 goto error -:: Build a static, thread support core library with a shell. -:: -set OPTS=static,threads -if not %SYMBOLS%.==. set OPTS=symbols,static,threads -nmake -nologo -f makefile.vc shell OPTS=%OPTS% %1 -if errorlevel 1 goto error - -:: Build the special static libraries that use the dynamic runtime, -:: but now with thread support. -:: -set OPTS=static,msvcrt,threads -if not %SYMBOLS%.==. set OPTS=symbols,static,msvcrt,threads -nmake -nologo -f makefile.vc core dlls OPTS=%OPTS% %1 -if errorlevel 1 goto error - set OPTS= set SYMBOLS= goto end diff --git a/win/coffbase.txt b/win/coffbase.txt index 7d19420..bdf5506 100644 --- a/win/coffbase.txt +++ b/win/coffbase.txt @@ -24,6 +24,7 @@ blt 0x10680000 0x00080000 iocpsock 0x10700000 0x00080000 tls 0x10780000 0x00100000 winico 0x10880000 0x00010000 +sample 0x108B0000 0x00010000 tile 0x10900000 0x00080000 memchan 0x109D0000 0x00010000 tdom 0x109E0000 0x00080000 @@ -32,6 +33,7 @@ tkvideo 0x10B00000 0x00010000 tclsdl 0x10B20000 0x00080000 vqtcl 0x10C00000 0x00010000 tdbc 0x10C40000 0x00010000 +thread 0x10C80000 0x00020000 ; ; insert new packages here ; diff --git a/win/configure b/win/configure index fed0959..0258898 100755 --- a/win/configure +++ b/win/configure @@ -840,18 +840,18 @@ if test -n "$ac_init_help"; then Optional Features: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --enable-threads build with threads - --enable-shared build and link with shared libraries --enable-shared + --enable-threads build with threads (default: on) + --enable-shared build and link with shared libraries (default: on) --enable-64bit enable 64bit support (where applicable) --enable-wince enable Win/CE support (where applicable) - --enable-symbols build with debugging symbols --disable-symbols + --enable-symbols build with debugging symbols (default: off) --enable-embedded-manifest embed manifest if possible (default: yes) Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-encoding encoding for configuration values + --with-encoding encoding for configuration values --with-celib=DIR use Windows/CE support library from DIR Some influential environment variables: @@ -1311,7 +1311,7 @@ SHELL=/bin/sh TCL_VERSION=8.6 TCL_MAJOR_VERSION=8 TCL_MINOR_VERSION=6 -TCL_PATCH_LEVEL="b2" +TCL_PATCH_LEVEL="b3" VER=$TCL_MAJOR_VERSION$TCL_MINOR_VERSION TCL_DDE_VERSION=1.4 @@ -3068,8 +3068,8 @@ else fi; if test "$tcl_ok" = "yes"; then - echo "$as_me:$LINENO: result: yes" >&5 -echo "${ECHO_T}yes" >&6 + echo "$as_me:$LINENO: result: yes (default)" >&5 +echo "${ECHO_T}yes (default)" >&6 TCL_THREADS=1 cat >>confdefs.h <<\_ACEOF #define TCL_THREADS 1 @@ -3598,8 +3598,8 @@ echo $ECHO_N "checking compiler flags... $ECHO_C" >&6 MAKE_EXE="\${CC} -o \$@" LIBPREFIX="lib" - extra_ldflags="$extra_ldflags -pipe" extra_cflags="$extra_cflags -pipe" + extra_ldflags="$extra_ldflags -pipe" if test "${SHARED_BUILD}" = "0" ; then # static @@ -4344,12 +4344,6 @@ esac # as we just assume that the platform hasn't got a usable z.lib #------------------------------------------------------------------------ -if test "$do64bit" = "yes"; then - - tcl_ok=no - -else - if test "${enable_shared+set}" = "set"; then enableval="$enable_shared" @@ -4361,14 +4355,21 @@ else fi - -fi - if test "$tcl_ok" = "yes"; then ZLIB_DLL_FILE=\${ZLIB_DLL_FILE} - ZLIB_LIBS=\${ZLIB_DIR}/win32/zdll.lib + if test "$do64bit" = "yes"; then + + ZLIB_LIBS=\${ZLIB_DIR}/win64/zdll.lib + + +else + + ZLIB_LIBS=\${ZLIB_DIR}/win32/zdll.lib + + +fi else diff --git a/win/configure.in b/win/configure.in index 2377938..0426bb1 100644 --- a/win/configure.in +++ b/win/configure.in @@ -14,7 +14,7 @@ SHELL=/bin/sh TCL_VERSION=8.6 TCL_MAJOR_VERSION=8 TCL_MINOR_VERSION=6 -TCL_PATCH_LEVEL="b2" +TCL_PATCH_LEVEL="b3" VER=$TCL_MAJOR_VERSION$TCL_MINOR_VERSION TCL_DDE_VERSION=1.4 @@ -120,19 +120,19 @@ esac # as we just assume that the platform hasn't got a usable z.lib #------------------------------------------------------------------------ -AS_IF([test "$do64bit" = "yes"], [ - tcl_ok=no -], [ AS_IF([test "${enable_shared+set}" = "set"], [ enableval="$enable_shared" tcl_ok=$enableval ], [ tcl_ok=yes ]) -]) AS_IF([test "$tcl_ok" = "yes"], [ AC_SUBST(ZLIB_DLL_FILE,[\${ZLIB_DLL_FILE}]) - AC_SUBST(ZLIB_LIBS,[\${ZLIB_DIR}/win32/zdll.lib]) + AS_IF([test "$do64bit" = "yes"], [ + AC_SUBST(ZLIB_LIBS,[\${ZLIB_DIR}/win64/zdll.lib]) + ], [ + AC_SUBST(ZLIB_LIBS,[\${ZLIB_DIR}/win32/zdll.lib]) + ]) ], [ AC_SUBST(ZLIB_OBJS,[\${ZLIB_OBJS}]) AC_DEFINE_UNQUOTED(NO_VIZ, 1) @@ -219,7 +219,7 @@ if test "$tcl_cv_intrinsics" = "yes"; then [Defined when the compilers supports intrinsics]) fi -# See if the <wspiapi.h> header file is present +# See if the <wspiapi.h> header file is present AC_CACHE_CHECK(for wspiapi.h, tcl_cv_wspiapi_h, diff --git a/win/makefile.bc b/win/makefile.bc index d17c624..18bfa28 100644 --- a/win/makefile.bc +++ b/win/makefile.bc @@ -433,10 +433,10 @@ install-libraries: -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\opt0.4" -@copy "$(ROOT)\library\opt\optparse.tcl" "$(SCRIPT_INSTALL_DIR)\opt0.4" -@copy "$(ROOT)\library\opt\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\opt0.4" - @echo installing msgcat1.4 - -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\msgcat1.4" - -@copy "$(ROOT)\library\msgcat\msgcat.tcl" "$(SCRIPT_INSTALL_DIR)\msgcat1.4" - -@copy "$(ROOT)\library\msgcat\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\msgcat1.4" + @echo installing msgcat1.5 + -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\msgcat1.5" + -@copy "$(ROOT)\library\msgcat\msgcat.tcl" "$(SCRIPT_INSTALL_DIR)\msgcat1.5" + -@copy "$(ROOT)\library\msgcat\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\msgcat1.5" @echo installing tcltest2.3 -@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\tcltest2.3" -@copy "$(ROOT)\library\tcltest\tcltest.tcl" "$(SCRIPT_INSTALL_DIR)\tcltest2.3" diff --git a/win/makefile.vc b/win/makefile.vc index 5183504..2784140 100644 --- a/win/makefile.vc +++ b/win/makefile.vc @@ -71,57 +71,62 @@ the build instructions. # Sets where to install Tcl from the built binaries. # C:\Progra~1\Tcl is assumed when not specified. # -# OPTS=static,msvcrt,staticpkg,nothreads,symbols,profile,loimpact,unchecked,pdbs,none +# OPTS=loimpact,msvcrt,nothreads,pdbs,profile,static,staticpkg,symbols,thrdalloc,tclalloc,unchecked,none # Sets special options for the core. The default is for none. # Any combination of the above may be used (comma separated). # 'none' will over-ride everything to nothing. # -# static = Builds a static library of the core instead of a -# dll. The shell will be static (and large), as well. -# msvcrt = Affects the static option only to switch it from +# loimpact = Adds a flag for how NT treats the heap to keep memory +# in use, low. This is said to impact alloc performance. +# msvcrt = Affects the static option only to switch it from # using libcmt(d) as the C runtime [by default] to # msvcrt(d). This is useful for static embedding # support. +# nothreads= Turns off full multithreading support. +# pdbs = Build detached symbols for release builds. +# profile = Adds profiling hooks. Map file is assumed. +# static = Builds a static library of the core instead of a +# dll. The static library will contain the dde and reg +# extensions. External applications who want to use +# this, need to link with the stub library as well as +# the static Tcl library.The shell will be static (and +# large), as well. # staticpkg = Affects the static option only to switch # tclshXX.exe to have the dde and reg extension linked # inside it. -# nothreads = Turns off full multithreading support. +# symbols = Debug build. Links to the debug C runtime, disables +# optimizations and creates pdb symbols files. # thrdalloc = Use the thread allocator (shared global free pool) # This is the default on threaded builds. # tclalloc = Use the old non-thread allocator -# symbols = Debug build. Links to the debug C runtime, disables -# optimizations and creates pdb symbols files. -# pdbs = Build detached symbols for release builds. -# profile = Adds profiling hooks. Map file is assumed. -# loimpact = Adds a flag for how NT treats the heap to keep memory -# in use, low. This is said to impact alloc performance. -# unchecked = Allows a symbols build to not use the debug +# unchecked= Allows a symbols build to not use the debug # enabled runtime (msvcrt.dll not msvcrtd.dll # or libcmt.lib not libcmtd.lib). # -# STATS=memdbg,compdbg,none +# STATS=compdbg,memdbg,none # Sets optional memory and bytecode compiler debugging code added # to the core. The default is for none. Any combination of the # above may be used (comma separated). 'none' will over-ride # everything to nothing. # -# memdbg = Enables the debugging memory allocator. # compdbg = Enables byte compilation logging. +# memdbg = Enables the debugging memory allocator. # -# CHECKS=nodep,fullwarn,64bit,none +# CHECKS=64bit,fullwarn,nodep,none # Sets special macros for checking compatability. # -# nodep = Turns off compatability macros to ensure the core -# isn't being built with deprecated functions. +# 64bit = Enable 64bit portability warnings (if available) # fullwarn = Builds with full compiler and link warnings enabled. # Very verbose. -# 64bit = Enable 64bit portability warnings (if available) +# nodep = Turns off compatability macros to ensure the core +# isn't being built with deprecated functions. # -# MACHINE=(IX86|IA64|AMD64|ALPHA) +# MACHINE=(ALPHA|AMD64|IA64|IX86) # Set the machine type used for the compiler, linker, and # resource compiler. This hook is needed to tell the tools # when alternate platforms are requested. IX86 is the default -# when not specified. +# when not specified. If the CPU environment variable has been +# set (ie: recent Platform SDK) then MACHINE is set from CPU. # # TMP_DIR=<path> # OUT_DIR=<path> @@ -178,7 +183,7 @@ Please `cd` to its location first. !error $(MSG) !endif -PROJECT = tcl +PROJECT = tcl !include "rules.vc" STUBPREFIX = $(PROJECT)stub @@ -231,10 +236,12 @@ INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\include TCLSHOBJS = \ $(TMP_DIR)\tclAppInit.obj \ +!if !$(STATIC_BUILD) !if $(TCL_USE_STATIC_PACKAGES) $(TMP_DIR)\tclWinReg.obj \ $(TMP_DIR)\tclWinDde.obj \ !endif +!endif $(TMP_DIR)\tclsh.res TCLTESTOBJS = \ @@ -243,10 +250,12 @@ TCLTESTOBJS = \ $(TMP_DIR)\tclTestProcBodyObj.obj \ $(TMP_DIR)\tclThreadTest.obj \ $(TMP_DIR)\tclWinTest.obj \ +!if !$(STATIC_BUILD) !if $(TCL_USE_STATIC_PACKAGES) $(TMP_DIR)\tclWinReg.obj \ $(TMP_DIR)\tclWinDde.obj \ !endif +!endif $(TMP_DIR)\testMain.obj COREOBJS = \ @@ -428,11 +437,13 @@ PLATFORMOBJS = \ $(TMP_DIR)\tclWinSock.obj \ $(TMP_DIR)\tclWinThrd.obj \ $(TMP_DIR)\tclWinTime.obj \ -!if !$(STATIC_BUILD) +!if $(STATIC_BUILD) + $(TMP_DIR)\tclWinReg.obj \ + $(TMP_DIR)\tclWinDde.obj \ +!else $(TMP_DIR)\tcl.res !endif - TCLOBJS = $(COREOBJS) $(ZLIBOBJS) $(TOMMATHOBJS) $(PLATFORMOBJS) TCLSTUBOBJS = \ @@ -564,27 +575,27 @@ install: install-binaries install-libraries install-docs install-pkgs test: test-core test-pkgs test-core: setup $(TCLTEST) dlls $(CAT32) - set TCL_LIBRARY=$(ROOT:\=/)/../library + set TCL_LIBRARY=$(ROOT:\=/)/library !if "$(OS)" == "Windows_NT" || "$(MSVCDIR)" == "IDE" - $(DEBUGGER) $(TCLTEST) "$(ROOT)/tests/all.tcl" $(TESTFLAGS) -loadfile << - set ::ddelib [file normalize $(TCLDDELIB:\=/)] - set ::reglib [file normalize $(TCLREGLIB:\=/)] + $(DEBUGGER) $(TCLTEST) "$(ROOT:\=/)/tests/all.tcl" $(TESTFLAGS) -loadfile << + package ifneeded dde 1.4.0 [list load "$(TCLDDELIB:\=/)" dde] + package ifneeded registry 1.3.0 [list load "$(TCLREGLIB:\=/)" registry] << !else @echo Please wait while the tests are collected... - $(TCLTEST) "$(ROOT)/tests/all.tcl" $(TESTFLAGS) -loadfile << > tests.log - set ::ddelib [file normalize $(TCLDDELIB:\=/)] - set ::reglib [file normalize $(TCLREGLIB:\=/)] + $(TCLTEST) "$(ROOT:\=/)/tests/all.tcl" $(TESTFLAGS) -loadfile << > tests.log + package ifneeded dde 1.4.0 "$(TCLDDELIB:\=/)" dde] + package ifneeded registry 1.3.0 "$(TCLREGLIB:\=/)" registry] << type tests.log | more !endif runtest: setup $(TCLTEST) dlls $(CAT32) - set TCL_LIBRARY=$(ROOT)/library + set TCL_LIBRARY=$(ROOT:\=/)/library $(DEBUGGER) $(TCLTEST) $(SCRIPT) runshell: setup $(TCLSH) dlls - set TCL_LIBRARY=$(ROOT)/library + set TCL_LIBRARY=$(ROOT:\=/)/library $(DEBUGGER) $(TCLSH) $(SCRIPT) setup: @@ -819,7 +830,6 @@ install-docs: @$(CPY) "$(HELPCNT)" "$(DOC_INSTALL_DIR)\" !endif -#" #--------------------------------------------------------------------- # Build tclConfig.sh for the TEA build system. #--------------------------------------------------------------------- @@ -1158,15 +1168,15 @@ install-libraries: tclConfig install-msgs install-tzdata install-tzdata: @echo Installing time zone data - @set TCL_LIBRARY=$(ROOT)/library - @$(TCLSH_NATIVE) "$(ROOT)/tools/installData.tcl" \ - "$(ROOT)/library/tzdata" "$(SCRIPT_INSTALL_DIR)/tzdata" + @set TCL_LIBRARY=$(ROOT:\=/)/library + @$(TCLSH_NATIVE) "$(ROOT:\=/)/tools/installData.tcl" \ + "$(ROOT:\=/)/library/tzdata" "$(SCRIPT_INSTALL_DIR)/tzdata" install-msgs: @echo Installing message catalogs - @set TCL_LIBRARY=$(ROOT)/library - @$(TCLSH_NATIVE) "$(ROOT)/tools/installData.tcl" \ - "$(ROOT)/library/msgs" "$(SCRIPT_INSTALL_DIR)/msgs" + @set TCL_LIBRARY=$(ROOT:\=/)/library + @$(TCLSH_NATIVE) "$(ROOT:\=/)/tools/installData.tcl" \ + "$(ROOT:\=/)/library/msgs" "$(SCRIPT_INSTALL_DIR)/msgs" #--------------------------------------------------------------------- # Clean up diff --git a/win/nmakehlp.c b/win/nmakehlp.c index b5e0788..b1a1517 100644 --- a/win/nmakehlp.c +++ b/win/nmakehlp.c @@ -14,8 +14,13 @@ #define _CRT_SECURE_NO_DEPRECATE #include <windows.h> +#define NO_SHLWAPI_GDI +#define NO_SHLWAPI_STREAM +#define NO_SHLWAPI_REG +#include <shlwapi.h> #pragma comment (lib, "user32.lib") #pragma comment (lib, "kernel32.lib") +#pragma comment (lib, "shlwapi.lib") #include <stdio.h> #include <math.h> @@ -37,12 +42,13 @@ /* protos */ -int CheckForCompilerFeature(const char *option); -int CheckForLinkerFeature(const char *option); -int IsIn(const char *string, const char *substring); -int SubstituteFile(const char *substs, const char *filename); -const char * GetVersionFromFile(const char *filename, const char *match); -DWORD WINAPI ReadFromPipe(LPVOID args); +static int CheckForCompilerFeature(const char *option); +static int CheckForLinkerFeature(const char *option); +static int IsIn(const char *string, const char *substring); +static int SubstituteFile(const char *substs, const char *filename); +static int QualifyPath(const char *path); +static const char *GetVersionFromFile(const char *filename, const char *match, int numdots); +static DWORD WINAPI ReadFromPipe(LPVOID args); /* globals */ @@ -147,12 +153,23 @@ main( &dwWritten, NULL); return 0; } - printf("%s\n", GetVersionFromFile(argv[2], argv[3])); + printf("%s\n", GetVersionFromFile(argv[2], argv[3], *(argv[1]+2) - '0')); return 0; + case 'Q': + if (argc != 3) { + chars = snprintf(msg, sizeof(msg) - 1, + "usage: %s -Q path\n" + "Emit the fully qualified path\n" + "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, + &dwWritten, NULL); + return 2; + } + return QualifyPath(argv[2]); } } chars = snprintf(msg, sizeof(msg) - 1, - "usage: %s -c|-l|-f|-g|-V ...\n" + "usage: %s -c|-f|-l|-Q|-s|-V ...\n" "This is a little helper app to equalize shell differences between WinNT and\n" "Win9x and get nmake.exe to accomplish its job.\n", argv[0]); @@ -160,7 +177,7 @@ main( return 2; } -int +static int CheckForCompilerFeature( const char *option) { @@ -245,7 +262,7 @@ CheckForCompilerFeature( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars], (300-chars), 0); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg,lstrlen(msg), &err,NULL); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL); return 2; } @@ -294,7 +311,7 @@ CheckForCompilerFeature( || strstr(Err.buffer, "D2021") != NULL); } -int +static int CheckForLinkerFeature( const char *option) { @@ -373,7 +390,7 @@ CheckForLinkerFeature( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars], (300-chars), 0); - WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg,lstrlen(msg), &err,NULL); + WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL); return 2; } @@ -419,7 +436,7 @@ CheckForLinkerFeature( strstr(Err.buffer, "LNK4044") != NULL); } -DWORD WINAPI +static DWORD WINAPI ReadFromPipe( LPVOID args) { @@ -444,7 +461,7 @@ ReadFromPipe( return 0; /* makes the compiler happy */ } -int +static int IsIn( const char *string, const char *substring) @@ -459,10 +476,11 @@ IsIn( * package provide or package ifneeded. */ -const char * +static const char * GetVersionFromFile( const char *filename, - const char *match) + const char *match, + int numdots) { size_t cbBuffer = 100; static char szBuffer[100]; @@ -480,9 +498,10 @@ GetVersionFromFile( p = strstr(szBuffer, match); if (p != NULL) { /* - * Skip to first digit. + * Skip to first digit after the match. */ + p += strlen(match); while (*p && !isdigit(*p)) { ++p; } @@ -492,7 +511,8 @@ GetVersionFromFile( */ q = p; - while (*q && (isalnum(*q) || *q == '.')) { + while (*q && (strchr("0123456789.ab", *q)) && ((!strchr(".ab", *q) + && (!strchr("ab", q[-1])) || --numdots))) { ++q; } @@ -565,7 +585,7 @@ list_free(list_item_t **listPtrPtr) * << */ -int +static int SubstituteFile( const char *substitutions, const char *filename) @@ -611,11 +631,11 @@ SubstituteFile( } } #endif - + /* * Run the substitutions over each line of the input */ - + while (fgets(szBuffer, cbBuffer, fp) != NULL) { list_item_t *p = NULL; for (p = substPtr; p != NULL; p = p->nextPtr) { @@ -635,12 +655,36 @@ SubstituteFile( } printf(szBuffer); } - + list_free(&substPtr); } fclose(fp); return 0; } + +/* + * QualifyPath -- + * + * This composes the current working directory with a provided path + * and returns the fully qualified and normalized path. + * Mostly needed to setup paths for testing. + */ + +static int +QualifyPath( + const char *szPath) +{ + char szCwd[MAX_PATH + 1]; + char szTmp[MAX_PATH + 1]; + char *p; + GetCurrentDirectory(MAX_PATH, szCwd); + while ((p = strchr(szPath, '/')) && *p) + *p = '\\'; + PathCombine(szTmp, szCwd, szPath); + PathCanonicalize(szCwd, szTmp); + printf("%s\n", szCwd); + return 0; +} /* * Local variables: diff --git a/win/rules.vc b/win/rules.vc index 3fbaaaf..1513198 100644 --- a/win/rules.vc +++ b/win/rules.vc @@ -8,7 +8,7 @@ # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # Copyright (c) 2001-2003 David Gravereaux. -# Copyright (c) 2003-2007 Patrick Thoyts +# Copyright (c) 2003-2008 Patrick Thoyts #------------------------------------------------------------------------------ !ifndef _RULES_VC @@ -218,7 +218,7 @@ DEBUG = 0 SYMBOLS = 0 PROFILE = 0 PGO = 0 -MSVCRT = 0 +MSVCRT = 1 LOIMPACT = 0 TCL_USE_STATIC_PACKAGES = 0 USE_THREAD_ALLOC = 1 @@ -234,18 +234,23 @@ STATIC_BUILD = 0 !message *** Doing msvcrt MSVCRT = 1 !else +!if !$(STATIC_BUILD) +MSVCRT = 1 +!else MSVCRT = 0 !endif -!if [nmakehlp -f $(OPTS) "staticpkg"] +!endif +!if [nmakehlp -f $(OPTS) "staticpkg"] && $(STATIC_BUILD) !message *** Doing staticpkg TCL_USE_STATIC_PACKAGES = 1 !else TCL_USE_STATIC_PACKAGES = 0 !endif !if [nmakehlp -f $(OPTS) "nothreads"] +!message *** Compile explicitly for non-threaded tcl TCL_THREADS = 0 +USE_THREAD_ALLOC= 0 !else -!message *** Doing threads TCL_THREADS = 1 USE_THREAD_ALLOC= 1 !endif @@ -287,7 +292,7 @@ LOIMPACT = 0 USE_THREAD_ALLOC = 1 !endif !if [nmakehlp -f $(OPTS) "tclalloc"] -!message *** Doing thrdalloc +!message *** Doing tclalloc USE_THREAD_ALLOC = 0 !endif !if [nmakehlp -f $(OPTS) "unchecked"] @@ -298,15 +303,6 @@ UNCHECKED = 0 !endif !endif - -!if !$(STATIC_BUILD) -# Make sure we don't build overly fat DLLs. -MSVCRT = 1 -# We shouldn't statically put the extensions inside the shell when dynamic. -TCL_USE_STATIC_PACKAGES = 0 -!endif - - #---------------------------------------------------------- # Figure-out how to name our intermediate and output directories. # We wouldn't want different builds to use the same .obj files @@ -348,10 +344,8 @@ TMP_DIRFULL = .\$(BUILDDIRTOP)\$(PROJECT)_ThreadedDynamicStaticX TMP_DIRFULL = $(TMP_DIRFULL:Static=) SUFX = $(SUFX:s=) EXT = dll -!if $(MSVCRT) TMP_DIRFULL = $(TMP_DIRFULL:X=) SUFX = $(SUFX:x=) -!endif !else TMP_DIRFULL = $(TMP_DIRFULL:Dynamic=) EXT = lib @@ -583,12 +577,6 @@ Failed to find tcl.h. The TCLDIR macro does not appear correct. TCL_VERSION = $(TCL_MAJOR_VERSION)$(TCL_MINOR_VERSION) -!if $(TCL_VERSION) < 81 -TCL_DOES_STUBS = 0 -!else -TCL_DOES_STUBS = 1 -!endif - !if $(TCLINSTALL) TCLSH = "$(_TCLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX).exe" !if !exist($(TCLSH)) && $(TCL_THREADS) diff --git a/win/tclAppInit.c b/win/tclAppInit.c index d6da500..56f45a0 100644 --- a/win/tclAppInit.c +++ b/win/tclAppInit.c @@ -109,9 +109,9 @@ _tmain( * Forward slashes substituted for backslashes. */ - for (p = argv[0]; *p != TEXT('\0'); p++) { - if (*p == TEXT('\\')) { - *p = TEXT('/'); + for (p = argv[0]; *p != '\0'; p++) { + if (*p == '\\') { + *p = '/'; } } @@ -242,13 +242,13 @@ setargv( */ size = 2; - for (p = cmdLine; *p != TEXT('\0'); p++) { - if ((*p == TEXT(' ')) || (*p == TEXT('\t'))) { /* INTL: ISO space. */ + for (p = cmdLine; *p != '\0'; p++) { + if ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */ size++; - while ((*p == TEXT(' ')) || (*p == TEXT('\t'))) { /* INTL: ISO space. */ + while ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */ p++; } - if (*p == TEXT('\0')) { + if (*p == '\0') { break; } } @@ -267,10 +267,10 @@ setargv( p = cmdLine; for (argc = 0; argc < size; argc++) { argv[argc] = arg = argSpace; - while ((*p == TEXT(' ')) || (*p == TEXT('\t'))) { /* INTL: ISO space. */ + while ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */ p++; } - if (*p == TEXT('\0')) { + if (*p == '\0') { break; } @@ -278,14 +278,14 @@ setargv( slashes = 0; while (1) { copy = 1; - while (*p == TEXT('\\')) { + while (*p == '\\') { slashes++; p++; } - if (*p == TEXT('"')) { + if (*p == '"') { if ((slashes & 1) == 0) { copy = 0; - if ((inquote) && (p[1] == TEXT('"'))) { + if ((inquote) && (p[1] == '"')) { p++; copy = 1; } else { @@ -296,13 +296,13 @@ setargv( } while (slashes) { - *arg = TEXT('\\'); + *arg = '\\'; arg++; slashes--; } - if ((*p == TEXT('\0')) || (!inquote && - ((*p == TEXT(' ')) || (*p == TEXT('\t'))))) { /* INTL: ISO space. */ + if ((*p == '\0') || (!inquote && + ((*p == ' ') || (*p == '\t')))) { /* INTL: ISO space. */ break; } if (copy != 0) { diff --git a/win/tclWinChan.c b/win/tclWinChan.c index 517aa20..52b9e32 100644 --- a/win/tclWinChan.c +++ b/win/tclWinChan.c @@ -940,8 +940,9 @@ TclpOpenFileChannel( } TclWinConvertError(err); if (interp != (Tcl_Interp *) NULL) { - Tcl_AppendResult(interp, "couldn't open \"", TclGetString(pathPtr), - "\": ", Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't open \"%s\": %s", + TclGetString(pathPtr), Tcl_PosixError(interp))); } return NULL; } @@ -959,9 +960,9 @@ TclpOpenFileChannel( if (handle == INVALID_HANDLE_VALUE) { TclWinConvertError(GetLastError()); if (interp != (Tcl_Interp *) NULL) { - Tcl_AppendResult(interp, "couldn't reopen serial \"", - TclGetString(pathPtr), "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't reopen serial \"%s\": %s", + TclGetString(pathPtr), Tcl_PosixError(interp))); } return NULL; } @@ -995,8 +996,9 @@ TclpOpenFileChannel( */ channel = NULL; - Tcl_AppendResult(interp, "couldn't open \"", TclGetString(pathPtr), - "\": bad file type", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't open \"%s\": bad file type", + TclGetString(pathPtr))); Tcl_SetErrorCode(interp, "TCL", "VALUE", "CHANNEL", "BAD_TYPE", NULL); break; diff --git a/win/tclWinDde.c b/win/tclWinDde.c index 183fe02..d0600e6 100644 --- a/win/tclWinDde.c +++ b/win/tclWinDde.c @@ -26,6 +26,12 @@ # define Tcl_WinUtfToTChar(a,b,c) Tcl_UtfToExternalDString(NULL,a,b,c) #endif +#if !defined(NDEBUG) + /* test POKE server Implemented for debug mode only */ +# undef CBF_FAIL_POKES +# define CBF_FAIL_POKES 0 +#endif + /* * TCL_STORAGE_CLASS is set unconditionally to DLLEXPORT because the Dde_Init * declaration is in the source file itself, which is only accessed when we @@ -90,7 +96,7 @@ static DWORD ddeInstance; /* The application instance handle given to us * by DdeInitialize. */ static int ddeIsServer = 0; -#define TCL_DDE_VERSION "1.4.0b1" +#define TCL_DDE_VERSION "1.4.0" #define TCL_DDE_PACKAGE_NAME "dde" #define TCL_DDE_SERVICE_NAME TEXT("TclEval") #define TCL_DDE_EXECUTE_RESULT TEXT("$TCLEVAL$EXECUTE$RESULT") @@ -157,7 +163,8 @@ Dde_Init( #ifdef UNICODE if (TclWinGetPlatformId() < VER_PLATFORM_WIN32_NT) { - Tcl_AppendResult(interp, "Win32s and Windows 9x are not supported platforms", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "Win32s and Windows 9x are not supported platforms", -1)); return TCL_ERROR; } #endif @@ -749,7 +756,7 @@ DdeServerProc( } else { returnString = (char *) Tcl_GetUnicodeFromObj(convPtr->returnPackagePtr, &len); - len = 2 * len + 1; + len = sizeof(TCHAR) * len + 1; } ddeReturn = DdeCreateDataHandle(ddeInstance, (BYTE *)returnString, (DWORD) len+1, 0, ddeItem, uFmt, 0); @@ -770,7 +777,7 @@ DdeServerProc( } else { returnString = (char *) Tcl_GetUnicodeFromObj( variableObjPtr, &len); - len = 2 * len + 1; + len = sizeof(TCHAR) * len + 1; } ddeReturn = DdeCreateDataHandle(ddeInstance, (BYTE *)returnString, (DWORD) len+1, 0, ddeItem, @@ -785,6 +792,53 @@ DdeServerProc( } return ddeReturn; +#if !CBF_FAIL_POKES + case XTYP_POKE: + /* + * This is a poke for a Tcl variable, only implemented in + * debug/UNICODE mode. + */ + ddeReturn = DDE_FNOTPROCESSED; + + if ((uFmt != CF_TEXT) && (uFmt != CF_UNICODETEXT)) { + return ddeReturn; + } + + for (convPtr = tsdPtr->currentConversations; (convPtr != NULL) + && (convPtr->hConv != hConv); convPtr = convPtr->nextPtr) { + /* + * Empty loop body. + */ + } + + if (convPtr && !Tcl_IsSafe(convPtr->riPtr->interp)) { + Tcl_DString ds; + Tcl_Obj *variableObjPtr; + + len = DdeQueryString(ddeInstance, ddeItem, NULL, 0, CP_WINUNICODE); + Tcl_DStringInit(&dString); + Tcl_DStringSetLength(&dString, (len + 1) * sizeof(TCHAR) - 1); + utilString = (TCHAR *) Tcl_DStringValue(&dString); + DdeQueryString(ddeInstance, ddeItem, utilString, (DWORD) len + 1, + CP_WINUNICODE); + Tcl_WinTCharToUtf(utilString, -1, &ds); + utilString = (TCHAR *) DdeAccessData(hData, &dlen); + if (uFmt == CF_TEXT) { + variableObjPtr = Tcl_NewStringObj((char *)utilString, -1); + } else { + variableObjPtr = Tcl_NewUnicodeObj(utilString, -1); + } + + Tcl_SetVar2Ex(convPtr->riPtr->interp, Tcl_DStringValue(&ds), NULL, + variableObjPtr, TCL_GLOBAL_ONLY); + + Tcl_DStringFree(&ds); + Tcl_DStringFree(&dString); + ddeReturn = (HDDEDATA) DDE_FACK; + } + return ddeReturn; + +#endif case XTYP_EXECUTE: { /* * Execute this script. The results will be saved into a list object @@ -947,8 +1001,12 @@ MakeDdeConnection( if (ddeConv == (HCONV) NULL) { if (interp != NULL) { - Tcl_AppendResult(interp, "no registered server named \"", - name, "\"", NULL); + Tcl_DString dString; + + Tcl_WinTCharToUtf(name, -1, &dString); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "no registered server named \"%s\"", Tcl_DStringValue(&dString))); + Tcl_DStringFree(&dString); Tcl_SetErrorCode(interp, "TCL", "DDE", "NO_SERVER", NULL); } return TCL_ERROR; @@ -1424,7 +1482,11 @@ DdeObjCmd( serviceName = DdeSetServerName(interp, serviceName, flags, handlerPtr); if (serviceName != NULL) { +#ifdef UNICODE Tcl_SetObjResult(interp, Tcl_NewUnicodeObj((Tcl_UniChar *) serviceName, -1)); +#else + Tcl_SetObjResult(interp, Tcl_NewStringObj(serviceName, -1)); +#endif } else { Tcl_ResetResult(interp); } @@ -1432,15 +1494,15 @@ DdeObjCmd( case DDE_EXECUTE: { int dataLength; - const char *dataString; + const Tcl_UniChar *dataString; if (flags & DDE_FLAG_BINARY) { - dataString = (const char *) + dataString = (const Tcl_UniChar *) Tcl_GetByteArrayFromObj(objv[firstArg + 2], &dataLength); } else { dataString = - Tcl_GetStringFromObj(objv[firstArg + 2], &dataLength); - dataLength += 1; + Tcl_GetUnicodeFromObj(objv[firstArg + 2], &dataLength); + dataLength = (dataLength + 1) * sizeof(Tcl_UniChar); } if (dataLength <= 0) { @@ -1461,15 +1523,15 @@ DdeObjCmd( } ddeData = DdeCreateDataHandle(ddeInstance, (BYTE *) dataString, - (DWORD) dataLength, 0, 0, CF_TEXT, 0); + (DWORD) dataLength, 0, 0, (flags & DDE_FLAG_BINARY) ? CF_TEXT : CF_UNICODETEXT, 0); if (ddeData != NULL) { if (flags & DDE_FLAG_ASYNC) { DdeClientTransaction((LPBYTE) ddeData, 0xFFFFFFFF, hConv, 0, - CF_TEXT, XTYP_EXECUTE, TIMEOUT_ASYNC, &ddeResult); + (flags & DDE_FLAG_BINARY) ? CF_TEXT : CF_UNICODETEXT, XTYP_EXECUTE, TIMEOUT_ASYNC, &ddeResult); DdeAbandonTransaction(ddeInstance, hConv, ddeResult); } else { ddeReturn = DdeClientTransaction((LPBYTE) ddeData, 0xFFFFFFFF, - hConv, 0, CF_TEXT, XTYP_EXECUTE, 30000, NULL); + hConv, 0, (flags & DDE_FLAG_BINARY) ? CF_TEXT : CF_UNICODETEXT, XTYP_EXECUTE, 30000, NULL); if (ddeReturn == 0) { SetDdeError(interp); result = TCL_ERROR; @@ -1483,8 +1545,13 @@ DdeObjCmd( break; } case DDE_REQUEST: { - const char *itemString = Tcl_GetStringFromObj(objv[firstArg + 2], +#ifdef UNICODE + const TCHAR *itemString = (TCHAR *) Tcl_GetUnicodeFromObj(objv[firstArg + 2], + &length); +#else + const TCHAR *itemString = Tcl_GetStringFromObj(objv[firstArg + 2], &length); +#endif if (length == 0) { Tcl_SetObjResult(interp, @@ -1506,22 +1573,23 @@ DdeObjCmd( CP_WINUNICODE); if (ddeItem != NULL) { ddeData = DdeClientTransaction(NULL, 0, hConv, ddeItem, - CF_TEXT, XTYP_REQUEST, 5000, NULL); + (flags & DDE_FLAG_BINARY) ? CF_TEXT : CF_UNICODETEXT, XTYP_REQUEST, 5000, NULL); if (ddeData == NULL) { SetDdeError(interp); result = TCL_ERROR; } else { DWORD tmp; - const char *dataString = (const char *) DdeAccessData(ddeData, &tmp); + const Tcl_UniChar *dataString = (const Tcl_UniChar *) DdeAccessData(ddeData, &tmp); if (flags & DDE_FLAG_BINARY) { returnObjPtr = Tcl_NewByteArrayObj((BYTE *) dataString, (int) tmp); } else { - if (tmp && !dataString[tmp-1]) { + tmp >>= 1; + if (tmp && !dataString[(tmp-1)]) { --tmp; } - returnObjPtr = Tcl_NewStringObj(dataString, + returnObjPtr = Tcl_NewUnicodeObj(dataString, (int) tmp); } DdeUnaccessData(ddeData); @@ -1537,8 +1605,13 @@ DdeObjCmd( break; } case DDE_POKE: { - const char *itemString = Tcl_GetStringFromObj(objv[firstArg + 2], +#ifdef UNICODE + const TCHAR *itemString = (TCHAR *) Tcl_GetUnicodeFromObj(objv[firstArg + 2], &length); +#else + const TCHAR *itemString = Tcl_GetStringFromObj(objv[firstArg + 2], + &length); +#endif BYTE *dataString; if (length == 0) { @@ -1553,8 +1626,8 @@ DdeObjCmd( Tcl_GetByteArrayFromObj(objv[firstArg + 3], &length); } else { dataString = (BYTE *) - Tcl_GetStringFromObj(objv[firstArg + 3], &length); - length += 1; + Tcl_GetUnicodeFromObj(objv[firstArg + 3], &length); + length = 2 * length + 1; } hConv = DdeConnect(ddeInstance, ddeService, ddeTopic, NULL); @@ -1569,7 +1642,7 @@ DdeObjCmd( CP_WINUNICODE); if (ddeItem != NULL) { ddeData = DdeClientTransaction(dataString, (DWORD) length, - hConv, ddeItem, CF_TEXT, XTYP_POKE, 5000, NULL); + hConv, ddeItem, (flags & DDE_FLAG_BINARY) ? CF_TEXT : CF_UNICODETEXT, XTYP_POKE, 5000, NULL); if (ddeData == NULL) { SetDdeError(interp); result = TCL_ERROR; @@ -1638,9 +1711,9 @@ DdeObjCmd( */ if (Tcl_IsSafe(riPtr->interp) && riPtr->handlerPtr == NULL) { - Tcl_SetResult(riPtr->interp, "permission denied: " - "a handler procedure must be defined for use in " - "a safe interp", TCL_STATIC); + Tcl_SetObjResult(riPtr->interp, Tcl_NewStringObj( + "permission denied: a handler procedure must be" + " defined for use in a safe interp", -1)); Tcl_SetErrorCode(interp, "TCL", "DDE", "SECURITY_CHECK", NULL); result = TCL_ERROR; @@ -1712,24 +1785,24 @@ DdeObjCmd( } objPtr = Tcl_ConcatObj(objc, objv); - string = Tcl_GetStringFromObj(objPtr, &length); + string = (const char *) Tcl_GetUnicodeFromObj(objPtr, &length); ddeItemData = DdeCreateDataHandle(ddeInstance, - (BYTE *) string, (DWORD) length+1, 0, 0, CF_TEXT, 0); + (BYTE *) string, (DWORD) 2*length+2, 0, 0, CF_UNICODETEXT, 0); if (flags & DDE_FLAG_ASYNC) { ddeData = DdeClientTransaction((LPBYTE) ddeItemData, 0xFFFFFFFF, hConv, 0, - CF_TEXT, XTYP_EXECUTE, TIMEOUT_ASYNC, &ddeResult); + CF_UNICODETEXT, XTYP_EXECUTE, TIMEOUT_ASYNC, &ddeResult); DdeAbandonTransaction(ddeInstance, hConv, ddeResult); } else { ddeData = DdeClientTransaction((LPBYTE) ddeItemData, 0xFFFFFFFF, hConv, 0, - CF_TEXT, XTYP_EXECUTE, 30000, NULL); + CF_UNICODETEXT, XTYP_EXECUTE, 30000, NULL); if (ddeData != 0) { ddeCookie = DdeCreateStringHandle(ddeInstance, TCL_DDE_EXECUTE_RESULT, CP_WINUNICODE); ddeData = DdeClientTransaction(NULL, 0, hConv, ddeCookie, - CF_TEXT, XTYP_REQUEST, 30000, NULL); + CF_UNICODETEXT, XTYP_REQUEST, 30000, NULL); } } @@ -1743,6 +1816,7 @@ DdeObjCmd( if (!(flags & DDE_FLAG_ASYNC)) { Tcl_Obj *resultPtr; + Tcl_UniChar *ddeDataString; /* * The return handle has a two or four element list in it. The @@ -1755,10 +1829,11 @@ DdeObjCmd( resultPtr = Tcl_NewObj(); length = DdeGetData(ddeData, NULL, 0, 0); - Tcl_SetObjLength(resultPtr, (length + 1) * sizeof(TCHAR) - 1); - string = Tcl_GetString(resultPtr); - DdeGetData(ddeData, (BYTE *) string, (DWORD) length, 0); - Tcl_SetObjLength(resultPtr, (int) strlen(string)); + ddeDataString = ckalloc(length); + DdeGetData(ddeData, (BYTE *) ddeDataString, (DWORD) length, 0); + length = (length >> 1) - 1; + resultPtr = Tcl_NewUnicodeObj(ddeDataString, length); + ckfree(ddeDataString); if (Tcl_ListObjIndex(NULL, resultPtr, 0, &objPtr) != TCL_OK) { Tcl_DecrRefCount(resultPtr); diff --git a/win/tclWinFCmd.c b/win/tclWinFCmd.c index 77a5b82..ac88861 100644 --- a/win/tclWinFCmd.c +++ b/win/tclWinFCmd.c @@ -1530,8 +1530,8 @@ StatError( * error. */ { TclWinConvertError(GetLastError()); - Tcl_AppendResult(interp, "could not read \"", TclGetString(fileName), - "\": ", Tcl_PosixError(interp), (char *) NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf("could not read \"%s\": %s", + TclGetString(fileName), Tcl_PosixError(interp))); } /* @@ -1649,9 +1649,9 @@ ConvertFileNameFormat( if (splitPath == NULL || pathc == 0) { if (interp != NULL) { - Tcl_AppendResult(interp, "could not read \"", - Tcl_GetString(fileName), "\": no such file or directory", - (char *) NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "could not read \"%s\": no such file or directory", + Tcl_GetString(fileName))); errno = ENOENT; Tcl_PosixError(interp); } @@ -1738,11 +1738,11 @@ ConvertFileNameFormat( } nativeName = data.cAlternateFileName; if (longShort) { - if (data.cFileName[0] != TEXT('\0')) { + if (data.cFileName[0] != '\0') { nativeName = data.cFileName; } } else { - if (data.cAlternateFileName[0] == TEXT('\0')) { + if (data.cAlternateFileName[0] == '\0') { nativeName = (TCHAR *) data.cFileName; } } @@ -1941,9 +1941,9 @@ CannotSetAttribute( Tcl_Obj *fileName, /* The name of the file. */ Tcl_Obj *attributePtr) /* The new value of the attribute. */ { - Tcl_AppendResult(interp, "cannot set attribute \"", - tclpFileAttrStrings[objIndex], "\" for file \"", - Tcl_GetString(fileName), "\": attribute is readonly", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "cannot set attribute \"%s\" for file \"%s\": attribute is readonly", + tclpFileAttrStrings[objIndex], Tcl_GetString(fileName))); errno = EINVAL; Tcl_PosixError(interp); return TCL_ERROR; diff --git a/win/tclWinFile.c b/win/tclWinFile.c index 1f56060..a1189f5 100644 --- a/win/tclWinFile.c +++ b/win/tclWinFile.c @@ -1048,10 +1048,9 @@ TclpMatchInDirectory( TclWinConvertError(err); if (interp != NULL) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "couldn't read directory \"", - Tcl_DStringValue(&dsOrig), "\": ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't read directory \"%s\": %s", + Tcl_DStringValue(&dsOrig), Tcl_PosixError(interp))); } Tcl_DStringFree(&dsOrig); return TCL_ERROR; @@ -1785,7 +1784,7 @@ NativeIsExec( return 0; } - if (path[len-4] != TEXT('.')) { + if (path[len-4] != '.') { return 0; } @@ -1866,8 +1865,9 @@ TclpGetCwd( if (GetCurrentDirectory(MAX_PATH, buffer) == 0) { TclWinConvertError(GetLastError()); if (interp != NULL) { - Tcl_AppendResult(interp, "error getting working directory name: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error getting working directory name: %s", + Tcl_PosixError(interp))); } return NULL; } diff --git a/win/tclWinInit.c b/win/tclWinInit.c index d89c98e..f552e2c 100644 --- a/win/tclWinInit.c +++ b/win/tclWinInit.c @@ -101,6 +101,10 @@ static TclInitProcessGlobalValueProc InitializeDefaultLibraryDir; static ProcessGlobalValue defaultLibraryDir = {0, 0, NULL, NULL, InitializeDefaultLibraryDir, NULL, NULL}; +static TclInitProcessGlobalValueProc InitializeSourceLibraryDir; +static ProcessGlobalValue sourceLibraryDir = + {0, 0, NULL, NULL, InitializeSourceLibraryDir, NULL, NULL}; + static void AppendEnvironment(Tcl_Obj *listPtr, const char *lib); static int ToUtf(const WCHAR *wSrc, char *dst); @@ -175,7 +179,7 @@ TclpInitLibraryPath( int *lengthPtr, Tcl_Encoding *encodingPtr) { -#define LIBRARY_SIZE 32 +#define LIBRARY_SIZE 64 Tcl_Obj *pathPtr; char installLib[LIBRARY_SIZE]; const char *bytes; @@ -206,6 +210,13 @@ TclpInitLibraryPath( Tcl_ListObjAppendElement(NULL, pathPtr, TclGetProcessGlobalValue(&defaultLibraryDir)); + /* + * Look for the library in its source checkout location. + */ + + Tcl_ListObjAppendElement(NULL, pathPtr, + TclGetProcessGlobalValue(&sourceLibraryDir)); + *encodingPtr = NULL; bytes = Tcl_GetStringFromObj(pathPtr, lengthPtr); *valuePtr = ckalloc((*lengthPtr) + 1); @@ -360,6 +371,57 @@ InitializeDefaultLibraryDir( /* *--------------------------------------------------------------------------- * + * InitializeSourceLibraryDir -- + * + * Locate the Tcl script library default location relative to the + * location of the Tcl DLL as it exists in the build output directory + * associated with the source checkout. + * + * Results: + * None. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +static void +InitializeSourceLibraryDir( + char **valuePtr, + int *lengthPtr, + Tcl_Encoding *encodingPtr) +{ + HMODULE hModule = TclWinGetTclInstance(); + WCHAR wName[MAX_PATH + LIBRARY_SIZE]; + char name[(MAX_PATH + LIBRARY_SIZE) * TCL_UTF_MAX]; + char *end, *p; + + if (GetModuleFileNameW(hModule, wName, MAX_PATH) == 0) { + GetModuleFileNameA(hModule, name, MAX_PATH); + } else { + ToUtf(wName, name); + } + + end = strrchr(name, '\\'); + *end = '\0'; + p = strrchr(name, '\\'); + if (p != NULL) { + end = p; + } + *end = '\\'; + + TclWinNoBackslash(name); + sprintf(end + 1, "../library"); + *lengthPtr = strlen(name); + *valuePtr = ckalloc(*lengthPtr + 1); + *encodingPtr = NULL; + memcpy(*valuePtr, name, (size_t) *lengthPtr + 1); +} + +/* + *--------------------------------------------------------------------------- + * * ToUtf -- * * Convert a char string to a UTF string. diff --git a/win/tclWinLoad.c b/win/tclWinLoad.c index b59ccba..3e11224 100644 --- a/win/tclWinLoad.c +++ b/win/tclWinLoad.c @@ -57,10 +57,11 @@ TclpDlopen( Tcl_LoadHandle *loadHandle, /* Filled with token for dynamically loaded * file which will be passed back to * (*unloadProcPtr)() to unload the file. */ - Tcl_FSUnloadFileProc **unloadProcPtr) + Tcl_FSUnloadFileProc **unloadProcPtr, /* Filled with address of Tcl_FSUnloadFileProc * function which should be used for this * file. */ + int flags) { HINSTANCE hInstance; const TCHAR *nativeName; @@ -91,9 +92,8 @@ TclpDlopen( if (hInstance == NULL) { DWORD lastError = GetLastError(); - - Tcl_AppendResult(interp, "couldn't load library \"", - Tcl_GetString(pathPtr), "\": ", NULL); + Tcl_Obj *errMsg = Tcl_ObjPrintf("couldn't load library \"%s\": ", + Tcl_GetString(pathPtr)); /* * Check for possible DLL errors. This doesn't work quite right, @@ -109,29 +109,30 @@ TclpDlopen( case ERROR_DLL_NOT_FOUND: Tcl_SetErrorCode(interp, "WIN_LOAD", "DLL_NOT_FOUND", NULL); notFoundMsg: - Tcl_AppendResult(interp, "this library or a dependent library" - " could not be found in library path", NULL); + Tcl_AppendToObj(errMsg, "this library or a dependent library" + " could not be found in library path", -1); break; case ERROR_PROC_NOT_FOUND: Tcl_SetErrorCode(interp, "WIN_LOAD", "PROC_NOT_FOUND", NULL); - Tcl_AppendResult(interp, "A function specified in the import" - " table could not be resolved by the system. Windows" - " is not telling which one, I'm sorry.", NULL); + Tcl_AppendToObj(errMsg, "A function specified in the import" + " table could not be resolved by the system. Windows" + " is not telling which one, I'm sorry.", -1); break; case ERROR_INVALID_DLL: Tcl_SetErrorCode(interp, "WIN_LOAD", "INVALID_DLL", NULL); - Tcl_AppendResult(interp, "this library or a dependent library" - " is damaged", NULL); + Tcl_AppendToObj(errMsg, "this library or a dependent library" + " is damaged", -1); break; case ERROR_DLL_INIT_FAILED: Tcl_SetErrorCode(interp, "WIN_LOAD", "DLL_INIT_FAILED", NULL); - Tcl_AppendResult(interp, "the library initialization" - " routine failed", NULL); + Tcl_AppendToObj(errMsg, "the library initialization" + " routine failed", -1); break; default: TclWinConvertError(lastError); - Tcl_AppendResult(interp, Tcl_PosixError(interp), NULL); + Tcl_AppendToObj(errMsg, Tcl_PosixError(interp), -1); } + Tcl_SetObjResult(interp, errMsg); return TCL_ERROR; } @@ -190,7 +191,8 @@ FindSymbol( Tcl_DStringFree(&ds); } if (proc == NULL && interp != NULL) { - Tcl_AppendResult(interp, "cannot find symbol \"", symbol, "\"", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "cannot find symbol \"%s\"", symbol)); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "LOAD_SYMBOL", symbol, NULL); } return proc; @@ -286,8 +288,9 @@ TclpTempFileNameForLibrary( Tcl_MutexLock(&dllDirectoryNameMutex); if (dllDirectoryName == NULL) { if (InitDLLDirectoryName() == TCL_ERROR) { - Tcl_AppendResult(interp, "couldn't create temporary directory: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't create temporary directory: %s", + Tcl_PosixError(interp))); Tcl_MutexUnlock(&dllDirectoryNameMutex); return NULL; } diff --git a/win/tclWinPipe.c b/win/tclWinPipe.c index cc696a2..36ae58a 100644 --- a/win/tclWinPipe.c +++ b/win/tclWinPipe.c @@ -1030,8 +1030,9 @@ TclpCreateProcess( } if (startInfo.hStdInput == INVALID_HANDLE_VALUE) { TclWinConvertError(GetLastError()); - Tcl_AppendResult(interp, "couldn't duplicate input handle: ", - Tcl_PosixError(interp), (char *) NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't duplicate input handle: %s", + Tcl_PosixError(interp))); goto end; } @@ -1065,8 +1066,9 @@ TclpCreateProcess( } if (startInfo.hStdOutput == INVALID_HANDLE_VALUE) { TclWinConvertError(GetLastError()); - Tcl_AppendResult(interp, "couldn't duplicate output handle: ", - Tcl_PosixError(interp), (char *) NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't duplicate output handle: %s", + Tcl_PosixError(interp))); goto end; } @@ -1084,8 +1086,9 @@ TclpCreateProcess( } if (startInfo.hStdError == INVALID_HANDLE_VALUE) { TclWinConvertError(GetLastError()); - Tcl_AppendResult(interp, "couldn't duplicate error handle: ", - Tcl_PosixError(interp), (char *) NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't duplicate error handle: %s", + Tcl_PosixError(interp))); goto end; } @@ -1129,9 +1132,9 @@ TclpCreateProcess( } if (applType == APPL_DOS) { - Tcl_AppendResult(interp, + Tcl_SetObjResult(interp, Tcl_NewStringObj( "DOS application process not supported on this platform", - (char *) NULL); + -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", "DOS_APP", NULL); goto end; @@ -1158,12 +1161,12 @@ TclpCreateProcess( BuildCommandLine(execPath, argc, argv, &cmdLine); - if (CreateProcess(NULL, - (TCHAR *) Tcl_DStringValue(&cmdLine), NULL, NULL, TRUE, - (DWORD) createFlags, NULL, NULL, &startInfo, &procInfo) == 0) { + if (CreateProcess(NULL, (TCHAR *) Tcl_DStringValue(&cmdLine), + NULL, NULL, TRUE, (DWORD) createFlags, NULL, NULL, &startInfo, + &procInfo) == 0) { TclWinConvertError(GetLastError()); - Tcl_AppendResult(interp, "couldn't execute \"", argv[0], - "\": ", Tcl_PosixError(interp), (char *) NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf("couldn't execute \"%s\": %s", + argv[0], Tcl_PosixError(interp))); goto end; } @@ -1409,8 +1412,8 @@ ApplicationType( if (applType == APPL_NONE) { TclWinConvertError(GetLastError()); - Tcl_AppendResult(interp, "couldn't execute \"", originalName, - "\": ", Tcl_PosixError(interp), (char *) NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf("couldn't execute \"%s\": %s", + originalName, Tcl_PosixError(interp))); return APPL_NONE; } @@ -1673,8 +1676,8 @@ Tcl_CreatePipe( if (!CreatePipe(&readHandle, &writeHandle, &sec, 0)) { TclWinConvertError(GetLastError()); - Tcl_AppendResult(interp, "pipe creation failed: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "pipe creation failed: %s", Tcl_PosixError(interp))); return TCL_ERROR; } @@ -1711,8 +1714,8 @@ TclGetAndDetachPids( { PipeInfo *pipePtr; const Tcl_ChannelType *chanTypePtr; + Tcl_Obj *pidsObj; int i; - char buf[TCL_INTEGER_SPACE]; /* * Punt if the channel is not a command channel. @@ -1723,12 +1726,15 @@ TclGetAndDetachPids( return; } - pipePtr = (PipeInfo *) Tcl_GetChannelInstanceData(chan); + pipePtr = Tcl_GetChannelInstanceData(chan); + TclNewObj(pidsObj); for (i = 0; i < pipePtr->numPids; i++) { - wsprintfA(buf, "%lu", TclpGetPid(pipePtr->pidPtr[i])); - Tcl_AppendElement(interp, buf); - Tcl_DetachPids(1, &(pipePtr->pidPtr[i])); + Tcl_ListObjAppendElement(NULL, pidsObj, + Tcl_NewWideIntObj((unsigned) + TclpGetPid(pipePtr->pidPtr[i]))); + Tcl_DetachPids(1, &pipePtr->pidPtr[i]); } + Tcl_SetObjResult(interp, pidsObj); if (pipePtr->numPids > 0) { ckfree(pipePtr->pidPtr); pipePtr->numPids = 0; @@ -1875,12 +1881,26 @@ PipeClose2Proc( && (pipePtr->writeFile != NULL)) { if (pipePtr->writeThread) { /* - * Wait for the writer thread to finish the current buffer, then - * terminate the thread and close the handles. If the channel is - * nonblocking, there should be no pending write operations. + * Wait for the writer thread to finish the current buffer, then + * terminate the thread and close the handles. If the channel is + * nonblocking but blocked during exit, bail out since the worker + * thread is not interruptible and we want TIP#398-fast-exit. */ + if (TclInExit() + && (pipePtr->flags & PIPE_ASYNC)) { - WaitForSingleObject(pipePtr->writable, INFINITE); + /* give it a chance to leave honorably */ + SetEvent(pipePtr->stopWriter); + + if (WaitForSingleObject(pipePtr->writable, 0) == WAIT_TIMEOUT) { + return EAGAIN; + } + + } else { + + WaitForSingleObject(pipePtr->writable, INFINITE); + + } /* * The thread may already have closed on it's own. Check its exit @@ -2628,15 +2648,13 @@ Tcl_PidObjCmd( PipeInfo *pipePtr; int i; Tcl_Obj *resultPtr; - char buf[TCL_INTEGER_SPACE]; if (objc > 2) { Tcl_WrongNumArgs(interp, 1, objv, "?channelId?"); return TCL_ERROR; } if (objc == 1) { - wsprintfA(buf, "%lu", (unsigned long) getpid()); - Tcl_SetObjResult(interp, Tcl_NewStringObj(buf, -1)); + Tcl_SetObjResult(interp, Tcl_NewWideIntObj((unsigned) getpid())); } else { chan = Tcl_GetChannel(interp, Tcl_GetStringFromObj(objv[1], NULL), NULL); @@ -2651,9 +2669,9 @@ Tcl_PidObjCmd( pipePtr = (PipeInfo *) Tcl_GetChannelInstanceData(chan); resultPtr = Tcl_NewObj(); for (i = 0; i < pipePtr->numPids; i++) { - wsprintfA(buf, "%lu", TclpGetPid(pipePtr->pidPtr[i])); Tcl_ListObjAppendElement(/*interp*/ NULL, resultPtr, - Tcl_NewStringObj(buf, -1)); + Tcl_NewWideIntObj((unsigned) + TclpGetPid(pipePtr->pidPtr[i]))); } Tcl_SetObjResult(interp, resultPtr); } @@ -2945,6 +2963,10 @@ PipeWriterThread( * an error, so exit. */ + if (waitResult == WAIT_OBJECT_0) { + SetEvent(infoPtr->writable); + } + break; } diff --git a/win/tclWinPort.h b/win/tclWinPort.h index c262671..48f7894 100644 --- a/win/tclWinPort.h +++ b/win/tclWinPort.h @@ -14,8 +14,8 @@ #ifndef _TCLWINPORT #define _TCLWINPORT -#ifndef _WIN64 -/* See [Bug 2935503]: file mtime sets wrong time */ +#if !defined(_WIN64) && defined(BUILD_tcl) +/* See [Bug 3354324]: file mtime sets wrong time */ # define _USE_32BIT_TIME_T #endif @@ -538,7 +538,6 @@ typedef DWORD_PTR * PDWORD_PTR; #define getservbyname TclWinGetServByName #define getsockopt TclWinGetSockOpt -#define ntohs TclWinNToHS #define setsockopt TclWinSetSockOpt /* This type is not defined in the Windows headers */ #define socklen_t int diff --git a/win/tclWinReg.c b/win/tclWinReg.c index d2f233e..6ac5caf 100644 --- a/win/tclWinReg.c +++ b/win/tclWinReg.c @@ -13,9 +13,9 @@ */ #undef STATIC_BUILD -#ifndef USE_TCL_STUBS -# define USE_TCL_STUBS -#endif +#undef USE_TCL_STUBS +#define USE_TCL_STUBS + #include "tclInt.h" #ifdef _MSC_VER # pragma comment (lib, "advapi32.lib") @@ -24,20 +24,20 @@ #ifndef UNICODE # undef Tcl_WinTCharToUtf -# define Tcl_WinTCharToUtf(a,b,c) Tcl_ExternalToUtfDString(NULL,a,b,c) +# define Tcl_WinTCharToUtf(a,b,c) Tcl_ExternalToUtfDString(NULL,a,b,c) # undef Tcl_WinUtfToTChar -# define Tcl_WinUtfToTChar(a,b,c) Tcl_UtfToExternalDString(NULL,a,b,c) -#endif +# define Tcl_WinUtfToTChar(a,b,c) Tcl_UtfToExternalDString(NULL,a,b,c) +#endif /* !UNICODE */ /* * Ensure that we can say which registry is being accessed. */ #ifndef KEY_WOW64_64KEY -#define KEY_WOW64_64KEY (0x0100) +# define KEY_WOW64_64KEY (0x0100) #endif #ifndef KEY_WOW64_32KEY -#define KEY_WOW64_32KEY (0x0200) +# define KEY_WOW64_32KEY (0x0200) #endif /* @@ -45,7 +45,7 @@ */ #ifndef MAX_KEY_LENGTH -#define MAX_KEY_LENGTH 256 +# define MAX_KEY_LENGTH 256 #endif /* @@ -58,14 +58,6 @@ #define TCL_STORAGE_CLASS DLLEXPORT /* - * The maximum length of a sub-key name. - */ - -#ifndef MAX_KEY_LENGTH -#define MAX_KEY_LENGTH 256 -#endif - -/* * The following macros convert between different endian ints. */ @@ -173,7 +165,7 @@ Registry_Init( { Tcl_Command cmd; - if (Tcl_InitStubs(interp, "8.1", 0) == NULL) { + if (Tcl_InitStubs(interp, "8.5", 0) == NULL) { return TCL_ERROR; } @@ -535,9 +527,9 @@ DeleteValue( result = RegDeleteValue(key, (const TCHAR *)Tcl_DStringValue(&ds)); Tcl_DStringFree(&ds); if (result != ERROR_SUCCESS) { - Tcl_AppendResult(interp, "unable to delete value \"", - Tcl_GetString(valueNameObj), "\" from key \"", - Tcl_GetString(keyNameObj), "\": ", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unable to delete value \"%s\" from key \"%s\": ", + Tcl_GetString(valueNameObj), Tcl_GetString(keyNameObj))); AppendSystemError(interp, result); result = TCL_ERROR; } else { @@ -575,7 +567,8 @@ GetKeyNames( { const char *pattern; /* Pattern being matched against subkeys */ HKEY key; /* Handle to the key being examined */ - TCHAR buffer[MAX_KEY_LENGTH]; /* Buffer to hold the subkey name */ + TCHAR buffer[MAX_KEY_LENGTH]; + /* Buffer to hold the subkey name */ DWORD bufSize; /* Size of the buffer */ DWORD index; /* Position of the current subkey */ char *name; /* Subkey name */ @@ -611,9 +604,9 @@ GetKeyNames( if (result == ERROR_NO_MORE_ITEMS) { result = TCL_OK; } else { - Tcl_SetObjResult(interp, Tcl_NewObj()); - Tcl_AppendResult(interp, "unable to enumerate subkeys of \"", - Tcl_GetString(keyNameObj), "\": ", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unable to enumerate subkeys of \"%s\": ", + Tcl_GetString(keyNameObj))); AppendSystemError(interp, result); result = TCL_ERROR; } @@ -694,9 +687,9 @@ GetType( RegCloseKey(key); if (result != ERROR_SUCCESS) { - Tcl_AppendResult(interp, "unable to get type of value \"", - Tcl_GetString(valueNameObj), "\" from key \"", - Tcl_GetString(keyNameObj), "\": ", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unable to get type of value \"%s\" from key \"%s\": ", + Tcl_GetString(valueNameObj), Tcl_GetString(keyNameObj))); AppendSystemError(interp, result); return TCL_ERROR; } @@ -788,9 +781,9 @@ GetValue( Tcl_DStringFree(&buf); RegCloseKey(key); if (result != ERROR_SUCCESS) { - Tcl_AppendResult(interp, "unable to get value \"", - Tcl_GetString(valueNameObj), "\" from key \"", - Tcl_GetString(keyNameObj), "\": ", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "unable to get value \"%s\" from key \"%s\": ", + Tcl_GetString(valueNameObj), Tcl_GetString(keyNameObj))); AppendSystemError(interp, result); Tcl_DStringFree(&data); return TCL_ERROR; @@ -817,16 +810,16 @@ GetValue( * we get bogus data. */ - while ((p < end) - && (*((Tcl_UniChar *) p)) != 0) { + while ((p < end) && *((Tcl_UniChar *) p) != 0) { Tcl_UniChar *up; + Tcl_WinTCharToUtf((TCHAR *) p, -1, &buf); Tcl_ListObjAppendElement(interp, resultPtr, Tcl_NewStringObj(Tcl_DStringValue(&buf), Tcl_DStringLength(&buf))); up = (Tcl_UniChar *) p; - while (*up++ != 0) {} + while (*up++ != 0) {/* empty body */} p = (char *) up; Tcl_DStringFree(&buf); } @@ -1111,8 +1104,8 @@ ParseKeyName( rootName = name; } if (!rootName) { - Tcl_AppendResult(interp, "bad key \"", name, - "\": must start with a valid root", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad key \"%s\": must start with a valid root", name)); Tcl_SetErrorCode(interp, "WIN_REG", "NO_ROOT_KEY", NULL); return TCL_ERROR; } @@ -1226,8 +1219,8 @@ RecursiveDeleteKey( } break; } else if (result == ERROR_SUCCESS) { - result = RecursiveDeleteKey(hKey, (const TCHAR *) Tcl_DStringValue(&subkey), - mode); + result = RecursiveDeleteKey(hKey, + (const TCHAR *) Tcl_DStringValue(&subkey), mode); } } Tcl_DStringFree(&subkey); @@ -1294,8 +1287,8 @@ SetValue( return TCL_ERROR; } - value = ConvertDWORD((DWORD)type, (DWORD)value); - result = RegSetValueEx(key, (TCHAR *)valueName, 0, + value = ConvertDWORD((DWORD) type, (DWORD) value); + result = RegSetValueEx(key, (TCHAR *) valueName, 0, (DWORD) type, (BYTE *) &value, sizeof(DWORD)); } else if (type == REG_MULTI_SZ) { Tcl_DString data, buf; @@ -1329,7 +1322,7 @@ SetValue( Tcl_WinUtfToTChar(Tcl_DStringValue(&data), Tcl_DStringLength(&data)+1, &buf); - result = RegSetValueEx(key, (TCHAR *)valueName, 0, + result = RegSetValueEx(key, (TCHAR *) valueName, 0, (DWORD) type, (BYTE *) Tcl_DStringValue(&buf), (DWORD) Tcl_DStringLength(&buf)); Tcl_DStringFree(&data); @@ -1338,7 +1331,7 @@ SetValue( Tcl_DString buf; const char *data = Tcl_GetStringFromObj(dataObj, &length); - data = (char *)Tcl_WinUtfToTChar(data, length, &buf); + data = (char *) Tcl_WinUtfToTChar(data, length, &buf); /* * Include the null in the length, padding if needed for Unicode. @@ -1347,7 +1340,7 @@ SetValue( Tcl_DStringSetLength(&buf, Tcl_DStringLength(&buf)+1); length = Tcl_DStringLength(&buf) + 1; - result = RegSetValueEx(key, (TCHAR *)valueName, 0, + result = RegSetValueEx(key, (TCHAR *) valueName, 0, (DWORD) type, (BYTE *) data, (DWORD) length); Tcl_DStringFree(&buf); } else { @@ -1358,7 +1351,7 @@ SetValue( */ data = (BYTE *) Tcl_GetByteArrayFromObj(dataObj, &length); - result = RegSetValueEx(key, (TCHAR *)valueName, 0, + result = RegSetValueEx(key, (TCHAR *) valueName, 0, (DWORD) type, data, (DWORD) length); } @@ -1529,14 +1522,15 @@ ConvertDWORD( DWORD type, /* Either REG_DWORD or REG_DWORD_BIG_ENDIAN */ DWORD value) /* The value to be converted. */ { - DWORD order = 1; + const DWORD order = 1; DWORD localType; /* * Check to see if the low bit is in the first byte. */ - localType = (*((char *) &order) == 1) ? REG_DWORD : REG_DWORD_BIG_ENDIAN; + localType = (*((const char *) &order) == 1) + ? REG_DWORD : REG_DWORD_BIG_ENDIAN; return (type != localType) ? (DWORD) SWAPLONG(value) : value; } diff --git a/win/tclWinSerial.c b/win/tclWinSerial.c index 58a9eb4..458b05b 100644 --- a/win/tclWinSerial.c +++ b/win/tclWinSerial.c @@ -376,7 +376,7 @@ SerialGetMilliseconds(void) { Tcl_Time time; - TclpGetTime(&time); + Tcl_GetTime(&time); return (time.sec * 1000 + time.usec / 1000); } @@ -1673,12 +1673,7 @@ SerialSetOptionProc( if ((len > 2) && (strncmp(optionName, "-mode", len) == 0)) { if (!GetCommState(infoPtr->handle, &dcb)) { - if (interp != NULL) { - TclWinConvertError(GetLastError()); - Tcl_AppendResult(interp, "can't get comm state: ", - Tcl_PosixError(interp), NULL); - } - return TCL_ERROR; + goto getStateFailed; } native = Tcl_WinUtfToTChar(value, -1, &ds); result = BuildCommDCB(native, &dcb); @@ -1686,8 +1681,9 @@ SerialSetOptionProc( if (result == FALSE) { if (interp != NULL) { - Tcl_AppendResult(interp, "bad value \"", value, - "\" for -mode: should be baud,parity,data,stop", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad value \"%s\" for -mode: should be baud,parity,data,stop", + value)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "SERIALMODE", NULL); } return TCL_ERROR; @@ -1703,12 +1699,7 @@ SerialSetOptionProc( dcb.fAbortOnError = FALSE; if (!SetCommState(infoPtr->handle, &dcb)) { - if (interp != NULL) { - TclWinConvertError(GetLastError()); - Tcl_AppendResult(interp, "can't set comm state: ", - Tcl_PosixError(interp), NULL); - } - return TCL_ERROR; + goto setStateFailed; } return TCL_OK; } @@ -1719,12 +1710,7 @@ SerialSetOptionProc( if ((len > 1) && (strncmp(optionName, "-handshake", len) == 0)) { if (!GetCommState(infoPtr->handle, &dcb)) { - if (interp != NULL) { - TclWinConvertError(GetLastError()); - Tcl_AppendResult(interp, "can't get comm state: ", - Tcl_PosixError(interp), NULL); - } - return TCL_ERROR; + goto getStateFailed; } /* @@ -1759,21 +1745,16 @@ SerialSetOptionProc( dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; } else { if (interp != NULL) { - Tcl_AppendResult(interp, "bad value \"", value, - "\" for -handshake: must be one of xonxoff, rtscts, " - "dtrdsr or none", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad value \"%s\" for -handshake: must be one of" + " xonxoff, rtscts, dtrdsr or none", value)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "HANDSHAKE", NULL); } return TCL_ERROR; } if (!SetCommState(infoPtr->handle, &dcb)) { - if (interp != NULL) { - TclWinConvertError(GetLastError()); - Tcl_AppendResult(interp, "can't set comm state: ", - Tcl_PosixError(interp), NULL); - } - return TCL_ERROR; + goto setStateFailed; } return TCL_OK; } @@ -1784,12 +1765,7 @@ SerialSetOptionProc( if ((len > 1) && (strncmp(optionName, "-xchar", len) == 0)) { if (!GetCommState(infoPtr->handle, &dcb)) { - if (interp != NULL) { - TclWinConvertError(GetLastError()); - Tcl_AppendResult(interp, "can't get comm state: ", - Tcl_PosixError(interp), NULL); - } - return TCL_ERROR; + goto getStateFailed; } if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) { @@ -1798,9 +1774,9 @@ SerialSetOptionProc( if (argc != 2) { badXchar: if (interp != NULL) { - Tcl_AppendResult(interp, "bad value for -xchar: should be " - "a list of two elements with each a single character", - NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "bad value for -xchar: should be a list of" + " two elements with each a single character", -1)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "XCHAR", NULL); } ckfree(argv); @@ -1837,12 +1813,7 @@ SerialSetOptionProc( ckfree(argv); if (!SetCommState(infoPtr->handle, &dcb)) { - if (interp != NULL) { - TclWinConvertError(GetLastError()); - Tcl_AppendResult(interp, "can't set comm state: ", - Tcl_PosixError(interp), NULL); - } - return TCL_ERROR; + goto setStateFailed; } return TCL_OK; } @@ -1859,9 +1830,9 @@ SerialSetOptionProc( } if ((argc % 2) == 1) { if (interp != NULL) { - Tcl_AppendResult(interp, "bad value \"", value, - "\" for -ttycontrol: should be a list of " - "signal,value pairs", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad value \"%s\" for -ttycontrol: should be " + "a list of signal,value pairs", value)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "TTYCONTROL", NULL); } ckfree(argv); @@ -1877,7 +1848,8 @@ SerialSetOptionProc( if (!EscapeCommFunction(infoPtr->handle, (DWORD) (flag ? SETDTR : CLRDTR))) { if (interp != NULL) { - Tcl_AppendResult(interp, "can't set DTR signal", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "can't set DTR signal", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FCONFIGURE", "TTY_SIGNAL", NULL); } @@ -1888,7 +1860,8 @@ SerialSetOptionProc( if (!EscapeCommFunction(infoPtr->handle, (DWORD) (flag ? SETRTS : CLRRTS))) { if (interp != NULL) { - Tcl_AppendResult(interp, "can't set RTS signal", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "can't set RTS signal", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FCONFIGURE", "TTY_SIGNAL", NULL); } @@ -1899,7 +1872,8 @@ SerialSetOptionProc( if (!EscapeCommFunction(infoPtr->handle, (DWORD) (flag ? SETBREAK : CLRBREAK))) { if (interp != NULL) { - Tcl_AppendResult(interp,"can't set BREAK signal",NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "can't set BREAK signal", -1)); Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FCONFIGURE", "TTY_SIGNAL", NULL); } @@ -1908,9 +1882,9 @@ SerialSetOptionProc( } } else { if (interp != NULL) { - Tcl_AppendResult(interp, "bad signal name \"", argv[i], - "\" for -ttycontrol: must be DTR, RTS or BREAK", - NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad signal name \"%s\" for -ttycontrol: must be" + " DTR, RTS or BREAK", argv[i])); Tcl_SetErrorCode(interp, "TCL", "VALUE", "TTY_SIGNAL", NULL); } @@ -1949,9 +1923,9 @@ SerialSetOptionProc( if ((argc < 1) || (argc > 2) || (inSize <= 0) || (outSize <= 0)) { if (interp != NULL) { - Tcl_AppendResult(interp, "bad value \"", value, - "\" for -sysbuffer: should be a list of one or two " - "integers > 0", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad value \"%s\" for -sysbuffer: should be " + "a list of one or two integers > 0", value)); Tcl_SetErrorCode(interp, "TCL", "VALUE", "SYS_BUFFER", NULL); } return TCL_ERROR; @@ -1960,8 +1934,9 @@ SerialSetOptionProc( if (!SetupComm(infoPtr->handle, inSize, outSize)) { if (interp != NULL) { TclWinConvertError(GetLastError()); - Tcl_AppendResult(interp, "can't setup comm buffers: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't setup comm buffers: %s", + Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -1974,22 +1949,12 @@ SerialSetOptionProc( */ if (!GetCommState(infoPtr->handle, &dcb)) { - if (interp != NULL) { - TclWinConvertError(GetLastError()); - Tcl_AppendResult(interp, "can't get comm state: ", - Tcl_PosixError(interp), NULL); - } - return TCL_ERROR; + goto getStateFailed; } dcb.XonLim = (WORD) (infoPtr->sysBufRead*1/2); dcb.XoffLim = (WORD) (infoPtr->sysBufRead*1/4); if (!SetCommState(infoPtr->handle, &dcb)) { - if (interp != NULL) { - TclWinConvertError(GetLastError()); - Tcl_AppendResult(interp, "can't set comm state: ", - Tcl_PosixError(interp), NULL); - } - return TCL_ERROR; + goto setStateFailed; } return TCL_OK; } @@ -2020,8 +1985,9 @@ SerialSetOptionProc( if (!SetCommTimeouts(infoPtr->handle, &tout)) { if (interp != NULL) { TclWinConvertError(GetLastError()); - Tcl_AppendResult(interp, "can't set comm timeouts: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't set comm timeouts: %s", + Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -2031,6 +1997,22 @@ SerialSetOptionProc( return Tcl_BadChannelOption(interp, optionName, "mode handshake pollinterval sysbuffer timeout ttycontrol xchar"); + + getStateFailed: + if (interp != NULL) { + TclWinConvertError(GetLastError()); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't get comm state: %s", Tcl_PosixError(interp))); + } + return TCL_ERROR; + + setStateFailed: + if (interp != NULL) { + TclWinConvertError(GetLastError()); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't set comm state: %s", Tcl_PosixError(interp))); + } + return TCL_ERROR; } /* @@ -2089,8 +2071,8 @@ SerialGetOptionProc( if (!GetCommState(infoPtr->handle, &dcb)) { if (interp != NULL) { TclWinConvertError(GetLastError()); - Tcl_AppendResult(interp, "can't get comm state: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't get comm state: %s", Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -2159,8 +2141,8 @@ SerialGetOptionProc( if (!GetCommState(infoPtr->handle, &dcb)) { if (interp != NULL) { TclWinConvertError(GetLastError()); - Tcl_AppendResult(interp, "can't get comm state: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't get comm state: %s", Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -2237,8 +2219,8 @@ SerialGetOptionProc( if (!GetCommModemStatus(infoPtr->handle, &status)) { if (interp != NULL) { TclWinConvertError(GetLastError()); - Tcl_AppendResult(interp, "can't get tty status: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't get tty status: %s", Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -2248,10 +2230,9 @@ SerialGetOptionProc( if (valid) { return TCL_OK; - } else { - return Tcl_BadChannelOption(interp, optionName, - "mode pollinterval lasterror queue sysbuffer ttystatus xchar"); } + return Tcl_BadChannelOption(interp, optionName, + "mode pollinterval lasterror queue sysbuffer ttystatus xchar"); } /* diff --git a/win/tclWinSock.c b/win/tclWinSock.c index 97b10a3..1a74354 100644 --- a/win/tclWinSock.c +++ b/win/tclWinSock.c @@ -72,7 +72,6 @@ #undef getservbyname #undef getsockopt -#undef ntohs #undef setsockopt /* @@ -163,7 +162,7 @@ struct SocketInfo { * socket event occurs. */ -typedef struct SocketEvent { +typedef struct { Tcl_Event header; /* Information that is standard for all * events. */ SOCKET socket; /* Socket descriptor that is ready. Used to @@ -191,7 +190,7 @@ typedef struct SocketEvent { #define SOCKET_PENDING (1<<3) /* A message has been sent for this * socket */ -typedef struct ThreadSpecificData { +typedef struct { HWND hwnd; /* Handle to window for socket messages. */ HANDLE socketThread; /* Thread handling the window */ Tcl_ThreadId threadId; /* Parent thread. */ @@ -220,7 +219,7 @@ static void SocketExitHandler(ClientData clientData); static LRESULT CALLBACK SocketProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); static int SocketsEnabled(void); -static void TcpAccept(TcpFdList *fds); +static void TcpAccept(TcpFdList *fds, SOCKET newSocket, address addr); static int WaitForSocketEvent(SocketInfo *infoPtr, int events, int *errorCodePtr); static DWORD WINAPI SocketThread(LPVOID arg); @@ -558,8 +557,8 @@ TclpHasSockets( return TCL_OK; } if (interp != NULL) { - Tcl_AppendResult(interp, "sockets are not available on this system", - NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "sockets are not available on this system", -1)); } return TCL_ERROR; } @@ -692,6 +691,9 @@ SocketEventProc( int mask = 0, events; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); TcpFdList *fds; + SOCKET newSocket; + address addr; + int len; if (!(flags & TCL_FILE_EVENTS)) { return 0; @@ -708,13 +710,13 @@ SocketEventProc( break; } } - SetEvent(tsdPtr->socketListLock); /* * Discard events that have gone stale. */ if (!infoPtr) { + SetEvent(tsdPtr->socketListLock); return 1; } @@ -726,11 +728,65 @@ SocketEventProc( if (infoPtr->readyEvents & FD_ACCEPT) { for (fds = infoPtr->sockets; fds != NULL; fds = fds->next) { - TcpAccept(fds); + + /* + * Accept the incoming connection request. + */ + len = sizeof(address); + + newSocket = accept(fds->fd, &(addr.sa), &len); + + /* On Tcl server sockets with multiple OS fds we loop over the fds trying + * an accept() on each, so we expect INVALID_SOCKET. There are also other + * network stack conditions that can result in FD_ACCEPT but a subsequent + * failure on accept() by the time we get around to it. + * Access to sockets (acceptEventCount, readyEvents) in socketList + * is still protected by the lock (prevents reintroduction of + * SF Tcl Bug 3056775. + */ + + if (newSocket == INVALID_SOCKET) { + /* int err = WSAGetLastError(); */ + continue; + } + + /* + * It is possible that more than one FD_ACCEPT has been sent, so an extra + * count must be kept. Decrement the count, and reset the readyEvent bit + * if the count is no longer > 0. + */ + infoPtr->acceptEventCount--; + + if (infoPtr->acceptEventCount <= 0) { + infoPtr->readyEvents &= ~(FD_ACCEPT); + } + + SetEvent(tsdPtr->socketListLock); + + /* Caution: TcpAccept() has the side-effect of evaluating the server + * accept script (via AcceptCallbackProc() in tclIOCmd.c), which can + * close the server socket and invalidate infoPtr and fds. + * If TcpAccept() accepts a socket we must return immediately and let + * SocketCheckProc queue additional FD_ACCEPT events. + */ + TcpAccept(fds, newSocket, addr); + return 1; } + + /* Loop terminated with no sockets accepted; clear the ready mask so + * we can detect the next connection request. Note that connection + * requests are level triggered, so if there is a request already + * pending, a new event will be generated. + */ + infoPtr->acceptEventCount = 0; + infoPtr->readyEvents &= ~(FD_ACCEPT); + + SetEvent(tsdPtr->socketListLock); return 1; } + SetEvent(tsdPtr->socketListLock); + /* * Mask off unwanted events and compute the read/write mask so we can * notify the channel. @@ -872,9 +928,15 @@ TcpCloseProc( * background. */ - if (closesocket(infoPtr->sockets->fd) == SOCKET_ERROR) { - TclWinConvertError((DWORD) WSAGetLastError()); - errorCode = Tcl_GetErrno(); + while ( infoPtr->sockets != NULL ) { + TcpFdList *thisfd = infoPtr->sockets; + infoPtr->sockets = thisfd->next; + + if (closesocket(thisfd->fd) == SOCKET_ERROR) { + TclWinConvertError((DWORD) WSAGetLastError()); + errorCode = Tcl_GetErrno(); + } + ckfree(thisfd); } } @@ -928,12 +990,14 @@ TcpClose2Proc( break; default: if (interp) { - Tcl_AppendResult(interp, - "Socket close2proc called bidirectionally", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "Socket close2proc called bidirectionally", -1)); } return TCL_ERROR; } + /* single fd operation: Tcl_OpenTcpServer() does not set TCL_READABLE or + * TCL_WRITABLE so this should never be called for a server socket. */ if (shutdown(infoPtr->sockets->fd, sd) == SOCKET_ERROR) { TclWinConvertError((DWORD) WSAGetLastError()); errorCode = Tcl_GetErrno(); @@ -945,6 +1009,51 @@ TcpClose2Proc( /* *---------------------------------------------------------------------- * + * AddSocketInfoFd -- + * + * This function adds a SOCKET file descriptor to the 'sockets' linked + * list of a SocketInfo structure. + * + * Results: + * None. + * + * Side effects: + * None, except for allocation of memory. + * + *---------------------------------------------------------------------- + */ + +static void +AddSocketInfoFd( + SocketInfo *infoPtr, + SOCKET socket) +{ + TcpFdList *fds = infoPtr->sockets; + + if ( fds == NULL ) { + /* Add the first FD */ + infoPtr->sockets = ckalloc(sizeof(TcpFdList)); + fds = infoPtr->sockets; + } else { + /* Find end of list and append FD */ + while ( fds->next != NULL ) { + fds = fds->next; + } + + fds->next = ckalloc(sizeof(TcpFdList)); + fds = fds->next; + } + + /* Populate new FD */ + fds->fd = socket; + fds->infoPtr = infoPtr; + fds->next = NULL; +} + + +/* + *---------------------------------------------------------------------- + * * NewSocketInfo -- * * This function allocates and initializes a new SocketInfo structure. @@ -963,14 +1072,10 @@ NewSocketInfo( SOCKET socket) { SocketInfo *infoPtr = ckalloc(sizeof(SocketInfo)); - TcpFdList *fds = ckalloc(sizeof(TcpFdList)); - fds->fd = socket; - fds->next = NULL; - fds->infoPtr = infoPtr; /* ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); */ infoPtr->channel = 0; - infoPtr->sockets = fds; + infoPtr->sockets = NULL; infoPtr->flags = 0; infoPtr->watchEvents = 0; infoPtr->readyEvents = 0; @@ -988,6 +1093,8 @@ NewSocketInfo( infoPtr->nextPtr = NULL; + AddSocketInfoFd(infoPtr, socket); + return infoPtr; } @@ -1057,7 +1164,6 @@ CreateSocket( } if (server) { - TcpFdList *fds = NULL, *newfds; for (addrPtr = addrlist; addrPtr != NULL; addrPtr = addrPtr->ai_next) { sock = socket(addrPtr->ai_family, SOCK_STREAM, 0); @@ -1140,7 +1246,6 @@ CreateSocket( */ infoPtr = NewSocketInfo(sock); - fds = infoPtr->sockets; /* * Set up the select mask for connection request events. @@ -1150,13 +1255,7 @@ CreateSocket( infoPtr->watchEvents |= FD_ACCEPT; } else { - newfds = ckalloc(sizeof(TcpFdList)); - memset(newfds, (int) 0, sizeof(TcpFdList)); - newfds->fd = sock; - newfds->infoPtr = infoPtr; - newfds->next = NULL; - fds->next = newfds; - fds = newfds; + AddSocketInfoFd( infoPtr, sock ); } } } else { @@ -1280,12 +1379,9 @@ CreateSocket( } if (interp != NULL) { - Tcl_AppendResult(interp, "couldn't open socket: ", NULL); - if (errorMsg == NULL) { - Tcl_AppendResult(interp, Tcl_PosixError(interp), NULL); - } else { - Tcl_AppendResult(interp, errorMsg, NULL); - } + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't open socket: %s", + (errorMsg ? errorMsg : Tcl_PosixError(interp)))); } if (sock != INVALID_SOCKET) { @@ -1537,8 +1633,9 @@ Tcl_OpenTcpServer( * * TcpAccept -- * - * Accept a TCP socket connection. This is called by SocketEventProc and - * it in turns calls the registered accept function. + * Creates a channel for a newly accepted socket connection. This is + * called by SocketEventProc and it in turns calls the registered + * accept function. * * Results: * None. @@ -1551,60 +1648,18 @@ Tcl_OpenTcpServer( static void TcpAccept( - TcpFdList *fds) /* Socket to accept. */ + TcpFdList *fds, /* Server socket that accepted newSocket. */ + SOCKET newSocket, /* Newly accepted socket. */ + address addr) /* Address of new socket. */ { - SOCKET newSocket; SocketInfo *newInfoPtr; SocketInfo *infoPtr = fds->infoPtr; - SOCKADDR_IN addr; - int len; + int len = sizeof(addr); char channelName[16 + TCL_INTEGER_SPACE]; + char host[NI_MAXHOST], port[NI_MAXSERV]; ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey); /* - * Accept the incoming connection request. - */ - - len = sizeof(SOCKADDR_IN); - - newSocket = accept(fds->fd, (SOCKADDR *) &addr, &len); - - /* - * Protect access to sockets (acceptEventCount, readyEvents) in socketList - * by the lock. Fix for SF Tcl Bug 3056775. - */ - - WaitForSingleObject(tsdPtr->socketListLock, INFINITE); - - /* - * Clear the ready mask so we can detect the next connection request. Note - * that connection requests are level triggered, so if there is a request - * already pending, a new event will be generated. - */ - - if (newSocket == INVALID_SOCKET) { - infoPtr->acceptEventCount = 0; - infoPtr->readyEvents &= ~(FD_ACCEPT); - - SetEvent(tsdPtr->socketListLock); - return; - } - - /* - * It is possible that more than one FD_ACCEPT has been sent, so an extra - * count must be kept. Decrement the count, and reset the readyEvent bit - * if the count is no longer > 0. - */ - - infoPtr->acceptEventCount--; - - if (infoPtr->acceptEventCount <= 0) { - infoPtr->readyEvents &= ~(FD_ACCEPT); - } - - SetEvent(tsdPtr->socketListLock); - - /* * Win-NT has a misfeature that sockets are inherited in child processes * by default. Turn off the inherit bit. */ @@ -1644,8 +1699,10 @@ TcpAccept( */ if (infoPtr->acceptProc != NULL) { + getnameinfo(&(addr.sa), len, host, sizeof(host), port, sizeof(port), + NI_NUMERICHOST|NI_NUMERICSERV); infoPtr->acceptProc(infoPtr->acceptProcData, newInfoPtr->channel, - inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + host, atoi(port)); } } @@ -1720,6 +1777,7 @@ TcpInputProc( while (1) { SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) UNSELECT, (LPARAM) infoPtr); + /* single fd operation: this proc is only called for a connected socket. */ bytesRead = recv(infoPtr->sockets->fd, buf, toRead, 0); infoPtr->readyEvents &= ~(FD_READ); @@ -1840,6 +1898,7 @@ TcpOutputProc( SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) UNSELECT, (LPARAM) infoPtr); + /* single fd operation: this proc is only called for a connected socket. */ bytesWritten = send(infoPtr->sockets->fd, buf, toWrite, 0); if (bytesWritten != SOCKET_ERROR) { /* @@ -1929,12 +1988,14 @@ TcpSetOptionProc( if (!SocketsEnabled()) { if (interp) { - Tcl_AppendResult(interp, "winsock is not initialized", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "winsock is not initialized", -1)); } return TCL_ERROR; } #ifdef TCL_FEATURE_KEEPALIVE_NAGLE + #error "TCL_FEATURE_KEEPALIVE_NAGLE not reviewed for whether to treat infoPtr->sockets as single fd or list" sock = infoPtr->sockets->fd; if (!strcasecmp(optionName, "-keepalive")) { @@ -1952,8 +2013,9 @@ TcpSetOptionProc( if (rtn != 0) { TclWinConvertError(WSAGetLastError()); if (interp) { - Tcl_AppendResult(interp, "couldn't set socket option: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't set socket option: %s", + Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -1973,8 +2035,9 @@ TcpSetOptionProc( if (rtn != 0) { TclWinConvertError(WSAGetLastError()); if (interp) { - Tcl_AppendResult(interp, "couldn't set socket option: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't set socket option: %s", + Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -2032,7 +2095,8 @@ TcpGetOptionProc( if (!SocketsEnabled()) { if (interp) { - Tcl_AppendResult(interp, "winsock is not initialized", NULL); + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "winsock is not initialized", -1)); } return TCL_ERROR; } @@ -2099,8 +2163,9 @@ TcpGetOptionProc( if (len) { TclWinConvertError((DWORD) WSAGetLastError()); if (interp) { - Tcl_AppendResult(interp, "can't get peername: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't get peername: %s", + Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -2164,8 +2229,8 @@ TcpGetOptionProc( } else { if (interp) { TclWinConvertError((DWORD) WSAGetLastError()); - Tcl_AppendResult(interp, "can't get sockname: ", - Tcl_PosixError(interp), NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "can't get sockname: %s", Tcl_PosixError(interp))); } return TCL_ERROR; } @@ -2398,6 +2463,7 @@ SocketProc( int event, error; SOCKET socket; SocketInfo *infoPtr; + TcpFdList *fds = NULL; ThreadSpecificData *tsdPtr = (ThreadSpecificData *) #ifdef _WIN64 GetWindowLongPtr(hwnd, GWLP_USERDATA); @@ -2442,58 +2508,60 @@ SocketProc( WaitForSingleObject(tsdPtr->socketListLock, INFINITE); for (infoPtr = tsdPtr->socketList; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { - if (infoPtr->sockets->fd == socket) { - /* - * Update the socket state. - * - * A count of FD_ACCEPTS is stored, so if an FD_CLOSE event - * happens, then clear the FD_ACCEPT count. Otherwise, - * increment the count if the current event is an FD_ACCEPT. - */ - - if (event & FD_CLOSE) { - infoPtr->acceptEventCount = 0; - infoPtr->readyEvents &= ~(FD_WRITE|FD_ACCEPT); - } else if (event & FD_ACCEPT) { - infoPtr->acceptEventCount++; - } - - if (event & FD_CONNECT) { + for (fds = infoPtr->sockets; fds != NULL; fds = fds->next) { + if (fds->fd == socket) { /* - * The socket is now connected, clear the async connect - * flag. + * Update the socket state. + * + * A count of FD_ACCEPTS is stored, so if an FD_CLOSE event + * happens, then clear the FD_ACCEPT count. Otherwise, + * increment the count if the current event is an FD_ACCEPT. */ - infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT); + if (event & FD_CLOSE) { + infoPtr->acceptEventCount = 0; + infoPtr->readyEvents &= ~(FD_WRITE|FD_ACCEPT); + } else if (event & FD_ACCEPT) { + infoPtr->acceptEventCount++; + } + + if (event & FD_CONNECT) { + /* + * The socket is now connected, clear the async connect + * flag. + */ - /* - * Remember any error that occurred so we can report - * connection failures. - */ + infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT); + + /* + * Remember any error that occurred so we can report + * connection failures. + */ - if (error != ERROR_SUCCESS) { - TclWinConvertError((DWORD) error); - infoPtr->lastError = Tcl_GetErrno(); + if (error != ERROR_SUCCESS) { + TclWinConvertError((DWORD) error); + infoPtr->lastError = Tcl_GetErrno(); + } } - } - if (infoPtr->flags & SOCKET_ASYNC_CONNECT) { - infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT); - if (error != ERROR_SUCCESS) { - TclWinConvertError((DWORD) error); - infoPtr->lastError = Tcl_GetErrno(); + if (infoPtr->flags & SOCKET_ASYNC_CONNECT) { + infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT); + if (error != ERROR_SUCCESS) { + TclWinConvertError((DWORD) error); + infoPtr->lastError = Tcl_GetErrno(); + } + infoPtr->readyEvents |= FD_WRITE; } - infoPtr->readyEvents |= FD_WRITE; - } - infoPtr->readyEvents |= event; + infoPtr->readyEvents |= event; - /* - * Wake up the Main Thread. - */ + /* + * Wake up the Main Thread. + */ - SetEvent(tsdPtr->readyEvent); - Tcl_ThreadAlert(tsdPtr->threadId); - break; + SetEvent(tsdPtr->readyEvent); + Tcl_ThreadAlert(tsdPtr->threadId); + break; + } } } SetEvent(tsdPtr->socketListLock); @@ -2501,15 +2569,18 @@ SocketProc( case SOCKET_SELECT: infoPtr = (SocketInfo *) lParam; - if (wParam == SELECT) { - WSAAsyncSelect(infoPtr->sockets->fd, hwnd, - SOCKET_MESSAGE, infoPtr->selectEvents); - } else { - /* - * Clear the selection mask - */ + for (fds = infoPtr->sockets; fds != NULL; fds = fds->next) { + infoPtr = (SocketInfo *) lParam; + if (wParam == SELECT) { + WSAAsyncSelect(fds->fd, hwnd, + SOCKET_MESSAGE, infoPtr->selectEvents); + } else { + /* + * Clear the selection mask + */ - WSAAsyncSelect(infoPtr->sockets->fd, hwnd, 0, 0); + WSAAsyncSelect(fds->fd, hwnd, 0, 0); + } } break; @@ -2664,23 +2735,6 @@ TclWinSetSockOpt( return setsockopt(s, level, optname, optval, optlen); } -unsigned short -TclWinNToHS( - unsigned short netshort) -{ - /* - * Check that WinSock is initialized; do not call it if not, to prevent - * system crashes. This can happen at exit time if the exit handler for - * WinSock ran before other exit handlers that want to use sockets. - */ - - if (!SocketsEnabled()) { - return (unsigned short) -1; - } - - return ntohs(netshort); -} - char * TclpInetNtoa( struct in_addr addr) diff --git a/win/tclWinThrd.c b/win/tclWinThrd.c index 102fd40..7b0f6f8 100644 --- a/win/tclWinThrd.c +++ b/win/tclWinThrd.c @@ -13,8 +13,17 @@ #include "tclWinInt.h" +#include <float.h> #include <sys/stat.h> +/* Workaround for mingw versions which don't provide this in float.h */ +#ifndef _MCW_EM +# define _MCW_EM 0x0008001F /* Error masks */ +# define _MCW_RC 0x00000300 /* Rounding */ +# define _MCW_PC 0x00030000 /* Precision */ +_CRTIMP unsigned int __cdecl _controlfp (unsigned int unNew, unsigned int unMask); +#endif + /* * This is the master lock used to serialize access to other serialization * data structures. @@ -124,6 +133,66 @@ typedef struct allocMutex { #endif /* USE_THREAD_ALLOC */ /* + * The per thread data passed from TclpThreadCreate + * to TclWinThreadStart. + */ + +typedef struct WinThread { + LPTHREAD_START_ROUTINE lpStartAddress; /* Original startup routine */ + LPVOID lpParameter; /* Original startup data */ + unsigned int fpControl; /* Floating point control word from the + * main thread */ +} WinThread; + + +/* + *---------------------------------------------------------------------- + * + * TclWinThreadStart -- + * + * This procedure is the entry point for all new threads created + * by Tcl on Windows. + * + * Results: + * Various, depending on the result of the wrapped thread start + * routine. + * + * Side effects: + * Arbitrary, since user code is executed. + * + *---------------------------------------------------------------------- + */ + +static DWORD WINAPI +TclWinThreadStart( + LPVOID lpParameter) /* The WinThread structure pointer passed + * from TclpThreadCreate */ +{ + WinThread *winThreadPtr = (WinThread *) lpParameter; + unsigned int fpmask; + LPTHREAD_START_ROUTINE lpOrigStartAddress; + LPVOID lpOrigParameter; + + if (!winThreadPtr) { + return TCL_ERROR; + } + + fpmask = _MCW_EM | _MCW_RC | _MCW_PC; + +#if defined(_MSC_VER) && _MSC_VER >= 1200 + fpmask |= _MCW_DN; +#endif + + _controlfp(winThreadPtr->fpControl, fpmask); + + lpOrigStartAddress = winThreadPtr->lpStartAddress; + lpOrigParameter = winThreadPtr->lpParameter; + + ckfree((char *)winThreadPtr); + return lpOrigStartAddress(lpOrigParameter); +} + +/* *---------------------------------------------------------------------- * * TclpThreadCreate -- @@ -149,8 +218,14 @@ TclpThreadCreate( int flags) /* Flags controlling behaviour of the new * thread. */ { + WinThread *winThreadPtr; /* Per-thread startup info */ HANDLE tHandle; + winThreadPtr = (WinThread *)ckalloc(sizeof(WinThread)); + winThreadPtr->lpStartAddress = (LPTHREAD_START_ROUTINE) proc; + winThreadPtr->lpParameter = clientData; + winThreadPtr->fpControl = _controlfp(0, 0); + EnterCriticalSection(&joinLock); *idPtr = 0; /* must initialize as Tcl_Thread is a pointer and @@ -158,12 +233,12 @@ TclpThreadCreate( */ #if defined(_MSC_VER) || defined(__MSVCRT__) || defined(__BORLANDC__) - tHandle = (HANDLE) _beginthreadex(NULL, (unsigned) stackSize, proc, - clientData, 0, (unsigned *)idPtr); + tHandle = (HANDLE) _beginthreadex(NULL, (unsigned) stackSize, + (Tcl_ThreadCreateProc*) TclWinThreadStart, winThreadPtr, + 0, (unsigned *)idPtr); #else tHandle = CreateThread(NULL, (DWORD) stackSize, - (LPTHREAD_START_ROUTINE) proc, (LPVOID) clientData, - (DWORD) 0, (LPDWORD)idPtr); + TclWinThreadStart, winThreadPtr, 0, (LPDWORD)idPtr); #endif if (tHandle == NULL) { diff --git a/win/tclooConfig.sh b/win/tclooConfig.sh index 68de106..5cb4d99 100644 --- a/win/tclooConfig.sh +++ b/win/tclooConfig.sh @@ -15,5 +15,5 @@ TCLOO_LIB_SPEC="" TCLOO_STUB_LIB_SPEC="" TCLOO_INCLUDE_SPEC="" TCLOO_PRIVATE_INCLUDE_SPEC="" -TCLOO_CFLAGS=-DUSE_TCLOO_STUBS -TCLOO_VERSION=0.6.3 +TCLOO_CFLAGS="" +TCLOO_VERSION=0.7 |